From c6991e22ce6837b636be168817a7c2b23aaed811 Mon Sep 17 00:00:00 2001 From: Shane Lee Date: Wed, 21 Feb 2024 12:18:00 -0700 Subject: [PATCH 01/54] Fix update winrepo script on 3006.x --- .github/workflows/release-update-winrepo.yml | 3 +++ .github/workflows/scripts/update_winrepo.py | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-update-winrepo.yml b/.github/workflows/release-update-winrepo.yml index 2c5630034b8..4282709d72b 100644 --- a/.github/workflows/release-update-winrepo.yml +++ b/.github/workflows/release-update-winrepo.yml @@ -41,9 +41,12 @@ jobs: - name: Add Version to Minion Definition File working-directory: salt run: | + pwd + ls -al ../winrepo/salt-minion.sls python .github/workflows/scripts/update_winrepo.py \ --file ../winrepo/salt-minion.sls \ --version ${{ inputs.salt-version || github.ref_name }} + grep ${{ inputs.salt-version || github.ref_name }} ../winrepo/salt-minion.sls - name: Commit Changes working-directory: winrepo diff --git a/.github/workflows/scripts/update_winrepo.py b/.github/workflows/scripts/update_winrepo.py index b12d6558a4d..ab2c92d44db 100644 --- a/.github/workflows/scripts/update_winrepo.py +++ b/.github/workflows/scripts/update_winrepo.py @@ -1,8 +1,10 @@ import argparse import os +print("Update winrepo script") + # Where are we -print(os.getcwd()) +print(f"Current working directory: {os.getcwd()}") arg_parser = argparse.ArgumentParser() arg_parser.add_argument("-f", "--file", help="the winrepo file to edit") @@ -12,10 +14,15 @@ args = arg_parser.parse_args() file = args.file version = args.version +print("Args:") +print(f"- file: {file}") +print(f"- version: {version}") + if version.startswith("v"): version = version[1:] with open(file) as f: + print(f"Opening file: {file}") current_contents = f.readlines() new_contents = [] @@ -23,9 +30,13 @@ new_contents = [] added = False for line in current_contents: new_contents.append(line) - if "for version in [" in line and not added: - new_contents.append(f" '{version}',\n") + if "load_yaml as versions_relenv" in line and not added: + print(f"Adding version: {version}") + new_contents.append(f"- {version}\n") added = True with open(file, "w") as f: + print(f"Writing file: {file}") f.writelines(new_contents) + +print("Update winrepo script complete") From 2f14cd2816656fbd1310b8ce882280ef96969e85 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 21 Feb 2024 17:57:36 -0600 Subject: [PATCH 02/54] Fix file.directory clobbering backupname path with test=True --- salt/states/file.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/salt/states/file.py b/salt/states/file.py index c78c5c24ab5..e36db6f2468 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -3897,13 +3897,25 @@ def directory( if not force: return _error( ret, - "File exists where the backup target {} should go".format( - backupname - ), + f"File exists where the backup target {backupname} should go", ) + if __opts__["test"]: + ret["changes"][ + "forced" + ] = f"Existing file at backup path {backupname} would be removed" else: __salt__["file.remove"](backupname) - os.rename(name, backupname) + + if __opts__["test"]: + ret["changes"]["backup"] = f"{name} would be renamed to {backupname}" + ret["changes"][name] = {"directory": "new"} + ret[ + "comment" + ] = f"{name} would be backed up and replaced with a new directory" + ret["result"] = None + return ret + else: + os.rename(name, backupname) elif force: # Remove whatever is in the way if os.path.isfile(name): From 21ebbf155d97ccab59573044faf76a9eb2553478 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 21 Feb 2024 18:57:41 -0600 Subject: [PATCH 03/54] Add test case --- .../functional/states/file/test_directory.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/pytests/functional/states/file/test_directory.py b/tests/pytests/functional/states/file/test_directory.py index 82a3f7f154c..904a7d43b97 100644 --- a/tests/pytests/functional/states/file/test_directory.py +++ b/tests/pytests/functional/states/file/test_directory.py @@ -436,3 +436,55 @@ def test_issue_12209_follow_symlinks( assert one_group_check == state_file_account.group.name two_group_check = modules.file.get_group(str(twodir), follow_symlinks=False) assert two_group_check == state_file_account.group.name + + +@pytest.mark.parametrize("backupname_isfile", [False, True]) +def test_directory_backupname_force_test_mode_noclobber( + file, tmp_path, backupname_isfile +): + """ + Ensure that file.directory does not make changes when backupname is used + alongside force=True and test=True. + + See https://github.com/saltstack/salt/issues/66049 + """ + source_dir = tmp_path / "source_directory" + dest_dir = tmp_path / "dest_directory" + backupname = tmp_path / "backup_dir" + source_dir.mkdir() + dest_dir.symlink_to(source_dir.resolve()) + + if backupname_isfile: + backupname.touch() + assert backupname.is_file() + + ret = file.directory( + name=str(dest_dir), + allow_symlink=False, + force=True, + backupname=str(backupname), + test=True, + ) + + # Confirm None result + assert ret.result is None + try: + # Confirm dest_dir not modified + assert dest_dir.readlink() == source_dir + except OSError: + pytest.fail(f"{dest_dir} was modified") + + # Confirm that comment and changes match what we expect + assert ( + ret.comment + == f"{dest_dir} would be backed up and replaced with a new directory" + ) + assert ret.changes[str(dest_dir)] == {"directory": "new"} + assert ret.changes["backup"] == f"{dest_dir} would be renamed to {backupname}" + + if backupname_isfile: + assert ret.changes["forced"] == ( + f"Existing file at backup path {backupname} would be removed" + ) + else: + assert "forced" not in ret.changes From 7386c6ec87ccc0af76e751078a91acfd8b488948 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 21 Feb 2024 19:04:49 -0600 Subject: [PATCH 04/54] Add changelog entry --- changelog/66049.fixed.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changelog/66049.fixed.md diff --git a/changelog/66049.fixed.md b/changelog/66049.fixed.md new file mode 100644 index 00000000000..baff6e063d3 --- /dev/null +++ b/changelog/66049.fixed.md @@ -0,0 +1,2 @@ +Fixed an issue with file.directory state where paths would be modified in test +mode if backupname is used. From f3f54a6eb19921cc8eeb0aea3346b06304df57a6 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 21 Feb 2024 05:51:02 +0000 Subject: [PATCH 05/54] Switch to python-tools-scripts >= 0.20.0 --- .pre-commit-config.yaml | 4 ++-- requirements/static/ci/py3.10/tools.txt | 15 ++++++++++++--- requirements/static/ci/py3.11/tools.txt | 12 +++++++++++- requirements/static/ci/py3.12/tools.txt | 12 +++++++++++- requirements/static/ci/py3.9/tools.txt | 15 ++++++++++++--- requirements/static/ci/tools.in | 2 +- tools/__init__.py | 13 ++++++------- tools/changelog.py | 9 +++++---- tools/docs.py | 9 +++++---- tools/pkg/__init__.py | 23 ++++++++++++++--------- tools/precommit/changelog.py | 9 +++++---- 11 files changed, 84 insertions(+), 39 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 555b1cec34c..b402fd7e93c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -46,7 +46,7 @@ repos: )$ - repo: https://github.com/saltstack/python-tools-scripts - rev: "0.18.6" + rev: "0.20.0" hooks: - id: tools alias: check-changelog-entries @@ -1762,7 +1762,7 @@ repos: - types-attrs - types-pyyaml - types-requests - - python-tools-scripts>=0.18.6 + - python-tools-scripts>=0.20.0 - repo: https://github.com/saltstack/mirrors-nox rev: v2021.6.12 diff --git a/requirements/static/ci/py3.10/tools.txt b/requirements/static/ci/py3.10/tools.txt index d3b6eb23735..dcda605b103 100644 --- a/requirements/static/ci/py3.10/tools.txt +++ b/requirements/static/ci/py3.10/tools.txt @@ -4,6 +4,8 @@ # # pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.10/tools.txt requirements/static/ci/tools.in # +annotated-types==0.6.0 + # via pydantic attrs==20.3.0 # via # -r requirements/static/ci/tools.in @@ -34,11 +36,15 @@ mdurl==0.1.2 # via markdown-it-py packaging==22.0 # via -r requirements/static/ci/tools.in +pydantic-core==2.16.2 + # via pydantic +pydantic==2.6.1 + # via python-tools-scripts pygments==2.13.0 # via rich python-dateutil==2.8.1 # via botocore -python-tools-scripts==0.18.6 +python-tools-scripts==0.20.0 # via -r requirements/static/ci/tools.in pyyaml==6.0.1 # via -r requirements/static/ci/tools.in @@ -50,8 +56,11 @@ s3transfer==0.6.1 # via boto3 six==1.16.0 # via python-dateutil -typing-extensions==4.2.0 - # via python-tools-scripts +typing-extensions==4.9.0 + # via + # pydantic + # pydantic-core + # python-tools-scripts urllib3==1.26.18 # via # botocore diff --git a/requirements/static/ci/py3.11/tools.txt b/requirements/static/ci/py3.11/tools.txt index adcf0b938b8..b980e3455dc 100644 --- a/requirements/static/ci/py3.11/tools.txt +++ b/requirements/static/ci/py3.11/tools.txt @@ -4,6 +4,8 @@ # # pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.11/tools.txt requirements/static/ci/tools.in # +annotated-types==0.6.0 + # via pydantic attrs==22.1.0 # via # -r requirements/static/ci/tools.in @@ -32,11 +34,15 @@ markupsafe==2.1.2 # via jinja2 packaging==22.0 # via -r requirements/static/ci/tools.in +pydantic-core==2.16.2 + # via pydantic +pydantic==2.6.1 + # via python-tools-scripts pygments==2.13.0 # via rich python-dateutil==2.8.1 # via botocore -python-tools-scripts==0.18.6 +python-tools-scripts==0.20.0 # via -r requirements/static/ci/tools.in pyyaml==6.0.1 # via -r requirements/static/ci/tools.in @@ -48,6 +54,10 @@ s3transfer==0.5.2 # via boto3 six==1.16.0 # via python-dateutil +typing-extensions==4.9.0 + # via + # pydantic + # pydantic-core urllib3==1.26.18 # via # botocore diff --git a/requirements/static/ci/py3.12/tools.txt b/requirements/static/ci/py3.12/tools.txt index f6e9cfcccb0..0617439a8e7 100644 --- a/requirements/static/ci/py3.12/tools.txt +++ b/requirements/static/ci/py3.12/tools.txt @@ -4,6 +4,8 @@ # # pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.12/tools.txt requirements/static/ci/tools.in # +annotated-types==0.6.0 + # via pydantic attrs==22.1.0 # via # -r requirements/static/ci/tools.in @@ -32,11 +34,15 @@ markupsafe==2.1.2 # via jinja2 packaging==22.0 # via -r requirements/static/ci/tools.in +pydantic-core==2.16.2 + # via pydantic +pydantic==2.6.1 + # via python-tools-scripts pygments==2.13.0 # via rich python-dateutil==2.8.1 # via botocore -python-tools-scripts==0.18.6 +python-tools-scripts==0.20.0 # via -r requirements/static/ci/tools.in pyyaml==6.0.1 # via -r requirements/static/ci/tools.in @@ -48,6 +54,10 @@ s3transfer==0.5.2 # via boto3 six==1.16.0 # via python-dateutil +typing-extensions==4.9.0 + # via + # pydantic + # pydantic-core urllib3==1.26.18 # via # botocore diff --git a/requirements/static/ci/py3.9/tools.txt b/requirements/static/ci/py3.9/tools.txt index 1f3d04a05e1..ca4ff2baff0 100644 --- a/requirements/static/ci/py3.9/tools.txt +++ b/requirements/static/ci/py3.9/tools.txt @@ -4,6 +4,8 @@ # # pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.9/tools.txt requirements/static/ci/tools.in # +annotated-types==0.6.0 + # via pydantic attrs==20.3.0 # via # -r requirements/static/ci/tools.in @@ -34,11 +36,15 @@ mdurl==0.1.2 # via markdown-it-py packaging==22.0 # via -r requirements/static/ci/tools.in +pydantic-core==2.16.2 + # via pydantic +pydantic==2.6.1 + # via python-tools-scripts pygments==2.13.0 # via rich python-dateutil==2.8.1 # via botocore -python-tools-scripts==0.18.6 +python-tools-scripts==0.20.0 # via -r requirements/static/ci/tools.in pyyaml==6.0.1 # via -r requirements/static/ci/tools.in @@ -50,8 +56,11 @@ s3transfer==0.6.1 # via boto3 six==1.16.0 # via python-dateutil -typing-extensions==4.2.0 - # via python-tools-scripts +typing-extensions==4.9.0 + # via + # pydantic + # pydantic-core + # python-tools-scripts urllib3==1.26.18 # via # botocore diff --git a/requirements/static/ci/tools.in b/requirements/static/ci/tools.in index 7bc0163df05..5d0da3fde92 100644 --- a/requirements/static/ci/tools.in +++ b/requirements/static/ci/tools.in @@ -1,5 +1,5 @@ attrs -python-tools-scripts >= 0.18.6 +python-tools-scripts >= 0.20.0 boto3 pyyaml jinja2 diff --git a/tools/__init__.py b/tools/__init__.py index 1d46e63b2d5..f5131d0e7f9 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -3,8 +3,7 @@ import pathlib import sys import ptscripts -from ptscripts.parser import DefaultRequirementsConfig -from ptscripts.virtualenv import VirtualEnvConfig +from ptscripts.models import DefaultPipConfig, VirtualEnvPipConfig REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent REQUIREMENTS_FILES_PATH = REPO_ROOT / "requirements" @@ -12,16 +11,16 @@ STATIC_REQUIREMENTS_PATH = REQUIREMENTS_FILES_PATH / "static" CI_REQUIREMENTS_FILES_PATH = ( STATIC_REQUIREMENTS_PATH / "ci" / "py{}.{}".format(*sys.version_info) ) -DEFAULT_REQS_CONFIG = DefaultRequirementsConfig( - pip_args=[ +DEFAULT_REQS_CONFIG = DefaultPipConfig( + install_args=[ f"--constraint={REQUIREMENTS_FILES_PATH / 'constraints.txt'}", ], requirements_files=[ CI_REQUIREMENTS_FILES_PATH / "tools.txt", ], ) -RELEASE_VENV_CONFIG = VirtualEnvConfig( - pip_args=[ +RELEASE_VENV_CONFIG = VirtualEnvPipConfig( + install_args=[ f"--constraint={REQUIREMENTS_FILES_PATH / 'constraints.txt'}", ], requirements_files=[ @@ -29,7 +28,7 @@ RELEASE_VENV_CONFIG = VirtualEnvConfig( ], add_as_extra_site_packages=True, ) -ptscripts.set_default_requirements_config(DEFAULT_REQS_CONFIG) +ptscripts.set_default_config(DEFAULT_REQS_CONFIG) ptscripts.register_tools_module("tools.changelog") ptscripts.register_tools_module("tools.ci") ptscripts.register_tools_module("tools.docs") diff --git a/tools/changelog.py b/tools/changelog.py index 12bbba22d3c..8e9e3ff3e73 100644 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -13,6 +13,7 @@ import textwrap from jinja2 import Environment, FileSystemLoader from ptscripts import Context, command_group +from ptscripts.models import VirtualEnvPipConfig from tools.utils import REPO_ROOT, Version @@ -23,16 +24,16 @@ changelog = command_group( name="changelog", help="Changelog tools", description=__doc__, - venv_config={ - "requirements_files": [ + venv_config=VirtualEnvPipConfig( + requirements_files=[ REPO_ROOT / "requirements" / "static" / "ci" / "py{}.{}".format(*sys.version_info) - / "changelog.txt" + / "changelog.txt", ], - }, + ), ) diff --git a/tools/docs.py b/tools/docs.py index 83868d1af7e..b36e676d974 100644 --- a/tools/docs.py +++ b/tools/docs.py @@ -11,6 +11,7 @@ import shutil import sys from ptscripts import Context, command_group +from ptscripts.models import VirtualEnvPipConfig import tools.utils @@ -21,16 +22,16 @@ docs = command_group( name="docs", help="Manpages tools", description=__doc__, - venv_config={ - "requirements_files": [ + venv_config=VirtualEnvPipConfig( + requirements_files=[ tools.utils.REPO_ROOT / "requirements" / "static" / "ci" / "py{}.{}".format(*sys.version_info) - / "docs.txt" + / "docs.txt", ], - }, + ), ) diff --git a/tools/pkg/__init__.py b/tools/pkg/__init__.py index 2d843893640..7eb7b0ba66c 100644 --- a/tools/pkg/__init__.py +++ b/tools/pkg/__init__.py @@ -18,6 +18,7 @@ import tempfile import yaml from ptscripts import Context, command_group +from ptscripts.models import VirtualEnvPipConfig import tools.utils @@ -137,7 +138,11 @@ def set_salt_version( ctx.info(f"Validating and normalizing the salt version {salt_version!r}...") with ctx.virtualenv( name="set-salt-version", - requirements_files=[tools.utils.REPO_ROOT / "requirements" / "base.txt"], + config=VirtualEnvPipConfig( + requirements_files=[ + tools.utils.REPO_ROOT / "requirements" / "base.txt", + ] + ), ) as venv: code = f""" import sys @@ -363,11 +368,11 @@ def generate_hashes(ctx: Context, files: list[pathlib.Path]): @pkg.command( name="source-tarball", - venv_config={ - "requirements_files": [ + venv_config=VirtualEnvPipConfig( + requirements_files=[ tools.utils.REPO_ROOT / "requirements" / "build.txt", - ] - }, + ], + ), ) def source_tarball(ctx: Context): shutil.rmtree("dist/", ignore_errors=True) @@ -411,11 +416,11 @@ def source_tarball(ctx: Context): @pkg.command( name="pypi-upload", - venv_config={ - "requirements_files": [ + venv_config=VirtualEnvPipConfig( + requirements_files=[ tools.utils.REPO_ROOT / "requirements" / "build.txt", - ] - }, + ], + ), arguments={ "files": { "help": "Files to upload to PyPi", diff --git a/tools/precommit/changelog.py b/tools/precommit/changelog.py index 5e108af5f11..99e3afbf116 100644 --- a/tools/precommit/changelog.py +++ b/tools/precommit/changelog.py @@ -10,6 +10,7 @@ import re import sys from ptscripts import Context, command_group +from ptscripts.models import VirtualEnvPipConfig import tools.utils @@ -33,16 +34,16 @@ changelog = command_group( name="changelog", help="Changelog tools", description=__doc__, - venv_config={ - "requirements_files": [ + venv_config=VirtualEnvPipConfig( + requirements_files=[ tools.utils.REPO_ROOT / "requirements" / "static" / "ci" / "py{}.{}".format(*sys.version_info) - / "changelog.txt" + / "changelog.txt", ], - }, + ), parent="pre-commit", ) From b9be2dec1b33a654da7cb73e39a5b35ff78fef57 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Sun, 25 Feb 2024 10:37:08 +0000 Subject: [PATCH 06/54] Update and remove obsolete pylint plugins --- .github/workflows/lint-action.yml | 2 +- .pre-commit-config.yaml | 21 +- .pylintrc | 1005 +++++++++-------- noxfile.py | 97 +- requirements/static/ci/lint.in | 4 +- requirements/static/ci/py3.10/lint.txt | 28 +- requirements/static/ci/py3.11/lint.txt | 20 +- requirements/static/ci/py3.12/lint.txt | 20 +- requirements/static/ci/py3.7/lint.txt | 796 ------------- requirements/static/ci/py3.8/lint.txt | 29 +- requirements/static/ci/py3.9/lint.txt | 29 +- salt/_logging/impl.py | 2 +- salt/auth/pki.py | 9 +- salt/channel/client.py | 2 +- salt/channel/server.py | 2 +- salt/cli/batch.py | 5 +- salt/cli/cp.py | 16 +- salt/client/__init__.py | 3 +- salt/client/ssh/__init__.py | 12 +- salt/client/ssh/ssh_py_shim.py | 11 +- salt/client/ssh/wrapper/grains.py | 25 +- salt/client/ssh/wrapper/pillar.py | 4 +- salt/cloud/cli.py | 22 +- salt/cloud/clouds/aliyun.py | 2 +- salt/cloud/clouds/clc.py | 2 +- salt/cloud/clouds/digitalocean.py | 12 +- salt/cloud/clouds/ec2.py | 8 +- salt/cloud/clouds/joyent.py | 4 +- salt/cloud/clouds/linode.py | 12 +- salt/cloud/clouds/proxmox.py | 13 +- salt/cloud/clouds/qingcloud.py | 4 +- salt/cloud/clouds/vmware.py | 2 +- salt/config/schemas/common.py | 2 +- salt/engines/slack.py | 2 - salt/engines/slack_bolt_engine.py | 2 - salt/ext/backports_abc.py | 2 +- salt/ext/ipaddress.py | 3 +- salt/ext/tornado/platform/auto.pyi | 2 +- salt/fileserver/s3fs.py | 8 +- salt/grains/core.py | 2 +- salt/loader/lazy.py | 2 +- salt/master.py | 4 +- salt/modules/aptpkg.py | 13 +- salt/modules/archive.py | 14 +- salt/modules/boto3_route53.py | 2 +- salt/modules/boto3_sns.py | 2 +- salt/modules/btrfs.py | 5 +- salt/modules/consul.py | 2 +- salt/modules/cp.py | 10 +- salt/modules/cryptdev.py | 5 +- salt/modules/csf.py | 2 +- salt/modules/datadog_api.py | 4 +- salt/modules/dig.py | 2 +- salt/modules/disk.py | 2 +- salt/modules/dockermod.py | 24 +- salt/modules/ebuildpkg.py | 10 +- salt/modules/file.py | 4 +- salt/modules/freebsdjail.py | 12 +- salt/modules/git.py | 8 +- salt/modules/glassfish.py | 3 + salt/modules/grains.py | 29 +- salt/modules/heat.py | 10 +- salt/modules/inspectlib/fsdb.py | 18 +- salt/modules/inspectlib/query.py | 16 +- salt/modules/iptables.py | 73 +- salt/modules/iwtools.py | 2 +- salt/modules/k8s.py | 2 +- salt/modules/kubernetesmod.py | 2 +- salt/modules/ldap3.py | 4 +- salt/modules/mac_softwareupdate.py | 2 +- salt/modules/mine.py | 15 +- salt/modules/mount.py | 15 +- salt/modules/mysql.py | 8 +- salt/modules/network.py | 2 +- salt/modules/openscap.py | 21 +- salt/modules/opkg.py | 5 +- salt/modules/opsgenie.py | 2 + salt/modules/oracle.py | 9 +- salt/modules/pagerduty_util.py | 2 + salt/modules/pkg_resource.py | 8 +- salt/modules/portage_config.py | 2 +- salt/modules/postgres.py | 7 +- salt/modules/quota.py | 2 +- salt/modules/rabbitmq.py | 14 +- salt/modules/rpm_lowpkg.py | 5 +- salt/modules/saltcheck.py | 2 +- salt/modules/selinux.py | 2 +- salt/modules/sensehat.py | 1 + salt/modules/serverdensity_device.py | 4 + salt/modules/smartos_imgadm.py | 17 +- salt/modules/smartos_vmadm.py | 10 +- salt/modules/solaris_shadow.py | 2 +- salt/modules/splunk_search.py | 2 +- salt/modules/status.py | 9 +- salt/modules/statuspage.py | 2 +- salt/modules/swarm.py | 2 +- salt/modules/sysrc.py | 4 +- salt/modules/systemd_service.py | 3 - salt/modules/telegram.py | 2 +- salt/modules/telemetry.py | 19 +- salt/modules/tomcat.py | 15 +- salt/modules/uptime.py | 12 +- salt/modules/vbox_guest.py | 20 +- salt/modules/virt.py | 149 ++- salt/modules/win_iis.py | 4 +- salt/modules/win_lgpo.py | 6 +- salt/modules/win_lgpo_reg.py | 26 +- salt/modules/win_pkg.py | 10 +- salt/modules/win_pki.py | 2 +- salt/modules/win_shortcut.py | 4 +- salt/modules/win_status.py | 7 +- salt/modules/win_task.py | 50 +- salt/modules/x509_v2.py | 2 +- salt/modules/xapi_virt.py | 30 +- salt/modules/xfs.py | 17 +- salt/modules/yumpkg.py | 6 +- salt/modules/zcbuildout.py | 12 +- salt/netapi/rest_cherrypy/__init__.py | 2 +- salt/netapi/rest_cherrypy/app.py | 8 +- salt/netapi/rest_tornado/saltnado.py | 8 +- salt/output/pony.py | 4 +- salt/pillar/__init__.py | 6 +- salt/pillar/foreman.py | 1 + salt/pillar/pepa.py | 12 +- salt/pillar/vault.py | 2 +- salt/pillar/vmware_pillar.py | 2 +- salt/platform/win.py | 5 +- salt/proxy/dummy.py | 18 +- salt/proxy/philips_hue.py | 10 +- salt/renderers/genshi.py | 4 +- salt/renderers/stateconf.py | 2 +- salt/returners/etcd_return.py | 6 +- salt/returners/influxdb_return.py | 2 +- salt/returners/local_cache.py | 4 +- salt/returners/mysql.py | 6 +- salt/returners/pgjsonb.py | 10 +- salt/returners/splunk.py | 1 + salt/roster/cache.py | 14 +- salt/runners/asam.py | 2 +- salt/runners/launchd.py | 10 +- salt/runners/pkg.py | 2 +- salt/runners/state.py | 4 +- salt/runners/vault.py | 8 +- salt/scripts.py | 6 +- salt/serializers/msgpack.py | 105 +- salt/serializers/yaml.py | 2 +- salt/state.py | 54 +- salt/states/archive.py | 12 +- salt/states/boto3_route53.py | 3 +- salt/states/docker_container.py | 12 +- salt/states/docker_image.py | 4 +- salt/states/docker_network.py | 31 +- salt/states/environ.py | 1 + salt/states/file.py | 10 +- salt/states/git.py | 183 ++- salt/states/gpg.py | 2 +- salt/states/grafana_dashboard.py | 1 + salt/states/grains.py | 4 +- salt/states/ldap.py | 1 + salt/states/netsnmp.py | 4 +- salt/states/pip_state.py | 22 +- salt/states/pkg.py | 2 +- salt/states/probes.py | 10 +- salt/states/saltmod.py | 4 +- salt/states/win_iis.py | 2 +- salt/utils/ansible.py | 8 +- salt/utils/args.py | 20 +- salt/utils/atomicfile.py | 8 +- salt/utils/aws.py | 14 +- salt/utils/cache.py | 4 +- salt/utils/cloud.py | 6 +- salt/utils/compat.py | 4 +- salt/utils/configparser.py | 12 +- salt/utils/data.py | 9 +- salt/utils/dns.py | 56 +- salt/utils/dockermod/__init__.py | 6 +- salt/utils/dockermod/translate/container.py | 20 +- salt/utils/dockermod/translate/helpers.py | 2 +- salt/utils/files.py | 11 +- salt/utils/fsutils.py | 10 +- salt/utils/functools.py | 4 +- salt/utils/gitfs.py | 117 +- salt/utils/iam.py | 1 + salt/utils/jinja.py | 4 - salt/utils/msazure.py | 12 +- salt/utils/nacl.py | 6 +- salt/utils/napalm.py | 9 +- salt/utils/nb_popen.py | 6 +- salt/utils/network.py | 35 +- salt/utils/odict.py | 303 +---- salt/utils/openstack/nova.py | 2 +- salt/utils/oset.py | 4 +- salt/utils/parsers.py | 2 +- salt/utils/path.py | 8 +- salt/utils/pkg/__init__.py | 4 +- salt/utils/pkg/win.py | 4 +- salt/utils/preseed.py | 2 +- salt/utils/process.py | 4 +- salt/utils/psutil_compat.py | 102 +- salt/utils/reactor.py | 2 + salt/utils/ssdp.py | 5 +- salt/utils/templates.py | 32 +- salt/utils/vault.py | 28 +- salt/utils/verify.py | 7 +- salt/utils/versions.py | 5 +- salt/utils/vt.py | 3 +- salt/utils/win_network.py | 1 + salt/utils/win_runas.py | 3 +- salt/version.py | 6 +- setup.py | 18 +- tests/buildpackage.py | 8 +- tests/committer_parser.py | 2 +- tests/conftest.py | 4 +- tests/eventlisten.py | 4 +- .../cloud/clouds/test_oneandone.py | 12 +- tests/integration/cloud/clouds/test_vmware.py | 2 +- tests/integration/modules/test_cp.py | 4 +- tests/integration/modules/test_ssh.py | 2 +- .../netapi/rest_tornado/test_app.py | 2 +- tests/minionswarm.py | 2 +- tests/modparser.py | 15 +- tests/pytests/functional/cache/test_etcd.py | 4 +- tests/pytests/functional/modules/test_data.py | 4 +- .../pytests/functional/modules/test_system.py | 2 +- .../functional/states/file/test_append.py | 14 +- .../functional/states/file/test_replace.py | 20 +- .../functional/states/pkgrepo/test_debian.py | 4 +- .../states/test_docker_container.py | 16 +- .../functional/states/test_docker_network.py | 17 +- tests/pytests/functional/states/test_pkg.py | 2 +- .../functional/states/test_ssh_auth.py | 2 +- tests/pytests/functional/test_crypt.py | 7 +- .../integration/_logging/test_jid_logging.py | 2 +- tests/pytests/integration/cli/test_batch.py | 4 +- tests/pytests/integration/cli/test_salt.py | 2 +- .../integration/cli/test_syndic_eauth.py | 2 +- .../modules/state/test_state_test.py | 2 +- tests/pytests/integration/sdb/test_etcd_db.py | 4 +- .../integration/ssh/test_pre_flight.py | 7 +- .../pytests/pkg/download/test_pkg_download.py | 8 +- .../pkg/integration/test_pip_upgrade.py | 4 +- .../pytests/pkg/integration/test_salt_user.py | 2 +- tests/pytests/scenarios/blackout/conftest.py | 2 +- .../pytests/unit/beacons/test_salt_monitor.py | 2 - tests/pytests/unit/cli/test_daemons.py | 4 +- tests/pytests/unit/client/ssh/test_ssh.py | 8 +- .../pytests/unit/cloud/clouds/test_proxmox.py | 1 + .../daemons/masterapi/test_remote_funcs.py | 6 +- tests/pytests/unit/fileserver/test_roots.py | 4 +- .../unit/modules/dockermod/test_module.py | 68 +- .../unit/modules/file/test_file_line.py | 2 +- .../unit/modules/file/test_file_lsattr.py | 12 +- .../unit/modules/file/test_file_module.py | 14 +- .../pytests/unit/modules/state/test_state.py | 12 +- tests/pytests/unit/modules/test_cp.py | 13 +- tests/pytests/unit/modules/test_devinfo.py | 10 +- tests/pytests/unit/modules/test_glassfish.py | 3 + tests/pytests/unit/modules/test_gpg.py | 8 +- tests/pytests/unit/modules/test_hg.py | 17 +- tests/pytests/unit/modules/test_mount.py | 2 - .../pytests/unit/modules/test_salt_version.py | 3 +- .../unit/modules/test_solaris_shadow.py | 2 +- .../pytests/unit/modules/test_win_powercfg.py | 2 +- tests/pytests/unit/modules/test_zabbix.py | 5 - tests/pytests/unit/modules/virt/conftest.py | 2 +- .../modules/win_lgpo/test_admx_policies.py | 2 +- .../pytests/unit/pillar/test_consul_pillar.py | 24 +- tests/pytests/unit/proxy/test_napalm.py | 2 +- tests/pytests/unit/runners/test_asam.py | 4 + .../unit/runners/vault/test_app_role_auth.py | 9 +- .../unit/runners/vault/test_token_auth.py | 13 +- .../unit/serializers/test_serializers.py | 8 +- .../pytests/unit/state/test_state_compiler.py | 54 +- tests/pytests/unit/states/test_host.py | 6 +- tests/pytests/unit/transport/test_zeromq.py | 6 +- tests/pytests/unit/utils/test_cloud.py | 9 +- tests/pytests/unit/utils/test_data.py | 13 +- tests/pytests/unit/utils/test_vault.py | 6 + tests/pytests/unit/utils/test_vt.py | 2 +- tests/pytests/unit/wheel/test_file_roots.py | 2 +- tests/salt-tcpdump.py | 6 +- tests/saltsh.py | 10 +- tests/support/copyartifacts.py | 13 +- ...ate-names-file-from-failed-test-reports.py | 4 +- tests/support/pkg.py | 7 +- tests/support/pytest/etcd.py | 4 +- tests/support/pytest/helpers.py | 16 +- tests/support/unit.py | 4 +- tests/support/win_installer.py | 9 +- tests/unit/ext/test_ipaddress.py | 8 +- tests/unit/modules/test_elasticsearch.py | 16 +- tests/unit/modules/test_sysmod.py | 8 +- tests/unit/modules/test_zcbuildout.py | 20 +- tests/unit/states/test_loop.py | 16 +- tests/unit/test_pillar.py | 6 +- tests/unit/test_zypp_plugins.py | 2 +- tests/unit/utils/test_configparser.py | 4 +- tests/unit/utils/test_context.py | 2 +- tests/unit/utils/test_dns.py | 4 +- tests/unit/utils/test_systemd.py | 2 - tests/unit/utils/test_thin.py | 13 +- tests/wheeltest.py | 4 +- tools/changelog.py | 16 +- tools/ci.py | 14 +- tools/pkg/__init__.py | 11 +- tools/pkg/build.py | 4 +- tools/pkg/repo/__init__.py | 8 +- tools/pkg/repo/create.py | 12 +- tools/pkg/repo/publish.py | 18 +- tools/precommit/workflows.py | 4 +- tools/release.py | 14 +- tools/testsuite/__init__.py | 8 +- tools/testsuite/download.py | 4 +- tools/vm.py | 51 +- 314 files changed, 2209 insertions(+), 3342 deletions(-) delete mode 100644 requirements/static/ci/py3.7/lint.txt diff --git a/.github/workflows/lint-action.yml b/.github/workflows/lint-action.yml index 6f177667129..9dc4be360e3 100644 --- a/.github/workflows/lint-action.yml +++ b/.github/workflows/lint-action.yml @@ -23,7 +23,7 @@ jobs: if: ${{ contains(fromJSON('["push", "schedule", "workflow_dispatch"]'), github.event_name) || fromJSON(inputs.changed-files)['salt'] || fromJSON(inputs.changed-files)['lint'] }} container: - image: ghcr.io/saltstack/salt-ci-containers/python:3.8 + image: ghcr.io/saltstack/salt-ci-containers/python:3.9 steps: - name: Install System Deps diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b402fd7e93c..2b170f88ef3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1370,23 +1370,6 @@ repos: # <---- Doc CI Requirements ---------------------------------------------------------------------------------------- # ----- Lint CI Requirements --------------------------------------------------------------------------------------> - - id: pip-tools-compile - alias: compile-ci-lint-3.7-requirements - name: Lint CI Py3.7 Requirements - files: ^requirements/((base|zeromq)\.txt|static/(pkg/linux\.in|ci/(linux\.in|common\.in|lint\.in|py3\.7/linux\.txt)))$ - pass_filenames: false - args: - - -v - - --build-isolation - - --py-version=3.7 - - --platform=linux - - --include=requirements/base.txt - - --include=requirements/zeromq.txt - - --include=requirements/static/pkg/linux.in - - --include=requirements/static/ci/linux.in - - --include=requirements/static/ci/common.in - - --no-emit-index-url - - requirements/static/ci/lint.in - id: pip-tools-compile alias: compile-ci-lint-3.8-requirements @@ -1762,7 +1745,7 @@ repos: - types-attrs - types-pyyaml - types-requests - - python-tools-scripts>=0.20.0 + - python-tools-scripts==0.20.0 - repo: https://github.com/saltstack/mirrors-nox rev: v2021.6.12 @@ -1770,7 +1753,7 @@ repos: - id: nox alias: lint-salt name: Lint Salt - files: ^((setup|noxfile)|(salt|tasks|tools)/.*)\.py$ + files: ^((setup|noxfile)|(salt|tools)/.*)\.py$ exclude: > (?x)^( templates/.*| diff --git a/.pylintrc b/.pylintrc index 04fa981c375..d9e7af58eae 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,25 +1,77 @@ -[MASTER] +[MAIN] + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Clear in-memory caches upon conclusion of linting. Useful if running pylint +# in a server-like mode. +clear-cache-post-run=no + +# Load and enable all available extensions. Use --list-extensions to see a list +# all available extensions. +#enable-all-extensions= + +# In error mode, messages with a category besides ERROR or FATAL are +# suppressed, and no reports are done by default. Error mode is compatible with +# disabling specific errors. +#errors-only= + +# Always return a 0 (non-error) status code, even if lint errors are found. +# This is primarily useful in continuous integration scripts. +#exit-zero= # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) extension-pkg-whitelist= -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS, - ext, +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns=salt.ext.* +# Specify a score threshold under which the program will exit with error. +fail-under=10 + +# Interpret the stdin as a python script, whose filename needs to be passed as +# the module_or_package argument. +#from-stdin= + +# Files or directories to be skipped. They should be base names, not paths. +ignore=CVS + +# Add files or directories matching the regular expressions patterns to the +# ignore-list. The regex matches against paths and can be in Posix or Windows +# format. Because '\\' represents the directory delimiter on Windows systems, +# it can't be used as an escape character. +ignore-paths= + +# Files or directories matching the regular expression patterns are skipped. +# The regex matches against base names, not paths. The default value ignores +# Emacs file locks +ignore-patterns=^\.# + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the -# number of processors available to use. +# number of processors available to use, and will cap the count on Windows to +# avoid hangs. jobs=1 # Control the amount of potential inferred values when inferring a single @@ -29,12 +81,8 @@ limit-inference-results=100 # List of plugins (as comma separated values of python module names) to load, # usually to register additional checkers. -load-plugins=saltpylint.pep8, - saltpylint.strings, - saltpylint.fileperms, - saltpylint.py3modernize, +load-plugins=saltpylint.fileperms, saltpylint.smartup, - saltpylint.minpyver, saltpylint.blacklist, saltpylint.thirdparty, saltpylint.dunder_del @@ -42,8 +90,18 @@ load-plugins=saltpylint.pep8, # Pickle collected data for later comparisons. persistent=no -# Specify a configuration file. -#rcfile= +# Minimum Python version to use for version dependent checks. Will default to +# the version used to run pylint. +py-version=3.9 + +# Discover python modules and packages in the file system subtree. +recursive=no + +# Add paths to the list of the source roots. Supports globbing patterns. The +# source root is an absolute path or a path relative to the current working +# directory used to determine a package namespace for modules located under the +# source root. +source-roots= # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. @@ -53,125 +111,215 @@ suggestion-mode=yes # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once). You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use "--disable=all --enable=classes -# --disable=W". -disable=R, - locally-disabled, - file-ignored, - unexpected-special-method-signature, - import-error, - no-member, - unsubscriptable-object, - un-indexed-curly-braces-error, - whitespace-before-colon, - indentation-is-not-a-multiple-of-four-comment, - blacklisted-name, - invalid-name, - missing-docstring, - empty-docstring, - misplaced-comparison-constant, - unidiomatic-typecheck, - wrong-import-order, - ungrouped-imports, - wrong-import-position, - bad-mcs-method-argument, - bad-mcs-classmethod-argument, - line-too-long, - too-many-lines, - bad-continuation, - exec-used, - attribute-defined-outside-init, - protected-access, - reimported, - fixme, - global-statement, - unused-variable, - unused-argument, - redefined-outer-name, - redefined-builtin, - undefined-loop-variable, - logging-format-interpolation, - invalid-format-index, - line-too-long, - unexpected-indentation-comment, - continuation-line-indentation-is-not-a-multiple-of-four, - continuation-line-missing-indentation-or-outdented, - closing-bracket-does-not-match-indentation-of-opening-brackets-line, - closing-bracket-does-not-match-visual-indentation, - continuation-line-does-not-distinguish-itself-from-next-logical-line, - continuation-line-over-indented-for-hanging-indent, - continuation-line-over-indented-for-visual-indent, - continuation-line-under-indented-for-visual-indent, - visually-indented-line-with-same-indent-as-next-logical-line, - unaligned-for-hanging-indent, - block-comment-should-start-with-cardinal-space, - too-many-leading-hastag-for-block-comment, - module-level-import-not-at-top-of-file, - do-not-assign-a-lambda-expression-use-a-def, - 3rd-party-local-module-not-gated, - pep8-reserved-keywords, - import-outside-toplevel, - deprecated-method, - repr-flag-used-in-string, - keyword-arg-before-vararg, - incompatible-py3-code - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable=c-extension-no-member, - literal-comparison +# In verbose mode, extra non-checker-related info will be displayed. +#verbose= -[REPORTS] +[BASIC] -# Python expression which should return a score less than or equal to 10. You -# have access to the variables 'error', 'warning', 'refactor', and 'convention' -# which contain the number of messages in each category, as well as 'statement' -# which is the total number of statements analyzed. This score is used by the -# global evaluation report (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) +# Naming style matching correct argument names. +argument-naming-style=snake_case -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details. -msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} +# Regular expression matching correct argument names. Overrides argument- +# naming-style. If left empty, argument names will be checked with the set +# naming style. +#argument-rgx= -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -output-format=parseable +# Naming style matching correct attribute names. +attr-naming-style=snake_case -# Tells whether to display a full report or only the messages. -reports=no +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. If left empty, attribute names will be checked with the set naming +# style. +#attr-rgx= -# Activate the evaluation score. -score=yes +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. If left empty, class attribute names will be checked +# with the set naming style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. If left empty, class constant names will be checked with +# the set naming style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. If left empty, class names will be checked with the set naming style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. If left empty, constant names will be checked with the set naming +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. If left empty, function names will be checked with the set +# naming style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=exc, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. If left empty, inline iteration names will be checked +# with the set naming style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. If left empty, method names will be checked with the set naming style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. If left empty, module names will be checked with the set naming style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Regular expression matching correct type alias names. If left empty, type +# alias names will be checked with the set naming style. +#typealias-rgx= + +# Regular expression matching correct type variable names. If left empty, type +# variable names will be checked with the set naming style. +#typevar-rgx= + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. If left empty, variable names will be checked with the set +# naming style. +#variable-rgx= -[REFACTORING] +[CLASSES] -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=sys.exit +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + asyncSetUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# List of regular expressions of class ancestor names to ignore when counting +# public methods (see R0903) +exclude-too-few-public-methods= + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=35 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=48 + +# Maximum number of locals for function / method body. +max-locals=40 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=100 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when caught. +overgeneral-exceptions=builtins.BaseException,builtins.Exception [FORMAT] @@ -195,13 +343,6 @@ max-line-length=120 # Maximum number of lines in a module. max-module-lines=3000 -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma, - dict-separator - # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no @@ -211,141 +352,296 @@ single-line-class-stmt=no single-line-if-stmt=no +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow explicit reexports by alias from a package __init__. +allow-reexport-from-package=no + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, +# UNDEFINED. +confidence=HIGH, + CONTROL_FLOW, + INFERENCE, + INFERENCE_FAILURE, + UNDEFINED + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then re-enable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=R, + deprecated-pragma, + file-ignored, + locally-disabled, + suppressed-message, + use-implicit-booleaness-not-comparison-to-string, + use-implicit-booleaness-not-comparison-to-zero, + use-implicit-booleaness-not-comparison, + use-symbolic-message-instead, + useless-suppression, + 3rd-party-local-module-not-gated, + attribute-defined-outside-init, + bad-continuation, + bad-mcs-classmethod-argument, + bad-mcs-method-argument, + blacklisted-name, + deprecated-method, + empty-docstring, + exec-used, + file-ignored, + fixme, + global-statement, + import-error, + import-outside-toplevel, + invalid-format-index, + invalid-name, + keyword-arg-before-vararg, + line-too-long, + locally-disabled, + logging-format-interpolation, + missing-docstring, + no-member, + protected-access, + raw-checker-failed, + redefined-builtin, + redefined-outer-name, + reimported, + too-many-lines, + undefined-loop-variable, + unexpected-special-method-signature, + ungrouped-imports, + unidiomatic-typecheck, + unsubscriptable-object, + unused-argument, + unused-variable, + wrong-import-order, + wrong-import-position, + consider-using-f-string, + raise-missing-from, + broad-exception-raised, + consider-using-dict-items + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= + + +[METHOD_ARGS] + +# List of qualified names (i.e., library.method) which require a timeout +# parameter e.g. 'requests.api.get,requests.api.post' +timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request + + [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, - FIX, XXX, TODO +# Regular expression of note tags to take in consideration. +notes-rgx= -[BASIC] -# Naming style matching correct argument names. -argument-naming-style=snake_case +[REFACTORING] -# Regular expression matching correct argument names. Overrides argument- -# naming-style. -argument-rgx=[a-z_][a-z0-9_]{2,30}$ +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 -# Naming style matching correct attribute names. -attr-naming-style=snake_case +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. -attr-rgx=[a-z_][a-z0-9_]{2,30}$ -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata +[REPORTS] -# Naming style matching correct class attribute names. -class-attribute-naming-style=any +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'fatal', 'error', 'warning', 'refactor', +# 'convention', and 'info' which contain the number of messages in each +# category, as well as 'statement' which is the total number of statements +# analyzed. This score is used by the global evaluation report (RP0004). +evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style. -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template= -# Naming style matching correct class names. -class-naming-style=PascalCase +# Set the output format. Available formats are: text, parseable, colorized, +# json2 (improved json format), json (old json format) and msvs (visual +# studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=parseable -# Regular expression matching correct class names. Overrides class-naming- -# style. -class-rgx=[A-Z_][a-zA-Z0-9]+$ +# Tells whether to display a full report or only the messages. +reports=no -# Naming style matching correct constant names. -const-naming-style=UPPER_CASE +# Activate the evaluation score. +score=yes -# Regular expression matching correct constant names. Overrides const-naming- -# style. -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 +[SIMILARITIES] -# Naming style matching correct function names. -function-naming-style=snake_case +# Comments are removed from the similarity computation +ignore-comments=yes -# Regular expression matching correct function names. Overrides function- -# naming-style. -function-rgx=[a-z_][a-z0-9_]{2,30}$ +# Docstrings are removed from the similarity computation +ignore-docstrings=yes -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - Run, - _, - log +# Imports are removed from the similarity computation +ignore-imports=yes -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=yes +# Signatures are removed from the similarity computation +ignore-signatures=yes -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any +# Minimum lines number of a similarity. +min-similarity-lines=4 -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style. -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -# Naming style matching correct method names. -method-naming-style=snake_case +[SPELLING] -# Regular expression matching correct method names. Overrides method-naming- -# style. -method-rgx=[a-z_][a-z0-9_]{2,30}$ +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 -# Naming style matching correct module names. -module-naming-style=snake_case +# Spelling dictionary name. No available dictionaries : You need to install +# both the python package and the system dependency for enchant to work. +spelling-dict= -# Regular expression matching correct module names. Overrides module-naming- -# style. -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +# List of comma separated words that should be considered directives if they +# appear at the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= +# List of comma separated words that should not be checked. +spelling-ignore-words= -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=__.*__ +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Naming style matching correct variable names. -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style. -variable-rgx=[a-z_][a-z0-9_]{2,30}$ +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no [STRING] -# This flag controls whether the implicit-str-concat-in-sequence should -# generate a warning on implicit string concatenation in sequences defined over -# several lines. +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. check-str-concat-over-line-jumps=no -# Enforce string formatting over string substitution -enforce-string-formatting-over-substitution=yes -# Force string substitution usage on strings to always be an error. -string-substitutions-usage-is-an-error=yes +[TYPECHECK] -# Force un-indexed curly braces on a 'string.format()' call to always be an -# error. -un-indexed-curly-braces-always-error=no +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of symbolic message names to ignore for Mixin members. +ignored-checks-for-mixins=no-member, + not-async-context-manager, + not-context-manager, + attribute-defined-outside-init + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# Regex pattern to define which classes are considered mixins. +mixin-class-rgx=.*[Mm]ixin + +# List of decorators that change the signature of a decorated function. +signature-mutators= [VARIABLES] @@ -379,6 +675,9 @@ additional-builtins=__opts__, # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes +# List of names allowed to shadow builtins +allowed-redefined-builtins= + # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, @@ -386,128 +685,17 @@ callbacks=cb_, # A regular expression matching the name of dummy variables (i.e. expected to # not be used). -dummy-variables-rgx=_|dummy +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ -# Argument names that match this expression will be ignored. Default to name -# with leading underscore. -ignored-argument-names=_.* +# Argument names that match this expression will be ignored. +ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. -redefining-builtins-modules=six.moves, - salt.ext.six.moves, - past.builtins, - future.builtins, - builtins, - io - - -[LOGGING] - -# Format style used to check logging format string. `old` means using % -# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules= - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes. -max-spelling-suggestions=4 - -# Spelling dictionary name. Available dictionaries: none. To make it work, -# install the python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains the private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to the private dictionary (see the -# --spelling-private-dict-file option) instead of raising a message. -spelling-store-unknown-words=no - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members=REQUEST, - acl_users, - aq_parent - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# Tells whether to warn about missing members when the owner of the attribute -# is inferred to be None. -ignore-none=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=SQLObject - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis). It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=salt.ext.six.moves, - six.moves, - _MovedItems, - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - -# List of decorators that change the signature of a decorated function. -signature-mutators= - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [FILEPERMS] @@ -518,135 +706,6 @@ fileperms-default=0644 # File paths to ignore file permission. Glob patterns allowed. fileperms-ignore-paths=setup.py,noxfile.py,tests/runtests.py,tests/jenkins*.py,tests/saltsh.py,tests/buildpackage.py,tests/unit/files/rosters/ansible/roster.py - -[MODERNIZE] - -# Fix up doctests only -modernize-doctests-only=no - -# Each FIX specifies a transformation; "default" includes default fixes. -modernize-fix= - -# Use 'from __future__ import unicode_literals' (only useful for Python 2.6+). -modernize-future-unicode=no - -# Exclude fixes that depend on the six package. -modernize-no-six=no - -# Comma separated list of fixer names not to fix. -modernize-nofix= - -# Modify the grammar so that print() is a function. -modernize-print-function=yes - -# Wrap unicode literals in six.u(). -modernize-six-unicode=no - - -[MININUM-PYTHON-VERSION] - -# The desired minimum python version to enforce. Default: 2.6 -minimum-python-version=2.7 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# Maximum number of arguments for function / method. -max-args=35 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in an if statement (see R0916). -max-bool-expr=5 - -# Maximum number of branch for function / method body. -max-branches=48 - -# Maximum number of locals for function / method body. -max-locals=40 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body. -max-returns=6 - -# Maximum number of statements in function / method body. -max-statements=100 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=yes - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=yes - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules=regsub, - TERMIOS, - Bastion, - rexec - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled). -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled). -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - [BLACKLISTED-FUNCTIONS] # List of blacklisted functions and suggested replacements @@ -700,11 +759,5 @@ allowed-3rd-party-modules=msgpack, looseversion, pytestskipmarkers, cryptography, + aiohttp, pytest_timeout - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "BaseException, Exception". -overgeneral-exceptions=BaseException, - Exception diff --git a/noxfile.py b/noxfile.py index 2ed8e4d0a00..1a78e4628ae 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1300,7 +1300,7 @@ def decompress_dependencies(session): # Let's try to fix shebang's try: fpath = pathlib.Path(path) - contents = fpath.read_text().splitlines() + contents = fpath.read_text(encoding="utf-8").splitlines() if ( contents[0].startswith("#!") and contents[0].endswith("python") @@ -1310,7 +1310,9 @@ def decompress_dependencies(session): "Fixing broken shebang in %r", str(fpath.relative_to(REPO_ROOT)), ) - fpath.write_text("\n".join([fixed_shebang] + contents[1:])) + fpath.write_text( + "\n".join([fixed_shebang] + contents[1:]), encoding="utf-8" + ) except UnicodeDecodeError: pass @@ -1467,48 +1469,26 @@ class Tee: return self._first.fileno() -def _lint( - session, rcfile, flags, paths, tee_output=True, upgrade_setuptools_and_pip=True -): +def _lint(session, rcfile, flags, paths, upgrade_setuptools_and_pip=True): if _upgrade_pip_setuptools_and_wheel(session, upgrade=upgrade_setuptools_and_pip): - requirements_file = os.path.join( + base_requirements_file = os.path.join( + "requirements", "static", "ci", _get_pydir(session), "linux.txt" + ) + lint_requirements_file = os.path.join( "requirements", "static", "ci", _get_pydir(session), "lint.txt" ) - install_command = ["--progress-bar=off", "-r", requirements_file] + install_command = [ + "--progress-bar=off", + "-r", + base_requirements_file, + "-r", + lint_requirements_file, + ] session.install(*install_command, silent=PIP_INSTALL_SILENT) - if tee_output: - session.run("pylint", "--version") - pylint_report_path = os.environ.get("PYLINT_REPORT") - cmd_args = ["pylint", "--rcfile={}".format(rcfile)] + list(flags) + list(paths) - cmd_kwargs = {"env": {"PYTHONUNBUFFERED": "1"}} - - if tee_output: - stdout = tempfile.TemporaryFile(mode="w+b") - cmd_kwargs["stdout"] = Tee(stdout, sys.__stdout__) - - lint_failed = False - try: - session.run(*cmd_args, **cmd_kwargs) - except CommandFailed: - lint_failed = True - raise - finally: - if tee_output: - stdout.seek(0) - contents = stdout.read() - if contents: - contents = contents.decode("utf-8") - sys.stdout.write(contents) - sys.stdout.flush() - if pylint_report_path: - # Write report - with open(pylint_report_path, "w") as wfh: - wfh.write(contents) - session.log("Report file written to %r", pylint_report_path) - stdout.close() + session.run(*cmd_args, **cmd_kwargs) def _lint_pre_commit(session, rcfile, flags, paths): @@ -1527,26 +1507,17 @@ def _lint_pre_commit(session, rcfile, flags, paths): from nox.virtualenv import VirtualEnv # Let's patch nox to make it run inside the pre-commit virtualenv - try: - session._runner.venv = VirtualEnv( # pylint: disable=unexpected-keyword-arg - os.environ["VIRTUAL_ENV"], - interpreter=session._runner.func.python, - reuse_existing=True, - venv=True, - ) - except TypeError: - # This is still nox-py2 - session._runner.venv = VirtualEnv( - os.environ["VIRTUAL_ENV"], - interpreter=session._runner.func.python, - reuse_existing=True, - ) + session._runner.venv = VirtualEnv( + os.environ["VIRTUAL_ENV"], + interpreter=session._runner.func.python, + reuse_existing=True, + venv=True, + ) _lint( session, rcfile, flags, paths, - tee_output=False, upgrade_setuptools_and_pip=False, ) @@ -1554,7 +1525,7 @@ def _lint_pre_commit(session, rcfile, flags, paths): @nox.session(python="3") def lint(session): """ - Run PyLint against Salt and it's test suite. Set PYLINT_REPORT to a path to capture output. + Run PyLint against Salt and it's test suite. """ session.notify("lint-salt-{}".format(session.python)) session.notify("lint-tests-{}".format(session.python)) @@ -1563,21 +1534,21 @@ def lint(session): @nox.session(python="3", name="lint-salt") def lint_salt(session): """ - Run PyLint against Salt. Set PYLINT_REPORT to a path to capture output. + Run PyLint against Salt. """ flags = ["--disable=I"] if session.posargs: paths = session.posargs else: # TBD replace paths entries when implement pyproject.toml - paths = ["setup.py", "noxfile.py", "salt/"] + paths = ["setup.py", "noxfile.py", "salt/", "tools/"] _lint(session, ".pylintrc", flags, paths) @nox.session(python="3", name="lint-tests") def lint_tests(session): """ - Run PyLint against Salt and it's test suite. Set PYLINT_REPORT to a path to capture output. + Run PyLint against Salt and it's test suite. """ flags = ["--disable=I"] if session.posargs: @@ -1590,20 +1561,20 @@ def lint_tests(session): @nox.session(python=False, name="lint-salt-pre-commit") def lint_salt_pre_commit(session): """ - Run PyLint against Salt. Set PYLINT_REPORT to a path to capture output. + Run PyLint against Salt. """ flags = ["--disable=I"] if session.posargs: paths = session.posargs else: - paths = ["setup.py", "noxfile.py", "salt/"] + paths = ["setup.py", "noxfile.py", "salt/", "tools/"] _lint_pre_commit(session, ".pylintrc", flags, paths) @nox.session(python=False, name="lint-tests-pre-commit") def lint_tests_pre_commit(session): """ - Run PyLint against Salt and it's test suite. Set PYLINT_REPORT to a path to capture output. + Run PyLint against Salt and it's test suite. """ flags = ["--disable=I"] if session.posargs: @@ -1960,8 +1931,8 @@ def ci_test_onedir_pkgs(session): + cmd_args[:] + [ "--no-install", - f"--junitxml=artifacts/xml-unittests-output/test-results-install.xml", - f"--log-file=artifacts/logs/runtests-install.log", + "--junitxml=artifacts/xml-unittests-output/test-results-install.xml", + "--log-file=artifacts/logs/runtests-install.log", ] + session.posargs ) @@ -1978,8 +1949,8 @@ def ci_test_onedir_pkgs(session): + cmd_args[:] + [ "--no-install", - f"--junitxml=artifacts/xml-unittests-output/test-results-install-rerun.xml", - f"--log-file=artifacts/logs/runtests-install-rerun.log", + "--junitxml=artifacts/xml-unittests-output/test-results-install-rerun.xml", + "--log-file=artifacts/logs/runtests-install-rerun.log", "--lf", ] + session.posargs diff --git a/requirements/static/ci/lint.in b/requirements/static/ci/lint.in index 86ed3a61c28..977c91fcd47 100644 --- a/requirements/static/ci/lint.in +++ b/requirements/static/ci/lint.in @@ -2,6 +2,6 @@ --constraint=./py{py_version}/{platform}.txt docker -pylint==2.4.4 -SaltPyLint>=2023.3.8 +pylint~=3.1.0 +SaltPyLint>=2024.2.2 toml diff --git a/requirements/static/ci/py3.10/lint.txt b/requirements/static/ci/py3.10/lint.txt index fbcaa9b1269..3841c2aad37 100644 --- a/requirements/static/ci/py3.10/lint.txt +++ b/requirements/static/ci/py3.10/lint.txt @@ -33,7 +33,7 @@ asn1crypto==1.3.0 # -c requirements/static/ci/py3.10/linux.txt # certvalidator # oscrypto -astroid==2.3.3 +astroid==3.1.0 # via pylint async-timeout==4.0.2 # via @@ -145,6 +145,8 @@ cryptography==42.0.3 # paramiko # pyopenssl # vcert +dill==0.3.8 + # via pylint distlib==0.3.2 # via # -c requirements/static/ci/py3.10/linux.txt @@ -285,8 +287,6 @@ kubernetes==3.0.0 # via # -c requirements/static/ci/py3.10/linux.txt # -r requirements/static/ci/common.in -lazy-object-proxy==1.4.3 - # via astroid libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" # via # -c requirements/static/ci/py3.10/linux.txt @@ -320,8 +320,6 @@ mercurial==6.0.1 # via # -c requirements/static/ci/py3.10/linux.txt # -r requirements/static/ci/linux.in -modernize==0.5 - # via saltpylint more-itertools==5.0.0 # via # -c requirements/static/ci/../pkg/py3.10/linux.txt @@ -385,6 +383,7 @@ pathtools==0.1.2 platformdirs==2.2.0 # via # -c requirements/static/ci/py3.10/linux.txt + # pylint # virtualenv portend==2.4 # via @@ -405,8 +404,6 @@ pyasn1==0.4.8 # -c requirements/static/ci/py3.10/linux.txt # pyasn1-modules # rsa -pycodestyle==2.5.0 - # via saltpylint pycparser==2.21 ; python_version >= "3.9" # via # -c requirements/static/ci/../pkg/py3.10/linux.txt @@ -435,7 +432,7 @@ pyjwt==2.4.0 # via # -c requirements/static/ci/py3.10/linux.txt # twilio -pylint==2.4.4 +pylint==3.1.0 # via # -r requirements/static/ci/lint.in # saltpylint @@ -571,7 +568,7 @@ s3transfer==0.5.2 # via # -c requirements/static/ci/py3.10/linux.txt # boto3 -saltpylint==2023.8.3 +saltpylint==2024.2.5 # via -r requirements/static/ci/lint.in scp==0.13.2 # via @@ -591,7 +588,6 @@ six==1.16.0 # -c requirements/static/ci/../pkg/py3.10/linux.txt # -c requirements/static/ci/py3.10/linux.txt # apscheduler - # astroid # cassandra-driver # cheroot # etcd3-py @@ -646,6 +642,12 @@ toml==0.10.2 # -c requirements/static/ci/py3.10/linux.txt # -r requirements/static/ci/common.in # -r requirements/static/ci/lint.in +tomli==2.0.1 + # via + # -c requirements/static/ci/py3.10/linux.txt + # pylint +tomlkit==0.12.3 + # via pylint tornado==6.1 # via # -c requirements/static/ci/py3.10/linux.txt @@ -658,6 +660,10 @@ twilio==7.9.2 # via # -c requirements/static/ci/py3.10/linux.txt # -r requirements/static/ci/linux.in +typing-extensions==4.8.0 + # via + # -c requirements/static/ci/py3.10/linux.txt + # astroid tzlocal==3.0 # via # -c requirements/static/ci/py3.10/linux.txt @@ -696,8 +702,6 @@ werkzeug==3.0.1 # via # -c requirements/static/ci/py3.10/linux.txt # moto -wrapt==1.11.1 - # via astroid xmltodict==0.12.0 # via # -c requirements/static/ci/py3.10/linux.txt diff --git a/requirements/static/ci/py3.11/lint.txt b/requirements/static/ci/py3.11/lint.txt index e1b74f92032..19dbac9d26f 100644 --- a/requirements/static/ci/py3.11/lint.txt +++ b/requirements/static/ci/py3.11/lint.txt @@ -33,7 +33,7 @@ asn1crypto==1.3.0 # -c requirements/static/ci/py3.11/linux.txt # certvalidator # oscrypto -astroid==2.3.3 +astroid==3.1.0 # via pylint attrs==23.1.0 # via @@ -141,6 +141,8 @@ cryptography==42.0.3 # paramiko # pyopenssl # vcert +dill==0.3.8 + # via pylint distlib==0.3.2 # via # -c requirements/static/ci/py3.11/linux.txt @@ -276,8 +278,6 @@ kubernetes==3.0.0 # via # -c requirements/static/ci/py3.11/linux.txt # -r requirements/static/ci/common.in -lazy-object-proxy==1.4.3 - # via astroid libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" # via # -c requirements/static/ci/py3.11/linux.txt @@ -306,8 +306,6 @@ mercurial==6.0.1 # via # -c requirements/static/ci/py3.11/linux.txt # -r requirements/static/ci/linux.in -modernize==0.5 - # via saltpylint more-itertools==5.0.0 # via # -c requirements/static/ci/../pkg/py3.11/linux.txt @@ -360,6 +358,7 @@ pathtools==0.1.2 platformdirs==2.2.0 # via # -c requirements/static/ci/py3.11/linux.txt + # pylint # virtualenv portend==2.4 # via @@ -380,8 +379,6 @@ pyasn1==0.4.8 # -c requirements/static/ci/py3.11/linux.txt # pyasn1-modules # rsa -pycodestyle==2.5.0 - # via saltpylint pycparser==2.21 ; python_version >= "3.9" # via # -c requirements/static/ci/../pkg/py3.11/linux.txt @@ -410,7 +407,7 @@ pyjwt==2.4.0 # via # -c requirements/static/ci/py3.11/linux.txt # twilio -pylint==2.4.4 +pylint==3.1.0 # via # -r requirements/static/ci/lint.in # saltpylint @@ -536,7 +533,7 @@ s3transfer==0.5.2 # via # -c requirements/static/ci/py3.11/linux.txt # boto3 -saltpylint==2023.8.3 +saltpylint==2024.2.5 # via -r requirements/static/ci/lint.in semantic-version==2.9.0 # via @@ -552,7 +549,6 @@ six==1.16.0 # -c requirements/static/ci/../pkg/py3.11/linux.txt # -c requirements/static/ci/py3.11/linux.txt # apscheduler - # astroid # cassandra-driver # cheroot # etcd3-py @@ -604,6 +600,8 @@ toml==0.10.2 # -c requirements/static/ci/py3.11/linux.txt # -r requirements/static/ci/common.in # -r requirements/static/ci/lint.in +tomlkit==0.12.3 + # via pylint tornado==6.1 # via # -c requirements/static/ci/py3.11/linux.txt @@ -650,8 +648,6 @@ werkzeug==3.0.1 # via # -c requirements/static/ci/py3.11/linux.txt # moto -wrapt==1.11.1 - # via astroid xmltodict==0.12.0 # via # -c requirements/static/ci/py3.11/linux.txt diff --git a/requirements/static/ci/py3.12/lint.txt b/requirements/static/ci/py3.12/lint.txt index 777079138cc..0f9d5f8f2b3 100644 --- a/requirements/static/ci/py3.12/lint.txt +++ b/requirements/static/ci/py3.12/lint.txt @@ -33,7 +33,7 @@ asn1crypto==1.3.0 # -c requirements/static/ci/py3.12/linux.txt # certvalidator # oscrypto -astroid==2.3.3 +astroid==3.1.0 # via pylint attrs==23.1.0 # via @@ -141,6 +141,8 @@ cryptography==42.0.3 # paramiko # pyopenssl # vcert +dill==0.3.8 + # via pylint distlib==0.3.2 # via # -c requirements/static/ci/py3.12/linux.txt @@ -276,8 +278,6 @@ kubernetes==3.0.0 # via # -c requirements/static/ci/py3.12/linux.txt # -r requirements/static/ci/common.in -lazy-object-proxy==1.4.3 - # via astroid libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" # via # -c requirements/static/ci/py3.12/linux.txt @@ -306,8 +306,6 @@ mercurial==6.0.1 # via # -c requirements/static/ci/py3.12/linux.txt # -r requirements/static/ci/linux.in -modernize==0.5 - # via saltpylint more-itertools==5.0.0 # via # -c requirements/static/ci/../pkg/py3.12/linux.txt @@ -360,6 +358,7 @@ pathtools==0.1.2 platformdirs==2.2.0 # via # -c requirements/static/ci/py3.12/linux.txt + # pylint # virtualenv portend==2.4 # via @@ -380,8 +379,6 @@ pyasn1==0.4.8 # -c requirements/static/ci/py3.12/linux.txt # pyasn1-modules # rsa -pycodestyle==2.5.0 - # via saltpylint pycparser==2.21 ; python_version >= "3.9" # via # -c requirements/static/ci/../pkg/py3.12/linux.txt @@ -410,7 +407,7 @@ pyjwt==2.4.0 # via # -c requirements/static/ci/py3.12/linux.txt # twilio -pylint==2.4.4 +pylint==3.1.0 # via # -r requirements/static/ci/lint.in # saltpylint @@ -536,7 +533,7 @@ s3transfer==0.5.2 # via # -c requirements/static/ci/py3.12/linux.txt # boto3 -saltpylint==2023.8.3 +saltpylint==2024.2.5 # via -r requirements/static/ci/lint.in semantic-version==2.9.0 # via @@ -552,7 +549,6 @@ six==1.16.0 # -c requirements/static/ci/../pkg/py3.12/linux.txt # -c requirements/static/ci/py3.12/linux.txt # apscheduler - # astroid # cassandra-driver # cheroot # etcd3-py @@ -604,6 +600,8 @@ toml==0.10.2 # -c requirements/static/ci/py3.12/linux.txt # -r requirements/static/ci/common.in # -r requirements/static/ci/lint.in +tomlkit==0.12.3 + # via pylint tornado==6.1 # via # -c requirements/static/ci/py3.12/linux.txt @@ -650,8 +648,6 @@ werkzeug==3.0.1 # via # -c requirements/static/ci/py3.12/linux.txt # moto -wrapt==1.11.1 - # via astroid xmltodict==0.12.0 # via # -c requirements/static/ci/py3.12/linux.txt diff --git a/requirements/static/ci/py3.7/lint.txt b/requirements/static/ci/py3.7/lint.txt deleted file mode 100644 index bc9fea72e56..00000000000 --- a/requirements/static/ci/py3.7/lint.txt +++ /dev/null @@ -1,796 +0,0 @@ -# -# This file is autogenerated by pip-compile -# To update, run: -# -# pip-compile --no-emit-index-url --output-file=requirements/static/ci/py3.7/lint.txt requirements/base.txt requirements/static/ci/common.in requirements/static/ci/lint.in requirements/static/ci/linux.in requirements/static/pkg/linux.in requirements/zeromq.txt -# -aiohttp==3.8.6 - # via - # -c requirements/static/ci/py3.7/linux.txt - # etcd3-py -aiosignal==1.2.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp -apache-libcloud==2.5.0 ; sys_platform != "win32" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -apscheduler==3.6.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # python-telegram-bot -asn1crypto==1.3.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # certvalidator - # oscrypto -astroid==2.3.3 - # via pylint -async-timeout==4.0.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp -asynctest==0.13.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp -attrs==23.1.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp - # jsonschema -backports.entry-points-selectable==1.1.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # virtualenv -backports.zoneinfo==0.2.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # tzlocal -bcrypt==4.1.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # paramiko -boto3==1.21.46 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # moto -boto==2.49.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -botocore==1.24.46 - # via - # -c requirements/static/ci/py3.7/linux.txt - # boto3 - # moto - # s3transfer -cached-property==1.5.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # pygit2 -cachetools==4.2.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # google-auth - # python-telegram-bot -cassandra-driver==3.23.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -certifi==2023.07.22 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # kubernetes - # python-telegram-bot - # requests -certvalidator==0.11.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # vcert -cffi==1.14.6 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # cryptography - # napalm - # pygit2 - # pynacl -charset-normalizer==3.2.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp - # requests -cheetah3==3.2.6.post2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -cheroot==8.5.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cherrypy -cherrypy==18.6.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # -r requirements/static/pkg/linux.in -ciscoconfparse==1.5.19 - # via - # -c requirements/static/ci/py3.7/linux.txt - # napalm -click==7.1.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # geomet -clustershell==1.8.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -colorama==0.4.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # ciscoconfparse -contextvars==2.4 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt -croniter==0.3.29 ; sys_platform != "win32" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -cryptography==42.0.3 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in - # etcd3-py - # moto - # paramiko - # pyopenssl - # vcert -distlib==0.3.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # virtualenv -distro==1.5.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt -dnspython==1.16.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # ciscoconfparse - # python-etcd -docker==6.1.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/lint.in -etcd3-py==0.1.6 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -filelock==3.0.12 - # via - # -c requirements/static/ci/py3.7/linux.txt - # virtualenv -frozenlist==1.3.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp - # aiosignal -future==0.18.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # napalm - # textfsm -genshi==0.7.5 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -geomet==0.1.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # cassandra-driver -gitdb==4.0.7 - # via - # -c requirements/static/ci/py3.7/linux.txt - # gitpython -gitpython==3.1.41 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -google-auth==2.1.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # kubernetes -hglib==2.6.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -idna==3.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # etcd3-py - # requests - # yarl -immutables==0.15 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # contextvars -importlib-metadata==4.6.4 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in - # attrs - # backports.entry-points-selectable - # jsonschema - # mako - # moto - # virtualenv -ipaddress==1.0.22 - # via - # -c requirements/static/ci/py3.7/linux.txt - # kubernetes -isort==4.3.21 - # via pylint -jaraco.classes==3.2.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # jaraco.collections -jaraco.collections==3.4.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cherrypy -jaraco.functools==2.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cheroot - # jaraco.text - # tempora -jaraco.text==3.5.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # jaraco.collections -jinja2==3.1.3 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt - # junos-eznc - # moto - # napalm -jmespath==1.0.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt - # -r requirements/static/ci/common.in - # boto3 - # botocore -jsonschema==3.2.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -junos-eznc==2.4.0 ; sys_platform != "win32" and python_version <= "3.10" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # napalm -jxmlease==1.0.1 ; sys_platform != "win32" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -kazoo==2.6.1 ; sys_platform != "win32" and sys_platform != "darwin" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -keyring==5.7.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -kubernetes==3.0.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -lazy-object-proxy==1.4.3 - # via astroid -libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -looseversion==1.0.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt -lxml==4.9.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc - # napalm - # ncclient -mako==1.2.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -markupsafe==2.1.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt - # jinja2 - # mako - # moto - # werkzeug -mccabe==0.6.1 - # via pylint -mercurial==6.0.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -modernize==0.5 - # via saltpylint -more-itertools==5.0.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cheroot - # cherrypy - # jaraco.classes - # jaraco.functools -moto==3.0.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -msgpack==1.0.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt -multidict==6.0.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp - # yarl -napalm==3.1.0 ; sys_platform != "win32" and python_version < "3.10" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -ncclient==0.6.4 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc -netaddr==0.7.19 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc - # napalm - # pyeapi -netmiko==3.2.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # napalm -ntc-templates==1.4.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc -oscrypto==1.2.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # certvalidator -packaging==22.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt - # docker -paramiko==3.4.0 ; sys_platform != "win32" and sys_platform != "darwin" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # junos-eznc - # napalm - # ncclient - # netmiko - # scp -passlib==1.7.4 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # ciscoconfparse -pathspec==0.9.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # yamllint -pathtools==0.1.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # watchdog -platformdirs==2.2.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # virtualenv -portend==2.4 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cherrypy -psutil==5.8.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt -pyasn1-modules==0.2.4 - # via - # -c requirements/static/ci/py3.7/linux.txt - # google-auth -pyasn1==0.4.8 - # via - # -c requirements/static/ci/py3.7/linux.txt - # pyasn1-modules - # rsa -pycodestyle==2.5.0 - # via saltpylint -pycparser==2.17 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cffi -pycryptodomex==3.19.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/crypto.txt -pyeapi==0.8.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # napalm -pygit2==1.10.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -pyiface==0.0.11 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -pyjwt==2.4.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # twilio -pylint==2.4.4 - # via - # -r requirements/static/ci/lint.in - # saltpylint -pymysql==1.0.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -pynacl==1.5.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # paramiko -pyopenssl==24.0.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in - # etcd3-py -pyparsing==3.0.9 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc -pyrsistent==0.17.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # jsonschema -pyserial==3.4 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc - # netmiko -python-consul==1.1.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -python-dateutil==2.8.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in - # botocore - # croniter - # kubernetes - # moto - # vcert -python-etcd==0.4.5 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -python-gnupg==0.4.8 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in -python-telegram-bot==13.7 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -pytz==2022.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # apscheduler - # moto - # python-telegram-bot - # tempora - # twilio -pyvmomi==6.7.1.2018.12 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -pyyaml==6.0.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt - # clustershell - # junos-eznc - # kubernetes - # napalm - # yamllint - # yamlordereddictloader -pyzmq==23.2.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/zeromq.txt -redis-py-cluster==2.1.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -redis==3.5.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # redis-py-cluster -requests==2.31.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/base.txt - # -r requirements/static/ci/common.in - # apache-libcloud - # docker - # etcd3-py - # kubernetes - # moto - # napalm - # python-consul - # pyvmomi - # responses - # twilio - # vcert -responses==0.10.6 - # via - # -c requirements/static/ci/py3.7/linux.txt - # moto -rfc3987==1.3.8 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -rpm-vercmp==0.1.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in -rsa==4.7.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # google-auth -s3transfer==0.5.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # boto3 -saltpylint==2023.8.3 - # via -r requirements/static/ci/lint.in -scp==0.13.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc - # napalm - # netmiko -semantic-version==2.9.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # etcd3-py -setproctitle==1.3.2 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in -six==1.16.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # apscheduler - # astroid - # cassandra-driver - # cheroot - # etcd3-py - # genshi - # geomet - # jsonschema - # junos-eznc - # kazoo - # kubernetes - # more-itertools - # ncclient - # python-consul - # python-dateutil - # pyvmomi - # responses - # textfsm - # transitions - # vcert - # virtualenv - # websocket-client -slack-bolt==1.15.5 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -slack-sdk==3.19.5 - # via - # -c requirements/static/ci/py3.7/linux.txt - # slack-bolt -smmap==4.0.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # gitdb -sqlparse==0.4.4 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -strict-rfc3339==0.7 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -tempora==4.1.1 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # portend -terminal==0.4.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # ntc-templates -textfsm==1.1.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # napalm - # netmiko - # ntc-templates -timelib==0.2.5 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/pkg/linux.in -toml==0.10.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in - # -r requirements/static/ci/lint.in -tornado==6.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # python-telegram-bot -transitions==0.8.9 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc -twilio==7.9.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -typed-ast==1.4.1 - # via astroid -typing-extensions==3.10.0.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp - # async-timeout - # gitpython - # importlib-metadata - # yarl -tzlocal==3.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # apscheduler -urllib3==1.26.18 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # botocore - # docker - # kubernetes - # python-etcd - # requests -vcert==0.7.4 ; sys_platform != "win32" - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -virtualenv==20.7.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -watchdog==0.10.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -websocket-client==0.40.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # docker - # kubernetes -wempy==0.2.1 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/common.in -werkzeug==2.2.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # moto -wrapt==1.11.1 - # via astroid -xmltodict==0.12.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # moto -yamllint==1.26.3 - # via - # -c requirements/static/ci/py3.7/linux.txt - # -r requirements/static/ci/linux.in -yamlordereddictloader==0.4.0 - # via - # -c requirements/static/ci/py3.7/linux.txt - # junos-eznc -yarl==1.7.2 - # via - # -c requirements/static/ci/py3.7/linux.txt - # aiohttp -zc.lockfile==1.4 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # cherrypy -zipp==3.5.0 - # via - # -c requirements/static/ci/../pkg/py3.7/linux.txt - # -c requirements/static/ci/py3.7/linux.txt - # importlib-metadata - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/requirements/static/ci/py3.8/lint.txt b/requirements/static/ci/py3.8/lint.txt index f230eca7800..114395d2fbe 100644 --- a/requirements/static/ci/py3.8/lint.txt +++ b/requirements/static/ci/py3.8/lint.txt @@ -25,7 +25,7 @@ asn1crypto==1.3.0 # -c requirements/static/ci/py3.8/linux.txt # certvalidator # oscrypto -astroid==2.3.3 +astroid==3.1.0 # via pylint async-timeout==4.0.2 # via @@ -149,6 +149,8 @@ cryptography==42.0.3 # paramiko # pyopenssl # vcert +dill==0.3.8 + # via pylint distlib==0.3.2 # via # -c requirements/static/ci/py3.8/linux.txt @@ -296,8 +298,6 @@ kubernetes==3.0.0 # via # -c requirements/static/ci/py3.8/linux.txt # -r requirements/static/ci/common.in -lazy-object-proxy==1.4.3 - # via astroid libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" # via # -c requirements/static/ci/py3.8/linux.txt @@ -332,8 +332,6 @@ mercurial==6.0.1 # via # -c requirements/static/ci/py3.8/linux.txt # -r requirements/static/ci/linux.in -modernize==0.5 - # via saltpylint more-itertools==5.0.0 # via # -c requirements/static/ci/../pkg/py3.8/linux.txt @@ -413,6 +411,7 @@ pathtools==0.1.2 platformdirs==2.2.0 # via # -c requirements/static/ci/py3.8/linux.txt + # pylint # virtualenv portend==2.4 # via @@ -433,8 +432,6 @@ pyasn1==0.4.8 # -c requirements/static/ci/py3.8/linux.txt # pyasn1-modules # rsa -pycodestyle==2.5.0 - # via saltpylint pycparser==2.17 # via # -c requirements/static/ci/../pkg/py3.8/linux.txt @@ -465,7 +462,7 @@ pyjwt==2.4.0 # via # -c requirements/static/ci/py3.8/linux.txt # twilio -pylint==2.4.4 +pylint==3.1.0 # via # -r requirements/static/ci/lint.in # saltpylint @@ -599,7 +596,7 @@ s3transfer==0.5.2 # via # -c requirements/static/ci/py3.8/linux.txt # boto3 -saltpylint==2023.8.3 +saltpylint==2024.2.5 # via -r requirements/static/ci/lint.in scp==0.13.2 # via @@ -621,7 +618,6 @@ six==1.16.0 # -c requirements/static/ci/../pkg/py3.8/linux.txt # -c requirements/static/ci/py3.8/linux.txt # apscheduler - # astroid # cassandra-driver # cheroot # etcd3-py @@ -687,6 +683,12 @@ toml==0.10.2 # -c requirements/static/ci/py3.8/linux.txt # -r requirements/static/ci/common.in # -r requirements/static/ci/lint.in +tomli==2.0.1 + # via + # -c requirements/static/ci/py3.8/linux.txt + # pylint +tomlkit==0.12.3 + # via pylint tornado==6.1 # via # -c requirements/static/ci/py3.8/linux.txt @@ -699,6 +701,11 @@ twilio==7.9.2 # via # -c requirements/static/ci/py3.8/linux.txt # -r requirements/static/ci/linux.in +typing-extensions==4.8.0 + # via + # -c requirements/static/ci/py3.8/linux.txt + # astroid + # pylint tzlocal==3.0 # via # -c requirements/static/ci/py3.8/linux.txt @@ -737,8 +744,6 @@ werkzeug==3.0.1 # via # -c requirements/static/ci/py3.8/linux.txt # moto -wrapt==1.11.1 - # via astroid xmltodict==0.12.0 # via # -c requirements/static/ci/py3.8/linux.txt diff --git a/requirements/static/ci/py3.9/lint.txt b/requirements/static/ci/py3.9/lint.txt index eac557ef05f..5c47a8a493e 100644 --- a/requirements/static/ci/py3.9/lint.txt +++ b/requirements/static/ci/py3.9/lint.txt @@ -25,7 +25,7 @@ asn1crypto==1.3.0 # -c requirements/static/ci/py3.9/linux.txt # certvalidator # oscrypto -astroid==2.3.3 +astroid==3.1.0 # via pylint async-timeout==4.0.2 # via @@ -145,6 +145,8 @@ cryptography==42.0.3 # paramiko # pyopenssl # vcert +dill==0.3.8 + # via pylint distlib==0.3.2 # via # -c requirements/static/ci/py3.9/linux.txt @@ -292,8 +294,6 @@ kubernetes==3.0.0 # via # -c requirements/static/ci/py3.9/linux.txt # -r requirements/static/ci/common.in -lazy-object-proxy==1.4.3 - # via astroid libnacl==1.7.1 ; sys_platform != "win32" and sys_platform != "darwin" # via # -c requirements/static/ci/py3.9/linux.txt @@ -328,8 +328,6 @@ mercurial==6.0.1 # via # -c requirements/static/ci/py3.9/linux.txt # -r requirements/static/ci/linux.in -modernize==0.5 - # via saltpylint more-itertools==5.0.0 # via # -c requirements/static/ci/../pkg/py3.9/linux.txt @@ -409,6 +407,7 @@ pathtools==0.1.2 platformdirs==2.2.0 # via # -c requirements/static/ci/py3.9/linux.txt + # pylint # virtualenv portend==2.4 # via @@ -429,8 +428,6 @@ pyasn1==0.4.8 # -c requirements/static/ci/py3.9/linux.txt # pyasn1-modules # rsa -pycodestyle==2.5.0 - # via saltpylint pycparser==2.21 ; python_version >= "3.9" # via # -c requirements/static/ci/../pkg/py3.9/linux.txt @@ -463,7 +460,7 @@ pyjwt==2.4.0 # via # -c requirements/static/ci/py3.9/linux.txt # twilio -pylint==2.4.4 +pylint==3.1.0 # via # -r requirements/static/ci/lint.in # saltpylint @@ -597,7 +594,7 @@ s3transfer==0.5.2 # via # -c requirements/static/ci/py3.9/linux.txt # boto3 -saltpylint==2023.8.3 +saltpylint==2024.2.5 # via -r requirements/static/ci/lint.in scp==0.13.2 # via @@ -619,7 +616,6 @@ six==1.16.0 # -c requirements/static/ci/../pkg/py3.9/linux.txt # -c requirements/static/ci/py3.9/linux.txt # apscheduler - # astroid # cassandra-driver # cheroot # etcd3-py @@ -685,6 +681,12 @@ toml==0.10.2 # -c requirements/static/ci/py3.9/linux.txt # -r requirements/static/ci/common.in # -r requirements/static/ci/lint.in +tomli==2.0.1 + # via + # -c requirements/static/ci/py3.9/linux.txt + # pylint +tomlkit==0.12.3 + # via pylint tornado==6.1 # via # -c requirements/static/ci/py3.9/linux.txt @@ -697,6 +699,11 @@ twilio==7.9.2 # via # -c requirements/static/ci/py3.9/linux.txt # -r requirements/static/ci/linux.in +typing-extensions==4.8.0 + # via + # -c requirements/static/ci/py3.9/linux.txt + # astroid + # pylint tzlocal==3.0 # via # -c requirements/static/ci/py3.9/linux.txt @@ -735,8 +742,6 @@ werkzeug==3.0.1 # via # -c requirements/static/ci/py3.9/linux.txt # moto -wrapt==1.11.1 - # via astroid xmltodict==0.12.0 # via # -c requirements/static/ci/py3.9/linux.txt diff --git a/salt/_logging/impl.py b/salt/_logging/impl.py index 2bcc27a0761..9ffa5320301 100644 --- a/salt/_logging/impl.py +++ b/salt/_logging/impl.py @@ -169,7 +169,7 @@ class SaltLoggingClass(LOGGING_LOGGER_CLASS, metaclass=LoggingMixinMeta): logging.getLogger(__name__) """ - instance = super().__new__(cls) + instance = super().__new__(cls) # pylint: disable=no-value-for-parameter try: max_logger_length = len( diff --git a/salt/auth/pki.py b/salt/auth/pki.py index f33e3ccf00c..1c9d6f205a2 100644 --- a/salt/auth/pki.py +++ b/salt/auth/pki.py @@ -84,11 +84,10 @@ def auth(username, password, **kwargs): if cert.verify(cacert.get_pubkey()): log.info("Successfully authenticated certificate: %s", pem) return True - else: - log.info("Failed to authenticate certificate: %s", pem) - return False + log.info("Failed to authenticate certificate: %s", pem) + return False - c = OpenSSL.crypto + c = OpenSSL.crypto # pylint: disable=used-before-assignment cert = c.load_certificate(c.FILETYPE_PEM, pem) with salt.utils.files.fopen(cacert_file) as f: @@ -101,7 +100,7 @@ def auth(username, password, **kwargs): cert_asn1 = c.dump_certificate(c.FILETYPE_ASN1, cert) # Decode the certificate - der = asn1.DerSequence() + der = asn1.DerSequence() # pylint: disable=used-before-assignment der.decode(cert_asn1) # The certificate has three parts: diff --git a/salt/channel/client.py b/salt/channel/client.py index 499041d0c73..8d43406728e 100644 --- a/salt/channel/client.py +++ b/salt/channel/client.py @@ -225,7 +225,7 @@ class AsyncReqChannel: if HAS_M2: aes = key.private_decrypt(ret["key"], RSA.pkcs1_oaep_padding) else: - cipher = PKCS1_OAEP.new(key) + cipher = PKCS1_OAEP.new(key) # pylint: disable=used-before-assignment aes = cipher.decrypt(ret["key"]) # Decrypt using the public key. diff --git a/salt/channel/server.py b/salt/channel/server.py index 4d7cd23fc29..e4eabd40076 100644 --- a/salt/channel/server.py +++ b/salt/channel/server.py @@ -206,7 +206,7 @@ class ReqServerChannel: if HAS_M2: pret["key"] = pub.public_encrypt(key, RSA.pkcs1_oaep_padding) else: - cipher = PKCS1_OAEP.new(pub) + cipher = PKCS1_OAEP.new(pub) # pylint: disable=used-before-assignment pret["key"] = cipher.encrypt(key) if ret is False: ret = {} diff --git a/salt/cli/batch.py b/salt/cli/batch.py index 8e1547c61d4..ca1f464a8d4 100644 --- a/salt/cli/batch.py +++ b/salt/cli/batch.py @@ -90,7 +90,10 @@ class Batch: """ Return the active number of minions to maintain """ - partition = lambda x: float(x) / 100.0 * len(self.minions) + + def partition(x): + return float(x) / 100.0 * len(self.minions) + try: if isinstance(self.opts["batch"], str) and "%" in self.opts["batch"]: res = partition(float(self.opts["batch"].strip("%"))) diff --git a/salt/cli/cp.py b/salt/cli/cp.py index 457be4b044e..42ebfd9d515 100644 --- a/salt/cli/cp.py +++ b/salt/cli/cp.py @@ -68,7 +68,7 @@ class SaltCP: except OSError as exc: if exc.errno == errno.ENOENT: # Path does not exist - sys.stderr.write("{} does not exist\n".format(path)) + sys.stderr.write(f"{path} does not exist\n") sys.exit(42) elif exc.errno in (errno.EINVAL, errno.ENOTDIR): # Path is a file (EINVAL on Windows, ENOTDIR otherwise) @@ -97,7 +97,7 @@ class SaltCP: Take a path and return the contents of the file as a string """ if not os.path.isfile(fn_): - err = "The referenced file, {} is not available.".format(fn_) + err = f"The referenced file, {fn_} is not available." sys.stderr.write(err + "\n") sys.exit(42) with salt.utils.files.fopen(fn_, "r") as fp_: @@ -211,12 +211,10 @@ class SaltCP: log.debug( "Copying %s to %starget '%s' as %s%s", fn_, - "{} ".format(selected_target_option) - if selected_target_option - else "", + f"{selected_target_option} " if selected_target_option else "", tgt, remote_path, - " (chunk #{})".format(index) if append else "", + f" (chunk #{index})" if append else "", ) args = [ tgt, @@ -261,11 +259,7 @@ class SaltCP: log.debug( "Creating empty dir %s on %starget '%s'", dirname, - "{} ".format( - selected_target_option - ) # pylint: disable=str-format-in-logging - if selected_target_option - else "", + f"{selected_target_option} " if selected_target_option else "", tgt, ) args = [tgt, "cp.recv_chunked", [remote_path, None], timeout] diff --git a/salt/client/__init__.py b/salt/client/__init__.py index ebfbea48e7a..cfda90d5782 100644 --- a/salt/client/__init__.py +++ b/salt/client/__init__.py @@ -8,7 +8,6 @@ The data structure needs to be: 'key': ''} """ - import logging # The components here are simple, and they need to be and stay simple, we @@ -1296,7 +1295,7 @@ class LocalClient: except KeyError as exc: # This is a safe pass. We're just using the try/except to # avoid having to deep-check for keys. - missing_key = exc.__str__().strip("'\"") + missing_key = str(exc).strip("'\"") if missing_key == "retcode": log.debug("retcode missing from client return") else: diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py index e24c0b45344..a5f681569d1 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -559,7 +559,7 @@ class SSH(MultiprocessingStateMixin): try: retcode = int(retcode) except (TypeError, ValueError): - log.warning(f"Got an invalid retcode for host '{host}': '{retcode}'") + log.warning("Got an invalid retcode for host '%s': '%s'", host, retcode) retcode = 1 # This job is done, yield try: @@ -573,7 +573,9 @@ class SSH(MultiprocessingStateMixin): retcode = int(remote_retcode) except (TypeError, ValueError): log.warning( - f"Host '{host}' reported an invalid retcode: '{remote_retcode}'" + "Host '%s' reported an invalid retcode: '%s'", + host, + remote_retcode, ) retcode = max(retcode, 1) except (KeyError, TypeError): @@ -599,7 +601,7 @@ class SSH(MultiprocessingStateMixin): """ que = multiprocessing.Queue() running = {} - target_iter = self.targets.__iter__() + target_iter = iter(self.targets) returned = set() rets = set() init = False @@ -829,7 +831,7 @@ class SSH(MultiprocessingStateMixin): for ret, retcode in self.handle_ssh(): host = next(iter(ret)) if not isinstance(retcode, int): - log.warning(f"Host '{host}' returned an invalid retcode: {retcode}") + log.warning("Host '%s' returned an invalid retcode: %s", host, retcode) retcode = 1 final_exit = max(final_exit, retcode) @@ -1784,7 +1786,7 @@ def ssh_version(): ["ssh", "-V"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ).communicate() try: - version_parts = ret[1].split(b",")[0].split(b"_")[1] + version_parts = ret[1].split(b",", maxsplit=1)[0].split(b"_")[1] parts = [] for part in version_parts: try: diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py index 9b8f9e0f658..f0b697d0ac4 100644 --- a/salt/client/ssh/ssh_py_shim.py +++ b/salt/client/ssh/ssh_py_shim.py @@ -41,7 +41,6 @@ ARGS = None # The below line is where OPTIONS can be redefined with internal options # (rather than cli arguments) when the shim is bundled by # client.ssh.Single._cmd_str() -# pylint: disable=block-comment-should-start-with-cardinal-space #%%OPTS @@ -230,7 +229,9 @@ def get_executable(): Find executable which matches supported python version in the thin """ pymap = {} - with open(os.path.join(OPTIONS.saltdir, "supported-versions")) as _fp: + with open( + os.path.join(OPTIONS.saltdir, "supported-versions"), encoding="utf-8" + ) as _fp: for line in _fp.readlines(): ns, v_maj, v_min = line.strip().split(":") pymap[ns] = (int(v_maj), int(v_min)) @@ -314,7 +315,7 @@ def main(argv): # pylint: disable=W0613 ) ) need_deployment() - with open(code_checksum_path, "r") as vpo: + with open(code_checksum_path, "r", encoding="utf-8") as vpo: cur_code_cs = vpo.readline().strip() if cur_code_cs != OPTIONS.code_checksum: sys.stderr.write( @@ -330,7 +331,7 @@ def main(argv): # pylint: disable=W0613 sys.stderr.write('ERROR: thin is missing "{0}"\n'.format(salt_call_path)) need_deployment() - with open(os.path.join(OPTIONS.saltdir, "minion"), "w") as config: + with open(os.path.join(OPTIONS.saltdir, "minion"), "w", encoding="utf-8") as config: config.write(OPTIONS.config + "\n") if OPTIONS.ext_mods: ext_path = os.path.join(OPTIONS.saltdir, EXT_ARCHIVE) @@ -340,7 +341,7 @@ def main(argv): # pylint: disable=W0613 version_path = os.path.join(OPTIONS.saltdir, "ext_version") if not os.path.exists(version_path) or not os.path.isfile(version_path): need_ext() - with open(version_path, "r") as vpo: + with open(version_path, "r", encoding="utf-8") as vpo: cur_version = vpo.readline().strip() if cur_version != OPTIONS.ext_mods: need_ext() diff --git a/salt/client/ssh/wrapper/grains.py b/salt/client/ssh/wrapper/grains.py index bbacdb4ea4f..92446f4018e 100644 --- a/salt/client/ssh/wrapper/grains.py +++ b/salt/client/ssh/wrapper/grains.py @@ -23,21 +23,28 @@ def _serial_sanitizer(instr): return "{}{}".format(instr[:index], "X" * (length - index)) -_FQDN_SANITIZER = lambda x: "MINION.DOMAINNAME" -_HOSTNAME_SANITIZER = lambda x: "MINION" -_DOMAINNAME_SANITIZER = lambda x: "DOMAINNAME" +def _fqdn_sanitizer(x): + return "MINION.DOMAINNAME" + + +def _hostname_sanitizer(x): + return "MINION" + + +def _domainname_sanitizer(x): + return "DOMAINNAME" # A dictionary of grain -> function mappings for sanitizing grain output. This # is used when the 'sanitize' flag is given. _SANITIZERS = { "serialnumber": _serial_sanitizer, - "domain": _DOMAINNAME_SANITIZER, - "fqdn": _FQDN_SANITIZER, - "id": _FQDN_SANITIZER, - "host": _HOSTNAME_SANITIZER, - "localhost": _HOSTNAME_SANITIZER, - "nodename": _HOSTNAME_SANITIZER, + "domain": _domainname_sanitizer, + "fqdn": _fqdn_sanitizer, + "id": _fqdn_sanitizer, + "host": _hostname_sanitizer, + "localhost": _hostname_sanitizer, + "nodename": _hostname_sanitizer, } diff --git a/salt/client/ssh/wrapper/pillar.py b/salt/client/ssh/wrapper/pillar.py index bc1b625d5cb..f085771614c 100644 --- a/salt/client/ssh/wrapper/pillar.py +++ b/salt/client/ssh/wrapper/pillar.py @@ -12,7 +12,9 @@ try: from collections.abc import Mapping except ImportError: # We still allow Py2 import because this could be executed in a machine with Py2. - from collections import Mapping # pylint: disable=no-name-in-module + from collections import ( # pylint: disable=no-name-in-module,deprecated-class + Mapping, + ) def get(key, default="", merge=False, delimiter=DEFAULT_TARGET_DELIM): diff --git a/salt/cloud/cli.py b/salt/cloud/cli.py index f458e975c63..c633dce3b77 100644 --- a/salt/cloud/cli.py +++ b/salt/cloud/cli.py @@ -174,11 +174,11 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): msg = "The following virtual machines are set to be destroyed:\n" names = set() for alias, drivers in matching.items(): - msg += " {}:\n".format(alias) + msg += f" {alias}:\n" for driver, vms in drivers.items(): - msg += " {}:\n".format(driver) + msg += f" {driver}:\n" for name in vms: - msg += " {}\n".format(name) + msg += f" {name}\n" names.add(name) try: if self.print_confirm(msg): @@ -212,7 +212,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): key, value = name.split("=", 1) kwargs[key] = value else: - msg += " {}\n".format(name) + msg += f" {name}\n" machines.append(name) names = machines @@ -255,7 +255,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): elif self.options.set_password: username = self.credential_username - provider_name = "salt.cloud.provider.{}".format(self.credential_provider) + provider_name = f"salt.cloud.provider.{self.credential_provider}" # TODO: check if provider is configured # set the password salt.utils.cloud.store_password_in_keyring(provider_name, username) @@ -275,7 +275,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): # display profile errors msg += "Found the following errors:\n" for profile_name, error in dmap["errors"].items(): - msg += " {}: {}\n".format(profile_name, error) + msg += f" {profile_name}: {error}\n" sys.stderr.write(msg) sys.stderr.flush() @@ -283,17 +283,17 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): if "existing" in dmap: msg += "The following virtual machines already exist:\n" for name in dmap["existing"]: - msg += " {}\n".format(name) + msg += f" {name}\n" if dmap["create"]: msg += "The following virtual machines are set to be created:\n" for name in dmap["create"]: - msg += " {}\n".format(name) + msg += f" {name}\n" if "destroy" in dmap: msg += "The following virtual machines are set to be destroyed:\n" for name in dmap["destroy"]: - msg += " {}\n".format(name) + msg += f" {name}\n" if not dmap["create"] and not dmap.get("destroy", None): if not dmap.get("existing", None): @@ -382,19 +382,17 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): # This is a salt cloud system exit if exc.exit_code > 0: # the exit code is bigger than 0, it's an error - msg = "Error: {}".format(msg) + msg = f"Error: {msg}" self.exit(exc.exit_code, msg.format(exc).rstrip() + "\n") # It's not a system exit but it's an error we can # handle self.error(msg.format(exc)) # This is a generic exception, log it, include traceback if # debug logging is enabled and exit. - # pylint: disable=str-format-in-logging log.error( msg.format(exc), # Show the traceback if the debug logging level is # enabled exc_info_on_loglevel=logging.DEBUG, ) - # pylint: enable=str-format-in-logging self.exit(salt.defaults.exitcodes.EX_GENERIC) diff --git a/salt/cloud/clouds/aliyun.py b/salt/cloud/clouds/aliyun.py index 9b1b318885b..572f0cfde96 100644 --- a/salt/cloud/clouds/aliyun.py +++ b/salt/cloud/clouds/aliyun.py @@ -798,7 +798,7 @@ def query(params=None): signature = _compute_signature(parameters, access_key_secret) parameters["Signature"] = signature - request = requests.get(path, params=parameters, verify=True) + request = requests.get(path, params=parameters, verify=True, timeout=120) if request.status_code != 200: raise SaltCloudSystemExit( "An error occurred while querying aliyun ECS. HTTP Code: {} " diff --git a/salt/cloud/clouds/clc.py b/salt/cloud/clouds/clc.py index c111c49a481..88ed72b1295 100644 --- a/salt/cloud/clouds/clc.py +++ b/salt/cloud/clouds/clc.py @@ -308,7 +308,7 @@ def get_build_status(req_id, nodename): counter = 0 req_id = str(req_id) while counter < 10: - queue = clc.v1.Blueprint.GetStatus(request_id=(req_id)) + queue = clc.v1.Blueprint.GetStatus(request_id=req_id) if queue["PercentComplete"] == 100: server_name = queue["Servers"][0] creds = get_creds() diff --git a/salt/cloud/clouds/digitalocean.py b/salt/cloud/clouds/digitalocean.py index 8c3cf54f05f..7f843f22ab1 100644 --- a/salt/cloud/clouds/digitalocean.py +++ b/salt/cloud/clouds/digitalocean.py @@ -474,9 +474,14 @@ def create(vm_): dns_hostname, dns_domain, ) - __add_dns_addr__ = lambda t, d: post_dns_record( - dns_domain=dns_domain, name=dns_hostname, record_type=t, record_data=d - ) + + def __add_dns_addr__(t, d): + return post_dns_record( + dns_domain=dns_domain, + name=dns_hostname, + record_type=t, + record_data=d, + ) log.debug("create_dns_record: %s", __add_dns_addr__) else: @@ -639,6 +644,7 @@ def query( "Authorization": "Bearer " + personal_access_token, "Content-Type": "application/json", }, + timeout=120, ) if request.status_code > 299: raise SaltCloudSystemExit( diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 3c8ea286bce..571b0c04674 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -403,7 +403,7 @@ def query( log.trace("EC2 Request Parameters: %s", params_with_headers) try: result = requests.get( - requesturl, headers=headers, params=params_with_headers + requesturl, headers=headers, params=params_with_headers, timeout=120 ) log.debug( "EC2 Response Status Code: %s", @@ -1198,9 +1198,9 @@ def get_imageid(vm_): "Filter.0.Value.0": image, } # Query AWS, sort by 'creationDate' and get the last imageId - _t = lambda x: datetime.datetime.strptime( - x["creationDate"], "%Y-%m-%dT%H:%M:%S.%fZ" - ) + def _t(x): + return datetime.datetime.strptime(x["creationDate"], "%Y-%m-%dT%H:%M:%S.%fZ") + image_id = sorted( aws.query( params, diff --git a/salt/cloud/clouds/joyent.py b/salt/cloud/clouds/joyent.py index 58b853b3f00..cd68508f43a 100644 --- a/salt/cloud/clouds/joyent.py +++ b/salt/cloud/clouds/joyent.py @@ -1168,8 +1168,8 @@ def query(action=None, command=None, args=None, method="GET", location=None, dat digest = md.final() signed = rsa_key.sign(digest, algo="sha256") else: - rsa_ = PKCS1_v1_5.new(rsa_key) - hash_ = SHA256.new() + rsa_ = PKCS1_v1_5.new(rsa_key) # pylint: disable=used-before-assignment + hash_ = SHA256.new() # pylint: disable=used-before-assignment hash_.update(timestamp.encode(__salt_system_encoding__)) signed = rsa_.sign(hash_) signed = base64.b64encode(signed) diff --git a/salt/cloud/clouds/linode.py b/salt/cloud/clouds/linode.py index 72c985f148e..99850b3936a 100644 --- a/salt/cloud/clouds/linode.py +++ b/salt/cloud/clouds/linode.py @@ -530,7 +530,9 @@ class LinodeAPIv4(LinodeAPI): attempt = 0 while True: try: - result = requests.request(method, url, json=data, headers=headers) + result = requests.request( + method, url, json=data, headers=headers, timeout=120 + ) log.debug("Linode API response status code: %d", result.status_code) log.trace("Linode API response body: %s", result.text) @@ -1092,7 +1094,9 @@ class LinodeAPIv4(LinodeAPI): "entity.type": entity, } last_event = None - condition = lambda event: self._check_event_status(event, status) + + def condition(event): + return self._check_event_status(event, status) while True: if last_event is not None: @@ -1965,8 +1969,8 @@ class LinodeAPIv3(LinodeAPI): for key, val in ips.items(): if key == linode_id: - this_node["private_ips"] = val["private_ips"] - this_node["public_ips"] = val["public_ips"] + this_node["private_ips"] = val[1] + this_node["public_ips"] = val[0] if full: this_node["extra"] = node diff --git a/salt/cloud/clouds/proxmox.py b/salt/cloud/clouds/proxmox.py index e293ad4067f..61340f0928f 100644 --- a/salt/cloud/clouds/proxmox.py +++ b/salt/cloud/clouds/proxmox.py @@ -137,7 +137,9 @@ def _authenticate(): connect_data = {"username": username, "password": passwd} full_url = "https://{}:{}/api2/json/access/ticket".format(url, port) - response = requests.post(full_url, verify=verify_ssl, data=connect_data) + response = requests.post( + full_url, verify=verify_ssl, data=connect_data, timeout=120 + ) response.raise_for_status() returned_data = response.json() @@ -171,6 +173,7 @@ def query(conn_type, option, post_data=None): data=post_data, cookies=ticket, headers=httpheaders, + timeout=120, ) elif conn_type == "put": httpheaders["CSRFPreventionToken"] = csrf @@ -180,6 +183,7 @@ def query(conn_type, option, post_data=None): data=post_data, cookies=ticket, headers=httpheaders, + timeout=120, ) elif conn_type == "delete": httpheaders["CSRFPreventionToken"] = csrf @@ -189,9 +193,12 @@ def query(conn_type, option, post_data=None): data=post_data, cookies=ticket, headers=httpheaders, + timeout=120, ) elif conn_type == "get": - response = requests.get(full_url, verify=verify_ssl, cookies=ticket) + response = requests.get( + full_url, verify=verify_ssl, cookies=ticket, timeout=120 + ) try: response.raise_for_status() @@ -862,7 +869,7 @@ def _import_api(): """ global api full_url = "https://{}:{}/pve-docs/api-viewer/apidoc.js".format(url, port) - returned_data = requests.get(full_url, verify=verify_ssl) + returned_data = requests.get(full_url, verify=verify_ssl, timeout=120) re_filter = re.compile(" (?:pveapi|apiSchema) = (.*)^;", re.DOTALL | re.MULTILINE) api_json = re_filter.findall(returned_data.text)[0] diff --git a/salt/cloud/clouds/qingcloud.py b/salt/cloud/clouds/qingcloud.py index b684f6bc9d8..fd2f179b758 100644 --- a/salt/cloud/clouds/qingcloud.py +++ b/salt/cloud/clouds/qingcloud.py @@ -179,7 +179,7 @@ def query(params=None): # print('parameters:') # pprint.pprint(real_parameters) - request = requests.get(path, params=real_parameters, verify=verify_ssl) + request = requests.get(path, params=real_parameters, verify=verify_ssl, timeout=120) # print('url:') # print(request.url) @@ -439,7 +439,7 @@ def _get_size(vm_): if not vm_size: raise SaltCloudNotFound("No size specified for this instance.") - if vm_size in sizes.keys(): + if vm_size in sizes: return vm_size raise SaltCloudNotFound( diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index 68fa1c821ab..72dcac96c20 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -1628,7 +1628,7 @@ def _get_snapshots(snapshot_list, current_snapshot=None, parent_snapshot_path="" snapshots[snapshot_path] = { "name": snapshot.name, "description": snapshot.description, - "created": str(snapshot.createTime).split(".")[0], + "created": str(snapshot.createTime).split(".", maxsplit=1)[0], "state": snapshot.state, "path": snapshot_path, } diff --git a/salt/config/schemas/common.py b/salt/config/schemas/common.py index f8d164abfed..9105ed39266 100644 --- a/salt/config/schemas/common.py +++ b/salt/config/schemas/common.py @@ -47,7 +47,7 @@ class MinionDefaultInclude(DefaultIncludeConfig): class MasterDefaultInclude(DefaultIncludeConfig): __target__ = "master" - __confd_directory = "master.d" + __confd_directory = "master.d" # pylint: disable=unused-private-member class IncludeConfig(Schema): diff --git a/salt/engines/slack.py b/salt/engines/slack.py index 969a6bcd1f2..b6c868c0dbb 100644 --- a/salt/engines/slack.py +++ b/salt/engines/slack.py @@ -890,8 +890,6 @@ class SlackClient: if cmd in runner_functions: runner = salt.runner.RunnerClient(__opts__) log.debug("Command %s will run via runner_functions", cmd) - # pylint is tripping - # pylint: disable=missing-whitespace-after-comma job_id_dict = runner.asynchronous(cmd, {"arg": args, "kwarg": kwargs}) job_id = job_id_dict["jid"] diff --git a/salt/engines/slack_bolt_engine.py b/salt/engines/slack_bolt_engine.py index 75eb0909e48..ca4f1791371 100644 --- a/salt/engines/slack_bolt_engine.py +++ b/salt/engines/slack_bolt_engine.py @@ -995,8 +995,6 @@ class SlackClient: if cmd in runner_functions: runner = salt.runner.RunnerClient(__opts__) log.debug("Command %s will run via runner_functions", cmd) - # pylint is tripping - # pylint: disable=missing-whitespace-after-comma job_id_dict = runner.asynchronous(cmd, {"arg": args, "kwarg": kwargs}) job_id = job_id_dict["jid"] diff --git a/salt/ext/backports_abc.py b/salt/ext/backports_abc.py index da4cb329832..64669416f3e 100644 --- a/salt/ext/backports_abc.py +++ b/salt/ext/backports_abc.py @@ -87,7 +87,7 @@ def mk_gen(): return True return NotImplemented - generator = type((lambda: (yield))()) + generator = type((lambda: (yield))()) # pylint: disable=unnecessary-direct-lambda-call Generator.register(generator) return Generator diff --git a/salt/ext/ipaddress.py b/salt/ext/ipaddress.py index 9ce8ba83d88..f1ee6bcaf38 100644 --- a/salt/ext/ipaddress.py +++ b/salt/ext/ipaddress.py @@ -2162,8 +2162,7 @@ class IPv6Interface(IPv6Address): return x def __str__(self): - return '%s/%d' % (super().__str__(), - self._prefixlen) + return '%s/%d' % (super(), self._prefixlen) def __eq__(self, other): address_equal = IPv6Address.__eq__(self, other) diff --git a/salt/ext/tornado/platform/auto.pyi b/salt/ext/tornado/platform/auto.pyi index a1c97228a43..03eb7d1bf20 100644 --- a/salt/ext/tornado/platform/auto.pyi +++ b/salt/ext/tornado/platform/auto.pyi @@ -1,4 +1,4 @@ # auto.py is full of patterns mypy doesn't like, so for type checking # purposes we replace it with interface.py. -from .interface import * +from .interface import * # pylint: disable=unused-wildcard-import,wildcard-import diff --git a/salt/fileserver/s3fs.py b/salt/fileserver/s3fs.py index d013ea3b193..f946eb2019b 100644 --- a/salt/fileserver/s3fs.py +++ b/salt/fileserver/s3fs.py @@ -726,7 +726,7 @@ def _get_file_from_s3(metadata, saltenv, bucket_name, path, cached_file_path): if cached_md5 == file_md5: return else: - log.info(f"found different hash for file {path}, updating...") + log.info("found different hash for file %s, updating...", path) else: cached_file_stat = os.stat(cached_file_path) cached_file_size = cached_file_stat.st_size @@ -762,6 +762,7 @@ def _get_file_from_s3(metadata, saltenv, bucket_name, path, cached_file_path): https_enable=https_enable, ) if ret is not None: + s3_file_mtime = s3_file_size = None for header_name, header_value in ret["headers"].items(): name = header_name.strip() value = header_value.strip() @@ -771,9 +772,8 @@ def _get_file_from_s3(metadata, saltenv, bucket_name, path, cached_file_path): ) elif str(name).lower() == "content-length": s3_file_size = int(value) - if ( - cached_file_size == s3_file_size - and cached_file_mtime > s3_file_mtime + if (s3_file_size and cached_file_size == s3_file_size) and ( + s3_file_mtime and cached_file_mtime > s3_file_mtime ): log.info( "%s - %s : %s skipped download since cached file size " diff --git a/salt/grains/core.py b/salt/grains/core.py index df53ccddd45..2edbcde420b 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -2910,8 +2910,8 @@ def ip_fqdn(): if not ret["ipv" + ipv_num]: ret[key] = [] else: + start_time = datetime.datetime.utcnow() try: - start_time = datetime.datetime.utcnow() info = socket.getaddrinfo(_fqdn, None, socket_type) ret[key] = list({item[4][0] for item in info}) except (OSError, UnicodeError): diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py index 8198b4f62e9..5ad3c6c6d0b 100644 --- a/salt/loader/lazy.py +++ b/salt/loader/lazy.py @@ -15,7 +15,7 @@ import time import traceback import types from collections.abc import MutableMapping -from zipimport import zipimporter +from zipimport import zipimporter # pylint: disable=no-name-in-module import salt.config import salt.defaults.events diff --git a/salt/master.py b/salt/master.py index e91ab24e2bb..2dbf519d1dd 100644 --- a/salt/master.py +++ b/salt/master.py @@ -769,7 +769,9 @@ class Master(SMaster): mod = ".".join(proc.split(".")[:-1]) cls = proc.split(".")[-1] _tmp = __import__(mod, globals(), locals(), [cls], -1) - cls = _tmp.__getattribute__(cls) + cls = _tmp.__getattribute__( # pylint: disable=unnecessary-dunder-call + cls + ) name = "ExtProcess({})".format(cls.__qualname__) self.process_manager.add_process(cls, args=(self.opts,), name=name) except Exception: # pylint: disable=broad-except diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py index 58a6fa85f68..d143cdcee07 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py @@ -239,7 +239,7 @@ if not HAS_APT: opts = _get_opts(self.line) self.architectures.extend(opts["arch"]["value"]) self.signedby = opts["signedby"]["value"] - for opt in opts.keys(): + for opt in opts: opt = opts[opt]["full"] if opt: try: @@ -1609,9 +1609,11 @@ def _get_upgradable(dist_upgrade=True, **kwargs): # rexp parses lines that look like the following: # Conf libxfont1 (1:1.4.5-1 Debian:testing [i386]) - rexp = re.compile("(?m)^Conf " "([^ ]+) " r"\(([^ ]+)") # Package name # Version + rexp = re.compile(r"(?m)^Conf ([^ ]+) \(([^ ]+)") # Package name # Version keys = ["name", "version"] - _get = lambda l, k: l[keys.index(k)] + + def _get(line, k): + return line[keys.index(k)] upgrades = rexp.findall(out) @@ -1685,7 +1687,10 @@ def version_cmp(pkg1, pkg2, ignore_epoch=False, **kwargs): salt '*' pkg.version_cmp '0.2.4-0ubuntu1' '0.2.4.1-0ubuntu1' """ - normalize = lambda x: str(x).split(":", 1)[-1] if ignore_epoch else str(x) + + def normalize(x): + return str(x).split(":", 1)[-1] if ignore_epoch else str(x) + # both apt_pkg.version_compare and _cmd_quote need string arguments. pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) diff --git a/salt/modules/archive.py b/salt/modules/archive.py index 3f91cd9cefe..e7be041bc66 100644 --- a/salt/modules/archive.py +++ b/salt/modules/archive.py @@ -380,7 +380,7 @@ def list_( dirs, files, links = func(name, cached, *args) except OSError as exc: raise CommandExecutionError( - "Failed to list contents of {}: {}".format(name, exc.__str__()) + "Failed to list contents of {}: {}".format(name, exc) ) except CommandExecutionError as exc: raise @@ -395,9 +395,7 @@ def list_( log.debug("Cleaned cached archive %s", cached) except OSError as exc: if exc.errno != errno.ENOENT: - log.warning( - "Failed to clean cached archive %s: %s", cached, exc.__str__() - ) + log.warning("Failed to clean cached archive %s: %s", cached, exc) if strip_components: for item in (dirs, files, links): @@ -796,8 +794,8 @@ def zip_(zip_file, sources, template=None, cwd=None, runas=None, zip64=False): os.setegid(uinfo["gid"]) os.seteuid(uinfo["uid"]) + exc = None try: - exc = None archived_files = [] with contextlib.closing( zipfile.ZipFile(zip_file, "w", zipfile.ZIP_DEFLATED, zip64) @@ -1203,7 +1201,7 @@ def is_encrypted(name, clean=False, saltenv="base", source_hash=None, use_etag=F "{} is not a ZIP file".format(name), info=archive_info ) except Exception as exc: # pylint: disable=broad-except - raise CommandExecutionError(exc.__str__(), info=archive_info) + raise CommandExecutionError(exc, info=archive_info) else: ret = False @@ -1213,9 +1211,7 @@ def is_encrypted(name, clean=False, saltenv="base", source_hash=None, use_etag=F log.debug("Cleaned cached archive %s", cached) except OSError as exc: if exc.errno != errno.ENOENT: - log.warning( - "Failed to clean cached archive %s: %s", cached, exc.__str__() - ) + log.warning("Failed to clean cached archive %s: %s", cached, exc) return ret diff --git a/salt/modules/boto3_route53.py b/salt/modules/boto3_route53.py index 32c971356c2..88a9b1b2cfc 100644 --- a/salt/modules/boto3_route53.py +++ b/salt/modules/boto3_route53.py @@ -946,7 +946,7 @@ def _aws_decode(x): if "\\" in x: return x.decode("unicode_escape") - if type(x) == bytes: + if isinstance(x, bytes): return x.decode("idna") return x diff --git a/salt/modules/boto3_sns.py b/salt/modules/boto3_sns.py index 65ab6283f51..46026693b54 100644 --- a/salt/modules/boto3_sns.py +++ b/salt/modules/boto3_sns.py @@ -137,7 +137,7 @@ def topic_exists(name, region=None, key=None, keyid=None, profile=None): salt myminion boto3_sns.topic_exists mytopic region=us-east-1 """ topics = list_topics(region=region, key=key, keyid=keyid, profile=profile) - return name in list(topics.values() + topics.keys()) + return name in list(topics.values()) + list(topics) def create_topic(Name, region=None, key=None, keyid=None, profile=None): diff --git a/salt/modules/btrfs.py b/salt/modules/btrfs.py index 4b02eb21afa..6adf421009b 100644 --- a/salt/modules/btrfs.py +++ b/salt/modules/btrfs.py @@ -223,7 +223,10 @@ def _usage_specific(raw): """ Parse usage/specific. """ - get_key = lambda val: dict([tuple(val.split(":"))]) + + def get_key(val): + return dict([tuple(val.split(":"))]) + raw = raw.split("\n") section, size, used = raw[0].split(" ") section = section.replace(",", "_").replace(":", "").lower() diff --git a/salt/modules/consul.py b/salt/modules/consul.py index 205cfb202bd..dfcf84c0ab8 100644 --- a/salt/modules/consul.py +++ b/salt/modules/consul.py @@ -75,7 +75,7 @@ def _query( data = None else: if data is not None: - if type(data) != str: + if not isinstance(data, str): data = salt.utils.json.dumps(data) else: data = salt.utils.json.dumps({}) diff --git a/salt/modules/cp.py b/salt/modules/cp.py index 64666aefa5d..07554808386 100644 --- a/salt/modules/cp.py +++ b/salt/modules/cp.py @@ -115,7 +115,7 @@ def recv_chunked(dest, chunk, append=False, compressed=True, mode=None): if os.path.isfile(dest): return "Path exists and is a file" else: - return _error(exc.__str__()) + return _error(str(exc)) return True chunk = base64.b64decode(chunk) @@ -126,12 +126,12 @@ def recv_chunked(dest, chunk, append=False, compressed=True, mode=None): except OSError as exc: if exc.errno != errno.ENOENT: # Parent dir does not exist, we need to create it - return _error(exc.__str__()) + return _error(str(exc)) try: os.makedirs(os.path.dirname(dest)) except OSError as makedirs_exc: # Failed to make directory - return _error(makedirs_exc.__str__()) + return _error(str(makedirs_exc)) fh_ = salt.utils.files.fopen(dest, open_mode) # pylint: disable=W8470 try: @@ -139,7 +139,7 @@ def recv_chunked(dest, chunk, append=False, compressed=True, mode=None): fh_.write(salt.utils.gzip_util.uncompress(chunk) if compressed else chunk) except OSError as exc: # Write failed - return _error(exc.__str__()) + return _error(str(exc)) else: # Write successful if not append and mode is not None: @@ -149,7 +149,7 @@ def recv_chunked(dest, chunk, append=False, compressed=True, mode=None): try: os.chmod(dest, mode) except OSError: - return _error(exc.__str__()) + return _error(str(exc)) return True finally: try: diff --git a/salt/modules/cryptdev.py b/salt/modules/cryptdev.py index 40c28d17f10..ec195245ccb 100644 --- a/salt/modules/cryptdev.py +++ b/salt/modules/cryptdev.py @@ -263,7 +263,10 @@ def set_crypttab( criteria = entry.pick(match_on) except KeyError: - filterFn = lambda key: key not in _crypttab_entry.crypttab_keys + + def filterFn(key): + return key not in _crypttab_entry.crypttab_keys + invalid_keys = filter(filterFn, match_on) msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) diff --git a/salt/modules/csf.py b/salt/modules/csf.py index 1ab12cab941..63b3cb01ba6 100644 --- a/salt/modules/csf.py +++ b/salt/modules/csf.py @@ -29,7 +29,7 @@ def _temp_exists(method, ip): """ _type = method.replace("temp", "").upper() cmd = ( - "csf -t | awk -v code=1 -v type=_type -v ip=ip '$1==type && $2==ip {{code=0}}" + "csf -t | awk -v code=1 -v type={_type} -v ip={ip} '$1==type && $2==ip {{code=0}}" " END {{exit code}}'".format(_type=_type, ip=ip) ) exists = __salt__["cmd.run_all"](cmd) diff --git a/salt/modules/datadog_api.py b/salt/modules/datadog_api.py index 57ce01953f6..7a18f903b45 100644 --- a/salt/modules/datadog_api.py +++ b/salt/modules/datadog_api.py @@ -157,7 +157,9 @@ def cancel_downtime(api_key=None, app_key=None, scope=None, id=None): elif scope: params = {"api_key": api_key, "application_key": app_key, "scope": scope} response = requests.post( - "https://app.datadoghq.com/api/v1/downtime/cancel/by_scope", params=params + "https://app.datadoghq.com/api/v1/downtime/cancel/by_scope", + params=params, + timeout=120, ) if response.status_code == 200: ret["result"] = True diff --git a/salt/modules/dig.py b/salt/modules/dig.py index ea0463075d4..a78e4875ded 100644 --- a/salt/modules/dig.py +++ b/salt/modules/dig.py @@ -314,7 +314,7 @@ def MX(domain, resolve=False, nameserver=None): stdout = [x.split() for x in cmd["stdout"].split("\n")] if resolve: - return [(lambda x: [x[0], A(x[1], nameserver)[0]])(x) for x in stdout] + return [[x[0], A(x[1], nameserver)[0]] for x in stdout] return stdout diff --git a/salt/modules/disk.py b/salt/modules/disk.py index fb78906b18f..c7e5f905c07 100644 --- a/salt/modules/disk.py +++ b/salt/modules/disk.py @@ -49,7 +49,7 @@ def _parse_numbers(text): "Z": "10E21", "Y": "10E24", } - if text[-1] in postPrefixes.keys(): + if text[-1] in postPrefixes: v = decimal.Decimal(text[:-1]) v = v * decimal.Decimal(postPrefixes[text[-1]]) return v diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py index f9ffd2dda9e..49036f0f756 100644 --- a/salt/modules/dockermod.py +++ b/salt/modules/dockermod.py @@ -399,7 +399,6 @@ def _get_client(timeout=NOTSET, **kwargs): docker_machine_tls["ClientKeyPath"], ), ca_cert=docker_machine_tls["CaCertPath"], - assert_hostname=False, verify=True, ) except Exception as exc: # pylint: disable=broad-except @@ -690,9 +689,9 @@ def _client_wrapper(attr, *args, **kwargs): raise except docker.errors.DockerException as exc: # More general docker exception (catches InvalidVersion, etc.) - raise CommandExecutionError(exc.__str__()) + raise CommandExecutionError(str(exc)) except Exception as exc: # pylint: disable=broad-except - err = exc.__str__() + err = str(exc) else: return ret @@ -1333,7 +1332,10 @@ def compare_networks(first, second, ignore="Name,Id,Created,Containers"): if bool(subval1) is bool(subval2) is False: continue elif subkey == "Config": - kvsort = lambda x: (list(x.keys()), list(x.values())) + + def kvsort(x): + return (list(x.keys()), list(x.values())) + config1 = sorted(val1["Config"], key=kvsort) config2 = sorted(val2.get("Config", []), key=kvsort) if config1 != config2: @@ -3312,7 +3314,7 @@ def create( except CommandExecutionError as exc: raise CommandExecutionError( "Failed to start container after creation", - info={"response": response, "error": exc.__str__()}, + info={"response": response, "error": str(exc)}, ) else: response["Started"] = True @@ -3502,7 +3504,7 @@ def run_container( f"Failed to auto_remove container: {rm_exc}" ) # Raise original exception with additional info - raise CommandExecutionError(exc.__str__(), info=exc_info) + raise CommandExecutionError(str(exc), info=exc_info) # Start the container output = [] @@ -3554,7 +3556,7 @@ def run_container( # it to other_errors as a fallback. exc_info.setdefault("other_errors", []).append(exc.info) # Re-raise with all of the available additional info - raise CommandExecutionError(exc.__str__(), info=exc_info) + raise CommandExecutionError(str(exc), info=exc_info) return ret @@ -4286,7 +4288,7 @@ def dangling(prune=False, force=False): try: ret.setdefault(image, {})["Removed"] = rmi(image, force=force) except Exception as exc: # pylint: disable=broad-except - err = exc.__str__() + err = str(exc) log.error(err) ret.setdefault(image, {})["Comment"] = err ret[image]["Removed"] = False @@ -4606,7 +4608,7 @@ def pull( except Exception as exc: # pylint: disable=broad-except raise CommandExecutionError( f"Unable to interpret API event: '{event}'", - info={"Error": exc.__str__()}, + info={"Error": str(exc)}, ) try: event_type = next(iter(event)) @@ -4700,7 +4702,7 @@ def push( except Exception as exc: # pylint: disable=broad-except raise CommandExecutionError( f"Unable to interpret API event: '{event}'", - info={"Error": exc.__str__()}, + info={"Error": str(exc)}, ) try: event_type = next(iter(event)) @@ -5496,7 +5498,7 @@ def disconnect_all_containers_from_network(network_id): disconnect_container_from_network(cname, network_id) ret.append(cname) except CommandExecutionError as exc: - msg = exc.__str__() + msg = str(exc) if "404" not in msg: # If 404 was in the error, then the container no longer exists, # so to avoid a race condition we won't consider 404 errors to diff --git a/salt/modules/ebuildpkg.py b/salt/modules/ebuildpkg.py index 0e8fd851066..1b268fa7476 100644 --- a/salt/modules/ebuildpkg.py +++ b/salt/modules/ebuildpkg.py @@ -148,9 +148,9 @@ def _process_emerge_err(stdout, stderr): if slot_conflicts: ret["slot conflicts"] = slot_conflicts - blocked = re.compile( - r"(?m)^\[blocks .+\] " r"([^ ]+/[^ ]+-[0-9]+[^ ]+)" r".*$" - ).findall(stdout) + blocked = re.compile(r"(?m)^\[blocks .+\] ([^ ]+/[^ ]+-[0-9]+[^ ]+).*$").findall( + stdout + ) unsatisfied = re.compile(r"Error: The above package list contains").findall(stderr) @@ -331,7 +331,9 @@ def _get_upgradable(backtrack=3): r".*$" ) keys = ["name", "version"] - _get = lambda l, k: l[keys.index(k)] + + def _get(line, k): + return line[keys.index(k)] upgrades = rexp.findall(out) diff --git a/salt/modules/file.py b/salt/modules/file.py index 69d7992f5ab..d65d3e9a15f 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -4027,7 +4027,7 @@ def readlink(path, canonicalize=False): except OSError as exc: if exc.errno == errno.EINVAL: raise CommandExecutionError("Not a symbolic link: {}".format(path)) - raise CommandExecutionError(exc.__str__()) + raise CommandExecutionError(str(exc)) def readdir(path): @@ -5927,7 +5927,7 @@ def get_diff( continue paths.append(cached_path) except MinionError as exc: - errors.append(salt.utils.stringutils.to_unicode(exc.__str__())) + errors.append(salt.utils.stringutils.to_unicode(str(exc))) continue if errors: diff --git a/salt/modules/freebsdjail.py b/salt/modules/freebsdjail.py index fc3c3ce04f3..1c2343195c7 100644 --- a/salt/modules/freebsdjail.py +++ b/salt/modules/freebsdjail.py @@ -38,7 +38,7 @@ def start(jail=""): salt '*' jail.start [] """ - cmd = "service jail onestart {}".format(jail) + cmd = f"service jail onestart {jail}" return not __salt__["cmd.retcode"](cmd) @@ -52,7 +52,7 @@ def stop(jail=""): salt '*' jail.stop [] """ - cmd = "service jail onestop {}".format(jail) + cmd = f"service jail onestop {jail}" return not __salt__["cmd.retcode"](cmd) @@ -66,7 +66,7 @@ def restart(jail=""): salt '*' jail.restart [] """ - cmd = "service jail onerestart {}".format(jail) + cmd = f"service jail onerestart {jail}" return not __salt__["cmd.retcode"](cmd) @@ -126,9 +126,7 @@ def show_config(jail): """ ret = {} if subprocess.call(["jls", "-nq", "-j", jail]) == 0: - jls = subprocess.check_output( - ["jls", "-nq", "-j", jail] - ) # pylint: disable=minimum-python-version + jls = subprocess.check_output(["jls", "-nq", "-j", jail]) jailopts = salt.utils.args.shlex_split(salt.utils.stringutils.to_unicode(jls)) for jailopt in jailopts: if "=" not in jailopt: @@ -145,7 +143,7 @@ def show_config(jail): line = salt.utils.stringutils.to_unicode(line) if not line.strip(): continue - if not line.startswith("jail_{}_".format(jail)): + if not line.startswith(f"jail_{jail}_"): continue key, value = line.split("=") ret[key.split("_", 2)[2]] = value.split('"')[1] diff --git a/salt/modules/git.py b/salt/modules/git.py index 62dd7028994..4af2e548de7 100644 --- a/salt/modules/git.py +++ b/salt/modules/git.py @@ -1067,7 +1067,7 @@ def clone( url, https_user, https_pass, https_only=True ) except ValueError as exc: - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) command = ["git"] + _format_git_opts(git_opts) command.append("clone") @@ -3044,7 +3044,7 @@ def ls_remote( remote, https_user, https_pass, https_only=True ) except ValueError as exc: - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) command = ["git"] + _format_git_opts(git_opts) command.append("ls-remote") command.extend(_format_opts(opts)) @@ -4051,7 +4051,7 @@ def remote_refs( ) ) except ValueError as exc: - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) if filter_: command.append(filter_) output = _git_run( @@ -4185,7 +4185,7 @@ def remote_set( url, https_user, https_pass, https_only=True ) except ValueError as exc: - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) command = ["git", "remote", "add", remote, url] _git_run( command, diff --git a/salt/modules/glassfish.py b/salt/modules/glassfish.py index 637264e7331..558db0809e5 100644 --- a/salt/modules/glassfish.py +++ b/salt/modules/glassfish.py @@ -126,6 +126,7 @@ def _api_get(path, server=None): auth=_get_auth(server["user"], server["password"]), headers=_get_headers(), verify=True, + timeout=120, ) return _api_response(response) @@ -141,6 +142,7 @@ def _api_post(path, data, server=None): headers=_get_headers(), data=salt.utils.json.dumps(data), verify=True, + timeout=120, ) return _api_response(response) @@ -156,6 +158,7 @@ def _api_delete(path, data, server=None): headers=_get_headers(), params=data, verify=True, + timeout=120, ) return _api_response(response) diff --git a/salt/modules/grains.py b/salt/modules/grains.py index 9c474a94a64..a7040e00b32 100644 --- a/salt/modules/grains.py +++ b/salt/modules/grains.py @@ -40,7 +40,9 @@ __outputter__ = { } # http://stackoverflow.com/a/12414913/127816 -_infinitedict = lambda: collections.defaultdict(_infinitedict) +def _infinitedict(): + return collections.defaultdict(_infinitedict) + _non_existent_key = "NonExistentValueMagicNumberSpK3hnufdHfeBUXCfqVK" @@ -54,21 +56,28 @@ def _serial_sanitizer(instr): return "{}{}".format(instr[:index], "X" * (length - index)) -_FQDN_SANITIZER = lambda x: "MINION.DOMAINNAME" -_HOSTNAME_SANITIZER = lambda x: "MINION" -_DOMAINNAME_SANITIZER = lambda x: "DOMAINNAME" +def _fqdn_sanitizer(x): + return "MINION.DOMAINNAME" + + +def _hostname_sanitizer(x): + return "MINION" + + +def _domainname_sanitizer(x): + return "DOMAINNAME" # A dictionary of grain -> function mappings for sanitizing grain output. This # is used when the 'sanitize' flag is given. _SANITIZERS = { "serialnumber": _serial_sanitizer, - "domain": _DOMAINNAME_SANITIZER, - "fqdn": _FQDN_SANITIZER, - "id": _FQDN_SANITIZER, - "host": _HOSTNAME_SANITIZER, - "localhost": _HOSTNAME_SANITIZER, - "nodename": _HOSTNAME_SANITIZER, + "domain": _domainname_sanitizer, + "fqdn": _fqdn_sanitizer, + "id": _fqdn_sanitizer, + "host": _hostname_sanitizer, + "localhost": _hostname_sanitizer, + "nodename": _hostname_sanitizer, } diff --git a/salt/modules/heat.py b/salt/modules/heat.py index 40540fe7cf0..c4ea3a5e9e1 100644 --- a/salt/modules/heat.py +++ b/salt/modules/heat.py @@ -241,9 +241,15 @@ def _poll_for_events( """ if action: stop_status = ("{}_FAILED".format(action), "{}_COMPLETE".format(action)) - stop_check = lambda a: a in stop_status + + def stop_check(a): + return a in stop_status + else: - stop_check = lambda a: a.endswith("_COMPLETE") or a.endswith("_FAILED") + + def stop_check(a): + return a.endswith("_COMPLETE") or a.endswith("_FAILED") + timeout_sec = timeout * 60 no_event_polls = 0 msg_template = "\n Stack %(name)s %(status)s \n" diff --git a/salt/modules/inspectlib/fsdb.py b/salt/modules/inspectlib/fsdb.py index b834b8f6783..787be0c0252 100644 --- a/salt/modules/inspectlib/fsdb.py +++ b/salt/modules/inspectlib/fsdb.py @@ -16,15 +16,12 @@ """ :codeauthor: Bo Maryniuk """ - - import csv import datetime import gzip import os import re import shutil -import sys from salt.utils.odict import OrderedDict @@ -182,12 +179,15 @@ class CsvDB: :param obj: :return: """ - get_type = lambda item: str(type(item)).split("'")[1] + + def get_type(item): + return str(type(item)).split("'")[1] + if not os.path.exists(os.path.join(self.db_path, obj._TABLE)): with gzip.open(os.path.join(self.db_path, obj._TABLE), "wt") as table_file: csv.writer(table_file).writerow( [ - "{col}:{type}".format(col=elm[0], type=get_type(elm[1])) + f"{elm[0]}:{get_type(elm[1])}" for elm in tuple(obj.__dict__.items()) ] ) @@ -270,7 +270,7 @@ class CsvDB: def _validate_object(self, obj): descr = self._tables.get(obj._TABLE) if descr is None: - raise Exception("Table {} not found.".format(obj._TABLE)) + raise Exception(f"Table {obj._TABLE} not found.") return obj._serialize(self._tables[obj._TABLE]) def __criteria(self, obj, matches=None, mt=None, lt=None, eq=None): @@ -333,14 +333,10 @@ class CsvDB: return objects def _to_type(self, data, type): - if type == "int": + if type in ("int", "long"): data = int(data) elif type == "float": data = float(data) - elif type == "long": - # pylint: disable=undefined-variable,incompatible-py3-code - data = sys.version_info[0] == 2 and long(data) or int(data) - # pylint: enable=undefined-variable,incompatible-py3-code else: data = str(data) return data diff --git a/salt/modules/inspectlib/query.py b/salt/modules/inspectlib/query.py index 54494d6a104..4ba5417a185 100644 --- a/salt/modules/inspectlib/query.py +++ b/salt/modules/inspectlib/query.py @@ -480,11 +480,13 @@ class Query(EnvLoader): raise InspectorQueryException( 'Unknown "{}" value for parameter "time"'.format(timeformat) ) - tfmt = ( - lambda param: timeformat == "tz" - and time.strftime("%b %d %Y %H:%M:%S", time.gmtime(param)) - or int(param) - ) + + def tfmt(param): + return ( + timeformat == "tz" + and time.strftime("%b %d %Y %H:%M:%S", time.gmtime(param)) + or int(param) + ) size_fmt = kwargs.get("size") if size_fmt is not None and size_fmt.lower() not in ["b", "kb", "mb", "gb"]: @@ -525,9 +527,9 @@ class Query(EnvLoader): pld_files.append(pld_data.path) else: pld_files[pld_data.path] = { - "uid": self._id_resolv(pld_data.uid, named=(owners == "id")), + "uid": self._id_resolv(pld_data.uid, named=owners == "id"), "gid": self._id_resolv( - pld_data.gid, named=(owners == "id"), uid=False + pld_data.gid, named=owners == "id", uid=False ), "size": _size_format(pld_data.p_size, fmt=size_fmt), "mode": oct(pld_data.mode), diff --git a/salt/modules/iptables.py b/salt/modules/iptables.py index 0b1177f1f54..986005b1f71 100644 --- a/salt/modules/iptables.py +++ b/salt/modules/iptables.py @@ -25,11 +25,11 @@ master config. The configuration is read using :py:func:`config.get - "-A FORWARD" """ +import argparse import logging import os import re import string -import sys import uuid import salt.utils.args @@ -73,7 +73,7 @@ def _has_option(option, family="ipv4"): _has_option('--wait') _has_option('--check', family='ipv6') """ - cmd = "{} --help".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)} --help" if option in __salt__["cmd.run_stdout"](cmd, output_loglevel="quiet"): return True return False @@ -192,7 +192,7 @@ def version(family="ipv4"): IPv6: salt '*' iptables.version family=ipv6 """ - cmd = "{} --version".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)} --version" out = __salt__["cmd.run_stdout"](cmd).split() return out[1] @@ -204,7 +204,7 @@ def build_rule( position="", full=None, family="ipv4", - **kwargs + **kwargs, ): """ Build a well-formatted iptables rule based on kwargs. A `table` and `chain` @@ -316,7 +316,7 @@ def build_rule( if not isinstance(match_value, list): match_value = match_value.split(",") for match in match_value: - rule.append("-m {}".format(match)) + rule.append(f"-m {match}") if "name_" in kwargs and match.strip() in ("pknock", "quota2", "recent"): rule.append("--name {}".format(kwargs["name_"])) del kwargs["name_"] @@ -335,7 +335,7 @@ def build_rule( if match_set.startswith("!") or match_set.startswith("not"): negative_match_set = "! " match_set = re.sub(bang_not_pat, "", match_set) - rule.append("-m set {}--match-set {}".format(negative_match_set, match_set)) + rule.append(f"-m set {negative_match_set}--match-set {match_set}") del kwargs["match-set"] if "connstate" in kwargs: @@ -382,7 +382,7 @@ def build_rule( else: dports = mp_value - rule.append("--{} {}".format(multiport_arg, dports)) + rule.append(f"--{multiport_arg} {dports}") del kwargs[multiport_arg] if "comment" in kwargs: @@ -526,11 +526,11 @@ def build_rule( if after_jump_argument in kwargs: value = kwargs[after_jump_argument] if value in (None, ""): # options without arguments - after_jump.append("--{}".format(after_jump_argument)) + after_jump.append(f"--{after_jump_argument}") elif any(ws_char in str(value) for ws_char in string.whitespace): - after_jump.append('--{} "{}"'.format(after_jump_argument, value)) + after_jump.append(f'--{after_jump_argument} "{value}"') else: - after_jump.append("--{} {}".format(after_jump_argument, value)) + after_jump.append(f"--{after_jump_argument} {value}") del kwargs[after_jump_argument] for key in kwargs: @@ -539,8 +539,8 @@ def build_rule( # the value in the kwargs, thus we need to fetch it after that has run value = kwargs[key] flag = "-" if len(key) == 1 else "--" - value = "" if value in (None, "") else " {}".format(value) - rule.append("{}{}{}{}".format(negation, flag, key, value)) + value = "" if value in (None, "") else f" {value}" + rule.append(f"{negation}{flag}{key}{value}") rule += after_jump @@ -704,7 +704,7 @@ def save(filename=None, family="ipv4"): parent_dir = os.path.dirname(filename) if not os.path.isdir(parent_dir): os.makedirs(parent_dir) - cmd = "{}-save".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)}-save" ipt = __salt__["cmd.run_stdout"](cmd) # regex out the output if configured with filters @@ -743,26 +743,24 @@ def check(table="filter", chain=None, rule=None, family="ipv4"): ipt_cmd = _iptables_cmd(family) if _has_option("--check", family): - cmd = "{} -t {} -C {} {}".format(ipt_cmd, table, chain, rule) + cmd = f"{ipt_cmd} -t {table} -C {chain} {rule}" __salt__["cmd.run_stderr"](cmd, output_loglevel="quiet") return not __context__["retcode"] else: _chain_name = hex(uuid.getnode()) # Create temporary table - __salt__["cmd.run"]("{} -t {} -N {}".format(ipt_cmd, table, _chain_name)) - __salt__["cmd.run"]( - "{} -t {} -A {} {}".format(ipt_cmd, table, _chain_name, rule) - ) + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -N {_chain_name}") + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -A {_chain_name} {rule}") - out = __salt__["cmd.run_stdout"]("{}-save".format(ipt_cmd)) + out = __salt__["cmd.run_stdout"](f"{ipt_cmd}-save") # Clean up temporary table - __salt__["cmd.run"]("{} -t {} -F {}".format(ipt_cmd, table, _chain_name)) - __salt__["cmd.run"]("{} -t {} -X {}".format(ipt_cmd, table, _chain_name)) + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -F {_chain_name}") + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -X {_chain_name}") for i in out.splitlines(): - if i.startswith("-A {}".format(_chain_name)): + if i.startswith(f"-A {_chain_name}"): if i.replace(_chain_name, chain) in out.splitlines(): return True @@ -792,8 +790,8 @@ def check_chain(table="filter", chain=None, family="ipv4"): if not chain: return "Error: Chain needs to be specified" - cmd = "{}-save -t {}".format(_iptables_cmd(family), table) - out = __salt__["cmd.run_stdout"](cmd).find(":{} ".format(chain)) + cmd = f"{_iptables_cmd(family)}-save -t {table}" + out = __salt__["cmd.run_stdout"](cmd).find(f":{chain} ") if out != -1: out = True @@ -823,7 +821,7 @@ def new_chain(table="filter", chain=None, family="ipv4"): return "Error: Chain needs to be specified" wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -N {}".format(_iptables_cmd(family), wait, table, chain) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -N {chain}" out = __salt__["cmd.run_stderr"](cmd) if not out: @@ -851,7 +849,7 @@ def delete_chain(table="filter", chain=None, family="ipv4"): return "Error: Chain needs to be specified" wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -X {}".format(_iptables_cmd(family), wait, table, chain) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -X {chain}" out = __salt__["cmd.run_stderr"](cmd) if not out: @@ -889,7 +887,7 @@ def append(table="filter", chain=None, rule=None, family="ipv4"): returnCheck = check(table, chain, rule, family) if isinstance(returnCheck, bool) and returnCheck: return False - cmd = "{} {} -t {} -A {} {}".format(_iptables_cmd(family), wait, table, chain, rule) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -A {chain} {rule}" out = __salt__["cmd.run_stderr"](cmd) return not out @@ -977,7 +975,7 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): rule = position wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -D {} {}".format(_iptables_cmd(family), wait, table, chain, rule) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -D {chain} {rule}" out = __salt__["cmd.run_stderr"](cmd) return out @@ -998,7 +996,7 @@ def flush(table="filter", chain="", family="ipv4"): """ wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -F {}".format(_iptables_cmd(family), wait, table, chain) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -F {chain}" out = __salt__["cmd.run_stderr"](cmd) return out @@ -1016,7 +1014,7 @@ def _parse_conf(conf_file=None, in_mem=False, family="ipv4"): with salt.utils.files.fopen(conf_file, "r") as ifile: rules = ifile.read() elif in_mem: - cmd = "{}-save".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)}-save" rules = __salt__["cmd.run_stdout"](cmd) else: raise SaltException("A file was not found to parse") @@ -1057,7 +1055,7 @@ def _parse_conf(conf_file=None, in_mem=False, family="ipv4"): and args[index + 1] != "!" and not args[index + 1].startswith("-") ): - args[index] += " {}".format(args.pop(index + 1)) + args[index] += f" {args.pop(index + 1)}" index += 1 if args[-1].startswith("-"): args.append("") @@ -1082,17 +1080,8 @@ def _parser(): iptables(8) and iptables-extensions(8) man pages. They will not all be used by all parts of the module; use them intelligently and appropriately. """ - add_arg = None - if sys.version.startswith("2.6"): - import optparse - - parser = optparse.OptionParser() - add_arg = parser.add_option - else: - import argparse # pylint: disable=minimum-python-version - - parser = argparse.ArgumentParser() - add_arg = parser.add_argument + parser = argparse.ArgumentParser() + add_arg = parser.add_argument # COMMANDS add_arg("-A", "--append", dest="append", action="append") diff --git a/salt/modules/iwtools.py b/salt/modules/iwtools.py index aec30a8390c..353fea5ea28 100644 --- a/salt/modules/iwtools.py +++ b/salt/modules/iwtools.py @@ -112,7 +112,7 @@ def _valid_iface(iface): Validate the specified interface """ ifaces = list_interfaces() - if iface in ifaces.keys(): + if iface in ifaces: return True return False diff --git a/salt/modules/k8s.py b/salt/modules/k8s.py index 3368a1d547b..c62d1c79ebc 100644 --- a/salt/modules/k8s.py +++ b/salt/modules/k8s.py @@ -581,7 +581,7 @@ def _source_encode(source, saltenv): try: source_url = urllib.parse.urlparse(source) except TypeError: - return "", {}, "Invalid format for source parameter" + return "", {} protos = ("salt", "http", "https", "ftp", "swift", "s3", "file") diff --git a/salt/modules/kubernetesmod.py b/salt/modules/kubernetesmod.py index 4755d4cf212..d66120925d5 100644 --- a/salt/modules/kubernetesmod.py +++ b/salt/modules/kubernetesmod.py @@ -154,7 +154,7 @@ def _setup_conn_old(**kwargs): or kubernetes.client.configuration.password != password ): # Recreates API connection if settings are changed - kubernetes.client.configuration.__init__() + kubernetes.client.configuration.__init__() # pylint: disable=unnecessary-dunder-call kubernetes.client.configuration.host = host kubernetes.client.configuration.user = username diff --git a/salt/modules/ldap3.py b/salt/modules/ldap3.py index a065b306b6d..2313b024bb9 100644 --- a/salt/modules/ldap3.py +++ b/salt/modules/ldap3.py @@ -32,7 +32,9 @@ log = logging.getLogger(__name__) def __virtual__(): """Only load this module if the Python ldap module is present""" - return bool(len(available_backends)) + if available_backends: + return True + return False class LDAPError(Exception): diff --git a/salt/modules/mac_softwareupdate.py b/salt/modules/mac_softwareupdate.py index 0b5df536210..3cb894e258c 100644 --- a/salt/modules/mac_softwareupdate.py +++ b/salt/modules/mac_softwareupdate.py @@ -176,7 +176,7 @@ def list_ignored(): # "Safari6.1.2MountainLion-6.1.2", # or: # Safari6.1.2MountainLion-6.1.2 - rexp = re.compile('(?m)^ ["]?' r'([^,|\s].*[^"|\n|,])[,|"]?') + rexp = re.compile(r'(?m)^ ["]?([^,|\s].*[^"|\n|,])[,|"]?') return rexp.findall(out) diff --git a/salt/modules/mine.py b/salt/modules/mine.py index f8d55464019..f25e894740f 100644 --- a/salt/modules/mine.py +++ b/salt/modules/mine.py @@ -186,7 +186,7 @@ def update(clear=False, mine_functions=None): res = salt.utils.functools.call_function( __salt__[function_name or function_alias], *function_args, - **function_kwargs + **function_kwargs, ) except Exception: # pylint: disable=broad-except trace = traceback.format_exc() @@ -309,17 +309,8 @@ def get(tgt, fun, tgt_type="glob", exclude_minion=False): # Load from local minion's cache if __opts__["file_client"] == "local": ret = {} - is_target = { - "glob": __salt__["match.glob"], - "pcre": __salt__["match.pcre"], - "list": __salt__["match.list"], - "grain": __salt__["match.grain"], - "grain_pcre": __salt__["match.grain_pcre"], - "ipcidr": __salt__["match.ipcidr"], - "compound": __salt__["match.compound"], - "pillar": __salt__["match.pillar"], - "pillar_pcre": __salt__["match.pillar_pcre"], - }[tgt_type](tgt) + + is_target = __salt__[f"match.{tgt_type}"](tgt) if not is_target: return ret diff --git a/salt/modules/mount.py b/salt/modules/mount.py index 869c6f2016d..aedc8dc79f2 100644 --- a/salt/modules/mount.py +++ b/salt/modules/mount.py @@ -866,7 +866,10 @@ def set_fstab( criteria = entry.pick(match_on) except KeyError: - filterFn = lambda key: key not in _fstab_entry.fstab_keys + + def filterFn(key): + return key not in _fstab_entry.fstab_keys + invalid_keys = filter(filterFn, match_on) msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) @@ -996,7 +999,10 @@ def set_vfstab( criteria = entry.pick(match_on) except KeyError: - filterFn = lambda key: key not in _vfstab_entry.vfstab_keys + + def filterFn(key): + return key not in _vfstab_entry.vfstab_keys + invalid_keys = filter(filterFn, match_on) msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) @@ -1878,7 +1884,10 @@ def set_filesystems( criteria = entry_ip.pick(match_on) except KeyError: - filterFn = lambda key: key not in _FileSystemsEntry.compatibility_keys + + def filterFn(key): + return key not in _FileSystemsEntry.compatibility_keys + invalid_keys = filter(filterFn, match_on) raise CommandExecutionError( 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) diff --git a/salt/modules/mysql.py b/salt/modules/mysql.py index c9c6ad69fe7..4d8f5e07e8b 100644 --- a/salt/modules/mysql.py +++ b/salt/modules/mysql.py @@ -2394,7 +2394,7 @@ def __grant_generate( if dbc != "*": # _ and % are authorized on GRANT queries and should get escaped # on the db name, but only if not requesting a table level grant - dbc = quote_identifier(dbc, for_grants=(table == "*")) + dbc = quote_identifier(dbc, for_grants=table == "*") if table != "*": table = quote_identifier(table) # identifiers cannot be used as values, and same thing for grants @@ -2663,7 +2663,7 @@ def grant_revoke( if dbc != "*": # _ and % are authorized on GRANT queries and should get escaped # on the db name, but only if not requesting a table level grant - s_database = quote_identifier(dbc, for_grants=(table == "*")) + s_database = quote_identifier(dbc, for_grants=table == "*") if dbc == "*": # add revoke for *.* # before the modification query send to mysql will looks like @@ -2764,11 +2764,13 @@ def __do_query_into_hash(conn, sql_str): rtn_results = [] + cursor = None try: cursor = conn.cursor() except MySQLdb.MySQLError: log.error("%s: Can't get cursor for SQL->%s", mod, sql_str) - cursor.close() + if cursor: + cursor.close() log.debug("%s-->", mod) return rtn_results diff --git a/salt/modules/network.py b/salt/modules/network.py index 524b1b74faf..c72230f3335 100644 --- a/salt/modules/network.py +++ b/salt/modules/network.py @@ -2015,7 +2015,7 @@ def iphexval(ip): salt '*' network.iphexval 10.0.0.1 """ a = ip.split(".") - hexval = ["%02X" % int(x) for x in a] # pylint: disable=E1321 + hexval = ["%02X" % int(x) for x in a] return "".join(hexval) diff --git a/salt/modules/openscap.py b/salt/modules/openscap.py index 762796cce47..3f3ff6dffd8 100644 --- a/salt/modules/openscap.py +++ b/salt/modules/openscap.py @@ -2,24 +2,12 @@ Module for OpenSCAP Management """ - - +import argparse import shlex import shutil import tempfile from subprocess import PIPE, Popen -ArgumentParser = object - -try: - import argparse # pylint: disable=minimum-python-version - - ArgumentParser = argparse.ArgumentParser - HAS_ARGPARSE = True -except ImportError: # python 2.6 - HAS_ARGPARSE = False - - _XCCDF_MAP = { "eval": { "parser_arguments": [(("--profile",), {"required": True})], @@ -32,15 +20,10 @@ _XCCDF_MAP = { } -def __virtual__(): - return HAS_ARGPARSE, "argparse module is required." - - -class _ArgumentParser(ArgumentParser): +class _ArgumentParser(argparse.ArgumentParser): def __init__(self, action=None, *args, **kwargs): super().__init__(*args, prog="oscap", **kwargs) self.add_argument("action", choices=["eval"]) - add_arg = None for params, kwparams in _XCCDF_MAP["eval"]["parser_arguments"]: self.add_argument(*params, **kwparams) diff --git a/salt/modules/opkg.py b/salt/modules/opkg.py index 98882c85e96..72e7bcbb411 100644 --- a/salt/modules/opkg.py +++ b/salt/modules/opkg.py @@ -1222,7 +1222,10 @@ def version_cmp( salt '*' pkg.version_cmp '0.2.4-0' '0.2.4.1-0' """ - normalize = lambda x: str(x).split(":", 1)[-1] if ignore_epoch else str(x) + + def normalize(x): + return str(x).split(":", 1)[-1] if ignore_epoch else str(x) + pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) diff --git a/salt/modules/opsgenie.py b/salt/modules/opsgenie.py index 18539b80654..7ed014042a0 100644 --- a/salt/modules/opsgenie.py +++ b/salt/modules/opsgenie.py @@ -99,6 +99,7 @@ def post_data( "Content-Type": "application/json", "Authorization": "GenieKey " + api_key, }, + timeout=120, ) else: response = requests.post( @@ -108,6 +109,7 @@ def post_data( "Content-Type": "application/json", "Authorization": "GenieKey " + api_key, }, + timeout=120, ) return response.status_code, response.text diff --git a/salt/modules/oracle.py b/salt/modules/oracle.py index bc80943d480..bb79063533f 100644 --- a/salt/modules/oracle.py +++ b/salt/modules/oracle.py @@ -180,9 +180,12 @@ def version(*dbs): salt '*' oracle.version my_db """ pillar_dbs = __salt__["pillar.get"]("oracle:dbs") - get_version = lambda x: [ - r[0] for r in run_query(x, "select banner from v$version order by banner") - ] + + def get_version(x): + return [ + r[0] for r in run_query(x, "select banner from v$version order by banner") + ] + result = {} if dbs: log.debug("get db versions for: %s", dbs) diff --git a/salt/modules/pagerduty_util.py b/salt/modules/pagerduty_util.py index 642e2ce2a5a..10114b3e4bb 100644 --- a/salt/modules/pagerduty_util.py +++ b/salt/modules/pagerduty_util.py @@ -174,6 +174,7 @@ def _query( params=params, data=salt.utils.json.dumps(data), verify=verify_ssl, + timeout=120, ) if result.text is None or result.text == "": @@ -196,6 +197,7 @@ def _query( params=params, data=data, # Already serialized above, don't do it again verify=verify_ssl, + timeout=120, ).json() offset = next_page_results["offset"] limit = next_page_results["limit"] diff --git a/salt/modules/pkg_resource.py b/salt/modules/pkg_resource.py index a6fa5eecd3f..578e53da30d 100644 --- a/salt/modules/pkg_resource.py +++ b/salt/modules/pkg_resource.py @@ -26,7 +26,9 @@ def _repack_pkgs(pkgs, normalize=True): if normalize and "pkg.normalize_name" in __salt__: _normalize_name = __salt__["pkg.normalize_name"] else: - _normalize_name = lambda pkgname: pkgname + + def _normalize_name(pkgname): + return pkgname repacked_pkgs = { _normalize_name(str(x)): str(y) if y is not None else y @@ -71,7 +73,9 @@ def pack_sources(sources, normalize=True): if normalize and "pkg.normalize_name" in __salt__: _normalize_name = __salt__["pkg.normalize_name"] else: - _normalize_name = lambda pkgname: pkgname + + def _normalize_name(pkgname): + return pkgname if isinstance(sources, str): try: diff --git a/salt/modules/portage_config.py b/salt/modules/portage_config.py index 9cf937f9406..15c0ad983da 100644 --- a/salt/modules/portage_config.py +++ b/salt/modules/portage_config.py @@ -88,7 +88,7 @@ def _get_config_file(conf, atom): # parts.repo will be empty if there is no repo part relative_path = parts.repo or "gentoo" elif str(parts.cp).endswith("/*"): - relative_path = str(parts.cp).split("/")[0] + "_" + relative_path = str(parts.cp).split("/", maxsplit=1)[0] + "_" else: relative_path = os.path.join( *[x for x in os.path.split(parts.cp) if x != "*"] diff --git a/salt/modules/postgres.py b/salt/modules/postgres.py index f73959a92ed..d9664ac840a 100644 --- a/salt/modules/postgres.py +++ b/salt/modules/postgres.py @@ -35,10 +35,6 @@ To prevent Postgres commands from running arbitrarily long, a timeout (in second postgres.bins_dir: '/usr/pgsql-9.5/bin/' """ -# This pylint error is popping up where there are no colons? -# pylint: disable=E8203 - - import base64 import datetime import hashlib @@ -1007,7 +1003,8 @@ def user_list( return False # will return empty string if return_password = False - _x = lambda s: s if return_password else "" + def _x(s): + return s if return_password else "" query = "".join( [ diff --git a/salt/modules/quota.py b/salt/modules/quota.py index 931ae63d0ab..eb99d67a4f6 100644 --- a/salt/modules/quota.py +++ b/salt/modules/quota.py @@ -105,7 +105,7 @@ def set_(device, **kwargs): "file-hard-limit": 0, } - current = None + current = ret = None cmd = "setquota" if "user" in kwargs: cmd += " -u {} ".format(kwargs["user"]) diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index e0a9304bd54..a11fc4a3ede 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -165,7 +165,9 @@ def _output_to_dict(cmdoutput, values_mapper=None): ret = {} if values_mapper is None: - values_mapper = lambda string: string.split("\t") + + def values_mapper(string): + return string.split("\t") # remove first and last line: Listing ... - ...done data_rows = _strip_listing_to_done(cmdoutput.splitlines()) @@ -237,11 +239,11 @@ def list_users(runas=None): ) # func to get tags from string such as "[admin, monitoring]" - func = ( - lambda string: [x.strip() for x in string[1:-1].split(",")] - if "," in string - else [x for x in string[1:-1].split(" ")] - ) + def func(string): + if "," in string: + return [x.strip() for x in string[1:-1].split(",")] + return [x for x in string[1:-1].split(" ")] + return _output_to_dict(res, func) diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py index 4cd137c258f..7bf45780f0c 100644 --- a/salt/modules/rpm_lowpkg.py +++ b/salt/modules/rpm_lowpkg.py @@ -710,7 +710,10 @@ def version_cmp(ver1, ver2, ignore_epoch=False): salt '*' pkg.version_cmp '0.2-001' '0.2.0.1-002' """ - normalize = lambda x: str(x).split(":", 1)[-1] if ignore_epoch else str(x) + + def normalize(x): + return str(x).split(":", 1)[-1] if ignore_epoch else str(x) + ver1 = normalize(ver1) ver2 = normalize(ver2) diff --git a/salt/modules/saltcheck.py b/salt/modules/saltcheck.py index 79113bb71c4..99672a3c133 100644 --- a/salt/modules/saltcheck.py +++ b/salt/modules/saltcheck.py @@ -476,7 +476,7 @@ def run_state_tests(state, saltenv=None, check_all=False, only_fails=False): # Check for situations to disable parallization if parallel: - if type(num_proc) == float: + if isinstance(num_proc, float): num_proc = int(num_proc) if multiprocessing.cpu_count() < 2: diff --git a/salt/modules/selinux.py b/salt/modules/selinux.py index c12db3d9e19..552ec282ff2 100644 --- a/salt/modules/selinux.py +++ b/salt/modules/selinux.py @@ -375,7 +375,7 @@ def _validate_filetype(filetype): Checks if the given filetype is a valid SELinux filetype specification. Throws an SaltInvocationError if it isn't. """ - if filetype not in _SELINUX_FILETYPES.keys(): + if filetype not in _SELINUX_FILETYPES: raise SaltInvocationError("Invalid filetype given: {}".format(filetype)) return True diff --git a/salt/modules/sensehat.py b/salt/modules/sensehat.py index 71c5630703c..d5ba0b5f1f1 100644 --- a/salt/modules/sensehat.py +++ b/salt/modules/sensehat.py @@ -39,6 +39,7 @@ def __virtual__(): """ if has_sense_hat: try: + global _sensehat _sensehat = SenseHat() except OSError: return ( diff --git a/salt/modules/serverdensity_device.py b/salt/modules/serverdensity_device.py index 27a4c0b0a32..f55815fb07a 100644 --- a/salt/modules/serverdensity_device.py +++ b/salt/modules/serverdensity_device.py @@ -89,6 +89,7 @@ def create(name, **params): "https://api.serverdensity.io/inventory/devices/", params={"token": get_sd_auth("api_token")}, data=params, + timeout=120, ) log.debug("Server Density API Response: %s", api_response) log.debug("Server Density API Response content: %s", api_response.content) @@ -120,6 +121,7 @@ def delete(device_id): api_response = requests.delete( "https://api.serverdensity.io/inventory/devices/" + device_id, params={"token": get_sd_auth("api_token")}, + timeout=120, ) log.debug("Server Density API Response: %s", api_response) log.debug("Server Density API Response content: %s", api_response.content) @@ -171,6 +173,7 @@ def ls(**params): "token": get_sd_auth("api_token"), "filter": salt.utils.json.dumps(params), }, + timeout=120, ) log.debug("Server Density API Response: %s", api_response) log.debug("Server Density API Response content: %s", api_response.content) @@ -209,6 +212,7 @@ def update(device_id, **params): "https://api.serverdensity.io/inventory/devices/" + device_id, params={"token": get_sd_auth("api_token")}, data=params, + timeout=120, ) log.debug("Server Density API Response: %s", api_response) log.debug("Server Density API Response content: %s", api_response.content) diff --git a/salt/modules/smartos_imgadm.py b/salt/modules/smartos_imgadm.py index 5d5cb75e750..cfa74f055bc 100644 --- a/salt/modules/smartos_imgadm.py +++ b/salt/modules/smartos_imgadm.py @@ -37,13 +37,16 @@ def _exit_status(retcode, stderr=None): """ Translate exit status of imgadm """ - ret = { - 0: "Successful completion.", - 1: "An error occurred." if not stderr else stderr, - 2: "Usage error.", - 3: "Image not installed.", - }[retcode] - return ret + if retcode == 0: + return "Successful completion." + if retcode == 1: + if stderr: + return stderr + return "An error occurred." + if retcode == 2: + return "Usage error." + if retcode == 3: + return "Image not installed." def _parse_image_meta(image=None, detail=False): diff --git a/salt/modules/smartos_vmadm.py b/salt/modules/smartos_vmadm.py index 3ef9c3d5b6a..308d41d0294 100644 --- a/salt/modules/smartos_vmadm.py +++ b/salt/modules/smartos_vmadm.py @@ -43,10 +43,12 @@ def _exit_status(retcode): """ Translate exit status of vmadm """ - ret = {0: "Successful completion.", 1: "An error occurred.", 2: "Usage error."}[ - retcode - ] - return ret + if retcode == 0: + return "Successful completion." + if retcode == 1: + return "An error occurred." + if retcode == 2: + return "Usage error." def _create_update_from_file(mode="create", uuid=None, path=None): diff --git a/salt/modules/solaris_shadow.py b/salt/modules/solaris_shadow.py index 65d20f2e9e1..9441ecea293 100644 --- a/salt/modules/solaris_shadow.py +++ b/salt/modules/solaris_shadow.py @@ -114,7 +114,7 @@ def info(name): } try: - data = pwd.getpwnam(name) + data = pwd.getpwnam(name) # pylint: disable=used-before-assignment ret.update({"name": name}) except KeyError: return ret diff --git a/salt/modules/splunk_search.py b/salt/modules/splunk_search.py index 560874cd23e..be9a50c28e5 100644 --- a/salt/modules/splunk_search.py +++ b/salt/modules/splunk_search.py @@ -162,7 +162,7 @@ def create(name, profile="splunk", **kwargs): _req_url = "{}/servicesNS/{}/search/saved/searches/{}/acl".format( url, config.get("username"), urllib.parse.quote(name) ) - requests.post(_req_url, auth=auth, verify=True, data=data) + requests.post(_req_url, auth=auth, verify=True, data=data, timeout=120) return _get_splunk_search_props(search) diff --git a/salt/modules/status.py b/salt/modules/status.py index 4b0a3b0d400..8489256f0b5 100644 --- a/salt/modules/status.py +++ b/salt/modules/status.py @@ -186,10 +186,10 @@ def custom(): try: ret[item] = vals[item] except KeyError: - log.warning(f"val {item} not in return of {func}") + log.warning("val %s not in return of %s", item, func) ret[item] = "UNKNOWN" except KeyError: - log.warning(f"custom status {func} isn't loaded") + log.warning("custom status %s isn't loaded", func) return ret @@ -1361,7 +1361,10 @@ def netdev(): """ freebsd specific implementation of netdev """ - _dict_tree = lambda: collections.defaultdict(_dict_tree) + + def _dict_tree(): + return collections.defaultdict(_dict_tree) + ret = _dict_tree() netstat = __salt__["cmd.run"]("netstat -i -n -4 -b -d").splitlines() netstat += __salt__["cmd.run"]("netstat -i -n -6 -b -d").splitlines()[1:] diff --git a/salt/modules/statuspage.py b/salt/modules/statuspage.py index 0a38e84102b..0bfbd2798e0 100644 --- a/salt/modules/statuspage.py +++ b/salt/modules/statuspage.py @@ -110,7 +110,7 @@ def _http_request(url, method="GET", headers=None, data=None): """ Make the HTTP request and return the body as python object. """ - req = requests.request(method, url, headers=headers, data=data) + req = requests.request(method, url, headers=headers, data=data, timeout=120) ret = _default_ret() ok_status = METHOD_OK_STATUS.get(method, 200) if req.status_code != ok_status: diff --git a/salt/modules/swarm.py b/salt/modules/swarm.py index fb0d1e273e6..48d49130274 100644 --- a/salt/modules/swarm.py +++ b/salt/modules/swarm.py @@ -374,7 +374,7 @@ def node_ls(server=str): try: salt_return = {} client = docker.APIClient(base_url="unix://var/run/docker.sock") - service = client.nodes(filters=({"name": server})) + service = client.nodes(filters={"name": server}) getdata = salt.utils.json.dumps(service) dump = salt.utils.json.loads(getdata) for items in dump: diff --git a/salt/modules/sysrc.py b/salt/modules/sysrc.py index 2f7952d5959..67a2ce2faf0 100644 --- a/salt/modules/sysrc.py +++ b/salt/modules/sysrc.py @@ -93,14 +93,14 @@ def set_(name, value, **kwargs): # YES, NO, Yes, No, True, False, etc. to boolean types. However, in this case, # we will check to see if that happened and replace it with "YES" or "NO" because # those items are accepted in sysrc. - if type(value) == bool: + if isinstance(value, bool): if value: value = "YES" else: value = "NO" # This is here for the same reason, except for numbers - if type(value) == int: + if isinstance(value, int): value = str(value) cmd += " " + name + '="' + value + '"' diff --git a/salt/modules/systemd_service.py b/salt/modules/systemd_service.py index 52c17ba6074..dd27106afd0 100644 --- a/salt/modules/systemd_service.py +++ b/salt/modules/systemd_service.py @@ -55,9 +55,6 @@ VALID_UNIT_TYPES = ( # Define the module's virtual name __virtualname__ = "service" -# Disable check for string substitution -# pylint: disable=E1321 - def __virtual__(): """ diff --git a/salt/modules/telegram.py b/salt/modules/telegram.py index 79230b5e049..e0f2f969045 100644 --- a/salt/modules/telegram.py +++ b/salt/modules/telegram.py @@ -113,7 +113,7 @@ def _post_message(message, chat_id, token): parameters["text"] = message try: - response = requests.post(url, data=parameters) + response = requests.post(url, data=parameters, timeout=120) result = response.json() log.debug("Raw response of the telegram request is %s", response) diff --git a/salt/modules/telemetry.py b/salt/modules/telemetry.py index 20dcf08c185..c55c94668ca 100644 --- a/salt/modules/telemetry.py +++ b/salt/modules/telemetry.py @@ -101,7 +101,7 @@ def _retrieve_channel_id(email, profile="telemetry"): _get_telemetry_base(profile) + "/notification-channels?_type=EmailNotificationChannel" ) - response = requests.get(get_url, headers=auth) + response = requests.get(get_url, headers=auth, timeout=120) if response.status_code == 200: cache_result = {} @@ -140,7 +140,7 @@ def get_alert_config( get_url = _get_telemetry_base(profile) + "/alerts?deployment={}".format( deployment_id ) - response = requests.get(get_url, headers=auth) + response = requests.get(get_url, headers=auth, timeout=120) except requests.exceptions.RequestException as e: log.error(str(e)) return False @@ -197,7 +197,7 @@ def get_notification_channel_id(notify_channel, profile="telemetry"): "email": notify_channel, } response = requests.post( - post_url, data=salt.utils.json.dumps(data), headers=auth + post_url, data=salt.utils.json.dumps(data), headers=auth, timeout=120 ) if response.status_code == 200: log.info( @@ -236,6 +236,7 @@ def get_alarms(deployment_id, profile="telemetry"): _get_telemetry_base(profile) + "/alerts?deployment={}".format(deployment_id), headers=auth, + timeout=120, ) except requests.exceptions.RequestException as e: log.error(str(e)) @@ -293,7 +294,10 @@ def create_alarm(deployment_id, metric_name, data, api_key=None, profile="teleme try: response = requests.post( - request_uri, data=salt.utils.json.dumps(post_body), headers=auth + request_uri, + data=salt.utils.json.dumps(post_body), + headers=auth, + timeout=120, ) except requests.exceptions.RequestException as e: # TODO: May be we should retry? @@ -364,7 +368,10 @@ def update_alarm(deployment_id, metric_name, data, api_key=None, profile="teleme try: response = requests.put( - request_uri, data=salt.utils.json.dumps(post_body), headers=auth + request_uri, + data=salt.utils.json.dumps(post_body), + headers=auth, + timeout=120, ) except requests.exceptions.RequestException as e: log.error("Update failed: %s", e) @@ -429,7 +436,7 @@ def delete_alarms( delete_url = _get_telemetry_base(profile) + "/alerts/{}".format(id) try: - response = requests.delete(delete_url, headers=auth) + response = requests.delete(delete_url, headers=auth, timeout=120) if metric_name: log.debug( "updating cache and delete %s key from %s", diff --git a/salt/modules/tomcat.py b/salt/modules/tomcat.py index 46451508c50..d9f9f28e276 100644 --- a/salt/modules/tomcat.py +++ b/salt/modules/tomcat.py @@ -630,17 +630,14 @@ def passwd(passwd, user="", alg="sha1", realm=None): salt '*' tomcat.passwd secret tomcat sha1 salt '*' tomcat.passwd secret tomcat sha1 'Protected Realm' """ + # pylint: disable=no-value-for-parameter + # we call the first parameter the same as the function! + # Shouldn't it be SHA265 instead of SHA1? - digest = hasattr(hashlib, alg) and getattr(hashlib, alg) or None - if digest: + digest = getattr(hashlib, alg, None) + if digest is not None: if realm: - digest.update( - "{}:{}:{}".format( - user, - realm, - passwd, - ) - ) + digest.update(f"{user}:{realm}:{passwd}") else: digest.update(passwd) diff --git a/salt/modules/uptime.py b/salt/modules/uptime.py index 8e40717fa8a..294e91aeee4 100644 --- a/salt/modules/uptime.py +++ b/salt/modules/uptime.py @@ -49,7 +49,9 @@ def create(name, **params): application_url = _get_application_url() log.debug("[uptime] trying PUT request") params.update(url=name) - req = requests.put("{}/api/checks".format(application_url), data=params) + req = requests.put( + "{}/api/checks".format(application_url), data=params, timeout=120 + ) if not req.ok: raise CommandExecutionError("request to uptime failed : {}".format(req.reason)) log.debug("[uptime] PUT request successful") @@ -72,9 +74,11 @@ def delete(name): raise CommandExecutionError(msg) application_url = _get_application_url() log.debug("[uptime] trying DELETE request") - jcontent = requests.get("{}/api/checks".format(application_url)).json() + jcontent = requests.get("{}/api/checks".format(application_url), timeout=120).json() url_id = [x["_id"] for x in jcontent if x["url"] == name][0] - req = requests.delete("{}/api/checks/{}".format(application_url, url_id)) + req = requests.delete( + "{}/api/checks/{}".format(application_url, url_id), timeout=120 + ) if not req.ok: raise CommandExecutionError("request to uptime failed : {}".format(req.reason)) log.debug("[uptime] DELETE request successful") @@ -106,7 +110,7 @@ def checks_list(): """ application_url = _get_application_url() log.debug("[uptime] get checks") - jcontent = requests.get("{}/api/checks".format(application_url)).json() + jcontent = requests.get("{}/api/checks".format(application_url), timeout=120).json() return [x["url"] for x in jcontent] diff --git a/salt/modules/vbox_guest.py b/salt/modules/vbox_guest.py index 56c576ed211..d6dbce68602 100644 --- a/salt/modules/vbox_guest.py +++ b/salt/modules/vbox_guest.py @@ -90,19 +90,19 @@ def _return_mount_error(f): def _additions_install_program_path(mount_point): - return os.path.join( - mount_point, - { - "Linux": "VBoxLinuxAdditions.run", - "Solaris": "VBoxSolarisAdditions.pkg", - "Windows": "VBoxWindowsAdditions.exe", - }[__grains__.get("kernel", "")], - ) + kernel = __grains__.get("kernel", "") + if kernel == "Linux": + exe = "VBoxLinuxAdditions.run" + elif kernel == "Solaris": + exe = "VBoxSolarisAdditions.pkg" + elif kernel == "Windows": + exe = "VBoxWindowsAdditions.exe" + return os.path.join(mount_point, exe) def _additions_install_opensuse(**kwargs): kernel_type = re.sub(r"^(\d|\.|-)*", "", __grains__.get("kernelrelease", "")) - kernel_devel = "kernel-{}-devel".format(kernel_type) + kernel_devel = f"kernel-{kernel_type}-devel" return __states__["pkg.installed"](None, pkgs=["make", "gcc", kernel_devel]) @@ -279,7 +279,7 @@ def additions_version(): except OSError: return False if d and len(os.listdir(d)) > 0: - return re.sub(r"^{}-".format(_additions_dir_prefix), "", os.path.basename(d)) + return re.sub(rf"^{_additions_dir_prefix}-", "", os.path.basename(d)) return False diff --git a/salt/modules/virt.py b/salt/modules/virt.py index 1e671621c25..0f11dbde206 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -298,9 +298,7 @@ def _get_domain(conn, *vms, **kwargs): if vms: for name in vms: if name not in all_vms: - raise CommandExecutionError( - 'The VM "{name}" is not present'.format(name=name) - ) + raise CommandExecutionError(f'The VM "{name}" is not present') else: lookup_vms.append(name) else: @@ -515,7 +513,7 @@ def _get_disks(conn, dom): disk_type = elem.get("type") def _get_disk_volume_data(pool_name, volume_name): - qemu_target = "{}/{}".format(pool_name, volume_name) + qemu_target = f"{pool_name}/{volume_name}" pool = conn.storagePoolLookupByName(pool_name) extra_properties = {} try: @@ -526,12 +524,15 @@ def _get_disks(conn, dom): "disk size": vol_info[2], } + _nodes = elem.findall( # pylint: disable=cell-var-from-loop + ".//backingStore[source]" + ) backing_files = [ { "file": node.find("source").get("file"), "file format": node.find("format").get("type"), } - for node in elem.findall(".//backingStore[source]") + for node in _nodes ] if backing_files: @@ -570,7 +571,7 @@ def _get_disks(conn, dom): disks[target.get("dev")] = {"file": qemu_target, "zfs": True} continue - if qemu_target in all_volumes.keys(): + if qemu_target in all_volumes: # If the qemu_target is a known path, output a volume volume = all_volumes[qemu_target] qemu_target, extra_properties = _get_disk_volume_data( @@ -605,7 +606,7 @@ def _get_disks(conn, dom): elif disk_type == "block": qemu_target = source.get("dev", "") # If the qemu_target is a known path, output a volume - if qemu_target in all_volumes.keys(): + if qemu_target in all_volumes: volume = all_volumes[qemu_target] qemu_target, extra_properties = _get_disk_volume_data( volume["pool"], volume["name"] @@ -614,7 +615,7 @@ def _get_disks(conn, dom): qemu_target = source.get("protocol") source_name = source.get("name") if source_name: - qemu_target = "{}:{}".format(qemu_target, source_name) + qemu_target = f"{qemu_target}:{source_name}" # Reverse the magic for the rbd and gluster pools if source.get("protocol") in ["rbd", "gluster"]: @@ -622,7 +623,7 @@ def _get_disks(conn, dom): pool_i_xml = ElementTree.fromstring(pool_i.XMLDesc()) name_node = pool_i_xml.find("source/name") if name_node is not None and source_name.startswith( - "{}/".format(name_node.text) + f"{name_node.text}/" ): qemu_target = "{}{}".format( pool_i.name(), source_name[len(name_node.text) :] @@ -638,7 +639,7 @@ def _get_disks(conn, dom): qemu_target = urllib.parse.urlunparse( ( source.get("protocol"), - "{}:{}".format(hostname, port) if port else hostname, + f"{hostname}:{port}" if port else hostname, source_name, "", saxutils.unescape(source.get("query", "")), @@ -743,9 +744,7 @@ def _migrate(dom, dst_uri, **kwargs): try: bandwidth_value = int(max_bandwidth) except ValueError: - raise SaltInvocationError( - "Invalid max_bandwidth value: {}".format(max_bandwidth) - ) + raise SaltInvocationError(f"Invalid max_bandwidth value: {max_bandwidth}") dom.migrateSetMaxSpeed(bandwidth_value) max_downtime = kwargs.get("max_downtime") @@ -753,9 +752,7 @@ def _migrate(dom, dst_uri, **kwargs): try: downtime_value = int(max_downtime) except ValueError: - raise SaltInvocationError( - "Invalid max_downtime value: {}".format(max_downtime) - ) + raise SaltInvocationError(f"Invalid max_downtime value: {max_downtime}") dom.migrateSetMaxDowntime(downtime_value) if kwargs.get("offline") is True: @@ -782,7 +779,7 @@ def _migrate(dom, dst_uri, **kwargs): try: params[param_key] = int(comp_option_value) except ValueError: - raise SaltInvocationError("Invalid {} value".format(comp_option)) + raise SaltInvocationError(f"Invalid {comp_option} value") parallel_connections = kwargs.get("parallel_connections") if parallel_connections: @@ -888,7 +885,7 @@ def _disk_from_pool(conn, pool, pool_xml, volume_name): # Gluster and RBD need pool/volume name name_node = pool_xml.find("./source/name") if name_node is not None: - disk_context["volume"] = "{}/{}".format(name_node.text, volume_name) + disk_context["volume"] = f"{name_node.text}/{volume_name}" # Copy the authentication if any for RBD auth_node = pool_xml.find("./source/auth") if auth_node is not None: @@ -947,7 +944,7 @@ def _gen_xml( consoles=None, stop_on_reboot=False, host_devices=None, - **kwargs + **kwargs, ): """ Generate the XML string to define a libvirt VM @@ -1013,7 +1010,7 @@ def _gen_xml( efi_value = context["boot"].get("efi", None) if boot else None if efi_value is True: context["boot"]["os_attrib"] = "firmware='efi'" - elif efi_value is not None and type(efi_value) != bool: + elif efi_value is not None and not isinstance(efi_value, bool): raise SaltInvocationError("Invalid efi value") if os_type == "xen": @@ -1391,7 +1388,7 @@ def _zfs_image_create( ) ) - destination_fs = os.path.join(pool, "{}.{}".format(vm_name, disk_name)) + destination_fs = os.path.join(pool, f"{vm_name}.{disk_name}") log.debug("Image destination will be %s", destination_fs) existing_disk = __salt__["zfs.list"](name=pool) @@ -1423,9 +1420,7 @@ def _zfs_image_create( sparse=sparse_volume, ) - blockdevice_path = os.path.join( - "/dev/zvol", pool, "{}.{}".format(vm_name, disk_name) - ) + blockdevice_path = os.path.join("/dev/zvol", pool, f"{vm_name}.{disk_name}") log.debug("Image path will be %s", blockdevice_path) return blockdevice_path @@ -1458,7 +1453,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): qcow2 = False if salt.utils.path.which("qemu-img"): - res = __salt__["cmd.run"]('qemu-img info "{}"'.format(sfn)) + res = __salt__["cmd.run"](f'qemu-img info "{sfn}"') imageinfo = salt.utils.yaml.safe_load(res) qcow2 = imageinfo["file format"] == "qcow2" try: @@ -1477,9 +1472,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): if disk_size and qcow2: log.debug("Resize qcow2 image to %sM", disk_size) - __salt__["cmd.run"]( - 'qemu-img resize "{}" {}M'.format(img_dest, disk_size) - ) + __salt__["cmd.run"](f'qemu-img resize "{img_dest}" {disk_size}M') log.debug("Apply umask and remove exec bit") mode = (0o0777 ^ mask) & 0o0666 @@ -1487,7 +1480,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): except OSError as err: raise CommandExecutionError( - "Problem while copying image. {} - {}".format(disk_image, err) + f"Problem while copying image. {disk_image} - {err}" ) else: @@ -1514,7 +1507,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): except OSError as err: raise CommandExecutionError( - "Problem while creating volume {} - {}".format(img_dest, err) + f"Problem while creating volume {img_dest} - {err}" ) return img_dest @@ -1730,7 +1723,7 @@ def _fill_disk_filename(conn, vm_name, disk, hypervisor, pool_caps): index = min( idx for idx in range(1, max(indexes) + 2) if idx not in indexes ) - disk["filename"] = "{}{}".format(os.path.basename(device), index) + disk["filename"] = f"{os.path.basename(device)}{index}" # Is the user wanting to reuse an existing volume? if disk.get("source_file"): @@ -1965,7 +1958,7 @@ def _handle_efi_param(boot, desc): return True # check the case that loader tag might be present. This happens after the vm ran - elif type(efi_value) == bool and os_attrib == {}: + elif isinstance(efi_value, bool) and os_attrib == {}: if efi_value is True and parent_tag.find("loader") is None: parent_tag.set("firmware", "efi") return True @@ -1973,7 +1966,7 @@ def _handle_efi_param(boot, desc): parent_tag.remove(parent_tag.find("loader")) parent_tag.remove(parent_tag.find("nvram")) return True - elif type(efi_value) != bool: + elif not isinstance(efi_value, bool): raise SaltInvocationError("Invalid efi value") return False @@ -2006,7 +1999,7 @@ def init( consoles=None, stop_on_reboot=False, host_devices=None, - **kwargs + **kwargs, ): """ Initialize a new vm @@ -2912,7 +2905,7 @@ def init( consoles, stop_on_reboot, host_devices, - **kwargs + **kwargs, ) log.debug("New virtual machine definition: %s", vm_xml) conn.defineXML(vm_xml) @@ -3112,7 +3105,7 @@ def _get_disk_target(targets, disks_count, prefix): :param prefix: the prefix of the target name, i.e. "hd" """ for i in range(disks_count): - ret = "{}{}".format(prefix, string.ascii_lowercase[i]) + ret = f"{prefix}{string.ascii_lowercase[i]}" if ret not in targets: return ret return None @@ -3294,8 +3287,8 @@ def _compute_device_changes(old_xml, new_xml, to_skip): changes[dev_type] = {} if not to_skip[dev_type]: old = devices_node.findall(dev_type) - new = new_xml.findall("devices/{}".format(dev_type)) - changes[dev_type] = globals()["_diff_{}_lists".format(dev_type)](old, new) + new = new_xml.findall(f"devices/{dev_type}") + changes[dev_type] = globals()[f"_diff_{dev_type}_lists"](old, new) return changes @@ -3499,7 +3492,7 @@ def update( stop_on_reboot=False, host_devices=None, autostart=False, - **kwargs + **kwargs, ): """ Update the definition of an existing domain. @@ -3761,7 +3754,7 @@ def update( consoles=consoles, stop_on_reboot=stop_on_reboot, host_devices=host_devices, - **kwargs + **kwargs, ) ) set_autostart(name, "on" if autostart else "off") @@ -3796,7 +3789,7 @@ def update( # _handle_unit treats bytes as invalid unit for the purpose of consistency unit = unit if unit != "bytes" else "b" value = node.get("memory") or node.get("size") or node.text - return _handle_unit("{}{}".format(value, unit)) if value else None + return _handle_unit(f"{value}{unit}") if value else None def _set_vcpu(node, value): node.text = str(value) @@ -4063,32 +4056,32 @@ def update( for timer in timer_names: params_mapping += [ xmlutil.attribute( - "clock:timers:{}:track".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:track", + f"clock/timer[@name='{timer}']", "track", ["name"], ), xmlutil.attribute( - "clock:timers:{}:tickpolicy".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:tickpolicy", + f"clock/timer[@name='{timer}']", "tickpolicy", ["name"], ), xmlutil.int_attribute( - "clock:timers:{}:frequency".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:frequency", + f"clock/timer[@name='{timer}']", "frequency", ["name"], ), xmlutil.attribute( - "clock:timers:{}:mode".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:mode", + f"clock/timer[@name='{timer}']", "mode", ["name"], ), _yesno_attribute( - "clock:timers:{}:present".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:present", + f"clock/timer[@name='{timer}']", "present", ["name"], ), @@ -4096,8 +4089,8 @@ def update( for attr in ["slew", "threshold", "limit"]: params_mapping.append( xmlutil.int_attribute( - "clock:timers:{}:{}".format(timer, attr), - "clock/timer[@name='{}']/catchup".format(timer), + f"clock:timers:{timer}:{attr}", + f"clock/timer[@name='{timer}']/catchup", attr, ) ) @@ -5490,7 +5483,7 @@ def migrate(vm_, target, **kwargs): if not urllib.parse.urlparse(target).scheme: proto = "qemu" - dst_uri = "{}://{}/system".format(proto, target) + dst_uri = f"{proto}://{target}/system" else: dst_uri = target @@ -5779,7 +5772,7 @@ def get_hypervisor(): result = [ hyper for hyper in hypervisors - if getattr(sys.modules[__name__], "_is_{}_hyper".format(hyper))() + if getattr(sys.modules[__name__], f"_is_{hyper}_hyper")() ] return result[0] if result else None @@ -5862,7 +5855,7 @@ def vm_cputime(vm_=None, **kwargs): cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus return { "cputime": int(raw[4]), - "cputime_percent": int("{:.0f}".format(cputime_percent)), + "cputime_percent": int(f"{cputime_percent:.0f}"), } info = {} @@ -6134,7 +6127,7 @@ def snapshot(domain, name=None, suffix=None, **kwargs): ) if suffix: - name = "{name}-{suffix}".format(name=name, suffix=suffix) + name = f"{name}-{suffix}" doc = ElementTree.Element("domainsnapshot") n_name = ElementTree.SubElement(doc, "name") @@ -6258,7 +6251,7 @@ def revert_snapshot(name, vm_snapshot=None, cleanup=False, **kwargs): conn.close() raise CommandExecutionError( snapshot - and 'Snapshot "{}" not found'.format(vm_snapshot) + and f'Snapshot "{vm_snapshot}" not found' or "No more previous snapshots available" ) elif snap.isCurrent(): @@ -6363,7 +6356,7 @@ def _parse_caps_cell(cell): if mem_node is not None: unit = mem_node.get("unit", "KiB") memory = mem_node.text - result["memory"] = "{} {}".format(memory, unit) + result["memory"] = f"{memory} {unit}" pages = [ { @@ -6425,7 +6418,7 @@ def _parse_caps_bank(bank): minimum = control.get("min") if minimum: - result_control["min"] = "{} {}".format(minimum, unit) + result_control["min"] = f"{minimum} {unit}" controls.append(result_control) if controls: result["controls"] = controls @@ -6848,11 +6841,9 @@ def cpu_baseline(full=False, migratable=False, out="libvirt", **kwargs): ] if not cpu_specs: - raise ValueError("Model {} not found in CPU map".format(cpu_model)) + raise ValueError(f"Model {cpu_model} not found in CPU map") elif len(cpu_specs) > 1: - raise ValueError( - "Multiple models {} found in CPU map".format(cpu_model) - ) + raise ValueError(f"Multiple models {cpu_model} found in CPU map") cpu_specs = cpu_specs[0] @@ -6892,7 +6883,7 @@ def network_define( addresses=None, physical_function=None, dns=None, - **kwargs + **kwargs, ): """ Create libvirt network. @@ -7191,7 +7182,7 @@ def network_update( physical_function=None, dns=None, test=False, - **kwargs + **kwargs, ): """ Update a virtual network if needed. @@ -7658,14 +7649,12 @@ def _parse_pools_caps(doc): } for option_kind in ["pool", "vol"]: options = {} - default_format_node = pool.find( - "{}Options/defaultFormat".format(option_kind) - ) + default_format_node = pool.find(f"{option_kind}Options/defaultFormat") if default_format_node is not None: options["default_format"] = default_format_node.get("type") options_enums = { enum.get("name"): [value.text for value in enum.findall("value")] - for enum in pool.findall("{}Options/enum".format(option_kind)) + for enum in pool.findall(f"{option_kind}Options/enum") } if options_enums: options.update(options_enums) @@ -7888,7 +7877,7 @@ def pool_define( source_format=None, transient=False, start=True, # pylint: disable=redefined-outer-name - **kwargs + **kwargs, ): """ Create libvirt pool. @@ -8076,9 +8065,9 @@ def _pool_set_secret( # Create secret if needed if not secret: - description = "Passphrase for {} pool created by Salt".format(pool_name) + description = f"Passphrase for {pool_name} pool created by Salt" if not usage: - usage = "pool_{}".format(pool_name) + usage = f"pool_{pool_name}" secret_xml = _gen_secret_xml(secret_type, usage, description) if not test: secret = conn.secretDefineXML(secret_xml) @@ -8114,7 +8103,7 @@ def pool_update( source_name=None, source_format=None, test=False, - **kwargs + **kwargs, ): """ Update a libvirt storage pool if needed. @@ -8487,7 +8476,7 @@ def pool_undefine(name, **kwargs): } secret_type = auth_types[auth_node.get("type")] secret_usage = auth_node.find("secret").get("usage") - if secret_type and "pool_{}".format(name) == secret_usage: + if secret_type and f"pool_{name}" == secret_usage: secret = conn.secretLookupByUsage(secret_type, secret_usage) secret.undefine() @@ -8809,7 +8798,7 @@ def volume_define( permissions=None, backing_store=None, nocow=False, - **kwargs + **kwargs, ): """ Create libvirt volume. @@ -8910,7 +8899,7 @@ def _volume_upload(conn, pool, volume, file, offset=0, length=0, sparse=False): inData = False eof = os.lseek(fd, 0, os.SEEK_END) if eof < cur: - raise RuntimeError("Current position in file after EOF: {}".format(cur)) + raise RuntimeError(f"Current position in file after EOF: {cur}") sectionLen = eof - cur else: if data > cur: @@ -8963,16 +8952,14 @@ def _volume_upload(conn, pool, volume, file, offset=0, length=0, sparse=False): if stream: stream.abort() if ret: - raise CommandExecutionError( - "Failed to close file: {}".format(err.strerror) - ) + raise CommandExecutionError(f"Failed to close file: {err.strerror}") if stream: try: stream.finish() except libvirt.libvirtError as err: if ret: raise CommandExecutionError( - "Failed to finish stream: {}".format(err.get_error_message()) + f"Failed to finish stream: {err.get_error_message()}" ) return ret diff --git a/salt/modules/win_iis.py b/salt/modules/win_iis.py index 42ec335bf32..3a2500d637b 100644 --- a/salt/modules/win_iis.py +++ b/salt/modules/win_iis.py @@ -1454,7 +1454,7 @@ def set_container_setting(name, container, settings): # Map to numeric to support server 2008 if ( setting == "processModel.identityType" - and settings[setting] in identityType_map2numeric.keys() + and settings[setting] in identityType_map2numeric ): value = identityType_map2numeric[settings[setting]] @@ -1488,7 +1488,7 @@ def set_container_setting(name, container, settings): # map identity type from numeric to string for comparing if ( setting == "processModel.identityType" - and settings[setting] in identityType_map2string.keys() + and settings[setting] in identityType_map2string ): settings[setting] = identityType_map2string[settings[setting]] diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index 324d49bcba3..1875edad440 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -8687,8 +8687,8 @@ def get_policy_info(policy_name, policy_class, adml_language="en-US"): } policy_class = policy_class.title() policy_data = _policy_info() - if policy_class not in policy_data.policies.keys(): - policy_classes = ", ".join(policy_data.policies.keys()) + if policy_class not in policy_data.policies: + policy_classes = ", ".join(policy_data.policies) ret["message"] = ( 'The requested policy class "{}" is invalid, ' "policy_class should be one of: {}" @@ -9712,7 +9712,7 @@ def get_policy( raise SaltInvocationError("policy_class must be defined") policy_class = policy_class.title() policy_data = _policy_info() - if policy_class not in policy_data.policies.keys(): + if policy_class not in policy_data.policies: policy_classes = ", ".join(policy_data.policies.keys()) raise CommandExecutionError( 'The requested policy class "{}" is invalid, policy_class should ' diff --git a/salt/modules/win_lgpo_reg.py b/salt/modules/win_lgpo_reg.py index e84d0dc2ffe..b3e1fef58e4 100644 --- a/salt/modules/win_lgpo_reg.py +++ b/salt/modules/win_lgpo_reg.py @@ -373,16 +373,16 @@ def set_value( if found_key: if found_name: if "**del." in found_name: - log.debug(f"LGPO_REG Mod: Found disabled name: {found_name}") + log.debug("LGPO_REG Mod: Found disabled name: %s", found_name) pol_data[found_key][v_name] = pol_data[found_key].pop(found_name) found_name = v_name - log.debug(f"LGPO_REG Mod: Updating value: {found_name}") + log.debug("LGPO_REG Mod: Updating value: %s", found_name) pol_data[found_key][found_name] = {"data": v_data, "type": v_type} else: - log.debug(f"LGPO_REG Mod: Setting new value: {found_name}") + log.debug("LGPO_REG Mod: Setting new value: %s", found_name) pol_data[found_key][v_name] = {"data": v_data, "type": v_type} else: - log.debug(f"LGPO_REG Mod: Adding new key and value: {found_name}") + log.debug("LGPO_REG Mod: Adding new key and value: %s", found_name) pol_data[key] = {v_name: {"data": v_data, "type": v_type}} success = True @@ -462,20 +462,22 @@ def disable_value(key, v_name, policy_class="machine"): if found_key: if found_name: if "**del." in found_name: - log.debug(f"LGPO_REG Mod: Already disabled: {v_name}") + log.debug("LGPO_REG Mod: Already disabled: %s", v_name) return None - log.debug(f"LGPO_REG Mod: Disabling value name: {v_name}") + log.debug("LGPO_REG Mod: Disabling value name: %s", v_name) pol_data[found_key].pop(found_name) found_name = "**del.{}".format(found_name) pol_data[found_key][found_name] = {"data": " ", "type": "REG_SZ"} else: - log.debug(f"LGPO_REG Mod: Setting new disabled value name: {v_name}") + log.debug("LGPO_REG Mod: Setting new disabled value name: %s", v_name) pol_data[found_key]["**del.{}".format(v_name)] = { "data": " ", "type": "REG_SZ", } else: - log.debug(f"LGPO_REG Mod: Adding new key and disabled value name: {found_name}") + log.debug( + "LGPO_REG Mod: Adding new key and disabled value name: %s", found_name + ) pol_data[key] = {"**del.{}".format(v_name): {"data": " ", "type": "REG_SZ"}} success = True @@ -553,16 +555,16 @@ def delete_value(key, v_name, policy_class="Machine"): if found_key: if found_name: - log.debug(f"LGPO_REG Mod: Removing value name: {found_name}") + log.debug("LGPO_REG Mod: Removing value name: %s", found_name) pol_data[found_key].pop(found_name) else: - log.debug(f"LGPO_REG Mod: Value name not found: {v_name}") + log.debug("LGPO_REG Mod: Value name not found: %s", v_name) return None if len(pol_data[found_key]) == 0: - log.debug(f"LGPO_REG Mod: Removing empty key: {found_key}") + log.debug("LGPO_REG Mod: Removing empty key: %s", found_key) pol_data.pop(found_key) else: - log.debug(f"LGPO_REG Mod: Key not found: {key}") + log.debug("LGPO_REG Mod: Key not found: %s", key) return None success = True diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index e8fdf22e419..fec5ab56a9c 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -1656,7 +1656,7 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): # single files if cache_dir and installer.startswith("salt:"): path, _ = os.path.split(installer) - log.debug(f"PKG: Caching directory: {path}") + log.debug("PKG: Caching directory: %s", path) try: __salt__["cp.cache_dir"]( path=path, @@ -1673,7 +1673,7 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): # Check to see if the cache_file is cached... if passed if cache_file and cache_file.startswith("salt:"): cache_file_hash = __salt__["cp.hash_file"](cache_file, saltenv) - log.debug(f"PKG: Caching file: {cache_file}") + log.debug("PKG: Caching file: %s", cache_file) try: cached_file = __salt__["cp.cache_file"]( cache_file, @@ -1703,7 +1703,7 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): # file if the source_hash doesn't match, which only works on # files hosted on "salt://". If the http/https url supports # etag, it should also verify that information before caching - log.debug(f"PKG: Caching file: {installer}") + log.debug("PKG: Caching file: %s", installer) try: cached_pkg = __salt__["cp.cache_file"]( installer, @@ -2102,7 +2102,7 @@ def remove(name=None, pkgs=None, **kwargs): if cache_dir and uninstaller.startswith("salt:"): path, _ = os.path.split(uninstaller) - log.debug(f"PKG: Caching dir: {path}") + log.debug("PKG: Caching dir: %s", path) try: __salt__["cp.cache_dir"]( path=path, @@ -2126,7 +2126,7 @@ def remove(name=None, pkgs=None, **kwargs): # only works on files hosted on "salt://". If the http/https # url supports etag, it should also verify that information # before caching - log.debug(f"PKG: Caching file: {uninstaller}") + log.debug("PKG: Caching file: %s", uninstaller) try: cached_pkg = __salt__["cp.cache_file"]( uninstaller, diff --git a/salt/modules/win_pki.py b/salt/modules/win_pki.py index defb92e9d8b..c90af40dd1b 100644 --- a/salt/modules/win_pki.py +++ b/salt/modules/win_pki.py @@ -124,7 +124,7 @@ def get_stores(): salt '*' win_pki.get_stores """ ret = dict() - cmd = r"Get-ChildItem -Path 'Cert:\' | " r"Select-Object LocationName, StoreNames" + cmd = r"Get-ChildItem -Path 'Cert:\' | Select-Object LocationName, StoreNames" items = _cmd_run(cmd=cmd, as_json=True) diff --git a/salt/modules/win_shortcut.py b/salt/modules/win_shortcut.py index c11cc1c64d1..97048b45560 100644 --- a/salt/modules/win_shortcut.py +++ b/salt/modules/win_shortcut.py @@ -82,7 +82,9 @@ def get(path): # This will load the existing shortcut with salt.utils.winapi.Com(): - shell = win32com.client.Dispatch("WScript.Shell") + shell = win32com.client.Dispatch( # pylint: disable=used-before-assignment + "WScript.Shell" + ) shortcut = shell.CreateShortcut(path) arguments = "" diff --git a/salt/modules/win_status.py b/salt/modules/win_status.py index fad2323a43b..033af16e063 100644 --- a/salt/modules/win_status.py +++ b/salt/modules/win_status.py @@ -147,9 +147,6 @@ def __virtual__(): if not HAS_PSUTIL: return False, "win_status.py: Requires psutil" - # Namespace modules from `status.py` - global ping_master, time_ - return __virtualname__ @@ -525,9 +522,7 @@ def master(master=None, connected=True): """ remotes = set() try: - data = subprocess.check_output( - ["netstat", "-n", "-p", "TCP"] - ) # pylint: disable=minimum-python-version + data = subprocess.check_output(["netstat", "-n", "-p", "TCP"]) except subprocess.CalledProcessError: log.error("Failed netstat") raise diff --git a/salt/modules/win_task.py b/salt/modules/win_task.py index 8c9f2718dbd..2e8750ddb97 100644 --- a/salt/modules/win_task.py +++ b/salt/modules/win_task.py @@ -227,7 +227,7 @@ def _get_date_value(date): :rtype: str """ try: - return "{}".format(date) + return f"{date}" except ValueError: return "Never" @@ -245,7 +245,7 @@ def _reverse_lookup(dictionary, value): """ value_index = -1 for idx, dict_value in enumerate(dictionary.values()): - if type(dict_value) == list: + if isinstance(dict_value, list): if value in dict_value: value_index = idx break @@ -269,7 +269,7 @@ def _lookup_first(dictionary, key): :rtype: str """ value = dictionary[key] - if type(value) == list: + if isinstance(value, list): return value[0] else: return value @@ -323,11 +323,11 @@ def _save_task_definition( try: failure_code = fc[exc[5]] except KeyError: - failure_code = "Unknown Failure: {}".format(error) + failure_code = f"Unknown Failure: {error}" log.debug("Failed to modify task: %s", failure_code) - return "Failed to modify task: {}".format(failure_code) + return f"Failed to modify task: {failure_code}" def list_tasks(location="\\"): @@ -363,7 +363,7 @@ def list_tasks(location="\\"): try: task_folder = task_service.GetFolder(location) except pywintypes.com_error: - msg = "Unable to load location: {}".format(location) + msg = f"Unable to load location: {location}" log.error(msg) raise CommandExecutionError(msg) @@ -551,7 +551,7 @@ def create_task( # Check for existing task if name in list_tasks(location) and not force: # Connect to an existing task definition - return "{} already exists".format(name) + return f"{name} already exists" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -566,7 +566,7 @@ def create_task( task_definition=task_definition, user_name=user_name, password=password, - **kwargs + **kwargs, ) # Add Action @@ -642,7 +642,7 @@ def create_task_from_xml( # Check for existing task if name in list_tasks(location): # Connect to an existing task definition - return "{} already exists".format(name) + return f"{name} already exists" if not xml_text and not xml_path: raise ArgumentValueError("Must specify either xml_text or xml_path") @@ -731,7 +731,7 @@ def create_task_from_xml( try: failure_code = fc[error_code] except KeyError: - failure_code = "Unknown Failure: {}".format(error_code) + failure_code = f"Unknown Failure: {error_code}" finally: log.debug("Failed to create task: %s", failure_code) raise CommandExecutionError(failure_code) @@ -767,7 +767,7 @@ def create_folder(name, location="\\"): # Check for existing folder if name in list_folders(location): # Connect to an existing task definition - return "{} already exists".format(name) + return f"{name} already exists" # Create the task service object with salt.utils.winapi.Com(): @@ -812,7 +812,7 @@ def edit_task( force_stop=None, delete_after=None, multiple_instances=None, - **kwargs + **kwargs, ): r""" Edit the parameters of a task. Triggers and Actions cannot be edited yet. @@ -1016,7 +1016,7 @@ def edit_task( else: # Not found and create_new not set, return not found - return "{} not found".format(name) + return f"{name} not found" # General Information if save_definition: @@ -1183,7 +1183,7 @@ def delete_task(name, location="\\"): """ # Check for existing task if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1224,7 +1224,7 @@ def delete_folder(name, location="\\"): """ # Check for existing folder if name not in list_folders(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1266,7 +1266,7 @@ def run(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1309,7 +1309,7 @@ def run_wait(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1370,7 +1370,7 @@ def stop(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1419,7 +1419,7 @@ def status(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1458,7 +1458,7 @@ def info(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1714,7 +1714,7 @@ def add_action(name=None, location="\\", action_type="Execute", **kwargs): else: # Not found and create_new not set, return not found - return "{} not found".format(name) + return f"{name} not found" # Action Settings task_action = task_definition.Actions.Create(action_types[action_type]) @@ -1808,7 +1808,7 @@ def _clear_actions(name, location="\\"): # TODO: action. # Check for existing task if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # Create the task service object with salt.utils.winapi.Com(): @@ -1848,7 +1848,7 @@ def add_trigger( repeat_stop_at_duration_end=False, execution_time_limit=None, delay=None, - **kwargs + **kwargs, ): r""" Add a trigger to a Windows Scheduled task @@ -2303,7 +2303,7 @@ def add_trigger( else: # Not found and create_new not set, return not found - return "{} not found".format(name) + return f"{name} not found" # Create a New Trigger trigger = task_definition.Triggers.Create(trigger_types[trigger_type]) @@ -2481,7 +2481,7 @@ def clear_triggers(name, location="\\"): """ # Check for existing task if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # Create the task service object with salt.utils.winapi.Com(): diff --git a/salt/modules/x509_v2.py b/salt/modules/x509_v2.py index ba26d7b6b2e..f0b9b40130e 100644 --- a/salt/modules/x509_v2.py +++ b/salt/modules/x509_v2.py @@ -1907,7 +1907,7 @@ def _query_remote(ca_server, signing_policy, kwargs, get_signing_policy_only=Fal ) result = result[next(iter(result))] if not isinstance(result, dict) or "data" not in result: - log.error(f"Received invalid return value from ca_server: {result}") + log.error("Received invalid return value from ca_server: %s", result) raise CommandExecutionError( "Received invalid return value from ca_server. See minion log for details" ) diff --git a/salt/modules/xapi_virt.py b/salt/modules/xapi_virt.py index 489a5b2ed4a..2d03d231ffb 100644 --- a/salt/modules/xapi_virt.py +++ b/salt/modules/xapi_virt.py @@ -17,6 +17,7 @@ Useful documentation: """ import contextlib +import importlib import os import sys @@ -26,15 +27,6 @@ import salt.utils.path import salt.utils.stringutils from salt.exceptions import CommandExecutionError -try: - import importlib # pylint: disable=minimum-python-version - - HAS_IMPORTLIB = True -except ImportError: - # Python < 2.7 does not have importlib - HAS_IMPORTLIB = False - - # Define the module's virtual name __virtualname__ = "virt" @@ -50,14 +42,12 @@ def _check_xenapi(): if os.path.isfile(debian_xen_version): # __salt__ is not available in __virtual__ xenversion = salt.modules.cmdmod._run_quiet(debian_xen_version) - xapipath = "/usr/lib/xen-{}/lib/python".format(xenversion) + xapipath = f"/usr/lib/xen-{xenversion}/lib/python" if os.path.isdir(xapipath): sys.path.append(xapipath) try: - if HAS_IMPORTLIB: - return importlib.import_module("xen.xm.XenAPI") - return __import__("xen.xm.XenAPI").xm.XenAPI + return importlib.import_module("xen.xm.XenAPI") except (ImportError, AttributeError): return False @@ -156,7 +146,7 @@ def _get_metrics_record(xapi, rectype, record): Internal, returns metrics record for a rectype """ metrics_id = record["metrics"] - return getattr(xapi, "{}_metrics".format(rectype)).get_record(metrics_id) + return getattr(xapi, f"{rectype}_metrics").get_record(metrics_id) def _get_val(record, keys): @@ -507,10 +497,10 @@ def vcpu_pin(vm_, vcpu, cpus): if cpus == "all": cpumap = cpu_make_map("0-63") else: - cpumap = cpu_make_map("{}".format(cpus)) + cpumap = cpu_make_map(f"{cpus}") try: - xapi.VM.add_to_VCPUs_params_live(vm_uuid, "cpumap{}".format(vcpu), cpumap) + xapi.VM.add_to_VCPUs_params_live(vm_uuid, f"cpumap{vcpu}", cpumap) return True # VM.add_to_VCPUs_params_live() implementation in xend 4.1+ has # a bug which makes the client call fail. @@ -518,7 +508,7 @@ def vcpu_pin(vm_, vcpu, cpus): # for that particular one, fallback to xm / xl instead. except Exception: # pylint: disable=broad-except return __salt__["cmd.run"]( - "{} vcpu-pin {} {} {}".format(_get_xtool(), vm_, vcpu, cpus), + f"{_get_xtool()} vcpu-pin {vm_} {vcpu} {cpus}", python_shell=False, ) @@ -641,9 +631,7 @@ def start(config_): # This function does NOT use the XenAPI. Instead, it use good old xm / xl. # On Xen Source, creating a virtual machine using XenAPI is really painful. # XCP / XS make it really easy using xapi.Async.VM.start instead. Anyone? - return __salt__["cmd.run"]( - "{} create {}".format(_get_xtool(), config_), python_shell=False - ) + return __salt__["cmd.run"](f"{_get_xtool()} create {config_}", python_shell=False) def reboot(vm_): @@ -816,7 +804,7 @@ def vm_cputime(vm_=None): cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus return { "cputime": int(cputime), - "cputime_percent": int("{:.0f}".format(cputime_percent)), + "cputime_percent": int(f"{cputime_percent:.0f}"), } info = {} diff --git a/salt/modules/xfs.py b/salt/modules/xfs.py index 04b104f9967..b506cd965e7 100644 --- a/salt/modules/xfs.py +++ b/salt/modules/xfs.py @@ -319,7 +319,10 @@ def _blkid_output(out): """ Parse blkid output. """ - flt = lambda data: [el for el in data if el.strip()] + + def flt(data): + return [el for el in data if el.strip()] + data = {} for dev_meta in flt(out.split("\n\n")): dev = {} @@ -439,11 +442,13 @@ def mkfs( salt '*' xfs.mkfs /dev/sda1 dso='su=32k,sw=6' lso='logdev=/dev/sda2,size=10000b' """ - getopts = lambda args: dict( - (args and ("=" in args) and args or None) - and [kw.split("=") for kw in args.split(",")] - or [] - ) + def getopts(args): + return dict( + (args and ("=" in args) and args or None) + and [kw.split("=") for kw in args.split(",")] + or [] + ) + cmd = ["mkfs.xfs"] if label: cmd.append("-L") diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index f794389c861..fa8e0eeffe3 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -397,7 +397,7 @@ def _get_yum_config_value(name, strict_config=True): Look for a specific config variable and return its value """ conf = _get_yum_config(strict_config) - if name in conf.keys(): + if name in conf: return conf.get(name) return None @@ -3135,7 +3135,9 @@ def mod_repo(repo, basedir=None, **kwargs): if key in filerepos[repo].copy().keys(): del filerepos[repo][key] - _bool_to_str = lambda x: "1" if x else "0" + def _bool_to_str(x): + return "1" if x else "0" + # Old file or new, write out the repos(s) filerepos[repo].update(repo_opts) content = header diff --git a/salt/modules/zcbuildout.py b/salt/modules/zcbuildout.py index 99b9202011e..3552d580890 100644 --- a/salt/modules/zcbuildout.py +++ b/salt/modules/zcbuildout.py @@ -287,7 +287,7 @@ def _Popen( directory = os.path.abspath(directory) if isinstance(command, list): command = " ".join(command) - LOG.debug("Running {}".format(command)) # pylint: disable=str-format-in-logging + LOG.debug(f"Running {command}") if not loglevel: loglevel = "debug" ret = __salt__["cmd.run_all"]( @@ -499,7 +499,7 @@ def upgrade_bootstrap( else: buildout_ver = _get_buildout_ver(directory) booturl = _get_bootstrap_url(directory) - LOG.debug("Using {}".format(booturl)) # pylint: disable=str-format-in-logging + LOG.debug(f"Using {booturl}") # try to download an up-to-date bootstrap # set defaulttimeout # and add possible content @@ -792,9 +792,7 @@ def run_buildout( cmds, outputs = [], [] if parts: for part in parts: - LOG.info( - "Installing single part: {}".format(part) - ) # pylint: disable=str-format-in-logging + LOG.info(f"Installing single part: {part}") cmd = "{} -c {} {} install {}".format(bcmd, config, " ".join(argv), part) cmds.append(cmd) outputs.append( @@ -960,9 +958,7 @@ def buildout( salt '*' buildout.buildout /srv/mybuildout """ - LOG.info( - "Running buildout in {} ({})".format(directory, config) - ) # pylint: disable=str-format-in-logging + LOG.info(f"Running buildout in {directory} ({config})") boot_ret = bootstrap( directory, config=config, diff --git a/salt/netapi/rest_cherrypy/__init__.py b/salt/netapi/rest_cherrypy/__init__.py index fbc85c9ff60..4580c6dc81b 100644 --- a/salt/netapi/rest_cherrypy/__init__.py +++ b/salt/netapi/rest_cherrypy/__init__.py @@ -28,7 +28,7 @@ cpy_min = "3.2.2" def __virtual__(): - short_name = __name__.rsplit(".")[-1] + short_name = __name__.rsplit(".", maxsplit=1)[-1] mod_opts = __opts__.get(short_name, {}) if mod_opts: diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index e65bca8f2d9..3a4571968b4 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -711,9 +711,9 @@ def salt_api_acl_tool(username, request): :param request: Cherrypy request to check against the API. :type request: cherrypy.request """ - failure_str = "[api_acl] Authentication failed for " "user %s from IP %s" + failure_str = "[api_acl] Authentication failed for user %s from IP %s" success_str = "[api_acl] Authentication successful for user %s from IP %s" - pass_str = "[api_acl] Authentication not checked for " "user %s from IP %s" + pass_str = "[api_acl] Authentication not checked for user %s from IP %s" acl = None # Salt Configuration @@ -777,7 +777,7 @@ def salt_auth_tool(): Redirect all unauthenticated requests to the login page """ # Redirect to the login page if the session hasn't been authed - if "token" not in cherrypy.session: # pylint: disable=W8601 + if "token" not in cherrypy.session: raise cherrypy.HTTPError(401) # Session is authenticated; inform caches @@ -1145,7 +1145,7 @@ for hook, tool_list in tools_config.items(): for idx, tool_config in enumerate(tool_list): tool_name, tool_fn = tool_config setattr( - cherrypy.tools, tool_name, cherrypy.Tool(hook, tool_fn, priority=(50 + idx)) + cherrypy.tools, tool_name, cherrypy.Tool(hook, tool_fn, priority=50 + idx) ) diff --git a/salt/netapi/rest_tornado/saltnado.py b/salt/netapi/rest_tornado/saltnado.py index 6d47de1446a..a0697bbc3fc 100644 --- a/salt/netapi/rest_tornado/saltnado.py +++ b/salt/netapi/rest_tornado/saltnado.py @@ -333,12 +333,12 @@ class EventListener: Get an event (asynchronous of course) return a future that will get it later """ future = Future() + _loop = salt.ext.tornado.ioloop.IOLoop.current() + assert _loop if callback is not None: def handle_future(future): - salt.ext.tornado.ioloop.IOLoop.current().add_callback( - callback, future - ) # pylint: disable=E1102 + _loop.add_callback(callback, future) # pylint: disable=not-callable future.add_done_callback(handle_future) # add this tag and future to the callbacks @@ -346,7 +346,7 @@ class EventListener: self.request_map[request].append((tag, matcher, future)) if timeout: - timeout_future = salt.ext.tornado.ioloop.IOLoop.current().call_later( + timeout_future = _loop.call_later( timeout, self._timeout_future, tag, matcher, future ) self.timeout_map[future] = timeout_future diff --git a/salt/output/pony.py b/salt/output/pony.py index 908b8b29392..f1d6d1e3d9a 100644 --- a/salt/output/pony.py +++ b/salt/output/pony.py @@ -66,6 +66,4 @@ def output(data, **kwargs): # pylint: disable=unused-argument Mane function """ high_out = __salt__["highstate"](data) - return subprocess.check_output( - ["ponysay", salt.utils.data.decode(high_out)] - ) # pylint: disable=E0598 + return subprocess.check_output(["ponysay", salt.utils.data.decode(high_out)]) diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py index 9ad3c485fdf..dde097a209a 100644 --- a/salt/pillar/__init__.py +++ b/salt/pillar/__init__.py @@ -259,8 +259,8 @@ class AsyncRemotePillar(RemotePillarMixin): load["clean_cache"] = self.clean_cache if self.ext: load["ext"] = self.ext + start = time.monotonic() try: - start = time.monotonic() ret_pillar = yield self.channel.crypted_transfer_decode_dictentry( load, dictkey="pillar", @@ -357,8 +357,8 @@ class RemotePillar(RemotePillarMixin): if self.ext: load["ext"] = self.ext + start = time.monotonic() try: - start = time.monotonic() ret_pillar = self.channel.crypted_transfer_decode_dictentry( load, dictkey="pillar", @@ -1217,7 +1217,7 @@ class Pillar: errors.append( "Failed to load ext_pillar {}: {}".format( key, - exc.__str__(), + exc, ) ) log.error( diff --git a/salt/pillar/foreman.py b/salt/pillar/foreman.py index 62ae03072f2..298aae1ef20 100644 --- a/salt/pillar/foreman.py +++ b/salt/pillar/foreman.py @@ -111,6 +111,7 @@ def ext_pillar(minion_id, pillar, key=None, only=()): # pylint: disable=W0613 headers=headers, verify=verify, cert=(certfile, keyfile), + timeout=120, ) result = resp.json() diff --git a/salt/pillar/pepa.py b/salt/pillar/pepa.py index a35ebb47a09..842a14d49a3 100644 --- a/salt/pillar/pepa.py +++ b/salt/pillar/pepa.py @@ -291,7 +291,7 @@ except ImportError: # Only used when called from a terminal log = None if __name__ == "__main__": - import argparse # pylint: disable=minimum-python-version + import argparse parser = argparse.ArgumentParser() parser.add_argument("hostname", help="Hostname") @@ -611,11 +611,11 @@ if __name__ == "__main__": log.info("Authenticate REST API") auth = {"username": username, "password": password, "eauth": "pam"} - request = requests.post(args.url + "/login", auth) + request = requests.post(args.url + "/login", auth, timeout=120) if not request.ok: raise RuntimeError( - "Failed to authenticate to SaltStack REST API: {}".format(request.text) + f"Failed to authenticate to SaltStack REST API: {request.text}" ) response = request.json() @@ -623,7 +623,9 @@ if __name__ == "__main__": log.info("Request Grains from REST API") headers = {"X-Auth-Token": token, "Accept": "application/json"} - request = requests.get(args.url + "/minions/" + args.hostname, headers=headers) + request = requests.get( + args.url + "/minions/" + args.hostname, headers=headers, timeout=120 + ) result = request.json().get("return", [{}])[0] if args.hostname not in result: @@ -651,8 +653,8 @@ if __name__ == "__main__": if __opts__["pepa_validate"]: validate(result, __opts__["ext_pillar"][loc]["pepa"]["resource"]) + orig_ignore = salt.utils.yaml.SafeOrderedDumper.ignore_aliases try: - orig_ignore = salt.utils.yaml.SafeOrderedDumper.ignore_aliases salt.utils.yaml.SafeOrderedDumper.ignore_aliases = lambda x, y: True def _print_result(result): diff --git a/salt/pillar/vault.py b/salt/pillar/vault.py index 3e7d06b6f78..6388ab923dd 100644 --- a/salt/pillar/vault.py +++ b/salt/pillar/vault.py @@ -241,5 +241,5 @@ def _get_paths(path_pattern, minion_id, pillar): except KeyError: log.warning("Could not resolve pillar path pattern %s", path_pattern) - log.debug(f"{minion_id} vault pillar paths: {paths}") + log.debug("%s vault pillar paths: %s", minion_id, paths) return paths diff --git a/salt/pillar/vmware_pillar.py b/salt/pillar/vmware_pillar.py index cb93efed0da..41fd89a771d 100644 --- a/salt/pillar/vmware_pillar.py +++ b/salt/pillar/vmware_pillar.py @@ -483,5 +483,5 @@ def _serializer(obj): if isinstance(obj, datetime.datetime): if obj.utcoffset() is not None: obj = obj - obj.utcoffset() - return obj.__str__() + return str(obj) return obj diff --git a/salt/platform/win.py b/salt/platform/win.py index 694238e4fc0..fff1010039b 100644 --- a/salt/platform/win.py +++ b/salt/platform/win.py @@ -15,6 +15,7 @@ import logging import os from ctypes import wintypes +# pylint: disable=3rd-party-module-not-gated import ntsecuritycon import psutil import win32api @@ -23,6 +24,8 @@ import win32process import win32security import win32service +# pylint: enable=3rd-party-module-not-gated + # Set up logging log = logging.getLogger(__name__) @@ -398,7 +401,7 @@ class ContiguousUnicode(ctypes.Structure): @classmethod def from_address_copy(cls, address, size=None): - x = ctypes.Structure.__new__(cls) + x = ctypes.Structure.__new__(cls) # pylint: disable=no-value-for-parameter if size is not None: ctypes.resize(x, size) ctypes.memmove(ctypes.byref(x), address, ctypes.sizeof(x)) diff --git a/salt/proxy/dummy.py b/salt/proxy/dummy.py index d470c1082a7..8656be31d93 100644 --- a/salt/proxy/dummy.py +++ b/salt/proxy/dummy.py @@ -95,7 +95,7 @@ def init(opts): __context__["dummy_proxy"] = {"id": opts["id"]} log.debug("dummy proxy init() called...") with _loaded_state(opts) as state: - state["initialized"] = True + state["initialized"] = True # pylint: disable=unsupported-assignment-operation def initialized(): @@ -113,12 +113,12 @@ def grains(): Make up some grains """ with _loaded_state(__opts__) as state: - if "grains_cache" not in state: - state["grains_cache"] = { - "dummy_grain_1": "one", - "dummy_grain_2": "two", - "dummy_grain_3": "three", - } + # pylint: disable=unsupported-assignment-operation,unsupported-membership-test + state["grains_cache"] = { + "dummy_grain_1": "one", + "dummy_grain_2": "two", + "dummy_grain_3": "three", + } return state["grains_cache"] @@ -127,7 +127,7 @@ def grains_refresh(): Refresh the grains """ with _loaded_state(__opts__) as state: - if "grains_cache" in state: + if "grains_cache" in state: # pylint: disable=unsupported-membership-test state.pop("grains_cache") return grains() @@ -262,7 +262,7 @@ def shutdown(opts): """ log.debug("dummy proxy shutdown() called...") with _loaded_state(__opts__) as state: - if "filename" in state: + if "filename" in state: # pylint: disable=unsupported-membership-test os.unlink(state["filename"]) diff --git a/salt/proxy/philips_hue.py b/salt/proxy/philips_hue.py index 9b846baf096..d3400e3f66a 100644 --- a/salt/proxy/philips_hue.py +++ b/salt/proxy/philips_hue.py @@ -117,9 +117,9 @@ def _query(lamp_id, state, action="", method="GET"): # Because salt.utils.query is that dreadful... :( err = None - url = "{}/lights{}".format( - CONFIG["uri"], lamp_id and "/{}".format(lamp_id) or "" - ) + (action and "/{}".format(action) or "") + url = "{}/lights{}".format(CONFIG["uri"], lamp_id and f"/{lamp_id}" or "") + ( + action and f"/{action}" or "" + ) conn = http.client.HTTPConnection(CONFIG["host"]) if method == "PUT": conn.request(method, url, salt.utils.json.dumps(state)) @@ -130,7 +130,7 @@ def _query(lamp_id, state, action="", method="GET"): if resp.status == http.client.OK: res = salt.utils.json.loads(resp.read()) else: - err = "HTTP error: {}, {}".format(resp.status, resp.reason) + err = f"HTTP error: {resp.status}, {resp.reason}" conn.close() if err: raise CommandExecutionError(err) @@ -175,7 +175,7 @@ def _get_devices(params): raise CommandExecutionError("Parameter ID is required.") return ( - type(params["id"]) == int + isinstance(params["id"], int) and [params["id"]] or [int(dev) for dev in params["id"].split(",")] ) diff --git a/salt/renderers/genshi.py b/salt/renderers/genshi.py index 206cce5a3fe..9a9e57b6711 100644 --- a/salt/renderers/genshi.py +++ b/salt/renderers/genshi.py @@ -4,7 +4,9 @@ Genshi Renderer for Salt try: - from genshi.template import MarkupTemplate, NewTextTemplate, OldTextTemplate + from genshi.template import MarkupTemplate # pylint: disable=no-name-in-module + from genshi.template import NewTextTemplate # pylint: disable=no-name-in-module + from genshi.template import OldTextTemplate # pylint: disable=no-name-in-module HAS_LIBS = True except ImportError: diff --git a/salt/renderers/stateconf.py b/salt/renderers/stateconf.py index 3b0348633af..c93a564f0ed 100644 --- a/salt/renderers/stateconf.py +++ b/salt/renderers/stateconf.py @@ -65,7 +65,7 @@ STATE_FUNC = STATE_NAME = "" def __init__(opts): global STATE_NAME, STATE_FUNC STATE_FUNC = __opts__["stateconf_state_func"] - STATE_NAME = STATE_FUNC.split(".")[0] + STATE_NAME = STATE_FUNC.split(".", maxsplit=1)[0] MOD_BASENAME = os.path.basename(__file__) diff --git a/salt/returners/etcd_return.py b/salt/returners/etcd_return.py index fbac0e169df..fe1d1e4cf22 100644 --- a/salt/returners/etcd_return.py +++ b/salt/returners/etcd_return.py @@ -232,7 +232,7 @@ def get_fun(fun): client, path = _get_conn(__opts__) items = client.get("/".join((path, "minions")), recurse=True) for id, jid in items.items(): - id = str(id).split("/")[-1] + id = str(id).rsplit("/", maxsplit=1)[-1] efun = salt.utils.json.loads( client.get("/".join((path, "jobs", str(jid), id, "fun"))) ) @@ -251,7 +251,7 @@ def get_jids(): items = client.get("/".join((path, "jobs")), recurse=True) for key, value in items.items(): if isinstance(value, dict): # dict means directory - jid = str(key).split("/")[-1] + jid = str(key).rsplit("/", maxsplit=1)[-1] ret.append(jid) return ret @@ -265,7 +265,7 @@ def get_minions(): client, path = _get_conn(__opts__) items = client.get("/".join((path, "minions")), recurse=True) for id, _ in items.items(): - id = str(id).split("/")[-1] + id = str(id).rsplit("/", maxsplit=1)[-1] ret.append(id) return ret diff --git a/salt/returners/influxdb_return.py b/salt/returners/influxdb_return.py index 645218242aa..ff78d2b02d4 100644 --- a/salt/returners/influxdb_return.py +++ b/salt/returners/influxdb_return.py @@ -109,7 +109,7 @@ def _get_version(host, port, user, password): # check the InfluxDB version via the HTTP API try: result = requests.get( - "http://{}:{}/ping".format(host, port), auth=(user, password) + "http://{}:{}/ping".format(host, port), auth=(user, password), timeout=120 ) if influxDBVersionHeader in result.headers: version = result.headers[influxDBVersionHeader] diff --git a/salt/returners/local_cache.py b/salt/returners/local_cache.py index 1530d94ddfc..632e11c22e9 100644 --- a/salt/returners/local_cache.py +++ b/salt/returners/local_cache.py @@ -287,6 +287,7 @@ def get_load(jid): ret = {} load_p = os.path.join(jid_dir, LOAD_P) num_tries = 5 + exc = None for index in range(1, num_tries + 1): with salt.utils.files.fopen(load_p, "rb") as rfh: try: @@ -297,7 +298,8 @@ def get_load(jid): time.sleep(0.25) else: log.critical("Failed to unpack %s", load_p) - raise exc + if exc is not None: + raise exc if ret is None: ret = {} minions_cache = [os.path.join(jid_dir, MINIONS_P)] diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py index 67b44004acf..6ad64bebb36 100644 --- a/salt/returners/mysql.py +++ b/salt/returners/mysql.py @@ -148,10 +148,6 @@ import salt.utils.data import salt.utils.job import salt.utils.json -# Let's not allow PyLint complain about string substitution -# pylint: disable=W1321,E1321 - - try: # Trying to import MySQLdb import MySQLdb @@ -274,7 +270,7 @@ def _get_serv(ret=None, commit=False): pass except OperationalError as exc: raise salt.exceptions.SaltMasterError( - "MySQL returner could not connect to database: {exc}".format(exc=exc) + f"MySQL returner could not connect to database: {exc}" ) cursor = conn.cursor() diff --git a/salt/returners/pgjsonb.py b/salt/returners/pgjsonb.py index d47e9cce8d6..86fd63b7441 100644 --- a/salt/returners/pgjsonb.py +++ b/salt/returners/pgjsonb.py @@ -170,10 +170,6 @@ import salt.returners import salt.utils.data import salt.utils.job -# Let's not allow PyLint complain about string substitution -# pylint: disable=W1321,E1321 - - try: import psycopg2 import psycopg2.extras @@ -225,7 +221,7 @@ def _get_options(ret=None): } _options = salt.returners.get_returner_options( - "returner.{}".format(__virtualname__), + f"returner.{__virtualname__}", ret, attrs, __salt__=__salt__, @@ -258,11 +254,11 @@ def _get_serv(ret=None, commit=False): dbname=_options.get("db"), user=_options.get("user"), password=_options.get("pass"), - **ssl_options + **ssl_options, ) except psycopg2.OperationalError as exc: raise salt.exceptions.SaltMasterError( - "pgjsonb returner could not connect to database: {exc}".format(exc=exc) + f"pgjsonb returner could not connect to database: {exc}" ) if conn.server_version is not None and conn.server_version >= 90500: diff --git a/salt/returners/splunk.py b/salt/returners/splunk.py index df3414bcacf..5e11a550e59 100644 --- a/salt/returners/splunk.py +++ b/salt/returners/splunk.py @@ -210,6 +210,7 @@ class http_event_collector: data=salt.utils.json.dumps(data), headers=headers, verify=self.verify_ssl, + timeout=120, ) # Print debug info if flag set diff --git a/salt/roster/cache.py b/salt/roster/cache.py index a6a117d2d8e..ebae66ba2d5 100644 --- a/salt/roster/cache.py +++ b/salt/roster/cache.py @@ -199,15 +199,21 @@ def _data_lookup(ref, lookup): def _minion_lookup(minion_id, key, minion): grains, pillar, addrs, mine = minion + def _data_lookup_ref(data_id): + if data_id == "pillar": + return pillar + if data_id == "grains": + return grains + if data_id == "mine": + return mine + if key == "id": # Just paste in the minion ID return minion_id elif isinstance(key, dict): # Lookup the key in the dict for data_id, lookup in key.items(): - ref = {"pillar": pillar, "grain": grains, "mine": mine}[data_id] - - for k in _data_lookup(ref, lookup): + for k in _data_lookup(_data_lookup_ref(data_id), lookup): if k: return k @@ -220,7 +226,7 @@ def _minion_lookup(minion_id, key, minion): try: net = ipaddress.ip_network(key, strict=True) except ValueError: - log.error("%s is an invalid CIDR network", net) + log.error("%s is an invalid CIDR network", key) return None for addr in addrs[net.version]: diff --git a/salt/runners/asam.py b/salt/runners/asam.py index 81e547b784b..6014429c792 100644 --- a/salt/runners/asam.py +++ b/salt/runners/asam.py @@ -146,7 +146,7 @@ def _get_asam_configuration(driver_url=""): def _make_post_request(url, data, auth, verify=True): - r = requests.post(url, data=data, auth=auth, verify=verify) + r = requests.post(url, data=data, auth=auth, verify=verify, timeout=120) if r.status_code != requests.codes.ok: r.raise_for_status() else: diff --git a/salt/runners/launchd.py b/salt/runners/launchd.py index ce9be4e3a9c..268668a79a1 100644 --- a/salt/runners/launchd.py +++ b/salt/runners/launchd.py @@ -51,8 +51,8 @@ def write_launchd_plist(program): sys.stderr.write("Supported programs: '{}'\n".format(supported_programs)) sys.exit(-1) - return plist_sample_text.format( - program=program, - python=sys.executable, - script=os.path.join(os.path.dirname(sys.executable), program), - ) + return plist_sample_text.format( + program=program, + python=sys.executable, + script=os.path.join(os.path.dirname(sys.executable), program), + ) diff --git a/salt/runners/pkg.py b/salt/runners/pkg.py index 6a4a06e6109..5d084b45032 100644 --- a/salt/runners/pkg.py +++ b/salt/runners/pkg.py @@ -40,7 +40,7 @@ def list_upgrades(jid, style="group", outputter="nested", ext_source=None): for minion in data: results = data[minion]["return"] for pkg, pkgver in results.items(): - if pkg not in pkgs.keys(): + if pkg not in pkgs: pkgs[pkg] = {pkgver: {"hosts": []}} if pkgver not in pkgs[pkg].keys(): diff --git a/salt/runners/state.py b/salt/runners/state.py index 3baf1b86346..e0e41a659ba 100644 --- a/salt/runners/state.py +++ b/salt/runners/state.py @@ -106,7 +106,9 @@ def orchestrate( orig_user = __opts__["user"] __opts__["user"] = __user__ log.debug( - f"changed opts user from original '{orig_user}' to global user '{__user__}'" + "changed opts user from original '%s' to global user '%s'", + orig_user, + __user__, ) except NameError: log.debug("unable to find global user __user__") diff --git a/salt/runners/vault.py b/salt/runners/vault.py index f7c5ce37f10..12225aea361 100644 --- a/salt/runners/vault.py +++ b/salt/runners/vault.py @@ -84,7 +84,7 @@ def generate_token( if namespace is not None: headers = {"X-Vault-Namespace": namespace} response = requests.post( - url, headers=headers, json=payload, verify=verify + url, headers=headers, json=payload, verify=verify, timeout=120 ) if response.status_code != 200: return {"error": response.reason} @@ -117,7 +117,9 @@ def generate_token( return {"error": "No policies matched minion"} log.trace("Sending token creation request to Vault") - response = requests.post(url, headers=headers, json=payload, verify=verify) + response = requests.post( + url, headers=headers, json=payload, verify=verify, timeout=120 + ) if response.status_code != 200: return {"error": response.reason} @@ -346,7 +348,7 @@ def _selftoken_expired(): # Add Vault namespace to headers if Vault Enterprise enabled if namespace is not None: headers["X-Vault-Namespace"] = namespace - response = requests.get(url, headers=headers, verify=verify) + response = requests.get(url, headers=headers, verify=verify, timeout=120) if response.status_code != 200: return True return False diff --git a/salt/scripts.py b/salt/scripts.py index 176cab56366..3c74fb5a3ef 100644 --- a/salt/scripts.py +++ b/salt/scripts.py @@ -483,16 +483,14 @@ def salt_cloud(): """ The main function for salt-cloud """ - # Define 'salt' global so we may use it after ImportError. Otherwise, - # UnboundLocalError will be raised. - global salt # pylint: disable=W0602 - try: # Late-imports for CLI performance import salt.cloud import salt.cloud.cli except ImportError as e: # No salt cloud on Windows + import salt.defaults.exitcodes + log.error("Error importing salt cloud: %s", e) print("salt-cloud is not available in this system") sys.exit(salt.defaults.exitcodes.EX_UNAVAILABLE) diff --git a/salt/serializers/msgpack.py b/salt/serializers/msgpack.py index 93a3fddeb3a..afcf93c3a39 100644 --- a/salt/serializers/msgpack.py +++ b/salt/serializers/msgpack.py @@ -5,109 +5,42 @@ Implements MsgPack serializer. """ - -import copy import logging import salt.utils.msgpack from salt.serializers import DeserializationError, SerializationError log = logging.getLogger(__name__) -available = salt.utils.msgpack.HAS_MSGPACK -if not available: +__all__ = ["deserialize", "serialize", "available"] - def _fail(): - raise RuntimeError("msgpack is not available") - - def _serialize(obj, **options): - _fail() - - def _deserialize(stream_or_string, **options): - _fail() - -elif salt.utils.msgpack.version >= (1, 0, 0): - - def _serialize(obj, **options): - try: - return salt.utils.msgpack.dumps(obj, **options) - except Exception as error: # pylint: disable=broad-except - raise SerializationError(error) - - def _deserialize(stream_or_string, **options): - try: - options.setdefault("use_list", True) - options.setdefault("raw", False) - return salt.utils.msgpack.loads(stream_or_string, **options) - except Exception as error: # pylint: disable=broad-except - raise DeserializationError(error) - -elif salt.utils.msgpack.version >= (0, 2, 0): - - def _serialize(obj, **options): - try: - return salt.utils.msgpack.dumps(obj, **options) - except Exception as error: # pylint: disable=broad-except - raise SerializationError(error) - - def _deserialize(stream_or_string, **options): - try: - options.setdefault("use_list", True) - options.setdefault("encoding", "utf-8") - return salt.utils.msgpack.loads(stream_or_string, **options) - except Exception as error: # pylint: disable=broad-except - raise DeserializationError(error) - -else: # msgpack.version < 0.2.0 - - def _encoder(obj): - """ - Since OrderedDict is identified as a dictionary, we can't make use of - msgpack custom types, we will need to convert by hand. - - This means iterating through all elements of dictionaries, lists and - tuples. - """ - if isinstance(obj, dict): - data = [(key, _encoder(value)) for key, value in obj.items()] - return dict(data) - elif isinstance(obj, (list, tuple)): - return [_encoder(value) for value in obj] - return copy.copy(obj) - - def _decoder(obj): - return obj - - def _serialize(obj, **options): - try: - obj = _encoder(obj) - return salt.utils.msgpack.dumps(obj, **options) - except Exception as error: # pylint: disable=broad-except - raise SerializationError(error) - - def _deserialize(stream_or_string, **options): - options.setdefault("use_list", True) - try: - obj = salt.utils.msgpack.loads(stream_or_string) - return _decoder(obj) - except Exception as error: # pylint: disable=broad-except - raise DeserializationError(error) +available = True -serialize = _serialize -deserialize = _deserialize - -serialize.__doc__ = """ +def serialize(obj, **options): + """ Serialize Python data to MsgPack. :param obj: the data structure to serialize :param options: options given to lower msgpack module. -""" + """ + try: + return salt.utils.msgpack.dumps(obj, **options) + except Exception as error: # pylint: disable=broad-except + raise SerializationError(error) -deserialize.__doc__ = """ + +def deserialize(stream_or_string, **options): + """ Deserialize any string of stream like object into a Python data structure. :param stream_or_string: stream or string to deserialize. :param options: options given to lower msgpack module. -""" + """ + try: + options.setdefault("use_list", True) + options.setdefault("raw", False) + return salt.utils.msgpack.loads(stream_or_string, **options) + except Exception as error: # pylint: disable=broad-except + raise DeserializationError(error) diff --git a/salt/serializers/yaml.py b/salt/serializers/yaml.py index e8a5e85e4b5..dc1099db448 100644 --- a/salt/serializers/yaml.py +++ b/salt/serializers/yaml.py @@ -90,7 +90,7 @@ class EncryptedString(str): @staticmethod def yaml_dumper(dumper, data): - return dumper.represent_scalar(EncryptedString.yaml_tag, data.__str__()) + return dumper.represent_scalar(EncryptedString.yaml_tag, str(data)) class Loader(BaseLoader): # pylint: disable=W0232 diff --git a/salt/state.py b/salt/state.py index 2e00933c0a4..9cd31e6ab8b 100644 --- a/salt/state.py +++ b/salt/state.py @@ -126,11 +126,9 @@ STATE_INTERNAL_KEYWORDS = STATE_REQUISITE_KEYWORDS.union( ).union(STATE_RUNTIME_KEYWORDS) -def _odict_hashable(self): - return id(self) - - -OrderedDict.__hash__ = _odict_hashable +class HashableOrderedDict(OrderedDict): + def __hash__(self): + return id(self) def split_low_tag(tag): @@ -448,7 +446,7 @@ class Compiler: errors = [] if not isinstance(high, dict): errors.append("High data is not a dictionary and is invalid") - reqs = OrderedDict() + reqs = HashableOrderedDict() if not errors: for name, body in high.items(): try: @@ -1490,7 +1488,7 @@ class State: errors = [] if not isinstance(high, dict): errors.append("High data is not a dictionary and is invalid") - reqs = OrderedDict() + reqs = HashableOrderedDict() for name, body in high.items(): try: if name.startswith("__"): @@ -1570,7 +1568,7 @@ class State: # It is a list, verify that the members of the # list are all single key dicts. else: - reqs[name] = OrderedDict(state=state) + reqs[name] = HashableOrderedDict(state=state) for req in arg[argfirst]: if isinstance(req, str): req = {"id": req} @@ -1945,7 +1943,7 @@ class State: # Not a use requisite_in found = False if name not in extend: - extend[name] = OrderedDict() + extend[name] = HashableOrderedDict() if "." in _state: errors.append( "Invalid requisite in {}: {} for " @@ -2033,7 +2031,7 @@ class State: if key == "prereq_in": # Add prerequired to origin if id_ not in extend: - extend[id_] = OrderedDict() + extend[id_] = HashableOrderedDict() if state not in extend[id_]: extend[id_][state] = [] extend[id_][state].append( @@ -2046,7 +2044,7 @@ class State: ) for ext_id, _req_state in ext_ids: if ext_id not in extend: - extend[ext_id] = OrderedDict() + extend[ext_id] = HashableOrderedDict() if _req_state not in extend[ext_id]: extend[ext_id][_req_state] = [] extend[ext_id][_req_state].append( @@ -2064,7 +2062,7 @@ class State: continue ext_args = state_args(ext_id, _state, high) if ext_id not in extend: - extend[ext_id] = OrderedDict() + extend[ext_id] = HashableOrderedDict() if _req_state not in extend[ext_id]: extend[ext_id][_req_state] = [] ignore_args = req_in_all.union(ext_args) @@ -2093,7 +2091,7 @@ class State: continue loc_args = state_args(id_, state, high) if id_ not in extend: - extend[id_] = OrderedDict() + extend[id_] = HashableOrderedDict() if state not in extend[id_]: extend[id_][state] = [] ignore_args = req_in_all.union(loc_args) @@ -2113,7 +2111,7 @@ class State: continue found = False if name not in extend: - extend[name] = OrderedDict() + extend[name] = HashableOrderedDict() if _state not in extend[name]: extend[name][_state] = [] extend[name]["__env__"] = body["__env__"] @@ -2948,7 +2946,7 @@ class State: " with name [{}]".format(req_key, chunk["name"]) ) except TypeError: - # On Python 2, the above req_val, being an OrderedDict, will raise a KeyError, + # On Python 2, the above req_val, being an HashableOrderedDict, will raise a KeyError, # however on Python 3 it will raise a TypeError # This was found when running tests.unit.test_state.StateCompilerTestCase.test_render_error_on_invalid_requisite raise SaltRenderError( @@ -3070,11 +3068,13 @@ class State: self.opts.get("state_events", True) or fire_event ): if not self.opts.get("master_uri"): - ev_func = ( - lambda ret, tag, preload=None: salt.utils.event.get_master_event( + + def ev_func(ret, tag, preload=None): + with salt.utils.event.get_master_event( self.opts, self.opts["sock_dir"], listen=False - ).fire_event(ret, tag) - ) + ) as _evt: + _evt.fire_event(ret, tag) + else: ev_func = self.functions["event.fire_master"] @@ -3738,8 +3738,8 @@ class LazyAvailStates: def items(self): self._fill() ret = [] - for saltenv, states in self._avail.items(): - ret.append((saltenv, self.__getitem__(saltenv))) + for saltenv in self._avail: + ret.append((saltenv, self[saltenv])) return ret @@ -3756,7 +3756,7 @@ class BaseHighState: self.opts = self.__gen_opts(opts) self.iorder = 10000 self.avail = self.__gather_avail() - self.building_highstate = OrderedDict() + self.building_highstate = HashableOrderedDict() def __gather_avail(self): """ @@ -3990,10 +3990,10 @@ class BaseHighState: environment from the top file will be considered, and it too will be ignored if that environment was defined in the "base" top file. """ - top = DefaultOrderedDict(OrderedDict) + top = DefaultOrderedDict(HashableOrderedDict) # Check base env first as it is authoritative - base_tops = tops.pop("base", DefaultOrderedDict(OrderedDict)) + base_tops = tops.pop("base", DefaultOrderedDict(HashableOrderedDict)) for ctop in base_tops: for saltenv, targets in ctop.items(): if saltenv == "include": @@ -4046,7 +4046,7 @@ class BaseHighState: sections matching a given saltenv, which appear in a different saltenv's top file, will be ignored. """ - top = DefaultOrderedDict(OrderedDict) + top = DefaultOrderedDict(HashableOrderedDict) for cenv, ctops in tops.items(): if all([x == {} for x in ctops]): # No top file found in this env, check the default_top @@ -4127,7 +4127,7 @@ class BaseHighState: states.append(item) return match_type, states - top = DefaultOrderedDict(OrderedDict) + top = DefaultOrderedDict(HashableOrderedDict) for ctops in tops.values(): for ctop in ctops: for saltenv, targets in ctop.items(): @@ -4223,7 +4223,7 @@ class BaseHighState: Returns: {'saltenv': ['state1', 'state2', ...]} """ - matches = DefaultOrderedDict(OrderedDict) + matches = DefaultOrderedDict(HashableOrderedDict) # pylint: disable=cell-var-from-loop for saltenv, body in top.items(): if self.opts["saltenv"]: diff --git a/salt/states/archive.py b/salt/states/archive.py index f3405b6ea0a..8de42988764 100644 --- a/salt/states/archive.py +++ b/salt/states/archive.py @@ -119,7 +119,7 @@ def _update_checksum(path): log.warning( "Failed to update checksum for %s: %s", path, - exc.__str__(), + exc, exc_info=True, ) @@ -1066,7 +1066,7 @@ def extracted( ) except Exception as exc: # pylint: disable=broad-except msg = "Failed to cache {}: {}".format( - salt.utils.url.redact_http_basic_auth(source_match), exc.__str__() + salt.utils.url.redact_http_basic_auth(source_match), exc ) log.exception(msg) ret["comment"] = msg @@ -1208,7 +1208,7 @@ def extracted( else: ret["comment"] = ( "Failed to check for existence of if_missing path " - "({}): {}".format(if_missing, exc.__str__()) + "({}): {}".format(if_missing, exc) ) return ret else: @@ -1237,7 +1237,7 @@ def extracted( # that dir will raise an ENOTDIR OSError. So we # expect these and will only abort here if the # error code is something else. - ret["comment"] = exc.__str__() + ret["comment"] = str(exc) return ret if incorrect_type: @@ -1288,7 +1288,7 @@ def extracted( extraction_needed = True except OSError as exc: if exc.errno != errno.ENOENT: - errors.append(exc.__str__()) + errors.append(str(exc)) if errors: msg = ( "One or more paths existed by were the incorrect " @@ -1369,7 +1369,7 @@ def extracted( ret["changes"].setdefault("removed", []).append(full_path) except OSError as exc: if exc.errno != errno.ENOENT: - errors.append(exc.__str__()) + errors.append(str(exc)) if errors: msg = ( diff --git a/salt/states/boto3_route53.py b/salt/states/boto3_route53.py index 3edbc57a870..56f93256fbe 100644 --- a/salt/states/boto3_route53.py +++ b/salt/states/boto3_route53.py @@ -61,7 +61,6 @@ passed in as a dict, or as a string to pull from pillars or minion config: """ # keep lint from choking # pylint: disable=W0106 -# pylint: disable=E1320 import logging @@ -71,7 +70,7 @@ import salt.utils.data import salt.utils.dictupdate from salt.exceptions import SaltInvocationError -log = logging.getLogger(__name__) # pylint: disable=W1699 +log = logging.getLogger(__name__) def __virtual__(): diff --git a/salt/states/docker_container.py b/salt/states/docker_container.py index 17e11ed2ed7..da18c2c6d17 100644 --- a/salt/states/docker_container.py +++ b/salt/states/docker_container.py @@ -1686,7 +1686,7 @@ def running( if exc.info is not None: return _format_comments(ret, exc.info) else: - ret["comment"] = exc.__str__() + ret["comment"] = str(exc) return ret comments = [] @@ -1753,7 +1753,7 @@ def running( return _format_comments(ret, comments) except Exception as exc: # pylint: disable=broad-except ret["result"] = False - msg = exc.__str__() + msg = str(exc) if ( isinstance(exc, CommandExecutionError) and isinstance(exc.info, dict) @@ -1810,7 +1810,7 @@ def running( # of the network's subnet. An exception will be raised once # you try to start the container, however. ret["result"] = False - comments.append(exc.__str__()) + comments.append(str(exc)) return _format_comments(ret, comments) post_net_connect = __salt__["docker.inspect_container"](temp_container_name) @@ -1943,7 +1943,7 @@ def running( ) disconnected = True except CommandExecutionError as exc: - errors.append(exc.__str__()) + errors.append(str(exc)) if net_name in networks: try: @@ -1952,7 +1952,7 @@ def running( ) connected = True except CommandExecutionError as exc: - errors.append(exc.__str__()) + errors.append(str(exc)) if disconnected: # We succeeded in disconnecting but failed # to reconnect. This can happen if the @@ -2205,7 +2205,7 @@ def run( if exc.info is not None: return _format_comments(ret, exc.info) else: - ret["comment"] = exc.__str__() + ret["comment"] = str(exc) return ret if __opts__["test"]: diff --git a/salt/states/docker_image.py b/salt/states/docker_image.py index 10bca898c3e..6dbce1b7cac 100644 --- a/salt/states/docker_image.py +++ b/salt/states/docker_image.py @@ -247,7 +247,7 @@ def present( try: image_info = __salt__["docker.inspect_image"](full_image) except CommandExecutionError as exc: - msg = exc.__str__() + msg = str(exc) if "404" in msg: # Image not present image_info = None @@ -355,7 +355,7 @@ def present( try: __salt__["docker.inspect_image"](full_image) except CommandExecutionError as exc: - msg = exc.__str__() + msg = str(exc) if "404" not in msg: error = "Failed to inspect image '{}' after it was {}: {}".format( full_image, action, msg diff --git a/salt/states/docker_network.py b/salt/states/docker_network.py index 38e9027a1a2..94ca9696649 100644 --- a/salt/states/docker_network.py +++ b/salt/states/docker_network.py @@ -523,7 +523,7 @@ def present( try: network = __salt__["docker.inspect_network"](name) except CommandExecutionError as exc: - msg = exc.__str__() + msg = str(exc) if "404" in msg: # Network not present network = None @@ -578,7 +578,7 @@ def present( **__utils__["args.clean_kwargs"](**kwargs) ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = exc.__str__() + ret["comment"] = str(exc) return ret # Separate out the IPAM config options and build the IPAM config dict @@ -607,7 +607,7 @@ def present( *ipam_pools, **ipam_kwargs ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = exc.__str__() + ret["comment"] = str(exc) return ret # We'll turn this off if we decide below that creating the network is not @@ -662,7 +662,7 @@ def present( ) except CommandExecutionError as exc: ret["comment"] = "Failed to create temp network for comparison: {}".format( - exc.__str__() + str(exc) ) return ret else: @@ -674,9 +674,7 @@ def present( try: temp_net_info = __salt__["docker.inspect_network"](temp_net_name) except CommandExecutionError as exc: - ret["comment"] = "Failed to inspect temp network: {}".format( - exc.__str__() - ) + ret["comment"] = "Failed to inspect temp network: {}".format(str(exc)) return ret else: temp_net_info["EnableIPv6"] = bool(enable_ipv6) @@ -690,9 +688,8 @@ def present( existing_pool_count = len(network["IPAM"]["Config"]) desired_pool_count = len(temp_net_info["IPAM"]["Config"]) - is_default_pool = ( - lambda x: True if sorted(x) == ["Gateway", "Subnet"] else False - ) + def is_default_pool(x): + return True if sorted(x) == ["Gateway", "Subnet"] else False if ( desired_pool_count == 0 @@ -776,9 +773,7 @@ def present( __salt__["docker.remove_network"](temp_net_name) except CommandExecutionError as exc: ret.setdefault("warnings", []).append( - "Failed to remove temp network '{}': {}.".format( - temp_net_name, exc.__str__() - ) + "Failed to remove temp network '{}': {}.".format(temp_net_name, exc) ) if create_network: @@ -803,9 +798,7 @@ def present( **kwargs ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to create network '{}': {}".format( - name, exc.__str__() - ) + ret["comment"] = "Failed to create network '{}': {}".format(name, exc) return ret else: action = "recreated" if network is not None else "created" @@ -859,14 +852,14 @@ def present( ) except CommandExecutionError as exc: if not connect_kwargs: - errors.append(exc.__str__()) + errors.append(str(exc)) else: # We failed to reconnect with the container's old IP # configuration. Reconnect using automatic IP config. try: __salt__["docker.connect_container_to_network"](cid, name) except CommandExecutionError as exc: - errors.append(exc.__str__()) + errors.append(str(exc)) else: ret["changes"].setdefault( "reconnected" @@ -917,7 +910,7 @@ def absent(name): try: network = __salt__["docker.inspect_network"](name) except CommandExecutionError as exc: - msg = exc.__str__() + msg = str(exc) if "404" in msg: # Network not present network = None diff --git a/salt/states/environ.py b/salt/states/environ.py index fb495d1af44..c561fb899d4 100644 --- a/salt/states/environ.py +++ b/salt/states/environ.py @@ -131,6 +131,7 @@ def setenv( r" Manager\Environment" ) + # pylint: disable=cell-var-from-loop out = __utils__["reg.read_value"]( permanent_hive, permanent_key, _norm_key(key) ) diff --git a/salt/states/file.py b/salt/states/file.py index e36db6f2468..3c6b28ad163 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -567,6 +567,8 @@ def _gen_keep_files(name, require, walk_d=None): like directory or recurse has a clean. """ + walk_ret = set() + def _is_child(path, directory): """ Check whether ``path`` is child of ``directory`` @@ -1233,7 +1235,9 @@ def _shortcut_check( if os.path.isfile(name): with salt.utils.winapi.Com(): - shell = win32com.client.Dispatch("WScript.Shell") + shell = win32com.client.Dispatch( # pylint: disable=used-before-assignment + "WScript.Shell" + ) scut = shell.CreateShortcut(name) state_checks = [scut.TargetPath.lower() == target.lower()] if arguments is not None: @@ -9063,7 +9067,7 @@ def cached( name, saltenv=saltenv, source_hash=source_sum.get("hsum"), use_etag=use_etag ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = salt.utils.url.redact_http_basic_auth(exc.__str__()) + ret["comment"] = salt.utils.url.redact_http_basic_auth(str(exc)) return ret if not local_copy: @@ -9150,7 +9154,7 @@ def not_cached(name, saltenv="base"): try: os.remove(local_copy) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to delete {}: {}".format(local_copy, exc.__str__()) + ret["comment"] = "Failed to delete {}: {}".format(local_copy, exc) else: ret["result"] = True ret["changes"]["deleted"] = True diff --git a/salt/states/git.py b/salt/states/git.py index 0f3f977442e..32a597ec74d 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -144,7 +144,7 @@ def _strip_exc(exc): def _uptodate(ret, target, comments=None, local_changes=False): - ret["comment"] = "Repository {} is up-to-date".format(target) + ret["comment"] = f"Repository {target} is up-to-date" if local_changes: ret["comment"] += ( ", but with uncommitted changes. Set 'force_reset' to True to " @@ -177,7 +177,7 @@ def _fail(ret, msg, comments=None): def _already_cloned(ret, target, branch=None, comments=None): ret["result"] = True ret["comment"] = "Repository already exists at {}{}".format( - target, " and is checked out to branch '{}'".format(branch) if branch else "" + target, f" and is checked out to branch '{branch}'" if branch else "" ) if comments: ret["comment"] += "\n\nChanges {}made: {}".format( @@ -234,10 +234,8 @@ def _not_fast_forward( ret, "Repository would be updated {}{}, but {}. Set 'force_reset' to " "True{} to force this update{}.{}".format( - "from {} to {}".format(pre, post) - if local_changes and pre != post - else "to {}".format(post), - " (after checking out local branch '{}')".format(branch) + f"from {pre} to {post}" if local_changes and pre != post else f"to {post}", + f" (after checking out local branch '{branch}')" if _need_branch_change(branch, local_branch) else "", "this is not a fast-forward merge" @@ -276,7 +274,7 @@ def latest( refspec_branch="*", refspec_tag="*", output_encoding=None, - **kwargs + **kwargs, ): """ Make sure the repository is cloned to the given directory and is @@ -619,9 +617,7 @@ def latest( return _fail(ret, "'target' argument is required") if not rev: - return _fail( - ret, "'{}' is not a valid value for the 'rev' argument".format(rev) - ) + return _fail(ret, f"'{rev}' is not a valid value for the 'rev' argument") if force_reset not in (True, False, "remote-changes"): return _fail( @@ -635,7 +631,7 @@ def latest( if not isinstance(target, str): target = str(target) if not os.path.isabs(target): - return _fail(ret, "target '{}' is not an absolute path".format(target)) + return _fail(ret, f"target '{target}' is not an absolute path") if branch is not None and not isinstance(branch, str): branch = str(branch) if user is not None and not isinstance(user, str): @@ -656,13 +652,9 @@ def latest( ident_path = __salt__["cp.cache_file"](ident_path, __env__) except OSError as exc: log.exception("Failed to cache %s", ident_path) - return _fail( - ret, "identity '{}' does not exist.".format(ident_path) - ) + return _fail(ret, f"identity '{ident_path}' does not exist.") if not os.path.isabs(ident_path): - return _fail( - ret, "identity '{}' is not an absolute path".format(ident_path) - ) + return _fail(ret, f"identity '{ident_path}' is not an absolute path") if https_user is not None and not isinstance(https_user, str): https_user = str(https_user) if https_pass is not None and not isinstance(https_pass, str): @@ -681,7 +673,7 @@ def latest( if os.path.isfile(target): return _fail( ret, - "Target '{}' exists and is a regular file, cannot proceed".format(target), + f"Target '{target}' exists and is a regular file, cannot proceed", ) try: @@ -689,7 +681,7 @@ def latest( name, https_user, https_pass, https_only=True ) except ValueError as exc: - return _fail(ret, exc.__str__()) + return _fail(ret, str(exc)) redacted_fetch_url = salt.utils.url.redact_http_basic_auth(desired_fetch_url) @@ -731,7 +723,7 @@ def latest( output_encoding=output_encoding, ) except CommandExecutionError as exc: - return _fail(ret, "Failed to check remote refs: {}".format(_strip_exc(exc))) + return _fail(ret, f"Failed to check remote refs: {_strip_exc(exc)}") if "HEAD" in all_remote_refs: head_rev = all_remote_refs["HEAD"] @@ -825,7 +817,7 @@ def latest( # remote repo. return _fail( ret, - "No revision matching '{}' exists in the remote repository".format(rev), + f"No revision matching '{rev}' exists in the remote repository", ) git_ver = Version(__salt__["git.version"](versioninfo=False)) @@ -1067,6 +1059,7 @@ def latest( if (not revs_match and not update_head) and ( branch is None or branch == local_branch ): + # pylint: disable=used-before-assignment ret["comment"] = ( "{} is already present and local HEAD ({}) does not " "match, but update_head=False. HEAD has not been " @@ -1200,9 +1193,7 @@ def latest( output_encoding=output_encoding, ) if fetch_url is None: - comments.append( - "Remote '{}' set to {}".format(remote, redacted_fetch_url) - ) + comments.append(f"Remote '{remote}' set to {redacted_fetch_url}") ret["changes"]["new"] = name + " => " + remote else: comments.append( @@ -1217,7 +1208,7 @@ def latest( if __opts__["test"]: actions = [] if not has_remote_rev: - actions.append("Remote '{}' would be fetched".format(remote)) + actions.append(f"Remote '{remote}' would be fetched") if (not revs_match) and ( update_head or (branch is not None and branch != local_branch) ): @@ -1418,7 +1409,7 @@ def latest( else: if fetch_changes: comments.append( - "{} was fetched, resulting in updated refs".format(name) + f"{name} was fetched, resulting in updated refs" ) try: @@ -1518,7 +1509,7 @@ def latest( "as a starting point".format(branch, remote_loc) ) else: - comments.append("'{}' was checked out".format(checkout_rev)) + comments.append(f"'{checkout_rev}' was checked out") if fast_forward is False: __salt__["git.reset"]( @@ -1527,14 +1518,12 @@ def latest( user=user, password=password, output_encoding=output_encoding, - **lfs_opts + **lfs_opts, ) ret["changes"]["forced update"] = True if local_changes: comments.append("Uncommitted changes were discarded") - comments.append( - "Repository was hard-reset to {}".format(remote_loc) - ) + comments.append(f"Repository was hard-reset to {remote_loc}") elif ( fast_forward is True and local_changes and force_reset is not False ): @@ -1595,10 +1584,10 @@ def latest( user=user, password=password, output_encoding=output_encoding, - **lfs_opts + **lfs_opts, ) comments.append( - "Repository was fast-forwarded to {}".format(remote_loc) + f"Repository was fast-forwarded to {remote_loc}" ) else: return _fail( @@ -1615,11 +1604,9 @@ def latest( user=user, password=password, output_encoding=output_encoding, - **lfs_opts - ) - comments.append( - "Repository was reset to {} (fast-forward)".format(rev) + **lfs_opts, ) + comments.append(f"Repository was reset to {rev} (fast-forward)") # TODO: Figure out how to add submodule update info to # test=True return data, and changes dict. @@ -1639,7 +1626,7 @@ def latest( return _failed_submodule_update(ret, exc, comments) elif bare: if __opts__["test"]: - msg = "Bare repository at {} would be fetched".format(target) + msg = f"Bare repository at {target} would be fetched" if ret["changes"]: return _neutral_test(ret, msg) else: @@ -1724,9 +1711,7 @@ def latest( if exc.errno != errno.ENOENT: removal_errors[target_path] = exc if removal_errors: - err_strings = [ - " {}\n {}".format(k, v) for k, v in removal_errors.items() - ] + err_strings = [f" {k}\n {v}" for k, v in removal_errors.items()] return _fail( ret, "Unable to remove\n{}".format("\n".join(err_strings)), @@ -1747,9 +1732,7 @@ def latest( log.debug("Target %s is not found, 'git clone' is required", target) if __opts__["test"]: ret["changes"]["new"] = name + " => " + target - return _neutral_test( - ret, "Repository {} would be cloned to {}".format(name, target) - ) + return _neutral_test(ret, f"Repository {name} would be cloned to {target}") try: clone_opts = ["--mirror"] if mirror else ["--bare"] if bare else [] if remote != "origin": @@ -1774,7 +1757,7 @@ def latest( output_encoding=output_encoding, ) except CommandExecutionError as exc: - msg = "Clone failed: {}".format(_strip_exc(exc)) + msg = f"Clone failed: {_strip_exc(exc)}" return _fail(ret, msg, comments) ret["changes"]["new"] = name + " => " + target @@ -1799,9 +1782,7 @@ def latest( ) log.error(msg, name) # Disable check for string substitution - return _fail( - ret, msg % "Repository", comments - ) # pylint: disable=E1321 + return _fail(ret, msg % "Repository", comments) else: if remote_rev_type == "tag" and rev not in __salt__[ "git.list_tags" @@ -1813,7 +1794,7 @@ def latest( ): return _fail( ret, - "Revision '{}' does not exist in clone".format(rev), + f"Revision '{rev}' does not exist in clone", comments, ) @@ -1872,7 +1853,7 @@ def latest( password=password, output_encoding=output_encoding, ) - comments.append("Repository was reset to {}".format(remote_loc)) + comments.append(f"Repository was reset to {remote_loc}") try: upstream = __salt__["git.rev_parse"]( @@ -2110,7 +2091,7 @@ def present( else: salt.utils.files.rm_rf(name) except OSError as exc: - return _fail(ret, "Unable to remove {}: {}".format(name, exc)) + return _fail(ret, f"Unable to remove {name}: {exc}") else: ret["changes"]["forced init"] = True elif os.listdir(name): @@ -2142,9 +2123,9 @@ def present( actions = ["Initialized {}repository in {}".format("bare " if bare else "", name)] if template: - actions.append("Template directory set to {}".format(template)) + actions.append(f"Template directory set to {template}") if separate_git_dir: - actions.append("Gitdir set to {}".format(separate_git_dir)) + actions.append(f"Gitdir set to {separate_git_dir}") message = ". ".join(actions) if len(actions) > 1: message += "." @@ -2170,7 +2151,7 @@ def detached( https_user=None, https_pass=None, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2016.3.0 @@ -2261,14 +2242,10 @@ def detached( return _fail(ret, salt.utils.args.invalid_kwargs(kwargs, raise_exc=False)) if not rev: - return _fail( - ret, "'{}' is not a valid value for the 'rev' argument".format(rev) - ) + return _fail(ret, f"'{rev}' is not a valid value for the 'rev' argument") if not target: - return _fail( - ret, "'{}' is not a valid value for the 'target' argument".format(rev) - ) + return _fail(ret, f"'{rev}' is not a valid value for the 'target' argument") # Ensure that certain arguments are strings to ensure that comparisons work if not isinstance(rev, str): @@ -2277,7 +2254,7 @@ def detached( if not isinstance(target, str): target = str(target) if not os.path.isabs(target): - return _fail(ret, "Target '{}' is not an absolute path".format(target)) + return _fail(ret, f"Target '{target}' is not an absolute path") if user is not None and not isinstance(user, str): user = str(user) if remote is not None and not isinstance(remote, str): @@ -2294,13 +2271,9 @@ def detached( ident_path = __salt__["cp.cache_file"](ident_path) except OSError as exc: log.error("Failed to cache %s: %s", ident_path, exc) - return _fail( - ret, "Identity '{}' does not exist.".format(ident_path) - ) + return _fail(ret, f"Identity '{ident_path}' does not exist.") if not os.path.isabs(ident_path): - return _fail( - ret, "Identity '{}' is not an absolute path".format(ident_path) - ) + return _fail(ret, f"Identity '{ident_path}' is not an absolute path") if https_user is not None and not isinstance(https_user, str): https_user = str(https_user) if https_pass is not None and not isinstance(https_pass, str): @@ -2309,7 +2282,7 @@ def detached( if os.path.isfile(target): return _fail( ret, - "Target '{}' exists and is a regular file, cannot proceed".format(target), + f"Target '{target}' exists and is a regular file, cannot proceed", ) try: @@ -2317,7 +2290,7 @@ def detached( name, https_user, https_pass, https_only=True ) except ValueError as exc: - return _fail(ret, exc.__str__()) + return _fail(ret, str(exc)) redacted_fetch_url = salt.utils.url.redact_http_basic_auth(desired_fetch_url) @@ -2377,9 +2350,7 @@ def detached( current_fetch_url = remotes[remote]["fetch"] if __opts__["test"]: - return _neutral_test( - ret, "Remote {} would be set to {}".format(remote, name) - ) + return _neutral_test(ret, f"Remote {remote} would be set to {name}") __salt__["git.remote_set"]( target, @@ -2427,9 +2398,7 @@ def detached( if exc.errno != errno.ENOENT: removal_errors[target_path] = exc if removal_errors: - err_strings = [ - " {}\n {}".format(k, v) for k, v in removal_errors.items() - ] + err_strings = [f" {k}\n {v}" for k, v in removal_errors.items()] return _fail( ret, "Unable to remove\n{}".format("\n".join(err_strings)), @@ -2449,9 +2418,7 @@ def detached( log.debug("Target %s is not found, 'git clone' is required", target) if __opts__["test"]: - return _neutral_test( - ret, "Repository {} would be cloned to {}".format(name, target) - ) + return _neutral_test(ret, f"Repository {name} would be cloned to {target}") try: clone_opts = ["--no-checkout"] if remote != "origin": @@ -2469,7 +2436,7 @@ def detached( saltenv=__env__, output_encoding=output_encoding, ) - comments.append("{} cloned to {}".format(name, target)) + comments.append(f"{name} cloned to {target}") except Exception as exc: # pylint: disable=broad-except log.error("Unexpected exception in git.detached state", exc_info=True) @@ -2481,7 +2448,7 @@ def detached( # Repository exists and is ready for fetch/checkout refspecs = [ - "refs/heads/*:refs/remotes/{}/*".format(remote), + f"refs/heads/*:refs/remotes/{remote}/*", "+refs/tags/*:refs/tags/*", ] if hash_exists_locally or fetch_remote is False: @@ -2489,9 +2456,7 @@ def detached( else: # Fetch refs from remote if __opts__["test"]: - return _neutral_test( - ret, "Repository remote {} would be fetched".format(remote) - ) + return _neutral_test(ret, f"Repository remote {remote} would be fetched") try: fetch_changes = __salt__["git.fetch"]( target, @@ -2511,7 +2476,7 @@ def detached( else: if fetch_changes: comments.append( - "Remote {} was fetched, resulting in updated refs".format(remote) + f"Remote {remote} was fetched, resulting in updated refs" ) # get refs and checkout @@ -2522,7 +2487,7 @@ def detached( ): checkout_commit_id = rev else: - return _fail(ret, "Revision '{}' does not exist".format(rev)) + return _fail(ret, f"Revision '{rev}' does not exist") else: try: all_remote_refs = __salt__["git.remote_refs"]( @@ -2543,17 +2508,15 @@ def detached( elif "refs/tags/" + rev in all_remote_refs: checkout_commit_id = all_remote_refs["refs/tags/" + rev] else: - return _fail(ret, "Revision '{}' does not exist".format(rev)) + return _fail(ret, f"Revision '{rev}' does not exist") except CommandExecutionError as exc: - return _fail( - ret, "Failed to list refs for {}: {}".format(remote, _strip_exc(exc)) - ) + return _fail(ret, f"Failed to list refs for {remote}: {_strip_exc(exc)}") if hard_reset: if __opts__["test"]: return _neutral_test( - ret, "Hard reset to HEAD would be performed on {}".format(target) + ret, f"Hard reset to HEAD would be performed on {target}" ) __salt__["git.reset"]( target, @@ -2585,9 +2548,7 @@ def detached( password=password, output_encoding=output_encoding, ) - comments.append( - "Commit ID {} was checked out at {}".format(checkout_commit_id, target) - ) + comments.append(f"Commit ID {checkout_commit_id} was checked out at {target}") try: new_rev = __salt__["git.revision"]( @@ -2734,7 +2695,7 @@ def cloned( comment = "{} would be cloned to {}{}".format( name, target, - " with branch '{}'".format(branch) if branch is not None else "", + f" with branch '{branch}'" if branch is not None else "", ) return _neutral_test(ret, comment) clone_opts = ["--branch", branch] if branch is not None else None @@ -2751,14 +2712,14 @@ def cloned( output_encoding=output_encoding, ) except CommandExecutionError as exc: - msg = "Clone failed: {}".format(_strip_exc(exc)) + msg = f"Clone failed: {_strip_exc(exc)}" return _fail(ret, msg, comments) comments.append( "{} cloned to {}{}".format( name, target, - " with branch '{}'".format(branch) if branch is not None else "", + f" with branch '{branch}'" if branch is not None else "", ) ) _clone_changes(ret) @@ -2777,9 +2738,7 @@ def cloned( else: if __opts__["test"]: _branch_changes(ret, current_branch, branch) - return _neutral_test( - ret, "Branch would be changed to '{}'".format(branch) - ) + return _neutral_test(ret, f"Branch would be changed to '{branch}'") try: __salt__["git.rev_parse"]( target, @@ -2809,10 +2768,10 @@ def cloned( output_encoding=output_encoding, ) except CommandExecutionError as exc: - msg = "Failed to change branch to '{}': {}".format(branch, exc) + msg = f"Failed to change branch to '{branch}': {exc}" return _fail(ret, msg, comments) else: - comments.append("Branch changed to '{}'".format(branch)) + comments.append(f"Branch changed to '{branch}'") _branch_changes(ret, current_branch, branch) ret["comment"] = _format_comments(comments) ret["result"] = True @@ -2826,7 +2785,7 @@ def config_unset( user=None, password=None, output_encoding=None, - **kwargs + **kwargs, ): r""" .. versionadded:: 2015.8.0 @@ -2951,7 +2910,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) if not pre_matches: @@ -2984,7 +2943,7 @@ def config_unset( if __opts__["test"]: ret["changes"] = pre_matches return _neutral_test( - ret, "{} key(s) would have value(s) unset".format(len(pre_matches)) + ret, f"{len(pre_matches)} key(s) would have value(s) unset" ) if value_regex is None: @@ -3000,7 +2959,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) failed = [] @@ -3016,10 +2975,10 @@ def config_unset( user=user, password=password, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) except CommandExecutionError as exc: - msg = "Failed to unset '{}'".format(key_name) + msg = f"Failed to unset '{key_name}'" if value_regex is not None: msg += " using value_regex '{1}'" msg += ": " + _strip_exc(exc) @@ -3041,7 +3000,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) for key_name in pre: @@ -3062,7 +3021,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) if post_matches: @@ -3081,7 +3040,7 @@ def config_set( user=None, password=None, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2014.7.0 @@ -3219,7 +3178,7 @@ def config_set( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"all": True, "global": global_} + **{"all": True, "global": global_}, ) if desired == pre: @@ -3248,7 +3207,7 @@ def config_set( user=user, password=password, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) except CommandExecutionError as exc: return _fail( diff --git a/salt/states/gpg.py b/salt/states/gpg.py index 4329e6685a6..bde4b3beeda 100644 --- a/salt/states/gpg.py +++ b/salt/states/gpg.py @@ -76,7 +76,7 @@ def present( keys = [keys] for key in keys: - if key in current_keys.keys(): + if key in current_keys: if trust: if trust in _VALID_TRUST_VALUES: if current_keys[key]["trust"] != TRUST_MAP[trust]: diff --git a/salt/states/grafana_dashboard.py b/salt/states/grafana_dashboard.py index a23d0f084e3..0ba2b5f7622 100644 --- a/salt/states/grafana_dashboard.py +++ b/salt/states/grafana_dashboard.py @@ -459,6 +459,7 @@ def _update(dashboard, profile): request_url, headers={"Authorization": "Bearer {}".format(profile.get("grafana_token"))}, json=payload, + timeout=120, ) return response.json() diff --git a/salt/states/grains.py b/salt/states/grains.py index 9e6399dd57f..fadc518a254 100644 --- a/salt/states/grains.py +++ b/salt/states/grains.py @@ -296,7 +296,7 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): comments.append( "Value {1} in grain {0} is set to be deleted".format(name, val) ) - if "deleted" not in ret["changes"].keys(): + if "deleted" not in ret["changes"]: ret["changes"] = {"deleted": []} ret["changes"]["deleted"].append(val) elif val in grain: @@ -304,7 +304,7 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): comments.append( "Value {1} was deleted from grain {0}".format(name, val) ) - if "deleted" not in ret["changes"].keys(): + if "deleted" not in ret["changes"]: ret["changes"] = {"deleted": []} ret["changes"]["deleted"].append(val) ret["comment"] = "\n".join(comments) diff --git a/salt/states/ldap.py b/salt/states/ldap.py index 227182b828b..9b88c96918f 100644 --- a/salt/states/ldap.py +++ b/salt/states/ldap.py @@ -314,6 +314,7 @@ def managed(name, entries, connect_spec=None): o = old.get(dn, {}) n = new.get(dn, {}) + op = None try: # perform the operation if o: diff --git a/salt/states/netsnmp.py b/salt/states/netsnmp.py index 54dbf7887d3..a0f0d50b5f5 100644 --- a/salt/states/netsnmp.py +++ b/salt/states/netsnmp.py @@ -116,7 +116,7 @@ def _clear_community_details(community_details): _mode = community_details.get["mode"] = community_details.get("mode").lower() - if _mode in _COMMUNITY_MODE_MAP.keys(): + if _mode in _COMMUNITY_MODE_MAP: community_details["mode"] = _COMMUNITY_MODE_MAP.get(_mode) if community_details["mode"] not in ["ro", "rw"]: @@ -201,7 +201,7 @@ def _create_diff_action(diff, diff_key, key, value): DRY to build diff parts (added, removed, updated). """ - if diff_key not in diff.keys(): + if diff_key not in diff: diff[diff_key] = {} diff[diff_key][key] = value diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index 9430ea457ce..f8447ec350c 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -355,7 +355,10 @@ def _pep440_version_cmp(pkg1, pkg2, ignore_epoch=False): "The pkg_resources packages was not loaded. Please install setuptools." ) return None - normalize = lambda x: str(x).split("!", 1)[-1] if ignore_epoch else str(x) + + def normalize(x): + return str(x).split("!", 1)[-1] if ignore_epoch else str(x) + pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) @@ -368,7 +371,7 @@ def _pep440_version_cmp(pkg1, pkg2, ignore_epoch=False): return 1 except Exception as exc: # pylint: disable=broad-except logger.exception( - f'Comparison of package versions "{pkg1}" and "{pkg2}" failed: {exc}' + 'Comparison of package versions "%s" and "%s" failed: %s', pkg1, pkg2, exc ) return None @@ -735,11 +738,13 @@ def installed( # prepro = lambda pkg: pkg if type(pkg) == str else \ # ' '.join((pkg.items()[0][0], pkg.items()[0][1].replace(',', ';'))) # pkgs = ','.join([prepro(pkg) for pkg in pkgs]) - prepro = ( - lambda pkg: pkg - if isinstance(pkg, str) - else " ".join((pkg.items()[0][0], pkg.items()[0][1])) - ) + def prepro(pkg): + return ( + pkg + if isinstance(pkg, str) + else " ".join((pkg.items()[0][0], pkg.items()[0][1])) + ) + pkgs = [prepro(pkg) for pkg in pkgs] ret = {"name": ";".join(pkgs), "result": None, "comment": "", "changes": {}} @@ -862,7 +867,8 @@ def installed( # If we fail, then just send False, and we'll try again in the next function call except Exception as exc: # pylint: disable=broad-except logger.exception( - f"Pre-caching of PIP packages during states.pip.installed failed by exception from pip.list: {exc}" + "Pre-caching of PIP packages during states.pip.installed failed by exception from pip.list: %s", + exc, ) pip_list = False diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 08ddd83b82e..908d3711b07 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -3943,7 +3943,7 @@ def unheld(name, version=None, pkgs=None, all=False, **kwargs): (pkg_name, pkg_ver) = next(iter(pkg.items())) dpkgs.update({pkg_name: pkg_ver}) else: - dpkgs.update({pkg: None}) + dpkgs.update({pkg: None}) # pylint: disable=unhashable-member ret = {"name": name, "changes": {}, "result": True, "comment": ""} comments = [] diff --git a/salt/states/probes.py b/salt/states/probes.py index 2b5c566caf0..6adc6183f4e 100644 --- a/salt/states/probes.py +++ b/salt/states/probes.py @@ -80,7 +80,7 @@ def _expand_probes(probes, defaults): expected_probes = {} for probe_name, probe_test in probes.items(): - if probe_name not in expected_probes.keys(): + if probe_name not in expected_probes: expected_probes[probe_name] = {} probe_defaults = probe_test.pop("defaults", {}) for test_name, test_details in probe_test.items(): @@ -97,7 +97,7 @@ def _expand_probes(probes, defaults): expected_test_details.update( test_details ) # update with the actual config of the test - if test_name not in expected_probes[probe_name].keys(): + if test_name not in expected_probes[probe_name]: expected_probes[probe_name][test_name] = expected_test_details return expected_probes @@ -167,12 +167,12 @@ def _compare_probes(configured_probes, expected_probes): # new tests for common probes for test_name in new_tests_keys_set: - if probe_name not in new_probes.keys(): + if probe_name not in new_probes: new_probes[probe_name] = {} new_probes[probe_name].update({test_name: probe_tests.pop(test_name)}) # old tests for common probes for test_name in remove_tests_keys_set: - if probe_name not in remove_probes.keys(): + if probe_name not in remove_probes: remove_probes[probe_name] = {} remove_probes[probe_name].update( {test_name: configured_probe_tests.pop(test_name)} @@ -182,7 +182,7 @@ def _compare_probes(configured_probes, expected_probes): configured_test_params = configured_probe_tests.get(test_name, {}) # if test params are different, probe goes to update probes dict! if test_params != configured_test_params: - if probe_name not in update_probes.keys(): + if probe_name not in update_probes: update_probes[probe_name] = {} update_probes[probe_name].update({test_name: test_params}) diff --git a/salt/states/saltmod.py b/salt/states/saltmod.py index 386c5811ceb..d904da011d0 100644 --- a/salt/states/saltmod.py +++ b/salt/states/saltmod.py @@ -782,7 +782,9 @@ def runner(name, **kwargs): try: kwargs["__pub_user"] = __user__ log.debug( - f"added __pub_user to kwargs using dunder user '{__user__}', kwargs '{kwargs}'" + "added __pub_user to kwargs using dunder user '%s', kwargs '%s'", + __user__, + kwargs, ) except NameError: log.warning("unable to find user for fire args event due to missing __user__") diff --git a/salt/states/win_iis.py b/salt/states/win_iis.py index 773f7e7b3ad..4d1162680bd 100644 --- a/salt/states/win_iis.py +++ b/salt/states/win_iis.py @@ -502,7 +502,7 @@ def container_setting(name, container, settings=None): # map identity type from numeric to string for comparing if ( setting == "processModel.identityType" - and settings[setting] in identityType_map2string.keys() + and settings[setting] in identityType_map2string ): settings[setting] = identityType_map2string[settings[setting]] diff --git a/salt/utils/ansible.py b/salt/utils/ansible.py index b91c931dff6..e0f35146999 100644 --- a/salt/utils/ansible.py +++ b/salt/utils/ansible.py @@ -12,7 +12,7 @@ __virtualname__ = "ansible" log = logging.getLogger(__name__) -def __virtual__(): # pylint: disable=expected-2-blank-lines-found-0 +def __virtual__(): if salt.utils.path.which("ansible-inventory"): return __virtualname__ return (False, "Install `ansible` to use inventory") @@ -24,7 +24,7 @@ def targets(inventory="/etc/ansible/hosts", yaml=False, export=False): Default: /etc/salt/roster """ if not os.path.isfile(inventory): - raise CommandExecutionError("Inventory file not found: {}".format(inventory)) + raise CommandExecutionError(f"Inventory file not found: {inventory}") if not os.path.isabs(inventory): raise CommandExecutionError("Path to inventory file must be an absolute path") @@ -44,6 +44,4 @@ def targets(inventory="/etc/ansible/hosts", yaml=False, export=False): try: return salt.utils.json.loads(salt.utils.stringutils.to_str(inv)) except ValueError: - raise CommandExecutionError( - "Error processing the inventory: {}".format(inv) - ) + raise CommandExecutionError(f"Error processing the inventory: {inv}") diff --git a/salt/utils/args.py b/salt/utils/args.py index 536aea38166..dbc6e7e4081 100644 --- a/salt/utils/args.py +++ b/salt/utils/args.py @@ -49,7 +49,7 @@ def invalid_kwargs(invalid_kwargs, raise_exc=True): """ if invalid_kwargs: if isinstance(invalid_kwargs, dict): - new_invalid = ["{}={}".format(x, y) for x, y in invalid_kwargs.items()] + new_invalid = [f"{x}={y}" for x, y in invalid_kwargs.items()] invalid_kwargs = new_invalid msg = "The following keyword arguments are not valid: {}".format( ", ".join(invalid_kwargs) @@ -236,7 +236,7 @@ def get_function_argspec(func, is_class_method=None): the argspec unless ``is_class_method`` is True. """ if not callable(func): - raise TypeError("{} is not a callable".format(func)) + raise TypeError(f"{func} is not a callable") while hasattr(func, "__wrapped__"): func = func.__wrapped__ @@ -244,7 +244,7 @@ def get_function_argspec(func, is_class_method=None): try: sig = inspect.signature(func) except TypeError: - raise TypeError("Cannot inspect argument list for '{}'".format(func)) + raise TypeError(f"Cannot inspect argument list for '{func}'") # Build a namedtuple which looks like the result of a Python 2 argspec _ArgSpec = namedtuple("ArgSpec", "args varargs keywords defaults") @@ -345,7 +345,10 @@ def split_input(val, mapper=None): Take an input value and split it into a list, returning the resulting list """ if mapper is None: - mapper = lambda x: x + + def mapper(x): + return x + if isinstance(val, list): return list(map(mapper, val)) try: @@ -466,18 +469,18 @@ def format_call( # In case this is being called for a state module "full", # Not a state module, build the name - "{}.{}".format(fun.__module__, fun.__name__), + f"{fun.__module__}.{fun.__name__}", ), ) else: msg = "{} and '{}' are invalid keyword arguments for '{}'".format( - ", ".join(["'{}'".format(e) for e in extra][:-1]), + ", ".join([f"'{e}'" for e in extra][:-1]), list(extra.keys())[-1], ret.get( # In case this is being called for a state module "full", # Not a state module, build the name - "{}.{}".format(fun.__module__, fun.__name__), + f"{fun.__module__}.{fun.__name__}", ), ) @@ -529,7 +532,8 @@ def parse_function(s): key = None word = [] elif token in "]})": - if not brackets or token != {"[": "]", "{": "}", "(": ")"}[brackets.pop()]: + _brackets = {"[": "]", "{": "}", "(": ")"} + if not brackets or token != _brackets[brackets.pop()]: break word.append(token) elif token == "=" and not brackets: diff --git a/salt/utils/atomicfile.py b/salt/utils/atomicfile.py index 574797b77e3..59f7e273715 100644 --- a/salt/utils/atomicfile.py +++ b/salt/utils/atomicfile.py @@ -14,8 +14,12 @@ import salt.utils.win_dacl CAN_RENAME_OPEN_FILE = False if os.name == "nt": # pragma: no cover - _rename = lambda src, dst: False # pylint: disable=C0103 - _rename_atomic = lambda src, dst: False # pylint: disable=C0103 + + def _rename(src, dst): + return False + + def _rename_atomic(src, dst): + return False try: import ctypes diff --git a/salt/utils/aws.py b/salt/utils/aws.py index fead9cf7ac6..1231661d970 100644 --- a/salt/utils/aws.py +++ b/salt/utils/aws.py @@ -240,7 +240,14 @@ def assumed_creds(prov_dict, role_arn, location=None): requesturl="https://sts.amazonaws.com/", ) headers["Accept"] = "application/json" - result = requests.request("GET", requesturl, headers=headers, data="", verify=True) + result = requests.request( + "GET", + requesturl, + headers=headers, + data="", + verify=True, + timeout=AWS_METADATA_TIMEOUT, + ) if result.status_code >= 400: log.info("AssumeRole response: %s", result.content) @@ -511,7 +518,10 @@ def query( log.trace("AWS Request Parameters: %s", params_with_headers) try: result = requests.get( - requesturl, headers=headers, params=params_with_headers + requesturl, + headers=headers, + params=params_with_headers, + timeout=AWS_METADATA_TIMEOUT, ) log.debug("AWS Response Status Code: %s", result.status_code) log.trace("AWS Response Text: %s", result.text) diff --git a/salt/utils/cache.py b/salt/utils/cache.py index 88e7fa24000..02c89b28bba 100644 --- a/salt/utils/cache.py +++ b/salt/utils/cache.py @@ -99,7 +99,7 @@ class CacheDisk(CacheDict): return if time.time() - self._key_cache_time[key] > self._ttl: del self._key_cache_time[key] - self._dict.__delitem__(key) + del self._dict[key] def __contains__(self, key): self._enforce_ttl_key(key) @@ -365,7 +365,7 @@ def verify_cache_version(cache_path): file.seek(0) data = "\n".join(file.readlines()) if data != salt.version.__version__: - log.warning(f"Cache version mismatch clearing: {repr(cache_path)}") + log.warning("Cache version mismatch clearing: %s", repr(cache_path)) file.truncate(0) file.write(salt.version.__version__) for item in os.listdir(cache_path): diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py index 3e026a0bb57..5a1660cfd6a 100644 --- a/salt/utils/cloud.py +++ b/salt/utils/cloud.py @@ -2120,9 +2120,7 @@ def _exec_ssh_cmd(cmd, error_msg=None, allow_failure=False, **kwargs): return proc.exitstatus except salt.utils.vt.TerminalException as err: trace = traceback.format_exc() - log.error( - error_msg.format(cmd, err, trace) - ) # pylint: disable=str-format-in-logging + log.error(error_msg.format(cmd, err, trace)) finally: proc.close(terminate=True, kill=True) # Signal an error @@ -2969,7 +2967,7 @@ def update_bootstrap(config, url=None): "Python requests library to be installed" ) } - req = requests.get(url) + req = requests.get(url, timeout=120) if req.status_code != 200: return { "error": ( diff --git a/salt/utils/compat.py b/salt/utils/compat.py index 0579a7f5e62..d9313e1b408 100644 --- a/salt/utils/compat.py +++ b/salt/utils/compat.py @@ -38,12 +38,10 @@ def deepcopy_bound(name): """ def _deepcopy_method(x, memo): - # pylint: disable=incompatible-py3-code return type(x)(x.im_func, copy.deepcopy(x.im_self, memo), x.im_class) - # pylint: enable=incompatible-py3-code + pre_dispatch = copy._deepcopy_dispatch try: - pre_dispatch = copy._deepcopy_dispatch copy._deepcopy_dispatch[types.MethodType] = _deepcopy_method ret = copy.deepcopy(name) finally: diff --git a/salt/utils/configparser.py b/salt/utils/configparser.py index 6a3b1e689ea..10e3c889ef0 100644 --- a/salt/utils/configparser.py +++ b/salt/utils/configparser.py @@ -3,18 +3,12 @@ Custom configparser classes """ import re +from collections import OrderedDict from configparser import * # pylint: disable=no-name-in-module,wildcard-import,unused-wildcard-import import salt.utils.stringutils -try: - from collections import OrderedDict as _default_dict -except ImportError: - # fallback for setup.py which hasn't yet built _collections - _default_dict = dict - -# pylint: disable=string-substitution-usage-error class GitConfigParser(RawConfigParser): """ Custom ConfigParser which reads and writes git config files. @@ -47,7 +41,7 @@ class GitConfigParser(RawConfigParser): def __init__( self, defaults=None, - dict_type=_default_dict, + dict_type=OrderedDict, allow_no_value=True, ): """ @@ -269,7 +263,7 @@ class GitConfigParser(RawConfigParser): fp_.write(convert("[%s]\n" % self.DEFAULTSECT)) for (key, value) in self._defaults.items(): value = salt.utils.stringutils.to_unicode(value).replace("\n", "\n\t") - fp_.write(convert("{} = {}\n".format(key, value))) + fp_.write(convert(f"{key} = {value}\n")) for section in self._sections: fp_.write(convert("[%s]\n" % section)) for (key, value) in self._sections[section].items(): diff --git a/salt/utils/data.py b/salt/utils/data.py index 0235551462f..40c79e3418a 100644 --- a/salt/utils/data.py +++ b/salt/utils/data.py @@ -1049,9 +1049,14 @@ def repack_dictlist(data, strict=False, recurse=False, key_cb=None, val_cb=None) return {} if key_cb is None: - key_cb = lambda x: x + + def key_cb(x): + return x + if val_cb is None: - val_cb = lambda x, y: y + + def val_cb(x, y): + return y valid_non_dict = ((str,), (int,), float) if isinstance(data, list): diff --git a/salt/utils/dns.py b/salt/utils/dns.py index dc0d680c773..271fd79553e 100644 --- a/salt/utils/dns.py +++ b/salt/utils/dns.py @@ -123,7 +123,7 @@ def _to_port(port): assert 1 <= port <= 65535 return port except (ValueError, AssertionError): - raise ValueError("Invalid port {}".format(port)) + raise ValueError(f"Invalid port {port}") def _tree(domain, tld=False): @@ -276,24 +276,24 @@ def _lookup_dig(name, rdtype, timeout=None, servers=None, secure=None): :param servers: [] of servers to use :return: [] of records or False if error """ - cmd = "dig {} -t {} ".format(DIG_OPTIONS, rdtype) + cmd = f"dig {DIG_OPTIONS} -t {rdtype} " if servers: - cmd += "".join(["@{} ".format(srv) for srv in servers]) + cmd += "".join([f"@{srv} " for srv in servers]) if timeout is not None: if servers: timeout = int(float(timeout) / len(servers)) else: timeout = int(timeout) - cmd += "+time={} ".format(timeout) + cmd += f"+time={timeout} " if secure: cmd += "+dnssec +adflag " cmd = __salt__["cmd.run_all"]( - "{} {}".format(cmd, name), python_shell=False, output_loglevel="quiet" + f"{cmd} {name}", python_shell=False, output_loglevel="quiet" ) if "ignoring invalid type" in cmd["stderr"]: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") elif cmd["retcode"] != 0: log.warning( "dig returned (%s): %s", @@ -333,9 +333,9 @@ def _lookup_drill(name, rdtype, timeout=None, servers=None, secure=None): cmd = "drill " if secure: cmd += "-D -o ad " - cmd += "{} {} ".format(rdtype, name) + cmd += f"{rdtype} {name} " if servers: - cmd += "".join(["@{} ".format(srv) for srv in servers]) + cmd += "".join([f"@{srv} " for srv in servers]) cmd = __salt__["cmd.run_all"]( cmd, timeout=timeout, python_shell=False, output_loglevel="quiet" ) @@ -364,7 +364,7 @@ def _lookup_drill(name, rdtype, timeout=None, servers=None, secure=None): validated = True continue elif l_type != rdtype: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") res.append(_data_clean(l_rec)) @@ -385,10 +385,12 @@ def _lookup_gai(name, rdtype, timeout=None): :param timeout: ignored :return: [] of addresses or False if error """ - try: - sock_t = {"A": socket.AF_INET, "AAAA": socket.AF_INET6}[rdtype] - except KeyError: - raise ValueError("Invalid DNS type {} for gai lookup".format(rdtype)) + if rdtype == "A": + sock_t = socket.AF_INET + elif rdtype == "AAAA": + sock_t = socket.AF_INET6 + else: + raise ValueError(f"Invalid DNS type {rdtype} for gai lookup") if timeout: log.info("Ignoring timeout on gai resolver; fix resolv.conf to do that") @@ -412,18 +414,18 @@ def _lookup_host(name, rdtype, timeout=None, server=None): :param timeout: server response wait :return: [] of records or False if error """ - cmd = "host -t {} ".format(rdtype) + cmd = f"host -t {rdtype} " if timeout: - cmd += "-W {} ".format(int(timeout)) + cmd += f"-W {int(timeout)} " cmd += name if server is not None: - cmd += " {}".format(server) + cmd += f" {server}" cmd = __salt__["cmd.run_all"](cmd, python_shell=False, output_loglevel="quiet") if "invalid type" in cmd["stderr"]: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") elif cmd["retcode"] != 0: log.warning("host returned (%s): %s", cmd["retcode"], cmd["stderr"]) return False @@ -470,7 +472,7 @@ def _lookup_dnspython(name, rdtype, timeout=None, servers=None, secure=None): ] return res except dns.rdatatype.UnknownRdatatype: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") except ( dns.resolver.NXDOMAIN, dns.resolver.YXDOMAIN, @@ -489,12 +491,12 @@ def _lookup_nslookup(name, rdtype, timeout=None, server=None): :param server: server to query :return: [] of records or False if error """ - cmd = "nslookup -query={} {}".format(rdtype, name) + cmd = f"nslookup -query={rdtype} {name}" if timeout is not None: - cmd += " -timeout={}".format(int(timeout)) + cmd += f" -timeout={int(timeout)}" if server is not None: - cmd += " {}".format(server) + cmd += f" {server}" cmd = __salt__["cmd.run_all"](cmd, python_shell=False, output_loglevel="quiet") @@ -511,7 +513,7 @@ def _lookup_nslookup(name, rdtype, timeout=None, server=None): try: line = next(lookup_res) if "unknown query type" in line: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") while True: if name in line: @@ -581,7 +583,6 @@ def lookup( rdtype = rdtype.upper() - # pylint: disable=bad-whitespace,multiple-spaces-before-keyword query_methods = ( ("gai", _lookup_gai, not any((rdtype not in ("A", "AAAA"), servers, secure))), ("dnspython", _lookup_dnspython, HAS_DNSPYTHON), @@ -590,7 +591,6 @@ def lookup( ("host", _lookup_host, HAS_HOST and not secure), ("nslookup", _lookup_nslookup, HAS_NSLOOKUP and not secure), ) - # pylint: enable=bad-whitespace,multiple-spaces-before-keyword try: if method == "auto": @@ -895,7 +895,7 @@ def spf_rec(rdata): # It's a modifier mod, val = mech_spec.split("=", 1) if mod in mods: - raise KeyError("Modifier {} can only appear once".format(mod)) + raise KeyError(f"Modifier {mod} can only appear once") mods.add(mod) continue @@ -959,7 +959,7 @@ def srv_name(svc, proto="tcp", domain=None): if domain: domain = "." + domain - return "_{}._{}{}".format(svc, proto, domain) + return f"_{svc}._{proto}{domain}" def srv_rec(rdatas): @@ -1133,7 +1133,7 @@ def services(services_file="/etc/services"): if not curr_desc: pp_res["desc"] = comment elif comment != curr_desc: - pp_res["desc"] = "{}, {}".format(curr_desc, comment) + pp_res["desc"] = f"{curr_desc}, {comment}" res[name] = svc_res for svc, data in res.items(): @@ -1210,7 +1210,7 @@ def parse_resolv(src="/etc/resolv.conf"): ip_addr ) ip_net = ipaddress.ip_network( - "{}{}".format(ip_addr, mask), strict=False + f"{ip_addr}{mask}", strict=False ) if ip_net.version == 6: # TODO diff --git a/salt/utils/dockermod/__init__.py b/salt/utils/dockermod/__init__.py index f703ee7b1e6..00b012b8992 100644 --- a/salt/utils/dockermod/__init__.py +++ b/salt/utils/dockermod/__init__.py @@ -25,11 +25,11 @@ except ImportError: # functions so that we can get argspecs for the container config, host config, # and networking config (see the get_client_args() function). try: - import docker.types + import docker.types # pylint: disable=no-name-in-module except ImportError: pass try: - import docker.utils + import docker.utils # pylint: disable=no-name-in-module except ImportError: pass @@ -241,7 +241,7 @@ def translate_input( pass except Exception as exc: # pylint: disable=broad-except - error_message = exc.__str__() + error_message = str(exc) log.error("Error translating input: '%s'", error_message, exc_info=True) else: error_message = None diff --git a/salt/utils/dockermod/translate/container.py b/salt/utils/dockermod/translate/container.py index b155308bf74..3bc37101f76 100644 --- a/salt/utils/dockermod/translate/container.py +++ b/salt/utils/dockermod/translate/container.py @@ -378,9 +378,7 @@ def port_bindings(val, **kwargs): try: start, end = helpers.get_port_range(container_port) except ValueError as exc: - # Using __str__() to avoid deprecation warning for using - # the message attribute of the ValueError. - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) bind_vals = [ (_format_port(port_num, proto), None) for port_num in range(start, end + 1) @@ -403,9 +401,7 @@ def port_bindings(val, **kwargs): cport_start, cport_end = helpers.get_port_range(container_port) hport_start, hport_end = helpers.get_port_range(bind_parts[0]) except ValueError as exc: - # Using __str__() to avoid deprecation warning for - # using the message attribute of the ValueError. - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) if (hport_end - hport_start) != (cport_end - cport_start): # Port range is mismatched raise SaltInvocationError( @@ -427,9 +423,7 @@ def port_bindings(val, **kwargs): try: cport_start, cport_end = helpers.get_port_range(container_port) except ValueError as exc: - # Using __str__() to avoid deprecation warning for - # using the message attribute of the ValueError. - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) cport_list = list(range(cport_start, cport_end + 1)) if host_port == "": hport_list = [None] * len(cport_list) @@ -437,9 +431,7 @@ def port_bindings(val, **kwargs): try: hport_start, hport_end = helpers.get_port_range(host_port) except ValueError as exc: - # Using __str__() to avoid deprecation warning for - # using the message attribute of the ValueError. - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) hport_list = list(range(hport_start, hport_end + 1)) if (hport_end - hport_start) != (cport_end - cport_start): @@ -526,9 +518,7 @@ def ports(val, **kwargs): # pylint: disable=unused-argument try: range_start, range_end = helpers.get_port_range(item) except ValueError as exc: - # Using __str__() to avoid deprecation warning for using - # the "message" attribute of the ValueError. - raise SaltInvocationError(exc.__str__()) + raise SaltInvocationError(str(exc)) new_ports.update( [helpers.get_port_def(x, proto) for x in range(range_start, range_end + 1)] ) diff --git a/salt/utils/dockermod/translate/helpers.py b/salt/utils/dockermod/translate/helpers.py index f172d080cdc..5d81f89c99e 100644 --- a/salt/utils/dockermod/translate/helpers.py +++ b/salt/utils/dockermod/translate/helpers.py @@ -72,7 +72,7 @@ def get_port_range(port_def): if range_start > range_end: raise ValueError("start > end") except (TypeError, ValueError) as exc: - if exc.__str__() == "start > end": + if str(exc) == "start > end": msg = ( "Start of port range ({}) cannot be greater than end of " "port range ({})".format(range_start, range_end) diff --git a/salt/utils/files.py b/salt/utils/files.py index 3c57cce7132..8071a55d3a4 100644 --- a/salt/utils/files.py +++ b/salt/utils/files.py @@ -322,8 +322,8 @@ def set_umask(mask): # Don't attempt on Windows, or if no mask was passed yield else: + orig_mask = os.umask(mask) # pylint: disable=blacklisted-function try: - orig_mask = os.umask(mask) # pylint: disable=blacklisted-function yield finally: os.umask(orig_mask) # pylint: disable=blacklisted-function @@ -390,7 +390,9 @@ def fopen(*args, **kwargs): ) kwargs["buffering"] = io.DEFAULT_BUFFER_SIZE - f_handle = open(*args, **kwargs) # pylint: disable=resource-leakage + f_handle = open( # pylint: disable=resource-leakage,unspecified-encoding + *args, **kwargs + ) if is_fcntl_available(): # modify the file descriptor on systems with fcntl @@ -649,7 +651,10 @@ def is_text(fp_, blocksize=512): If more than 30% of the chars in the block are non-text, or there are NUL ('\x00') bytes in the block, assume this is a binary file. """ - int2byte = lambda x: bytes((x,)) + + def int2byte(x): + return bytes((x,)) + text_characters = b"".join(int2byte(i) for i in range(32, 127)) + b"\n\r\t\f\b" try: block = fp_.read(blocksize) diff --git a/salt/utils/fsutils.py b/salt/utils/fsutils.py index 7b0eb084f64..96d0cd16bb8 100644 --- a/salt/utils/fsutils.py +++ b/salt/utils/fsutils.py @@ -57,7 +57,10 @@ def _blkid_output(out, fs_type=None): """ Parse blkid output. """ - flt = lambda data: [el for el in data if el.strip()] + + def flt(data): + return [el for el in data if el.strip()] + data = {} for dev_meta in flt(out.split("\n\n")): dev = {} @@ -84,7 +87,10 @@ def _blkid(fs_type=None): :param fs_type: Filter only devices that are formatted by that file system. """ - flt = lambda data: [el for el in data if el.strip()] + + def flt(data): + return [el for el in data if el.strip()] + data = dict() for dev_meta in flt( os.popen("blkid -o full").read().split(os.linesep) diff --git a/salt/utils/functools.py b/salt/utils/functools.py index f1360527723..f4d4cbdb3de 100644 --- a/salt/utils/functools.py +++ b/salt/utils/functools.py @@ -119,9 +119,7 @@ def call_function(salt_function, *args, **kwargs): # function_kwargs is initialized to a dictionary of keyword arguments the function to be run accepts function_kwargs = dict( zip( - argspec.args[ - -len(argspec.defaults or []) : - ], # pylint: disable=incompatible-py3-code + argspec.args[-len(argspec.defaults or []) :], argspec.defaults or [], ) ) diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index a197921f6ef..934794bfab7 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -118,7 +118,7 @@ try: if PYGIT2_VERSION <= Version("0.26.3"): try: import pygit2.ffi - import pygit2.remote + import pygit2.remote # pylint: disable=no-name-in-module except ImportError: # If we couldn't import these, then we're using an old enough # version where ffi isn't in use and this workaround would be @@ -244,12 +244,16 @@ class GitProvider: ): self.opts = opts self.role = role + + def _val_cb(x, y): + return str(y) + self.global_saltenv = salt.utils.data.repack_dictlist( self.opts.get("{}_saltenv".format(self.role), []), strict=True, recurse=True, key_cb=str, - val_cb=lambda x, y: str(y), + val_cb=_val_cb, ) self.conf = copy.deepcopy(per_remote_defaults) # Remove the 'salt://' from the beginning of any globally-defined @@ -473,7 +477,9 @@ class GitProvider: try: self._cache_basename = self.get_checkout_target() except AttributeError: - log.critical(f"__env__ cant generate basename: {self.role} {self.id}") + log.critical( + "__env__ cant generate basename: %s %s", self.role, self.id + ) failhard(self.role) self._cache_full_basename = salt.utils.path.join( self._cache_basehash, self._cache_basename @@ -574,9 +580,9 @@ class GitProvider: """ def _getconf(self, tgt_env="base"): - strip_sep = ( - lambda x: x.rstrip(os.sep) if name in ("root", "mountpoint") else x - ) + def strip_sep(x): + return x.rstrip(os.sep) if name in ("root", "mountpoint") else x + if self.role != "gitfs": return strip_sep(getattr(self, "_" + name)) # Get saltenv-specific configuration @@ -1203,12 +1209,14 @@ class GitProvider: def fetch_request_check(self): fetch_request = salt.utils.path.join(self._salt_working_dir, "fetch_request") if os.path.isfile(fetch_request): - log.debug(f"Fetch request: {self._salt_working_dir}") + log.debug("Fetch request: %s", self._salt_working_dir) try: os.remove(fetch_request) except OSError as exc: log.error( - f"Failed to remove Fetch request: {self._salt_working_dir} {exc}", + "Failed to remove Fetch request: %s %s", + self._salt_working_dir, + exc, exc_info=True, ) self.fetch() @@ -1426,12 +1434,20 @@ class GitPython(GitProvider): tree = tree / self.root(tgt_env) except KeyError: return ret - relpath = lambda path: os.path.relpath(path, self.root(tgt_env)) + + def relpath(path): + return os.path.relpath(path, self.root(tgt_env)) + else: - relpath = lambda path: path - add_mountpoint = lambda path: salt.utils.path.join( - self.mountpoint(tgt_env), path, use_posixpath=True - ) + + def relpath(path): + return path + + def add_mountpoint(path): + return salt.utils.path.join( + self.mountpoint(tgt_env), path, use_posixpath=True + ) + for blob in tree.traverse(): if isinstance(blob, git.Tree): ret.add(add_mountpoint(relpath(blob.path))) @@ -1498,12 +1514,20 @@ class GitPython(GitProvider): tree = tree / self.root(tgt_env) except KeyError: return files, symlinks - relpath = lambda path: os.path.relpath(path, self.root(tgt_env)) + + def relpath(path): + return os.path.relpath(path, self.root(tgt_env)) + else: - relpath = lambda path: path - add_mountpoint = lambda path: salt.utils.path.join( - self.mountpoint(tgt_env), path, use_posixpath=True - ) + + def relpath(path): + return path + + def add_mountpoint(path): + return salt.utils.path.join( + self.mountpoint(tgt_env), path, use_posixpath=True + ) + for file_blob in tree.traverse(): if not isinstance(file_blob, git.Blob): continue @@ -1945,15 +1969,24 @@ class Pygit2(GitProvider): return ret if not isinstance(tree, pygit2.Tree): return ret - relpath = lambda path: os.path.relpath(path, self.root(tgt_env)) + + def relpath(path): + return os.path.relpath(path, self.root(tgt_env)) + else: - relpath = lambda path: path + + def relpath(path): + return path + blobs = [] if tree: _traverse(tree, blobs, self.root(tgt_env)) - add_mountpoint = lambda path: salt.utils.path.join( - self.mountpoint(tgt_env), path, use_posixpath=True - ) + + def add_mountpoint(path): + return salt.utils.path.join( + self.mountpoint(tgt_env), path, use_posixpath=True + ) + for blob in blobs: ret.add(add_mountpoint(relpath(blob))) if self.mountpoint(tgt_env): @@ -2086,15 +2119,24 @@ class Pygit2(GitProvider): return files, symlinks if not isinstance(tree, pygit2.Tree): return files, symlinks - relpath = lambda path: os.path.relpath(path, self.root(tgt_env)) + + def relpath(path): + return os.path.relpath(path, self.root(tgt_env)) + else: - relpath = lambda path: path + + def relpath(path): + return path + blobs = {} if tree: _traverse(tree, blobs, self.root(tgt_env)) - add_mountpoint = lambda path: salt.utils.path.join( - self.mountpoint(tgt_env), path, use_posixpath=True - ) + + def add_mountpoint(path): + return salt.utils.path.join( + self.mountpoint(tgt_env), path, use_posixpath=True + ) + for repo_path in blobs.get("files", []): files.add(add_mountpoint(relpath(repo_path))) for repo_path, link_tgt in blobs.get("symlinks", {}).items(): @@ -2181,9 +2223,12 @@ class Pygit2(GitProvider): if PYGIT2_VERSION >= Version("0.23.2"): self.remotecallbacks = pygit2.RemoteCallbacks(credentials=self.credentials) if not self.ssl_verify: - # Override the certificate_check function with a lambda that + # Override the certificate_check function with another that # just returns True, thus skipping the cert check. - self.remotecallbacks.certificate_check = lambda *args, **kwargs: True + def _certificate_check(*args, **kwargs): + return True + + self.remotecallbacks.certificate_check = _certificate_check else: self.remotecallbacks = None if not self.ssl_verify: @@ -2663,11 +2708,13 @@ class GitBase: pass except OSError as exc: # pylint: disable=broad-except log.error( - f"Failed to make fetch request: {fetch_path} {exc}", + "Failed to make fetch request: %s %s", + fetch_path, + exc, exc_info=True, ) else: - log.error(f"Failed to make fetch request: {fetch_path}") + log.error("Failed to make fetch request: %s", fetch_path) if repo.fetch(): # We can't just use the return value from repo.fetch() # because the data could still have changed if old @@ -3437,7 +3484,7 @@ class GitPillar(GitBase): "Failed to remove existing git_pillar " "mountpoint link %s: %s", lcachelink, - exc.__str__(), + exc, ) wipe_linkdir = False create_link = True @@ -3457,7 +3504,7 @@ class GitPillar(GitBase): log.error( "Failed to os.makedirs() linkdir parent %s: %s", ldirname, - exc.__str__(), + exc, ) return False @@ -3475,7 +3522,7 @@ class GitPillar(GitBase): "Failed to create symlink to %s at path %s: %s", lcachedest, lcachelink, - exc.__str__(), + exc, ) return False except GitLockError: diff --git a/salt/utils/iam.py b/salt/utils/iam.py index dea1e950145..45017df57ef 100644 --- a/salt/utils/iam.py +++ b/salt/utils/iam.py @@ -24,6 +24,7 @@ def _retry_get_url(url, num_retries=10, timeout=5): Based heavily on boto.utils.retry_url """ for i in range(0, num_retries): + exc = None try: result = requests.get(url, timeout=timeout, proxies={"http": ""}) if hasattr(result, "text"): diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py index 898c8d3fc0d..f802156ddb8 100644 --- a/salt/utils/jinja.py +++ b/salt/utils/jinja.py @@ -239,9 +239,7 @@ class PrintableDict(OrderedDict): for key, value in self.items(): if isinstance(value, str): # keeps quotes around strings - # pylint: disable=repr-flag-used-in-string output.append(f"{key!r}: {value!r}") - # pylint: enable=repr-flag-used-in-string else: # let default output output.append(f"{key!r}: {value!s}") @@ -252,9 +250,7 @@ class PrintableDict(OrderedDict): for key, value in self.items(): # Raw string formatter required here because this is a repr # function. - # pylint: disable=repr-flag-used-in-string output.append(f"{key!r}: {value!r}") - # pylint: enable=repr-flag-used-in-string return "{" + ", ".join(output) + "}" diff --git a/salt/utils/msazure.py b/salt/utils/msazure.py index 28f8f33cc2f..de4419caacd 100644 --- a/salt/utils/msazure.py +++ b/salt/utils/msazure.py @@ -108,16 +108,14 @@ def put_blob(storage_conn=None, **kwargs): "x_ms_lease_id": kwargs.get("lease_id", None), } if "blob_path" in kwargs: - data = storage_conn.put_block_blob_from_path( + return storage_conn.put_block_blob_from_path( file_path=kwargs["blob_path"], **blob_kwargs ) elif "blob_content" in kwargs: - data = storage_conn.put_block_blob_from_bytes( + return storage_conn.put_block_blob_from_bytes( blob=kwargs["blob_content"], **blob_kwargs ) - return data - def get_blob(storage_conn=None, **kwargs): """ @@ -157,15 +155,13 @@ def get_blob(storage_conn=None, **kwargs): } if "local_path" in kwargs: - data = storage_conn.get_blob_to_path( + return storage_conn.get_blob_to_path( file_path=kwargs["local_path"], open_mode=kwargs.get("open_mode", "wb"), **blob_kwargs ) elif "return_content" in kwargs: - data = storage_conn.get_blob_to_bytes(**blob_kwargs) - - return data + return storage_conn.get_blob_to_bytes(**blob_kwargs) def object_to_dict(obj): diff --git a/salt/utils/nacl.py b/salt/utils/nacl.py index b04904c2e14..918eb942ca6 100644 --- a/salt/utils/nacl.py +++ b/salt/utils/nacl.py @@ -15,9 +15,9 @@ import salt.utils.win_functions REQ_ERROR = None try: - import nacl.public - import nacl.secret -except (ImportError, OSError) as e: + import nacl.public # pylint: disable=no-name-in-module + import nacl.secret # pylint: disable=no-name-in-module +except ImportError: REQ_ERROR = ( "PyNaCl import error, perhaps missing python PyNaCl package or should update." ) diff --git a/salt/utils/napalm.py b/salt/utils/napalm.py index 082be2167c9..d78422a7111 100644 --- a/salt/utils/napalm.py +++ b/salt/utils/napalm.py @@ -44,8 +44,11 @@ try: # try importing ConnectionClosedException # from napalm-base # this exception has been introduced only in version 0.24.0 + # pylint: disable=unused-import,no-name-in-module from napalm.base.exceptions import ConnectionClosedException + # pylint: enable=unused-import,no-name-in-module + HAS_CONN_CLOSED_EXC_CLASS = True except ImportError: HAS_CONN_CLOSED_EXC_CLASS = False @@ -93,10 +96,8 @@ def virtual(opts, virtualname, filename): else: return ( False, - '"{vname}"" {filename} cannot be loaded: ' - "NAPALM is not installed: ``pip install napalm``".format( - vname=virtualname, filename="({filename})".format(filename=filename) - ), + f'"{virtualname}" ({filename}) cannot be loaded: ' + "NAPALM is not installed: ``pip install napalm``", ) diff --git a/salt/utils/nb_popen.py b/salt/utils/nb_popen.py index 12cdc39e1b0..7624d609713 100644 --- a/salt/utils/nb_popen.py +++ b/salt/utils/nb_popen.py @@ -24,14 +24,12 @@ import time mswindows = sys.platform == "win32" -try: +if mswindows: import msvcrt import pywintypes from win32file import ReadFile, WriteFile from win32pipe import PeekNamedPipe -except ImportError: - import fcntl log = logging.getLogger(__name__) @@ -180,6 +178,8 @@ class NonBlockingPopen(subprocess.Popen): if conn is None: return None + import fcntl + flags = fcntl.fcntl(conn, fcntl.F_GETFL) if not conn.closed: fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK) diff --git a/salt/utils/network.py b/salt/utils/network.py index 9566f433444..13eaa4835ca 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -1722,9 +1722,7 @@ def _netlink_tool_remote_on(port, which_end): valid = False tcp_end = "dst" if which_end == "remote_port" else "src" try: - data = subprocess.check_output( - ["ss", "-ant", tcp_end, ":{}".format(port)] - ) # pylint: disable=minimum-python-version + data = subprocess.check_output(["ss", "-ant", tcp_end, f":{port}"]) except subprocess.CalledProcessError: log.error("Failed ss") raise @@ -1770,9 +1768,7 @@ def _sunos_remotes_on(port, which_end): # pragma: no cover """ remotes = set() try: - data = subprocess.check_output( - ["netstat", "-f", "inet", "-n"] - ) # pylint: disable=minimum-python-version + data = subprocess.check_output(["netstat", "-f", "inet", "-n"]) except subprocess.CalledProcessError: log.error("Failed netstat") raise @@ -1817,8 +1813,8 @@ def _freebsd_remotes_on(port, which_end): # pragma: no cover remotes = set() try: - cmd = salt.utils.args.shlex_split("sockstat -4 -c -p {}".format(port)) - data = subprocess.check_output(cmd) # pylint: disable=minimum-python-version + cmd = salt.utils.args.shlex_split(f"sockstat -4 -c -p {port}") + data = subprocess.check_output(cmd) except subprocess.CalledProcessError as ex: log.error('Failed "sockstat" with returncode = %s', ex.returncode) raise @@ -1879,8 +1875,8 @@ def _netbsd_remotes_on(port, which_end): # pragma: no cover remotes = set() try: - cmd = salt.utils.args.shlex_split("sockstat -4 -c -n -p {}".format(port)) - data = subprocess.check_output(cmd) # pylint: disable=minimum-python-version + cmd = salt.utils.args.shlex_split(f"sockstat -4 -c -n -p {port}") + data = subprocess.check_output(cmd) except subprocess.CalledProcessError as ex: log.error('Failed "sockstat" with returncode = %s', ex.returncode) raise @@ -1932,9 +1928,7 @@ def _openbsd_remotes_on(port, which_end): # pragma: no cover """ remotes = set() try: - data = subprocess.check_output( - ["netstat", "-nf", "inet"] - ) # pylint: disable=minimum-python-version + data = subprocess.check_output(["netstat", "-nf", "inet"]) except subprocess.CalledProcessError as exc: log.error('Failed "netstat" with returncode = %s', exc.returncode) raise @@ -1973,9 +1967,7 @@ def _windows_remotes_on(port, which_end): """ remotes = set() try: - data = subprocess.check_output( - ["netstat", "-n"] - ) # pylint: disable=minimum-python-version + data = subprocess.check_output(["netstat", "-n"]) except subprocess.CalledProcessError: log.error("Failed netstat") raise @@ -2024,7 +2016,7 @@ def _linux_remotes_on(port, which_end): "-iTCP:{:d}".format(port), "-n", "-P", - ] # pylint: disable=minimum-python-version + ] ) except subprocess.CalledProcessError as ex: if ex.returncode == 1: @@ -2089,9 +2081,7 @@ def _aix_remotes_on(port, which_end): # pragma: no cover """ remotes = set() try: - data = subprocess.check_output( - ["netstat", "-f", "inet", "-n"] - ) # pylint: disable=minimum-python-version + data = subprocess.check_output(["netstat", "-f", "inet", "-n"]) except subprocess.CalledProcessError: log.error("Failed netstat") raise @@ -2332,9 +2322,8 @@ def filter_by_networks(values, networks): {{ grains['ipv4'] | filter_by_networks(networks) }} """ - _filter = lambda ips, networks: [ - ip for ip in ips for net in networks if ipaddress.ip_address(ip) in net - ] + def _filter(ips, networks): + return [ip for ip in ips for net in networks if ipaddress.ip_address(ip) in net] if networks is not None: networks = [ipaddress.ip_network(network) for network in networks] diff --git a/salt/utils/odict.py b/salt/utils/odict.py index 76f313fe5be..bf9dd06e448 100644 --- a/salt/utils/odict.py +++ b/salt/utils/odict.py @@ -5,311 +5,16 @@ salt.utils.odict ~~~~~~~~~~~~~~~~ - This is a compatibility/"importability" layer for an ordered dictionary. - Tries to import from the standard library if python >= 2.7, then from the - ``ordereddict`` package available from PyPi, and, as a last resort, - provides an ``OrderedDict`` implementation based on:: - - http://code.activestate.com/recipes/576669/ - - It also implements a DefaultOrderedDict Class that serves as a + Implements a DefaultOrderedDict Class that serves as a combination of ``OrderedDict`` and ``defaultdict`` It's source was submitted here:: http://stackoverflow.com/questions/6190331/ """ - -# pragma: no cover # essentially using Python's OrderDict - - +import copy +from collections import OrderedDict from collections.abc import Callable -try: - # pylint: disable=E0611,minimum-python-version - import collections - - class OrderedDict(collections.OrderedDict): - __hash__ = None - -except (ImportError, AttributeError): - try: - import ordereddict - - class OrderedDict(ordereddict.OrderedDict): # pylint: disable=W0232 - __hash_ = None - - except ImportError: - # {{{ http://code.activestate.com/recipes/576693/ (r9) - # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. - # Passes Python2.7's test suite and incorporates all the latest updates. - - try: - from _thread import get_ident as _get_ident - except ImportError: - from _dummy_thread import get_ident as _get_ident - - # try: - # from _abcoll import KeysView, ValuesView, ItemsView - # except ImportError: - # pass - - class OrderedDict(dict): - "Dictionary that remembers insertion order" - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # The internal self.__map dictionary maps keys to links in a doubly linked list. - # The circular doubly linked list starts and ends with a sentinel element. - # The sentinel element never gets deleted (this simplifies the algorithm). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - __hash_ = None - - def __init__(self, *args, **kwds): # pylint: disable=E1003 - """Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - """ - super().__init__() - if len(args) > 1: - raise TypeError( - "expected at most 1 arguments, got {}".format(len(args)) - ) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - "od.__setitem__(i, y) <==> od[i]=y" - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - "od.__delitem__(y) <==> del od[y]" - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - "od.__iter__() <==> iter(od)" - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - "od.__reversed__() <==> reversed(od)" - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - "od.clear() -> None. Remove all items from od." - try: - for node in self.__map.values(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - """od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - """ - if not self: - raise KeyError("dictionary is empty") - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - "od.keys() -> list of keys in od" - return list(self) - - def values(self): - "od.values() -> list of values in od" - return [self[key] for key in self] - - def items(self): - "od.items() -> list of (key, value) pairs in od" - return [(key, self[key]) for key in self] - - def iterkeys(self): - "od.iterkeys() -> an iterator over the keys in od" - return iter(self) - - def itervalues(self): - "od.itervalues -> an iterator over the values in od" - for k in self: - yield self[k] - - def iteritems(self): - "od.iteritems -> an iterator over the (key, value) items in od" - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): # pylint: disable=E0211 - """od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - """ - if len(args) > 2: - raise TypeError( - "update() takes at most 2 positional " - "arguments ({} given)".format(len(args)) - ) - elif not args: - raise TypeError("update() takes at least 1 argument (0 given)") - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, "keys"): - for key in other: - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = ( - update # let subclasses override update without breaking __init__ - ) - - __marker = object() - - def pop(self, key, default=__marker): - """od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - - """ - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - "od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od" - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running={}): # pylint: disable=W0102 - "od.__repr__() <==> repr(od)" - call_key = id(self), _get_ident() - if call_key in _repr_running: - return "..." - _repr_running[call_key] = 1 - try: - if not self: - return "{}()".format(self.__class__.__name__) - return "{}('{}')".format( - self.__class__.__name__, list(self.items()) - ) - finally: - del _repr_running[call_key] - - def __reduce__(self): - "Return state information for pickling" - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - "od.copy() -> a shallow copy of od" - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - """ - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - """od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - """ - if isinstance(other, OrderedDict): - return len(self) == len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - -# # -- the following methods are only used in Python 2.7 -- -# -# def viewkeys(self): -# "od.viewkeys() -> a set-like object providing a view on od's keys" -# return KeysView(self) -# -# def viewvalues(self): -# "od.viewvalues() -> an object providing a view on od's values" -# return ValuesView(self) -# -# def viewitems(self): -# "od.viewitems() -> a set-like object providing a view on od's items" -# return ItemsView(self) -# ## end of http://code.activestate.com/recipes/576693/ }}} - class DefaultOrderedDict(OrderedDict): """ @@ -342,7 +47,7 @@ class DefaultOrderedDict(OrderedDict): return type(self), args, None, None, self.items() def copy(self): - return self.__copy__() + return copy.copy(self) def __copy__(self): return type(self)(self.default_factory, self) diff --git a/salt/utils/openstack/nova.py b/salt/utils/openstack/nova.py index 4c3855edb31..386b585c861 100644 --- a/salt/utils/openstack/nova.py +++ b/salt/utils/openstack/nova.py @@ -197,7 +197,7 @@ class NovaServer: self.extra["password"] = password def __str__(self): - return self.__dict__ + return str(self.__dict__) def get_entry(dict_, key, value, raise_error=True): diff --git a/salt/utils/oset.py b/salt/utils/oset.py index d0bd6536e82..85cc0931328 100644 --- a/salt/utils/oset.py +++ b/salt/utils/oset.py @@ -113,7 +113,7 @@ class OrderedSet(MutableSet): def __contains__(self, key): return key in self.map - def add(self, key): # pylint: disable=arguments-differ + def add(self, key): # pylint: disable=arguments-differ,arguments-renamed """ Add `key` as an item to this OrderedSet, then return its index. @@ -168,7 +168,7 @@ class OrderedSet(MutableSet): del self.map[elem] return elem - def discard(self, key): # pylint: disable=arguments-differ + def discard(self, key): # pylint: disable=arguments-differ,arguments-renamed """ Remove an element. Do not raise an exception if absent. diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py index 036530820d8..385e69f6a15 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py @@ -13,7 +13,7 @@ import copy import getpass import logging -import optparse +import optparse # pylint: disable=deprecated-module import os import signal import sys diff --git a/salt/utils/path.py b/salt/utils/path.py index ed4b4a0f35a..f6aa7d5dad7 100644 --- a/salt/utils/path.py +++ b/salt/utils/path.py @@ -182,9 +182,11 @@ def which(exe=None): # The specified extension isn't valid, so we just assume it's part of the # filename and proceed to walk the pathext list else: - is_executable = lambda path, membership=res: is_executable_common( - path - ) and has_executable_ext(path, membership) + + def is_executable(path, membership=res): + return is_executable_common(path) and has_executable_ext( + path, membership + ) else: # in posix, there's no such thing as file extensions..only zuul diff --git a/salt/utils/pkg/__init__.py b/salt/utils/pkg/__init__.py index 9a11e492a04..3dfa9884bb4 100644 --- a/salt/utils/pkg/__init__.py +++ b/salt/utils/pkg/__init__.py @@ -33,7 +33,7 @@ def clear_rtag(opts): if exc.errno != errno.ENOENT: # Using __str__() here to get the fully-formatted error message # (error number, error message, path) - log.warning("Encountered error removing rtag: %s", exc.__str__()) + log.warning("Encountered error removing rtag: %s", exc) def write_rtag(opts): @@ -46,7 +46,7 @@ def write_rtag(opts): with salt.utils.files.fopen(rtag_file, "w+"): pass except OSError as exc: - log.warning("Encountered error writing rtag: %s", exc.__str__()) + log.warning("Encountered error writing rtag: %s", exc) def check_refresh(opts, refresh=None): diff --git a/salt/utils/pkg/win.py b/salt/utils/pkg/win.py index c34fa2c26b3..f988f7a99af 100644 --- a/salt/utils/pkg/win.py +++ b/salt/utils/pkg/win.py @@ -825,7 +825,7 @@ class WinSoftware: Returns: str: Package Id """ - return self.__next__() + return next(self) def get(self, pkg_id, default_value=None): """ @@ -848,7 +848,7 @@ class WinSoftware: return 1 if Version(ver1) > Version(ver2) else -1 @staticmethod - def __latest_to_oldest_version(ver1, ver2): + def __latest_to_oldest_version(ver1, ver2): # pylint: disable=unused-private-member """ Used for sorting version numbers, latest to oldest """ diff --git a/salt/utils/preseed.py b/salt/utils/preseed.py index 749b24dace4..3b1f6105950 100644 --- a/salt/utils/preseed.py +++ b/salt/utils/preseed.py @@ -25,7 +25,7 @@ def mksls(src, dst=None): continue comps = shlex.split(line) - if comps[0] not in ps_opts.keys(): + if comps[0] not in ps_opts: ps_opts[comps[0]] = {} cmds = comps[1].split("/") diff --git a/salt/utils/process.py b/salt/utils/process.py index 6c393706acd..765a2fac8d9 100644 --- a/salt/utils/process.py +++ b/salt/utils/process.py @@ -590,7 +590,7 @@ class ProcessManager: # with the tree option will not be able to find them. return - for pid in self._process_map.copy().keys(): + for pid in self._process_map.copy(): try: os.kill(pid, signal_) except OSError as exc: @@ -942,7 +942,7 @@ class Process(multiprocessing.Process): "logging_config": self.__logging_config__, } - def __decorate_run(self, run_func): + def __decorate_run(self, run_func): # pylint: disable=unused-private-member @functools.wraps(run_func) def wrapped_run_func(): # Static after fork method, always needs to happen first diff --git a/salt/utils/psutil_compat.py b/salt/utils/psutil_compat.py index e6684e5ca46..ef5d9768c10 100644 --- a/salt/utils/psutil_compat.py +++ b/salt/utils/psutil_compat.py @@ -9,104 +9,4 @@ Should be removed once support for psutil <2.0 is dropped. (eg RHEL 6) Built off of http://grodola.blogspot.com/2014/01/psutil-20-porting.html """ - -# No exception handling, as we want ImportError if psutil doesn't exist -import psutil # pylint: disable=3rd-party-module-not-gated - -if psutil.version_info >= (2, 0): - from psutil import * # pylint: disable=wildcard-import,unused-wildcard-import,3rd-party-module-not-gated -else: - # Import hack to work around bugs in old psutil's - # Psuedo "from psutil import *" - _globals = globals() - for attr in psutil.__all__: - _temp = __import__("psutil", globals(), locals(), [attr], 0) - try: - _globals[attr] = getattr(_temp, attr) - except AttributeError: - pass - - # Import functions not in __all__ - # pylint: disable=unused-import,3rd-party-module-not-gated - from psutil import disk_partitions, disk_usage - - # pylint: enable=unused-import,3rd-party-module-not-gated - # Alias new module functions - def boot_time(): - return psutil.BOOT_TIME - - def cpu_count(): - return psutil.NUM_CPUS - - # Alias renamed module functions - pids = psutil.get_pid_list - try: - users = psutil.get_users - except AttributeError: - users = lambda: (_ for _ in ()).throw( - NotImplementedError("Your psutil version is too old") - ) - - # Deprecated in 1.0.1, but not mentioned in blog post - if psutil.version_info < (1, 0, 1): - net_io_counters = psutil.network_io_counters() - - class Process(psutil.Process): # pylint: disable=no-init - # Reimplement overloaded getters/setters - # pylint: disable=arguments-differ - def cpu_affinity(self, *args, **kwargs): - if args or kwargs: - return self.set_cpu_affinity(*args, **kwargs) - else: - return self.get_cpu_affinity() - - def ionice(self, *args, **kwargs): - if args or kwargs: - return self.set_ionice(*args, **kwargs) - else: - return self.get_ionice() - - def nice(self, *args, **kwargs): - if args or kwargs: - return self.set_nice(*args, **kwargs) - else: - return self.get_nice() - - def rlimit(self, *args, **kwargs): - """ - set_rlimit and get_limit were not introduced until psutil v1.1.0 - """ - if psutil.version_info >= (1, 1, 0): - if args or kwargs: - return self.set_rlimit(*args, **kwargs) - else: - return self.get_rlimit() - else: - pass - - # pylint: enable=arguments-differ - - # Alias renamed Process functions - _PROCESS_FUNCTION_MAP = { - "children": "get_children", - "connections": "get_connections", - "cpu_percent": "get_cpu_percent", - "cpu_times": "get_cpu_times", - "io_counters": "get_io_counters", - "memory_info": "get_memory_info", - "memory_info_ex": "get_ext_memory_info", - "memory_maps": "get_memory_maps", - "memory_percent": "get_memory_percent", - "num_ctx_switches": "get_num_ctx_switches", - "num_fds": "get_num_fds", - "num_threads": "get_num_threads", - "open_files": "get_open_files", - "threads": "get_threads", - "cwd": "getcwd", - } - - for new, old in _PROCESS_FUNCTION_MAP.items(): - try: - setattr(Process, new, psutil.Process.__dict__[old]) - except KeyError: - pass +from psutil import * # pylint: disable=wildcard-import,unused-wildcard-import,3rd-party-module-not-gated diff --git a/salt/utils/reactor.py b/salt/utils/reactor.py index 19420a51cf0..3ddb363117c 100644 --- a/salt/utils/reactor.py +++ b/salt/utils/reactor.py @@ -312,6 +312,7 @@ class ReactWrap: Populate the client cache with an instance of the specified type """ reaction_type = low["state"] + # pylint: disable=unsupported-membership-test,unsupported-assignment-operation if reaction_type not in self.client_cache: log.debug("Reactor is populating %s client cache", reaction_type) if reaction_type in ("runner", "wheel"): @@ -333,6 +334,7 @@ class ReactWrap: self.client_cache[reaction_type] = self.reaction_class[reaction_type]( self.opts["conf_file"] ) + # pylint: enable=unsupported-membership-test,unsupported-assignment-operation def run(self, low): """ diff --git a/salt/utils/ssdp.py b/salt/utils/ssdp.py index 497accb522e..4c7e588284d 100644 --- a/salt/utils/ssdp.py +++ b/salt/utils/ssdp.py @@ -157,7 +157,10 @@ class SSDPFactory(SSDPBase): :return: """ tries = 0 - slp_time = lambda: 0.5 / random.randint(10, 30) + + def slp_time(): + return 0.5 / random.randint(10, 30) + slp = slp_time() while tries < attempts: try: diff --git a/salt/utils/templates.py b/salt/utils/templates.py index 554c76d51e1..872d92686af 100644 --- a/salt/utils/templates.py +++ b/salt/utils/templates.py @@ -2,6 +2,8 @@ Template render systems """ import codecs +import importlib.machinery +import importlib.util import logging import os import sys @@ -32,17 +34,6 @@ from salt.utils.decorators.jinja import JinjaFilter, JinjaGlobal, JinjaTest from salt.utils.odict import OrderedDict from salt.utils.versions import Version -if sys.version_info[:2] >= (3, 5): - import importlib.machinery # pylint: disable=no-name-in-module,import-error - import importlib.util # pylint: disable=no-name-in-module,import-error - - USE_IMPORTLIB = True -else: - import imp - - USE_IMPORTLIB = False - - log = logging.getLogger(__name__) @@ -676,18 +667,13 @@ def py(sfn, string=False, **kwargs): # pylint: disable=C0103 base_fname = os.path.basename(sfn) name = base_fname.split(".")[0] - if USE_IMPORTLIB: - # pylint: disable=no-member - loader = importlib.machinery.SourceFileLoader(name, sfn) - spec = importlib.util.spec_from_file_location(name, sfn, loader=loader) - if spec is None: - raise ImportError() - mod = importlib.util.module_from_spec(spec) - spec.loader.exec_module(mod) - # pylint: enable=no-member - sys.modules[name] = mod - else: - mod = imp.load_source(name, sfn) + loader = importlib.machinery.SourceFileLoader(name, sfn) + spec = importlib.util.spec_from_file_location(name, sfn, loader=loader) + if spec is None: + raise ImportError() + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + sys.modules[name] = mod # File templates need these set as __var__ if "__env__" not in kwargs and "saltenv" in kwargs: diff --git a/salt/utils/vault.py b/salt/utils/vault.py index 07fcf3929b1..9e31adf5066 100644 --- a/salt/utils/vault.py +++ b/salt/utils/vault.py @@ -136,10 +136,16 @@ def get_vault_connection(): if namespace is not None: headers = {"X-Vault-Namespace": namespace} response = requests.post( - url, headers=headers, json=payload, verify=verify + url, + headers=headers, + json=payload, + verify=verify, + timeout=120, ) else: - response = requests.post(url, json=payload, verify=verify) + response = requests.post( + url, json=payload, verify=verify, timeout=120 + ) if response.status_code != 200: errmsg = "An error occurred while getting a token from approle" raise salt.exceptions.CommandExecutionError(errmsg) @@ -153,7 +159,9 @@ def get_vault_connection(): headers = {"X-Vault-Token": __opts__["vault"]["auth"]["token"]} if namespace is not None: headers["X-Vault-Namespace"] = namespace - response = requests.post(url, headers=headers, verify=verify) + response = requests.post( + url, headers=headers, verify=verify, timeout=120 + ) if response.status_code != 200: errmsg = "An error occured while unwrapping vault token" raise salt.exceptions.CommandExecutionError(errmsg) @@ -334,19 +342,21 @@ def make_request( token = connection["token"] if not token else token vault_url = connection["url"] if not vault_url else vault_url namespace = namespace or connection.get("namespace") - if "verify" in args: - args["verify"] = args["verify"] - else: + if "verify" not in args: try: args["verify"] = __opts__.get("vault").get("verify", None) except (TypeError, AttributeError): # Don't worry about setting verify if it doesn't exist pass + if "timeout" not in args: + args["timeout"] = 120 url = "{}/{}".format(vault_url, resource) headers = {"X-Vault-Token": str(token), "Content-Type": "application/json"} if namespace is not None: headers["X-Vault-Namespace"] = namespace - response = requests.request(method, url, headers=headers, **args) + response = requests.request( # pylint: disable=missing-timeout + method, url, headers=headers, **args + ) if not response.ok and response.json().get("errors", None) == ["permission denied"]: log.info("Permission denied from vault") del_cache() @@ -407,7 +417,7 @@ def _selftoken_expired(): headers = {"X-Vault-Token": __opts__["vault"]["auth"]["token"]} if namespace is not None: headers["X-Vault-Namespace"] = namespace - response = requests.get(url, headers=headers, verify=verify) + response = requests.get(url, headers=headers, verify=verify, timeout=120) if response.status_code != 200: return True return False @@ -431,7 +441,7 @@ def _wrapped_token_valid(): headers = {"X-Vault-Token": __opts__["vault"]["auth"]["token"]} if namespace is not None: headers["X-Vault-Namespace"] = namespace - response = requests.post(url, headers=headers, verify=verify) + response = requests.post(url, headers=headers, verify=verify, timeout=120) if response.status_code != 200: return False return True diff --git a/salt/utils/verify.py b/salt/utils/verify.py index ab468dd04c1..00f81f5c413 100644 --- a/salt/utils/verify.py +++ b/salt/utils/verify.py @@ -327,7 +327,7 @@ def check_user(user): try: if hasattr(os, "initgroups"): - os.initgroups(user, pwuser.pw_gid) # pylint: disable=minimum-python-version + os.initgroups(user, pwuser.pw_gid) else: os.setgroups(salt.utils.user.get_gid_list(user, include_default=False)) os.setgid(pwuser.pw_gid) @@ -418,7 +418,10 @@ def check_max_open_files(opts): # and the python binding http://timgolden.me.uk/pywin32-docs/win32file.html mof_s = mof_h = win32file._getmaxstdio() else: - mof_s, mof_h = resource.getrlimit(resource.RLIMIT_NOFILE) + + mof_s, mof_h = resource.getrlimit( # pylint: disable=used-before-assignment + resource.RLIMIT_NOFILE + ) accepted_keys_dir = os.path.join(opts.get("pki_dir"), "minions") accepted_count = len(os.listdir(accepted_keys_dir)) diff --git a/salt/utils/versions.py b/salt/utils/versions.py index 9a97fee1bd7..5c03a15b090 100644 --- a/salt/utils/versions.py +++ b/salt/utils/versions.py @@ -352,7 +352,10 @@ def version_cmp(pkg1, pkg2, ignore_epoch=False): version2, and 1 if version1 > version2. Return None if there was a problem making the comparison. """ - normalize = lambda x: str(x).split(":", 1)[-1] if ignore_epoch else str(x) + + def normalize(x): + return str(x).split(":", 1)[-1] if ignore_epoch else str(x) + pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) diff --git a/salt/utils/vt.py b/salt/utils/vt.py index 42635b3be29..55b8172905b 100644 --- a/salt/utils/vt.py +++ b/salt/utils/vt.py @@ -73,6 +73,7 @@ def setwinsize(child, rows=80, cols=80): Thank you for the shortcut PEXPECT """ + # pylint: disable=used-before-assignment TIOCSWINSZ = getattr(termios, "TIOCSWINSZ", -2146929561) if TIOCSWINSZ == 2148037735: # Same bits, but with sign. @@ -396,7 +397,7 @@ class Terminal: def _spawn(self): if not isinstance(self.args, str) and self.shell is True: self.args = " ".join(self.args) - parent, child = pty.openpty() + parent, child = pty.openpty() # pylint: disable=used-before-assignment err_parent, err_child = os.pipe() child_name = os.ttyname(child) proc = subprocess.Popen( # pylint: disable=subprocess-popen-preexec-fn diff --git a/salt/utils/win_network.py b/salt/utils/win_network.py index eeae8fc091b..1e8ac4db3b8 100644 --- a/salt/utils/win_network.py +++ b/salt/utils/win_network.py @@ -330,6 +330,7 @@ def _get_ip_wins_info(i_face): def _get_network_interfaces(): + # pylint: disable=used-before-assignment return NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() diff --git a/salt/utils/win_runas.py b/salt/utils/win_runas.py index 0b695aaad26..b50bc01ddb9 100644 --- a/salt/utils/win_runas.py +++ b/salt/utils/win_runas.py @@ -81,7 +81,8 @@ def create_env(user_token, inherit, timeout=1): break if env is not None: return env - raise exc + if exc is not None: + raise exc def runas(cmdLine, username, password=None, cwd=None): diff --git a/salt/version.py b/salt/version.py index ab852acca0b..8cc50f6ef05 100644 --- a/salt/version.py +++ b/salt/version.py @@ -58,7 +58,7 @@ class SaltVersionsInfo(type): _previous_release = None _next_release = None - # pylint: disable=bad-whitespace,multiple-spaces-before-operator + # pylint: disable=bad-whitespace # ----- Please refrain from fixing whitespace ----------------------------------> # The idea is to keep this readable. # ------------------------------------------------------------------------------- @@ -184,7 +184,7 @@ class SaltVersionsInfo(type): # <---- Please refrain from fixing whitespace ----------------------------------- # The idea is to keep this readable. # ------------------------------------------------------------------------------- - # pylint: enable=bad-whitespace,multiple-spaces-before-operator + # pylint: enable=bad-whitespace # fmt: on @classmethod @@ -862,7 +862,7 @@ def versions_information(include_salt_cloud=False, include_extensions=True): Report the versions of dependent software. """ py_info = [ - ("Python", sys.version.rsplit("\n")[0].strip()), + ("Python", sys.version.rsplit("\n", maxsplit=1)[0].strip()), ] salt_info = list(salt_information()) lib_info = list(dependency_information(include_salt_cloud)) diff --git a/setup.py b/setup.py index c2992548c93..f4d171f9293 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ The setup script for salt """ -# pylint: disable=file-perms,resource-leakage +# pylint: disable=file-perms,resource-leakage,deprecated-module import setuptools # isort:skip import distutils.dist import glob @@ -181,7 +181,7 @@ else: def _parse_requirements_file(requirements_file): parsed_requirements = [] - with open(requirements_file) as rfh: + with open(requirements_file, encoding="utf-8") as rfh: for line in rfh.readlines(): line = line.strip() if not line or line.startswith(("#", "-r", "--")): @@ -260,7 +260,9 @@ class GenerateSaltSyspaths(Command): exit(1) # Write the system paths file - open(self.distribution.salt_syspaths_hardcoded_path, "w").write( + open( + self.distribution.salt_syspaths_hardcoded_path, "w", encoding="utf-8" + ).write( INSTALL_SYSPATHS_TEMPLATE.format( date=DATE, root_dir=self.distribution.salt_root_dir, @@ -308,9 +310,9 @@ class WriteSaltSshPackagingFile(Command): exit(1) # pylint: disable=E0602 - open(self.distribution.salt_ssh_packaging_file, "w").write( - "Packaged for Salt-SSH\n" - ) + open( + self.distribution.salt_ssh_packaging_file, "w", encoding="utf-8" + ).write("Packaged for Salt-SSH\n") # pylint: enable=E0602 @@ -463,7 +465,7 @@ class CloudSdist(Sdist): # pylint: disable=too-many-ancestors try: import requests - req = requests.get(url) + req = requests.get(url, timeout=120) if req.status_code == 200: script_contents = req.text.encode(req.encoding) else: @@ -482,7 +484,7 @@ class CloudSdist(Sdist): # pylint: disable=too-many-ancestors "Error code: {}".format(req.getcode()) ) try: - with open(deploy_path, "w") as fp_: + with open(deploy_path, "w", encoding="utf-8") as fp_: fp_.write(script_contents) except OSError as err: log.error("Failed to write the updated script: {}".format(err)) diff --git a/tests/buildpackage.py b/tests/buildpackage.py index 108cd729a0b..26a2faa5e91 100644 --- a/tests/buildpackage.py +++ b/tests/buildpackage.py @@ -18,7 +18,7 @@ import re import shutil import subprocess import sys -from optparse import OptionGroup, OptionParser +from optparse import OptionGroup, OptionParser # pylint: disable=deprecated-module logging.QUIET = 0 logging.GARBAGE = 1 @@ -236,7 +236,7 @@ def build_centos(opts): log.info("Building CentOS RPM") log.info("Detecting major release") try: - with open("/etc/redhat-release") as fp_: + with open("/etc/redhat-release", encoding="utf-8") as fp_: redhat_release = fp_.read().strip() major_release = int(redhat_release.split()[2].split(".")[0]) except (ValueError, IndexError): @@ -322,9 +322,9 @@ def build_centos(opts): # Prepare SPEC file spec_path = os.path.join(opts.build_dir, "SPECS", "salt.spec") - with open(opts.spec_file) as spec: + with open(opts.spec_file, encoding="utf-8") as spec: spec_lines = spec.read().splitlines() - with open(spec_path, "w") as fp_: + with open(spec_path, "w", encoding="utf-8") as fp_: for line in spec_lines: if line.startswith("%global srcver "): line = "%global srcver {}".format(salt_srcver) diff --git a/tests/committer_parser.py b/tests/committer_parser.py index 8056b7fd406..25572bb3268 100644 --- a/tests/committer_parser.py +++ b/tests/committer_parser.py @@ -53,7 +53,7 @@ def parse_gitlog(filename=None): if not filename or filename == "-": fh = sys.stdin else: - fh = open(filename, "r+") + fh = open(filename, "r+", encoding="utf-8") try: commitcount = 0 diff --git a/tests/conftest.py b/tests/conftest.py index b6adab5401d..38cfa97c7f7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,7 +34,7 @@ from tests.support.helpers import ( PRE_PYTEST_SKIP_REASON, get_virtualenv_binary_path, ) -from tests.support.pytest.helpers import * # pylint: disable=unused-wildcard-import +from tests.support.pytest.helpers import * # pylint: disable=unused-wildcard-import,wildcard-import from tests.support.runtests import RUNTIME_VARS from tests.support.sminion import check_required_sminion_attributes, create_sminion @@ -1559,7 +1559,7 @@ def from_filenames_collection_modifyitems(config, items): ): # In this case, this path is considered to be a file containing a line separated list # of files to consider - contents = properly_slashed_path.read_text() + contents = properly_slashed_path.read_text(encoding="utf-8") for sep in ("\r\n", "\\r\\n", "\\n"): contents = contents.replace(sep, "\n") for line in contents.split("\n"): diff --git a/tests/eventlisten.py b/tests/eventlisten.py index 8ff5ada8232..4b56378a448 100644 --- a/tests/eventlisten.py +++ b/tests/eventlisten.py @@ -4,9 +4,7 @@ what the sock_dir is. This script is a generic tool to test event output """ - - -import optparse +import optparse # pylint: disable=deprecated-module import os import pprint import time diff --git a/tests/integration/cloud/clouds/test_oneandone.py b/tests/integration/cloud/clouds/test_oneandone.py index 632f2b871d3..64a2d16694d 100644 --- a/tests/integration/cloud/clouds/test_oneandone.py +++ b/tests/integration/cloud/clouds/test_oneandone.py @@ -5,15 +5,9 @@ import pytest from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest -try: - from oneandone.client import OneAndOneService # pylint: disable=unused-import - - HAS_ONEANDONE = True -except ImportError: - HAS_ONEANDONE = False +pytest.importorskip("oneandone.client", reason="salt-cloud requires >= 1and1 1.2.0") -@pytest.mark.skipif(HAS_ONEANDONE is False, reason="salt-cloud requires >= 1and1 1.2.0") class OneAndOneTest(CloudTest): """ Integration tests for the 1and1 cloud provider @@ -26,7 +20,7 @@ class OneAndOneTest(CloudTest): """ Tests the return of running the --list-images command for 1and1 """ - image_list = self.run_cloud("--list-images {}".format(self.PROVIDER_NAME)) + image_list = self.run_cloud(f"--list-images {self.PROVIDER_NAME}") self.assertIn("coreOSimage", [i.strip() for i in image_list]) def test_instance(self): @@ -35,7 +29,7 @@ class OneAndOneTest(CloudTest): """ # check if instance with salt installed returned ret_str = self.run_cloud( - "-p oneandone-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p oneandone-test {self.instance_name}", timeout=TIMEOUT ) self.assertInstanceExists(ret_str) diff --git a/tests/integration/cloud/clouds/test_vmware.py b/tests/integration/cloud/clouds/test_vmware.py index 1e82566fc21..a0845cb8a6b 100644 --- a/tests/integration/cloud/clouds/test_vmware.py +++ b/tests/integration/cloud/clouds/test_vmware.py @@ -102,7 +102,7 @@ class VMWareTest(CloudTest): """ # salt-cloud -p my-instant-clone IC3 profile_name = "vmware-test-instant-clone" - self.run_cloud(f"-a remove_all_snapshots cloud-tests-template-base") + self.run_cloud("-a remove_all_snapshots cloud-tests-template-base") # create the instance log_format = "%(message)s" diff --git a/tests/integration/modules/test_cp.py b/tests/integration/modules/test_cp.py index af873bb6784..7c92978b31c 100644 --- a/tests/integration/modules/test_cp.py +++ b/tests/integration/modules/test_cp.py @@ -597,7 +597,9 @@ class CPModuleTest(ModuleCase): @pytest.mark.slow_test def test_push(self): log_to_xfer = os.path.join(RUNTIME_VARS.TMP, uuid.uuid4().hex) - open(log_to_xfer, "w").close() # pylint: disable=resource-leakage + open( # pylint: disable=resource-leakage + log_to_xfer, "w", encoding="utf-8" + ).close() try: self.run_function("cp.push", [log_to_xfer]) tgt_cache_file = os.path.join( diff --git a/tests/integration/modules/test_ssh.py b/tests/integration/modules/test_ssh.py index 55586211622..a22551649e7 100644 --- a/tests/integration/modules/test_ssh.py +++ b/tests/integration/modules/test_ssh.py @@ -21,7 +21,7 @@ def check_status(): Check the status of Github for remote operations """ try: - return requests.get("https://github.com").status_code == 200 + return requests.get("https://github.com", timeout=60).status_code == 200 except Exception: # pylint: disable=broad-except return False diff --git a/tests/integration/netapi/rest_tornado/test_app.py b/tests/integration/netapi/rest_tornado/test_app.py index 65bb4ad6463..e8a8656106a 100644 --- a/tests/integration/netapi/rest_tornado/test_app.py +++ b/tests/integration/netapi/rest_tornado/test_app.py @@ -67,7 +67,7 @@ class SaltnadoIntegrationTestsBase( def setUp(self): super().setUp() self.patched_environ = patched_environ(ASYNC_TEST_TIMEOUT="30") - self.patched_environ.__enter__() + self.patched_environ.__enter__() # pylint: disable=unnecessary-dunder-call self.addCleanup(self.patched_environ.__exit__) def tearDown(self): diff --git a/tests/minionswarm.py b/tests/minionswarm.py index cb3cb0aa38d..d34a5ea2e61 100644 --- a/tests/minionswarm.py +++ b/tests/minionswarm.py @@ -7,7 +7,7 @@ on a single system to test scale capabilities # pylint: disable=resource-leakage import hashlib -import optparse +import optparse # pylint: disable=deprecated-module import os import random import shutil diff --git a/tests/modparser.py b/tests/modparser.py index 978b3ad7836..f0de1011437 100644 --- a/tests/modparser.py +++ b/tests/modparser.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python2 - +#!/usr/bin/env python +import argparse import modulefinder import os import pprint @@ -9,13 +9,6 @@ import sys import salt.utils.json import salt.utils.yaml -try: - import argparse # pylint: disable=minimum-python-version - - HAS_ARGPARSE = True -except ImportError: - HAS_ARGPARSE = False - def parse(): """ @@ -46,7 +39,7 @@ def mod_data(opts, full): try: finder.load_file(full) except ImportError as exc: - print("ImportError - {} (Reason: {})".format(full, exc), file=sys.stderr) + print(f"ImportError - {full} (Reason: {exc})", file=sys.stderr) return ret for name, mod in finder.modules.items(): basemod = name.split(".")[0] @@ -86,8 +79,6 @@ def scan(opts): if __name__ == "__main__": - if not HAS_ARGPARSE: - print("The argparse python module is required") opts = parse() try: scand = scan(opts) diff --git a/tests/pytests/functional/cache/test_etcd.py b/tests/pytests/functional/cache/test_etcd.py index 01ec44b4f4f..e69dcba8431 100644 --- a/tests/pytests/functional/cache/test_etcd.py +++ b/tests/pytests/functional/cache/test_etcd.py @@ -21,8 +21,8 @@ pytestmark = [ scope="module", params=(EtcdVersion.v2, EtcdVersion.v3_v2_mode), ids=etcd_version_ids, -) # pylint: disable=function-redefined -def etcd_version(request): +) +def etcd_version(request): # pylint: disable=function-redefined # The only parameter is True because the salt cache does not use # salt/utils/etcd_util.py and if coded for etcd v2 if request.param and not HAS_ETCD_V2: diff --git a/tests/pytests/functional/modules/test_data.py b/tests/pytests/functional/modules/test_data.py index 87f31c230ee..96520cbacbd 100644 --- a/tests/pytests/functional/modules/test_data.py +++ b/tests/pytests/functional/modules/test_data.py @@ -139,9 +139,9 @@ def test_has_key(data_module): ret = data_module.update("foo", "bar") assert ret - ret = data_module.has_key("foo") # pylint: disable=.has_key-is-deprecated-use-in + ret = data_module.has_key("foo") assert ret - ret = data_module.has_key("bar") # pylint: disable=.has_key-is-deprecated-use-in + ret = data_module.has_key("bar") assert not ret diff --git a/tests/pytests/functional/modules/test_system.py b/tests/pytests/functional/modules/test_system.py index 2dabaaebfad..92fb1363864 100644 --- a/tests/pytests/functional/modules/test_system.py +++ b/tests/pytests/functional/modules/test_system.py @@ -128,8 +128,8 @@ def _test_hwclock_sync(system, hwclock_has_compare): raise CompareTimeout for _ in range(2): + orig_handler = signal.signal(signal.SIGALRM, _alrm_handler) try: - orig_handler = signal.signal(signal.SIGALRM, _alrm_handler) signal.alarm(3) rpipeFd, wpipeFd = os.pipe() log.debug("Comparing hwclock to sys clock") diff --git a/tests/pytests/functional/states/file/test_append.py b/tests/pytests/functional/states/file/test_append.py index 874d5d20714..fabb33d305c 100644 --- a/tests/pytests/functional/states/file/test_append.py +++ b/tests/pytests/functional/states/file/test_append.py @@ -145,13 +145,13 @@ def test_file_append_check_cmd(modules, state_tree, tmp_path): Test that check_cmd works for file.append and those states do not run. """ - sls_contents = f""" -append_in_file: - file.append: - - name: /tmp/test - - text: "appended text" - - check_cmd: - - "djasjahj" + sls_contents = """ + append_in_file: + file.append: + - name: /tmp/test + - text: "appended text" + - check_cmd: + - "djasjahj" """ with pytest.helpers.temp_file( "file-append-check-cmd.sls", sls_contents, state_tree diff --git a/tests/pytests/functional/states/file/test_replace.py b/tests/pytests/functional/states/file/test_replace.py index 22dab816804..473ea0cef54 100644 --- a/tests/pytests/functional/states/file/test_replace.py +++ b/tests/pytests/functional/states/file/test_replace.py @@ -378,20 +378,20 @@ def test_file_replace_prerequired_issues_55775(modules, state_tree, tmp_path): assert managed_file.exists() -def test_file_replace_check_cmd(modules, state_tree, tmp_path): +def test_file_replace_check_cmd(modules, state_tree): """ Test that check_cmd works for file.replace and those states do not run. """ - sls_contents = f""" -replace_in_file: - file.replace: - - name: /tmp/test - - pattern: hi - - repl: "replacement text" - - append_if_not_found: True - - check_cmd: - - "djasjahj" + sls_contents = """ + replace_in_file: + file.replace: + - name: /tmp/test + - pattern: hi + - repl: "replacement text" + - append_if_not_found: True + - check_cmd: + - "djasjahj" """ with pytest.helpers.temp_file( "file-replace-check-cmd.sls", sls_contents, state_tree diff --git a/tests/pytests/functional/states/pkgrepo/test_debian.py b/tests/pytests/functional/states/pkgrepo/test_debian.py index 5452ecac1c4..822b4773f5e 100644 --- a/tests/pytests/functional/states/pkgrepo/test_debian.py +++ b/tests/pytests/functional/states/pkgrepo/test_debian.py @@ -614,7 +614,7 @@ def test_repo_absent_existing_repo_trailing_slash_uri( with subtests.test("Remove repo with trailing slash in URI"): # Write contents to file with trailing slash in URI - repo_file.write_text(f"{repo_content}\n") + repo_file.write_text(f"{repo_content}\n", encoding="utf-8") # Perform and validate removal ret = pkgrepo.absent(name=repo_content) assert ret.result @@ -630,7 +630,7 @@ def test_repo_absent_existing_repo_trailing_slash_uri( # Create a repo file that matches the URI but contains no architecture. # This should not be identified as a match for repo_content, and thus # the result of a state should be a no-op. - repo_file.write_text(f"deb {repo_uri} stable main\n") + repo_file.write_text(f"deb {repo_uri} stable main\n", encoding="utf-8") # Since this was a no-op, the state should have succeeded, made no # changes, and left the repo file in place. ret = pkgrepo.absent(name=repo_content) diff --git a/tests/pytests/functional/states/test_docker_container.py b/tests/pytests/functional/states/test_docker_container.py index 2267399891e..1e8c1567217 100644 --- a/tests/pytests/functional/states/test_docker_container.py +++ b/tests/pytests/functional/states/test_docker_container.py @@ -55,7 +55,7 @@ class Network: return ipaddress.ip_network(self.subnet) @_rand_indexes.default - def __rand_indexes(self): + def __rand_indexes(self): # pylint: disable=unused-private-member return random.sample( range(2, self.net.num_addresses - 1), self.net.num_addresses - 3 ) @@ -70,12 +70,14 @@ class Network: @staticmethod def arg_map(arg_name): - return { - "ipv4_address": "IPv4Address", - "ipv6_address": "IPv6Address", - "links": "Links", - "aliases": "Aliases", - }[arg_name] + if arg_name == "ipv4_address": + return "IPv4Address" + if arg_name == "ipv6_address": + return "IPv6Address" + if arg_name == "links": + return "Links" + if arg_name == "aliases": + return "Aliases" @property def compressed_subnet(self): diff --git a/tests/pytests/functional/states/test_docker_network.py b/tests/pytests/functional/states/test_docker_network.py index 16a78b13a4a..e5e9a7ec448 100644 --- a/tests/pytests/functional/states/test_docker_network.py +++ b/tests/pytests/functional/states/test_docker_network.py @@ -46,13 +46,16 @@ class Network: "Indexing not supported for networks without a custom subnet" ) - def arg_map(self, arg_name): - return { - "ipv4_address": "IPv4Address", - "ipv6_address": "IPv6Address", - "links": "Links", - "aliases": "Aliases", - }[arg_name] + @staticmethod + def arg_map(arg_name): + if arg_name == "ipv4_address": + return "IPv4Address" + if arg_name == "ipv6_address": + return "IPv6Address" + if arg_name == "links": + return "Links" + if arg_name == "aliases": + return "Aliases" @property def subnet(self): diff --git a/tests/pytests/functional/states/test_pkg.py b/tests/pytests/functional/states/test_pkg.py index 9ea9aa98aa1..a67aa8bceca 100644 --- a/tests/pytests/functional/states/test_pkg.py +++ b/tests/pytests/functional/states/test_pkg.py @@ -513,7 +513,7 @@ def test_pkg_012_installed_with_wildcard_version(PKG_TARGETS, states, modules): ) expected_comment = ( - "All specified packages are already installed and are at the " "desired version" + "All specified packages are already installed and are at the desired version" ) assert ret.result is True assert ret.raw[next(iter(ret.raw))]["comment"] == expected_comment diff --git a/tests/pytests/functional/states/test_ssh_auth.py b/tests/pytests/functional/states/test_ssh_auth.py index 7ed7c7047fe..fea9a29df6c 100644 --- a/tests/pytests/functional/states/test_ssh_auth.py +++ b/tests/pytests/functional/states/test_ssh_auth.py @@ -45,7 +45,7 @@ def test_ssh_auth_config(tmp_path, system_user, state_tree): ssh_auth_state.manage( name="test", user=system_user.username, - source=f"salt://authorized", + source="salt://authorized", config=str(new_auth_file), ssh_keys=[""], ) diff --git a/tests/pytests/functional/test_crypt.py b/tests/pytests/functional/test_crypt.py index 0c8e90e82d6..b0cf862d641 100644 --- a/tests/pytests/functional/test_crypt.py +++ b/tests/pytests/functional/test_crypt.py @@ -7,6 +7,7 @@ import salt.crypt @pytest.mark.windows_whitelisted def test_generated_keys(tmp_path): - priv = salt.crypt.gen_keys(tmp_path, "aaa", 2048) - assert "\r" not in pathlib.Path(priv).read_text() - assert "\r" not in pathlib.Path(priv.replace(".pem", ".pub")).read_text() + priv = pathlib.Path(salt.crypt.gen_keys(tmp_path, "aaa", 2048)) + pub = priv.with_suffix(".pub") + assert "\r" not in priv.read_text(encoding="utf-8") + assert "\r" not in pub.read_text(encoding="utf-8") diff --git a/tests/pytests/integration/_logging/test_jid_logging.py b/tests/pytests/integration/_logging/test_jid_logging.py index 016bf89e104..96ba7697053 100644 --- a/tests/pytests/integration/_logging/test_jid_logging.py +++ b/tests/pytests/integration/_logging/test_jid_logging.py @@ -12,7 +12,7 @@ def test_jid_in_logs(caplog, salt_call_cli): """ Test JID in log_format """ - jid_formatted_str = DFLT_LOG_FMT_JID.split("%")[0] + jid_formatted_str = DFLT_LOG_FMT_JID.split("%", maxsplit=1)[0] formatter = logging.Formatter(fmt="%(jid)s %(message)s") with caplog.at_level(logging.DEBUG): previous_formatter = caplog.handler.formatter diff --git a/tests/pytests/integration/cli/test_batch.py b/tests/pytests/integration/cli/test_batch.py index 70d66d99598..45c506a2bfd 100644 --- a/tests/pytests/integration/cli/test_batch.py +++ b/tests/pytests/integration/cli/test_batch.py @@ -141,7 +141,9 @@ def test_batch_state_stopping_after_error( # Executing salt with batch: 1 and with failhard. It should stop after the first error. cmd = salt_cli.run( - "state.single" "test.fail_without_changes" "name=test_me", + "state.single", + "test.fail_without_changes", + "name=test_me", "-b 1", "--out=yaml", "--failhard", diff --git a/tests/pytests/integration/cli/test_salt.py b/tests/pytests/integration/cli/test_salt.py index 7f026845843..30752102025 100644 --- a/tests/pytests/integration/cli/test_salt.py +++ b/tests/pytests/integration/cli/test_salt.py @@ -254,7 +254,7 @@ def test_minion_65400(salt_cli, salt_minion, salt_minion_2, salt_master): Ensure correct exit status when salt CLI starts correctly. """ - state = f""" + state = """ custom_test_state: test.configurable_test_state: - name: example diff --git a/tests/pytests/integration/cli/test_syndic_eauth.py b/tests/pytests/integration/cli/test_syndic_eauth.py index a37127c3949..e1d159cdf91 100644 --- a/tests/pytests/integration/cli/test_syndic_eauth.py +++ b/tests/pytests/integration/cli/test_syndic_eauth.py @@ -523,7 +523,7 @@ def all_the_docker( except docker.errors.APIError as exc: # if the container isn't running, there's not thing we can do # at this point. - log.info(f"Docker failed removing /etc/salt: %s", exc) + log.info("Docker failed removing /etc/salt: %s", exc) @pytest.fixture( diff --git a/tests/pytests/integration/modules/state/test_state_test.py b/tests/pytests/integration/modules/state/test_state_test.py index 40049e9a6b6..9dbcadd04e6 100644 --- a/tests/pytests/integration/modules/state/test_state_test.py +++ b/tests/pytests/integration/modules/state/test_state_test.py @@ -136,7 +136,7 @@ def test_state_sls_id_test_state_test_post_run(salt_call_cli, testfile_path): true post the state already being run previously """ source = pathlib.Path(RUNTIME_VARS.BASE_FILES, "testfile") - testfile_path.write_text(source.read_text()) + testfile_path.write_text(source.read_text(encoding="utf-8"), encoding="utf-8") testfile_path.chmod(0o644) ret = salt_call_cli.run("state.sls", "sls-id-test") assert ret.returncode == 0 diff --git a/tests/pytests/integration/sdb/test_etcd_db.py b/tests/pytests/integration/sdb/test_etcd_db.py index d981b222da7..3085dafb8ce 100644 --- a/tests/pytests/integration/sdb/test_etcd_db.py +++ b/tests/pytests/integration/sdb/test_etcd_db.py @@ -28,8 +28,8 @@ def etcd_static_port(sdb_etcd_port): # pylint: disable=function-redefined scope="module", params=(EtcdVersion.v2, EtcdVersion.v3_v2_mode), ids=etcd_version_ids, -) # pylint: disable=function-redefined -def etcd_version(request): +) +def etcd_version(request): # pylint: disable=function-redefined # The only parameter is True because the salt integration # configuration for the salt-master and salt-minion defaults # to v2. diff --git a/tests/pytests/integration/ssh/test_pre_flight.py b/tests/pytests/integration/ssh/test_pre_flight.py index c2fc14094e8..7dc56f37535 100644 --- a/tests/pytests/integration/ssh/test_pre_flight.py +++ b/tests/pytests/integration/ssh/test_pre_flight.py @@ -207,7 +207,7 @@ def test_ssh_pre_flight_script(salt_ssh_cli, caplog, _create_roster, tmp_path, a try: script = pathlib.Path.home() / "hacked" tmp_preflight = pathlib.Path("/tmp", "ssh_pre_flight.sh") - tmp_preflight.write_text(f"touch {script}") + tmp_preflight.write_text(f"touch {script}", encoding="utf-8") os.chown(tmp_preflight, account.info.uid, account.info.gid) ret = salt_ssh_cli.run("test.ping") assert not script.is_file() @@ -239,7 +239,7 @@ def test_ssh_pre_flight_perms(salt_ssh_cli, caplog, _create_roster, account): try: script = pathlib.Path("/tmp", "itworked") preflight = pathlib.Path("/ssh_pre_flight.sh") - preflight.write_text(f"touch {str(script)}") + preflight.write_text(f"touch {str(script)}", encoding="utf-8") tmp_preflight = pathlib.Path("/tmp", preflight.name) _custom_roster(salt_ssh_cli.roster_file, {"ssh_pre_flight": str(preflight)}) @@ -255,7 +255,8 @@ def test_ssh_pre_flight_perms(salt_ssh_cli, caplog, _create_roster, account): fi x=$(( $x + 1 )) done - """ + """, + encoding="utf-8", ) run_script.chmod(0o0777) # pylint: disable=W1509 diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index a71d4b038e9..57b1e4c834e 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -7,7 +7,7 @@ import os import pathlib import shutil -import packaging +import packaging.version import pytest from pytestskipmarkers.utils import platform @@ -97,7 +97,7 @@ def get_salt_release(): salt_release = "3006.0rc2" if pkg_test_type == "download-pkgs": if packaging.version.parse(salt_release) < packaging.version.parse("3006.0rc1"): - log.warning(f"The salt release being tested, {salt_release!r} looks off.") + log.warning("The salt release being tested, %r looks off.", salt_release) return salt_release @@ -109,7 +109,9 @@ def get_repo_subpath_params(): latest_release = packaging.version.parse(latest_env_var) if current_release >= latest_release: log.debug( - f"Running the tests for the latest release since {str(current_release)} >= {str(latest_release)}" + "Running the tests for the latest release since %s >= %s", + current_release, + latest_release, ) params.append("latest") return params diff --git a/tests/pytests/pkg/integration/test_pip_upgrade.py b/tests/pytests/pkg/integration/test_pip_upgrade.py index 19ed1d6d336..cabc74cefef 100644 --- a/tests/pytests/pkg/integration/test_pip_upgrade.py +++ b/tests/pytests/pkg/integration/test_pip_upgrade.py @@ -49,7 +49,7 @@ def test_pip_install(install_salt, salt_call_cli): pytest.fail(f"Failed to find {dep} in the versions report output") if dep_version == installed_version: - log.warning(f"The {dep} dependency is already latest") + log.warning("The %s dependency is already latest", dep) else: found_new = True break @@ -88,7 +88,7 @@ def test_pip_install(install_salt, salt_call_cli): else: pytest.fail(f"Failed to find {dep} in the versions report output") finally: - log.info(f"Uninstalling {dep_version}") + log.info("Uninstalling %s", dep_version) assert salt_call_cli.run( "--local", "pip.uninstall", f"{dep}=={dep_version}" ) diff --git a/tests/pytests/pkg/integration/test_salt_user.py b/tests/pytests/pkg/integration/test_salt_user.py index 4538ce79adb..a7516e2b4d8 100644 --- a/tests/pytests/pkg/integration/test_salt_user.py +++ b/tests/pytests/pkg/integration/test_salt_user.py @@ -296,7 +296,7 @@ def test_paths_log_rotation( for _path in log_files_list: log_path = pathlib.Path(_path) assert log_path.exists() - with log_path.open("a") as f: + with log_path.open("a", encoding="utf-8") as f: f.write("This is a log rotation test\n") # force log rotation diff --git a/tests/pytests/scenarios/blackout/conftest.py b/tests/pytests/scenarios/blackout/conftest.py index 09cee10db66..1cef38bcc84 100644 --- a/tests/pytests/scenarios/blackout/conftest.py +++ b/tests/pytests/scenarios/blackout/conftest.py @@ -46,7 +46,7 @@ class BlackoutPillar: self.minion_1_pillar.write_text(pillar_contents) self.refresh_pillar(exiting_blackout=False) self.in_blackout = True - return self.__enter__() + return self.__enter__() # pylint: disable=unnecessary-dunder-call def exit_blackout(self): if self.in_blackout: diff --git a/tests/pytests/unit/beacons/test_salt_monitor.py b/tests/pytests/unit/beacons/test_salt_monitor.py index 1edf8be539d..e718c780e50 100644 --- a/tests/pytests/unit/beacons/test_salt_monitor.py +++ b/tests/pytests/unit/beacons/test_salt_monitor.py @@ -1,5 +1,3 @@ -# pylint: disable=E8231 -# Salt libs import pytest import salt.beacons.salt_monitor as salt_monitor diff --git a/tests/pytests/unit/cli/test_daemons.py b/tests/pytests/unit/cli/test_daemons.py index 6f339b61234..5d68c56c77b 100644 --- a/tests/pytests/unit/cli/test_daemons.py +++ b/tests/pytests/unit/cli/test_daemons.py @@ -61,9 +61,7 @@ class LoggerMock: :return: """ for data in self.messages: - log_str = ( - data["message"] % data["args"] - ) # pylint: disable=incompatible-py3-code + log_str = data["message"] % data["args"] if (data["type"] == log_type or not log_type) and log_str.find(msg) > -1: return True diff --git a/tests/pytests/unit/client/ssh/test_ssh.py b/tests/pytests/unit/client/ssh/test_ssh.py index e3baf3f5d35..7582cbbee0d 100644 --- a/tests/pytests/unit/client/ssh/test_ssh.py +++ b/tests/pytests/unit/client/ssh/test_ssh.py @@ -229,7 +229,7 @@ def test_update_targets_ip_address(opts): assert opts["tgt"] == user + host client._update_targets() assert opts["tgt"] == host - assert client.targets[host]["user"] == user.split("@")[0] + assert client.targets[host]["user"] == user.split("@", maxsplit=1)[0] def test_update_targets_dns(opts): @@ -245,7 +245,7 @@ def test_update_targets_dns(opts): assert opts["tgt"] == user + host client._update_targets() assert opts["tgt"] == host - assert client.targets[host]["user"] == user.split("@")[0] + assert client.targets[host]["user"] == user.split("@", maxsplit=1)[0] def test_update_targets_no_user(opts): @@ -282,7 +282,7 @@ def test_update_expand_target_dns(opts, roster): client._expand_target() client._update_targets() assert opts["tgt"] == host - assert client.targets[host]["user"] == user.split("@")[0] + assert client.targets[host]["user"] == user.split("@", maxsplit=1)[0] def test_parse_tgt(opts): @@ -298,7 +298,7 @@ def test_parse_tgt(opts): assert not opts.get("ssh_cli_tgt") client = ssh.SSH(opts) assert client.parse_tgt["hostname"] == host - assert client.parse_tgt["user"] == user.split("@")[0] + assert client.parse_tgt["user"] == user.split("@", maxsplit=1)[0] assert opts.get("ssh_cli_tgt") == user + host diff --git a/tests/pytests/unit/cloud/clouds/test_proxmox.py b/tests/pytests/unit/cloud/clouds/test_proxmox.py index 1d1823a8035..405db87caec 100644 --- a/tests/pytests/unit/cloud/clouds/test_proxmox.py +++ b/tests/pytests/unit/cloud/clouds/test_proxmox.py @@ -384,6 +384,7 @@ def test__authenticate_with_custom_port(): "https://proxmox.connection.url:9999/api2/json/access/ticket", verify=True, data={"username": ("fakeuser",), "password": "secretpassword"}, + timeout=120, ) diff --git a/tests/pytests/unit/daemons/masterapi/test_remote_funcs.py b/tests/pytests/unit/daemons/masterapi/test_remote_funcs.py index 8151dcaf006..99821a8f54a 100644 --- a/tests/pytests/unit/daemons/masterapi/test_remote_funcs.py +++ b/tests/pytests/unit/daemons/masterapi/test_remote_funcs.py @@ -42,7 +42,7 @@ def test_mine_get(funcs, tgt_type_key="tgt_type"): funcs.cache.store("minions/webserver", "mine", dict(ip_addr="2001:db8::1:3")) with patch( "salt.utils.minions.CkMinions._check_compound_minions", - MagicMock(return_value=(dict(minions=["webserver"], missing=[]))), + MagicMock(return_value=dict(minions=["webserver"], missing=[])), ): ret = funcs._mine_get( { @@ -81,7 +81,7 @@ def test_mine_get_dict_str(funcs, tgt_type_key="tgt_type"): ) with patch( "salt.utils.minions.CkMinions._check_compound_minions", - MagicMock(return_value=(dict(minions=["webserver"], missing=[]))), + MagicMock(return_value=dict(minions=["webserver"], missing=[])), ): ret = funcs._mine_get( { @@ -114,7 +114,7 @@ def test_mine_get_dict_list(funcs, tgt_type_key="tgt_type"): ) with patch( "salt.utils.minions.CkMinions._check_compound_minions", - MagicMock(return_value=(dict(minions=["webserver"], missing=[]))), + MagicMock(return_value=dict(minions=["webserver"], missing=[])), ): ret = funcs._mine_get( { diff --git a/tests/pytests/unit/fileserver/test_roots.py b/tests/pytests/unit/fileserver/test_roots.py index c1660280bc5..c6a58136a3c 100644 --- a/tests/pytests/unit/fileserver/test_roots.py +++ b/tests/pytests/unit/fileserver/test_roots.py @@ -290,7 +290,7 @@ def test_find_file_not_in_root(tmp_state_tree): """ badfile = pathlib.Path(tmp_state_tree).parent / "bar" badfile.write_text("Bad file") - badpath = f"../bar" + badpath = "../bar" ret = roots.find_file(badpath) assert ret == {"path": "", "rel": ""} badpath = f"{tmp_state_tree / '..' / 'bar'}" @@ -304,7 +304,7 @@ def test_serve_file_not_in_root(tmp_state_tree): """ badfile = pathlib.Path(tmp_state_tree).parent / "bar" badfile.write_text("Bad file") - badpath = f"../bar" + badpath = "../bar" load = {"path": "salt://|..\\bar", "saltenv": "base", "loc": 0} fnd = { "path": f"{tmp_state_tree / '..' / 'bar'}", diff --git a/tests/pytests/unit/modules/dockermod/test_module.py b/tests/pytests/unit/modules/dockermod/test_module.py index abfd101540d..4c820bd9190 100644 --- a/tests/pytests/unit/modules/dockermod/test_module.py +++ b/tests/pytests/unit/modules/dockermod/test_module.py @@ -307,10 +307,10 @@ def test_check_mine_cache_is_refreshed_on_container_change_event(command_name, a try: mine_send.assert_called_with("docker.ps", verbose=True, all=True, host=True) except AssertionError as exc: - raise Exception( + raise AssertionError( "command '{}' did not call docker.ps with expected " "arguments: {}".format(command_name, exc) - ) + ) from exc def test_update_mine(): @@ -319,24 +319,14 @@ def test_update_mine(): """ def config_get_disabled(val, default): - return { - "base_url": docker_mod.NOTSET, - "version": docker_mod.NOTSET, - "docker.url": docker_mod.NOTSET, - "docker.version": docker_mod.NOTSET, - "docker.machine": docker_mod.NOTSET, - "docker.update_mine": False, - }[val] + if val == "docker.update_mine": + return False + return docker_mod.NOTSET def config_get_enabled(val, default): - return { - "base_url": docker_mod.NOTSET, - "version": docker_mod.NOTSET, - "docker.url": docker_mod.NOTSET, - "docker.version": docker_mod.NOTSET, - "docker.machine": docker_mod.NOTSET, - "docker.update_mine": True, - }[val] + if val == "docker.update_mine": + return True + return docker_mod.NOTSET mine_mock = Mock() dunder_salt = { @@ -937,19 +927,19 @@ def test_compare_container_image_id_resolution(): """ def _inspect_container_effect(id_): - return { - "container1": { + if id_ == "container1": + return { "Config": {"Image": "realimage:latest"}, "HostConfig": {}, - }, - "container2": {"Config": {"Image": "image_id"}, "HostConfig": {}}, - }[id_] + } + if id_ == "container2": + return {"Config": {"Image": "image_id"}, "HostConfig": {}} def _inspect_image_effect(id_): - return { - "realimage:latest": {"Id": "image_id"}, - "image_id": {"Id": "image_id"}, - }[id_] + if id_ == "realimage:latest": + return {"Id": "image_id"} + if id_ == "image_id": + return {"Id": "image_id"} inspect_container_mock = MagicMock(side_effect=_inspect_container_effect) inspect_image_mock = MagicMock(side_effect=_inspect_image_effect) @@ -967,8 +957,8 @@ def test_compare_container_ulimits_order(): """ def _inspect_container_effect(id_): - return { - "container1": { + if id_ == "container1": + return { "Config": {}, "HostConfig": { "Ulimits": [ @@ -976,8 +966,9 @@ def test_compare_container_ulimits_order(): {"Hard": 65536, "Soft": 65536, "Name": "nofile"}, ] }, - }, - "container2": { + } + if id_ == "container2": + return { "Config": {}, "HostConfig": { "Ulimits": [ @@ -985,8 +976,7 @@ def test_compare_container_ulimits_order(): {"Hard": -1, "Soft": -1, "Name": "core"}, ] }, - }, - }[id_] + } inspect_container_mock = MagicMock(side_effect=_inspect_container_effect) @@ -1004,16 +994,16 @@ def test_compare_container_env_order(): """ def _inspect_container_effect(id_): - return { - "container1": { + if id_ == "container1": + return { "Config": {}, "HostConfig": {"Env": ["FOO=bar", "HELLO=world"]}, - }, - "container2": { + } + if id_ == "container2": + return { "Config": {}, "HostConfig": {"Env": ["HELLO=world", "FOO=bar"]}, - }, - }[id_] + } inspect_container_mock = MagicMock(side_effect=_inspect_container_effect) diff --git a/tests/pytests/unit/modules/file/test_file_line.py b/tests/pytests/unit/modules/file/test_file_line.py index 80030e1417d..5c2e444617e 100644 --- a/tests/pytests/unit/modules/file/test_file_line.py +++ b/tests/pytests/unit/modules/file/test_file_line.py @@ -1633,7 +1633,7 @@ def test_line_insert_ensure_beforeafter_twolines_exists(tempfile_name): ) # pylint: enable=W1401 after, before = ( - file_content.split(os.linesep)[0], + file_content.split(os.linesep, maxsplit=1)[0], file_content.split(os.linesep)[2], ) diff --git a/tests/pytests/unit/modules/file/test_file_lsattr.py b/tests/pytests/unit/modules/file/test_file_lsattr.py index 232f2a22d4b..5e211b06428 100644 --- a/tests/pytests/unit/modules/file/test_file_lsattr.py +++ b/tests/pytests/unit/modules/file/test_file_lsattr.py @@ -79,9 +79,7 @@ def test_if_chattr_version_is_less_than_required_flags_should_ignore_extended(): ) with patch_has_ext, patch_run: actual = set(filemod.lsattr(fname)[fname]) - msg = "Actual: {!r} Expected: {!r}".format( - actual, expected - ) # pylint: disable=E1322 + msg = f"Actual: {actual!r} Expected: {expected!r}" assert actual == expected, msg @@ -107,9 +105,7 @@ def test_if_chattr_version_is_high_enough_then_extended_flags_should_be_returned ) with patch_has_ext, patch_run: actual = set(filemod.lsattr(fname)[fname]) - msg = "Actual: {!r} Expected: {!r}".format( - actual, expected - ) # pylint: disable=E1322 + msg = f"Actual: {actual!r} Expected: {expected!r}" assert actual == expected, msg @@ -135,7 +131,5 @@ def test_if_supports_extended_but_there_are_no_flags_then_none_should_be_returne ) with patch_has_ext, patch_run: actual = set(filemod.lsattr(fname)[fname]) - msg = "Actual: {!r} Expected: {!r}".format( - actual, expected - ) # pylint: disable=E1322 + msg = f"Actual: {actual!r} Expected: {expected!r}" assert actual == expected, msg diff --git a/tests/pytests/unit/modules/file/test_file_module.py b/tests/pytests/unit/modules/file/test_file_module.py index 34fe4fa210d..ea6acc79fdc 100644 --- a/tests/pytests/unit/modules/file/test_file_module.py +++ b/tests/pytests/unit/modules/file/test_file_module.py @@ -506,12 +506,14 @@ def test_get_diff(): mockself.path = path def readlines(mockself): # pylint: disable=unused-argument - return { - "text1": text1.encode("utf8"), - "text2": text2.encode("utf8"), - "binary1": binary1, - "binary2": binary2, - }[mockself.path].splitlines(True) + if mockself.path == "text1": + return text1.encode("utf8").splitlines(True) + if mockself.path == "text2": + return text2.encode("utf8").splitlines(True) + if mockself.path == "binary1": + return binary1.splitlines(True) + if mockself.path == "binary2": + return binary2.splitlines(True) def __enter__(mockself): return mockself diff --git a/tests/pytests/unit/modules/state/test_state.py b/tests/pytests/unit/modules/state/test_state.py index 7c42646bcf7..e08b2be6ad7 100644 --- a/tests/pytests/unit/modules/state/test_state.py +++ b/tests/pytests/unit/modules/state/test_state.py @@ -759,9 +759,7 @@ def test_top(): with patch.object(os.path, "join", mock): mock = MagicMock(return_value=True) with patch.object(state, "_set_retcode", mock): - assert state.top( - "reverse_top.sls " "exclude=exclude.sls" - ) + assert state.top("reverse_top.sls exclude=exclude.sls") def test_highstate(): @@ -800,7 +798,7 @@ def test_highstate(): mock = MagicMock(return_value=True) with patch.object(salt.payload, "Serial", mock): with patch.object(os.path, "join", mock): - with patch.object(state, "_set" "_retcode", mock): + with patch.object(state, "_set_retcode", mock): assert state.highstate(arg) @@ -906,11 +904,11 @@ def test_sls(): assert state.sls(arg, None, None, True, cache=True) MockState.HighState.flag = True - assert state.sls("core,edit" ".vim dev", None, None, True) + assert state.sls("core,edit.vim dev", None, None, True) MockState.HighState.flag = False with patch.object( - state, "_filter_" "running", return_value=True + state, "_filter_running", return_value=True ), patch.object(os.path, "join", return_value=True), patch.object( os, "umask", return_value=True ), patch.object( @@ -922,7 +920,7 @@ def test_sls(): ), patch( "salt.utils.files.fopen", mock_open() ): - assert state.sls("core,edit" ".vim dev", None, None, True) + assert state.sls("core,edit.vim dev", None, None, True) def test_get_test_value(): diff --git a/tests/pytests/unit/modules/test_cp.py b/tests/pytests/unit/modules/test_cp.py index 6caa9ef5938..6700832e345 100644 --- a/tests/pytests/unit/modules/test_cp.py +++ b/tests/pytests/unit/modules/test_cp.py @@ -43,7 +43,10 @@ def test__render_filenames_render_failed(): saltenv = "base" template = "jinja" file_data = "Remember to keep your files well salted." - mock_jinja = lambda *args, **kwargs: {"result": False, "data": file_data} + + def mock_jinja(*args, **kwargs): + return {"result": False, "data": file_data} + with patch.dict(templates.TEMPLATE_REGISTRY, {"jinja": mock_jinja}): with patch("salt.utils.files.fopen", mock_open(read_data=file_data)): pytest.raises( @@ -65,7 +68,10 @@ def test__render_filenames_success(): saltenv = "base" template = "jinja" file_data = "/srv/salt/biscuits" - mock_jinja = lambda *args, **kwargs: {"result": True, "data": file_data} + + def mock_jinja(*args, **kwargs): + return {"result": True, "data": file_data} + ret = (file_data, file_data) # salt.utils.files.fopen can only be mocked once with patch.dict(templates.TEMPLATE_REGISTRY, {"jinja": mock_jinja}): with patch("salt.utils.files.fopen", mock_open(read_data=file_data)): @@ -149,7 +155,8 @@ def test_push(): assert num_opens == 1, num_opens fh_ = m_open.filehandles[filename][0] assert fh_.read.call_count == 2, fh_.read.call_count - req_channel_factory_mock().__enter__().send.assert_called_once_with( + + req_channel_factory_mock().__enter__().send.assert_called_once_with( # pylint: disable=unnecessary-dunder-call dict( loc=fh_.tell(), # pylint: disable=resource-leakage cmd="_file_recv", diff --git a/tests/pytests/unit/modules/test_devinfo.py b/tests/pytests/unit/modules/test_devinfo.py index d3895e53246..8e0db9bfdec 100644 --- a/tests/pytests/unit/modules/test_devinfo.py +++ b/tests/pytests/unit/modules/test_devinfo.py @@ -42,9 +42,17 @@ def test_devices(): "E": {"ID_BUS": "ata"}, } + def _udev_info(key): + if key == "sda": + return hd + if key == "sdb": + return usb + if key == "sr0": + return cdrom + with patch.dict( devinfo.__salt__, - {"udev.info": lambda d: {"sda": hd, "sdb": usb, "sr0": cdrom}[d]}, + {"udev.info": _udev_info}, ), patch.dict(devinfo.__grains__, {"disks": ["sda", "sdb", "sr0"]}): assert devinfo.filter_({"e.id_bus": "ata"}, {}) == ["sda", "sr0"] assert devinfo.filter_({"e.id_bus": "usb"}, {}) == ["sdb"] diff --git a/tests/pytests/unit/modules/test_glassfish.py b/tests/pytests/unit/modules/test_glassfish.py index 159d00cbb16..e6e22b3a696 100644 --- a/tests/pytests/unit/modules/test_glassfish.py +++ b/tests/pytests/unit/modules/test_glassfish.py @@ -33,6 +33,7 @@ def test__api_get(): url="http://localhost:4848/management/domain/ThePath", verify=True, auth=None, + timeout=120, ) @@ -51,6 +52,7 @@ def test__api_post(): verify=True, auth=None, data='{"1": 1}', + timeout=120, ) @@ -69,4 +71,5 @@ def test__api_delete(): verify=True, auth=None, params={1: 1}, + timeout=120, ) diff --git a/tests/pytests/unit/modules/test_gpg.py b/tests/pytests/unit/modules/test_gpg.py index 697f53c6541..67e6f2e0f84 100644 --- a/tests/pytests/unit/modules/test_gpg.py +++ b/tests/pytests/unit/modules/test_gpg.py @@ -621,7 +621,9 @@ def test_export_public_key_to_file(gpghome): keyids="xxxxxxxxxxxxxxxx", output=exported_keyfile, bare=True ) assert ret == GPG_TEST_PUB_KEY - keyfile_contents = pathlib.Path(exported_keyfile).read_text() + keyfile_contents = pathlib.Path(exported_keyfile).read_text( + encoding="utf-8" + ) assert keyfile_contents == GPG_TEST_PUB_KEY @@ -746,7 +748,9 @@ def test_export_secret_key_to_file_with_gpg_passphrase_in_pillar(gpghome): True, passphrase=GPG_TEST_KEY_PASSPHRASE, ) - keyfile_contents = pathlib.Path(exported_keyfile).read_text() + keyfile_contents = pathlib.Path(exported_keyfile).read_text( + encoding="utf-8" + ) assert keyfile_contents == GPG_TEST_PRIV_KEY diff --git a/tests/pytests/unit/modules/test_hg.py b/tests/pytests/unit/modules/test_hg.py index 314b48b2c8e..5d31217b76d 100644 --- a/tests/pytests/unit/modules/test_hg.py +++ b/tests/pytests/unit/modules/test_hg.py @@ -97,18 +97,15 @@ def test_status_multiple(): """ Test for Status to a given repository (cwd is list) """ + + def func(*args, **kwargs): + if kwargs["cwd"] == "dir 0": + return "A file 0\n" + return "M file 1" + with patch.dict( hg.__salt__, - { - "cmd.run_stdout": MagicMock( - side_effect=( - lambda *args, **kwargs: { - "dir 0": "A file 0\n", - "dir 1": "M file 1", - }[kwargs["cwd"]] - ) - ) - }, + {"cmd.run_stdout": MagicMock(side_effect=func)}, ): assert hg.status(["dir 0", "dir 1"]) == { "dir 0": {"added": ["file 0"]}, diff --git a/tests/pytests/unit/modules/test_mount.py b/tests/pytests/unit/modules/test_mount.py index 3a4e1d544e3..ea5feb8a5e0 100644 --- a/tests/pytests/unit/modules/test_mount.py +++ b/tests/pytests/unit/modules/test_mount.py @@ -416,8 +416,6 @@ def test_set_filesystems_with_data(tmp_sub_dir, config_file): Tests to verify set_filesystems reads and adjusts file /etc/filesystems correctly """ # Note AIX uses tabs in filesystems files, hence disable warings and errors for tabs and spaces - # pylint: disable=W8191 - # pylint: disable=E8101 config_filepath = str(tmp_sub_dir / "filesystems") with patch.dict(mount.__grains__, {"os": "AIX", "kernel": "AIX"}): mount.set_filesystems( diff --git a/tests/pytests/unit/modules/test_salt_version.py b/tests/pytests/unit/modules/test_salt_version.py index 4b7a7cd0731..6e3a09cbe78 100644 --- a/tests/pytests/unit/modules/test_salt_version.py +++ b/tests/pytests/unit/modules/test_salt_version.py @@ -29,8 +29,7 @@ def test_mocked_objects(): else: assert len(v) == 2 - sv = sv.__str__() - assert isinstance(sv, str) + assert isinstance(str(sv), str) with patch("salt.version.SaltStackVersion.LNAMES", {"neon": (2019, 8)}): sv = salt.version.SaltStackVersion.from_name("Neon") diff --git a/tests/pytests/unit/modules/test_solaris_shadow.py b/tests/pytests/unit/modules/test_solaris_shadow.py index 4cc99c6e983..85d7aa41fcd 100644 --- a/tests/pytests/unit/modules/test_solaris_shadow.py +++ b/tests/pytests/unit/modules/test_solaris_shadow.py @@ -29,7 +29,7 @@ skip_on_missing_pwd = pytest.mark.skipif( missing_pwd, reason="Has no pwd module for accessing /etc/password passwords" ) -# pylint: disable=singleton-comparison,comparison-to-True-should-be-if-cond-is-True-or-if-cond +# pylint: disable=singleton-comparison # TODO: A lot of the shadow functionality is common across solaris and Linux. # It would be possible to combine some of this into salt/utils -W. Werner, 2021-01-26 diff --git a/tests/pytests/unit/modules/test_win_powercfg.py b/tests/pytests/unit/modules/test_win_powercfg.py index e1cd9426a4c..ab6f0ee6258 100644 --- a/tests/pytests/unit/modules/test_win_powercfg.py +++ b/tests/pytests/unit/modules/test_win_powercfg.py @@ -168,7 +168,7 @@ def test_get_disk_timeout(query_output): calls = [ call("powercfg /getactivescheme", python_shell=False), call( - "powercfg /q 381b4222-f694-41f0-9685-ff5bb260df2e SUB_DISK" " DISKIDLE", + "powercfg /q 381b4222-f694-41f0-9685-ff5bb260df2e SUB_DISK DISKIDLE", python_shell=False, ), ] diff --git a/tests/pytests/unit/modules/test_zabbix.py b/tests/pytests/unit/modules/test_zabbix.py index 5c2f8fc7ee5..fd9fae8c1a6 100644 --- a/tests/pytests/unit/modules/test_zabbix.py +++ b/tests/pytests/unit/modules/test_zabbix.py @@ -407,7 +407,6 @@ def test_user_exists(conn_args, set_zabbix_version, query_return, mock_login): """ module_return = True - # pylint: disable=E8128 query_return( { "jsonrpc": "2.0", @@ -464,7 +463,6 @@ def test_user_get(conn_args, set_zabbix_version, query_return, mock_login): "type": "3", } ] - # pylint: disable=E8128 query_return( { "jsonrpc": "2.0", @@ -547,7 +545,6 @@ def test_user_getmedia(conn_args, set_zabbix_version, query_return, mock_login): "active": "0", } ] - # pylint: disable=E8128 query_return( { "jsonrpc": "2.0", @@ -707,7 +704,6 @@ def test_user_list(conn_args, query_return, mock_login): "type": "1", }, ] - # pylint: disable=E8128 query_return( { "jsonrpc": "2.0", @@ -924,7 +920,6 @@ def test_usergroup_list(conn_args, query_return, mock_login): "users_status": "0", }, ] - # pylint: disable=E8128 query_return( { "jsonrpc": "2.0", diff --git a/tests/pytests/unit/modules/virt/conftest.py b/tests/pytests/unit/modules/virt/conftest.py index 03225530056..fb0d8746c57 100644 --- a/tests/pytests/unit/modules/virt/conftest.py +++ b/tests/pytests/unit/modules/virt/conftest.py @@ -39,7 +39,7 @@ class MappedResultMock(MagicMock): def __init__(self): def mapped_results(*args, **kwargs): - if args[0] not in self._instances.keys(): + if args[0] not in self._instances: raise virt.libvirt.libvirtError("Not found: {}".format(args[0])) return self._instances[args[0]] diff --git a/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py b/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py index f808dbf4467..56eecd4bbc2 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py +++ b/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py @@ -83,7 +83,7 @@ def lgpo_bin(): # download lgpo.zip log.debug("Downloading LGPO.exe from Microsoft") url = "https://download.microsoft.com/download/8/5/C/85C25433-A1B0-4FFA-9429-7E023E7DA8D8/LGPO.zip" - r = requests.get(url) + r = requests.get(url, timeout=60) with salt.utils.files.fopen(zip_file, "wb") as f: f.write(r.content) # extract zip diff --git a/tests/pytests/unit/pillar/test_consul_pillar.py b/tests/pytests/unit/pillar/test_consul_pillar.py index 430f7aa5e43..b37d5f7876e 100644 --- a/tests/pytests/unit/pillar/test_consul_pillar.py +++ b/tests/pytests/unit/pillar/test_consul_pillar.py @@ -54,9 +54,7 @@ def configure_loader_modules(): def test_connection(base_pillar_data): - with patch.dict( - consul_pillar.__salt__, {"grains.get": MagicMock(return_value=({}))} - ): + with patch.dict(consul_pillar.__salt__, {"grains.get": MagicMock(return_value={})}): with patch.object( consul_pillar, "consul_fetch", @@ -71,9 +69,7 @@ def test_connection(base_pillar_data): def test_pillar_data(base_pillar_data): - with patch.dict( - consul_pillar.__salt__, {"grains.get": MagicMock(return_value=({}))} - ): + with patch.dict(consul_pillar.__salt__, {"grains.get": MagicMock(return_value={})}): with patch.object( consul_pillar, "consul_fetch", @@ -90,9 +86,7 @@ def test_pillar_data(base_pillar_data): def test_blank_root(base_pillar_data): - with patch.dict( - consul_pillar.__salt__, {"grains.get": MagicMock(return_value=({}))} - ): + with patch.dict(consul_pillar.__salt__, {"grains.get": MagicMock(return_value={})}): with patch.object( consul_pillar, "consul_fetch", @@ -104,9 +98,7 @@ def test_blank_root(base_pillar_data): def test_pillar_nest(base_pillar_data): - with patch.dict( - consul_pillar.__salt__, {"grains.get": MagicMock(return_value=({}))} - ): + with patch.dict(consul_pillar.__salt__, {"grains.get": MagicMock(return_value={})}): with patch.object( consul_pillar, "consul_fetch", @@ -122,9 +114,7 @@ def test_pillar_nest(base_pillar_data): def test_value_parsing(base_pillar_data): - with patch.dict( - consul_pillar.__salt__, {"grains.get": MagicMock(return_value=({}))} - ): + with patch.dict(consul_pillar.__salt__, {"grains.get": MagicMock(return_value={})}): with patch.object( consul_pillar, "consul_fetch", @@ -137,9 +127,7 @@ def test_value_parsing(base_pillar_data): def test_non_expansion(base_pillar_data): - with patch.dict( - consul_pillar.__salt__, {"grains.get": MagicMock(return_value=({}))} - ): + with patch.dict(consul_pillar.__salt__, {"grains.get": MagicMock(return_value={})}): with patch.object( consul_pillar, "consul_fetch", diff --git a/tests/pytests/unit/proxy/test_napalm.py b/tests/pytests/unit/proxy/test_napalm.py index f93279af900..2a537b8d61e 100644 --- a/tests/pytests/unit/proxy/test_napalm.py +++ b/tests/pytests/unit/proxy/test_napalm.py @@ -276,7 +276,7 @@ def test_grains_refresh(test_opts): def test_fns(): ret = napalm_proxy.fns() - assert "details" in ret.keys() + assert "details" in ret def test_shutdown(test_opts): diff --git a/tests/pytests/unit/runners/test_asam.py b/tests/pytests/unit/runners/test_asam.py index 285138781b7..2f2f7d7e786 100644 --- a/tests/pytests/unit/runners/test_asam.py +++ b/tests/pytests/unit/runners/test_asam.py @@ -44,6 +44,7 @@ def test_add_platform(): auth=("TheUsername", "ThePassword"), data={"manual": "false"}, verify=True, + timeout=120, ) @@ -69,6 +70,7 @@ def test_remove_platform(): "Submit": "Yes", }, verify=True, + timeout=120, ) @@ -88,6 +90,7 @@ def test_list_platforms(): auth=("TheUsername", "ThePassword"), data={"manual": "false"}, verify=True, + timeout=120, ) @@ -107,4 +110,5 @@ def test_list_platform_sets(): auth=("TheUsername", "ThePassword"), data={"manual": "false"}, verify=True, + timeout=120, ) diff --git a/tests/pytests/unit/runners/vault/test_app_role_auth.py b/tests/pytests/unit/runners/vault/test_app_role_auth.py index 241da179a37..14d5dc77ef7 100644 --- a/tests/pytests/unit/runners/vault/test_app_role_auth.py +++ b/tests/pytests/unit/runners/vault/test_app_role_auth.py @@ -73,7 +73,14 @@ def test_generate_token(): headers=ANY, json=ANY, verify=ANY, + timeout=120, + ), + call( + "http://fake_url", + headers=ANY, + json=ANY, + verify=ANY, + timeout=120, ), - call("http://fake_url", headers=ANY, json=ANY, verify=ANY), ] mock.assert_has_calls(calls) diff --git a/tests/pytests/unit/runners/vault/test_token_auth.py b/tests/pytests/unit/runners/vault/test_token_auth.py index 60307dc0955..fcd0ef8058b 100644 --- a/tests/pytests/unit/runners/vault/test_token_auth.py +++ b/tests/pytests/unit/runners/vault/test_token_auth.py @@ -68,7 +68,9 @@ def test_generate_token(): assert "error" not in result assert "token" in result assert result["token"] == "test" - mock.assert_called_with("http://fake_url", headers=ANY, json=ANY, verify=ANY) + mock.assert_called_with( + "http://fake_url", headers=ANY, json=ANY, verify=ANY, timeout=120 + ) # Test uses num_uses = 6 @@ -85,7 +87,11 @@ def test_generate_token(): }, } mock.assert_called_with( - "http://fake_url", headers=ANY, json=json_request, verify=ANY + "http://fake_url", + headers=ANY, + json=json_request, + verify=ANY, + timeout=120, ) # Test ttl @@ -103,7 +109,7 @@ def test_generate_token(): }, } mock.assert_called_with( - "http://fake_url", headers=ANY, json=json_request, verify=ANY + "http://fake_url", headers=ANY, json=json_request, verify=ANY, timeout=120 ) mock = _mock_json_response({}, status_code=403, reason="no reason") @@ -152,4 +158,5 @@ def test_generate_token_with_namespace(): }, json=ANY, verify=ANY, + timeout=120, ) diff --git a/tests/pytests/unit/serializers/test_serializers.py b/tests/pytests/unit/serializers/test_serializers.py index 0f3125c89e3..2d46f320b82 100644 --- a/tests/pytests/unit/serializers/test_serializers.py +++ b/tests/pytests/unit/serializers/test_serializers.py @@ -284,12 +284,12 @@ def test_sls_repr(): sls_obj = convert(OrderedDict([("foo", "bar"), ("baz", "qux")])) # ensure that repr and str are yaml friendly - assert sls_obj.__str__() == "{foo: bar, baz: qux}" - assert sls_obj.__repr__() == "{foo: bar, baz: qux}" + assert str(sls_obj) == "{foo: bar, baz: qux}" + assert repr(sls_obj) == "{foo: bar, baz: qux}" # ensure that repr and str are already quoted - assert sls_obj["foo"].__str__() == '"bar"' - assert sls_obj["foo"].__repr__() == '"bar"' + assert str(sls_obj["foo"]) == '"bar"' + assert repr(sls_obj["foo"]) == '"bar"' @pytest.mark.skipif(yamlex.available is False, reason=SKIP_MESSAGE.format("sls")) diff --git a/tests/pytests/unit/state/test_state_compiler.py b/tests/pytests/unit/state/test_state_compiler.py index db91a0109d7..4bf8f4f751a 100644 --- a/tests/pytests/unit/state/test_state_compiler.py +++ b/tests/pytests/unit/state/test_state_compiler.py @@ -11,7 +11,6 @@ import salt.state import salt.utils.files import salt.utils.platform from salt.exceptions import CommandExecutionError -from salt.utils.odict import OrderedDict from tests.support.mock import MagicMock, patch log = logging.getLogger(__name__) @@ -56,21 +55,21 @@ def test_render_error_on_invalid_requisite(minion_opts): """ with patch("salt.state.State._gather_pillar"): high_data = { - "git": OrderedDict( + "git": salt.state.HashableOrderedDict( [ ( "pkg", [ - OrderedDict( + salt.state.HashableOrderedDict( [ ( "require", [ - OrderedDict( + salt.state.HashableOrderedDict( [ ( "file", - OrderedDict( + salt.state.HashableOrderedDict( [("test1", "test")] ), ) @@ -89,7 +88,9 @@ def test_render_error_on_invalid_requisite(minion_opts): ] ) } - minion_opts["pillar"] = {"git": OrderedDict([("test1", "test")])} + minion_opts["pillar"] = { + "git": salt.state.HashableOrderedDict([("test1", "test")]) + } state_obj = salt.state.State(minion_opts) with pytest.raises(salt.exceptions.SaltRenderError): state_obj.call_high(high_data) @@ -720,13 +721,22 @@ def test_render_requisite_require_disabled(minion_opts): """ with patch("salt.state.State._gather_pillar"): high_data = { - "step_one": OrderedDict( + "step_one": salt.state.HashableOrderedDict( [ ( "test", [ - OrderedDict( - [("require", [OrderedDict([("test", "step_two")])])] + salt.state.HashableOrderedDict( + [ + ( + "require", + [ + salt.state.HashableOrderedDict( + [("test", "step_two")] + ) + ], + ) + ] ), "succeed_with_changes", {"order": 10000}, @@ -764,16 +774,20 @@ def test_render_requisite_require_in_disabled(minion_opts): "__env__": "base", "__sls__": "test.disable_require_in", }, - "step_two": OrderedDict( + "step_two": salt.state.HashableOrderedDict( [ ( "test", [ - OrderedDict( + salt.state.HashableOrderedDict( [ ( "require_in", - [OrderedDict([("test", "step_one")])], + [ + salt.state.HashableOrderedDict( + [("test", "step_one")] + ) + ], ) ] ), @@ -974,7 +988,7 @@ def test_mod_aggregate(minion_opts): "__sls__": "test.62439", "__env__": "base", "__id__": "sl", - "require_in": [OrderedDict([("file", "/tmp/foo")])], + "require_in": [salt.state.HashableOrderedDict([("file", "/tmp/foo")])], "order": 10002, "aggregate": True, "fun": "installed", @@ -1000,7 +1014,7 @@ def test_mod_aggregate(minion_opts): "__env__": "base", "__id__": "figlet", "__agg__": True, - "require": [OrderedDict([("file", "/tmp/foo")])], + "require": [salt.state.HashableOrderedDict([("file", "/tmp/foo")])], "order": 10001, "aggregate": True, "fun": "installed", @@ -1011,7 +1025,7 @@ def test_mod_aggregate(minion_opts): "__sls__": "test.62439", "__env__": "base", "__id__": "sl", - "require_in": [OrderedDict([("file", "/tmp/foo")])], + "require_in": [salt.state.HashableOrderedDict([("file", "/tmp/foo")])], "order": 10002, "aggregate": True, "fun": "installed", @@ -1026,7 +1040,7 @@ def test_mod_aggregate(minion_opts): "__sls__": "test.62439", "__env__": "base", "__id__": "sl", - "require_in": [OrderedDict([("file", "/tmp/foo")])], + "require_in": [salt.state.HashableOrderedDict([("file", "/tmp/foo")])], "order": 10002, "fun": "installed", "__agg__": True, @@ -1045,7 +1059,9 @@ def test_mod_aggregate(minion_opts): assert "require_in" in low_ret # Ensure all the requires from pkg states are in low - assert low_ret["require_in"] == [OrderedDict([("file", "/tmp/foo")])] + assert low_ret["require_in"] == [ + salt.state.HashableOrderedDict([("file", "/tmp/foo")]) + ] # Ensure that the require requisite from the # figlet state doesn't find its way into this state @@ -1190,7 +1206,7 @@ def test_load_modules_list(minion_opts): "__sls__": "test", "__env__": "base", "__id__": "nginx", - "provider": [OrderedDict([("cmd", "cmdmod")])], + "provider": [salt.state.HashableOrderedDict([("cmd", "cmdmod")])], "order": 10000, "fun": "installed", } @@ -1215,7 +1231,7 @@ def test_load_modules_dict(minion_opts): "__sls__": "test", "__env__": "base", "__id__": "nginx", - "provider": OrderedDict([("cmd", "test")]), + "provider": salt.state.HashableOrderedDict([("cmd", "test")]), "order": 10000, "fun": "installed", } diff --git a/tests/pytests/unit/states/test_host.py b/tests/pytests/unit/states/test_host.py index 3a3ab022a02..92e7c5f0a67 100644 --- a/tests/pytests/unit/states/test_host.py +++ b/tests/pytests/unit/states/test_host.py @@ -259,11 +259,7 @@ def test_present(): ): ret = host.present(hostname, ip_str) assert ret["result"] is True - assert ( - ret["comment"] - == "Host {} ({}) already present".format(hostname, ip_str) - in ret["comment"] - ) + assert "Host {} ({}) already present".format(hostname, ip_str) in ret["comment"] assert ret["changes"] == {}, ret["changes"] assert add_host.mock_calls == [], add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls diff --git a/tests/pytests/unit/transport/test_zeromq.py b/tests/pytests/unit/transport/test_zeromq.py index 97d65a204ad..ec93a72439e 100644 --- a/tests/pytests/unit/transport/test_zeromq.py +++ b/tests/pytests/unit/transport/test_zeromq.py @@ -616,7 +616,7 @@ def test_req_server_chan_encrypt_v2(pki_dir): if HAS_M2: aes = key.private_decrypt(ret["key"], RSA.pkcs1_oaep_padding) else: - cipher = PKCS1_OAEP.new(key) + cipher = PKCS1_OAEP.new(key) # pylint: disable=used-before-assignment aes = cipher.decrypt(ret["key"]) pcrypt = salt.crypt.Crypticle(opts, aes) signed_msg = pcrypt.loads(ret[dictkey]) @@ -1541,7 +1541,7 @@ async def test_unclosed_request_client(minion_opts, io_loop): try: assert client._closing is False with pytest.warns(salt.transport.base.TransportWarning): - client.__del__() + client.__del__() # pylint: disable=unnecessary-dunder-call finally: client.close() @@ -1557,6 +1557,6 @@ async def test_unclosed_publish_client(minion_opts, io_loop): try: assert client._closing is False with pytest.warns(salt.transport.base.TransportWarning): - client.__del__() + client.__del__() # pylint: disable=unnecessary-dunder-call finally: client.close() diff --git a/tests/pytests/unit/utils/test_cloud.py b/tests/pytests/unit/utils/test_cloud.py index 0bfe6d28ce6..7edce2000af 100644 --- a/tests/pytests/unit/utils/test_cloud.py +++ b/tests/pytests/unit/utils/test_cloud.py @@ -59,18 +59,18 @@ def create_class(tmp_path): def set_password( self, servicename, username, password - ): # pylint: disable=arguments-differ + ): # pylint: disable=arguments-differ,arguments-renamed self.__storage.setdefault(servicename, {}).update({username: password}) return 0 def get_password( self, servicename, username - ): # pylint: disable=arguments-differ + ): # pylint: disable=arguments-differ,arguments-renamed return self.__storage.setdefault(servicename, {}).get(username) def delete_password( self, servicename, username - ): # pylint: disable=arguments-differ + ): # pylint: disable=arguments-differ,arguments-renamed self.__storage.setdefault(servicename, {}).pop(username, None) return 0 @@ -249,6 +249,7 @@ def test_run_psexec_command_cleanup_lingering_paexec(caplog): "MermaidMan", "BarnicleBoy", ) + # pylint: disable=no-value-for-parameter mock_client.return_value.cleanup = MagicMock(side_effect=CannotDelete()) cloud.run_psexec_command( @@ -475,7 +476,7 @@ def test_winrm_pinnned_version(): ): try: - import winrm + import winrm # pylint: disable=unused-import except ImportError: raise pytest.skip('The "winrm" python module is not installed in this env.') else: diff --git a/tests/pytests/unit/utils/test_data.py b/tests/pytests/unit/utils/test_data.py index 5614a770316..e6a6cdd6185 100644 --- a/tests/pytests/unit/utils/test_data.py +++ b/tests/pytests/unit/utils/test_data.py @@ -14,8 +14,13 @@ from tests.support.unit import LOREM_IPSUM log = logging.getLogger(__name__) -_b = lambda x: x.encode("utf-8") -_s = lambda x: salt.utils.stringutils.to_str(x, normalize=True) + +def _b(x): + return x.encode("utf-8") + + +def _s(x): + return salt.utils.stringutils.to_str(x, normalize=True) @pytest.fixture @@ -566,7 +571,9 @@ def test_encode(get_test_data, get_BYTES, get_EGGS): None, [True, _b(get_EGGS), get_BYTES], ] - expected[11][_b("subdict")][_b("tuple")] = [ + expected[11][_b("subdict")][ # pylint: disable=unsupported-assignment-operation + _b("tuple") + ] = [ 123, _b("hello"), _b("world"), diff --git a/tests/pytests/unit/utils/test_vault.py b/tests/pytests/unit/utils/test_vault.py index 9e3dfe59f16..af755cadd4b 100644 --- a/tests/pytests/unit/utils/test_vault.py +++ b/tests/pytests/unit/utils/test_vault.py @@ -301,6 +301,7 @@ def test_make_request_single_use_token_run_ok(json_success, cache_single): "http://127.0.0.1:8200/key", headers=expected_headers, verify=ANY, + timeout=ANY, ) assert vault_return.json() == json_success @@ -324,6 +325,7 @@ def test_make_request_single_use_token_run_auth_error(json_denied, cache_single) "http://127.0.0.1:8200/key", headers=expected_headers, verify=ANY, + timeout=ANY, ) assert vault_return.json() == json_denied mock_del_cache.assert_called() @@ -358,6 +360,7 @@ def test_multi_use_token_successful_run(json_success, cache_uses): "http://127.0.0.1:8200/key", headers=expected_headers, verify=ANY, + timeout=ANY, ) mock_write_cache.assert_called_with(expected_cache_write) assert vault_return.json() == json_success @@ -381,6 +384,7 @@ def test_multi_use_token_last_use(json_success, cache_uses_last): "http://127.0.0.1:8200/key", headers=expected_headers, verify=ANY, + timeout=ANY, ) mock_del_cache.assert_called() assert vault_return.json() == json_success @@ -404,6 +408,7 @@ def test_unlimited_use_token_no_decrement(json_success, cache_unlimited): "http://127.0.0.1:8200/key", headers=expected_headers, verify=ANY, + timeout=ANY, ) assert ( not mock_del_cache.called @@ -508,6 +513,7 @@ def test_request_with_namespace(json_success, cache_single_namespace): "http://127.0.0.1:8200/key", headers=expected_headers, verify=ANY, + timeout=ANY, ) assert vault_return.json() == json_success diff --git a/tests/pytests/unit/utils/test_vt.py b/tests/pytests/unit/utils/test_vt.py index c31b25e623c..692bbf76f61 100644 --- a/tests/pytests/unit/utils/test_vt.py +++ b/tests/pytests/unit/utils/test_vt.py @@ -51,6 +51,6 @@ def test_log_sanitize(test_cmd, caplog): stream_stderr=False, ) with caplog.at_level(logging.DEBUG): - ret = term.recv() + term.recv() assert password not in caplog.text assert "******" in caplog.text diff --git a/tests/pytests/unit/wheel/test_file_roots.py b/tests/pytests/unit/wheel/test_file_roots.py index 5c8c54f23a5..4da2f359f2c 100644 --- a/tests/pytests/unit/wheel/test_file_roots.py +++ b/tests/pytests/unit/wheel/test_file_roots.py @@ -17,7 +17,7 @@ def _make_temp_root_file(root, *subpaths, binary=False, dir_only=False): full_path.write_bytes(content) else: content = str(full_path) - full_path.write_text(content) + full_path.write_text(content, encoding="utf-8") @pytest.fixture diff --git a/tests/salt-tcpdump.py b/tests/salt-tcpdump.py index 4a92966132b..c16e98a20e6 100644 --- a/tests/salt-tcpdump.py +++ b/tests/salt-tcpdump.py @@ -34,7 +34,7 @@ tcpdump "tcp[tcpflags] & tcp-syn != 0" and port 4506 and "tcp[tcpflags] & tcp-ac """ # pylint: disable=resource-leakage -import argparse # pylint: disable=minimum-python-version +import argparse import socket import sys import time @@ -124,7 +124,7 @@ class PCAPParser: packet_data = {"ip": {}, "tcp": {}} - (header, packet) = cap.next() # pylint: disable=incompatible-py3-code + (header, packet) = cap.next() eth_length, eth_protocol = self.parse_ether(packet) @@ -232,7 +232,7 @@ class SaltNetstat: """ Read the table of tcp connections & remove header """ - with open("/proc/net/tcp") as tcp_f: + with open("/proc/net/tcp", encoding="utf-8") as tcp_f: content = tcp_f.readlines() content.pop(0) return content diff --git a/tests/saltsh.py b/tests/saltsh.py index 64ace99cc3b..de87f55d9e7 100644 --- a/tests/saltsh.py +++ b/tests/saltsh.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -'''\ +''' Welcome to the Salt repl which exposes the execution environment of a minion in a pre-configured Python shell @@ -91,9 +91,11 @@ def get_salt_vars(): __pillar__ = {} # pylint: disable=invalid-name,unused-variable,possibly-unused-variable - JINJA = lambda x, **y: jinja2.Template(x).render( - grains=__grains__, salt=__salt__, opts=__opts__, pillar=__pillar__, **y - ) + def JINJA(x, **y): + return jinja2.Template(x).render( + grains=__grains__, salt=__salt__, opts=__opts__, pillar=__pillar__, **y + ) + # pylint: enable=invalid-name,unused-variable,possibly-unused-variable return locals() diff --git a/tests/support/copyartifacts.py b/tests/support/copyartifacts.py index a3054d80931..b0e5382a07f 100644 --- a/tests/support/copyartifacts.py +++ b/tests/support/copyartifacts.py @@ -2,7 +2,7 @@ Script for copying back xml junit files from tests """ -import argparse # pylint: disable=minimum-python-version +import argparse import os import subprocess @@ -19,13 +19,12 @@ class DownloadArtifacts: self.sftpclient = paramiko.SFTPClient.from_transport(self.transport) def setup_transport(self): - # pylint: disable=minimum-python-version + config = salt.utils.yaml.safe_load( subprocess.check_output( ["bundle", "exec", "kitchen", "diagnose", self.instance] ) ) - # pylint: enable=minimum-python-version state = config["instances"][self.instance]["state_file"] tport = config["instances"][self.instance]["transport"] transport = paramiko.Transport( @@ -44,9 +43,7 @@ class DownloadArtifacts: Make sure all xml files are readable by the world so that anyone can grab them """ for remote, _ in self.artifacts: - self.transport.open_session().exec_command( - "sudo chmod -R +r {}".format(remote) - ) + self.transport.open_session().exec_command(f"sudo chmod -R +r {remote}") def download(self): self._set_permissions() @@ -61,11 +58,11 @@ class DownloadArtifacts: self._do_download(remote, os.path.join(local, os.path.basename(remote))) def _do_download(self, remote, local): - print("Copying from {} to {}".format(remote, local)) + print(f"Copying from {remote} to {local}") try: self.sftpclient.get(remote, local) except OSError: - print("Failed to copy: {}".format(remote)) + print(f"Failed to copy: {remote}") if __name__ == "__main__": diff --git a/tests/support/generate-names-file-from-failed-test-reports.py b/tests/support/generate-names-file-from-failed-test-reports.py index ac4b13b2fe8..e565f335cf4 100644 --- a/tests/support/generate-names-file-from-failed-test-reports.py +++ b/tests/support/generate-names-file-from-failed-test-reports.py @@ -43,7 +43,7 @@ def main(): failures = set() for fname in sorted(glob.glob(os.path.join(options.reports_dir, "*.xml"))): total_xml_reports += 1 - with open(fname) as rfh: + with open(fname, encoding="utf-8") as rfh: test_suite, test_result = xunitparser.parse(rfh) if not test_result.errors and not test_result.failures: continue @@ -54,7 +54,7 @@ def main(): if not total_xml_reports: parser.exit(status=1, message="No JUnit XML files were parsed") - with open(options.output_file, "w") as wfh: + with open(options.output_file, "w", encoding="utf-8") as wfh: wfh.write(os.linesep.join(sorted(failures))) parser.exit(status=0) diff --git a/tests/support/pkg.py b/tests/support/pkg.py index 3d0e086e077..57feac63855 100644 --- a/tests/support/pkg.py +++ b/tests/support/pkg.py @@ -256,7 +256,7 @@ class SaltPkgInstall: self.install_dir / "salt-minion.exe" ).exists() and not self.relenv: log.debug( - f"Removing {(self.install_dir / 'salt-minion.exe')}" + "Removing %s", self.install_dir / "salt-minion.exe" ) (self.install_dir / "salt-minion.exe").unlink() @@ -640,7 +640,8 @@ class SaltPkgInstall: Pin: origin "repo.saltproject.io" Pin-Priority: 1001 """ - ) + ), + encoding="utf-8", ) cmd.append("--allow-downgrades") env = os.environ.copy() @@ -1487,7 +1488,7 @@ class ApiRequest: @pytest.helpers.register def download_file(url, dest, auth=None): # NOTE the stream=True parameter below - with requests.get(url, stream=True, auth=auth) as r: + with requests.get(url, stream=True, auth=auth, timeout=60) as r: r.raise_for_status() with salt.utils.files.fopen(dest, "wb") as f: for chunk in r.iter_content(chunk_size=8192): diff --git a/tests/support/pytest/etcd.py b/tests/support/pytest/etcd.py index 6606e9436b8..7bcc44fda03 100644 --- a/tests/support/pytest/etcd.py +++ b/tests/support/pytest/etcd.py @@ -59,7 +59,9 @@ def confirm_container_started(timeout_at, container): sleeptime = 1 while time.time() <= timeout_at: try: - response = requests.get("http://localhost:{}/version".format(etcd_port)) + response = requests.get( + "http://localhost:{}/version".format(etcd_port), timeout=60 + ) try: version = response.json() if "etcdserver" in version: diff --git a/tests/support/pytest/helpers.py b/tests/support/pytest/helpers.py index fa12784c04e..e6752ee7070 100644 --- a/tests/support/pytest/helpers.py +++ b/tests/support/pytest/helpers.py @@ -706,13 +706,17 @@ class EntropyGenerator: log.info("The '%s' file is not avilable", kernel_entropy_file) return - self.current_entropy = int(kernel_entropy_file.read_text().strip()) + self.current_entropy = int( + kernel_entropy_file.read_text(encoding="utf-8").strip() + ) log.info("Available Entropy: %s", self.current_entropy) if not kernel_poolsize_file.exists(): log.info("The '%s' file is not avilable", kernel_poolsize_file) else: - self.current_poolsize = int(kernel_poolsize_file.read_text().strip()) + self.current_poolsize = int( + kernel_poolsize_file.read_text(encoding="utf-8").strip() + ) log.info("Entropy Poolsize: %s", self.current_poolsize) # Account for smaller poolsizes using BLAKE2s if self.current_poolsize == 256: @@ -738,7 +742,9 @@ class EntropyGenerator: raise pytest.skip.Exception(message, _use_item_location=True) raise pytest.fail(message) subprocess.run([rngd, "-r", "/dev/urandom"], shell=False, check=True) - self.current_entropy = int(kernel_entropy_file.read_text().strip()) + self.current_entropy = int( + kernel_entropy_file.read_text(encoding="utf-8").strip() + ) log.info("Available Entropy: %s", self.current_entropy) if self.current_entropy >= self.minimum_entropy: break @@ -773,7 +779,9 @@ class EntropyGenerator: check=True, ) os.unlink(target_file.name) - self.current_entropy = int(kernel_entropy_file.read_text().strip()) + self.current_entropy = int( + kernel_entropy_file.read_text(encoding="utf-8").strip() + ) log.info("Available Entropy: %s", self.current_entropy) if self.current_entropy >= self.minimum_entropy: break diff --git a/tests/support/unit.py b/tests/support/unit.py index dc1051ea773..419e287b92f 100644 --- a/tests/support/unit.py +++ b/tests/support/unit.py @@ -158,7 +158,6 @@ class TestLoader(_TestLoader): class TestCase(_TestCase): - # pylint: disable=expected-an-indented-block-comment,too-many-leading-hastag-for-block-comment ## Commented out because it may be causing tests to hang ## at the end of the run # @@ -178,7 +177,6 @@ class TestCase(_TestCase): # print('\nWARNING: A misbehaving test has modified the working directory!\nThe test suite has reset the working directory ' # 'on tearDown() to {0}\n'.format(cls._cwd)) # cls._chdir_counter += 1 - # pylint: enable=expected-an-indented-block-comment,too-many-leading-hastag-for-block-comment def run(self, result=None): self._prerun_instance_attributes = dir(self) @@ -225,7 +223,7 @@ class TestCase(_TestCase): found_zombies += 1 except Exception: # pylint: disable=broad-except pass - proc_info += "|Z:{}".format(found_zombies) + proc_info += f"|Z:{found_zombies}" proc_info += "] {short_desc}".format(short_desc=desc if desc else "") return proc_info else: diff --git a/tests/support/win_installer.py b/tests/support/win_installer.py index 6a2f387dc84..65d39a40d1a 100644 --- a/tests/support/win_installer.py +++ b/tests/support/win_installer.py @@ -29,12 +29,15 @@ def download_and_verify(fp, name, repo=REPO): Download an installer and verify its contents. """ md5 = "{}.md5".format(name) - url = lambda x: "{}/{}".format(repo, x) - resp = requests.get(url(md5)) + + def url(x): + return "{}/{}".format(repo, x) + + resp = requests.get(url(md5), timeout=60) if resp.status_code != 200: raise Exception("Unable to fetch installer md5") installer_md5 = resp.text.strip().split()[0].lower() - resp = requests.get(url(name), stream=True) + resp = requests.get(url(name), stream=True, timeout=60) if resp.status_code != 200: raise Exception("Unable to fetch installer") md5hsh = hashlib.md5() diff --git a/tests/unit/ext/test_ipaddress.py b/tests/unit/ext/test_ipaddress.py index e4b2f98c357..474d05192fc 100644 --- a/tests/unit/ext/test_ipaddress.py +++ b/tests/unit/ext/test_ipaddress.py @@ -13,7 +13,7 @@ """Unittest for ipaddress module.""" -# pylint: disable=string-substitution-usage-error,pointless-statement,abstract-method,cell-var-from-loop +# pylint: disable=pointless-statement,abstract-method,cell-var-from-loop,unnecessary-dunder-call import contextlib import functools @@ -312,7 +312,7 @@ class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): def test_invalid_characters(self): def assertBadOctet(addr, octet): - msg = "Only decimal digits permitted in {!r} in {!r}".format(octet, addr) + msg = f"Only decimal digits permitted in {octet!r} in {addr!r}" with self.assertAddressError(re.escape(msg)): ipaddress.IPv4Address(addr) @@ -657,7 +657,7 @@ class NetmaskTestMixin_v4(CommonTestMixin_v4): def assertBadNetmask(addr, netmask): msg = "%r is not a valid netmask" % netmask with self.assertNetmaskError(re.escape(msg)): - self.factory("{}/{}".format(addr, netmask)) + self.factory(f"{addr}/{netmask}") assertBadNetmask("1.2.3.4", "") assertBadNetmask("1.2.3.4", "-1") @@ -827,7 +827,7 @@ class NetmaskTestMixin_v6(CommonTestMixin_v6): def assertBadNetmask(addr, netmask): msg = "%r is not a valid netmask" % netmask with self.assertNetmaskError(re.escape(msg)): - self.factory("{}/{}".format(addr, netmask)) + self.factory(f"{addr}/{netmask}") assertBadNetmask("::1", "") assertBadNetmask("::1", "::1") diff --git a/tests/unit/modules/test_elasticsearch.py b/tests/unit/modules/test_elasticsearch.py index fc073f54d4d..4ab515e7d46 100644 --- a/tests/unit/modules/test_elasticsearch.py +++ b/tests/unit/modules/test_elasticsearch.py @@ -9,18 +9,14 @@ from salt.modules import elasticsearch from tests.support.mock import MagicMock, patch from tests.support.unit import TestCase -# Import elasticsearch exceptions -NO_ELASTIC = False -try: - from elasticsearch import NotFoundError, TransportError -except Exception: # pylint: disable=broad-except - NO_ELASTIC = True - - -@pytest.mark.skipif( - NO_ELASTIC, +_es_module = pytest.importorskip( + "elasticsearch", reason="Install elasticsearch-py before running Elasticsearch unit tests.", ) +NotFoundError = _es_module.NotFoundError +TransportError = _es_module.TransportError + + class ElasticsearchTestCase(TestCase): """ Test cases for salt.modules.elasticsearch diff --git a/tests/unit/modules/test_sysmod.py b/tests/unit/modules/test_sysmod.py index 00185a90099..125f17d8606 100644 --- a/tests/unit/modules/test_sysmod.py +++ b/tests/unit/modules/test_sysmod.py @@ -113,15 +113,17 @@ class SysmodTestCase(TestCase, LoaderModuleMockMixin): cls.salt_dunder[func] = MockDocstringable(docstring) cls._docstrings[func] = docstring - module = func.split(".")[0] + module = func.split(".", maxsplit=1)[0] cls._statedocstrings[func] = docstring cls._statedocstrings[module] = "docstring for {}".format(module) - cls._modules.add(func.split(".")[0]) + cls._modules.add(func.split(".", maxsplit=1)[0]) docstring = "docstring for {}".format(func) mock = MockDocstringable(docstring) - mock.set_module_docstring("docstring for {}".format(func.split(".")[0])) + mock.set_module_docstring( + "docstring for {}".format(func.split(".", maxsplit=1)[0]) + ) Mockstate.State.states[func] = mock cls._modules = sorted(list(cls._modules)) diff --git a/tests/unit/modules/test_zcbuildout.py b/tests/unit/modules/test_zcbuildout.py index db7a862f727..b26fac3a928 100644 --- a/tests/unit/modules/test_zcbuildout.py +++ b/tests/unit/modules/test_zcbuildout.py @@ -116,7 +116,7 @@ class Base(TestCase, LoaderModuleMockMixin): def setUp(self): if salt.utils.platform.is_darwin(): self.patched_environ = patched_environ(__cleanup__=["__PYVENV_LAUNCHER__"]) - self.patched_environ.__enter__() + self.patched_environ.__enter__() # pylint: disable=unnecessary-dunder-call self.addCleanup(self.patched_environ.__exit__) super().setUp() @@ -490,8 +490,8 @@ class BuildoutOnlineTestCase(Base): out = ret["out"] comment = ret["comment"] self.assertTrue(ret["status"]) - self.assertTrue("Creating directory" in out) - self.assertTrue("Installing a." in out) + self.assertIn("Creating directory", out) + self.assertIn("Installing a.", out) self.assertTrue("{} bootstrap.py".format(self.py_st) in comment) self.assertTrue("buildout -c buildout.cfg" in comment) ret = buildout.buildout( @@ -500,17 +500,17 @@ class BuildoutOnlineTestCase(Base): outlog = ret["outlog"] out = ret["out"] comment = ret["comment"] - self.assertTrue("Installing single part: a" in outlog) - self.assertTrue("buildout -c buildout.cfg -N install a" in comment) - self.assertTrue("Installing b." in out) - self.assertTrue("Installing c." in out) + self.assertIn("Installing single part: a", outlog) + self.assertIn("buildout -c buildout.cfg -N install a", comment) + self.assertIn("Installing b.", out) + self.assertIn("Installing c.", out) ret = buildout.buildout( b_dir, parts=["a", "b", "c"], buildout_ver=2, newest=True, python=self.py_st ) outlog = ret["outlog"] out = ret["out"] comment = ret["comment"] - self.assertTrue("buildout -c buildout.cfg -n install a" in comment) + self.assertIn("buildout -c buildout.cfg -n install a", comment) # TODO: Is this test even still needed? @@ -537,8 +537,8 @@ class BuildoutAPITestCase(TestCase): out = ret["out"].decode("utf-8") for out in ["àé", "ççàé"]: - self.assertTrue(out in uretm["logs_by_level"]["info"]) - self.assertTrue(out in uretm["outlog_by_level"]) + self.assertIn(out, uretm["logs_by_level"]["info"]) + self.assertIn(out, uretm["outlog_by_level"]) def test_setup(self): buildout.LOG.clear() diff --git a/tests/unit/states/test_loop.py b/tests/unit/states/test_loop.py index ba100dfe663..ea3b0989d97 100644 --- a/tests/unit/states/test_loop.py +++ b/tests/unit/states/test_loop.py @@ -294,9 +294,7 @@ class LoopTestCaseNoEval(TestCase, LoaderModuleMockMixin): """ with patch.dict( salt.states.loop.__salt__, # pylint: disable=no-member - { - "foo.bar": MagicMock(side_effect=range(1, 7)) - }, # pylint: disable=incompatible-py3-code + {"foo.bar": MagicMock(side_effect=range(1, 7))}, ): self.assertDictEqual( salt.states.loop.until( @@ -312,9 +310,7 @@ class LoopTestCaseNoEval(TestCase, LoaderModuleMockMixin): with patch.dict( salt.states.loop.__salt__, # pylint: disable=no-member - { - "foo.bar": MagicMock(side_effect=range(1, 7)) - }, # pylint: disable=incompatible-py3-code + {"foo.bar": MagicMock(side_effect=range(1, 7))}, ): self.assertDictEqual( salt.states.loop.until_no_eval( @@ -334,9 +330,7 @@ class LoopTestCaseNoEval(TestCase, LoaderModuleMockMixin): """ with patch.dict( salt.states.loop.__salt__, # pylint: disable=no-member - { - "foo.bar": MagicMock(side_effect=range(1, 7)) - }, # pylint: disable=incompatible-py3-code + {"foo.bar": MagicMock(side_effect=range(1, 7))}, ): self.assertDictEqual( salt.states.loop.until( @@ -354,9 +348,7 @@ class LoopTestCaseNoEval(TestCase, LoaderModuleMockMixin): # returning a lower number of attempts (because it's slower). with patch.dict( salt.states.loop.__salt__, # pylint: disable=no-member - { - "foo.bar": MagicMock(side_effect=range(1, 7)) - }, # pylint: disable=incompatible-py3-code + {"foo.bar": MagicMock(side_effect=range(1, 7))}, ): self.assertDictEqual( salt.states.loop.until_no_eval( diff --git a/tests/unit/test_pillar.py b/tests/unit/test_pillar.py index b71c0e9a371..323d5660cfe 100644 --- a/tests/unit/test_pillar.py +++ b/tests/unit/test_pillar.py @@ -36,13 +36,13 @@ class MockFileclient: self.list_states = lambda *x, **y: list_states # pylint: disable=unused-argument,no-method-argument,method-hidden - def cache_file(*args, **kwargs): + def cache_file(self, *args, **kwargs): raise NotImplementedError() - def get_state(*args, **kwargs): + def get_state(self, *args, **kwargs): raise NotImplementedError() - def list_states(*args, **kwargs): + def list_states(self, *args, **kwargs): raise NotImplementedError() # pylint: enable=unused-argument,no-method-argument,method-hidden diff --git a/tests/unit/test_zypp_plugins.py b/tests/unit/test_zypp_plugins.py index 7bd248ffbd9..64bc86b49d3 100644 --- a/tests/unit/test_zypp_plugins.py +++ b/tests/unit/test_zypp_plugins.py @@ -1,7 +1,7 @@ """ :codeauthor: Bo Maryniuk """ -import imp +import imp # pylint: disable=deprecated-module import os import pytest diff --git a/tests/unit/utils/test_configparser.py b/tests/unit/utils/test_configparser.py index ab32ec992d9..d4d3a79ed3c 100644 --- a/tests/unit/utils/test_configparser.py +++ b/tests/unit/utils/test_configparser.py @@ -179,9 +179,7 @@ class TestGitConfigParser(TestCase): self.conf.write(fp_) # Confirm that the new file was written correctly expected = self.fix_indent(ORIG_CONFIG) - # pylint: disable=string-substitution-usage-error - expected.insert(6, "\tfetch = %s" % new_refspec) - # pylint: enable=string-substitution-usage-error + expected.insert(6, f"\tfetch = {new_refspec}") self.assertEqual(self.get_lines(self.new_config), expected) def test_remove_option(self): diff --git a/tests/unit/utils/test_context.py b/tests/unit/utils/test_context.py index abea69fbf62..8cdbb8d53c5 100644 --- a/tests/unit/utils/test_context.py +++ b/tests/unit/utils/test_context.py @@ -102,7 +102,7 @@ class ContextDictTests(AsyncTestCase): wait_iterator = salt.ext.tornado.gen.WaitIterator(*futures) while not wait_iterator.done(): - r = yield wait_iterator.next() # pylint: disable=incompatible-py3-code + r = yield wait_iterator.next() self.assertEqual(r[0], r[1]) # verify that the global value remails self.assertEqual(r[2], r[3]) # verify that the override sticks locally self.assertEqual( diff --git a/tests/unit/utils/test_dns.py b/tests/unit/utils/test_dns.py index 75ceeef1359..225f9811937 100644 --- a/tests/unit/utils/test_dns.py +++ b/tests/unit/utils/test_dns.py @@ -259,8 +259,8 @@ class DNSlookupsCase(TestCase): :param secure: delta cmd.run_all output for secured RESULTS """ # wrong - for wrong in wrong: - with self._mock_cmd_ret(wrong): + for _wrong in wrong: + with self._mock_cmd_ret(_wrong): self.assertEqual(lookup_cb("mockq", "A"), False) # empty response diff --git a/tests/unit/utils/test_systemd.py b/tests/unit/utils/test_systemd.py index 698a2337e5e..082076feba8 100644 --- a/tests/unit/utils/test_systemd.py +++ b/tests/unit/utils/test_systemd.py @@ -351,8 +351,6 @@ class SystemdTestCase(TestCase): Raised by DBUS, e.g. when a PID does not belong to a service """ - ... - dbus_mock = Mock() dbus_mock.DBusException = DBusException() dbus_mock.GetUnitByPID = Mock(site_effect=dbus_mock.DBusException) diff --git a/tests/unit/utils/test_thin.py b/tests/unit/utils/test_thin.py index 7fd1e7b5dc3..28f26824118 100644 --- a/tests/unit/utils/test_thin.py +++ b/tests/unit/utils/test_thin.py @@ -113,7 +113,8 @@ class SSHThinTestCase(TestCase): return popen - def _version_info(self, major=None, minor=None): + @staticmethod + def _version_info(major=None, minor=None): """ Fake version info. @@ -801,7 +802,7 @@ class SSHThinTestCase(TestCase): "salt.utils.thin.tempfile.mkstemp", MagicMock(return_value=(3, ".temporary")) ) @patch("salt.utils.thin.shutil", MagicMock()) - @patch("salt.utils.thin.sys.version_info", _version_info(None, 3, 6)) + @patch("salt.utils.thin.sys.version_info", _version_info(3, 6)) @patch("salt.utils.path.which", MagicMock(return_value="/usr/bin/python")) def test_gen_thin_compression_fallback_py3(self): """ @@ -852,7 +853,7 @@ class SSHThinTestCase(TestCase): "salt.utils.thin.tempfile.mkstemp", MagicMock(return_value=(3, ".temporary")) ) @patch("salt.utils.thin.shutil", MagicMock()) - @patch("salt.utils.thin.sys.version_info", _version_info(None, 3, 6)) + @patch("salt.utils.thin.sys.version_info", _version_info(3, 6)) @patch("salt.utils.path.which", MagicMock(return_value="/usr/bin/python")) def test_gen_thin_control_files_written_py3(self): """ @@ -905,7 +906,7 @@ class SSHThinTestCase(TestCase): "salt.utils.thin.tempfile.mkstemp", MagicMock(return_value=(3, ".temporary")) ) @patch("salt.utils.thin.shutil", MagicMock()) - @patch("salt.utils.thin.sys.version_info", _version_info(None, 3, 6)) + @patch("salt.utils.thin.sys.version_info", _version_info(3, 6)) @patch("salt.utils.hashutils.DigestCollector", MagicMock()) @patch("salt.utils.path.which", MagicMock(return_value="/usr/bin/python")) def test_gen_thin_main_content_files_written_py3(self): @@ -974,7 +975,7 @@ class SSHThinTestCase(TestCase): "salt.utils.thin.tempfile.mkstemp", MagicMock(return_value=(3, ".temporary")) ) @patch("salt.utils.thin.shutil", MagicMock()) - @patch("salt.utils.thin.sys.version_info", _version_info(None, 3, 6)) + @patch("salt.utils.thin.sys.version_info", _version_info(3, 6)) @patch("salt.utils.hashutils.DigestCollector", MagicMock()) @patch("salt.utils.path.which", MagicMock(return_value="/usr/bin/python")) def test_gen_thin_ext_alternative_content_files_written_py3(self): @@ -1087,7 +1088,7 @@ class SSHThinTestCase(TestCase): "salt.utils.thin.tempfile.mkstemp", MagicMock(return_value=(3, ".temporary")) ) @patch("salt.utils.thin.shutil", MagicMock()) - @patch("salt.utils.thin.sys.version_info", _version_info(None, 3, 6)) + @patch("salt.utils.thin.sys.version_info", _version_info(3, 6)) def test_gen_thin_control_files_written_access_denied_cwd(self): """ Test thin.gen_thin function if control files are written (version, salt-call etc) diff --git a/tests/wheeltest.py b/tests/wheeltest.py index 93880b0b9f3..1f661941a81 100644 --- a/tests/wheeltest.py +++ b/tests/wheeltest.py @@ -3,9 +3,7 @@ Test interacting with the wheel system. This script is useful when testing wheel modules """ - - -import optparse +import optparse # pylint: disable=deprecated-module import pprint import salt.auth diff --git a/tools/changelog.py b/tools/changelog.py index 8e9e3ff3e73..99c81c40082 100644 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -110,18 +110,18 @@ def update_rpm(ctx: Context, salt_version: Version, draft: bool = False): header = f"* {date} Salt Project Packaging - {str_salt_version}\n" parts = orig.split("%changelog") tmpspec = "pkg/rpm/salt.spec.1" - with open(tmpspec, "w") as wfp: + with open(tmpspec, "w", encoding="utf-8") as wfp: wfp.write(parts[0]) wfp.write("%changelog\n") wfp.write(header) wfp.write(changes) wfp.write(parts[1]) try: - with open(tmpspec) as rfp: + with open(tmpspec, encoding="utf-8") as rfp: if draft: ctx.info(rfp.read()) else: - with open("pkg/rpm/salt.spec", "w") as wfp: + with open("pkg/rpm/salt.spec", "w", encoding="utf-8") as wfp: wfp.write(rfp.read()) finally: os.remove(tmpspec) @@ -153,20 +153,20 @@ def update_deb(ctx: Context, salt_version: Version, draft: bool = False): tmpchanges = "pkg/rpm/salt.spec.1" debian_changelog_path = "pkg/debian/changelog" tmp_debian_changelog_path = f"{debian_changelog_path}.1" - with open(tmp_debian_changelog_path, "w") as wfp: + with open(tmp_debian_changelog_path, "w", encoding="utf-8") as wfp: wfp.write(f"salt ({salt_version}) stable; urgency=medium\n\n") wfp.write(formated) wfp.write( f"\n -- Salt Project Packaging {date}\n\n" ) - with open(debian_changelog_path) as rfp: + with open(debian_changelog_path, encoding="utf-8") as rfp: wfp.write(rfp.read()) try: - with open(tmp_debian_changelog_path) as rfp: + with open(tmp_debian_changelog_path, encoding="utf-8") as rfp: if draft: ctx.info(rfp.read()) else: - with open(debian_changelog_path, "w") as wfp: + with open(debian_changelog_path, "w", encoding="utf-8") as wfp: wfp.write(rfp.read()) finally: os.remove(tmp_debian_changelog_path) @@ -254,7 +254,7 @@ def update_release_notes( return unreleased = " - UNRELEASED" - warning = f""" + warning = """ z_$(H7Kf_+0p3gquLS}VVJ*&2H~$LOXDl4k5^d2IH4%? z^DllD0^BRtr2==*PfNC=eYP#!yPCUjYZTVC{JIyeH!+j>(v9h~6@_hDpS>dLlKI=G zd25~wa8)YNuh(KjFM(1tDz~|w*q8Vc?#j6zwyePiFm=0bpGh`5 zDX~Yv;3jSjzv}cL!JyU@QZc5u)qvsYq?SvI8LNo9$CjU3KNOZ_-@O)4-dnevTKA7X zMmRk0$P^J_f^sbqlC_JP#Q*YThpj#dNg4ny{eEYEpet(Xxs{;LcTWv@!Epw#-*Bpw z=z;?vDxrz6QHgSiQd0vAlau72@DpV#j~K)T=gYnBQ2p}imzo+a&4*rMo{z7KPLpN( zlZMHHw?2J*?{Om4YwE9k)NDYaA#kACuyjmgcX*FbJF7e^IJto`WapMY{aDQ?%I?JdSJ1r03+FBx~vH?E^-sq2`U#AQzS!b>F2U4-+5_Wtj z^=cU*cpGzM}o|@;K$?gyErJr*; z*-b<`{>4vns`QIC;&`!VR@Xjwe{Z;--JdA)9sBhA?#0}UioH~?AyEUN#51F7bDU0s zl8$2)GY8;;b1-{;ExGTMKf{eD{z@-cb99tDU>G%UV3Bj|-S@cn-0o>^Z}GeF3r=%f zjtRq6fL()hikt{I)#qQ1OyoiW@4r#o`~Gh(;{F?y3_|TU5KA%mYwm&Sy1^E=DmOrQ zp;)Y67c10__3Qle1_b-0j+RnWg!LK%iOkbbwxVulc!JJIVrycY5uBF0*Fe5=PRyyX zw>ED4&4<(*ijEh_Wm;Zls9@VRIbN#GiIERize`8R%P>urox0H6cmZgJ9b~Xma^PB_ zZwAh`kbtscOx;>yE4=tJW&j!Pvhv_VeBt-_%fue4;igQfQ1brSn<1zdLYEdP>wB7pKAOwZb=8hSt0 z_}c;MUM*}a@TY7%m{R97WPYGuG^cLzapYB<7~gC@HETDJt#n`e`;K*+QCwO($L;Ii z*Q8e0+Lo-Yp0376@}DIb25*l?w10Lg@_U_1iy+G`>N2Evd=X2zjT#omr~>eQYYMw{ zA!}-0sX@q6yc-rFi{HUPH^Z3#%ZKzZ+;4#>VfKk{Ce68fu&E=>ux^76QWLBk;QTq~ z*e6v9M`upDg9Hi8`FECl`$k2lq`(^v1}kR#=PAm9NPRjXknns|XGd~*_1dhC1}A+I z$EtgsmmxRuxcuwu^5tq-FvO?da!eP~pBkw(7V!IK7N9WJleJ`FN^yGoEfQ3jxHB{t zD1KQg%ZieZhA=(~-7J(D-+TUyMk;0gfnG|Kj}o|fQ|G>>9<1-a|NGh#AAIe}fUF#M zCL7h~S64)#(U?B#cSFFu41_7gp$brLT z+tNj(JICMW3teo{vXgxDArv^wGzIJZSdX)Lv4nQN8uh0yk;f!yS(%T7!C$76SlT*x~t~kEt?%rPOZoN!9gFj zzMFY+d@o&Dq@wzp4VviM_urnd$Stl#PXFWR8VUVg%-UUoXw1KvM7Xr-#aVgJrcu4 zas=|pmqvlOw?U)HcET{E`sxN;9*QcVFkBNEYR^(7Ju+$Ko4Bclo!oe6aj9irVRWTmBkJ%k-aJ6!h2JW~aAbx$MWyzy zaClAA*`TK5LtZOrN-#`zZZ5pQeQdbmV7UOwi6VhfF$B_`;~;;to& z#`Utk^Q>^Veox2bmInP~qRB?{h?Y0)-jWK2JWHw%zMOy2 z-wY$w$Hc0QRTS&OeHP8Jyv{;ukl{GJZcdt-8rtwW@7VZKpoK0SBr$t_f#Nn7h0pVj zDZ0T;f;dl*z+*Cxl_FZer9%1Kj^1hEtrAmw!dXyF)0)ek62OT+|C~u^j;srqL(x$= zg_7bM?8>FZoL^2bB6Tou1m9LbqHQP8X2+db4L|LeHQWX?TL=XK-pxY;RqR5Gx|JO! z{0KwYzRN?MWXIn zdP1#nnJKH~?2%tGY|GgNYpy}yPlzueRF{r3dAI@j%bmc@QcY6SJ*%2gP0us!C*WczN+s0@L&HQ9JF6e zURT$_Ao10$-5>Oe-u|l_=^KCkum5}cU;oe1pnBRzeYL>|uJPA@7)&QegIg#5O>aCn z;Y&$Ubu2-7EY36{KK5r-J+Hc6z2I8taByUruL}(;A}T8x3g1PRWz09Rq1<|nJ8iWp zY)&V18Vr_=4+X?u4n&o9wqbY?3jNrcm_wYk`j4^RJbPnC`t zB~A*kFfXEF*^J^F1Vm(-eT9tHkU*`Hv}Q7@ZXl^H z8)H7WSn2PVV=kXfVot6Xa`V)w5y_ViHa5cMfPJfch{d(Ca+OP^RO$R&?dTSWBl*u! zxICn1?^O?@>kKLKgQrh7i6A__eJ46bTe9@%sddG44ohgF#bE7D7EgKW5ZuTNTWJfF0G7u+~u zY7k$`YYo>QB|SZBYQOg1(j zvFsU3^GxoBI0@%?c1+7BC@1i*6f)!l_Q5;+2v&c^B{DLTfx zH0g1FloQCp;}Tk0Ibyf`f=0Pq@@Y}z%4Wc-+N-+%br=MS^4}vE6_yp8VkFN%xsDbGOVZeR=UF|OUshZPk`VNof)f&HatBPwMsRsftk6EO5`WJF`IPSx>bds zO*jkxG!0d4O8kPKq>XE^wy+C1U@Z}hvTg6e=E+(M8&0`QpIy;RtQIY!M6^j(nINfl zWfJ*(Om*1h5sB>`cuX0bNp?t+g~=$yn_!-mNN=a_fwtA%u?uocPlF)rJ!{VsW`{aT zxsWV$RVJ!Hc$gjTKyunSnd~ULB-bw5P%g+DEySK>me4fu55*Pfvk^0L3=8W=#RNydQV{qss%oM zDCN{n7eb9zs1}IvQ7g3ga4AT!VH=cg8BpPTBUNkZH%TR&SCP^1SH1qd${ud}t8-5$ zy9M^;d!`C`uY-K-!6P)N!jL)pl523?Sc!<7N+ZyBN@nIiD;s#S>6NR?Gn^8n`^x$pw27_3hm{qZ`@%9w) zKhO*J=@CWCvKO@0cGZ9M{=?vBKinIwGPtkk&+s(c75g?fv;_yTe978RjY;Y}7`)O+ zGC6XSk?RKEUi~+iW}uQH+CUHi!X31H=o*(V*HAM+gP0kcM?9z4CS+lc{Bx&20vwT< z#(^mIluu#|ba-$@Ez#Z18m_TAI~{nX(1O^k1%kv#Zzsjvi2DFC8^e zEI7fa6!EVW2T%`d3SGw~HBcdYqxE1R60d(0_Lq<-Q6Sso=Pzh-g_Tyk1m#j5ek=46 zG!r&m2Vuz-l7M}4@+YnV)O5vl49YE}n*w1x$#y^);m6*s`o`5T#`Q67a^T{A$aD3O zrw_|Zq^K2$@E4HELf66VNuW?(1aSM}b*2o=+f4j&dQ`*R*w1rqk>$3KcU%*p!_ja* za~$GOurKg3LyQX}T>iQZ0q+jfbQ#8wNW<5Y#JXS|oQ}r>)~4$t8j(KRbSu`pK|l#+ zR3a(noe^<9VjuX}rUYfIaqf~9pm;JDsl(iJh5>?XiP{4WF5B_N^@7vzb*6gsUliZ;PJO6N@gA~1=>yAjjW^X0{7RV8Blt5DI9q}<( ztNzKZOPK1#`6(qnWbf&qlvvyUJH`Ar9CP;;OU_$C7LDQO>9Uo%1}Rt)6$g1%WZX0X zeH3P!Qjs^z>Z3QH!+R?CD1|O|zfR%F z>OimON5q(zbOS*nQ3LsgEQP#-^d+S-Ln-8RoOqUkr5BmW zDZ$`gcXv8@H5g|TW{;u>m~O#oE#V~1*Z7fFEitCPN_nhN9ncqoRFv>b<(835drSUI zr26#hc(q-RDCl+)t#~#V9Esb7X@EJHOcfmNi+in|{l5DLxPSH)X0k{G51&Y`pA<8- z&WJy8Wq|?JXWisH3$quzjqR<5DUOjgfA>xfRAM+;NYR2-mX`f20CV1@ zCa8=A_bqe#owr@Sm>fxh#0Y-{!=;N<*$hhsR)~liazlCSq>PjRWCH5LwEHU?ltMX_e{%OmL6H$T?5(vNUS$n5?I!vHgsEP}XmgwHsv z773@*z?DvZ1)zO~UL}C>0UV2F&%^|X#Ski_LVcDPsCFIyl8!ss`q^WlizZZuPZ8KP z9N!UtMzeL;ny^#!kByJq;KH}~Y25sb{iJXEy^L|8rbqOzHnAnS(@f@@;|4uJAMP_g z_Fy=eDs!!iEDMj?FDg7BMnXKuZ{or{?A~^7GJUxo>aJSkgVkFFYMo!GkRx{?>@twD z>hPt@bH8Gy*-B{ZzR-13pjcMF&S86$~_ z9c}tr;%FScY)$H`g?(`i@M)Y~-4DT%3AIGKe$$JTU>47WGh8tB~V766S5~ zxlRYAi)L~BI$?6yuH88P@)6U;q+*Em8QVy}?-uI*^^e$20GYreHheP$0&RYIcQk|m zv2{Gyo8Rq(4jw1kI_tPWaWm}DsNNvR=j%>ZTx@oIcYM+)IE5q(duK{llT*4nn1A48@4_GPYf9S!(b!8wMFOQ*ER@`vl}X!*D$XB?^;Gd4uDUF6=_K zP3T?$I3Gr52QYm2NJydOViyTkR^_r7oweh{^Y9_U;#*Fd_r)d_Ip6KTu{++KsR$Cd zMcj>)Z>J+g{hVXQ_VqL4*6;M~#Y|xt%3};cOLCODob3wKpP8lJcn>1-vzrhgr@})O z8RXNHJ)dsxb{)xoJpOWZd-u~JtkR-fmNqzB=4RyEhl9OWTZ1WFKkmOpM3xsUp$=OJ z??9_bnsUeh#Pfb3&?1{o@7_467I9Kb!p84QsfR@CLlA@lN>ir&MRPIrN zu8o|Z*+eWd7&LUG>}o+z%C?*UeAH1tP)9}dHx6&6g{o#$d`S=Dwj4&ws;wlnvooaf zI4U}q4z^w+(qvZQ2mdTu%vGBgJRQOz{V${b(QzN=elV)8V|t@o$A`yd<{Gf%=@Nw~}p0Qb{Rit*geOX(*zn z3O1sWz$0tlN4Y6&Y?5QGb&~-&d5;NTWNtxLaju^ zvFu`@Z9GuO#nuT3G?=Oz33Pw)#Zz(XqV&& z_s6d@m75x}`5)G0NZCTvqC7clH({iEZqrD`(6kH1InF6MN6a1Habv+0yqV!a!z{do zb#(5D5d9WRBEi;%2_zk~4K5nM4&s}31}Z~zX0OL3~SMV{#~ZA zf~P^*1p@OMM?+>{ZWupHZkip+1>h=F#dvpZXNo7_sB9jQ8axd9kfsBq* zgCM*qeoGFCbP)ydfWr04j5Zrqi^n-*XI9ZPC>~d;tJo3rpGfVAP?zomUZ+GTWYlL< zb0p1-N<2wwRT9H|QGxRL_x-hhTwVK9?}b*OWME)EVM>}||LhUuvpd0j5O+5|eF|iE z1KxYc?}5x=pmW(rat>7840$2K{^)E!a89I`EsBf50A%z+Mp~@@n@DUoT2bG}S;St( zoU)2-hJ|?0s>mA>ejtc0(onLDrP29rsw*e@ZMj=w)ywS=lAh2B_Lk5J{uxXQ=pi1-JD@*{fRvnc z=}2+L7AO|_rWIbPxX>L9*F`|E88$M)k#yI(+VEziD9Or}0a@FTv&tkIN{x6DfYih? z4-@xC(IR3E>~85pP1^}7Vpr6-ue>Ubs9Z^H|H)3ICWd$4OIG0St?m8Gt2ftIBq4Cx zgQW$I5EMkW5D!f;htkERHDZPG8L>rMe35W$*|_Q8b$og)dD602~BlpH((w^n_*TumS z;ORDL?={GAIfj|hs=+V$iPBDp9I3f6H3W`Cr>A6tzjz+!~y&efP!XRnJMz;y*$@=AMx} zTbYxaD{6~S>Z+WjI6U5PCJXqcG4Fb6-kXPtKEEkH z@wYNZb~zU_y>tHL045YVYDzAZ>^tyJ2{h3b*IuXtYY!Ha7NDgg7;oY(JXceU@!V@K zl>JLW36s@Nhok+6!J#tuU`snqe{bAul_|*YeA4meEq%HCJ;(zY`j)Nu_nckh<9KfQ zSNdswQvWvpCjQmH^y0}{$oQ5a2T{{qf+V<=sKf=^cYi#WG^qI@apw-oYuPISxnfU| zg*_2|+}a>lg9Qzh@tXFZ-iKqeV{p^`!N-9<`F0jBY8e`8}fdo)2B zHzKA6ft13Ksey^-P%+yT8_k{I0m&xs8h|m(X9f3YB2^WyuHA6!QfSJ-F45FP%^eCE za$K$@75}Pt+`OMIL%H)=|u(+YDgyb~ou|Pdu}$FM5BJgou;T{$Ls=%t^*uGa6InwyXv< z+~-LAudbJ_$Q=#z9R9-!!}MXB-A6UHIqPJWMp>hV(=;y?xYkGIY83k(!p0XS%3T7; zk~}g9Bkomy8vudfkpUamKB^WVyz~^&fq5&`fJdyug@Ev11%yDpivi*7ye#E`!0>%R zh@e}U7+~jU^Xq_R{e0K$Jh$QPvpbuNPLV3|7?h&w!eL>bVdfA|rKUXG?r|;xwKW;rM>4bVcd=yUr~-Le_!-GO~u#-fz`AosaIr{&Gm$^i{WButU|`Bf^h zSLne3EPKP*ZCmO>n%Lou2bL*GTu)$k5DJRJx4q3fLUHzB-~1%x-PT9K)y5B%mg2;W ztF7<8l~kR~J;?uQ#|MlLhHtA=&E{$3KzT*tkKh2s(n8wKmfi4luR2%xm)Ax|9Pla9 z1dssx-xwTfh*$4ck-$5^$4C zYa?BTN~&mj93L6dY^kT4`v!#jUTazN6$sb;wmFFqL69T^z?O_8pLFd@yrFy?xg$)z zPr6AEs(!WOD5gdQt|PM60z^?~JJ)RrL3vedbhZ{-XdFi_h{S@*oD#I4W?Z?(iU^l@ zM^nR#ZYL%|(gaAz-Ye=UHkxTFh@)?y?l7m>!Q^zje+Buk;RUE<7V-w!If|1Z@D*f= zm^~aNn{Ek zg`zAAr|xv5iP#WhZ*v)7X=qktbIN*6CZ`&5ov7cT9TdPp8k=AY1$UYuNbH29{Zi`O za|siXR5+7kR+_Uz8qR8-Gn%J^L0LjNgkOMWh&^px6@hgaYKwOv(-9cF+Zjp@5)zH@ z2TD<5AHiAng~7xLmlIircLbubTUdfuY~nywAGu^B*1y@9LwjL^!HAc7P*K^_AYbp& zY5qrd=nr&<7KB{jd;EU>#OuEk6@$5MVja_v{-&PiOpZ2H7?}QZfOkN?` zEtEP5If8BKie;7-m1c0Vr$`n8ZVRV~)F;(+sN@Rn$>8L4s&yINLqr^8L-xte0zMBk^~+*9zWW+)d(oJZLAGH0Yi5&;}W;;Dri};^Kf5`w}fdsgDGZa$HjTfKHw+ zsMx$pF{jDdr2&@V?KyO**lw^HN~mz`Zwv3NFZCN#?BqI7005zu`%tLFP>{f9!E#7> zYeY3{X}CdNxJk{<4D|^oSWDw_if&zD6jxCG6~PAxrL{~c>nFqGs@L(V!=5-Smr3S(}>TxzyIVC*^cf_Hy8lxrx(%H68$vJ(Dc5BLsDG`!TH+|dMW)hk#Y!nNASZGNe{Ip zW~WC2d_M`Tl&0olSx1ducrBDw<9b+UW8oqi99-+mNKT>EuU!hUn-udpwmzdXZ~K_6 z_iWTRo+KEGnDfcGgVJSOdf+?Bn3$X!Gx&Y3-W}BhGoQX0&b-(}v?lyqd`^l^SIFOy zmz!3L;5imDe=FyOzSe=OagRvt+y@J{=)tJ_ds=LhPM{7^RT@peGH9GaD2|mAZ6QG+ zZm~Y_T`F3jIF`A~Mqm|hH~rZL;%JuS(l#i`F9=>V5zXk~V-PWDY_Sk};KSgL%*-ht zXteSNvX9Aiz5N{sa*hJ}3TXsB#Cr%hAizVi&2VR>E9 zn9*qRMwQN4)#V6s!$TPeglWiXDQBx_Cn_D(xqUcfg|SRR;8^xuMxjcBmnR$T7I3@5 zDzb!(0YMER_*drb&QSmMyN}w(&!BxggP~=6b8$|fXo6gzzA)Bv>+I-YGCtD~xG|hK zd<6fA<0xWp%q#>taE|nj3*sPQbg&vak|RRZ*W^nVjA{>Zw}JX&*gRk*sC`dWLF{2L zz2%O6iEzKX=V7Wo$-#Q3#|x*KHmtZ6#a&piE!7NFW_BXm%2LnZ!0Td2D4Jck#h#bF zq@*hgEeiQ+VsGrRK5XdCZGfyAvx8QRvuW3kTcYS z>wQYj`K43*Lr{M*ob52$ffcN~`@<=vO*eEJFzaDn>|m}{@Gh7P`IzY0G>e6egE^17 z>mEIJacv<1siKIQ{@4@y)Fr&)v+i{+RhXDAiS|Nv>{G6GVR)yKWn6}dIC^E$^uh{= zE0FsFD3+Dt4Xv;Uy(Qt<=3Ipbp>M^6fSg>ot;KN!hwgBQbc)ZWqdR9x<{f_6P|$c? zx?~y3`r%ECRE!Ur3pYefqJ3q4%zGFGvFvT`9kvdD@zH#@=&*TJ^B3#Tn4$VdyFI>x zZXtQYes@L-usY_1nR-8^{he#)s0$3t===C|G&*O;31G|Y$=3(WqMT&gH>l-Ub)^ZJ z+_r)Jj9>)+KVxoGESu8Be$@><1xS@gXQ`fP?B z-ORb@#>QZ_*FO&Qf&^?~qkvv1=J{E#k#$asB?ao*gWP08hm^Z${WLKXYke zydi0#hF5sT|A{vwx`5hEiGTe;D~s183>fqSY8FS-c1|vKqIaN=>_3aM6;4D#)Q!aA z(7K(&Uye^wI}M-KuU?jyUNBH;sgh~sLQHw5nM+@PDX&bV-U4#aOLP!FLw0o@gPT$9oQ7y-x$IO8ocZ7G{GZ1qqMV{+eKv za2RrxPt>{BTGu$3LN^|!gl_rauvZsu_AkR`vX|MQN%B0t@5C-^<0M8E!0;&5c^uKRz`V>g zdtq?ioTIT!e2wxancTZDMIuqjEKXpsud@hVAe8zy0m4t)mU6S$+Z=&BA}2dq#-H8U zwS-rq_j0Q2hs&aIg8E46pWFQ&(UjXWgi~(ME+e*kqucv@b!Cpi_PN?QVwe1g zz2kX^q>wNU_u0-D!q#ol1D{!30)c~IiQzGl_9RD}Eexh?Av_a5;}8u8S$QOzYqJl; zmMF6~Eg$#i!!I47ToSG^)*X~gK_R|)EPx~4#so6%Wb5(ww(m^>F7{TTfpnzQ z7|{~ln;TjeQn7LYk&G4Ew|r-f9h|y`dxv7B-T;14(-m3KRI+QS=^;bex;XVQ2{zb6QikY-Hj? z5p=;P2`=zY5553KwFF(Tm49dz5|_v~@zxSXN!YCVZvRuS0SLtO+Y7K^2SNdBN+WrG zlYx&b6U$&Nw1R!v`tleFK8Q>-S*UA2LRcKfYr^T@;F069tCPtnu z&>Uo+ak$L`Hf8>{1RIvID1MqhUeSHv6|aU~P# zl~iGJ$(If8mRg`h-A{tIWW1fkA=9ISd%^`xLmA291@+l-|A*K$Ey;S}QoNAfzSmzH zPKxH*N5kBqm*djDXk93;4X+tFF5WAVrQt=5@k%j<)HeXG4GxWWv)P+>dFUDj6tlbO zJjp#S0D}EI;CCsXckYZBaG;5s<|0r!)ON}0R65Z6CS|2V>Dp6wQ7Hl8T$|h) z7kpQ2vJqX`f3Y5ITKenH73$&~ttdlX#H%&Il;SitHfjQ2?S*DJ-jp+tEOeLv%O;`+ znpj{B1HoFZd7MSwzSb`stuVgRsboOKTRzm^YHu3pVGI8ic|n_mP;{RF!4}l8fAu{@ zhsJNc0*_*C+yTFklmIN9sf}eqU_xu2h^zdpa^aUw;JDxCoxXY(CN9v4mzGejeQ_C| zEOZNxX2ozKO~9)=b_Mnl0#ej9Oh{;&5wb*T7a7$CB=ak667Spu@$Sp3KS>VSWO1z! z3inb=nSU2}JU!_@WyfOJ{rIpEhk9BNAB^$ zHw8+|Jx{s3Fn#Zooy0EJZqO>yKk44P{q+9Mldtdc_9o#A2_PIne3lt9Bm_N>tA+O= z^W3Nl9BB=v&GWMZS?(?%fC=*Rijip~>zPN3M5T2oBsL&>m_Xng3;Ypl8Cev6VVLO2 zWN$J;?2M>k@IOXTcb0iKui;YEzRM6T9s>1b2B|?@Z1rjkZ)VB&Ko$vaH`+Jd?-+(o zB#hNV5S{I9=S)RYK^Q*SQ27{{Q6c`y=Vou3k8|Sz-vY^khhWM5NC?kS^Vg=-5fE7& zisIm8U$2nF#w2#kWjGj3VW#qYDdGja1mp3u(H#UN7l^)k;_ssCxs{G^w#204 zrZ}%rv|LG}_1^^}S=_Bq>Q_LNe4iN5bXXW1U?GSt!g?)uIf_&~=X(B<@622JTX<;K zo`DN6C2s9|S0a;c_7baB@-=!O8aeuq8YfT5DQcZF;{#ExXgdv7hT0>&8`HE%d*ZXb z4}m1%rf>jyO;Kk>?Vxs#4(6)1!}_6!R;}zsldvw@CQ@J?rWvpj>rk_Z+QxhV_I1fG z!I6N|8yl&SCXu_0Js1!uv-z*kzGZ+sLv9B_?T4qk;y>1L5okMNnoyK)h9?hBca^9V zUO9Y!)L;DmqkjAQYvHbN;WX|HPj*jH3hbnHG7GzCe)I6 z#=jwhK+K$Gq9g-58AQVS$79|LXoMVZ12`b)mkLTe^Y}2I%>0#Zc}=$j6of6ojzc?c{ihn7QG}*Q!SkP#Aij{xVq;8XuZ3atr3GgVp?G{|OT2X>t z(kkm-A9C*c+oE|ZYS!kQm`wI1BS)#S=8MucIu?PM=wj^2c3TByZ998z6XyOl)c;Tx zj%BpJ6o*UpPkYDuX--{{Ufj?bArBEb*O zVa5MOP*kX@C|KkjIPCA6QgFvywQ58m$MFU!F()>4%S3v93T@U!t+YvEfLlrEydGWq zB5k8cOxmYSK$hcedd;0Q}SN}mn>UO@J`1QY}N@Jj;Me2Wd zcMEjD^}{TnGNCI8ZM1n}DN(4m6A2a;zl)SkXRpgMK2YS%w>|?OARSE9LOwaik2qX+A=5K<{(6k{4YneuzlskgF(pUh6o5hPcg-0U*)CFoxF- z=aA1k44*YoBmDwGMs8tdcL@=4Q{;BQhQb8N_5veA&XSVzxlOMnesb&8@c0;}EF1?U zC`OXdUJ9LZ^~~Le7DYC@UZ*VzGFeMB!bgId!1*b>qq|y{2aeJdu~QR%iE>9XG^vn^ zPcxgk@maHJ!E$+>*Bv()N#^L6?oO{l@T!q}%75;F)Qpg3t&7Mc?S$AsuVm~P)|0)abc0wm*vH=T)EODI z^d0yTdxIC7aCQ++b6E*w5~y^pzv)kz%ItH502FT=w* zM#NwK#Sf%-WL!*>f%Dq};&npCMhcQ;X;5;3)dV5$(D_tb8@78tNWodm&y^(inGY$B zQ->D6ZHAb(&rpV60aua87MZ7!q{TRf5GP3pP-{(yny9a2)m{OqZG*>3)^I1}BHr&L zl|QVTO|hA--3X1k`P&$#&J9{mvMmqZdlQzbBD0N4y8=FrSXfCe7S3dCz3if#f}E_r zxudZ``pFyDRvV6I!!q*Y%uZ!*Ug36$b^x9qqp359Bk-;VzO3z|+S|d%6NV-;$tNPP z7I*VNQr?{1Fg1&5J*n-{f<62m+23}G?3^Z=3JDp zs<2|VYhMmuL=rwHB*LJ75kj&IfLeg_5H_u;q}3%Husr-gev*X?ZDt@f1h7$&9(Pl( zYFtE733}}YfBJVo;Z4o10NNuegq;igNI677h+=x^d6FX$WWuWx(wdl1`-ia>=a^=c5+6ji}$D*o500#5>_)2&!Z^8}dqZ^-A^SYW3rf zRp(Fop&Y0$WG&l-nS6Z$3mX$@+B4arlcW>j+W46(aKqnO)Z93Ag@8=@3ypf~V6I?9 z_!oCRg@Ug`G;f!6-J{z4GAhUKy4$@!z5C-&tCv|9xYK(}Q8wM9f>+BL>eBWH5S=K% z*mft>rY^>GUO-4&R(3JOxo3tnRq2-$QW_B3x{Fjfmw}Se8h|DcN-dMAu+iwEBA%1! z8)7^Bn;HyYeriL|Xr^s(V{viKrw>E07-`TaHh<2Df*PXS5~K}_tn1Vb@}t42cs&S# z4T9H7t@1U|@B?tJCJfe54_Pz{lR}jB=9BR{5Sqz%Sn*tgsjswE(qjXD5{WOhFg2eQ zeI@>DFDn>I*Oq!P?VRx})1BM1ngELfzO+qt&PYuwYk_oNXmM|X;W#)DCftaq)e7(g z(B~7awO2h~ICGn-P&J(7+6jIVu1$i5BsVSMrIzcf5lgAcGF`K60em8;AwspGk|?nZ zFep=^iz&`X5#UkbgzjKEIYI(IP~1oj6@sRQMCYpDKcA4-21lo$7P^BG=t!;{%2vG# z8wPpc)nK63V2UQ3Kb?k;Py)jJK!)%hhT0pz0-)K+uD80E@@#`#;vVN zM97SGaF#l0u-I7#`jo>Yw*~O}L+RK=0WP6QBp2k!Mw+35&>k;hN!6B`ZlT3TjYJ$5<9%WWqkBqet+L(qp{n!N5lTi{=o5;K!?w(zgf;;^+rrCr{R46 zc^aC2KF?b3R_>J}>0ZXi)?bZpmHxF!jK=a&Dk2bM4hwcV-m5oUsL|+`9-0s74y+KV zmM3F6>Dd;6Cl=HNI*ACLNhDszLKB(|mVrkVGL0Nf;53Mfi@?ypJO+qYle;t|+m#GE z$kvC;H57lvRUhse5sx`e>W_wT@0sfj z>qd1r2eyMCG>P^{e`JuK1JgH$h`Ph&xxMi|pdb^q*9H6n!p8@xYm6>FOq74tm;GEW z=B%d(xCB(r6>AXF)<1nLpn%$Fdq@gPBE0^)-%%z*)C9h~YhiJTPdIQZi&fdQcoO>= zh-U-M$7P;{ssLY55Q;U~O1l3SCLieY4!!!z>HhSrk2vAi)%5|yhTcC0C%0Zg3?0QZ zB%zILA)5MakkCfhye4SIB|q8JQ$b8po{#j>&KOJ__z1> zWA=LMFOK7#D!zxL86{xDsR=Z;sH@UEspLMXwMQo$$&?wS{~F*p)@}CG=xNQYpLgDj z(R)3xDR<8^^>4tEPRGOlM0FyYJu0~@;!&{2Xc8S^O+*9KN`4I4!_>=UwZq48wo1OBm)kGY1i4=t=Ii&;NudJyk|^32yHo)f){~=(s{Ew zL6R=h>`Oc-^)yRHki0*}6v{{mcaff$O{Kbr8>SebcRgWI zYvL)3;idpttx&v?-#BgEQhrsiT}LZ<#bJ@dZ?enuO~rdDTo3^y19>8aS z1*Axn)yArHz%nUeqs3<+AEAYSteAk>`Lvsr{uG{@{J7sZIXOa|_PqiQj?#2q2lUpG z9v(|PE)quRH;`V~QAJyp%!}3j%s1WoYi3Ak=%Q=|Q%Grs5yn92Zw+~-0zfSA^NN`e zbcsRr3190p!}q0jiwifL|=MlG-!Gu{z#ww~RtnDwo;P0W*G^KKLlU@#5q?#A_9pb7JMFzakF-WGPDzx3Emr^_B=JefVMRSgY{Hv&8EDzceD>57kMvXMzZ+FTTk0p-#>sw=hwgZat&NPY}U&xAAA37 zQ!-x7+j^^g_G{hwWCgbII^jk8p1h|bvmt%l_FwbDx$DUaeA5>%9ea+`{`A?_+~dyF z`=_&C?P*U|V0*3;UbN@Qdo6qZYhF0_JXwM7`QoKx&u>3_`uNe~+xK?vJ^SlsE0w2z zr}%Fi@G=B6{w2vbtwJS5{-+T6d=a+uKIgUl)1%{ggg$?}W&gc5t?tf>@4Ewpz5I&c zKrG0Y;)vjLUkHgOj~_qX*}Q%CFSox5+&{;ONCa7`&MmW2I9}jky!F?B7lcRSf*dSd z!P>D}`<*M!!;`yD?lTGG=99;NzJK>=8(j7fzIHNLgZC0mCV^50j47p~>RY4<-B7u( z%2>@NSCGhHCgHeN_sgF&&L;_|%Q`8oC zJ(#z4Ii_ukkH_oR&TrEFa|Gx&t{w)@aD^apIqp13Jx9pX$vaq@j7s?%(49+$OaY1B zgkVV*M0y@JE9KIAlLnGpkSw8g&o(xwm6VHP?@-2_nWl9h?6|9mG3qsC4~Br}AZKL{ z4UF%%316PDa&hMba8nnKb4A0BKR7zOWpYr6eysBIQY9Hb{5fVcf5G zI~CqkPtwqY;;09Aa&U={{MVwua^B!yuT=9JeDN=fT3q|G-h#pO@Hf8y7UjoK`5P{T zb0+!wYxNHDS$>J&)cMo=a^XV$P%OkNhJSP{UE)$GJ!zR=kJP~{YXlWeK6foCb@n2Q zyCgOGKJ5H{r47Dg4ymVc#6sD(_$4y&jR#1|El66XX-$10bSZQxU^k6r zvJPf7(xBJ$m<-(w!kly- zVW;)@EqjR3q;Pu!UCdsO!*DpReK_7xlIY_&iR^%$BfT-G60gx-4+n4f>ulUVhUfB0 z2mYiC=B&+#{Wd~OwyFdkTQ^1lv~}UL${aV!?M6!9yE;;UUWs5DJ8{8lkHMC>hL=z` z_fAS;E$s=4+{(@~gwlRx0Hr6XW~j;JU<167n;@K!TX3a{8xZ&MqEXNh*JcPzwi(7D z1<{UAQwD5ph^KHe@-=Nf*xb4Q_>s9AwV%&NkVz2RSnd<+wrQQ1uhdC_>BDv;+= zVFl0GY=m4($YY?zQ<%$uza=NiL-R;W8Vh6vVk3tX1WQGV4#)$t*h63L~7^2|`wb-;ynSJJvd;p^Jq z@&uhH;lVsUCf;boG{>&-eh#9WWMS2b2c{hBFs5Xj5$0N^fAzt$(c(GQj4%zIfrEpN zfoYc=_Q$g~@NNn7WwPA-`U5|Q*6W4YOqeeBZ?uc{6SdANePW zJN^xSCY1KcDWb%V1_`a*l&rIe)RE2Vo~^=n3JQC7ygEtqDR_TB)qyCbSZbi{oOQDA zQf9@@1d|*^kOc|tn-;&a04>>7Ty^{{B5K*I_6Stm-?t+(IALPK24p0!U)$}^hI_pf z%P|v)Qxh2)U!BJ$|Jur_KNjkH%jn#NaoHc`KMSosTV0`5D~@V~Sq>myVGfXI zkM{r2O&&+G5|5J4UdbOM){s5|I@>xJ}QmD$< z`OHB085Yp_%=*zk;`-zn;rJPp#)e*&--rC|xR;?*JFYpeZ$Sr?e_DVM$Z0bN1JbSi z^!x734g4o6$ju*7J!+N8ffS+IW>D`szq^%uv9a2H{{8xk%d6|%-sPLCcz3(U*KV$S zN@UQX1#xQpMhZ597{5GR1I3dz&%Zz}v-R-TwIo|ylnL?)%TzJRP^D^{D$aV#tk%yl zuif3{=T)#$Tbj%i@xz*Q{oV8L`)mKWy7s3XWJ=c5#cP0(GIaqIF+8Kx0U_QCk3-t) zeISTp^YZAMAkBrM>w}k=%sl#)3@pokR|5hpk{cUF48J)K_AABt$oiIMeVJyqX^8|L zNqN9uL9xkTM>ZKB0#Fb(7buX~!a_eZ`4lg19q+&0=0A^yd$7?AU{rSH(=`kF|ARD& zc?G}FNQ#P(6vxVVi6@iY!Stj;t=<3nf5#~HJF2e3Br}=q9Zqh&oJ?Mh25Ity_m(I) z1Do6=s<;-U8KOK(V`FOTE;QLva0ntO6|VL;uLvN>s0JBmA!9~PoSaU_Gl@pf`n&E! zq=!A^R?r{`g!<7E-Ta|LA@9sQ{{x#Ay&wq%-$mSDsE-;^=4%O{)PG^wN=x4`o&OM* zjMz%+F?4JMS$f3&vpff8h}}Oy7B;5O;gSaw6lXAcQl7(QAS|HaJA%RTU|VK352r1n z+iVVlt^ff%b+N!YWF7Uqkj>pDU4)#M z9Ll#Zp=1pegQ5XelSb+eS@j*HhMDzWHkubi;P=^<@;+h3PrmJ%yvO>C61z5qI$RA< zv$~Le{Nak?)}k%~Lh!w)3Iw>!%>|l`QKZl`lbuf|J+jDbZ)Y=KE{>Pubh<_HDn3PO zRMAAC6N#`6Yaocdbd)3B^Ug?_M?>O5^hX*eb>wj=IXLN0&ngshg2FUB>C7~8ThCFo zwR!LFNrJ~K)h_Hra3SsQu^6+4j5{L=6XNPQso~7;$CjBE--=k)@P-)oUk%PAa8^(XWg29{0xA3)yMEr}N{F~&Si4Rw7CU*G11C-9B zY`@HURbSI5&`g_V%ACbUTeUVw!)n;(liD=aZa6V&1VK%qlC?Pc%Bh zJC77AtIyzt+<<8Yl?>x%gF)pQ*9=mT=vvlrwoXLD4T+>&>5nVkYE|~Ims{vKK0m!n z+vA6tzH~M@IKkv4PG@g~yQ=-QnWX!?B7Gk9&!pe&O9>`zUm_m*5SMaAMMtQF_w2v~ zLD!k44azNLd@DKn{4*j?Be@F{LqN`Ie-63X@nCOwFdXcoY?Yi;M2t##vV9y@Se*A^ zbe{C8uYqydit(+%g3$Dprwh;4om>$nm`x0|BHEs&exRR)F+$KoRJ( zEHBow8W?v`MFkSyt@nq5U+Rv`#0hbW-B1pESe?US#QQDyd7+`x`T^V4KVHD9!9G`iw4eGzAFYb>*7o)n+uOfi z+upvmz5OLk9krozZdnYR828gBz`Trd=iF)jneND%E`2t;RF?XoEV@ex$SOZ0G2o#0 zvRBFF!rC5FJgzgT*4jQi#|E?2UiCLti4s8J&{3R~Zr$;*x;?{VB#k6`z8NBpnu$+P zl3FBOUZtGw9uec^UM1P<`T?zht)WS>Wf^diV_M*S9d&5aA5c6ZKMX$0e5GF;Q4#B?%gdvVUYI-xVv`2A(spGhfPG901 zP3bm9+zB+wYAd0@<*ohxWN*EX%16lGJzKZ8dq?|nkEMSCGxnrBsp_YfB90~ygiHcS zeeadLHy!-v=@8-PNS;w4x7u`yq|GsvbR&_mR}9=W8kF?dM2GD0V;>8rRM_W^q!OGV zI&BB6Kc(bhyzCU_!xZO=^L8XD2W;l6fZr6t-d9x@xxvQ}N@}lFH!2jQfCC4Zn3SRz zrq##ENchQ-D7bXO?raxyTpi5bweE2$FIDeWbRIuJg_eCmo}dYIUtCMt7p7l_O@o0E ziOrEW8mt&<582M?c<>gSNhHPrO1}*!(*zMX$%NxYdX%9B`52COu#QKR@Rw_kaA5rgK!jrBo+Se!=B3PQ{nK@FkIGU+cbZqi{x8*DS; z#^zd+n=mp9RJSZDZElw+DRMgE?UWoowJduFF!IneS0Ij1?iyjS@UfGk6B zVpJS}@BpD;@Rmj-Sh`DphTGGV!BO>S0vmh3y1qM{`~!Z|d#}nw&zeB>KCNmGz&ns0 z%$*s`Bj2vC<-S0ONfJFRuOS_SzQ=P!p9=X=-9je7K1E}-;g1kxHo}uf^3zJ6$U>@V ze+W&cc+YPT%!FC#Q1(|#Tfc3fk(s9$A{5dRQ;X7p-hkKZV3=0XN0{djp3j^oe~wR& zaP!mLL*ElrhK>|c;ZJd?npN8}^KijskFy+(rH6n5w7ViO!x6Pr<2SC5XBLwyZv-Ib z=_+Y3Ay=br2ZQA3lvWD}n(~zH6k23eCxVpI&^fY%RNkOLiN@{lf>H_8~mOtzif+g#jvC&k*GWafoR;6;^^Eq7BoVm=I$V z8nMK)a4_g)5WJpneRGGsRvZ};p8ASg@~0!t(O+2Q4(GYO8AoJ6m) zfhR=8d9`7Q5y_y#*>{8KE&$wI^et)GIK8bCTxR3e4$)~F^GlaC_oTW4W{;d|T~i$T z$KAxovtL3?amkJGV%P5TW?&4v1dbwpCoozh7=PJ#XoNF?8eUaMhF&vp#x3@~_%k_j z>DM+4WwZKwKe?hhqn)!WhjV8a@Dy;eVBR%2mnMRQ4&?o-{A&XzJm3iq7}7~h?L-+f zXt@_oE~tOxEO`yR3`Im7rVP?eI^esIYuHUm3$aT(O3-XNy4T&Eox6{2Z*A@DKyBA2 znd6SW5-4OBd1D?us(!4PtL(|cyH69?1oXlTgf%L#K1Kj9iU3Yx2c8U=-Vq6G?!i#C z2S@m`hrpvgeo<$R@Z7)lpZa*~?C4-JKHI)aAC58X+uL8`AkNN!j7RbAar@!pKvCP@ z8}B16>eoa5faLpLfys&62T%)zcdEa_>bG|Yb^QeXBKpe@lfz~KEKa=;zZmgD@6r2j z0WATIoR@iCAe;Fc&@JrUmeXQ4@Wntx?C>J$%25+6diKjTBMRl5w8Dhm_LnDA1clko z{t!iNNk41Sfsrzsn|2lO#NLTCE}@6)nLX}!{NfVbpN>J#U(M^)rjz(P)G6Uz8eefI zhcXhVW@0E!NlYvcM&|5?i^p<{3_JY_UI>qDuw@b`52yEOZ$Xjz;k1M?0850%Mk;1+ zY-r9b3vzS9zIJ2y5-x{>@9u7OWqsOD`S{-CM3A((4Q%CzVYym+6|U`^SzVnpYphOD z{e!RSezstf0P&uKRk{WHg>TpCG!l^e60?dGOZbWa^qqng%c)@oXGU=ickH_V{G#Ol zhJlVEx*7*gfp^W*Y3Z?X>JF}!0WeccKpWM%U2ePC^MWl;o6OsGZP&Q<)GyCw+C`iOEA@MQVAB+YB9)o0|dxV8C=v!`@XdD4f??T5u zGur{ekYPK3+rWYOL9kR3F4K6kz}sisbPo7KC1$iK%Ihj>0;P#apSY6cjG3-QdV=b< zfu?N?c(-|YoT6UqR&I{^Cp6@5Yz$|A11p@oX(&*^!%O_7mKh zAUdc6;~G?P&;+k~f@tvM{m{2`%zmZY%!N~Ej4goPR4vD^<(#*kv-2a69nws*jm$!h z4~x{fSf}n4w8o;UohU6#v(HZ;@4`QjWB$RzNB4HVe)weTY1OLIh`9;pRx%5@V=>@Q zRvAV`&>Biy1M%cO5LtR~EeO|SR{X@YRF{Ht$mG~2BECvI_o)6u)o9(PkB(>&B&*t+ zOt~b)b3#-sS70_=XHXFneSljA=Y^tb!E}lvEZx1+P65G&t18@Ct8-s~U?2ys6($Ff zSzg+7%Z-h#zdYRBx%c?#Rw6!x3!3d`;g%g2TBk7#w&98fM+P1iob7~;pPC6!aNRx0 zle45m^Z;22a9luZhh{$(oDr|<8FI5Q@)n*WXf=~NK>B3$kF}@{i7$MOk%J@kC6OR6 ziScq*nDy|B-ubS7dG+d_0&qEA{XE(%Fz=#ipk}qb1Y-*^HA5lJt zVjBNi`PsKNEPZ7l4uF7;{(Xw zGvIHt4b%l*G9pz;C1Q9JyoQ$=cqwu`0cV>pw{_&2iw;cQ(AragR3fnylvHQsgyhWT zV(m){K)Z@#;*$&*5B`$a#b#WMOA?VT)g&bXXr8nbR?LR}iT%Ogt!4yq&#_CDM7wWr zk1cm68$lL$>*$qiZ2%$+{D1u8A0daeB{cf573@zyQh2u^OOcg8`-W>Mzk~OmS_Ssc zvz9jf>bA<8P@CwkM12AJ6}L*^N4FHnix5Fc;h?yaNWgm@;)GN=`TZZR9wD{B7^F|c zHHBSZs0BOn?ZQvd2Ca2bNC^iD8ZpuZbFu-qKF4VlTW(GNX z&k|uaJ(;TG{FV=Ohyar{l4wY!t!GZGP&5*6(W zf&+_rj@NLxb%Y$X=FLV%`0kc)NodoM?S3j1uq~(rm0oFyFEBK2Z7KW|^q;{f)WgMH zA{bQ6$Mf?F)Ct7PTw!U<#7t0k8#z!U%9-d@a#we}(IB3{Q`MWtA0pfhG~XU(zASF# zfns@l_7pI9B6Y^QD;^ZIqVG1@8iRdJ+t!3Rc3JNzXE_-|_Qs&08KYEs8DC6D>2m6b zFD57o_uMcLHH9WM^CC2mt^1F@R&zqa8f@7u0=I!Yfx=SyiftA31#oZs3vBw{L-@Kp zef;F#ced_t-hOf$zv5f0O%#=_(_Oytt>`Kd#>6$!X3>n6QGn*Ig(D=(XXlLuH$G6b zAq6QEDOkf4GEKb&gh`P@?Q2cO3`1F6uf0;LLwa-_DZ}VZM}ewowv9 z7nwF|uv4`HClQ4(I~_>~yP}R6Q19D~d}^K5iAD=;a$30(!0BhR&$9ozO(>iIKIVR2 z6^yhsmH5X-MuqfzIG&fpmkmo~<#&l>+hoze`VrlR&`WBqyn%r26@k{5^n6^3dHN(V zsE1<5kUDYfo7RkOl=Vd^eIxG$HpMs!r+5_XA^5|GP=X-$hX;}ziv`ILwI$BC#<;l- ze44QC=r!?e?v=tvG+PeM7GO{0_1e(UaydF?G%Qh_o+MdM;6n|+YKCNzDIOrLB}{$% z7xZi8#C_RJFe;rq6gjeg<>hlU4?~2$)8h77*Wyzmb~Z8hBd`}dMV)7rS*-{E&KDgJO0lQzelx$uihGIv0br^rRP#;j0G78`5-oNF;}ZnxYV4`IBUs z$pAuPCu4#`WYbBMLewNfPZ3E(NQ7c`IzXMmfWE^oR>gPwDh*-yOOrgr7GfXEuj=)l z9=YiBem=IXVNo&?W`~)aOd~jw_uz-Ry^Wc1HgN&TGL`KzM@71vY$<}_TmVB5lYz?( z4a6`3RWefYCZ=q=9;d2vgqV+!;!KTWaTnk@E?c2FZ&4V9(YBTVS1x2 zJOfPwAK<001X(b8;0knXDEfBEE`b)dS_!bX=}^izCaV5VU=wO8K!Edv0Y42Nq}PRo ze2@DQSjI2FTR5H*GQol-{zB{uvjg@e9+B^KvRDvL>fuUqdQ03|}g1U7>mgFluV9xMF5_BeReoHNA<9I?g)k~(>MEcny*-vfe zPOwTY!<`Wpa!%e>UCspA2qZ2tAvWcj5~L6ghA25Z23+2y9^e!B;(AYn%aSklE_ITN zs73=>eU!9cm)Dw@ZqK3J$)>W})HW_UYWc7ujGl@eIY73ZIVXavlZben1Ux;#7?CeR z$CB0qINd`gwt%k`m1wQ>(G3MyxW$FAI`5CZ{bc1Y5wtQ^hEDsGN%_Xh0!uSK2zc_w zFu$U~P6&H{mPF*xQx7WCkWUXzO@-6da zjEE*Igi9olYj%k3%%RN`C5ViHhXArvsS|_!aRuWXA%K@2^!qp^z76tNbn3myXoQkq zXaU;<48SbLy| zc`IaMXOS=aBl&fGeIJPc5Cx3mG-KMMvr4}R-4g?IJ-J&wN4j+8V|#b)%1@U!D)_k5 ze$5}MLszRe`QMM>&!2{G$u|fy{E(#bwIdT(t__fNKB6wqgKn#{X+54%*VC1^m|eJt zoI;|0rBg_n3gRBhNC~(pKrAzlFS7F+z_)UG9QTZU^AoP;AY*CmP|f}+eqnE%6Y6m!{ zNCmx+@5{CUhuGHF#xe%$VD_xyK0vBC(K z?YmXAjR~eI_zgmK8CuSm{-_qG(LQUUjklT~&B1YToMd6fePn4jH*9gJFd>N|H*T)$ zR3&^Lt6uqHBc8E{ICWGh`?ij?GK3Sc96Lx@VTp%;K5t_;R^n%lRXO*Aw66 zd%v7ZLW@)M3MB{Zh6Q%=ml_m^Sx)C&R< zytE`f((VKu>UM?P4AemK?IP}}TZyq5ZS% zDoXuIklmtp9VR*5dxt>kc&{R(Cy&ih0X^Tc#WO!-9MUJ8*cPxxv$F|2dWo~*k5yQXI7YUf2>)3gX|k+37mhqP2?~E+kNCV zWEaJfy)-h8fS1^Dvu}Hce!HnK!a0#)0UEPY8a}tMtog$loWtmC1S#+;Wb}Ia^;Y$R zh0!k{KT2(FbKTp-PnP##kDF~|-Y8)Z{#D~{EG6M5cC(@+bnwdf+7?KEE6`i|i^Xct z2ri-{wug7XJ|!{YklRCYsN6(A>c&roFvg0?eT$PzvJORek-NwXgvmG%c!ng)uSA1} zsYY%gHhmjPEV`C-wZ;geW?P1{AH5>!tk(bR&SwD=byeYClW^TJF@(8e$3qE5=)+f< zoPWVceNDJgIqwLNLM)Kpp_=e;Lfr^pDu$@E^)J3W{KKn19vt-g zv*Wkb8~U0uDumVm@L-=KNYa~lY(BTz4V2nDM{ru`u#gbMNx3+u0cE3-Dh4}SI}g9c z#W)lNq@=-}%0M&IP@MLA8Ooc1b^n{F74q7X``_@jbkz19kTrxL2+9a-!RU4H8hHeJ zm*|!&;U_j6Fb!GF?kv`pLe(=Hna-jXMt8Wn(f3>v<0E8z0nm0*XZ($~uCnM3R zm_h^Vx6BQoDgD=zAp-vQ_TXNL$k35w9_kB1y_rs6gdZ|TJB)Bl<Su0~2!lBNWkc z2c<6UR&0)|TZ*2rq1-V;Hc{9`QeBs{KhgVW#9tEYUcedu>f5^v7Hua^dVA9k@si7k z7&YRfU`6#nJDY9h&OmMS*67b6A&_tW&qr|r*n*IEUe4IaItx}8or)UPRuZxWY%P&~ zBB9}Z*~uYr3v|fBzZI5}lLE($2Fw7>WOnT$hT4&q$e7dE??NmNN6v8LT;c#PxFhy{ z%+ATH_Wc1!BZ`V;DZhm}2yo}F{!Efx-I=_6 zIqZ)o)%72GyY~Anq)y%M?GA3pBsBdvssR^iFYTJZ>uVUP0&A{r!Ih&*)4+QD&0x3< z`B+19T>=+PdKj(oaDLIX@$1mK5QQ6FLl2BRQmPog%O4Qw2?$bgVEi7RER z1A~$oYsytmPsczsR7}9VA+6r{J?f!?usRp)0=fxV$G2qY}*)oTb>5J``b8UwL{h|&tBxj3h}Y3VY=Dz^;?g=B9idW=#! zDEUl^iD}v(BCHWkm=;wt$+{2h3^*lwo5lS_y|se{!h&{$i@|E`HMy=PX2UPQhJ^95 zlR5&xl>$(c+SNa*0c~}Ac3Db1-sBZ-@AB#f|GCwD{{8xk%ed-1%EoB+ut+96oUGk| zK5-l59AfJb!EcaHS-tCI@9_EWk@*~Wv5&HdTAYzze(?g{l(lcKy-3X|93V;(35t`N zoJ`>CL+6;{EJE?`5?qI;yKAADyXvt=f`_&|abbYT&%2s;2x?AONKQgtV5-)oa=c5b zY~b32*+N*5`bzZ@#vGmzOpt}-vXSEnkLv|C8U54Vk&qoJoo6WFhamkh>wrFuyRKXO zBRW{cK67+UMUFXqGdy{4x_fVeV&vl)(y|ZUx~!zMZj~nxsPVZ}LNsdDj0m25q|sH0 zAdmOBVcv3`>wlF8$+xM4({KJM^O~}`?&C9%A9%iEy|+j~g69u@2XTqtTq}Hm*h8bk zDn`u*Ysze~Sq94THFY43`Z7BJgF0^q1I+96rlpzuV9nd~87ZbEJN5Qou{@zL-{ zqZbJ96dxvY0_mhk^K1rDU^F~A3rCY3*t&(Wh7|MNPGU_IQ6*!duZMksaPTJr z5CK6y3Wy^ls||mGKv*(Y=c2kB{yH}YuUodH8PNm;IDtg6W~>)rkM&hv2Cq>0n!tfJsm3K(HE<(1qMs*OvQVi2t(Dy~ zGR>{o;n$O?QYoD2T%zFtKR-1ikGr|L-NV}!l*jecC*YIe*!Y2voD|5x=RZ!+L{H3W z@u5@*$9Jjm;Kf{e6AW)yHY}7^H5#NiH5Nb?r~oFs%!wyU$v2Y8cxOXaQwRwp0Ug6* zF8xe*NBwX)`LGmXb)D&4;LZ?NDL~X1vyU9?ACNu{`?F^01A;~y;akCE!2_wra!XLM z;2ZhE8R3vo#R_@liQ!M+J5{>m>~K#0@gs&#JJdjE4mRqciC`fV@YJxfI#?t5dLlMm zfp;@2q)5qFoe-}YXb*%&BRSq+A7m;E-%Hs*E>!g0Q)Hk%+3roIFIPpn?Fv6wMVR(8GFNODQPb%T7=L)F znh-9vL$(qcB!uLSk8~bdQtMjJ?g!$x9WxT6`;oAO34SZ~X! zeL8ssSp`I(7zmU=9+h6ADb^)~qg4g|0xEFl?b->4StAw^)smrGPFe%PTe2JA<=+M! zrjSHuPN=|USl}I|4e=a@l!bcZyk7$MnxP=LXY5XAFEBtK=b?Z#JY|QRP}LvdetsV^ zLmxhlRDFd}?Z~?Ix=Lb7^umgX=5YU)T)`z16UxrTr36!Cp&X8Fyq#U85N_C98(%j# zP*!eCF>LrMA<4~rfTPNx)ha%S4-f#z5UpYeU*hLyL?m`!N2ca)KeAb)|FBV!scHad z1DkC;2G06`Z;O=!A{wNImec=h;3Y>T3xLB}|3EX@H_K%nl!!yy_;62_F5~z~Zdz3hbW>+B^?h4jOKo#(wei+Q2qoKJ(lerRzYc&kd@IaJZfgcA%!%;Y5C+9b7BzJb1kI zR20hV>(X`=Aa0(pqoH1aG*0pVXYbwj+PJcH(f|7?DsIw}9Rt4LbeiSZV32Kg+rUCN z=`54hPapy6fJ95eHgU3EXTQODf&F6V`^FgaT2(?gN%uPYgkN_IRkP-G%yGYPT|rPS zzJ3zJY2TN2%kT4CyeR8qzqW6|JdJi1(gm;JK~DR@cEA8(#MsFm1jAdL4Q>JNrcM@*b* zO(yK0qMOPiVn4q~`;m4lP&&)WK<2HK=o2g^DaNy7tG8~L!dlE39u~!3q&5oc!1Ste zH50QCju$8|IsqNuZfEW%GPxQay&ll4J%jQaHjFL} zyKuw=eHMedJH$zv$4NyX`GjhGqm-z^IIE*8l-En-qco8FYqNwO==p{S27?FzWn zjB-&mU#7rrZ=G8V`571BAbXK_Lnz>n`OEpR2wk~29N;1@V)HHZhM@tNWAxs3aS`VB zOL*I;g8>${t4i`xkbsnxvRu*PD>%Ol{o5|3 zNgSd!fGN5t4gp!gk6I01@a=^Lqz|?Kky!eWGY0O>!KK=kI`b;(8a)`!aoA8c!+0uy zl>$rEdF#X$7tiJDxEPSx=Q!h-IcjtyINmUG#XEDJYuN->ItPac@{liNL;_+DELAGl z{7K1Xjv08pKTA}|O?9Mz55;YBk)dNmFe2g>dl|_uvL3P`h!M(RvkLwbNgs{lE@t5H?!GX zN)cO{Z&k+?HN&C%o`dTLd-MxsFn{zQ$4Wc_CpIXk%%TiQM~vx_i=6iv9Y=b9`67_B z=xhwiBDCPZ?DCM&_~v%%5v*MO*6>{^@Sn>epZ-m2uf4Ui-PzhK9v6@9A)AQ=g0f{-Yw0U3S1$EROiSRGwacr0Rwk?s6&fg6&iJa>Ca0@UxwR^By32g z1UN#8TM5ts)#tqs6Rf)+-e1oHFwYLBgSj`;ja6lI|LAm7qRmWCmbL#{8>STMa)@nd zE}$^R9zf%5(tj-fr|a_+W;{AUoDV6n?JS)xv9Zo~6=&#n4bQvM@^m!%p>}PE4k`mo zyclV4{TkRToj>mwfAZb@c4zOeo&CL5YxcNNv+G9>jng^!WdlY4`UC}<(UF)ztR?`F z-r#6T-<9Ik`u2-A>n~dVlX%|lrKN;!Y}B5=Yxy;rgn8GTCeM)G06Xo!!Dse{MLQqd zU-|NnQoxgTUO@Wd!$&KB{^~C)A!NzU@z&;dC@}kK>)GBqO0w*(@4t*w#pMuLYV6N- zHY&u8c~N#S+)$@U@GW$n%*n2y+XiI*B}sBZchSaA;3PHM)Oq)!i8>@mLiEo|IKq;3 zP9%9;1SlgHQS5^*jQ}W7huk)U`0V*kx^x)-u@A8qQkyv@$mxIdFkthO8CbTU4t4xg zgd=Sb9ciELJ|-r4BEHs7;Z%zUj@~|@^U)ezu06rPP&t(%pvefrPcR!1G7ufpTl?dE zq(@s2m+f=9&*oq9dbuscT<+Ytvx@((W&QvW@MRxx*B96`{%z!+{!9)h@z-$snR8s3 z4CubX_Y~l=EyYbF`Z^z+oFeaqmcNRF`y^X78c?kasSJdOHKQdFB#8i zTXY`?8+QTdT-<|reTn>2hrjED>4Yl}tlG`i`ApwrfZ~tjZ~c| zzA}}?+BUnmVfVqBfiKt{5a^$%o-X$BDfh<}K^tD4A9_Q!3(-+_%wH=YpKto(30=^0 zfFmTRVp~tig$$Jr*iEH>cD%akTE#e=w}(HU0$V29=Qmi#tQ#c83d?_w_oR8y`vNZh z$hFq{;`SG}mn)q2`;+-rNb7`Pp8f=wAfL+5fA~EpZqA@Mxd(SBJ2TpZ_jjPFnWQw3 zMDLnjhSvj@GghrK_YGWdawLEfFl|s7Ab_7<5_gJkA<4>RGS&rt7R+=i4ao9JsUvEy zrswdu#fZYXQyr;yP*pR`DR@U-ySWJ82u2;4WPm7R@(*Ox2jqn~Fx#)GM2J|u(_zt` zlAT6*am4E3??ps$>)&gK2tB_Vq5kO@fjUc2>SS@@H)EnN@t?h3*J9}F% zwzk(_0sI;pJFjAbY8ed1 za4@WHY|hypR}sy?9R*I#@YX}KW3k>-OhAtv^w>EYbs<(r5fdH(*hhOYVQ{RyalzMj z1aIjl$xaiM6C0}IxXeTj>AZWzBwLazvkol^7i73H$)S?Vp}>FZXJ?hTZ-HE<2$Wc< zlWP-F8C)D!;xkSI!EUu)b37QSyc8=^eFWOajnC3Kl!S)t2 zb{{0WU3N-MN9(}n>BKTG!(<$>kyNpQ%Dd$>?vmtN-!c!bnLiP~WLuy^C~7Pdz0LmQ zXgoNy3+KR)0L5cBh`?e5N~!F#1FfckbDs8V<;+Sa?svmS{Rmt{>KRfmpP+SmI(d7q z%vjpG8|(gdao$1hmqOtx)C*@O&R-0Zkc@G>a!U~tTHa6zBy?K>_8IvQu9UqopVdY9 zn@9yW+#VPJwF)$+>JH&|s&q4|v=5Ro(U{Ec356vDVvaf>Djy^(JDk3U#AINvG~#-D z1UmNNYPXAm?cFdO2m$CrpT#!XhUv%BhXFQr^!9IZ67wEv9t zi{qjR{p=y<0liT{=OcX8iN|6-YOGVW^!WHN3vU2Y;sEkiopCi04l zoey$~j$Oj#=^7yt*>db3pVT5`1nkQY#*_&GGh`wg>IO&%g6D*pUq#J6(tkkd3#TK@ z9%yxzH-WC4Sa3mtb?ck&?(FTm6J`4ttstbfL`^J;u~|2Kd*fy6b*uClyB779IN3K= zb<_AX`f+ppDoP|9y)F)cma<&Wd>#6oT+{K&%EPcT*YsSeR}MOHX9gi8QYFqK%_%SU zQeL0{L(#ZXQZ{i0hN7$V+Q}X%Z;x{~op$n49d0;|l}dPk3IX9| z4B;O1#)VuHDDdo$1L$l?rlyg$3Le?FpzVNHPQgCfh9Z z`qOqZ#O_I^CFVew&`Ugl3AZ%vGW0ae*#tI~lmbO`*&`~JJBj4O6)JUXZnym?k#*Dc z!+!;!xzk)FCz?Zi+&G8W_?`QG=6+cm?y9v@JtX8g@U;8O27d04eY;Ep6 z18c`5qjp=UFuJIK5`G_W0RQ4o`lNRHe%eTsPYzNwn`P);IPG3R27tl{2trgr>OsK0 z1^m%>fWbi#6Q<6b+Ng?5ak}}Ah^Af zU?+v=>>6Ro$h*b#p3Dv*TCn6?1a@?2SkB_hrcQ-ol&QUFg065>T;VS15*F@70P!W{ zn~Gx;{9$}@_!u)#V)L0@SMBp-GGo8hZo>@qy65iS3?|Z34$H2(D>JZv=-p4sT1V3; zOEDXwegtyhJ?ZsuZ9t!lQ|uOmf9=l8&$N$2>3oc2uzhMWmVN}xN`|}1yJ2{|ETu&z z@K8LuJY-E4pZe~<(Ee}B-=2;JljZduvS{?j%NxMxOArjQvDQ)^O7Q;H?z@%ZkarT| zwoH)PR7pc&U*}0lfq)7u51-ir^HFS{%Gt$CK{k^<17BY5M{stGM*66$wrVPx`&E?_fUAF z`QP{WLG$5*V$rrK+mV+@x&jI{x*S6ee^2fm6Vg-XeDI9@4v@!A21yqieS8XQMd@ok z)X#syRCJb1i1*xnvbluQ;c){N-%B)?AUtlIyKL|yl7suCGZTvB7icHu&tvAe#u~)? zqb7-)oLM~dmMTE7QfR=alfyOT(#PH53D`d%gtJRYb7;G}Y)1rT5rV{mrwUeq&%m{? zELhYJZ;W>4N3{#Qpc8+Bv*i&JY3q~6c*4*~XgLp{KcKDM{foOLl5|ijzlOXF{q|rwMS1kc{AV^GDrXV{k`1K@a(y4$4>u!9J>bUUV_Zi8Z% z8oo!N_0jvu^Rw76O%_WBbJy&z&GL?^hLU!(T zmzOZ5dZd&75QuWxe^YbK<0y8KXks|4wD$x!4&n*FG*wCfQ-os3pdCb12s-W@2|Ddi zhXS9WTx^+RO>=i1PttE%%`AIF{`K=Q>cB0Hhqtfdfp~HGQ!@_oc>^)e8c0!hK9c+H z218w}faH#64MhT$59Gdz2C^7mzlB_$ozumN>%&3Xba%yBh?|Ywl{YZhrao@`nm;ug zbg|<6qGrw9(b)3r!`IOYWa`)6H6f_$!=9c1yyFQIxUstTIi85-FAeKJIRYJNmrpC( z3mdHFURx5QfPHsGzeksm7DL_|a}p1xI1%5t z%&{B^#~pQ4CbInxs4YD0`){n@xS>vzOj|q}?uAZ{FOmh432H-6*FR6%KldqkYg)S` zc1ZRmd%=#gGx6-Lrz~~z&raV?#8#&)9cFjyRsgpJn0KcrVvdxl{sfIC23qJMQLwFg z#z~KuZ4PgtR~@Max&W5CnAVmDheGt}V1nGh0azQ@6-mMxsH8Yu>ilczI~a?Ow9D2J&d7F; zqdK8C-IH{a%iw~27Vb4iepzo|aMPYLHa_q(5ieW~a%AWUQ2aM61PP!6lwneJmjn9> z_akH|*mRj49WTiKuDu;xE_nG8P-V*%#((C5VNkO3M+yN7clibyoLsDEGcHaWMr($w z)n|ofywHpY+5+$g%TZ{zylj1dzk)8AdK8pfChb~wAG|-MV+Ip5=o4y^q(#)&-$dRZ zq}AluPl^Y%glLl^Q2fLU5iHF`Mur4s3u|sKO3F$5x_ze2;OHDBgdMQ@v9NX<3YthN z`LZL;;11_mGg1|r(559cA^V{-2@}t^CArwz5%)!N>!$0VK%lu}-13yBhZALIwZ0kCBB&}KM8-L?DcHM<>vk`85W=B9w(h<3wQsi^e4HwBqGrNP^K&60_D^#BPI${n~0E>2~Qdl#ti#@@tNv+i!J$Y!geXe62Qvj*vA%aY} zKv5#6hM&425y6QN@a&1QA%7sqQ&EXMQKPs5PtKoeTm3J;SZB_5eB-RcjNWYRyaJNZ z?jpR#kAg>!|Ca7N^jpl2o6S*z8f8t$>bU+JUz4en_TiA(ls^W@LMpkfXsI30TT^Uc zRfF(LqwhX~)O{!U2$4#qJeC{JeF@@QYffid{w#=*2CE6(S9e@X?6jY#Cx_l`ot$ru z;oUdx-+(aO6aMSxrl&76#j-un$88X&K}ExfBdqOdA{hjx zE~;EvzIwB{F}Us z{=fnkFI8ou>q*ug_aH>TPa(%#QJ35XKN0qSl=UC8U-1axqDCE*dNb9%pRG!SJgK;^ z`X1apt~w$&Z9VUrGa5`#llG+F+bV~txxNVsZi4xNHqJ(-4cE*)3Od`Q6opO zyjNH<2*5bLe(ab(^LEa*b^$Y$Bj4~R0G<9F7m_{j31|?&yaJaPDP2VmC5`ul-G~n3 zr$7;azlCVx*gzNt>5K{l-U}CBXJGv!i!{xs-*4)3SIf=sS7U+ z6a~F#Aurd0q!RK$;Bh2!sf)uDeyhIsewd0srycWm;E7XzVK5KWm)d zgUYGeXElpwdMVzKXK>(xPz;BnqyAq1816;GqY7jSw@9d|aA|N!P^~Fe^B$cdNsiZl z1l1L%j!kUKKng6gFaal2EFLEWhL9~0v`mOnnq+3}E02{94y3pypqVW;T=M{#wfh{c zCOQ_|0z_eOmu7Fgq)Swoq85CAMExL6fEw`(1dpYyzJn%0Kgw@{17CocG5F!PXo^{1 zZzOA&_Qm{R&Bk}j=gYm~e^3;9&n0B5X8eY_H3I30?pyqmZ?M~YqY)|?r+x3@rZjK3 z(L1s%#E${(B58ww2YyA)t3w2o^EXTotnj3`9MX>z?(Im$Lkn0THA^{z8%(=>d3ZjU zhC!KsW;{j6?DQ0-CoVH6CY*mb9mG5 zQ+=UM!70C^1B)Q4Qbw||5~?6Lkykx91M(4n8s7~1?@Kp8XC!daSVj?O#sQ>o6y1Mq z5p8TTc06BsQ9~I7s&>udLljk#k0K*pV52}7(vJdO737AN$D@lrD(W416CjY<`;fJe9SXYW@I6fVFO91_{?o!S&sz90p&d}1{c(G)M=59 z`=euRR3lY}$%Sc%euaC9{f65Rhlm!T#*?Nts?8!cyAN9x_d_`;orYU%X0|Y;Af$i+ zj@HR_IVGD*764ulVW1m>g!8$=lEqC+J*1+dQRENqivJU~+K*o)(CDWyMPEW#nYpNo z6#ISVk}?IDUypyVu+h%xI86|MCg_05aGfZN?5jZ_XV;Bd>`{uNqeot zTGEMQ?x};Nc1JLdpEZa`qxdN$XE`t22#1MWK`8kYLn+7L&nHQE`YAqEl@IoCUY#hv zl%1@T4_()lGRZBG4Y@1;DQnnkEk+{`4z_X`GP;|t_i&f_B>bhn)m$_53kgJ+k1hD; z(ReD=Ns*TWCAFYoEE`B1vqJt7uBgc7CJvxFVe}V0Z+ff#(m#+8gKFHU|D=IQy&J1RrSPo zVKn?z)jToWavJ=Z4{ErENr0Mad^tA&$+#XjRs)et&iMs*MOTm9xg@*Q>Q2R*j*uL`?DBiP~OfltC;<*OSkHTCya z9X9%tG8d1-Mw!>MzH5Qy`@9xzE{gD#X4H#eh$=|CdTVg!d_ccP-}VSN*9kRY>D9N> zP+$CQiO&Gg!kdR~M3GqJ{8)K$AvERC_1oPgz}s(Zb;StJ7-pG+>I}2%5z_G?gNA)c z#|4Bceyjv(bJRuel2HWy<7eF?D2JBc{(XJ%zq*S*B8g-1y>}qAF5j-iNlG2)@ZSo+ zP*-392={rMq|JRDz@AUSU*Wg8kgK8>VAoi!{@a_0t->*%#x58K@UG#1W~ z>1zYr0b){db==23Ul6;E+Mwq$MED+J_9FDVeJM`7;Q>04e0d%+3>u=0Hw{FtB9IOB z%u!9{`b&@dx5k|hV_?u2ojO{rK+&HlMyN+-``wcYL^cneIHUI$G@AkE{M(OsipAj6 zx^&ZU0x8e+296jddlAt9D7W~!#fxRXg3Fz|WT4koxS)<8)?gVpzMo9q+DCw)YIM)* zwkBA*hWLfMT_$xh#7yvzfLM36bB=T#5D_m^#y#co>c1OOeg%LKuhf4XKoHbGnahr` zkSzV-JGa<6T4bWN2D_T~uKT*SNRY!QIm;66J+A_P0<@)nm0>TkmfFiGg_dP<0E#x_ znW9fb1>0242Os)9Nd#+eEX`F}YY5h8LsaXpq)?piv80B|o!IKxkPuZ`*=C}h^LCy4ur||cv9=YHndD|T?M=yqX@uW3Fb7d$ij3~ zesv8vW_n%1qOc#(AwtibjD|}b4N!tkw$+_=EA~34@Hp!-+ASWHj29YS~8ncXo1bArQtcXGTOa0F-M_jWo1%P>TTvK;3pjo6MhAbn3S$n zz7jzto@4$!edwHtKP+d5i{LL#wSpdaEEvrPRIL{fdZ+wlk(OF0*N+P3ppk8gX>m zZ2a->|NZvhVEOw$(tscz)ZlBM%9jovKKxCr+>XoO=XZ1Jkx%0ZkoR`ereKx=^grYYHBj4TIK{Ch|GMyIR0{z1jC$G->C*7kfC=R_;{j>FgU=LIctj409YCoXba#J%!J~f9#lDVro(!7c|qKq}z4zRAUVX_OBP z0RzcMppA50NxP>16CWXJIpU+a6>hft_H6^si7`M&`xKdZb8u@mHavKFkWwf?e}InB z_{wo@)?*CCHUp;JW4!|;`x;B4FebA^7SAIj4nxAUP}!>MvBXY$9>g4>hYX}_WK=Qc z9Y9tK#Qc1_wY|CXZQECFd-i7Qm5(r}n0-b=KriyUL@Q_5XcXnT>>^jl6nQw2L~qzd zRZm1KoWRm*S)P^T+{MY9bjQfm2?sU2nGDWwY0nRhSiv0^1(oKyS@=T2A@FZblk5^Q zKH&9XTgjkHkHb0hhZls5yoeQX%M$pdy_CTB{IH`_QSe6SxE8^4Yg*zLoe{j|m^9x3 z45tu*A!jpd5_Y71ED2$S@cI?<71nfVpTyhbFz)Ys;+%XUj((mTaC0?#1BMQqI@?01 z2KMTYOF8HAWO92WxO7g7_R;D8`G1C}u5wm9#%H4m{BhP!Mx&FnK7_Zk5^I@ekTMPv zl8ccvcRfg4k=+TX_2E6_7?%qkS}hzQc`4Xh4V6&PiQY!O{iSyyby}uSh_l*fX}KtI zQMk`=naNU>xxylB3wJJXV6GA#SuW;eG#Qf$Yr|e1iDmfBTE<^7DYVJ8`B$RNgY5;I zhhlVe8AP>U{ap%2AhR@`6~So1MF`zcYGWN5A{}~A5k-;%Ja!!u8&v(EeOC&&NHITj zVqe1`~u7Sg;N@(Sd z+V;6oU*(Q1BQjC(A*zU+YyJ4f_e+hu+?{;SjW78a@lCYH;#@1+5)pjcYyWylraDgEI~6lJlUmy zJa|U2h$5S|tK{qL$P(NP&{y-ma2oi&(;d@9N-O{U(2IQ>d@deahyCp|k zPS!cva(|d?2wsRstE(7xU+GE8jDw75Wl8ion8>vxGHbfLg2;O8(8Q{lL1m&~ZWN`x zRE!pLInEzg-FW>7u?!I5lXS0ej!3suo=53e4530-Z=16C1Z&(8G#guLqw86@!^!7z z!$Kd5Pyug-3DUL}!RQ9FfpRUVsl5(lu;IhSatUy8a4TB}H6vf-Pw*WupZ_D4bs zaRc!C)LE#Jpjr^0)|qL1JQzPc7)mWq-zzbT%{8LXFOUwRJG?3c{2aBSVq0!Modevx zH7b)+Bc0kz5`^e)K8*KR>~6H1HAw>`>X3RD1@N^8H9jP4=;~l>dSY!4(f8? z()|wiE`p&H^Ee`yccAh1I*I5Ux%JodZFhQgwY9gWvJY33_ivEQ$nl6W*s9CM@oLvC zH+ky=Y0+iVDn6GZO84KGRL@?-_@(+>9VS{ZzP9RA^IoBRcUa4PmY-?fE%2CYnv4*^ zdJ6^EE~vY8I#|#+@Pv+4!(%9%L9NCoC{r?INksnKv48Re|E^iF4>IZh&{~U-o~7KL z4CvHdz8|~RdUND+6m`SQz%bg-)->Vh@;%aTkm26G$v4PGF~AZrXLVISTDMQ4kKLaA zE`#1c1_h6+0;8srzD9~9%j3V;9KA;vAWA-t5BAA(F`JIpsAe5)bf2MU?^*xA{i5%8 zC*uQHfcgKE{&?*54VraPcoPKzGTMhm($bdP)~sI&nC}VzC?5!bm-X| zDLTgwv**43$r$Z>uQe4!W*2)mfO15pD-lb+Q{lqmS%HZah^gUn+(whIOR7`y8fQ>C z9CzWeK(<=1PAuS7rY+O2@l6cO?ip>^4Jc01i3VqWXL9*QQ6Smz77HpTh5L$gnP55^?P&`e5VFA~Pf zU(ln`#TB4#JV2Bos05D9w!(hnI`ONYzh*xQr;BT5h&#WDHjM!1b;AUR;n3NDb`i?J zK_QReESqsHW9t|AD}uwn`D}lRcx~H+nI{cQv!P*`L^G8K{x3OY)#Z4Isy*O6up$Fw zfRIym=!dup7{CtRQPP?lpqFSzG3s@DW6eswT`3sbJnAskYu3(&-VX{bYdLdj?t0Ih z8Qp%Pm|`#?p;C4XR&bf~N1Zv)Q@TwtT>?ccrACU7JdRl^ z((_19l~HqMT+!5wQDPq6P_y=N=Jo;XUj-iUnt7MF#WLP8|7*p1SU7(c+{E>OU~AUx zfb{F$oDHCu79CXOgeYjF_7m-xB!$0eH+f-H$4b%EP|g-``!1N2%-` z{L_|M2;^vu!@pawf+Ox11YI0P$E};lm<7TGOSy;mkX8fNICaM2G%?6zMC$^Y7->63 zDXHQ;E4Ot8rMQo2pE&H(XabNin;c8g!s;;^f}w*k4SBT?IMs8w(r%JY)ZbaRJAU`l z6Xoj=v|u-Z58Yjla(>QnPXb&>p4d;kBsMmdI3IYo#iGc}V;OY+OTb#->!6J~jR(Ci zZpVN&6P*9G07o&0mMYs?g>HZmtz9fbOS9Pz{XVJ?0<2(x8J^TbP!k6OmA>56@-6h= z-4vL}>Z<2IpFIkH{0xEejBO`9miE1~P$uG*dQE)LAT`FsiZXMzm|Vb%*X_ z0felt8|sr}3-|GC8NV4doi z?6mQ;HmFG~-kHR+A|Ro4ENprIy?}x%=L8HeM;RN6C*)FctU!{1BN9Vv#4|URU~4_S zJfu<)CM%k*eAaf~>^6$3-oIa>D1rCJn6%ltegZ9xu7@#ostCjfg7G`3orahdRqUa} zADr$Wt#;ZQFI%r$k?O!cb_zp$4vmyMFUKxANdRxd)Jn~4FgCJZE1L)iTO0mfY7~hW zUIZvLBDvai60;svsSU8z_$t!-VP=8N#5le?Aa!s9;Gio)C)OPp(gT$C9;&?EI zt*Xy!eSAG7rAxFB{#k?1fRhe5~=d9xRo5Ua>KByK| zo?LbBnLQJpUBoOm=%8kQ1{0?T2FyhoWJ26L`(PaAtmOwabNzgMH{lcn=9B5^t?@w3 z2G{L_@3&_8Ci@aucrB*^$@9?|YNix>SMGPz^{nYc&FIuRJ_FbCd~~LTsSVt0I&T}i zV2$tJHjbr1hnhRy4Qw-gZa#D3_>6`TzzDK@t~i)0^=Q#=WpvVh3X1O+r=uVG95-B_rRK{BTq1l{b5IBqu05#VY?;xZ=`t%8 z7PXy!VR{KlXBYO`-IBoxtO5OwIIm0?1(XrkYy<78C+0KUDi>ho4;~?<5AG|^Bo`9& z?xK72L-zzx9806|2?}^+QAW5F3K-yitRV<41{J_6{(~LDP4;ql#eNWF;-ZRWz!l%>tuQz%rV8`W#mtF(BgmW{)BU(4E~~<8P2j%WSK} zZcLt{e2*Lvyxp9i9KXdvOR&K*&Jx%+q1CNlP`v=xQ}~608jRi(`1M7AGafZGQK*=5+J!4nkACa#kUDG( zDuN(E?189@PT)fh#SvV``(vhegr6$}6F3ibA3XZfLkIDs-^1iWKh&HC?%pJqWcdR3 z=%=4%Q-cLuC18tL1mp7uC`SOig=Pj-rE4WG4G{rWVFb@{N%9hvCdZ@G0RmgVlRUcu z)Z>fzUO6a=4zC*Pp&zyH2_F&otD506xV#mETk|pKEPb_}Ui|CEfKubt2{vw@(>WcJ`8ZXFD7g>|w?O7D{%$#e)$<1>kU{5#=P5SAb> zNN@+ur8`d#;8RXshDA(e1!0VzqtmX)5FNHE?>K@S*+%rNxY1uAS)tA2m4>VZ97*Jp zYm=o~72K8;5OaO~Le(e4?`r2;)TlVztW{BWge7twavbSg0KCER94KFc-gLdF03_ym zrghbs=f}%FNvR=l0}CM6y+GIby(UJHs_Tdsve8+wV=NAY{!hC?O;O+}WIfd*Y)gj4-b7CR( zvaIc5@FhAKP8aP+&Ic0_i(@}crb>gAi(UVCe2yR)^4J$iKS%X{~Tq8#P( zjOb)?M%jbDPaPa2+}q$!G^{GD&d#xut@BHXT8J7Wvgd4o`UxQG3_QZ<9C9gOXnx8c zgguX$rcfB~oO0{CoN()h_!MFI5|6x#nLZB_MPH83c-yF5ObTNCimtN-ZpFpxq0!hN8vND4iOLI7D9?iZ!1KKN>y$saL&cn zK~<|==!=@^rP^#^_Nzc&5hmqg_+y_%c9{sd#ZN2y%Q_7E!LH|Bt;?ZUo3K8b=bl;j zB%dWnLuY?IGG-QfkTeMUG4-k&KZG zt!&311GJZaR#ySXC7B1s_&kA(irpe&W00?i&mfh{UHI0b^7&+WIv&C1-=CbKA`H4)I`93_ zb+*XPM4C9qVFO1Tk7i6RkrLfPaoq6TaC?b~cqc$-Q~(R4yXU2avWhrqL!*Iz;JE7S zP%=8KC^xO5;m-y2ml;xOEN^Pyru!l3zUBH$UkcQkoKb~}s?cIOm|yv@cP(B^p)Q+P z)RAIa_137wxDofqV4E18qiq9eR3L&*1Su4zhnFbcGqoBD7nB=NrkCIc!IAoSY?63t z`)w68<}C^;Jo|n`Gvb>PSRxcLnCyxd%Co`rnT+aWAJ09fYD#?Sq;?NOi%wo&`f+g4 z$VWPI^u*pH9!u4i43-5&=ONIY%$Gn4PPW&4>_SWR=SMVRJi90QdQYSZUUW zJ-P4Am3wglBDM`kIXyk|=Y9C$gV*wE${*nR$6yHWBF=uL*anvjOsfJtxaj_eqq9r6 zw)-8UQb4ukeM~{s`rz|2AyC$rDc7;DF|ISTpO?{3ko@Wi{(nx6Q4znr8v_DOs`b%*3E@QPTsV!KzrnanNhxksOP9 z+d$8PC(cf23QKVq@~0sC8{w&J7qPc1DpO>8`{*x!$+w1GIa*sujJYilygCdU-%$BZ zAJi){*bjefV@VvDcO;77%aj^Q_P9;`o})8Wnhfo>By7o8)LPKDvdqLb8~YF}Z-L?_ zf0%$!h}7P6OsMWj!EE3$hY zLG-TyBJ+aAEd>0#DFHPoO9&mTaZxGAh%(k|$nM{}_jyo^AyvSwDv*lS1;VG6@8Sfc zBfWt(2i!geN5Hod1!E+f4S9`zJR2OUhO$JAO6p^D@L3g#%I~V9Q!NCoiEi1OOCcd9 zewo)%deqRA9%5=QCv9s*$42G+SeRskTL9~TGT+k?G{}7v*34Q0>isscPk{{WH(wB6 zmlbAw${&81sY`&_9^C_OtLjKU0)la%QSc0W1s{D{aV7a(WsI=vkpBVpSFA*SNX;nDS&;v+ttPo3eukFb-IX29l@BFkNK z{#%V0U5f}qxJUfgFjzbWC{UTtaNk52FCv69Bt?D*4RmtBTxasmaA0YZap1y3NMe+m z3Yl@w!g&5q5;QrvN@0^Pz?%F!1Wpc}!ff~}0v%u#PEo1n8g&aR>uAnlh&J+`bS&E9ZhsmxL2|LmhXQ}+Y|c}tPz`+>c~zyu}T{h z`wK9@zxY%7u+kQVJYH%@pTic#USoTdjH1{cJ7yklLRR8lRg^YWiqVE3xUdgAoUP(x zqX3oU5k483ZorunYl8J6H32Knb#W1h3gMs0(WT1?M-jmouH#DpDJTwkbJBTfG!?H9FCJhzCo>H}qu?Eh<0mjU@ZLMGw+p zu6x2T9StKL0?s7QHJi##A-8rfghA^d{O?xe&)YSKLKO69Y#w`1mq9TGZ;H2c8(QY+ zeGi>&uvXuwio5|$-8>ER0u(r-BR@&;)R_9GYzLlpioj!lkit&14_q`BgE|cov8K>H9tb7gL!O4+Kyj%2Hwj z986-ex|zpAX#g|C9Nf|#(kM+i0ro^#pCdqmi#Il$;1D&>c7hnk(@=ajx*XGSiW&nt9s-ZuEk1`A1Yo3#++A{00KFUEv=$%SyZ>|D^tpU1c&LX&qH90)=*8lEs|!zB{r0C!!DE`c4zyAUoy zf<2$q2ow=rDlI2=^p_p=Eh2&{fZ{Z^IGr3&Y`5LXnRdzd#C{!X>s1}UsnIAII-0#t z{X!~lvxeHE!d*<}ObdwmD*zs;eP0)c|0>fKn$U?Yk@(>Bk-ooB^Y&D*~?5_-z@?J ztfYuyNGzv#aH}C@cpm} zhXa%qqR|*BrkRH|rq9dn2DnurB@;fVwPtaKO`|)`5r;#4UOW;-GQL&YPyCV+Yy7u3 zrz`4?(K>;H79_d?r#<-PfIho$TuWYzXsgjgJah2wWK_@- zOeopS@zZYDOp&EUn)qRHkXM2*iXPuF;i+v&(vS9B(? z79DNG2;lro{p?TLFBOrkvs_9gv+S<~tBgheO<)yB1kfbRwU!5#yt#gfU{o6f##Q~6dtMGzV)L&2A+C$&9cd50vyEaaB$;KqP?YilUxyyP6{T3#nuz{qt7yBL_; zB?PlZh&8+08Kdd1y6t^_5#9EO{Ytj`CRe>?gvzU~$(gW@?6e{t>;F49KVO7k{zmHC zp99DOq6MCh#)5A5g?d!kZEg?di55FZ5{X$TKhEh04EFppnz}XXj5dKe}Ah&r7N$03Nq)AZawd>jgIlwGmhkq0< zddVq0`j=Mm%6eo~hC$NcWRd3u~>Jm2OEHs48q6ZenHju+}QbPktGp z4eFBU6w0KQ1Euq-Kxn1QQw4F?b9rG(X7nXtEOUAuuo7kuY#V87vyyOv`-w2Lae_$r z09LS;51gL~W6f2H^nKZUhoa{wno@gntN_0I=prQI#N3LB2HJrP4*!qSXkI;_vJh zVRUN3y!s4kzY+7AX!?OcVC745aG^34$6Ga*>S-gHQ4NVOzMrDm{&i|rqIgutgmyP! z0hbPj-$DKBqIyHxqi9*8=;VqinT4-{UNX_o3(<>#symZmrp z=G`3vT?qh{k(Cq&N8rM&$!C~J?+SW+q?+gMCBw_^C`Fr-L$BJnnG5(=G0zdz&LXu+ z{xDI~$dA22a9I!VMOBrD+U8>h5F_Ln9#P1JjRC2t=K8kuiUY0Lz zujX#TlE;tySSsRx$85?JisB7?57_{21KCLeab`&t21}p$=aL{r z-i;GpOYb&{HkbXf)k!Wxl87^fQI1&2M%Yxa9g^1O;nIruK}+bBbA--vcOn%QSPW+9 zgVS?=1jVKY0`|rqEDqMw$p|wCs%OQcA@U0or58}tEML>C6YiwTJuK?ODks)>pz4%2fFz43 zD7)h$$p)6AZuJ#cf<}6+b7$!L+8Ja^(7l(*lM{*QGQ>Pyuxqjoy3?&D?z0_T-$=Gi zCGnq6jB+!9;D&}2WZU6#&j`F_U)4CLiUTrzi5o}Ai(4HLmw-a)nwx>7W*17$t6(yP zV>>dPQ3}v?7lDVGCif!5`i_o~eK_qXT(#($`AQj8#FL<07oVIH4A;?Hx?VTdp?0~L zF1irlRf%6s5&-#4a_-`ee9u!vC=h+Bc=9p`5i7$LIKj&~1XhJ_5^r1HRPh%?vMi|u zIgz}V%lDV=gX#?!c%p<&qIflQM6vy0H)OitiJ?OTnpQ?8WmZwb#|YXuN`wBtNznHs=}{acm)I#NFIWWXxmKo?g=tyA5QtkT0wt!_ngW%A-bufm{1=+8`IfP`D zdCOnig=+>I#!)t5Nsv3{uAEjshF}5P;;?zqb~$fuo29m~_jbVxpWIjVw|gcN`qEhy zDIQ_Um3m%fk`L5qvBz>@KKg4TD9;sN(2Qn*hRmD$#C=~*1<39rEtG4h1C^@fDl|0w!PCrduzUjIXvnP;UO0z&|qdC#wnpYvy7iW>GJqi|{I9K!Li zWk7RtOj>kjHB)X&v2e(^$Qld36`S?)ay;MTQ5xS_o~j}xHEAR88U$p%$v2SXTj+P% zToM?Eqvv@1iFf#-iyGXz#mklRgJAYjq~N&vQGz_fsmcabh)x)Aua7$Lr~tt6EXzCv z6wx$7l%ZGk@Cb5dh4dC5W**azIz3Gm?fGf#HngAP{z>PbmvAR*Qd;4(q3Xo@RThAI zdK%A6bd88gJkgUSE8X!Aryqf0~$G-GLLa8=7&CiaIxkqWSsdZG?<6 z;g|xpdxI#_fJ$y4;+D}dD>-XVTE7$ZpyYbw!Wy8&O`}$@5(As?Y1s0EmSI;ckoVhn< zR>QQv>M@gDMrYNnqU}YS`L=de!?eHZG5ySVP8BoD4hStOK&jj)A1ph*YrC=8)Qn|- zaQ&2PT3mZK(14%X<*7Ic>!Erb_I2$`-b=j9_b7Z;@g{$?vHrUC>eW`Mlg(CpapT#> z!>R#3>u$e!^(yb_vwr2%*57t__V!DS(SPaL-bM)teD-?tQK{W-`>&;EU1F@#Q`}*> z?K4-yMg;MhjsCj#>``5dB*4TYd(w+L!B)p~U75`#xa<5dq#0|35&;MXpe6*YAZyFgDWaO3f+Az>dnkW-q>tU{{b(#N3I37Wq*6kVwF8vh#>*G@7GR zJ?fHCkkYyI4!bHGBmAzMs3KXLI(%i?IlZP#e*pE;vgu* zCE+2#E}f89sV@=AWhL+UdBZ3eB%LQv>nk}c+bSB2K|a3f&>A33#X3{&&6@R~l|Pks zf3E0@XJ+=4S$$c8VHvYSgF{W@+hGWBEq+eqoO4}@6x%3s&u$CN`Uh$*WWUNpkTnJW zXNP6qMtoDm|1BJKpCQ2Ntp93+94FL5d43wFj`X)$$wJ?Xi`_BBI$tGcF!J?o{Q9z6 zv2JOG05jA#04^!DB23qVpmJIOK;+EE`Owz|dnB#~knt7){JwA8GF%Lr560rG0N+QS z?@wG47}bdjH9A7ku2^Qe697{r7dwD#*I<8=Sp{Vl25)*u_C{Dh00djK%GCoQ=Ss*q zgd5wwLTK#yMt2XT0d&82@jWsDCA%L339kSrDnhRKXEYlh|9$~GI>cWo3~BnFdW|?pS%wTIvNJG$T3w7Xk9`-!0e-SP4#CWUDB^yW(>C(1REDD2__kbTCot}>nav0j(E$)5!<(JU~vV}m$TUuNd ztZ=Prt`B{tLkGPS)Ti8LcS=!S}K>!noQD;-_Kz`_-B4l*0v=Y;0^Y2$peJ5{=(v%R*6UDUjUkZtCY=Y%AcDAFLP zqmEEbiEZa25KS%!8O+0;&%HHzY#M3At&yXz*h1Hi!Ex8^ptb#_>t;8_} z_?{7I0JJ277l;CWmy~oHdt0wtOiG6`Ww0zug)wtPN?D^6lUMn3t=up9)RsZUEZj&B z>Zc=@H1(f~j?!sq-1+EvTLZt|JM@@DP6}7V^Wq8>g**DEkW>JRn7)~|7R!%wW7E#f zGBbylCzB;s5*qfW{DZ$g9rV8ba^=g1D|!KqoAaqrFaSBVg$WX49Odas+)G72)ZJbo`qhmpXi<) zi$UMDsCc0x#ba1K(0pZeXZgI8Z4=<)(nm^Kxj4Zg-Qx^Zk%@tWLwkMOxZ`kO(-B!s$@z+-HH09(EjpP3M9ahzU_j)+*h z>h_?hUQTub&OCV5?Y$OxV*~DeEyu7mox;^0rlXOK&#@|cQ5v!Y>jwDOMbr6mDOWP_ z!%pXQYyaiWW~Y<%m)i9FD@~)13?}mw@=dnHDa3r;yBdMydSRt|fo$3RYefPst|YRE z7V$3aG~WSp2>%LDI7Y=D6}~3jVgIw@8I+_n7U0zx6ugnpg+8IJj-`zl;?eC^Pkk|^ z>-R#s{=p-`SvW+cDQ7#HI|pIdz)anDBUH>|7938a>$e*nvKTJN-ajvy7LjRlEO9@k z&tr}&u#hh_unbcs=&5(Gn6cCXisM@|L?VaO7$1UPwasy7Tq0|Vl`Cm4Cb~h7ABqx5 zum)XGwcIOSI0ZDRxGWT@QSq9oY{G;crqP*3mfw2Dv;t#2qJndU1+NL+|ekTWH| zfm%Z263DCxHl@L$bg&%MNUjLIsn(ir`9l{*)e!ieg4C@|^uG-_1hQeYh7@T&$KhL@ z(9%MpyXE?fV1SQ;i-G=TY(dG`k1^jwPPSsXEYVftFm@5PU8g-chDRKi^Wc8ET&W5z zZ@#)$@dlYA@X^Z3!|dH;a{6Ft;yZm%`TEF)jNZnOyP$?_z**g?w>Mt4Ubo_J1lm(s zTvq+oIx9=q5h=1r`1SFL)T^C`7;SjI9R~rIN6}EBYA&*VlX$}$QM7Zql2x%1`kU!a z-lmp3ucJ)SN%H|_pgNvs?F>1f zy$6Q6^d$}$UhH4S$$1Eq%vAGib<%Q(->>oIetfX z8Emet?Qk?YE51Di2LcU{=tH6G96CK}x44jkcXUA0p@MqIsYfOBk8~;~31HXUh&3G6 z4BxWy;>tH#6Qbuwo9#)-wZefMuL-zg=vpBAN>|{Xll_81hNM)eWljk|2eBU-EbsRN z3SzkA(kVmvvF>^IN2G^)A1lo;Jih&w@f1SWB{Ya<2FEzdoB@wsk<@U0d9aI}Sgkw- zY9yMb6kKb!WOsf4WsEv7vt4$;d+X2LD+ARh*SIMRguEuhV)-K#hd(cWWD=d9mtEt@ z^2hfmJjCpY0ga>kkLgV~JR6-XC7ZsC3LJk~zPGY`|G_d+>MR~3#SgeZ#OTha4URk@g4~CQoba#_%{e4J#T)tNcEQSY;%(`ly?qE*bNHJ3(MsN{ z*PVd97oc(2;O9R)ehP8(4}VyO#6oQ=SyA3s{EL&CQmWZ7wI8mGG-@8*F1DE|eI3;f z5G^$<9uK?v>zeyzsn>tP4*B!HkPc-~JcG)4(8WD`{EwwW`+W_$^?FN((v+=XCh{Tp?*>S4MC|ZtYooQ@Zm}y_gz%{>3B~rC+d9I>s?QtCG@SJ#S!23q&O-z4**fQlLW9pFEAJ%6aZwH zuaJ*2I~E-{!~IG_Y#+Rzrkhw(=UtzT3@SP?8*q6gw$^>z>U_Jtx4pIfqWGz3b+&i* z0jcuqn|5n2c_$B|2Ai$jz19Z&y*ESq>>0ALZf)!b#v(#P+yfvWZaU3K3Y^Ud{iucM z;&O7@WTMN}RhDHu`hj|cvtHCL?}D#U#qGakfia>sEW`H>$>h+vrzLV|w4}ii*oK?$ zWL&e|7-`Rs1+c>W?#-O$3TvqjYVkTs2a>PD)<3#PmY*_s1gNs&j~WqK0ur7=tLJ8rkm00LOlHR1fSC*Uz`^j^RBrGDa64yUcn)&FDN9 zN~vhU>%0LaB`ZF}q^}CFIye_{R;n_hma-1!00dM^Jz9FCz{Ba_r!-%Etp8OZF7>VB zo1g#iJNrTV(;Vyvb$6a6X|yzeCQaK+cAgV)>6hBxk&}bFj6u#aur0_K1$q_|tuc${<`uF$|jwfuVhZ=L_#|E?oBz`@hB+TdLt8SaZX zQQ>Zda2o-09IeYWyAWlqtofXpg}SdTP_yRC1Ah=k#hF zGS2=Ofx(ywqGT(l5q4DJv#vWp2?_~SbfTh$?q^JR?03eCSf8$>Ll`nW#A0DE%9`q& zs=C$rWX-cZ4d1zKOjoC@i{~6WtY3+Rz|&5Y#YxOPCwCWQfV)6tI{$?dDLq8VHqGP0 zhF2v}HjgiC2^w%`0{al0!SIG)>n3k6bVPopzm*yopsJJUplRM4f}>n z%EQ+1U5V8P|8m54tXQ=-Enw7Z&QSO`8-rGj0F`;ijv1&wrZS&BZ4Gk<$UxmT$&q&#pEEMHnLSx0_rV_nbcqlXpYVGpVMG zTg!1I(SSWGuQAhJF4)dHgQ)h3e&H(W`%6%XT2SeG>X9D2?;yNl&kipcDtB9!-29XE zjpvf<)wVEKcT@0}?={0L=2KFPa#DJ{0b}u5(39{lcGTFjKqbO1_MTe~8yfVk$io8A zKxqP*B76iPwEd-|U0^@gkK{HD^^dK;bY8Ngn&ol?>_?KO#!pJ^0cmGpkw1qQRPszO zNh0jX4YMph@xUDb0|#J-hTj0=5$5Aet;~Y1Vv*|)b{X?i${zhuPF%8pMh-eqQv_4LzWY+RJK>4 z0j!&tXTlUqTYC%N;Q)cz#!+{58`U|&&w{(1^KS1Q4+qCM=ogsveULfV;=U4FOWS= zRUKtnCEpgzh58#BQ3zso!x8{+w?omczj_sP1vihF7ymfCPM;r*^ydqY70q|}h@04{(>lHA^tElv+>Z{B)?nb4Yua&FOjs=9GW zO)X|XI56vGJ;|(kYZux&)|Svd^Qq^6ABem4CfuOePMf#dTCgqJJL!P93cPi+Pfv^H z6}&!%quYh#W4UD6SU-4-!s@Qtx{Fx@B}B(U6M+#yR-C+p8+cj1U75sk4$qJQm{z)^W}xyO*IUwtNjUlJ~aSk`AWU6AY6M7QY?a-at;b^%A zo0oU6W|N#BE=mU=a|swf#@V%8l8xG^PI>3%WU!PRa06hqxJa>?C<}jJ`3^1duUg0< zKeoaBnHyw0&^ZJNZf{O#^Pf6Ah)?}849S-1{0n&g3IAotvl0SeMwNhAF(8+Y(@}ZE zMGlT`q&cX>0%7_Ur(C8GB5;T%FS|<-Wlm?-ytNIH0|=7T7q%VcEtX#h{xU z0eYGa(1(K7v_O2QgTMNt@PIbQWnBA}H$Q;g|D???pL)z*)FHY}IoSf-q$H0o!L42S z8TJCNg7HYDVpqg_Cn|<$ZF5G^Mzf_@Bb_>lNCa`jWcB^!as5)>ee zRP2i(dcjN748=<+fgKXi zsRS%Zuc)9CxL-FO_^))lh>NXFG!KSxrkk!|P42Re`&POtJF*ABb*8!ahI6*1KH>&p zxx7nNojH1~Vnjt}p+U58_ExvgsRR_=-?|T?gSk0OVy6XYBCjMH=cX_y=pX|?@Y(}x zGA=?|LIa~l;u*nIeaP5e_rD_Se~$HYU!xtXIxt5C^}wR>!dc6;i6_J}te8+$_u;q+ zT++RM9lDPuShu7A1HU`#Aky{|oON7S`+@rfw@(yjkRN$VA;4~&j-h&PqmJuo@%V^; ztQ}1r{P`Y_SiY6QZhxA_jL&+sIds0|ZHCw0^^!ol3M=!(-^c?dW1o(zOZsO#%_AK6r! z3(_evo^)9wKwtTXtQ!zJDEh^6CDZYAL|Y|nV{Q-Pd4t8b6ujy1aLSjZaxyt537=vd zo#dy{jpClLp+GK2au4E>xLhJk|230UTTjv4^1=9-o|xMME;l2QY-A`hU_?ITPh?>$ z>BXYsD3iq22UJHnniiYeZGmJYvVjpB;0$53bgO3G$QWwMpVolCoWJfIL`2G$Qg#S*b#;IuNCCsOyT{N!)b%>jmYom4 zQXQfH$!sj-IAQ{#DXWCIq8PSH{Vc!=-7XvnX# zOEi0&(Ak1bW&KR92C<6nb$loE5F|W7`}OrLz()AhSQiz`s2Bt~uanLM>1x4Ee>|An zxr_fxhN8I!2=nL7spwvj5=0VMFElxJ=e&C%9@8SMC{oG~o1Jm3YKsO=665R;y9=`{ zu2+TClArL$PAbAX!+2b&o0!o-cm}k;slL?=pYyjr9ppsOa^QDbb5Za+#7d~r;B{H_`ZKQ=^rir(7#&5{29Boc<({h z+dkvuTp~VZxb7h%1k6j4z)yIYy)4vOPI4C zpZC}L_!D7*@aqEJ0aM7IJ8p5$#dW_AkD43B&Cy>@BGOi~{+JI&L+?0~2lwtjgtNDw zj~jIzgGnpePsQ-&avJ)H?ZKS}w}_E<)HKlH4D2aQloor(Ctyn8uSUJ>Il{oiw+-uY zi5ifdOF2z+U|@JhT%;}#d^kX)XOHGnwOmWQACZt#;AgdA^UpxmJPSclUO_+1f-H+_UeB{gn%p$?eE-`vF$V0Y52O>d0xD3 z?QOh7XY0?lUTy7vC)0YqwZF|FpJUARVt0KH0f28_t?w1PZ}xU~+N}bMbiHkEwKra^ zBR$sU66S*Oi`F--?fn7?VG$FVE`8_Q?baR_lC1k#3o~AS_NvA4T(?~L<`!ZJ_qoLI z+XgljlYMo!Xz#W*w)jiyZ!PQ#TwU*4*X`DSzCk0rEH>9)ufJ%uU9Zh+b_=Jr@n#Qs zAg}=JP5aHW_WsuXoBdYtVrOSl&VX*S2#0JNHM>*1+Tr0mFA!aF7vt@(%QVmvcCq~* zoYJ#5?Je2Qt?m8R-rk$t{jHtt+W>@bu~pcNb$q%h8^5#dX3F(r^LF;WW8d5#Ii9=4 zw=a=>2w!2ZWf#}ELmE>VH^Z<1s(sg8Sa`ABdhu%OMQa-&ooKYf&c5Ahw{GK5w=mBa z?3tr~yN;m&Q5c@5h&k%7TYfhkyyFOP=AnvSQwz*9*WX|I~@1%!o;25_Q9!f(es&w}=g#F6OJ z{;;0jHt=Cw(rtMe`c-&&AS+VqHMIb^@gQClFL^QUH-PN*Xn=$0-iVekGcWSzS?dK( zVE4^4#D^DuZG9&XBP;0w0*rj)7Ldq{rkE_*Lo{~`qF=<_khLLtrgOPnd_hqe@!H_x zI5}87rMW!u&2OVbE1C)S>K}q}!~`MW+$oxiNu(e$j6|h`dVP{AX0wqg#&UpTa!r3W_wW9CRZzcs$@)=#zzlk*5hosRIyr_Uv}Ue-8)rh!DVBl$}90# zu;|;;a#SHl<_cVnSBM}h^)j;1*?zfgb8C0es1-v0Sj{@7MD&O36fI@VOSTsasOZ`| zLfuzUZ;9-LP!>sR;rf6mb|=XI7$mmvbuQV#*Xv((bX+bT)CJV=d@r15Q zI%&)~S^RE@4w(-CZk-}-K~#*|CoO9^TN-!vc0_?ywfo=2NABrx=E(3d0gYbOX23;9)(GBn!pkWb4q{qf%>*~AS8p5B2K|mU?taj zqR|(&lhG4)AP5`~fM2-J=BSbNwVQfnVls9Bp)+gZXLA?7QGG4E7FcIEhD+AbtY>Dc zo%X|#G0R2vM4J?$&756>xe3$bZwox)&rP>FUMZTaQ^OZMaxb19!3%ll0h`7qB+4Hu|!3a_FM; z41F1TT3uCto_yg5v6GofB%V$;qHy-oc0i6)uX&m6T{D8DjH>}&^-)5I+~-v-1pt$M za9NjhT5_e|Hj)co_QA2Cor5BGDdOeqty>F6&U>s|loh>@gjQcKTMUIAtdcfMW?`OO z3I?3H>wf++Pn2GTigz%CPfe~B;361kHH zp^9~w1`H$W3h*^2VF8E=33fd~AS26Q+gDM}Nre=p1Ymw(cSV>_iMjSbzxV_;G@hFU z^+6q0^GA0n*OAb8g!&t1B$l1w3YP4&Vc`zFIpR(fC-y+ z7{L6srqk|3uF;v}JbTEz-Kh`r(9HKS{=v3#cRNnA!#@aI5`x3V{Q21>eJZnqP#onV zlib?AoeH!?nn-k|oCKa-NAMq)>wGNXvQI1_uOc*Fu?Y+UV{eUFdc3Ud;_3kGl|MB- z?-R)}hD=1+>3gb!x>)oC23$qH`nmqMrjz?i#do7iu@MoOxho4bi5MQb0S!<`AR!OS z&RY)4pp%RkHEuBEgD~W!)X>5b1b_N%xhsj&dxPHapyBWl`P-c~Pl<<(JT=HN+v`#5 zh)e{UHxt!%0Zhnupc{HCeLgnZMO`ZUNty(K$&AP~(qq4y)iAq9870YnzjY;E7iJ1PuJCtVK$B zDu&>r1@Q2b?g=@23N(6)m4|T*hB}|)zFVp}=cN~t3g*$|p0-&`NEzY%6cXS0#bKA5NCS^Q%6ML{2o*b1%iofoAT>eeHC4Y5h{$>28I)YV0by0T>9B16T~ic zr%d#Q?7NismpzlFa`7U<1pT8$)L6OfEk1bo)x8IQUU_(biQW;hsYI!K7KQ5r6t(`c z=>I4IQstbm6xX#71?4Q0c#-+$3Y1$)<)QMdWfCa*UJ~M%DR2^Hgd@ z-bRd9!nP2SKa0Db51bp1Eu-%fgsZuU6~ND$Ul>H|Q1jJ-lW;9_njB3&=1~4eQH#;c%X1=r1#=qpalz#sI{=~u^nk^{Cw}kc|yIytdO1qscq2;G{ zEqFo77QD&gRnQ9nd6Et04Fq2FT#MZ-X}L8Fm@*}CZUI0KGna!gsZtW3DUhWB=mPlh z!|nvhiOCQ|k=jU6jKzB;KnU@*8RisFliNn5@q-dq5(!lZgiZj~Q zcudFEC+JYc8zVWUN}Y~npMikA#W^VO%Z6y7P<`Okf>D@g z;JQkJjV-`nM>?z4>X9*waqzEoqaDNfi!XGI+Va=Er*m&tS%zuDyrrgJ=%tr0FM1H* zl7uTEcBkH`QBr_tbb>z-#{D1uWxsW!JcR%zO2e7gwepMi!hTQ^+$7k-A;1}6La%QF$Rf5RK5j&oB;RUbTM0{<=kw^qD|#}RN7?ur_vI&bV;;)gFELJ3 z-lo(TCAVpw`PD(I!9=V?`aK2ur^Ms_oBS|tmKpuUVEXd%(7R!{>~N7IhJU2^OOZT` zUzSJCnTbo!bNh_(zrVXdKu%C};FE??VEL8ZAgT@B|0bV>+_q;p?f*(Ig)$kgv)Sv_ zgJLOI$=^l6A z!(asyn#9#`cGnw)yz%NKsw7e6@ri~nAP-Rv!lopv_?OzfykN8-V*|qU@RU?kW~XiJ zi!3zT?jXJ8v?RjLu?;7-4(TkU?BxF#vyjn9)z=s~g4GSxk+=~R9tCA`KqMN`i)bUR zu_DM2GwD->qgMA~@J39;j=s|x3@0X3HwcnD3QiXdv|I`+T4wUO(1KOOmeFGQ-NR+) zMeV48tsoaNL|G5j1HGnFCopfVZY)85mkIugu3zzOy}6rI;Ff+XUm68#NNp0n{wWSq zzpA10#t_Y8uZC*Ai6EPQ&h(MFkxeRMRRL7c-UaJ@rE)b{S4=9(7XGMfa%Oq=Wo=+> z-(;+b2r5*L)fT3G!Jogty!5+1=u`ATY5lJ(JV(zzdswYOx+X4%{wR(~JNRF4X_Wsk zegZ;87PGTAnxNoH@dElnR8W3AmOqzHrX8&IhIP<&4 z2nB~n<2b)>4U<8mM$ULJO6HRzTW+K?!sRRJjB4!m&W7oAFqtQ&Ugg;l9$r;xOrw8$oeo-s(BaU(GZ`48y-beS~@b*6JgX4IU(tD>)%s zeX!;5;rxpS*DgMdC665th*RMr7-(*{Bw}cU?dRzTUy{sHgJzaxSy}ui<9xJNCH*`ZUJ{;M9H{v6zcv9FE9is6j+M2CE9OABi7P)Q(Qw2?AN@A`{#B1=2q?+2JoHUdb7wiF)9g*%sFwp_CN#c1yRmiC$*D;2WNVa1K zHxvK)1xOG=WoWTEgdz_I>JqmHcM>+^k2HPArYJLqa7+YDA{bLPWP)TjM}2%7N(t&W z8oL+>>&)WY*9{Z=^wO)W}9_3T4j4 zGY-*QVPERv9V2u)hnL7<)cNOSe|)7`hf`;_hT92=`StsfQi6tCyf$)wWsO3-u*MI& zW>KgxQo}KEG;YJ6lFc27#VTx$-!_8V4I-kijfQT_5eePUqtdn7v879uSrN_P{InT& zJZ)98wZ*0F+I5dDpccYv1%=*43dS+sYL>*8l6bgkx!MF`=ja=1B<-+h zTm3lwct>jiF6niv1uC)2$dpX;GgI)`wWYhjo({aay1L*F;Neqn zBC=sP$_rGDyPMR6Zmu^hsi z=e?P#NV!CvZxkIGjg+4bVamyj^`3M0lg_^o9an=RIj|zNZXHEz)a0PoX(;4{{FDsU zvWFEw2wVwSN<@F}M(LC(OBPP*GFx3wrayU8QkZgVplj@BL(J@SW7~?CWuZMRM?&Uvd;L#d7$y}w@nN?tZn|*}5+}xR!6B`SSv0H8M3Ob9;cL;XOsMnH8v|^o;8>XMc z4idM#7=d`fP<77OfD;S`M*0fud10!z>C!Y7YRqgD1w|l(YmHM$?_m!St$TVFBJEs= zM_8kJmZ55$zQQX5UWxT6mMB<$Li|XdC&dptKg+~!68q{0VV{4z1mEvx!?W>67!G)J z@%Uri@E6*b^h!eOs{Qi)>(}ou&s||ERBZelbeM{~DJ6%)C57+s{wuzy-l~*{5E9F5ZV@r;*FEB3**6ZCa5BJFh_To=5$E?MlF+Gjo>#Ev-OhG?cn`ShPpCXSL z_*q&^gA(|kP>y_>l!Q-{vSpIsdP-55_+Sr%D>CYdg1c%`bLbzoGCVSoiU@=M&Is0| ze~*10R*bPW<8o25q)Awe9!rZaLllXLlQB%chn3)HiQWkl)yu{3Zb#82rs0t zrQ-(^cKS&Ro<1$a_S4Ux{P2QYz|9kxGQpv=C(&~bqy55HtEoIa;WK}7&jOSAM#h6? zwvxB*X$VzMXYGzAe;M;n5m%&?qlbSHC75G>grp}Cx`Gd953H$^h8D@@0mH5^r<;Nu zQTTK){QL@1dBq1FFNg7{ulY$s86q&cNUVWzdeaqt$g4lUQMNGcIBraDr+-G=hT@}` z(bSmlfh*6)Jew$6hy#n1vy=_W^GBtE zq^1ZTm2I97(kD6vxbZd09DP0i18xV=|G%C;GR}Y01XJPeCr{)WCt_F6rieF#$u`z4 z8qjAoy0amIl(aidfhFNJg;|{lw&Txuf^A-}K|R__UIS_CtN*IkaDq)+)%W8MV>~?I zVKN-mtO%8%VQH3?zkLe7n)>^P2*2?z+LE|`rpQn(bOX_Myi3F3cPi9NSIpGFCT8G* zMWf#j4hs(s5q_Z9hBAWJ?-#?-_4#=CDjwnBLR{r&-QNu+<9j@?f=pU^ znTeiSnNLRX^*b)vF8|>y#6hR$xuWsM$?X`A)Y8<)Ndui0-i|l%yovbxSr>)%?(y;{ za+Z3Nt>p)C5Qrx}5$^a)KgPTf2OBea_6G$)%;xOvpWAri@!gNKM4!HULk~kZ3P2Ns!5>K32M7m?TKh05srWgttAu=o~i65Z_dLc(z3+psZ&p5MEh8QY6Mp)WK zxqU|Pi=LD+1xS2}UR#|bmSqFcJvI#p?9jTZ!*QQ^#LRGxgh_f2IJH2L+jEW`Z0q#o zZ5z*Q5}f9S?36{&wI3UZ1_GH#3yKFLEFfUz?6c&lUQ07$bV5oU2p~?BcdQdSzI`d3 zKa{lNb zg;j9LxHreFFYqDjWDp2hF*RPFiOlh>pgcw?3#DrBbMM9`|MrH2W`k0`0`DlU0#@5boq zkg|uVYB~<BnWRrp-ZuD4lWD994e8sg+b;zrAi`x!+>*} z-iOpfF&mxPjrHi>uh;^}nIWgE*oOC zSb?OP^28-Ar&*;_?7-Nm_{_ZYL~ZFu8V@OTJgq948nc>O8Jk4eleovb9KaPB8RCq-5BQM--0?`p{ET$$QPU7Eh5Ns$dft z69oNu_tN64Y?S6&quM4>4n~`-DfB10e~O&xS)^6~^vf_T*dHSujc1m$8IdrzmOMxn zxr-A~N{yg&K~fq>jp-+Al{x#2Kn#w4O+LY*nh(5U^y3kZSws`tZVSeB$`d9vZEnL2fLrFF|jz!-;$4Ytm*K`O*Zi(15cx5LW z$c!ECA)m2YS}h>cZjUQbx|4H{QH5T8!t26xRRYF~mu_QfIr2KkNQ{xACZ?ZAh$0L$ z0TJ@KoqQs+bo4p=5RdTe3ydot*qVKV%qq03f^=Vkwlt%gOkOY7pUNR5>*` z|6S)nnhkuW-EFAaKa-pkkGQ+OF@|IkNudi}$NFYwO>Dq_LcYi?t<;H03x< z(VpK92bhiuonhsSDQg%`zEE?;+Z+SRT~eforG((R8PgE1h4yb@cJe8kS`(_*q`a2K z7}_nBK>ow`6zSp@MFvS)WEWwhF&hZUW{-{sDWuF%E&52hugVt9mDi>aN*lzo<-Spx zG%{!j6hS3)Hu0(*Uc&X#90P}v&mw*0Dk@#vLXYcsu#{i7r@z}stEy9oxPn!py2~_y z-8q055kE&gFi`ObRaP2oa4sk_bLWu87Xu%*5Q zz8V^&IJI!zA+>IH-yRL`h6|H7^K+9ip_~v2&3$X}`tkhji+4Y^RQ#p={Qdds7iq15 z5&97swws+9Y+9dJ6>x~{@VHMI?FbRk6L~c2=2+nW<6wJ#N7HnN0trJsC_}s@PR-lM zZhgA#>9Jw5q~UnR0}r201jV^Llj+F707;FInvk<>Vh$@8L^*Nrd9oY|;fBaLt{gS- z2)!Ct3aRL=5VtfI7nq9^vAg3b&Zz*xZ-7#7_UNp~?1-VrNIc~9a(UX?=4^E&7z%_M z4#ZnrC634#NsVyzKhm+evF=D=>Vu{T)Wz~~*O|)uM9d9XL+QEBG!}_t;+UaWveLyP z1FIzLThZa8(5i;zM2c1ZqwbD#kqB&)^zst@cpC%hjI22T8QS<36I9(WP$&{}Dpv0( zdOeZ%fkm(YkqBZFN30wsna+9>_RwsQQl!v_U|UXdQ*M;Dm%SZKdH?BEnr5&u8^PJ{?JFHSB`uHIdmE=G06W$;ezK6So%IOjCoC1fKNr{rs2~?5*$lH3X+QP!PfezCG&?-#=1^&%p)C(U8&r$5znYQ6{Nvsf{`Z11(LcQ9O)0slvix=3P|JgjjCy z;wRP&SUb!k>~ioHBb*nSSd=_Sw``o5f3BlRC~Fzd?(o#+NQ8iUlM!9v5Er%dt_Z#m zy^^Vdj*@^xs=QB371#;9uo?F{6jU|rB&Lgu{FC=OoW}ipkCa5s-Y8jlG44(eo=Net zPRQ@FmoH-lk>-jhxTcD6EYEqMgY&O3e z&R@hhu7>XSaYEq4>^3HY0ptt)liM%u0&Tr;gt>zwOydNTRFON{o>Mw6{7h;LB@;L} zy&N6n4j4fQCX;?D>#P=nqroQ)o)oa&64LrR~e zB(Jb|OL|&<`C2Yo^FU*qnHZIe#T&&8m$+=CcXpg7&{dWyAqer%LO@K=uR%~KnDJ@JjW)*!SvTEcxDUFZ#5bG??@YQ~))~H|O=bJ|l`EI~Q zbEA2E{ZLNA$2i4D-}_8=?yd_glhmY=f>J;<#hIW?8fbj|)8D@S`MP)vQZY`XgPXAi{@|Z z2FPf6etGit^c7NA&QEke#E624Mk*8Z#mUtfeYvyUJlxzq+T1>fn)^?-x1a3ntH_se z{_zaw)VLtdnUG#p^R8Oh`!j^xyu0{>9{M41+Rr-5-@1T_f~IxVj}8lq)NZX>Ud&1X zp3FAkM1J(4*^0MrkVSb!bo{Raco*M6x!T^!c)>%eSAe4X3 z7))m}`Z>T1F=ucFDm7u#GuMx`BWJof!HIEGZA6Y_t_tIBp-@*zMW4ofoD7vaC?&G& z!re|%6XCDRxl#9-VU5`J(d52BlBF%Do-o9JdV8qcM@cPUCOVuV%%(VXnNf?eh~pJ8 zBIGHwg`<}GHCv@M4rRzlw65DgE*nxNLf1$n;y2|V@Yt9GE7=xEZT)aK;P@tKa4K`f z?s@@1(Q`Ed!iGf~!d~UlhXh3Hx($>e0fCVuAbu;7fXz`ZCy<2X#HDRZqJXfFM4mCm z4n=qnx$HnN2@+|Z>ZwmOE|+JiF)0&IqLbu{WS0;tT2RtDmB1?2T?TETrufWcPRLiS zL+K?+cdtmg3WZ|O`CH?08JCiE7P%5~RfN*K=duj_RFH~gmo;0a4u=I2&0UVQFmgGB z%6fd?y5}>E&+UN}u4kbyA>iDuPw$lB+fXp!VH2oYPmhPw5a#*rab z%hxF(P#?d!Y(kC}V+9hl_$rW{<5D3h%66Y}`GWWy_`36V3SWjO9jYWu=cCMi$XV(T z&gC2Obeb1PG?W)%O|yMV1b$pUGM7;ZSRvDnXFc_a2Wy6yQ`AY&sSk@ptr#fsozv@> zf=oK&GHTo0OxAu6;aDLYeZD>%_eRTpd_Fi6*8oM%huq#v*>ZvavJvT;piD3M9)}SO zDDq8k0wBYO*d9=Tu>KVsM2aOqUtAJxx)RZDqa@?jRs+VPKbbYuxY1oQN|ZoAGZ+Q1 z;C~JV6&;Lwx09%*YocI&M9V2358({;@3>llJLJekL1E_}is|71o6fNQ2S))M$O7-Y z$7&7jsrL7vcBCcfu(S?WKA57vSF&B99tWt;N$kW zw4263Z-#-ZhT^p`pY<9>YaaT?k;Fo|EH<8mX~Ohrx``B*2IstNN|XYl3F+XRcDln6 z?v3D4c#B0Z>KQJBIhfP%HUYjgv%CvH&X*PD%R8HZ18*aTOcAFDz>QX@fM;X2fxU>| zAf~<=b`yg`f_At8$i*(#Vcmpv(9VK%1bK1}$^Go;y09t4Rgo$<8zEj_odwNjZfJ9A!CGj~v2q2WMJ^B;T4-%p3+)@!>kKgu zcht^8YC$?U$4ey|u~v8uvB#dhi4({)%5!Avu7KABPa{W+icgkSAmE~~h`fy#RCcv( z8q;#Z@nNt?yyJ}RY8|j)EwnP$7l2pBaV<4*pl!^2Mi78lr%v0bEpQt%YBPr5O)sez z24os#_0eOzCU_e86^`guVA=%tAV)chRgfFt7V^uObMgaF&qPaW2pwn}GaR)Lw5~sQ zX~0d zIU~)OZ3H%fB}!GaPx?rY3=jx%Cga&=hg#cGNn^37Ty;KA#*@4I01_VQxX?E0%0?>F zKJgc(X)Gu56u8YVJ?j=C2X#Bg5;St=5@-+JH z7uv%89!4Pmtw%LX$TZ68W5{?-@HFxkE*l`wvI5@@hBOINL(AzP^KXJ%$bYFt&{Ps|Fa8&} zQO=>ukFhvW3Luu-uS|qRrP(kL>BoZ<0M4%p;~3bhQ~ zSYARxBgi1Y;nLN5VW7w$^6vBfT|BDV1p%Fb`oHPPzN(lRI0Nw|*H@`NwhBH2eGAv4 z7HtyUd_^TnW6B`Oo~PD_sxq^&WRUvtFPH6?c$tx3c&SRsLXtt~FK=GA={X^O@2Dyv z3yDkU9P^t}^f70vPQ^3|m&lvWw5?i|?u7~LBIbbN`HOjV>?sU32@b{tY_~j7n;$J$ zg%&5vd1u_HdNHD=ndjT~RfQ9INFL8{GkS5jyW1P=bq{wB4*G{X{q6nzop^Wms7HSu z?=}x)=7UNv$Laq9N!2o$L8gXJMV^ZMPN!1P`TQxJzrW_p2NaH?Kiqs3%8tO3rt+eU zV(!`i#OPDWGXd>f#FTexBbh_NJ0=5^B`7ioM6R}xv7Ny+0%?+8AE)#PDc=qgH=m^( zRB{DjryrRHV6`#15GhM&h#R48owR_vbx0|RXR2_d+8u)seN~(*rHoo(Lb<*&xPk zI=;cj>IG!(SW1~}euw+qtXXIyRhe2R!b~m)Y7i|5zWZsgE)_&J6gbR6#zrd3fZluL z6ENoR?%$frqNb@%T)Wo4>5Md=vBn5YCvfvA*+u-q$u8;-rQr?ri$$TTI{jw1v-&{fb%Bw5_@1*b}QDRU+lEAdT@TKv4JzM@%~7-AeAbOkKX z+sGzdb?Ppr48ku|#^3!V9(EnUcf7tv@q;0SjlD5RJ&W}(mR_XsH8i?XEbz-R7ZY6L z^6qCeb^S{*8wSb}tngGH_AZg}Q(-hb@-PsVU;|I{!tutaT&qjH`jhprrO`FywFCV@ zH7@Bj=#$Z~GneS%zDBrihI2@*$ou=`A>=R5y^mNm{xz?wm@$v)YP=2oo2F2W(-zwt zjcwhU;h?X^qaK$p#%7vAMNX$EZWw<#Hf{7Jcoc?Q>&kkD*+E*0oryR8rWX_aOVO%w zfrll_5S~p?U;b`Q{TIkekiQgfSgwb>L{^6U+SX87jY|^Vc}=nD&S*_u4RN4RmSm+B zdyks5(&=A{w2znovhw6t*}r(!1<8lTTArc2aGw^3{v}W@3Ta7pex&jxr?;q?zovkWi79|ERn1-(X&YAvaTuQo9#C8x11WqV zOrQ|y+8D5K1rWbnA8iX&0O{7p@w&Qgp$Z^-zfbq%|L{#EQbzuu)}@eu-TpO5Rpb5DA%q_x#=UHKnYczpH@y{9Qx9<{@7W2GFOf z=p}Rx0UQ(0aci?G1r44<;{4qz>jI=?Ajl!}7Kv3=yCGn+kc)~nm3(=1YH6pZpXwwB z{XO&u&o<2N^#@fHN-^4Sa20h-5x>BDC@9+#uQXl`6Dgd<%t#rS<)&AXh6i6T6Y-3# z-a6<@RAot5Icd;Zq)y=_?Rg2}>rn#DiAGnfh50*#+Q!!y#H)3_YHxZR1yPD3MbOSVATBtN?yO zNg*jDhY0y_y2O3iiT47PrlWuH6Ex5ilKgXLG(--^ivGUts|Q^M3sQ}6SVB2l@~;X5 zDj^#tnnIG|d`6$tP;7!j$oLPA2v*@jVwPt%4&oK~LY2fX!xteg%U4|eC`S*MEhvSt zG$$(^>SQsKAPwh-HfY$VQbEu4X;BJkI6tRy=dgC3yokg3!a>E_S#oiPbMuN$)z>>_ z4$5#|E)Y(aN4;yA>L$K$E)dgOCldy`A|6QDS6>GVEJXxKlSlDl4MZJGB?;>d&k75V z!+}Ow#LA219TL4MWntF27k{k4g+PGCPa`X$|9Uw7umV8>4EHC0vzGyqMF0mxILa7VNYnlIIWE_N{d>AiRtxFgwl%c$+edYLu*Oqnh<3(G{ z6TL*Y(u5%dMPycYg(QYRLhDdCNl~LJB2D^WZroQ8s*5Uw^y(ru6uJaKEuR(pTUOk1 zp}4-5zx=R7y}p%HSt4rK2#ZAF@^R6bt(6UduPhg>c!Xkql|pZFAe0!?zY1d(C*mno z+_ILB8{E^4YxR2--C%@`1c&i!86HFp10-O7L}k}XmM+bRjWdLsO7UG0Ru}!wys{%2 z@x}2w)OxIXexYcIt}&K^ehCO}S>@nD5;U;{5nRdMh@liTHKHK0D?|xRq7qFJ$r*=m zRZ`W8V~VqA3J6=+G8mw9khyp#S?r>d4=POI1XwuK$=^Zb7enN?8;>Wh%7Ke7fC&n~ zBwVk?fQ>7FIE6u|_{X{!NaG7;0=NIx%Y}t7hz+U-v7FH%M8b)l!mEu8_OW@$1K8sO z7tYyFm|Kk}AI1Pi)QM`Jw-)PSCJSpBhI}1bO+=b2AL=r!C1P5WLTS!Cn1dMO9e)D6 zN;DzCq9O^&CmL@6Q_?L=fL9y56uKZ57Psr8Z{i9ej-zZ`dAM5}11Wp~OeDms=XNGI z8p*Hu37<*3YvT#wHBFWTxkgw@64gDkgt8%td=D)FF(uK8drMSrz1Q<;wYiZHNg)o9 z43hT~1gkM(p$a2SNtKK45<#KGiy7{XR@reS>^Hyx(mE}Kp?tg)ci7g%go!Pb103Z# zystbQjWo^@+^lOvz=S|mg7&Lrca7vVwh|n??yQpojV+XeS2t@{h7`(hUe+}hxU|SK zER^zvy6Cs2d1>Pd<$|ugt%(7RDwH-|u38gqjjA+lz0|I5ku(z;X8<=;CY<(iYu%<~ zAT7a8vhwK8tR^7Ek_T}HTjF}r%JDpbM!npU7td1!t45h5r4SO*>0gnOiKRe@f;XmD zB}OT`W@5=A7~jFy;ZdWf*oz|Xb8aqbj3UY-APP|@X&)zD$^hvt0#D#Aatcc$jidwz zD^X5>D^U!aoBmEGq&1cjJUCe~xwgSi-@#CVwv$m(fwqI8fOd;@G?a{JU4T-al?5D; z8N#!GG6=k13`a--SuSp0#Utc^<#MglFRYAnLP2$uC5Bu=+L5bDMXhO=3v zqde}DjirDf1wv&a!73CjG`S?tsB5oqa5btvY9@|cVo9K|>cAx!atUFBRFwiii%?_p zvjTQN7ZJeTW(5L(&Lx276IPq08bL0Zw-X%te!fR(6I_F+QaX!gkBudlpxTO56`g|5 zCnCd!m5E6Bd?K?+57`vr`h0ae0Qs9}a!Fpscaw#dTM?Z_%KX$rhdoxa-j7K>6Ny3XqP2lMj6A{`cj4F&tB(cX#rs z@pmBFoHHigHzbIuSiVdMN3hgF8^+4%WJK9Qg&Dn-81f+xWlMEyZPH03Rh9+4TlfOJ zXxw2;osE|?$K{Z(jUO9r7%Mq8rjoMwj-e7ocV>`y73>R0!bKb=i?_==6v6od?6`=- z*b&eDegSq|#9{0R8~6p-aS;cyvzQIXH(!Ds2XPoXSNGHS^fvB&xW0ZpLC%l?uq7nlYf z+?h%kXd%Rye6tv7Lh*rB=lMfpopDZ?l~ z;q`tt{8B8Y@P{x*P9WaGn)I=1ubVM1?hvNv)vqOr;J%$KUQY08+`1Xd#2>`m5@z*o z?TU8kpbcT=Jzlm%xxJ5c;7h`mR(ajxDk2la>TF0-r?=eJ&YlN#2utc-UqKbi;Qf~F zSHpujlOgpS$n~}G|JC0stw#z;!^WA(#O0v3ySsb55>1IClZG(yEu7$XZoC1zU_o1$ z!suxiVWlowgf+@c4q)q*&g;f2(f1+Dr;a^Ej48K9@-D_a`jpBk+aoZij>Yw7tI7h& zr3$+~bJrh*^L4tMdEea%)<+DB$qL~Mr%nf7Kg5)9uz)-2O{S>Ih=V$uCtPfjI~YzQ zTIV=9sKa?;-FKC5ot$|I;k#i7b*(A zY6KlT{t;mkZL0RU8ZnI_gADStU<19O2|X(M7khXlXcl5VuB$Ta;-Jru_H2BE*iHqk z0x$!q3LsR$t6&RIx66b+w7~T*mgEy(Hw$SIGp{E%!=6U7O1BYsHBl82b~jopk#><4 z5pUg(7oE@R>9&Kbi1hpMhcO;Q!qi6`a6KIOQ3f(14xZP_h=Veak*gRL-ta>0T3JaU z^)n+lPL6UbD5HzQPv~{$uG{a3wiSq&;28wCj8GNS448+sT~N+Pn<)K@WvfITpv=-! zZF8g41RX@VJxmtlRjIm|a><^LM_9{NC23;GCHH2@cN12n zXQ9a@h(xLWk`pjou~b&nMmEk|R_O3;b)7P?WRXJ&?kdg{R#5=vA=TclXj(~xL__<# z0VL63WL~XG(8S{JVRq`Yp5yu#YqASKKhhRQu`9?)0OlcWCknkHm4=JSPgX5x6?&sU zGZ0Tc#N**VE9vZ&f=#0y-%PNx9N%1Dx2E?!AJ?Czo4wIc>?l?1%{dx#8W=%YSl@lV zzl*(rqH(u@d{}(h5N$kQxxPgJ{1vL|`}*L5Qag+M#T=JsFnyBnTlQR<&S#C$IM~IA*)*0wXWv;JLl=tpFOUqn7sU2wuSkTPoXr7?pX&=IW5UtDjAE;92 zkDku%dc9@bn8_xMk$4UU5nBOciA8-#;VAFh=0(`}rb{-;HquCkUTYMDn6glZwpr2~ zpH3zphTgbDA!-5Y=URN%{$t0hZGos80QaNMHH?MWHFN>;_N%L_3!k=yQ)m#15HjuE z?Y%XSY5+|jx&8H!+YcmnupV*;LFD$fx7R@qXadPK*F&xuNN#66mj!jN^U(yY$wo&?XJhF?1ovD{q=ZaKoex5_qW&5JD>?9w-%eZ zza3^X_qW$#Gl3?scWbek`+=U={(3wypb6{UdY0Gyz~xn*dalDglBkM$c{S^d=hMk- zu_8^4CzxQn_x|$rx~Mh?nVkHfs#USAw^Gd>$Sn=dV z2G)FLa72itp}4Q^6|BUAi_9X8*HHSnjy@VnJ}RVJyf8&srifmdbXDxTd9$CR}F5i4wI z(c9o9m{82?)ivmfx@#D9+JaheQ&=joq|s^%7bF9R=DO+%r$llCA_qjj2Hp5;OmM8z; zlpqf8uXMj{!19D!!fm$Elu&Lje0esms7O=^vfRERnbUaWy`+($&rFJ7Dv~Qbq)f1? z9y4$&o@T#Blh;iRSh26cUZI>hf?IMW!wIrEMf7oY^O1iI(Hd@uJGK&}06efmI}0c(KXVQ6`G&m1+&H;5RTZZU2Ge1ri98S;x3MVM8Z0TsH_%np2XsH67;;(SBVt#CDPMyWyA#_E{h7DMruspgcP1k~3k*rq868*O5YXs#Pp*w@6JD&iRCs>-80H{hx zi>8EZ1w{>6p0v1wUb?3ySU6GTZDQ`;PVh#G`a7hf83xPsgjs*{b zDvVSju7JV`wr&GGUv5|eFF9~3Y8vbUazhy{<=;yaWGJokAtNVf+HmE`iY*gkDM8eL z3MWbTizy;)9FvQWLI{hN<`KL2q&#_f7+9LL1y@KmDfM8~WjB5e8tMV6waxi0spP~c z`Aws!$_(+CIuFYm3@<-kELB-Le;0ISUv_|Qm7F+>s-!yZUG0VqZ1 zHPS3|9*k0Z2SeBfL;xi`&Op<>-ALRFqU>mZfE{`Gqu1@;paNMs>-hi&a zf)In&h%()GK+6+S0%-hNiR=p`XC&AH1~+Nkuwg5aS8qEhIh13-g$`yxuM@B^Jvvc%f!aoK{sRVy zMdKmRC>mZ2l~@r|^<`%`TF&z89A-1)$5DkH-NQ0wM*~%JHH6jINZ?E3aE$jQ@HOy2 z=-qHpb(nH7Rgn*G4lo@kdv~QV%R^Lxu_+xS5buZ&$fY?4Y11|aT}1hqDzFAtV!T#;J69uFMs-ra6&aw%sjAC_xJYBD$VyMV zHL)5uUL+M68h7qilua5#HC8IlYFm^QNWWQ*7Q-pjv^QHp64_WPutYP)?pK*0L2qT_`l&KrX#Ye=i|X7ghJA~kb+DLGa{?TuR*(>sYpmmHap308om-6 zS$Xw&5=b+Xg{2ZpI3Es7hfgzN!&V|M2a9%Efm^^d8-5(CutV2N>Ev5)S<4NOWGIED z5=(B%e>qlM=rSx|0bmPPylqLw#D)o{hB({VXB#-AqaLtQH04MIl9H`UP#8{QPpy{a?mLnnRJs=oaWMnMrN$6QnS%C{c|5xqE%7RrPu96) zZSY*0fs%7xun=-ZD%oVRfM#^2iLl~XYY|U#heJc@fe}DnMs;I@8txMFP=ghd!7eC2fU=bY~Ns-T6nwTdI*khhwcb4PcZ7HK;f)w?F-ky3foKHIoJUSX`)oh>;5>zY@ zF)KCS17$^Y9LNx2hG5-mfG3sG}Hi^$=u3pID*8PfFQS<=5yl3C!PWM8TY zTGEaxx+(ZV!o2vQ4jY~l>V>Z4LU|RCmjpRJqqumqjCPrL$p1Qjm#bogMl{R7BG&rE zbagt-0B313Zh=qF;qI9xlw$5o(BA%&l;bq8C;nS`2`TOtXP}Kw|K*%lgkzr+CVhfln zLB*eJ>qYo>@-BZbPYt|~()WJT8N-2}aXl&6JSvFMEwF02kbYWb053y$z6h@}Ch|Kt z7`XyVnt8bhaIQrYFEpN=o=oS%d4Soso91FeI@7RU=zl1Ly0sVQ`{~V$sxY@csE|~K zsLh66Og~OvEf!NY-%>wv<(_Wt!P?GU-pzR8rd+BmB&c?a7}o4&d56Mh((gtMwEkqK z!jdxLhUg@{Z@IacOi-~DuijCiT)LqxAk#>BCs`h&0868L6W>j+KNSKi!J&jpBSfO+ zaNsR}oZDjomPUt3!ZjsIGpGR5C^HYMa~Vt@TJso-i+|0$&>-?VU&6%WE_`{u1#$(RiT|q8P5iJDViD*iv9eD`X9;kp;8_%3` z{hR37jX1@N`%(8kg0sMpn+FfrGthr0k!FhK;(5!?c5}Pi92^|)$H%*SJNt2`*Nr;| zoo?^AfB4{+2N8azv*AY^NJWTdErz{lV}uA`Jp01~@#V6Miumfgfea=_)P@g8C|nrN z>Kn|*BL)#z3G;9e)oY4ZeddWe{y13?fRN(Tr;&t?5=erciD+rmZofFcY`6Jv)c|D? z{(&h{>)-gd-*UOWi5HSzAE#r~H;BFhJE-eEc=ANb;ZcgK#d0>b+n8KvhH#SF)+0KT z5z=~RhUzqlP|6Kh?Qv9dBwu^vG_04iDW@PRwp9Jm;mD$ejCT1B2kAP0UGb9 z)J;5QHC2Q@Z#Fr`p7zw7jcI)kFo zI>92ei{z?7v?NIUChxPDHAFTPIDUKZn{T31f-+7Wa3zeiIdhV4B&PRi)E~|WtgilT zw_l#WK5MrhfrkyXrAeA4u*9R}O=uxYyM~pDZJGEiY0mR4%PWA|323ngH4!KlWG;km zNkcNy@q&$8zLPX>6rW_vLp`gWQ*jN`K+hmpU1Zy zywvam4u#aN(M!2Y?HV_t8Kq9R7#LAD7Xn`VS3+a7JSzj+G&c4N?=Bl>XT-|ltS+dn-c+lBjx1W zckV`LVF_7zrfuYk|2y|#+wnpFushi6>>o9o-9cx+H`v?m?e}{9gFz=g=h13BceW3Y^Nu3i1=?D#&Hi-b?PmA5+dMel+3)wd z=+MD_Z*RN1cW`jj?DV`(@@DOt`K%55Z4>`dXB&gC(;pmk_P37?2RpspqwT@bpufL^ zVLIH+k(cc`Sbv!mx(5gSo#Vs(!vWYIbPqen2ir#&_oI0CuzAqk&ZFRZ9B@@E7sRBq z-;Xtl$y?(Xa#Z66-&A&lDX zAMG6Pc8+^__)X`iXZ&H}?;Y$94)=F=5BD*r_Ecz`GFF*A0%y9doK=G{Rvk9Wrrv;VYc9Pc0Xd!60E9;`>w(>yW8K#-X0VBcz3tChnd!mkB(po^Ja89n2`F!qO{%Xb`N66YNy{j zK01o`j`w;8-Q(W&-tN)PZryiNO0lLq<#ySlyK?;c`McK72RhGBQ7vklel@9*c$ zx|EyheqhqskGGGH`@66*2Zx9K{!TaUHMh5S_D*hJW~Mi8{$b(=tLQ~@ z5Fc%KVb449?)L6scMnHA$Afr(FHeWlPQ2sQn{~x#m-MxMj|L(;- zOrgU=uTvuDV^$2!yDczjHg}G(UchN+?l*T2_h^zH?H@L~y-o-AW;@RYI2#CaJ7H2d z+HW2o9v*iwIrn2=-`nX7U?O*pd+}lSU~rV9X>;GkBmJ34tvT4<-#rA0UhfcEx8LmS z!a0fu&HnxYyq7$^cD60{pOS{(nH7h5)Fg8YqYoeS@u5Bp!bt(|g7h~nJ{zP%#hqqv z`=B$xNHhm~N5{v5qvQQ!ERs7rN4p(Z9d)Q^of~ejZ;i7Y_8Ox)yKi)wQVa5W%@e?_ zts0+9lyiNVR*?JaqlM$xGCnX93-W_~#40+&Of<+L&LJA=6*I9Q&p3w|Z6M(cJE>^4 zdo0E+#6`{_WO>F7>n~%Tiav$-%6X(5|G1IkFf+j*r#X+HNv*posGL<4RYf1h?~B9!}9B0QbFE)9;vkZ-tf5jF4-WrK8LLB%s1>m z4Px-`*w3he!74NQTQf^Vsbk z1yJTEik0v~=;5aD9QIOygp9AaT&y5cQsf+vi`&kO3jxVyO@A{dRiv5Xn31{ZA0{$W z$1ehO+{pwnWNKo16M)H=7h-n6#P`Pld`VJ=l36nua1+^S05aAn>>aPKThsn$h0qnR z(aKC3X}VgFv~!X|nuh$?9waT9Nn^6e9^~3i+>FXLoLt-qIqFWGCfT=Ki@F^>{mx2S zRv`b}F1-`j)X>iK@Np;3GVhIj8ZGP@4tZr~K}0R67Nz{GLQMzTF~xw$FgX zo>UJ_&DI7nGZRk>#8e*roFETsOucca& zMh~pjZ#CjFnXn9Pl`Oc@d{qOBHTSLIAW6b+`i)K*4ft)*dDcu8~?&P>RB zRicc^zat-UG#oE@lDFs+g*!{M-Zgmz4k+S?TU&Qi<{^Wsvu;--H+51x{rc-$*sIaY z4jfZTxu1H<4X8#sIDyp9MY4_?{zE1w=2S5tO`jqYHdjM?o=nvuh8-7WMZ$JsYZ2{Y z&n(lf>#piwpd(2hY>IM*BQ=mk-Ev$h4+{-^aPdIxyF5I70BJD>+epk_qf?(ty(Xc8EAXdV>+rd>`$&c{W- zW*pmQxarX;aVRKFpq=~SaNR6YEw6`baNaCZFFRE1k}py)H}dPk7ipLk%XNW^G|Y+3 zy5L1x=EPcE@FGn!vmIR6B4ta5N3ChyEYi2^&4@AdJ4Kpj1uC5`>=Y@UC+O&+C{jH; zifBM*7;q6qjAnY;MPshc_!Hl$DR#^P`MS_=@i7N{BU@@m|{)D24tQJCuFvStu( z!7(zd&$h@bamUxHfXcoW8pP>yo4i+wd>z!jSGt-s#nn;s0%|6&B#)Y8fd8@itt2i% zUi{Zys|lSkQRS~0)`)YC#HDXjZ2s0NBRs;zj-+<&tbUqQ7f_eA-P`{17BmVGOy;O% z{p3j(*A?p;Vf|6GoX5B}F0RaHUK;lu!Ke*Mc)}Da4Wtky7tcw4`pUUzXE@s{P*Yek zNO?T_O2k||8RVRGs1hj?M+O-~!77nZ@J6MA-yTO)IO1_+=-rbi+z@(8!spm-gTyB>(=>9z_F&n{NMSl=i695oN*In#nso^cLJaqr6Az;#)15(7ZCVr_1?m zeZxfcm==Pz30bF-7(|kO=I)o+rHydCtbTEF^{U-EyEwT#xq5er3%w>%!k|%XU{w%y zT~v_)^B1o!+J8Q~Y@NS*+dh90efKol-#*yhj{fsMqpy&`jw1j4dhOM#Kfh6}YLDo< z`d4bPX~&;YI(uHP{SybVZL#3+O|&*nWx-w_0KfhkeUdxFZ< z)+v=bmTD)d!;re}Jjt+!a8DcfXKiA??kgfALuh4|KWF_`tFAG2zeVu~3-T`(GaIP& zlA%7jD>}tlTpLTYfqH`)ttf|di*=qbb>`8AZced@4Z3ydN{`_5atxKKCos?)hOmjq zfh`x!gZin-TxQg)av@=^olY!RAEwrFU_1>fC?Qk@YPEc?KMd-)Tw__^w zgfe}0W)@`fHqc)9@P&ZCb*)E6VT*XO5aZ(C=CiaW7D zjil%kl(3H#4|SB6c=;y!G+f-GH99z-EN57fXwjp-H6A=j%yDWOLh_Aoxc`RR9nq2= za|PU}6J4|}H@6@2KYPryvQH8J!X@nRE)+-+hx8*&2nHpvM4E;~@jhjC1on6?dZxQD zcZjg1tJl=YId_nb{^1A8oWZRcosCQ<{3$Jl7LztSppu^iUKdBJF}y-Sr3R7f#YO*U zpwx01&s2-FF?A6vCQ&@5@|JL{C?6EBtMQ;qg9CNNxYpyFEn2sti?fqUe8lA|=Gcup zUBN>7evTJc`F$et3+u9`ni!k&vCxqCbB6}_F}d{jlO?9keFQ$>kYKpQpbn{N9Hqoc zB=uNC;0R)+*)&|tBQQVe&*E`ZPl3VObHW;TVkqDHpcuwCOePT=MjMl4fQ+IA6l?N< z0f-a97K+ut*z(_MNE?KtuU;^I%o;kx{2)ANIF8iLnYu`jdN3Oa7)b&JP6^du0wPg2 zCfgs~3_sFAn*_22T&51+I_4|lQ+w>s{#xFY`;n73XTbOr7r%511p?QWL-$HsX zJKZ5zyukZa;~uRe-wybbXLFIExdqK-i=zO-tWE?I6q6#~qQ3T%M&r|`PvlH&;!4Zb zWOmb_6LtK5bDM=1*m#c`H`IN$q)&2nz+@mxvG;)Js#2KghzyJZZ#-0KM5m>Srero# zqv>nNq$MBQK0fUDe2N7Jw+`e}LmM5YiZRQ;EI{XS`O!UMHF?9%wZF@%!3itFkgf)P zj5Cnk4d-*HBI^>2VwMy;)86ueGny64BHLNJ1lS~q@8fyh4d>AU|CL$?L>nG-c|MILFS{10uP5w|yS-8Fkx5!gM)sTN8Qi4KojlUfWj{r1jtnU| zBD4-f*r%`%$utnC%&ym?WEKSFQI$n%!J<20q<&IS6nmz}NZ6gP)ih|cp1HtKJB>&5 zlTi5g3_?j%bKupW1|)Y-YNH{mOIee4j@1(@FfE7dGwJ1JhzU!pcZb#!n0qm+9!D{J zHu4qd=bNZAr5tivZqO7>)L(Mh!a@t@bryddPL^}5IYfz&66X>lRu@L4Fv>wBClOf1 zkF>}UoZ?u5In8;Lew9GH6`uo?nu}h|P!Y%Mngfo4IU`96<0bnM{dgNwUrBY;NBG-= zCR2;*l5-gznA5*PNXlaR^yw=J}Jvai&hSQibnQH#q2D5t4KqzU zyFqgLuE)G%6QEXQv;T6zj3Zvdw4~)w$r+tDp{a?~ZD(oF*9O1L(jc}~%I46&#x$ls zy;GUKSb^OP(DcM5IysY!AsN&| zCscKNIDO=o)AOJY9X6AoHA&mDzsB8GB}S~T$$|+9$o?d2ZVE|iAOK|#c>d#+mj^s#7cLz7}T)H(XG`A@5LK6b6a zgvuBV?@UC8PuRatnWN6XuD|*HN%!BDPiBAli{SNmJ1qfwTO{awgVCp=@wD=F#`n>L zwh!yv0MUj<%r`~Q-1EANDzz5dABy#vU69cJ#f^PdK}9WWWp*iYz?`Lqb|LoAxKqzP z;q`gVf-Bb$Wa2G1$RSRb5__p}cI^O84(LaFMBcq_GSsVkS4t5woh!}IN?s8Z$LAHT zt~}(YWDc@7J>d6clDDKkuYZ}$m{V7H7imtX2{|W16#3z36-VOc8Ji7u@G0BI2v$q| z%(Pd|0g?mlDxkDbHVKlH{fRJ8={4dMt6w*!lczp~hWJhpoy9C*ZjD1Bd_U*UtWz-s zpk|zw393)a&(v4XWXzTXk}Cj&$KPAxDu|)o^ zr?7K;_}%y1+R^B_Gs$&)9Uz2yu?lMC4zg85$d zQwcU$MTT>~1l+#b#{{K%c5-pLl+FoF3n&@S4tn51^s0fu-xU30#4*C5a@y!ySCs4^ zj+XlwN+1@?Upc9BBRM%LQh*bE##A?;-0n-ukf6o*s#5`-tViFr2lODk$mbi5hiy#3 zdJSJ}N#^m*_mM#;dcujqSz190v?)J~KjinAg6iB+h>5?ZyNl#pLP|7~vLq!((GXRx zc)+|N9#WhkDknsbb>foGm>}cB{Yie-v1zQKL%jP79k)bVERtP@9!XlzW zaK`0dAe61)%`&5vXP<6Y^Iq*^)iCpP@m`F4d{1u}vqbV@29T#7mqADhPMGFPCl6 zgpLj&F~I}tnhLKQIb8I)2x+9HN)<7LR5>{Y29g9qXroWqB*IoI`OxH+*~1xvmU0dd zvMXz85wLEu^2`-N0>QdfYWC^GAO%ivLib@|UR-EbaBhGuz)LTh% zuD}d(p07D0Fy1Xr24e^C71F(gmrn!n363#Te6}2q$v|M2Kw0rxRcNS$O7eTKJSmVT zpOHfEcC{qmw^+3kX&C({F2VvHZGk|%jJ z6;rA|!PbHu0J=XQt%M+=tean(Vf~VnQ-`Otx=4mqZjf?>Fs{OK`c-2C&YZhCp);Ik zHJeLnNDA(eK@x!$h|Xn_<5Ed{?#%T{D_cT&{o8h}1T)Ak3(qgiD06PHNz9m8keCj>s!cb2pqCyR z3#Tg-sm@dmnudn#cg9?}gb;!1= zS;VzbRb4W)FT;G;xhW|%aFtTba~p^iQ+&a9Qb?{lisP_Xj(-uQ;cQXbuZn|e@h%{)1$Aeg*}Y`- zC1-j5yY3H>u%0EimQMBkCAu*69O36ne$*wZ%ew~M7!M%RGcR;^0frsW>XwsifnmXA z5W1wqml5Q*^TwO=s|f!G2<|MAdZjP-no_E1g|TvR7kqj`B1Pe=C1u{ySRykQ+a-9H zQo=HdG8|8rxQR8Jb?y;BRoD4&{R6V6A8|cpLje5=eUcxmZ{JPn$`)J*fYVKyyUso0 zwv&%QMG?9Uc=z#Vz>#|K?;M+ujLFEf(BinSa56XGz--EWpgtuSWk)0uqa!Yl=CL-x zQ;$!OV=`I{H~T}}@}fuGJ0qFvU7y8xkfcxP#gByO;FaTYFFG*A{WZlTOUL;S?hf&@ zmK35AT~w^7bn?65XUxPzoE$fCfryll$rirHG+|sUS{xNY2zfjZOB7tY!B+1B^*%`m5S-?7gs& zFh6;yR3Do^bJ8LWNQxT57j5x;w26s)w>#X_nDli3K+3E6Gi|imi%E;E9~NJYGGF7I z(RyN>=@wg5e9&C_36FLpHKYJN`j1$0?(U zJx&>ooN@BC@(co+We>v6S_eTmB>&1WkcxROExpoH^RkEh?35SmKS4i`uB6%-`b=lS zbs=HCX+t*hCw#BYhP85PlF|_qOGjd#$S9@M!qsTe$eErrQhe}%ZA~(1@u>?bCsrG;TkhYjq>-~yhI>kApPrPTLaiBPi97t=)y8kW2bB>THv z+#oGN08+SWu8f&)v}obVnrb9|m(x`!mQ| zVzIQ;m`cX4(giXnmtY5NetYok_qc>l@d?@$XGQ{4{Qz0!0lp%)r|ouVxd6id?~NK* zRY%h0Am|7m&)l5!J5xB>aAlv_K40w$JDJ*6yZ!d$%~|W>Y^ zoDcaC^Xze)2Ri^%KcUJC*w#inTSx4{b2$k37_<0p@{yxK(eBpvR`gycbHksf?UUe4 zVMe72+(g()oR1f07dSsVxjK6R|3gKZ&Q&%CpV!in9_g^clv3g1E)+lG(bV-E z;?8*UC7#my|Nh?z`q3KRf$48i+f@%M)g@gc6y2)B6)`0U0>&9 ze<*c`dIB7c2OTL!*-KZdM)emdXx%~eDDeyhD|!@F+Zaqnqsgb&!|?~+qnKq7belVr zqJiPx7E=NHE(Lry9OLCIJ`ePK+4-!#r0Q_zZ?D>KPX3a@5r5`tC*~SP)7qfI#};|t zPZn?KhD}Zr9uUYdrwPuGQRHON$!|3u{xg?QA3B^z1))RUl^QFy)7$w3K}Dw^g%&vF zsN|tXC+K`OugUOcjI&Eh!|L>@ZVerYCG^-vs#9)J0FU;#aceo9f-z`}!8tcJf_J|> z8;+5{GhFm1JsFeEs46g=YlNu;U9KbtGBP-gjUSD!<=fB#^Hti9AVqnM$k%9qTCyh7 zDQCjd<|n4h3y3(Igz=$`fRgU_(7AD`oK%jac{+q#;v>@E%OESU+XD;qXL>sWRm{o~>AsP1(9np$$R

dF08X@Kiz%0)ikz+vc5uOiE3A^CnOXg}x$qtiuH6FQuJ~vPBfv(PvXS`DjH#C_ z`KsZUvQC{5wNlSk<``%$xlEOR}f@AjO{Yo-)`| zUlV)k_b>VhK5_NUI~bI z0U7+L9Ri|W@O{1{N0^2tQ9jV=G1ntrSC1KCLUu~*K=YaDp3N5 zk0^+at8EJ7sB`bR(nJ+44O(*BM^O>crDxJ7;hT-R+*rbmB`OId&ZBiWB#9a5BWi0C z_j?5IR8?KQUNM44;3ratMI!#cFN#Om7MUSRIHuSIB9wT2!ii!p;_)!<>remiAQ$=^ zbCmXH1=-(fvhEkOr2!UO(CfFH7?FGs4oNP8 z38&(u%!ofQij)`1-1y<`d%hBZOd{s?e{;ChRAIh!i%V%vC{>llr3%~9N`36iB9?B_uZz^fB@X;4zq=h!a!PZ$=E0Q$JC_T^uNB!W1G@ zvlqs06kj2G1pi_}tB;>NdH449U)$dyzB>je0l_1XrheTN|NzN>K z9WW1)>_BKbviT1xI1RG!~p@v$7+uRtdgyY zS<&4ALmOz&jI#n!vdfNpa0qAj_sQSwrRM{JBS=4vhBlwY2| zPHSi}&4ESpfgX1`6s##6T@aH46OJCS7~{^d(sB-&Bz%Vh%20*48*cR6#K7|*O&X>^ zGeCx8UL9QRHgehEje435X>Vy4pTPjFmGdk>-Z=v>5jwn$A8?-^lUWLZZTaSRKmuFB z)4N`~K?_k&A*a!2N{%$gmP)qJb``jhO~5%Vl6~5}k}1oZWpo`b!d#Hfr-boWUt6Bzi~F*3=v_z1SKVvL`%RYm~h<#;qgHL1&b_`U>`c6wmBhcv339y{pzdW%RJ%o)7d&dr!M6 zDv^LKAH88g>kLhPxidw+4^F1#zInKK9R1IHf$wJjLtx@#RhvZN$G_j}Iw4RG0RXvp z?(RJCH%y8zdR=yn^A83}Q!Pd4BY%o5$HRY!!X#Sh=mvA`S4e}t+59g497Er+$Ra0A z95vE6ORA9|=Bd%d(6No7+%kZE!QwCY%w3UH9Njq_$|Qn)4Ta%fC?8Ht4()DeI6X@g z0k8Ve{Qhbk6Fg5QG*9(3&f!$eXU)1XJq`IAvxm)-m|_DFDNIezEXGbz!EVY}Aff2jGn&PStA)zUnBO$Wkh9ub9868a1;6p-<&;T`rs7{I$ zBGFaZAZ(+d^F@4785Tn#3`I^_M%qg`izAsQwd|$Yke6jn#T3;`iV$|H${=~&@+;j! zav(9tk7W&-bWc)_wo6$~Z^o1ErZgpjiZr2e`4jzgzF`|h-$XUBGgD?4?)40g8~T&_ zoXpzhc!IqWxq@^%f?|B~lW4-h5whp*lOP2K~;~G6!K%PG% zsBP7Fxu|X77fepNjfb#?xPx6dF!>|%)6en{PKsaMKjPRR>oq37{7wyxc*aSqn9r|G zkBvO8J8Zb%DG#K*bVEQ{{(r}xCcHBvHNpBaKWz2F*r=SimNuP8b4H=H6 zTN&^M*ekdhO}g`_{_vZvUpkMwzdelR_t^D*ek21KQU}@G5_Kr>{0D$w=_IQsK0+db z_>8^8VF?| zR|B3}4O0S$Db5YUduQC8m8drHh};LdW5jcTs=9E=TSVV+`|qc}HGZ}Q1mc^~j}%_V z^rf%Aso|0f4KGim&VUXC1j#ytiI~RUe%*)$qs|RN>}W)hLrk(fu?tD0w37HmPAhc= zZnl=7Y@KK;wWA-=mY)xz8ew(y_ibm6=N@N^m*5Gb3-xV~?$#QjH@4{!sG?}|J2f52B6O3RI7q&ME{afer2$KhH@=}c?#pONH)JixA3{3 z>6IN}QjN(ISB*tqV0*bVwBX_!9~(&$2B9*H0%P{A0`!H9nGB=vqHVSnlbJRZDY3}L zVsM9ZIku^0gcnyYq!OSOB65scbcdAQt`cLq$ztJw-Gn0vt#K9`!a+Yz3hk~&Mgm|@I zQFeVo&u)$2L3({64)7!%U-Hn~g)*xYbD7d<;o~Ip-YdHHO8(iamorCD$auVzt!f_?2$H?e@$E1^e6vHn@hqMKgw=9Hqw1LKvL? z`)y`ks?=e@LT!_xb5fp3alS{eM0 zqDFME?e5)a)!)YEfU&u3k!Z2wyd$g}t{1sogC&yD?4obfQVoE#CDG;`IE*&8eFg(q zQN@&RFxY?c!`q4_jINlCG0+!VnhP7akrPG?AI(Fs`=f z6zi2=1@e7r9#r{fVx0>mDnQd8txrkk&Et_{!2Q_gU?{o1K}e500_cBQI?gvc_G_OhQtR<>Bxu z)Z~G*y19@XH#5?-ge7Hhsd5#6Euni19Kr4v{zQIGf6h0XJzJbix4Qv zjIEF+Z!1>m^9#y4Q#2V{Ax)X9unJX?525KM*$<2~J(;ghN0T{r8^5yQ@;OMQ4{-OL@IZ@jzxjiO6n>*d&t#tONqA8%dbRGn-{veY5t>PF#dAodGtrEjj(&Q> zv8vo^CD(yVx*9{5P}updvvNIoa`o4Xvo^-?vAAL+KX`F+`Q!Op94I5R2ay2GOr#gN zg>qKxNr@==RpMT!U$#_nIx&|*XLtYFC6wyW;aW^v5k$dxOZBgqny@w zF{szxk3WnjpYSX<|`X&YwhI?}h{?gzQ(9z1!j%r{@2HJB^kd}P(XSET2SLOh zp*iTwCUQO9_LLwh)M=~s_2TQd=@udbp85L~{u7~zcGMBTT4psYt6a8x5lx-GnixxE zWQ0*Lz?D>Ff-TGAWO0s!q0h*7J%dcGt7U4Z(G!`$YcaXZ6K!EJ-ePZ5B`oOJFpQ9V zSxRlB`TR-#;hys3WlAa#$3EfsW-;kcaI4|tWXRdRAHX&xmheLwpdT>!)>Nh=n z@_TvF6`lPb#!JI>``y_$u8VwWXa9fY#ed=KJ6iE?a`tb=c+?cjmvlJRvY1-udvaOT zC;7^!aF&<SSO(&ptAwSZFTZaE%5DV= z2Y+++yN^%NH2s+1?@tKK>KRW6T-;9oj|k?gusb&2GO>l;4x^O_m;AhM3*gM?8-60- zUyuO9?!@ULLkcND8me~G5iGnGl>1iAGkf0q@Rh@(X);#EqJIPXQM zhbrA^UKD|#9w%d@Fsgq|%-O9lkY}%7wqKrKwyrWdj4V>l>EX+eNewPt5BpnsoKL+n zks55(Jy$G@^0G6&i3GR0gi1$ZeflQ_r%0O2YJx@liUgm~ z!KB=vFzr%_Lp06l$1pF(aEer)Q0kN=6h>X85DD5@)Cd2jDk^f^I1$IzWlp&XRuXDm zsK-pjR1HC+P%m((lgY^cja6Nogq@x72BSk`zTJjVo+erihGYS=*C2@KQTBf!O5()rm{(UsF&xNI3O5rHRlNz!pZ?Qn_7emZ#D3SyJwey6TZNP(2&7HQ*> zTM6!7VwI*+N(;q4^7+={?Xgx2=XkwLjY)u%RnsB~C(qpE%2=TjN|Gbx5N>T@E7W*7 zosa2tFD2{ppXgb+D?5%6#PH~@YTb5+h?euOl5gF`Tyv_XM8=x@Rg%x6KvV_~o(#fc zzu(e-aCet}<^N)W;dfl>dXy>%Q7Vr?W;$pQMi0N9Kjb6^#fW*W&2VI-a;jFC^jZvA zLoU-hZz#bW#R&DxPAR7tZuvkxRnx>s^FREiq&v!TZWpG05(X3i#(&*W)aNK-=cfAP zx&VCA;C;eLn-}60cQ^$ebGoX5mpFV^k!>V2-SMOs3Z@yh*2dzyQ)eOhHULKDbI5p50lug;8?htvz0Wj%z1 z2rv99z9i_>*7YdP5dbIlYkG*++u$KS5!-_)Nz{q?J-zy9>?cRxS<{#ULA_A5Vy z`l~1r_A83c4M&f@r>0x~_5CCKyYU}G7<8tAe;66c6uTCvlxcr~cL`ADPj;26!IEvK z1f-5o1QIZtdbWxF$j4%K?=EVrL?SqLO$u;DSKSrMKjF>oWP3&SO8G{Z&IGynok&|l z3Y|(uqgKD+*%5wK4^Jt`WIGf$TdDutTRGkx=_wEg++`_YV%Ol;utj<`!^$S#Bv&v^ zJU0Hl9whP7x$t{r~K}X?I-5ktY1zzoM*08z4;pBqiB0Tc!kppu{$} zAt=j!2^psd6iAo=3XK9J(USVi&}PrRnX|7w`%KT$0EaV!o#%`R66|wKV)gf`U-CW? z`9$8ldGD<%aPipPtRoS1>*f*}TSi7kM!GcgHl@glw^JD+dJ&H_>>g82g3T?GED(qH9P(frI9_KlQU4_<48Ms3!s&{ZXUtYp(ENH66*5T$s?sn{3=&U zTp#zpUO$4TLp>#|#j0qtHa9jl{&@vz{xC;ART|gcWJ*AWshKJkure(kKYVz~Usa8K z8Re0Y>da_aF0fXVp}aJ5cA#IPa*<7QX7ohq#_a6$iQeAn8@FoXBekBXacI=*)lYjz z=H_}o!nkX_*T$#HGq-wf%ueE9lI{teLYBVK5*B9y!KKQ~1krfngqt^ki0bIvgq%A{ z?IA(0v^77A?;LcJ3?n(N4vi>)bq(V#Wv}>dUNvnC*$wwn_sh`GNl(E z>FTeQsS+3(Hd7z}B$=PoRKsNoXi+Xe^V3s2B_7DevgI?u^owUseJRsI3S~v4u?kk3ts;RlE)ej>S57-p%Pl%@7NweTz?Keww{-02QQrN| z&itR8qbWhlan9epnFueS~U^Nry8!A5Y< zfrN>5JQKDs^n|oYk&AXIcEs^THuP(2v5o8R5@&z&1S>yA+Lf^xm@w7xS`Tc;>eTy4 zI*kkKCUDJS52me?m}qUj%)OrjnZvOSi+j0-KAOTQ3Eb#a8U22FVy@y>X;|UEKJ6fe zTk2@DM-NEV-r;7(;+!duPaw;Jum9o)AK+FP82)H*;PUY4flHSM`una7oQ9M&zblc@ z4Ds(-ORtk~o>;Nq4qL0sNu%J7QoT41|pK+A}sIoT>I>=5Y7% zo_BDAPgPbVGnL8er?91At-slGRP1HX%r1vO2AiIpFUz`lGQhLHOSOh{`y7=YcGivc zzT6!+RCrTm5&qKNCMF5%C_89@Tv49Ejv3Qr#Z)L+4K|lfX#J%gl#-Uqn_pu)P*~!wNwX@0IIR!gJ;(CXSSn?vQDl9r0!CiRZ*Ygvh3X z$Bh6cA2hVRk-cu@;6FfpIRV z*M?TE9)tm`*V)6;YH#XI@=Corwf6$^tgQwEFoR{D`Y~b)5Gzsm^fh17<$(_degKI$ z=6EJ}^TD}`r|{x<&Vo&JPt>r=ku9lg$*0?IIrY;a5R#aJ?9V?w6<@6~F_tG8k}+m{ zB)N>0*Nbb8i+Hs~6IYJ8NOLX`M&as*%8^?f+F%|4{?@+K0!>B|cb^km;6k1hIY6*p zev@2zr)?xYP-dN)Ze; z6SR!&%iMj|4hAxnT7iKTq$8n8b9ORv>DSunU4oT0S6fl9?Gpfc+g0bp@= zXSM{z%`(pqiFD)03s0(iV2|3~^SSEv@e%I^;p==ghLPt2EZdj?;uPAi7egEGZwA|} zX<)iKl~xk4BH?Rr^Uh)mqb5;faOc7CdmZEINyUyizo`r{{f71W^w7R+gR~0ukjGw@6x;A}_hOOKsUd zFRfEQAt@ccaMVaN;DFEg%ZW|&bCD`+-_ppKO!>Ws$M&>Dz=!R3){a?2dl&xx=N!x@~y zc8laiZ$>W3+z$1Dj5`RO(!DF<9zLKig2YE6yGSV9x)RbT7BM83ngTttsbUQ^GJCF4 z9>r4Xw7==cHZ#LQACFIrjv$h8aH3qh;Y1>XlGgLR&B2+T!DYhP*y40BrMlzGjFy|> zRo#jHKXJnM5Fs+tV}4h_xZutWFp+s#%sNBGT@CBe``U(h88(EX_SG2?FTo^m5Vo=j zoFi-SN*{7%pE=j}0T{RQM-2UU?*=ZM_HQ~;Z%$qO=mOG)|4{1uVd~BAU;N&{W%(I5 z13R&1TZ8?5m(E_$UWSJ7DxMEClH&R760vAB&pAb%3m7wKnAWzS%dBd&dT^o5%*xI3 z2d;@wspqPvJ?fqH&(md5#pm%Q5|hbFvBgbhYQ8KmT&txV_779~RZDD4by9ORYBrJ~O94Q@j z38Q5yvQGzSlPTAoN-Hfz1uQo-tBAk2sm669%Ufv&^V`=`z+XN5-qjQ334{Tk_@p$1 z&nF7ERy*XTgrGe+pA)u;`BR#7Afk`XIK!~ijq7wpbq+;yaJ=A_HfR-ihi@8d$BvYM z5WzE!MG4lYMmdE@UHRn3g9a=4B4+98`~WGRro@Kf7K0tcD+8wMmCyZpK5O+yZf6=D zo=?+Ep2}qH_urg$!TGbw#JGe9m`^?5;gPp?0XEpQs5oIs-xhw5FsFFl7e>-REcJ=_ z(lJ#K=Ix@`{1 zsOinPnOfx%S1&m=SS%U8p`y@wBb((Z^~hs7Jp3ExBX=Gxo90pku(gGAoEyT@!rjwG zeLpQZiPAovYkial$QK@D62XjhRYfv6!2{)h3@iXd%|+S+_u4w!RO{&s<14zUKBrE| zmuW=6Vii7(fAk!vo`(pP1_9JioBanhQX}>DjKW;Rw(YO}+FS*Hox{6Pu3gj&`(2$# zUH{_UA9U%jKJ6Fp_Am5uJeq}^3_DrNtT3~dWu)~IhM+2qClAVQ(Hfc>#7|0vJarJL zm03BW{E4wVI!Zn+09)p~EYn-zcILr!y(y|J1;y+XVN@Wnu-QK!sC zXxig8E&L+515LFJ=~j7kI6O4e^M^8*v4o%1l4Yi&Spc<6do9$BTPOO(D#@O9=6UL1 zy`QsM)jD7J&czT3Rf?_#Fga_SN3ibsuIy>hbHp*wd6Y3$5*%eJh!aUEg@1zObqs__ zsDpz3(gFaEXFXj_065+f0P20w53YN^B+5kr+(6=xVo~$p>JCtht?uLMH98QyaL=jd ztvS+6ZzMoB!CCk5_91=~-2=e~A+bPQfaQz~nG40Z{`Kz5%h-MSzMMMt(Yl&j!yV?r z)@bI8DASjea8?wFIOGr@65nJGj6#*=9*upWtr!Fe@|al~!|TI}*&`D`f78&f=RA~U)zX*UwYc@qDy6T(ZnIKyM@WkbqRCytX-)l? zJhor&f@bt-yQU9PO%74{S)fIyc5T2={~S_1PNuWPw_8^-9OmTRZ@W4!4!-dM^)dVj zBu^{2>Z4sKF!Tzxu^Dr$?T|48RR!Sk_f%#*@4hXEh~g8M)YyMB=j8j)-hJ{yLVo~+E? zs3NlpXL3mfhpTZgThB67v{cnqs0>R7h?{(Cw@OIbHa-P&0oRMe@qD<{A!7v0-(@X- zT;>omZOX{I@I^@1)p@u_68GZ~r}2h|PoKR!JS+Nb{%09+4Zo{b!H(7>Z+W9hVS$PhyTbRtEEu7<16ZW9H;P~D1tGo)A7^{%JPhTQXOlP%eI#S>!fLgruX( zXBq6`ahzR+5r{@cDr&A6`5?JlxaC*-b{Af%^p)=Z0kZT`(EWp013Q z=O!%U4rV;Ai=-%vk$APMIeCCS@fykDoIP~14pJy1r9U5#gf{qe8kSrcdx{Df&9#s! zoTNYqYDj%-Zo%pyfpkRDZIHGmQNxlA&Bw2456QsL9wJd1)w?hOi=o7A@hk_$Hp_L3IGnC6qkm0 zZJ+d_O5BY)2gB;qB@Fkk2u%5+{0vfy31SB z?l*6^#JgQad{XnOw|0Wv>#zIkcBUHCZU=6o3w!Tq#r6jd|tt44p#fUV--x6zn_C_qrA4!f;IHcs` zZAHu&PDgj2)Jk2QCrigV50wz{E=|&Lq&st1PvH=U=b7?sX#%ddiPACa2<^s=y<2)S zzcJi2F@lY?5?Yz8!uEaBHCB@iH5&&UfG~{VG*nQudtp|++`{_gaBO+!j3<}(-$8dp z5F_Xyw8=(Ngo*b)|Nw-;Y(tt!q^RVOzBkjrzj&60G&HlBy!==&EwajICENOeoh zXFue%II@Qa?;;oi4$Lk)hQrjsy|{Ge`V>w@$vJE&5#&%%XE(_pE`9lUwdeJen8)7d zZU~Lu_6~_l9%tNCE!I#&ujjgktkwlJL@zrxe$;QY$;|P9bL?9ek6KORW=S24-kgIw zg_NBfy^>+H)LCaB&N4*&4JK9smCqfD5sQu~U=S(e7{m&`JSLDOQ7$9=HsH?fSacay ziqOZ64OQz__IWVq=Kom}Bjk6~-NTyG$+=h@R7O$}xzvAoz!Q zOFy25+gIr_&|l{)s7PqRBU0w2&w>GWfCuwu!dJv0=V&Kh^5L;*YZ{u^hdv!tY8vBcdv1C^s(>x6R%0E3OvD5{VnrHd)qlBv~H;_ zC1J$spK$r3Qd@Y%UaOgV5UsXa_Qb2;rlze9s6+lOn9b!??!qVT1_wf^#r3=>nu z7=$>bRwile^0*BYX-$@wjEsUO7jjDEx*}<}No-}c!gTZawWc^_3=Y=L*F!JZ{3UXEUx1 z(!d?CbCDUyXeEYZt@QB?I5`l>1y_a*%XjIzz)S^k|22{z4PjSD`Z=bF9(ak0#OI|P zWn7`smvUaVS>%cE?^mVD1m^x^e?@*Ih1t$GzFYdkHX8bx!yKxITwCPgJyV?-0ae6T z>HL^N7l}Q1pC+&1>jjgjN4Gnh{l}KA(7&dtW?bj?ySbKYWIwZu$77`vXhf=IK({biy-v zs?PCja`F(NIj9UvNx&*x>cc5tDdU2xF0a-&5HXB9ren%re-_D&!(cWpI|5212+WqY z;Fw|D6Z{8r6`mgp+v7Z*-4hx_2n#k5RJ%p-x3Xy%UR>>w5EDb3!Tx${UkVaDQb9@~ z$meHO+`~3KAv*Ldwi|tT7G70(HE$*$;tIBQ%q>xqZ2(|S_M1i6{We5C+~$*p3PBvP z+&(9pBqJIZKVHk(=XCDeq5g?#4Hx3!ehq$+h%&pj+mGv@x?M0FhDPUcncoqVh@!3x zAhDcNwMt=--oQQJq}hVd5ixN!wKM0T@s1p+c5N=e@13pO?6Nic$%XbEaC( zGaBLL5c&MY(`V0|eLgC~l7;>6^!_-$>2WjXQ^+$Jvvg=~FqhNjve@Nn(^6e)d^&9+ zv7lYBqq7#`uISCkn3Q^2;)QM7yi=P5EPsC)(<0E-wuS48({W0x{DAX(=p)cWTN0xJ zv8mmfoEV?FnF$VfKW9!X7)x>ntjMYyONum)ye;x@T&YY<$ns3j4<^oyxhb(DG^!>r z8)Mp^l2|Z3c7eGAs$I?`mh!8bMu9e&k#m|bKXNadkGsfmmXZF(pY7w*E$2V-Lpu$h zqB%Q=y@G{MUQN`n%wF#G0r|#VQH|BBSaQyZ7@)fJ*^P0m?{y(6NFJYp>7ZME1sI|$ z;@9BPZFLkt@+Zq-6HXoBpwdz4O$8a}Q}dm^2vV<3V9hPm0}XV*sdE%r-v~eeg5em! zm)JET4$JY{Fy3f?nT#;vr9!Twq)+ELLHWdYl6bPz{i(M#d{^UZv`sjlNkQa5#uXgH zr!M#P4y;Aa6I)O7*r7ztt5}As?)YiZl0?g?h0*b(0fy8!L1W0^xJ#O;iKxYlE zz_xwkcWa3s9GW0|;y}cWnIn946hIn00jzZ-*j~a|!r2^~niVZu37cVGuP)NU!p9`W!aBz4Tsnpxx^&kC_Y`I99XD zG_mcm`(#Sl1l*xJeXaXFSa!uT=n=WD@A&5p*%jxOxnqqTm!K{L7vWDS>G^q`o zK9_|cd+czoEZYn==h%U*BYta%Q4lx~2K6S)TI#qKGoQ*{Id!HJg3xg-{3WgJMR=_2Li6U+hf7*w@Ggg8lx1NZ1O_#xZYR|mBMshDLU5Nlil;Wb;D6EbAT zPV_Q`YNan+RSZmU83iR^bJr5tAn#}KTU-T0$-F*=t(vUbac?b3gbSgx+3bT~vOBu@ z6LJo`J`ac*OfkI4+cx3F+=RVt1~zv7PS=mV>^(Hp)AP-)-Y+{2{SI%95}pWHL^;w8 z*H}7cz(l#G%c+WGrMQmt;+WluQ*itd>5*!KbJNohrpjnn2KQ1^KH1C5-S6&S<7$D( zb3|CczIUJ0lvR}KE=w~Jz~lJJ%Ey0m%}(LQM2Ck}{GI6opO4^(7}hxc;4PAr=V3`| zr)Q1qFUk9WavhW7Q+lusGbD2nNzIPQ^5^#Rr4KI+pS^Hp_5Vv~;GgxI7>#c9b`pp`+ z1~1ypEEU-0cVD2-Y@^a=)BfHq>@J~3;Sjr@Yl!a_53zNh2O1*%kZlk#;Ju>JrhCrk z>@lSB7jMPTXXaBdxS3X4&80%nwL5ko$Z?fm z1xTz+t!<w7UC@-wJt+oeTS{! z)ll-b!5YjDb1jPGlVquSC(Q>e(4JW^rho(+ zLJAU2!eW=to=J9SZCxHt`@SKmqZL&D`}?(>;hVPqwHRU*{2>R`!P%BLsam%-Wo8Si zF1BK-t8+TMK%MQ&nGVmkXKKufnySlhH7*UMZ9nBy5MAc6gg#Mk67KQMNj@|^Q^f*o7Uv=|nkjh|dY8~#n39#! z74IvRY@|wcOeG2`)%g(yLw$my%DImnQEjwLx9D>q);o8f}M38_M3-rO6(RkIsC~C z4TR=4o@AAfeLsCE-G-P%NHmnQoT)ip+AX95nl!wh zDodLZ%8DJsOO=_4(iKqU#0iBC^DVN=ThRlhO_wDha!k!&qXAb_m*0P8zlgE+wapLClYj8G?_Doe~PdZR|^h}!=sZQUTL2h9r9!5r?x4I>* zP^sMv?xpwB)sL6j0|Px<@^?W<-nBL^WuWDoVK@^*PAh*f2X%}Uoo?X@hK0x`2)1SE z6iwy=Z!H??D15&XH4#9JB;iFkHIh+8EXxrFSu0R{FitH^132o|%e4HI&wNu6B$ExeTRK z^-B1G#dUp&3`TJkS|@T^>rL+HAg`iSrb_L>FuUIS?$sX+^?Y(D7_StOPvD_(KcJ=u zDvQ&cDl(4FUZj&2+oS-XRFf_(tMyjUVseSRZ&;SPGIHxkpSz;xL(%h>(epQ>=O0DS z9m#VZW)rNwF*GEjl{qf>xS%#g$>DZe>hLW5o?J|hdMChVj_zrB!TYN}>itAZboLw$ zcd8YQK4hWuz31#4^;&c;1we(s$rp9~#dCIzdT6;TherjSU-wwbBa46_5@-USCW-=B zM5eD2a7z%aq>a3O67qX+5cSZBHUN5_c(n(5cX!h50YE?U5j4`N4JEzg zp+rXLk&#zGu%F-!42~AFgVa)95Hh-4UdyL2XjEQ$Frc@xN=B=HEyV`%leh%Nr{*eY zkP7=rMk3N5RZ2A;LKDqQfzma%jh_K~I)BvJ<9g}o?7&z5#&!03VUxZ3%!f)OE1W!E zt60}q;8>u$9QvM~p137Oc=qtK_$PE3AO=zPHEblF`EKtB%i)~kE84u7-tAh-X71(= z5GwxCS!+&IA%R?bi(h232094rz)_5Jwg88D<*425}BZ z41iV8i4!4)JYEVtduPZ=vU2iF;Ie>c*oK-;mq4PO#Q>IiTD(+4rdnKS(0m#IK}v(SCdaB%IpxGLR&a5o zdB_U(3jGu!*9r)MAc;-# zXI;EpJnu~4_}1$Ud6en1<&+>JNr)m7LkJztptu-O%nj+1J`~xeiF^eSDz#>6Kj<{0 zOsGIS=Lph5C|~PR5L+ib5sP6x9)T?_Q-Zn+E89%s?!=}*JYDAN!$1RSODa)r{!-1Z zt)6$Mq!U{_nWnQu6RqyZoC!fu;O%AiNl8KI;Fn%A01I#D11)co$u}4Ri@#RlIEPlO zoK0CIwtP__QfXp*avYlqVnrazR1e-HmqNUlYLzPsa$-f~Dw#GcY#)lHjz_gi4yICl zET3V+{vOoW#;%L-W8TNdZmEt2$nF9OXFz&uy=em$J1I&Y;a{l++EB%9j1qQKh)j93 zPQROqYKx6OC;CBM-%g?^{6ysf8Q5@F5G?1MjlN3;{(Bf;7&~+Uzkd!bXeulk#&UvW z3MpNT73D5p{HD^0*yEGl$~L4sM8CFFb1YE9VWQ-k2cD+vPSbTR!Q%_*xfZ?VYrF8c zaW+;p_BM=T(JMjkjvKraV!Y<1KYGLPpv<{?(P6&26@p12d)Ac0gDF`fLZDO8MOy}| zvquFYIl<$Pe1?{4_&Z!71en^j4ds}H&budqrVH#;L%JBL_C3&hPB{i72+Mh+T8>wG zA{jVAD?VNza3l#zAe$jstJEOdnArQ0`=hP#~f;u zI|Tm`UN<@N^y{6~uKYUuLW<5T*I@G}btR@@)RE1V$8>iFs~fk5`9$*#5dY&fl*^v$ z$zLG^Yk~k6>yRYO5E?|gA#!S#rntNdsnj0Fuw15D~0qX&4&Su3gPoSwTjf$Pw{ zM;ECj`fngW0^ZAv12ApAgxXFv`iMr(PTeO{EjbA%JaM1kg2FyK5Y(g4fKqx%I1=94 z_)QTjfsz)e*15r1MTB zV6W(gRmq+@cnSG+7}!8_8gU~bO(k%8XUMhe0ty#?vCucGH_aiv8n4bIFyf~YA+q8e-7?;Nm^37 zflOT37M+}wAU$`6J@!=oex*FseFm=0U;L*kMld)&i2${CWh)hF``-WY7;Ys)^5Le_%Ii zO)PqwRy$Xjx;}fOpmMWrYjf9RK+j)Ork;Y@0crDr=M0fkUA*B4KhzC4wGMEwq*OYG z3!5di$+Yk-^*Wdo`=%)#VQ1;PDRE@pVYnm#jN+cr0L~dsOWI~hPda2s6lwU-dFvn) z^W}z|tzs7iHn0JJDU)9VMd`FZe|O}BiUjF2^2-_~s$_o3HG~ups%=gdAuBnwI(~51 zUPrhxj9Uf@b7T8rRLPpZB~8>Umaq@yt|s^E1mA3oAvT-dx?+M6g~_HYZ&U!=!g>hL z?nqj-2|^(Y27XynTtRpFrG&6iz@H_}AX#$<+p~<}&j!SJ2%8Y)fcCM_fRTZ-<4w`y z$DyUZaAiSNoAOd7RMD{BXX!ivkH~Sea;t?oLWtBB5S8F;%2d~}-7y92muc1b(!F%` zgDRb1WyOjuCU zM|?^{h_#b=HEA^A!QAzCx+Aoc{y~6|#)C*Sa*hI>QU@p}mVBUlx-um4m?q%yv-IcZ ziP!dYGkaRK#bF6y$~pJ#Zr!_CsZ2A9>xkd^fj3l>qFqDKNNlejG`OmubF)728p}qr z z6$KFF1k&4Df*~OSKKLydj59FgFov`cPh6o1=a){2V-muW931_^&&`xr1qJdO;70rS zix#jXgO-m>0r^DG&8nhz-s7RDE{O+Z3?e25lq4Avj&Iw2<>Sl)ILPyuj6w+9uPypM z{al_iPV29C(+{|tE|iv)dL}i5-(wQKKuS~1RfkEJg=@GoSwdy8=8+v2+%e~l3At;? zb*Wuz9nw^KcdUGEyfXDZvXV=1Ru3Ev;wA7$&_3R{T^;=iHuftsKPi1s{_$wJ^zL=} z^V$3EPtWv(RIoVM;^COKK93}PTt zdxe=0!fd}!RnG@+VjprwW<;TchL4cGb;zVzp;lD1hf1)V$N73nsa$62_O=yEvYU=L z9A#0=l0lQ=d3C=dfL>!I+~+%V5yy)x>yB(!ozlx;2Br8*Vx^1>6Ey;4wo4 z3YYlU=5sP3N_q+b;|s)5FCIBeia1d<>|=4a3%YM2{4EEfOn^OZ}GzlId4MjwdQ(v$*GiH#%8) zcf2362X%nM{3tgISA9)9Wsr7ty$K_oIAQXhxr^!jwC7TU+p8#rF;*#Fw;fDD<+kN?m7Nu@7q1!>iM=;O>!aPjoI1h z+KJv?v{LIqDiBFX(EF`--hTVrw%x>Z27MDqDsifMy*gR`N%d1T8sQ;>FaQv@{T8WC zQ&qBE*VImQn1FDVKC8~$EaQqZO=uyx9V!S?s^WOlq?5F$DTr+OQ<63Roq+3XlR%YC^Oy!|A-9Rz8ak+d@1CA6pJ-;aLgv^w% zXHX@}{yNy#IgEzd@DvxX?;}&Vz<+@&Dq#&B%#Bgt#pwN7G`}=~&E}f4rlvC)BFx1Z zV$Fk3sk>4)WX#U*S(nsxJNDs*Gv`0|Ii{~U7R!8T7 zm(xhZLad^4{5F{HBKd3lmjv0xz8q+K6U_yzlre>hr zJB?DjOiRP9TvuAe^>59W2Ir94T@$A>=@+tjjp9Zt0ZJq1T$|!Sb@r@8S*T-14#{9x zRYY(pY?z?SIG!_GHIOwO0c^_A@v$*naf)}>DmP#*79PSUYBX64Y)TPM{scin#F%m$ zK(jPtWA3~*`?GG}=b}xHX7jhgHCX5#b6v%}4wHq4xp6KQ)-DzaUIO(VEx9~U1f3y_ zu1BbbgjpSnrx{Q=RtX+UidZaRu&EZpo)W=}i=!vnlX1c*d6SqM!StLnB*m;Bjvs?s zPY!%7pJh&lEHp#p>9#+2b1p7hy;l#vclAVh zVrp*k#3v=m=JN?*2Z#|g5i5DFcczK^xAO~$CjY7vk!Ad$OMW;M{BTu%_$2t@UHRc; zC-5W_s85iS5wpCZCZ%x;o-9!v$^;9+t78c6Pe>^3*eAoX_Co%~l4S1!L}cYDhv%bx z1?1lF3>%~MC7 zRks}(Cq`r3N8}Y8u?e)SXjnNZqcIs4DD%VN!GTMCm;0_HfB_>rM^*5l2Z_|x@mU{!nDq5cPqE}ujtn0#W;smHFi$mMzP7>@#)&! zWbbGdPlB+MrILFw|=PO z^`h^ITJ=C19aNEM22BeiMBTqnRem6i3XixmDd>5#h$+9`&sVA1buuBbXHV)f8YqN`QsW{_)Q1kr5ZWZ?R1LdV*4yCE}8H)99v*0LcHwOZ|TWoo=K>VN&c=QxNn z!0ZyTGEI)&W<15Rda~g8)QJk8w9c~1eIIFt!EvW5xC|J#&A$7oKEGd^n?vRdi@mW> znqt?qPkYe>sH}R|qck~-N|yn@BkvA@thcH~BhDKuj%lkZ9&_9sPMgFoJ# z*zf_IGgWt)g7e1spBWV#{pvN=pjTK3NtQqf758AGM4$<@Of#1qm5?5dG5tvA8Dl)% z9a_;lOGuqZ3l{Y?>?YvLbI6!ES@Dd{0$dzL2O(14AF*bzz|kAU@HekhEM9b}8G99U z#p13a`-Vjr_J4Hw@&In^>l+-t)OY1WIdF%2>s?G@@J_DG$}FjZjC=8Tx;n3<_BnNm zNyJU^i3?xQ7?7z)CRmA@!f9$pVz(A>h{5+9%rd1}e90_md$-hq{8M_Lx-!==V4-|{DG`oE z=h?Hjy!vC}ps^{LR0{zD1?Q?o?Ra;%XDUiFrmj=~bGvrUbFI#C@o1}S9A>@EOU~-z z?U!)nxLe?HB%@YEgp#Q-F{R<%uTFJ}Z@c8Q8T`{zwp*Y*aKf3u86%0}VLHU~R1tZjFg6_B{_w-^pT`OP>(Jmn zH?w7+&@o#W-u3a>8*|rWG1)tYg*7m9v-if0PvO?7)#fU--ftg&=a?XMZ2a@eXo^8` zm^0u`OkCnu%mx@0jRo4Zcv~tF0L2%H^WD<>h>b!l6%NZf6ehjKC`91TSXGQ}S9cgC zajX4oc^LUX%evJA;fy4HWTJ}enxu7C39tQ#ML<-sYP)jJT;-;Sd1vlkLz6*gckvR- zEf9hxEd*$L9gqJ4@%R#*#6;2;<|eOIW|AL3cwN9BMs}2+TFATZL0BhhCAA?JWaFx-Zn@%VxK70EGB&Kt0TERs=vxdMG` z#_r zhD1||?-%Er@CrLc_~zm}tjG)N(zwguwn(om{6*B%rMhM=4PLx_W%$$&ht+8rWeTu& zSAKYD0IC960)%1G_4@kz2L=ZRP7hx>3$N#QOK;{C>i@9s!Usv2xAMxIzj*rWnX^fu zx2cW1@7lDotL%RkoU-V_6#tc(vTOzF0>`Vi_VhhG*zIwt@Un)7l-r`9*Xw*$)({R1eAvL6U& z@*z^Xna;!g=>AP07qnPIvY2%ZpUz8dU=6U{yk^s@2C49yMVUzbygU+dm}Ig(ceO*Q zThWOH7=K7uM^MuSC#5yvs{*$_2A4k^7~DuHzbbfnb4G&R%vBnN=uO>hrP3LzleF?t z2~O~k>x4@ja6?7fSN7&`cSJnz%J!~I^rqQ$f`C7*Tte;!?Bz-duGwxqH3v(eJaN4` z1E&Qt9-@+5F5{fl(e|B=-3elx&<31nHbf>l8S>-JlqH3=DR8;Z+O3p`5_^H*SmZkn z)Z$!OFbTCQEkH#(4~1ekm<1>zvJ;X{gUO11neaN#RDYbebx@L<0+;P2ZAEoWg8Ir* zwbFF8XpLV}T2&6KAYg-UzZ74i^Ie(e*>b14MQYag(@+iN-TZpjtBmzm^b)4Avg4d|qJMx(Zia z=}$`E^lqHMa+I&3b}YiI=bnW3k07K1aTW-ZaLnC8Nq|M4pJjx-(LgJfan1*dj+773 zd5}?hwd77Q_-RV@VvBL2?sJb*wG|p@Z=4QFz1{qv13f#13t?gHluODaID%<1B6}Hf z(izutREq9aHofoIQ1tlR)c7CZ%3S@SVDv(pFH?G+1${KqP#ozf2lreb?+icY)IpvX(tf!VZPgVq%zIIp%bcL2DOR&|q}zttkyK z31^IO5x*pS)XjXfOC!H(hrMR*qgETgl74sr-<<_$; zG7$q7tR-WjhYZ*hIz+?`1nqR?HyX=m@d(pR!_Hp z?rZ1t_;f{%P0z?V>SH-CK9d*6^Iu4Cqcl(pU=#QVu|k5|@@m*{o$c!U!>*y3p{Xy2 zX1*MnI`oI=6jljBr8Izwv7Im>v^|_-N88=Uj+AhN(FenWm(HENGJN6U@WA;?SAK}j z9Brg4d<5r?xzS;hHjigb4XK`z3pNyuCkP~v8j4;G=>oV8=|P2{urawKpzM-4th031 z3G(}JkvN4{q~21NT>eDt_(oCmg+~-Y@%R0efPV#M*oDw^`I0h1_hzy@-Q|~$Zdn!a zoRqaeLgD)086-68=i(1ZVDYB=q=O2{V6`E^h5EA+rk1w80z)NhvqMM*7<@9ISl2qc zX*eHx`n}+^y~X%u5$z0d*x?SJa{RLFK?V&pEgRNYvKZ7LP#GN(m$*Oy+#Kn$uDNv} z%v)IwqAi>xqyOe;)(UVgE7xJ(lHT%D@L-mW-1XrwahQL+8%wdpAM?2Z%l0VpxINmX6TF4eV0EzdjYRfp)mTY|A!yASE&FP zeTCmoU;KCw)lz{k`tH==Y5Z=nE`g_3_aG>`qHfY6XFDJgXu`=UsC$`C_v?syMig-A z;$TS%7HN2hf4cRoWpxGBTbLeBi%LJSi9z9(R~Rdw6gJmvqLFiEvZPrPWrZ~u?Uf2V z1u`d>%|MeN@A9YRaV$nBvZD^QqDI%r)*2DOKVI8q4-H4Sfq95b@Vd7lY1;KmY!LDd49VDz1YWmFU1oM- z5iv2U%TxI5JR%%e(n&`EH7L^Qvfl<*5DCQ2OOa+^+5b-n62qQtRt_Ns%?86TT%mjC z-AbJJhQ+|>qLG^5y2t8cws5u%zR2nNoOuAor@$?5B_4(=ESk8;AA7Wju|81osU28+ zD4a&|Qo!oUUkSxKEUbSPDJMRw%yda|+lzzYAcPdk4SGTr3PCTCuELGnIdbbdPUsZ! zP(VPZoZL8t0RloaX@9gl(`NflFCMi0YqimKfQO1KY}wH^g_Slzrc%yrnL-#KP-X;I z^tCCGH6mo1zFLfbQ4c<&armlM5ZY&J!MRsJHnR5APAomdCV!S z!;31&Zzh?Fp};aQJ7_jWWo!vukvt2+k|poh75_k)xj8-U;(G6!rf?grnSMyJe5Au+ zbvd{kJ!4+6?HoKDc)ZF1G4RQtIaYUWUJq@o*lXBRVX3@ipQQq zxV&nlpO?Jn^4ww6{r;{XZR!ixph(07He4pe2ois!B-=vV9pYcQj)r1G&`?aq61lIO zJ%&z1P#sExx^cU%!=OMi|Iy5SVl%dCRNtU#tFE>|CyHJ&8&2CUhd+AD@{1-ojPx7htCZl4>i3{N73&<*T4 z188mJwEk>vI@CQc2U}QTY`ijowIW+kxUww_$awS=w+u>-(}zv`;0He_UFf@V_WJ{+ zv*$0J8#s^5L3q4)p>%ezba|lf+_@i?PJQ$Nj?4IdglyQwAJ$~g0;PPqOP5>*36}$U ztU94M)YCx7Lmls9-&Op~-?ubTlffye@1 zT{#Ef1new9 z#DS>+#I^Fs&E(h&*#Y}fUfc{c*{&oKugyvBZr^%sWM=M~hml_d)aePFm52XiVxk+Y zDijnYFkfjAD=0@BOoTNw_3nbH=>0z_7K2EpWjXP+fW@YY*TD7(WgZ4damn-z3 z>F&~b*?hLbNW6pm!JVWLsUUr{Dl2SkU~e8<7oVoE0tqw*_gE1k zNp6NL!Jn%Oz44RERQJvD&AB&@ zl-_{acHbcZxOfb^co|CrU{=60u&&0DTu7!*wG%$Pa{e5)CiR^ux0#CGy8wj;=ZWV_ zj}cY(mEpL-0cUvl@>02J>q&#iF*|(N58izd!d#!5D9^yTf`G7EO%#sK29t7=t(zvG zzOZER4MD}!D#H=mz*Lc+OCJne>AiGu@Jet0#f#rNJ5ZARC5kS|!z6d#zz#7>Eoo74 zflwT^)P`k+WBN?ZDjBWRciio(Y0_Lj&2wbNYDq|kpE$)#ONOPj%u~iY`UUWT}$Wa;0gx7vt8rl#RmhY$_5f8xt z9NfGq8J$ODOq#<1+mu!3niGqx$!swhOR<|@aEfed1mUC>{!Y`utq$<3)*$ZUeha^I4oWsO~3T}J3vv08f>{$s_(WR25 z)Qsy+l&7xGVL^*}ol})LT3nwEJ)ar+{5wbA&{y*HSn?I6q=NkVE&ugYQub6* z_LM6-aBS%FQ++6ZO3Ulx0Dc;HBZ!zFP)}C@R1N<>T>|dhr}NoQ<%fI84^J19@6Y}y z`2LrZ?@yPL@6Y~9^8G1>&4w`!1?D?LpZ5W3>5~w_yWmLeHtgb4HnOaZmY+zK1V86& z)yRVf(f9TUDro$Ow)%x9h4@c!2GtEdRpF4N8Ov_ngl&Sij%2q$Qmvp{w+{h`M|HjB zm6`)MY%g@F4KV)?DNm~AW7 zRkRPicYL)2m+s#HY^iu zH`elJubdqiw0vTonS>WQrAX#Y>}o4)EH&Dwx$s@wU>>SEKZdo9Wc1y~j=z08*rAoO zNirCDQgED>(jCY&gG5-93Q9TkG^Lrz^k{GI*$*yUygUFI&QLVKsWe3*=$%S%jmkn5 zJ`lGY?!pBy(0E6?hdw`Z=96#A)h|v4hll&m^$iXV52M2yvy&5ETzplDFHChEblVp8 zV+`w%*_YUM3CA8ONnYswi{~%(T`>gML?R=UPYR=8I zc!s=*Ml>4?!I6oCMC$Me5{i}qt>{Ggel7Su5`350%gV?cY2U~AJ>Ey^K8y%k> zf|-PLE#E*R7-ZpyW2y_QIQ6cc^G^YQStBP-l=D#|aK`a))O#<|zj2;fDuErRt8O}E?+o%;e&P&Ulvcg_zEg(OnxYFHaZt7Ze_ z$q;M-0%PDDl48L$5z56wQ1FW;x1no8(_fsM_)5p0o!KzWU?)&GV^|%CnK?}c+Ps5P zSEYx!ujJp^uP}uQrknPp9?ncpxhYgaEPQn7(!k|HEC`^s4s*UzC!J}=kW$j7u#Ai6 z(y}p1rI>s=tR>IBrzKZvr~cdzti_YCR7&_lp5%i|R;R%XuC+8kxucdk0;TKKxWFw# zi?~4Q$VZ8VWxKy|iR#lNwQL@qIs{fU(t*>McyeL8U6>x_V-E>1TejDz~p1ZNa0Dt|E`oCDXlTnUG7 zg~~i12^PPqZRa0W(YDyNhy%-}>10iJOr=pK^JxASCkE#qh?P=Ji%aN;Q> z#U%Aj36h1lifvXaMhluQwOKr?0n@)EPl05nHHOWYF)__D<%tX#OVCDWN_P3F+}jGz zxt=l0(=P#W*ovM$(7(uZN~RbqTrd_YXzOKwO(&EH1{iki)uq))zzT&$@Jdv;8PC8; z`;}<__zu87RuEPTE-;OuF92I4!YW1@gVaecuY$qx{Xy0j<~5ZA-0BH!O${j+kA*#R zNY-dB1!~y2z=heqL#TC&x>gu6c#=uB)QN-#oxCcL^5=dxS8w{A6p4Tlyb53uPNn3l zz-ubFp(wh}&6;E`P9CIZv3J0jV;Gt2fEqXl?3Z{UWvEsZtH~9VjY;Ux2@lgdxp;Q2 zr!1Csmjv}iAY3n`LDD)C?Z;RN*dq`t`BgrN9+oFh z2Y^%{+_@5w5}rKwGT^cmf$sxil5%S|RX^fwX_vjS&TYMf+IWmxGomIy1aKBE5X5*D zIWhmGu^YA!quCFO%@ciLl>l{lt3~MxsU~a#Agr0uC@ErvdrjB@obKwxm?p6V!)EJ* z_`9(+5U`sRx6`H4j(iH(Alq^xh?ypX;UzA9>{(XIsw~6t$bP6GEJmV=*m-znZZu!>x_h9=?Q&i+g9ynU2glfDPpV{}?Oz5XZ?8H18D zzH|^EiNkjGfqhSaX5fVzlv>*}~sz6Foah-}(S!OK4(uJP*Fm;?jCmlMpLzmd3V zF@$_1DzQi>H|Bi*etIioc=-Ill@BkT9v<%LJW(3ZyX{6R6S!*_!QasFne7R$AB2V^ zTqJv0%DOF(*2D=2a{!9}c_4YKF%;9>`1N8?U}DZKD`J%a^=xh50A6e)C&W~naC*e3xj^1&AR)!GEW_kR4?Ti<@`oj1Sr z*0+lx$yM$h5L67(b9XTjO>u&ZUVuX3aq$z<9QJ0ZsJ@AOM)=`io3oHH@4AqfCF{6A z&k+VU9RwTGGRx_tVjC6bE`B_4IcV!h1CO{_^{_$`K#%MU1?UlO z_hzu*L@i;lgK-NcHi}~QCpwe)TbMYj4rO+B6dwV-ReOTWu1#l3wx0I`S3hRD8Qf1Q zdlE<=$DstcDHvSH8^3OQAPc?XM7M`IjQ2{3T*`ik`?-l8R5V~4C8Lz!5|GmkfuLsX zixQ+wizTMK&`#A|VZ&0wHy&#zFXsXMrMY;ZF%KnVOvax86)0@tDR01h)pEovhkb&g zu@`qDgD1a-u>$gQuCioVD$6VbaNGgk9_q1%TZ;p%nif_Q=--avXA=~P7idK*VOy@I zB4sZ(ggzk}ZP4N-%|>-S7B}d5D%RVt%CwTxIQiDJhJe$_7K|EW%w2o9nbKnv%@)!t zq*Bg&=~dO>+%*9LY40TEiKMp|C74jh>$d~URdO`wrHnV2cRj!ZbVej@i9nl)YIs>| zt>&W$I!y#Mhegd~Gv)+ckOMKss>u6Gv4cFCUI|_0Jl0DgESFY+b~rGeLMbQ~gAmdA za*yTvtHIS@a7|il#uu$u+L@nTvL-EZbOh2ZD#aO>YFB}(v8};rB(r`Op_Y%DKcZL* zDjMr2N>`M(bd*eff%#*z7AOCtR#2rSD#7)7VjTgeIA6CBJ+<00eSh6 zL3P@$yx+!y*W_f;_EY+}$0c)>@s@)w5+pwK&Ce$%4#mw$MDlPI$NVR%2pJVvk47D)N(@h6)^;5sQMa!b zRgsfpx&(qx%oTRqsd>d*hJ!S^?7T)^`D@kDTWyub$@0qeGU3P_na!ia8p2vlF`{gfUkf-btNZJ61}lOy+$IQ%TYs`q7FAJZkCu)O6kQC)rD5TW%<^1L0nm^V z&p0~&3nx2=s&Gqz&?#$&@+C|yA8CS-Tf+Uw@sCEbp<9$fZH8sS);vU6<U^sNN71m=y5%)_>z6@9_`8q;i(#f zKV}CF8+-m>2$5DI~(&J~&oH^|vv7g@5pFYve)lS*j#u7nNcz1wyd6^))^hN32cT2|( z!583NdRYG|p$`}k<0eLTE~r>hSr!RkIfF zpdwNr-F|^Y7V71fIY_FRKzu?*Ofc?520K2=0drH+*z1J*;4n0u+2jyz7~^jpf|DA1 z3N_qffSE3EQaY&t+q{eYXpz~N8k|VGL|q_fRX60~3`A2@fguAcM9negT_Ffo$2LUPxHM|dXG zPbO^4CcFad<)7{C>X^)~5+S_7-R9^An?vKsY$Ye-5>j?d;)j%!Nf%Za4eJSl}z>HQ*%s&YQH9q zKlvr43W|G`T`~wg`^r@a;k#HT=7f5CRf^7=F2ngH-J`e~{t$N^3lNraItL~IUs!YYN zg~0a1!>7+)mKd4d%avMnZU)KkdJ+CFS&Di=D9t0=*)x4(x^Pc;21)bAk@H^5CXA4! zY2b`&K~Ib%$EeDg4U#QKuaqNZPSHJcEISumuakiutcm?DzwaW@e1g`_cTSzXLhpu^ z(bN~G&R*!d{KM!?EZ+o>J0u}MA`bG=K465t(`HM~UJYCFiaL=l7d`3<1?k;6U3X}f zDmocUa%)j%A9_Do>MW~ks`He4y5^qx-P4GBI_;it23+b5xF=kHB~NGElXGx&e&C+2 zyLTVDryK6+ta}=FPrvV;e(avU=bmo5CrK{?$R^y=dG~~%a_R4adzx}j7u{3UJza87 z)9&dnxu-vHPnX>j0>z{iNo|52oIA8rXpN^?_wFP2gmc7F^84=TQ}^_-d-}{h{lGna z?w*7%(8?|M^#8f1pSY)A{AKs}i$CV`U*Yq=;qz@i|64x)l+XW;&p+eyzvuHEKK}BMsg;7{^xvN;q$-XGtxlm`+v#jH9r3m2@SpOT_<8ux`AmE~{Fi*@_#ggjKL4@9$3yb-!+*<1_i~;s4+>`Rn1ld!}-Ec#p5iJ`eBnne6iL zfAjhO5d0-RlN}ze@R{U)xW;EA_XGF5fjnPA-VKWL#%(@Rd^di^XNv2_AMu&ux$)Qd zOmc6K+#4kK2Fblaa&M5_8zlDz$-O~xZ;;#@B=-i%y+LwsklY(2_Xf$mL2_@9+#4kK z2Fblaa&M5_8zlDz$-O~xZ;;#@B=-i%y+LwsklY(2_Xf$mL2_@9+#4kK2Fblaa&M5_ z8zlDz)yD?uy+L|!klq`l_Xg>`L3(d2I{N(rS?82~r2hu#zd`zMkp3H_{|4#*i1dC! zd_SVNKcculqPRbzxIdz}Klul)zelA1Bhvp7)$x;m#P{TfC#2USs^dq0i|@$~k4c|L zRJTt^&qw5sC#2^is@q3DXML*IC!CHRkzbyWevim6Pe`9f|JdQ{38#-oGO!{@(I=Xqkql%q{k!j&m;2BBl6E9>!1Adi2U=2{PSm&w@3fUwfD&2`7iGI&kXvKAKw7~j*gZLpo{Tb!)(f?$5PCt+S7oR!ZJo-PZZ}=sDJz8RW zt1Qpy<1zW;G4;V?>IeT!{&@V?UH!+L9{e-;<1zW+G5Nzkb9#RKcUYhN@%ZoYnf&mW z@IEF#JSKlW=JfiQ{P>vkfBa8apVR5%f5vA{pO60qpQ$e%Q(rtLy&sd_k4f*xr1xXe z`!VVLnDl;3eesz3;xYO0G4;h`>Wjyu_hZugG3ou7{P>vkeN6rEnDq6})EAG*pO2|8 z9#MZjCVd}KUpyv#ACtb1mmPf{(|mYLdOtRLuk$_YZ~kTXy!lrgzBZ{pHp#!6W59vADf&%HmT1xsSh?e{!QwG zP3ogf%Ks+if0OgaCiTrG^}#0f(T#nh<{0r|0QS0U(&*P#`jMN&r>b{o)Vs?#PCzjU{ARKcuM%5 z65~$^-!qQyDdBrYc%M>3J)_2YN)7dt@IEDnO7>Nmv7b_7JvI2qu}`U?pHhQKmQ^iJ z4t`3F{gfK*DaZSi94#4LwLCSPq<__Ca=2u3)n{tFr!h{lr!iv^4C*J)HBYAPyZ|1C%-*2dQl@hBmSOIBRnI%o>3z_BYvJyBRnHM zo>3z_v+;9=ct(xzj2hvYjh6!X%*IEJ@XW?TjquFir$%^2jqr^8`ivUk8Ts=WX8@!B zGiv;24hJ4QGT~czb(q|HWl0! zEsSl_bBpr4%^81-7RNT}yG8llriR}lzigA4AMS0&MeYeQZTcqz6 z<$cTOOa9)Xyl+w7w>Ou|@gcru=VF9=0j}Ta^E8%KsMS zW1I57Mfu;R{BKcSwkiKxl>cqY{}$zEoASR!`QN7eZ&9AMsn56myVDQb)aP52uWjn{ ztv}^^&PUree#-l{jhFJiZR4Z7Z`*h%@7o4H<$c@WrMzz&e3bWXgNO3I&G~Sf{I<>c zaGU(KO?|LUe%j{zxJ~}qUgUVlFWb}y+vJb!RlX-bY*Qa>lm0uD{~gkMhw`>V{O(Y` zc8Jd%%F_<`*>-s1J514?C3q9rFJU<$Z_zzC-!mA%E{so_EO4 zJCxrY(r<_K+adjSNWUG@Z-?~TA^mnpza7$VhxFSa{dP#d9nx=y^xGl*c1XV+(r<_K z+adjSNWUG@Z-?~TA^mnpza7$VhxFSa{dP#d9nx=y^xGl*c1XWn(r=ga*rop7rM&J^ zU++>rcd4IuDUZ9<$GeojUFzRm%G)mW?JnhOm-=;=^0Z6(?~?wzr2j7Izf1b>lK#7- z|1RmjOZxAU{=20AF6qBZ`tOqdyQKdv>Ay?*?~?wzr2j7Izf1b>lK#7-|1RmjOZxAU z{=20AF6qBZ`tOqdyQKdv>Ay?*?~?wzr2j7Izf1b>lK#7-|1RmjOZxAU{=20AF6qBZ z`tOqdyQKdv>Ay$%?@@mDZaaD3qki7|8K0?-_x^~_)W3UwjnCA#dzAk@%Kskae~Ay$%?~(p{r2ii2zeoD-k^Xz6{~qbTNBZxP{(GeV9_hbF`tOnc zd!+v!>Ay$%?~(p{r2ii2zeoD-k^Xz6{~qbTNBZxP{(GeV9_hbF`tNZ?zi<7M{`>#d z*++Zy*z6lT>GUKkA1G+_Gtg@8@%L~{r}ARv$hp9HSV+D`fUnA<34+?-=?Y7xX-@p zw<#Qr`@VOYYmNKV7xmi|n8tn181>sU*&6q$L+ZCFM2-8LMe4U{wl(fkuhef-up0L{ zv(#_XbZgwFuBqRqur=;;wyEEy`PR5k{Zqe91>CsL6-@m$MY3_9I;nn}LfN>_RZRUh z#jOZBh zHtthf)qhIyYTT!OsV@?q`l4~~B73hd8m}(0ulk~K<|5TXebM-Ek&2+cXk52Q(XTHW zk1bNz>x;%wixltrqVdln1-iay+_Fd!t}hyIEK+Fei^d6y6w~^m(S4BgrskiHk zl#BWzHFbTFQcz!{Zmutq=j)5q#`Q&Vczu!jx4vZjvt<0UWc;&a{Ig{Ivt<0UWc;&a z{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{I zvt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0U zWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a z{Ig{Ivt<0UWc;&a{IhKQvuymcZ2Yrq{IhKQvuymcZ2Yrq{IhKQvuymcZ2Yrq{IhKQ zvuymcZ2Yrq{IhKQvuymcZ2Yrq{IhKQvuymcOuGNV$i8f3UpBHY8`+nQ?8`>>Wh48t zk$u_7zHDS)HnJ}p*_Vy%%SQHPBm1(Eec8yqY-C?HvM(FimyPVpM)qYR`?8UJ*~q?Z zWM4M2FB{pHjqJ-t_GKgcvXOn+$i8A^Uoo<;7}-~h>?=n06(jqKk$uI;zG7rwF|w~1 z*;kD0D@OJeBm0VxeZ|PWVq{-2vacA~SB&f{M)nmW`--WJ6;m54rZ!egZLFBuSTVJ+ zVrpZ>)W(XbjTPgc72}^3I#_$p1L`l@l=s&UJznc=Hk zh16G#4_A%ut7i7D(sNv2HI7;}PFOXwca`4b`l|8Rs`19EnZ2v@AlFxo>sF1Xt7by3 z(&VqN8n>((l~>J#T&2lhUp4+&HM*~w3Asv>zrJc5wQ8KO$^~$Jl_r0E)p%^xXu8Tp zXnmC?c74^jW!0#>%7tisl_qw5)%a)C=)TIuXnmC?c74@2YSlPll?&4PDoyPAs`1#G z@y43*#+vcQn(@Y(@y43*#+vcQn(@Y(@y43*#+vcQn(@Y(QF+a%yk<0AGn%d$1=oy% zYxMfp*GzA$8BN!WrfWviHKXa8(R9sdx@I(8Gn%d$P1lU3Yev&Gqv@K_bj@hGW;9(h znywoT*A0j3hQoEk;kw~)-Eg>WI9xXzt{V>54TtN7!*#>qy2;nN$=ABc*Sg8qy2;nN z$=AAJe%&y?Zt}Hm^0jWXST|a%n|!UCe61UG){Q#rrj6HaS-EcXS~q&F8@<+zUh77$ zb)(n1(QDo4wQlrUH+robz1EFh>qf72qu098Yu)IzZuDCB^fDP-HyK_)Fq*EJygx8nJTO{3Fj_n?T0AgXtkDrwe_*s&vw7!%(c*z&{()h2jqa`b z1Hc=QYuqtc)E$H64(*7>9a67x$6Qf&NWI1#!rQn* zIyCN>E9wsE(6~c7H0}^vjXR`6;|{UaxWi#K?vM_RI~-`^4(ZUiLpn6>5TlJdl!?Y2 zVzhCGGSRq0$6(_QWukG1HbUc%%xUsR)IE)#(;jKuCC4>>ZVscn4cg4cWvx~U4 z(!Oror6e`(nhWVJC8=?j`k--_TCH)H`k--_TCH)H`k--_TCH)H`k-;w`1vmNLE|p9 zTH`KfhQ?iLwZ>h}42`>VuQ%>;W@y}{J=>T!{LGsa%o~2@O$z1>Kl3I9^M;>!lY)7} z&%8;&yy0iwq+s6gGjCEbZ}^!vDVR6>%$pR<8-C_Z3g!(z^CkuJhM#$pf_cNwyh*{l z;b-2YVBYXEZ&EOC_?b5;nCHr-vA~(UF;5?PV}UbyW1efB#sX*Z#ytJxjRk7!#ynR) zjRljYdHTv53wJ0N^IQ)#7C4hP<{4knSl~?Fn5WinEYM-yn5WinEN~6in5WinEYM-y zn5WinEO1rVnCDF1SfInYG0&O2vA}g+W1cg4W5IOhJZJL80#|;GdDEf`rW58(i!PW> zm^UrDU^-#mwCIBAgn84V3#Jq1O^Ys=PM9|>x?nnC-n8g~>4bUHq6?-I=1q$(m`<2C zExKSjVcxXpg6V{L)1nKe6Xs2eE|^Z3H!ZqgI$^jm33 zSTLDgpw`_q5m}(pePR-F&veQ?laPC+LGGD6+%tV~&$$1dX@`5p>-S6-+%wL;XOe%< z`1qd5`90&>dnVQQj7RU84Bs=<+%t*2XZ&~1>C*3niyJviJ z&*bW!amhWCqI)(^+%qn@XIyg6B;=mW0ryNE?wQ8FXWW0!^!q*I^?Rnx?-^&`Gj{v` z*?YIolI2?xpd?M_L?s0@M)J{n>2kcu=)}uSm)cE6Cthw+3|?-!q-?qzY`Pq5GCJ{c)2;cY zdjp$pyElFA-*ij8=`;PN+vQE4*Ee0-H+>f0bb;D(`Pp*$*>d^Wa{1YE`Pp*$*>d^W za{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE z`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`>^HqVax5;7B|CRZaJ5? z$mQKNj{NQ#M}BvWBfq=Gk>6e8$nUOkapZT`IP$w|9QoZfj{NQ#M}BvWBfq=Gk>6dT=I*Xhb9dLMxw~uB z+}$;5?(P~jcXy4NySqls-Cd*R?ygaDcON--9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+ z9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+9yxa& zId>j8cOLsVKlX8c?Bo2{$N903^J5?9$3D)FeViZrI6wAre(dA?*vI)XE#&TFTFBkU z)Rf)Ft|^ac4|gBa9_~J-J=}dvd${|U_Hg$x?cwfY+QZ$)w1>NoX%BZF(;n_Vrajz! zOnbPy?tEW&zOOsq*PZX{&i8fa`?~Xe-TA)md|!9IuRGt@o$u?;_jTv{y7PVA`M&Oa zUw6K*JKxux@9WO@b?5uK^L^d#mjSu9fSqmFupR>#mjSu9fR9 zE$c2V>n<(pE-mXWE$c2V>n<(pE-mXWE$c2V>n<(pE-mXWE$c2V>s;~fu5*2|yUz9P z?mAZ^yX#!d?)+z$jdkbyy7PU*`M%+N-*CQfINvv%?;Fnd4d?rY^L>M>qumYq`nwxk z3;n?dW5Zdx;Vj*7mTovpH=KbR&cF?4;D$4B!x^~Y4BT)AZa4!soPit8zzt{MhBI)( z8MxsL+;9eNgf=?^H=KbR&cF?4;077^2dke5Acaf9SJ*cog{*speFIXsBz%Q^15(J$SJ*co zg-gO$*f$_0)XrYNLgZd=rM&VDjaP`=lfrR$g~&ZA9Eewl+>^qQc!kJ4DIAJdh}@Gx zVSn{|E(u@xhQ_Pk(>%PwJ_cLJb;c{~V~|4WdWC%qQn>VZg?$WCC~vQ@k3kBTgs-rV zK?;q^E9_&C!X@D=>|>BZDShP|EU$jgCE+XIV0nf82lk7G`PJ{aB>bnp`5S50T+nFJK%*{$#&`;7)Mn6V=s=@BgT|N&Xw+!XX#PN> zPJ_m{3TV`7&}bAvqh5nXLjxK$8#J04(5Ty>(b#}S?FNnJ1~lq7Xf!yWQNux_$pMWz z4jPRPXw>q5dibrk@8NHK{2qSm?R)rJAHRp+dix&!*2nMRx8A;ozxDBZ_^r3^;ctEX z9)9cXd-z))zlYy?`yT$*$M4~{-oA&w_3?Z7EzROTJ^ZbY-@|ViM*+>p@8P#JjiCAX zJ^Yr&5i}pahu_jXg68A*@LL*4(0u$JeoGSxnvdVZZy9+3Ege6aNziB~F{U(>pwUu- zMpFqIZ6#BQk)6G-Nxnve{R;bi$v96tF8(76sD9*o>nv5DiX8P0i2eQK!%OHEm-YN>OU zs#$8c3qeP*d;OMPysx}`2y>X(-Kcb2+ksV^+mu+&9Mtyt=krJ9zyY^j!| zu2^c-QdceYD@*;QrP`L7u~f%WvzF>wYR*zUOI@?nZA*P=sXLbX%2MB0>Sva^YpI`G z>erU~D@*;K6ii(3)d?5~PC9FE)0Aw}kZjY8Y}1Hr(}Zl(fNaxzY}0sb({y0p&&s3O z*rw6grpef*!Pus`*ru`Arm5Jbq1dLG*rt)#ris|5f!L;b*rsvVrfJxwVc4cw*rrj~ zrb*bQLD;4_*rqYqrYYE_A=suF*rpNKrU}@l0RW5 z{5`$6zo$3=;mLj{`+@MJX&^dTcjXqwKyGCjlcmXS06JNkOA`P#S(-}*05Dma>;u4zrO7S;Dp~rG)dzeLOK&hub^tKR z+T&@m2LMWzpX~Xb>;XWM<^Lb~JBR;!4*&PG=HLG({!Z%*z#}V<));_CmZtUnp4Rbu zTGQ`;$KN@e0L;<+0oaJ+1%M-M4*-ztcaGmbaQpypWWRfw>hlj&9{?QL@1Euo?;kjO z0pQ4f=WGRlBTIAq0dQn#&PD(@vNUHO032DG&LsejEX~;l07sVQ>;eETO@B}I1>lkW zPIUs{k)_Em03KPI`~u*SrO7V<9$A{|1i&LpQ=I^KWNE4s0FNw9egg2w(p0Aabo3p^ zo9YBWBpZLK(?3w10BB_IlfM8ovh?3FKlu%SBYWTZ{dblIppoVWz>)qAKqE_2e*kD? zY4RU{MwaGm2|y!DbG8Jak)_FR02*1E<`aNMmge{a(8$s>p8zznG|eXfjVw*`2|y!D z(|iKZ$kNnD02*1E<`aNMmZtdxppm7?ZvYrsn*0TTk)_FB02o=C`~`rKrO96a7+IS9 z1%Q#I$zK2%S(^L>fRUwXE&*U?~G%P^Yvor+{r!F-862~yC3i|208$K*#{r40-9G2i4lm&q8 zS&{T?|3KXa_@0$W-F=B;97+J1p1nX}1bUvO|0n)V)=L=KUhvtDH3Ga!UjUeu{muX$ z;Pfm_+4!E)2yiRQPiN^LeRkw*fw;B)E`e+<;Qyw%_#@3P(5o~9(5&otiaXG(EKP3! zXjYb{`2sqRrKt{oqVxleN6P~`kNysHD@_CK%FKK{|$>+fh7<%H-i0^$+N2DlgACp*;Psnf?vOkIT7d z^c9C;y(4f6vLk=j7jW^6xqM_niEDPX0Y7 z|DKb7&&j{%YJRocw!E{yiuEo|Avi$-n31-*fWsIr;aT{CiIRJtzO3lYh_2 zzvtxNbMo&w`S+asdqMm3g8KS`_UHxm^9AkC3+m$w+M5^DzZbMGFQ{)XXir{Hzh2OO zyr4e4Apc)bUS5#@FUbEF0Uj|y1rKulsMo=M;_?FkB2rv_06;{F%MSpENOAcA01+uJKL8*i#pMS8M5MU< z0Dy=TmmdHSk>c_L03uRcegHs3ipviGh)8ky0RRyxEc_L03uRcegHs3ipviGh)8ky0RRyxEY#@CJ`ylcVH5c z;(P}t5h>1hU=oqydY#@CJ`xaH-Je*irWof5|QGv z0ZbxN+-?Aqh!nRQz$7BYM5MU<0F#Immmgpfk>c_LOd?WTet=0tipvi$iAZtz0VWYCEtPYNCT9UPe_#ia#D z=1HM*zXMDnQe1w3Nkj@A{2gEtk>U~sOd?X~Z1n4lN zZ~?ai+!<2bwg7jA6fWX+fFMJPTN@zA7zOA{?7R01=u4z{zkt3(iuViXOQd+efWAbE z%MZ|(NO9W&^d(ZA01^N;xE~`LaBE@AD z=u4!ytO9+B6qgO4FOlN10c0go+_wCkZ>RbY0wT$>05r)20T4-~_`m}qiInh`4+a2{ z_?8a_0Fg-XZUO9w6mJedij*P%Lt3&x4w1rc3FHtd?3O?dkwO&|$RSc#vOo@zLKS=o z$RSdwf&w{23RO@bhe)9c3gi$eR6&6pB84g_kVB+U1qE`56sn*=4v|6?6v!b`sDc7H zL<*TBkVB-<1rW#~qX1yYMhuWcM)?i-C6Gg;kY55hL<$u}Acshyq6p*=DO8k~|A9tA z0EVot|3D)l07IlW2Y*9F5y&By!yPJt93qA8p+F9i!d)tX93q7dqd*Rk!ksFC93q7- zq(Bal!rdx?93q8Ir9cjmLRl5aAyO!-0y#tq6;~jKNTK2ix$Ag*H z0T?2Mla&Ark;2L9<#%oqp12kL&TYaIx1!&yttbG7NO3C)fFV-ciUMGW6t|)P7$U{3C;)~?aVz?r+k_`> zMZa@>|1OLMH5Xr5G%@^+ii@u(lHgkUUFZXM3SI(Whv{9atY`kQd|lF{X>e&9H4(laR~$T4=FBBfc_!Hr3cVIq`0gA`iB&k3_$;o z;&K4!A5xs_fc_!Hc?{?uQk5Zj(WPmzyqOn+yWH+;n*Y&=0xe(gUC$QWyky37{WRoXeYT zRRR6OUbqe2^jUe+E#{`r!JBR$H(d-j-5LV=hvm5K+jPkU(2v!=j1E3#LTz&xbLyF7Kmdg*If2?0y zE?-G7Bl3b>zz|q)-m!%PgdD){!r>kV46nFSC&1tEPYN znv3tS*l6I(EX?CeNPL-v6iTmrnS~U3qVi=HQfLq5%PgeO9?F+lNTIEhFS95`fUC52 zfwCfnvMNwkq);*i%8C@qp+H%YLa7rdD^e(90%b)CB}$;INTK`)loctI7J;%Ng|Z<~ zR-{l81j>pO@?D^;NFkR6%8C^7RG_R#AqNG@iWKropsYwCcLd6c6!Jo#tVrR=3zQWp z9C?AVB84-NKv|K(nMk0lNFjFw%E~AJt}^Zb%8C@{4xp?^aqa-hiWKJ#psYx7?f}Y) z6z2}0tVnV00LqFK=MJE(NOA4}%8C@{4xp?^aqa-hiWKJ#psYx7?f}Y)6z2}0tc>#5 z#~Dyor1&@k%8C>pXFyqz;^Pb`D^h%%0cAysk29dGNcm43XFyqzLd!2uR;2uA&qIqO zz*WW_Kv^-*|Lzo88v(9j9@-WGt|En&M1ZSEq21VBcfJG4%1T~$z5~jN6z4mjtVnUb z1ImgN=R2URNO8Uc%8C@{JD{vcalQk}iWKKNpsYx7z5~jN6z4mjtVnUb1ImgN=R2UR zNO8Uc%8C@%Nb(Xqia1|-eWdK)^;#>xB z6)Bv%cL7{Qit`INRirq-fKx?^a|bw8q&RngQ$>n%2RK!vICp?kMT&C=I8~%LcYsqx zigO1zRirp~fKx?^b7#Z315_%G54j_FQA!a6DShjeZ)XUC6e%1-L69PazLp?Jk-||G z1SwMJYYBoBDI8}(kRpY?)~nxz_E5hBL5g|kYrXRAC&7zio9Sx_UKA;mD8Y*&g}#>H zMUg@o6TB!==xe?DJ$)@fkYerRyC6uBLSIV|q)4G82!a$T^tA**iWKUyAV`ryUrP|A zNTK`)f)pwAwFE(m6iSpJNRdKc>y>YZ0W62hY&=m9@I=<*iCz(&xcJ5swF6I7S3J=( z!V?{PJW*%xL?y-(y(2u)-NzF(2~SjQJke*u69aL0q7}u{cg74n{kPULJTVxDC)!p# zaT>uBbrVkv$l-|=7f+mA@I=oHPYfI2iFO!IoO1BQI2fK7n8Opb9Z#Hy@Wfaco@k`- zL>qu7PEUAZJPc1XU3j7;#}g+lJTWGQCkE;8L<@o^8aX^ME(QoBE}1~1T>*`X3>sr& zpmEs*8m$dzRA$f^9|Mi*3>s|^XjEv>7$XCXDh(Pf6KGUw&=@BJjcN@V?GC%7(W_H&}b<^qp1Xq zwh}ZNOVDU7L8G|@jrI~W8cfh=F+ror1dTQmG#X9NXf;8j*#wPt6Eqr5&}cb9qv-^V zz9eXzph2Ub0UDR8pwYtwjng)0T&;q}Ic4w|f3e+Y2Y#M_6Hx0AW$dM8<| zH);v~u2$OJq_voImut!F-Ic{w^Dbx$w<=4uab%YKqYFoq^OgB}t(jbHb!*Lqdaa$D zTvW=Lj=eL!&{{do{O4P3EpD;bXe0}*)w}Kb(sDPcG^2+HMvvoE+aR3&}sGB z3pG?!)fP`2KHNiT?8}X-t;SuH(ztPHUS4i4B`9bW*jn|)Wb}>2UUNYjQLcT1vOA-t zmH9HVHEPY$(WA+|!wLRXYm4<}ZM1ah)AH2W+3E7Nt5>IIO2?Ap;6%~y7q5J!zrQ=+ z_qhvm7pL+5d%{U6z#EaE@`YCOcCFnlW0YG}w03l)b1WI@w(y_Dc55X$l{7J`Xj(#S zu+`A9$;rLnKYAj0&{t=*CSzA#sjt+QYn5uPjYE zQ1o(PZS`ii)^1iB5##q$Pw{JoH8d*Cr5?0;bVQ!^>_Ikrafwiw(B97IV9qph83#%W z1ioBp)G^|nQ5k1dfx+c^j)HfJs#sXAE!+wX9v!(|X{SQwW$igI1*Mo!SYwMSuGYG> zg>{HsKZJtWFHG?wN>N2|50Q1th?aV!kRG0 zbZTN(Rgc~Zu!l*d-LBjn6-z7gP?U#R3QI#du+OHFX!V{9%jF+b=4uNvC&so}t5qAK z=&i*?GgQZoS^KGJP$^czpt`%QM(d8+-Tl{;e`j#nz17tNmz{m5xa=Ng)Or`QaanA7 zWdRm!RL%R|12yo~!8MuiK%n8UV3Z&NOYi_rCGWla!N(u`^!<-M_;|l#CzThLHk?WI zLA*sH4j>@|i`k?0(B>eY>blWR?6>bQF2w~6uf4sn%n|#6wGSw0kJ{@$TJ-};+N=H_ zhxP5(?!x#j z+`@uSRqcOj(l&-4`u` zW%OXJ8L6Ow^Z5S){$Iua#VuLXZax^ifQ7M4SFiEn68_r$MKsP_Jg_n)$jVXLwGTf` zZFri$u*}XvyEk9d#;Atm)TvWe<0rCW?q32OO(ymC6TU_sxGqMst??XE;%hf6E42=S zAhqPHtL3SS7jB&GiMLg$&aO7T5E^jZ%j2RozA7o>SwiPtzGH1 zkTa8Us?}VqFXf2Sx1m($>Zq}c#YOu@E}hGLp$Xk-0AWAiHctP0S-<+iO4eVug$Y376XCWZ%mc)YIPR_`( zG$#TYvXP1;%WAuRyV9*e#Ith4Xi~nYNC1k9ska8aIp1nEieIVLZeN1p!}6&QaNzfK zyr3pv;Bu>7$6Qjs{raU zy)RODwT(FAH*@VC^i*rfGje|goR_EpOIYpABjB3G7t0b}L@~XE?x=MH;*=A$KCzOB zz5RQO`a+g8MvSXSWzU5UoF?LSojAvw4 zMb7GoE71U}d0eTi+W5aMIa9rdrImlM>-r~w#cfws5@`+`A5N$lOTnBphdCj~5a{fX zH!tv2ipm-=E`@o)ymXWbbNo1CcJ}I2FIlK8EW_Xo9UZZJdkw}}wg}hsojI31ZO;Xcr1+JWIPN=6B`*-OZ zBZz}x!F#UWj%b~QO7m)`eVpZoDJ{;@Tf{Vjkt~&z39-4AEiqcgLg|k4impyfB-rbN zo7`6~M5LK$8PIy!X3S{3abMLvfyM1_v~bzDC7Eb~IfLjz6B~x-gLgPe)0oSL z>7&`{wQCqD1mWR;PTN)=c{_F*qc~cED^+c^$EtN%I;B;khv!;q=GwKD7JQUy3+AQ< zhq2OtyS|J~53sz^p_Za*8I$@q@F^E7^#=4e`3ieXtvljlhF9t<*z#O~saMu!-kq)0 z5?R)ECMPE5drO^heDG(yS?fwdoHk&4s+srfusbnrh8Dv?xDBe@@Nm9~> z5*Csrk;PIf5vksVv9=1L!5U9W6QyJvTbr(<(fcy{J6i@wW_S%9OZl8uFlD}Xqzq%H zu}58<#iZJ;b-Kba$&=bMX=`A1+N`6gVUQdV!?Qog7=(rlY1D`BVW{C?mcfJuR-B`y za{1hanQ|H1-6iOjEUZV%yb2?=czN^~&n% zr%*lEl^?lLL8G&6JwQtav4G=%Cd=4oJCGUs)J26QJH>svAOR{X=4YoF=O82526HM& zv#7h9=E>CPlf`+cN2n1wq%Qe~m3a*w5hkd#JhTmwiijW+RCq()GM^7~kQ948%K0_w zIC=8q^p*4eQ8gIudr^i5Wp9y~-Q-N_=FZ;@!I8sBA5>OQbrZ^UZT zen4WQ24u>ahq1XOrwmYz#A4Gy)Kfl5ZDqB47fvwEedl_q_KnUmV={ze&gs(E;n0sX zRsM~{MVIc4idmQGTdZs8zG~6lh2ovk(Ff5al4b2;qk^Df)3hvzZ&0YD2IF}STRiy=NYldm5%)a**ZOkk zr5weEymXgkUn0{8DM%cEni zkAp@z_r`S&nsEzaHRwHQ^ay?j8`KcHmy~s0Gh-pI#Q!qy)jMbBJFNx|D2PLZfC#D{ z`nHtxi8f)+Y}jE4es^&9P{F_#3%KkJHyc&&l<~f`a@YvTTX1H(^=7FhC31lc)?s6`V0BLpQw!;*i*@l;R!{iRx4jnYU21ym<3>4rWmb}i8MP? z^%Wx?feA~ohWQJDWqV{xJ?%X*f?<2)2-C+N`NC)!Pxi>IrWP~!KpqT`wya%|VaZa` zR3tyCI!E)Twg9%iG*GKk=I)=Xk^1(Jz!2_5epkVJgwqP;UN0WCuJl$s2jIqT^ZyqoDAm zw4O{? zIMhSSPP^;_C0#GkPOzAO!vs})d$FLPkdo+Ii zU6Y1JDwc~}4alFeDARu_D{CuWYeYgcF*hJ$ZyE<2l^MM9Lq;a;>42dq3Ih+w+862F z|KOQ=QMLR$MK~!n(D^KMPYT?UNC48d%km>i1;-G^D(i2go-;<;{PS!EU86Fz1t$;% zFg~CI5YGs~Vq}JfGq*>yrs!zv(gTh`Xc?Y!ZmF%-Q(r|^!*P8o{X!I{U950WE}6@O zXx4|$db)-}RjJ}4VFiyTM~)?#iC8Ky6J76Mqc`2ty>2$8KY*i6(iUT=JeM@ho0&Cy z50V;o0Hg}Gz23@D_iNu& zWK-yVr`wx9+WBPSK^-##!nkr!y|4A+7O77p^&ymUjQ{}6H4`C0;lRUJP$;X~Emxtz@|oY@%$ z4oxwc9AuyR6gP1F$Fngbo#ob@z-|fv)Fx~~#KOhqyCM0^4?j*$E?|!7)}VP=5zDqy zxEEQS&>N)}wIh>5a)nh(fwoTO%&V4~vumM1GAoQcuDjw|3(f`do+wVc6!{6UOAuSK z{PZ8ZEv@igs1{f9I^8K;q7lQC8p7P`*I^Iz=F`9&N0YH6c6r5)9Vs2L6SH1Ns8vSd z{(V(dJyP43A?C3T+rWy^ZaZckuP<`V$Bo%z$=JJD8zsfU%;)?^_e}1Efq4+G#?(gV zm&k+LhNb2a(cb};l;Wb(?IQ{`Hi^z&o4a!H%Gq;+c8Z2>5b4`hLF?as*P>!U(t02-7}(FJ z&z_r}88ocHKOMOFW{$|v0mA`X5i$4iaTW$j6Vilmpp3IIN&$T zKAQli$}37%@Sq)VQ_mFVGQ^OUO-NCDIy8?%2iaOdUe%r43@@beb?faM?#_< z%r;iM$wd5>POY&xIq8EDGf66<0%SAA?a-nnC!$bgk5PbYOW25md~y!=k@1CEU;TI0m|Gwk&yMm>le zV?9xrlVm++cvTNFr!#`=lYI1n-Mg-h76m^%24XYB`w^G(qlS}_*P;;<(Lr48G?oHq zacI$M9xX-9kh4LD<*iK5q*(c<-6^tY`GJc$SGsU{>f*I?(^t>VeV)2|v?$t^Yn@tj zifL2>JZMJrUSVtEN@k`%yD&R9JyVv62R72$n*=EzI~|0yP)!aW&Xo``F|Oy*^xWrH z&Xvz!xq`|nr^aR)x1Q_s!Ip%5)+UpHBBjI09C z7G1@8an>9?_MoR0J4tR3j@c!Gf&upXEeMrj%{2Y9xtX)&FQ$JE<52PmW6bw3XvHk+ z#Vem(n8MvF7)gJ@^Ns07#=zVcuS}htyKv=l!D|b8-ZJy%?A41G=E`$tXFi*rD_@2CneJx8+WvqJKCeX4WjC*B0Tsgy9T#swWI-e551EvrH`G*@uR9Bs#PhwGlHU2UC zb2^#x;&F7p1-u?i<{ zA>cL;l6rC{yB7KshSu&bXv29)#dHHD5yS|?y@Z>3h#K&v%r%C*530w~@*fL#12oI0&~XsuB*CAqhQJUFitUmzwq(PE|7!1~n; zF)G9+lC9ej;(IW0XB9{B>i!4&H4}FKcEZ;Vv%G(+yB4Vr#l=L*%zQh2u8HTC8_QY_iwNqzqquVX3Cszo^|EwT9%TKCF-i+(OQrd-vHf z8eA)Gcm?rni4|9lLoxGY>&6`HIY`OS9t@jQ(H-XoHWyb`Agi5BN78!qK*6w)Dyk>U zyKzN}xKLKR(`w(+<$w&o{1fm04b=ySf6KC|Z<{&%tnS)X2@8Xbn7feI8Tg(itzk5txiMO~Tk>3iw!TE)*D?hh(M(I6q)3)ck00$fkY64_=&?lfPOl4NUsWxo|}mJGOT7 zA~Nn%h}{8=O8YVzst(ONmgH)SU8??3ai9Bkr2(^t8MH!gJGoW6Ye(>9ypE_9KZ2N= z0!n)8a^q!Qb}}Nb>OYu$^|P^%6X(ER^KtR~SS&Q=amF1uoP4n6U}~2|GHr&GDma;9 zB4AN&;|6Zp2@e$kV|Zp z1|fCZL8b%G+ZT6l;tl*DVp2mS0T!9YNtIUifcUD;@B9Y0;-LhyR{+N>DLC?!4?;k%d z0Uh}_+gn(ubvlz;8k<|P7fZ5LZZ8N$pGw|UdH2mkY|_9cKwYCI=<8mqH;MfT5g~KD zL3JpT3?~DOiLu}L1erX1NEmboeL9QFAQc-?H~KLX#wC+x)B^{IS&1FB;i)vR-B-P9 zPL16)5re9R=FTzz+maQ)5*U(zy@9JNrLLBS4S2|+SUE2rT)T2r;y<&2bP`3K*6fps zc1+4n-#Dp-dWJ96%*&EVuD96DmQ42RCv`|qf6Wpv0S%#L$T9kZ_;A%qx1tEeB6jGD z@(TCnr86+#avfO69q6sjBB+N)36jb}yM+@JS`htxJ zI7M5xAW&%EIfXAyu$`YYT4)>Ux>c)LXhVB`OymvIRtui^cyjajO^!Dv5`6)G5$ovG zvEm)jp5uKjiFL<0W1=g9LeZ7J$-hW_WYA3u0wkk`)Z0;cmfZ=BqMgYdbU?7*a3xCtmMs6$|ASXjGC%8(*l@z2$8#zXG12Ysf@@1_2t06L%$2dJ|s0HCF< ztRJS(*H0R9YfynXR8?6K6uktOH%$$p2BA7tMnq3mN*!y`06BlRPtN}Z8-u|rs4PR! zie^cfU_H)hqYRL%<9k6NgARW1(*Y_a@9kHoj8(2wu^t^dWC{n(3W~&%O_TDkrm6== z3*A%i(nPFSuSy~qmciX-sX)aUBB&lrPGNMhZ}U2OsPE>?26Qaej~T;_@X1cE?272W zmU=V*B>jWtx__neD*YZZYgB8RAvbXZISq5g6>|$MyNzSPgkV4KSAK1dip)R67RMqn zJ!j=sS{No0zEmi%e0hk(Qgl+0HL)lX*I?gExxQQGSWwS5dL8+q!XVK+k4Vl}0EI;K z1pdhiI#@?IUOwf3MIV;*9jrvf_ZjGjA5(@bN;Q%%Uz44v#HCreINrd@I<&{UC)t3( z4~bMt$LP}3t^yJbJ7;PIm6p1x zeeDd>l@^@S$FO3^dOhd0GlTseEvjE&=g=+dy)ZkjuRw0~=OJR-Z%yqDiEhzlIf&hi z4HzOK?x0{A_jV2!$l|{B%cZP!et`9qn5noI44FDx4!%tI7iK!k<+8|&%FN)YK3XUu zbKcu7S}A(Auv7%0K-lo=5K+r`%|#Z{Cf#UaxAJUWA7&kgP3K2weLVNkOxGASaj+j{0o~77$ed#`qvN!nlV-laq2nZu6j7rn+vCEUu8-Q z{yhs#BP6yWh+`xkRT>x$Vzv9#T$Mmyy$%cs6|M==noN_26;4P7ZjF(V&IdTg8( zp@Z2;F^wCAE#^I9Mt$SG|FDq+(cPE3GNU$Hr?PP@j7N!;an{DU|Ssx@sEV40psU(A*uJmmNaIMxI7WZI-S&;Hv z_Fuyypu&F!YhbnfnJvM7qQ^xJaR?(EiN|vP+I|-JW`JPRBc<}$vGxkSsK`KUtoDKw zJ71IN0Cu&bY5X!SG(pX9B2IK|3EOlydzq}@@V^9f^{8vQ^N)yt9mzA*)M)|%^(z|u zDNo5BrJsVcGO?W^&5@$tZ{sWuJ}`CH1;$q2IF1XbP7e?yxT)7%LIc!r;TUKr&X&PA z`hZ&rvICDTla)^NsY-8TsiUpJ7c}uX0zClmI-@dp**7I$x?|)(V93-oELZeulzA(SvHlNJKSyvqHV>ly%{p1vK|8lY!5)BVKH8s%%Wp#3^3Jl#?m*&RV&ajo1*!NVdhDDE4$CQV}Ro)%ppN! zoOP5iZ#ojOu48^@Q@C{;Mox}i#yaMnK&oVWybJNKwpPRB6vj$A-jf`zYVP!c|9`>Trt!o^r;V>hbiql9X z$t&Yo4kM+=)%5JYEbGA3}__+qXr1 z;9#7%C__~8W_(EErZhvf4v_$R#=^z zDT+4hMCPMY9D6I79us*F7gebiKU_J{{37KPa#lI@P)Vei-k*HbA-8iFeD_EvZ9IK{ z#^DqWrRPF;@FaRAv%`bNrMu&q?QS|0L-emeeXi>XEtlyp_M8-R6AkMWQ4VuW1((2e zHX1n7U@?IOLIo2|!F&T{fmh)z@=oR45;q9QOqZwNg??vf?^*55#JlAFn7%W_A4~Nr zOk4$OR5dRwZ9vBB8qm@qwT6E8S9)MK&<8Wqq`V{OCPGh)1?`}FhjVh`33{H;|9AK6 z3gXQI^J0TG#KPz#i7!>)0I%VU+d(i)y>=8BCgb|?uW|nO^0kW>HIO$V{o32s$Q4RG zizZiD@a0oGzh(9c?)AY6Aa}J8-|m&`UUo`G8brH6+$-xgzO3Gmi%c*Le*9Pt#2h*# zC|P=r8~WvixBwLv#2*U^^VYmUcSFuP_gkW?_%;=)?5x%n>Wf%1yJkq_?U;OvO3uNn z1V|!CW@@HT=nps69F+oRiob+*;exPtEV9`u6q)`NnP)32J%AJ$=pWvNeLI78iZR!C zVNL#cVl+$S&ZOu?W%wAa-jW?H3B!}%QwTMD@?BymwlyD|KuA`mmO`hJw;VW9C**i5 zuI;rAp)0K=+?cZJ`f7tH$7f*9h1irtD|AKTa)twyxv%!P#k$a};>Zft7$HiXajNiL z$g3B`&E)ZzW;V2Bt3S0`T#wl@EH%>mT>E6gIdf^V<%CS9a$DBpcA6Pcnf{sz44(yT zR2!G{%RI?Q8SiR0a7m$Cw#c1@ci@EFS*^}TLO(b!KrJCeA?^b#fMLyzzJc7tCQAlV@>Z5+wj3-S z|Kh|JF2So^$F(Rq7mL%&HbS@q(Y`w>!+Yf1^u_79=>*>(o=?utT)E^~eCXuk#P*U? z=98~JpPrePw=3gDEX(DTRw@tOPy!mx}th32&eI4vHCN727&QA=ShAXHdpH^{ha}L?l(Cl0B74 zvR;`f%qQMTPW4`2n$v;(5u`XO?7vv)4f`FuG?KZH{;%i~plmsHdMkPlkk1}5SJ#d= z`ovAoL^3h6ai{0YT3cNE^pNoatWJXMIxRTt`wY3YmaA7ym3)7@Ab{`lbN;fcqVQw2 z*K7NVXk;1DY5A0`<1ClX;_lvR*FH@E#}eOI)^Op3M9Dd;;%vq$V(T*f+FqD^)DdOt z6+=u>fE&U{NiD|=pEU7mU`gBU%3b8)l&AH)FY}B}*eWLP9Y1ahH?Ie{V}Lg7b#N^c zo1&bOcvV%-qibWvPS3Zhcg2M=nB(lkmAPyrM`jlRWU!2b80?8&UAQMrevpiQJ~ww2 zmL7H8i;9oh@Ze~Av{HR+AMoH1$wCBQ#%#*%(lSoK0Wy%EQ1uRsVCKdE_Arj^x_-WL z6j4&aEHo~O%`5rWGApa~acn^VUc(1a-az(HjxO#v@OqqDhg;Ty z&JBGXR4hEwYgB!*FMto2e3$UGSj>w-C!}Mzr4%WJFGJ38D6ubI{V>fCLdx_46Ap+u ziKyi(hO^B=LjTA2zQ0f zI9u!;`HY)OQy7=Dzfweh15|jH>bOdtj*$=CJ{pHG3`hCY2jc~IH~&mcwb9>S`^e;4 zvwTf249htD*~juV8u-gf=ug;@Jnxt=VysOt`dB=PyL0}r+>RSVflqqf;^eOON^N|( z%ROKjuYyj5G!t|F3-;&M@Q2;o^Zm;9h(mDfSq9Bk1rWv$~WSMKyt=lMfm^bJb zhS+jcvD0e*^J8MDEp%iy9L8=1clMmkT~oI{g()(Wy@*U0kko%36f*CO8`+ z_BiB*4T-2~#7hmGRX#`Q{dYeRai!T?^;N|Mktn9X6i7>Yt5~AfpgX)C24;>ybLHDo z0%+}!?^d#c_r9xcs`-_NB&&U;P#F`7c_Rxza`w~Nt3ZlFP|jKyMk&OZLtNrW#^h<- zc#>c3eZa^`epn3B4h<-3&InwkvO;T}60b=gN0Yt=sbpC&#d9fscHcnm)#8Ch+OVDX z>_a5o89CO5hXsnH5TZetOC(TEvve}D0Dx_mO*uM=-6aXtVC4YSkiqD%0EjfVoYJ4f z-18r_(LN?3jy&`t&15EF1iQ?2Ibj4-sm1DhTtwkpmy3(is!%B`t0r7HwH0t$qM%!< zoP9+Hp^2owFOw)ij_4{dh;#V-gx_oo;+88Sa4m3$7CY9@fkDCp`9MRWgKkRt%kvwM z1B9=W+LXcTv>ba?!6V+m{Fp@P3bhM>)O(`ss?Q>p0?0li>wpe?$qSIp3IdA$SA)%m zGFgBI36P&w`)uBbnC^AI` z<=vJh`wZ-m=A~mPl&Z@OMHMI5~;PUjP>U?lG=dgB9 z-@|rMyLKB_`FZ<2de`g3Bz|{gp_VCN4zx>C)86BJwf<_KyCjttz6;}-3Df7}a-3v> z(`hD%z3#vlS1`_W>J}9V{PMw(?`OvDdKND;TUbz(tkkMmIWi~c+F^6KQ?sw2;}BmZ z8d|Pg#__?b1OtSBN3O!v$EsLbd+MhAccR;xxZ_c)n{sra-D@Tg7X;U^-1qp{&D2Pv zAYkU|k^)oi;17Mu$7VE_4UUHy^;2@mN5_))j(_k|POdl?hw!E#t?ZQaw}Z ze-BnFKP>(B#9EWn+*uq%fX9nQ>CTgF`+-sQrKatgql&r$KHm(r;oxX9x%xR{pf_Pk ztF=g(RX!jhi1z}962>1VEnB#-0@ElFE(xFAyfO0S*_ra?vzMmPEqp5V1U{5{Q|`U# z8E$OwNgz`UsN7#SiJha+_u53ySAKXJ{lP)gZy;W_Hj?X^wCl7p_`pB zo@N#hum}FG%wtlq4plmIY5sZyzv0FZEypME=$VyTEC;v=vsZ3!u(Oq)~X zM@a9827^PFa6SN;a!WeCoQg@vDJ#cD2LC0w2dRz*`{MyS5$u#)J%VucEwu* zoRYu=l;nARn%4Q)XTMoSd11Czae2zFa;pgo@qUG6m?6j_+KUNO0?g44Pf$S%IZ~Ym zL}+tT<(a=Uqvz5F@zN6wg_5Z2dq7!V)JVQ)Xq=awpKrAq_ia)>udq_k$VJ3M@YTlg zY90R@T2eij7D>^KDFP;P??Bp6(g z?EHqAW*)j}X7Ac`@!I=lp^?@MUxmSpa`%f&5r8K%ft;BZxOX})t|sR`#1$u=-T zE#B%fm3PxHC&c2?7vGc_VPFl@&8p}-C95Qd^JIzJ^!SlY=%6^fQjX$Ryr2vu8NlfMIBlONO9u*F!NUxlA3@5$e=#n@M$yqHK9St{g8 zzz!|$2Uh3h@8A;TSA7wyj~tq;ntl0QhcI`i4=vM=9%&o(X>c8SeGu24Vo(c z*Rp_*pTg=%HGCXg4>Js?qSswiTuSe#)~92=&}zsBQM3+w98!m72#ezUpcQq(rq5IP z{bFb4S645dz5H2_VW4f;m1~G^t6*Qj*BlvcNMVS=CQ}P43{xi-NcEdk?iL zj*H^h1_P(E2A0d6SQ?A`VwG{bjx~y$&u3SnRTH?R_3D(DuQ#KBumnv5+Lx2na_>^# zi7^9E7*=!(H81B1%!PjP8mqEzfa)u25ee+nAaxK&8W*{ZDwPMbfyI6>1$tVdw%WM^kKRupv|HtwE1~GH(eLK9s^LJ4 z2q&wOb}Q|Pv}S;_BAa9aUSGZ?Vd98ZUC1?3M-wG{Z_&pwbT3Bl4m;ZRKofnaAtpw^a~CSRgfWYbKkh?d)KfdGR3^ zSx>nvV2>72cPHt5YA>MofzDabevnBo{lz9X`-N1SoRpMq;^!Su)M%@ih_Sw3w^C~_ z$y&yHm1BPzRfQ#8Dr;B@I)4B9FDhfdK0fvr<*)D8p}vvGT$k=z-}GdJbT`M!lA1-$ zgKY&|oRJgdU_Xu{G;wNj1)uVS^~RZR>?qMElt@+^U+IH6x2s<$7XIs$oD5A6>rN*Q z{O}rrna)olos>Y6Py}wvD|b7;YCuBu3mEACM6c7Hn8!X%t$7=$MfeeBz1bS`QN)m> z>*+(K+BXQJbZf@B6UI86aD;EBq}=E!{cGFkDv66&lu7BHN$grtCZ$^@bV_tqcVTpV z4x+Zf>dWBB-jx}4)6-1r)0`5Vl6lymVl1GI-L4Y6oXLraP8Y^jqY!bM-pC#y-ou!r zzD&fkut|9+(=PFD#;~|B-v>)>|0o`$Gn*41Mp+(1cFkit)oa!fUy%)W9*W7nVRQS~ z!C%A&PnT*{Y-b#-zNUP0{$Q_Y+r+VZy%_#!30>$3 zPFBK-lukynosnpqRv5d3P2J{FMw;U=@38z~9MmEpc(10d+-||=_OtD)SiF@xmBpHF z!;QwDBszCtrd$?FDV^haZZns1-$$^xFlJ)2F|}mMmbiz2hRKSpqo0H{2iITAP9}`2 zjm+Og?y|V~^4VG%mQ~#Ul34@Z6%0#ui_n}2iSbB*a^759%9$Zo-T;SVDjX4^t1od3 z*?)`*H=lgS`3=S<@g~9ETT*S9#O%5Q*5PMm_gahxEHyd}53#6n6u3+Kp4L^0# zpF$NgwQjGS`5F_pKB8mw{zBY8S-KDFBWkpj!>N<@ci**f!4Zw+KI+2a0{-d00!*#J zih2?2(NxlOG4BH}mxK3`ELo*yViZ`7!7=5)#4un<@(yBOxqk(uT#h}HQ4#M1({f)w zhNX@3|J)~}i>F`X@BKti(8!zjLse1z-qr$=|Fqw~Q4w*kbU@3t*wGH$hdPvBqbt!X zGB7-qkoM|6mN<5zAmr4l@Kxoqgq;HQKo9qWA&Ul3tGYHjJ(Cu7KT)qBB^>-|a8*~& z&dz>yW#*if`RA(&AB_LJ{KfRoL)%f+NAH~JEMI;1?v=Mjj=sB8?Ts%tu21~(#K(Wt zzP-}@>(+@kzxrmjQ#roU_{%Hx_dfXLdkZtiKCZv>mzO5q{CIY<^^0UcuV$yGuGuH* zS>yerer4>}Zd6WU? zhGm|^WS_2*OK_VR)X?J%d=?$oM@;JCYWfO0`>vIzOJITX(CyjMF>(Ev-)pqEhvwGZb+20|icQ2$oDzEqc^*qj~2BR1y*BP7ANJ~~fv z4|*TwN6w7lU-o^W4|p~BKK5RCmGr6|6PK6K@R}Yu@raPL5CN7Z779o8)My$BL{G5G zu1gH>uWkLtElh)6(x3GA(M;d1?U06HoyKAd`Sd^-1jhtZ&%YH8vlOXIGhG0smB+)s zzs7|(@WJcBEeyHPOn=t3CB_EQ>^DQwhUh5C0X*ncBDX_St30%&3n4k&m+71{5{iK! zkG*kS6;nca_fQoC59O8Ro5j6VNQk6l1P&dVM;mVGV_53S1z)iR*+${yUsMDN&W)fp zJV=u3x#3~Tap`PneXn~TSc1nn?OuY2TV5&)20fIKZ=3&M=QO-+l8pA=hGF)h;GvznQYDM+UlGkDORXb=Q02v#XEc7h8 zlo7TAaK41r1u+L38+nV~x>$_jw=9Fb17T6&!w1)+`mi6M1QwNB+;QE84-q$IsmAN} zx_58g*R_hbP2J{7!lDQ+jw^}4;sxMK205&tB{+#w(2{Ugk9TA2Y(y9@m|>0rIFimE z5UseElr*za-dZdoBMDI9*O3iDbA;1UHmeEc$qdmOWt|yQf^*x{Rt7f6ifBvPnCm|4 zeNF3D_Sk<`qcZI&Zl%i*)j;f4rXHQ$DI(HBKRI$0-@8g>H8(ST#H{6;pzBXM<66`cp{2Q@uPmnZuHyExcEQ~M^FOpwEYBaRTLB0GLF z1WpZbu#<4?)MB##2I%pl1A4f!Ud8cjp5!euvN%Uh3ri1EPR{QYrMch-h|Ncp!{{u8 z$36BeORA8g^NG$0w)c)hD5lWyIgv9N6Oo#y*nY?v;H-&`f2Gk$l|LB6p}E9_O9snC zOT$C*bBLIQ!IZ(`REBt=7aolXT!uZz;{?C2rM0DAlRgbCJU8GvtkR;OV0Y>WB0~Fc z#~}>29M8ikn-mH?kB0Z>ofp*wEts?EE~tNHV*oRhvOIQM%m9fg@{FlZW4|?8ty^#s z5n@Fl1BUMv@%&XNiAW)48Nn%TfxmkoFr#su`CeF zEMA#=Sh~ey7n*UcruL0bMP<9lfwyf=(2~PkK!Ht5hQDsFe+?7^xv^j!GN%#S_tiSi zPo{uK;_!5O*x1BrsFpM_t|V=o0|lf7gckVP(4+ODG^Kk|&Vv$eg$wT<`0=nk^&?!c zQjVGIq;td)?5I7acVc&eBH0l;Ssg!REaDFL)pKED8+ ziZ(N~5qdN@?BimSER#1}#M6U)VS`MxK~Kp*pi7nc1<1hCa{ZUL8Y|7#>aW_JZtwP; zZ|?s3?59)brq6%&`GtS?#l=gPuU!30+z7t*_r3Q&`0%5TfBF}1oOyHP zC%<^>Z3G|6$@Q=AJve##uW!C{>e%>+$%#+yD=Mjq2P(1)hVZThfT516kDrjgCzFpp zkcW5PaT(GV#^YN(at0P(J`1CO3#;knVRq#xZqB?bS2XaSp!6;lV6Tb*gn)2sD#&lx z2a3{xHt`LEY_Ffdr*{sI-~>QR08`NLY8^0-vUV)vn)JnK-N%(}S-=5RTkQ$Yshg)K z4r@(%kVCnkYYH!mDl790Zg!XDTmtMaf7NO{9S2+UinUklbuE;2>bhr!bRt4ax6X+GZWf z0nC1V6ZyL4edc7--GRS z_i0M%I7kc9jodR80MX$>>1uBt7<8$2nny!d0x?8ushG!WGZ*}F7RlpshFEYM#8TS4 zF4H--TV?aG(k${9Y<5c0bF_N8OgAoZm=;^e;t@p7mV8*F)svyrwkKyOuhzo*;N3JX zA+{4~;Ucd2h3cg}&KB^&dm>V%nBTZ<>+c#&u$EtNY|#sG%pRzw7bZRdEQPWIhAi>5 z=W-3T<3?zUKBEqf4;o$&$4&B|!C6lT;QQkr3&d4QHYTX&i1ET&Wfh0lfR&V%I}ef4 zkIBdq%7#P^mP)6+9zP^5%+YBY9n?xQEKWNkBj_EIQA&7IA$o^+$_CycoRoJkj6pc{ z+A_LiRbepY60bBKAu@m+-jyh=9Js^TlO8on_O=3+9~4%bDl1JBJv^y|slhTkp*QJt zR<*L}nYkfTVlZ#v03Y7<-eEv0fRY0alU|yxt;i?hq|4*Ur!ua{s`pzpi*!ZneM1g< zr^gfD_{FH)jk~W`>h3RgSC8Vz*&BLL(d*G8s8VjQp580i@m#CFJ zEF#BzR0S}m&6W$PY)iR6+J;o6^l!KSDCzHgPlOF)@dIjI3Kp>gxTz=x1wEVJWuf+9{GPPp!4csT-<9!`sl z;nRc`i_vlkieEr5(tKyabkrTELk%wGEx)Q6Zul!MWwXAt+-=+)(;JzN%5e`BWJ7sJ z>=e1S!jKhlPubce%`J_OyU&WS%qjpwqaQ_bgip$5zo4Zg70zf?G9hM6%)>e2N2=LR zg6IQLMUn&siO}-{@S8i8o(+-tf!|eF143D(c1OrIx zrlz-WMDz4wtyYzN4+y_cI~cQAse>s{v687LIfF%9a$|@>D}TW#573R<1j5p94^Kf+$K;%Hd7 z8C&3O?(JaWvn977Wn>DxESz3nz=bJ+M%ViR{sqJ{E){(q<>glM95~$WVYzg>CZ1%N ztKGlM5MfGuZ3R0l#k%l~`rL)S8?L(l0-4f*HwJSY;AB8UCns}-#PfQt6p<_$F<*X& z&4BNVvB&ZB8?&_)XqBdc2!RVVC)8c{sbpHNgbD0ZmaNA`p(z||w^R0AG8|w#Mw~j` z&RMB6#Vap@VS$e>o_l<#$|⋘gd^l|59umnM&jp`Ikblx(KHiw3?0b<%^!t%Mm-7 z7WKjShvV-hqnh(5EVt(ttX|AE%YK=)I+-kd`2I&9RgZr-|KWS@{`CEKtJUN4@BKw} zapC=+epLJLqsoW=YPiXh*5XYQM?3D@1qq|VuMRoAjI>t-t3js#@O-NFjeZ+-97{1! zy7g|Oc52#aNGtRdJ_Ld*ubmzad;&fQ7Sri|dFm8Iw$)tnWcaT$D3WHQu6v zUa@Id0Pv8ktPxZ@i9}(k*)UE zTG%Ak(0b(DZsEu{8v+f!vIgtcMstb!!Lj89owN#^@?5F>a?kRltbG)vCwX`PHXIi% z-iqKC-t-L(eCZ(w8?;RG>~zqUiTH)}27&@bE?vms!?@tM--5E;&$WmEe-i01j?BbP3O_o*CZjpX0= zd056@&H6$9lb*9o+nGK|E3zqX*M9%T?YH>?CsqL(1)X6t?<PKPyhM*Rr2U)^jsn2^%E1_xT~}V3)CCuRYO5H zyvnFrJ3C`L;2A)jNbx0#8R{N)oucwJx81t#Vi-eS-oV0U>uxrXqpiW>Gy1icN8 zv8`0oPYkJ}FL9u>TzFcDOJZNx4`eh9^31g<-WM*O5hYe~>ZJTPOggjvNkTMJevoCZ zVJKskb+;Ai5oW)w$&4oNAIT>-{Gg;}u7OluI`!>U!bjdU|eOesoHJ9V(D zy0C-`xc+QWi2g>X(e!{Jw|z@NwP-OMjkD4as0Ls*KrPt`1oU~XFKr&WB|%Fph^bRL zz9F{DP9T@uDwG|d=ze4WJ02j(HL|1UBLH}P1WU2r;$nTFE`y4-(+ZH8WDx*c!P|pq z4YXCzCQ3i)l*R=OFyA!cks99Adh6-Gw3;cwX%Jo5Z)xo3nU!1pqXB65k3asHFdY+b zqj`qp{PqMmMHwH**IoC^E z*r>=`O%lk_pm-7I`bJVWqz5-nI3U4IIZf*Pm)H%zeIp;8ZTGcK21Phzp?R}b7#9z7 z*!5TOVFu%0*h}Ix^nYByp}b7YN3K8vBcqf14n@GnK(0~D zX?|D`D}324zN6Q7eZs)rwEIGcSv7A-FMPgGdHEztPvRILm%+xqi3#QfiVy$`F%!WR zP~eBKx|Io59a{67L>F`?L#6>~Us{`;PG|Y37G7`(A7X}Q)E-~@HSCNkQYsX(D#&=5 zLGkblOaz+>@iPXA9AXQ_xE%%6)6Ym*U|5(Piqh{tp)d-DwZVjy@3~6ljEEweFx(4A zi0_ZGprddOOi(j7R3U{jK0e6k9Y0@15%yC@p?Nk2;B1NoUXsxkHjZ=P&~KLFuZiRZ znb*z?;DSgeWm<*PN1;#=OP6h{WQZ(41~llSWpYe1N4G}=;mYsLgS!e-$51oe(sWzT zyQ22rW;8#)9Dg`RW+z`%U~`Lr)F?P}i^FlM^S0XrF4rVEJr;l1gv^T0Pq`#yt$gVm zr>v~g^OH_8`jd`C8NoB>e2`hQP7n&jg1gIz|4Qg4vk4dmLPSBiDpFo+>O3VQNGXuM z7^_vURN2xpuLI45FR59&=Xx3yB=6~n&{pTZefU@P)wAZ?M}wX>)}?7%KgbwV5|n7` z0MQdnq@5%!#Kl5Y!i=-65e9EUhRp(W+jbU%Q-Xa(@=3NBO^ms}#U9*W1@T*p|8On9GLw5!|n&WFiS#d3Y(yxL(=a`+su|XTSpW%M6eTih|7lnXS6OJ==+-HXVMY} zM@uJHpY?q>^m|9%T$nU-MT@tQy*(N#mE#*&GP}oQmF0#(K8@sMXSmTf6nl_2FZ@sSI9#91r~ z_c1UCQ>rJAioP~;5arRyai1p%dQAY$;0Q>NG!Bc&T5uvlc*Q+RTQ4jih~Mn3!Z*dl z%v;g;qD|z;7CLq^P3qwLJRCy0QIN#>g;15Lv%G=u#BDj8|8JM4eCYbb>)*bHtV_N> zn1GI0ldgz0cLKAA?P5xcS)G)}v*`uV~ChN)@LQ1&iSn^aFuQ z*Z6gS_SO)e*}SwuI0?0m%+)x`R_)=mufZ#w5T{b%gmI7@AOyA}A(1@nec=S8AeQdY zu(U6Tpf_vSOmE-%T3dt-cOM2Z3S#{$$qKGR;#*B9mW@l_AG8(wCd(NH|3A&hQ@tkUd|&yK`|-xllgsL6QuGA>Sj zEI3<^&~WHJ41Vz@CR#aqpa>vkAzJuq5vXh)en(WJ#>znsqJi_b?(exVTL!|QeErN^ zk;3WUvhY%gx(V@aV^OuNq_B>-ifo2(ZAE7)-#DBB1VlzDW7RiKA)Jln7ZgygJfvc; zfo>?FXmqOk)MDN=4a(h9TxQ7%CmZo>IoG7uJ(TY}keBH3CJpW4jGle^7S-Oa;~Poi z$<>1>ojm!Fhe=&!v^3NWoX3{j{(!_{|1)azWgJ$Y6dl7R9KOKf?_r^u zb^-4LR;@Q50{CdJTxpe8aFk1ywOS9%%}ofko$d6aaAG2`l)9Nz7G)<}GU%Qv1@-25 zavqJ+6i)gJ0=kwJ)gIYfHbv)0862n;nun5~JaxTpE*hcv)88l=30w5=GpiP4I zIJJyb9|C2y@ul(P=G3*>xht3O4e;ri^4!@^FHYY?6kFs(WkH*u$JX?WVK~typ=o?1 z44c(@M@aHZ+4!Ibpmy?b({|6sAmXE3{&h~hGzD4IGY8s2zeQu)LeXa*3U;RL)ZR(3 z+&?}sr;V>-B@hl~NvK5xBOM_>+ILdOcFZq+U-iS!Vimm|9RxfnZI%{;>@7lok;8S zD(x8JN&OSInS8F=(8(5G%NI?wQ|7RT+lcD@kRvb})F%sbaT+>b(#}RYqmt6SOfFh^Dcn5!?_&@+7 z?>rFY?to+uAUqQ2&+e)eEe8iMf{~u0dECMtkuip2%B}WLn1|XCZjj}rPxEuo&yGx= zGPS`KN8BxTW+BkvUVL^tI5jp`HKIe4@x-5I3sb$>ce~4pOQkknr}-R3A-L?Bi_oc# z%QOjzgXe2gNZM`vG|^d{=~~A8*{-eB1dd(<&3fC&X3X(roc0%o<)+G^1lIM&pV^dE znX`Z-26sMfS-YlRDZx~kIWtvY^kIMOWcEoqi?rZwio|mEnQ&%Jdx%n?FZe1BCJ+5E zX|TL-(0QWCya+K{oa)uE>jhdpORG%8`*!ma3o9JqmGRM9pboh&4nf{=YKLTf7E=mW zNBxNSi!-7r@$yc3?`e%XTo=Ia3q&&w>wx`+2EISw?^Uf z({UJNc++)G;E~|tBHEX(LF5}hI8_}oq+g0MF|=_In|8J;U)oGF200YT>6bxyB?;$^ zF5CLhbwS)wn{J>|*kYC<0Hh`@86ZSwFgAWJGqfSon=_S09oxuMWM7dAj|z-bC_?b9 zWI*;ZSNUa%#0hP8PetpcF59)jHwj*xLC9EKn=D>0(G=4fQJ=InyYiGF?!; zQFNR_wZ_hrm<5e0x{l8tV%dOSQKKL0DStDHqaw*H+^CLhl%KO&G0U6GioT%H#}sYQ zTy>mNkd+*N$?u;3zwEtxe^f`VF8nw76f2I|Z4%mGAU6j{2$+n|K;U3A*>gxv<4Xe` zeA{k2gctbk@AEv8>au!uyA5Q{p8XrY`GqRFXs6e_b(yqJP>Iq0kV{u< zlALFJU8<>WmJBv1UYgh_0Aml+CGn5Sg?)@cd{QL-HJNhS;r{swO6*S&r?+gvn`XYX zb=6|tzjYYy=Da@+3kk{kLL9NJ3M*mu?Jt(u%75Ov|M1?*8lUx!+hW(o?E4nx&LpF` zUxvHb@E`{vP8sVkF`~KV*VNEW6t^j)4trxxzvt4+kk)U^#jozlrVPxnjWV!pF7>k} ziB~FkTR=z~o_nfhf#F|UwD9>L3Z}{rUhXvcA$G;0_>{fS6cyWtUNQIzXPPmNn~gf|37>^(Ysr6hbv}1cABjiV>LaA=C^wDjyyko-lA@;KBfMN27mKwFniRx$tZ$ zOUw%wzB%tVt1=8s-TOpqGjJ4XQ2=_N%N$dp!HKrm= zxsjW;qYC(-$+R58J-gH4_<)pRAKk;;nl$+j_7J;TnIte4ul1xC6y*1!Rp18I#5e22 zV!Y~tq}3=@4!9up_?*T?GSJYv&*?uUH!f|6}s&8&u{oQz}M ze{#6g#At!)@;Z98p2c%NTZFL>aJJ#_+?DGNF267V+hJa5A4aWMXlZzp%3=^4q1N*n zOiRo|1?Bnq!R|IsJqw28-muEN*1iHui|8i5?Bs{<`{*^njOOW@{&h%Z!RF3p;bC?^26zu z!o&745b_E0HvA~;DN|q!Eu3Mf$|5^uQ5Kmt)k4y6f!3XUr2pL64%bO7C^|{PcL77h zNV51QDV>X4y^}uDgPO&Y;R`ku?kj;3pL#7*3<7OBh|y14M6Dt8R*eJLS&X?PHw$#w zs|r%Mv4f)pZ&4|%E+k3O=&l>bEBo7dllLjDvRG|z_I^V)Dnv&a*b@<6LksGr^T~Er z9yDmbU2G58FJ2(mjFK_zh^(;&p!^)-g47|1+y)223E>wJMWaW6^q1JgrOL27FO=?=q(fYUIYAry4OG+nZX8AI5uU zmw<$w!nAF7bGQJdT`0|TV%rdflG(ird$I8EC%+>dd*n*ImlxX?gDfHRDm6a{6dpYL zaZ~_?Pykgi1#s^0&PP^0Pyr86KqCpyaY~Ow0wQ>`)h?u|bjFp1X}t}egCLr=v<(0& z6`>`0`s7MJqG+2e!v%*0^!i?Gw#fuN{y~zMNu5=NJYzlBV?1w}C?-icF^txsp)0_r zop1n5ttC^T)$(-4JOU+cy?|Gg_iMNMh~S_H*^NFBZ-~Jy9z+RsJKG+w)m!F=ba)^j zI~wxvP)d7*E?phq(q3*HSr=g@-QI#f;9z@y)M`F4k--3j^@|s5?)arSkf915Y>W0C z;7wh+5v8(_Kn8l_90Ouk3E;RjMPVjlOssV(5Ux>&fW%2&-FsoEHFaDGo`lIqyO5)%0_kHv|9uA`2zA{>iE;3wn1QC zi3#7Vs8qtPbi9Far@8CjT)hJpIfD1<7Bg21`a}Zcku%i?+3g`muB*c@4uwtiBz8_y50TK`PajZqw|-}@8JUT7s$nfpW7R+@n59W zJm$onkE`Q{yCZm)fLRL&fGj2eztoudJ)u&%NXIFByLV!=>wMNR3ossyG@%! z;%t$uCR1~a;XpGrn&u0Z4f8Z?%aN19GWCh{;??RM`fTJzY-3SNHiy=n3&w@UVehG1 z@K@s1!T*&Ub0EM$d@Mq`LosS&Ig5sW;dgT#1|^A7eaKh`oLBNAo_yF_yA;dX%r!~3 z`Iwe#BVRUpV8DKKoN(msE>6aYx)j}Kl#QAB9{rO%sn z9AEV4`GWvpxM?3YL+;`G&p(|rwr0YG_s6-VGo8}R#5>@))qkEs353#!vAQfxH>yEj zrCh=hfY~`X$#m3d8RoTX=xB3DGC&=3jk^GNAiCOxvepj1wR#|aIco0_Rk9?Je|gTP zC`7wc{^-Bdj>eBm-qQ%i#t#q-PKqkgAbuL!@xy^9g2%VrNqcJd8H~+;+OVK@JTDT6 zScd)Y;oSe0OAY_8)LjxGt*RiSJZ1AE?242m(~Mc`sIQDwS`@LBp;UxpN2$vgzBQpX zeSmo<72m=IA@oI@nm$&C@haBs@gwticsZ=SICuq807+3oivVo82=mf;$fQ+kosJF2 zMLac|Edj0_AiSI8X<+$mOJ|APW^#c@z-{azO|N-IT6*>Z+SFwBwumwH`xtJfTEK{+b&k78kb1Zd36ZU1d=~JH}bmAfdicfYg8%olfc@NL^a^b^8MT|HXwq z4&@;88KATs?Z4iG)Z+uj5hgSa`tEV{X&Hk@y*Po&g9W^?P5pnsIs;U~_^s@drQg6* z{7wheesYD^Phs~doG7NXV|jSYwsB6eg7x_K5UfMzY5;+ygggrflv2Lr(PDhUu(E)9 zj%rVgiS$N8Um7%~B)<8XY!Al5c-2*WdvmOY+=k&Jt?L~mK`bO=blH>2VF$Ew%Em{` zKu)&INA`e|n<s5dcb@MD@Fz~ois&=xa7aNi3N}(Aay)O4DT+$VTu1r@Wx6R zbo{S#>~hwVE)Jgwz?u3g=fLn|<4Ar#4r4XoG9a8gw4! z7jcWmwQoWY)FsZ$Sr>{(u|go_a56Fz!iyG}P?Bm-Kehyk%jvk)w=0tvv-^{}rs9Gh z1K9_h^}F>M&P?fxJl%)8&z6_r1+|R})|vDszGCz60VlKw0%0szVRJ;lPOI1Gc(HsAA4vBE_kAQ9&NLVL=SascBU zHa9v2@NDVnuk(Mq^=P0=kdQ3!$^ZTCw=XU{#R`26KPg=M@&`6i%g9O3a2o*XidnF} zCB3)(a)=NYsC_`=M)TCxvS^7f_M4~R48!Ncqo>Wn_V5s!7(u{3t!t@9CpfS?k&L)$ zIf(!31VO=y6~=iQeXv4=fyc$ho`*4Jyf=Rf>}d9YF1xLh_%vSeLtRlAOQ_4`cM6F# zI3yr{Yva)cG^a3*ZmLj!t`=e^hj&IH$@3$qcV3xtf|MvwppZxy%S|E;Li??pL3A z3%3#-Sui#)ODsuP;t{UZy~o?zPto9%ZP*6(hKPZc0D6^o4w{k?7d-)3 zWBT}VZhCq+tBaitJa3jXZ9qi;8NC5rapq`X#IlVhVS_xeYbueXk9SCY3LT>O2piK0 zPw2qUrP2HR=M&m_W#6K|)XpBJDOa_uTw2s#gcnvo^Bo{dT^BB<(@Cbv#*Iq@!bKcOGJ3}N3+@12B zH4pZI5LoJ|d^oaL?8X(fC_>fo1$v}F)3{K1a`m}`sI7OxaLK05UoA5Z1~ z*n^81Chd13Yz2K(BSc3XG|=4Q)t&n=MEy>eFvcbyVmnB=daIFRkXysBYk9|XCNTFN z7qcO%VQ3DoyiXz8nwT!i4CmYcQm?t-xMoN^b! zq)^_^a0M^|{|epTl+SykXMP#aYPe+H9z9seRc7hSTm`^_Dn!;i`Bs5 zi;I`69bzO^>Y62%Mli$2LfTzm48ZOk{LU1Qur}x%=F&e#myS1{kNTSje=PpPvI!6a zWw(=S8YW@Tav_{Go2y@c?bGw;PRG^7B}#raWhyxRPyVwEIEkG#^(yZ}6e-u>u_ zs19qh%{+t@8k-?QWmg?n7qVMHm?2Fmv5JuKEFC1IQTz^d2tKZU#W@64GobvctHdbtu*vsgy60E$>$630MbMqW zMCYCsuc8=y7A(l&T+c-*FCe?L_aXmHdQZIC=gCBFLSz99c>y;i<1PyQqy4u6rLh<% zAPN#cl&xdAM<6){!*rWNq9%d*y z-Y>y2mBEe2B9cTRg@0VM*&-OR9_f$!I1b4h$+>gcj%FI3d!3a_hSpAykzu1k2eMw4^%yn}OiUYz@FQ-M;8jdr)FP9I%D;po4*dL_cnyKphGjxE9&+ zt(zkO-eU1dYC;ut>&?46E4!i{-xqnzpVvvuBKzvPItX-UkpgSIzGtkGrz2(oeV96B z5UAJk;GxZC#?f7X;|KW(&Vr++=_&gm8!HI)Tul-s#Zk$p^G-K^gvNgz)Ip4KLV{JA zw|?FR3XbYU>kg;Wp!VpXLDmO@jL1V&qj{j02)z z4Q~j0%UO4g)^F3r$Vbac8ful;n+q@_(j}0e?mhVN*1feSJnq@r-EpJJ05SlqQ>b8Y z*%F03Vu5yf^9ZR>^X3BL1u{APPP1ti=5t8Js*uO2otB$p8Ry~0N14yUMfy2F42)ZR zM~<$G=nwDP<_!y#0eD0fx2h;JAwq-*PZ*CF3ij&zV6{V}f@v2LfKimQm&$7@;Vcyb zIELX)3kD{2Xb(qe$JBP6LFnX_12Ru6@KvUw~cXuaYNZ;9hf9(x#|I1?Y$kEMi9o z(+IM$3Q{X^JDz2lM<+otpbZ@0@=|jQ7S+T1uz{L^a19H8>4Ecu{zCXr@0X$6F`ihd z>-#sYv>$nzZ-6OiIFLj6R|uuX(Ft@&xXO}gkB+x-+$#z(!K3o?{46o&g~cx}d`4H# z)RWc38~Lli;Gg9(V8DZ8F~Ybg*o(or6Vw%iuFXG}ox`0(I10p#)bGd@4fT%eEIYAM z)y3SMytj7o-|?nwz=3?N*XTL0%Lpx;z1S=QuuBL!ZSaBzx)1Gj3rtZA?QDv zMYy5_6@lCN>fo=mWYU@mJtM6RE$0EQ1i?`lh$k&23rzRNv}hu9iBU`3O<*cv5l*ca z#q_*7+&h6HAY96l#m^P*A0I~`(;;5S2}}#osdN82zm2#f+r4zFq_==BjY~Mem-znx z4UVLPp^R@^pw)q5K0N#xJTYx`&h>4Hv@k&>qPxMEstIgj3}bU05=CU{Poj`cd<*I4 zO?T(-C|~GX9>u$)QMMKnEI2r54Qk!dbu`BZyZ~V|!b$EXv!Z*77;b0xU$6b|d$HvC9CAnr*pdP0r`)IfS_p84B4#0Z#OA>LZz z5(R+ScVO2myU#o3a3q&Z3HG-^zKd`}D#wvr}i11Yi(!zAfvmhHLhnlEw+{J+#N zexk2c*s&UJZH#|Fmg?kXbuq3Sq_-h%5WSW7#n@@ zSrMG)Lek+*ncIrh=^!U3tXHMGM%)?>j7yBgDwkt9k73&q=1; zQgMbFsC;N~;N8FJr`dr2 z`!w+JuLxEet4TpZ{pCfP~GiiOj z!U+fgECq}49#8WH3eCbWs@<0Bc^-K-vj;gDzJg@9zsU79`5FO3F*YBnj}9d5zi?@= z%MGGd9Wti+vo&3!Z9>BUx+3d(0P=$lis!Ln1|ZoDrXqL9AktLneX&Z>L)oRx*)H}$ ztxzZ+G}piY&xKc z&4$CW{a<5qY)0QfacUX~P;krA02qb<4gxU5D>vtu&t#U*i_n@Dq%(NJ=4Jq=>38ow zx&A#uOF#LD}w=O0jeQszVfg41Nb8-!budMF zW!NX^N&b0Lo`2aJiYcEp>%-A8EhlOK=JZ!`iypm3EWjS?@t>W2u?K|U9mm@>vn?*C z?o(}up3tFmnJ`u~Vg`}x54SO);-ybS4C*b$<>??sXlHQy-fDVH^*Cai1*J~tx*^q= zkA_N)w~4@ViN%OkL+ng85-9x9=T{@KK(7S04O(g8^SK8*HBpvhog&LYx2mbpm4O_wxy}C zlB{F;+eKTGPi%A2nN!);Z8?TC;0`4 zm`~jE8#{sas(GWQO6WtefnK`_RHG`rV_?4*6^;oRj@_`>(0RMSoTqNKb4e9lZqD9{$izyPG+IDNeijqNHO25sW8AooQ=%XF*bNnz5W}Qf3Q*{`*wWkA@=@p~bqHd5K z7nC$+i|{j%BsLf~`O+1%94{Hs1ZoeWDYo=zEY1BSEULF5)ADS>RvrslTmXEJtW+x= zxLukbHRrF)3&n&Rn2rN5OkF4dL~ZczHO(vX$XlQ-mjE+TY=I<{g~Itaj|p|A7dX%C zM9e#xU&$L`4USOwy`4QQZn0{Q>qV+Kg#E%I`Bc+2U{4Dd?3zjCXl7yT_bCsijhCq9 z7xYgrF~s2T37~=sL={Xc7w!09GK@c1BizVV$lpCccikGa2vT_O$7kBPdC(RPG_o^; z^tf3H<0ZqA+ElC{vmVcnM!R6u2p1H0Y%9d2wJ+RmuPyRyoIbXq;Ozs9S?M*=I2J&r zj`NFGuH3~c0&0(NLoa19>D`)Q5o z+UaCx#1l#v)bM=;(+vs8)hj>B??KIh%@6G$YgI7{GyE}fMAnnsF|S_m*kDz=>h>0# zo^MfFvBo$^|B$e24YdX+lQD88F}(;%(zJ<*5Z_6&ash}s$NvP@K5JHJ#6_;4jVAg{ z%L4SOWX{at4NqSYqtd>;I6x{m9*l7B06EpjrECwRQ?kHLt&1*YnrKfFE}J1zetW{J z6>Y@ykK};Ow(4YGax)P;G>Kxa{fY;y`ueRkPP#(Jz7*Wyk*~lHl4dYXemzZM4Y^o; zW3O8t+bFZ)-Qnx)Ij zOW!UpebxMQe?5TaGW@K01eYATxMkSDuaKkQh-WD9?0Gc_R0u?LxHuUiwlNh-g7(TE z!>toChYc`LI-h_)T`4=Mp}2$CP#hYNUK9ZmI>B~PWfCCfOEU#y*7!F1SEMWMR!JAB z=TVo~t6{r`Jb`IqN`OGX`_2Dad+_rl$QYQwFuR@M?)K;g=jb9wCpRcX-$C`g!ASRL z;K`dgmYQ3hE7>6>>A8z@Q59cXGyCQ8($%?l7t6|SsXg31K`PDBd)CHuV6!}}^0m2l zzhM9z1I{s(DNBZs-5tEDw5UqSoTf{K)e)u%qK+Ip;>#o2{yFqstc&I)DX z!Nc{{2S4XK4&iC)G;rPirU>_YkOsg6LH0QGM+Qh!Z-!gEWWKS$FmO!bAa{V)teKk# zDyQ8xwFYYqc`GgpJJ?5yN6jAHs5q^X%|o~jP{9H)W+cawjmy2Q5pfk= zyC!Z`fnF{?DWuGTY4z28y;!tw^o*EV<<$!Ui$QUV{cav<^7+Sxm$m`wR(^GaC3Kc<=&kN}ggjkOoN<(Sivj+5L()~RpNq?p50G}-uY!2}eWqT% z(8~%ML@4=n0N~^BANd_}8vO#JSJJjO1u@iraRZE(Zh!Gd<~lk80r+DqGCu0nWMz5s z>QF`QH|_n795Q|U0+Z4H*Y&R7pW*EnsoA%}JA2Rn-c}P3?~AuF2l(_BGEeZ2=51=W z3x=+DXNI=T`Uye7@UL81ULwQC+odH8?F6=&FTaN9yN~^L#J5-cEh;8x--0Dau!(O9 zAG=vF4(t})&|W(mv|V`YdN(_66CyrqCX;E}&y8txlk037dbIGbyQ9Z?FFo61xpr8o z_z734OpJn`H(t;EiO!WNHZZ+r-4rS8lKH&$8SekZfgHtqdq3GY%IgtR6N=-;%T0lhM~ z?%=X9~B2pW0ja zn8)|K@u_HfUzpIrXp3hD2RE2UW^?1{#+8JV4;aB>do-4+I)hSS{wvi?GtugVq8z2R;m#n*VBoDiIYl})P(&1C8yp%WR% zmYYud=wq&jqYaw>Ej|o71#Tdxb0}L_WRlKu0PTJPO$E|zn1VY-w>Ygw|bb^Xqs;sXH6=xwp(*PvXk{9{$y^==b?i) zlODK(oF8dVOU+~*APK+GqC2k4K?ZzELvo(d}WKRs-aA0 zm0W1@t{i>jovv;5jV-smI|F!d{4o1Qsl@YVu=}D;2Tw=4AWkyt7L^yV2f-2~iMVg= zX?#4X6kz2JwI4x$dg>lf)&;g%uSNbrb)JFD@;KJ!w*ti%DPYoXA|dcnzmJAX0zDUM z$Or2@t(6h&X4OY)&l%`c@t&+1%hrQKg?;KgB+x)e@Y?;9Se0LWePc@FIL;l}TCk;) zyt!4oak?=3H{3;nQ*Z_d4c)hlovP#aBm$qzdC-Mxl-NxQ1+f^kn4cwis`y~+ie02x z+zX{T{hN*xqw*F?S}B`2K;Lu80pS306T*zQ!#9C>Y~mSyi^f$cp-FhM|HS;Gm0Vt% zZXsTL$eJjceNQw_MHr{vspo@7%={#o&xXq{Mi}1&VOk z05d5dAR8z*bMJ>Pg?=!)vxh`$&|Q%pH*bk4(#~#b3=0o!2AUyhF+cc;Ff*4ozr4Wt zHmp`es7>N4Fh2*=LL3uVVDFH1)!S4LiGnZ?*sVJw0}|3W(Bb^FaP@ky`twh6(JQtg z`%Fi${55zjk*cXwQ!(Ko6fqf($#%g6>0>R{9xSlpHbg!pE5wbuc$eQe5&3u9oJHsG zHrO4|=XpSHnAjPZ`Ut1@-i$2}dLkqM@(x9t^?qFvLV|ZhCU_bUz`^#x0EyaRvO%ZM z0)}X#8+6oi3J8CLlG0{5t3IpbIEw*mvNSgfL`gkw3v^@0=VLP6dz_zl%Xrq+G%?R) z3VOFydb?))Bbb4M$+*~NRDfIxX|3RjBRV3`t6LEOGwcb~@*+LSx~d!fpQ zu!SELq5*7p23PX5FHEhOcaHnb&E<)L@J9&x_7&!!m~}&U;RoCbtQh zAz^bJG;i&apNNCGN5|>%fz_KfL70NTb~2*Tw5)#?8BLqYK%v6$F<6k{4U$6X+LCuq zQz&p<>zD<`m}9#yx-CRsQ*1ZIPCcQWbj}_!bGRSW`#gOYpU6B&i`j(Ft(i;37*O7Rh7#y~|*!W#TOJge7 zDO3i~zZ|(V9igXFb+i6yo)As*5SI*y36tKiQn91k`((+8q7GJ6XxE6(tOsUhKD|io zqw?$_p-IYkokTXWd;7sDsW!SbKVIO0a9e%=e&SR5g#L2o0QR1~Q0mT=up~FagEkcj zOv*uc-ioAmo}V1u$AVC?Qw%F?1a`Gt#WP8G0$MZEV2WH5v4xq)XRx<%2#$1{d&^20 ze}?Pn#E=cu)D4`#vG~!J)0Dq-f8FH2fBRq`-pyp@B7lGmk_8yOZra2Ox64qSKj+3`=5hc6Y`d@E@{EtXS7zq`EZ_z5^3zK+ z-B$AtT!l*KyxgTLq=1g(1Q$gzg9J3a`q>~lAK@~jefMq)HsW`5ajQvHP*h+xtx-|| zkWz~K^x$gio{wo4jQUtY28OK{lWy(JbqK|=Dtr!fI+mqpD+lfnCr{p#rVa72iA|1U z3G+Jd_zLdA#bkV@`RX#fOZA^C*YNA=S6?<4n_ma}gZ+a8(hv?5UgHu%kV^c-Y5)@w z@lR;u@>mmla9V%iZRq!@jeOmP;?-~n?^Hp-pQkj?uD!iMpL`Ahzb4mhSECb{*ONb3 z*U;N_%wH@9YtCb1^g?B3!h);4*Hn*{h z&G0$A6`3^T56vU?y+8hd_bR3Xhtu|+7}0AD(cU7tmG(j0Hm~lu05_Fp1h>g;?9$0p z&KjFT-feW zUwjb@0y+4#K2gJqKAGS7%@3ZD8y&tVtxrohlSY>WiT5sA2*nWaKYtE)6vI=qU|YRE zJ;T^8HuCUcpoS@ngw3PYpY0wT@Jdfxc9-zOf#QA)iw~BsHo?M4C^2VZ2G{cXOyMR+ zbTIEv5YFH+y?>0TeJnb3z~S&x3;)F|gAu`i5 zu^=zxvDn-1h9ejdk&l-FN$KPUuB1H}OWis@B|atui&KNT?=eOqdoNLZOLFWe;v%xm zD%zFnQ+%#mL#v07lJ7DAzFV6sbObpxDBW6*C@WuhvtqyUAxMlOSY4XTS;rgTDQ`u{LNR_TE#1H ztA{r1RiMUN7-v0~!28B(5YHBZ;XZ)&5V8iJv}IKB6_bb|%S;^}fFC`?;)6pZf>JZs zgi&klzi*VpKP@gIu%jRa*`^T_0c!D|PA>iw^ukBIg20=V-w2I`r=~gNW{giZnNMds zVFI7Tcj9}sqN;~_c}4kIIZu?YnyelswLcs0iS}n@KDqpC+$YLcAXg7#@M~Vl)!acJ zu40ToieMJg{)1{#;RzE&-$X@C-4Lfw>n=wJHSUvHa$k)t(b)e}zxNnueddwgmX7Zq z$D=znjg4Mhn<5WIkkVE@&8a&z;ME|Wl$Np?%&yTwUcRmyo7OlV-{s&P4=UWgmRgfe zr8r87wRlmNfUHp#3V|tSqEX4I2e?*e5bb+1D+rSLa8y8;5}jT@G2H5=7k(##L$Zsi zF578K{JeRjteP-p&_RbQ0{Tw97GU-}I8vnT7IKxD8gY=s7z_n06Oox?!!`t<#aiTA zY*vs1K4T8afYF$Z0uaO72W3AVqgMY{rpy*bxIAMW*wU4UUxJx?>r- zkXet`TJp;BGE17Q3XwdON8cJkX?Ys2+nQYHy19i`VzS(FESHWM9hFlG>qX~UAi(33 z>lPD)7seha+9Z>jIt7L(o8ozx==|3vR`r_#LKq37U1TloBRPNh!omLMY8ipiaYaL_ z+^4wZ6H3azUW%^mP1;QE{1`c-G(Jy}MVG+P#&kIbG-ppc;MZC(+cYAAX>VoTX~cW- zUJ5uhAm1*O{pVQ3NQZ(e|2B5P50GdSM@}#VT0XjGJI|T91S$lzh*Bo9H@55EhP@DW zLEdolDs{w2c&QrNXpuV`{h(C5O>Uoe0x0Yl8kj#MJJWF(_{ z1H$Jn?7A&{S+VOldEY#FzBu}?T@(maD-**s{VH^$3G)L^AZh3k^HV*&{b+^BweH+n zzxCs-wUws=m8M>VX2KF@wDJ@k|K-8j`qPU@|MlbG=Uewzo2hhY!aIJw|Qw zbm!57hyN{SY0RZv>*P1h?J|xgMz7!shviAjmqd|+eOOR&c+QwO_Xe4L+Kc5rdFs=8 z@1A;o?w-8>3jWMnr;?l&_;hyR zdrRUBV?5)`{6bBclf3badWWhA=buZ7<)$#16n$6dCPaPw2$X1`{Hdh4dbe5m&(*c{ zwN9e^sQl7UHcr8}nbpQvh;P{3rjWSJb(~3Ly!RTLD8&7(mrt9M;~nKrvjE(FKVC~B z;_hV>n+Vu;x<8Ly`(SJI+X54AEnm8{J^X!95HBKL_!2%{f)gsTvtIgg@#{;& z{Y!$luO+zaF_6+$FJ*mx&IPimJ`e9<4mQwfg7-NXKex#z4*ysNgrQSC5l=NrmX1FxJ)WzubDXwz7_kWPlBi zmZ`d)kScBE58N39v)FUXfIxLd`4L>Lu{+l+u7|m_a+9U`BoN8X6j|R60fJTZ=}2^$ z_Fv@0;|9-v+8C9yM6Z58bUa)NQF9+zRr#ueE8@m*2$=NsYiS~~>bZd|e6q8q@}w72 z$-9Z%26(PeWvT))EstBaq7za# zQm0c`EHzZvBPqlNDNbl`u8?t?`Gr@94Xlo?7ihsPlcylw7}p4+up{u9}QiUe#$CmEQIUr{dpPKGbt z{f0}TVG~|t*aTwjkb$lI_ZFU3oQSv57ocCsDdn$Tq)HGMH}Tc&@#@l|!4GPW8G1h^ ze7qq6cFnTM4}yub zJ#&Ei2<=&j2+;Uq=aBggKM=l;i9e^mvdLNDE7o@h7s#)oT>S0e2Z?8W);z?9!o!4G zw!y6jxLuE%i^P*uzGmgUwUv7-x7Q(_+mbC(PO0ty`JCa5agn+0BTaDc&Gsgne#i5_UPjUT3v|S2!ZeyO`RK-V`&*5PEDAas z3<@|f#yMU1kt8k7WvgPCD}QY5p140c+&@?o91iC`8jvAlieOg_aHzJ1*c2d4jXn&* z7YNbJ*Q$~6;278zlL3XJWw@_=MCdW?TgW87vmXaw4=hVJ2}8s}OD%<3>mSg>`p8I_ zCUWZ%sHkGO26ZH690Sonn1`V)1d0&BuYC%TJ7{~m&k9BWiLa;Q(-jdez{2eI5(jnp zt|msdj|(4Eq1i$J6-MoHcWQU6f1lO7Ra^`qG}ZZFSP-up@;{Clw{+FS21#*yYvX7N zZXC9j3c=(Pl#)NU{DnNZyn+1TW_KqJ{uFp|{ra<=KN3zR;jsm)azpvr?(>YJZ|z{$ zH5a9i1^F75QftohdEyvpPaZ~VvHv+_Az-Hy#m4}?H5Y#(-Ao*i&vrW5egBzg4d$Of zSZ>aWjjBV$veBGw&MGA%#LX1;D;zE2<|AI?qtGgfP9ASnIjzzN1(C@wK5zE6zeL6* zT*3hn19o48+#u5HYx7z?=ZQC>%@n(XkUUW z@0e5q8z=l=VL1&^Gl0ZJaRnqE9UYD@DX(2@fGLe9Z}P^5B73Vxhwa(rdLaV3+oi-( z6K>%@X^8P&ieWwJ8Ghiejr$}e+7<{)7Dxn0=~7EztmAl*RMxUW;&hRfquzk0laj3? zxHOEM?!_TMyDX=+jZ}71dj(KH!k#4iBBjEk9e9{jV~fi0{JRLWIFUsH?>xCrdQmdy zFvhDevJmhzq%t1eAyKrutW}QSH108w%uExCo6cvb+TM|NCfWx4TM1GZ@ z;wc1M*LAw6FkP1@*0zsq1{~K-^bm=78m`+le9YKWQ+jtvt9GUM6ukEPxYiA|Y>&3t zc^}lrDL5{TMbb3f$U9*wMq3+@c;ntz%mrdxyAo{GOvMl8L80#ZJUn`iWUG1ry#}RO z?4ed!UM+F%4o%iwj*>QDX?^#Hx`vN(Ff}G5HY20yqVU9=xRz?qDL?@r%dw4}86@tN znh6~_SQcz|7*)lgGjJJ-PZNoSjtd`)jhz- z`~yj_*AAYw<*fc^EkWvXoMG(1rt!~IlVPRsyHU3f&^6OFo10@E0zJ?p41kxrAy^SE z$P`0yfi4s?*kqsyZH!<(#fBph(NE*(hfEa-gUiG1I(o$6#*F$nE+-h*$9ZnzZg4WK zNL?RO#}Od?QvNkllyYj8eLvloV`FH4NCmj>6N6xgun=5?%a3s8`Wg>Nu|t*(FkRpa zvJ=F$fuGO?S|?;&doUF67>buT$g){vi(5-lu1~e3Cr6^>`DBBV%(>^E~D(%cUfmBxE7YQ$9i_IJ?xz(^M};;*@xVsjjTtm|*7<>vN-`}bGZzq2e$xSy7eeVU{v zz0%Z~rr1V_ouNWR5)nVx0-6Ev{b|b9&{`>zH-~a#P|PV=VcHl>%E@f;j`>N*s931D zN5kg`oIuE{3^{CJ{?#FlMN>O3z(ID0N4cR+{;J+?7TL)SAd_`?ghT}oGX!f8V?(pVTJi=WP ztuzm?Q625zCKsMvl(1GEplFBTWxPMb-7zhbGEQly69kQG@64J&(Zg1Bnnxg7b65l9 z>leW}p2IW-du#HhHDDkCVy8J1MBRv}0HhEAE80iA`Hwbg?M{9GWjERJ zs=xH5y!Q_WNi3}zlef&0*eR~2s|`sXbip`A>@*F`kY9od(ceo%1h~y`1ZL>YJ7K|d zVhd6tA%m`v{^1794U5A+aH$ZShrlyaO|*4Y>n0zR=@t1ZkFx86j)3}QoC4Qxb(TB+ zDjmmme5y`X$G`JfvwrJ9#)tGV8ICOrkFAO^B&XtmJu?9TVTQ&VV`i!jM5444-05c9 z2|`bY_+kJ|6ko6}dhGMr6kvnY72htU$P0uOjl7+84j1@rp0-(oqo5s6<`ay+6JC~+LI&>6th2a`2`8Dk3oMw{#j2ZH zh&6BRH=E7E=4;#_=|>^`<|W>|+`(>Lz1_pxJ?t;l+kye7)5tc^nrD%kowLStXltg= zTPyIRHCJfYC@$JnQx|#p>%}JB^g1?HmFgHT6N-{eIZvuDk!?4pLI9wW7Xprd%QpX0 zWt&N|L~LJNc}_n~)8*pg?@Gs(pK+8f{XG5WZL`J|T>G$O-x&MV(NeLw`OU*`o3EPt zKc1nb1bjK7v>m6fT|*;S@qYUFI8YzsDWFYiGsLfiGX214uQh)yhiiA-;&8Y0$5QXt zzUe60>5TZz<&Kgen-u`OZNB}gqhzN8A+G8hhtt__(Il|cSu(`EqUhVEb3_sWi(>dW zrDT!}t;V#Hm7q8YPWC<<<_j@0pdIf$sLK{W{%^b&)g>BjQE;(&-mvYC9ew%DS6^QH zS~nHWQt@R`^Xn_$u*xje_HwnaSiVEtBzWDT799B@Y{J}r>-PhsKtd9EI6fXTizX91 zAW!6uBCRX&0~LM#+La*|@tR^F2DMBE{X*NH_iKn5)@?xczNO_JO31>sSHO!#!hlGsE-I|RWkBvn^X}g7HpOM{^Yqma)%rq2B;SU$)XsNEGqq* zq!gs%!~&z0tbY^651d*JJ@@vUySc7CzP~^PVE|XI=Quq70)puF@DG2yU{0_*`-V_n zAH&QvdmD?2zFp%1IOJ^W-@X6_SvknM!;z{Xbj9)p`RDu&`jbOA_?e}*UtN_DVuc5J#Ir_Hx7nV z0&U{D)A$5#c0gu9{lKi%GQ`t~LhXvepp6w-!}z|Kz@(9}H9^`jd4}X`M;oL}WNjX0ry+pJ!rC=QTLkIQDoC?bI@K;~FMifkw2} z^J$X9Mq@YJS{D}^b8}`i>h8f2I5mWf;WO-a$Ym^(7U$5)=I-wlXIFM~L}*J`oT=2O zS#b)2>_Kr@LkD~Ko%>Ry=h-gOFVK12w>NJHD@N2bkx1GpWUd=r3cAH@FKdQSG-~f@ z>{~P&o>0l2$**wr!)Uk<65PR+B%ojiED!xjINld$Yvs+q4sY%#uo5F^<8u6n%OkF9aeEc2AxI=Ww-1$9Zu)6MY$N4UzKbARVM(z&K@tT;>gmijW$gGP0%7^od{s zsO^LO-Z4G+url7~5Uz!tTlel2CyynM`>4lpen2Q0bJF}3blLB34nbo$p2t-R2n)M$ z9s6`TmHk;pV)BF(W3Sci+XPN*SyxL;hns46+?;&vvN$a?^oq8gVNZI$em7Y4J-Y>c z4F3oUmQ$5@m91wI&HQ_=)U$ES`UOc2(SBRhhhTkr8_aS1~`KpQsGhDE9 z{~f!ry~PK2j$Z@hpAT@dE@r?nE@&i3T(mvBKrez_*@b!R54RBz&B9s9h3T6P`URu=${`)G)xOntP;K;ShPSv_E2BVLREix zXM0)idmx0;sbUO26?CdH9075=uLHsd^d@v@1d8p;UKCfLC=QCKayBN?YYhjk4o42N zEkbJ$QbW~0lV*)l#}>_{cXWMW=cdSzDMtU#cu6y465hjfyzz3lkKft{FWD50E=i6y zg5tWjuMHinl&3UAW$d^Wa!~!?2w7102L!d9gAtMSb&L5r^$GvoM$a|1S91Y>9F1hL zxhuy8s{b58&YlhpzSSTyh>Vb}OgH1CtST^I{Dg(Pd8Am?=SRcg{)GyCJM=z&f2f_N zJ|47x&(OXeGBlwES5x>w5UYh|;bdRlG>Wo_HB6ygJC#$VA}tV0qRtB2T4&7fJ*jQe`E|J_kKgt8TnnsW(GmXDB7gu6XV@18gYd*S3 z-lo~`W6jwVI_oJ`AQ-9Esdu=y0S;bNH$p+~0Vh{Z3k@uOlILBd|yQu?Z9rec34taQ@|r)~5-QkM2;O=xLI z7opO_Kt~Zw!jkaL&f0|2^Jad%^eYN{I) zvmc-P)Qun0a-Y}n?m)umjb?8Lmv`{@0-_JG1DmnxXt~{}bxJd)!e8xLDWYM<% z=S@Na#mndbgLN3IX9*gtE8}GH8g4Drsc!v+$8GM4*!u82?y;!M9lX>o>b2n1Sq>0wOX_SmRULq*d)7f-{GZNathIreF5aU} zGc@Fub%^4PW=;Kl8cwy*cn`cpBwz>AG3^@FAQg-;F^C&nr})62VT;auhqD%)>mckA zYD|5-lD#4=CqG+{nM62usk!NphN==k+u8P~zw=2FgPq~DNbv33_FN;*#)Je!*I<0U zc>QG6*pBQAXIwuepsHWb&V1Mh&e&{JYqh2UyFP!$7R#!wR<&K6u{qT#+rd(>m~|Bv8d;spV&_7n+w*FR6Sf4v zWlR*C1-C~)D7+~kK_|+n3t+4_kU%d`jt8K)8mup;gxd?0}89!i}f*)WEeU599 z{Nz?V-oOJ@i#m;Ar1MaZWSd)u)MUfxRilDTh13KiPshzw$8qBX2}VbV5jey=+1<@U zxvXRfu*SjL4J*(bH)xiIl@t)196y5+kl0q$P)~M8kG>XOaDZ(%Grks>8AlDwmIA?` z6LW~;Tg}qOv*94^cf!zroxtV^0PQUx`>bM3XB~!bk-#*m9qCh(TbP}F$Q7y`E5T)wEcEk1-V?=D#RQ8B#5p1^HM=&;jx~Fi0m)Q}4WP-NlV%%ggaKO&CZBz@JwO zwhxG1av!h*S(u~|cMNN*{fzC4#yfn5 zz`cjOwhW+TvR|IwfK|CHIu8SKJfR-qU^QHV>}8^Za^J+VsO!DqnjBlvKjS=<;mQKA z=^1nge)py__n@Ch0agsay~m7)7i-VVq4IsPHht+8E6zM7bTUU%8@TGLjiY_?3+b|u zufb~y`5GrTFLnSb>}&s^(f=xVt*oXL*=YsiKW7OggX>-D5Z31}VfRRLkpNHlaZp-w zgY`KFj1du`D;Tge5hv^++#t-sb6Co(;S;RDZyscyp#hVHoTnP^I>&X3TikV}pflTQ z^ZO#-WL{62W+B*SNp)#H!&M<6pbfqzry4KMhLSZt^5A8Qe9+RllFUKI<>LV1z+`T| z+Dj@ai=l|6wFpI|9)fes;-$A+wE><0R<5$*3RRAklEk@M4Xp_~#ZH{wMIIsY72nIa zHZ5=&tR$S+-jq-fuy=2~`FG}j_{Qk*T|!vJY)|XPy9VXU|MBeIHkSD_19flpuL=w2 zO-R99gY`;+<$@E3a4z6OE-{ltu!1C0F`KV&>~sqL9asATk$8g0?zwWD(e-#6Jg;dA zOf4s1d5_biI=mj9pvDdNFa$cY_bzo>huh+DpPntL~|iZgicz;2(o?b z-}G7aP7ODiAq~Km(W-AC5?z2_K*DD5%Oz#}GD++E=Ha82p9T-^-bDod;P$PD>yL5% zylihD-dbN@dGzxDm$t1u0$7=m1t*O5bO^`z!iD7W=U6qp11bwxd|I^~2vT$+%lMgN z*;(S7=HX;pX)&R}#7>_Cnl=J+PF$>X_%g6utZuMlU@|BL%9+zgo{6$>K_Du+L{jQ4 zQ_`eTCcT?fa&8`J=3AcBdf&PD@kQ?`;aU!`B=#1QQA@)mp|NE(fRVJMw{a~}Q}FC$ zU;bVBTFkvo=)cGCZ5c%0rT8q^D-h6aE)Q5+w&wXe z|0;wXr(mvCt{Kz3z_%-cK@JG&A6z%7fG2dbPOw^^J)_%1RU)lr7J^##KxOO@7)C$& zDAT(LZj#G9k~=a<5cbLn%W9(lF1ef)y&vThZ`ODOfv zj7)^ImZxWfEqKlIPW}o*g=_EfWh3ktN?2A*4lY^iizZ_^gF%a3oHV zDY4!(fs)CT$uvB0e4hv7r9IV^Uc+LBQ{4_nPnLdr(#*38`9|V80hBhTV75=LOf72z zh<2~0vR$LGoeLDG;$Yb)5PFNvRJG{zsyjaokF| zFd515P>8vdND*}|6wbT&Jyt3VK3>dF3PK0AmW+9qScWpLN9p5^8j~9xh^l7nd7K~A z)T3(Zmt`nSHma(o?~^vQsA|uuYd@nh4O&&rY~eyRJg5%-MuosbRViMk{sdsCECtBv zm5{2rxNP~6>Lz00B($?T<|4$lilvh25Mnn-u$}}>IM^9PGWy(f9&>-ek9uV&M#hlhBGDmW6iWq zlvMO$Q~p`BC!~~9o8?jlJ`xq;cZ`E*%7egDL0#zyXvXi7dh(-vOZ0&c{B3Wm*~6E3 z##h2;i-U||cNKT5pKQSooE8x+L*YmzFmYU?kg$Ho(YlTbacOl3CymS#uzwWS?JBZt z9;UAJvcNVjch_~sldn+aOo<3_Vh>jUUOtEb8ov{Y0uQ!gD8>MDA2yZNH>c6MchG1| zHYoMZ%H3O!@2xj+%amW?I=M*#MDpzb>cPExxSF{esQm3LKv}J(8>phm0Lq=9s{!NN zv?(L;DY+OX+mehKfFGJ{%Z%$hZXa%)93$?Kdv0_+NfP=dxL8$qt2881#d%Q+| zr>&!%LtKPTsa=A&0S-OjzfN|T;U|idzI!i_$VxzfeEx!~v9&6DwCl%PUW;vSaR(8i z{48T!Tus0)06S*>Q&^-Rrvl0hAMT0hx&@8dFbM)E^+Sj_hBdhtZj9Y4!RP}(%wrL4 zSPr&8&tT88g%$%L;|L^b+1sfuNySpA@oXP%qiK$EtF4)diHq6}6@ zrRjG-A%WsE1)|`ldj^ES+;?E96U{U#ch$<2M*mg1+xoVdPULao!FvrT)6%|Z+*H9I zw)fHKtHR9>zHUTa%`F%i5l*A))a?z?3Y#rkq0c2;@{Zur#ow-K7696qn1?HuD!|R3 z>3Hi!&_0v#v;8~}D=7f!TQH5|8fGvXHZWTUa6$cvzF#Ych*GeJ2&sf#%c1fTY zf9^eew2Fny?2e$0{>{HakazxzwNT>2v=bG&yEEL~<~Tx1Ra3?fp^gRCNc?Pb{q-T$ zh}>)xpoMx`vn9Se%b7$BKn(?LTw`-?O^dK!(lTHy2Z_a50*A+P%G+xdxlm=GXNCef zsxw%MD*xp0wJ_DI@Y_EV&4nS%AMZh?Z8@WG|SdI_i=pEChDYmmx<^l!Fuv1DlOssiX@$qvJ zYUD;MDJ}jkj68f7Ja0vbkD0j1lDRrR0-#`SNWHB96-b#I%~Kj*pEg^&8`zf?n;&mC zuZ|ehfCxW%{bt^Xv#f^hlDc~ge29TilV)L_ITzPbBpmilXM6?H{jRK7* zT2pSMS7M(+Kplt#Zr4X_gzMG&Y8LRL*8|0Klf=;)ZEOB+j9zS4E93xemXdF<7c(>x zE?~M%)xmM_ut9S$E)-Ohd|$q2pcVxzs}X3)i%}WKgYqVCgWCdp zc^P}J{p5`p{NETH<_rR{uy^VIE_}ay{)xLBfRG1q{@aDmaf+(CEl#U*Y`~dt z;ybcx?*{NKMr-A1Q9?2La-jP&xDqBb?h-a@1{gF(ZsU|VVcOcK5Z4M980%Ccv!UCB z7Qo)h*+J7i!dbLy-pDkS|I|tiQ)!ho@8fxJdUYr!C#-fKe`hR?%>Ki@ zRA&_rvsT&ktF4_J4=CCH*_GU{By+ z!~)qbWfBlK)4~i~yW3iiHy+S!1ab#BwjTIi^?~KJ0EvQa~Aad$%(AW=z=p)UnDz4K%{d5Xq#Xd#b1m!v&W~j(`3f5V} z-x-U$jFW1$usGB7|G%64xapSQuludHGYmW?Wybkn@k9ZtQ>~aa8Z1@N{!kfsD)i zM0(d2uW?M*6N?@95_@DOpi%P+ZkBimE*!17C1uYL_cAYE?_$2zq(i%wCvyH^-QM~AR}`p`AY<1^-cDlNO0M2Y}x zD;CgoGP*3A26!^Ul%1??Y&>Wo26fUGD}+P`HCD3O}*K zh{F@yHB=nH4Zz|d-yEH69s8y^Pt#EU=CdLEZopVusm1K==vPOyMDuL9>R$N~kO_X# zPQQfw2e{)2=F^)uuFJn7CHA<*fSYVZ$muLgrh*7P62Sl>8m_06m<>j;Pz1Z9gLFOE zZ;Cct_Ec8p9!xt#(IV1YWGhF>-(n2LF?^g(9%eq^mp`Am0S+z7v`jj=o0~#gbG;?L z4E@ZL!ez^ZE8B&w0`m^Mj-X^QZC_auQ+|#z!T#~`@?dh4P^#Snjb0%#8#3L$ByUOO zaU5o!o{X&n9D+r8Sl+oWAoU0o*oox{7>)E4a&PElnLpXNSBAjB5~dSaIS1%mm}p4~ zkeyeKjt-DLueX1odpWRK&mpHfl0)I#Y8!WIqK9ZTWE!{q%eqIGvtJYg)J2?9C_KA8 zaEvZ9;W9uS+6GeMPzPZo_%5Q{cWI3y>}YpG`RGt@duNCh3$721o{S3t2_x`CB|V|( z^cj-tP!Tihq?4-QaD2rCTHVSMI4Wudrd%~|Aqv?KrAAS#xvlhC)S`?!Vn+!DO6Jal zap?HA_3!8i@?a&mPlHc@;CjX;F8umg_s)yx1t#d{KS%j*bwc73ERU zmY$dX7+dOS#(6tt%mf0)3yT}sW1iI9>|~DOqjZ=ia1?78(a6&Uk1-x$jTb@yC68_% zVO@Mw9x=JeQ+dRvpj4}#u$d_}affb_%w%XS1l4qtVK@|z)89`+WX`61$YgXyE+DP| z+%mg|6cR?k1vwg1<_Qii{@Y?kt?gFLsH01UydCBvsA#2Qx0E}Ua<<{VkhEF;1&ji6 zO$LQDjjSpH{Cm-^r>u%Z7R!iy?@ZF>%<{%{{^(;3#jc4B8Mn8k!Lo-mye;v>3_EsR zV@x0O3Mj}u&?9-;f<4d=Lh?0G)mL5x1Q13^T>a>ok*T1-~aG zZ<{|9li%NlBNK8ltTyMdLB*6xhh{D|yhR2K9J0aDt1WKaVjjC@3z1a^d)N&jxn)?A zO!6UxI?^Hpf+un%Y>ja5dA5OUq1hv!`z3@5%t4R%hI0-mouvE8dxRnnL)j>F|s}F;M6bTfY`R=qM)1B|hD?}S7c)E}T$pesLWR%E=Jjh{`n+=eXMg_0=MJFV2ibRQWCl&sV57!%Of)8JO5nDs*SfXQx z*kcC}0H9FB+}t3lF~XUlC zm)4;X=mMkRe?%ZN49kfW8YUc=pj{;DVgumJ!&m z)>*VyvF*?pxW00OBJ;xjB<(XcxmD=GE}ENE!Sz8M@zsli3<2}E9-kZ`9W6guTmb#N z0?^DCtIkH=+bHd+_n6*OjaWz(;dF@sIyxa6r9^z_3_C8YH2$7Vr{+KUeT#AoQ}bgx zZT?i=xX9n>k}N*F-q_n!17)(zX&W$uW!+X7+fJoV<3PH(vcz3hGv~`xU2x&S@V1Yu zrm+%)rEoBSo{C^;?W0g3K4tOFEk>T16D}$)R*Lhq3(}$e5H&vI8(<8+1|F3cnDJ1p zj>xW9=qD#O@qS*tr-B1}7)F zZAT|sjpr&3mfDLA(VPXM3hw8nZ(~}!};#lTCleox3X2zPz97LuH z`**;{8$Bbpu<877#vDQhpUNmCK=?AA%ry6x{KM+QR`-N{@O;lM)Xl|9j+)=T+<=9t)qpZ~ zw%*ZZ-g;$bLVwAFD2N*IWGU|SG5jdzUey2C+wv~ICF{X@xpH~w%l_rB`d2PDm%m-U ze0h24GWx!MRGj|;m;`y%aP@G?xKj&0Rk6}y@TZW4rEiuZ&fp{*QF#OZp1B!k4!00q zP80vO!MtDXU%uL3x&~9^^3^Ywkpl5;^S=&W>^FA~;wsBL@2K$YgxX8XUw*ZG`5V^W zzz*D1yCRh8VHT?S0ZxxxBJ^hE!X+tnh=2SvfUGg7G+-B>vTQP|JOgd0QqY>*1k@hM z>Pa-qlF*Z0A!#M`(vB5f{mz8}iUk-zt!L!j0GHlE5;JdG#2g%$SVqyVs01M`V9VFw z8V=A?h za9Ils7HI^~zY=ADoV}BB07VmCg<<_&uiw=su`!@rP*e-o8 z{k$MhqS<oR4!Dk}laW=qY)+#6sH@Df?J@6bukbWCO57r8yNv*-IJ z){sz3=7i%T9NadWJNvopWGTzxEuj^^u4F9hx^^}JGgZN4__da@%1YOi3<1l2#!F4; zwIct@!)#NTw27DfUb%Wr`oBC~X77ADjBHdecI*q*IhV);%YaF^I0&CyvOeSrYTRi> zs)hv@+zeN9oY{=L1@~8wAs2@tuuptB7WN2)byN7siz#!rd1~rdyf%nV0|u6df#$u4 zJ)mB2LVLC%$Vk%@0s0= ziOSFe1Un*#YV>si4bZS#0FHUuK$3EXu2<=m*)+bTJ*9`)JP)D3hEBtNOhT3b=2@vl z4lzlwTRBKbPZrQkLuZM{Xd$dwX-re518D2S7vf_w_4-n5W37cNAft9k3mN>xU8f6QGhn=gCYFVx zF6`%`{rB2|V1;PhL83IF(h#OKo!R;14aItQWU7K#aJ8SPF>NPFy<0Oz0Ly)A<)&?< zgGH+yUk#X=EN?pQ3-J&g-U%NyOJ9c`^b+9{+rMef7c511JMMhlEFTzW&u8 z)_;gG_16Cw5p~>o-)HZif_a?7vDsO09}rB(zBf1l|K3KyJEzTnxAmvZL4u~31@Cj> zJly9sDrpip>vT)4@Yi;(s0FbplYtzpXuG4umH)hT|KYurY??HIXRYw6ov;|>GfNzg zuLX_-6XE?O?mKNl*xH{q8#O$|ln^c47ah_`>%*{@#?ghx_nw)PeQSO8xp}-V)StFk zrp%AEus8Es`BNt+0aMHiF180f>`h!Mx6Gk9ua=LqO5Da)H8x>^1O(G(A&hq2%f#Er z(%!TM;!S=)~>9M>8At zQ*$33|2U&(RQFsO*mgJiZ!0~X4;t19-2Y?e`wT6im#HpMYdL<2HFqfRPsTjuZ13Qy zBqb;w6i|9Hmzn4kPQbHFQ4MJgsOpakR^@S8!z(ToF0ibE_|Mhsf=0fO-t&9@Bypqs zwv=`zj;F8h!)=u?H$v8jT2t0RgF0&AC*1)`H%hC67rDjS9SAMhKA3t$L{T+i%m}fO zJr31;C0iP*ujSL9F)S>7n_3^kLLSc;7V@XFV4>)YH=$No$Ssax!K!tLyc*t=#S^aS z(1B_{FrC69W}aCWPk3d4=~Bows{3@HkwDdiXoZTg`b>3f7Ee8eKBz6}UsMrgov z(6W~;<%~DSEij$L;BW((s-W@8V6qHb?9$iJ7?jSF*fHI$7W^L#p+s!qjx3nAxaxhK z8xq|`2&xEHaCT!SKBqe@)G{g6vd%V$baQf^g{J`2ayhBVU{n)$3bPe(O4$QP&CB=ZsN!{e%3P{etxBjpStWg19(W#(B1aIaAdcT<4CIN z2!M<5U?QQjU1f3p39eCY;E^Ai!%|U0msBk#Xr6K~kNbud^T<7m=8~$F2_jq#K-v8` zcXmK4IW8D90qUTaWRIC-hvl&YXd&i68b0_8i;E$o#ZSgIgHaSH7Rgv*5V_hq*e#|J z=B?W~=!G~dW+Tv90GEt5g(WjgM8<^z-Y!=2x8c#wv)8;+7ONJ{ZfW6JGK@T3cXmdH zyBn_+hG3?Z2oj3R#{)J}odv(<+8v?}+0jQMncKosj3OW@#xPDf_Hlv~dfUysN^}Hj zCVknMjK_A6m9$NP45UnlUW)0;$IN=!X4eKn6v#S0u2LRN8BIE)tScXTi~t@h zIBh9yZuW*);w_iiPlmAr5pr9JMG7jw{;B|?NQa3Cv1SfR{cEPa*eF~#wi$SKfaElb z;~~|-B+EE}2FWZf!zRP&17HJ>>>*}&I(S%{ZSZ0&(}8pZS$_uKj9uEk((biD3Z%_f zLq-4O#0DP|J9g?ZBeZr#(}p&1luW4UB&CYf7!Q=bU!;(k7A?(kw3$Mih(KvhWJjcQ zcH*`bj%(`8#W@H7YtvQ(S&7(*=iS7yM)3dCOFlCpyBN6B>JBrBrr*A$&(9pPoX(Fa zHF~Z3e4uEXhWgftacO|p*)L8lPEDe44_nkl4~axl2}M)kFXUvOQl{xSb)j2i85SzT z&sZa7UMrn1BI`G(3uYtNf*0zxX-YJ$ddwBcad;uT2Ph8`B&-!?m@-d^txY@U^{a)(;MaXw*19IJDYtQ=(V4=_NlD?5N+$upw}D z&oz@aMWIX&e9N$|zH{ps;jKd+zx&;yy}6 zMwi6pOyWwf-{_<^aW`;)#N75ben%7-l4xPE7YvX^%w-FF#LkPsE08`EIhB}RkPl2Z zX1_?%_AB5Y*`tV>KOyWD%(G0QVxtUp*(I5=M4z37fOZRP#kXT9>HLxuy}C8{kj#`J zfwg8zkC12BLo=L^jZc_JHU!9z0fk}Z7upg&+z~PB+Y8eVw3=){!m#P!w z1aBdZ3JuQb1OCuHq(QbdNtZ=RGX;A*#Z18>MX>!k_yQ>oSL}f3VPEB4cF0(TouBp# zG6>dK(0zO^1C)|&5IPxbrY7Ger%=<9@gOT`fvFu*zkSZM#3X=R{Mq<5ugRqgjc$PL zI6{VE854xe=WZ~whFe7EO1o$Q*J80S{9{_40(dz-;mJyX@WYecZCV8!1wIylohs{kVz6iqkpAattCteA}W5IMn zV)|5u)l3Sr`@_cv7xO4@n(Q3XzCI}&wc`#MlMrRmi|Y!&7TG{YS6l=TUsJC?AzrGeLi z=yXcMP8Z_D*f|?%D75k!HKTkA^Ka?4Gl|5}|Vipj`9wzDrjsG2Ml0$==P&}R9&{lxF>e?|E+ z7Fkn7qbtVFu4rl1AngH9;+Ou^^#@j3U;G_m%0;gq3*s*Y1kBjBG2rQK^A~27^M7x{ z8aw=BV=wHn@lk&vhsSdnVEdJS#Bh$yYWcQVQxnZY=E?19_|ixP`iCfR2_>$KHykL4 zznqxzcl)V5ajo*2JW<9OMS33NLw3lLV@SjE#+7CAtK@aPr#OO|I@jgLFLMRlf+8&oS8SNlWFUd~eEZ-Ct}VxztZ-kGT?L0Lw~@s`Sv*lLOI}YA z!1xrYMtJWW+}eJ5*uQ;mmBMO_EK8Irp(@73uRsFDrAp`u;a>&%Hxqe7;ANHmP4O88 z;!5iDw^}Hv3_#MyIQ3#pzF>@`fd#QG@Yx+3Y%-*ze+2qw`8iKv7XB-kYazO0$Zybb zK9I9Pi4zFq3Pd+tWubUhxqrGKU7(<}TOsKkWHqipDsd))YFo*hIauk(l@5~YsaDmp zq)b{_Da8UDKa3HjvV=-Oq7aw7ab15>E-JbZz?Z~Wlkri^VlvjYhJsc|G&ipEzuj#x zGZ=tOli+coYG*dcV+LCRGXVrBGT8I&nRXdU-0`Ng^W+INg~JrismGgl<7e4Bc~u5 zD=U+HUhLp%H~OFA?=${_cm6tMHBgeYH&}mWbI%}zmdCz zbF9BI^}oaGaZ+p2{o^1)$eG~G7F!(4T|FHu_DfoLip5ZIbpka$IDe!tkif2en-1 zC$1eQ_H{oCbAQXp75~kuJ2s_%v+DnWtXgZJV%5eQaKE3W>v~Vd%yy?RW_~^+W1f*K zk8{eJqhA^4=vS0!H_O#jXb9k7^EFte?yKxzz-qSQn@@VSg-H57g~PM`%;C}Z3|u=H z;aQlrinBS}pZ&2rZ!yGB7tbj{;O_a>AEGcF|1f6J@5I4cX6 zrS2g4_uukrwg`8|OtkFg5E;ThuVRA}O!x0Es@h7N!V|5)%v@2c?LC+xsidejksr>) zk__hA7?S&j&#a(tZx*849pt3m+*Oe~(nfVoEMLrFV8W6rD z)BK-n5SM=(3h(J|N(D6NeiptO$}D9xAj(xqpI)2B#)vHtR8|EXz1yrlb55&l%cfC+ zjG0W_Z8bbt!XUE5KUEuGKB^&M0D`+*RP89WCK|o1OQi^tDA$h5Y3|p_;nd#&HL(HM zXCB?XfA@wc(SP{g!c_Mj_MKkSv7Y8XoV=4!TGqD)XI7@XHvCtv4w#^ReH83dHkl?fDXtexo0pbn@d@RLCorKZ ze+z)3QkB3IC0Qdp)>cW*BmsqI8;#L3at!Y>sCVJ=KBKDxISft92n|!WDgPhYrPsLRxu8vza}6_gnj`v?HOcOcV>ezx@6N9W zlT)k(m*AqaXWBE&F0~B8hD&z3X`iQs@s}oR0MKV}fY>s?OCv9fXuDE2Fh;~q7Uj$A zP|3f{-%Bb*Mgxg4@WK}FZ&76w*`MTt+ZvDxcws`88cMCT3ZsA*Ewo3d!j4--ivnK7 z6?xu4M-?kjm8L?F6?#j9Dtd(^eDqbw1GJ)EFWXdEv7;jvFoz?rVZwsC>8@b~ytFHi zyg1s=j=l|f)I2N!Na&hyxdgxqiSrak6@*ZHQH|{}9Gqe>-Qz(4AB@F) zh|(RC=bk)nC4jUnbsc~>kjElGbPnp$mjZ?`WQ;a_nS-U)mjZ5L z0CVsWALalcwKccV>C4=vrZ01w5nl`yAz;q_K60Q${yk#h!T#y!0EzwRUtqM?mL4^D zqk5n;*R$tVz_6<}9^dbdW)phkqLtC%ONPe)f_`C+!(Po`WNzbAtJO9WOBWDXVH_dk z%;8r+0DxRq3UMHU_+Y8ToYTQrbJUv}bzf{p?+^k0(%A6OVlxz`)vNZ?xA;zrTk8X(BcqF1q6z4D2$a0Bo zS|`a$GINCrL;|Zf+6p_2BD1xGZak&0b&Dn8FnX_fVqO-vMUB?Nk&$ySa}0f5(Q=ZO zRxkNpA1Y*KB1ubSH+?L^!e*TVB>)(W_V6R(v@86i%XgP3B-7#=bf1t!HMTzV!{P_C z=e(dur&IWZ>_H3*$C8Z(J~du{e|&tPcLq(` z9YdfPq?AKop8zDKUMR^?I&kSePSOEgGCnL~SV%(@t=Qcl6DxIK5{&c8WLx)S2g`ZK zHn2$<)s+`6-!3jf*d&+)yGyxDr$YE4!3P$hr>hXjQX?}9GXyF8>wr0Th6u>3&dwsB zUf8Aqb{P|%TSfViD2M-_#f87o-4;#AEn|J zN6$TyBJojV0W)NgDo3$wQ;JWP^u}8$Tz89~$!WKUjFGCp$x#GwZtY(Rf>AV5{OoGa zLpspk`N8P~L3%ATNvl1C{h01epf+Q!dKru{p83U~@>D>2-9w~Ch_@^^rb|Y`;HRad1)Xm#lX$dTfA*Zu<4u5H$gy-WU zs^_!KwCyJgQwjJeCfB}cf0OO`A^HX#@Y{(N8gz6DF&n`cPst#nlA4B%V#qFnk=z2k zLPkBkdfOzY>6SBgvB+J>hq$Eey{a3W?ss`}C19$&xWc##>WlMC@woUVMzF*j9gQ05 z;Ck_2alnh8#aWMnxOL(1fkRx3K&{|lYZMo3(IL1GedMl};EyO+%%J#LPe$V`?ErBP zyu-(npL)`Vfh48-ykTED9X~^bF{ISQ-bUW+SUWNaS#i-4BchO53*t#~c)8$Com2O& zKhn+3+1dUVhag2J2}Bbtk?#vb3P^Rk%9VYgXz@5-+Vf+T9kGxJ2zExXAn0+Gd!^1S z4Wczu0;`;lB3{mWNRxa>Pg!<2Bb0uVW#g zti-8cS;3--!8l-e3qhc|tz?pgH({F^vLzeU!R;1QtJ_F6gb*L?Y{h7n;~wwP?i)d* z-%Zgmqm5#6xO=`#n;*6EiYy*k(r`q@Hcp&DMG@Z`X$@j=lCY$ehOT>848<;@ZNqbN zzG3PRqb1#<$6*cGJc}@PkV@7qRig5UomVSf9zy5mibJ@vQJn3@A=>$eIEIV($RMfd z7%pNYB-w~w6SVZEyZwg6P5E)ZSok*ANxXHwg`W3fd52$`xRF{Kdw zmE2T`uBo7!ox_$l9PJ}DN*&=c+Lo&T5H(CrFn^7A>!L!G&E=5z8d|TQZda>6PG-|n zDC?bhzJebiLVaTc-~F1-2MiZXeRW7s0R#U2&y%y~EC*9yq0qp77lBtfGQ=h9Stjb& zV05-c=v$U5&;)C+g7|gOWWI@@qKp;jcXqb*K3*u|#o%^hmx|?mF^E~*!+lt{ly+Y|=6R z9a4|j0W6*&m{@sV9!%~WR8HH(Xwtx!X)6w=Biy!wy%&RH6E@U57&_Uma@|xLgFK_` zQr(v5GTs@catKuoqVE}en)c8Ap2@-a8B%xpz+J4dO;<3^z*w|+Z8P>ldJ!np8ZZCtoBU(CxvE>o=|sH*XBDZ#LI|w{`tG{x?XyCj?ca-cN5>%G*>fg%s9E6+|ia zPkUpzkhpiL${cODdX1HbUhnD|_9%7}1AR6mx?H$;ZUDZJ5^P^NFK9>r4Sh(&HyUQtEf-b$g4G(fx+Zr zrpmTT>EtmP{T`5+LcLxt3ZP4fo z42fJy*r*`8NXV3PN1=d+xrZr3VRivRAh!rDGCq~2^cV@kpH8vIx&1y;m2tEUOlcz= zDU&hTW?)Ak0RWA^tr%%gJ&6H{iWt;`=ErdNp;}SoOq{_%2Q#r4{gun5VpRjC_*yO#{6xGxHn6e zHWV8Rl~z6;G^|s&gk4=SW)P)&=1I@9W%DJGpnPSSQrXsqe=%X#L~0ZtL0fkGjM5Mr zobTy^f!dAMUTyA-4@QhJPtZi7QER{TdF`YtOr-2VlRaT2GRhMjIavMVhx6Q#^FTUv|2%LgoZ&|=CMNdUB>2Gk5564g;3BG0+;fXK{ z6{sE1opr9@P=T5EvH~J;rPg4JD@|>s4v93VaIqk#WNb5g?A@$ietBX8laauAVyS8d ztjc@O;=#|hVYvq>Z8ONV9(ePUkF+^86WuEF`%m%)vS2-494Yv{+Fb_iV(N3n!8=25 z5OAT<-}vPBOGkg>Q=4Ij3}8#T2*bF?c=mH4-DFJoJuEa>1u-mmXS6%Z?j-)a%7II< z2y%-aqM=H{cVv=e^#1X**j-{VrgJaV04{JuTF!h6%P)Qe4q)O@vIvGgLqSh$C~QYa znlDO(3E9yGnE2_AVJK!M7AFv8V(&s8S|9B(lr`Eb2A^x;Ufw`}K<{*vG1#EJb8tF_ z&5DT|?MoUhE?f=n=)i*S+iC_5ys$QKmca@Iw>LBYU+^|-F%%thVSg-YSQ*0$_;pt! zx)#VLz69R`&92skIHIR1v@x$A`KmJYv1Y+4bRb=z!yYAjiGazZi!}x?@-LhQ{?GaN z^i@8=eeBc&u!-bdz(DmdN|N%GwVI=yZ}Ea`lTqJ)U@j^ABbVg5>EoZ?r5`01y!4^G zcSl(E13_FBIGZKmw3l2g^-Mi{S;3AK-{>ubRM>rtIRWB=@#KVu6yyjIfy1M_>|TwI z&T$R&v}~5$>^?h+px!Fw%wAb+{L|j}^dw3lqaO_?j;5jU`HTP8ZkeI)Der_iVh)NG{Hy{AK1zkT|x- zuh;I~S=-v&ShE&rY+Bn|`{VfV5H`K(>EZr+YyOSkjZe?{X{b-}g%F4@u;P3?y#C4X z#`WgDGSU@Qycs_xo1g$mjdw{A8>7BWb z;C*j2nofW0?zY-XMBi14`>|5mK8~}C!R}nM4VKOTn<+xmY<}F___+D-qXtR5H$T<6 zYWHt8$yGXpI%gY($JBrpyUBy-0vyd*6aE;ffisrI!o%;+#b=;C}%ScOacP0QK!Nm00Uu`oLfRkg&Z&4 ziA*z~%?$m0c9F{vhE|VoPaaq4&z{eL)R*uQcs>DqpCY&xJPJ%-La2Z(GWNtXG#DiB zPhUc_NZSHLMp&7Sp=&|Q>Te!6HoF$l@Y%b(lnE;JjBzH_+uXg(>g$4QmObW`uL1#R z0c@gVZnB(}7HVjI8rz%Ku@u@F6T1qRJps?=r=NaGN#puQ8Zle*ULckD@#g7$zj+L$ z+lBu9(7>B-v$@7UYCZMvo9M&z=!jtgSMkP-H2dLtSxyf(Z4V>66c|5oeOKY=er|oiKP- z)9gT2=laB7|M7+00xsHRp#}f$(C4#(!?^uTgFrvHOpJf`#|QYUZd0q+f(A0h^-m#O zKJSKDjnwvopTVYA8Bf}vn5%Uc&2%HBz# z4n93V66^xU-ldtJkGB~%0q`8AohFwz2v+PCVZb=>giytomu$KCTV3klNf1l!p7X)5 zlUsKYsr+mNO6|#pQLy?%8T#N?-=QctqI=@etJ!}a!n2|%>V!b0Eh3V5a`-+YsvJzW zE7?Fcn!EqG^KkdkpYAHh4V;;P{B6x8303hyP1m+t|l zS77bj;t;pyJe1!IS1ymw4iNui@IEr;!u1d2J@$?$7w*bMUtZdPJ;J3XOTKEUB_s!1b53bC`N1b_u(Y)CRJIau!?Y&~J$~YNZ zJ;owV)D8d6-0M|y1=q@%opLt3MduKPW{?_PW~B9sYbk7N1dN{6$|}~#;p7Mx60ia~ zoo_;miF&yp2z{iBj>D2`)uT8< z*d(|F8QZf9vhre5EE0RSKJAL zk|2%1#)U2t^3APujB{?HI^M;M)E+~^a)@DEoEr|fN*p+q#dwHPR6KWBEf*R}<87@N zwGZq^^+l7gcA3h=^(sKGkas>g!tU`|x35TE*8Ci;Pu9u;1(C59>_u6mAT(CQUX(>_ z=r)c33wu|VqMA}=WF8o{Mv{n@b;8H8a>90)i zVyBZ{2l|S+L(RoSOCLkJq4y{}(;+V7*i-be5YJp=6iPmmM`ydIU^^}&%ExpX_j`b2zh%@Ec64@eh=yc;PT4iBBgsS7R(BkvP zOHHevGnI}#%Lk3GsTjN&x*NWe&H<2xAaux0*!~!#ZJvye6 zPQ9`FrCUiP)paXD28Y?T4GD!Cl{iuRuV8%q_j=8}K-dNxIaCjB zCJ*ok;dHHRVQq_?gav)`?4=1ZNcK=St)L#9isMQx08h~4JE9xu}`<)YR+ zMc{?vHm=X^GUFHXkf(Eu*jV7~n0rBNDE#Ra>Jq9p!6}&Vp6`^wLQ z3;L+)xa9eU>+1y_RTJLvfz}QF^Thmgi!HaG%;vlFPbIM{9YhJ?>gR(-Anv~l822|N zkozmgP8{V21?m$vV-XeGLF#sf6hRQcX{WpD++LOJb+kg{;HbCrsHiIz>PEG0wSc!u zDk%JFG^3boML#xdf*Y+9oSGoGZ9Kq#W*ZwDoAN-*-#|?^L{j((AMu<%X7su7HLiJ% z=Bo$#+<55D^z5SUp~9aVYu}81oIFGP7P#zx&G=mRfK@@xidw1ri_tJ{Z~w}+)@A__ zi*^>^^(gX20VCC`{!@^#D6!Uw6Df{;Zk3n*DG5_@3{6@)4msrI6zWl?1DaJ4fR z^fc=;UuBOSGU=JAvm=1x58gjp8Jxvas=kQp$W_xBrW;o-3f;9amaxVcW0<>|cbpOT zH>VcqV)wevb4J`9lf=Ucl3@xL8J&sUrD1$@g1}3-Yv*X9j-z3X%VjcLT)jgo3^e9-SOrGW zy}7-L5l@&LKazcbYc;$jYR*n=ERkY~HCiQ&x7hPK%Vb>^;LFMV$Z_T9>IV{*ayrNMU=Y$Nwo=?HW~iOAFh z0dz!Lik7?00X!n9?&aox6=cWHfh!?aiRm3m4hK|;<{}qn37=O$J+Npvip)8DIYGz@ zM682vCwQr)3Jmk~RMil%g|iq-Ge^2)*y`=^Pa~*$lTsk-pjh-nFTB6iynOlcs+YYA z$G&U+`x@GhE)cu${EWf87$AX-CRt7We)sTx9fnkIUF~4<8m}%nV;5POTiq`CJUf57 zKRK-j)$|Xyrd^9>2PF{6q69 zT25;V=|d%;v1n5I>DEM3Q_MtYT_e1GbC6aTP&5d?E?w0Dx9b%QYg}T=r4>qpTAq!(3e8Y;^4qnYhu?kkMUkJk zHT=~|vkRLq$z^Nvbcc#EshFq*yGL$o`PQjax{j4MP480{;x%^#YHf}RtpUi)YQXLF zI}u;pzxVw;2qPne0-b&Te|Yg3%U?9QL9aUaRyr|qo*dcs&<3eRenC4ldO&_JpuuQl zcncm?ro$F&mOca44d|))ie8385xum~M#mm=NH}@!jb)Dt25qa2Tc02N?)mWq7j0^I zx0xz`H!Po_W!Kw0&0-#{17gQm;!H&K^tK*HrB?`M;U|gy1Sy)|dPl+ShL)Y4Q$GL_ z#hyZ}U7ZjVbOPPxdV2czEry4NX)d1=i3= zwV)gei2FG%aEHr}cVasRRA4|-_Zeyg=nObKiM-dzdg0MTe#*=7WFHi_Hx16DWymvxYToIa;fubDkDON0}+OV-duMbgm1xC70t9mO}NPolego_M-{- zsu>RM?Kx3?B6k-0#AO3&_n4W_#=t#f%vwEdUg3aBY+&*NrCP|u zFg;EX=q7x_E{n_9NYVs05vT~P0@(v1n8Gf(bBgew7}rd`2q+Vbwv|>z%h{(3lfrNk zrc<}lAbZz{80ZSN(ZK-|C}?>2crbZ(Zi<5DvfnSeLjOKq4=BvH_YnB-{P>t&g^Im9 zgUOe+bJM3AQ@uf7M+mEwh2eU5aCnZp@|1vGPJ*zGG}W-pYOHclblDbDvO9k&X)%H5 zmVmSP6zK(y#R)f4v~~J&GAnW;?lAh{4EKOcNIOTm^P`;QTp10qa*)smXzG~vt}w9Y z)9DL~kk2K>(rcl{KaKa!$&zN<;*%#&^eGgWxDB++%D{-42ypq2(--3{t)+$lSP4It z%U52jGSyYJTp6ld=NbI&3K~7RaUx*5aY9%iI;GU7Sr|@obqAaD*Gby6XTV}vrjM$r zNu!Wn9QXmhekL&EuTNaRJIoibN}TJq+3W`u*=lZc6I|!<0ay=3nE~i}tTrwX@+SC` z*KMGD0VE<4ezujM>H}WUw>`5BCNOESdBM*DfC_|})skjIXdeIwxw$?&Y*y*0 zT}^_E+N;iKbq`fcw^D}(K8dfLM>Z>ZVy7;m=@~TC@NhKntj+T*4R2{i9V&m*dVrF3 zo8HLB+vY&{o6TVF1;QUttz&euzNjIMXYb7)-(>LwPVwiPHdN+tLqs_T8tPo+CJv!* zIQYg3?ABln(jy^f7g|FIQ&({(Yx!QWQhPyA^E2N6$yP<@d0c1fiX|a>6F%z?fyKMN zWih1w+RZYG^KbFDttAGztk)h#4qFO6kQc-UGTO{}_K| z%D6-gNGftCPH`%e)(ovb9y}e*;2>~1_+eu~ovkh2$=kj2?am{=^>-Nac*h;;dDa(pn2 z1w;($@#yemgnPwkHoofK+(UeLfDgWqya8|rp#$Nvc{qK_cnQ!m6ZAmPo+FElE9OB+ zfv||sj(F9a1vm*iXt?abx4V1`XvJkA3s+4~cY4kPx^ReNL|{m+se^09X}eU1gQv_A ztrx?e%&>jvAvoSk-797?cl1YmP`k3vFMekY*3&o=<(u2HSo<_0+e^%rYwi+ktBvkW zW=rt}qOYBUOQ%P8ht`TOnvR-`kNI#E;A?$XsA!fFyzc~IqLRJ~*OX}62ye+V-mxIC z&NKoXkf9Vh8pNOkGl$cUn|p^D+jmjqn=Cq<)DasX4uBpdq6yZ=4uCR0@h&Rp<&Q8H zK{rSv#u3;jIUTdca40z`In?FuL8JKzp)c^?6d{5qAbO*|j*J#~H|ua8sh41EnF`ba z_O!g%gHH}jTHX;a5O^gPpx{PpHsSX1>?MvF7zcLB!BR!%scv%jio7o7nnvlmY z<13;m<1b>K*ucRB0{8d-@O~Y7giUF$a(M z0YudlX;zE5PEP)84?ntc&oS#mV+v1rWsqdJuLo(9(c9kEh*K{`PpfLY*!<33GxX z3UiUQ;^M!1geiR<;v!M4m$3E@p8{>?zFoby1p+ZX!`*IP3s6+m=j7LahVF&j>V)1)S}bZ%sRu_-ff9aLbcf5 z%gwJqHcGV%b(>}_6;~~+yH44J{QNvsATjV9*pNlZHFA&w~w%HSJ6Qwq-nIDQ}D%%PPOoie{aEZl^{Y+ZUuJe#XU%phqnGBe##lx&uQ#gRpkChm?4OH~;tY0TXF+Mq*Q~$p5-V-FIoaUTfK;7-C28vi zIH$yZx%7K%F*to$uz(Bt>u1WqVdA>}6mgqhQrFDYfYlkg>6o6h?t7zSE;B?GXuNS* zeP)~+O%yPi4WI#{cbaESMB>DygV7Noc#7G=M%oov5_nT%>l|+w`Ga7AZiU?K0#ix# z#JU;OK@<8E(h3>NBlrh3MHmm|;y2zC^Fz)eF9`;riWFEX!+6oYnHGor(1 zFJTp9_e#!<5Lckn_?$3PvH)tJ*aZExv!|mUn8x4h?mWP&RXjLTY#!rrTe@(-64i#~ ztI$7LYoTv!A+@ps8iqmy9Xg!V9b_IIOaJebXwhM@z~DGASxncO1UQ0A0U|7WfJ3r& zF$!UeB8?A!?mmU5&p+G6PB~Qo;3^(4Pv}`AT3bpd za2disj6|?ng*Geo#tIOIj91!aKN$l?tJtw(xOPgcF_7WZQh-~?JrT0vi;?t_HXU{l zj`pUO%LJ89BABcOu?zeN5dgMGm{>3(Uq_522365zq7t(^J%?&(S6#!wf!muHDzqM1 zWW_I81Mn)+qUAMkfiS_2`aFA%KdOemX)uZCFp%n=Y_sc5^sk_tb1TDJ+*OUm#yERE zeOZmsAONQgWAtU?xDr}P-wTA17sYVXd&F@XSvb!iX4V8D`(H`K<+1Z|=XS$5Usa1@ zIIHajXh<(&1PNmRR3G4~7s&#}Fd1u!-4&UhuuB1gZefadv-9npZ$S?&@-=A)w-b_y z6851fxSJ|bAyv`T6$BqgmlG&FthMm@=3U)CKWM%%gKBes0>SPcs-GSJ?RhjcmB3x@{L z7{j9jHi9){{5=eK@c8}N4@%)IdBzU(J`1&Q5m!iTk3JO(fGzkE*2S%6O)W?+U2AR* zuC_-3+c4KWhH-UpYaoE*4&?*ZI+>WY#o!ajh4qd6nGh*;M*_TyXhM=aDfY^E&*&Dg zLEpAG3>Bu<67;Bt(q!@7>-*u4ma~dQ>%=Y$q2XFU(zCd87M6slIoyB00-+A6LYFPb zGmRR{Y*6N+hf6!74PkRdc;awF%#kepx!<%vTHwPs!VArp!nasL+~AEa#9m1Qkh*Z* zHG3L_I6LRX#f9*OunztU10c!3W|fj>2yFKmrZqa}{7^1xlF4?g$(C_a%th1Rfrirq zMb@`9cU1nM^3vp{x%U$W0e7c;YTK%D0h9ua-U}Aa3or?{(+nK^Z>ewCBd2UxHk~P; zkBZ1M{FITmmfsnngqNey?xl#a5luQ1CEDxXM5qAJ<)$lk08Qqcfm{SGZ2K4vz0YkX z`}{#Lu+@{W7Si2pGi<&QWWoHd5qugUxt~Q8m&M39G zmITL&0nQC0fszc5VCG5nAP)gq!ps17Hjn_bFZjW+z+1ixzttXOMGq85I zN0Dv?S#j#g9b3@ze-O-f0get z^MzjGBmrD}19-byE$Ah_&K0GTpZ8Q^;JL?H1~oSHux#C+pRQ$yg#lL=>_|wmlG@Xiq%S&irZSo-LP=V0~ zqtFKtR!H|4jOTE4~RA$7)B=mW-y|lyzFRhDCDc) zGS*yKV_%CW=iExy++w$NF{W6(L8_CQUkC1&&la;9WzgdK4(yo78Qa8P9*h~m{n9`~ zH@R6q?X3Z=y|&-^a45hu#mbOM?s?C%?|0~0K>?u}i*cZMi5-eM-<=_y`}e8b5f>CC z3O`zCd@#xYJGTzw7^9In^L0x;Va4GsKmBMyI3;nae6MBWd#r&W(@x8b;~GLW(>w8E zjirVy_o68DnoFv)!yQPoi|kUGqK^g=63alS6{bHqJXa8Q?l`<+5>!WN>jcY+I_27b zX_*3B!BIAJp@AnJ&H35xz2i=wG7iQuZz-QaHHH|nq#9qXHQWL;{wg7PX68mSHwsy2e*U+cpE02Szfmb|`|-U* zHY^7DPUy5fVm8;zHG}gnta)n?4%=l4=g8)Mf}BOp>{!A<=rzmBegbSm}O zN7gJ%kLEgQ6?+@R_0Hz#l?Ob4;|yGGPNQ(*ywDh64wtaKocT8U#3SaC_4}QY9<0>0 zZEn%~;Pn~?um*D@2C?=ta?@3b?6K_pmquk>tvIebcH5-bu$blC8XL;YC~%!$vP8(jcIm&IJZt`PGDehH5&MgJ;4j={UF5(iw0|uZU1&Qqp%7I(}r^kYL|RRLTk@Q zhi8{JU1b4$7c@h*|CE$YRa+wjcC2&_IQ?%2XRwc0wBPcwl_M!C8TLzu^_Go}b!}e# zmFWr!zX}{5`h27c@b)A9FfLN*cvgXIb_mCx31UnA)h-UfP>aGvsJY5x7ux8DfP`$4=$2cJWfBLBCg=}f#VImSwWLQlCcD#9D1R{N)U-*G^L4p4OW+(` z>MXrSSd{yFit5ARWriVG*BFvEo`_hc1xj@iEn6+c#kxf!Z`D&;AY^4Q^8G!_xuW z?PXw0dN_QBHNc?-j)#wfA7VNKS7(c)6Q+jB-{8J7F8Y~Z6NpfN9vBb+Ci_G`M0HDN z77`&^tlA--mmAlsA(_?78<`~^02>vNhF=!J!0eLRWG{kuSk=0 z>Cv%2fz5C9%Hn%iV$K=j3vpqz$UN7vY9O|%)PsIxzUW3h`BQ~<_)rFZu5I+m6whMC znAJrKV=c&F07R@MO!snp%HR`$yFAK{@Th2S-$L0jPVm~`li)y^G!h4wf!9w!;u#iC+|x_$9?!R#5Jst0X$Hi z*>A0h8+{;qVz2E=z;?5?asTc&U+w(yvg)YZmFD)N=1GQ#CootB-RQFW+a6Z7$~?x| z`0!wB3xSki(|SQWVCD>Q?N+{Ww z>tb!CM}$i{dW!L6*gIJn z2L*28yVqKrG?wsk$eWieeXU)8^xfB&=Xbtq>)lqp9uTv@5%Gzmm?s;A9}!0W3~+q1 zVLt_BPZUxmkBSqyMEke`;y&?S*b1vZagWB_R&)Q}pYAFHa|s{#ZOR#KWl~aYH)dR3 zywpBqu4}BUP5LUhHnWn4`z5Xe-Tvl|m=99__vxmQdUFv3Q0v~C6nLyY2asJlt@UES z?-($G!*U;A?-;x%uXP8)cXMmOn5|&q)ovAMSuO&MyFyIFkA4abdckbfG1M()i9B07 zt-Y=<`Bj84Q?L{~PKO*ubGo2Z@iG42khr?myp*_P1Q{)nxNLE=mIz{&t>c+XiX_xY zWn^70P#Fc^@i}Bvn#IO_WYqfYrK32CWD@@V!dH^_($zX+crkJeFpFQL7ll5#2*z2L zCq5C{Dqjx*X6oW&SI<%L?o1^JqMI15Qvbk zZOQ!T@+1SxCQVHqMS_f8S+KfOmRgt>Q*9X4@Lf_3s{pTKwC*3cUi9to&!3hl8~Zrx zIVO2d=NcSsIzda7uH9UxHSEX5w}G6ffgxV_Ny$+3o`-yy-%moD@gV_B^PAukv4t=9 zBC887pe9I@?gb9t&ai0Gngby>MXxE?QP^yJ_%)*qm;gKKhGt%S+p{YPA3-FbasYR} zsN8Lyj`m)_x&yTV9C*R@PAp?4s!t9sH(*_!PxtfvLNWnhKcoMG(?Dlv8r5{{Gs6%? zu`?Q~7|G(Oq27mAKV_Is1TYfiRk>~W5x>BdyBX4;fa_)}v;XEj9hfm#Lazq ze{ukPRh7))8;aJg_l!R{wBxg_t!i4rB-w5!oRHn>15yD}nG5e$*uM2WEb>Je1K}pb z-!&<0;I=&7Q1#B=dRnNajfPCiSS(+^{qiAh8o))^b-ov}VP;LLYh|;2Cx2?|RSR

vs)dR(LLDtusS-JrdQ>XxHGpL)VeOoH(ehODm0m;P3V##xIdQFL zeer2-S4tuot&l(zD%1?5rs?Kq@quZp$(LoDe^y~PvNU?8@ZyAS6liOs!dPATU^O## z8U$|R3tahoHa*4Zv>dI<__~?O1)tVWnZPwZ?ozLVbgrpc zs3=|_C6NVR-&n(~@fS@V32L$cJ4!V)5TmFYU&=_~qw&F{f}N|~&y)m@-MI_J+AiQq zqKRIz9tG;$umxWd1y*Pw7LA)&a2C-*FKf~&FwdJrfkk7`BEJ(=H^`I?0VkO3uhA^x z@$?$>DQk~Q5w}ZaTkKS&x6Lg)_7t#6ZHY2*N2~0mT_zL0$kRebY%Ysa*#u~|jU}Ze zs;d^)hk{8UAx^nzT*n(PhPR5Dq33o?qV94UcVhOVjD!iuyWs)S1A*zzK$B!_%g%Hv}MVVUmn z5fGVb(PA8WEyHzei*FUD2KVTir;};3_BG;g(U>u6{)~{22$+SaSNjOja>&dKSJ$G6 zq-_tYL^&$l%biRIF*JgPA>?HPA=dSQL_dp%gHloOH;s*C>1^HjF+X7hoOwB(O+nAz z?aWOzzjRz~4`|Ilt#c^&%XQ`oCp93pbN6d{NGV1P)bXJQ3@w_!|1(^XSdP>H84i#k zj^U=)2?>$VUWvuvN0Zf67Nzs-ITARKZ`4L2+nfcbCQ%e&gp$%DPw|nYDYYMLJT9Y* z_g?HemO=tosNbLd1!I8AfEyi@i881YW>psg@6*!%R~!bZU{ z5;SVJHlmc4Ya3tH|K7aov2ZE)4;l(ziRkbRZC?m0Jek4h)b%fo1=@(zO0kTp^9GlN z79n47!pXLhTWM_oM)!J6G4>#0D$>Q;79%14oQ9QJ$@`Fh#U9MRi7)<_dlbV-xOW*u z{k?GSvT^-F-1{AYlsNTW;9ibZxObVABpWft@W!4Gd0}s7-*a?^z|yUuWRWDQ5!)jb z5TpO^n-*{+1hrTz!I3771gHX^8$=D694l@!GZ`Wf&q5LlF* z(hb>um@7{rf&bJ-haMee*S)L*cO9PKsu?b8(j^LXmZ^+!I|i_e zA9!U&i(8@nCSzZzrSRd?BRYm=B2lm;0|3p^iM{uX2YC4hR=01+0g>%BXgR9a(GaZB7A9m39v zYopR`A`(8X0GlH-Jo0ZvHfjaN)M$qWn2Z^nA%nQ8 zZl;3@Af8Z%b%(d^-NEW4H6}mXYV~L@P0&ZW))_SYxa0}Z*%Uh^ek@fzraREmv}#Gi zl+mO&XwJ*hNPRy3X@qo9fjM24^@px6XjI6=BGlsfs zYMBI&V0wn9#2!*h_c=hjZx%gKrTJszA83{wkkns zipNpzM;y^*EHc*(%BXH7m1dv0gvU3vGD!nP-a~Ifl@$XLkE?C3GiFl1RKOE+M<6Bz z^=w|V=xaCxOZ?w4?GPxwb$x z`=@`2M@Q7cMQ97uB<<6>-6Ek!Cy?|b$KN|dz_YC_CNbEXzoYi7;YE6|IFZTGb=<%}BPMwXeSe%eH9ntTyzDAw01pZS zj$MqyGZlt=(9EJfBl5x>E2I7jAU0Qr;8e)7DBi$&KzZI*E(to=jW1Z1SV9q=Y!Bud z#(Ky|9GQHgDn9yhrR$M-px=P=b0)}C7KYAaptKHOT4!nm3=KC3FpN}O8;eUN8UO&2 zr5+(6! zw1%+%2%om_r?BEXCF#kT@C|4OVA_YM8S6?sor=XBxmT)Ed>(LA9I1tCcV_FCFn*Dzdm$_#X~`wxa*?GouNxq%YzJvc zkADRD${jgrvQ>XMI($*AdYKyq9Fh+{Q$Vdp0+2+c1=98(0ye27ccCblPcAOT_zA$; zVOWFz8XgVzn?G(%wq^=?W5oLLKvj6vrqxu&O+tpcXtSiLTqWB3*;gSv)?%B`7ny<% zz?tI@`r)RvUhAff3sAtJVmO$EkWkkMSg7AFfQFb=yFwcjVxR@5ZnJM`;0RC!y7^xf zz7b4#kE^7OsqO@8chP5$f=vjM-h@jvYxLF4r9*F&1zov2;`qq!fZ&1oen^x}!WNrK zeTIwZchnc{U?g+Oq7a4(7g3g*aa}ST(PJ{Xh;pECQ%aMjV<3X6BX_znjPM?HH_1Ox zxw;3A7=Zx6;u&sXXb3Rzh!G*RD?-X2njk`K^prKsEi^4!ml|w@z-Xt44(_cNqrdZq zZ{=0mc7jba=WY0iq5L@l4=blGgrV>XWiWmb%>V#WF zUJECmbs6qF>;sl6;hW!rE0|64G$>HWI!l54{lh+{>YUjrQMza?;tyYpC-aMdd z@)&2LqcOINoFGLfXqQn;Y|!2&V2!)8zULpCFA?xZ`5M^0#wN{PFH|HSXis7eqQz+f zgJs?a52<~VRFTTU{07ooC@(5{0in#dKW^>lj4H=%YKPsVx=u4B9M@^Qt+6a1J5E5L z!qd|!bFD`K(lSY%9Wfe&WqafH)j5|*T~j9>j;-v2IWMX*NdjFnP=nWcUI!gmAERdq z;2`6Se`nF=BVY160M0L_ht393iCQK{!X$tz8fJw6U>O0cASqxx@5+}RuJV={u8N9i zxoIEDfb!)KX`QbCkydauh+Ma$3nt(?&%dc(Leo-$S}@FMmm><&H)9+aUA1s*lGiDP zHI9aZHuWj$(jtQUL^N5Lz)1Lp(re(ng7Ju9!0Sx~6lVo7L=cAo1xglFU=8FRi9Ljc znAs!X(wRru0O@yT9B3rH%yUn1LJ9~CM2)**sX5bMfyqQPrt`v)%|V@Ut`Fcti)^ph z8UuFBLd&>|ba|i|CrbBusXXmIIwk77bZN~%f5BnlAq!C@?dPw*?1f5H>yFDL(u&zq zkYz3p@XqPzct!>eSCbN1kbQTsyF0Kj?_WIn52ihzW@@edk=8>(e;;+QkDZ3xAnEOR zSzwDOG3_Gw1XD?#AAxw!xF^3++Bte+Nuyu1`xa=BzumZa5_tKgt;Q4SD=hj#-bg~ls}~Td?5k~kY+B_ngBq_j!i0Bb41d?m_8c%UT$aG@qHC-wianA-HweEvh7G{1^L9d#5UN3=mV!fzt z3QhpX0vNjpYnZsGlsT)j-lpnt96nob60ghc_zD_=STlseGL|)M1U;Y*Cs<7J5)zw) zN=x{k=VBi$kg@0$LB?!yjEE|BqR4$Yg7%>XR!jry-=1aqoY;r=x-%Aw-=-!lb|nsr z5ee)`CXkOKX?jsS;yPp3p&B>@XyO!Y@C9F%&4LaE?I) zF^4~7P()N5Siaq3VX5Q|UJroK#1IzgWYWRjMRsiNuZiA)p&bqYnah}eA1hC_#SpZM zc7`~0y&0_=?R0XPPOeM2(WjMztT?>&y4V8~6rkP>`iX29hbxrhDaW#N(1D6F_xY zgpt`=-?n(w5Ifn{(dpy=yqkqIr<{=T$%B5jh0sE<<7_as%SOZ4gZN2dH#w$x2`-10 zM=vHP4SJ_1$mtmA62PSH^P7(-6fs)tD@>URkCS5)OVJBnV>13R zd||-sf*7BVo#?Q&JT4ysN5%15kkmAyOXbULBrSUNbi7NQrQOe<-lD9fb;o{bB_2~= zy=)76#rKnaLunECFzvw4*xNNNN!kd-l|h6XmBEYPFv#VYAbQH-VX0KKpQ zmG~w5Pit+vX?y|!S882=H7NPKIU+AsM+}RBjKLB%2vP}HDy-q#Q2Vs9Mr9TmrnOlt zHqSz`mDMjrW&{m)j^aMJZE5B(+xLlNba7|UqDQ0txmv$VP9KUScI-ln9Uh6;1;Da% z4H*D@)7z*IXDq-HC4iGy@t2?~okBE3U|`GCU}HQB@KiAbBt~>?01ks-d4Nbz6ilpH ziG=%;u~J2%h?(%Vw%{so?78>Qm&&5ma`M0!rBsoWM|qd>_ADmZiy`8%Kq7pjS+*Z0 z3O$lh{9o&0BH#`3eGDq*?u<+q1JVIj{hFj6$ZCUA0<(&+0@@yLQeOGYK#vbw%>V{M zAYWApfGVglE8Qq7;lU~e*aUG&ojQS8MLCb9Ds-0tV$w7~c6x9)rq$P+Q=#Is%detV zVC2Z+lDW?gt(AvrL7Xo@{&f&8KJs-9nPgnrCeh49EmuFD*c+16w301qPbwHX9du=2 za`BVz5{Mo8)Lzj2bkO0ba=BSE2uALi*J)VDtz2DFj07RIESuU%s)@BPVYUEE3KVTa zU#Zbcd2NZXw6wr4SPK0|8x}=k4sAf1>lkoX&0!XxQ_msVNm>~=E+Yjn=CGgv46P#F zUilYnSYT~O%vu7QceLG}cp7lpzs?;i$C>uaPv87*bvME3)(9W>SmUgU>v=cWes%h9 zmuYgZk9%?b9Q#mTMkjW$HOF;f=m1=g_)n5KxP!3t-t8?Fn3`!Xg9U*N34l443o=(_ zS0*}ip4eEsd|+{UfM2@KT6tQd-uz+3c)M%Yhtw>})c>TDX$qEK zoU82u@jI4$qdG~ zG9z|*9lPpAbhoS|&z&AkmlRQ1vsF9_L+bK16^rHgzhG!p4B3OU+OVl*`BlQSLKR6j zF1f0~d6Is~a8qSiFS`0-dBgmecnlkEuO;LAFFj%*)FkdYtT&)rIp`_fKWURsmP%Qj z4jQ_ZLK}8Ed5S#AavBb=XL<#*Mp!8RKr!<*wmw_~KQG;XX^Fi{t3Ebc#&5asp~lPS zFoD7O9GHB+A%CE-GN;oYCm`Wz`@>sEmRV$y{$hHLWO}-^7g1~#&!Pmu*~%b#0QiLjg+ex*1b1V zpI=6^SM-^}M|=Y!A-?pIs9w}5cpmta(l0oFM;9)z`1q30Owdh0;;jip@ZsiXC(lp* z?cdr?*jQh@B17_aECNV+l1vcps zi~pl+lE%JxlT>8+Cb1X}-P@gCuk6Pwu&psfyWBGtz@DXY+P6zJrs2ot@>A%4t{7G$ z)eGOhNfCt2P4PrI{1>fOLw`D*9=}<0?|v<<$E+#XGSg0#L4_YCz& z=WGDO#$w_f)jRi@Kp|xKx+C zT{Gp8QVUC{91c5{JNez@-`~rkfX~juir-xM`Ws#3W^d(&v!e@paU#3?aDv0E7+yON zcC9b5*}uwtH}}sdI`PBkWJdB+VxaL2XtrdGHEee}8yjJ7KGIUf&`)xqFGT~VQF zi^RsBIQ9pjtF7h%ZM!I+^xjaAGr9ZmGu#2!+RB0{Z#Yh8zQqeBYAr&la|jy7#Vz)2 zr=|_wv+6S8t9_W9-(`3Uu0s{u!T?2GeISdp|0JmR&wv#^>ebFgBUuO>qnThAKVV>{ zz0=7FZy-ij9L}@T>3PJ@0Nny*^RMy&OQU#KK40r_)aQND?AC-sb7^4SDejR2)8;@v zX;NG8$bcy;ya?L&sG>=bu%eXlSA{V^jA+!IJ)azegNADX(~?Py1dVhj40N78(JcdC z?Cg6F#zI4(!8A2kZxBbrRQT;&p4)pHd`eAOFSO~#tDtPIrHt3RrjIG=+JHrZOnsQA z4d-Jy`Y=WS?)U=OX+(d`MNa+j0@AGTQucD9_2fy-+X~Z!6@-F;&qhe9oE&wUkxg8) zDPL%%e1&XCsLw^U%3dM*aWT?ZgFZGYmfz$hvTE^kKmLo-;nwB zU(^#6r)`m=QOq|SM_HUxkHC0bBWV7jSb+p@^3yHg<3OlgRmqiVnTeOd0U;U^X5_ZT zGxTL!Q8YUoK7G~B-+31v=99h28AONYxHHcf9jMB7&0a!B0-$c-9QNnr6uuG)^W$lm zXE{-ILQV`3q%+S`u)?`s>7=49JEcY?x0_XbNS;D(p9Dc=t|H#?{&4x9s9G0Oc_7p< z4ECi8{F!iZ)^vsa2W zu3Qg8Jp$eNZd_x--pqBL4$6|fk=}%0;w=b6`G!?8VRmT@P|a>a^YtAj0h9?cU0|)p z?I4&(J7?fZkmXQbT<2wRvd=90m2ALdACPHimXoNk(WKH$ZizJm}M6oT$|}ahNK?_BFf^^ z@gdHRI9tGxMh0NN)ojA=QCSSZEkPl~4?4yxZR6Z7t_4zfZC&PsfyI7Ct$8mE-_E(p zwe=3ZAi?PXSwLaZW({tioZyO0CjBTyDlBG_=$dd$Cnqi#FH^Qiw4{JS+}uH3h@9>g z)$S}yoT}&P8cN0}Qjja~2F3#J2JR>xhs8SMP{<(_O&F76S-|+Y%^mCynpX})HS6CUwM+tpkh zYn>#WCQo@V%g6ukc<#;XqA(UE+2{f%f3A^#yt5CO{MXqx)c22d_GJSjj|A@HZ+G~4 zI^XW-1CZux)<@r*dBCqE8Kc{aCuwYW)G8Hvy6_w=bm^TSiF3_Tkx-SDY9gcb5W&b| z>B@8Y6(JBTKm^(e_9|aDjD`z|VAuLcTyvXo3j1DE#Y)A`%y`v{g*4@qpPl!?D4vvj z!xM{uPOmw{nczAJExAQoQjGJC<@<;hBU!xbLkx=Fx)*+Rv0e%htsYHxb~Vei3!&?S zbF8Tc!0#q)C3tP9)u^IR+^?=_>YgMCf;5(mC6sU|~~@zuvmszAe-;>3?r_(IVm;iom> z&1Nom*M@*nqHzCq;M7$b-Mlys*46-)h}r^tZ4KxvqsEH{@$h5EdVHB~p<>WzBzqA2Z9|9{JoxMl zqkNynws`hQF@3pN92K_REO~(<`dk4-I=WKar8te+HEIFqrxE^b{Z`|zN5_b~6S~{T z1ylwt#~JW|XmIRSKOErhEgt^qK@aP$c)AV!nKWWv->(K+R-Pq3hZ$+{nY?@h3zYz~Y&@pjEZs zJjuwrS;Y3%K9a!ux*xXn`v3@ zc7te!aQ#w&vMFLJp)!`TbFJRUGNt!jy;KG2=HpYUZ|y2MnYrZjPe6stMJQEg+)n5N zKQA%I{ILDN06PBt(YN1JP{Fyi=YS~A2r{&L0``FpL-lz^>#WnfUc0`wwYL8XGnz1l z&a0vS9?syx1yu0;wFMuq!lf8V;x^I55$posc7`t}``D)Muhq|9@CFLbo=;y6_s&mg zMn_yxB(Foj_wTQDzV>P#q8iTR(Rio;B;Q{v9=yoMDDrZ8y3d%;v*F~3=V6S&&%aXz zsG*I+>~rJpG_U!MA)It*L@PU(om*oBZJR*JR89hvm_3uI$`Ap@MFz9}d~^s|c+(g} z8Ls2Yg<}Sg(u@?s!eK_^%lJ#~_%mv?iR!$}=#Uo(Uzz%&h%>bW+3lbOo`V8oH@ks1kBGJnzRKYmQJ$C59tMP2$Xl2+8j;Hpp8fv!?(9)CJ9^#4wK|+R0 z$2qWOcB8hMd#R93a}(x-1hg#IG=H% zfTEV(we^$e@jUXqzv`N;8ish6xmMSi=*UO#y_Jm04j!~=6G?FM@ROnpJbU~jCdT*R zc`I97^_?J~0^n*~eSj5nzS7VV2J8bLP)bd$_bL$br5oE840oA3t*RX9%P z?mON>njG%KdmOi}E`uhr<vKI-U;m+b5j-O95Hiw3{!(=zk*@8Sv)qSrzKsidO}bcZ5@p?* zNjx`=;Z9&e5(hu6v6Qo96uk5F{^lsR4j1y1g$cC8cxt5ZIzyU3Gyij zN4O7A4wA!bYu2UDr%g*rOpW0KUl~Kue5Kde2Ao&hHr?m2dgNN0(T@m@LQPiLZX676 zl5P63LyYo8a|4fO zSWm4R`zb03it{S+YolvXMSsjTjhi^TSiht3?&)+2SJutzskOP{MX}#~(p$__7S<^J z(Kdg-xvcCSG0^X?Yh61>>TQOM)O_;EM<27%)Ntgk!@k=h%mC?-r^F6j4a+) zuWN1apNq7XI%c+9M)eV@?^`4Tg`?^IY{j)IDrE32p*LmM9o}o+ha0Z15)h9D^L`p% z(pe=%QqlI=OOUu%vk79YBCn{okvDUNx(9HQe(So^bBL*}jy3Rivas0t9#-jkx9q4dp54aVPGf&BTuWj7F`^{H7f4uA!Rq{%6 z`%&{GqnsyeWKt9FnJRM-!MH|R*UVi%9@t?j<4hNGnvD++kX~oDw|h8IcDwGH?3pfA zxLQ9uo1Ec(du9XqsciA=6poKjQZRS$-~-P8ee%q)j^>4y9+g|7sPGvp?9Nq?crOv5 zYl^-j)g1FKEu3RfRg)}s7Z#LaV0k9dvd<(Q`)3j*RAKQ<43w&gB$an7IBJz~+ za7mgfXl@p((pcQ@a*)B(0h>2nE69HI-Pf19pt~Eq^U%BYIhccTeFPMPDR7ZAMJ4=J z#a|OnJC4s_Y1x9cG;NV?#0CBWz-vrjSC+6CJj1G}I1D{=GllZ3f?GX6O6e_n~9Cbm`lN6`785v=FsQYqi|XRJ)NCgMX7LeDm#2|1=0Z z<$TM+y>lVHUWXJ3W-Ew@CYG>bEU}fj3hhjNPrO6y&kPKNp7X1v_$;p!1r;j3Y6 z#FMDxlZ_|Q*ORpd{bcl`1Apmivt}3RpZFTulFgpLr$fv8vknjnYYW~n#ti+LN8R`7 zLd^y@g(O|M2D?!F5XK~nVSO34Zcn+D(VfEcL`DZr-N}=oby^y3wUhnE;yYcc zJRi(nS?D&k+G6y?Z@smW+a!qGP?w&YGq(QTPOTjf(V;nhh;Zc-OdPkSn~$#ExZ3C~X9bmR_j~2FCy>|G{I*dHUaEKDycxCJB zITed}!5}Y~4RgZkv*HT;f+f&gl8Lr8(R#EjCEL^5!@~H>H(AP_-;1bKiF@<#k;hTk zo0kr!C<}ZKyKbLddf5nzhL#MpFgw%c25isz#HzvB6LB3A< zztd@-#mG;RAA6{Y0O!DT&!?wpFXs2IEWK<9R73rh2g-cM7H(aX-E|+uwc835GP?E+ zoCN=Cdir9~cC{+ckL&Ya9IR5tq*nhS-xRUS-TRJ%{rJSvYRMSjv~&b)lNeU4sd23X<%yq zL!zB$dd8w5Iwb9aL0IS`e7uKC*3WQ}DQtTMZzxzWTu_ZQ+bA>8rBNjLG7lq>+OqfP zu(Fn>%5kqOTQ?miIlgoQXDyLdY-MOZ->HjOzfq#IJK^fm^xzuM>`@mA=Y&p^CN!0a z?GlpgxT9rly4l^qwbvcSj<;2*_B2C!fYJOG_~LeS5mN&fwX1`)^1=UeMifdcZ~YM50gNU_FnogYD+PID`rb!k#z(sRV{hkY3V z86n3`p5k1ey%Gkw%=o9zr-**_6U;@t3_z(7$RYZts>*Q#Iz!Wxgn06S=v@AbqNuE) zQtg*6v7$8UeR%a#YF7@y7!>uXA>Bpo5nPlTwle!~2AQ<^I+{W8@T10iG+l&5Tk2^G zA?*m92zYN8JW8OpH-y{YG~sk2v5+-t-&nqB_Q0KElLCb{xV8yiVK^*Ur0uoajr@V3 zVmdfIpPa4D`H@;ri0+NHo=u^s-u(2_7@dvfEATG+2uM3Qgo}Y<$yuC?jv)cFRt;t2 z9(`Q0xsBt8Px=OV(hYj@Z6{_JaN zqc+4x(Kg*%?O8|1Zg~Md#y~l;ZFM-eVmn-Xs{~K3a@V+041_5X`#DRi;!DR161oE<}+Ywh7fV3OYoG_xs z;TWZuc9fYzh((!t!VkwOAAm{{R(pC%0^?_6T82ScG+~ld-M*W^9%UdanK8#qXSLmJX*%+06pj;I3Qec zi0mP5@uar|G5bz{wqM2BwHFpx$$o35{3&iFT(jkX!j%x7#nJTp(xO?C8M?GMQL4B# zT{HxAA(7jYW_n@lBimD(P;z*fueJ-$my<(`hT4O&3AZU+o{h%}@2dgh4u~Aq=+%wI zU^Q||BReC+S+dSw$y1?jh3_uzAETDvU5v2{d&@k;m3qt%4ge>J#(5!M_Uz7L99ZGT zor(E<;b!rf#w9~bU*>43s#oB|E+1077D!k?zc zQ}A8sHBX0^;PLRE#rg0zc0l|g%}vixw_VILhG;hcyrj(W&d{sQ3GqrGS3egmyhc7S zO1vUwH!rHZM~zJ#WKauIEI~mRiwSSoRGn1X1~$!&jT;*yMBPB^>F>t%jqC*S;l_s> zBSanj?{nU2JD$u?u70eFf3)$@2GJM<6Gk(yepdxQ-uQT9G=uNL_2Z>)gJ#0cP@6~D{z;63jZsQvPHS*9Fk`P=8N{@#gu zM7rt8m~&LBGU!*j7#n=I>nak^CRRP(WEOo+u-u7=9=X+hILjUn7#^J=C2P?VLh0sd6jkYsjGcf*$y7D@rmLIi{mN`1<@g3g zeCV=S=QwF!=ZYwCYgaj392uV?^hPc>h^q5u_*B@NH2oK1FS%0{1Nswz!CmB|tG}bF z=Vl?srJK7pAMJ%r5)^?OxWFwU#uRG~TWrgB zTZNZmwF2&am-4M;ZciO83**?EAB;H2M0-*o(KuHsuviXphoz zQq{#O6rww>1_)kcr&b}Xv(|t2XmoNpiT$W*6MN0B^m}+qlosU`O{{#UQTYoaSglg_ zvMffUOmP^X-+PhzRJjngISjt|*%!h?IohsR#7b)I5>^=AvY)Z%8Wy1mU`e9GTVQ+9 z7vs#Z0{~2Txs3Oo!($tFu|VViw+*1yo6zEy`h>F6wguMK)~eL*`yFC_@EQx5c42#j zN(w}ZX-e>t7c=_9QC8@tOF9m>NZr|j8lcV=-s4BreKp#YEI#(Nxjvkm5 z{_UY>MvicIrUV;LikydpP71DO`)2V_bXmNe?~?P;oY0oR)3zo$M3Ccf%)d>k0vybe z+SAiL1n`?2N40N_LI2A+or@vM$C5_0OLg1N99BD;L|Ru}m}~3^+LRPfSIZ*8pZTG; zQ|ts^l|x+sz#4_j(V}#@R;E*;uh^Iip02G3GQroJO>| z4qc>eKc;aJ%T221sDgRO6|yIF_IQxXh%%u&C>^0z$l6YU=1p@_pbk?syBILq5D0?; z-)gQ~hIOH+;I<-zPT6bJNGj5nQhD&ej)m5oe3!BY8RO-%F$c4}aE37>tzq$AIL&s? z!Z;#)MnniP0)S>;7NOq{9+2V zX(3~3s%z_<_Q%+u#HJ=Mp0k1jb8(qoQ-o{r@;UA5JOUg3WnqB&ig=k)$~924L~rg-a4%Pl zyN-v{&;nw@gd#;&iXM;7a1j`Omi|8N2Nu^@7Bnw?L2CYQtv@O*rS@xydR&RR;5X4i z5FGPsk39Fb0R95lo*S4;2Sk*v1;PR+n%zqW++pb!#3&d`?RA|nJ&oX3&_b9ZI{-)IV z)IP0=UBm!5(jc0>2ERCbzl3I*xi6D}KDrsg5m$gXzFqGhlz37=+rG*FCVB%|5yGT& zspX{d5@0GsICHWhs|geJRx2=SpY+E@iegEIAX7@-I2yybu$z&*z ztdF&)Fe*qgq@LL&J7-QxyQXb@Ze+7%Ru0macj{S(5H5wehiYq%WBB}lJ(@4nA-zmac zD7hHP*~LqPIuUiJ5W`!<7GUpc39Q(Wf_QhznFP2N8DAo0hI|;cl6Yw3KTfw9I7;f} zJ{$AyDnY&K;6$P?6*HkY`9Mp!ZS)e5hDd3rQ(XK%qN!P~9u$2hMY^tELJrM$BqL%Y zhdBWIw{S0pD0#$-=J)O(dXI^f_yM^Rnkt`kM<~$RfsvM?i@&au8F!*nn{5pPstaPX(AAj; zVQCMgm;4HNRO<;4cC7^*xgczv%etL1=Th8A1(g8G)s_Pzzr1paSxRWZz*ZKmT&>43 zQcYS72k?v4FGf$1NASSF!c`8V0@b@{rsnP$+OhoT)AM7Co`xjyh`QHk6;l>=IjO#w z0J@+ig2Vc$oZ+p15$cwhmnlSt1&=B~1ih(^+r=1NpahNL{JDwvhp1q1t3Ox%U7Gf) zHF57kpcyM28!5R8o1KWBgDxNs&8;ls4&<6Io1?Rv$hE2h898 zR%0wL^;)UcZD?Fqx(uLWnn;>G<5+d-Pqppka^(|IclTP$7IZibGk5bAdjmy|Osxjh zh<^Z2X53alKrHxkJES0(0MkW5u9h{ChHhJQ{E~jiaRAI6xW;PQ<1u{-{4jF~OUB@< z@iAM5@r}2pIQ=57m#Lab?em#EK0kU&M>Ck+AOWd@DV6rmkB$(52&t-t%Y+M8Vgd+r zZA;@b9~Qhi>mh-PYnl)zHIO7w{t-tF9+ilb#R`;IqK(fql(`F!o7XKkPU)G3){jO% z?e33H&Jeh))k9jUJ){@&f#LAIM1~q@Tbn(YAD9ALl?|QG_gM}_ztJNQE5bCrON}ge zvuC`JrXJ?B-PKpqcw5PGCHgs&vY4wkePtkg3Ox4_7#zdyg}*CwRZ?x zbp8G2F>t;8`=PnMb^S(jO@BBi&C9qF#ImD1Km1Y=`3*MVS83aAhgKbxZvwqR{(ttq zyg#nvxb|=8Q(Qry2b8c7q-0w#Nt+@m3kkPy@$x9W$p9FVV*&#N1BhZMe)o6Isj6P? zy)yu5*-73nav}|GZ`IY+)z!6ifOstl1M7$-#s4Db4Jph9WnR8Z&>rB`Af%0s(?6Zy zmS}GewqB&j)tQyS`9&)ANCJWKURl7R8ag2r@{mJ=v<)w0cGW)Ag%|5(cjUBr?6aFt z!PemBe1g=ttKk5$*ym}jx%-!=kB3kGb?1?v7zT~4LShDzC$@lr1I)bcp zNRMEZc?pX%t~2x-H|J1ufC*0I2d3SCd zMTnfN(nBhJhWoH*>NyG**G69MNtuZG<;&P3OW~as~U>K5rSW02%K#2s~fa;Kb>GiSthU;{*hq# z$H~#z%)~OB&n}a$cuHfMeQ*)+`0SYHj-)Fhm+@)?&BhbGaRJTeY}K-oXW$=6uOuRPD~~R zGXwYB@>QgwgNuwLpcQkcAQqB88+ykoQZ}C8bIkM$%$#4Ym!Ay1{QkukS~0YB-++>y zQjwQ+)&L%Au4_LWz1<fe?Nadak6NkNDzJ++LuX z6E{FUk@b~{-e9+A3+^=Pdy&S=-~B{)z`la(;j)9^r&YUkm~f8Xun@Ba+Z00g+&!+I;Hy2F8Y2@M zz?O9c7pqwwdl%xh@I{=!`Tmtb3t&qjA8}Np1HNhiIX}zql;7xm-HNK>vPn#lJhL-} zh7W<7QwCaECLu`KXE>Nl*@zCHggZo*Y)W9f)Utimt@^RSARe;{FA0puwj|>{5FPDJ z0PB7@w6RO|vIhm`E&{r+Q{V-$e)M8}_IA2w)z~pa41(6`G0)~HbA6+^La$Ds`=+aA zq1uHPF@nIsEx?d97vEfbIh)fG5SZsKE|cczVMi6iO=JE@e~Fkge^nw6z3?j3uiEsj z&Gq=5LdvszjJwNd+z| zcWXy~LT^z!_5WED6QN#@f@+r7x`8nvyh)(-NRJz0tUp@@7pANfU_P@n&Oc}#{j;8q zeuV$n^sGJW{@Qd{PH!h)tclQSQeC@2&y~S(0Y+pehNP~RUr1B&{FA~eU z8l9{vc^b>_y%v=(pIVL>frsO{u);B9hdi@vxF2nEL6O>tSuZ|o4f zfrQlW#vSJ_1j-PWbvAUli5+KE=Uq;p^?b9g%U|p*;HTJC{kWk};~6|}<_uU1Vm{(l zHKMABr-IQTb+Ktt<_x=aMdSWPi`P3YNx{e;_&V=7thl3mD?N-F6i%{SDm{K>jxz4W zZ=S40Tt3}I5cPZCp1VSn{>iyP`1e3te97;GHmrz77Vp)^iihpoi3(fz5x-l3{A^Z7 z&8s7mE}Gq=UH<i>R(4*` z)y|hcKKO3+R~1-BuvK*Y9N=ubG!~s6kqzY7H|~$1%t68|ObXY#+3dz4KJZ5e&e$HB zEqbbh$W7mCli)Daz+++(d;E07>8iG0{rWf2d0q!ouR4U$@J3NJ;VWL(4mj+=@NR^? zqiTMH_%qHKuG|t+B0@aK)W823`hz>)JhaE^c$vbz`V?{pjz_)vr@RbE3`t-p47ZAn zn!)7k28o?E*tuhI;A}C3(tI+tzsprAYK#w&vZ44pYgFtbDT~jdfWv0au!6)F!=ACZ z;;C-yd7vSrGKiojXV4#+f+2R~7^-pkd{Gr0`1#hp&b}uWG4WCmPFv2jl{)?JOlC-K z_qNDKL710x5Dl-T3`=o;i2k%Iz9ysUjHDB zZ8us63Ur2QzZQ5Ud1EOFA2T{t-H3Ajp5T0r*X{8i{glN&+qwF`QE)yHUIypmAmgU_ zTq|!}#y^y7rmQ1AQ+~*d#=nx5bv4u9Pd_*;pF2+nO99ywnT5!d%7Hz8KY-U$Z&Kb3 z;W1TKWMZQ;yDWYV)7i)_ub-QvjJ@28PQVJI4!L6P0~@0#GhgrM{^BVFh-8)6ziZ8v zFSoD#X8X#O<+Tb@&MM8Uiw3>v^AgYeO+COO)$L%xj=CFjrUmiFq*QzEGnV1`yXCS0 z-2C(O5HTQh2`yDgp5pR*@!14bH3J1w>-3U_V}OvV)1gQi`LPCO){={$*rd?gnH3Fg zq}Ll&W6Z{*v~Q?_dKp3&lhFB#BoKh8qI+kY_ZRU2@skBoyY#^M>IxNUI%!-}=cW9R+L<+cgH@|BD zNtx{9vMw0*^1JNmmKVX;d0Z-)ab1%J%U0f`$GHenh&QKS&VC*?2jJ3X#3Qjw-E6Ze zk)^SRdIdogkc?q1;p=_j=r(|qB#sp8&5>HD@NsXBC5Sz?C}_Rg@jHOJw1OD7c=Ydk+u7zMb#!7` z18mA`DSH4dUhFHzbe$CTwFRx@;>+wm=`qyEElB#kep6cjqvweHH5wz?dlZJY$iC&o z0(OBOO36LMXCHO_CQi5Lfo+B%R)pTkwJHt`z$2Y7qxR}6(MvV6$8l$rb9j-(olXu zTS3`E%cEsW)v_d!PGytzh)ON9Wu>F<8LbZX=rIzrrylBos8y<@7=)7JTY7Y~N8Jqg z$fkM&?Z5#91kH!0b+g;NMPBP6VsD$0)u;hHDc}QyR%{Ksoik0dhUFU12X@Z!G%mKe zGH+N*V*<7ZGyh`G1`mKQHH%%AJZIZFM=&_Kc}ul~tEkF^c7z7BdjiKH8lv2&td#Vb zlplJsdft=Qntz9FL&!6Y)xSe`0WHAE`0(gQT9AB4bo$i7>ZaZ7Sgy$C-;towF6??# za&$1G`HB7Xbd!yFyJz-z0389a7hxBa*~(RI002*iibW!LU;?g!Qh^$_Gys6CwK?~u8>l1R2?Q&p*U=r zI^-Du0heuKCn+PVZt$>dXiaWSXK&CFU)Yqsj(Xvj-h=cYf&759Q-x*=7@T7qyklPN zqLvHjMB`$Tx4t99)V67+REkF357&y;mo5j9N+NnJpG-hqN7xdT`nIGgphWYznn37) zyRsTvq`agS-6y8GbLTRCr-|i0`=|BWt!s0Yy^9g@)o*^gsAUiPG}JHRpiYfoS|52w zg7Z#&F``fm-)i5szn%q?ZD z)Fwl%M-=SG`+SwIb6(h;frP7&i=IOdMgWE(@Vs={&^)EKx8d8wR~P+gsT0TbO2`<7 z^0MO|(6ljcC#78E{3PAEW8!GNYJQOdO@PSW93P%JDAHm(JoK~^&Oth!ECrR5`@QyR zjJILFPUXET`tI+!f}PY^4^mlTVi4PBeBX)B14vB2j6arRaEaYE&wQP50o|-5&0uE6 zS*~Qv$>vyr-fAQ*0-7v;3mp{bQp-kaZsEYu1?#O{11cH8jB%iP+B(=UpAz#<%5{l; zA=~q?)Q9ps*N-9RNbo9x2 zn=uftiklTO**uak5G5%c%C^4-18FF{qm>=D>NP7DZ(M(if7TBV*Z23=U%gtNOx9;P z4-1EZ$Wur{xn(h82yCp%abm2v%E`o8hs3LAH%75IuSm>1ZjT5}fO=XU#%cPu{J|9n zDI=sf0iQ%L0**_j315G4f=9*oF@N@(qTNMBjfQo6gN2^DOof{h%liSr75Bz<{Hr^< z4_u0L=m{`XqvF$>@or0+jaiD&Zd^A4OtMc*uYZ7wI4i^fQ?DJ_{wo2^nRAYSCTgt( z=}E*o4;L>cCs3YR@A-FM|0?Y!s+0cI+NYm=%~{xOUBsQwOLX85>l8@iPoAKbYCmRJ zp$sYCUk%6mc&cTJ{0rq@3ARLSxbDy`5dBD=hs^|0!6G8IYuF2F;Qw%JZZzNGDuJ*! z#17#QRW_1p;2DT?T}v6u{sdp-MnLsFnN3O0hd`?GLL-AbRt6-;KI#L z_iux|XA(0gmb>_{ev|lhvrydY^~v^nD?~+7m{in~NQV8{)Y%4Bo^*=nEH?}#&rw8N74BxZaHAzPEFryTRU@c3$g z@vWghMn)h!z@Qqr1Uv%=q%FKFP{Jx?SBv)13Zx~1qj|V_8`i1<2e>+&^@pv9gr7+DfNIN>kjv;JG)$Rhbcb-}F2X>ts_II3k z_XqZy+O@hBb@Z8tgmLcX(n?gWD9Zpuu~g6H0VJVm@B<~~Qc~?{3Rjd6lGKQy~Air*h;WwG1VF_gRGG-f;bnZu($0Czz0JF=ANFNOoyU7 z-F16A&>p>5>&z(X%Xly*+}XJrQhWWS zGbM!63njdadW=Y$p+B3xo-&G8bFkYG56yJXD$~UWpMv(zmCXQMlS#wKZ`j-#%USs4 z&bM}n=M3K*2vgU#35mAOCJqcnkPtg{0P0gvC#7+Xhs(%Fz|0Dl*3q;d<~Zj}BP}-VzN6!jUj0ItKsL0ty90xS{fNfoXy7}m0;YH@W#(MN%jM7M&s#Y%WO z+O+T_=5isTo=c55)+;eJRxo6YU?i5WxOH6EfuG$gZ0zMn*v95itloUTbJD)`um~jI z1*!N5ekHm;eDrkZ;e#iXP$jRLne!s1gJkdQwH(;S&O^nemC)YkDkaiAslJu-7NZxH z;m`k*sS}BS>WFUh^&VI8d}8I|_!d;x&welyE7ElJi}yUDoH=AT4S`)T+U2Es72K zVR0d$FG)5!8^RST3JmF2SlD1VedjqPxYTBc8aRFOhSTzjA(uC@I5SgPpyg*ki)r5x ze>&n*M7uER>kg6L=UwW_#b}qeG=L6giU4u!^0Jq508}};&a))x*(HJ>@>J^5;=EZz z|D`-+o;L=?iubEnmX?xvDxp_H z)W8&l7feosttB;LC-+avE@XXTPlRamVcCUxHZEDV?yl~p5FH!Y&I+4CX%#VJ)}J4h zT)|vV{>LN|LUx?FseAHTlPwh5)xb`6Is#qc4_mgmDSO!8{|_m9+@07|W=;>82Y@jw zg}*D_K}l(ONM6dwGhe^rsd_3cU+@;hDxd#E*@|emrFzo9&^pEasn8z)q^vIJ*XyXq zeC;s?WorH#5Y!Oet}E2cy}aaRo37<5NBW7Q)6s!dGxgWXfgVz50jk6wf<_X_JVO34oN2{LxlM7-705-!xL?O99z<5>F0r@UG>vcs#|Cin4y}`=UJ+g+{i9kie~{Ayo=4eABehbkNWW97 zOBRFb+hJkmk|%`_t5Y(Iu=Bhg!e>DgcTr#FT9&>~2gZ<{n^zDa%k@W`MF_RUm~`%bDIP6K=AW zJN@UwE0T75X@S$IgF)iTkkxFq#65<_W;H(U+>8gNe5nZLTd->M>KCbafiv~Du$RtT2|wir!KL*WK{-t1%+i1Jh*a2d*`#(Fo@MaYXyuscR5?8z=TJp=2RQ9 zqmQD&%4X5x_wyLO!z|Kfq(#m3k@1ER4|XJ^;$&2%WWkfEa}2oT8(hDIAVv)`xSMwt zo-JLzA4mx%pLgE-7Ux%VNSF7ADW+vL!FI>COyVdKCDVtRy;nP=-*Dm#{26LrG(PM) zh6-7XI*!)J`xlUjK5IHa=krP+)ye^|z;z7Mkh{BEE7FaQ4<~1MrvtHbsY%ihIuCTC zb6Iy#0?bj>>FU<63*{z9|5zCDUJsq)m=1LxnN8+`R#xhT$ppZ!3b5M87*N9Qd*nMH zjMTV5^Z9||oeNji$}bko`O;8AqzI`~4Rl`|S_S|s&D#^1WB7WJU!Z~6ci&2gDY*uU zE_86=!-O2go}|~!jKc*FGg|q;P9vfLy6Rw?J+aC zzn|_Tv*m7};YRPjaK3rEZHj?)f?rb!V_z>A2`gQk^TQ8}i_P1B19KD1nybocLW1vS zxIMg|gA0I?lcpY7(!)zxZb$okJJJVo)3~eF?372g#luo$s-y{3)E8wgB-6Fp5Icwr zlQ~wD?!zS;e2%)wkVL@*RKom^5no?)%7@0#N@_RjDXD}^U)1^t$5Gt0Lz0T|%*uqn zXkdcN3IENDgr6V-q7yngCKt~(Bcz`Y@ygitP7Mn<`-YL3i_nIaD@k1L_@c5327o}} zEgYTfxn0d4_)IuLtrABU8+#>phQ2!P&*-wKv3`>-%3MQXNwY1>XNJPuWig97xdsOc zZOgZdvm9cm$j`>B9U(H5E5Ac1P$^6?Aw?cL5>IOhTgU3op`yu2i5}8CYHmOI6D-K( z-4NQeq;d=IX?uvgSp~mBGD`Q!sGKqAts@o(^$VI$wQW;B@PRfXB#dcOB#E-{mVd|7 zl6Zn=-HQIbd2uj;LyY2G>Z7(J3lri}rad@fihh8=GX*h0F)Ic**>oXfBhVbd^c4%v z-ljhY;O(Xp=)g6zE|j?qQ$nP}q9})AO3~?^BU+kmngI`^gDUi9z~)ChbXU-39`n^C z$YC=Bwpp(unMt#WC+S~po*r##J{x8BrzC?QXTaYO{|@Uo*bdwaQje(y5W@Cb^J|D& zKqahJ)=GVS)^sP*TDerWcP3p0Ydxpb`U(8opo!Eb{l% zWngG6ew6VUYu_Lb!@m%LYxH39XzA28aJLpes@8T1(qp;&ZM1qiTKkCva-+ zP3xje5ytTaLwSy7!eCL)L24D4250WQ1dPdyO~f4SpS+3dx8JLg-{?U3+sHn3@3>N! zA+P9MVQds4b}>j)hRx1bn7Us$$DUJ>NgkyowzC3G&NBqq;OLN9%P4F33UMIC7_J^j zb&=c>xzq8gnT2XyhCR$1!o?b4dpI|vTUA9@@wazndYzmSDT-AcX);nqq%YT+ucYva zvoMqo?(w~R`{?XopDcq;K46xuz0s_G_w?x_>Xm(-8sR;v*|ecHbdY$OyA!FP`&9Iw zRP71jf=1_f3zU50yAO>Osf%m04c!p49>;pIIS(lvI#Bu;zaw*ndH7@;j(f-|eU=lp zlfN)s!e%f=+`u_o^uy~g`u=Et|89G2>WjGhWArS^V3(%zdI!)j-QMhbFx!fbB--G$ z4?HS?1|okTMA%&Ebq!duFblSrZ&T?tuYxGU@gjvlz~BL(!%CZ7++_@FXTQl-_+ic zPYtjk4`JwTC1dOD#)T&j!4fps<(i}w`EqkVYb1)*{FNXGS8AltJ3vM$E*Z}cyfTIxh53Gh5m6e}8}Sr|X&hwO zEq=e{gB{}W9-)YDC$x$#t;7*;tRx?*L%xGK5G$jXM@9foTn~YgPYHXmE!OHQXrcAF zJ%mwccL=B4bhxB(TKyqHDXuve$qHFW%yEi~qs1a(ScE&gs|P8gkw7UFeryf6t9Hl8 z3CeDdVe(H~Dz7EGFR8WeTH9F=6gWm!Zf=gcW;kYI(Xili~xtq|}KF{njZI zSmh52|I3E0#0d#~8BgeI);b>iJgMm#0gkSvBk%=f*C$(dnsm(>Ty*+HTwFqV&$)VD zv|HNt?WcCr)bb+5=GK~o(^Wn9c%G;=bLWN5Z|jxw-n27~Jo}a-)mpd^&aJ$gn%h)< zdx^pVGTS?L9()j2PDvnwDT6-4$p>61us56=ITtmm(B}*mIy2bfh)1V>14{E-aH8ir zhPVaXJp&R#4%C?z)EE@@PxKxX;5bU+u58CTauZ|U)WncQ)3)42A+`RdLyHTfKGtvY z4#e4Fm$oYkUj^zv4LQ7G@&(xjKcB^uIEl#Wjn6Djq3BD;Zbi8t)RU{Aa!+8*EtTf& zS7W^Rl@gzX3qO>IlBu)e1HllZL(g3k`i_&yk4zxMEb)`QoXIxDa69_=A7K~6+sSPy zQ-E17vSat$>p@K3i9Fw}A9IB2`S7@5`v4NZxnlhP2*13=2h@%{2hs_me{vqS-7%ac zk=oHrSaUb)WhsT$n=d!6ZEQ(^MK+oralOaIichB*;XqLJ=i#A5g)tN_IpU?Nq#RUp zDo%Of%XQy?MDc#c*$GrTcEY=#sgL;$p5%DLkzMCX@tDVi;xFSN3O;)3F}eLqnRbkN z{X@CR%}R8~GU~VHtoK~>q|UK1qc7iPqJx^7q8q$>JfkZk7KXt$5Y~lRZ0y0!8wD4= z$cUsSwA(#8eTA0XvZcU!v7tX|;GQ9M>Rbfq0!@Ng1pEGz>%TvKb^OUEzIpW6O430M zY*!@gm@xLcPeAD_(1RWw9F6$E>i$HDVpf~s@Y|hxcZWkP#6~mNMDqXrqm#|3xq*QY z=B|;bol3*xzWhiz8UM!_QicwX_|{e`)wr=w$wIluaI@pR3w(hHy^H_Gqd;1j`PGs6 zSLrm==39bu+qzRb$BNL=u-CE%wjk0&A*9B7kA_f+WCn1LsIfG`$dd9=q;s zBW2;l(k6Rc7jfhyveI^q_ z-d8XPKxN@VNv2b{hSXS&%@&}j8(Je__Jz@PF2T>E>Cc)wowv3qJu@90_$*HTqm#FS zhxReEC32y_1Nka2>Fwczr*|Jb9p2e_{5w1shDUVx&n9;9=9@QfHq(ORK`kIbJtt(b z=4Z_xBcv4m?_gm_uWgUT&L38f9bW$306~T|deZn`{^sjnU%m3>)oW?2d0YNt_G;|K z|I%&a`-K}N60aAJAN~(NV1J^0UPr8c#V#!m%k+dM_&0=9)OX$*EHoaE>9xEJz-Q=s zC)0>~kkHZ*-Ym4pP#(E!Ly{Ot8Pw815oThC#$NA8Se@-Y~jmno96r-(Px zu-Rt^16F-&G=sWs;IsXK95wLZZ2I}2oTiO?3g$>r(L}gr#cCial`Ry9c@K9{xRAh` zDNp6@Pt0UMQ{YM%UA%{w^2x~&Gk<}ZSXb*h>Od(gV>w{m$2mWGIp*4P4D$Rgp-5pd zJAI3Tl&dh5EBVpE{xE+FT9Q&go2hcsN7$xVnKY=TI8Y@%K|@nVtVUUl_{a$bxNXZ` z0Bwl%s^|;F{MAD~9BC?N?e^SEjX2GOXjYKq3MJ>$yZ0YGe0=NiUo#4nSjvcL_iTb0 z?>vB9J7r=~TGG3-n(`$AfG^;V;{B(E_ z9VCAu=5F7IvCtAk*nshJEH3nWud%aX1zF!an4sz&$3>Asn_qo=7## zMKS*&>|vZ$hxm`E4`&nBj`vy23?E5iqtjFPmg>Vs(bfKu5(B$DZB|Qk|6=m;3_cKG z8tQ7*y^Jpt7*ccYO*A1Vze5Q6c=kkMom%zWM04e<;%=G*Q)>Hs z;!d3;Ks*Qwargi`iwZqp2KoN)cpfK>i?xef;1Eysu6F7&L+7%$uKh$)h~DPW5(o(- z#vPW-pn#?7?r`)IdDwV31L@tke*c>^Jw(c3v9NcFrZEeTb%q|3&ki7C#>>&}+f&CQ z_U^joJulIdBJsZganLJqn@e}xkShUb$2g7M_6G% z!!~Q2wjU0E#Xsx!@2}svQ%yRtmWvN!_wo-Kg>dSaM8Y@xT<3|oU_$P{iCLtE8&F$P zX9(SiUZ|k2APXCI6_0HScU7acOHMG|}l)?~kpw*UzH%ECEG2fVEc5$oLYcu;k3 zygqXT?l&}3lcVAl^=cfWxye4J-yNqQIDwAF4U%B<5=c&4y(Uf15xe$61QU{CW24+f`O#n z!a&iW!iX>rwBT{t8`tf>3%bg5YgMbR$Xb*^+csn;>CiI}5EcziDY#<$rp13sp2Oxj zy^*wbgLm{)d0!ml@3`~dZ@inn=OI4GFqDE%Fq&UZ^x=`kfBqS=PmJ|szVH)OK3@8X z9?lVeP)*yp2a_OSY?4$uA2VrxBjeiI*3~cZ|8`8U)Bm=UO!}bwh@cDJbEcf8xvXcU z#2&YxA^4S2+6E2FQ)-N23esC8~-F1 zbUt~!DfxeI`0DiVU=w@!d|CP8)UsHkHN;J)t9nlAhLBHrS4IAI=r`(rpcZ-X?A|>& zg$@9?Unf$vsyxpAREn6>vc1+zm)kT*e|a36QljMXjdd5jxB3r`Th!?Gk4b>}MwMRYhlvTOSALjZ5eybdAXGwmvN>%$xAWY?3Um12={G8=zeJ(#{W9UBc?{b}c6itOL zKdZ>7HCgh+F}M&<$m^48Dz&H$5}mXyNh4Pn1x(8?BY+9H!_o1iumVt(d~auaTONLc zCvzFERDghy7CA1j+#O{5gzqEL2WEW4Mj$6A$dLS$xw<^Gqd;c5ih`#yj)4NX$4zLA0 z7BQLX_BTuyCk^3!y!nZ2^z>CUAo?YlAVv))zf;S6XA~hDQ@fnnw?u5xX_k@=m2TEG zycRqs7?o$CPwdemrUehLqCRb*Y)z?V@^BgSswG5+YBA3`HE(7K8!m$xNv=@LB9fpY zn2o5R_|GvPbT=<^W;B{iUmStfSx5VdJ5^e@(5|H(Lcg|Db~<3OKZ>0cvj_@6EQ`#r zL6N~>sChF{Prs&k%>)5`MnrHVa%hpt80!hJ{<@CGxm0Cv>B=?xrG2M`kEu%0H{buF z!ye3-_X0}dPjN&|rem7l|231O5TQ!UD0Lf=KBptx)fKLd9Ym`ywIHv~aChe0k^6cJ z2_VDP1_U$0gbmFAjc7i`&A{k|&{#J@@fH);?Iq-@Ck!nR){xcl>X*_t7d47~1N^DR z=S=~5yZ#@GNu~NlC++%A`|1~+wCg|Wt6y}|u79_$e$h$0{{QK#Uv$#0|JT0yMJHBY z24eTm$c`UiI;5(~1H^nlg6GfN`=i>RQAkUDeXvn8=i3lI^s?P+ds zx}MudXs;c~284MvDqP$96}!aoUd=JZl0XA*98gT9tkgO*UyTkHW}S+?uuUmwdvrFhmSyD47EaN(>J~ z67mAJImk_Rf3gbx z0ys=JF;X+G!qTPoQ)F2T)7}6oPsn~Wc@`zbcCxKNa?RxtS#~y^{0AM2Bvqt1PtZ#k z|8R5`&BQB7ZTTCyGzG2Hcck$u7-%MJg##W+-J7ERrl%{l$at}eVQQ>(bUe;8#s&gsCOz-}1j@3tqpNyJ8}v6w#AEbZQ^A5mRqdd#iT?0& z0TZ**{-f1x8Q7!|9`Y$z91{XyjG}u8bok%p=J)#VHk=i7#j+W2fPNA^WQMoFWO@ow z6g)0*JOpUS2z7K4Sa2W>5#m>I-HXX)4i!3-#GsZ_ooo^{t4+4mu!;;d5hdl=F2o?+ zksiS5$WC%IkI({?!wkZ94r@TDkE&x|fIyX6uoTSfgE)%GA`@nAh@bt7Ta+$hBdHqP zO|%eI$CBo7HGJggfmINAf`OYefpXZ8K!yyP@$K$=#42u9p?>Fb7 zBV*y+Rhfh7Xla;^zdi`lrdI_z>_HYqBxF(ZcQ92Hp3-&tyTX#5;^h*C4ICQonmUflBtxP#=q z;v#`}$%6|S=HoKkn$XZt6+=4W)Lv<=(#-%)U`RPAQcV@;YsE)QaLSB!CX3+v%Rdn zZ7!hugZ5R}BY^n$>C2^s%(uRxw10O&&3lMNje0pAAingR7i!b9!TkHVyKB%{o-|lm zCoB%BA{ER>Z~rk74Gq8X*9Re4Ck@yhj5@%x{piPXD(lBFi;>GEUoWiw*dI61lEqnU zb$gH-1@o}mK`L05PGmLQfM~(VhuEE1lJsJN054V}l-*}KdF~U2hTP{o|JKrU#@5Ji zf+g=hcv9DmoS8OXX)zU`b}h|f@Y=lEj`Q8;dlz2Nq{IthM&YqKcbBM*m)%*lmqA`D*N??FsqmCj6Fn?8udgu>_wE<~I_TBG*TWMf`LXg$U&Q&4v1f_L*<(=Hkd8|@b?yG4Poyuh?W zrERuj$}gkrdrk{m#8~RomXs5Jd;sOVp!j-p zJmy8%sV92Dh4qb}Dz=rQLXgAhs}n?HN4$mYkA&-0xcVV)+bM4By1@MTQDa*Of#M9! zXgDZkGKh$v$cC$oKgq;^lNKl#QQKUHnM~vj&$_@=Yzfg|GVbQpOF-pdktG9u1#1Pm z?P>EAauYUvC(5L5h=pEyv3CGnUB;h4)y_@Kp`Vs*2gBmRH3%yAnF9x)cTHNzFGP1X za1MIT3iKo1F`XULEhd4w2}d$E^4wka@Ta$j;{!<07HRB%zUvaaIeIHn6JARZDB^Be zF$2vF!4?XVh>yW%R-zqno2zKSfOfx+iB#~dk5vW;!#yazM_i%56Oi?rgaZ!qGyL*C zGh_%_n(94y^1%y$7d_}1>GI6PtE`8!;o0en-x6k^noDE0Yy0y?!@}Ws%Bap%r-hl= z9rZ9m6_90dD;~D;nAsVSdXd?%^!6-t%{mL@@Q-W)II(EQrx9jE!lC=CHaz@`5n#di zj9W-bcX)WFJmC!z!s1v&BC1yt1a7^AhX-!;%9XAjnCc8?Cigu`yeoDTks5jLDrSvy z2cDr;`L}0xAOCfD`@3fk{uR3hk0grM)=3(&k5b{IHn7tQdL>$7J-lwozM5lM`Ps$C zs;b}Ts&A;5{MyR)$?DQmn_ggL-MG7yU$GI3gC#)6+Leb5~sOZZkTlOAc7Khu)q2>343lEPh@v#x?utk-``C6x$xiRIzoxU^U z=j2cfHz;(TgC23lv4k%dAH3M!&Py%U<;??MXzyQOCEq)vKauI@pm5Af~S^9t8%hr*%^roeHlUuVW``UnksXc(wBsE+}AHF6YJH31eU}OYY$V zV)ALmFvF7>u210rBpcA+?BqZc)?Zbn<|{Qg7$FTad|MY(&sDq)JiYdy@urvEf@W1M zZwW!^4i-kOFk{+y@jB0bbHDj(^WFAjd)9n`D6lJ(3p8h;Cnf_$h+;7KarN@=A&i_d zP-pn+=rA5s+n$4*a>m3P-(On*daf=?3$loHnL`jDU(daIbTY*0Q&Yz1`1s(h8#B3H z;Dxz5v?HXP>Kp19+m)1*f6p1+HCR4q9fyg#gBK@~vMpp^N#xu<4BE8!3J?*Ago;n@ z-n)DIX>(`i$u6p^8*ezd-Sf}6m=EeU=l zf%Dd?_*7DX3Jl&x5>)9Rv@e!NpNOI=R6C}s49wWI#H+_-lLV?82Gc^Wt=(n&utpzv@mf>(-S)!VCk6L`yD6zCikUGB61 z%U_rR9wIzFGtUTT&;~Dy1iH&rev<+KeFvkLy8AwD2kfQQ)Ci_17~=+ia!ey#U!Pvu z-)A%}`-Hp!kM_OSd5DrrT_t69a3*ux={M{$HvMAWJR%gbS`;-A6b8$t{BUBn9 z7;U)YMVP*woNUemKZN`8uBSzC5WJ)NcLxZRB5+73EAk})$fM^RfjVbfeRi*E; zpu@KP zA1$+qLe>Q&!RTw*q)GdGS$l;y*m@N31+7Mw?+nv+*VO>AG0zckVRDy1`_5%x(bxOt z)|2MAS<%1_i2*Ho_bv^Bc<~_CHmNmp$^#^nft(d@-`d@ji%r{CGz+W*<;3^cgRc8X z)T{E6VtPr}y4P570RbYNkOzAsKCP|HN>o+wyeOBZk9gUY2>l)KTX^2-7BRnp#7G8K ze2d#TREm+_fU~fGdUn^|Xlah58Q9ad^#z>nKQ}jM> z$Qe0K_a4~hO}jq7dZ%qpRY|``CoYeI;akvf=kgfKbi}0Lt#hJ=6La**MGGEQILsM% zX}QC~amxv}7aP_aC{mT#W0$1np((Y6D<2Mr>7}SKqH}YB=PiS-+X+Av!Llv;w3=V!A*FVs&ooMm2)Wx<3NBy%>&$ zhp-M6hIP|b@wGhrg^ShcBNK1#;g?vh>wU|0_1gAVU*rESyj(_GSz_#2 zF7B16#-nH#0hqiC^-?K}CMAv9+itn}$4?w$9tl)CFhMhy3O|Gh-r}F(Vch*)d@Hu& z@=DbBVoQY6tZ#vmOeNZT9JFQa9;7-)^P4%idK;bTa05OW<5h&TSfjP1K3vo^9p^2s z7$A}(#zKPn0aUVHEgfqlY*f1a&9?vA~pPn=ik^k>_1B61&$%dIWA?aUUF8W@?4ADrPyRz>s z+M+8Xxd3zhW~a(rBK+X{!#ixX-n%Oz{Ay-cQb)C?3j3jnKN*Pf(qs2iSbdQb3tM@Y zT$rp;{hCR^MQ<$F8xT?Xd060-X9BY!kZZy=}KdXD1paw#V%?UtR1;m7bM~t ztf+rNNz$*2(8R)9!*9&@Rv zwiWWd4-&qkJ4R?3sLD1#CTCrK!iuMEfa>%c2=3))i=;M5WJZEI)ghT>KSD38DU{H# zp#3z8Uj+1qQ*;G33}++2dx4&mP=TalbxAFDfO}_lO=F>J051lXRaS3#NyBY-KDvTo z^l;KB@->XPX0#O*x-gRe03lHaDzo_M8s2KsP=h)KqZUT>PEF+vW=W2!U`5{0qF%S- zpy%*UX1nJDwYFpb_h!8?09&PXchI~B3i}o*U~p~=KAeDdiq`>OV3?Y~ageYeBVDnPy^Ecr^E`yGIR@ z58#pAm}5Sr0GL~3cn(=dR9)~_MW^iYxqVLy-Eg8|B(W=Eg(u#YuLPzF0NN<1fhZ~} zEQq-k9Po14Ad$JBK4Eq6a^19`S}aL`>CV}8$5Czu8$@g7-ix)*=2MQ7Tpinvn=A!L zjdu#8?!Ymuq0IJ`DWgl6RGu@B-HWTxIwy#pPE6);BP*EEP8IxKtR zP)>xDi&^>iL6zH?Xw%7VRnV&3F@0$1w+i*%3szEH)9eNh@p)M(l_&eVC@SO{O9{f+ znKKCP*Q9{#4Dxx$^Mjq0&L1xDM&x;%lSE6gODhn#S=CLsH`+ElrjN4O3>C~kqF^JO z);b12g#2^;rn*K@iGPUot=})S12aeXx0||}bub)5_=GKW?={95Q2xv^Tyos1i{L~7 zg@a{d3ieYE&V8`dUL#{DgoCImd8#HvrfJh}kxDWKa5IEquxkSBp%V<_a)XIAt@}Yc zWTbt38j7^DNxE z1(XN6PW_YU{Et{ABf`IDLwJW=G2asbXR$5(6CI3Y#)XBHM9O71s^Fev7vLM}sbU)m z&qnD{w@ozOxA~-CeX7T#vdisbf0-gVdFP@|_>0Fu*n(nQIy1nH^a3#};f5Lx5WkFD zKaitm9RNz3SvaGRau?fF)v!x@pMyx8I8Ms>uSvv!wpQGx9}-Qlf0T0*I)FMV!}p2+ z`X0t zY(h7~;m4A2cB-x-e5UZl7bE9gbQezXkOKiykTN`#PUr}2RTQ753ZI-C4~A7122PZO zk;H2vhjSs9xE6;5ZEik&c<14EBY~O^hFkhEgkvI;c!+Q0$+jSMh@IS7Jd;!b$@5nF zM+%*AaQUiE_lR3p34W&$`H+v=n-LQ8t=sq3GT(^U4LD7eFEA2CcKYCXTh*xAmw|CZ z5*3?k8 zRGM6e4}2lxj$vCXBu5-1kL7JE?LpWxX?jk=2p;NeBE8)M&K zqmJOYZ_Z$>CwP3Q22M~2U%_99jzzT4^d$m5_0G`Y^ywHtLfIpRjGA9NfCgvW0<`r$U~~I zJOj^OYhr#(#{I$9F5d(!E)SuA=(smZ(v>ai-hGx zy!rdf$spxoazSFPleXN>u_MZF+GlYUS?QEe{50x$g)Dn~rc|&jsMm_(I*u57=Gh4BVodf)zX21iaS&iz6g}FmmXFHmF4mZRN;f zr_B}GBBzCH4++d?bU>Zr2~`b;T@_5$t>3QUF8ucB%wmMWigw7IEKV9s!&nJ9 zAs&jy;VS0mx&o=4>H10}P8{tX>S7!7iB&ano!HW`{Pz(d82Adx8dvmH{ zw+Cai-o@*3XUELOnI^J9WFFDk8CDa6r<^u=)a!rg(KbP0S*cK)DLs+A^LV!XNwc-l z+&g+nPKzd*g6bNwNBf6(strQ>2yc}E^s5`qA5rTFV;>#NwwoOrU-`@M$Xgmt?SSLy z_yDc0ZQxluNSSy%3S&3Rsot_r0LT-*Sjsn1(B{jH<`#3E)1B*A4URq^OBnoWqj`oj ztaw(OTf&IuOv%*Q16RMHIu0*VVI46szL>`aN58+`&`Rq4ycd%bX!H?SKAOEoO-u`x zZGq^#QCQ&!PIR&4w7kwf;lmp09mvEYZ!|c28YSYk=4)Io(F~p=W^UCOfW)BIDXpsP zyhUG3z>3;?dSMErKz_qIn80uF0$#$irhz##5MGp^;Vo^eh0~uy>EqKq^of6b_W%uA z%)qJ$siZpJ%j6EhmW;>X!_xXqTr}*5Z>+59G~?C!&6Cj^d~CCgC}oNc3neyn1Up+A z__1pdgjYANc)r;IMw`yIJ!(d!%dbvPkGD7T)6N@5CoeZ``8MBmPxALDQ@GCNvgNJy zK7AWkeI6qqSKZ-M+1%Q=vUzy4e}<@k_Hgm4VuX;V9wR)xsudq|UyzUBBKqcdyO1Wc!nODqkfsK^ zOamq4a3;7Y1qzY2oS3iXSGP*B=2ffoHO-+~FFCL{9P&FqBm}T}TS^;MaMkv^VGUDG*hg_tA5DJ)pla>s_Q% zR_^H&Ky$@Q9ldde7H8=tx-6OXa+Q2REalrI&2>fAvcG~3v2$~Yl$$bI&|(G+r57b{ z(DWg^BZhQA;9yZR3Sd6V{XUQ1Z=)EYvTBL+%og*T9K1!)c zpwCgec2rRYRV{ASP7uv+WX6GdDEnquh?ebaNMw8%*{G=+&}hb?oYPD%S`JGVU3F0u zr1}0`bcaowLQAW2te4_gyGv`1t+j58%orcr|^xdE5>KZOQ)chXi zjoDRGXt1MQ<~uz>avu^4`pEkm_*pN z!Q*x`R1vQgBuoxz+8O(f8M;(xG9%IoQJ6x$ipmvPsdDfJ=ONx_n!fhVh~xAPr<49i zE`|Xt$G@JZ9(A~A zEt27<`IUz+4^Mj<@N=h;-;lY*`Nn6W%=&w$*)eqVoi@eCZUfR)u=4`jnW+bsG3_=m zLX~~&?>LJBMc4MR(?Cg1a4Y3Akg*T*w@!79O~=VxJALY}e2j+~dF^dAh|iryDW67e zkUmA_I3Pjaz)#_JXV)+(GEPf(Jn;_aGTEidFFVdv?YM@Lk5T}(7eh2s1ixGVI><8sQS?d zs%?1RHmp@`cFqhOF;!v(J|9V}^LKWZG^BUx;vtf=dDoAk163=wJo+gF!1k}MalHaeorn0D2BW|N(stad%yHl%S5q&w=IUWVm$wOFVc zGN~Bw9!#8%;kTG)=f@6qKpYX}Qnq^AdBpXf2hq->E-gd{!InF1Gjr}6m!-j=dz)r9 z-Phbtr;Dyn_b}`0H2g;UQ4vn1ai8j}Z*a%Xbj;s;9;Icb-Dy~|?mmE}I%pBMe@hEy zQd$zheGKUa@zMV*D5Th=6$A9|A-RU|cfOh`Ok`rJ-X(-$YSACcAV!(F-K{%SnA#IG z%@oTN^RORE<)>X5y8c4x+5yI!!fFg;AG+__n3ul@*}v8or) zDzKA^nA_CC3a&k~0sTW-=R}Swh@*(4?DhR{n$v*y&|KMWrCb`SLd zJ1@%vv!qr5l&RdnDUqmKlk`#5p^HA^ypIgdJoVLGh)~v9mYx>1Ddgik)8b>oOtA&p zba^4_o4dy-RU?MBx*!cd7jMK42RWB0JIrTP>_~ zk2Y3XxCvO{pCPMMqDoBy*b_x|^iSH45d7u-z2QSx$cEoNeflUl3uR_A&w*YpYb0YD zbdqaX?IHvAWUohHPpA4WB-wWQM?V^nUZ;15oUCHwwbiscrr-!a9V8Xsm(K@mv|ciX z0k-t$>GPMr+mm=7^m&e7`vqOvaZA{rn7K+FuGtF(cjZXf+@-5Os4!o=Y4IOY&!B6! z-Txz~7}o+MIA1Lsqn?sc_rYJPj0{zBoJna`#gky)MsAW=Xwad6`scX%|AKgNZC>|a z4oAoArR=J~9zTD2$Hwz2X-kxZW)g*|7QKDAaK(NoX)-o)*+AR5cc7YbHI#ev@Hr$s zSg?L4XT9ETzNHJwQ};gs0rB+gwwS=r4kkjl!ytkuh5r9eZWG-9H}u}Ofmm$v-p-!l zI=+oC>z__HfzRL3S&-?+)dlfnrzh^pvMze5NIPY8D|lIAWji=j>0(k)F^0fKp5Y0P zco3uSDV5R#EAhVQE&fYPrq!$&92AKfm^Tslr*PjndvhX5UuD^`8pKSjc7JzT3Tl_r zuYnoe7Mk5R-$+q23(S(+BypbTJ5J#yF`e{u~~RUocx|`exgN;zkP9Lut$Dtwv*X zjd{i33>2wX#)3wZCYhp46>kxp@WhDUfGduP0JU9gl8JIZ=#g^+fQnt@zOYIPqJ*uD&oRcvgI^3^&?OF4Ly0TLszx0Q1W1wB^)Wsz;=!b_I6BrE z+Ia2#L@?XS;1`FOng3QyeHrVoiOt73u8Uu|GnR7 z+93Md0lpyhXuc>aE5?=ggrvlvr8*%(aNK_*t=Em49KAbgt6?CnDo3O z#-QTJNMu3Ir2lU(eu_V^`PjpA5UJsS3H#{)H;CK!c5rqZ;MSUtp?yMU8YJ9@`{fP1 zvV1}rf=_OJyL0dEaERI)NP_nx4)3Fr&8WF?{OTC)4H`)@MhuhtO5^;;+2mwAJYrNq zD%H3K(f0OeAL+fIP=%W=;5>#J0ZMUbz#r+?@U|669_nub6B*oD(Bdh7T(m(0f4|)5 z{?UHb&?B2YxZ(b23V&1jlES|R?Pl<@)SE@0eb(Il%dPv5?%jRjU+8`LS@UE}H{LM> zCx{>~Pma!*!VE~py&!c$m(T%UCc)bz?2j#*6+Bo|RDm!if8nwVq(0<7(c;P3-X88X z+i*m7=(;V~4Ms~1qwQzSA5lVATRK0d_V5|~mnTSCX4i;$ut7lVj%=OruS2|w zF1py6HC9jWPQ`Ok!ribSf+T$!$pvj-Qx>w&i^=#vubd?B)`9FG*r5Y6a(uD`R`$sf z$!G~HOl%)b$Mgq2gu7fuIp&0N)d5L8eDoAiHc!&0=hs1VH#asmeo&3==3&tX$&rhT z<;a~p$2t(W8`t%po6+#GBJ&vyG;Ykk0`FqH*ku%;x>YB@WHh}8M$%e{3}9OJ>$d#G zfRJDCR-bt?fUuPP1xbzYm=fH?bx+lZ&HDPfW`}^I5#%LYOZeogKG`({?(M{3)2tUo z{7a-3MSHU!Q?<7v`Y)r6_pRUMmJOVfnrts%!tGV*BQ?^#(V30gG+$th)<5~v7Y z{M>*-)MNVB&%P2UOx1GJ)Mx%w_SW7}7{GQ?+1t->!-tcD7?2P9bMx8${?}h$yH*VP zGrZgR&I9B8ye_K!_UhFy$7Qt)$UNB6G%mLl7O z2%h$xI!t)5CE=gxlc7d$PceOW8qPR@R_P++nSMZPrX@@LFIuINfaa6q#i+6DYd$gN zzJ6}nAcJK6pIqx)=r_BUPLK=iQOa46E~k($;Y4t>*OwImT-rsYbDk^7JwV0)gP;(F z%%^c%(1_`d5F(0%M98KJG{So_h?X7i;l&l`Y#O+6;R6o>FmE0PFu55!*>IVZvb;g} z5wN-J+Cl|IOLdD&E=Er%lJKrW#NYUl5XBGWeFb4&>6HpqP7_AzeV}oQXd50x$m@il zr&HuR9iO}!9U~$NRyq+k^r45N*C;(h6)=7|i{mX6FkCo!yq4S7io=mq3nuDDZ7i=1 z0zZq_@{9P7#!tG!mW}n*%TTH1OgR3x=_GB2RCj?qD6nD=lqW{84hi7!!$cw zuefNv9WQh9tPEcxLs8NH3LEP-q02&jr(GoK6I=`!p_m`lAJwVQG=o{snsvRXsk2nfx&xO~2l)z_V z>^yPJ2k((*bVSUTg620Amu?+O21H91S}1hahoFzvzJkm>bbY+`Nt2GfH1w8ut5t`n z-#hAuoW64g?wn>_NUj=NDnaQvy{!0u4=^6C&HxN0^nk^!o;%U)e{sal?B)xl!PB_9 z=F43$giv(&;dc&WY7c2Aj`0>dJoQElSW3JVV~2zeQHLi|gQ3!@KP&?;8Dycrynf#d zF6~#8IY90s|5gCc{yNjl`8HZ3fqBIM9VYYyY?=pPA>j(41R`&Xo=d0hoT6r_785-MYysi;%mOX$A>tn7opA9+Orf*4`s>OXcbek1~mIFIp3@dSj zL?qoN>?i9-(6VQPqRt2H&ZQ-u3PwO!AjAJ<5QXFli4y2CQ+KvYe-ml&e13OS26oHPlI(pwl5*zAmw#)7wX92m6Y6x24Z_7$kO$z6lYjCQBI@x;|)Z$0y%E86Uz2;(Pu*l11-#Dv!#nYrnsL1_=^It55Ly z1LE45)&%<08GE8a@z0afSI>@Lo*?B$(&)G#&{FAyop^<3x}Mbm*x7u%f;_Frr$v1a z7p5pUv+iN$c>#^|tGZPb0yN}CL1wpBW0+JYd?0ntzy)=BB8EY{mV5<)O$q>_}j*(#E zvMMk7Fon8326}30>MqtcWaE4OPW12*9VC36=uJKt&E8HCw_&ISD_?7_B44ryX$?G8 zTrNz1FA(+4_vKq+o_(EtZ)#*TCI3!Tk{2*0qRo|NEGoj5#CZWC)p+N%72#;lt9nR* ze;@@PnoXs-$Ez2ZsP7m&leRx0+r-TT?5ejayA|{GIDDFWFl40ST zB331N7EB=ywZ$Ef8$rHwDfmJ-ve*OSmA($=HnHl6lcs_itu6)^9;Ih?3NyPQ*YFWq z(jSo%O9HITi85v?D|er!6BS_#oAl9P#1jM z;N-K%R7~(G`Ep&QgP>rz$!?#hyzJC$fLe5(OJ)J*t?M8FIs-iJ#ejv(~=j!@f) z?H`|mg>ri{V}KR&A`iU}yo{PlZ=YS7T99zLvPF%?OQm+OhB=QEpaRSH*db7O8q!vH z@B`Q=ZssTPzOMI+4wmu14d!k{Vn3MNa!a1dY?n}Td81jrG+id&bzNByY#J?+d9*I> zm}43#50EOWM+wvg5dbl(aZTUemO69tpWOCBSrQ~F!eJX*rPvWrM!;zWNryPKM62Td z;lz?Q18F^0JXN+`!R(dDwuqI2O9O`NC4$!4uULbW6*D2p5bK2JB*MBNpBN|6M|=QT zqKYHRZ!gaKqY(;;!_Ks*km=ySre(x|d~jjqKbuYv-nk01qYi-~M1no0+7RYQLKe@K zw~gVJ?u;bkq^YY>l!oC}u|Hx5U{+ilbs&XSy4DOX%^;rg^{`9W7?!}LU`iqgKo;Fq z6_Dx&nKMN0KR}h_b$;m9IXIfW9F$c^+n^xFu(mIZATFZNwPI~9ZhUhSH|F}?ncD!H z95Z?*F3{Zi5uAcnE$w>@nHivHe{fHzF%N-MmN!Cv3>OQ7ZCYT`UD82n;tUMi> zDfTyRDWpUR6$2zFqSoS5T+lQ=UrAYo10c>*}oA%%g}# zH_&K+@dmUgK&i}Q#ap11|9eNk!Mx{BT5ynp9YF$eeuL-|$cQ{%O4ns`2NDde!UDmu z@%bwRa?0Ap#tfmE^wpBD2sv8v(orssQB1<)yt#qO+qe}lOG`l3;3e*MXS*A?lfbPS zXoQ@N5Fd-zoZsW4?;Z`Y@WbyOK6zT;w*>QSs+X*|49H2h2L=FQ5~ZcTW6J1(cTrTG zH)2{rQQw`T=>S%AJXCy$H|0Tm$o7pxxA{Lik7f`g>4gJX2j3|z;Vn5Bim)S@?93;w zwXGhg{LJw1JrS|F`uzWH{_w@+^xx=WbN}egl)Z0$CdM(3m@bocKcM^3n{zu1asw&E z@nvWf#foV0FZ{Ezi%T+Id&8;sQu&7C94&UzJS?v@X?M|Y>A|i0ce%JRgzbpB{{k-f zpuLGC$Fnmk5>}fNJWs{vtYXOr+~e|nTjz4ueSN_@DgH-SDU;baAse-DY1QtYy@i~7 z$ZQI{Fc%|aDDt*vH=%-&ki7g@1he1#QPjUqzp{O%$NL*ox@sQ}DBVdd@;ysQUuhJ< zxC|#GxE}RZOPJtfmIq;vBpiADqEeu@wk{PlQBeY&LL#70cyqjWFo8=ej%VD@K)7eS zAjf5ClDIMC?9)3l@@d9TLe_yiO+Piv_vqwp1t646`X~O|OK;QW{K!6#nk9t+o z0{`hr%zyF`7oM#6XhdfqV-z1F)HC+|;uDV9;$*QQlbB$h#W-^GEMAP`l0zzFtEvVL zom;cn8CV`1f#l$4$|pPgQ`*RM)n>LkFhZQS6E63hW4S0p7ywLaHx^2(vwP^Rtc?jpo$*|OZZf>t?x$klYi(eY&X z0wUyCj*F(WD?gH|Y@K*OewsWKVr&~17t#?#WWvQu8|989?a)G;1l`pX=S{D6 zeqS(!`1hRMiv#3wk~|ImpCvP_9W}hn#kxKnpVIll*3o%Ix_H=u^T4XCdm9SwzKU>2 zOmccCW25Jk<-)idPR>yJrXis`;S@+f#?VTZ`Z2RvG>cm{v%#hCJznT1dri{ZjHJ6JLyXCR#^Wat z6W!W2O&d#4uiuPP+!}ICa!!*Nr0~H>RkJ5tgJA?|n35KE=v^e{GVdkj+UL9O!1L+Z z$<(T#H}vpiJhle7$DF>IK<+=0oIV}xO{SZsrP%yx>*}>%U;XvhUtYcP)z+6+zW(|u z8mGy?+r(ves!ZS+B+VTb_yFcJoaCM&mn>PJ@x}xM1TNamK`Q9o_5JFQHc3P|9`HCS z+queoaYw?e-FkWdO;@@(tpKE*_qs9buv$seQKqC8*SI&ZVO#YdRbW|0p@q|Q1jMN>tF>LVqFAi7~CJIIP$oR+c z!O=1E1UG-OCm~e5JXngB37t+Yi$+!?N({Ae9wf04_) zvj(X_TJqa89YHIKt3kI@A;Y4GG?1bd26jq{=vUwyj0GdgY28-c@BBK6dJ< z4kW-@mNO<-NI1rDhlewn4Wg@3s!PIzpJ_efu{Y0pPlftZ9P~HcqhFhHIvsiTq{CU9 zKO0SmWtdEEk9dues8z4Yr5Tdt$HH7f)_&$uFHBmJv+9%WIub>3vioVs6Y3nhYbB`o;;e+S1^Evl#ef8QbWc{6%m){eg2d3pBe+(6 zS?mfPF+5<4pAJbJyFHUK)$kBL2uS!fNA3DC2E#1WXMyhd05gFtNLHp=obRiYMKK0W z@Z3Pmgvn068=%a3`LbhCzo(D0@Bi&=GG<6{L5y@{u{M~jHx}7Sq|@H|G%Pz8S{kSa z2oWX|1}8VjI)v?Qu>44>vgBl4`doIe6*#_Wx5e3_7>JhTnKEP6KykarsixPO#0Kif&2$1;d1iIk@2w=ByRl7ox zWOhY}8w$3L6#5^(AVDCq4&|L_YK4Wa1R$4?Rb{eol}Mpyb-^M-+M;zanbW*#wy(i(@pAk50_04utBp*0N}U?V6_KadOpnJ)KS zq;(8PM?(J%Ymt$bwxnUBLKt*eFSfTy%xXcyi5fUcdH)dFb0aWu!BngRGH@Q8;ef(Z zNeU#r&@T2yPOW~#njc;Cm(ErsgwY7*O@eWfNIF;pk8*8n$;sHZSpOkQLW(#-WLKyT>kt4st&2D@o!DnhFAboZdyP@s<)#( zc2@WBoUen}KY6=;a)$Jmi3Bvc;P)-O zcJH1EgiZk&bLnug0iGa+a~tCDQ#3s!$Stqyu)yiu3cDc*)i$lOoSI<(xTp#!t-sI>eJnFL-OJs&6$_27s1 zP8w!@2_ZWw1(Hw=MvQi83zI**Patz=)vC?E3j_7mtchcwP+KhQFHH`-GM~5ITC=*) zZnLcw%9;>_aBV{1FqmEGl!9yO!|4IT?y$&ab9GSyR0_5REg4=%%I_s&jjTL)+NbAo zB;*>xO_;JiG*>iqrzw%^QYka6YIqof(`4hmW(5JpDdYkI9%nBHSikw^6)09hkgLnA zi|{tX@h&BrT)E7t&nVpPXZ#)S>-dtVmWfz>KXd)kttTIBoLAh1s-xEV0FZunsz5(r z82FR}wj^!~J&!9Rbd7v!jqe&!yMaroq5=t_Mow7jCWj`s=Tq zIH=LFeVQn1{pRl3!RsKYInHQ#S@Q{m)U{YDBUWmapbSbT&R+~-aT}2IJrAV;t(`Ql zrwDo^b=z#@JimgMS~HYbjL_Y8$ddR~ZR0gez2bGnyV4{ASDIsRq}DJu8@R@s8tWf& z@GjmvBDdmx#$8mMoki9~pAEK*ou7XAVG)0TSV{e{@`B-R6KHW;#|xwjgOGr$4&3F7 zkP}mz7K#Xy*y89-=kvP&;{8ARj1JGk;t&E04e!zUtiB{0M`7?T*bL=^`P{a4!ZqL7 z$d_IWf*iZL7I^!_Rbd# zl-MtWTMMv9Ls%X=gza*Lz~stxz@LHUV0h{7wQ_m{hZ?`nlb2jXmEbBiB%H3f)^>2B z6m9W$m@$oHC|On@;%^S>yBvQ>31)W8bL7P&TV4Ee20W34_h@P5@(f902oN%LI5!2y z|5njI$qYyV{_l?aSfT5a4g@Szp~+64O*}LLFVYO8avpfx(g_o;LF~T?^S+AgQ|bB( z8cfghB|s=}%1`BH^DA)~p@4%3j8X!Ap6-E?c*I-Oq%6Q@HG5ewKDx|t&bn?XjE>CW zS1IoBo%+#WDcbQyxCdC_QWU^_AujdK|J@SSZf<7D%tkE)6R=I89*(9Q*sc==W=v?# zA%6wf(VYehxiHhtb9iwfND#QujHpU1C@YmR2RiYQK6v%e3Z=z<&UFbTP~PyyNzARb zprQ1+M<`#EzaR}KQHtmYPXcq7#+&lIDurKwys+RSVEZ@gSg2KpzPjT!5cYprJfA{l za{Da$gd-Tg(p$hh2HXs@ix-Lcfq}Tm2_R&Dj_=F^6IHLaED$IeZli6D-NkE4Ed`>w zt!+nW<;<~UK71@}(O)I-2Y4=X+Cc3ZYDHv z)L$AwqWe!TiXYnsj#R>3B6(HQxlFTKTD2Z5ItakGXFJD zXbHd0ha;e3{iPZlIw&EFVNuY6$^5YF9qp*t0+4Zb&j7CVQo(63vjD6{wBEC?jDO^q zvXE0k0434PQ;9`VA%;Y(e%HGD)-Ug$4lF ziAd}QK0>bwhH5)Qk-x?sjdh5?koCvJh)43HompFNAs!q7#ldN0)M@Tw2=MZ-A7OAe zAlV4Mx*8&J8QXf*A}uy1QR0KT$wev5FoX^RSsE^G6_X15P{ljqaQ9^h2R3+ij|jIW zczbPB4riNoj?6a6==6p+5)Zf>Z^x@$iQ@cBz9i`0L}V%FPR8?ohn!&KU z2qeM#+*)pneTAgHum|9Q_czD%n;>C{Eh0u82YW;iq|xwjmo9K}=THd2RmyPgc@jsy z5W{;@wy?BjX3T^zjXl|3{~ zAw)fnlO(#CJPSS!VCU^Y>yUf=OIBHBx5@;vTmToncWkP>V(r7P z|BzQ;9E#o*R$FpdDb)&biWO7(iNZ;d41(5p+|$M<#F?%8r)g3J&7-hdKUcVcmZXp7 zJCn%6?pu#WrTCrujY2c@aXUerjE_{8RI?2f%o~=EKXOD7!+>lky3*kGxftB*RfB(8 z`ilEPa?bfGYprlwHKR0RX2Q$Y3BDITligdyg4uqmoFJA11V(JI5eU6c@v2j`gspaY zbM=lDSWDEDsKHh~$}@%5#HLzOqGB<3+=>AADzb+WlH9@1gYK@0!gk@ZPi|pQmPzPh zq<|!r@WXgQ!8y7LWU#u{C<5P(4r4c|QBo8ajrR%yA2y9KG@%uWkzyK5%7z1$;3)rU#aG!J_zSN|4Vmr1U2(a zk$lIsDlVN^OtnN_s*{&=@eSBovr#h}Jers)!nrcum<=ysxnvYWzynRGadb|QQR~k* z;_NSG__NPcT#_dkO%Yg(fNk>u*ICUF&fg-S;xYhiBBe>f=;~y8iu*-zJ!iQsfyIVr z?Dy5>%6L7a1Fecyyt7t5OJ4y1D3(^Zj)X|et)mPU2|o~QfD#vG7|;VzL~kxL8Xwuv z^_(ny-8EgwB$e~8wbyMLSvrg6_K6}*t2Jp<@YOD_>5b?x;ZDsfs?+b=Q78eRBFEpWn10`PI+-J zzj$`ctP%sTEz`2Yf)l}$=aWyhl6>(-ghWTToY=Ez*j#&0Um-g#UpdDGk37E!eJn!3 z&_m>H$NNd(B)U33(pGsEw&r+n$n!s?>{1Xypi=5jkPwD*=k_2FW4Txk$u4%G-rf%7 zk=?79mau6c3QWgiMsEY>0v;qIgCvB-0RtmI2s#>cP7E|li0~=46TCCCMLSFeqg}=g zOU{sL zr!)f(^L?Z*kU6u3!VU~%IHZ^ZnNyC?FA&WIsp=Foh_IzGY}I)O*|tf^@xDPrZIRGj z{NYFB=??`0o%&^~Ydp+>H%Pi(KtYU35YEH_(_VFxVKqeR$nR z%72v2)%Sh`4kMxR!NF0~c%(xek&XN~fU?Tsmi2avx_A<=-`t8Kq~d_AwH4xYfX3RN zHFvO$t&0Vq?B`00fXUT*z{vycp92u{X)Xjt6)HgP;L1x4WT3@R$eGqSiF%7LvSYFB zl30)}6!J(YF6@e2-{u*d5*Uo(%2jm1quJf1Pv4C3HIDD7?c-4@-rYr&sE&j)%LlO7!P~jDZyT;LrfhdbPrv4#S3eXOJc0)nklj%$SJq8d&oou#r;_HeVeb zjyHcC!B=s5y1DV@cpbS)HdV#-%+cd|>TytZIVF(n78?_a2DxAs<;BERL6lvTKQdDH z83U}+_bCDHWX@p*KEV26&R=2u_jJ?d{HArY|p9-u7~6?Zu5-;cute#d&owv8MHC%!dZ+0 z_6=9N&Ld7dS!L!4mm6N{BdSQhU12u}Q(8-a=;rFBjbRe+pxyfB3DXsAU`p$weP~Q! zz)E%&5adgB5+Rt><}hcjkqGjp7iF=uNzII zm#T0l&AAY)jM6Q0DQZXiNSIt!XO`z(jO7Q7y$}J<@&sT3nFLZ+EP1EZOhsP>^TP&p z@{I?u*m9>Cy`IeQo;m+0|GBoYwXwC8x?xRZ5qrD7k6e535?fDPv$+bkyY=g$<}FV2 zaJ+6lPDQ6zuWbGL%2!v>by0h#c{84_!wu_beFm`~CPn|}>c*9gYemKT&2$Ex8`AEz z{@FssE2&~6Kit8--El+t8dL>0+~mF1+{bSj;$Y)uv(yv^dk?b@oms$My*HEj-`GwA_juFI?Uf9g`G`PiU|@Sj~_qk z^TiR=H{Bnd@ChHB@yAT1K0&&R4J?4HF5U-HAEaair|{AFlry91yu|^Hn3Li`ydaoS ztE{uLP0tS?6LgAB_dS_Ye{pCbHZ8vI6YBRl$;IunrDkN$1*tDLGf4efZS?k|eAlgJ z`M`nSImtE5SWz(xyvaw!^o{HMcVasawTjS@@+()(-$^I@VDH>76qepP38s0vc1_FOy_0$UBO4tZb8LBq??x=#;Knb6!qy6ZHts~8*dfP zywh0%{?_cZnt2LNq<^uqI;9DN3U~uDy_;HqJf7TZw2Q2bw27Fxp5on_*+@XmFn1p- z+{pm7M+JpQZm!QiXAhr$zTG$%;3h9h*>zF+1b-H#E)}rC?K3?T9SJ*{2SR^Q*WfGq zvR&V)5i{u2Y#!OviWan(NyP&PnWFyf;&V~kWs9=reVE%0&kmc%CU(dgSF|8Q8SfW8 zKh+1Mw{4!vy-ob-^UtMnIGyZH4ko8>i|P;zVHKVr0dB*G8H%25d5Wr!Wz#BZ&|lbU z31Gt~$=Mgm8e}&4`RA19xv7d?4aYFme&=Py08qsSPt7e*wcxcyZKWEfTDG?h^!_KO z?UrgyVwbTC#IFA)Vn<>}o}vHHmom%8F=cY_8MWTf{GfL;t5en3-u~?6^bMYLV;+NG zP4JCLQ!gIu#6cN1_%N1S* zo$>D3OS~(~oyuor9TXFdS#=$UrK+y)dsQQ=F(&ntK+H;z9dXYnc+-@GC2=uFDEq`|mWY_3G(7had1w;I#Kpz$Nu$-knk z``=V2{ZO6qsYyetD3-3#k80Obx$aSVV zt}BZR0oR4QZ7z@a05_>x17Nm&-TYi?hcAm+xZOliXQnVELOg(w zdZS|6KcX9H)=V`WzOkvM9e>%^*sRHHpY8|N92R%;toDv#TcfA+z`~zAFPeGZm;uH* ztU?8>LvwHl4?w@uOC@3LSizS}DvU=8(_GHRks3W8Bnsj*1Rdb3y5L{7I7MysDg&C&MqW-3 za9h!t9-Eoj(Z$vr6e2ysAT>n00cmL+#u@WZPnyZHj*L7af+!ATXc?LPq%L)3Z@V*_TE~72Hwol331z$@gpew_3F6n%!T%_@X z(p|z6B2ORU5fiv;9D>L~;N-nHj25{+$nBusXtwi$ujpYXXJsS2@9_uh*3q_jT@j5v z>utLOUYMOBciQXf%L;IAgzC7_Yo!clf}@GD_Gakj>md`0Y?O5Bmhxgi?54L+mp!tB zB8*H?%jTs8O(J59(lsTNGHS;TNIlKG$z1?aTqqn9sd5WuFK(?#4f_L+t4Z_gm_sm! zo-;h^`)OG_Q?@;aklSBNHhcp`DbC*d?BJm{KT(o5b&Ea2M?bIww7{t&jzA8Lon;3k zdvaDMejSK*L_V_`EW%=qKF}5sXMO#z`6xnn^lu@to0^Qi+EG zd#XAYSBk8UZm}?VrO2;nvWjM=t1Z^Whr=YVC!afWp-l5mqy0bj-n~Dn>qr;=8-I#z zS)LXSk^o;ahXAn**w#51bGXErA9#8ibpsu@x)rr#tN`z4f1l^6s&(1DyCq?gapuJH zo1or%?RBYDt8S|<@r}RFDd|!tMv_u2KSNsM9bI1S@6@r;Z7wMDHhY%7^AukKM6o6C z?I?oQozc6{;HkUi{woA*rSJ~URYe}W<;KB3%`x4sWR>=Y)aB*)#Y^7$PH5Ss>g|X< zhWC&S&d&u`4_J#+2VTJ#1Yc$d7XIPTT&h3LN!z7jHrUM`?3*j5p@x%t?(7gAyLYw2# zmH8eStPo28UqW&sFqFd206!@Y;U8WA`=n#TiV8*NTTdP!9ne5$Ls2Il1q}g4n9vhj z;9s_I8=^ZXPdyu>K#@ewQ6(_F_#QJ8t;vdkjpRQd@jnjoQc0raiwAhcHfF>ua*MOC5ovq9R;f8(ii8JmwB47Q1en}`?0inKRB%% zpt6(d1^3vR>0TUWG!*)RjyO3{X>k^e$z{;r7> z6I4D{^@#IjVt5%>6;n|PkyT&6+k8&#HcyH=+k26i^6quZObPqWL(Y?UfIjhmrY8pO zS(>IKFvxMStq4FcNoh})$Z0t=CIKQ1n`;dPCQy1z&7d?8((kivoUWdf^SYKYlxeRXhagN(sW|7L>uQ0c{PaeRw zXC5F-J?mzl}yi|!Jd)@&UUy{XiQzg{?;|UVjok} zcbQ;X=J}@AA=4U2{-N?L2wzsf{wd5*rxME3g+eeD@#EALN+TPaWteynQ(FI^R0O}4 z1vArm|28AhGHP7wB^}(>dkQoeY6NW7%dn13cm|oyZ@=<#v!E zcGyXTOvYK)Cf;a{;dF-#ACPS3s858{+#9?szJK@eH@o-xw|5_unr=!a?q=ptc74;6 zW>y)wJ1^xCThIOCUScTxI09vwa>x4tpvQj;G1{zrih|I7NcM0h388*Ckf% z`uvvo-roGhHMcKU2q6p2gn!ckq*%G4UxCb90w+* zMtB0oGxI){?%#Mef|NicWkV{HAz5ve&SHe5koVlmUO-am&1l<1C5;Fse0vH(iEgSgb(x%a65e;Mgd|6K)9=%0FSGGPYnJc1kE^;}sBvA3am%+N1j-plw6<9IKrx=b0)R{Pj zt;R7b{on59T=*JqBBWB~W&{ej?Ui8hvvT9Q|B*I3q#KDyMxMe|!%-$AHxE+)LU71peW*-&7x3MTh?Whx~j0KrY0k|C{ zMzxo0-`sxB@wgs|ONE~QJzf?!8x4vH=RF9M0DE}AJS!yoe2r`?0sh2`v}@%T&Sql& zTyR&F0qq%k&ARntQ3}_suf|^G&1K_`Z4fO=V81iPWeF$w9nus*_#8|TBe{>7pXIzt zQ2SIsOYXGP0B?{o6Za zzoD}s^!*Zfqu@j5ng}0tm}87wuQ14*M{$RA>Tcz(2~`%C%B@gYo?NtdHLgsrsp`v6 zuIcc7g^E_PI#M`>I&xk^W_bk}aUiz#73HK|!&_o|p}JW()|-t*9@SI@hsV5GhbE(- zgPgL|tPL4b?8ODuw)cI+frLHF=Sy2nTiK-6B_j@Y(i}_8T4njHA~AO!tB!;afVI&% zV`OXo@W9uJqbVcp*U~o0K}J2l<^Ht+k~)0CJ=UbvIOWjQGP)i9aUHGMxTn0aPK%_- z8hEnt7(6PkdbQnPIgDH=K`AMPX_4Q=1%2zd06uC!6}6l!rXvLelrI14)kpCrKB&4+ zp(KBbpqpyKeTD&W*}6BdS$YrvpQf+xL8JCSlnbztq(EBxI5n%nOf(SC(!CEIHGxR2 z?bVSL62wH1UeD}W!ksYPbBcU(9Y;4B)G4Ed5P2N?z%tz8LN%e6&Qc2fh{{{Q7Ni8| z!!>X+*n|l&5B?~`Ahng}bkO$>vmNp|-Lef=r*0MToKm3094W#@xC>n4xloVv$2wRMq z!=yLTdJXf)pqb3}kZ%DW>83%o;2%G@Ywwt|6A>2iG7k@9P-xRjO#~oXX7&NuM)r*3 z2~sEeM;*zuI$Ti_(y&%pafM-&NaX#8>Khlk9bGoSyT(aG-c#+9p| z{@a~j4iK3*zwz1UU;Nv{@rx;Pu^oIVBa-ScDVB1(AV`4Og^K+w2vhj}ZP@L= z`@i2g&+Wsz(9rjK?QqVW>@Y|9zCo*5jJlz21tm4vDf)1tS?~%9?Gakn{!eJoN6_tp ziV5?a#1PG>6k$tpwitax^9}3^vatd&y)-{NT1~@37%N45IlN>OV-d- zZWWp3(8dKUS(5WPqFXbXp+~7yqcvD+I?cvd|I#x`FE`ULl1EHs?dbHpGpi*&uum=S zL^e!+(pLclD?e*(^rU^dQ31z1_h>^|46z0Mi2jhK7}lA{=wGCdArDNcL15}y9hEQZ zS+7dSLGxHK#V5Uc?6H*|h7ztUdR5ChPmFK9O=h9jKUJ2(1#2IDGhZDt=|DZ1%Jyf) zty&3DIMPZxYT+>#r46%_Q&qOgZFw;RK^ag7`t&W!e;=--$YT%Nr++0hmcqOMs*sC*M%G25I1d=Or&RIb&*K5bAg;5#kX!9w; z*39Amw4lz~I8NHKJnzfusajlJI#e=!wdV^H*gM44<#CtYTsqx5b70+tglpYtBHXVz z8-t7DU-o8Bc31fiAaa$8kxUJAcD3H~GbCPYI!cn6r0kpiOP55IyK7gE^ zR-EaDk`eSedrf9|O`0??_6<@E2!1+zIkLrd3tw$Jz{Qt(?%CHFhJt!-Wz*gBUw%a=!eM_K)Xb0RYa`C-HZh+fWUShT|<+hG!P*sY-WWz{)57jMEAyPJo00{wjI=EtiWCaF<{eNlDs1b;& zuRDL<`R@MRI}cO;+yGV$A}R5CYFs`qchvf7?WKLTSf*!zbw|V1_YFRa2&(nzbeoHO zJ{{H~L)jatmr&fPN)$FBtr%0smEg(#-e?mwOL2(}fB8fR6C9ERvSJw>=xI|t6Jloi z2Z6jLd=$dOY1h@uq>S@&j9BL~`5+PR1;Txy;u>`#2vU0f|KEqO8?=7~RsRNN1l*=n zkq#&%xZ)r}{&s5+oazUY;~YQnwOkWYAp$erBHb7T?V@~uOi6i&Wj3b2Pwjz~wj@&s zf5WCDIk@-jD-rf1??w#iA-8*-0XBr4m7(`v0k)vh2N(J~A3NU&>X$d%z z>`iD_xfD&}lU$?mlay2r{{NqNWQ#X)BSJ!|YGj&-EC~lB12_@9dog5o(e-I|0RO z$V!N3Reii6<-#gK1yVN}RSopbi5o|j)!p3{i!Ra~0PQkHnz0IwF73tqEL&5xL2~{| zo>su7W6FdWER-NQrkvOFZO{MB8|0UT2A7gP!{eHXVRPQB*%UdkjF6>Sx*=s<03=LI zBt8o~b%7z-6TSIFS-e;a#O}Z#(fqOTp06Pbod4;T2Gbp@Er2#r=z(S$xo@{Ekemr9 zq<{_gz1KeG+hLNPsY{-vi^We%DLeGgY}&h(s!XRZ#jW$C45~2^S6Vw#8g$@^42l9q z+jiN9rV>fdiVfom9TnRco42Ih*UIlJ^hU71p(qnimDd53=P9Ga4Kc3QB0W?Vxxd7b zMsXbzcg2&w^ttLDBZx%%{1PtSZ=R{nt3ei^m<(Z9DX++Iv*Pz*-X?s6H;N1tb{2t& zvL?ixik?Q`K>jS9T!1(Zdo})(vIA6(5PTMhQHLS1TnaAkv5q21hA=$r)9BO`I=X%{ zm9S5MU+H|557O)EN|A2MNQHra`hS^?r>$E=P?fUFj54(m6$tcdJRQzn73H9j;o(~t zJZW^XE_nZrm~{%;ya$0igvehA_1r6%8I(g>(dOT>8Z+X8DTi;~jIXz4$zttMwv98u z%>fc{{@gb=xUYvDOZgEd&Gz$V`>%~9M=MY7g|gw{u-Tp$?Kq5e-14(u+g`iWtUY~- z|IKMhD&4#4cE8y?d~SpDgaoq0y~4F?lfm(HkEvi{)=ame1qo^1esKMdT=fU6mu>XM z?jo=oEL{&BujROZy`zT3W>J+eNp&9?H9ZOqI$U3F!^ zjFb8Jm!r{W3YVcE@iBwloJix5nl=x;?Z%a@tLLlJ49_%R-E=Y=4BKUzHL2}tG6?a! z8Zo;*|D~>C{=S$jIwVQkS4g$Lex#b|$qw4`ANEE&h5K+dpR%-aGIKqIi4q)D>A8C~ zfZ$uE@d3#I=0^=FZAoQICmc18ro~o)f-Y>6Y2a4GOX}*S&~tqmt7PIB<4yB5FQ_G! z|A|H!;hg^GO|&^%KUpuSVE`q>=kvz2YK^tLP10SExZ-M_4V8qmtt*-tq}?QsgR%^^ z-lE#*=)=&ZdKG(jE!teTa1XKzD!*1|BfouESAO+HT)6NjbAq_Wb>`OQMsba^&HgPY z-8$Gu8#V(EUQ&izlYL)RxCJc|;4J4LCJY7hh9d+pJ%^Vs*-%l0TOY8ZcGnkOHMr9U z)fbR0{y`DPmgDGW?Qu_c;jlY-Mna10{5j`xl>Ac^2jeQN?h zG1*bD;IBud7l-qw+Ay(<5(MwNn6^eqb+eH)v!^Hh^vGvG*2Jrbhocpxv~AO}MA&iR z^5nW2C7-{lkhWgQ5AR*-XcrW*^VG&oiWb-+m`-wY&E_TNHu|`5Ar9`Yi_C%!DN^g~ z<}X$pUNq{^pKTS8B#IC`$4k#QhS0p~q79e@js}dXQEWxIwhQ@I4IHsHuk=h&mgAES&$gx+DjWyfA{^R_m{5vqPO_ghO>K(;`Fp&uz-zA%0C+%AUMOr zdvUO#iLta|98}Wj!LNSTBI4*kh#$DmCG3b@8e=b@LB9~(Z}}J z*JM6_E#^l$0_3{sNPhAOBRg5B*Iquvui~W(6?}h=O3c=k9qOX9154G^hebCJ82OtJ zIa)Nu#Q|h$Wc@m-TR%+CoB9K*I-0wEaOS$lHd$+*FM;c_$K`^~RQ1?CDEuzDHm#3H z_8WAIt}nXI?<9RB)beue2iUh66rxnL_=~i)S^5Vbqf5dU%HDGMQxh}oCREaEmYyqv z_Gynx6MTr)r8EpPIx)U_#2>kEZJO(8Lsj$2`Ao_g+$SXFt-;i)r_8>y zi{RlYqmb1T#K?n}CzvbZ-t~A>J*CGT9q7BSX0xBlN%#zq4Wae8ql2%$v9X)4VZsVE z=S}nMg^j)Wym}mUaT5^VG|$Va$1L!;oO*uT(Sg2i?vDc{`<-_;@m z@z-o)m+0}|Saa4+*_mY+3e+y|)S?Q>V#$WV%0*D%tk8sDJexVm`hky z#n}7>hCYF@Z-In`lnEVQRqg4JrJ2N(LvQ$ge8Yixd4Yx5p6 zafDqfal7m$26-Cxn0>R-pKN6iX*FfHH^wy!IxsE3CCYi~; zp=K85zv}x=Pq;!Ii;rrhD^btPF3(^r>sFOwgiw|iJko84Gl4KId#PeXqT+gvzR@n) z15;#N59_bci`GN6K@axna1iIsm%0%HEyi{+N0abC@ z7CuNf12KJvnxf5cF;@&zQZ`&58W!vgrXIQxXfsTnq~jx8aNts7ih{j$S9!*7d-=8x zi=PW?YYNexGwv3a%*tW+cvKEKJm(b- zq)uv@q8x&WqR@|NP*^3CkVf6Vbc{E>iDN(4{#<@WBCw4R>Rk* zr8G3$i=(UqM#{$-U^25;ydoslBX(KE>=?#i6i+`n2XAMbhAG&%j6Uv>5Bn5r!3MCD z*EZF+z6#uGqj-Y)x9)upw6AF?)*w0#b!A~Z3nrEh)S3*k*{OTudnMOxnCcL>A0x^M z3llcDpE_q^W^0aF=sA5$q@>pU=C{0BFAsTD@TG|1u;>slF%E38Ux$6*pPQ zy__2!PyNpI9AEx+SzdjH78%!t3(I+)A9X)}9p9S8t>yc?T&blED;x1nx0lIWmPL%x zU& zf8*)iH5lcNTrv`SIgWK%K<2Sd@3I@P%U$l7`u5O;u`(+&pQ zY4tO|Dt#|lbWwh8M|z%W?u~vyF%H5AX$23CQT}8PMX&ZJWd%Ni13yilGyHlmh3`Sy zL*H5$7OHV_1;9Kx$c3Gb7yR%v9+9LlOONatQFxeAQvCiN5;Q+jQ9owyvB@tOZ_ld- z;jkn>)^3@*J`im0f@8QC<-|WL@<}XK_fz%2gvYiJYBwPjL!-*hyM7Y0e^@fSyL;t% zO8Xh;`Y0@hwAlLbKdi9dJ8Tf7L@Ux4m}h9Myxbs0$sDPBV9EToffgwV=0}Bt_l5UZ z!!OABS&H~Q(w+L!8h*UTkT3Zy6c>ZNg%w&@QxHgJUk+!ZIjhkt^%sqiYy0E*oR{tb z$ePC^fZ*cX=<_}dWOPs5AAXKQu2!2j^-uqB26CKIZTYLrYAllA0zl6|z?AUBP!i$N zz3kD!UoTPY44!=a^8oHq>52zo@fQ_dj%-hU>2%=&E)r~ZDb$^BF_%ph?94MqZ<-i; zp@1O>>53p7#Mz4tq_R6i>8R&8Foo0e$NwsI_}^ISu!9)#q!!ney3n-5_dw8OZow{# zLUdc<)@8H`?a`Bv$!Mg)nTxg`>ns>p^|cGTxKXDeEcaPXCV)9Sv^8+-o2w41Uo#=WPvDI)L}oeK)@H1jY3*w5mKaKSfl#kmWy zs_P(O$BBis#_4)9+O$x+Xa-r7|Fz1*JV|clG^3(EivrFs@u*1vGd<14hxa?k^8QQO zaNZTPW`3qc&ul7`1jOe;S=8BDE@(o}Le|5AyylW3g+sLo0EjAJXj?^TGLbO{Y?2my zmo>g!BDRNj?}t+{)2 z7Dmw!@+G`fs<-I&Uv*L3TL0e5q8Q90S7ey)&r}sQzh0^p2Pp-0=7&b(0Sd>D* zGsO^6okb)==uAo2%P&nII~=`$Y7Ne#0$iSI0kD&X$>I9rGLA%!bul(%cxU$*o&7+d`8PjTYnpBHpj9prwxyvJc zgV1E(@cdV#_erOJWvuTxdy0^RH?6SOBIVG^aNiiN$W^o$?;DNsn(|-e>N@BKz_^rV z1j)!s-!g&DLhq#K{lbnT|uiD}RHM|gqDuti@3D2~iJ15cS8V$*lNwX1T@RPtt3l2R z$H+2!yoQ74#LP38Rcs2fM|`vEzL^w9;u~ftk@JNa9dbrO`#n@&R!18=FKT6*KD0@+ zpQqctTdbRit2%INp!YB(x71L|yGHL0jE8u>W8_SLmznnmM^4mBwAokrXvt=OgHdwx zW32QL zIeu(ugiXGBIo?A#P6}?=!T@i%havHFGSH8_;vpG4M^ zqcR6d`l{4f{4;IzX$2Ow4o_v`BOsN@=aI@J_*$*2*Z`#}vYQjH5bCv3S2jGY6q4ps ze(*?2j)QlJit|1e?@49KJTCtni*E}W_3vfB%8<#BkfbCd)DdZu`hFnrt0=>aUlzR4 zod?kbon<5PZGKmdZx|i;{RYz2XEqi5FMoYr{CX^^KCFee@Cf>{z0viz9dEy@R?0er7EUk)Z?C=H$giH|yzPTQ>&dZ(m+_%4`on&j~(N!==Z zyDP<|9XQuVf$tL^2ucjq8S(f~XpjjNih%hUBtH?g*u0tbHPZv~&2tgyNY%(qVcGpB z#So%*GlW%1^q^N~9RnJT+*iuj0A7CC4N5YE*{yT((J1HEidCVmW1bM^4pBtAg?Y_S zO97jXK5)lW-lE(ptCJWE8R24*S6N)-!QY`ciN-6-DcS^}22OgtW&oNVCqA-NEiNsFJY8S5b3})o_3{1#kmt@_N#aMuz|~NO5>rIGlf7 z-6~ zU@czg!W5aRqLi6H^IcgZYw9IydCA1Kl)W~T17kwZXUB(B6EB5sa*5R=E?wFBeVT$b zbW>Aqmny=bad*+QziVNGlm%LR=BuW@*nA}$yM+Fl4GiD7)Z#8aE z^}%q6e5NoEPls^w9Pc0C{)j|%SARu*S-B>Ao@*_wso%pieuPQRJpp!nhTHWIF7W1M z9j>x_NGdrR_770MCSOL0am6LL^@&prQ^C}$KqCXipC9B98==Ad!x;iIAubHiR#S)d z9(NS*k49dt0oLl#K&fQ3PdAnGL&4?Qq55JbE+8!Z%T>5}e~i3jEYz_2jsrw>GAhdB zDmn8s*(V*uu@L30~PC78@|%!S})WiWvo`~V3+4!~bCA%|wFJWEK% z=zoL?@$KxD3|#gYH-QHSTt>dHKp+hgyt9z4yoYU=o;lWYkNpcoG5w66xZ&xspk{B2 zUNHdqAxay`>L0H7(-VX@O>wP4cL;0{Bh|4iUWR~9q?OwD^AYxOXdS@49@!SOj5JLt zk7EP1^)YB}J^YjA5d-ppB9KSJG3ph)h`N#lzC~t5w1DPh1M?fN3<9zF6|}3_VyNYLd#?Nt!%a&Wnb#cH$2pP+KueEK+rhm}DH$jvitzY(OVGT^S{Y||*JQ^Hodx=Hfn-h%CiO76# z>`6liG7^#IqbtqEnpGpfn3Lg$YZsdhzUdR%*VG7JxbC^Oxru6`$UBpZa^lIOW7KQ8 zdZqc_$J2(hZ7zR)?b9pQu3T+?cNzbc9~(rlD;gU%7>$Gj{!#8RDNA1?&moe<(Z`Q_ z$tmlY^iBg(FO#|slT#n=>p#zaVpJBj-qKAhA8Lm?6CpKnb`6{|f zFK+;u;NCFALVK4$n!4IxEcdrsHz1d{;TSs}_LF2#xQEp`QZxrr_HR=dp>XlZ)@#iF5)SBFK>C}z-+$Hr>cP&fJ7M!% zm=+R1AHE<8#(c3qB*?B?)keZDAw@3NG0D7a^SQVCq%j5M!Z@J!gpF8( zcb*ZE42TIaFl%oRwRz7|#K6S(ixrNiDB>>V#sBo5`>`0^qCFxL3?taHHXmCA?+4nhB`aw}$cuESfK&|8)k=j!X)q=Uo4>?4BUzymHazW@0F;qTvU-pnE#k7@24xpi!glJT%^=6gLq^PFk1o>!59{5J|3*Uq57eHS1K=8q z`_dPbsp6jgm5&v2|b%3+7>DKOw~+T1+(Zsl1;NqzUFRIeDH4((Egfo zPlW^t+ssCbEsq>8SU9a6CXM45P@#nE2>dKJm6tK{!sqc_c=4ncyUwn(>$>4x(paUx zeImq=xZCr2h<-ZEY;K~Cmzpb=ov^G}nhf5sqcQ5BSR!r7e2OFEwjKW~j?AxHws(KV zmB(b%JQg1h?T7`=s4yiboAS3P{4qnwz;L^{qV1Q=%nKqgFELh<8!)=Wg zsF}1;oEK@i?Pr-?^%g9H9}i&~1edA}f*;Q>Vy)WTCq3U{iDUfRpIA%`Wwi1k?1|V2 zCvDZtidn#(_%XEV=ltId2w@^sHs%y&SkM#RGz=K3be8jhQWj_WtUf9DYQ@HMFQJE- zGbs%af)+QFbkIr(@bZWWy$ZadU&9O~X-V8&6@>H0=7NkWBfmY-c~)&PPy`Q|1fI}E4=43V+-D_kSc z@vgLf=-BL$l4VTjqu0^%+uDw#MVtvAK5jlor5%=+0Ew$sXZ2>E>O3N;Qr|+vEd7w# z59-s@tYNCkzl523Jel$lMP7JQgWi&wUTQu&)0R_ysJ9#m_roH=m%hP<1OksQqCERH zGuYmE{lTxAr)#gvUY=O++K+Fat~ngfHcN^r+6#8tqWedXV1}gnd>4NXewj^Y`zL3g z_0DkUbH?c>D&a_!@^N&Iz1sp^0x4*Yd=M=%ek`o)^E1IexJwsDGnjh|tjParoxnh< z_r&EoD0@vS4PZW(=A(~6vV(kzOvfxqHO@o`L%#42NwClOrIAqo4jMW@;pcr7b~()x zTJ4XH1~vNo$p^TZ3y1-Tthc)i=M5OCD}7WWxO4PUGTdc^+DMn3BPcI%+XP)X-Ff_R zslm1ThD3D5Z%@r_VCSoc_jewB%e#VC2b+T-?iIHq4d%9$4tIwH@C#A1Mc)S_i()HA zxSXv-8gWw=q7J#K-2N-au1Z$W_4eGk=$?Dr?Jl#$jU3%oR^T|nz>0?W>*F^dx z_03Zc|2%Lr;sN=fxsUbt=Pw|OuKj@7z?wUs2f;VXYBF6|x(MF9KRP@i+`LM9t~ij! zOw&XS5;EAZ37l)d?7-X}(BCLxRq#vW71=#BG{z1cq-8EJo_4tDdH5(o8Dk_gsO*(E z>7rN@1z%lHF1!+GZx{`Um%3j45;pO{J^~_;-mWTe=NdI{5&b!=63u_bE%JXsA$@U7 zfjt?s;cIz-i%F7U-ulZkq#VQSNui7L-_Y76cId@UVRiy%g7S5^Ihy|!N7q*3{L(Uf zf9ViY$8W;KQuG_fyQbNZxhQ)-$h3vy;&(03@Gd1A4c#2(Gmw;*1j#e_PP`<{rUtbx z^=`T8QNs#`*fv{&S?5WKu;)->v1N3pfrkdxUQbgZ>;`8t8=9B;ypiz;dMM9@&O00B z(_}r^uKD2!A=1pGyjg46NM#6sSX_N8C8C<1Nz|xE4NV(HiAxCfvLwBlX1Ic!z%nm) zkTgGd){IcE=!TFCG`1cIwhVc|#8IzjYpx2X&$kU-&ECrI)WZb}z{+k(&~cdKB15$< zPMYD2uEc2>e*n^)z#t0E0YS64w6hBY$Pd{*hozzx16CQ{J#bMhq;~^+wUjxPk#xxv zpm)?DA-Ztk8K(D>{={76vqFEDIs6%@8;#+MCe!@Ut*qb*fY_iDekZ-Q^Z6YO4 zgNe;8V*$%7#%ntr^kS_1tsqJ8tpiCmrI$W!5@?7iEwGiQZsME7fjEXX!NAlOw}}(f zxwW7VI1(!MfXO(Cv-y(VXAa~;74#bm(4bbl6hhrr_Y{>6n<#j9S`_U;CoauJRK~E$QIYQ+Li|*M07| zHPr#L6YVVdf}@lwI?08{Nw5K;dwIGR%nYRL9nf*obn5Eb=c?d;Wsj?9O844)Y1PWa zR_snT5lI1}mjx-^|Miq@2sBL3Z6kGESUsnzftxx|K^WfLy>bihc7=o!6AFxXg05qzNaUHpJ|D(tpK?A>gXj{;Y)C7ym&sD@va|f zv1>E>5#s*rV~Y0#n|+HxMyB*}kiE%lZWHP$i*F%c zEG&pZ2FDX*Kv&WISH{F%(P|}4f(~bp-X?Y`%@8B{G*AQtx zn1Iuyay7OE$nsbslkW>IgBP1tqHg(-;NnLFIFo&-{TTC^jzED>NrI_y#PGWGt%?(M z?oP@rlQ^^fZe18id@1@tpKb-?BzNnzFX7oyf~4ak!yZSz{`@79Dgg*(hvx^EeeHOu zMII78&@b0ofG&_8#_NOntf45Eu4907 zE}>}UAJ=s=Lqx=+)h-{Z2FVX!mIhdl`#Ch*3%IQ^zH`D?z#=>mC^6@V!(h&A*I zoLj;)3zdSVf?7CGK%t-bNs2C;o1hlPpb$KQwZ;ol8j^~*gsz|0CLW^+LA8CUm_MNS zKO{nKg5pHSh`Rwe4wXCc7XIzu^`{Z|21XiOvS)I;M{Y>INInOK6hf|0QLL5^BnnRp zLth1Y4MTGOZ0j=m?Oi9Qada}1!nJGCC*ZIBV5ERQ#Nj0iHNIkK*9+O24oeaK;s-dV z9@HmHIbi6VbqOK}1j;`cq6apy)5J|d_(hqhYmJjnl`(7woS{dQ4UW= zANz!EVkI^ZIdD=QbLE}Rd^phwn2LY_5)z%cWTfrjTECVD6BBk}bk%NilEKLY&_JQM z2WTmo`-5i5CHGYGGm5@`{GFXy*28%x9NjQ0M z)dT#S{Ir_hu^+KMu5bDQW6%Lj6};NPg}*3&8K)FQQ3IL1y>F)(L7g=qd5c&axQ8W| z!MCw(=q~C401-TUI1yv3`HFBw(=mlLp(dB2aX+L7+zV(7Fjs?WefXanOrZEiSrp$q zKRURGwC^7xp=+8th#7b$`^~oqF@;3wV%Gj5&09l8iq&Ob(F8&Qd&fOsr?Ws(PQ&C@ zJ1FoSEneaxI1RKu2^#M<8t`xb@~821^JeQczguSYY*3lnjp(dR-Q7%G+l+^)bKQjC(i_2|UEN1>Eq*=nlf~Cvi|{rY zEM~i^eYDXBj6o{@yCKqua`&@LLM}D;aS6S9@9XdTcm9krd=GcOzsJoHlmRC|tLC6o zZJC)^k#UT4JD!gJI%bSJcq=(5?z6X4i3`J9KVn?yD3~g{&@;b-*55S2qsRVm-dJQw8Kl-&_n>SI?42#br+ERt= z075N}b!1EHy%Pue#hai>b(r)`pE zlF8f7em9N;;9>u^o#DcaD>D#~=Lmjy2G$7_4Kfc_RT8R1 z-h{7|ZkjKdUEwLkJ}Bk${)5r{0Kwm*H;nNmL;Pz1hkxE^Ou8f~hS6K!U^KYL7u1+8 zGl&mv0-X3OAY=e@B9EX`HU#>xYmspN#f)=BN6wy#>7)Td+_3%*2FPv!;^9JmOawVL3|wg{E0ZNz+q#?ISpIM1BTcJBwukqc z3Mr#$nGh-VSxU_(AlVta{852k{>1Rhe;9&QKk{}%kj7bboTg#YXcJHknK(kBET`j~ z*t>HI%3pf2JOPF zb>TtEJX^mh)6m99E^NK2Hpd_8pCUgke&-ypb=Mei;lUYZ0ftrn_omr796Uor%))Us&SDmCz~8CnrT^YE-^~!_vj<~wtFIMZ{4IUXKQN2GA;4xZ{>xxGZoOHUg?8o3 z`SCONG1G?fAzian={kj#=v5yq3C=1V`8q&1*Gqmu3DA@ZMR`vq{n#^I37~bxwW?`? zQ~d$^xAUaz3AyWHP%nU)?i|96R$3ipQclHwxFB47oJ{1rA=*gG#)6ARkPavW5(;rr zAXU`k;6Y5(h1#+QMD$6jP&CX21j2~^s~ZKdEXFp*!tm0S5{#%V^@?4!a)d5iA0Mg! zO01qx&V=qs=ACpBHle0&P)xLEnIEnDxP7z>{v2Ej0TK3Cz{Z!KEr%3C(~3-d?4AjB z`2yA`an@F0eJz=xy%Z>WX+wOHh5JB-nNMJcz;!vJU|6;iX|Bpug>qg%ij#r!bO{?7 zC-B&>jA|T#sR6e|Qm$|-SahUCaE0)50OQXHhqly_s-^-#?mzg1@`B*w1Q09@ z8`X7XJ8mxR_?@plY~chQa^fSyh?F6rm>i47a(N-Sn&?Wyy)Yx!XQ^ob76VI)VMv~h zZFc?!#b-PbfNE&gU~#x}n2^tIfnieDp#Gw3IB87HGcZwvIJ>0QqrfETMlPozY=-q( zANI=?LR+?OF+P$?tUq&jJ90K*QkfdLy?YFEBcPy@c2KTW;-AZWmLPeki8Iwo+)vC~l4%UDp9~7_-q!tL?>x zXR;vv3?FEKIK{aD@c9tbP$$vVrgTBl`+iEGhbj>R;8p^aBg~oa=Ml_8qNR2&6NRkL zWdhU!!*%l0Y_#W30v97{`D7rZY(|YTPpcYneHAA&5|dVz1KaKf&i1m^N#ndl!ng?? zT4_oFf0{5UVAz04qYkamWb?hs;Jim#s`e+^}M|tM?Wbgt-wGfg+Y)$FOaJ?4iw76vpJ59Xud(uT1 z1n&-J9Mrv}V~3%r%{S1?@b0lRzLa{Xq*;UMmc}>GTy)wh6Y;8f3$+lP}U`PPJr8I_i8kf#?yg6SXbJdrGraKu@=k z#$Ho%ZkO#M;i7Fz@BU;p0ky}m18z>M8wM*@%VKgU#8FuP_)Q!viD9@V{&|d>S+53| zDR3u8GRfjRoZJ~;!N?P3V7h4dMj{R2^axUCZzoAuAA^^cGqHuwui=Iy#8Q7mA=3oK zkY-%IFqN(Eni$HP!pDUdEdE_!MbqP6;f0+U{ObVcqX4NUZ=zL;JfS=Hy&*E+@8e41 zY4U}+4-qY#4TRs6ui)d5v}am!uphwp$0m=Ii#{_gYQb|&eTnJEUFYV_SP6vCVhr*B z+=yuSw#mO85^v+KlBdI$fU|42SfpwJ17W#?<09ON4KxY&Lplv8nD3l{B%$Rxg3S9z zGdG73mlrmiZPm=Sa#%Dn&$(pG32+NT_>~frUBWe|P8J zH>A+@x`fDS3h6ZEDa3Y%GF>7(L`PkK+F+0(6NdqN(3^r9Dw506xM!E>FNgufW*!0k43Nsa%X`(i%uCU1>XlFxN^WbrmasED`mk&YGlP> zA>;$+{3VdBJZGUyQ%wu|7Y$UIM|?RS(Wf~1PA1|h*P4xsJY{zFDu>VYFnnc~=dcCG z8;!Bl(-tc}K12o)>Jn*c>H2b zV%WJX%sOfKG*W5ga{Q?o^1@vhS#s(pok7s}MV9QgjoiAJv@SH^#=UtnJi3e#W`+v{ z$f?rhf0=Z&Y|z7uU9L)soAnC-_#(qk(Pr~dJjN$ zE4^jDU}ZX)t0b;5!H|qP?t?SM0d}8B4Nk&Jt;s>4TzU0+Ud4IA@R0?Gf^U^~tmO9> z)={JfD=`s3i9A~*gaIA&Ofl|o_a4tY~LmUVGkd=X!%^fA<{o#It5J-5n&zhb4yRti~N-wp% zmd?Ph0n)DtG@&SEU_3*CD=T^n9hp*+9wuB1D7$K!ay%Lw7-S-`ms`Pd)rc5Q^_uvM zY{4W|r0}xbE@dJP&|$iOlQH!XN$>(OgNok4-#Bmqkgy{CuK7%pBlR9~g=l+BM{~60 zV3(TB#r|xOfir~-$-W3GS&zl=nS5#FEa^b$UY9<07N0Zl zq)*dvtPdeEywrhdYx+9;#3G?@N`Ns(J;BLXp`A#yh)T(&=lhqY^Jb!h54J z9H?436;ZpA-5?SM#0BSo4r)NQS{?S~Jxvn}{*j^ zj?^#tPMSCPeiqBj{jYkI?!Zd;JwWIsLxZpy;7XT?NMwUPtRRs_P||8l52x2Bv--o5 z#-!Lw`*{s|B3z1=DddrHX*RUmb}aVHP7*((396%k(Wugk$FQ`IS^*;yXU0g92|K3= zQE?NDj)~vYs8h#gm@0$bPU%b9tU3ZbQzVUt&3reQMxcB~WRHj`1sRxM5c|ddK5BMd zbPA#nZ#oS6A!SV`{d;$#-9sxSUr1BljN(l>&`w-PoMEJ}^ERgp742F>Jx&7Q8OF+I z|CGT}!}iJ)xsXLUyfMblLQlXin;=&K$9}uFEdI{%t!fe77c(jTe2=r&M%kopA2Ua%|M#Z3 zH$rX%Y&yJ_G2;YR{GD`i{B31YKi|CaX>${i;AWvc)Z_Xmtc)#}U5Goq?^q=#;_&dm#G?-` ztjP1xxEaVG0BUOmb6C_EIatY`p?T6)@eaWiNVR=u+vmlO^LcYY$I`Q~2+HJ3t+t z!{)2Q@$kiHt=ZVU-TeNG%ZNnwv96xd%~!L*;qcX9@{@o2`S0_$pPusV!{h0*W0vLq z9yX=s0sP<(qn9soFNp`1tND~UNdf|~7bH~Rxk~U&WoQP2hXF}WrSLXFf(MUr<~7E1 z6lTCB1YOw4*&(yxD<-W^t1mXgqH&x5Z~M02K+L!G+13FNcXQM8 zJLw*S^6Gexqpjg}3~VPSK%Ew9E5Ij`+k4wDk(qTH*=G^v-8DMgp`kyfa@wdY*IfDi z=bviL_846ONjSxZ^F#BPfh|1%2=RGI&YFr$w5VxN52$@PBqMKD8}rJV@_E*UjT%Sl z`}>cO5#eF7wm!L@TW*erjBJP~h3}^<|Jk6J=ZH1+B3Dgrk1MPCfW!qEoQk!B5H0^U zx^X@Kox)}5#}geIj<9K~zee6)#qmOJY?> z2lfh}e~FMBm{^EVt}pV8dEV|~*pmDQUKtr$egMp4C?hCGF=dlq79{5|k#8N_D_1|m zzn}9^upxA0TDgJmnHYpqi98c8NjrGTo{f%Pjd19Y!Sk{>7xHXe&N#S^P_)0= zOTK`b@e8fB$#{z=w=)cjU_$KY>A()O|Y9FKAHWQGzJD}#6QD$*~wHpW98~B zP2l#7ObiGDFr757Q2M$im0}O4PT-HtlauY~j}3DB{3`Mr1EuwAp=HM2Y?66dv9Ed(mH;J}h>u zPB5=&qp4DcK#(DK@(fci&qyc!ED~`z1%*wqINP0GS_TUpuyp@X7i8+fCT3q2P7KPkUcv2nAk7wy}(2Km(`S&HGZ58Lx% zty*N<#x1=Cf7*pgOOMX({*R|WVRxtH>0!0VEna8j;dnD+CQ__O(+r0rQPO~(y{f;H zy*AYzbWy4dI5^uG!<@=FO5aK+{EzL~V)EG#Zd0$rC<7j8KD|??K_Ng8nQOSk{s9`A z(vd_La(3V3Y;1X0|Fg5w@`%eqLU*I|I;mbi#Mkrn#!o|7_U;VDsy^M)(wcR+oY{)@ zkpfIvm9iHEif0qC%YJQzI5Z$Zx}_@E9=AN}Ke| zdV=7OWC&)z!|hV@&@I%GURWM<zvIM&O+zfLt z@xZBM_F@W~5UR}q;W*=FgM1BH{!uR#4hqVlhYSsH%{N;T!@apUrjDfzi0QxJHsKbc zBwdEzE_%lN2g*cgExmBgGgNfer2clY*-?Y)5J0ub?J89UbfI>>GV!ErL z>4srH$;?GC$c(YvCF03s{7k7xStgKfvwH*>9c2H$l8R``C{|M_;3QR-OcgOC+w@+RDVUFkTv2=V>}lg5<|!rM&pl~E3od{#g`pz z2(?-UJo&N9ac)&#){ma>?W5-E7CZ~*;}>?asuN0{#@^00hxKOX(W9MP-+p)J-lP8R z?Hg}~WZ@r3Q(aiI;JwG~`jO^-h&S(Kk6TJ!9f96+_#;ALbFht4<0nzFO z+!&GM3k-AZA?nkh?A~5umx?glE6*dS%JfCvf!1MqxA}A*vCs3u6S&iGi|3{^1{o?r z@}$)QB4(k(hh7=lY5neuh9E)Dls{J$T~w)_0gTme$_>Q>nOY#f%WW6+XK3$4$y=hM z)C_>0Rv)xjN3QKDRGA)0u|-nhqsQ=6;1_!NU*gaIWtUQOTp?R$GJA{8(S6vl3q49* zIE$eoj00Lnu0CWY6AsI!vK`dMyH@uJ z)Yj@l4Xrp}8bA3f?}psN;e2}SS_bdqDf4?!Yw?&&Yyb!LjbC_#1`h^Q?OW^q1qf$fgH1JG*Kz8`Yb!9gJ9!Xwp!q1Hshhf0E$x(RYe8U z1Z82l4^c#N2v4s0?u#kx zY4~|~BqVV=mxQPr&6ij(tZiY=<5O0h#Xbhc#d%oT^_?lwpU0YVke`{aG)!?^&bn}1 zvLGIxW!`c>2neJVLhQ#bVOZh;)k?>ExVk`I>?7E1`f9WEyJ9Nk&bI&$($g`l5fr;l zi1nUnce)po(6*%C9h1uY+?rPEAWe+h@RpllXZx(cPR7iomQ|^16t`>k# z04%zR4uEI8z0mDnMIZc2zkg7s>G2eGU*JS#d_0+hjgr8>6}~wAtb$=`8N{IK9I=vk zeFT%SY+JR7H6NOr@KWMU+!!Rjzk&^ER&MiH%7!Xw1%6^Je&kblkL-w19v%Ub0R|qI z2$By83v5x&_>`teJ`yY|Ap-R5wj!-eB__Gcg@K^W;J>hZV>e~j>*I!e2*EFGw2o=U z+m`KP>$#IKJk6L8Nc#S_+O%}ZL%rY5RvR_I20Vl<11gD3yM(v^P{{$6!g3)ZgeXuD zGq3>(D|)OlU7&*zaDFe039eoW4$--8P@HDQtlA#6I0DbJiXtZ8Hp|M!3u90BO0?ZN z*kA|eA%crqUC`?eaFokSBZ5L#h7t;tiH6w8;1xOatz`U%*T3pY$_x+uw**-o8f(x&uPwdI0W zs1p(?VzMK@&eS2sX+dxzt{Y{+uq(#6VMtex=t~Ft!y+}za&L<+xSj1{Q}zs9c5_BR z^0?A8cbL5F5zS1+O{VLIMt$OW?V|G%v|@u-!8|U22Um~9gXEBLK=na%48l!+QJ^Mk z!oik_YiQi_Z9$JR|9W~~fEK+R<8B*yJI0fF^WE-ucNz&YLqx19G?M{Kt=vhaZmX)S zcGNsxp9&!-VU+|qKXE;(V>q}Aa+!6&W?F9uu;dZ?1e=a`RUfLuXgW~YwZ`8f3=r!F zkBMa509nSh4Pcx*P2+v&Iy$FOwXk6W?X?T26?iLU+u4Jf0&7dnr=@nG#OTpWvsPf{ zkpUyd#>m{P1)#ncKY?}hg386Hzw2AVgjozJ5R@%xV30e32cV(bf;pk#4Lp+O%xxDZ zyy>mMzXSJPbe4vb#}Elg17K$zVXLwc+>E9&)?@?5B^3m5 zkyU5%%k0%+g<361K)F09r)_Ig`8uguv8PEkUAr}y_IUdXZ+8+P0U?>2d;?P^0}&c0 zAf*RKFdX+uaj%Kl#C2I($K>=;Zb@s!#7cEfn;x8-$mrVsPRfoD22S{VxzAO(kukZ_ zp+u%vGfmNJv)dn~JvB|DHAgK|Co*JV%<^;*cwy--WNNOpI+6NKJGN-mT8~B@560g_*h}LS7wiBnJf zSQoK{kj@xDF+%Rlxg4XcOZ0<>Cq0Bj?ZI~RLQZ{U@PWKvjowqls6d->9`}u)_<8c! zgmQ0rtOIU=aOF8IPmlAu>cABPEu4YC&@NUM__ve}oZ4GZ(!cBJwKHNsE|v;)>G^XN zHY^?jlmWp^LXudtK#z%*=c5e?X@rtM4j_mJ4a*`s=e<%@Z3UaXIHlhl75PxJKZTCC zfv5#WZ9d7jKM!fiRqP)+PM3DfkFA|CxZ4hoUT(h}jal^^Zdw8(9cs(AI`H`U&k~1T-Tata&RK@=jTJ3yNGB05x}n(#d=^qp%Mz^I9cAHVNFLj`xlckyvt* zA;P-oVFAB9bK`C?5hPYj%!8pUKpI>nU|>tZE%WDCRn2Yl&C8rj1Q~{C$GKS}IDC|m ztsG`7Fr?XpUc(rD?{Id|sAinhCRb!};|v5`K=oB{c^7trvu!-_9<*K4<&JF5mzsPk zGY^ycXGnoHP#_vYwN@TMI5hCctXuw>%dQtY@I!@P9E%%a!c0igfNCS}3U8Y!sxB8{8l^l@eg{+K{ob>h#^mo|bSkv+w=S7YYPBcj3u z*Y_F4gEz&4bO|V&!ZK_;(K>ck6E~kj@z$P56@tA1-vhfT>@CB1A0TZS{-}mYzoX;y zfT!M7uAr5U21DGE{epJ<_k`^a_w<|p@;9Hq@_%WI<#Yb#zb~;Pz+=u@_~uBEh-)q9n zb)c#8Kf8PoCzJ#N{#zkfn%C=v9`CS^_v4ph>g|VZPOaD(qH3+&YozErp#hsf!=9&s zmuW1tEvH861rI`wHEbwNJFCWC#i=~Gq_du#A!3f+CyW6|?Pdh7C;67iFgY)Hp~LHF zHXTd~gB-5o62Dp3t#oHAfOTari-|LVMPGyBA;IT$ zvmnA3R<#KnD-X2P^Mopghl3NFd%+}@;fdKpVr0!RJdc-86jW&56!K+)cBWF*dsM-| z_!n2Lz15{rtHQo_O3%cFsMoaidVT&@C$j%4T$y#r5F&%I^V63Xq&{O)YZj@&ITje- zoVLPf2P`$yELdcQ zAiV;ET~O{bvY0BC5DT#velYN`=-OuFAxf}*|ZF?AHmel zy1_3OCd{Dg5Mk>4Ej2_ccxLukH`4RB0$a%)Q#P7}os~JpPFG+I(cYc_zla>1sLr1S zp6nuA@4KBpyOdQP+`P6JC!gX6s;Slto*@VsKw~r$um=(kXdLtv7N z4}C4~3ZA^o`_3n9(&f9!mB zx4Ffn*B>B&_><;K&lA*K-uhzesy{<6$Cp5#KTQV1W(Ncn>9?lM^`G%`3(B;9e)(b_ zB>=aOUFc^0(XE${SC-<3;y%ErBmG#E74_@bIvTsimqU+><%)9+h48dzzz`H7bU1NK|zgUNU> z-{|Tau8}qd*v}aT7*F>m$FRR`hd48j%40la7FEb_D6mv^YnBb{7$T8}%s@N(fOw1> zuK5X4iT=WxIK1zAKAYfX6-a%pA@E`e@KVECP6qpv4~8?rfB<70_hEE|l!R7N9kXlK*za9j zNj%hWsVVW2?80bNbh@}OA?UAIo$&iUc>tiGHS)?^n-Mk#SM@54;I#S z8xNt8akFB+F;&|%d$m49ykxUe?y1AvHgL&iaY&qXe!O(6I0I{P$qIX=e<<^SDA=}n zF$7T4&yQxGH5+SNTjG->NNXTYM9j?z%Lg6t(Puq;`9bV5iLiY}yFY|1-niI|kWCKx z!l8{}lVt7mm|BuSwAJ|0rVI~kHhLdzDF4LX8#kxpUoS~|@#*|`PuD*h!_?6G8JDO} z*J*U%NblYs1MXz z{S95FpHomGE(3GW?iKM1wCNS%B1brcooqdw zu7UjtuT4{jKs9PAap@0M>EmBw?SHdao0uFWy-u~lh^ELO#6d`bl2dU3H>H1t^fPQc zq&nDWGFQ-TF9;5_5zBWJ#K$@U-Y|(C6&PcuO|uINuGM~I*8fNeIB3wr3FJ{o?a%~S zZP4OuAh%jq6iSWZ!mqrX>|cK08>u#?QT3yy}t&ehQz9c3YNMMqzD=q|QloD29ZRtmZP;hjg1 zcJF=jkUz0A2;zHi=ezrl{sSvtdwMzk52u*TKS2RC9n_KP@IeirE`S_(%!aJ1ci1Ly zz_|r-9w880OXdz8 z{IqFfjK0R8=|3VW^2{CVAAN};X4L5i3g(1)R*_})jAQJNVH)L6fyU#`)&-PZ==D=n zECtA_=gdI$!{Okde#6s=T!Hg%P%z|RX9^{UrDPqDWfyfr>Z+aX=*3)(V16>yqq{iK zhl9y|rX=_lUb%3=g_hXw_qiE;f7|~GSr~u9Lj-dc^LWVQk(w;W*Ky;WWzm9mV_Sbh z0*S8sNUwq1Vak_&#Ofl)lOYM2+^uM5evVl&JsAc1$ZLo|b9x;cYTEW{Obpn9J+gle zPDVowRZI*GF^z@&RIOvYquFL*JFO7%dVdPiwL8R7)IvT%RRED%I0M06Xq3;?58y5j zIcACeYQzkHv>q3N%Mra|{j=+ZsVn?oPlF}YlOp)); zGsCZ?TN`bz^@wtk1*zohf+7&)f}`Nq=0++6$Qmq@6MVuw_J6KKQs5!PZ~6g%eDAZZ*si%(}}D&CIoWn_-l*2PN?Z8hIg@tYjdz6;1l>=%HKPNmqm3-|`ELehR5m~2ZD{gTM zk&XAaSbwP5&h>@f@m(PH0_q@%u${Y@aeJHI7aC#BKs36z73dOZ)QL4dvG#-#-n0-V z`eKydHSs^O_{92Ps$<2Dp`2<}u!EZe?Gbk7_$k8f*&y}fWC-=9I0OH%(_u3rY{;t5e-L~{HC;dRaj3uU zIusK9?C26Nl5D^F7*K#)Nlg*-V2s z=B?HtDiz~W3G>`RaxoHoADK{)J#+T_dFr8o?9aIqqcMGW#n~6};cBj8yOY`$roA^$ z=SRa^ycr9Imr%0R9LR#pR|$;ZK?X(1zM&2jP$J7`1_%P9tDAsJ>gcjI0@r=<#;t&Q z9H8C!?DEA{Z&Z7513P040G{^#5P9uDbWu} zb2Tf6pg7EMwueNWQ&L1 z&zk(keP=xlJc3E;1^BI5Uo@8Mp|15~MxoDc=#Pu`+vbM1@@kwN&l#=>;A~!rH;|Al z(%(CPh_|jb@TOF(Rq(a6NONw7(E(Mm*&Vhb|3KgTJbKTNLVB{m8;Xu_VBBECOE$=* z%a^Jtf&-@h@wY9h=(M$*a>%!~>-t~Ux_t}yecJ%CgEO>$fSAWZha5Bnz_uG}4X(_D z-eRv=)lVi#zzAx+kJ>4f3ASX&@`&~A#&DW0KQ`gbpdwR?HX#s$(`Yw!sfC^TpWba) z?r1#ok3|057Mkc^ziUJMkOKHESfe6Yu{qf9%lK_RMkxpL6nP~AZ^q9zKuu=P{(?J; z4M!F-x8}L0W-Z0Hh6$56w z*H$j8wWLsWNm6k~^Ad+-4}LAf!x4$`4^mlXunqjt=ZI$CA(=PTA|7Y+@cIe6BV9l3 zVL=<>Y>=iFQ?{#1yO;Qt^WFiE;baU)e4-AC=6CsYW~v_N4XgPNJF=NL#rIC!7EkvM z6;|K9OFoQ)(I~PA=JIVeNJlnzk9toa|Bvy3t4OEA&?(G2@469`KrLJFnMsLj?(c~<)oCAO{5IQxV0L<1e8fZ1D0P7NO(8G z7;HhQ7pP0Uu$)1ympm&#j2EK~C={0VxYYtPDUd`0A}sH?^FpKnd~KZBl>(uyeyg|H z^tKEL8xF$ zFBjvVX7h)dgMrl(wcZ8i9?b4EO7Es&N-s zIUL3|@5uH)2b{2bc)Tss>3*PQidOx%1*+Vu6rF5eM+OYFsnji=kPlscds%gfi-z`i zsrxyUmW)O)#A5ui>#V|Ca$NbYo~BdS85VOeT}D@8CA!%zw_oh$hA-i(PwG0yAx78v9^NGb|hfU8O^&CkDV{zmG zxP4i7U`$55UVV6+y>7pn|A@@Aj~^Gg1os@h)^`9ROo??kQ z!1C1?IQ?aNtU&;U#VR{vJZmpQHfp^|6BQaHuWb>uaBDhZsC)#g!6VHhP@IUIjCt6F zi_4sI;$jw*x20;2*fYC%m`4>#WoEM#+G5KuPLOa*aSDxb>*4K(tGcOHC0s;hIYdv6 zGM3(t@S3@b=bTd*9TE|EAFq?O?`e8cat8n4ic+CD&ck}aVU1T%4DQdGeR%~ZeB%SE?aKu{q`4@ zD+Y}fo3rBOLN@#rA_+y065LmK8h$h=;4=_y)qS{t9Ir zINg&)iGzBaTtR%FAUgplE`B2y-F^qxtxqg++5y%NYQ?>WYqyd2(!2ZpgIinc4<9H2 zrp0=z_}>r-o6}S7+~kvDfa_g2p6z)VEu7_#iCDJ$5rKHo(*B#-L-+WbQmmribD^kO z+X{rH_$#5919q{UBYoc|v>0cQ6&-Zw8lBlM5d9&TJ$0Gsi;;&D>AhqK>9{|=#hIyH za0u&=W*5@8v|2$FX+@xN7;t{9j_Y;2x7C_@wcRn4;g0DnP5Sm%H5oGrMVoqI4_5e> z;mavjT$T^?`Z3;K{~TKabq&~><_mgd?woqW8N9S=_jb%8k3%xZJOQ^cM5+W zfF{Ch61Ca4ST#>i@hM=FZ@`^1!M{&leDiu;fsg}#X@lg?!?cm)qeksvFk$6%e^xT@ zTc|OC!Q8Z2R6z5165QS`I~S~X5TAgPR2f0-mOhrRj;_4r6f&ON`68$B=E-YBmWN8G z@X1;2R4z;{cT%>#&+CI#a8!i*h(AGjt#6?CUhaV^6AtyMyg~vDFy+I+=vFt{!2@OV z=WrIOQntgjpg!QPPH1ok0rQ?XPa}d%KUZ(St58jY6M@oPa&XEi z-a#`xo< zrNE!>a}P-ZHTRfkz%nSnq8)dYz6LkQp}2lhawJ~|`6>`Hl5g6@MZ2?4KS5Ua<(>ZH ztBbsD7q{&iJ-0yU#<`myh*IAlAG~IH1pi? zf_Kbo?7Z08Kv?7e&maONshu&7_@tu9^hs7z?0uQQCzZwb6I=tut6~oJ8F>(BQ;k^y zuWX#gazZcqLCc|nMPd%M`eJ=oN=#013~8x^w5*9xwlLc-$byUTu_SeRft?KQpmSO^ z?exwv#V2Zrc#kn_`w7_9h9xhVl)?=YL->^28i?R*=_=ZVEj1`Z-UQ9)-S)yuE?e;OU7`g0#r9~uC~D6ag1WHnAVgE07}efj zFoK}~V@EU$Re2bEIWBFETApI*L?8xi3T~m`h1bot`YNSP;gS`d&G}G(B(<%k_=V@pIR@^1cMvlaDk&Y=#lJ0uSc<+VR?xNycD*u! ztvz^zHM8$RuBKt6x~RQ#mc|Dz7&M;sZz{umx$HLm*v(;!jZxFP{p$R{_s5*x&3-mq zp5JxZy4~-1CjNKFGMH<4yTI*e-PI{L^LV1R=Xcp^iw;E*UE||$Q4`u2j@@%^tg*S- z?t<4^MKamNe$2%@A~;m#MBwcjR$`upwH}cJ@CSV7GN-c@J;w=d#&zsA^^ta>LmxT# z&;jNgtes4^c&~li9b!*(_SDB2ly?|W)qcpF@~OB*1OZNijHnlo+yvem30G(kCk~DP z3$pO_W0_&qNT9>H@Q%RA{>COHuk6PGXR3on?M9Sp$HRF%R&|4imx^J>D;<@zJ88gN z^wECP?xLDR=_4v?t!Xj>IL)|V7DfotkE2e`fG3wG1i=N=z&Zb%iSsNDr7`}?Ch{$XXvsB z(SkMzRkny+!fJk;u^e->$$)TL>h0A}2FqEq4dmrDXi^4n*WWgxX)HM3JO(U5jqulO zF_KuRzY=&n_OW;e3RGkWfEhy$hMo?+WHLJb!H-z+#o?UAs8_fAiZJA@m?Raq07QtZ z8r+E{6JTyp9k?^w8*+!|p3(@I#0K1e!{;o;E9{uY=d|N^MURcKvR)d4QhWJ1V+Y`< zyKSkP4o+ex16~AH0E?kJ zXu>?}HfVZ=f!*1Q@iRCF^ftXpI$d@nKjOWUQebdXB$GFDiTGWKnM@Ng^KJ%_AT!QYQ1Y2H3Hn+W4I=7Zo52a|{Wnk0*#{(UVfWY3 z_U7r+wPRL=Ne*SsK z7_rS#PsP_k-_a(vqOjB2ib3k2FddR9;=>pR3E{!__wMzZ&loY+c-H)lgSNz29f0zH zBk^mV`F5PjitXDm#h}0P(_rcC;`WWD|NHUP?d$mWr*v$@?&&QCV!;nj9CEvbqU1g< zT2m7!0!ZfFjq2xAD#~~NS-cFP6fBTb5^V$7fn<%}LUKOYPHGtj%#-9CuW$eI?~ggX z;nK6UrMr)>mXplL#76sW^b3kz?4dgMfwB0=&u}1KjDErE7^worsk=NkOH3%ONqb51 z@ZuIh9-xowS$cUApdmUeTQ$AbL(n2aTzo9&83jHE&tQF@EY=G)AE&K1O?CZys^!S; zH+g9(XD>#3FBK7|%+GiO^VqdiQ@dTbpBpHr-DDG)qlY(TH6?c-lI+s&e|9#mDLc1rc61zylm@>Z+=vT-=k9mLuSonHnMy7)vjD^8G z6&AJ9{?@3Hg@wk@?T0LWvF~v*^WKu*;_kwds|Pf8pDrC7V#;(fCG89+d(TI|;H&=1 z0CCc92ULR>SBfaOy!&<$SjwY7e86B`uG2NoW1JQ4&IJQE0~BqNfrNS5=hQkX&DDGF z^St#A4;d5|EQ*NzNwMGoaRLQ$r#;bmQ~YXmz)60!ib*aG244+sEW!!=`0Cs3pX3Q% z)T7I9KM)Qa3^GFh^F48}sik@^B&Za&<2RX@fWX;~%*qagg#xcvZnfp52jkt@hQIvH zyPfTw$8eeNJYM-efpraJi<5E^bVUdFZEA3O-7)`*g`A*Ftp;242xsJN%9P|a=2v*T}P_~a8j8|oMDxI6Jmwv8nZ^~ zIe9P9YbovvHuIhsb|&6MyCzlU;<=`rri|{dh!v|3*cUGDeKOlF=x`it_+mO)iANXR zl}eL8s+!`I+j8?y(=eeRw2~;+usBArqui<%&Q9;c63vABl-Pt#2o{7 z$^^0EihRyK-1nk7@`o;hgWR4o=W)Xg& z@;=tB7WWKXvW=rgV}#K|BXEXqdI7V%Hh8p;&=g$ei{*zm^k6zY!X<7*KLmpQ8+N2K zRQ4)a(LNh4f!~!K zbjH#>h2seDCHy=*|K|0Y3M#|-$^QoA&GQ-07BY|TCi#etF=yNM8Nzsw{wC%8@;9hd zt5Z;wTv>&eiybdt{@h7FiDf%0W$+YDh`C({d(7M3n&t=vE@s}y8e6^U=sjk{M!5?~ zJD$Hs??!M*i4+>0Uk82YoB7lc0U+z<8EuxE%Wy0(7;QQc0_)i`pd$bxVUSh727yVj z1d8i5c4E&nSF`Sb1I*p97EpRVK?+R(v$a5yLP+^1go-QF06PE;iPWITZu*PirF$dd z38p$~44w=%y#IDMToJ}5#zvf+>@trV_eYj;Z=JU2Ty8pdHVVxtzVDoRpmq&;h%<`!Us$|3Gpp1cE)M+pWMr z?$PkaBt0b|eeBDqc$pO7V7p%DZibP@Yn5Z?rUw2uQJMW@4 z&P?62O7y_M%8;8&SXkpk=qY^Tgqvv6c5+f=ZI>qUsUs)`yl40;NvjGF8h<%qgkfS>MUikl-E2Wvp#_qa^nOR4gZ#g3g2 zEI;xB+VQE`*^C#?Jh5bSd9&M8v^N`kuDdVxnHipTr>|M(`j^6>WSoIP&l72gk-&a~ znABOI?hJCQLIj9b?kHey%_`%YzT5*5`eA|gA(IXeUZEqeLtOdSGvY)m9|;pTfzLe! zx3+cD$hs$Se(^;?oovjqe8yC9T^#<9l+$0a#61LGo3^0M?+d4IEV}>%$%moKI(IG7 zOGKX+-7?)k<^5ESZ~WuSo3@=2TOT36tNx&K<2i(HylMBqOnGk%sjZl|9iq)+dvW0S zz{tGXw(KW=$4%=vj~<+4;Y3BSCa$t@v1GXRhe3aQ=QB?28=Dg@2=#+u{LP#X;ML<^ zBz#7~b(npC6P?hLW$nl$S z^k0nKY5lqS-P<yI zLMRsSG4onCg}G7Werp98`l8m1f4Z3?3DUE-;D5D_Nvzf1l2I1z5(tJ7FzfHOa5?PB z@HygU?4lD^j>hqjR5Y01kX9a^?e(29bIvY#xQajdV)@grZZ3R6KY%9P1zTu!F*QPQ zCQhHvk7;+sM1ujLL}cLGCMV*8^vK3q7f5Usi=n=_45{uAV~ysa7%MAg0}Rt;?ai`@ z$DV5x{j~kl>f@_8@R@zOv)zHI{B3j03P~wI7wWl3!QTTgnthcI!FAAbDw9IK(Ta2vNGmMv{MR2{BJty&7Pxbl7gQbz1)+%Lm2qT= zVk>^o7DQ?5I!El@@Y=!I{3IuUA=StYBdXguVS4H~bO;+v)O%8!3fe?OojHX7*tv|; zO9Mz8Bl>vKB<)5oNAZSxKAJj8;T?m`X)>8@slQSZt!vKflbqoQl7dQGwse)Hgyst@ ze)s2#9;bLT~?VplP~EfjrG=POxkY* zgu6RQ2lel$2tiq6p}7ynvs;#==Zg?*mP0r4SCSt#^e3!Y2zSOlH^#MAS$6|d?U{&D zeX3p`rOdm&@@~>-)y8OpFVB1fc<&;L_}TVkoEBn|&mfFC$D`3_MhLw@G@}u$d@zjU ziZuNMx6MB|CSgFh7%uJR=?5lHY1o{qe5BnV_mK^w_KePU*Qc`BPCGe;j7J)IG|Z!IEq8nq)iVbYOIwHRFj+2FEAC=TG+$K9U?ccZ$NcTG#{kZMLovwpiDXewQ$dP=VeiH9puhbF z3DD^j8HB;z?=HsR+=+?s3!?;(2vZS?a3Js7@R;w=F3VGHO{Yi4>A5zkK|16qk;wGOFE)f~Kr_hxqCJDel%B zS%mZqLBy!Qii;MIAtg3yTgXIApc7js%bzaVA3L+fPgfD3 zYt;%o@^Vy0BSJGb_&uWsn>_`SS)k@FhMU* z_QK@Pq4Lg9Q0OHUPd{!Tc9;#8(mWj(7$xVlq^LnACK)=~;H2avallAL@=t>u3w)b+ zYF}j}rD3Ztj8V6_hI&e%n9XnHC|KbTrzvHAs~RKVdwqgxjwZve^+qRqKI60=P2#Ty zkv>DLNwwrTpq2wMauc$NI5}HMo`WVEnsf>sZ4zIuN?mJ2UGm zhYoBlSh+rg$uRpj)`6Sp$Iz1#TQ7v5_RgY8_1q(SGF?lW93}fF3esZKAj%S?oN+WQ98`Kzqa&u zWXJ68EVY=QaUe+Ve*kSIK`*_lR>war->0=RHJVGd0h1R;Rr_P4G{BheeZFL?C$ttU z4Fj?F?2%QH(m!k?=CT9$W!7R*#*(q<;6YiDk0)SXhRoK0pLPwn^XZ2jv6|1|%;{Ki z(tFLP?)^;I7k&l0a`!wz_z8aTFTTLP=pY|pFg(C2EPt9$6~LBV7@V;XPSn{{>=x(n zo-3%wNf})$7Aba{mQzncOp;P#Co_dGM`y%&QPNiQT@E*G_eHAi?u)1IRR7~Lghp2@ zD>=R<`&h(tx~EAIaP+MTXvChYCn~v*5#`RP1hfw=t(;^NtSz_(pON<8ee~|5FTOf@ zarDtgoN4c4WJRIMLX?K-^?%&hy>)NB-&@50z4_>peg8SW`e4 zD8TvK>G*iG%NwP0Cj`&nUR?#L;Dk_L4SIdt8Nhy^BlO!{e(spy&AB@m37&<~ar)!) zkDAXB>G-_+>CV5-rV~VLpn;WOYBsx#`wD2H?Y(|9noSSj``+0=#m{E5I}EA3Jx0N3 zth zF=n%kqjb*Woo~SG&uQYXp#Y)OCaxl$*VPXQOu!`@JN{qQ=9vdhG>ZRjjt+2PTO0aE zBP{s13zhkeQv*(r^0Ow4`Awpo{OF9vxe-tdB5lp*`;+m(4%f!+V)w3$(9=+9z5V%} zUr;Etn65u&Uo!-?sld^v$S&uIy&pH0u-S26vvvss&OXKeHy^`C!9(W5!&3zMzFs;6 zGbKaCi8D%~@-nS;ON$OCu$}?MdTZFVl~9|6SJvh zR-zypHcK>znWRgMkhK}`ts6xTX*&h%0`dT1VwRbTZaMU}6BtzN{n0Ov2VQ&k)zQ-4 z!C2LI{re@lwtrb!j3Ms9IX}_m-Y`pWDF*93pep)tZ~AH?T+l?(P4zJn7zkO_taocV zeTj0uFS|y=)tj@GK)@0%{8q~qs6j&fC!h50{QKJdjeB=C{Rz#JPkQ$-FW8H=kAZey zFV0Z*OYhZDJVXe<4CbS~xC-ZX*FW=~ceKq-^IvFoHHLU=_dg1b@?UR}&5GMZ#z-#( zS)BRL+a9C=A|YqJw@ioSMrV86HS`D0!boBT5&$4zWwe+8Xwz;s#cU9mIXz+_L7a}W zk%BgVMD_0t#1Rtq_=i*f8QTQ3c>G7rB5?HyC|zVCV-s8(Da#e?f#6hPNn1ZYUnnWb z2@a3ATN*;(I{P8+@m0Ju!Ozaix0r(6h`YJA6)m%}fZ?GnoN5aZq=S*Ox9iK- zum4}5L$KEUG{V|sc<}n~;D7)8m(OCFa;vBp6eKSPj=|DLH?IHXAA85AkT!;4sVSYG zAP}#;>e1hi$78K1FPKwB!FciQ2;sT5+DZANPME+imSOXBkM~-v_BM>u#R4)5-Z&-6 z=Mx0~#>)Dt#9$R2Lu~n;IFphejc`RV*C(h8`v@1Da>I+!zXy#57`LH%2pd5((3_=; z;8NZ*Dc<$ybKrfRQJSbda7#pKk0o3tWKnP%UIUw72YjXwIF7%5^#VoFpN@D^y!+}% zb+qwnkXQ?Q|pwOjwT_U#=M1-X6a-*>-%bdPQa zO61w<%8E_3LnOm~_~=r2lopPlHRH1|7%x$uxrCX1b3A2zR`E`Gx)W=3@c23b}vi z7w^I+j4GhqnNdm}n~UEp_im4#4Nnj3;%DCB<{hZ#6!K>H{pOclR zAG`}eKYSeh4NR^5u(p10?VEdddUx0F+`GNW=X$sGVuaPUnSw22)`)}Lhv9TEd=2t` z`Z^$$kk+-}zQBT0eS9j-#s4gn6@TJ7iT`r3$zOT`0C;5@{x_NWmG;0rJlC1vYZy@&TCs!}wv0vK-#4zG9<3anE**}alc`Q8fq%ZFX};QSBEb2+2ka!> zY_+!rK?3FdS?nH28q;J+Z79)?92H60G#1-Z#zOth`j2=l%yNm3LlEQ`#+8wXjp+zo z?LGM4|L@+5DcladwaNbR|NdVET#n{d02mt7HT~`CS86&Ojt(aiBqf~u?5tyHe+vHd zbEs}@e4P79>b!xU+v+&9{+a20vYd)9((La1jN-8OhbJeQz&Zakv!AaoBWRWXUV1t@ z8TyaUY?`JtrYWaCsCwEDDs;1zrz70doks7N8QJQ4p`!dCb=*LNb62Mi;o(%e7WJx3 z3EypPZS>YQ){AZ~jGesh{F?t;0r$r#*?2EqD1dZFGW!8i2jB^W_iDO_90G(z%VTxP zeRYVDeuY#9vuxoCvX6LLWWG2nbnHfLZpdOFWtX3SbP2w%BxhXl0jI1*O%^8`Nsxd! zxGI6uEEV$6UB=^mn24^MI(#T633C$WGT4}~=1d-}Y&a`9mUnJ8m$VWC14oeF6@(lN zS>xKD_P&MqprEyasAC$;;Ei0az0+e}5`a+h5x6HDLrCQTw()}t=QQPE5)L&=%C03~gd}~r+*^O9`^uoap}6ERxCOQ3x>0oBH~Eu$Q$92N9!_hh z0M!IE%_jPwo$0hxkToC^GP1ELm~KrZQec~pS)#g z-CN-Erg{hK#EWY^yy2>XA*2Oj!)u&=f>+zK1~HbvR*rqmM06&?CBKlJcW{dORG?J1 z#HG6(!{1~4W-wZQzT9o%t$q!S86*ZLO5k&z(7Uji8ZMTE=z_e-Rx9awwwllN;Xl5G zNr$m|oqBd{vBuZQ#yeYq2amjv$(p*osLdK5l*+)bv|6L9G^NTujJFrCTchcF8?NzT zGD0t8xwgK#fax0Fbla}+wr#w|oB7sjv?v!O*<2eY3}WNaenoq2W|Cs(Hn2?;`_J|& z8(*B%Vl6 zjz}D+7xG3xZ|`hTMXxEB#T()hIqK&Dk#{Oe z{_Hvf+C9EU_t9ybrJMBPoz8G3yzi0kT8TFX?p&JP$2pJI$013y2y1}TuOK9MAX05l z@O^_>oQ?Z*OuY*lR39fObzl&JRQyD*p>FoDlGP(3U7&gU=`psVsj3Z91O`i9=2+}t zh-ethjjYk{E&>IW%d-pSzw6C*xvxoD(E=kEzkGI=Fsb|0)@5W+J(h#}DUOTx{W`^p zTNuKnMze1~Vwrug8R%(TT_sUN62ZSbSX{cvUk>2RVL5p*0NwP(5g4XmD!F(x)(Xn} z>F}Tgn+ux9TdoT0u^aTY)FjiGT!H?*>Cx+5O!W8_oZ=&K1#+qaBfxOS=)NLFPsfM& zsQxs@12VrE!JV>?J7~d6e96UC?Py2jT8zobwFfoYg*m{xD+eIDy^$T=El@5RF$TV! z!!L}4?EAcd8n-<{Y*;5)uaaAX9~$r_)u2zZW-yBsdQxvGE>opMrx=jd?y5c%2rk=f z+hKfi^WEW7ou!a5m)IzzUHSM+Zm_*q`(l!}*B{-vwe|4P|FgS!XJhTr8vX>AEW1fF z?@}y&pM6vcUrqP|qM<A@dL7xjj;=A;R?@piowMJs~no+Iz1{)q_TeR8x z?qBMYl}1~glFo-WS$lvIU&Ucp;VHn;C_#_@5@_1(8`w(R>bBW)qo*(_bn%n+G1klX3r%d)(+20cF5BKkWT*YZLSVB~wvSAPaJV z(kcp;-#y<)>C?t$4_&U;XEeOsb@TI{E?hr7J}}L(W0+E?l)N{#^n1*V0--&%lK+3e zsc|q8Uz%ITIP@_W+`wpi7xxT6ZDqivwuk*}?}5DV;tuPUW)ehcHpTuFmLCg-a9d(u zh<}6=*twMXjtji-(yeDu+3hy#ObT$as_G-oonXHkt%V^O!|v8|*aqD@B_SxH|9IQ? zBL5;{Xm-N#vMts=DTZ#JxybwX{030g47{KC;JnHA02XQ9)td8ZJZ98I-hq{p4(83( zNlzppZihHO}|2 zzscJb-@!i^9D&pfsAXagSdUYhWH=Z>pIEgm*rPPCC>*$SKFSEy*BHZTHAZR$gc&{0 z5PUJ(M;AdNQl0wWU(na>JFos2Zq|_7U`$vBX}w(hOw#ru;{u>pbUeqtiGf}r^i$Hc z+rXhh7)@|U2ch`x@dXqs7I6Vyhh<%G)pP&iAq{#We&*a6Odop}Yk;hSrW zZU(q5S8os$jCJLWi&$422)*HS-YqVp#ye<{Ub`4c`lh?;fSdBPl%X|whH=K{47WIT z>o^1ZGbkp-e)!3PP7Q#mKQ1W7Pwh4Er*ROhyX9GgGqFdUl`>17(l0GnlO}nvovi;wL>uH3a-_I2;eIFj-(VqOX)l1F+Zdx>tEo>>D67DBhbx8HD)DGDjs zN9HFhR3n540mKmY^4!yyDD?x=fsy)yx(BZNHur*@RG>Hb{XLt({W0g$S0y0|c|`(i z>!8*k$V1n{#j=BACKC9c6>IU&{|Jj37Jmx7?IGsUvjlEj|ECM22?P$(XP{T>!YMk=|7|hhj(Y=g&xS#$tk`-5FOR2{jqsanT^UV<1=%oF0aM%Z zG=JxxrtW{4savovdiXoc)HaLwKfy%Jn=OpIsOVDo)WWd5E0dp^MFUyqn3d6WLq4R; zo%!*$9a@ViEn?Yob(WMA^uBT=fz+uuCpqyUvx$P8{yynM(K}86&deu@b}6{6Goc8r zy7+NmEh{bL%+#y1j?fi^^SLO8LZP%e6RmYe>eF%!v zqqB48uJCZD7|FfRc{o4JgFBBQ0n~?iPI2+$!(V@LSbVv3laW|IkKiJH0H4?VvpVyt z{R;0~H5g`DyXF5&bQKI*`{jcU<&pOvAdU5KPS@^kt2y!i6IXXd-I=JvWDGl!xxjQZ zAPzHgOgPI_9R-OL>Ci|n;QtaAHCFY)uIMg49`d*l^}mAL6F2egt;3|mLz+xbn-BRV z7xF^~fVIMKOSh2YTmu#(?g9#H&Kw{``Vyo+?*EE)Rpgl@H}YH#M~66#n!P|03rrkPDavRM+ToXqAtLUEn8xP z+g6!_hXlz!vb6e=T=IsbX!E*f>jywJdg%&KwShFR{~9{R1gk@L1_ksyBR! zxKkcp9W&q&%!}?Q_jN2`kM^Vp@opFI2EDJl-(eXo zPz7H*8F@{ib6C6L=p_3}CyuBH9vt@zCejV^FV18f%mDTh=b9!SmFH!+X zc8vx(>V@ILb^_OK6~3*cS1RbD(N)&-TKfvP^L+(~s1TifHs0iQ-6x8QDb@*j?CLh) z9b32b!fN9iyz%)SklP?-h^J003pDWpoxbPjpZj)RKUhp)1s&XSE|A-@Nf%Kx7D9fV zpoQvPCWDWI8yi=Ql?Rlp(}gu=d>Irl{P3mpS4%e!N5=?gE#uw$_LX9jsxbI60E^dR z@HjtW;aTEAUw|pNVQ@Bg>@C`-z|^HnEa8U#B%rXR4ca)-kNCLyX@_G=$~?Ec^P21t z%W>>RK!FtF@p)MS7deP&Zt%)A;k8f;h3#su%sGGmwVS1}{*{NB;UB080QL>^kwtl9 zC4!2gzcw+>+IwL0#P$hdsLNN0TlKtcdeB9wjkBZZ5E^m}-8d%_ElXMJ>zpZAm*7ZL z8ywzi9#qK~9^Oc5xzzVV+rCi}#G(o+#ZU9f)W71~)}Csm%22z=oc@h)6=%CK{8^wH z7?{$6&z!LydFS;F587Q(t{0_%X=OGrWm~Fmr7zUJuPoI*`qm)jp`8z5Hw;2^im@9@ zCMJVoj8GT?D0PKFRBIyZTu^UjY30*mD&iT|wo`=oQXti&ums+jzuq=_Q-#`cm|_O) zPs-(QeR(^Vqj2!r9R#uP<6^~G|5;=Ko%!JOa5CuG1-z))S;Dqv6~>eXLR7+WYesy> z>|)DsB%`>xuLe3(Kko6wx!VNlS!9>k)7WF^lGVkzQ_tJ-fXq+4(rE>PF86osVcReO zjkcu=CoFx)D9cBUj*)`le~JX}LUC$Nj+ca0nCxm42ZjJSBOyh2_IyBG;sN--9(Qt(P$No_t});zg=yQI27Y@e+sdA52l- zaeNF8uOjdEJrd**;Q;e2rHMe1M!Ah^ilF@F7Cb^jBrMDzdl4}}3lz%qgdvItsF4YK zoQgQr@4YFiZ!i;5)#kn(pL}=vlqDU`G`)i;FPc%Kb%cRyP7x04Js8k7J!CaN&qs{J zl&QL^hk+b2$Q)`zEHm@-Sg{mf@71PP_JTW$t zB~;;3X%Sz!g5x~6yV0tvDw>3-FcLE6j7xJ+jNZw|G#!0T-rfecfvC(6j*-|QjNckU z@fic_8|Hc>t<2*F;|cG59u{Q~)P=DDNQiEz1EB$X7nqg)TQH8aQQCc@;6q#Tl<|4N zJX{D-gFKT}x1pbVHpn%|xXcvQ>f$VHR{RLer&if6%v%$Rx_F6+5s+3XNr(xSf&LlN zcwcVz1IWOA$m)panu{mpR^3Ql^W8YNCzMM|pxxoR`&pRNy4eig?Ok;ftk9A-oM}6?3rHz8UR39~F$*{av9@ zGVC%w7Pj6i6JL8jF;eBGld~28A!x9ff=%4j3l!!|DinYRT~$!TJ;k}Id{92dUJjKr z`1&p!*F%6)WxaJV;PioY6zqX;8r5XpnwqljWWuJgTl31eDL+uppJ6U#VDYlLX#P=d4v8eCVD1AZH@Q2=z&f1uB5Fy|Akf<7z4 zjP~Jse1rKoafjdXE*8J3PId^l08=Yrwsn~^bZLQZ zXV6&c^1Fxk?|7hEB3ov>7L5u0^xV|fBVt; z4;%zcqZ*gzU1@A7@8}?AphWFR~V%;bS0n(sZz<l(VJ?j9bEN620&miJjpnnOYV(w8Me$+~ z`(~(-F^AUu}di>`4wRekOvAUEK`VV&=u?P}4h}VWPcbLyEoS0EJ>N?#EU!}IZt_L@`k%&v4 zbBmb@tU>6AttShM^#w~yp;Qd3@8SsCRSvBhQNjO(uRbJg(1xwWk1F5W7Tw-+Ng3?Q zXG8VjE#`fP6|NdMPpszsXu^0%CIZkZHUz27t4~#Mcby+|4@gja4E4(^t)!3GT@pYk zw)l9e>gp+N)t1uzIB>=8?j7!fl^wq1=SxSZ2SC4ivr|M%rMyaR!HWT5W0h6H+4CC1jDp}KxHiz zMPLH~60?X?6O|FrTfUxi4yV%}9esf95VEM56)x>!zMQQGvpRJ88hTtR5^d)u>!H(g zLpHn!EFr7H+ZEnI4a$&0Io~&HwNA;ZD>-wH%Q0d`_*9U3)yz3~G-8z1i=!XxFso|F zn5x_ge=T73rpFJFK+ks8*5|)r9*P9vTWWc1(WTFJ9=kMqNOQcFCzd7z_L+gEtPH@w zBxHHI2?Q;MgUQ6M)18Y3^`L5gtykPcwz`_W0*^L>(e@Xy^%SvS2@nFDCLUt;tSR6G ziv<^SygW!iw)*rPB=n`h+)qj%aN`iTq%RQ{45S&un`aqY0&->$rnq|Y_B!FD1#Z_A z6HCqhxfkR1F5YGz}>AEi5Y}@Pqqa~GIk2jiJPHNl^?*>^lJ6a7ZpHI@ko+QrVQKL69J>Itnzlf! zj5#7Xu46N9T4{#ZK9|_=)wV!e9A4lg%rzn0+LoAa9cmNbY#1-LqV|kbV-Rogm4hVq z4#gc>`*G!iwCv{gm|d(KDl(w!EW_&*;G^|xl1ns?%14v!{$e3p%41seE%Q+0p|mZZq{ys@kTdCe|dR@U4tcjo?33+dbGZ= zwaXyX6heWh=VvDarV9VerZp6)Yr%0aeyToKq)ss_7J=_}-6x0IDITw`!n(wXBFl54 zQ@cIrJDjQ^a1A9HQCs9Aifwq2PplsB!Y&I_+f}{gQ~Zq>V05A8jY}bRVSamr;{cw7 z8IInpUpDp~t$wkAb?cDof0_*wI}bws#M@{xfzCRyhRA~vYIFCwu1zRC~}LLyn7aZ|RBdo&2^;P$>qnk66WMvOmC(f*ml$;9O;agMUGzi5R>W zI2eH1mR|X(2QKxE55<|jvu1vFG^XahV4s#KWB+8<3uy3V?|SnUU+)0U9bSAp=wJEv z&8qeB?#cw@PCkqpsDr*e)W+Z^wIqSc0)L+5e@6dUf<3wrhk^q7==aM}y-E&xfIz3sA4 zKX>gXqA740DE0|;j*^!6HP^iGR`pkY8hm$W?e<#~j()rGa1;Ofe(UY+JNNEv-C67n zb~djr+FjZh6ieiODCuVGt^CKgRAa}6=jz7e{Q350j|==p9~Yt*k*p8^&a(42RNH=2 zkrz8t5Jr>gVw6|~tb^H(d;yVfoYeMl!CNgD4i#84WAA+hvb^!xKQH4F!Q~sP|8l+W zlZjrEW5-QSps_3m93X1}aqchx0qsn#Jh}{8YQ?vMysqFa=@Afrb9a`i<+=XNSGGYqt7MH(!1oAoqHVErA?*_3G8~6gNcMY;_5qx0$Wr z2Dl~vLHXL-LO2KKeb44?>H<$EaceX%1)hh^%s75>KS=UZ-e5S}S@XZ_7UBBcccX)& zP53QGldiXZq!br@VCyZHzQ zHAnDi;lRWEWsGwVR7B*PLfK-t<=zhf0v`0psA47+DEbNH;lWYgj!vHR4PE^w*H9b~ zB4OC03O*XL=BK+;(g)ahPsr?_6nF1kLx0f)ccwWy^4)y7oA4WHRl&{zE)*+i&xr0} zYCnOq@YQxZ1;iP zpZgFKHx|(zq{jhVO$*wJ0k`|so67NcBP1wniarOqm7|a12E9>uxI4rFNAx7UCH?FY zu>n!%(#*)*RWt;NCOf~`nfKb&-9sal0=C@Py99$zgbvkF1g?NlkYi9DZ_fjRj$6pg zY}qgB$)1-j)>vhj^lQQ6pv`bmiKUNyW{!T_oXI0&PxUanU24M@$3(uLIjg2tk5Mzv z^kMybYTd;|knGybVasU`H(y!F;(tWf*v%@bih_-#Wp5r-QQtkDjZ+-E3bEquE-!Hz&(7HfUri`>INTt zdiK}SO(@kyxgZ+Hv2AR;h+7G~F?7G0lo~4<nS zjm!RqLuyviu$=Q%v!0kmc_|j&!zlZdt() zDEWXp_LOsL@U=u#O$LVx6QCZcN^)=DT1=v)#fZue;!*|4xk#cQWp=;uV>&wFzJQL+ zvoI=Ze6I?Qr8;JfO}GWghPH!w@Z*_yr#%G8r>9BZVaLud{bj%a`I(Mt30nCRG>fBi z1U9^4Kr1d0ri$0-My^#DKA~fZ=}7${-V z2MonWB>tv~=Ny`S&9>E1V$Z=-SZ81$eX@?InZaE^)1Kd|>kyXu(8j`mX{xZemRLLI$Q3SZ85&SN7GjNKYZm*`# zUVZf7SD3OahIWN%@7Es2ih=T( z7|Vn$O5PDbf;YhgmVAr2iZ@QR?^=w>H;NXh!9;8V*e&?jq-8nvv$qG-EPZY~J3DI~ zDF_qP)aafKuwB>keKUdU0rs|a6I7l|A|tm4(*}Y}^Q21(6n`oE)bNALluW95d)SHp z+(nkPY$i-^;H*6O|9c7q@8t}UU@d+ZpiV9Ux=mOnMkpOt6_gU)1L$Y&fY_~TI5$Pek)7?S=qRQayVhG z67bZj^cAAbEB|`aOJ1ZDv-&T+Dh>cNVFwW>QsGw4!}6X4 zR9AdXV;7FHJy;P>O``x)JRYM&lq(tnU@e?qx&^Zd#9*-i!~Hd;tRt{V*um8J>c)J9nYIx&oJ+tETsz<->UT zSLpMmADXZ;P0^k#-ITS*7t-k3ek8VTS}Be7D4V37vW{AsJ4!)495Vi7E_;h)R88$# zlo06>0jkrBnE6);lR~bWWV4nW#l$k?@L6~1;4dsG12O&WsRtd zrk4dI%tc~$=$nSt3%V7a&@nOH{1R0WI==ka@`hvEssnQ1(nxyL@E3CvHay1Ua+Wnj z{M#m(OZvh6dLM@TxgFkP3y>epF@?s$kRqaVj#}Y(pqNM%NHKczr6`(T9C5@m#Zt0~ z=ORljKMbNi6p|3TXpWzfRV2FRMra_2a{z8Kz501g5WQ~RQ1pl*@KRUXIGgjKa7fjl zN^xV9?35nC6Q36iVDVta+Xx;-8<-pKZcz zvm;oSbKhn&ESE9C7N7Q(@5QO@o8OmL$Ap3`IRi{V|LfwYU;qzI)$ZoTK2N9H4u0JE zb%P^&Cr#>qf1Vs$WiF?A54LPTou`+4NXBfaDtK)v{(?0ZjHlJUiNFmWjW)tEq<4l} z&qbW$-`s&lA;rN|x_!!Q1%}FuOr@icw2DFpQz&*i4K<K9M+>=J_G#r{h=-$am&fO3%^#Q~BG`O9r z$2&#A;1!R?6)2QWZRAWfIS`E*CjI)hCDbYl1cS8rh4o0YHD+c^P~P?ENg&;Ypebm? zn>GE4*wx~n&bahtn_fg*G{f+ZKan6o&3(?yh-vMZ*{cl}!-I$^+L_&{y$_ zC=0n$K@b*8rkYoEX{3u%&0`j8g01~CvM6b0ie|gQ^LHD|FO>W8rztuxXE>m>2ua1x z8um60Xq2kmSKy7zk7n<_y(Nq6?=GtWVa@AS2_0f8bCD!XKV__>e@i#S)qZ(ev3_`0g8B_?X)A4zcla}pUQq?vA^q% zL#~_?Rih0KyKV@iqEdc$%P$pPlfd^mG2{l%q)l`qEf|pzqhX{*TBF5TNCVw&jD|0J zLk6YO&BGe&2&={Z1?@tA!5)so*or5LIeyR-vpn1yf?1RB*hNd0}aO_+*SzwXfzOFIM;eKCxhC9z8g_XZf zsgxi9#{5#lXY{8WOs7ZmQV|aVA9aWd&A(T5sOaB=K|NBJ251FfnV|SR|43EB#%Y6`e zO{r7HedEH9=`H%?usxIZ+V+<1@>U|tM$J695Gx?k)Keo*+1EcPt=WvbQK|^G$alQt z9nd}15k`nnt4GScMOtPKFt_1k@9-$nWBa?v54sT|&j(Dqr#YfCqFNdK*hWc_kKB3K zPP9jUb-&OpR7o{3D-=YhocCEEqLARhE)1yST^3gvcwbCROnmDMl$u11%z;#%W%qPK zY%~|r)98U%3S?(5t=>xt!I~8;ypBd|;@c68RsM79Gi1~AS>O)%y%S(IPY`5wh@6#R zwp-ZePaaH9#?M|qalQb}owhk{0m5Hy`#i&~87eO;*1e);9{W@rkj`;y>b2ep}Ir4T^?u65bDZq z@Cp7ONk}@PL!2Q_5>uQZBL0xEW0$%;14dsW*ao7QM%v5K=!nqGkhP48UK1Q-5+G^}LC*@x(0vYvzl;y<3>=rXby;Y?_T@KOCkr1P=~(uLy@P7?b~iVW&y~mGlC&v=z!$IJbBMkg$Uad{?%BQc;JLwg^fkwPk5qXgtNMei-KO_ z1l;#n^=bhJx`w?cB5mJtbXdq~@paIm{jwG0IT5m-km~@|6$x7QZZ@)1yLwc+0WZe;=mh8`iT*ycZpZAhYnxn@PgXUwMvU%v+mSQ#eL!0Exsm@$l0 z(dVu@BbS*4{H9pIdWWTTZEUafT-(JJijoerW%BcK=^w@MA!wYOW_ZGi>Rc|Q48lGr z_Ks^Zv3a;-=6=y}zVCCXz43@k#0_t|)=yGEyeUO>3G1!l!QSbC_Bkn$vx3+k9x)kV zh8Si%Dt4+8WeiiC4!Af8!3f2tLb_HYY4oBlv0}bq^+m^2ytz-MvT3vguCw?ka$Im8 zxM|v<1!n~C_^yE{0iC z{k$!@O&TNqCR22?H6hrRVgg^omtfC($Y|wSNY~V+LGtc|-?0VP2i@>F2LOC{cN5yZ zwkb+p2mDvBvJG~k4~mcNLCmO0+`W}z_KW<*zWI&dbJ{V4;Ay!JwsaTY&^CY|G7m^5 zTxlM*si3x;$S2@zPAZX>--h7cF*icEhSAOa`>UIq+TF#bG0v+!gK1*#kpt)t!BC72 zp<#pT>y%P9k8_|a_Arlptg9_9lEyXMJA$5prykpL;P9Uy8c`5rm3~o-22Ur7VhF@5 zc!#nN*GOfXTaQqe<@WBqJ9oF5Jm#*+0NyoeBHuNMguP8GcnLSM3p-OA%gqHvQ3!^T z#&aU4?8%Hi6-Aeo2E#wu0kdwV(4}%IF5_}Xq#-$KJYc(DX)Z`gUHa? zjXA`Wni(_pzClF!#ZxO?)Pb4Q2IWU$F4(=kLu2!YAcc!KH*0LG+o&6S3|$;*BrdDO zOe|%_5gLaHSa@fbJYj`4&>QaI3Xy&4&nHtMfy5I!4OpWxii)W_W-We)6@xkn0pAookYtv0IU4$TLndaX0c(nElRR&8=vofw{&=fx_Um&d1A<*kOBs^e7G~ zD&|Q`E@`bo`5{uF!q~J;FVpd^^7P>y&2*K?TMO;^Bcae&>xU_hCezdBkh|oSG}=tF zbybB#0#_K6N^F;cI!Z2^2NthAV`KEbZgQ0Lt=;w5Zcr16=F{pVn8`f0MA*;TcNvJh z>p&GwZNAVoAimm(YgIfhG~EQ3Q52-(pUxcYC;-7s(r$u!cIFL0aOfRrs z)agQImsu=_BlZQU;SF%l7Y1aUMhY4M@0#onkM|Qu!EIrb!89NS>urQbD<37p(OlOt zF_f0#^~9)=k`3LahvZ~>f=jeroef)3{tEbx++mUW3)a(O2GC?ET|S(vtVF`LR3Nt432Kt`B0ghRK=NjB8^o_!Q$@1RF8(FrKJsby? zaz1-(j$%btv8tT-tU&K6Ku$Tcq7(2lTKFAE&Y zHJA6I7OzfSarHHr5;=%jXk^3Gh++UxY2ica+UedqA?u*LG!-Mc8P5xK*am1r@AMv| zX=cD=_r)TlZs=Y>AI%N@sM`ak?TPAvRtA$>&OCRfDCM!lnQJ5%#ph2t=H_r~X5Lq~ zD@+ZWAU7Ogg%lLjQaFtvl@=YB949d53DPtQK<5Q8idk`b%|Wuf2=6vWWUQJd&cQra zN-pyFS4i*TOa+WmL|BYKjrm~o?8Ir9vvSc>%V!7+I>6?sxXDj9hr-f`VI+mKCPaaC z&Mircr3LS_X z8>*Kdz7X5C&4_ZoX{{<jR}2J-uZAmSn^s2B}aow zE(CDd`zD}>$k>+gU1NspVZ%dP{6D}SL5n;wGouKwDYtY3i&qPu#avdPrFR_}5rm-y zS6(NlPWa3~5mG&xO11fbJC@lS`bOby2q=x*ig+&{#X|9D>-mH9Ma&DNA2z+@qDUbO zxsMp^0JmVOqiEW<+l8RE@>GzLonB=s3SYv%cl+V@Tj&jv-^&cVTFFBebUA|~uiPW#q zkziJ@i#EtZ+BK@+9BwXA%j{2sEu_~XS)&kLnGW@`sVmV4)^BrV4 z^h1aYT&pVs#6&(0)z{(M_yyrSy%}aQ1lNz4cI{dB7b+-?{OAdfC7&46!B1Bl!nm;R zp*qM)dot5$SE;82ZEiW%a z6nY+03w@NJ^bbA9VWG_+Q0u+stcs;6@K}a)5?Ww8vg<-{8Gdpv1ma zbk`U5u$G~>Q0M)41_>{RyM94?1I2%ZI<@u+*UV3k`7oxlsz12XNXdjAq{_v&bHG5R zpr_|HN?QJvCWY#DV)>i|ePSqIm^LUUSAmKF0x%5|L}0_=Y}ork+{kFAOPy8F8H9Dp z2r_9EX*R8iIzBELif}*Im#J+ra{RNxEZn&4>7ltPxkvN+~ra*T@j zWlHe&0n#+C*m`5Enjhc@i6y`7Bm7r;#Q;z94H|5%+C|8-mw>%&+VW7CI(;&WVqPif1;Un1dRAZG0&hiKbYM0|4wBa?~fz zm3>7zS=)!ez;5RpwG7gbrql0Jg1eqAejZ`Ee ztaO9*r7I+|4Zbmir|${T^n`0ep7LtEZ#FZ3%uvdWi8Z7`agta>ItKw;yZFPIsD};h zwlo|xQ#%?Bznhm={6M0lMz}-UbiH*Tn>IH52o=s_UtJK%+)=h5T09^`hP(FLHFK+O z60PuROb<>EC(Nsl%RP#fVR#ZYLMee`>zGn8WV#zqKbdjGC5Q33iBO>@A}=lu=~~-D ztYv??rwnr$OU0H6+mq0qLybCXHO7JB^1MQmGzqp`Q5xltj@)?o$5U16lQet$q=+$w zHU*McgfR}EPT}-Icg9gYo);0%xT#;Wckaua3IzpHU?%`aqJ88 zE9lMt9r+cmQ^i&VhHcZ?S#`K1s{dwMp{tCfl^m_LCih|4-F$_ORsH|R5K;%*1^jc_ zuB!xoUr*lB7T{v#{VbLcqHz5IT-K)Cr-UD<=rRrK=?UQ@GCbP zYlHR%Ki%fG;B`QIBP&pVS8_`i<$aAmLKxatt0Vg8vAi&L`B1Btzp z*G>EKf4QgOnPkPZd+))1QEN$;oIz5P?!^FpBC2rYnog}Hvf zMw(g4{coojbC$4W*gTvpxCu(z5DYeil)GPLTFFcf(uP!4?8)6=qacvY$L* ziPCoPnJD;P;8p#FIwx>YZImHUMQLJ!BIP6Ya{`hIeT*-xow>Q$J^i#E0a1Yv8=Otj zCht8Iivvq}-6Op-xas{iIe9_3BlAg)uyCF#WNQw3iWy_m#C+49b%a4z@_U-dqH3}h z!N-U29{}NSW>x(%MS4-$+0}kXBln>3^n1#qP9VV6d(2C(&2rXVNdsex&ISq%wde>U z+1A+hXY6-tY`RGuO2TJ*;=EFaRhWQVl0jpY3pO2VY@ zO#)IVk3yS>#i!F5yT9uNUg+{ijqqa&{XOK=C#INB;YKhuMG&7 z@hO99VcHH&w`46%uqOyfSX`F9;L)>~Cy1Q-xg~U)`^)-`(2wLK-^VHDgu1?&$zI;a z$JQ2uQ_Zr#Aoyqm4tq~_anQCY@R*Whr!FlvWdlNxLajYSDQ{y2sraQHCe?tmaky!( zR8rZ1K}Uf{=_ts;L)@GlIAlhGUc0|N8K1C}zX1_mX4e5Mm?OagG$VswN?BrX9n7c# z0I)+?AX6ZXAB>6g(>z`;#D3NVXs4dTzDNbw*+OWhcfoyESs5g(n~cD^EJ*|3&aQZsfx%a7UU?hPnVX&AH=l+t3biF`YjNelowk_ zza^adRJ0`;Flq2b>ru9eD@5XF2qxp?5oP zTw_&fjo5_>EfeFVb|p^f<{W7%rV~3jkKr3D=w=>=M9?7JxarCztSwWa8AJ~g3RRvI zp{1hq0C#$p09UJXq!phxTU9y^Mszwv69L|4A2 z4U$0etv|=r5W6k<5&?hg`-{7aaKti1v_h_J1*nTT7QrRsl55<| zVuYr$72NUWAlF}uTsP+Q32#23XClC2+Uhbqlo6cbQSg7>nfg25nJPbBzU0&>ytwsL zHyG`#&GyFQ+{zw4(%Bv>1#p#lu4T`+hEI`0TwIV!kI@r6Js1^5D8y^9vt7mN?c=f} z_`9Gzq8EOjPC{v~S!j~_pdSx}oo-LJBSwNzJ+^zOtGZ0p`)5;h0k2CGYoR18yS1~& zd2bQ!U45E8>+6&H($i|nRMqjnzaWj;E_t%-cBL)AvIEo7tR-bk(%e8qP4ntg z?5(f@sGyn?Tjn;8uO$-r+|KuUjuq<;ESIjaVehl0q~#--!t`?JRs7C_gW4Txy@&== zr+c4uz=o78BxiBqA&3o7EHTt_{N`j?l?|$aYdwhDPH>qeBYQJunAps z=34%zn*FCt1+#hulqwoum=?+TybKX8%zX-f@hQO7@PZPKqmZo6Sg{T!L$VAa`Ge^KrSw$2O^sjlAzTOOk2wU zjo1k0BHaYx_wM=*5L(UxB+JAIe}f?5CEPgMz_s!QUz%VT8~#{;Hl76t_BiAw!hbzG z(y25OBjJL;K?;v-xaR5*D6=Cfz@0`$oC}wWjSyqvWnl1&Ryhxbm2HU6)2671z-)I& zD}xxKIHw!Hui^8E!6>xwRO5uj#2@t))SMHxj;SUv!L4e+SL90{t<~*Q`4JtW)chG3l$5IKXlqbMGqsQ`g1@08P7Jx zM~of!S>(?{bPTBOZ5h8uGtQ(szVr1LRo4}NGc^}4!))OUFs<@{XEQGR49R7zK)K+F6_68(8#)uv&fW<$ zKyywX8#{3PNa4mFAV)Bh$5{!z4bBTwFV=tgMwo3s_7&ob4qi|$PXaK(XKNqWPf&w; zo!1dC)= zyLd!UHzwLxy@yumi#*uS3>7cM3Y{|W*0LYWzfy=xaCnQxGbw)r&Oy?%R*1VN#o43~29oDC) zGJw}ydm|u-6KY}OohC=?rBViV*oU=e>;fihyDoPTZa(axgVE}$K|u16veU7hTp{+r zb0;b+z7YoOM|TF_V;u#wBB9A=%sAeYQOQkH54{Q0?wt4z;!*y&RAfu9YL1%LrMief&oRCq8mCT|3t`V*gRkl`&j)0q|ka})>KKaZ!U2%!>RrZ0t8 zuXA2zo$~ovlj8-(o!%ELJ-$6-%He;QBTlh`k1%#DAK_?EIe5L9Gg;WMbyLb1Vtmv< z3ppzZxM_WStJI`++?oQ< ze67(kH3Y6BfQuX#V{s8}=hGpT36is~#%SGU>>bVMX`ocV(Twp_W2as(P^U~B2v5fd z(mREFEyimO(I9P2S*1EQN+Vz%g=3H|ivg2>r^XTGN28P+Ee%QjxFIS$g7OU8wshSp zSOrpVp)m>;H7Fwj7}n{zOBiY{DZbCk`4vgp^hRUll%Zkz+$xcbMbu7p%sG{DW$dC) zO!O7f5l0pIz`|Bs8TM+|8si&o-`0B3DyhKy+=?P9KBRl;;Qr`bx#q8d&N?Y@P#&OJ}*WeMGC=P;qSSGzMj%WVo*AVa%7>~1) z)BW*uwv5sUH&ugZZ+i3^N)cjpKf8Y8dhcJE2#pIHp3nAixH|AM-Ou4Ke0mK1V0n7{ zd{N*1{-wPA+-nOo_+$$uuP=6Df`&^6V+4+w9cmS({mcaKAnfGnD9<;-H2S>tMlR*z z;6n`rmpMzoq)o;}7Y+Xv1`Nka@~_xV#xdY1d7s|PhZTMrcUG1Cq%n$j;$U4b?jxj> z$Kw8OMgMJzFYwYw;cu)#PChF#N5O=DHTM~SasOc z{dW0-Px|+UPe%tx?7i7*z0>o%u=MW17+271X-)*!B z-GlA1d+<*iWqe0;@xSv>WlLeQnY7GP8Ru}Qy9y?bP&J)_1s)UF-pby-r8oafxNXhg zm#JZ$%T2v~EWhSCZxZga(JY)c;LyT!&V(o#mJN`UtKj1X)M@1Z87#YGxnSA*2qJy< zb;WW2TXX82NOb3A3p{k9JK(-uxq>Io#UG8JGI)$QlvuCfK)0sfJ0)TUS7!bObEgpY z3k?w&nTVcYV#a~FF%iK7lf#ZA;huS}+)3TN2%1l)-nTdKA_cyz^JHUz=xHnas+IS{1KB=SRC3&>Uh zknzW7+3Hk?_$TRY~G=P=L?6hqM*w9F2K`ZhiP} zfHDC4#&oSCUK?nUr&6dO2WJSKAi*aBZPpp6DtG|@e;S>~lA7Zg9bgESM;FRXhU z>f>V=Uen7Nf(`wG3y^h%r5EhqA?0qCj?LGK`ZvBe$0S} z-`SJVsUHW|C@v^VkEHaX+8Ioui67ICjtk}XJLtrl_7;R&Ix_5n-4`@ zgQa1!o?C-P#tJ<>+7Vq%5Mzfnni_tZjj7!<=hOJm#)uJdo}Ce5d?_3QzN!850&z<> z5iwxhP^y!cdD~~Yz1y7%D56D1P`*RqW2~rL4k%$ImT)e-G11=)adgyxd8!O@(xSmt zLv3#_1a}aIVUdO;`Ybtn$)fo>vuFD>qx90H^V&8hITE1xLB;W^>2J58DZ)$&znDi+q4ts z0GTE`2TWhWiva3fT>wBS6EPM6dS@K%<~ zn-v#KWAa|%zzFiv0*i~K>UX&NWPr<&4IxN9{ELCEv_gPF2xF5Xo2CVIH(c0R3vV#Y zyM;IG;N4}RL;Im?-zGF^>~h;Qw(A+2H8EkQ5vL}sB*0fa=4Mq0Nx#3j+ zyFY`n6qpeB7|;Oaezp&M1#_QyG32Tm&H9hkzkUVcN;an6Y1gV(YgS-R7vqu*8&;w< zKCm?-+2Sq!O=pHI1GQm#IUaf=Ml@MZ3LFa{IZlar!3Df1z{mxD8NUw?FImkRXnF z(Q3_#JYaIha~enn>v8V$=M7AM$QgX6<(f}+>`?t4QrM7m;MWtyIScQI_M858*5S3{ zz1g<6<3z+_nhK3P5ghO6MPi&w(jdcyUC0>T8xrPgbYzaDxc)isr0S?PlKc_(6fA-~ zi#0>y9UH-&xd8!lMD7B+cQtrs}$ zjc%~dacudwotu1@BR0m{7>!=`hK$i9F34j1E^1&xaj_7~VC~_XBWwtHZ37kTWe!-l z-r{8q6EmLTqhyi@C06iRY$&jDA9Y9toDEO!KdbG4iJ-m$3N0Y8>=|z#g>My3-m!(k zbuf3%&B2iRYip)Yn%P;dg1VkqL1SM3fCsh}O4I3vAk-Uh&*nTdA%<%XhH%hUBPfK1 z_CsUUgpW275E5`L&Q7do0aHL#4V>B}CT4<#?IXG?rUH7Hdsox(=oR2{ zfCExf+J&(KySv(>u7pO@a+4>4X)UqGBkl@V??60uZE;ND6oGk4%1g_Jx*}nT2nk;g z?)x^;p5gd+nka=_rc!aJFOpa{-o$yA!hGWtNxulg3JUe@g{nQE7Y7Sv20E@}^s>uV zk3~n-fCi^x=)qU4gS1a4ZZmNY8MaN~PcKRa1wCEu0CT7-!Jlw(={%Qy2i|#LZh945 z7%{E)#x}mKiNAqs)Tv>$y#~e|;UOfluHuBK#Y+^&;x@=-E!mDC$njR9M+amHF-EM8 zm-N)#@fI{3qnu6-ags6Uli$f!>Q<)Gw*rxyCC-$@qnB>xlNsMQu4olI11pyezykQC zn{iMe6Yyw^vX=Gk3yN^-&svZYwB7zZ7x*L21z?ekpD|7(f@U80gZRCPs3;WfK?^s_ z*6c1x=v!vhr1GdTz;JX1o`P_h@pK;=Opb=RJw=paXlOQw>0-HZ#6Fr}`3uu)7nH?3 zJ~*}BtfCVAyEm(B^bUo4-mLmfRPV0g&JtZ?^=@Uh$ikLo2jDJt-Fj)f=|0MI9i@Ol z{0(zuymDH>qAgO=bR8Iaycog$p@wvV36ULoU|8rZ;`-L@$aIvbWUu@qe80eHqhs)73(iTuU<)6P5qulhlsz4tyrSH-Tbxa=JpUHOIr>3) z%0g_={l~d{+4~Ebc|Zi_jq8xbR)9gMCKtYqa@V`lb<66TOIKyAsl^x2!JVHJHF+A= zey#@GzYW`48ZT2qNu=*}x#9-&bPuz|-Pg>3jUs;NN$_CNQev&@?ossXVmc>O2A7$d z!wbwru`N2ICNP4qM%87zmc93c!p`r?hLC#&{lfJp*4YC@IeN+UjatKZa`( zpNM@ouhq_JJU~!fcA)%*{3dm#eYu76Zp)i(w(CM+k}{_0x|XdcqIHjWL3Nh1 zL@)(|Nhq61$dXp$wB@f}?OkE$FFP}_f-d~Vh7gqQ9O3JrW9)S~&iP;ac+g*_yV!ov zx9DPyU`fsNYw}p4;_&I{*xA;gy8X@(;vzk0BF)h_oiOU%dlMB_0C>)bS67SG2|(=Q zYoPB#)FX#`8yk~;3IfRgYHa@Def9;#pB{`q#)C0=Zy8J3@?`U9%nMKRb406cj?-jFCjn2f$YMu$sr?V7ibD|aFbNsXD zP;U@FwEv48>uV|S{=XR;B$y@lOC0e}Hu%RSQ|&-4e-2*{O$j$Ha;3VB^e)*Qh*&^O zLHgM=Lp*~6ypWz#b=-Rj;>3j<6J?N_=jCLKQzC??AK*G&yYT*-;S3jN8jC}2&!_l* zXih)f-~6`M+qm=SN^cw2OLYBH>Q|3@z3bOkuV3%2*nbxaOXnLv5r$68t7+;0QgPoe zZ+7!uKbgT+a>EDNI;*g%_Ml0>1Bl&UL3?2AB0hSI<}T~s0Y?0YOL^aQf0{>nvkKr~ zXhC&FXKdcdy(^?c_a(YGAG&fbyR5y`dG~iBu5TS|8^V4X%h-BhU1CM_V&GX?%i0hBreiu zvcDGc`%sW^tL_xJ6zR)PW%FHQK!rrieBonnl16J`LCM!<*z_&XR%#s(>9ADWGYKWo zi}eU)I_Tf)lr01`_CWbDA#dC9wUI8qRc(F=$24p>>1^|XOW?j;<5p2#s4+9!rp3e@ z7Kx~UGfmHLfp0FdFsye=IVzZVWwez*Ne*z-ibcVy9&1R4(d3;Lw|0|vRv|KBTaZ=Z zC%j48E=@DwIC_YyBvuqolhS<%iI@-ZiJFvbjt($}5(oVW=;V!ts)pR&4 zPbV!5p2F-R)R5hX{jk*BKy`wh3;BJ9vEtu9`|U0jtzStXN4odRR*M4Vgf`m+=ByG?1s*un^r(rzfm^ z&Obf&1d=s?1WzcRx=#K`?)8a{LyX93rVg>VQP?NJXv9^sp06l02kx z7cwMCCBB1KFDQepzQX7)rBGxJ*t6fB6fdB_l7W~m!&-DR&rfjYwa7Fs9Z`WHlW%`e z>~Bf2;r^n|4z7kT++p*MlO6>{TR3CNn5@T_dkS%sk{`h}a9D!Vg` zqT_#Alfv|BV?P98$~NrYd#(1DZCo{brOoPa$LFvxLQ7Z*Z5luAE$LHMtP1!^mPzKoPE?ge_o6VPO(jB}z4LvPlh#uf7GCRu0$S z;y58(jW6g}(N{|DL8hRsAP2iAXT=lNMXjCsP?zlHi`GpLh)u@{s|nik!3v5bT+tzt z!Od8rtrS7g8tvf>1<_aq9S@skkrv%pqk8@*|UNkZJXasltQFn~gMdl|VPut2I?Be!ATLN25I|??@ zNnX|hDx5_|r~hwn#B2s$dxU*3x;-FZ7|Ql1Pa#wKd?TR;oD^92WB=%HEwTOz-gM@e z=GcV5&vFtW%ROZECJ%=?lTM2T>&!=h2qlYGG!EZ4dtVQ#4Y8iJPaS0ea{Vn}uRQ_+ zO5Y|;A}i%&znbn3Z_JdtoiP^;g@j8v2Ll?+>56- z^`#ftfpnPYDV~&{yGdzKlF7y1?&!w{HqRPc*lPao@Uxs1tfIGR zW>+(C{*z^*?QxT?VSC{a6{qmiDl_i@M~ljb@&Ya6I;!E@bEBt#*FWd$57b?y~jHW|C3VmW^ub z32i>u9jbB^OqA1s?j=lDqP359I(Dk76U}%X=C`fM=Mbub;F@lRxn}9ui(h~=aSrT@ zMSQiAQ@BBTC{O#cKj!6i@ zsM4vS8kG|**PKHtmkduX0E5L#%y7JN1t;O&ni>zwE@-a+#dZLG(cCrpsVi+JoKw(y zuD6?%M6UOrRuhC~Jp+g1K%&{V#fV|feBk;NJ$;<@0o463zf4e>Bf^R@c``1siis98 zP2y~}pE_|<&22T9^g3c4JQl1Y(XKXT!%<8nh2A|jGr*KO0U%{4)Fxp`E#SbAgYr7(uYA_H8PBE5+P1}P@_ku zNEl;&c}VTd>N&(2zzQ#!FVpIZc!{krx$rOAl29g2xg?I{eHcjp9`Jq=tP6P5s5bhD zz)4|^=3vW0>w!X?D=T-|)L?yZel>riM1Y*IH*|{AuoUWo2Xa(RZEi z*48&RQ}=YV?V}bWh+bZYbBYmU)xnapIkIgoz0Tiau2ALlD4?}aPH4s|i1R)4F8|@5 zU{J%(@2tr9AAE4H)I(t)xMU$y)5o#;-6kn9AL9TEHDJBweK&B%VGAdzdx)3X({f8(3 zf0!@&YQ6IGqQ1?dAjCjTul_X01 z892lV{t(G9JPgpeS+&iL*&+|l-}qy7=vvhk4e_fw{{$^+Y#XJ1?Rs6oZ|Kchh^ln$H#zFJ=`Jy_-y$b zz3UNxulVd6bi=6#u&!o~E|z!MtjjKz@z$oYL$HOvWgumF2cO$#I|5jU1xCpX4f4`B&S-KhTm%j!8Tng)X=~le(-?h@5Ul-`x zDSAjt?hU_=4}~RxWQ)y36|7w%ydWAbuT277cZ(NVX#TzgoGuqH654#sj4cohdlRJaKu^8ha+sn8;n^$U*()0o9+Ijrgwe{rHSgZ$^6u1{?}+<| ze9~xugno9?@+^akmh~}+s7oxO7q$=|Wm?%01F@^_b-fq=>-Vn($^Lafg1*qrj=e+E z8*D0(AfT%Y#8*q@Z0jttoLHo5NEL!1e*y_cLfuS4HwDV_PSNYqty=Re_?9K2B={0; z*!9<#a7s5sRd&#S?p}0sjL9{GE#A)A5Fl0utu`_=NCJnosHI9jDi608iByPGCz(UwEkti8Wy1bp} zXeSHW<%CloGo#YRtBIQBw1UzP!O-LYsvPMta>9-@MwigqLWxYeNmwRPV4TuTQq$B) z*My~i+$DFQCtJ}9g_G3sqI8{;?NOy6)<7&}ulB4%qu5HjYKJ@T(cx8;6`+f7W9h~> zx0Vq6-9spS2rmHc?Mt(wWM9X_*AFCz_GWq5)!Uv>IS3@?A0`r1$r-bQH<$iGE05%lr6TVs4K#vrK`o zOnM=!bio~@(=Pb6+vNjM^Pa2)43tC(07?KuoDe{AWS6~p?-G=vXc@fGDSS2zOOl6!eYRo9NpKG5M6vstiww zxdenJuneTYhR8)WpNy=AN#@mToFuKV>O>`gF^?>hyIJ&de$q6=6xU-(m?E9*B#A31 zl0@Gz$s1^%{F*i`bGX)Vq&gGMVXX)WtKx1seTXoX#o1^ZnR56RS7ruJns z8sh+Shd*b;bLk7qc_*n>(K}EsQl)Yx379c1uVDwEFMTZw*8MK7ZC5;R=7%_#$d@0{ z!w+5P)-H9ci5mVudB#=TktQ_LpDjo;OXOD)(6XkpL|B&vim5>fCN`!Ywj-Tw`cw^p zR{3HHy|OWPgj)MPku2NU7?M!VM?`5?WCqkNk@_TzC2&mZ5%W@XCZZ&Exl}H)$nxfX z0pDhXP`DUBlD$LKaiF9Ui1-3Zd1ofy@WSwGVk<8drr0GCO<;=^O&A+lX<;;PsRyx# z41jDSQ{;0g42k$bR+#2%t^I?dP&>JDkbvi0kdnf!2yi(0_9ehh&GRF zxezF}2wd-Mw_CtKaH3c1BL@v=4;f=gfM&0VFS?>@lQl%pEdrm{jGyK;TZ%O^Ehe$I zq=l0!Pb`?ElPx6^%7)CmOp~NyPzY0rohR)8bQ;>*$c$f$w@kE=mv?9{*|gndAzroC za#yUq@j_OGqEC4r#zUNb#;Nd*mh| zqtN1*{L(jKg5|FzT*N>Hq9u>*ck5d^MVd-8Fhxn|mcuv4Fw_>y7|$H=WrjR35M_kf zxWIxrx+FAlxCy)p1uk)U#acv$$rX_18D{xHZeL+a((Yh8`T(Xa zjJKD2?(PFhBTV#Yp-h?%k|z`_AZ4j-a=C>{%_iqq%O+?f3@Jt76W7srs}KR`4)~?q!=L642fDt*o53`J;GLIYZFN=W3QsLd4Qn# zczB8`MY!d{>NOyR`5!En=@o(=uWe!r6jh9HMYGDs;)@+z?s3@LV;v^1n~8_m;CzLv zDWXh*x_h+tVD-tyDtAxW_%Gel6I^1-ouJ?O?bV3nYxm#_o|<9N3+`GXTMCmy)d&`u zjXAIP_HpCpV7Ir@@(}*ZQTOseFaCA=BcGd6pbOqrHuU!k%v1gCh{Y;H0ZT zZ+&IYcF(#4YxK1}Kt}9|jvDjBZveqnK5vgt&JOVy4@+=y0N~)npmX5%`bX_69Ml2h zMKdFA((79X1e+p*SNM$GIUFP24L&w_zcEM-`g_=mx89c$AUnX&OBDj0fTlp+?K<*q zHz4nJ1M+Uyk$1ZRdAIAxyWN1i+d`flz-}Ok-hhYVc#W17+GwO3+iC9X;;(qo}Y#YtM zu{Z@U2C;etz)axP=f235^xcW|h-G;9j%+_yfBz}o8{Yo(CpNfJ^j`h6d{usxt7!Gd znAs%2!E9Nx9 znH>mE87UR$5>)u1faa<)R!HSO7Jxx0SO;7I&DJbm*~u_V+W=UJngsCJ+idAem^TKq zV`;1d4MBcQA8;~CoE2_4h~H>wjiWz9l6990qd65AW_XvS&VRK3j0$4@0kh0!gtC$} z9}v})0=OL8svDh-c_J4)f4qNs7!QF;6u3t|BktK=v!ZC*8%S6}$$hXnB*?Z0%}Ji! z*5>B_xO_oZuW82#{mv>j5}gaJ{~4a5%o;9UL4N)Sr~jDW z;zA}>DlcS*GN4eh(K#yk!4ji_sZfp0@}D@UCp_fp<-#naUh6vvc7w2GrF95Yws3$V z2uCZ+L<}7E_Hive&LxwAx7Ci5)?5RA^$uiyIIl|D*#u%8lWsHeLaN!AavOAN?Wo1X zOrIL9O_806nw)Tu`_wz!Us>7f8PpK7$g5Z1*IGAmZthjDcbtwoj(KcR^lD#8lWqvn zOqU}>fY-XVc0P!$Wt0Y-$Ak-lcAB}OIl_#Tc$cr|ZooNhl(l`X0 zqE@3&FT~IJN9BNiuGk@%08-$!32KJ%%9ZmLrkqMFj6DNJO6jo9d*;K&r_oL+!22gu zGA%^LG>sMj-w!DwF4i>RFs07)dGIDvI`Id1=^f+WoYd)3=SFMCF0O+3<(XngFNhr8 zLk4mAvNiKL?hS6e9@-^N8u$1ZRro?^-E84ct#tDw#G3**`P93$Gl#@QJO!#I#4uT0+ zC^c4;#we&olO1!mAHcU$U~OdCiFr=c1Zd>42l7K`N5@%gr)I$TfxOMG2nMW9q6i;W_wPQ5wN?acN1j)-Km6%f@)qP$4Z@H2x4K z-4U`hPe&6+XdtbR{;KY^13h$=+Xlv0|mRWX?JS)+DK zK0bN%VkA&JxKS!nYr+Q?JY*z)#-D-CH~Ef=3VQ{>`h*{u);jFkHG;}t4`CMYCKQl zho4;~f)h9a$k?T^St)?`?wt#hn*GWW8&ip80*r5=7Tt6;BLQ|RYPdlPtQ4Rp5NUgs zjP;Dyd?uWkYqQ%MouHIo6yJm+z?)V-oPKcrq_VJX0BJpN21D1lIxTTIz2;{*Y?w~J zf2uQLI$xpyUnSWYh9(yNLi&Rvf|?kP-*A3{6q|{6>+>2{IQX0MT2|Tk`gu*Oy!>6+ zGzZDCQ^_s7fbxeat@7?)v|O6fGWP$X-SU)nH9^q1pjm?xl2j9&S?Us%%D1{e({vLJ z8hLR|?ax&~8|q$;bM+?VCeN;B)jhz~m3Bpd11S&$Y!{a9#o%Pj?)lJqvj9_=nI=119iZG1qU}w)Z z)`S}W2+r_a+H%i@7JE1}R&;H3YK-qx%WtrU0(LAU>Dz6*(dPlybR^_zmD9qu9-O^= z4d;#4?)QicV$b`4rIZi`+dkrU--D-5w!L@-ZDLSCT%#*VrY?PMSOfkM)U^Gzrgt;a zgdqbQC2ru|zC_)w6P8zQFCyQGL%;ji_~0sYs}?ZHtKZHpDo(17RP8w}z~<^Y43=V! z+Ef(sqG~$PgsxSL1Q3qVoPG!Xczrto`l)sUORS@TZ_1$B7VlP?=XLh_69?lX6c!y` z@v#D9gxa>o@PqjS>MOO^(ARCzi}$KNX(#j3;$7kLJsJ*Q+3I083QNUA7X&g?rva-s zv(ma_EOBq9g+18rX!n4A5SeM_fl=|wjP1qkcl(Frj=^v+zdCq{+olgJ!2tn&UqN5P z>I$tqAAhlReSZ1Hm(K@Ve_wg=B_GV$ldI1MT&cK-LRC-_3RHJf3ysPb<%-#Md1cK| z5*-B58*kZFR6@G1R;-%+S}il~D+!{@Y-XkN6TvuR8qH+n+6`NG5fK-$ES`=>i#z?n zBG?=n8{$zHZr!}MxYzq>k&K$D$OygNZZY@4`k5eWLr*KvWaNyF$kNm&d8GmKO$bP=(`rUQEJ^(9OG9SS4u!$dz+uHSm#o_Oo>wT5R*`dlvqd}lEQ?@k>v zCGyXnV$;Va4EO$x=hMeyLS^G3s|Ya(OaSSGBV6o=axVNtpRHlLV*oMmQwxHsukCr$ zLeJKot@%RP z#o7bh^oDkQT&tsm8_yU3#-J&>ySu$(*bEu6&7sGU{dN-wBGCH@5rh0Y7!L>d%M=7A zO;lrBhj*r6qMF+3lmBX()ZOc8@_+HgCnS70-BLxBHxA&+-SiTlK(srLv@_b6%mW%D za}_O9dXq~I9~(=FRiS7v8eeODxAq7;*ZHsekJcXE-(2nd6;{IP{U?(CrQq^j=AsTy zsQC8raNK{>K^h1o5HfurRz58s%^A&E$x1L?8KM1Q3@N)!(S;n0VGFs9%*91Pu0b#nd&1D4k%S?wRn8FOVVI}3z6!p1PNIAPFrM=wv0AYe^)y+rjnn7`V* zrIg*C#buM*^mq81bz+7S61J>&h*G69YW{qzeJT+sVT$#aHZ+s`&Su&w;G+|cmoHqwNrV7w9Gq31ypR#$7=SFdRe zKFSjOH0i1Dl;trASoe7HP^m2C3fwT zVNp9{$%z@U)kSkTmlIdl*C9MNA@O3S|9(z{<%1iA2FNLwJ&fw2U-)iw?Vr2`G-0`9 zw16jN>Br>bf@6E5(Zwr-Mi(v6CT@y?Ge8s3k{Br>*AVn^?PLnll#CReTn;7DL8%VL zN2pbdok$WKTmmKI|zqjBK-o1*d5zZ8@P=~ zc+Y&72q_>1CB=^pv?c!VLolwO$6*}SWYrzR4PB`sIZrI6gjNC|(HnG=K%)q&jtAgV zNIQ4#F0}leo~RTAN<}HS3_q6Z!?ObB6lt0bbjD8#s%S~wQ(dW>x^%Zi0;vSd2uB6P zIZwpr4EYZS3@zxy!DY6yL5()rIsGc&HG0+KZSd--LUYf!?`kSflNZB4{UKb@hqDU7 zGQ>tlT788ImpDch({*9(j0Bb= zAqPLdFX?eLadR1go*+!sj?DP>-UI#i(L(FV504&E0CW>6fmL`9A4Jyhb;u6toDo7o zX1s>C!i0HbI%isCu1mVSA$kD+pm!kt7@4#1FdpEv8-cyx55VZZ9Pq4~@!V8m^qFY> zv^4aGBD?6HS7`6y5bBR?H|7a5 zAmyzwkHK^G=W9wh?H<0COyr)J5uD6Vn>`Wf+&qn*(zGs5Ozd%jSV)P1215_R?!4tX zq=_qPq21Spukd@JDzJwDHOK2n3v5TX6&42x>Ly$Ef#%UB!uaU{lejE|i?|Kaoggv> z77pQNisFt~$A;CZEiD5)4t9LU;K~{LYF1I^euBbH>|-go8u0H=eH#lqos{!DMgrVqwUI+|_MBhScM_va``zvp5lbGzOz^m9a5{T}-Cy^BD;=&BH`mKr?=8jC_tDs0%b2 z8#~+&`5Kf4O`8C+!$r7%>mw^=@TVDka_JPqQTUsh>qsoQa2T$aUUoD zU=xAVNL5H62YJjhf4c=SL3AT9p=h@oBbL1=6ACi>5auv8l0`=#m}d{xSB;+9&;Pqk z62g^v{$Xy2Ks(Ox5KY~mu!YBHzwU55#Et`ws&jd;gNk|p_!7er$HJ*;w$Kfd!pu?D z4bi;O0qmBgoTQgs9Gu5KD|$+DQf}S`uBLzSzvCrdF8K=lUZ>tqDp}66h2G#xq#A^qVq0`?z#Xbu* zEHnhSO~9bGew-|8UKD6mey{d~ZC^#hV$caZVQ};_@wjrxE7XRK20g-UN&Nq^IIAr# zWVOz&dbeiw{wg>--bJGS8$+87Q^#8kw4ghXyb=E1>Cw>{^7;q89vv~7#oTcCYT=e{ z(+q9>{^%`^l%0d#N4=NbT^ylvK}e~H_y8&@00`Wy22ojO|KR&5H)tA zfCdR+#iPp>2%zzUh8sugvrT;%ja6UQI3@k2n>xuCb~CAyRmxt+N!@@N;M!{B z0ohtepT;?F(SQWHak_(G3d-$ZcMj!Jp8#Wtf7daEE{u|R;4h)bhRju^J^OQ;FRz;0U;aNNUjgPt`9qOf>r(d|>+~HNA1LlL&Uz%+>KDv@RcF({?Yd#kY-*|wH zFr2y8b|y{|S=QNf>qls`UhHEmcXsbBqm8?5Tvc=T=2P zV{^+xW(#2rmO0caB|_p0_>j^hpihV2J@v4+SqQ1W-|y`y=!HRgBZxp|CBnLA42}4* z1jPD@Fq)ASlgEq~U_A|=fg}FY<3PJDUsJzM%W}*p5&%T&yY3;<7Qi~DOL1{zAc`A} zNT0}c9TKLAdjCGn6gL4GDF{`L7EOc&9jpLUNI>2@&`oVl3jWhX*G8A!n)sSNfM)zLIPzZDhoQ-;ll8@6^$^MqmRMs3BW z%}tkJ&-!ned})yB>80%1AN~rH_Ji$NAHB&qng zvRs68o85GnF@JVZ-f&4Q!7aZQ#Uc-?p4R)EHOGyaufSvT|gc{KONm%m*9H z3~c+kmFoGk>3_Bm%ht=9; zW1YP8_viopmU&IyaG}-yc@B@RU(-Vue0+Kpj-x_E(wCHf8pcQ~h5w)9bvB*jGVkpkt=jt+Ewa!e<)Jc zuct3jM~@p2d;dUGl(rAu%&Nb_V;0Z~5`6TFG{2J9AYMWH2vJNu&y9YxxFYv3(LIB z3xOZp<^?MRB@%n{mRUm|5jgiqU%(^Fv>GjIz>-;wiS*yfo?r419uNcrn3FX~YZZl0EpiCjA=o|} zOK-O1x+4_#L{J+RH@4F1xMN~7cNcl{=9oDOho^|2Fy$H9-~;;&m!6o5&b#Fpj^|up zIj-LSk<>1#%>Y|munsgpzaT_YwRo`@8uLH6|8USfWVkX2l?@sCo9Y$ zH(cHwW_rU8atK`(ps0}O^=qaU?Sur_)6uqwvSv_mH~3fZp=rBTk4{cNwfg4xkVk{u zg@Jp9@v#RL=jtt%Xtde-YZTGMu_5Fqb+T9hmGkJz>*IMx^?1=uZC)Tl+~Q0R2^?0G z5RANpKC;wsSO}$&ud{~oH>k_J%L>o?w_j}iz2V^(D35G(gTH;6xCs*W{`%_oosDOY z);2p2S0AlC?mW2vZ1V@i;op_7o;>ZWK7NK10YU@7LEst)?W458?httlz@0$|j79g} z)EE?TQX5rC<*c?;iHG9sLwt4zU7>eMI{WlqE5H5n%P?%N_}fYt2w)_(1Rw$lmwx+v zU*Owsv9v2KJI5rA2JTtM45kr~urJc~@n~BSHt+MEs%wcL!lRj=|1+0Ny}Kk*#YNS+ z5^Z$GJi-__Q}%T92lJO-<752azb5%s0!34{T9|rAb>!se5E9jUmdX5Rpyla7548v0Fl(>9?VY`vhK zgfW6#?w6gnt`&lSXqajS5J!)RLfHc}_qa`6lRt5B7Y;^nd#fIs1`++z*v0#A$_XWv zZMh=)QtZt+mJIUgXMH!hb*na%TBg);HWg5<5^=g z!bbXXV&kHswUV?s-%`qI0(5#Qtk;aQe?zDOin9_K3e49at8VK-l0jylkBnptOI2TT zfr_|5Xxd+Gfj*+I>=gFz_m;IV3^Sg$Js3-DyMy|z)X5c%`q8!sZP1Eo=>CX{WDwN* zv6+E(Ny2LImjzK~*--w4>@6TFk&^cZ*S&~D9OGSk@B^JS9<@h_$KGIg`jYATx~T*u z`f+v@=NXc|_7NLW;3^3VZ&RiH*&>qxT7c_JeI*9VasINAiAYEzWf{=`A&6hyzSikFiGrkJ|&mza|fP@vuj zoLXexDc1=LnX;K=iyZM^1XjIu62?czpMWO%5c3x9x@i&M2H-IwD<{yNWZ79Z&Tm`B5x z-~QC^y}nB`6-N?u!sn}7Bp%S$Q=JDai``o07>jlIT|6-T5Uk<8*PXlE&04s5tMw=Q z8HA#aW;J8)1^9^|9s3Fbly3$}F+PT;TYb^Ke&gn?+h2YC&C>D$N$INYiuGc{jPW3k z0flA21v)A|J~`druMoe6e}jQ1$h!g=Xqt$r(zZ4SxxMn2tU7(eiotUpRGLDwHfl+> zbS)TEF-sPP>Yz8mabRT6Agwa7E+)}U1Zl>H z*a#fD@Ch1>bL+W0JA$Y!ZyCzAnijl>%#AV@eGGK z5&yxlf*B?~&TvCk3S-8O`S?Xitc&F7E#e_$2_g|;ym&IYaYKL2-&odNNm+)wx)Y>w zSF)Gr%Q6=N3Q4Ru*o{ITGmlXxecm0!l!Y_%cz1^3GPpcYPlrg+0A~sq z2{VreGnyzTi0S9^8=f>TAs4NWPe(}lP=U#seo5gRa2SLex&P4+M;>>OO>ilS<&Muk zPy0Y{r}J=az0<)KRD03UxM%EyjUV-aT60{jwSmsL zq(y^>B4rYzEEj=a=kGznJ+?EnNUy|gFV6?h2Q$(FI}dv)x}6Oo16iSf3sE!&T0}*VRq!BTXfHOCqefzFm^4i8%QIjq z1fJe%T!Uz31+h@ti@fI#igDC?JwkRoRpYw-*m+oJ|NH*qXOC7lphBp?_~*0McQEECkTi^a5-(?4uaDE4eYT4?8>grjGaj!%-4);A zel4`I{IY2IS?h;mnGq1tN8p*kD+akvccCTIS*6N2=`GOw`5Ee9eZKhl5zZhU;K&Dl zgtR^3l6>Bd5hh^CJs@o@G`~&u5l>`XJXamun4bq@U@!UZ?)aw|OIyp=aN-8(7gppi z-uxY#ApaN-2aDg%Uelooil}dq3xCqVM$bv_?&3A2kxjIpTlnJYw^KfeBm$Ib)F}&KBnuzWny;;y#jw7w7o*yV2hMyU}>e|8BnPo(zw!Rw0TnJ4E8$Vt_yK^ZelE zi)+y|K#t#i(BFEz9!~u1U3M~Re3t^LoCart)Iz)75(@?yghx^R&}ljN%bkUB%NR2~ ze#_XWUqRQvJg}6(UMvZ<&Rf3l`Ea!N41@q7U78?E+m6x`Ypa5*8qD9fL$H zymzvjJKJQfkFaoIqrzO`(PdV8f+4L?4cM@7SHt+U~28{3;qCAVE@JJ<_<8_C7S zulO0lL11Fv10RgQ>%_;x*%4~XF)IM)%U<%g1zsctWOP|{XeG^VdwW}-cY)7?UdK8d z>pgf4R#+ZQ?YzByhAeveY!hxWYJoYjw&v$yckaE=`<2$S-iX|XiSnrl7Ib=QvSd5W z9)%4l9Qm-UsPXb%q=4tIb`c^S_r zL@L6{gd!K4e?5d-P#%HnXERTV#X`!ujfYY&ws!X@9}f`7c`(yAPZ-F2xS5f z8i{K|6^cm5rx?U<+(YJiUVA96IhkTtosU*l*r$O5{Z<9U^s!r~p%7npM@*-mYt5_& z2hfC{-~rdIOfN?6F^<#*PON4IwnTUUj|vh62gVCC@-!75`9(8FqMlAUla64bOa(s4 z0Ul(8&zG1v5wo$f%rV>aDoL{fuPvgsr#j$(p)yrD^R-O98>KmTm&PMv*t}?|>zDaD@&mS4;FzO$w}X zG8=fX#LR|t$`clBt6i8VRNFX2KBT$c-$#NZ@oU z$8ZWBQT)Lx=&3z4P*^zgR2O&e@b7z}kzzxY4;2E4#<_cl@BRYROnWijEw=NzpnpUR zFV!{LHT8N>;~ni9RAy>)j@o>AINX5_n0Pr0VVK?F@fnIvopdcuxCq0iyN8URMR%s>6TQ%er()ziKKp$}JZE5SrZ^9^r1Cj$0UZMv#s9Fmwhwxl-?Xkwc+>jUUcaAq90VlSaeVb-Pv8 z&xTV9;{-ns@XMya>#W^BHK_}{rAZcDChgVu)^oVxCdpR&v&AnzqhrbhE&K(~7z+bz z+f9>r&*%8Bu{Xw@Ic*sofnZ>*f(C>+h?yo>u@=4z3$`m=jQjV+Z{>qM=K`J&gm#QvDtsv)6`htBAq^y-f6Qd2*Q;Ob|_A zw$co!sQg|x?oi@t0$(AHtEj@$Ml9vlO$bU~CETPZHK|b}*UO_Nbr`HOfstqdWW+3cz7&$Q5EAoQ zo)n)#Or9VSAg6_M-8T?bK5otYXs+K%YlbL~5t2g~8=oa4(cQJyG6f(}E@;@%6C^0N{rO1*dA{f2*Hp}fwsBM)52})Dl`XyI@P=ZCcki5z4zo?ky3CbMz@dna z+j1dhj)43r3*P>){wQ}3L(*c8ckkH0=k@288W(-}2gd&mAw-975# z(h|8Fh+wj~AhH)<02N_eyaH6uERr{1xD(=h9*2b(IWvlLPRt~FLa z;Iw%eqi*S}KrLdYM33Bd%kiiDiqR;>aLwkNZ!t`pe$nn``t7WHq)Oy5l3rZO^qmYD zhlx9h6d$hDx^&Pu`brAwrwsUu1IOrBOZFGY8y9U72YlGz zosbkdG|i?2^rm{Vn&dy(x|}$xYk;I)_H~t zaB#oClmE08Ko-B&r4Hd%oBL-UI5uOg{M_6S({#+C#_$huufatlkA}k!oi#tzUMUE=bFk+)bw@&o7UBUW%9UCN>tAP=5Ce!Ti*bHh?UtAAUH?*)`#ck_H8j9d@v zpkYNeR`0Jr_}fKT;#U1|bm{Rc=-}}7eZ%ngf7txn)Afyu#y>^`eR6a@t#JYH2w??d zZdJAW#Rf)!taHkvd9-ujsDNQzGxd2}iS2vkd+n<%hZMe1w}f7sKjxBK?@DTb$SI#i zSYDzN(HE0j^(HP#S?{o!70WI;%;g0_G5alCmBCPUn+KOG&wIxR3yoh*z94q@CLeRl zw&Ce;6l6d7@^$y{RR?JeV6utP2YbguoV+3bi3hHfN5g+*q=+}4JbmIKDSH{9pZg5d z$_};LTE?uSsC_QEjXcb(EiS}IKyc77yq*F2V9F|TlW;bqKgh&>G_f0WGVR+fZ_R~Q z{J7&FVL0y+@!u*VFalN`Bm05UD;@9vG#_+}cj3{MDe#{ILz`}Y<+J9&&3~i8(UIXA zid@U?2;?zGGf9Xq>0~N$)*D534_O7s4qHTfIrt!J=dHGBf6x-!UC|z)0z!I@-Mml# zZoPhr^gOtGtYzBpxrG+t$$3B6T0p)SeQ9NdCZJOmmwkQ;Sy(~0BLTJ$cr5}s@LNo%}Cl7(Er zc0Etv+TsAYT24?&vfo4lh0E+a!DhI1RH?JJQuay$B@G8LZfA@!)-@7gxwPgxYGNF% zbhdFa8Hstmf$bYlP#61*@v0tuv6t;;`5F@wXgFw}S4YZ`nY77Eg(8)nz%We{uBBVw z@kWNdZ$eW$+Ey1D;+PzAmErKlmK@6$Si|TeuI$QAt_H=p_)f{A3O7|5(yFXr5l)eB zaMm(Y9R4-sn}BKB4pxpu>oqb-hz6=pr7LK{xF2Uzw>>fwADOGTF-`r@S??7I8#fk+ zMusnnnZy*L!kE6inOZh%0%8CCJi^oFO5uA^2` ze~7ykJW?@**v?5LF}mY~asM8T9+rq;eu=C8M*NoeDadHnyOAnt`_!eeiFy(1^zIBj zQ+xB*ge!Fxgdfn;h-dncsT-Xmq5Xq*_c=^EeT4G zM=DF~b$rfTHI;%EB_LlG22kLJb`B=-Gs|nnXz!H~{C`K<^KSQ;Hpv4hmK|Pl4aYDN zFcq+xf|?=o=8>9%e=E%!)1<+mEGnNzh+N?^;0yKPsS2O9?(glvOyV9D12Xwj-S63U zzq~cV;5s10{03zUVhof5!ne^RcM_ea)Ip2^KD%*I=kc8Z#bP!X1ojROKDBY*=?NkP zf`lqIjoS>GJb?7kyVe^9E}8mWhdTzX0ekayh8FA8IAVPI8M0!JhA4(}F33E0Bjbx( zf2`~?xZE59zqL7xY{-~mz>=n6Anmno)h05DO*?&M_pLuDC?|;Ryqw|C^s{FDCRqxB z)MhN9jRO@_Z?Wz4h`H)mg2VvII)VYK>ke%x!@6nMak|46kqPymxT+9Vx~#wIm)!mN z=-V=+C@HInU77TTn=-%t7R_g^q`?o554t-&o^V0QP@)#v_W^v#QGW-Ait2&@h$Z`G z{?#XKI#>Qd8+C@pIJ=~Ivgsb`(lgMCK(SrQ%ZFse+M`2UpL^KREx2rfidX#oM(PLA zi#`6L2Onw6VU~;D!L=5kIt%jCWa2}*a-KsZ>N7Rm=5!g7sQH@V>4hT2@45(5IfQj4&kwyxp}2%Fn`a&ivo7?^;ot|(LT-Qir?zRgVQ!hBp-Yy{=@T% zTMd(dPRIN`7Z&UkDglsWJ5N~IE(BD@I7uBsXU*a4zn&4BiYqYaNxpz@ujA5|M zhGOPAo5`|HUC-Y;=#EJx!EnuiwU8L|_b|z_xe+}sY)AF9FTW&xD_Are*Ud05@rH>G zgOcfpGlt~P3ko!=>2n^7!Nibvfh>>7R$)-&b{sL}#yGOE{T^RT$-w~oXmtE*cyqHl z>sL2KDr6~*|8L|8vs5m_77l&3Br|J6)yoVFYe?u#WS=Zj8|z~Bu#svu>68%~Sj2|; zy>Q8=AI>H=(O=Fff$u7>7{W6bkXxEsl3(g=e<{a=-G?9trI)I{6S z@mpaa$0H``;Z!}YYr~Ux_!-JfAW%(Tk(E|}QCwt5AXNzi$M8z~yLeF>Jn8Uteyc-} zYY(#noI8vDFfJ@sRuYt*$DSL;+VwWaNK?dFB5pwHhv=nYSXjP{D_T3m2Gm2kB#vl< zFCq^CktLfYLx58NFkb@U&G#MGKCF$agQ(Rp<)tHL)<=m=zcQp$gbg_1_6ti#vq-HI zMCgu&Mb8-0XSWt_WwIm|&pCyQCHW}sG;0{NiQh)Yn(+s|te*I6IF)MV_xt5W+Wmnz z&d0RMtj&KFUpqU|6V7&i^$}7a@Bi2RwMX~=`e?QF-P-D-hxz30<^h)2=W3f0JJV+V!7Ol`?sB;xZ);xAfssbrvhp*2Zf0lG%Cn-OnZk!I6__g+Wqbl;&AhZWy| z09+^!;|n%U=2L|M(o+|S@r7Al>21j$(WH=yc%-Hu$=7dGS>ch2b@F|&&;i*;FP{%SLg0P_GNx{u)=t$?XG)_g*%#yk(q z0NdHW$g$4O`BcAJP)v9crp6}qS1ju4n?6o7NHe)f!rEad#f(oNe?{-E^jNnWPmyxX zvQR7;l|{$20N*^26+u353nHaF3<@Sulma2H7^BivDg+WxntnQGE^JVk5~f%~83#>g zp-=Xjs*TaS!B4O*tA0WwDFa2k)-au)i1-!mg6G~;#GvZ5tPB#{{%JJP61dS{J1v8) zPdXJ$k2|^;hXXpZUYT?5#BC5eZBBZP_-=zC63g)sS6gA=c~V13CRT$0=?6dcdG;Fe z6%7~>og^11Efmcf;5aN9ASLZT;Ir&=CbwhKxG5$zjqc3cV*iR#hq)!1tx?`o)9f4~ zoMxK^WE>(Hh6##isvn3;8%mSs9FSnDq2Az$6hv#L@oSu7al5vGRRm?(Nnu6evj&zi zTsX@h(2-MYJQ~%=KbHtmk%vM_OoXYBhCm#tfXviJU=i_YY{BXa_Ij1~h*h47^wQRB zFjlyE4^%6`SDn4^vg|P`683ldNcq7pCjEJ#Gm!TaO3}dy^zbL3U`#phpm>#Rsty+; z0ZPUl&O?&6Ej!5sMs`J~d9RJ1bC?(>cTtah$4uLAiv>(T{M_u}dWd{tdKD2Uq{9}i zhvAdv6b=~PV@uFctda-KY>Cs-)G$^-Y-;4hVOtH;J$+G_g|s7jiSa94*7pi>&kZ3- z;6r-`4U##91`81_USlxD2y1VlC3#jvCzC*HqnS473*eKbQ+gugdAR3^M=`Zj=S0?0XrHORXb8oRsDq{(=mAAI+MIQhh^_m> z7m3kuoT0=WW}%GQKs8DuQBZs1(J9_90E($o3>w&e24ObxPvDhpZ}2A zCR^`ZCXUr^V&bSXP{ZH3{fVW8Si03t&6Ay1^VTfl!&<)KdyAHtd)OH5Ifv=D%!0(~ za$oO-Xx~b!O!ykK2xGU8<0;6bxRKaOpTe9(=q0*Y)77%D+!2il$m~nqMTi;KKA$d1 zY|8vN^RU(GA{VQhi=$VQaz){*8##Oxm@+Y9gHAv{9RkgMQhwZ@n17ykgUHa!sdgU- z|9ny5iahq8FH`9YQ)KELlK4YB61leN{V?qP7 zB(RAa66|{fN?B2_LeZcJT)bo4mqtqc#Hh%YuSA%b&F1M`_{n$l@KX^|Vv`(AQg$3h z+UYT_le#tODpY^Kvb)LZks=_aIuBZETqE~7(&)IrN{@N+U}CRG#xb^OvY3xf?2UQQ zFMwM1p=UIKu2iYQLRcufFvP*O{e7h7^~{=0IU+dhw7*YYi3NsnRR!PdD<{Js?}iSu zjq8Zu37Lj=M90MAgqx&1QQZgISPyV`2|0Vh6Fh*4?_mGq8LD5{+#(3!)^5cpBz6kO zM45`54+GsF_lzp%1@ zyh@ENGKP^b_PnH3HyS}P= zcxXZJ1_tnsjhun4XE;5ygQ~U-W)zQGlwP&)HYq|m6LhqWa>djdM15d%&v150gxg%+ z3Nz}^aE48sea7c~G@dHSsDL&D4XpzOg~sQ8eqB*uDBoHz0ev^UMYe-U#XM_2q{v`ipZI zBvqks%1nY*TuxEE1BbJyd5zO!+;~;07oNDiVR0T@27u#xz@4574f^C{n7#^D%`Kd3 z;;T^JCRIJ&rPXrveUX&rT1#NeHhjgyiZ=UdZy_$e{4&qc^*-iHB2>;<*e_Dz1cXqN zk}ADbmkvwXFk-b$pc}`0Nmf(Gy09Y*b`dBag~X6*!BLf7y?hCH|T z5l(PQ9-XH|ys~%iNksxHIYz7)*e;(S24?4JA>)yiMAsDZm z3CjLcSx}fcAb6lwHoBluRpj&OU1;C}DYE3zy|Rb*DgQ3TPc1PB*aZ0~96Zhjtyr z%!Xd^JoypsM?$bl$$fWc{$qGBXgwVEW@6w;_%wXG>;Sco8}T{0X5drafPgGRZsXy! zmz{AEWHDk5!&vV5le1&ism66{0QC^3dk*hD_TTjB-Em(FaM<5Z8I2QwFX9ONA}**} z^cxNqP$OZ{_QyL1Cr5`Y56ox_HX9e!>v*x~c9C=^K*o!LL?wf5+S7B~>WqK{1N4uh z-6p<+KVXdIbb++cyc#Z{FwOxpmk@{lEtrsa0Tw4fp{vuhn==OCl}P~;@mx$d^HuH( zAzVZD9sQG10yfcHni!m`izl$4gE1p`GK;<5x@-JuS{y&KI>~qM+T4 z1W`~_``hc{a0OQF?w$Cl(pNl;o5E7Qb7)c6qsgI|GVUAW<&ppFBM$AHcON+M_`3*6E8T5Wpw00x68TuLDE> zL0|u6h-N_6+79~E8MqD^b`H1q;tU?H>VP!|M@q#mxiM0i1lD#pVg4y{aIH>;gd`BA z^P!l~-kIm-B#26B9>j04`out8UQhv{(ayx3XsKQBHf{;vB52jv#V?gWTz&qT5J9+4 z>Z8k`qVRl~SD3_ALfBt)k(mH%?H=nmW5bREzq92tXOn(Ux(P(qXIQNeRd(smXjR#edI3E0owIdJR zKuO43I0A?8x*P{4y}+gi6#!CKQVW1#P6j6#yY`8OFIEC>1f6BJ`d}R}*%kOc!H&AI z{MnRX5;xCcU40YKZa5O3QFcq(Q9?BK{l8tkNG^obYZR=1=!Hw_g;@W8zgoCFOG$Mp zLJWyy_P`V+5wpXMG$>gHE4APn9Qz)eTvM1eN>|;>?7*8RLVuM4JbKJ83;B(geBL0x z<1?3J6*19ZAQFR{5mmIVgIoxe3+0@WE~*YOVy5kM5BrmxrWO^Vp3v8Y@ zf!Zu+;GE1iO{AuW@`>fm?1?%S1ZE;o~E$ zqoWQ-c1}8#cX1$D`^dw?w2f^@0_-D5Fg>kcw}JvmX{+uFD$W-@Koxf0&FfMS)PCcg zAiT5{C2!CbX9i$(KPr$#`^tLImZG81%~7i7;wj__b#~>c6eQ3-3;T)c-=}*H_?gI! zO!XxSasn)snG%2^V1HAX5!|Wt5xCQn-(X$@V5_t_SY5M%+{$={I(1k!+G_iY5&}Ky zobK+UXeW#D`k%Yl)X<|edUPt9cZlp`V06?y%-`mT*qi>pxQSqMxTu!`k|`kYGBO*^ z=8S!yA9?edxq(Npe^Biq@2e#a*z2LNip2o9MTg>$YH3-hY1Va8GeYZt(44p!m#uv3 z@H9`_2vYdw`ADDvgod>>#zLpT$LSf!mvj)UXG_J8?6eAATJ}v?a@dN2Wk=$#^(>+_ z6nTuVLNQxyl05BaZKr8@(7EmWM9FLRQ8MKf6n4y5lW4BsLL7!`gH_L8{A4U8*z76A zSTGjqP4sb^OB@CbLAwfg^pQPjLVBgmhSVMEwHMIp)NW$9dO;@T~sIY zDrN$S!J>A8gW1hob5ty~&}8|Y8Mi21RW=ue2zh15A8c;14ZgPPo6FhR;%a>-ycsw} zBW@3;uvP>`ig0H3V|b4vU5Bk7$X8?50A`NB4lmP6m(k%Yc)VLU>MdTC=b<_zxIYtl z4n@4^GJcWhCIU`8?*6dEY9BW z^?;=T89bw6%rnOKpk$oWnIH5{STHksS=G~X`bdEd*qVq=VP8bwSGv|<7686;(myE< z`TWR03nEaw`@;iX?M;H#dV=#pEA7?+LNHi2yhBavGo)Vb;+oq^=N>`6vyXfSJBAdn zH+6nr@#gpFxN|z{^G=n1ay+MZi(6FIF4grI<|OWq3_#aZs~kDUoFVSFWh|K_x4QHH>b!XV`penHzFD_W@Nwha zJf5^=ixluvBe_nhN59rAH{SSN5wN&m2caO_hRJa;ySSM4BCZZZB#b9sfjw;2qP7Bl zDCQ*(_2BFn$tpAtlmvu)6<&NSS!;BJOO4bCleY86wcr{qPX!jabbDfu%q5xMym}lU&Kz=2_}-7$mbDzvEW*WU1MlQb-Sr zv%Kng%f=#;yujjun9Q6|#IbWUeu=MKv+8gFs;}ev5L}ZH(R*ZNstYFBSBLw+b$mOU z#{M~-#vzfLvj1?)V|IMN13$6{da@1j+;Cv!==h}5-w&Iij|A8q6oK<#IxH2eV`Y9- z^CN81$uVlgtaJx%y~_}ZBUND>?e&Y3+O{-%Jr)Ex)@C18&{JUb4pnWK*r9bSsp$n- z`x?>*Q7doAO0*~|P_%SnvWqTfcZS#(xbRPHzxtEt}?YvZ7cTPTc+S5rTa-5*|jip#^$ z1r|7>)+TD3FcqI=Y~iyTYA-T;pPY5q-k`sbx{Zs=W&-a9C*vWaqvL(|7$ETI;^8-N z3Dt;s)i5=Whsc)2w9tYnLSFLGT2+Oi=@g4^%({j#;YS=K(I@ciIbtQf?h)TWB=W{U zdmJu<`Ew@@CBP1`C?p||5-|D33Nxq-(u9VZ@+n$m48&K6vmvpfoFu9jjQU_dW)`Yr zHNmvwcf*h%xq1D1ipqG(8%2I`|jvQpX6VhfJTdUx|E7Gq4UJX)G)YL{xD)K>f;BMH`|b z^bS|is^L|74=2??a)>2B!&5{DSFTjl+uOn_`gw7|&V|4pz*XBbii-i#4pkX#1Q`5K z)E0`caFvBLtPndq;PP`Zi)al#XmJZtI;`NXArCBQAK6_L=CV!7>Yw3K8a0&uVU7G| zwC+l!Mc@az3TPkO{o=x}Ym+&Q5UBsTjS8YC95b)L&+Qc?sFkR-s$#Bj%>$mhTG6}j zEmFdHD`ZN{2De=T-H1sKPzloF!!3_%!W2v&CaRG|E4EExk@p6t>I=R%Q1&?kW`;%s zDMVMR?LMM}ji@)kt)4Lqsa|GQ<@}?v4upouu98uZT~?8Dvf!v5(v`F{i0ngSA7onw z>~?Z6w~aJ%hacp?7x`ehCv4E5+Ry;OUAiB*UlVFNQe>JO%T130UdpXBY*W7=z2gr* zJ2KBM<-u<%>Tp>HKG-gt@rGcFNn9L`$Z3I@3@#sUY3SxMA(vk_RM0Ln{7~Z{Pcif7 z=4+7o*+w6`RK3BJ-AjFF`GNJM!3vw4sIPIYuZifu2c@|bxr#+#soW7Qp!ChpkRCR3 z<7H^)=3qmLC`b&#Xi2e#(BP@kP$@98xLlymzrcGmv&9+OA#9ur{e1KNJ^2O4p4;dT zUOD?sx|Ak`w5{1?|5kt8_wLL~r|mJLtzWm2%_JZ~WnmY3MvjBME=i~pOV$~8_w9B; zn8J;LmC27WhS^(giWGi|hR;!m=5Og*mQ1o>Q3Hn><|FXU1#ONqDdtqn@E3<1Oiggu zX_ouU`Q$V;++aORk6QSI4rUIaV93R!WX)HzFJf`V^`HyCNH4jik}$`@DM-!9C_#OH8pHC)pwfO_mSEuvT*~RSKYMyh8>7Xt;D$-O^N;?`Ovy> zrQRnB5GKHTTgU0cntfbxXntoV`$V$Ie9f4iyrH+>DQg*s@)0Gcu?L>a_GND;?y0 znj)qvM;&3F@VX{v`HgUZcUAJor^ghfzH$5z5COv-`hm=@I%ZWpjTwnMJaM3l$oJG5lO%k0V; z9NAFbWLEm{5ZOK2`Q%14oM7JW^SXOBPPyQFWwF<7>tvqh0d>YU&t79$aa|U+HJF8G z4J1D_6!NB#NRCY1-onY7lhocGsadkQ3jp~Q?oE7!9q@&JjE95mI24A^@snqdTL*AB z$1Nl&^m$d<5q5=X9^fbnE@bKAY$o4WkB+Qn$uC%G5Y z5I(0H;@V;cIMHMsz;3oabUcEe>#iQ0DN?8Ma;8%(ibr|jm_0=PK*>gxIFdo_HLv4d zLIn5xs|0;;%oAY?Z;lQZIO;{{0*(K`_5ui0x`1pu6yoINl^1=wsg|t=YYVL(5QPSC zyV(B*jk56J$j*x(<_CgBVk#@2@S-_j7`1BpyIvUyBkuGEi++bFDOGb@7$1m2w7}qF z6911lHUCV3Ih{WnpCZLVRE`7<9!Mj{Fh?UzMLjLi(KriJV?_9*gYKy zKxcU=Uu1{#kUcnLKuRSXdGy*yd@*nCZW^oW&guj+sh3@VYpEF$5C_M*Y|CV~zy_HbgUj{?3p`xC(nR(Bu{ zn04Z4f}GUtkloQvA85w8VtiyrkH}gF5LW8EcpUY#qzupvnC2AMYWERfmmnrBiXH)m zjdJOX5FhJFnG%xmllv?DGR!jX0j8NYMc5wZb}7i#)VXbp-MwS~p4;X9YLdzH-ss&j zx#aK?-BprHn!3DHUyjN$&Q<9vOQN8Thq`Ar_RmD}xBx^O`hG?gJXGnUA~2$x2M0r4 zyG#|)B;m;vx_6tplH~l-bwG$74S@vrc@dExi&?=Q7A2dWO_rz6?^K_@KiW-&*5|1h zkcz4=z1JYmu+Rhc`;)0ufsZ&{TR}j4Ur(lbV!2VRcpqGcq=|F;`{=>EYPODXV+7#r zH=%;w`$Uk_4$UNCFTTWvY&i$48DrEwvo@c|mQ&BtjyT(vuz*PcFU{cUx9HO{k1 z>vTLxfk5LAKl`7jKdiTSm-E!t9!botH`X?rS}QHcI`+ODq$%x5=&0{kO7%cvA@#2 zj+fR$-PLXQI8IPjLV$+9azp+DGPA4`re^ta5T@x~bVN$6@dOJugi6h+R;=Aekjca_ zX&$kHE)RTWp=It?4we?**(ZO%H%tvuV-EKt*My7j@3mu%)uOLqSj7 z8jOqI@iB(e!`(i9ktDL;O(?l3mQUpTn(=p=2WJ%K_rz>|Sp+`14XeLcs&kQjAz&cz z$oqNU%o)*Mge8IW6!Y*1k>Vcow-C%RII<%%Es&L6m3;HoAJHoLJHNAN6=FUh+EZNS zMCd+X@Ggc29Z2TG8HgvWoSP4*Ltk(aS|N7%$p) z^Zd@l(BjohrHGELKKZY;^`}oBER~E$}WMI$D)s4*! z?X2_$KlMk$0l`vFjNkKQRAtDCYy9fPa5%mkRKN1b=Z=tnu#bftjX}Ygx%+8hy6;on z8wN(xhv3}7a4?Tk7lXa-C}|yw(yi^|Whf%Kzt{?~Vz~&+v9M@SRLB5E1IC{#@ciy0 zI?^{0&iTkErxHCEYvRitc~bVPr5DMyYzn{_ZC^GFBY7ht$SYMQEjiPO1xUvYB^#^> zve3c%=S5@8o(h|Qhn?ZuTI#~|kCWv9H8^em&uG{yDPEwRK&j<{MeP1{Z#ZjMLns-bOqzdLGJCpzjjjhSvgH) zFuiw=v#J(q0onJilj8y0$dsH~Qz+s|-BBsOm3Ny!WK~fRtFYuAk6w!vu&JYJ{kuQ0GBp@DBF1GY}4k{r$ zpSda^&F7A7J(M1M(A$00aOPPQ#+=90WhU?Urpt5V>UCynKx4`*%)r#r3x#ln%Icdd zA2b1U=lK)K{aV0HbcXr-@?w++afmDPqKAO6ySA7zLmdzHDxuYMenuoRhumu26?dnW zAG)x;c$rjl7OrJ%5Ltqt%nk0QUA$Er(;}!yepJvM-%Z<`RnN97i;78bWSIMi_NXzR z;s1G2uf%4v$V_T(gBQMK0s$r0L`BY!X8sC&5|gQa+d-bvECz6>(8~7!QCMIoeFpeU zWUC*PwRy(M2jQmY9UP!Qv`1jlt!2f$kgnQZ%*~5{BM!zY^Nu+cOwYo#w3C7Mb9>ST zBr4dW>{=>KvEKXVDaaTZm?tRg&>f#VUzuC@;_CCk;t^x1)iLovAELRYX;X=Ueg10e zhRd{QYY*OH=2-p))ajCTWZm)5blFEi+2?$S>StU;-8nI}_co3s4ql-RDKM&Vb?7~% zbt8DBFse*tDa_CYV)UEjs~zt2+G$w39YN4+;pCyn1Ui17(6_!Z(CfwFu9H)u;R zW}2;r!3ZzFowDZ@u+Qf-yQnqBebFjTtkND%69jjN*@~38^Y)R_Nc=j!xnL|&llTHF z#pEAsDd5VeiEWOMS$?Jn~_SE)$95OC|{vT%FrKrR^e1K_rtsb2^;_b-uog~Za!!fqdAocl%%uv$GZ zg4J_>pn689P68le<2z?U(#G&O-AHbANgL8vZS%?nyeG2MQgfB}LP?NGEHx|=LD_7w zm4O4$dZ@9-%l`r}-l0SZu5YN}!hVrhml9xcmz$w*AujFA2aB=i$42 z3V}H>fKTm;=K~fuGgcQ{sz8sFNNNhJ>UiO-7MAs#A_az2?I2S>5|Idsv!H^cjJq_= zlt7uIH3@*-PMiSY;An`W`{n9fYhC~5tFH?4HyKv1v2TKWN|r&0sufI~Z?zj?09o|j z^mb2?BaICTFNr|w4hS|gk19-u);`X5IK}jbZHDJB7kn#RMrfP~c|fOu8QZJ}2cL7h z;2))|BR^E9j6vdVNBhpokI(o4DiQKHtHq`(_YCayj{SZFWLu+K=xjSBq1Xkk&=_@( zXkIcCTyLq$@yAOvvDX>v7KgTFDG)Zd{a0?XQu_`<%MAuXbs)*J50U2J?_s)l3 z@12~EaK{^;p_UeX177Qd%Vb6)fDzRe@kS5S8RPmR75+p6f2Nu>eQUgg{DF_oS=)fTb`vgpfl$Mmk+o)f$ z1DPtrWO3gTg;kuTtf!kx<$xkzb4+u?&^ozGfUi)G6u-FJu^5(h6D5^RCqfUq3ltTs zKaxr_O_8mL57B6ti+mi-qUviV7R+-AZZe94=B!|J{vJwbCgj6%V5bgbfq_s}^$^jj z1dJAya*!V*aVYu-#bPF`DE=J1T`pbL(S(Hrm-Ld8S=o9zxq$*NQEM*Xt<&D5jd52> zp76NR=BL@kj*ha1c4%oD@GFHi0*Ogyx4%O#IGRXD*zb)Qvup#uh{n*v#p>8Qhasp* z40B~~X#e6y&cPU&XW#;4MLai5SYh5P?F}3pgU-R8Jwd)kW#zRZTS&4{shfynV_m(p9Ko>XT$U?gD!`i$5aN$ z1#|h24;yIZu9}$Jrr9N=&Z0;r923Tg8@@wI+q!CDVm7)>k_b5FFOxWqj&N292dq|~ zK5}&wgf~GI=wgbrn{GTAlcdtjpgiX4MS)}fS}S>M9HNR7^^i%fN-<@(Mm1%e zIokSYpsV3%9rRS}&1Ft`kH$g=eah`go^D5K{6UtGlruU@rZYl!ossU>22qj!j#p1i~P^sD_h?|N_aNotu!pL_Fe z_u$=l{BC?u1;R(q4Y&T@?cpf)*^77oJiUqwHv$H0c$UVlv^$Gd^4BpP-dXDtpF2SP z!0MoeCF?P_`*vk+>+kz7uI~5V&21fy@PmD2?VjKKDfc<!knU z>giDi&zoDH-PCU9bRRPQ-N_Iry*kXztsPjgXnD19Y__~n4y_Ae;Iwp4PRCaZ08_qudRC7pZtRrSee;g);nn)o>-|;wD6zwaX&$qv_6%;p5Yk*aXi68wI&kf?QVk}=mmpvzk?Iz+Ms%+e%kMk5A+0; zypN^+$z*+;LwpUGTDEJq#q&C3ur?0V$e9pPx=k(k* z@$I>OhCk<@jC*fVNBB7{53Z=wkuG+{pT{{xeO9-r@E|iv|58wB113qlSrZR-BK%n z%*!AUL-fH>=!~I$v_K`S)g6#Il?aLZKCt~FK8EVyn9@MySs|Ct>LQo$UYynms%IEl z;O(FmIf6vjfQ+ly>K-z>XSOxJ z$3^da$H@PC?7{FG%+h<~H02V6!bZP%Hf4h6-7}?1pSpd@Ve}qn+AK!R+h$QH0MS9p z7wpCK-uQ#|H9Uc@8+TXXYZ4AVb2!50djRLe?@N_sSH#L%U`}`qanP^g$3%|KWF(++ z0?)cs{TZSdXt5-X*p{W8+8o#+3MCxM>;}d4v|G#RyhW2Mu(q@x+c~CPS2SP;L^%Iz zm@GH}rq#!tt@l|@w>AaLw~V+nO`_JMX&P(DeDBL}LrkhgCv&WD!SqFG3abczFAs-1 zF!idz1C9wWa>riIIHsD8c8K z7lqvnI<9QC#?m`9mf$e)d5V~%A3B}y)*h{PI?f6R-Z^BrX$`EAwlQNodb#DyzDF)h zd}6a>R)y}q_F%jfsbMhlg2|fOQYnv|hIg7U-bEyfb*UhWY?{Xh-H|F5df>H~9B!kq zxpDPUZ|O|v+e(MbfUx1mi`f12pMQpMz{gIrbVG9pB-&Vqu?8uO5xGTamqK-<%B~Cd zC+MisXTmmd*IM_`H#nL%w5EVF&NHCg$TbUP>;W^Z%Ck2-rOn1)$Gw+SWMhOq#=}EY z^Ue|W2g73)AJO@fjkBZu;o$7~1B8)ayA4jBKO7!C!1Y&$z0vdgRJ+)~{bAH!wHyCd zR!SJ20fIR@a?)A@77@qhi0j`yXx&;~`WhF|AvnrfE?+I&T)3S9sO=PRBHAO+5Ac;) zKPgYP_|EYKsOS)HHljq$3m3W0U*!axcn~xP1SUtd<~Sax5R9H9^M@tH@&gyRv3P7m zQX`8P$+QvMV)JC3u*tR7JZ%>L*oH)DFm#S zRZ!R7UQy5(_d-)s_>d9F;&sseb=x)+>L2?T7QpnEoB`%v)%8gy+YU%E(9fUz{K=hf zdC%r2&SJQJZahvr)}}Umv}U2Qx1YFm^=Ewb$t)@y;7UW>?_F%i6atNjKe*jc7lAqrgy4%r5H~GrpA3(>X#XeO{%;o)Gp^;i!M`W_J%BdUrsa zI*AHi{KV^~sh{~cXv^4PPO9X)0&NM+tSNMO*vA2(6V%%=8XBt_AU$_kSI{iT@Dry{(>z3;s&;+DqX1m7q#8*2cm(Qv6#mqpnafVplMF7 z`yCYIitnA%5P0W7zYA6o_+Txs`WkNC5oYf#EG)dxv{qV=P)v^W5QE230!k=U=pU4M z<3c(u$!9znF0_6`S^Zs{HdHZ2^~GXeU``$?>@B=pXl*kY>I*N))ZXUKgdXu)-!Iz5 z4m^)Lj?U)6>H*aHsbK^w)n{o}p)0K;F6Z&eP+TSi@m~`<41KM&1EsR3a#g%LxmY=c zrkj}y!~3D?7{11yCDXBsMq)QY=P_!Hnn>K%>+mo$62=4j&RZ|@+@YC=JB^$DV)#|N zaj(QUOpET|EJpSMcPGr)4tV@_z!tB3h8rg!Sk$FpNpvD8r+{+)@b@1*is5VIdW~a% z5+DFVvS@Uhl<|^7rK>oaAkxW~5$X$$QQyl~L!EGir{SwI57P`=ckfX1-Fp#}`4QV1 zSTV@GF~u+h6A4{+>-|5Ew9lah!gd{*07OH3tH3zt!`Z-Tp{WipMu_7d$O^*z6tJzlO=}KHp!|0qyPX6;$;m@lJEr3rovC{hLI=|DmAbM)fc~_5j@AwaS&e%c%xq`L1P7@*rwCe(X zm$ehAeXTsD)KFR_Yjf5T`@v36ZA(C0RZoZI*>3;@xMR0JPIq;FHyptfBauO$a>=n{ z*_!+R*?aqjxQ^`H_iy=Av>8nrjnyF8nal)Rc(9CZ&XFY@K;z^J2O&TbF>j$kvLfrd z-`}%dYS-Sqy8(?oNzT1=mo!TO{P}J3=K!r6SFXn5dLFf@bUfiRTh{?;dw8%`T(=Nyh`|1ATqo4X}hlq43bc!q1n zJm22fdB_~Cie3d$-Czmg49d>`20cTF9T+#sUi72^vQ+ji z+$qxNLPfY3x8ZJ3xej&X;?;0C8c`_qUM?_eiKO$zuK!kdE!9(~RXIMhg9m1uGd*8PT85%*wJ#(OFDM07s*4zXi*#Pt>yqgB+rN1 zk{~m{bz+680V=Jh3$%E5^S^8MX{^7eNB3D-w;$4@^Y(VXt`yXeUL#Pds&D8a)}!dn zS4>+eon>GXHtBIq3u9iV_j*qE{t&e8j^ka3AfXd(_m*Db9Wi6h#B z4KS;O$U*Uwlyf1Rr&m^F@F!xIs$x|lX1j+yV0Ye%u@mt zGX2biehY&Sc469J3Q!$5HT_=cgSzJymw&kOnUCY#Hm%`2W|D&j=KX2oJa*Gu_$XAF z+dQ&j?OmN^nbh0u>IJw~nqkA+pAG{vWN{4NB(M&sd96KS;aF;Smtc31)f{Yi;vOPs zK;sVPem|abXQC%@E+`YA50u;<9>cIe#*J9^+8qH2IALyi3{t^MSuop1YOQH9xd6U$ zXE6L9@5J&LF<{7^-%0{&k3=fZWCz+XeUFz1bn8UcS&3?NpzrzCmr`rp$e$($ya{R5 zyEHgyj5zf>4o@88;PT@+ra0nU9=}3$l69=SAT-Z}x8{2mS{h>TpAnzqs%T>$^k#8q z*;7`fhqPD>J&QUY?!P!EPwOmH0BpeYJJsuLgX#0}#9l@dwn((z+F7?LWxs?i*mgOD z=)EZbXKqVd1mUvY>itCgLW#xFetIbV_F!)7`0MpYj|ZD8Up-hItbK!hxJDU1JNyNR z&pzKe&Z7q?DmZ#sTSXN70$v`F2($6sqaOy?&np!3_I{o@l+Q?ySy^9S`Pc1-L5w$M zL!%LN{G6Tz61kS^t9KWg|ooIA)xU(C&^ZU2PuIbbLyC!!ob(s z!s5B}1>SC1p?vU$4X_X8n zSz%)eYHD+y?(Y?Dt#dO6$9~|$g=W1gVy2c{#@}TW+Z0XFb|?IHukg^L*-1rR9=Va7wtlZ`;RgBUttfh#`3Y9#QgRfH;z4t7Zw zN&-z$^WH=R?SV0S_{ZXL{rV^GDOn5t&MeVuC% zeLwf>>w#`)2?>BhR)OMw>r?p4>Vwt$oA^4vS%36>;Y@=cbSVKpLG`o2`s%l<|MGY+ z{I{n&2akSSdU_W>%5d;t?fbRO!QH~av6cBR zC$LkffFf-Vhp=tdT7{6}MvM+;65FjiL+E*Ref`n;;O^be{@E3@ciuyL!g->4b;A3h-{WQP|T1XlDwR+O*|;04h}Mm&t3v~nJY729AAPPg^$t!Q9^ zfwnX=1Z)h5t9;skcwhPkG*-<>lOq`KN>1I!Hv(jvm|ztQ!SaB}Om6XNdvDY$98ahl zZP^JOyKd^p?U9_xYhLUgVpfXRni<^g#&(Mh1>HT8!CfV@V?sobYUc&E5G09taY_gY zx2=;{Zc=CJ3I?qh9XT;gVNcoBJ2PKjgOG)Ac*`MQtxkDiNGi8*q;*sJg~v#Mxl7{(F5!l0yYSHz#;p!A>i z#j}Or494l~pQNd=J+6S6f;tvySLUQ%^_KhQ*qKJ?Pv@krYCFp9`{jj+d|fEA2|- zDu_IUAK@}tYsEcvXeu`Y)w7WGt8Z$nt5(tiIa8TxKzaogEeUUif>yM%)XR*!%Y-Tu zaUR^*ku^rw5IQ^OCuiee*UZ$G^AHQ!cb7dQ-(SgE?R9kS<>oYC7%!7fsO2_Z&`?n|`LfQo zof9X8XzJl+>TaPow9kajq&!!A227_hQp38SDZff3e!GA@dHl6JU(bBQJsWJSZl+aw54-g7gO&TM0q|`A(*NBO zRE-ELqe}vQxNP}tXta+UmE(p>xgp15eYJ?MIX$1&S1);euo2o%ZDrj`boKA4P>3y) zkwgq%Tr?CDg&E^2sJWKkLMIBl1SPkHk**A&D^RXj+|61@N)#};sm{BUW0?HdW_jMtyAk*%-V+G(DeowM@r>p^Xw z)F9A+s+B*zzehOm^?N(i=~CF0fgHE+_gq_NL zXviu6qz0YpP4%67f}O)edmZJjT7-tv<9Dt3Qiq8L&+;BWZg*&)3PrH_kk)NmH#dvR zr_jQ#vCOeXIzwzHh;P0&neV<1h{y$ulmcHFPi1WMqm+vvp+21qe|E?mBB@*dEmep< z_B^32^s{HClqbt(^5-k*m;Jo>;KjU01dN5;ijCcMAbIQ%mNgfN)oTwoA2kAXe$H52 zv|=CrJ6nqrbYs3?+KwC{U6){ zJ)srcY=$1*8vJ$T!IRYu=M&W%B5Cx=M>n1Q#w!Eec1Fu^Qaj43AQ$cp?phnCQz}ep zrvSb!tPx*NFtrgb;c=|OuLeYJAn!)(k^aKmNcJi?#rCWi!X!?~(Li`m0HJ~?O+d(6!PlSW?05kou>C!*FjA8nH|}!wCSwR(Vs@$~7?P?Ps>2@~PC902Q^V(-g>W83 z2gUHwlVni_(AhY+Oj$sP!JIQB@UQP5?T9)^038qhbN`IQNR@bE9)4oX><|vU5{Nq| z)J+yFbHQ`9|MTwQ1+d0+062*3_tiK8BfLPEb{6S(N+h_SbNrN}Vv$*`P)T>1isIM| zvwe=^(gXt53pT&9TD3|O$M!5glZDhd6WgUAUl`Ik9Q@pzk!53v;Br6Y{dGF47I+D!RE`v9dSTJa|X<69!;QH#FYG@l#o^X8p3rm6MIvl`0T?Omx&J zR*mxMca(qCSYN1?#U~LsHN|E4c%4(e=9pvH(enT1{9xj|1)cj^tj#xaci9S*!tLm zow!|AV@=O}y~~Mr)%zS%7T<0#vOW@?&UBW%@%h|Ttp-~yI!i|o9#hND&FtR# z)zQw+IFt06vpr(SdBnP1dI5Eej++G5!C=EnE0B!>Kh7BbXB@O(eGBeDUC2B^=NX$ zE)cE84g^j3qx+&j&K8JQJ*^-M)YnkWf zQ#<2zONEX2Vd7Ux4RW%XOpAt?7cp=e;d1mNVyXCjEmW(=agDLmg?l|YKmKy6oIY9ZJ0=Kqrv7IHPk6!s%?-{cyO%1p7re> z+{pSeI#ybgN3x`~!9$SA=O-sljB78C(O&fteK|b;37AQI7sqyzx4U|QHqp4)rgc?s z5`!e`n0x)6YOibpk#f%Tx#uNw%JH~&bJ$mrl7lW0MZ=g2~j)NKXhBnoMu=Zq_k>CUJ;?HOVek08%2qt>6xv{-q4aDpMj2vWtdvq4IArZ@TV&>1unik1 zwBGc$(FPbp-oj%Wj1dv$N6mcL|9`1|H%-0Lf6W_^s0LVB++YvY=endDhTF4CK2dQ< zTWV9qEI%co>@0RJtNW`n(Lm1Y0-e)LqkLDc?aEqlc(Y_;7i`VtsXpY?L!)qndKQEX z)ZM-9lkipROl8Vu1nDz~x0-}uSH=QB)ecs(G+0$bKN$h`I(Jwsf{B`6VItB#P$woy zCs)PZmzhd6$~T2PV7V_9HdQc*u*YJwmR^>Bn=a+blHz;LEY45((~yuzu40T0^+D84 z?^WM3`q7^7#d7c~M%yy7ii%ND8sEN$O;f>Sez5xUE+R`u^ZhQ#WVF_IixJ44KAVVLe7k8jG_~3M)>G-71+>3w)#A4Mwp{kc)JYVUyK;H5MQwTABuKTI(N;2+nEzGHeb!150HF{|r9|12d z%?Xy1 zsX7xH=6pQuDu0#P4O_GEMy*F0P7F~-PJ2G^A;u=~q9#ErZq!33S6bW|X!tD_d&Y1b ztXHevzqrged}6w$1A1oZum|O?w49lbx)Q6<6@DT%U~a8k579<4s?ZARFN|Tb>F$$p zd|~DThBKU9>ZekRvn(Ps4!aFwf?-M@g&rCL$CZHz#Y8HPMBTnbSsNIQs4qlw?L?Qb%%*=h)aPQywMF=WuMg)6`ERFvP!e%sZobXv3xYJ6L~MV z@M{}0T`W$e9c;_%jw?jmwjSK$Fri8p@^>~dX0C69y{75Yp`HyzhA|iCoOKH&;N@k~ ztxw|xR>+@8Hr4jE0Tie6nN0Q~Fmm>4Y-J=t5t1>DbCr?%sTPSUHsq;gQpcaHKR|vX zJ6ochGICbViJgl`KK7bUGEo;kszl~s=%r{t9+!)utWk2_l!?TW_}0yDA3XYM<-x|& zq4+On1h&&C7Cu1)2;`4yCRr!KtG!ch>#wWpPlw-aZa&`r?$O4ku>1b@;8RP;?FC1G zs_!Wf*~-NJ9$X3@gvU~ddH7`KSz=~OK@QnQafZk&n+h4KZiZA~by&kAqa33!CObiL zm*K|*zNRF6P3?tu;^skjH#_aYaT^ZTagE&V7*nNywmwA?ZuhJJk7GcS2}y!HtJj9W zGs+iZmoC13bpOfss}D&!fAq)}(o57r;fuqC!6De>YT;_L(cvB?F;#TE>12KN{}6@W z+pf(x2fNoB#Z;KKzkNp3?~XS#2_$HeKYtE=FK4PgTL zm7QwAAW#)<(LKCZfGkFmQ=Ir0-?O3MYJOTwjeyl^#sa^3t?km?R|Zk3Hr)nIj27hiDAf)wS2K%Ii$3w-OAstDUkyILWHet^grw#&O216>8ru4em$5OXc;bkf4Y(!U9e0$p!q6RyMThZ+ca`?-dGC zXJk`Y&ECPz>zxBGzNWGR3XS3~XfpCLcvV8qUxIL94{?ugLH~>DVg^i5#GM8Ef2E1? z?f$s%PegIQRuJsO?k*Z^_yibOHFYgCydEROYzOnW z>l*E@p8EKL@}kAL13B4_D5Sh#f5k0yLB&CN8tB9D^4XoGJO6Y!UJ4L*Ybfsis(88{ zMV2LKlT6ThRXa{JTp9~We}bScBcAVBuodF1pME;H`{~l1e_p!tkJmubuY{Jrn8!aP zB$~W@YMKe;mqKz-6dc`@XF{glaGOaE;$d0YxIIf`YI0axz)une zBeSP=TaC&n%}3Fkr6noq#JY|tF~x0wz5uBo0>zhCYq%61bOX;ju>sA8@Iu9SP#K52 z{Dq?L_c9~TX>HnBJ@It+XF_CRpo1Q1?x4q+v{dE>cTa~oWegu$xf)j5x?-YaXYtj% zfg}$ewb4OILlxgw=0di$F0;?-d8}9qsFkla9$nxDas;U`DzyLGttuSQ};Od`%rZgxh7?bii?sg zm$mm1wnI}#BbB!Md1JiY#nN;e#(<(?H+PQ|pU#7=Uf@YdLOh3@eoy_;4Gz`}M(6hL zuKrai4&l3AP@S4V`Jfp7{4IOgq89OK>>@cp%z~~d$@bHa{!LKTWCy-*m{S_J18m$5 zrqIW>*1!y>3Ojtl7SLR&C%$`jaH?ab%sE10lr3087xwA}_Fu|mxZSFlvgF=)X>pN+ zkFl1-v^r&f@b{NgN&TlgcmI4>okt1W(y?tj+Zb(laa6uROCztlIq9AsKb?F2R;8aP z?a0*xb8O?sXcVQ+QZ}||#y0IX_6WAnf%OzU8*UA? zOG}nD=-Kj(*NdSQ#%D>C5$_+*4+e9hk&x5gf~qy5?D*be-@(1@n*M2E3QgT%ViM+M%Io75 zqD|%Qru-scqcx^_6RkSRQG11FYj}$|R2F4Zi~Rh|{kHZK*VgBvHq?*LagCLZJbT^% zl1%1KH`wIii=`!Qn?utg#lm?r8ci833FhQEi9cmIZrl)?NAYl&oLY2Y7!#qTb_2Oc zJIB6wF^@ZgFSNxu5UPYBH7<&r)Cv1Ir@=3)jtE6C4L{t)Y#~Jbo5w~{hw;t~iki?u zrS6$FNzeGExF0xYV1@%dCpx16#dnBpYLbpdDM&xql`81iXz@g5;E4$ae~xvB%lZDP zIX9SuZh6!F(<*VcYZs4N#zx$mX_M(<_U8U;lBDmMApJElyubU3+>juX+4!}lb8zH2 zUs+78?Y)a5T_Y#pOw*fOh4#WnE9V}@Kypt)N3D}A6VzvWB^>8sdlq{b{=#ax3M;e? z1*23S7q|M$QY7?83g+PBw(IQqiTR!*J4#OuUg+O3dtsLgtF7NCRA_IH?L60(x%l-U zoWIqd@s2N3wQTbC6AbCE@St>GTc|TOeS`)099z=ZKn4nK;Q4tcfP(ix5c7kNy%muW z!m=oQ)=M3_;FSAlgbl9{wC6unoQqV1Q@Y_gK-KE?UEwsj?XBDfiUHXg-b2mh20D4D z^C!L?a<{x-!z+=F{%gkdaj*xUNF`WIoRqzmG^yF-rmwh`cfyrDEAD;#*DLcgO z%~mMNuvR)RAtdjeh74CtCs6!R=uO6p&>ueV%8R^Qy|Y*-Z65s^(h?4 zPQO%*Tkn0wVNcH~em#2e`2dye#tk@jG#!j6)?0tpw0N-gaP{8S+}2$42nNZ03*^;| zP77pe*0dnu>C3@r|363){!tmc7T=p3bUdKroBFiwzQBau(GQa`KL3z0jR<3HhUG4a z!D!dS!UT5YSrBE_D_3~Hq`qK;n%S>xpxrlnu!sfEk@38uZQ=p=&Swq{UGn4qKD)DK(#_{UEcm5*u6%JIXPp~*##+V?xhJ6tcwp)g_&J9~ubNTE8eOu%x} zN9G;YhKpw+%Fy_o-{&W^dFaA=99fUpV5d9Jb-L_ef2`C+{m+dR4I7P=8l5lgV=}c* z&hm+ML<=k3#lw95yTP|yv1T>gOHUGau!xtKg(wEHlLVIF?;n{^h$FxT`83;YctyY^ zAAv~5v?(QK)H^YTecigzYJ6RQs5hv?dp6z_n0%DWVd5;u?oV1_r$^?tn1|tn`|TAi zd2vL{h=`^RK~_|&7#dv13yGVt%C$VUX}Y?2eO@d$qszD#Y(LKKA{}Lvq)qmXKOJv9 zVc}w9myj$}U<;aO-5b(v5n9XCe)M>gIP`|BTCBwex@9l&Y3G2d3( zF(0+}V-Efognq{B6B~VA1igb5_PY>lG}4ca7u5y6{ZVjbH_+5k7-_Yq*VoqaW8O(D zhTV;v-hG++uA7;~mMuoh6?EuH&99!uaUi=IpiBo9)%F8!yzXAi=U}42aZyr(9r#q6 zPPn

(OrGqB@d_T8(OD`3#Mcfw{3OM(&bG#n&rFE;U{8S{1<1G%vXUS50)^tZkts z$`H4|9;|(hL{+1KicTEzgU;=@5ktH8-rM6QL|9jl9=e-pOSr-!pg&qMn}+H;VLr2=}o_ncCU4z zPu-Et*UM&6H-;3{$brRgp& zuB7QO8tB74Sh9H=m8@hBw762Tj@*(#(8Gr~Z0kMAUZ;T747*9IlWVIr^<89w?qgF{5abD)ua>?)UgwHkD9!zhbpI{k}nzubNxcpUbu1fJihs& z!%GvBH(wmuRWYU?y0FxY9CW=4d77^bCV9`prZRDpqDK-+yH&So9}jVupI|MY4OGU{ zue8sQN2DVvZ&1auExJmUFD^|27s@Jh1=_+x;zK%=NG=N+6_-%%9CCu%F%I9&xMkVD zx`dXqk`ibY8p@n9cc^+7?&vr;nCs@J4hr=a2M|wQgFU{N{@;hblx1LvGoh*^rsPu! zRP0(@+4RGa%F_5WNt&#us|d4dkV%X5R=TM7z-nDETOzh?XF7aB+gCMlqYI283b?(#G=vOOyS+qBIU?7=97A5|D5VR z179f(ADWo(5WG)PMWt+#K1BLvF(7o1Z2&32G{rcn3FLaHlAbG) z8T&mU>N)pV(XOl?Esg|W`s2Eu<60`)@CuwNsa^aX*v-pblLM~rJUUK6DQ{xnBmZL1f6R&$p3Fi0Mo{E&$WV*8@3NuYG*2sT`QP*v}O>& zNhc#R_KLrq7yXP0hT>U8&PK`yp6q{k*f0|a#n9gG@+V-_J3>6%66I+cC!IZh5_S z9Eot=ZajAz&jG2QmK{ePg+3NY#ii{4{jKh7L1{7R;lZB&H!~f{pGyySdaVpS6u}_v~F^F4vsKKHX@>kG$PIg|3>;D~fO?Kbz9Ntr4~i#Rq+>I3pswZ^F64)%ZsB zM^U)K!3fSdzMBVcq;lHjp|K9;gSUbIV0W6vp9fyz><@hBiMp(;UfJu`Xkylm0Xq&{ z&e7BzTMAV4oM!}#IOCaJbQbj5ZgzffuF64R=??>MRi4<>dQ&EN^6+1G|M@x$3s$Ry+kx4B?rK{wLHo}p zHN+@D%I#(AI$F@&jMW`y`MgS-2N&sk=isG+0xvbD`?H{HZqam2UmCeTZ)y}YS!13f0R?R3RC&$ zl)fYF^o(+>*xTWEoM5eL;CA0Qn}== zR)uC^KVUdbDA1Iuoc`qE6o^yq^r%>0B$XWO*=c7i@wKnxxHjd3PADHVK7|U+{&K== zYgGR?>Swh|_5sNTzovfXt6OVPQoBPHD(YF%OFR#P(Jy;~rqjLa$|$no^oJ`CA*{T(!?_VDi9uY*qrCd5im7;+H*Uzh9Lw={JX1C(YLO=12Ni4DKGatArm zf^%NyoeE>b^GG#t2`CGo4oM{7fpK9u))8Lhf>zTwWng-`XE%&i0W;P z1|Z-|Y`}pS!Y?ll)?4(Lc| zwGYb9o5l`OfzcN!TXRL|Hf77*z`CrsK_&Q;3DlB$nhMjWIOO+5bWc@lXlXd9SqLNP z*=2bo&7L%~tKlEU%Gx}kVI$Zexvo5Hn_=P&?Xy^B;C*^q2}kC9IZic=L|TtTT-jce2V_mi%f+h`;vxnrIXCtteROt zH`%X|L)8NKJ;)Q~f$LW?NI6>oAJ9}wOU_g#4nivE#*Us09#L;sgyqa3oFd# zs2uN5_?atEsH!SYk=BR z98PKUDbWK~28rGeV1p_Zpj*Y#KKKQjQDw zbqNkoBV+mmleZZ)n)?&05L+wo-lXvH=_279>24AQz6>8I4er0%IVLqGMFHlX1Hffa zV*PYK_vqqGRT4CugZ8ib<5$*{NnVqA9wZIX4_`Q@WIqgsTfl0??2ismIgDri!asC8c$b_gB|AhLaW1O-*x$(kcrD_ z7gJ`W(*gWVGsBrkYeNnkj}D@ROYSDfzKx!?6i!^)V9~GOKl^MZ{6W zF*g}?*@!z6<|{1yii}(gDh}}l7)Z0ehjt6;^|(Gvpr}};n)Qd2I@ABM4smsm!*StB zXe+I*$5+zV|WWWD@gX@aVGd#P}fvxbOw`$>Z@;jKUd*VxGQShJ+p%lTPrn{GP@0Zs^(kE zeKhvC0tY{TaQ#r+WzV-sTPOdTkT?~EuqAr~43_!~P9obP$hYCTtTWQk8LlmCm*X}~ zXRGtgahz!yJ<*uL?5E40YCfW|N!jAC8d%1?Ye}%zAYCvqS(@+WaPk=9mp9dZ5ZU#1`Mm9g&KlIeKjqgkk?7dU`SYnqwXvr)lkJ)`F?y75h`q(D%a7RLed=|eX3kKC0Zv~}NOG@WPA21Bxo*F^PAIeB>Ki3g)?2foAjl7Dne5(}R^EoJqt(hIath=N&m8G!< z{MVP+rdyl+Gvb%dUQ)3C{dt82R%h`EkAun>h!vQ|IIO2DFbzk>9ugGII5|j_vDIc9 z>UAp1(98dCvI_+Ix*vqs+69@~4Vt=lQ`jtCi{F-|OF=vBrhtL3s7pIy6V9*iS7EUu+^J+1A3RIhXa)JLHcgHqR#3A!UJ zZEbuBfR`Vwy&!x|X)r-tKFU~_H%CW_eHL}A*3Yc79D_8L2@8C~?ToVgqr1Z{ z>{9wviUW|nz&BTKW|x_j+IG%%M$N{f9@oU|@lD?>>f=P)PiMkfW4BCv5;?Xq<^A-* zT8Oz0V3)N0te!-Vo5PSfOKM#q!&4g>7I9gGQJGtI8664?U$8}^?2{=%@Wrn@(T}*h#7pmCu7#RrzwRDnIuU%RF96S zA+>ze{kO#GA08`NisWnNmCmtbSp{twNEApn9Dj8-FJ33slGT9wi!Wy~UC=2DL(gi9-py&bZ-p$gn{gOBjeW6+88Su|-B>$$o zx5zE6E9=bcss>f+(S}n{xk{Q&Yq-e@pr2w97c7>5xd&1m%+d0}p7nW&{y5>NDPUdS zEG^Ms`Dls{(cyuh{110jc8BfVPmoXxny>_Aff}X?{yDrx$-!dLws3E3dK$tji!wUB zj#U}J!H%ij2n+iF)ycO#7cZa_QJbu6TTzVCcv#XHMUv2@A=R$9nI*~@R~Rb!Fj3a8 zoDJ@AuNJhXhu{jbsx73dy*=|Z!r#gx(hr#a^bTKW{N=_;^T1LYt)_35psACg_GBj| zdkTUJ*$Vs811`gFFqE3&ZLhMqlb(w*-$X}2XvLIDgRIXNP*@;Oe5_RRY&>SMsO3}R z71c^pakVf)i77D~V{ldJmoizgZ?}&sewSOgKvC*hcFS*Sf5r*Q_DArf+N1Jq6#UMy z=B2c-UI%Q3CSP4{Fz$;*I%m@QwKm1zF9AyUzWbN4!u}MI;5cg;U&TzGy?iY>f_{?& zbgjjrKhyxbfohD2f|~ofd2BB`NZrWWG_){d3`r2nE-K`Zl3fJR9f1Mh)o`1-I+rfB z#F2E5xN_Fd9l`u^rRAzM+0%~Mrzz~|Ox{Jb3$in}0vD#1s=U@~Y1s$gXgNO0!S&Mz z@8C)j5s4VLYuUwas+oU&g2BSoMK*;IBXspKI%6W zPt@M_fW=fI)XMepQx~f??DF6rV)M#;t|Y3P=c=6z-PNg_ek`I^4GPI;115D{8e+eg0X;_59A(ja%!zYtz|1x8w3^oi+!o1)U1*~lYP}f*-2y? z-Dzm2$6C1QNuN@stsW#7LxD7PVTdluMT;Xudt<>q(TX9oX7R)i#~BN=tra<(?IUqh zHc&GWXdX@c=-}u5smk{yo^Eps$CSE`-^uCRjOLv+SttAzXE-xI4DSW>O|(0ig}ZE& zQHDo|q6#uMVx=2z=xk2mv-N9Keo>-rUuHue$7vgTbqhj}ot})1b((lOL3z_hE|*)J zlNl(`dK)qxWUJt`*1$Py?C)!9f9zOY)IFvUTN|Hjl0w2ZN0l;Ah*G<1Mo?1$}SkeL;91vC|SZ3`-p z6Y$1B#%z7%y2~9by?k(w>Q?DfYOhb59IY0Xa+g~6!bF=^VYVAL@GkfkwsH04Y4yx_Rkzhx!Lc-PT%h~1N=D{B6 z33$;TN`w(Gm*{aUdFzmgxI2C@v-=k#QoZYAceQl1GeOzC(^}=t@iDevkoLr7LZ%l7 zA+pdYKVDEyCyR7#WG2X;rtFRHM$56HW$8H5XcHpi1Us@B-d3+=?)sN-jo1e<)8fFG zP*b+uK+Nwt!tTD3%Q@(PX!91VOe!O-)$rxlNrc1a)Q1-;KV)Gl8PB~22WRJRGqb(! z&2#_^x5K^m+nDT36=8Z_e4rINZ4J!tYM|uD&9a7SJDo_hNw2a-p+2d(trFsj(1INh zd&5=7s1kcbjL#@yu3PZ%u-RS6GPeeb)tJYo4LUv1Nt%#9cuL>O<25?s-k3dQE{0bQ z#qualHuF*7@h>q+DuSB^2OFM=8PPkCmkJ*?>5u=XUT`1uj=R|rm!%7=;z~M7$xEe* z+Yw2kx^Xmk9;}XfvVNfXzQ44OqG*;1pM16dYUg~*|Gm#8U|f^1b)Q=?xnzAWe%rN; za0Ko|RP40xi%rTMj}KL3;_Ba6Khb=$=T*u|o^Ne%(e=Ll$&w1(^hQ7C_D%}8ecpO# zSz$DU)YguL0+@wxLe*3J6LDL_M@9^GyRZ8*=egbZ>$UamZLTpHE?%5dFWqj9P1Y6n zGueGjQ<}0NLV!3ut z+oJhm_;5i55mecDa_*CZB*!LJSccX2+k2EY*<)zKow&@d=!F9hY{v;u>7}rnM(@ck zN6R}G=O?-jbF{4PsxUOedaukj@5ZwGZn^q%d-c%+^;%iz(|eS|Q+)7RBP8{9Y)<|5tvQQvZBEeP=$t#<7PF*tg+Sfl z%-pZh3G?Ecg||nCUcK5DNVh2Dgj)-wwuq8^=j+4`gDmB1Scfx|?fZ`&ezW%N_G7Mv zzGsteR@eZv)n(T2tKH`JYkpMJ{^^@yVPTQ~&*i_>eq&*$ZjPqCgSU9qT{Z2)YMV{& ziJBjH2QZ_(le5Jn+7^Gf4C=mbnQLI_Dx*6LA2fK+ry3j4m^H4x+27&TLUy1L#Lpy2 zN%!=dFXP>PmkY>xXoTYrHRm?3ecZ-7O>UTrEImn^Xux5R4&I!c{iIVC>>88^6jf6l z#+;_wIXgH}YS_*>K4#n(JA=7ztwYI)Xj5jbBhdaki_Y8|I%AS+|y1q;NlE z>&R^v$%3dx+u*7w$GghDDuXzpgSy+eyZ`9>$B#Bv*S8-$y1(*Zn~Q57ZLDoRTL0JC zSkx4!%|GQUHP~SS+z>W}hO9<^@=+K+ltE3g~zvEIoE@;yIp1edi% zUKl))vx1%IHk(dL(e5Zwc?Iq#ws#Cm(v_aOB{9!)6p{@VD9a)aNWqnNr zP`4khe82jBVX$$6ON5{{IZ{}a#x9ly_aCjZ`Ca$eSl!%Qd-(0f?ZL+SedjubE!p-08Uw1QlNV6t@DW;C}Md&=&)jjFe@Zn_Yi7wIHI zrZ%grVDL%m0t~+)VG2@FAP%o=b8NAR4 zklh$ci8uZ;C{SYRno(7clg|qL{@pFV!uYGz?^ZUqAq?y3u0NFMch0tWesr1^&MS6y z7CtON2D4GN?f%$F6jj!S&=eNiO=j}6#~>jnPj~`-6-&l?M5RTi&7s8R>SfqmUH^Wf zS9|ECaA@A{0K3G}uIo-h1Cq_Rvi|MHM1S4))^&E&?w*T2x&L$f`NaWl!w$)8uCM%c zZDaeZCuz9}`P0KFdQh#QDs9L6M$7BfKZEikhi@t^5XtUY{chviI zh1|5BDa@hlR9C&+WxYR+?diAl+$?GtD>d6*)=(5^INKlPyhiph26NI4OOnT{^CIhN z0QrWbc^T1-#yjLH?H4mpyUbB--Np6Aen^ob+njqa%Q9`ex#nAS^@%wyLqmX=(P!gWB$Sx(8Jql>A` z^VVotHWDPj^>>23Cc3|Twa<+A&8wFT+QnOlgtF?9zcf#6iu3^Lns_;iojKfenq}c9 z05(J)9$+QD&}Hsk8|nifzhM_QS6&|b9RrV+$&I5hqR`fD=VNsVS1o5i-Ceh&mRP(? zh=iNk{>FI@8w=L_J&xZQ(`+s5$_u#e71q^aeb#RJ(wa*o_d(c66Xr+C2yf>_f5l9j ztvmfot;CH>2OtBIWCyi1H&??tlZrzTY!h;!V2^pGw#YVWQLkqq6|LjxFjQO^~C&2`dPCHm3P%vs_ zV<>Wk>M^cqxuJMNyb*oh^3g>;jv1S~T|ByOA{6oT#o!;a^FVJ8aTX|y6wP@Y^q6m& zHPAk*4#9?xA-u?yHV#DGed_8sB3pty8%ex8(^V4bd&a6)q$rGoofj_%EFy&LI&G_C zq?chvP~Km^_*$2~i>WTe8&QzqA(JU5sQU5B{r|o4?W&nhbt>iLt}SI9LJxn6*4qBo zNuz~}u4xh|NU#E>eW)-n3Y*`~o{^K-rRO3aEt2 zalmnTxJQMV%e1wL(T~Ut=9*gux7n~Xaa%I8d3HJ;j7|opyu7XdORD^3@De}M;AZpf zGh=!U+DZa?NN0t{?P_TT5%z)?y<<41Q1pqH+uVu1i`_L`{I{*~ALh6AKDo6u{>1*f zh@M~{@gHkdN2JKX#!g4`!03pVPw#pH6)`0trhfBjByIZ4 z+0s3u1`IdOU!9%2u_FcR^3xvea~a{jrC`nnTx86|VW0A;!{#$@5v*5}hFT?FPR_8v z5*|Gh+Nm8APJRi>Lp;j)zrFX|PdmjkRtB zhj1YP{ge^DJ30C3(h-a{C#>!Deak(b^t?Yju@C@kJPnXAAmq_LIVPy5Eo2vo6LUG+ zRRSY{McZ6b1qnc~&*V+vx>%UJJCyCtSC6T55QQ*T5_IKcl~!^V!U3CDqSYjHw#@83 z3G1zQ^G{bs|IhZ1i0k(f)IM8Rok(y}Oe(vF0FmInjI zK2T8MfTtZCY+O92JoY*HC4;#d<$=wJ+Pt4D#OTGOs@PoFaS7>mdodbX%E&_X9(1*= zS^e-!(CS8sl=@kQ|Cl5bG~W#;+t>^D2J1v1@F3C^zap&}4LGe9^ zc|2Y?IeSS8*4h4IPSw0(i+30PBr+Btg_wuZiBMt9nf@7-&m6T*!Jpo_;}FxUK_IV; zECS>cNp75GgHWEI?5T8oD^m-K%n$6fXxz@eMdELM);bZVmZRkpRg_d(mbcG6*LfLe zlX?2Uf^UPED(3XTj@Pl`1ZA^zp0-H919tD{BoQ*TyfXrc@b#0YcYYi#=NMc->Qxo|Ly6W(LewA$<~7Z_g4OKQ|mRnc~=|4x@%x? z9kuB;D)_gi`7XzNUx?jFiqE)N`}h)Ydcnw9l<~8pegN|ABm~AIn+v+@wG#Jn=&aMK z&WX0e%$D$|HloCi`JdP&|C>2zOzrY9+YM(AX#?w@iebYyB=RLMSlDVlMdT+R|2E>0 zmiZ?USO-$!zS1pA_|^2vfw_jdTt4_yVQ6rVZEM(Zru{>0!5XqqWM7@^H5FIvD~M7` zNVvUf8I}>>?TiJ>B9r^voK^XSD^#9|cG)Q3cu@K3gTx2*7@mk3;xf6i7R09uj9s`5 z+y_Lby_=M@z0JOnKT`XlHaWsn)cT}fv}8LK2VYick(J=9sr02lYgxmNRugt$IP7XG z@Z+ieumEAw6_$x*aHR>6J8ZtXzTpRW*D?5RgvB=t2xB>{TA#-1LCw=wrn@AcCXttb z*}h1}l$fqgF)Zm7rkl?iTVc4`$ejx#*Tx-Dx72M{sV}J3J7*r>Lp*IFt_R^}8|=J< zukjmqm-{?3qtM+2$}t>a##ISe&?ue6V||MnmyPk1*xkjMXtHbh07pAN?QaW&jCoIH zm3q*he=n4DzNjxo`ofF?G0b3-;yTUF?{r-B)@hSWhcPzP{u!N0=3ENeG>EPTQiU@l z@lJ(Lk5#bC0(pY#N`OVWgD-m|98ATZF?*3|nuc;}&38hi8hS{ielXfIKLNiN5fBPPtK!a&VGck7wpENcBlve9+#y^wZvV>KBFhAOO zrEY3&^VmJ7O$5Ci+BM{ns&zORjW=FAa3WiFGMhqI3Dh=UT~1XDFolp(ohfN_N=(&N zw#wL$;LCwvZE_o02By1%*}n%zJ1>>*b)D4XqUm(pH7*Du8|W&j8v@ak{a&7E9TiTP zGR&VkH5V38O!23~f(92mYEEMlYwb+6G7Aa&@qgfQzsbKL&U|(C=IAX?vB~lj*5bwZ zY>~vQMP+2!OZdp~2^oog`yV9cc9oID{?Gfn7|CVV1MP!dnR!`G$@mJP^u~dAgWUsOcGB5-m z?uc%lqxOY?FjZUagjZ{=wVj%m$@){&w~2myOI|vDqxY7reRKDX9AIH_8JI8<@8O; zz>M|DB)1u~DMT}g@!|gd>HOUQzK!V-(e69pWmY5-N5KBh zk%dSth!kfVHKV7Wn)_pdqI%-@Pvy=sketqYxt3Kfkz#ND=(AnNV`jGzZiZblu?bVD zP&p>f+~Upg*{&{YxU3mVblz~#q+YMoExr68&tJ{+$Hm#015(Y27-#&#HF@ZbD75bm-Oy-IHadH>{;dr7B&$VIxkdJ)JtAk)mk?pLzY zy`3%9odjpE-o_Nbr2dL^(4SYF(cCVk!x}N=zi+h?E8BBsa>|dn2PeuNC;|490}=+Vnbsp zp0WxaHV%c&;^Pt;lL}knBjQ&W3COZtTocq2QCPqZX6oeo z;)7dU=cSWZ?(R{(j&(l%>EM)HZ7zec?q$!}%nrB!r-`6f7)r}HJ22eglR0(p3Mvbg z1?QFgA%c)OyS{G)pLbLNdKLRV{7X}JP}x*5dKCb*#Cj7czVSkIx_k&a=>*cdeoW0R zI_}-eM&!|83gyM9Igh%U`#inh7-Glzu@N~Dh@0*I>(Rf-iC}!Ipa1+ z1do?Hd(1m*;V3)C zv}kidc1j9lZ|p^xHcL9r?U7I8gbf+xv?|kB851&w(Q@vE54TjSu*wK?yww%v_vXO7 z+^c#3|Ad`z&l5MkQP9HqZB91xy~7S;JNh;xB&oyuBgr8PZ%?4MMbVSp#BsC1zn{E1 zK7GzP*jI~XrU0cXL`S4Fjq-p#vBh3cg%Ae`XD;F(c=BAU>H$!i>KEQ(uj4U?vNuT) zl8`y3yNqqA5+A6tI=LJ|VOT&G%}#)E?Hy~!f#rQz`tzMX-7Wlc3(((EklL`_-Jah4`i0NsZ&=aQ7^AD|nRRxO~`c9eQad2TpH? zWbdy;(icI=Zbmj-6H1XdNF^wBsN5rykePVBmJ5P_{F&^^^g>`}KOOd*a^vu%+2Fk| zXCJFfb`%(EbV3cC)~M`#W4;rsqhL}g)Z!@UN$H>c`2t?@;8)X61DN%5yA#9FHKSeV#$?g-G`d1RxzEf}^ONz)LspJHXP{Ts|Fzpk^Tvh_2o;PI zx%RCn20S-D(ts)rT;qejGk9lm)$-!HzJ}iuxZA)eAB@iJ-(CHyW0vA+u^GA;wRc0~ zY#s3yA5=tJt4tV$ss4~Hqyg0P?u(a7dz3Q5U#>;5gFr+L!_+Q)&u3iCr<~_=7Rh3U zq)hTNT&=`RaTq2}yD5hgge=FNBi6lX$(twKOl8;FQSmB4XcAZ5ruR5WzrQ;_^g1{R z!qBE+DIq?X>)n@k2ak5`&RnBCR#qtnh?y@sQAxOTW>E}CPFapPS!p9HOEdoHqkN5q z0_x9K|AQ(!vaPZN0E!fvC=XpCyMrQM+7;0C>&o+39e$Ww@gA(8>C!-&9@Kz>sH;sG z%X`RJWVis>86DV2>Afa+I-~LT1JAt!Wj+IP{rH8)$}ZdT*9U z{LIR&l?^LahwE%pj>ejsY;!_NffL`9`OC*~=-^z+V|#IMrd%e@QxUz_gI8p%pj*hK zGS4?*CM6)_o&3lnd}YP0S8`}8=2RYacidJzodhF9NM40e!Kz+0*?g6B+w?CPfAa`g z!a~?nXwf24I4)k`k!wTQ#)Nh4Yn1`hR!QG5f9FWv0No`K+z&jr3!`v6GPgQhL-~J_l%$wox zri)ol8?f7-y3qgB4QuTQOdtHUv%${TdnX+FsTlagoN^}S`F?tE{9_AOg9)5~Tlkg2 z;M}Gm6jUF!a3y5sgBq(b;HtZj$4iccY>6Q{+!-$2z3un<440nXz5UtkKmPbWJ{xd{ z`7Qs%sipbg`Ecpe+r!=A(r5L@pYr)XMhBqU7i`H;UAp{qvde3AW|()N2Ba_e^$|=% z3_sXja|8C-2^8X7q5$yOBmf}c&h6ocgCX=A|FEiiZJ0z4cgx_^KXBNuiqIZ(wlJWf zr7s}RI1>7T%Wzc@Z%DRU(Bi@I?%@R|VLoHr#YQzYjYe%+=p!@WedFD#%|#3jIM+S2b- zhK_a!oDadT@=$iiukqJ|;6p3D-IO~hy-EfbGD_X3^|ld@Av`H%LwP$Dpzu0Yz7qAy zp{RKm-_Z%JwLTaV zu9n(6VZeIC24s!rzshJ*cZ@0Ik+}9!n8w+D6`#5qC#pR-j!1W|qqRt|ErvEGrluoS zxt7gbTEi7y;$!qq%%QEPVFe)KW(faKlWOR~SK^aTgqAo-68o_rIu>iWIT@JCVq|g| zPm8@P74BbGzJD-Xh5Of?BT^f3r}wIG)`2s;mb%mW^vWt+>#J6O5;@{c`rkAa?s{K$ zRXF>)h|QRF9}EpYtyMVt+*P<5Cs$G7>{AKyTt#0N$10=s@l<`&W~$AT!dUgFqDmX5 zX00v*CAPo6zPLOcMyrweBAON+LD+iidBaSFY)YyXjFzngJHl!4-&6{# zU2a`xWZ|k5V>Ra!2*n>xX&j%j{}?UzB%8edNb;+1h%X28Hpnl>C&wd8=R*U$HJE=& z{T`|TGzouG#uix!$nBG}ZMw)Fc&uE208D@4&oN+e8#lECN-B*t7N>GeEe^|Ud9VSi zSRt|Po#$i3&ADWOckbO2q-*s*#nVqFC+#eJFW!`li#2>;rt&<(js<&1^Q7_|_|jq!i_)1Sg= zzW9fd(@Je3sV6RSrcqrGwj~N)iKeSHoyc^DwBj7>eMAgtA9*UMQ@dp5CP;c$_-JW5 zt&0vRRb6d(OZ1T0l*BHMub*5{>YSIdQTdDo#q}%n+od@k-gmXV`z{4V^OfYd#AlyO0wmZ*6>DOR#F)g3e2f#^l2ELgPqL5P3AD=t&RwJ zDF+xh&GXm;h3#lms|b+HE_odz`bDq&5uNdu(Bt_3K)mKOq=nmzEwJb-DFdU-*yUDC z+7dfkxxGEGmA1mr6|qTC2$V1WuZL%os;6GYQ;0OlFi5ISFPybRo^4Ae^p=91SL?f- znK-L=a?9h^f@}30S(MYrs=lY>YW-#&A$ikN!JR|$B7b1ZC^4kuLYl**%i+z%xjqRj zs*Ge%a}Ouat;TCw%-ATcfo+S(m!NdT>&~x}?0Dtbwg&YIg%n*N%l#;F{Av+(1++{i z0!~3t2jHGuys2}LuA~(^qQLe6sWn`t;;Z3loxkV@Cxi};Z+*En{xa5N3PM>)g&AN2 z!@3V;RlF11j%`&ftiZC0Cq9OFLUS3H^<@QKtUH4u?b@G5h3VF-+frxG^3$xD0oqDVAp_6#_pL#53j+PpcYSnfIg$}7p5ymR|b)g z-;tFyo3?{KiMMDDa;S6ejuw&$Vlq^Xls`sM(q2zY3Q|=O;qVZBnnR{p4#ycut^rnp zjAZb010)3*+@xy~dA;iNIkxMh@7&SEI+EAPY6=16gqzbOCY&1ecdC#tELa>EVQ=Kt zJ`mC`oH|2kDI3((hoG!np$j$eJUn`vCoC+hsQG5f5t+`x7R#=g^Bg2rPZrIihnuSp zsme!D{o6%HN&VIHY}G3@`aO$=e~rgG!Q=EtT&+9T=S=^2z=?j<^VdwD+Ia`n zOiK{En|zi-^knlF{%%#3gvCRQIWhUyPxr$ zNAZWp^Wz#|ek)Kb#EIO4ky#>!E@^yY2NIIK*#L%)CwG`H#1RtrlD=<~KLQ&h*`BDXg*ZBx3EGeQY(nEQkP2w!Wsf5QyYLAbkmU zm+9LF1dm|Vw(9XE(3${?tB6Z0NzofRM%-!a<;R-)4nbZdO4Q`s8eCmjdRxHOaNMY@ z2Mms@=n52MM$U9ylbgKX#N>!X-8x297`ww0d2j_K+by)}Mj zaS=4^<}SRy8<;s}w@S(^NNukPcM#<*=M?RocC~FLzND?*CFp9SK`LgqsVPftoUCKl z73wYJEsIMk2M_`OPuh@W%3z}GuHSGEmhpb=ZD(pdp?JgvcBw8)Hn(7-V<@B`M>924 z`jxVI=T51*7hTFkM8iHB{!o9FtTzm-k`H;GHb`|d@Y!qq}L zr9>duWtJ<#$gUFG?j8()UZ!(fqOe?Pcz{U3{(iInoD)0BMZen65Je}0J;(Yr9r-W? zq@6kKHz_q?K6~-Cl0bmMHhy(-frFmx8>@jo1$=g@e`F`m1CK8M>*r*_C2~{T)~`b; zYtr*3ebnvGUCp!Dpg7#bWV#AbOlJQ1{x4GDFsO+dlr+;@(-qi8DUcDS6p*$DHRC!q zbA)%ahi9WrOi_nn*NIbA5C7EG?G(21zIys8S@%RNLl?g7yn+#d92hX1MrYPGtXXX0?$^(-PBuKrYuf9i z`%=vl`Twuhud-S&R25N5)61h27;|lsxFho!F2`vbr?yJ(^(+Sq5PDx`)HSlEl?q((mD!Z#dR=9u{=2cMCSB~l+XUn0N!e(>5u2K> zU)vu0HI?i3)@=#6;`Ee)bbSsyjYOtQF4XVeW`Z~sB;r#e?Vo0POD88=pJr=)n~LK# z=W1p~dP*^fq^!?>@yi$Yep&uy`Q9)0`2W9reD9YpmgTJfWb4hsyZ0l~OfFk@DH0?v z?@)t*KVP1p?l4G9r};gby)>VR!(3{yM#5R6M#Z$O9ubQ4e0ro?cq^opIIrNXX3r7Dhkd_ifx^O z1nFwG$oPi3O8m;>J|?0GORecnMcpTgJBBMzEMjfmVijiRRr8n}Jf>t3=aw=d-ASm8*@wc(HQrQ9o7}Kssa|}4n;~ST(1)jiB z`0Sd>5|B_*i`Cbo2FvlDr31ECGSmP;Hmm0>SaEr`??7Xt)mFQFxOR;8&E2w&N~;6w zG%(G26g&NHbMrCFZg=Wh3dG;w2`^V{K}lQdL=#|9TnnbSf-x(*8jK2uoq{sH(w({@ zmBSoN<3{hf?5nsJe$8ls9}JjC`_KGVGL~Lb7dDGeE1?Paxc(w`6QMj67j^F+OEshz zAq&4uv0thZ8u?pA9FnLwwHeQ;u&B9E%R(0$@ws|=8r|Bpc8(6%J>#KlcthnzVl5TW zc6UzC3BPSu1PRT%^}Dzk#l)N4ZMrnrPu^n z5ACe^J{Qc|fa|tfssdo1b^3+HxpkEhweDb`8d!hM6eP`EfyqBSM#NWb(uyf~%A9{y zC`~N*5GkH4O{WHGXEqJv^VZ@pMn8>2<8~*un0`J2IL zZKA&s0y8Dk?!}BW;QuBlC5B$3RJ2bv&+CH|t~$pf>lf7Prl#rC-|(Q&r?OI2YjHvI z43F@T8?U?LE|?I3;JmW@y}?8dSkhXOPXOEyVR>Pf2ejZBE$3YVC9&39Pwa;ltNnX# zfRHeS)si=;>ecK&%o4K=uw@>cy!0#6kajYGPcL*{i8IzWT%0T|9iC9nXznszJK#o# zllQJS!zF#}T`npg4<7ye_Gtf5&WqEiTz2#4qeHM!ev;i>|IA>1R8FX0+0EzV3{%c) zUl)~@E?%DCfZadc#u3XwF>d9H3I~2zxNdfFX(OFF2N&Ci+_AChLzsv$G%@`Ejb5A5*~+gZUygn z&N1){c_6r*?V>Hm`1f zv8K1SIq&2)dU6BNO~beY0dW#6o=;$YVt#aDB=)hO&S`QnoBhsNm_88$C}%Eu*S#HL zuows-KWq~zb=b+a>ayEK47IHVF;3b*JiW7N@Wk_`GxaJo#r(CondlXE?XFJ8@s$p* z#-^GzZ)X+YAkTW=*S%gF97{ozHQm&#+q#>=Gc;=Rm3H*C2H)g!9ZqPvxaz>t=h&Cc zhu0qaez%9K4vi>n^T}QUn?Q7^sO+&dGEdJg0^>uv!+hoP0Iu~xo0z-1aA%HkW;i}* zdT;K@<~O51lVuNE(cZoSMVy#EHlKRgP09h42t~w4L7P1tEjuN=Iyl_ZI^gr>@W-xx zCWDS&gog|0Wul+JNsdevX!RPT^>K|MLBV`GmmMVHTO^$J1A= zTj95tf(lnLNf`s$k*tmaZJKca?qt{7>cS7M=IXRm?FKiUz7qlWMHBPMHiZIH&AJom z9axHc?3h|Pn4+&F;l&F3gxbJ{?l4n%kg&AkP_H2A=lfj1_mah{7Enz|1t z)7xG;!_L%4%SzWfw*7AN%?^4;@#z{Wr_H%KNU{B4I*+MZ9hK@G>?Cz0Rx5823_5CQ zUux=F1Oh*ekY4o){F)*_p{7QCgBkWVHsmztkfMz!XKM4-;iM~l&@jyo;1ils{}ydq znnq<=6Sl}Ky7Ip}l;9jK-oZtMW{x&}{pkDTqb)XMe3t!&%KpgeCDY#Pdlnhd9iWyo zLT8NC+H=j~_VS>%soQKLFW8b33--{lOs-&+XpxMu=s>ef6q&YTj!;=a7PC%ji$o$T zZT&|27EGgt%@V%)y0PgEpE?62an#7^rZPw^QTY@E_G0LIDtCiHuLW+NfF#w}9w``@ zYC|2VVy?Qb4a9DH?%)~R ztyRJCKn)RKraZam^_mvNvkm$c94V2eX(deYuSzjOdloQTn)|HIq@*%PO;AJ zF0J&Ek6Vw*KJX6;q^~r_k*XQ5tWN&Th0Qxi48yDhnEG1sJToxnpa*8rM z>{ZDb;D)WD5&3+~V_VIId%N^W0vpyyb$~&KEUZby(G}dR-QLBG$NX><5pHjuyrZ!@ z%JUeT9CxL*K~tQ|vm@LA<~N142ie3GUHT`J;fb8ZSS%FTq^!rbUf)+v&byDA0&mlu z&#Z-nwhzb5#l(s_s$i?ktZmp8rPHj$9LvA0Iv!_uBJsb=6{n;(nX9J0rLo$viaFHw z#h2nGvrXGCor$=Y+8otJ6O&NslA&}{b%z>$@qFj`jxnX&Dx+mRa!aK%zq+UGj9b?n zV`qM9hx503yKKb6@k#pg`hgtm+?#toH`u*5w>Q@VaMb$*dDN3uEdIF|?XLg5XMTVw z_z96rDZR#t*bl;TH2q>xC~D(hPZ&H}q~Bq3HMmrI=k!3Nal)#w3FVD(<`658NL>Dh z!}HH)4E4ojgZLN)!#bY?r6f6v+J8M@H>*do6gJc@zijJL7rmwhcXo?Z^BYXLy z!QhL%w>x_$i_0HPqbRh_(9rR2sjb4fxU+gWT?}VztQg$|2XkMT%)4Xb+MjoA;Cvdd z7nda@9O*xgmi=uFhJR{sTmyF6TFmKtN5%|# z!8Y#YZCZ8lH5VfJqc6}lm{5C@Xkw#f>%w18*$~#k7G^sC?~Vl1+M0X5HFwE~J(5=5 zo+*G}dz<-Y@uLpib^$Pcp&52K!^EUrN0~CBjGX;M@bi7HFjqux63vSzhkL^BM}hDb zGxAQn#mvz(KX1%m6NA8aeLk?=S;P4ZuRN%lPmJ}&j%jXR{Jh9+-f1r))TwW@yBjVK z&z(-C87S&38Qg3%GH6E~<`rR~7^i5OVSO@awE)1E^2I=*s@l?_OZ@lkJ@s+^wmEDFm4u8V97A|0lYO z*w}A`VG~7XW0I*73a3Qd6}`}gK4l-mp~nf?bFpyj zW4YZA&6IymX-@)R+u~aKObh&h;5aW41XBUKHh8|26<{BLrY<9sYT|(C->aZVE~xY_ zSXxF<(ag1~#o{DV8~_)FGr&*|MNZkQ>U~qGL}ZW%lrlabL!u+UFdPT}uyb_!`9S`G z#`y4r487#VbY+Gc7VvvDj55b(w!1s*a}C?C*nJ?AYPL+3#2A|Y0U^B6w z+w*Q;^y;4Y;(10qRGquzP7mBia^sIrcksVG9-nQI7E1^ru9(}za8aV!&R{Ih-@cM& zUy?FmKa?C`QeLTdT;yfR6yAU|Xp->`j!CcJP@r;x@{*CYbMNY{mGFN_LtxY>wo@?%PZwr; zXg7!`U)u_5nsH+#QPf-9kvXQ@mpf;B9NV%xyVTmO0q)0BR;;4tfK*VRnJs?AEehvn zoLC#U3v?xZcJVb146Z@JXD`6{NAFA-F?>ra`NLr2EvDv?rS~0Qj8#>K5$sj`C-0MT zZ!+gj{7%)*TaN=reD!DU_iJ|%{@m9m2i#p}uNLjU-IP*pa65a68}sdajuQ@=(lfT2 zdpB-zc^d!o3F)ucd#u|$cz7V}EiJ8nzqcjj03JC|~{AFAE=W{4iA7Ys4KNV6| zEGMX35_-;YQ|OCCr@aGK{qSuUMRBLz(qI)II9UzUI|yf1=xUu~F7z<@EHBwrZrK5}Xr*i?r9_0tFf#pqoDS zf8O0cRoiZVe^2c0#`JzI1m9m@+g!W9^59xHUiX_(oD-=gFdR1m>k&d}wu2QD2ft{j zdESx(;aZ`?w@K8TpJZRYjOyb@Cn$=D`Mv*2JiE)KVG7Q{k~LhH&8)9KTE7;Ci)95N zpX_?}#V*pxg$X>w&RNSLJe|6q5NhJGKFT~&&K$%S5=kjKI9{;$O(9zKFctX>NajMthxt zj>3hZ(=+XV-B@{hu>V7xIQg}3xAyRxN7usK*Zbrx9kN^Z_Mcz81Sgn0 z|1W!Q-q6;Ow2%IuPjSL!M)Cp}J1gXJnkxEN_tGvp1p|ARz{EdqCL znY@Z~XXK_@L}VKNWD${;ve&*N%WL26vl2*MzxmV~kc}#PZH!FYHzt`C(B*6ZD5uEY zlVqiN0!aGH-pb^8??M)MeK~ygbh{rd^Z=e+K7x=7EO{s|a;+w{5z|gqS!R-o(x?1u zEn>MKBLTxVAaYPf)*GE$m7K&7Et?7Gy1@!KkEjPu#^Br!5KD>RxGVXZ5dS7Yt#=g*R9YNATw$mOg)hDmnAZasFd$HeYuNS>I}ZTa7%W(#Zn628^KfpeU+*yml(uA94)@Ub%Io(C@K;J)&m45J!G~(@4+|$VU?Bykth)< zhEkDfhjohrFL99alnueM0csPo3JfUcz5Sn|{{k1+ncc}Tjj{A(G&CI@RC7U13nSa= z_p77x^RqD$h`dBp)WzN+w7n%7)m<$7rdyPmQmC zu=Hf>>B6lAB_3oeH*?A23CtB&_1rel!7TZ}ti7zJA%2dj+~EHif9b2V<)iQj~0g3m3avZLmk2Y1-60upk&AT zZ&&NZ;W-(+fp`TGny!=L-9N>#0P(A< zy{Gn+R>SOUx>lQ0Q8g+NRmI!@D**g6aLrIC)iVTD?pLEIh5OvnNtRfS_r?UDLgcvS1Ux1?v9WYegZpuQVfa@V}3G z1hmk7VrG4)HwRRLdSspS4``GX%t(L$g^*>#T?(v7XNQKcAy(~m?=7?ZR6}tX^o|j} zhrl)X0#1j)FEysk{}p0sr5D7rji?-srnnwwMU)>WFXwN`t@%F z4E}=spEJL30+%X^<5E*pec?Zh@O~q`6`Lb+-kuJJXYv$D=IsFfCmuewySujWba!{L zv$VLl1aHv65Z;&z-V@q8@T2$r{i9*k*}@DS^^cE-Rrl3kJb;FNWkvG5&i78oxN{wh zbgO@Suyg--@C2d1XXo+T$_gkAPk7qr6K(CU2%pq?{R1?!=#4B^b~8aJne=-!IKU}^ zOLVIh6r9U-Zpnm~%AdNnN!;=0&@n-E0&)y>7^av4PSf_}U?Bk>id|V+U1<_H)_;{@tEwfuFj_W?q9G4sOsK?4Y$zc@xbgU?Zzwd;C9;Pn8c+ncS6 z9n(jH(xkp@++P<0f~$K?)KlG)4QO1|8UO-_6jLHY?U?zkaZdZ>jJGi%ilehM1x&U8P-!0qd+GOZk{A4y z$!_&07%RdKdIx0Ve3Jofm4QkolYw$DM9gjoYe1ynnET@5Y5#l)KluIb;NVYReD=ky z&uZ<=8`pK_M9h~wiT&||yiquF!K|Fh$P5K2{`y+V!?bkOJTh=7;q$OgXmbe<^NN9& zNy!NXT3gWkcnw|E5ul`IV~PBfu-JJI2g@&{1({IH*hS5KB-nh@PuVRCV`lfU7b1bB zN;Td9sZH-wu`Wt!VwZ+x`$zxeNG{I@^GeK3eL@^dw0vsk3Mzv$kW4b|^xn@c;d z{xGf<_7TlVd2{oBI@QfP)zU%#)e`YOmlF@Rw|;N`sOqZnj??MmBX0Kqh<^YR{{Srh z!M|4|lkfPbY5Itf4*QGuH6|oD#&NvU^FvS!+_6|!Xak>u2|J$g7PN~sj4wIBUc#<% z^Pm3r*9<+$bg=*dG|HCt8@tB^Oud8qaknja)~gmq$vX=}b=de9Mr6I=1k2M9(l~eH^YgdW0%!0WOy@V?QuwVuWmpGWnjCzYWRv0tJCdAc7m)*%)n;uK+Y*h5-u z$cX9wl|Y@L!bL}2Hde}y!j`%~BDgbgUMXc+!#I!ga@XQByPbDCqq{q&^S`c3{Y<`EGaj*}k9Aq?h2Y_q~ziRT?u>%1Uq#h1uivAyC9(8@|n zUsl`Lic?kLg@f3IVRl=n$m~%$93SaMj0TZzRMHqCPpjjdSgcue4{L7#5NReXe47OmLfLUALUcbM+`#-mf%KfxHm8Cp2&z3-bm_iFVgw zdAaf1lf5CV9L_d^^wiN~I=Vq7{~~kbO}#df4?ASzTXHG@msQ0NO5I9IZEZirLB*^D z%c9h0Nh!AV_~K-*kDP(Y2cpc1#|lV2J+sq7e`xPCZ!%f zd-%{_^xvk|JNwEj354Rf1p|R!Vq!|0;B_>6S zELNibhu-l8Zf#0GESBPbee*$HKnt^2IRTq{f5%ywtTc1c=sY|TWf8@Pjnn1+z&Ws9P6nqix$V}O z!cDC@C%j=UlIv&oT-SN>;tPABi#B=jRe166Ve)wShRoF*7gPFpSs%;dNuQ%*40sOo zoj(0ipT0|VTdeuJ$-gdpFK~XSj~VVq5psKQw+BOGCaLigBOdr;VC#l(&K>;goQev@vlBwzP^kRSD*6MXOBQu*faPD_ZKhU;uny>vh+z>l1{(E7wId& z^%<(&l+xi5EX<~EbgQI~Tj}F`aB%&^8p*4h*S{oG$*A@+51pjjV27Cu!#G39)9hBTusS zK5K>V^ICg+lEWuYvi7pokiBV`7Pglx8O&X+hlXitg}6RRG9eiT>Qj`?kn#a=(FAhi zMk#9XNLH$_n`Ll`o5F9FzvgYKMwHUjzlg8tFt~ZW7eB*zvhm-PNsy*6{c(ud)U`9U z6_PYl4GXRBaf0f$-AvHh2;`+Ku?`5;8ARI!m3chzxi)P z__wfr-;eO)kc(-r?|aMjjZYut_)oXKe>q3EMN#LyI6{J$d|{Cd<^&4P*jl>2fh?zs zHg8C|PKHiAGMTp~S|YTecX52KC)CG5#teoV73f@ss=ml2)FhV1lEBgb&FGWjGp~^k z)Tgb4_Hflt*D-NGQHMY0#hg`rJ2*#5f}a@}AQrqOn&K>qa$I%CNN^yAHJGt1O(eoa zBw9-0g_X}kQ|Pq(g=V|dP#%n!hz%2Ml(8*`j4;5yB-YZbH2Pv<3XT&Y9!ONgj78`e zo`?}cYHVy-kV=S`QoE<%1I`W|AFfa;t=#8GHSsP?gW!UJLUPIB7@4iI1~9FTyk8N5 zdQJ~)ZH)8%(y3(rn0Z_*6spTNGsw>}z3(xzAAVBhY^II@Gi~PJ5&`zUc~*q13anx^ z)TYI}4h&n`JpFd_kyY_^mCTdRtd7>qw8?w1pN0i@Bbh?$LoKwSghV;SiSlsVyqOG+ zw{Iom37pM|=Xn0@TToyhgf91X`MmRSAM~6*MB=<5u0pCqX_uFkSUa<+U0CBjFX7U<%ipMR8c`lwQshEPLc4|Td zZje-kXL6lM1-HbGU4IW`Bdu+%8dA+N|4aRO{gI#{@AU0k*xgwY*g<@xxoX11oYfn_ zOw}Kv`c^Y|A%kZPK=3-4+e2Gn-t3xI2HcfALp?vEK62CmTB74rjO^+^IUk;pNefYi z)`U15bvAiY0$0Q!lcqW<Qg zhl3elzi5uu2vccrHrI_LLjc3&sQi(B2+6$Dnj*hMrxy>!66#J@iI>ZR4)|0i1fe1Z zIRi}Xwo;oP#+V)sMsQ8Zo{`~-4Z!qku#)sH)|37Hv~I1Aw&Y3uy*fM^T>>eu&6eW*j9~XquKoV{2504$3Mb{S;5vesTH;q zfEUg;*O|kOmkwSq#j{P`gxM*gx7dJx>V(EONtB2e2%IE+>EC6LxQdUyp6*=7 zym$;Ya)iq`kfCseG~A7eVIzkZZ*7Mts#&Xfu82}8f{_1lfgE$pbr#}b59B%(doclE z z^U_Wu$Mo6FP~12`Ihe%wP~10xOZhNb2FZ^RnQ(-2Nh{UdqIUC~J3!iO`n_#@-McFo z+KX$ya9nd&uFn5@GQ-Gz%u^Tc`8;MHeA8?=wCsFh$*K4G%=KB-q zTLa2qRuU%+1`ybxap0~V#!pO|-bTcycPI;c=6pyh(t8Iipc}-&Ys+#u?g}nv zZN~n*wH7aSHG<)(k|#rCbcYOt`yc$8=XBQmJL%GS#iZ4e_GOEv8K~B+*LzG_>YB6> zxec5c+|TCLo#FHJ#PATLh+Ql^#nb)^LrYtR-U7XG z64}&6kVd4qh?vf*TOsUFRl%^aU1r=!`Tc}yLtH)}^*)s=@f=a<2HGIHBwL}q#f+Pb z6aA)6MEboouul|J7U}JqqP8Hp~np#J^ua{4?>$ zW1T!N4`yhX9}r<%vQ(o$g&h#?$rcimvQf^Rha%WklugH2RxFJiQ5q_3zF=Ol?4 zgr?lQs!_*u?y?Rax7Jbef%H_?(iiRZX3&QnPy9Q(mQlk9@JW*t_Bta9Rrs2TXM+Cd z;Gn(zqdpGFQDKo*ykQ)UyMPRY$YnVhC)!#K95zF;6A5q^p{IUsVqQ%XL8{5Ll!;8T z{aKcsiR5rtuDCtmHP2f^3{tDDrh+B0bWy0Dpxpkd8)QSqu zy!c8R#F_8mSWdh{eNbBmb`9#g!ZPp$VwjMcKNb^4u__9rjBzH6*7I~Eb&&UYEV z$eXi}VZ^C6qcyQZ>io5Ea}|5k=&NSSOc2tIWnx{8(rv7pn@Al(Av*0vSA;;R*rgW6 z@ts{jJrjgB57M{&!jzhJK@$12U=kn%wyxLzAyXhv#6o{qatBOfX9BNozma{JNIYp* zwtAP|nY}-^mtSUg_PUqcp;=A#m4p`{2D541u&93$*0HeAOe8GYypOpO#R<`!Sj0uU zcLy#oFaq2$Q6U3+;W>Vv@_D*R`evhwLu*~4TKs?}= zcp^TVTmyZ~3#-t#8stbwy97lZH$uZkI?~Z@O{r?wot3q5+|2QFO8sE@%8Tb|3on{= zB2(WE1M~jyBvmS9M8Iy3AHo3$M+~O^6T!nk~diBS7 zg||cjfkW7+Y=B{9%ck%rS2(O9b_+Xo$Jq;#z4ef;aFgdlb1ZL64Lyk`#m+0^-eFDZ z0;dXm4)iuWPdq9we&Lgg=e>o))rAK)7QTM*?z3OT$)Y=>&^c2dh>u`{tN3h)yK*7= zcIanOMp`fvMO-2uH0c6`^}+<5Y((U3=onfPIX9(YK+;DJ1}4!Er)>pKYpuk3S|Y_7 zvBXaa-yyP;onxxKmtr_BZf3AGwNrxxHbC*jDXe#~C1l-Dv!2p*)@KvSZmncR%Aw`) zA_TgrkW!|p*$m%SlqO0P434}%;XD@Bsn4@Sy%<_~;GVW7HNo#{sCd?TCd8%RhrieuG z!HWVBjc^w;%E@463r|P2u~yx#zPzz~qfuvsW`%TYBP9QzNSE{slZ`B`PKP;3cEy*n z%RD4ysRGYcAKA1Tj5?D#Dw@a^-0w|WoV{#OBNoC?qHB*rp>iu~&Ow?E&udhOSzhDx z0EFkvInf-*CGfy7u_fVc|1SRT#9KTUQhD(5Hi>>n@cRPmv5q$mDq2fJ1OL;Hxj@{5 zM&&Bvip{wTHgRIYW+qA+eE$XKVNXi!?Q_+X#Nhqs>cBIb+-FQ6$S4ur2#tSm&-S|- zLHW!1&6E@e%Vkh)93u4>J_;M^~ z;m$jb_}5lXqAzhoT~kH-Hwe0Mh!~W$=Bw=gA53TZY=s5-@6C1~B?L&pcYbHKgWkwE zOA)cgb}~NPD2{xUizAujh4vf8|Hg*Cp4?En*<}h0*+x@?H*ZXCur967BAnk`E?P~v zBH4LO#LQV&iJoj!CA%(0Rku1(2o07}k0lQVsKG17?gyI~t~w7 zio6A@PxU;}7dy0pbaG6X;)z$uSrjWh*HU(_UUaXy=>E~D`&F_PTf>L#rEv^B;@*m% zHW#1ELL#l~sIBa1uGa2(TiNq^*`=1UOG#04<1`}p===mZT9M7^{H^87>URG4f4%7} z9!nUZ$5i{=;S?gwPMsSar0@L(?s6Of?L6Clu<%tHZKYyL8|8#}lljwxGw>a!zq^9;jOZov70OFJL^AGZW}2)&9!87 zxD2C&Msg9#W6!1 zzKX#Glwm$atc4W=4k?<}B#{787Oi5jBe1lyQW~aGya_sgq~kho(N?rX8@g&|e z7d8#xKuE3n7PiRE(LsOosE5qX zi_^87aFO{$up)!@Svh4;B1W3Ch2oinmUQQEl8?tYJx<=#Ss**rTPNWyInU_nN(z#$;E-!`^{$M_=pn9mwSQp9leoI0= zX~}b5j&y@#EGk!?lB&BZ<{4qwaN1eYQFNAm+8JM4>O_CCBy7Org}dG7wCVryd>Q}B z*K1e0JB#)WZ~N;no?lydao3;h?4|A8WPEey-A{AfyLY%pPW2r8^8BZr8w)#cmJeAR z#~ZF)xq595XEp-y%i(xJ{4VWCPJi?1ujx}c!p^79)2EWLhfiOmPbGa1o?cHM${BV% zTuC2(ErVM6iB|1=xSCA}<;7NAymOq=qF%gGG%fu!pLV0UhS1oeKgHq_G=xb7ztp>U z8fJEGz`f!{Q4Kyzr6m{^{=lZ^&Zmd zA?Fp7ZsgU4DU5L_QkozxVu7}^_W|B5#%mT7Dom$%c7h;_;t?-=C?3h)-al~cXi`;` z<*cMVa`R8^X$Wt&%(0M5WB77>ra@&o2Sw`E#;r1mBRGZg$wgA4U$!;`8qDJ4cOORL z*l*gPd@}Y@?&N5D>2rYE zR$K$w@cV|sophtq5R2MO7Z30=JMgW$T~2H$qgzzR)Xw97DrKllWpm# znFPH&Rc=-Lz4LBo0hLaAZ@L%`9>XctW%~?2qNP+l=&!3)Imw6@izx9D_hene>&3qh z2dCY+g}J6N639jG>9_|uxCzMO_?;iAVr1(+{+av9bb%I%&WBmU6N9=iTD|kbFk^%y zf|Czeab|Bg^oAFd)x#9nMAF5q7(-7C`bDlAxRe$bVT45>E?l_4fc1{p1Nfj9kep}Y z%-4@3mZKs+!Kl*V#OW0Q(STyXEAWt^%PLZjtTAZ=MluIZ5g-d*5QA|*lG8PqngY`%CIveHp{gl4M4+LT%&f#*x`G$(K;Vj~ zj~4Ev4P&Of1p(Ah%z|RwcxLV?PjDP`oZKO=yBr9icnl6ze@Nd4B?T=T$XK@`qki!9 z76=0`PI+y@t7YM!_4IW*0GB``Z@PamV$SrZ6iw5;QH9lq5*liuQBpZwdyLXV%8WnV z_y$`P$UD^GZ%B;=mN`c7qL;e@rO&Oj`dq6%pC7!40eiLx%pg>@#!<)Cb`cy% z7q3E6v!lb}f0`GJCyRy^`Oz0ZmVQCuNI_b{f}*v7VlZC9Fd25#Yat$}t>0um>W!p( zUmy-I#=mLsDR;WqKdR0UJX&m&vAX%>q5#>@YqICYim~6xfu6Mu*(Ts_;PHYnKNDnF z$L0sK0sa*WfrwYYb-hn)gT4g_dC^2zA4?M%=%TZg#dF49zfKM|XkBG96%BHg1DE#J z4o$OY=QCnp7)NW~I=nw0OlsgN+L0m%#+x=EnsB&WbO;t}?m@Y>j0bV~=CYqpt5(k6 zG5tydE|htTwW($Cg*||U>eJP*(yT_KmDP?FfL@B&!`TV$izA#kM z&L9vd*oqtoo=cKOJCZtL(UaHQ%JLSaIsr_NEjx?Mi>m6w3Pu5jbJwqfi~w;g->U@R zxR2+U4+MswrzVn{MvjQX7mDuKrqBjeu?pmRUbr-NPkSeQTr_uljN4I>J{vpIU;nzh zwY~auyVUi9XQQodN@C&%xUsTywHp6CIAhEJGIrqdnLaOw@TuY7!cQah3OA7cx%==#V&wEl6ygaa;67GZx@YWd5eSP@9)#l9+v z72$DK?B=baSP|al#Y)(UI43V=H)wDeGK9ka=*5!Q5-C=A7p>TGqJitQ6;4AhS2nlY zJijGImW%21=E|`yH%|mq_a9atZmcC&WJ1T zUe{i7|MbUewqUCoN4GhsVit$ZlkZobR?m>tCtUshpMCGx6I>1}!vXQ@rPJF3GN_O_E`^hGA2wyLI7StYnNmXd89;lAKN}B zURuVcS{9argB2*(X<|uW_g4_R0zq%8h(DO(LgCd0#s$ji*RzfQzd5 zx$5m%LS3A3_+<@XaRPpER0e=5zM{HC48sQCCHXxEok*XC;|oDRoN5>beB?kUh07A@ zDvO6giTQrVK}m%s4lrvo{#dw!nF?K}_Kz5c3g5R5H36)_{T;v&qwe{TgGg&ci6b^m zzdBHz7Mln-;IM`}%U^%>*~0S8g`1yk-?*_N|Np;Jb9$n>z~v2Y4=*$4d~k>r#e539 z0Td^%5h5U|GcWd(1b{1|_tR)v!I`7o-S1Z)ZsTULM^A8B^V6N~&XsR)4yn4fbN9}b zyK@L+2ljjTS|e)e>|hQSzOJn^nc8wpqP`21pT2djl+ zuoc3^-Hrtg8SF&!Rp3C9BoC9cJR(igE*w#$*7bmtd6cK}>-scKmNu9iXmyAajg$}< zd+QQ}A=R(BNX+|9pUK3dRoq{Y)?q&|B0(IBeIxeb0XTyIpknqVTL1~j5LcgUREX}N zPEvLMy7_QZmzJy$>lngp=-8_Xhmn~1@Ja_%z==F^y)kTtbV~$7!7QKxmAHvCR8BxZ z;_?ACXBGL|Wx6ZeB#B(cNau*1d0%h^ z=id;Z9dU0xVFEQtl=qTJ0$-1Y<@LE7m4TJW6kEuCgp;=5kxC>7QR+d4$TJ@NguVQ& zUPUgKr(=bIY=RKcA{O|bkLxtgk97L;T>A5&h1KJixVKv}8&(wTR#qOZ;er+Yy7m1k z>;vKZ&CkD}=n#H?zI-z@ZW_cM?k==v&8gJK7&82&fD0s=K~YK%vfu-E;(o$2?foqm zpuX+DgfA5=InXy)(@Ww04VJQ^?T#w2`PVYkv`Ib(s@*~s2wcj|pWd6XLM*Rg2Ue-aFS3HlO zfSd3-js%@>xX90h@nV5yZtTc0;kYMpfl1PZ7`Ik-LjE{-S)IQ<%NhKl+#PLvHo(C7 zsns7I^#;{AEleK*r`V_KpwnU;ph#M>Wk{yA zi$wW}a$`#_Z_osqHmhkN63p)*(q~*-r`S7y_={87h~{v`Vk_cxPqJpxHQ@FKG$o01 zI1_bt3G0RO0AZPXT>o;-28dPUOkXuMu4v6el2eqs7FqhYTbYbhdl%*lL}K!7m;@?RrshspF^MdlOXaY4@!I=!rUd+Y7V;qdgW$N{~VeQYvU8IMj|?t|Xm z0EWCL@D7~r4-l|^`%s?T!|4guSwz=&to#E=(A=#KVK9U0b@p~NczJ}B+b}=y>BG(UP!N!( z5{6XB4p34qMsPdwBmyB``s5QT$?A)=5$)UuVj%RLp5xmovU(zB_!C$ItJe2BYe>>R z8k`}o+s-z;CGqDsvse7f$?@##UAmzLIa#2JXdi zjmIU*OVKr^Z4()4woatdrfA8RsDP2+Al2#lWvaY}&uwOeDUt1bdvSOOqrrjxoYtFF z(m$8&%2w^Addlj|+#xsxY|{ti82meJR9>9adC4lgj()}}O8YzdXRAMTX081Dt?0Eu z?|Ar9o0v9y>j>-mCGBgMsk?`NU4Ft)5n^XJ^>TW&h^IE!?%K!Q)a$hz5t)|9kj-d<;(y?fcMP_jNf1|1hrL zuzDw`1jh-J>!0E106jveZHt%pba+QDj%;(&SFbF-(1v&-p=R1Gyeg*$y!GJz!woe1 zY5+?mnW5KyHil$_Fd~s`C?U?H3y6}8!%Ifh?VP;D3z(cc%ZoP{wN6A{5%bSg5iD76 z;ZE=1pv$UTy#1taq}i1a$F$h!LhN|j>%HE^`4Mn5t4y_IKIjCzx)WNs6*Uu!yHMHB zW7p4f(HkcNi9k2u8elJZp1p1E#{r*idXAaeE^u z$DPR}mysLr^+xvEZDX&9g9?P)GCi>XM<0LbJk*VePcKf5HS5WWf|(NVlAr~Jf#qZF z2b8C)3M^k)%;NO5Z2RIWyP=@qT#Z-L4SWAboLg=hR^9W*fuo4 zQ@HB5qhOcdJqV)cS@qD0_zTi-w(3X5ofuaG$75&`4%#!>t7?s}`TpHKga-4-{rP?F zevxx^ul(vuzIoA+p%=(9Txp=lbsKlYrK6-hkc0sydT3v;UL!%B3)`w(TS-@mkpL%_ zrrFq@&PJ_4nd9E_zAY`$S0)5Cx1gn{55A zX|a_%{&Het*4a+?3_6at}MVPir=_>1`)SW@E+RGK%R79HgI=Y*~vqNE3!Q zoz+5qSU7F73qkZsd=e*|1^Hpi$d({eZN%GzLl#ZjO(LcFil2DKLw>cUvUAw6Mv7Kq z3kjBF`fbxPfvW^iiiBoy67%!V%OV6Rg&#$7TqHfREL#JGI7VXGq@3F%vw4k@w%keYCdIK1a2I)+UiQ1$OcS(*%9zwxx#1jSLm-O}vXf$w z+p(+(Z><|%U(a8xtZY8n-q?J+`VbqHQfWGx1fbZ&71=`ESPz>;m+@t!fd-Iuu{o6K z#HO^ZJ(~n-bPe83p)6t?PBXQgh(@8hD4||!)FAK1B}014s2+XHZ{fHL@Z$SgyyE4 zv6(tnnbcDyXWq?Zu91eh1#pQerDcMJJFLZKaIh#eNi+zpCjCqtCuTb~rJ7#+%`;2h zbjz&A0$fD#*MxajUA-K|sE_M0K;?2~1b9e{fHgeW?3Yb&@Z~e7go#MNWXC~Ine9sq zk%Up%wbpH8Fw5GitWGaH4Omj<6fiNQOkQc5576cqhguQ+3WfvRi)9nytr_-VcOFTw z?7@W`J+Y;O699gbUu|GG)z&+y7(L3Qd~iX-paCPrdv`Dq86e-%qT!vk5NzFa+a;7x zf(+PMF-7w(J^Q>U=B+3MRS)-cs!Kq(xqu|Y;$?C59$ies)~e}9T_0`>niAvnjQ9aZ z*Oe_2W!<)08@#PzTLE0W3GWjTVd7vw;g2akmjm#vR^<``GjT>im$iOtpejvgR`5&1 z3sMz$RbY{!z0(0kfl^QhJ~|2NfaerjrqQ@q3fXO7=lHf# z;&o^k^hEH1bqC+g`6a=a{NlX;{r0tOC{O!1^=BsMVKGP z!8IahC2Wvk(UiL2q#BOEMr)E&7~Ec`=ZD?SZH7GE`NR13l6(ocxy`Ku!o9rm?{wP) z{aRKB)sgTdcC1t3sz{=K@X-_y8ahb?_@pgs$A(}A#A+M6gAK+!JauXIDFT?s;QbKa z#KCIYWNr3yx|Y>WK4QgFo@Yc|-7}!>tIVpNxBhGFIQww)P++pk6ITHu*abe*mI`XI zE)4JP>9roMieaoi^wk3#ug4ZI`fcI?uZDYnhg+PEaDIXVW<$N+xPg*Dt$r?f#vuGe+GjG2jZX?wmH?Rd&i7l6@dhoxn2)A1wL`7 z-)J-dQcu0n3axPi^!9%9d<2YCtFXZ9Br72lWKhucFXF@DT5wX0ludh>QwXI|7#1cH zI|jic8O_=&)mrOb%oZV zw$!OC=gR_X5ZDifI20fp`wjLJ>%G~G1TtveZDc`ZDeDcZAOLnU>5yC-z>&yPj0uV7 zATLrFU@vVXX|P0#U;$i0gdB*`Q!rw;&|7$qb}cGNktc)(dooQ0Hn`X|QD{c>xPDk8 zEiN3)s>T(UfXNC@zezW-#rLOk@w@;HWCo5nc)MiZkzrOtyc)e8j2W@cPY?ra8?UKU z-b}Vs%DOfju`yf%hKckFr%^M#T4xg}R*_lX(Vsd)NF)=O3z)J4mmdf}kobM%AF;c6 z_ceqC47a`!)>sCD3j=u@n4F52$KctJqCn<)Ishkk_IYyjb?+@LH=Ll_d{}**5QtT& zFcn&IzSFwoAA6tR!h-I1igZl9EIS)*5xqysh%8;jf1qhfq*8A#J|5ZAYF`n!p9%$&tfLqiG zn9L6Xl_hwttq9O~D90dD+fBgtQl==Oy_}$>83e?iAz{r=IEPN~7CVxc zCL3D1rnqa$t+NSY#&ucR%;p$ukYBO2BXa{}PDmiW-QcVgJrvX(HDQzN`C$UXcJJfJ zmbPr*JuU|1al&ExWC}QitI3-LSYRd}T)F3SeX?mJ9|)O=(_U(WWd(kaA7jj@ZKj1q zzWANfwZQ>zrh!`k3O3o|-JMewoQs<`fAZ7nX6MVv4O@}`>>T6%gbs4HST@VBa0Vs; zZob0FabPK8HX$LtPDBp=jJk^nGBt@5WU9DnZ#QWZga}>_+8Lbgs^2}*ZA#csk10MR zz;WIz_jVv6EF4^KQ2p_b2wszh%L$(W{FI0je&-$yAe4c;$v_qY5!*uv5HhG9I3D_M~Y!);kly_ zzL2LPVIwwMTq2KM4i7h`k$mNP3dxs}Ad@wdDLG*cm9%Yn3pieQ});uB4_~v8?46qAju%<@hjspKRZ2t-7|xSZl6U zYeJ&tqac$MO<~MY@oTcaleOI<7bWdX5{M!`CW}M!<0zTLIm4bloAeU8DG_!VG3&m` z4bH7v1T2g^0k$S9rJ(qfCFu0o3*s3g!YO!~&=lpRvLS0EF&%&B(Gy;@>Lx0;DK~17 zC2i>L0A2|D{Hp=nWLHXI2HKMDY3*5(wEQ1Be>Rt~6y5M`2yKr zmK%i(@81pW3FC?*CY?{RE`>(4N}ZCQHrPBN0gWXEaw?IJHG>`G9q1Gk&jke~9h;$8 zgi_N*>b6Ov7yA>aO)I6A%&dPao>3X-9wA+EpD5Ut33Bz!Y1;4<+K>STk|@c5+h}(l zS++1QFlyn8PB$*1lc#r(jHy~!;P_*W0ic0lNulgt!np{vszww zB0bp1r;>wQkpcx00`?egLopJ1q<7*iZJGbnQJ~BZ)9QIO6OEd{2QpA*C2j)XXViPm zQR9<@BN_wXJ6p4fpmH^|WW|E5(Y}Py@E9j~X)+M28=5%a$Ps-ATh$mw#dr+*=He}E zyAtO;>Yu<#FUG7}i#Hq<8G#17UT@5NJ#|iqJ&mI=M^mZm-Ge3#yTNEz&X{&P+$K7U zyStCpx4++9+ucR>NTxy^0tVXF+Ci4>L!vbhSx~?Y`^Eb1v#s@~yKC!6M16mCdwnh4 z%@HT;NrwO@eb#yEp_H@w(LODgr()^mKUY?MSbzHM=GMmcUw0pGK7GW45uXwn3GF9c zFWgZu_Fx3nbACV_`L18<+>!OlyI%BCo$wQU7On1TC3z=iq;!bBv1plvJBNLoyY+ER zWSW0@^zdJ~N_yipT*KYGN_y2A?$4%?{Px(Z4{&(_K>JE*cY+?PZ>WZbb{9Ob`c z^&n|gkcFM&LhJ~#P_c)v* zuXth?s;cLI7{9;`YFXru#8>Dr6jLg~{K?MftgL`_h=3#QrCqZ4{OiF%n$I3W*tRAn zI{uMw;24IA71XZsonBq|eb{4zrjSE?D*x*Y6d^fXo_rhh88L?n7I@d^2>v0t>{E}TKT@9zL*W<< z$rej4lQm{jCe3ZhT_)eY)d`il;4nJz3%H+QVvB4Q(+J=e04dD>5ZZXjtNIQ^64P9a zx>bzLL9|FX5A>S5>P{OnI8&))z0AyUbE1N4^fJ>Nv zz3t%W3e7PTJT$2Mqu#Jx!YxQyXkii|N`bxd6Npr&VIsu@6bS}OD68rZWB!*ws%-Ls zC!AbafymlBgQ&=vIF7$qZQL3M~B$mS7s&O0y3}iHjdYo|#`WFU zn!T9ZT5t4nEUnr0kY6FnA!GuWj|oc>HjDv~%FO&?pTc*uQwic|&5)a`<>5EgwQKW( zrcHw_&TFVLoFKT;#4*nstDkq|O$YZBQxM>UWRK+n`g|ohg!8-)05H{?QAjcqnkb8QU=?g@^` z|1nPQyz+xTE8*-9Hw>94{3ROk$C1LXpmzKr2r#@);5;ssI^z6qu?g~V4b&M0UT>0r zBb)w}&MZi~Fza(}buB(&gc~Bj@)RIsp0Z}e^{bL;o`ImG@fxTBtBy!NbcEf~LikO7 z${Q9oy!G~Ucs3pYD&iV8jKuH67?4Y%w+7rL@u)bgn>n^)7zfj8i5HP(GXx6ZLKwuX zs{9AxTiu8pNp?CDL$CWJO#6fAF2_ieh&?uM)aWlcLe zy;e-Ln5o*XgvQ$8g8TQt#8F?8iT~43@xAm{kJ^o+`Hi?(&hK?jd|y+kB7tEKCp>U} zp1PDRSh`4m%0*nW+?p$3gakI&jwF&oQtyePi6nr@}pi2iM-n@0~02 zR0W~Nopga2q@e9~Rv&L|+^5D$HYC*%c3OhNK5X17Tv!q^D~~|b>&Rv%dCC0I&Ge2x z){jh@zls4KB?FvoXfhxfPGp`4NMi#1N0M&spEjIgnsGM* zzp0KYg8WTIXO4h7Wq{x4a2BPOeYcwbvJoZ}kgXDm7uVI-t;nfwDq9jn;CpH0nx$3q zKJ53JRS4k#5>+|m%@WS8aQ{Tu|0vM=&WZgQmqs<59Z@4GmaH3aGVfOBZtP|b&- z`FOa;sNNh5#p5d5%@BhG&x+k?0I`P^B)fWD;!%W4uA2?NI|I_M_C(8a@v1N^`)m|a zp^MM6o2Ki+753JUGPMB0lW4W{T22$UAvxS7$6#e>lT-Wkko>wK|6Pz}K`d*19Oj@4 zR$5M&OuQiYQeB=77cSMSgomcxMsv=khl{?kn)=+pwz;E8s(VmUSWa|ob+ zW*k%Fc@mDt>o+9X>@2)`^$HY%Sn7$Tn1mBX!~UOc<%KajPl~*qnz56GQIs=ys}y!P zu5^jdgqXGUZ=ZdatV1>uS-?c#FE_%QmmlHH4>CfSYyV0I62c+Y-*ccj=#BFoW^(xw zh4Z3QCjCPpqX`c|>uEDrJS`K;TZm98Pi-J*AD&=d-om@P?3xB%UV)A zxgFv%qmSL}s#mo(c6|w)9uH$X2bJYsqoL#&m&q^ezukvb$}()VfRv|6A$`loqxag+ zrMPTRY~De*2+~CmV}jVGQc1y&d~r%{eSKHf3=NoYg>CIUa^#zYSQkmMoSyeBFxU}c zIaP(d(@$&TtXa%_7^RdFeNZ+LvSB4Vns}v-#I0D;vanNq6;Og%70j<@7gd!tIhU4W z({?A^UQkaY%wkbfE;gnZ9jhC0B;2w$mwCeoVTH5KAY|*Nl<=6OA84X`Jg~LbC!Q?C zSk!7d#(BAf(mhO^LwUnyC3b%gj zlPjihl1`!%HQ>G^Da6_tUqosiApq%eys~nC^U?B`VBl2e9j!o#+ z(eUE<0KB*At26jpn^G+JTr6U~QutK^Dg- zP$tFOCbOgta}kv{G)!58X2GyK*V93gxyM6u{`NFh!J|L zsL2=hC!7u#O9YZsFg77^GXreeBHc3(&5(Z14%i zX2^8^bRAycr|Z}zBx2p?3)`UP*oAs{J>NJ&>ziUj>q3*Hs3pqv5&o62=sT#)s}G;8 zBWCw0xl9-dHOu}TZGyUG5_cxgGHQUhTAr_T?akAM!YuG>}mek)Gg} z3q5KhgYyooG*13dTrbYxEXVOioB$&qmrz$@C~b>FB@ab$h*KH7f@321+GwiIoV*3K zQ(XJBZmI_|b`kJMM?m2e*5wf;*+hIx&SQ+v`uo8RhBOOz%p=x08z49iT<IAIZ8PYc9$xu4utN*W_Hu;68mxy+h*0tql**%dI5AP<~E%cNSSwEy_bW>ya zY7*DrGdpFCJmoE|(Wo~(g{19aXtsDtjdj&}lcU6{#6p(WbJ%)+QUc@D1sI@#biNhG zhQvJrX6>lEaVL*S?fe03no+={cdLT9$K(g&xhw+Qn?$OYn~2;FZD8j-sQz$JQPn^@ zW$A?qPB8>N%dO;?y}HQu)Fz4=PB^7V78EWM+c$eN-D-%@LC#L<#n~YRM`85{vz=Ew#2x%fmhwkzULhIVC9QHwa4t?}a z5o(hjYL|dW)i{91w3jlQjINYI%oobBta0INNt%h1S@xYE*i4k@D z^c1Q#UE_=&glM#P4EwF@! z+t+i$baLGRwZ#%1$ zCKyeJYYo+9WZgdIAL7t!2oq}1W!ghg$)s~XKF_iy1Hf7VGv)DHLoyZ$I>iM$1Ij@N zPk8I;g;n6X;$ZYohe)i!wK*OF@u7E#i8>ep)etjeP+7}>?6gk-B-+8C6e)0u3$-rb z43CdTm4#{#UNNK?wn9nhxvlLO13KSFM)w2iY=5dw_I3|&bY=g1*B^rAi>%|OC$%gU zn`{)Q75TA}O;lu}3HO@6I6wSqONDUh+LXP9zB?>RIoZKV)|i}_Y&_{NZ!jtz6DLpO zCrA}>nsK6M>4J?%cr@DraauAmOgCfx$sgy1F4V?D7r+_pjL1Als_}zZJj@xoX7^;P zKr(PDQ=+Hm7o{Z_6J?ahrHf^v1YY2oE$E<-2vsV@f$<$b&0BnAi!8&q8xhs7S7#UF zqYPY$vyo$A)Im>rKa&JsOFoHgB#L&;9)Lx6)=;n5B@a6l!y0|FS)xNQ5JyJZ?#*>h;6J&(fsq)uPZr?pSI{W04rK_JnND-?JPnmO5B4BRp*m`?% zIE1SPncaTIbqgR#Dc{|{Qa$MH4VdKzhlWr02QaeSK9nc-##)DAi+8O21MIN0Hwmfk z56|9e${Df|S|3iax6)`yyC97Q)fuir#QxN(2|@zy#)6)45i`WiEZSRU*W z*wJKk(B`e){@k{H-&9jHHbC%BiVm5gPLQ# zKkAQOg6Ukk#*avLh6!)$i#)67eryRVT2XSrn{e7OM#M-+gNZ6hWFc7}#PYk72O6H0GPitFF8Hn1W3uVFbXS28tWV z7>N<6gKMPe?uTSUfsrwuYGSx)`p(;(NZBB&q)s>ap0_=b-cul;GbTS35oEihzVuBy zk%#RsD=z`O@s&H3*mR?`Yts~1maW(bP#fKaInt_RH!Twppz&its5(PrS;1S-erTv0 zz9mhzFc}4pT>|CdM;qmR=hi$e**Gc_@*@n>qvVRQV4a8BwT0t41O;oHTaJ5)%%Qpl zk{u;LoRHHc){6C(67>754~!^jV#=5jNZaP&J}(^Ng)PYU4NWKAj<^%qo$TOUWTxP) zQb4aKos@BB6P`%iGR|mYG(+Q%Tx>)p_=fR9$his)$#9}(IV{Muckpla>AVIi|Z zQ6(E>(s!L-ufOTz)ka%m{fd)MHRE?Em&MWa>FSg*QG~r7@a%@sev}E z6iv4#X?gu#bsu4NOcI7-qz+WogEiJ*3nvu$CTK*kTMXpHL^uEuUlp5@?`efj4a@!9jPrqbT*u0EbycrUL2T;MN28;^-|f4s^YSrp_DffK9x`WN7dx#bs+NG&xa@ z#5xP}n@>BVCi+aO+4o4i(BinC;MAVBQmM~ofn7!J%!g%L#kvl!niruO*B?0d=sR@; z8VXz}5T*t7D1o+z2g#&^`oZm>sR%iN?rZA7b{+?0gU*hx7UDBaOC}Ze51b->{ZUyE zqmHaEGDDEDWSz$O5}0zpdBdStJq(Kl>GK1+(cB)d`b<-e2!C==^o9HyTyrPzBa((j zeVjQNLHczoWStGd_Jxca#nk;X7e*^t`5>E5QO!hGbxyf)3hxvo_5XEdX+-jODs8<( zpj9S9`9e6OUzaMGxh6$Dp)J_gN&3Om+{+%b==jDS=x5Vlv;zNm%ZBeuH z?FQ4?2O|I_xbEmte1SnYLd$K3oEp28@hPrA_U-)9cRQ~Q3c&S77kdlJq3p50{nt-c zfW!nH?pBI0Wk@`53L0+RkD~EbZ5li{Pn;;l9^#M?Z}l zVS}Bu9=!Rdntqh`VQg--6=#)@oT;7y9<2M6oM4WCf%@|y&C$b34ds+}a`^FRnx@$1 zK_)y2qyei~gpYdrn_G)X68VH=2!?+eEj0d;f9F*QhZC0Oa{&wL4-%Zk)tDCNcX;cP zJGHcd=N&s-+d=rd-G=q!>eI&?kITeU-dZHD<|hhyBT0Z9IDHc+AuZ83SLgi%#b*6%+wIZ5K1#IVpieW|?Ih_@09OrU~@<75dF zrMeL;+!>68oA3lKvgFk~;bFC_aNe-i%NwJF{K3zP% zyk>^Vx9-3cRaEtlM-6mC;dM3K(p=`S{SpA6!wno&mD5<`*GnU)MHwyH5~oFGuZ`QMH{yyw%`;-nP#UTMz-uEf z#j4%S82;)~Ntj9_V?s1q(y&3`($0jo;;>w>8}H)SNPjc{ zJh4qi6IrU|_z;0aHy%!s2&*$X2SP(`bNcgRk4MHvw7X z!E(hgr~AHgC0vlC&@8&mg>0{2sT2*cMequ%-Ho;C&Y!B!Z+v#+2G_Yxh?~!#K<}8b zuLO90L}v-ymOD@Thj#qt0TvbIZX091aS;)biy#>eR=u^o4YI3qbOO#w1+=%TFK^&e z!o$-1fCGMeK{baLf_)xu{X#B`@gic77Ek-cLxW5`r@-MzgP~lrETcHvN_0l z2<9U2W^-YRu+5bTVVY-#VGgB8gqTa3j-ZObhy+6e3>$52tIUf!b~2qAO-B7iIf;ha z==gM4y=Jx(SXnL5lT6%tLxHxI2^$wvruDy?4$+R7iBl#|!G*cD}K`viOY$%=xT(d(TKmaqI+5@l?%hv{x)UP9X!c=1L(WS?+O+nsN5(>0YHmv-n zMUaAW8;)A~s!6Og*j~W6T(MRHH+*WF}C6#Im%t>2u$yp1N2~F&D z$vT~7JNeGV>;eHrCShz7CXkg|h`S)m`k;sMQ8CfY!YBAbf|zm!(;=l+J4ITZ_*;jE z4aJYu8+VOB7OAIZVW^n+`8ts}uD|_4!rW?6= z%D3gb1N!KoFS|00!`^+^zQ*pJW!pFv11khPHq7BRLSyjjx|1=Xj1uqVjQu{FzRgTI z=f8mr9s}{O`ZE(lK{#y`v3dZf8Rp8lV2K^m=ol9d{H90a#kAtpB+4(aDs_d?rNP}x z^0M$7KHD@?_^A!PSkdWOwP(!fstE_l7X^Fq)u!YgU42;eH;fS%xPXqX-xes4GXuIUy~?^OC#$K=t2^0bHKY>)x-_eycKDSJ zg9psyk%Ble91r6#3%&?Cj>K+=L=8`5POaa(!`N3Q@1#s;8d<6P;gUq9m6}M(r&><* zAS%aaE&T2>vIe|?LaI-T$CtFxqjjg$xC#F;_CHGDGVdz!d7{dzunvl7aPEooym5yt zov#l?gdX%Pl6RoU95SZR^Z^G_PiM*=w$hm zVViH;h)QBj_XkoJ#H(r#`;pKH>&w|JHx5`p`JvANqrJv`GDL)PfvQfpUD3#V40CXI zrJOPnG}K_RK#No)hSSdBaJaJ98wHzBX>fDuli`rZ`liYU28u)E5=tsahIdnpXfb|X zdcyWU&_gHIKr?j#V=@fkG&XWAa5YA>s!(l}*$(oBv5>6ySin^n*J2EN-f4m24G$gG#9>Ct;s}6d7-Z zG;f>7Y@oICPs?Olmr_#HT|Jqj9bnGWUfU+@X_8nfrREZGPR=&)7UFLn6l5f!w{jRM zd<%D!+PE_70(Bs(l<$*8a}Hamst~EtnuI?6U9|LDW^c{T8H)Wj>7yLGEw!YC>UQJ( z(LfS9UvlB4^O!bT3~h#Koltus>53#Az@HMnopjPhnPJWuz8=n)%r@Clg|pmL_qR;% z_kg7 zT$90^hA-pK{ewotsp=MNkIK}vN#Ji@0%MsFj90+;Y02=K81CeF=|rz|{x;$!DU#R= z=M~!$9Np5Dsw7$O^SEXADV$o*JMY* zwsAtLOku%Kl|{fX6ou7YWc~@y))Eft2Gj{V0^;frO3LhXv+o8t;ExnSS`VgzXhCdl zOGjFxC;_>AH)4tY8ScaY2zCoA+uR?ICKlITR-aQoYh6@&4@ZgF$k zXzZ|eiL!a*=c34^h3-}z`O;w;R;m|BF{B-VIBjh~zj7~{!}6T1yr?O9x?X(A;3cJ`}@W*sN34qGhTD4HG99X1r%SHQ$|=4$B$kG~JLSgxKpP z-JrphAhP%-(1`o3H*0InhO2qVQ^r zjR+y0cPk#0qxla(-Lc68QcFgSmEn2>nhNhjL(GIABCAV~q=sb8rVBDTAT7}cS=I-u zlN^=~>lE=sHHV$=d9K@()N1{jGJ=G}>hOVltX@AKl+`b*AF$j$FZi|qRo`lFF5Z$G z6~TN*uzS5i0mN?ITD;-Qv6(=7V>%sc+~6LdN&>#+N~+G{?(U=Y?e90&c6Xr>#PG&R zFp0VL^+0!p0x-;wg^jPRKY6--ANRJcrD{d+$$-2xMvkz$b}$^J;TslhYUT1&L*4vm z8sPnS^Xa42hd>5z(lfoiv}x>N)6s}l+poiQ9i!gsU44TC19!BkbQn%)9y)&5 zKi@xc*e6iesrZEhVTe0;8g->YT5r5IJV}K#1Eg22Z9bA{2<<^Buq3pMPJh`!m9^o% zCV_((`ogEV89_*f`W zyZ^FHllCH1^{Zz_tiAxeW!mVF%8KIMM3tLt*M|e*@!{x7B%>sYPjrP;z2M@8jZQW7 zQqXaIS31y=t(x`19h+2Fv9ra67%kZas{jMD<>9p2}itZzXh0Cjvu_tx1 zILsO?afkC|@lhzg|4}H`OytVN>OwJhkoLUf!V>GLzFm@jh#d+TW{Pv)xpe0UTNi9= z_3cY!Y;L)UG4{90*eNK@GWPEzOlRvq5s`_4CMhTpk$vqllTAN)K2`AIU_)})aZ@kf zzn82sdnIwV4;;$&n)xM8`=cu};Ade0 z%{vg67x^a0OZCLAmpp@_=ZI4B_U%cQ&igLQ4=1%X?6@LHlw#XQ5s3m4WU#3s639Ih zWdC)t65;IxMpFt{QJjuN3PFnv)cqh6)=Oz%t&@MDIGFJ~7!;C~(qKag#hPHBW;_X_ zRP#wPR1PyV?Q$nq!DUP)!rhupCbhOH(_W@+a!+TA>?ak78-WjML95B<1KDF-`TF&f zkK*?IQrw0iQyBbJ9F@hXQK)(%UhtAnNE(z9dT=bjL=)j_{dJj!{h$CbZ55KWW%8i>i*`VN2`z5 zm>3vG6(RfZ!U#qgpaVqp_V$lt*Y0B@hBZjDelVYh6Qif-xax^yWGs|!c}fhOBXcv` zg+!1yj-ynAL(SP_Z857eG<{K~Rjg6r@~ZcXR)HpjNZ`=x0q^hwjM`J9p@zfLVR6N9 z1nwAzo4yYVH{D$A!oOh6uQI~SQp}fU4wVPj)C@#vDKC5vH=mhX)*h)@h*&xgvw+i$ zjy6Mzhq@Khw!QxJ(Z*wVYv|4*rM4<#vB`0wO(Ey7V4CAT}d% z5_}?VOM7j>==xvouglq5!{~4yNh>5lJ>p%M2N0RdUml%<%=h~eBuVwH-y7A^BWyE) ziqc(9@du2F4?%aao#DuF0D4ZAg*Xn8mfJgA6ceMi+(yyf(#(V%@>r%si-oAUA3gwS zN4zGJ5yphc__%F=xfHI;XrjXoGTBCvNSf0;gT}<-wQQ4H4y54~9uLnS@S6GXB5rT) z8~igaDOz}dz3Tt{e}-5FTLT>Pt8V`tPY=0);n^atbswJILly;uAtOWDIK9;lUOtJh zJeI9YH?d@Zjuyl(+is@p^Sg(e->yE~eZ2Z;ee22U{dE{RJG(EBhkL!_hSe^tIBC_^ zjG5_8fK9JxskhTe9M_pF`A;3r$p zeePBhZ?{VDnq7e7j43<#mt2A+mXLfbh3cK&J=NBW#TDvl6=y4wcY3Zeook6Hvjok^VT>J{3?FN<0D{ zvJ|7+1!tg_q+l}fKB^Y7tB=eI&NeQm)(<->Z?$zydBi-CYXoS2LcSpzO!?MAlI(4b zJ6iE(_a7$T>a~X-eW*r1?Gqp<=@J|HFdt%OP zX+7<~?4H%>n*G$h*y7qHI-2uivOKo=^TDa#C&wrLNqCw+62Gs3l(el$qKTp=h*;UC z%12}Ch|_J4ln%Wg{%y?dJ-NcKISj?{OZppYr^4G`gcFFv?G zX<@4%IH|~cQnH^?YhVWO!STYY$CxldzUP!luhHfV>q5XewI-UJ&mn&vWZDW|UBA5^0c7saV+@A^DKC&OKF<0?K4(P(wswMZz6g;=)%GskGt|sY2}8dnTw@GN zA&l>mO1R`=`@Dd`?#a#}u^SACnGzI9X|&pt2!2@Cjq|2KFF@{v7!w zA5R2DX?Zq4%Y@o#Q9~vtrgiHm)%6;hW6SK)w5R$U*3&w%wk*s$WHPJRc z6gAOJAxk-2_ZAzkABv$uYJ@C#;NeY$O1&$5#o;YZ;*(tKzU&`yr~nEsH4J*du+8gI zteL)ZYk`#yB5rcJ4-4&}zfT`sIL7RT!P*6^axD=h2k9M*B-8{`&`Y+Yi+5o$+agvV z7w(h|NS&;myXDQHD=VANwx2xP-qjP9&^9;a$VlL$p}^DCAB_vt@upmQk4`j8>+6gs zaHJL#W_$;xH%oh3pi+f@&KW<>l&nxFYqFJEVSkZB>Gn=h9yT1L6*>ophSMa?BS~?r56|g30W<#; ziiuF^jV|#wSFuC+zL@gd+S3qZJ4MjFTd?wb(u!|ZB`EJZ^ehfy+W3=gDzoCZ;NkbC zj0Bu+@;w7>B3?dvLqSIGuL|l;R*&;`twuTX**P^1x*BuQ68$X;Qw}W4+C(^95>4=DoGwk6fS;9!kLsp| z35J5-PpFgyTa)@l+F$FP_uOd&ohK7m^_`2fxU>%)m5${1 z9a9wI-czW%snC{%+%Z4{>ewL0RKEn0>W}|865m1g!TFw#rfY{uW)c(80}- zZL8>c5=;*dJiNP2FU)@%4Q0>=!ntv@$!PEdcIQ2kmAV&Q%A&<2Fr=VX1N)V%5quFT$`x;v%+UCCevcY2Ah05veyboex3${g_w zJoiVnISGE?v0}!97F&r5YJy3{84UBOCBW&=UWPJe7m@0dV$^~$Bn~3!veZ;stk_bw z%TesYRfZd3fI~qkY~(gYi?l_@G-HUSTbnxO$aU zCjPCJPl#NqNQNWN5ZzhY8DD+AGukkRm{$kVVcia}r>;}t^E^v2@{ z8hcSxml9w?NbiawOzv8CU?pPPtx}9FiUw1a&G&Dhg+vBvX#ahvptG=mq}{r8v=f5l zyu}4SI;BbJtt0r|@j`KjrszE5vg`b^fNAQ#@n4*?#(KzqfK<9kZgLW8r?=10cIAV4 zr}_rz!7dP_6Q@IJf%1fN7F6r~4#rY#65*bJQU*xrk@q>kJ>4ISavd71@5|F|R=I&{ zo8Ctx%|x?N4or=QznyktyKB@Mgnr|*w6Btm^;qbtU#FVN7{=9jpxL6*u-wB;8op$niwEN=vi=s|krCKvzTahg&nWpX5&%7rC z3B>l%c76Z1*sc?ma9a2e`r&azKbSMEIMZSDM?3mwT47a~BTbA>I`>u@!$$AH^Jh$^Bav@{DD{;gR*B0id_&ov??n50jCp{ml~-cMIz zza-enD_~W$CrmGtq#TY+dzy`Ov7DqK1P}k?0%`RR@)m1K)y%EBu2r`8&sbQ=yd+DL zQ!^F0ms?g@M{Y#;CoQVD0Z!7kO3PYQuS$toPP4!i@cRE_?_JlUII^_S|8o^-M(h$c z;$+(0jWM+PRiWMu?DORiqia*Nk;utO>?+2}B*OlrX+-JEEk(?g5%pA!LY_A& zps9)R^NlS5r7=vwzJakk?gQN7xK}DaA8ZYPN_f}q5KSrQa%U{7@{{6Re_x1XGS#+` z6m|I(Q?sEi&c>{fX%NdCd96dWEDK`Fv;ic$TkX+Jr`q_PJ9s`GPU;4xHgZLDt&+Bt zuuo;=sj-&4T#C1f&3dP-8HySPC1!B4JJg)k=dp@|`J0)=ZY@LO2^$eW1UfxMNioMu zh=d#+YDEgB{tjX4$x;2-dIQZOLe?+#L8yMQk#b_Q`x;Ck|~Yt*IQe+9(&}!HN&; z)RXlQ1XLYJ8PKO3KL4l(7#~SOZUnkoNNo7M$UFDX<}&24HqLYs za`|T6yJuE4xCd?`uH8_a`T#?zE7dQ*xasMZn8=h^qLEmiHYy!rP_V)+N8uicYRlf< z!DXwj<82b$w^myftPj_NSo^Y(oH;0yt|ON%9)C|D=^-l=85chZpIteg9{0yTjRwaD z05=a_k(b+V`8E$-sl9@yC|B)k$f7`isE2op-sb zhZVWv5_Zsz(1unOs(&M{{^RKh5<<@0T@sXSS?htMNZYkO%$568d@TJjeNyjhrCDPo z^tA=eQhr?Py-vVpq0}K0T1c762k|sxFuVQn?#UQ2b1wp~gifK*&+XQ$g2QOV@4HUr zK#2(@b6xY@2jQ`H8TbECKom<#ToaLzF}GM9_4Q)!q`ombLvz_x(9NZDj_<<-+eoGY znL+Ku?vgCJ$)vsE|1CIkG6l=<<@%Td0fay?Zh}PJV%4`gbSFhJFHheN2Uik3L!#iq z1btj~4^72lq%LM-puVz~TAula!PDRekIWPr*K$E!E>?4XRfp@a{|;wW0VoY1V`zTW*my);+52PC^TTrMRpo8{wy+TG2s}fXFf*jJ2dAH@rnL za8RS#8(b4ZTm$aX20T$*wX3~U7nPX1i2Ry=fgSR*%;<`eWx;gNq-dwNOvWt&VgVII zI?mgrq;ly5(W5v@nQ{>Yky5PXrRb!U1_F2swrz+}SNEr~G-XjlImqp*n>n4!EOH{# zv1-0JZ6vO3FUr3>&)Sw!FD=LKi>AlRTe%tm>)@SEFOYa6QL_7p{1gof5dIH7E*;?o znH=uMv%g`xV|iP{J(^0Cr<3W?d^FemM3KbGg*;$05Q=#!&lcs`n69`^bq{M1HxERj z+gh4`PI*EZZn=A&YC(XP(aj#rnLQ7?SweNi-K)k33ZkS@1{++yyH%7?aUnFSTJu4} zNf1rI(8Oyd7+#s z*<(ugo8Y)f&qB&Fb*nE)&YQ=}fH?9qlOXlnnHTn7a#vpR0>%LyC~+BB(;}JC<_8|* z42zPhD~AvF{pg*Tn&;WQP+Re`%*O88inu1ZtV3M)gX#F>a3X%i=CMW-1YDwtkxB{( zY%(3Ntm{}uc${&?e2Etc(k<{ym)G7asK3tPh-AQJ%3Omfo<4k7KWY}JAXCDN{TA3u zWSB+I5$B`VgS%X>`XWXXN)$YB?KW9kxqsRIm!R8LW|c6bavQ;_&E=ddYNw729nD2d ztxp2St1VRx=dY_RH^Anvn?ME{O~CT?CFV)OmBSrZ$+HIHl6O}GlR=EsnNg|Z$V3Zs z+8nGJY4wIKY>Aje%sI`ORzeg7>u>raT!k?X_q)%z2IX!e$#)l+QYJ5aD&oQFIuB*hqVL-L%Y3DoS3d;p8a73J(&q{ItCTSvU z60Y(A0S!eI76_E(_-UfM3acAxUciioP+aRR(rLBT+CG*)iug=gH4cDq17YEOQ=-}; zs9nQK_kzeWb*Zg2_QIsYC{rEQVt+0(pv>sDQP{(BCoWsN$~`g$+DpVtVPlHwX*~$$ zfwDondO;XbLJi>Tt*n}GM){$?YDCX8vbbXwxbrPZTE{jSIBpF;(K z!xg9>9c>@?_mMckfT0iGzt>&1r7otDds5Y~&s>tJp5w339u2X8W@9%^!}yWx7SEB| zi}%PWbGq*G4bcI*6Rq1P+8Ppn@e{HtNCrtUXSivdm$CRBj(M_gFIy4`VC^+Ft_^@( zV(4eGZf}0SzWLXU z&FYu@#mgTaKY03Z!vhnVi_20h80&mHDOt9y;Wmy%j2#==}c<;z4RN@DpX zR!by0uia&zSWDs~r6y0}$HHlg!md+Kqbrdf!6zjB_UR!i5pP$|TB+VyB-3Q68zIQf zibz>>^+k0{Yqri?5@x`;GtI4q!!4Y;?rmUiy)lJxF9M79MjUHIs=*~_)bBYSp-x^} zyMz(rP>iI(z*kt2Yx0cxfR4#lv?x^H4=4K)({mGLi8r5Z?LlTR@v>i~lbz8kUo^Cr zq{0vAs%bluYuNC!fQ)<`1W>o~YvAPsS?H0$HQxX@VQ#h2Hro6GnwYoHh%|usz6IHO z<7+m!g$7?oZe!@vNL2%njY*&SJ5C=9M^Y6aYBSx~1Wab7li4LZhfdy~4w-`kpFcrr zV*e}(0X0s)>>+buFu(7)@&9=8{YQ=g{g1=38wyLF7Ed!1Jq(-IsmHv92fupw^vT2N z?#Ut2(p!;oURH?F%opR;x&jRvym>G^1XrOKC+&H)ck|i}C>On#FCMM^DLo~)f(l@9 zhh+ywP?$5O@$$SIA0f3Byp8>bu%cN7qD22uLV%;cj)3{ ztc+cCICN02mB`kFJyi|Gw_FpE={oosH&P=wYxi)?)%r0k+MSbQWDvu-9ZYT7ZP0Uk zMfqDgsKinJcH}Ugi%>CkHJ#*t7Iv>Gom1W8?CW z=}Qq|gh4Ga(cFIQ7z1C|fwv0nNIoOf`2o*5+)-2*kahO{Fi5JvM10m{r8f7{lc{cD zt#M6&K5G3-lO{gr_fKE+_hm`e1nJs6++uUMDj72a`j_Xj>v5;Gw%KLe)^m=kcd6yp z=1|tUO|=Mn*Q&oH{RfOD&uTCMJ!CVo9YBSJH>FDZ@3j}ODaw@()n#VW=`pmuHZ5j; zdbl^8oYpy!7=Kt+@MNHrwkF z_bFRS;ZDgXkwP%AFWMo6Lcy9SV*C6=M0q>;>Q!ATw35JV=c5x*scojnDA#j3TxR<&v=9NT&78H> zfdMN~9KYZoHjyDYQGbGD7L28|=Yx*yf=}YFWZ^6!%g&z&%gr^lm;D#motbfGh>=XT z*W$9PYY*OjeDD1@Zfx9%HFW;5sa>Wc)9>yPyx387+kY21qNsg!`8O_hbg|DkYf(wN z;CXvsyVLeJm}3_To=3gAu)jMh(WhdW#-ku zJayGBU17K~nm0)zNj>kBoWPiB$?s1knYLE7qGkC#DAJnaJ{CcO3ha0c2hXJ0x=x*6 zq>hmTu7HWyNbKjTIQq2rdegZ+9VK+V94tnTmQCPz6}EZ9&s-=c!^;FkglFv@Qhp9+ z4l_&|882H$Y=L*=$q`faN~MM%B;lDq=`9PuaG0HrS@3Sfcre_CnJAbvXSh|tNMkj% zh@_hw&+0D)wh=m@TiVcT8Tt?hYu2NLfWYBOt9{;oGlUG6y{IxKQXjNSpD5jy7_1d( ziFI%Xv^VXjY!j!YVJ~H_DHs@|4qR#cf%=~H;&=$ z%O%E6d;Rnp2U<>{nJgXZP42)g+oE{5>QJSpAG_MBAq(qu7jZkZQ9Ce}l&T{wc_Emq zw_WfgCBp}?JdC~5W0YvYDLU(oYD`L(i2-rUke7K5sy+pM`4t)QD4onHL_6yN66}ZO zfZ8j}5uuEY@FfN_VBy9X3AFP|x*15(+j6fSI!S1Yn`Mh0P=12?l?z%TkiQiec34NKeKV;xKB6Etnpro z=GB?N@)a2S1mcnw^f&{s1pttpG19NFFVH-3JJ>8(Wu!6)%ow?zFEQU!-d7E-nG29`TCQ?VyMuhz%o z>DxJN`oR?EauEI<5?UP}gkw8UF_9K-h^x7VgR9ke^z*Qq|2#T6LUB3FV{VoTp+ma| z{mH&RA2D7%zwP!>e`f?Y!n5fyF4Y?iXVu+3dGeiYJzYa{`Wojhz_aQgxyFbkKr_sQ8KfqNKF?SLO3oksO`ghX=v@qAkC4B_6G&rt-y zqQuFtLKOMoXu|vShQyv5+iEr9aKQYydcN`EQ-}Q(tY3R z05c*=!4}O+eFRNM>&B!3{J8-gN?YfKGrBUGU_KunpUft}G29*bgoE%f)6zFGMT7i? z)f96vdpnvp9c#-XJ;&o2(eCK}#5_R`EzI)-6Sb)u<%I;PMn>m|FMW(dPqRIoYF`w> zs!lY^eY&ugutzNRqyF(OsOy#dF3Et=WPUWRjQ_YRo@RfVv*r=5l$BM zPmU3(UOk%iC&+`iJFUJSzM0PYV48RLN5|jojq&qjc5N~|F0gZfA@FheWeof%Tt4oc z%vk7=`GWOQJ*Cs|Oab+h86Vo-7A`$I**z}g-xsqtAhFWsuiDw0V^Liv=h}Z69@jWFxOX2@7A15W7c{!8)*({$v^3`Xn3GqR zBN_6b{#yCvIEgcmR=5=p-gg_c*{rNjs_cn3un2gmwg7YiX(8Y?L*8*419EWAX4Fg&tR9kBJk_3OWGb^{b=F@s$XYFH&hb(Zqw2NNYnU zI*h1|%_PHrQK+_vwZx(1c&e-A0giUqkC=!@Wzr(xU(nbJO{&=id&h};4|~cm+2&Zk zP_a-HI48-|KpCdCmyON?I1^mNiK)(vmf8##+sttlX55!4#CI588^(eJC!s*CD(s@$ z9DsUc6uTy{Lxsh&t7~9^=x|DPNIwaW|1E?E93`V8$!4r8$H}aw$5)!5d<1P$eLIjc z;58SZ+rMys$wGmWus|->K;8tDYu@O-!2;<3!P=;=0yhsLQOo;}D}+9-w6R4TJMo1o zBTKNi=|(|7VFPCnfBi#ZEsCRa@D^c_4X^~9_c|R>VERNXF9$zyMq7Z7U|4ej?D2w& z-RaTkY_xxHT+t+lhixd*aiRe=ShiQIqw%m0iTP%PV~(u%{o@B4KWuK$PTw0rj}#m6 zEkc>#lCv{W14v&S9vAoL9ESQXmz#*9&#(W>zl0du4o62&A)qS>Eq-1-AL4R@Ih>@3 zo1(J1JDttwQE&mqW~<}VBXO?^q_oW8-px7Bzx~huJNuvi4~1X!4-pnN#u)DY*KjsH z9DaA~Pnxa;F>8OA9zVi8l7j#q_zHZ@2xh}6UhMdd1|HB8OCTgm&vDMH@bIyFV}fHs z^VO{M$8giYA3S<9oST}MEJfS5*E1zF;a6~|W8U8%@_QAVul%uinW5b4@(C$hWIs!) z)H&Gy;vi5UKUi6at(5r{X~i zi~9o9flqV4)ZBl_%Kd)2KiVzKS@wL9;`V8#KKe`{#Nc>zI4sOnE3t_Gtg@1L{%rWT4|IGY)RMxVv5}O?4M; z+1a(f50AgwKSZ+MJa|VpuwrKk0c5XI#fauc*i#q`VMHQaW}wP!cs@TqW$a2Y4oa^# zkNdknH%+t+$p|^GF5SI^Tl|K*qdtu61Mw+U`>^WZaE5-+;z2RPZiPiEo&ja_6!yQ7 zW6}(%U{9F^U^TSYfwXN!YWhB~dz?nkXq&iY2z@mD&g}RbU}?A?a#{4QuWtP(QzyRu z7MDRWEO_PSt5%(1H<6?31U_w%j zq)K*%jVtS5VYxmLyR*63B4TfjQ@{Bu<0_Hz+@9hCHrEty9hJ#u}ZlkRc9EY7v?azk8Np~B&*pPykud|s`cMnE$q!koT+BPBR>^c>-<=mMm4c zhP*1x7NEKS@QnO{!a8!bcQ_19Rpit6&xsuNEu zLOy(UROqa_r#YVA<75j;#U++9KL_~*m@ z;X6Lx>aYF%HUGJ>_UG+yzFvF%`4>sLb5Y_TX?G8{Aq7`2{p;OTCJ>U4t_R~j?HaA{uBQG{$(l-*cM`mdiwr=QU2_wm2E)VnB zw?lI)@^b6u>xc`%2Q>=}&|crb>%f}%o@91IZk*xSJ6uy?np6OOOWI$nZZ@v{VRh&u zg}eL`1&4*~8V>Gy2{b21RLJ>rLg0YM8c04{(5#I9aad=3`rrf`RTEn>uI5Dy>%0T$ z9LJi|LG!SllZTW;Drd{SEjn6;8^Aq9E(19$(ck~J1|;!@^GBjf_O9!lJ!}ILkWUa% zKw=5AFr1^**2?HLX16|D#WQ|MedA3|9AA1Xa)7w;R1WcF9W-a3S07*)nEKBMWeIv9 z;_h{X2xp&^bBj=2yLU9j?L=9Z)evFx#Fxg;Q%hHdPJ}3%)niM-4Ig0#aZ{EzS9y>H zgsh><3udMg4OVqgiyK!d{PAW18GmWmrSYB6>Jlbc9A@FzSE&_XsoY4wak7LyWIfc* zxW_s8jFyt0vK9P6cZ2EDz_44PmAqtZ=Ca-2bH+AHSJHzybtIu2stUJq}+t%#cafQx@o19 zE5cW(A{Z^z9thd2q!#N8GeF(~N=R zq4Na84*Wq;z}s_-4VtK>oPGNI;l}ee=md#HU;rts2{5TPLn7sL4aqIp4+NH+waDt( zo*#_%j-l*OsQ}3bN+j(P4ZXd6dNiWo&YNLD1yPQ*KZ2dLKVwvdHA+bo$Hmf-<@I*X z);K**OEq5Lf5)@a!qW_T-2iHZT%pI2yxjv_jnby&B5bOJBv!WdolQ31@Dq=#)_*0G z=?p?>qKzx8GwBn(G^(nAKuJKx2!KLSd!QsBBh+4Xc!FpHMAlNd84U*uc!VfUa!?}m zPUg(Q7{Mm{Ex9rC_1{#iioQ%Ayb9}@rAfU3y+&UeE{eW^6WZybH{Adn*mSs6+`uPY zoBs`piuCJv{j??2+!Dh22CvXf1`Fj1k05kBi~)Qoa}t8EY7wJn+$D%jXL2{#_040w zA=WXt8mhf%qYgdmm(^C!fr-!YoQKWLb<~Lt*R#!i*F=ZTIigQ}m0)uLp3{Mt+3FV14Jtv|e8J2a zQxJmo?@-I7Za!d}QClE^fCmmp=eU&6qIc@+Pr+e@lht8CW8Oc;R=6&sxFIeSNy-Vt z@*%QL+bu1ks(o90lgd_LU0EdZTz8CD`hL$Y5M*jPE})yv;_kQ-9~gE|H&bX!o1G2b zDW>(8h^g(JAhO(k{`pG0W{@76qBq%v{O7;F+u4i_c2TC-EB$``iCz9KB zBDuW`k=(8mNxe=hk=(8mNxfD(k=(8mNxfPdk=(8mNxf1Bk=(8mNxfbhk=(8mNxf1l zk=(8mNxfDFk=(8mNvOAoNYrF5GLY$bP+BqdS-y2EWgqYx;IakC;o=&tWB=Cev?dbD zOnxqPS4aJ=Kctm#Y60C9`>Lby)*sVq*lySz_Q$2({#09PxBg_+T!-|vwgNeB3|Otr z@M0(UIISSxWH zNh`_2)>ecso5f(M)#O-7P?YRm<1>U~B*5#r5BTR2Q2d$p9Qq81E_on%>x!m&jE(1B zA9p?sam>hPdo`JPTUs1zbp6oj78{RHwl{u1P|RvFs@BGL;hclV&&a9akBmUu%8o^q zAS1XIkG}=0dCUO{|6ES`#=QzO2~*r6!##1w-kh zl?r4hNlLcNQGyC>%B&G1a`OtN*bQ13so^vAcB^>4bEjR2+rptIV7lo6Kf}&^=-Gkm z8K&vaH;!eq6HMDX)uqexOV@CAg-L;6>P{!fPX)*?&#&~NZs;v4l+EYVZE^N&mAg0= zFSU(pv**}=W4vS6$gk++cn>WbKStWgK)C(1sBOop&QB-J$JP2zM)N5Pxfq&HP;sF& zA0d4phKtWmgO6PZ%_pN!wET`VpO5@ZG@lHlMDuyuj@53O#~E9VirzysvT}WuDxJI@ zF%g=mhJ4<>Cf>iZGy0^BvvK;T0*A}D5`S-Hy;>F9h}!u_V!1Z5a}%A`{~%6l16_{T zR9a28)wFK1R%^jnuyS z+&^~wUw*lDd470#?%xnx9E`TF zVY7wNG60GTCx0Ku=O)^(pZ2d7>|ZsaER>yLPAp{vC{wpYFKh!Uwq4qU$~T!32jr%x zRT^%TxeHpPknMu1Pe43{YG@@EL90x96uQ9mXyTMKPfc^THvud%h9!)2=8>Vdv*?p* z1?+y}ky{F|kD`dSf~T@P5vC$dl4*STG4FdGuyP zn_TEnDj#_A)@xM_J^b8r9g5H>B_U&m#LgDW?a56uo8>RW(m>9}*+j(CD)nO0inNQb6cvV3nt^Rwwu9GL{XsYwW|pJ!}Foaq1q zYD{779F-Lgb(Y%BlHPbg4Izh~DG`U@CpZ#49CV`@M|?Wru^7je1wm^&F|^hR20;Vqev&c_2An<}Gl^)xh`lxIJfv&Ky8q?uXr4UCPvry3}Tw*T-+kA++U<%GaSnfB$k-@xP%M^ z_9vXj5{l|X52VXR5O|B2K_sG93M&2DDyP%H%>RmAxoU9-iLEx=VTv}2OJhb?!05-Ekm+-BNbmG ze=l4;OmsU&nxW}Fvqy`dZQKNe3r-p(cTt_kkE&<0DRQjfY&stN^~H;42#b)UA6I$M zqCYvsvO{M)#0w5m3$H!vMR5-~9ykv)Vqb?Ja{cMgEPhtK0MS8f!LbNbU=kJl(da~c zv4BH-lNdt$^{_yEl}JDQ4JlYW9?v9N2m%9t=RNl>DO`yR?}h8&?b^+z_PxovRC#pT zbkbxV=RmLKZl|OG3gwThbnb~64dl7FJn-ETtT&r!sqWG5^qBZ}xX+PJ8n-{3wp7Ad z%e~P%Jr82vQ3vLkl@HZyeJiZ?w5%8l3RhP~xQ8%FfMAUy)57zYKlF0$5yZ4$A4lT{ zO#7jG7`+`F4j9fP=I@IytfbDvWe7HjsZz-x9v``%R{;b%9c*`{UY_6G+5d(V^7Y>S zH$o2gkOG6p+i}aGzPX1&*YCZWFoT0O4AysFfZ(v`V%5>a0k+y2>jNaUmbD2I;PJn{ z9nU=nU649Bx#ysbos+#ipfBnQ&Q9Mq#mTG5ysNfX!_k_H-SBhc}lYQQNZY5{xIN z2*Km09WG2-yZ}-Qhv)?Vnc@#L8!{9SmpE$f4CK|M1N07#k%Eo^DwQRJC}#dxKn%;_ z{LI9l&3*_mEJvk|QzHhEEP(lmb9kgI@7s(*<2-m2M zg}5RuJS1@;ZNk2z($Ult8unhDA-lQ(q@7c$ICHZW{Aa7u;X-A8f*axIbKIQKDpTNH z!@bpX7g*uI*z1EZDZ+`*gu^jp46c-@3zyK!^5S6*{5G_iI08(f!9dk!W3wp&Jp1Ox z)9*oj3we9>%P(DpbaCQVM$^ux z6(e|WB#|u9#BbzpffZ*32xsnKuLKAp<08NbC|e{H!yxO-#Cc?BXUWxCzj_4P;(r{Dm#_C!d@;-3;>_(gT$B{AC2Y-915?0!J}=<7w*=pP+KLC_ z6M_Mco12lrg()yNPjJ*scm4}bVs1oK*gBLue{@06v0HP?{M$M9LL*MP+%k#YAv>b6 zR-l}=eNY_-=`DJ5AQyxmCCwJLFw16Jy8T#mCj?GM3r;POL1ZZL(6S` za&$DMUn^G$*Zo+!AMJzBWq3z1_c?DS6JOmOY)CLe88&gCRH?mfuWF|eKd)x}x7!Rq zyHiou0~x|{;$ExO;k9Da=}^r2@UCjk`9Mp4)oWHtR|2P1KP&nmD<$3|FM_`w_L}#+ zXd_Tut{k{#rBIYWMUz}>0khU>nO2qdcZRkZ&=?<-3>`wqR;}@h$x3OEcvfQja5&o^ zYLxJ*0%K$E`J{*kO(LS}2NQZaBzdiiBh;s_%R2J4%2u1sfMj+1A%pprHw+aaS4EfD z7z>&Sf})&$o$BP+8&-+~7rXNCMuM5@nh`*#o2JjiXW=|a3bZaVHiYCvE-aZLTp2RL zxGWuFm^=r^^xdXL^xT+`dWpTwd{x$!L;?^#Jj4p`xlx;YkRJx{64Ht=Tj@~AbyZr) z_OML1foEE`SE~g*HKU<8v3OS^6w|QYt$xl2oMtv(&9r zE_1)hvMuCS(=5^~O;;k)_UYyS*9U|-xAS~DtW`|A+B(k?whIypYt2| z&t2V{lmwpbp4a3vhHQjF6EjLuFz8mnaPh?HRhSnVME4Y0WNf)?{cFFTa{eaeP>N?!)Y*u{&{I3 z9#bUY8VuYC+cA+)^>|S%vLZBRQ>JfmfAx9Oi#IrLkgyxuFE=-yZ$I2X;_?UUFE$?5 zd^x0$rj%QsGwcK!6A74PHXn|8#cUsj3wGXG#9g-bAlpT}vI~5$gRKRGsCX+#5ND}J z@Ry+Vt@y2@e2KfBth;KU9?Rkomg@Q$z{r#j4>-SAU2mjz$O{@dy3M9QPbhn+nK6vLh@}s+QbzFSQIdVGvd;%m;}`6NT|f{~cm0 z4|mWaw~le&mu@)De+FSd=!yc%oqVKUw}Wvzyw62|yNbwy5e|nPLT9Imi3@9SS&33T zIZ29R?;b-FihcrLE-%mZzuJ;hBrcG7i+hIm(5T$(t2Cf-3W`m=clE8@GXoMPUPEx5 z_iV1?(DjPMq8nXRn@V4Y93<{hhUtSm2tsQhJ%UaSh{5jSPL#eOHQ?6t4dB&g&1i@- zr5&KMHU@SeU*^>+XAC(Ke3#zoLa4~m7P?qqVpzGd4yGV^^aVfl2L*z$EJ%)c8Y7OUgU?iU_BossIV-Ia|Y=v9g4X&v38HaM&y>d z<~`H{u>WVJFE9Bk~a*?J|dZ|-IK6u<0@L)O~_m9v5?#qCCzYk7oeBahEj;v8A31arE9KdHO~ zS&fq^!H9v7x3qB6CBfqSe880GqRo)UHVZS-9J|KUOB)%5}76i)PrbX=1MW{9|f`i5|y!3`3V6vUlf_HY#%yY9ElG>Mw-a z;X@4ifNE1h=-QC{yV5^7o`N+UjfXI8zPHQhg&tIsOI}-3p+!T#flJjzbZ-SJFKp^a zZeUlBMG=J#CC<$XVxmv&9kNf%Lk>eMF}j0cidnN|wFS~R?i^^a>j}2_X;G?v3W+0f1GFJ44|>&n_ZxqBR&2dXHfk(#vnI+0;b*YEVhi6^FwL z2>subsQ^DWpJw_Hr=~VvJbe5^B04!5NpdGgKxzbsxC2}OB-oRb*2kw|cc6*66`&5C z?mwTHrggA z*4rBEmY_oDYjrT%KN#ab+F#rk(vvMU_*0etk^9qlK?F9A#ErJvJMg_XwFW{ddmS#H z)adS-f=}pyq32{_eHv_ngBk#+1>CKEwl|#a)kwL)E@XOkF)xDFTG^}B&3t04YaU4# z{TI3@EKz8@vs(8o#`SUO)y+Tt@sb{J+AS>)FQ`c-RuYl|-{Tc-Ai+^vMOI#0TN%~q zl282uEIolEkaw5Np)T{VJ{)ob+aT~#$=@(>Vuo0jiklBFC95teo$G%7O4uvb8=$|@ z1w8KcE3H3ohJRhz?p}+v8VM2$>oP6s-&<8-FOW`5gNt~fOcD0Sm;;=e6nz2LJ0Hu9 z*FrIHGpLhDBHDQQ!OZq#8??l>jIsG8d0>TCD>>d)m>V6CQXuk-ETTYRH}E&oam+P^ zgC%mYHmoby&2Y=rugUX~t?V)`xwLL>mDUZbp{I3B<;x@96g+)`NQ9f#TAKDCxeC;a{mP z<9gBXw9J6&a$KMcw+7F`0{>xxq3U?A0;Y6kZIvtLnOe1A??l-VOq`t1N|t751*>&Sv9EjhOu63kgV& z2Ff$SnoTxUep;YOF8Ns>{!p%Rk?D2|km*~nvrV>RuhsUp*tmT%y3&+jf1|F|z~1>e z8erV)M->nlAJHY;=z%bm0QzH_?uUkdqOZDP4=mGk@9x3)UhkT-HZz-)&4Lt0SFZK$ zUT2XOK7!7lBVPmeh78wd9@w8s1FI85Hs#tWY-BOpV33V?*WUrK%gsH6@QiWVzrPR8 zUqeA+W%-tY8h(09x0{A3Ur##5syLbP#-_;7{Wd|_r*qCdINRF1TAlJbY*-qTY2I#kFd&HU z12%(eFk@^0S7#t>ayGUa-9y#l?sM#5{TB9aL*q6%(t3J-ocQT@cbQ>*h;y^*E5RP{ zaQ1c-&f>N@+8!kHbylYvLCH7sR?L@)J;A>xm!O-W>~Fz-KO4oA!|^Ist&O{_5j`m0 zyw%<*H*+RP(UJ3JZw!)9T~G8I8gIekcIrx&c0%vubctKZ<|*&O5br$!Y=8q@h3h0- z9~)tg+&}5b+W5>Hp%JmTk=6y~!=iW9$wz~0;h{M~6uG!y4@QH*aPoUCjzGBTtZu9d zAbw0ILG^e7R}&!SKmz!5KJhMM?C0w+7+`>yc8v!Kb>Xdo$7)TBL|!6X!GjzFAT|k@ zHfqZ+(4Eej6$s^8-P;ME0RjoG5&y6R3D7szJrL`rbus=`W(^WY=5e{@7@*N}s`+{p ziT+!=pxG&I_*P5#;bTPqyms`Ng?K-dk zPX)GqukVZ|*L9Y~S9}eH)AP{OC?GNsx&eg{oDkkmPjX=iEsmfzDe74kAAyfg?`Y{?OnzthsW0c(ftF&QIst@L(fk{qSgeFq*AGmneYAO6g~JdUU$V z@q$BXTM2*if`$((5V;E9C!B>pGhM30^`w|;(ce_Kiya>BL|0&6sZP*r6j1`mkd$eQ zM4_KY6qFRvbuwY}AEMo~NaskL*JgTjGG3wOrFR*Y*anfYx?%(ZOwiKmGjEo0CpKI2 zk6IgO(sntLt)@-gb@2_B;-*K^$s%2@LD*mj;HY9xt4&j|$Ii7~QtK%UP-+Acbf zof%Tl*Ld``s{Hzs|5mS7V)s2p_y_{<*Wk{WN0^o7GB<$EvDBBFq!kxLIdk{wXV=lX zsPyGTwymH9K{V7A2sh?hR4Di_JepLtvp~8M)udsku7%{P6IBK)iTa3)9%5HmtN32G zH*~Ff465M`?KX5M1t$5u30OH&E1VCKU(hF{4FO9BPapZa-J#rh;%x-oK8JCk?L*4^ z0Q-m4iHB4LZQ4M)Q0`=ISR5bHBoPd>;j>;n`|C3(eX0QZkPLFhQR-r6QB?J~5&89d z1gQr5jSz6`{=m!}h@{^!WaDu3E=0QqRGJDKPm(fG!UQxG0#3t(;540@{UkGnOj;wY z3Thez_*6oyB}QToA$qQfB$gMxhOY2EOeUlvWfUGcHqRcw0Re!UGE5L8x(VV5U`f9j z4H+GcjzVan$0Vv;s6%OB5XK}<20z(JJ3s3mBZFko=8Qwj+D!QMuL;z39%)D$u3LyU zcZMIVY_a@9_Tw7Wg6j?}M1%c{$&2!1me=^xxA$cTsFise{3Z zcsM(otG+W{na2#(M(uiyo~8MC=Ke+V)&O_eF>s*_)cabNWoC|!$kAN2KttZ<@5nMY zdHx*QTP<`kgf)tHK{PmF&!i0amLz>H>(DuyYiKVJB1bynwk@3aD8fWW)JTzsSE?VK zaJQ=MoD-IWI7MIws1-?$Bwi7EBp1b1!kT#;qwSa>nN@O+k(pLWTpq=&mQ@3QMV7itz!>gs|-CK8W8V0S8Q7>MbR z^Rd?DZZhPyfnMO@VL8(o4h{=<<5XkQrVdcc5$aJkD zi57fk0B1GDZNokk}%%E>nN8${VPMShN7{Qrfv&_F}$2{adfPb+5WU7{0kq^jwN#WgB5D-L^Ui z4R<>L5dQ!s{-HAhk(W5CFh9uA$ySJq9($tCr(yWJ`$2#OTSXhqtrRxHPlk0At^=&4 zTH`A6ZA~wp%&V=qv?J}p%J}Krptv{ViI*WgxK(mgWj&)r99se)+@T&Zd+Xl+brTa1 zr4xwlm=0!$q(J%2X2~wSq|AxMSy(5@BLC4`4=~Pf@1LBP(;xppCU=0y zBjc*HO=IEx>d(Mscb2ok4_Z|z<<2&w)_C=8lM0Ju$laa5~`>!&&R$fFaO)Y-TK2`deKy56sF2bGcqI6tPQ zBiqR%KZlU#^*~Kw{hx~;F%;{_>Y zGC_ajaacL<+ajz~6@{vyrDVMRJ-H&#&*yt_?}gf{eGhzBrJ$FTD?31`EUDiajdOGa zlggqZtUIe8nrX6p!*RWQ+5f3UH+4|3p7aYAr2&g?3JhXjcq+S*&eeOj4WZs$!ZZN^?~(KnTe=5#@x^s5~*DoHhfGc=tOX1NP|ICDX-PYUoV zoDu>-OfhLT;I%eAWFcU%K1m(3^!5OW-W0;DshUS>W!y)8GByfNHZ&K>3u4IZSNbxA zC$!}Vj}l(z5S%=tu&x<5R&SU<;F%5$f3<6~PD)Y~S}gXj2b$*S5qW|moQ<#un+kzAhD4vXi;A$?E#1ARL}Ln=>RVZKp?`A92^O3E5=*5 zVNz2##NyXV-QwyYbGqQI1S7}h6F8#e76na))7@{Wvs#0?Qh@r>7#(*@4HKvU)wr=K ztPRhEBEz-w#G zd%rwGe~5V8d8JPRh#|As^ccb!X57kwxH@4efb`XLkp-3LPD*9zco)?7Z6Ht3%x{%kPhePjxP0nDp5HJ9xPQsV7bhdbMN zpoxUQk`bnli45Mumbug>$Pz;+s(pou1@8cqwGn7Wd$j@EpKy;HtU%GKB4}JH+KiR0 zk$|PT3qCcJ6fvVUN{UNjbK_vYteR!!%g3nv`vp>&iK;%&N9pPRnC$G4@cO7g1+pP@ zst@1@Z0~M$la^2KN<9az7PyH59j|ZUHR{eG4R03ff5jedR)-^mx)Z#eFqv~h*^M>Z;!AZ3Gu_7+@Pp3lLC-&UMeoP!w_{H{vANTiW^%I!ChGpG{8Se@=kQ*Qm!2ujrnZcD&DvvP~19ZGoQ+Hug1oSLA|iDpmfmQS*S zCHsRW4s<6-Gs!017%kRXTMF(*OPM8mCV*E)bAt)$USL50is^yEn>58>gj=$Z#4;jL zli9+Sq=H)Ay>{)|Jz8M2H-NRkMO;UycdP|nEEZerkHK*Vr`{%Dk0(b9ts}3=en_5o z>G~_Aa(K11^`D2YKR>*Vm}AMLXR1OJ+N}dkaR%r@e>V9xDA&9`-NNz!S-X(+YjO;q zv)%!sN^fovMZz`H2wI@pPLd~4HFAWOFz}dWvluZ@LeFU(#nu&^(7l;K|LjJNQD!oX zi#A!X;Tg=APusZUQkof6AZzX z!wn*BuMBV-y^7w4Im*<(h}8(KVDy!K&|lqIsCyeWK~^}KmcZoUN}-`h z*N&rlk0FrQdT3n6R8O+L!d=#Mj*?wh!+Y>0$xd6ERKWY<%>mMvM-GN_N1aoLC>A6| zLjU>9mq8Tl-SYsp#Jk~Se=?yf5RYP+G<4migaWwUr4NL;!D7~N}AHe^<*Ik5^ zWIew#T;nyBQkTKov)L4abUs&l{cz0H+xso93h^HA_h-xB6A}@3%u|JD#o7y2x+s(- zjr|t*lJ1trRMXThEk!rHWhp0ON3;RT8q=t{wyCIDwkQmy-6A=eDrPW({L!+TR91e~ z>xHH|x2L>6I7{qn+ek&4e8@;mk~w^593gnT)oi=6)>!C*VSHy`C~@cd^U2N_mm7s0 zA9U*acw4U&8?V-9v;Ju)S?A?JWBKH>!34JXY`UWZ)&s9>< z4L}$!!SoV0EiD+SSFa&)9!fBcaKfM9=S5u9zg2hN_Q!+K^xE6u4z3v+?N7ej$9bjk zHPGWdxs5B^IFJ2k%UNJyglt{{sky5@B6gb2kL5!s=N-JP2HE6l|rnzzbJ)`DVzL_zZy_x#G9JObSg2SG7!>(%Sq-zAIP zKN*b&!&&sxQl+*gY$d3F0pjT_KD<4RJy8DYwP>4&x1!uh4;pxj4#1g)3Jb&&@#ylL&Hdg@14%2#`ie~|~ z<`DO@jRzuA!aHjzG-yhSPa&7cky5)Nbk_HYDf^x=aUFTkKr*mXb)Hl^#Ls}$@FYM7 z{+?0sojX5nJiq^R^YM%SwT*A`4}NasQi2BWZ+|AnHU&We5KJ8hR0hMHll|>bx|Xer zkjF4&V5||Jv*I)IjW0E0ZFlbM!duA;zgSJ2Xf~1QmS@ZYFH6{0Zd|yzt(x@58qp0` zOplzDri$tS2uMlQX#L1k#VNlF)ae?K0sQDxyf|l6z$dnHkNdM@I8VmgdfE0i+*}8^ zsY*$iF~~YQ%7!*&nh1I0WTJRIBR$u4Cc&cCnHdEGPo;C^>x zp$+fG$drjI@R2*nQ+kEB*X<0xFpGEYz>dNw%93m@d&?dn!;^qctqJa95N`d)oM-5>3SpA8qC zEO~50Qh|K~E!E@Z#Fb>e9ln!tQI36no`YtUhgCf|m|@ZV8)7}@)!p%Mh`TOw&wB9U zIe_l8yIxHt2dsw8gy^T8{_H2a$Nbixbk(QtcxzzxR4z2e$oUHFytihg9;*4My}-S^ zfHK>xS?2+dB#JqEIU5dU{kM;1!~aH)xCl%bMPg1!7+5B}>deH_pBNv{n#YZkM`+m2 zLx+Lj6mg>dMN&nsG@Z=Du)rL?baYqvbBW`+{;Br0{32iER8g17C9>fHD!F=V?<@ZsX z)c&5ThdiiVI$6Yp8R*!r0#-JO5FC%`ze`mI0`7r7+E8}%AlLG6t^f>-3TzdLOtKUj z9D^zN4?QRIlcOWtj9ab$u=!YQXl@B6AA>Ho(oDm~(&!KafI$FP;e4uTxpl?!&PF73 zoa~;$MQ&UaddH-9T=5{%z;pLmpAj3+1H+Kof)qK;W6OvY60ez8q>qlvo2v$Y+(+5e z7ofD#f`JErcSsjD{HtLti95S*7jQGEDc5&WB??*TVDyZ~)3?>>^n?}=u{C2xa&c}T zHysV3q@%pGnvVg)(s&>aP+a8+gc4x2I-2Z`PX=t1K9a$3JUYbXSTi}`QH@7G539?* zj64$4Ef%#fg)(9)uEf%*nKH&hf?kd(eingIHjjQEGDJ{r`qGdztU&Lsv;;r1yl(;9 zjax7q1u&WVjQx~AnEN~vX$e&{TCylZG#FsirPw5pzxe6pWaiF5BK1j)!H8*VXP!=z zh#_#(@vL_2*=H20a0#9HjQ-x!Xm){yjke7xJ;-hE;6J9_)i%|}3zQ;1#^TqOyVt$1 zdaikcg!B=nJl!^Ra~JLkD+<#H48aO7TE&ksA|EJl)+(mMTwNuiDvCE7XI4 zxjYq=wiyeHQ;RK}v$oY})e}Sqd`Dvxi1h_#<(J1cR@kE=wtq_`x33?^cw_PSiv=rZ z-Sb#bmdXw7lFkC&d64d)OX!izr2_1sxRWkQ3ZojsvUHuA<)DT>uJ#lf>Dw4n`|1~Q0~%$+!w+n$<7-P4|wtn z2`I5lksJm0fj|+Sb7Sw;wXcvDM9!Y+foJ$0C)JnNZd|KgBDc@`@30Dgu7L1o?uxzg zt2noDgt^g6_tXxL7NLYjR%1T%QwLney=&XsPc~ls_31-iNQd1xcbayMQxdyM=2^H) zOM@i~s*N->jBqE87oN_I?U$Py&$l0LJj1n}DQrsiOM=4wqXBtP6>3r@<6?C_WP zJ+>E);W&#j7w>gOz|-oW6NrTnXDb(AOR}8?%;fQ=gL{tG7fILagxU)8|^Qm zIt6PP+7mZZg8-YTN!(E#tI}t*h9~n{wG9H6H#TBO;$5{Djm2mAnYzdpjL1N0n{QFU zxio6yC{ML&!gMaJ%twFMLvFQdeA)>;ELr$Jbt0sVoI4s{2d9%lP)K2Q;~F3-+%|^4 z1dB1{l;tsWlG7savE~E#IplRZ@&UAg9MFz}F+oIwZtAuN6G_1G;2)$;8+P9qrKqMS zS;``?2w!ucBf42otaJQr13KWj8)(CX>gr3wtGJEu=Aec>Jh@#_y?cOz6>>LReJUuj z5##g?gPCl+sUuzooB1#5Em${gXbE#E&5GhoTnpMSct$r4kB(38>!=q`YdXxO=XRMv zoO_0w@aNN9$9y`1h3K!bqK`EL&U_=Gb}cLiiKUmG0k5=xlFmH|%^`G8g2Tf>oNW@+ zYG1Gh%(SOe)US&qh}!k5Elv|#;?}B$a>O-mZ(V88rZ_WNe&O(P=X%T7(Ecwf>{sZA z7m*(w@=(F4f-O9T-*CmViF~eXL<-m=-RA?#Lqax@o2BeR9BHMV>(c^uPKXMl?Fq}&r zZ@9Uk#Mb#q9OPEm95C)hZ>pQ?gEu?`U!0)oKNRWhG|0#e46`sveQnp~HcYWa_tkgs z?QPjuw}zM!OAvaqg+8HN z4xhuO+~f$gN>g8WD)BCg*<4~mTi{-0H-^JBW*mTM(Z(Np>cjN--oL+myz#;!aD@Zt zY%V(W)iHi{C^}*?0ji|u=#H3rKJ1TGrT2vjZB^o9^=b8OZ~?e7I=qj21g%cX!5mB{ zBoEx>Un2d{Y{aOIIr$aiauY}MUjGdQ5j0^+fJ#qJD$!@aEeqm%{=x8qY1IU z?zkSzrbkD?3knKBzToj5`2fi_5=s(JuJo+jrC}3{$~o@A8e*fG5vojg zJl?|ww}QtQG2O0eY-G!_14i`T2Vs1YsTOXbMUfKL;})_^=cK_khRYYhC5L+mD#nS9|M5g+D_*I7jkF=SDGh)4%i zr(z2^rn?Xm&aqua8fx$5)@z`Jn9H$I@6CZ@$q3f3tSf9lk?aer$*-OxA@!SF63}Rr z3w~wk*v?5wyL*8?xJeCC<6XWOIwQf}LPXFI)fi8n+ODzQ&#?-TnSe29sk<1>;DFF1 zVUX1WP>k=9nLF#0TdmUMpMpo)bcaE#_FQ3W&iSTm zzcu_Tr8pKa+-mc|A zYH)}%Ly|Cx@>%kfBap!>E)uXKYpHeqy$5;|A1AyxW_y=$-!9{|ovRh^DQZ=W%0!2m z>j(r$j4w{{i+q=i52+(&j=TaDKBNUMy`aia9MCksQg~AI=v1NW#7Bk zXJi*HAxoOQjWHC?Wf>)&FGUaD&&yCUVxd1lBdU;{%;r$PY;-$AoS7u+_fRDYo3PYb zmmh~iRBXGvboJ7!cQ+oA>>9<<-NuYJC=q{WYVhX$ty_QVZj<(f%o7_n`co+7U!ugo z)zuN#&^-j`7qpDl0dl$7U2PaEK)bmve*j@7;)g$inp?CUvSmF-{2FhB&H8~@_^~|=28iaV z&{w;ab;nf_YCbU6Xpit(L-^=o4cHP4AtA9gj6&>`Ad9YOgSDcXce_NLX^boZcZBdsT{z`zd7 zF+;{y-4l2pTKEcHU(G4ft+^5#Vg5(i{XuPpBlD~YF1h|aHB^uM15el+K6_mXkpT@F@FiOAPNi>Mp-b(vTu9ZjJ*VY6wO z3La1&YXV3czxC~HVyaM&cT?6{U&};%^M)8Rv<2CZ+?wXy*r9nxbTZJw$cV6jtZNB$ zh3eNzs4VRC1Bfu-LYE2i_UUp)WV2RhG{4p_+3F3)$c-=@ETHBR(ONfpw)V~)m6+T< zT-BpYoClxPBr-J{LkxN1t!6It!P^_O}m42q7EKGl%`n*{OF z!r@bJdO03A$u@N%XXMNp63@C-=QG5=g^8=f?=;iQrsU16M1aC!Qhz61h?dZ{jMB<8 zSO$aD1rx{nw;Z_x{4KM5NJvAzF*bQECwN1>w# z&^hQRt^8qh6sRj%x^?a)RNXWhI_M=pw}4*sBDZr8OR;aeIZhkhhVlv*DvvnmWs~(W z8R3ScI+qyYs_WnC5Pb z*uLHQd(8AH$49C)VXvuu%=X4uc9&+U+5?V{Ew4+uUJG>+myO%(U%q}Ba^-Thbr~G@ z^6Tod;o#1f^UIfenGCO~!&FO?cDx1Dsj*qNMg*xz`L2Ge%cd>d`D)$(qHf)^K#{l5 z04W$K=Z5S0<*?-Mtd-#motOo2E?~{TsbhO-?B!5amz7tPFq;}s%YfR_Rv_X}8KNJY zHyOJ61z!Dt)4BS!E%CDFcd-iPbXQAO&YTg8YK0s!OQn>ttHh7apH*gIl9-TAX4#9* zC1*`XVA>zbfoZIkeqO?hXlJ#Y{8mTaNgP;>51V6;W31p4hCo<3Rsk9x!HLnxIF zvZXL^gS)F*8CVesaOj;kdk_coO`ZYBEohqWEO6c&La58lAsw&l0kBC5*@D8`aewZ| zP3Pas&FooqNO;2abT)!Ny^qEf1)qPe(h=KvymT((0`{)Hg=c<@W(yCJgLIAU2)2%h zk8+Eqk2ITvj$Sf*&(=D0oMy}7EKt+P4-+R_&S&c8a%`5viGxO1V73(0yC0#%Bg zh$FC!CG%ve_V=SY@iM<*&-MDKy!9~rM3)nxA5X7HnMk{um137yyJ!FIC^_Cxxrp5e#ItlRyZ-xtoh|vH~1FsSofsG*qzAlZBhsX`;?(R% zVBNKzX3<(fEZ+V;llWjO4@bA*dY5dV;LBoK3wGZJ9E+#9rAqD;Yzq#5@csJcrkto& zRe{?_?FYyIu+)L-&C|oZ>EyKaW>#JX;`#JUL1WhDj^oy@_tdsP624I0$d`52;C0Cc z{y)@#)i4GK%y^u$1$;O`xHB!s%$7b)iO3gdh|$O2bx6&mHYiU@sZ2KyK?(7qf-E?k zrkFo3=*`W8F8DK*Xt_baOwdU4k2wWS{L9UQgJi1RImV$PYylmaoMVuNepM#ZcI3*V zn3g?nR}1UupdwW@W16}asG-gwQs{R$LzkSNYh4j%Jv*0azP^zfGdoJ|jpWwT#-Tgo zj&k-6-(7WO&_ou6lwCq6>SG?k?Et`;3cbTjg52RJqGzgk6g}fUl+CguAeTi+oU%3{ zJCjS~z1G;Jp!8BKCTRtU28*jOWfTQ0O=$8?2Nh$fO!s36*kunTc0!_lbaWD(jkL=h zSsIaAh>4lsN?vB1RKcb{W4!y-&TRVga1u7zG#tZdIs$8G1gCXujOGuA$e_gi9qeOc zL)?lWaT<;^MfZ#!5llwcG{=faF!t_78OrovRMs>L2@_lxXCDGu9QN)|7DBox1VzmE zX4FJ7NaI!>37I-A)FRi#$r|ZL^`#KMQivx?OM9@8Y?uQ<8g-fWRqiE*F{Q2TAQ|V+ z%?gWf(Hf4kM8%GXnnkr+LSZH+(Ws7^ck z!0|@JBzyEWtBfAP9nwg7;;f}9tUvJdv7N=M79T)%Ij83|O*Qx_o&mKdJm@)f_l~J8 z)pr+gXc+>~y0ARExezp@L9I3il!x`X__1@$p`oxxAz+r&Xs_vNUxxw&#oXLp)Y|;J zR}6?yrMrg1>f<3X#f5T9}yz9IC&zK zkT0NQ~$WdECdQAigQIE6=q2Afq znh#{fy7`A%gbrN$3iRUxAS9hO)%~IjGFH2`0HgxwM$L>HHeItN5bGYgE5>+aDkx8aielmxIX_s z`smvt^mUvcdnA*c9~xA=yAVC|@$uhYDk;sbwyuXDD}~Kv_Ha(tEbM1sVD;v&6M{{= zecEPbAI9azO8jJOQry$^Qc=%L$_KfQrAF-5tN8p2L$$*+`Eib zL{J~ajo2hx0K%_DrZhL+Qk~tz_M>IA0}IyFZr5kC{%O5q9Oi>&p`DsaQQu(?2R?Es z3gi`achXVZ{Y%Jw#r7vrF>%2yK}WG(mbj#$8G;nj2?@)Qo!DXbRAu-PkZ#E)bo1o< zVz^`()y`c2BYKX-A;#I1z&wBAB~S@EWM#F*tF!mdg1YiP41|^ZQ$O<&`qmB|H8}Co z2>}}`u9&u7vgRVXy+Y&`(suM9@@G8RQCoY0o5C>`>#WWz+=S!)M}|)Z+M;38*l;bj zb46RjP`A5qD zqhX>HfW}UfvYjiy0|c6@V8vdcY4xjfl60IwZpZ!-fI^ct9TJ|c6%S5u$@cIC-Spl( z4<6}DXX>FocJC|fo415&FFV2@J{rPM*wt2uv!Hz8+$8W?-3ExE&5Hq1#8?}6@{;qb zSUMM^R5+$qemJ6||B9h-5Sv7u-u)Wb4N3ycFB#y0Gy_qOheD9x@y^C&1;t6(!qcIcy0D5?i40`0AK?;8)ma*Sw?KmKm5JnM{ z@CT>3n1ZHBaZf>Sk`CtFIS$nG^VoA=g?+lkd$&e;j^W@{kbDwnOq0+81=g**Dg0JG2*u7WQg|f?~!8pV92SLk9UCn`j+#VExUBQHqx~66SfK_w7mu zjB%}B|K-zhigO>Qh({G3PhfP72J5r^lS3S24=>Jt*nw$@+T-k$CA`Ww187fZ1|iq| z6I`D%tNwhdG7g0Oni*`X z*oT9+Ou}H|49NvEDC_SF(Z+V`R5o8OPn2V1d9O6zHrau7>zpV44O3N*=}PsbSQza@ zT-K0PDekC{4QD_eRi(obcF`c!si|e)iT5Ewmo%#r7`j}a=n-bLXEPkb9=*}B%QlUf zZNV8tfYKPIj3NlXLpOC=Kmn+^>3f5-Gn=?lJL(#vPxyL}dJ;UNP&9;B0L~;|F?oy< zArY1crF!#WPzrRTpX@yVmibx584;-OuU_%rU--}UmhHuewtyCCVf&3N$JP9OD&Yv~ zEqDt}C(U4Km_KoEw~b$}_MYIrxaxq};c;mW^5@~#t%QICsDzAKcXn0whFMscQY|se zZN|cA8srpFQhybvGjAfGHdfU~jVghmVkT)m_y%QDz1{STdS<#NSTaW2Vn?ZN>iPUN z<(IAT@^Zvh`V%b{Qzc1-_gW3~YXi29xoiTn&&z~8K^=Q@V1GILz-soMjLZgPf2!|< zx#4&cS!GDTO7{>r`_5=QI`%sb%P2t9o1-8%1cND}foF=Sg=2Hal7ueEq|0Ohef&Q45cW0CZ=cz5c|GAR;(i>e>FlR|)1ZPUg^9#5Vm zS`Pwq5#FWcLLx37)zJo}X#Id|d=`yTN{Oz{EySj-D_ ziW}&6h6sLMFxP4Ss#C4qtA#)31g8uy%Ed%8@=zn2@uem))7xrIglMjS<47cD0V^Yt z*a#_YSM3&od3l2R;)@39x&3oya?;QV@#Tbp>K(Zzqn)yhk+}V^6o0XR1~2=MMt+9H zl3qe4!H*TmR%PPZwK2t%%1FQ3AK}^nxx~3;CRF@c zlv6yzBUNnD!rV1gq4V5Z4$k;U9M=zroME0+T$Na<;smR9Z3bB*%X|GTP^1sotoG4% zUAgN%b10yz^;Wh77&ytZYv{vW%1hlrpWO0nCNwNy(Ga^PcjUJghG393h>Axg8i1E88n8;oG|C!2Z*SrzTlI(Y3^rn1e+*`3X7fY;Scj zsnC;>Guqlbvp|htN+7h6PopIx8sW-@lEr#DBLxqpW88;+1`;XVGXBBSnJ;n2vs!Xz zpHZyw5<1Vm;y>;*wsQgY+r|izcSs)^L(z;UyJs&1#02&)Sbnd##v-KtlDVKh?iDC< zEd@!GT1BG0n4pQFryu9qj(j zx>98*=%wm{h&JYr<=f#0$XI}pgysr89PQ4g$Mn-mgfw(6>@|2Q#;m(sqoM*_62NCl zzZfjKmh_U3!`@4DJ?E2_GSbkVoY^+4n13wJ25aPrKaJu(3LH<&{hSd`4uZ#-F*i<- z>>;=L8Bx)h8M=<9&FCy$0HLNy%y85(A9Wy};PlAsbX6N!J};}mv;;W@d#p_Jy0xS{ zg(QHF@jDq2lEekPTxJ?axlN>zYBS@IoGjE#O4mDpJ*9ULXt`1k)oPmB^GcGGN&9vnp8gUCW$sO0!l%X_IAuCTNA2L6|MrN@4-r833VC;;#8B8SHaadC8< zAijntf{+X?M$0Ul;M3D?X5AOlZn~8L>5FOJJjMpep~_KzV`{+)E=TqAQjJ%~$ERir zCP88A^Pd^n_}_+Fzt_k{M$U)P$sczF)rkzgCIN~?)+bf=(zCu~O=MK#;St(I{<5VF z#~VB5XC(}QlNx?t-um;Ot^WXqsb7bqcL>*Ed5#y(w)xxPEH7)PY4a6XJ(jBva9CU} zIY6$r<36#+%`1?KdCDjs2vw`iwy!FqqmZ%TS-r_3lKe0@SzAFcrzM;R`5E^A@=$hZ&zp^U9qiP zLyN%mkJs)k16<+A1;h2@W1bSh(Z2*pbl)~)8*ai6LO_VFYNg#k*K)U} zCOa}_NFQ>}4>@IlYrLSNo4#&bX)-<~ig@8BoIw==h1IWp!qbXv7qH`q`}72d-kB1F z>qwSs3S7&2ZHo>9i&C!x8MrkmEBF{}&^zl~tZ-t>THO?Q5VtOWON;Nb(Hu9RDg2>a zP6lyvyba{lp7iI?O8yGmAl&C6y^$mV5DYEYDHoh6%;JF)s8xzI$>90$_+&QGNCFjs z2;5Gw-q?XKg7o2bVi2ZsioqOpb=pqgZiDvXBAcBhgve$YN3uRdUXpaYWS7Jg+CLm3 ziWVYaUU^o}w&0Wt4K_i7Pc_QJN@0C<*qp-Uw{N)sxmoTO8kLPj-Yum*UE&k z02uJWXfPN~th2J9R4&;v_GM(Ed3(gCgy0h}%L2oOKu{=%v4s9y8bGi`MT}R2Z@zf= z_=o7(SV83U)Q=6ak`s#vxb@`aOuQnp`4oDjh?4^m5*k`-3TaF{4g)b1o6zV&vg4-k zLoOG}uVgP-NC5w^hXkh4{I7!fW)rNyD{kKh;JgX`wGKcchaLcgm91?(x9Lr=o8YW? z2NEbju03pMS}ToQ91caU4fseN8S#}zp)I)AmgedEtxC7K9J^RryLEExq!j=|O5`p%TWRB0>~tMF4F6`$1R zl>>>CU9V6)+*PZsidRa*2|@U(fP&IO8wrlBSui9yg(Ud3n*d4YxZTg2%eBZryF&Kr zI70F=*@vpt`GLU-%xl)6Nyh4{geXBx0xMoXdI}!fM3%BJ6|fEjuN4PF`lt-wo%qw^ z;V#*6P+wDy_#yn&TyPDp_wOc&sMptLBn&^bQECQzzLJ=8R1b*jwZ|H3juZ;3>Rc2i zk8pJ*7Np?Tc=qj|ho@L|-k&@*mh@la&_#o9fn2dh2MA@K`U29?Oo;G)XJl%yAEqIV6 z^u+g7u;S!tDrL$dB6i-pD^*CEg%(MY_CAtgD~U9B?V3cADqpGN>w}2I`9N5IzU+-o zTpM@eD3nXYo)rx>Oor4HaA)44N=MdR6R&6B-I?5#uHP#Ffbd*OY#143a+WW6WrQb5 zo|l#B9$D+!%{a9lf_gLficW{zkxX2==t9!#s% zx5M6ejJ(hClg^NXAzgxcQ-Q8%;-m?J^|Z!ja%k2E0~ka52V?w4AuY$`=X8+=m;-af zGJWLBeD%uOJ$NU?nZDXP7~{wmb3rRfgi`i;2SI5+^H7(Z*#?KGW8^u9-LHJip<|RD z!^`#A9$blZGX)K{;e1=!1?~lXwQ{_$Bk79R!35j~FnVqr;qmmcyCatG@gXz3^y=mx z|9DCD>)l)@@Isd5G9eQ%$s3XuYh_fb#ENTcE2BtbeBvK~_5=|QOr1K1NTEghwmZqYco)n(^xVyLkQ7N+(DvtfjOl zzZY4#7h0*cm8^0vkZ^5(1l&HG9*L)1@&oMp%p)O{-Yd+M0`OSFy+!9&@I-h6`0HlD z$qovLN`AGHbD9~>6?mm0%t{v(2|GY41Ntbq2B1#Ncl$^177oGJ;Y0tnF`FQDr28q+ z`mLPS2|IdN$J%&#RINi%d3&w8k6#a`ZzuY@(LBMnWL3Lc$csU_51S7A$e@)KKC0ju z=-p2qG*+YIjBVAcqOrA`+7vi)8|AUSQD0$p`L-~_e9R6Ti?XX1oEL^)I6bMuX8hCA zi-7h86!qHJ7}|}o-Ki28;|=kz4G2-`QL5m4g`fd>vf|Uy0!|x>&|;yVaM) zoGMC!$4-EpxJ$1l{<94)td)Sn$^-lIXRj+TrW&eIhNPMobzuf@NjD5&k08`){G7D`YAFT|*Hgb_l1 z1q)-h1E`k#Hf*K^kaWIkijNPXP_In;t(-T*G3c&IsKOzcjBL004kv_0nJgB(M8XGS zDlB(fH+a*Sei#X6`=$zDWJ(**gt0`_o*H=y zP4P1+%x%k(O~zFfvG&Cml9f^_H?huIO|M)1Nk$u7lCwU&=MmeZ{e5hchM^`_!yLOoljA)zU@r6GxM1ScRClu*NzY1o214Q}`3uj+_iei+ zZo~*Zbp(E>86g|`3@>s|2B%kIKlFWwG|*9m^Fv*>uk7g}od}lgjPS^IrqvJ4*uYc| zlp1G@*SPr2sXP>#E)>~G0X50yR=fA7W;w|i-|I+$OD;ub-4LDZ;p68U4_-V)82skO zv-Rie_?mO06_~c*)7#r9%Uk-cU%Pf45C|6M*LOyf>$`;F~wQNaIDR6tjb505qk*!k&PVow>b zuss;T;|{o+U=q6YvpYRHh41MdkBDhoh2?DcumW}dn=DASt8PvpZzj7~$%11exsp;B zw|{1<&9ZA%+r^nDfLv7JTcU zfX6+ofhBgfl2(`IZ0w6eO?KH-Iv2Jl&#@PlAe23Y5$X1(_Ee{(CCFj9$hl^~itl~3s>H5ihCVXT#c~f1US8Kc6TcIP3wD2_^eXUYWfAZhz)k@L@ zuSSrO;jh7+t=oX^=0Y@p&aoI5W50_|UQXn^D^x4+CFCETz|AsEJ#?~ z?xyirEzV^>dr5NR2QmR}FN-W&$9A}#xRpS(|DU~gX^!j4(#7WWD^fDlnUn~SVpVl_ zp(#ob2ubLs2o?ZI)j_hL1dsso639en0;E`!CU#)NS4u|bYhv(|Q z;9uhJTaW!Z=VYD)z^YPTqN_z9b3fKzd+oK?d%r?i35GISX0cnC#T04lGzjC1AZ~ZQ z-p$=;-6qUyF%Hq)cghbxw0}CE8FVq&5@(44dl2+-*ULRwc9CtFb`lp!8np#?7?Ls1 z_8}}l2{0TZR2Nkxq?&{%AQ+ugJd*n98YQLiCZU;R%-hTjmUV};A+D|gudU)x#I1ot z7PCr)1j1@?VttR*%hLZLK#`msGshYpU zL8n^czSmAUODvdZee8%4M47aiE!U0_gF3-8l7j(GSWLNK+=w3eGV0?eA0?qVbITRi zORaG4gAzpwUX?R!TTGqD?Ol$BKj`&Z;SYu(m34oVce!@KeuNygizM>j*5Dq9+<+d+ zVIX$BMG$g!G=?%fo5tf6BkkU3Yixc-B9;d)1DAy2&<;+IR#(#ybW%`45$PD9e7W@! zNmTB3I2YilLB#{OFVkzM>cNac>llo0(%IUXY9#7@e|mD~Px${A_37@j_ zRDmF@_(8d2REzthQ+wyh#kTcN-OjxSojZqvmv?xA-p|P~*grHB0dEQ5MuwLK0P!Ed z#D92A>!U-{lM}%uxH=hB-5X+|RP>KMZ#{Gel1>t~ACxS;|HaS-%;5K9pFiQLtt3r#2w`B29 z6WpzM@4?@EOuc;U0p=j&3u;v0Sm9JvhXu7k+0d4<-)3-oS5~+Ab$B3@!S>C?Z9~|` zv%KWkyp*BMt0z(w(!ji#T&$`jC(T}1>^2@94H@5oj41!G^_*=xh_CpWp;`WzH$`wW zmnmM@G7*zM^j+)7c%3gVDP2pn?68jth5zCq%NlnMP5@Cd=2tCHjo85UwQArD>gim- zR5}fEtA1>SiW5P;eNg$^$=;zxq?89!UB1C4Hd1J@Fsjt)T=BE(M)brAGZ2f zxG%!RscuKZBtMv1Aml1$DO{88D%^Szh&sL3gXx{o_?Cf& zkWSh~KsOHvuK)f#fDFhTpD+iZvzUKId90DHWZ|`B!MQwlVaZJS`x*ual>I(MOl0p? z%^G1HLNYGHw~}tqLe@PLH=Y)UFD&H~un@ zLV{RDF8|A)Ml|=j2&-}T@J(E^YA|cOWviAZxl7_*CVM;8;4;@d_)e9*hAOKBRDGvqww@Rj;HI?VsE|P( ztW>+OT84-dxS$)PRKwbqxd^Yw{QO^k{?~v1FF*fl=jZ?W@BjJdfBpIY`uTtV`Tzd; z|NQy?`T2kS`TzL$|EY8T^6Y##nZ9_Pzbq5_ukE8u=_$0`qs|&5C&rhD2+q9UU+E7o z^pA#)U&CAQaF9J^d^RUed(5#HTDM8(L8eG2d8 zX_Ar3gCR9UL-m)e8)P2UWBiaM`lgPLaL|PZXP;Rkua8eJ&qgqg9$uVGAsr)leo^=j zWC+Q*nmN_u;Fi%ISDa40J6lHzxmU1Eko6hyU2xWV%qv4QS)d$2a4u$u`p#1=OCw*F zePtu-yXo3x+$y%Jby*PC?@RO)@yihsrjdxy;t`vwYKDpn%MWzj6tXi6@DdP}+RegT zVI}A{`x0a5->fyKi%PGRD}{B!TbX=T_$#x7^RmpIFX>?bQ7c*BP6yOU%Kdn2*v>X7DN8I% z)%&_C#e7+h@Xr40g=&Xaa2`-^c8`eX{D@rcpW+d$620_6af3?q{@HNJP13NPI;>WF zE2R;iXUKM-R#1wzrl!ld=hALh5P`?qr|;7-!qNzGF8C4#gjlpVD`6V9G6*(_gpS!2;>0sJ;rka}PPG;9Kf?W;o#K%Yk6U z`X!2;TiMulCdtFw#Mn+6+Ek!XwoyS)EAkBsa=M-K?2F*E3A|*_^xkNIOj#g2;becw z4+3_0y`wPY;D?T0n9vsRN7x_j*|h04RL)7?%HAt*wv!3ePSyhO8wDFsWeY=Q2bPWm z?4(~p2SzOVrObfym^2k5&RZiW*Xkixf}Ct+a7j*VTxWCda7o)A)@mmXZ_@ z{*}t^YWL{4OkOU_KX-{bykTcDd}3ITt6iRD?|HA_nlOKbb>dsh6uZDd2_;g%nB)_F@q|d!3%H4%xxx4l(=npf%!6svRi}&sh(7F?u{S%u(A)#Jp5tj zqviak{M)~+`TQg2$v<{BcRqhi3ecY)JG;XRs3+ymj~$dN;1j&@=SLr-9KZa#9UQ;= z-S6&wy!_k0U;g;+^51oS>^vOeecu7@ld}PyVDle*4$nN)Cnls12a{o^6X5u<^Sj^u z9fnxGdkqrQKvj?9uu^VzS<~VpUKyA5fjK96R{F{3iIq z20UR48;}%N8-GhTR!O4>E-a_6#cK81IKX4Pqsw!rp{fGwOc_jX_$TCnLmXDJfeFg) z*(L^UoH;%B{<|~YhA3}6;W?4lT>qBDE-!P&V_BFgOOnq*+XLa)8@;t7hY0L;Xjshegy`a(W?mxH&f=qXOjC$q& z&_Oz}HYh>y`H+ST8y;$+o)7vcyjULS`n3m&*0I$H9WMV{E0tk#w8SM;=~1tI%l}3` zmm6U!L+W1m2?9ilz-CK~6EdC+zzb*~W5Zm9jAzp1x~gJM`jtz_1g!R8ml(%`Ljqn( zYjz7YA5N8+z!w^i;tdD|F6Y=QXezPFMOA!bM&YFc+y=Tq)?g-PaoQ8*2OAo@mm(*b zp(%M-b4383al(16qP#xh4MQR60pbE-kef&;s&dql zIhpmZW7wq3B;x>FuZh~}!XpfFLCqSeB+S?~-Xb=4dB_s1v?Mj|jmGw$L)invD+zBd zk(k-cR(&HBv`%D39kv0bGSwTMke9wJ)^0-i|zIAD+OCD*{UOt>gGju4Hv zF2q;D$q5Wcr~_k2!r9T*K|oP4IC+;@fp9#=@r&@TNY=?U0^IOE166ijjYnNP4Kbd) zU>VQz!35d-QW*V=;c(0Quc1FFtD4?sZK2VCg}ug|BP0P)!!gPZl*0W>@yjkWACPZ!7v{i&4@qi81U;xt->B{8G4(Lat z!dF*IY~`PShnGOW-X0DP#;^g&`?kt&o#%o6^iD!zr)07T*5fI~5%B9FT;g#J>)4|0 zaE0hV=_moeC9*h+Hoxrz%59OUaMWa#_&3h$L%%8U%vEwLZBLGnH~kow#x_3H&e$&NnQ$mh4sO1U$I(#Erayu^9F-GU zOh2ucpNoHRwiMKLzzW>^8Wp!<4@pu=36ZPupfSX@N9Jd z&I1Np3iQbZ;WLB-V^i@sa8lV()H~+y<(_$8IU^jna!A(YwyNUFd&;m_7I!U3IX(H* z%*nkjcoKyYBvk?o&XNm1&ft7V|F?=nenU{rB4Dd)S`=FgQ3gVYA|A+;z2l)|WB+L^ z`{fO?A5OPt5S-gB1j>j7=okC#thixsGwu^gGMqW zIWh}gp3uNkfvXh{oXrJt)rAz(sJf7pmqz=KjOE2MAA3Qu$hTGcaJ`YPmDN?75zYnJ zv>@QEvfg67c45k5sM-ZoeA>~HO?%dYybv6pcMKm=FpL$qBM0Y?u`-UDF_;?8JB8c( zy4?2?Z^Yo%mqpNvUfqU-DJg_9*Y0k>GlB4sQ!ONn=9+ECbM@`1C__d>;Orc7f27K!-VIk&3|RXu9exEleYv zb=Jkr0q{jOVTvngD1pGQBDd#X{K-Fwex7*UHj%2o(@6c-8}QBwJu zzI|LLuezSy6~+;sq*`4RESA$O6FcvavUq&==* z4I+4G5L=TAex{tX68v(K>+URc4a@oP4pR=fKanl2oT9#l54zw zg$@Z{ii^~w&+qsX=_>!LhRSS*@a7y(OB20i{t!9wfmYHmV!7+DPD~|Bp$t(WDUu7A z5dHz%6DcDSLfAKcUCWcdt$Q4at-%jKJm6f6{wi@Ah)cTHQdr$SSH{gn+AiYn^;}eC z6q#tYIU#Ox&9-7iO?&wzGdA?5GtUa5y;14zHJQj<9kF3|Arja(4QgP`T`p^vovduK z@&f8M(MZ>Vd6b*rmPQ)joxjwwhfhN&LXLB}#vr05CCh7&ZP3m{_$f+|rRWB!ikn7? z23`mAg2lPG-!2@!(&3GE1CI!ZLUAy0rSZv&dK+$jvClto<(`DIRC|mTWYplIgC7n~ zFH!L4crw0}TJIuAc+MmFpZz3j6r7<-@DW~|vCX?}3wJi)PDEu2GrWiiS#qM8r*aOV z1iuHe9Ca0t!Vi&SIrmgfXA?m1gRJYY-*Hrx+{&Xzx^$%A_~l_awG=TcOb3p^W9Ep~ zSoDajjCvZw;n-5B2K=c)G&7wY>{;*d;5W%h=AZn@0Fny?@8_6twlwn*k&J!^opJDTUR(;#oFn~-dsj?M;nKw^-Ax5- z-U2wdUg1NYe;-2Yx9AX2^hhD`-y<*ZPyFBdZ>pcxkm!<~sno2E%XJ<2ipQGzpB(jK zON;S>Do2r1dPAntj$EZU>ufp(I0TZB?40QA<=k??$bNs}v9q{5??nXZ;tYVqa4q79 z&Z*q4!t6{NX(M7Ntp%Q-2q{^djc2O~ZgORAaaCnlfFUb3sEu_qgg31dm}*$1%F$6K zGLG)K$7YLHMA>(t$s!mEbP}hE)FLBBv4E#OT66+wR2(64T0t--@CxM>;V#ld_M^gs zt{n8B>$fvyIEeG4q!(IRt56YBzDTGMSMVt-Js%;y0^V6h>N7|N_AU!G)^Z0Ol$-85 zp*BdoAvU={YR#boN@O=uZ-+H2Oj2mcI0aps5t)0=%OvPDy}pEDUt)ogJ;A#K`(7h1oC;4oPhMdK>%Fe>S1 z@OLdxKwRr3dEU;OMiNy=eEhp;Xar&IdL^Nv$@KNv(RlQFS(*GXD~W3Ji09ZNXZ3yx zL;OljqPYN`vsX#LuS&H%h^2hu9F8gbwahKD>t9sSfuDYL|I_o6bCz>uVb)zp7l>j+ z#uxs@tte_UBO0wv6+Sz7(LW9qgnD=!uWj`pjt}`nH18u8bfn1%wR}!4BpinpbvQY& z9S|n967KB|lJ!^%ozEypzek(v8;^H3IFvxCuPH#tM1>=i^V`3qi$tP%C{c9u*&IxC zC=lQI)vvgJ@G&Fo$5!+V>2Y{V08!oeZG`d!gJ&wGgCpErQKrxEe%cAvzG&g2tc(%a zShbXqRL|k!N5^_Li-0^YS}I>Ax2^P(<6qxxe9jois6J{daIG#>!4P`$aXgZlAOt-m$y_pLa`eKA%{rM(?2b_LYR=D1K0qRG!Xx1Er&3nLK*-ZZyE3kdkTs<9pEuMS+-8A-xBfb>g#1mFE|ieMnAR`Sir=c&El0SB1oPS90Pn^h$cslv*MuPP5@|9l z?{;tHx5(ERGj2nzhz!=~{CedsrIqyO8%Q*7K7;%0g>uuMLp6WL$ ziG(Wm`lpEiFtov|@o4Rzx4zlkd${q%+Bc7O!6Qw(&c6M8Yy08G_M?rR9W<~IxvatZ z*4Izg*4Z6KBRP->;}k(b*uL_TQofL#v2JB)lI(T{uRJ~;Odc8nfio$pidm)bcfknc z!fWVK-ou|+yFIOhDi>9EWp8i&(b~=qUr~ewfk=f&IBWYv4)xfZd=FPT+_gj!Zj>9J z395WT>=8E>SKY?mH#-~K*r_LY19EM5<6)xeS1&y!_eA~dQ4@>DE~Lj-S@jNmjN1RS z{~F0F@(^!@RY%|Pk~LGs#V85~j6eQQh)a+=t^7`eh-s&(9$E)4#Eb-a8Ccj2iVuu{ z8s(%_+-e9Kd?YJDNS^##%5Yvl-oGxg-lT?nwz_yC>Pkh6WFer60cA%lGu^1$dI`kz zP}fzXuFh)*t^K5~Hz&m6v$mVjI79mxUHfl2qcyLNzldOIgp*S(tL90WJlpdGpya%` zVorf3ld(!x1R_$)NGOzK89ya4nba2d-@ADk4*;U%ik(@#9&4oYIr&qL{q>)@u=V7^p0%R<;%VA!kR53;3JoLCTh-tT5`S7V`G zs?M+w-dYZM6`UPdA(hso<{g+YdmR$X{3lE4s0*QH#xPewhu(6^jnuL_=j72iqE{ZQ zwJ^k93nj%^V7bL7i=n3ITr=ENPz3J3AbxP`+zfKUK)RIh=MA7Gj&&`ZKv9&MC#`7* z^R8>38$(exUcglL>B0yr!E6}zD!3CV1Fsse*m;6u!Bd^C}p5wHNL0?brbw`azvM;z3yPG>WNz8VtNf- zEA-8>aI_pf+a4V85jPm!@IVYI+FZQ$OfMl%JY%fXnc6m%&P5|wJHQKX(;+g%dt#_l zHJfG#Yw#@t`-|ahEvZ(OE7rCUG~h^8GuDik5Q}pT1?Dl_x=mh~t}M`sFTH!bXy)TZ zqQ8CE`5F}k5fUt!O>nO74;Y8l&&oD}Eys6U+Zxa_<93J?4EF6^uV_`{<<=9Uo?-X( z%{(Zn={fI)BOxEahAJaO9~mY=Ai(Ns+E?6^rE~F}-|5PJr#23uwt*M)Ay3s43WF?mCF%{&S6$KHlv6*A%0}lNzLeT*K%@x4Q|1`HuQOM$;d0rq zs-3ghk7ct|M`eSLDh&#Si;aqRRqMJ0)r0L3XICtP@?a@`vn5{st1LN{jO#~pf$@_d zGH!2v`PHroYo$dBt)=wZ0hE1&F%Blb2#Xz^Veh5nQF_3lwLL!*J@JL5i`LTdbiBY( zDfy4-m7iGF?Yg$UG>!oODGUpW!xHI`Lb4G0%?{ckE(7AglW0$Ek_xJ;YZ64n&>K&l z>ve&E=BReDr)pK#wK6SWaV%~(TXG#h+}XO%ud>B)ocX9)Xjf}jUS8p;y?psWge4+> z<~}>)oDaGRByPd?esLNTPVAq>)Yg{P(fa+Zg2LUcetMO?^-<=dXQ7>~S?}z9bvPor zXYQ)sbASCNVTaV&ZTk0BHq86aSb4Tn$X!b6kQ?#VYog$@>q*-=j5Zy1=3f0W?bW4O zn@6tv>?-@$0vp->&E2s=pqsaAMe~_EH~Gbw(M-ead04w`Gb7LBjRQ;D23S5YaA&qdm2Xxv#_vq_`vI(Z(0Mw{smk z{`vXV?pH`W5c_bmZrT(e*z0-(nCpiZaMrAJHhwsV%^LAENYG&ck6wFN=Dc}^dBn@4 z8ZCdl3f;}$Qlq*Sar@9&3C0|1Gq{}*yt6}A?U0)zIN7k9ZHsDlEE&Cu4YDD zn;gHC(Gcc`pzkSc!z>+*aBa+htgGqWLvW-R z9LXG(w6l6;!UU3hENwo2%_o9cs2QgT=F9Jw_7FDw?Z)=gE(U+ueg3@~uNli6Le1Dv z$Cad(F#9f(;0^#WOg$)TF_{bx4-turazm^bJv_ieb*OiT$Y?I49E8#9{0#RXwA{-B zJd4<3Atku<@5sV7k2(lOmf2Wx8^2E&l6$*zD32}R!h%A92~mcNvmOmmG8>O&4Tw&j zeSRnmijD^?i+?kl&%c{ojz;39IOocwfWL3TcML!FWda+%ON`bpR(PAJnqE#A>kUW% zDE6I92$@(PO5-W#oLutpJGe#^s^gdBP%E9yi!MGrJsSh`{^_g!Yx+(un9h!wNRMdF zalYS?ydj~j?=?D_xOs(#`PdR~PP|0+tKg`E;Aq`jUyWxyv~{|0!q29ILFeS+;(Yba zoma13tsIXoSAg(4)A7;8D>yywoDTO7?wsL0um0(slZ&&{y%BOI?|?pqoR@cAqonZ< zEBvNzI5-qXQUgc^9gkQV4Dq+qJ9qE??r(qh+h70gcX#%Y#|gro-uYqwa1XY#^N;Vz zaR1#!|9J1?dwX~9VPLnAhjS5JLxQT(Tz)a;+k?srgN+<^8O&tdJhA>lka99^u-FN8 z{U}cn@TBU`5>K7|z7`(aJOVjQKnU1cxE4|lfc&aR6e@+ODTBM9HX~V!xG3b!^9>a0IjPxQ@u;QR<2p z3|BmO$vSgyGtL>GUSYiMV&D?>1!Kofc6>AwXe)~SjiV9N#wBn&EFv3wnG9D zB$O1wc~kJ#jHe)8fRo#fuoZu_0BZdt%gghoDR3lD?nETb8DAd&0D+>|kO7CN2uxbR z0S8K#^k_Uf)}6V+qPQl<9cp5;2pjx)o%h0r^ANfNBlpGp>5H70at(8~C7jNtQbJEi zo{Slo5**86ZeX-z0uVTq08n!PGREbE=N6YANFrx)li^F&{thQp_PA!v((6rtQ)@e* z?iH>fKD{9$-zPXhy=q$s zHo8AhD65_D-Zlbk&M!2Irk2>iI3c!-H80#AD-lVr)04kOW(=hAKrRDM#!{zl4}UqTtdQtwsbx$^cJBu{^05 zIOH3iXfLG!hb8kMHT&D6v&ngBSbgQ5L=`>FB{IT`o8ohRe;N5(PP3s_fM7+kx`YH} zlDHC%pU4aR(_($%ot8p9<6v>*d|)}qx>YTXTqMbqyL)#`{1_)j-tPk9$*Z|VsLzS2 z`yw%|7Do&FgQxL$zQR%9^7vCzslN7orwTmtNFZv-bNHuhUE?Kg3~&wu zy%>*C@DT5GL7G?l34TLaSv<(mMj9w(my(VSKoeHWSobJQladlHSy0nZY&)thAXS$}ww89x*_iLKW9li#k!qdF zk)%YXd^E)Llm2VG1p29xs!OMQ7e=-%VMe-oWXZ#FVMD{pVgq2s=TPza#wGOym?*M_ zfukkT`#f}Lb!P~>ww{8mC+nA%%MSuDZL*X3k<^gTEEc!tw@fgJnt(B7llm!Mu7mZ zq@%fFpAS+Yvo;$_bj%a^;so&+CgPrRw!_0rG>~cx1$)>MRVY)Z!r%!n4Cv7L8Yw3c zcUlpS2qr=SY0r5?^OvTW6ssoQs8rFOSQPK3;+2fJJ(;vn4N@MH(uhjnjhr+CFlX5? z05fb%V_tQeVZR@XxSk&rE4wSmp;})qG?aa#kX=j4Ja3`~h#5!O1n#=`Oq-dbe_Ruh zYEFPDM&=F5Rs%)@sG`LLQ0pP3fg_WoM1`$d300b~y;69f=PS6ui7U znPJ&kAgtbZ3nkTkK^JTg#7h?lq#k<_R7HJJ4X}$S_%FYf6e9Gb`h%IcGrM=$ocjjP zGZe7Y&%sXm%Yec)87O5@ zbj9{II1wwq)?q3^ZoQERdzl5kj zW<{Jh^=GknoGc?UBfToJ&id!Q;2#S{9>$yWWQ3AqaOV-vbi9Yc6bC20?wddMmY@Fd zljk3Oa;vxU(XF3YnAcf_G^vm|x4~ApBrTqP{Cq{`T7EE?9`w%#yCnIZeR;36#TO)y zurIL)u`hk0l%64umGGyt6GO$E0(wOX3alyZElne0f8xSL-;^)16Kl&2wvkT25}R?* zce&+tx#bdd0#@2K9Iq)xbm2m?dS};$^}#ACV8vrD+KJkJUALepBf(;5jpO|x1E1!F z^ZCFk2lToW@8IBn(CHqH#~>Jl6YTdV;S>HYYMBhaXkb^2mhx$5hf9g^OG1|HW?MWu zie#StFcJhylrX6J=qO`-e}UMi2-@vRJXI1B1okSvG6D2W;1b3M;vi(h@vlTSz=!Qa zjuMo&mqekEEGCObI7J?ZVM^ZKsudrF_p(JQmE&(wha*0G*B6q>Wx|BL8k>}Vu7ruV zE0dRKQ>2x*4-v+v0T9#OTY6D@H7>m*wY-QcC-!RYycl!;(xvig?SOXqRK@Wq2PMN> z>%VT{JDjvA2J6+^eivqM0{5vkg1JGBNY>rsfBh%gc;XB%T5aJHq7{7<{yS>}f6=0= zY$J6lkx^5})|?HOj?S;@4xh5&j9*Eg29Bl8r)p%8hATY;EWW2!6Zl4<H4)S7QGgy ziMyTLz>)3}`mO=JK7cI@{vXAaS S)DvQdW{rYcW#*euF9ID!XK?Nyen;7~8(+$B zVh~}vMQ_(HTEBvl^8WnZQJySuS4QJ;d3@L;ac_LPh&yQUWna}Pq#T&Sx4KBK6cKd*H_b9N=0?p$Z%K_QB9o94AI0hZQx%Avd_jor}j%JAxzu zcGNi zgCvP|f(V4r#=Zqj#V`bB)S4SAq{t%66N}OO;qO-^SV--Q@E9ObCQBN0`kc~%h$K6j z8u7m@O*9<>ms@6~G}nc9TVvR#7&xoukJCR3TafIG!hsauq+9xJcdEv$`60W(@e45Lwk zfW&BQV?nE*hLu+(h$oXVOD}_6n47V~%<6ERkwx*xWZQ5aBUuNpV3??+>Gmj%8zp1B z(YY~wvO=y`wd06`xUEYP&=0O?G5(=(IG`zpOngt9tGg2~|KhBwi^ZNkjkAf$6#5`g z>2^#VlyqX5`<7(mr^E@RGl#A`9A+JSPho(*zbCm&NELPHYlfgVvjMi)5AW^_r!llD z;_D|IiGXDuVhg=1F~hvYyCu9)P%1CRC?GvXxbmidLuoR57`K7y9%`@*5)H7AX2avmn=;*`#Nx+Vw_`x*Aw< zJnI3Of6#S+nqzKa%gr2eon_%8o^@-!uogJrx~dyE-iDs);m*HkJlfgP-on97$G^g{ zPP^ZXO-1ptAm;5zYv0y}w1p0Iw$l1jRKuKcoU@Kihj~MS+Ze1a5n_^kNAXGheA5%u z_=7me)B==_Vyr|TrF%LE*Y6*}hHwIL-(_~aY=TA4?SC??eHWS-8`3uRX?;=N%-<+u zHE@zV{_p9tSIf^oT8fc>db=?W4-}s-&I1e`MenR%e+|~JyzGCpeQhU|>*}>gk8NAr z0F>B$T<$O{4=5jr#M>Lc|7LT0;~_-j?A7tDC%ciE$l2n3ctlrVA7MVYKK z&_gj`vn9gFU-*;t;TNb8f#}uM)qp41BlQ!+{_zXGvm5#XP81NH9zjPSnSZLn|oxkgZKklQ{ zM-e#?_3d2GDnp47UqFPj{Y4S6 zrqwNGVZn!%I3dGA_^cfkP?Sl_d^(E}ep%UhWzfoN{TvA0X5EZ#?Vk|YkYC=)J%^)% zF^ZzWy^@VUH&#tul)?^Eb0~4C*2Ou~6i`ry1OcegLpBOVObHH2=rp zBl3Mf1fe-!%HRjqJ(I`M#Z>QXZ*|r0KRGf@rJM=69p=V-OSXxT4Gq8xTXfKB4FCK- zzW_uJ7xOX2jfz6W4w2uN7~zerDQkN5iW|~Pi^fay5)u@O(S{U+N*H1|_{P9EYhd7> z6X&!z_mG1nXJAz*+zzsmIAxivxsi1Jl@5;l(C&x^btH$o9kB6^qSVs_uSstTaNcD; z%%T09%OtxYxexDhfoA0brGEJ})*lwLyS#yl*tg5mLlS=QBqP}l{&n}eOI_x}0m~7w z766m*==Y{?c8ps{7zt=0%c%JdZ=2%&{m0JzSN+q&;dtfMU>{pHJRW^^eAXYHuE4$a z0DbQKN(}k}h;pP1xT*^~Tn^>*q=6_d>*XLLhLz4FK5$EE-OKw}^>D~n@09MVD%}rF zcN$Ng?SgH@Kj%f7#Fo$gaCRF1n%7UC>V5Y4<=tFnINCaMAJ>?U$V66;TicKNtpc41QBh(ZV#qVO8N3up1ml$3Q&PuUfL~MQ$whP!ucCl=q zPOb?z?5rfm@Ay+2GQ=<9ni{(*3OPs&jEI}q*_oJ64>>K5 z_x}^0glM3KtSy!j*EQpK*pTyRq;84e1hdaU-#z@XW!w@&U&egU?rx<;aFL*VQ^tD| z+|FZDNz)`&xMshqHkmcal5sW3$blNh78oot$B9qQjgcnR}&bZ5kDSZ+i2k?KkGb)y)m+dnOBA-?{0W{_leRFYnE zlYKaob^Fs4_u-R^dsj`2)#7lCdjAwR@#x~H*OfccTnAddosI>KS2;ydr9(c?gW};+ zvGdkU+7Pvp*h8x4uq2p9Fx_AS+^OxsAnhMfg>q{|Fo(`G&P3Q#vt?2xKjA4?12C9k z13;Yss4{mJo5R~Ysr4keJOpPcm}_cOETJ(jS;Z?(dY+X%Yw#H4SC0SDM|FHS9@^SV zGXkX-nlR=@Xsop_7T$ONHKk{)Cw#8cS6Q)}$3YDF!G@Yn>pZLb;a8NLlJ{&H*o7Kq ze#DuutQX2m`FK8Q&*w5|it!RG7j5yHFq;smd7BUqSF&*nWzZ zo?_3P2z8|Q#BPaOyNHZqwsiSf;xMw^isM_b%{($AMbnW|AveAAjaic7N_u(gl$Uum zV2LW|Hv@1n_ePZ_g!td+5x|`t(fD?@$u2?X5gx45C@O#HeiGGPS_^1(XBa{=PVwx4 zj2AQ-oc%;K#?nG%=@)n2h@GeR;5pk*{xOVqgqg~-kHjQ4LJY8uZvqu4h4TTB-oHm ztUK6IYNEEvYlB@HVaTfqbx;$ga`!!7F9|kQgFe6Mm`~^?5@(T_Trm3?o>~ z;#ie75S|sz7B&Xgv~qTrFSA06iAOOdV8LWjWFPR8N~pg8`qafZFViqk;yhjbzHF zPKvu%e@O*(d2B2eKt}ZgM3J~iHmhH`F^!sFs<7&SB48ahs;U(rXDO;l;~jg4p;}ft z5E$R9MWj-%`y->h8v2s>{B)M9Bz;xT>y3e6|5YDxn~PU7B^uyq|EfiRQ}bsLM2lU( zVQNIUH%RfUbNOMa{*~ybb|e*>wM2%aZ^(`;PE_WG9f<6d6W{FamFzd!vj}E#LL$V3 zWxmDBr5#r@w#2XHYDEL5$znr;0&88Vj+7k6?$4B!nIFzNsm@S#6WWStRi$y*dUt5?k*tU%l9gOCs65eMOZr!+oJpmOHOOtk-tv6&|Fv9mZq>JVC>Err5yq ze0waH3L}DH`dwtLSt_VUzHB)71%m-EUdm7=n{Tf3J$h+^>-bQjTa2A3Ijn} zUr1i69=kdnGg~)a{N|4r4r)3yRr$S^FqIosm$U65v4xQ%10|tIXZcs51Mgch7X$b$ z(!!44@U5xAVa2u7f*z_o+xySKlQ)yY=TN2r{eDb8t5VQRk+RV)p&R=}`Vy=I(Qr!a z;)~p%xCwX1k8xs9>f4a)(m<8i=f;ppU=YXw)fW^JBoysVm%_icArZbIiBYrKhQ zy!v~23k7{wzfNQVsoj%&YVdgSEzf%*AKCKf=(^i}g2BGiYn^24>Vm$C3_f2$u_|)T zzI_YDXyku199QepM(DVj^bqr<^UWXnZ~$R!w5M*}`Y_w9?CfYaj2&joq?BDL_E%;I*nL zQkLwEXD9ok@hPN(C*bKmG@k1(98&H*v}HvQ>#KA7_Vx`gfB&vn|`-iam0my|G5|0rBjh0?a;A_Cn^j=wI{gIO9sQ4lF5 zOpy^)80+Z=Q>q&uOrO(+;A|i_Cn$RGnb?4f6{R|4zyPVl?CL&k`VKsZKk-DAq#I6? zk^k~?M)@(wsfNarVP{)^4J=ameN;MjyMJ;mu5=$1XcS(ZG)?{Y~a$I&}vPd@D3edH(vNC&Q2gs^R+o~f) zCV-eQ5lZPuC7nPqO?Qe57sxk9urf@1xF(RgJ;jRy*~>H{ctD!5fWwNIVY8deu;!Vh zVKCP}i*c07V<0=??vav&YF&pNlvX`J(wE&)_f~#=o0k|=;mP1^{1Od@qt35a?m8s( z@^F9380?B;>odHXb9_9Q>r6>zBHvtW_{m1-s6iw_|-d=aof3>II z$g?6cRJsh?dF#FW;Ap@%e{43R&m`_E5ZtKqhp!)9k=jx@r$2o-KC6*)`kjYcUsH;K zKEj!lG)scZ==R5F=<;xUpjp?@M`FJS=wFPIkraS$?KDI**KWt?16 z$@876lseDxjHg^D1^e*5Qh7h2@PseUJUU62HisgG-67PoQK9>H2{cztpt;G^l(IBk zOimF>3dvGlycO{jgNdYP71?1lNDLXF?|EXlcW`Z?R6+j|mfA_@i~jx)#Y~={qUh*g z2#xFhk$m#m^!3@%c=Wn41uVc&&Hi#;NtNx0k7dRn#8BQ9>^WwDqrNM1VZk2pf?U;< zn=v~v0f-dpug?`zPyxjI!!7g1A%_-k2-!KW;r$+P#dXbqpH(|p-zL1=S}^a_P>y?A zr2{vVV<#u$={fV8IgRd}+#B+mlnsSzo02b^yzZRzQJZytfL#Pyq-N;hN@w!|8R(iR zD?=Y3oA3x|;genbiL#4cN_x%ws3tA5>_k)xl&9nI3rR}G(&|va)OUyz_^*tj8gep` zZDYlps+$Q+7~WJys?K15*Go+Bz&!Ccx3~-o$fkqfHgW5Jh zwr1w8bST$)%1e9ej>TyjsNI;1V?j5R@kDRh&wFit*xZCM9Z|tLsW-f?wT% zl98h3k!OSHJju7HhIPRiXRdZ`@!skRzcr4as}ychVE|?YE$`orJdF7Fy%dtD8W4?wgzwBmVQzM);%hrGTKjGrivYs~N6!gC zJR%i@rW`ei;SS@`0&Y;+Kb_AiXCSmrPeEwj%5oisxPFv&6;l$*CcNGfAq37v!UBXl z1sD^gIJ+^e+^mOWGokfg04cD~uVvBbi8W02rG~s+VgR0mANT+k^OyK9xqNDU9@0OP zsBR)TpmGh*0B~U+x3AM8C#uxr=PW<}%J&&XFgb=45V-FRo_>`LU;%H2iTo(Nfkfu< zlW$*eyJl`ta_*BZb5DIbZ`rujnYRJ1aN@U2YU0vru;b@Fg|OXe7jZ$n)mrP#Mrb_n zKdK{0`3X;bI^~}eDLC;dQm$~`wR`<(Z%aOME^VL$XNHJybJU;bIsg_v%_$OUC}Wet z1!OysE^v1HsO%{Usa7igwA?bg>IkrXRWH&P_0FpYR!EYkRcDTK4lkP293`#T60YeZ z5kPbZI6u6~O001{6G+g=W^CF^Yn%gB@2n|*4c3&VLLbdFK*z!haYCfy=i ze`MITfabL~@NHHHRKE>1z@!=|nJe^WX!`nXsN(iX=kM*rgi06W9_mmD zAGx=$_&8QS3@z;rE*iR>^Liyj<%X~uQ-2rPPH%{|#q=*(7KX zf@i?pJIGTCZJ@fI4$n}IL8>YJXqI=igQV>Ozg6iTEW{wiKU(S1{!VTzqH(peg{Mg{ z5*d~5(TBQY{n3TT(&g*2fr4e1!47T9nQGsl`|?i$lu1x{%EC-TVko0xqowW?JQ8Nb zcr#D<02{UK@*;-A5pM7y>flJM=lJX#j=B9)SA6POeqD`I-zhqgWE;IEsr{9ZAeywS zdYV7V%7fAHDyzyZpLG0fRBd_>yxn#w4UD2+U~qPR@%rlNs?35<=$-^j6&!Xo8F*H{ zw$1GLs>YP~H-^c^B?whW9R}}Fx;eN|q`=B4NdxSP+O9-V2q?g;!O1JJ3t{jG2s^}R zf~-69zN9$!^!#*q(d)kHJ^S(2@~14#eG0eeSp zoIL^^uuDP!VRa?$*iKH9y&)y1#1*FCM38a_MhHICOk&`$5p{_pi7?5IO8rWn&JrR& zP$d(H`x2uQn#=rt{M#F=^SdS2?^~?$8!(DI4*xx_*5ajvk)Z+qt$dktos?B4Btg{M zU?I4IRUZ7Mmzlv+ZD?fk4EBO4*(zrqlSQCgE(Pp^Y;jr!C^DXdIQ z=Y=r--bJyqHouH_K0y^L zK^c5k(i_qdZ{w7jQ~{4=;1!$lX^t;m*-<7oRjL%C;&q*y8)jDeX2KhCS8i1$p=yy4!U6tz-9f#lNGN3l`J{4Vq9hxyRv(mS*Dpyf) z9A&Ny2LeyHy{Zp?H{+FB!|cov|ZMPe2gSg7;juq z3tijVqpg%c%^YPih)Z<}dlFDCEZRsCa%&?kGQ%77C*1Ukb1NqGYBg-_qXFf~$UWAn?kq3w_a~pck6-cc z`=Xv+%QBx#03SR;9}xxw6O6t}pV{iSH@@8X!`{yB_U7X+aWi&%PyhIA`uw9$Z}mQ1 zeK!5E_v!ujp5f=#`|;Oj-5-}c^FmGYI>_(8*+M9NI@YJF?_<38Il%J|IUs&k!UwlL z#Hi0?#%|f zHSe2@d0Qmw)Q)P`Bdkojd}lG#?vYm;hkruChoGDW-oW^Skn3;p7?qVswXtPA2{IE& zS52r@K~P}9>=`TLQo)DhAE$XcR(6_5uzIc_fA|WlN9btcf?y;o>?IxCM--ZiTs^Pm z$>peTRzV;iRIWhuU{Rxkdo)0T66}RYgBpSPFWX3xL7-?4GZz2u&!uXWyeHvQ<%8dDhU zNG^dR9h@kE;ZvQfqNzl+CL0WV`IGm-WtG=|0)F3JQRT6QnXhy|x^;!A1qF&f$#YbI zpMLy&#eTc@e1+t6elR`l;|HV@v=ML@N<>?FujeYqOwd(n$guba|0;55H(s>^_oXEBA z;2#o>Q;8oPJuIM=yH%=)Y?tu(IsGUebEPWmO5Bg+GH~Tc316GMdlsthStuBiknD+T zj$+D_>Eszcc(%slfXFKUGX1WJBJ@oh9|1idf&b$j6!zWGJfCM(jbTf2H=pT066C}T zqn5qa_1&pTXICDc>})UpS~T+0Ap#*JB7*N!oywYBP4FzGfBLuoCs4J zdKp02etkFG>HDlL{#v&8>;5^Q(OV*L5#RgO)s3$=w!hqXypC6eACyqlt@fD{xd|$EmcWc{^MWwr9|HoT^9`RcKaC!INlw9)yE8!tdls?;q^Oe!YH_SCIBkj&RrDpjbL@~H!>YAitPl>{>G$aR}iS2t%3ARjfhkJ5^bSb?yFIgFLJ zbeX2y+c%#LM=)*=FAm2C7OK-wMGv=N4{8rCX(%pdgXy$?i~u!59IhJ{y=cZ5HKV+s zR0TIrb@Xac)YXt$ z-)7c<#LB45J@Ftoxte#me(L21uZaB9 zQ7k@s|AUX0rVpNeaBpe)yz{}Ym!|jc$R|({X5txNJGojU2ZQ3z$ET=?0^Q9ic*$rt zQ!1KFE+TU35SklIq8I0zc9bJwNE*RyDsNx!| z<>$V1HsK8IUk+i^K?1Xy2F{qts+}Z-Y9IOn4Odtn41mO%vyc~q*JfTKAGPk0u|!$~ zgB$b@PH2`f?!%(e=uY{A33}xzF&^Y0qS69qk9=uQOZiHEwgmrZ(bzqG+(|x$>0)p1 zV!R`0M=WPKIuDhD`!p1?dh@}Q;h+TTmQ*yvtZ@nKQyU-&1SWXTkk~|RG^Fab>V9JA zxXWU#2o!HfHReR-c2XMz>gWVaJ(Z3DsHLmVw@6v={K z2xD5KYH`a*E8r?QM<@yqT2&%x^Cr-m9zq=Q!1@({NbJU}tHARV*z`V%_Ntn^XNW5k zlnXgv%0%E?hhw?OQ(lkfYEOrwLCLRj&`?gyxvHU;5Xyb${maWsFBn@I`tvQ9jjcy< z@qVGaa|1USb%5&Gwx2J=pNGrH%s=68xi!@e6SAAq0cYYSV`z~$0Ga;9TGpCv2>5_px(5rs%) zKR`Jv;F&*Iqx|Cn5-w2rp#DEm4U=S~Ag7w<&_h5^$dK|PaAFaJWDYh8%b(&Stk8W{ zK0QO5f0PitIsoA5I~Y%-I$u&()<1L+l0}GEH%Msp@?yMve2GgO47!|5VX2-71;BJf z932DNeB=DUJ=``ET!K7>epHHaecJijc!FLS;RmNjHTFA3yg3p)k*b(5V7HU3q2700 z=g@U+2uDK)R(k6}a1!Q{3AVw?fGm7*UH&o2332Q0^RR@hJ6NY{i!zo>$?>a%_`J@fpr>?F-S>o3 z;l3JAN~C2QNFiBTDY~k_YWPrN3&d zX32}OUx-1R;mYGRY1pY2J*bM(C}p-IGR2Ng+LRd~b;$F;NYro|0lKZ7-`u_H9P-bw zV3^h_a>2q2#vZ+`1zT`2w2H8|;dPmGmmv;re*Sf5xC0|CB-5VY5%(8DQVvdhgK6UA z>oy2)gfx2kT1C_eT$m>)KnJa8vW!xS<3sEN6vM&AD^})P+gab-WRBj(=j#tQ*B8JR zgj3i@gPw(g)7c&uhj2+A+KF!@D$pcF{P-YlX`ukShd`mTL6^nF!(YAb6dzQ}sDl9j zTfOeq&h9@y*+76vHagX?t)2K;dRrPXD8({H3*zJusf)dk5&RD{+$iu2ToKHB8e)}# zKeGW*SZ;hdDa)pnAxymYbCIOPnx0}63!+k8J&3?kF7*>jss`u~ZX+PN4aUz@TQH?W z=TK##^C_|qQdPpn&~KaA)#7Ux2I?|TxpZNT^(#+LWVUjAA@%O(tlSo!%#g3_oqj$; zKQ~iYroF~{51fj2+#&77b#-5}ZmLgHLsqR9Z!c1*IuhZVX6ODsC=X|n+MnNOQ_-&3 ziTzxieb}E2FQn*uL!{=4) z^-F(3xo9b>now8O=ObgU)>mmAb&^u%sUjQcHTAIW;+zC+dyRZ(+(bFEK1KKKzr8f)i?HALehQCz|W>$-0CPR!!fK8IkLd&ZtxW$AwP8@N< zQr)z*m6o^Pf3vx!T#lO z6XI@YMIJ)oUMv(Hvjk3RVM-J5Z#?;C*Pb;g_wi;4Rlo^eI09pCGyo$jz6tQ&3GOol z_bW;p;fA=f*a3Ofl!njya4SU5n~E6a3lO^qMPo%}zR`dO1SEV1xz$H}yGX-`gE#C$ zT(U6KpRTf)yCr0w_aVX@vQR$1F);?T{UNMgHUw(lEx$yuIlfe&FeKlCUhE76WdG)JuB4BoqoJ z1~e*n4xb;n&!eheP*M7;_p?z%t^bLxo%CHJ_b~)Nn_Se?DO0VeDk=Sf+-b&Gl|-s5 zNkmw1VS0_qJHQOqfn=Yq`k2w|>r$zRDTRGHzr8cfj4aQ|u6G}wT}jZc%1 zj-`v&=P=6EDs7z~b5(A8?Yr`$Cy&-PAL|j<%M+vV#??_nS)VB{UfuXiEldINgFz>x zgA-rJ)Kl#M#n1KC%m7yW!cShc3%-dbp!&7YW3nWN3sK)u;2@B7tBdn1V95d{yfY4l z2=Wka^KD@4m7s6ssu3JB_7T|-aV$LD_f?+$wLi+BoGA==63fo5DZk`!2h^WbnhR># z>T0%K(2Z(-oUCNurJ`jJzVOnb2>wAgx1&;yvX7O#h>P^EXMzN3tcT|+g9#ni50@+t zddl#8@1lPk>T}FkY5S!nd&-p?UCanBj+pYO-;(ou#~c@il6tBLD{;VgrV3`o6R%1M zmzN}bp!|B$TR0T$!Eu;Er;$>t0N-sdN!THrZ-B+WfXfK>YwN9%enIaXGxB0NDBXZ}prU(7@1% z-`kb(N$1!3LlYi^>*>efXMg*f`XRC_1kYLA!?P1Sy5&@s1lzgyTfmaE$ha!z$=<`T zFL~P*Z(-Os!mRKefRiy3iQ^jQ-XE3-mkDfTfdRmO<~1p4En|uU%w~KWj={nR2~*x- zXWFeC#u12_gfFCal8iAFy+K^sQ+lffZrTA?+8&sP$HAZYX0KB46$6^QkE8 zHj}|$VWW@cZ1gXGtB?=s7k%!`sN0$l5)s8Y&|Cj7@-~qtvR~^$#Z}-oC=iGDVYNn$wwOyhwAQcTiCKwUkQ20HmNMZP~EhKnSg^PBj7;dJ6GV9 zU4h}PmuIukF7$_M8X9Dj|l4mFJ?~r$rlLr2uPM+>34|~zm+8@29z=dgVcV3S#<@5gOR5PpkaBZFr+>JROggbbn z>g3MF_>P{X6%@B%USA*o5f_i7;$-oV?cIs$j!hRHvitNPng}2Kgu1Hgxu5SO^r+}4 zGN!*F%a7>dM{9;Uge_%p)GoC0f@}VXE+@GKT<^M{Gr4wJc-8hFHru#kRU@Oy^=RaG?jf`+x-M^* z;c9_nq|U{9Hz)0WECAu;hBv!}7NrVASAXwzm>+;^CbZh4nJzRf?R6~*)^sVP?Z`}e z)Xb$n8Vp2f(21$@Flj%>b@uE)Vx2O}ly!wURDZMM%0t7&5@G6p31}?g&k$^*BJp5- zd^(Q#FsYSGHyRUoLR+@EVNcVo!|y?$!JSR$s*#dGP;+!#pvuAtl|mZ2peOF681z)u zCgH-jxRJ-y>x$TSou(;jE5m!!Qf34aE@V>^OuY#R=Z?xfAY1y`ktw#G@TQlLt4>1G zcn466Aaq#!WNu%pWPo}nC6ypZY+iBDco0fqpx2FsK-G3>_nRl!Bm}`E!()`BR zC5<9qN<1Y~Abog*{dt-ff3+|hp zjVEi{Yxq^D5_RE`yA|6K$qKYClYiS!HzKJkeMx@bZ9aau_1z8)e>|p2hm~pZ+Ls;#=xZ$`#U|hKWfd*6 z2R=E}=XE{dFtL`-R}jFh#JlC#68Sy+L4^(`W%F-gzb1NyL&RRFcP2=J9h&mh=@1es zEO?Xc_S|L2Z22Cs+aT#1gGgA`U2+#f@%A}#>Y;T0Vhq;WUVL{mjoG6mf%J! zQke-t1~}-$*PtYpG@&t+FERH~zQuVKIO#(jGk%p8ns6~|aIuC`C}fo} zIC4OwoC=9}k?(*NUzu1Q@WzOe@Sw@>pjOyqU|V!JVuldefSCvZG+#&fV6u;Yl<{b` zn@J1OOY-NnXhxv~!KI)#q2DPZedx<+n6c;yQ0105tq_GXF*BTg9dR*-T9WyiKn{wL zacihjzUfUMDubN~Bu?NH;r?>~)JdCQ6KbY0t_5s)WP^4v5bd9iqqr6I8Td;&QUlEy zTp&07Em4r$kV{yfT!wDAKUaFDVz=>3smc&rKyBvr)@I zEn?lT&-8-64k9;L!^AH7p4KX{zZ#I5PRx^>{{81a%0ydnfxqk}_bS6GWC2H2j&&j=yY@QdWV90J`*P|D0BFn4PBQtomvj zKs4YdOu25N8w`KRlQP{7&E2fT5kO1MD+iznBn77gf^7&0Uvrc*g%dX*<6*H#h!JP@ zMs=(@%O3pU$nRxO@ci-VA8$YZ2+yM3mS1jtxO684&6Ys)@SPtBZ*{h(jM3^>IkAA*`P@ZK2Se zHW5oeGbEgeKMs+;tb|!|3~3``%762J3*7Nz&VGR6$rn8z6=k*z)LEIl3C9c2X2}Z$ zqEtzAOxD1Z-Vy71+T|ef1v8i)5P+|QnlG>zh?|-YRJSG!F+$R?0hne0^tVX8AXP zUCuFZ^@tfT1w%r5-I%amovEBWo_Fhl+u$(+v`+DCXN}=2`OcY|@t=e;w!JoFb%!+Z zonzmWl9NItn2Y#x%tTcq>PB8K#x68&d(d$Tv?bSgRUJ{vb7jP~LPQD-S@K@JaQC=x zC}=B(t5*JY{;W;n9ue4r-Py60!r)qp7o%As-g3{Yh%Xag3i1_k=OSKwH+b1;bZE$8_OZP?p5XEl)fUr zE|kiGw})l0;R`B#NGHR?Ls+8g-ADT67tr?i`_Q+QEtlg~?e|3s$aU%*C_c9XRD2rQ z-i_R&i(Q}#IghBe(Kba7RtHiZUIt=BK`0i+M31z{BZRay;jNtFts=QcT=!L8Y1x8m>UBwtWKJ zS<>kYaQmm$vLC(^rEuEG*<)vOq=~RRLwG?edI1@x<1w~}GZ6$4%rIn7l?H85@zflf zP4O)aO*7oFIjFtvnr&qi#t-@h%0tKfV(vBj1UA-kAv!u<88oYTz72dBZR7=k$gnh}ZBeA6**3`UC z8SPgPV2k6eqX}z2KHHu25$P$Bax<3;hF|BvFPEC4Z}~w6jh@7&#mMe2v>4@74Qny8 zm&c6E+TQS;F|Q`me%UVP95ayz?p238HO);+9FmnGw%H8xij#^;WPN$_E7uDiBkO=V z+iHnD8%&M|TCQRb)@uY^SPP4A+0#G6$1K>cJ&P}N>nMFBnhb%J;A95jIZ)7p7@a+P z1?>5r_wXoS#QmfsNu{W^%{q-Q-Fx0In!=jeaf$W`7_rAE*;lZt|rCK@`C`zOpZ)|&-y5qFLQ6hHi!Bb@ zKZk*5a%goi6h)`6RU-Tz_DZ~&u~{Z`^TXN}%UjYQU^bHD2Ri|4xOChB!D zf5Vn&_#l{AzrzsY3s&UBR$mS>u9NT?qwxS9NZfzFDuw@92qrxnpqP2bBHgiaqw<3h zSD$d?#FA@FESfI@7jse6$;SzE7l$ZmZnq3VjUnOk4nr|13nxM)1$=xuo?f!jDN8|U z6fwQC1HK=`%Vuv6WIBE^D5tSA6h>W&bGA4|jkNwaF@47oOB@;*#Rj}2;$K%Kr8vTs zu-qpGZy3u)Ek5i#!h0OiSK=(EySUVhBg3a(7Vin7o(NbCqngU8(FQ8dA%_(*NG1yE z2#D2zxTa`LPaa$X4nLITwlX`P>etGe1N8H--`@9aCg7}P4`p7WS zznc0ynT!#`HGO9Pe$IEk2Y8^felel-$@zx7Z$&Qk1(KrJ#ckbdot={b?t8wbD);@` z`T6PaKs>7A!9;zkskAugpX<};tnda$;*e%1@!r}yU2?Wz0YO~(YZ09-P8_~jM5*wh zgz@ABo=k&WjsuPSAx40mBO@C|qYw3C1REW)f{wh3fd|$)J(J>>m)UJOd=IW_ADs^O z2ZzH8oFDZhA2JOD@Izoh0UqRlP%$P5_g4NM&eJhfgUR4*{1Oe2bNp*0hIv;A$tM`N zZ4!5QM&s-L1T4MtRew7EfB#G8{+ax_f&kO;sC)&-(!Pn%(h-2yY#s5+I)X32a9Vt- zNqfbIm~`84SbPHxMB3Q|mFeaNAA<0{(@Q97fWKa;teE5IU=uyID1u!MCjJW-ZwiN z+j|c;o*=VtZFl2gjTb!GZCunIN*dmC^X*ABRTmT^vGIye@TO!#p~;&1iIyyE$+!Dz z>uWssw$i<`V&Cm`SJEMtA3%e7jJi>oD_RX4O0}4i#ilc+=Z$Ne3ztwusKW>&a)GH{ z)R|n4Dt653nx!N%jRzY)3@lhRaN$o>2G zyBk|ybboc9ubMpoui-10dczo;U|_}vwN8j-Qy*CEGf>-bx_bYP^alg^up?2h!2cO- zLg0SN)o_O(Xw^fSnRP)P%SR7C)bQpJDheEq`97qxNU@{qU3Rj5m)?IidcPc$&1;I3Ccv{rLUsuUtee`Q-$OOM zc-9=&NXQ(OKcT&xiP%F|V23rqD*H48H}6ca_tN>kp9v)%6Y47X*2dZfJt{j`fBA}_nopWb~wv$cpo^gBzs2f5CjY%`LXYj zO*%#$^(0e9=AwP8r1Mi9Eh9pS>AVpfte98MI&%O@I+Doc;y?-rHi!~oa#ict16)X~LJuX|s_p$9aR7z7>Ysb|BH$l@yX zk1PpmdeOhQ#EZH}wYq;t`)RcLMSACO@i8F3si5z65|gKz%86WGE+;7MAw&}Ex}1zW z<%@7?L;J+qnOITP*OPlun!X7{Z3E-lAp`!^cY{+P0Dfkz2&|XT8$(~VeHc>3q@V1n zF;%N~pBRLp=s{DrZ&j)3-9k@qdkZ(fnijeQ`6GA;>JE#JhrytAoX6%OtWOCjKfnDe zXg;AOv$vC$SP4Ld(pHnzt;B}JqF?QfaVriL0NIFg{y#p9W9n_C$H+KnqJnIrQYYhc zVE&YqwAf2+*kTi()Tdb@P3e*qTSd@>O<(K%0XM4cOa^#Ph&55+pNCOgTKa8K5<+oO zfVwYyyxy%?_`Bvj2ZDeSfeHY2WDP%9VQE7``z?7evLf>uO=h5E*sdQf(Sha+nGkX| zZnBHJ@@zJU$AC$MQ!3={IB{iBVzPkY3q1N%*>H6ssc{Q@4NbJn02Aw{gJXG>9X<_e z3F$aS5B5*s0gR2XVy|m~sE-k1!Z)mR5-H+K8L1$t;sNetO%hcMz)F2_iBcqP0Vfw2 zevif}_t)hh_wJH!O!cJw(=P2Gd;6D1M}tZCIcoEQowMW9F3v{xd3xK3Jfz>9kHL() z&y|s<&5L`*c7*HG-BVs0C>f{Wg2C&24gAyaX)f~tR=(LS&_neAxvHa=n^RsOP63li z|F!wAYseqMaHe!5q7?x0ipG?{z4qBO0(Swc)0+UQT%3Ln1!*=RTGJ>T=LA}iTwPUq zCH(|Lv^*B@EGU9V&umz2BX*aBk6Mydue-cV4(z9$kmG1r+MO*yRBA-S4M%VWjiKVo z2U}t>K?MYAA@^|Ild>e(T?)@g2E^U`;Thf)KkhG|gtl<`7MN}bM?Mz^zI>TE?SXwe# z?f#DP=R(WqR{#ezWR}AUqMcauMB`$~nrGxw4i7JEWq6mCgQ>E@Q0phcCVGTk6^6hV z5~?U$(W(2MSZIR@&5NzVK7WQ-QCuz0-1;7VftjUXJkj}E+BwtOYifd!S`9=PAEi(; zmm3KUGcc3c+-i2cz`4Q^JB8uAa0ioI-le70rKRm$ygmh?H+V|S4*4vIX)~ViuJ^V0 z2w#Db4<;m$WB8G$pZ6QRGu}hxH=A(N!;7MW#%okV9uY~;oia34!C?euixPtw)gUWC#~Ej8i8-8O9*pvB1F(h9dhX$h8UG z%|zk>F3pQU(i$nReddYXEf-+CokoVNxw2qIB%nucyJ)JQx5uYd(Dah?7#H*UHA!0| zJ`t7H3)I@PA6lKZ1ik)Rt`2U4-W2@BdkNQrw`Q;#fD^Ya3<&zF@9Y;7b%VuSQt6Rh z>EX<~{EUz4&H+qP`CJI_=>UDj1vbQk{AnGxa z^|(F&SX#ISTRlZk09nOU9Ii##;f07Nj@+7fk}i&`cL6d%!1OQ_1hA;QB**$gf3Qkr z4JxZwl`?RD*|S)+fKce0v&S7BJR7Y{_gKI>vRI_f{jjX5w z>dDVF#}%(8&Bi^j}71%v!wQepOBYq2iM`W zO=QFeTUnBA(a7Ux^<56;lg!NN&@pFn2w0ta0VIg#HZOD&LV^#%9QM(CG-%`pT?0_w zCu)^!%JofoilAo(hTh8JJwevfNfuZ!xHc}!SP^IT_6H;vTPj(@l?@M#ObDHuU21?d z?4<;sRBs@oU#;1-7#TMcvK~0!OtiC-U|~t=p8p65#fUkl_|V!A(1Mh8o)iOi_6>jv zb=Q$H;%`j}?oHw0m1V%X!=F(0N2~&BgP>bGX2n>~*^CB_N-IWnXLc?S)vD&nb2Dzu zelpiB6&>VkNS4d=Vt@$a9^RNdLQ>I-5h6TQYHupM;Pc4TV9I8osKT~(__B{k-&*K8 ze}IJy6VJjN8+0CryeI_}Zp*%oYsjwW(hj7-z;|gd7%f3nI1zh2gk!uGPKR&yEII;x zhwqe@W~F7ei8gU@H$~37Z8rG$D)GwmdImMKv?R~#Xa;2cr)A^BFxRq&c^H0g#XlCB zZI^Lf^XAbs2>I`(t99pQ+2`W&9vteQEjwxB)>HYypRG$VLjQB#WZsTya;5HE z>&`w37(}jKoAn8|xT)A7M8Z8nqBM8Dq_H0iV{s$Dr60ULI~tE(>tImG5K!Qjefi9+ z__)ClT=DhVANC$?KHk`SwDI`M-LJ^n?%g%s7BUpX(W~~9@Y%l<#KjvceCcdc930Sx%m-nv?%!oJSeOJNr_`22A6%#$JB{KS%KPYm5=5+a=2X{*4PvOo(&SNLm5 z2WN{YNN3J$}WYs)Lh0 z!nr`%v06=BY20$G5&?sW?|fGy2v5J`Y>0DMMp14)zx%Y4Nqvs7F9=v;*JWI*^Y>merNx5jA~m9KEhe@d%PexQ>IM*b035RKloS> zIP^6x`0A*u$guUps7|J?5Q0jfPoWTRLk}Uqh-1Pyi2Goml{^u`f=<Gn2h=8S3X-A(yWl!iK936g6;>v@?5QZMZZ>@(q^t7>ClzhopjjWZcl5L60 zLxd)iSd8Lj=hU(1Izi)EXm6)4%&oF#Z*=EKDLUT*D;C7|!TxhKoNs6A=2($C$RU0T%B z1ME%#+@;Ec&idzR3WR-M#w@v6!^8PuUHD*1PU!8UfbvuPG#DXyVvNE=KAA(3LU;4* zCG#k>MproGe*XAYL4}hyGV)MfDKd_TA6#@6z3FUU;xqlA7r|l$)&j#Z^n0%aiA|Xh z%2z0oxXaAg;UYqbBBsH0X5+<0m-r3~zBV%B1}%I;7)BfJM7{p?zuo&s$Df#;?;rNV zuMhZW2``Yh%!k#*)r?JDc`nEx(t7Kka4x%meE$^p7vV;**-u2`m4S0Q2T zP?LEW!{xhEHF+#chh>SDOyliUK$bA4bs+vLNgz{pio`bh!$qQ$U)WFJ&?`?$|EO{< z^Q)YfaO)*mmW-|AB4xtddG)Qf;oHN@GV0;uB>YK6k;T!_j5StaK~kV3Ph~Q}jo-S9 zd+ExpbMufHHryzddQ05*m!iqLX-Jy88`J7<$?oIcVi@WcNr7+b%Of^zf)5MHY?xsH* zmeL@tADs@*!>dIJ<;xD+7-($Wp86R{UMMnJW`{Y*%#7a|8Y>=3mxQi!P~7NSIP?mv zne^t3VIk&nm4nsCEhkv2b_S!M>(bfbO~7CE_0=x{7g6GxVa}F$6xB<310?E5a=&0( zIG9HUqem5SZuhxY{mSRk4Iy1O*+~}=N?OOEGbzYZDnJi#*^BwMkst&UJOVs~-Dl6b zk`h^CHLje;WFom_HjqjE8jD_s2^)1gkmcF^|Nh7S9#R06gwx^i2@+6GP%lMn+|r=) z?DF1kfA?_!fncQY%dk&uJ;|`CL{i(QgyMfND3EOTq8^A}2Ow&=LbB4Ptu&{K-FG*l^oL>sPs>LHk6-|lE<#oeV+;SnKi(2&Gi>Ws@#6pi}+7gfC@%0;Q$I#gybvVqlY5Ht6Tfa)3N(E!x~ za7o?nEK{Tk%aHvKuYtlh&I(NB?)zGGXs2`$Joq-$Ys9chu}!$U;X7t|yz%8J>sLVD z)tJ}5Tu)>qW&#$rE!-RbxpT*yjG>hToQUlj?~QaGePMq4-Y#aclHe%&2(#np1w>e^fD~-P=6O7~NQ_gMAOado8xGCufa14%U6UBe#kjT;mxP@=JC~{T<~- z37+Be4!3H_(QPA?Ac%mP#bZ<83q(mZ0EXkls%^;4T+KF((26MOg(GZcZ1BgG4J=TQ zaHq_KUs-Mgr!5xEpbZ3j4p=f}++jeaKXG;OY8+Pre*i);EYUQq1)Z_^2!}>xaXRH? z;lHu{Mt(Uw?HJdooKXab<2Zy(ihPFS%kJG`kO8|JC3Y0;VHTs{T0fNNy$vMq$dxug zZCVon-X|L`K8fL1RKu?0`1Pa@-jsBSqEKind(hxLa4|&v2Np8XGKc`zjJluwRxgEJ zL;~S;w+jt_LL!D_4I@3 zbBUjj))9PJLa{n^lw<3n3?)nDYROzS1sPtfHo3AjLL(h5S&y+0jszNKB$E_cMZgHT z9LLpnc7)5BhcaNf!E@)2lDjXi@Zb?owzDOI2!@j!HnbreA;@USI@mK=iwvaD2fwb+ zzwX~{l-|;p+J4>*hw(sDsq_&dexZRZ;vC;|WjvIr8FZtOf9 zEWU*!VV-UXo?@BCOZW6h6%}{R0cP4DXE|>-$hsngS)vZA88(6Rep| znN%eUwOjtoGK1chZ&<~G-Pf(6Fr)~~GU|SZ19|#Q#;2;Rbr_FMd&f{-KgIuqfKyWo zassDeRhnq^hT^MSt5wRDLGNL%%M{FC`AGB6lUbEO%Ca%ZVwJmGJHz1wQ=|B7B=$$~ zA&ekY7-gMRlM{&_3PB`@r;7tTRM3(clR%hRsH`!ce&;pjB|R1!s}iXtc_vLYP6tW% zrKS<;xs@P<5j596@b!0Uc4F~UobrsCJ|~O*@Bz9+m~7QyhG?`rvb1e+0LGOCAClwK!Db;*&ELK z#3{s3(tK*K4|uJGD0Bmik%K^F`AG0cqDk^(G*^QS{j`&8DQZcU3WsY;97qI!h)(mk zJACCJN{J+zD9*_L zHKCxDpwn#&%D%4N$ia3dkrUrJJL3#FKLwlUys-WEk@WA50j+k=Yxh=Tb%sPSHk6G1 z_;ys9${*fHLaA1;A-pbPmEqiah6&`3i1AFxV-VXsJ9hz>!8?<=a6I1EWpxusT2lJQ zeR??Dli);yA@oF-`!Zp7;KWpPiKdGKe-91e*n*^lcv)}|QCR~rYD}0-!Bq1`zoWHE z_&s4iCn9Uqc31==aG4Hr~S*>e%c9t*Y%O&$HA7QaeSXWA@eC{lDDK zy{&wa`4QIC5_D?7h z>cZQnUCdC?(d`LxGp|B9qPZpuT=6I@C<>)d%hK`{y%l(AftNaQ$rK6^RnA1Y#E~WM zE?5N<90wSQM?H)>wdDj?2ufzdGAyajDCy$SkIELFGY1rAAwBI_7wGVz6%QP^i<7WN z3QSPFt)~R6*P>?zI$}9eYO720Br6>Wfq1`Y%@)!P@WerCI^lr&4NL$r8TXP$;bU+5 zkr8D{|T0*ty@*9!cr_v=hR-LSG~!QgnwPFSCxjOs^6>` z8Hj|gh?D?+WfRioEzf`t=Hve$^RbNv{yUkDbJkcWwV8da@(5yJxmLw5{f>G~oDrzg~ISZzb2Lt45|*kKtE% z_8u=Xm+uWg3$;qXp~_aU><|z7P~U9b@%wDi&C}?b?UKAx)>BeK3dZRn)7kLS@Db86 z@K$KPWtV>Pdi`X~vcd>Ve)qrs@9}g<);RFbj(f-+!$-@YKN%?rIAaWO%kBwiPIU`Ke5p{Mk}>;s(%T59j+UU%Un%d6ONlwX1%mN2x*W2>X6SM zV_vyBxzac=R5<}Gs-uLdF|EcEtDBIEVTe_ZHpV+5Kx01e2UlI{s^gX{B6Hi=R{J7M ziQuc0JU#*sT_Bh91U4zolah%Sk-I@izY_z8Q5KaO&hZIP2R^UWR!rZUNjjvb1F1K7 z*+|(InnA>1o_7%qW+-uPj3nG;FbHf-)y0f!>rB)doLl@N9kjnKfHFt-Q%n)S z51hI0fVLP*V?Taa)6Am1fNMuDP=a)VR~aUQg9-)tPw|*NV+;s749+h| z_(B^;)O7S5D^IJ-9vu0#xBBpc*TI+Dw4o+tmN@p{q@Pzqrl1J>}4_`*Qr7g)OHp=GY;fVDt zLly}tkfGpX?=+o8p4Gis(FWnB%bU9?5FPF?vZvBKbXqRO9DLjo!?Uq}MWoe|zXV;9 z9m=n3Nbg3I0|m(_EgtaT9^omolK|a z6Hvka#qner>2%A({*-_4_iqM=Uw?7ui_h*TTN(LtJbf@$%v*CPeO=wtoV;YOkdQa7 zzjDf9BC#awHJe00FBz%Wyh1UVQOwLh&=>U#C{%~gAqo=8_-{Tv5#9uy{1bTFQEg39 zxA3UAUi%WNhW86s>Iheq=eY40-+zCwyG4$qvd4=yu+wnI5#Bnc(@Nfym1~)Wb=`E( zs$)G;fu%tzi|9O>VfG4{W|$Q(=13T@+c}z^<00U?8Wrqzf*g_$$pqK`n6R@SWYWY$Z zS$v6$Kny0=hp+8-l)G_v-}8RFch;z%AWZ}W26{Mn-miW>IR6 zqiftXqZ28{B!u%=l|CHN6Uo}q=LMYAnAl=-eA|6C4sugYZ*{8xbD zVG44-Hfuvc%L(QCU%H&dbLp2*GFdoK3sx}1k!Nqtoc+o$7 zJyTEBx4?dRhQiCx_4Kw1a%fQ#p1NurFEJ3kMmfw`!q@P#1j5mT(l`J=GUd_!X;c6o z<5s}%buzICR1&E<*{pMOtWEV0fgi{hDBw-{{qKKYI*@U8StVFaPo0i7d6fdF!&{?R z{WZDzhu=zKBlkhWz&FycQCN_m2E$atA&!a@jsx)okUQ)5BH#wM-|K8R8VN6XIm7xlZvziian3V;-h9sZSF4aX>7%4N zHj0iRSYe2p0^vulMvVi@!C=3<#1KJUt;uM#0g!-}TN*hVP+fV1&&MwZ6PGg05<=FF<4Zugj8xDLA{O{-Nr)s-sb)r% zy`h>JEfeTHu=sWEYcMfxfBuJZ7}8EN-E`JNTt;eQUviXaKc87x#-95aqZ+L`+D#&mRXaDvxsnQ6&``^gZG za_~>2cbuIsJ|Yl-At<^HNppq_BMXsDs>C={kBb5}-{m6hjEx|(WZDq9Rj8Unx3f-O zQkfmSLYKwix1_)^*^{gO1_}hxs8ARX_(x`E9r*O?LUNN`!|AKzF3yS#juwTC>Z6<{ z0(~mO<%4#XAam4-e;c>%Uckl`v`~8DWDxc4pCzKl0#GTV+ek@T)6Y5Af2ZTN2xV@S zifgcz=39a1(_^IEIctqd_oma)=v0ebzp^7Ep^3jsNS{+tT}s>51YHsY} zToj{*4O>R`GnqWHgzhvXg0v~uMeqO}F6E&Rp-@!Wf^gbCWeC2@YU+-`jhSLjYqqCYdd>e zYrEe+TKi!G_H|>^oj+}E?cIO8yVGi4e|#_9BkCZ(nJscz_WHeV(#Q95N?v%?mmtc^ z5+u?7Rtt@k*sj?3hR1zsM$93Did`z+@9E?qC%mJA9{>$%$Xu04mc^+>$st3@C*9G( zw0COvF|y}&rETp$OBZJ--zpzdS&}j2ljec4SI@G+mV#p?T%1P1HEsaS5{#RAUWj=Z z(Tg6K9Kiyb5e)X)TOs9%#gF`Mam92!Q3ezmRHSR} zQeA5mJ>+6|KqKDO#m*^SHh4K~4rb=EMq4U+4ZDpZhLc}H%wYDn5Hp-4U$2@Hh3U#> z`6^_&zuiSB1Bb=cjnnnWTF2wj#reO2Xc9md7fre@ZXHFF{`DRuk`DNfl1Rs66r6N* zL8kuK5=n%Au1KDs#`X>$?UGED zkC8Dnc*OwDF%xIH*6n==GXV3C6=wC-Hz`o$rAvt9_qK|;(rjBY@#u*qi%>O4f~hlo z%bq&rVnUYEXsn(G5RxE!r|?=I zA_~VSkmuC}$Ygh#{K7G1Fk4ddaE+neBq^{u=nWZN#I+|x6M?2f1EAU1(Keo;1^&_n z;g`7177GX7FhmzMVj>s!3>SF{T%Zr0(Mc*AH5I>kJ=q4@m^tCO4>dlWL)q)PW?f7O z*ig4Om?Zlk-yZQM>(^OK&^}7Nj@cTbW!8eb8t`1X+eAvkwI-y{S>DAYsqOPSH~;v1 zn1J*`BKOVH-jIcS(K}t~4_EvFgJp$}$#DO6>(*y~yz^OD2dCqYZNS-JJZ5-aflG)$ z^RO)AiUcu63bbTcMe;z()*)(2Ps`8KDt0USjE_f-5NRv;J zB$Kexc?6)-3;L1>+Af|=oG>{~3?h?n%KI=SaYJGvNqi*iIdU!tC0+zz#FnJX4|T_C z*9$11%CFkQi`TH1@FhSx9l@nyY2bPI(nd5vQNHdmNVwGDEu*}o^vi^5DW6)xwaxq6 z8mdij9r*uk0=5ECq`P`Z6^u+FuhJ^uL3=c)@)E}6;RnC@{s@<%S@`cc$h-q4)zjWNJY06s)ek|!`514z>q`i3{)0wk0mJ~_M>yhZ z3D#y&!t_YO{2-RKbOD8B1kTmpa~NCBt9is(YE>o(EWllv+2%lnFxpmW((AW%zc8Uv~$dp#Y2`x&w-jE zCxPn-{=NuPxfnJhBdK37wnNgE>wTQA!Pqwl{Sb*=BinMtt8a z@|@~QJo#r6WbJf^`{;ax_i5(kl^NJBqMAq3~{MMaDT>1oD%iq`Xodh^z|%!b2qB;nO%l#R*ocXPq@rqg1#$lnbqp zAn@@+fKzQf>EnjDm0>+NMONGNS!cPrKdN4jE;N&kM`P%}c6i2T9jB6CcmuhuC)3F{ z;LDhW(?%X#Qm#?te>E?+Aubx1oyhm2@#su~Qba*;uB*f@xpf}23RnGX`3@gI0W^K&F(BEAV z@DP81e8LNL~e;T*j zNU`(Z6MZJq0dNcqH{d-X#(cYSN^IH4j?(Dla$(NooR8mb?Uo4#6;B$;B%#)oUSkk&bd=k!4+bvZ+xHCBLip3zOK;EL!FJNf^ z6t;BW!eSw-lncngfHW?Ax!bXm%lI)a2n96D&z7+?q}9s1T48XLhZsjFA)D$O(2R7+ zAW)3fRmC5~!ACblBDiqOL*s@XHe2=Mequ+1?pp0)<4fOz!W^=NOkuOGsvtt`m9F|% z1f=MiW}jk9EzOkqQM<`KDoIr2;DC{ zpF+m=;><1W!^e;*p;~J2p#D?_6zEsYRC)SUs9uVbMbjy&?gYuF{2`Qv25Cx+IVVWT0lpvKAu_ zb3VldQxLRuWCcM+Fr}CdUyW$m;q1p7B>g=63O$DgnY&SqYTxyDVQu28bWO z3Gk6}aUgJB&*G&ZbAF`+3*ZjegeJm%;tmX~2TQ2N8o`M4kx9i`EU#jb@fkGxqdmaXyy$G;Lw zHus!j!yCPlqEQDTtqH^$n6*(ODc3s3JxajJ>2+YISxKo%52SjI8lCOm%pu#h?DYqa zA3l8i=e?c3{P1w|(VuppSX_qu1M2~xcP09ah{%d_h<<0|;e#5@7x-+XFfd$w_cZg? zE&xY?)wolUjeM6{FC-e906nJK$|FTlF6ZY%3-e_1PvmR1_a%vt4cH2vbux+O8`W0K zR{Sv(am0`Zr|UUOt}Q~ZdFH7XeYOE6WMcP2 z#B-nk%t{JqR%8bg_rdcRHxVL(MQ)8A_sO~CS({ENVTxPPdBZ)xO|>p$V0QKTGkPTs zs9^8)PR~zzIuHG;0defgA2jq=?}?x5)h+x_y+57R=nv7x+I%{$!*!dzvcdDe0Hx@R zjD;nou5?Pi9nKLF3z-1QLAM`3Y9^?IlXBAY8^$|o1+66wQfQXO2t z7kI`qBB_=%y8wVxDByBwV?&%;#SsgZ;In*AYGNn`fr{nG_OfykMjT}vMxU>iaqU+I zQZV8%3Qi%K!J=l_deV#l-+=tzN2n0L>Op_Ln@39#$^T03c&D5!N{jUb;gSQWKKTBK z^>U5|uMElnY$Q9nS-5&?9(9PSuArHW1VITTs}ztR*a3WiG;3(t;EoTf2HWt>+`z%H zNU1dfnX7Q={zrB=MQjnyNhGf!gs2PdyVq%O^oW4a^XuMH2s_wTiWN#eJr z6?O!Zw$iZ(y8Q-uaD@bPg`ZtHhO4yuos-(giQP;RVGLysDlQI1RdxS!umKo*BGPQ4r2+sw+yUr+eoR?;ku$%)v#ldBtP$dML`A?##`bR#3Au{h%v~NDq5H2Ss6G@X*j5D@hPSa45aj_K- zN27B%I#94w@-;O|->Y7TM=Mel_D3qkh<6wJb?au;LkZBcbI)YOk|@^jloZI}=9e(h ztFO@NO9>~G7{t6PDdBUx7!Ljm$pEClC{+wWj!g0s1RnjM%f^e#>^C^gt@)hr8%$S36WYaboc8%NW&K+xC(pK?&I~{$4{yk7pIi4`%*79gM111JP;fq zb6NR8qY|9Bm=yY7)*L`VgrEZ3g%s_;n;W1{2`>nvoMM}^_K{7*eXNs}`@{t=R8)x@ z%BpcP7ja8AMC6#&j3Pw5`z0j|Gf3`v!8wDWSXe8MBy{{h5va`|^6O9r(Rzj|9Yibk^Zl7m&pO zlxe@P8j2R;;wJ7wR?6H$w08G)Sq>dE*7|Z)EKCO_)Lg7+kGd}*O`K!3{M_$DFrz>W zgu`UO8b{3C;E8*C`LpF)(86@t>P%#T@anVWn>FmoPUdOwAZuS}lD;0%=VLS<6kDtfOe$DvcP0NP07dQ*}{nTn?Tl7PZ2a3ShgboGC^qcP&yo!A^-DJ&P%1 z?vVob@LXT|EVS-U+>^^L`a!6?u*i@TStHhdV*+hQxCRzUhFw}G3*+>O2A z#TiPL98bEErCc^6pWK6|{1^$MWI2iGzNZBa&IYd_kEByu`dAvFF+pmQq|9+o zYZVfF%T;(2PBYCY_-~k+n8oDk9ar*N^xA3Ra~rPXd<8TBy#1z_82; zhg=WCWBVfCl4wJ(V2V z$y2#^8q~I`+h0CjmOr5euVBBb8(w~wAYi-B&aYi_SzVl1(7Yso&X#1?a9+tDdT@ws z?$?zyCO`hIDDv;9xH!A-YE*0PQ4^M}!H#{8%Jriz;1)qk?ACCA) zc<56YPY2Jx7d0IY9n=EF8@v7x1nzV&F$Hn^eNZ<%98`rs$*|3zgP~sIG=(n%xy)xs zH=yr>560OoA+`ahz=!uKJbU~LLX3n&_n?_{d}#uoa!}}YGOCb0yg|qdK&5UD&yTy; zmaE5TGv;X0PW5a!T*NuVKsq?x^R%S}hn$cPWk|ISq0M7c7Op0!^Y7*gVN0iAv9%IN?B+~h_n{H~5c6z93k6%Pd zS>k@tVJkg?mPbm1e-Vfx!r2CC@|qMu(;l%8-Fz}Y^dE%oHer~zT`L!I3H@LoC2zPn zrIHLZf8W*HT>j2_#EuAoTnnpgu5FlpAAkR5l`pMGonEd{it(m0*p+U8-wnNL`sdP- zJdFp3;{%@g;!rC~{-Vu|yB4={P@9ispVKihW8yj5J}D$3UX=U-%cANBa8i9ge5j;K zf=g5f)4fFCAc_e>9!`(CovV|T$(_TqmWfTx=eB$dvOL#jY$<>`O+Zv5@$jXyqH z-n;SB?^XtA+_}LX+)!xac;@@0+nJp7Zh!to_&6L`LLUjMJj8TD$#7{%?fMoyLT;rk z?Gq}>m6tsTEtOu*2DuF5!XaSfpYR&I46^O-Jh4(VHZAn0N27P37gX9R;D!gjOAl)TxT~fcgD>&+fo%pr4DMkNPg!jr3byGqpX*BXW;bNp~41RUt8!E zB4Az-0Em%Np{CEC9Xet-$yq3crH3Ps#M$Kd8Y2W%_Y*mdCU(%D#Yd-3|l+vscSrRMm8jk=fk4&8k`@tdjvmgW!*X$G{-tjm37;(%Ln>>4C z%I$3ybh_!O)KUiow=qF&LZ?8-<8bBXdWCdyxO|T)#PHzKJ%B=k*Q?0K^!_k1cfES} zc>Pa%kG`#V$fKGYGAIM4Fj#XX&pWqn|1q?Z?L1OGRPdC}ZRm~v;1dmzL%%_S_NvcX ze}Kdtq3KA;Qkyo8N3TA$$NO@^V2+REK; z$KI1iz@BYUfrhun6cNN9kIsKEjiPCUN9_2tKztk+gk^@#554hoB-?L>C#orE$V=7- ziS#XRU;q0E95IBx`NMLx14)U8}~P+haH7F%p3FcU95cc5$&DHc@H1%ygoY`4bw+Vn|8F>CFL#c-zb># zO=o5coI>X+$mKne%ztu8VXQ7Kn^OZVaXu%2Z5mi-{qRNU5iwv)NhwX3^gU{uh}kxB z5S5NrQPb_a8+Qkjoe=6q!g-MgnCO%((y80ocy$g(JMaa!TZXvn)&7Ovde*D(HfIsd zZcC~N)=IFPcSY$uLlLG!%Q%(kmOIN=o(-Q3H(tR^T?fhVQJn78$u)lXXQ-sKVS|a! zFRxq=dKHxzN0cPrLr`!6B#R>denvaa#>p0Hw2NJy+0eke@8LyzZ=2B7jeunD9$!om z2)u7k1J?J?khmQE4}vP~w)$*{cw+YRYoZ;&qiNqD)nGibLLu{i>#zjaPCJA{JZ9GxOd%*H%8*hvRkj@%q-n zSgxr-qZ2VS)F(1gYeTWG@6A-Bi)rcKei!+?3n6?6dJKXXp(s2yg=dIbBs9!mWMS_9 zWou*ayNyR1+iMTuF}bCrk$ks#|KSF{xa|VmJ>3~y24^>q0xWD73BKN8hI`kDHV`?S zLCFB6{GY=c!l7z9CxZa=bW8(^ZJQXWdtPz5mua#Cp(oxb77YmH^XKzw%w7f4;NLZXSr@4Uon277h?nI%Z1r1R}b|O zrWy~X1z$cmUKXnE|)AVk3?Zi-8(UukM|C6nyG5b!uc<2d@7eK@tYhsE3Kegkpl04=fZDCL z5Q(p=w=T@P-W$U5e%!fGr@)3#M`m*t{a1e6&Z^i{O%fCJ1X zdYn-yO1jGza{mVEpXfy*I+y{h05dBi&0pZPekBFVZ??Y>wz7i~_CD@}By&KaK0-kt zPXhDtlsZs0p5!pPkWZ3|uZI3r6Ga?=?<;zO7 zh#f+Nn4XN@G3w;N;%E%3eeuWJcWx?P+0lN8gnLMY#3pKuw3?sCTQXUDqNL9)%NNB) zjYW;TH|L3|%p8FC3@sf8H-ZR5q{BI&a8OtEnqgs!7((S={K-Fwe>Flb>veIwch(;t z_q#Rpc`jl}3ZSX}@I|-7&rvN4c{1S>EFD4a+;$;wkz})35&}tF9YKmZfT(tqv?R7? z)h8_}NyuyC6)WHcI05;_f9$5C3Y0FsePY8*00=C}E#Y9_K(c7zs1iNigxQs5*Z8=} zD&htuY+(nD7T;58T{tFVW06ec9{f@+nTv7aXTV#NfUznzUT%2icv&RQvL6u@h;}B9 zdB3k9Y6+~jGMG~|TQzW3Mimh?2~qd}CK7dwzki7EJgd2&qMC@xR8j0815_%WP2jbb zx0p|ncZrHUgJV2%672$HJH$SvgXtfmPHvr?Z_LpsBZ#VTnsHjXA5v#&i{4X?1SX+= zRs!HDdq$CoN~g*Y&wXZ!#Nk>rAwmlXXl?s1daCjEzW#k}S%8R(NCXoAi4Fbao`M_>F2;1(BXQ__ zkkCalq;Uw$4Q#}}`PX1*mpSS^JhQ? zO0zZM!%t4-%eWO3T>UW<8)0#fW8 zxwrn~5k$e7g@Qm=9_(v^+PZp4z^uru7yYEGkPF|Vf5!%C*5Oh;*tQTto|{m5mVhMx zC_w#n^#z{1FyE6;9z<+SuP#rR$RittR-dYc6wj)nA~6G8AsPnU2DxY1POF*%VeK`Y z+0h>DNI79KB(M7N5k0jFcP;%YiS0+N+MlGC2e$9Rwe zb#TXcR^VcKh#IkbUd+GSxfrt88}(j}P;``aBCCZ;va$3N)LxmauJ$Jfz4QK>9f4}_ zmz|ASb%Wyq3OqrNkn%MRZUX9)!Xi@M1_&*WIw-^3GANxDjTb&-ftpPt*qQL9Y7r}l zQgP?ug5xngtoW83m2og}gddE?s>JT`J046=F7_F+Sh4U$_!o5taVc%(^P8Wcu*^PP z$X4bDQw0UVhIGS9z#+6*1EZvlEQ94@TC~ij@IM~lk;z-gR0!J$TwlB?wIN$nJXrKaRIGxy}36S z;vVP#1bbj4)1s$I-59(#g=?hyJzTv~f-40DnNo;J7(OH}r0~@EJO-D`fMT~3>sL@u z6buq;QG~Q*-1$}(UIUkdsBak`8H;`uGdl#v2=hxuvTG9@Z%2k-hb;aU0}J=)xHY^i z;r9Ae@=`$`awStPKl9VflIF22btm_bpM?p{b%W???-c5KxTycLe*JT{LTCob+88z# z8w-arwF1=%!YO4dwW`7ayyTTRadGLq_8Q$lo}+7O3)L;1I>EaKg6iA#WGGyU#5`GX zsIb|J@eA!xLoQD{uU~GAUs9T`Het!=7`PnChTWO&`DJD(0ia)8hioL_a1@JPr(B^@ zq+sC2k(2i21YswQNutP;J=3+;vHoWkDI=jk+))FXOb-V`=Yv+%O9iK9#2W=A{LY%O z^EZGz%pa9*6r0In<4!HH($^9Vhj7klKlFSVK1~G$r#FeumS8DdwCzl^N@5Qs7w{@1 zc7=rnF(Wtwg--Fbt`t5qQVh7|?j@$v5EI@D8$|}ivs=(RU*i9y0PfNJm50$I>Alpr zB=@51PY^O3%hsugZ^AU!yu|&2cLLxZ>DJ+)CX7vGS?)q7VALR zuhTUQ^)}EG1QSoX=k?uXlk_JZ8T{0!-Ww1GrLq#YY(Z1M`{kESU-9cDSXw>e5eXK^ z9udUxJ~Fds*S~-A=udk)oBwO0Vdd=1nc<{|$$-ML7^iK&*p@&0nB;k+ef?1Xo3GHn zam+VtH0Nsp%h%*v%BC}Sk<%qRxyVu)X-Fncc+;2R|6X#}*{zP3`X>ba2=%_43flG> zq5^46XDrUbB~mEvwfJT#ugJ+}hJ*%EI~>NrPYNv}^R2&~#VUHFK#>DwHmTl!iINx0a_fuF{&2^n zO5%RsHgftIQ!W10sqG2%pohrO|?sRdx=!sXBs~ zo!pl{pFn$q4*?_SXNnF;41D~$gW4;S5eaN=Jbqxn1ei>KI6|@zfJl5>W3e4ap5NNM z{p`6mJp3~?>{wa^2de_;MS$8VRe=xD7nZjshJg@7A#!{(K0y|)q1%>Lw_uCQUbyr4 z7^60A^Eyp?@W;&kZAO8tlw*Ey?6o`gNb&7gO)T~hW%HBa;FXBN=&#dv;4ltf!W+CY zQ2;_Qc6>jQSTC8!={?|?IT1@&p|EM`j+;(j|A3?;)of>b?w~m>+VoKGC~JJzxN4@4 z&%gjj+AR3Z6ndm(Oc<)v!Ad`%=_%G9M^2Z^gj+3J7{!unG`fnUWwx%QWj1fpKKtAj z$8PRX&*F}<2vhb=8LT4$XCDfQ!DMY&UEp0#Q+FIJ?iwtQK@q!eRQO_ODs_gYY>}mw zw?uVRjcwpX3x;)84*M@w_=Tiq(YX}HCD@r}n0>=<)tc;3aI!lR_8ZcvyGiuRW92nS*{_}-BLAE*u|qej-tR{0(# zT2SLDpfKhS?%e3`5RaaHt$r&288Cw86CSTi=qYKDgK-q|w<=O456 zX`q7YFXbmpE6)XX+1>nMSZ0u^0Igfg;q*p;o$D#k_M6N_!WN|oLjP&UiV#F zrM}CAVCxk9E=NHy^Mt-4DcCGQkCmtZmjkB|!K=@y&q6T?k!hLHD)5@&HA_?te-m!L zWH6wXT2Xor*1ekIzqp^$^m1zy+8Wd}j0cumy3HkUuLG-%|HM=C}-MD)5{TK ziVq;t!Hs+z2GkHW5Y9`cMiq)FAUZ3j3cJh6G4n!FtoRT1eKHy* z_h1Mw6t1EccsM2DjzLv05O7-WJ&X*3!*c>j{*u&sul`=Fi3ErME8w{KW%JvTgn~5J zlj==M0IrggSM>#g27Q$sC1o3fdmS)5dhqPo04qKh`vH`=n$y?XCYsENVI!;u!*zU`s#u-(!TBn zzb6Fn?7Z6dG^w;9e^)Vpq6cppXJ8X8RfsX;CN+cO<3;MD@tTmLE!;Eo#h?Xrz_Qfn z*u&kvS%7eSM@c&b%}8NiD1Xfr>-lBV&y1AiKqj+aVP#-N%{y^7i0~st@dbJnf-LSy zx)M7$Eti!7)VwC!JGuzmCgy(Iq4-oJ5{N4mi{V$0Td03Tqn;lg&^!uoA^ z*dIN4NC)%5Z``*|9i-o}w@@$euIaI;6sa=f8U=NC+{{;{r|VZr2Ir%9nSUjf(Wz{K$R*iovj`pPPHYpWx=MXTFA2Qk(}Da(PGY-$nX%<0qJR_mPn|lgR8pcs)o#8)cf4_w$7IekC0b+Uc8^3vBkq6m+sHv z*ID8E#YZUb5YOwmMR%ZPC5JTR#rlLu)MCw3k%zs6N0`obLl|9`Nc*Rn{c_wp$AjpQ zr{d(KpxgU2@Hri$6})VNQv_~5Wv~d(Zl~o;=!!MrSbyy0(zV_ei2;NPC91_`>C)n# ztUB;vm{U-*sKtX`bzooMV-Z&R`Ofaz?vtIp?Txkjf5DLgE30?-I_qgI@Xt1$uxA@V zLI1F+)$Ydj52*cR4RQGr_Ys-aTuyp_^ASe6sY1&kQ8$17`hj~~!_x<_nXFJdb`mxC zSlbrc0iP#^LCODQZFSuiQ!dxuQ1A=(3QQ=soETo^H!n@O32jlOplBlpPVt%GjTH=v z&*^a0Gm9%LzGQpsTJh;1R_HIjvAPJwr+vIP!}pMikKy){+5$U>vR>2xmb{FUyD@b_@AQMBa0$}${;ewcuyUJ$$RTewsl=fKtbClsIzy&3W;gr z5wdJ9P?(q}E~(W9GB3y%cW&Ie^;v~ck84B4vIRDHmapz$b4nmF`xk>##0cO*j<({h+h0gq=m#UdA8$g% zOGj!|4ft3BEVpj|UOIq;rEVo_SxR-utj!;M(BA3bP|@YZ&eGW-EA=XPyoiQ(Q>8CV z<>L#~s*4k&<_pmvbi=Fd*>{SM|KkGtLMPPW#o0O5GR`3XOwqD=dfGomMH<=|%s~bT zWJ7%>)9j9M`DjI4z2_s`10u!b;M|dRTjrrhO52#{NDA=h(&AePF7eo}R#$ol;?Bo` zjcBEouSAXbv5+D5=?r>4QsGAXe}%8@N;Z~m(}U9yXqNs(fr&57oU=2A<`hFnVrUJx z^l^d<#b5@+6vjg2`Cz(*e;R-&y5S5&NEOJLy z^I|Yk_DUPx(JjnIx}7!9eUxh}RBLEEYe6AghQ#tbjGXn+ZB>~74n($~TwCg$_Qq#f zL)%$9^vU|&asR(iQAlo|2SlWc2Zi3ca|dZ)q;uP`NRoGShu107UB!Zt=1K(;*`_0C zZiiJD0ZAPH5}`Z%G@anq9o^Y=kKe)0vR)bNx@9{U&r02p3fvxq>X$Xv4ck>fPGvk} zw5*wK+qbCQa~w5GhMRi0u#J18GKJkcmAE~QfU0|CFuanj;B(#8x#L(^3%+0(24`(C zj&A-Fq=V4;c&0BM*^AF{dp_Z?&von9x1Pu&Gu7z;55@vN`X*A=Qum%` z6EN|&{;a0T*fn~hqQhO}ONPKbO3O_zSl9|5gZN(oz|Q$-9PuuhR8z5meK+xPsCsHHPL;t~nJo`3d zcEKniGC0oWRX0?ezGJaN`o2DPznVM1I@D7I1@$2LjBEgTC(gA7O^w6V+5z-Fh`2B$ z60}bS$W1XcWpeN}9)OnoD)Ev+4Di5ht9oWmwFGHU%2P&Fot}H`O{HEW5o;oW-$AMX zJTrLkOo-LyL{qO=@?y}#?+6nz2{o*PXJ+r>l%?)828aeM9fV*h-4ZY1aRdQSb5a5d zQ++qQSb2zqmRHv;l?+GhL{)(sH{hVenQ-F_PlZhJe`xA|!whi8S13(1s(L6Zzye9> zkdmsk8j1|gjJUo{znh=mz7zV9UU+v)icltKW#YLh5#7%J+IVz-Z})q8Hc(Ia!3HXV zBRgYeh3L}LnhY&*j2{>61w!4WI$^K>m)Z8XDz-q1+359zT}c^|glMN9EZ8)Yzo5+JtZ zh7eqaTx;Vp(XU2~`|^a9J}TAiux>rlK~Ni=7WM>XN$*NoeFUww&f^|c-1s?jx*ID; zUj7axwaBg)g0kpKeH4U<_!O{g@SAd*0eN^c_C5l9PF(d^4t%U&@fhPT&1umF%$Wlv z{-8gQcm_Ji#S+*)>Y{|yQ{+=q;>Z=3BfOBw>n*xEI8K>@N?21TDJ2$F-@^+kB(7sau39he%!OF`Dh*9@ z|3%Rg6xQAm41p9Sl;yZ;Gk`JfryZ0?x_JAnvH#dgLyP^2zc->wrh5&RAri3NdzjRN z(2EV!<0uhLCvb;hwI;GN{HYq4RBn@GTg(iR39yJsBg ztUUGs>}*=~3mkb))IcL>=*55!zLGKwQK8hIsa_6e<^yuof(r87f~qEXG!l3~~N+>2V&)}YT4!Z{KOjz6j@7eVKu%o*; zk7tP4U|m2a66AU!^q{qzyNhTXv?Ah{PoASyyW;!D;^Yh({CGET1xx2_47!9|pA`3K5 zam7by(f~`^`5I9U?^hyO@t2ygxs2hiPQrKa zd4}KNwhX^VFIrfFad`5ELN@#iHNSog$7e{?0b#W$4ASCcQ*;L*0a|WI=CK5}gck^} zS8R^w3Ye${so^P4mwJl(Glv~=9Nq|@UaO99K25ybSp!NraO36?4x0g?+wx#hd!VtS zb-Fl5Ft@)WtJV_c$voCZZguYBl!gSF;bugvzBG+o-PUdXwE7lN!`@h~Ql9i6tP%qS zj3E9_NbEV=V61RKWujtTrLrW^U$?@Kv}f zcx@7!8x<~4ZkwyZsAe$vRdr}x0=PF^H27KxNCi`*dH?>#-C_yp(dIj4tf#%}#{Zvj zI!Hl;jC5&}dtymRsJkHXpvAtWA?&*qoa6s34B;1&e?}*hTHYOzyk zC(riF`ukJewgudc!5MC`~w>wWV)ki~0`g`{~?JvSvNqCl~y!X>!Vj zT4+8@x;0iN&8AFXE{}S@&C8kPKLy9^y zM!V#xnl$&fglvY#B$QvEn6$~F*TO-vXAAYQ!YfxNSC(O$00JLL4mzL+&d>HxC#V+9-vy?MfKF?U3*xYUZ}M0+Gke+kYB+OlJv!(&tF` z4e~$4pSBAJV}KL~;1QB9FUB69ZKe-Jch}HfMwN_#4o5q(E8fhiL?)(AN>6QsVb?dH z8}+A%!y#I0ItpDAl3(E;1SN)9*5lLHY-{9LBb{{SmfdW{QHp0AwS_;n+|e3Qke?A* z!BrW_BE@RBm56Iu&t{C9pY^fj3rO2H+5?1^NZ^DkFCi{Fisl5p^*|4xG^!=QBx1bA zHW^SV<@P^0hChTV9_%U;lPf~);N>_APG<&*I4uH2?sm2)O*29ZumZM>K9!D)zKWL` z34Tf=ZPckLLjP*S*-T>UE&A0cOi=ZH2yE_7+Wn)@Zjr6r_R|_1o{UaiD=;d+iOwtwy`nR{7+W?V ztJfMtD2v2OK$u6O4z$NhxLk#8r8Q`SwL$)c=x?*UnpxxV%abAs?eRwB;`C=zBm|<8ZdA+lfgN2wMEZny@1nFAof)tpnn2mpr!4uj16 znsF8ggv}>{k9Wy~VaAB!^R;1p^n1Ty^&~kSl5METpUac%qGtqfnH3pJXea?_frFyf zy5Y3IWdE&Bi)78UEo(Y5u>RRcMy)~p$VleYT>+lo<=hA<*rx5lorIU$6NS6&M5S&2 zOIv>bbxkvaKERQ-?4pG^4nk1NGowpRZFRmZ=m&#?N|Uxl<*lV=7sf}kIsnah!^$(% z_LgdnXYKsYOPn^EY>e>hP8RCRjk}Bb!ttJvTn+{;@(LA9SGnlO1T-O}OB3sE%mc@m ze&v!h$+}HR9u&+;=4a3a%p~8z-(+GZOnMv72F!yp4;04gzks(`AQMM`*InR+lGi9R zf7bdorZA4Jb8V3Y8*B_Fyd_^HKJe-3;rTM2WLkN6e`}?;KUq1Mp1}=n!HUT;|MX=` zrVz`=!gt;uF25W+M_3BwBBVe6S|Jwq)E{h}=5o_69)f7(C~+2waqZARv>CBw+}LbT zsHxCwNoz)p*3ntw=f8nLB{&z;J)0hJG{2P}Bj@%_fw$*(Q*> z@`+NP2Mm0+w5TMvQ0b?{h+OJR+z@cHs@pBxNiKW1FCp=}1xkLm2unFk;ij4y>xt{0 zxj(?uxBdQ5gC=~eP+B)wEqMrj*AqkzTchy*5~mf{;eo%z(+|QN4{&kuu+5uqlxsBG z6n|9eVgPzB5#v}GUYzaoO%ml_?Te!aNo62bd5Vp;c3%7?Nz*|BJQ6Qo^$#xOg1+sz zlMhH*9A>AlVQBSu4*-|B$mq4rH)RYS4lq_5okRI5Cb;*TCvymLZncv6dnR%tf`&Y3 zrXDP&u_2e@25QnoG1x>>WNDB_Lt41t|NUKl`}MdYEMYEF%$Mw*y+pBYJY16OuOiF~ zDLf-sz}0HeM`M^~EydYTD>%JJ>Rdod>72i&km5GIqkMA2yrXz}?;8iHvIE%OyHr_h z-$WF&@sYf!lFh*22s5E4CC%x8c zlANV>NwYSd7J)2uaud^+u^*d+uwkv8W12A^^ie?18Z;UUL#eqjDg@$or(J~g$SK#@ zdH`q2x>;%16nd6lUv?vQESIv>`*ISrNj^sC5trTh4qYsjdua-cQgI>DbB!J=j6E;A z%-tY~+r;Z-=)%x}(>g;(toYl8lkadXLOcq-C>^Q9!!DFPn**z6q;qtn@7iI1@dXJ8 zuJ5p>vcI!%65Vvd$|s(AEQxfZd*c0}tPL-eq8VapE7HOYP(8II8LUOUz#(Y@{yP#V ztoE@jtV+`LC=QV93aQDYJziZdvi{)r;VtW!gWn2i0Z7I!H7rgNgypsx#MsYW_`dvVw zZVHh@=^M1!Afii2i@RLMsHrooe#W9n^FLQ-z1Qxd@>-+xU5NqnGtsygi1lX{O3=Ob z+(+h5!t=l$L^IuF;VT$6kT~*)G%xk?y9u7Rt5{D)H<^Ir$KVe6f44q28Ii=9*{+t1 z%@3QijrmQ?X0}wacnyTweTmht0#*g@Y1o0IErwvW1d`WYjF43tYn^b(tDama>3gX7 zgcrBv@IZQ+olMtpK@SGs)I5h$mx$!U;-G&;iH;0wHkDTp0wJ@2B1#*f7T@r-u!28+ zj;il)j6!dKANxR#EbN7NrDS(tJ#+JbUUUSmhQ;fdoT=O+r{Hf^t3NjHR&sGQ#;6y= zB3os5Y~jaADtz0Owc7nQ!kIt+(%3BtnX?Cf$|I9Cu>zMCR2bLAo`#p&8!8RCIZB1@ zKx~tzYlo88?8Pw2HJWrqzb{gUYT^~bsXvBXG`U%bPdi7JWIP^DJ}@5(@Mqv#s>1XR z`IdqdaAU7h&#ze*p-wmIM7dbP8$@uxi$x=S#9Bz0h2qhz zMHZ5*`(c|A&xZ*98Hi7Uc3oYyVDU}B<-21a0syha#jr1J=V4zPnXrwS1<6w8Y(dbm z?6PklR)|O|GJaU2f8*U$VX~^@P|U5DF-7wM4P|Lvdprb{*EFVFHW*~&hc*u0aZT|u zt57A$xiy(Zv?L#?wjx_te5(j2uJ*7z&Mgn5%3Xy6PsnS=1d__v6HKIcu3MNt1r%|B zlIF1)%donM#8AuM%Kavw(`djAP4-i)tu%vp7koZq(czzmn$*WHmPPmA7Y=!FG^ zBw7j>(>uWri~-hULSb?gRgjx0#0cSSIV$ushkDyvO74=eCCSwY_z`e1XD)B<8Y#Mc z(87~Ga)`^x9Va*?YW*+CqqV(!dn*3d-`~O`NnKEXAYiDpDf@DJi{z1zx&A9qNXoix zR6^xi0_WETf{fvc90A=9=MI853CNLU__TH4}tuEs@a6odQk zi=zEH4w6M|m(;x7-Th0&vWzW)MZ9=Re4t>Lu@0WfTKZQEVGTOtLmTov3l@D>jc()Y&qeFhV(XvbHd2s#cBSU{q7dDD{M*}fPJbl4>c zT!W8_4idh}-tF`cPDa(ODpml()nF}RWTlMopo5e$T49MGpqgckPzlFdb(+5CW5r$y zspWeXgO*}9iCsjX6AP4oa?KwX3u#*GLK|n-`X`mIg*-q%2K?A7wA|$GaeB*7A>x1e zlfY(d4tzwkk`R+ETSR}%UH2)48Ee*9*+$Jg@+Avd-%Go!!AvD1rHi<6R~DFHBFP7m zQ+8_+0YuPe2p9XRRn^}j%L^SBJa1c~rPGblrQs#_WZNzqa53b|x;RbtU?#MK34xuB zQh?j0ga+dxc>_cr3TdMXHN@f-dH2EB1_*Wq?no_i6B@=QYh%I3c3<8~$73b6b>-qo z?P(OSD!G-;T-SeWQJZBpIkCBm9THKe`%q z2ZTSxiAiQ4Lz9=e%n5G0;HH<9E5?a|3Xb$7V;(ki1o`OjHDc^+NCPjx4A&v`5Z$zd z7x=5SHA=)9+qPD?B?X|iL$xg~Ol`bQv5N)p5?ZaV5vBd}{;cd83Gg9}lDy;MsrU#E z0zOmxw4o+YJqn%;@az|#-GbdT9&kfjb4~S`7h=S>w6VLPq*=INi#PBBx-7OqWo+|A9t4+EBsDvQ3P?pU*DgA&VeuIb; zDuC6TPPkHuA6x{>r)WDZKe=r{7 znrI+nS(HDD0sRK}l4nJ5;3C&ko`~x%NrQby$N|^b+_47W|5!54XoZA=^ZJ)BC)Xvib~cmC=a{0_ru2S_mA)I?JakjL8#$COgK4CMW4+O!S_Bz zL^!ZGd3|Aq04Vhvdrx*Yw)gIDY;A9>^AX{c5K|(MLb!&(xdh=%CWT5JNnuxQSe~c9 zB%biBlQnKdtU*#BHV0T{Z-X_6ZKu6<;!V$B^Ufj01A1@?=R+9KJr`Av$BsNa-hJ$&Pla>VW z|6G1bB*{DRQy9kP*yo_TNQTRh5LeMcj(tlcqyHTXG0Nj!Yup%Lu09RzJ;8Z>w-Q!LsdVHKBCjl_&-R98!N0qZ_<18}50mREx7 zIb-<|V1u>6yyMZ&#b8#pF!j>A_#t3_8{GEK`?JCx+j{faOG#)u?y$iWvtJYSGR06E zVq`N>dmG{d3J=~Vh1qQ-`L)nWxOEC1YjIkMWWv{S-3!U{_HJSuB_s}_X0F4gZ?wNs zUsJNuWzv9aec!$f2SOb0hy%+D6u%wp2Z7<&qL5k0@wr>*Wd?Q$FS)$pUV@dMp5 zu1gAWg$R%2Qt8Gt@m+|px80WmJZr(NlTpmlL%4;#)U6cuSB+0JhHy3w77m~bJT8x{ zOX!UK;RH1@Gtg`q<@TEfx20AAL-tIpny6TG z*5hhB1H@UDyxr(%_Qfa*)5uApI~+6#HUm9~ebhqE{>fLhq}&^>aLE?1T{*cO&yr=$ zdc%rOv$bL{s|}y3RpR;J7JRR+?*3(KWAD3-M;qH~4-=o!oJA(7F-dGa{dC4+^OVYe z&WbnhKitTco9t{7ttyWq#(Ka5A@0nOE?LN($%vJX5upt=4@%B-w^p0#LefNhH@F8S zG8E#xHKMlWODGM2_oWl+$O%)wE)nhOj(0YqD(QPxczpJdkdqRuX=I&z_9#*>6>~;V zEQugD{8dJe>(2OfNESY*%Uw*KT|vO4&k_Ym>6iIdi3vNCPGc!X9QP83arQEnw0;v9 znp<`mT$^ODqd@AT1B<3|%b%;OD1U{;xe!Q=yOj2;{wW-P5fTzY^XRN@ajBuByz>3# z8FJ%p3bptNGt4N#)c5LJzDb668_$*Jy!Jh=U&uzye<2YkuH>I1nm9TTo(*r*n&)G3 z-ai-|fd%(3@PPVQj$T&d^6-Pqj0wl^aB0#$a`}&Ns7i4bMk?)4wI?Wi{F)$8J&1!a zUS&?gFy=0(QD*T=D+@f|@NE5bB*(D5c&vXFG&!2etMHL3+ujQ(s1x*n7>DKDMTTC& zQHxLY7=8R?H~A*41yUeJJNVKy`~`Rmr*};rCM9w95N!=FF5p)TT1pmjhfYQqFi6?J zh_*MqaW_fqmw6&kY^3ju737}xPExwN3TiP#Bx`oeg{`l<2|#|g$9>%+O5!6gSaXV) zayCxFpT8#(-ucO=(>`^cc_Qx)seCiV$7(qk4_>Ek1+J1Ln-(%vb$$PIbimL)pU#1} zL%B}_N50vg005A;(9)IT(?Z$a5+hsMNvLWnQJv{ zMap+-CT#~bt;8U^tfK*MZx&*=0lS67&7_Jl0dJ*=C#1xL34@|lJ4Rg~@4+!J!Fy;O zJn=9X9*ywWAL@PBnbYlj|NW0Y?ESd0y@Q8rI<@;~&69#5+LgZ1{vH?$&s!y&WK(xH zA3b=S7$SkBXHTP6+;oiVhFy#f9czzuYY{;O2h}&w=BL;u#jPnTB z#9Cyd99$5FJhJ%$Cp{=sCe2QkbCb#>$~AF38_e|yT_zsXXbx=*ERv=W#1~sE_ZHg4 zI2iP>OXzeJ1eca_sfz~b6YG52I+{eV@vH)I|I(?`j|F{o;O7J(+8$SOK2d${nO-@dT@4BKkd8!zyb4Q$_AgP;%tq$a)B z?4AT{bq^Mb-m9<@O*U|g@!_$XU2~7LrO*54VB@X;jhqjgHNiJ!)6HeCj;2GFGReDP zq#_Sa>fQ(sF<*1Rvf~a4MRd+#6?-5<*#$ArIHaz?@lB8jG)&@&xC@B1K zC`Vj8xMJ#(P0Q>hs>+hSq*lZm#SSrnAJWxlrXRMM2|f=9P=-nzf%jp=gwlunebtN` z+>`}MTI~r=i)<~#U0r9)HJ|j|ui8mUxEuAQryajfojhSGKtvR=bG)>zztzvTb?zmU zeDwoD;7#zX@c~RR*<_qe3CYMkG!=$EeT|fjLBLjW@Oiu0LP+MSIk9q$(CEmT#$^)0 z$cA&k9m}qnm*PVdc^xDlKhZoQ)~t!IB2uIcpQx$nmPF`m0JR#>Ju_O;>MMa(xt_eR zn$KP?g)Q?nWZ*z2Ox}~bS+USVi;DfU!-x+$piojK#XD7DHP$NGqy zlyc}X0TPuUY*bw3z{_l}wUR6nOprfKZ8Cs5r#j2@;jyz z6s4f{d&ih%ga_0PruYy#2yThPNyZpv%&y1ak47)mn;UqlokQ3NEZG6|Q!cySHxMzJuog`40`Qm;1jvv?x70)M@kG9(xSc zmK>V*|LUU`t5VHXH1im-O|(zd*<)QGw_a6P$_1iem@4w(OOi6S+&9G;M2p8dG5E{6 z=UK7nwi|0{S%ti5-z0ZQ=ypEVA@97E3 z(xMOLrL1%jUCJlp(aW$=O@_V1uH}{}9wh}$8_~myBJZ7+N`h%3*{BVAgpvVo9Od}$ zcGi(-DLx7oG_wt6egi%ndU~+$OJVr)@eBKU>p4{N9=LYIIF#{9d)2RkFnGjuDq zuL03)8j)R6YFx_`xxP(zy{srD{_fSuHNNsYI6FTD_}xy$)#kt=-CK)&{?(G2FGbhrkrzW^c?hjkK7k4ycKFR7OFH@Y+BSR>wZ%B z6JG5Ri*wSIgm?9j8>8^z7o|Tv=x@^))?Yh};-Fy% zH>+dpyB$HYXHwny2uzO$w%LF3^!86BO2S#kRqDQto;Qsv6#xE6R}NB3Wo8*fQCszN z|M}|VXL+F7Hn9MifW9rU)}l3qTG55w3&)sF9EFdG&s-l%Eq{9l$@uN2}qpgS^`^`wzh&d{2q zm=FGGSFXd6t*$M*-LvGJ_lO?#U7Xhbf%@3Rt4`H`_CZ~zFrW&MHtQe}AS}#*Y1Q=e zHwJdBG;IcD)A{Pc4MNMS*_J#L<#!Hkl-^tBvvJ?1*b^{c_WSgX2?od&S0};@jwd26 zmEUcSp_bi#>n%3r`f$MX3F>XwDiq|5GNeYvPo9i2ob~XsA_$z}HKsXE+BvD-y zY+)HVSb@4YCGVLKuYB|o<8u=%0!1ekx@SxZMiGJG^qH|4WF-myuhrHgAs1oH<(E&sT^ ztB29kpQ?zbYRxXwOQQVv_=05zJeX^u<6P9@6%2!8(Ry*aBN_~_BW`SWxq+fA_SURKN(LJ7tmIx+lb9+A@ucRCUSGKPSAAUYF z6EUu&Ty(knpg~yYK4)E@llE;?p~!$;Eo@_nj=qlO^;6@r_B;v@b?J|JWnM0X@UN*P zIXgi0avP~O_ls?|4H$7~A3&l(MbJh#a2zuI)~l>U-dq^N;-2N2Vb;jnTd-_kd<_SV zS6i_5hy+?!!~s=U`B0bKgB`y&7*OVCtEt!}1+KYl(U>+BRov?|YWBvE?)?{o5iT>t zVOfV_j4%P;h$@LQ-IYwNl?^Y0;{a(*y0zdt!kW-DP9OyW5;&c`ji>`cYgKJpR!v`* z7Y|^$8L=vAo!;^r3NMVVFs{({1M{*cKcH0%}2wdUfNW`_?FkLwG%& zAH5t;7dM29L%oGKvUW+Yw;>Nm6{sx^OsITQ;sGdCX%<>k;GXe#fEbv(4+LqTTqa2- z%Tg!fXVTNpk^&386-un3&9mngn%ORUstgw0qgs+2G9gYcW+W!B4{u#EYS!Er%IwfZ zK6>k&#DbuGbp;kUn`E$-{Q`oYN;^5Bq~#^I%8n-@5z@bD!)nLN+9~r)UNag!k*#a& z<)#2)3G^ZeVy*OvW7GEe5EhKx^q`(0tDprGYa-wj)P%m}iWLN^V*7nOM#QxORY_#F zZ*~-Vt4X%eu1ET4_fkP`Y*$X#zKO1hBEtf;DG%(@h}5wX3b49b z(6|(k%Zh2S5$2qEhND^)3GFK$BxM!D#VkC9@5~p}W~^l)AwQWkxD7HG_>Ds!?l)OJ z!n8$2)305%0n#$}4VtA_68vtc5G%I3wYp@D>zFr**p%iOzQ?_{p_*9=@@RKXvLt=o zF@$FDl@31J9Qzh*#vTb5QS7IDt_lx7O}y8>cyynWmKj?9=5i`)h;UF7WYiJSX4}Ci zu|gr1lwZ=H2@^Y8lVjC#_<0;SR~KzX{)=R`w(`LOgx5+*kLBLLLImjs0kBCVJ)&XyBrj7e%qDx#I^TWLLzfEN%5`jFLBe8vt3{ zZ{GO}Dj7)Bgua$*!LbmAD!t|@%vt(DDv6Ch>5tKfw0)3BvEZng1g+|tF4VEt{<)au(7kXw!Xn4fY02EEft#>2Udr{ znmH4ASvms8@K9hjZi>MZO|bGTV}|JP;Pe88M6}8$ob}bW>(%)MFW|VVhD41YRM-eE z5Z<`p2Z$CjrGSncfKgcV)b$66ViW~JS!2T z`O3;Yyd77aOsD4)B<=#J$ua`H%ftSZfAIHj28Uk@oR{uIfI=sp8<)wlllC2bP~JDS z6q}?*+e6(1$6>MwQG&8{azOLXCEM>cJNIymb~<^FrT@A>$QoamI>v7PgS}+Ap{k36 z`gm`04jItxtaPtjTVW2CLwy~o`>3q5z46`N&ep@t-MvST_cnfDg_vK`Pw#I$-27p0 zeQj&^$@a!IDZk9ndefQ(H&+ZfZH)+IZGFpF;In5}iZ!xnOlH$NDM&@Z+iB3dpul~L z7ZNxP^n|O;`D`2khrT`d89hwF%>@_Sd2h%H%Yh=;$A20D{m-jcI?I!bebBzo4@BO$ zg+#en zc_;oGh%M$_rC&>vl4LQBY)($LY?{xJ|HZ}WY)uQPZ3oB(dr^LjeJGY!@Rw^U1v>R5+iz;y zdC+uW+b(M}n@mp_@%_pDV4B7b!$7l}s410;rAh;L;<4u6mGlb4Tpz+(<2* z3oOK5QuG_z71UKv(`v1CA27_t8w#}wvI9r!TbaRYLntUXBKG#Cqa7*7-+We-HR^vg zdcz?+vj{yG#~<6KIY`ZL5_9m{;sr4;^D1yITK>U7{~SJX-8;E(jbHJWF#ymMG|kME zRMl~wlNly&ASsi7p7vC7RC$m?Edf6rob<-2lAhqiSuWl6hC=hNaH_Ao@Z!>fABYy)aTFVOpsCjLKSK$6uPpmM8~ z|L74lbHT!cEt7dyHgRM0zu-gUQ4 zcd!WT;VH_$o^(4C8QY;DIC9PgFmBu(Ol0D2kQee^+7-%p77IKb;H>!foyU*D(SSqi zn1-VkXtfER4RQ8m&JP_%dWP4GY+5{q{^MYTJZ~splU3=;eF@5Ix_EfDB$FQ1uSEkD z4{$0hWgfqEaOLUM$xlcq#+V=}X^Th6$1HA$f_p#3&yY7U~QhF~RjPX!^L;0`>ZIus_CCU2TJVmf{z2f5f-Q*p0}ldnE25^sQW1DMhLX z49*9yl%!-A9H``GX_+`TWGF6Z4O*K}X~lXDNPsyRzjg;?P`J8^ zY7dXMVbDF=Xqol_Zu;RScH6MP9KUYptjeQxua>M~KF*8;(y}83AmWLo$TugcjgCe> zQN?G;;1{)VybzP0HO0*Eo69D36Vj$tf}~@e7oxyq0MDMlBlxz1Q`)i*gbG{W)NS+R zPelWz7=EI}kzya}E5{s2&6y_fY~uMTczH!OZBbe)e74S{VYkCOQNt|IzRq1&8M zS%7?H@MRCp{ee3k|3JS5s}J3%9M5Vwtih>)Hl|uEHeF zBgCE@Q1!0pbu>8c;vW-dtE=nZZ>;}m?}x|tH}*FEV|`<57uCLY!a2sV_!Bjw25A(P zA_2`0IlY#$ij#zX6WMBn<;9{$`uE*>2_c=a`W>jB zZKCR*4DHbbMnor?Wh-#T#%T)?6u)3RTZ`{gP>EzKREoxwXXm1cCrC=~Ny)RaWA;_y z>qub;B5^N^DQQPX^CUqek*NTiockmlj-SQFvaQCLUiMC(E1~~FtP(Hjk+Yov(a&Q1z5GTC!CJ47W;Jmng36y8SW<_B}EMX>FY1Y1lT-=&# zS#huminZ7bemyV_ZUEVEiLSGbt59Ru47h}a1U-54T2-FOa#ihwM<7L;v)2T4J)a^1 zemWiCDpiomxN9%QP)MuH!XP21P}2Ns!TVHp1X1K_1nDGgFk7)=>-tK+^EWFfvcK-dTekH5nZsh{y7B zs_9Tw_GhI^pjGeFcJOw>>MUCrNNSljt*rC_$SAv`$70F`2x;77^ipCi{T0>;q#OU) z!&N<6-PSUSAM%(qV2OTvYw(&BQ+q}ebT6vKrG#)bkeXjCH=y%WYTX)=;Hu(Sg@c(h zJLS3OsZ)TmcQ!e0c0GmJ>6>4zXuLP{O{r9AkN@?bsNl4^eteplVk5W~1OoGK2=)VW z2gk|(bR*d_Ob#mS17ybQyUC4bXJu8r@lxAUikEw5u_F*zq zI|nEK`~MvxetcSeh3iZsv>n|$9*vGq;Wvtb^~$?_i;LkS1QrH;@bz{dp7pQx`O)(E z@)&_%G8ndiDug!r-7?A8Zi6@Sj zS*tJA)z#H?>*_bmzPZHQbLCQD3+GZZj_YJ%RkUDT1_{7c;m)|X2}$o{aze8oade2HQM79=wIQFJCa) zsmx@YzD-7>f(XYIVgkOk?x!gjssFE3Q35!xtKw@TV7HInn7N z`S=HGN{=Q)U?E_OAMdsmbju_AM<**QwTGN_>vDeHl~StBibcHE(m)gBtPu7x8bZQn zp=TvbZY^hrPZ9GeS-q_t=k#-Hv3i;?&wph?Wh6)t%W7;nX1o*4^lx7cpjrr41A%a? zb;N)hvY3}wQ4o+q$J1izA>VuEDL`sp>5NKydkbw232GWw~PI zU|cp}hhnT!vAMU8h1}CRRon{Lhfx!F#yNG^;TeZ|()+u(drCvLM8=h4PT7!Plrvx} zMto?t9=(lG59x10_F~uY$SgKkC1(!OmeJ~r?SzcW4Tnw~vToRv;FPr#z=AIg5s1*B zEM2hT#)8%Ueu3ptg+2l9b<2#^HbS4GF<6ShU|vTIhSl6hVDWhJE=0x*yIB>QWE0Yn zF{={nY>;59({lEP93bv*x`*)TgojVTI+y;)I4un^M3&S3kpx1)t7+L`A;R($D--h2 zhHy9;^TIyH1y%xU9iqvDw%QaB&3bTvsDFgJ9zzM9h$m>_jpTC2apYmh0PBFwBt0Y- zOUN!*vf-4hn1FKi2!T$wFIP>xrw$bUy%POE2sOtkWf9$OqrNN1lwARBk9tEeP7&3~ z346>vi{lM_-F@eUZ00LbZ@oy>=ZMmiN|@maqO<*xDxg)k6>Z0Mr>P0;4 zsq;|B9toWxK<%MKUfgPV>tK}-QhF%>X|Am$l}mvb$gc*#5=Q@J7-s;ql97Ri9y&Gx z-8YxY(uI3jjz^MHZRBdbM3ZSy7hlwEQn1<>`8$;67*jg1Zp+SPH^>KJ4w`|Jz-de4uQV!vN!#2wZ}Cj}SXZ?_$Z~!NP9A0J_Li z0Llm341R9J8LPKfoeEeZa7@SvzkiC?qs>!12zFBtBDfJQs7{YGAW)7ocO_|JRM?}! z=cn{xfW1C6*{-79g?V9hHEcU(KrvSe6aXkMQ798*_fRhW+)0(Vr8;td`uf_=Zm8z#+^Okj{n^Gg4s5gPj#cw@zO1RUwzc*6PpyX=kJg?)-ql*Z z&hKmLgm5kooU3!&l5&>D^Kf%#?c2v2tw+y*3mufJbEmG(v!?)Ud*gqeZ*Ffq3@{ex z)z$rdUELqn9&bKe+udmGVDg@<5m2jh`xffRTpNvJ}=$8&m_5SHEjWfqf{PLEkNVT ze22sZKhmLCZ_*Z`KtwI*Ldh(6NgBmD69_sq-QpZVBQt{fu403RAys7rBoQmiba!EZ~U*IDQl+I_%8;VH942?DJ}oO{z#%xQ`R)$#BO?m zKR%XDLMy?FNde7EAVG?y+eXJqqDfsTQve#N|;3oYIw!l;&3ho z28}jC)S_Ur607sHG8^eCd0dff!%#uWRbx{MPY1=K>1ci;;^)>wGdklUB+IkJz1tG_ z1+Iji!8DyRcQK+X(PdpkOW-cEQB3aL3iW?xHn&b|Jv{Z2jZ6InUBo9rV)<8}Lp(rShE8TZ?W{00xg ztSk1HJ;#q^O#jSTR;>Oa=J`82z#?M0DDymmjld6_zo7We5CDCAf?AA~sKD_wB%#ajT1bU#;SdZsGHVzX%OsnD*Qr=)! zuM=E+$hQiD(#{SM42mW8eY0mFZKh||M4`9BX%u>ud&i9eSvdORLque>z)lb=f8eSh zczv&d^Td6&r%wFIi_p3%7VEKu4p zQXV~)mZO0S7<8EPOkZ`k(SokGrW!Nh64H-5k!5WRp*$zD1>x|FMgV%EfJa_4mI7Jav=Tb-Xf}Stt7Gh0^)UPa*mD29 z{u|(0L7&bgVn~F^ zZSC1omnr)=I~mdo&3NY{7o-A=Jv+Jf5z?M4qJQxWJ@Mv1B_(VS5jW3|9om8pQ9$nC zA%r@ZWRW3f)Z1s$U@_x=#OC7nq$?dm%*Nw<@nMLc;sB!I0#b;sppUV_ATa0|lc^ae zK*nCoh+|IhcIfS%df`t9`;oXjHziD_#p4Q?25)N&1D06i{7i-=F6%56a>KX|gQh#V z@3&KmbX2w%ys9B?#?Cbq*o`UoKK6*&Y4mX+{m8&ac4JT zHdZ+v!pcvMM19JzY4?qPvmk06q{5n`BS##o$K|Jv!54O9bP@QhP&Wj=ONSv(C_0I`<4skt0lKq*B*5-a4i|;v^Da$5Os-TlSU7}e z%C96YQ>fXf^gmP^35;hH<&G-_jCldzDrw;?Pk}CU-%_cM9f%F}A#2H7FNTyFxoTuv z7C!fbbNWLbw3xR?nkr4AGI0kqqRE)kR|C3KU}w00k57d>nK9obo3py*&FlfQ%q2rh z#Z+%Iv8~Go^hvQubCHJPsJ*&&CP~;|Wi!wgv)a8kIG4+$opAa+fiVc2J`hflnd>RT zu^yMDXo1fgdn#;2FJ4ynNxr`>M}u7QHMdpeqX*b7{E!0rfhJ1IT6KX3DXNDq-MkTbRxCy{AWG2gl6uDDjFTO? zo?=0OZKPPU5Yhz2F5_I>JAflx#}!q0Rm{P9+p(qc5IG+GVl8LW{mh&5+!I7OcL@>;kc~$K&w5@yF$x%Z3e#V^=w0 zi6-d4reJU{zzz;n}KTwVEb@%ec}7ZpN5@ zB(UVUQqgS6fO6!eV@){NMGbo~xdbd{#My>))qC;yMLq*BOI9H(F{KI!!Ew^CM1NDa ztpp2=U*DW?e!h|9&3+(zj|aGR&;PV>X;J-GvpxF~dlc3VV(;(_1T|$~3Cd%|L8T0p z9`#Q1Y>m2Cc65o*hK<4|*{OFjl&PE^tx*?{ls*2IRcSh>A8gJW{SlL2$m=SL;x&2W zj|^)w@di(LW=I#c%9c#ncj+uVA%-4P7oG*0>drzp0%h1AuL5*r1Tm}KMl78djd9>PFx_O0Q`%ZP)EEbp>5dS)M9Nd`wndE>mF5p0^jGlqSdM9(d9HgQOa?SEMFXDJ{X{t z=?Xttz03+{A)2~Xk+z+z4;>|_q70zJp(s8tvhkGxG%B24i~BatW>-^e3g%1Y>($WO zJRTe~f!0ht*HJoU9}=^8V@dAJRb4|i%2}rp26ovEy5iSe4tXhk?$I1CzUF=D)QZ*t zNGbk80MkWgIy0d>b;+lE2v&>W5wWBDB)APTOKMv^zx3N3#58f7EGoM_qzs%hlztbG55{biW zD+{@}61VV-5nnJ`MgrEu<-zc1<<i$FlwS^4VC;v-3%up)r@U@!eNEi=)!0I}Y8$SSp=;>1p25 z9u`uVJ?8EDeD;5&$DB5_*bS>Ic51EFp z?^k=PqmM@yp}-X#WpurIwR&>0I^yLWzW`)$R-02WCQ3cEY2#e0t1A9H!f~M;F;NGn zd@jtpsk#h>2`rU(3uLzIQ26HpF*6mxiD~kzFTaZ4h~-ZGLVQ1gS+o$#NIZ`UYRI8yOS;*ixVBp??pc&FN3=b z-j2FGAZ2E7y&^PA9 zMQ_w?BYmS7L9*oCiKD3f(LfSQNlvh!#)G3{~!K2U^gp z@%VI9qXZ41oncH~=lOE^ju^Zk8~faPf&mvYlXbzLoGEwxx!*Bv-7M}b$=$CFT!IR^ zWxBrReBI>17U0Zs3MT?>+`gWlB<oBD7?g-7Bi9h2SI>opXe5=Xf+kAkD!!u9n` zvjM&6nD_rQR=`#Q*mo+_8HZ>=?|2AGT$)FkDna@uaf*P1Ud$|e*D2Bz^>efa}d?9aU8nR{9B{X z{3QDe`zym;ep0Uv%QZX|TgrmY>?3;pLA^GA*&bUaB%;gGGA=f((xb;~-?fltZ1ZvJ z`P0pH+<95At$^`KNP7DXZU<^J>lian6kFeK75DEIzgxb&3}y+Q-#h9fup7Bdg##Z9 zkoOO{0oAP@qCJQn_ell>Pd#=kIs(R1!IT8=4|s3ax^=NB9hc~^jB;Y)a(l9%2)rS} z{FQ|moz|aKe(9Yyu@fS0WR#JU$}qjtH(zEiI5n3?)8AI40dAh1hghy+!qDK}@)z7O${N~BiLnEG!H6293qN{M zY-#>f)_+c@c92|7Jok|#~SwOLf^ciulKo`Od5b@)tfeVP1>3q44^Hr|~!`rvM zDgkHPIwzbT-Gt1a0Oelz-3Fi0!+Nq{5Zyj_uN3^bUS`@Xil%ae+v_?+~OfR zYkMEUf-MNh87FYT_Tc!yI*|jBBcK2bpu5x4vrLy1je*&Z_*keEZJb zKR2i}+nQQj!Zjo4Tt^;5R#zR3{yAKyL_G8Ubt)N+2~`s#1W_-V(BycZ2*N>+aB~}+ zQ_x@bmiIbe{CPq27>As4D9c4tQKo>43D=CbVtmahHEvH}e~=rP7Yp; zdU)q&kBhl+gbQW)`e@ii)>eEursoQOPujx)5`^Mgzx_sv431$>;R9sI?jOmw)5#Fg zMtPgVZimH2JtRpR^4qxEKIUJLF}#WRa@OU2br8^NR&4FkGW;h<|I78o7wzWZt>zzI zp5OiO-hcn?hoyy;9=bCe%{mQc-4*L>J`D@z496K@qA%9C|A?N3@J1mel2pYo|A-L= zzO&Hl3)9`eNhsF82h$M<9+*D`z5iuzbmK*{-TeE@FYs*@|6l&Xzz==iEVi~czH5EA zy|LBWeEP%2_HN7u4LNdm0kZKXz0FL7X7v@TZ9e)+?C*W?&EnqTUI)0}TY4{lmkRmA zf4}^oOIX{Rbqa#4L|G>XW5EePvQmLZU~iE$@b|UmpGgL!0rx$8-D|$Q5q`Z~+FM?_ zvG@X2P*`h)@8Pl33NM7DqOGTlk`y{npA5l`{MVoq3rcZ^1SuBg2Zf^W+5D8g`VoAf zikIT#00d$~B+}$cIbS~RSbk{;{}KoD!`;BVd)Ds^ve`fe!S!=4NTvJk;21ZbY<*EUXRz*+T*ul;crxu94&uQ5f|8O5IPs!KZ?Z9oN8MD}bq zOnVF7oevn?-L_aOBPYoG5d2sJzvnRd30CYdrVwx9D*g;Za)4ibB%VUTxGLbTn}+8I zD1xe$V-`}SBxQi$%kw~TBPN3Zgw7}}oZvDt91eP7PogbV!05Pp=^=g4arfJ^ zqFFp-plk64v8?u~Sc_2&OXmWU8B7z%Ea@$X5H8)ul@!MfFktA*X&4F>W4Df}Zfa20J!sa!n`lq<{m^q4>0~P1+}bmwT$6tktCt; zxiFP>RD!;Z^7`#gNxiZXP^{ol$C)b$-MJmDVx+|DOdt-TL|vPKt3qY&9)S2^n$iYu zExXH_ZY7O&dWVN7vUqqrXv37Z=zD1fP$SKYYo-}B{xxiaY=K*me8B_Xb-o%*Z38F) z(1F&YFgw^m-Izfd?)x1_nE#>4eqgKVjn5>-UuEji z{Lt1E%~jKd{PHx{(hz3RTputCk8uCuaSzHBSYohJ(Ho)`>ozZar0>YoEoPwHhoO;Y zA9+EH(x*HB>3s?LjVojvV%`J~k}A=8)Su@(M>M!R1x0p~3}B^0Ub%95l}vb*-6#{r zm-Awgx}5;z96>;KMQ)dB7FW&QG-$UBMUME0-7bh>Ud)z$E@JV8n@~F393c2H%<06e ztT^$e=Tw=39=vvvzdyEAm+Y`%BRboW&942{Y(Di7Pzu3tTlEdjs zB>?)TN-J?<>1Zp8u@=PudgS?5kP|?nP2{+Ah)&61*-)g%fY`(W3KjVb9RBf*<45Rx z3y(8VBg^nI%MAS&oK?nCRe}l2qdaLs5$B#R7RHFZbWA~F-5S>+ZZ*E(KmXuApF6ip zMnWapg(J#RH#ul}ADqyNEf-I_ z2MAzkV+`os(f_D8?!E37e_1JR76Yu0;aeQnD9#2GrihI5D;tpoz=;fk>U+pRWDQcd z6JvBtnA4~R&)2v(KSDifA7Ysf7zyjqZavGN%q#3(r6EcY9kT$M{Xx^jDF-l&V@u#* z&=pg_z%hz$>8}>-7js*%N(gPWfY#+m zsym1#S7keB=SBGUy)@?Ovo&uENl)M4o6?&5EhMDxoKVFc-3MzI$0sMaGS)re-xQr; z%H8tkwBrILsK!`wlWyI_v)jw!3hG2vbA-yVym*Nmy#4 z%FD8GiIR7DF5riooa{QbNHNi#bF>8{M)YVBu^Wnx!QMyWg`-z>=C!2z`3YT5&1!*Se5)`Sp`tIod;Qupi$9p%`MC3LaOyB4uX+Wj*XD5gQC zOy9Lyl*B;^w3N{E48n+kM|s_SLxsPPRn{^fbl17MWIkmq1-wc#+-SN(O}NYl9>3*$ z;OXvEtc7U#(5As(eG1)eSvE7%Hb}owMHoo8FzpEtM_Z_`mF=YVJeT~keH+H_C+&CZ z{$O(qU$SjG5t;b9G`|4HJd~WAqO2PT*nVsx&cF}-lwdv5;NXYK4#D92k`CV;RS3m- z*EJ#*LRbsSlaXIb*SPU}HR)ut>h~y7@>PhfyhWNp>)?wp1t2WQ52=csIi6C<@O7+a z59@Igalu{ECYQFOFi*F|*MN`>2=q)IMY6s+G|6fx&!H`c zvuc-D8|RlG_a$xM8W?eoaidj&PnKh#J5ZD}%jdKtv*+58*{*2GHYg0=N>=Xv)0a!| z-f>O%!HT@3%g2F;MT48NK^3CH@PZ)W z(=3#;=`>&;Bi}$IQ!cC#o471U%{iVSo=roS+gnOZ{935*V@d0@`)~Yaat0%!6DTlW zF%1X_X97_y{%~PlB;nS!8$=xgs|Ivxv8vR_n!p zX#XusAX`|>-{@L$2BtbK)$eJzfg=!#(XWPTDZh$3RBlnXd3*8+J9Z$<8R;(CTf;^k z0d;}w?{LW#@tcd6Le3f(M3HB zD{)CSV=&7x#R{loJPq39F`l=tcsUt_@!r@7La9wjPI+OzN7zu#s@4|=ccm@j;*|)k z1hIi{K>pzhXqE60%5D~9m<&WYFxs|1PN+7~*wJxOT)Yfn7NFuC2xiMIJt*Q1qMB}? zNgwYc)UvYf8mkwQWEn>jTR0p_}qbRc<9vXfQ(me*g_L>l5D1slIkz& zxUrH;Pfjf@!x6OXIL^iILkS-V#UK+-!OwSsM_tw)|Oj5 zR)!M$0`x@FNehuaSi&-^^8-#2yb zWGhLQOx~x&TW$G0RhAc0uzE_psC>R8xM;)vT~>)azYBoRGOE)^u3&Vw6?+4AKubRmPJylI?3`sPx$>X|- zjSF2gvA??Gy*nNb3Sn|P*mFTx&g<(aaZ+dQ~vRk z3ftg2I51ORRGadb&}6{=px%(d5VF1)oo^Jo(44hWq&kGJc|5$^ zOJk@FD*$JOujk>$qqXOccUwES(Co=tYiDa?9a=`C=0KySioEsZ%1Fj}9bPxtnj*{n z&l4B`=SzJicm+<*iBW&d`5!p59?&bapx<1{wly7uBzaL(Qs>fgkw6yiAM+-i$_;Yk z9ilW4%Vp#ONkPk3Sx-x%A>h<oyIdfQZLMSthCFy-2|^-@i1hOma3?9ckvrz_7DhKHmqV&#qJG1I4Uwh<6NG;qFiv0NPKALV zERbTz3@yOVIU0e(nwnF!ju$b6Ay_aDVY`L96pk-P@}0MgK-B|ADifdD?NS@YDM}b- zbMEXtnn{*JZ=^`Az-7KTxdsD$<$Qjzv99T+JgRB&G~7Ti)PufCDlvhv)gYwtS2X$@ zS|{DQ#hVisBuSg6>QpE8a)$}6VykF^64!|=%4t1>wJ3wAv%9CAs_I)o6Ip9Pv1H>Q zGvGoTE0T>%@#?9NMO-&y97aV-7C*e0f_7wYu)R0FHHQt%Mkd-bF<7Fr7z)F%l~$PK z26zR*oph3RE*kl$jbq)C-x^9W#0w<$*PC~KgOmUJxDDZ8Ttt_CX3HT(k|?e1V^L>B zM+%675+IM|a&eBueQ5@ZuI^I4H|TwJJSW`SkHgpL?<#fBSL6!a^kX#%wAkl1v} zV$)yIK%zCk()BZ0wcc4vW-s=i{ryagn4h)IXJ3v5Hfq6`jO_eseLg0mTL z(Cg0(Cl%EaI*lrG$(?X)xoPa#fRK>%fVN)WVFCV(I<&#e>wyUs z(*1D;v>kV;=%q)xTywQ}a|Nd1&6i2><{r<8H%D)6Y!VDb26tqI1?73C2>M)zt!n7)s|jtfxeh#M*6JXtzAD<_syS%Bxnr8 z)9`9gz!;GQC)h3EB}Z%QaY?eKfuCsdOSxeKk_Z+r^em5G1Jvp`NTw#TjCOHm%^RJ9 z{9?mxw0niiu3^@b>%)rlI=mv>a#nb4c9XZ=KsN2#r7v~?Au_a$dk2MgBPTWhgs;h% z0?*Kq`GJyAxwu*4ed2msiuId!uND&a~s2iso>nhd;*l6d2gX% zCDVGG`&r&L@1OhDJ_KbT+I*7Yk#GMp!0*6n`5T?22zq=)cCz-B2BD25&{Jn-d(kMW z3@utS8c0PwncmsvB{DF5vZ-;?>thgPsv^u)vn`t`q1C#03nhum%$?Xi+)~UI%Vp?I z7YWo}BTr^OhgIEZG@7(v&$0m}%PRprl5E$hz*CB}@JYR7T5v%g4m+!38N74`@lCpf zZ`dCf#h?`y@F#z7!0hAlEqmpnZS<&knOBzC6q?PcJ)bn7gr&ssA-Uofp{N@Mf*IYs$e>^jKMAEOL4)9 zzEVc@Y1xyF(1Cgp=b5eZX{^IKoP{e~Rr--^X%uQcTFx;K>1;GQy|BY@HQmitcRC@> z)<*5VHCy#$YX3O*Yid4A&6fo!c!R79kEn^Lc;0un^8G+b)>q@%)Ey+j@3e=Vx-yus zDE>i2dT-2{V%N&ekj}6*MvmrxV(dc(|13tW2R@;~dsXXjwvwYLm?0b59?tn;%g5Hx zgLueXDqY_4T0oB)K`(QG@yXFP+sqfN1#n*7V07n)Uen-wZx*EoeXC`)wPeQTp|Kcgnh3u;ZcFy<&}Y(wBeAKD2tRBnWE0Y!<2!hS}5 zFuZ~dcrfuZdX0mS@|LePl0W!ah)jm^Nf}C6$8Xzb@bu$oliUHJf#iK;+*WV7q1;W3 z$HXmmFQ58Okl!3fT)NFO&LrATyAw5>QR~(j*3DZa%9S1U6L)+g7(Ec8ZT6!7iX!Sf(Kmq^x) zp6E4s-Gn9Ss>Uj1tEIaOa7Js9aD@@E9{$+c;1CrUe1kD5$;IGfY$7|rv~F`(hhRN) zY0Z1O;h0pA2neXm)aF2>2&E3ccz`B1T0hmw6;T&jfki^7F~=TDFnZPE>jCAxh@xwnY5~mNQZEP1^uKla{?F_PNyISWn8Fb zTkj}GTgdYS6Cw|dvm3T9l@&kOP53lv+QQT1q>(LFVOdC-(ZS_s=*bY7tDt%c#l|Mn zZvOxU;CuBE_&Ro>gSc9u;;)wpFoJ>J!(*6p$atWq0jwDerq|ge7L6*4HQQY{a9jK% zLA4GY+(?m5?E9$@aIzk_(J|z~&=P>%MKz0eiudaTuLh;C8f(`n;Rso1>Mqx%6j7l4=dST!W2cI z4Pq3}#7Zj&^*3PfHYMLVk%qQ$AN4CnOm*KXO&<7ZPD&c%*S^7CPAek|gnPL`=L2!G zq?l^M;~to)k7}qm4NBa^3*5ECzYB=U*}%vV82llUJiNu#3N>`A6c|oZuIJ0j zoD$OJec4z7pZERRo^@09*9wj+P^!F$ts`m>+)}~-N-;pbcSqj$iffCc_$9&2-z+s*LLuP(PW5|%-C1B1;T$g#5OHnV5TpS)dyau zUEV;n&7oZbc@r$KjrcQ+egSt!k2g@dH|jT#n1@m+IYD+JJ6Y9nIgTjVhB}@p zxIS={)Fnf*NA69+zx~lV8;b}X#?swTv9<#Yh=&(J#ADV;aMD3w z>Lk}t#>si~K0&S%N!>O7;`YlD7d6lw4Tb&zi>nt=aG=};qHM!R0ZdJX(i$E2;Ai$V zZx*=jCD1?ap&O2@4)clrb)|3pjg_w@W!qi4+yqjdj0d^jK-j8MWIFH{ zstA-wGlUFY1m~ikN?DQkX9VAUe|%Ve!2*q^I3})&ix^ry2d>@akT-d&s$O#CCC2u! zyIQ>XeDpH1GPsWT7uFn@pHBxvXvI3^k}4&bB;vwurRm~UqSfme7gMyrIh+hDBLBL5 zLSmJe!ax#kIQtl8Nv#heryU^80*^KlP@7--<2*|4P`TFo;Q|>xp}kCS&*k=#3(M%R z?(kL)pDk3faCf}$puy$-t;D%f$gGJOe%rYw~H~aOSCW!(dGdWQ(zUloZgc*Wx%!ltVK4M zgm!i6fD&BQ)E&av;Y}P~DhJev5aEfC5Gb;`8U@0yKik+|-)J#Zn~~nWNx`zSY}Uih zV%B>;37jiaWj$Qu!KNBdov9&Ujm4u`=1;e!j#>buTq7zi&^n`Q?Sx($*r$@iyWI0s zSOEq?_6}SvNv8$7kS=fcG>khR1=plnhU=*N(!=;xn=JP|bsPkwTqOrrhXp%!9kgK* zXT^ZtkNYWGR6F+!AhO`pF^8?Rj@2&4X^w>R)28dRH|8L+hn5#j90+)1HWb-MC8$zZ zh0=*3J+g^mH6ykR@^ss5;*e2{a+Zrn;JV#+ZRk1>n&!y`=aC)?mmP9LtG7PcVx`z4 zAj+nr{qUU5o?&r;p0X`^{Q({URJJ1 zBVKK3hPkk{@9vib)|~SvpOr7elzdquj3(AVZmCtX;@Yp77BJ5Dax=iJbCa^Xim3rB z%Q#%k+!*@5K<0j$tK?WH5Q574QMR^-pVT88o^u9qLelr~h^3umCQ!+YaUmq`N$|ws z*JCAt#f3j+82^!8@*r}ILTu_@8k1Vi5>Rn>K&@;22Xzg=8R`Azr3Rl5dwcl*c6T)3 z&6=st+@Gxpu*Qz_f1)?M3bM<&#EXBqI|hWo!B}v47b_|;qpwS+HO0as{ENH1b|QJI z;ygR{xSFX|ZW7{;2(ovt4^uc(XKcYEs;RIG%hw!b6v}(I|2dq@U(} zSfU<$g-%!l+PC6+ zLV*0ULs*{rXZi>3j6Sa=vaqKqJwH2~p;x&PxZLaO{@|_Z;I#vz+UCMdYeo|Z!jX_= z+{GM!y8F7rVBC)>p}80mh0GgAP4#EHw!us*pfs12h=@fopS?GGfp*cem!`(oq-<17 zct6;M>x^>^!lqPQ*7cnuk=m*D4p4-K)z45?m=i^|MBQ3Ts5UM*WyU!4DwDaR9o$++CC){Q}YkH!r2jS zYbjs_&6@?1O(3f1Fg~yDk5c%Hm=I14*J|!eb~^B++vFSwkTgbl^8hlT`&~ zZ5%`4`LddpOK)qNHAH8(%p^F9_KYg>SH|FLa7mWz57SoP4#LBEP%7Pxu?{2l@5rpG ze^U=~04~rPVgh>_+g+}}0J`Wa>t6gf%4eJR`MzW&j{(>~fmsniR2Uj6_YUaY*jG#2 zU~qbA?8QHM$0%!9n0`i0BF9c97hHP(z}79Z5i~3^C1jh03-sN%+wagtBT2k1AOfx) z9LweP!;-u}jPN>ljEeQqeZ;&{cRIV;W@&=6h2V*yrZ`(S&IO7wIK3s)VF#Lp6D2*N z`r^?-WoyCb$6p4HI4)chp=Q27StCT9WUvz}3kG6UMOKc<+v^sA#;tbsDrbFu(g9o) zXdrtv<^3f{JUFfA!WRmrGhq!LFvnWnvoK?;1C%Yt7vP&}r0;B_d>3i+{t)b5GMJaW3VA z_d3Y*3_Zk-jJ^5yRWsqq?ruzWkgJBh{mHoNDUHOnTAa^Q|H7Afr9{wMOoKEHr$BQk zvH^cH{_T$*o8Y&Aq;zf;-#7&R|3)LjpVu(hWL-WCn=xH_>n7HVr-H{M+54D5e3{a z#Mt?9D(V6A4xqm{a!`E3S~P?Vy2*F&r1MaZ93ouXG6Z1;6TnoaLE=P4GfKE0MHQ%X zNHa4M45>)Nq$3Cy^OzHkp0vd2v~!=Z4Muai?MF zJ7QCkHtrbdf9qm>efz2l0>I4^OdKlGs$rf?KriGIhcB18%8E)K)yko1BUU7hGQtkT zT%pRLvJ&*%V$X7W@3a1~8SFwg=6hpFtLy@TvfI!Vev!aqL3uH09cWTEi!VH%ZZ<^0 zUVyURvgjaf4gf0hGj-(5*WmC_VFT_-9M_UQ^KH&XlzWKXynzy3QdKWbakGXrlXT*L z2v?E8@R~H*o03-$A&iN|6VbfyhN2p<>s?Aa*=W`ZeOG}{WVo#A=*k$mI~5}tul56U zfi86tpGaA5_YJjD0c(a?vxUU?GCu=WEpp_SS7epes11Z=@ROTj+^Q=1v&juI)ibxV z$du!dod6xs21=G?A}u&RgY!>^#bLLN7j*IuqtXMLyaP1`EC;$3~8 zR>D09073!*PPjXoozPWxf2p1+sm{9lRCSW03(HBlQ5p6slo1$AI%XFszT7g4_iP8P z{Z*3l37N_eQL>OxmqgvTrMmgp;mKi99Wah;GLSU}i3;J|nbv7otZ{d>a-S=7HF&N9 zNhN(69gw5+x*gDvoGOtcNjVnE0}Sd1M-zV4S~Enctzi$bkFqp_3sMtIOgFZ*-BpVGMQlD4o0uCqyTstRnni<{KvaoGF&+ zXVe^=y06A=#p6Ox>BHUBTJOY7LafS)MJd(@T#AuDm7ZH?!O1Pq)fAi)lB#N9!Xi~c zMW)1`AQMsINDJZ2aH`)EErGi`B9TVKxunfyvE;0DIqRa-P>Hn8!e|s^j)5f3kG1)U zM&Z9=y}G?r+m8(4b*A5dOST#q4Sx}(*IeuQRIq>(sGQf!0B$^L_n zl)Lz3cqOBu=T;X?DnkUPO=_ga6GncJEVn&0Yj;o%BkZJDSU6};j$Vb^%TR?To3u~` zr4TZu6oK)RP)haf6Edg^Xh=gTr_m5w;T*du#yBrcKUHMGcKO+diuyXmn!d;hjZgix z7{*8Aux!L9)b$g=UNP~~uqUkYuTMweapD(c9W;(hJZp*4tJ2F7Hd{`?6%vtcipH=` zr!N)>qAf2LEI@VrV8%t>j01rM67%Tnh^vf;#BZelTyjN~7mJ4XGW0}YtXM1;lDq#9uMqRRU0(&XL6|Z-=rIXbPye z$gJ1Kof+5`WHOR<=?09}<6y30AooW~Mkad0o=H^rVXu4Kv4c;pA_tVTnEnzzm(GIZ z%Dr7RZP~sy(o6;wSdW)MoEgCZl{KUR{oo7v28jcA6muE$ZW|@Jhmht^%smL{6j?U* zUnzD!PHL@a&&j4GG1B^T@2@7iR=ek7Fe>hAt`%SdAB$U%Js%po=>Go2Sx#9(f_`N( zdScz32Y0r%+)#=}OWd0?#-^gM+^EmIQq?`t?z;1Z@K=F<4Bm=0S);IgJ1}fZ zkj#F2$QT*M%%san8+9V$b+kf@TXSYtdh-6r=7!k?xm z9{C<2Nzoa|SXM+a#MjCFrarhi_PI$lE5UjmK?{E!x%*lTf*=tIpLG2*SB7W=F3K5A zmgv$fI-AUE>ZsZKj8q!O^6w#VF3ymOL-TolRL)rnS{Na{Pz@{29hUo`5({VlJNdKi+ARCxr4A%&ttD5o%_ zot_PQP+MiGF#%K`M|669@C%4Nki~8mIMNTlck!mjtbeHYcyoQ@>COgwmyRW@hVfh- zWFFJ7NuR3>z>NkI<_S4KL$w>ZW+W zM9?N)cx#x3t{{08Zs@@97uMoNX8Mwlve%>DK#3~-9tmGoC=W; zN(C_%0-`m$FoJ^+w?H2PcgQHkA;(kl?c62< zvCc|kvzBv$vd10dy-_Qobera|94~w1f5EKgy}Wn3-01 z@iLv^VHWIF31GR8eBMP7PZkb==f_Jveoj`PB>_;Jwko#^hQGqwzG!0LGRmbRdC1vP z;nko;K~>Ts^s#TwUPO%AAndJ;hG>zMJ+PjRMqSLT6efjl<6T^liHB~-U~%)yR!p6h z5{jBW4~UQ~5lW8qxV6?v`!tR3P!=YL0#>a(K!-!<9%>H9Pzk$gN|xFiOBhxw#*^|Q zj@?FOf2OB*tR_7)Vv{M2oO@sc9gl}jC)YtX{&8E=>XWn@|G1?;{=pxg-}y>^eGam6 zo47O?Gxbk8j)3Y*k7LCkzb)giAGc&2HVO=9$~Xdw0w1V8ACBpMWSit-4P6;wI38Jx zyrk2dzhpZ|4V9H9+4_zdME$DL*%ML-0We!!h(?C?$5Uf0P>{gAIFLchjIZgUsOls~ z-vUK%@8Kq+Qq-{{zH8o3hDC0cJctBtLoI8~hJG7q?VQJ>SsUqoQ8)iXVbYE3Aj)OA zFiLh*E-{;(N*;w27i8g|0NhqApxf^;PJjaftr01ZhZQc zl40gjGs%-~r`M)=y^KvQ@GCZH4+_?n8on?iHa)t3MeA&6m8B1Zp~qJRotDb@g! z|FanY>ycv!@$3 zi#^{xh4Jp2-e5v&MpYWD5wwDXSCRv{QwngA6xdPg4>z`UzhCuo9^vC>!QG99c)MNL z4^P_fdMA?;m@{EPrJD=}#8)D6!cf z^$S2TD&?KIC+%a}py6iZXs*`v`tJ7Q*82Br+tU$%&2l`%am9mIxNid~Kat6nH>bez zJ;2F}eK^>Wb73&ln9@R(jw>SL`R=3NPY33SA2-T2e;SH8l~aw0y~(ptfOa6wU(u=1i&%cI&3N#AU}5$ke!HrKZC$;v@#hxg^X1 z3ryk;D)>0y)v$Rm_j%c9Jv(T)Abm!-oHmrf;9|8u1_(qfeiUvTK0bb?;E(8at_F*x z?wB%LURu98B@Mf8d;J*!teG$@Dm$$3F;k|o{#PRCDta? zDdH6*C6)6L0}>}=G#iSQf@hkhaKj|HJ9s)w1J$b(@{4-c5p7S zSQ3s{c8nYENg0}BI1h{?2sfRMkV?o6<_tj$Wkh<25|<{ljNgZuL}MKHc219X_&bSk zloDV`lM#XmJXRDsw1BKw2-!nyt(EJIHcn2*Snj2G6FbI@&Rp5k!D-wT0kSv~?FW}* zDPt`)#-f6ymcpe&r2cFb(s{Fmz*_wHKpLBCxY8XFV4FoWjcY}NXDr0%spMjcvV=fD znv~2|Y(E=>b4goyT!|S1snd5k&e#|~9$_*GX`OVWEFFvu>8}V2ZtGFJX%l5`VewHq z8Shm9kQ3lWoA$>C1I$3TB~CALPku^zYK*-tu1Oi=}TC|NMUO#TU(&@@{GM8#Zz0!_v~i3d~G0 z5fQW59iA0(r8M2_?E=Kz-G#HvpO4SyFAdt!@V2~+;dak8_C93sN+mKdf^qL4TsEY4 zTa&|D2m+{?!F83h4#U?G0x}B^Gu@>doWnjL#q)H zEOda8wSGsC0)AxeAZjqIriGK&7KOqk?9 zTVR}P`YvjPj=p@!Y_zMApVpQ5>LtRl8(-YIwR-DT+$v#xBtgt*7h{JogxhMv01zdz zi@NV}=Spy{oHX-n4h^RKElF z5d;hrNwCGh5yJ)Y93Y0rH%s&^HlFXUOYD`>7`T+GQOKXEf@g+<|_IxcFFMOkTwC9^4a@A#Fb0-PnG*_PDjR{p^R$he-algQR6o)>_ZE zH%Y=kAMRvmAFr;gV9R;agX5$*!ZD7MwqrSXY{xAYCcGrdL&r|?m+l6s?47ol1iT7a zOmjYYx)JM*_38&%B*0)Kq@)n3DRmT>yh=Foff~|Dyu+BZ5RVj%r=8hdMKN6QMie*U zJJS~IXWW23a`h|rXInOLZ+=LMqm(s!PagKVxKc?Wa_do*op{7=a}xa$bV>QsDQSUONnLbyZYz z6kNdmirS`fOT+UoGM@Xftc7X#rz!Svu5X=KqcwM zvbrkub_dGox4Y0GM!h#k5Uw58f`Wof4qmnf(L(9i%~7{oyc&;BM_}nkC_UNd0il(@B6z?WZVrY= zEA*2#cZAb7ce|r;b7uk(cm)O!T!3#?wvJAb%)>#N&$fBU-}lTLm& z3{>Xl(sz(ycseadHfO}}hjVZ+7h+c;`~W|Kd6_V~e6%at;PujVr9^>m3o8tw3Z`;tG@60IzETsaP4fAtDmPSUnuC^bO4f)ZL#FsM>LzH%J|g4>OO>PhYflOyhTg z3z;Ltxm22QQxuUn@Y!ukXou2(ug}vc;gWM!rqy38FC=QG^Tj#7{kN=zGzW z8a;h!Fa;5v^@Ca;z8ObUnjgJD&&&vC)cNr{B*X-rBkqt@JK{BAdM(&@{Y=SLs*Kve zD&gLsPWImjVG;SIyMH{)j~|>(C62i<|Mp=%JUOvCg*aHnG;huhHW_PB&XQ735q^HE z-NQZm=g`#^Sxy$@3_#t={kj$tnP$|aPBbAT7=D2pSc4(^W+(<4qC!aN*H zxUG+882wP7R*=Wz^v|dPm2BWo=-Q?;ALME_!B31h8P!&FMlU-lp*3(Ws(Si?RA2@B z9QXn66pW;$fKW_?5-BNP2`{2sp1C2qqYeUdiq?M#($Ql5**TLG-2Ubv5O!4JUH&y# z0}pnUCQq>DONC(s3U#Z{7XoLKwmwATVl!cj0#`Ii##a*X$}5&I0klvo=g3!p?}b1Y zAHodKRi!$5H5|OvgZ39hJJgdeJ7{nPtrnkC62|g_P^GDN;F74JY!}B=QxMWucTQMjs0=R6e-tHpJe&0h2=3L~!-eedpHE$}+xPYZIz>O!|rn>KtsKKDg zATABXzc-mehctC4(KaHwr4){^Tnjo#LKO%_KGF;oqse~ID|oGy$dL}u9=OyJk9O>h zFEBgw*;;YJNQ1qLW&*ZPCz8XVfa<-QVF~1=t^%#nc(kqnxmzIu{Ea9phKsl1 zHm_%jB(|$MGY4!_dzdpdq2eg13+P$f2elwx+P{kpsWi}7=r3;mLG&)L(}i`TH^3sg z0f~gS5MY8k-4RlbbeQ1Hw*#uy8<2Z_*jjoZ)g%ybXDpW$f7c%3mhs~2x7~eMYfeti z^4uM5gAXZvVL2(Lf-Cm7+#(tRg&ZBpp%qC!OzDo-bLCSPa)Q_!mtw=4d|^d~HEGO~ zM&)H)WrlN|KN!IdAtra7Ynr~JiBU^+6yHeDK%aJ`yi3_mAVOHtUn&u@6lwtqvo8 zh~>^#Vd3`Q4mxK>xYL{sRie-}XGwQzZv*DO;}!!$%2q6BG3)I<_p33CX=12_RN6(7 zT_hv&^(e8z`#IuzC@zvXt($YRy0vM)wYNj@D5Ff$=V zfI~mMC4MOK6ha!3Xd#9ZyxpFnsUJ1A z6k-I+6%-W7$$R-VWljzF`?Y65)?vhnMmDH|YkDaD)iB zi2So;K@PG)))=RbGM%7Z`*5DOJd|z9Af;m1qoP=d`IW_QR`-T`{Uro_EH2+b*vH8T zDINWw@m1mo%7}`FM$3Yf@_`QJRetGV+Gu?cP${FAO;VF`0y5;b$<>+CO9(98%ry_8vNxepe!K(i{M&_5_71G z*B)udNGp#ER78dMQM&G5#f?7XznYu?SC=lR6tt-AAE?*}lit;Z3>tsF^AhOjEF>3<-asS1r-=TrB>EKL#>0nC%K?1$uLd1FKOP*kc?k&o&VD1{NM*NRz|Y%1o80 zxL8B53mgdlte*>%4mN`#>Vc9BmGee&^98j#7yw5DBGW~qAXD*S`!&K^P6f{n9|>+N z_wJODMT_IA5}}CdAQq8qMumui+is10uTK>$=(qg9+-iM&3Rx*j{a2EdQt)!^Dfq%1 z{PfW4_k0}-_fSdQHdGPmTLnT69%chnfCx+qP2c99fp8`F0cWujs zWNi6n*5r~$X$#)#8&X{UaX~@tgOjdAG+8$*2=YOQ$Mr_Rs|gzC1@e>^AL#Czr7}Dj zU@IfkuCBb~q)CNa`=s#VM-WA)T?isIH|UIN;?2f9}67wm)9$+)Ho>ku~fxl$PR$*ku2OQ_(+9{3?NEd(W{5jWGisVxbBST(XLtSWSAn!jZV7b*-Hm zT-Cn#R8*m9{NI?;%fd>SRv}A`;q(tn{;a5wC*81SAkr&+38&i8*a|G2D=iq^<)aQ` zk8||c!%<#BTR5W#YFBR>79d0O5OR-OANru46R7y`B)M(Zs3hNgCys-L&D)5pLL|s& z8M{2K>S!X@DIoVb(`)1XUltc%{AG3Jo9i#XSX#v~#+4QP=Fb~T`1Rs1@@;XCU+vj- z+P9a!dC%;~Xx)p!CWDaKW9xMT#D*`hx>GWI&F$?g*nsUIx*EoFDLQS#8c{s44f`}i z7U)8N6cN&FzIR@h1Hc-3BS&w1Ci0?{{IaSf1MZ~7xXrI#CY@6pv`^53II!PcVqh;C zf17lNXAKDoR&(|5q9cxJ!+*F`!-p0b8n^w2q-_tskyM26I&tY+p2v4I?KKH^Ym@{s ziBV-18aF91P>RA+qV$>AXkRY-)B7u8>dQ%=1WOGd^!mb4ke>L23C-h0rWZ#gDsG%$y4(wdb{WK@qh&u{4w;yDkVgU=`Ot=65PvYCU`yu#x_!tUlW`XhN-vIeNj9(aD8Bz5vGLYo#*R3erO??=4Hv!1Bt{jinnRO~rjjVwD@sLVt4d7!irb z&rgX`J9468!>yM~#mZfTN8b)W3tx=t+()l+S0c_-n~&JT3I+u z&KR<#%SKCUUcfKmcyaNYudnSbFA0W8=7L{oAdqU!{H&}<1wpda@GHt~nS5S{;mpy1 z-L(c27v2TpFL^{8rGfh?lRP99(nAh(SvD|Qjm-c5ex@$4!^~UZH!*ihhpO%6jQu5B zK&Z(Rp{2~~Q_6D#t-RZ!R0pgtj(UES2AEt_To|W$O1zn%s?v7J9!Hk|Wvkhm@b+}z zS8P=`e1Q8%?QHeNkli!Hh7@bB>5usOum{Ul|G{u_g5Px0#4)@vEU_`97S6IoL@tz6 zweLy$l-Gwcx)_oDeK0bnwRD`!`8a$)a8!mhok_tjD|n_!S?a@w3!g#GXr8(#&6UBc zWm_pYKRxTCZ)y*!FW!1__sf?{?qE2q9pYrNYd=wqSCHD<_^f+V&$%z$UglXd)g|5j z5g8H%74-VOkMZis#JE%m50l7x3oNMHPzvX53!2~S85)04nKfHTeE;#FZRs_#-V)E! zI!=i*PF33TvAa=k-%XIp9zG%_xZvHZlDyuGq&&7DegbB)hv0!TH#G-pDzT8JZt=h; zLba2P>@U?oE9lGHMnM+;{>{K2ol4|j9~}jM*I{pX;yI8gmVSj|uSW+J{NFptfGQU8 zHRRYTU4C{D!=sP@t8QdDOCnEONgM-x|JX&2oZ>Ccy7W5z##qkXLi_0T-!NllP(BP1 zI_R*$MuL^}+INRfqi&IOL>#!Dp;S2NuzlmIAP8WxV1@D#P+u)f*Y=(SC?SUF&RvaB z;+m{jktNZ8W##*|_5c1ODULU-A44S_7W>1&YaB$d@yL-G<0lD9O6ee#PEaPuyq2iD zZZq=YZ$nS%2$_G*h(quiL>xiJnTA5=1}h7MbT6pA*war&%$tXZ)kXp{_`kd#2FcgD zV~UXO6jZiRdFQ{RsBz0e34|xM5tXKV!eWw27P!jAY3)?6BKS4pN_KqU+@m@ne3h5t zMN^_D=NrtLWvYv8u*hp!Np?D1XWEH7)8ggHFhv`96{}4>wwcdR*%`%|_kocrbYF0;$w^14Tv> zq?|>KkpF^r;RK5{f(P1PV?1bx-q6rD4OboeWNFfsy;>7;#M;D%*so%%%x&1Y83XvW zMVAX889hHR!$z%8mY27AH1J}O+K0>%^0s{p;f4CrTf?=R1_%X6Q81Nkhw4JIq!NqK z;APlN;z|G03N@HD9?z}AX1D#lRRJAJ zDdjEdGX50RM5`StSPo9ZqO33H=wx2c{p@sXyJxDMWv_9fcYz6aiC-!fpF znnVPxtVm5!5b0JNOvc4^#|i^b?co+?Qmihab>VDsG>!29gd`$Il{_RbgjJ3gL5c1x zg+x`+bothdH255>i3pTv$|2uVsy@?bnUX>bgb?m9Njc|9dRKYMPbiWS@o-j(hN$m| zKXJyic2EwJ>K^j|_&F4AiX5^Bn@B`3y+>FFcs_;>)y3mGhG**nwtCN=K*+|E_4@k$rZODCxkH9(4BbMhn%} z1lpKx8mL%jDe03IT1pEz?rI>RqlCb@o}vpI5%i&lpD<9V4QLU$9ABg)}jDL7zTx!rM8Gn>~V{#(0;@{B(J9M#x2kHSsmmZ?G-UVN=>b0!F!U=yqZ{3=kS^)?$2MnNXu5mWxwZF^3|Qb!qts zwK0P@F1#p5pWxqOqLJ`21V)x7+U;ThFUVLC6-nsE`adIF4HIePGQ$W)8BpU+dbz9tpO0u)MMm&rT4)zrt%sZ2trksOE6dCJADn!C5WX|FNIW0-w+&wj zp%qx!g7GxR;mRCNcyx!712p16UWX_LLtJ84ljSB8%WpGmZ4y}E>;zZa-$FNGC#=?? zrf+utwkMh{O%Zu0P!&mN8DYC6Qw~Ie_KBTj6N(U?BHv;+SePy+8&y$*v2gq2)#nPg znln>a(K;G%<`b|2@CiqACh`0`6G0Zywm$pKR&mkry%Zr9BHb)30c8(+NB(iCg4$>- z2XP?NwTNROkB7T}D?3iQJwW=#G4mMzzyI4uY``%xJ9cr++QF;AgQLOV2!6kI@7M*0 z`76`E9Zujh*@6uX?&|F>d?;V<^U?C@@({n$gsD8jDP zdV}08yR9{@wf6XNTHJoI)+76<_!8H8_-y_8lZ~gltsmANZ$4bx-F)^`>P3B7_;y^& zMwr#X(X;^J9WyaS;+r86k^_xyYLLe5ZSA6c#OwoVi&NZ0MrnkR^qubuFfdU8z3FTM zd>*%yIti=zc7T9tK4)qh;~O+?^O0*7(F?qd2-*Gce1JSW;B49qqx0Ho&otXOvhN&w zd-yIIdBeCSi83m91rHz#$$JnP9reRlh`|V?3i+rygvd4Q_#M(A(s^N#85%Uv9vuahqLry)?; zCw{{wd+_=RT?o}WBxJ}FCfgZJfO1zGDN?;Yb5v!<>W4m|84+c|O%uWdQ0v06;i z3Cy@mu9v%kC|W&Gd97OI{AV1_pgY7do}6u7Z9vF9>}8_WRot_={@<-9&mL~H)}L)` zuWv{e-yKXi$&YI8`8h6GYax;qlY(q;oe!8m|>(`6#9zXkb z?QyZSw!QXb1J{4ypHR+* z#6@FW(Sa7MQZrQ@iBdV%6E4fepCCeZpo)w&P8chW8YI~`u9qlAxX1CPh?$5aW@Q{^ zp{(m#M)COslz9=}(W^+mYz7<~w?IN1MHEP!Dhc3g-Z2(B98g>#kjd~#rBdxi@#Jjh ze;zZke2h|%`fuQWJ6#NXT;Mi2d*J5|Q;2cnbmd|1ot9nuc4upC_j_ya!Evwu+FxzS zV3>Eykm@_AF&ZuNe#nhZk3F@L(Ye~r<`&P)3Qjw%6gP56`DA5K+Ro08&$b`BW>~J=%&Wm@Tm``Q&vtfQO_qsk`Z-&F#Xtinf=YtmTT0f9 zo_3g$c^xh1(5-*Jw!O3AyFjc3TZ(%j?n6(YHe4JlXEK(HheG|R)5ne2LfVk*(K`>d zj>}y=d;EB9*U!j-HWhV6awA8C>Sm`>isvH475@!7mF2P1hT`g01ct30BXKLo-sv5R z&3#;`><5K*2zE5O#)i3C8Po3^KwPM(rk7*jdvTspcKfuK(KRlp$C_zk&8*yBzP$o9 zb&SJ2jw_P%vB+Ezd>y{Q;b!pp(6`4Fdxpx2OMeTAw+#yt@034^ zi~uQB7&N8DxCWZ&zJqhF3Aq6c09jZ@ZDx_i>VZKB_m&jM2FHEtTJb$1c+ZM`(jk5e zACq0k`)lZ1<5DHt2>9;whB!0^tB2H}jib2cl2l_uvTYRL6-#rU`Gw;i-vs-TEoiZ5 zwH|Fg-hkU~NgQ`!$JycOFr;A)eZpp?j1epQc!KN3MQl+vKkWW(0+3o<8-;bl2C*+Y zVSpkK5PV&Eiby<^ParvggC3rd?Qo3P<@t3q#u;OI8#pbI2Ax}&^X9{i5!%v6CS!ps z&f!^rcwO6qtc)AHpbF!q9N@)iK^nd?o=akZbl&ga%;)PBg`-I`ht!4OK&1sF!$9}B zxfeHH&e;xzXOr<^^Y?Q&tkoJEwjj08gz}p*X0ltru7RUr@ zIR%(kkl{vhfAY+<{C)px5@ke}r5pc=9EHILCouB+niX4{qL&v%~mvc5?jT zr7vsMrD^|A8@R&;ZY+=AjcA_k4ziaDlCQGGYkX1%OUl{qOqB!ViNSN+sAD|#i%vUzC%iAC^rdIurNoep5# zqu~k?N+Ey#8!BP1=H|foUK9)0i{|mTxLdrGv%USf&${qC74s8bIJ8b?>z4Hl(IXxr6@8d9?oyG5NRW4tsNRCi>r7 zxXrH=;qNWn;a7^{_ZIH*E9L5Y3+G=pW!n(RdhW-q)(^1Lz?6YEUo}a$5V+@d{(Ez) zg(~ataP4m3)o+`U6CK+KYV2<8?Cvnk0x#m9&6V-V>B?KD88z9~sEG^MKCssMGYCt* zlKYj_SwRmx{m9ULPho=I{{z;9;|jcU>Hl~Xb6)u2)1o;l<`-_y7x(e!&b%7CaJ-sx zW0l{6K+2W*v}j^7o6n@Cv?5au%mN;^fawjWD(?NGcyX)whnHXME$d$-MA9!y-xM$X z{CnK&u6=iJe%wA9twgQN&na+O(~t%Fy`xv-V`O@K|32*&@4&PBuN(E9@HJZ=b>}|Q zZAQd$h#xo#3=R(_KA_5g)A+bF5(0^CMXrz&i4ZSWP_Od>4(njO&p=O~RS`wjpR8yqx6ST5kRN><$H%ZO$bwKni)Kei!!0AfB0l>}P2hi=V{dbx zoxBDYESjfDX*{nW>dR7IXggc?M!y(%LNX)BJDxd+*~AJq_a!rDc3;mPX@KwDE}DOTcXF6v$+gy8&u}AzSt5;L`|a`(PD@Vq<&uSy_VD%K zRk!z7bg_aB@#Jjux8oiJW?YLiT)9zq7g*`(N zy{1|z?V95Yev6KXthz2nShqREZv|>6OK#nk1qSe_k zkTo3XHP~ljEXu@a~jh@=PK$vur8_#lq_9JodcLxEU@O^%Zzkr;v|^2P=)$M%*5L&(Ao9td|v-R4}O1@fpXfhH45U zD+>@gX~ACkn1-EQ+qXz*_@i2MW^Ugih3c!e_})w3?-$NZD*y0)#sQNvP$D&^*4d9m zf`#)`Z2th|e4aW!1Q@^5n1lS5=Q7a$V3{>Q#L_{=s8?bgyvC~cK}4fD<7V*h?(W=M z^x&_o?5(a8A3#sa&8#ubBs2smjnt(dAd>j^JI~;uMgZFuA`*O=+fkW~|HT!z_vYtS zRJn$A3dxN0K`n+Y7cUDxC|SpjJ~J}e+HQ$WjS)*pBs z6{CAePt7J#BF~bR@f`O!4Pe#3H$FHOL67Q21Z+|~0yye!ge#Z3<;JU8s~URLQYGLS zfFK~Zy@)0mOq~!Fxx=rjwmHmw26NXKl12LzsuGHhR{R5Q^}q*1NhYV?9S`=~$D@1mqLAV- z&<|@IDv{Fpvkzh1f?jq9KGL*Q0%3G;R*a?<`LR7@1YvcV`*WXtEr4=g9^qH?lfORu z+S?z@x2OYa&Lh(85U$31^D?me%eGB^jkJ7bPL;TQV)+U=?M8vBK}zTblT zXbj=Sa4EJ?Se$9M_QC%!&xorZb|N_q0GkwT(sK*2%>ePVn}BsdD~5#w)|_~k67vyg zoOa&0IE_J{#Sb72WdgOdO=|$Gui#;De||@+dK;He!@*9|vUE=C7p$@n^1$1iJ!*L_ zvFyej(Q4!c3s-(b%+ic5F{N;Q%8iH6W@%Rt`>tXDQJoa6*fTCc6fC$Vik4oJczo7k zrIuDu;n9Ez=Ig3$Qw>@k*J`pdxIWC423s^vCfdhHI+RRojY=TQI*z*?A&;w!NUQvo z7ZovYz2TtGfKZRQWV#Zhd15i(mLKl47%kX^2^CI_(K41PW$WYKvhZ(OcIW!=g11fv z9h|5dt<2q62J67Tsz2Zhbul?3Fi!z_ezlm-5HU~lThPIad9i}(Q{FPdD&N7FF{Xtc z76W}lui9XkG^dX~e9!_A%pP`6ArB#GBRq#FsYc5ABeung|G2gMfj8UV;+cv+gg z+rO7S@%pRfTcy{qlypwI&GDc~y@c|hv<1U03S%S;s^SquKT0)1^H}2CI+T)OZ+}9k z!D_K6PGiIf(NG{k#m7j-NiVMh9*fj~ZAwQ(-HUnBqh0TVBz*@>>Vq9xANUb5mpL>?e>n3lAkhTa1v_Hg9usj{ zfJ@N7=KT?HzS0kAMlmDu4q(BNrkRm<%6qwiX4WM?z&$`(xL5IR=sEwII}PAwjiJLd zCuF+;RxbmnTyMI;(Z2(Q`fj~tG>VSn$o5%KE4Gb%pzodldgLWS%K!zQk`9;o{?ov$ z`<0mFnhHg-lgEjV$RnR7ET%yAXLDpQGD9j>_QYm>zLa!n2z|gdM_wZ|YR^&LwuKgw zbj=R}WVjj$mP~e~%_iT|4JMXpHvS%)z^&W_;=j7sL)Wh)3P}7TKoBX}&+DV%e&r~U z%yz$uq0BKby0~7n7``P)FNr%bggG1#L>(}5Fi~G>LmC%)$TyS16-e#Q#xW;kAC6gV z*DW~6u)e9;<$_A9XyLj?oG#DJCq;>3I&9|@Z>e2kxT zrfePXSGWK*wlR1Qei2Q~DTqOE#wM_)DA%m*F#)8Ajlga)n1I<0K{Eu6xU+oI=rGwu zLE&wnNkabSUE>bKNAuFKJHvnngn%dw?WJQOFzeM_1Brl93<*9lYZ!eXVbM{MD-?Gd zV^k`|g?jGEX^|-tNt-09jdL3yQUm>%Ismo{CaxoLMYb%gjxZih4V%$>qW^lH92FFO z0Q37RZ_Esl#PIzpw(?iI0+lyf0}WU*3H2d^vh4(znWIwLrmexlsooWsU;*nbU};NG zS`*G<^m&0QS2%uUA`6x-tlaN-Pt0)taR9Fe#BezN_T#VgJp)l;GG4QdiWB<{$O7ES z>oLx+2$xYtaT#_0!67^Fo;~45OSQcT$#9&^+<(9Y$OwR%t@r#?7zl{3uwOqoY6KJ< zn)`Evf3;SBbFi<(C+1UZ5W)(lE&AvO#M-QS;CBWPzu083Xq{mQ_MBkplGkDIyGA)Z z6eh!=f(bG|fAl=PU(Aeuj286&p79T3*#C>2#xSI3HD~x1z9chNxdfN2=WqeM$$7>) zKtlQS;{1TE8Yt@QT5DpUGl~SiO4OM?C47S^*q4X{vJEBKdZvIb_%n4-q#3?APmVZx zFqzixL1g&ckb>T}UM%-l04@B1M&L`P&R1*p>EunHcaVq!2N#xi&*+&P=u#5*?a?mG!wVm}Xi(pFIOrbMDX_ z9Ee>cHWB_A2-#t&XmH)yTR4aTo$!ecA$6eg!lpMl@)gLd_7G~E)lo2*Y!MBh$7u_` zpFBPdww9|_MB_L#!S#nR1e9gkqy)IVjC0)qlK6$9zCg6W78BP(WSgAb;Qj-wKx{Tk z@(xRliO4vTzKso;^?Ll~p)UZ+u6GplpgZra$;8qpT0zya2o{LhGUlwZ7Dj%s$qit) zR?>rslo<|xdO)zl%_=!ViqU`ykmR`yLkiG2x+WXw1|Fbd*Kp^y8*euJxE{SL|or-SdXm?10_tV=HEk;fsEUJ2@dvIxR2?}fOC{&C4nS9-?- zKxO6Vw|3ZPP|5YYzk$u8_wW}cjxmN3-G~i9=j9_1*a4o|9To!1HvgBOrb1Rj$PHfq z@+9fQ4do(1Uk+}LYrzc?lo-(yVC=EKH{V#|HeByOO%ZC_gYI$iH0y0#0OS$asWmK; zTqtz$ff%by>@xj(5Yr_5yk~3%VH8ri!{3m_UCil9FcsKz3;z~V&f^G}Y44x{w|Zfp zupoA@Dddoc^W+Qz-2k|6cE-ys7xRGhQY5{!K~S*qlkNxUN6<@%$-^~xFKYiCY%mA| z8m=L{#CTCA06Roy{`Na)V<8=X_Z_yzq}devfT&i)C^!t<54y1=-2xw>OHk}fZ6r%+ z>L@c$KGHk9RS#(@?f8dGsfCNThA>ZBN?zRd+$r6A=zG@Ce|;p~Ck+%uYbbuCZ>Xnl zp!$@B?~6%-Sf@|)$_0J+cE$vD_7I+LKpv)%_#3RV#B+EPK$8nPL~(+6s4cQc4Fua9(CChJ|utZ zD6}>M-oz!soLCr66>1wOOZY3gGF;tsrLm?L^v}{)U23l3^I`z!^;RDdN)Hc1RBmBj zh+O9izeDcfhx36`1yC;dQ`=1@8N*W zd@}7zhmQ7pG6K9KbLoG7;o^w|$P+!uNPX%n2PB4<#_s$2*W`)H=eHb{0~y_qporiAl0` zc`+me+STzR0w&H4>|e7j9)j(?c>S&mXrQO-M+Bvqztd6C7Kt^2UE7#n*?XkNA1N^P zvPTh6%==)C&_B3~2@1GqIgNcZ=@gMWrX22|*umoD|xgkOz2-*Vg9^Zjp`nyrfiUXx$<`n}^@@hf6i zU<5UoeHtY?uml(&zxj62V|8N@LCS2ZAFaRfDK%n_<=fLlWtKaL5ng$KK+qZ zp9D`*0dPSp?9j|fkj@H56v#^yt#N=fi?j032O?P>kuP-234}#$!0VCH5Iz01g~$#R z+ui)|@Uaa7J$`TupfLR5;m_-bA1|@qUtO&q?_d_>eSj4OtigoVWvv;fMu6j`$U{)AT6!gG1DBN z6zwgh#ZDtAf^j;c^+$$2-XlBCZ1Wdbdavg2Jx5{`hUNHhMrc8r_A3y=P$t4DIE;Kz zmS*as}!IaDT%eh!%_my=}uu(#!ooConX?Y~LRXLvbGU^8{34j`0r*_@Z(u@0E3X zu!+AG13`c)01u`o%0@q7Su5_4Esh1jLf#XNYy%Mr`E&_sF<&q#`$j^x?Mi{S5#q;N z1h2b7_tj)?W$zaS8=HW1=8~_v`~*44*4hjTnY9s<|fj+KO zWIi_cxIJ-gXzg<PWQnfJ5&hye!(xW81!{$F$>w)6qGf2O9HE!_;ifYzV(0p@Q=?D#L~kl&wwu_d=4 zJHWT5XADmWfG}l+4P0s*$T1E7$`+CwJt0(w z`i82)Ts||HlF<$QvV40#JWzlQn*n)N{`mA)7yBuOER)L_TPS=aup}}AfHB5QnL^t( zfZ5%eI>VT~1Iy5ZP$5c*H2d*8*G1UCcYk$Vx48S!4))#o%5|^#UtQ+W{wSH^GNr1- za(Ko{)0gFgBY*^8UN2tRLL+z+dvwbO$8#|&%&L#3BEb8)B~MvfK+Zs9`bg#x!bq<9 z5V{eoY)&63Lq2>DyYm3+*Y@SGx1x={A3u}Zf zfW}e2z^lcqrjEx||1#+KG9;ZA?;tu1#n*6#cp^4uiVL9**H3u97hWoC49B*Oc##xkS;B{El4 z3$L?S2>3vu1>52Y=3JCaKdg5k2eorLId%*r9-r{fQfgU?U7Hjnc4K1t!{P#P- zS?wM?i`ZKLuhbc?ItZDfAT4o=dBzp%FLD!-?7>x%$-(n>CUic5l1jGU+4LorAchjX zvey@X@do&!vlid--}sAju?)KF7r|ugl1Us-UPPAN4=fW^3s_p>KT+yymID_eDMhg2 zyjU7a2lFqZq$8A4qDx`6D;6*H(Z$-iD6Ny$K%&@>FIVV-hO;KcnYU?6WQa?C~L0m$>VXk zG-&`uVEl>UQqWy6b)da0(;X82^B7Lfg0MH+87q4cMP`3OUN>D*zEVC(%9O(MrJRWg zUmG0|xvL^vlWi9NlL7^R-QgMfXa*|rc@Zaa<|^2Le1VjE5J_w{kC1POTS7D;?gQc? zrk&MsfhZZ4)WflWFE~Ft*smrIqwAoVwNJf^Jtl;=Vw z2K0)U5;1=KEoiBPbrIqDfS-XU-v^cvnBaCeWjV?=s9W4ZCTCj72Qzkz#sXE z;a!m4u@v3(y*XR)8zXL)g9Tq3jCIIw?q>|fBT=7v2hNfHaF%cp{SQjbZ1d7L??~Du z5bSIa9sCUt35fm-YHLX0?;sZaJcCo)U;m6!cw^&f06)J4_Qmn%AKCLLvRSWKSl9c` zUsx;F^^=gRpEmPu>-hfRh=1@_HNVoyZ;)sQxqymHyzuEoI4I?(r^+$No*A2yD<{h% z`9y=cex`aqWSuK;KU4BfK4{(dV6S*>Q^!J|mJAQ+Cf8Z;AqA^jwsMVzcThOW7 zaXfP`fyn_v{Ml)ZVr60Q;MxMp=}v!rV}B11g7crIOUO6>WM&dm(~H%7i3`c54y&G!Dex{T4EH1*RHutqTL_42ZUHSqxa&EZ{Att>)i(j%=;7$OtEiB z*JBRCH-ZmEX+0Nngxs<{yzKXSKlpZW|HyY|=SXgSLUJDXR>pCZ7}fHAw8fIM&Hv^b z3`UJezP;CQ4u=;uQEHgPSkB0QU^ zbY5x455^v+ZU0KBh^Tw?PBv=*%unwwt^t9Nd4BJHVK!DiwX2W$NbK{wfW^NR>p~r! z$rE|=_YrVF$cEi-2{}y{u4n5B&-vjWv<`!ivv-UNT$K! zQa?Cmh~MMY=<&3VRIYIMM?g4>aRHYCj~4h9uns6Rk$(?Vj-YUSCUxLJ#e^%NLx8nZ zv@v-y8u0N(bYmY%5WIm<5A=nZhe3QyRKyW_^04_b(fb2=X^Y%_HhF^44{D1f-RvJ^ zo#)!VBJ{CAIens@t~)x*XvmlRlHm1BKgdc`O_igmAMoB3d(FvndU6@;YK0he+mnQ1kR6wNc_z;#S^6vPbGeZQ8WzW(MrMrIn8bUr_r|)lve8FHht(A`y-MhmWl zr|4-b4FwBOh3h0GO14$6VNxOrYtJZdh{9S*9H{Um0?V)vB&At^iDeE7R zBN54&-_uQCI-EyZ3LOko6W?L5v*y^v-jnRj-0>)83|Y;PH|g7RPxuB&oP=plEDl_) zL0-ymQiR-2kURj%E-e4 z(Tm*Yn9u?DLLsY;c~EOgz(JsZhz5T0lv@Do6d3383;;F4m(Usw8*HZJB~}{p!VC$k z(TpSq>>Jy;J9{9GfWs?9EOGhJ%X1?$u;rV2137TfheP{&*xRr68zRm#W8vmuFdIvQ z`P0R?{Q|1s^&!-` z;I|B&5Q2A2k6Th<+7jb(?I}yvfPA>{I!CSpmnZ1)N@qA@!1(Te_*XDj4k;I!ITN9KU1+wb`c{;j~C*qyVk53aig5P0VZ6HTK{LC*O z+QA+fvh4^(oW1qI<4^Kqv-NoT_-51sNF@{J8*t0F(0vlNfRGAKoM8?K(tvX7_MNAJ zbH(+(z(yAXU7;iEL+X}|0>lFN1}eE2lsXld*ZRiH0>@CEIf%GDh%>do{S)wx^^Mqi z^NL_L0`1~JDV)~YIyi_B9CK8_Qnq3~R%zdau~wZ1e#Fn;{W@9 z|BL%!|AyVyOJ!OPH3l6rI4|%+v+o^g=o^L(g^JO%W^+j@-~}bd0+EFhjnb`vTSWQ+ zBzs2At3DaLaeW}~;=%*Zz<^3srl8}%2lF;%w;-K!3p%vLQDPAs=tcyVGc_-qbLSn( zV$g+A#}-F!8rYGvt><_sTcPM|kS;h+q_Sk{c=3v%QA)5y&SIoy#GEOy0olQ64kD=z zyX8D`o9XOHt+X=&p|vS-y)WIWDjlUNZ(x^R&)J9+ z_fEag%+G1hprC}h2dWIM~nWGWIU z!xecNSj)lc=o;bRhj26|(V51(UMAwz^`weww{g8DmsCfp>?oA-Rn+QRD2hAXsEoJM9;F4%BJ+j_fkBi=cvzkz67fxrNvD}sS>ZF zP$?DiWfjB6&}}Z2ib|NKdzy@Li!yl!^q-59^HQAm7!;U z5@{SsElQsixUEb)CdDN^<^|xzQz!!&7`G-+y#q!!JddOqlR#4agGryd`1mIW&v5zu zRW^`cczKxzFzV+%crHrTg*m136ZTZhh%WfdFlR(>=-)-Uk@ISpSC1XXAnOD9%diYj zu6LBb28{m`_wb;8prWQ9^zXqO@M;=1w6L9F18MU$$+qVv>?sW@%|?;0FW;pe{ueW zoSRr`6wm=mt3motl8HEGV#tN}%`yrSCfv-QuDA1Qv#m|J*dG=Y`3TJ@Hsa-7im5;u zQIsc%eV}Ydl%a1HqH`Jv!Joj;K%`_TB9cd=!y%O=k>nj#z-EGXxyT@ozfn1J4sMowL-E%X z-`lcOe%7vC!q3&VU2Xdr7#Tobe)<5{GcaXh4{a}>foEZ?xIHZ~ER$ufL4ie$+{fkZfVpLbktzrgp? z?w`!B*mA6@-!P2uV)W3tkdN;A8Azdc#4j{^oG4XxWbu+Li`BaZ{yl2iV~mx+J^$rM zCO>G}hjRHHlhw~Jbn&9eupxH;nQ5Ec-m^3R$pQz*0|#}J5)p*aziYtA@&vt%ilCGw zur64x)e7mgz$lxev6s(nBs8(Oq~}!2d>9P$EeH?h`S2&W!2(-z-jEcxthojHc64hJ z)@N6DNvf@pYx;J;{8TR2439^F_7|Fye)`rl_`?$bVX#IhOyf)JA%y$)r0ApHH}g5PDeG zcA5K8GCj`M-B&^^L*rkB%BU%#nduNg;IEkRXM|S^bK*T^E_@_j3QDh==~xW~sRM!S z8NJojI94;;>7g&saTwTm*Q5wSB2tzomqZqGWN0gqos=nopcmr-FT`216sPY4u=61c z|Cxam1KC&(@d#yFd&s_N#j6ZnUkvJIkjw5H7n4Fdb4oNtVwq*3wnRF>6oWWawxL4y z^D$#;S!N`T7wIcfy_-`6`vDR0Z7U-M03s+@eR<~h`|8r{Or%LOueeBS+wL5hc`Kl| z1gFN8-96aWYTA7%48}?i3{Fs4cEL5HHF#}3QRO&$?MO|-QRzHz-~~0 z(a%^J{$T5+w8K9?{PT@_L<-3M@e%4IbM~+9(Zi=5zjfE3&YbVziwyrjxY6@mvRF4) zXnkb*G_nTRy4ls9Z2vtQ4yYv=GF*DQkt8~qC7r2 z;WzGuNXk{34cs5;NU+7sO`8oz7H3L)j8d`on?*qU#!WTNPq?eBNY<^0U_p_<5BG#~ ztI-vx$(93vHGm0L?CzW`W)7sLNB&?YnJr+tXUU8qn^O^7`^tX$`2ipO4Bhb0Ou@K5 z|N8U8FW1P?n%48W1FMNx-aSrVG&*zq){{$YOpj@Th-P@4lN9wjh~DLQMfcZ&plnG? z+#{9oTa;FTkIAf;Y+URz%!SxbEQ|XuJ8%Wh`;A-p^TS_RqaWD~yj=%d%bO)7YsO!6 zA1T1*Ywsh*e8WDX6$PsN8|@=I?5_xqw2!#TycEGR(D-F`kUyC}G~>*^!j3?60$78+Wn=*E-;B(n zJ_Zt5GX{7<1wh~{%c62jGb_v%qz5F5p;Gh?6D5dr;D0S*#>}knNGHv@!(+0EAP(3RY3gk}YK%1_{gdHV~Rsex^S^5Tp?E(Bk&;ayjehka3Io zm)n9<*hIvkwWtmsQl!H~@y4U*v?y-k^;39Ooz6(Z4XG#S!2%e>6WoCNWuTAW1^h%& z<%&XH9H|-Ol;H#JWQ+~+w@^(9c-N5Kigy8ErIRqfed4pW0Uj953Ak6PYeHN%>&xs1 z=gFBQV%j!j3TJ_z>m$7Brw(%#j8BCY*NpFZ8>3F?%HBfOKWXoPC&cQYLVUmf2FeuM%Z5fnJ=ybgk2hC2f5Ln;AMPI2)A z#l1M=C<>(79zz`Y;>^&C%V4)j=&!LQKUtFnn+vgNy(TNw!!yzy`x@N!JqtFyyZ(3X z{8|Nj-ID&c)Uq$av;E6!mQ@Gnip{5AIOH+3sSpg%Ed;8hTSz*B+goVw{0>pKzdmo) z*IS!7pMQOAH!O@;+O60@Z*HI7*&SG#;FkMHd;B`fV^=8%3j7SzU7s?m#02C|i81=b zN&q5JJe;T;Lo^p>4BY@KJVuwM1>GycxKNoVPX+9@} z-D6Jp07I7BoEgbz4T88|FMtMN>@9v;DhY>yupvlH+z-mMxc$r~LT$wWNL#{`hbU1w zaMU=RU^Jxy;zEKpWG=4xcr*AyU)5=?x{qev-{*J9)b`sC{1YVyI&g6xdA&RUDT21T zOqmJ35mhaDmI`1YI~&BM1#+3Vv_+BvP{8&}GF z4W_LHljq4s%Cx>;`h>7reuoJD2+2^0fNlQg#R5t2&?<(SxpI}nec=&BCf6>UJ*Q(#NsFYa z8^nd9;G4BMEKZoV*k)8&n}(MwewhK^8@GkCZjanP{JPG^bU=RN-L=g5X7{v8w%(br zKqDXy>V2UEVQ7tZCo$Y4w{2KDpc{fw5L*Nt|8{Y86}WYuQUL<&{%H1mN&^G`BTBh) zH!$c%8SrU%F=jI$GL&Gm9@>ykUWO_S+fLSf1cjh%Fvl}3mS%|ICzE-nNM=R{STXe$ zuM|WY5wb0U#uDh6nj_S!=ZktfjKOmIyTBM(m7jqzGY|=&mPMoI;ma~Q|3Umk%-Vrw z+KAV&`HQOfYj#7&DGTLl@Na; z@%3^krje0h(l;yvHlKR{e!;e#wdyu)`U6n(s&#WRLUH+%74q=Lc#d<)an>IJ1Z8CaHv@q8BxY&L=IhIinPoi|;x~c)=$!-M6a)rl zkTpWIxmPUcI&1Jre%pkdtUa^ulHiAKH|p6i6UJnoZ9eyUqlBinJqkCYyOy=ddUR$ zuvo7i-8bvFAsTnrW3{^Cr3INi`&klYS_3|?7F!4np?YDZWr3FDrD%d0XG$QYL&?RX zY7pDbBSx5~AB)^3n>X}%EOO+MLw|;GIB#*`<$bZ1c1M!D8yh7)pq~$~`}MJA0$5%$ zXHdiQ<)^>IzuTuaFcpp1`TBpy^QB-@|NT=2n@x<`e~#C}TH@5`=i81~h+eOs@Td64 zS{K+B&v$uIi6)q_!j@EJMkzBtc$R*F?l*h;NJni7{bUydQX=R7dsOfC;yy4b?zdkc z*W+2TVT&sSgaZVzAl$%9Pk?amP5$B_&j)C`myl~%Mdq93+z{3> zCjLoKU~>?YaEP2A*!gQ)>~lE=1R#RLV8?kgU8{k>VV?qCHur1pe9tG!usLA_b5Q1F z#KS7c*@%4eVQMp756S&OuiI2y{y`!z56>ORn|A5)YKzfXzlb}! zU`;$PwQU_P+umK+84rnpuFk~z%62*rminY={RjW<+xwh94-R5Ga>q?oz|K!rbk8gM z0evQODCJ(*V$K4GpZ&1;ux5>K%-Yt1wCoTB*sj19O36TgD2eRe9G?i+*^-1snvTn0E9p1z6 z!oG;wvox5@aU76=>VHh9yWTEXHt0#uXmuc<^XweZW0E0?TtQH?6dYR@3Qq3Q%%KX9 z05cXONg*SHi@3QpUvzW1#Cxj%KJTlEdtbRdWhObVndX;@tC@LhgoTL*cVZuTofQ}N z{v$Vdc1=*1>B^h-RZa*S_9*aCXG-~-E;9uP&UX+VflI*( z#IVb34oeCZO8QIw(qes-@QtPHA-6j?FRq}4gkd8}>Xi>4%rHvwm7qJ1HgIAeP{gv? z)mvF`AeqfqT|GZ9!eoDd#pC3;srT_KA3Psb9Mj0C>>TA2PEhz z=MDe{grxIG&RxIx;%!{K7#PM)Ab1-6>tc5?{?}RfnWl?zf3I~@WumW6)6dJd4^IdG zyWD#2k@IM(1-=SHd)|S|!M_$?`vygisWiDk0z!nh{3kB@dR0@vDy`jgYKi+oi~dRe zGAe5M!I`$(WtCgVAHbaawI0J725n#)!89KDd@j~Nt!yeU>myzg;tS86(#Ara#e{h( zIRQ6Lc#5E+?v)D0n#FnQ7dd3b`+F0|C(JMYWu1)B#N5}ZUz>1j^Jd+D$@%Vwif8oidN>Ns1aE9C=*jxe4&{qOOqKv1@1?OJG)4IsjAC11`YIs(#FT5ZV zSWxz44|OV5B;w5&-18xCl#T+TA3g)(QETE>i)wZFSxCkP@E4UVzU1bw*1zGbODK^* zRWd(&!WT&LzI9-RL~mxDqeoF5^9Gg#1$m>Dz%mwdnn2)#lA*l=j5N$(#qHxXGNONa zs11U;J5-pHCszi9k<;XmwEW!FpT(&_`HjmYYG;Y5UT@7yCfF+=dc)?lP!buH?R&TC z@$-(@tjBLN9Hvklgo0OL5*r{dAo$3QEsHXx{@@aoH8|3>SuTs_XtbqgA&lJ7Tm`u_vPVY8q^uWse!6Nf2Jiv?KZEKgAizKKgi&bX4 z6Z$7E(q^M%2V>3yM9fN zspnR-Lblk8%S?^!|2}^;GP}sIGt(GAD~w$+<;3Rz>E^ziDJ4zn{FiM#gnqbJ^);kf zbH96guMtq}(r0=w-}4!pzURV4SOn|cumZ2$*+0BP^nd(i&+uix0=G|X&?g%H#~u1j zXv7{jeb?1T>?i$vfrGqgc11*Pkcen}dyw?z_UXOjW!}bcHhy-M7P7g=?1&j$Lb2vESF?4;?S)k6+HLx`41tXg>dCgK6-f@VX(tFVqOJ#>M<^*y_8Dc>?)2 z=z;Enx41*k$#fTSfTHoeIm7-t-+x5@;E$xMLrqv-=H|Qxp{cmL2&n8jy~j!GbR@G1 zg{ksFR`)))K!B!m|F&PW^k9IBl=R=r zr%3R$9!}^D&luh5(eLZs>`Oq|Z2pKuQI}Bp;)!0Rg1&cwlB7z*p^HC^d-ZtpM5BF$R!Sk){MdsCKCi(_ka7_>Y z(8z!t`F+UzJ%|Eu@k{Z}f*w4WVFnk6^ph330W3t>iwF%}oR|3g4mqJ$pGJ}{dOnY1 z>l-l!x6I8S8XCleKN*3)VKc57wLkPm&}2V(6Yh`~Gf`~|$wsfJiiP^#vURs?>X+C( z6YXE8pZhW#r`7pg;rQlOaqH z`J0*2%Ea~wZsYdau~t`l|AMJvrmjDwX1cYPx5J2uyv=LnW-Yee6@ySt90ZZQoaW|g zVfGlc`2X4Jib~-cFcGs@J#ovs69zkBsf#YsW^7 z-UjZ_YEF>3=-+t>6gGXgytOzw>)!lvkHJ*3{W~9nc^U3z4*NGciRTJ4{~Imge&W3A z1-zO-&-&n*Y#?t}ML*{pVU6%CF1|`tCqB4`jGxOrB)$+zp)*R+~lvVjkl+vabc;KG{0>oTG^#4o_;y_g8Y znv!{TpSX8+q2u2)F^07RU-eMl>b?FlC4bg<2+gNe1N&O)wif(WC94S<&$DUN z`46apGky{0(@DK_h1PJSe<6nI=Acap^;xidX{_H3tS@GJHN!VqZ#WC`PwAi1pZzwH!Q8RW!@=Et zha05brB%F-%6}nWedLpJ>{-n^Fr?>#FN|I8P)c|EJekul)@Lia$~q%%2xVZfYDyse zv^i|hH_u$fUfEL}3XkKdxpYq55Fyy>eV~a^QC0+lO%JOlv&qwZWw^}WUA#GB#dt+& z7pg(KCd0O?Gw$zQ?d@=a;EuJ+K9#?%TKgY7<`$-`ET)t`3du@sCq*+Ws2WA5QBHEo zyM!h{|H!XIGc#AgQ+e?$T4riW%w^(mAv0Cm{EbRg)2}EniDK3$s7>D^-=hp8#-Qg! z-gxpt!N#|F&>M@0V^x-!#hQ|H*-DW<(bs9JflFfj(AXm16AOr8n+w>XmEh~B96c{5 zPUVeh)zY6F|MUJ&e{p9y4EHF>HYn27A%id?M3 z<(T5pitBx}*oak&#e}5p)A5q74z;M9kUbSOYV4cEs%BKY)nhj?nYQYsQ?ph*wrZY5 z$Ge%}|DMiCoomqsYcKEj{Zgf36wzK{AJlRK{M@yNN~~E6xI5E|QJF?|-KY{P>S{w% z8i{CmnJA~)zF1LB%cVxTlh`bZ$=oVCtxmLPsu4S-_L8Q{2Q8-U#n0NnC}<=3q{Y;u zrgx6osS?QPla`jO9HJ*Vtr)qgA~$q-T#akx)IKG%C1zsEM3E{-MQ_&A?pCe2=q7U$ z{Jv<{Ca0FSdTRNqC#`Jk(+2w>7E>beQW>*1+c&&%d>7fK)ZC;!D;=d~St+-@5jP$v zTFKbQjYc{%Z>9#jPEIb4mAC=NQ13+Uc-Pxzt+F=^?62&$FPjcSmi;M3itS};kdfy& z$zm*((qe1BR?RN=UH_z?Q$xFTHdctZN7F=TUCS<0k>P4ys~mgVZ9eXH*1Yl}G;XCw zZLOzCdNdH&1;=q$V$zv3JVR%DvJZ7~rG7W62d1Z$rtSv2q}Nqh?DFl|W)dC^5Bp5& z81iP0t-La*gjMgP?^;i?bFZ{o>^qB7st~9j-G^z!?W(UE!OWo^DmIKVPN){&MNX~J zblyMgcd1~x6WP`mzWrb|@+pzZFxigwBC})FZB%P}DdMYp3$4<)6=@a%;efmzA*F(AfAX1B!_5jMY__bCI7nHaV%_)!HR3 zr+T7Q?{U@3c@BY0bE@a+TCHO^lhJ5u*b1q^QCRnPvbo7R*@|anLsMiqF)|wSz0v6G zV|$!-$*oIrG3ip|3XVZlTqikCaFi^D6}cZ)6&d%U*w`oOx|G~`MQNyUC3~!mLd)vl z=sFc!>u_J499xsDM=3WYO|8(i=%$NBrxx2MqS1AN?wzvNqKaXx6a(KEJ27;c%Iq78 zQmiE9y=HHxigpq;jLPMn~3HIM*;bIYYzr0Vvk!ii0_y^A-s)G&}J z`sd?f)OS)>MyR7K$CK5#weokB#B|<>6`O^_DX^8cO_w6sF5s%UAsgznr>*PMLJz6?APmV zcpCAJwZ0~GJBiw%>HdMEV>K7MMaEJ>2dY1|dnS@cau%{x$p_t&M=+ zI{-c-F}X$^09N@1=}oG-iHZoXXViTpSyd~BRP;uUokZl=sFxOPum6xf$rFw#*Lrf? ztq`K?)zUy0rDM0AbEo3DT{~H22(NS88|7MHlpU!fEvhCYA`n2zt&*n{2l5LvrqyFL znf7#iMWf_B>>AVfIu%dv+P>mGIq2l_y0Op4RG@76nAhcf4bL?5nWT+04|_PeBuSu1 z)yjzz3PzCzTEQG}*O@81&Xl8Lt=!qCIT_1J>LI|^Tl7taz}uD1ta<{)(c9jGhf$-M zwoa*&ZR6-aq)zgHZ-J&K?redSQoHN6H$7-aIiA;2iT?E=aQvOf$+4(1EM^p=7_G*F zQExaN?F5snrK=t*TgEKb5he^Xfm`_p~6;#7T^WX|Y^ zGWE*7*RQxHn_5~gul%0PFwv6(TkmlKVAVRyiIhxcf^|7NYpU6qvo&6OM)TY%<%uqb zMJ3;Bbqf1Lyt?-^2JX7w?XNAz-tlx$S5ihST#k3TfsGQ5XHPKh6;m-FK3Tb57QvS6 zPbhN2w@U11i~43#@_IYNMyt3ir~{ursDu}rz-c}x#s<1CwA}mmhlW;@G{34x(}55O zR==nX+@8=R;wzNA)w;Lc@Dv-tery@`91q^cCYoH${OVpqP~UerTeK5 zTKf%{KbATH^2g1seC;j*esLFPN5N|;sQG)vR~5lmMU_KL&1&+Pu|>*2i`K^KA+F0h zhc!c&V)5>z<10-%Q$P5n_`a#DWe_F)!9h#2XJw_*_I0;f$-PeyiK5GVC{`R+a^V?nyeWMg z>=kp{`6-rmZ)@S)VVggdtB|XC0!O($3@^t^zi(0L z&W3vQ&|G$xf%UA?j*PR%P`H0g6sGB2rr;V5wQWc3yvQb)XsEF2O^4g*3+PA)hOeTf zG@+$M^i{NU8vUE0rGcg}C{YP5HO^>BIW{4Lc57}foC5tY0gOv-mjc*evhPf*n^wKL z$<{eKlR9I?ZDP@F!yDOXioYJy$6hUFkc`Ptlop@kSqgurPW1nrKKA6R5EwfC3mH?A zCku#vmA%SQbV}VH>P@guz_cVM4myd-K^@6Oj{7@$w8EYl)kMSx%-huz$OR;B544J8 zEl~yUHOqP0N$_gZj?wUHhfGYKTKt-uVcSJ>IvJV#oVgW~QM0ZYrNqQ5wdy&>=%sYI zZ*e(sfu12!nEP^t=I12PU&-Z7sgq1kASQd-WzUI-2>vg3O*)aCVzzoznVqi5p&FMV zMvaOPY#ZaK(NJagsDYWyclG^b+w;!jN@E`OhsI;I+HDs@hkbieY9>R6K`N&&%8}@1 zsm#NntaDNG2c3yg(_fDSg4o+iRPVX6(N=08Rl38rJJBz04R2W)lun*>Av-zFbmL|EzF*T0w8d_&?JC<24>z<-3yy>TV38hz` z`hAUK+LxOJkMVHPz3o?0gZ?Qk>m!%m4jtp;bSx0sv`V|3au}$6DO_3ZGip1%50|3- z_9?jZOtzkOw=`6eqeZIHZ28mLLf)5wR>rH5>#%oECQt;%k1_vb6DT*gfz+{6?C%GY z&_=36d(&8}F>r#ng>Pk~Q6+gEqFFgX3@3avst- zUGhQryAGiSf)Es10m;1ke%$?|Hd4L0nCj80bobTkXM6n$e^#s7L5*=efg;a!NpV*X z-P&Z@s2hi@EJppbYhDlsu{2hmU0>#mE;_l%xNpHDL`>OX) zOLS6=ZP1tw-Ti37TZ$)!jp!ic^ctm|>MspbokB_KYr($Ki~4~H^11wJI9ycJX6AHg zd2)TFUC1{5QCHE(y^LclsoBhwHg42A1*rUtyMqT zifT{*dYW41P)d%ryG*3LZMdtULwC}z71xq7 zlO(&zeQBX3I{Riz8O;-kas8xpUjl*WAVB&Y5YUS5eUu~bn7S{;D&ze@Q|5eTs$9g~ zPbj2^Px;0;?W$<<-sF`ypCl2Zl(1Bd&4}U# zgCt`ahjqL<(zaRxT(;4cZ)7^AY6RaHALTQ>RX7p}dZd$)3B*ISxVt?Y`O|eRt*c;u zTIKf437Ik9tEB6t>C`n=yMfW57Hou;BUf!b(yQ(Cv{UW(_K@NV<>f5p9xIZPYDRmm z)3zT>)hes%tQpD4-qU(o%ckbtlXn|Wb_br_eAyiKj97m;>v&GfP9afA)v9XUwF-xh zlliihN%ne?fE02&*NU&>e@Uo|4H0MwHA{JD%#e;A$cbxTqVp%Afq|vTb0g~s=IZL_ ztGrf5CtfRa#$q$MI=Qc2Puv0FF_hXC7Hfk{&wzzUy`Z;h-7QEt!&pL-QuKx){+X1g zSj?*Xfm-pDV#Tr&2cy!9@7)1tRgO$Uj$iiLDA&S65I)k3%lKJj&os4h!L`VwBq|s8 zDX!>-T)9y(fkihFUrXQz7ENzp&`nm4P;d(kN~{fyiK@#5fz`+yQHA0=rB)7*NV?b1 zMv4&$NIOd+@nFw1BSt%wSe#D9UOMM<4u&JmH`jK~YN%4&War(4GF1acBAJ<#)ahiW zRcnEAJtaqzA$?Ixt5WV*ZjK_;SUKfvwwo1w>()Zq@gzTt^_8t>;Bsvf5odNYIQ4VM zeR?_#_w%J-auAla&EQxm&N{V8wLA-?^`3Vq%|rgEF2^$RaAy=^hFg$7g;$ebBW=BQdn*1N?(h6jT&hF zBHr0o^-GqUNJcs)5BVO>^@JM~z&mj_YI{(I$*c{Pmc+6NJ{SWXelKocMSM{j7<$x5`xeznyOA~~v1Qh; zDQCEm!RYX$E~W9Q6;JtxnSz{~yTjnb z+`e!-qXREx^w@kVuaiEfk%&y%CF3;l@1iaLY}<(WQd4Kdl{uw{oj@U5$mc@-S<^3- z+Q-3oUk(ix;b6_33-0}k$-j=#e7_w=n}+n$?}E`rc8nGqAM(2D(?-oRMq|&4?AdRP z(T;D$Xs)q8Tpw@4C-pE|smVw_zH+%Bv@8ehL(f?*Pt&QPR}S@+y(b*2MdG{FED#M& z8>4L^ACs!P^*q~C{lk#HUCPP9X>jxoqw`^DUJuQJ-TkuCsT9JYUb7#aclzBzdV17$ zTFVoP1k!0&B$b)@=6bQ99YX1{bQp9F>S^oIySvn((2m89#iiFcb_0QU+t9p~*}nls zOMN0nvw?{XqwN7Y0WuBeki>#9cQ0ZzB^cGqgNYG4rHi%TI#&*~j*-yT8Jn~(FHS>A4=PW%M)>XCt7{m$&@{s zYg%-MvQ6E!UA9AwY#X#btN13{4)#IV5ST~8eZyE4NmgGaJJ!`2{WApJKXDnsJ5ZX*-v2;B??S%*1 zj9e+htF?TH_@#azsBfEd zc{$8QJj-KzKF!4sz7)(sCG9Y)9^9kZPIqVb-EKHD)>`>g!r6$qhU=6kvIjjM9~xs(Ns14$aeF}Wat))yhOiNjIqp8DP zAscPTl71-azE(TrlINvC>U7E|huL@-32)Z*pwAVXPulzL$h%)J<4LU(8IJey!d~Ar zru$?=srnP;`Y?HLx09|wL>@>r&9jI*b80fZZx{Q8dsRVs$ax!xUAyR0KYm*6iML=h(-bg=^R_g5I{BFWV9;iW~ zxnLal&@y$0wb)!}mQF=4$g58?G~C&4Exm5l;2M=A-=X+X>fLn`vMF@R@+PIiQ%Rri z^V}OLtHNB@IF1d*oJSRF0#aMdU`QV|cQC&Vy7kh$?Mp9u)9N^ttezm3?b_2rKr4m0 z8iAz4L(}R6K37a`lVJMJH|r%IK3<)5T@^@%7kcg+4Dz2nGxzKnJa&b~wE9LZ)vJev zJG0ZbwS_h#i|~8=+$+};|%qxQ{b&&TTPafL2je1 z)2GusQ=A6WTFHINR!_6TA+>BD268Vnj0YQ<-z}%|d+@pL(kZi89a_!ou2a%uQoeOK zECOn}?JOOXRX$j&cBZ{z%5|H4 z;uR{NECf^fr^G9p);>_Yi*l-0>_Tx|Ilw_kt_yZS6`mzb+2S|avj%(_RGU6|tt%ep zKx07GKO|0alYgt}>bSdxZ5?hY=ErBRN+ChX0m$^QtodY=G7mGA;% zr!PO|zCg5;7o8xld>~s=Y};y%I>C|O?acIdyTj10O-jiX9gY3%eIqN-z=H_j1`Qq?dxVI`%*w1R%%+U*9sn1 zV|5zUjAkYhPb|lyS~I$;OU6luZEU5ql}W5@^x}a?E*u%g=OO3nSXo3|<3Ow+jPb=0 zG)LUB(v5LjJZZHQWyBSIQnJJh^ENHbg^I`Mc^j=#(OW;xC&jGKt)BGq+~qn&%6CjV z60CvH{;RTQR+#nGh}WI+xwi8cO zCILhBg>(H$u2MagO3F+tb-T4i2ck1sFvq*N3PBqgj zW73aKL&s@BZmZQzao=5lsmdnC

cEe?l6V;jmG)4g@v}z<1pze zvtgsMa@LO1dZpEc5ilA^PfEUe)aUgyB8^^Y>93w@k)1!{8z(g-7#LMn5xwFnu7aI@ zWV7oa&zIAU$*1jB1Euk zrDs{TS5f1ZxUr?B4YyEZ%-@&>4EJ5s2n{84soa(aZDyU^1tszq65Jvtd5lJ53kwBoi$%*CQ>~0Lp_+k0d0^^@vcT?b%4tw6eTU3aobMTF6Tx zy}aqkNZ8BB!sQzulSP>Gh661lJRaE!Z13Q;aPdxR(|*At{mOTjJN6iA0h)5$k9m~& z@n+hEv>bG1r{VduQjH!mYiFujZbu_I*B}`SO6sbR-TAxy!_1j*hf@1`t{qwR;~`(Z z?r)?U>G2@uamNcir*Grz_=oGtd=M%x+nI8!*;{6MT5XUB_vYEvZhl%w>)^4LF81o> z#dxV4o$lnU=NcMLk354(el?13_4#_2Ym~RWO|#$27L|FkUms7F8-3Cn#`N_rX=u^( zP;F;MIjI~f8~x%Tp!cKxY-c?Mi`j zuk8I@g2iOfuS#*FSeZJ(j(an{sR;tRP!Y9pPMYY{$3F=M%5zYyUj=)Zcz4=}>x08#KJm9op}dmWs>STm zpIE2euG+qBbc((q{GwJc+wQ~dsoK^n>xC3)hU3X{TiNEPF*%WrZd2c>e&o-#O77}-7FXKULcAN;mXbzb5F9wSu3R9I zPK2aL!r9&Tqgt+U=*sSW;yWqlDCtV?Uzo)cP@mO_s_2#;cxDmu- zOkto{oGPy6q>?Rd(?wTE(v^|hRn0a>)9E3os0H7A)Nmd==}2(Zn{>iPPfHu>W<7za zXz5A@qIp#rtGga55he8OEB+HzWT>NfBU1zBaa8YkPzcohybnb*K%QO`nP})W4&jn+ zdu=l>b@YU%IcO&)EPy2yXTOihUkKcz-_WO3cNb3Kt&>{U6c(*OUP$>WaB-_b%BZ5{ zDV@{h6UV`8JmuAWwPm6X(F7UpMV@^-OE;`cO zd8Q+SI@o+@KHD2_+$*tF(wEpPu~pKS*ekJB(r4|}GlK24g04|(q=Uouu(n+`c5s_% zWS3n;sx-He{4!V0?hg~CzYn{E;q}V!jAyOAJ5!s;UFfF{siBl8j{Gk8zfHsbWTYKg zB!+FLzMYl&0r$G7c$%$5aO#W?_p{Qn;6AwyKG*<_mXY_zR^4Mf7mpU()0i(7bB?1^ z$O7q_QVcirK4geZ{8X)%bKP0SNH*Qwea`KI#rCd(P8bR0xH2zPX6~%APe_xTv)V{H zYrR9?srwR}rZ(z!BiUW8TAvr3!@N?S55h*jylHjIuEp`N*{0iFpqbz-TT6x4b3@O@ zC7Ja7|Mory2%xa-}BAN-z3Q~U6_hjqY)Ju}>6+-d;UqmRWKNv!RFbzkGu_tFo zC?sL?XTK*xNg4k>2qmANB{PB6E>&x$tDfMl(Un8+bewssm2R_H>ExAay%P)=-a`DK z*Sp&ObQ-O9l|(vJu12M3xwMK-g7EP0l(Uu7)RSvQ;BmKTc1vmX=pO5(L$MvID}!n= z&r*xPhzu4;YXE`&;bshQN={!pZ!uA7d85g)xkN6pSDI&O=YtQIhscl z(!7>*4tm9?XX~8iRS)rgN|jL|Qpr`F)7m~3&?cHo+pL$~ z)~P&%R=-`*w2{BKULV%;?y)sh_tBcGkl!|gla3L{Y);{DU;w|fY-rO}k7216sScCw zLiZ(vQYzoZ<3H;*^_pDxhvrkDw*N!%DGaTQ;AQS%UZqiH-* zOXf$_b+M(iCjD4vR@0YZXK%4Po#GSd)GFS7u2P<7jZ#i=Pc!-G%+o#fXPe-rEBQ{% zLp(h#__Rzp-0K?SMSty8N1a_*ji$85cmc*(i!Z$GcDxgg_k8TF=rLcDv%`2}`Ud-0iZuMoaLS6J(DDIAX&ocl1016LfwXQFci{t(o#0~-E>4(x7yF5&J{RRe>y$^BLU9A5l((PK5ZB7 zt!?lUgUerp0_r!F9~}C(=jSS^y6KQ}Jwym8!7AX|2c^~Z;MwiYzy<4cO9w&y26(P^=+{DHgi~voFhOj{T6d$o6isK!++5dT)p)K^?|<2dnVTN1IkRfsuQ`Lh=L*?6Mv3#92ax-WdX}1$791K9od>WLYnA~KQ z?8nSGG9giGDy_`2H%T!aZ1UYzb{~cBd!ec6>it0&w;Vc%G)9;i|;&U~M4?VaN@Nk@^!?lAeot-4Vj1wZ)9 z>hp`C7yKw6y|a~MAN?^Nj)IvWd#0L^!H(}ZXo+Xpyw(K>hogWvb6_{}`^)5B41Bkk zy>ky3GT_(_Ti>3iw&HfdL|s-nPH%*TX#A_5iVFYi69H3ab>PS6z6qSYz3I;5IW1#m ze4@pkJ)ZIVEnyuX4{`qOhGacL4p;r`sz*yoTYiA*#NVJECE4 zG-w32H)owbn4@ytJqEL{D%)~xZyqR`s%27Y{Tx2aTZ^uyLAwU>@l=-@bB;1iRq&(7Dsl8=%9Qa<*7YYh>*hnDV7cdy|RM7rqXvy?ag z->MiUW^6l)1xzc;|o6okWU zC@)*zrdvqGmtEtlHMhA5z#%FRDwmD>)P&~ebl!s=d`qc(U-vhEwI8x>%`3}+!>YP| zHuKSdF7D>WOoxL~7JZZL$BlN}M*YH@NDvMer^~w2(Tv<6cIOeLjFDSjq z=uUP+V1x1UJw^^{=$n*3l-AWAi@wZlogu}=dCN`hyAjv@6qxBo@!^;FU{-g?exq)PnJH9sOpuu@K z0_qLtcZ|+(g7J**bmQSuK)mc=Mv?$W3{YxsP#bE90_$mEyrTjF1f1-1B9K`KJ9k)u zylQ^~^Ndo0_uXDp1=PmAI%tjrTs4rDz58VoP0?!@-B578$m}1#apt^#ZMlj>iH7<4 z+ZVw|d;0mpZhIGOK%dPmb?;izv%s5{J-X6g;t_Btwj3|K{1*0UIxMxcxw_c#9b z5^(}oARItd0aGR53vBfaKEG>tBWwNWj_Ui^3Urp^ci|>D@m?gj@86i$UtbHyC9n9R z_5^f{{PTt149ahWy?2PgS4;3W1^DXIt^7}(lpjrYqM@lEaN>s@Gp?ToB~1v;0Gg+I z(0kQd#RvRCQ9908bupk9jOPfTm0ZUPKzsmJlYnU~~z;1q}5M)yHC zj`?x0+RM&p60GE@RTk7Sx?G5{XhSVhtH{_El`_(t+G578FV_bmmrR5mq%tHlG0k$I zj-4c5@fFJ3pDM5*zMJgM$p|N$?VGIP_bxj)CfRRD9k2@@;osk2c{t1}($-93dRXK&{J!g! zTZl(VHci82FxN(K4sBXWS;d)h6s2yPMos47zQ@gj%C7Ega>f%Qv&bnFZ<@cywS3R7 z>DCIK&9Wn}G^iD)3JbV^a&xNRyY8MHVUh?Nsr5J>c*Jb+US zz{GI_z>+8x@FmfW%rvNjE8v)*0KkGpUcT*b#k6y{{IgnYg)a>^>BnlUO4AD!ib8{J zg0|Q6QMPqQD}KK4&sH8)0N8|Rk=nO92zKqC>}4_CHn>QRZ~&F(e8W^{{`pYfz29^OC48y%3xV(^QZ@SXf#rBP@Dc#WIDwlY2 zWi=Z5w4Y1Rh4vpxrUnw=lNXz4}#Rg&vwB#Lc zrCq4hd4QA9=h$C?_H`Ao}AeT#vZjN{ys;x^lEQwW~6F7^% zy6^X`!jK4mw0?-4ccm4&Jyi0q&@Gm^5lBlh4&;GU>Eb#kZs_Tv`{2>6jJH_5}2*3RER(F zhv1!kZ{PWD+Nt4DlbI^Hd3riL1X<}q#>wgFzK@ux-klZ25=a&pth{`^C}yrv=)@5` zjyC#Z^)Qc{sxp?1Pn25!>}9QJr#!S#;o0)!P~tU}C=up^&coG`Ox~Q-qxK+BZh9gV zrCQewNB7C$%sa_(^V>OLL_uyF(%nBE!~ zb0MBcJ1r*FciYz6oURdJX(PI<@X@iUqU5Bx$JfiIzN>{PCuG>E9;v!)>x>)Ps4fPN z>=D5bZ$w`qTC)b>UU)S*N9!s3abXySj`Co2Fp+LFN{bPwy{}QqiRFe77vrS#=BGQ! z_e!CkmPWiUr5qmZzu&2Y{Cf#17Hszg#b1R ztJ*i(=$k3x-EQ@AU;rN@mq(ufYcCM|Qwwr@P@Nm^!n*uvzxac4+cIzkXqk-Bd-$uFXj*Ll4M<44YSr( zA{Nj>G*_)hVZ!}JrZ+F!Dw2W_t6$XH*46bHJn*W+_GER}W(pEL@a&Lh3#tr`)W zb?kt~eIL{_t0y^=(nEN|;_QA;)|qW-7kkm`TYeks*&>oD`E= z>jsA?p~vKy6H`=zobXgpKa-H&9L~cvuiI5g*tx#J9*VdfQx(IX$eiXS+FYBn0XxjQ zl7G^X3|W`-AD701fA+zGWMjGBnh$m5iLsI{4aQ3ZERAnCnezumQPsKdg;9iJsK1+Z z!1w;HU;dzZ{N(vs@oxZ)7tKVFMHxR(3TwxbDnAT-dKWcS7Wik@1*O9H{BEt#2c|96SAz^VbrPmws z5L#5Kfq#HP*<7ZSjqtQjZs|qXsP&G59iY8GU9j=wckwFRU=*&{lAcvIihFMy&!zqs3B0fiCr_t$<|EMIN3)mG%<_f7o6k-l@-zVO!G zna|(3Z2CWN**?v60$*CtXM-LQuzK~E`J)Gu$-kl;4nq8)iae-Odv$a$j*zKY z@x!^E?yGAOs3R_YxFL*6SKxR72jNhSAT!}aT7Z*(=Kyire*(6?iMe6NxB5h$J)2tw zM-D4SkHma5!!?~F9d>SGW&Ckn+tZK7)}CFZmwKkiadUVe8zYGEYxk=+^^-;|iZ{+v znrU5M@b+#+7Bgb`CKhdbcd8X8&<;ET}!Ul*J~ z-_#->H0U2+%m4iDUOPAEcYo@~V)P%qyBB(cf4#eZ#a!0Or*ayDp17n1U0(bQh4Yye zi@O|E`!ZT#y8W=90%|0_%*~?GqJF7*vJ3}F--ng#v<6mv_? z`tcyzU2gG%--wYlknu{5pwUxIp5M9VK?1)^MUeYE@VCLz0(fdXhoaiphwk~vpNEQW z!G=kOnKnxI=Q^iD@YB3!T|_xw0KMy<2xjkI&tI*c?~LXb`s6?aGJ+(&XAr353nM!`2WG3k$A_UV@V@`VC2mB)N=8gSFL z0#um3T&miE9E<8{>XCm3>cvU-PZ!_Qb#QrAopQ!e;38z^WxANmC3>mfS)<{_GPIahpZh`HV;)AV~S{ixty3OIOe-YLrO6?}Q|2QAci zC#nAY+HXm!U-2|6vH0~*)sNx0`-Epqn4AP2&{Jjd#V-ztH&)@V1skaH|B9qai3L?m z6cB{Fhw;44kNGZdLVA`?#F}2GDD;0#WDM>rJVKS{v{%h>Gh@9}bk}W)0yXp2AE*5; z+le-1*{vqlg>Qt_ZF9A|ECJ)MrQ=muB2wZc2yY$;>u6Cc5Rs<)N)8{qx~Jj*>e90@ zh^-EjC*sh8XShkb$$u23L?4@jzS72pNd zo($2#{>^y6-I05`VN(c+;nlk2n;9WOb=%yt`%kGnvXBbv<{7j_cGM!s<$1EWz|%Fk z!+#zR{Le|M+^l2`Fxajww#pyHoy%qBd1PDX&`ZR5C1W2&OqR0wxF!t z+-qS*6KU;IjA%oP|A^R6YCB%2wKh@vTfEvZ2X^Vny`DP}am#xhe@d8feFfnBXg=g4#dcwW_7)KH3Fn$#n}M&1fEeBDbzHL{& zzLxWE@A~W1@t3##pT28oD19(!e)G2f^sb>*^GnLus~7qfGxj54L-5Pqx*mP;7O$^7 z2ozEv10~XI8lw|z*KBlqpGOJcH_VP}J;1 z`1jsi?>(S)CZGVVQEz`0H^4(2d4s<9$^k_-O48=@^Sp`t>Ewfsd?@QfjzaE4F`I-S z6m@w$g+Mb_*~z3M)tm0*?mX?IaxTy6I&8a~8oBUB(bGcE?y$zdV{Ut;YCf=4RNYfz zUZzt!j-XR4r2g3&j`t|^j_Y>G)eNkwio2+`=}A8}eKH8Cs@^XQ@g8 zy&v3*`h=+TGGo4`v| zl{Xge%N730G0VauC;#CaKm4kQmiHU=ivSxA^*=pd|LKkT^*&vFG55YbU;lig!Vv%W zHs<#jGhymi5#L=F3qo+LEnQYRsu$O7_0kq!uvu=R#l~8cW{H|TpEkhrs&B4+exeXz zmI96(hRN3}c|IL<(4v^v)eXia4YW_4qF6{`$7nY&o{Jkq6WacPFp0XUMQ<$cj@yGA zgdh=oK8O4!+)6#$JJJ(B^GtBb)0ou5RVtn#2qjy1{BqfL=T@sdynV2cwkD!(d#v3t zH%SR`((Z;$BOcQ{Lb}hQ4G~ zd@j9=fb`4kg80WtdN8Mwj_=9CKY$2WPE`;Dd!|62$or|$8gC(=`6@}qRDpOO0dOLH zA+poK!bltSw}!xIT+o@jjO0q^A;f?6o` zOLVwA-G(XFsHhAFb6I=6E4O|*SFZmM#$(W)_I1DxdV?5C)^Br|T*lbwb)fQh7UZGV z6goo&ns>M>!N>wEx#moeIfika%IZ43(sJV(OHdW`lRq7*BswO^33!@ZyOk)EidNsLl_H^ zaQl%Eiu*oB#p}Gnr{lv;?6Y>qiQYI#n`SYjw^r8kY>iwAYF8@u>rkB(qFxTBclRPT zL2C?+3E|e4kfbD>CVw8b&&_JHF3&FOqW&%U+_Uop2mx{D-4FD_h`cBw?FkRl{D|(J z7kUyRcQYPXpp)-C(7t@)YeBa1*~9;RbW#?*%cIm0rgPA!%prf^pT03nfSYSV+mo&^ z-!Ncr6tEH|5I?F6zCI*14^Yf||tIxgI*Bj82ZR@Km2WI%$`yNdPpyt;n z;mh;-Y7@Qhz5Y@h_QDB9o8{PtIhnypzt+xHbW8Birm}O9`jfR)m#AFj8!k}Iz>cvdAz-f-!o5LmAHTM|?W}=g!`8_)UuYej6d!$x0 z$c9|o>T_u6koxvw--G*3BRW>n&}(Fj5^VMFR)~RT%h8BdcU|q8R;Eq0!*x171*0V$ zF^$=fpr}EIgz3I@FAAJ*e<$j{fh`o65bNmySEOzfovf@bDqIPa*vpI?Kv`r9-1M!f%* z583xzs7ZIfZpc2LD-i3QVfNg808(B-GrA+AUmmRQ)ZXv)>>tE5A7C~JO86qCq3y?* zlLr+hk{K?}r+n(y9C6&>)!nh1fXq8pmm=PVoF?G#@gCiGmt%PvR`=N$SnLC;lu-I!U>gACpz6?rGF`5A2;)I0W+LPa~QiLZq^m@ zKVb!VriLK0y{8riupqYjnp^wgI!%u%)1xpXwq+XkT_8)-qv4~&zGit|dC-d_m$iL> z?1;mi;xP|$iO$oAS`)j56dDrsB ze0%+vuYp1E^^X2#J^gm@{>$PI2140w$<@wyv>P>3?0s1v<$kpe&4+FHvvu^5+tzy`6C|aU zjujvxy;-8=Vt2TmgkXZRyg}NScX=)$v6RcRQ*J8VoFdwV*`HVfh|eoU%Ezf)tmks% z%5JB1K7N=eUIxU~y_H<)L9~e%?RPdrqADPD+C&qunYrVz@frspvE)%Tt|MO{4^Se6 zd0Ey2WT8E{QmQ1r5iAGrI`*zaXu}ibqdqG38hjC3!3c1tdbm~<-1c435r|dSk_r;8 zDb?YJg4wk+Tn+(7(74u2`bG=z~{oi(pUcI8f z)`IPuIXnK_sp0;AVJ*-{^<4-AwV?i?7T9O7(!9J4FQfGz>H+$jdhqrdL|sj*AA;)t zzUlg7J%9n$cl+~?p~he9fsBD>=@mFuMqkf3Kh=a4JEE}F{I0P4S`#Rqj*))c`H!@? zqv=}m*3YZxoWgvf(*32@_dzG}V>9t5ggi{siY8l3@;ALR;x>9!!@XO0u*WLYtGShY z2T`wDJcJZjh;uXXnyWIH+s z4WgQl!Gv{m`v9ywc3WRalX3maEEQ}8!>!4c*24uoqBiJ{=|fMJaOiie177ggy>x)y z>T2{ti~(g|1f+yhGZZ|NU}&O>`VyVa$EdfS(lJJj=aEp{b#9$EwlT~P9;pPj8~h-o zzt;p86s@mb&)0F9MU`QHyJ5=?Qw7@R)`2;>s>RG!&n!&7i7Bk#3k)lfx!P zYqnwyYI^iX%)guj!lZ?XXHT`mE-C15fUt09PW$XmJu&UN=`_yFqGVrs+-N^B@cfU2 zOwjCo7oXW(z9ei2iQq!GuoOs7rA`GIt_@cFRODATxwW@<#o5jPwLQ3LW01^lIU^ZO z!=VEi_5Bt(QuoKyNPnygALhCb#x`IMp*AFOe|y~j*MAn~@z=Tl$6A3SzUi1G+wXzl z`@6}fz;{1wX5P$pIp@9(p>Jk8(fy{4{|4#+_ZjgyNzk|dKuh%%y!@62HpfzpF5=DyI}qs5%;&|uy1Cc zxA7~710H+^!3E%hbabVcZz;ClUW7RY3aU_i6R;YExI6toMY+BCF2I<;;p%ta#kXI~ zPqM8~Q^VU?>=knGMx*?l;qW6*^IvORSKL1K`oa*_T?BXxRwXDHoq378>A*_of-rI* zI;4K^IW3Wzxe$^RRe;A&l~#(K?qox8R6G5S=wY|4ICdbQgS%E$JKdaizNTGBat{Df z=OV-W?@-P)ba*r`yap$my<;FI2eR#R*E*ZjF$OD>IYbB>i93v7Y0J?N$keO`>!M1z z!CvyyElz<-8HE;izCLOf8Jv7c@WcjcqEWWG%4isiKCNl_X`5@IxZVYd+MZ};1+w>J zSqzOE5(Pw2M6^U1cXsGHy!D=9=_W}{r}wo*1n4<4Krx0D)p*^msoK1;q*z3k4mBXl zEZg$Ns$Fi%z6MDPjLKzt({AwvTQrn+@7Q5dmN&$M2oLdbs*IX45NSv24K*#S`j&Iq)#7L*;DVU>c1K4;%qg6M z5d1orWaDTLi|p+-v**OCCxv@0KE(KLQ!}Y8=BaAiVuQ3BT(s`S@kTeBdcK=1L{kU_ zVL!E|yU(qK5G;bNe%&O4A!8leme|!Hdu#k@XTziLZ9a#5#!~F z06m(J%B$Bo$dy9;)?(g^$?uUOFWTK(mhr8h|JR!d?)iJ%)ZZ$S7``e}@vS0R0!Sty zB!~lU_A4Ypd;Np^#lH0FWO4M@w1pMKEgaofbLl-F7~IDoUw|T_|G1s{<(dz-oBzRK z0vaXv;@(0`t*BEUd7v{GtifRR{WS=-nSMy4karHuJU$%B5I}r<3$S_{tbcT^09^IU zMet2uJ~BC6{^rv9JVU(9LR?R>UUJqrBIxThzKja!|iFqYNwi9dT^W<6_LFmtU6f4;n`hS#5GrIZKnE* zMN~X!=O5mwA7|k}o}Z;thPqJ?00a-zZsCBP@W#J=;Q9!89`D0pI7xsZ;9GnHC~My= zfIjbHMHvwU>T;7+3Ivw zm_U~Edspr236Yug^&Sm_=z;+&Ot$wbTs;xOlddx5W}86|D~1RVARUCBn%*?dvy8*D zcZYM7V|%433;bpk1ej#jdoZ;i(Fp<`=JRyZ?1dz4AV0;nM|y%oUAsdHF$_=Xq&^oW zfPDf4ukkf8r0AZdy~~+9nhUzVpeQ0MIVO291HK%s8W?K2FCw8j<|~hDo=77P(^;mq z>I!ZHS`cmmx}^z_D(sqg>mAyoOO&b)_K2-Zw~2mS<}=N!93!tgF;%)mF%}lUSD;2y zL8fNOnQ%j%iByzj=5=;*rNeTMgF7TbEUyi?^&Z9L1EUc*LWi+%*pY!{5>H3I!Y)!_ zmOalD+^W{@!Fb!55ql;!0w;%O@{e0}C4Ib$d_If@ze{reYkNlYUP7LH{%p^PTyFcn z<>g80AGeucp2oJ3&wfS>zlY}8?>RD`F*0BN|3@mr+jR3I-QnepeU}oiUP7IBanAP_ z-(Jgk;ipE?OX=+Ey!B~pFl^j=eonDotL_RicOm=nZJ_pQSRTJ#@Xg2o2h)GE@U1@W zsdzVr;UcmupX5pzt$mhZPGVjpr!!fckIdtI)z{ip>@%}=ju20%=CLoZ)!|sNJhb%g zP7YDSr*m_;D+SfrS>1}y>~P#^+&bNzPkn|Q`nuk3E4>sH(RJ@JOvGw+aF}+wLZ+`= zd%@llpSL5INce9^N>1hmMl?#ljDn}<6T2umv zz=c6777T!m!#twPJG3N8ckMyE4mtKn$>qj#s;F)_fVnZ^_Nm9^6w~bdx0WBX z1-d?s%yt_y-S)v|hjdRHrS2TgcDe&dni*&A>gnuTh0|Z@SrZj^iwP;I!Jyz@yIyvWC(*ZQO1!%pts)$Fy8uyM|ozYv+ zYGIbobTwOx(A6b)!Y>EOlWyt&*yJ|!pdk&ib;>-OiEMVM=4Q)DKEcK}dX`fwyRml9 z<4C|)RpXk&zChG1J{()0ydSJ{-#nqc7Vr~!=yAloUq@0p83B;@`12+_AN#q3wUVUj zsz&K^D^Z)tFhF{_3M6z1D0K&E5mgYR!8BpGMBhE?A_2We!mxNb?Y8o`-(BH`FM{6K z=I*gi&uQ+V#$-b6hKRhFdnC_lrH`L2Sgri1|~R=gZA*mC%nb*XTk`2co)SQv$#JyfcYX`##R z$!Q6tQ#hXXUM_AU_(fAYRY3qCvS&j4e(H{O3xRPVljU`)_sPzSRRX3Y2kVl&JtE4 zr=_2pfv!aIMDhN%i3mnFsCZ9Rg>O$=VTToB2M+%6CUcP5++-7h($d=OJSJVR1_t&J z0M4aJ$AV!1${Mvd?i{5?nOeurS*(D%7vCPu=Gr5{(^=a`_4+9+3>WCeaz9EzV0ZVn-TTpKwFU3- zQx$a2*aBpXj@-D0ac!t_?(S>4`7%?B})LsCowy0T_W9uBj?8j-Xx_zsfY00D&`73f5xt;S zY09qLVvwg~@7C?9*{=?ZU7qcJQf;)8xn?YDAAHR13>}VoD3GRz3^YE0d~YqqD7V<> zN3g%$e73~M4wOF8Zb)&M{oOWtA*?1WWUyS19__f!={wms*|C=Q+)gg)Fqy6uFU70+es?X3xO>hwL zy>?me%}rS8bkN|v+Bz@F@O$_%m`mPY{CI5yIqMHo?5~aAmkv*K&*cewXLhMl3BAaf zoVGcae9DvLuNTPP5C_n-yaWIAH8p#k_iz7{;H8?Yw+OH772yTTpcZ;wEac!Ty5u|b z>KYgRdFxMod`utba`yKqr=T+uCWX6oeW77O=(UBgrU}WRVf)q2yfKNTr2Nxkf@#Bx zWuRqL9qAew%?q!VDOl=B0zKCC9OZOhCSoRoe@Wt*R<|}mDLampA2I-*zh(!gv%@?> zV?E1q@Q4I+@g`~+Avbi8wCYIZSZKzeiWA4@`6z{#`AUEi?<#N7ioRrNb?%qb)6yO{ zKniU7rnyGDszo9?hNPz9rmBX8m@w$V)>S)PZe6*E51Uf(XR_Jh+nBJr`}M9g7PXb7 zeT2m#;#|*SvN^Aqeb<&(Bu$qc_#p62Z^hRR^sV(d_TnuvRzMiEt!z!P>P~cgmk9ZT zOI?EADkW91d>J}pj;tH8vGG>TePUi0_LKRratw4?NXDedFvUtE_TX;kn4u!V0MU)6dw&MO)( z>q`dhl_0OCO>h}@Ha7=bsS$(Dz7oRqqQgET9tC7RbU6s{WWSA6J6Xl?-Kz48Sr0&G zPCbbvd8$-y#lRdv0tj1FhgWWx)s}JaWS4bxHBpS}m}%;#=1E_`ES+B~c_aGS6<;-R z{5;QVBHUw=UA4~=VV5#d4)o64AdW(8Bzd=u}yv&?tS2)2mU_nEL8Yir2@ z%c{BObH94*w)Vw1iI-9YLFsL6Ie9w-E+e0-)9eDWAG(|_f-b`nh85{T92zm~;|VV| z_lOHIRnqbe>)aIP+-a++#ihq=@I)UGCo*uakcmQSlznR(!@QqvL-M#Y<@&P0sYtX= zp*E!jdY{?>V_c=UnMwgsqiB-k#U!t^8R$X=awn|nplEq)srV7V-VT7{&-8}4PZC-i z__l4uqK{@0fG94Pk^XhrvhcJKMUVE?W;EnbsqmF3Yku*t)4DlewMe#jvV;nnf{56O z9i$LxX!*_yvSjSW8a*fP*O_LZ_+FI@QRl1cUca%Dja=HUgdg()nAR#*S_MLr*?Z+q zqj|$X;9xzfnJ3W^!|aqz>pK@i95LbDq9cQ+Rxirr?!?`Ki>9-eor##V0^;w0UFp!F?veVT!@$;mwxF zJk^znw3R+6hJvpP>ahve$5Op@)Pmf`f7hM)TDSkp|FlDS@PXq5z~m$h-SdNV5rlDC`S!(mx=Q zPnOqEHnGhLvTv`3F*br(4CAO&YGEbNmJq1&c>oFu!y9^(%$KpLugJb(4>Xy;LE_v5 zz-;$XpCd+(>Dy%$0!Ajhv615=dLf)f30#>DYN)Jng%b z3RsZq7?!;h=2`uGdCSl61(&lV(J% zr^jHtNpE|;ixy24*t(CN&bhs|UZ1sXNOz_G)Czp%o9J4(n7s&Lp2d=r4lICRDznNp zT$@CIvyxhXo6_s2y-_`hdzLD>bXb+fIhuK=8>;F%8%Ecz(wZwAg)zOeA!Z~hLCZ0L zqeeI^J0BRNw7)^0H+w)HC+C3>Ya=%pkPh+(pO^dU2fJkcAToi6-#m*|coZe*s1sFk7+_7$4W0GPp|wy&IA1jfJn)h;Rv%-L!EQ z2xZSKZTV$%`t9Q1TnjG#S2im1HgW)w1rV{r@E@iCusv2z{B$!HJmrQ{i98mX9y`G^ zG$h;jyPn&L=NNLk{o`f5K*~q4JdSLi@CjO6sQcxCbk*8Rv!?X6Gm>Dkw3VJf!OqFf zNTM7uMvETt9Og#MVr(s_(!<2tF#$2$E7I90i)Pi-OiN7`j_DSH$7YB+cXB|90do}H zv1+s)OsCPYOHGJ&*2)=mF@`OpweGmn5%{WU;{$zkRh?=nd#@2K#IFmYzE z$Aw^-ob4yl8RF2vT-sfmPw)d=CSnNz1XHVZ3W5UM-nTsd+HovvrnXJ9z6N!+3fJ~o zCkqgTDh=MBz+dKpYcXl}xSn5S$Tt$fu%_lr6-kd>RYjP(4(vUBz}(wZ3t7$BK1!y3 zN?dN{s;-y{8w=)e9bp(8bq10Gh7eHV`XxN8+JY*q=50DmJEqxfon31PRWnLL$N9LM zHtOBl?Yx6-nHPxjhq8s>G3%u5om>07Q^wJaT*kd0 z4qh<^01n(~hvPmjt`5NR49|mJ2N!Tob~ z?Dg&Vr?E0ur7b9*{@3AN0=?;vdZ@oKUS2ZUuYdiuRaw7k{o~tA=AUYP{+n9=BjU;O zu~*Dc9)e!{1hcXe@a;aTEI@wWMIA7kS-o5ENb%Kq?b8>P> zB`uYcjm~>ZK7g*hPBo8Dxno;a`$uj(e15Jl-Y4)K5)g0(z0?g-k>s)x=RLcfH+LS6 z?qPnH0U%HBY%3?SMKPV_kY#xl0YJ%hI{(n<@`V8!YZBAnP!ixVSCdXt9TrUc3Z9iz;-!a;7mX4fCBqC7bbS^s;mO*R-Alj zh>ToUAOra&N3&7qZNT$IEA%a+`(>`!r&|5mTVL-p0oo^ULIV3qj%h=m;UaMc2jVe1P$y z5p-#!u<0AEkRezX1-s=1jy6yB@!ZguHuKT#cA8trZ`-5g(_0U-dTQ+3!b8)5r@;oN z@Noc~16@6Er+r>;=V?N5bzGN8sKge$X`c?gPyWW5m{!i&(ouSuE?wf67IP^W%HdRvXypb zu4l+1!soT1>!+;|#&Cd+E_UDP_Jvqn9j1bvp|);Zk;gM&meE7CISFTi&6$B`m3G6B z1`hNUKWPnqjpP2I`3h^W`o0E#HeYqv?%70bx~RoI=E+Kcyw`O` zzhSotYmS~voTqGo{beY}9Y*%XDBvi~Gi-WaUAE9l@ef&$>RVCDfgE9ps_7tN-W?HY zFv#TODI2?2hr@&u%r(;1%2Q5mS|4pQ?<{3y-X#@XH? zQm$Ao;%>{q4PA$Z%F1W|^pNn~bTv1-?lJa96a&7enT;*MJS2>X4|I7wtQzfDD*V*h z(G7eAQjY?MGPj|76I4XztXck{-uE^i@+XhvPsI}lBT}*B*RouY17#HwZ1L{4b3w_S zu>wvRckt9%Tpy(FUW-h*NrQzs6X{`AXyK~ebn$c}dC-+4_1(iJ>U@3nv_crRibHnG z69w$SaAjdqjIJ_1CCfd-n`sNCx+U|KBpAFryQz^90ZT!W&Y|9O*kxNZg|>?&UdoLa zeJ%%E^XZGaLo|^n=}mCI+*h>b4I!f%fI72sW7qjN=`i1J`EqOPGC8XY6+O3+TF&}O zfrA;$uEuIIb{INHkYdTPKJCXe!)}!32D?ouC`DR`qci!`_Qc^t*;R&SHGZheTw6Oh z95FmEsQ|sWHx?y=L(~RFWjjOM-3Cd&@^@8#cvEk80lm@y=0QB}N#Z@>lTX$JCSn7Z zl)J%a`U}Z$?SWYDDJV^eUGB*I#HZSzJ^;~U!{MO<9j2f^gi8yAP=F?q6p`qUmfd1F zxxL>1y7E)=^~=S-T>De=bp=3e{!h)<2=A1^ zW97qKLw31YDR>__5Mw@^(qflX_sQhlGV2RwBZn&oqikfa1?hY)$05+D5!H7=e#DHY^VpwZlb2b-$O$C^}mV<1y3*7t) z9T);)?K^E=;&T^d%$*>znGuZHzBjprO)inpE;g9cdU9=!@62{BXj~v&4&0#Icho_U z=rOOBEmpYJrUm&wei-yr%@?80PiG}v-@$FP>^eTuLr=d$mLfqr`XW>gLfJihD2}kZ z%&-ju95L~j{p_%cdYuz<{pf=zmvS_#*_+BqJ@n@_y}#V)sfnKsc~S6jzir?#y`z*^ zYdg(N@$06XA6hiyGPn~hiZiY&%y^VWmq279eyuU(sdM#?jidTHCcQ01cz%POWc~~k zZO`1nhq~zD25sHoP$6s!vrabHMbTbHwfqWO8fm$_bnkwCa-Z`$x*zgrXcdpjc6&9J zPZ%gma)=c?K|}`^9k2j&n}l!2^EHDhgDy!IG|4T_9K;J`aFfkBY5+!GZxM-kJOh}s zTqy%~NVW~Tw=#m@3p~+i?L@~%@g`K4BXU4NzIv&U{06Z)dTn|#vRR&kxk>_r4X#xt zqJs^;828D=qa89;5o-q+bw>fO5kgSj_pQxxyke&>9O8lH1808v1O^qnX@;*3U- zMnORkKK;8env9IftgOACecpWrbw#BaX{Z7J)!plNM}Hmp`T|8<@>aYdKZXCdKl~{P z5b8Nd0VHs~f!Iv7#8tR(Z5-ozzJQoJ6741t9rO9YYq z&oBSqzIx=}y!?Or>cQG$E=qsA{68sHeh60h-e<@F(35B4!b6>Q+8`3sD&~rp+;yIG zoq)$UW?s_bOsq9^FWlOlYbpwH+W`6VzCHPBdr&yGT!~c!%OZj~w1DLmLA!71>lke0 ze4U29+qi^hl`FK?TUkCgRNLGsCK zleJz>G}=taR0evh13wIZGC)B9o?V!hU`jyuOM^jaCe#BUo*$mL9a|?3IM4EBPf+A( zcW8#q;H_mZ6fX`-;4%kd1}mbaQa2Ja8BkP+4>yBl5B`YLuxkJ-V7Dt4=Ow! z76BiZ_a+$o?I``@DJsnEtkdV{YSy)9zpAyt@#dSvm@|wY3Su4hDl|WyO`Z3452Vo9 z>Wxz6^&^JnkXS&O4jt=w$_CHd=!T&D#aDP6r!kD$*Q+WyQ)+*1nMb28y1{HbGHa9fL%`JSK=hn z&fz5Tp~;Kb&`3!=)#!@$_C)+xRr{!U>|(ksVRmCv+(==!OF&^dn5|>E01ZC>EIk;s zy4;*NJdwUjTQ~4>YD_)y`2r{$nCfLLbg+0zjLsJ9+lz-Ht8+rVD-Z0}fB=Fvk*zcN zUDu=xo`E}`Lr_fBPc5M?Zf#67A+7iyt_;TPxAEC+dNWk`SgU^9K1I%DF28Ng|L~l7 zsLLIVCf=jP9%3jX_k1t3B_L51K9jHSS=;9x68^0 z>!a;G&)t?ghi&qwqo;<=?)op-yn-#ScS6yH0_a>ihz%|?^FnNrbK4MR*O3hLQNYz1;Ai-XftCfW?bHQQ!v*$=OMr=k zMDCRl>L5H9Vq(!B&gNZCw}REl8O#g9%W|>v>*4qX05EsoL0kKjC-(4maAt;Brm*cS0eMc%+&}^! z(sP9*OL&WgINLP61b!T_|2+`%0b6r~R~s4Jo1G{Rw)7UkbTI*^^StN(#bQl$-)4{V z91)tm5(gVevwH=W}a&&aN+GH5;OI zaPFwgp*xb@P-_scdMfN10PqC->7<0;Y#nFeh3k=sFJ~Fy7v^omhjQ3FNB41mN)e6w zTJ7-dmTHS_w(4%0e=_pGG>=OI>$6pq7n*HeiDJBHoP6d_N_xkNN$^@EU#ye^cz_LJ zKHM~g3=a&UN_<@=>7_e%z;)jSYqgFhk_{Y$V5 z3m41;a{=iRWviP3WwCIu@4L&9Q8KDX)+XU?@(VlOH{dM6LZ)#gD{bv8=eERFCi8{8 z-dB36kR?|rNZ5>MwoWd`iPE*?1TwhgWgBFcsu3o!rJVsR%>`$ZU6HULXwdzlFKk`Z!BI5 zu&pnj@l;`{&B)A;&knn<3-#SW7Fzw%&)1{>;}%2SJu`p19l}fTn(g_RGSL$44)n8h z*a-sn^AxgyFNVp5a|C}geVREZW7{;XkK1zHQ zUH>ggoW2>D{V7VoWcUoWI{$f;n7wGDi7;1-AyvRe z3&VB|X%E$(RIii31q4%XxV(by`X1Q9jbJPtrLpPF!Aft}{k{cR+kNvaJ)B<`)Yxv@ zET;t?qRFb=c;%zpL zl?Y^0Sn+9Mz&(Lh_x!$9Y;JQmH#TgRT@4n%rsXI!*DI@q`1-#TDUd9DnUI2Mv`raG zHtZ;ttYIN{8~plk2NA*Rpx=C4N^f=HjLj;LIdg+sXH4M_hrRI#ms)FpP;5)Fi!+4V zRI!I$zV7G8Apk%(jVa^t&8Pk2miq`l$oKg35q^GYMLb`NYQn{ik)En{e@djY(V`}a z?et2jF33t-)i;TDJIun#TTQl25)^h5DUbt6a%fgL6YHxt16BYn>o}F?JErdI;ri%L^vOV_HHEo*7;mHd zr8wTjqXfby#g5HR&2%u{6^<*wMr;saFEX@hOmQbYjC0&xj3mex;H0Uyl0OnIL)Grc zsP5{XJa+5F-QyB15~zh%ogUqTCzf#ukdcZhD04s>J};%jkr@8uMKo6JcXq{I4_*iK z_(Sfxa-gW*S*Y^q7(JpZsl-q@9<(!nD7h(;PC^W7A7Bjg&jt9n*-MUArWSMlxikD8 zGG2?*z`Xl+CB10#Wg)Bb%bxuG_rI{zn6UIw&N7LtDjT~=wLJ^$57<(lDCaJ>4wCoRl8afo^s1zN zbS~BBCwmn?dJ^1$+318<-BGlA{5e<)J=OgE&h4lV#>Gkjgq?tGmG{5fy6r66(oW#Bi2+T+%7V`ZyGSAdq#>f4&z!;P({ z?q#4G=f;ImknHZwl0X^?Gf73rY>p`o_rLG%QauSoHv zZ`)7|hZ`veg8x*Vf=jSUh|zs4uu#_}?!&bF1xzF+&7%C2honECSita|&lm2Z_LyZV9`og20uULiKR>T?6iYs-fX^OcvRB!z_}ee!U% zx_M55vE5iC*OXJQuJIr$^m@2w=PoF~+{E&gG-x6<-W9UJ>=0%o_Z@j2_H7{^H(dU9 z#{YT|-Fno1l;&^#Ilo%L{8NCCaA<>boBSg{h`am2%6~QO5V-F_f_Gi7HX7Z<6V;dNhHN1tar3=@;@3eH~%IFX|(J`DbIb+h{V#Q)|AjvxJXmz`#;+&opB zVAb~(B%mP${io#fvA+iiFk`XHL3%sBbpR&;k(CL;z;2*~=YBfm-_Lk}6F*;u4&ToA zc@&yidmsO#=)t=7=B?c(AmZqMJ~KS=zk7n;1c_e~wtGTeRQ`_gv58t=lFjaXKY@8< zS;em18w+Z}!luesC2TsBJ2Q#S=`(~2v_v#q-{Tr8062a&YKvLj2a+Qzrn?Qd5N`Jc zh11+KlZu`Y?z`qf*jXH@_l5twg^zyUrNv@Rq?8vG9gI2GieJ!+YA4)$Tv+(ql0F^% zrSTzYZm3Q&6ZB{B&LuCipANfWy!2OvNNLt92H17CC-8o+5x`L z@&MA5JTeKDz|?mI=pJR6X5wK~a3KK79zaztVjkB|*m_y*wwDoY(k71|Wb!=q0jRK8 zC)w3)<2_@Es_ey6DeETB;DadlT*Fnzc#5|Jr2}<@Om;iX>CLkUSbXd886;HRn>)AV zYCudYRP`a`plt)Kby0-t>@`N`dGOnr`$7}Topb4R6erW%LV~W(k_9JM5c<6Cnr(l$ z9H#kFK@M;Iq+do4pl|c6{W8r>RTfy*HaJUWFvp+S>N7EJei5vU1}qEs7=@mBuRx{D z?p!uEITJwZKtc4paZgFBK*Mr|tfx|C5K$|34L#3)ye3~I$_qp(OAo+!4I!A{z}IuK z+%Dq42Qs5ngoHn&@b|Ma0GubXR6bX)Cl6LxxaS7=p+y*IExb(*y3^9*AWI`493k)0 zI=B28A@=q;=*DaPP+8GI#HfRz2X~Vxg!Rx0=(js0Q z&hSLDN$9tZHP_FtEDGr=9v0(Y4f*f*uiv&Q^Um_R6OCVhG$p4_dAh1$!BjN@sL65} zr2TGx7jM;ySyee$hVkK9R%#jDHZn`^P&~D2k;c}%b?W2Ij&V+FnrGbGbxX6;0*@bI zaD6-~WCN;7KTj>4(5b#`6I1dN%f`#TRsr+3gu{)bq)Tx+c?&yH&U?iLZ(j@0&OmbD zGavX8KpRr_z-c6&NT#kd|9(kiuz24m%Kq35_Hio&`$S$YB7D4929>u@PlLb%icnXr zWXisb=Lbo{eEg}wBA$s~&HE(qIYK^~gIb?f73S@*`UeBi@43S-*FgW6 zKXmh1M4})01J7CIuhy~t#!RqE{3k#lBK~xv!d3{pS>T_4nFN83sQPjsi(hv}Z zM=1Y5LnJH6euhw+G>|R|)_%+s_02^7r9>zOA5*@?O*ZnEC^wF#s*)B%}VZ! zGX<`nXaV~ENa;yb0Z=%y*B}IsHI+j5!%!AypHnt82p!2z&riL7kDoa}2HFlgmMA?y zN%Rz&rJ>0Zc22R#jWCkb0`LJh(6B_RKEWPUdsjdfIdq3BcIz&l+I70j-f1SyhV{|y zRh%eKTMXT{wzzhZbQyE^d%{PxMBThVSY`Xm1FZRwN;sO1A{FXm0OrBb&&&Q)tPc_Y z2!_>yIYv+UE|?dI!rcbAhSU0SMfX~6F#BB}(Kb4zcEaYJu>+?uq=NQ~RiE~YcxPF3 z+KQM08)LDEswIZ+_lvUK*^BU|;+oJd<>fI?v?@778^JP}>xPM?+vpJJ9X;;H4xuP) zDYbn(Io=&Kqx7Z0axWPuZ+NO?MloY-!+Ol-BHBACxxhuVW5sRWX0o-ZQ$0C#uu6L9 zxdj*oUXj5f&!L)6W+&H}ZbnKB{>si4BvLjJ9~T^9$fJ5cxXO0DP|^_!;rdDP%LRGd z$Iz_6$WYkx#4f|8-5C++x|Qtxt)fk*z6a_@o=+^ z?5Lmd7_>&Dr_^I&)927S(oe}L#}VPSI{eo5j36mHPp(ztbg_wSG!GJ_6w_^^3e2Mj z5@y%M=*fSmqfgV5tR(rgUE;VkZmlZkG&O+teuQlBMDIqWKzD5#e5O9~0I>};q`#h^ zeYi?}no7M(t={Ws0C33q+7SmRzFd#)1cF^#unQ}D(ZoIG_R1VDXE(u&`~CMK5hZDj znEdg0`8THv^4sGDHno3qu7Q&vh%kkfE|tWIs{r{4N*9n!^~eDYT{|>I=nqW;AA-!? zR}Rv0)hXc0aq|Rdef#>NO@Xs|Y zhB0Ar1O;t~1=PX7NLp-{(>*}cdP>flHiuryiZnu!vK-Ykb`-VnsW{{hn(4Rfsb5tz z?*RytfmiWNiEO(Ktm3{o`?Y1-uBRTB=6QhxepH|lm@=I5UbvTbt&Gd)f#dilyo5y- zorh^fnfL=IIgEp8gOVQ5y&4FYm|gJ#*6jOo!J)1eUdTOiqEf3m9jQ_4FU3veo+)fk z0h@CTOWUjX!tW&_8_;X$Z16*U7QxMw8qephHp^@&*ZFdPI2^CWsn-ZqMOKXnJ;u#b zO$iDV&wRC%Id77iD|TSQJ2S4LovS3Hu2s+`+X}nIK(Ij4Up4McaaBTZQeUnxwG}s) zHRAKI_U&_xMbdctU^;X+MeF14Ni(QjEUX(p?m6vz6}>Yn9nye@3ZFL;{PACDEBy5< zcJZH51NjOIjU2d)z3Y^DF8SrA_8;%v|133_zNZGSbl}wq_>mg8EU^{r=>Ox?!1%AE z27=+^Dip^P3^GjDJ<=$h98cC%>4(^?r8>ijVR0z;u36qQ(b93=ndCb(gY9UWWr%RD zxz)L$fq<04;AUw88*(~!=i3^rLC@&2qlsmKO-usZuo~6}*a)oWm&!#LD*~gX;OKdG zg(N9|mluc*{;O?}@=&fDtt~n5%Mz&2iF6@I+ z^red;dbjN$xwslSoKI~p-Q{B>v~o<5%oQt+v@tYDLxOh3GkO}6P8ygEyQlLp?oJ0u zULC+({kmH@TDi7e-`<_Q{TT?lg;qmS|EM%RBUc`6`A$$(K|`K^c;v2iJuMQK6n7#$ z9jnMa<>UngMBS9{&_x!lAwARF(To+kNxaqo(4VwX*9Q4W30?#;+%3(8E?~tyVrXU~ z*L{`{<{@fy&+#Z&o`80wZsdkJXmpU}2^Fb=wg+gZVHITkZF13Kq3@>?7D*!}19-pvCi!RSdhzH&EZ&rOQOr z$;;52TpA1dAty;SArE0qUmbr#^e}qW+s_65d!GWr?-l5J zdwT(6ncw#&z7`)}3ybkh5C%2CyygHJG>5Zb3%LPLgKYEummh!kT0@t(F$~}bf?^B= zaroRtho;B_eA$Q1dw&RdHHe_cp#GQ;e`_&pudxgclEIrK2((5+@(UXta0d{O&mP1~ zCV+InnrNB^7cip<7yIpFHNwv|4z7NObVzo|-JQ5Fw|XC?+m2lEcMvR$;7rG& z1xcMNJj{4+9M!CEoNEvVd~~M{$NjBA)@5CKeTrjovm`V=fYA0p?Kr$>C02W}z(kXYh zI>4LBh0Z;q9>XIG$N(wU(gh)}A}0e2H2awFb)u%Zxr*^37#FyuZ4TkH+$PMTL3&wJ z`W*+3>zn%t;Hon4KJ7L*t8I63Td^)d+4$(Zo4#r7{CRXQT9sAOP)v*Z3W&`O)EDmd zxuPRCz9Y8-c~)lmWexf9)k2R$SrVDFwAU6rxsGu;?e&%8pAA|&$f)*MOzFPMhz4*< z|G511X$CRxe?6`r_C+>`hJQ7;`Jo*CH)DPwc=e$5k5mgPl3!UCan`qcTK5DoG`R3J z!GU|)L_FLVTpUnGind6W)*}X2Xv0Yc?QLfa#vJ5V4~JPT+@%5eIvd~4zZrI6!-4}$ z=HIx&#;|jNvmscsmjn5>+4b$Q;{Wz5`!8&5fqH|)Z~|znPw)bLj%sL2d$d`(%3woO~WY7GCj$YT*&DaW*4yK z%^ozW)CAZo=<$bv2xjA7gg&Hr7=0|o)iE0P<>fNvd-?{sw0r@d&@-c*xA$kKEuy23 z((E9`3}|&qBBXhhIc{&J8EWwF5K>`R%qFBd4Tp`*gHTiQ+VQK=<&EJyNFh^Fs3M<( z0~lyq{!)c?q?_+SEy&czRmn0yVuBXD&R&I6iU``Fyru&j6wYQzC`ajFJ5t0kUJIfh zUeTU+r5o2fKirDuTJHvQi*4LJ@Ot{&oro8hZ|W7bhodz;5QxT~r;n{Ib7Gl~Df_!a zX_nxZL$n>GfB*#JnDtP;G6p>;j_`Lky5ITv{I=yBiF|Y0^rgE1_~H;OBzl{PDA0f_ z;7s7@_J;Kj^g{qw_)&GxGvD6Of8g%Fn7Fox_bqf zjO)zy-WR^RMkD0H*Ouj0&U3pwz&yJz2l>(Fv>u7TSG$Zu3p**(@ftaX<&Wr<`Y%r8egSLfttX1-r(Cpj!8oHrfAHZVdbVov#I47|g-+F`7#KKV!+xUT$G8V|q_kNw{RQTle^{Gv>MN}7 z|HW5P+x|uTW^?P~==)QBDS+q^a)r;)H3v4#fB%&WEcxxwlO0zy=S?pbtYYENlM!zo zH0`zXm!U5-csVyFNZ9ohGmCh_bjtvR&?hK(-q?b6GYcM2CH}tH@OljS@*o_1KZAnp zvV01!;rgs9s$H&v^b{z>;g>-=WKGt`3j*6s&@jMat&zWjf&awXe;!Fxz%DVkFg81v};G!ZsDUrrzb8BW#YBjKg2DZRhUl_ePnc(bZ3FavOd}8 zV(nYB)+~sC1ffNbKGq`LF5Qa{-ib1DLQ~B$3W<$1FSvxMd74Pd9rSB0uM(5x09RW0 z%A~@kjiqFK04wF*1az@}cc-tG?&EO;h(jRo3TqSTb`t+w6$_Kh>xQnAl>({_C{#0_ zqxN!#+ZhEHMIjWo^J9Gt$2dOdfJ;cNS5lfr?q1aLoRU`pUPLYN{ruf&{MfBwm(f%BE4@oRQs;xs#)`;IdOF-YpnlaeNXg zk*U>0e>=oN(6kqT1|P92^sIEsEve%K8Ev(l4))=Bq(#U!C>q}<&Jz*4N#9Y~<7(Rx zw-1)|HZ4~7deOlLTONz(dH{st-3#xq#0AR)xWTCLklL7B+;%)wk8#(pU4S4H?nXht z=6JYo8RMUNUk)@2y1&5X^RF$KLjbAwnjWuzII7-{tUsPuk2y`deWqzZd(4CUS5=U} z`QJ{hohyj25%(sEnZ-6hm$A>`-pURy?IKytU*p#(-G3NPIB4%G6Y;rlVZ?q055w}c zLUr-stJcDDSb2bXJn|u^`LUD=0!lZ5(+hUAglg8zfb;zPSU8_(;6{Ir4C(t2jfAaO z5J4z!KNUnX{y+WHr&h4Du;jHFtN2hT!-AJ8zt+}vhXB4_p0gSgs^|Pu7xS;Ya6YVX zK>oY%z%M8llECT5t?!{5 z{-|1Vzg%wdJUs3B=RhyOnw{`)!bFPA5T?aZx*iMNNluPSW-cG8s9NXAiHS#14j|=P zhYR~upvInAHAGG?fRVaC<^n1XpcrGxY0KDh62X#}Qs)$Z^t5xmmDCe3Il1+Plh%cD zzqwMa#~o!IXj$H)pzIe(c8QKlzfQ=|z593J+mfgM}@>aOzF0fW@F6O5^GPE{#u7r}^C@eGWVvrZ6}xaxf`F2;z>a z*lkUU1%4R2n`pCV=L7$_lEGbG-WlxcqD;lX`dpuK-=vKhC&Kz&!HHaE`-tK|Pe&Mr z-8ZSl=DX5D?wWWx+jyRvd9?eV(%%NlNDtS6omn>!;d(D?rc>eRo|)h*FtFd*#2{|=lN!*O6R=$RrV4PLls%iAsK>J5jYkd?{H5CK zFmGZ?6C9@2!>OXGqr{w=c%1;9*)@uj?Yi2OEl1=kTPiN}f}R8;ePG2Q7Ml`UZ1Gxd z5)l4k6&^_AU`NLk#o9pNq1U_QRSGuR8+EFJP(E7uND{kKYa_XKB2Jsd=E1YUVF@kZ0BB|qKU6;h z5Q4t^AOwEW%SQ3-G@V@(ZP6M(X)P7Jf)8Qg9}iGaih+bI(?PflrevEl+iQv+KC%5J z;x~fG9@9;#UcJa*@0(1MutBzW*X?S1-zUc%8d}42u4%OIcR7I<2;lf0hX&OeaD28Z z?uwp)chb8Smqysw9d@LA&SEjTDbk`?Sw~s8cx(gCQb`i6AE8|Dt~k)UuJ&C7fc1;7xWXhPeHa9ss|Ne!+2%EF3#K7oK+0jn=in5yXa_0!w`TXx|X8S7dR*yf53d8 zL;KSOJ72HJfB%C00R@73M6?!~0W#WOI^@1pLaqq>3gfw5d^qHaFB_FPjevcOB^cyx z-cn*PiUeIeY%_#^Lu1CW#XT`Xila#-8q(rbke|5E;3ly@+YLcimxU;M4v2Q#-j0aJ z<`Td0*8c4b``~|%M!$E_^&VhU`jd+;!aFzFQRAgx!7t$lYjbCFK zx0nf8`hCs!%wrvQU;t08Op*5)JZDN9U28$>0@K;3@xp^f!)jtKu%viQ!Ut7HXQsG& z2p>;)FM|<U6%(t>el?5AABZ62|CEb+ z?)EQ%by>c?H-9-Y|BtcY-!w|a{hWd0(MLS6?9B>v`z)Baf*KI4vbh@!3xC;1fb97T zrvUlD1oIQCy`8+7%T~T;*vTNhHA@w7AZN@14$Ogb1WH(o0OMQtM;bq8@jfVH5moYC z+t)m=@?9S=tALVO0-ND(fIdcfJNKdUdj4GE0NeQG<_fbfklrTnHGM6jgP;zm2`{ZF z++!e?^F23bJ5{tfUj(qjQX60-rC4thaT1*9fzoY(4Bmq-hV)AFKOdX_ZsH<{2eSL^ zn3<7bpY}&QH`9`>rv#gPZy!VA3Ki^1DHd!1NOzc*2{3#kzt;v{Bzu|fZzZp?9r)_0 zB3Y$M3dvpj{NOThZ0pKDR^(qZvULB_@Q%=c*y67ZNcRT-W1cwqFr8I-JhMf~vtT zxKW$kGp^+u2LtjeE=!<-9TZ{o27%pIJm2_-e%n|2N_1oZcJ3Bs`T!N%=D-{;PZn4o zXBq%v*p{4PFzWH!wlH!j*bkcxivV+FG{^E*?fYa_C2y(=4cq-#wJ>c?q;m-a_Lv} zvZrXr=%@W^0S1~n3%dD+8Dzo8(zTP{KSQ5n99=K7V{w}!Zw?hq}leb9z7RW8`D^m*jIjFGL?EzGd zbzAodI9zk92HS0xi$mdA8=zU=(K}@0(C=X^v{aIN14Dt_Ky&}9)x)VnWYBY9%80_T z5iN^a_t`A46aCPJC+O*c!pSn5r$~iu@i3&jv8&lJ^t6Y2+q2rpk43?(d2+`+cfE`w z>Qc{cnQ~f^8IWB0%y1%zKCnT_9~LM~xD<6cO+I^pLErV#VZPw`iXOBrc?AHNQ!z%j z)V9UQ+>1RlZ4RsSL9&3LOLqnEBn3j76kojnv?Fv*_>gMg-07%2VenfTjPu}xHXAcg z7e%U$S?ZsHisy*7l;7L#FD1ICLv;UO>3_$FeKey#zW%Y`Nav>XV*Fcx(SS6KPa#0l zJstZ^fT_M5tpEQEFv`THp8-aC1(<~oGegI|R3pp_J7?bGP{1(c;=OD|cigV7(zxTHgXSjcQ>)+># zuN!}M00Ip-_a*`V@G<3|%-UF)G_)wzYZ3<2aPSi+yl28SdOYdqu+4q2o_BLlA)GRG zU#ZA&@4%Tt4;1%#OFC~Y$_ceQ;&<=^x=^I28I;{tv{FAG6PNBUKnbR{H-@`mae4FY z#PT=BVXfVXbu6VwcLO&n6jp(VN1mH4yTn$Ju}=&zr-8{3;86xq*~zrf_)y`C0jQb< zuqy&0B{nbaDhEvC+)*ZQI0dj@IbFtb zYiB5w1ts3fmEE68c?$CGP>yT!_B{92O%>YWgqTNi&4K4SEOXw=G=4l$yoTN2?Riy! z7YJ42+$zYQAaE-!;Y93O(pYF$BXB?jHrC!b{+KUjaXBCv_`m+#dxzED-$<8dUCpPg zMwiC@2nIYFEdBeqvSk7ZshY(GZ?_UuM(@R$#Tc-Xwu{(hEd($y`P?0PaeY3Lmd~8U zVSF%$>*fRq@k)TBf<|fMo#D2zm#|L-@^hdI!Gilo(9sLF{uXq8teOqpr$7qf21EY( zjj(g}_nFu`xYB->=JM*wmjlonbiCeQgB>+4u5?M#I+GX(hQ-Hm5#;)pM#)!~N0uWwXRyhxwIirzzZJh&9Xka`&FL+;9X$)b zc?XI^Q!v52vS63Pj#rMNVPJH=-2UL6%11x|KIQidj6%=RB?bf4zv|Opepo^8vLvCFpo%&h~*hjzP#K`E)neL0S?%;Ah&lsfD5`A zFe`!RTx3hbF$VQhE7E+XT(61+*a~5=$mf%Fih}g9nOSX)Lt@~veJtfBW;4J~S7 z^?+LIiWo4gRX>L?l@Q5N7tWruZ@Y{y?F@Vr1=L8d2HmSd`CD&Nlvuc5p+dpgS96Yi zYtD7k!6zfYBML%B)RkABCiS`4tTqebK+_T|N`kwQ-NldVUcz)))l9JZNNU)EuRP=_ zNdTT}0MwSPvv{)sMem_>49sDrA&p8&zu~9kWNN;Er`)As&AVZok0h+OUHPzeR$I`~ z?Jdy&J)weZqgxCujqFe?H(GW}EM39(ha5|yN5#t7jSjbzKmn5|weohw4<`GJyrAp? zE;s4J<+zSu&-Vy?KB@>1fklTvD&hhBs;|w%_5oXjHx?}97TS2yE8^xEDwY&NGmO4Z zKCh}Jd50P{oDMs^u%l($uv;QAd|vXAl&N+2&Nf!;-sIshd|AL|d@WL4gR-vp}s4=JtT*o%?S9%N99ouv7!!AM9xj9nt~b$}3Qu zxY=+JuDhB?vrQP@zY`ojfAd5I?wDi`*ICkkxn{DKk<)B`RJ1^cmOBg%Zh%ML5cs0eSxdev1d#DVK8nAoDI!Y!29Pas3S zUysX|W{aI)5b&+%d+*0pZ1AuBelVP{zygut6o53%H}QNA&x4p$8Egfh(LO89~Dj5HQV&$Y^bZHt9Zo#I+(=4EEav z0F$if(#Xox-Dmhwu-28(R+Uq#lIq*70F4s9oBA2) z{!BW0zCs=GQF#3>)G^<>S^sxK-8UD}XCGc({^Osw)O?ZuOvZngO1dG0Iza^ATOi|4 z^Kc$CmGI!}v4Z>K+xi~Bk^dxue+%FlaMa%@tPsJ$s`a1W7Tk+}18sknMiy{l;Tu#i zM}@PC&l4Tk(YXEyo+pI>kiDduYj=G)chI%SyW`OW2g$PTGQYp!Mvkg(BxStmEP0R0 z9EZ`6MQ4K3RSKjoxPNv72F_B;NscxbNv(Nnb9y=`+>N(=N@K01;Z<^bEX+v{QTn(9 zA+kuifr9#bs(!9_Gf=x;2A7QRRO{IT!_?SV))I^Rodc%EjelgDXI5K7R35|6YSALs`wend1wa*XioD6HFvg!5SQ^`1(v zC(9ir>pa}GO#uH7VY)NAtlgl`yY_^6?rl#d$hzWTOCC&-@w3$&F=ymz7rk>>8>&f4 z)aITUHdToA){?&1R#}0@UZ|lK_2zbkHw@yN^O!rw62ReR1FT^{xPxLKa z^qkDNvBNnhzZ}&s7~M}7@hi83lNta6?@?wB4%e3z-W%2Krvbe!T!rY=YO4XX~*UxC{C5&}Ph5(1m5@msY9TTSz9PGV(#oWUOefDe-g51%I( zlYq1B&zy;$N<{_G62A(5&qC{Ly6^GADiTz1&yjD`NP zvI5^UdZ57^?3=P(osw;f9w(LGZb0L#%lZijFa?HrgpThQ4ld#@6C%Kq;({jSCPt^LeS{lwX03dTxF zy9#ynsl$Fk#XB7g&yOwA5h=#PoHb}b{+B2ix=VHk%2u5HAx#f##5j?;{zH|wJ$9Qq zDgWBmU34G+`hVV3uk8Q(8e;u(#QRfS2U!NJRtBGS9VDa1_q<2s;4FnDvu|R8v;PGI zu0mFus-WM$Lel|eH1B#wAcTvbGTZMFKBTXUr8P)&Y&)-aDd%BjzQM|P^ph5m>hpG{rq@x1fG2pFPqyT zNXg@cX;l6!fV^#j>WR}G?w3#Yh8-_S@R1o|F%a|=7QS87dqe=n{L5ShE|B*J|M=Pb z?xTUv?7#lm{O+Scz=-F+{Mr2OqnY7UzyEAN*`fYTYxq`OerF5zuzL?Ug3e%sRfA+N3iZP+>*;W$OP;b<)9btiH)%GcNRf#Qcw#G&}iH%Y{ijdWKC* z_mv6IbSj@P9GFDZCfqfELhNoMm^-nRyR-}PX()|#Gr7}=J;)5&j7PTWXm3*=fFK1) zHDF~V^k|!eWe{SUZ}~?ItX@?i(KBD$6tZgdu9}G5B2h^Hwza4vf_?Zrrnu%b+Rr-fM;XTgbWoLNH(C(YeXlyL-v>Tb1d7vZ4hu5LkZ3c9IN+fD;$p=H_@xA04QS>qn;wbf6fOrF zu$j^XH@kd*AvesdfhFZP(BXKf^0R_25ePcL;{76xAYq4d9iU9IG{B$X?>j&-PT0o3&I7NK7i_*c+|z23?ExgB#3{(S>oU1>tz zKa+C;K3H$xIKP5t4R5hmW$+dLajL!!&#yu=RX)R>04yQElff_T3{N&Un7L_20l&4@ zV0tdUervClE%56GM6dw}tqMM)RR$;S6&PK2_{;!rI{!ckJZk)QekaKLTVZEO8+?#( zuD^J~*#T~E_>5-W7SMS72fQWC^*Iwp_MBURu3LK1!kQWU1)tm8$C@R();sO%+iLF5 z&@RA@!7o99e|TxC5ZsYdu$*}Dx@H}~`}K!d3(kd?O3bff#)Zv40WODE;`t(|fg~V( zy;{2k@3H$kH@}4chu<(WzG2F|E)JvyiQzhee+<2Y?f19(_&TJ0&1l)TQ4P5FsG1lr zAK(&)wpk5U&pQ%g2}CClokQloWUvXgA1(t2jf6`|t5jwr49E&FiEIID3=CzBL-=6I<)#UoWx_KzKEC8fg_67`Npz^B z{FVF={e!Tygf7q027NqJ_Ca-_=|7(3X>p4s39_r@%Jq!&j_8j=ZElzZJe)w5MpD#K zX9083z`AP-Hn|q*WLJG*jn>)W)8j#3^RV<0?2Ni^MYA?`mnk0Popn)-oq??ROu4(j z1FG`{2DHF`8q$6wPaLdEU5~IW^qxL(|0aF{B7#$(Kvr7A*qSY{}=)$?fIK=dKuph+85giniK zeFBA{@M>MrhZ73K32;)ubx)EJQNhW?+`%zrfZpTm+y{{3>c^8yz(#>XCvsSja=aFm zGAl1L#D^0b22M??9N-D7dlX1z{6qUQ8U=_>VTHvgv=8kMJO<74_s2k=arkJK%xMa^ zVQVT32JH8-nF!!|)w=p60R7-Jx1QR>R&xn7Z#F6AkJ}h#!YyQS5G~%$W&}3!&j+G> zi!a3&ua>7_|MFE6EnvM^s7c@U1$6JnlOz7VY2kzZnjiAN%@0-i^!-+UYdy%@`L~Va zmd<4s58fwk3yiK}sMo8|z!dv#f|(gjKcHXD!7~17_0*x^{b;tXo&W2&OrW(tqSWIMuT za<(-4?CJ+I*kl_&zirQVWO0?JCdbLZo z)e6^!$EaJYIx=w~@9Jm-^{OF3xEJ4zb|hQ{1nN zPghY^U(db{Nu;F@{JsWcCqGO2S0Ne!02%jtfbM<-XwhE*o)$vnmip4f5Rl(SDQ>kF-1jbq zD}sa(v{QZ!kG+~0fKm8-4CpxRtHJXw$_ib!oI5=KJB=K8rSAqnPvibk&&-V+>8Nlc zWJuF7|B|GPW%kQx4{j~jzsXi!jS3C{SLY!MOCC&DSPC5hBrNM7AnQY3D2M~LE{8te zhs03FTktj5?6CblJHn>;xw^^KLFqi~1_qVWg@T2ABml8a?=Pp_0QPA6OAIoQj7nKS z)Il$Dws`_1i=wkp@Eqi;Hz&HCC;(hWX>>n1+pCARVW=?|vOAU35;;D`M-sXO2TEhj z-P}`s2q66{Ee#A+s82H*DEZegSk?iP^EO!iRfP|X#MfZi{JAIayU{N65iZbe{xbFz zETBSHVvuFp7O~4p2|TzeJRAyXpL!L9KP87{2GgJ~7wju7&45D-?SUt-n3)Mg5frT3 z{U6@mY)Nq}iPpa7De4|O#vlo#OO0p-4QSv_BbsL<#M2)akr6pmR%N&KfBrTrvrHNy z5Q+Bo?Y`ExDp)w-K{!MQP`~M=)qkFMJ(wHA(X_w8p&CwEU*}#Q`UuMp`F3=L6R3I! z;b$!8i+TGxnFNbott%}m00Dq%-G!WOQ1xn=kN^4X`*C82?niP1Qk4gZLXZRb z{)Hb+iH|E;EtjI5e(oIzr;h_OY;PH$Z{c4Ry&Kn^W&)x}yJA-Xny-s`--G)(e8(|D zhXlODutC530Slx16Z*Y;;2AU>fQR+P&srXX7mCo?Rk!e(@!RWu`2MNd>I$C?bS)bA ztkRDjjCOy^DtP4pad~eqz%S(m#8!eb0K_#AeVIbHqmXTIV%gIj$}RXVA=KY4RsLH) z6gHJ5^hG1J&e=E&Ba!rwo^Yph2M@Wve8?t$iZ@}hUTQhyoZPI}*Ymg)6KLaxddY3l zXfk2~kB}Sym!Pe&yRrzU=CQvw=k0@t5qyj>Rh{n2cs|>!`z-GaeSm@8V{3ucFcyn5 z4;eMbf$p)Jd=Me3z$wqTAc>(>@y=!@02}@=h;VeTZ2tNjy_5eu zfB4g;%qq*Y@cFeVYk(W+k5ty~Zs7d7#bfBM@7+I$o9{p5w|$A5`HT!cPIcg0bl%Mz z6zhasOYfBDSKT5On^Vr(Z+ z=6~Ceb+CcM52h&|j^Ybi4fJgA{I8fsh_qjpq|ni8s9%>K_!cn3Y~l&dH~24rlQFsd zn7@PEXL*ddzSI|sE&AmjFYi;oy!!v*@;>C$lU2L5oo!+M*R zkSGfaWaqf_MY`=zC!!3PTQY68q{j4mGB9#oyL%S^ zl(4G~d;6#{Pk~jiFgEv`ho4QrT8hl@jbL{GMTHlSfy!I^O zVW1d}DgkX-Ub%>x9!KD}sb?hVM@e~&w~HCcYouN$>8lEeK(Y?cynI$2LEA%fW7wdlEmJ0m)3$xyYaGw808Y!qIM zRV%%W-Mo4lh`9+NTMQ&2BnfVf8x zv@iSpPXcD;cB!-N$wf6#M`I~Q8hvKXI{@nX3iC#Pfw@#$k}4(%bUv$^j!xotGGVp^ zlSUA);5*a{mh4?nf{X22+NsR~h7bO{gqpH2dieg%ui#*P`#hl(T_P#!n~;ow3cg}U zpddd4St1J~8-)V7`_V{V7+q3+9X4vQmobr3svRokW_ldwfm7O!(d2|EN+DG53$&28>K+ESL+QpdDL;1wc zYwt9WgmHSN4UvgXBv zIHe~&RXTpJ0q^N+jOhQn9_v*9#du*je{q=T-@0D@xEnynj3ysnyTLyxuCmW2;h3g z+8l4s7tEy6mxX{?u8NMw+aMksn!H%9>rTnI+K;lbWrz(~XsJapZeR0Y-?a|gUYWxT@X9EdkVkmjdqh>b zt5Ih8+d;4xV20bujg6*y?WRfm$XWin%Py>gqM_oTo1@j_!WzPkTIY0Fq`qKK2;ku9 ze~*1xy>nkwne72zxdWg};H$~}+9#UZd6L2XC* z&7}T#yZq^H0i*tZe!F~&j{Do)0$(q3vC@AVLVqW_{PJb|zL+zjj2~s`(ty0R_Yw-7 z&*6c5QHdVp6zURFT0%ln4Osk$WPuooi703ejdQFSTvcR?#1>(kp4g{+8>?KY5o#WRQ{tmK~1Jspyo6UYUH zl1q~X%{(93j-r^RwIh14Ew`!F7n;&fQ&2Ga5$lnwRx_Agz@udsV62+fBkyed)p*1I zRb30bD)5p-Mfiv1{LcznW)UQeKLkwwt>t!wnHW|7W*;4%zeu(t0% ziu480_rqhLEnofVt^f2c{_xJ+Q zB94%r%Rp9}GFE-fkvApEfN*pMy6_rqkYLh^+hah$3UPbp?QJFM`t>mTJdWVEok>mE zVLj<-w}GZ_a}1-ny&HT@m{{svw+=Bdxhw2p*~fcuI^4&7a0a%^%#0&dTIDK&Vcm&A zHi5+gNe_$1Y=;C#5nLuOM%a0tgaUm!nJcopqUPniGEz;S3j0SpNss5(C9x{<4HS&ppkGJ9e ztgJ5AC%G3+BV=bXQ3r1B&2`J6$0g5myP>BR2pOAZFNSjJm?Q~-Jjt#Gh#&xN_cELx zZpd{DcF>5KWwBU2;egY4Eq+CB17bz_Jc1-l8*2Pw9zz+k9jC#FI1iIZ84CZn3vLwi z61H)9Cn49MYAi!^!Ia*jPZ1jR*1*&1UeWBPpxUeuyoMUYYf|_Hu{Dj3CA?u&U+KlH z)X@Yzl?3Ifb`gcnxKyeYNkdc&gC_Yv>so0P2ktQfV@hemU@7!s(0hWX#sq+p`>Q!USfqnD=q(|7m8Z@V~uvl)m$CA1X?Ze0pxsO7=F zvaJ1;4(7J)-Q@KgD&bC{^N%Mym2~OYKuZJa{m-uKuZa=Q%W=`2SQR0=QfDew+8`@N(P{MyFEsuuT3PF*b&us(|Uhy+tcJ(vL1*| zC$8$gl)2VB$~+2_EK9XdsKIN1ZcIq^nTeazWrGu!PW2nUR`YUw%9AF=CEL_%qc3x3 z(pqgdHkgp7o7JNlnl;bx>#9cf>RsJdH&CLiHOLIow*vx@C>puFx^UCB0j?Tyj6k$m z@5RN@M?18=vr=|jKeN-&Sy1F}Rej^I@_yDe$QPdY1yc z?oTW+(nEj3gRM9gm5$m z12h03C<0|Ihk0u$`Z(nWujEdJOD302fC=yR2lL1ZDi>S$0W`3*5gz1X9c_smuc~S=Wp2uM5n^&4qNhAp)U?(YUAyR8NCmrAqYt!UKJ#He>v2{hk8y7p~Kw6q}KiLe6QDBul%AN(1}%zaCWtv{zv-x65F?ea#J2GNh< z=6^f#3fyNJ>_1GNm?g4z=`v}L0IqQPVHs?5Z?m_Ie7+c)Zl`}yR5ABo2DMtpr3LV` zmk)gjivu||SZS8GZkoW3{PzaY?`=QJSA*or`9_>vMZGv$VqpaRczG;~0uB2ZH|do# zFm|4z`w=&hP$vtY+Ln?O3?Y}rh;~lH2H`X~LM%p+R@fA%b%B{iB8Y>Uyq(6cedtkd1?;)yr6}xLF zk?UjTR$KF?!f}6Mj^WwkZymVfnO&_?y9#zK9L5wHmZ9El7NbCCvivrqdu`9Q(D&6* zG`&&CD(=ndj6>T<`YTDp#TnZjiDY6<}5tzKFaR;WXzaN*HK0-~BSBQDL}D(5!X zcToJXkFhrDGZ2$jZ0!|%8RnhlKIB6&C9vf&$SmGs`>gG>b4%=tJK!!|n7_=o8!SVL zLFj}K9k)STK9C9^VM6wJtS?i$n#Y#Dw#?XV2PZX(gZff3=hP6eo zM1(RYDBK2Flu_5nXhod#2Yp6VAa6HLf|&*A2s5s{!Xapj+(Q_C+-}9}!P2NtRmn`8 zEna${1!7oh-N78M0Z0B|J<2UmJ`VFCueEcSY0}2t9C>@QDkhnu^-Q-);t$l^f^Vvw$bI)zCI_;W)xNNxMsdz^zksRe{&o@ThTwByM8=&EiNT+B#{8r7A62|12_ZNnP5|5 zOy$?drpqt-CW{MT?nu59GC^poh}#fg$Uv3wOBmHx-=VYrzHq=tk_!LSSr#tu&hov6 z&NA3=#kzQ$UrJrsb+n1k_O6s*e*nuuay^Q#83R3YdQtI%=fox(>>H}5cpi@|v{hFV z?&v}U$rKC$V6I0jx2G#MPeD$cHmB*tU$N@kY_5{v+<@j*BG2l4HMc&(vN^JDlbd0| zznm7@c->(uYG6RrF2eUaq#mY(_Ax-Yv1t=rb|&JU+WkpIi6Jrl_SAc|mIsA#dJfV& zC(}7{d3%7nmnPYVnS+;ir=P~w+Z1KD30^`t02ocQ4)U=WD+M(P6SAX}xEV~E9N^14 zRI?%teXu77F%BSO-sYmB-5ty%V&n5F8JwdMUk-|oZrcA^f^1kmIbcf+mq_L;4( z2ZL%W^Fa+Y0Rulc#=0K*0;D%*T^b1cww>pW-A(nl60znKd#oCIJ3s;f1>YQ>MUP&} z1JlbA`Zo{l&I3&=hB1@gjK7??SNc@Bfi;jC2=~gGz5BY8=%{qAg+Ym z55>ALoJVDOl^l6v;JcK$Z6aeI*ip-`yVMLgTDxEs9JEk*8*GBx{J;!eg3@JJQHPX` zA!_exI8PU&qfNv)>1iC(R2}-rBQ6I-zua6I(k4`Ij*i1*`$zeqw_44!uoIXm4c-P^ zFI1?bzdPJ%dHYG+%6Sb3E2hbY|bXS_jIa+%0FonaznAXH(CaP1fS>E>5r%l@f zCwi1yo(rdSryGl}3gZktCLJ4;0-vsR@;O%ZpzHT@SI1Od=ZzxSbbdabj3Ij+lv28M z^wm1Qfc60$`xUP%EM-E55}2VCCO^TB+)@+C!pwgelfpcJoM_GE;4^2)1X^ee331F; z1*AceTpD=TI0?yRQyBOCY72s)iIIw%ObG|ju;WlGo*fZAU9AJ^6?k)+e zE%wEJ^r-TRB>fOl!EI$e3S;oAJ6-8%TV_%uQA$~(y)YjwFA?&Q(CaPQX?uXB3>2;) zS+cfX8JtM-@hoxR2RQGa~n-RisKdl&2QC z*#{C;h~yGVr6=83xO0<~&jER)6_8Vdk86F)?N@5F*^s=u*GcH!dV_93QS9i7k4`MCw>NT3qonxqj_q==o2RZ@`rIgvnAd(KKWF zYu?XSH~6+x%sN$iQF^)%o~2WETbrY-b(;r8Alq(T*b1QLVT%aMiNL@~rlc3nDj$;K+|TH?t>- zT7LEFdu=KW_3Xr=Q0sz%P?ENyZ`3u{6kK0B)@(cXVLK2<76QB;keVg zfQe*enP__9S) z=$GtM%RqMV&2VzQE>l@z_CP8KZP^@rXkUdnoDezC$q`^N1dbc@EwaSsp^cvKS+yukqa#2Ns{0~kz*mBPJ zCP#w7GQ3+Q12+(`M&FYTQ~CKZIGZgW!Ac=N`ff|7`Pa|jzx@bS|MnUDw;#dk-#&wX z`v{<8{Wr-H@Q;4SRb(nCu0}{%FPthn7shKSDC|KuDD_;|)7F?n#Ek0_OE7D=-~qAG z(gCwp*^bBT2apXNhJ{4HVRKMa|4!r(*gcX)=yoI4H`{vTX2cALtH}$*tueKpw=`A{ zcJ)JINb=xZlB)=LGe+XS)@#x~(^`Sn)P+J`$&;MKJRx?QS5w`%=Vp8I+AF}n4LrH0y@bcQomqQbkd4~>cHx_{B_}p7RB}=Ps&+5zcDGUYi1Rr^)fE9k*r{8E{D*KtOrA&|eZQ$E|e~jElVI@x5aXgNC za`4+tdXZefE*-u$^|rDu%x=d=fru22bqp*Eu%h0N;^vhfKc*}%Y%{MW;u9Ti3Y7w2{N`rr1EKW!llwsg|^FG>`9jtp2H ze!q?UPSOc9n)g>0teUk+??MoPKVPu&!@N5j6-aJ<-wSV@lIp-#(t{rP1ltPas(#-x zmLTCD#XhSKwGX=#m+wIde4|Ti5B6+c0g*irbwNJ#h9CaY5Q2RO0Ixp_R#&hsz;*yP ziV100rtm?G%HRfBtR$b0{exol^YT8g4xIk~`{jLJ-Rgh6ydPKpzYolRQmiso%Rofy zBGSP3e*CzyI*yWPwL`EMPs^Z}Fzpmmd|))}N@w*%&TahKLB9j#Fi6Et!$Ns5Yk#fH z+xaBiWY&JFHdDeJd0FEjY9WC!d?STMIu#gDkJnGXS>MzKOMe))SC)?XU#x;@J zJw);vXR?5a3#KaQS-e98UpqpE$bsI?xDcE&swF!tWO2Sdm>62CYY|eXE?tJL&a8|# zUg8_{`E^(;MPJj80%nPoBBEt~t4|V&xLFuo9lN$q7xEfmBpANy?%Cc^pF%5(RwCf~ zYy>o0_3BWNJPk|go#al~HEG(z>yjhv#lIu9HUPPWQ;9Q=J{=A6MzlD|6EBhA$hkGh zM{yA>6hzk_g4LC4QedWiYuv(bCYCP&s`=5ghy17Oq`fGLx)1jx2QlzC9Fr-aAT{Bw z{`d^`25v3T|5E*{jsAujR3Eq3?c)vrG!nGp-wjy(v#I?r3$-d#$Ze9s`Ee9RfgY}n zl*g4W`$tH-YU<;3$jNi{z}A}wF;+z=ne?86a82GkzRJh$JQo<`7mO>&*NVND|1jul z!O1tfPMG@GhMO(3&bEpgiVu{3DHlqlPdq>1Een~Bn(kLe?{Hn$&v~7wJh=MTUA5I$ z=j75u`xWGU`mu6$8*$u$i^(1i8QR3#S4MKd+{+O1VJXhueasw*PKUDtVu@Sc;TpLM z6IZ;vcG>#%gfH#B*iU%14g6UXvXbB2lJ=t0vz#N_L%Ei@8#+}Iw5GN@P3UT~RJ`E< zZjgdcU#+1b@cES1bJDhZ1TZKdZe|b0fZISQBm}OsjvP$#H<$6Y3vU;}z8;N=fEix@ zuM4#?rF|d3sQO#A|JUv}!|6XQ)7*YprtzmXZO~AeU!Ney4amWn! z1t3nKqJ>}&h5ksT0`*a#1Jwk)PjHa=`{rOm6L7yo(L>uD3}+vw0oWakA3lPwjRj)a z!O$V8Q^z(y1k1x5o=l*3@Vz*cqk{SKwU=M7gI1y-$^uV&l#P zlpde+hl^tC7JgA%>?Y=PeKVei%(r3)h8R+bw>YQmY=8%ql2*rW9gy(M~|L zkKFJ(KoetU-LY@mUh*N&>UCsttvV@Jq^efO2k-M9_2Avf3tv{iC1`hj;*iI~^_vT% zZXzAz=KzSXeI)&LOkPYFZ=8*4dIyxpp3K^4T4> z24?MmOe%4p8Hyf&D8uP_%W6HMM5B5+%+(g!q*ApD=`6k1LQ#sgpFs+*CSeNiWRxmb84f)9D=BrV^(0Fu zmHlJ*OjUQKTt!B9Oh`pOl<9rbY`Qgr<*Fmf-Kb|qyL$@M`TS+Wq>`lqdM#crIDcsP z`~0yu7D!M;10Uh7?Mgu7JAITy;XQFQ3I@=ym3{y7KYKWXuXHOA3g0KL2B6G*9g%Vk z9g-%H)v2rPa(5#PWxM&VDt?QKNu`hp3c^A{jqWInNYQ~ zBzLSb_RU>W8EvCZ>Z5Bfl2A;qIG+hMW+_{7x~?IK`^)KGW3N=J?5?aEb!!|EGzv)< zzr6UF=O4OafZtrD`hqZ<;wa=+g4xr{CQ=e8d{5H5oq7JAF__ZsqbvQYBGS=TiqCna z(Co~H3Otzaqnya!OQz(9mg?gkPPpB(A|&gP9kmnTTEJjmL)+YEa7w(%{o@LLy=`iu zh>r3rYar2Dv?hV~lpV2+kOp|Q^kuw1)u5g=%QOn|asuLIm?BMX6ijU1E6AYJc(UB6 z-A#Sy7$#pgqc{|+vFpKOwDG~XhMn)(S>FvN6lJ$fv2T!wPHoY~sz zd%aPbQJ48EWV^&@+LTV@^#NV1&IT65rz(|Yrd9WCj#^zpSWIzWuZzdr3K;tGH-Ks` zo@E`Ex1ERZ?ReyQ|G;ds)`ZXi&d+F<2_z0#?KIY~CUUojbRY(p&SkuRvL`~`yzYa` zqJ4E9s=?cdkOvlb(&otADDPHMljC)2q-y!GPpDdig}r&Ut7@DvQL$f~E3U`(U`fFC znba;LZBlm1vQM~MGFGg!S>~-9K!Cl=?K-lQ#2Z&l$UX zFNLq3xUFAX_my_Cs@t>^6IY=ap4ah#%rSNc_z`ux(5>{C_ga2Ar?yAU!XrLg;6(`) zd!@PucFRF0h3a+?54~lI3wAC>o&SSz5ui!wqImm@?0aa*gntRlXIb%^qT-7c{HN-I z8J0d`^VLVxm~(u`^w`zM!v(V${Inr~ulw8TqWHDCSlldMDUncJD9e8AUEeZ+4;P}I zPu!<@h4HN& z=)yS<&UVlW{Avfj*yq~=@bzFu{q(kBj`?4`>lI|7|Kr>KZ{PLOMfqC`@An-%dSDXg zjIn3Zkxx8+4DV})H5%_2h|m&mNAtWQ3=#vS*`2whB;1TvVT#E`wx5zHExZ zNPEepS;COQbeIz>jqasngnih*BE+2Q`a!honV%sCnUAZParm|L+{dVUQw77`Z7`d< z??yIOYtzR(WOD^F2PmLNCSxwQJ&n7Y^nU3N5wnB1OXy@J>dm!RFjx#y2dmU^FU+V-Ol@MnBB%YN*YCI49r7q>bbq>&J18G0qd)qPaWdv7(NRb+MN z_@$s%NzTDQNChi4hY_W!5ch2Xs)k_a>20mA8~a(69Xlk|-8JKQ%JJgtp<+7SM|1y@ z;LPZ3@Dyz#mR}de5smK%&Q&YJSHr_m5TysO(;bk8n0SXDgHpA3ajKp6hV_U^&Gy^Z zwwQu>ALBBFiu$K@sn-XT9g6cn51Uru2LKholnv6HLx^m@Jo$aEsQ18*Um;Aph9MeR z$Wo%2-5juEKAwvsEc%d3$cAeYo2J*T!%arlA0Wn$-6vGB>w4>p_O8zkHsWfh=eC7` zpiVt24@sv@#gx_wk)}X+rN{CrOV#?`aPmQ(@cXAK`1jMBueJA^Z~PC#n?J6(-Fwab zGM8vHGv2L+qV?{Sgmx#|H=Z|sf1*qNAFa6{mgT?J-0;UW_sb&w*>w9%@P%NJ#SQ*# zy?vkNfG7L$*wT3W=sus=pHFj;>iA27?~lK1u{b_Kw&Q#pDS-gThsX-BhWWA!d=urp z535UX!{@n^+rIVF?=ckkCBYy74&Cnpl%JA*f4H%J&wGVrr-XH2YATs#y^C6?dM-2) zX|pF4$3#9u@0FqrMj>zKYGr0La@~Z?^OTbohNPJxhskt<3{6&i^{9V8ZsM0YJoSfc z-}->-5x3%M;#egID~=9`0d|S~;DOO-0!c?{K}Nzh9;p~@fv+a1;WkDZ6ucrF3}4}U zE6U^cNG>%niqM=b9Sj~zLNzKoxHBIP~Of;?l5UP;lbFPo6Y`WVPtsU9?qM}>O~wlk?0PX zm*wSfImG^Of;n{Q+glr>vRD{aL)0KfvxcV$ogGl5u-*=mAaa)q(r!}E1$w>EGVzG3 zH_W9VMCp7#zwAS=Q;Tw?^3dybEp_?+isJ`}2=)>Ak+IemNTLSo?lfbFn5jS4R0j~u zk<-m)FH|5aN_w>6`V<1yA5KtMFPKTqMuvv32HA%A;A{D6A?6>!X-*#rZrssW8(+GT zWQ{IJg=cf$I_OrqD1HMvGs_SEUDfur&hqI!`6zU~Dv17Kt^cId{Z{k-arJ$NW3*pm z4~=Y}fmqhECO+UsujVdyi|}vErMKO$|9`al_R~uG2#NxnrTF85D8RZ`3oM|%fdKLi zEX!Hxm$(kJ919=|T4&43`>pa_ee-fJo@Yv-4#&X4(r1`Os)?i@yaUlhF)r-AB zp2a)$X7O%o?^bmAe$t0DynHv|zFaNPHA{ag`j-R1SKZD%Kp=3v>z4by(Y7={Yn(R5E zX>$7cl%qKVL_i}Ilx=nZa`Lw{!n{7$n{%W zb*C-KaWy*}Yx4j}>LpMg1VDni0JG36x{Rz@M3O?Xi0cC@w!w9Nt^tPYQHhs({6$*< zD8h6k?z!DHxD^hN?!+R=i?XTnRUc@$*+vdKyJ<=$91bl`B$Y!H?`x@L(vB`odfeZ_ z0wxr-agA2VZtGpaF~;^!>aj;n?zs_LFf2*sc~i&t#m{qA6R4CG|ez3J|2KH}c#KoV=EiPG0ecF7dtPN$Q@Nyrn_-_Y@ zSN~Wze_sJFork7)^k2T}OP7{QlEcsX3aYXNj2 zstR=W67dDbOF6b(h_*9L|WT~-c7S5zQMpk<@1f$~4E0?pQ z{jA&~%jFq{$Y3-)p&hp7;`yoo`0LD@Eb6XhWcGUgXv^ng$k_H{5~bUa3nLpmnh@|l z$V_0-DgrDSuJ@2ep2N7+cFDF)iDE#?jRnWr>y|%-&2-^tbQ|>>NW#1o*Ke!gnaUWN zO1~kl7bWa!k>xB>SWx9i3i+YR`ONG7RaAo_5Co0)XNiR7ihs`MszkGHtQ8@DQ-)Wr zaDz-lfQiHA_7z&kd}Pc4hG-Gj|IU>4?mxZHLLXnPciU_wZ&kyjiR}H&ehDABLjSmo zE`a8>pi`BM5c-CMBv)lG?T8&qb&Y(-UOs+k@R&Xy=P>(%i}mzAq;&wdr~ z_0`^|xt~B2ZT25xTpq}jLPt)9W~+3ceGm)j^E8bMo^UJB0X4RonjRqbW}*%TG^RE? zL7BP)k!&g#2NiMPl8&E z&E&di{cxxjxcd^*{&sJ`Q9pkznKGcUd7j^RR`~P#u?5e{K2@t;+#5e}>)v(Z$E?>PKsTJe~T`pxKTuXD+vFN#bVZyw3 z9vf9jn7w02Lq2Edt00hQVyg!Pr_y45C=W*mG}!m)q}1m$t|8Ds+3NL~ZO?Ln(HT#y zuJWF|g=^$$pPBhA32xLtRwmzH%Li6JMER7au_2u!MygVdrj@|L7}CN) z*H=KkZYHw$oF%HX0{X(wQ~b9y&M&L#-;ewdUG_7d&8T`$2Zt|z*snP`2kOg{vhInS z!%*#?7qje?&OSF$K@0O->Et43n0P*4pdp;fdtp!^N)$I;71oS-AkzGCUxn1>%nDKv zLV!lx+&v`dP2&g(v$LTef)^fpj_*C3H3kL%bJ!y!)9wPc9Px+Kkt45@b$^>N?cn4Y zyE;*rd$MrI$LS{Ka(Z@fYPDTY_8+BAKwS2^D@x@62pIgBHqYBj$NTOjmXo^8E-2W; zhycGZyf7!YKdp3mFhM%a5XMa?3$cPOX}2lEec)t1if~dtIZnt!2Ww?eEKt2I>JIumanUazSSk zfocT;ZsA~^Ev_{dQ_bX^83FXmpB{r#_y>>rV+Dnl*V6k0hS|49tHeG(8m<4h3jd(h zS;6UB&^h%Ay#Qv>um5IgeqRC@?kHHA_wNAZzx9y60+iqC73!^Cfl%CsiR@&hydu0U z71l002oM`ydYFCV0)5y6&T)e=_w)8*pN!E^%E7)o@pk&r4W2?!qI6Wj64(#>pK0tEjHAkUsOT z2p#?IRPCXPW-jwe$)-}@)RjoeVw~*!l!buJ%))`F*vO@)2hGJ&QlAYkmRTRwupC`+ z{<84%0x)$z68Lcj{u`w7?^3uLCi-H__Jfgw|za$I~zi13$Gl7(p?TuHL1ZMDG!_oamV6mf& z!HMWWMTN=R_xErBLwtU7?vHQLi$8U0SF|IX%p?IEonyZgwM}2#F%s7G{doV~k?w

PPkMBq<6g3m|LMKomV4({c1p-kz8 z--UZjpGR0XJv?`wkNYN;`b6pCHl|{VJ`5|a!;|7kQzQvSyPfVz6iqAUY2T;Mq9si&zEj}Zw zT8dT7sR7X3ffVT9)r#g-mrVT%73z1gPV|=%bz>St{a=@^9@8-DKI+%sDH(q~{r~v) zKi0PErH})=$G6({AN@?jiv=IzH);4Z?JeaTT=U_2g~b)hQw~(xRtL8S7%PenYTGvm z6Kpgc0K)~qq7OItN4@TOwt{@1C@`KbZaf3{@5fDrA;l{k<}dG>W5M}Q6Lb%*n5~zDjmX#U~_HecoKnlNv60JNKZF=?=0?4j+ zZ9zJG`@4>xad0g^{8I(*3Zj5c#bFVu!i#2Lt5b4sM?mL(Z#>YB*eT#~f&rTV{fY2n z=P^m}O)nMq$76utg8vVnF5e1ghPnOn&K6w!umxk)!voU$2Tu7-e;xqBo`A(=w*c2o zH!xy2PhwA*%izD)6XF>`t}K4r(G;@K4MoG3dwBtp@(g*SR%Skc`;L8D8Fl^ESXN9U z$t2^gbKVJ@$yA&uTO3F)pqyVmiX{Q*DFZPd!i%0aq5<;59u6Zk1f4%WAK<6s6F~MD zd~QYzpUby@O&wk&!mNgUJa6dZzuNX@AWQ6k1G1-{F%pVLCl(a<#Q7d@&Lrfn##fsV zDibnYFVr((+Y3~1?ai1T*vVPVrvgtD8<>sHo?Y}7-ab#F)QUTWgfft(^lTT1+kJXC z${6*aV(cue_l@;H_FUc{4z{@QmEICI67)bwoIZ+m_$6a*zU=^PctMLYyYLf(P%yTtSaPxr^zSDxs~2G4Ha55WbU zxGdz9OxhdIHHXGv$uP8=CX47i4Waa`Y{|Z2JAWHS(`OD7*t?kQ!$|z@o_raJ|FM)O zEy4ozCgzd0amqImYne2&-*Fp{oK5_NLEJ12E%XO^SoL-{9yiH-d!6>T{0dSFmkvq& z2tCCbxi@=ey|(-gf&JWtW6LZW+^F1NK22P2P@RkRpgL>eXu1~lWLGV2RG4m_FD#eD z?4^7K@a=Q^e7(~O0O!}m{aI1__3O&U8Bc39Vzh2^;@A6iZK%hII%V+VZR~`PR?7cZOaK0tQvb(g{&#==)6&mgmZs+XJ%8?>tgK`9|HIP1fGz&M z^xIem{mw+Owv+v#Uy~S4|7B7AdAa{w-IvvV^KoClFq#`Dce@?fmLKLiBAJ#k4WCA^Tjp<{yj>K!zJ;~sJ zA#N`$zGs~grWR*O0qzIjQnX-X#Xi?AL1TMY7$A_K9p?MI zfpNT_ArUkmFbw((8x&eVBH#4oGr0H>VU{A>tuS)Eww;`hEbfVb`P)l5v>fuX|u7R0#askAQe}b6bcGfSO)o(^bALj{Pycb;zCbE0u zq-V}KN-x>*kEt3sn`#(Vx}WV6dya*1YFS$D+b*Aoc5rtYAOwH~NXmQhmh;C@J?PLG zl&hna0O;i~j&@y0N^04tW5gRnidl3e7RcCm^(1E*i#8+eNO{uRL~O|_y=GmvU5Yc++>DE%Bzn_Nk8M46`|z_AV<#fslT6F z`M|~^sotKfcT$cWqmJ%z>K_}~n2{S1yP3-ecaFCYcp(*K#)r@6rq$OluB;w8wz_tH zMX|!4-A_h(2TW1D5Shup{?A{hf7(3$v`KJ}rT2aK>V3m0d?0!DvUBn^M1lU@2%xan zA4^rp0#k)Wcm_xBcdZIOqUVQ?Xt(sgA*tvZJo(p$EgGZ-Cil(E^agOIkd(3qfb-H^ zp|^MFoP93Epg9IuFT|2T|6AF;m*Uqik7X413oIYpo`^@zGl3z~$O8 zZ^U5kk}wfPnw?wxW<|8dV2-Hlv~<3Ej9t66P12c;L!1?= zWzz9M6zQ**Pzz9Lg|?q~n%5jAT?4n_CjpfHgpJ&cHB)CicM*3)|I=9eMn<0%yDbwUy5sjm`k zKf&w|nE9|?_FU&q$W_^}E++RnL`Waj zK(Ffo2J{xEoT(0uRqgMjgD^+<96Ef&#KDdJjgR?LN6LnMv}pC>>KxE>d?BOLEjln= zg`a_&`HOV$$LFqoeX{;RyuMQm9J5XGNZpIKE6Ud3-D;3IkdZxgzjxGq$#@B9fSP z&P>L1-x$Z2g>un$9f!6zUe1XfkIy+`?#v!cg{O(e*5~5>0xbO1g<6K;9_Y1MpJ<}7 zeV4ciu;ruZnZ>|=m{kb$=%kzL1G+%IcPXIO!7cjCU#YEl9(LX-n`t&os~DR6@!}@G zN6GW0=ME)Iy+fRI&+$shqr){7w!A4GXn<_R^mX5wJ9*#Jv_G{+woiFu4)nE-4o^&3 zHse?<2V-v>Ku2JnbYW|?ezY0GL%BLV4i7mVg#XLjn{_FwZC$(f{EB^VJD;GSa!FlC zU5L=W8!Az1MGE=#XAo6J=E}8l@3&~@Tx8442qQuXoO8@Edhbs%T~__-H3)`#cP|ui zmD5us;L-RRxC908Z=X!tUQNKdk)q@DV~AQgpMVugMg?zP5}P#xwci3U72dJu&M5; zJri5~MmbU@LLqod{SEyb^cUkcY;0 zYu`7d!H%Hp={a1pB5?Z?28r|DPPymEaMOp!fDP1&0{cCjg|86f9Utf}t?-u@!QvFn z`rSegMNxQ%YDD=9y~>Fl9$e&qI(xpEq~FQ}`&JInU;O7n;ZvzkbAqJ(HE9XG~EjVM=R~^$$-Zh4t`5AIAGfT z<7e|rxqy%(3TL91QRBuhJkkz_P_tplj@4zzH3HEDE!(O@Lnao`g&qBeA)qX3x+clhB0O5W^t;5c_ zrF(xIM1<;Le{9VoX=;kHb=aeG7+8kG##zD%Rn>?_?S|+vXa+=)>KL*S}T1A#9Iza2R z^rqEt&klv~kj*({XB0h(v7@+troIwFK3)TZ1|fpr)fWk>9J?#)iMM-Oa4xyV_Z__j z`prQS+bTxlv;>jSd23D5CDC}$=|=N-mjGk?oFO{6BDSgk`qOL|^TC6QcEoLs&s!n3 zstqyGo~DZhYq|L_@!K=P=sQujk8qfQsU&A?ZkOJbmG$eRBPZq&U=#V;4+P|} z%XD|<7=OA$qSf(nF2Q9?t`%f^_P`j95rs5HIL}twTwH-$dOYtua{~#=)FT*B;M{6}=K{k}J>%D!> zW?v$Ox=|&EtU6cjiKFc2?+=bl@)JyAM&*Gkq;48xE(^Pgd31tm7}+w(xPxr zdlz$`K+h;(aO|@|XwcLSqg6u_1l%(p8xQjI#DXuMcw%kNFir{X_T4~$H^V{%lv%kY zsE;#pIB{U`f1D0yh&g@T_xc_!d$|n_=rtBXDDJb_a}v`^sONp1b?o{GS%`SOvb(-V zyeZ~i#!-`I-qAJb8Rjdd_faVvlGHp~{W$R}dN;Pd%&m2`J#*BCRGGEdrUBh(_n!9C zusK>~1P4-tm8xB@>BK1ON7cA%M9@BXlh=dYBlJsub)~Kq+L@b67_T_vCE*&lO-+Wp z57553YrAkLZ*i~6&Z>`q*v#dJV70$!a~#poS&Ed`6Y?C;%m>ooizVazohENEf8Tcm zb>AP0`N4P;F?a24!w~&Hl?y`JIFG)2!aVXrfeg~*{|W}=vsL}4&I5Z{+SAond)gF^ zFDx9e_IY)8{^m7oh6fypf9sI;zn}Y|^YG?1{)rJ{ZBE0d-fiKu!jbO_mItK;!18{4 z{<~5b`97Ebo}cv|F!eDkT)tTz|K!jE1q(Ee0rxk%pj;_KmCq*R+f46WrD8$W!^en| z8!<8P$WLA1uMk2otX#i;-dqB_p3p2O{uuoXLI1zDExyVS^If2Vd@59iM|Of#Rrexd z^~2YS^l)X|*Y-j-rUbwt5BB?e&6(C?MQ+x?X*E~e*l%Ie9FHXBMaTWs(;%3H8*62A zy#_k~6>Hv&qCg~;_hIWZn-pbpRtyZ=_)Z6RM7r-o5tq<6^4{_EWS*zU=D^;p=(qFYN?m36U_*`}9V48GI z148rNmDix)%lK@$enb#1)4Dea-|t+}zlxm|4Fs!W!E#sS(M{y0HAh%84W5 zbohgRx{7<<9srYfqY8I&4tvN%)$0`KTp>hw`SSzf_%BYC3MC%xA$eEuHRrx6R`>ql z9$$s9&ejaCA)2SoH@EgGbbp+nwuS!Jb_40}m3Iu1eRz_}-LW|iXfNLU7XWIjxO~-h zuGu>{iiY&e-L{9Z5O!H0h6oQ0+2^`KW1q5ZxqQV~8@LBPci{$W54EkE^0?}m$*lbL z-af6pL%Y(|x@^KO8B^Omz|{7*zT98+RY0)E&02@PcAOfQa&`dVJ!X(jn?~_gwRaZe zt#-haF;cJhvWuP>(iIDLr{W)5v(IZdKGUxy^q>9Ae_9|pX;~o0FZQXaar@Kh#h&)* zB$Lcq*U0VxNt(Y2s9L%?KOkUVBgs8lEAFb_v?dIUE>BpYWyOD5&lGSk2FXGI~vbTK@@Iee3Z8-5#j-Zv@h1 zP1^;YnSna0lmxPe&Hd+QasBx$q1p4f{_!wbTV%{1wi5W^iy;rpVIMZVk7hB<@RmT_ zPg}{)*W?q7_IH;A`Pel6t!wh9OM?6-*W^!^1mXX1O+IIH|Hf#pLmC5eu=(1p)wGxi znAegEK`t^1t@yAO` z^wFIP@wqjw*llNn+5rivc#-xUr>DDQejVbo6i+c-1FDI91#(C2E;%p>3~kaUAhAV zPS|0I1oFebyzyZes4rboDuvh^d#_v1VIFr7>%@8lKa}UDAQhdOfgXGFM)7n}#Jt@! z+}ych)C3@)NSOM{0sDTnm4Qkw9M60(|odHWE^vlYRS~P*M4vbQA(jViS0ptzggcQh$8jiOmrZTe0mZ|GjQ5og;AbUY8m_R zUrYck{gpb}dozZsK9n4MEX`tqK}mnDh>_zHQ?T_{6>jb_(7;3L`AJ0P{Y`_JB;DQFL?z6InCrZmzi*Jh#H|2`T6 z&`A03_L46P3-s|y=*v~*Tc7T8ssA=;194m6En>2d&e~_mt3$DEZKJLHP@QJf-|J$9 zo4Fs-zZ?DS3qLlh+cKRC251CcKXYkQh%Q1Tup@%D4FrnN^mZW=^nD=7a`W`zfURO1taep4@58iVc$W%U%;=8=f8OUfV=wTCDQ-9*AG<5 z@4>#y1^n+`KjhyzoP1utKW$Qr$LL5kFqbizL8gE=2ndF{qSSkzD1caqFAy(dS+D(Z z#jcK~LY&519!TyL52m#ze0`$18hRv}cw-?9V&P-# z(FbxVfO{0;I!rJvh#RcqmFhC$9+J?=xo6emjG=2yO1)c8I6Humd~Q-%1YorgHl+7S z-CIh?_uk!a{Y8=ajm&0_+!EE>oB(=0(}Bvzn#Q_{_+yMb9Gw=w&20Skm6ZgSp zDkFe2Acw3=p$WU(Cm!QrMTJjG5|{~~DflRZ`}-^9{f+E==objl(xhLM1#k9D1r#ok zKtl92QHS0yt|xKr1R=0wQZSE$^!R|P#0t2?U^1CMr43&Z&-90Q3GO!sM)Bi$qZk|d z?kn^5zLksTaJ~TEs<`PuA#8Uv&fT#aTby9lbFRyc4@|Rig`D9=nVD;O$b>sXx8ioF ziHj_Uj8J53Qmi5mKd|23C$i8o0pPKMu%<2fr0+fBNouVDUIWj-P_w@uIY_SPoCx1X ztcI45hf>_8l0yrAM|(M#7tWqwp@2A^iBWz0$r8er51Fp+D zyfMhJLK|^Jl}SI>!p#rx3*-k+3|3y|h35pWfL-FA@aEa>coZ9k_KfkSc+{UG0l%zh zuL4Xnj&6yJ4;&Jl4%)R2V@rH&AiZRBb|gvNS?=?itwVl(nZ=#gd7C{$l&@kOJ1z;E zy{Fy(ssCiBF~sk^x1j!Fe*e?<#`eom>CSv@Z>+)SkRt81A;w(R>_eWe0s5PY2~gwG z?|Ml;xt>08vY-7VApN~y%=`jlEu}E9KWr-|@5@K;V>HIRL zTF~LrlI}zRwF6t+oSArd4k-xKc!m9hTv-1d9&Z&2rFXs&}?HPz9bMYFaS@J~V<|Z&1^Nawf4+46t z74GYUU%q4%BG0^yFyl05nbw#@1B3VL9Q;JWt}Sw*o;Kvr>{?i7@lr=y;c3G}Mop*{ z`9xSRhSc3yc*GBhynr=yATPH(Bwf*0 zoC6>fq?G&uBZc_bzgwz*8nb|SXu}T;2T|6Ey?wCjOQM=I7Mi=msJ*ABgKGyJVL0A4 zP%6v5pCdn(T(?>f)zF4*2tf{a0cU#272$5-+QiE=J& z**yZVGtD$(J0`3Z%c$3NG@6$UMB>#7R#CfduaxWUxgE}l8k5FKf`yW~o1idK(oXI( z@Xk*FV-(|F5idv;O$X^@J_!DH>#?|fw7a&MiV6aKdq!c0wO1PutS9HGUe~Wd)^ckv zD;n;|?zyG>N_>DeJ`XOwa0!rFb@>FM!-JP$GtkA~g*)Z4;zp89R_oY*ZEl;?f+{hB zaOCY%f?Zfyn+6zEg+QQ7yE^33(FdMwNPxg;D}mau7YNK#%;wIb!Fa-tpbm*f$6Kj^ z+7S0i+uIspUllRHJMh^z1Edb`bM7CTQ|~M6zdo||{<6mYSpdKeZ>#K&jy=@Rw^oPw za8qg|ZAj2xySKk>NYTgt_A2`$y$+U3@E^UcvNkP(F$pGaZw#dOn30dN9J=wvf-w4E zQ-DM&2ZWJRVBjg*c=^xI=wpPCK`7G)cM;sKe_Hqd?iqbPA!O-L{i)FXUgv7|-hT+w zDKvwLu)w0OXaG@>X`5Q5DsTB2^ZI;i*$uOs`78D+W=GwFd$ZYI zveiy)a~L3`Lw>l#FX!eRz+brL#b>BSCK7>yM%IMh>~5Ybs6B2F*t&(zH(J2xT_x0w zt&4Z-QfP8*C`zy{1mYCNa$ZZk*bIp!d5rm_WdQ1B$U%c#Kl%J1?`OKW8~k{WC7;4F znr6H-z+u1~w$Gs{EvJ^m>P!@C?|uOEP_=mad@zx)?!1DZOH)2@@mNSP*)@K6koOq* z&{vL{VHb}KbM={-&c5Skw}uRiGri64u8f`Q!A({N;-oxe=9)!ZTLPH$sz8Z+L!ft3 z=i3$?aP|d;)N2TxiY+19SjD*!!nimeEz6)xX(2f9m%9 zq0#fFT9*?S8P@nE!!jL+K)W?^iBlcy0XRk#Q3=w?zjOy7!0RAkzc`WFfi$^v#!)q;ZMJ*QO!tg7RCQw5Ew zLbaMv_#D_yJc~FeW?01rnOau!>Fy&V_lb zO${U#bGB4&w~uqX+9XditqwY!eXx!nMhg$&yayHuRkF>`_y0|71 zeiLvHlyiVTSszal@=$;l_LU_d=wR?wer~{#ujqFNT$l(fo(0NiZ)vsm!5I@1&+V-j&yo)mQxT%ip?p}&cW~W2Q}T3S zcssb%CpP6flHIArR=1Q);hZd)q61?fy1+?ydI!3DYLFNbx)@??bKc<)M`>RN5B0F1 zr+C590W%V>q|!LdBOf)g?~9x&UX-Py)ErRM4E!FAjjGf!B515uyhbYOLZnGn5ciF!ZF@DZlBoD zFNZzj3!i|= z%L3k=f7V%?zM~fZHfj)|AeR~%)%!;=K#tYraoIJ`Cv0$6??DqsHzD-+u)A16a87{| z0}4jl-QeQ=tmHX$+AwTIg>1bqH)%zf2(H{E#egm*eH$z2TeAI_^isaQVpI%>>>Ov0 z)Ucxz>yWd6`3r*iNI6q{P0gu2YeWhP0On~&cUL3Vh#! zH=Eq;qS@lnS9IO>Q{=po2VcKP3%1?tq06Zio3VrKnronwrl_^TRE9@hPRfZzUdipC zRY}(dHioG$0`@x$hS=#w1>f+YFMRGbo8 zd`UcfGv=cnnDGDf5|>x_6It}X^AeX=h=307zx@*blbxcE_BNTOKuKVPRHrOjPFD|a znw;W30kUb!Obo%7l!_rYDCSQqF6>N*#P%Yo>Q)kW6sz?dW^J>61$&4-d_|S z?=1X*r8_ut?1R(msMsA>DXpCwRW=`c`s|$s-#%?#fIG+Wo>gu%azw>S=fjH~JiBDL zAJ3PVPJR9``Wgi>Fw@!`*Dzhl7?UVrY&uXe#T)nJ@MZJnu{g}k~ZJ)(2yCskVHr2P5~PAE*ybt^?k8NV&T~;zaxomlNnI$x&P5C z|9u?UcfpTYA*EHAAiKPlgt*?)b?`LJ6YEy%ySBK$iG0+5i%A^9s#^4kVjy*WPrHh(}VPMvF8PzFeF zYd|jZ`WB|ISewtsePy!8i{J;Y8l5VA^B6`gB;0K&c3|2IQUOcVWF4@wA)dCUZA-4S zJ&I}PZJ7or5?#^5qlWSWPKLBSP4>%O(JL*j1^|YwKGg@?4 zSgc_ZniwD19EBST)9f-w?&9nA3{kw*H_vq(hT?j42D`+*o4vXKdQSpIU})%Dd}r2b zIY$6*EDJ2vjS9u&>>6Nc!eLuK^H*tyaGMJoK_I79&!_UrkvES_?nm*Fn~!ju&^bDS zEn}*}>P#wzuUSV(;8k#6ZED<9?7`(*SD|-J&&#rmJYVIo5zy&!IUgE}60Zk*@RD)m zY5$yO_R-zq80Oni=0E9hEt}n+&N0kw>2hU1_-P`V4);o;VxD##N=U1X9vpM(2xj2> zwa9g2X@<^!z0r~XsSei?SBCskhijRleRjB{9~~~jgN>p@fh^(Nl(5|>v9gNxrc z@&417xX6nT=%cmEOH6VK`quHsZ%YD_jQhw;laewG3ZMz|fD~9*a`y{n3{%Jq_ z78IdiK%+Z?ro`15!Of;HXq2XPoJ1Q`2KHo@q|R=&O^?UHWqq#O+$KNg@2DJKtRu-> zfd{&iL;+t%%wb?oWz>RdR3+*gGR_;=6`F3pR~)*p^0&^+&-zO&4r8cOszVKvNz=Vt zO4X7QqIRG)`I9W>5AB~{Zq!k0KzdM8IY;eBElTgNZA!JTC!Sx{`;&n1RB>G0+3I5E z0#whWaD=oPJ39K*3m`ESV8lm5)rA$$igzlfTvApKb{NlTOAFRs%b`^rIgexz*px!t zHG~}N6jtStHH`v6JOKo@J|qg;cqg*5^~C?j!67Je*3^50;!kf|j#}Ce{TFzE*DW4` zQ_SD`gERlvD3RbR^=_%QByJ1@kTpOP+MU>syfd1L9r{FHp*;-nfv>JD#EvAUW0Q`B zTDofDBl}*ID%^PD5EIiJ+u?MTf^II{daetC#>I##0xGitO;@D+O&f@{E z0$nyL-XukIBgV)k>S%k~C{+M~rSD`I$f$*?6i_E>Uc6N7P0aysRcZo-$NR_1X8fm@ zxV%E>vi#4y#N`zt|5Gn}t5g{mo199!+L$xLBH3><-zTcnqXq z79j+62)r;zU-x)ftO;2zkOXya^9V0*%8tlmW~o zB_MhNG7Zi)=7^pAz_|x(BJS$T5mjWLjh`K9rW-ki+p>Lt8N6XEVtL`Asy6j&GCYZXA7*I(d&rb`{Hin7B-&Cl-pb{)N z-!Hp>Xj9zsj!~%wqG|6ml4d*sZQx&GqU;=GE56UO%*}ix#}{v`aYDbda1-ahvK4N?RxY@4!4ew5J)~7nzTyeDudE-!$Zo= zHi4{ma$__+b|5X~Q4=`cau>BDqF`vp@;+)H^j@7Z6CATWBMtdwjQA~NnFrnLh@s~o z(0yN-fCCI;1$rNdhTh7BLO^$!0ch`rq>1o;Eunr}H!#l58Y9#WQjJADEYv0pgnUTv z1bch9mYdE{w(RpzCMo0c2IjlfIESmbmDX+2p1a1p4hiIcm;mK?0TN*w>o{SIU^>!r zJ9Kz!#gCeVlxDVQ>4&Qcd~bKl)yc4bbh{S{nviTWCf!3L4#2pp&U+Y7EBg6~Stxnf zWFZ%&3^{dcK5#hSKOTD?K`Ywx{s32eYf%87^j}O@2Q0og5u1CR1~RnSfHum3{1JROL9Dc~Eh^baf&w~-rC7bN6Mj$kD8TT}Ei@St z?isKJ-ER8Ew9kkq)`P^|nGhdu!)m;+tBQ-$?ZoyrF3^U0$^l{@G^y*s8@i%5H`au9 zfnjy>_UNZ_A;!Ew@2{Y3!Dl3hbe%b!Y$Ni>^>}$aJpLpwuQm*>M+jEp)yXOo3S?W! zZlKT{%+*fJ;m)2YWgqq`MgmGG+AR>j4g>bK<{}Q(#no*HC_2n15|C zd_=7MPKVrFS9Q07D4BC?&_S0_HgP#zC*AZq2WU6#<+e}j=UVihp1r+2bX+*V!nB(z zHHzANS zCI>Y;pmGD(^Fn58+Mnv$Ln`srab0FSolA0i61}Ff#|4Dg~tRm9tdqu!D|$3u0SUGk&X>F zFyPNW4+T?c*bpUd*|Y$4eIE$#+G&Yf{tfEx&8bi!ZA$)}WlrSh3$X|)L z3A8z3@%}gb_n)ec7rKJj?~X*Y=axX-@*Yk!NGfI^g($*`J<>;4KRGg}Xd!ddO7{7S zo~+ZU?~7HoUB8}>UE#Th!fQ=a(Q|H} zm(56Swc%(h&!D{alyGZEOT*w0S%h2sNnNMlNP@X$dR&HxMG^u99Kukr(tO=G(Y5kB zzA}fW<#6(=lc>!)c{Oqf2_|q@?b3~ZRsqrws$058{oV0$0g1b62v?aL0%Q%Sl$$JM zICl^`<_a>*EGki3huE%+-|XvSzcO?a@_{79H)%^&>J|oCmleKo)bUh8D{j2D*ptNR zt%WF!5RK#&u)iBm*iB<+`7T2~v)%?Z@@MgkaicT;vwnIJY5X?Tu7fi3k%xy)tU)+r zR?n-jk|Mdiw%~X9k7dtXe_f9~XjTkjbahawtIbHG{mU%rRclh>(Jt;lZ_8&Cc2=-p zL@xkeN)@82h55Q}q}A38L|AZ#i0<4=vAH}4%wYlb?vjypSU1dTvzh2BNz{`#0cw-o zjqYZi(U^F(G(^X3MGHq(Lx%Z$!Ehk|8;qycF_8DTe`c!K)+#phRU!iNptR$4uio3Z zJc|lMV(uPJKIfSuT&P{N9}T>{@#he^LN)=lk8anaUTHu+*E8`daD!(Fx7oOqP9oW} z)xu#qW40MQJv@bz`Ln+fubTnvkQ<-l6h6I5t>Jv6DJDDVD684*E4WCx2TTX|;I0yX zC4_eAyL&J0H>=B8b^X1D4tS8uYh{07GV~w27wRp3G+i41EB$}$8B$Z5Pf*z3FXew) z#Kk)Zq3QO^ZemgD3n%s@uumUk^PH;I8as9Z;3sI{f04kCprrdUc)VAay!#ED6N9Kx z#$Z7j12A_00rPuchz9lTE82qi`9-UVU;@Sq?!=Ed9rO~Or2;yoCGIeS!rA;--9I`W zf#a1hnk?FSS0?d*f&~gYBw@Lq(pkPg6Gyb5sszh9%rri>A?5qCTdH@6Gs)fyY1Kgl z7i&Q)H7s&jNpPR;wuRN67^H8x0H1TVKY8Gxh-RNJialj#2;8A)an^cnw0SUr*e1(} zfs0?BMxk-;ZuMA6Ok{{R4U;x~udf|0dC^37*q6=hMblY8lI?;52NCeYudyxk`d#&~ zd)A$@!imGCt!=z#=9hv8r}IityW!$qcgFcl-0xJ~ZTp-QTX%baxP^cdJ7`Zd3uy+{yKf>`WCh`@|Tx@L1-S<3~$8( zz;-`hJ~&+$%YZ9_^_8Q*Ov6xALeW=Bz^PS6gXR#W5ct4`(m5*1XkvN5&ZJ+IXi~u1 z?I@rk!{0kfFQ|BATMAHMZ~uRP+`K&g{c%1OjdYDr0!IZDd!^vg<0jou!huRNDqB7- zQJ{Mfo8^J-SUHAZ$>FY{mbW}J^$?i@C@UTZkM0v0vB@mhJFS=NEoSfd4}-+ zx0eQ=hsVMHT@akWp#Pq^517@;HK@$Uh8KU%lNIP&@ zOpRFtc7f=gWl;)$Y~l0vLO|v7$NMXiLOKVcpMQQ+1$E1k{+GJ|)pW%8ww}q3G=5wB zN);M((S}5qkHbRPIhafS@_8^~O~&WC z>SPD!VEELOf~I*+*yj!KQ&$8sbbrIFhKveH@ZPTz2b&KLUG5%YL(3in;ndG>Ij=}& z8dGf*YVS{I4&8p=#=dr}5h#J5Ghx`de(V?HsC~WUPM?9J;~-xC?EzO+`@W&r;2?kv z#rlZdSmf%GS)bq+L4%at{L8KdGHd}dg_owO%4MMmR%ik4h%~d$t_M2L2-wyfI&fQ4 zW(VgvZ<}*iBrN^C-toXYsX)Um-pa*4L0Fg2y)NfAI~BM98djl ziog?+C0%g4=%dqRcd+JLr8Vx$huVmjd&rsfZY{N2i1WrS1LQEp+$4KAv*I}fuD58; z6!c^_Fv@2ext=q<6Ct`!nUW|X zZ>M#L9CjIA&#u6z_^pig8g_ZDJdz+na@yU!Qw6DVrB|+>m#5xY6{eExQG7BKhYJ(l zi5KhY21o_R8^bz?g-@gc+UYo2n)-rNh9{Iuxh)!D^EJfV%F#&%61x!OhW;T_nZQWasRQB zeG?96b@)}d{;5u7mpYaDQK!n3v5)Z)at7Ue{poc~XB#&@NKxC-jp+-eFu9#1Vh!mLcak<2aqH{L|dzk=O1ruY8)lxW3mo~?0@35 zW2Ml5JfLSdYoc3akeB#W_IKp0bJgDBML!j8VBEz`Ml5`p2w#G6ofN?Q`pQhAvY9I*F?*^i$Cjo{DXxWx@8=s-g(@b)Fww&Mz{Atz$^p+_;Q% z*~-@b)KwI<7Y_F$bLx*d?)y_*8Z*I3bhME>pnPP|hSQT=F?1F14Xd-!Swfc6R&~4} z5+r1d4b}o&a_3Re<*Vw8M%X-I19|t;y@g8rutWU33<>>qWjYniycjDOGV$d;Pdr&R z1W;DSV7d1e%@YrhAe?ePAN<$H3RnGTf_&orCVtcJg0l}074LWPe|i&VSwXFzGu(-5 z8L@#6_E-7VlGnrujK>Hz)U7MHVqnSxQZJMxzvD%J%*2qZ32|GsxH0eRYqJqR1_!SD z^|8dX`-ymltC01{3&gHE(qll)!!j5)XFKfX#a*n3uenu-l-*%gL7x<1-_R2GX1dDv{KA^voV@25` z25n324KL#bFHw)5{t)Hlj(3C(hRQ zwn|;^q1h-GkToi_egtJ7;=RNJ7r;hbh(k(j&dCJ;KQZHZ%=+G=(Yaqaf%1o$7{&a{ z3jgoKZ2#{>vGcopDgO9BR)vr7U-ti@{?FI?`sKR#?LYps`oazgT>|dQieUhV&Mvk? z#;4l(AXMrL2rIu`g~gxwwg@m*U?LHZ)_VzcWLX027Z8F1=j#Pn;(I{It^heMz|#4- z3NNE2Pix1$)=S*7DwpWul13Eh#=fg?4bXppFSFtx|AU~RWXfR;f7eHhV`#cdJtne` zbMq-*%EukQM37!3UhPeYXh9Zk)>~Hq)^%togLG6P-sAT`smsEcZBgyQxD6V8`(Mf> z)|mmv!oAz(m~31jAdAmK4+=F11cW&-5GCbn#L)2W{d~qj3w3H9#`+BNJr4RD?Hl74 z$T1(=z}GVb$I07M{E&An8;Pn41jf)fGRxjCFPMxX$5ipbSm6oKBHU#QodJA5GKlo#%Rc^Clr1+nDE+aDAbkv zQ8^Ijb7ZRR?dFqaopGdGcK(%~l?$70FX`-DwlLWi?yrq>J1Xu8y&LJ=1FsC(bm;AN z2C2ish7T=buB+Aws%Y} zYtP*xc#|{GXB3jto>0P6RM#@Dy}$=TZv<_wplPo719yjXrE5qJ^9%~d9l$7M`N9&< z2IVf-*apzc+2$q#*}VL8cX*iuJ`f?`x4=twN7)A7&gmHkAVDUG4k*8@43$HNvgMHG z4iBDeGEP)|PSM#Dgdb3=2nve|IY_`;Kx?4HVA5?}up=+m)ue34LFy~v#B7o<#NqIv zny=>-NQYG2j5{!#t?)yBD{YZb4u^d|u!(!UAYxt)8R*g{d&}{d89e6{0QIT$GJFL~ z+dRVcPFI!LAa~(v#pV8mmE^A5ydc&de$Pd-16}1wpSJ^mmDTHtg|uvV!xR^ncskAX zTWeqpK1!PKwNjAqENu`(>8pP|!*F z3FLD5iXMT(b@C!U7|Ghl`|~||BoJw^xYFV0*CKBe7_bHk;0}W-aaj>y6(RcohVg;m zX2AyD+#Z4MJ$`;$Am1#%Zub2Y90-Rj-T+T97Efg$oO%iV0RFiLEB+O{!X+#>9jp+X z%Yn)5H&iSzK~fT(x}Fc6hs+B6iJ)W7llCShBRb30!D0 zdTa(G$<3_A2d>;O4R3GV+O2YF-V=TO+Mdf4EHen#(s5r8d_}JIx@|~nBG;J$y-{u^ zUYZAm0avr+oMG6ex0{zp&<0}ZP>}a3dBbP4gptfzex!TpK@7-xF3*Y5?p`2u8Nu?i zJ9gbl5d=vu*01>#q1Q`$9CmQlOsIWxy#)}Kt#8;ionJW2xYt?++3r=&sFnxiyl{TN zF-=M%P}!t1lhKhw25P?MUgy`T*+$}c+i(vJZSYMtS5`r@5+tHwmwbhzxCnr4GklgT zBZV-Z*lN_EZ)_(q7_TryP!E)$#xdT3_3bg#&>XO%WcTn|ojI(hB(#suyzpYy~PH*#SZ7I-MvF-wAm|5*eT$bR4w5t;8T#b-lcR;=7 z<-z#uOyV^oYU+zRl8{5HW!|gVSzF?vvijA(m23M^UzId=5orX-6D+>zWjvi=L0B`V z$=|xO$f%D8HV1n*+4>Z|XQ#bAYEwb`^&y4Jq%Z+{|AT$iVgB`&$;H41P@PGY+ zUml;??x&U;j8QP?hQYQu>#RAy`dn6 z@#>o@3Mh6K3zX)!WCm-4-5@CJZFc`LGYLK)`2BGvu(%=4I#U;Dj`Krvg~04S{^J+e zv~2%JLZo9)U5Q>lsM_I5Ucm7!S=~G*=0@pPs>W}6aJ%zs>-bRa#U{Tz)!Z{zHJ6;q z^;(A{5SE8FAq3FYx0FcN=nn0wc4wIb0BKmaofzK^EsDN>0aC{w;zKW zKF%^(t}nBah4qB9{m?-E$Sr+v*10s1bGUD%vu!*6Gsv2ii?7P#Ax-2CW-6qoDA@T( ziu>BG0d8_P8v3Ob+LnAAEMhaiK-FQpk4XyamB8&G%StnYenpameoS6izlnx5VCf%q z0-UA3p-NpHiZFmGF>J!C;eKw~4CO$7GJ_zi# zau8y;gNfoK+^0()+=X^Dgmu92CaRYJ5BH^hyjPcgxBC8ndigiJ2RmoRT=NBw`DGzk zKEJ$s5Sy8d6KHRi?)qCPAgY}O4f0=}#oNc=nfznZ9C`1WLktzfm>d6a@Xxi&<=O6ThQt)J=d6`;4nozw~afw@veA0&%>B^S3N_=dQA>~AENw}#@idD z-u0f>^I~+>rS|a*^0K!Hu;*V!MZlk12%B?)rVfy!7AgnyboBQZG991Sb98+U9fUD& zYY3YH!fCNtoonk5_Nb@Rp;`sT|Wpd@3C=Pd& zgXjrvataJZMR>YqUVOJIpK$mWOR*3wTv9k=>gR^{3Y(2+-~!Mt3c!v2tG+h^)_I z0-*{)NSt?6DkW~~H6W?f?@pBmN3bLtFFY0nKY7wqoJQn`hpu}D>*){&One55$97Yj z%^X~S7587+#^{ia-*u>ENwheaM&L)I#91O{l%rPALphaP{>4YISPed5;;zR;G3YY%M^ zw28vG8BPU=_MHvZm~7BMw^F=jhs*7;&W^8e-9eu4x#FL~6HWj&VKi9Sy8+Ulwvj&J z;fgfYyk$xos=W7wm+)elT|$z&Wy#zTx`%E}Gi}vB<9|_7Fi#ek&gh^G?*UmqAp-|L8X6HUmUD91Nc# zwey)u3zV_z(U2$%j+g&y+t~cSyNxYd77XzI|GkZA6Uri6eUpYyjnvrY?%3B9wx#XymckM7x`Q#B5UUSc_s-$X^xaYeE+A^04$kv@ z2T)fZcf$TS5M4Cftcr^c$jf@3z10J(x81tq1>b;7JB2UkP4nb-I*+cyq}iVAU4};8 ziwm*UadjTqP8OxL9=ATJV!;RyGN?^XBqGUowuX>!{UY-59ZY0vbZ?eYy8(d(Nj%eB z3$<&32dl>z51o5${WMJ(e6tzLso6^CN|-^n2%v`&rm85p@mEi$q6cSu-ss$3HSG}I znc%wLXW_lpcBmuhp*`XvtwKbXco%E@VUwyi>aK$gD@M@xMjCXso#BhIdn0U-Zrwml4KdEo}L**Tm8SZy-Bj_*ca~C z*C?`S2k`<>LD5uQAqmw&@j5~hs%wEjEk`&!2X{RHPryyTnRp~#aEg0wk@sf4_kS6Y znK#Ij2smQzwb%N--}j4+EdGHt@vqKf5<`Nf=FK6&|Ki*RZCo&Qcn~j8LmTLs&26y& z5`O^|pDw=WSBDtKCE6z_JVc=-4qqk_I4#dc^>gqD23rx%WcFHRKFFXyZDzzjIg=r8 zH0YnsWQ9V1>e$Zz4wF+ zVWYf`y`?}5TL7P}Q)oeV7(VIQ>XO-LCW@p85Fy%+pr|8=#~s&#qzb1^272i>wfBIK z>~F}uFIn6P_t<@Ji&y972hE%^{XEy*!tvv4Ziq*YIcB!NFy<+=Zk!OW3CJh9!c>3O zOsaMdMLn62ay=nIvRGGJAA^V*zmBb&+hOwr&5rfT(HJZXuSyYfr_l{mdmx+g{I0 z`hnc0v%g(;ivbnWQH^`myIaQ&no9vYqG^-Y;T&z5X$0@t%F~y$T35S=-DZb)-NSV# z9ebeN(2u7xgf}Ir4V<9HRn#2FPreXBbBkq9Hoyn9elZJ&&7iNh=ll8k;D_PRFupVc z++fAb-SPys;mp5_I!{dG0ccm(JYrpn+mKZ!?wD`|SqN>f!l`lTw>fXxT3vDSnRMmp zK_4gJf-YCOOyDqx3}XE5E>Tc&0J$o#^HqRsX;BfN*V^RRv|(y+u29>pv$~vj9t1VU zr?*bmuNQ14zK#Q+lK!&dGA^3xLwo!e`kU4IPpvbieulX;Aku@TJO~CU>6d;H&^_tH zM8C}ppB{>zdP|7GJL^bL0fT8L4(|-UJKoObEBg5I&OvgG$KDxl@L>MuxA8X@ zdNkW@BqM``krHg^>B<6!je1k z;VTI)nw)5cxhV3fq&%0S5 zwl#l(4vNj$VAS$QXB%J_9u5-?9>|Cp6Bc#a`IhR%u27vaG)9H_n92;)6K&qcfZ5S;u>Z_w`( zR-CUl==0n!N#->phfebFxJH24ca_MXo zc5$uIRxuw}ts#&3@d^__Rf0?yt-)(?hxGn-2{CU)wQ^Sw%sI_g;aAL|++0| z;j7^iLVy7niNM;IO%)A9N|dFNML?{1$Hi$_Rq=s4hR3YaU9~`E0kJj;Gkvl6!K48!erM+ujFWs&+@9JH1S;n5jB}r_ z@`nbLX@g!XftkV&<4usXlTY3tGm+DmR3@ky-Si^(x-)Hb(J`^S;iAoUQLg0vN?f=| z;!`fR9-ts$b2qrg$F)Fs(xKq9_$i9(1_a+XX(A{oeccm45x>yKMQRJ!1I|*C!|xVA z0~*=mcbI)ZNtX8RE!Ot+&&yd25)J zJlgl$AzAJOKX3s|7PRg*4fYhe5`9kQuxqT`2v=gNha(!y9%?=GaHo($fm^)FgUw0O zJ8Nv_trL+gltHj;qP7|V3PdvE$>&J`97~WRzepy= z%KBncquA%6=?N1C(Dznhssv8Z>oiwCyYoH-dIg^N%1DBg&Kf8tIb4~lf}{64 zh>k^>5Pve>!o>x2hNQR@jtRllcLJ)zUl?6Kh{fEnycVgdci3RpxrXW)w3jFsPA|7z zc+GDH0C{>&pnP@g}o`)$1UwHHlw1f zJtC%k{(K+M>NwKTz(dG4P*_(Uak`J02C&pe9c?;hl4f*5kNQrAfTI@S(w4he3gchE zB;d>Z5j{8Sk4h4 z)}3Uf#tomNLkg6v+R%kx`&IgKo{Y5dj+a2uWmn$noY{5PD9x0nDM;$9O$O@F+Gics& z0KWtb!m-(BVpn>~kKcd{Y&3v$_1Q6am7VW$Wb|2T!UBpzCx8V1`%8}utL)o@?~hHt zy87=fj{NcJ|H2TAEEF(38HVns$K_5{i7n*GjQ3v18}H86TEz#Aj)H*_qW^+uCX9=7 zMlo80n*mZX4lHIx4lHNebE75mn-wU_DOTT>-?SpB|e=k zHsltE+#RvxQLTji!qd>~0LEyoLLb6mOeWSpAS7tufyBaRBelu{$R!%K*QFL8ul!i; zusus2_LXGlJqA=JL66OU91F|+e;fEV`1}&?9&mOKib0gU@tEx4R^xXBJtb&D6v#F>bENCzI7P3?DP@K}V zga7}U7@4k37fqlrHu3N6OrAW`uGl1ZjctlvpA-I?L^`LpR*Pqr4w?aOyMKj&iqC0~@uWA*Fwj z7GfQM0@rRPvfNWUtJ}tT>ZI+I(<4f`K!G?y%ZUpX0!->VsAez6y_gT$N?`49 zYQ&k$5CS^BhtBiGg@#*2le8#KOVTbo@zFNBuOD=1-#x7)YMg?d98Kvdw2$^>NrEq( zAxD-#m9oVa58(QuNUE*!eZ3Mo5dW_Bi}|*IZG1qRrV4v|bTR)z63|jj3a_&4WN%|9 zZCmg8BUHTew7V@8?Y;vw>&c)N7UE&7B=!JuzcwMc+C)60hAwax+j83-UAX;v5qhAR zNj4RIZXwG$=Y|&O(FrH5#&Y#&i@O`0LY?wfxr?}mwF}|K8XG1leo&0U_0FRlh?+t; zzv}|TM_GJ7`F}!!|0OW-PwOlcU=5JbHkmd$DngR|2*bylE-Y0-!6I8ipK=XVUn7+Vn6w!5ba|KR=4@1{;{S4ff zeD}qG7eRRWQ^*GcYMC6?<(EPxdP75ec?^02QJ`@6_YRfP@SgUvcXyf0P%RS(Kyg4* z3?RB>e}C- zqkye8R)t2Z$IjlN>gqAEX^>yKlp_UTpPgx29T3qcx`%2rdzWf+$W9Qi`h{3VotX33 zf$|>s5!{Q#ahakXKN>yNuI{5)lWCRcyFR#F$RRPfxYWtMC#-$%)%YdZHM3xL7d*8qivx5bZ~{ZVq)f^Q zPc=dEM{dV;VH7XS<<)kD^#Wln?XKUV>`dkEJeAF{-Vb|lYM(l^JnaV%)9x}I?AT|b zl8@tsIIgHoe5Om%KbW<(0tJPwlO{SVb3Xc3)t7caj_DZ6TXC(uyjC3kPw?9F4#eR%U^C>N5QpSUVs#)hu=BR6< zg7DM=YaeptFzow`R_zo%`M&W?;n2G9>)n+%Azy%-IGZ@s;S$n5Gq63r$cmsx`X)sJ z^*QT58Ue;gcZJ@8T^rh!ki+^d02Ul)WXMyX93dwX+|C9!Cd+Yb^2Fbj&a10)JvE)bIhDuBZ=L$cWEE^_a2|Cqoqx1*hsauj`;SwZMN zl?cSfM@03m0L>^{8kG{ACeeJe1m_1n(rgo54~w(+%;qz$Nw_%!P-B}YlW_^;rcM`_ zKY^ZRd&cqr+Bc{DqDOeO+7Q=L-juY=pu8nq#gUK23F22wPv4-_X6Gm3UMM*3a44_{ z#=9n6iZVy^JHDrM@@i8Js$e3JEs(o38kNCnAu;j!TEDiB6v7ZI!O2$G?c}hf#zN!j z5l)26sl0Gtw%OS%RCAf@o69+G<>-!r=U`e;#vMtNQ>+$%_9?g!_TUCs0YCvLSpp+Y z?k2-?vLO_k{Y!qcEKwVXm3b>Dir_CHo2z*I%Y6Eq;OF-+6nenZz#q@+|9aoR)4lz9 z`1k{)&YSN~ME4(msQ$wK=A`#a57dAD!9Nx{+_Po3`~*W&U_t$PVR#lp=JzftvNXWU z3WK>fT#A4&6`$frm_l;%>|oB$&KePmiU=+yn{Wpd~n~r1lKnSFqR* zpoJ`95K;zU(1y6j4gtL>WP3@#PTH^T2krr4p2P&&AFLDWXXd%1XrVrs0Hfs&3LJZl zcW4X4?7=$iyau}lOjrU8a)Zw(0q{@?1>+N>B$iXe@8LMxwoo-aPN54auI4?g*69;h z1#;guQnXzNc}cGe+0H???N8qmaES*nK8@+wv!9K@cMSCiy5JWjQH9d1_krT4z%jsl zA44-NXHUePz8@%Cw}-@ed(s3kcN+Q(|M{rr0w@SgzTBK$2lhQRy-RzLPuJ|=9@)Wz zzn`BicZAOnB2{?^`JLY}VDs}3{?X!OUd7%MF@u9)?5*tyk3HEK^8CF_&fy@hjv-(8 z0YCvO%ql9O-BKdY_iloL?BqHFP&dDGmcfU=gAqv^yLJM+dd)2N z=L_$Q3c+rJ)R+Y?UmBr;JVc(fetve~oBR5i+)ak!-=z!6aqU2$%S)laoq4B!9o?$3 zf8Hh_DIWp)NWpC9ehVsKRsL|B7%l;<%W^es@8Bbzo)>bU)db=4Uy5+>7nxv*Ln5%L zef#ja8I0Iq?|a(+0KQfMLJ6V)-d>fW=#ItI?13FPgEAlQPYUm7+WI~GvPuxtf-ewW zCcI5C@LDk3K@>PDfEoFo#-VvX?chFxzn`D24fj_#XuGosedu2_G=QYTa^!0&vLl~A z@PRnXs`X)cr$uczqL4&GL)hT99U(G2 zZWQpO`8>*Q99@jkdgp@Anin7#Le{oMwE>&eQq#Kg;cy_M;c?p^`ZQdmjN>uxoO*7bAuJcNsN?+-SXxVx#1m`(tWzkuus1tK|# z9H64VQiy+%lRwquP|rbP>gAWx)i($Pwcag?>ZocJ;N3;HN}#i|y6I=D93~J|&wX;g zDc0pi_c)>w>t6uoF3XGupYcdJ>u=YsbiIARg9Nm?I321 z;HdF5qVOAnQqAqdgM~cy2VK7?m0EP?(w#t4BtQ;LAOI86>x3|K>}&Y07wp!-5=3o}~`07WnXQQ92v z5XLQemWJUp)E)tt)yE`ht6(8A25{sXbs?=gR6(LnvA|4}%IM8ME380gA|x_BIEf9~ zTfR8NqDfyeU8yf91^nW&(^ja}LSB;p(9!Fo)$_+VCgN`^0}6gF7$8LMn-S;NAm2aj zqma1^dt`q77=8UsmJoIL+8lu1fM(5Xq)>o5dKy%c$wq*!LWEC^KdheiV+Eg&0(eIS zCRmWSYLVxU(~QwI~Y>FGp3j@JbU9sK*J0G>Ht-TCV)L@FJJ@o&Q4Sh!P=3%ZJy-06OO2oI0k-74{T@XGb>-k3WK zS@mFT?W(b3AF=5AjJC;kyQ#`G)$t`opbadzXWWCuM@Tsg23hv?QG4oe8|Hbmn9>1Ro7_x79c8CK=#M#0&{=t1@uAPsIOEWp zy+z@Jd5fV%M9Oz0yZA{q!0?_u7|=y*9t-}wMGa%@E=TU-tP(z93z<4KSAW%(s^!>e zek3FpGYu`jWgB_9oK>-lWi?zO^=7)QlO>4F7kj&xq|{vz>V;wzNU@iW8cM)q_r~)# zNR6-;JJI8CW5D67x=@PHdCb$%+t@eSwNfn$5K?L(MM(0JqoK`Xb=4r0(!P^`KW>E> zg&4aV;HyIa4tjAT1s-@>RQ+yRBxl-3z4S3um{7tr9g-|JA+pZXg(Q-Wa*|ybRD(w< zI%ni0pK@!_uF^$yW~YoGvC@E6*v1|po5gvkx5(9dy7#hVFAg6qH~Js1aT;Y+k0af- z!nnzg*)ef1@c66Y{uGHR7rzB*Ej7C$Wy4^?pJ_|1ElKk@i&e zkjmH9d4}cujt;A%5Mp6W>%m5Qq+5t*kWTI((loQn5?2 z&EPkYuY|yo8|pUZ7J;OrHb!vPt3tb;g+`R`Cu^UNpzb1aS#<3Lt7YmZmv2W_^f2fV~A8gnB zsb=JeXU(|#?7fJVyr1>-p+)3RSp^()0Raq1-k)>Oj}q{(a%kg0aS+V-<&X?V(SLdp zeWgNvP;emrP%pv+c^&DYEfToUXMrdFIL^aG9)bC4qr4w)p|uBSaFJ!NcOU;ze`VWH z7$Hvq7Qo5z=am!&l&JvJfXAM|a(GOK$H2c0kHHL?RIFrD-x@iP47q>3nvW*VvxkHH zt5%7{0xsMhxb>0B93pYFAB|=qW`Pl8zZL#dSVoiYjX%BG0F%!DY zL$jAzwOrtp!SH54*-bx_^L1yTXC$er!a8Qbc@btXDc*R%ZsF-r?&OwTWcV;1N4`oD zCc)%B(~K@0>e4s%S2vV^Am z?anp@ro=F&VJvjXt#(<)G5fwh4+TfbF0pX*pqH7gBm-UBhY%x`=Yks^uA~lR=DRV(C!1qN;Ei7(9kV+UWW zF$U1#ZrU?(ravTNl~Mx+S?r*V5q9-Sms#vKX?teZOt9z0oqK84VrmeD2a?IAo1HiT z%-&v>cl;&rJyGQZrr4YaJfEf2g}Xe~<9UUsO>th(<&bUR3$f>mL)R_ndrcd0IeE`^ zh=lntc9;P9_EPu$6yE$r^YJvzKS6CjQEiCbmbaFZ>l5dV*(s3yY1R+4kI^Fhba;Fi zJU)IF`PC2qLNf}j6BvO>*Av)z7Q08112A*gW6MgHwxl{f9L7LLgbQsHRc&Is1Uf;v znUmg#uB$0{w4#cw!b0ek0s^wc%}JdwA1a%3H)D4{IF8%oalBbecWM`u1BBwFLS{)d zdw>ZS1S3bgRyE^g=8i>ovlz`f$kdoKnrkluz!P z3=Z32uS-ks2Cc!)Le6w`5`%2Z-L#f1_p9*~pLVTXVY7A1O3lb1lcAKA<%K@rYdiyq z(8KK*P@ePhg`^1Ev8DQ6toeL9*oa}Rm>Xsf%WC$W94)w`s;IauLiXU@Ijmx=B?fv4Xs3+5j|kcol!2>-go=6s9pxCZ z&V|`*AHJ~Y*XuFOVocn$YhGy*VoM&^I5eQDFgqc?^|6GLxQCZ8MIRlXdAXwP(JAcnak+HC^At^e};>(?fi5N1%O$g6)D znr8hTI&@WZ@F51c9)D?G7_{n2?@3g2fE`IA?w!x#c^5)e)DECrx#^!xeHZog*=9O~^VQpmh-7!#2y22&T>%)$G%ND}@Wb9J7P;Mveya0r;-IOW zvgj@-b(*>?FBQ>reYp}~6bZ!J2 z_&`n_Q9MaE1Y~_S%&f>NL$ovqAnXRd4(Iiz&^27x*tDE^LtcP9{xmbbs<&b;3h2TND=)TO3#=}yIVLeOQZol$l zJKpC2>@TLhZkoCkfO<2$?xfX*Pw^EEoxc!}0{RXydHh(fZub7ZwZOw%I8u~{CF3~Z zawAF#4en${Bvg$n9kdZB;vBA0VYj;-&XbSh$$h~UK?1+Rasx@ocPRbb-5oe{(t2qO zG#!op8I!Hx65jO)gl~t1F!U=ozEmA?faj0a5aOqVqs0mo6Rh}_-Zz4Ahtg<7ZotW5 z@Zh=&hQ)nDLN`qnS21(;wb&fP#Vstgk*5W$y>?H@766^RYd@T!lL!%4E4vg z%6ST!bM&Kc&YG4&lE0im1OD=hunv0X3@k^V8KloFVMvi9G}8u-@(f9kubDISWQwOX zu6&XzkJeg$j|L8(m}Fqvg7g(yM{hK#Z;v6b2cNlizq#T+z2MX3@p)4Cz(cs3L9kUrs*TE(_@Yp4S zB$}h|-)&611yCWX{l#VVQb~*Mju8+~fkWSy+Jf;}QZD3#?v!(sRa>x&fAcLHB5#^BstACgrv;PeD4$>UC2s?7S2FRifUuW`fc%KU(i+ z728z=97!8&c@*Us+s!>-$BFvzVQUL#a6tY&Wcc#DZJy-%=TtnQjB=OrqkOwym?OLN z5Yot`Z*T2rZ$DVwKUc-CVGgh!-wNX8512>)BHnwm$M*ZRiIhn%kOQl2H)lutb;8Zt ze2^X1ka1r0{gOF%D1-q)vwS_o(9~`ls75qRCJ_F%h=~dZgx}`6$z5#kYlbzpG#)A* zgpvX+d#bJ{8QWA?QHxehVujZe$-Y!?!Zl&)>tRPZI}S4}Q9-mNzY@r7S~@&*qETQ; zDri-q*nNHwcw$6g%PZx?K#Nb?3NO`;*Z9tA7MH{M>RrG;=YaEgfAJPTZl$H|RfFB<;f|rhZ;Er0 zIIa46=71?d_6`5oU5F)MBYK4;Lq0@$uACWE zH^LbM;YL^y;}b^qC4>p$q}Nm^P#__B4{|U5S>PM;A%|#DEQ#2SkZ)`rtFjEm1K&h- zHM~Ibtbf(ItDqc4snd4cW|X2dKXr?H+l5qb@^-9aOl{!ErCi7tfJv`cp}2IYz_}Vt zPp32J4cf~+Gj(=1)))6`u<5KOLG06jfu@gVk3JWnR~^?70xtHIHHE#3OwM`Cc)&a} zMM`nu(A?aevEq(iu0w!=eUaUDY~EBg>G7RHat64`t`ejBa~!2FpQkIjwKdz-QpAn5CocvUybJ%oV`;yLESk!mvZ* z=!EtDqCPoSq<%E=nbBW+uqaT9YUuB(sn%p-Io{ZwGYb zrHjz_hvc!ZtV0c8Qg>P|*F%#?u>Iza#^-G>iu8`=Iwd!2K|lq6pCC&nnb`#&V+H)7`wsr3p7832a8{{cv z4X_?lR(UK}%Q)o2rF*zG@Ec`Rw)gHK#C>j-6Fn?w|F+0ve=$m;x1=>YIj^tn&Q+%C zU>MO2*Tc$1BKTxItT2NGD4y002hrKm{NOKHF-ajGw9>%#tPSAXWV>4fwS&o}A~-Ha z%1bZg9c^%e9wd!C>T+~IARn$7@q^5hmug&(tBpzem#uit9R0UzEgv^8IO<==J_C9@ zL@oc?-T})n|1V{ge_Vf;Pkib%_$WhlF1TMys(Qqr9NT9x+;_=Q_z6Wga8LGf^(AoQ z6+!1X3izGB2Gm65dHvy~E3c;qe%Ih6{8pk4mhvrF69=^F=g)%H?e)V?4I2b&ipj}y zRsjTRg1W2(H}d+q$U|p*0BF!Nr{Q%jhso$@pg~No)ahmOx}jAWZa~RR1@| zk(Y2YoZrPGI6NWfM!-PwY3>92^pgzAWbJiR@iU*p%exOA*93p{iW)}RXA z+b`H8O-bhph|fAnMVIur zn=l#?&2-9+OINDy!->>Ot8^BZc(E+mJRa{@6pAa(gG#De9_a10H$a;>p7JDek~2rH zB15DAfqW+qOeJ5DsC1zX5HF5JLD@43o^KVEAk=zPuhOQj%duCs$8D>~EVrbZH+*8m=TyA2p2 zDw#r8iyO9wBOSU(SrrWJ8ikjg?3}Ui2A*U8j)B_6>%e!5id#xoJP-V`K?p~IKo{7! z=NW`_(|vC9X-Vajal?>Jv}1Jact{{rpdi)b^+7>{xIlM(!elF9$O#t{u{Gf1 z1XCKoUouKZ3>%Pfi5+q`miX>AUhkV6lH^40(Sb#ui=IYiXhEDKwd59igB-lB3uu%d z+9Jb4w!afIzFRMvBt7)J!H&P{9*k))jq&Hw|B8ryRowjV*go(337qFd^)DKTJR%1J zH;a9>S0RZ^q_byXoqYBeboDY-o?5ZiuGmZY+N(BO&&i=!Op-1wa_y*tiV48I>6bK19eEi{liCK%1hgWz@Z%|Hz^LRd22UDkKyCi6=BgxWxlApvh*8bPA{;e7>s z$*cdgs(pjGDHe}?Tnza9RryQ}AwB{+5g?L2cL;EmeyG7g^bG=-*TVf)!2>fJ_5~|> zD6nnv1isn6zUBI3f&EeME(9{e;Lpo*vGEbRg((JbV`<6JlHBLeFb<*(|$9$S>9`wyd!(#(Qp8 zb!eR?<(%$?y1J^HHfXPlZ8yU~tIlL`y_U6LfCkER-Q5>mMj*T80Nh5w0B@7?t{?v6 z!0hklWk@w9VB=!y03zFXZF3lhjm#Vq13v?O>KSeM_SRw8rZ54B0>C+RCsho`xkzv~ zmx>;={r&{n=-E~g9xrx|=wq_dJ>N|{#wUC@LU5mWUy=|aaa%4=jkWc`772nK^NCvy z?foIFy~Ks1`z%5x3BGRb9y|ro_bW@bbyZql8v@Nj_7>s&253%FR4rIFRb78F2)y7G&#muA8@~o0Frkk{wqErK^U= zL<1s^1;V4c+@1V63%6ocg13U_mMrA%cxMvS0`x&ti)nL_J!8g$TP8;=nX0SMQ)Im? zXk-EL<-zIzFo?w_z~v0wkhR&bV$wUDP0VUEY`?q!+Gd0ZWBgzQJsW~YD)$E3H^Kb| zgOBqGHO>7#>rVjZ<3Ou+L*pxOuqPXwyw z*N3UF0i5-n1>?IV6oKSi@Mj2+v-nHUMD*(0zQ=I(?xQO~?!C2=)lxkuW{_w6vg=lz8B$g2crcbmSDCo zbn+C-2#NK~X5PsMPIMc3WUi*GA2GUB9?ob$9iu%i#}1esdV0HPtC>`0uW$+lw z{*m8?o5yt3S%cBt6&ZK=!QTl|O*JR@UNEM9yq`!ypY1cZ!y;n8Jvlg&pYO2!HsrL7 z9{vh7Z4=FffKRufZ1aYg-`jRO(8#X$Lut~aJ$de`h4DzPT1tmPOH#FU9E}MQ7@!x{ zp8A`)-M9~Qi-QqldjkrI@17z>Zg)m#@zj>`!U~B2#6zvc;dF~2$*v%7{4Sj8I)pjE zZ655wCyh8`{HqcfBwvY;UA9}3!DcvZ$p6@>|F@;!&&}6A?HqLf+&S`3NUsiG$CXJo zB!1iW5(Aqhvt@$$=i>0|iT_)1_}_Qp$G)EUpVbo_hw=Z&iT`=ve{p{P78UV!;(vU` zi(2diJfF9X;f3>2prmDCArt54fgkx#o%o-HBlr~|)b8;=e&T-~_>s@{%D+AFKQm(} zlBXUWZz_;^1_lNgS6m?~oXkiRf+s2WzB#TK&OVmCc7<~!=wA0Sqn6U%aKeMxthWv` zY|iD*AqPrt0b+K*FxdpayUi;hB4@04ks1^wZ;O?A=3IuIWZIiO2hFdCpd6*cc%~nh z&3?^ffw(hQnIXV4O5@T!feKsjT|`eXtA+G7B~Zn%YlOoVTj;_673&t?Haf=kst`0;9VsUtGhFL*o}h z7gSe1bOEIHosam@Uen;~ZeY;S>JcqM-yv$?`1aYrTgBGfN%bFAqWd3D zst6oaJ%xH#_oj;G0G~W~!!>@KK=075eN_eE*tWPYpC<@^->GIq841x1itFL7fgbto z!-saPndY(y!+!?!B;3!xh##x-uf;j?(Ubh5)3y%lZ%^_Af&Il(d$NDuCEM@wI2>%v z&I*#epS@m#_?1KWYkB&$I=!PTOx0ORRmW_7chAc;FmY%lN7fas6;Z5LqPii<1W73d zW20QS9pv0_>vXdvTpa(Dgc29P0@f0U;<|A3L$?QiEw?}m}@JaPPrM`#+9 z0lLjm6RS`_kcRZ%sNsgmwE!~4*)HuuW5SL&fyiN5?6wKGH$;KD^esHEMNK)&Qu<{`_=vV95JF?fj<@i9t)F0qvAQZxo z)9!w?j^!RC<>BK{tgmoeoR&?os2)tt#*u~|=L(QAO6wYf7w>urnCCG-bHjit9Y0`t zfnFc@$_?f_JlPeusI_0Pu%v>yNr1s7d%RLMlPG6pz8}Nm`n1qy{2@pZQ@2aQsSNN< zvk|3+8^Gq?iv2c7FQ?JEBgZB5thun~fn+l(dV{v6*8(l6r_cp;7p8S|i-^-atu4U7 zEqo6LvCXZ6&gZ;}#z@CEV?23Gdkpf$5t(=&YTLd=1Kr(=f>9c}b^(}$s@7%>@l%O+ z4KF=B8bfvG6Lo4e~#P zFnw--Z{}s}ujBO$T7}OR>TjlJ_`lr^zwV5G?74#E47SFp``j8KZ*Bpx>Y51dEa1vF z#VH5W%YkxTYT<{(2V^1Z4v6wFFV@rx5ekKh3pvFA4~pglbJu|YS6qT!PWRyo4-Xu zCoqYFmQt>~hab|^^Ya7Lz!#s&a}fDI@cF%E#L<-Yr?TRoe16YgK>MsKzAG#KJ3l`t zCw{$W{`mPtIRwcj;d^f%{0WKOC%O*OSv4a`vv%rshX9GT0EG4k%#pa4#Qic6D&B7P zVA(z_D$ox>L{H|{8%GJC&rLXTWyRDjP|f^0vJ3<{`?N@jb)xY6jDRYbYOz~aw0l~|3IvG%J1OnGcfViE!Jswz*;U?vKnGx3&p@m+ln(X!+(3w-Dxi1Ks- zU9&Ba`ox|r>e4u9;?9(>aN*<_C+Ru)^idm@dsyme7UIQcQusy-)9rlWS$q==`HASK z-GU58L*(iEmWM2I$vEYo0mAQl#xn&b@Lo`CIHdvx@PPR<@Oo-MA=h9M|9<**P~75z zUE69~j3y!Fc!a~wI1p!k{o|O<0{pQw#smYq9ih7d5{0fA+kM8%j$3qhqf02DqKmPh(-j-j!DWm`O zFYdqnAOGL~_J58+{onrg|M&kH;2;0@c!PibU-jc(t+;&7a`pVQtJVI z0aZD7jiDLy!L|S~+u+khVhpYUq12yOeY@yKOl$&auutR>Si-?=_@?Vk?$2HWa4+5; zgrM&B2j+#z0b1?d=Jezs(E!)*d2aGO74&NM#J(-@AWFKw&REJBg}29!6%?*d(9-(- z?4TSOArBCroN)h!Q=UEzE>e25QY7k7rc!NK+9l}^V^dt%Hhk0 z|HK@fLB=3|fHl|%P+2-iUC$iE9lS1ze7)+wIx~RhD}<2xvtcpK#mY;9x+1Hb;)Hy@ zLiA*TQyqL0o9WRUbBJ%r_Y9;oaJ%5bjpJ>mjwyXX>-%21DS=M|$BkJ!OC8s-)0#iT zoiiazp*_u~&3PNDJQ%$vF9M6APeQ6SK6TzUmC$3ob@g3y$R!0mF1VIif+1nQhKVz* zMGU-F3(yVHf{O|V$| zPH*5_P$XT`hu3u7?sBgTUOYq-a+&AYRIjeR4T)%>2lx=WDI9*>$70JHF1O$-Ztquh zcM(_ZrUISCad*Z~dq=pVlr;7WKqr%o1(2e0jnuI#lABgtkVjLm&m{kp(aG7NSwWdF zLwNg(Gyh@%ea*=L`t#3SZRE#*`1#n@#gay^DqT+0b_ULbV(%Bsn)oS7>|0k`9+%s6 za*@uTcD4?L8HyDtkT4R}j>%ZwL9ZZu87RE_VJ5s%rtU_7wbBx?#@>*jxxs^wqDLRK1#NjWK?+4-pbTIH|YVp zE?UFMo5*z1B_CfenzWly4x$v#x85b>OC2C8$T&=2XHwRxZ!6_KW9~tUgjHKv>*5yl zR6OiAfqhV`12lI1i`raKFXwUjHpcr}xEOR0-?fukoOMvL_%3O??Lm=)>D2Mo&cB`J z!N?;BWH+|I7Y>_a5R89C5b~|Y@Xs=+qqzReD*^@EKj~%vX&>Mo&j$APbM(oQQs(AA zp*^2XClKv^?`6;|hK&{K#TjKmPdhm_W~3)zmie!QZ=!tu8){fc4tB1JIZX1KQyje6 zk_9Vp8qrh%=F$X~ZTPn|fb6*NUHluS_&K(JP3_-sM9@oC9_nj(PVVaZg^Pz?GdyNJ z1q)yV=Nd>T`rc}dfLQD<a7jbIOs9(DBLun!Zx=vY4=&zI_<=aqkl#5* z`PL>_@!<7q0lFqEY4ZIMy|TQ1=lw3#OSW5O80&pXQBthT`_T|?uo)RTi#h1hwCN5E~z3!MB+bS1*@9B#c&K~qpK1pb7@wLP%aVqeO@N&?n6!Z_EM1W?y$*=P#ts}B%6U+nCR z_8gl6`+My@d^f1tnKls6{o=yu#HNQPkh~Pk;!DNm8JEQ)bL%P>kgD&e)Q0I(pI$1x z&4t5>OVvHSf^={bN@c<5?-mvfaw{UVwYtLFR{6^FWjqV2^K`nj%j?DUcSi_|fOtr4 z_7h-Xa5sNXFT4fSYyqJ@gvH=`nc0oI{=|cX!PyW9zUw!aHO(J85v0zO6wrwwXjXc4 zriHO>9>;sGxVW_j?)2&|NGm+n4h`EuM$hTC=~inrW2{V+(j6sc$k@;NIamT`4iySH<8=HYcJI(Ih=k(FbW0GYG96e7?TA)aCV2oz%`w7LAmga;?~^!G_vISAYxJExh?6w@%5$+X2?E^QbM_tXA9W zF(jTA81U^u6p9Z~C_bP~esSVh&cJehd0ej+e+~EOGcu#<+%vg@s*J$pAPBT&+ib0WjS!JC1FI2+{w3%k@Q;LW!0JQsQs$Al zf2)>0b~qbezq}cFpGLr6rF9I*gRrg+ z`GxmMpYu(Om>{^BJ=;HrhRq>`Y3}$VBu`!Nv+$^5fHh;+!VP?_RwHcHUuM=Wr}8!e zQb6T|J+tfWYw6IV>!}-n_Hj57ls9E|Zi^@-H3Z73#XZT~;cgOf;2pKpiuO>4!rx-LZ!+PV+_0>ve+q<^^PJ z|Ez2wU(2=d6@5Jol(R_=T=pR8zf(1^XT)U*)|TDaM#a8_Gj5y!v~0k4(8I6nnFS^J z+YlD|i;dRU$9v)BwDqdXsZjSrXAYPCc5Dd;GKavr3Z+&^1;lH6V2|mhk*?A# zQh}$oI#$@aamY{$7S1(L4xqWBT$p#OJ9~(Z&tRJG&j$!!@K>QPX7Uv7ji2>;v9&I@ zRcvk>LA%}D)*t+bs!vxF@JffrI=5wddQ@{@lFcDFIpk43H$aIn&Zhme6yDj+6^Gi2 ze?JC#7mV?OD-~UBPN%Iz{Gsaynn*h9v*g=;@=rAaL%&7M)AxA8-@7YG>6iMz0xqES zcFKY6g8|Q+1Y|-n1+psa_*vAozW)%Uf|3D`d!W5@P3#4G#E;G8`ximkC%kX4Uw;0@ zeF+h*AHlKEGP_#Jr~T6U5+?igvHZ_x^!0>*fAhaTqhH;b8vs>;74v&a*LQm+W#Tzc z#%_*RaNk4uX$|i8MG5>@==dkwOu1AHkE*=%h`g|l3%m#pd=u)jO-&$s91jeG+xq>O zBNvlRC(v-7AST05S0R5CO4`#)(M;)+)sL`?;nSN`hh$sdt9-GuS3z&I8DU?&-z5iu zdXo5ZSr5lh&waOeHQWA-VQ3Q%RliTVF3T6sjCJ^qF)n=%XkeRPPEf=qC*k}UZM)f| zbKVb1bDJ7D9BdP^I#G`1(#&^n&gD7V?yKW=51{Y?bkn?S(awS_ogrYbNIhDb16^@P z+vfW|@RVV*R&fU@vZHb;lq7>q0@tKEX(u#T+>?vcvgw@=!Otu$-mq308WPle*l7#{ zwE73CvR~bq2{2MONj(38b9XYo8HcNpUTL49H`2tNJFlNvmx*-hc zE}`pd>|&C=%y$TeY^X7jT(|z^eh9H)&@fvu*!=@d8NNX8xG-R2$54xYTr!`5G}HUpJmO)i2#keNfffu@fnZ3vx_0vDWRjawjMhU}fdpAy15Y^tJY&kD8;tmVltJOKScJzFmT zV0;lBI|Pih0SuN}t4W?Ec4;zAoi|T*<*g4ZN_^*SQLFJz_HQ zx80uo-tC27taRdcsarv^N%=0%hz)#)$A@G8?A$4CtODK_fQ7uL8Q|e8fj|2lj|~=z z@+~>=9r)UUfYUobKr&=g!SL|Q_+t*G@P1q6n<{@%6v3_zP_ZQ?@8b7Fz!odGZ69JI)NQ+0IU$o{9Xu;!ZmJSLwdEm17{oL&il+Gq3&^k+bc)?IK`0%K{Q=Vw zp%KPux;2t;#b$7wM=R}ZtacfW5UPY!8qTh;q0&*~6y;`iVKTUL(i-;q?_5 za-|4w26P(N{5oF$#?Xd;h!0*pZxRgrS^W?{y!+w0%~9EV#IBPs*oM8Ayd-vkOHY8r z>FelSpcH|pH~c$C1>$L;b664-K?F1Wmluc-K4F4$2@g7o1P4|Fo!q^D?$6}-{%@Gj z1$6a*8BV4Iue^^>Hw3Q}p-vX>1K`Cig4(^G;Pw8y{r4x{y?^oJh2aI^xPjn`_X)rY z+Hh^Y|G?Yu0Fk`Uz=u~LxE&$CpP1FwM7=N+sj*PoXk+;iqluwG`EIep&s zD18=kA_0*U!6zm|xD)MY-gpuY2 z;?^_6;@4)w7_cW{%15WaWWLS1K7%~@_lRM>sgnZ! z_m|f6!?#Z8?@`2{H~7=tkXGI*gY+9Rfg-lQkH3W6@}J<1CUC`mbmwkpI|Ydw1aG4l zu$IW_Jp+Tbee~IJR4jJ)x1T3pWp2>o{7PGg8=bv?F&5_Z79iU{<1jxSgvTIcSXkfk z**~4lk0%3+%KydL{3cD}trdgL4=k?w&uJ2!b~z4XSrJ8@H=UIhT1n)G8asA-3`r#X zoS7zX$|%~v21zpP$#;omgroNZFPj1sq}DuxkqFyo=aG>XeeVQ9;qNl&(pPI5Vm^K^SU zW8aQ`1W}{txt6k%(=WyAbT;FsEF2*07gE*E?l@FIy_X&$0;H_R-HY@L3506(EJXBJ zt6BmGKeVHC;6<3Fg2AM5#q&NW$tF|CkWO#eyv5`y$~FR_AJBG|cMC*H3EO*Q8B@w6 z;LuZm@@_CS#?H7vMk%9FQV3*$)Pi<5+A|^*r7U&6h>yv5Y^BSk?Kc+E7}wOk8NCJ> zz^X6XjCsD1wQeY&j2`Xm*NGV=V^OYC@x};Uc&F8VfUWpIKhvE-5~a>&#s@^Q2Zwb7OHr z=C0i>>z~M}mbV2qn1mwcFWUF4{8Za01H|5J zl2eL~Kw=r7`KvdMCXB(zP123>1$MBFYj|Rk3FIbL(gL*QuqX9BYwaEjVkTP~=^2zd z+#kkX;*d_;T+hT(<+l+w9o%lFj0>doKJ0Z-373cfkbMD4fD^!*8?##Jw5nn#ZV7fZ z(@aWqIYAKRlDV)E(XxTq_^nA$4vO|De(+zmU~4^ey}kx}Cely@K+o-|pm! z6ZcS(!5xVPP3V^2$w?omEI>h-?wrHi>yFvM1YI$qyOsUXIn~Mb*hRM!cWm{|HAQjS zU(Pp{kVjjZZXV$#-oC7&?G_VPWD%TB_eI;s=kf&v(_;fVKD`tn!Q<>yl|y8Jm%53M z(|xz!tUz~I>n(|ZU2KO0&_uq++iQ%qTDz7qvc z8m`pYPR00$E_SCq0LLPr)L#9ZtW@0$Mg4k?uuNsH;hGAAcOsB~56mGbhK4Li<)eQ4 z+PL^shyH2lV~6+BhkX+*39ftK)4Yd?lKs2h)NBAP5vG@44E*;H5o z4t%4a%33X?;2fXfZ|529d>6>bmo(#s`{G??zJRdh`nm*E zdY-87K+SpWVjpxydWo1#a@5XPjaa6G8vs7!E%|yq-+XDZ5e;A=GwG+6;Dou>q7qnH zVRG;UF~a4@;{E}BrWHD{cgxx=lDIr4-HxMR9ZASdi`grn!R|y}gQomOUHgF0#-ef; z{t57V30bnRAHuWz>K^4ZHGC_L%>FK*W{hqii`@t86q!cqp?*Az%RC#reh>ikG7hc? zV6qDs_%D-?X>Onln6H%b|h@TEPhN` z1f+RvL52H$E{eIuR~WaM=dI0vb_hb(`WZ%ef%x(@hQBj*!P3r{AnbEvx#elwX|C+} zv)aUaX%B5WU^Wom6&PA?<=sEP#L3J1I{u!>E_tub(d;|Z_wT`pdzP9_Vh6Rfqy=P- zf0s+8zi<}YPD`bA5Qiar0SDgR;9z3`eZJDM#B98qoW?F8>D_#N5g3^mKz$^@0LRSo z{DZU>dQCsLDuA4GD?q6?ZG7{skAc_{bYBM*z7Hr2{=AzWAYc4-AWeP_lVI~jUu9x2 z!KhKi`dlYRgvEzvvVqBoR+Q&w%PT8%+?c)qs#r8@kqvo`lF!qRgFH+Pa;;y_>6lvF z>vc$`hE**sRlW2+Ut<8iT#(`=YMY32>2MC+6G(I7{H#Y{=DVZ=M5~RL@>-lC6a&1m z6bUDT-9p{ZoGF=;`4Bd1VY?HNn}0q#=YijAbFq2p=2#~7ZU1~-q4y_I7w2@$HDrH=?o2XUO0QceCsxskUa!N$n4 z_Hj0gdwXVUcB)1i8~LV_?U|pBEP14{qp7I2aDkiHrN2WI!SFn2iEpRrr4hhZsnqbz z>Rwyac1|lWl4M?zIElgr)y$S5wJu_iFZFS#1M=KKCgCrH!bBGohpuiLM4-`DuH*5k{h^{lbz;_w&_ovbEKnuwiP#=L? zsnjHZ^bdyKRe2v#Din@a?%G1G`h15LomuZ4o+%-8H^FPq;1$r`ZO!&MbUUgEy~Qbb z^Vo=M898tz8=c_k_ja5bx(Dv-5&nr^?V;HWg{%5CP}!@?QyDmp>I5l=kilc{Y?O ztDyvaj1Pnl!5haNVZc+Om=)N+x;_5r zR`{$&3V^sV?|s$}4r~F65pa6spAPJI2Wj)W)BWF`?YqVFujZ8Bc~d}99{;+?y(i|N zy5ZC}5iiq0aic@tI9o-Rbd(6g+%f8f(bXxxoq(NSQ(8(ui@?$zsKIOJ1Tbpr{UAM4 zhV&r4Zoz@diJh$R(Gbr}1)bf>HWk$02cdpxhO*SRWtZ2JwUg&Cyhw%OT?KCI(n!_= z26zUhcCosC4cB2pPjdog7vxUXkW8$Q2`=w#?>)ZNVyEzhk z;H&+FfNru_Hx$Fqi_=Rl{-_BC%=x%DxC5USp#M#P?J`tMNBDB2kd<}mnH%93W|;fb zQr1Q)>#(s5rJ~3>r>dR%#?NsJv7LuYqK&kBVfSYsqP#utaj|sieZ4QzTj&%>5#PWQ z6t+TDQDt`)S3ti(R8k)-rQq3E7jq7>p^*jR=`#KEGWmVJfRY73XpDltqW>{paOF1N zda>wkhyUTi{L}TvQ12P#^i7c}!d7^z&k*(cx;%dUaNo=|_%2bu^g2G=2{7*YCDML+m)yDCBEalh?sP*;8_ zn-iMc{yGi)2C@C3bNQ*6@)N7qlIe>dZ}dV_v|!wu)HUVmXC-z0&ZCK6c;}x7|HH8# z(X+h4FdG(H+KEB7e)X7ixU7ONmz7+l;O+Y9G9tf&6=`v&W05@EmHseqS7gSKc?Zqs zhr+Bf;=S(GQOD@HmCw^YILvb$i-aea*Y^BLO!cGCb}4|%Jpnh}MFdjVzdi3VJ+FxquTxuFX-KsCNL@hTxK zn{I8qQ+fV&G;!|)Nv&Fia!~zIuN{oYYACdh)dhXAd~faNfu>_qER&jY{%yTy{)ZbU z@E%A_@rR7Or1aJ-fO75+H-X<)Xn(ph(8K%A(0)^|=!RIS8j$Y9Ga7`ggF)xMAO2=E z|4_5+f4oC%Ao>Bq<(TFhhAma%A9LcsK1M;JTMc1#Z#{Jh_zGC`fdFe_7HAVM3jNtK zf>ru$gnB0DOqPI8egJa>L%(rMbkl2E;5<=abGJngvzVdT`mkt0O=v{-j zad-U~0KVOFKRq^wKd?XECg&R~EZ{4vKJQtL#qVzY!x?ta`Nl`j>63RJ-~059!wm&~ zI4dN|nAKA-6QJRpVXzw2Y1Ar+VuytrVW zqDTvv13m0O-U{uP_ht3}x5Xbcb#E8MTc{0!A@MZd6SB;0jDyKba587E#P6@5FXu4| z<%bK?^)t5B)X;`R&}eT+Cwl>~O_}EB{p4;g+Z|Z!+r^Z$fT8w){vQGpTOEpl063CY zva-#H8+|*?r6nUdog=3g0t&)rRO8q`57d@SPH5dL+k?BwmN# z5*DhQ&NGGY)CfFgv%04q(Y&?59!JZHx}{?w(9uV-qRe6(que^3@LL5KQ27NPN?UC3 zYq4w0bsubbN*i-wwe*r=U$3+0^QE{QGDayOC<}A7Q-8gE&uRWZ|NOGZZ$4v|KN}{@ zr|to?ET0kcKM`<6WHjWfy^o)UwVofhN5kBPepuA8{JKtmm0Z28#Kb#5htNsnel8(? zNWnvBL~MIw$Mpku*gaaFm9-~$(7fve)m~-CS)WG7QCC$lDJsHRW>oj#bXq>yG9TnP#de{QUUmukr znHUX=pZ9-Tr@6B6z4F_H5t6?EbPn8t->$a*fj;8?R<;%2bl)-%tv;ln!Y#EZ>2E%# zw`Fh!PZ*d)KALL`L~Pv+aDH#xitWEn3g3f5u-=nzJb|76n6%SC(oP825wNMU9~SXn zQg}Xpw)yhIFG6q-yu5&6@MXvQY1jSbv7CfehM4(Jl_8Liz*fuQnd>YTtZL!-V<`_5 zToaz~n{53HYS;{tPx^pM~$gEq&itzPSur5+my*W2ZZjoIPgE zG6=)Hp-kWmn~aw)Mk3P7S(0E_9g9jonp-wW3O}`h1_-?C*;n_)E}HhTq-aULQ>4@B zzCXLr;3Bc{)msT4Db$q}H@m8ZHa8w^+edRa7IkT5F$oz@YtUDYzJCFLP&k?HHCgW5 zc|XcPOi$LLswC~vUJ+kjsm#D0sN~*)!=~eP`@mbtb;MSAJq25w0_2~K6IY0C-)59_ z!mJiR)xq%<>iRLc_7wPD`L-{%I+$~l(=C=q2+i`iyxd%=M-uuHC^WVPd)8ohEj3~ndp!w9dP;mS!wfJ z!HnQ~#pLqtOWkF|w0>`2+ySEuP~jT+7GErn3mvVw9$zmzoiAmB^k;7_ug{kV{~j?3 zr0w-~xVNrEHWMG7p~(`GIY5gyei&Mk7;Z0U!0_q)p0yrq;xR=$847n$U*V+Rt3ZgO z!aP#pkb53m0@^=l&%hw$$>R^uTHbooJN?5&ypyeGJkN<7y zv#7s5k{>9D(*eiqccL4tfr23X(-Qb~W&C65d3;wjef3p1eRWs3)#(Jq3cDAp%Z0Cj z8Sdxp?nh%V`lT_rF&KN{L2v)HSY!4E1dDz0#6XBKh9B11aBz!c`OfFvmU z5KP3F_IdY9&MY=H`qj}{h(N?kA0 z?Qwwh{|@nOXN^B8r4UP(3EU13J=(@d+ok>UjM?XVd9oqH=c>gyaLl&Y13Wypb<2#y zhT?10b4x-*?C0$5>9Yj&8^@tIE@Dy@xM7hF&T5lypyaTJ{lIebT^IbUWIv!D9$ZXM z_q_T>GxUC=97#II);!Ewc96D6{5tX4!DnA)2jf-Sag+(;5L;V8CvI2faaTW}sM8il zM3Aq>9QOr#6&TTdNNt5#cNNkjSk|wPx4zVmbb>dpH1O9e<`NJDokQT=@5|F4)gO@i z1F(G{Zhi%keMuLBsAv|{5m(}!D9CcW9Z@j!#ILXrK^2bh1qZ=!!A*3jp*L^IV}F&l!+8tC#?@Y>al4VY z+3^4&QtsTO;nLa_5&-V=u17#i;2EQ!heglVwdd09`lv84F@Xb@Jrn*TK)cRX?+!54 zDSI`-R04BOq%Cs5_x6sXBd$Cl#(wRd!A?eByO&T{S8RK%UB=u2#7>jj8?9ZiI}>Y$ z5tPNWTql7T(RBy+|J#NV5^)CG0cTdTKpl|vl|kMobD!!m1vCXu93P5R_guYjT<+GR zc(MFrH$U=ZqUS~9;SQHyajn557<|nj)-1_~eYsv@5hKcx*j*vSm=AXm&Pz#od6>J$ zACz&#I5b@rdLhsbzDM>1SyTVTW?kjAT@yz={M9S}q6GFY;)I?K$KC1jr)B-?^8WY# z{%OJI*!L6&S-&p$g1w#3=V@F`Fl+s8p|^k8lp8Ps(sPpd@KwF{xmWv5uLK&SW2BJ0 zQvm<#N3>1;#+U;`vkfXpo8iUj0m*0Y$39oVl7kI93KSamr2=9Vloeka$goaB_n8LH zu628_*KfBBG?1BZk0~r9iM$B$^N#b5$%23#8``t_r%#6lHRC(SW&#Rj;Q}K5!P!4) z0%2DV5=WBr?jpoSkl??DJI?ztsOsSkA{vl`vr%&aRe(08<_WC3--GSHR!Co#-CuL< zA**VX`pF^_>j^90b$$v+A$XTT-S67C9ypM^}Tg&Afz=(3KMz_ z8=w=KTum9V4UCiTO3fTmT~`9H$L;%3+mJY(lebqpVa7C@6|B4#Sf^=HlgB~bwZS^E zvYH%==NX|>KE|Icz3ZcxlW}2i-2I6vPL2nYlV|P$-duZ~SV2+L1rdupMD|B!z@Xc3 zq>nqKig%F2W$X}xcrM zi1m)gnfGxXu_WQLIJe1Kb*UOyhywT9_^e-SL9DhCE>C#9W=}f2v6n?T@qlWJ1e}D0 zGb%ZAjKEBIQVTMp3$KLeT|KmcWV3+t0^ue*u{YDJRQDoA4$ao#ovTye6)1y~#S@PQ zG9QV|zNJ@F!bCV%O> z{N`2#^1ZQBjUxg0BFJwef`M204G{1P8A4>*&nHOWMLtvX1kU{?H4!)sVs?JE-(>2~ z_M7U_LLcyNOUn2GUjt7Lq?rO3Y;{gZQ*LZ9d#YZ<|s= zP6T&+yN19VbOB!z`~p0#62#%d#`NKD0x#g(z65@!5C0Rmk=_^x;N?R?2?3xrh|m4a zY6_-O=pvCJ-e}eC5Zu|*X)lYilM>G+g_f5MwjTQIbuFh&t1Dac>KSE$P+SBgnJZ z80USVbQ3DNW+v|By&%&Rvk(ScJh!m`v(X?j$A?>;UaY`OyC>Qg+zVnBpZ0W1*Bpy1 z)6_DIIcc7@u^_}qTb{Ps#>-_9Q6ms+OwLyJ<9wfT-9#xASOL|+# z3dWW&s-@AJZXP^@wvuDK5zC``kgw`lb;v+Hn{aKg7j(Je_9DXW-av3c7VS6cm1CAd z0uQaF?Rcy(BWpdJyeBi}u1f_Km65zPl>TM(JT_C`AqEZw^l zvCF!&9U+}(3QtcFO?VZ@A2YKsj*6X&Aj8hj{o!svpcNm5wpHu(A-kaieh{mR<|@sp zp{zW(DUX1i6CXrN5dH}kXvi6i)=uj)vWM^~BjkA&uf|aEnxQc^y=Pto@bgYhjEs=T zxn*~WIT$f^-Zv3?Us;f`UZ2Hq3e!%M*1N+PdsOe@)JI7Z(c8c6QH57jx6%I-G}RAv%byAn_VV6&;@@_j zIw4aB2Tu8ZM$#1`8~00H#eW-myn#)`@z6QPBdIDNqhfboGQ{Nu_hOKVTJ`ey(CoW}JZy9z{x@}ZOI>bi@nsg~|3l2eZA!faT zr`{WC78NbfQJ#D)iiETQGUIg#6NpabALf-Aw4srL0nIDp?j@eY<3KDB>qvB@gL9hK z6*N;XzdHC)osuU#gJ#x=mn+wRygYleeXU{8Qx|zcr~$?RA;1pyNVN0hQ-()Z((hT$ z-=pf0IdC`D5jp6NQXP9Ay{l9yT7P{3h1_P_xV}>xjiOl>&=1i1P73jw7R>arYPc$H zrnl4WO82R~1y0=L9qQUId zhXMrN+mjc%6_8Efa_k_3`4nGLvTlKaCk#-8rGoa#LUuE4IxWA?uvCb z4N#{r6iA(Ys*%5yU%N>IbuPInBXh8XX3Ju{-8*ubzz&m?bUJQO1g*CjjfEPm!e9rF z4eTy%c_lp{`_ZG%5x}P*?7>T%GZPgo)DzH@Ajsy(qfk&lk`On)YxVb>Jn^8K_8gK% z%kfd+#5=aruR%@nW^u!Gval%77qGm-d?DE<^LF#gMg2|!p-tOObn88@gb2>uo#mSd zwWpZN<)i)Fl`xR`$-bcd)J7R;Lqi>cyGZU`*C+NXS@ahPwGFVY>mdFoyMGSQC-mCzKpW#z;=PREZ)^{7db1}NO1hp(`&&FK~A{{*XhQ_vZCZA z3-mVII`lps`-!(Hn6)b)?e%O6K=DT0K7MA!$R@sroxHhvE?GT#Oj#=eOjmNox!#8D z#hAx~Gm9OByU(t89sLQLy32EuS_q*_%E^hBhxwWtQ5_*l(-~s@wR1ku*$RK)U=vTo}XrMiY~JeY~rb^0WIi&gHKc;=sV z8gWR2sWw^X(EuMm9 zI~h5b(bpTfN3N~M_D5sCJx{if3~qcu^jcv{M!V(tawV+h(Hb~s)v#CXTmH8-wEQf4QnW@%oeK}D9?O9bm z#bw6ljvpv!%N#D+{;_eo>tp50USC~Ob=2hMLPxy5yJOKk0AVs7fE^--%yEA^4iuK+ zTJ-{sn+M;Cuk*U!OY*1`*mY6Y|JB5QQB74vT@Zb$^8V*95as>3Q}U-egtuTANLt^9 zfpB-!;958py?6G0z0}@=U|7a}&3|KW7E41Q>o+3Q$pX&ryX^p+UjS~{iF<&?bOl{- zh|hd*#tQV@7v%Qt1pWgJm%Gj$SUaChlJ^=2Dti3efdB(G-$^{g8#iSrq7G@5>Pvqq zd2&#Ue&#;4w!kG3N$5M%KR(&J0Q#syB#Wp&*EvWjX4D1_%HGXrNad*D@00&=29O-g ziW9`Dzt^^pn2#?Cj!&&ENcf;tQ|tjp2^OJu1QG)$`kHM0D{Iw->Q*33{KhKb7 zUajgn2K0*bL;`Bc8y263u)@BZ`0#lY4_*X(h5~WUkYoI&EL1Q60AR_ZDp$}0ec9c8 zJFZm>;hlQ<_B64uQ7uWR-3}^%Gp}^8aDXxWe9Mi+fDZ%S=8sR7*egbY>ZMhv;N!D} zy9o4$QaDB|f$y$BfHd4(0OtKZ0~Z3NKdtRR?)-=d{LlMAa2up1LKz^`X(XJYIr)5M z$DWFCDT1n@gQJ&THFyE)5lOeZHovZ^>z|yL|1hfyzAtF@j^bmyLQovBxsPnNbZ&ce z+5XZYWo(Jhn?$S-nY`tX(_M2YE;Wtm2p>TBIwl}MNxicopm$wOuc}Hy~w9Tm&r|NaI6vJ~?QWMc}+*une2^`$22=TS(j0 zA*BzPuUMiY8(3OF9FgwFsDcg7@e#!KYGTXal7+mztYH|gh}ffAaY(S}u12DMmhRU9 zEIYCMU|2qAubr)E9d&;c8&wss;ousSzDJF~Y`c8_?9Mm*VQy_G9Qr%IPVp$AoLcME z4)e?qn!w4VXv!O(8wGr%UGws~B||I$y~I>+9!O@qJ(7Qtmm-VP7}9d$>%DfE-OuWf3*N8E0ULo!SB3Waw6xZHtHJx%kfZ+3GTqtR7Tg9USn z-2-r!;IHR~4lythteJ#9F5P~0E=OYB?q|HxxJ27^(e&Kf@=)HYG#p)V4|!8*zF7fx zc_)+oQH05LzG&(yVevR=5Js1_`RazJymzV!!b@}nh{&jiz^Xihp-Cn11v=Fzg%#G+57U-`iQ0=|4e%Q5K(AN>`w;meR z%o6e4uJsm1IXw4`-1Z3`JruB_vIE=)s*fi4mmTpxcCJLi>{emFnV$-Fq0Z6Czqb*; z2otbxjfWVW!so)pv!jVyFgALTH^%gMLxmFob;hb_hs-|R`$cO5ZZCUtu`3gPb9l;{ z=NgH!1!IJ9Z3UcSF&8_x?GX=BbyX1O83&J?pYt7(u!yK!I+@kQ!zgtA103cySg-PB z8x_92F`SlrUWYvhHtQ$EjeDf>!rR?^;V$*n)S*j7;{{dhFRd1<(w)PRe98$tGwXHS zAvb#~plDTkJlhDTjdFtab&?-|8u*lf8dr7Z-tZLmir0Z$+=%P83u3Teop2sP>5_d* z)9m%R-0Mz-03GtYH86>E1hUQ2{l*m|lXi|<%L-}wA>80@oV{+`qoE2;@0BybrQcfaWa&mpI)WV#%u~l~w)S z)_5{UNP)@)YGI{O804VOSPGb7#D%KGGtnsbtE`Xx0z>{l+Pp{s!cnVP(^bT?r=3cX zc>l7Vc`?A|_Kf$dTC*^)9yRcE>ZPH{Ks1l3QotiRyjrE)*Km!86qq=Ub zG-q)NuvOazV`;TJX@M8bu#d$lpeRrLWMm!1T`mbX5ZY2a#>$Z}Sl{oeg6_9CVP{6N zxpD!cL@S_JWbV+Fx62Cv9k(tR^yJpv-I7Z7XSs@5TmG@KG@-*qTHkW;!0=J4yKQ}oP3`&*m1X~Hf9d}R zmE{k%5{v&TbOX@_NAzQx=@5ec$jXbEl9?}_XO81#KS z_vX)ifj{=z4k!fY zS}1~$1DFHU9dNvEB7a(dc&yVZ1x3A}Pa4O?yiKz-cEbU;D6P4Q*@O)_c6U z=iU`i4nbfmAsTkmU6s$!(>e_S46-i^)6VE97&bEATfczKT}ukb%&4T{NSnu8oNn!E z?3+ZV&gyRS5XGIVY3OT7!SgJDiZ3|7Di*qi2t}(9J=o^3n@q3GxsbYwN}v^Iy63i< zoIKh3NAD?cXTAW{Y^aeNBq5Sfyib#4qyk>5YC>!*9)*2V=t=iR;(*rH0B9n57G!Mt&Q?ENotVcV zpm{G@{r$S*P$4`3h5^3C*d^BYv^buZK58TP+@s2dN5;VRPI4gc>iWP#uJ3{uoZsyC zyA$oxx4D6>pNNLDa{whRZeUmKIKL9KgD9LZ@__%Nh6N@lUJ^%}>w>z#n&@XRJ~Sty zL=MtEOb?MC75yVy%v2@WqCW;$WWV@u=IyrPCjQd#Hh`wxu7z$CvMAhF$zq}(qx-#nHI9`1|79be8HPtgE!Zf z!NqhlKe)3Ai&nnl6m$3TJp<;_q8SK+`UtlBOB2fr5*`j_sL~GH^xR8>gG+mVE9;i- zo8$$f&|)pL@1*sFeZFZm5a;(#*&oW!;ujO6f@i=FlLfZbt{eCE{V8;qM-(M=K%?~Bj^!>mBG(ga*`)E1Z7G=MK%7PvE zB97{d@fGqjqXG1}CNPR&`}tX(eR(p{k_!eRCxRKeO7C4Stew~w)h~$3zHDAWHV3wj z<1hQwjH1AJ`UrL*W6o9 zHBNIwc6X$Q$P*|v3}lHHX&EDYknUK>uxmm71QT$8Wq&SFfkl^uO(6opJA&R)12gdiWw z7qr#va56sncJG}e#NJV)=vUBkgs$Kl7xKA8ttk)V6Xv}JLh|}&A^3AhVfj-A^3UNo z7?{Vv`S6qXABH`a0IkRG-v7jfq2iBfuoBc@0Ac=6s_44F%pnOK+0({Hp@DBGGxN14 zIky&^I>f`Opb}e3#b{>k8|j(l{T=AqI0FcN&?Gg#QR9}kLgj;M1Z~3x@HYVRfA=Me zZvaf#Re#HQhEBv=iq^b?9z!?=MpqE;0snA6@Rc|J1X%tsl*#zwCa}vbiygj9A}48w zgel#VDbdUcRJstHdp%kU*4)H;jh`F5f!)xP+Mx%^U0wp&>-Ls}v=dxwHF;mm!Webj z?a>_@f=8e<2weh$9FB4e?xv7AwYe);nCv1?{Yr1PPidQ_w`YtW<@xMBSmG{$8LJ_o zgJ;z9O2>fh&7jDGoL&`3o}3KC@pMTBIzJK3>$=1D9EpRHU>w3ttfZIinds~j7}BcJ z5cONi70?K#R*0Q&^TTOAC6DGR1$OX^Ac(s2qBlRA6Q3=rz zXU-VtVU}`y>?5#g5-eWh7KZLsApW3;d=1^_IgO3!bzR7w)`+?@Ef!cm-s{K&-&_^Y z!H4h5ZF@zi;w^tfF-jmaCamG=y2=x!VJ!uc32om_oG}yb#=YaDS zq5=RQ+4vRS!)geL+F&~ex5VgzZT7u6|NJGzlHPe@-+$?k>-GjhDSu2g`*2+RdELJJ zcHRC8&;Pb?|8d_rdFQab$3`VYK_;6UcgsBvgJ>my1Ua|Y*ZUOQL1xf3 zez{GRKmF2IknykU_~uUw`MI3cGeIhD95Bd0dhFfI82r*4Vo{RJaZ_%rS)EF;I9KVGO0C)s6UV-fOjDry?5@{TBjt9_+sBJ# zJnP7ev&OCL$nAH5JNT`gn5{sbf< zw{`8Fa~12H_B9Ft^^j7KLaC86kXl4R5aIN{ntdC4-`E~RL`FvDo5fn|`&VnLWxj@K zU^V8PWAy%X3iR1ZcVllOy>_2{H_T5FU)7fLAkFO#GU?Cx#%gW`8>}S%ko5G;9TABJ za0e&k+%d~H4VY*04g<#FY8^UtC|zttK2zYhKo5#U)XkBJ6!bN1sO$xSB8|L0f_(7B zO(d+Qn2Ovr%&bRGeI9Nnl~v8BXHh&j#__GRm6Hnqfa>Cy07Hb=Hm}uF<9$ow=bp{8 zWSa>ZanR(dxk%#o!y`Xt&b*3NCrHq} zkSDc_gBpS^H09|B7>N|v1>9u7|FL@edKZdw3SCu`IK)`2*vXaLyzYKi4rIbP-Hbi1 z)T?FW@H9kKf2x&Qh9HC*G*+Vv&M~9_r}IdrDYwhPa742(vxjEqR=7CN#_IuatoQc1 z>9<|gHBUjNtt{qGpbYX&rOWjtGzI(`cdm|2?TBdm-4((W)50qD*)BZX=6m190c7zq zj9?xpeY=&JwbWHMxGOdchr8ZRzlUS7rJw~;3q>40&g=fdTqO?a^v3lJ6g=V!Z6($l zqIRP_wt1Gf=SyOJxzZ1>5ncIePZD{! zR?*<0TTE`Ie^as;wl&aQdmVVBIGNni(i`ng>wC!z@4j@8iY*EPwE|V5N&ZjDy9$pXlo6b0U z*xl?Hm(i;fwf9P>$920ob#a7C5NQkU&kY*U83(!VkF~{slyY@vP(jCr0~*$-o&)&x zR-RE8UDwh&HCX8-yUCH&^i=8g*A}#%;8%jEl;Pqr2$vnUkYVF>4FUATqi6&th8wlL zfvscM+JNcl@WN-CemD;oZFY30+N20P?hS z(Z=uA`tJFp@hTnmeA{`W4!SPL9}UozYTSt@wXRkyP3zwTIA1vOKwhRqDL36FJnmeo zPp5W+H81K&gRk<*J7leZkMrN`VZ7~qfAJ~*$i6EdTh=_xXV$>RZcAu4KbWrDlq^C2 z+}J&bubg1hK(W{b?s10{C54{X0PuBDr;TG#y|6!2hVZ1hC zClPQTaFi>beYmj?lM5(@-NOUM=H>+6VBl@cU_*L>#;Psd!;w6oIV1^aaafgiod}hU zkH3hJX;J428iHh+x1`&!?Ov>$KX zrEI>3ntrWr|3!Vv#0{VZXE3wlKi9W6uEX!D%70tm4q;%epzGNIFS7YXeFG)yyO#7z zeS5p@|9XA<@k;)a`qnFsuD{MhL|c!DliWpaR zc6weZTSVk?HJ$eO=sYH|NR`L@Vp6P%I(>B}EJ($vi`&*13I+ghp2bLQbb5xE_F%fE zj)=^GpvWP*@J4q98Ud0hXI-vQx+zyoOXwYdugT-x0Mc`*%dJw$hSheq%3MtVJNSY2 zgvq>TTbe1_uiZ8)##_Ly3Kl!2B!$4v;iVAA^ON+0c-zpXyfdyP6&pus%AUF|btEqRslIU#;6Xz+=y+vHQ?tSN3QlVow8k2IaQ_$e zZTXbH*EgjO9!1EsU@a#4YkZv@zR}D{63OOnV2@`Dkrd)FzBt*T7nA{UB{wo$nlwSL zx~7elQ+OkYkA%@8`jtKq`>hF!m1Mi~UBsKC0ZsO2{-HY#hIy8C|j0@O#B zOD-uVKDk2teHg9$mCdRGe#J|4oYTut#d)TrQVl^Yx1Jhq^|0+;6%9IQ<1954ND|~} zljhuf-{STwiMb0CcHS1jLg|^q$dBJ2V@b?jwQ?%zj&*MF;O%ccz+XRt$a*!g|e27$2Oc5Uys z{q`z;-nA{8HfS^&_!j~V>>vMd6~D>Kc!PjIR0aZKi_ff#7pG;dhoL5D?6(joMFEZu zhDX#D{4*PQ%iILLT`71DNc%oUQ-^dQmi<~Cs~S!kUf&=bq;cnoH=_4ot63o&I2mP z{rwA1Ck4=6amuu{2Z4@yX-}k8K}jv6?e&E=mPl$Jw=qdE3`kIhp zp_}Jn?_LvR2P}on)W0gtXAWkvPq6u^-BptVml5PSuGjbhGoVP5$9ld`^Mp&FNEfMV zK%r*DUY^6TI&;HixK^}<+_z%+V%z2*7LNzkU|BTmJoLa2H;+ozcY(PS*tRc0fePre ztw_dFao&JAY3G^I);!w4SS~6J-#oU4g4jz!s*KvL9PWU?S|1^%Z8Rag=yC$*W;XX* zfAVbkIrJ}`-DhiQ?>71xyP1$@jOS%2UD@@uS=;o0QwTGRoLs#W?{b0He_XM9MiCy| zO!?a@6YOPO0Q{`^5T@`B!LqYd%XINlx-6rVh$kA+cR*&be&vyOq7f_xnfo;Rp%8~p zx9SUSi{1fYsdfdwRUn{AI+&?Q^}8p@#kdn3MhUMkTFxGnAwoL|g4iCz8bcw2@rIzr zOg6Y&9kEiz)yssx+=`Yu<>w{jvvqe~gt>^`T6W>`o2xMS>vLJs6F!;$> zCjcw}u#aG@<7W@Y&C`WqXmxHO0pW@0xOGQdJ1Lt)UUM4G8xct*k??SlZ@P z7>btbD+zq`tOrxh0+-LdZKp?IV^7C^Y|1TF-=OVe^z=p`FHWg?gmKT6`yuR zv^w?-vq2xYX_RH2dDL;jyn8l>x86!QmI}Iz<~9d^IzR7XUKu>X@Wg3LMEa>h8M6b+ zmh?ikt9uO~qnXwARMx`EY?H>okq5BJkC-o*x(eH8)+*bx(;ErR)F^&9NQ{kWv@zbJ z>p5nUt@t9)S6(O&k8T)3RQ73e-9xsV8t%?`RnNSXrB^e;!OH{e1es^ml9I(651nvx zbY&GmsgY0ul0O{PySEoZBLqvVe`8)TsFA7b?t+%_WNw)Is-hw;R8?Q2EtExE@?N1Grg+ezU#n(tr{(V}sq^X##q3V#vD6ObShL&ZM7&Hv$hh zSnwa~OADiJ==qcEZe2Vo>?Y-i^192X8{{{07d+pgbH{a6gK=wHU3qL$H+@@A7xdPL zoj(l+b9>aZCsg*98B?sC0i$w?Haj&UT8Y7toP2eWD>%(|evM?^4XM=gne%FEj^vyB zHZ9V^3q$_uh>&Z=S`{?oGB88K&^D2bPL@zps&BKn*W4JHU#1LN9qLBYT+xjpz8n0B zZ&?E(Vb^0+t-MMq92^DsYpSL|-DB(9&KghVUyOBMj~O4!@V`W!|4kp|uZ4$IDiFX>EnY&m!g`K?O&G!- zV5E;f=u1}ahOin0e9%^a^xQsi0b(8<2|`L~H*t!BuLBT?&67plduR||s|DutRcHzR zV>{}gvjK<^uu6v(fT)G&NwY+>_JOK=T;8Q`ft?V%3?3mF`&H}^2bvAoT;(6n9e8G= z(LezEg{|0t&kk}aL88S5UZ8F(2blMWZZQlA5}XzahZsF+XxcC9k$l)8OfISo@>IRtcKZvz&BL2_YD!}!dkCA^L#q0o} zVFFk8hq(F$>cBOY{zE;1AW0Mw zt?&JwAh0d*=pRHUyB^xz1@(G5rDU9=JG^3fq{gZs^3q}lQqt&Z(XU(zJ3!LeRk6Wy z$F`^HrbwGL$7s3}9ODf`A74c5`EBZ#SvR+2IFbKtmVV9wXx1N0MBwCgRX>$<7{SJjIw!VSGduryBvekw!K%)#uTgAXB7 z55HN9Jsx-Z#odFJCD>nt;z?qHj#5-w6Bm^5xdWZMx3yc-B0ey-@pz(v<{Zu)DsOYZ zwm*H`gkQs+kB?O$_7D}E4Uz!j(`yqY6hwSgs=E*9JK<=a5}H=j(Dsi#g3scE0EtTc ztUf=)I+#lGSZN%#xojVSv5p7xc~C_I4~gykYaQ3mfgay`1Zs5aYz@5hbTHa%`Rq%>=+MPIf5VC0T6;jz*%2WFahX6@INNCf0l#h;&OmDiL4>0bK zGfmkp74zk5sB{<1RoHf$BKL%lYyBHWyDJ@3(#0D`q@6KvMCtH&AhXtngK;~KQqCriEn#4s*tc>72R{s`J49S z-HiEsuy?y&d71I;`78kg--J(RC=R(vVLmjaZ=4Ff^W3r@58K!JvH29}Qc%K$_t_8Ux9hXlh2JLZBeTdzB^V0P^>+h4Y-MI35LGz=VOKCHS^}_sxNSUrXvf}ksf)tEs+BKV z-UUSdUL-$$>+5?s*257%`UNFC2mAbda4r-ub7$Q?jmZ8RPmv=&$c`YSg1z!WIyVC- z)r+WA2jix+hZsNrx-3e!-+SI2#aU)WjGErv^@#ksMw(xOnzMZK}Y$t2Yw%r zV(A=Gu}R(_g?r-8VGTnQk$zFtNg}{Xca4+(WP=(y_8I}LSiEzVPc zzvv?&=_i=3IP~Rw==KnfB9t_^Dyf^i5;D);9@gjN6_53VXv50W@0q#riWTnj;0RyG z*PBBEJ_a%;L-XEj+q0c0h2W>%k-kHmIulfG4Q$lLcDz;Ho=G2-jn!m~kQ_&406`pN(iG35ve=vcAJiT0Ft(Gd#p2vYEZTrzK!RUHZUXCP^*;5MqHcp zP)^J) zwpnoz>Feyc1EUL<<`AEl18Q(#Fv55mS&mg7dc%)Z3%*jkiJsUHl_9bE*gxCuHANaL zYFphWNcZyEN(5JddfI_j?d=H%>pWIK82Cc`wn>ya_gbZM9_eY~Pl^y5XN=b~YKU)a z95+5DDN_(x*j<2pxOJ!>lHua`XM_L{0ncit@hYxRsb1)gBw6wm zoFY!>No*PO&f+1pY8hfHd4O~1l;`Djb&rr+q6hwoo-4H>IX)O=3P+kf3MrnDSiRZ6 z8HohRTyi_>`g{jp4{5km4dJ3`I$(TGDfGsD!f`5BUlxFF<(xaa4RtataozbvL2wAf zH&kVE-1BIu4ozF#R{F{~aa*y==LBb|@pw;lL!0{c@FH5(tEpY=4#eF#!rCVtV^4Yr z(4Wm7arH#@8u4s^eEuRGUYLrq@WXW13{#JygK@ruI#W`6uu}sL{ze6!VoC8D5ZcOs zr+e^<-?t}WM~jxJ5srwom!qUR5{!Xj30}De#NfT0tXkC=>Pt^GaMB8dJ~Dl1AW(Nl zi4!V2mgTqiL`)iws2JV>V2V=~3?3ssVA8MHGe}lr2A`(#X0y@l;YRAwELfBpAgzgo zQB#=rVVpcP?Eoc(J@S<>?E3g3tVo8(aWNXCBoPtt>Jw<9XqzG8yrWCQSimo{k^)ny;`|MH?bZO&x`-_FmO!7u;vx9z|VTEsjTd>+cg10K|n z|MioJ<}GdM_S2SN!T-Ib<1J_&1U!4b1*m(FbAV9>_}Bok@qi@^aGOQmF`OI`Ql0QO z)(m_GcS|U@MTFc>cD^^A^^%JT2>S#gnt(myzW`+*j2ll{eQ$vpOw}TgiD9!8= zw+9#=^W)t0b{j zM-|_q4!a?yGqqkHboX_UYcSe8eId(df4aTAs$1vJ%S8r~#0B7uC;8;GKBp=0RqWUF z5vHm6>x&mx2R@J@z~=}6BA?7$ctgyq4hCrmHc-^@wB#TGId``MU_98RSVo(+&(q2n zwT9~=n{JTgD#E89yj8!!#IQ?~uzJg_Paug9c8QM#stv$6@PUp{DVATt?l2EJWx&vd zI~O|KLB4&tDtG|6J-MZDyAP`)o0uHFfO^k4cV~A1|2Cn;^o8te0;m^ZWra=HA&93kAE=Kdu~%3MSOnpPt&+XNLUpsmX7zQN8@b_t)tB{tK3;#KJFvmjqrzfF0}0 zOY;qW+{2Y!mP;L$rx=42b$M~$t_-NhZ%+l5dU!y1O~C#2alf~p|Kd$qUbBC^D_<}D z*H^wg@bZh_Ui^xc-M3!^@20u@<~J_$+i!-a_Kn{RK9 z25!_(BD3!e7Tzil=jlW0q{6G9@=KzX6rVu=BcMQG_m$CeSaEkP#d32xPM+DyFK`}$ zt1q*N*F}grf=`Z->klOUdOeaE;V%`c$XXw7=37pRzIBH$rQ2_-``zYkjErCNL6G+4$))}(ELKIgRCea8 zp1Sf3sG3x(s8Xqq4_mcD@kzJ_C6H(!CBxYX8xIY$2iMRC87cQG+Nu*!QS;9$4>5w~Qrk+YF#tw2fGa&o+6@>rKqdUu3r0#IJH z4)yK6&0DiPzI#A#5qkrB9Ij_vG zclu?#(69Gqe1C*}EsGt@!-nH{%4U%{9orjCbOX8O&6~4wEvLAtc@M{MYtvKJMzBPT z29E;kR<+C1+^Vei*-3r6{tkq*+mW>og=-b-71|(E)^YpuBxySx<9u$m%^*L)Hck|u zXNXk`=SBkb^Psk+lkvD#l0>wzd$k5e%gUVBNxs#uBC8#l@+cy~U-7BcBH75fGNB)-Ji};3cu|mI2P&== zM3Aqfdb)#r9n8*0?{$D9JawFRhpzXh&X1tby`rId zkm<@p&clRyqkP~zKU?)uUUJ}MhqOVK-Bm^fJ;dL%7~U-G7Jh({sR;9?w)PVb0Zk3; zY2Jbg6X89&0fw$HdHh2{ke664?$t`59U!f{#ZD7;$w3*5+-9phKI7B+3VBGNV2{VA z%VGT?F)>H$kF2!GcIsi=!JB#!at3nTQ2hZ}1LtH0xH4t%*L;dKm|j`e4tbc#+6gNs z&;)CvCj3nc#Hz*6jf3H9e7j@ixMM*V-6VUqex%?=E;BJ`W{9D@JuS>hm0j+-=38{cVB9s5Pl26TB zr+fGGU>Nv_2?nHJgWh3xX&EFc+U=TqDzB3r&3_p(!dk%o>{wgkfj(goe>vR#8|`i( zT?#c2N|p}+^p1Yl?#_NH(ylju$Ie2H-XoqU?LAyNXf6!LzM~a1U_XBI2E$qQjXU^e zs18@GejsJP4j#d_^%lPKb@2FYkoX4R2ej<8bfVuu{J>ZMLKvK9iG$Tl8wcpOLe>%b+8V zoFeo|=YzOA1DslvirhCLpxw;m+Vifi!`&z<^)eGIHRS6ydS(=Ur zC7uxhsY$YJcu<$f5KE#-5Tbu zqhILpsbEBhOsIP-=iFH5-3H6iQ!}%#mH)EC?5gE4RZ`aL#I9RwM_uG^W%5nM@QbPk zc&Ohf7Jir+TJ1r4T&sl9{O2A{$F{Jus)`roexw#1;IkMzd)i8&79bbs(A#GhAi4U9<N5>`gBS>R&y*1kKPI;>0F$}cGJC1>j^V&yD;BL59 ziF*4Mv&0>^$f$g{*5`FstmZTQkQq{_i()Huu6sB+FZBStZ<=1q&3*E3hdK4JXMdbc zzV%LsgU1<4611PGOVsorZ02<)Je%kNDyg%h4ng7+>5o5 zyT6E+?DRamp>!4`_|TN+s9&n)(kJ9u@-H>>uRGghDVR0-y--zrR)mw*8G$ubaB%!1suILOA3Io3Xb8?kJsimr0YLqOoB`~p6%euCC^2vB=>VcI zL8@n4~a4@a(zdZ8==n#`i1>9-)n2@s`xsxRIE3X70pY1n)L-TaA< zfI!ZYcktAg+Z~vfcLjneVRzMC2u~ak=2ZV_Jjfbik3wa-1rU}2fc4diK5rp&l?>9c z=-pj6$2FSVQ4~QPiZoPqJ!Yqu2y4-0CW2fK=rU{|Wvp)rEr`sJHOD0O&0E7iF>qJi zJ>3KAyfIi(zIwP}5}$!HVj-)B(p#|FOEJZGZ5YL?@b0!XGn}g~y2FUFXM6toAf)_a z0;sPA(Z&waXk}Wa17}7xhD@na1?EEyDmVBhiCKId3+u8=`E`7y7v#a zs>y1t809I)O6Q3ML#KM*;ZzkmurRT!c`_awmuZo{v3BBhveuR3t@o`(<2DM=_K9#W{5IF> zEr)fParM2Z!PZJgU)>Bdyc^%-aOm=x=b*;Qk4?nS$= zPb-jDCzT2WyPJ5+)MUFyA8dDnqx+k_?AIbTk^dj|Q`Gsl!Y6s~MdgG~ONF@x2OzUG zi&bIYPVFdewkwhSMp&hzaFYW`I+(M#9q;UIsrF$nP{dV~KFM>KZxhm32?4<>*5fGP%(Cs+&h;3h9-=m75@Dq!OB!s36 zgtg0F3A3&Wmb70z;LCs>%llJ&IGPkf;scn>ls67JHy_H)^IOV8vRfY19AMssYbyxi zyh=-A#sfYI6=YX{_4)lB{CES^<&6PFu0%w>m|Gw@hgAr4Zohu};f;V6k@Q%Cd_brJ zHSK*02e0PNa`oPH4ao2KgWm6Fx!+^bWCv9P^X@Aa1%a3a9&7;Mx#wtWLzgNt(qO8= zd6Nrx`J`Xi7M!7>btxq)<4y8)we~lI6DT@nJS}bSRZrc;CaJ5-$+}W}ejF|u$h+1n ziBBCQN*PONjZEm|E^POc^MZ}n)q~-Ff8;P5c7Q^3xTxW4y~iG}$dmPqHZ-u1C4LyR zoN|-bjYRs?t??;DejaPH0oPe}Q0<+S+Am(}n|{zN^|rdZK2}p)gl7_UyFc#% z^xdCz5?sjH{cyX2&SL z>H6_dOx7J++lH4SH5$EcS#??Cr@98q7fD{I=kPiUbu5RTT)PVN+HlQNK`oEQZK`!g zbt@liHXl%D7kA2$p{KPUW@rS#78q`2zAi?OJs_}Lk zP&K~YHs;}vh7g3kB)0CFBe0&|+V|qz|1YlWZ9`zf$l?o4$&pwv*nLYNTG`O+Uql{} z53ds({2+|3U;Ykj*9BTrkWlRv=c{o8g-AWX84XT~9&kpt11!Pc4u=b4AD-HOa_j;& z0m#gT`!hPASK*{VbRo)*ttYOH;baxHQ~<=6)M)WIC#S37rjB52RkaieTJFyF3dUac zt+nYsQ4qpJFNd-gjX0OL*F5pgIOS$M@ERd9nmX>Y6xItAk5U>B(D;xXB=&f(@AT!w zKMjVt;ngiVj=}p@zk8+EIwk!t${w14r{)yZ(nY>VB7a%rXkQJfys8-svQF zIQ|IfrtS!KuO$Q~<=|f)TXq8v27Tp;Zq5}e<+%=ErN`Qq(fgT<1$Jv;laPUl&M_}2ZF5Pzmf?bpC>=IRo!EEZK`YD{0AAZ(X6^b_a2BJXq zy@nZjvE8&2?SbB8dKgWM-5P`0Qjok5wgm)vA0ZjXK-QCX4x2%Ix-Njb@y*oLD?`Cx zbiKiJXI+(t18dvBR$cqa^o$DY?8+34ww>d%D^j{lb ze{?9lts8$^BcwN*67xARP$0y>s&P%EHot}xBd&{%3OxXkKFq1#vkzLb(0A zWeL^?sD1A~rq7I#rRDUk%#EG>PGVgD*V0mtwL7QKN>>urjRjvc=0D&V1D^ zbSv5r)P$m~rmS@Sz#wx5f?EQFsfj8?c%i@4A#phU zuz_gt{yGgXo)BrIf+Tx>;@wp<2*VMpyc@ZK4B&NjR9~Y9jA6Fd)$MiK9etv~KRc0? z4j#ZCBvF!fLLj_WX;#H`4U?aAF2-8Ffaotae>Vn~-Za1n3|FV}eW0F{3Un5bQf#_O0B=Q?j& z1xNOwLAX8BG!cF%sMQNo^}% zHHb;fO<62rvYRdk?cS^*0u2f3EF+*1?$)EQ1^@uLN-2#-+H6a+Zz$U=v~%BdpdQ#6R=bP&-PEePc# zU#`^ixNQ?YVr2ek2c1vHxGMCIenXKM0}WgtamjTc-w?7jHm|crC3{8OQ816<_l~JW z5A5Q_Rtu2)Ty)RiQLoRj?m{-YhF+DvhJR$hm=)TRd~hbw8rD!4f%P$Uwhi6p=)fb_f%XTo-%qd?VSnnx>w`? z`wV~nX8@AHFY_V?GLhS`EU4MS-6z8zAsLy{ZtF=>I-QBV4N6Xl zpaw;qe>(;Kx+VOk`+}{5bhJN|2fuVQ|80{Xgv*rd@;N0lcQ3T>Asu`V0d5hN$(z%Z z`@d`!bJEwIk*v$K;L!wLc)RGukm3=hRuT*n(oKh z=Y92jmuoHY5YRn^Ng3cL-g!LAI{?6ewSPVlKpy)Cion8^*ABF7%i6!72poZU=Qu9S zP6wn|aEz@(L4;iaOm{%_4?SS0{(E9MiNV$GTnU<@*X0)jph5R0sSbZ^jUIru8#RZy_ht4S|Ok+0sMZI0*q)j0= zk;=WpYj$^cCum5JWM1*N!50Gic?YiHcl5CAts`jb;_~)Gcoc&+Vx6A)08Us%k@qiV z4VLE{Aj4)hd6(vXv=4{p{k0FSnum+Eayn_}beKX=$1DE%_x(7TK4BP6z=q?D>_jwu z@WZCMjV?A#IeAIq5k)yI+JFtnQhZEDojjA{vp-)po6_(m^0;!FV7&S>L@GWntRBE% z3*Cb=eJY!K0PnL$JtzbGcDoA%oP{(u90*7iw=bq%QV-SbqJR~n$B`m9WkSuh@JPm~ z5Y0!t>30HpznVZfK{j4l-*em$NIAWSbdvdgapbb5mAu265#;qb6f?phZYY0*shy|X zHuwIvt0*5@zn~ls(WzJV8~t>ZJ+QfNp@+QU$Qr+^Hy7)6!2riN38J5}70P5=4IAWa zIMFg{s+2{EEd8*(<5Tkb+Pd76Zr!a9jgrjSsYXhU31)tGR!z|e(;hz3Mo@RXGM~gh z_T!f5haO}D|9bNnXWvdv|GwbrZ-r3?(G1V|pM{ZwS<0t^-ErL)3_dr5` z7WbPuVv!FRhzqA9U@rh779aq!1rq_W)A^6V&Py*pqyjKzvLNmY#!mhc0rnN{;4Z4t z20C;D63#ycU4MP>AOF$sbXlhn;AW7!bHNd#`T#u4-*1H5NDyZI^=WA1H98@z_6ikZvoNSse@n$W>rIrTL?C zf`_rvd8k*Li>}`C5XO|#!Fc8rT^`5yNL?2+Y5S!Pv{dH+R=n~y#8VC zGP6w+CGb;sVvSV?)CJG>GuTVup>Q`;*eYnkIWve;WkXrHV~BjihPC6E;yLwaPuULD z(O<#l0wDXUO=JAN#F*YXozIoGnyME_SG!_=djNwv1VclQOMHN?V?QrhEJ0HJ*2`lW z=&abEn})IalLL}ka5xWwZLR9ffF(4$JM7r@cp`Ma@F7LFxG=NkUGI;5m#~mbhDzkI zvwDO)h9VUhr3^}mC-i5$(tEgOvufL?3jD_{K*8oF8L*=tZ3HQ5JGxM6=dP`or@i-!|%F>Hs=tLUE0>W0(PQD?TQ!5rFiih^$f=Qo1Pi*FyyrhCN+$v*j-D2J#h%=Y|@E1h~Jy!&vF)q2nq&HxF> zXM8s=z8UVJdGmf!`iSp#;WPecKso|l#lu^=kw|IlS9>v~p_WK+FX%Ts5<#9AtwD(N zZh%%s6ZUYxgZ#~Xk+(a;kkwyW>B~e7{tgL1FyPAA1z^(o0>XHVwIzfYAODguOg~`aK8x&8Pzk__s>?{Q-bt z09(!pvcWIl+{D9=2g=WzuX8>gCX~F+pM8)^ElD}}qJly|1_je=n72bYRzH5QD7jRd z)03S!=qxZ>O)&z~&*$D&5kb2ESuKlgG=-2cn0yy7M8P2}*3F^gU%d-Z+1A;4&GNt> zThTXw4@^`bEOmQTWa|dzh_?`%WYJ^6z<<#)M1BZH3UCc9Q-U8x4>o54H3(D_m;4lj zMFf%zP*H&80KBF@y+%L3M2Pm&iwt7){YeSIMi)~i#KONHuE8iJ*d~0|S9q5q%aLNC;;$N+$z~fmOVbu)-aI-}t*>NXj^mZSUV42Pa z9m^eQ^uhD#s_IiZtZLS{>H_+r$F^~K&f5oDGA&F4bemvgIH9CccHEQ-ZQx%a1?MPZ z?$dT6JTUcQ_pEx%&1Rv`-PcMdCFMfDdTjp+IyQQBty8W_+r9-<%Ax{RqP=#^E_dzG zok{XT!J&>mYp=;FP~HLFa>-C7EjvaM91C<;b7F8ia%v5q z(-DsoXG5~?aPwe`FKy(NS4a~ZASpSnO}jo*aAt+1Km7`)VcBXPFnAfsXHD-^PdehY z05L+z-f$l`449mDO3>-UE5jmEj}&-4uk}}uO@H9Kq9S2z?L35sLmfVxr~gN9-von$4S*qI@Yc#uti6R z0jl=ptElhC(!2D-Ia@)OPt7)b!nxhmylg>hfZy*NDz)2ZouA8Itq2`-lp?ZkpxNQk zFL?3m9XX#)i5^js6VF|H*E_e|HU`IgBn4=qgFs(R;*v%2cw6Vv zCE)9+*UIU(b7C<{%d@JRcr;k!!vx0@YRFg4hM>0YhXvyL?JZSZ1U^P1*D|_ z5hbfXlfeJBRsA<(B>%Qyl}^h^9v?pSuAtib)rQsiZ#JwCoqsDA>i_E2&iCI06&9$=O3?bvF00JfBVOF`oFq5Sb8q`a&>>( zKYrgn@?`0RF}FVFMo01k3Tqg9@X~g3KyE~^--opdU2fkzrKV#``JJ=n!)CR8R16-D zM!QbMqrCyEWWY(3s6yoFr6O3-xN#gk!0hOm9UvW0-XRo=Y0d5C@*Tv#)?v9hdsAO2 zH5qF&#K=g3{Thf6_OZ%?H7%QuaTWmPx0`^uX*Ol6S`$~tIFm1sv4ODZysed{n0IRj zf)v$Va2<%*=EH2eF~Q%pGKZ_7Zne{q#!UROE2)<-Nby7l8~B=L?Hw;cN9z$xIn;^-v2gTyF}=6T$} zf%dkh+xUST(D5odmQrOAs{){!9R^i~PQBXnzEr#>wL7#F6cWHth*xy~lnd+RGl1bD z^3Axu9}W-^NQI~FIBaC(2_-c+zl>&F6)Uw}Q$7`~6|Cq1t&|4)1d<9gImtL{+xq*1 zU;@iA3dmD08sk%i*xdb-Qf02uae>kh&^GL~XB|W8wcH$PXwiFs4fbZpuiS6wln;jJ zcrf!6cKT4S6$cyn^LEX&u8x(iTLpknexf3c>Ja0GNIQi|{Npi&u1sDH_hD|zmxe!B zcCARv=&W(Pu7GfS;n6!;)>}E+;soYC)N%PVpWM}~0L z9N*T&cqu>x>*m@CUhaGYkZcJ`>T9sJAi2!n=pXk31XaVW3XLAnmC z^DEmO>{Qsq_lq-!sEUveoZIulIPKe_ zjjX$PSI5kWT}#OVHxuutZAi>kd_nfqB|&v%vX86yn()Vfu<%)Z!5Sfzq&cbvm07n} zqEx*S$XOg|~W08-fxoO&kvVy5D= ziD8(MQB`1D>NYWYfmB4!1Dfjn!Y@CI?oZt3}QWnAk#CSN#d*JcEZ`C6$)UGr!hTP@x@EW$)3$+#n=l}2S%ynMJ zlPf-OW~L4&nOycr6h%^mBa!01?-Vocq&DuWLqC~gzlfj0aOvLO?(IfT+lCV-p8x@Z zJ_-`+UsdP)PJ+C}(jf_P@zK(F_=-3;ZM0cls>^SGnhNI=t`X&6cW*b6+wuc=O3?6l zF?T1;+_^TIhRcN`mEAsgrbzrOZ^3qjT>&wvkTv1FR-z%IGT)R~*O>)&8M2HEee_a4 z3m!L9VH#h+!f{Wi(ffwW5f02U*<%fo1pupMeBPL}DGWM&WTA|Ee= z#V8fVGERLBk1zH$a^XX)>oWDyR1vIeMZq0?EG3C-Pzbw zrN2l`STOaui23&Lgy%j9_O!bma2;I2Fv{5=lzxE*GW)s&hrot|gk}LOK_wZ=Rc-`?oB9=K)kB=MsN?vl^zf5{mrv zZk{>-K@Z0Hw@uwdO#K!H%%qT$b_>9l&1(IZM_|}}Gl2&b-S>pYA13hMq3E<+2&SB- zDGS>jK@Vp5b6y;eNxh>-<7 z@rrnFAD#Ki)R+xXZri+^$%&IkOr68r@RXB&%tzymP$ALXjJI?>c$;Vp3vnMo$`vUud4)G!>Eu91} z)8gnF@|W^afgCFPN#7!kURU*qCc>gZqK5O{AIiq)OHJ1&cH9RSP6y&}!ilYmFs;)< zqLJceAT?U<#C2l318~eCr>>+(6J(xg6}El&^Lr^oWV5&$O`e_GW2{y0lOZ>59;RkQXo84j?_dxuFmOg6S!^b z+~sn$%O{L`S+6LhfD5O98oPungGaMR{S|d$bvyAw7sO=qx|~;ZK^23+ql+h7Os?ca zjooO-I&DkgvF}yvU0SxWcdE^h$_EAQ&T$G5w}rKzJX}nI4m3|YojK!lb43B-s)86F zRQ-b9!A>%1^;jiytx@(TMWNA%H=z5{NeC9Sx}9?h3xyt0cO)9e)~ND#NQb+`kp^b0T)N5Z{WKI<@xF;3jI!0H0G~DA zF4&+y$N8z@?CHRYFy#|^A&n^q#+w#(ahY@XT04(SF`O1q;<}KLs)x~R;1O;5Q~_J> zdYAWAl0JdbhVm0>vmJg(uBWq&fE9isOPuHmNv_JIODCfD#K%Kn&-Ok1!|Y zBqRgoh_A=!I1pvbK6!31pI}`r=Y9KZZ^|u2uJ4DsPr6nT>2(Gg;~8LP<|@j|ZaiK^ zn^8o%GjFvxgPJX(b|Kr3GU^fVi3){O6h~VP2pyQ*`_;c9;O8YKs-x}`@mvpXFPv@B zC2;IIyrQ)CVfk{rk3-O_EqQ6%4Lbzz9ivR)^tfYUP0Wo%wOdWB{p$)Y|5Y)?-RS!7 zroqhJ-sG}ALZ9X_(!-Na?(QasORMT(0Io+;hBIBgVBtB5*xZ)XP z_6yvJ?VHbs)yB4F(8ED~wwKKE4zFYdTIMyAUYCSGL#t_x7MIn1v!_bT;3CJLSMgws zoqQk3M{OgFv!qEP@3OpO%43l-do+oXnLkJk zIg=TfY@#xn$pvXyZyEx}T;FRizq=m#woYUJPwMm!+i|Fnzfq?@JlQW9T)(K(U!VKG zuG8Ob%KvbkmV<}^uZFAZ-uX$S=^Z3I?>0VLG{he;(cp<77PADTm(I6PStDxdyezFC zz+U1*FxM=l9qG-d3&0c!Mv0l>Wn+htGnmZ_gP6zZ_&s2heFF&artFjQh+k5VW zE=q9O;h?#zMq`#Q(;;mtNWM$G{$4wKCD}<^21zD*?X2B&Q+jIH-q&lv3E*q`9AJTK zl$8jXztXAXAS|GFAl)S8>UP$aC3w5RzLIX>&Y5Hy8>aGT1c$5CqEEEH8vGXD-xbIe zA%f!a=Cspk*5?oj>zhqT=*pGa!|k(1TQ;h=Um@FO)IexF49aBJ#OM;`+Tmu>deeczAcF%!af?h@KY69H(?Mg)N^~l79 z|vKT_}kz5r=}jMQlYDrHX@{pgA(Nu#`&dYm=>`E@&QR*9(u*j)%j%bw5kjr@00Y z5OM>~Gol94wtWALcjT!b=gEQ4F)4=Z6n=tG z+CRc~`9+-u_S@ZbT=t;?%=vYlPIpg5w_Sg_+vX^9Q##c?*IJ^sZp}kgR>LUdH&xMi zJjBP!?cv4`m>Sz$DKPHB0;&b6LEjfS6X5%JgXt^m@!ELDNvt|A=!qdg%y6p<{Ne4| zib~{0wE|n@yME7zw5;xUWE3wMEWE77*;cO8gm=Dy09s&IiWU-l~qmn+BQOlj`W z3VKc*w=uzI-UE<>Wd9lX&FEwgb>?Ryxb@`)5-ZP0s9Q3MbIv6yii#(a;9x^xXJ}1d zrUQmWHn;Bvi8(9LBVmX+K_jXD(2CJ%UGD3SwC}72e%XY8Bqv0+WAr%O+4I{2qdEbQ zDoxHF^z(7bPeRS8<>>Qheb)D!+TZlTzgcZ%JT!81fWymo=(&EpE`A01aN>pl%aMJ= zqNUO7ju>cQRGhC5{G#qrmh$!%9gl)iD`dC&fKyJk$L<=nkp#C9?-(SksX_OQVmhk^ z@d#1Zp`+ww+_CoV{&)nUBM9N7zCss*j1=^0Ope!3*Mqke(NnpccT~+2Pi4A}B=yWR zna^@c(wFvnHLe+w>6>^4R}DW9jGW(Tf9PP^aeITn0~*Ie;zniN9-R9@96%LVkR!Ed z=+Rl-n0&SE5D|_r(%rI6i&h~_vlqrN`Q1A0{F9SCGvGk{g@4v@^!$p5{nA|jnq~Gy z_5Q=3zcmfN&Yx*``|~vX*M{d$XAM56?|N7ZqGaUl()`%NBI45=enETy1*QcKS9*=W z7zMkokA)W2avt=pU-?}E=!(9+xL3JvU+aF&p7|`tK=2+0;xFJ0sw!|G)B@K~=z-&E z1@;+FRUnf8Vg~xTDF*gnnP?we8MuQ#?w|``Bi!THaXPSdKF@s_r+@f5fBW)&ygJ}g zcmoU%{#Tdx1N!ay;hO!AFYkLE5A^)7L;g*sEJLNCG2bd_l4P>T0Bn*2%|X)q)3D#P zGpj%>dL?>K0;Dr$>X@sHP=jG4hGh?F<5ki3~iR9_mQ-wa>- zhR0*0AWS*xN1lmFx#c;dLoO@tPJ2>ce{0h9SpkD@%DZDg*YK(1TVH*J7$5TSCgJ(+ z67#cLFefK7V-fmEB=4_d@B-F;L?vj6MThqr=JQDdfp!8`SmAZgg(z=xHvXCaLtcb#BYZ9(ipUTG{=Ys z5&Y?i>a;@V)e1qaXO?>26w7LA(h#asOhAN)Z&w+8YMjQnHk|4Dzt7`A|BC(f@Q+E* i(Es87gYmELfB*aS-~RbO|NJk1{<}Z@=}$bg9RCFp{RA!m diff --git a/tests/kitchen/tests/wordpress/states/wp-config.php.j2 b/tests/kitchen/tests/wordpress/states/wp-config.php.j2 deleted file mode 100644 index 928dbddc335..00000000000 --- a/tests/kitchen/tests/wordpress/states/wp-config.php.j2 +++ /dev/null @@ -1,82 +0,0 @@ - Date: Tue, 27 Feb 2024 10:24:22 +0000 Subject: [PATCH 38/54] Update pre-commit hook versions --- .pre-commit-config.yaml | 25 +-- doc/ref/executors/index.rst | 3 +- doc/ref/modules/index.rst | 1 + doc/topics/development/tests/index.rst | 3 +- doc/topics/proxyminion/index.rst | 2 - doc/topics/releases/2016.11.0.rst | 15 +- noxfile.py | 3 +- salt/__init__.py | 7 - salt/_compat.py | 1 + salt/_logging/__init__.py | 1 + salt/auth/django.py | 1 - salt/auth/file.py | 1 - salt/auth/keystone.py | 1 - salt/auth/ldap.py | 1 + salt/auth/mysql.py | 1 - salt/auth/rest.py | 1 - salt/auth/yubico.py | 1 - salt/beacons/adb.py | 1 + salt/beacons/aix_account.py | 1 + salt/beacons/bonjour_announce.py | 1 + salt/beacons/cert_info.py | 1 + salt/beacons/diskusage.py | 1 + salt/beacons/glxinfo.py | 1 + salt/beacons/haproxy.py | 1 + salt/beacons/journald.py | 1 + salt/beacons/load.py | 1 + salt/beacons/log_beacon.py | 1 + salt/beacons/memusage.py | 1 + salt/beacons/network_info.py | 1 + salt/beacons/pkg.py | 1 + salt/beacons/proxy_example.py | 1 + salt/beacons/ps.py | 1 + salt/beacons/salt_monitor.py | 1 + salt/beacons/salt_proxy.py | 1 + salt/beacons/sensehat.py | 1 + salt/beacons/service.py | 1 + salt/beacons/sh.py | 1 + salt/beacons/smartos_imgadm.py | 1 + salt/beacons/smartos_vmadm.py | 1 + salt/beacons/status.py | 7 +- salt/beacons/swapusage.py | 1 + salt/beacons/telegram_bot_msg.py | 1 + salt/beacons/twilio_txt_msg.py | 1 + salt/cache/__init__.py | 1 - salt/cache/redis_cache.py | 1 - salt/channel/client.py | 1 - salt/cli/api.py | 1 - salt/cli/caller.py | 2 +- salt/cli/daemons.py | 1 - salt/cli/spm.py | 1 - salt/client/mixins.py | 8 +- salt/client/ssh/__init__.py | 12 +- salt/client/ssh/ssh_py_shim.py | 4 +- salt/client/ssh/wrapper/__init__.py | 1 - salt/client/ssh/wrapper/grains.py | 1 - salt/client/ssh/wrapper/mine.py | 1 - salt/cloud/__init__.py | 1 + salt/cloud/cli.py | 1 + salt/cloud/clouds/aliyun.py | 2 +- salt/cloud/clouds/cloudstack.py | 1 + salt/cloud/clouds/ec2.py | 1 + salt/cloud/clouds/gce.py | 2 +- salt/cloud/clouds/hetzner.py | 1 + salt/cloud/clouds/joyent.py | 1 - salt/cloud/clouds/libvirt.py | 2 +- salt/cloud/clouds/msazure.py | 1 + salt/cloud/clouds/opennebula.py | 2 +- salt/cloud/clouds/saltify.py | 2 +- salt/cloud/clouds/vmware.py | 118 ++++++++----- salt/config/__init__.py | 1 + salt/config/schemas/common.py | 1 - salt/config/schemas/esxcluster.py | 1 - salt/config/schemas/esxdatacenter.py | 1 - salt/config/schemas/esxi.py | 1 - salt/config/schemas/esxvm.py | 1 - salt/config/schemas/minion.py | 1 - salt/config/schemas/ssh.py | 1 - salt/daemons/masterapi.py | 4 +- salt/engines/__init__.py | 1 + salt/engines/docker_events.py | 1 + salt/engines/slack.py | 7 +- salt/engines/slack_bolt_engine.py | 7 +- salt/features.py | 1 + salt/fileclient.py | 1 + salt/fileserver/__init__.py | 1 - salt/fileserver/azurefs.py | 1 - salt/fileserver/gitfs.py | 1 - salt/fileserver/hgfs.py | 2 +- salt/fileserver/minionfs.py | 4 +- salt/fileserver/roots.py | 5 +- salt/fileserver/s3fs.py | 1 - salt/fileserver/svnfs.py | 3 +- salt/grains/cimc.py | 1 - salt/grains/core.py | 28 ++-- salt/grains/esxi.py | 1 - salt/grains/junos.py | 1 - salt/grains/minion_process.py | 1 - salt/grains/napalm.py | 1 - salt/grains/panos.py | 1 - salt/grains/pending_reboot.py | 1 + salt/loader/context.py | 1 + salt/loader/dunder.py | 1 + salt/loader/lazy.py | 2 +- salt/log_handlers/logstash_mod.py | 1 - salt/master.py | 7 +- salt/matchers/confirm_top.py | 1 + salt/metaproxy/deltaproxy.py | 16 +- salt/minion.py | 1 + salt/modules/aix_shadow.py | 2 - salt/modules/aliases.py | 6 +- salt/modules/apache.py | 1 - salt/modules/augeas_cfg.py | 6 +- salt/modules/beacons.py | 49 +++--- salt/modules/bluez_bluetooth.py | 1 + salt/modules/boto3_elasticsearch.py | 1 + salt/modules/boto3_route53.py | 26 +-- salt/modules/boto3_sns.py | 1 + salt/modules/boto_apigateway.py | 1 + salt/modules/boto_asg.py | 1 + salt/modules/boto_cfn.py | 1 + salt/modules/boto_cloudfront.py | 1 + salt/modules/boto_cloudtrail.py | 1 + salt/modules/boto_cloudwatch.py | 1 + salt/modules/boto_cloudwatch_event.py | 1 + salt/modules/boto_cognitoidentity.py | 8 +- salt/modules/boto_datapipeline.py | 1 - salt/modules/boto_dynamodb.py | 1 + salt/modules/boto_ec2.py | 12 +- salt/modules/boto_efs.py | 1 - salt/modules/boto_elasticache.py | 1 + salt/modules/boto_elasticsearch_domain.py | 1 + salt/modules/boto_elb.py | 1 + salt/modules/boto_elbv2.py | 1 + salt/modules/boto_iam.py | 1 + salt/modules/boto_iot.py | 1 + salt/modules/boto_kinesis.py | 1 + salt/modules/boto_kms.py | 1 + salt/modules/boto_lambda.py | 1 + salt/modules/boto_rds.py | 1 + salt/modules/boto_route53.py | 1 + salt/modules/boto_s3.py | 1 + salt/modules/boto_s3_bucket.py | 1 + salt/modules/boto_secgroup.py | 1 + salt/modules/boto_sns.py | 1 + salt/modules/boto_sqs.py | 1 + salt/modules/boto_ssm.py | 1 + salt/modules/boto_vpc.py | 8 +- salt/modules/bsd_shadow.py | 1 - salt/modules/btrfs.py | 6 +- salt/modules/chef.py | 1 - salt/modules/cimc.py | 1 - salt/modules/cloud.py | 1 - salt/modules/cmdmod.py | 9 +- salt/modules/consul.py | 12 +- salt/modules/container_resource.py | 1 + salt/modules/deb_postgres.py | 1 + salt/modules/debian_ip.py | 13 +- salt/modules/debuild_pkgbuild.py | 1 - salt/modules/defaults.py | 1 - salt/modules/djangomod.py | 1 - salt/modules/dnsmasq.py | 1 - salt/modules/dockercompose.py | 1 - salt/modules/dockermod.py | 6 +- salt/modules/drac.py | 1 - salt/modules/dracr.py | 1 - salt/modules/elasticsearch.py | 1 - salt/modules/eselect.py | 1 - salt/modules/esxi.py | 1 - salt/modules/esxvm.py | 1 - salt/modules/event.py | 1 - salt/modules/extfs.py | 1 - salt/modules/file.py | 8 +- salt/modules/firewalld.py | 1 - salt/modules/freebsd_sysctl.py | 1 - salt/modules/freebsd_update.py | 1 - salt/modules/freebsdjail.py | 1 - salt/modules/gentoo_service.py | 1 - salt/modules/github.py | 1 - salt/modules/glanceng.py | 1 - salt/modules/gnomedesktop.py | 1 - salt/modules/gpg.py | 6 +- salt/modules/grains.py | 2 +- salt/modules/haproxyconn.py | 2 +- salt/modules/hashutil.py | 1 - salt/modules/helm.py | 3 +- salt/modules/hg.py | 1 - salt/modules/hosts.py | 1 - salt/modules/http.py | 1 - salt/modules/icinga2.py | 1 - salt/modules/ifttt.py | 1 - salt/modules/influxdb08mod.py | 1 - salt/modules/influxdbmod.py | 5 +- salt/modules/ipmi.py | 1 - salt/modules/ipset.py | 1 - salt/modules/jboss7.py | 1 - salt/modules/jboss7_cli.py | 1 - salt/modules/jenkinsmod.py | 1 - salt/modules/junos.py | 132 +++++++-------- salt/modules/kerberos.py | 1 - salt/modules/keyboard.py | 1 - salt/modules/keystone.py | 12 +- salt/modules/keystoneng.py | 1 - salt/modules/keystore.py | 1 - salt/modules/launchctl_service.py | 1 - salt/modules/ldap3.py | 1 - salt/modules/ldapmod.py | 1 - salt/modules/libcloud_compute.py | 1 + salt/modules/libcloud_dns.py | 1 + salt/modules/libcloud_loadbalancer.py | 1 + salt/modules/libcloud_storage.py | 1 + salt/modules/lxc.py | 7 +- salt/modules/lxd.py | 17 +- salt/modules/mac_brew_pkg.py | 6 +- salt/modules/mac_group.py | 1 + salt/modules/mac_shadow.py | 1 + salt/modules/mandrill.py | 1 - salt/modules/marathon.py | 1 - salt/modules/mattermost.py | 1 - salt/modules/mdadm_raid.py | 1 + salt/modules/mdata.py | 1 - salt/modules/modjk.py | 1 + salt/modules/mount.py | 1 - salt/modules/mssql.py | 3 - salt/modules/mysql.py | 1 - salt/modules/nacl.py | 1 - salt/modules/nagios.py | 1 - salt/modules/nagios_rpc.py | 1 - salt/modules/namecheap_domains.py | 6 +- salt/modules/namecheap_domains_dns.py | 1 - salt/modules/napalm_bgp.py | 3 - salt/modules/napalm_network.py | 29 +--- salt/modules/napalm_ntp.py | 7 - salt/modules/napalm_probes.py | 4 - salt/modules/napalm_route.py | 2 - salt/modules/napalm_snmp.py | 4 - salt/modules/napalm_users.py | 4 - salt/modules/netaddress.py | 1 - salt/modules/neutronng.py | 1 - salt/modules/nftables.py | 80 ++++----- salt/modules/nix.py | 1 - salt/modules/nspawn.py | 1 - salt/modules/omapi.py | 1 - salt/modules/openbsdservice.py | 1 - salt/modules/openscap.py | 1 + salt/modules/osquery.py | 6 +- salt/modules/pacmanpkg.py | 2 +- salt/modules/panos.py | 1 - salt/modules/pcs.py | 1 - salt/modules/pf.py | 1 - salt/modules/pip.py | 10 +- salt/modules/pkg_resource.py | 1 - salt/modules/pkgng.py | 6 +- salt/modules/postfix.py | 28 ++-- salt/modules/proxy.py | 1 - salt/modules/ps.py | 1 - salt/modules/puppet.py | 1 - salt/modules/pushbullet.py | 1 - salt/modules/pushover_notify.py | 1 - salt/modules/qemu_nbd.py | 1 - salt/modules/rallydev.py | 1 - salt/modules/random_org.py | 19 ++- salt/modules/rbenv.py | 1 - salt/modules/reg.py | 1 + salt/modules/restartcheck.py | 1 + salt/modules/restconf.py | 1 - salt/modules/rh_ip.py | 5 - salt/modules/rpmbuild_pkgbuild.py | 1 - salt/modules/salt_version.py | 1 - salt/modules/saltcheck.py | 13 +- salt/modules/saltutil.py | 11 +- salt/modules/schedule.py | 47 +++--- salt/modules/scp_mod.py | 2 +- salt/modules/sdb.py | 1 - salt/modules/seed.py | 1 - salt/modules/selinux.py | 1 - salt/modules/sensehat.py | 1 - salt/modules/serverdensity_device.py | 1 - salt/modules/slack_notify.py | 1 - salt/modules/slsutil.py | 1 - salt/modules/smartos_nictagadm.py | 24 ++- salt/modules/smf_service.py | 1 - salt/modules/smtp.py | 1 - salt/modules/snapper.py | 7 +- salt/modules/solaris_user.py | 1 - salt/modules/solr.py | 1 - salt/modules/splunk_search.py | 2 +- salt/modules/state.py | 2 +- salt/modules/statuspage.py | 1 - salt/modules/supervisord.py | 1 - salt/modules/syslog_ng.py | 1 - salt/modules/system_profiler.py | 1 - salt/modules/textfsm_mod.py | 46 +++--- salt/modules/timezone.py | 1 - salt/modules/tls.py | 8 +- salt/modules/travisci.py | 1 + salt/modules/tuned.py | 1 - salt/modules/uptime.py | 1 - salt/modules/vault.py | 1 + salt/modules/vboxmanage.py | 1 - salt/modules/victorops.py | 1 - salt/modules/virt.py | 105 +++++++----- salt/modules/virtualenv_mod.py | 1 - salt/modules/vmctl.py | 1 - salt/modules/vsphere.py | 51 +++--- salt/modules/webutil.py | 1 - salt/modules/win_autoruns.py | 1 - salt/modules/win_dacl.py | 21 ++- salt/modules/win_event.py | 1 + salt/modules/win_iis.py | 1 + salt/modules/win_lgpo.py | 73 ++++---- salt/modules/win_lgpo_reg.py | 1 + salt/modules/win_license.py | 1 - salt/modules/win_pkg.py | 1 - salt/modules/win_servermanager.py | 1 - salt/modules/win_service.py | 1 + salt/modules/win_shortcut.py | 1 + salt/modules/win_status.py | 1 + salt/modules/win_task.py | 6 +- salt/modules/win_timezone.py | 1 + salt/modules/win_wua.py | 1 + salt/modules/win_wusa.py | 1 - salt/modules/winrepo.py | 1 + salt/modules/x509_v2.py | 9 +- salt/modules/xmpp.py | 1 - salt/modules/yumpkg.py | 7 +- salt/modules/zcbuildout.py | 7 +- salt/modules/zypperpkg.py | 17 +- salt/netapi/__init__.py | 1 - salt/netapi/rest_cherrypy/app.py | 14 +- salt/output/__init__.py | 1 - salt/output/highstate.py | 1 - salt/output/overstatestage.py | 1 - salt/output/pony.py | 1 - salt/output/progress.py | 1 - salt/output/raw.py | 1 - salt/output/table_out.py | 8 +- salt/pillar/cmd_yamlex.py | 1 - salt/pillar/cobbler.py | 2 +- salt/pillar/consul_pillar.py | 1 - salt/pillar/ec2_pillar.py | 1 - salt/pillar/extra_minion_data_in_pillar.py | 1 + salt/pillar/gpg.py | 1 - salt/pillar/hiera.py | 1 - salt/pillar/http_json.py | 1 - salt/pillar/http_yaml.py | 1 + salt/pillar/libvirt.py | 1 + salt/pillar/makostack.py | 1 - salt/pillar/nacl.py | 1 - salt/pillar/neutron.py | 1 - salt/pillar/reclass_adapter.py | 1 - salt/pillar/s3.py | 2 - salt/pillar/saltclass.py | 1 - salt/pillar/stack.py | 1 + salt/pillar/varstack_pillar.py | 1 - salt/pillar/vault.py | 1 - salt/proxy/cisconso.py | 1 - salt/proxy/esxcluster.py | 1 + salt/proxy/esxdatacenter.py | 1 - salt/proxy/esxi.py | 1 - salt/proxy/esxvm.py | 1 - salt/proxy/rest_sample.py | 2 - salt/proxy/restconf.py | 1 - salt/queues/pgjsonb_queue.py | 1 - salt/renderers/cheetah.py | 1 - salt/renderers/dson.py | 1 - salt/renderers/genshi.py | 1 - salt/renderers/gpg.py | 1 - salt/renderers/hjson.py | 1 - salt/renderers/jinja.py | 1 - salt/renderers/json.py | 1 - salt/renderers/json5.py | 1 - salt/renderers/mako.py | 1 - salt/renderers/nacl.py | 1 - salt/renderers/pass.py | 1 - salt/renderers/pydsl.py | 1 + salt/renderers/pyobjects.py | 1 + salt/renderers/stateconf.py | 3 +- salt/renderers/yaml.py | 1 - salt/returners/appoptics_return.py | 1 - salt/returners/couchdb_return.py | 1 - salt/returners/elasticsearch_return.py | 1 - salt/returners/librato_return.py | 1 - salt/returners/multi_returner.py | 1 - salt/returners/postgres_local_cache.py | 1 - salt/returners/rawfile_json.py | 1 - salt/returners/smtp_return.py | 1 - salt/returners/zabbix_return.py | 1 - salt/roster/cache.py | 6 +- salt/roster/cloud.py | 1 - salt/roster/clustershell.py | 1 - salt/roster/dir.py | 1 - salt/roster/sshknownhosts.py | 1 - salt/runners/auth.py | 1 - salt/runners/digicertapi.py | 1 + salt/runners/drac.py | 3 +- salt/runners/lxc.py | 1 - salt/runners/manage.py | 11 +- salt/runners/mattermost.py | 1 - salt/runners/nacl.py | 1 - salt/runners/network.py | 1 - salt/runners/pkg.py | 1 - salt/runners/queue.py | 1 - salt/runners/spacewalk.py | 2 +- salt/runners/ssh.py | 1 - salt/runners/thin.py | 1 - salt/runners/virt.py | 1 - salt/scripts.py | 4 +- salt/sdb/cache.py | 1 - salt/sdb/couchdb.py | 1 - salt/sdb/etcd_db.py | 1 - salt/sdb/rest.py | 1 - salt/sdb/tism.py | 1 - salt/sdb/vault.py | 1 - salt/sdb/yaml.py | 1 - salt/serializers/__init__.py | 1 - salt/serializers/json.py | 1 - salt/serializers/plist.py | 1 + salt/serializers/yaml.py | 1 - salt/serializers/yamlex.py | 1 + salt/spm/__init__.py | 4 +- salt/spm/pkgdb/sqlite3.py | 1 - salt/spm/pkgfiles/local.py | 1 - salt/state.py | 16 +- salt/states/alternatives.py | 24 +-- salt/states/ansiblegate.py | 6 +- salt/states/apache.py | 1 - salt/states/aptpkg.py | 1 - salt/states/archive.py | 40 ++--- salt/states/artifactory.py | 1 - salt/states/at.py | 8 +- salt/states/azurearm_compute.py | 12 +- salt/states/azurearm_dns.py | 39 ++--- salt/states/azurearm_network.py | 109 ++++++------ salt/states/azurearm_resource.py | 37 ++--- salt/states/bigip.py | 45 +++-- salt/states/boto3_elasticsearch.py | 1 - salt/states/boto3_route53.py | 97 +++++------ salt/states/boto3_sns.py | 8 +- salt/states/boto_apigateway.py | 37 ++--- salt/states/boto_asg.py | 1 - salt/states/boto_cloudfront.py | 1 - salt/states/boto_cloudtrail.py | 1 - salt/states/boto_cloudwatch_alarm.py | 1 - salt/states/boto_cloudwatch_event.py | 1 - salt/states/boto_cognitoidentity.py | 45 +++-- salt/states/boto_datapipeline.py | 1 - salt/states/boto_ec2.py | 48 +++--- salt/states/boto_elasticache.py | 7 +- salt/states/boto_elasticsearch_domain.py | 11 +- salt/states/boto_elb.py | 15 +- salt/states/boto_elbv2.py | 7 +- salt/states/boto_iam.py | 6 +- salt/states/boto_iam_role.py | 14 +- salt/states/boto_lambda.py | 1 - salt/states/boto_rds.py | 7 +- salt/states/boto_route53.py | 9 +- salt/states/boto_s3.py | 1 - salt/states/boto_s3_bucket.py | 1 - salt/states/boto_secgroup.py | 18 +- salt/states/boto_vpc.py | 10 +- salt/states/bower.py | 1 - salt/states/cabal.py | 1 - salt/states/chocolatey.py | 24 +-- salt/states/cimc.py | 7 +- salt/states/cloud.py | 9 +- salt/states/cmd.py | 13 +- salt/states/composer.py | 16 +- salt/states/consul.py | 1 + salt/states/cryptdev.py | 6 +- salt/states/debconfmod.py | 2 +- salt/states/dellchassis.py | 1 - salt/states/disk.py | 16 +- salt/states/docker_container.py | 18 +- salt/states/docker_image.py | 8 +- salt/states/docker_network.py | 14 +- salt/states/dvs.py | 13 +- salt/states/elasticsearch.py | 129 +++++++-------- salt/states/elasticsearch_index.py | 7 +- salt/states/elasticsearch_index_template.py | 15 +- salt/states/environ.py | 1 - salt/states/eselect.py | 1 - salt/states/esxcluster.py | 23 ++- salt/states/esxdatacenter.py | 1 - salt/states/esxi.py | 10 +- salt/states/esxvm.py | 1 - salt/states/etcd_mod.py | 1 - salt/states/ethtool.py | 25 ++- salt/states/event.py | 1 - salt/states/file.py | 105 ++++++------ salt/states/firewalld.py | 2 - salt/states/git.py | 24 ++- salt/states/github.py | 30 ++-- salt/states/glance_image.py | 1 - salt/states/glusterfs.py | 33 ++-- salt/states/grafana4_dashboard.py | 1 - salt/states/grafana_dashboard.py | 1 - salt/states/grains.py | 20 +-- salt/states/group.py | 7 +- salt/states/hg.py | 7 +- salt/states/highstate_doc.py | 1 - salt/states/host.py | 1 - salt/states/http.py | 1 - salt/states/icinga2.py | 25 ++- salt/states/influxdb_continuous_query.py | 6 +- salt/states/influxdb_retention_policy.py | 6 +- salt/states/influxdb_user.py | 6 +- salt/states/infoblox_a.py | 14 +- salt/states/infoblox_cname.py | 14 +- salt/states/infoblox_host_record.py | 14 +- salt/states/ini_manage.py | 1 - salt/states/ipset.py | 8 +- salt/states/iptables.py | 65 ++++---- salt/states/jboss7.py | 9 +- salt/states/jenkins.py | 1 - salt/states/kapacitor.py | 1 + salt/states/kernelpkg.py | 6 +- salt/states/keystone_domain.py | 1 - salt/states/keystone_endpoint.py | 1 - salt/states/keystone_group.py | 1 - salt/states/keystone_project.py | 1 - salt/states/keystone_role.py | 1 - salt/states/keystone_role_grant.py | 1 - salt/states/keystone_service.py | 1 - salt/states/keystone_user.py | 1 - salt/states/keystore.py | 1 - salt/states/libcloud_loadbalancer.py | 1 - salt/states/libcloud_storage.py | 1 - salt/states/linux_acl.py | 1 - salt/states/locale.py | 1 - salt/states/logrotate.py | 1 - salt/states/loop.py | 9 +- salt/states/lvm.py | 28 ++-- salt/states/lvs_server.py | 64 +++---- salt/states/lvs_service.py | 20 +-- salt/states/lxc.py | 1 - salt/states/lxd.py | 1 - salt/states/lxd_container.py | 15 +- salt/states/lxd_image.py | 1 - salt/states/lxd_profile.py | 9 +- salt/states/mdadm_raid.py | 17 +- salt/states/memcached.py | 1 - salt/states/modjk_worker.py | 14 +- salt/states/module.py | 9 +- salt/states/mount.py | 30 ++-- salt/states/mssql_database.py | 8 +- salt/states/mssql_login.py | 8 +- salt/states/mssql_role.py | 8 +- salt/states/mssql_user.py | 8 +- salt/states/msteams.py | 1 - salt/states/mysql_grants.py | 24 +-- salt/states/mysql_query.py | 1 - salt/states/netntp.py | 20 +-- salt/states/netsnmp.py | 14 -- salt/states/netusers.py | 9 - salt/states/network.py | 38 ++--- salt/states/neutron_network.py | 1 - salt/states/neutron_secgroup.py | 1 - salt/states/neutron_secgroup_rule.py | 1 - salt/states/neutron_subnet.py | 1 - salt/states/nexus.py | 1 - salt/states/nftables.py | 96 +++++------ salt/states/npm.py | 1 - salt/states/openstack_config.py | 1 - salt/states/openvswitch_port.py | 56 +++---- salt/states/opsgenie.py | 16 +- salt/states/pbm.py | 1 - salt/states/pip_state.py | 1 - salt/states/pkg.py | 87 +++++----- salt/states/pkgrepo.py | 19 +-- salt/states/ports.py | 16 +- salt/states/postgres_database.py | 22 +-- salt/states/postgres_privileges.py | 8 +- salt/states/postgres_schema.py | 8 +- salt/states/postgres_tablespace.py | 17 +- salt/states/probes.py | 10 -- salt/states/rabbitmq_plugin.py | 1 - salt/states/rabbitmq_upstream.py | 1 - salt/states/rabbitmq_user.py | 1 - salt/states/rabbitmq_vhost.py | 1 - salt/states/restconf.py | 1 - salt/states/saltmod.py | 8 +- salt/states/serverdensity_device.py | 13 +- salt/states/service.py | 78 ++++----- salt/states/slack.py | 1 - salt/states/smartos.py | 20 +-- salt/states/snapper.py | 1 - salt/states/solrcloud.py | 1 - salt/states/sqlite3.py | 1 - salt/states/ssh_auth.py | 15 +- salt/states/supervisord.py | 26 +-- salt/states/sysrc.py | 1 - salt/states/telemetry_alert.py | 8 +- salt/states/timezone.py | 8 +- salt/states/tls.py | 1 - salt/states/tuned.py | 1 - salt/states/user.py | 38 ++--- salt/states/vbox_guest.py | 6 +- salt/states/virt.py | 13 +- salt/states/virtualenv_mod.py | 1 - salt/states/webutil.py | 1 - salt/states/win_dns_client.py | 14 +- salt/states/win_iis.py | 1 - salt/states/win_lgpo.py | 1 + salt/states/win_lgpo_reg.py | 1 + salt/states/win_network.py | 34 ++-- salt/states/win_pki.py | 17 +- salt/states/win_powercfg.py | 1 - salt/states/win_shortcut.py | 1 + salt/states/win_smtp_server.py | 13 +- salt/states/win_system.py | 22 +-- salt/states/win_wusa.py | 1 - salt/states/x509_v2.py | 31 ++-- salt/states/zabbix_action.py | 8 +- salt/states/zabbix_template.py | 8 +- salt/states/zabbix_user.py | 7 +- salt/states/zabbix_valuemap.py | 8 +- salt/states/zenoss.py | 13 +- salt/states/zk_concurrency.py | 1 - salt/states/zone.py | 156 +++++++++--------- salt/states/zookeeper.py | 9 +- salt/syspaths.py | 1 - salt/template.py | 1 + salt/thorium/__init__.py | 1 + salt/thorium/calc.py | 1 - salt/thorium/file.py | 1 - salt/thorium/reg.py | 1 - salt/thorium/timer.py | 1 - salt/tokens/localfs.py | 3 +- salt/tops/cobbler.py | 3 +- salt/tops/ext_nodes.py | 1 + salt/tops/saltclass.py | 1 - salt/tops/varstack_top.py | 1 - salt/transport/__init__.py | 1 - salt/transport/client.py | 1 + salt/transport/frame.py | 1 - salt/transport/ipc.py | 1 - salt/transport/server.py | 1 + salt/transport/tcp.py | 1 - salt/transport/zeromq.py | 1 + salt/utils/aggregation.py | 2 - salt/utils/asynchronous.py | 1 - salt/utils/atomicfile.py | 1 + salt/utils/aws.py | 1 + salt/utils/boto3mod.py | 1 - salt/utils/botomod.py | 1 - salt/utils/cloud.py | 7 +- salt/utils/color.py | 1 - salt/utils/configparser.py | 4 +- salt/utils/crypt.py | 1 + salt/utils/data.py | 3 +- salt/utils/dateutils.py | 1 - salt/utils/decorators/__init__.py | 9 +- salt/utils/decorators/state.py | 1 - salt/utils/doc.py | 1 + salt/utils/dockermod/__init__.py | 1 - salt/utils/dockermod/translate/container.py | 8 +- salt/utils/dockermod/translate/helpers.py | 8 +- salt/utils/extend.py | 1 - salt/utils/files.py | 7 +- salt/utils/find.py | 1 - salt/utils/fsutils.py | 1 + salt/utils/functools.py | 1 + salt/utils/gitfs.py | 8 +- salt/utils/github.py | 1 - salt/utils/gzip_util.py | 1 - salt/utils/http.py | 16 +- salt/utils/idem.py | 1 + salt/utils/itertools.py | 1 - salt/utils/job.py | 1 - salt/utils/json.py | 1 - salt/utils/lazy.py | 1 - salt/utils/locales.py | 1 - salt/utils/master.py | 1 + salt/utils/memcached.py | 1 - salt/utils/mine.py | 1 - salt/utils/minion.py | 1 - salt/utils/minions.py | 1 - salt/utils/mount.py | 1 - salt/utils/msazure.py | 1 - salt/utils/msgpack.py | 1 + salt/utils/namecheap.py | 1 - salt/utils/napalm.py | 1 - salt/utils/network.py | 4 +- salt/utils/odict.py | 1 + salt/utils/openstack/neutron.py | 2 - salt/utils/openstack/nova.py | 7 +- salt/utils/parsers.py | 1 + salt/utils/path.py | 1 - salt/utils/pbm.py | 1 - salt/utils/pkg/rpm.py | 1 + salt/utils/pkg/win.py | 1 + salt/utils/platform.py | 1 + salt/utils/process.py | 5 +- salt/utils/profile.py | 1 - salt/utils/proxy.py | 1 - salt/utils/pycrypto.py | 1 + salt/utils/reactor.py | 1 + salt/utils/saltclass.py | 4 +- salt/utils/schedule.py | 33 ++-- salt/utils/smb.py | 7 +- salt/utils/smtp.py | 8 +- salt/utils/ssdp.py | 2 +- salt/utils/state.py | 1 - salt/utils/stringio.py | 1 - salt/utils/stringutils.py | 1 - salt/utils/templates.py | 1 + salt/utils/textformat.py | 1 - salt/utils/thin.py | 4 +- salt/utils/url.py | 1 - salt/utils/user.py | 1 - salt/utils/vault.py | 2 +- salt/utils/versions.py | 1 + salt/utils/vsan.py | 1 - salt/utils/win_lgpo_reg.py | 1 + salt/utils/win_network.py | 1 + salt/utils/win_osinfo.py | 1 + salt/utils/win_system.py | 1 + salt/utils/win_update.py | 1 + salt/utils/x509.py | 86 +++++----- salt/utils/xmlutil.py | 8 +- salt/utils/yaml.py | 1 + salt/utils/yamldumper.py | 1 + salt/utils/yamlencoding.py | 1 - salt/utils/yamlloader.py | 1 - salt/utils/yamlloader_old.py | 1 - salt/utils/zfs.py | 1 - salt/version.py | 1 + salt/wheel/file_roots.py | 1 - salt/wheel/key.py | 1 - salt/wheel/minions.py | 1 - tests/conftest.py | 4 +- tests/eventlisten.py | 1 + tests/integration/cli/test_custom_module.py | 2 +- .../cloud/clouds/test_digitalocean.py | 1 + .../cloud/clouds/test_dimensiondata.py | 1 - tests/integration/cloud/clouds/test_ec2.py | 1 + tests/integration/cloud/clouds/test_gce.py | 1 - tests/integration/cloud/clouds/test_linode.py | 1 - .../cloud/clouds/test_oneandone.py | 1 + .../cloud/clouds/test_profitbricks.py | 1 + .../cloud/helpers/cloud_test_base.py | 1 - tests/integration/cloud/test_cloud.py | 1 + tests/integration/conftest.py | 1 + .../pillar/ext_pillar_opts.py | 1 - .../file/base/_modules/runtests_helpers.py | 1 - .../files/returners/noop_returner.py | 1 - tests/integration/grains/test_core.py | 1 + tests/integration/grains/test_custom.py | 1 - tests/integration/loader/test_ext_grains.py | 1 - tests/integration/minion/test_timeout.py | 1 - tests/integration/modules/test_boto_iam.py | 1 + tests/integration/modules/test_boto_sns.py | 1 + tests/integration/modules/test_macdefaults.py | 1 + tests/integration/modules/test_test.py | 5 +- tests/integration/modules/test_timezone.py | 1 + tests/integration/shell/test_master_tops.py | 1 - tests/integration/spm/test_install.py | 1 + tests/integration/ssh/test_state.py | 2 +- tests/integration/states/test_boto_sns.py | 1 + tests/integration/states/test_compiler.py | 1 - .../integration/states/test_handle_iorder.py | 1 - tests/integration/states/test_lxd_image.py | 1 + tests/integration/states/test_lxd_profile.py | 1 + tests/integration/utils/test_idem.py | 1 + tests/integration/utils/test_smb.py | 1 + tests/packdump.py | 1 + tests/pytests/conftest.py | 2 + tests/pytests/functional/cli/test_batch.py | 1 + .../pytests/functional/cli/test_salt_cloud.py | 1 + .../functional/modules/file/test_replace.py | 1 + .../modules/state/test_jinja_filters.py | 1 + .../functional/modules/test_archive.py | 1 + .../functional/modules/test_dockermod.py | 1 + .../functional/modules/test_mac_pkgutil.py | 1 + .../pytests/functional/modules/test_mysql.py | 1 + .../functional/modules/test_network.py | 1 + .../functional/modules/test_win_shortcut.py | 1 + .../modules/win_file/test_check_perms.py | 1 + .../modules/win_file/test_remove.py | 1 + .../functional/modules/win_file/test_stat.py | 1 + .../functional/states/file/test_comment.py | 1 + .../functional/states/file/test_managed.py | 1 - .../functional/states/file/test_rename.py | 1 + .../states/test_chocolatey_1_2_1.py | 1 + .../states/test_chocolatey_latest.py | 1 + tests/pytests/functional/states/test_mysql.py | 1 + tests/pytests/functional/states/test_svn.py | 1 + .../functional/states/test_win_certutil.py | 1 + .../pytests/functional/states/test_x509_v2.py | 6 +- .../pytests/functional/utils/test_process.py | 1 + .../utils/win_dacl/test_get_name.py | 1 + .../functional/utils/win_dacl/test_get_sid.py | 1 + .../utils/win_dacl/test_get_sid_string.py | 1 + tests/pytests/integration/cli/test_salt.py | 1 + tests/pytests/integration/cli/test_salt_cp.py | 1 - .../integration/cli/test_salt_deltaproxy.py | 23 ++- .../integration/master/test_payload.py | 1 + .../integration/minion/test_return_retries.py | 4 +- .../integration/modules/grains/test_module.py | 1 - .../modules/saltutil/test_modules.py | 1 - .../modules/saltutil/test_pillar.py | 1 - .../modules/saltutil/test_wheel.py | 1 - .../integration/modules/test_beacons.py | 1 + .../pytests/integration/modules/test_event.py | 1 + .../pytests/integration/modules/test_file.py | 1 + .../pytests/integration/modules/test_idem.py | 1 + .../integration/modules/test_useradd.py | 1 + .../pytests/integration/modules/test_virt.py | 1 + .../integration/netapi/test_ssh_client.py | 2 +- .../pillar/cache/test_pillar_cache.py | 1 + .../integration/pillar/test_pillar_include.py | 13 +- tests/pytests/integration/proxy/conftest.py | 8 +- .../integration/proxy/test_deltaproxy.py | 1 + tests/pytests/integration/proxy/test_shell.py | 1 + .../pytests/integration/proxy/test_simple.py | 1 + .../runners/state/orchestrate/test_events.py | 1 + tests/pytests/integration/sdb/test_vault.py | 1 + tests/pytests/integration/ssh/test_log.py | 1 + .../integration/ssh/test_py_versions.py | 1 + .../pytests/integration/ssh/test_ssh_setup.py | 1 + .../pytests/integration/states/test_beacon.py | 1 + tests/pytests/integration/states/test_file.py | 9 +- tests/pytests/integration/states/test_idem.py | 1 + .../integration/states/test_include.py | 1 + .../integration/utils/test_templates.py | 1 + tests/pytests/pkg/conftest.py | 12 +- .../pytests/pkg/download/test_pkg_download.py | 1 + .../blackout/test_minion_blackout.py | 1 - tests/pytests/scenarios/compat/conftest.py | 1 + .../scenarios/compat/test_with_versions.py | 1 + .../pytests/scenarios/performance/conftest.py | 1 + tests/pytests/scenarios/setup/test_install.py | 1 + tests/pytests/unit/auth/test_ldap.py | 1 + tests/pytests/unit/beacons/test_adb.py | 1 + .../unit/beacons/test_avahi_announce.py | 1 + .../unit/beacons/test_bonjour_announce.py | 1 + tests/pytests/unit/beacons/test_diskusage.py | 1 + tests/pytests/unit/beacons/test_glxinfo.py | 1 + tests/pytests/unit/beacons/test_haproxy.py | 1 + tests/pytests/unit/beacons/test_load.py | 1 + tests/pytests/unit/beacons/test_log_beacon.py | 1 + tests/pytests/unit/beacons/test_memusage.py | 1 + .../pytests/unit/beacons/test_network_info.py | 1 + tests/pytests/unit/beacons/test_ps.py | 1 + tests/pytests/unit/beacons/test_swapusage.py | 1 + tests/pytests/unit/cache/test_localfs.py | 1 + tests/pytests/unit/cache/test_memcache.py | 1 + tests/pytests/unit/cache/test_mysql_cache.py | 1 - .../unit/cloud/clouds/test_azurearm.py | 12 +- .../unit/cloud/clouds/test_digitalocean.py | 1 - .../pytests/unit/cloud/clouds/test_hetzner.py | 12 +- .../pytests/unit/cloud/clouds/test_saltify.py | 1 + .../pytests/unit/cloud/clouds/test_vultrpy.py | 12 +- .../unit/config/test__validate_opts.py | 1 + .../unit/engines/test_libvirt_events.py | 1 + tests/pytests/unit/engines/test_slack.py | 1 + .../unit/engines/test_slack_bolt_engine.py | 23 ++- tests/pytests/unit/engines/test_sqs_events.py | 1 + .../unit/fileclient/test_fileclient.py | 1 + tests/pytests/unit/grains/test_core.py | 18 +- tests/pytests/unit/grains/test_esxi.py | 1 - tests/pytests/unit/loader/test_context.py | 1 + tests/pytests/unit/loader/test_lazy.py | 1 + tests/pytests/unit/loader/test_loader.py | 1 + .../unit/log_handlers/test_sentry_mod.py | 1 + .../unit/modules/file/test_file_line.py | 6 +- tests/pytests/unit/modules/napalm/test_bgp.py | 1 - tests/pytests/unit/modules/napalm/test_mod.py | 1 + .../unit/modules/napalm/test_network.py | 1 - .../pytests/unit/modules/napalm/test_snmp.py | 1 - .../pytests/unit/modules/napalm/test_users.py | 1 - tests/pytests/unit/modules/test_acme.py | 1 - tests/pytests/unit/modules/test_at.py | 1 - tests/pytests/unit/modules/test_augeas_cfg.py | 1 + tests/pytests/unit/modules/test_bigip.py | 1 + .../unit/modules/test_bluez_bluetooth.py | 1 - .../unit/modules/test_boto_dynamodb.py | 1 - tests/pytests/unit/modules/test_bower.py | 1 - tests/pytests/unit/modules/test_bridge.py | 1 - .../unit/modules/test_cassandra_cql.py | 1 - tests/pytests/unit/modules/test_chocolatey.py | 1 + tests/pytests/unit/modules/test_composer.py | 1 - tests/pytests/unit/modules/test_config.py | 1 - tests/pytests/unit/modules/test_consul.py | 1 - tests/pytests/unit/modules/test_cp.py | 1 - .../pytests/unit/modules/test_daemontools.py | 1 - tests/pytests/unit/modules/test_data.py | 1 + tests/pytests/unit/modules/test_deb_apache.py | 1 - tests/pytests/unit/modules/test_devmap.py | 1 - tests/pytests/unit/modules/test_dig.py | 1 - tests/pytests/unit/modules/test_disk.py | 1 + tests/pytests/unit/modules/test_djangomod.py | 1 + .../pytests/unit/modules/test_dpkg_lowpkg.py | 1 - tests/pytests/unit/modules/test_drac.py | 1 - tests/pytests/unit/modules/test_drbd.py | 1 - tests/pytests/unit/modules/test_etcd_mod.py | 1 - tests/pytests/unit/modules/test_extfs.py | 1 - tests/pytests/unit/modules/test_genesis.py | 1 - .../unit/modules/test_gentoo_service.py | 1 - tests/pytests/unit/modules/test_git.py | 9 +- tests/pytests/unit/modules/test_glassfish.py | 1 + tests/pytests/unit/modules/test_glusterfs.py | 1 - .../pytests/unit/modules/test_grub_legacy.py | 1 - tests/pytests/unit/modules/test_hadoop.py | 1 - .../pytests/unit/modules/test_haproxyconn.py | 1 - tests/pytests/unit/modules/test_hashutil.py | 1 - tests/pytests/unit/modules/test_helm.py | 1 - tests/pytests/unit/modules/test_hg.py | 1 - tests/pytests/unit/modules/test_http.py | 1 - tests/pytests/unit/modules/test_ilo.py | 1 - tests/pytests/unit/modules/test_incron.py | 1 - tests/pytests/unit/modules/test_ini_manage.py | 11 +- tests/pytests/unit/modules/test_introspect.py | 1 - tests/pytests/unit/modules/test_ipset.py | 1 + tests/pytests/unit/modules/test_junos.py | 1 + tests/pytests/unit/modules/test_key.py | 1 - tests/pytests/unit/modules/test_keyboard.py | 1 - tests/pytests/unit/modules/test_kubeadm.py | 1 - .../unit/modules/test_launchctl_service.py | 1 - tests/pytests/unit/modules/test_ldapmod.py | 1 - tests/pytests/unit/modules/test_linux_lvm.py | 1 - .../pytests/unit/modules/test_linux_shadow.py | 1 + tests/pytests/unit/modules/test_locate.py | 1 - tests/pytests/unit/modules/test_logadm.py | 1 - tests/pytests/unit/modules/test_logrotate.py | 1 - tests/pytests/unit/modules/test_lvs.py | 1 - .../pytests/unit/modules/test_mac_brew_pkg.py | 1 + .../pytests/unit/modules/test_mac_service.py | 1 - tests/pytests/unit/modules/test_mac_shadow.py | 1 + tests/pytests/unit/modules/test_mandrill.py | 1 - tests/pytests/unit/modules/test_match.py | 1 - tests/pytests/unit/modules/test_mdadm_raid.py | 1 + tests/pytests/unit/modules/test_mine.py | 1 - tests/pytests/unit/modules/test_mongodb.py | 56 +++++-- tests/pytests/unit/modules/test_monit.py | 1 - tests/pytests/unit/modules/test_mysql.py | 1 - tests/pytests/unit/modules/test_nacl.py | 1 + tests/pytests/unit/modules/test_nfs3.py | 1 - tests/pytests/unit/modules/test_nftables.py | 1 + tests/pytests/unit/modules/test_npm.py | 1 - tests/pytests/unit/modules/test_openbsdpkg.py | 1 - tests/pytests/unit/modules/test_oracle.py | 1 - tests/pytests/unit/modules/test_osquery.py | 1 - tests/pytests/unit/modules/test_pacmanpkg.py | 1 - tests/pytests/unit/modules/test_pagerduty.py | 1 - tests/pytests/unit/modules/test_pam.py | 1 + tests/pytests/unit/modules/test_parallels.py | 1 - tests/pytests/unit/modules/test_pecl.py | 1 - tests/pytests/unit/modules/test_pkgutil.py | 1 - .../unit/modules/test_portage_config.py | 3 +- tests/pytests/unit/modules/test_postfix.py | 1 - tests/pytests/unit/modules/test_ps.py | 8 +- tests/pytests/unit/modules/test_publish.py | 1 - tests/pytests/unit/modules/test_pw_user.py | 1 - tests/pytests/unit/modules/test_qemu_img.py | 1 - tests/pytests/unit/modules/test_rabbitmq.py | 1 - tests/pytests/unit/modules/test_rbenv.py | 1 - tests/pytests/unit/modules/test_rdp.py | 1 - .../pytests/unit/modules/test_restartcheck.py | 16 +- tests/pytests/unit/modules/test_ret.py | 1 - tests/pytests/unit/modules/test_rh_service.py | 1 - tests/pytests/unit/modules/test_rvm.py | 1 - tests/pytests/unit/modules/test_s6.py | 1 - .../pytests/unit/modules/test_saltcloudmod.py | 1 - tests/pytests/unit/modules/test_schedule.py | 78 +++++++-- tests/pytests/unit/modules/test_sdb.py | 1 + .../unit/modules/test_serverdensity_device.py | 1 - tests/pytests/unit/modules/test_servicenow.py | 1 - .../unit/modules/test_slackware_service.py | 1 + .../unit/modules/test_smartos_imgadm.py | 1 - tests/pytests/unit/modules/test_smtp.py | 1 - tests/pytests/unit/modules/test_status.py | 1 - tests/pytests/unit/modules/test_suse_ip.py | 4 +- tests/pytests/unit/modules/test_swift.py | 1 - tests/pytests/unit/modules/test_syslog_ng.py | 1 - tests/pytests/unit/modules/test_system.py | 1 + tests/pytests/unit/modules/test_telegram.py | 1 - tests/pytests/unit/modules/test_tomcat.py | 1 - .../unit/modules/test_transactional_update.py | 8 +- tests/pytests/unit/modules/test_tuned.py | 1 - tests/pytests/unit/modules/test_udev.py | 1 - tests/pytests/unit/modules/test_uptime.py | 1 - tests/pytests/unit/modules/test_uwsgi.py | 1 - tests/pytests/unit/modules/test_vagrant.py | 1 - tests/pytests/unit/modules/test_vault.py | 1 - tests/pytests/unit/modules/test_vmctl.py | 1 - tests/pytests/unit/modules/test_webutil.py | 1 - .../pytests/unit/modules/test_win_autoruns.py | 1 - .../unit/modules/test_win_dns_client.py | 1 - tests/pytests/unit/modules/test_win_iis.py | 1 - .../pytests/unit/modules/test_win_licence.py | 1 - tests/pytests/unit/modules/test_win_path.py | 1 - tests/pytests/unit/modules/test_win_pkg.py | 1 + tests/pytests/unit/modules/test_win_pki.py | 1 - .../pytests/unit/modules/test_win_powercfg.py | 1 - tests/pytests/unit/modules/test_win_psget.py | 1 - tests/pytests/unit/modules/test_win_shadow.py | 1 - tests/pytests/unit/modules/test_win_snmp.py | 1 - tests/pytests/unit/modules/test_win_system.py | 1 + tests/pytests/unit/modules/test_win_task.py | 1 + .../pytests/unit/modules/test_win_timezone.py | 1 + tests/pytests/unit/modules/test_win_wua.py | 1 + tests/pytests/unit/modules/test_xapi_virt.py | 1 - tests/pytests/unit/modules/test_xfs.py | 1 - tests/pytests/unit/modules/test_xml.py | 1 - tests/pytests/unit/modules/test_yumpkg.py | 6 +- tests/pytests/unit/modules/test_zenoss.py | 1 - tests/pytests/unit/modules/test_zfs.py | 6 +- tests/pytests/unit/modules/test_znc.py | 1 - tests/pytests/unit/modules/test_zpool.py | 6 +- tests/pytests/unit/modules/test_zypperpkg.py | 1 - .../pytests/unit/modules/virt/test_domain.py | 16 +- .../modules/win_lgpo/test_admx_policies.py | 1 + .../modules/win_lgpo/test_defined_policies.py | 1 + .../unit/modules/win_lgpo/test_mechanisms.py | 1 + .../win_lgpo/test_point_print_enabled.py | 1 + .../modules/win_lgpo/test_point_print_nc.py | 1 + .../unit/modules/win_lgpo/test_policy_info.py | 1 + .../win_lgpo/test_policy_info_functions.py | 1 + .../modules/win_lgpo/test_policy_resources.py | 1 + .../unit/modules/win_lgpo/test_reg_pol.py | 1 + tests/pytests/unit/output/test_json_out.py | 1 + tests/pytests/unit/output/test_nested.py | 1 + tests/pytests/unit/output/test_yaml_out.py | 1 + tests/pytests/unit/pillar/test_csvpillar.py | 1 - .../unit/proxy/nxos/test_nxos_nxapi.py | 18 -- .../pytests/unit/proxy/nxos/test_nxos_ssh.py | 14 -- .../pytests/unit/proxy/test_esxdatacenter.py | 1 + tests/pytests/unit/proxy/test_napalm.py | 1 + tests/pytests/unit/renderers/test_aws_kms.py | 1 + .../returners/test_elasticsearch_return.py | 1 + tests/pytests/unit/returners/test_pgjsonb.py | 1 - .../returners/test_slack_webhook_return.py | 1 + .../unit/returners/test_smtp_return.py | 1 + .../unit/returners/test_syslog_return.py | 1 + .../unit/returners/test_telegram_return.py | 1 + tests/pytests/unit/roster/test_dir.py | 1 - tests/pytests/unit/roster/test_terraform.py | 1 + tests/pytests/unit/runners/test_bgp.py | 1 + tests/pytests/unit/runners/test_fileserver.py | 1 - tests/pytests/unit/runners/test_git_pillar.py | 1 - tests/pytests/unit/runners/test_jobs.py | 1 + tests/pytests/unit/runners/test_network.py | 1 + tests/pytests/unit/runners/test_reactor.py | 1 - tests/pytests/unit/runners/test_spacewalk.py | 1 + tests/pytests/unit/runners/test_winrepo.py | 1 - .../unit/runners/vault/test_app_role_auth.py | 1 - .../unit/runners/vault/test_token_auth.py | 1 - .../pytests/unit/runners/vault/test_vault.py | 1 - tests/pytests/unit/sdb/test_yaml.py | 1 - tests/pytests/unit/state/test_state_basic.py | 1 + .../unit/states/file/test__clean_dir.py | 1 + .../states/file/test_retention_schedule.py | 14 +- .../unit/states/mysql/test_database.py | 1 + tests/pytests/unit/states/test_aptpkg.py | 1 - tests/pytests/unit/states/test_archive.py | 1 - tests/pytests/unit/states/test_aws_sqs.py | 1 + .../unit/states/test_boto_cloudfront.py | 1 + tests/pytests/unit/states/test_boto_lc.py | 1 + .../pytests/unit/states/test_boto_route53.py | 1 + tests/pytests/unit/states/test_boto_sns.py | 1 + tests/pytests/unit/states/test_boto_sqs.py | 1 + tests/pytests/unit/states/test_bower.py | 1 + tests/pytests/unit/states/test_chocolatey.py | 1 + tests/pytests/unit/states/test_consul.py | 1 - tests/pytests/unit/states/test_debconfmod.py | 1 + tests/pytests/unit/states/test_drac.py | 1 + .../pytests/unit/states/test_elasticsearch.py | 1 + tests/pytests/unit/states/test_eselect.py | 1 + tests/pytests/unit/states/test_etcd_mod.py | 1 - tests/pytests/unit/states/test_ethtool.py | 6 +- tests/pytests/unit/states/test_gem.py | 1 - tests/pytests/unit/states/test_git.py | 1 - .../pytests/unit/states/test_gnomedesktop.py | 1 - tests/pytests/unit/states/test_grains.py | 1 + tests/pytests/unit/states/test_group.py | 3 +- tests/pytests/unit/states/test_helm.py | 1 - tests/pytests/unit/states/test_ini_manage.py | 1 - tests/pytests/unit/states/test_iptables.py | 1 - tests/pytests/unit/states/test_kapacitor.py | 1 - tests/pytests/unit/states/test_kernelpkg.py | 1 - tests/pytests/unit/states/test_kmod.py | 1 + tests/pytests/unit/states/test_layman.py | 1 + tests/pytests/unit/states/test_ldap.py | 65 ++++---- .../pytests/unit/states/test_libcloud_dns.py | 1 - tests/pytests/unit/states/test_mount.py | 6 +- tests/pytests/unit/states/test_pip.py | 1 + tests/pytests/unit/states/test_ports.py | 1 + tests/pytests/unit/states/test_sysfs.py | 1 + .../unit/states/test_virtualenv_mod.py | 1 - tests/pytests/unit/states/test_webutil.py | 1 - tests/pytests/unit/states/test_win_lgpo.py | 1 + tests/pytests/unit/states/test_win_wua.py | 21 ++- tests/pytests/unit/states/test_xmpp.py | 1 - tests/pytests/unit/states/virt/test_domain.py | 22 ++- .../pytests/unit/states/zabbix/test_action.py | 8 +- .../unit/states/zabbix/test_valuemap.py | 8 +- tests/pytests/unit/test_acl.py | 1 - tests/pytests/unit/test_config.py | 1 + tests/pytests/unit/test_fileclient.py | 1 + tests/pytests/unit/test_log.py | 1 - tests/pytests/unit/test_syspaths.py | 1 + tests/pytests/unit/test_version.py | 1 + tests/pytests/unit/transport/test_base.py | 1 + tests/pytests/unit/utils/jinja/conftest.py | 1 + tests/pytests/unit/utils/jinja/test_jinja.py | 1 + .../pytests/unit/utils/scheduler/conftest.py | 1 - .../unit/utils/templates/test_jinja.py | 1 + .../utils/templates/test_wrap_tmpl_func.py | 1 + tests/pytests/unit/utils/test_aws.py | 1 + tests/pytests/unit/utils/test_cloud.py | 1 - tests/pytests/unit/utils/test_compat.py | 1 + tests/pytests/unit/utils/test_crypt.py | 1 + tests/pytests/unit/utils/test_data.py | 1 + tests/pytests/unit/utils/test_files.py | 1 - tests/pytests/unit/utils/test_nacl.py | 1 + tests/pytests/unit/utils/test_rsax931.py | 1 + tests/pytests/unit/utils/test_x509.py | 8 +- .../unit/utils/verify/test_clean_path_link.py | 1 + .../pytests/unit/utils/verify/test_verify.py | 16 +- tests/support/cli_scripts.py | 1 - tests/support/events.py | 1 - tests/support/helpers.py | 1 + tests/support/kernelpkg.py | 1 + tests/support/mixins.py | 6 +- tests/support/mock.py | 1 + tests/support/napalm.py | 1 - tests/support/pytest/helpers.py | 1 + tests/support/pytest/loader.py | 1 + tests/support/runtests.py | 16 +- tests/support/unit.py | 1 + tests/support/xmlunit.py | 1 + tests/support/zfs.py | 1 - tests/unit/ext/test_ipaddress.py | 4 +- tests/unit/modules/nxos/nxos_n36k.py | 1 - tests/unit/modules/nxos/nxos_n3k.py | 1 - tests/unit/modules/nxos/nxos_n5k.py | 1 - tests/unit/modules/nxos/nxos_n7k.py | 1 - tests/unit/modules/nxos/nxos_n93k.py | 1 - tests/unit/modules/nxos/nxos_n93klxc.py | 1 - tests/unit/modules/nxos/nxos_n95k.py | 1 - tests/unit/modules/nxos/nxos_platform.py | 4 - .../unit/modules/test_boto3_elasticsearch.py | 1 + tests/unit/modules/test_boto3_route53.py | 1 + tests/unit/modules/test_bsd_shadow.py | 1 + tests/unit/modules/test_freezer.py | 1 - tests/unit/modules/test_influxdb08mod.py | 1 - .../unit/modules/test_kernelpkg_linux_apt.py | 1 + .../unit/modules/test_kernelpkg_linux_yum.py | 1 + tests/unit/modules/test_kubernetesmod.py | 1 + tests/unit/modules/test_libcloud_compute.py | 1 + tests/unit/modules/test_libcloud_dns.py | 1 + .../modules/test_libcloud_loadbalancer.py | 1 + tests/unit/modules/test_libcloud_storage.py | 1 + tests/unit/modules/test_localemod.py | 1 + tests/unit/modules/test_memcached.py | 1 - tests/unit/modules/test_napalm_probes.py | 1 - tests/unit/modules/test_napalm_yang_mod.py | 1 - tests/unit/modules/test_netbox.py | 1 + tests/unit/modules/test_netscaler.py | 1 - tests/unit/modules/test_neutron.py | 1 - tests/unit/modules/test_nova.py | 1 - tests/unit/modules/test_nxos.py | 60 ------- tests/unit/modules/test_nxos_upgrade.py | 23 --- tests/unit/modules/test_openstack_config.py | 1 - tests/unit/modules/test_opkg.py | 6 +- tests/unit/modules/test_parted_partition.py | 1 - tests/unit/modules/test_rh_ip.py | 4 +- tests/unit/modules/test_snapper.py | 1 + tests/unit/modules/test_sqlite3.py | 1 - tests/unit/modules/test_supervisord.py | 1 - tests/unit/modules/test_sysmod.py | 1 - tests/unit/modules/test_systemd_service.py | 1 - tests/unit/modules/test_twilio_notify.py | 1 + tests/unit/modules/test_useradd.py | 1 + tests/unit/modules/test_virt.py | 40 +++-- tests/unit/modules/test_vsphere.py | 1 + tests/unit/modules/test_win_system.py | 1 + tests/unit/modules/test_zypperpkg.py | 1 - tests/unit/states/test_group.py | 1 - tests/unit/states/test_module.py | 1 - tests/unit/states/test_syslog_ng.py | 1 - tests/unit/test_config.py | 1 + tests/unit/test_zypp_plugins.py | 1 + tests/unit/transport/test_ipc.py | 1 + tests/unit/utils/test_color.py | 1 - tests/unit/utils/test_decorators.py | 1 - tests/unit/utils/test_doc.py | 1 - tests/unit/utils/test_environment.py | 1 + tests/unit/utils/test_extend.py | 1 + tests/unit/utils/test_filebuffer.py | 1 - tests/unit/utils/test_immutabletypes.py | 1 - tests/unit/utils/test_jid.py | 1 - tests/unit/utils/test_job.py | 1 - tests/unit/utils/test_mac_utils.py | 1 + tests/unit/utils/test_msgpack.py | 1 + tests/unit/utils/test_proxy.py | 1 - tests/unit/utils/test_roster_matcher.py | 1 + tests/unit/utils/test_sdb.py | 1 - tests/unit/utils/test_state.py | 1 - tests/unit/utils/test_thin.py | 2 +- tests/unit/utils/test_vmware.py | 30 ++-- tests/unit/utils/test_vsan.py | 1 + tests/unit/utils/test_win_chcp.py | 1 + tests/unit/utils/test_xmlutil.py | 1 + tests/unit/utils/test_yamlencoding.py | 1 - tests/unit/utils/test_zeromq.py | 1 + tests/unit/utils/test_zfs.py | 1 - tools/changelog.py | 1 + tools/ci.py | 1 + tools/docs.py | 1 + tools/pkg/__init__.py | 3 +- tools/pkg/build.py | 5 +- tools/pkg/repo/__init__.py | 1 + tools/pkg/repo/create.py | 1 + tools/pkg/repo/publish.py | 1 + tools/precommit/__init__.py | 1 + tools/precommit/changelog.py | 1 + tools/precommit/docs.py | 1 + tools/precommit/docstrings.py | 1 + tools/precommit/filemap.py | 1 + tools/precommit/workflows.py | 1 + tools/release.py | 1 + tools/testsuite/__init__.py | 1 + tools/testsuite/download.py | 1 + tools/vm.py | 1 + 1226 files changed, 2974 insertions(+), 3131 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bd136d50a9c..9067d37d074 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ exclude: ^(doc/_static/.*|doc/_themes/.*)$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-merge-conflict # Check for files that contain merge conflict strings. - id: trailing-whitespace # Trims trailing whitespace. @@ -1622,7 +1622,7 @@ repos: # ----- Code Formatting -------------------------------------------------------------------------------------------> - repo: https://github.com/asottile/pyupgrade - rev: v2.37.2 + rev: v3.15.1 hooks: - id: pyupgrade name: Drop six usage and Py2 support @@ -1643,7 +1643,7 @@ repos: - repo: https://github.com/saltstack/salt-rewrite # Automatically rewrite code with known rules - rev: 2.4.4 + rev: 2.5.2 hooks: - id: salt-rewrite alias: rewrite-docstrings @@ -1662,7 +1662,7 @@ repos: args: [--silent, -E, fix_asserts, -E, fix_docstrings] - repo: https://github.com/timothycrosley/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort additional_dependencies: ['toml'] @@ -1675,31 +1675,32 @@ repos: )$ - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 24.2.0 hooks: - id: black # This tells pre-commit not to pass files to black. # This should be kept in sync with pyproject.toml exclude: > (?x)^( + salt/client/ssh/ssh_py_shim\.py| templates/.*| salt/ext/.*| )$ - repo: https://github.com/asottile/blacken-docs - rev: v1.12.1 + rev: 1.16.0 hooks: - id: blacken-docs args: [--skip-errors] files: ^doc/.*\.rst additional_dependencies: - - black==22.6.0 + - black==24.2.0 # <---- Code Formatting -------------------------------------------------------------------------------------------- # ----- Security --------------------------------------------------------------------------------------------------> - repo: https://github.com/PyCQA/bandit - rev: "1.7.4" + rev: "1.7.7" hooks: - id: bandit alias: bandit-salt @@ -1713,7 +1714,7 @@ repos: )$ additional_dependencies: ['importlib_metadata<5'] - repo: https://github.com/PyCQA/bandit - rev: "1.7.4" + rev: "1.7.7" hooks: - id: bandit alias: bandit-tests @@ -1726,7 +1727,7 @@ repos: # ----- Pre-Commit ------------------------------------------------------------------------------------------------> - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.3.0 + rev: v1.8.0 hooks: - id: mypy alias: mypy-tools @@ -1746,7 +1747,7 @@ repos: - python-tools-scripts==0.20.0 - repo: https://github.com/saltstack/mirrors-nox - rev: v2021.6.12 + rev: v2022.11.21 hooks: - id: nox alias: lint-salt @@ -1766,7 +1767,7 @@ repos: - pip>=20.2.4,<21.2 - repo: https://github.com/saltstack/mirrors-nox - rev: v2021.6.12 + rev: v2022.11.21 hooks: - id: nox alias: lint-tests diff --git a/doc/ref/executors/index.rst b/doc/ref/executors/index.rst index 97379fdba3a..44df3a12918 100644 --- a/doc/ref/executors/index.rst +++ b/doc/ref/executors/index.rst @@ -59,8 +59,7 @@ the ``execute`` function with the following signature: .. code-block:: python - def execute(opts, data, func, args, kwargs): - ... + def execute(opts, data, func, args, kwargs): ... Where the args are: diff --git a/doc/ref/modules/index.rst b/doc/ref/modules/index.rst index ca9171383c5..3231368c036 100644 --- a/doc/ref/modules/index.rst +++ b/doc/ref/modules/index.rst @@ -329,6 +329,7 @@ the case when the dependency is unavailable. """ Cheese execution (or returner/beacon/etc.) module """ + try: import enzymes diff --git a/doc/topics/development/tests/index.rst b/doc/topics/development/tests/index.rst index 55e8bb18f2a..a789bab089d 100644 --- a/doc/topics/development/tests/index.rst +++ b/doc/topics/development/tests/index.rst @@ -364,8 +364,7 @@ the actual testing, such as functions containing assertions, must start with .. code-block:: python - def test_user_present(self): - ... + def test_user_present(self): ... When functions in test files are not prepended with ``test_``, the function acts as a normal, helper function and is not run as a test by the test suite. diff --git a/doc/topics/proxyminion/index.rst b/doc/topics/proxyminion/index.rst index cb4aec151a2..2d18e3607cf 100644 --- a/doc/topics/proxyminion/index.rst +++ b/doc/topics/proxyminion/index.rst @@ -581,7 +581,6 @@ and status; "package" installation, and a ping. def uptodate(name): - """ Call the REST endpoint to see if the packages on the "server" are up to date. """ @@ -592,7 +591,6 @@ and status; "package" installation, and a ping. def package_remove(name): - """ Remove a "package" on the REST server """ diff --git a/doc/topics/releases/2016.11.0.rst b/doc/topics/releases/2016.11.0.rst index 2aad664eca9..227eaa9ce93 100644 --- a/doc/topics/releases/2016.11.0.rst +++ b/doc/topics/releases/2016.11.0.rst @@ -551,15 +551,13 @@ General Deprecations .. code-block:: python - def fcn(msg="", env="base", refresh=True, saltenv="base", **kwargs): - ... + def fcn(msg="", env="base", refresh=True, saltenv="base", **kwargs): ... has been changed to .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base", **kwargs): - ... + def fcn(msg="", refresh=True, saltenv="base", **kwargs): ... - If ``env`` (or ``__env__``) is supplied as a keyword argument to a function that also accepts arbitrary keyword arguments, then a new warning informs the @@ -568,8 +566,7 @@ General Deprecations .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base", **kwargs): - ... + def fcn(msg="", refresh=True, saltenv="base", **kwargs): ... .. code-block:: python @@ -582,8 +579,7 @@ General Deprecations .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base"): - ... + def fcn(msg="", refresh=True, saltenv="base"): ... .. code-block:: python @@ -597,8 +593,7 @@ General Deprecations .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base"): - ... + def fcn(msg="", refresh=True, saltenv="base"): ... .. code-block:: python diff --git a/noxfile.py b/noxfile.py index 1a78e4628ae..05de53de6f6 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,6 +4,7 @@ noxfile Nox configuration script """ + # pylint: disable=resource-leakage,3rd-party-module-not-gated import contextlib @@ -1712,7 +1713,7 @@ class Recompress: d_targz = tempd.joinpath(targz.name) with tarfile.open(d_tar, "w|") as wfile: with tarfile.open(targz, "r:gz") as rfile: - rfile.extractall(d_src) + rfile.extractall(d_src) # nosec extracted_dir = next(pathlib.Path(d_src).iterdir()) for name in sorted(extracted_dir.rglob("*")): wfile.add( diff --git a/salt/__init__.py b/salt/__init__.py index 2553ed40e9e..409ccabb2c3 100644 --- a/salt/__init__.py +++ b/salt/__init__.py @@ -7,13 +7,6 @@ import os import sys import warnings -if sys.version_info < (3,): # pragma: no cover - sys.stderr.write( - "\n\nAfter the Sodium release, 3001, Salt no longer supports Python 2. Exiting.\n\n" - ) - sys.stderr.flush() - - USE_VENDORED_TORNADO = True diff --git a/salt/_compat.py b/salt/_compat.py index 7d20691f594..2cead97d0b2 100644 --- a/salt/_compat.py +++ b/salt/_compat.py @@ -1,6 +1,7 @@ """ Salt compatibility code """ + # pylint: disable=unused-import import sys diff --git a/salt/_logging/__init__.py b/salt/_logging/__init__.py index 43bcbac3aca..ea97b6ce9a8 100644 --- a/salt/_logging/__init__.py +++ b/salt/_logging/__init__.py @@ -9,6 +9,7 @@ The ``salt._logging`` package should be imported as soon as possible since salt tweaks the python's logging system. """ + from salt._logging.impl import ( DFLT_LOG_DATEFMT, DFLT_LOG_DATEFMT_LOGFILE, diff --git a/salt/auth/django.py b/salt/auth/django.py index a5a52063eb7..0b810b83510 100644 --- a/salt/auth/django.py +++ b/salt/auth/django.py @@ -46,7 +46,6 @@ indicated above, though the model DOES NOT have to be named 'SaltExternalAuthModel'. """ - import logging import os import sys diff --git a/salt/auth/file.py b/salt/auth/file.py index 807c9c93bba..61f73480978 100644 --- a/salt/auth/file.py +++ b/salt/auth/file.py @@ -94,7 +94,6 @@ When using ``htdigest`` the ``^realm`` must be set: """ - import logging import os diff --git a/salt/auth/keystone.py b/salt/auth/keystone.py index 5ed9f7c499f..def2e8170e5 100644 --- a/salt/auth/keystone.py +++ b/salt/auth/keystone.py @@ -4,7 +4,6 @@ Provide authentication using OpenStack Keystone :depends: - keystoneclient Python module """ - try: from keystoneclient.exceptions import AuthorizationFailure, Unauthorized from keystoneclient.v2_0 import client diff --git a/salt/auth/ldap.py b/salt/auth/ldap.py index 629bd93a3e0..604f06c3d20 100644 --- a/salt/auth/ldap.py +++ b/salt/auth/ldap.py @@ -3,6 +3,7 @@ Provide authentication using simple LDAP binds :depends: - ldap Python module """ + import itertools import logging diff --git a/salt/auth/mysql.py b/salt/auth/mysql.py index d08accb6cf4..215e7a42d2b 100644 --- a/salt/auth/mysql.py +++ b/salt/auth/mysql.py @@ -47,7 +47,6 @@ Enable MySQL authentication. :depends: - MySQL-python Python module """ - import logging log = logging.getLogger(__name__) diff --git a/salt/auth/rest.py b/salt/auth/rest.py index 42fc73da59a..d48b24797aa 100644 --- a/salt/auth/rest.py +++ b/salt/auth/rest.py @@ -22,7 +22,6 @@ structure of a user as above. """ - import logging import salt.utils.http diff --git a/salt/auth/yubico.py b/salt/auth/yubico.py index f0b37eb6c0d..7682d444194 100644 --- a/salt/auth/yubico.py +++ b/salt/auth/yubico.py @@ -36,7 +36,6 @@ the API key will be updated on all the YubiCloud servers. """ - import logging log = logging.getLogger(__name__) diff --git a/salt/beacons/adb.py b/salt/beacons/adb.py index cea98eafdae..e5ebba1771c 100644 --- a/salt/beacons/adb.py +++ b/salt/beacons/adb.py @@ -3,6 +3,7 @@ Beacon to emit adb device state changes for Android devices .. versionadded:: 2016.3.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/aix_account.py b/salt/beacons/aix_account.py index 8a9e0469bd0..07aad263846 100644 --- a/salt/beacons/aix_account.py +++ b/salt/beacons/aix_account.py @@ -5,6 +5,7 @@ Beacon to fire event when we notice a AIX user is locked due to many failed logi :depends: none """ + import logging log = logging.getLogger(__name__) diff --git a/salt/beacons/bonjour_announce.py b/salt/beacons/bonjour_announce.py index edbd135e751..c129128f849 100644 --- a/salt/beacons/bonjour_announce.py +++ b/salt/beacons/bonjour_announce.py @@ -1,6 +1,7 @@ """ Beacon to announce via Bonjour (zeroconf) """ + import atexit import logging import select diff --git a/salt/beacons/cert_info.py b/salt/beacons/cert_info.py index b9b59902063..298d56317bd 100644 --- a/salt/beacons/cert_info.py +++ b/salt/beacons/cert_info.py @@ -7,6 +7,7 @@ Beacon to monitor certificate expiration dates from files on the filesystem. :maturity: new :depends: OpenSSL """ + import logging from datetime import datetime diff --git a/salt/beacons/diskusage.py b/salt/beacons/diskusage.py index 5be33ff975e..eab69786902 100644 --- a/salt/beacons/diskusage.py +++ b/salt/beacons/diskusage.py @@ -5,6 +5,7 @@ Beacon to monitor disk usage. :depends: python-psutil """ + import logging import re diff --git a/salt/beacons/glxinfo.py b/salt/beacons/glxinfo.py index 20c4d4b9b01..a4aa4013804 100644 --- a/salt/beacons/glxinfo.py +++ b/salt/beacons/glxinfo.py @@ -3,6 +3,7 @@ Beacon to emit when a display is available to a linux machine .. versionadded:: 2016.3.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/haproxy.py b/salt/beacons/haproxy.py index e19ec34abd2..a3aa13de597 100644 --- a/salt/beacons/haproxy.py +++ b/salt/beacons/haproxy.py @@ -4,6 +4,7 @@ Fire an event when over a specified threshold. .. versionadded:: 2016.11.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/journald.py b/salt/beacons/journald.py index f2c46c02e7d..19618a59938 100644 --- a/salt/beacons/journald.py +++ b/salt/beacons/journald.py @@ -1,6 +1,7 @@ """ A simple beacon to watch journald for specific entries """ + import logging import salt.utils.beacons diff --git a/salt/beacons/load.py b/salt/beacons/load.py index 56bc5b0cfa0..90b76201f8e 100644 --- a/salt/beacons/load.py +++ b/salt/beacons/load.py @@ -1,6 +1,7 @@ """ Beacon to emit system load averages """ + import logging import os diff --git a/salt/beacons/log_beacon.py b/salt/beacons/log_beacon.py index 6e5621f53a7..52227cd09cb 100644 --- a/salt/beacons/log_beacon.py +++ b/salt/beacons/log_beacon.py @@ -4,6 +4,7 @@ Beacon to fire events at specific log messages. .. versionadded:: 2017.7.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/memusage.py b/salt/beacons/memusage.py index a80423a398e..029fb8efbeb 100644 --- a/salt/beacons/memusage.py +++ b/salt/beacons/memusage.py @@ -5,6 +5,7 @@ Beacon to monitor memory usage. :depends: python-psutil """ + import logging import re diff --git a/salt/beacons/network_info.py b/salt/beacons/network_info.py index c8a28b4d700..8d2c94176ea 100644 --- a/salt/beacons/network_info.py +++ b/salt/beacons/network_info.py @@ -3,6 +3,7 @@ Beacon to monitor statistics from ethernet adapters .. versionadded:: 2015.5.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/pkg.py b/salt/beacons/pkg.py index 2613f41a61f..2a7c5e19eec 100644 --- a/salt/beacons/pkg.py +++ b/salt/beacons/pkg.py @@ -3,6 +3,7 @@ Watch for pkgs that have upgrades, then fire an event. .. versionadded:: 2016.3.0 """ + import logging __virtualname__ = "pkg" diff --git a/salt/beacons/proxy_example.py b/salt/beacons/proxy_example.py index 1c804d05284..960e23fa709 100644 --- a/salt/beacons/proxy_example.py +++ b/salt/beacons/proxy_example.py @@ -7,6 +7,7 @@ Example beacon to use with salt-proxy proxy_example: endpoint: beacon """ + import logging import salt.utils.beacons diff --git a/salt/beacons/ps.py b/salt/beacons/ps.py index 6c19d8f8640..090a06b1235 100644 --- a/salt/beacons/ps.py +++ b/salt/beacons/ps.py @@ -1,6 +1,7 @@ """ Send events covering process status """ + import logging import salt.utils.beacons diff --git a/salt/beacons/salt_monitor.py b/salt/beacons/salt_monitor.py index 1776d0ce896..d389976ae2a 100644 --- a/salt/beacons/salt_monitor.py +++ b/salt/beacons/salt_monitor.py @@ -24,6 +24,7 @@ See example config below. - test.ping - interval: 3600 # seconds """ + import salt.utils.beacons diff --git a/salt/beacons/salt_proxy.py b/salt/beacons/salt_proxy.py index dea7ce42057..1eebc4103b9 100644 --- a/salt/beacons/salt_proxy.py +++ b/salt/beacons/salt_proxy.py @@ -4,6 +4,7 @@ .. versionadded:: 2015.8.3 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/sensehat.py b/salt/beacons/sensehat.py index 8f1d1393350..6e3c29f4d36 100644 --- a/salt/beacons/sensehat.py +++ b/salt/beacons/sensehat.py @@ -8,6 +8,7 @@ Monitor temperature, humidity and pressure using the SenseHat of a Raspberry Pi :maturity: new :depends: sense_hat Python module """ + import logging import re diff --git a/salt/beacons/service.py b/salt/beacons/service.py index b27f75273af..6f7519e8f95 100644 --- a/salt/beacons/service.py +++ b/salt/beacons/service.py @@ -1,6 +1,7 @@ """ Send events covering service status """ + import logging import os import time diff --git a/salt/beacons/sh.py b/salt/beacons/sh.py index 29c2a2a206a..8141b5a1a95 100644 --- a/salt/beacons/sh.py +++ b/salt/beacons/sh.py @@ -1,6 +1,7 @@ """ Watch the shell commands being executed actively. This beacon requires strace. """ + import logging import time diff --git a/salt/beacons/smartos_imgadm.py b/salt/beacons/smartos_imgadm.py index 2432a54e79f..f1e3e83df3b 100644 --- a/salt/beacons/smartos_imgadm.py +++ b/salt/beacons/smartos_imgadm.py @@ -17,6 +17,7 @@ Beacon that fires events on image import/delete. - interval: 60 - startup_import_event: True """ + import logging import salt.utils.beacons diff --git a/salt/beacons/smartos_vmadm.py b/salt/beacons/smartos_vmadm.py index fd48253785b..1dae2430b1b 100644 --- a/salt/beacons/smartos_vmadm.py +++ b/salt/beacons/smartos_vmadm.py @@ -17,6 +17,7 @@ Beacon that fires events on vm state changes - interval: 60 - startup_create_event: True """ + import logging import salt.utils.beacons diff --git a/salt/beacons/status.py b/salt/beacons/status.py index aa5aa13b478..9492d339691 100644 --- a/salt/beacons/status.py +++ b/salt/beacons/status.py @@ -87,6 +87,7 @@ markers for specific list items: to check the minion log for errors after configuring this beacon. """ + import datetime import logging @@ -165,8 +166,8 @@ def beacon(config): except TypeError: ret[func][item] = data[int(item)] except KeyError as exc: - ret[ - func - ] = "Status beacon is incorrectly configured: {}".format(exc) + ret[func] = ( + "Status beacon is incorrectly configured: {}".format(exc) + ) return [{"tag": ctime, "data": ret}] diff --git a/salt/beacons/swapusage.py b/salt/beacons/swapusage.py index 0cbdec07ea4..1bb9a572a3d 100644 --- a/salt/beacons/swapusage.py +++ b/salt/beacons/swapusage.py @@ -5,6 +5,7 @@ Beacon to monitor swap usage. :depends: python-psutil """ + import logging import re diff --git a/salt/beacons/telegram_bot_msg.py b/salt/beacons/telegram_bot_msg.py index e11c869947f..76e0e2a6c34 100644 --- a/salt/beacons/telegram_bot_msg.py +++ b/salt/beacons/telegram_bot_msg.py @@ -4,6 +4,7 @@ Beacon to emit Telegram messages Requires the python-telegram-bot library """ + import logging import salt.utils.beacons diff --git a/salt/beacons/twilio_txt_msg.py b/salt/beacons/twilio_txt_msg.py index 7ff5a361fb6..742342ef9f9 100644 --- a/salt/beacons/twilio_txt_msg.py +++ b/salt/beacons/twilio_txt_msg.py @@ -1,6 +1,7 @@ """ Beacon to emit Twilio text messages """ + import logging import salt.utils.beacons diff --git a/salt/cache/__init__.py b/salt/cache/__init__.py index 2b13a364235..71fafc6d286 100644 --- a/salt/cache/__init__.py +++ b/salt/cache/__init__.py @@ -4,7 +4,6 @@ Loader mechanism for caching data, with data expiration, etc. .. versionadded:: 2016.11.0 """ - import logging import time diff --git a/salt/cache/redis_cache.py b/salt/cache/redis_cache.py index 6579303fef8..754bba71f0a 100644 --- a/salt/cache/redis_cache.py +++ b/salt/cache/redis_cache.py @@ -151,7 +151,6 @@ Cluster Configuration Example: cache.redis.separator: '@' """ - import itertools import logging import time diff --git a/salt/channel/client.py b/salt/channel/client.py index 8d43406728e..0360af34658 100644 --- a/salt/channel/client.py +++ b/salt/channel/client.py @@ -4,7 +4,6 @@ Encapsulate the different transports available to Salt. This includes client side transport, for the ReqServer and the Publisher """ - import logging import os import time diff --git a/salt/cli/api.py b/salt/cli/api.py index a54595578c4..3e46676e1ef 100644 --- a/salt/cli/api.py +++ b/salt/cli/api.py @@ -6,7 +6,6 @@ """ - import logging import salt.client.netapi diff --git a/salt/cli/caller.py b/salt/cli/caller.py index fd12b4e0ae3..ce2b8edfd4e 100644 --- a/salt/cli/caller.py +++ b/salt/cli/caller.py @@ -235,7 +235,7 @@ class BaseCaller: retcode = salt.defaults.exitcodes.EX_GENERIC ret["retcode"] = retcode - except (CommandExecutionError) as exc: + except CommandExecutionError as exc: msg = "Error running '{0}': {1}\n" active_level = LOG_LEVELS.get(self.opts["log_level"].lower(), logging.ERROR) if active_level <= logging.DEBUG: diff --git a/salt/cli/daemons.py b/salt/cli/daemons.py index ecc05c919ef..7578e8e64c3 100644 --- a/salt/cli/daemons.py +++ b/salt/cli/daemons.py @@ -2,7 +2,6 @@ Make me some salt! """ - import logging import os import warnings diff --git a/salt/cli/spm.py b/salt/cli/spm.py index 9098e0d78e6..a4c97da5570 100644 --- a/salt/cli/spm.py +++ b/salt/cli/spm.py @@ -7,7 +7,6 @@ .. versionadded:: 2015.8.0 """ - import salt.spm import salt.utils.parsers as parsers from salt.utils.verify import verify_env diff --git a/salt/client/mixins.py b/salt/client/mixins.py index c6b479e106b..6e05e86d342 100644 --- a/salt/client/mixins.py +++ b/salt/client/mixins.py @@ -387,10 +387,10 @@ class SyncClientMixin(ClientStateMixin): try: data["return"] = func(*args, **kwargs) except TypeError as exc: - data[ - "return" - ] = "\nPassed invalid arguments: {}\n\nUsage:\n{}".format( - exc, func.__doc__ + data["return"] = ( + "\nPassed invalid arguments: {}\n\nUsage:\n{}".format( + exc, func.__doc__ + ) ) try: data["success"] = self.context.get("retcode", 0) == 0 diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py index a5f681569d1..80936a06112 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -745,9 +745,9 @@ class SSH(MultiprocessingStateMixin): data["id"] = id_ if "fun" not in data: data["fun"] = fun - data[ - "jid" - ] = jid # make the jid in the payload the same as the jid in the tag + data["jid"] = ( + jid # make the jid in the payload the same as the jid in the tag + ) self.event.fire_event( data, salt.utils.event.tagify([jid, "ret", host], "job") ) @@ -862,9 +862,9 @@ class SSH(MultiprocessingStateMixin): data["id"] = id_ if "fun" not in data: data["fun"] = fun - data[ - "jid" - ] = jid # make the jid in the payload the same as the jid in the tag + data["jid"] = ( + jid # make the jid in the payload the same as the jid in the tag + ) self.event.fire_event( data, salt.utils.event.tagify([jid, "ret", host], "job") ) diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py index f0b697d0ac4..679fb52cbbb 100644 --- a/salt/client/ssh/ssh_py_shim.py +++ b/salt/client/ssh/ssh_py_shim.py @@ -169,7 +169,7 @@ def unpack_thin(thin_path): """ tfile = tarfile.TarFile.gzopen(thin_path) old_umask = os.umask(0o077) # pylint: disable=blacklisted-function - tfile.extractall(path=OPTIONS.saltdir) + tfile.extractall(path=OPTIONS.saltdir) # nosec tfile.close() os.umask(old_umask) # pylint: disable=blacklisted-function try: @@ -196,7 +196,7 @@ def unpack_ext(ext_path): ) tfile = tarfile.TarFile.gzopen(ext_path) old_umask = os.umask(0o077) # pylint: disable=blacklisted-function - tfile.extractall(path=modcache) + tfile.extractall(path=modcache) # nosec tfile.close() os.umask(old_umask) # pylint: disable=blacklisted-function os.unlink(ext_path) diff --git a/salt/client/ssh/wrapper/__init__.py b/salt/client/ssh/wrapper/__init__.py index 42bdc624f21..deac7a465ef 100644 --- a/salt/client/ssh/wrapper/__init__.py +++ b/salt/client/ssh/wrapper/__init__.py @@ -5,7 +5,6 @@ to be easily rewritten to execute in a way that makes them do the same tasks as ZeroMQ salt, but via ssh. """ - import copy import salt.client.ssh diff --git a/salt/client/ssh/wrapper/grains.py b/salt/client/ssh/wrapper/grains.py index 92446f4018e..400131e1517 100644 --- a/salt/client/ssh/wrapper/grains.py +++ b/salt/client/ssh/wrapper/grains.py @@ -2,7 +2,6 @@ Return/control aspects of the grains data """ - import math import salt.utils.data diff --git a/salt/client/ssh/wrapper/mine.py b/salt/client/ssh/wrapper/mine.py index 1817058eea8..d22d0926ca1 100644 --- a/salt/client/ssh/wrapper/mine.py +++ b/salt/client/ssh/wrapper/mine.py @@ -4,7 +4,6 @@ Wrapper function for mine operations for salt-ssh .. versionadded:: 2015.5.0 """ - import copy import salt.client.ssh diff --git a/salt/cloud/__init__.py b/salt/cloud/__init__.py index a4d11eed59a..2e1d1d4efa0 100644 --- a/salt/cloud/__init__.py +++ b/salt/cloud/__init__.py @@ -2,6 +2,7 @@ The top level interface used to translate configuration data back to the correct cloud modules """ + import copy import glob import logging diff --git a/salt/cloud/cli.py b/salt/cloud/cli.py index c633dce3b77..19b26e42287 100644 --- a/salt/cloud/cli.py +++ b/salt/cloud/cli.py @@ -1,6 +1,7 @@ """ Primary interfaces for the salt-cloud system """ + # Need to get data from 4 sources! # CLI options # salt cloud config - CONFIG_DIR + '/cloud' diff --git a/salt/cloud/clouds/aliyun.py b/salt/cloud/clouds/aliyun.py index 572f0cfde96..30a3cf593a8 100644 --- a/salt/cloud/clouds/aliyun.py +++ b/salt/cloud/clouds/aliyun.py @@ -575,7 +575,7 @@ def create_node(kwargs): "HostName", "Password", "SystemDisk.Category", - "VSwitchId" + "VSwitchId", # 'DataDisk.n.Size', 'DataDisk.n.Category', 'DataDisk.n.SnapshotId' ] diff --git a/salt/cloud/clouds/cloudstack.py b/salt/cloud/clouds/cloudstack.py index ef50aaf3bf0..ebf301e4ebf 100644 --- a/salt/cloud/clouds/cloudstack.py +++ b/salt/cloud/clouds/cloudstack.py @@ -20,6 +20,7 @@ Use of this module requires the ``apikey``, ``secretkey``, ``host`` and driver: cloudstack """ + # pylint: disable=function-redefined import logging diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 571b0c04674..9cba9cd52b3 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -1197,6 +1197,7 @@ def get_imageid(vm_): "Filter.0.Name": "name", "Filter.0.Value.0": image, } + # Query AWS, sort by 'creationDate' and get the last imageId def _t(x): return datetime.datetime.strptime(x["creationDate"], "%Y-%m-%dT%H:%M:%S.%fZ") diff --git a/salt/cloud/clouds/gce.py b/salt/cloud/clouds/gce.py index 4c14f4e74d8..8e2d8618476 100644 --- a/salt/cloud/clouds/gce.py +++ b/salt/cloud/clouds/gce.py @@ -43,6 +43,7 @@ Example Provider Configuration :maintainer: Russell Tolle :depends: libcloud >= 1.0.0 """ + # pylint: disable=function-redefined import logging @@ -1698,7 +1699,6 @@ def delete_disk(kwargs=None, call=None): def create_disk(kwargs=None, call=None): - """ Create a new persistent disk. Must specify `disk_name` and `location`, and optionally can specify 'disk_type' as pd-standard or pd-ssd, which diff --git a/salt/cloud/clouds/hetzner.py b/salt/cloud/clouds/hetzner.py index e666769ee6a..48bf8610c18 100644 --- a/salt/cloud/clouds/hetzner.py +++ b/salt/cloud/clouds/hetzner.py @@ -16,6 +16,7 @@ Use of this module requires the ``key`` parameter to be set. driver: hetzner """ + # pylint: disable=invalid-name,function-redefined diff --git a/salt/cloud/clouds/joyent.py b/salt/cloud/clouds/joyent.py index cd68508f43a..0da4a4a5e64 100644 --- a/salt/cloud/clouds/joyent.py +++ b/salt/cloud/clouds/joyent.py @@ -532,7 +532,6 @@ def take_action( method="GET", location=DEFAULT_LOCATION, ): - """ take action call used by start,stop, reboot :param name: name given to the machine diff --git a/salt/cloud/clouds/libvirt.py b/salt/cloud/clouds/libvirt.py index 76f6f6daa26..59affa6b94b 100644 --- a/salt/cloud/clouds/libvirt.py +++ b/salt/cloud/clouds/libvirt.py @@ -258,7 +258,7 @@ def get_domain_ips(domain, ip_source): log.info("Exception polling address %s", error) return ips - for (name, val) in addresses.items(): + for name, val in addresses.items(): if val["addrs"]: for addr in val["addrs"]: tp = to_ip_addr_type(addr["type"]) diff --git a/salt/cloud/clouds/msazure.py b/salt/cloud/clouds/msazure.py index 8d5b74e701c..fef62f07a70 100644 --- a/salt/cloud/clouds/msazure.py +++ b/salt/cloud/clouds/msazure.py @@ -42,6 +42,7 @@ Example ``/etc/salt/cloud.providers`` or certificate_path: /etc/salt/azure.pem management_host: management.core.windows.net """ + # pylint: disable=function-redefined import copy diff --git a/salt/cloud/clouds/opennebula.py b/salt/cloud/clouds/opennebula.py index 02602ca1e17..71f9372a594 100644 --- a/salt/cloud/clouds/opennebula.py +++ b/salt/cloud/clouds/opennebula.py @@ -76,7 +76,7 @@ from salt.exceptions import ( ) try: - import xmlrpc.client + import xmlrpc.client # nosec from lxml import etree diff --git a/salt/cloud/clouds/saltify.py b/salt/cloud/clouds/saltify.py index 89082ddbef5..451478a5552 100644 --- a/salt/cloud/clouds/saltify.py +++ b/salt/cloud/clouds/saltify.py @@ -358,7 +358,7 @@ def _verify(vm_): log.debug("Testing SMB protocol for %s", vm_["name"]) if __utils__["smb.get_conn"](**kwargs) is False: return False - except (smbSessionError) as exc: + except smbSessionError as exc: log.error("Exception: %s", exc) return False diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index 72dcac96c20..f6d8cbcef6c 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -1454,15 +1454,21 @@ def _format_instance_info_select(vm, selection): if "storage" in selection: storage_full_info = { - "committed": int(vm["summary.storage.committed"]) - if "summary.storage.committed" in vm - else "N/A", - "uncommitted": int(vm["summary.storage.uncommitted"]) - if "summary.storage.uncommitted" in vm - else "N/A", - "unshared": int(vm["summary.storage.unshared"]) - if "summary.storage.unshared" in vm - else "N/A", + "committed": ( + int(vm["summary.storage.committed"]) + if "summary.storage.committed" in vm + else "N/A" + ), + "uncommitted": ( + int(vm["summary.storage.uncommitted"]) + if "summary.storage.uncommitted" in vm + else "N/A" + ), + "unshared": ( + int(vm["summary.storage.unshared"]) + if "summary.storage.unshared" in vm + else "N/A" + ), } vm_select_info["storage"] = storage_full_info @@ -1553,15 +1559,21 @@ def _format_instance_info(vm): ] = device.backing.fileName storage_full_info = { - "committed": int(vm["summary.storage.committed"]) - if "summary.storage.committed" in vm - else "N/A", - "uncommitted": int(vm["summary.storage.uncommitted"]) - if "summary.storage.uncommitted" in vm - else "N/A", - "unshared": int(vm["summary.storage.unshared"]) - if "summary.storage.unshared" in vm - else "N/A", + "committed": ( + int(vm["summary.storage.committed"]) + if "summary.storage.committed" in vm + else "N/A" + ), + "uncommitted": ( + int(vm["summary.storage.uncommitted"]) + if "summary.storage.uncommitted" in vm + else "N/A" + ), + "unshared": ( + int(vm["summary.storage.unshared"]) + if "summary.storage.unshared" in vm + else "N/A" + ), } file_full_info = {} @@ -1593,14 +1605,18 @@ def _format_instance_info(vm): ) vm_full_info = { "id": str(vm["name"]), - "image": "{} (Detected)".format(vm["config.guestFullName"]) - if "config.guestFullName" in vm - else "N/A", + "image": ( + "{} (Detected)".format(vm["config.guestFullName"]) + if "config.guestFullName" in vm + else "N/A" + ), "size": "cpu: {}\nram: {}".format(cpu, ram), "size_dict": {"cpu": cpu, "memory": ram}, - "state": str(vm["summary.runtime.powerState"]) - if "summary.runtime.powerState" in vm - else "N/A", + "state": ( + str(vm["summary.runtime.powerState"]) + if "summary.runtime.powerState" in vm + else "N/A" + ), "private_ips": ip_addresses, "public_ips": [], "devices": device_full_info, @@ -1610,12 +1626,14 @@ def _format_instance_info(vm): "hostname": str(vm["object"].guest.hostName), "mac_addresses": device_mac_addresses, "networks": network_full_info, - "path": str(vm["config.files.vmPathName"]) - if "config.files.vmPathName" in vm - else "N/A", - "tools_status": str(vm["guest.toolsStatus"]) - if "guest.toolsStatus" in vm - else "N/A", + "path": ( + str(vm["config.files.vmPathName"]) + if "config.files.vmPathName" in vm + else "N/A" + ), + "tools_status": ( + str(vm["guest.toolsStatus"]) if "guest.toolsStatus" in vm else "N/A" + ), } return vm_full_info @@ -2004,14 +2022,18 @@ def list_nodes(kwargs=None, call=None): ) vm_info = { "id": vm["name"], - "image": "{} (Detected)".format(vm["config.guestFullName"]) - if "config.guestFullName" in vm - else "N/A", + "image": ( + "{} (Detected)".format(vm["config.guestFullName"]) + if "config.guestFullName" in vm + else "N/A" + ), "size": "cpu: {}\nram: {}".format(cpu, ram), "size_dict": {"cpu": cpu, "memory": ram}, - "state": str(vm["summary.runtime.powerState"]) - if "summary.runtime.powerState" in vm - else "N/A", + "state": ( + str(vm["summary.runtime.powerState"]) + if "summary.runtime.powerState" in vm + else "N/A" + ), "private_ips": [vm["guest.ipAddress"]] if "guest.ipAddress" in vm else [], "public_ips": [], } @@ -2242,15 +2264,21 @@ def avail_images(call=None): if "config.template" in vm and vm["config.template"]: templates[vm["name"]] = { "name": vm["name"], - "guest_fullname": vm["config.guestFullName"] - if "config.guestFullName" in vm - else "N/A", - "cpus": vm["config.hardware.numCPU"] - if "config.hardware.numCPU" in vm - else "N/A", - "ram": vm["config.hardware.memoryMB"] - if "config.hardware.memoryMB" in vm - else "N/A", + "guest_fullname": ( + vm["config.guestFullName"] + if "config.guestFullName" in vm + else "N/A" + ), + "cpus": ( + vm["config.hardware.numCPU"] + if "config.hardware.numCPU" in vm + else "N/A" + ), + "ram": ( + vm["config.hardware.memoryMB"] + if "config.hardware.memoryMB" in vm + else "N/A" + ), } return templates diff --git a/salt/config/__init__.py b/salt/config/__init__.py index 4690c9f61d5..d94a690e8b9 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -1,6 +1,7 @@ """ All salt configuration loading and defaults should be in this module """ + import codecs import glob import logging diff --git a/salt/config/schemas/common.py b/salt/config/schemas/common.py index 9105ed39266..df136d537ea 100644 --- a/salt/config/schemas/common.py +++ b/salt/config/schemas/common.py @@ -8,7 +8,6 @@ Common salt configuration schemas """ - from salt.utils.schema import ArrayItem, OneOfItem, Schema, StringItem diff --git a/salt/config/schemas/esxcluster.py b/salt/config/schemas/esxcluster.py index 2522a4bf4e1..cc3f30da6e5 100644 --- a/salt/config/schemas/esxcluster.py +++ b/salt/config/schemas/esxcluster.py @@ -8,7 +8,6 @@ ESX Cluster configuration schemas """ - from salt.utils.schema import ( AnyOfItem, ArrayItem, diff --git a/salt/config/schemas/esxdatacenter.py b/salt/config/schemas/esxdatacenter.py index 2bb4ec0b29f..edf8b404cd4 100644 --- a/salt/config/schemas/esxdatacenter.py +++ b/salt/config/schemas/esxdatacenter.py @@ -8,7 +8,6 @@ ESX Datacenter configuration schemas """ - from salt.utils.schema import ArrayItem, IntegerItem, Schema, StringItem diff --git a/salt/config/schemas/esxi.py b/salt/config/schemas/esxi.py index 1bb03b44c34..822f382b098 100644 --- a/salt/config/schemas/esxi.py +++ b/salt/config/schemas/esxi.py @@ -8,7 +8,6 @@ ESXi host configuration schemas """ - from salt.utils.schema import ( ArrayItem, BooleanItem, diff --git a/salt/config/schemas/esxvm.py b/salt/config/schemas/esxvm.py index 5842cb0be5c..2dfdbb26ac5 100644 --- a/salt/config/schemas/esxvm.py +++ b/salt/config/schemas/esxvm.py @@ -7,7 +7,6 @@ ESX Virtual Machine configuration schemas """ - from salt.utils.schema import ( AnyOfItem, ArrayItem, diff --git a/salt/config/schemas/minion.py b/salt/config/schemas/minion.py index 9aee9fe4c0f..22fe2fdeb7f 100644 --- a/salt/config/schemas/minion.py +++ b/salt/config/schemas/minion.py @@ -7,7 +7,6 @@ Minion configuration schema """ - from salt.config.schemas.common import IncludeConfig, MinionDefaultInclude from salt.utils.schema import IPv4Item, Schema diff --git a/salt/config/schemas/ssh.py b/salt/config/schemas/ssh.py index 2db9acda5de..2123768935c 100644 --- a/salt/config/schemas/ssh.py +++ b/salt/config/schemas/ssh.py @@ -8,7 +8,6 @@ Salt SSH related configuration schemas """ - from salt.config.schemas.minion import MinionConfiguration from salt.utils.schema import ( AnyOfItem, diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index 3716c63d993..020bfb03198 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -132,7 +132,7 @@ def clean_pub_auth(opts): if not os.path.exists(auth_cache): return else: - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk(auth_cache): + for dirpath, dirnames, filenames in salt.utils.path.os_walk(auth_cache): for auth_file in filenames: auth_file_path = os.path.join(dirpath, auth_file) if not os.path.isfile(auth_file_path): @@ -724,7 +724,7 @@ class RemoteFuncs: if not os.path.isdir(cdir): try: os.makedirs(cdir) - except os.error: + except OSError: pass if os.path.isfile(cpath) and load["loc"] != 0: mode = "ab" diff --git a/salt/engines/__init__.py b/salt/engines/__init__.py index edd4a178225..d7dc6befa90 100644 --- a/salt/engines/__init__.py +++ b/salt/engines/__init__.py @@ -2,6 +2,7 @@ Initialize the engines system. This plugin system allows for complex services to be encapsulated within the salt plugin environment """ + import logging import salt diff --git a/salt/engines/docker_events.py b/salt/engines/docker_events.py index 66b95c46b0b..d5b798484cb 100644 --- a/salt/engines/docker_events.py +++ b/salt/engines/docker_events.py @@ -2,6 +2,7 @@ Send events from Docker events :Depends: Docker API >= 1.22 """ + import logging import traceback diff --git a/salt/engines/slack.py b/salt/engines/slack.py index b6c868c0dbb..93f75f8cd4e 100644 --- a/salt/engines/slack.py +++ b/salt/engines/slack.py @@ -800,9 +800,9 @@ class SlackClient: channel = self.sc.server.channels.find(msg["channel"]) jid = self.run_command_async(msg) log.debug("Submitted a job and got jid: %s", jid) - outstanding[ - jid - ] = msg # record so we can return messages to the caller + outstanding[jid] = ( + msg # record so we can return messages to the caller + ) channel.send_message( "@{}'s job is submitted as salt jid {}".format( msg["user_name"], jid @@ -855,7 +855,6 @@ class SlackClient: del outstanding[jid] def run_command_async(self, msg): - """ :type message_generator: generator of dict :param message_generator: Generates messages from slack that should be run diff --git a/salt/engines/slack_bolt_engine.py b/salt/engines/slack_bolt_engine.py index ca4f1791371..7cd82ff877f 100644 --- a/salt/engines/slack_bolt_engine.py +++ b/salt/engines/slack_bolt_engine.py @@ -913,9 +913,9 @@ class SlackClient: if control and (len(msg) > 1) and msg.get("cmdline"): jid = self.run_command_async(msg) log.debug("Submitted a job and got jid: %s", jid) - outstanding[ - jid - ] = msg # record so we can return messages to the caller + outstanding[jid] = ( + msg # record so we can return messages to the caller + ) text_msg = "@{}'s job is submitted as salt jid {}".format( msg["user_name"], jid ) @@ -969,7 +969,6 @@ class SlackClient: del outstanding[jid] def run_command_async(self, msg): - """ :type msg: dict :param msg: The message dictionary that contains the command and all information. diff --git a/salt/features.py b/salt/features.py index 4335c46ca5a..51761c24fcb 100644 --- a/salt/features.py +++ b/salt/features.py @@ -1,6 +1,7 @@ """ Feature flags """ + import logging log = logging.getLogger(__name__) diff --git a/salt/fileclient.py b/salt/fileclient.py index 5929c1dbdc2..77e107830dd 100644 --- a/salt/fileclient.py +++ b/salt/fileclient.py @@ -1,6 +1,7 @@ """ Classes that manage file clients """ + import contextlib import errno import ftplib # nosec diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py index 4eca98d14a4..f6a1c6cdc8b 100644 --- a/salt/fileserver/__init__.py +++ b/salt/fileserver/__init__.py @@ -2,7 +2,6 @@ File server pluggable modules and generic backend functions """ - import errno import fnmatch import logging diff --git a/salt/fileserver/azurefs.py b/salt/fileserver/azurefs.py index cdb1a390d7a..7e92a229cd9 100644 --- a/salt/fileserver/azurefs.py +++ b/salt/fileserver/azurefs.py @@ -45,7 +45,6 @@ permissions. Do not include the leading ? for sas_token if generated from the web """ - import base64 import logging import os diff --git a/salt/fileserver/gitfs.py b/salt/fileserver/gitfs.py index 968e2c9ebfe..3f947d2384c 100644 --- a/salt/fileserver/gitfs.py +++ b/salt/fileserver/gitfs.py @@ -47,7 +47,6 @@ Walkthrough `. .. _GitPython: https://github.com/gitpython-developers/GitPython """ - import logging import salt.utils.gitfs diff --git a/salt/fileserver/hgfs.py b/salt/fileserver/hgfs.py index a7f548ac6a9..c2c9f93ac5c 100644 --- a/salt/fileserver/hgfs.py +++ b/salt/fileserver/hgfs.py @@ -860,7 +860,7 @@ def _file_lists(load, form): if not os.path.isdir(list_cachedir): try: os.makedirs(list_cachedir) - except os.error: + except OSError: log.critical("Unable to make cachedir %s", list_cachedir) return [] list_cache = os.path.join(list_cachedir, "{}.p".format(load["saltenv"])) diff --git a/salt/fileserver/minionfs.py b/salt/fileserver/minionfs.py index 02b1b59eeab..0cc77994fc2 100644 --- a/salt/fileserver/minionfs.py +++ b/salt/fileserver/minionfs.py @@ -150,7 +150,7 @@ def update(): salt.fileserver.reap_fileserver_cache_dir( os.path.join(__opts__["cachedir"], "minionfs/hash"), find_file ) - except os.error: + except OSError: # Hash file won't exist if no files have yet been served up pass @@ -204,7 +204,7 @@ def file_hash(load, fnd): ret["hsum"] = hsum return ret # Can't use Python select() because we need Windows support - except os.error: + except OSError: log.debug("Fileserver encountered lock when reading cache file. Retrying.") file_hash(load, fnd) return ret diff --git a/salt/fileserver/roots.py b/salt/fileserver/roots.py index 4ffdb6df6ff..c79da1a616b 100644 --- a/salt/fileserver/roots.py +++ b/salt/fileserver/roots.py @@ -291,10 +291,7 @@ def file_hash(load, fnd): # check if mtime changed ret["hsum"] = hsum return ret - except ( - os.error, - OSError, - ): # Can't use Python select() because we need Windows support + except OSError: # Can't use Python select() because we need Windows support log.debug("Fileserver encountered lock when reading cache file. Retrying.") # Delete the file since its incomplete (either corrupted or incomplete) try: diff --git a/salt/fileserver/s3fs.py b/salt/fileserver/s3fs.py index f946eb2019b..01f527b1984 100644 --- a/salt/fileserver/s3fs.py +++ b/salt/fileserver/s3fs.py @@ -87,7 +87,6 @@ structure:: s3.s3_sync_on_update: False """ - import datetime import logging import os diff --git a/salt/fileserver/svnfs.py b/salt/fileserver/svnfs.py index 48843f22e67..b8582ff716c 100644 --- a/salt/fileserver/svnfs.py +++ b/salt/fileserver/svnfs.py @@ -30,7 +30,6 @@ This backend assumes a standard svn layout with directories for ``branches``, :conf_master:`documentation ` for more information. """ - import copy import errno import fnmatch @@ -721,7 +720,7 @@ def _file_lists(load, form): if not os.path.isdir(list_cachedir): try: os.makedirs(list_cachedir) - except os.error: + except OSError: log.critical("Unable to make cachedir %s", list_cachedir) return [] list_cache = os.path.join(list_cachedir, "{}.p".format(load["saltenv"])) diff --git a/salt/grains/cimc.py b/salt/grains/cimc.py index 72b89d931bb..30032159294 100644 --- a/salt/grains/cimc.py +++ b/salt/grains/cimc.py @@ -3,7 +3,6 @@ Generate baseline proxy minion grains for cimc hosts. """ - import logging import salt.proxy.cimc diff --git a/salt/grains/core.py b/salt/grains/core.py index 2edbcde420b..8dbcec294a5 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -2389,10 +2389,10 @@ def _legacy_linux_distribution_data(grains, os_release, lsb_has_error): "Please report this, as it is likely a bug." ) else: - grains[ - "osrelease" - ] = "{majorversion}.{minorversion}-{buildnumber}".format( - **synoinfo + grains["osrelease"] = ( + "{majorversion}.{minorversion}-{buildnumber}".format( + **synoinfo + ) ) log.trace( @@ -2880,14 +2880,16 @@ def fqdns(): opt = {"fqdns": []} if __opts__.get( "enable_fqdns_grains", - False - if salt.utils.platform.is_windows() - or salt.utils.platform.is_proxy() - or salt.utils.platform.is_sunos() - or salt.utils.platform.is_aix() - or salt.utils.platform.is_junos() - or salt.utils.platform.is_darwin() - else True, + ( + False + if salt.utils.platform.is_windows() + or salt.utils.platform.is_proxy() + or salt.utils.platform.is_sunos() + or salt.utils.platform.is_aix() + or salt.utils.platform.is_junos() + or salt.utils.platform.is_darwin() + else True + ), ): opt = __salt__["network.fqdns"]() return opt @@ -3318,7 +3320,7 @@ def _hw_data(osdata): # of information. With that said, consolidate the output from various # commands and attempt various lookups. data = "" - for (cmd, args) in ( + for cmd, args in ( ("/usr/sbin/prtdiag", "-v"), ("/usr/sbin/prtconf", "-vp"), ("/usr/sbin/virtinfo", "-a"), diff --git a/salt/grains/esxi.py b/salt/grains/esxi.py index 57041db8283..e9b40e73c22 100644 --- a/salt/grains/esxi.py +++ b/salt/grains/esxi.py @@ -13,7 +13,6 @@ Generate baseline proxy minion grains for ESXi hosts. """ - import logging import salt.utils.proxy diff --git a/salt/grains/junos.py b/salt/grains/junos.py index a24e39dade4..0dfd3344ff2 100644 --- a/salt/grains/junos.py +++ b/salt/grains/junos.py @@ -5,7 +5,6 @@ via salt-proxy-minion. Thus, some grains make sense to get them from the minion (PYTHONPATH), but others don't (ip_interfaces) """ - import logging import salt.utils.platform diff --git a/salt/grains/minion_process.py b/salt/grains/minion_process.py index 54c0b61eb07..9a8dd420f0a 100644 --- a/salt/grains/minion_process.py +++ b/salt/grains/minion_process.py @@ -2,7 +2,6 @@ Set grains describing the minion process. """ - import os import salt.utils.platform diff --git a/salt/grains/napalm.py b/salt/grains/napalm.py index d36eb0273ab..5fca987e132 100644 --- a/salt/grains/napalm.py +++ b/salt/grains/napalm.py @@ -15,7 +15,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging import salt.utils.dns diff --git a/salt/grains/panos.py b/salt/grains/panos.py index 60d0e52b71e..f5ba8d731de 100644 --- a/salt/grains/panos.py +++ b/salt/grains/panos.py @@ -3,7 +3,6 @@ Generate baseline proxy minion grains for panos hosts. """ - import logging import salt.proxy.panos diff --git a/salt/grains/pending_reboot.py b/salt/grains/pending_reboot.py index dddba83fb6f..c83aecaf7ed 100644 --- a/salt/grains/pending_reboot.py +++ b/salt/grains/pending_reboot.py @@ -3,6 +3,7 @@ Grain that indicates the system is pending a reboot See functions in salt.utils.win_system to see what conditions would indicate a reboot is pending """ + import logging import salt.utils.platform diff --git a/salt/loader/context.py b/salt/loader/context.py index 560b05a8d2b..88a6472a8f3 100644 --- a/salt/loader/context.py +++ b/salt/loader/context.py @@ -1,6 +1,7 @@ """ Manage the context a module loaded by Salt's loader """ + import collections.abc import contextlib import copy diff --git a/salt/loader/dunder.py b/salt/loader/dunder.py index f0235d19a29..d3027098b5a 100644 --- a/salt/loader/dunder.py +++ b/salt/loader/dunder.py @@ -1,6 +1,7 @@ """ Salt dunders. """ + import salt.loader.context loader_context = salt.loader.context.LoaderContext() diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py index 5ad3c6c6d0b..f077d245248 100644 --- a/salt/loader/lazy.py +++ b/salt/loader/lazy.py @@ -318,7 +318,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): # A list to determine precedence of extensions # Prefer packages (directories) over modules (single files)! self.suffix_order = [""] - for (suffix, mode, kind) in SUFFIXES: + for suffix, mode, kind in SUFFIXES: self.suffix_map[suffix] = (suffix, mode, kind) self.suffix_order.append(suffix) diff --git a/salt/log_handlers/logstash_mod.py b/salt/log_handlers/logstash_mod.py index 1d69cfc8945..dcc54f5a68e 100644 --- a/salt/log_handlers/logstash_mod.py +++ b/salt/log_handlers/logstash_mod.py @@ -154,7 +154,6 @@ """ - import datetime import logging import logging.handlers diff --git a/salt/master.py b/salt/master.py index 2dbf519d1dd..caea839427c 100644 --- a/salt/master.py +++ b/salt/master.py @@ -2,6 +2,7 @@ This module contains all of the routines needed to set up a master server, this involves preparing the three listeners and the workers needed by the master. """ + import collections import copy import ctypes @@ -321,7 +322,7 @@ class Maintenance(salt.utils.process.SignalHandlingProcess): else: log.error("Found dropfile with incorrect permissions, ignoring...") os.remove(dfn) - except os.error: + except OSError: pass if self.opts.get("publish_session"): @@ -886,7 +887,7 @@ class ReqServer(salt.utils.process.SignalHandlingProcess): # Cannot delete read-only files on Windows. os.chmod(dfn, stat.S_IRUSR | stat.S_IWUSR) os.remove(dfn) - except os.error: + except OSError: pass # Wait for kill should be less then parent's ProcessManager. @@ -1577,7 +1578,7 @@ class AESFuncs(TransportMethods): if not os.path.isdir(cdir): try: os.makedirs(cdir) - except os.error: + except OSError: pass if os.path.isfile(cpath) and load["loc"] != 0: mode = "ab" diff --git a/salt/matchers/confirm_top.py b/salt/matchers/confirm_top.py index 7435f4ae94d..09a11ff428d 100644 --- a/salt/matchers/confirm_top.py +++ b/salt/matchers/confirm_top.py @@ -3,6 +3,7 @@ The matcher subsystem needs a function called "confirm_top", which takes the data passed to a top file environment and determines if that data matches this minion. """ + import logging import salt.loader diff --git a/salt/metaproxy/deltaproxy.py b/salt/metaproxy/deltaproxy.py index aacc4a336a2..82c3c12598c 100644 --- a/salt/metaproxy/deltaproxy.py +++ b/salt/metaproxy/deltaproxy.py @@ -371,10 +371,10 @@ def post_master_init(self, master): self.deltaproxy_objs[minion_id] = sub_proxy_data["proxy_minion"] if self.deltaproxy_opts[minion_id] and self.deltaproxy_objs[minion_id]: - self.deltaproxy_objs[ - minion_id - ].req_channel = salt.channel.client.AsyncReqChannel.factory( - sub_proxy_data["proxy_opts"], io_loop=self.io_loop + self.deltaproxy_objs[minion_id].req_channel = ( + salt.channel.client.AsyncReqChannel.factory( + sub_proxy_data["proxy_opts"], io_loop=self.io_loop + ) ) else: log.debug("Initiating non-parallel startup for proxies") @@ -398,10 +398,10 @@ def post_master_init(self, master): self.deltaproxy_objs[minion_id] = sub_proxy_data["proxy_minion"] if self.deltaproxy_opts[minion_id] and self.deltaproxy_objs[minion_id]: - self.deltaproxy_objs[ - minion_id - ].req_channel = salt.channel.client.AsyncReqChannel.factory( - sub_proxy_data["proxy_opts"], io_loop=self.io_loop + self.deltaproxy_objs[minion_id].req_channel = ( + salt.channel.client.AsyncReqChannel.factory( + sub_proxy_data["proxy_opts"], io_loop=self.io_loop + ) ) if _failed: diff --git a/salt/minion.py b/salt/minion.py index d948acde4ad..61965b70aed 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1,6 +1,7 @@ """ Routines to set up a minion """ + import binascii import contextlib import copy diff --git a/salt/modules/aix_shadow.py b/salt/modules/aix_shadow.py index aa7471cb026..3282603e01f 100644 --- a/salt/modules/aix_shadow.py +++ b/salt/modules/aix_shadow.py @@ -6,7 +6,6 @@ Manage account locks on AIX systems :depends: none """ - # Import python librarie import logging @@ -30,7 +29,6 @@ def __virtual__(): def login_failures(user): - """ Query for all accounts which have 3 or more login failures. diff --git a/salt/modules/aliases.py b/salt/modules/aliases.py index f04b457ac80..01337791ffe 100644 --- a/salt/modules/aliases.py +++ b/salt/modules/aliases.py @@ -74,7 +74,7 @@ def __write_aliases_file(lines): os.chmod(out.name, 0o644) os.chown(out.name, 0, 0) - for (line_alias, line_target, line_comment) in lines: + for line_alias, line_target, line_comment in lines: if isinstance(line_target, list): line_target = ", ".join(line_target) if not line_comment: @@ -173,7 +173,7 @@ def set_target(alias, target): lines = __parse_aliases() out = [] ovr = False - for (line_alias, line_target, line_comment) in lines: + for line_alias, line_target, line_comment in lines: if line_alias == alias: if not ovr: out.append((alias, target, line_comment)) @@ -202,7 +202,7 @@ def rm_alias(alias): lines = __parse_aliases() out = [] - for (line_alias, line_target, line_comment) in lines: + for line_alias, line_target, line_comment in lines: if line_alias != alias: out.append((line_alias, line_target, line_comment)) diff --git a/salt/modules/apache.py b/salt/modules/apache.py index 4b867706d10..d50ff3b17df 100644 --- a/salt/modules/apache.py +++ b/salt/modules/apache.py @@ -8,7 +8,6 @@ Support for Apache Debian-based system is detected. """ - import io import logging import re diff --git a/salt/modules/augeas_cfg.py b/salt/modules/augeas_cfg.py index 70f05b3a465..6fd455235af 100644 --- a/salt/modules/augeas_cfg.py +++ b/salt/modules/augeas_cfg.py @@ -230,9 +230,9 @@ def execute(context=None, lens=None, commands=(), load_path=None): # if command.split fails arg will not be set if "arg" not in locals(): arg = command - ret[ - "error" - ] = "Invalid formatted command, see debug log for details: {}".format(arg) + ret["error"] = ( + "Invalid formatted command, see debug log for details: {}".format(arg) + ) return ret args = salt.utils.data.decode(args, to_str=True) diff --git a/salt/modules/beacons.py b/salt/modules/beacons.py index 3aef0abbec2..0a759fbd7e5 100644 --- a/salt/modules/beacons.py +++ b/salt/modules/beacons.py @@ -5,7 +5,6 @@ Module for managing the Salt beacons on a minion """ - import difflib import logging import os @@ -185,10 +184,10 @@ def add(name, beacon_data, **kwargs): if not valid: ret["result"] = False - ret[ - "comment" - ] = "Beacon {} configuration invalid, not adding.\n{}".format( - name, vcomment + ret["comment"] = ( + "Beacon {} configuration invalid, not adding.\n{}".format( + name, vcomment + ) ) return ret except KeyError: @@ -285,10 +284,10 @@ def modify(name, beacon_data, **kwargs): if not valid: ret["result"] = False - ret[ - "comment" - ] = "Beacon {} configuration invalid, not modifying.\n{}".format( - name, vcomment + ret["comment"] = ( + "Beacon {} configuration invalid, not modifying.\n{}".format( + name, vcomment + ) ) return ret @@ -300,10 +299,10 @@ def modify(name, beacon_data, **kwargs): if not valid: ret["result"] = False - ret[ - "comment" - ] = "Beacon {} configuration invalid, not modifying.\n{}".format( - name, vcomment + ret["comment"] = ( + "Beacon {} configuration invalid, not modifying.\n{}".format( + name, vcomment + ) ) return ret @@ -459,9 +458,9 @@ def save(**kwargs): fp_.write(yaml_out) ret["comment"] = "Beacons saved to {}.".format(sfn) except OSError: - ret[ - "comment" - ] = "Unable to write to beacons file at {}. Check permissions.".format(sfn) + ret["comment"] = ( + "Unable to write to beacons file at {}. Check permissions.".format(sfn) + ) ret["result"] = False return ret @@ -636,9 +635,9 @@ def enable_beacon(name, **kwargs): ret["comment"] = "Enabled beacon {} on minion.".format(name) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to enable beacon {} on minion.".format(name) + ret["comment"] = ( + "Failed to enable beacon {} on minion.".format(name) + ) elif event_ret: ret["result"] = False ret["comment"] = event_ret["comment"] @@ -654,9 +653,9 @@ def enable_beacon(name, **kwargs): except KeyError: # Effectively a no-op, since we can't really return without an event system ret["result"] = False - ret[ - "comment" - ] = "Event module not available. Beacon enable_beacon job failed." + ret["comment"] = ( + "Event module not available. Beacon enable_beacon job failed." + ) return ret @@ -732,9 +731,9 @@ def disable_beacon(name, **kwargs): except KeyError: # Effectively a no-op, since we can't really return without an event system ret["result"] = False - ret[ - "comment" - ] = "Event module not available. Beacon disable_beacon job failed." + ret["comment"] = ( + "Event module not available. Beacon disable_beacon job failed." + ) return ret diff --git a/salt/modules/bluez_bluetooth.py b/salt/modules/bluez_bluetooth.py index ba2ec098e5d..043c404bb73 100644 --- a/salt/modules/bluez_bluetooth.py +++ b/salt/modules/bluez_bluetooth.py @@ -8,6 +8,7 @@ The following packages are required packages for this module: bluez-utils >= 5.7 pybluez >= 0.18 """ + import shlex import salt.utils.validate.net diff --git a/salt/modules/boto3_elasticsearch.py b/salt/modules/boto3_elasticsearch.py index 7462ea74d5d..60238776980 100644 --- a/salt/modules/boto3_elasticsearch.py +++ b/salt/modules/boto3_elasticsearch.py @@ -46,6 +46,7 @@ Connection module for Amazon Elasticsearch Service :codeauthor: Herbert Buurman :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto3_route53.py b/salt/modules/boto3_route53.py index 88a9b1b2cfc..8183de2f5db 100644 --- a/salt/modules/boto3_route53.py +++ b/salt/modules/boto3_route53.py @@ -913,10 +913,12 @@ def _aws_encode_changebatch(o): ) rr_idx += 1 if "AliasTarget" in o["Changes"][change_idx]["ResourceRecordSet"]: - o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"][ - "DNSName" - ] = _aws_encode( - o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"]["DNSName"] + o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"]["DNSName"] = ( + _aws_encode( + o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"][ + "DNSName" + ] + ) ) change_idx += 1 return o @@ -1026,13 +1028,17 @@ def get_resource_records( if done: return ret args = {"HostedZoneId": HostedZoneId} - args.update( - {"StartRecordName": _aws_encode(next_rr_name)} - ) if next_rr_name else None + ( + args.update({"StartRecordName": _aws_encode(next_rr_name)}) + if next_rr_name + else None + ) # Grrr, can't specify type unless name is set... We'll do this via filtering later instead - args.update( - {"StartRecordType": next_rr_type} - ) if next_rr_name and next_rr_type else None + ( + args.update({"StartRecordType": next_rr_type}) + if next_rr_name and next_rr_type + else None + ) args.update({"StartRecordIdentifier": next_rr_id}) if next_rr_id else None try: r = conn.list_resource_record_sets(**args) diff --git a/salt/modules/boto3_sns.py b/salt/modules/boto3_sns.py index 46026693b54..825c9b23bb0 100644 --- a/salt/modules/boto3_sns.py +++ b/salt/modules/boto3_sns.py @@ -38,6 +38,7 @@ Connection module for Amazon SNS :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_apigateway.py b/salt/modules/boto_apigateway.py index dad8858edb5..c889f272648 100644 --- a/salt/modules/boto_apigateway.py +++ b/salt/modules/boto_apigateway.py @@ -74,6 +74,7 @@ Connection module for Amazon APIGateway message: error message """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_asg.py b/salt/modules/boto_asg.py index c52c7946791..a3ff1619b78 100644 --- a/salt/modules/boto_asg.py +++ b/salt/modules/boto_asg.py @@ -41,6 +41,7 @@ Connection module for Amazon Autoscale Groups :depends: boto :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cfn.py b/salt/modules/boto_cfn.py index 4c6b700482a..d02e82bc2b3 100644 --- a/salt/modules/boto_cfn.py +++ b/salt/modules/boto_cfn.py @@ -28,6 +28,7 @@ Connection module for Amazon Cloud Formation :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cloudfront.py b/salt/modules/boto_cloudfront.py index 7e4db092d06..e9b72633ea4 100644 --- a/salt/modules/boto_cloudfront.py +++ b/salt/modules/boto_cloudfront.py @@ -46,6 +46,7 @@ Connection module for Amazon CloudFront key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cloudtrail.py b/salt/modules/boto_cloudtrail.py index 25c165bd424..31d69846bee 100644 --- a/salt/modules/boto_cloudtrail.py +++ b/salt/modules/boto_cloudtrail.py @@ -45,6 +45,7 @@ The dependencies listed above can be installed via package or pip. region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cloudwatch.py b/salt/modules/boto_cloudwatch.py index f7967d23876..c3a36561f71 100644 --- a/salt/modules/boto_cloudwatch.py +++ b/salt/modules/boto_cloudwatch.py @@ -40,6 +40,7 @@ Connection module for Amazon CloudWatch :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cloudwatch_event.py b/salt/modules/boto_cloudwatch_event.py index 1e8def652d1..1fd40f018bb 100644 --- a/salt/modules/boto_cloudwatch_event.py +++ b/salt/modules/boto_cloudwatch_event.py @@ -40,6 +40,7 @@ Connection module for Amazon CloudWatch Events :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cognitoidentity.py b/salt/modules/boto_cognitoidentity.py index 5d8e7d8aa8f..f675c1682b0 100644 --- a/salt/modules/boto_cognitoidentity.py +++ b/salt/modules/boto_cognitoidentity.py @@ -72,6 +72,7 @@ Connection module for Amazon CognitoIdentity :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -147,7 +148,6 @@ def describe_identity_pools( keyid=None, profile=None, ): - """ Given an identity pool name, (optionally if an identity pool id is given, the given name will be ignored) @@ -447,9 +447,9 @@ def update_identity_pool( if AllowUnauthenticatedIdentities != request_params.get( "AllowUnauthenticatedIdentities" ): - request_params[ - "AllowUnauthenticatedIdentities" - ] = AllowUnauthenticatedIdentities + request_params["AllowUnauthenticatedIdentities"] = ( + AllowUnauthenticatedIdentities + ) current_val = request_params.pop("SupportedLoginProviders", None) if SupportedLoginProviders is not None and SupportedLoginProviders != current_val: diff --git a/salt/modules/boto_datapipeline.py b/salt/modules/boto_datapipeline.py index 52d5872d360..bdbcebaa16a 100644 --- a/salt/modules/boto_datapipeline.py +++ b/salt/modules/boto_datapipeline.py @@ -6,7 +6,6 @@ Connection module for Amazon Data Pipeline :depends: boto3 """ - import logging import salt.utils.versions diff --git a/salt/modules/boto_dynamodb.py b/salt/modules/boto_dynamodb.py index 29e2757f63b..10201cb48e0 100644 --- a/salt/modules/boto_dynamodb.py +++ b/salt/modules/boto_dynamodb.py @@ -40,6 +40,7 @@ Connection module for Amazon DynamoDB :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_ec2.py b/salt/modules/boto_ec2.py index be4edce11dc..7ece2dbe6d3 100644 --- a/salt/modules/boto_ec2.py +++ b/salt/modules/boto_ec2.py @@ -39,6 +39,7 @@ as a passed in dict, or as a string to pull from pillars or minion config: :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -658,7 +659,6 @@ def find_instances( in_states=None, filters=None, ): - """ Given instance properties, find and return matching instance ids @@ -785,7 +785,6 @@ def find_images( profile=None, return_objs=False, ): - """ Given image properties, find and return matching AMI ids @@ -885,7 +884,6 @@ def get_id( in_states=None, filters=None, ): - """ Given instance properties, return the instance id if it exists. @@ -2295,10 +2293,10 @@ def set_volumes_tags( profile=profile, ): ret["success"] = False - ret[ - "comment" - ] = "Failed to remove tags on vol.id {}: {}".format( - vol.id, remove + ret["comment"] = ( + "Failed to remove tags on vol.id {}: {}".format( + vol.id, remove + ) ) return ret if changes["old"] or changes["new"]: diff --git a/salt/modules/boto_efs.py b/salt/modules/boto_efs.py index 70f226bf67c..800aa7977f6 100644 --- a/salt/modules/boto_efs.py +++ b/salt/modules/boto_efs.py @@ -47,7 +47,6 @@ Connection module for Amazon EFS :depends: boto3 """ - import logging import salt.utils.versions diff --git a/salt/modules/boto_elasticache.py b/salt/modules/boto_elasticache.py index 43f183b0f39..656182822bf 100644 --- a/salt/modules/boto_elasticache.py +++ b/salt/modules/boto_elasticache.py @@ -40,6 +40,7 @@ Connection module for Amazon Elasticache :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_elasticsearch_domain.py b/salt/modules/boto_elasticsearch_domain.py index 050ef2f011b..5440435dc2d 100644 --- a/salt/modules/boto_elasticsearch_domain.py +++ b/salt/modules/boto_elasticsearch_domain.py @@ -70,6 +70,7 @@ Connection module for Amazon Elasticsearch Service :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_elb.py b/salt/modules/boto_elb.py index 310b91134bf..a1aa8b16694 100644 --- a/salt/modules/boto_elb.py +++ b/salt/modules/boto_elb.py @@ -40,6 +40,7 @@ Connection module for Amazon ELB :depends: boto >= 2.33.0 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_elbv2.py b/salt/modules/boto_elbv2.py index d91927caa67..7754ef1ef86 100644 --- a/salt/modules/boto_elbv2.py +++ b/salt/modules/boto_elbv2.py @@ -36,6 +36,7 @@ Connection module for Amazon ALB :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_iam.py b/salt/modules/boto_iam.py index 521b1ff7140..fc13002d5ab 100644 --- a/salt/modules/boto_iam.py +++ b/salt/modules/boto_iam.py @@ -33,6 +33,7 @@ Connection module for Amazon IAM :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_iot.py b/salt/modules/boto_iot.py index 1243a1700f9..b7b798487cb 100644 --- a/salt/modules/boto_iot.py +++ b/salt/modules/boto_iot.py @@ -45,6 +45,7 @@ The dependencies listed above can be installed via package or pip. region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_kinesis.py b/salt/modules/boto_kinesis.py index 846defa5d6a..0c9e7b4b5eb 100644 --- a/salt/modules/boto_kinesis.py +++ b/salt/modules/boto_kinesis.py @@ -41,6 +41,7 @@ Connection module for Amazon Kinesis :depends: boto3 """ + # keep lint from choking on _get_conn # pylint: disable=E0602 diff --git a/salt/modules/boto_kms.py b/salt/modules/boto_kms.py index ac106655d5b..70a172d51c7 100644 --- a/salt/modules/boto_kms.py +++ b/salt/modules/boto_kms.py @@ -32,6 +32,7 @@ Connection module for Amazon KMS :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_lambda.py b/salt/modules/boto_lambda.py index 5dcd82a3634..5a23660042e 100644 --- a/salt/modules/boto_lambda.py +++ b/salt/modules/boto_lambda.py @@ -74,6 +74,7 @@ as a passed in dict, or as a string to pull from pillars or minion config: message: error message """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_rds.py b/salt/modules/boto_rds.py index 129c80bc6fe..a241935a5e7 100644 --- a/salt/modules/boto_rds.py +++ b/salt/modules/boto_rds.py @@ -40,6 +40,7 @@ Connection module for Amazon RDS :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 # pylint whinging perfectly valid code diff --git a/salt/modules/boto_route53.py b/salt/modules/boto_route53.py index 500e6f2cb78..ddacf0926b6 100644 --- a/salt/modules/boto_route53.py +++ b/salt/modules/boto_route53.py @@ -41,6 +41,7 @@ Connection module for Amazon Route53 :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_s3.py b/salt/modules/boto_s3.py index bef68657e9b..54939033667 100644 --- a/salt/modules/boto_s3.py +++ b/salt/modules/boto_s3.py @@ -46,6 +46,7 @@ Connection module for Amazon S3 using boto3 :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_s3_bucket.py b/salt/modules/boto_s3_bucket.py index 9fc2417cbfc..a696bd5d2ee 100644 --- a/salt/modules/boto_s3_bucket.py +++ b/salt/modules/boto_s3_bucket.py @@ -45,6 +45,7 @@ The dependencies listed above can be installed via package or pip. region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 # disable complaints about perfectly valid non-assignment code diff --git a/salt/modules/boto_secgroup.py b/salt/modules/boto_secgroup.py index 97941147933..2f0feb03814 100644 --- a/salt/modules/boto_secgroup.py +++ b/salt/modules/boto_secgroup.py @@ -40,6 +40,7 @@ Connection module for Amazon Security Groups :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_sns.py b/salt/modules/boto_sns.py index 7df58b95e5a..dc160896e7f 100644 --- a/salt/modules/boto_sns.py +++ b/salt/modules/boto_sns.py @@ -38,6 +38,7 @@ Connection module for Amazon SNS :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_sqs.py b/salt/modules/boto_sqs.py index c2a572ab248..cb9033d4ce4 100644 --- a/salt/modules/boto_sqs.py +++ b/salt/modules/boto_sqs.py @@ -40,6 +40,7 @@ Connection module for Amazon SQS :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_ssm.py b/salt/modules/boto_ssm.py index f2908a46edc..475279a9153 100644 --- a/salt/modules/boto_ssm.py +++ b/salt/modules/boto_ssm.py @@ -12,6 +12,7 @@ Connection module for Amazon SSM :depends: boto3 """ + import logging import salt.utils.json as json diff --git a/salt/modules/boto_vpc.py b/salt/modules/boto_vpc.py index ee7a757e2b2..9b06a7b3db7 100644 --- a/salt/modules/boto_vpc.py +++ b/salt/modules/boto_vpc.py @@ -120,6 +120,7 @@ Deleting VPC peering connection via this module salt myminion boto_vpc.delete_vpc_peering_connection conn_id=pcx-8a8939e3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -579,7 +580,6 @@ def _find_vpcs( keyid=None, profile=None, ): - """ Given VPC properties, find and return matching VPC ids. """ @@ -1419,9 +1419,9 @@ def describe_subnets( subnet["id"], subnet["vpc_id"], conn=conn ) if explicit_route_table_assoc: - subnet[ - "explicit_route_table_association_id" - ] = explicit_route_table_assoc + subnet["explicit_route_table_association_id"] = ( + explicit_route_table_assoc + ) subnets_list.append(subnet) return {"subnets": subnets_list} diff --git a/salt/modules/bsd_shadow.py b/salt/modules/bsd_shadow.py index c9717d8c036..d3700df5d73 100644 --- a/salt/modules/bsd_shadow.py +++ b/salt/modules/bsd_shadow.py @@ -8,7 +8,6 @@ Manage the password database on BSD systems `. """ - import salt.utils.files import salt.utils.stringutils from salt.exceptions import CommandExecutionError, SaltInvocationError diff --git a/salt/modules/btrfs.py b/salt/modules/btrfs.py index 6adf421009b..ba09acffa1c 100644 --- a/salt/modules/btrfs.py +++ b/salt/modules/btrfs.py @@ -159,9 +159,9 @@ def defragment(path): and not d_res["passed"] and "range ioctl not supported" in d_res["log"] ): - d_res[ - "log" - ] = "Range ioctl defragmentation is not supported in this kernel." + d_res["log"] = ( + "Range ioctl defragmentation is not supported in this kernel." + ) if not is_mountpoint: d_res["mount_point"] = False diff --git a/salt/modules/chef.py b/salt/modules/chef.py index 698db0db560..57946400eb4 100644 --- a/salt/modules/chef.py +++ b/salt/modules/chef.py @@ -2,7 +2,6 @@ Execute chef in server or solo mode """ - import logging import os import tempfile diff --git a/salt/modules/cimc.py b/salt/modules/cimc.py index e555538a901..132b513c2aa 100644 --- a/salt/modules/cimc.py +++ b/salt/modules/cimc.py @@ -24,7 +24,6 @@ rest API. """ - import logging import salt.proxy.cimc diff --git a/salt/modules/cloud.py b/salt/modules/cloud.py index b4f52ae3b73..dd1ededf158 100644 --- a/salt/modules/cloud.py +++ b/salt/modules/cloud.py @@ -2,7 +2,6 @@ Salt-specific interface for calling Salt Cloud directly """ - import copy import logging import os diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py index 4822971d552..051143eb856 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py @@ -431,9 +431,11 @@ def _run( "as user '{}' ".format(runas) if runas else "", "in group '{}' ".format(group) if group else "", cwd, - ". Executing command in the background, no output will be logged." - if bg - else "", + ( + ". Executing command in the background, no output will be logged." + if bg + else "" + ), ) log.info(log_callback(msg)) @@ -999,7 +1001,6 @@ def _run_all_quiet( success_stderr=None, ignore_retcode=None, ): - """ Helper for running commands quietly for minion startup. Returns a dict of return data. diff --git a/salt/modules/consul.py b/salt/modules/consul.py index dfcf84c0ab8..01f161e5fe2 100644 --- a/salt/modules/consul.py +++ b/salt/modules/consul.py @@ -296,9 +296,9 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): return ret query_params["cas"] = kwargs["cas"] else: - ret[ - "message" - ] = "Key {} does not exists, CAS argument can not be used.".format(key) + ret["message"] = ( + "Key {} does not exists, CAS argument can not be used.".format(key) + ) ret["res"] = False return ret @@ -1543,9 +1543,9 @@ def catalog_register(consul_url=None, token=None, **kwargs): "warning", "critical", ): - ret[ - "message" - ] = "Check status must be unknown, passing, warning, or critical." + ret["message"] = ( + "Check status must be unknown, passing, warning, or critical." + ) ret["res"] = False return ret data["Check"]["Status"] = kwargs["check_status"] diff --git a/salt/modules/container_resource.py b/salt/modules/container_resource.py index 0a44ce3e518..5474d43a54c 100644 --- a/salt/modules/container_resource.py +++ b/salt/modules/container_resource.py @@ -8,6 +8,7 @@ These functions are not designed to be called directly, but instead from the :mod:`docker ` execution modules. They provide for common logic to be re-used for common actions. """ + import copy import functools import logging diff --git a/salt/modules/deb_postgres.py b/salt/modules/deb_postgres.py index d92859562d4..e43f87f0fbd 100644 --- a/salt/modules/deb_postgres.py +++ b/salt/modules/deb_postgres.py @@ -2,6 +2,7 @@ Module to provide Postgres compatibility to salt for debian family specific tools. """ + import logging import shlex diff --git a/salt/modules/debian_ip.py b/salt/modules/debian_ip.py index 4a7062c48fc..8c901488d10 100644 --- a/salt/modules/debian_ip.py +++ b/salt/modules/debian_ip.py @@ -5,6 +5,7 @@ References: * http://www.debian.org/doc/manuals/debian-reference/ch05.en.html """ + import functools import io import logging @@ -908,7 +909,6 @@ def _parse_settings_bond_0(opts, iface, bond_def): def _parse_settings_bond_1(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond1. If an option has a value that is not expected, this @@ -995,7 +995,6 @@ def _parse_settings_bond_2(opts, iface, bond_def): def _parse_settings_bond_3(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond3. If an option has a value that is not expected, this @@ -1082,7 +1081,6 @@ def _parse_settings_bond_4(opts, iface, bond_def): def _parse_settings_bond_5(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond5. If an option has a value that is not expected, this @@ -1121,7 +1119,6 @@ def _parse_settings_bond_5(opts, iface, bond_def): def _parse_settings_bond_6(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond6. If an option has a value that is not expected, this @@ -1295,9 +1292,9 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): tmp_ethtool = _parse_ethtool_pppoe_opts(opts, iface) if tmp_ethtool: for item in tmp_ethtool: - adapters[iface]["data"][addrfam][ - _DEB_CONFIG_PPPOE_OPTS[item] - ] = tmp_ethtool[item] + adapters[iface]["data"][addrfam][_DEB_CONFIG_PPPOE_OPTS[item]] = ( + tmp_ethtool[item] + ) iface_data[addrfam]["addrfam"] = addrfam opts.pop("mode", None) @@ -1350,7 +1347,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): iface_data["inet6"][opt] = opts[opt] # Remove incomplete/disabled inet blocks - for (addrfam, opt) in [("inet", "enable_ipv4"), ("inet6", "enable_ipv6")]: + for addrfam, opt in [("inet", "enable_ipv4"), ("inet6", "enable_ipv6")]: if opts.get(opt, None) is False: iface_data.pop(addrfam) elif iface_data[addrfam].get("addrfam", "") != addrfam: diff --git a/salt/modules/debuild_pkgbuild.py b/salt/modules/debuild_pkgbuild.py index b63f0b3f183..21c2629332b 100644 --- a/salt/modules/debuild_pkgbuild.py +++ b/salt/modules/debuild_pkgbuild.py @@ -9,7 +9,6 @@ environments. This also provides a function to generate debian repositories This module implements the pkgbuild interface """ - import errno import logging import os diff --git a/salt/modules/defaults.py b/salt/modules/defaults.py index c807337dc2c..48ce0b11819 100644 --- a/salt/modules/defaults.py +++ b/salt/modules/defaults.py @@ -3,7 +3,6 @@ Module to work with salt formula defaults files """ - import copy import logging import os diff --git a/salt/modules/djangomod.py b/salt/modules/djangomod.py index 17942130e80..9047667e589 100644 --- a/salt/modules/djangomod.py +++ b/salt/modules/djangomod.py @@ -2,7 +2,6 @@ Manage Django sites """ - import os import salt.exceptions diff --git a/salt/modules/dnsmasq.py b/salt/modules/dnsmasq.py index e3f1d8bfa80..af9c8b8ccba 100644 --- a/salt/modules/dnsmasq.py +++ b/salt/modules/dnsmasq.py @@ -2,7 +2,6 @@ Module for managing dnsmasq """ - import logging import os diff --git a/salt/modules/dockercompose.py b/salt/modules/dockercompose.py index a785b983c62..7ebdf2207e9 100644 --- a/salt/modules/dockercompose.py +++ b/salt/modules/dockercompose.py @@ -103,7 +103,6 @@ Detailed Function Documentation ------------------------------- """ - import inspect import logging import os diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py index 49036f0f756..de88620159c 100644 --- a/salt/modules/dockermod.py +++ b/salt/modules/dockermod.py @@ -4491,9 +4491,9 @@ def load(path, repository=None, tag=None): result = tag_(top_level_images[0], repository=repository, tag=tag) ret["Image"] = tagged_image except IndexError: - ret[ - "Warning" - ] = "No top-level image layers were loaded, no image was tagged" + ret["Warning"] = ( + "No top-level image layers were loaded, no image was tagged" + ) except Exception as exc: # pylint: disable=broad-except ret["Warning"] = "Failed to tag {} as {}: {}".format( top_level_images[0], tagged_image, exc diff --git a/salt/modules/drac.py b/salt/modules/drac.py index 86ff8eedd5a..d752199fb7b 100644 --- a/salt/modules/drac.py +++ b/salt/modules/drac.py @@ -2,7 +2,6 @@ Manage Dell DRAC """ - import logging import salt.utils.path diff --git a/salt/modules/dracr.py b/salt/modules/dracr.py index c790f5423b2..bb3192c370f 100644 --- a/salt/modules/dracr.py +++ b/salt/modules/dracr.py @@ -4,7 +4,6 @@ Manage Dell DRAC. .. versionadded:: 2015.8.2 """ - import logging import os import re diff --git a/salt/modules/elasticsearch.py b/salt/modules/elasticsearch.py index 4db9b370abc..e8a468103fe 100644 --- a/salt/modules/elasticsearch.py +++ b/salt/modules/elasticsearch.py @@ -48,7 +48,6 @@ Module to provide Elasticsearch compatibility to Salt Some functionality might be limited by elasticsearch-py and Elasticsearch server versions. """ - import logging from salt.exceptions import CommandExecutionError, SaltInvocationError diff --git a/salt/modules/eselect.py b/salt/modules/eselect.py index 9a0c1cf6756..86c4d246a46 100644 --- a/salt/modules/eselect.py +++ b/salt/modules/eselect.py @@ -2,7 +2,6 @@ Support for eselect, Gentoo's configuration and management tool. """ - import logging import salt.utils.path diff --git a/salt/modules/esxi.py b/salt/modules/esxi.py index c436da91288..23499b7657c 100644 --- a/salt/modules/esxi.py +++ b/salt/modules/esxi.py @@ -34,7 +34,6 @@ type manor. """ - import logging from functools import wraps diff --git a/salt/modules/esxvm.py b/salt/modules/esxvm.py index bf910aee44c..3fac436e898 100644 --- a/salt/modules/esxvm.py +++ b/salt/modules/esxvm.py @@ -13,7 +13,6 @@ Module used to access the esx proxy connection methods """ - import logging from functools import wraps diff --git a/salt/modules/event.py b/salt/modules/event.py index bf6d4bde0d7..7bb64a8119a 100644 --- a/salt/modules/event.py +++ b/salt/modules/event.py @@ -3,7 +3,6 @@ Use the :ref:`Salt Event System ` to fire events from the master to the minion and vice-versa. """ - import logging import os import sys diff --git a/salt/modules/extfs.py b/salt/modules/extfs.py index 63d2cfeb1e1..370e3066b46 100644 --- a/salt/modules/extfs.py +++ b/salt/modules/extfs.py @@ -2,7 +2,6 @@ Module for managing ext2/3/4 file systems """ - import logging import salt.utils.platform diff --git a/salt/modules/file.py b/salt/modules/file.py index d65d3e9a15f..68576d04391 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -4924,9 +4924,11 @@ def extract_hash( if basename_searches: log.debug( "file.extract_hash: %s %s hash for file matching%s: %s", - "If no source_hash_name match found, will extract" - if source_hash_name - else "Extracting", + ( + "If no source_hash_name match found, will extract" + if source_hash_name + else "Extracting" + ), "any supported" if not hash_type else hash_type, "" if len(basename_searches) == 1 else " either of the following", ", ".join(basename_searches), diff --git a/salt/modules/firewalld.py b/salt/modules/firewalld.py index 135713d8516..2c5f35ea18b 100644 --- a/salt/modules/firewalld.py +++ b/salt/modules/firewalld.py @@ -4,7 +4,6 @@ Support for firewalld. .. versionadded:: 2015.2.0 """ - import logging import re diff --git a/salt/modules/freebsd_sysctl.py b/salt/modules/freebsd_sysctl.py index 3d6dd930ec5..6f809176f49 100644 --- a/salt/modules/freebsd_sysctl.py +++ b/salt/modules/freebsd_sysctl.py @@ -2,7 +2,6 @@ Module for viewing and modifying sysctl parameters """ - import logging import os diff --git a/salt/modules/freebsd_update.py b/salt/modules/freebsd_update.py index 26a6acd932f..816c2b13e96 100644 --- a/salt/modules/freebsd_update.py +++ b/salt/modules/freebsd_update.py @@ -8,7 +8,6 @@ Support for freebsd-update utility on FreeBSD. :platform: FreeBSD """ - import logging import salt.utils.path diff --git a/salt/modules/freebsdjail.py b/salt/modules/freebsdjail.py index 1c2343195c7..f86bdab07fd 100644 --- a/salt/modules/freebsdjail.py +++ b/salt/modules/freebsdjail.py @@ -2,7 +2,6 @@ The jail module for FreeBSD """ - import os import re import subprocess diff --git a/salt/modules/gentoo_service.py b/salt/modules/gentoo_service.py index 5a35ba0fcbd..ede473e6779 100644 --- a/salt/modules/gentoo_service.py +++ b/salt/modules/gentoo_service.py @@ -9,7 +9,6 @@ to the correct service manager `. """ - import fnmatch import logging import re diff --git a/salt/modules/github.py b/salt/modules/github.py index bc45f9cae96..d1c3d0e16b0 100644 --- a/salt/modules/github.py +++ b/salt/modules/github.py @@ -29,7 +29,6 @@ For example: allow_repo_privacy_changes: False """ - import logging import salt.utils.http diff --git a/salt/modules/glanceng.py b/salt/modules/glanceng.py index 7f1b824b0f6..85a76dc650a 100644 --- a/salt/modules/glanceng.py +++ b/salt/modules/glanceng.py @@ -25,7 +25,6 @@ Example configuration identity_api_version: 3 """ - HAS_SHADE = False try: import shade diff --git a/salt/modules/gnomedesktop.py b/salt/modules/gnomedesktop.py index abefaeb8586..2ae41dd1155 100644 --- a/salt/modules/gnomedesktop.py +++ b/salt/modules/gnomedesktop.py @@ -2,7 +2,6 @@ GNOME implementations """ - import logging import re diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index b713a0ae9fd..14949e993c4 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -576,9 +576,9 @@ def delete_key( if skey: if not delete_secret: ret["res"] = False - ret[ - "message" - ] = "Secret key exists, delete first or pass delete_secret=True." + ret["message"] = ( + "Secret key exists, delete first or pass delete_secret=True." + ) return ret else: if str(__delete_key(fingerprint, True, use_passphrase)) == "ok": diff --git a/salt/modules/grains.py b/salt/modules/grains.py index a7040e00b32..d803a209549 100644 --- a/salt/modules/grains.py +++ b/salt/modules/grains.py @@ -9,7 +9,6 @@ file on the minions. By default, this file is located at: ``/etc/salt/grains`` This does **NOT** override any grains set in the minion config file. """ - import collections import logging import math @@ -39,6 +38,7 @@ __outputter__ = { "setval": "nested", } + # http://stackoverflow.com/a/12414913/127816 def _infinitedict(): return collections.defaultdict(_infinitedict) diff --git a/salt/modules/haproxyconn.py b/salt/modules/haproxyconn.py index f9e156572bc..a7b0e31b89b 100644 --- a/salt/modules/haproxyconn.py +++ b/salt/modules/haproxyconn.py @@ -4,7 +4,6 @@ Support for haproxy .. versionadded:: 2014.7.0 """ - import logging import os import stat @@ -315,6 +314,7 @@ def set_state(name, backend, state, socket=DEFAULT_SOCKET_URL): salt '*' haproxy.set_state my_proxy_server my_backend ready """ + # Pulling this in from the latest 0.5 release which is not yet in PyPi. # https://github.com/neurogeek/haproxyctl class setServerState(haproxy.cmds.Cmd): diff --git a/salt/modules/hashutil.py b/salt/modules/hashutil.py index 926d385aa4f..cdddadc8d45 100644 --- a/salt/modules/hashutil.py +++ b/salt/modules/hashutil.py @@ -2,7 +2,6 @@ A collection of hashing and encoding functions """ - import base64 import hashlib import hmac diff --git a/salt/modules/helm.py b/salt/modules/helm.py index 19790726716..960c90e87bf 100644 --- a/salt/modules/helm.py +++ b/salt/modules/helm.py @@ -32,7 +32,6 @@ Detailed Function Documentation ------------------------------- """ - import copy import logging import re @@ -1044,7 +1043,7 @@ def repo_manage( ) already_present = False - for (index, repo_present) in enumerate(repos_present): + for index, repo_present in enumerate(repos_present): if repo.get("name") == repo_present.get("name") and repo.get( "url" ) == repo_present.get("url"): diff --git a/salt/modules/hg.py b/salt/modules/hg.py index 2835a531494..855fe2f2cfa 100644 --- a/salt/modules/hg.py +++ b/salt/modules/hg.py @@ -2,7 +2,6 @@ Support for the Mercurial SCM """ - import logging import salt.utils.data diff --git a/salt/modules/hosts.py b/salt/modules/hosts.py index a8c4d412c2a..83f60ab2050 100644 --- a/salt/modules/hosts.py +++ b/salt/modules/hosts.py @@ -2,7 +2,6 @@ Manage the information in the hosts file """ - import errno import logging import os diff --git a/salt/modules/http.py b/salt/modules/http.py index 44464eaa11b..6252b21dc16 100644 --- a/salt/modules/http.py +++ b/salt/modules/http.py @@ -5,7 +5,6 @@ like, but also useful for basic http testing. .. versionadded:: 2015.5.0 """ - import time import salt.utils.http diff --git a/salt/modules/icinga2.py b/salt/modules/icinga2.py index ef222ced217..e3e758d2259 100644 --- a/salt/modules/icinga2.py +++ b/salt/modules/icinga2.py @@ -6,7 +6,6 @@ Module to provide icinga2 compatibility to salt. :depends: - icinga2 server """ - import logging import salt.utils.path diff --git a/salt/modules/ifttt.py b/salt/modules/ifttt.py index 3c49b25a111..248e059b87a 100644 --- a/salt/modules/ifttt.py +++ b/salt/modules/ifttt.py @@ -11,7 +11,6 @@ Requires an ``api_key`` in ``/etc/salt/minion``: secret_key: '280d4699-a817-4719-ba6f-ca56e573e44f' """ - import logging import time diff --git a/salt/modules/influxdb08mod.py b/salt/modules/influxdb08mod.py index 8a46c7d4ef6..b48d08e0792 100644 --- a/salt/modules/influxdb08mod.py +++ b/salt/modules/influxdb08mod.py @@ -21,7 +21,6 @@ version 0.5-0.8) overwrite options passed into pillar. """ - import logging try: diff --git a/salt/modules/influxdbmod.py b/salt/modules/influxdbmod.py index 303ab044706..4793e54c8be 100644 --- a/salt/modules/influxdbmod.py +++ b/salt/modules/influxdbmod.py @@ -635,7 +635,8 @@ def create_continuous_query( .. code-block:: bash - salt '*' influxdb.create_continuous_query mydb cq_month 'SELECT mean(*) INTO mydb.a_month.:MEASUREMENT FROM mydb.a_week./.*/ GROUP BY time(5m), *'""" + salt '*' influxdb.create_continuous_query mydb cq_month 'SELECT mean(*) INTO mydb.a_month.:MEASUREMENT FROM mydb.a_week./.*/ GROUP BY time(5m), *' + """ client = _client(**client_args) full_query = "CREATE CONTINUOUS QUERY {name} ON {database}" if resample_time: @@ -683,7 +684,7 @@ def _pull_query_results(resultset): Parses a ResultSet returned from InfluxDB into a dictionary of results, grouped by series names and optional JSON-encoded grouping tags. """ - _results = collections.defaultdict(lambda: {}) + _results = collections.defaultdict(dict) for _header, _values in resultset.items(): _header, _group_tags = _header if _group_tags: diff --git a/salt/modules/ipmi.py b/salt/modules/ipmi.py index a30a8fb5a14..3e5cf05723f 100644 --- a/salt/modules/ipmi.py +++ b/salt/modules/ipmi.py @@ -30,7 +30,6 @@ systems hardware through IPMI drivers. It uses a python module `pyghmi`. uid=1 """ - IMPORT_ERR = None try: from pyghmi.ipmi import command # nosec diff --git a/salt/modules/ipset.py b/salt/modules/ipset.py index 25717e7676a..35401c11529 100644 --- a/salt/modules/ipset.py +++ b/salt/modules/ipset.py @@ -2,7 +2,6 @@ Support for ipset """ - import logging import salt.utils.path diff --git a/salt/modules/jboss7.py b/salt/modules/jboss7.py index f43a66fb1f4..e68621ced11 100644 --- a/salt/modules/jboss7.py +++ b/salt/modules/jboss7.py @@ -21,7 +21,6 @@ Example: """ - import logging import re diff --git a/salt/modules/jboss7_cli.py b/salt/modules/jboss7_cli.py index 683b61662e8..183d32998f2 100644 --- a/salt/modules/jboss7_cli.py +++ b/salt/modules/jboss7_cli.py @@ -35,7 +35,6 @@ Example: """ - import logging import pprint import re diff --git a/salt/modules/jenkinsmod.py b/salt/modules/jenkinsmod.py index d87c13c3049..46308a2062f 100644 --- a/salt/modules/jenkinsmod.py +++ b/salt/modules/jenkinsmod.py @@ -22,7 +22,6 @@ Module for controlling Jenkins api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15 """ - import logging import salt.utils.files diff --git a/salt/modules/junos.py b/salt/modules/junos.py index 2f1f0c6ab4f..e2afa164f78 100644 --- a/salt/modules/junos.py +++ b/salt/modules/junos.py @@ -479,10 +479,10 @@ def set_hostname(hostname=None, **kwargs): ret["out"] = True except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Successfully loaded host-name but commit failed with "{}"'.format( - exception + ret["message"] = ( + 'Successfully loaded host-name but commit failed with "{}"'.format( + exception + ) ) _restart_connection() return ret @@ -493,10 +493,10 @@ def set_hostname(hostname=None, **kwargs): conn.cu.rollback() except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Successfully loaded host-name but rollback before exit failed "{}"'.format( - exception + ret["message"] = ( + 'Successfully loaded host-name but rollback before exit failed "{}"'.format( + exception + ) ) _restart_connection() @@ -579,10 +579,10 @@ def commit(**kwargs): ret["out"] = False except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Commit check succeeded but actual commit failed with "{}"'.format( - exception + ret["message"] = ( + 'Commit check succeeded but actual commit failed with "{}"'.format( + exception + ) ) _restart_connection() else: @@ -592,10 +592,10 @@ def commit(**kwargs): conn.cu.rollback() except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Pre-commit check failed, and exception during rollback "{}"'.format( - exception + ret["message"] = ( + 'Pre-commit check failed, and exception during rollback "{}"'.format( + exception + ) ) _restart_connection() @@ -708,10 +708,10 @@ def rollback(**kwargs): ret["out"] = True except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Rollback successful but commit failed with error "{}"'.format( - exception + ret["message"] = ( + 'Rollback successful but commit failed with error "{}"'.format( + exception + ) ) _restart_connection() return ret @@ -1078,9 +1078,9 @@ def install_config(path=None, **kwargs): ret["out"] = True if path is None: - ret[ - "message" - ] = "Please provide the salt path where the configuration is present" + ret["message"] = ( + "Please provide the salt path where the configuration is present" + ) ret["out"] = False return ret @@ -1139,9 +1139,9 @@ def install_config(path=None, **kwargs): db_mode = op.pop("mode", "exclusive") if write_diff and db_mode in ["dynamic", "ephemeral"]: - ret[ - "message" - ] = "Write diff is not supported with dynamic/ephemeral configuration mode" + ret["message"] = ( + "Write diff is not supported with dynamic/ephemeral configuration mode" + ) ret["out"] = False return ret @@ -1153,9 +1153,9 @@ def install_config(path=None, **kwargs): try: cu.load(**op) except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = 'Could not load configuration due to : "{}"'.format(exception) + ret["message"] = ( + 'Could not load configuration due to : "{}"'.format(exception) + ) ret["format"] = op["format"] ret["out"] = False _restart_connection() @@ -1185,10 +1185,10 @@ def install_config(path=None, **kwargs): try: check = cu.commit_check() except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = 'Commit check threw the following exception: "{}"'.format( - exception + ret["message"] = ( + 'Commit check threw the following exception: "{}"'.format( + exception + ) ) ret["out"] = False _restart_connection() @@ -1199,10 +1199,10 @@ def install_config(path=None, **kwargs): cu.commit(**commit_params) ret["message"] = "Successfully loaded and committed!" except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = 'Commit check successful but commit failed with "{}"'.format( - exception + ret["message"] = ( + 'Commit check successful but commit failed with "{}"'.format( + exception + ) ) ret["out"] = False _restart_connection() @@ -1248,9 +1248,9 @@ def install_config(path=None, **kwargs): with salt.utils.files.fopen(write_diff, "w") as fp: fp.write(salt.utils.stringutils.to_str(config_diff)) except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = "Could not write into diffs_file due to: '{}'".format(exception) + ret["message"] = ( + "Could not write into diffs_file due to: '{}'".format(exception) + ) ret["out"] = False except ValueError as ex: @@ -1396,9 +1396,9 @@ def install_os(path=None, **kwargs): no_copy_ = op.get("no_copy", False) if path is None: - ret[ - "message" - ] = "Please provide the salt path where the junos image is present." + ret["message"] = ( + "Please provide the salt path where the junos image is present." + ) ret["out"] = False return ret @@ -1467,10 +1467,10 @@ def install_os(path=None, **kwargs): conn.sw.reboot(**reboot_kwargs) except Exception as exception: # pylint: disable=broad-except __proxy__["junos.reboot_clear"]() - ret[ - "message" - ] = 'Installation successful but reboot failed due to : "{}"'.format( - exception + ret["message"] = ( + 'Installation successful but reboot failed due to : "{}"'.format( + exception + ) ) ret["out"] = False _restart_connection() @@ -1666,9 +1666,9 @@ def load(path=None, **kwargs): ret["out"] = True if path is None: - ret[ - "message" - ] = "Please provide the salt path where the configuration is present" + ret["message"] = ( + "Please provide the salt path where the configuration is present" + ) ret["out"] = False return ret @@ -1862,10 +1862,10 @@ def get_table( ) globals().update(FactoryLoader().load(ret["table"])) except OSError as err: - ret[ - "message" - ] = "Uncaught exception during YAML Load - please report: {}".format( - str(err) + ret["message"] = ( + "Uncaught exception during YAML Load - please report: {}".format( + str(err) + ) ) ret["out"] = False return ret @@ -1873,18 +1873,18 @@ def get_table( data = globals()[table](conn) data.get(**get_kvargs) except KeyError as err: - ret[ - "message" - ] = "Uncaught exception during get API call - please report: {}".format( - str(err) + ret["message"] = ( + "Uncaught exception during get API call - please report: {}".format( + str(err) + ) ) ret["out"] = False return ret except ConnectClosedError: - ret[ - "message" - ] = "Got ConnectClosedError exception. Connection lost with {}".format( - conn + ret["message"] = ( + "Got ConnectClosedError exception. Connection lost with {}".format( + conn + ) ) ret["out"] = False _restart_connection() @@ -1914,10 +1914,10 @@ def get_table( ret["table"][table]["args"] = args ret["table"][table]["command"] = data.GET_CMD except ConnectClosedError: - ret[ - "message" - ] = "Got ConnectClosedError exception. Connection lost with {}".format( - str(conn) + ret["message"] = ( + "Got ConnectClosedError exception. Connection lost with {}".format( + str(conn) + ) ) ret["out"] = False _restart_connection() diff --git a/salt/modules/kerberos.py b/salt/modules/kerberos.py index ea898a22634..30b0a356df0 100644 --- a/salt/modules/kerberos.py +++ b/salt/modules/kerberos.py @@ -19,7 +19,6 @@ authenticate as. auth_principal: kadmin/admin """ - import logging import salt.utils.path diff --git a/salt/modules/keyboard.py b/salt/modules/keyboard.py index 85d3e3aca93..ed26c7362d2 100644 --- a/salt/modules/keyboard.py +++ b/salt/modules/keyboard.py @@ -3,7 +3,6 @@ Module for managing keyboards on supported POSIX-like systems using systemd, or such as Redhat, Debian and Gentoo. """ - import logging import salt.utils.path diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index b39a8b0ae5b..9ca44b14337 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -355,11 +355,13 @@ def endpoint_get(service, region=None, profile=None, interface=None, **connectio e = [ _f for _f in [ - e - if e["service_id"] == service_id - and (e["region"] == region if region else True) - and (e["interface"] == interface if interface else True) - else None + ( + e + if e["service_id"] == service_id + and (e["region"] == region if region else True) + and (e["interface"] == interface if interface else True) + else None + ) for e in endpoints.values() ] if _f diff --git a/salt/modules/keystoneng.py b/salt/modules/keystoneng.py index 77c5e7f8b01..1bec255d60e 100644 --- a/salt/modules/keystoneng.py +++ b/salt/modules/keystoneng.py @@ -25,7 +25,6 @@ Example configuration identity_api_version: 3 """ - HAS_SHADE = False try: import shade diff --git a/salt/modules/keystore.py b/salt/modules/keystore.py index 449c78b9589..6a4b7b90bf2 100644 --- a/salt/modules/keystore.py +++ b/salt/modules/keystore.py @@ -2,7 +2,6 @@ Module to interact with keystores """ - import logging import os from datetime import datetime diff --git a/salt/modules/launchctl_service.py b/salt/modules/launchctl_service.py index b30ce1320f4..b1d2ec5a639 100644 --- a/salt/modules/launchctl_service.py +++ b/salt/modules/launchctl_service.py @@ -10,7 +10,6 @@ Module for the management of MacOS systems that use launchd/launchctl :depends: - plistlib Python module """ - import fnmatch import logging import os diff --git a/salt/modules/ldap3.py b/salt/modules/ldap3.py index 2313b024bb9..87836de7b6f 100644 --- a/salt/modules/ldap3.py +++ b/salt/modules/ldap3.py @@ -10,7 +10,6 @@ This is an alternative to the ``ldap`` interface provided by the :depends: - ``ldap`` Python module """ - import logging import salt.utils.data diff --git a/salt/modules/ldapmod.py b/salt/modules/ldapmod.py index 8b1e22d994e..ceac8cd5dc3 100644 --- a/salt/modules/ldapmod.py +++ b/salt/modules/ldapmod.py @@ -39,7 +39,6 @@ Salt interface to LDAP commands badness may ensue - you have been warned. """ - import logging import time diff --git a/salt/modules/libcloud_compute.py b/salt/modules/libcloud_compute.py index 73171caa553..b902055df36 100644 --- a/salt/modules/libcloud_compute.py +++ b/salt/modules/libcloud_compute.py @@ -26,6 +26,7 @@ Clouds include Amazon EC2, Azure, Google GCE, VMware, OpenStack Nova :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/libcloud_dns.py b/salt/modules/libcloud_dns.py index 182b7fb7820..33779286112 100644 --- a/salt/modules/libcloud_dns.py +++ b/salt/modules/libcloud_dns.py @@ -24,6 +24,7 @@ Connection module for Apache Libcloud DNS management :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/libcloud_loadbalancer.py b/salt/modules/libcloud_loadbalancer.py index 08d768ef626..3fa4fd49467 100644 --- a/salt/modules/libcloud_loadbalancer.py +++ b/salt/modules/libcloud_loadbalancer.py @@ -26,6 +26,7 @@ Clouds include Amazon ELB, ALB, Google, Aliyun, CloudStack, Softlayer :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/libcloud_storage.py b/salt/modules/libcloud_storage.py index 7e055ab30e5..51fc04b5512 100644 --- a/salt/modules/libcloud_storage.py +++ b/salt/modules/libcloud_storage.py @@ -26,6 +26,7 @@ Clouds include Amazon S3, Google Storage, Aliyun, Azure Blobs, Ceph, OpenStack s :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/lxc.py b/salt/modules/lxc.py index 444359bd216..4dab95f44eb 100644 --- a/salt/modules/lxc.py +++ b/salt/modules/lxc.py @@ -1666,9 +1666,9 @@ def init( ret["result"] = False else: if not result: - ret[ - "comment" - ] = "Bootstrap failed, see minion log for more information" + ret["comment"] = ( + "Bootstrap failed, see minion log for more information" + ) ret["result"] = False else: changes.append({"bootstrap": "Container successfully bootstrapped"}) @@ -3274,7 +3274,6 @@ def systemd_running_state(name, path=None): def test_sd_started_state(name, path=None): - """ Test if a systemd container is fully started diff --git a/salt/modules/lxd.py b/salt/modules/lxd.py index cc91c1b59b7..fadaa98f27e 100644 --- a/salt/modules/lxd.py +++ b/salt/modules/lxd.py @@ -31,7 +31,6 @@ several functions to help manage it and its containers. :platform: Linux """ - import logging import os from datetime import datetime @@ -3438,17 +3437,17 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): if newconfig[k] != obj.config[k]: if not test: - config_changes[ - k - ] = 'Changed config key "{}" to "{}", its value was "{}"'.format( - k, newconfig[k], obj.config[k] + config_changes[k] = ( + 'Changed config key "{}" to "{}", its value was "{}"'.format( + k, newconfig[k], obj.config[k] + ) ) obj.config[k] = newconfig[k] else: - config_changes[ - k - ] = 'Would change config key "{}" to "{}", its current value is "{}"'.format( - k, newconfig[k], obj.config[k] + config_changes[k] = ( + 'Would change config key "{}" to "{}", its current value is "{}"'.format( + k, newconfig[k], obj.config[k] + ) ) # New keys diff --git a/salt/modules/mac_brew_pkg.py b/salt/modules/mac_brew_pkg.py index 976dd1ad615..26c47a7a5b8 100644 --- a/salt/modules/mac_brew_pkg.py +++ b/salt/modules/mac_brew_pkg.py @@ -725,9 +725,9 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 if result: changes = {"old": "hold", "new": "install"} ret[target].update(changes=changes, result=True) - ret[target][ - "comment" - ] = "Package {} is no longer being held.".format(target) + ret[target]["comment"] = ( + "Package {} is no longer being held.".format(target) + ) else: ret[target].update(result=False) ret[target]["comment"] = "Unable to unhold package {}.".format( diff --git a/salt/modules/mac_group.py b/salt/modules/mac_group.py index 4c13f598802..44b57f25909 100644 --- a/salt/modules/mac_group.py +++ b/salt/modules/mac_group.py @@ -1,6 +1,7 @@ """ Manage groups on Mac OS 10.7+ """ + import logging import salt.utils.functools diff --git a/salt/modules/mac_shadow.py b/salt/modules/mac_shadow.py index e5c23332ea5..d116f3e2077 100644 --- a/salt/modules/mac_shadow.py +++ b/salt/modules/mac_shadow.py @@ -6,6 +6,7 @@ Manage macOS local directory passwords and policies Note that it is usually better to apply password policies through the creation of a configuration profile. """ + # Authentication concepts reference: # https://developer.apple.com/library/mac/documentation/Networking/Conceptual/Open_Directory/openDirectoryConcepts/openDirectoryConcepts.html#//apple_ref/doc/uid/TP40000917-CH3-CIFCAIBB diff --git a/salt/modules/mandrill.py b/salt/modules/mandrill.py index d9c7d333ecd..5896662d664 100644 --- a/salt/modules/mandrill.py +++ b/salt/modules/mandrill.py @@ -17,7 +17,6 @@ In the minion configuration file, the following block is required: .. versionadded:: 2018.3.0 """ - import logging import salt.utils.json diff --git a/salt/modules/marathon.py b/salt/modules/marathon.py index c749f28015e..04e910dd5fd 100644 --- a/salt/modules/marathon.py +++ b/salt/modules/marathon.py @@ -6,7 +6,6 @@ Currently this only works when run through a proxy minion. .. versionadded:: 2015.8.2 """ - import logging import salt.utils.http diff --git a/salt/modules/mattermost.py b/salt/modules/mattermost.py index adb3cb7b676..5f821766a55 100644 --- a/salt/modules/mattermost.py +++ b/salt/modules/mattermost.py @@ -14,7 +14,6 @@ Module for sending messages to Mattermost api_url: https://example.com """ - import logging import salt.utils.json diff --git a/salt/modules/mdadm_raid.py b/salt/modules/mdadm_raid.py index e76f400a214..7333101cbaa 100644 --- a/salt/modules/mdadm_raid.py +++ b/salt/modules/mdadm_raid.py @@ -1,6 +1,7 @@ """ Salt module to manage RAID arrays with mdadm """ + import logging import os import re diff --git a/salt/modules/mdata.py b/salt/modules/mdata.py index 9b31be55dbc..8075922a5ef 100644 --- a/salt/modules/mdata.py +++ b/salt/modules/mdata.py @@ -8,7 +8,6 @@ Module for managaging metadata in SmartOS Zones :platform: smartos """ - import logging import salt.utils.decorators as decorators diff --git a/salt/modules/modjk.py b/salt/modules/modjk.py index 41f6253fd43..9b1ec755f61 100644 --- a/salt/modules/modjk.py +++ b/salt/modules/modjk.py @@ -29,6 +29,7 @@ this module. realm: authentication realm2 for digest passwords timeout: 600 """ + import urllib.parse import urllib.request diff --git a/salt/modules/mount.py b/salt/modules/mount.py index aedc8dc79f2..f27575fc8ed 100644 --- a/salt/modules/mount.py +++ b/salt/modules/mount.py @@ -2,7 +2,6 @@ Salt module to manage Unix mounts and the fstab file """ - import logging import os import re diff --git a/salt/modules/mssql.py b/salt/modules/mssql.py index 3b64899929c..9254d78fe5d 100644 --- a/salt/modules/mssql.py +++ b/salt/modules/mssql.py @@ -20,7 +20,6 @@ Module to provide MS SQL Server compatibility to salt. configs or pillars. """ - import salt.utils.json try: @@ -217,7 +216,6 @@ def db_remove(database_name, **kwargs): def role_list(**kwargs): - """ Lists database roles. @@ -231,7 +229,6 @@ def role_list(**kwargs): def role_exists(role, **kwargs): - """ Checks if a role exists. diff --git a/salt/modules/mysql.py b/salt/modules/mysql.py index 4d8f5e07e8b..522b8858ce7 100644 --- a/salt/modules/mysql.py +++ b/salt/modules/mysql.py @@ -28,7 +28,6 @@ Module to provide MySQL compatibility to salt. Additionally, it is now possible to setup a user with no password. """ - import copy import hashlib import logging diff --git a/salt/modules/nacl.py b/salt/modules/nacl.py index ef0e1774548..ca1e54193e5 100644 --- a/salt/modules/nacl.py +++ b/salt/modules/nacl.py @@ -149,7 +149,6 @@ Optional small program to encrypt data without needing salt modules. """ - import salt.utils.nacl __virtualname__ = "nacl" diff --git a/salt/modules/nagios.py b/salt/modules/nagios.py index 29c02e4bf03..960b8b2e718 100644 --- a/salt/modules/nagios.py +++ b/salt/modules/nagios.py @@ -2,7 +2,6 @@ Run nagios plugins/checks from salt and get the return as data. """ - import logging import os import stat diff --git a/salt/modules/nagios_rpc.py b/salt/modules/nagios_rpc.py index 0f7969dbf38..5eae58b0b2b 100644 --- a/salt/modules/nagios_rpc.py +++ b/salt/modules/nagios_rpc.py @@ -5,7 +5,6 @@ Check Host & Service status from Nagios via JSON RPC. """ - import http.client import logging diff --git a/salt/modules/namecheap_domains.py b/salt/modules/namecheap_domains.py index 97ec8e215a0..c3d9f3ba1d0 100644 --- a/salt/modules/namecheap_domains.py +++ b/salt/modules/namecheap_domains.py @@ -402,9 +402,9 @@ def check(*domains_to_check): domains_checked = {} for result in response_xml.getElementsByTagName("DomainCheckResult"): available = result.getAttribute("Available") - domains_checked[ - result.getAttribute("Domain").lower() - ] = salt.utils.namecheap.string_to_value(available) + domains_checked[result.getAttribute("Domain").lower()] = ( + salt.utils.namecheap.string_to_value(available) + ) return domains_checked diff --git a/salt/modules/namecheap_domains_dns.py b/salt/modules/namecheap_domains_dns.py index ef6789ec778..24805acba6d 100644 --- a/salt/modules/namecheap_domains_dns.py +++ b/salt/modules/namecheap_domains_dns.py @@ -26,7 +26,6 @@ file, or in the Pillar data. #namecheap.url: https://api.sandbox.namecheap.xml.response """ - CAN_USE_NAMECHEAP = True diff --git a/salt/modules/napalm_bgp.py b/salt/modules/napalm_bgp.py index 84a19b27a2c..b7721397bd9 100644 --- a/salt/modules/napalm_bgp.py +++ b/salt/modules/napalm_bgp.py @@ -17,7 +17,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -59,7 +58,6 @@ def __virtual__(): @proxy_napalm_wrap def config(group=None, neighbor=None, **kwargs): - """ Provides the BGP configuration on the device. @@ -169,7 +167,6 @@ def config(group=None, neighbor=None, **kwargs): @proxy_napalm_wrap def neighbors(neighbor=None, **kwargs): - """ Provides details regarding the BGP sessions configured on the network device. diff --git a/salt/modules/napalm_network.py b/salt/modules/napalm_network.py index 124d70b4876..c6156db1566 100644 --- a/salt/modules/napalm_network.py +++ b/salt/modules/napalm_network.py @@ -64,7 +64,6 @@ def __virtual__(): def _filter_list(input_list, search_key, search_value): - """ Filters a list of dictionary by a set of key-value pair. @@ -84,7 +83,6 @@ def _filter_list(input_list, search_key, search_value): def _filter_dict(input_dict, search_key, search_value): - """ Filters a dictionary of dictionaries by a key-value pair. @@ -310,9 +308,9 @@ def _config_logic( _comm = __salt__["napalm.junos_commit"](confirm=minutes) if not _comm["out"]: # If unable to commit confirm, should try to bail out - loaded_result[ - "comment" - ] = "Unable to commit confirm: {}".format(_comm["message"]) + loaded_result["comment"] = ( + "Unable to commit confirm: {}".format(_comm["message"]) + ) loaded_result["result"] = False # But before exiting, we must gracefully discard the config discarded = _safe_dicard_config(loaded_result, napalm_device) @@ -838,7 +836,6 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument def traceroute( destination, source=None, ttl=None, timeout=None, vrf=None, **kwargs ): # pylint: disable=unused-argument - """ Calls the method traceroute from the NAPALM driver object and returns a dictionary with the result of the traceroute command executed on the device. @@ -892,7 +889,6 @@ def ping( vrf=None, **kwargs ): # pylint: disable=unused-argument - """ Executes a ping on the network device and returns a dictionary as a result. @@ -947,7 +943,6 @@ def ping( def arp( interface="", ipaddr="", macaddr="", **kwargs ): # pylint: disable=unused-argument - """ NAPALM returns a list of dictionaries with details of the ARP entries. @@ -1008,7 +1003,6 @@ def arp( @salt.utils.napalm.proxy_napalm_wrap def ipaddrs(**kwargs): # pylint: disable=unused-argument - """ Returns IP addresses configured on the device. @@ -1065,7 +1059,6 @@ def ipaddrs(**kwargs): # pylint: disable=unused-argument @salt.utils.napalm.proxy_napalm_wrap def interfaces(**kwargs): # pylint: disable=unused-argument - """ Returns details of the interfaces on the device. @@ -1109,7 +1102,6 @@ def interfaces(**kwargs): # pylint: disable=unused-argument @salt.utils.napalm.proxy_napalm_wrap def lldp(interface="", **kwargs): # pylint: disable=unused-argument - """ Returns a detailed view of the LLDP neighbors. @@ -1169,7 +1161,6 @@ def lldp(interface="", **kwargs): # pylint: disable=unused-argument @salt.utils.napalm.proxy_napalm_wrap def mac(address="", interface="", vlan=0, **kwargs): # pylint: disable=unused-argument - """ Returns the MAC Address Table on the device. @@ -1563,10 +1554,10 @@ def load_config( # When using salt:// or https://, if the resource is not available, # it will either raise an exception, or return False. ret = {"result": False, "out": None} - ret[ - "comment" - ] = "Unable to read from {}. Please specify a valid file or text.".format( - filename + ret["comment"] = ( + "Unable to read from {}. Please specify a valid file or text.".format( + filename + ) ) log.error(ret["comment"]) return ret @@ -2097,7 +2088,6 @@ def load_template( @salt.utils.napalm.proxy_napalm_wrap def commit(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-argument - """ Commits the configuration changes made on the network device. @@ -2117,7 +2107,6 @@ def commit(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-argu def discard_config( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Discards the changes applied. @@ -2137,7 +2126,6 @@ def discard_config( def compare_config( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Returns the difference between the running config and the candidate config. @@ -2155,7 +2143,6 @@ def compare_config( @salt.utils.napalm.proxy_napalm_wrap def rollback(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-argument - """ Rollbacks the configuration. @@ -2175,7 +2162,6 @@ def rollback(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-ar def config_changed( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Will prompt if the configuration has been changed. @@ -2210,7 +2196,6 @@ def config_changed( def config_control( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Will check if the configuration was changed. If differences found, will try to commit. diff --git a/salt/modules/napalm_ntp.py b/salt/modules/napalm_ntp.py index 125c36dfb47..d737c149e23 100644 --- a/salt/modules/napalm_ntp.py +++ b/salt/modules/napalm_ntp.py @@ -20,7 +20,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -62,7 +61,6 @@ def __virtual__(): @proxy_napalm_wrap def peers(**kwargs): # pylint: disable=unused-argument - """ Returns a list the NTP peers configured on the network device. @@ -103,7 +101,6 @@ def peers(**kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def servers(**kwargs): # pylint: disable=unused-argument - """ Returns a list of the configured NTP servers on the device. @@ -141,7 +138,6 @@ def servers(**kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def stats(peer=None, **kwargs): # pylint: disable=unused-argument - """ Returns a dictionary containing synchronization details of the NTP peers. @@ -208,7 +204,6 @@ def stats(peer=None, **kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def set_peers(*peers, **options): - """ Configures a list of NTP peers on the device. @@ -285,7 +280,6 @@ def set_servers(*servers, **options): @proxy_napalm_wrap def delete_peers(*peers, **options): - """ Removes NTP peers configured on the device. @@ -325,7 +319,6 @@ def delete_peers(*peers, **options): @proxy_napalm_wrap def delete_servers(*servers, **options): - """ Removes NTP servers configured on the device. diff --git a/salt/modules/napalm_probes.py b/salt/modules/napalm_probes.py index 7f798391a75..132b984d6b1 100644 --- a/salt/modules/napalm_probes.py +++ b/salt/modules/napalm_probes.py @@ -60,7 +60,6 @@ def __virtual__(): @proxy_napalm_wrap def config(**kwargs): # pylint: disable=unused-argument - """ Returns the configuration of the RPM probes. @@ -103,7 +102,6 @@ def config(**kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def results(**kwargs): # pylint: disable=unused-argument - """ Provides the results of the measurements of the RPM/SLA probes. @@ -270,7 +268,6 @@ def set_probes( def delete_probes( probes, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Removes RPM/SLA probes from the network device. Calls the configuration template 'delete_probes' from the NAPALM library, @@ -327,7 +324,6 @@ def delete_probes( def schedule_probes( probes, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Will schedule the probes. On Cisco devices, it is not enough to define the probes, it is also necessary to schedule them. diff --git a/salt/modules/napalm_route.py b/salt/modules/napalm_route.py index 41d8d74987e..1f88345c4fd 100644 --- a/salt/modules/napalm_route.py +++ b/salt/modules/napalm_route.py @@ -16,7 +16,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -58,7 +57,6 @@ def __virtual__(): @proxy_napalm_wrap def show(destination, protocol=None, **kwargs): # pylint: disable=unused-argument - """ Displays all details for a certain route learned via a specific protocol. If the protocol is not specified, will return all possible routes. diff --git a/salt/modules/napalm_snmp.py b/salt/modules/napalm_snmp.py index dbcbb4ad700..2e72c03fa69 100644 --- a/salt/modules/napalm_snmp.py +++ b/salt/modules/napalm_snmp.py @@ -20,7 +20,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -62,7 +61,6 @@ def __virtual__(): @proxy_napalm_wrap def config(**kwargs): # pylint: disable=unused-argument - """ Returns the SNMP configuration @@ -90,7 +88,6 @@ def remove_config( commit=True, **kwargs ): # pylint: disable=unused-argument - """ Removes a configuration element from the SNMP configuration. @@ -157,7 +154,6 @@ def update_config( commit=True, **kwargs ): # pylint: disable=unused-argument - """ Updates the SNMP configuration. diff --git a/salt/modules/napalm_users.py b/salt/modules/napalm_users.py index 170e441ba98..40603097102 100644 --- a/salt/modules/napalm_users.py +++ b/salt/modules/napalm_users.py @@ -19,7 +19,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -61,7 +60,6 @@ def __virtual__(): @proxy_napalm_wrap def config(**kwargs): # pylint: disable=unused-argument - """ Returns the configuration of the users on the device @@ -100,7 +98,6 @@ def config(**kwargs): # pylint: disable=unused-argument def set_users( users, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Configures users on network devices. @@ -149,7 +146,6 @@ def set_users( def delete_users( users, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Removes users from the configuration of network devices. diff --git a/salt/modules/netaddress.py b/salt/modules/netaddress.py index 7c528c92a9e..86b7b1aae97 100644 --- a/salt/modules/netaddress.py +++ b/salt/modules/netaddress.py @@ -6,7 +6,6 @@ Module for getting information about network addresses. :depends: netaddr """ - __virtualname__ = "netaddress" try: diff --git a/salt/modules/neutronng.py b/salt/modules/neutronng.py index daf91f49ff7..3aa2817985c 100644 --- a/salt/modules/neutronng.py +++ b/salt/modules/neutronng.py @@ -25,7 +25,6 @@ Example configuration identity_api_version: 3 """ - HAS_SHADE = False try: import shade diff --git a/salt/modules/nftables.py b/salt/modules/nftables.py index d6020a10122..5af8f7b3b85 100644 --- a/salt/modules/nftables.py +++ b/salt/modules/nftables.py @@ -574,10 +574,10 @@ def check(table="filter", chain=None, rule=None, family="ipv4"): out = __salt__["cmd.run"](cmd, python_shell=False).find(search_rule) if out == -1: - ret[ - "comment" - ] = "Rule {} in chain {} in table {} in family {} does not exist".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} in chain {} in table {} in family {} does not exist".format( + rule, chain, table, family + ) ) else: ret["comment"] = "Rule {} in chain {} in table {} in family {} exists".format( @@ -799,10 +799,10 @@ def new_chain( ) ret["result"] = True else: - ret[ - "comment" - ] = "Chain {} in table {} in family {} could not be created".format( - chain, table, family + ret["comment"] = ( + "Chain {} in table {} in family {} could not be created".format( + chain, table, family + ) ) return ret @@ -850,10 +850,10 @@ def delete_chain(table="filter", chain=None, family="ipv4"): ) ret["result"] = True else: - ret[ - "comment" - ] = "Chain {} in table {} in family {} could not be deleted".format( - chain, table, family + ret["comment"] = ( + "Chain {} in table {} in family {} could not be deleted".format( + chain, table, family + ) ) return ret @@ -904,10 +904,10 @@ def append(table="filter", chain=None, rule=None, family="ipv4"): res = check(table, chain, rule, family=family) if res["result"]: - ret[ - "comment" - ] = "Rule {} chain {} in table {} in family {} already exists".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} chain {} in table {} in family {} already exists".format( + rule, chain, table, family + ) ) return ret @@ -923,10 +923,10 @@ def append(table="filter", chain=None, rule=None, family="ipv4"): rule, chain, table, family ) else: - ret[ - "comment" - ] = 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( - rule, chain, table, family + ret["comment"] = ( + 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( + rule, chain, table, family + ) ) return ret @@ -984,10 +984,10 @@ def insert(table="filter", chain=None, position=None, rule=None, family="ipv4"): res = check(table, chain, rule, family=family) if res["result"]: - ret[ - "comment" - ] = "Rule {} chain {} in table {} in family {} already exists".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} chain {} in table {} in family {} already exists".format( + rule, chain, table, family + ) ) return ret @@ -1008,10 +1008,10 @@ def insert(table="filter", chain=None, position=None, rule=None, family="ipv4"): rule, chain, table, family ) else: - ret[ - "comment" - ] = 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( - rule, chain, table, family + ret["comment"] = ( + 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( + rule, chain, table, family + ) ) return ret @@ -1061,10 +1061,10 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): res = check(table, chain, rule, family=family) if not res["result"]: - ret[ - "comment" - ] = "Rule {} chain {} in table {} in family {} does not exist".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} chain {} in table {} in family {} does not exist".format( + rule, chain, table, family + ) ) return ret @@ -1081,16 +1081,16 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): if not out: ret["result"] = True - ret[ - "comment" - ] = 'Deleted rule "{}" in chain {} in table {} in family {}.'.format( - rule, chain, table, family + ret["comment"] = ( + 'Deleted rule "{}" in chain {} in table {} in family {}.'.format( + rule, chain, table, family + ) ) else: - ret[ - "comment" - ] = 'Failed to delete rule "{}" in chain {} table {} in family {}'.format( - rule, chain, table, family + ret["comment"] = ( + 'Failed to delete rule "{}" in chain {} table {} in family {}'.format( + rule, chain, table, family + ) ) return ret diff --git a/salt/modules/nix.py b/salt/modules/nix.py index d5331cb7a97..b0e95afc2d1 100644 --- a/salt/modules/nix.py +++ b/salt/modules/nix.py @@ -18,7 +18,6 @@ For more information on nix, see the `nix documentation`_. .. _`nix-daemon`: https://nixos.org/nix/manual/#ssec-multi-user """ - import itertools import logging import os diff --git a/salt/modules/nspawn.py b/salt/modules/nspawn.py index ec74385fff9..a1893ef8d2c 100644 --- a/salt/modules/nspawn.py +++ b/salt/modules/nspawn.py @@ -20,7 +20,6 @@ Minions running systemd >= 219 will place new containers in package. """ - import errno import functools import logging diff --git a/salt/modules/omapi.py b/salt/modules/omapi.py index c63d94d3dae..fd92162b04b 100644 --- a/salt/modules/omapi.py +++ b/salt/modules/omapi.py @@ -11,7 +11,6 @@ config or pillar: :depends: pypureomapi Python module """ - import logging import struct diff --git a/salt/modules/openbsdservice.py b/salt/modules/openbsdservice.py index b68d217b448..58304aa9fdb 100644 --- a/salt/modules/openbsdservice.py +++ b/salt/modules/openbsdservice.py @@ -8,7 +8,6 @@ The service module for OpenBSD `. """ - import fnmatch import logging import os diff --git a/salt/modules/openscap.py b/salt/modules/openscap.py index 3f3ff6dffd8..ca026e02868 100644 --- a/salt/modules/openscap.py +++ b/salt/modules/openscap.py @@ -2,6 +2,7 @@ Module for OpenSCAP Management """ + import argparse import shlex import shutil diff --git a/salt/modules/osquery.py b/salt/modules/osquery.py index 93c3774dc18..c28d1685dc5 100644 --- a/salt/modules/osquery.py +++ b/salt/modules/osquery.py @@ -81,9 +81,9 @@ def _osquery_cmd(table, attrs=None, where=None, format="json"): for a in attrs: if a not in valid_attrs: ret["result"] = False - ret[ - "comment" - ] = "{} is not a valid attribute for table {}".format(a, table) + ret["comment"] = ( + "{} is not a valid attribute for table {}".format(a, table) + ) return ret _attrs = ",".join(attrs) else: diff --git a/salt/modules/pacmanpkg.py b/salt/modules/pacmanpkg.py index 88336f6957a..25ed1177d9d 100644 --- a/salt/modules/pacmanpkg.py +++ b/salt/modules/pacmanpkg.py @@ -8,6 +8,7 @@ A module to wrap pacman calls, since Arch is the best *'pkg.install' is not available*), see :ref:`here `. """ + import copy import fnmatch import logging @@ -363,7 +364,6 @@ def group_info(name): def group_diff(name): - """ .. versionadded:: 2016.11.0 diff --git a/salt/modules/panos.py b/salt/modules/panos.py index 64be78723de..f5e22d268be 100644 --- a/salt/modules/panos.py +++ b/salt/modules/panos.py @@ -27,7 +27,6 @@ through the XML API or through a brokered connection to Panorama. """ - import logging import time diff --git a/salt/modules/pcs.py b/salt/modules/pcs.py index 4e3c74158a3..8225206f51c 100644 --- a/salt/modules/pcs.py +++ b/salt/modules/pcs.py @@ -10,7 +10,6 @@ Pacemaker/Cororsync conifguration system (PCS) .. versionadded:: 2016.3.0 """ - import logging import salt.utils.path diff --git a/salt/modules/pf.py b/salt/modules/pf.py index c463e1ce50f..3a52257c8cf 100644 --- a/salt/modules/pf.py +++ b/salt/modules/pf.py @@ -6,7 +6,6 @@ Control the OpenBSD packet filter (PF). .. versionadded:: 2019.2.0 """ - import logging import re diff --git a/salt/modules/pip.py b/salt/modules/pip.py index ebe51b85474..aa58d230bec 100644 --- a/salt/modules/pip.py +++ b/salt/modules/pip.py @@ -872,9 +872,13 @@ def install( if download_cache or cache_dir: cmd.extend( [ - "--cache-dir" - if salt.utils.versions.compare(ver1=cur_version, oper=">=", ver2="6.0") - else "--download-cache", + ( + "--cache-dir" + if salt.utils.versions.compare( + ver1=cur_version, oper=">=", ver2="6.0" + ) + else "--download-cache" + ), download_cache or cache_dir, ] ) diff --git a/salt/modules/pkg_resource.py b/salt/modules/pkg_resource.py index 578e53da30d..6308641a2f9 100644 --- a/salt/modules/pkg_resource.py +++ b/salt/modules/pkg_resource.py @@ -2,7 +2,6 @@ Resources needed by pkg providers """ - import copy import fnmatch import logging diff --git a/salt/modules/pkgng.py b/salt/modules/pkgng.py index 8becb90cc91..e5f94b7c297 100644 --- a/salt/modules/pkgng.py +++ b/salt/modules/pkgng.py @@ -2018,9 +2018,9 @@ def unhold(name=None, pkgs=None, **kwargs): # pylint: disable=W0613 ret[target]["changes"]["new"] = "" ret[target]["changes"]["old"] = "hold" else: - ret[target][ - "comment" - ] = "Package {} was unable to be unheld.".format(target) + ret[target]["comment"] = ( + "Package {} was unable to be unheld.".format(target) + ) else: ret[target].update(result=True) ret[target]["comment"] = "Package {} is not being held.".format(target) diff --git a/salt/modules/postfix.py b/salt/modules/postfix.py index aa67793fafe..64059bfe44b 100644 --- a/salt/modules/postfix.py +++ b/salt/modules/postfix.py @@ -456,17 +456,17 @@ def hold(queue_id): if queue_id == "ALL": ret["message"] = "Successfully placed all messages on hold" else: - ret[ - "message" - ] = "Successfully placed message on hold with queue id {}".format(queue_id) + ret["message"] = ( + "Successfully placed message on hold with queue id {}".format(queue_id) + ) else: if queue_id == "ALL": ret["message"] = "Unable to place all messages on hold" else: - ret[ - "message" - ] = "Unable to place message on hold with queue id {}: {}".format( - queue_id, result["stderr"] + ret["message"] = ( + "Unable to place message on hold with queue id {}: {}".format( + queue_id, result["stderr"] + ) ) return ret @@ -509,17 +509,17 @@ def unhold(queue_id): if queue_id == "ALL": ret["message"] = "Successfully set all message as unheld" else: - ret[ - "message" - ] = "Successfully set message as unheld with queue id {}".format(queue_id) + ret["message"] = ( + "Successfully set message as unheld with queue id {}".format(queue_id) + ) else: if queue_id == "ALL": ret["message"] = "Unable to set all message as unheld." else: - ret[ - "message" - ] = "Unable to set message as unheld with queue id {}: {}".format( - queue_id, result["stderr"] + ret["message"] = ( + "Unable to set message as unheld with queue id {}: {}".format( + queue_id, result["stderr"] + ) ) return ret diff --git a/salt/modules/proxy.py b/salt/modules/proxy.py index 370bd3eab93..1aa5dc9f2c6 100644 --- a/salt/modules/proxy.py +++ b/salt/modules/proxy.py @@ -6,7 +6,6 @@ This module allows you to manage proxy settings salt '*' network.get_http_proxy """ - import logging import re diff --git a/salt/modules/ps.py b/salt/modules/ps.py index 643764a1342..a6b23c500d0 100644 --- a/salt/modules/ps.py +++ b/salt/modules/ps.py @@ -5,7 +5,6 @@ See http://code.google.com/p/psutil. :depends: - python-utmp package (optional) """ - import datetime import re import time diff --git a/salt/modules/puppet.py b/salt/modules/puppet.py index b97eaa3ff60..8fd1e994c7e 100644 --- a/salt/modules/puppet.py +++ b/salt/modules/puppet.py @@ -2,7 +2,6 @@ Execute puppet routines """ - import datetime import logging import os diff --git a/salt/modules/pushbullet.py b/salt/modules/pushbullet.py index b716e667d04..ff58bbda489 100644 --- a/salt/modules/pushbullet.py +++ b/salt/modules/pushbullet.py @@ -21,7 +21,6 @@ For example: """ - import logging try: diff --git a/salt/modules/pushover_notify.py b/salt/modules/pushover_notify.py index 43f2f237009..2a0f2e3ecf3 100644 --- a/salt/modules/pushover_notify.py +++ b/salt/modules/pushover_notify.py @@ -15,7 +15,6 @@ Module for sending messages to Pushover (https://www.pushover.net) token: abAHuZyCLtdH8P4zhmFZmgUHUsv1ei8 """ - import logging import urllib.parse diff --git a/salt/modules/qemu_nbd.py b/salt/modules/qemu_nbd.py index 9a76d68cad5..c27bde15a78 100644 --- a/salt/modules/qemu_nbd.py +++ b/salt/modules/qemu_nbd.py @@ -5,7 +5,6 @@ The qemu system comes with powerful tools, such as qemu-img and qemu-nbd which are used here to build up kvm images. """ - import glob import logging import os diff --git a/salt/modules/rallydev.py b/salt/modules/rallydev.py index 6461fb133f5..219d0ab2baa 100644 --- a/salt/modules/rallydev.py +++ b/salt/modules/rallydev.py @@ -12,7 +12,6 @@ Requires a ``username`` and a ``password`` in ``/etc/salt/minion``: password: 123pass """ - import logging import salt.utils.http diff --git a/salt/modules/random_org.py b/salt/modules/random_org.py index 494c323eba5..f5d39cfbeaa 100644 --- a/salt/modules/random_org.py +++ b/salt/modules/random_org.py @@ -15,6 +15,7 @@ Module for retrieving random information from Random.org api_key: 7be1402d-5719-5bd3-a306-3def9f135da5 api_version: 1 """ + import http.client import logging import urllib.request @@ -218,9 +219,9 @@ def generateIntegers(api_key=None, api_version=None, **kwargs): or not -1000000000 <= kwargs["minimum"] <= 1000000000 ): ret["res"] = False - ret[ - "message" - ] = "Minimum argument must be between -1,000,000,000 and 1,000,000,000" + ret["message"] = ( + "Minimum argument must be between -1,000,000,000 and 1,000,000,000" + ) return ret if ( @@ -228,9 +229,9 @@ def generateIntegers(api_key=None, api_version=None, **kwargs): or not -1000000000 <= kwargs["maximum"] <= 1000000000 ): ret["res"] = False - ret[ - "message" - ] = "Maximum argument must be between -1,000,000,000 and 1,000,000,000" + ret["message"] = ( + "Maximum argument must be between -1,000,000,000 and 1,000,000,000" + ) return ret if "base" in kwargs: @@ -614,9 +615,9 @@ def generateGaussians(api_key=None, api_version=None, **kwargs): or not -1000000 <= kwargs["standardDeviation"] <= 1000000 ): ret["res"] = False - ret[ - "message" - ] = "The distribution's standard deviation must be between -1000000 and 1000000" + ret["message"] = ( + "The distribution's standard deviation must be between -1000000 and 1000000" + ) return ret if ( diff --git a/salt/modules/rbenv.py b/salt/modules/rbenv.py index e0bc1e82503..b41ed1e8909 100644 --- a/salt/modules/rbenv.py +++ b/salt/modules/rbenv.py @@ -9,7 +9,6 @@ http://misheska.com/blog/2013/06/15/using-rbenv-to-manage-multiple-versions-of-r .. versionadded:: 0.16.0 """ - import logging import os import re diff --git a/salt/modules/reg.py b/salt/modules/reg.py index 229998e27a9..5184d0423e2 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -64,6 +64,7 @@ Value: :depends: - salt.utils.win_reg """ + # When production windows installer is using Python 3, Python 2 code can be removed import logging diff --git a/salt/modules/restartcheck.py b/salt/modules/restartcheck.py index 287b9bd3b38..b2a2a30bb66 100644 --- a/salt/modules/restartcheck.py +++ b/salt/modules/restartcheck.py @@ -9,6 +9,7 @@ https://packages.debian.org/debian-goodies) and psdel by Sam Morris. :codeauthor: Jiri Kotlin """ + import os import re import subprocess diff --git a/salt/modules/restconf.py b/salt/modules/restconf.py index 3007adc225d..1a2d4f7799c 100644 --- a/salt/modules/restconf.py +++ b/salt/modules/restconf.py @@ -7,7 +7,6 @@ Execution module for RESTCONF Proxy minions """ - import logging __proxyenabled__ = ["restconf"] diff --git a/salt/modules/rh_ip.py b/salt/modules/rh_ip.py index e476bbd3f6e..b6ee34846e2 100644 --- a/salt/modules/rh_ip.py +++ b/salt/modules/rh_ip.py @@ -372,7 +372,6 @@ def _parse_settings_bond_0(opts, iface): def _parse_settings_bond_1(opts, iface): - """ Filters given options and outputs valid settings for bond1. If an option has a value that is not expected, this @@ -418,7 +417,6 @@ def _parse_settings_bond_2(opts, iface): def _parse_settings_bond_3(opts, iface): - """ Filters given options and outputs valid settings for bond3. If an option has a value that is not expected, this @@ -491,7 +489,6 @@ def _parse_settings_bond_4(opts, iface): def _parse_settings_bond_5(opts, iface): - """ Filters given options and outputs valid settings for bond5. If an option has a value that is not expected, this @@ -511,7 +508,6 @@ def _parse_settings_bond_5(opts, iface): def _parse_settings_bond_6(opts, iface): - """ Filters given options and outputs valid settings for bond6. If an option has a value that is not expected, this @@ -531,7 +527,6 @@ def _parse_settings_bond_6(opts, iface): def _parse_settings_vlan(opts, iface): - """ Filters given options and outputs valid settings for a vlan """ diff --git a/salt/modules/rpmbuild_pkgbuild.py b/salt/modules/rpmbuild_pkgbuild.py index 1532817222f..9d205392b1b 100644 --- a/salt/modules/rpmbuild_pkgbuild.py +++ b/salt/modules/rpmbuild_pkgbuild.py @@ -9,7 +9,6 @@ environments. This also provides a function to generate yum repositories This module implements the pkgbuild interface """ - import errno import functools import logging diff --git a/salt/modules/salt_version.py b/salt/modules/salt_version.py index 99dae5f61a5..56dde8f708c 100644 --- a/salt/modules/salt_version.py +++ b/salt/modules/salt_version.py @@ -30,7 +30,6 @@ A simple example might be something like the following: """ - import logging import salt.utils.versions diff --git a/salt/modules/saltcheck.py b/salt/modules/saltcheck.py index 99672a3c133..77a010f3fb1 100644 --- a/salt/modules/saltcheck.py +++ b/salt/modules/saltcheck.py @@ -297,7 +297,6 @@ Supported assertions ``saltcheck.run_highstate_tests`` are needed. """ - import copy import logging import multiprocessing @@ -879,12 +878,12 @@ class SaltCheck: else: assertion_section_repr_title = "" assertion_section_repr_value = "" - value[ - "module.function [args]{}".format(assertion_section_repr_title) - ] = "{} {}{}".format( - mod_and_func, - dumps(args), - assertion_section_repr_value, + value["module.function [args]{}".format(assertion_section_repr_title)] = ( + "{} {}{}".format( + mod_and_func, + dumps(args), + assertion_section_repr_value, + ) ) value["saltcheck assertion"] = "{}{} {}".format( ("" if expected_return is None else "{} ".format(expected_return)), diff --git a/salt/modules/saltutil.py b/salt/modules/saltutil.py index dd3c89908c6..57b18d007f9 100644 --- a/salt/modules/saltutil.py +++ b/salt/modules/saltutil.py @@ -5,6 +5,7 @@ minion. :depends: - esky Python module for update functionality """ + import copy import fnmatch import logging @@ -1533,7 +1534,7 @@ def regen_keys(): path = os.path.join(__opts__["pki_dir"], fn_) try: os.remove(path) - except os.error: + except OSError: pass # TODO: move this into a channel function? Or auth? # create a channel again, this will force the key regen @@ -1639,9 +1640,11 @@ def _exec( old_ret, fcn_ret = fcn_ret, {} for key, value in old_ret.items(): fcn_ret[key] = { - "out": value.get("out", "highstate") - if isinstance(value, dict) - else "highstate", + "out": ( + value.get("out", "highstate") + if isinstance(value, dict) + else "highstate" + ), "ret": value, } diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index b8553bc6f78..1fab2038924 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -7,7 +7,6 @@ Requires that python-dateutil is installed on the minion. """ - import copy as pycopy import datetime import logging @@ -425,10 +424,10 @@ def delete(name, **kwargs): ) ret["changes"][name] = "removed" else: - ret[ - "comment" - ] = "Failed to delete job {} from schedule.".format( - name + ret["comment"] = ( + "Failed to delete job {} from schedule.".format( + name + ) ) return ret except KeyError: @@ -908,9 +907,9 @@ def enable_job(name, **kwargs): ret["changes"][name] = "enabled" else: ret["result"] = False - ret[ - "comment" - ] = "Failed to enable job {} in schedule.".format(name) + ret["comment"] = ( + "Failed to enable job {} in schedule.".format(name) + ) return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -971,9 +970,9 @@ def disable_job(name, **kwargs): ret["changes"][name] = "disabled" else: ret["result"] = False - ret[ - "comment" - ] = "Failed to disable job {} in schedule.".format(name) + ret["comment"] = ( + "Failed to disable job {} in schedule.".format(name) + ) return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -1397,9 +1396,9 @@ def postpone_job(name, current_time, new_time, **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to postpone job {} in schedule.".format(name) + ret["comment"] = ( + "Failed to postpone job {} in schedule.".format(name) + ) return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -1486,9 +1485,9 @@ def skip_job(name, current_time, **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to skip job {} in schedule.".format(name) + ret["comment"] = ( + "Failed to skip job {} in schedule.".format(name) + ) return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -1528,9 +1527,9 @@ def show_next_fire_time(name, **kwargs): except KeyError: # Effectively a no-op, since we can't really return without an event system ret = {} - ret[ - "comment" - ] = "Event module not available. Schedule show next fire time failed." + ret["comment"] = ( + "Event module not available. Schedule show next fire time failed." + ) ret["result"] = True return ret @@ -1555,9 +1554,11 @@ def job_status(name, time_fmt="%Y-%m-%dT%H:%M:%S"): def convert_datetime_objects_in_dict_to_string(data_dict, time_fmt): return { - key: value.strftime(time_fmt) - if isinstance(value, datetime.datetime) - else value + key: ( + value.strftime(time_fmt) + if isinstance(value, datetime.datetime) + else value + ) for key, value in data_dict.items() } diff --git a/salt/modules/scp_mod.py b/salt/modules/scp_mod.py index 4121bdbf4a7..e193b1c9816 100644 --- a/salt/modules/scp_mod.py +++ b/salt/modules/scp_mod.py @@ -55,7 +55,7 @@ def _prepare_connection(**kwargs): paramiko_kwargs, scp_kwargs = _select_kwargs(**kwargs) ssh = paramiko.SSHClient() if paramiko_kwargs.pop("auto_add_policy", False): - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # nosec ssh.connect(**paramiko_kwargs) scp_client = scp.SCPClient(ssh.get_transport(), **scp_kwargs) return scp_client diff --git a/salt/modules/sdb.py b/salt/modules/sdb.py index 6dc4457b1f8..1182d6dc934 100644 --- a/salt/modules/sdb.py +++ b/salt/modules/sdb.py @@ -3,7 +3,6 @@ Module for Manipulating Data via the Salt DB API ================================================ """ - import salt.utils.sdb __func_alias__ = { diff --git a/salt/modules/seed.py b/salt/modules/seed.py index 7b985249cac..9bce998fd38 100644 --- a/salt/modules/seed.py +++ b/salt/modules/seed.py @@ -2,7 +2,6 @@ Virtual machine image management tools """ - import logging import os import shutil diff --git a/salt/modules/selinux.py b/salt/modules/selinux.py index 552ec282ff2..71dae99a7a0 100644 --- a/salt/modules/selinux.py +++ b/salt/modules/selinux.py @@ -10,7 +10,6 @@ Execute calls on selinux proper packages are installed. """ - import os import re diff --git a/salt/modules/sensehat.py b/salt/modules/sensehat.py index d5ba0b5f1f1..404f469933d 100644 --- a/salt/modules/sensehat.py +++ b/salt/modules/sensehat.py @@ -19,7 +19,6 @@ Example: """ - import logging try: diff --git a/salt/modules/serverdensity_device.py b/salt/modules/serverdensity_device.py index f55815fb07a..23c228ea706 100644 --- a/salt/modules/serverdensity_device.py +++ b/salt/modules/serverdensity_device.py @@ -5,7 +5,6 @@ Wrapper around Server Density API .. versionadded:: 2014.7.0 """ - import logging import os import tempfile diff --git a/salt/modules/slack_notify.py b/salt/modules/slack_notify.py index d0d32fabe18..9ac29929bd6 100644 --- a/salt/modules/slack_notify.py +++ b/salt/modules/slack_notify.py @@ -15,7 +15,6 @@ Module for sending messages to Slack api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15 """ - import logging import urllib.parse diff --git a/salt/modules/slsutil.py b/salt/modules/slsutil.py index fe7ba15f336..df78b727f79 100644 --- a/salt/modules/slsutil.py +++ b/salt/modules/slsutil.py @@ -2,7 +2,6 @@ Utility functions for use with or in SLS files """ - import os import posixpath import textwrap diff --git a/salt/modules/smartos_nictagadm.py b/salt/modules/smartos_nictagadm.py index 99d09826e28..9112b44efa9 100644 --- a/salt/modules/smartos_nictagadm.py +++ b/salt/modules/smartos_nictagadm.py @@ -170,9 +170,11 @@ def add(name, mac, mtu=1500): return True else: return { - "Error": "failed to create nictag." - if "stderr" not in res and res["stderr"] == "" - else res["stderr"] + "Error": ( + "failed to create nictag." + if "stderr" not in res and res["stderr"] == "" + else res["stderr"] + ) } @@ -226,9 +228,11 @@ def update(name, mac=None, mtu=None): return True else: return { - "Error": "failed to update nictag." - if "stderr" not in res and res["stderr"] == "" - else res["stderr"] + "Error": ( + "failed to update nictag." + if "stderr" not in res and res["stderr"] == "" + else res["stderr"] + ) } @@ -259,7 +263,9 @@ def delete(name, force=False): return True else: return { - "Error": "failed to delete nictag." - if "stderr" not in res and res["stderr"] == "" - else res["stderr"] + "Error": ( + "failed to delete nictag." + if "stderr" not in res and res["stderr"] == "" + else res["stderr"] + ) } diff --git a/salt/modules/smf_service.py b/salt/modules/smf_service.py index 5c3d948b9d9..f45ba48af75 100644 --- a/salt/modules/smf_service.py +++ b/salt/modules/smf_service.py @@ -9,7 +9,6 @@ that use SMF also. (e.g. SmartOS) `. """ - import fnmatch import re diff --git a/salt/modules/smtp.py b/salt/modules/smtp.py index 8eaa6bb0a73..acfa0d0d639 100644 --- a/salt/modules/smtp.py +++ b/salt/modules/smtp.py @@ -40,7 +40,6 @@ Module for Sending Messages via SMTP """ - import logging import os import socket diff --git a/salt/modules/snapper.py b/salt/modules/snapper.py index 4968dbc329d..f5781a1a64f 100644 --- a/salt/modules/snapper.py +++ b/salt/modules/snapper.py @@ -11,6 +11,7 @@ Module to manage filesystem snapshots with snapper :maturity: new :platform: Linux """ + import difflib import logging import os @@ -524,9 +525,9 @@ def modify_snapshot( try: # Updating only the explicitly provided attributes by the user updated_opts = { - "description": description - if description is not None - else snapshot["description"], + "description": ( + description if description is not None else snapshot["description"] + ), "cleanup": cleanup if cleanup is not None else snapshot["cleanup"], "userdata": userdata if userdata is not None else snapshot["userdata"], } diff --git a/salt/modules/solaris_user.py b/salt/modules/solaris_user.py index e8d7d0b2bc4..f2c45f809b5 100644 --- a/salt/modules/solaris_user.py +++ b/salt/modules/solaris_user.py @@ -10,7 +10,6 @@ Manage users with the useradd command """ - import copy import logging diff --git a/salt/modules/solr.py b/salt/modules/solr.py index 373aee65b20..fca581922f1 100644 --- a/salt/modules/solr.py +++ b/salt/modules/solr.py @@ -58,7 +58,6 @@ verbose : True Get verbose output """ - import os import urllib.request diff --git a/salt/modules/splunk_search.py b/salt/modules/splunk_search.py index be9a50c28e5..e0d101cb2f3 100644 --- a/salt/modules/splunk_search.py +++ b/salt/modules/splunk_search.py @@ -286,7 +286,7 @@ def list_all( d = [{"name": name}] # add the rest of the splunk settings, ignoring any defaults description = "" - for (k, v) in sorted(search.content.items()): + for k, v in sorted(search.content.items()): if k in readonly_keys: continue if k.startswith("display."): diff --git a/salt/modules/state.py b/salt/modules/state.py index ca86bcc62dc..20e1e67a24b 100644 --- a/salt/modules/state.py +++ b/salt/modules/state.py @@ -2345,7 +2345,7 @@ def pkg(pkg_path, pkg_sum, hash_type, test=None, **kwargs): return {} elif "..{}".format(os.sep) in salt.utils.stringutils.to_unicode(member.path): return {} - s_pkg.extractall(root) + s_pkg.extractall(root) # nosec s_pkg.close() lowstate_json = os.path.join(root, "lowstate.json") with salt.utils.files.fopen(lowstate_json, "r") as fp_: diff --git a/salt/modules/statuspage.py b/salt/modules/statuspage.py index 0bfbd2798e0..4670d628151 100644 --- a/salt/modules/statuspage.py +++ b/salt/modules/statuspage.py @@ -18,7 +18,6 @@ In the minion configuration file, the following block is required: .. versionadded:: 2017.7.0 """ - import logging # import third party diff --git a/salt/modules/supervisord.py b/salt/modules/supervisord.py index eee4a9f42cf..90754afc70a 100644 --- a/salt/modules/supervisord.py +++ b/salt/modules/supervisord.py @@ -3,7 +3,6 @@ Provide the service module for system supervisord or supervisord in a virtualenv """ - import configparser import os diff --git a/salt/modules/syslog_ng.py b/salt/modules/syslog_ng.py index 9e8e8829df7..5df09f233b4 100644 --- a/salt/modules/syslog_ng.py +++ b/salt/modules/syslog_ng.py @@ -24,7 +24,6 @@ configuration file. """ - import logging import os import os.path diff --git a/salt/modules/system_profiler.py b/salt/modules/system_profiler.py index 5cbb4998a8c..aa3af692a37 100644 --- a/salt/modules/system_profiler.py +++ b/salt/modules/system_profiler.py @@ -8,7 +8,6 @@ information about package receipts and installed applications. """ - import plistlib import subprocess diff --git a/salt/modules/textfsm_mod.py b/salt/modules/textfsm_mod.py index 0e0d390b87d..bcade66de15 100644 --- a/salt/modules/textfsm_mod.py +++ b/salt/modules/textfsm_mod.py @@ -195,20 +195,20 @@ def extract(template_path, raw_text=None, raw_text_file=None, saltenv="base"): fsm_handler = textfsm.TextFSM(tpl_file_handle) except textfsm.TextFSMTemplateError as tfte: log.error("Unable to parse the TextFSM template", exc_info=True) - ret[ - "comment" - ] = "Unable to parse the TextFSM template from {}: {}. Please check the logs.".format( - template_path, tfte + ret["comment"] = ( + "Unable to parse the TextFSM template from {}: {}. Please check the logs.".format( + template_path, tfte + ) ) return ret if not raw_text and raw_text_file: log.debug("Trying to read the raw input from %s", raw_text_file) raw_text = __salt__["cp.get_file_str"](raw_text_file, saltenv=saltenv) if raw_text is False: - ret[ - "comment" - ] = "Unable to read from {}. Please specify a valid input file or text.".format( - raw_text_file + ret["comment"] = ( + "Unable to read from {}. Please specify a valid input file or text.".format( + raw_text_file + ) ) log.error(ret["comment"]) return ret @@ -393,17 +393,17 @@ def index( ) platform = __grains__.get(platform_grain_name) if not platform: - ret[ - "comment" - ] = "Unable to identify the platform name using the {} grain.".format( - platform_grain_name + ret["comment"] = ( + "Unable to identify the platform name using the {} grain.".format( + platform_grain_name + ) ) return ret log.info("Using platform: %s", platform) else: - ret[ - "comment" - ] = "No platform specified, no platform grain identifier configured." + ret["comment"] = ( + "No platform specified, no platform grain identifier configured." + ) log.error(ret["comment"]) return ret if not textfsm_path: @@ -431,10 +431,10 @@ def index( ) log.debug("Cache fun return:\n%s", textfsm_cachedir_ret) if not textfsm_cachedir_ret: - ret[ - "comment" - ] = "Unable to fetch from {}. Is the TextFSM path correctly specified?".format( - textfsm_path + ret["comment"] = ( + "Unable to fetch from {}. Is the TextFSM path correctly specified?".format( + textfsm_path + ) ) log.error(ret["comment"]) return ret @@ -457,10 +457,10 @@ def index( log.debug("Processing the output from %s", output_file) output = __salt__["cp.get_file_str"](output_file, saltenv=saltenv) if output is False: - ret[ - "comment" - ] = "Unable to read from {}. Please specify a valid file or text.".format( - output_file + ret["comment"] = ( + "Unable to read from {}. Please specify a valid file or text.".format( + output_file + ) ) log.error(ret["comment"]) return ret diff --git a/salt/modules/timezone.py b/salt/modules/timezone.py index 4904c8dcc6e..26d37943987 100644 --- a/salt/modules/timezone.py +++ b/salt/modules/timezone.py @@ -2,7 +2,6 @@ Module for managing timezone on POSIX-like systems. """ - import errno import filecmp import logging diff --git a/salt/modules/tls.py b/salt/modules/tls.py index b74b765cfbb..d54922a26c9 100644 --- a/salt/modules/tls.py +++ b/salt/modules/tls.py @@ -1929,10 +1929,10 @@ def revoke_cert( ) except ValueError: ret["retcode"] = 1 - ret[ - "comment" - ] = "Revocation date '{}' does not matchformat '{}'".format( - revoke_date, two_digit_year_fmt + ret["comment"] = ( + "Revocation date '{}' does not matchformat '{}'".format( + revoke_date, two_digit_year_fmt + ) ) return ret elif index_serial_subject in line: diff --git a/salt/modules/travisci.py b/salt/modules/travisci.py index 70672403b5b..100890e103a 100644 --- a/salt/modules/travisci.py +++ b/salt/modules/travisci.py @@ -3,6 +3,7 @@ Commands for working with travisci. :depends: pyOpenSSL >= 16.0.0 """ + import base64 import urllib.parse diff --git a/salt/modules/tuned.py b/salt/modules/tuned.py index 73742a9d54e..8db9ea83e98 100644 --- a/salt/modules/tuned.py +++ b/salt/modules/tuned.py @@ -7,7 +7,6 @@ Interface to Red Hat tuned-adm module :platform: Linux """ - import re import salt.utils.path diff --git a/salt/modules/uptime.py b/salt/modules/uptime.py index 294e91aeee4..34ebff403a1 100644 --- a/salt/modules/uptime.py +++ b/salt/modules/uptime.py @@ -3,7 +3,6 @@ Wrapper around uptime API ========================= """ - import logging from salt.exceptions import CommandExecutionError diff --git a/salt/modules/vault.py b/salt/modules/vault.py index 8abd7bb04d7..8dc2e5868d0 100644 --- a/salt/modules/vault.py +++ b/salt/modules/vault.py @@ -212,6 +212,7 @@ Functions to interact with Hashicorp Vault. .. _vault-setup: """ + import logging import os diff --git a/salt/modules/vboxmanage.py b/salt/modules/vboxmanage.py index 635734466a2..39ca6ecb3e6 100644 --- a/salt/modules/vboxmanage.py +++ b/salt/modules/vboxmanage.py @@ -15,7 +15,6 @@ The default for this setting is ``False``. :depends: virtualbox """ - import logging import os.path import re diff --git a/salt/modules/victorops.py b/salt/modules/victorops.py index c5288355579..3f41a0b8ba4 100644 --- a/salt/modules/victorops.py +++ b/salt/modules/victorops.py @@ -11,7 +11,6 @@ Requires an ``api_key`` in ``/etc/salt/minion``: api_key: '280d4699-a817-4719-ba6f-ca56e573e44f' """ - import datetime import logging import time diff --git a/salt/modules/virt.py b/salt/modules/virt.py index 0f11dbde206..f5c58f235a0 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -116,6 +116,7 @@ ZB 10**21 YB 10**24 ====== ======= """ + # Special Thanks to Michael Dehann, many of the concepts, and a few structures # of his in the virt func module have been used @@ -322,9 +323,9 @@ def _parse_qemu_img_info(info): "file format": disk_infos["format"], "disk size": disk_infos["actual-size"], "virtual size": disk_infos["virtual-size"], - "cluster size": disk_infos["cluster-size"] - if "cluster-size" in disk_infos - else None, + "cluster size": ( + disk_infos["cluster-size"] if "cluster-size" in disk_infos else None + ), } if "full-backing-filename" in disk_infos.keys(): @@ -554,9 +555,9 @@ def _get_disks(conn, dom): "file": backing_path.text } if backing_format is not None: - extra_properties["backing file"][ - "file format" - ] = backing_format.get("type") + extra_properties["backing file"]["file format"] = ( + backing_format.get("type") + ) except libvirt.libvirtError: # The volume won't be found if the pool is not started, just output less infos log.info( @@ -773,7 +774,7 @@ def _migrate(dom, dst_uri, **kwargs): "comp_xbzrle_cache": libvirt.VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, } - for (comp_option, param_key) in comp_options.items(): + for comp_option, param_key in comp_options.items(): comp_option_value = kwargs.get(comp_option) if comp_option_value: try: @@ -1297,9 +1298,11 @@ def _gen_pool_xml( ): source = { "devices": source_devices or [], - "dir": source_dir - if source_format != "cifs" or not source_dir - else source_dir.lstrip("/"), + "dir": ( + source_dir + if source_format != "cifs" or not source_dir + else source_dir.lstrip("/") + ), "adapter": source_adapter, "hosts": [ {"name": host[0], "port": host[1] if len(host) > 1 else None} @@ -2975,12 +2978,16 @@ def _nics_equal(nic1, nic2): } return { "type": source_type, - "source": source_getters[source_type](source_node) - if source_node is not None - else None, - "model": nic.find("model").attrib["type"] - if nic.find("model") is not None - else None, + "source": ( + source_getters[source_type](source_node) + if source_node is not None + else None + ), + "model": ( + nic.find("model").attrib["type"] + if nic.find("model") is not None + else None + ), } def _get_mac(nic): @@ -3228,12 +3235,16 @@ def _serial_or_concole_equal(old, new): """ return { "type": item.attrib["type"], - "port": item.find("source").get("service") - if item.find("source") is not None - else None, - "protocol": item.find("protocol").get("type") - if item.find("protocol") is not None - else None, + "port": ( + item.find("source").get("service") + if item.find("source") is not None + else None + ), + "protocol": ( + item.find("protocol").get("type") + if item.find("protocol") is not None + else None + ), } return _filter_serial_or_concole(old) == _filter_serial_or_concole(new) @@ -6438,15 +6449,19 @@ def _parse_caps_host(host): elif child.tag == "cpu": cpu = { - "arch": child.find("arch").text - if child.find("arch") is not None - else None, - "model": child.find("model").text - if child.find("model") is not None - else None, - "vendor": child.find("vendor").text - if child.find("vendor") is not None - else None, + "arch": ( + child.find("arch").text if child.find("arch") is not None else None + ), + "model": ( + child.find("model").text + if child.find("model") is not None + else None + ), + "vendor": ( + child.find("vendor").text + if child.find("vendor") is not None + else None + ), "features": [ feature.get("name") for feature in child.findall("feature") ], @@ -6492,12 +6507,14 @@ def _parse_caps_host(host): result["security"] = [ { - "model": secmodel.find("model").text - if secmodel.find("model") is not None - else None, - "doi": secmodel.find("doi").text - if secmodel.find("doi") is not None - else None, + "model": ( + secmodel.find("model").text + if secmodel.find("model") is not None + else None + ), + "doi": ( + secmodel.find("doi").text if secmodel.find("doi") is not None else None + ), "baselabels": [ {"type": label.get("type"), "label": label.text} for label in secmodel.findall("baselabel") @@ -6645,9 +6662,9 @@ def _parse_domain_caps(caps): result = { "emulator": caps.find("path").text if caps.find("path") is not None else None, "domain": caps.find("domain").text if caps.find("domain") is not None else None, - "machine": caps.find("machine").text - if caps.find("machine") is not None - else None, + "machine": ( + caps.find("machine").text if caps.find("machine") is not None else None + ), "arch": caps.find("arch").text if caps.find("arch") is not None else None, } @@ -8708,9 +8725,11 @@ def volume_infos(pool=None, volume=None, **kwargs): if backing_store_path is not None: backing_store = { "path": backing_store_path.text, - "format": backing_store_format.get("type") - if backing_store_format is not None - else None, + "format": ( + backing_store_format.get("type") + if backing_store_format is not None + else None + ), } format_node = vol_xml.find("./target/format") diff --git a/salt/modules/virtualenv_mod.py b/salt/modules/virtualenv_mod.py index 81c270196d2..e662b339214 100644 --- a/salt/modules/virtualenv_mod.py +++ b/salt/modules/virtualenv_mod.py @@ -4,7 +4,6 @@ Create virtualenv environments. .. versionadded:: 0.17.0 """ - import glob import logging import os diff --git a/salt/modules/vmctl.py b/salt/modules/vmctl.py index 6b3d7b8880c..01021c3225f 100644 --- a/salt/modules/vmctl.py +++ b/salt/modules/vmctl.py @@ -11,7 +11,6 @@ Manage vms running on the OpenBSD VMM hypervisor using vmctl(8). target machine. """ - import logging import re diff --git a/salt/modules/vsphere.py b/salt/modules/vsphere.py index 29aa68cf4da..95dc3e03c29 100644 --- a/salt/modules/vsphere.py +++ b/salt/modules/vsphere.py @@ -181,7 +181,6 @@ connection credentials are used instead of vCenter credentials, the ``host_names 6500 """ - import datetime import logging import sys @@ -9682,7 +9681,7 @@ def _create_scsi_devices(scsi_devices): log.trace("Creating SCSI devices %s", devs) # unitNumber for disk attachment, 0:0 1st 0 is the controller busNumber, # 2nd is the unitNumber - for (key, scsi_controller) in zip(keys, scsi_devices): + for key, scsi_controller in zip(keys, scsi_devices): # create the SCSI controller scsi_spec = _apply_scsi_controller( scsi_controller["adapter"], @@ -9730,9 +9729,9 @@ def _create_network_adapters(network_interfaces, parent=None): interface["switch_type"], network_adapter_label=interface["adapter"], operation="add", - connectable=interface["connectable"] - if "connectable" in interface - else None, + connectable=( + interface["connectable"] if "connectable" in interface else None + ), mac=interface["mac"], parent=parent, ) @@ -9800,15 +9799,17 @@ def _create_cd_drives(cd_drives, controllers=None, parent_ref=None): key, drive["device_type"], "add", - client_device=drive["client_device"] - if "client_device" in drive - else None, - datastore_iso_file=drive["datastore_iso_file"] - if "datastore_iso_file" in drive - else None, - connectable=drive["connectable"] - if "connectable" in drive - else None, + client_device=( + drive["client_device"] if "client_device" in drive else None + ), + datastore_iso_file=( + drive["datastore_iso_file"] + if "datastore_iso_file" in drive + else None + ), + connectable=( + drive["connectable"] if "connectable" in drive else None + ), controller_key=controller_key, parent_ref=parent_ref, ) @@ -10098,9 +10099,9 @@ def get_vm_config(name, datacenter=None, objects=True, service_instance=None): if isinstance(device, vim.vm.device.VirtualEthernetCard): interface = {} interface["adapter"] = device.deviceInfo.label - interface[ - "adapter_type" - ] = salt.utils.vmware.get_network_adapter_object_type(device) + interface["adapter_type"] = ( + salt.utils.vmware.get_network_adapter_object_type(device) + ) interface["connectable"] = { "allow_guest_control": device.connectable.allowGuestControl, "connected": device.connectable.connected, @@ -10438,12 +10439,16 @@ def _update_cd_drives(drives_old_new, controllers=None, parent=None): current_drive["key"], new_drive["device_type"], "edit", - client_device=new_drive["client_device"] - if "client_device" in new_drive - else None, - datastore_iso_file=new_drive["datastore_iso_file"] - if "datastore_iso_file" in new_drive - else None, + client_device=( + new_drive["client_device"] + if "client_device" in new_drive + else None + ), + datastore_iso_file=( + new_drive["datastore_iso_file"] + if "datastore_iso_file" in new_drive + else None + ), connectable=new_drive["connectable"], controller_key=controller_key, parent_ref=parent, diff --git a/salt/modules/webutil.py b/salt/modules/webutil.py index 42da8f330d4..746c9a7299b 100644 --- a/salt/modules/webutil.py +++ b/salt/modules/webutil.py @@ -7,7 +7,6 @@ The functions here will load inside the webutil module. This allows other functions that don't use htpasswd to use the webutil module name. """ - import logging import os diff --git a/salt/modules/win_autoruns.py b/salt/modules/win_autoruns.py index 14497199e25..940474138c1 100644 --- a/salt/modules/win_autoruns.py +++ b/salt/modules/win_autoruns.py @@ -3,7 +3,6 @@ Module for listing programs that automatically run on startup (very alpha...not tested on anything but my Win 7x64) """ - import os import salt.utils.platform diff --git a/salt/modules/win_dacl.py b/salt/modules/win_dacl.py index a084a75684f..d9114a56453 100644 --- a/salt/modules/win_dacl.py +++ b/salt/modules/win_dacl.py @@ -4,7 +4,6 @@ Manage DACLs on Windows :depends: - winreg Python module """ - import logging import os import re @@ -503,10 +502,10 @@ def add_ace(path, objectType, user, permission, acetype, propagation): ) ret["result"] = True except Exception as e: # pylint: disable=broad-except - ret[ - "comment" - ] = "An error occurred attempting to add the ace. The error was {}".format( - e + ret["comment"] = ( + "An error occurred attempting to add the ace. The error was {}".format( + e + ) ) ret["result"] = False return ret @@ -730,9 +729,9 @@ def _set_dacl_inheritance(path, objectType, inheritance=True, copy=True, clear=F ret["result"] = True except Exception as e: # pylint: disable=broad-except ret["result"] = False - ret[ - "comment" - ] = "Error attempting to set the inheritance. The error was {}.".format(e) + ret["comment"] = ( + "Error attempting to set the inheritance. The error was {}.".format(e) + ) return ret @@ -818,9 +817,9 @@ def check_inheritance(path, objectType, user=None): dacls = sd.GetSecurityDescriptorDacl() except Exception as e: # pylint: disable=broad-except ret["result"] = False - ret[ - "comment" - ] = "Error obtaining the Security Descriptor or DACL of the path: {}.".format(e) + ret["comment"] = ( + "Error obtaining the Security Descriptor or DACL of the path: {}.".format(e) + ) return ret for counter in range(0, dacls.GetAceCount()): diff --git a/salt/modules/win_event.py b/salt/modules/win_event.py index f813abb329a..d8d9bde990b 100644 --- a/salt/modules/win_event.py +++ b/salt/modules/win_event.py @@ -2,6 +2,7 @@ A module for working with the Windows Event log system. .. versionadded:: 3006.0 """ + # https://docs.microsoft.com/en-us/windows/win32/eventlog/event-logging import collections diff --git a/salt/modules/win_iis.py b/salt/modules/win_iis.py index 3a2500d637b..68f67c01d9c 100644 --- a/salt/modules/win_iis.py +++ b/salt/modules/win_iis.py @@ -8,6 +8,7 @@ Microsoft IIS site management via WebAdministration powershell module .. versionadded:: 2016.3.0 """ + import decimal import logging import os diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index 1875edad440..f387eeebeb3 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -41,6 +41,7 @@ Current known limitations - struct - salt.utils.win_reg """ + import csv import ctypes import glob @@ -6938,9 +6939,9 @@ def _checkAllAdmxPolicies( TRUE_VALUE_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = True + configured_elements[this_element_name] = ( + True + ) log.trace( "element %s is configured true", child_item.attrib["id"], @@ -6957,9 +6958,9 @@ def _checkAllAdmxPolicies( FALSE_VALUE_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = False + configured_elements[this_element_name] = ( + False + ) policy_disabled_elements = ( policy_disabled_elements + 1 ) @@ -6981,9 +6982,9 @@ def _checkAllAdmxPolicies( TRUE_LIST_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = True + configured_elements[this_element_name] = ( + True + ) log.trace( "element %s is configured true", child_item.attrib["id"], @@ -7000,9 +7001,9 @@ def _checkAllAdmxPolicies( FALSE_LIST_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = False + configured_elements[this_element_name] = ( + False + ) policy_disabled_elements = ( policy_disabled_elements + 1 ) @@ -7102,9 +7103,9 @@ def _checkAllAdmxPolicies( ), policy_file_data, ) - configured_elements[ - this_element_name - ] = configured_value + configured_elements[this_element_name] = ( + configured_value + ) log.trace( "element %s is enabled, value == %s", child_item.attrib["id"], @@ -7224,9 +7225,9 @@ def _checkAllAdmxPolicies( policy_file_data, return_value_name=return_value_name, ) - configured_elements[ - this_element_name - ] = configured_value + configured_elements[this_element_name] = ( + configured_value + ) log.trace( "element %s is enabled values: %s", child_item.attrib["id"], @@ -9402,23 +9403,23 @@ def _get_policy_adm_setting( log.trace( "all valueList items exist in file" ) - configured_elements[ - this_element_name - ] = _getAdmlDisplayName( + configured_elements[this_element_name] = ( + _getAdmlDisplayName( + adml_xml_data=adml_policy_resources, + display_name=enum_item.attrib[ + "displayName" + ], + ) + ) + break + else: + configured_elements[this_element_name] = ( + _getAdmlDisplayName( adml_xml_data=adml_policy_resources, display_name=enum_item.attrib[ "displayName" ], ) - break - else: - configured_elements[ - this_element_name - ] = _getAdmlDisplayName( - adml_xml_data=adml_policy_resources, - display_name=enum_item.attrib[ - "displayName" - ], ) break elif etree.QName(child_item).localname == "list": @@ -9553,12 +9554,12 @@ def _get_policy_adm_setting( this_policy_namespace in policy_vals and this_policy_name in policy_vals[this_policy_namespace] ): - hierarchy.setdefault(this_policy_namespace, {})[ - this_policy_name - ] = _build_parent_list( - policy_definition=admx_policy, - return_full_policy_names=return_full_policy_names, - adml_language=adml_language, + hierarchy.setdefault(this_policy_namespace, {})[this_policy_name] = ( + _build_parent_list( + policy_definition=admx_policy, + return_full_policy_names=return_full_policy_names, + adml_language=adml_language, + ) ) if policy_vals and return_full_policy_names and not hierarchical_return: diff --git a/salt/modules/win_lgpo_reg.py b/salt/modules/win_lgpo_reg.py index b3e1fef58e4..3ee147aa812 100644 --- a/salt/modules/win_lgpo_reg.py +++ b/salt/modules/win_lgpo_reg.py @@ -54,6 +54,7 @@ The same values can also be used to create states for setting these policies. you will have to find the values needed to set them with this module using a different method. """ + import logging import salt.utils.platform diff --git a/salt/modules/win_license.py b/salt/modules/win_license.py index 669521368ef..5311418abd0 100644 --- a/salt/modules/win_license.py +++ b/salt/modules/win_license.py @@ -6,7 +6,6 @@ This module allows you to manage windows licensing via slmgr.vbs salt '*' license.install XXXXX-XXXXX-XXXXX-XXXXX-XXXXX """ - import logging import re diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index fec5ab56a9c..bc421a1f9bd 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -36,7 +36,6 @@ old. """ - import collections import datetime import errno diff --git a/salt/modules/win_servermanager.py b/salt/modules/win_servermanager.py index f26ce42183d..cab3d996e82 100644 --- a/salt/modules/win_servermanager.py +++ b/salt/modules/win_servermanager.py @@ -7,7 +7,6 @@ available and installed roles/features. Can install and remove roles/features. :depends: PowerShell module ``ServerManager`` """ - import logging import shlex diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index f788f7559d9..604a22fd5bd 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -5,6 +5,7 @@ Windows Service module. Rewritten to use PyWin32 """ + import fnmatch import logging import re diff --git a/salt/modules/win_shortcut.py b/salt/modules/win_shortcut.py index 97048b45560..6bdb679d385 100644 --- a/salt/modules/win_shortcut.py +++ b/salt/modules/win_shortcut.py @@ -6,6 +6,7 @@ url shortcuts. .. versionadded:: 3005 """ + # https://docs.microsoft.com/en-us/troubleshoot/windows-client/admin-development/create-desktop-shortcut-with-wsh # https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/windows-scripting/f5y78918(v=vs.84) import logging diff --git a/salt/modules/win_status.py b/salt/modules/win_status.py index 033af16e063..8b349a79bcc 100644 --- a/salt/modules/win_status.py +++ b/salt/modules/win_status.py @@ -7,6 +7,7 @@ or for problem solving if your minion is having problems. :depends: - wmi """ + import ctypes import datetime import logging diff --git a/salt/modules/win_task.py b/salt/modules/win_task.py index 2e8750ddb97..2b23e381bc0 100644 --- a/salt/modules/win_task.py +++ b/salt/modules/win_task.py @@ -1582,9 +1582,9 @@ def info(name, location="\\"): trigger["repeat_interval"] = _reverse_lookup( duration, triggerObj.Repetition.Interval ) - trigger[ - "repeat_stop_at_duration_end" - ] = triggerObj.Repetition.StopAtDurationEnd + trigger["repeat_stop_at_duration_end"] = ( + triggerObj.Repetition.StopAtDurationEnd + ) triggers.append(trigger) properties["settings"] = settings diff --git a/salt/modules/win_timezone.py b/salt/modules/win_timezone.py index d8c3c82bb23..d95f7338bfe 100644 --- a/salt/modules/win_timezone.py +++ b/salt/modules/win_timezone.py @@ -1,6 +1,7 @@ """ Module for managing timezone on Windows systems. """ + import logging from datetime import datetime diff --git a/salt/modules/win_wua.py b/salt/modules/win_wua.py index 1393fc6efaf..9c4a0bc8f2d 100644 --- a/salt/modules/win_wua.py +++ b/salt/modules/win_wua.py @@ -54,6 +54,7 @@ Group Policy using the ``lgpo`` module. :depends: salt.utils.win_update """ + import logging import salt.utils.platform diff --git a/salt/modules/win_wusa.py b/salt/modules/win_wusa.py index e6a8730f009..c4c5f21ea01 100644 --- a/salt/modules/win_wusa.py +++ b/salt/modules/win_wusa.py @@ -8,7 +8,6 @@ Microsoft Update files management via wusa.exe .. versionadded:: 2018.3.4 """ - import logging import os diff --git a/salt/modules/winrepo.py b/salt/modules/winrepo.py index 12d4a0b4c5f..227e81ee2e8 100644 --- a/salt/modules/winrepo.py +++ b/salt/modules/winrepo.py @@ -6,6 +6,7 @@ Module to manage Windows software repo on a Standalone Minion For documentation on Salt's Windows Repo feature, see :ref:`here `. """ + import logging import os diff --git a/salt/modules/x509_v2.py b/salt/modules/x509_v2.py index f0b9b40130e..72e8f466bb7 100644 --- a/salt/modules/x509_v2.py +++ b/salt/modules/x509_v2.py @@ -132,6 +132,7 @@ Note that when a ``ca_server`` is involved, both peers must use the updated modu .. _x509-setup: """ + import base64 import copy import datetime @@ -733,9 +734,11 @@ def encode_certificate( else: cipher = serialization.BestAvailableEncryption(pkcs12_passphrase) crt_bytes = serialization.pkcs12.serialize_key_and_certificates( - name=salt.utils.stringutils.to_bytes(pkcs12_friendlyname) - if pkcs12_friendlyname - else None, + name=( + salt.utils.stringutils.to_bytes(pkcs12_friendlyname) + if pkcs12_friendlyname + else None + ), key=private_key, cert=cert, cas=append_certs, diff --git a/salt/modules/xmpp.py b/salt/modules/xmpp.py index 5e058ff1324..944ef5c92af 100644 --- a/salt/modules/xmpp.py +++ b/salt/modules/xmpp.py @@ -34,7 +34,6 @@ Module for Sending Messages via XMPP (a.k.a. Jabber) """ - import logging HAS_LIBS = False diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index fa8e0eeffe3..4e5cd8416d8 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -17,7 +17,6 @@ Support for YUM/DNF """ - import configparser import contextlib import datetime @@ -2411,9 +2410,9 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 ret[target]["changes"]["new"] = "" ret[target]["changes"]["old"] = "hold" else: - ret[target][ - "comment" - ] = "Package {} was unable to be unheld.".format(target) + ret[target]["comment"] = ( + "Package {} was unable to be unheld.".format(target) + ) else: ret[target].update(result=True) ret[target]["comment"] = "Package {} is not being held.".format(target) diff --git a/salt/modules/zcbuildout.py b/salt/modules/zcbuildout.py index 3552d580890..e4a8b36e403 100644 --- a/salt/modules/zcbuildout.py +++ b/salt/modules/zcbuildout.py @@ -22,7 +22,6 @@ You have those following methods: * buildout """ - import copy import logging import os @@ -190,9 +189,9 @@ def _encode_status(status): logs = status["logs_by_level"].get(logger, [])[:] if logs: for i, log in enumerate(logs): - status["logs_by_level"][logger][ - i - ] = salt.utils.stringutils.to_unicode(log) + status["logs_by_level"][logger][i] = ( + salt.utils.stringutils.to_unicode(log) + ) return status diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py index 9d16fcb0b1b..5d3404a4ab1 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -11,7 +11,6 @@ Package support for openSUSE via the zypper package manager """ - import configparser import datetime import errno @@ -2322,10 +2321,10 @@ def unhold(name=None, pkgs=None, root=None, **kwargs): lock_ver = lock_ver.lstrip("= ") if version and lock_ver != version: ret[target]["result"] = False - ret[target][ - "comment" - ] = "Unable to unhold package {} as it is held with the other version.".format( - target + ret[target]["comment"] = ( + "Unable to unhold package {} as it is held with the other version.".format( + target + ) ) else: removed.append( @@ -2892,10 +2891,10 @@ def download(*packages, **kwargs): if pkg_ret: failed = [pkg for pkg in packages if pkg not in pkg_ret] if failed: - pkg_ret[ - "_error" - ] = "The following package(s) failed to download: {}".format( - ", ".join(failed) + pkg_ret["_error"] = ( + "The following package(s) failed to download: {}".format( + ", ".join(failed) + ) ) return pkg_ret diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py index a89c1a19af0..c0275c127fe 100644 --- a/salt/netapi/__init__.py +++ b/salt/netapi/__init__.py @@ -2,7 +2,6 @@ Make api awesomeness """ - import copy import inspect import logging diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index 3a4571968b4..52334728242 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -898,9 +898,11 @@ def hypermedia_handler(*args, **kwargs): ret = { "status": cherrypy.response.status, - "return": "{}".format(traceback.format_exc()) - if cherrypy.config["debug"] - else "An unexpected error occurred", + "return": ( + "{}".format(traceback.format_exc()) + if cherrypy.config["debug"] + else "An unexpected error occurred" + ), } # Raises 406 if requested content-type is not supported @@ -1747,9 +1749,9 @@ class Keys(LowDataAdapter): tarball.close() headers = cherrypy.response.headers - headers[ - "Content-Disposition" - ] = 'attachment; filename="saltkeys-{}.tar"'.format(lowstate[0]["id_"]) + headers["Content-Disposition"] = ( + 'attachment; filename="saltkeys-{}.tar"'.format(lowstate[0]["id_"]) + ) headers["Content-Type"] = "application/x-tar" headers["Content-Length"] = len(fileobj.getvalue()) headers["Cache-Control"] = "no-cache" diff --git a/salt/output/__init__.py b/salt/output/__init__.py index 32d0560772d..a8c318579df 100644 --- a/salt/output/__init__.py +++ b/salt/output/__init__.py @@ -3,7 +3,6 @@ Used to manage the outputter system. This package is the modular system used for managing outputters. """ - import errno import io import logging diff --git a/salt/output/highstate.py b/salt/output/highstate.py index 6c852554fc4..76ebac0d6d0 100644 --- a/salt/output/highstate.py +++ b/salt/output/highstate.py @@ -123,7 +123,6 @@ Example output with no special settings in configuration files: Total: 0 """ - import collections import logging import pprint diff --git a/salt/output/overstatestage.py b/salt/output/overstatestage.py index 3f80e0871f6..a8facfcb308 100644 --- a/salt/output/overstatestage.py +++ b/salt/output/overstatestage.py @@ -6,7 +6,6 @@ This outputter is used to display :ref:`Orchestrate Runner ` stages, and should not be called directly. """ - import salt.utils.color # [{'group2': {'match': ['fedora17-2', 'fedora17-3'], diff --git a/salt/output/pony.py b/salt/output/pony.py index f1d6d1e3d9a..60e47ba281a 100644 --- a/salt/output/pony.py +++ b/salt/output/pony.py @@ -46,7 +46,6 @@ CLI Example: salt '*' foo.bar --out=pony """ - import subprocess import salt.utils.data diff --git a/salt/output/progress.py b/salt/output/progress.py index 1d00a379cc4..302ce1f1467 100644 --- a/salt/output/progress.py +++ b/salt/output/progress.py @@ -2,7 +2,6 @@ Display return data as a progress bar """ - try: import progressbar diff --git a/salt/output/raw.py b/salt/output/raw.py index d2e68041180..a3005948e42 100644 --- a/salt/output/raw.py +++ b/salt/output/raw.py @@ -24,7 +24,6 @@ Example output: {'myminion': {'foo': {'list': ['Hello', 'World'], 'bar': 'baz', 'dictionary': {'abc': 123, 'def': 456}}}} """ - import salt.utils.stringutils diff --git a/salt/output/table_out.py b/salt/output/table_out.py index 730e0cb2df8..8bc94eb3e46 100644 --- a/salt/output/table_out.py +++ b/salt/output/table_out.py @@ -42,7 +42,6 @@ CLI Example: salt '*' foo.bar --out=table """ - import operator from functools import reduce # pylint: disable=redefined-builtin @@ -117,9 +116,9 @@ class TableDisplay: ) def wrap_onspace(self, text): - """ - When the text inside the column is longer then the width, will split by space and continue on the next line.""" + When the text inside the column is longer then the width, will split by space and continue on the next line. + """ def _truncate(line, word): return "{line}{part}{word}".format( @@ -136,7 +135,6 @@ class TableDisplay: return reduce(_truncate, text.split(" ")) def prepare_rows(self, rows, indent, has_header): - """Prepare rows content to be displayed.""" out = [] @@ -198,7 +196,6 @@ class TableDisplay: return out def display_rows(self, rows, labels, indent): - """Prepares row content and displays.""" out = [] @@ -245,7 +242,6 @@ class TableDisplay: return self.prepare_rows(labels_and_rows, indent + 4, has_header) def display(self, ret, indent, out, rows_key=None, labels_key=None): - """Display table(s).""" rows = [] diff --git a/salt/pillar/cmd_yamlex.py b/salt/pillar/cmd_yamlex.py index c014370f1d0..bf6d40a65fa 100644 --- a/salt/pillar/cmd_yamlex.py +++ b/salt/pillar/cmd_yamlex.py @@ -4,7 +4,6 @@ Execute a command and read the output as YAMLEX. The YAMLEX data is then directly overlaid onto the minion's Pillar data """ - import logging from salt.serializers.yamlex import deserialize diff --git a/salt/pillar/cobbler.py b/salt/pillar/cobbler.py index 5103d91f419..41425c12734 100644 --- a/salt/pillar/cobbler.py +++ b/salt/pillar/cobbler.py @@ -25,7 +25,7 @@ Module Documentation """ import logging -import xmlrpc.client +import xmlrpc.client # nosec __opts__ = { "cobbler.url": "http://localhost/cobbler_api", diff --git a/salt/pillar/consul_pillar.py b/salt/pillar/consul_pillar.py index 2b28b297353..3e4ff329329 100644 --- a/salt/pillar/consul_pillar.py +++ b/salt/pillar/consul_pillar.py @@ -315,7 +315,6 @@ def pillar_format(ret, keys, value, expand_keys): def get_conn(opts, profile): - """ Return a client object for accessing consul """ diff --git a/salt/pillar/ec2_pillar.py b/salt/pillar/ec2_pillar.py index e197940908b..c4fe8e17519 100644 --- a/salt/pillar/ec2_pillar.py +++ b/salt/pillar/ec2_pillar.py @@ -53,7 +53,6 @@ returns a list of key/value pairs for all of the EC2 tags assigned to the instance. """ - import logging import re diff --git a/salt/pillar/extra_minion_data_in_pillar.py b/salt/pillar/extra_minion_data_in_pillar.py index 170cdb6fa08..457c79462b0 100644 --- a/salt/pillar/extra_minion_data_in_pillar.py +++ b/salt/pillar/extra_minion_data_in_pillar.py @@ -27,6 +27,7 @@ Complete example in etc/salt/master include: """ + import logging # Set up logging diff --git a/salt/pillar/gpg.py b/salt/pillar/gpg.py index 28497a51f2c..8652a18b2a5 100644 --- a/salt/pillar/gpg.py +++ b/salt/pillar/gpg.py @@ -15,7 +15,6 @@ Set ``gpg_keydir`` in your config to adjust the homedir the renderer uses. """ - import salt.loader diff --git a/salt/pillar/hiera.py b/salt/pillar/hiera.py index 19e9c78c034..55b8305db72 100644 --- a/salt/pillar/hiera.py +++ b/salt/pillar/hiera.py @@ -2,7 +2,6 @@ Use hiera data as a Pillar source """ - import logging import salt.utils.path diff --git a/salt/pillar/http_json.py b/salt/pillar/http_json.py index f79f8655020..acebb3aaf89 100644 --- a/salt/pillar/http_json.py +++ b/salt/pillar/http_json.py @@ -48,7 +48,6 @@ Module Documentation ==================== """ - import logging import re import urllib.parse diff --git a/salt/pillar/http_yaml.py b/salt/pillar/http_yaml.py index 434d5b8a892..ff791c6cd8c 100644 --- a/salt/pillar/http_yaml.py +++ b/salt/pillar/http_yaml.py @@ -43,6 +43,7 @@ in <> brackets) in the url in order to populate pillar data based on the grain v Module Documentation ==================== """ + import logging import re import urllib.parse diff --git a/salt/pillar/libvirt.py b/salt/pillar/libvirt.py index 072293df251..ae957639b7d 100644 --- a/salt/pillar/libvirt.py +++ b/salt/pillar/libvirt.py @@ -4,6 +4,7 @@ generated using the libvirt key runner :depends: certtool """ + import os import subprocess diff --git a/salt/pillar/makostack.py b/salt/pillar/makostack.py index b689bd5f4cd..ef3b3d64cb5 100644 --- a/salt/pillar/makostack.py +++ b/salt/pillar/makostack.py @@ -372,7 +372,6 @@ You can also select a custom merging strategy using a ``__`` object in a list: +----------------+-------------------------+-------------------------+ """ - import functools import logging import os diff --git a/salt/pillar/nacl.py b/salt/pillar/nacl.py index 67f8c6fd25a..5e0a03512d7 100644 --- a/salt/pillar/nacl.py +++ b/salt/pillar/nacl.py @@ -18,7 +18,6 @@ Set ``nacl.config`` in your config. """ - import salt __virtualname__ = "nacl" diff --git a/salt/pillar/neutron.py b/salt/pillar/neutron.py index 738305b916b..2999f9a6b7c 100644 --- a/salt/pillar/neutron.py +++ b/salt/pillar/neutron.py @@ -42,7 +42,6 @@ name after the Keystone profile name: - neutron: my_openstack_config neutron_networks """ - import logging try: diff --git a/salt/pillar/reclass_adapter.py b/salt/pillar/reclass_adapter.py index 2f7e158ce75..f47b4c52de2 100644 --- a/salt/pillar/reclass_adapter.py +++ b/salt/pillar/reclass_adapter.py @@ -45,7 +45,6 @@ either let the master know via the ``PYTHONPATH`` environment variable, or by setting the configuration option, like in the example above. """ - # This file cannot be called reclass.py, because then the module import would # not work. Thanks to the __virtual__ function, however, the plugin still # responds to the name 'reclass'. diff --git a/salt/pillar/s3.py b/salt/pillar/s3.py index 6e97dfd33bd..7f08439f8e4 100644 --- a/salt/pillar/s3.py +++ b/salt/pillar/s3.py @@ -87,7 +87,6 @@ for each environment rather than specifying multiple_env. This is due to issue #22471 (https://github.com/saltstack/salt/issues/22471) """ - import logging import os import pickle @@ -144,7 +143,6 @@ def ext_pillar( path_style=False, https_enable=True, ): - """ Execute a command and read the output as YAML """ diff --git a/salt/pillar/saltclass.py b/salt/pillar/saltclass.py index 3354b1ae7ba..badf776eb0d 100644 --- a/salt/pillar/saltclass.py +++ b/salt/pillar/saltclass.py @@ -11,7 +11,6 @@ SaltClass Pillar Module For additional configuration instructions, see the :mod:`saltclass ` module """ - import logging import salt.utils.saltclass as sc diff --git a/salt/pillar/stack.py b/salt/pillar/stack.py index f5e2a07ea44..0d72444418d 100644 --- a/salt/pillar/stack.py +++ b/salt/pillar/stack.py @@ -373,6 +373,7 @@ You can also select a custom merging strategy using a ``__`` object in a list: | - root | - mat | | +----------------+-------------------------+-------------------------+ """ + import functools import glob import logging diff --git a/salt/pillar/varstack_pillar.py b/salt/pillar/varstack_pillar.py index 7f1d707b538..eebb12fda19 100644 --- a/salt/pillar/varstack_pillar.py +++ b/salt/pillar/varstack_pillar.py @@ -18,7 +18,6 @@ data to return as pillar information. From there you can take a look at the varstack on how this file is evaluated. """ - try: import varstack except ImportError: diff --git a/salt/pillar/vault.py b/salt/pillar/vault.py index 6388ab923dd..904c626b0e6 100644 --- a/salt/pillar/vault.py +++ b/salt/pillar/vault.py @@ -150,7 +150,6 @@ You can override the merging behavior per defined ext_pillar: merge_lists: false """ - import logging from requests.exceptions import HTTPError diff --git a/salt/proxy/cisconso.py b/salt/proxy/cisconso.py index aa97f37b1b5..8d9bd56c629 100644 --- a/salt/proxy/cisconso.py +++ b/salt/proxy/cisconso.py @@ -171,7 +171,6 @@ responding: salt test.ping """ - import logging from salt.exceptions import SaltSystemExit diff --git a/salt/proxy/esxcluster.py b/salt/proxy/esxcluster.py index 4448178398a..cbb15e587ff 100644 --- a/salt/proxy/esxcluster.py +++ b/salt/proxy/esxcluster.py @@ -149,6 +149,7 @@ Associated states are documented in Look there to find an example structure for Pillar as well as an example ``.sls`` file for configuring an ESX cluster from scratch. """ + import logging import os diff --git a/salt/proxy/esxdatacenter.py b/salt/proxy/esxdatacenter.py index 98b0be0e1d1..ff100786656 100644 --- a/salt/proxy/esxdatacenter.py +++ b/salt/proxy/esxdatacenter.py @@ -144,7 +144,6 @@ Look there to find an example structure for Pillar as well as an example ``.sls`` file for configuring an ESX datacenter from scratch. """ - import logging import os diff --git a/salt/proxy/esxi.py b/salt/proxy/esxi.py index af58e48185c..a7f6b1e90e4 100644 --- a/salt/proxy/esxi.py +++ b/salt/proxy/esxi.py @@ -277,7 +277,6 @@ for standing up an ESXi host from scratch. """ - import logging import os diff --git a/salt/proxy/esxvm.py b/salt/proxy/esxvm.py index ac46bdf304c..247aa078b47 100644 --- a/salt/proxy/esxvm.py +++ b/salt/proxy/esxvm.py @@ -144,7 +144,6 @@ Look there to find an example structure for Pillar as well as an example ``.sls`` file for configuring an ESX virtual machine from scratch. """ - import logging import os diff --git a/salt/proxy/rest_sample.py b/salt/proxy/rest_sample.py index 596e91494e3..4e66bbfd67e 100644 --- a/salt/proxy/rest_sample.py +++ b/salt/proxy/rest_sample.py @@ -192,7 +192,6 @@ def fix_outage(): def uptodate(name): - """ Call the REST endpoint to see if the packages on the "server" are up to date. """ @@ -205,7 +204,6 @@ def uptodate(name): def package_remove(name): - """ Remove a "package" on the REST server """ diff --git a/salt/proxy/restconf.py b/salt/proxy/restconf.py index d375894b368..31f214aa7cb 100644 --- a/salt/proxy/restconf.py +++ b/salt/proxy/restconf.py @@ -72,7 +72,6 @@ Proxy Pillar Example verify: false """ - import copy import json import logging diff --git a/salt/queues/pgjsonb_queue.py b/salt/queues/pgjsonb_queue.py index decade54234..aa42daa650d 100644 --- a/salt/queues/pgjsonb_queue.py +++ b/salt/queues/pgjsonb_queue.py @@ -38,7 +38,6 @@ Use the following Pg database schema: salt-run queue.process_queue test all backend=pgjsonb """ - import logging import sys from contextlib import contextmanager diff --git a/salt/renderers/cheetah.py b/salt/renderers/cheetah.py index d7351fa6af9..5cb8499e390 100644 --- a/salt/renderers/cheetah.py +++ b/salt/renderers/cheetah.py @@ -2,7 +2,6 @@ Cheetah Renderer for Salt """ - try: from Cheetah.Template import Template diff --git a/salt/renderers/dson.py b/salt/renderers/dson.py index 0a9597aa5f6..45d4f1ab252 100644 --- a/salt/renderers/dson.py +++ b/salt/renderers/dson.py @@ -11,7 +11,6 @@ This renderer requires `Dogeon`__ (installable via pip) .. __: https://github.com/soasme/dogeon """ - import logging try: diff --git a/salt/renderers/genshi.py b/salt/renderers/genshi.py index 9a9e57b6711..680da8bcbc7 100644 --- a/salt/renderers/genshi.py +++ b/salt/renderers/genshi.py @@ -2,7 +2,6 @@ Genshi Renderer for Salt """ - try: from genshi.template import MarkupTemplate # pylint: disable=no-name-in-module from genshi.template import NewTextTemplate # pylint: disable=no-name-in-module diff --git a/salt/renderers/gpg.py b/salt/renderers/gpg.py index 7218b613de5..f6569c6d637 100644 --- a/salt/renderers/gpg.py +++ b/salt/renderers/gpg.py @@ -335,7 +335,6 @@ In the Chlorine release, the default behavior will be reversed and an error message will be added to ``_errors`` by default. """ - import logging import os import re diff --git a/salt/renderers/hjson.py b/salt/renderers/hjson.py index f76f993dee6..84a7531af94 100644 --- a/salt/renderers/hjson.py +++ b/salt/renderers/hjson.py @@ -6,7 +6,6 @@ See the hjson_ documentation for more information .. _hjson: http://laktak.github.io/hjson/ """ - try: import hjson diff --git a/salt/renderers/jinja.py b/salt/renderers/jinja.py index 3ad9855805f..e19636dba00 100644 --- a/salt/renderers/jinja.py +++ b/salt/renderers/jinja.py @@ -4,7 +4,6 @@ Jinja loading utils to enable a more powerful backend for jinja templates .. include:: ../../../_incl/jinja_security.rst """ - import logging from io import StringIO diff --git a/salt/renderers/json.py b/salt/renderers/json.py index 36125685334..79d29fa6b37 100644 --- a/salt/renderers/json.py +++ b/salt/renderers/json.py @@ -2,7 +2,6 @@ JSON Renderer for Salt """ - import salt.utils.json json = salt.utils.json.import_json() diff --git a/salt/renderers/json5.py b/salt/renderers/json5.py index 9d4b345113f..ed8e96e5aa1 100644 --- a/salt/renderers/json5.py +++ b/salt/renderers/json5.py @@ -11,7 +11,6 @@ This renderer requires the `json5 python bindings`__, installable via pip. .. __: https://pypi.python.org/pypi/json5 """ - import logging try: diff --git a/salt/renderers/mako.py b/salt/renderers/mako.py index 01d413140ba..9032542f865 100644 --- a/salt/renderers/mako.py +++ b/salt/renderers/mako.py @@ -10,7 +10,6 @@ To install Mako, do the following: salt-pip install mako """ - import io import salt.utils.templates diff --git a/salt/renderers/nacl.py b/salt/renderers/nacl.py index 9cd2ba0f46b..6fa0351d45c 100644 --- a/salt/renderers/nacl.py +++ b/salt/renderers/nacl.py @@ -50,7 +50,6 @@ data like so: a-secret: "NACL[MRN3cc+fmdxyQbz6WMF+jq1hKdU5X5BBI7OjK+atvHo1ll+w1gZ7XyWtZVfq9gK9rQaMfkDxmidJKwE0Mw==]" """ - import logging import re diff --git a/salt/renderers/pass.py b/salt/renderers/pass.py index ba0f152c23e..12f7d47e833 100644 --- a/salt/renderers/pass.py +++ b/salt/renderers/pass.py @@ -75,7 +75,6 @@ Salt master configuration options pass_dir: """ - import logging import os from os.path import expanduser diff --git a/salt/renderers/pydsl.py b/salt/renderers/pydsl.py index 5cd74941bf2..996bbb13848 100644 --- a/salt/renderers/pydsl.py +++ b/salt/renderers/pydsl.py @@ -333,6 +333,7 @@ For example: my_mod = sys.modules['salt.loaded.ext.module.my_mod'] """ + import types import salt.utils.pydsl as pydsl diff --git a/salt/renderers/pyobjects.py b/salt/renderers/pyobjects.py index ad56246396b..f8de8d1f9e8 100644 --- a/salt/renderers/pyobjects.py +++ b/salt/renderers/pyobjects.py @@ -313,6 +313,7 @@ file ``samba/map.sls``, you could do the following. Service.running("samba", name=Samba.service) """ + # TODO: Interface for working with reactor files diff --git a/salt/renderers/stateconf.py b/salt/renderers/stateconf.py index c93a564f0ed..e65664754d8 100644 --- a/salt/renderers/stateconf.py +++ b/salt/renderers/stateconf.py @@ -5,6 +5,7 @@ A flexible renderer that takes a templating engine and a data format :maturity: new :platform: all """ + # See http://docs.saltstack.org/en/latest/ref/renderers/all/salt.renderers.stateconf.html # for a guide to using this module. # @@ -50,7 +51,7 @@ __opts__ = { # name of the state id for the generated start state. "stateconf_goal_state": ".goal", # name of the state id for the generated goal state. - "stateconf_state_func": "stateconf.set" + "stateconf_state_func": "stateconf.set", # names the state and the state function to be recognized as a special # state from which to gather sls file context variables. It should be # specified in the 'state.func' notation, and both the state module and diff --git a/salt/renderers/yaml.py b/salt/renderers/yaml.py index eb76a431372..cfc908bce19 100644 --- a/salt/renderers/yaml.py +++ b/salt/renderers/yaml.py @@ -4,7 +4,6 @@ YAML Renderer for Salt For YAML usage information see :ref:`Understanding YAML `. """ - import logging import warnings diff --git a/salt/returners/appoptics_return.py b/salt/returners/appoptics_return.py index c49d5e22e28..036112e11fa 100644 --- a/salt/returners/appoptics_return.py +++ b/salt/returners/appoptics_return.py @@ -69,7 +69,6 @@ the name of the state that was invoked, e.g. ``role_salt_master.netapi``. """ - import logging import salt.returners diff --git a/salt/returners/couchdb_return.py b/salt/returners/couchdb_return.py index 1a67a61d275..eff8c919bb0 100644 --- a/salt/returners/couchdb_return.py +++ b/salt/returners/couchdb_return.py @@ -51,7 +51,6 @@ otherwise multi-minion targeting can lead to losing output: * other minions fail with ``{'error': 'HTTP Error 409: Conflict'}`` """ - import logging import time from urllib.error import HTTPError diff --git a/salt/returners/elasticsearch_return.py b/salt/returners/elasticsearch_return.py index e4c790b64b5..aa93542339a 100644 --- a/salt/returners/elasticsearch_return.py +++ b/salt/returners/elasticsearch_return.py @@ -93,7 +93,6 @@ Minion configuration: - saltutil.find_job """ - import datetime import logging import uuid diff --git a/salt/returners/librato_return.py b/salt/returners/librato_return.py index cceaffb6490..890393808e1 100644 --- a/salt/returners/librato_return.py +++ b/salt/returners/librato_return.py @@ -29,7 +29,6 @@ by adding more tags to the submission. """ - import logging import salt.returners diff --git a/salt/returners/multi_returner.py b/salt/returners/multi_returner.py index 550a6c1e43e..9a030a2ae60 100644 --- a/salt/returners/multi_returner.py +++ b/salt/returners/multi_returner.py @@ -3,7 +3,6 @@ Read/Write multiple returners """ - import logging import salt.minion diff --git a/salt/returners/postgres_local_cache.py b/salt/returners/postgres_local_cache.py index 58d2a19766e..4a8c6d4262e 100644 --- a/salt/returners/postgres_local_cache.py +++ b/salt/returners/postgres_local_cache.py @@ -106,7 +106,6 @@ and then: Required python modules: psycopg2 """ - import logging import re import sys diff --git a/salt/returners/rawfile_json.py b/salt/returners/rawfile_json.py index e06347180d5..a4687611813 100644 --- a/salt/returners/rawfile_json.py +++ b/salt/returners/rawfile_json.py @@ -16,7 +16,6 @@ noise, so you may wish to configure batch processing and/or configure the to restrict the events that are written. """ - import logging import salt.returners diff --git a/salt/returners/smtp_return.py b/salt/returners/smtp_return.py index 7e3787d46e8..ca10015ef24 100644 --- a/salt/returners/smtp_return.py +++ b/salt/returners/smtp_return.py @@ -104,7 +104,6 @@ Also you need to create additional file ``/srv/salt/templates/email.j2`` with em This configuration enables Salt Master to send an email when accepting or rejecting minions keys. """ - import io import logging import os diff --git a/salt/returners/zabbix_return.py b/salt/returners/zabbix_return.py index ce751c50b7d..acf9db3f746 100644 --- a/salt/returners/zabbix_return.py +++ b/salt/returners/zabbix_return.py @@ -16,7 +16,6 @@ To use the Zabbix returner, append '--return zabbix' to the salt command. ex: salt '*' test.ping --return zabbix """ - import os # Define the module's virtual name diff --git a/salt/roster/cache.py b/salt/roster/cache.py index ebae66ba2d5..5a6018d69d0 100644 --- a/salt/roster/cache.py +++ b/salt/roster/cache.py @@ -235,9 +235,9 @@ def _minion_lookup(minion_id, key, minion): else: # Take the addresses from the grains and filter them filters = { - "global": lambda addr: addr.is_global - if addr.version == 6 - else not addr.is_private, + "global": lambda addr: ( + addr.is_global if addr.version == 6 else not addr.is_private + ), "public": lambda addr: not addr.is_private, "private": lambda addr: addr.is_private and not addr.is_loopback diff --git a/salt/roster/cloud.py b/salt/roster/cloud.py index 7b9305fbd0c..096329f569d 100644 --- a/salt/roster/cloud.py +++ b/salt/roster/cloud.py @@ -17,7 +17,6 @@ usually located at /etc/salt/cloud. For example, add the following: sudo: True """ - import copy import os diff --git a/salt/roster/clustershell.py b/salt/roster/clustershell.py index 1d07bf4adc4..ea3250117ef 100644 --- a/salt/roster/clustershell.py +++ b/salt/roster/clustershell.py @@ -11,7 +11,6 @@ When you want to use host globs for target matching, use ``--roster clustershell """ - import copy import socket diff --git a/salt/roster/dir.py b/salt/roster/dir.py index b194f192fd0..2aa78dffe4e 100644 --- a/salt/roster/dir.py +++ b/salt/roster/dir.py @@ -46,7 +46,6 @@ This makes it possible to avoid having to specify the hostnames when you always their minion id plus some domain. """ - import logging import os diff --git a/salt/roster/sshknownhosts.py b/salt/roster/sshknownhosts.py index 33ecea925a1..9f8432e1672 100644 --- a/salt/roster/sshknownhosts.py +++ b/salt/roster/sshknownhosts.py @@ -36,7 +36,6 @@ Or with a Saltfile """ - import logging import os diff --git a/salt/runners/auth.py b/salt/runners/auth.py index 7485ef55a44..91f20c52e38 100644 --- a/salt/runners/auth.py +++ b/salt/runners/auth.py @@ -5,7 +5,6 @@ Authentication runner for creating, deleting, and managing eauth tokens. """ - import os import salt.auth diff --git a/salt/runners/digicertapi.py b/salt/runners/digicertapi.py index 76db62ed61f..44c8d02f728 100644 --- a/salt/runners/digicertapi.py +++ b/salt/runners/digicertapi.py @@ -34,6 +34,7 @@ This API currently only supports RSA key types. Support for other key types wil if interest warrants. """ + import logging import os import re diff --git a/salt/runners/drac.py b/salt/runners/drac.py index f5e9d39ed7d..0a377c6d808 100644 --- a/salt/runners/drac.py +++ b/salt/runners/drac.py @@ -12,7 +12,6 @@ configuration file. """ - import logging try: @@ -58,7 +57,7 @@ def __connect(hostname, timeout=20, username=None, password=None): password = drac_cred.get("password", None) client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # nosec try: client.connect(hostname, username=username, password=password, timeout=timeout) diff --git a/salt/runners/lxc.py b/salt/runners/lxc.py index 0ded584f427..f325dcb7b64 100644 --- a/salt/runners/lxc.py +++ b/salt/runners/lxc.py @@ -4,7 +4,6 @@ Control Linux Containers via Salt :depends: lxc execution module """ - import copy import logging import os diff --git a/salt/runners/manage.py b/salt/runners/manage.py index 3a0a201a4ef..63ee54e4b66 100644 --- a/salt/runners/manage.py +++ b/salt/runners/manage.py @@ -3,7 +3,6 @@ General management functions for salt, tools like seeing what hosts are up and what hosts are down """ - import logging import operator import os @@ -134,7 +133,7 @@ def key_regen(): path = os.path.join(root, fn_) try: os.remove(path) - except os.error: + except OSError: pass msg = ( "The minion and master keys have been deleted. Restart the Salt\n" @@ -540,10 +539,10 @@ def safe_accept(target, tgt_type="glob"): elif minion not in pending: failures[minion] = "Minion key {} not found by salt-key".format(minion) elif pending[minion] != finger: - failures[ - minion - ] = "Minion key {} does not match the key in salt-key: {}".format( - finger, pending[minion] + failures[minion] = ( + "Minion key {} does not match the key in salt-key: {}".format( + finger, pending[minion] + ) ) else: subprocess.call(["salt-key", "-qya", minion]) diff --git a/salt/runners/mattermost.py b/salt/runners/mattermost.py index 40309f62160..bb332de3411 100644 --- a/salt/runners/mattermost.py +++ b/salt/runners/mattermost.py @@ -14,7 +14,6 @@ Module for sending messages to Mattermost api_url: https://example.com """ - import logging import salt.utils.json diff --git a/salt/runners/nacl.py b/salt/runners/nacl.py index 3c097604bad..62b89444723 100644 --- a/salt/runners/nacl.py +++ b/salt/runners/nacl.py @@ -111,7 +111,6 @@ Larger files like certificates can be encrypted with: """ - import salt.utils.nacl __virtualname__ = "nacl" diff --git a/salt/runners/network.py b/salt/runners/network.py index 1a56da20f17..2812bb3a94e 100644 --- a/salt/runners/network.py +++ b/salt/runners/network.py @@ -2,7 +2,6 @@ Network tools to run from the Master """ - import logging import socket diff --git a/salt/runners/pkg.py b/salt/runners/pkg.py index 5d084b45032..1987b696920 100644 --- a/salt/runners/pkg.py +++ b/salt/runners/pkg.py @@ -4,7 +4,6 @@ Package helper functions using ``salt.modules.pkg`` .. versionadded:: 2015.8.0 """ - import salt.minion import salt.output diff --git a/salt/runners/queue.py b/salt/runners/queue.py index 286ebebcbff..36c77daaa98 100644 --- a/salt/runners/queue.py +++ b/salt/runners/queue.py @@ -61,7 +61,6 @@ run them. And it will do this every minute, unless there are any jobs that are still running from the last time the process_runner task was executed. """ - import salt.loader from salt.exceptions import SaltInvocationError from salt.utils.event import get_event, tagify diff --git a/salt/runners/spacewalk.py b/salt/runners/spacewalk.py index 638e338b496..69fce4731cd 100644 --- a/salt/runners/spacewalk.py +++ b/salt/runners/spacewalk.py @@ -31,7 +31,7 @@ master configuration at ``/etc/salt/master`` or ``/etc/salt/master.d/spacewalk.c import atexit import logging -import xmlrpc.client +import xmlrpc.client # nosec log = logging.getLogger(__name__) diff --git a/salt/runners/ssh.py b/salt/runners/ssh.py index 90ac4cfc02d..6a6086d21c1 100644 --- a/salt/runners/ssh.py +++ b/salt/runners/ssh.py @@ -4,7 +4,6 @@ A Runner module interface on top of the salt-ssh Python API. This allows for programmatic use from salt-api, the Reactor, Orchestrate, etc. """ - import salt.client.ssh.client diff --git a/salt/runners/thin.py b/salt/runners/thin.py index 83698cf6eb2..346c9ce68b0 100644 --- a/salt/runners/thin.py +++ b/salt/runners/thin.py @@ -6,7 +6,6 @@ in a standalone way. This runner has tools which generate the standalone salt system for easy consumption. """ - import salt.utils.thin diff --git a/salt/runners/virt.py b/salt/runners/virt.py index 71e665b4c50..317a7206068 100644 --- a/salt/runners/virt.py +++ b/salt/runners/virt.py @@ -2,7 +2,6 @@ Control virtual machines via Salt """ - import logging import os.path diff --git a/salt/scripts.py b/salt/scripts.py index 3c74fb5a3ef..dd3af6247fc 100644 --- a/salt/scripts.py +++ b/salt/scripts.py @@ -1,6 +1,7 @@ """ This module contains the function calls to execute command line scripts """ + import contextlib import functools import logging @@ -18,9 +19,6 @@ from salt.exceptions import SaltClientError, SaltReqTimeoutError, SaltSystemExit log = logging.getLogger(__name__) -if sys.version_info < (3,): - raise SystemExit(salt.defaults.exitcodes.EX_GENERIC) - def _handle_signals(client, signum, sigframe): try: diff --git a/salt/sdb/cache.py b/salt/sdb/cache.py index 837fcba8ff1..96503b3bbc3 100644 --- a/salt/sdb/cache.py +++ b/salt/sdb/cache.py @@ -44,7 +44,6 @@ it must be specified in the URI: master_ip: sdb://mastercloudcache/public_ips?bank=cloud/active/ec2/my-ec2-conf/saltmaster """ - import salt.cache __func_alias__ = {"set_": "set"} diff --git a/salt/sdb/couchdb.py b/salt/sdb/couchdb.py index 978385f9788..5e7012798a1 100644 --- a/salt/sdb/couchdb.py +++ b/salt/sdb/couchdb.py @@ -35,7 +35,6 @@ Additional contributions to build true map-reduce functionality into this module would be welcome. """ - # Import Python libraries import logging from uuid import uuid4 diff --git a/salt/sdb/etcd_db.py b/salt/sdb/etcd_db.py index bf31fc74eb3..aa2858307c7 100644 --- a/salt/sdb/etcd_db.py +++ b/salt/sdb/etcd_db.py @@ -39,7 +39,6 @@ defaults to true, meaning you will use v2 unless you specify otherwise. """ - import logging try: diff --git a/salt/sdb/rest.py b/salt/sdb/rest.py index f436fc5802b..dfcb980331b 100644 --- a/salt/sdb/rest.py +++ b/salt/sdb/rest.py @@ -64,7 +64,6 @@ For instance: user: myuser """ - import logging import salt.loader diff --git a/salt/sdb/tism.py b/salt/sdb/tism.py index 08b05b08b4a..50c72b85317 100644 --- a/salt/sdb/tism.py +++ b/salt/sdb/tism.py @@ -27,7 +27,6 @@ configuration. token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6MSwiZXhwIjoxNTg1MTExNDYwLCJqdGkiOiI3NnA5cWNiMWdtdmw4Iiwia2V5cyI6WyJBTEwiXX0.RtAhG6Uorf5xnSf4Ya_GwJnoHkCsql4r1_hiOeDSLzo """ - import logging import salt.utils.http as http diff --git a/salt/sdb/vault.py b/salt/sdb/vault.py index 08360e2d84f..6e99e267a45 100644 --- a/salt/sdb/vault.py +++ b/salt/sdb/vault.py @@ -39,7 +39,6 @@ The above URI is analogous to running the following vault command: $ vault read -field=mypassword secret/passwords """ - import logging import salt.exceptions diff --git a/salt/sdb/yaml.py b/salt/sdb/yaml.py index 1411e6c2899..e899382eff5 100644 --- a/salt/sdb/yaml.py +++ b/salt/sdb/yaml.py @@ -41,7 +41,6 @@ embedded GPG-encrypted data using the :py:mod:`GPG renderer `. """ - import logging import salt.exceptions diff --git a/salt/serializers/__init__.py b/salt/serializers/__init__.py index 2d0b5dc10db..afa7ff49cb3 100644 --- a/salt/serializers/__init__.py +++ b/salt/serializers/__init__.py @@ -14,7 +14,6 @@ """ - from salt.exceptions import SaltException, SaltRenderError diff --git a/salt/serializers/json.py b/salt/serializers/json.py index 8ee1085452c..cea79944b42 100644 --- a/salt/serializers/json.py +++ b/salt/serializers/json.py @@ -7,7 +7,6 @@ It's just a wrapper around json (or simplejson if available). """ - import salt.utils.json from salt.serializers import DeserializationError, SerializationError diff --git a/salt/serializers/plist.py b/salt/serializers/plist.py index a833b4e7897..d205d68ea1d 100644 --- a/salt/serializers/plist.py +++ b/salt/serializers/plist.py @@ -7,6 +7,7 @@ Wrapper around plistlib. """ + import logging import plistlib diff --git a/salt/serializers/yaml.py b/salt/serializers/yaml.py index dc1099db448..ae050376d6f 100644 --- a/salt/serializers/yaml.py +++ b/salt/serializers/yaml.py @@ -8,7 +8,6 @@ It also use C bindings if they are available. """ - import datetime import logging diff --git a/salt/serializers/yamlex.py b/salt/serializers/yamlex.py index d67ff7a60b2..ec77d2c7333 100644 --- a/salt/serializers/yamlex.py +++ b/salt/serializers/yamlex.py @@ -98,6 +98,7 @@ Document is defacto an aggregate mapping. """ + # pylint: disable=invalid-name,no-member,missing-docstring,no-self-use # pylint: disable=too-few-public-methods,too-many-public-methods diff --git a/salt/spm/__init__.py b/salt/spm/__init__.py index fa8f366702c..6738d108a6f 100644 --- a/salt/spm/__init__.py +++ b/salt/spm/__init__.py @@ -635,7 +635,7 @@ class SPMClient: if os.path.exists(self.opts["spm_repos_config"]): repo_files.append(self.opts["spm_repos_config"]) - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk( + for dirpath, dirnames, filenames in salt.utils.path.os_walk( "{}.d".format(self.opts["spm_repos_config"]) ): for repo_file in filenames: @@ -753,7 +753,7 @@ class SPMClient: old_files = [] repo_metadata = {} - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk(repo_path): + for dirpath, dirnames, filenames in salt.utils.path.os_walk(repo_path): for spm_file in filenames: if not spm_file.endswith(".spm"): continue diff --git a/salt/spm/pkgdb/sqlite3.py b/salt/spm/pkgdb/sqlite3.py index 48a23e0109a..7d1634c3b76 100644 --- a/salt/spm/pkgdb/sqlite3.py +++ b/salt/spm/pkgdb/sqlite3.py @@ -4,7 +4,6 @@ This module allows SPM to use sqlite3 as the backend for SPM's package database. .. versionadded:: 2015.8.0 """ - import datetime import logging import os diff --git a/salt/spm/pkgfiles/local.py b/salt/spm/pkgfiles/local.py index b75a1457448..6eab896bf68 100644 --- a/salt/spm/pkgfiles/local.py +++ b/salt/spm/pkgfiles/local.py @@ -4,7 +4,6 @@ This module allows SPM to use the local filesystem to install files for SPM. .. versionadded:: 2015.8.0 """ - import logging import os import os.path diff --git a/salt/state.py b/salt/state.py index 9cd31e6ab8b..08198e7f54f 100644 --- a/salt/state.py +++ b/salt/state.py @@ -4465,9 +4465,11 @@ class BaseHighState: " on the salt master in saltenv(s): {} ".format( env_key, inc_sls, - ", ".join(matches) - if env_key == xenv_key - else env_key, + ( + ", ".join(matches) + if env_key == xenv_key + else env_key + ), ) ) elif len(resolved_envs) > 1: @@ -4669,10 +4671,10 @@ class BaseHighState: # match SLS foobar in environment this_sls = "SLS {} in saltenv".format(sls_match) if this_sls in error: - errors[ - i - ] = "No matching sls found for '{}' in env '{}'".format( - sls_match, saltenv + errors[i] = ( + "No matching sls found for '{}' in env '{}'".format( + sls_match, saltenv + ) ) all_errors.extend(errors) diff --git a/salt/states/alternatives.py b/salt/states/alternatives.py index f69b5f70351..de4e119c529 100644 --- a/salt/states/alternatives.py +++ b/salt/states/alternatives.py @@ -76,10 +76,10 @@ def install(name, link, path, priority): ) else: if __opts__["test"]: - ret[ - "comment" - ] = "Alternative will be set for {} to {} with priority {}".format( - name, path, priority + ret["comment"] = ( + "Alternative will be set for {} to {} with priority {}".format( + name, path, priority + ) ) ret["result"] = None return ret @@ -87,10 +87,10 @@ def install(name, link, path, priority): out = __salt__["alternatives.install"](name, link, path, priority) if __salt__["alternatives.check_exists"](name, path): if __salt__["alternatives.check_installed"](name, path): - ret[ - "comment" - ] = "Alternative for {} set to path {} with priority {}".format( - name, path, priority + ret["comment"] = ( + "Alternative for {} set to path {} with priority {}".format( + name, path, priority + ) ) else: ret["comment"] = ( @@ -135,10 +135,10 @@ def remove(name, path): current = __salt__["alternatives.show_current"](name) if current: ret["result"] = True - ret[ - "comment" - ] = "Alternative for {} removed. Falling back to path {}".format( - name, current + ret["comment"] = ( + "Alternative for {} removed. Falling back to path {}".format( + name, current + ) ) ret["changes"] = {"path": current} return ret diff --git a/salt/states/ansiblegate.py b/salt/states/ansiblegate.py index ec8913dee59..2ecc18f6e81 100644 --- a/salt/states/ansiblegate.py +++ b/salt/states/ansiblegate.py @@ -236,7 +236,7 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs= if ret["result"]: ret["comment"] = "Changes were made by playbook {}".format(name) else: - ret[ - "comment" - ] = "There were some issues running the playbook {}".format(name) + ret["comment"] = ( + "There were some issues running the playbook {}".format(name) + ) return ret diff --git a/salt/states/apache.py b/salt/states/apache.py index 8b340b7de48..60ed48f8043 100644 --- a/salt/states/apache.py +++ b/salt/states/apache.py @@ -84,7 +84,6 @@ it still needs keyword ``this`` with empty string (or "\b" if nicer output is re do: another thing """ - import os import salt.utils.files diff --git a/salt/states/aptpkg.py b/salt/states/aptpkg.py index 62b83f37b26..7a285bfc913 100644 --- a/salt/states/aptpkg.py +++ b/salt/states/aptpkg.py @@ -3,7 +3,6 @@ Package management operations specific to APT- and DEB-based systems ==================================================================== """ - import logging import salt.utils.data diff --git a/salt/states/archive.py b/salt/states/archive.py index 8de42988764..bf47864f542 100644 --- a/salt/states/archive.py +++ b/salt/states/archive.py @@ -716,9 +716,9 @@ def extracted( kwargs = salt.utils.args.clean_kwargs(**kwargs) if skip_files_list_verify and skip_verify: - ret[ - "comment" - ] = 'Only one of "skip_files_list_verify" and "skip_verify" can be set to True' + ret["comment"] = ( + 'Only one of "skip_files_list_verify" and "skip_verify" can be set to True' + ) return ret if "keep_source" in kwargs and "keep" in kwargs: @@ -780,9 +780,9 @@ def extracted( # from making this state blow up with a traceback. not_rel = True if not_rel: - ret[ - "comment" - ] = "Value for 'enforce_ownership_on' must be within {}".format(name) + ret["comment"] = ( + "Value for 'enforce_ownership_on' must be within {}".format(name) + ) return ret if if_missing is not None and os.path.exists(if_missing): @@ -792,9 +792,9 @@ def extracted( if user or group: if salt.utils.platform.is_windows(): - ret[ - "comment" - ] = "User/group ownership cannot be enforced on Windows minions" + ret["comment"] = ( + "User/group ownership cannot be enforced on Windows minions" + ) return ret if user: @@ -941,9 +941,9 @@ def extracted( ) else: if password: - ret[ - "comment" - ] = "The 'password' argument is only supported for zip archives" + ret["comment"] = ( + "The 'password' argument is only supported for zip archives" + ) return ret if archive_format == "rar": @@ -971,9 +971,9 @@ def extracted( # string-ified integer. trim_output = int(trim_output) except TypeError: - ret[ - "comment" - ] = "Invalid value for trim_output, must be True/False or an integer" + ret["comment"] = ( + "Invalid value for trim_output, must be True/False or an integer" + ) return ret if source_hash: @@ -1048,10 +1048,10 @@ def extracted( # salt/states/file.py from being processed through the loader. If # that is the case, we have much more important problems as _all_ # file states would be unavailable. - ret[ - "comment" - ] = "Unable to cache {}, file.cached state not available".format( - salt.utils.url.redact_http_basic_auth(source_match) + ret["comment"] = ( + "Unable to cache {}, file.cached state not available".format( + salt.utils.url.redact_http_basic_auth(source_match) + ) ) return ret @@ -1423,7 +1423,7 @@ def extracted( if options is None: try: with closing(tarfile.open(cached, "r")) as tar: - tar.extractall(salt.utils.stringutils.to_str(name)) + tar.extractall(salt.utils.stringutils.to_str(name)) # nosec files = tar.getnames() if trim_output: files = files[:trim_output] diff --git a/salt/states/artifactory.py b/salt/states/artifactory.py index 2395fe7d6c4..23fa8d8dd59 100644 --- a/salt/states/artifactory.py +++ b/salt/states/artifactory.py @@ -3,7 +3,6 @@ This state downloads artifacts from artifactory. """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/at.py b/salt/states/at.py index a4065314552..09b2fd0e423 100644 --- a/salt/states/at.py +++ b/salt/states/at.py @@ -209,10 +209,10 @@ def absent(name, jobid=None, **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "more than one job was return for job with id {jobid}".format( - jobid=jobid + ret["comment"] = ( + "more than one job was return for job with id {jobid}".format( + jobid=jobid + ) ) return ret diff --git a/salt/states/azurearm_compute.py b/salt/states/azurearm_compute.py index e23461afd27..bfdd2dd925a 100644 --- a/salt/states/azurearm_compute.py +++ b/salt/states/azurearm_compute.py @@ -198,9 +198,9 @@ def availability_set_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret if sku: @@ -325,9 +325,9 @@ def availability_set_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret aset = __salt__["azurearm_compute.availability_set_get"]( diff --git a/salt/states/azurearm_dns.py b/salt/states/azurearm_dns.py index 90f8c0b61c8..6002d24a821 100644 --- a/salt/states/azurearm_dns.py +++ b/salt/states/azurearm_dns.py @@ -116,6 +116,7 @@ Optional provider parameters: - connection_auth: {{ profile }} """ + import logging from functools import wraps @@ -232,9 +233,9 @@ def zone_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret zone = __salt__["azurearm_dns.zone_get"]( @@ -377,9 +378,9 @@ def zone_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret zone = __salt__["azurearm_dns.zone_get"]( @@ -564,9 +565,9 @@ def record_set_present( ] if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret rec_set = __salt__["azurearm_dns.record_set_get"]( @@ -590,19 +591,19 @@ def record_set_present( record = eval(record_str) if record: if not ttl: - ret[ - "comment" - ] = "TTL is required when specifying record information!" + ret["comment"] = ( + "TTL is required when specifying record information!" + ) return ret if not rec_set.get(record_str): ret["changes"] = {"new": {record_str: record}} continue if record_str[-1] != "s": if not isinstance(record, dict): - ret[ - "comment" - ] = "{} record information must be specified as a dictionary!".format( - record_str + ret["comment"] = ( + "{} record information must be specified as a dictionary!".format( + record_str + ) ) return ret for k, v in record.items(): @@ -723,9 +724,9 @@ def record_set_absent(name, zone_name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret rec_set = __salt__["azurearm_dns.record_set_get"]( diff --git a/salt/states/azurearm_network.py b/salt/states/azurearm_network.py index 2555a2d06ad..513206d95f2 100644 --- a/salt/states/azurearm_network.py +++ b/salt/states/azurearm_network.py @@ -91,6 +91,7 @@ Azure (ARM) Network State Module - connection_auth: {{ profile }} """ + import logging from functools import wraps @@ -188,9 +189,9 @@ def virtual_network_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret vnet = __salt__["azurearm_network.virtual_network_get"]( @@ -312,9 +313,9 @@ def virtual_network_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret vnet = __salt__["azurearm_network.virtual_network_get"]( @@ -409,9 +410,9 @@ def subnet_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret snet = __salt__["azurearm_network.subnet_get"]( @@ -517,9 +518,9 @@ def subnet_absent(name, virtual_network, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret snet = __salt__["azurearm_network.subnet_get"]( @@ -625,9 +626,9 @@ def network_security_group_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret nsg = __salt__["azurearm_network.network_security_group_get"]( @@ -721,9 +722,9 @@ def network_security_group_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret nsg = __salt__["azurearm_network.network_security_group_get"]( @@ -873,9 +874,9 @@ def security_rule_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret exclusive_params = [ @@ -1127,9 +1128,9 @@ def security_rule_absent(name, security_group, resource_group, connection_auth=N ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret rule = __salt__["azurearm_network.security_rule_get"]( @@ -1351,9 +1352,9 @@ def load_balancer_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret if sku: @@ -1565,9 +1566,9 @@ def load_balancer_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret load_bal = __salt__["azurearm_network.load_balancer_get"]( @@ -1678,9 +1679,9 @@ def public_ip_address_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret if sku: @@ -1823,9 +1824,9 @@ def public_ip_address_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret pub_ip = __salt__["azurearm_network.public_ip_address_get"]( @@ -1968,9 +1969,9 @@ def network_interface_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret iface = __salt__["azurearm_network.network_interface_get"]( @@ -2151,9 +2152,9 @@ def network_interface_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret iface = __salt__["azurearm_network.network_interface_get"]( @@ -2250,9 +2251,9 @@ def route_table_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret rt_tbl = __salt__["azurearm_network.route_table_get"]( @@ -2359,9 +2360,9 @@ def route_table_absent(name, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret rt_tbl = __salt__["azurearm_network.route_table_get"]( @@ -2455,9 +2456,9 @@ def route_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret route = __salt__["azurearm_network.route_get"]( @@ -2557,9 +2558,9 @@ def route_absent(name, route_table, resource_group, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret route = __salt__["azurearm_network.route_get"]( diff --git a/salt/states/azurearm_resource.py b/salt/states/azurearm_resource.py index 7cef3bc0bd9..5cd896c4252 100644 --- a/salt/states/azurearm_resource.py +++ b/salt/states/azurearm_resource.py @@ -86,7 +86,6 @@ Azure (ARM) Resource State Module """ - import json import logging from functools import wraps @@ -172,9 +171,9 @@ def resource_group_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret group = {} @@ -255,9 +254,9 @@ def resource_group_absent(name, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret group = {} @@ -415,9 +414,9 @@ def policy_definition_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret if not policy_rule and not policy_rule_json and not policy_rule_file: @@ -630,9 +629,9 @@ def policy_definition_absent(name, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret policy = __salt__["azurearm_resource.policy_definition_get"]( @@ -726,9 +725,9 @@ def policy_assignment_present( ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret policy = __salt__["azurearm_resource.policy_assignment_get"]( @@ -843,9 +842,9 @@ def policy_assignment_absent(name, scope, connection_auth=None): ret = {"name": name, "result": False, "comment": "", "changes": {}} if not isinstance(connection_auth, dict): - ret[ - "comment" - ] = "Connection information must be specified via connection_auth dictionary!" + ret["comment"] = ( + "Connection information must be specified via connection_auth dictionary!" + ) return ret policy = __salt__["azurearm_resource.policy_assignment_get"]( diff --git a/salt/states/bigip.py b/salt/states/bigip.py index 58b525435c6..2b72e4b7530 100644 --- a/salt/states/bigip.py +++ b/salt/states/bigip.py @@ -4,7 +4,6 @@ A state module designed to enforce load-balancing configurations for F5 Big-IP e :platform: f5_bigip_11.6 """ - import salt.utils.json @@ -331,9 +330,9 @@ def manage_node( # we think we are managing if existing["content"]["address"] != address: ret["result"] = False - ret[ - "comment" - ] = "A node with this name exists but the address does not match." + ret["comment"] = ( + "A node with this name exists but the address does not match." + ) modified = __salt__["bigip.modify_node"]( hostname=hostname, @@ -1443,10 +1442,10 @@ def add_pool_member(hostname, username, password, name, member): if exists: ret["result"] = True - ret[ - "comment" - ] = "Member: {name} already exists within this pool. No changes made.".format( - name=member["name"] + ret["comment"] = ( + "Member: {name} already exists within this pool. No changes made.".format( + name=member["name"] + ) ) ret["changes"]["old"] = {} ret["changes"]["new"] = {} @@ -1457,10 +1456,10 @@ def add_pool_member(hostname, username, password, name, member): if new_member["code"] == 200: ret["result"] = True - ret[ - "comment" - ] = "Member: {name} has been successfully added to the pool.".format( - name=member["name"] + ret["comment"] = ( + "Member: {name} has been successfully added to the pool.".format( + name=member["name"] + ) ) ret["changes"]["old"] = {} @@ -1636,10 +1635,10 @@ def modify_pool_member( else: ret = _load_result(modified, ret) else: - ret[ - "comment" - ] = "Member: {name} does not exists within this pool. No changes made.".format( - name=member["name"] + ret["comment"] = ( + "Member: {name} does not exists within this pool. No changes made.".format( + name=member["name"] + ) ) # pool does not exists @@ -1706,10 +1705,10 @@ def delete_pool_member(hostname, username, password, name, member): # did we get rid of it? if deleted["code"] == 200: ret["result"] = True - ret[ - "comment" - ] = "Pool Member: {member} was successfully deleted.".format( - member=member + ret["comment"] = ( + "Pool Member: {member} was successfully deleted.".format( + member=member + ) ) ret["changes"]["old"] = existing_member ret["changes"]["new"] = {} @@ -2353,9 +2352,9 @@ def manage_virtual( ret["result"] = True ret["changes"]["old"] = {} ret["changes"]["new"] = virtual["content"] - ret[ - "comment" - ] = "Virtual was successfully created and enforced to the desired state." + ret["comment"] = ( + "Virtual was successfully created and enforced to the desired state." + ) else: ret = _load_result(virtual, ret) diff --git a/salt/states/boto3_elasticsearch.py b/salt/states/boto3_elasticsearch.py index ff0dae55457..ac50995660c 100644 --- a/salt/states/boto3_elasticsearch.py +++ b/salt/states/boto3_elasticsearch.py @@ -43,7 +43,6 @@ Manage Elasticsearch Service :depends: boto3 """ - import logging import salt.utils.json diff --git a/salt/states/boto3_route53.py b/salt/states/boto3_route53.py index 56f93256fbe..7cd3ede3452 100644 --- a/salt/states/boto3_route53.py +++ b/salt/states/boto3_route53.py @@ -59,6 +59,7 @@ passed in as a dict, or as a string to pull from pillars or minion config: - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ + # keep lint from choking # pylint: disable=W0106 @@ -281,10 +282,10 @@ def hosted_zone_present( if update_comment: if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 {} hosted zone {} comment would be updated.".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Route 53 {} hosted zone {} comment would be updated.".format( + "private" if PrivateZone else "public", Name + ) ) ret["result"] = None return ret @@ -309,10 +310,10 @@ def hosted_zone_present( ret["changes"].get("new", {}), r ) else: - ret[ - "comment" - ] = "Update of Route 53 {} hosted zone {} comment failed".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Update of Route 53 {} hosted zone {} comment failed".format( + "private" if PrivateZone else "public", Name + ) ) log.error(ret["comment"]) ret["result"] = False @@ -320,10 +321,10 @@ def hosted_zone_present( if add_vpcs or del_vpcs: if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 {} hosted zone {} associated VPCs would be updated.".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Route 53 {} hosted zone {} associated VPCs would be updated.".format( + "private" if PrivateZone else "public", Name + ) ) ret["result"] = None return ret @@ -365,10 +366,10 @@ def hosted_zone_present( log.info(msg) ret["comment"] = " ".join([ret["comment"], msg]) else: - ret[ - "comment" - ] = "Update of Route 53 {} hosted zone {} associated VPCs failed".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Update of Route 53 {} hosted zone {} associated VPCs failed".format( + "private" if PrivateZone else "public", Name + ) ) log.error(ret["comment"]) ret["result"] = False @@ -696,19 +697,19 @@ def rr_present( profile=profile, ) if len(r) < 1: - ret[ - "comment" - ] = "No EC2 instance with tag {} == {} found".format( - tag_name, tag_value + ret["comment"] = ( + "No EC2 instance with tag {} == {} found".format( + tag_name, tag_value + ) ) log.error(ret["comment"]) ret["result"] = False return ret if len(r) > 1: - ret[ - "comment" - ] = "Multiple EC2 instances with tag {} == {} found".format( - tag_name, tag_value + ret["comment"] = ( + "Multiple EC2 instances with tag {} == {} found".format( + tag_name, tag_value + ) ) log.error(ret["comment"]) ret["result"] = False @@ -781,10 +782,10 @@ def rr_present( if not recordsets: create = True if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} would be added.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} would be added.".format( + Name, Type + ) ) ret["result"] = None return ret @@ -817,10 +818,10 @@ def rr_present( return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} would be updated.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} would be updated.".format( + Name, Type + ) ) ret["result"] = None return ret @@ -858,10 +859,10 @@ def rr_present( ret["changes"]["old"] = rrset ret["changes"]["new"] = ResourceRecordSet else: - ret[ - "comment" - ] = "Failed to {} Route 53 resource record {} with type {}.".format( - "create" if create else "update", Name, Type + ret["comment"] = ( + "Failed to {} Route 53 resource record {} with type {}.".format( + "create" if create else "update", Name, Type + ) ) log.error(ret["comment"]) ret["result"] = False @@ -966,10 +967,10 @@ def rr_absent( recordsets = [r for r in recordsets if r.get("SetIdentifier") == SetIdentifier] log.debug("Resulted in recordsets %s.", recordsets) if not recordsets: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} already absent.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} already absent.".format( + Name, Type + ) ) return ret elif len(recordsets) > 1: @@ -979,10 +980,10 @@ def rr_absent( return ret ResourceRecordSet = recordsets[0] if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} would be deleted.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} would be deleted.".format( + Name, Type + ) ) ret["result"] = None return ret @@ -1006,10 +1007,10 @@ def rr_absent( ret["changes"]["old"] = ResourceRecordSet ret["changes"]["new"] = None else: - ret[ - "comment" - ] = "Failed to delete Route 53 resource record {} with type {}.".format( - Name, Type + ret["comment"] = ( + "Failed to delete Route 53 resource record {} with type {}.".format( + Name, Type + ) ) log.error(ret["comment"]) ret["result"] = False diff --git a/salt/states/boto3_sns.py b/salt/states/boto3_sns.py index 30509176e70..b47b4447288 100644 --- a/salt/states/boto3_sns.py +++ b/salt/states/boto3_sns.py @@ -350,10 +350,10 @@ def topic_absent( log.debug("Deleted subscription %s for SNS topic %s", sub, TopicArn) something_changed = True else: - ret[ - "comment" - ] = "Failed to delete subscription {} for SNS topic {}".format( - sub, TopicArn + ret["comment"] = ( + "Failed to delete subscription {} for SNS topic {}".format( + sub, TopicArn + ) ) ret["result"] = False return ret diff --git a/salt/states/boto_apigateway.py b/salt/states/boto_apigateway.py index f70edf470f1..32aad36f677 100644 --- a/salt/states/boto_apigateway.py +++ b/salt/states/boto_apigateway.py @@ -50,7 +50,6 @@ config: """ - import hashlib import logging import os @@ -1255,10 +1254,10 @@ class _Swagger: if not result.get("deleted"): ret["abort"] = True ret["result"] = False - ret[ - "comment" - ] = "delete_stage delete_api_deployment, {}".format( - result.get("error") + ret["comment"] = ( + "delete_stage delete_api_deployment, {}".format( + result.get("error") + ) ) else: ret["comment"] = "stage {} has been deleted.\n".format( @@ -1601,12 +1600,12 @@ class _Swagger: ret["result"] = False ret["abort"] = True if "error" in create_model_response: - ret[ - "comment" - ] = "Failed to create model {}, schema {}, error: {}".format( - model, - _dict_to_json_pretty(schema), - create_model_response["error"]["message"], + ret["comment"] = ( + "Failed to create model {}, schema {}, error: {}".format( + model, + _dict_to_json_pretty(schema), + create_model_response["error"]["message"], + ) ) return ret @@ -2264,10 +2263,10 @@ def usage_plan_association_present( plan_id, stages_to_add, **common_args ) if "error" in result: - ret[ - "comment" - ] = "Failed to associate a usage plan {} to the apis {}, {}".format( - plan_name, stages_to_add, result["error"] + ret["comment"] = ( + "Failed to associate a usage plan {} to the apis {}, {}".format( + plan_name, stages_to_add, result["error"] + ) ) ret["result"] = False return ret @@ -2371,10 +2370,10 @@ def usage_plan_association_absent( plan_id, stages_to_remove, **common_args ) if "error" in result: - ret[ - "comment" - ] = "Failed to disassociate a usage plan {} from the apis {}, {}".format( - plan_name, stages_to_remove, result["error"] + ret["comment"] = ( + "Failed to disassociate a usage plan {} from the apis {}, {}".format( + plan_name, stages_to_remove, result["error"] + ) ) ret["result"] = False return ret diff --git a/salt/states/boto_asg.py b/salt/states/boto_asg.py index 58a5baed2ca..2734aec50c3 100644 --- a/salt/states/boto_asg.py +++ b/salt/states/boto_asg.py @@ -191,7 +191,6 @@ Overriding the alarm values on the resource: threshold: 50.0 """ - import copy import hashlib import logging diff --git a/salt/states/boto_cloudfront.py b/salt/states/boto_cloudfront.py index db83cc10b80..fbfe1602eaa 100644 --- a/salt/states/boto_cloudfront.py +++ b/salt/states/boto_cloudfront.py @@ -43,7 +43,6 @@ either passed in as a dict, or a string to pull from pillars or minion config: :depends: boto3 """ - import difflib import logging diff --git a/salt/states/boto_cloudtrail.py b/salt/states/boto_cloudtrail.py index 5699ef2033d..dc8a12b153a 100644 --- a/salt/states/boto_cloudtrail.py +++ b/salt/states/boto_cloudtrail.py @@ -51,7 +51,6 @@ config: """ - import logging import os import os.path diff --git a/salt/states/boto_cloudwatch_alarm.py b/salt/states/boto_cloudwatch_alarm.py index a3737765dff..25600b363e7 100644 --- a/salt/states/boto_cloudwatch_alarm.py +++ b/salt/states/boto_cloudwatch_alarm.py @@ -52,7 +52,6 @@ as a passed in dict, or as a string to pull from pillars or minion config: - arn:aws:sns:us-east-1:1111111:myalerting-action """ - import salt.utils.data diff --git a/salt/states/boto_cloudwatch_event.py b/salt/states/boto_cloudwatch_event.py index 4a421549bfc..65c460ca28b 100644 --- a/salt/states/boto_cloudwatch_event.py +++ b/salt/states/boto_cloudwatch_event.py @@ -51,7 +51,6 @@ config: """ - import logging import os diff --git a/salt/states/boto_cognitoidentity.py b/salt/states/boto_cognitoidentity.py index cb6905a2781..41f8e3dc573 100644 --- a/salt/states/boto_cognitoidentity.py +++ b/salt/states/boto_cognitoidentity.py @@ -45,7 +45,6 @@ config: """ - import logging log = logging.getLogger(__name__) @@ -234,10 +233,10 @@ def pool_present( IdentityPoolName ) else: - ret[ - "comment" - ] = "An existing identity pool named {} with id {} will be updated.".format( - IdentityPoolName, IdentityPoolId + ret["comment"] = ( + "An existing identity pool named {} with id {} will be updated.".format( + IdentityPoolName, IdentityPoolId + ) ) ret["result"] = None return ret @@ -261,10 +260,10 @@ def pool_present( if r.get("created"): updated_identity_pool = r.get("identity_pool") IdentityPoolId = updated_identity_pool.get("IdentityPoolId") - ret[ - "comment" - ] = "A new identity pool with name {}, id {} is created.".format( - IdentityPoolName, IdentityPoolId + ret["comment"] = ( + "A new identity pool with name {}, id {} is created.".format( + IdentityPoolName, IdentityPoolId + ) ) else: ret["result"] = False @@ -280,19 +279,19 @@ def pool_present( if r.get("updated"): updated_identity_pool = r.get("identity_pool") - ret[ - "comment" - ] = "Existing identity pool with name {}, id {} is updated.".format( - IdentityPoolName, IdentityPoolId + ret["comment"] = ( + "Existing identity pool with name {}, id {} is updated.".format( + IdentityPoolName, IdentityPoolId + ) ) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to update an existing identity pool {} {}: {}".format( - IdentityPoolName, - IdentityPoolId, - r["error"].get("message", r["error"]), + ret["comment"] = ( + "Failed to update an existing identity pool {} {}: {}".format( + IdentityPoolName, + IdentityPoolId, + r["error"].get("message", r["error"]), + ) ) return ret @@ -388,10 +387,10 @@ def pool_absent( return ret if __opts__["test"]: - ret[ - "comment" - ] = "The following matched identity pools will be deleted.\n{}".format( - identity_pools + ret["comment"] = ( + "The following matched identity pools will be deleted.\n{}".format( + identity_pools + ) ) ret["result"] = None return ret diff --git a/salt/states/boto_datapipeline.py b/salt/states/boto_datapipeline.py index e42e328791e..40735585868 100644 --- a/salt/states/boto_datapipeline.py +++ b/salt/states/boto_datapipeline.py @@ -48,7 +48,6 @@ config: myDDBTableName: my-dynamo-table """ - import copy import datetime import difflib diff --git a/salt/states/boto_ec2.py b/salt/states/boto_ec2.py index 773016b48a7..fda59c13b5b 100644 --- a/salt/states/boto_ec2.py +++ b/salt/states/boto_ec2.py @@ -50,7 +50,6 @@ The below code deletes a key pair: - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ - import logging from time import sleep, time @@ -624,10 +623,10 @@ def snapshot_created( state=images[0].state ) else: - ret[ - "comment" - ] = "AMI with name {ami_name} not found after timeout.".format( - ami_name=ami_name + ret["comment"] = ( + "AMI with name {ami_name} not found after timeout.".format( + ami_name=ami_name + ) ) ret["result"] = False return ret @@ -1007,10 +1006,10 @@ def instance_present( if r[0].get("instance_id"): if r[0]["instance_id"] != instance_id: ret["result"] = False - ret[ - "comment" - ] = "EIP {} is already associated with instance {}.".format( - public_ip if public_ip else allocation_id, r[0]["instance_id"] + ret["comment"] = ( + "EIP {} is already associated with instance {}.".format( + public_ip if public_ip else allocation_id, r[0]["instance_id"] + ) ) return ret else: @@ -1070,10 +1069,10 @@ def instance_present( ) except SaltInvocationError as e: ret["result"] = False - ret[ - "comment" - ] = "Failed to set attribute {} to {} on instance {}.".format( - k, v, instance_name + ret["comment"] = ( + "Failed to set attribute {} to {} on instance {}.".format( + k, v, instance_name + ) ) return ret ret["changes"] = ( @@ -1309,9 +1308,9 @@ def instance_absent( else: # I /believe/ this situation is impossible but let's hedge our bets... ret["result"] = False - ret[ - "comment" - ] = "Can't determine AllocationId for address {}.".format(ip) + ret["comment"] = ( + "Can't determine AllocationId for address {}.".format(ip) + ) return ret else: public_ip = instance.ip_address @@ -1748,14 +1747,14 @@ def volume_present( return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "The volume {} is set to be detached from {}({} and attached on {}({}).".format( - attach_data.instance_id, - attach_data.devic, - volume_id, - instance_id, - device, + ret["comment"] = ( + "The volume {} is set to be detached from {}({} and attached on {}({}).".format( + attach_data.instance_id, + attach_data.devic, + volume_id, + instance_id, + device, + ) ) ret["result"] = None return ret @@ -1956,7 +1955,6 @@ def private_ips_absent( keyid=None, profile=None, ): - """ Ensure an ENI does not have secondary private ip addresses associated with it diff --git a/salt/states/boto_elasticache.py b/salt/states/boto_elasticache.py index f46b2f7a1b4..475f165484f 100644 --- a/salt/states/boto_elasticache.py +++ b/salt/states/boto_elasticache.py @@ -75,7 +75,6 @@ passed in as a dict, or as a string to pull from pillars or minion config: key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ - import logging log = logging.getLogger(__name__) @@ -520,9 +519,9 @@ def replication_group_absent( return ret if __opts__["test"]: - ret[ - "comment" - ] = "ElastiCache replication group {} is set to be removed.".format(name) + ret["comment"] = ( + "ElastiCache replication group {} is set to be removed.".format(name) + ) ret["result"] = True return ret deleted = __salt__["boto_elasticache.delete_replication_group"]( diff --git a/salt/states/boto_elasticsearch_domain.py b/salt/states/boto_elasticsearch_domain.py index 4c47222b560..c0f1f8b059b 100644 --- a/salt/states/boto_elasticsearch_domain.py +++ b/salt/states/boto_elasticsearch_domain.py @@ -77,7 +77,6 @@ config: """ - import logging import os @@ -275,11 +274,11 @@ def present( )["domain"] if _status.get("ElasticsearchVersion") != str(ElasticsearchVersion): ret["result"] = False - ret[ - "comment" - ] = "Failed to update domain: version cannot be modified from {} to {}.".format( - _status.get("ElasticsearchVersion"), - str(ElasticsearchVersion), + ret["comment"] = ( + "Failed to update domain: version cannot be modified from {} to {}.".format( + _status.get("ElasticsearchVersion"), + str(ElasticsearchVersion), + ) ) return ret _describe = __salt__["boto_elasticsearch_domain.describe"]( diff --git a/salt/states/boto_elb.py b/salt/states/boto_elb.py index 0fd59a31088..73a3f7d62e3 100644 --- a/salt/states/boto_elb.py +++ b/salt/states/boto_elb.py @@ -234,7 +234,6 @@ Tags can also be set: OtherTag: 'My Other Value' """ - import hashlib import logging import re @@ -730,10 +729,10 @@ def _elb_present( profile=profile, ) if not _security_groups: - ret[ - "comment" - ] = "Security groups {} do not map to valid security group ids.".format( - security_groups + ret["comment"] = ( + "Security groups {} do not map to valid security group ids.".format( + security_groups + ) ) ret["result"] = False return ret @@ -1039,9 +1038,9 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): if enabled: ret["comment"] = "Enabled availability zones on {} ELB.".format(name) else: - ret[ - "comment" - ] = "Failed to enable availability zones on {} ELB.".format(name) + ret["comment"] = ( + "Failed to enable availability zones on {} ELB.".format(name) + ) ret["result"] = False if to_disable: disabled = __salt__["boto_elb.disable_availability_zones"]( diff --git a/salt/states/boto_elbv2.py b/salt/states/boto_elbv2.py index b3c2fe2a2e0..d2eca045f0a 100644 --- a/salt/states/boto_elbv2.py +++ b/salt/states/boto_elbv2.py @@ -66,7 +66,6 @@ def create_target_group( unhealthy_threshold_count=2, **kwargs ): - """ .. versionadded:: 2017.11.0 @@ -348,9 +347,9 @@ def targets_deregistered( changes = True ret["result"] = True else: - ret[ - "comment" - ] = "Target Group {} failed to remove targets".format(name) + ret["comment"] = ( + "Target Group {} failed to remove targets".format(name) + ) failure = True if failure: ret["result"] = False diff --git a/salt/states/boto_iam.py b/salt/states/boto_iam.py index 93400521fce..a5bbd1ee8b3 100644 --- a/salt/states/boto_iam.py +++ b/salt/states/boto_iam.py @@ -1957,9 +1957,9 @@ def saml_provider_present( ET.fromstring(saml_metadata_document) except OSError as e: log.debug(e) - ret[ - "comment" - ] = "SAML document file {} not found or could not be loaded".format(name) + ret["comment"] = ( + "SAML document file {} not found or could not be loaded".format(name) + ) ret["result"] = False return ret for provider in __salt__["boto_iam.list_saml_providers"]( diff --git a/salt/states/boto_iam_role.py b/salt/states/boto_iam_role.py index 67c41f760a0..1ff1abcc5c8 100644 --- a/salt/states/boto_iam_role.py +++ b/salt/states/boto_iam_role.py @@ -344,9 +344,9 @@ def _instance_profile_associated(name, region=None, key=None, keyid=None, profil ret["comment"] = "Instance profile {} associated.".format(name) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to associate {0} instance profile with {0} role.".format(name) + ret["comment"] = ( + "Failed to associate {0} instance profile with {0} role.".format(name) + ) return ret @@ -729,9 +729,9 @@ def _instance_profile_disassociated( ret["comment"] = "Instance profile {} disassociated.".format(name) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to disassociate {0} instance profile from {0} role.".format( - name + ret["comment"] = ( + "Failed to disassociate {0} instance profile from {0} role.".format( + name + ) ) return ret diff --git a/salt/states/boto_lambda.py b/salt/states/boto_lambda.py index cd8bca05f52..2a0cb1c20a3 100644 --- a/salt/states/boto_lambda.py +++ b/salt/states/boto_lambda.py @@ -59,7 +59,6 @@ config: """ - import hashlib import logging import os diff --git a/salt/states/boto_rds.py b/salt/states/boto_rds.py index b5894c1fbd3..e7af123149e 100644 --- a/salt/states/boto_rds.py +++ b/salt/states/boto_rds.py @@ -68,7 +68,6 @@ config: """ - import logging import os @@ -470,9 +469,9 @@ def replica_present( ) if not modified: ret["result"] = False - ret[ - "comment" - ] = "Failed to update parameter group of {} RDS instance.".format(name) + ret["comment"] = ( + "Failed to update parameter group of {} RDS instance.".format(name) + ) ret["changes"]["old"] = pmg_name ret["changes"]["new"] = db_parameter_group_name ret["result"] = True diff --git a/salt/states/boto_route53.py b/salt/states/boto_route53.py index 0143c4e276f..2f2792c6449 100644 --- a/salt/states/boto_route53.py +++ b/salt/states/boto_route53.py @@ -70,7 +70,6 @@ passed in as a dict, or as a string to pull from pillars or minion config: key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ - import logging import uuid @@ -186,10 +185,10 @@ def present( log.info("Found private IP %s for instance %s", private_ip, name_tag) else: if public_ip is None: - ret[ - "comment" - ] = "Error: No Public IP assigned to instance with Name {}".format( - name_tag + ret["comment"] = ( + "Error: No Public IP assigned to instance with Name {}".format( + name_tag + ) ) ret["result"] = False return ret diff --git a/salt/states/boto_s3.py b/salt/states/boto_s3.py index d466374cc27..d5ab644a661 100644 --- a/salt/states/boto_s3.py +++ b/salt/states/boto_s3.py @@ -48,7 +48,6 @@ config: :depends: boto3 """ - import copy import difflib import logging diff --git a/salt/states/boto_s3_bucket.py b/salt/states/boto_s3_bucket.py index 66dc68db08d..d3a4067dd47 100644 --- a/salt/states/boto_s3_bucket.py +++ b/salt/states/boto_s3_bucket.py @@ -137,7 +137,6 @@ config: """ - import copy import logging diff --git a/salt/states/boto_secgroup.py b/salt/states/boto_secgroup.py index b4037ad11a2..983ef5b80e5 100644 --- a/salt/states/boto_secgroup.py +++ b/salt/states/boto_secgroup.py @@ -509,9 +509,9 @@ def _rules_present( vpc_name=vpc_name, ) if not sg: - ret[ - "comment" - ] = "{} security group configuration could not be retrieved.".format(name) + ret["comment"] = ( + "{} security group configuration could not be retrieved.".format(name) + ) ret["result"] = False return ret rules = _split_rules(rules) @@ -654,9 +654,9 @@ def _rules_egress_present( vpc_name=vpc_name, ) if not sg: - ret[ - "comment" - ] = "{} security group configuration could not be retrieved.".format(name) + ret["comment"] = ( + "{} security group configuration could not be retrieved.".format(name) + ) ret["result"] = False return ret rules_egress = _split_rules(rules_egress) @@ -882,9 +882,9 @@ def _tags_present( vpc_name=vpc_name, ) if not sg: - ret[ - "comment" - ] = "{} security group configuration could not be retrieved.".format(name) + ret["comment"] = ( + "{} security group configuration could not be retrieved.".format(name) + ) ret["result"] = False return ret tags_to_add = tags diff --git a/salt/states/boto_vpc.py b/salt/states/boto_vpc.py index d822adbbeb7..d0a567fad35 100644 --- a/salt/states/boto_vpc.py +++ b/salt/states/boto_vpc.py @@ -141,7 +141,6 @@ Delete also accepts a VPC peering connection id. """ - import logging import salt.utils.dictupdate as dictupdate @@ -548,7 +547,6 @@ def subnet_present( route_table_name=None, auto_assign_public_ipv4=False, ): - """ Ensure a subnet exists. @@ -2053,10 +2051,10 @@ def vpc_peering_connection_present( keyid=keyid, profile=profile, ): - ret[ - "comment" - ] = "VPC peering {} already requested - pending acceptance by {}".format( - conn_name, peer_owner_id or peer_vpc_name or peer_vpc_id + ret["comment"] = ( + "VPC peering {} already requested - pending acceptance by {}".format( + conn_name, peer_owner_id or peer_vpc_name or peer_vpc_id + ) ) log.info(ret["comment"]) return ret diff --git a/salt/states/bower.py b/salt/states/bower.py index 0c1928ca47c..f6185825b04 100644 --- a/salt/states/bower.py +++ b/salt/states/bower.py @@ -29,7 +29,6 @@ Example: - npm: bower """ - from salt.exceptions import CommandExecutionError, CommandNotFoundError diff --git a/salt/states/cabal.py b/salt/states/cabal.py index 8c415e32c4f..4b38de6eda7 100644 --- a/salt/states/cabal.py +++ b/salt/states/cabal.py @@ -22,7 +22,6 @@ pkg.installed state for the package which provides cabal """ - import salt.utils.path from salt.exceptions import CommandExecutionError, CommandNotFoundError diff --git a/salt/states/chocolatey.py b/salt/states/chocolatey.py index 87dad46a751..5e49113607e 100644 --- a/salt/states/chocolatey.py +++ b/salt/states/chocolatey.py @@ -141,13 +141,13 @@ def installed( ret["comment"] = f"{name} {version} is already installed" else: if allow_multiple: - ret[ - "comment" - ] = f"{name} {version} will be installed side by side with {name} {installed_version} if supported" + ret["comment"] = ( + f"{name} {version} will be installed side by side with {name} {installed_version} if supported" + ) else: - ret[ - "comment" - ] = f"{name} {version} will be installed over {name} {installed_version}" + ret["comment"] = ( + f"{name} {version} will be installed over {name} {installed_version}" + ) force = True else: version = installed_version @@ -374,14 +374,14 @@ def upgraded( if salt.utils.versions.compare( ver1=installed_version, oper="<", ver2=version ): - ret[ - "comment" - ] = f"{name} {installed_version} will be upgraded to version {version}" + ret["comment"] = ( + f"{name} {installed_version} will be upgraded to version {version}" + ) # If installed version is newer than new version else: - ret[ - "comment" - ] = f"{name} {installed_version} (newer) is already installed" + ret["comment"] = ( + f"{name} {installed_version} (newer) is already installed" + ) return ret # Catch all for a condition where version is not passed and there is no # available version diff --git a/salt/states/cimc.py b/salt/states/cimc.py index 09832c99ed4..ac6996211bc 100644 --- a/salt/states/cimc.py +++ b/salt/states/cimc.py @@ -17,7 +17,6 @@ relies on the CIMC proxy module to interface with the device. """ - import logging log = logging.getLogger(__name__) @@ -477,9 +476,9 @@ def user(name, id="", user="", priv="", password="", status="active"): if not conf: ret["result"] = False - ret[ - "comment" - ] = "Unable to find requested user id on device. Please verify id is valid." + ret["comment"] = ( + "Unable to find requested user id on device. Please verify id is valid." + ) return ret updates = __salt__["cimc.set_user"](str(id), user, password, priv, status) diff --git a/salt/states/cloud.py b/salt/states/cloud.py index adb55dcab0f..5cc287db906 100644 --- a/salt/states/cloud.py +++ b/salt/states/cloud.py @@ -13,7 +13,6 @@ Use this minion to spin up a cloud instance: my-ec2-config """ - import pprint import salt.utils.cloud as suc @@ -114,10 +113,10 @@ def present(name, cloud_provider, onlyif=None, unless=None, opts=None, **kwargs) if info and "Error" not in info: ret["changes"] = info ret["result"] = True - ret[ - "comment" - ] = "Created instance {} using provider {} and the following options: {}".format( - name, cloud_provider, pprint.pformat(kwargs) + ret["comment"] = ( + "Created instance {} using provider {} and the following options: {}".format( + name, cloud_provider, pprint.pformat(kwargs) + ) ) elif info and "Error" in info: ret["result"] = False diff --git a/salt/states/cmd.py b/salt/states/cmd.py index 5a859c8092c..8518659061f 100644 --- a/salt/states/cmd.py +++ b/salt/states/cmd.py @@ -231,7 +231,6 @@ To use it, one may pass it like this. Example: """ - import copy import logging import os @@ -1100,14 +1099,14 @@ def script( return ret if context and not isinstance(context, dict): - ret[ - "comment" - ] = "Invalidly-formatted 'context' parameter. Must be formed as a dict." + ret["comment"] = ( + "Invalidly-formatted 'context' parameter. Must be formed as a dict." + ) return ret if defaults and not isinstance(defaults, dict): - ret[ - "comment" - ] = "Invalidly-formatted 'defaults' parameter. Must be formed as a dict." + ret["comment"] = ( + "Invalidly-formatted 'defaults' parameter. Must be formed as a dict." + ) return ret if runas and salt.utils.platform.is_windows() and not password: diff --git a/salt/states/composer.py b/salt/states/composer.py index c21ae515098..79629271c17 100644 --- a/salt/states/composer.py +++ b/salt/states/composer.py @@ -161,7 +161,7 @@ def installed( composer_home=composer_home, env=env, ) - except (SaltException) as err: + except SaltException as err: ret["result"] = False ret["comment"] = "Error executing composer in '{}': {}".format(name, err) return ret @@ -172,9 +172,9 @@ def installed( ret["result"] = True if quiet is True: - ret[ - "comment" - ] = "Composer install completed successfully, output silenced by quiet flag" + ret["comment"] = ( + "Composer install completed successfully, output silenced by quiet flag" + ) else: ret["comment"] = "Composer install completed successfully" ret["changes"] = {"stderr": call["stderr"], "stdout": call["stdout"]} @@ -281,7 +281,7 @@ def update( composer_home=composer_home, env=env, ) - except (SaltException) as err: + except SaltException as err: ret["result"] = False ret["comment"] = "Error executing composer in '{}': {}".format(name, err) return ret @@ -292,9 +292,9 @@ def update( ret["result"] = True if quiet is True: - ret[ - "comment" - ] = "Composer update completed successfully, output silenced by quiet flag" + ret["comment"] = ( + "Composer update completed successfully, output silenced by quiet flag" + ) else: ret["comment"] = "Composer update completed successfully" ret["changes"] = {"stderr": call["stderr"], "stdout": call["stdout"]} diff --git a/salt/states/consul.py b/salt/states/consul.py index b35b72649ed..181ebc9ea9d 100644 --- a/salt/states/consul.py +++ b/salt/states/consul.py @@ -20,6 +20,7 @@ The consul module is used to create and manage Consul ACLs consul.acl_absent: - id: 38AC8470-4A83-4140-8DFD-F924CD32917F """ + import logging log = logging.getLogger(__name__) diff --git a/salt/states/cryptdev.py b/salt/states/cryptdev.py index 2b5740f7f79..54a167f7018 100644 --- a/salt/states/cryptdev.py +++ b/salt/states/cryptdev.py @@ -85,9 +85,9 @@ def mapped( # If neither option is set, we've been asked to do nothing. if not immediate and not persist: ret["result"] = False - ret[ - "comment" - ] = "Either persist or immediate must be set, otherwise this state does nothing" + ret["comment"] = ( + "Either persist or immediate must be set, otherwise this state does nothing" + ) return ret if immediate and (keyfile is None or keyfile == "none" or keyfile == "-"): diff --git a/salt/states/debconfmod.py b/salt/states/debconfmod.py index cb93d0d721c..0006e9696fa 100644 --- a/salt/states/debconfmod.py +++ b/salt/states/debconfmod.py @@ -184,7 +184,7 @@ def set(name, data, **kwargs): current = __salt__["debconf.show"](name) - for (key, args) in data.items(): + for key, args in data.items(): # For debconf data, valid booleans are 'true' and 'false'; # But str()'ing the args['value'] will result in 'True' and 'False' # which will be ignored and overridden by a dpkg-reconfigure. diff --git a/salt/states/dellchassis.py b/salt/states/dellchassis.py index 2ac905c8ad2..6f95f4f20df 100644 --- a/salt/states/dellchassis.py +++ b/salt/states/dellchassis.py @@ -153,7 +153,6 @@ pillar stated above: """ - import logging import os diff --git a/salt/states/disk.py b/salt/states/disk.py index c257870c1be..255cc225383 100644 --- a/salt/states/disk.py +++ b/salt/states/disk.py @@ -136,10 +136,10 @@ def _check_min_max(absolute, free, available, used, maximum, minimum, ret): return ret else: if used < minimum: - ret[ - "comment" - ] = "Disk used space is below minimum of {0} {2} at {1} {2}".format( - minimum, used, unit + ret["comment"] = ( + "Disk used space is below minimum of {0} {2} at {1} {2}".format( + minimum, used, unit + ) ) return ret if maximum is not None: @@ -153,10 +153,10 @@ def _check_min_max(absolute, free, available, used, maximum, minimum, ret): return ret else: if used > maximum: - ret[ - "comment" - ] = "Disk used space is above maximum of {0} {2} at {1} {2}".format( - maximum, used, unit + ret["comment"] = ( + "Disk used space is above maximum of {0} {2} at {1} {2}".format( + maximum, used, unit + ) ) return ret ret["comment"] = "Disk used space in acceptable range" diff --git a/salt/states/docker_container.py b/salt/states/docker_container.py index da18c2c6d17..040e8553fd3 100644 --- a/salt/states/docker_container.py +++ b/salt/states/docker_container.py @@ -1877,9 +1877,9 @@ def running( if not _replace(name, temp_container_name): ret["result"] = False return _format_comments(ret, comments) - ret["changes"].setdefault("container_id", {})[ - "added" - ] = temp_container["Id"] + ret["changes"].setdefault("container_id", {})["added"] = ( + temp_container["Id"] + ) else: # No changes between existing container and temp container. # First check if a requisite is asking to send a signal to the @@ -2235,9 +2235,9 @@ def run( if remove is not None: if not ignore_collisions: ret["result"] = False - ret[ - "comment" - ] = "'rm' is an alias for 'auto_remove', they cannot both be used" + ret["comment"] = ( + "'rm' is an alias for 'auto_remove', they cannot both be used" + ) return ret else: remove = bool(val) @@ -2275,9 +2275,9 @@ def run( pass else: ret["result"] = False if failhard and retcode != 0 else True - ret[ - "comment" - ] = "Container ran and exited with a return code of {}".format(retcode) + ret["comment"] = ( + "Container ran and exited with a return code of {}".format(retcode) + ) if remove: id_ = ret.get("changes", {}).get("Id") diff --git a/salt/states/docker_image.py b/salt/states/docker_image.py index 6dbce1b7cac..b2b887ffea3 100644 --- a/salt/states/docker_image.py +++ b/salt/states/docker_image.py @@ -310,10 +310,10 @@ def present( repository=name, tag=tag, base=base, mods=sls, **sls_build_kwargs ) except Exception as exc: # pylint: disable=broad-except - ret[ - "comment" - ] = "Encountered error using SLS {} for building {}: {}".format( - sls, full_image, exc + ret["comment"] = ( + "Encountered error using SLS {} for building {}: {}".format( + sls, full_image, exc + ) ) return ret if image_info is None or image_update["Id"] != image_info["Id"][:12]: diff --git a/salt/states/docker_network.py b/salt/states/docker_network.py index 94ca9696649..4ff8c95382c 100644 --- a/salt/states/docker_network.py +++ b/salt/states/docker_network.py @@ -619,9 +619,9 @@ def present( # Set the comment now to say that it already exists, if we need to # recreate the network with new config we'll update the comment later. - ret[ - "comment" - ] = "Network '{}' already exists, and is configured as specified".format(name) + ret["comment"] = ( + "Network '{}' already exists, and is configured as specified".format(name) + ) log.trace("Details of docker network '%s': %s", name, network) temp_net_name = "".join( @@ -862,9 +862,11 @@ def present( errors.append(str(exc)) else: ret["changes"].setdefault( - "reconnected" - if cid in disconnected_containers - else "connected", + ( + "reconnected" + if cid in disconnected_containers + else "connected" + ), [], ).append(connect_info["Name"]) else: diff --git a/salt/states/dvs.py b/salt/states/dvs.py index 7b4cdf4ba00..5b757c13678 100644 --- a/salt/states/dvs.py +++ b/salt/states/dvs.py @@ -200,7 +200,6 @@ The 5.5.0.2014.1.1 is a known stable version that this original ESXi State Module was developed against. """ - import logging import sys @@ -363,12 +362,12 @@ def dvs_configured(name, dvs): ) updated_infra_res_pools.append(dict(dvs[infra_prop][idx])) if updated_infra_res_pools: - props_to_original_values[ - "infrastructure_traffic_resource_pools" - ] = original_infra_res_pools - props_to_updated_values[ - "infrastructure_traffic_resource_pools" - ] = updated_infra_res_pools + props_to_original_values["infrastructure_traffic_resource_pools"] = ( + original_infra_res_pools + ) + props_to_updated_values["infrastructure_traffic_resource_pools"] = ( + updated_infra_res_pools + ) if props_to_updated_values: if __opts__["test"]: changes_string = "" diff --git a/salt/states/elasticsearch.py b/salt/states/elasticsearch.py index bf58af5913d..ae9a37c3e8e 100644 --- a/salt/states/elasticsearch.py +++ b/salt/states/elasticsearch.py @@ -4,7 +4,6 @@ State module to manage Elasticsearch. .. versionadded:: 2017.7.0 """ - import logging import salt.utils.json @@ -35,9 +34,9 @@ def index_absent(name): ret["comment"] = "Successfully removed index {}".format(name) ret["changes"]["old"] = index[name] else: - ret[ - "comment" - ] = "Failed to remove index {} for unknown reasons".format(name) + ret["comment"] = ( + "Failed to remove index {} for unknown reasons".format(name) + ) else: ret["comment"] = "Index {} is already absent".format(name) except Exception as err: # pylint: disable=broad-except @@ -136,17 +135,17 @@ def alias_absent(name, index): aliases=name, indices=index ) if ret["result"]: - ret[ - "comment" - ] = "Successfully removed alias {} for index {}".format(name, index) + ret["comment"] = ( + "Successfully removed alias {} for index {}".format(name, index) + ) ret["changes"]["old"] = ( alias.get(index, {}).get("aliases", {}).get(name, {}) ) else: - ret[ - "comment" - ] = "Failed to remove alias {} for index {} for unknown reasons".format( - name, index + ret["comment"] = ( + "Failed to remove alias {} for index {} for unknown reasons".format( + name, index + ) ) else: ret["comment"] = "Alias {} for index {} is already absent".format( @@ -198,10 +197,10 @@ def alias_present(name, index, definition=None): if ret["changes"] or not definition: if __opts__["test"]: if not old: - ret[ - "comment" - ] = "Alias {} for index {} does not exist and will be created".format( - name, index + ret["comment"] = ( + "Alias {} for index {} does not exist and will be created".format( + name, index + ) ) else: ret["comment"] = ( @@ -216,16 +215,16 @@ def alias_present(name, index, definition=None): ) if output: if not old: - ret[ - "comment" - ] = "Successfully created alias {} for index {}".format( - name, index + ret["comment"] = ( + "Successfully created alias {} for index {}".format( + name, index + ) ) else: - ret[ - "comment" - ] = "Successfully replaced alias {} for index {}".format( - name, index + ret["comment"] = ( + "Successfully replaced alias {} for index {}".format( + name, index + ) ) else: ret["result"] = False @@ -270,10 +269,10 @@ def index_template_absent(name): ) ret["changes"]["old"] = index_template[name] else: - ret[ - "comment" - ] = "Failed to remove index template {} for unknown reasons".format( - name + ret["comment"] = ( + "Failed to remove index template {} for unknown reasons".format( + name + ) ) else: ret["comment"] = "Index template {} is already absent".format(name) @@ -316,9 +315,9 @@ def index_template_present(name, definition, check_definition=False): ) if not index_template_exists: if __opts__["test"]: - ret[ - "comment" - ] = "Index template {} does not exist and will be created".format(name) + ret["comment"] = ( + "Index template {} does not exist and will be created".format(name) + ) ret["changes"] = {"new": definition} ret["result"] = None else: @@ -357,10 +356,10 @@ def index_template_present(name, definition, check_definition=False): ) if len(diff) != 0: if __opts__["test"]: - ret[ - "comment" - ] = "Index template {} exist but need to be updated".format( - name + ret["comment"] = ( + "Index template {} exist but need to be updated".format( + name + ) ) ret["changes"] = diff ret["result"] = None @@ -369,22 +368,22 @@ def index_template_present(name, definition, check_definition=False): name=name, body=definition ) if output: - ret[ - "comment" - ] = "Successfully updated index template {}".format(name) + ret["comment"] = ( + "Successfully updated index template {}".format(name) + ) ret["changes"] = diff else: ret["result"] = False - ret[ - "comment" - ] = "Cannot update index template {}, {}".format( - name, output + ret["comment"] = ( + "Cannot update index template {}, {}".format( + name, output + ) ) else: - ret[ - "comment" - ] = "Index template {} is already present and up to date".format( - name + ret["comment"] = ( + "Index template {} is already present and up to date".format( + name + ) ) else: ret["comment"] = "Index template {} is already present".format(name) @@ -418,9 +417,9 @@ def pipeline_absent(name): ret["comment"] = "Successfully removed pipeline {}".format(name) ret["changes"]["old"] = pipeline[name] else: - ret[ - "comment" - ] = "Failed to remove pipeline {} for unknown reasons".format(name) + ret["comment"] = ( + "Failed to remove pipeline {} for unknown reasons".format(name) + ) else: ret["comment"] = "Pipeline {} is already absent".format(name) except Exception as err: # pylint: disable=broad-except @@ -465,9 +464,9 @@ def pipeline_present(name, definition): if ret["changes"] or not definition: if __opts__["test"]: if not pipeline: - ret[ - "comment" - ] = "Pipeline {} does not exist and will be created".format(name) + ret["comment"] = ( + "Pipeline {} does not exist and will be created".format(name) + ) else: ret["comment"] = ( "Pipeline {} exists with wrong configuration and will be" @@ -527,10 +526,10 @@ def search_template_absent(name): ) ret["changes"]["old"] = salt.utils.json.loads(template["template"]) else: - ret[ - "comment" - ] = "Failed to remove search template {} for unknown reasons".format( - name + ret["comment"] = ( + "Failed to remove search template {} for unknown reasons".format( + name + ) ) else: ret["comment"] = "Search template {} is already absent".format(name) @@ -575,10 +574,10 @@ def search_template_present(name, definition): if ret["changes"] or not definition: if __opts__["test"]: if not template: - ret[ - "comment" - ] = "Search template {} does not exist and will be created".format( - name + ret["comment"] = ( + "Search template {} does not exist and will be created".format( + name + ) ) else: ret["comment"] = ( @@ -593,13 +592,13 @@ def search_template_present(name, definition): ) if output: if not template: - ret[ - "comment" - ] = "Successfully created search template {}".format(name) + ret["comment"] = ( + "Successfully created search template {}".format(name) + ) else: - ret[ - "comment" - ] = "Successfully replaced search template {}".format(name) + ret["comment"] = ( + "Successfully replaced search template {}".format(name) + ) else: ret["result"] = False ret["comment"] = "Cannot create search template {}, {}".format( diff --git a/salt/states/elasticsearch_index.py b/salt/states/elasticsearch_index.py index 9acd98a629c..48fcbf891c1 100644 --- a/salt/states/elasticsearch_index.py +++ b/salt/states/elasticsearch_index.py @@ -6,7 +6,6 @@ State module to manage Elasticsearch indices Use elasticsearch state instead """ - import logging log = logging.getLogger(__name__) @@ -35,9 +34,9 @@ def absent(name): ret["comment"] = "Successfully removed index {}".format(name) ret["changes"]["old"] = index[name] else: - ret[ - "comment" - ] = "Failed to remove index {} for unknown reasons".format(name) + ret["comment"] = ( + "Failed to remove index {} for unknown reasons".format(name) + ) else: ret["comment"] = "Index {} is already absent".format(name) except Exception as err: # pylint: disable=broad-except diff --git a/salt/states/elasticsearch_index_template.py b/salt/states/elasticsearch_index_template.py index 841fa381b43..61ae82e1838 100644 --- a/salt/states/elasticsearch_index_template.py +++ b/salt/states/elasticsearch_index_template.py @@ -6,7 +6,6 @@ State module to manage Elasticsearch index templates Use elasticsearch state instead """ - import logging log = logging.getLogger(__name__) @@ -39,10 +38,10 @@ def absent(name): ) ret["changes"]["old"] = index_template[name] else: - ret[ - "comment" - ] = "Failed to remove index template {} for unknown reasons".format( - name + ret["comment"] = ( + "Failed to remove index template {} for unknown reasons".format( + name + ) ) else: ret["comment"] = "Index template {} is already absent".format(name) @@ -88,9 +87,9 @@ def present(name, definition): ) if not index_template_exists: if __opts__["test"]: - ret[ - "comment" - ] = "Index template {} does not exist and will be created".format(name) + ret["comment"] = ( + "Index template {} does not exist and will be created".format(name) + ) ret["changes"] = {"new": definition} ret["result"] = None else: diff --git a/salt/states/environ.py b/salt/states/environ.py index c561fb899d4..4c22a98da50 100644 --- a/salt/states/environ.py +++ b/salt/states/environ.py @@ -3,7 +3,6 @@ Support for getting and setting the environment variables of the current salt process. """ - import os import salt.utils.platform diff --git a/salt/states/eselect.py b/salt/states/eselect.py index 18d4f644771..36246efdd99 100644 --- a/salt/states/eselect.py +++ b/salt/states/eselect.py @@ -6,7 +6,6 @@ A state module to manage Gentoo configuration via eselect """ - # Define a function alias in order not to shadow built-in's __func_alias__ = {"set_": "set"} diff --git a/salt/states/esxcluster.py b/salt/states/esxcluster.py index 6cb06df1ab2..b8509b4a329 100644 --- a/salt/states/esxcluster.py +++ b/salt/states/esxcluster.py @@ -48,7 +48,6 @@ The 5.5.0.2014.1.1 is a known stable version that this original ESXi State Module was developed against. """ - import logging import sys from functools import wraps @@ -408,11 +407,11 @@ def vsan_datastore_configured(name, datastore_name): ret.update( { - "result": True - if (not changes_required) - else None - if __opts__["test"] - else True, + "result": ( + True + if (not changes_required) + else None if __opts__["test"] else True + ), "comment": "\n".join(comments), "changes": changes, } @@ -606,13 +605,11 @@ def licenses_configured(name, licenses=None): ret.update( { - "result": True - if (not needs_changes) - else None - if __opts__["test"] - else False - if has_errors - else True, + "result": ( + True + if (not needs_changes) + else None if __opts__["test"] else False if has_errors else True + ), "comment": "\n".join(comments), "changes": changes if not __opts__["test"] else {}, } diff --git a/salt/states/esxdatacenter.py b/salt/states/esxdatacenter.py index c4414c287fa..b341a1ed9bb 100644 --- a/salt/states/esxdatacenter.py +++ b/salt/states/esxdatacenter.py @@ -58,7 +58,6 @@ State configuration: esxdatacenter.datacenter_configured """ - import logging from functools import wraps diff --git a/salt/states/esxi.py b/salt/states/esxi.py index 54a0c58192e..566396e5e7b 100644 --- a/salt/states/esxi.py +++ b/salt/states/esxi.py @@ -1407,11 +1407,11 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): result = ( True if not (changes or errors) - else None # no changes/errors - if __opts__["test"] - else False # running in test mode - if errors - else True + else ( + None # no changes/errors + if __opts__["test"] + else False if errors else True # running in test mode + ) ) # found errors; defaults to True ret.update( {"result": result, "comment": "\n".join(comments), "changes": diskgroup_changes} diff --git a/salt/states/esxvm.py b/salt/states/esxvm.py index a99ccb92c0a..3a429aa8bd6 100644 --- a/salt/states/esxvm.py +++ b/salt/states/esxvm.py @@ -192,7 +192,6 @@ execution functions against ESXi hosts via a Salt Proxy Minion, and a larger sta example. """ - import logging import sys from functools import wraps diff --git a/salt/states/etcd_mod.py b/salt/states/etcd_mod.py index ec8cc96c355..5bf2c0e9175 100644 --- a/salt/states/etcd_mod.py +++ b/salt/states/etcd_mod.py @@ -154,7 +154,6 @@ Available Functions - file: /some/file.txt """ - # Define the module's virtual name __virtualname__ = "etcd" diff --git a/salt/states/ethtool.py b/salt/states/ethtool.py index 3d9fff691ec..2d735fd37dc 100644 --- a/salt/states/ethtool.py +++ b/salt/states/ethtool.py @@ -29,7 +29,6 @@ Configuration of network device """ - import logging from salt.exceptions import CommandExecutionError @@ -118,10 +117,10 @@ def coalesce(name, **kwargs): return ret if new: ret["result"] = None - ret[ - "comment" - ] = "Device {} coalescing settings are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Device {} coalescing settings are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret @@ -205,10 +204,10 @@ def ring(name, **kwargs): return ret if new: ret["result"] = None - ret[ - "comment" - ] = "Device {} ring parameters are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Device {} ring parameters are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret @@ -284,10 +283,10 @@ def offload(name, **kwargs): return ret if new: ret["result"] = None - ret[ - "comment" - ] = "Device {} offload settings are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Device {} offload settings are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret diff --git a/salt/states/event.py b/salt/states/event.py index 2026b2e2032..759bd16dd83 100644 --- a/salt/states/event.py +++ b/salt/states/event.py @@ -2,7 +2,6 @@ Send events through Salt's event system during state runs """ - import salt.utils.functools diff --git a/salt/states/file.py b/salt/states/file.py index 56a7ae2118f..5c084634350 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -277,7 +277,6 @@ For example: """ - import copy import difflib import itertools @@ -1139,7 +1138,7 @@ def _get_template_texts( txtl = [] - for (source, source_hash) in source_list: + for source, source_hash in source_list: tmpctx = defaults if defaults else {} if context: @@ -1897,9 +1896,7 @@ def symlink( fs_entry_type = ( "File" if os.path.isfile(name) - else "Directory" - if os.path.isdir(name) - else "File system entry" + else "Directory" if os.path.isdir(name) else "File system entry" ) return _error( ret, @@ -3113,9 +3110,9 @@ def managed( if not create: if not os.path.isfile(name): # Don't create a file that is not already present - ret[ - "comment" - ] = "File {} is not present and is not set for creation".format(name) + ret["comment"] = ( + "File {} is not present and is not set for creation".format(name) + ) return ret u_check = _check_user(user, group) if u_check: @@ -3178,9 +3175,9 @@ def managed( else: ret["comment"] = "File {} not updated".format(name) elif not ret["changes"] and ret["result"]: - ret[ - "comment" - ] = "File {} exists with proper permissions. No changes made.".format(name) + ret["comment"] = ( + "File {} exists with proper permissions. No changes made.".format(name) + ) return ret accum_data, _ = _load_accumulators() @@ -4084,9 +4081,9 @@ def directory( # As above with user, we need to make sure group exists. if isinstance(gid, str): ret["result"] = False - ret[ - "comment" - ] = "Failed to enforce group ownership for group {}".format(group) + ret["comment"] = ( + "Failed to enforce group ownership for group {}".format(group) + ) else: ret["result"] = False ret["comment"] = ( @@ -6088,9 +6085,9 @@ def blockreplace( ) except Exception as exc: # pylint: disable=broad-except log.exception("Encountered error managing block") - ret[ - "comment" - ] = "Encountered error managing block: {}. See the log for details.".format(exc) + ret["comment"] = ( + "Encountered error managing block: {}. See the log for details.".format(exc) + ) return ret if changes: @@ -7583,16 +7580,16 @@ def copy_( ) ret["result"] = None else: - ret[ - "comment" - ] = 'The target file "{}" exists and will not be overwritten'.format(name) + ret["comment"] = ( + 'The target file "{}" exists and will not be overwritten'.format(name) + ) ret["result"] = True return ret if not changed: - ret[ - "comment" - ] = 'The target file "{}" exists and will not be overwritten'.format(name) + ret["comment"] = ( + 'The target file "{}" exists and will not be overwritten'.format(name) + ) ret["result"] = True return ret @@ -7687,9 +7684,9 @@ def rename(name, source, force=False, makedirs=False, **kwargs): if os.path.lexists(source) and os.path.lexists(name): if not force: - ret[ - "comment" - ] = 'The target file "{}" exists and will not be overwritten'.format(name) + ret["comment"] = ( + 'The target file "{}" exists and will not be overwritten'.format(name) + ) return ret elif not __opts__["test"]: # Remove the destination to prevent problems later @@ -8057,9 +8054,9 @@ def serialize( if not create: if not os.path.isfile(name): # Don't create a file that is not already present - ret[ - "comment" - ] = "File {} is not present and is not set for creation".format(name) + ret["comment"] = ( + "File {} is not present and is not set for creation".format(name) + ) return ret formatter = kwargs.pop("formatter", None) @@ -8337,17 +8334,17 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): else: ret = __salt__["file.check_perms"](name, None, user, group, mode)[0] if not ret["changes"]: - ret[ - "comment" - ] = "Character device {} is in the correct state".format(name) + ret["comment"] = ( + "Character device {} is in the correct state".format(name) + ) elif ntype == "b": # Check for file existence if __salt__["file.file_exists"](name): - ret[ - "comment" - ] = "File {} exists and is not a block device. Refusing to continue".format( - name + ret["comment"] = ( + "File {} exists and is not a block device. Refusing to continue".format( + name + ) ) # Check if it is a block device @@ -8379,10 +8376,10 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): elif ntype == "p": # Check for file existence if __salt__["file.file_exists"](name): - ret[ - "comment" - ] = "File {} exists and is not a fifo pipe. Refusing to continue".format( - name + ret["comment"] = ( + "File {} exists and is not a fifo pipe. Refusing to continue".format( + name + ) ) # Check if it is a fifo @@ -8976,9 +8973,9 @@ def cached( if hash == source_sum["hsum"]: ret["comment"] = "File already cached: {}".format(name) else: - ret[ - "comment" - ] = "Hashes don't match.\nFile will be cached: {}".format(name) + ret["comment"] = ( + "Hashes don't match.\nFile will be cached: {}".format(name) + ) else: ret["comment"] = "No hash found. File will be cached: {}".format(name) else: @@ -8998,10 +8995,10 @@ def cached( ) if local_hash == source_sum["hsum"]: ret["result"] = True - ret[ - "comment" - ] = "File {} is present on the minion and has hash {}".format( - full_path, local_hash + ret["comment"] = ( + "File {} is present on the minion and has hash {}".format( + full_path, local_hash + ) ) else: ret["comment"] = ( @@ -9059,10 +9056,10 @@ def cached( return ret if not local_copy: - ret[ - "comment" - ] = "Failed to cache {}, check minion log for more information".format( - salt.utils.url.redact_http_basic_auth(name) + ret["comment"] = ( + "Failed to cache {}, check minion log for more information".format( + salt.utils.url.redact_http_basic_auth(name) + ) ) return ret @@ -9259,9 +9256,9 @@ def pruned(name, recurse=False, ignore_errors=False, older_than=None): if result: if recurse and res["deleted"]: - ret[ - "comment" - ] = "Recursively removed empty directories under {}".format(name) + ret["comment"] = ( + "Recursively removed empty directories under {}".format(name) + ) ret["changes"]["deleted"] = sorted(res["deleted"]) elif not recurse: ret["comment"] = "Removed directory {}".format(name) diff --git a/salt/states/firewalld.py b/salt/states/firewalld.py index cc6eaba5c3f..2e090326ebc 100644 --- a/salt/states/firewalld.py +++ b/salt/states/firewalld.py @@ -102,7 +102,6 @@ with an example output of: rule service name="snmp" accept """ - import logging import salt.utils.path @@ -204,7 +203,6 @@ def present( rich_rules=None, prune_rich_rules=False, ): - """ Ensure a zone has specific attributes. diff --git a/salt/states/git.py b/salt/states/git.py index 32a597ec74d..d5127437208 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -235,12 +235,16 @@ def _not_fast_forward( "Repository would be updated {}{}, but {}. Set 'force_reset' to " "True{} to force this update{}.{}".format( f"from {pre} to {post}" if local_changes and pre != post else f"to {post}", - f" (after checking out local branch '{branch}')" - if _need_branch_change(branch, local_branch) - else "", - "this is not a fast-forward merge" - if not local_changes - else "there are uncommitted changes", + ( + f" (after checking out local branch '{branch}')" + if _need_branch_change(branch, local_branch) + else "" + ), + ( + "this is not a fast-forward merge" + if not local_changes + else "there are uncommitted changes" + ), " (or 'remote-changes')" if local_changes else "", " and discard these changes" if local_changes else "", branch_msg, @@ -1249,9 +1253,11 @@ def latest( else: actions.append( "Repository would be {} from {} to {}".format( - "hard-reset" - if force_reset and has_remote_rev - else "updated", + ( + "hard-reset" + if force_reset and has_remote_rev + else "updated" + ), _short_sha(local_rev), _short_sha(remote_rev), ) diff --git a/salt/states/github.py b/salt/states/github.py index f93e6e8799d..b1d3e480f2b 100644 --- a/salt/states/github.py +++ b/salt/states/github.py @@ -302,10 +302,10 @@ def team_present( } else: ret["result"] = False - ret[ - "comment" - ] = "Failed to remove repo {} from team {}.".format( - repo_name, name + ret["comment"] = ( + "Failed to remove repo {} from team {}.".format( + repo_name, name + ) ) return ret @@ -373,9 +373,9 @@ def team_present( ) if result: ret["changes"][member] = {} - ret["changes"][member][ - "old" - ] = "User {} is not in team {}".format(member, name) + ret["changes"][member]["old"] = ( + "User {} is not in team {}".format(member, name) + ) ret["changes"][member]["new"] = "User {} is in team {}".format( member, name ) @@ -684,10 +684,10 @@ def repo_present( ret["changes"][team_name] = team_change else: ret["result"] = False - ret[ - "comment" - ] = "Failed to remove repo {} from team {}.".format( - name, team_name + ret["comment"] = ( + "Failed to remove repo {} from team {}.".format( + name, team_name + ) ) return ret @@ -709,10 +709,10 @@ def repo_present( ret["changes"][team_name] = team_change else: ret["result"] = False - ret[ - "comment" - ] = "Failed to remove repo {} from team {}.".format( - name, team_name + ret["comment"] = ( + "Failed to remove repo {} from team {}.".format( + name, team_name + ) ) return ret else: diff --git a/salt/states/glance_image.py b/salt/states/glance_image.py index fe8f7857ce7..385244cb7be 100644 --- a/salt/states/glance_image.py +++ b/salt/states/glance_image.py @@ -22,7 +22,6 @@ Example States - name: cirros """ - __virtualname__ = "glance_image" diff --git a/salt/states/glusterfs.py b/salt/states/glusterfs.py index bfe4fb63380..aefe8499960 100644 --- a/salt/states/glusterfs.py +++ b/salt/states/glusterfs.py @@ -2,7 +2,6 @@ Manage GlusterFS pool. """ - import logging import salt.utils.cloud as suc @@ -105,10 +104,10 @@ def peered(name): ret["comment"] = "Host {} successfully peered".format(name) ret["changes"] = {"new": newpeers, "old": peers} else: - ret[ - "comment" - ] = "Host {} was successfully peered but did not appear in the list of peers".format( - name + ret["comment"] = ( + "Host {} was successfully peered but did not appear in the list of peers".format( + name + ) ) return ret @@ -368,10 +367,10 @@ def op_version(name, version): ret["result"] = True return ret elif __opts__["test"]: - ret[ - "comment" - ] = "An attempt would be made to set the cluster.op-version for {} to {}.".format( - name, version + ret["comment"] = ( + "An attempt would be made to set the cluster.op-version for {} to {}.".format( + name, version + ) ) ret["result"] = None return ret @@ -421,18 +420,18 @@ def max_op_version(name): return ret if current == max_version: - ret[ - "comment" - ] = "The cluster.op-version is already set to the cluster.max-op-version of {}".format( - current + ret["comment"] = ( + "The cluster.op-version is already set to the cluster.max-op-version of {}".format( + current + ) ) ret["result"] = True return ret elif __opts__["test"]: - ret[ - "comment" - ] = "An attempt would be made to set the cluster.op-version to {}.".format( - max_version + ret["comment"] = ( + "An attempt would be made to set the cluster.op-version to {}.".format( + max_version + ) ) ret["result"] = None return ret diff --git a/salt/states/grafana4_dashboard.py b/salt/states/grafana4_dashboard.py index 8f85ebad9cc..fa3414ae6b4 100644 --- a/salt/states/grafana4_dashboard.py +++ b/salt/states/grafana4_dashboard.py @@ -52,7 +52,6 @@ allowing users to manage their own custom rows. type: graph """ - import copy import salt.utils.json diff --git a/salt/states/grafana_dashboard.py b/salt/states/grafana_dashboard.py index 0ba2b5f7622..143eb35c134 100644 --- a/salt/states/grafana_dashboard.py +++ b/salt/states/grafana_dashboard.py @@ -37,7 +37,6 @@ they exist in dashboards. The module will not manage rows that are not defined, allowing users to manage their own custom rows. """ - import copy import requests diff --git a/salt/states/grains.py b/salt/states/grains.py index fadc518a254..8ffe5fe3cc9 100644 --- a/salt/states/grains.py +++ b/salt/states/grains.py @@ -199,10 +199,10 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): value = list( set(value).difference(__context__["pending_grains"][name]) ) - ret[ - "comment" - ] = 'Removed value {} from update due to context found in "{}".\n'.format( - value, name + ret["comment"] = ( + 'Removed value {} from update due to context found in "{}".\n'.format( + value, name + ) ) if "pending_grains" not in __context__: __context__["pending_grains"] = {} @@ -378,9 +378,9 @@ def absent(name, destructive=False, delimiter=DEFAULT_TARGET_DELIM, force=False) ret["comment"] = "Grain {} is set to be deleted".format(name) ret["changes"] = {"deleted": name} else: - ret[ - "comment" - ] = "Value for grain {} is set to be deleted (None)".format(name) + ret["comment"] = ( + "Value for grain {} is set to be deleted (None)".format(name) + ) ret["changes"] = {"grain": name, "value": None} return ret ret = __salt__["grains.set"](name, None, destructive=destructive, force=force) @@ -436,9 +436,9 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): if grain or name in __grains__: if isinstance(grain, list): if value in grain: - ret[ - "comment" - ] = "Value {1} is already in the list for grain {0}".format(name, value) + ret["comment"] = ( + "Value {1} is already in the list for grain {0}".format(name, value) + ) return ret if __opts__["test"]: ret["result"] = None diff --git a/salt/states/group.py b/salt/states/group.py index 601283fae51..6180b661a6b 100644 --- a/salt/states/group.py +++ b/salt/states/group.py @@ -33,7 +33,6 @@ In Windows, if no domain is specified in the user or group name (i.e. - user2 """ - import sys import salt.utils.platform @@ -188,9 +187,9 @@ def present( # -- if trying to add and delete the same user(s) at the same time. if not set(addusers).isdisjoint(set(delusers)): ret["result"] = None - ret[ - "comment" - ] = "Error. Same user(s) can not be added and deleted simultaneously" + ret["comment"] = ( + "Error. Same user(s) can not be added and deleted simultaneously" + ) return ret changes = _changes(name, gid, addusers, delusers, members) diff --git a/salt/states/hg.py b/salt/states/hg.py index c75e58435fb..f4c5592a41f 100644 --- a/salt/states/hg.py +++ b/salt/states/hg.py @@ -13,7 +13,6 @@ in ~/.ssh/known_hosts, and the remote host has this host's public key. - target: /tmp/example_repo """ - import logging import os import shutil @@ -145,9 +144,9 @@ def _update_repo(ret, name, target, clean, user, identity, rev, opts, update_hea " updating." ) else: - ret[ - "comment" - ] = "No changes found and update_head=False so will skip updating." + ret["comment"] = ( + "No changes found and update_head=False so will skip updating." + ) return ret if rev: diff --git a/salt/states/highstate_doc.py b/salt/states/highstate_doc.py index ea7c27e0125..83bc4db149e 100644 --- a/salt/states/highstate_doc.py +++ b/salt/states/highstate_doc.py @@ -2,7 +2,6 @@ To be used with processors in module `highstate_doc`. """ - __virtualname__ = "highstate_doc" diff --git a/salt/states/host.py b/salt/states/host.py index c70f04d9ed7..eadb30c00a2 100644 --- a/salt/states/host.py +++ b/salt/states/host.py @@ -70,7 +70,6 @@ You can also include comments: """ - import logging import salt.utils.validate.net diff --git a/salt/states/http.py b/salt/states/http.py index 271f06fece1..bef03f01309 100644 --- a/salt/states/http.py +++ b/salt/states/http.py @@ -6,7 +6,6 @@ Perform an HTTP query and statefully return the result .. versionadded:: 2015.5.0 """ - import logging import re import sys diff --git a/salt/states/icinga2.py b/salt/states/icinga2.py index c67e58b3451..f8134630cc1 100644 --- a/salt/states/icinga2.py +++ b/salt/states/icinga2.py @@ -18,7 +18,6 @@ Its output may be stored in a file or in a grain. - output: "/tmp/query_id.txt" """ - import os.path import salt.utils.files @@ -69,10 +68,10 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): return ret elif __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Ticket generation would be executed, storing result in grain: {}".format( - grain + ret["comment"] = ( + "Ticket generation would be executed, storing result in grain: {}".format( + grain + ) ) return ret elif grain: @@ -102,10 +101,10 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): return ret elif __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Ticket generation would be executed, storing result in file: {}".format( - output + ret["comment"] = ( + "Ticket generation would be executed, storing result in file: {}".format( + output + ) ) return ret elif __opts__["test"]: @@ -156,10 +155,10 @@ def generate_cert(name): # Checking if execution is needed. if os.path.isfile(cert) and os.path.isfile(key): - ret[ - "comment" - ] = "No execution needed. Cert: {} and key: {} already generated.".format( - cert, key + ret["comment"] = ( + "No execution needed. Cert: {} and key: {} already generated.".format( + cert, key + ) ) return ret if __opts__["test"]: diff --git a/salt/states/influxdb_continuous_query.py b/salt/states/influxdb_continuous_query.py index 8c402dc1b09..d769c4d865c 100644 --- a/salt/states/influxdb_continuous_query.py +++ b/salt/states/influxdb_continuous_query.py @@ -86,9 +86,9 @@ def absent(name, database, **client_args): if __salt__["influxdb.continuous_query_exists"](database, name, **client_args): if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "continuous query {} is present and needs to be removed".format(name) + ret["comment"] = ( + "continuous query {} is present and needs to be removed".format(name) + ) return ret if __salt__["influxdb.drop_continuous_query"](database, name, **client_args): ret["comment"] = "continuous query {} has been removed".format(name) diff --git a/salt/states/influxdb_retention_policy.py b/salt/states/influxdb_retention_policy.py index e729269a605..2c4e7fae9ba 100644 --- a/salt/states/influxdb_retention_policy.py +++ b/salt/states/influxdb_retention_policy.py @@ -142,9 +142,9 @@ def absent(name, database, **client_args): if __salt__["influxdb.retention_policy_exists"](database, name, **client_args): if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "retention policy {} is present and needs to be removed".format(name) + ret["comment"] = ( + "retention policy {} is present and needs to be removed".format(name) + ) return ret if __salt__["influxdb.drop_retention_policy"](database, name, **client_args): ret["comment"] = "retention policy {} has been removed".format(name) diff --git a/salt/states/influxdb_user.py b/salt/states/influxdb_user.py index 52f153ccc53..7088a84ed8a 100644 --- a/salt/states/influxdb_user.py +++ b/salt/states/influxdb_user.py @@ -118,9 +118,9 @@ def present(name, passwd, admin=False, grants=None, **client_args): else: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "User {} will be updated with the following changes:".format(name) + ret["comment"] = ( + "User {} will be updated with the following changes:".format(name) + ) for k, v in ret["changes"].items(): ret["comment"] += "\n{} => {}".format(k, v) ret["changes"] = {} diff --git a/salt/states/infoblox_a.py b/salt/states/infoblox_a.py index 35f3d716aa5..c2b43599c64 100644 --- a/salt/states/infoblox_a.py +++ b/salt/states/infoblox_a.py @@ -48,10 +48,10 @@ def present(name=None, ipv4addr=None, data=None, ensure_data=True, **api_opts): if obj: # warn user that the data was updated and does not match ret["result"] = False - ret[ - "comment" - ] = "** please update the name: {} to equal the updated data name {}".format( - name, data["name"] + ret["comment"] = ( + "** please update the name: {} to equal the updated data name {}".format( + name, data["name"] + ) ) return ret @@ -59,9 +59,9 @@ def present(name=None, ipv4addr=None, data=None, ensure_data=True, **api_opts): obj = obj[0] if not ensure_data: ret["result"] = True - ret[ - "comment" - ] = "infoblox record already created (supplied fields not ensured to match)" + ret["comment"] = ( + "infoblox record already created (supplied fields not ensured to match)" + ) return ret diff = __salt__["infoblox.diff_objects"](data, obj) diff --git a/salt/states/infoblox_cname.py b/salt/states/infoblox_cname.py index 99c42a6d9f8..f02470261d9 100644 --- a/salt/states/infoblox_cname.py +++ b/salt/states/infoblox_cname.py @@ -57,19 +57,19 @@ def present(name=None, data=None, ensure_data=True, **api_opts): if obj: # warn user that the data was updated and does not match ret["result"] = False - ret[ - "comment" - ] = "** please update the name: {} to equal the updated data name {}".format( - name, data["name"] + ret["comment"] = ( + "** please update the name: {} to equal the updated data name {}".format( + name, data["name"] + ) ) return ret if obj: if not ensure_data: ret["result"] = True - ret[ - "comment" - ] = "infoblox record already created (supplied fields not ensured to match)" + ret["comment"] = ( + "infoblox record already created (supplied fields not ensured to match)" + ) return ret diff = __salt__["infoblox.diff_objects"](data, obj) diff --git a/salt/states/infoblox_host_record.py b/salt/states/infoblox_host_record.py index e5c5ecb9529..49f6f0fb15f 100644 --- a/salt/states/infoblox_host_record.py +++ b/salt/states/infoblox_host_record.py @@ -53,19 +53,19 @@ def present(name=None, data=None, ensure_data=True, **api_opts): if obj: # warn user that the host name was updated and does not match ret["result"] = False - ret[ - "comment" - ] = "please update the name: {} to equal the updated data name {}".format( - name, data["name"] + ret["comment"] = ( + "please update the name: {} to equal the updated data name {}".format( + name, data["name"] + ) ) return ret if obj: if not ensure_data: ret["result"] = True - ret[ - "comment" - ] = "infoblox record already created (supplied fields not ensured to match)" + ret["comment"] = ( + "infoblox record already created (supplied fields not ensured to match)" + ) return ret obj = __salt__["infoblox.get_host_advanced"](name=name, **api_opts) diff --git a/salt/states/ini_manage.py b/salt/states/ini_manage.py index 9d3989769c7..5d5e7159bf9 100644 --- a/salt/states/ini_manage.py +++ b/salt/states/ini_manage.py @@ -9,7 +9,6 @@ Manage ini files """ - from salt.utils.odict import OrderedDict __virtualname__ = "ini" diff --git a/salt/states/ipset.py b/salt/states/ipset.py index f59e01f80c9..dd8535a4d28 100644 --- a/salt/states/ipset.py +++ b/salt/states/ipset.py @@ -212,10 +212,10 @@ def present(name, entry=None, family="ipv4", **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to add to entry {1} to set {0} for family {2}.\n{3}".format( - kwargs["set_name"], _entry, family, command + ret["comment"] = ( + "Failed to add to entry {1} to set {0} for family {2}.\n{3}".format( + kwargs["set_name"], _entry, family, command + ) ) return ret diff --git a/salt/states/iptables.py b/salt/states/iptables.py index 79edd60b8ff..8917f624087 100644 --- a/salt/states/iptables.py +++ b/salt/states/iptables.py @@ -245,6 +245,7 @@ Example rules for IPSec policy: output of iptables-save. This may have unintended consequences on legacy releases of ``iptables``. """ + import copy from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS @@ -324,10 +325,10 @@ def chain_absent(name, table="filter", family="ipv4"): chain_check = __salt__["iptables.check_chain"](table, name, family) if not chain_check: ret["result"] = True - ret[ - "comment" - ] = "iptables {} chain is already absent in {} table for {}".format( - name, table, family + ret["comment"] = ( + "iptables {} chain is already absent in {} table for {}".format( + name, table, family + ) ) return ret if __opts__["test"]: @@ -341,10 +342,10 @@ def chain_absent(name, table="filter", family="ipv4"): if command is True: ret["changes"] = {"locale": name} ret["result"] = True - ret[ - "comment" - ] = "iptables {} chain in {} table delete success for {}".format( - name, table, family + ret["comment"] = ( + "iptables {} chain in {} table delete success for {}".format( + name, table, family + ) ) else: ret["result"] = False @@ -497,10 +498,10 @@ def append(name, table="filter", family="ipv4", **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set iptables rule for {}.\nAttempted rule was {} for {}".format( - name, command.strip(), family + ret["comment"] = ( + "Failed to set iptables rule for {}.\nAttempted rule was {} for {}".format( + name, command.strip(), family + ) ) return ret @@ -633,10 +634,10 @@ def insert(name, table="filter", family="ipv4", **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set iptables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to set iptables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -749,10 +750,10 @@ def delete(name, table="filter", family="ipv4", **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to delete iptables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to delete iptables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -788,10 +789,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): == kwargs["policy"] ): ret["result"] = True - ret[ - "comment" - ] = "iptables default policy for chain {} on table {} for {} already set to {}".format( - kwargs["chain"], table, family, kwargs["policy"] + ret["comment"] = ( + "iptables default policy for chain {} on table {} for {} already set to {}".format( + kwargs["chain"], table, family, kwargs["policy"] + ) ) return ret if __opts__["test"]: @@ -814,10 +815,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): else: filename = None __salt__["iptables.save"](filename=filename, family=family) - ret[ - "comment" - ] = "Set and saved default policy for {} to {} family {}".format( - kwargs["chain"], kwargs["policy"], family + ret["comment"] = ( + "Set and saved default policy for {} to {} family {}".format( + kwargs["chain"], kwargs["policy"], family + ) ) return ret else: @@ -852,10 +853,10 @@ def flush(name, table="filter", family="ipv4", **kwargs): if "chain" not in kwargs: kwargs["chain"] = "" if __opts__["test"]: - ret[ - "comment" - ] = "iptables rules in {} table {} chain {} family needs to be flushed".format( - name, table, family + ret["comment"] = ( + "iptables rules in {} table {} chain {} family needs to be flushed".format( + name, table, family + ) ) return ret if not __salt__["iptables.flush"](table, kwargs["chain"], family): diff --git a/salt/states/jboss7.py b/salt/states/jboss7.py index 8d3438d9940..1b018196244 100644 --- a/salt/states/jboss7.py +++ b/salt/states/jboss7.py @@ -35,7 +35,6 @@ For the sake of brevity, examples for each state assume that jboss_config is con """ - import logging import re import time @@ -649,10 +648,10 @@ def reloaded(name, jboss_config, timeout=60, interval=5): ret["changes"]["reloaded"] = "configuration" else: ret["result"] = False - ret[ - "comment" - ] = "Could not reload the configuration. Timeout ({} s) exceeded. ".format( - timeout + ret["comment"] = ( + "Could not reload the configuration. Timeout ({} s) exceeded. ".format( + timeout + ) ) if not status["success"]: ret["comment"] = __append_comment( diff --git a/salt/states/jenkins.py b/salt/states/jenkins.py index 3b04caf3b0c..4386577a420 100644 --- a/salt/states/jenkins.py +++ b/salt/states/jenkins.py @@ -6,7 +6,6 @@ Management of Jenkins """ - import difflib import io import logging diff --git a/salt/states/kapacitor.py b/salt/states/kapacitor.py index 23f99ff2e8a..07d33b2457c 100644 --- a/salt/states/kapacitor.py +++ b/salt/states/kapacitor.py @@ -15,6 +15,7 @@ Kapacitor state module. .. versionadded:: 2016.11.0 """ + import difflib import salt.utils.files diff --git a/salt/states/kernelpkg.py b/salt/states/kernelpkg.py index 0f535e74038..85476c071da 100644 --- a/salt/states/kernelpkg.py +++ b/salt/states/kernelpkg.py @@ -99,9 +99,9 @@ def latest_installed(name, **kwargs): # pylint: disable=unused-argument result = __salt__["kernelpkg.upgrade"]() ret["result"] = True ret["changes"] = result["upgrades"] - ret[ - "comment" - ] = "The latest kernel package has been installed, but not activated." + ret["comment"] = ( + "The latest kernel package has been installed, but not activated." + ) return ret diff --git a/salt/states/keystone_domain.py b/salt/states/keystone_domain.py index b8df63b9871..a639aec50f3 100644 --- a/salt/states/keystone_domain.py +++ b/salt/states/keystone_domain.py @@ -26,7 +26,6 @@ Example States - name: domain1 """ - __virtualname__ = "keystone_domain" diff --git a/salt/states/keystone_endpoint.py b/salt/states/keystone_endpoint.py index 279c3be23f6..56b30d20d0a 100644 --- a/salt/states/keystone_endpoint.py +++ b/salt/states/keystone_endpoint.py @@ -36,7 +36,6 @@ Example States - service_name: glance """ - __virtualname__ = "keystone_endpoint" diff --git a/salt/states/keystone_group.py b/salt/states/keystone_group.py index ac6077a3f9a..678b5ebce83 100644 --- a/salt/states/keystone_group.py +++ b/salt/states/keystone_group.py @@ -26,7 +26,6 @@ Example States - description: 'my group' """ - __virtualname__ = "keystone_group" diff --git a/salt/states/keystone_project.py b/salt/states/keystone_project.py index b6db7cc2033..49d0b80f61f 100644 --- a/salt/states/keystone_project.py +++ b/salt/states/keystone_project.py @@ -27,7 +27,6 @@ Example States - description: 'my project' """ - __virtualname__ = "keystone_project" diff --git a/salt/states/keystone_role.py b/salt/states/keystone_role.py index 1cb938a4a51..3ca384bdbf4 100644 --- a/salt/states/keystone_role.py +++ b/salt/states/keystone_role.py @@ -25,7 +25,6 @@ Example States - description: 'my group' """ - __virtualname__ = "keystone_role" diff --git a/salt/states/keystone_role_grant.py b/salt/states/keystone_role_grant.py index edc17a1148c..d908cf93af5 100644 --- a/salt/states/keystone_role_grant.py +++ b/salt/states/keystone_role_grant.py @@ -26,7 +26,6 @@ Example States - description: 'my group' """ - __virtualname__ = "keystone_role_grant" diff --git a/salt/states/keystone_service.py b/salt/states/keystone_service.py index 988eae706e6..4a62e711465 100644 --- a/salt/states/keystone_service.py +++ b/salt/states/keystone_service.py @@ -28,7 +28,6 @@ Example States - description: 'OpenStack Image' """ - __virtualname__ = "keystone_service" diff --git a/salt/states/keystone_user.py b/salt/states/keystone_user.py index 8f9ec9f8c8d..527d71916ad 100644 --- a/salt/states/keystone_user.py +++ b/salt/states/keystone_user.py @@ -29,7 +29,6 @@ Example States - description: 'my user' """ - __virtualname__ = "keystone_user" diff --git a/salt/states/keystore.py b/salt/states/keystore.py index 5990c9d1e0c..de1586e1a5f 100644 --- a/salt/states/keystore.py +++ b/salt/states/keystore.py @@ -2,7 +2,6 @@ State management of a java keystore """ - import logging import os diff --git a/salt/states/libcloud_loadbalancer.py b/salt/states/libcloud_loadbalancer.py index c49ea093c1f..b10bb0b854c 100644 --- a/salt/states/libcloud_loadbalancer.py +++ b/salt/states/libcloud_loadbalancer.py @@ -45,7 +45,6 @@ Using States to deploy a load balancer with extended arguments to specify region :depends: apache-libcloud """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/libcloud_storage.py b/salt/states/libcloud_storage.py index a2a70f44389..641155f4cea 100644 --- a/salt/states/libcloud_storage.py +++ b/salt/states/libcloud_storage.py @@ -63,7 +63,6 @@ This example will download the file from the remote cloud and keep it locally :depends: apache-libcloud """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/linux_acl.py b/salt/states/linux_acl.py index c45c9383487..582b6bb8b7d 100644 --- a/salt/states/linux_acl.py +++ b/salt/states/linux_acl.py @@ -52,7 +52,6 @@ Ensure a Linux ACL list does not exist - perms: rwx """ - import logging import os diff --git a/salt/states/locale.py b/salt/states/locale.py index 23a8c8684f7..856e17d2747 100644 --- a/salt/states/locale.py +++ b/salt/states/locale.py @@ -17,7 +17,6 @@ Manage the available locales and the system default: - locale: us_locale """ - from salt.exceptions import CommandExecutionError diff --git a/salt/states/logrotate.py b/salt/states/logrotate.py index fcac9f20ff3..aaeb49cec0f 100644 --- a/salt/states/logrotate.py +++ b/salt/states/logrotate.py @@ -5,7 +5,6 @@ Module for managing logrotate. """ - _DEFAULT_CONF = "/etc/logrotate.conf" # Define the module's virtual name diff --git a/salt/states/loop.py b/salt/states/loop.py index 6b787393858..e99ab55abbe 100644 --- a/salt/states/loop.py +++ b/salt/states/loop.py @@ -57,7 +57,6 @@ The function :py:func:`data.subdict_match ` check instances: "{{ instance }}" """ - import logging import operator import sys @@ -222,10 +221,10 @@ def until_no_eval( break time.sleep(period) else: - ret[ - "comment" - ] = "Call did not produce the expected result after {} attempts".format( - current_attempt + ret["comment"] = ( + "Call did not produce the expected result after {} attempts".format( + current_attempt + ) ) log.debug( "%s:until_no_eval:\n\t\tResults of all attempts: %s", diff --git a/salt/states/lvm.py b/salt/states/lvm.py index b48bf6dde3a..a7a1df8b609 100644 --- a/salt/states/lvm.py +++ b/salt/states/lvm.py @@ -342,18 +342,18 @@ def lv_present( else: # ignore percentage "extents" if the logical volume already exists if "%" in str(extents): - ret[ - "comment" - ] = "Logical Volume {} already present, {} won't be resized.".format( - name, extents + ret["comment"] = ( + "Logical Volume {} already present, {} won't be resized.".format( + name, extents + ) ) extents = old_extents size_mb = old_size_mb if force is False and (size_mb < old_size_mb or extents < old_extents): - ret[ - "comment" - ] = "To reduce a Logical Volume option 'force' must be True." + ret["comment"] = ( + "To reduce a Logical Volume option 'force' must be True." + ) ret["result"] = False return ret @@ -378,9 +378,9 @@ def lv_present( ) if not changes: - ret[ - "comment" - ] = "Failed to resize Logical Volume. Unknown Error." + ret["comment"] = ( + "Failed to resize Logical Volume. Unknown Error." + ) ret["result"] = False lv_info = __salt__["lvm.lvdisplay"](lvpath, quiet=True)[lvpath] @@ -389,10 +389,10 @@ def lv_present( ret["comment"] = "Resized Logical Volume {}".format(name) ret["changes"]["resized"] = changes else: - ret[ - "comment" - ] = "Failed to resize Logical Volume {}.\nError: {}".format( - name, changes["Output from lvresize"] + ret["comment"] = ( + "Failed to resize Logical Volume {}.\nError: {}".format( + name, changes["Output from lvresize"] + ) ) ret["result"] = False return ret diff --git a/salt/states/lvs_server.py b/salt/states/lvs_server.py index 1c0eb81fb69..4d86848b9de 100644 --- a/salt/states/lvs_server.py +++ b/salt/states/lvs_server.py @@ -91,27 +91,27 @@ def present( weight=weight, ) if server_edit is True: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) has been updated".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) has been updated".format( + name, service_address, protocol + ) ) ret["changes"][name] = "Update" return ret else: ret["result"] = False - ret[ - "comment" - ] = "LVS Server {} in service {}({}) update failed({})".format( - name, service_address, protocol, server_edit + ret["comment"] = ( + "LVS Server {} in service {}({}) update failed({})".format( + name, service_address, protocol, server_edit + ) ) return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) is not present and needs to be created".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) is not present and needs to be created".format( + name, service_address, protocol + ) ) ret["result"] = None return ret @@ -124,18 +124,18 @@ def present( weight=weight, ) if server_add is True: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) has been created".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) has been created".format( + name, service_address, protocol + ) ) ret["changes"][name] = "Present" return ret else: - ret[ - "comment" - ] = "LVS Service {} in service {}({}) create failed({})".format( - name, service_address, protocol, server_add + ret["comment"] = ( + "LVS Service {} in service {}({}) create failed({})".format( + name, service_address, protocol, server_add + ) ) ret["result"] = False return ret @@ -168,10 +168,10 @@ def absent(name, protocol=None, service_address=None, server_address=None): if server_check is True: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "LVS Server {} in service {}({}) is present and needs to be removed".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) is present and needs to be removed".format( + name, service_address, protocol + ) ) return ret server_delete = __salt__["lvs.delete_server"]( @@ -186,18 +186,18 @@ def absent(name, protocol=None, service_address=None, server_address=None): ret["changes"][name] = "Absent" return ret else: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) removed failed({})".format( - name, service_address, protocol, server_delete + ret["comment"] = ( + "LVS Server {} in service {}({}) removed failed({})".format( + name, service_address, protocol, server_delete + ) ) ret["result"] = False return ret else: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) is not present, so it cannot be removed".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) is not present, so it cannot be removed".format( + name, service_address, protocol + ) ) return ret diff --git a/salt/states/lvs_service.py b/salt/states/lvs_service.py index 4e12c321773..8aee6a062f0 100644 --- a/salt/states/lvs_service.py +++ b/salt/states/lvs_service.py @@ -58,10 +58,10 @@ def present( else: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "LVS Service {} is present but some options should update".format( - name + ret["comment"] = ( + "LVS Service {} is present but some options should update".format( + name + ) ) return ret else: @@ -80,9 +80,9 @@ def present( return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "LVS Service {} is not present and needs to be created".format(name) + ret["comment"] = ( + "LVS Service {} is not present and needs to be created".format(name) + ) ret["result"] = None return ret else: @@ -141,8 +141,8 @@ def absent(name, protocol=None, service_address=None): ret["result"] = False return ret else: - ret[ - "comment" - ] = "LVS Service {} is not present, so it cannot be removed".format(name) + ret["comment"] = ( + "LVS Service {} is not present, so it cannot be removed".format(name) + ) return ret diff --git a/salt/states/lxc.py b/salt/states/lxc.py index 51dae0b92c6..98ccd67fcb2 100644 --- a/salt/states/lxc.py +++ b/salt/states/lxc.py @@ -3,7 +3,6 @@ Manage Linux Containers ======================= """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" diff --git a/salt/states/lxd.py b/salt/states/lxd.py index e5ddbf382af..30991ab1e8d 100644 --- a/salt/states/lxd.py +++ b/salt/states/lxd.py @@ -27,7 +27,6 @@ Manage LXD profiles. :platform: Linux """ - import os.path from salt.exceptions import CommandExecutionError, SaltInvocationError diff --git a/salt/states/lxd_container.py b/salt/states/lxd_container.py index 014c0265522..065e267c5fd 100644 --- a/salt/states/lxd_container.py +++ b/salt/states/lxd_container.py @@ -27,7 +27,6 @@ Manage LXD containers. :platform: Linux """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" @@ -580,9 +579,9 @@ def frozen(name, start=True, remote_addr=None, cert=None, key=None, verify_cert= elif not is_running and start: if __opts__["test"]: - ret["changes"][ - "started" - ] = 'Would start the container "{}" and freeze it after'.format(name) + ret["changes"]["started"] = ( + 'Would start the container "{}" and freeze it after'.format(name) + ) return _unchanged(ret, ret["changes"]["started"]) else: container.start(wait=True) @@ -780,10 +779,10 @@ def migrated( return _error(ret, 'Source Container "{}" not found'.format(name)) if __opts__["test"]: - ret["changes"][ - "migrated" - ] = 'Would migrate the container "{}" from "{}" to "{}"'.format( - name, src_remote_addr, remote_addr + ret["changes"]["migrated"] = ( + 'Would migrate the container "{}" from "{}" to "{}"'.format( + name, src_remote_addr, remote_addr + ) ) return _unchanged(ret, ret["changes"]["migrated"]) diff --git a/salt/states/lxd_image.py b/salt/states/lxd_image.py index c6d554ee284..5fc991b6466 100644 --- a/salt/states/lxd_image.py +++ b/salt/states/lxd_image.py @@ -28,7 +28,6 @@ Manage LXD images. :platform: Linux """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" diff --git a/salt/states/lxd_profile.py b/salt/states/lxd_profile.py index a4a0176ad39..35c781941b7 100644 --- a/salt/states/lxd_profile.py +++ b/salt/states/lxd_profile.py @@ -27,7 +27,6 @@ Manage LXD profiles. :platform: Linux """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" @@ -156,10 +155,10 @@ def present( # Description change # if str(profile.description) != str(description): - ret["changes"][ - "description" - ] = 'Description changed, from "{}" to "{}".'.format( - profile.description, description + ret["changes"]["description"] = ( + 'Description changed, from "{}" to "{}".'.format( + profile.description, description + ) ) profile.description = description diff --git a/salt/states/mdadm_raid.py b/salt/states/mdadm_raid.py index 7f32f3bd991..9d7fb7e9557 100644 --- a/salt/states/mdadm_raid.py +++ b/salt/states/mdadm_raid.py @@ -19,7 +19,6 @@ A state module for creating or destroying software RAID devices. - run: True """ - import logging import salt.utils.path @@ -100,20 +99,20 @@ def present(name, level, devices, **kwargs): new_devices.append(dev) if len(uuid_dict) > 1: - ret[ - "comment" - ] = "Devices are a mix of RAID constituents with multiple MD_UUIDs: {}.".format( - sorted(uuid_dict) + ret["comment"] = ( + "Devices are a mix of RAID constituents with multiple MD_UUIDs: {}.".format( + sorted(uuid_dict) + ) ) ret["result"] = False return ret elif len(uuid_dict) == 1: uuid = next(iter(uuid_dict)) if present and present["uuid"] != uuid: - ret[ - "comment" - ] = "Devices MD_UUIDs: {} differs from present RAID uuid {}.".format( - uuid, present["uuid"] + ret["comment"] = ( + "Devices MD_UUIDs: {} differs from present RAID uuid {}.".format( + uuid, present["uuid"] + ) ) ret["result"] = False return ret diff --git a/salt/states/memcached.py b/salt/states/memcached.py index 9f4a6d367dd..14cfd6771c2 100644 --- a/salt/states/memcached.py +++ b/salt/states/memcached.py @@ -5,7 +5,6 @@ States for Management of Memcached Keys .. versionadded:: 2014.1.0 """ - from salt.exceptions import CommandExecutionError, SaltInvocationError from salt.modules.memcached import ( DEFAULT_HOST, diff --git a/salt/states/modjk_worker.py b/salt/states/modjk_worker.py index bcf745c03eb..120531356b3 100644 --- a/salt/states/modjk_worker.py +++ b/salt/states/modjk_worker.py @@ -127,16 +127,16 @@ def _talk2modjk(name, lbn, target, action, profile="default", tgt_type="glob"): return ret if status["errors"]: ret["result"] = False - ret[ - "comment" - ] = "the following balancers could not find the worker {}: {}".format( - name, status["errors"] + ret["comment"] = ( + "the following balancers could not find the worker {}: {}".format( + name, status["errors"] + ) ) return ret if not status["wrong_state"]: - ret[ - "comment" - ] = "the worker is in the desired activation state on all the balancers" + ret["comment"] = ( + "the worker is in the desired activation state on all the balancers" + ) return ret else: ret["comment"] = "the action {} will be sent to the balancers {}".format( diff --git a/salt/states/module.py b/salt/states/module.py index 5ad87b053d2..e6422e146f8 100644 --- a/salt/states/module.py +++ b/salt/states/module.py @@ -300,6 +300,7 @@ Windows system: .. _file_roots: https://docs.saltproject.io/en/latest/ref/configuration/master.html#file-roots """ + import logging import salt.loader @@ -464,9 +465,11 @@ def _run(**kwargs): success.append( "{}: {}".format( func, - func_ret.get("comment", "Success") - if isinstance(func_ret, dict) - else func_ret, + ( + func_ret.get("comment", "Success") + if isinstance(func_ret, dict) + else func_ret + ), ) ) ret["changes"][func] = func_ret diff --git a/salt/states/mount.py b/salt/states/mount.py index 36b9a16b5d0..c820d268325 100644 --- a/salt/states/mount.py +++ b/salt/states/mount.py @@ -477,10 +477,10 @@ def mounted( if trigger_remount: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Remount would be forced because options ({}) changed".format( - ",".join(sorted(trigger_remount)) + ret["comment"] = ( + "Remount would be forced because options ({}) changed".format( + ",".join(sorted(trigger_remount)) + ) ) return ret else: @@ -642,9 +642,9 @@ def mounted( elif mkmnt: ret["comment"] = "{} would be created and mounted".format(name) else: - ret[ - "comment" - ] = "{} does not exist and would not be created".format(name) + ret["comment"] = ( + "{} does not exist and would not be created".format(name) + ) return ret if not os.path.exists(name) and not mkmnt: @@ -670,10 +670,10 @@ def mounted( if mkmnt: ret["comment"] = "{} would be created, but not mounted".format(name) else: - ret[ - "comment" - ] = "{} does not exist and would neither be created nor mounted".format( - name + ret["comment"] = ( + "{} does not exist and would neither be created nor mounted".format( + name + ) ) elif mkmnt: __salt__["file.mkdir"](name, user=user) @@ -861,10 +861,10 @@ def swap(name, persist=True, config="/etc/fstab"): ]: ret["result"] = None if name in on_: - ret[ - "comment" - ] = "Swap {} is set to be added to the fstab and to be activated".format( - name + ret["comment"] = ( + "Swap {} is set to be added to the fstab and to be activated".format( + name + ) ) return ret diff --git a/salt/states/mssql_database.py b/salt/states/mssql_database.py index e5c4c3cc67f..532a93fa5b7 100644 --- a/salt/states/mssql_database.py +++ b/salt/states/mssql_database.py @@ -51,10 +51,10 @@ def present(name, containment="NONE", options=None, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if __salt__["mssql.db_exists"](name, **kwargs): - ret[ - "comment" - ] = "Database {} is already present (Not going to try to set its options)".format( - name + ret["comment"] = ( + "Database {} is already present (Not going to try to set its options)".format( + name + ) ) return ret if __opts__["test"]: diff --git a/salt/states/mssql_login.py b/salt/states/mssql_login.py index 89ace89bcaf..d635a3c42e0 100644 --- a/salt/states/mssql_login.py +++ b/salt/states/mssql_login.py @@ -67,10 +67,10 @@ def present( ret["comment"] = "One and only one of password and domain should be specifies" return ret if __salt__["mssql.login_exists"](name, domain=domain, **kwargs): - ret[ - "comment" - ] = "Login {} is already present (Not going to try to set its password)".format( - name + ret["comment"] = ( + "Login {} is already present (Not going to try to set its password)".format( + name + ) ) return ret if __opts__["test"]: diff --git a/salt/states/mssql_role.py b/salt/states/mssql_role.py index 2fbdfe172a7..5434c226512 100644 --- a/salt/states/mssql_role.py +++ b/salt/states/mssql_role.py @@ -35,10 +35,10 @@ def present(name, owner=None, grants=None, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if __salt__["mssql.role_exists"](name, **kwargs): - ret[ - "comment" - ] = "Role {} is already present (Not going to try to set its grants)".format( - name + ret["comment"] = ( + "Role {} is already present (Not going to try to set its grants)".format( + name + ) ) return ret if __opts__["test"]: diff --git a/salt/states/mssql_user.py b/salt/states/mssql_user.py index d07c0d56cca..f7acf30489e 100644 --- a/salt/states/mssql_user.py +++ b/salt/states/mssql_user.py @@ -66,10 +66,10 @@ def present( ret["comment"] = "domain cannot be set without login" return ret if __salt__["mssql.user_exists"](name, domain=domain, database=database, **kwargs): - ret[ - "comment" - ] = "User {} is already present (Not going to try to set its roles or options)".format( - name + ret["comment"] = ( + "User {} is already present (Not going to try to set its roles or options)".format( + name + ) ) return ret if __opts__["test"]: diff --git a/salt/states/msteams.py b/salt/states/msteams.py index d84387c7d68..d061051c5d0 100644 --- a/salt/states/msteams.py +++ b/salt/states/msteams.py @@ -21,7 +21,6 @@ The hook_url can be specified in the master or minion configuration like below: hook_url: https://outlook.office.com/webhook/837 """ - from salt.exceptions import SaltInvocationError diff --git a/salt/states/mysql_grants.py b/salt/states/mysql_grants.py index acc9856a1f4..cefba9465bc 100644 --- a/salt/states/mysql_grants.py +++ b/salt/states/mysql_grants.py @@ -257,28 +257,28 @@ def absent( else: err = _get_mysql_error() if err is not None: - ret[ - "comment" - ] = "Unable to revoke grant {} on {} for {}@{} ({})".format( - grant, database, user, host, err + ret["comment"] = ( + "Unable to revoke grant {} on {} for {}@{} ({})".format( + grant, database, user, host, err + ) ) ret["result"] = False return ret else: err = _get_mysql_error() if err is not None: - ret[ - "comment" - ] = "Unable to determine if grant {} on {} for {}@{} exists ({})".format( - grant, database, user, host, err + ret["comment"] = ( + "Unable to determine if grant {} on {} for {}@{} exists ({})".format( + grant, database, user, host, err + ) ) ret["result"] = False return ret # fallback - ret[ - "comment" - ] = "Grant {} on {} to {}@{} is not present, so it cannot be revoked".format( - grant, database, user, host + ret["comment"] = ( + "Grant {} on {} to {}@{} is not present, so it cannot be revoked".format( + grant, database, user, host + ) ) return ret diff --git a/salt/states/mysql_query.py b/salt/states/mysql_query.py index be4ee5169a6..46bac68c201 100644 --- a/salt/states/mysql_query.py +++ b/salt/states/mysql_query.py @@ -19,7 +19,6 @@ Its output may be stored in a file or in a grain. - output: "/tmp/query_id.txt" """ - import os.path import sys diff --git a/salt/states/netntp.py b/salt/states/netntp.py index 27a8b09713f..e0efb1b14a5 100644 --- a/salt/states/netntp.py +++ b/salt/states/netntp.py @@ -80,21 +80,18 @@ def _default_ret(name): def _retrieve_ntp_peers(): - """Retrieves configured NTP peers""" return __salt__["ntp.peers"]() def _retrieve_ntp_servers(): - """Retrieves configured NTP servers""" return __salt__["ntp.servers"]() def _check(peers): - """Checks whether the input is a valid list of peers and transforms domain names into IP Addresses""" if not isinstance(peers, list): @@ -141,28 +138,24 @@ def _clean(lst): def _set_ntp_peers(peers): - """Calls ntp.set_peers.""" return __salt__["ntp.set_peers"](*peers, commit=False) def _set_ntp_servers(servers): - """Calls ntp.set_servers.""" return __salt__["ntp.set_servers"](*servers, commit=False) def _delete_ntp_peers(peers): - """Calls ntp.delete_peers.""" return __salt__["ntp.delete_peers"](*peers, commit=False) def _delete_ntp_servers(servers): - """Calls ntp.delete_servers.""" return __salt__["ntp.delete_servers"](*servers, commit=False) @@ -276,7 +269,6 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): def managed(name, peers=None, servers=None): - """ Manages the configuration of NTP peers and servers on the device, as specified in the state SLS file. NTP entities not specified in these lists will be removed whilst entities not configured on the device will be set. @@ -334,15 +326,15 @@ def managed(name, peers=None, servers=None): return ret # just exit if isinstance(peers, list) and not _check(peers): # check and clean peers - ret[ - "comment" - ] = "NTP peers must be a list of valid IP Addresses or Domain Names" + ret["comment"] = ( + "NTP peers must be a list of valid IP Addresses or Domain Names" + ) return ret if isinstance(servers, list) and not _check(servers): # check and clean servers - ret[ - "comment" - ] = "NTP servers must be a list of valid IP Addresses or Domain Names" + ret["comment"] = ( + "NTP servers must be a list of valid IP Addresses or Domain Names" + ) return ret # ----- Retrieve existing NTP peers and determine peers to be added/removed ---------------------------------------> diff --git a/salt/states/netsnmp.py b/salt/states/netsnmp.py index a0f0d50b5f5..325ca88e9f7 100644 --- a/salt/states/netsnmp.py +++ b/salt/states/netsnmp.py @@ -60,7 +60,6 @@ def __virtual__(): def _ordered_dict_to_dict(config): - """ Forced the datatype to dict, in case OrderedDict is used. """ @@ -69,7 +68,6 @@ def _ordered_dict_to_dict(config): def _expand_config(config, defaults): - """ Completed the values of the expected config for the edge cases with the default values. """ @@ -79,7 +77,6 @@ def _expand_config(config, defaults): def _valid_dict(dic): - """ Valid dictionary? """ @@ -88,7 +85,6 @@ def _valid_dict(dic): def _valid_str(value): - """ Valid str? """ @@ -97,7 +93,6 @@ def _valid_str(value): def _community_defaults(): - """ Returns the default values of a community. """ @@ -106,7 +101,6 @@ def _community_defaults(): def _clear_community_details(community_details): - """ Clears community details. """ @@ -126,7 +120,6 @@ def _clear_community_details(community_details): def _str_elem(config, key): - """ Re-adds the value of a specific key in the dict, only in case of valid str value. """ @@ -137,7 +130,6 @@ def _str_elem(config, key): def _check_config(config): - """ Checks the desired config and clears interesting details. """ @@ -187,7 +179,6 @@ def _check_config(config): def _retrieve_device_config(): - """ Retrieves the SNMP config from the device. """ @@ -196,7 +187,6 @@ def _retrieve_device_config(): def _create_diff_action(diff, diff_key, key, value): - """ DRY to build diff parts (added, removed, updated). """ @@ -207,7 +197,6 @@ def _create_diff_action(diff, diff_key, key, value): def _create_diff(diff, fun, key, prev, curr): - """ Builds the diff dictionary. """ @@ -221,7 +210,6 @@ def _create_diff(diff, fun, key, prev, curr): def _compute_diff(existing, expected): - """ Computes the differences between the existing and the expected SNMP config. """ @@ -240,7 +228,6 @@ def _compute_diff(existing, expected): def _configure(changes): - """ Calls the configuration template to apply the configuration changes on the device. """ @@ -279,7 +266,6 @@ def _configure(changes): def managed(name, config=None, defaults=None): - """ Configures the SNMP on the device as specified in the SLS file. diff --git a/salt/states/netusers.py b/salt/states/netusers.py index 9120ce358aa..98b589cfb90 100644 --- a/salt/states/netusers.py +++ b/salt/states/netusers.py @@ -54,21 +54,18 @@ def __virtual__(): def _retrieve_users(): - """Retrieves configured users""" return __salt__["users.config"]() def _ordered_dict_to_dict(probes): - """.""" return salt.utils.json.loads(salt.utils.json.dumps(probes)) def _expand_users(device_users, common_users): - """Creates a longer list of accepted users on the device.""" expected_users = copy.deepcopy(common_users) @@ -78,7 +75,6 @@ def _expand_users(device_users, common_users): def _check_users(users): - """Checks if the input dictionary of users is valid.""" messg = "" @@ -103,7 +99,6 @@ def _check_users(users): def _compute_diff(configured, expected): - """Computes the differences between the actual config and the expected config""" diff = {"add": {}, "update": {}, "remove": {}} @@ -135,21 +130,18 @@ def _compute_diff(configured, expected): def _set_users(users): - """Calls users.set_users.""" return __salt__["users.set_users"](users, commit=False) def _update_users(users): - """Calls users.set_users.""" return __salt__["users.set_users"](users, commit=False) def _delete_users(users): - """Calls users.delete_users.""" return __salt__["users.delete_users"](users, commit=False) @@ -161,7 +153,6 @@ def _delete_users(users): def managed(name, users=None, defaults=None): - """ Manages the configuration of the users on the device, as specified in the state SLS file. Users not defined in that file will be removed whilst users not configured on the device, will be added. diff --git a/salt/states/network.py b/salt/states/network.py index b942a7e58d4..d3a2a2e203d 100644 --- a/salt/states/network.py +++ b/salt/states/network.py @@ -554,10 +554,10 @@ def managed(name, enabled=True, **kwargs): elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None - ret[ - "comment" - ] = "Bond interface {} is set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Bond interface {} is set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) else: if not old and new: @@ -626,9 +626,9 @@ def managed(name, enabled=True, **kwargs): # Interface should restart to validate if it's up __salt__["ip.down"](name, iface_type) __salt__["ip.up"](name, iface_type) - ret["changes"][ - "status" - ] = "Interface {} restart to validate".format(name) + ret["changes"]["status"] = ( + "Interface {} restart to validate".format(name) + ) else: __salt__["ip.up"](name, iface_type) ret["changes"]["status"] = "Interface {} is up".format(name) @@ -670,10 +670,10 @@ def managed(name, enabled=True, **kwargs): __salt__["cmd.run"](cmd, python_shell=False) else: log.error("Command 'ifenslave' not found") - ret["changes"][ - "enslave" - ] = "Added slaves '{}' to master '{}'".format( - " ".join(missing_slaves), name + ret["changes"]["enslave"] = ( + "Added slaves '{}' to master '{}'".format( + " ".join(missing_slaves), name + ) ) else: log.info( @@ -726,10 +726,10 @@ def routes(name, **kwargs): elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None - ret[ - "comment" - ] = "Interface {} routes are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Interface {} routes are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret if not old and new: @@ -791,10 +791,10 @@ def system(name, **kwargs): elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None - ret[ - "comment" - ] = "Global network settings are set to be updated:\n{}".format( - "\n".join(diff) + ret["comment"] = ( + "Global network settings are set to be updated:\n{}".format( + "\n".join(diff) + ) ) return ret if not old and new: diff --git a/salt/states/neutron_network.py b/salt/states/neutron_network.py index 30e6cfb050f..3361675749a 100644 --- a/salt/states/neutron_network.py +++ b/salt/states/neutron_network.py @@ -28,7 +28,6 @@ Example States - project: project1 """ - __virtualname__ = "neutron_network" diff --git a/salt/states/neutron_secgroup.py b/salt/states/neutron_secgroup.py index 045f413c945..144178bbc2d 100644 --- a/salt/states/neutron_secgroup.py +++ b/salt/states/neutron_secgroup.py @@ -34,7 +34,6 @@ Example States - project_name: Project1 """ - __virtualname__ = "neutron_secgroup" diff --git a/salt/states/neutron_secgroup_rule.py b/salt/states/neutron_secgroup_rule.py index db4721fc79e..3c65fc34308 100644 --- a/salt/states/neutron_secgroup_rule.py +++ b/salt/states/neutron_secgroup_rule.py @@ -28,7 +28,6 @@ Example States - project_id: 1dcac318a83b4610b7a7f7ba01465548 """ - __virtualname__ = "neutron_secgroup_rule" diff --git a/salt/states/neutron_subnet.py b/salt/states/neutron_subnet.py index 30c69992b58..60e241e69ef 100644 --- a/salt/states/neutron_subnet.py +++ b/salt/states/neutron_subnet.py @@ -46,7 +46,6 @@ Example States - ip_version: 6 """ - __virtualname__ = "neutron_subnet" diff --git a/salt/states/nexus.py b/salt/states/nexus.py index a823b0a47d0..10d71db4cd8 100644 --- a/salt/states/nexus.py +++ b/salt/states/nexus.py @@ -4,7 +4,6 @@ This state downloads artifacts from Nexus 3.x. .. versionadded:: 2018.3.0 """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/nftables.py b/salt/states/nftables.py index 71c6e997eed..2088e51efea 100644 --- a/salt/states/nftables.py +++ b/salt/states/nftables.py @@ -157,10 +157,10 @@ def chain_present( return ret if __opts__["test"]: - ret[ - "comment" - ] = "nftables chain {} would be created in table {} for family {}".format( - name, table, family + ret["comment"] = ( + "nftables chain {} would be created in table {} for family {}".format( + name, table, family + ) ) return ret @@ -198,10 +198,10 @@ def chain_absent(name, table="filter", family="ipv4"): chain_check = __salt__["nftables.check_chain"](table, name, family) if not chain_check: ret["result"] = True - ret[ - "comment" - ] = "nftables {} chain is already absent in {} table for {}".format( - name, table, family + ret["comment"] = ( + "nftables {} chain is already absent in {} table for {}".format( + name, table, family + ) ) return ret @@ -211,10 +211,10 @@ def chain_absent(name, table="filter", family="ipv4"): if command is True: ret["changes"] = {"locale": name} ret["result"] = True - ret[ - "comment" - ] = "nftables {} chain in {} table delete success for {}".format( - name, table, family + ret["comment"] = ( + "nftables {} chain in {} table delete success for {}".format( + name, table, family + ) ) else: ret["result"] = False @@ -286,18 +286,18 @@ def append(name, family="ipv4", **kwargs): if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) - ret[ - "comment" - ] = "Set and Saved nftables rule for {} to: {} for {}".format( - name, command.strip(), family + ret["comment"] = ( + "Set and Saved nftables rule for {} to: {} for {}".format( + name, command.strip(), family + ) ) return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set nftables rule for {}.\nAttempted rule was {} for {}.\n{}".format( - name, command.strip(), family, res["comment"] + ret["comment"] = ( + "Failed to set nftables rule for {}.\nAttempted rule was {} for {}.\n{}".format( + name, command.strip(), family, res["comment"] + ) ) return ret @@ -361,18 +361,18 @@ def insert(name, family="ipv4", **kwargs): if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) - ret[ - "comment" - ] = "Set and Saved nftables rule for {} to: {} for {}".format( - name, command.strip(), family + ret["comment"] = ( + "Set and Saved nftables rule for {} to: {} for {}".format( + name, command.strip(), family + ) ) return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set nftables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to set nftables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -442,18 +442,18 @@ def delete(name, family="ipv4", **kwargs): if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) - ret[ - "comment" - ] = "Deleted and Saved nftables rule for {} for {}{}".format( - name, command.strip(), family + ret["comment"] = ( + "Deleted and Saved nftables rule for {} for {}{}".format( + name, command.strip(), family + ) ) return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to delete nftables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to delete nftables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -492,10 +492,10 @@ def flush(name, family="ipv4", ignore_absence=False, **kwargs): check_table = __salt__["nftables.check_table"](kwargs["table"], family=family) if not ignore_absence and not check_table["result"]: ret["result"] = False - ret[ - "comment" - ] = "Failed to flush table {} in family {}, table does not exist.".format( - kwargs["table"], family + ret["comment"] = ( + "Failed to flush table {} in family {}, table does not exist.".format( + kwargs["table"], family + ) ) return ret @@ -562,10 +562,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): if (policy or "").lower() == kwargs["policy"].lower(): ret["result"] = True - ret[ - "comment" - ] = "nftables default policy for chain {} on table {} for {} already set to {}".format( - kwargs["chain"], table, family, kwargs["policy"] + ret["comment"] = ( + "nftables default policy for chain {} on table {} for {} already set to {}".format( + kwargs["chain"], table, family, kwargs["policy"] + ) ) return ret @@ -590,10 +590,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): __salt__["nftables.save"]( filename=kwargs.get("save_filename"), family=family ) - ret[ - "comment" - ] = "Set and saved default policy for {} to {} family {}".format( - kwargs["chain"], kwargs["policy"], family + ret["comment"] = ( + "Set and saved default policy for {} to {} family {}".format( + kwargs["chain"], kwargs["policy"], family + ) ) else: ret["result"] = False diff --git a/salt/states/npm.py b/salt/states/npm.py index 535a516a1d4..8f7415d1f58 100644 --- a/salt/states/npm.py +++ b/salt/states/npm.py @@ -18,7 +18,6 @@ for the package which provides npm (simply ``npm`` in most cases). Example: - pkg: npm """ - import re from salt.exceptions import CommandExecutionError, CommandNotFoundError diff --git a/salt/states/openstack_config.py b/salt/states/openstack_config.py index e9154d57a4f..e635366f696 100644 --- a/salt/states/openstack_config.py +++ b/salt/states/openstack_config.py @@ -8,7 +8,6 @@ Manage OpenStack configuration file settings. """ - from salt.exceptions import CommandExecutionError diff --git a/salt/states/openvswitch_port.py b/salt/states/openvswitch_port.py index 3ca769b1e37..efacfe5800f 100644 --- a/salt/states/openvswitch_port.py +++ b/salt/states/openvswitch_port.py @@ -52,19 +52,19 @@ def present( comments["comment_port_created"] = "Port {} created on bridge {}.".format( name, bridge ) - comments[ - "comment_port_notcreated" - ] = "Unable to create port {} on bridge {}.".format(name, bridge) + comments["comment_port_notcreated"] = ( + "Unable to create port {} on bridge {}.".format(name, bridge) + ) comments["changes_port_created"] = { name: { "old": "No port named {} present.".format(name), "new": "Created port {1} on bridge {0}.".format(bridge, name), } } - comments[ - "comment_port_internal" - ] = "Port {} already exists, but interface type has been changed to internal.".format( - name + comments["comment_port_internal"] = ( + "Port {} already exists, but interface type has been changed to internal.".format( + name + ) ) comments["changes_port_internal"] = {"internal": {"old": False, "new": True}} comments["comment_port_internal_not_changed"] = ( @@ -76,23 +76,23 @@ def present( comments["comment_invalid_ip"] = "Remote is not valid ip address." if tunnel_type == "vlan": comments["comment_vlan_invalid_id"] = "VLANs id must be between 0 and 4095." - comments[ - "comment_vlan_invalid_name" - ] = "Could not find network interface {}.".format(name) - comments[ - "comment_vlan_port_exists" - ] = "Port {} with access to VLAN {} already exists on bridge {}.".format( - name, id, bridge + comments["comment_vlan_invalid_name"] = ( + "Could not find network interface {}.".format(name) ) - comments[ - "comment_vlan_created" - ] = "Created port {} with access to VLAN {} on bridge {}.".format( - name, id, bridge + comments["comment_vlan_port_exists"] = ( + "Port {} with access to VLAN {} already exists on bridge {}.".format( + name, id, bridge + ) ) - comments[ - "comment_vlan_notcreated" - ] = "Unable to create port {} with access to VLAN {} on bridge {}.".format( - name, id, bridge + comments["comment_vlan_created"] = ( + "Created port {} with access to VLAN {} on bridge {}.".format( + name, id, bridge + ) + ) + comments["comment_vlan_notcreated"] = ( + "Unable to create port {} with access to VLAN {} on bridge {}.".format( + name, id, bridge + ) ) comments["changes_vlan_created"] = { name: { @@ -108,9 +108,9 @@ def present( } elif tunnel_type == "gre": - comments[ - "comment_gre_invalid_id" - ] = "Id of GRE tunnel must be an unsigned 32-bit integer." + comments["comment_gre_invalid_id"] = ( + "Id of GRE tunnel must be an unsigned 32-bit integer." + ) comments["comment_gre_interface_exists"] = ( "GRE tunnel interface {} with rempte ip {} and key {} " "already exists on bridge {}.".format(name, remote, id, bridge) @@ -139,9 +139,9 @@ def present( comments["comment_dstport"] = ( " (dst_port" + str(dst_port) + ")" if 0 < dst_port <= 65535 else "" ) - comments[ - "comment_vxlan_invalid_id" - ] = "Id of VXLAN tunnel must be an unsigned 64-bit integer." + comments["comment_vxlan_invalid_id"] = ( + "Id of VXLAN tunnel must be an unsigned 64-bit integer." + ) comments["comment_vxlan_interface_exists"] = ( "VXLAN tunnel interface {} with rempte ip {} and key {} " "already exists on bridge {}{}.".format( diff --git a/salt/states/opsgenie.py b/salt/states/opsgenie.py index 8e80bf2ef90..f7cafcccfd9 100644 --- a/salt/states/opsgenie.py +++ b/salt/states/opsgenie.py @@ -75,10 +75,10 @@ def create_alert(name=None, api_key=None, reason=None, action_type="Create"): raise salt.exceptions.SaltInvocationError("API Key or Reason cannot be None.") if __opts__["test"] is True: - ret[ - "comment" - ] = 'Test: {} alert request will be processed using the API Key="{}".'.format( - action_type, api_key + ret["comment"] = ( + 'Test: {} alert request will be processed using the API Key="{}".'.format( + action_type, api_key + ) ) # Return ``None`` when running with ``test=true``. @@ -96,10 +96,10 @@ def create_alert(name=None, api_key=None, reason=None, action_type="Create"): response_text, response_status_code, ) - ret[ - "comment" - ] = 'Test: {} alert request will be processed using the API Key="{}".'.format( - action_type, api_key + ret["comment"] = ( + 'Test: {} alert request will be processed using the API Key="{}".'.format( + action_type, api_key + ) ) ret["result"] = True else: diff --git a/salt/states/pbm.py b/salt/states/pbm.py index ae21462ea47..6e761f41957 100644 --- a/salt/states/pbm.py +++ b/salt/states/pbm.py @@ -90,7 +90,6 @@ PyVmomi can be installed via pip: information. """ - import copy import logging import sys diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index f8447ec350c..917d2748778 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -18,7 +18,6 @@ requisite to a pkg.installed state for the package which provides pip - pkg: python-pip """ - import logging import re import sys diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 908d3711b07..df57a7477a2 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -67,6 +67,7 @@ state module Make sure the package name has the correct case for package managers which are case-sensitive (such as :mod:`pkgng `). """ + import fnmatch import logging import os @@ -1890,10 +1891,10 @@ def installed( ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while installing package(s): {}".format( - exc + ret["comment"] = ( + "An error was encountered while installing package(s): {}".format( + exc + ) ) if warnings: ret.setdefault("warnings", []).extend(warnings) @@ -2298,9 +2299,9 @@ def downloaded( ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while downloading package(s): {}".format(exc) + ret["comment"] = ( + "An error was encountered while downloading package(s): {}".format(exc) + ) return ret new_pkgs = __salt__["pkg.list_downloaded"](**kwargs) @@ -2355,9 +2356,9 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): if "pkg.list_patches" not in __salt__: ret["result"] = False - ret[ - "comment" - ] = "The pkg.patch_installed state is not available on this platform" + ret["comment"] = ( + "The pkg.patch_installed state is not available on this platform" + ) return ret if isinstance(advisory_ids, list) and len(advisory_ids) == 0: @@ -2378,9 +2379,9 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): if __opts__["test"]: summary = ", ".join(targets) - ret[ - "comment" - ] = "The following advisory patches would be downloaded: {}".format(summary) + ret["comment"] = ( + "The following advisory patches would be downloaded: {}".format(summary) + ) return ret try: @@ -2397,18 +2398,18 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while downloading package(s): {}".format(exc) + ret["comment"] = ( + "An error was encountered while downloading package(s): {}".format(exc) + ) return ret if not ret["changes"] and not ret["comment"]: status = "downloaded" if downloadonly else "installed" ret["result"] = True - ret[ - "comment" - ] = "Advisory patch is not needed or related packages are already {}".format( - status + ret["comment"] = ( + "Advisory patch is not needed or related packages are already {}".format( + status + ) ) return ret @@ -3094,9 +3095,9 @@ def removed(name, version=None, pkgs=None, normalize=True, ignore_epoch=None, ** ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while removing package(s): {}".format(exc) + ret["comment"] = ( + "An error was encountered while removing package(s): {}".format(exc) + ) return ret @@ -3186,9 +3187,9 @@ def purged(name, version=None, pkgs=None, normalize=True, ignore_epoch=None, **k ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while purging package(s): {}".format(exc) + ret["comment"] = ( + "An error was encountered while purging package(s): {}".format(exc) + ) return ret @@ -3278,9 +3279,9 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs): ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while updating packages: {}".format(exc) + ret["comment"] = ( + "An error was encountered while updating packages: {}".format(exc) + ) return ret # If a package list was provided, ensure those packages were updated @@ -3425,19 +3426,19 @@ def group_installed(name, skip=None, include=None, **kwargs): if "unexpected keyword argument" in str(err): ret["comment"] = "Repo options are not supported on this platform" else: - ret[ - "comment" - ] = f"An error was encountered while installing/updating group '{name}': {err}." + ret["comment"] = ( + f"An error was encountered while installing/updating group '{name}': {err}." + ) return ret mandatory = diff["mandatory"]["installed"] + diff["mandatory"]["not installed"] invalid_skip = [x for x in mandatory if x in skip] if invalid_skip: - ret[ - "comment" - ] = "The following mandatory packages cannot be skipped: {}".format( - ", ".join(invalid_skip) + ret["comment"] = ( + "The following mandatory packages cannot be skipped: {}".format( + ", ".join(invalid_skip) + ) ) return ret @@ -3459,9 +3460,9 @@ def group_installed(name, skip=None, include=None, **kwargs): if __opts__["test"]: ret["result"] = None if partially_installed: - ret[ - "comment" - ] = "Group '{}' is partially installed and will be updated".format(name) + ret["comment"] = ( + "Group '{}' is partially installed and will be updated".format(name) + ) else: ret["comment"] = "Group '{}' will be installed".format(name) return ret @@ -3960,9 +3961,11 @@ def unheld(name, version=None, pkgs=None, all=False, **kwargs): comments.append( "The following package would be unheld: {}{}".format( pkg_name, - "" - if not dpkgs.get(pkg_name) - else " (version = {})".format(lock_ver), + ( + "" + if not dpkgs.get(pkg_name) + else " (version = {})".format(lock_ver) + ), ) ) else: diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py index 7a55c5c0c59..3aaa5791a27 100644 --- a/salt/states/pkgrepo.py +++ b/salt/states/pkgrepo.py @@ -117,7 +117,6 @@ Using ``aptkey: False`` with ``keyserver`` and ``keyid``: - aptkey: False """ - import sys import salt.utils.data @@ -365,15 +364,15 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): if "key_url" in kwargs and ("keyid" in kwargs or "keyserver" in kwargs): ret["result"] = False - ret[ - "comment" - ] = 'You may not use both "keyid"/"keyserver" and "key_url" argument.' + ret["comment"] = ( + 'You may not use both "keyid"/"keyserver" and "key_url" argument.' + ) if "key_text" in kwargs and ("keyid" in kwargs or "keyserver" in kwargs): ret["result"] = False - ret[ - "comment" - ] = 'You may not use both "keyid"/"keyserver" and "key_text" argument.' + ret["comment"] = ( + 'You may not use both "keyid"/"keyserver" and "key_text" argument.' + ) if "key_text" in kwargs and ("key_url" in kwargs): ret["result"] = False ret["comment"] = 'You may not use both "key_url" and "key_text" argument.' @@ -409,9 +408,9 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = "Cannot have 'key_url' using http with 'allow_insecure_key' set to True" + ret["comment"] = ( + "Cannot have 'key_url' using http with 'allow_insecure_key' set to True" + ) return ret repo = name diff --git a/salt/states/ports.py b/salt/states/ports.py index b4e53c4a6a7..2d9acff696e 100644 --- a/salt/states/ports.py +++ b/salt/states/ports.py @@ -128,10 +128,10 @@ def installed(name, options=None): if not default_options: if options: ret["result"] = False - ret[ - "comment" - ] = "{} does not have any build options, yet options were specified".format( - name + ret["comment"] = ( + "{} does not have any build options, yet options were specified".format( + name + ) ) return ret else: @@ -143,10 +143,10 @@ def installed(name, options=None): bad_opts = [x for x in options if x not in default_options] if bad_opts: ret["result"] = False - ret[ - "comment" - ] = "The following options are not available for {}: {}".format( - name, ", ".join(bad_opts) + ret["comment"] = ( + "The following options are not available for {}: {}".format( + name, ", ".join(bad_opts) + ) ) return ret diff --git a/salt/states/postgres_database.py b/salt/states/postgres_database.py index 7e162d6e7ff..b5de4fa1f97 100644 --- a/salt/states/postgres_database.py +++ b/salt/states/postgres_database.py @@ -119,17 +119,19 @@ def present( return ret elif name in dbs and any( ( - db_params.get("Encoding").lower() != encoding.lower() - if encoding - else False, + ( + db_params.get("Encoding").lower() != encoding.lower() + if encoding + else False + ), db_params.get("Collate") != lc_collate if lc_collate else False, db_params.get("Ctype") != lc_ctype if lc_ctype else False, ) ): - ret[ - "comment" - ] = "Database {} has wrong parameters which couldn't be changed on fly.".format( - name + ret["comment"] = ( + "Database {} has wrong parameters which couldn't be changed on fly.".format( + name + ) ) ret["result"] = False return ret @@ -140,9 +142,9 @@ def present( if name not in dbs: ret["comment"] = "Database {} is set to be created".format(name) else: - ret[ - "comment" - ] = "Database {} exists, but parameters need to be changed".format(name) + ret["comment"] = ( + "Database {} exists, but parameters need to be changed".format(name) + ) return ret if name not in dbs and __salt__["postgres.db_create"]( name, diff --git a/salt/states/postgres_privileges.py b/salt/states/postgres_privileges.py index 9241c2de6e4..9829e583441 100644 --- a/salt/states/postgres_privileges.py +++ b/salt/states/postgres_privileges.py @@ -311,10 +311,10 @@ def absent( if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "The privilege(s): {} are set to be revoked from {}".format( - _privs, name + ret["comment"] = ( + "The privilege(s): {} are set to be revoked from {}".format( + _privs, name + ) ) return ret diff --git a/salt/states/postgres_schema.py b/salt/states/postgres_schema.py index 0f58db1afe8..7e77da04642 100644 --- a/salt/states/postgres_schema.py +++ b/salt/states/postgres_schema.py @@ -166,10 +166,10 @@ def absent( ret["comment"] = "Schema {} failed to be removed".format(name) return ret else: - ret[ - "comment" - ] = "Schema {} is not present in database {}, so it cannot be removed".format( - name, dbname + ret["comment"] = ( + "Schema {} is not present in database {}, so it cannot be removed".format( + name, dbname + ) ) return ret diff --git a/salt/states/postgres_tablespace.py b/salt/states/postgres_tablespace.py index fcb28d68774..a946b1b65fc 100644 --- a/salt/states/postgres_tablespace.py +++ b/salt/states/postgres_tablespace.py @@ -15,7 +15,6 @@ A module used to create and manage PostgreSQL tablespaces. """ - import salt.utils.dictupdate as dictupdate @@ -120,11 +119,11 @@ def present( # already exists, make sure it's got the right config if tblspaces[name]["Location"] != directory and not __opts__["test"]: - ret[ - "comment" - ] = """Tablespace {} is not at the right location. This is + ret["comment"] = ( + """Tablespace {} is not at the right location. This is unfixable without dropping and recreating the tablespace.""".format( - name + name + ) ) ret["result"] = False return ret @@ -152,11 +151,11 @@ def present( if "{}={}".format(k, v) not in tblspaces[name]["Opts"]: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = """Tablespace {} options to be + ret["comment"] = ( + """Tablespace {} options to be altered""".format( - name + name + ) ) break # we know it's going to be altered, no reason to cont if __salt__["postgres.tablespace_alter"](name, set_option={k: v}): diff --git a/salt/states/probes.py b/salt/states/probes.py index 6adc6183f4e..1c7e7525000 100644 --- a/salt/states/probes.py +++ b/salt/states/probes.py @@ -54,7 +54,6 @@ def __virtual__(): def _default_ret(name): - """ Returns a default structure of the dictionary to be returned as output of the state functions. """ @@ -63,7 +62,6 @@ def _default_ret(name): def _retrieve_rpm_probes(): - """ Will retrieve the probes from the network device using salt module "probes" throught NAPALM proxy. """ @@ -72,7 +70,6 @@ def _retrieve_rpm_probes(): def _expand_probes(probes, defaults): - """ Updates the probes dictionary with different levels of default values. """ @@ -104,7 +101,6 @@ def _expand_probes(probes, defaults): def _clean_probes(probes): - """ Will remove empty and useless values from the probes dictionary. """ @@ -127,7 +123,6 @@ def _clean_probes(probes): def _compare_probes(configured_probes, expected_probes): - """ Compares configured probes on the device with the expected configuration and returns the differences. """ @@ -190,14 +185,12 @@ def _compare_probes(configured_probes, expected_probes): def _ordered_dict_to_dict(probes): - """Mandatory to be dict type in order to be used in the NAPALM Jinja template.""" return salt.utils.json.loads(salt.utils.json.dumps(probes)) def _set_rpm_probes(probes): - """ Calls the Salt module "probes" to configure the probes on the device. """ @@ -209,7 +202,6 @@ def _set_rpm_probes(probes): def _schedule_probes(probes): - """ Calls the Salt module "probes" to schedule the configured probes on the device. """ @@ -221,7 +213,6 @@ def _schedule_probes(probes): def _delete_rpm_probes(probes): - """ Calls the Salt module "probes" to delete probes from the device. """ @@ -240,7 +231,6 @@ def _delete_rpm_probes(probes): def managed(name, probes, defaults=None): - """ Ensure the networks device is configured as specified in the state SLS file. Probes not specified will be removed, while probes not confiured as expected will trigger config updates. diff --git a/salt/states/rabbitmq_plugin.py b/salt/states/rabbitmq_plugin.py index d59e74fa035..4994e52f95f 100644 --- a/salt/states/rabbitmq_plugin.py +++ b/salt/states/rabbitmq_plugin.py @@ -12,7 +12,6 @@ Example: rabbitmq_plugin.enabled: [] """ - import logging from salt.exceptions import CommandExecutionError diff --git a/salt/states/rabbitmq_upstream.py b/salt/states/rabbitmq_upstream.py index da0e74ee746..35e0b008454 100644 --- a/salt/states/rabbitmq_upstream.py +++ b/salt/states/rabbitmq_upstream.py @@ -17,7 +17,6 @@ Example: .. versionadded:: 3000 """ - import json import logging diff --git a/salt/states/rabbitmq_user.py b/salt/states/rabbitmq_user.py index 8cf9d5f7e75..fcd14ce3757 100644 --- a/salt/states/rabbitmq_user.py +++ b/salt/states/rabbitmq_user.py @@ -21,7 +21,6 @@ Example: - runas: rabbitmq """ - import logging import salt.utils.path diff --git a/salt/states/rabbitmq_vhost.py b/salt/states/rabbitmq_vhost.py index 4231e9519f4..3aba14a55d1 100644 --- a/salt/states/rabbitmq_vhost.py +++ b/salt/states/rabbitmq_vhost.py @@ -14,7 +14,6 @@ Example: - read: .* """ - import logging import salt.utils.path diff --git a/salt/states/restconf.py b/salt/states/restconf.py index 4ac74e27bd4..44fcbc5896c 100644 --- a/salt/states/restconf.py +++ b/salt/states/restconf.py @@ -11,7 +11,6 @@ This state module was designed to manage RESTCONF states. This module relies on the RESTCONF proxy module to interface with the devices. """ - import difflib import json import logging diff --git a/salt/states/saltmod.py b/salt/states/saltmod.py index d904da011d0..e120e418875 100644 --- a/salt/states/saltmod.py +++ b/salt/states/saltmod.py @@ -349,9 +349,11 @@ def state( cmd_ret = { __opts__["id"]: { "ret": tmp_ret, - "out": tmp_ret.get("out", "highstate") - if isinstance(tmp_ret, dict) - else "highstate", + "out": ( + tmp_ret.get("out", "highstate") + if isinstance(tmp_ret, dict) + else "highstate" + ), } } diff --git a/salt/states/serverdensity_device.py b/salt/states/serverdensity_device.py index bce8db5bc92..02eced4b42f 100644 --- a/salt/states/serverdensity_device.py +++ b/salt/states/serverdensity_device.py @@ -46,7 +46,6 @@ Example: serverdensity_device.monitored """ - import logging import salt.utils.json @@ -206,9 +205,9 @@ def monitored( ret["changes"] = {} if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Agent is not installed and device is not in the Server Density DB" + ret["comment"] = ( + "Agent is not installed and device is not in the Server Density DB" + ) return ret if __opts__["test"]: @@ -224,8 +223,8 @@ def monitored( ) ret["result"] = True - ret[ - "comment" - ] = "Successfully installed agent and created device in Server Density db." + ret["comment"] = ( + "Successfully installed agent and created device in Server Density db." + ) ret["changes"] = {"created_device": device, "installed_agent": installed_agent} return ret diff --git a/salt/states/service.py b/salt/states/service.py index 0bb04c34cc1..650def38a38 100644 --- a/salt/states/service.py +++ b/salt/states/service.py @@ -155,10 +155,10 @@ def _enable(name, started, result=True, **kwargs): # Check to see if this minion supports enable if "service.enable" not in __salt__ or "service.enabled" not in __salt__: if started is True: - ret[ - "comment" - ] = "Enable is not available on this minion, service {} started".format( - name + ret["comment"] = ( + "Enable is not available on this minion, service {} started".format( + name + ) ) elif started is None: ret["comment"] = ( @@ -166,10 +166,10 @@ def _enable(name, started, result=True, **kwargs): " service {} is in the desired state".format(name) ) else: - ret[ - "comment" - ] = "Enable is not available on this minion, service {} is dead".format( - name + ret["comment"] = ( + "Enable is not available on this minion, service {} is dead".format( + name + ) ) return ret @@ -184,10 +184,10 @@ def _enable(name, started, result=True, **kwargs): elif started is None: # always be sure in this case to reset the changes dict ret["changes"] = {} - ret[ - "comment" - ] = "Service {} is already enabled, and is in the desired state".format( - name + ret["comment"] = ( + "Service {} is already enabled, and is in the desired state".format( + name + ) ) else: ret["comment"] = "Service {} is already enabled, and is dead".format(name) @@ -214,10 +214,10 @@ def _enable(name, started, result=True, **kwargs): name ) elif started is None: - ret[ - "comment" - ] = "Service {} has been enabled, and is in the desired state".format( - name + ret["comment"] = ( + "Service {} has been enabled, and is in the desired state".format( + name + ) ) else: ret["comment"] = "Service {} has been enabled, and is dead".format(name) @@ -240,10 +240,10 @@ def _enable(name, started, result=True, **kwargs): " but the service was already running".format(name) ) else: - ret[ - "comment" - ] = "Failed when setting service {} to start at boot, and the service is dead".format( - name + ret["comment"] = ( + "Failed when setting service {} to start at boot, and the service is dead".format( + name + ) ) if enable_error: @@ -274,10 +274,10 @@ def _disable(name, started, result=True, **kwargs): # is enable/disable available? if "service.disable" not in __salt__ or "service.disabled" not in __salt__: if started is True: - ret[ - "comment" - ] = "Disable is not available on this minion, service {} started".format( - name + ret["comment"] = ( + "Disable is not available on this minion, service {} started".format( + name + ) ) elif started is None: ret["comment"] = ( @@ -285,10 +285,10 @@ def _disable(name, started, result=True, **kwargs): " service {} is in the desired state".format(name) ) else: - ret[ - "comment" - ] = "Disable is not available on this minion, service {} is dead".format( - name + ret["comment"] = ( + "Disable is not available on this minion, service {} is dead".format( + name + ) ) return ret @@ -310,10 +310,10 @@ def _disable(name, started, result=True, **kwargs): elif started is None: # always be sure in this case to reset the changes dict ret["changes"] = {} - ret[ - "comment" - ] = "Service {} is already disabled, and is in the desired state".format( - name + ret["comment"] = ( + "Service {} is already disabled, and is in the desired state".format( + name + ) ) else: ret["comment"] = "Service {} is already disabled, and is dead".format(name) @@ -337,9 +337,9 @@ def _disable(name, started, result=True, **kwargs): if started is True: ret["comment"] = "Service {} has been disabled, and is running".format(name) elif started is None: - ret[ - "comment" - ] = "Service {} has been disabled, and is in the desired state".format(name) + ret["comment"] = ( + "Service {} has been disabled, and is in the desired state".format(name) + ) else: ret["comment"] = "Service {} has been disabled, and is dead".format(name) return ret @@ -347,10 +347,10 @@ def _disable(name, started, result=True, **kwargs): # Service failed to be disabled ret["result"] = False if started is True: - ret[ - "comment" - ] = "Failed when setting service {} to not start at boot, and is running".format( - name + ret["comment"] = ( + "Failed when setting service {} to not start at boot, and is running".format( + name + ) ) elif started is None: ret["comment"] = ( diff --git a/salt/states/slack.py b/salt/states/slack.py index a0c1b3a2dfc..1ba0f4b4e59 100644 --- a/salt/states/slack.py +++ b/salt/states/slack.py @@ -24,7 +24,6 @@ The api key can be specified in the master or minion configuration like below: """ - from salt.exceptions import SaltInvocationError diff --git a/salt/states/smartos.py b/salt/states/smartos.py index 7420d6ba33f..29c2bb72352 100644 --- a/salt/states/smartos.py +++ b/salt/states/smartos.py @@ -381,10 +381,10 @@ def config_present(name, value): ret["result"] = _write_config(config) if not ret["result"]: - ret[ - "comment" - ] = 'Could not add property {} with value "{}" to config'.format( - name, value + ret["comment"] = ( + 'Could not add property {} with value "{}" to config'.format( + name, value + ) ) return ret @@ -1026,9 +1026,9 @@ def vm_present(name, vmconfig, config=None): "update_{}".format(instance) ] = [] - update_cfg[ - vmconfig_type["instance"][instance] - ] = state_cfg[vmconfig_type["instance"][instance]] + update_cfg[vmconfig_type["instance"][instance]] = ( + state_cfg[vmconfig_type["instance"][instance]] + ) vmconfig["changed"][ "update_{}".format(instance) ].append(update_cfg) @@ -1156,9 +1156,9 @@ def vm_present(name, vmconfig, config=None): ) if vmconfig["state"]["hostname"] not in ret["changes"]: ret["changes"][vmconfig["state"]["hostname"]] = {} - ret["changes"][vmconfig["state"]["hostname"]][ - "image_uuid" - ] = vmconfig["reprovision_uuid"] + ret["changes"][vmconfig["state"]["hostname"]]["image_uuid"] = ( + vmconfig["reprovision_uuid"] + ) else: log.warning( "smartos.vm_present::%s::reprovision - " diff --git a/salt/states/snapper.py b/salt/states/snapper.py index 964c88c5001..6a6a7d66973 100644 --- a/salt/states/snapper.py +++ b/salt/states/snapper.py @@ -106,7 +106,6 @@ and include this change. :platform: Linux """ - import os diff --git a/salt/states/solrcloud.py b/salt/states/solrcloud.py index 6e9aaab545e..edbb6baf74b 100644 --- a/salt/states/solrcloud.py +++ b/salt/states/solrcloud.py @@ -5,7 +5,6 @@ States for solrcloud alias and collection configuration """ - import salt.utils.json diff --git a/salt/states/sqlite3.py b/salt/states/sqlite3.py index d0eb0615dd2..3cddab97d97 100644 --- a/salt/states/sqlite3.py +++ b/salt/states/sqlite3.py @@ -92,7 +92,6 @@ can be approximated with sqlite3's module functions and module.run: - sqlite3: zone-insert-12 """ - try: import sqlite3 diff --git a/salt/states/ssh_auth.py b/salt/states/ssh_auth.py index 1806a34709a..19bc0ae2934 100644 --- a/salt/states/ssh_auth.py +++ b/salt/states/ssh_auth.py @@ -59,7 +59,6 @@ to use a YAML 'explicit key', as demonstrated in the second example below. - AAAAB3NzaC1kcQ9fJFF435bYTEyY== newcomment """ - import re import sys @@ -356,10 +355,10 @@ def present( ) return ret elif data == "no change": - ret[ - "comment" - ] = "The authorized host key {} is already present for user {}".format( - name, user + ret["comment"] = ( + "The authorized host key {} is already present for user {}".format( + name, user + ) ) elif data == "new": ret["changes"][name] = "New" @@ -386,9 +385,9 @@ def present( ) elif data == "invalid" or data == "Invalid public key": ret["result"] = False - ret[ - "comment" - ] = "Invalid public ssh key, most likely has spaces or invalid syntax" + ret["comment"] = ( + "Invalid public ssh key, most likely has spaces or invalid syntax" + ) return ret diff --git a/salt/states/supervisord.py b/salt/states/supervisord.py index d0a5614c939..68ec8717ad6 100644 --- a/salt/states/supervisord.py +++ b/salt/states/supervisord.py @@ -82,9 +82,9 @@ def running( if "supervisord.status" not in __salt__: ret["result"] = False - ret[ - "comment" - ] = "Supervisord module not activated. Do you need to install supervisord?" + ret["comment"] = ( + "Supervisord module not activated. Do you need to install supervisord?" + ) return ret all_processes = __salt__["supervisord.status"]( @@ -115,14 +115,14 @@ def running( if name.endswith(":"): # Process group if len(to_start) == len(matches): - ret[ - "comment" - ] = "All services in group '{}' will be started".format(name) + ret["comment"] = ( + "All services in group '{}' will be started".format(name) + ) else: - ret[ - "comment" - ] = "The following services will be started: {}".format( - " ".join(to_start) + ret["comment"] = ( + "The following services will be started: {}".format( + " ".join(to_start) + ) ) else: # Single program @@ -130,9 +130,9 @@ def running( else: if name.endswith(":"): # Process group - ret[ - "comment" - ] = "All services in group '{}' are already running".format(name) + ret["comment"] = ( + "All services in group '{}' are already running".format(name) + ) else: ret["comment"] = "Service {} is already running".format(name) else: diff --git a/salt/states/sysrc.py b/salt/states/sysrc.py index 991e33bbff9..2a620b4cc93 100644 --- a/salt/states/sysrc.py +++ b/salt/states/sysrc.py @@ -3,7 +3,6 @@ State to work with sysrc """ - # define the module's virtual name __virtualname__ = "sysrc" diff --git a/salt/states/telemetry_alert.py b/salt/states/telemetry_alert.py index ccbe8fb9791..eb94cb86b3e 100644 --- a/salt/states/telemetry_alert.py +++ b/salt/states/telemetry_alert.py @@ -190,10 +190,10 @@ def absent(name, deployment_id, metric_name, api_key=None, profile="telemetry"): if is_present: alert_id = is_present.get("_id") if __opts__["test"]: - ret[ - "comment" - ] = "alert {} is set to be removed from deployment: {}.".format( - metric_name, deployment_id + ret["comment"] = ( + "alert {} is set to be removed from deployment: {}.".format( + metric_name, deployment_id + ) ) ret["result"] = None return ret diff --git a/salt/states/timezone.py b/salt/states/timezone.py index 514e4c0dda6..558cd1d6486 100644 --- a/salt/states/timezone.py +++ b/salt/states/timezone.py @@ -58,10 +58,10 @@ def system(name, utc=True): compzone = __salt__["timezone.zone_compare"](name) except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret[ - "comment" - ] = "Unable to compare desired timezone '{}' to system timezone: {}".format( - name, exc + ret["comment"] = ( + "Unable to compare desired timezone '{}' to system timezone: {}".format( + name, exc + ) ) return ret diff --git a/salt/states/tls.py b/salt/states/tls.py index 8e0f1249424..9881505d124 100644 --- a/salt/states/tls.py +++ b/salt/states/tls.py @@ -4,7 +4,6 @@ Enforce state for SSL/TLS """ - import datetime import logging import time diff --git a/salt/states/tuned.py b/salt/states/tuned.py index d158f2ad104..91759ddb76f 100644 --- a/salt/states/tuned.py +++ b/salt/states/tuned.py @@ -7,7 +7,6 @@ Interface to Red Hat tuned-adm module :platform: Linux """ - import salt.exceptions diff --git a/salt/states/user.py b/salt/states/user.py index d575655cf34..83693a809ac 100644 --- a/salt/states/user.py +++ b/salt/states/user.py @@ -914,10 +914,10 @@ def present( __salt__["shadow.set_password"](name, password) spost = __salt__["shadow.info"](name) if spost["passwd"] != password: - ret[ - "comment" - ] = "User {} created but failed to set password to {}".format( - name, "XXX-REDACTED-XXX" + ret["comment"] = ( + "User {} created but failed to set password to {}".format( + name, "XXX-REDACTED-XXX" + ) ) ret["result"] = False ret["changes"]["password"] = "XXX-REDACTED-XXX" @@ -925,9 +925,9 @@ def present( __salt__["shadow.del_password"](name) spost = __salt__["shadow.info"](name) if spost["passwd"] != "": - ret[ - "comment" - ] = "User {} created but failed to empty password".format(name) + ret["comment"] = ( + "User {} created but failed to empty password".format(name) + ) ret["result"] = False ret["changes"]["password"] = "" if date is not None: @@ -978,10 +978,10 @@ def present( __salt__["shadow.set_warndays"](name, warndays) spost = __salt__["shadow.info"](name) if spost["warn"] != warndays: - ret[ - "comment" - ] = "User {} created but failed to set warn days to {}".format( - name, warndays + ret["comment"] = ( + "User {} created but failed to set warn days to {}".format( + name, warndays + ) ) ret["result"] = False ret["changes"]["warndays"] = warndays @@ -999,10 +999,10 @@ def present( elif salt.utils.platform.is_windows(): if password and not empty_password: if not __salt__["user.setpassword"](name, password): - ret[ - "comment" - ] = "User {} created but failed to set password to {}".format( - name, "XXX-REDACTED-XXX" + ret["comment"] = ( + "User {} created but failed to set password to {}".format( + name, "XXX-REDACTED-XXX" + ) ) ret["result"] = False ret["changes"]["passwd"] = "XXX-REDACTED-XXX" @@ -1021,10 +1021,10 @@ def present( ret["changes"]["expiration_date"] = spost["expire"] elif salt.utils.platform.is_darwin() and password and not empty_password: if not __salt__["shadow.set_password"](name, password): - ret[ - "comment" - ] = "User {} created but failed to set password to {}".format( - name, "XXX-REDACTED-XXX" + ret["comment"] = ( + "User {} created but failed to set password to {}".format( + name, "XXX-REDACTED-XXX" + ) ) ret["result"] = False ret["changes"]["passwd"] = "XXX-REDACTED-XXX" diff --git a/salt/states/vbox_guest.py b/salt/states/vbox_guest.py index 45a78381d59..78907dd14f7 100644 --- a/salt/states/vbox_guest.py +++ b/salt/states/vbox_guest.py @@ -126,9 +126,9 @@ def grant_access_to_shared_folders_to(name, users=None): name=name, users=users ) - ret[ - "comment" - ] = "List of users who have access to auto-mounted shared folders was changed" + ret["comment"] = ( + "List of users who have access to auto-mounted shared folders was changed" + ) ret["changes"] = { "old": current_state, "new": new_state, diff --git a/salt/states/virt.py b/salt/states/virt.py index 3b958e32d60..2565be0af4a 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -11,7 +11,6 @@ for the generation and signing of certificates for systems running libvirt: virt.keys """ - import fnmatch import logging import os @@ -680,9 +679,9 @@ def defined( ret["comment"] = "Domain {} unchanged".format(name) ret["result"] = True elif status.get("errors"): - ret[ - "comment" - ] = "Domain {} updated with live update(s) failures".format(name) + ret["comment"] = ( + "Domain {} updated with live update(s) failures".format(name) + ) else: ret["comment"] = "Domain {} updated".format(name) else: @@ -2422,9 +2421,9 @@ def volume_defined( # otherwise assume the volume has already been defined # if the sizes don't match, issue a warning comment: too dangerous to do this for now if int(vol_infos.get("capacity")) != int(size) * 1024 * 1024: - ret[ - "comment" - ] = "The capacity of the volume is different, but no resize performed" + ret["comment"] = ( + "The capacity of the volume is different, but no resize performed" + ) return ret ret["result"] = None if __opts__["test"] else True diff --git a/salt/states/virtualenv_mod.py b/salt/states/virtualenv_mod.py index d395dd2cc1a..729e16a8e28 100644 --- a/salt/states/virtualenv_mod.py +++ b/salt/states/virtualenv_mod.py @@ -4,7 +4,6 @@ Setup of Python virtualenv sandboxes. .. versionadded:: 0.17.0 """ - import logging import os diff --git a/salt/states/webutil.py b/salt/states/webutil.py index 573e494cef6..d988c4e30e0 100644 --- a/salt/states/webutil.py +++ b/salt/states/webutil.py @@ -14,7 +14,6 @@ Support for htpasswd module. Requires the apache2-utils package for Debian-based """ - import salt.utils.path __virtualname__ = "webutil" diff --git a/salt/states/win_dns_client.py b/salt/states/win_dns_client.py index 9afa0faf368..48d045bbd76 100644 --- a/salt/states/win_dns_client.py +++ b/salt/states/win_dns_client.py @@ -89,9 +89,9 @@ def dns_exists(name, servers=None, interface="Local Area Connection", replace=Fa ret["changes"]["Servers Removed"].append(server) else: if not __salt__["win_dns_client.rm_dns"](server, interface): - ret[ - "comment" - ] = "Failed to remove {} from DNS server list".format(server) + ret["comment"] = ( + "Failed to remove {} from DNS server list".format(server) + ) ret["result"] = False return ret else: @@ -217,10 +217,10 @@ def primary_suffix(name, suffix=None, updates=False): else: # Changes to updates policy needed if reg_data["updates"]["new"] != reg_data["updates"]["old"]: - ret[ - "comment" - ] = "Updated primary DNS suffix ({}) and {} suffix updates".format( - suffix, updates_operation + ret["comment"] = ( + "Updated primary DNS suffix ({}) and {} suffix updates".format( + suffix, updates_operation + ) ) ret["changes"] = { "old": { diff --git a/salt/states/win_iis.py b/salt/states/win_iis.py index 4d1162680bd..4c19e823e77 100644 --- a/salt/states/win_iis.py +++ b/salt/states/win_iis.py @@ -8,7 +8,6 @@ from Microsoft IIS. """ - # Define the module's virtual name __virtualname__ = "win_iis" diff --git a/salt/states/win_lgpo.py b/salt/states/win_lgpo.py index 07b5d98cb08..125b1e9e895 100644 --- a/salt/states/win_lgpo.py +++ b/salt/states/win_lgpo.py @@ -206,6 +206,7 @@ Multiple policy configuration Windows Components\\Windows Update\\Configure Automatic Updates: """ + import logging import salt.utils.data diff --git a/salt/states/win_lgpo_reg.py b/salt/states/win_lgpo_reg.py index 8377817a198..7bd3919b350 100644 --- a/salt/states/win_lgpo_reg.py +++ b/salt/states/win_lgpo_reg.py @@ -53,6 +53,7 @@ configure that policy. you will have to find the values needed to set them with this module using a different method. """ + import salt.utils.data import salt.utils.platform diff --git a/salt/states/win_network.py b/salt/states/win_network.py index 72bf74fca13..b0549ba6dab 100644 --- a/salt/states/win_network.py +++ b/salt/states/win_network.py @@ -312,27 +312,27 @@ def managed( else: if not __salt__["ip.enable"](name): ret["result"] = False - ret[ - "comment" - ] = "Failed to enable interface '{}' to make changes".format(name) + ret["comment"] = ( + "Failed to enable interface '{}' to make changes".format(name) + ) return ret errors = _validate(dns_proto, dns_servers, ip_proto, ip_addrs, gateway) if errors: ret["result"] = False - ret[ - "comment" - ] = "The following SLS configuration errors were detected:\n- {}".format( - "\n- ".join(errors) + ret["comment"] = ( + "The following SLS configuration errors were detected:\n- {}".format( + "\n- ".join(errors) + ) ) return ret old = __salt__["ip.get_interface"](name) if not old: ret["result"] = False - ret[ - "comment" - ] = "Unable to get current configuration for interface '{}'".format(name) + ret["comment"] = ( + "Unable to get current configuration for interface '{}'".format(name) + ) return ret changes = _changes(old, dns_proto, dns_servers, ip_proto, ip_addrs, gateway) @@ -382,10 +382,10 @@ def managed( ) ret["result"] = None - ret[ - "comment" - ] = "The following changes will be made to interface '{}':\n- {}".format( - name, "\n- ".join(comments) + ret["comment"] = ( + "The following changes will be made to interface '{}':\n- {}".format( + name, "\n- ".join(comments) + ) ) return ret @@ -431,7 +431,7 @@ def managed( "for interface '{}'".format(name) ) else: - ret[ - "comment" - ] = "Successfully updated configuration for interface '{}'".format(name) + ret["comment"] = ( + "Successfully updated configuration for interface '{}'".format(name) + ) return ret diff --git a/salt/states/win_pki.py b/salt/states/win_pki.py index 168939374e1..658d979bef8 100644 --- a/salt/states/win_pki.py +++ b/salt/states/win_pki.py @@ -6,7 +6,6 @@ Microsoft certificate management via the Pki PowerShell module. .. versionadded:: 2016.11.0 """ - _DEFAULT_CONTEXT = "LocalMachine" _DEFAULT_FORMAT = "cer" _DEFAULT_STORE = "My" @@ -104,10 +103,10 @@ def import_cert( cert_props["thumbprint"], store_path ) else: - ret[ - "comment" - ] = "Certificate '{}' unable to be imported into store: {}".format( - cert_props["thumbprint"], store_path + ret["comment"] = ( + "Certificate '{}' unable to be imported into store: {}".format( + cert_props["thumbprint"], store_path + ) ) return ret @@ -163,9 +162,9 @@ def remove_cert(name, thumbprint, context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE thumbprint, store_path ) else: - ret[ - "comment" - ] = "Certificate '{}' unable to be removed from store: {}".format( - thumbprint, store_path + ret["comment"] = ( + "Certificate '{}' unable to be removed from store: {}".format( + thumbprint, store_path + ) ) return ret diff --git a/salt/states/win_powercfg.py b/salt/states/win_powercfg.py index b7f4e82a139..c65b80ad0ed 100644 --- a/salt/states/win_powercfg.py +++ b/salt/states/win_powercfg.py @@ -14,7 +14,6 @@ powercfg. - power: dc """ - import logging import salt.utils.data diff --git a/salt/states/win_shortcut.py b/salt/states/win_shortcut.py index 8443a187a3c..3f14d1f6a4d 100644 --- a/salt/states/win_shortcut.py +++ b/salt/states/win_shortcut.py @@ -6,6 +6,7 @@ shortcuts. .. versionadded:: 3005 """ + import salt.utils.data import salt.utils.path import salt.utils.platform diff --git a/salt/states/win_smtp_server.py b/salt/states/win_smtp_server.py index e3eadc82745..fa5a9a76bbe 100644 --- a/salt/states/win_smtp_server.py +++ b/salt/states/win_smtp_server.py @@ -3,7 +3,6 @@ Module for managing IIS SMTP server configuration on Windows servers. """ - import salt.utils.args _DEFAULT_SERVER = "SmtpSvc/1" @@ -144,17 +143,17 @@ def active_log_format(name, log_format, server=_DEFAULT_SERVER): current_log_format = __salt__["win_smtp_server.get_log_format"](server) if log_format == current_log_format: - ret[ - "comment" - ] = "LogPluginClsid already contains the id of the provided log format." + ret["comment"] = ( + "LogPluginClsid already contains the id of the provided log format." + ) ret["result"] = True elif __opts__["test"]: ret["comment"] = "LogPluginClsid will be changed." ret["changes"] = {"old": current_log_format, "new": log_format} else: - ret[ - "comment" - ] = "Set LogPluginClsid to contain the id of the provided log format." + ret["comment"] = ( + "Set LogPluginClsid to contain the id of the provided log format." + ) ret["changes"] = {"old": current_log_format, "new": log_format} ret["result"] = __salt__["win_smtp_server.set_log_format"](log_format, server) return ret diff --git a/salt/states/win_system.py b/salt/states/win_system.py index 34f47f15e0d..1e8d66ec81e 100644 --- a/salt/states/win_system.py +++ b/salt/states/win_system.py @@ -191,9 +191,7 @@ def workgroup(name): current_workgroup = ( out["Domain"] if "Domain" in out - else out["Workgroup"] - if "Workgroup" in out - else "" + else out["Workgroup"] if "Workgroup" in out else "" ) # Notify the user if the requested workgroup is the same @@ -216,9 +214,7 @@ def workgroup(name): new_workgroup = ( out["Domain"] if "Domain" in out - else out["Workgroup"] - if "Workgroup" in out - else "" + else out["Workgroup"] if "Workgroup" in out else "" ) # Return our results based on the changes @@ -461,14 +457,14 @@ def shutdown( if only_on_pending_reboot and not __salt__["system.get_pending_reboot"](): if __opts__["test"]: - ret[ - "comment" - ] = "System {} will be skipped because no reboot is pending".format(action) + ret["comment"] = ( + "System {} will be skipped because no reboot is pending".format(action) + ) else: - ret[ - "comment" - ] = "System {} has been skipped because no reboot was pending".format( - action + ret["comment"] = ( + "System {} has been skipped because no reboot was pending".format( + action + ) ) return ret diff --git a/salt/states/win_wusa.py b/salt/states/win_wusa.py index 4371bfc1341..17996c0bde7 100644 --- a/salt/states/win_wusa.py +++ b/salt/states/win_wusa.py @@ -7,7 +7,6 @@ without WSUS or Windows Update .. versionadded:: 2018.3.4 """ - import logging import salt.utils.platform diff --git a/salt/states/x509_v2.py b/salt/states/x509_v2.py index ffabf7a4a83..7047b3612c9 100644 --- a/salt/states/x509_v2.py +++ b/salt/states/x509_v2.py @@ -180,6 +180,7 @@ according to the www policy. - require: - x509: /etc/pki/www.key """ + import base64 import copy import datetime @@ -433,9 +434,9 @@ def certificate_managed( file_managed_test = _file_managed(name, test=True, replace=False, **file_args) if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -839,9 +840,9 @@ def crl_managed( if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -1078,9 +1079,9 @@ def csr_managed( if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -1362,9 +1363,9 @@ def private_key_managed( if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -1584,9 +1585,9 @@ def _file_managed(name, test=None, **kwargs): def _check_file_ret(fret, ret, current): if fret["result"] is False: ret["result"] = False - ret[ - "comment" - ] = f"Could not {'create' if not current else 'update'} file, see file.managed output" + ret["comment"] = ( + f"Could not {'create' if not current else 'update'} file, see file.managed output" + ) ret["changes"] = {} return False return True diff --git a/salt/states/zabbix_action.py b/salt/states/zabbix_action.py index 01877edcacd..c3ff6a05054 100644 --- a/salt/states/zabbix_action.py +++ b/salt/states/zabbix_action.py @@ -164,10 +164,10 @@ def present(name, params, **kwargs): else: ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( + name + ) ) else: diff --git a/salt/states/zabbix_template.py b/salt/states/zabbix_template.py index 53efe618cac..0e0bc6169eb 100644 --- a/salt/states/zabbix_template.py +++ b/salt/states/zabbix_template.py @@ -867,10 +867,10 @@ def present(name, params, static_host_list=True, **kwargs): if not CHANGE_STACK: ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Template "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Template "{}" already exists and corresponds to a definition.'.format( + name + ) ) else: tmpl_action = next( diff --git a/salt/states/zabbix_user.py b/salt/states/zabbix_user.py index 51158b2e599..e1236458801 100644 --- a/salt/states/zabbix_user.py +++ b/salt/states/zabbix_user.py @@ -6,7 +6,6 @@ Management of Zabbix users. """ - import logging from copy import deepcopy @@ -84,9 +83,9 @@ def admin_password_present(name, password=None, **kwargs): unique_passwords.reverse() if not unique_passwords: - ret[ - "comment" - ] = "Could not find any Zabbix Admin password setting! See documentation." + ret["comment"] = ( + "Could not find any Zabbix Admin password setting! See documentation." + ) return ret else: desired_password = unique_passwords[0] diff --git a/salt/states/zabbix_valuemap.py b/salt/states/zabbix_valuemap.py index 23c14e16869..2475b2b4e53 100644 --- a/salt/states/zabbix_valuemap.py +++ b/salt/states/zabbix_valuemap.py @@ -132,10 +132,10 @@ def present(name, params, **kwargs): else: ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( + name + ) ) else: diff --git a/salt/states/zenoss.py b/salt/states/zenoss.py index 0a05c67af23..a2b11e888c7 100644 --- a/salt/states/zenoss.py +++ b/salt/states/zenoss.py @@ -17,7 +17,6 @@ Allows for setting a state of minions in Zenoss using the Zenoss API. Currently - prod_state: 1000 """ - import logging log = logging.getLogger(__name__) @@ -60,15 +59,15 @@ def monitored(name, device_class=None, collector="localhost", prod_state=None): # if prod_state is set, ensure it matches with the current state if prod_state is not None and device["productionState"] != prod_state: if __opts__["test"]: - ret[ - "comment" - ] = "{} is already monitored but prodState will be updated".format(name) + ret["comment"] = ( + "{} is already monitored but prodState will be updated".format(name) + ) ret["result"] = None else: __salt__["zenoss.set_prod_state"](prod_state, name) - ret[ - "comment" - ] = "{} is already monitored but prodState was updated".format(name) + ret["comment"] = ( + "{} is already monitored but prodState was updated".format(name) + ) ret["changes"] = { "old": "prodState == {}".format(device["productionState"]), diff --git a/salt/states/zk_concurrency.py b/salt/states/zk_concurrency.py index f76ffdd64d4..0bf709911fc 100644 --- a/salt/states/zk_concurrency.py +++ b/salt/states/zk_concurrency.py @@ -45,7 +45,6 @@ This example would allow the file state to change, but would limit the concurrency of the trafficserver service restart to 4. """ - # TODO: use depends decorator to make these per function deps, instead of all or nothing REQUIRED_FUNCS = ( "zk_concurrency.lock", diff --git a/salt/states/zone.py b/salt/states/zone.py index d411ad33a0a..e4a1af32a32 100644 --- a/salt/states/zone.py +++ b/salt/states/zone.py @@ -193,10 +193,10 @@ def property_present(name, property, value): else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -250,10 +250,10 @@ def property_absent(name, property): else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -373,31 +373,31 @@ def resource_present( ) if ret["comment"] == "": if resource_selector_property: - ret[ - "comment" - ] = "The {} resource {} was updated.".format( - resource_type, - resource_selector_value, + ret["comment"] = ( + "The {} resource {} was updated.".format( + resource_type, + resource_selector_value, + ) ) else: - ret[ - "comment" - ] = "The {} resource was updated.".format( - resource_type, + ret["comment"] = ( + "The {} resource was updated.".format( + resource_type, + ) ) elif ret["comment"] == "": if resource_selector_property: - ret[ - "comment" - ] = "The {} resource {} was not updated.".format( - resource_type, - resource_selector_value, + ret["comment"] = ( + "The {} resource {} was not updated.".format( + resource_type, + resource_selector_value, + ) ) else: - ret[ - "comment" - ] = "The {} resource was not updated.".format( - resource_type, + ret["comment"] = ( + "The {} resource was not updated.".format( + resource_type, + ) ) if ret["result"] is None: ## add @@ -418,9 +418,9 @@ def resource_present( ret["changes"][resource_type][resource_selector_value] = {} for key in kwargs if ret["result"] else []: if resource_selector_property: - ret["changes"][resource_type][resource_selector_value][ - key - ] = _parse_value(kwargs[key]) + ret["changes"][resource_type][resource_selector_value][key] = ( + _parse_value(kwargs[key]) + ) else: ret["changes"][resource_type][key] = _parse_value(kwargs[key]) if ret["comment"] == "": @@ -436,10 +436,10 @@ def resource_present( else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -541,10 +541,10 @@ def resource_absent( else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -682,11 +682,11 @@ def export(name, path, replace=False): if __salt__["file.file_exists"](path) and not replace: ret["result"] = False ret["changes"] = {} - ret[ - "comment" - ] = "File {} exists, zone configuration for {} not exported.".format( - path, - name, + ret["comment"] = ( + "File {} exists, zone configuration for {} not exported.".format( + path, + name, + ) ) else: ## export and update file @@ -700,29 +700,29 @@ def export(name, path, replace=False): if __salt__["file.file_exists"](cfg_tmp): __salt__["file.remove"](cfg_tmp) ret["result"] = False - ret[ - "comment" - ] = "Unable to export zone configuration for {} to {}!".format( - name, - path, + ret["comment"] = ( + "Unable to export zone configuration for {} to {}!".format( + name, + path, + ) ) else: ret["result"] = True - ret[ - "comment" - ] = "Zone configuration for {} was exported to {}.".format( - name, - path, + ret["comment"] = ( + "Zone configuration for {} was exported to {}.".format( + name, + path, + ) ) ret["changes"][name] = "exported" else: cfg_diff = __salt__["file.get_diff"](path, cfg_tmp) if not cfg_diff: ret["result"] = True - ret[ - "comment" - ] = "Zone configuration for {} was already exported to {}.".format( - name, path + ret["comment"] = ( + "Zone configuration for {} was already exported to {}.".format( + name, path + ) ) if __salt__["file.file_exists"](cfg_tmp): __salt__["file.remove"](cfg_tmp) @@ -743,11 +743,11 @@ def export(name, path, replace=False): ) else: ret["result"] = True - ret[ - "comment" - ] = "Zone configuration for {} was re-exported to {}.".format( - name, - path, + ret["comment"] = ( + "Zone configuration for {} was re-exported to {}.".format( + name, + path, + ) ) ret["changes"][name] = "exported" else: @@ -820,9 +820,9 @@ def import_(name, path, mode="import", nodataset=False, brand_opts=None): res_import = __salt__["zonecfg.import"](name, path) if not res_import["status"]: ret["result"] = False - ret[ - "comment" - ] = "Unable to import zone configuration for {}!".format(name) + ret["comment"] = ( + "Unable to import zone configuration for {}!".format(name) + ) else: ret["result"] = True ret["changes"][name] = "imported" @@ -874,9 +874,9 @@ def import_(name, path, mode="import", nodataset=False, brand_opts=None): ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = False - ret[ - "comment" - ] = "The file {} does not exists, unable to import!".format(path) + ret["comment"] = ( + "The file {} does not exists, unable to import!".format(path) + ) else: ## zone exist ret["result"] = True @@ -1020,25 +1020,25 @@ def present(name, brand, zonepath, properties=None, resources=None): name, resource_cfg["resource_type"], resource_selector_property=resource_selector_property, - resource_selector_value=resource_cfg[ - resource_selector_property - ] - if resource_selector_property - else None, + resource_selector_value=( + resource_cfg[resource_selector_property] + if resource_selector_property + else None + ), ) else: - resource_cfg[ - "resource_selector_property" - ] = resource_selector_property + resource_cfg["resource_selector_property"] = ( + resource_selector_property + ) if resource_selector_property in resource_cfg: resource_cfg["resource_selector_value"] = resource_cfg[ resource_selector_property ] else: resource_cfg["resource_selector_value"] = None - resource_cfg[ - "name" - ] = name # we do this last because name can also be a attrib value + resource_cfg["name"] = ( + name # we do this last because name can also be a attrib value + ) res = resource_present(**resource_cfg) if res: ret["result"] = ret["result"] if res["result"] else False diff --git a/salt/states/zookeeper.py b/salt/states/zookeeper.py index 5fb20f1d813..2f629afa76b 100644 --- a/salt/states/zookeeper.py +++ b/salt/states/zookeeper.py @@ -27,7 +27,6 @@ The following options can be included in the acl dictionary: :type all: bool """ - __virtualname__ = "zookeeper" @@ -154,10 +153,10 @@ def present( cur_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) if cur_value == value and _check_acls(cur_acls, chk_acls): ret["result"] = True - ret[ - "comment" - ] = "Znode {} is already set to the correct value with the correct acls".format( - name + ret["comment"] = ( + "Znode {} is already set to the correct value with the correct acls".format( + name + ) ) return ret elif __opts__["test"] is True: diff --git a/salt/syspaths.py b/salt/syspaths.py index ce9bbc44ef6..23445622614 100644 --- a/salt/syspaths.py +++ b/salt/syspaths.py @@ -13,7 +13,6 @@ paths that are set in the master/minion config files. """ - import logging import os import os.path diff --git a/salt/template.py b/salt/template.py index 7de759dc4fb..1836259257f 100644 --- a/salt/template.py +++ b/salt/template.py @@ -1,6 +1,7 @@ """ Manage basic template commands """ + import codecs import io import logging diff --git a/salt/thorium/__init__.py b/salt/thorium/__init__.py index 0b2bfb37f0d..97b37d75b95 100644 --- a/salt/thorium/__init__.py +++ b/salt/thorium/__init__.py @@ -1,6 +1,7 @@ """ The thorium system allows for advanced event tracking and reactions """ + # Needed: # Use a top file to load sls files locally # use the existing state system to compile a low state diff --git a/salt/thorium/calc.py b/salt/thorium/calc.py index 9eba4317779..b01b4d37c58 100644 --- a/salt/thorium/calc.py +++ b/salt/thorium/calc.py @@ -7,7 +7,6 @@ values are stored and computed, such as averages etc. :depends: statistics PyPi module """ - try: import statistics diff --git a/salt/thorium/file.py b/salt/thorium/file.py index 1e7dcc8f09e..ad6911e9003 100644 --- a/salt/thorium/file.py +++ b/salt/thorium/file.py @@ -37,7 +37,6 @@ Be warned that if you do this, then the file will be saved, but not in a format that can be re-imported into Python. """ - import os import salt.utils.data diff --git a/salt/thorium/reg.py b/salt/thorium/reg.py index 20cbebb253f..57842202cdf 100644 --- a/salt/thorium/reg.py +++ b/salt/thorium/reg.py @@ -3,7 +3,6 @@ Used to manage the thorium register. The thorium register is where compound values are stored and computed, such as averages etc. """ - import salt.utils.stringutils __func_alias__ = { diff --git a/salt/thorium/timer.py b/salt/thorium/timer.py index a1eefa3aa6f..bc67ec502a0 100644 --- a/salt/thorium/timer.py +++ b/salt/thorium/timer.py @@ -3,7 +3,6 @@ Allow for flow based timers. These timers allow for a sleep to exist across multiple runs of the flow """ - import time diff --git a/salt/tokens/localfs.py b/salt/tokens/localfs.py index 61c2d945ad3..8e739ae11be 100644 --- a/salt/tokens/localfs.py +++ b/salt/tokens/localfs.py @@ -2,7 +2,6 @@ Stores eauth tokens in the filesystem of the master. Location is configured by the master config option 'token_dir' """ - import hashlib import logging import os @@ -93,7 +92,7 @@ def list_tokens(opts): :returns: List of dicts (tokens) """ ret = [] - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk(opts["token_dir"]): + for dirpath, dirnames, filenames in salt.utils.path.os_walk(opts["token_dir"]): for token in filenames: ret.append(token) return ret diff --git a/salt/tops/cobbler.py b/salt/tops/cobbler.py index 7a5d66662ab..5e5aed16a4b 100644 --- a/salt/tops/cobbler.py +++ b/salt/tops/cobbler.py @@ -20,9 +20,8 @@ Module Documentation """ import logging -import xmlrpc.client +import xmlrpc.client # nosec -# Set up logging log = logging.getLogger(__name__) diff --git a/salt/tops/ext_nodes.py b/salt/tops/ext_nodes.py index 4aa7ee1566c..a32c9f8eae8 100644 --- a/salt/tops/ext_nodes.py +++ b/salt/tops/ext_nodes.py @@ -44,6 +44,7 @@ The above essentially is the same as a top.sls containing the following: - basepackages - database """ + import logging import shlex import subprocess diff --git a/salt/tops/saltclass.py b/salt/tops/saltclass.py index 94dbae8b156..f9057842f47 100644 --- a/salt/tops/saltclass.py +++ b/salt/tops/saltclass.py @@ -207,7 +207,6 @@ Not using ``^`` as the first entry will simply merge the lists escaped one will not be correctly rendered - '\${xx}' will stay as is instead of being rendered as '${xx}' """ - import logging import salt.utils.saltclass as sc diff --git a/salt/tops/varstack_top.py b/salt/tops/varstack_top.py index 7f0f833cb65..479701d60ac 100644 --- a/salt/tops/varstack_top.py +++ b/salt/tops/varstack_top.py @@ -42,7 +42,6 @@ managed by salt as if given from a top.sls file. """ - try: import varstack except ImportError: diff --git a/salt/transport/__init__.py b/salt/transport/__init__.py index 3c7e2326efa..0086e5db395 100644 --- a/salt/transport/__init__.py +++ b/salt/transport/__init__.py @@ -2,7 +2,6 @@ Encapsulate the different transports available to Salt. """ - import logging import warnings diff --git a/salt/transport/client.py b/salt/transport/client.py index bd79ac357b4..2de5ddff47a 100644 --- a/salt/transport/client.py +++ b/salt/transport/client.py @@ -7,6 +7,7 @@ This includes client side transport, for the ReqServer and the Publisher NOTE: This module has been deprecated and will be removed in Argon. Please use salt.channel.server instead. """ + import logging from salt.utils.versions import warn_until diff --git a/salt/transport/frame.py b/salt/transport/frame.py index c545a6ee7cf..aa6961f5ad9 100644 --- a/salt/transport/frame.py +++ b/salt/transport/frame.py @@ -2,7 +2,6 @@ Helper functions for transport components to handle message framing """ - import salt.utils.msgpack diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py index 9921fe72e5e..2ee99eb06d0 100644 --- a/salt/transport/ipc.py +++ b/salt/transport/ipc.py @@ -2,7 +2,6 @@ IPC transport classes """ - import errno import logging import socket diff --git a/salt/transport/server.py b/salt/transport/server.py index a289c88be50..67720c08098 100644 --- a/salt/transport/server.py +++ b/salt/transport/server.py @@ -7,6 +7,7 @@ This includes server side transport, for the ReqServer and the Publisher NOTE: This module has been deprecated and will be removed in Argon. Please use salt.channel.server instead. """ + import logging from salt.utils.versions import warn_until diff --git a/salt/transport/tcp.py b/salt/transport/tcp.py index 2c3b5644fe6..e64b013a978 100644 --- a/salt/transport/tcp.py +++ b/salt/transport/tcp.py @@ -6,7 +6,6 @@ Wire protocol: "len(payload) msgpack({'head': SOMEHEADER, 'body': SOMEBODY})" """ - import errno import logging import multiprocessing diff --git a/salt/transport/zeromq.py b/salt/transport/zeromq.py index 96f12a0d6f7..e2278dff055 100644 --- a/salt/transport/zeromq.py +++ b/salt/transport/zeromq.py @@ -1,6 +1,7 @@ """ Zeromq transport classes """ + import errno import hashlib import logging diff --git a/salt/utils/aggregation.py b/salt/utils/aggregation.py index e668f2c3782..eadbd2cfeb5 100644 --- a/salt/utils/aggregation.py +++ b/salt/utils/aggregation.py @@ -102,7 +102,6 @@ """ - import copy import logging @@ -132,7 +131,6 @@ class Sequence(list, Aggregate): def Scalar(obj): - """ Shortcut for Sequence creation diff --git a/salt/utils/asynchronous.py b/salt/utils/asynchronous.py index 0c645bbc3bb..b156c020ab3 100644 --- a/salt/utils/asynchronous.py +++ b/salt/utils/asynchronous.py @@ -2,7 +2,6 @@ Helpers/utils for working with tornado asynchronous stuff """ - import contextlib import logging import sys diff --git a/salt/utils/atomicfile.py b/salt/utils/atomicfile.py index 59f7e273715..8ef7ca58592 100644 --- a/salt/utils/atomicfile.py +++ b/salt/utils/atomicfile.py @@ -2,6 +2,7 @@ A module written originally by Armin Ronacher to manage file transfers in an atomic way """ + import errno import os import random diff --git a/salt/utils/aws.py b/salt/utils/aws.py index 1231661d970..7cf604fa1be 100644 --- a/salt/utils/aws.py +++ b/salt/utils/aws.py @@ -7,6 +7,7 @@ This is a base library used by a number of AWS services. :depends: requests """ + import binascii import copy import hashlib diff --git a/salt/utils/boto3mod.py b/salt/utils/boto3mod.py index 3692ae5549e..cc6d1117a1b 100644 --- a/salt/utils/boto3mod.py +++ b/salt/utils/boto3mod.py @@ -24,7 +24,6 @@ Example Usage: .. versionadded:: 2015.8.0 """ - import hashlib import logging import sys diff --git a/salt/utils/botomod.py b/salt/utils/botomod.py index 8d9d5cad535..cdadb4f0bcc 100644 --- a/salt/utils/botomod.py +++ b/salt/utils/botomod.py @@ -24,7 +24,6 @@ Example Usage: .. versionadded:: 2015.8.0 """ - import hashlib import logging import sys diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py index 5a1660cfd6a..ab389610938 100644 --- a/salt/utils/cloud.py +++ b/salt/utils/cloud.py @@ -2,7 +2,6 @@ Utility functions for salt.cloud """ - import codecs import copy import errno @@ -565,9 +564,9 @@ def bootstrap(vm_, opts=None): ) if saltify_driver: - deploy_kwargs[ - "wait_for_passwd_maxtries" - ] = 0 # No need to wait/retry with Saltify + deploy_kwargs["wait_for_passwd_maxtries"] = ( + 0 # No need to wait/retry with Saltify + ) win_installer = salt.config.get_cloud_config_value("win_installer", vm_, opts) if win_installer: diff --git a/salt/utils/color.py b/salt/utils/color.py index d765288f496..37da77472a6 100644 --- a/salt/utils/color.py +++ b/salt/utils/color.py @@ -2,7 +2,6 @@ Functions used for CLI color themes. """ - import logging import os diff --git a/salt/utils/configparser.py b/salt/utils/configparser.py index 10e3c889ef0..b636d5e320e 100644 --- a/salt/utils/configparser.py +++ b/salt/utils/configparser.py @@ -261,12 +261,12 @@ class GitConfigParser(RawConfigParser): ) if self._defaults: fp_.write(convert("[%s]\n" % self.DEFAULTSECT)) - for (key, value) in self._defaults.items(): + for key, value in self._defaults.items(): value = salt.utils.stringutils.to_unicode(value).replace("\n", "\n\t") fp_.write(convert(f"{key} = {value}\n")) for section in self._sections: fp_.write(convert("[%s]\n" % section)) - for (key, value) in self._sections[section].items(): + for key, value in self._sections[section].items(): if (value is not None) or (self._optcre == self.OPTCRE): if not isinstance(value, list): value = [value] diff --git a/salt/utils/crypt.py b/salt/utils/crypt.py index 3f9c5955915..de892d55597 100644 --- a/salt/utils/crypt.py +++ b/salt/utils/crypt.py @@ -1,6 +1,7 @@ """ Functions dealing with encryption """ + import hashlib import logging import os diff --git a/salt/utils/data.py b/salt/utils/data.py index 40c79e3418a..e525f47c47d 100644 --- a/salt/utils/data.py +++ b/salt/utils/data.py @@ -3,7 +3,6 @@ Functions for manipulating, inspecting, or otherwise working with data types and data structures. """ - import copy import datetime import fnmatch @@ -1385,7 +1384,7 @@ def recursive_diff( append_old = list(old.keys())[min_length:] append_new = list(new.keys())[min_length:] # Compare ordered - for (key_old, key_new) in zip(old, new): + for key_old, key_new in zip(old, new): if key_old == key_new: if key_old in ignore_keys: del ret_old[key_old] diff --git a/salt/utils/dateutils.py b/salt/utils/dateutils.py index b55d9a40027..e219753da6a 100644 --- a/salt/utils/dateutils.py +++ b/salt/utils/dateutils.py @@ -2,7 +2,6 @@ Convenience functions for dealing with datetime classes """ - import datetime import salt.utils.stringutils diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py index 1f62d5f3d65..b849ca31145 100644 --- a/salt/utils/decorators/__init__.py +++ b/salt/utils/decorators/__init__.py @@ -2,7 +2,6 @@ Helpful decorators for module writing """ - import errno import inspect import logging @@ -217,9 +216,11 @@ class Depends: mod_name, func_name, dependency, - " version {}".format(params["version"]) - if "version" in params - else "", + ( + " version {}".format(params["version"]) + if "version" in params + else "" + ), ) # if not, unload the function if frame: diff --git a/salt/utils/decorators/state.py b/salt/utils/decorators/state.py index bcca040b996..569df725f85 100644 --- a/salt/utils/decorators/state.py +++ b/salt/utils/decorators/state.py @@ -4,7 +4,6 @@ Decorators for salt.state :codeauthor: :email:`Bo Maryniuk (bo@suse.de)` """ - import logging import salt.utils.stringutils diff --git a/salt/utils/doc.py b/salt/utils/doc.py index 9f80bc3337b..4fcbe1549d6 100644 --- a/salt/utils/doc.py +++ b/salt/utils/doc.py @@ -1,6 +1,7 @@ """ Functions for analyzing/parsing docstrings """ + import logging import re diff --git a/salt/utils/dockermod/__init__.py b/salt/utils/dockermod/__init__.py index 00b012b8992..d0f504e60dc 100644 --- a/salt/utils/dockermod/__init__.py +++ b/salt/utils/dockermod/__init__.py @@ -5,7 +5,6 @@ This module contains logic to accommodate docker/salt CLI usage, as well as input as formatted by states. """ - import copy import logging diff --git a/salt/utils/dockermod/translate/container.py b/salt/utils/dockermod/translate/container.py index 3bc37101f76..8dd21b7dc9f 100644 --- a/salt/utils/dockermod/translate/container.py +++ b/salt/utils/dockermod/translate/container.py @@ -445,9 +445,11 @@ def port_bindings(val, **kwargs): bind_vals = [ ( _format_port(val, proto), - (host_ip,) - if hport_list[idx] is None - else (host_ip, hport_list[idx]), + ( + (host_ip,) + if hport_list[idx] is None + else (host_ip, hport_list[idx]) + ), ) for idx, val in enumerate(cport_list) ] diff --git a/salt/utils/dockermod/translate/helpers.py b/salt/utils/dockermod/translate/helpers.py index 5d81f89c99e..2b090de0d78 100644 --- a/salt/utils/dockermod/translate/helpers.py +++ b/salt/utils/dockermod/translate/helpers.py @@ -110,9 +110,11 @@ def map_vals(val, *names, **extra_opts): "'{}' contains {} value(s) (expected {})".format( item, num_elements, - expected_num_elements - if fill is NOTSET - else "up to {}".format(expected_num_elements), + ( + expected_num_elements + if fill is NOTSET + else "up to {}".format(expected_num_elements) + ), ) ) val[idx] = dict(zip(names, elements)) diff --git a/salt/utils/extend.py b/salt/utils/extend.py index 72903af23fc..5fbef75fbed 100644 --- a/salt/utils/extend.py +++ b/salt/utils/extend.py @@ -12,7 +12,6 @@ This tool is accessed using `salt-extend` :codeauthor: Anthony Shaw """ - import logging import os import shutil diff --git a/salt/utils/files.py b/salt/utils/files.py index 8071a55d3a4..6a70ca6f304 100644 --- a/salt/utils/files.py +++ b/salt/utils/files.py @@ -2,7 +2,6 @@ Functions for working with files """ - import codecs import contextlib import errno @@ -490,7 +489,7 @@ def safe_walk(top, topdown=True, onerror=None, followlinks=True, _seen=None): # Note that listdir and error are globals in this module due # to earlier import-*. names = os.listdir(top) - except os.error as err: + except OSError as err: if onerror is not None: onerror(err) return @@ -699,7 +698,7 @@ def is_binary(path): return salt.utils.stringutils.is_binary(data) except UnicodeDecodeError: return True - except os.error: + except OSError: return False @@ -888,7 +887,7 @@ def get_encoding(path): try: with fopen(path, "rb") as fp_: data = fp_.read(2048) - except os.error: + except OSError: raise CommandExecutionError("Failed to open file") # Check for Unicode BOM diff --git a/salt/utils/find.py b/salt/utils/find.py index c82b27965f1..f6fc3bf9250 100644 --- a/salt/utils/find.py +++ b/salt/utils/find.py @@ -82,7 +82,6 @@ the following: user: user name """ - import logging import os import re diff --git a/salt/utils/fsutils.py b/salt/utils/fsutils.py index 96d0cd16bb8..7dda4454e9d 100644 --- a/salt/utils/fsutils.py +++ b/salt/utils/fsutils.py @@ -1,6 +1,7 @@ """ Run-time utilities """ + # # Copyright (C) 2014 SUSE LLC diff --git a/salt/utils/functools.py b/salt/utils/functools.py index f4d4cbdb3de..e164811393e 100644 --- a/salt/utils/functools.py +++ b/salt/utils/functools.py @@ -1,6 +1,7 @@ """ Utility functions to modify other functions """ + import logging import types diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index 934794bfab7..730e6b01993 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -3054,9 +3054,9 @@ class GitFS(GitBase): remotes if remotes is not None else [], per_remote_overrides=per_remote_overrides, per_remote_only=per_remote_only, - git_providers=git_providers - if git_providers is not None - else GIT_PROVIDERS, + git_providers=( + git_providers if git_providers is not None else GIT_PROVIDERS + ), cache_root=cache_root, init_remotes=init_remotes, ) @@ -3291,7 +3291,7 @@ class GitFS(GitBase): if not os.path.isdir(self.file_list_cachedir): try: os.makedirs(self.file_list_cachedir) - except os.error: + except OSError: log.error("Unable to make cachedir %s", self.file_list_cachedir) return [] list_cache = salt.utils.path.join( diff --git a/salt/utils/github.py b/salt/utils/github.py index 1d6824f2ae9..d24244e5a0e 100644 --- a/salt/utils/github.py +++ b/salt/utils/github.py @@ -2,7 +2,6 @@ Connection library for GitHub """ - import logging import salt.utils.http diff --git a/salt/utils/gzip_util.py b/salt/utils/gzip_util.py index 5946d2269ab..49592e7280e 100644 --- a/salt/utils/gzip_util.py +++ b/salt/utils/gzip_util.py @@ -4,7 +4,6 @@ Helper module for handling gzip consistently between 2.7+ and 2.6- """ - import gzip import io diff --git a/salt/utils/http.py b/salt/utils/http.py index 30c7fbdc8de..991b4735f5b 100644 --- a/salt/utils/http.py +++ b/salt/utils/http.py @@ -485,10 +485,10 @@ def query( try: match_hostname(sockwrap.getpeercert(), hostname) except CertificateError as exc: - ret[ - "error" - ] = "The certificate was invalid. Error returned was: {}".format( - pprint.pformat(exc) + ret["error"] = ( + "The certificate was invalid. Error returned was: {}".format( + pprint.pformat(exc) + ) ) return ret @@ -725,10 +725,10 @@ def query( valid_decodes = ("json", "xml", "yaml", "plain") if decode_type not in valid_decodes: - ret[ - "error" - ] = "Invalid decode_type specified. Valid decode types are: {}".format( - pprint.pformat(valid_decodes) + ret["error"] = ( + "Invalid decode_type specified. Valid decode types are: {}".format( + pprint.pformat(valid_decodes) + ) ) log.error(ret["error"]) return ret diff --git a/salt/utils/idem.py b/salt/utils/idem.py index ab7641a8e91..c05f9c26f00 100644 --- a/salt/utils/idem.py +++ b/salt/utils/idem.py @@ -6,6 +6,7 @@ This util provides access to an idem-ready hub .. versionadded:: 3002 """ + import logging import sys diff --git a/salt/utils/itertools.py b/salt/utils/itertools.py index a1f55cb026a..3e0635e15c7 100644 --- a/salt/utils/itertools.py +++ b/salt/utils/itertools.py @@ -2,7 +2,6 @@ Helpful generators and other tools """ - import fnmatch import re diff --git a/salt/utils/job.py b/salt/utils/job.py index 140f315f6c9..3d4653d412d 100644 --- a/salt/utils/job.py +++ b/salt/utils/job.py @@ -2,7 +2,6 @@ Functions for interacting with the job cache """ - import logging import salt.minion diff --git a/salt/utils/json.py b/salt/utils/json.py index 33cdbf401df..5e14872309f 100644 --- a/salt/utils/json.py +++ b/salt/utils/json.py @@ -2,7 +2,6 @@ Functions to work with JSON """ - import json import logging diff --git a/salt/utils/lazy.py b/salt/utils/lazy.py index cdc963aa801..832be90fc0d 100644 --- a/salt/utils/lazy.py +++ b/salt/utils/lazy.py @@ -2,7 +2,6 @@ Lazily-evaluated data structures, primarily used by Salt's loader """ - import logging from collections.abc import MutableMapping diff --git a/salt/utils/locales.py b/salt/utils/locales.py index 8017958d5de..cd42a8c9e8a 100644 --- a/salt/utils/locales.py +++ b/salt/utils/locales.py @@ -2,7 +2,6 @@ the locale utils used by salt """ - import sys from salt.utils.decorators import memoize as real_memoize diff --git a/salt/utils/master.py b/salt/utils/master.py index 031b151caef..ce2dfe46bf0 100644 --- a/salt/utils/master.py +++ b/salt/utils/master.py @@ -5,6 +5,7 @@ Utilities that can only be used on a salt master. """ + import logging import os import signal diff --git a/salt/utils/memcached.py b/salt/utils/memcached.py index 3bb1fa94000..11248abadd6 100644 --- a/salt/utils/memcached.py +++ b/salt/utils/memcached.py @@ -34,7 +34,6 @@ specified, rather than top-level configurations. This being the case, it is better to always use a named configuration profile, as shown above. """ - import logging from salt.exceptions import CommandExecutionError, SaltInvocationError diff --git a/salt/utils/mine.py b/salt/utils/mine.py index 4f6416e554f..04795b0f8a3 100644 --- a/salt/utils/mine.py +++ b/salt/utils/mine.py @@ -2,7 +2,6 @@ This module contains routines used for the salt mine """ - import logging import salt.utils.data diff --git a/salt/utils/minion.py b/salt/utils/minion.py index 28e63af1df3..9c53428c89b 100644 --- a/salt/utils/minion.py +++ b/salt/utils/minion.py @@ -2,7 +2,6 @@ Utility functions for minions """ - import logging import os import threading diff --git a/salt/utils/minions.py b/salt/utils/minions.py index 082b6985225..3006118c239 100644 --- a/salt/utils/minions.py +++ b/salt/utils/minions.py @@ -3,7 +3,6 @@ This module contains routines used to verify the matcher against the minions expected to return """ - import fnmatch import logging import os diff --git a/salt/utils/mount.py b/salt/utils/mount.py index 019cac5562b..c09791e668e 100644 --- a/salt/utils/mount.py +++ b/salt/utils/mount.py @@ -2,7 +2,6 @@ Common functions for managing mounts """ - import logging import os diff --git a/salt/utils/msazure.py b/salt/utils/msazure.py index de4419caacd..7b76f2f6b32 100644 --- a/salt/utils/msazure.py +++ b/salt/utils/msazure.py @@ -4,7 +4,6 @@ Utilities for accessing storage container blobs on Azure """ - import logging from salt.exceptions import SaltSystemExit diff --git a/salt/utils/msgpack.py b/salt/utils/msgpack.py index fcd9f93a04f..6dde58938ff 100644 --- a/salt/utils/msgpack.py +++ b/salt/utils/msgpack.py @@ -1,6 +1,7 @@ """ Functions to work with MessagePack """ + import logging log = logging.getLogger(__name__) diff --git a/salt/utils/namecheap.py b/salt/utils/namecheap.py index 343ecfb62b6..c09a04b6ac6 100644 --- a/salt/utils/namecheap.py +++ b/salt/utils/namecheap.py @@ -15,7 +15,6 @@ """ - import logging import xml.dom.minidom diff --git a/salt/utils/napalm.py b/salt/utils/napalm.py index d78422a7111..9fc15e45fdb 100644 --- a/salt/utils/napalm.py +++ b/salt/utils/napalm.py @@ -14,7 +14,6 @@ Utils for the NAPALM modules and proxy. .. versionadded:: 2017.7.0 """ - import copy import importlib import logging diff --git a/salt/utils/network.py b/salt/utils/network.py index 13eaa4835ca..29c6c2f1049 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -2174,9 +2174,7 @@ def dns_check(addr, port, safe=False, ipv6=None): family = ( socket.AF_INET6 if ipv6 - else socket.AF_INET - if ipv6 is False - else socket.AF_UNSPEC + else socket.AF_INET if ipv6 is False else socket.AF_UNSPEC ) socket_error = False try: diff --git a/salt/utils/odict.py b/salt/utils/odict.py index bf9dd06e448..2834f1d9246 100644 --- a/salt/utils/odict.py +++ b/salt/utils/odict.py @@ -11,6 +11,7 @@ http://stackoverflow.com/questions/6190331/ """ + import copy from collections import OrderedDict from collections.abc import Callable diff --git a/salt/utils/openstack/neutron.py b/salt/utils/openstack/neutron.py index b7934b5f651..cace3e3b77a 100644 --- a/salt/utils/openstack/neutron.py +++ b/salt/utils/openstack/neutron.py @@ -2,7 +2,6 @@ Neutron class """ - import logging import salt.utils.versions @@ -89,7 +88,6 @@ class SaltNeutron(NeutronShell): use_keystoneauth=False, **kwargs ): - """ Set up neutron credentials """ diff --git a/salt/utils/openstack/nova.py b/salt/utils/openstack/nova.py index 386b585c861..90b0b1f8269 100644 --- a/salt/utils/openstack/nova.py +++ b/salt/utils/openstack/nova.py @@ -2,7 +2,6 @@ Nova class """ - import inspect import logging import time @@ -1033,9 +1032,9 @@ class SaltNova: "OS-EXT-SRV-ATTR:host" ] if hasattr(item.__dict__, "OS-EXT-SRV-ATTR:hypervisor_hostname"): - ret[item.name]["OS-EXT-SRV-ATTR"][ - "hypervisor_hostname" - ] = item.__dict__["OS-EXT-SRV-ATTR:hypervisor_hostname"] + ret[item.name]["OS-EXT-SRV-ATTR"]["hypervisor_hostname"] = ( + item.__dict__["OS-EXT-SRV-ATTR:hypervisor_hostname"] + ) if hasattr(item.__dict__, "OS-EXT-SRV-ATTR:instance_name"): ret[item.name]["OS-EXT-SRV-ATTR"]["instance_name"] = item.__dict__[ "OS-EXT-SRV-ATTR:instance_name" diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py index 385e69f6a15..c915d5621f6 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py @@ -7,6 +7,7 @@ This is where all the black magic happens on all of salt's CLI tools. """ + # pylint: disable=missing-docstring,protected-access,too-many-ancestors,too-few-public-methods # pylint: disable=attribute-defined-outside-init,no-self-use diff --git a/salt/utils/path.py b/salt/utils/path.py index f6aa7d5dad7..80b4dcb405f 100644 --- a/salt/utils/path.py +++ b/salt/utils/path.py @@ -3,7 +3,6 @@ Platform independent versions of some os/os.path functions. Gets around PY2's lack of support for reading NTFS links. """ - import logging import os import posixpath diff --git a/salt/utils/pbm.py b/salt/utils/pbm.py index c8eceaeedb3..6e3e32ddbcb 100644 --- a/salt/utils/pbm.py +++ b/salt/utils/pbm.py @@ -37,7 +37,6 @@ version currently listed in PyPi, run the following: pip install pyVmomi==5.5.0.2014.1.1 """ - import logging import salt.utils.vmware diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py index f9975f8dff1..4f91278fc7d 100644 --- a/salt/utils/pkg/rpm.py +++ b/salt/utils/pkg/rpm.py @@ -1,6 +1,7 @@ """ Common functions for working with RPM packages """ + import collections import datetime import logging diff --git a/salt/utils/pkg/win.py b/salt/utils/pkg/win.py index f988f7a99af..91e93d9aac0 100644 --- a/salt/utils/pkg/win.py +++ b/salt/utils/pkg/win.py @@ -10,6 +10,7 @@ Collect information about software installed on Windows OS Known Issue: install_date may not match Control Panel\Programs\Programs and Features """ + import collections import datetime import locale diff --git a/salt/utils/platform.py b/salt/utils/platform.py index 35bb7ff3f81..c6ca7fe8cae 100644 --- a/salt/utils/platform.py +++ b/salt/utils/platform.py @@ -1,6 +1,7 @@ """ Functions for identifying which platform a machine is """ + import contextlib import multiprocessing import os diff --git a/salt/utils/process.py b/salt/utils/process.py index 765a2fac8d9..fc63cd0778f 100644 --- a/salt/utils/process.py +++ b/salt/utils/process.py @@ -1,6 +1,7 @@ """ Functions for daemonizing and otherwise modifying running processes """ + import contextlib import copy import errno @@ -920,9 +921,9 @@ class Process(multiprocessing.Process): self.__init__(*args, **kwargs) # Override self.__logging_config__ with what's in state self.__logging_config__ = logging_config - for (function, args, kwargs) in state["after_fork_methods"]: + for function, args, kwargs in state["after_fork_methods"]: self.register_after_fork_method(function, *args, **kwargs) - for (function, args, kwargs) in state["finalize_methods"]: + for function, args, kwargs in state["finalize_methods"]: self.register_finalize_method(function, *args, **kwargs) def __getstate__(self): diff --git a/salt/utils/profile.py b/salt/utils/profile.py index 30f4276ef0c..a9fa13b9b48 100644 --- a/salt/utils/profile.py +++ b/salt/utils/profile.py @@ -2,7 +2,6 @@ Decorator and functions to profile Salt using cProfile """ - import datetime import logging import os diff --git a/salt/utils/proxy.py b/salt/utils/proxy.py index 6677134f478..b9db9251582 100644 --- a/salt/utils/proxy.py +++ b/salt/utils/proxy.py @@ -2,7 +2,6 @@ Utils for proxy. """ - import logging import salt.utils.platform diff --git a/salt/utils/pycrypto.py b/salt/utils/pycrypto.py index a0f3874035e..d42ee6db9b9 100644 --- a/salt/utils/pycrypto.py +++ b/salt/utils/pycrypto.py @@ -1,6 +1,7 @@ """ Use pycrypto to generate random passwords on the fly. """ + import logging import random import re diff --git a/salt/utils/reactor.py b/salt/utils/reactor.py index 3ddb363117c..0229738ec3c 100644 --- a/salt/utils/reactor.py +++ b/salt/utils/reactor.py @@ -1,6 +1,7 @@ """ Functions which implement running reactor jobs """ + import fnmatch import glob import logging diff --git a/salt/utils/saltclass.py b/salt/utils/saltclass.py index bbd33068b06..6667226bd74 100644 --- a/salt/utils/saltclass.py +++ b/salt/utils/saltclass.py @@ -138,7 +138,7 @@ def dict_merge(a, b, path=None): # Recursive search and replace in a dict def dict_search_and_replace(d, old, new, expanded): - for (k, v) in d.items(): + for k, v in d.items(): if isinstance(v, dict): dict_search_and_replace(d[k], old, new, expanded) @@ -206,7 +206,7 @@ def expand_variables(a, b, expanded, path=None): b = a.copy() path = [] - for (k, v) in a.items(): + for k, v in a.items(): if isinstance(v, dict): expand_variables(v, b, expanded, path + [str(k)]) else: diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 6565dda59e6..34b29d36738 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -1108,10 +1108,10 @@ class Schedule: and i in self.opts["grains"]["whens"] ): if not isinstance(self.opts["grains"]["whens"], dict): - data[ - "_error" - ] = 'Grain "whens" must be a dict. Ignoring job {}.'.format( - data["name"] + data["_error"] = ( + 'Grain "whens" must be a dict. Ignoring job {}.'.format( + data["name"] + ) ) log.error(data["_error"]) return @@ -1123,10 +1123,10 @@ class Schedule: try: when_ = dateutil_parser.parse(when_) except ValueError: - data[ - "_error" - ] = "Invalid date string {}. Ignoring job {}.".format( - i, data["name"] + data["_error"] = ( + "Invalid date string {}. Ignoring job {}.".format( + i, data["name"] + ) ) log.error(data["_error"]) return @@ -1382,10 +1382,10 @@ class Schedule: try: start = dateutil_parser.parse(start) except ValueError: - data[ - "_error" - ] = "Invalid date string for start. Ignoring job {}.".format( - data["name"] + data["_error"] = ( + "Invalid date string for start. Ignoring job {}.".format( + data["name"] + ) ) log.error(data["_error"]) return @@ -1394,10 +1394,10 @@ class Schedule: try: end = dateutil_parser.parse(end) except ValueError: - data[ - "_error" - ] = "Invalid date string for end. Ignoring job {}.".format( - data["name"] + data["_error"] = ( + "Invalid date string for end. Ignoring job {}.".format( + data["name"] + ) ) log.error(data["_error"]) return @@ -1883,7 +1883,6 @@ class Schedule: def clean_proc_dir(opts): - """ Loop through jid files in the minion proc directory (default /var/cache/salt/minion/proc) and remove any that refer to processes that no longer exist diff --git a/salt/utils/smb.py b/salt/utils/smb.py index d3468078a48..a31c8e175fc 100644 --- a/salt/utils/smb.py +++ b/salt/utils/smb.py @@ -4,7 +4,6 @@ Utility functions for SMB connections :depends: impacket """ - import logging import socket import uuid @@ -87,9 +86,9 @@ class SMBProto: file = cls.normalize_filename(file) # ensure file is created, get maximal access, and set everybody read access max_req = SMB2CreateContextRequest() - max_req[ - "buffer_name" - ] = CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST + max_req["buffer_name"] = ( + CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST + ) max_req["buffer_data"] = SMB2CreateQueryMaximalAccessRequest() # create security buffer that sets the ACL for everyone to have read access diff --git a/salt/utils/smtp.py b/salt/utils/smtp.py index bab7a3aa4eb..a138a03110b 100644 --- a/salt/utils/smtp.py +++ b/salt/utils/smtp.py @@ -83,10 +83,10 @@ def send(kwargs, opts): config["smtp.content"] = str(encrypted_data) else: log.error("SMTP: Encryption failed, only an error message will be sent") - config[ - "smtp.content" - ] = "Encryption failed, the return data was not sent.\r\n\r\n{}\r\n{}".format( - encrypted_data.status, encrypted_data.stderr + config["smtp.content"] = ( + "Encryption failed, the return data was not sent.\r\n\r\n{}\r\n{}".format( + encrypted_data.status, encrypted_data.stderr + ) ) message = "From: {}\r\nTo: {}\r\nDate: {}\r\nSubject: {}\r\n\r\n{}".format( diff --git a/salt/utils/ssdp.py b/salt/utils/ssdp.py index 4c7e588284d..bbc0c07eb23 100644 --- a/salt/utils/ssdp.py +++ b/salt/utils/ssdp.py @@ -306,7 +306,7 @@ class SSDPDiscoveryServer(SSDPBase): if not addr_pairs_info: raise ValueError("can not get address information") exceptions = [] - for ((family, proto), (local_address, remote_address)) in addr_pairs_info: + for (family, proto), (local_address, remote_address) in addr_pairs_info: sock = r_addr = None try: sock = socket.socket(family=family, type=socket.SOCK_DGRAM, proto=proto) diff --git a/salt/utils/state.py b/salt/utils/state.py index de3913e0286..41c2e191cc9 100644 --- a/salt/utils/state.py +++ b/salt/utils/state.py @@ -4,7 +4,6 @@ Utility functions for state functions .. versionadded:: 2018.3.0 """ - import copy import salt.state diff --git a/salt/utils/stringio.py b/salt/utils/stringio.py index 1dae9346484..0d3cadf2936 100644 --- a/salt/utils/stringio.py +++ b/salt/utils/stringio.py @@ -2,7 +2,6 @@ Functions for StringIO objects """ - import io readable_types = (io.StringIO,) diff --git a/salt/utils/stringutils.py b/salt/utils/stringutils.py index 30ca46fee5c..6f7af315eda 100644 --- a/salt/utils/stringutils.py +++ b/salt/utils/stringutils.py @@ -2,7 +2,6 @@ Functions for manipulating or otherwise processing strings """ - import base64 import difflib import errno diff --git a/salt/utils/templates.py b/salt/utils/templates.py index 872d92686af..23990534546 100644 --- a/salt/utils/templates.py +++ b/salt/utils/templates.py @@ -1,6 +1,7 @@ """ Template render systems """ + import codecs import importlib.machinery import importlib.util diff --git a/salt/utils/textformat.py b/salt/utils/textformat.py index 304456a0e50..c3298d17d68 100644 --- a/salt/utils/textformat.py +++ b/salt/utils/textformat.py @@ -3,7 +3,6 @@ ANSI escape code utilities, see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf """ - graph_prefix = "\x1b[" graph_suffix = "m" codes = { diff --git a/salt/utils/thin.py b/salt/utils/thin.py index 80766a286a9..3c77898fc69 100644 --- a/salt/utils/thin.py +++ b/salt/utils/thin.py @@ -701,7 +701,7 @@ def gen_thin( # This is likely a compressed python .egg tempdir = tempfile.mkdtemp() egg = zipfile.ZipFile(top_dirname) - egg.extractall(tempdir) + egg.extractall(tempdir) # nosec top = os.path.join(tempdir, base) os.chdir(tempdir) @@ -973,7 +973,7 @@ def gen_min( # This is likely a compressed python .egg tempdir = tempfile.mkdtemp() egg = zipfile.ZipFile(top_dirname) - egg.extractall(tempdir) + egg.extractall(tempdir) # nosec top = os.path.join(tempdir, base) os.chdir(tempdir) if not os.path.isdir(top): diff --git a/salt/utils/url.py b/salt/utils/url.py index a30610394c1..a5d2e566670 100644 --- a/salt/utils/url.py +++ b/salt/utils/url.py @@ -2,7 +2,6 @@ URL utils """ - import re import sys from urllib.parse import urlparse, urlunparse diff --git a/salt/utils/user.py b/salt/utils/user.py index c9c12f5ca64..1ce7aa2c78e 100644 --- a/salt/utils/user.py +++ b/salt/utils/user.py @@ -3,7 +3,6 @@ Functions for querying and modifying a user account and the groups to which it belongs. """ - import ctypes import getpass import logging diff --git a/salt/utils/vault.py b/salt/utils/vault.py index 9e31adf5066..c8b54ef2e49 100644 --- a/salt/utils/vault.py +++ b/salt/utils/vault.py @@ -609,7 +609,7 @@ def expand_pattern_lists(pattern, **mappings): # very expensive, since patterns will typically involve a handful of lists at # most. - for (_, field_name, _, _) in f.parse(pattern): + for _, field_name, _, _ in f.parse(pattern): if field_name is None: continue (value, _) = f.get_field(field_name, None, mappings) diff --git a/salt/utils/versions.py b/salt/utils/versions.py index 5c03a15b090..7a5ca51a4ce 100644 --- a/salt/utils/versions.py +++ b/salt/utils/versions.py @@ -6,6 +6,7 @@ which works under python 3 because on python 3 you can no longer compare strings against integers. """ + import datetime import inspect import logging diff --git a/salt/utils/vsan.py b/salt/utils/vsan.py index 7f893150fa6..c44cb50a2f0 100644 --- a/salt/utils/vsan.py +++ b/salt/utils/vsan.py @@ -41,7 +41,6 @@ The 5.5.0.2014.1.1 is a known stable version that this original VMware utils fil was developed against. """ - import logging import ssl import sys diff --git a/salt/utils/win_lgpo_reg.py b/salt/utils/win_lgpo_reg.py index 8144d87f5de..c6f7e17f323 100644 --- a/salt/utils/win_lgpo_reg.py +++ b/salt/utils/win_lgpo_reg.py @@ -2,6 +2,7 @@ A Salt Util for working with the Registry.pol file. The Registry.pol file is the source of truth for registry settings that are configured via LGPO. """ + import logging import os import re diff --git a/salt/utils/win_network.py b/salt/utils/win_network.py index 1e8ac4db3b8..8d168595967 100644 --- a/salt/utils/win_network.py +++ b/salt/utils/win_network.py @@ -18,6 +18,7 @@ depending on the version of Windows this is run on. Once support for Windows :depends: - pythonnet - wmi """ + # https://docs.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface.getallnetworkinterfaces?view=netframework-4.7.2 import logging diff --git a/salt/utils/win_osinfo.py b/salt/utils/win_osinfo.py index 56f1e12d50f..99a3b0ad9fd 100644 --- a/salt/utils/win_osinfo.py +++ b/salt/utils/win_osinfo.py @@ -1,6 +1,7 @@ """ Get Version information from Windows """ + # http://stackoverflow.com/questions/32300004/python-ctypes-getting-0-with-getversionex-function import ctypes diff --git a/salt/utils/win_system.py b/salt/utils/win_system.py index e9f38c9171e..125024674ce 100644 --- a/salt/utils/win_system.py +++ b/salt/utils/win_system.py @@ -5,6 +5,7 @@ Functions shared with salt.modules.win_system and salt.grains.pending_reboot .. versionadded:: 3001 """ + # NOTE: DO NOT USE RAW STRINGS IN THIS MODULE! UNICODE_LITERALS DOES NOT PLAY # NICELY WITH RAW STRINGS CONTAINING \u or \U. diff --git a/salt/utils/win_update.py b/salt/utils/win_update.py index 778acd141fa..edbc60881db 100644 --- a/salt/utils/win_update.py +++ b/salt/utils/win_update.py @@ -1,6 +1,7 @@ """ Classes for working with Windows Update Agent """ + import logging import subprocess diff --git a/salt/utils/x509.py b/salt/utils/x509.py index 37ee5155f73..e9575875c10 100644 --- a/salt/utils/x509.py +++ b/salt/utils/x509.py @@ -1190,21 +1190,21 @@ def _create_authority_key_identifier(val, ca_crt, ca_pub, **kwargs): cx509.SubjectKeyIdentifier ).value.digest except cx509.ExtensionNotFound: - args[ - "key_identifier" - ] = cx509.AuthorityKeyIdentifier.from_issuer_public_key( - ca_crt.public_key() - ).key_identifier + args["key_identifier"] = ( + cx509.AuthorityKeyIdentifier.from_issuer_public_key( + ca_crt.public_key() + ).key_identifier + ) except Exception: # pylint: disable=broad-except pass if not args["key_identifier"] and ca_pub: # this should happen for self-signed certificates try: - args[ - "key_identifier" - ] = cx509.AuthorityKeyIdentifier.from_issuer_public_key( - ca_pub - ).key_identifier + args["key_identifier"] = ( + cx509.AuthorityKeyIdentifier.from_issuer_public_key( + ca_pub + ).key_identifier + ) except Exception: # pylint: disable=broad-except pass @@ -1484,12 +1484,14 @@ def _create_policy_constraints(val, **kwargs): if isinstance(val, str): val, critical = _deserialize_openssl_confstring(val) args = { - "require_explicit_policy": int(val["requireExplicitPolicy"]) - if "requireExplicitPolicy" in val - else None, - "inhibit_policy_mapping": int(val["inhibitPolicyMapping"]) - if "inhibitPolicyMapping" in val - else None, + "require_explicit_policy": ( + int(val["requireExplicitPolicy"]) + if "requireExplicitPolicy" in val + else None + ), + "inhibit_policy_mapping": ( + int(val["inhibitPolicyMapping"]) if "inhibitPolicyMapping" in val else None + ), } try: # not sure why pylint complains about this line having kwargs from keyUsage @@ -1544,12 +1546,12 @@ def _create_name_constraints(val, **kwargs): ], } args = { - "permitted_subtrees": _parse_general_names(val["permitted"]) - if "permitted" in val - else None, - "excluded_subtrees": _parse_general_names(val["excluded"]) - if "excluded" in val - else None, + "permitted_subtrees": ( + _parse_general_names(val["permitted"]) if "permitted" in val else None + ), + "excluded_subtrees": ( + _parse_general_names(val["excluded"]) if "excluded" in val else None + ), } if not any(args.values()): raise SaltInvocationError("nameConstraints needs at least one definition") @@ -1954,13 +1956,15 @@ def _render_subject_key_identifier(ext): def _render_authority_key_identifier(ext): return { - "keyid": pretty_hex(ext.value.key_identifier) - if ext.value.key_identifier - else None, + "keyid": ( + pretty_hex(ext.value.key_identifier) if ext.value.key_identifier else None + ), "issuer": [render_gn(x) for x in ext.value.authority_cert_issuer or []] or None, - "issuer_sn": dec2hex(ext.value.authority_cert_serial_number) - if ext.value.authority_cert_serial_number - else None, + "issuer_sn": ( + dec2hex(ext.value.authority_cert_serial_number) + if ext.value.authority_cert_serial_number + else None + ), } @@ -1994,11 +1998,11 @@ def _render_authority_info_access(ext): for description in ext.value._descriptions: rendered.append( { - description.access_method._name - if description.access_method._name != "Unknown OID" - else description.access_method.dotted_string: render_gn( - description.access_location.value - ) + ( + description.access_method._name + if description.access_method._name != "Unknown OID" + else description.access_method.dotted_string + ): render_gn(description.access_location.value) } ) except AttributeError: @@ -2015,9 +2019,11 @@ def _render_distribution_points(ext): "crlissuer": [render_gn(x) for x in dpoint.crl_issuer or []], "fullname": [render_gn(x) for x in dpoint.full_name or []], "reasons": list(sorted(x.value for x in dpoint.reasons or [])), - "relativename": dpoint.relative_name.rfc4514_string() - if dpoint.relative_name - else None, + "relativename": ( + dpoint.relative_name.rfc4514_string() + if dpoint.relative_name + else None + ), } ) except AttributeError: @@ -2031,9 +2037,11 @@ def _render_issuing_distribution_point(ext): "onysomereasons": list( sorted(x.value for x in ext.value.only_some_reasons or []) ), - "relativename": ext.value.relative_name.rfc4514_string() - if ext.value.relative_name - else None, + "relativename": ( + ext.value.relative_name.rfc4514_string() + if ext.value.relative_name + else None + ), "onlyuser": ext.value.only_contains_user_certs, "onlyCA": ext.value.only_contains_ca_certs, "onlyAA": ext.value.only_contains_attribute_certs, diff --git a/salt/utils/xmlutil.py b/salt/utils/xmlutil.py index 46e2946f914..9943c28b7c7 100644 --- a/salt/utils/xmlutil.py +++ b/salt/utils/xmlutil.py @@ -331,9 +331,11 @@ def change_xml(doc, data, mapping): if new_value is not None: # We need to increment ids from arrays since xpath starts at 1 converters = { - p: (lambda n: n + 1) - if "[${}]".format(p) in xpath - else (lambda n: n) + p: ( + (lambda n: n + 1) + if "[${}]".format(p) in xpath + else (lambda n: n) + ) for p in placeholders } ctx = { diff --git a/salt/utils/yaml.py b/salt/utils/yaml.py index f590d493261..8e9e202b15f 100644 --- a/salt/utils/yaml.py +++ b/salt/utils/yaml.py @@ -1,6 +1,7 @@ """ Convenience module that provides our custom loader and dumper in a single module """ + # pylint: disable=wildcard-import,unused-wildcard-import,unused-import from yaml import YAMLError, parser, scanner diff --git a/salt/utils/yamldumper.py b/salt/utils/yamldumper.py index e5e937cac7d..8c6e40394a3 100644 --- a/salt/utils/yamldumper.py +++ b/salt/utils/yamldumper.py @@ -3,6 +3,7 @@ ~~~~~~~~~~~~~~~~~~~~~ """ + # pylint: disable=W0232 # class has no __init__ method diff --git a/salt/utils/yamlencoding.py b/salt/utils/yamlencoding.py index 7e26b9afcb5..b9c2d20d6c8 100644 --- a/salt/utils/yamlencoding.py +++ b/salt/utils/yamlencoding.py @@ -2,7 +2,6 @@ Functions for adding yaml encoding to the jinja context """ - import io import sys diff --git a/salt/utils/yamlloader.py b/salt/utils/yamlloader.py index 25b4b3bb936..f5bba7dc5c4 100644 --- a/salt/utils/yamlloader.py +++ b/salt/utils/yamlloader.py @@ -2,7 +2,6 @@ Custom YAML loading in Salt """ - import yaml # pylint: disable=blacklisted-import from yaml.constructor import ConstructorError from yaml.nodes import MappingNode, SequenceNode diff --git a/salt/utils/yamlloader_old.py b/salt/utils/yamlloader_old.py index d24717a79b2..9a81f5c8793 100644 --- a/salt/utils/yamlloader_old.py +++ b/salt/utils/yamlloader_old.py @@ -2,7 +2,6 @@ Custom YAML loading in Salt """ - import re import yaml # pylint: disable=blacklisted-import diff --git a/salt/utils/zfs.py b/salt/utils/zfs.py index 3c38cecc7aa..593cd8f96c8 100644 --- a/salt/utils/zfs.py +++ b/salt/utils/zfs.py @@ -12,7 +12,6 @@ These functions are for dealing with type conversion and basic execution """ - import logging import math import os diff --git a/salt/version.py b/salt/version.py index 8cc50f6ef05..53522e3f9a2 100644 --- a/salt/version.py +++ b/salt/version.py @@ -1,6 +1,7 @@ """ Set up the version of Salt """ + import argparse import operator import os diff --git a/salt/wheel/file_roots.py b/salt/wheel/file_roots.py index c25bb883fbe..6fb23d2cd4d 100644 --- a/salt/wheel/file_roots.py +++ b/salt/wheel/file_roots.py @@ -2,7 +2,6 @@ Read in files from the file_root and save files to the file root """ - import os import salt.utils.files diff --git a/salt/wheel/key.py b/salt/wheel/key.py index 44a1b7ab626..1b756c683f6 100644 --- a/salt/wheel/key.py +++ b/salt/wheel/key.py @@ -26,7 +26,6 @@ The wheel key functions can also be called via a ``salt`` command at the CLI using the :mod:`saltutil execution module `. """ - import hashlib import logging import os diff --git a/salt/wheel/minions.py b/salt/wheel/minions.py index 75d06a94f02..65ac422f268 100644 --- a/salt/wheel/minions.py +++ b/salt/wheel/minions.py @@ -2,7 +2,6 @@ Wheel system wrapper for connected minions """ - import salt.config import salt.utils.minions from salt.utils.cache import CacheCli diff --git a/tests/conftest.py b/tests/conftest.py index 38cfa97c7f7..24ad882c878 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -519,7 +519,9 @@ def pytest_collection_modifyitems(config, items): log.debug("Finish called on %s", self) try: return func(request) - except BaseException as exc: # pylint: disable=broad-except + except ( + BaseException # pylint: disable=broad-except + ) as exc: pytest.fail( "Failed to run finish() on {}: {}".format( fixturedef, exc diff --git a/tests/eventlisten.py b/tests/eventlisten.py index 4b56378a448..c2ced91a979 100644 --- a/tests/eventlisten.py +++ b/tests/eventlisten.py @@ -4,6 +4,7 @@ what the sock_dir is. This script is a generic tool to test event output """ + import optparse # pylint: disable=deprecated-module import os import pprint diff --git a/tests/integration/cli/test_custom_module.py b/tests/integration/cli/test_custom_module.py index 68d42ff2cd8..7a307f139e0 100644 --- a/tests/integration/cli/test_custom_module.py +++ b/tests/integration/cli/test_custom_module.py @@ -36,7 +36,7 @@ from tests.support.case import SSHCase pytestmark = [ pytest.mark.skipif( "grains['osfinger'] == 'Fedora Linux-39'", - reason="Fedora 39 ships with Python 3.12. Test can't run with system Python on 3.12" + reason="Fedora 39 ships with Python 3.12. Test can't run with system Python on 3.12", # Actually, the problem is that the tornado we ship is not prepared for Python 3.12, # and it imports `ssl` and checks if the `match_hostname` function is defined, which # has been deprecated since Python 3.7, so, the logic goes into trying to import diff --git a/tests/integration/cloud/clouds/test_digitalocean.py b/tests/integration/cloud/clouds/test_digitalocean.py index 64ad0f17426..7e2230c6b17 100644 --- a/tests/integration/cloud/clouds/test_digitalocean.py +++ b/tests/integration/cloud/clouds/test_digitalocean.py @@ -1,6 +1,7 @@ """ Integration tests for DigitalOcean APIv2 """ + import base64 import hashlib diff --git a/tests/integration/cloud/clouds/test_dimensiondata.py b/tests/integration/cloud/clouds/test_dimensiondata.py index 56ac83042c3..0d258216f93 100644 --- a/tests/integration/cloud/clouds/test_dimensiondata.py +++ b/tests/integration/cloud/clouds/test_dimensiondata.py @@ -2,7 +2,6 @@ Integration tests for the Dimension Data cloud provider """ - from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest diff --git a/tests/integration/cloud/clouds/test_ec2.py b/tests/integration/cloud/clouds/test_ec2.py index c3c3da8484e..c349c40844f 100644 --- a/tests/integration/cloud/clouds/test_ec2.py +++ b/tests/integration/cloud/clouds/test_ec2.py @@ -1,6 +1,7 @@ """ :codeauthor: Nicole Thomas """ + import os import pytest diff --git a/tests/integration/cloud/clouds/test_gce.py b/tests/integration/cloud/clouds/test_gce.py index affa0134fc5..a2366b1d90d 100644 --- a/tests/integration/cloud/clouds/test_gce.py +++ b/tests/integration/cloud/clouds/test_gce.py @@ -3,7 +3,6 @@ :codeauthor: Tomas Sirny """ - from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest diff --git a/tests/integration/cloud/clouds/test_linode.py b/tests/integration/cloud/clouds/test_linode.py index 7b0919cb2f1..1b06fe72620 100644 --- a/tests/integration/cloud/clouds/test_linode.py +++ b/tests/integration/cloud/clouds/test_linode.py @@ -2,7 +2,6 @@ :codeauthor: Nicole Thomas """ - # Create the cloud instance name to be used throughout the tests from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest diff --git a/tests/integration/cloud/clouds/test_oneandone.py b/tests/integration/cloud/clouds/test_oneandone.py index 64a2d16694d..148d9aafe53 100644 --- a/tests/integration/cloud/clouds/test_oneandone.py +++ b/tests/integration/cloud/clouds/test_oneandone.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Amel Ajdinovic ` """ + import pytest from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest diff --git a/tests/integration/cloud/clouds/test_profitbricks.py b/tests/integration/cloud/clouds/test_profitbricks.py index 0428b40c260..bc7928f4c1e 100644 --- a/tests/integration/cloud/clouds/test_profitbricks.py +++ b/tests/integration/cloud/clouds/test_profitbricks.py @@ -1,6 +1,7 @@ """ :codeauthor: Ethan Devenport """ + import pytest from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest diff --git a/tests/integration/cloud/helpers/cloud_test_base.py b/tests/integration/cloud/helpers/cloud_test_base.py index 48e44a6f0fa..ec634ab7380 100644 --- a/tests/integration/cloud/helpers/cloud_test_base.py +++ b/tests/integration/cloud/helpers/cloud_test_base.py @@ -2,7 +2,6 @@ Tests for the Openstack Cloud Provider """ - import logging import os import shutil diff --git a/tests/integration/cloud/test_cloud.py b/tests/integration/cloud/test_cloud.py index 29bd820da7b..85a0d397efe 100644 --- a/tests/integration/cloud/test_cloud.py +++ b/tests/integration/cloud/test_cloud.py @@ -1,6 +1,7 @@ """ Integration tests for functions located in the salt.cloud.__init__.py file. """ + import pytest import salt.cloud diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 1e1baf6134a..13ded49f4a6 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -4,6 +4,7 @@ Integration tests PyTest configuration/fixtures """ + import logging import pathlib diff --git a/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py b/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py index 19d4d4e9420..37d8e0d2450 100644 --- a/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py +++ b/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py @@ -6,7 +6,6 @@ Returns a hash of the name of the pillar module as defined in _virtual__ with the value __opts__ """ - import logging # Set up logging diff --git a/tests/integration/files/file/base/_modules/runtests_helpers.py b/tests/integration/files/file/base/_modules/runtests_helpers.py index 3ee0e2da5f3..a38dd1835cf 100644 --- a/tests/integration/files/file/base/_modules/runtests_helpers.py +++ b/tests/integration/files/file/base/_modules/runtests_helpers.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~ """ - import logging import os import sys diff --git a/tests/integration/files/returners/noop_returner.py b/tests/integration/files/returners/noop_returner.py index 0201e5076b9..c6a34f975c2 100644 --- a/tests/integration/files/returners/noop_returner.py +++ b/tests/integration/files/returners/noop_returner.py @@ -5,7 +5,6 @@ noop_returner A returner that does nothing which is used to test the salt-master `event_return` functionality """ - import logging import salt.utils.jid diff --git a/tests/integration/grains/test_core.py b/tests/integration/grains/test_core.py index e45836e4ad2..59b84456938 100644 --- a/tests/integration/grains/test_core.py +++ b/tests/integration/grains/test_core.py @@ -1,6 +1,7 @@ """ Test the core grains """ + import pytest import salt.loader diff --git a/tests/integration/grains/test_custom.py b/tests/integration/grains/test_custom.py index 17a09a4797e..d99e88d1902 100644 --- a/tests/integration/grains/test_custom.py +++ b/tests/integration/grains/test_custom.py @@ -2,7 +2,6 @@ Test the core grains """ - import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/loader/test_ext_grains.py b/tests/integration/loader/test_ext_grains.py index af98e544f65..242519aa3f4 100644 --- a/tests/integration/loader/test_ext_grains.py +++ b/tests/integration/loader/test_ext_grains.py @@ -5,7 +5,6 @@ Test Salt's loader regarding external grains """ - import os import time diff --git a/tests/integration/minion/test_timeout.py b/tests/integration/minion/test_timeout.py index 8ceb66c4a5d..29923ffc49d 100644 --- a/tests/integration/minion/test_timeout.py +++ b/tests/integration/minion/test_timeout.py @@ -2,7 +2,6 @@ Tests for various minion timeouts """ - import os import sys diff --git a/tests/integration/modules/test_boto_iam.py b/tests/integration/modules/test_boto_iam.py index 01f15d76edd..667395083b6 100644 --- a/tests/integration/modules/test_boto_iam.py +++ b/tests/integration/modules/test_boto_iam.py @@ -1,6 +1,7 @@ """ Validate the boto_iam module """ + import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/modules/test_boto_sns.py b/tests/integration/modules/test_boto_sns.py index fd4313a3344..46eb1c1657a 100644 --- a/tests/integration/modules/test_boto_sns.py +++ b/tests/integration/modules/test_boto_sns.py @@ -1,6 +1,7 @@ """ Validate the boto_sns module """ + import re import pytest diff --git a/tests/integration/modules/test_macdefaults.py b/tests/integration/modules/test_macdefaults.py index da7a6ef854d..bdd74901628 100644 --- a/tests/integration/modules/test_macdefaults.py +++ b/tests/integration/modules/test_macdefaults.py @@ -1,6 +1,7 @@ """ Validate the mac-defaults module """ + import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/modules/test_test.py b/tests/integration/modules/test_test.py index f9849e3a48c..06f9d23341c 100644 --- a/tests/integration/modules/test_test.py +++ b/tests/integration/modules/test_test.py @@ -82,7 +82,10 @@ class TestModuleTest(ModuleCase, AdaptedConfigurationTestCaseMixin): test.collatz """ self.assertEqual( - self.run_function("test.collatz", ["40"],)[ + self.run_function( + "test.collatz", + ["40"], + )[ 0 ][-1], 2, diff --git a/tests/integration/modules/test_timezone.py b/tests/integration/modules/test_timezone.py index 8d7180cbd13..3af9bf628ec 100644 --- a/tests/integration/modules/test_timezone.py +++ b/tests/integration/modules/test_timezone.py @@ -3,6 +3,7 @@ Integration tests for timezone module Linux and Solaris are supported """ + import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/shell/test_master_tops.py b/tests/integration/shell/test_master_tops.py index 27625a4ff60..ac419de96b6 100644 --- a/tests/integration/shell/test_master_tops.py +++ b/tests/integration/shell/test_master_tops.py @@ -3,7 +3,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import pytest from tests.support.case import ShellCase diff --git a/tests/integration/spm/test_install.py b/tests/integration/spm/test_install.py index c73f6639230..bd4d3617694 100644 --- a/tests/integration/spm/test_install.py +++ b/tests/integration/spm/test_install.py @@ -1,6 +1,7 @@ """ Tests for the spm install utility """ + import os import pytest diff --git a/tests/integration/ssh/test_state.py b/tests/integration/ssh/test_state.py index 8193c148a8c..812a6489a6c 100644 --- a/tests/integration/ssh/test_state.py +++ b/tests/integration/ssh/test_state.py @@ -14,7 +14,7 @@ from tests.support.runtests import RUNTIME_VARS pytestmark = [ pytest.mark.skipif( "grains['osfinger'] == 'Fedora Linux-39'", - reason="Fedora 39 ships with Python 3.12. Test can't run with system Python on 3.12" + reason="Fedora 39 ships with Python 3.12. Test can't run with system Python on 3.12", # Actually, the problem is that the tornado we ship is not prepared for Python 3.12, # and it imports `ssl` and checks if the `match_hostname` function is defined, which # has been deprecated since Python 3.7, so, the logic goes into trying to import diff --git a/tests/integration/states/test_boto_sns.py b/tests/integration/states/test_boto_sns.py index c40adbdba5f..2978e6fbf35 100644 --- a/tests/integration/states/test_boto_sns.py +++ b/tests/integration/states/test_boto_sns.py @@ -1,6 +1,7 @@ """ Tests for the boto_sns state """ + import re import pytest diff --git a/tests/integration/states/test_compiler.py b/tests/integration/states/test_compiler.py index ea64759e26d..257655fae91 100644 --- a/tests/integration/states/test_compiler.py +++ b/tests/integration/states/test_compiler.py @@ -2,7 +2,6 @@ tests for host state """ - from tests.support.case import ModuleCase diff --git a/tests/integration/states/test_handle_iorder.py b/tests/integration/states/test_handle_iorder.py index 39a5e88fe32..7bdd4a0d0df 100644 --- a/tests/integration/states/test_handle_iorder.py +++ b/tests/integration/states/test_handle_iorder.py @@ -2,7 +2,6 @@ tests for host state """ - from tests.support.case import ModuleCase diff --git a/tests/integration/states/test_lxd_image.py b/tests/integration/states/test_lxd_image.py index 374aac57762..b0ab485bdf3 100644 --- a/tests/integration/states/test_lxd_image.py +++ b/tests/integration/states/test_lxd_image.py @@ -1,6 +1,7 @@ """ Integration tests for the lxd states """ + import pytest import salt.modules.lxd diff --git a/tests/integration/states/test_lxd_profile.py b/tests/integration/states/test_lxd_profile.py index cfcc24d968d..e6df9db2ef8 100644 --- a/tests/integration/states/test_lxd_profile.py +++ b/tests/integration/states/test_lxd_profile.py @@ -1,6 +1,7 @@ """ Integration tests for the lxd states """ + import pytest import salt.modules.lxd diff --git a/tests/integration/utils/test_idem.py b/tests/integration/utils/test_idem.py index c2b57b1ec14..eb2fcd83254 100644 --- a/tests/integration/utils/test_idem.py +++ b/tests/integration/utils/test_idem.py @@ -1,6 +1,7 @@ """ Test utility methods that the idem module and state share """ + from contextlib import contextmanager import pytest diff --git a/tests/integration/utils/test_smb.py b/tests/integration/utils/test_smb.py index 5f7db744242..8ef792d6340 100644 --- a/tests/integration/utils/test_smb.py +++ b/tests/integration/utils/test_smb.py @@ -1,6 +1,7 @@ """ Test utility methods that communicate with SMB shares. """ + import getpass import logging import os diff --git a/tests/packdump.py b/tests/packdump.py index d25b5454e73..e9b7b70096a 100644 --- a/tests/packdump.py +++ b/tests/packdump.py @@ -1,6 +1,7 @@ """ Simple script to dump the contents of msgpack files to the terminal """ + # pylint: disable=resource-leakage import os diff --git a/tests/pytests/conftest.py b/tests/pytests/conftest.py index 79807df8055..1179e0e1dfb 100644 --- a/tests/pytests/conftest.py +++ b/tests/pytests/conftest.py @@ -2,6 +2,7 @@ tests.pytests.conftest ~~~~~~~~~~~~~~~~~~~~~~ """ + import functools import inspect import logging @@ -643,6 +644,7 @@ def io_loop(): # <---- Async Test Fixtures ------------------------------------------------------------------------------------------ + # ----- Helpers -----------------------------------------------------------------------------------------------------> @pytest.helpers.proxy.register def delta_proxy_minion_ids(): diff --git a/tests/pytests/functional/cli/test_batch.py b/tests/pytests/functional/cli/test_batch.py index 8c69b48cf4a..b13ed3fb7b8 100644 --- a/tests/pytests/functional/cli/test_batch.py +++ b/tests/pytests/functional/cli/test_batch.py @@ -2,6 +2,7 @@ tests.pytests.functional.cli.test_batch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import salt.cli.batch import salt.config import salt.utils.jid diff --git a/tests/pytests/functional/cli/test_salt_cloud.py b/tests/pytests/functional/cli/test_salt_cloud.py index 0b661490bfe..4bd33bdc6c9 100644 --- a/tests/pytests/functional/cli/test_salt_cloud.py +++ b/tests/pytests/functional/cli/test_salt_cloud.py @@ -2,6 +2,7 @@ tests.pytests.integration.cli.test_salt_cloud ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import pytest pytest.importorskip("libcloud", reason="salt-cloud requires >= libcloud 0.11.4") diff --git a/tests/pytests/functional/modules/file/test_replace.py b/tests/pytests/functional/modules/file/test_replace.py index 3be41d0661d..3505cc38bf5 100644 --- a/tests/pytests/functional/modules/file/test_replace.py +++ b/tests/pytests/functional/modules/file/test_replace.py @@ -1,6 +1,7 @@ """ Tests for file.rename function """ + import os import shutil diff --git a/tests/pytests/functional/modules/state/test_jinja_filters.py b/tests/pytests/functional/modules/state/test_jinja_filters.py index 0fd44dba74c..7a72ba7f530 100644 --- a/tests/pytests/functional/modules/state/test_jinja_filters.py +++ b/tests/pytests/functional/modules/state/test_jinja_filters.py @@ -1,6 +1,7 @@ """ Testing Jinja filters availablilty via state system """ + import logging import os diff --git a/tests/pytests/functional/modules/test_archive.py b/tests/pytests/functional/modules/test_archive.py index 60f06aef71f..158ac4d0cf4 100644 --- a/tests/pytests/functional/modules/test_archive.py +++ b/tests/pytests/functional/modules/test_archive.py @@ -1,6 +1,7 @@ """ Tests for the archive state """ + import os import pathlib import shutil diff --git a/tests/pytests/functional/modules/test_dockermod.py b/tests/pytests/functional/modules/test_dockermod.py index 3c7bb25e461..7d66379de0c 100644 --- a/tests/pytests/functional/modules/test_dockermod.py +++ b/tests/pytests/functional/modules/test_dockermod.py @@ -1,6 +1,7 @@ """ Integration tests for the docker_container states """ + import logging import pytest diff --git a/tests/pytests/functional/modules/test_mac_pkgutil.py b/tests/pytests/functional/modules/test_mac_pkgutil.py index 397bb895871..6b9233c2ecd 100644 --- a/tests/pytests/functional/modules/test_mac_pkgutil.py +++ b/tests/pytests/functional/modules/test_mac_pkgutil.py @@ -1,6 +1,7 @@ """ integration tests for mac_pkgutil """ + import shutil import pytest diff --git a/tests/pytests/functional/modules/test_mysql.py b/tests/pytests/functional/modules/test_mysql.py index d920bbdbc03..c82bba30193 100644 --- a/tests/pytests/functional/modules/test_mysql.py +++ b/tests/pytests/functional/modules/test_mysql.py @@ -1,6 +1,7 @@ """ Test Salt MySQL module across various MySQL variants """ + import logging import time diff --git a/tests/pytests/functional/modules/test_network.py b/tests/pytests/functional/modules/test_network.py index 702373c15ae..e2515e4556b 100644 --- a/tests/pytests/functional/modules/test_network.py +++ b/tests/pytests/functional/modules/test_network.py @@ -1,6 +1,7 @@ """ Validate network module """ + import pytest pytestmark = [ diff --git a/tests/pytests/functional/modules/test_win_shortcut.py b/tests/pytests/functional/modules/test_win_shortcut.py index 292f439536b..90aa30d614d 100644 --- a/tests/pytests/functional/modules/test_win_shortcut.py +++ b/tests/pytests/functional/modules/test_win_shortcut.py @@ -1,6 +1,7 @@ """ Tests for win_shortcut execution module """ + import os import shutil import subprocess diff --git a/tests/pytests/functional/modules/win_file/test_check_perms.py b/tests/pytests/functional/modules/win_file/test_check_perms.py index 7b829b35eed..f2196185904 100644 --- a/tests/pytests/functional/modules/win_file/test_check_perms.py +++ b/tests/pytests/functional/modules/win_file/test_check_perms.py @@ -1,6 +1,7 @@ """ Tests for win_file execution module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/functional/modules/win_file/test_remove.py b/tests/pytests/functional/modules/win_file/test_remove.py index 6cc26686f5a..d9e92411ca2 100644 --- a/tests/pytests/functional/modules/win_file/test_remove.py +++ b/tests/pytests/functional/modules/win_file/test_remove.py @@ -1,6 +1,7 @@ """ Tests for win_file execution module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/functional/modules/win_file/test_stat.py b/tests/pytests/functional/modules/win_file/test_stat.py index 0ff78e85fb7..a09d7d43aa9 100644 --- a/tests/pytests/functional/modules/win_file/test_stat.py +++ b/tests/pytests/functional/modules/win_file/test_stat.py @@ -1,6 +1,7 @@ """ Tests for win_file execution module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/functional/states/file/test_comment.py b/tests/pytests/functional/states/file/test_comment.py index b7a7c8a7c95..cd825d75d83 100644 --- a/tests/pytests/functional/states/file/test_comment.py +++ b/tests/pytests/functional/states/file/test_comment.py @@ -1,6 +1,7 @@ """ Tests for file.comment state function """ + import re import pytest diff --git a/tests/pytests/functional/states/file/test_managed.py b/tests/pytests/functional/states/file/test_managed.py index 9678fb63432..7746134d564 100644 --- a/tests/pytests/functional/states/file/test_managed.py +++ b/tests/pytests/functional/states/file/test_managed.py @@ -658,7 +658,6 @@ def test_issue_8947_utf8_sls(modules, tmp_path, state_tree, subtests): @pytest.mark.skip_if_not_root @pytest.mark.skip_on_windows(reason="Windows does not support setuid. Skipping.") def test_owner_after_setuid(file, modules, tmp_path, state_file_account): - """ Test to check file user/group after setting setuid or setgid. Because Python os.chown() does reset the setuid/setgid to 0. diff --git a/tests/pytests/functional/states/file/test_rename.py b/tests/pytests/functional/states/file/test_rename.py index db293d16277..1aa4fc77b68 100644 --- a/tests/pytests/functional/states/file/test_rename.py +++ b/tests/pytests/functional/states/file/test_rename.py @@ -1,6 +1,7 @@ """ Tests for file.rename state function """ + # nox -e pytest-zeromq-3.8(coverage=False) -- -vvv --run-slow --run-destructive tests\pytests\functional\states\file\test_rename.py import pytest diff --git a/tests/pytests/functional/states/test_chocolatey_1_2_1.py b/tests/pytests/functional/states/test_chocolatey_1_2_1.py index 9dcc186636a..0e9972df17e 100644 --- a/tests/pytests/functional/states/test_chocolatey_1_2_1.py +++ b/tests/pytests/functional/states/test_chocolatey_1_2_1.py @@ -1,6 +1,7 @@ """ Functional tests for chocolatey state """ + import os import pathlib diff --git a/tests/pytests/functional/states/test_chocolatey_latest.py b/tests/pytests/functional/states/test_chocolatey_latest.py index 9d329d5fc59..41ba0df5b38 100644 --- a/tests/pytests/functional/states/test_chocolatey_latest.py +++ b/tests/pytests/functional/states/test_chocolatey_latest.py @@ -1,6 +1,7 @@ """ Functional tests for chocolatey state """ + import os import pathlib diff --git a/tests/pytests/functional/states/test_mysql.py b/tests/pytests/functional/states/test_mysql.py index 355f2cc1eba..1f14d8d8ed2 100644 --- a/tests/pytests/functional/states/test_mysql.py +++ b/tests/pytests/functional/states/test_mysql.py @@ -1,6 +1,7 @@ """ Test Salt MySQL state module across various MySQL variants """ + import logging import time diff --git a/tests/pytests/functional/states/test_svn.py b/tests/pytests/functional/states/test_svn.py index 5ad09ad37e2..b4f04dd8a6d 100644 --- a/tests/pytests/functional/states/test_svn.py +++ b/tests/pytests/functional/states/test_svn.py @@ -1,6 +1,7 @@ """ Tests for the SVN state """ + import logging import pytest diff --git a/tests/pytests/functional/states/test_win_certutil.py b/tests/pytests/functional/states/test_win_certutil.py index 92d238b3f4a..6b3d58b19c6 100644 --- a/tests/pytests/functional/states/test_win_certutil.py +++ b/tests/pytests/functional/states/test_win_certutil.py @@ -1,6 +1,7 @@ """ Tests for win_certutil state module """ + import pytest import salt.utils.files diff --git a/tests/pytests/functional/states/test_x509_v2.py b/tests/pytests/functional/states/test_x509_v2.py index 3cd09d7d840..01c877fceda 100644 --- a/tests/pytests/functional/states/test_x509_v2.py +++ b/tests/pytests/functional/states/test_x509_v2.py @@ -572,9 +572,9 @@ def existing_cert(x509, cert_args, ca_key, rsa_privkey, request): ca_key, encoding=cert_args.get("encoding", "pem"), passphrase=cert_args.get("pkcs12_passphrase"), - subject=subject - if "signing_policy" not in cert_args - else "CN=from_signing_policy", + subject=( + subject if "signing_policy" not in cert_args else "CN=from_signing_policy" + ), ) yield cert_args["name"] diff --git a/tests/pytests/functional/utils/test_process.py b/tests/pytests/functional/utils/test_process.py index 6c420b95f48..bbb83638761 100644 --- a/tests/pytests/functional/utils/test_process.py +++ b/tests/pytests/functional/utils/test_process.py @@ -4,6 +4,7 @@ tests.pytests.functional.utils.test_process Test salt's process utility module """ + import pytest import salt.utils.process diff --git a/tests/pytests/functional/utils/win_dacl/test_get_name.py b/tests/pytests/functional/utils/win_dacl/test_get_name.py index 8ea5d7614e4..f35c1336ec4 100644 --- a/tests/pytests/functional/utils/win_dacl/test_get_name.py +++ b/tests/pytests/functional/utils/win_dacl/test_get_name.py @@ -4,6 +4,7 @@ tests.pytests.unit.utils.win_dacl.test_get_name Test the get_name function in the win_dacl utility module """ + import pytest import salt.exceptions diff --git a/tests/pytests/functional/utils/win_dacl/test_get_sid.py b/tests/pytests/functional/utils/win_dacl/test_get_sid.py index e2e09f6dea6..4560713dad5 100644 --- a/tests/pytests/functional/utils/win_dacl/test_get_sid.py +++ b/tests/pytests/functional/utils/win_dacl/test_get_sid.py @@ -4,6 +4,7 @@ tests.pytests.unit.utils.win_dacl.test_get_sid Test the get_sid function in the win_dacl utility module """ + import pytest import salt.utils.win_dacl diff --git a/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py b/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py index adde42501ae..bea9240f75e 100644 --- a/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py +++ b/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py @@ -4,6 +4,7 @@ tests.pytests.unit.utils.win_dacl.test_get_sid_string Test the get_sid_string function in the win_dacl utility module """ + import pytest import salt.utils.win_dacl diff --git a/tests/pytests/integration/cli/test_salt.py b/tests/pytests/integration/cli/test_salt.py index 30752102025..46680b449ea 100644 --- a/tests/pytests/integration/cli/test_salt.py +++ b/tests/pytests/integration/cli/test_salt.py @@ -1,6 +1,7 @@ """ :codeauthor: Thayne Harbaugh (tharbaug@adobe.com) """ + import logging import os import shutil diff --git a/tests/pytests/integration/cli/test_salt_cp.py b/tests/pytests/integration/cli/test_salt_cp.py index 9c303e7c9b4..ce01de43437 100644 --- a/tests/pytests/integration/cli/test_salt_cp.py +++ b/tests/pytests/integration/cli/test_salt_cp.py @@ -3,7 +3,6 @@ tests.integration.shell.cp ~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import os import pathlib diff --git a/tests/pytests/integration/cli/test_salt_deltaproxy.py b/tests/pytests/integration/cli/test_salt_deltaproxy.py index 99c8368b73d..26ba9eedfad 100644 --- a/tests/pytests/integration/cli/test_salt_deltaproxy.py +++ b/tests/pytests/integration/cli/test_salt_deltaproxy.py @@ -1,6 +1,7 @@ """ :codeauthor: Gareth J. Greenaway (ggreenaway@vmware.com) """ + import logging import random @@ -177,7 +178,9 @@ def test_exit_status_correct_usage( "{}.sls".format(proxy_two), dummy_proxy_two_pillar_file, ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile: + with ( + top_tempfile + ), controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, @@ -404,7 +407,11 @@ def test_invalid_connection( broken_proxy_two_tempfile = salt_master.pillar_tree.base.temp_file( "{}.sls".format(broken_proxy_two), broken_proxy_two_pillar_file ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, broken_proxy_one_tempfile, broken_proxy_two_tempfile: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), dummy_proxy_one_tempfile, broken_proxy_one_tempfile, broken_proxy_two_tempfile: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, @@ -533,7 +540,11 @@ def ping(): custom_proxy_module = salt_master.state_tree.base.temp_file( "_proxy/custom_dummy.py", module_contents ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, @@ -666,7 +677,11 @@ def ping(): custom_proxy_module = salt_master.state_tree.base.temp_file( "_proxy/custom_dummy.py", module_contents ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, diff --git a/tests/pytests/integration/master/test_payload.py b/tests/pytests/integration/master/test_payload.py index 692005b5692..9d663ac34ee 100644 --- a/tests/pytests/integration/master/test_payload.py +++ b/tests/pytests/integration/master/test_payload.py @@ -1,6 +1,7 @@ """ Tests for payload """ + import pytest diff --git a/tests/pytests/integration/minion/test_return_retries.py b/tests/pytests/integration/minion/test_return_retries.py index 37ea32ffce8..8d59a89de13 100644 --- a/tests/pytests/integration/minion/test_return_retries.py +++ b/tests/pytests/integration/minion/test_return_retries.py @@ -110,7 +110,9 @@ def test_pillar_timeout(salt_master_factory, tmp_path): sls_tempfile = master.state_tree.base.temp_file( "{}.sls".format(sls_name), sls_contents ) - with master.started(), minion1.started(), minion2.started(), minion3.started(), minion4.started(), sls_tempfile: + with master.started(), minion1.started(), minion2.started(), minion3.started(), minion4.started(), ( + sls_tempfile + ): cmd = 'import time; time.sleep(6); print(\'{"foo": "bang"}\');\n' with salt.utils.files.fopen(tmp_path / "script.py", "w") as fp: fp.write(cmd) diff --git a/tests/pytests/integration/modules/grains/test_module.py b/tests/pytests/integration/modules/grains/test_module.py index cbbb149d2ad..bb977af9183 100644 --- a/tests/pytests/integration/modules/grains/test_module.py +++ b/tests/pytests/integration/modules/grains/test_module.py @@ -2,7 +2,6 @@ Test the grains module """ - import logging import time diff --git a/tests/pytests/integration/modules/saltutil/test_modules.py b/tests/pytests/integration/modules/saltutil/test_modules.py index 9d10189bb30..d35cb735f2e 100644 --- a/tests/pytests/integration/modules/saltutil/test_modules.py +++ b/tests/pytests/integration/modules/saltutil/test_modules.py @@ -2,7 +2,6 @@ Integration tests for the saltutil module. """ - import pytest pytestmark = [ diff --git a/tests/pytests/integration/modules/saltutil/test_pillar.py b/tests/pytests/integration/modules/saltutil/test_pillar.py index 7eb51605604..c1e451772c3 100644 --- a/tests/pytests/integration/modules/saltutil/test_pillar.py +++ b/tests/pytests/integration/modules/saltutil/test_pillar.py @@ -2,7 +2,6 @@ Integration tests for the saltutil module. """ - import logging import time diff --git a/tests/pytests/integration/modules/saltutil/test_wheel.py b/tests/pytests/integration/modules/saltutil/test_wheel.py index 51164c62399..3ddb95c2dc3 100644 --- a/tests/pytests/integration/modules/saltutil/test_wheel.py +++ b/tests/pytests/integration/modules/saltutil/test_wheel.py @@ -2,7 +2,6 @@ Integration tests for the saltutil module. """ - import pathlib import shutil diff --git a/tests/pytests/integration/modules/test_beacons.py b/tests/pytests/integration/modules/test_beacons.py index 1a1ae274854..7908f4db609 100644 --- a/tests/pytests/integration/modules/test_beacons.py +++ b/tests/pytests/integration/modules/test_beacons.py @@ -1,6 +1,7 @@ """ :codeauthor: Justin Anderson """ + import pathlib import shutil diff --git a/tests/pytests/integration/modules/test_event.py b/tests/pytests/integration/modules/test_event.py index 172b2ab445b..b6ea0a2d1cb 100644 --- a/tests/pytests/integration/modules/test_event.py +++ b/tests/pytests/integration/modules/test_event.py @@ -2,6 +2,7 @@ tests.pytests.integration.modules.test_event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import time import pytest diff --git a/tests/pytests/integration/modules/test_file.py b/tests/pytests/integration/modules/test_file.py index 1489269a93f..27d3af8f5d9 100644 --- a/tests/pytests/integration/modules/test_file.py +++ b/tests/pytests/integration/modules/test_file.py @@ -1,6 +1,7 @@ """ Tests for the file state """ + import os import pytest diff --git a/tests/pytests/integration/modules/test_idem.py b/tests/pytests/integration/modules/test_idem.py index 90e319cab0d..9ddc3eb4412 100644 --- a/tests/pytests/integration/modules/test_idem.py +++ b/tests/pytests/integration/modules/test_idem.py @@ -1,6 +1,7 @@ """ Integration tests for the idem execution module """ + from contextlib import contextmanager import pytest diff --git a/tests/pytests/integration/modules/test_useradd.py b/tests/pytests/integration/modules/test_useradd.py index 6b180d89df6..25c2d7090da 100644 --- a/tests/pytests/integration/modules/test_useradd.py +++ b/tests/pytests/integration/modules/test_useradd.py @@ -1,6 +1,7 @@ """ Integration tests for modules/useradd.py and modules/win_useradd.py """ + import pytest from saltfactories.utils import random_string diff --git a/tests/pytests/integration/modules/test_virt.py b/tests/pytests/integration/modules/test_virt.py index df1f516636b..b14d03ec73d 100644 --- a/tests/pytests/integration/modules/test_virt.py +++ b/tests/pytests/integration/modules/test_virt.py @@ -1,6 +1,7 @@ """ Validate the virt module """ + import logging from numbers import Number from xml.etree import ElementTree diff --git a/tests/pytests/integration/netapi/test_ssh_client.py b/tests/pytests/integration/netapi/test_ssh_client.py index 3f4b8855064..6582c993f9e 100644 --- a/tests/pytests/integration/netapi/test_ssh_client.py +++ b/tests/pytests/integration/netapi/test_ssh_client.py @@ -10,7 +10,7 @@ pytestmark = [ pytest.mark.requires_sshd_server, pytest.mark.skipif( "grains['osfinger'] == 'Fedora Linux-39'", - reason="Fedora 39 ships with Python 3.12. Test can't run with system Python on 3.12" + reason="Fedora 39 ships with Python 3.12. Test can't run with system Python on 3.12", # Actually, the problem is that the tornado we ship is not prepared for Python 3.12, # and it imports `ssl` and checks if the `match_hostname` function is defined, which # has been deprecated since Python 3.7, so, the logic goes into trying to import diff --git a/tests/pytests/integration/pillar/cache/test_pillar_cache.py b/tests/pytests/integration/pillar/cache/test_pillar_cache.py index d54bbfa082f..86f0d49d39b 100644 --- a/tests/pytests/integration/pillar/cache/test_pillar_cache.py +++ b/tests/pytests/integration/pillar/cache/test_pillar_cache.py @@ -1,6 +1,7 @@ """ Pillar cache tests """ + import pytest diff --git a/tests/pytests/integration/pillar/test_pillar_include.py b/tests/pytests/integration/pillar/test_pillar_include.py index 63a76599660..dfabd4cb99f 100644 --- a/tests/pytests/integration/pillar/test_pillar_include.py +++ b/tests/pytests/integration/pillar/test_pillar_include.py @@ -1,6 +1,7 @@ """ Pillar include tests """ + import pytest @@ -83,8 +84,16 @@ def pillar_include_tree(base_env_pillar_tree_root_dir, salt_minion, salt_call_cl "glob-include-b.sls", glob_include_b_pillar_file, base_env_pillar_tree_root_dir ) try: - with top_tempfile, include_tempfile, include_a_tempfile, include_b_tempfile, include_c_tempfile, include_d_tempfile: - with glob_include_tempfile, glob_include_a_tempfile, glob_include_b_tempfile: + with ( + top_tempfile + ), ( + include_tempfile + ), ( + include_a_tempfile + ), include_b_tempfile, include_c_tempfile, include_d_tempfile: + with ( + glob_include_tempfile + ), glob_include_a_tempfile, glob_include_b_tempfile: ret = salt_call_cli.run("saltutil.refresh_pillar", wait=True) assert ret.returncode == 0 assert ret.data is True diff --git a/tests/pytests/integration/proxy/conftest.py b/tests/pytests/integration/proxy/conftest.py index d924f4eba8a..5c7abec4c84 100644 --- a/tests/pytests/integration/proxy/conftest.py +++ b/tests/pytests/integration/proxy/conftest.py @@ -89,7 +89,13 @@ def deltaproxy_pillar_tree(request, salt_master, salt_delta_proxy_factory): 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: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), ( + dummy_proxy_one_tempfile + ), dummy_proxy_two_tempfile, dummy_proxy_three_tempfile, dummy_proxy_four_tempfile: yield diff --git a/tests/pytests/integration/proxy/test_deltaproxy.py b/tests/pytests/integration/proxy/test_deltaproxy.py index 48f23b18d68..c95c43f17bf 100644 --- a/tests/pytests/integration/proxy/test_deltaproxy.py +++ b/tests/pytests/integration/proxy/test_deltaproxy.py @@ -1,6 +1,7 @@ """ Simple Smoke Tests for Connected Proxy Minion """ + import logging import pytest diff --git a/tests/pytests/integration/proxy/test_shell.py b/tests/pytests/integration/proxy/test_shell.py index 44a0e137f75..fec736d7063 100644 --- a/tests/pytests/integration/proxy/test_shell.py +++ b/tests/pytests/integration/proxy/test_shell.py @@ -1,6 +1,7 @@ """ Simple Smoke Tests for Connected Proxy Minion """ + import logging import random diff --git a/tests/pytests/integration/proxy/test_simple.py b/tests/pytests/integration/proxy/test_simple.py index f3d26834ef9..048138e43e5 100644 --- a/tests/pytests/integration/proxy/test_simple.py +++ b/tests/pytests/integration/proxy/test_simple.py @@ -1,6 +1,7 @@ """ Simple Smoke Tests for Connected Proxy Minion """ + import logging import pytest diff --git a/tests/pytests/integration/runners/state/orchestrate/test_events.py b/tests/pytests/integration/runners/state/orchestrate/test_events.py index f1deeb5c6f5..387133b6e40 100644 --- a/tests/pytests/integration/runners/state/orchestrate/test_events.py +++ b/tests/pytests/integration/runners/state/orchestrate/test_events.py @@ -1,6 +1,7 @@ """ Tests for orchestration events """ + import concurrent.futures import functools import json diff --git a/tests/pytests/integration/sdb/test_vault.py b/tests/pytests/integration/sdb/test_vault.py index c70c251c2a9..c4327ef1019 100644 --- a/tests/pytests/integration/sdb/test_vault.py +++ b/tests/pytests/integration/sdb/test_vault.py @@ -1,6 +1,7 @@ """ Integration tests for the vault modules """ + import json import logging import subprocess diff --git a/tests/pytests/integration/ssh/test_log.py b/tests/pytests/integration/ssh/test_log.py index e87c4a8581f..cc851407521 100644 --- a/tests/pytests/integration/ssh/test_log.py +++ b/tests/pytests/integration/ssh/test_log.py @@ -1,6 +1,7 @@ """ Integration tests for salt-ssh logging """ + import logging import time diff --git a/tests/pytests/integration/ssh/test_py_versions.py b/tests/pytests/integration/ssh/test_py_versions.py index 52ab819e808..cacd2ba97cb 100644 --- a/tests/pytests/integration/ssh/test_py_versions.py +++ b/tests/pytests/integration/ssh/test_py_versions.py @@ -1,6 +1,7 @@ """ Integration tests for salt-ssh py_versions """ + import logging import socket import time diff --git a/tests/pytests/integration/ssh/test_ssh_setup.py b/tests/pytests/integration/ssh/test_ssh_setup.py index 00e7e6394ff..2b68f5c4a48 100644 --- a/tests/pytests/integration/ssh/test_ssh_setup.py +++ b/tests/pytests/integration/ssh/test_ssh_setup.py @@ -1,6 +1,7 @@ """ Integration tests for salt-ssh py_versions """ + import logging import os import signal diff --git a/tests/pytests/integration/states/test_beacon.py b/tests/pytests/integration/states/test_beacon.py index 5d6737e6a18..5aefa6ecf2b 100644 --- a/tests/pytests/integration/states/test_beacon.py +++ b/tests/pytests/integration/states/test_beacon.py @@ -1,6 +1,7 @@ """ Integration tests for the beacon states """ + import logging import pytest diff --git a/tests/pytests/integration/states/test_file.py b/tests/pytests/integration/states/test_file.py index 42bdc06baad..31d3a85cde2 100644 --- a/tests/pytests/integration/states/test_file.py +++ b/tests/pytests/integration/states/test_file.py @@ -1,6 +1,7 @@ """ Tests for the file state """ + import logging import os import pathlib @@ -655,7 +656,9 @@ def test_patch_single_file_failure( math_tempfile = pytest.helpers.temp_file(math_file, content[1], tmp_path) reject_tempfile = pytest.helpers.temp_file("reject.txt", "", tmp_path) - with sls_tempfile, sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: + with ( + sls_tempfile + ), sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: # Empty the file to ensure that the patch doesn't apply cleanly with salt.utils.files.fopen(numbers_file, "w"): pass @@ -730,7 +733,9 @@ def test_patch_directory_failure( math_tempfile = pytest.helpers.temp_file(math_file, content[1], tmp_path) reject_tempfile = pytest.helpers.temp_file("reject.txt", "", tmp_path) - with sls_tempfile, sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: + with ( + sls_tempfile + ), sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: # Empty the file to ensure that the patch doesn't apply cleanly with salt.utils.files.fopen(math_file, "w"): pass diff --git a/tests/pytests/integration/states/test_idem.py b/tests/pytests/integration/states/test_idem.py index feab60d4951..afdd9c93637 100644 --- a/tests/pytests/integration/states/test_idem.py +++ b/tests/pytests/integration/states/test_idem.py @@ -1,6 +1,7 @@ """ Tests for the idem state """ + import tempfile from contextlib import contextmanager diff --git a/tests/pytests/integration/states/test_include.py b/tests/pytests/integration/states/test_include.py index f814328c5e4..f4ebe611e39 100644 --- a/tests/pytests/integration/states/test_include.py +++ b/tests/pytests/integration/states/test_include.py @@ -1,6 +1,7 @@ """ Integration tests for the jinja includes in states """ + import logging import pytest diff --git a/tests/pytests/integration/utils/test_templates.py b/tests/pytests/integration/utils/test_templates.py index 241bd8f58d8..0d4ee011d31 100644 --- a/tests/pytests/integration/utils/test_templates.py +++ b/tests/pytests/integration/utils/test_templates.py @@ -1,6 +1,7 @@ """ Tests for the templates utils """ + import os import pytest diff --git a/tests/pytests/pkg/conftest.py b/tests/pytests/pkg/conftest.py index 048ad7a238d..20d71f14228 100644 --- a/tests/pytests/pkg/conftest.py +++ b/tests/pytests/pkg/conftest.py @@ -373,12 +373,12 @@ def salt_minion(salt_factories, salt_master, install_salt): "open_mode": True, } if platform.is_windows(): - config_overrides[ - "winrepo_dir" - ] = rf"{salt_factories.root_dir}\srv\salt\win\repo" - config_overrides[ - "winrepo_dir_ng" - ] = rf"{salt_factories.root_dir}\srv\salt\win\repo_ng" + config_overrides["winrepo_dir"] = ( + rf"{salt_factories.root_dir}\srv\salt\win\repo" + ) + config_overrides["winrepo_dir_ng"] = ( + rf"{salt_factories.root_dir}\srv\salt\win\repo_ng" + ) config_overrides["winrepo_source_dir"] = r"salt://win/repo_ng" if install_salt.classic and platform.is_windows(): diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index 57b1e4c834e..b774d9fa047 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -1,6 +1,7 @@ """ Test Salt Pkg Downloads """ + import contextlib import logging import os diff --git a/tests/pytests/scenarios/blackout/test_minion_blackout.py b/tests/pytests/scenarios/blackout/test_minion_blackout.py index 581ad2b135b..ed5fca72c48 100644 --- a/tests/pytests/scenarios/blackout/test_minion_blackout.py +++ b/tests/pytests/scenarios/blackout/test_minion_blackout.py @@ -2,7 +2,6 @@ Tests for minion blackout """ - import logging import pytest diff --git a/tests/pytests/scenarios/compat/conftest.py b/tests/pytests/scenarios/compat/conftest.py index 29d58354abc..3d7c44381b8 100644 --- a/tests/pytests/scenarios/compat/conftest.py +++ b/tests/pytests/scenarios/compat/conftest.py @@ -4,6 +4,7 @@ Salt Compatibility PyTest Fixtures """ + import logging import os import shutil diff --git a/tests/pytests/scenarios/compat/test_with_versions.py b/tests/pytests/scenarios/compat/test_with_versions.py index ecb3a73de1a..cc61a01f509 100644 --- a/tests/pytests/scenarios/compat/test_with_versions.py +++ b/tests/pytests/scenarios/compat/test_with_versions.py @@ -4,6 +4,7 @@ Test current salt master with older salt minions """ + import logging import pathlib diff --git a/tests/pytests/scenarios/performance/conftest.py b/tests/pytests/scenarios/performance/conftest.py index 13fbb831d7c..ef29cf03973 100644 --- a/tests/pytests/scenarios/performance/conftest.py +++ b/tests/pytests/scenarios/performance/conftest.py @@ -1,6 +1,7 @@ """ Salt performance tests """ + import logging import shutil diff --git a/tests/pytests/scenarios/setup/test_install.py b/tests/pytests/scenarios/setup/test_install.py index 9c506b56cab..5953a9640c5 100644 --- a/tests/pytests/scenarios/setup/test_install.py +++ b/tests/pytests/scenarios/setup/test_install.py @@ -1,6 +1,7 @@ """ Tests for building and installing salt """ + import json import logging import os diff --git a/tests/pytests/unit/auth/test_ldap.py b/tests/pytests/unit/auth/test_ldap.py index fe973701af3..6a43bb350d0 100644 --- a/tests/pytests/unit/auth/test_ldap.py +++ b/tests/pytests/unit/auth/test_ldap.py @@ -1,6 +1,7 @@ """ Unit tests for salt.auth.ldap """ + import pytest import salt.auth.ldap diff --git a/tests/pytests/unit/beacons/test_adb.py b/tests/pytests/unit/beacons/test_adb.py index 0d9ee99ee6a..945e782093b 100644 --- a/tests/pytests/unit/beacons/test_adb.py +++ b/tests/pytests/unit/beacons/test_adb.py @@ -4,6 +4,7 @@ ADB beacon test cases """ + import pytest import salt.beacons.adb as adb diff --git a/tests/pytests/unit/beacons/test_avahi_announce.py b/tests/pytests/unit/beacons/test_avahi_announce.py index 2eb95a35a2f..bd7359dcd58 100644 --- a/tests/pytests/unit/beacons/test_avahi_announce.py +++ b/tests/pytests/unit/beacons/test_avahi_announce.py @@ -4,6 +4,7 @@ Avahi announce beacon test cases """ + import pytest import salt.beacons.avahi_announce as avahi_announce diff --git a/tests/pytests/unit/beacons/test_bonjour_announce.py b/tests/pytests/unit/beacons/test_bonjour_announce.py index c5551edebfd..25df0ffbd13 100644 --- a/tests/pytests/unit/beacons/test_bonjour_announce.py +++ b/tests/pytests/unit/beacons/test_bonjour_announce.py @@ -4,6 +4,7 @@ Bonjour announce beacon test cases """ + import pytest import salt.beacons.bonjour_announce as bonjour_announce diff --git a/tests/pytests/unit/beacons/test_diskusage.py b/tests/pytests/unit/beacons/test_diskusage.py index e37863cd733..94fff2fa918 100644 --- a/tests/pytests/unit/beacons/test_diskusage.py +++ b/tests/pytests/unit/beacons/test_diskusage.py @@ -4,6 +4,7 @@ Disk usage beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_glxinfo.py b/tests/pytests/unit/beacons/test_glxinfo.py index b556c2cafa9..4888c6301d2 100644 --- a/tests/pytests/unit/beacons/test_glxinfo.py +++ b/tests/pytests/unit/beacons/test_glxinfo.py @@ -4,6 +4,7 @@ glxinfo beacon test cases """ + import pytest import salt.beacons.glxinfo as glxinfo diff --git a/tests/pytests/unit/beacons/test_haproxy.py b/tests/pytests/unit/beacons/test_haproxy.py index 33197cb1414..dc0c961d547 100644 --- a/tests/pytests/unit/beacons/test_haproxy.py +++ b/tests/pytests/unit/beacons/test_haproxy.py @@ -4,6 +4,7 @@ HAProxy beacon test cases """ + import pytest import salt.beacons.haproxy as haproxy diff --git a/tests/pytests/unit/beacons/test_load.py b/tests/pytests/unit/beacons/test_load.py index a0a28428e4b..0f57465cfe3 100644 --- a/tests/pytests/unit/beacons/test_load.py +++ b/tests/pytests/unit/beacons/test_load.py @@ -4,6 +4,7 @@ Load beacon test cases """ + import pytest import salt.beacons.load as load diff --git a/tests/pytests/unit/beacons/test_log_beacon.py b/tests/pytests/unit/beacons/test_log_beacon.py index f0dc61865cb..18184936d9d 100644 --- a/tests/pytests/unit/beacons/test_log_beacon.py +++ b/tests/pytests/unit/beacons/test_log_beacon.py @@ -4,6 +4,7 @@ log beacon test cases """ + import pytest import salt.beacons.log_beacon as log_beacon diff --git a/tests/pytests/unit/beacons/test_memusage.py b/tests/pytests/unit/beacons/test_memusage.py index bab3d5321e2..6f172c9c1d8 100644 --- a/tests/pytests/unit/beacons/test_memusage.py +++ b/tests/pytests/unit/beacons/test_memusage.py @@ -4,6 +4,7 @@ Memory usage beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_network_info.py b/tests/pytests/unit/beacons/test_network_info.py index ee48fc57905..0e80637f7d7 100644 --- a/tests/pytests/unit/beacons/test_network_info.py +++ b/tests/pytests/unit/beacons/test_network_info.py @@ -4,6 +4,7 @@ Network info beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_ps.py b/tests/pytests/unit/beacons/test_ps.py index 55d448ae78a..aa869dc4535 100644 --- a/tests/pytests/unit/beacons/test_ps.py +++ b/tests/pytests/unit/beacons/test_ps.py @@ -4,6 +4,7 @@ ps usage beacon test cases """ + import pytest import salt.beacons.ps as ps diff --git a/tests/pytests/unit/beacons/test_swapusage.py b/tests/pytests/unit/beacons/test_swapusage.py index 5ffed290bf8..39070ce49bf 100644 --- a/tests/pytests/unit/beacons/test_swapusage.py +++ b/tests/pytests/unit/beacons/test_swapusage.py @@ -4,6 +4,7 @@ Swap usage beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/cache/test_localfs.py b/tests/pytests/unit/cache/test_localfs.py index cda71066368..e5f7c6cc30b 100644 --- a/tests/pytests/unit/cache/test_localfs.py +++ b/tests/pytests/unit/cache/test_localfs.py @@ -1,6 +1,7 @@ """ Validate the functions in the localfs cache """ + import errno import shutil diff --git a/tests/pytests/unit/cache/test_memcache.py b/tests/pytests/unit/cache/test_memcache.py index d8a074c5c35..7a1d9374335 100644 --- a/tests/pytests/unit/cache/test_memcache.py +++ b/tests/pytests/unit/cache/test_memcache.py @@ -1,6 +1,7 @@ """ Validate Cache class methods """ + import pytest import salt.cache diff --git a/tests/pytests/unit/cache/test_mysql_cache.py b/tests/pytests/unit/cache/test_mysql_cache.py index c74f44d4310..11959279695 100644 --- a/tests/pytests/unit/cache/test_mysql_cache.py +++ b/tests/pytests/unit/cache/test_mysql_cache.py @@ -2,7 +2,6 @@ unit tests for the mysql_cache cache """ - import logging import pytest diff --git a/tests/pytests/unit/cloud/clouds/test_azurearm.py b/tests/pytests/unit/cloud/clouds/test_azurearm.py index d84aeeffd65..699a94981dd 100644 --- a/tests/pytests/unit/cloud/clouds/test_azurearm.py +++ b/tests/pytests/unit/cloud/clouds/test_azurearm.py @@ -66,15 +66,15 @@ def test_function_signatures(): mock_azure.salt.utils.cloud.gen_keys.return_value = [MagicMock(), MagicMock()] mock_azure.__opts__["pki_dir"] = None - mock_azure.request_instance.__globals__[ - "__builtins__" - ] = mock_azure.request_instance.__globals__["__builtins__"].copy() + mock_azure.request_instance.__globals__["__builtins__"] = ( + mock_azure.request_instance.__globals__["__builtins__"].copy() + ) mock_azure.request_instance.__globals__["__builtins__"]["getattr"] = MagicMock() mock_azure.__utils__["cloud.fire_event"] = mock_azure.salt.utils.cloud.fire_event - mock_azure.__utils__[ - "cloud.filter_event" - ] = mock_azure.salt.utils.cloud.filter_event + mock_azure.__utils__["cloud.filter_event"] = ( + mock_azure.salt.utils.cloud.filter_event + ) mock_azure.__opts__["sock_dir"] = MagicMock() mock_azure.__opts__["transport"] = MagicMock() diff --git a/tests/pytests/unit/cloud/clouds/test_digitalocean.py b/tests/pytests/unit/cloud/clouds/test_digitalocean.py index 576264864d1..ec949457364 100644 --- a/tests/pytests/unit/cloud/clouds/test_digitalocean.py +++ b/tests/pytests/unit/cloud/clouds/test_digitalocean.py @@ -5,7 +5,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import pytest diff --git a/tests/pytests/unit/cloud/clouds/test_hetzner.py b/tests/pytests/unit/cloud/clouds/test_hetzner.py index cfe5bb4e85e..c423d83dbca 100644 --- a/tests/pytests/unit/cloud/clouds/test_hetzner.py +++ b/tests/pytests/unit/cloud/clouds/test_hetzner.py @@ -490,9 +490,9 @@ def test_destroy(): connect.return_value.servers.get_by_name.return_value = None hetzner.destroy("myvm", "action") - server = ( - connect.return_value.servers.get_by_name.return_value - ) = MagicMock() + server = connect.return_value.servers.get_by_name.return_value = ( + MagicMock() + ) # Stop the server before shutdown but failed hetzner.destroy("myvm", "action") @@ -531,9 +531,9 @@ def test_resize(): hetzner.resize("myvm", kwargs, "action") - server = ( - connect.return_value.servers.get_by_name.return_value - ) = MagicMock() + server = connect.return_value.servers.get_by_name.return_value = ( + MagicMock() + ) # Invalid server size with pytest.raises(SaltCloudException): diff --git a/tests/pytests/unit/cloud/clouds/test_saltify.py b/tests/pytests/unit/cloud/clouds/test_saltify.py index 8dd0359185a..851c05d0f80 100644 --- a/tests/pytests/unit/cloud/clouds/test_saltify.py +++ b/tests/pytests/unit/cloud/clouds/test_saltify.py @@ -1,6 +1,7 @@ """ :codeauthor: Alexander Schwartz """ + import pytest import salt.client diff --git a/tests/pytests/unit/cloud/clouds/test_vultrpy.py b/tests/pytests/unit/cloud/clouds/test_vultrpy.py index a388ba7f2a5..2945588280d 100644 --- a/tests/pytests/unit/cloud/clouds/test_vultrpy.py +++ b/tests/pytests/unit/cloud/clouds/test_vultrpy.py @@ -96,7 +96,9 @@ def test_create_firewall_ssh(): patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with ( + patch_scripts + ), patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: vultr.create(kwargs) query_ret = mock_query.call_args.kwargs["data"] assert "SSHKEYID=key1%2Ckey2%2Ckey3" in query_ret @@ -143,7 +145,9 @@ def test_create_firewall_doesnotexist(caplog): patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with ( + patch_scripts + ), patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: with caplog.at_level(logging.INFO): ret = vultr.create(kwargs) assert ( @@ -193,7 +197,9 @@ def test_create_ssh_key_ids_doesnotexist(caplog): patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with ( + patch_scripts + ), patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: with caplog.at_level(logging.INFO): ret = vultr.create(kwargs) assert ( diff --git a/tests/pytests/unit/config/test__validate_opts.py b/tests/pytests/unit/config/test__validate_opts.py index 741631e6f81..f07a60c3c1f 100644 --- a/tests/pytests/unit/config/test__validate_opts.py +++ b/tests/pytests/unit/config/test__validate_opts.py @@ -1,6 +1,7 @@ """ Test config option type enforcement """ + import pytest import salt.config diff --git a/tests/pytests/unit/engines/test_libvirt_events.py b/tests/pytests/unit/engines/test_libvirt_events.py index 382ec311732..a83a1948fac 100644 --- a/tests/pytests/unit/engines/test_libvirt_events.py +++ b/tests/pytests/unit/engines/test_libvirt_events.py @@ -1,6 +1,7 @@ """ unit tests for the libvirt_events engine """ + import pytest import salt.engines.libvirt_events as libvirt_events diff --git a/tests/pytests/unit/engines/test_slack.py b/tests/pytests/unit/engines/test_slack.py index c375e903b7b..b3269a6f2a5 100644 --- a/tests/pytests/unit/engines/test_slack.py +++ b/tests/pytests/unit/engines/test_slack.py @@ -1,6 +1,7 @@ """ unit tests for the slack engine """ + import pytest import salt.engines.slack as slack diff --git a/tests/pytests/unit/engines/test_slack_bolt_engine.py b/tests/pytests/unit/engines/test_slack_bolt_engine.py index e537a859550..1d2e30a045b 100644 --- a/tests/pytests/unit/engines/test_slack_bolt_engine.py +++ b/tests/pytests/unit/engines/test_slack_bolt_engine.py @@ -1,6 +1,7 @@ """ unit tests for the slack engine """ + import pytest import salt.engines.slack_bolt_engine as slack_bolt_engine @@ -327,7 +328,13 @@ def test_run_commands_from_slack_async(slack_client): # # test with control as True and fire_all as False # - with patch_slack_client_run_until, patch_slack_client_run_command_async, patch_slack_client_get_jobs_from_runner, patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: + with ( + patch_slack_client_run_until + ), ( + patch_slack_client_run_command_async + ), ( + patch_slack_client_get_jobs_from_runner + ), patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: slack_client.run_commands_from_slack_async( message_generator=message_generator, fire_all=False, @@ -389,7 +396,15 @@ def test_run_commands_from_slack_async(slack_client): }, ) ] - with patch_slack_client_run_until, patch_slack_client_run_command_async, patch_slack_client_get_jobs_from_runner, patch_event_send, patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: + with ( + patch_slack_client_run_until + ), ( + patch_slack_client_run_command_async + ), ( + patch_slack_client_get_jobs_from_runner + ), ( + patch_event_send + ), patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: slack_client.run_commands_from_slack_async( message_generator=message_generator, fire_all=True, @@ -509,6 +524,8 @@ def test_run_command_async(slack_client): }, ) ] - with patch_runner_client, patch_runner_client_asynchronous as runner_client_asynchronous: + with ( + patch_runner_client + ), patch_runner_client_asynchronous as runner_client_asynchronous: ret = slack_client.run_command_async(msg) runner_client_asynchronous.assert_has_calls(expected_calls) diff --git a/tests/pytests/unit/engines/test_sqs_events.py b/tests/pytests/unit/engines/test_sqs_events.py index 894d1d6f652..28fb75f8f89 100644 --- a/tests/pytests/unit/engines/test_sqs_events.py +++ b/tests/pytests/unit/engines/test_sqs_events.py @@ -1,6 +1,7 @@ """ unit tests for the sqs_events engine """ + import pytest import salt.engines.sqs_events as sqs_events diff --git a/tests/pytests/unit/fileclient/test_fileclient.py b/tests/pytests/unit/fileclient/test_fileclient.py index cbdbd763313..b9acd173c5e 100644 --- a/tests/pytests/unit/fileclient/test_fileclient.py +++ b/tests/pytests/unit/fileclient/test_fileclient.py @@ -1,6 +1,7 @@ """ Tests for the salt fileclient """ + import errno import logging import os diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py index a87451af336..af6f721f843 100644 --- a/tests/pytests/unit/grains/test_core.py +++ b/tests/pytests/unit/grains/test_core.py @@ -1780,9 +1780,9 @@ def test_lxc_virtual(): os.path, "isfile", MagicMock( - side_effect=lambda x: True - if x in ("/proc/1/cgroup", "/proc/1/environ") - else False + side_effect=lambda x: ( + True if x in ("/proc/1/cgroup", "/proc/1/environ") else False + ) ), ), patch("salt.utils.files.fopen", mock_open(read_data=file_contents)), patch.dict( core.__salt__, {"cmd.run_all": MagicMock()} @@ -1828,9 +1828,11 @@ def test_container_inside_virtual_machine(): os.path, "isfile", MagicMock( - side_effect=lambda x: True - if x in ("/proc/cpuinfo", "/proc/1/cgroup", "/proc/1/environ") - else False + side_effect=lambda x: ( + True + if x in ("/proc/cpuinfo", "/proc/1/cgroup", "/proc/1/environ") + else False + ) ), ), patch("salt.utils.files.fopen", mock_open(read_data=file_contents)), patch.dict( core.__salt__, {"cmd.run_all": MagicMock()} @@ -3603,8 +3605,8 @@ def test_linux_devicetree_data(test_input, expected): raise FileNotFoundError() m = MagicMock() - m.__enter__.return_value.read = ( - lambda: test_input.get(filename) # pylint: disable=W0640 + m.__enter__.return_value.read = lambda: ( + test_input.get(filename) # pylint: disable=W0640 if filename in test_input # pylint: disable=W0640 else _raise_fnfe() ) diff --git a/tests/pytests/unit/grains/test_esxi.py b/tests/pytests/unit/grains/test_esxi.py index 29be04bc56e..e158b2b3843 100644 --- a/tests/pytests/unit/grains/test_esxi.py +++ b/tests/pytests/unit/grains/test_esxi.py @@ -4,7 +4,6 @@ :codeauthor: :email:`Gareth J. Greenaway ` """ - import logging import pytest diff --git a/tests/pytests/unit/loader/test_context.py b/tests/pytests/unit/loader/test_context.py index 9815f443f25..64b36411f4b 100644 --- a/tests/pytests/unit/loader/test_context.py +++ b/tests/pytests/unit/loader/test_context.py @@ -1,6 +1,7 @@ """ Tests for salt.loader.context """ + import copy import salt.loader.context diff --git a/tests/pytests/unit/loader/test_lazy.py b/tests/pytests/unit/loader/test_lazy.py index 571f458b360..8e461b454b4 100644 --- a/tests/pytests/unit/loader/test_lazy.py +++ b/tests/pytests/unit/loader/test_lazy.py @@ -1,6 +1,7 @@ """ Tests for salt.loader.lazy """ + import sys import pytest diff --git a/tests/pytests/unit/loader/test_loader.py b/tests/pytests/unit/loader/test_loader.py index 3c26b435c8c..e7359c6a74a 100644 --- a/tests/pytests/unit/loader/test_loader.py +++ b/tests/pytests/unit/loader/test_loader.py @@ -4,6 +4,7 @@ tests.pytests.unit.loader.test_loader Unit tests for salt's loader """ + import os import shutil import textwrap diff --git a/tests/pytests/unit/log_handlers/test_sentry_mod.py b/tests/pytests/unit/log_handlers/test_sentry_mod.py index 4c2d174b710..e011719ca84 100644 --- a/tests/pytests/unit/log_handlers/test_sentry_mod.py +++ b/tests/pytests/unit/log_handlers/test_sentry_mod.py @@ -1,6 +1,7 @@ """ Tests for salt.log_handlers.sentry_mod """ + import pytest import salt.log_handlers.sentry_mod diff --git a/tests/pytests/unit/modules/file/test_file_line.py b/tests/pytests/unit/modules/file/test_file_line.py index 5c2e444617e..4099d61b845 100644 --- a/tests/pytests/unit/modules/file/test_file_line.py +++ b/tests/pytests/unit/modules/file/test_file_line.py @@ -1588,7 +1588,7 @@ def test_line_insert_ensure_beforeafter_twolines(tempfile_name, get_body): isfile_mock = MagicMock( side_effect=lambda x: True if x == tempfile_name else DEFAULT ) - for (_after, _before) in [(after, before), ("NAME_.*", "SKEL_.*")]: + for _after, _before in [(after, before), ("NAME_.*", "SKEL_.*")]: with patch("os.path.isfile", isfile_mock), patch( "os.stat", MagicMock(return_value=DummyStat()) ), patch("salt.utils.files.fopen", mock_open(read_data=file_content)), patch( @@ -1640,7 +1640,7 @@ def test_line_insert_ensure_beforeafter_twolines_exists(tempfile_name): isfile_mock = MagicMock( side_effect=lambda x: True if x == tempfile_name else DEFAULT ) - for (_after, _before) in [(after, before), ("NAME_.*", "SKEL_.*")]: + for _after, _before in [(after, before), ("NAME_.*", "SKEL_.*")]: with patch("os.path.isfile", isfile_mock), patch( "os.stat", MagicMock(return_value=DummyStat()) ), patch("salt.utils.files.fopen", mock_open(read_data=file_content)), patch( @@ -1677,7 +1677,7 @@ def test_line_insert_ensure_beforeafter_rangelines(): file_content.split(os.linesep)[0], file_content.split(os.linesep)[-1], ) - for (_after, _before) in [(after, before), ("NAME_.*", "SKEL_.*")]: + for _after, _before in [(after, before), ("NAME_.*", "SKEL_.*")]: with patch("os.path.realpath", MagicMock(wraps=lambda x: x)), patch( "os.path.isfile", MagicMock(return_value=True) ), patch("os.stat", MagicMock()), patch( diff --git a/tests/pytests/unit/modules/napalm/test_bgp.py b/tests/pytests/unit/modules/napalm/test_bgp.py index e9dcb21ecf5..48a7105342d 100644 --- a/tests/pytests/unit/modules/napalm/test_bgp.py +++ b/tests/pytests/unit/modules/napalm/test_bgp.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import pytest import salt.modules.napalm_bgp as napalm_bgp diff --git a/tests/pytests/unit/modules/napalm/test_mod.py b/tests/pytests/unit/modules/napalm/test_mod.py index 306a9840a46..5b693c2de2a 100644 --- a/tests/pytests/unit/modules/napalm/test_mod.py +++ b/tests/pytests/unit/modules/napalm/test_mod.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`David Murphy ` """ + import logging import pytest diff --git a/tests/pytests/unit/modules/napalm/test_network.py b/tests/pytests/unit/modules/napalm/test_network.py index 4dfaf8af447..2ce2d6e621b 100644 --- a/tests/pytests/unit/modules/napalm/test_network.py +++ b/tests/pytests/unit/modules/napalm/test_network.py @@ -2,7 +2,6 @@ :codeauthor: Anthony Shaw """ - import pytest import salt.modules.napalm_network as napalm_network diff --git a/tests/pytests/unit/modules/napalm/test_snmp.py b/tests/pytests/unit/modules/napalm/test_snmp.py index 67d25850f3a..5166372ca68 100644 --- a/tests/pytests/unit/modules/napalm/test_snmp.py +++ b/tests/pytests/unit/modules/napalm/test_snmp.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import pytest import salt.modules.napalm_network as napalm_network diff --git a/tests/pytests/unit/modules/napalm/test_users.py b/tests/pytests/unit/modules/napalm/test_users.py index b76010e76f1..f55a649aa7b 100644 --- a/tests/pytests/unit/modules/napalm/test_users.py +++ b/tests/pytests/unit/modules/napalm/test_users.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import pytest import salt.modules.napalm_network as napalm_network diff --git a/tests/pytests/unit/modules/test_acme.py b/tests/pytests/unit/modules/test_acme.py index 2d7aa6d2883..aa56dc59813 100644 --- a/tests/pytests/unit/modules/test_acme.py +++ b/tests/pytests/unit/modules/test_acme.py @@ -2,7 +2,6 @@ :codeauthor: Herbert Buurman """ - import datetime import os import textwrap diff --git a/tests/pytests/unit/modules/test_at.py b/tests/pytests/unit/modules/test_at.py index 0a44d83beea..da5be7f4b0e 100644 --- a/tests/pytests/unit/modules/test_at.py +++ b/tests/pytests/unit/modules/test_at.py @@ -4,7 +4,6 @@ TestCase for the salt.modules.at module """ - import pytest import salt.modules.at as at diff --git a/tests/pytests/unit/modules/test_augeas_cfg.py b/tests/pytests/unit/modules/test_augeas_cfg.py index 0720b6b25b9..dd197555665 100644 --- a/tests/pytests/unit/modules/test_augeas_cfg.py +++ b/tests/pytests/unit/modules/test_augeas_cfg.py @@ -3,6 +3,7 @@ Test cases for salt.modules.augeas_cfg """ + import pytest import salt.modules.augeas_cfg as augeas_cfg diff --git a/tests/pytests/unit/modules/test_bigip.py b/tests/pytests/unit/modules/test_bigip.py index 3e24ad9df4a..2fc8cb44c50 100644 --- a/tests/pytests/unit/modules/test_bigip.py +++ b/tests/pytests/unit/modules/test_bigip.py @@ -4,6 +4,7 @@ tests.unit.modules.test_bigip Unit tests for the bigip module """ + import logging import pytest diff --git a/tests/pytests/unit/modules/test_bluez_bluetooth.py b/tests/pytests/unit/modules/test_bluez_bluetooth.py index e7b832e613f..d3bab5ba043 100644 --- a/tests/pytests/unit/modules/test_bluez_bluetooth.py +++ b/tests/pytests/unit/modules/test_bluez_bluetooth.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.modules.bluez_bluetooth as bluez diff --git a/tests/pytests/unit/modules/test_boto_dynamodb.py b/tests/pytests/unit/modules/test_boto_dynamodb.py index f5b983e13f0..0a2fe186a1c 100644 --- a/tests/pytests/unit/modules/test_boto_dynamodb.py +++ b/tests/pytests/unit/modules/test_boto_dynamodb.py @@ -2,7 +2,6 @@ Test cases for salt.modules.boto_dynamodb """ - import pytest import salt.modules.boto_dynamodb as boto_dynamodb diff --git a/tests/pytests/unit/modules/test_bower.py b/tests/pytests/unit/modules/test_bower.py index df33182ab1a..537fb08fbaa 100644 --- a/tests/pytests/unit/modules/test_bower.py +++ b/tests/pytests/unit/modules/test_bower.py @@ -2,7 +2,6 @@ :codeauthor: Alexander Pyatkin """ - import pytest import salt.modules.bower as bower diff --git a/tests/pytests/unit/modules/test_bridge.py b/tests/pytests/unit/modules/test_bridge.py index f68ffbce2d7..7595e4263ee 100644 --- a/tests/pytests/unit/modules/test_bridge.py +++ b/tests/pytests/unit/modules/test_bridge.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.bridge as bridge diff --git a/tests/pytests/unit/modules/test_cassandra_cql.py b/tests/pytests/unit/modules/test_cassandra_cql.py index 6b39d2f0cc4..b50a101e416 100644 --- a/tests/pytests/unit/modules/test_cassandra_cql.py +++ b/tests/pytests/unit/modules/test_cassandra_cql.py @@ -2,7 +2,6 @@ Test case for the cassandra_cql module """ - import logging import ssl diff --git a/tests/pytests/unit/modules/test_chocolatey.py b/tests/pytests/unit/modules/test_chocolatey.py index ac2c7341045..8dd630793f1 100644 --- a/tests/pytests/unit/modules/test_chocolatey.py +++ b/tests/pytests/unit/modules/test_chocolatey.py @@ -1,6 +1,7 @@ """ Test for the chocolatey module """ + import os import pytest diff --git a/tests/pytests/unit/modules/test_composer.py b/tests/pytests/unit/modules/test_composer.py index 74d828aee6a..c0f5f552f2a 100644 --- a/tests/pytests/unit/modules/test_composer.py +++ b/tests/pytests/unit/modules/test_composer.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.composer as composer diff --git a/tests/pytests/unit/modules/test_config.py b/tests/pytests/unit/modules/test_config.py index c522dc7897c..122d41b9291 100644 --- a/tests/pytests/unit/modules/test_config.py +++ b/tests/pytests/unit/modules/test_config.py @@ -2,7 +2,6 @@ Test cases for salt.modules.config """ - import fnmatch import pytest diff --git a/tests/pytests/unit/modules/test_consul.py b/tests/pytests/unit/modules/test_consul.py index 52f1c8ece2e..59c07ff43da 100644 --- a/tests/pytests/unit/modules/test_consul.py +++ b/tests/pytests/unit/modules/test_consul.py @@ -2,7 +2,6 @@ Test case for the consul execution module """ - import logging import pytest diff --git a/tests/pytests/unit/modules/test_cp.py b/tests/pytests/unit/modules/test_cp.py index 6700832e345..2e626e5da45 100644 --- a/tests/pytests/unit/modules/test_cp.py +++ b/tests/pytests/unit/modules/test_cp.py @@ -2,7 +2,6 @@ :codeauthor: jmoney """ - import pytest import salt.channel.client diff --git a/tests/pytests/unit/modules/test_daemontools.py b/tests/pytests/unit/modules/test_daemontools.py index 3a5e51fcba4..a5cbed24568 100644 --- a/tests/pytests/unit/modules/test_daemontools.py +++ b/tests/pytests/unit/modules/test_daemontools.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_data.py b/tests/pytests/unit/modules/test_data.py index 02a91c36a14..4a575a19dd9 100644 --- a/tests/pytests/unit/modules/test_data.py +++ b/tests/pytests/unit/modules/test_data.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.data as data diff --git a/tests/pytests/unit/modules/test_deb_apache.py b/tests/pytests/unit/modules/test_deb_apache.py index 1608321f107..d78f17c5d60 100644 --- a/tests/pytests/unit/modules/test_deb_apache.py +++ b/tests/pytests/unit/modules/test_deb_apache.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.deb_apache as deb_apache diff --git a/tests/pytests/unit/modules/test_devmap.py b/tests/pytests/unit/modules/test_devmap.py index f7fc9f09ea1..405eccac1b4 100644 --- a/tests/pytests/unit/modules/test_devmap.py +++ b/tests/pytests/unit/modules/test_devmap.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import os.path import pytest diff --git a/tests/pytests/unit/modules/test_dig.py b/tests/pytests/unit/modules/test_dig.py index dcc0acc8295..0d39a20e73c 100644 --- a/tests/pytests/unit/modules/test_dig.py +++ b/tests/pytests/unit/modules/test_dig.py @@ -2,7 +2,6 @@ Test cases for salt.modules.dig """ - import pytest import salt.modules.dig as dig diff --git a/tests/pytests/unit/modules/test_disk.py b/tests/pytests/unit/modules/test_disk.py index 58d8cbc305c..33bee16deaa 100644 --- a/tests/pytests/unit/modules/test_disk.py +++ b/tests/pytests/unit/modules/test_disk.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.disk as disk diff --git a/tests/pytests/unit/modules/test_djangomod.py b/tests/pytests/unit/modules/test_djangomod.py index f3a22dd8052..f3fb1ed884e 100644 --- a/tests/pytests/unit/modules/test_djangomod.py +++ b/tests/pytests/unit/modules/test_djangomod.py @@ -3,6 +3,7 @@ Test cases for salt.modules.djangomod """ + import pytest import salt.modules.djangomod as djangomod diff --git a/tests/pytests/unit/modules/test_dpkg_lowpkg.py b/tests/pytests/unit/modules/test_dpkg_lowpkg.py index 41bd615ff29..625015b7590 100644 --- a/tests/pytests/unit/modules/test_dpkg_lowpkg.py +++ b/tests/pytests/unit/modules/test_dpkg_lowpkg.py @@ -4,7 +4,6 @@ Test cases for salt.modules.dpkg """ - import logging import os diff --git a/tests/pytests/unit/modules/test_drac.py b/tests/pytests/unit/modules/test_drac.py index 2a8da5a23f6..9d684797e0c 100644 --- a/tests/pytests/unit/modules/test_drac.py +++ b/tests/pytests/unit/modules/test_drac.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.drac as drac diff --git a/tests/pytests/unit/modules/test_drbd.py b/tests/pytests/unit/modules/test_drbd.py index ce9625c2d0c..c4686093a5a 100644 --- a/tests/pytests/unit/modules/test_drbd.py +++ b/tests/pytests/unit/modules/test_drbd.py @@ -4,7 +4,6 @@ Test cases for salt.modules.drbd """ - import pytest import salt.modules.drbd as drbd diff --git a/tests/pytests/unit/modules/test_etcd_mod.py b/tests/pytests/unit/modules/test_etcd_mod.py index 1c43772524d..d4b26a8486f 100644 --- a/tests/pytests/unit/modules/test_etcd_mod.py +++ b/tests/pytests/unit/modules/test_etcd_mod.py @@ -9,7 +9,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.etcd_mod as etcd_mod diff --git a/tests/pytests/unit/modules/test_extfs.py b/tests/pytests/unit/modules/test_extfs.py index c4ab8d3bc6b..bef0e35bfea 100644 --- a/tests/pytests/unit/modules/test_extfs.py +++ b/tests/pytests/unit/modules/test_extfs.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.extfs as extfs diff --git a/tests/pytests/unit/modules/test_genesis.py b/tests/pytests/unit/modules/test_genesis.py index 0a2100f4848..2fd7f091006 100644 --- a/tests/pytests/unit/modules/test_genesis.py +++ b/tests/pytests/unit/modules/test_genesis.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import sys import pytest diff --git a/tests/pytests/unit/modules/test_gentoo_service.py b/tests/pytests/unit/modules/test_gentoo_service.py index 1d7e8eca7f9..31df975cb53 100644 --- a/tests/pytests/unit/modules/test_gentoo_service.py +++ b/tests/pytests/unit/modules/test_gentoo_service.py @@ -2,7 +2,6 @@ Test cases for salt.modules.gentoo_service """ - import pytest import salt.modules.gentoo_service as gentoo_service diff --git a/tests/pytests/unit/modules/test_git.py b/tests/pytests/unit/modules/test_git.py index 9d7c9ae9fc7..4da79b7bd55 100644 --- a/tests/pytests/unit/modules/test_git.py +++ b/tests/pytests/unit/modules/test_git.py @@ -2,7 +2,6 @@ :codeauthor: Erik Johnson """ - import copy import logging import os @@ -88,9 +87,11 @@ def test_list_worktrees(worktree_info, worktree_root): return "worktree {}\nHEAD {}\n{}\n".format( path, worktree_info[path]["HEAD"], - "branch {}".format(worktree_info[path]["branch"]) - if worktree_info[path]["branch"] != "detached" - else "detached", + ( + "branch {}".format(worktree_info[path]["branch"]) + if worktree_info[path]["branch"] != "detached" + else "detached" + ), ) # Build dict for _cmd_run_side_effect below. Start with the output from diff --git a/tests/pytests/unit/modules/test_glassfish.py b/tests/pytests/unit/modules/test_glassfish.py index e6e22b3a696..fa0022f5fe6 100644 --- a/tests/pytests/unit/modules/test_glassfish.py +++ b/tests/pytests/unit/modules/test_glassfish.py @@ -4,6 +4,7 @@ tests.unit.modules.test_glassfish Unit tests for the glassfish module """ + import logging import pytest diff --git a/tests/pytests/unit/modules/test_glusterfs.py b/tests/pytests/unit/modules/test_glusterfs.py index 2816a18ffd3..79d61c3e2ba 100644 --- a/tests/pytests/unit/modules/test_glusterfs.py +++ b/tests/pytests/unit/modules/test_glusterfs.py @@ -5,7 +5,6 @@ Test cases for salt.modules.glusterfs """ - import pytest import salt.modules.glusterfs as glusterfs diff --git a/tests/pytests/unit/modules/test_grub_legacy.py b/tests/pytests/unit/modules/test_grub_legacy.py index 47ec919939c..4d0feae6f4b 100644 --- a/tests/pytests/unit/modules/test_grub_legacy.py +++ b/tests/pytests/unit/modules/test_grub_legacy.py @@ -4,7 +4,6 @@ Test cases for salt.modules.grub_legacy """ - import errno import pytest diff --git a/tests/pytests/unit/modules/test_hadoop.py b/tests/pytests/unit/modules/test_hadoop.py index 37416403274..fad51b9b6e6 100644 --- a/tests/pytests/unit/modules/test_hadoop.py +++ b/tests/pytests/unit/modules/test_hadoop.py @@ -4,7 +4,6 @@ Test cases for salt.modules.hadoop """ - import pytest import salt.modules.hadoop as hadoop diff --git a/tests/pytests/unit/modules/test_haproxyconn.py b/tests/pytests/unit/modules/test_haproxyconn.py index 7834818fbea..51d39fc7d3b 100644 --- a/tests/pytests/unit/modules/test_haproxyconn.py +++ b/tests/pytests/unit/modules/test_haproxyconn.py @@ -4,7 +4,6 @@ Test cases for salt.modules.haproxyconn """ - import pytest import salt.modules.haproxyconn as haproxyconn diff --git a/tests/pytests/unit/modules/test_hashutil.py b/tests/pytests/unit/modules/test_hashutil.py index 57a237bad66..cf1527e624e 100644 --- a/tests/pytests/unit/modules/test_hashutil.py +++ b/tests/pytests/unit/modules/test_hashutil.py @@ -2,7 +2,6 @@ Test cases for salt.modules.hashutil """ - import pytest import salt.modules.hashutil as hashutil diff --git a/tests/pytests/unit/modules/test_helm.py b/tests/pytests/unit/modules/test_helm.py index 8286f4af27a..776ed45734e 100644 --- a/tests/pytests/unit/modules/test_helm.py +++ b/tests/pytests/unit/modules/test_helm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.helm """ - import pytest import salt.modules.helm as helm diff --git a/tests/pytests/unit/modules/test_hg.py b/tests/pytests/unit/modules/test_hg.py index 5d31217b76d..723bf5044d9 100644 --- a/tests/pytests/unit/modules/test_hg.py +++ b/tests/pytests/unit/modules/test_hg.py @@ -4,7 +4,6 @@ Test cases for salt.modules.hg """ - import pytest import salt.modules.hg as hg diff --git a/tests/pytests/unit/modules/test_http.py b/tests/pytests/unit/modules/test_http.py index 7e2c33dc4c6..16aa8a72a99 100644 --- a/tests/pytests/unit/modules/test_http.py +++ b/tests/pytests/unit/modules/test_http.py @@ -4,7 +4,6 @@ Test cases for salt.modules.http """ - import pytest import salt.modules.http as http diff --git a/tests/pytests/unit/modules/test_ilo.py b/tests/pytests/unit/modules/test_ilo.py index 0df13c8be7d..3328856e577 100644 --- a/tests/pytests/unit/modules/test_ilo.py +++ b/tests/pytests/unit/modules/test_ilo.py @@ -4,7 +4,6 @@ Test cases for salt.modules.ilo """ - import tempfile import pytest diff --git a/tests/pytests/unit/modules/test_incron.py b/tests/pytests/unit/modules/test_incron.py index 9f241d570f1..cae619a6968 100644 --- a/tests/pytests/unit/modules/test_incron.py +++ b/tests/pytests/unit/modules/test_incron.py @@ -4,7 +4,6 @@ Test cases for salt.modules.incron """ - import pytest import salt.modules.incron as incron diff --git a/tests/pytests/unit/modules/test_ini_manage.py b/tests/pytests/unit/modules/test_ini_manage.py index 538e75c171b..5074f026860 100644 --- a/tests/pytests/unit/modules/test_ini_manage.py +++ b/tests/pytests/unit/modules/test_ini_manage.py @@ -437,9 +437,7 @@ def test_unicode_set_option(encoding, linesep, ini_file, unicode_content): assert ini.get_option(str(ini_file), "Ascii", "ay", encoding=encoding) == "Aymar" # Check new section and option added - assert ( - ini.get_option(str(ini_file), "Юникод", "dv", encoding=encoding) == "ދިވެހިބަސް" - ) + assert ini.get_option(str(ini_file), "Юникод", "dv", encoding=encoding) == "ދިވެހިބަސް" @pytest.mark.parametrize("linesep", ["\r", "\n", "\r\n"]) @@ -478,9 +476,12 @@ def test_unicode_remove_option(encoding, linesep, ini_file, unicode_content): ini_file.write_bytes(content) assert ( - ini.remove_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) == "zh_TW" + ini.remove_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) + == "zh_TW" + ) + assert ( + ini.get_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) is None ) - assert ini.get_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) is None @pytest.mark.parametrize("linesep", ["\r", "\n", "\r\n"]) diff --git a/tests/pytests/unit/modules/test_introspect.py b/tests/pytests/unit/modules/test_introspect.py index caf9db42eee..fa2c99d6672 100644 --- a/tests/pytests/unit/modules/test_introspect.py +++ b/tests/pytests/unit/modules/test_introspect.py @@ -4,7 +4,6 @@ Test cases for salt.modules.introspect """ - import pytest import salt.modules.introspect as introspect diff --git a/tests/pytests/unit/modules/test_ipset.py b/tests/pytests/unit/modules/test_ipset.py index e0f486300f3..83d07f1d4ef 100644 --- a/tests/pytests/unit/modules/test_ipset.py +++ b/tests/pytests/unit/modules/test_ipset.py @@ -1,6 +1,7 @@ """ :codeauthor: Rupesh Tare """ + import pytest import salt.modules.ipset as ipset diff --git a/tests/pytests/unit/modules/test_junos.py b/tests/pytests/unit/modules/test_junos.py index 616f15f1d8a..1c4e3d57f29 100644 --- a/tests/pytests/unit/modules/test_junos.py +++ b/tests/pytests/unit/modules/test_junos.py @@ -1,6 +1,7 @@ """ :codeauthor: Rajvi Dhimar """ + import os import pytest diff --git a/tests/pytests/unit/modules/test_key.py b/tests/pytests/unit/modules/test_key.py index bfc9442a103..726d7db44ca 100644 --- a/tests/pytests/unit/modules/test_key.py +++ b/tests/pytests/unit/modules/test_key.py @@ -4,7 +4,6 @@ Test cases for salt.modules.key """ - import os.path import pytest diff --git a/tests/pytests/unit/modules/test_keyboard.py b/tests/pytests/unit/modules/test_keyboard.py index d88f52bd6d6..ceb0d7effe0 100644 --- a/tests/pytests/unit/modules/test_keyboard.py +++ b/tests/pytests/unit/modules/test_keyboard.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.keyboard as keyboard diff --git a/tests/pytests/unit/modules/test_kubeadm.py b/tests/pytests/unit/modules/test_kubeadm.py index 252a89da2f9..a4c1d2fc449 100644 --- a/tests/pytests/unit/modules/test_kubeadm.py +++ b/tests/pytests/unit/modules/test_kubeadm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.kubeadm """ - import pytest import salt.modules.kubeadm as kubeadm diff --git a/tests/pytests/unit/modules/test_launchctl_service.py b/tests/pytests/unit/modules/test_launchctl_service.py index bda0137189b..afb0920476a 100644 --- a/tests/pytests/unit/modules/test_launchctl_service.py +++ b/tests/pytests/unit/modules/test_launchctl_service.py @@ -4,7 +4,6 @@ Test cases for salt.modules.launchctl """ - import pytest import salt.modules.launchctl_service as launchctl diff --git a/tests/pytests/unit/modules/test_ldapmod.py b/tests/pytests/unit/modules/test_ldapmod.py index 751625eb992..9b8207ed5bf 100644 --- a/tests/pytests/unit/modules/test_ldapmod.py +++ b/tests/pytests/unit/modules/test_ldapmod.py @@ -4,7 +4,6 @@ Test cases for salt.modules.ldapmod """ - import time import pytest diff --git a/tests/pytests/unit/modules/test_linux_lvm.py b/tests/pytests/unit/modules/test_linux_lvm.py index 848a57040a1..9c39f63e747 100644 --- a/tests/pytests/unit/modules/test_linux_lvm.py +++ b/tests/pytests/unit/modules/test_linux_lvm.py @@ -4,7 +4,6 @@ TestCase for the salt.modules.linux_lvm module """ - import os.path import pytest diff --git a/tests/pytests/unit/modules/test_linux_shadow.py b/tests/pytests/unit/modules/test_linux_shadow.py index 5d977fc5212..0c742672750 100644 --- a/tests/pytests/unit/modules/test_linux_shadow.py +++ b/tests/pytests/unit/modules/test_linux_shadow.py @@ -1,6 +1,7 @@ """ :codeauthor: Erik Johnson """ + import types import pytest diff --git a/tests/pytests/unit/modules/test_locate.py b/tests/pytests/unit/modules/test_locate.py index f74853a10bc..f4e5b2fb822 100644 --- a/tests/pytests/unit/modules/test_locate.py +++ b/tests/pytests/unit/modules/test_locate.py @@ -4,7 +4,6 @@ Test cases for salt.modules.locate """ - import pytest import salt.modules.locate as locate diff --git a/tests/pytests/unit/modules/test_logadm.py b/tests/pytests/unit/modules/test_logadm.py index 7926252d025..fd5e61ba30f 100644 --- a/tests/pytests/unit/modules/test_logadm.py +++ b/tests/pytests/unit/modules/test_logadm.py @@ -4,7 +4,6 @@ Test cases for salt.modules.logadm """ - import pytest import salt.modules.logadm as logadm diff --git a/tests/pytests/unit/modules/test_logrotate.py b/tests/pytests/unit/modules/test_logrotate.py index 86caa5e58ad..03872c4cf06 100644 --- a/tests/pytests/unit/modules/test_logrotate.py +++ b/tests/pytests/unit/modules/test_logrotate.py @@ -4,7 +4,6 @@ Test cases for salt.modules.logrotate """ - import pytest import salt.modules.logrotate as logrotate diff --git a/tests/pytests/unit/modules/test_lvs.py b/tests/pytests/unit/modules/test_lvs.py index 58ba24a4160..513046787f0 100644 --- a/tests/pytests/unit/modules/test_lvs.py +++ b/tests/pytests/unit/modules/test_lvs.py @@ -4,7 +4,6 @@ Test cases for salt.modules.lvs """ - import pytest import salt.modules.lvs as lvs diff --git a/tests/pytests/unit/modules/test_mac_brew_pkg.py b/tests/pytests/unit/modules/test_mac_brew_pkg.py index 749c9765cce..99574efb01d 100644 --- a/tests/pytests/unit/modules/test_mac_brew_pkg.py +++ b/tests/pytests/unit/modules/test_mac_brew_pkg.py @@ -1,6 +1,7 @@ """ :codeauthor: Nicole Thomas """ + import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_mac_service.py b/tests/pytests/unit/modules/test_mac_service.py index c657ea893c5..91578d946cf 100644 --- a/tests/pytests/unit/modules/test_mac_service.py +++ b/tests/pytests/unit/modules/test_mac_service.py @@ -2,7 +2,6 @@ :codeauthor: Megan Wilhite """ - import pytest import salt.modules.mac_service as mac_service diff --git a/tests/pytests/unit/modules/test_mac_shadow.py b/tests/pytests/unit/modules/test_mac_shadow.py index fa294b6651d..94d3c36b046 100644 --- a/tests/pytests/unit/modules/test_mac_shadow.py +++ b/tests/pytests/unit/modules/test_mac_shadow.py @@ -1,6 +1,7 @@ """ Unit Tests for the mac_desktop execution module. """ + from datetime import datetime import pytest diff --git a/tests/pytests/unit/modules/test_mandrill.py b/tests/pytests/unit/modules/test_mandrill.py index c1930d470e3..4f1c62e4673 100644 --- a/tests/pytests/unit/modules/test_mandrill.py +++ b/tests/pytests/unit/modules/test_mandrill.py @@ -2,7 +2,6 @@ Tests for the Mandrill execution module. """ - import pytest import salt.modules.mandrill as mandrill diff --git a/tests/pytests/unit/modules/test_match.py b/tests/pytests/unit/modules/test_match.py index 3a942dec752..d6ec425a02d 100644 --- a/tests/pytests/unit/modules/test_match.py +++ b/tests/pytests/unit/modules/test_match.py @@ -2,7 +2,6 @@ :codeauthor: Oleg Lipovchenko """ - import pytest import salt.loader diff --git a/tests/pytests/unit/modules/test_mdadm_raid.py b/tests/pytests/unit/modules/test_mdadm_raid.py index f496339b738..ebbf9cecc25 100644 --- a/tests/pytests/unit/modules/test_mdadm_raid.py +++ b/tests/pytests/unit/modules/test_mdadm_raid.py @@ -5,6 +5,7 @@ tests.unit.modules.mdadm_test ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import re import pytest diff --git a/tests/pytests/unit/modules/test_mine.py b/tests/pytests/unit/modules/test_mine.py index 9fdfecbd0c1..9f7ec6b998a 100644 --- a/tests/pytests/unit/modules/test_mine.py +++ b/tests/pytests/unit/modules/test_mine.py @@ -3,7 +3,6 @@ :codeauthor: Herbert Buurman """ - import pytest import salt.modules.mine as mine diff --git a/tests/pytests/unit/modules/test_mongodb.py b/tests/pytests/unit/modules/test_mongodb.py index b8b011dfdac..37bf432af25 100644 --- a/tests/pytests/unit/modules/test_mongodb.py +++ b/tests/pytests/unit/modules/test_mongodb.py @@ -112,7 +112,9 @@ def test_version(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_command, patch_pymongo_database, patch_salt_dict: + with ( + patch_mongo_client + ), patch_pymongo_command, patch_pymongo_database, patch_salt_dict: ret = mongodb.version() assert ret == "6.0.2" @@ -139,7 +141,9 @@ def test_db_list(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_list_db_names, patch_mongo_client, patch_pymongo_database, patch_salt_dict: + with ( + patch_list_db_names + ), patch_mongo_client, patch_pymongo_database, patch_salt_dict: ret = mongodb.db_list() assert ret == ["admin", "config", "local"] @@ -167,7 +171,9 @@ def test_db_exists(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_list_db_names, patch_mongo_client, patch_pymongo_database, patch_salt_dict: + with ( + patch_list_db_names + ), patch_mongo_client, patch_pymongo_database, patch_salt_dict: ret = mongodb.db_exists("admin") assert ret @@ -215,7 +221,9 @@ def test_user_list(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_pymongo_command, patch_salt_dict: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_pymongo_command, patch_salt_dict: ret = mongodb.user_list() expected = [ { @@ -318,7 +326,9 @@ def test_user_create(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_create("test_user", "test_password") assert ret @@ -344,7 +354,9 @@ def test_user_create_exception(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_create("test_user", "test_password") assert not ret @@ -370,7 +382,9 @@ def test_user_remove(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_remove("test_user") assert ret @@ -396,7 +410,9 @@ def test_user_remove_exception(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_remove("test_user") assert not ret @@ -446,7 +462,9 @@ def test_user_roles_exists(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_roles_exists("test_user", '["read"]', "admin") assert ret @@ -471,7 +489,9 @@ def test_user_grant_roles(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_grant_roles( "test_user", '[{"role": "readWrite", "db": "admin" }]', "admin" ) @@ -498,7 +518,9 @@ def test_user_revoke_roles(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_revoke_roles( "test_user", '[{"role": "readWrite", "db": "admin" }]', "admin" ) @@ -525,7 +547,9 @@ def test_collection_create(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.collection_create("test_collection") assert ret @@ -552,7 +576,9 @@ def test_collections_list(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_list_collection_names: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_list_collection_names: ret = mongodb.collections_list() assert ret == ["system.users", "mycollection", "system.version"] @@ -579,7 +605,9 @@ def test_insert(): patch_pymongo_database = patch("pymongo.database.Database", pymongo_database_mock) patch_pymongo_collection = patch.object(mongodb, "getattr", pymongo_collection_mock) - with patch_mongo_client, patch_salt_dict, patch_pymongo_database, patch_pymongo_collection: + with ( + patch_mongo_client + ), patch_salt_dict, patch_pymongo_database, patch_pymongo_collection: patch_pymongo_collection_insert = patch.object( MockPyMongoCollection, "insert_many", diff --git a/tests/pytests/unit/modules/test_monit.py b/tests/pytests/unit/modules/test_monit.py index 092782bc1dd..7e16f1eca69 100644 --- a/tests/pytests/unit/modules/test_monit.py +++ b/tests/pytests/unit/modules/test_monit.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.monit as monit diff --git a/tests/pytests/unit/modules/test_mysql.py b/tests/pytests/unit/modules/test_mysql.py index 001655c8fd1..beb6b3b6d69 100644 --- a/tests/pytests/unit/modules/test_mysql.py +++ b/tests/pytests/unit/modules/test_mysql.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import pytest diff --git a/tests/pytests/unit/modules/test_nacl.py b/tests/pytests/unit/modules/test_nacl.py index 915e2c5e3dd..2906ebc5419 100644 --- a/tests/pytests/unit/modules/test_nacl.py +++ b/tests/pytests/unit/modules/test_nacl.py @@ -1,6 +1,7 @@ """ Unit tests for the salt.modules.nacl module """ + import pytest import salt.utils.stringutils diff --git a/tests/pytests/unit/modules/test_nfs3.py b/tests/pytests/unit/modules/test_nfs3.py index 030e7f6d6f2..ecb16dff4a5 100644 --- a/tests/pytests/unit/modules/test_nfs3.py +++ b/tests/pytests/unit/modules/test_nfs3.py @@ -4,7 +4,6 @@ Test cases for salt.modules.nfs3 """ - import pytest import salt.modules.nfs3 as nfs3 diff --git a/tests/pytests/unit/modules/test_nftables.py b/tests/pytests/unit/modules/test_nftables.py index 423a38c0101..855e7712e7f 100644 --- a/tests/pytests/unit/modules/test_nftables.py +++ b/tests/pytests/unit/modules/test_nftables.py @@ -3,6 +3,7 @@ Test cases for salt.modules.nftables """ + import json import pytest diff --git a/tests/pytests/unit/modules/test_npm.py b/tests/pytests/unit/modules/test_npm.py index 61117ffcc12..53243964953 100644 --- a/tests/pytests/unit/modules/test_npm.py +++ b/tests/pytests/unit/modules/test_npm.py @@ -4,7 +4,6 @@ Test cases for salt.modules.npm """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_openbsdpkg.py b/tests/pytests/unit/modules/test_openbsdpkg.py index 33261be9464..aca6068cc48 100644 --- a/tests/pytests/unit/modules/test_openbsdpkg.py +++ b/tests/pytests/unit/modules/test_openbsdpkg.py @@ -2,7 +2,6 @@ :codeauthor: Eric Radman """ - import pytest import salt.modules.openbsdpkg as openbsdpkg diff --git a/tests/pytests/unit/modules/test_oracle.py b/tests/pytests/unit/modules/test_oracle.py index 2e578e6b5db..4aa8318d9b7 100644 --- a/tests/pytests/unit/modules/test_oracle.py +++ b/tests/pytests/unit/modules/test_oracle.py @@ -4,7 +4,6 @@ Test cases for salt.modules.oracle """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_osquery.py b/tests/pytests/unit/modules/test_osquery.py index 98ce22b25e3..20647a6dfc4 100644 --- a/tests/pytests/unit/modules/test_osquery.py +++ b/tests/pytests/unit/modules/test_osquery.py @@ -4,7 +4,6 @@ Test cases for salt.modules.osquery """ - import pytest import salt.modules.osquery as osquery diff --git a/tests/pytests/unit/modules/test_pacmanpkg.py b/tests/pytests/unit/modules/test_pacmanpkg.py index 09a6f6aef16..d3728936da9 100644 --- a/tests/pytests/unit/modules/test_pacmanpkg.py +++ b/tests/pytests/unit/modules/test_pacmanpkg.py @@ -2,7 +2,6 @@ :codeauthor: Eric Vz """ - import pytest import salt.modules.pacmanpkg as pacman diff --git a/tests/pytests/unit/modules/test_pagerduty.py b/tests/pytests/unit/modules/test_pagerduty.py index 0d4cda95868..f43df961f53 100644 --- a/tests/pytests/unit/modules/test_pagerduty.py +++ b/tests/pytests/unit/modules/test_pagerduty.py @@ -4,7 +4,6 @@ Test cases for salt.modules.pagerduty """ - import pytest import salt.modules.pagerduty as pagerduty diff --git a/tests/pytests/unit/modules/test_pam.py b/tests/pytests/unit/modules/test_pam.py index 0fd8078a560..6f1e7faf661 100644 --- a/tests/pytests/unit/modules/test_pam.py +++ b/tests/pytests/unit/modules/test_pam.py @@ -3,6 +3,7 @@ Test cases for salt.modules.pam """ + import pytest import salt.modules.pam as pam diff --git a/tests/pytests/unit/modules/test_parallels.py b/tests/pytests/unit/modules/test_parallels.py index 2d48ccb6146..6f6acb2c00a 100644 --- a/tests/pytests/unit/modules/test_parallels.py +++ b/tests/pytests/unit/modules/test_parallels.py @@ -2,7 +2,6 @@ Test parallels desktop execution module functions """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_pecl.py b/tests/pytests/unit/modules/test_pecl.py index 65b1235ce18..8113fb4ce64 100644 --- a/tests/pytests/unit/modules/test_pecl.py +++ b/tests/pytests/unit/modules/test_pecl.py @@ -4,7 +4,6 @@ Test cases for salt.modules.pecl """ - import pytest import salt.modules.pecl as pecl diff --git a/tests/pytests/unit/modules/test_pkgutil.py b/tests/pytests/unit/modules/test_pkgutil.py index 627c807d917..5df0044fc30 100644 --- a/tests/pytests/unit/modules/test_pkgutil.py +++ b/tests/pytests/unit/modules/test_pkgutil.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.pkgutil as pkgutil diff --git a/tests/pytests/unit/modules/test_portage_config.py b/tests/pytests/unit/modules/test_portage_config.py index 34b388a8a43..71da51390e2 100644 --- a/tests/pytests/unit/modules/test_portage_config.py +++ b/tests/pytests/unit/modules/test_portage_config.py @@ -4,6 +4,7 @@ pytest.unit.modules.portage_flags ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import pytest import salt.modules.portage_config as portage_config @@ -26,7 +27,7 @@ def test_get_config_file_wildcards(): ("cat/pkg::repo", "/etc/portage/package.mask/cat/pkg"), ] - for (atom, expected) in pairs: + for atom, expected in pairs: assert portage_config._get_config_file("mask", atom) == expected diff --git a/tests/pytests/unit/modules/test_postfix.py b/tests/pytests/unit/modules/test_postfix.py index e834b654473..72ed5a8d4b7 100644 --- a/tests/pytests/unit/modules/test_postfix.py +++ b/tests/pytests/unit/modules/test_postfix.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.postfix as postfix diff --git a/tests/pytests/unit/modules/test_ps.py b/tests/pytests/unit/modules/test_ps.py index ebff755e0ac..14a75446890 100644 --- a/tests/pytests/unit/modules/test_ps.py +++ b/tests/pytests/unit/modules/test_ps.py @@ -84,7 +84,9 @@ def sample_process(): patch_create_time = patch( "psutil._psplatform.Process.create_time", return_value=393829200 ) - with patch_stat_file, patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: + with ( + patch_stat_file + ), patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: proc = psutil.Process(pid=42) proc.info = proc.as_dict(("name", "status")) yield proc @@ -1137,7 +1139,9 @@ def test_proc_info(): patch_create_time = patch( "psutil._psplatform.Process.create_time", return_value=393829200 ) - with patch_stat_file, patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: + with ( + patch_stat_file + ), patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: if salt.utils.platform.is_windows(): with patch("psutil._pswindows.cext") as mock__psutil_windows: with patch("psutil._pswindows.Process.ppid", return_value=99): diff --git a/tests/pytests/unit/modules/test_publish.py b/tests/pytests/unit/modules/test_publish.py index 38731761a91..5da0902dfa7 100644 --- a/tests/pytests/unit/modules/test_publish.py +++ b/tests/pytests/unit/modules/test_publish.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.publish as publish diff --git a/tests/pytests/unit/modules/test_pw_user.py b/tests/pytests/unit/modules/test_pw_user.py index c527bcbd2df..9b1c86f1039 100644 --- a/tests/pytests/unit/modules/test_pw_user.py +++ b/tests/pytests/unit/modules/test_pw_user.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import logging import pytest diff --git a/tests/pytests/unit/modules/test_qemu_img.py b/tests/pytests/unit/modules/test_qemu_img.py index b616f6f172b..ed175d33a36 100644 --- a/tests/pytests/unit/modules/test_qemu_img.py +++ b/tests/pytests/unit/modules/test_qemu_img.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_rabbitmq.py b/tests/pytests/unit/modules/test_rabbitmq.py index b9004962b4f..13860cd33f5 100644 --- a/tests/pytests/unit/modules/test_rabbitmq.py +++ b/tests/pytests/unit/modules/test_rabbitmq.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import logging import pytest diff --git a/tests/pytests/unit/modules/test_rbenv.py b/tests/pytests/unit/modules/test_rbenv.py index ed0a535ec37..5d36acc2094 100644 --- a/tests/pytests/unit/modules/test_rbenv.py +++ b/tests/pytests/unit/modules/test_rbenv.py @@ -4,7 +4,6 @@ Test cases for salt.modules.rbenv """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_rdp.py b/tests/pytests/unit/modules/test_rdp.py index 682bd752f1b..8815b201737 100644 --- a/tests/pytests/unit/modules/test_rdp.py +++ b/tests/pytests/unit/modules/test_rdp.py @@ -4,7 +4,6 @@ Test cases for salt.modules.rdp """ - import pytest import salt.modules.rdp as rdp diff --git a/tests/pytests/unit/modules/test_restartcheck.py b/tests/pytests/unit/modules/test_restartcheck.py index 14efa9a7add..c5ce6e8a0ce 100644 --- a/tests/pytests/unit/modules/test_restartcheck.py +++ b/tests/pytests/unit/modules/test_restartcheck.py @@ -217,7 +217,11 @@ def test_when_nilinuxrt_and_not_kernel_modules_changed_or_sysapi_files_changed_a return_value=[], ) - with patch_grains, patch_kernel_versions, patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: + with ( + patch_grains + ), ( + patch_kernel_versions + ), patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: actual_result = restartcheck.restartcheck() assert actual_result == expected_result @@ -262,7 +266,11 @@ def test_when_nilinuxrt_and_not_kernel_modules_changed_or_sysapi_files_changed_a return_value=[], ) - with patch_grains, patch_kernel_versions, patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: + with ( + patch_grains + ), ( + patch_kernel_versions + ), patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: actual_result = restartcheck.restartcheck() assert actual_result == expected_result @@ -635,7 +643,9 @@ def test_valid_command_b(): patch_popen = patch("subprocess.Popen", popen_mock) patch_grains = patch.dict(restartcheck.__grains__, {"os_family": "RedHat"}) - with patch_kernel, patch_salt, patch_deleted, patch_readlink, patch_grains, patch_popen: + with ( + patch_kernel + ), patch_salt, patch_deleted, patch_readlink, patch_grains, patch_popen: ret = restartcheck.restartcheck() assert "Found 1 processes using old versions of upgraded files" in ret popen_mock.assert_called_with( diff --git a/tests/pytests/unit/modules/test_ret.py b/tests/pytests/unit/modules/test_ret.py index 85c4e539859..25d85beecfa 100644 --- a/tests/pytests/unit/modules/test_ret.py +++ b/tests/pytests/unit/modules/test_ret.py @@ -4,7 +4,6 @@ Test cases for salt.modules.ret """ - import pytest import salt.loader diff --git a/tests/pytests/unit/modules/test_rh_service.py b/tests/pytests/unit/modules/test_rh_service.py index bee9e1e0860..e6373b92e6e 100644 --- a/tests/pytests/unit/modules/test_rh_service.py +++ b/tests/pytests/unit/modules/test_rh_service.py @@ -4,7 +4,6 @@ Test cases for salt.modules.rh_service """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_rvm.py b/tests/pytests/unit/modules/test_rvm.py index 0125d7a42ff..dab57c2a2ff 100644 --- a/tests/pytests/unit/modules/test_rvm.py +++ b/tests/pytests/unit/modules/test_rvm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.rvm """ - import pytest import salt.modules.rvm as rvm diff --git a/tests/pytests/unit/modules/test_s6.py b/tests/pytests/unit/modules/test_s6.py index 7809051f03f..a66fd62018b 100644 --- a/tests/pytests/unit/modules/test_s6.py +++ b/tests/pytests/unit/modules/test_s6.py @@ -4,7 +4,6 @@ Test cases for salt.modules.s6 """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_saltcloudmod.py b/tests/pytests/unit/modules/test_saltcloudmod.py index 54f56552329..53f2f61f77b 100644 --- a/tests/pytests/unit/modules/test_saltcloudmod.py +++ b/tests/pytests/unit/modules/test_saltcloudmod.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.modules.saltcloudmod as saltcloudmod diff --git a/tests/pytests/unit/modules/test_schedule.py b/tests/pytests/unit/modules/test_schedule.py index d39ae30e5c2..1b656144162 100644 --- a/tests/pytests/unit/modules/test_schedule.py +++ b/tests/pytests/unit/modules/test_schedule.py @@ -52,7 +52,11 @@ def test_purge(job1): schedule, "list_", MagicMock(return_value=_schedule_data) ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_list: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_list: assert schedule.purge() == { "comment": ["Deleted job: job1 from schedule."], "changes": {"job1": "removed"}, @@ -103,7 +107,9 @@ def test_delete(job1): SaltEvent, "get_event", return_value={"complete": True, "schedule": {}} ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: assert schedule.delete("job1") == { "comment": "Job job1 does not exist.", "changes": {}, @@ -339,7 +345,9 @@ def test_run_job(job1): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: assert schedule.run_job("job1") == { "comment": "Scheduling Job job1 on minion.", "result": True, @@ -365,7 +373,9 @@ def test_enable_job(): SaltEvent, "get_event", return_value={"complete": True, "schedule": {}} ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: assert schedule.enable_job("job1") == { "comment": "Job job1 does not exist.", "changes": {}, @@ -392,7 +402,9 @@ def test_disable_job(): SaltEvent, "get_event", return_value={"complete": True, "schedule": {}} ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: assert schedule.disable_job("job1") == { "comment": "Job job1 does not exist.", "changes": {}, @@ -474,7 +486,9 @@ def test_move(job1): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( schedule.__salt__, {"publish.publish": mock} @@ -516,7 +530,9 @@ def test_move(job1): mock = MagicMock(side_effect=[{}, {"job1": {}}]) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: with patch.dict(schedule.__pillar__, {"schedule": {"job1": job1}}): mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( @@ -576,7 +592,9 @@ def test_copy(job1): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( schedule.__salt__, {"publish.publish": mock} @@ -616,7 +634,9 @@ def test_copy(job1): "result": False, } - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event: mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( schedule.__salt__, {"publish.publish": mock} @@ -887,7 +907,9 @@ def test_is_enabled(): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_get_event, patch_schedule_salt: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_get_event, patch_schedule_salt: ret = schedule.is_enabled("job1") assert ret == job1 @@ -925,7 +947,9 @@ def test_job_status(): SaltEvent, "get_event", return_value={"complete": True, "data": job1} ) - with patch_makedirs, patch_schedule_opts, patch_schedule_get_event, patch_schedule_salt: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_get_event, patch_schedule_salt: ret = schedule.job_status("job1") assert ret == { "_last_run": "2021-11-01T12:36:57", @@ -978,7 +1002,11 @@ def test_list(job1): "os.path.exists", MagicMock(return_value=True) ) - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: @@ -1006,7 +1034,13 @@ def test_list(job1): seconds: 10 """ - with patch_schedule_opts, patch_makedirs, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_os_path_exists: + with ( + patch_schedule_opts + ), ( + patch_makedirs + ), ( + patch_schedule_event_fire + ), patch_schedule_get_event, patch_schedule_os_path_exists: with patch("salt.utils.files.fopen", mock_open(read_data="")) as fopen_mock: ret = schedule.list_() assert ret == expected @@ -1038,7 +1072,11 @@ def test_list(job1): seconds: 10 """ - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: @@ -1094,7 +1132,11 @@ def test_list_global_enabled(job1): "os.path.exists", MagicMock(return_value=True) ) - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: @@ -1151,7 +1193,11 @@ def test_list_global_disabled(job1): "os.path.exists", MagicMock(return_value=True) ) - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), patch_schedule_get_event, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: diff --git a/tests/pytests/unit/modules/test_sdb.py b/tests/pytests/unit/modules/test_sdb.py index 01d1e1a6273..aa046d7cffe 100644 --- a/tests/pytests/unit/modules/test_sdb.py +++ b/tests/pytests/unit/modules/test_sdb.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.sdb as sdb diff --git a/tests/pytests/unit/modules/test_serverdensity_device.py b/tests/pytests/unit/modules/test_serverdensity_device.py index 6d79aefa813..5a65012c11e 100644 --- a/tests/pytests/unit/modules/test_serverdensity_device.py +++ b/tests/pytests/unit/modules/test_serverdensity_device.py @@ -4,7 +4,6 @@ TestCase for salt.modules.serverdensity_device """ - import pytest import salt.modules.serverdensity_device as serverdensity_device diff --git a/tests/pytests/unit/modules/test_servicenow.py b/tests/pytests/unit/modules/test_servicenow.py index 1971b63f653..d5e9a96ae13 100644 --- a/tests/pytests/unit/modules/test_servicenow.py +++ b/tests/pytests/unit/modules/test_servicenow.py @@ -4,7 +4,6 @@ TestCase for salt.modules.servicenow """ - import pytest import salt.modules.servicenow as servicenow diff --git a/tests/pytests/unit/modules/test_slackware_service.py b/tests/pytests/unit/modules/test_slackware_service.py index c2cd52e1a5d..93e685a0677 100644 --- a/tests/pytests/unit/modules/test_slackware_service.py +++ b/tests/pytests/unit/modules/test_slackware_service.py @@ -1,6 +1,7 @@ """ :codeauthor: Piter Punk """ + import os import pytest diff --git a/tests/pytests/unit/modules/test_smartos_imgadm.py b/tests/pytests/unit/modules/test_smartos_imgadm.py index 3f9500aaa81..111e28529dc 100644 --- a/tests/pytests/unit/modules/test_smartos_imgadm.py +++ b/tests/pytests/unit/modules/test_smartos_imgadm.py @@ -4,7 +4,6 @@ TestCase for salt.modules.smartos_imgadm module """ - import pytest import salt.modules.smartos_imgadm as imgadm diff --git a/tests/pytests/unit/modules/test_smtp.py b/tests/pytests/unit/modules/test_smtp.py index 983bb209cf2..840b6c08fbb 100644 --- a/tests/pytests/unit/modules/test_smtp.py +++ b/tests/pytests/unit/modules/test_smtp.py @@ -4,7 +4,6 @@ TestCase for salt.modules.smtp """ - import pytest import salt.modules.smtp as smtp diff --git a/tests/pytests/unit/modules/test_status.py b/tests/pytests/unit/modules/test_status.py index e0bb270df66..7b6bb6ce854 100644 --- a/tests/pytests/unit/modules/test_status.py +++ b/tests/pytests/unit/modules/test_status.py @@ -2,7 +2,6 @@ Test cases for salt.modules.status """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_suse_ip.py b/tests/pytests/unit/modules/test_suse_ip.py index b6812a0043f..7494ab57d2e 100644 --- a/tests/pytests/unit/modules/test_suse_ip.py +++ b/tests/pytests/unit/modules/test_suse_ip.py @@ -585,9 +585,7 @@ def test_build_interface_bond_mode_4(): "lacp_rate={}".format( "1" if lacp_rate == "fast" - else "0" - if lacp_rate == "slow" - else lacp_rate + else "0" if lacp_rate == "slow" else lacp_rate ), "miimon=100", "mode=4", diff --git a/tests/pytests/unit/modules/test_swift.py b/tests/pytests/unit/modules/test_swift.py index f8c0f313387..3fb5c504df8 100644 --- a/tests/pytests/unit/modules/test_swift.py +++ b/tests/pytests/unit/modules/test_swift.py @@ -4,7 +4,6 @@ Test cases for salt.modules.swift """ - import pytest import salt.modules.swift as swift diff --git a/tests/pytests/unit/modules/test_syslog_ng.py b/tests/pytests/unit/modules/test_syslog_ng.py index 5a4b2f57942..ad5d76ee475 100644 --- a/tests/pytests/unit/modules/test_syslog_ng.py +++ b/tests/pytests/unit/modules/test_syslog_ng.py @@ -2,7 +2,6 @@ Test cases for salt.modules.syslog_ng """ - import os from textwrap import dedent diff --git a/tests/pytests/unit/modules/test_system.py b/tests/pytests/unit/modules/test_system.py index d2a8a4ba9a9..c825db51cbc 100644 --- a/tests/pytests/unit/modules/test_system.py +++ b/tests/pytests/unit/modules/test_system.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.system as system diff --git a/tests/pytests/unit/modules/test_telegram.py b/tests/pytests/unit/modules/test_telegram.py index 568c01002b2..02679df4d1a 100644 --- a/tests/pytests/unit/modules/test_telegram.py +++ b/tests/pytests/unit/modules/test_telegram.py @@ -4,7 +4,6 @@ Test cases for salt.modules.telegram. """ - import pytest import salt.modules.telegram as telegram diff --git a/tests/pytests/unit/modules/test_tomcat.py b/tests/pytests/unit/modules/test_tomcat.py index 869c3f96c85..6658fca0dad 100644 --- a/tests/pytests/unit/modules/test_tomcat.py +++ b/tests/pytests/unit/modules/test_tomcat.py @@ -2,7 +2,6 @@ Tests cases for salt.modules.tomcat """ - import io import urllib.request diff --git a/tests/pytests/unit/modules/test_transactional_update.py b/tests/pytests/unit/modules/test_transactional_update.py index 5d9294c49bd..eb6dfae2868 100644 --- a/tests/pytests/unit/modules/test_transactional_update.py +++ b/tests/pytests/unit/modules/test_transactional_update.py @@ -178,9 +178,11 @@ def test_commands_with_global_params(): "--non-interactive", "--drop-if-no-change", "--no-selfupdate", - cmd.replace("_", ".") - if cmd.startswith("grub") - else cmd.replace("_", "-"), + ( + cmd.replace("_", ".") + if cmd.startswith("grub") + else cmd.replace("_", "-") + ), ] ) diff --git a/tests/pytests/unit/modules/test_tuned.py b/tests/pytests/unit/modules/test_tuned.py index 01240df03cc..561dd53990c 100644 --- a/tests/pytests/unit/modules/test_tuned.py +++ b/tests/pytests/unit/modules/test_tuned.py @@ -2,7 +2,6 @@ Test for the salt.modules.tuned """ - import pytest from salt.modules import tuned diff --git a/tests/pytests/unit/modules/test_udev.py b/tests/pytests/unit/modules/test_udev.py index d5dbee9d20f..19e055908ee 100644 --- a/tests/pytests/unit/modules/test_udev.py +++ b/tests/pytests/unit/modules/test_udev.py @@ -4,7 +4,6 @@ Test cases for salt.modules.udev """ - import pytest import salt.modules.udev as udev diff --git a/tests/pytests/unit/modules/test_uptime.py b/tests/pytests/unit/modules/test_uptime.py index 2e129a7c9bb..9857a9959f4 100644 --- a/tests/pytests/unit/modules/test_uptime.py +++ b/tests/pytests/unit/modules/test_uptime.py @@ -2,7 +2,6 @@ Test cases for salt.modules.uptime """ - import pytest import salt.modules.uptime as uptime diff --git a/tests/pytests/unit/modules/test_uwsgi.py b/tests/pytests/unit/modules/test_uwsgi.py index 5c97c191ce8..0de0995f15b 100644 --- a/tests/pytests/unit/modules/test_uwsgi.py +++ b/tests/pytests/unit/modules/test_uwsgi.py @@ -2,7 +2,6 @@ Test cases for salt.modules.uswgi """ - import pytest import salt.modules.uwsgi as uwsgi diff --git a/tests/pytests/unit/modules/test_vagrant.py b/tests/pytests/unit/modules/test_vagrant.py index 2a4b5de0b56..53566cb1a2d 100644 --- a/tests/pytests/unit/modules/test_vagrant.py +++ b/tests/pytests/unit/modules/test_vagrant.py @@ -2,7 +2,6 @@ TestCase for the salt.modules.vagrant module. """ - import pytest import salt.exceptions diff --git a/tests/pytests/unit/modules/test_vault.py b/tests/pytests/unit/modules/test_vault.py index c72c958f4f2..b9de4b941c7 100644 --- a/tests/pytests/unit/modules/test_vault.py +++ b/tests/pytests/unit/modules/test_vault.py @@ -2,7 +2,6 @@ Test case for the vault execution module """ - import pytest import salt.modules.vault as vault diff --git a/tests/pytests/unit/modules/test_vmctl.py b/tests/pytests/unit/modules/test_vmctl.py index e0935924a43..b264d99f1c7 100644 --- a/tests/pytests/unit/modules/test_vmctl.py +++ b/tests/pytests/unit/modules/test_vmctl.py @@ -2,7 +2,6 @@ Test for salt.modules.vmctl """ - import pytest import salt.modules.vmctl as vmctl diff --git a/tests/pytests/unit/modules/test_webutil.py b/tests/pytests/unit/modules/test_webutil.py index d6e9d0b466d..038e4778206 100644 --- a/tests/pytests/unit/modules/test_webutil.py +++ b/tests/pytests/unit/modules/test_webutil.py @@ -4,7 +4,6 @@ Test cases for salt.modules.webutil """ - import pytest import salt.modules.webutil as htpasswd diff --git a/tests/pytests/unit/modules/test_win_autoruns.py b/tests/pytests/unit/modules/test_win_autoruns.py index dd8060eedd8..1261a05c012 100644 --- a/tests/pytests/unit/modules/test_win_autoruns.py +++ b/tests/pytests/unit/modules/test_win_autoruns.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.win_autoruns as win_autoruns diff --git a/tests/pytests/unit/modules/test_win_dns_client.py b/tests/pytests/unit/modules/test_win_dns_client.py index 8dfad4d0127..8e30c1bb58e 100644 --- a/tests/pytests/unit/modules/test_win_dns_client.py +++ b/tests/pytests/unit/modules/test_win_dns_client.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import types import pytest diff --git a/tests/pytests/unit/modules/test_win_iis.py b/tests/pytests/unit/modules/test_win_iis.py index f5e37724d24..4562f5a491e 100644 --- a/tests/pytests/unit/modules/test_win_iis.py +++ b/tests/pytests/unit/modules/test_win_iis.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_iis """ - import pytest import salt.modules.win_iis as win_iis diff --git a/tests/pytests/unit/modules/test_win_licence.py b/tests/pytests/unit/modules/test_win_licence.py index 2948be088f0..70a6cfbc490 100644 --- a/tests/pytests/unit/modules/test_win_licence.py +++ b/tests/pytests/unit/modules/test_win_licence.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_licence """ - import pytest import salt.modules.win_license as win_license diff --git a/tests/pytests/unit/modules/test_win_path.py b/tests/pytests/unit/modules/test_win_path.py index 7dad024a878..8b12653feed 100644 --- a/tests/pytests/unit/modules/test_win_path.py +++ b/tests/pytests/unit/modules/test_win_path.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_win_pkg.py b/tests/pytests/unit/modules/test_win_pkg.py index 9ef693a21f7..33c3325e146 100644 --- a/tests/pytests/unit/modules/test_win_pkg.py +++ b/tests/pytests/unit/modules/test_win_pkg.py @@ -1,6 +1,7 @@ """ Tests for the win_pkg module """ + import logging import pytest diff --git a/tests/pytests/unit/modules/test_win_pki.py b/tests/pytests/unit/modules/test_win_pki.py index 128fb14f820..600282e8bd8 100644 --- a/tests/pytests/unit/modules/test_win_pki.py +++ b/tests/pytests/unit/modules/test_win_pki.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_pki """ - import pytest import salt.modules.win_pki as win_pki diff --git a/tests/pytests/unit/modules/test_win_powercfg.py b/tests/pytests/unit/modules/test_win_powercfg.py index ab6f0ee6258..3fefad60804 100644 --- a/tests/pytests/unit/modules/test_win_powercfg.py +++ b/tests/pytests/unit/modules/test_win_powercfg.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_powercfg """ - import pytest import salt.modules.win_powercfg as powercfg diff --git a/tests/pytests/unit/modules/test_win_psget.py b/tests/pytests/unit/modules/test_win_psget.py index af7737b121f..417106affe8 100644 --- a/tests/pytests/unit/modules/test_win_psget.py +++ b/tests/pytests/unit/modules/test_win_psget.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_psget """ - import pytest import salt.modules.win_psget as win_psget diff --git a/tests/pytests/unit/modules/test_win_shadow.py b/tests/pytests/unit/modules/test_win_shadow.py index bccb67fe9da..dbac3807172 100644 --- a/tests/pytests/unit/modules/test_win_shadow.py +++ b/tests/pytests/unit/modules/test_win_shadow.py @@ -4,7 +4,6 @@ Test cases for salt.modules.win_shadow """ - import pytest import salt.modules.win_shadow as win_shadow diff --git a/tests/pytests/unit/modules/test_win_snmp.py b/tests/pytests/unit/modules/test_win_snmp.py index 339f834e0d8..bb8370a521a 100644 --- a/tests/pytests/unit/modules/test_win_snmp.py +++ b/tests/pytests/unit/modules/test_win_snmp.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_snmp """ - import pytest import salt.modules.win_snmp as win_snmp diff --git a/tests/pytests/unit/modules/test_win_system.py b/tests/pytests/unit/modules/test_win_system.py index a33aa3b1002..54eed432995 100644 --- a/tests/pytests/unit/modules/test_win_system.py +++ b/tests/pytests/unit/modules/test_win_system.py @@ -1,6 +1,7 @@ """ :codeauthor: Gareth J. Greenaway """ + import pytest import salt.modules.cmdmod as cmdmod diff --git a/tests/pytests/unit/modules/test_win_task.py b/tests/pytests/unit/modules/test_win_task.py index 6e71612264a..ee61d739b99 100644 --- a/tests/pytests/unit/modules/test_win_task.py +++ b/tests/pytests/unit/modules/test_win_task.py @@ -1,6 +1,7 @@ """ Test the win_task execution module """ + from datetime import datetime import pytest diff --git a/tests/pytests/unit/modules/test_win_timezone.py b/tests/pytests/unit/modules/test_win_timezone.py index 26a867dff85..b32b6a0187b 100644 --- a/tests/pytests/unit/modules/test_win_timezone.py +++ b/tests/pytests/unit/modules/test_win_timezone.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.win_timezone as win_timezone diff --git a/tests/pytests/unit/modules/test_win_wua.py b/tests/pytests/unit/modules/test_win_wua.py index 234574a015d..ee4db206a03 100644 --- a/tests/pytests/unit/modules/test_win_wua.py +++ b/tests/pytests/unit/modules/test_win_wua.py @@ -1,6 +1,7 @@ """ Test the win_wua execution module """ + import pytest import salt.modules.win_wua as win_wua diff --git a/tests/pytests/unit/modules/test_xapi_virt.py b/tests/pytests/unit/modules/test_xapi_virt.py index 47cdc4b6376..2f854f64cc9 100644 --- a/tests/pytests/unit/modules/test_xapi_virt.py +++ b/tests/pytests/unit/modules/test_xapi_virt.py @@ -4,7 +4,6 @@ Test cases for salt.modules.xapi """ - import pytest import salt.modules.xapi_virt as xapi diff --git a/tests/pytests/unit/modules/test_xfs.py b/tests/pytests/unit/modules/test_xfs.py index 9d1ce9dff34..79ff0dc2f34 100644 --- a/tests/pytests/unit/modules/test_xfs.py +++ b/tests/pytests/unit/modules/test_xfs.py @@ -2,7 +2,6 @@ Test cases for salt.modules.xfs """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_xml.py b/tests/pytests/unit/modules/test_xml.py index 334d2f2b73e..e627a5b6402 100644 --- a/tests/pytests/unit/modules/test_xml.py +++ b/tests/pytests/unit/modules/test_xml.py @@ -2,7 +2,6 @@ Tests for xml module """ - import pytest from salt.modules import xml diff --git a/tests/pytests/unit/modules/test_yumpkg.py b/tests/pytests/unit/modules/test_yumpkg.py index 188ed58ec7e..a44c35a41c6 100644 --- a/tests/pytests/unit/modules/test_yumpkg.py +++ b/tests/pytests/unit/modules/test_yumpkg.py @@ -1557,9 +1557,9 @@ def test_remove_with_epoch_and_arch_info(): installed = "8:3.8.12-4.n.el7" list_pkgs_mock = MagicMock( side_effect=lambda **kwargs: { - name_and_arch: [installed] - if kwargs.get("versions_as_list", False) - else installed + name_and_arch: ( + [installed] if kwargs.get("versions_as_list", False) else installed + ) } ) cmd_mock = MagicMock( diff --git a/tests/pytests/unit/modules/test_zenoss.py b/tests/pytests/unit/modules/test_zenoss.py index 3d03f11d770..fb2834cc484 100644 --- a/tests/pytests/unit/modules/test_zenoss.py +++ b/tests/pytests/unit/modules/test_zenoss.py @@ -2,7 +2,6 @@ Test cases for salt.modules.keystone """ - import pytest import salt.modules.config as config diff --git a/tests/pytests/unit/modules/test_zfs.py b/tests/pytests/unit/modules/test_zfs.py index a9d8a3016ec..a60a61f2aa6 100644 --- a/tests/pytests/unit/modules/test_zfs.py +++ b/tests/pytests/unit/modules/test_zfs.py @@ -215,9 +215,9 @@ def test_create_error_missing_parent(utils_patch): ) ret = {} ret["stdout"] = "" - ret[ - "stderr" - ] = "cannot create 'myzpool/mydataset/mysubdataset': parent does not exist" + ret["stderr"] = ( + "cannot create 'myzpool/mydataset/mysubdataset': parent does not exist" + ) ret["retcode"] = 1 mock_cmd = MagicMock(return_value=ret) with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict( diff --git a/tests/pytests/unit/modules/test_znc.py b/tests/pytests/unit/modules/test_znc.py index a28f8f1ca26..1cf491e5b0a 100644 --- a/tests/pytests/unit/modules/test_znc.py +++ b/tests/pytests/unit/modules/test_znc.py @@ -4,7 +4,6 @@ TestCase for salt.modules.znc """ - import pytest import salt.modules.znc as znc diff --git a/tests/pytests/unit/modules/test_zpool.py b/tests/pytests/unit/modules/test_zpool.py index 48fcf9e272c..f3256db0b8c 100644 --- a/tests/pytests/unit/modules/test_zpool.py +++ b/tests/pytests/unit/modules/test_zpool.py @@ -469,9 +469,9 @@ def test_split_not_mirror(utils_patch): """ ret = {} ret["stdout"] = "" - ret[ - "stderr" - ] = "Unable to split datapool: Source pool must be composed only of mirrors" + ret["stderr"] = ( + "Unable to split datapool: Source pool must be composed only of mirrors" + ) ret["retcode"] = 1 mock_cmd = MagicMock(return_value=ret) diff --git a/tests/pytests/unit/modules/test_zypperpkg.py b/tests/pytests/unit/modules/test_zypperpkg.py index 1e2d6ea443a..4a6357cc753 100644 --- a/tests/pytests/unit/modules/test_zypperpkg.py +++ b/tests/pytests/unit/modules/test_zypperpkg.py @@ -2,7 +2,6 @@ :codeauthor: Gareth J. Greenaway """ - import os import textwrap diff --git a/tests/pytests/unit/modules/virt/test_domain.py b/tests/pytests/unit/modules/virt/test_domain.py index 1d1a3d1849a..00e74f01d15 100644 --- a/tests/pytests/unit/modules/virt/test_domain.py +++ b/tests/pytests/unit/modules/virt/test_domain.py @@ -1946,9 +1946,11 @@ def test_update_disks(make_mock_vm): ] == 'qemu-img create -f qcow2 "{}" 2048M'.format(added_disk_path) assert mock_chmod.call_args[0][0] == added_disk_path assert [ - ET.fromstring(disk).find("source").get("file") - if str(disk).find(" -1 - else None + ( + ET.fromstring(disk).find("source").get("file") + if str(disk).find(" -1 + else None + ) for disk in ret["disk"]["attached"] ] == [None, os.path.join(root_dir, "my_vm_added.qcow2")] @@ -2018,9 +2020,11 @@ def test_update_disks_existing_block(make_mock_vm): ], ) assert [ - ET.fromstring(disk).find("source").get("file") - if str(disk).find(" -1 - else None + ( + ET.fromstring(disk).find("source").get("file") + if str(disk).find(" -1 + else None + ) for disk in ret["disk"]["attached"] ] == ["/dev/ssd/data"] diff --git a/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py b/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py index 56eecd4bbc2..cc178662b63 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py +++ b/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import glob import logging import os diff --git a/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py b/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py index 9acfc0f141c..7b3366eff8c 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py +++ b/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py @@ -1,6 +1,7 @@ """ This tests policies that are defined in the giant dictionary in the LGPO module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py b/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py index b9d659acb5f..5ce9ce2a4fb 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py +++ b/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import os import pytest diff --git a/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py b/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py index 88b1c05b4e7..4d39311f8e4 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py +++ b/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.cmdmod as cmdmod diff --git a/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py b/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py index 174ca38fb50..2196c7624c3 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py +++ b/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.config diff --git a/tests/pytests/unit/modules/win_lgpo/test_policy_info.py b/tests/pytests/unit/modules/win_lgpo/test_policy_info.py index d0ed3c911a3..a11bf800dc0 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_policy_info.py +++ b/tests/pytests/unit/modules/win_lgpo/test_policy_info.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py b/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py index bedacc237fb..2c3bb255212 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py +++ b/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.win_lgpo as win_lgpo diff --git a/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py b/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py index b7a6618f47e..8d49468792a 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py +++ b/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.cmdmod as cmdmod diff --git a/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py b/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py index 79c8a10393c..ae7a2a55f8a 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py +++ b/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.win_lgpo as win_lgpo diff --git a/tests/pytests/unit/output/test_json_out.py b/tests/pytests/unit/output/test_json_out.py index 229315b31fe..3ade8e44e7c 100644 --- a/tests/pytests/unit/output/test_json_out.py +++ b/tests/pytests/unit/output/test_json_out.py @@ -1,6 +1,7 @@ """ unittests for json outputter """ + import pytest import salt.output.json_out as json_out diff --git a/tests/pytests/unit/output/test_nested.py b/tests/pytests/unit/output/test_nested.py index c56faf89672..4e85ff623cb 100644 --- a/tests/pytests/unit/output/test_nested.py +++ b/tests/pytests/unit/output/test_nested.py @@ -1,6 +1,7 @@ """ Unit tests for the Nested outputter """ + import pytest import salt.output.nested as nested diff --git a/tests/pytests/unit/output/test_yaml_out.py b/tests/pytests/unit/output/test_yaml_out.py index 6a87fd667c2..53380cc2c9a 100644 --- a/tests/pytests/unit/output/test_yaml_out.py +++ b/tests/pytests/unit/output/test_yaml_out.py @@ -1,6 +1,7 @@ """ unittests for yaml outputter """ + import pytest import salt.output.yaml_out as yaml diff --git a/tests/pytests/unit/pillar/test_csvpillar.py b/tests/pytests/unit/pillar/test_csvpillar.py index 82d270b0d43..cbb411ca9c2 100644 --- a/tests/pytests/unit/pillar/test_csvpillar.py +++ b/tests/pytests/unit/pillar/test_csvpillar.py @@ -1,6 +1,5 @@ """test for pillar csvpillar.py""" - import salt.pillar.csvpillar as csvpillar from tests.support.mock import mock_open, patch diff --git a/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py b/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py index 7b703f4f901..8e632649ac1 100644 --- a/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py +++ b/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py @@ -32,7 +32,6 @@ def configure_loader_modules(): def test_check_virtual(): - """UT: nxos module:check_virtual method - return value""" result = nxos_proxy.__virtual__() @@ -40,7 +39,6 @@ def test_check_virtual(): def test_init(): - """UT: nxos module:init method - nxapi proxy""" with patch.object(nxos_proxy, "__opts__", {"proxy": {"connection": "nxapi"}}): @@ -50,7 +48,6 @@ def test_init(): def test_init_opts_none(): - """UT: nxos module:init method - __opts__ connection is None""" with patch.object(nxos_proxy, "__opts__", {"proxy": {"connection": None}}): @@ -60,14 +57,12 @@ def test_init_opts_none(): def test_init_bad_connection_type(): - """UT: nxos module:init method - bad CONNECTION type""" with patch.object(nxos_proxy, "__opts__", {"proxy": {"connection": "unknown"}}): assert not nxos_proxy.init() def test_initialized(): - """UT: nxos module:initialized method - nxapi proxy""" with patch( @@ -78,7 +73,6 @@ def test_initialized(): def test_ping(): - """UT: nxos module:ping method - nxapi proxy""" with patch("salt.proxy.nxos._ping_nxapi", autospec=True) as ping_nxapi: @@ -87,7 +81,6 @@ def test_ping(): def test_grains(): - """UT: nxos module:grains method - nxapi grains""" with patch( @@ -98,7 +91,6 @@ def test_grains(): def test_grains_cache_set(): - """UT: nxos module:grains method - nxapi grains cache set""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {"grains_cache": n9k_grains["nxos"]}): @@ -112,7 +104,6 @@ def test_grains_cache_set(): def test_grains_refresh(): - """UT: nxos module:grains_refresh method - nxapi grains""" device_details = {"grains_cache": None} @@ -125,7 +116,6 @@ def test_grains_refresh(): def test_sendline(): - """UT: nxos module:sendline method - nxapi""" command = "show version" @@ -136,7 +126,6 @@ def test_sendline(): def test_proxy_config(): - """UT: nxos module:proxy_config method - nxapi success path""" commands = ["feature bgp", "router bgp 65535"] @@ -148,7 +137,6 @@ def test_proxy_config(): def test_proxy_config_save_config(): - """UT: nxos module:proxy_config method - nxapi success path""" commands = ["feature bgp", "router bgp 65535"] @@ -160,7 +148,6 @@ def test_proxy_config_save_config(): def test__init_nxapi(): - """UT: nxos module:_init_nxapi method - successful connectinon""" opts = {"proxy": {"arg1": None}} @@ -194,7 +181,6 @@ def test_bad__init_nxapi(): def test__initialized_nxapi(): - """UT: nxos module:_initialized_nxapi method""" result = nxos_proxy._initialized_nxapi() @@ -206,7 +192,6 @@ def test__initialized_nxapi(): def test__ping_nxapi(): - """UT: nxos module:_ping_nxapi method""" result = nxos_proxy._ping_nxapi() @@ -218,7 +203,6 @@ def test__ping_nxapi(): def test__shutdown_nxapi(): - """UT: nxos module:_shutdown_nxapi method""" opts = {"id": "value"} @@ -229,7 +213,6 @@ def test__shutdown_nxapi(): def test__nxapi_request_ssh_return(): - """UT: nxos module:_nxapi_request method - CONNECTION == 'ssh'""" commands = "show version" @@ -240,7 +223,6 @@ def test__nxapi_request_ssh_return(): def test__nxapi_request_connect(): - """UT: nxos module:_nxapi_request method""" commands = "show version" diff --git a/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py b/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py index ef14addbdf9..b6f4f991ad4 100644 --- a/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py +++ b/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py @@ -42,7 +42,6 @@ def configure_loader_modules(): def test_init(): - """UT: nxos module:init method - ssh proxy""" with patch("salt.proxy.nxos._init_ssh", autospec=True) as init_ssh: @@ -51,7 +50,6 @@ def test_init(): def test_init_opts_none(): - """UT: nxos module:init method - __opts__ connection is None""" with patch("salt.proxy.nxos.__opts__", {"proxy": {"connection": None}}): @@ -61,7 +59,6 @@ def test_init_opts_none(): def test_initialized(): - """UT: nxos module:initialized method - ssh proxy""" with patch("salt.proxy.nxos._initialized_ssh", autospec=True) as initialized_ssh: @@ -70,7 +67,6 @@ def test_initialized(): def test_ping(): - """UT: nxos module:ping method - ssh proxy""" with patch("salt.proxy.nxos._ping_ssh", autospec=True) as ping_ssh: @@ -79,7 +75,6 @@ def test_ping(): def test_grains(): - """UT: nxos module:grains method - ssh grains""" with patch( @@ -90,7 +85,6 @@ def test_grains(): def test_sendline(): - """UT: nxos module:sendline method - nxapi""" command = "show version" @@ -101,7 +95,6 @@ def test_sendline(): def test_proxy_config(): - """UT: nxos module:proxy_config method - ssh success path""" commands = ["feature bgp", "router bgp 65535"] @@ -113,7 +106,6 @@ def test_proxy_config(): def test_proxy_config_save_config(): - """UT: nxos module:proxy_config method - ssh success path""" commands = ["feature bgp", "router bgp 65535"] @@ -125,7 +117,6 @@ def test_proxy_config_save_config(): def test_proxy_config_error(): - """UT: nxos module:proxy_config method - CommandExecutionError""" with patch( @@ -156,7 +147,6 @@ def test__init_ssh_device_details(): def test__init_ssh_opts(): - """UT: nxos module:_init_ssh method - successful connectinon""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {}): @@ -174,7 +164,6 @@ def test__init_ssh_opts(): def test__init_ssh_prompt(): - """UT: nxos module:_init_ssh method - prompt regex""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {}): @@ -198,7 +187,6 @@ def test__init_ssh_prompt(): def test__initialized_ssh(): - """UT: nxos module:_initialized_ssh method""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {"initialized": True}): @@ -211,7 +199,6 @@ def test__initialized_ssh(): def test__parse_output_for_errors(): - """UT: nxos module:_parse_output_for_errors method""" data = "% Incomplete command at '^' marker." @@ -246,7 +233,6 @@ def test__parse_output_for_errors(): def test__init_ssh_raise_exception(): - """UT: nxos module:_init_ssh method - raise exception""" class SSHException(Exception): diff --git a/tests/pytests/unit/proxy/test_esxdatacenter.py b/tests/pytests/unit/proxy/test_esxdatacenter.py index bcba6514af5..1142626e675 100644 --- a/tests/pytests/unit/proxy/test_esxdatacenter.py +++ b/tests/pytests/unit/proxy/test_esxdatacenter.py @@ -3,6 +3,7 @@ Tests for esxdatacenter proxy """ + import pytest import salt.exceptions diff --git a/tests/pytests/unit/proxy/test_napalm.py b/tests/pytests/unit/proxy/test_napalm.py index 2a537b8d61e..dbf108b6977 100644 --- a/tests/pytests/unit/proxy/test_napalm.py +++ b/tests/pytests/unit/proxy/test_napalm.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import pytest import salt.proxy.napalm as napalm_proxy diff --git a/tests/pytests/unit/renderers/test_aws_kms.py b/tests/pytests/unit/renderers/test_aws_kms.py index 9770531633f..8562d9f3e16 100644 --- a/tests/pytests/unit/renderers/test_aws_kms.py +++ b/tests/pytests/unit/renderers/test_aws_kms.py @@ -1,6 +1,7 @@ """ Unit tests for AWS KMS Decryption Renderer. """ + import pytest import salt.exceptions diff --git a/tests/pytests/unit/returners/test_elasticsearch_return.py b/tests/pytests/unit/returners/test_elasticsearch_return.py index 9b8940bc8f3..8c711d32c97 100644 --- a/tests/pytests/unit/returners/test_elasticsearch_return.py +++ b/tests/pytests/unit/returners/test_elasticsearch_return.py @@ -1,6 +1,7 @@ """ Test the elasticsearch returner """ + import pytest import salt.returners.elasticsearch_return as elasticsearch_return diff --git a/tests/pytests/unit/returners/test_pgjsonb.py b/tests/pytests/unit/returners/test_pgjsonb.py index 92abcddd7a8..d0c2bf83a5c 100644 --- a/tests/pytests/unit/returners/test_pgjsonb.py +++ b/tests/pytests/unit/returners/test_pgjsonb.py @@ -2,7 +2,6 @@ Unit tests for the PGJsonb returner (pgjsonb). """ - import pytest import salt.returners.pgjsonb as pgjsonb diff --git a/tests/pytests/unit/returners/test_slack_webhook_return.py b/tests/pytests/unit/returners/test_slack_webhook_return.py index 0cfc7df00c0..0846680f6c1 100644 --- a/tests/pytests/unit/returners/test_slack_webhook_return.py +++ b/tests/pytests/unit/returners/test_slack_webhook_return.py @@ -3,6 +3,7 @@ Unit tests for the Slack Webhook Returner. """ + import pytest import salt.returners.slack_webhook_return as slack_webhook diff --git a/tests/pytests/unit/returners/test_smtp_return.py b/tests/pytests/unit/returners/test_smtp_return.py index 67ad2c877f8..61045bb548b 100644 --- a/tests/pytests/unit/returners/test_smtp_return.py +++ b/tests/pytests/unit/returners/test_smtp_return.py @@ -3,6 +3,7 @@ Test SMTP returner """ + import pytest import salt.returners.smtp_return as smtp diff --git a/tests/pytests/unit/returners/test_syslog_return.py b/tests/pytests/unit/returners/test_syslog_return.py index 8f8de24e18e..c4879c4c07f 100644 --- a/tests/pytests/unit/returners/test_syslog_return.py +++ b/tests/pytests/unit/returners/test_syslog_return.py @@ -3,6 +3,7 @@ :codeauthor: :email:`Megan Wilhite (mwilhite@saltstack.com)` """ + import pytest import salt.returners.syslog_return as syslog diff --git a/tests/pytests/unit/returners/test_telegram_return.py b/tests/pytests/unit/returners/test_telegram_return.py index 0502b6975a9..23cbec36ea5 100644 --- a/tests/pytests/unit/returners/test_telegram_return.py +++ b/tests/pytests/unit/returners/test_telegram_return.py @@ -3,6 +3,7 @@ :codeauthor: :email:`Roald Nefs (info@roaldnefs.com)` """ + import pytest import salt.returners.telegram_return as telegram diff --git a/tests/pytests/unit/roster/test_dir.py b/tests/pytests/unit/roster/test_dir.py index 72279119357..aa85ed8f72e 100644 --- a/tests/pytests/unit/roster/test_dir.py +++ b/tests/pytests/unit/roster/test_dir.py @@ -2,7 +2,6 @@ Test the directory roster. """ - import logging import pytest diff --git a/tests/pytests/unit/roster/test_terraform.py b/tests/pytests/unit/roster/test_terraform.py index b79d7985461..596c5723407 100644 --- a/tests/pytests/unit/roster/test_terraform.py +++ b/tests/pytests/unit/roster/test_terraform.py @@ -1,6 +1,7 @@ """ unittests for terraform roster """ + import pathlib import pytest diff --git a/tests/pytests/unit/runners/test_bgp.py b/tests/pytests/unit/runners/test_bgp.py index 4eeb32538e9..620e162a412 100644 --- a/tests/pytests/unit/runners/test_bgp.py +++ b/tests/pytests/unit/runners/test_bgp.py @@ -1,6 +1,7 @@ """ Test the bgp runner """ + import pytest import salt.runners.bgp as bgp diff --git a/tests/pytests/unit/runners/test_fileserver.py b/tests/pytests/unit/runners/test_fileserver.py index a258ace46ca..4ba6d7c0261 100644 --- a/tests/pytests/unit/runners/test_fileserver.py +++ b/tests/pytests/unit/runners/test_fileserver.py @@ -2,7 +2,6 @@ unit tests for the fileserver runner """ - import pytest import salt.loader diff --git a/tests/pytests/unit/runners/test_git_pillar.py b/tests/pytests/unit/runners/test_git_pillar.py index 958d8372360..9edabb64648 100644 --- a/tests/pytests/unit/runners/test_git_pillar.py +++ b/tests/pytests/unit/runners/test_git_pillar.py @@ -2,7 +2,6 @@ unit tests for the git_pillar runner """ - import logging import pytest diff --git a/tests/pytests/unit/runners/test_jobs.py b/tests/pytests/unit/runners/test_jobs.py index a1146e7f7d0..8d9fe3853a7 100644 --- a/tests/pytests/unit/runners/test_jobs.py +++ b/tests/pytests/unit/runners/test_jobs.py @@ -1,6 +1,7 @@ """ unit tests for the jobs runner """ + import pytest import salt.minion diff --git a/tests/pytests/unit/runners/test_network.py b/tests/pytests/unit/runners/test_network.py index 6d16d54eb94..9531d4ff8e0 100644 --- a/tests/pytests/unit/runners/test_network.py +++ b/tests/pytests/unit/runners/test_network.py @@ -1,6 +1,7 @@ """ Unit tests for Network runner """ + import logging import pytest diff --git a/tests/pytests/unit/runners/test_reactor.py b/tests/pytests/unit/runners/test_reactor.py index 545caa5147d..cc8e370f73c 100644 --- a/tests/pytests/unit/runners/test_reactor.py +++ b/tests/pytests/unit/runners/test_reactor.py @@ -2,7 +2,6 @@ unit tests for the reactor runner """ - import logging import pytest diff --git a/tests/pytests/unit/runners/test_spacewalk.py b/tests/pytests/unit/runners/test_spacewalk.py index c6bacd4b117..410b3dc290c 100644 --- a/tests/pytests/unit/runners/test_spacewalk.py +++ b/tests/pytests/unit/runners/test_spacewalk.py @@ -1,6 +1,7 @@ """ Unit tests for Spacewalk runner """ + import salt.runners.spacewalk as spacewalk from tests.support.mock import Mock, call, patch diff --git a/tests/pytests/unit/runners/test_winrepo.py b/tests/pytests/unit/runners/test_winrepo.py index aecdaaf10a4..4245ba453ac 100644 --- a/tests/pytests/unit/runners/test_winrepo.py +++ b/tests/pytests/unit/runners/test_winrepo.py @@ -2,7 +2,6 @@ Test the winrepo runner """ - import textwrap import pytest diff --git a/tests/pytests/unit/runners/vault/test_app_role_auth.py b/tests/pytests/unit/runners/vault/test_app_role_auth.py index 14d5dc77ef7..0680726623c 100644 --- a/tests/pytests/unit/runners/vault/test_app_role_auth.py +++ b/tests/pytests/unit/runners/vault/test_app_role_auth.py @@ -2,7 +2,6 @@ Unit tests for the Vault runner """ - import logging import pytest diff --git a/tests/pytests/unit/runners/vault/test_token_auth.py b/tests/pytests/unit/runners/vault/test_token_auth.py index fcd0ef8058b..034b3db9516 100644 --- a/tests/pytests/unit/runners/vault/test_token_auth.py +++ b/tests/pytests/unit/runners/vault/test_token_auth.py @@ -2,7 +2,6 @@ Unit tests for the Vault runner """ - import logging import pytest diff --git a/tests/pytests/unit/runners/vault/test_vault.py b/tests/pytests/unit/runners/vault/test_vault.py index 3634e862e8e..de15c62f2f4 100644 --- a/tests/pytests/unit/runners/vault/test_vault.py +++ b/tests/pytests/unit/runners/vault/test_vault.py @@ -2,7 +2,6 @@ Unit tests for the Vault runner """ - import logging import pytest diff --git a/tests/pytests/unit/sdb/test_yaml.py b/tests/pytests/unit/sdb/test_yaml.py index 102bf4881b2..d6a505178af 100644 --- a/tests/pytests/unit/sdb/test_yaml.py +++ b/tests/pytests/unit/sdb/test_yaml.py @@ -2,7 +2,6 @@ Test case for the YAML SDB module """ - import salt.sdb.yaml as sdb from tests.support.mock import MagicMock, patch diff --git a/tests/pytests/unit/state/test_state_basic.py b/tests/pytests/unit/state/test_state_basic.py index a8a56fba82b..c76a8b950ad 100644 --- a/tests/pytests/unit/state/test_state_basic.py +++ b/tests/pytests/unit/state/test_state_basic.py @@ -1,6 +1,7 @@ """ Test functions in state.py that are not a part of a class """ + import pytest import salt.state diff --git a/tests/pytests/unit/states/file/test__clean_dir.py b/tests/pytests/unit/states/file/test__clean_dir.py index 43504105a31..7602ba6f93d 100644 --- a/tests/pytests/unit/states/file/test__clean_dir.py +++ b/tests/pytests/unit/states/file/test__clean_dir.py @@ -1,6 +1,7 @@ """ Tests for _clean_dir function """ + import pytest import salt.states.file as file diff --git a/tests/pytests/unit/states/file/test_retention_schedule.py b/tests/pytests/unit/states/file/test_retention_schedule.py index 3e9179afcbf..7fd57195a25 100644 --- a/tests/pytests/unit/states/file/test_retention_schedule.py +++ b/tests/pytests/unit/states/file/test_retention_schedule.py @@ -209,16 +209,14 @@ def test_retention_schedule(): } if test: expected_ret["result"] = None - expected_ret[ - "comment" - ] = "{} backups would have been removed from {}.\n" "".format( - len(deleted_files), fake_name + expected_ret["comment"] = ( + "{} backups would have been removed from {}.\n" + "".format(len(deleted_files), fake_name) ) else: - expected_ret[ - "comment" - ] = "{} backups were removed from {}.\n" "".format( - len(deleted_files), fake_name + expected_ret["comment"] = ( + "{} backups were removed from {}.\n" + "".format(len(deleted_files), fake_name) ) mock_remove.assert_has_calls( [call(os.path.join(fake_name, x)) for x in deleted_files], diff --git a/tests/pytests/unit/states/mysql/test_database.py b/tests/pytests/unit/states/mysql/test_database.py index 4176d85fb88..5eb78a9f318 100644 --- a/tests/pytests/unit/states/mysql/test_database.py +++ b/tests/pytests/unit/states/mysql/test_database.py @@ -1,6 +1,7 @@ """ This test checks mysql_database salt state """ + import pytest import salt.states.mysql_database as mysql_database diff --git a/tests/pytests/unit/states/test_aptpkg.py b/tests/pytests/unit/states/test_aptpkg.py index fb36e377800..843fd4ff88f 100644 --- a/tests/pytests/unit/states/test_aptpkg.py +++ b/tests/pytests/unit/states/test_aptpkg.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.states.aptpkg as aptpkg diff --git a/tests/pytests/unit/states/test_archive.py b/tests/pytests/unit/states/test_archive.py index 178f00b83a1..d7d2171e27e 100644 --- a/tests/pytests/unit/states/test_archive.py +++ b/tests/pytests/unit/states/test_archive.py @@ -2,7 +2,6 @@ :codeauthor: Alexander Schwartz """ - import os import pytest diff --git a/tests/pytests/unit/states/test_aws_sqs.py b/tests/pytests/unit/states/test_aws_sqs.py index dd132c88420..c5f0f68c849 100644 --- a/tests/pytests/unit/states/test_aws_sqs.py +++ b/tests/pytests/unit/states/test_aws_sqs.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.aws_sqs as aws_sqs diff --git a/tests/pytests/unit/states/test_boto_cloudfront.py b/tests/pytests/unit/states/test_boto_cloudfront.py index fef82fcda2c..634d316cbd6 100644 --- a/tests/pytests/unit/states/test_boto_cloudfront.py +++ b/tests/pytests/unit/states/test_boto_cloudfront.py @@ -1,6 +1,7 @@ """ Unit tests for the boto_cloudfront state module. """ + import copy import textwrap diff --git a/tests/pytests/unit/states/test_boto_lc.py b/tests/pytests/unit/states/test_boto_lc.py index ab44a58f586..604af3bd6a7 100644 --- a/tests/pytests/unit/states/test_boto_lc.py +++ b/tests/pytests/unit/states/test_boto_lc.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.boto_lc as boto_lc diff --git a/tests/pytests/unit/states/test_boto_route53.py b/tests/pytests/unit/states/test_boto_route53.py index 7d0f125223b..ff3fce60ef9 100644 --- a/tests/pytests/unit/states/test_boto_route53.py +++ b/tests/pytests/unit/states/test_boto_route53.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.boto_route53 as boto53mod diff --git a/tests/pytests/unit/states/test_boto_sns.py b/tests/pytests/unit/states/test_boto_sns.py index d6fbdcee059..0db5d1db9cb 100644 --- a/tests/pytests/unit/states/test_boto_sns.py +++ b/tests/pytests/unit/states/test_boto_sns.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.boto_sns as boto_sns diff --git a/tests/pytests/unit/states/test_boto_sqs.py b/tests/pytests/unit/states/test_boto_sqs.py index 25175463eda..de8a8e9954f 100644 --- a/tests/pytests/unit/states/test_boto_sqs.py +++ b/tests/pytests/unit/states/test_boto_sqs.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import textwrap import pytest diff --git a/tests/pytests/unit/states/test_bower.py b/tests/pytests/unit/states/test_bower.py index f375f6ab58c..7a019d787b4 100644 --- a/tests/pytests/unit/states/test_bower.py +++ b/tests/pytests/unit/states/test_bower.py @@ -1,6 +1,7 @@ """ :codeauthor: Alexander Pyatkin """ + import pytest import salt.states.bower as bower diff --git a/tests/pytests/unit/states/test_chocolatey.py b/tests/pytests/unit/states/test_chocolatey.py index 5f24d3cb9ae..660ba4b61b2 100644 --- a/tests/pytests/unit/states/test_chocolatey.py +++ b/tests/pytests/unit/states/test_chocolatey.py @@ -1,6 +1,7 @@ """ Unit tests for chocolatey state """ + import logging import pytest diff --git a/tests/pytests/unit/states/test_consul.py b/tests/pytests/unit/states/test_consul.py index 02367458356..816278fa385 100644 --- a/tests/pytests/unit/states/test_consul.py +++ b/tests/pytests/unit/states/test_consul.py @@ -2,7 +2,6 @@ Test case for the consul state module """ - import logging import pytest diff --git a/tests/pytests/unit/states/test_debconfmod.py b/tests/pytests/unit/states/test_debconfmod.py index eae21c97535..3151e84275f 100644 --- a/tests/pytests/unit/states/test_debconfmod.py +++ b/tests/pytests/unit/states/test_debconfmod.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.debconfmod as debconfmod diff --git a/tests/pytests/unit/states/test_drac.py b/tests/pytests/unit/states/test_drac.py index 71f95396e25..57d60f9fdc7 100644 --- a/tests/pytests/unit/states/test_drac.py +++ b/tests/pytests/unit/states/test_drac.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.drac as drac diff --git a/tests/pytests/unit/states/test_elasticsearch.py b/tests/pytests/unit/states/test_elasticsearch.py index b3d55e1df41..89e84b1bb9f 100644 --- a/tests/pytests/unit/states/test_elasticsearch.py +++ b/tests/pytests/unit/states/test_elasticsearch.py @@ -1,6 +1,7 @@ """ :codeauthor: Lukas Raska """ + import pytest import salt.utils.dictdiffer as dictdiffer diff --git a/tests/pytests/unit/states/test_eselect.py b/tests/pytests/unit/states/test_eselect.py index 02eed1a319d..831514e376d 100644 --- a/tests/pytests/unit/states/test_eselect.py +++ b/tests/pytests/unit/states/test_eselect.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.eselect as eselect diff --git a/tests/pytests/unit/states/test_etcd_mod.py b/tests/pytests/unit/states/test_etcd_mod.py index e8fde7c48f1..17df492a1c0 100644 --- a/tests/pytests/unit/states/test_etcd_mod.py +++ b/tests/pytests/unit/states/test_etcd_mod.py @@ -9,7 +9,6 @@ :codeauthor: Caleb Beard """ - import pytest import salt.states.etcd_mod as etcd_state diff --git a/tests/pytests/unit/states/test_ethtool.py b/tests/pytests/unit/states/test_ethtool.py index c0f5267f811..dcf119fb417 100644 --- a/tests/pytests/unit/states/test_ethtool.py +++ b/tests/pytests/unit/states/test_ethtool.py @@ -51,9 +51,9 @@ def test_ethtool_pause(): with patch.dict(ethtool.__opts__, {"test": True}): expected["result"] = None expected["changes"] = {} - expected[ - "comment" - ] = "Device eth0 pause parameters are set to be updated:\nautoneg: off\nrx: off\ntx: off" + expected["comment"] = ( + "Device eth0 pause parameters are set to be updated:\nautoneg: off\nrx: off\ntx: off" + ) ret = ethtool.pause("eth0", autoneg=False, rx=False, tx=False) assert ret == expected mock_set.assert_not_called() diff --git a/tests/pytests/unit/states/test_gem.py b/tests/pytests/unit/states/test_gem.py index 6d3a7ac001d..ab054904593 100644 --- a/tests/pytests/unit/states/test_gem.py +++ b/tests/pytests/unit/states/test_gem.py @@ -2,7 +2,6 @@ Tests of salt.states.gem """ - import pytest import salt.states.gem as gem diff --git a/tests/pytests/unit/states/test_git.py b/tests/pytests/unit/states/test_git.py index 7410239bac1..b9e9f7b6460 100644 --- a/tests/pytests/unit/states/test_git.py +++ b/tests/pytests/unit/states/test_git.py @@ -4,7 +4,6 @@ :codeauthor: Erik Johnson """ - import logging import pytest diff --git a/tests/pytests/unit/states/test_gnomedesktop.py b/tests/pytests/unit/states/test_gnomedesktop.py index 0229e734592..fd089bdc5a5 100644 --- a/tests/pytests/unit/states/test_gnomedesktop.py +++ b/tests/pytests/unit/states/test_gnomedesktop.py @@ -4,7 +4,6 @@ Test cases for salt.states.gnomedesktop """ - import pytest import salt.states.gnomedesktop as gnomedesktop diff --git a/tests/pytests/unit/states/test_grains.py b/tests/pytests/unit/states/test_grains.py index 8015eaf9340..a2df4028244 100644 --- a/tests/pytests/unit/states/test_grains.py +++ b/tests/pytests/unit/states/test_grains.py @@ -1,6 +1,7 @@ """ unit tests for the grains state """ + import contextlib import os diff --git a/tests/pytests/unit/states/test_group.py b/tests/pytests/unit/states/test_group.py index fb13067b00e..f418bcbe789 100644 --- a/tests/pytests/unit/states/test_group.py +++ b/tests/pytests/unit/states/test_group.py @@ -6,8 +6,7 @@ from tests.support.mock import MagicMock, patch __context__ = {} -def ping(): - ... +def ping(): ... @pytest.fixture diff --git a/tests/pytests/unit/states/test_helm.py b/tests/pytests/unit/states/test_helm.py index d7d78432e17..9c91ab74f6c 100644 --- a/tests/pytests/unit/states/test_helm.py +++ b/tests/pytests/unit/states/test_helm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.helm """ - import pytest import salt.states.helm as helm diff --git a/tests/pytests/unit/states/test_ini_manage.py b/tests/pytests/unit/states/test_ini_manage.py index 9f0217b5b40..0401b5761f3 100644 --- a/tests/pytests/unit/states/test_ini_manage.py +++ b/tests/pytests/unit/states/test_ini_manage.py @@ -2,7 +2,6 @@ Test cases for salt.states.ini_manage """ - import copy import os diff --git a/tests/pytests/unit/states/test_iptables.py b/tests/pytests/unit/states/test_iptables.py index cb372f99a64..19e8d6d4150 100644 --- a/tests/pytests/unit/states/test_iptables.py +++ b/tests/pytests/unit/states/test_iptables.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.states.iptables as iptables diff --git a/tests/pytests/unit/states/test_kapacitor.py b/tests/pytests/unit/states/test_kapacitor.py index df748455541..172852f2744 100644 --- a/tests/pytests/unit/states/test_kapacitor.py +++ b/tests/pytests/unit/states/test_kapacitor.py @@ -2,7 +2,6 @@ Test cases for salt.states.kapacitor """ - import pytest import salt.states.kapacitor as kapacitor diff --git a/tests/pytests/unit/states/test_kernelpkg.py b/tests/pytests/unit/states/test_kernelpkg.py index 22b3cbf2db0..7aa35f6a556 100644 --- a/tests/pytests/unit/states/test_kernelpkg.py +++ b/tests/pytests/unit/states/test_kernelpkg.py @@ -2,7 +2,6 @@ Test cases for salt.states.kernelpkg """ - import pytest import salt.states.kernelpkg as kernelpkg diff --git a/tests/pytests/unit/states/test_kmod.py b/tests/pytests/unit/states/test_kmod.py index a4ec3dbc17c..c2b3e2e69d1 100644 --- a/tests/pytests/unit/states/test_kmod.py +++ b/tests/pytests/unit/states/test_kmod.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.kmod as kmod diff --git a/tests/pytests/unit/states/test_layman.py b/tests/pytests/unit/states/test_layman.py index ad3dec64b74..5de229c9f1a 100644 --- a/tests/pytests/unit/states/test_layman.py +++ b/tests/pytests/unit/states/test_layman.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.layman as layman diff --git a/tests/pytests/unit/states/test_ldap.py b/tests/pytests/unit/states/test_ldap.py index bf57549fd9c..99d0e36a36e 100644 --- a/tests/pytests/unit/states/test_ldap.py +++ b/tests/pytests/unit/states/test_ldap.py @@ -7,6 +7,7 @@ was an ugly second implementation. I'm leaving it for now, but this should really be gutted and replaced with something sensible. """ + import copy import logging @@ -239,20 +240,24 @@ def _test_helper(init_db, expected_ret, replace, delete_others=False): "changes", { dn: { - "old": { - attr: vals - for attr, vals in old[dn].items() - if vals != new.get(dn, {}).get(attr, ()) - } - if dn in old - else None, - "new": { - attr: vals - for attr, vals in new[dn].items() - if vals != old.get(dn, {}).get(attr, ()) - } - if dn in new - else None, + "old": ( + { + attr: vals + for attr, vals in old[dn].items() + if vals != new.get(dn, {}).get(attr, ()) + } + if dn in old + else None + ), + "new": ( + { + attr: vals + for attr, vals in new[dn].items() + if vals != old.get(dn, {}).get(attr, ()) + } + if dn in new + else None + ), } for dn in replace if old.get(dn, {}) != new.get(dn, {}) @@ -323,20 +328,24 @@ def _test_helper_add(db, expected_ret, add_items, delete_others=False): "changes", { dn: { - "old": { - attr: vals - for attr, vals in old[dn].items() - if vals != new.get(dn, {}).get(attr, ()) - } - if dn in old - else None, - "new": { - attr: vals - for attr, vals in new[dn].items() - if vals != old.get(dn, {}).get(attr, ()) - } - if dn in new - else None, + "old": ( + { + attr: vals + for attr, vals in old[dn].items() + if vals != new.get(dn, {}).get(attr, ()) + } + if dn in old + else None + ), + "new": ( + { + attr: vals + for attr, vals in new[dn].items() + if vals != old.get(dn, {}).get(attr, ()) + } + if dn in new + else None + ), } for dn in add_items if old.get(dn, {}) != new.get(dn, {}) diff --git a/tests/pytests/unit/states/test_libcloud_dns.py b/tests/pytests/unit/states/test_libcloud_dns.py index 230ecb940d1..92e87531213 100644 --- a/tests/pytests/unit/states/test_libcloud_dns.py +++ b/tests/pytests/unit/states/test_libcloud_dns.py @@ -2,7 +2,6 @@ :codeauthor: Anthony Shaw """ - import pytest import salt.states.libcloud_dns as libcloud_dns diff --git a/tests/pytests/unit/states/test_mount.py b/tests/pytests/unit/states/test_mount.py index 5e4d5274e85..3772cbcfdf0 100644 --- a/tests/pytests/unit/states/test_mount.py +++ b/tests/pytests/unit/states/test_mount.py @@ -1359,9 +1359,9 @@ def test_bind_mount_copy_active_opts(mount_name): ), ): with patch.dict(mount.__opts__, {"test": True}): - ret[ - "comment" - ] = "Remount would be forced because options (nodev,noexec,nosuid) changed" + ret["comment"] = ( + "Remount would be forced because options (nodev,noexec,nosuid) changed" + ) result = mount.mounted( name=name, device=device, diff --git a/tests/pytests/unit/states/test_pip.py b/tests/pytests/unit/states/test_pip.py index 1a71be86ac1..1c5cda4fe14 100644 --- a/tests/pytests/unit/states/test_pip.py +++ b/tests/pytests/unit/states/test_pip.py @@ -1,6 +1,7 @@ """ :codeauthor: Eric Graham """ + import logging import pytest diff --git a/tests/pytests/unit/states/test_ports.py b/tests/pytests/unit/states/test_ports.py index 3c1bded928a..6642392f4e1 100644 --- a/tests/pytests/unit/states/test_ports.py +++ b/tests/pytests/unit/states/test_ports.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import os import pytest diff --git a/tests/pytests/unit/states/test_sysfs.py b/tests/pytests/unit/states/test_sysfs.py index 030af223155..76aca32fda2 100644 --- a/tests/pytests/unit/states/test_sysfs.py +++ b/tests/pytests/unit/states/test_sysfs.py @@ -1,6 +1,7 @@ """ :codeauthor: Piter Punk """ + import pytest import salt.states.sysfs as sysfs diff --git a/tests/pytests/unit/states/test_virtualenv_mod.py b/tests/pytests/unit/states/test_virtualenv_mod.py index 5c2e33b85d0..d614050202e 100644 --- a/tests/pytests/unit/states/test_virtualenv_mod.py +++ b/tests/pytests/unit/states/test_virtualenv_mod.py @@ -4,7 +4,6 @@ Test cases for salt.states.virtualenv_mod """ - import os import pytest diff --git a/tests/pytests/unit/states/test_webutil.py b/tests/pytests/unit/states/test_webutil.py index d8a10f2d7a0..de8041e9770 100644 --- a/tests/pytests/unit/states/test_webutil.py +++ b/tests/pytests/unit/states/test_webutil.py @@ -2,7 +2,6 @@ :codeauthor: Alexander Pyatkin """ - import pytest import salt.states.webutil as htpasswd diff --git a/tests/pytests/unit/states/test_win_lgpo.py b/tests/pytests/unit/states/test_win_lgpo.py index 438b5c38689..cd898843986 100644 --- a/tests/pytests/unit/states/test_win_lgpo.py +++ b/tests/pytests/unit/states/test_win_lgpo.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import copy import pytest diff --git a/tests/pytests/unit/states/test_win_wua.py b/tests/pytests/unit/states/test_win_wua.py index 51e1d9ef987..cc6e169b0f4 100644 --- a/tests/pytests/unit/states/test_win_wua.py +++ b/tests/pytests/unit/states/test_win_wua.py @@ -1,6 +1,7 @@ """ Test the win_wua state module """ + from collections import namedtuple import pytest @@ -337,7 +338,9 @@ def test_installed(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": False}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": { "installed": { @@ -433,7 +436,9 @@ def test_installed_test_mode(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": True}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": {}, "comment": "Updates will be installed:", @@ -493,7 +498,9 @@ def test_installed_already_installed(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": True}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": {}, "comment": "Updates already installed: KB4052623", @@ -593,7 +600,9 @@ def test_removed(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": False}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": { "removed": { @@ -658,7 +667,9 @@ def test_removed_test_mode(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": True}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": {}, "comment": "Updates will be removed:", diff --git a/tests/pytests/unit/states/test_xmpp.py b/tests/pytests/unit/states/test_xmpp.py index bec7224cdf1..fe672be884a 100644 --- a/tests/pytests/unit/states/test_xmpp.py +++ b/tests/pytests/unit/states/test_xmpp.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.states.xmpp as xmpp diff --git a/tests/pytests/unit/states/virt/test_domain.py b/tests/pytests/unit/states/virt/test_domain.py index 091dc5ccce2..c2ddebc7374 100644 --- a/tests/pytests/unit/states/virt/test_domain.py +++ b/tests/pytests/unit/states/virt/test_domain.py @@ -165,7 +165,11 @@ def test_defined_update(test): "initrd": "/root/f8-i386-initrd", "cmdline": "console=ttyS0 ks=http://example.com/f8-i386/os/", } - assert virt.defined("myvm", cpu=2, boot=boot,) == { + assert virt.defined( + "myvm", + cpu=2, + boot=boot, + ) == { "name": "myvm", "changes": {"myvm": {"definition": True, "cpu": True}}, "result": True if not test else None, @@ -262,9 +266,11 @@ def test_running_no_change(test, running): "name": "myvm", "result": True, "changes": {"myvm": {"started": True}} if running == "shutdown" else {}, - "comment": "Domain myvm started" - if running == "shutdown" - else "Domain myvm exists and is running", + "comment": ( + "Domain myvm started" + if running == "shutdown" + else "Domain myvm exists and is running" + ), } if running == "shutdown" and not test: start_mock.assert_called() @@ -426,9 +432,11 @@ def test_running_update(test, running): "name": "myvm", "changes": {"myvm": changes}, "result": True if not test else None, - "comment": "Domain myvm updated" - if running == "running" - else "Domain myvm updated and started", + "comment": ( + "Domain myvm updated" + if running == "running" + else "Domain myvm updated and started" + ), } if running == "shutdown" and not test: start_mock.assert_called() diff --git a/tests/pytests/unit/states/zabbix/test_action.py b/tests/pytests/unit/states/zabbix/test_action.py index 57da6be2684..e12a92fb10d 100644 --- a/tests/pytests/unit/states/zabbix/test_action.py +++ b/tests/pytests/unit/states/zabbix/test_action.py @@ -193,10 +193,10 @@ def test_present_exists(input_params, existing_obj): }, ): ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( + name + ) ) assert zabbix_action.present(name, {}) == ret diff --git a/tests/pytests/unit/states/zabbix/test_valuemap.py b/tests/pytests/unit/states/zabbix/test_valuemap.py index bc589d7bc92..348c00d9011 100644 --- a/tests/pytests/unit/states/zabbix/test_valuemap.py +++ b/tests/pytests/unit/states/zabbix/test_valuemap.py @@ -127,10 +127,10 @@ def test_present_exists(input_params, existing_obj): }, ): ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( + name + ) ) assert zabbix_valuemap.present(name, {}) == ret diff --git a/tests/pytests/unit/test_acl.py b/tests/pytests/unit/test_acl.py index e5788fb846d..6c75b8902d1 100644 --- a/tests/pytests/unit/test_acl.py +++ b/tests/pytests/unit/test_acl.py @@ -2,7 +2,6 @@ Unit tests for salt.acl.ClientACL """ - import pytest from salt import acl diff --git a/tests/pytests/unit/test_config.py b/tests/pytests/unit/test_config.py index cb343cb75eb..7437c8214ed 100644 --- a/tests/pytests/unit/test_config.py +++ b/tests/pytests/unit/test_config.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_config Unit tests for salt's config modulet """ + import salt.config diff --git a/tests/pytests/unit/test_fileclient.py b/tests/pytests/unit/test_fileclient.py index d11f5ac2521..dee9d7901bd 100644 --- a/tests/pytests/unit/test_fileclient.py +++ b/tests/pytests/unit/test_fileclient.py @@ -1,6 +1,7 @@ """ Unit tests for salt.fileclient """ + import salt.config import salt.fileclient as fileclient from tests.support.mock import MagicMock, patch diff --git a/tests/pytests/unit/test_log.py b/tests/pytests/unit/test_log.py index 83d2e9e2cda..3eeee546faf 100644 --- a/tests/pytests/unit/test_log.py +++ b/tests/pytests/unit/test_log.py @@ -8,7 +8,6 @@ Test salt's "hacked" logging """ - import io import logging diff --git a/tests/pytests/unit/test_syspaths.py b/tests/pytests/unit/test_syspaths.py index 0ecb4789a61..66a0bc07596 100644 --- a/tests/pytests/unit/test_syspaths.py +++ b/tests/pytests/unit/test_syspaths.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_syspaths Unit tests for salt's syspaths module """ + import pytest import salt.syspaths diff --git a/tests/pytests/unit/test_version.py b/tests/pytests/unit/test_version.py index 1cb94c619ca..4192cd505b9 100644 --- a/tests/pytests/unit/test_version.py +++ b/tests/pytests/unit/test_version.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_version Test salt's regex git describe version parsing """ + import re import pytest diff --git a/tests/pytests/unit/transport/test_base.py b/tests/pytests/unit/transport/test_base.py index da5a6fa2615..939c2c7ce7d 100644 --- a/tests/pytests/unit/transport/test_base.py +++ b/tests/pytests/unit/transport/test_base.py @@ -1,6 +1,7 @@ """ Unit tests for salt.transport.base. """ + import pytest import salt.transport.base diff --git a/tests/pytests/unit/utils/jinja/conftest.py b/tests/pytests/unit/utils/jinja/conftest.py index 0b77a4fb2f7..4007bfd6ea1 100644 --- a/tests/pytests/unit/utils/jinja/conftest.py +++ b/tests/pytests/unit/utils/jinja/conftest.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.jinja """ + import pytest diff --git a/tests/pytests/unit/utils/jinja/test_jinja.py b/tests/pytests/unit/utils/jinja/test_jinja.py index de8df6067f5..9e1b33c2ff0 100644 --- a/tests/pytests/unit/utils/jinja/test_jinja.py +++ b/tests/pytests/unit/utils/jinja/test_jinja.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.jinja """ + import salt.utils.dateutils # pylint: disable=unused-import from salt.utils.jinja import Markup, indent, tojson diff --git a/tests/pytests/unit/utils/scheduler/conftest.py b/tests/pytests/unit/utils/scheduler/conftest.py index e74b67091bf..a1c997b1234 100644 --- a/tests/pytests/unit/utils/scheduler/conftest.py +++ b/tests/pytests/unit/utils/scheduler/conftest.py @@ -3,7 +3,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import copy import logging diff --git a/tests/pytests/unit/utils/templates/test_jinja.py b/tests/pytests/unit/utils/templates/test_jinja.py index 6d47e6b80d3..99856f65054 100644 --- a/tests/pytests/unit/utils/templates/test_jinja.py +++ b/tests/pytests/unit/utils/templates/test_jinja.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.templates """ + import re from collections import OrderedDict diff --git a/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py b/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py index 9ab74f0377d..a868e9e8996 100644 --- a/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py +++ b/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py @@ -1,6 +1,7 @@ """ Unit tests for salt.utils.templates.py """ + import logging from pathlib import PurePath, PurePosixPath diff --git a/tests/pytests/unit/utils/test_aws.py b/tests/pytests/unit/utils/test_aws.py index c4e32e369a9..22597ffcd8b 100644 --- a/tests/pytests/unit/utils/test_aws.py +++ b/tests/pytests/unit/utils/test_aws.py @@ -4,6 +4,7 @@ Test the salt aws functions """ + import io import os import time diff --git a/tests/pytests/unit/utils/test_cloud.py b/tests/pytests/unit/utils/test_cloud.py index 7edce2000af..88acbee39ad 100644 --- a/tests/pytests/unit/utils/test_cloud.py +++ b/tests/pytests/unit/utils/test_cloud.py @@ -6,7 +6,6 @@ """ - import os import string import tempfile diff --git a/tests/pytests/unit/utils/test_compat.py b/tests/pytests/unit/utils/test_compat.py index b86dea94296..0dacd615eb9 100644 --- a/tests/pytests/unit/utils/test_compat.py +++ b/tests/pytests/unit/utils/test_compat.py @@ -1,6 +1,7 @@ """ Unit tests for salt.utils.compat.py """ + import pytest import salt.utils.compat diff --git a/tests/pytests/unit/utils/test_crypt.py b/tests/pytests/unit/utils/test_crypt.py index 9a7b35f3d2b..ccf2cfbf46e 100644 --- a/tests/pytests/unit/utils/test_crypt.py +++ b/tests/pytests/unit/utils/test_crypt.py @@ -1,6 +1,7 @@ """ Unit tests for salt.utils.crypt.py """ + import pytest import salt.utils.crypt diff --git a/tests/pytests/unit/utils/test_data.py b/tests/pytests/unit/utils/test_data.py index e6a6cdd6185..ee85b0d0a62 100644 --- a/tests/pytests/unit/utils/test_data.py +++ b/tests/pytests/unit/utils/test_data.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.data """ + import builtins import logging diff --git a/tests/pytests/unit/utils/test_files.py b/tests/pytests/unit/utils/test_files.py index ded95093cd2..3f711259cce 100644 --- a/tests/pytests/unit/utils/test_files.py +++ b/tests/pytests/unit/utils/test_files.py @@ -2,7 +2,6 @@ Unit Tests for functions located in salt/utils/files.py """ - import copy import io import os diff --git a/tests/pytests/unit/utils/test_nacl.py b/tests/pytests/unit/utils/test_nacl.py index 77f40d6fbf9..a498efcf6f8 100644 --- a/tests/pytests/unit/utils/test_nacl.py +++ b/tests/pytests/unit/utils/test_nacl.py @@ -1,6 +1,7 @@ """ Unit tests for the salt.utils.nacl module """ + import os import pytest diff --git a/tests/pytests/unit/utils/test_rsax931.py b/tests/pytests/unit/utils/test_rsax931.py index 39bdb7cac30..0cdc1aa1e67 100644 --- a/tests/pytests/unit/utils/test_rsax931.py +++ b/tests/pytests/unit/utils/test_rsax931.py @@ -1,6 +1,7 @@ """ Test the RSA ANSI X9.31 signer and verifier """ + import ctypes import ctypes.util import fnmatch diff --git a/tests/pytests/unit/utils/test_x509.py b/tests/pytests/unit/utils/test_x509.py index f13ac97fb33..ab7384ffde2 100644 --- a/tests/pytests/unit/utils/test_x509.py +++ b/tests/pytests/unit/utils/test_x509.py @@ -1472,9 +1472,11 @@ def test_parse_general_names_rejects_invalid(inpt): ) def test_get_dn(inpt, expected): expected_parsed = [ - cx509.RelativeDistinguishedName({x}) - if not isinstance(x, cx509.RelativeDistinguishedName) - else x + ( + cx509.RelativeDistinguishedName({x}) + if not isinstance(x, cx509.RelativeDistinguishedName) + else x + ) for x in expected ] res = x509._get_dn(inpt) diff --git a/tests/pytests/unit/utils/verify/test_clean_path_link.py b/tests/pytests/unit/utils/verify/test_clean_path_link.py index 8af20f5550a..23857ca1c51 100644 --- a/tests/pytests/unit/utils/verify/test_clean_path_link.py +++ b/tests/pytests/unit/utils/verify/test_clean_path_link.py @@ -1,6 +1,7 @@ """ Ensure salt.utils.clean_path works with symlinked directories and files """ + import ctypes import pytest diff --git a/tests/pytests/unit/utils/verify/test_verify.py b/tests/pytests/unit/utils/verify/test_verify.py index 5dcb90b0857..60171523cb4 100644 --- a/tests/pytests/unit/utils/verify/test_verify.py +++ b/tests/pytests/unit/utils/verify/test_verify.py @@ -257,9 +257,11 @@ def test_max_open_files(caplog): logmsg_chk.format( newmax, mof_test, - mof_test - newmax - if sys.platform.startswith("win") - else mof_h - newmax, + ( + mof_test - newmax + if sys.platform.startswith("win") + else mof_h - newmax + ), ) in caplog.messages ) @@ -279,9 +281,11 @@ def test_max_open_files(caplog): logmsg_crash.format( newmax, mof_test, - mof_test - newmax - if sys.platform.startswith("win") - else mof_h - newmax, + ( + mof_test - newmax + if sys.platform.startswith("win") + else mof_h - newmax + ), ) in caplog.messages ) diff --git a/tests/support/cli_scripts.py b/tests/support/cli_scripts.py index ee18d6856a0..58e54c6ec56 100644 --- a/tests/support/cli_scripts.py +++ b/tests/support/cli_scripts.py @@ -5,7 +5,6 @@ Code to generate Salt CLI scripts for test runs """ - import logging import os diff --git a/tests/support/events.py b/tests/support/events.py index 6a8de36a005..4abd116aeb2 100644 --- a/tests/support/events.py +++ b/tests/support/events.py @@ -3,7 +3,6 @@ ~~~~~~~~~~~~~~~~~~~~ """ - import multiprocessing import os import time diff --git a/tests/support/helpers.py b/tests/support/helpers.py index f3a73090fa7..455c5b747aa 100644 --- a/tests/support/helpers.py +++ b/tests/support/helpers.py @@ -8,6 +8,7 @@ Test support helpers """ + import base64 import builtins import errno diff --git a/tests/support/kernelpkg.py b/tests/support/kernelpkg.py index eada8d931d1..49c1efa5d3a 100644 --- a/tests/support/kernelpkg.py +++ b/tests/support/kernelpkg.py @@ -4,6 +4,7 @@ :maturity: develop .. versionadded:: 2018.3.0 """ + # pylint: disable=invalid-name,no-member diff --git a/tests/support/mixins.py b/tests/support/mixins.py index 53f7e75108b..9560d2d792c 100644 --- a/tests/support/mixins.py +++ b/tests/support/mixins.py @@ -287,9 +287,9 @@ class SaltClientTestCaseMixin(AdaptedConfigurationTestCaseMixin): mopts = self.get_config( self._salt_client_config_file_name_, from_scratch=True ) - RUNTIME_VARS.RUNTIME_CONFIGS[ - "runtime_client" - ] = salt.client.get_local_client(mopts=mopts) + RUNTIME_VARS.RUNTIME_CONFIGS["runtime_client"] = ( + salt.client.get_local_client(mopts=mopts) + ) return RUNTIME_VARS.RUNTIME_CONFIGS["runtime_client"] diff --git a/tests/support/mock.py b/tests/support/mock.py index c050d0bf4e6..79b44083188 100644 --- a/tests/support/mock.py +++ b/tests/support/mock.py @@ -11,6 +11,7 @@ Note: mock >= 2.0.0 required since unittest.mock does not have MagicMock.assert_called in Python < 3.6. """ + # pylint: disable=unused-import,function-redefined,blacklisted-module,blacklisted-external-module diff --git a/tests/support/napalm.py b/tests/support/napalm.py index 58bc45bfb18..bb096189403 100644 --- a/tests/support/napalm.py +++ b/tests/support/napalm.py @@ -4,7 +4,6 @@ Base classes for napalm unit tests :codeauthor: :email:`Anthony Shaw ` """ - from functools import wraps from salt.utils.immutabletypes import freeze diff --git a/tests/support/pytest/helpers.py b/tests/support/pytest/helpers.py index e6752ee7070..5667687e808 100644 --- a/tests/support/pytest/helpers.py +++ b/tests/support/pytest/helpers.py @@ -4,6 +4,7 @@ PyTest helpers functions """ + import logging import os import pathlib diff --git a/tests/support/pytest/loader.py b/tests/support/pytest/loader.py index 2ac99459c2a..7403894d011 100644 --- a/tests/support/pytest/loader.py +++ b/tests/support/pytest/loader.py @@ -4,6 +4,7 @@ Salt's Loader PyTest Mock Support """ + import logging import sys import types diff --git a/tests/support/runtests.py b/tests/support/runtests.py index ce5c9644cd3..046c20bd01f 100644 --- a/tests/support/runtests.py +++ b/tests/support/runtests.py @@ -192,12 +192,16 @@ RUNTIME_VARS = RuntimeVars( TMP_BASEENV_PILLAR_TREE=paths.TMP_PILLAR_TREE, TMP_PRODENV_STATE_TREE=paths.TMP_PRODENV_STATE_TREE, TMP_PRODENV_PILLAR_TREE=paths.TMP_PRODENV_PILLAR_TREE, - SHELL_TRUE_PATH=salt.utils.path.which("true") - if not salt.utils.platform.is_windows() - else "cmd /c exit 0 > nul", - SHELL_FALSE_PATH=salt.utils.path.which("false") - if not salt.utils.platform.is_windows() - else "cmd /c exit 1 > nul", + SHELL_TRUE_PATH=( + salt.utils.path.which("true") + if not salt.utils.platform.is_windows() + else "cmd /c exit 0 > nul" + ), + SHELL_FALSE_PATH=( + salt.utils.path.which("false") + if not salt.utils.platform.is_windows() + else "cmd /c exit 1 > nul" + ), RUNNING_TESTS_USER=this_user(), RUNTIME_CONFIGS={}, CODE_DIR=paths.CODE_DIR, diff --git a/tests/support/unit.py b/tests/support/unit.py index 419e287b92f..7e2aefb43aa 100644 --- a/tests/support/unit.py +++ b/tests/support/unit.py @@ -18,6 +18,7 @@ .. _`unittest2`: https://pypi.python.org/pypi/unittest2 """ + # pylint: disable=unused-import,blacklisted-module,deprecated-method diff --git a/tests/support/xmlunit.py b/tests/support/xmlunit.py index 940bbfe66ae..5b959799cc0 100644 --- a/tests/support/xmlunit.py +++ b/tests/support/xmlunit.py @@ -9,6 +9,7 @@ XML Unit Tests """ + # pylint: disable=wrong-import-order,wrong-import-position diff --git a/tests/support/zfs.py b/tests/support/zfs.py index 31fabe3d059..b9631ac1b6c 100644 --- a/tests/support/zfs.py +++ b/tests/support/zfs.py @@ -5,7 +5,6 @@ ZFS related unit test data structures """ - import salt.utils.zfs from tests.support.mock import MagicMock, patch diff --git a/tests/unit/ext/test_ipaddress.py b/tests/unit/ext/test_ipaddress.py index 474d05192fc..d884ba3d2df 100644 --- a/tests/unit/ext/test_ipaddress.py +++ b/tests/unit/ext/test_ipaddress.py @@ -265,7 +265,7 @@ class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): ("s", "1.2.3.42"), ("", "1.2.3.42"), ] - for (fmt, txt) in v4_pairs: + for fmt, txt in v4_pairs: self.assertEqual(txt, format(v4, fmt)) def test_network_passed_as_address(self): @@ -402,7 +402,7 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): ("", "::102:32a"), ] - for (fmt, txt) in v6_pairs: + for fmt, txt in v6_pairs: self.assertEqual(txt, format(v6, fmt)) def test_network_passed_as_address(self): diff --git a/tests/unit/modules/nxos/nxos_n36k.py b/tests/unit/modules/nxos/nxos_n36k.py index c6e0879665f..3721337158b 100644 --- a/tests/unit/modules/nxos/nxos_n36k.py +++ b/tests/unit/modules/nxos/nxos_n36k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N36KPlatform(NXOSPlatform): - """Cisco Systems N36K Platform Unit Test Object""" chassis = "Nexus3000 N3K-C36180YC-R Chassis" diff --git a/tests/unit/modules/nxos/nxos_n3k.py b/tests/unit/modules/nxos/nxos_n3k.py index 9436978273f..0210f26caee 100644 --- a/tests/unit/modules/nxos/nxos_n3k.py +++ b/tests/unit/modules/nxos/nxos_n3k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N3KPlatform(NXOSPlatform): - """Cisco Systems N3K Platform Unit Test Object""" chassis = "Nexus 3172 Chassis" diff --git a/tests/unit/modules/nxos/nxos_n5k.py b/tests/unit/modules/nxos/nxos_n5k.py index b5f21f2e691..ccaf838658a 100644 --- a/tests/unit/modules/nxos/nxos_n5k.py +++ b/tests/unit/modules/nxos/nxos_n5k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N5KPlatform(NXOSPlatform): - """Cisco Systems N5K Platform Unit Test Object""" chassis = "cisco Nexus 5672UP 16G-FC Chassis" diff --git a/tests/unit/modules/nxos/nxos_n7k.py b/tests/unit/modules/nxos/nxos_n7k.py index 18018748c66..ec7b84768c3 100644 --- a/tests/unit/modules/nxos/nxos_n7k.py +++ b/tests/unit/modules/nxos/nxos_n7k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N7KPlatform(NXOSPlatform): - """Cisco Systems N7K Platform Unit Test Object""" chassis = "Nexus7000 C7010 (10 Slot) Chassis" diff --git a/tests/unit/modules/nxos/nxos_n93k.py b/tests/unit/modules/nxos/nxos_n93k.py index a495da3da05..15517fa524e 100644 --- a/tests/unit/modules/nxos/nxos_n93k.py +++ b/tests/unit/modules/nxos/nxos_n93k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N93KPlatform(NXOSPlatform): - """Cisco Systems N93K Platform Unit Test Object""" chassis = "Nexus9000 C9396PX Chassis" diff --git a/tests/unit/modules/nxos/nxos_n93klxc.py b/tests/unit/modules/nxos/nxos_n93klxc.py index 4f45e3650a9..6cb91a819da 100644 --- a/tests/unit/modules/nxos/nxos_n93klxc.py +++ b/tests/unit/modules/nxos/nxos_n93klxc.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N93KLXCPlatform(NXOSPlatform): - """Cisco Systems N93K (boot mode lxc) Platform Unit Test Object""" chassis = "Nexus9000 C9396PX (LXC) Chassis" diff --git a/tests/unit/modules/nxos/nxos_n95k.py b/tests/unit/modules/nxos/nxos_n95k.py index c249f5e0bb7..1e3146affa6 100644 --- a/tests/unit/modules/nxos/nxos_n95k.py +++ b/tests/unit/modules/nxos/nxos_n95k.py @@ -21,7 +21,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N95KPlatform(NXOSPlatform): - """Cisco Systems N9K Platform Unit Test Object""" chassis = "Nexus9000 C9508 (8 Slot) Chassis" diff --git a/tests/unit/modules/nxos/nxos_platform.py b/tests/unit/modules/nxos/nxos_platform.py index 02cc2736523..22d8c8dc036 100644 --- a/tests/unit/modules/nxos/nxos_platform.py +++ b/tests/unit/modules/nxos/nxos_platform.py @@ -25,7 +25,6 @@ from string import Template class NXOSPlatform: - """Cisco Systems Base Platform Unit Test Object""" chassis = "Unknown NXOS Chassis" @@ -106,7 +105,6 @@ Module Image Running-Version(pri:alt) New-Versi install_all_non_disruptive_success = None def __init__(self, *args, **kwargs): - """ ckimage - current kickstart image cimage - current system image @@ -163,14 +161,12 @@ Module Image Running-Version(pri:alt) New-Versi @staticmethod def templatize(template, values): - """Substitute variables in template with their corresponding values""" return Template(template).substitute(values) @staticmethod def version_from_image(image): - """Given a NXOS image named image decompose to appropriate image version""" ver = None diff --git a/tests/unit/modules/test_boto3_elasticsearch.py b/tests/unit/modules/test_boto3_elasticsearch.py index 0e60a9e0746..4c3156042bf 100644 --- a/tests/unit/modules/test_boto3_elasticsearch.py +++ b/tests/unit/modules/test_boto3_elasticsearch.py @@ -1,6 +1,7 @@ """ Tests for salt.modules.boto3_elasticsearch """ + import datetime import random import string diff --git a/tests/unit/modules/test_boto3_route53.py b/tests/unit/modules/test_boto3_route53.py index 5e7332fbb35..eb19cd5e6c9 100644 --- a/tests/unit/modules/test_boto3_route53.py +++ b/tests/unit/modules/test_boto3_route53.py @@ -1,6 +1,7 @@ """ Tests for salt.modules.boto3_route53 """ + import random import string diff --git a/tests/unit/modules/test_bsd_shadow.py b/tests/unit/modules/test_bsd_shadow.py index b1ea906f7fd..bf659624e3e 100644 --- a/tests/unit/modules/test_bsd_shadow.py +++ b/tests/unit/modules/test_bsd_shadow.py @@ -12,6 +12,7 @@ from tests.support.unit import TestCase shadow = pytest.importorskip("salt.modules.bsd_shadow") + # Although bsd_shadow runs on NetBSD and OpenBSD as well, the mocks are # currently only designed for FreeBSD. @pytest.mark.skip_unless_on_freebsd diff --git a/tests/unit/modules/test_freezer.py b/tests/unit/modules/test_freezer.py index 436ec4b7446..aaa542d0e4a 100644 --- a/tests/unit/modules/test_freezer.py +++ b/tests/unit/modules/test_freezer.py @@ -3,7 +3,6 @@ :platform: Linux """ - import salt.modules.freezer as freezer from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_influxdb08mod.py b/tests/unit/modules/test_influxdb08mod.py index d58d99da138..79cf8542d87 100644 --- a/tests/unit/modules/test_influxdb08mod.py +++ b/tests/unit/modules/test_influxdb08mod.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import salt.modules.influxdb08mod as influx08 from tests.support.mock import MagicMock, patch from tests.support.unit import TestCase diff --git a/tests/unit/modules/test_kernelpkg_linux_apt.py b/tests/unit/modules/test_kernelpkg_linux_apt.py index 92f40f89767..5d6693ec2aa 100644 --- a/tests/unit/modules/test_kernelpkg_linux_apt.py +++ b/tests/unit/modules/test_kernelpkg_linux_apt.py @@ -4,6 +4,7 @@ :maturity: develop .. versionadded:: 2018.3.0 """ + # pylint: disable=invalid-name,no-member import re diff --git a/tests/unit/modules/test_kernelpkg_linux_yum.py b/tests/unit/modules/test_kernelpkg_linux_yum.py index 4005a4897d7..310f1adf362 100644 --- a/tests/unit/modules/test_kernelpkg_linux_yum.py +++ b/tests/unit/modules/test_kernelpkg_linux_yum.py @@ -4,6 +4,7 @@ :maturity: develop .. versionadded:: 2018.3.0 """ + # pylint: disable=invalid-name,no-member import pytest diff --git a/tests/unit/modules/test_kubernetesmod.py b/tests/unit/modules/test_kubernetesmod.py index 4d38d63bb51..049ed53663f 100644 --- a/tests/unit/modules/test_kubernetesmod.py +++ b/tests/unit/modules/test_kubernetesmod.py @@ -1,6 +1,7 @@ """ :codeauthor: Jochen Breuer """ + # pylint: disable=no-value-for-parameter import os from contextlib import contextmanager diff --git a/tests/unit/modules/test_libcloud_compute.py b/tests/unit/modules/test_libcloud_compute.py index a95a64c1bad..15893fefe3b 100644 --- a/tests/unit/modules/test_libcloud_compute.py +++ b/tests/unit/modules/test_libcloud_compute.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import logging import pytest diff --git a/tests/unit/modules/test_libcloud_dns.py b/tests/unit/modules/test_libcloud_dns.py index 87416c98199..77c64fa1ed2 100644 --- a/tests/unit/modules/test_libcloud_dns.py +++ b/tests/unit/modules/test_libcloud_dns.py @@ -1,6 +1,7 @@ """ :codeauthor: Anthony Shaw """ + import pytest import salt.modules.libcloud_dns as libcloud_dns diff --git a/tests/unit/modules/test_libcloud_loadbalancer.py b/tests/unit/modules/test_libcloud_loadbalancer.py index 02ae019759c..69b8ae26117 100644 --- a/tests/unit/modules/test_libcloud_loadbalancer.py +++ b/tests/unit/modules/test_libcloud_loadbalancer.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import pytest import salt.modules.libcloud_loadbalancer as libcloud_loadbalancer diff --git a/tests/unit/modules/test_libcloud_storage.py b/tests/unit/modules/test_libcloud_storage.py index 8f7fd069782..9347e2571c2 100644 --- a/tests/unit/modules/test_libcloud_storage.py +++ b/tests/unit/modules/test_libcloud_storage.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import pytest import salt.modules.libcloud_storage as libcloud_storage diff --git a/tests/unit/modules/test_localemod.py b/tests/unit/modules/test_localemod.py index 83496de3dfd..f378792acef 100644 --- a/tests/unit/modules/test_localemod.py +++ b/tests/unit/modules/test_localemod.py @@ -1,6 +1,7 @@ """ :codeauthor: Rupesh Tare """ + import pytest import salt.modules.localemod as localemod diff --git a/tests/unit/modules/test_memcached.py b/tests/unit/modules/test_memcached.py index b62986f2317..f51c9fb8e8d 100644 --- a/tests/unit/modules/test_memcached.py +++ b/tests/unit/modules/test_memcached.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.memcached as memcached from salt.exceptions import CommandExecutionError, SaltInvocationError from tests.support.mock import MagicMock, patch diff --git a/tests/unit/modules/test_napalm_probes.py b/tests/unit/modules/test_napalm_probes.py index 2ebda0dc84a..c7527142924 100644 --- a/tests/unit/modules/test_napalm_probes.py +++ b/tests/unit/modules/test_napalm_probes.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import salt.modules.napalm_probes as napalm_probes import tests.support.napalm as napalm_test_support from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_napalm_yang_mod.py b/tests/unit/modules/test_napalm_yang_mod.py index 9d711b04ca3..6e5f848fb10 100644 --- a/tests/unit/modules/test_napalm_yang_mod.py +++ b/tests/unit/modules/test_napalm_yang_mod.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import salt.modules.napalm_network as napalm_network import salt.modules.napalm_yang_mod as napalm_yang_mod import tests.support.napalm as napalm_test_support diff --git a/tests/unit/modules/test_netbox.py b/tests/unit/modules/test_netbox.py index a2257068b75..45958e677fb 100644 --- a/tests/unit/modules/test_netbox.py +++ b/tests/unit/modules/test_netbox.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Zach Moody ` """ + import pytest import salt.modules.netbox as netbox diff --git a/tests/unit/modules/test_netscaler.py b/tests/unit/modules/test_netscaler.py index 46b195ec297..d320f0fbe5a 100644 --- a/tests/unit/modules/test_netscaler.py +++ b/tests/unit/modules/test_netscaler.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.netscaler as netscaler from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import MagicMock, patch diff --git a/tests/unit/modules/test_neutron.py b/tests/unit/modules/test_neutron.py index 7fed7bcc121..c6fb5b38445 100644 --- a/tests/unit/modules/test_neutron.py +++ b/tests/unit/modules/test_neutron.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.neutron as neutron from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import MagicMock diff --git a/tests/unit/modules/test_nova.py b/tests/unit/modules/test_nova.py index f9cb3db9490..47fa1d3742d 100644 --- a/tests/unit/modules/test_nova.py +++ b/tests/unit/modules/test_nova.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import salt.modules.nova as nova from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import MagicMock, patch diff --git a/tests/unit/modules/test_nxos.py b/tests/unit/modules/test_nxos.py index 7610abadab0..cedf1e707ff 100644 --- a/tests/unit/modules/test_nxos.py +++ b/tests/unit/modules/test_nxos.py @@ -45,7 +45,6 @@ from tests.unit.modules.nxos.nxos_show_run import ( class NxosTestCase(TestCase, LoaderModuleMockMixin): - """Test cases for salt.modules.nxos""" COPY_RS = "copy running-config startup-config" @@ -58,14 +57,12 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): @staticmethod def test_check_virtual(): - """UT: nxos module:check_virtual method - return value""" result = nxos_module.__virtual__() assert "nxos" in result def test_ping_proxy(self): - """UT: nxos module:ping method - proxy""" with patch("salt.utils.platform.is_proxy", return_value=True, autospec=True): with patch.dict( @@ -75,7 +72,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_ping_native_minion(self): - """UT: nxos module:ping method - proxy""" with patch("salt.utils.platform.is_proxy", return_value=False, autospec=True): @@ -86,7 +82,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_password_return_none(self): - """UT: nxos module:check_password method - return None""" username = "admin" @@ -97,7 +92,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIsNone(result) def test_check_password_password_nxos_comment(self): - """UT: nxos module:check_password method - password_line has '!'""" username = "admin" @@ -112,7 +106,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): reason="compatible crypt method for fake data not available", ) def test_check_password_password_encrypted_false(self): - """UT: nxos module:check_password method - password is not encrypted""" username = "salt_test" @@ -127,7 +120,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_password_password_encrypted_true(self): - """UT: nxos module:check_password method - password is encrypted""" username = "salt_test" @@ -142,7 +134,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_password_password_encrypted_true_negative(self): - """UT: nxos module:check_password method - password is not encrypted""" username = "salt_test" @@ -155,7 +146,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertFalse(result) def test_check_role_true(self): - """UT: nxos module:check_role method - Role configured""" username = "salt_test" @@ -166,7 +156,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_role_false(self): - """UT: nxos module:check_role method - Role not configured""" username = "salt_test" @@ -177,7 +166,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertFalse(result) def test_cmd_any_function(self): - """UT: nxos module:cmd method - check_role function""" with patch.dict( @@ -198,7 +186,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_cmd_function_absent(self): - """UT: nxos module:cmd method - non existent function""" result = nxos_module.cmd( @@ -207,7 +194,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertFalse(result) def test_find_single_match(self): - """UT: nxos module:test_find method - Find single match in running config""" find_pattern = "^vrf context testing$" @@ -220,7 +206,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn(find_string, result) def test_find_multiple_matches(self): - """UT: nxos module:test_find method - Find multiple matches in running config""" find_pattern = "^no logging.*$" @@ -234,7 +219,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(len(result), 7) def test_get_roles_user_not_configured(self): - """UT: nxos module:get_roles method - User not configured""" username = "salt_does_not_exist" @@ -245,7 +229,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, []) def test_get_roles_user_configured(self): - """UT: nxos module:get_roles method - User configured""" username = "salt_test" @@ -260,7 +243,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result.sort(), expected_result.sort()) def test_get_roles_user_configured_no_role(self): - """UT: nxos module:get_roles method - User configured no roles""" username = "salt_test" @@ -271,7 +253,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, []) def test_get_user_configured(self): - """UT: nxos module:get_user method - User configured""" username = "salt_test" @@ -286,7 +267,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_grains(self): - """UT: nxos module:grains method""" nxos_module.DEVICE_DETAILS["grains_cache"] = {} @@ -316,7 +296,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_grains_get_cache(self): - """UT: nxos module:grains method""" expected_grains = { @@ -346,7 +325,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_grains_refresh(self): - """UT: nxos module:grains_refresh method""" expected_grains = { @@ -368,7 +346,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_system_info(self): - """UT: nxos module:system_info method""" expected_grains = { @@ -397,7 +374,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_sendline_invalid_method(self): - """UT: nxos module:sendline method - invalid method""" command = "show version" @@ -409,7 +385,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn("INPUT ERROR", result) def test_sendline_valid_method_proxy(self): - """UT: nxos module:sendline method - valid method over proxy""" command = "show version" @@ -424,7 +399,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn(n9k_show_ver, result) def test_sendline_valid_method_nxapi_uds(self): - """UT: nxos module:sendline method - valid method over nxapi uds""" command = "show version" @@ -440,7 +414,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn(n9k_show_ver, result) def test_show_raw_text_invalid(self): - """UT: nxos module:show method - invalid argument""" command = "show version" @@ -450,7 +423,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn("INPUT ERROR", result) def test_show_raw_text_true(self): - """UT: nxos module:show method - raw_test true""" command = "show version" @@ -463,7 +435,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, n9k_show_ver) def test_show_raw_text_true_multiple_commands(self): - """UT: nxos module:show method - raw_test true multiple commands""" command = "show bgp sessions ; show processes" @@ -475,7 +446,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, data) def test_show_nxapi(self): - """UT: nxos module:show method - nxapi returns info as list""" command = "show version; show interface eth1/1" @@ -491,7 +461,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result[1], n9k_show_ver_int_list[1]) def test_show_nxapi_structured(self): - """UT: nxos module:show method - nxapi returns info as list""" command = "show version; show interface eth1/1" @@ -507,7 +476,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result[1], n9k_show_ver_int_list_structured[1]) def test_show_run(self): - """UT: nxos module:show_run method""" expected_output = n9k_show_running_config_list[0] @@ -518,7 +486,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_show_ver(self): - """UT: nxos module:show_ver method""" expected_output = n9k_show_ver_list[0] @@ -529,7 +496,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_add_config(self): - """UT: nxos module:add_config method""" expected_output = "COMMAND_LIST: feature bgp" @@ -541,7 +507,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_commands(self): - """UT: nxos module:config method - Using commands arg""" commands = ["no feature ospf", ["no feature ospf"]] @@ -573,7 +538,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_commands_template_none(self): - """UT: nxos module:config method - Template engine is None""" commands = ["no feature ospf", ["no feature ospf"]] @@ -605,7 +569,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_commands_string(self): - """UT: nxos module:config method - Using commands arg and output is string""" commands = "no feature ospf" @@ -636,7 +599,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_file(self): - """UT: nxos module:config method - Using config_file arg""" config_file = "salt://bgp_config.txt" @@ -676,7 +638,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_file_error1(self): - """UT: nxos module:config method - Error file not found""" config_file = "salt://bgp_config.txt" @@ -704,7 +665,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): nxos_module.config(config_file=config_file) def test_config_nxos_error_ssh(self): - """UT: nxos module:config method - nxos device error over ssh transport""" commands = ["feature bgp", "router bgp 57"] @@ -740,7 +700,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_commands_error(self): - """UT: nxos module:config method - Mandatory arg commands not specified""" commands = None @@ -768,7 +727,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): nxos_module.config(commands=commands) def test_config_file_error2(self): - """UT: nxos module:config method - Mandatory arg config_file not specified""" config_file = None @@ -796,7 +754,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): nxos_module.config(config_file=config_file) def test_delete_config(self): - """UT: nxos module:delete_config method""" for lines in ["feature bgp", ["feature bgp"]]: @@ -806,7 +763,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, nxos_module.config.return_value) def test_remove_user(self): - """UT: nxos module:remove_user method""" with patch("salt.modules.nxos.config", autospec=True): @@ -815,7 +771,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, nxos_module.config.return_value) def test_replace(self): - """UT: nxos module:replace method""" old_value = "feature bgp" @@ -837,7 +792,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result["new"], ["feature ospf"]) def test_replace_full_match_true(self): - """UT: nxos module:replace method - full match true""" old_value = "feature bgp" @@ -859,7 +813,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result["new"], ["feature ospf"]) def test_replace_no_match(self): - """UT: nxos module:replace method - no match""" old_value = "feature does_not_exist" @@ -881,7 +834,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result["new"], []) def test_save_running_config(self): - """UT: nxos module:save_running_config method""" with patch( @@ -891,7 +843,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, save_running_config) def test_set_password_enc_false_cs_none(self): - """UT: nxos module:set_password method - encrypted False, crypt_salt None""" username = "devops" @@ -916,7 +867,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_enc_false_cs_set(self): - """UT: nxos module:set_password method - encrypted False, crypt_salt set""" username = "devops" @@ -944,7 +894,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_enc_true(self): - """UT: nxos module:set_password method - encrypted True""" username = "devops" @@ -968,7 +917,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_role_none(self): - """UT: nxos module:set_password method - role none""" username = "devops" @@ -993,7 +941,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_blowfish_crypt(self): - """UT: nxos module:set_password method - role none""" with self.assertRaises(SaltInvocationError): @@ -1002,7 +949,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): ) def test_set_role(self): - """UT: nxos module:save_running_config method""" username = "salt_test" @@ -1013,7 +959,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, set_role) def test_unset_role(self): - """UT: nxos module:save_running_config method""" username = "salt_test" @@ -1024,7 +969,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, unset_role) def test_configure_device(self): - """UT: nxos module:_configure_device method""" with patch("salt.utils.platform.is_proxy", autospec=True, return_value=True): @@ -1043,7 +987,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, "configured") def test_nxapi_config(self): - """UT: nxos module:_nxapi_config method""" mock_cmd = MagicMock(return_value={"nxos": {"save_config": False}}) @@ -1057,7 +1000,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, [["show version"], "router_data"]) def test_nxapi_config_failure(self): - """UT: nxos module:_nxapi_config method""" side_effect = ["Failure", "saved_data"] @@ -1073,7 +1015,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, [["show bad_command"], "Failure"]) def test_nxapi_request_proxy(self): - """UT: nxos module:_nxapi_request method - proxy""" with patch("salt.utils.platform.is_proxy", autospec=True, return_value=True): @@ -1087,7 +1028,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, "router_data") def test_nxapi_request_no_proxy(self): - """UT: nxos module:_nxapi_request method - no proxy""" with patch("salt.utils.platform.is_proxy", autospec=True, return_value=False): diff --git a/tests/unit/modules/test_nxos_upgrade.py b/tests/unit/modules/test_nxos_upgrade.py index 1b6be938ef4..1c0c5013caf 100644 --- a/tests/unit/modules/test_nxos_upgrade.py +++ b/tests/unit/modules/test_nxos_upgrade.py @@ -35,14 +35,12 @@ from tests.unit.modules.nxos.nxos_n95k import N95KPlatform class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): - """Test cases for salt.modules.nxos_upgrade""" platform_list = None @staticmethod def assert_platform_upgrade(condition, platform): - """Assert platform upgrade condition and display appropriate chassis & images upon assertion failure""" assert bool(condition), "{}: Upgrade {} -> {}".format( @@ -50,7 +48,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): ) def setup_loader_modules(self): - """Define list of platforms for Unit Test""" self.platform_list = [ @@ -81,7 +78,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): @staticmethod def test_check_upgrade_impact_input_validation(): - """UT: nxos_upgrade module:check_upgrade_impact method - input validation""" result = nxos_upgrade.check_upgrade_impact("dummy-platform-image.bin", issu=1) @@ -89,14 +85,12 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): @staticmethod def test_upgrade_input_validation(): - """UT: nxos_upgrade module:upgrade method - input validation""" result = nxos_upgrade.upgrade("dummy-platform-image.bin", issu=1) assert "Input Error" in result def test_check_upgrade_impact_backend_processing_error_500(self): - """UT: nxos_upgrade module:check_upgrade_impact method - error HTTP code 500""" for platform in self.platform_list: @@ -116,7 +110,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_internal_server_error_400_invalid_command(self): - """UT: nxos_upgrade module:check_upgrade_impact method - invalid command error HTTP code 400""" for platform in self.platform_list: @@ -134,7 +127,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_internal_server_error_400_in_progress(self): - """UT: nxos_upgrade module:check_upgrade_impact method - in-progress error HTTP code 400""" for platform in self.platform_list: @@ -152,7 +144,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_internal_server_error_500(self): - """UT: nxos_upgrade module:check_upgrade_impact method - internal server error HTTP code 500""" for platform in self.platform_list: @@ -176,7 +167,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_non_disruptive_success(self): - """UT: nxos_upgrade module:check_upgrade_impact method - non-disruptive success""" for platform in self.platform_list: @@ -197,7 +187,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["module_data"], platform) def test_check_upgrade_impact_disruptive_success(self): - """UT: nxos_upgrade module:check_upgrade_impact method - disruptive success""" for platform in self.platform_list: @@ -225,7 +214,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["module_data"], platform) def test_upgrade_show_install_all_impact_no_module_data(self): - """UT: nxos_upgrade module: upgrade method - no module data""" for platform in self.platform_list: @@ -245,7 +233,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): ) def test_upgrade_invalid_command(self): - """UT: nxos_upgrade module:upgrade method - invalid command""" for platform in self.platform_list: @@ -259,7 +246,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_in_progress(self): - """UT: nxos_upgrade module:upgrade method - in-progress""" for platform in self.platform_list: @@ -277,7 +263,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_in_progress_terminal_dont_ask(self): - """UT: nxos_upgrade module:upgrade method - in-progress (terminal don't-ask)""" for platform in self.platform_list: @@ -298,7 +283,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_in_progress_sans_terminal_dont_ask(self): - """UT: nxos_upgrade module:upgrade method - in-progress (sans terminal don't-ask)""" for platform in self.platform_list: @@ -316,7 +300,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_internal_server_error_500(self): - """UT: nxos_upgrade module:upgrade method - internal server error 500""" for platform in self.platform_list: @@ -337,7 +320,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_all_disruptive(self): - """UT: nxos_upgrade module:upgrade method - install all disruptive""" for platform in self.platform_list: @@ -367,7 +349,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): ) def test_upgrade_install_all_non_disruptive(self): - """UT: nxos_upgrade module:upgrade method - install all non-disruptive""" for platform in self.platform_list: @@ -390,7 +371,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["succeeded"], platform) def test_upgrade_CommandExecutionError_Exception(self): - """UT: nxos_upgrade module:upgrade method - raise CommandExecutionError exception #1""" for platform in self.platform_list: @@ -418,7 +398,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_CommandExecutionError_Exception2(self): - """UT: nxos_upgrade module:upgrade method - raise CommandExecutionError exception #2""" for platform in self.platform_list: @@ -454,7 +433,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["succeeded"], platform) def test_upgrade_NxosError_Exception(self): - """UT: nxos_upgrade module:upgrade method - raise NxosError exception""" for platform in self.platform_list: @@ -485,7 +463,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["succeeded"], platform) def test_upgrade_NxosError_Exception2(self): - """UT: nxos_upgrade module:upgrade method - raise NxosError exception #2""" for platform in self.platform_list: diff --git a/tests/unit/modules/test_openstack_config.py b/tests/unit/modules/test_openstack_config.py index 56976992c21..d014547160d 100644 --- a/tests/unit/modules/test_openstack_config.py +++ b/tests/unit/modules/test_openstack_config.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.openstack_config as openstack_config from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_opkg.py b/tests/unit/modules/test_opkg.py index d1df495db4b..6242f5fa31a 100644 --- a/tests/unit/modules/test_opkg.py +++ b/tests/unit/modules/test_opkg.py @@ -51,9 +51,9 @@ class OpkgTestCase(TestCase, LoaderModuleMockMixin): @classmethod def tearDownClass(cls): - cls.opkg_vim_info = ( - cls.opkg_vim_files - ) = cls.installed = cls.removed = cls.packages = None + cls.opkg_vim_info = cls.opkg_vim_files = cls.installed = cls.removed = ( + cls.packages + ) = None def setup_loader_modules(self): # pylint: disable=no-self-use """ diff --git a/tests/unit/modules/test_parted_partition.py b/tests/unit/modules/test_parted_partition.py index b164569c0c4..72fdded4af0 100644 --- a/tests/unit/modules/test_parted_partition.py +++ b/tests/unit/modules/test_parted_partition.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import salt.modules.parted_partition as parted from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_rh_ip.py b/tests/unit/modules/test_rh_ip.py index d061978ae35..0a38a24f942 100644 --- a/tests/unit/modules/test_rh_ip.py +++ b/tests/unit/modules/test_rh_ip.py @@ -791,9 +791,7 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): "lacp_rate={}".format( "1" if lacp_rate == "fast" - else "0" - if lacp_rate == "slow" - else lacp_rate + else "0" if lacp_rate == "slow" else lacp_rate ), "miimon=100", "mode=4", diff --git a/tests/unit/modules/test_snapper.py b/tests/unit/modules/test_snapper.py index 0729ad9a1ef..2ca4250e642 100644 --- a/tests/unit/modules/test_snapper.py +++ b/tests/unit/modules/test_snapper.py @@ -4,6 +4,7 @@ Unit tests for the Snapper module :codeauthor: Duncan Mac-Vicar P. :codeauthor: Pablo Suárez Hernández """ + import pytest import salt.modules.snapper as snapper diff --git a/tests/unit/modules/test_sqlite3.py b/tests/unit/modules/test_sqlite3.py index 1b534e7d963..8b69855dcce 100644 --- a/tests/unit/modules/test_sqlite3.py +++ b/tests/unit/modules/test_sqlite3.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.sqlite3 as sqlite3 from tests.support.mixins import LoaderModuleMockMixin from tests.support.unit import TestCase diff --git a/tests/unit/modules/test_supervisord.py b/tests/unit/modules/test_supervisord.py index 1d4ce112f27..8bcae14288e 100644 --- a/tests/unit/modules/test_supervisord.py +++ b/tests/unit/modules/test_supervisord.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.supervisord as supervisord from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_sysmod.py b/tests/unit/modules/test_sysmod.py index 125f17d8606..79711787084 100644 --- a/tests/unit/modules/test_sysmod.py +++ b/tests/unit/modules/test_sysmod.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.sysmod as sysmod from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import patch diff --git a/tests/unit/modules/test_systemd_service.py b/tests/unit/modules/test_systemd_service.py index f07773925fe..5e3715726cc 100644 --- a/tests/unit/modules/test_systemd_service.py +++ b/tests/unit/modules/test_systemd_service.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import os import pytest diff --git a/tests/unit/modules/test_twilio_notify.py b/tests/unit/modules/test_twilio_notify.py index 682cb7f7711..4785e4a974d 100644 --- a/tests/unit/modules/test_twilio_notify.py +++ b/tests/unit/modules/test_twilio_notify.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.twilio_notify as twilio_notify diff --git a/tests/unit/modules/test_useradd.py b/tests/unit/modules/test_useradd.py index bc7903dd5bb..533e3644b3e 100644 --- a/tests/unit/modules/test_useradd.py +++ b/tests/unit/modules/test_useradd.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.useradd as useradd diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py index 2fee41f8bd9..374429c7733 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py @@ -1831,18 +1831,22 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): ret = virt._diff_disk_lists(old_disks, new_disks) self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["unchanged"] ], [], ) self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["new"] ], ["/path/to/img3.qcow2", "/path/to/img0.qcow2", "/path/to/img4.qcow2", None], @@ -1853,9 +1857,11 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): ) self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["sorted"] ], ["/path/to/img3.qcow2", "/path/to/img0.qcow2", "/path/to/img4.qcow2", None], @@ -1863,9 +1869,11 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(ret["new"][1].find("target").get("bus"), "virtio") self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["deleted"] ], [ @@ -3501,9 +3509,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): }, virt.update("vm_with_memtune_param", mem=memtune_new_val), ) - self.assertEqual( - domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2) - ) + self.assertEqual(domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2)) setxml = ET.fromstring(define_mock.call_args[0][0]) self.assertEqual( @@ -3569,9 +3575,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): }, virt.update("vm_with_memtune_param", mem=max_swap_none), ) - self.assertEqual( - domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2) - ) + self.assertEqual(domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2)) setxml = ET.fromstring(define_mock.call_args[0][0]) self.assertEqual( diff --git a/tests/unit/modules/test_vsphere.py b/tests/unit/modules/test_vsphere.py index 7dcb13e4d30..1bb61e8e4e7 100644 --- a/tests/unit/modules/test_vsphere.py +++ b/tests/unit/modules/test_vsphere.py @@ -4,6 +4,7 @@ Tests for functions in salt.modules.vsphere """ + import pytest import salt.modules.vsphere as vsphere diff --git a/tests/unit/modules/test_win_system.py b/tests/unit/modules/test_win_system.py index 9a217c93d0e..ea73661dc39 100644 --- a/tests/unit/modules/test_win_system.py +++ b/tests/unit/modules/test_win_system.py @@ -633,6 +633,7 @@ class WinSystemTestCase(TestCase, LoaderModuleMockMixin): the WMI Class Win32_Processor. Older versions of Windows are missing this property """ + # Create a mock processor class that does not have the # NumberOfCoresEnabled property class MockWMIProcessor: diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py index 22137a2544f..4a8ec916f5b 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py @@ -2,7 +2,6 @@ :codeauthor: Bo Maryniuk """ - import configparser import errno import io diff --git a/tests/unit/states/test_group.py b/tests/unit/states/test_group.py index b9bf3434e72..eaa1c61cf8f 100644 --- a/tests/unit/states/test_group.py +++ b/tests/unit/states/test_group.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import salt.states.group as group from salt.utils.odict import OrderedDict from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/states/test_module.py b/tests/unit/states/test_module.py index a705bd30285..0543ff87824 100644 --- a/tests/unit/states/test_module.py +++ b/tests/unit/states/test_module.py @@ -2,7 +2,6 @@ :codeauthor: Nicole Thomas (nicole@saltstack.com) """ - import logging from inspect import ArgSpec diff --git a/tests/unit/states/test_syslog_ng.py b/tests/unit/states/test_syslog_ng.py index f367df58b17..132d95ad903 100644 --- a/tests/unit/states/test_syslog_ng.py +++ b/tests/unit/states/test_syslog_ng.py @@ -2,7 +2,6 @@ Test module for syslog_ng state """ - import os import re import tempfile diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 5cc58c273d0..08b5684a1d7 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -1,6 +1,7 @@ """ Unit tests for salt.config """ + import logging import os import textwrap diff --git a/tests/unit/test_zypp_plugins.py b/tests/unit/test_zypp_plugins.py index 64bc86b49d3..2bfbeab15c9 100644 --- a/tests/unit/test_zypp_plugins.py +++ b/tests/unit/test_zypp_plugins.py @@ -1,6 +1,7 @@ """ :codeauthor: Bo Maryniuk """ + import imp # pylint: disable=deprecated-module import os diff --git a/tests/unit/transport/test_ipc.py b/tests/unit/transport/test_ipc.py index 4a159ea8efb..91ad57d312b 100644 --- a/tests/unit/transport/test_ipc.py +++ b/tests/unit/transport/test_ipc.py @@ -1,6 +1,7 @@ """ :codeauthor: Mike Place """ + import errno import logging import os diff --git a/tests/unit/utils/test_color.py b/tests/unit/utils/test_color.py index b80b2e4eaf1..741db780a23 100644 --- a/tests/unit/utils/test_color.py +++ b/tests/unit/utils/test_color.py @@ -2,7 +2,6 @@ Unit tests for salt.utils.color.py """ - import salt.utils.color from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_decorators.py b/tests/unit/utils/test_decorators.py index 21992ccacc4..e3be199a028 100644 --- a/tests/unit/utils/test_decorators.py +++ b/tests/unit/utils/test_decorators.py @@ -3,7 +3,6 @@ unit.utils.decorators_test """ - import inspect import salt.utils.decorators as decorators diff --git a/tests/unit/utils/test_doc.py b/tests/unit/utils/test_doc.py index 62be2d15880..31088ac0831 100644 --- a/tests/unit/utils/test_doc.py +++ b/tests/unit/utils/test_doc.py @@ -2,7 +2,6 @@ Unit Tests for functions located in salt.utils.doc.py. """ - import salt.utils.doc from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_environment.py b/tests/unit/utils/test_environment.py index d36de65a33d..54972226994 100644 --- a/tests/unit/utils/test_environment.py +++ b/tests/unit/utils/test_environment.py @@ -1,6 +1,7 @@ """ Test case for utils/__init__.py """ + import salt.utils.environment from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_extend.py b/tests/unit/utils/test_extend.py index d96f588decc..94a9a92ca51 100644 --- a/tests/unit/utils/test_extend.py +++ b/tests/unit/utils/test_extend.py @@ -4,6 +4,7 @@ Test the salt extend script, leave templates/test alone to keep this working! """ + import os import shutil from datetime import date diff --git a/tests/unit/utils/test_filebuffer.py b/tests/unit/utils/test_filebuffer.py index b88a2f4fc56..5f0fc0f3fdb 100644 --- a/tests/unit/utils/test_filebuffer.py +++ b/tests/unit/utils/test_filebuffer.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import os from salt.utils.filebuffer import BufferedReader, InvalidFileMode diff --git a/tests/unit/utils/test_immutabletypes.py b/tests/unit/utils/test_immutabletypes.py index 745f9b933ed..28afcaac698 100644 --- a/tests/unit/utils/test_immutabletypes.py +++ b/tests/unit/utils/test_immutabletypes.py @@ -8,7 +8,6 @@ Test salt.utils.immutabletypes """ - import salt.utils.immutabletypes as immutabletypes from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_jid.py b/tests/unit/utils/test_jid.py index f6749228304..1409334c33f 100644 --- a/tests/unit/utils/test_jid.py +++ b/tests/unit/utils/test_jid.py @@ -2,7 +2,6 @@ Tests for salt.utils.jid """ - import datetime import os diff --git a/tests/unit/utils/test_job.py b/tests/unit/utils/test_job.py index 3d25719ade3..2e824e02351 100644 --- a/tests/unit/utils/test_job.py +++ b/tests/unit/utils/test_job.py @@ -2,7 +2,6 @@ unit tests for salt.utils.job """ - import salt.minion import salt.utils.job as job from tests.support.mock import patch diff --git a/tests/unit/utils/test_mac_utils.py b/tests/unit/utils/test_mac_utils.py index 9de2b56a844..609c939cd8d 100644 --- a/tests/unit/utils/test_mac_utils.py +++ b/tests/unit/utils/test_mac_utils.py @@ -1,6 +1,7 @@ """ mac_utils tests """ + import os import plistlib import subprocess diff --git a/tests/unit/utils/test_msgpack.py b/tests/unit/utils/test_msgpack.py index 4c41d212d47..90ad80d235f 100644 --- a/tests/unit/utils/test_msgpack.py +++ b/tests/unit/utils/test_msgpack.py @@ -1,6 +1,7 @@ """ Test the MessagePack utility """ + import inspect import os import pprint diff --git a/tests/unit/utils/test_proxy.py b/tests/unit/utils/test_proxy.py index 1c9a34ede31..a2ea8a6b660 100644 --- a/tests/unit/utils/test_proxy.py +++ b/tests/unit/utils/test_proxy.py @@ -3,7 +3,6 @@ :codeauthor: :email:`Gareth J. Greenaway ` """ - import salt.utils.proxy from tests.support.mock import patch from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_roster_matcher.py b/tests/unit/utils/test_roster_matcher.py index d49bc29f1de..b3ce554c837 100644 --- a/tests/unit/utils/test_roster_matcher.py +++ b/tests/unit/utils/test_roster_matcher.py @@ -1,6 +1,7 @@ """ Test generic roster matching utility. """ + import os import pytest diff --git a/tests/unit/utils/test_sdb.py b/tests/unit/utils/test_sdb.py index 87886cbc521..614a7173481 100644 --- a/tests/unit/utils/test_sdb.py +++ b/tests/unit/utils/test_sdb.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Vernon Cole ` """ - import os import salt.utils.sdb as sdb diff --git a/tests/unit/utils/test_state.py b/tests/unit/utils/test_state.py index 1b533e494f2..cae261d2052 100644 --- a/tests/unit/utils/test_state.py +++ b/tests/unit/utils/test_state.py @@ -2,7 +2,6 @@ Unit Tests for functions located in salt.utils.state.py. """ - import copy import textwrap diff --git a/tests/unit/utils/test_thin.py b/tests/unit/utils/test_thin.py index 28f26824118..f5a8d384d3a 100644 --- a/tests/unit/utils/test_thin.py +++ b/tests/unit/utils/test_thin.py @@ -1395,7 +1395,7 @@ class SSHThinTestCase(TestCase): thin_dir = venv.venv_dir / "thin" thin_archive = thin_dir / "thin.tgz" tar = tarfile.open(str(thin_archive)) - tar.extractall(str(thin_dir)) + tar.extractall(str(thin_dir)) # nosec tar.close() ret = venv.run( venv.venv_python, diff --git a/tests/unit/utils/test_vmware.py b/tests/unit/utils/test_vmware.py index 5294897c023..697171a067c 100644 --- a/tests/unit/utils/test_vmware.py +++ b/tests/unit/utils/test_vmware.py @@ -3701,9 +3701,9 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def setUp(self): self.mock_si = MagicMock() self.mock_lic_assign_mgr = MagicMock() - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(return_value=self.mock_lic_assign_mgr) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(return_value=self.mock_lic_assign_mgr) + ) def tearDown(self): for attr in ("mock_si", "mock_lic_assign_mgr"): @@ -3712,9 +3712,9 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def test_raise_no_permission(self): exc = vim.fault.NoPermission() exc.privilegeId = "Fake privilege" - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(side_effect=exc) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(side_effect=exc) + ) with self.assertRaises(VMwareApiError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual( @@ -3725,9 +3725,9 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def test_raise_vim_fault(self): exc = vim.fault.VimFault() exc.msg = "VimFault msg" - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(side_effect=exc) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(side_effect=exc) + ) with self.assertRaises(VMwareApiError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual(excinfo.exception.strerror, "VimFault msg") @@ -3735,17 +3735,17 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def test_raise_runtime_fault(self): exc = vmodl.RuntimeFault() exc.msg = "RuntimeFault msg" - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(side_effect=exc) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(side_effect=exc) + ) with self.assertRaises(VMwareRuntimeError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual(excinfo.exception.strerror, "RuntimeFault msg") def test_empty_license_assignment_manager(self): - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(return_value=None) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(return_value=None) + ) with self.assertRaises(VMwareObjectRetrievalError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual( diff --git a/tests/unit/utils/test_vsan.py b/tests/unit/utils/test_vsan.py index 8231776d694..fe2cd6cf5c9 100644 --- a/tests/unit/utils/test_vsan.py +++ b/tests/unit/utils/test_vsan.py @@ -3,6 +3,7 @@ Tests functions in salt.utils.vsan """ + import logging import pytest diff --git a/tests/unit/utils/test_win_chcp.py b/tests/unit/utils/test_win_chcp.py index 7fa0f0c35a8..b93e38f6b92 100644 --- a/tests/unit/utils/test_win_chcp.py +++ b/tests/unit/utils/test_win_chcp.py @@ -1,6 +1,7 @@ """ Test win_chcp """ + import pytest from salt.exceptions import CodePageError diff --git a/tests/unit/utils/test_xmlutil.py b/tests/unit/utils/test_xmlutil.py index d9a4ae5cc0c..4170cd80ffe 100644 --- a/tests/unit/utils/test_xmlutil.py +++ b/tests/unit/utils/test_xmlutil.py @@ -2,6 +2,7 @@ tests.unit.xmlutil_test ~~~~~~~~~~~~~~~~~~~~ """ + import xml.etree.ElementTree as ET import salt.utils.xmlutil as xml diff --git a/tests/unit/utils/test_yamlencoding.py b/tests/unit/utils/test_yamlencoding.py index 179b7067cd1..6e0876cbe83 100644 --- a/tests/unit/utils/test_yamlencoding.py +++ b/tests/unit/utils/test_yamlencoding.py @@ -2,7 +2,6 @@ Tests for salt.utils.yamlencoding """ - import salt.utils.yaml import salt.utils.yamlencoding from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_zeromq.py b/tests/unit/utils/test_zeromq.py index 1dcd69af997..fdb4faaaeb1 100644 --- a/tests/unit/utils/test_zeromq.py +++ b/tests/unit/utils/test_zeromq.py @@ -1,6 +1,7 @@ """ Test salt.utils.zeromq """ + import pytest import zmq diff --git a/tests/unit/utils/test_zfs.py b/tests/unit/utils/test_zfs.py index 253710f94fe..cdde04336de 100644 --- a/tests/unit/utils/test_zfs.py +++ b/tests/unit/utils/test_zfs.py @@ -9,7 +9,6 @@ Tests for the zfs utils library .. versionadded:: 2018.3.1 """ - import salt.utils.zfs as zfs from salt.utils.odict import OrderedDict from tests.support.mock import MagicMock, patch diff --git a/tools/changelog.py b/tools/changelog.py index 99c81c40082..ab6a4e79de6 100644 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -1,6 +1,7 @@ """ These commands are used manage Salt's changelog. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/ci.py b/tools/ci.py index 695adbc1204..f2126b7fa9a 100644 --- a/tools/ci.py +++ b/tools/ci.py @@ -1,6 +1,7 @@ """ These commands are used in the CI pipeline. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/docs.py b/tools/docs.py index b36e676d974..6e5ad281c12 100644 --- a/tools/docs.py +++ b/tools/docs.py @@ -1,6 +1,7 @@ """ These commands are used to generate Salt's manpages. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/pkg/__init__.py b/tools/pkg/__init__.py index 38bf0090ba5..7797c78df56 100644 --- a/tools/pkg/__init__.py +++ b/tools/pkg/__init__.py @@ -1,6 +1,7 @@ """ These commands are used to build Salt packages. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations @@ -62,7 +63,7 @@ class Recompress: d_targz = tempd.joinpath(targz.name) with tarfile.open(d_tar, "w|") as wfile: with tarfile.open(targz, "r:gz") as rfile: - rfile.extractall(d_src) + rfile.extractall(d_src) # nosec extracted_dir = next(pathlib.Path(d_src).iterdir()) for name in sorted(extracted_dir.rglob("*")): wfile.add( diff --git a/tools/pkg/build.py b/tools/pkg/build.py index 0aeb26da774..b6b18ba09a6 100644 --- a/tools/pkg/build.py +++ b/tools/pkg/build.py @@ -1,6 +1,7 @@ """ These commands are used to build the salt onedir and system packages. """ + # pylint: disable=resource-leakage,broad-except from __future__ import annotations @@ -230,7 +231,7 @@ def macos( 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) + tarball.extractall(path=build_root) # nosec else: ctx.info("Building package without an existing onedir") @@ -360,7 +361,7 @@ def windows( 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) + archive.extractall(unzip_dir) # nosec move_dir = unzip_dir / "salt" build_env = unzip_dir / "buildenv" diff --git a/tools/pkg/repo/__init__.py b/tools/pkg/repo/__init__.py index ed1bbf6574e..025529866b2 100644 --- a/tools/pkg/repo/__init__.py +++ b/tools/pkg/repo/__init__.py @@ -1,6 +1,7 @@ """ These commands are used to build the package repository files. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/pkg/repo/create.py b/tools/pkg/repo/create.py index 65133d1d63a..f13a8fc1917 100644 --- a/tools/pkg/repo/create.py +++ b/tools/pkg/repo/create.py @@ -1,6 +1,7 @@ """ These commands are used to build the package repository files. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/pkg/repo/publish.py b/tools/pkg/repo/publish.py index d31bb8a1487..108ba7ec379 100644 --- a/tools/pkg/repo/publish.py +++ b/tools/pkg/repo/publish.py @@ -1,6 +1,7 @@ """ These commands are used to build the package repository files. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/precommit/__init__.py b/tools/precommit/__init__.py index c10eadeb479..2bffffbb2ec 100644 --- a/tools/precommit/__init__.py +++ b/tools/precommit/__init__.py @@ -1,6 +1,7 @@ """ These commands, and sub-commands, are used by pre-commit. """ + from ptscripts import command_group import tools.utils diff --git a/tools/precommit/changelog.py b/tools/precommit/changelog.py index 99e3afbf116..027636e50de 100644 --- a/tools/precommit/changelog.py +++ b/tools/precommit/changelog.py @@ -1,6 +1,7 @@ """ These commands are used to validate changelog entries """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/precommit/docs.py b/tools/precommit/docs.py index a549a6cecf3..0c00844c407 100644 --- a/tools/precommit/docs.py +++ b/tools/precommit/docs.py @@ -1,6 +1,7 @@ """ Check salt code base for for missing or wrong docs """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/precommit/docstrings.py b/tools/precommit/docstrings.py index 29a7e0eb4e0..b26f8b1a954 100644 --- a/tools/precommit/docstrings.py +++ b/tools/precommit/docstrings.py @@ -1,6 +1,7 @@ """ Check salt code base for for missing or wrong docstrings. """ + # Skip mypy checks since it will follow into Salt which doesn't yet have proper types defined # mypy: ignore-errors # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated diff --git a/tools/precommit/filemap.py b/tools/precommit/filemap.py index 96a662fa7e7..7870375f299 100644 --- a/tools/precommit/filemap.py +++ b/tools/precommit/filemap.py @@ -1,6 +1,7 @@ """ `tests/filename_map.yml` validity checks """ + import pathlib import re diff --git a/tools/precommit/workflows.py b/tools/precommit/workflows.py index 290d9f70847..d08567dca9c 100644 --- a/tools/precommit/workflows.py +++ b/tools/precommit/workflows.py @@ -1,6 +1,7 @@ """ These commands are used for our GitHub Actions workflows. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/release.py b/tools/release.py index 6a1893e5b27..db58f2fa6fa 100644 --- a/tools/release.py +++ b/tools/release.py @@ -1,6 +1,7 @@ """ These commands are used to release Salt. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/testsuite/__init__.py b/tools/testsuite/__init__.py index 25a16c7a278..27ebe572465 100644 --- a/tools/testsuite/__init__.py +++ b/tools/testsuite/__init__.py @@ -1,6 +1,7 @@ """ These commands are related to the test suite. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/testsuite/download.py b/tools/testsuite/download.py index 4e4832c798c..8c5572b07e2 100644 --- a/tools/testsuite/download.py +++ b/tools/testsuite/download.py @@ -1,6 +1,7 @@ """ These commands are related to downloading test suite CI artifacts. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/vm.py b/tools/vm.py index eed42eeebc6..85aed8e0afd 100644 --- a/tools/vm.py +++ b/tools/vm.py @@ -2,6 +2,7 @@ These commands are used to create/destroy VMs, sync the local checkout to the VM and to run commands on the VM. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations From 03ad4c63372a60267ea35c989930841bf1cc68cf Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 27 Feb 2024 11:08:46 +0000 Subject: [PATCH 39/54] Update code to be Py3.7+ to reduce merge forward conflicts --- .gitignore | 1 + .pre-commit-config.yaml | 4 +- doc/_ext/saltdomain.py | 12 +- noxfile.py | 28 +- salt/__init__.py | 2 +- salt/_logging/impl.py | 18 +- salt/auth/__init__.py | 12 +- salt/auth/django.py | 2 +- salt/auth/ldap.py | 12 +- salt/auth/pam.py | 7 +- salt/beacons/__init__.py | 36 +- salt/beacons/btmp.py | 2 +- salt/beacons/diskusage.py | 2 +- salt/beacons/inotify.py | 4 +- salt/beacons/napalm_beacon.py | 2 +- salt/beacons/salt_monitor.py | 10 +- salt/beacons/salt_proxy.py | 4 +- salt/beacons/sensehat.py | 4 +- salt/beacons/sh.py | 2 +- salt/beacons/smartos_imgadm.py | 4 +- salt/beacons/smartos_vmadm.py | 4 +- salt/beacons/status.py | 6 +- salt/beacons/wtmp.py | 2 +- salt/cache/__init__.py | 16 +- salt/cache/consul.py | 36 +- salt/cache/etcd_cache.py | 38 +- salt/cache/localfs.py | 24 +- salt/cache/mysql_cache.py | 6 +- salt/cache/redis_cache.py | 2 +- salt/channel/client.py | 4 +- salt/channel/server.py | 4 +- salt/cli/batch.py | 2 +- salt/cli/caller.py | 16 +- salt/cli/salt.py | 24 +- salt/client/__init__.py | 40 +- salt/client/mixins.py | 6 +- salt/client/netapi.py | 2 +- salt/client/ssh/shell.py | 45 +- salt/client/ssh/wrapper/__init__.py | 14 +- salt/client/ssh/wrapper/config.py | 4 +- salt/client/ssh/wrapper/cp.py | 2 +- salt/cloud/__init__.py | 72 ++- salt/cloud/clouds/aliyun.py | 18 +- salt/cloud/clouds/azurearm.py | 20 +- salt/cloud/clouds/clc.py | 2 +- salt/cloud/clouds/cloudstack.py | 12 +- salt/cloud/clouds/digitalocean.py | 22 +- salt/cloud/clouds/ec2.py | 70 ++- salt/cloud/clouds/gce.py | 26 +- salt/cloud/clouds/gogrid.py | 6 +- salt/cloud/clouds/hetzner.py | 42 +- salt/cloud/clouds/joyent.py | 28 +- salt/cloud/clouds/libvirt.py | 30 +- salt/cloud/clouds/linode.py | 78 ++-- salt/cloud/clouds/lxc.py | 22 +- salt/cloud/clouds/msazure.py | 6 +- salt/cloud/clouds/oneandone.py | 22 +- salt/cloud/clouds/opennebula.py | 44 +- salt/cloud/clouds/openstack.py | 6 +- salt/cloud/clouds/packet.py | 14 +- salt/cloud/clouds/parallels.py | 24 +- salt/cloud/clouds/profitbricks.py | 24 +- salt/cloud/clouds/proxmox.py | 34 +- salt/cloud/clouds/qingcloud.py | 22 +- salt/cloud/clouds/saltify.py | 8 +- salt/cloud/clouds/scaleway.py | 12 +- salt/cloud/clouds/softlayer.py | 10 +- salt/cloud/clouds/softlayer_hw.py | 10 +- salt/cloud/clouds/tencentcloud.py | 30 +- salt/cloud/clouds/vagrant.py | 12 +- salt/cloud/clouds/virtualbox.py | 6 +- salt/cloud/clouds/vmware.py | 44 +- salt/cloud/clouds/xen.py | 20 +- salt/cloud/libcloudfuncs.py | 20 +- salt/config/__init__.py | 18 +- salt/config/schemas/common.py | 2 +- salt/crypt.py | 6 +- salt/daemons/__init__.py | 2 +- salt/daemons/masterapi.py | 14 +- salt/defaults/__init__.py | 4 +- salt/engines/__init__.py | 6 +- salt/engines/ircbot.py | 18 +- salt/engines/libvirt_events.py | 10 +- salt/engines/napalm_syslog.py | 2 +- salt/engines/script.py | 2 +- salt/engines/slack.py | 6 +- salt/exceptions.py | 2 +- salt/executors/docker.py | 2 +- salt/executors/sudo.py | 2 +- salt/fileclient.py | 26 +- salt/fileserver/__init__.py | 42 +- salt/fileserver/hgfs.py | 20 +- salt/fileserver/roots.py | 8 +- salt/fileserver/svnfs.py | 6 +- salt/grains/core.py | 104 ++--- salt/grains/disks.py | 6 +- salt/grains/lvm.py | 10 +- salt/grains/mdata.py | 4 +- salt/grains/metadata.py | 2 +- salt/key.py | 16 +- salt/loader/__init__.py | 6 +- salt/loader/lazy.py | 26 +- salt/log_handlers/fluent_mod.py | 8 +- salt/log_handlers/logstash_mod.py | 4 +- salt/log_handlers/sentry_mod.py | 2 +- salt/master.py | 18 +- salt/matchers/compound_match.py | 2 +- salt/matchers/ipcidr_match.py | 2 +- salt/matchers/list_match.py | 2 +- salt/metaproxy/deltaproxy.py | 38 +- salt/metaproxy/proxy.py | 36 +- salt/minion.py | 46 +- salt/modules/acme.py | 42 +- salt/modules/aix_group.py | 12 +- salt/modules/aix_shadow.py | 4 +- salt/modules/aixpkg.py | 30 +- salt/modules/aliases.py | 4 +- salt/modules/alternatives.py | 2 +- salt/modules/ansiblegate.py | 51 +-- salt/modules/apache.py | 42 +- salt/modules/apf.py | 8 +- salt/modules/apkpkg.py | 2 +- salt/modules/aptly.py | 34 +- salt/modules/aptpkg.py | 72 ++- salt/modules/archive.py | 54 +-- salt/modules/arista_pyeapi.py | 4 +- salt/modules/artifactory.py | 2 +- salt/modules/at.py | 14 +- salt/modules/at_solaris.py | 22 +- salt/modules/augeas_cfg.py | 12 +- salt/modules/aws_sqs.py | 6 +- salt/modules/azurearm_compute.py | 6 +- salt/modules/azurearm_dns.py | 12 +- salt/modules/azurearm_network.py | 96 ++-- salt/modules/azurearm_resource.py | 30 +- salt/modules/bamboohr.py | 8 +- salt/modules/baredoc.py | 4 +- salt/modules/bcache.py | 50 +-- salt/modules/beacons.py | 46 +- salt/modules/bigip.py | 72 ++- salt/modules/bluez_bluetooth.py | 18 +- salt/modules/boto3_elasticache.py | 72 ++- salt/modules/boto_apigateway.py | 20 +- salt/modules/boto_asg.py | 16 +- salt/modules/boto_cfn.py | 10 +- salt/modules/boto_cloudfront.py | 2 +- salt/modules/boto_cloudtrail.py | 2 +- salt/modules/boto_cloudwatch_event.py | 8 +- salt/modules/boto_cognitoidentity.py | 2 +- salt/modules/boto_datapipeline.py | 2 +- salt/modules/boto_ec2.py | 16 +- salt/modules/boto_elasticache.py | 36 +- salt/modules/boto_elasticsearch_domain.py | 4 +- salt/modules/boto_elb.py | 4 +- salt/modules/boto_iam.py | 2 +- salt/modules/boto_iot.py | 4 +- salt/modules/boto_kinesis.py | 2 +- salt/modules/boto_lambda.py | 8 +- salt/modules/boto_rds.py | 44 +- salt/modules/boto_route53.py | 8 +- salt/modules/boto_s3_bucket.py | 2 +- salt/modules/boto_secgroup.py | 6 +- salt/modules/boto_sns.py | 4 +- salt/modules/boto_vpc.py | 110 ++--- salt/modules/bridge.py | 56 +-- salt/modules/bsd_shadow.py | 6 +- salt/modules/btrfs.py | 94 ++-- salt/modules/cabal.py | 6 +- salt/modules/capirca_acl.py | 14 +- salt/modules/cassandra_cql.py | 36 +- salt/modules/chef.py | 10 +- salt/modules/chronos.py | 6 +- salt/modules/chroot.py | 4 +- salt/modules/cimc.py | 22 +- salt/modules/ciscoconfparse_mod.py | 2 +- salt/modules/cmdmod.py | 114 +++-- salt/modules/composer.py | 4 +- salt/modules/config.py | 4 +- salt/modules/consul.py | 94 ++-- salt/modules/cp.py | 2 +- salt/modules/cpan.py | 4 +- salt/modules/cron.py | 8 +- salt/modules/cryptdev.py | 10 +- salt/modules/csf.py | 46 +- salt/modules/cyg.py | 16 +- salt/modules/daemontools.py | 16 +- salt/modules/datadog_api.py | 2 +- salt/modules/ddns.py | 18 +- salt/modules/deb_apache.py | 40 +- salt/modules/debconfmod.py | 6 +- salt/modules/debian_ip.py | 33 +- salt/modules/debian_service.py | 6 +- salt/modules/debuild_pkgbuild.py | 60 ++- salt/modules/devinfo.py | 4 +- salt/modules/devmap.py | 4 +- salt/modules/dig.py | 16 +- salt/modules/disk.py | 56 ++- salt/modules/djangomod.py | 18 +- salt/modules/dnsmasq.py | 10 +- salt/modules/dnsutil.py | 14 +- salt/modules/dockercompose.py | 66 ++- salt/modules/dpkg_lowpkg.py | 14 +- salt/modules/drac.py | 22 +- salt/modules/dracr.py | 54 ++- salt/modules/ebuildpkg.py | 32 +- salt/modules/eselect.py | 2 +- salt/modules/ethtool.py | 6 +- salt/modules/extfs.py | 16 +- salt/modules/file.py | 300 ++++++------- salt/modules/firewalld.py | 66 +-- salt/modules/freebsd_sysctl.py | 16 +- salt/modules/freebsd_update.py | 2 +- salt/modules/freebsdkmod.py | 6 +- salt/modules/freebsdpkg.py | 6 +- salt/modules/freebsdports.py | 20 +- salt/modules/freebsdservice.py | 42 +- salt/modules/freezer.py | 4 +- salt/modules/genesis.py | 86 ++-- salt/modules/gentoolkitmod.py | 8 +- salt/modules/git.py | 56 +-- salt/modules/github.py | 8 +- salt/modules/glassfish.py | 16 +- salt/modules/glusterfs.py | 64 ++- salt/modules/gnomedesktop.py | 6 +- salt/modules/gpg.py | 16 +- salt/modules/grains.py | 10 +- salt/modules/groupadd.py | 10 +- salt/modules/grub_legacy.py | 6 +- salt/modules/guestfs.py | 6 +- salt/modules/haproxyconn.py | 4 +- salt/modules/hashutil.py | 6 +- salt/modules/heat.py | 46 +- salt/modules/hg.py | 22 +- salt/modules/highstate_doc.py | 26 +- salt/modules/hosts.py | 2 +- salt/modules/icinga2.py | 20 +- salt/modules/ifttt.py | 2 +- salt/modules/ilo.py | 8 +- salt/modules/incron.py | 14 +- salt/modules/influxdbmod.py | 6 +- salt/modules/infoblox.py | 10 +- salt/modules/ini_manage.py | 12 +- salt/modules/inspectlib/collector.py | 8 +- salt/modules/inspectlib/kiwiproc.py | 6 +- salt/modules/inspectlib/query.py | 14 +- salt/modules/inspector.py | 2 +- salt/modules/iosconfig.py | 2 +- salt/modules/ipmi.py | 8 +- salt/modules/ipset.py | 24 +- salt/modules/iwtools.py | 8 +- salt/modules/jboss7.py | 38 +- salt/modules/jboss7_cli.py | 4 +- salt/modules/jenkinsmod.py | 42 +- salt/modules/junos.py | 82 ++-- salt/modules/k8s.py | 52 +-- salt/modules/kapacitor.py | 24 +- salt/modules/kerberos.py | 18 +- salt/modules/kernelpkg_linux_apt.py | 18 +- salt/modules/kernelpkg_linux_yum.py | 6 +- salt/modules/keyboard.py | 12 +- salt/modules/keystone.py | 46 +- salt/modules/keystoneng.py | 2 +- salt/modules/keystore.py | 4 +- salt/modules/kmod.py | 10 +- salt/modules/kubeadm.py | 44 +- salt/modules/kubernetesmod.py | 16 +- salt/modules/launchctl_service.py | 6 +- salt/modules/layman.py | 6 +- salt/modules/ldap3.py | 6 +- salt/modules/ldapmod.py | 8 +- salt/modules/libcloud_compute.py | 2 +- salt/modules/linux_acl.py | 12 +- salt/modules/linux_ip.py | 6 +- salt/modules/linux_lvm.py | 58 +-- salt/modules/linux_service.py | 2 +- salt/modules/linux_shadow.py | 2 +- salt/modules/linux_sysctl.py | 16 +- salt/modules/localemod.py | 26 +- salt/modules/locate.py | 8 +- salt/modules/logadm.py | 12 +- salt/modules/logrotate.py | 10 +- salt/modules/lvs.py | 18 +- salt/modules/lxd.py | 76 ++-- salt/modules/mac_assistive.py | 16 +- salt/modules/mac_brew_pkg.py | 18 +- salt/modules/mac_desktop.py | 4 +- salt/modules/mac_group.py | 12 +- salt/modules/mac_pkgutil.py | 8 +- salt/modules/mac_portspkg.py | 4 +- salt/modules/mac_shadow.py | 42 +- salt/modules/mac_softwareupdate.py | 4 +- salt/modules/mac_sysctl.py | 14 +- salt/modules/mac_timezone.py | 12 +- salt/modules/mac_user.py | 42 +- salt/modules/mac_xattr.py | 28 +- salt/modules/macdefaults.py | 6 +- salt/modules/makeconf.py | 14 +- salt/modules/marathon.py | 14 +- salt/modules/mdadm_raid.py | 12 +- salt/modules/mdata.py | 10 +- salt/modules/memcached.py | 10 +- salt/modules/minion.py | 4 +- salt/modules/modjk.py | 32 +- salt/modules/mongodb.py | 8 +- salt/modules/monit.py | 10 +- salt/modules/mount.py | 110 +++-- salt/modules/mssql.py | 80 ++-- salt/modules/munin.py | 4 +- salt/modules/mysql.py | 78 ++-- salt/modules/nagios.py | 4 +- salt/modules/nagios_rpc.py | 2 +- salt/modules/namecheap_domains.py | 2 +- salt/modules/napalm_formula.py | 2 +- salt/modules/napalm_mod.py | 22 +- salt/modules/napalm_network.py | 46 +- salt/modules/netbox.py | 4 +- salt/modules/netbsd_sysctl.py | 16 +- salt/modules/netbsdservice.py | 28 +- salt/modules/netmiko_mod.py | 4 +- salt/modules/netscaler.py | 2 +- salt/modules/network.py | 30 +- salt/modules/nexus.py | 12 +- salt/modules/nfs3.py | 4 +- salt/modules/nftables.py | 64 ++- salt/modules/nginx.py | 10 +- salt/modules/nilrt_ip.py | 98 ++--- salt/modules/npm.py | 14 +- salt/modules/nspawn.py | 90 ++-- salt/modules/nxos.py | 22 +- salt/modules/nxos_api.py | 6 +- salt/modules/nxos_upgrade.py | 12 +- salt/modules/omapi.py | 4 +- salt/modules/openbsd_sysctl.py | 10 +- salt/modules/openbsdpkg.py | 12 +- salt/modules/openbsdrcctl_service.py | 36 +- salt/modules/openbsdservice.py | 12 +- salt/modules/openvswitch.py | 40 +- salt/modules/opkg.py | 24 +- salt/modules/osquery.py | 12 +- salt/modules/pacmanpkg.py | 6 +- salt/modules/pagerduty_util.py | 10 +- salt/modules/pam.py | 2 +- salt/modules/panos.py | 54 +-- salt/modules/parallels.py | 12 +- salt/modules/parted_partition.py | 38 +- salt/modules/pcs.py | 8 +- salt/modules/pdbedit.py | 2 +- salt/modules/pecl.py | 6 +- salt/modules/peeringdb.py | 4 +- salt/modules/pf.py | 22 +- salt/modules/pillar.py | 12 +- salt/modules/pip.py | 52 +-- salt/modules/pkg_resource.py | 4 +- salt/modules/pkgin.py | 10 +- salt/modules/pkgng.py | 38 +- salt/modules/pkgutil.py | 4 +- salt/modules/portage_config.py | 6 +- salt/modules/postfix.py | 30 +- salt/modules/poudriere.py | 50 +-- salt/modules/powerpath.py | 4 +- salt/modules/proxy.py | 12 +- salt/modules/ps.py | 2 +- salt/modules/publish.py | 6 +- salt/modules/puppet.py | 24 +- salt/modules/purefb.py | 2 +- salt/modules/pw_group.py | 14 +- salt/modules/pw_user.py | 18 +- salt/modules/pyenv.py | 26 +- salt/modules/qemu_img.py | 2 +- salt/modules/qemu_nbd.py | 12 +- salt/modules/quota.py | 8 +- salt/modules/rabbitmq.py | 20 +- salt/modules/rallydev.py | 2 +- salt/modules/random_org.py | 12 +- salt/modules/rbac_solaris.py | 6 +- salt/modules/rbenv.py | 8 +- salt/modules/rdp.py | 4 +- salt/modules/reg.py | 4 +- salt/modules/restartcheck.py | 20 +- salt/modules/restconf.py | 2 +- salt/modules/ret.py | 8 +- salt/modules/rh_ip.py | 28 +- salt/modules/rh_service.py | 46 +- salt/modules/riak.py | 6 +- salt/modules/rpm_lowpkg.py | 12 +- salt/modules/rpmbuild_pkgbuild.py | 26 +- salt/modules/rsync.py | 18 +- salt/modules/runit.py | 12 +- salt/modules/rvm.py | 6 +- salt/modules/s6.py | 14 +- salt/modules/salt_proxy.py | 22 +- salt/modules/saltcheck.py | 30 +- salt/modules/saltcloudmod.py | 2 +- salt/modules/saltutil.py | 24 +- salt/modules/schedule.py | 96 ++-- salt/modules/scsi.py | 8 +- salt/modules/seed.py | 8 +- salt/modules/selinux.py | 32 +- salt/modules/sensors.py | 2 +- salt/modules/serverdensity_device.py | 20 +- salt/modules/servicenow.py | 2 +- salt/modules/slack_notify.py | 2 +- salt/modules/slackware_service.py | 18 +- salt/modules/slsutil.py | 8 +- salt/modules/smartos_imgadm.py | 22 +- salt/modules/smartos_nictagadm.py | 22 +- salt/modules/smartos_virt.py | 10 +- salt/modules/smartos_vmadm.py | 66 +-- salt/modules/smbios.py | 6 +- salt/modules/smf_service.py | 24 +- salt/modules/smtp.py | 2 +- salt/modules/snapper.py | 24 +- salt/modules/solaris_fmadm.py | 18 +- salt/modules/solaris_group.py | 6 +- salt/modules/solaris_shadow.py | 12 +- salt/modules/solaris_user.py | 14 +- salt/modules/solarisipspkg.py | 8 +- salt/modules/solarispkg.py | 22 +- salt/modules/solr.py | 32 +- salt/modules/solrcloud.py | 14 +- salt/modules/splunk_search.py | 2 +- salt/modules/ssh.py | 32 +- salt/modules/state.py | 26 +- salt/modules/status.py | 22 +- salt/modules/supervisord.py | 14 +- salt/modules/suse_apache.py | 8 +- salt/modules/suse_ip.py | 30 +- salt/modules/sysbench.py | 10 +- salt/modules/sysfs.py | 2 +- salt/modules/syslog_ng.py | 24 +- salt/modules/system.py | 12 +- salt/modules/systemd_service.py | 6 +- salt/modules/telegram.py | 2 +- salt/modules/telemetry.py | 19 +- salt/modules/test.py | 4 +- salt/modules/testinframod.py | 2 +- salt/modules/textfsm_mod.py | 2 +- salt/modules/timezone.py | 44 +- salt/modules/tls.py | 168 ++++--- salt/modules/tomcat.py | 18 +- salt/modules/transactional_update.py | 8 +- salt/modules/tuned.py | 4 +- salt/modules/udev.py | 2 +- salt/modules/upstart_service.py | 18 +- salt/modules/uptime.py | 20 +- salt/modules/useradd.py | 6 +- salt/modules/uwsgi.py | 2 +- salt/modules/vagrant.py | 36 +- salt/modules/vault.py | 16 +- salt/modules/vboxmanage.py | 76 ++-- salt/modules/victorops.py | 4 +- salt/modules/virtualenv_mod.py | 16 +- salt/modules/vmctl.py | 10 +- salt/modules/vsphere.py | 152 +++---- salt/modules/webutil.py | 4 +- salt/modules/win_certutil.py | 14 +- salt/modules/win_dacl.py | 14 +- salt/modules/win_disk.py | 12 +- salt/modules/win_dism.py | 58 +-- salt/modules/win_dns_client.py | 2 +- salt/modules/win_dsc.py | 54 ++- salt/modules/win_event.py | 4 +- salt/modules/win_file.py | 74 ++-- salt/modules/win_firewall.py | 24 +- salt/modules/win_iis.py | 196 ++++----- salt/modules/win_ip.py | 34 +- salt/modules/win_lgpo.py | 60 ++- salt/modules/win_lgpo_reg.py | 14 +- salt/modules/win_license.py | 2 +- salt/modules/win_network.py | 4 +- salt/modules/win_pkg.py | 98 ++--- salt/modules/win_pki.py | 40 +- salt/modules/win_powercfg.py | 4 +- salt/modules/win_psget.py | 22 +- salt/modules/win_servermanager.py | 10 +- salt/modules/win_service.py | 42 +- salt/modules/win_shortcut.py | 18 +- salt/modules/win_smtp_server.py | 8 +- salt/modules/win_snmp.py | 6 +- salt/modules/win_system.py | 22 +- salt/modules/win_timezone.py | 6 +- salt/modules/win_useradd.py | 18 +- salt/modules/win_wua.py | 4 +- salt/modules/win_wusa.py | 18 +- salt/modules/winrepo.py | 10 +- salt/modules/wordpress.py | 14 +- salt/modules/x509.py | 12 +- salt/modules/xbpspkg.py | 6 +- salt/modules/xfs.py | 36 +- salt/modules/yumpkg.py | 98 ++--- salt/modules/zabbix.py | 14 +- salt/modules/zcbuildout.py | 18 +- salt/modules/zenoss.py | 2 +- salt/modules/zoneadm.py | 48 +- salt/modules/zonecfg.py | 30 +- salt/modules/zypperpkg.py | 50 +-- salt/netapi/__init__.py | 2 +- salt/netapi/rest_cherrypy/app.py | 14 +- salt/netapi/rest_tornado/__init__.py | 4 +- salt/netapi/rest_tornado/saltnado.py | 6 +- salt/netapi/rest_wsgi.py | 2 +- salt/output/__init__.py | 2 +- salt/output/highstate.py | 12 +- salt/output/key.py | 2 +- salt/output/profile.py | 4 +- salt/output/table_out.py | 2 +- salt/output/txt.py | 6 +- salt/output/virt_query.py | 8 +- salt/pillar/__init__.py | 12 +- salt/pillar/azureblob.py | 2 +- salt/pillar/django_orm.py | 6 +- salt/pillar/ec2_pillar.py | 4 +- salt/pillar/hiera.py | 4 +- salt/pillar/http_json.py | 2 +- salt/pillar/http_yaml.py | 2 +- salt/pillar/libvirt.py | 10 +- salt/pillar/makostack.py | 8 +- salt/pillar/netbox.py | 2 +- salt/pillar/puppet.py | 4 +- salt/pillar/reclass_adapter.py | 2 +- salt/pillar/s3.py | 2 +- salt/pillar/stack.py | 12 +- salt/pillar/vault.py | 2 +- salt/platform/win.py | 18 +- salt/proxy/chronos.py | 2 +- salt/proxy/docker.py | 2 +- salt/proxy/dummy.py | 4 +- salt/proxy/marathon.py | 2 +- salt/proxy/napalm.py | 2 +- salt/queues/pgjsonb_queue.py | 24 +- salt/queues/sqlite_queue.py | 28 +- salt/renderers/jinja.py | 6 +- salt/renderers/py.py | 4 +- salt/renderers/pyobjects.py | 8 +- salt/renderers/stateconf.py | 6 +- salt/returners/__init__.py | 8 +- salt/returners/carbon_return.py | 4 +- salt/returners/couchdb_return.py | 2 +- salt/returners/elasticsearch_return.py | 10 +- salt/returners/influxdb_return.py | 6 +- salt/returners/local_cache.py | 4 +- salt/returners/mattermost_returner.py | 4 +- salt/returners/memcache_return.py | 12 +- salt/returners/multi_returner.py | 18 +- salt/returners/odbc.py | 4 +- salt/returners/postgres.py | 4 +- salt/returners/redis_return.py | 14 +- salt/returners/sentry_return.py | 6 +- salt/returners/slack_webhook_return.py | 12 +- salt/returners/smtp_return.py | 4 +- salt/returners/zabbix_return.py | 2 +- salt/roster/__init__.py | 8 +- salt/roster/cache.py | 6 +- salt/roster/dir.py | 6 +- salt/roster/sshconfig.py | 4 +- salt/roster/sshknownhosts.py | 4 +- salt/runner.py | 8 +- salt/runners/asam.py | 20 +- salt/runners/bgp.py | 4 +- salt/runners/cache.py | 2 +- salt/runners/ddns.py | 30 +- salt/runners/digicertapi.py | 32 +- salt/runners/f5.py | 26 +- salt/runners/jobs.py | 30 +- salt/runners/launchd.py | 2 +- salt/runners/lxc.py | 10 +- salt/runners/manage.py | 12 +- salt/runners/mattermost.py | 4 +- salt/runners/net.py | 26 +- salt/runners/network.py | 4 +- salt/runners/pkg.py | 2 +- salt/runners/queue.py | 26 +- salt/runners/salt.py | 6 +- salt/runners/smartos_vmadm.py | 8 +- salt/runners/spacewalk.py | 16 +- salt/runners/test.py | 4 +- salt/runners/vault.py | 8 +- salt/runners/venafiapi.py | 8 +- salt/runners/virt.py | 58 ++- salt/runners/vistara.py | 8 +- salt/runners/winrepo.py | 2 +- salt/scripts.py | 8 +- salt/sdb/sqlite3.py | 8 +- salt/sdb/vault.py | 6 +- salt/serializers/configparser.py | 2 +- salt/serializers/yamlex.py | 2 +- salt/spm/__init__.py | 88 ++-- salt/spm/pkgdb/sqlite3.py | 2 +- salt/spm/pkgfiles/local.py | 24 +- salt/state.py | 58 ++- salt/states/acme.py | 6 +- salt/states/alias.py | 16 +- salt/states/alternatives.py | 20 +- salt/states/ansiblegate.py | 16 +- salt/states/apache_conf.py | 16 +- salt/states/apache_module.py | 16 +- salt/states/apache_site.py | 16 +- salt/states/aptpkg.py | 8 +- salt/states/archive.py | 42 +- salt/states/at.py | 8 +- salt/states/augeas.py | 6 +- salt/states/aws_sqs.py | 8 +- salt/states/azurearm_compute.py | 20 +- salt/states/azurearm_dns.py | 40 +- salt/states/azurearm_network.py | 188 ++++---- salt/states/azurearm_resource.py | 60 +-- salt/states/beacon.py | 26 +- salt/states/bigip.py | 4 +- salt/states/blockdev.py | 24 +- salt/states/boto3_elasticache.py | 76 ++-- salt/states/boto3_elasticsearch.py | 24 +- salt/states/boto3_route53.py | 4 +- salt/states/boto3_sns.py | 21 +- salt/states/boto_apigateway.py | 104 +++-- salt/states/boto_asg.py | 4 +- salt/states/boto_cfn.py | 18 +- salt/states/boto_cloudfront.py | 8 +- salt/states/boto_cloudtrail.py | 20 +- salt/states/boto_cloudwatch_alarm.py | 20 +- salt/states/boto_cloudwatch_event.py | 12 +- salt/states/boto_cognitoidentity.py | 10 +- salt/states/boto_datapipeline.py | 12 +- salt/states/boto_dynamodb.py | 44 +- salt/states/boto_ec2.py | 70 ++- salt/states/boto_elasticache.py | 38 +- salt/states/boto_elasticsearch_domain.py | 18 +- salt/states/boto_elb.py | 124 +++--- salt/states/boto_elbv2.py | 42 +- salt/states/boto_iam.py | 170 ++++---- salt/states/boto_iam_role.py | 42 +- salt/states/boto_iot.py | 46 +- salt/states/boto_kinesis.py | 24 +- salt/states/boto_kms.py | 8 +- salt/states/boto_lambda.py | 44 +- salt/states/boto_rds.py | 56 +-- salt/states/boto_route53.py | 34 +- salt/states/boto_s3.py | 12 +- salt/states/boto_s3_bucket.py | 30 +- salt/states/boto_secgroup.py | 46 +- salt/states/boto_sns.py | 14 +- salt/states/boto_sqs.py | 12 +- salt/states/boto_vpc.py | 74 ++-- salt/states/bower.py | 28 +- salt/states/btrfs.py | 38 +- salt/states/cabal.py | 14 +- salt/states/chronos_job.py | 14 +- salt/states/cloud.py | 52 +-- salt/states/cmd.py | 26 +- salt/states/composer.py | 18 +- salt/states/consul.py | 4 +- salt/states/cron.py | 60 +-- salt/states/cryptdev.py | 8 +- salt/states/csf.py | 8 +- salt/states/cyg.py | 4 +- salt/states/ddns.py | 6 +- salt/states/debconfmod.py | 2 +- salt/states/dellchassis.py | 8 +- salt/states/disk.py | 4 +- salt/states/docker_container.py | 70 ++- salt/states/docker_image.py | 20 +- salt/states/docker_network.py | 26 +- salt/states/docker_volume.py | 14 +- salt/states/drac.py | 16 +- salt/states/dvs.py | 18 +- salt/states/elasticsearch.py | 54 ++- salt/states/elasticsearch_index.py | 14 +- salt/states/elasticsearch_index_template.py | 8 +- salt/states/eselect.py | 4 +- salt/states/esxcluster.py | 22 +- salt/states/esxdatacenter.py | 6 +- salt/states/esxi.py | 110 +++-- salt/states/esxvm.py | 12 +- salt/states/etcd_mod.py | 2 +- salt/states/ethtool.py | 32 +- salt/states/file.py | 410 ++++++++---------- salt/states/firewalld.py | 82 ++-- salt/states/gem.py | 6 +- salt/states/github.py | 108 +++-- salt/states/glance_image.py | 4 +- salt/states/glassfish.py | 24 +- salt/states/glusterfs.py | 34 +- salt/states/gnomedesktop.py | 12 +- salt/states/gpg.py | 18 +- salt/states/grafana.py | 22 +- salt/states/grafana4_dashboard.py | 14 +- salt/states/grafana4_datasource.py | 16 +- salt/states/grafana4_org.py | 18 +- salt/states/grafana4_user.py | 18 +- salt/states/grafana_dashboard.py | 18 +- salt/states/grafana_datasource.py | 10 +- salt/states/grains.py | 62 ++- salt/states/group.py | 16 +- salt/states/heat.py | 16 +- salt/states/helm.py | 8 +- salt/states/hg.py | 16 +- salt/states/highstate_doc.py | 2 +- salt/states/host.py | 36 +- salt/states/http.py | 22 +- salt/states/icinga2.py | 30 +- salt/states/idem.py | 6 +- salt/states/ifttt.py | 4 +- salt/states/incron.py | 20 +- salt/states/influxdb08_database.py | 12 +- salt/states/influxdb08_user.py | 16 +- salt/states/influxdb_continuous_query.py | 16 +- salt/states/influxdb_database.py | 14 +- salt/states/influxdb_retention_policy.py | 22 +- salt/states/influxdb_user.py | 24 +- salt/states/infoblox_host_record.py | 2 +- salt/states/infoblox_range.py | 4 +- salt/states/ini_manage.py | 36 +- salt/states/ipmi.py | 6 +- salt/states/ipset.py | 14 +- salt/states/iptables.py | 2 +- salt/states/jboss7.py | 6 +- salt/states/jenkins.py | 10 +- salt/states/kapacitor.py | 2 +- salt/states/keyboard.py | 12 +- salt/states/keystone.py | 122 +++--- salt/states/keystone_domain.py | 6 +- salt/states/keystore.py | 4 +- salt/states/kmod.py | 16 +- salt/states/kubernetes.py | 44 +- salt/states/layman.py | 18 +- salt/states/libcloud_dns.py | 2 +- salt/states/linux_acl.py | 12 +- salt/states/locale.py | 18 +- salt/states/logadm.py | 4 +- salt/states/logrotate.py | 6 +- salt/states/loop.py | 10 +- salt/states/lvm.py | 68 +-- salt/states/lvs_service.py | 16 +- salt/states/lxc.py | 54 +-- salt/states/lxd.py | 12 +- salt/states/lxd_container.py | 68 +-- salt/states/lxd_image.py | 20 +- salt/states/lxd_profile.py | 14 +- salt/states/mac_assistive.py | 4 +- salt/states/mac_keychain.py | 14 +- salt/states/macdefaults.py | 12 +- salt/states/macpackage.py | 14 +- salt/states/makeconf.py | 6 +- salt/states/marathon_app.py | 20 +- salt/states/mdadm_raid.py | 32 +- salt/states/memcached.py | 20 +- salt/states/modjk.py | 6 +- salt/states/modjk_worker.py | 4 +- salt/states/module.py | 12 +- salt/states/mongodb_database.py | 4 +- salt/states/mongodb_user.py | 18 +- salt/states/monit.py | 16 +- salt/states/mount.py | 62 ++- salt/states/mssql_database.py | 16 +- salt/states/mssql_login.py | 18 +- salt/states/mssql_role.py | 14 +- salt/states/mssql_user.py | 18 +- salt/states/msteams.py | 6 +- salt/states/mysql_database.py | 22 +- salt/states/mysql_grants.py | 12 +- salt/states/mysql_query.py | 16 +- salt/states/mysql_user.py | 28 +- salt/states/netconfig.py | 16 +- salt/states/netntp.py | 8 +- salt/states/netsnmp.py | 2 +- salt/states/netusers.py | 2 +- salt/states/network.py | 36 +- salt/states/neutron_network.py | 2 +- salt/states/neutron_secgroup_rule.py | 2 +- salt/states/nfs_export.py | 12 +- salt/states/nftables.py | 6 +- salt/states/npm.py | 24 +- salt/states/nxos.py | 4 +- salt/states/nxos_upgrade.py | 4 +- salt/states/openstack_config.py | 2 +- salt/states/openvswitch_bridge.py | 20 +- salt/states/openvswitch_port.py | 28 +- salt/states/pagerduty.py | 4 +- salt/states/pagerduty_escalation_policy.py | 6 +- salt/states/pagerduty_schedule.py | 2 +- salt/states/pagerduty_service.py | 2 +- salt/states/panos.py | 60 +-- salt/states/pbm.py | 14 +- salt/states/pcs.py | 50 +-- salt/states/pdbedit.py | 2 +- salt/states/pecl.py | 18 +- salt/states/pip_state.py | 26 +- salt/states/pkg.py | 116 ++--- salt/states/pkgbuild.py | 2 +- salt/states/pkgrepo.py | 22 +- salt/states/ports.py | 20 +- salt/states/postgres_cluster.py | 6 +- salt/states/postgres_database.py | 22 +- salt/states/postgres_extension.py | 16 +- salt/states/postgres_group.py | 20 +- salt/states/postgres_initdb.py | 8 +- salt/states/postgres_language.py | 16 +- salt/states/postgres_schema.py | 4 +- salt/states/postgres_tablespace.py | 18 +- salt/states/postgres_user.py | 22 +- salt/states/powerpath.py | 8 +- salt/states/process.py | 2 +- salt/states/proxy.py | 6 +- salt/states/pushover.py | 8 +- salt/states/pyenv.py | 8 +- salt/states/pyrax_queues.py | 12 +- salt/states/quota.py | 10 +- salt/states/rabbitmq_cluster.py | 6 +- salt/states/rabbitmq_plugin.py | 20 +- salt/states/rabbitmq_policy.py | 12 +- salt/states/rabbitmq_upstream.py | 20 +- salt/states/rabbitmq_user.py | 36 +- salt/states/rabbitmq_vhost.py | 8 +- salt/states/rbac_solaris.py | 4 +- salt/states/rbenv.py | 12 +- salt/states/redismod.py | 12 +- salt/states/rsync.py | 2 +- salt/states/rvm.py | 6 +- salt/states/salt_proxy.py | 2 +- salt/states/saltmod.py | 10 +- salt/states/saltutil.py | 10 +- salt/states/schedule.py | 18 +- salt/states/selinux.py | 56 +-- salt/states/service.py | 75 ++-- salt/states/slack.py | 4 +- salt/states/smartos.py | 107 +++-- salt/states/smtp.py | 4 +- salt/states/snapper.py | 4 +- salt/states/solrcloud.py | 14 +- salt/states/splunk.py | 22 +- salt/states/splunk_search.py | 14 +- salt/states/ssh_known_hosts.py | 14 +- salt/states/status.py | 8 +- salt/states/statuspage.py | 18 +- salt/states/supervisord.py | 34 +- salt/states/svn.py | 14 +- salt/states/sysctl.py | 8 +- salt/states/sysfs.py | 12 +- salt/states/sysrc.py | 14 +- salt/states/telemetry_alert.py | 10 +- salt/states/test.py | 6 +- salt/states/testinframod.py | 2 +- salt/states/timezone.py | 14 +- salt/states/tls.py | 4 +- salt/states/tomcat.py | 8 +- salt/states/trafficserver.py | 6 +- salt/states/tuned.py | 8 +- salt/states/uptime.py | 4 +- salt/states/user.py | 34 +- salt/states/vagrant.py | 10 +- salt/states/vault.py | 12 +- salt/states/victorops.py | 2 +- salt/states/virt.py | 70 ++- salt/states/virtualenv_mod.py | 22 +- salt/states/webutil.py | 6 +- salt/states/win_certutil.py | 28 +- salt/states/win_dism.py | 44 +- salt/states/win_dns_client.py | 10 +- salt/states/win_firewall.py | 12 +- salt/states/win_iis.py | 72 +-- salt/states/win_lgpo.py | 4 +- salt/states/win_lgpo_reg.py | 4 +- salt/states/win_network.py | 18 +- salt/states/win_path.py | 20 +- salt/states/win_pki.py | 4 +- salt/states/win_powercfg.py | 12 +- salt/states/win_servermanager.py | 14 +- salt/states/win_shortcut.py | 12 +- salt/states/win_smtp_server.py | 2 +- salt/states/win_snmp.py | 6 +- salt/states/win_system.py | 40 +- salt/states/win_wusa.py | 16 +- salt/states/winrepo.py | 4 +- salt/states/wordpress.py | 28 +- salt/states/x509.py | 16 +- salt/states/xml.py | 8 +- salt/states/xmpp.py | 8 +- salt/states/zabbix_action.py | 28 +- salt/states/zabbix_host.py | 46 +- salt/states/zabbix_hostgroup.py | 20 +- salt/states/zabbix_mediatype.py | 40 +- salt/states/zabbix_template.py | 44 +- salt/states/zabbix_user.py | 30 +- salt/states/zabbix_usergroup.py | 22 +- salt/states/zabbix_usermacro.py | 36 +- salt/states/zabbix_valuemap.py | 28 +- salt/states/zenoss.py | 14 +- salt/states/zfs.py | 74 ++-- salt/states/zk_concurrency.py | 6 +- salt/states/zone.py | 84 ++-- salt/states/zookeeper.py | 28 +- salt/states/zpool.py | 10 +- salt/template.py | 4 +- salt/thorium/__init__.py | 6 +- salt/thorium/calc.py | 2 +- salt/thorium/check.py | 26 +- salt/tokens/localfs.py | 2 +- salt/tops/reclass_adapter.py | 8 +- salt/transport/base.py | 4 +- salt/transport/zeromq.py | 2 +- salt/utils/asynchronous.py | 2 +- salt/utils/atomicfile.py | 2 +- salt/utils/aws.py | 22 +- salt/utils/azurearm.py | 12 +- salt/utils/boto3mod.py | 10 +- salt/utils/botomod.py | 8 +- salt/utils/cache.py | 4 +- salt/utils/color.py | 2 +- salt/utils/configcomparer.py | 10 +- salt/utils/crypt.py | 6 +- salt/utils/dateutils.py | 6 +- salt/utils/debug.py | 8 +- salt/utils/decorators/__init__.py | 14 +- salt/utils/decorators/path.py | 4 +- salt/utils/decorators/state.py | 4 +- salt/utils/dockermod/translate/container.py | 18 +- salt/utils/dockermod/translate/helpers.py | 16 +- salt/utils/etcd_util.py | 18 +- salt/utils/event.py | 26 +- salt/utils/extend.py | 12 +- salt/utils/extmods.py | 8 +- salt/utils/files.py | 24 +- salt/utils/find.py | 28 +- salt/utils/fsutils.py | 2 +- salt/utils/functools.py | 2 +- salt/utils/gitfs.py | 54 ++- salt/utils/github.py | 2 +- salt/utils/hashutils.py | 4 +- salt/utils/immutabletypes.py | 6 +- salt/utils/jid.py | 4 +- salt/utils/job.py | 26 +- salt/utils/kickstart.py | 2 +- salt/utils/lazy.py | 2 +- salt/utils/mac_utils.py | 6 +- salt/utils/mako.py | 2 +- salt/utils/master.py | 14 +- salt/utils/mattermost.py | 2 +- salt/utils/memcached.py | 2 +- salt/utils/minion.py | 2 +- salt/utils/minions.py | 22 +- salt/utils/nacl.py | 24 +- salt/utils/nb_popen.py | 8 +- salt/utils/network.py | 30 +- salt/utils/nxos.py | 16 +- salt/utils/openstack/nova.py | 30 +- salt/utils/oset.py | 12 +- salt/utils/pagerduty.py | 2 +- salt/utils/parsers.py | 50 +-- salt/utils/path.py | 2 +- salt/utils/pbm.py | 20 +- salt/utils/pkg/rpm.py | 4 +- salt/utils/pkg/win.py | 18 +- salt/utils/powershell.py | 6 +- salt/utils/process.py | 8 +- salt/utils/profile.py | 8 +- salt/utils/pushover.py | 4 +- salt/utils/pycrypto.py | 4 +- salt/utils/pydsl.py | 12 +- salt/utils/pyobjects.py | 6 +- salt/utils/roster_matcher.py | 2 +- salt/utils/s3.py | 22 +- salt/utils/saltclass.py | 4 +- salt/utils/schedule.py | 6 +- salt/utils/schema.py | 18 +- salt/utils/slack.py | 2 +- salt/utils/smb.py | 2 +- salt/utils/ssdp.py | 6 +- salt/utils/ssh.py | 2 +- salt/utils/stringutils.py | 14 +- salt/utils/templates.py | 20 +- salt/utils/textformat.py | 2 +- salt/utils/thin.py | 14 +- salt/utils/timed_subprocess.py | 2 +- salt/utils/url.py | 10 +- salt/utils/user.py | 6 +- salt/utils/validate/net.py | 2 +- salt/utils/vault.py | 18 +- salt/utils/verify.py | 20 +- salt/utils/versions.py | 10 +- salt/utils/virt.py | 2 +- salt/utils/virtualbox.py | 4 +- salt/utils/vmware.py | 148 +++---- salt/utils/vsan.py | 22 +- salt/utils/vt.py | 16 +- salt/utils/vt_helper.py | 2 +- salt/utils/win_chcp.py | 8 +- salt/utils/win_dacl.py | 88 ++-- salt/utils/win_dotnet.py | 4 +- salt/utils/win_functions.py | 6 +- salt/utils/win_lgpo_auditpol.py | 18 +- salt/utils/win_lgpo_netsh.py | 56 +-- salt/utils/win_lgpo_reg.py | 12 +- salt/utils/win_pdh.py | 2 +- salt/utils/win_service.py | 8 +- salt/utils/win_update.py | 14 +- salt/utils/xmlutil.py | 10 +- salt/utils/yamlloader.py | 6 +- salt/utils/yamlloader_old.py | 6 +- salt/utils/zfs.py | 6 +- salt/wheel/config.py | 2 +- salt/wheel/file_roots.py | 6 +- salt/wheel/pillar_roots.py | 4 +- scripts/suse/yum/plugins/yumnotify.py | 4 +- setup.py | 10 +- tests/buildpackage.py | 28 +- tests/committer_parser.py | 10 +- tests/conftest.py | 22 +- tests/eventlisten.py | 2 +- tests/integration/cli/test_custom_module.py | 2 +- .../cloud/clouds/test_digitalocean.py | 18 +- .../cloud/clouds/test_dimensiondata.py | 8 +- tests/integration/cloud/clouds/test_ec2.py | 6 +- tests/integration/cloud/clouds/test_gce.py | 6 +- tests/integration/cloud/clouds/test_gogrid.py | 2 +- .../integration/cloud/clouds/test_msazure.py | 6 +- .../cloud/clouds/test_openstack.py | 2 +- .../cloud/clouds/test_profitbricks.py | 16 +- .../cloud/clouds/test_tencentcloud.py | 12 +- .../cloud/clouds/test_virtualbox.py | 10 +- tests/integration/cloud/clouds/test_vmware.py | 10 +- .../integration/cloud/clouds/test_vultrpy.py | 8 +- .../cloud/helpers/cloud_test_base.py | 4 +- tests/integration/cloud/helpers/virtualbox.py | 10 +- tests/integration/cloud/test_cloud.py | 2 +- .../integration/externalapi/test_venafiapi.py | 2 +- .../file/base/_modules/runtests_decorators.py | 4 +- tests/integration/minion/test_timeout.py | 6 +- tests/integration/modules/test_boto_sns.py | 2 +- tests/integration/modules/test_cmdmod.py | 12 +- tests/integration/modules/test_cp.py | 8 +- tests/integration/modules/test_git.py | 32 +- tests/integration/modules/test_groupadd.py | 2 +- .../integration/modules/test_linux_shadow.py | 2 +- tests/integration/modules/test_lxc.py | 4 +- tests/integration/modules/test_mine.py | 16 +- tests/integration/modules/test_mysql.py | 14 +- tests/integration/modules/test_ssh.py | 24 +- tests/integration/pillar/test_git_pillar.py | 6 +- .../runners/test_runner_returns.py | 2 +- tests/integration/shell/test_spm.py | 10 +- tests/integration/ssh/test_state.py | 2 +- tests/integration/states/test_archive.py | 2 +- tests/integration/states/test_boto_sns.py | 16 +- tests/integration/states/test_git.py | 34 +- tests/integration/states/test_host.py | 2 +- tests/integration/states/test_reg.py | 28 +- tests/integration/states/test_ssh_auth.py | 12 +- .../states/test_ssh_known_hosts.py | 10 +- tests/integration/states/test_x509.py | 20 +- tests/integration/utils/test_win_runas.py | 26 +- tests/minionswarm.py | 10 +- tests/pytests/conftest.py | 10 +- tests/pytests/functional/cache/helpers.py | 2 +- .../pytests/functional/channel/test_server.py | 2 +- tests/pytests/functional/cli/test_salt.py | 2 +- .../pytests/functional/cli/test_salt_run_.py | 2 +- tests/pytests/functional/conftest.py | 2 +- .../loader/test_loaded_base_name.py | 2 +- .../log_handlers/test_logstash_mod.py | 4 +- .../functional/modules/cmd/test_powershell.py | 4 +- .../functional/modules/cmd/test_runas.py | 4 +- .../functional/modules/file/test_replace.py | 4 +- .../functional/modules/file/test_rmdir.py | 14 +- .../functional/modules/file/test_symlink.py | 2 +- .../modules/state/requisites/test_mixed.py | 12 +- .../modules/state/requisites/test_require.py | 2 +- .../modules/state/requisites/test_watch.py | 32 +- .../functional/modules/state/test_state.py | 6 +- .../pytests/functional/modules/test_aptpkg.py | 14 +- .../functional/modules/test_archive.py | 8 +- .../functional/modules/test_etcd_mod.py | 27 +- .../functional/modules/test_network.py | 4 +- tests/pytests/functional/modules/test_opkg.py | 2 +- tests/pytests/functional/modules/test_pip.py | 4 +- tests/pytests/functional/modules/test_pkg.py | 24 +- .../functional/modules/test_service.py | 2 +- .../pytests/functional/modules/test_system.py | 4 +- .../pytests/functional/modules/test_vault.py | 22 +- .../functional/modules/test_win_dsc.py | 4 +- .../functional/modules/test_win_shortcut.py | 8 +- .../win_lgpo/test_audit_settings_module.py | 2 +- .../netapi/rest_cherrypy/test_auth.py | 2 +- .../test_external_auth_syntax.py | 20 +- .../netapi/rest_tornado/test_auth_handler.py | 6 +- .../rest_tornado/test_auth_handler_pam.py | 6 +- .../rest_tornado/test_base_api_handler.py | 4 +- .../rest_tornado/test_external_auth_syntax.py | 20 +- .../rest_tornado/test_websockets_handler.py | 10 +- tests/pytests/functional/pillar/test_gpg.py | 6 +- tests/pytests/functional/sdb/test_etcd_db.py | 9 +- .../functional/states/cmd/test_runas.py | 4 +- .../functional/states/file/test_append.py | 2 +- .../states/file/test_blockreplace.py | 4 +- .../functional/states/file/test_cached.py | 8 +- .../functional/states/file/test_managed.py | 26 +- .../functional/states/file/test_patch.py | 4 +- .../functional/states/file/test_pruned.py | 16 +- .../functional/states/file/test_recurse.py | 8 +- .../functional/states/file/test_replace.py | 18 +- .../functional/states/file/test_symlink.py | 2 +- .../functional/states/rabbitmq/conftest.py | 6 +- .../pytests/functional/states/test_archive.py | 10 +- .../states/test_docker_container.py | 26 +- .../functional/states/test_docker_network.py | 12 +- .../functional/states/test_etcd_mod.py | 40 +- tests/pytests/functional/states/test_file.py | 10 +- tests/pytests/functional/states/test_npm.py | 2 +- .../functional/states/test_pip_state.py | 18 +- tests/pytests/functional/states/test_pkg.py | 25 +- tests/pytests/functional/states/test_reg.py | 20 +- .../pytests/functional/states/test_service.py | 2 +- tests/pytests/functional/states/test_svn.py | 2 +- tests/pytests/functional/states/test_user.py | 4 +- .../functional/states/test_virtualenv_mod.py | 6 +- .../functional/states/test_zookeeper.py | 4 +- .../win_lgpo/test_audit_settings_state.py | 2 +- tests/pytests/functional/test_payload.py | 4 +- .../functional/transport/ipc/test_client.py | 2 +- .../transport/ipc/test_pub_server_channel.py | 8 +- .../functional/transport/server/conftest.py | 6 +- .../transport/server/test_req_channel.py | 2 +- .../functools/test_namespaced_function.py | 2 +- .../functional/utils/test_etcd_util.py | 261 ++++++----- tests/pytests/functional/utils/test_jinja.py | 4 +- .../functional/utils/win_dacl/test_reg.py | 2 +- .../test_multiple_processes_logging.py | 2 +- tests/pytests/integration/cli/test_batch.py | 6 +- tests/pytests/integration/cli/test_matcher.py | 22 +- tests/pytests/integration/cli/test_salt.py | 2 +- .../pytests/integration/cli/test_salt_call.py | 8 +- .../integration/cli/test_salt_deltaproxy.py | 20 +- .../pytests/integration/cli/test_salt_key.py | 4 +- .../integration/master/test_clear_funcs.py | 6 +- .../integration/minion/test_job_return.py | 4 +- .../pytests/integration/minion/test_reauth.py | 4 +- .../integration/minion/test_return_retries.py | 4 +- .../modules/state/test_state_test.py | 4 +- .../pytests/integration/modules/test_file.py | 2 +- .../pytests/integration/modules/test_jinja.py | 2 +- .../integration/modules/test_pillar.py | 2 +- tests/pytests/integration/modules/test_pip.py | 6 +- .../modules/test_rpmbuild_pkgbuild.py | 8 +- .../pytests/integration/modules/test_state.py | 8 +- .../pytests/integration/modules/test_virt.py | 6 +- .../netapi/rest_cherrypy/test_arg_kwarg.py | 4 +- .../netapi/rest_cherrypy/test_auth.py | 2 +- .../rest_tornado/test_jobs_api_handler.py | 2 +- .../rest_tornado/test_minions_api_handler.py | 4 +- .../integration/netapi/test_ssh_client.py | 22 +- tests/pytests/integration/proxy/conftest.py | 8 +- .../integration/renderers/test_jinja.py | 4 +- .../runners/state/orchestrate/test_events.py | 8 +- tests/pytests/integration/sdb/test_vault.py | 51 +-- .../integration/ssh/test_jinja_mods.py | 2 +- .../ssh/test_pillar_compilation.py | 6 +- .../integration/states/test_ansiblegate.py | 2 +- tests/pytests/integration/states/test_file.py | 47 +- tests/pytests/integration/states/test_idem.py | 2 +- .../integration/utils/test_templates.py | 4 +- .../integration/wheel/test_pillar_roots.py | 4 +- .../pkg/integration/test_multi_minion.py | 30 +- tests/pytests/pkg/integration/test_pip.py | 20 +- .../pkg/integration/test_pip_upgrade.py | 10 +- tests/pytests/pkg/integration/test_version.py | 3 +- tests/pytests/scenarios/blackout/conftest.py | 2 +- tests/pytests/scenarios/compat/conftest.py | 2 +- .../failover/multimaster/conftest.py | 10 +- .../multimaster/test_failover_master.py | 18 +- .../multimaster/beacons/test_inotify.py | 2 +- .../pytests/scenarios/multimaster/conftest.py | 10 +- .../scenarios/multimaster/test_multimaster.py | 4 +- .../multimaster/test_offline_master.py | 4 +- .../pytests/scenarios/performance/conftest.py | 4 +- tests/pytests/scenarios/setup/test_man.py | 2 +- tests/pytests/unit/beacons/test_btmp.py | 2 +- tests/pytests/unit/beacons/test_inotify.py | 4 +- tests/pytests/unit/beacons/test_wtmp.py | 2 +- tests/pytests/unit/cli/test_daemons.py | 8 +- tests/pytests/unit/client/ssh/test_shell.py | 4 +- tests/pytests/unit/client/ssh/test_single.py | 4 +- .../pytests/unit/cloud/clouds/test_proxmox.py | 10 +- tests/pytests/unit/config/schemas/test_ssh.py | 14 +- .../unit/crypt/test_crypt_cryptodome.py | 6 +- .../pytests/unit/crypt/test_crypt_m2crypto.py | 42 +- .../unit/daemons/masterapi/test_auto_key.py | 6 +- tests/pytests/unit/engines/test_engines.py | 2 +- .../unit/fileclient/test_fileclient.py | 2 +- .../unit/fileclient/test_fileclient_cache.py | 14 +- .../fileserver/gitfs/test_gitfs_config.py | 2 +- tests/pytests/unit/grains/test_core.py | 20 +- .../modules/file/test_file_block_replace.py | 22 +- .../unit/modules/file/test_file_chattr.py | 2 +- .../unit/modules/file/test_file_check.py | 4 +- .../unit/modules/file/test_file_grep.py | 4 +- .../unit/modules/file/test_file_line.py | 4 +- .../unit/modules/file/test_file_module.py | 2 +- .../unit/modules/file/test_file_selinux.py | 2 +- .../pytests/unit/modules/napalm/test_route.py | 2 +- .../pytests/unit/modules/state/test_state.py | 22 +- tests/pytests/unit/modules/test_aixpkg.py | 36 +- .../pytests/unit/modules/test_ansiblegate.py | 7 +- tests/pytests/unit/modules/test_beacons.py | 4 +- .../unit/modules/test_cassandra_cql.py | 2 +- tests/pytests/unit/modules/test_chroot.py | 6 +- tests/pytests/unit/modules/test_consul.py | 16 +- tests/pytests/unit/modules/test_disk.py | 4 +- tests/pytests/unit/modules/test_genesis.py | 7 +- tests/pytests/unit/modules/test_glusterfs.py | 2 +- tests/pytests/unit/modules/test_ini_manage.py | 2 +- tests/pytests/unit/modules/test_introspect.py | 8 +- tests/pytests/unit/modules/test_iptables.py | 4 +- tests/pytests/unit/modules/test_junos.py | 4 +- tests/pytests/unit/modules/test_kmod.py | 4 +- tests/pytests/unit/modules/test_linux_lvm.py | 2 +- .../unit/modules/test_mac_assistive.py | 2 +- tests/pytests/unit/modules/test_match.py | 2 +- tests/pytests/unit/modules/test_mine.py | 2 +- tests/pytests/unit/modules/test_mysql.py | 2 +- .../unit/modules/test_openbsdrcctl_service.py | 24 +- tests/pytests/unit/modules/test_openscap.py | 10 +- tests/pytests/unit/modules/test_pacmanpkg.py | 4 +- tests/pytests/unit/modules/test_parallels.py | 4 +- tests/pytests/unit/modules/test_pip.py | 2 +- tests/pytests/unit/modules/test_poudriere.py | 6 +- tests/pytests/unit/modules/test_reg.py | 6 +- .../pytests/unit/modules/test_restartcheck.py | 8 +- tests/pytests/unit/modules/test_status.py | 2 +- tests/pytests/unit/modules/test_suse_ip.py | 8 +- tests/pytests/unit/modules/test_syslog_ng.py | 2 +- tests/pytests/unit/modules/test_tls.py | 16 +- tests/pytests/unit/modules/test_uwsgi.py | 2 +- tests/pytests/unit/modules/test_vagrant.py | 4 +- tests/pytests/unit/modules/test_win_iis.py | 2 +- tests/pytests/unit/modules/test_win_pkg.py | 4 +- tests/pytests/unit/modules/test_yumpkg.py | 2 +- tests/pytests/unit/modules/virt/conftest.py | 8 +- .../pytests/unit/modules/virt/test_domain.py | 7 +- .../modules/win_lgpo/test__policy_info.py | 2 +- .../modules/win_lgpo/test_admx_policies.py | 2 +- .../modules/win_lgpo/test_secedit_policy.py | 2 +- .../unit/pillar/test_http_json_pillar.py | 8 +- .../unit/pillar/test_http_yaml_pillar.py | 4 +- tests/pytests/unit/pillar/test_mysql.py | 12 +- tests/pytests/unit/pillar/test_s3.py | 6 +- tests/pytests/unit/pillar/test_saltclass.py | 2 +- .../returners/test_slack_webhook_return.py | 12 +- .../unit/returners/test_syslog_return.py | 2 +- tests/pytests/unit/roster/test_dir.py | 4 +- tests/pytests/unit/runners/test_fileserver.py | 2 +- tests/pytests/unit/runners/test_saltutil.py | 4 +- .../pytests/unit/runners/vault/test_vault.py | 2 +- .../unit/serializers/test_serializers.py | 2 +- .../pytests/unit/state/test_state_compiler.py | 4 +- tests/pytests/unit/states/apache/test_conf.py | 12 +- .../pytests/unit/states/apache/test_module.py | 12 +- tests/pytests/unit/states/apache/test_site.py | 12 +- tests/pytests/unit/states/file/test_absent.py | 16 +- .../pytests/unit/states/file/test_comment.py | 12 +- tests/pytests/unit/states/file/test_copy.py | 10 +- .../unit/states/file/test_directory.py | 14 +- .../unit/states/file/test_filestate.py | 36 +- .../pytests/unit/states/file/test_hardlink.py | 34 +- .../pytests/unit/states/file/test_managed.py | 14 +- .../pytests/unit/states/file/test_prepend.py | 6 +- .../states/file/test_private_functions.py | 6 +- tests/pytests/unit/states/file/test_pruned.py | 6 +- tests/pytests/unit/states/file/test_rename.py | 14 +- .../pytests/unit/states/file/test_selinux.py | 2 +- .../pytests/unit/states/file/test_symlink.py | 28 +- tests/pytests/unit/states/file/test_tidied.py | 30 +- .../unit/states/mysql/test_database.py | 14 +- tests/pytests/unit/states/mysql/test_query.py | 2 +- .../unit/states/postgresql/test_cluster.py | 20 +- .../unit/states/postgresql/test_database.py | 8 +- .../unit/states/postgresql/test_initdb.py | 8 +- .../unit/states/postgresql/test_language.py | 16 +- .../unit/states/rabbitmq/test_vhost.py | 2 +- .../unit/states/saltmod/test_function.py | 6 +- tests/pytests/unit/states/test_alias.py | 16 +- .../pytests/unit/states/test_alternatives.py | 26 +- tests/pytests/unit/states/test_aptpkg.py | 2 +- tests/pytests/unit/states/test_archive.py | 4 +- tests/pytests/unit/states/test_at.py | 4 +- tests/pytests/unit/states/test_aws_sqs.py | 8 +- tests/pytests/unit/states/test_blockdev.py | 10 +- .../unit/states/test_boto_cloudfront.py | 6 +- .../unit/states/test_boto_cloudwatch_alarm.py | 2 +- .../pytests/unit/states/test_boto_dynamodb.py | 8 +- tests/pytests/unit/states/test_boto_ec2.py | 10 +- .../unit/states/test_boto_elasticache.py | 12 +- tests/pytests/unit/states/test_boto_elb.py | 6 +- .../pytests/unit/states/test_boto_iam_role.py | 2 +- .../pytests/unit/states/test_boto_kinesis.py | 12 +- .../pytests/unit/states/test_boto_route53.py | 10 +- tests/pytests/unit/states/test_boto_sns.py | 12 +- tests/pytests/unit/states/test_boto_sqs.py | 6 +- tests/pytests/unit/states/test_cloud.py | 46 +- tests/pytests/unit/states/test_ddns.py | 6 +- tests/pytests/unit/states/test_drac.py | 8 +- tests/pytests/unit/states/test_eselect.py | 2 +- tests/pytests/unit/states/test_file.py | 4 +- tests/pytests/unit/states/test_glusterfs.py | 34 +- tests/pytests/unit/states/test_grafana.py | 2 +- tests/pytests/unit/states/test_host.py | 57 +-- tests/pytests/unit/states/test_incron.py | 18 +- .../unit/states/test_influxdb08_database.py | 16 +- .../unit/states/test_influxdb08_user.py | 16 +- tests/pytests/unit/states/test_keyboard.py | 12 +- tests/pytests/unit/states/test_keystone.py | 52 +-- tests/pytests/unit/states/test_kmod.py | 12 +- tests/pytests/unit/states/test_kubernetes.py | 4 +- tests/pytests/unit/states/test_layman.py | 8 +- tests/pytests/unit/states/test_linux_acl.py | 12 +- tests/pytests/unit/states/test_lvm.py | 44 +- tests/pytests/unit/states/test_lxc.py | 18 +- tests/pytests/unit/states/test_makeconf.py | 4 +- .../unit/states/test_mongodb_database.py | 6 +- .../pytests/unit/states/test_mongodb_user.py | 10 +- tests/pytests/unit/states/test_mount.py | 26 +- tests/pytests/unit/states/test_npm.py | 12 +- tests/pytests/unit/states/test_pagerduty.py | 4 +- tests/pytests/unit/states/test_pdbedit.py | 2 +- tests/pytests/unit/states/test_pecl.py | 4 +- tests/pytests/unit/states/test_pkg.py | 6 +- tests/pytests/unit/states/test_ports.py | 2 +- tests/pytests/unit/states/test_powerpath.py | 4 +- .../pytests/unit/states/test_pyrax_queues.py | 2 +- tests/pytests/unit/states/test_rbenv.py | 18 +- tests/pytests/unit/states/test_saltutil.py | 2 +- tests/pytests/unit/states/test_selinux.py | 2 +- tests/pytests/unit/states/test_service.py | 8 +- tests/pytests/unit/states/test_slack.py | 4 +- tests/pytests/unit/states/test_smartos.py | 7 +- .../pytests/unit/states/test_splunk_search.py | 8 +- tests/pytests/unit/states/test_ssh_auth.py | 2 +- .../unit/states/test_ssh_known_hosts.py | 2 +- tests/pytests/unit/states/test_supervisord.py | 2 +- tests/pytests/unit/states/test_sysctl.py | 14 +- tests/pytests/unit/states/test_sysfs.py | 12 +- tests/pytests/unit/states/test_win_path.py | 28 +- tests/pytests/unit/states/test_win_wusa.py | 32 +- tests/pytests/unit/states/test_xml.py | 8 +- .../pytests/unit/states/zabbix/test_action.py | 22 +- .../unit/states/zabbix/test_template.py | 22 +- .../unit/states/zabbix/test_valuemap.py | 22 +- tests/pytests/unit/test_ext_importers.py | 5 +- tests/pytests/unit/test_log.py | 8 +- tests/pytests/unit/tokens/test_localfs.py | 2 +- tests/pytests/unit/transport/test_zeromq.py | 61 ++- .../unit/utils/event/test_event_return.py | 2 +- .../utils/jinja/test_custom_extensions.py | 10 +- .../unit/utils/parsers/test_log_parsers.py | 18 +- .../utils/templates/test_wrap_tmpl_func.py | 2 +- tests/pytests/unit/utils/test_cache.py | 6 +- tests/pytests/unit/utils/test_cloud.py | 34 +- tests/pytests/unit/utils/test_files.py | 2 +- tests/pytests/unit/utils/test_gitfs.py | 4 +- tests/pytests/unit/utils/test_http.py | 2 +- tests/pytests/unit/utils/test_nacl.py | 4 +- tests/pytests/unit/utils/test_pycrypto.py | 8 +- tests/pytests/unit/utils/test_stringutils.py | 34 +- tests/pytests/unit/utils/test_versions.py | 8 +- tests/pytests/unit/utils/test_win_reg.py | 12 +- .../unit/utils/verify/test_clean_path_link.py | 4 +- .../unit/utils/win_lgpo/test_auditpol.py | 2 +- tests/support/case.py | 22 +- tests/support/gitfs.py | 12 +- tests/support/helpers.py | 24 +- tests/support/mixins.py | 22 +- tests/support/mock.py | 4 +- tests/support/netapi.py | 6 +- tests/support/pytest/etcd.py | 4 +- tests/support/pytest/helpers.py | 14 +- tests/support/pytest/loader.py | 8 +- tests/support/pytest/mysql.py | 14 +- tests/support/pytest/transport.py | 4 +- tests/support/sminion.py | 2 +- tests/support/virt.py | 8 +- tests/support/win_installer.py | 6 +- tests/unit/modules/test_boto_apigateway.py | 94 ++-- tests/unit/modules/test_boto_route53.py | 2 +- tests/unit/modules/test_boto_secgroup.py | 2 +- tests/unit/modules/test_boto_vpc.py | 23 +- tests/unit/modules/test_cron.py | 10 +- tests/unit/modules/test_heat.py | 2 +- tests/unit/modules/test_k8s.py | 56 ++- .../unit/modules/test_kernelpkg_linux_apt.py | 5 +- .../unit/modules/test_kernelpkg_linux_yum.py | 2 +- tests/unit/modules/test_linux_acl.py | 2 +- tests/unit/modules/test_localemod.py | 4 +- tests/unit/modules/test_napalm_probes.py | 2 +- tests/unit/modules/test_rh_ip.py | 12 +- tests/unit/modules/test_ssh.py | 16 +- tests/unit/modules/test_sysmod.py | 6 +- tests/unit/modules/test_virt.py | 22 +- tests/unit/modules/test_virtualenv_mod.py | 2 +- tests/unit/modules/test_vsphere.py | 6 +- tests/unit/modules/test_win_wusa.py | 8 +- tests/unit/modules/test_zcbuildout.py | 26 +- tests/unit/modules/test_zypperpkg.py | 10 +- .../unit/states/test_boto_cognitoidentity.py | 46 +- tests/unit/states/test_boto_vpc.py | 16 +- tests/unit/states/test_ipset.py | 14 +- tests/unit/states/test_module.py | 34 +- tests/unit/test_auth.py | 2 +- tests/unit/test_config.py | 66 ++- tests/unit/test_mock.py | 6 +- tests/unit/test_zypp_plugins.py | 2 +- tests/unit/transport/test_tcp.py | 8 +- tests/unit/utils/test_botomod.py | 4 +- tests/unit/utils/test_dns.py | 8 +- tests/unit/utils/test_dockermod.py | 16 +- tests/unit/utils/test_jid.py | 4 +- tests/unit/utils/test_json.py | 2 +- tests/unit/utils/test_pbm.py | 2 +- tests/unit/utils/test_process.py | 6 +- tests/unit/utils/test_schema.py | 90 ++-- tests/unit/utils/test_ssdp.py | 25 +- tests/unit/utils/test_state.py | 12 +- tests/unit/utils/test_systemd.py | 8 +- tests/unit/utils/test_thin.py | 20 +- tests/unit/utils/test_vt.py | 6 +- tests/unit/utils/test_win_service.py | 4 +- tests/unit/utils/test_win_system.py | 4 +- tools/precommit/docs.py | 9 +- 1424 files changed, 11463 insertions(+), 12874 deletions(-) diff --git a/.gitignore b/.gitignore index 7561cae50f2..63b49a64487 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,7 @@ Session.vim # Nox requirements archives nox.*.tar.bzip2 +nox.*.tar.gz nox.*.tar.xz # Debian packages diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9067d37d074..7389a5d5b8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1625,8 +1625,8 @@ repos: rev: v3.15.1 hooks: - id: pyupgrade - name: Drop six usage and Py2 support - args: [--py3-plus, --keep-mock] + name: Upgrade code to Py3.7+ + args: [--py37-plus, --keep-mock] exclude: > (?x)^( salt/client/ssh/ssh_py_shim.py diff --git a/doc/_ext/saltdomain.py b/doc/_ext/saltdomain.py index 9810ae4c31a..03ad25cb93c 100644 --- a/doc/_ext/saltdomain.py +++ b/doc/_ext/saltdomain.py @@ -53,7 +53,7 @@ class LiterateCoding(Directive): comment; False designates code. """ comment_char = "#" # TODO: move this into a directive option - comment = re.compile(r"^\s*{}[ \n]".format(comment_char)) + comment = re.compile(rf"^\s*{comment_char}[ \n]") section_test = lambda val: bool(comment.match(val)) sections = [] @@ -136,7 +136,7 @@ class LiterateFormula(LiterateCoding): formulas_dirs = config.formulas_dirs fpath = sls_path.replace(".", "/") - name_options = ("{}.sls".format(fpath), os.path.join(fpath, "init.sls")) + name_options = (f"{fpath}.sls", os.path.join(fpath, "init.sls")) paths = [ os.path.join(fdir, fname) @@ -151,7 +151,7 @@ class LiterateFormula(LiterateCoding): except OSError: pass - raise OSError("Could not find sls file '{}'".format(sls_path)) + raise OSError(f"Could not find sls file '{sls_path}'") class CurrentFormula(Directive): @@ -196,7 +196,7 @@ class Formula(Directive): targetnode = nodes.target("", "", ids=["module-" + formname], ismod=True) self.state.document.note_explicit_target(targetnode) - indextext = "{}-formula)".format(formname) + indextext = f"{formname}-formula)" inode = addnodes.index( entries=[("single", indextext, "module-" + formname, "")] ) @@ -221,9 +221,9 @@ class State(Directive): formula = env.temp_data.get("salt:formula") - indextext = "{1} ({0}-formula)".format(formula, statename) + indextext = f"{statename} ({formula}-formula)" inode = addnodes.index( - entries=[("single", indextext, "module-{}".format(statename), "")] + entries=[("single", indextext, f"module-{statename}", "")] ) return [targetnode, inode] diff --git a/noxfile.py b/noxfile.py index 05de53de6f6..16433437f5f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -107,7 +107,7 @@ def session_warn(session, message): try: session.warn(message) except AttributeError: - session.log("WARNING: {}".format(message)) + session.log(f"WARNING: {message}") def session_run_always(session, *command, **kwargs): @@ -132,15 +132,15 @@ def session_run_always(session, *command, **kwargs): def find_session_runner(session, name, python_version, onedir=False, **kwargs): if onedir: - name += "-onedir-{}".format(ONEDIR_PYTHON_PATH) + name += f"-onedir-{ONEDIR_PYTHON_PATH}" else: - name += "-{}".format(python_version) + name += f"-{python_version}" for s, _ in session._runner.manifest.list_all_sessions(): if name not in s.signatures: continue for signature in s.signatures: for key, value in kwargs.items(): - param = "{}={!r}".format(key, value) + param = f"{key}={value!r}" if param not in signature: break else: @@ -211,7 +211,7 @@ def _get_pip_requirements_file(session, crypto=None, requirements_type="ci"): ) if os.path.exists(_requirements_file): return _requirements_file - session.error("Could not find a windows requirements file for {}".format(pydir)) + session.error(f"Could not find a windows requirements file for {pydir}") elif IS_DARWIN: if crypto is None: _requirements_file = os.path.join( @@ -224,7 +224,7 @@ def _get_pip_requirements_file(session, crypto=None, requirements_type="ci"): ) if os.path.exists(_requirements_file): return _requirements_file - session.error("Could not find a darwin requirements file for {}".format(pydir)) + session.error(f"Could not find a darwin requirements file for {pydir}") elif IS_FREEBSD: if crypto is None: _requirements_file = os.path.join( @@ -237,7 +237,7 @@ def _get_pip_requirements_file(session, crypto=None, requirements_type="ci"): ) if os.path.exists(_requirements_file): return _requirements_file - session.error("Could not find a freebsd requirements file for {}".format(pydir)) + session.error(f"Could not find a freebsd requirements file for {pydir}") else: if crypto is None: _requirements_file = os.path.join( @@ -250,7 +250,7 @@ def _get_pip_requirements_file(session, crypto=None, requirements_type="ci"): ) if os.path.exists(_requirements_file): return _requirements_file - session.error("Could not find a linux requirements file for {}".format(pydir)) + session.error(f"Could not find a linux requirements file for {pydir}") def _upgrade_pip_setuptools_and_wheel(session, upgrade=True): @@ -569,7 +569,7 @@ def test_parametrized(session, coverage, transport, crypto): session.install(*install_command, silent=PIP_INSTALL_SILENT) cmd_args = [ - "--transport={}".format(transport), + f"--transport={transport}", ] + session.posargs _pytest(session, coverage=coverage, cmd_args=cmd_args) @@ -1014,7 +1014,7 @@ def _pytest(session, coverage, cmd_args, env=None, on_rerun=False): if arg == "--log-file" or arg.startswith("--log-file="): break else: - args.append("--log-file={}".format(RUNTESTS_LOGFILE)) + args.append(f"--log-file={RUNTESTS_LOGFILE}") args.extend(cmd_args) if PRINT_SYSTEM_INFO_ONLY and "--sys-info-and-exit" not in args: @@ -1487,7 +1487,7 @@ def _lint(session, rcfile, flags, paths, upgrade_setuptools_and_pip=True): ] session.install(*install_command, silent=PIP_INSTALL_SILENT) - cmd_args = ["pylint", "--rcfile={}".format(rcfile)] + list(flags) + list(paths) + cmd_args = ["pylint", f"--rcfile={rcfile}"] + list(flags) + list(paths) cmd_kwargs = {"env": {"PYTHONUNBUFFERED": "1"}} session.run(*cmd_args, **cmd_kwargs) @@ -1528,8 +1528,8 @@ def lint(session): """ Run PyLint against Salt and it's test suite. """ - session.notify("lint-salt-{}".format(session.python)) - session.notify("lint-tests-{}".format(session.python)) + session.notify(f"lint-salt-{session.python}") + session.notify(f"lint-tests-{session.python}") @nox.session(python="3", name="lint-salt") @@ -1593,7 +1593,7 @@ def docs(session, compress, update, clean): """ Build Salt's Documentation """ - session.notify("docs-html-{}(compress={})".format(session.python, compress)) + session.notify(f"docs-html-{session.python}(compress={compress})") session.notify( find_session_runner( session, diff --git a/salt/__init__.py b/salt/__init__.py index 409ccabb2c3..17535b986a4 100644 --- a/salt/__init__.py +++ b/salt/__init__.py @@ -22,7 +22,7 @@ class TornadoImporter: def create_module(self, spec): if USE_VENDORED_TORNADO: - mod = importlib.import_module("salt.ext.{}".format(spec.name)) + mod = importlib.import_module(f"salt.ext.{spec.name}") else: # pragma: no cover # Remove 'salt.ext.' from the module mod = importlib.import_module(spec.name[9:]) diff --git a/salt/_logging/impl.py b/salt/_logging/impl.py index 9ffa5320301..832c72b4769 100644 --- a/salt/_logging/impl.py +++ b/salt/_logging/impl.py @@ -108,9 +108,9 @@ DFLT_LOG_FMT_LOGFILE = "%(asctime)s,%(msecs)03d [%(name)-17s:%(lineno)-4d][%(lev class SaltLogRecord(logging.LogRecord): def __init__(self, *args, **kwargs): logging.LogRecord.__init__(self, *args, **kwargs) - self.bracketname = "[{:<17}]".format(str(self.name)) - self.bracketlevel = "[{:<8}]".format(str(self.levelname)) - self.bracketprocess = "[{:>5}]".format(str(self.process)) + self.bracketname = f"[{str(self.name):<17}]" + self.bracketlevel = f"[{str(self.levelname):<8}]" + self.bracketprocess = f"[{str(self.process):>5}]" class SaltColorLogRecord(SaltLogRecord): @@ -124,11 +124,11 @@ class SaltColorLogRecord(SaltLogRecord): self.colorname = "{}[{:<17}]{}".format( LOG_COLORS["name"], str(self.name), reset ) - self.colorlevel = "{}[{:<8}]{}".format(clevel, str(self.levelname), reset) + self.colorlevel = f"{clevel}[{str(self.levelname):<8}]{reset}" self.colorprocess = "{}[{:>5}]{}".format( LOG_COLORS["process"], str(self.process), reset ) - self.colormsg = "{}{}{}".format(cmsg, self.getMessage(), reset) + self.colormsg = f"{cmsg}{self.getMessage()}{reset}" def get_log_record_factory(): @@ -726,7 +726,7 @@ def setup_logfile_handler( syslog_opts["address"] = str(path.resolve().parent) except OSError as exc: raise LoggingRuntimeError( - "Failed to setup the Syslog logging handler: {}".format(exc) + f"Failed to setup the Syslog logging handler: {exc}" ) from exc elif parsed_log_path.path: # In case of udp or tcp with a facility specified @@ -736,7 +736,7 @@ def setup_logfile_handler( # Logging facilities start with LOG_ if this is not the case # fail right now! raise LoggingRuntimeError( - "The syslog facility '{}' is not known".format(facility_name) + f"The syslog facility '{facility_name}' is not known" ) else: # This is the case of udp or tcp without a facility specified @@ -747,7 +747,7 @@ def setup_logfile_handler( # This python syslog version does not know about the user provided # facility name raise LoggingRuntimeError( - "The syslog facility '{}' is not known".format(facility_name) + f"The syslog facility '{facility_name}' is not known" ) syslog_opts["facility"] = facility @@ -767,7 +767,7 @@ def setup_logfile_handler( handler = SysLogHandler(**syslog_opts) except OSError as exc: raise LoggingRuntimeError( - "Failed to setup the Syslog logging handler: {}".format(exc) + f"Failed to setup the Syslog logging handler: {exc}" ) from exc else: # make sure, the logging directory exists and attempt to create it if necessary diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py index df2eebe4f85..019c9822963 100644 --- a/salt/auth/__init__.py +++ b/salt/auth/__init__.py @@ -137,7 +137,7 @@ class LoadAuth: mod = self.opts["eauth_acl_module"] if not mod: mod = load["eauth"] - fstr = "{}.acl".format(mod) + fstr = f"{mod}.acl" if fstr not in self.auth: return None fcall = salt.utils.args.format_call( @@ -474,7 +474,7 @@ class LoadAuth: msg = 'Authentication failure of type "user" occurred' if not auth_ret: # auth_ret can be a boolean or the effective user id if show_username: - msg = "{} for user {}.".format(msg, username) + msg = f"{msg} for user {username}." ret["error"] = {"name": "UserAuthenticationError", "message": msg} return ret @@ -535,7 +535,7 @@ class Resolver: if not eauth: print("External authentication system has not been specified") return ret - fstr = "{}.auth".format(eauth) + fstr = f"{eauth}.auth" if fstr not in self.auth: print( 'The specified external authentication system "{}" is not available'.format( @@ -554,14 +554,14 @@ class Resolver: if arg in self.opts: ret[arg] = self.opts[arg] elif arg.startswith("pass"): - ret[arg] = getpass.getpass("{}: ".format(arg)) + ret[arg] = getpass.getpass(f"{arg}: ") else: - ret[arg] = input("{}: ".format(arg)) + ret[arg] = input(f"{arg}: ") for kwarg, default in list(args["kwargs"].items()): if kwarg in self.opts: ret["kwarg"] = self.opts[kwarg] else: - ret[kwarg] = input("{} [{}]: ".format(kwarg, default)) + ret[kwarg] = input(f"{kwarg} [{default}]: ") # Use current user if empty if "username" in ret and not ret["username"]: diff --git a/salt/auth/django.py b/salt/auth/django.py index 0b810b83510..d11fa438f30 100644 --- a/salt/auth/django.py +++ b/salt/auth/django.py @@ -111,7 +111,7 @@ def __django_auth_setup(): django_module_name, globals(), locals(), "SaltExternalAuthModel" ) # pylint: enable=possibly-unused-variable - DJANGO_AUTH_CLASS_str = "django_auth_module.{}".format(django_model_name) + DJANGO_AUTH_CLASS_str = f"django_auth_module.{django_model_name}" DJANGO_AUTH_CLASS = eval(DJANGO_AUTH_CLASS_str) # pylint: disable=W0123 diff --git a/salt/auth/ldap.py b/salt/auth/ldap.py index 604f06c3d20..a3c952ce678 100644 --- a/salt/auth/ldap.py +++ b/salt/auth/ldap.py @@ -54,15 +54,15 @@ def _config(key, mandatory=True, opts=None): """ try: if opts: - value = opts["auth.ldap.{}".format(key)] + value = opts[f"auth.ldap.{key}"] else: - value = __opts__["auth.ldap.{}".format(key)] + value = __opts__[f"auth.ldap.{key}"] except KeyError: try: - value = __defopts__["auth.ldap.{}".format(key)] + value = __defopts__[f"auth.ldap.{key}"] except KeyError: if mandatory: - msg = "missing auth.ldap.{} in master config".format(key) + msg = f"missing auth.ldap.{key} in master config" raise SaltInvocationError(msg) return False return value @@ -120,13 +120,13 @@ class _LDAPConnection: schema = "ldaps" if tls else "ldap" if self.uri == "": - self.uri = "{}://{}:{}".format(schema, self.server, self.port) + self.uri = f"{schema}://{self.server}:{self.port}" try: if no_verify: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) - self.ldap = ldap.initialize("{}".format(self.uri)) + self.ldap = ldap.initialize(f"{self.uri}") self.ldap.protocol_version = 3 # ldap.VERSION3 self.ldap.set_option(ldap.OPT_REFERRALS, 0) # Needed for AD diff --git a/salt/auth/pam.py b/salt/auth/pam.py index 12af29bbdb8..6e179deb7c6 100644 --- a/salt/auth/pam.py +++ b/salt/auth/pam.py @@ -104,7 +104,7 @@ class PamMessage(Structure): ] def __repr__(self): - return "".format(self.msg_style, self.msg) + return f"" class PamResponse(Structure): @@ -118,7 +118,7 @@ class PamResponse(Structure): ] def __repr__(self): - return "".format(self.resp_retcode, self.resp) + return f"" CONV_FUNC = CFUNCTYPE( @@ -236,8 +236,7 @@ def authenticate(username, password): ret = subprocess.run( [str(pyexe), str(pyfile)], env=env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, check=False, ) if ret.returncode == 0: diff --git a/salt/beacons/__init__.py b/salt/beacons/__init__.py index a1e3da3ac51..5fe72327fbf 100644 --- a/salt/beacons/__init__.py +++ b/salt/beacons/__init__.py @@ -75,7 +75,7 @@ class Beacon: # Run the validate function if it's available, # otherwise there is a warning about it being missing - validate_str = "{}.validate".format(beacon_name) + validate_str = f"{beacon_name}.validate" if validate_str in self.beacons: valid, vcomment = self.beacons[validate_str](b_config[mod]) @@ -96,7 +96,7 @@ class Beacon: continue b_config[mod].append({"_beacon_name": mod}) - fun_str = "{}.beacon".format(beacon_name) + fun_str = f"{beacon_name}.beacon" if fun_str in self.beacons: runonce = self._determine_beacon_config( current_beacon_config, "run_once" @@ -125,7 +125,7 @@ class Beacon: if re.match("state.*", job["fun"]): is_running = True if is_running: - close_str = "{}.close".format(beacon_name) + close_str = f"{beacon_name}.close" if close_str in self.beacons: log.info("Closing beacon %s. State run in progress.", mod) self.beacons[close_str](b_config[mod]) @@ -140,7 +140,7 @@ class Beacon: try: raw = self.beacons[fun_str](b_config[mod]) except: # pylint: disable=bare-except - error = "{}".format(sys.exc_info()[1]) + error = f"{sys.exc_info()[1]}" log.error("Unable to start %s beacon, %s", mod, error) # send beacon error event tag = "salt/beacon/{}/{}/".format(self.opts["id"], mod) @@ -309,7 +309,7 @@ class Beacon: """ beacon_name = next(item.get("beacon_module", name) for item in beacon_data) - validate_str = "{}.validate".format(beacon_name) + validate_str = f"{beacon_name}.validate" # Run the validate function if it's available, # otherwise there is a warning about it being missing if validate_str in self.beacons: @@ -348,9 +348,9 @@ class Beacon: complete = False else: if name in self.opts["beacons"]: - comment = "Updating settings for beacon item: {}".format(name) + comment = f"Updating settings for beacon item: {name}" else: - comment = "Added new beacon item: {}".format(name) + comment = f"Added new beacon item: {name}" complete = True self.opts["beacons"].update(data) @@ -376,12 +376,10 @@ class Beacon: data[name] = beacon_data if name in self._get_beacons(include_opts=False): - comment = ( - "Cannot modify beacon item {}, it is configured in pillar.".format(name) - ) + comment = f"Cannot modify beacon item {name}, it is configured in pillar." complete = False else: - comment = "Updating settings for beacon item: {}".format(name) + comment = f"Updating settings for beacon item: {name}" complete = True self.opts["beacons"].update(data) @@ -403,16 +401,14 @@ class Beacon: """ if name in self._get_beacons(include_opts=False): - comment = ( - "Cannot delete beacon item {}, it is configured in pillar.".format(name) - ) + comment = f"Cannot delete beacon item {name}, it is configured in pillar." complete = False else: if name in self.opts["beacons"]: del self.opts["beacons"][name] - comment = "Deleting beacon item: {}".format(name) + comment = f"Deleting beacon item: {name}" else: - comment = "Beacon item {} not found.".format(name) + comment = f"Beacon item {name} not found." complete = True # Fire the complete event back along with updated list of beacons @@ -466,13 +462,11 @@ class Beacon: """ if name in self._get_beacons(include_opts=False): - comment = ( - "Cannot enable beacon item {}, it is configured in pillar.".format(name) - ) + comment = f"Cannot enable beacon item {name}, it is configured in pillar." complete = False else: self._update_enabled(name, True) - comment = "Enabling beacon item {}".format(name) + comment = f"Enabling beacon item {name}" complete = True # Fire the complete event back along with updated list of beacons @@ -502,7 +496,7 @@ class Beacon: complete = False else: self._update_enabled(name, False) - comment = "Disabling beacon item {}".format(name) + comment = f"Disabling beacon item {name}" complete = True # Fire the complete event back along with updated list of beacons diff --git a/salt/beacons/btmp.py b/salt/beacons/btmp.py index f980a3ff4e1..a5d10f997fc 100644 --- a/salt/beacons/btmp.py +++ b/salt/beacons/btmp.py @@ -130,7 +130,7 @@ except ImportError: def __virtual__(): if os.path.isfile(BTMP): return __virtualname__ - err_msg = "{} does not exist.".format(BTMP) + err_msg = f"{BTMP} does not exist." log.error("Unable to load %s beacon: %s", __virtualname__, err_msg) return False, err_msg diff --git a/salt/beacons/diskusage.py b/salt/beacons/diskusage.py index eab69786902..da904cfa520 100644 --- a/salt/beacons/diskusage.py +++ b/salt/beacons/diskusage.py @@ -95,7 +95,7 @@ def beacon(config): # if our mount doesn't end with a $, insert one. mount_re = mount if not mount.endswith("$"): - mount_re = "{}$".format(mount) + mount_re = f"{mount}$" if salt.utils.platform.is_windows(): # mount_re comes in formatted with a $ at the end diff --git a/salt/beacons/inotify.py b/salt/beacons/inotify.py index 283b84fdc73..3b11322319b 100644 --- a/salt/beacons/inotify.py +++ b/salt/beacons/inotify.py @@ -68,7 +68,7 @@ def _get_notifier(config): Check the context for the notifier and construct it if not present """ beacon_name = config.get("_beacon_name", "inotify") - notifier = "{}.notifier".format(beacon_name) + notifier = f"{beacon_name}.notifier" if notifier not in __context__: __context__["inotify.queue"] = collections.deque() wm = pyinotify.WatchManager() @@ -353,7 +353,7 @@ def beacon(config): def close(config): config = salt.utils.beacons.list_to_dict(config) beacon_name = config.get("_beacon_name", "inotify") - notifier = "{}.notifier".format(beacon_name) + notifier = f"{beacon_name}.notifier" if notifier in __context__: __context__[notifier].stop() del __context__[notifier] diff --git a/salt/beacons/napalm_beacon.py b/salt/beacons/napalm_beacon.py index 122d56edb75..e1c97415bf8 100644 --- a/salt/beacons/napalm_beacon.py +++ b/salt/beacons/napalm_beacon.py @@ -298,7 +298,7 @@ def validate(config): " dictionary".format(fun), ) if fun not in __salt__: - return False, "Execution function {} is not availabe!".format(fun) + return False, f"Execution function {fun} is not availabe!" return True, "Valid configuration for the napal beacon!" diff --git a/salt/beacons/salt_monitor.py b/salt/beacons/salt_monitor.py index d389976ae2a..d8d580edbb3 100644 --- a/salt/beacons/salt_monitor.py +++ b/salt/beacons/salt_monitor.py @@ -45,7 +45,7 @@ def validate(config): # a simple str is taking as the single function with no args / kwargs fun = config["salt_fun"] if fun not in __salt__: - return False, "{} not in __salt__".format(fun) + return False, f"{fun} not in __salt__" else: for entry in config["salt_fun"]: if isinstance(entry, dict): @@ -56,7 +56,7 @@ def validate(config): if not isinstance(args_kwargs_dict[key], list): return ( False, - "args key for fun {} must be list".format(fun), + f"args key for fun {fun} must be list", ) elif key == "kwargs": if not isinstance(args_kwargs_dict[key], list): @@ -70,19 +70,19 @@ def validate(config): if not isinstance(key_value, dict): return ( False, - "{} is not a key / value pair".format(key_value), + f"{key_value} is not a key / value pair", ) else: return ( False, - "key {} not allowed under fun {}".format(key, fun), + f"key {key} not allowed under fun {fun}", ) else: # entry must be function itself fun = entry if fun not in __salt__: - return False, "{} not in __salt__".format(fun) + return False, f"{fun} not in __salt__" return True, "valid config" diff --git a/salt/beacons/salt_proxy.py b/salt/beacons/salt_proxy.py index 1eebc4103b9..2ec7c47d2a5 100644 --- a/salt/beacons/salt_proxy.py +++ b/salt/beacons/salt_proxy.py @@ -23,9 +23,9 @@ def _run_proxy_processes(proxies): result = {} if not __salt__["salt_proxy.is_running"](proxy)["result"]: __salt__["salt_proxy.configure_proxy"](proxy, start=True) - result[proxy] = "Proxy {} was started".format(proxy) + result[proxy] = f"Proxy {proxy} was started" else: - msg = "Proxy {} is already running".format(proxy) + msg = f"Proxy {proxy} is already running" result[proxy] = msg log.debug(msg) ret.append(result) diff --git a/salt/beacons/sensehat.py b/salt/beacons/sensehat.py index 6e3c29f4d36..a6b4c912a18 100644 --- a/salt/beacons/sensehat.py +++ b/salt/beacons/sensehat.py @@ -73,7 +73,7 @@ def beacon(config): config = salt.utils.beacons.list_to_dict(config) for sensor in config.get("sensors", {}): - sensor_function = "sensehat.get_{}".format(sensor) + sensor_function = f"sensehat.get_{sensor}" if sensor_function not in __salt__: log.error("No sensor for meassuring %s. Skipping.", sensor) continue @@ -95,6 +95,6 @@ def beacon(config): current_value = __salt__[sensor_function]() if not sensor_min <= current_value <= sensor_max: - ret.append({"tag": "sensehat/{}".format(sensor), sensor: current_value}) + ret.append({"tag": f"sensehat/{sensor}", sensor: current_value}) return ret diff --git a/salt/beacons/sh.py b/salt/beacons/sh.py index 8141b5a1a95..57ef43bca9c 100644 --- a/salt/beacons/sh.py +++ b/salt/beacons/sh.py @@ -73,7 +73,7 @@ def beacon(config): __context__[pkey] = {} for pid in track_pids: if pid not in __context__[pkey]: - cmd = ["strace", "-f", "-e", "execve", "-p", "{}".format(pid)] + cmd = ["strace", "-f", "-e", "execve", "-p", f"{pid}"] __context__[pkey][pid] = {} __context__[pkey][pid]["vt"] = salt.utils.vt.Terminal( cmd, diff --git a/salt/beacons/smartos_imgadm.py b/salt/beacons/smartos_imgadm.py index f1e3e83df3b..665168c0e3f 100644 --- a/salt/beacons/smartos_imgadm.py +++ b/salt/beacons/smartos_imgadm.py @@ -80,7 +80,7 @@ def beacon(config): for uuid in current_images: event = {} if uuid not in IMGADM_STATE["images"]: - event["tag"] = "imported/{}".format(uuid) + event["tag"] = f"imported/{uuid}" for label in current_images[uuid]: event[label] = current_images[uuid][label] @@ -91,7 +91,7 @@ def beacon(config): for uuid in IMGADM_STATE["images"]: event = {} if uuid not in current_images: - event["tag"] = "deleted/{}".format(uuid) + event["tag"] = f"deleted/{uuid}" for label in IMGADM_STATE["images"][uuid]: event[label] = IMGADM_STATE["images"][uuid][label] diff --git a/salt/beacons/smartos_vmadm.py b/salt/beacons/smartos_vmadm.py index 1dae2430b1b..7cdb8806a18 100644 --- a/salt/beacons/smartos_vmadm.py +++ b/salt/beacons/smartos_vmadm.py @@ -83,7 +83,7 @@ def beacon(config): for uuid in current_vms: event = {} if uuid not in VMADM_STATE["vms"]: - event["tag"] = "created/{}".format(uuid) + event["tag"] = f"created/{uuid}" for label in current_vms[uuid]: if label == "state": continue @@ -96,7 +96,7 @@ def beacon(config): for uuid in VMADM_STATE["vms"]: event = {} if uuid not in current_vms: - event["tag"] = "deleted/{}".format(uuid) + event["tag"] = f"deleted/{uuid}" for label in VMADM_STATE["vms"][uuid]: if label == "state": continue diff --git a/salt/beacons/status.py b/salt/beacons/status.py index 9492d339691..8c1210e7dbc 100644 --- a/salt/beacons/status.py +++ b/salt/beacons/status.py @@ -143,7 +143,7 @@ def beacon(config): for func in entry: ret[func] = {} try: - data = __salt__["status.{}".format(func)]() + data = __salt__[f"status.{func}"]() except salt.exceptions.CommandExecutionError as exc: log.debug( "Status beacon attempted to process function %s " @@ -166,8 +166,6 @@ def beacon(config): except TypeError: ret[func][item] = data[int(item)] except KeyError as exc: - ret[func] = ( - "Status beacon is incorrectly configured: {}".format(exc) - ) + ret[func] = f"Status beacon is incorrectly configured: {exc}" return [{"tag": ctime, "data": ret}] diff --git a/salt/beacons/wtmp.py b/salt/beacons/wtmp.py index c8ac6cfc379..a9f1b09281a 100644 --- a/salt/beacons/wtmp.py +++ b/salt/beacons/wtmp.py @@ -159,7 +159,7 @@ except ImportError: def __virtual__(): if os.path.isfile(WTMP): return __virtualname__ - err_msg = "{} does not exist.".format(WTMP) + err_msg = f"{WTMP} does not exist." log.error("Unable to load %s beacon: %s", __virtualname__, err_msg) return False, err_msg diff --git a/salt/cache/__init__.py b/salt/cache/__init__.py index 71fafc6d286..fb2ecdc62f1 100644 --- a/salt/cache/__init__.py +++ b/salt/cache/__init__.py @@ -69,7 +69,7 @@ class Cache: def __lazy_init(self): self._modules = salt.loader.cache(self.opts) - fun = "{}.init_kwargs".format(self.driver) + fun = f"{self.driver}.init_kwargs" if fun in self.modules: self._kwargs = self.modules[fun](self._kwargs) else: @@ -140,7 +140,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.store".format(self.driver) + fun = f"{self.driver}.store" return self.modules[fun](bank, key, data, **self._kwargs) def fetch(self, bank, key): @@ -164,7 +164,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.fetch".format(self.driver) + fun = f"{self.driver}.fetch" return self.modules[fun](bank, key, **self._kwargs) def updated(self, bank, key): @@ -188,7 +188,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.updated".format(self.driver) + fun = f"{self.driver}.updated" return self.modules[fun](bank, key, **self._kwargs) def flush(self, bank, key=None): @@ -209,7 +209,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.flush".format(self.driver) + fun = f"{self.driver}.flush" return self.modules[fun](bank, key=key, **self._kwargs) def list(self, bank): @@ -228,7 +228,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.list".format(self.driver) + fun = f"{self.driver}.list" return self.modules[fun](bank, **self._kwargs) def contains(self, bank, key=None): @@ -253,7 +253,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.contains".format(self.driver) + fun = f"{self.driver}.contains" return self.modules[fun](bank, key, **self._kwargs) @@ -288,7 +288,7 @@ class MemCache(Cache): break def _get_storage_id(self): - fun = "{}.storage_id".format(self.driver) + fun = f"{self.driver}.storage_id" if fun in self.modules: return self.modules[fun](self.kwargs) else: diff --git a/salt/cache/consul.py b/salt/cache/consul.py index 547e2fe4e2d..61af6cc5149 100644 --- a/salt/cache/consul.py +++ b/salt/cache/consul.py @@ -119,33 +119,29 @@ def store(bank, key, data): """ Store a key value. """ - c_key = "{}/{}".format(bank, key) - tstamp_key = "{}/{}{}".format(bank, key, _tstamp_suffix) + c_key = f"{bank}/{key}" + tstamp_key = f"{bank}/{key}{_tstamp_suffix}" try: c_data = salt.payload.dumps(data) api.kv.put(c_key, c_data) api.kv.put(tstamp_key, salt.payload.dumps(int(time.time()))) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error writing the key, {}: {}".format(c_key, exc) - ) + raise SaltCacheError(f"There was an error writing the key, {c_key}: {exc}") def fetch(bank, key): """ Fetch a key value. """ - c_key = "{}/{}".format(bank, key) + c_key = f"{bank}/{key}" try: _, value = api.kv.get(c_key) if value is None: return {} return salt.payload.loads(value["Value"]) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error reading the key, {}: {}".format(c_key, exc) - ) + raise SaltCacheError(f"There was an error reading the key, {c_key}: {exc}") def flush(bank, key=None): @@ -156,16 +152,14 @@ def flush(bank, key=None): c_key = bank tstamp_key = None else: - c_key = "{}/{}".format(bank, key) - tstamp_key = "{}/{}{}".format(bank, key, _tstamp_suffix) + c_key = f"{bank}/{key}" + tstamp_key = f"{bank}/{key}{_tstamp_suffix}" try: if tstamp_key: api.kv.delete(tstamp_key) return api.kv.delete(c_key, recurse=key is None) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error removing the key, {}: {}".format(c_key, exc) - ) + raise SaltCacheError(f"There was an error removing the key, {c_key}: {exc}") def list_(bank): @@ -175,9 +169,7 @@ def list_(bank): try: _, keys = api.kv.get(bank + "/", keys=True, separator="/") except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - 'There was an error getting the key "{}": {}'.format(bank, exc) - ) + raise SaltCacheError(f'There was an error getting the key "{bank}": {exc}') if keys is None: keys = [] else: @@ -198,9 +190,7 @@ def contains(bank, key): c_key = "{}/{}".format(bank, key or "") _, value = api.kv.get(c_key, keys=True) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error getting the key, {}: {}".format(c_key, exc) - ) + raise SaltCacheError(f"There was an error getting the key, {c_key}: {exc}") return value is not None @@ -209,13 +199,11 @@ def updated(bank, key): Return the Unix Epoch timestamp of when the key was last updated. Return None if key is not found. """ - c_key = "{}/{}{}".format(bank, key, _tstamp_suffix) + c_key = f"{bank}/{key}{_tstamp_suffix}" try: _, value = api.kv.get(c_key) if value is None: return None return salt.payload.loads(value["Value"]) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error reading the key, {}: {}".format(c_key, exc) - ) + raise SaltCacheError(f"There was an error reading the key, {c_key}: {exc}") diff --git a/salt/cache/etcd_cache.py b/salt/cache/etcd_cache.py index c1a111bd4f9..36c23f8131c 100644 --- a/salt/cache/etcd_cache.py +++ b/salt/cache/etcd_cache.py @@ -141,16 +141,14 @@ def store(bank, key, data): Store a key value. """ _init_client() - etcd_key = "{}/{}/{}".format(path_prefix, bank, key) - etcd_tstamp_key = "{}/{}/{}".format(path_prefix, bank, key + _tstamp_suffix) + etcd_key = f"{path_prefix}/{bank}/{key}" + etcd_tstamp_key = f"{path_prefix}/{bank}/{key + _tstamp_suffix}" try: value = salt.payload.dumps(data) client.write(etcd_key, base64.b64encode(value)) client.write(etcd_tstamp_key, int(time.time())) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error writing the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error writing the key, {etcd_key}: {exc}") def fetch(bank, key): @@ -158,16 +156,14 @@ def fetch(bank, key): Fetch a key value. """ _init_client() - etcd_key = "{}/{}/{}".format(path_prefix, bank, key) + etcd_key = f"{path_prefix}/{bank}/{key}" try: value = client.read(etcd_key).value return salt.payload.loads(base64.b64decode(value)) except etcd.EtcdKeyNotFound: return {} except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error reading the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error reading the key, {etcd_key}: {exc}") def flush(bank, key=None): @@ -176,11 +172,11 @@ def flush(bank, key=None): """ _init_client() if key is None: - etcd_key = "{}/{}".format(path_prefix, bank) + etcd_key = f"{path_prefix}/{bank}" tstamp_key = None else: - etcd_key = "{}/{}/{}".format(path_prefix, bank, key) - tstamp_key = "{}/{}/{}".format(path_prefix, bank, key + _tstamp_suffix) + etcd_key = f"{path_prefix}/{bank}/{key}" + tstamp_key = f"{path_prefix}/{bank}/{key + _tstamp_suffix}" try: client.read(etcd_key) except etcd.EtcdKeyNotFound: @@ -190,9 +186,7 @@ def flush(bank, key=None): client.delete(tstamp_key) client.delete(etcd_key, recursive=True) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error removing the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error removing the key, {etcd_key}: {exc}") def _walk(r): @@ -218,14 +212,14 @@ def ls(bank): bank. """ _init_client() - path = "{}/{}".format(path_prefix, bank) + path = f"{path_prefix}/{bank}" try: return _walk(client.read(path)) except etcd.EtcdKeyNotFound: return [] except Exception as exc: # pylint: disable=broad-except raise SaltCacheError( - 'There was an error getting the key "{}": {}'.format(bank, exc) + f'There was an error getting the key "{bank}": {exc}' ) from exc @@ -242,9 +236,7 @@ def contains(bank, key): except etcd.EtcdKeyNotFound: return False except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error getting the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error getting the key, {etcd_key}: {exc}") def updated(bank, key): @@ -252,13 +244,11 @@ def updated(bank, key): Return Unix Epoch based timestamp of when the bank/key was updated. """ _init_client() - tstamp_key = "{}/{}/{}".format(path_prefix, bank, key + _tstamp_suffix) + tstamp_key = f"{path_prefix}/{bank}/{key + _tstamp_suffix}" try: value = client.read(tstamp_key).value return int(value) except etcd.EtcdKeyNotFound: return None except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error reading the key, {}: {}".format(tstamp_key, exc) - ) + raise SaltCacheError(f"There was an error reading the key, {tstamp_key}: {exc}") diff --git a/salt/cache/localfs.py b/salt/cache/localfs.py index df2f3ac4727..4ac5ecec062 100644 --- a/salt/cache/localfs.py +++ b/salt/cache/localfs.py @@ -51,10 +51,10 @@ def store(bank, key, data, cachedir): except OSError as exc: if exc.errno != errno.EEXIST: raise SaltCacheError( - "The cache directory, {}, could not be created: {}".format(base, exc) + f"The cache directory, {base}, could not be created: {exc}" ) - outfile = os.path.join(base, "{}.p".format(key)) + outfile = os.path.join(base, f"{key}.p") tmpfh, tmpfname = tempfile.mkstemp(dir=base) os.close(tmpfh) try: @@ -64,7 +64,7 @@ def store(bank, key, data, cachedir): salt.utils.atomicfile.atomic_rename(tmpfname, outfile) except OSError as exc: raise SaltCacheError( - "There was an error writing the cache file, {}: {}".format(base, exc) + f"There was an error writing the cache file, {base}: {exc}" ) @@ -73,7 +73,7 @@ def fetch(bank, key, cachedir): Fetch information from a file. """ inkey = False - key_file = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + key_file = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") if not os.path.isfile(key_file): # The bank includes the full filename, and the key is inside the file key_file = os.path.join(cachedir, os.path.normpath(bank) + ".p") @@ -90,7 +90,7 @@ def fetch(bank, key, cachedir): return salt.payload.load(fh_) except OSError as exc: raise SaltCacheError( - 'There was an error reading the cache file "{}": {}'.format(key_file, exc) + f'There was an error reading the cache file "{key_file}": {exc}' ) @@ -98,7 +98,7 @@ def updated(bank, key, cachedir): """ Return the epoch of the mtime for this cache file """ - key_file = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + key_file = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") if not os.path.isfile(key_file): log.warning('Cache file "%s" does not exist', key_file) return None @@ -106,7 +106,7 @@ def updated(bank, key, cachedir): return int(os.path.getmtime(key_file)) except OSError as exc: raise SaltCacheError( - 'There was an error reading the mtime for "{}": {}'.format(key_file, exc) + f'There was an error reading the mtime for "{key_file}": {exc}' ) @@ -124,12 +124,12 @@ def flush(bank, key=None, cachedir=None): return False shutil.rmtree(target) else: - target = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + target = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") if not os.path.isfile(target): return False os.remove(target) except OSError as exc: - raise SaltCacheError('There was an error removing "{}": {}'.format(target, exc)) + raise SaltCacheError(f'There was an error removing "{target}": {exc}') return True @@ -143,9 +143,7 @@ def list_(bank, cachedir): try: items = os.listdir(base) except OSError as exc: - raise SaltCacheError( - 'There was an error accessing directory "{}": {}'.format(base, exc) - ) + raise SaltCacheError(f'There was an error accessing directory "{base}": {exc}') ret = [] for item in items: if item.endswith(".p"): @@ -163,5 +161,5 @@ def contains(bank, key, cachedir): base = os.path.join(cachedir, os.path.normpath(bank)) return os.path.isdir(base) else: - keyfile = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + keyfile = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") return os.path.isfile(keyfile) diff --git a/salt/cache/mysql_cache.py b/salt/cache/mysql_cache.py index 8342ec77f16..229d8f3ae9f 100644 --- a/salt/cache/mysql_cache.py +++ b/salt/cache/mysql_cache.py @@ -144,9 +144,7 @@ def run_query(conn, query, args=None, retries=3): if len(query) > 150: query = query[:150] + "<...>" raise SaltCacheError( - "Error running {}{}: {}".format( - query, "- args: {}".format(args) if args else "", e - ) + "Error running {}{}: {}".format(query, f"- args: {args}" if args else "", e) ) @@ -266,7 +264,7 @@ def store(bank, key, data): cur, cnt = run_query(__context__.get("mysql_client"), query, args=args) cur.close() if cnt not in (1, 2): - raise SaltCacheError("Error storing {} {} returned {}".format(bank, key, cnt)) + raise SaltCacheError(f"Error storing {bank} {key} returned {cnt}") def fetch(bank, key): diff --git a/salt/cache/redis_cache.py b/salt/cache/redis_cache.py index 754bba71f0a..5584d118ba7 100644 --- a/salt/cache/redis_cache.py +++ b/salt/cache/redis_cache.py @@ -351,7 +351,7 @@ def _get_banks_to_remove(redis_server, bank, path=""): A simple tree traversal algorithm that builds the list of banks to remove, starting from an arbitrary node in the tree. """ - current_path = bank if not path else "{path}/{bank}".format(path=path, bank=bank) + current_path = bank if not path else f"{path}/{bank}" bank_paths_to_remove = [current_path] # as you got here, you'll be removed diff --git a/salt/channel/client.py b/salt/channel/client.py index 0360af34658..310804c84cf 100644 --- a/salt/channel/client.py +++ b/salt/channel/client.py @@ -143,7 +143,7 @@ class AsyncReqChannel: auth, timeout=REQUEST_CHANNEL_TIMEOUT, tries=REQUEST_CHANNEL_TRIES, - **kwargs + **kwargs, ): self.opts = dict(opts) self.transport = transport @@ -446,7 +446,7 @@ class AsyncPubChannel: except Exception as exc: # pylint: disable=broad-except if "-|RETRY|-" not in str(exc): raise salt.exceptions.SaltClientError( - "Unable to sign_in to master: {}".format(exc) + f"Unable to sign_in to master: {exc}" ) # TODO: better error message def close(self): diff --git a/salt/channel/server.py b/salt/channel/server.py index 47b8f96c0d8..14d3da30125 100644 --- a/salt/channel/server.py +++ b/salt/channel/server.py @@ -144,9 +144,7 @@ class ReqServerChannel: raise salt.ext.tornado.gen.Return("bad load: id contains a null byte") except TypeError: log.error("Payload contains non-string id: %s", payload) - raise salt.ext.tornado.gen.Return( - "bad load: id {} is not a string".format(id_) - ) + raise salt.ext.tornado.gen.Return(f"bad load: id {id_} is not a string") version = 0 if "version" in payload: diff --git a/salt/cli/batch.py b/salt/cli/batch.py index ca1f464a8d4..2e43b0ee22b 100644 --- a/salt/cli/batch.py +++ b/salt/cli/batch.py @@ -191,7 +191,7 @@ class Batch: if next_: if not self.quiet: salt.utils.stringutils.print_cli( - "\nExecuting run on {}\n".format(sorted(next_)) + f"\nExecuting run on {sorted(next_)}\n" ) # create a new iterator for this batch of minions return_value = self.opts.get("return", self.opts.get("ret", "")) diff --git a/salt/cli/caller.py b/salt/cli/caller.py index ce2b8edfd4e..ffc39356ba9 100644 --- a/salt/cli/caller.py +++ b/salt/cli/caller.py @@ -75,7 +75,7 @@ class BaseCaller: docs[name] = func.__doc__ for name in sorted(docs): if name.startswith(self.opts.get("fun", "")): - salt.utils.stringutils.print_cli("{}:\n{}\n".format(name, docs[name])) + salt.utils.stringutils.print_cli(f"{name}:\n{docs[name]}\n") def print_grains(self): """ @@ -130,7 +130,7 @@ class BaseCaller: salt.minion.get_proc_dir(self.opts["cachedir"]), ret["jid"] ) if fun not in self.minion.functions: - docs = self.minion.functions["sys.doc"]("{}*".format(fun)) + docs = self.minion.functions["sys.doc"](f"{fun}*") if docs: docs[fun] = self.minion.functions.missing_fun_string(fun) ret["out"] = "nested" @@ -194,20 +194,16 @@ class BaseCaller: executors = [executors] try: for name in executors: - fname = "{}.execute".format(name) + fname = f"{name}.execute" if fname not in self.minion.executors: - raise SaltInvocationError( - "Executor '{}' is not available".format(name) - ) + raise SaltInvocationError(f"Executor '{name}' is not available") ret["return"] = self.minion.executors[fname]( self.opts, data, func, args, kwargs ) if ret["return"] is not None: break except TypeError as exc: - sys.stderr.write( - "\nPassed invalid arguments: {}.\n\nUsage:\n".format(exc) - ) + sys.stderr.write(f"\nPassed invalid arguments: {exc}.\n\nUsage:\n") salt.utils.stringutils.print_cli(func.__doc__) active_level = LOG_LEVELS.get( self.opts["log_level"].lower(), logging.ERROR @@ -272,7 +268,7 @@ class BaseCaller: continue try: ret["success"] = True - self.minion.returners["{}.returner".format(returner)](ret) + self.minion.returners[f"{returner}.returner"](ret) except Exception: # pylint: disable=broad-except pass diff --git a/salt/cli/salt.py b/salt/cli/salt.py index f90057f668e..9c28e5de3d6 100644 --- a/salt/cli/salt.py +++ b/salt/cli/salt.py @@ -44,7 +44,7 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser): auto_reconnect=True, ) except SaltClientError as exc: - self.exit(2, "{}\n".format(exc)) + self.exit(2, f"{exc}\n") return if self.options.batch or self.options.static: @@ -146,9 +146,7 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser): if self.config["async"]: jid = self.local_client.cmd_async(**kwargs) - salt.utils.stringutils.print_cli( - "Executed command with job ID: {}".format(jid) - ) + salt.utils.stringutils.print_cli(f"Executed command with job ID: {jid}") return # local will be None when there was an error @@ -337,16 +335,14 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser): salt.utils.stringutils.print_cli("Summary") salt.utils.stringutils.print_cli("-------------------------------------------") salt.utils.stringutils.print_cli( - "# of minions targeted: {}".format(return_counter + not_return_counter) + f"# of minions targeted: {return_counter + not_return_counter}" + ) + salt.utils.stringutils.print_cli(f"# of minions returned: {return_counter}") + salt.utils.stringutils.print_cli( + f"# of minions that did not return: {not_return_counter}" ) salt.utils.stringutils.print_cli( - "# of minions returned: {}".format(return_counter) - ) - salt.utils.stringutils.print_cli( - "# of minions that did not return: {}".format(not_return_counter) - ) - salt.utils.stringutils.print_cli( - "# of minions with errors: {}".format(len(failed_minions)) + f"# of minions with errors: {len(failed_minions)}" ) if self.options.verbose: if not_connected_minions: @@ -449,7 +445,7 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser): if not ret: self.exit(2, "No minions found to gather docs from\n") if isinstance(ret, str): - self.exit(2, "{}\n".format(ret)) + self.exit(2, f"{ret}\n") for host in ret: if isinstance(ret[host], str) and ( ret[host].startswith("Minion did not return") @@ -464,6 +460,6 @@ class SaltCMD(salt.utils.parsers.SaltCMDOptionParser): salt.output.display_output({fun: docs[fun]}, "nested", self.config) else: for fun in sorted(docs): - salt.utils.stringutils.print_cli("{}:".format(fun)) + salt.utils.stringutils.print_cli(f"{fun}:") salt.utils.stringutils.print_cli(docs[fun]) salt.utils.stringutils.print_cli("") diff --git a/salt/client/__init__.py b/salt/client/__init__.py index cfda90d5782..6bd6bf5bf59 100644 --- a/salt/client/__init__.py +++ b/salt/client/__init__.py @@ -245,7 +245,7 @@ class LocalClient: # The username may contain '\' if it is in Windows # 'DOMAIN\username' format. Fix this for the keyfile path. key_user = key_user.replace("\\", "_") - keyfile = os.path.join(self.opts["cachedir"], ".{}_key".format(key_user)) + keyfile = os.path.join(self.opts["cachedir"], f".{key_user}_key") try: # Make sure all key parent directories are accessible salt.utils.verify.check_path_traversal( @@ -265,7 +265,7 @@ class LocalClient: try: return range_.expand(tgt) except seco.range.RangeException as err: - print("Range server exception: {}".format(err)) + print(f"Range server exception: {err}") return [] def _get_timeout(self, timeout): @@ -1053,11 +1053,11 @@ class LocalClient: :returns: all of the information for the JID """ if verbose: - msg = "Executing job with jid {}".format(jid) + msg = f"Executing job with jid {jid}" print(msg) print("-" * len(msg) + "\n") elif show_jid: - print("jid: {}".format(jid)) + print(f"jid: {jid}") if timeout is None: timeout = self.opts["timeout"] fret = {} @@ -1163,11 +1163,9 @@ class LocalClient: # iterator for this job's return if self.opts["order_masters"]: # If we are a MoM, we need to gather expected minions from downstreams masters. - ret_iter = self.get_returns_no_block( - "(salt/job|syndic/.*)/{}".format(jid), "regex" - ) + ret_iter = self.get_returns_no_block(f"(salt/job|syndic/.*)/{jid}", "regex") else: - ret_iter = self.get_returns_no_block("salt/job/{}".format(jid)) + ret_iter = self.get_returns_no_block(f"salt/job/{jid}") # iterator for the info of this job jinfo_iter = [] # open event jids that need to be un-subscribed from later @@ -1547,11 +1545,11 @@ class LocalClient: log.trace("entered - function get_cli_static_event_returns()") minions = set(minions) if verbose: - msg = "Executing job with jid {}".format(jid) + msg = f"Executing job with jid {jid}" print(msg) print("-" * len(msg) + "\n") elif show_jid: - print("jid: {}".format(jid)) + print(f"jid: {jid}") if timeout is None: timeout = self.opts["timeout"] @@ -1581,7 +1579,7 @@ class LocalClient: time_left = timeout_at - int(time.time()) # Wait 0 == forever, use a minimum of 1s wait = max(1, time_left) - jid_tag = "salt/job/{}".format(jid) + jid_tag = f"salt/job/{jid}" raw = self.event.get_event( wait, jid_tag, auto_reconnect=self.auto_reconnect ) @@ -1641,11 +1639,11 @@ class LocalClient: log.trace("func get_cli_event_returns()") if verbose: - msg = "Executing job with jid {}".format(jid) + msg = f"Executing job with jid {jid}" print(msg) print("-" * len(msg) + "\n") elif show_jid: - print("jid: {}".format(jid)) + print(f"jid: {jid}") # lazy load the connected minions connected_minions = None @@ -1684,7 +1682,7 @@ class LocalClient: if ( self.opts["minion_data_cache"] and salt.cache.factory(self.opts).contains( - "minions/{}".format(id_), "data" + f"minions/{id_}", "data" ) and connected_minions and id_ not in connected_minions @@ -1775,9 +1773,7 @@ class LocalClient: """ if ng not in self.opts["nodegroups"]: conf_file = self.opts.get("conf_file", "the master config file") - raise SaltInvocationError( - "Node group {} unavailable in {}".format(ng, conf_file) - ) + raise SaltInvocationError(f"Node group {ng} unavailable in {conf_file}") return salt.utils.minions.nodegroup_comp(ng, self.opts["nodegroups"]) def _prep_pub(self, tgt, fun, arg, tgt_type, ret, jid, timeout, **kwargs): @@ -2062,8 +2058,8 @@ class LocalClient: def _clean_up_subscriptions(self, job_id): if self.opts.get("order_masters"): - self.event.unsubscribe("syndic/.*/{}".format(job_id), "regex") - self.event.unsubscribe("salt/job/{}".format(job_id)) + self.event.unsubscribe(f"syndic/.*/{job_id}", "regex") + self.event.unsubscribe(f"salt/job/{job_id}") def destroy(self): if self.event is not None: @@ -2122,7 +2118,7 @@ class FunctionWrapper(dict): """ args = list(args) for _key, _val in kwargs.items(): - args.append("{}={}".format(_key, _val)) + args.append(f"{_key}={_val}") return self.local.cmd(self.minion, key, args) return func @@ -2272,9 +2268,9 @@ class ProxyCaller: if isinstance(executors, str): executors = [executors] for name in executors: - fname = "{}.execute".format(name) + fname = f"{name}.execute" if fname not in self.sminion.executors: - raise SaltInvocationError("Executor '{}' is not available".format(name)) + raise SaltInvocationError(f"Executor '{name}' is not available") return_data = self.sminion.executors[fname]( self.opts, data, func, args, kwargs ) diff --git a/salt/client/mixins.py b/salt/client/mixins.py index 6e05e86d342..1e40e85c712 100644 --- a/salt/client/mixins.py +++ b/salt/client/mixins.py @@ -273,7 +273,7 @@ class SyncClientMixin(ClientStateMixin): return True try: - return self.opts["{}_returns".format(class_name)] + return self.opts[f"{class_name}_returns"] except KeyError: # No such option, assume this isn't one we care about gating and # just return True. @@ -300,7 +300,7 @@ class SyncClientMixin(ClientStateMixin): tag = low.get("__tag__", salt.utils.event.tagify(jid, prefix=self.tag_prefix)) data = { - "fun": "{}.{}".format(self.client, fun), + "fun": f"{self.client}.{fun}", "jid": jid, "user": low.get("__user__", "UNKNOWN"), } @@ -523,7 +523,7 @@ class AsyncClientMixin(ClientStateMixin): tag, jid, daemonize=True, - full_return=False + full_return=False, ): """ Run this method in a multiprocess target to execute the function diff --git a/salt/client/netapi.py b/salt/client/netapi.py index 6d0dc73b854..27029af85a3 100644 --- a/salt/client/netapi.py +++ b/salt/client/netapi.py @@ -48,7 +48,7 @@ class NetapiClient: for fun in self.netapi: if fun.endswith(".start"): - name = "RunNetapi({})".format(self.netapi[fun].__module__) + name = f"RunNetapi({self.netapi[fun].__module__})" log.info("Starting %s", name) self.process_manager.add_process( RunNetapi, args=(self.opts, fun), name=name diff --git a/salt/client/ssh/shell.py b/salt/client/ssh/shell.py index 2df328ed1f5..5d93cdeb801 100644 --- a/salt/client/ssh/shell.py +++ b/salt/client/ssh/shell.py @@ -129,26 +129,26 @@ class Shell: options.append("PasswordAuthentication=no") if self.opts.get("_ssh_version", (0,)) > (4, 9): options.append("GSSAPIAuthentication=no") - options.append("ConnectTimeout={}".format(self.timeout)) + options.append(f"ConnectTimeout={self.timeout}") if self.opts.get("ignore_host_keys"): options.append("StrictHostKeyChecking=no") if self.opts.get("no_host_keys"): options.extend(["StrictHostKeyChecking=no", "UserKnownHostsFile=/dev/null"]) known_hosts = self.opts.get("known_hosts_file") if known_hosts and os.path.isfile(known_hosts): - options.append("UserKnownHostsFile={}".format(known_hosts)) + options.append(f"UserKnownHostsFile={known_hosts}") if self.port: - options.append("Port={}".format(self.port)) + options.append(f"Port={self.port}") if self.priv and self.priv != "agent-forwarding": - options.append("IdentityFile={}".format(self.priv)) + options.append(f"IdentityFile={self.priv}") if self.user: - options.append("User={}".format(self.user)) + options.append(f"User={self.user}") if self.identities_only: options.append("IdentitiesOnly=yes") ret = [] for option in options: - ret.append("-o {} ".format(option)) + ret.append(f"-o {option} ") return "".join(ret) def _passwd_opts(self): @@ -164,7 +164,7 @@ class Shell: ] if self.opts["_ssh_version"] > (4, 9): options.append("GSSAPIAuthentication=no") - options.append("ConnectTimeout={}".format(self.timeout)) + options.append(f"ConnectTimeout={self.timeout}") if self.opts.get("ignore_host_keys"): options.append("StrictHostKeyChecking=no") if self.opts.get("no_host_keys"): @@ -183,19 +183,19 @@ class Shell: ] ) if self.port: - options.append("Port={}".format(self.port)) + options.append(f"Port={self.port}") if self.user: - options.append("User={}".format(self.user)) + options.append(f"User={self.user}") if self.identities_only: options.append("IdentitiesOnly=yes") ret = [] for option in options: - ret.append("-o {} ".format(option)) + ret.append(f"-o {option} ") return "".join(ret) def _ssh_opts(self): - return " ".join(["-o {}".format(opt) for opt in self.ssh_options]) + return " ".join([f"-o {opt}" for opt in self.ssh_options]) def _copy_id_str_old(self): """ @@ -206,7 +206,7 @@ class Shell: # passwords containing '$' return "{} {} '{} -p {} {} {}@{}'".format( "ssh-copy-id", - "-i {}.pub".format(self.priv), + f"-i {self.priv}.pub", self._passwd_opts(), self.port, self._ssh_opts(), @@ -225,7 +225,7 @@ class Shell: # passwords containing '$' return "{} {} {} -p {} {} {}@{}".format( "ssh-copy-id", - "-i {}.pub".format(self.priv), + f"-i {self.priv}.pub", self._passwd_opts(), self.port, self._ssh_opts(), @@ -261,10 +261,7 @@ class Shell: if ssh != "scp" and self.remote_port_forwards: command.append( " ".join( - [ - "-R {}".format(item) - for item in self.remote_port_forwards.split(",") - ] + [f"-R {item}" for item in self.remote_port_forwards.split(",")] ) ) if self.ssh_options: @@ -306,7 +303,7 @@ class Shell: rcode = None cmd = self._cmd_str(cmd) - logmsg = "Executing non-blocking command: {}".format(cmd) + logmsg = f"Executing non-blocking command: {cmd}" if self.passwd: logmsg = logmsg.replace(self.passwd, ("*" * 6)) log.debug(logmsg) @@ -325,7 +322,7 @@ class Shell: """ cmd = self._cmd_str(cmd) - logmsg = "Executing command: {}".format(cmd) + logmsg = f"Executing command: {cmd}" if self.passwd: logmsg = logmsg.replace(self.passwd, ("*" * 6)) if 'decode("base64")' in logmsg or "base64.b64decode(" in logmsg: @@ -342,17 +339,17 @@ class Shell: scp a file or files to a remote system """ if makedirs: - self.exec_cmd("mkdir -p {}".format(os.path.dirname(remote))) + self.exec_cmd(f"mkdir -p {os.path.dirname(remote)}") # scp needs [ 1: for driver in drivers: - providers.add("{}:{}".format(alias, driver)) + providers.add(f"{alias}:{driver}") continue providers.add(alias) return providers @@ -609,7 +609,7 @@ class Cloud: pmap = {} for alias, drivers in self.opts["providers"].items(): for driver, details in drivers.items(): - fun = "{}.{}".format(driver, query) + fun = f"{driver}.{query}" if fun not in self.clouds: log.error("Public cloud provider %s is not available", driver) continue @@ -659,11 +659,11 @@ class Cloud: # for minimum information, Otherwise still use query param. if ( opts.get("selected_query_option") is None - and "{}.list_nodes_min".format(driver) in self.clouds + and f"{driver}.list_nodes_min" in self.clouds ): this_query = "list_nodes_min" - fun = "{}.{}".format(driver, this_query) + fun = f"{driver}.{this_query}" if fun not in self.clouds: log.error("Public cloud provider %s is not available", driver) continue @@ -771,7 +771,7 @@ class Cloud: provider_by_driver[name][alias] = data for driver, providers_data in provider_by_driver.items(): - fun = "{}.optimize_providers".format(driver) + fun = f"{driver}.optimize_providers" if fun not in self.clouds: log.debug("The '%s' cloud driver is unable to be optimized.", driver) @@ -801,7 +801,7 @@ class Cloud: return data for alias, driver in lookups: - fun = "{}.avail_locations".format(driver) + fun = f"{driver}.avail_locations" if fun not in self.clouds: # The capability to gather locations is not supported by this # cloud module @@ -842,7 +842,7 @@ class Cloud: return data for alias, driver in lookups: - fun = "{}.avail_images".format(driver) + fun = f"{driver}.avail_images" if fun not in self.clouds: # The capability to gather images is not supported by this # cloud module @@ -882,7 +882,7 @@ class Cloud: return data for alias, driver in lookups: - fun = "{}.avail_sizes".format(driver) + fun = f"{driver}.avail_sizes" if fun not in self.clouds: # The capability to gather sizes is not supported by this # cloud module @@ -1017,7 +1017,7 @@ class Cloud: else: log.info("Destroying in non-parallel mode.") for alias, driver, name in vms_to_destroy: - fun = "{}.destroy".format(driver) + fun = f"{driver}.destroy" with salt.utils.context.func_globals_inject( self.clouds[fun], __active_provider_name__=":".join([alias, driver]) ): @@ -1050,7 +1050,7 @@ class Cloud: key_file = os.path.join( self.opts["pki_dir"], "minions", minion_dict.get("id", name) ) - globbed_key_file = glob.glob("{}.*".format(key_file)) + globbed_key_file = glob.glob(f"{key_file}.*") if not os.path.isfile(key_file) and not globbed_key_file: # There's no such key file!? It might have been renamed @@ -1090,25 +1090,25 @@ class Cloud: ) while True: for idx, filename in enumerate(globbed_key_file): - print(" {}: {}".format(idx, os.path.basename(filename))) + print(f" {idx}: {os.path.basename(filename)}") selection = input("Which minion key should be deleted(number)? ") try: selection = int(selection) except ValueError: - print("'{}' is not a valid selection.".format(selection)) + print(f"'{selection}' is not a valid selection.") try: filename = os.path.basename(globbed_key_file.pop(selection)) except Exception: # pylint: disable=broad-except continue - delete = input("Delete '{}'? [Y/n]? ".format(filename)) + delete = input(f"Delete '{filename}'? [Y/n]? ") if delete == "" or delete.lower().startswith("y"): salt.utils.cloud.remove_key(self.opts["pki_dir"], filename) - print("Deleted '{}'".format(filename)) + print(f"Deleted '{filename}'") break - print("Did not delete '{}'".format(filename)) + print(f"Did not delete '{filename}'") break if names and not processed: @@ -1138,7 +1138,7 @@ class Cloud: if node in names: acts[prov].append(node) for prov, names_ in acts.items(): - fun = "{}.reboot".format(prov) + fun = f"{prov}.reboot" for name in names_: ret.append({name: self.clouds[fun](name)}) @@ -1155,7 +1155,7 @@ class Cloud: ) alias, driver = vm_["provider"].split(":") - fun = "{}.create".format(driver) + fun = f"{driver}.create" if fun not in self.clouds: log.error( "Creating '%s' using '%s' as the provider " @@ -1220,7 +1220,7 @@ class Cloud: try: alias, driver = vm_["provider"].split(":") - func = "{}.create".format(driver) + func = f"{driver}.create" with salt.utils.context.func_globals_inject( self.clouds[fun], __active_provider_name__=":".join([alias, driver]) ): @@ -1357,7 +1357,7 @@ class Cloud: handle them """ if profile not in self.opts["profiles"]: - msg = "Profile {} is not defined".format(profile) + msg = f"Profile {profile} is not defined" log.error(msg) return {"Error": msg} @@ -1396,7 +1396,7 @@ class Cloud: if name in vms: prov = vms[name]["provider"] driv = vms[name]["driver"] - msg = "{} already exists under {}:{}".format(name, prov, driv) + msg = f"{name} already exists under {prov}:{driv}" log.error(msg) ret[name] = {"Error": msg} continue @@ -1542,14 +1542,12 @@ class Cloud: raise SaltCloudSystemExit( "More than one results matched '{}'. Please specify one of: {}".format( prov, - ", ".join( - ["{}:{}".format(alias, driver) for (alias, driver) in matches] - ), + ", ".join([f"{alias}:{driver}" for (alias, driver) in matches]), ) ) alias, driver = matches.pop() - fun = "{}.{}".format(driver, func) + fun = f"{driver}.{func}" if fun not in self.clouds: raise SaltCloudSystemExit( "The '{}' cloud provider alias, for the '{}' driver, does " @@ -1573,7 +1571,7 @@ class Cloud: """ for alias, drivers in self.opts["providers"].copy().items(): for driver in drivers.copy(): - fun = "{}.get_configured_provider".format(driver) + fun = f"{driver}.get_configured_provider" if fun not in self.clouds: # Mis-configured provider that got removed? log.warning( @@ -1898,7 +1896,7 @@ class Map(Cloud): "The required profile, '{}', defined in the map " "does not exist. The defined nodes, {}, will not " "be created.".format( - profile_name, ", ".join("'{}'".format(node) for node in nodes) + profile_name, ", ".join(f"'{node}'" for node in nodes) ) ) log.error(msg) @@ -1931,7 +1929,7 @@ class Map(Cloud): # Update profile data with the map overrides for setting in ("grains", "master", "minion", "volumes", "requires"): - deprecated = "map_{}".format(setting) + deprecated = f"map_{setting}" if deprecated in overrides: log.warning( "The use of '%s' on the '%s' mapping has " diff --git a/salt/cloud/clouds/aliyun.py b/salt/cloud/clouds/aliyun.py index 30a3cf593a8..f7109ec8754 100644 --- a/salt/cloud/clouds/aliyun.py +++ b/salt/cloud/clouds/aliyun.py @@ -412,9 +412,7 @@ def get_image(vm_): if vm_image and str(vm_image) in images: return images[vm_image]["ImageId"] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_securitygroup(vm_): @@ -432,7 +430,7 @@ def get_securitygroup(vm_): if securitygroup and str(securitygroup) in sgs: return sgs[securitygroup]["SecurityGroupId"] raise SaltCloudNotFound( - "The specified security group, '{}', could not be found.".format(securitygroup) + f"The specified security group, '{securitygroup}', could not be found." ) @@ -451,9 +449,7 @@ def get_size(vm_): if vm_size and str(vm_size) in sizes: return sizes[vm_size]["InstanceTypeId"] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def __get_location(vm_): @@ -471,7 +467,7 @@ def __get_location(vm_): if vm_location and str(vm_location) in locations: return locations[vm_location]["RegionId"] raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -920,7 +916,7 @@ def _get_node(name): ) # Just a little delay between attempts... time.sleep(0.5) - raise SaltCloudNotFound("The specified instance {} not found".format(name)) + raise SaltCloudNotFound(f"The specified instance {name} not found") def show_image(kwargs, call=None): @@ -982,7 +978,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1001,7 +997,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/azurearm.py b/salt/cloud/clouds/azurearm.py index de93ac18a73..1f2895ca4fa 100644 --- a/salt/cloud/clouds/azurearm.py +++ b/salt/cloud/clouds/azurearm.py @@ -836,7 +836,7 @@ def create_network_interface(call=None, kwargs=None): NetworkInterfaceIPConfiguration( name="{}-ip".format(kwargs["iface_name"]), subnet=subnet_obj, - **ip_kwargs + **ip_kwargs, ) ] break @@ -999,7 +999,7 @@ def request_instance(vm_, kwargs=None): if not win_installer and ssh_publickeyfile_contents is not None: sshpublickey = SshPublicKey( key_data=ssh_publickeyfile_contents, - path="/home/{}/.ssh/authorized_keys".format(vm_username), + path=f"/home/{vm_username}/.ssh/authorized_keys", ) sshconfiguration = SshConfiguration( public_keys=[sshpublickey], @@ -1620,7 +1620,7 @@ def _get_cloud_environment(): cloud_env = getattr(cloud_env_module, cloud_environment or "AZURE_PUBLIC_CLOUD") except (AttributeError, ImportError): raise SaltCloudSystemExit( - "The azure {} cloud environment is not available.".format(cloud_environment) + f"The azure {cloud_environment} cloud environment is not available." ) return cloud_env @@ -1911,7 +1911,7 @@ def create_or_update_vmextension( except CloudError as exc: salt.utils.azurearm.log_cloud_error( "compute", - "Error attempting to create the VM extension: {}".format(exc.message), + f"Error attempting to create the VM extension: {exc.message}", ) ret = {"error": exc.message} @@ -1959,9 +1959,9 @@ def stop(name, call=None): ret = {"error": exc.message} if not ret: salt.utils.azurearm.log_cloud_error( - "compute", "Unable to find virtual machine with name: {}".format(name) + "compute", f"Unable to find virtual machine with name: {name}" ) - ret = {"error": "Unable to find virtual machine with name: {}".format(name)} + ret = {"error": f"Unable to find virtual machine with name: {name}"} else: try: instance = compconn.virtual_machines.deallocate( @@ -1972,7 +1972,7 @@ def stop(name, call=None): ret = vm_result.as_dict() except CloudError as exc: salt.utils.azurearm.log_cloud_error( - "compute", "Error attempting to stop {}: {}".format(name, exc.message) + "compute", f"Error attempting to stop {name}: {exc.message}" ) ret = {"error": exc.message} @@ -2022,9 +2022,9 @@ def start(name, call=None): ret = {"error": exc.message} if not ret: salt.utils.azurearm.log_cloud_error( - "compute", "Unable to find virtual machine with name: {}".format(name) + "compute", f"Unable to find virtual machine with name: {name}" ) - ret = {"error": "Unable to find virtual machine with name: {}".format(name)} + ret = {"error": f"Unable to find virtual machine with name: {name}"} else: try: instance = compconn.virtual_machines.start( @@ -2036,7 +2036,7 @@ def start(name, call=None): except CloudError as exc: salt.utils.azurearm.log_cloud_error( "compute", - "Error attempting to start {}: {}".format(name, exc.message), + f"Error attempting to start {name}: {exc.message}", ) ret = {"error": exc.message} diff --git a/salt/cloud/clouds/clc.py b/salt/cloud/clouds/clc.py index 88ed72b1295..b7d8cbd3a4a 100644 --- a/salt/cloud/clouds/clc.py +++ b/salt/cloud/clouds/clc.py @@ -421,7 +421,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "waiting for ssh", - "salt/cloud/{}/waiting_for_ssh".format(name), + f"salt/cloud/{name}/waiting_for_ssh", sock_dir=__opts__["sock_dir"], args={"ip_address": vm_["ssh_host"]}, transport=__opts__["transport"], diff --git a/salt/cloud/clouds/cloudstack.py b/salt/cloud/clouds/cloudstack.py index ebf301e4ebf..ff526aa82e0 100644 --- a/salt/cloud/clouds/cloudstack.py +++ b/salt/cloud/clouds/cloudstack.py @@ -474,7 +474,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", sock_dir=__opts__["sock_dir"], args={"name": name}, ) @@ -499,7 +499,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "detaching volume", - "salt/cloud/{}/detaching".format(volume.name), + f"salt/cloud/{volume.name}/detaching", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -510,7 +510,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "detached volume", - "salt/cloud/{}/detached".format(volume.name), + f"salt/cloud/{volume.name}/detached", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -519,7 +519,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying volume", - "salt/cloud/{}/destroying".format(volume.name), + f"salt/cloud/{volume.name}/destroying", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -530,7 +530,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed volume", - "salt/cloud/{}/destroyed".format(volume.name), + f"salt/cloud/{volume.name}/destroyed", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -545,7 +545,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", sock_dir=__opts__["sock_dir"], args={"name": name}, ) diff --git a/salt/cloud/clouds/digitalocean.py b/salt/cloud/clouds/digitalocean.py index 7f843f22ab1..6929195c9dd 100644 --- a/salt/cloud/clouds/digitalocean.py +++ b/salt/cloud/clouds/digitalocean.py @@ -223,9 +223,7 @@ def get_image(vm_): if images[image]["slug"] is not None: return images[image]["slug"] return int(images[image]["id"]) - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_size(vm_): @@ -239,9 +237,7 @@ def get_size(vm_): for size in sizes: if vm_size.lower() == sizes[size]["slug"]: return sizes[size]["slug"] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def get_location(vm_): @@ -257,7 +253,7 @@ def get_location(vm_): if vm_location in (locations[location]["name"], locations[location]["slug"]): return locations[location]["slug"] raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -333,7 +329,7 @@ def create(vm_): if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) if not __opts__.get("ssh_agent", False) and key_filename is None: @@ -616,10 +612,10 @@ def query( ) ) - path = "{}/{}/".format(base_path, method) + path = f"{base_path}/{method}/" if droplet_id: - path += "{}/".format(droplet_id) + path += f"{droplet_id}/" if command: path += command @@ -875,7 +871,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -912,7 +908,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -987,7 +983,7 @@ def destroy_dns_records(fqdn): ret = query( method="domains", droplet_id=domain, - command="records/{}".format(id_), + command=f"records/{id_}", http_method="delete", ) except SaltCloudSystemExit: diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 9cba9cd52b3..91e9eddd6b2 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -296,11 +296,9 @@ def query( location = get_location() if not requesturl: - endpoint = provider.get( - "endpoint", "ec2.{}.{}".format(location, service_url) - ) + endpoint = provider.get("endpoint", f"ec2.{location}.{service_url}") - requesturl = "https://{}/".format(endpoint) + requesturl = f"https://{endpoint}/" endpoint = urllib.parse.urlparse(requesturl).netloc endpoint_path = urllib.parse.urlparse(requesturl).path else: @@ -1480,7 +1478,7 @@ def _create_eni_if_necessary(interface, vm_): eni_desc = result[1] if not eni_desc or not eni_desc.get("networkInterfaceId"): - raise SaltCloudException("Failed to create interface: {}".format(result)) + raise SaltCloudException(f"Failed to create interface: {result}") eni_id = eni_desc.get("networkInterfaceId") log.debug("Created network interface %s inst %s", eni_id, interface["DeviceIndex"]) @@ -1751,11 +1749,11 @@ def _param_from_config(key, data): if isinstance(data, dict): for k, v in data.items(): - param.update(_param_from_config("{}.{}".format(key, k), v)) + param.update(_param_from_config(f"{key}.{k}", v)) elif isinstance(data, list) or isinstance(data, tuple): for idx, conf_item in enumerate(data): - prefix = "{}.{}".format(key, idx) + prefix = f"{key}.{idx}" param.update(_param_from_config(prefix, conf_item)) else: @@ -1870,7 +1868,7 @@ def request_instance(vm_=None, call=None): params[spot_prefix + "SecurityGroup.1"] = ex_securitygroup else: for counter, sg_ in enumerate(ex_securitygroup): - params[spot_prefix + "SecurityGroup.{}".format(counter)] = sg_ + params[spot_prefix + f"SecurityGroup.{counter}"] = sg_ ex_iam_profile = iam_profile(vm_) if ex_iam_profile: @@ -1905,7 +1903,7 @@ def request_instance(vm_=None, call=None): params[spot_prefix + "SecurityGroupId.1"] = ex_securitygroupid else: for counter, sg_ in enumerate(ex_securitygroupid): - params[spot_prefix + "SecurityGroupId.{}".format(counter)] = sg_ + params[spot_prefix + f"SecurityGroupId.{counter}"] = sg_ placementgroup_ = get_placementgroup(vm_) if placementgroup_ is not None: @@ -2044,9 +2042,9 @@ def request_instance(vm_=None, call=None): else: dev_index = len(dev_list) # Add the device name in since it wasn't already there - params[ - "{}BlockDeviceMapping.{}.DeviceName".format(spot_prefix, dev_index) - ] = rd_name + params[f"{spot_prefix}BlockDeviceMapping.{dev_index}.DeviceName"] = ( + rd_name + ) # Set the termination value termination_key = "{}BlockDeviceMapping.{}.Ebs.DeleteOnTermination".format( @@ -2509,7 +2507,7 @@ def wait_for_instance( for line in comps[0].splitlines(): if not line: continue - keys += "\n{} {}".format(ip_address, line) + keys += f"\n{ip_address} {line}" with salt.utils.files.fopen(known_hosts_file, "a") as fp_: fp_.write(salt.utils.stringutils.to_str(keys)) @@ -2563,7 +2561,7 @@ def _validate_key_path_and_mode(key_filename): if not os.path.exists(key_filename): raise SaltCloudSystemExit( - "The EC2 key file '{}' does not exist.\n".format(key_filename) + f"The EC2 key file '{key_filename}' does not exist.\n" ) key_mode = stat.S_IMODE(os.stat(key_filename).st_mode) @@ -2752,7 +2750,7 @@ def create(vm_=None, call=None): __utils__["cloud.fire_event"]( "event", "setting tags", - "salt/cloud/spot_request_{}/tagging".format(sir_id), + f"salt/cloud/spot_request_{sir_id}/tagging", args={"tags": spot_request_tags}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2924,7 +2922,7 @@ def create(vm_=None, call=None): __utils__["cloud.fire_event"]( "event", "setting tags", - "salt/cloud/block_volume_{}/tagging".format(str(volid)), + f"salt/cloud/block_volume_{str(volid)}/tagging", args={"tags": tags}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3054,7 +3052,7 @@ def stop(name, call=None): __utils__["cloud.fire_event"]( "event", "stopping instance", - "salt/cloud/{}/stopping".format(name), + f"salt/cloud/{name}/stopping", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3088,7 +3086,7 @@ def start(name, call=None): __utils__["cloud.fire_event"]( "event", "starting instance", - "salt/cloud/{}/starting".format(name), + f"salt/cloud/{name}/starting", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3163,8 +3161,8 @@ def set_tags( tags = kwargs for idx, (tag_k, tag_v) in enumerate(tags.items()): - params["Tag.{}.Key".format(idx)] = tag_k - params["Tag.{}.Value".format(idx)] = tag_v + params[f"Tag.{idx}.Key"] = tag_k + params[f"Tag.{idx}.Value"] = tag_v attempts = 0 while attempts < aws.AWS_MAX_RETRIES: @@ -3210,7 +3208,7 @@ def set_tags( return settags - raise SaltCloudSystemExit("Failed to set tags on {}!".format(name)) + raise SaltCloudSystemExit(f"Failed to set tags on {name}!") def get_tags( @@ -3292,7 +3290,7 @@ def del_tags( params = {"Action": "DeleteTags", "ResourceId.1": instance_id} for idx, tag in enumerate(kwargs["tags"].split(",")): - params["Tag.{}.Key".format(idx)] = tag + params[f"Tag.{idx}.Key"] = tag aws.query( params, @@ -3356,7 +3354,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3377,7 +3375,7 @@ def destroy(name, call=None): "rename_on_destroy", get_configured_provider(), __opts__, search_global=False ) if rename_on_destroy is not False: - newname = "{}-DEL{}".format(name, uuid.uuid4().hex) + newname = f"{name}-DEL{uuid.uuid4().hex}" rename(name, kwargs={"newname": newname}, call="action") log.info( "Machine will be identified as %s until it has been cleaned up.", newname @@ -3410,7 +3408,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -4056,8 +4054,8 @@ def _toggle_delvol( if volume_id is not None and volume_id != item["ebs"]["volumeId"]: continue - params["BlockDeviceMapping.{}.DeviceName".format(idx)] = device_name - params["BlockDeviceMapping.{}.Ebs.DeleteOnTermination".format(idx)] = value + params[f"BlockDeviceMapping.{idx}.DeviceName"] = device_name + params[f"BlockDeviceMapping.{idx}.Ebs.DeleteOnTermination"] = value aws.query( params, @@ -4477,7 +4475,7 @@ def describe_volumes(kwargs=None, call=None): if "volume_id" in kwargs: volume_id = kwargs["volume_id"].split(",") for volume_index, volume_id in enumerate(volume_id): - params["VolumeId.{}".format(volume_index)] = volume_id + params[f"VolumeId.{volume_index}"] = volume_id log.debug(params) @@ -4796,17 +4794,17 @@ def describe_snapshots(kwargs=None, call=None): if "snapshot_id" in kwargs: snapshot_ids = kwargs["snapshot_id"].split(",") for snapshot_index, snapshot_id in enumerate(snapshot_ids): - params["SnapshotId.{}".format(snapshot_index)] = snapshot_id + params[f"SnapshotId.{snapshot_index}"] = snapshot_id if "owner" in kwargs: owners = kwargs["owner"].split(",") for owner_index, owner in enumerate(owners): - params["Owner.{}".format(owner_index)] = owner + params[f"Owner.{owner_index}"] = owner if "restorable_by" in kwargs: restorable_bys = kwargs["restorable_by"].split(",") for restorable_by_index, restorable_by in enumerate(restorable_bys): - params["RestorableBy.{}".format(restorable_by_index)] = restorable_by + params[f"RestorableBy.{restorable_by_index}"] = restorable_by log.debug(params) @@ -5013,11 +5011,11 @@ def _parse_pricing(url, name): "storageGiB", "USD", ): - price_js = price_js.replace(keyword, '"{}"'.format(keyword)) + price_js = price_js.replace(keyword, f'"{keyword}"') for keyword in ("region", "price", "size"): - price_js = price_js.replace(keyword, '"{}"'.format(keyword)) - price_js = price_js.replace('"{}"s'.format(keyword), '"{}s"'.format(keyword)) + price_js = price_js.replace(keyword, f'"{keyword}"') + price_js = price_js.replace(f'"{keyword}"s', f'"{keyword}s"') price_js = price_js.replace('""', '"') @@ -5031,7 +5029,7 @@ def _parse_pricing(url, name): sizes[size["size"]] = size regions[region["region"]] = sizes - outfile = os.path.join(__opts__["cachedir"], "ec2-pricing-{}.p".format(name)) + outfile = os.path.join(__opts__["cachedir"], f"ec2-pricing-{name}.p") with salt.utils.files.fopen(outfile, "w") as fho: salt.utils.msgpack.dump(regions, fho) @@ -5093,7 +5091,7 @@ def show_pricing(kwargs=None, call=None): else: name = "linux" - pricefile = os.path.join(__opts__["cachedir"], "ec2-pricing-{}.p".format(name)) + pricefile = os.path.join(__opts__["cachedir"], f"ec2-pricing-{name}.p") if not os.path.isfile(pricefile): update_pricing({"type": name}, "function") diff --git a/salt/cloud/clouds/gce.py b/salt/cloud/clouds/gce.py index 8e2d8618476..f5b16897fa0 100644 --- a/salt/cloud/clouds/gce.py +++ b/salt/cloud/clouds/gce.py @@ -186,7 +186,7 @@ def get_conn(): "service_account_private_key", provider, __opts__ ) gce = driver(email, private_key, project=project) - gce.connection.user_agent_append("{}/{}".format(_UA_PRODUCT, _UA_VERSION)) + gce.connection.user_agent_append(f"{_UA_PRODUCT}/{_UA_VERSION}") return gce @@ -544,7 +544,7 @@ def _parse_allow(allow): pairs = p.split(":") if pairs[0].lower() not in ["tcp", "udp", "icmp"]: raise SaltCloudSystemExit( - "Unsupported protocol {}. Must be tcp, udp, or icmp.".format(pairs[0]) + f"Unsupported protocol {pairs[0]}. Must be tcp, udp, or icmp." ) if len(pairs) == 1 or pairs[0].lower() == "icmp": seen_protos[pairs[0]] = [] @@ -2014,7 +2014,7 @@ def reboot(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "reboot instance", - "salt/cloud/{}/rebooting".format(vm_name), + f"salt/cloud/{vm_name}/rebooting", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2025,7 +2025,7 @@ def reboot(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "reboot instance", - "salt/cloud/{}/rebooted".format(vm_name), + f"salt/cloud/{vm_name}/rebooted", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2056,7 +2056,7 @@ def start(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "start instance", - "salt/cloud/{}/starting".format(vm_name), + f"salt/cloud/{vm_name}/starting", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2067,7 +2067,7 @@ def start(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "start instance", - "salt/cloud/{}/started".format(vm_name), + f"salt/cloud/{vm_name}/started", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2096,7 +2096,7 @@ def stop(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "stop instance", - "salt/cloud/{}/stopping".format(vm_name), + f"salt/cloud/{vm_name}/stopping", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2107,7 +2107,7 @@ def stop(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "stop instance", - "salt/cloud/{}/stopped".format(vm_name), + f"salt/cloud/{vm_name}/stopped", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2145,12 +2145,12 @@ def destroy(vm_name, call=None): exc, exc_info_on_loglevel=logging.DEBUG, ) - raise SaltCloudSystemExit("Could not find instance {}.".format(vm_name)) + raise SaltCloudSystemExit(f"Could not find instance {vm_name}.") __utils__["cloud.fire_event"]( "event", "delete instance", - "salt/cloud/{}/deleting".format(vm_name), + f"salt/cloud/{vm_name}/deleting", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2186,11 +2186,11 @@ def destroy(vm_name, call=None): exc, exc_info_on_loglevel=logging.DEBUG, ) - raise SaltCloudSystemExit("Could not destroy instance {}.".format(vm_name)) + raise SaltCloudSystemExit(f"Could not destroy instance {vm_name}.") __utils__["cloud.fire_event"]( "event", "delete instance", - "salt/cloud/{}/deleted".format(vm_name), + f"salt/cloud/{vm_name}/deleted", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2279,7 +2279,7 @@ def create_attach_volumes(name, kwargs, call=None): letter = ord("a") - 1 for idx, volume in enumerate(volumes): - volume_name = "{}-sd{}".format(name, chr(letter + 2 + idx)) + volume_name = f"{name}-sd{chr(letter + 2 + idx)}" volume_dict = { "disk_name": volume_name, diff --git a/salt/cloud/clouds/gogrid.py b/salt/cloud/clouds/gogrid.py index a2457b48ca4..1a28f837459 100644 --- a/salt/cloud/clouds/gogrid.py +++ b/salt/cloud/clouds/gogrid.py @@ -417,7 +417,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -428,7 +428,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -536,7 +536,7 @@ def _query( path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("GoGrid URL: %s", path) diff --git a/salt/cloud/clouds/hetzner.py b/salt/cloud/clouds/hetzner.py index 48bf8610c18..f8f34ad6d85 100644 --- a/salt/cloud/clouds/hetzner.py +++ b/salt/cloud/clouds/hetzner.py @@ -470,22 +470,22 @@ def start(name, call=None, wait=True): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." server.power_on() if wait and not wait_until(name, "running"): - return "Instance {} doesn't start.".format(name) + return f"Instance {name} doesn't start." __utils__["cloud.fire_event"]( "event", "started instance", - "salt/cloud/{}/started".format(name), + f"salt/cloud/{name}/started", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) - return {"Started": "{} was started.".format(name)} + return {"Started": f"{name} was started."} def stop(name, call=None, wait=True): @@ -504,22 +504,22 @@ def stop(name, call=None, wait=True): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." server.power_off() if wait and not wait_until(name, "off"): - return "Instance {} doesn't stop.".format(name) + return f"Instance {name} doesn't stop." __utils__["cloud.fire_event"]( "event", "stopped instance", - "salt/cloud/{}/stopped".format(name), + f"salt/cloud/{name}/stopped", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) - return {"Stopped": "{} was stopped.".format(name)} + return {"Stopped": f"{name} was stopped."} def reboot(name, call=None, wait=True): @@ -540,14 +540,14 @@ def reboot(name, call=None, wait=True): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." server.reboot() if wait and not wait_until(name, "running"): - return "Instance {} doesn't start.".format(name) + return f"Instance {name} doesn't start." - return {"Rebooted": "{} was rebooted.".format(name)} + return {"Rebooted": f"{name} was rebooted."} def destroy(name, call=None): @@ -568,12 +568,12 @@ def destroy(name, call=None): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -583,14 +583,14 @@ def destroy(name, call=None): if node["state"] == "running": stop(name, call="action", wait=False) if not wait_until(name, "off"): - return {"Error": "Unable to destroy {}, command timed out".format(name)} + return {"Error": f"Unable to destroy {name}, command timed out"} server.delete() __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -603,7 +603,7 @@ def destroy(name, call=None): __opts__, ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def resize(name, kwargs, call=None): @@ -624,7 +624,7 @@ def resize(name, kwargs, call=None): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." # Check the configuration size = kwargs.get("size", None) @@ -638,7 +638,7 @@ def resize(name, kwargs, call=None): __utils__["cloud.fire_event"]( "event", "resizing instance", - "salt/cloud/{}/resizing".format(name), + f"salt/cloud/{name}/resizing", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -648,17 +648,17 @@ def resize(name, kwargs, call=None): if node["state"] == "running": stop(name, call="action", wait=False) if not wait_until(name, "off"): - return {"Error": "Unable to resize {}, command timed out".format(name)} + return {"Error": f"Unable to resize {name}, command timed out"} server.change_type(server_type, kwargs.get("upgrade_disk", False)) __utils__["cloud.fire_event"]( "event", "resizing instance", - "salt/cloud/{}/resized".format(name), + f"salt/cloud/{name}/resized", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) - return {"Resized": "{} was resized.".format(name)} + return {"Resized": f"{name} was resized."} diff --git a/salt/cloud/clouds/joyent.py b/salt/cloud/clouds/joyent.py index 0da4a4a5e64..403e2ffab92 100644 --- a/salt/cloud/clouds/joyent.py +++ b/salt/cloud/clouds/joyent.py @@ -161,9 +161,7 @@ def get_image(vm_): images[vm_image]["name"] = images[vm_image]["id"] return images[vm_image] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_size(vm_): @@ -178,9 +176,7 @@ def get_size(vm_): if vm_size and str(vm_size) in sizes: return sizes[vm_size] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def query_instance(vm_=None, call=None): @@ -375,11 +371,11 @@ def create_node(**kwargs): if metadata is not None: for key, value in metadata.items(): - create_data["metadata.{}".format(key)] = value + create_data[f"metadata.{key}"] = value if tag is not None: for key, value in tag.items(): - create_data["tag.{}".format(key)] = value + create_data[f"tag.{key}"] = value if firewall_enabled is not None: create_data["firewall_enabled"] = firewall_enabled @@ -419,7 +415,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -435,7 +431,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -920,11 +916,11 @@ def avail_images(call=None): get_configured_provider(), __opts__, search_global=False, - default="{}{}/{}/images".format(DEFAULT_LOCATION, JOYENT_API_HOST_SUFFIX, user), + default=f"{DEFAULT_LOCATION}{JOYENT_API_HOST_SUFFIX}/{user}/images", ) if not img_url.startswith("http://") and not img_url.startswith("https://"): - img_url = "{}://{}".format(_get_proto(), img_url) + img_url = f"{_get_proto()}://{img_url}" rcode, data = query(command="my/images", method="GET") log.debug(data) @@ -1077,7 +1073,7 @@ def get_location_path( :param location: joyent data center location :return: url """ - return "{}://{}{}".format(_get_proto(), location, api_host_suffix) + return f"{_get_proto()}://{location}{api_host_suffix}" def query(action=None, command=None, args=None, method="GET", location=None, data=None): @@ -1151,7 +1147,7 @@ def query(action=None, command=None, args=None, method="GET", location=None, dat path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("User: '%s' on PATH: %s", user, path) @@ -1174,9 +1170,9 @@ def query(action=None, command=None, args=None, method="GET", location=None, dat signed = base64.b64encode(signed) user_arr = user.split("/") if len(user_arr) == 1: - keyid = "/{}/keys/{}".format(user_arr[0], ssh_keyname) + keyid = f"/{user_arr[0]}/keys/{ssh_keyname}" elif len(user_arr) == 2: - keyid = "/{}/users/{}/keys/{}".format(user_arr[0], user_arr[1], ssh_keyname) + keyid = f"/{user_arr[0]}/users/{user_arr[1]}/keys/{ssh_keyname}" else: log.error("Malformed user string") diff --git a/salt/cloud/clouds/libvirt.py b/salt/cloud/clouds/libvirt.py index 59affa6b94b..366e1871e1f 100644 --- a/salt/cloud/clouds/libvirt.py +++ b/salt/cloud/clouds/libvirt.py @@ -332,7 +332,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -345,7 +345,7 @@ def create(vm_): ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) vm_["key_filename"] = key_filename # wait_for_instance requires private_key @@ -374,7 +374,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) @@ -392,7 +392,7 @@ def create(vm_): description_elem = ElementTree.Element("description") domain_xml.insert(0, description_elem) description = domain_xml.find("./description") - description.text = "Cloned from {}".format(base) + description.text = f"Cloned from {base}" domain_xml.remove(domain_xml.find("./uuid")) for iface_xml in domain_xml.findall("./devices/interface"): @@ -426,9 +426,7 @@ def create(vm_): # see if there is a path element that needs rewriting if source_element and "path" in source_element.attrib: path = source_element.attrib["path"] - new_path = path.replace( - "/domain-{}/".format(base), "/domain-{}/".format(name) - ) + new_path = path.replace(f"/domain-{base}/", f"/domain-{name}/") log.debug("Rewriting agent socket path to %s", new_path) source_element.attrib["path"] = new_path @@ -471,7 +469,7 @@ def create(vm_): disk.find("./source").attrib["file"] = new_volume.path() else: raise SaltCloudExecutionFailure( - "Disk type '{}' not supported".format(disk_type) + f"Disk type '{disk_type}' not supported" ) clone_xml = salt.utils.stringutils.to_str(ElementTree.tostring(domain_xml)) @@ -515,7 +513,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -617,15 +615,15 @@ def destroy(name, call=None): pass if not found: - return "{} doesn't exist and can't be deleted".format(name) + return f"{name} doesn't exist and can't be deleted" if len(found) > 1: - return "{} doesn't identify a unique machine leaving things".format(name) + return f"{name} doesn't identify a unique machine leaving things" __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -636,7 +634,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -718,15 +716,15 @@ def find_pool_and_volume(conn, path): for v in sp.listAllVolumes(): if v.path() == path: return sp, v - raise SaltCloudNotFound("Could not find volume for path {}".format(path)) + raise SaltCloudNotFound(f"Could not find volume for path {path}") def generate_new_name(orig_name): if "." not in orig_name: - return "{}-{}".format(orig_name, uuid.uuid1()) + return f"{orig_name}-{uuid.uuid1()}" name, ext = orig_name.rsplit(".", 1) - return "{}-{}.{}".format(name, uuid.uuid1(), ext) + return f"{name}-{uuid.uuid1()}.{ext}" def get_domain_volumes(conn, domain): diff --git a/salt/cloud/clouds/linode.py b/salt/cloud/clouds/linode.py index 99850b3936a..7eefa9a9d67 100644 --- a/salt/cloud/clouds/linode.py +++ b/salt/cloud/clouds/linode.py @@ -339,7 +339,7 @@ def _get_ssh_keys(vm_): key_files = _get_ssh_key_files(vm_) for file in map(lambda file: Path(file).resolve(), key_files): if not (file.exists() or file.is_file()): - raise SaltCloudSystemExit("Invalid SSH key file: {}".format(str(file))) + raise SaltCloudSystemExit(f"Invalid SSH key file: {str(file)}") ssh_keys.add(file.read_text()) return list(ssh_keys) @@ -513,11 +513,11 @@ class LinodeAPIv4(LinodeAPI): if headers is None: headers = {} - headers["Authorization"] = "Bearer {}".format(api_key) + headers["Authorization"] = f"Bearer {api_key}" headers["Content-Type"] = "application/json" headers["User-Agent"] = "salt-cloud-linode" - url = "https://api.linode.com/{}{}".format(api_version, path) + url = f"https://api.linode.com/{api_version}{path}" decode = method != "DELETE" result = None @@ -578,7 +578,7 @@ class LinodeAPIv4(LinodeAPI): # If the response is not valid JSON or the error was not included, propagate the # human readable status representation. raise SaltCloudSystemExit( - "Linode API error occurred: {}".format(err_response.reason) + f"Linode API error occurred: {err_response.reason}" ) if decode: return self._get_response_json(result) @@ -623,7 +623,7 @@ class LinodeAPIv4(LinodeAPI): ) response = self._query( - "/linode/instances/{}/boot".format(linode_id), + f"/linode/instances/{linode_id}/boot", method="POST", data={"config_id": config_id}, ) @@ -656,7 +656,7 @@ class LinodeAPIv4(LinodeAPI): ) return self._query( - "/linode/instances/{}/clone".format(linode_id), + f"/linode/instances/{linode_id}/clone", method="POST", data={"region": location, "type": size}, ) @@ -688,7 +688,7 @@ class LinodeAPIv4(LinodeAPI): } return self._query( - "/linode/instances/{}/configs".format(linode_id), + f"/linode/instances/{linode_id}/configs", method="POST", data={"label": name, "devices": devices}, ) @@ -702,7 +702,7 @@ class LinodeAPIv4(LinodeAPI): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -795,7 +795,7 @@ class LinodeAPIv4(LinodeAPI): __utils__["cloud.fire_event"]( "event", "waiting for ssh", - "salt/cloud/{}/waiting_for_ssh".format(name), + f"salt/cloud/{name}/waiting_for_ssh", sock_dir=__opts__["sock_dir"], args={"ip_address": vm_["ssh_host"]}, transport=__opts__["transport"], @@ -810,7 +810,7 @@ class LinodeAPIv4(LinodeAPI): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -824,7 +824,7 @@ class LinodeAPIv4(LinodeAPI): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -838,7 +838,7 @@ class LinodeAPIv4(LinodeAPI): instance = self._get_linode_by_name(name) linode_id = instance.get("id", None) - self._query("/linode/instances/{}".format(linode_id), method="DELETE") + self._query(f"/linode/instances/{linode_id}", method="DELETE") def get_config_id(self, kwargs=None): name = kwargs.get("name", None) @@ -853,7 +853,7 @@ class LinodeAPIv4(LinodeAPI): if linode_id is None: linode_id = self.get_linode(kwargs=kwargs).get("id", None) - response = self._query("/linode/instances/{}/configs".format(linode_id)) + response = self._query(f"/linode/instances/{linode_id}/configs") configs = response.get("data", []) return {"config_id": configs[0]["id"]} @@ -879,7 +879,7 @@ class LinodeAPIv4(LinodeAPI): instance = self._get_linode_by_name(name) linode_id = instance.get("id", None) - self._query("/linode/instances/{}/reboot".format(linode_id), method="POST") + self._query(f"/linode/instances/{linode_id}/reboot", method="POST") return self._wait_for_linode_status(linode_id, "running") def show_instance(self, name): @@ -939,7 +939,7 @@ class LinodeAPIv4(LinodeAPI): "msg": "Machine already running", } - self._query("/linode/instances/{}/boot".format(linode_id), method="POST") + self._query(f"/linode/instances/{linode_id}/boot", method="POST") self._wait_for_linode_status(linode_id, "running") return { @@ -960,13 +960,13 @@ class LinodeAPIv4(LinodeAPI): "msg": "Machine already stopped", } - self._query("/linode/instances/{}/shutdown".format(linode_id), method="POST") + self._query(f"/linode/instances/{linode_id}/shutdown", method="POST") self._wait_for_linode_status(linode_id, "offline") return {"success": True, "state": "Stopped", "action": "stop"} def _get_linode_by_id(self, linode_id): - return self._query("/linode/instances/{}".format(linode_id)) + return self._query(f"/linode/instances/{linode_id}") def _get_linode_by_name(self, name): result = self._query("/linode/instances") @@ -976,9 +976,7 @@ class LinodeAPIv4(LinodeAPI): if instance["label"] == name: return instance - raise SaltCloudNotFound( - "The specified name, {}, could not be found.".format(name) - ) + raise SaltCloudNotFound(f"The specified name, {name}, could not be found.") def _list_linodes(self, full=False): result = self._query("/linode/instances") @@ -1005,7 +1003,7 @@ class LinodeAPIv4(LinodeAPI): return ret def _get_linode_type(self, linode_type): - return self._query("/linode/types/{}".format(linode_type)) + return self._query(f"/linode/types/{linode_type}") def _get_ips(self, linode_id): instance = self._get_linode_by_id(linode_id) @@ -1049,15 +1047,13 @@ class LinodeAPIv4(LinodeAPI): time.sleep(poll_interval / 1000) log.info("retrying: polling for %s...", description) else: - raise SaltCloudException( - "timed out: polling for {}".format(description) - ) + raise SaltCloudException(f"timed out: polling for {description}") def _wait_for_entity_status( self, getter, status, entity_name="item", identifier="some", timeout=None ): return self._poll( - "{} (id={}) status to be '{}'".format(entity_name, identifier, status), + f"{entity_name} (id={identifier}) status to be '{status}'", getter, lambda item: item.get("status") == status, timeout=timeout, @@ -1126,8 +1122,8 @@ class LinodeAPIv4(LinodeAPI): return True return self._poll( - "event {} to be '{}'".format(event_id, status), - lambda: self._query("/account/events/{}".format(event_id)), + f"event {event_id} to be '{status}'", + lambda: self._query(f"/account/events/{event_id}"), condition, timeout=timeout, ) @@ -1170,7 +1166,7 @@ class LinodeAPIv3(LinodeAPI): if "api_key" not in args.keys(): args["api_key"] = apikey if action and "api_action" not in args.keys(): - args["api_action"] = "{}.{}".format(action, command) + args["api_action"] = f"{action}.{command}" if header_dict is None: header_dict = {} if method != "POST": @@ -1266,7 +1262,7 @@ class LinodeAPIv3(LinodeAPI): if status == "1": raise SaltCloudSystemExit( "Cannot boot Linode {0}. " - + "Linode {} is already running.".format(linode_item) + + f"Linode {linode_item} is already running." ) # Boot the VM and get the JobID from Linode @@ -1311,7 +1307,7 @@ class LinodeAPIv3(LinodeAPI): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -1348,7 +1344,7 @@ class LinodeAPIv3(LinodeAPI): kwargs = { "clonefrom": clonefrom_name, - "image": "Clone of {}".format(clonefrom_name), + "image": f"Clone of {clonefrom_name}", } if size is None: @@ -1412,7 +1408,7 @@ class LinodeAPIv3(LinodeAPI): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args=__utils__["cloud.filter_event"]( "requesting", vm_, ["name", "profile", "provider", "driver"] ), @@ -1505,7 +1501,7 @@ class LinodeAPIv3(LinodeAPI): __utils__["cloud.fire_event"]( "event", "waiting for ssh", - "salt/cloud/{}/waiting_for_ssh".format(name), + f"salt/cloud/{name}/waiting_for_ssh", sock_dir=__opts__["sock_dir"], args={"ip_address": vm_["ssh_host"]}, transport=__opts__["transport"], @@ -1522,7 +1518,7 @@ class LinodeAPIv3(LinodeAPI): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -1560,9 +1556,9 @@ class LinodeAPIv3(LinodeAPI): instance = self._get_linode_by_name(name) linode_id = instance.get("id", None) - disklist = "{},{}".format(root_disk_id, swap_disk_id) + disklist = f"{root_disk_id},{swap_disk_id}" if data_disk_id is not None: - disklist = "{},{},{}".format(root_disk_id, swap_disk_id, data_disk_id) + disklist = f"{root_disk_id},{swap_disk_id},{data_disk_id}" config_args = { "LinodeID": int(linode_id), @@ -1663,7 +1659,7 @@ class LinodeAPIv3(LinodeAPI): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1678,7 +1674,7 @@ class LinodeAPIv3(LinodeAPI): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1732,7 +1728,7 @@ class LinodeAPIv3(LinodeAPI): plan_type = "Nanode" plan_size = plan_size / 1024 - new_label = "{} {}GB".format(plan_type, plan_size) + new_label = f"{plan_type} {plan_size}GB" if new_label not in sizes: raise SaltCloudException( @@ -2052,9 +2048,7 @@ class LinodeAPIv3(LinodeAPI): if name == node["LABEL"]: return node - raise SaltCloudNotFound( - "The specified name, {}, could not be found.".format(name) - ) + raise SaltCloudNotFound(f"The specified name, {name}, could not be found.") def _get_linode_by_id(self, linode_id): result = self._query("linode", "list", args={"LinodeID": linode_id}) diff --git a/salt/cloud/clouds/lxc.py b/salt/cloud/clouds/lxc.py index da293dca66a..ced89e587bb 100644 --- a/salt/cloud/clouds/lxc.py +++ b/salt/cloud/clouds/lxc.py @@ -179,7 +179,7 @@ def _salt(fun, *args, **kw): ping_retries += 1 log.error("%s unreachable, retrying", target) if not ping: - raise SaltCloudSystemExit("Target {} unreachable".format(target)) + raise SaltCloudSystemExit(f"Target {target} unreachable") jid = conn.cmd_async(tgt=target, fun=fun, arg=args, kwarg=kw, **rkwargs) cret = conn.cmd( tgt=target, fun="saltutil.find_job", arg=[jid], timeout=10, **kwargs @@ -224,9 +224,7 @@ def _salt(fun, *args, **kw): time.sleep(0.5) try: if "is not available." in ret: - raise SaltCloudSystemExit( - "module/function {} is not available".format(fun) - ) + raise SaltCloudSystemExit(f"module/function {fun} is not available") except SaltCloudSystemExit: # pylint: disable=try-except-raise raise except TypeError: @@ -367,12 +365,12 @@ def destroy(vm_, call=None): ) if not get_configured_provider(): return - ret = {"comment": "{} was not found".format(vm_), "result": False} + ret = {"comment": f"{vm_} was not found", "result": False} if _salt("lxc.info", vm_, path=path): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(vm_), + f"salt/cloud/{vm_}/destroying", args={"name": vm_, "instance_id": vm_}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -380,11 +378,11 @@ def destroy(vm_, call=None): cret = _salt("lxc.destroy", vm_, stop=True, path=path) ret["result"] = cret["result"] if ret["result"]: - ret["comment"] = "{} was destroyed".format(vm_) + ret["comment"] = f"{vm_} was destroyed" __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(vm_), + f"salt/cloud/{vm_}/destroyed", args={"name": vm_, "instance_id": vm_}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -506,14 +504,14 @@ def get_configured_provider(vm_=None): matched = False # --list-images level if img_provider: - tgt = "provider: {}".format(img_provider) + tgt = f"provider: {img_provider}" if dalias == img_provider: data = get_provider(img_provider) matched = True # providers are set in configuration if not data and "profile" not in __opts__ and arg_providers: for name in arg_providers: - tgt = "provider: {}".format(name) + tgt = f"provider: {name}" if dalias == name: data = get_provider(name) if data: @@ -523,13 +521,13 @@ def get_configured_provider(vm_=None): elif "profile" in __opts__: curprof = __opts__["profile"] profs = __opts__["profiles"] - tgt = "profile: {}".format(curprof) + tgt = f"profile: {curprof}" if ( curprof in profs and profs[curprof]["provider"] == _get_active_provider_name() ): prov, cdriver = profs[curprof]["provider"].split(":") - tgt += " provider: {}".format(prov) + tgt += f" provider: {prov}" data = get_provider(prov) matched = True # fallback if we have only __active_provider_name__ diff --git a/salt/cloud/clouds/msazure.py b/salt/cloud/clouds/msazure.py index fef62f07a70..92fbf7f9bc6 100644 --- a/salt/cloud/clouds/msazure.py +++ b/salt/cloud/clouds/msazure.py @@ -853,7 +853,7 @@ def create_attach_volumes(name, kwargs, call=None, wait_to_finish=True): kwargs["service_name"], kwargs["deployment_name"], kwargs["role_name"], - **volume + **volume, ) log.debug(attach) @@ -954,7 +954,7 @@ def create_attach_volumes(name, kwargs, call=None, wait_to_finish=True): kwargs["service_name"], kwargs["deployment_name"], kwargs["role_name"], - **volume + **volume, ) _wait_for_async(conn, result.request_id) @@ -1031,7 +1031,7 @@ def destroy(name, conn=None, call=None, kwargs=None): result = conn.delete_deployment(service_name, service_name) except AzureConflictHttpError as exc: log.error(exc.message) - raise SaltCloudSystemExit("{}: {}".format(name, exc.message)) + raise SaltCloudSystemExit(f"{name}: {exc.message}") delete_type = "delete_deployment" _wait_for_async(conn, result.request_id) ret[name] = { diff --git a/salt/cloud/clouds/oneandone.py b/salt/cloud/clouds/oneandone.py index 7ddb50d3aba..6028e4f53e0 100644 --- a/salt/cloud/clouds/oneandone.py +++ b/salt/cloud/clouds/oneandone.py @@ -193,9 +193,7 @@ def get_size(vm_): if size: return size - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def get_image(vm_): @@ -211,9 +209,7 @@ def get_image(vm_): if vm_image and vm_image in (images[key]["id"], images[key]["name"]): return images[key] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def avail_locations(conn=None, call=None): @@ -735,7 +731,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -749,7 +745,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -846,7 +842,7 @@ def get_key_filename(vm_): key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_private_key '{}' does not exist".format(key_filename) + f"The defined ssh_private_key '{key_filename}' does not exist" ) return key_filename @@ -897,11 +893,9 @@ def _wait_for_completion(conn, wait_timeout, server_id): if server_state == "powered_on": return elif server_state == "failed": - raise Exception("Server creation failed for {}".format(server_id)) + raise Exception(f"Server creation failed for {server_id}") elif server_state in ("active", "enabled", "deploying", "configuring"): continue else: - raise Exception("Unknown server state {}".format(server_state)) - raise Exception( - "Timed out waiting for server create completion for {}".format(server_id) - ) + raise Exception(f"Unknown server state {server_state}") + raise Exception(f"Timed out waiting for server create completion for {server_id}") diff --git a/salt/cloud/clouds/opennebula.py b/salt/cloud/clouds/opennebula.py index 71f9372a594..7fa1428f834 100644 --- a/salt/cloud/clouds/opennebula.py +++ b/salt/cloud/clouds/opennebula.py @@ -558,7 +558,7 @@ def get_cluster_id(kwargs=None, call=None): try: ret = list_clusters()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The cluster '{}' could not be found".format(name)) + raise SaltCloudSystemExit(f"The cluster '{name}' could not be found") return ret @@ -590,7 +590,7 @@ def get_datastore_id(kwargs=None, call=None): try: ret = list_datastores()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The datastore '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The datastore '{name}' could not be found.") return ret @@ -622,7 +622,7 @@ def get_host_id(kwargs=None, call=None): try: ret = avail_locations()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The host '{}' could not be found".format(name)) + raise SaltCloudSystemExit(f"The host '{name}' could not be found") return ret @@ -641,9 +641,7 @@ def get_image(vm_): for image in images: if vm_image in (images[image]["name"], images[image]["id"]): return images[image]["id"] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_image_id(kwargs=None, call=None): @@ -673,7 +671,7 @@ def get_image_id(kwargs=None, call=None): try: ret = avail_images()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The image '{}' could not be found".format(name)) + raise SaltCloudSystemExit(f"The image '{name}' could not be found") return ret @@ -697,7 +695,7 @@ def get_location(vm_): if vm_location in (locations[location]["name"], locations[location]["id"]): return locations[location]["id"] raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -728,9 +726,7 @@ def get_secgroup_id(kwargs=None, call=None): try: ret = list_security_groups()[name]["id"] except KeyError: - raise SaltCloudSystemExit( - "The security group '{}' could not be found.".format(name) - ) + raise SaltCloudSystemExit(f"The security group '{name}' could not be found.") return ret @@ -761,7 +757,7 @@ def get_template_image(kwargs=None, call=None): ret = list_templates()[name]["template"]["disk"]["image"] except KeyError: raise SaltCloudSystemExit( - "The image for template '{}' could not be found.".format(name) + f"The image for template '{name}' could not be found." ) return ret @@ -794,7 +790,7 @@ def get_template_id(kwargs=None, call=None): try: ret = list_templates()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The template '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The template '{name}' could not be found.") return ret @@ -816,7 +812,7 @@ def get_template(vm_): return list_templates()[vm_template]["id"] except KeyError: raise SaltCloudNotFound( - "The specified template, '{}', could not be found.".format(vm_template) + f"The specified template, '{vm_template}', could not be found." ) @@ -847,7 +843,7 @@ def get_vm_id(kwargs=None, call=None): try: ret = list_nodes()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The VM '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The VM '{name}' could not be found.") return ret @@ -879,7 +875,7 @@ def get_vn_id(kwargs=None, call=None): try: ret = list_vns()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The VN '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The VN '{name}' could not be found.") return ret @@ -895,9 +891,7 @@ def _get_device_template(disk, disk_info, template=None): def _require_disk_opts(*args): for arg in args: if arg not in disk_info: - raise SaltCloudSystemExit( - "The disk {} requires a {} argument".format(disk, arg) - ) + raise SaltCloudSystemExit(f"The disk {disk} requires a {arg} argument") _require_disk_opts("disk_type", "size") @@ -919,12 +913,12 @@ def _get_device_template(disk, disk_info, template=None): if disk_type == "volatile": _require_disk_opts("type") v_type = disk_info["type"] - temp = "DISK=[TYPE={}, SIZE={}]".format(v_type, size) + temp = f"DISK=[TYPE={v_type}, SIZE={size}]" if v_type == "fs": _require_disk_opts("format") format = disk_info["format"] - temp = "DISK=[TYPE={}, SIZE={}, FORMAT={}]".format(v_type, size, format) + temp = f"DISK=[TYPE={v_type}, SIZE={size}, FORMAT={format}]" return temp # TODO add persistant disk_type @@ -1101,7 +1095,7 @@ def create(vm_): ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) if fqdn: @@ -1178,7 +1172,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], ) @@ -1192,7 +1186,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], ) @@ -4474,7 +4468,7 @@ def _get_xml(xml_str): except etree.XMLSyntaxError as err: # opennebula returned invalid XML, which could be an error message, so # log it - raise SaltCloudSystemExit("opennebula returned: {}".format(xml_str)) + raise SaltCloudSystemExit(f"opennebula returned: {xml_str}") return xml_data diff --git a/salt/cloud/clouds/openstack.py b/salt/cloud/clouds/openstack.py index 0a8b8d7e1b2..8dfbf1c341c 100644 --- a/salt/cloud/clouds/openstack.py +++ b/salt/cloud/clouds/openstack.py @@ -737,7 +737,7 @@ def create(vm_): ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_key_file '{}' does not exist".format(key_filename) + f"The defined ssh_key_file '{key_filename}' does not exist" ) vm_["key_filename"] = key_filename @@ -846,7 +846,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -863,7 +863,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/packet.py b/salt/cloud/clouds/packet.py index 1c6217bf4f7..0e1b65bed0c 100644 --- a/salt/cloud/clouds/packet.py +++ b/salt/cloud/clouds/packet.py @@ -242,9 +242,7 @@ def _wait_for_status(status_type, object_id, status=None, timeout=500, quiet=Tru manager = packet.Manager(auth_token=vm_["token"]) for i in range(0, iterations): - get_object = getattr( - manager, "get_{status_type}".format(status_type=status_type) - ) + get_object = getattr(manager, f"get_{status_type}") obj = get_object(object_id) if obj.state == status: @@ -340,7 +338,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -413,7 +411,7 @@ def create(vm_): volume = manager.create_volume( vm_["project_id"], - "{}_storage".format(name), + f"{name}_storage", vm_.get("storage_tier"), vm_.get("storage_size"), vm_.get("location"), @@ -441,7 +439,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -580,7 +578,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -606,7 +604,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/parallels.py b/salt/cloud/clouds/parallels.py index 4b65ddd9c8a..a5e6ca0fff7 100644 --- a/salt/cloud/clouds/parallels.py +++ b/salt/cloud/clouds/parallels.py @@ -310,11 +310,11 @@ def create(vm_): name = vm_["name"] if not wait_until(name, "CREATED"): - return {"Error": "Unable to start {}, command timed out".format(name)} + return {"Error": f"Unable to start {name}, command timed out"} start(vm_["name"], call="action") if not wait_until(name, "STARTED"): - return {"Error": "Unable to start {}, command timed out".format(name)} + return {"Error": f"Unable to start {name}, command timed out"} def __query_node_data(vm_name): data = show_instance(vm_name, call="action") @@ -391,7 +391,7 @@ def query(action=None, command=None, args=None, method="GET", data=None): path += action if command: - path += "/{}".format(command) + path += f"/{command}" if not type(args, dict): args = {} @@ -404,7 +404,7 @@ def query(action=None, command=None, args=None, method="GET", data=None): if args: params = urllib.parse.urlencode(args) - req = urllib.request.Request(url="{}?{}".format(path, params), **kwargs) + req = urllib.request.Request(url=f"{path}?{params}", **kwargs) else: req = urllib.request.Request(url=path, **kwargs) @@ -526,7 +526,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -536,7 +536,7 @@ def destroy(name, call=None): if node["state"] == "STARTED": stop(name, call="action") if not wait_until(name, "STOPPED"): - return {"Error": "Unable to destroy {}, command timed out".format(name)} + return {"Error": f"Unable to destroy {name}, command timed out"} data = query(action="ve", command=name, method="DELETE") @@ -546,7 +546,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -557,7 +557,7 @@ def destroy(name, call=None): name, _get_active_provider_name().split(":")[0], __opts__ ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def start(name, call=None): @@ -575,12 +575,12 @@ def start(name, call=None): "The show_instance action must be called with -a or --action." ) - data = query(action="ve", command="{}/start".format(name), method="PUT") + data = query(action="ve", command=f"{name}/start", method="PUT") if "error" in data: return data["error"] - return {"Started": "{} was started.".format(name)} + return {"Started": f"{name} was started."} def stop(name, call=None): @@ -598,9 +598,9 @@ def stop(name, call=None): "The show_instance action must be called with -a or --action." ) - data = query(action="ve", command="{}/stop".format(name), method="PUT") + data = query(action="ve", command=f"{name}/stop", method="PUT") if "error" in data: return data["error"] - return {"Stopped": "{} was stopped.".format(name)} + return {"Stopped": f"{name} was stopped."} diff --git a/salt/cloud/clouds/profitbricks.py b/salt/cloud/clouds/profitbricks.py index 72f1b362551..a8a9351a717 100644 --- a/salt/cloud/clouds/profitbricks.py +++ b/salt/cloud/clouds/profitbricks.py @@ -328,9 +328,7 @@ def get_size(vm_): combinations = (str(sizes[size]["id"]), str(size)) if vm_size and str(vm_size) in combinations: return sizes[size] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def get_datacenter_id(): @@ -415,7 +413,7 @@ def get_datacenter(conn): return item raise SaltCloudNotFound( - "The specified datacenter '{}' could not be found.".format(datacenter_id) + f"The specified datacenter '{datacenter_id}' could not be found." ) @@ -488,9 +486,7 @@ def get_image(vm_): if vm_image and vm_image in (images[key]["id"], images[key]["name"]): return images[key] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def list_datacenters(conn=None, call=None): @@ -725,7 +721,7 @@ def get_public_keys(vm_): key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_public_key '{}' does not exist".format(key_filename) + f"The defined ssh_public_key '{key_filename}' does not exist" ) ssh_keys = [] with salt.utils.files.fopen(key_filename) as rfh: @@ -746,7 +742,7 @@ def get_key_filename(vm_): key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_private_key '{}' does not exist".format(key_filename) + f"The defined ssh_private_key '{key_filename}' does not exist" ) return key_filename @@ -941,7 +937,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -972,7 +968,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1142,9 +1138,7 @@ def _get_data_volumes(vm_): # Verify the required 'disk_size' property is present in the cloud # profile config if "disk_size" not in volumes[key].keys(): - raise SaltCloudConfigError( - "The volume '{}' is missing 'disk_size'".format(key) - ) + raise SaltCloudConfigError(f"The volume '{key}' is missing 'disk_size'") # Use 'HDD' if no 'disk_type' property is present in cloud profile if "disk_type" not in volumes[key].keys(): volumes[key]["disk_type"] = "HDD" @@ -1187,7 +1181,7 @@ def _get_firewall_rules(firewall_rules): # profile config if "protocol" not in firewall_rules[key].keys(): raise SaltCloudConfigError( - "The firewall rule '{}' is missing 'protocol'".format(key) + f"The firewall rule '{key}' is missing 'protocol'" ) ret.append( FirewallRule( diff --git a/salt/cloud/clouds/proxmox.py b/salt/cloud/clouds/proxmox.py index 61340f0928f..82fe04f004e 100644 --- a/salt/cloud/clouds/proxmox.py +++ b/salt/cloud/clouds/proxmox.py @@ -135,7 +135,7 @@ def _authenticate(): ) connect_data = {"username": username, "password": passwd} - full_url = "https://{}:{}/api2/json/access/ticket".format(url, port) + full_url = f"https://{url}:{port}/api2/json/access/ticket" response = requests.post( full_url, verify=verify_ssl, data=connect_data, timeout=120 @@ -155,7 +155,7 @@ def query(conn_type, option, post_data=None): log.debug("Not authenticated yet, doing that now..") _authenticate() - full_url = "https://{}:{}/api2/json/{}".format(url, port, option) + full_url = f"https://{url}:{port}/api2/json/{option}" log.debug("%s: %s (%s)", conn_type, full_url, post_data) @@ -450,9 +450,7 @@ def avail_images(call=None, location="local"): ret = {} for host_name, host_details in avail_locations().items(): - for item in query( - "get", "nodes/{}/storage/{}/content".format(host_name, location) - ): + for item in query("get", f"nodes/{host_name}/storage/{location}/content"): ret[item["volid"]] = item return ret @@ -559,7 +557,7 @@ def _dictionary_to_stringlist(input_dict): setting1=value1,setting2=value2 """ - return ",".join("{}={}".format(k, input_dict[k]) for k in sorted(input_dict.keys())) + return ",".join(f"{k}={input_dict[k]}" for k in sorted(input_dict.keys())) def _reconfigure_clone(vm_, vmid): @@ -715,7 +713,7 @@ def create(vm_): # wait until the vm has been created so we can start it if not wait_for_created(data["upid"], timeout=300): - return {"Error": "Unable to create {}, command timed out".format(name)} + return {"Error": f"Unable to create {name}, command timed out"} if vm_.get("clone") is True: _reconfigure_clone(vm_, vmid) @@ -728,7 +726,7 @@ def create(vm_): # Wait until the VM has fully started log.debug('Waiting for state "running" for vm %s on %s', vmid, host) if not wait_for_state(vmid, "running"): - return {"Error": "Unable to start {}, command timed out".format(name)} + return {"Error": f"Unable to start {name}, command timed out"} if agent_get_ip is True: try: @@ -868,7 +866,7 @@ def _import_api(): Load this json content into global variable "api" """ global api - full_url = "https://{}:{}/pve-docs/api-viewer/apidoc.js".format(url, port) + full_url = f"https://{url}:{port}/pve-docs/api-viewer/apidoc.js" returned_data = requests.get(full_url, verify=verify_ssl, timeout=120) re_filter = re.compile(" (?:pveapi|apiSchema) = (.*)^;", re.DOTALL | re.MULTILINE) @@ -1102,12 +1100,12 @@ def get_vmconfig(vmid, node=None, node_type="openvz"): if node is None: # We need to figure out which node this VM is on. for host_name, host_details in avail_locations().items(): - for item in query("get", "nodes/{}/{}".format(host_name, node_type)): + for item in query("get", f"nodes/{host_name}/{node_type}"): if item["vmid"] == vmid: node = host_name # If we reached this point, we have all the information we need - data = query("get", "nodes/{}/{}/{}/config".format(node, node_type, vmid)) + data = query("get", f"nodes/{node}/{node_type}/{vmid}/config") return data @@ -1179,7 +1177,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1193,7 +1191,7 @@ def destroy(name, call=None): # wait until stopped if not wait_for_state(vmobj["vmid"], "stopped"): - return {"Error": "Unable to stop {}, command timed out".format(name)} + return {"Error": f"Unable to stop {name}, command timed out"} # required to wait a bit here, otherwise the VM is sometimes # still locked and destroy fails. @@ -1203,7 +1201,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1213,7 +1211,7 @@ def destroy(name, call=None): name, _get_active_provider_name().split(":")[0], __opts__ ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def set_vm_status(status, name=None, vmid=None): @@ -1302,7 +1300,7 @@ def start(name, vmid=None, call=None): # xxx: TBD: Check here whether the status was actually changed to 'started' - return {"Started": "{} was started.".format(name)} + return {"Started": f"{name} was started."} def stop(name, vmid=None, call=None): @@ -1324,7 +1322,7 @@ def stop(name, vmid=None, call=None): # xxx: TBD: Check here whether the status was actually changed to 'stopped' - return {"Stopped": "{} was stopped.".format(name)} + return {"Stopped": f"{name} was stopped."} def shutdown(name=None, vmid=None, call=None): @@ -1348,4 +1346,4 @@ def shutdown(name=None, vmid=None, call=None): # xxx: TBD: Check here whether the status was actually changed to 'stopped' - return {"Shutdown": "{} was shutdown.".format(name)} + return {"Shutdown": f"{name} was shutdown."} diff --git a/salt/cloud/clouds/qingcloud.py b/salt/cloud/clouds/qingcloud.py index fd2f179b758..6c3bda925e4 100644 --- a/salt/cloud/clouds/qingcloud.py +++ b/salt/cloud/clouds/qingcloud.py @@ -108,7 +108,7 @@ def _compute_signature(parameters, access_key_secret, method, path): """ parameters["signature_method"] = "HmacSHA256" - string_to_sign = "{}\n{}\n".format(method.upper(), path) + string_to_sign = f"{method.upper()}\n{path}\n" keys = sorted(parameters.keys()) pairs = [] @@ -166,9 +166,9 @@ def query(params=None): for sk, sv in value[i - 1].items(): if isinstance(sv, dict) or isinstance(sv, list): sv = salt.utils.json.dumps(sv, separators=(",", ":")) - real_parameters["{}.{}.{}".format(key, i, sk)] = sv + real_parameters[f"{key}.{i}.{sk}"] = sv else: - real_parameters["{}.{}".format(key, i)] = value[i - 1] + real_parameters[f"{key}.{i}"] = value[i - 1] else: real_parameters[key] = value @@ -252,7 +252,7 @@ def _get_location(vm_=None): return vm_location raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -320,9 +320,7 @@ def _get_image(vm_): if vm_image in images: return vm_image - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def show_image(kwargs, call=None): @@ -442,9 +440,7 @@ def _get_size(vm_): if vm_size in sizes: return vm_size - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def _show_normalized_node(full_node): @@ -626,7 +622,7 @@ def show_instance(instance_id, call=None, kwargs=None): if items["total_count"] == 0: raise SaltCloudNotFound( - "The specified instance, '{}', could not be found.".format(instance_id) + f"The specified instance, '{instance_id}', could not be found." ) full_node = items["instance_set"][0] @@ -878,7 +874,7 @@ def destroy(instance_id, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -894,7 +890,7 @@ def destroy(instance_id, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/saltify.py b/salt/cloud/clouds/saltify.py index 451478a5552..d3430935fc0 100644 --- a/salt/cloud/clouds/saltify.py +++ b/salt/cloud/clouds/saltify.py @@ -289,7 +289,7 @@ def create(vm_): if ssh_host: log.info("trying to ping %s", ssh_host) count = "n" if salt.utils.platform.is_windows() else "c" - cmd = "ping -{} 1 {}".format(count, ssh_host) + cmd = f"ping -{count} 1 {ssh_host}" good_ping = local.cmd(wol_host, "cmd.retcode", [cmd]) == 0 if good_ping: log.info("successful ping.") @@ -464,7 +464,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], @@ -510,13 +510,13 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def reboot(name, call=None): diff --git a/salt/cloud/clouds/scaleway.py b/salt/cloud/clouds/scaleway.py index 9b412181c01..d261e50360f 100644 --- a/salt/cloud/clouds/scaleway.py +++ b/salt/cloud/clouds/scaleway.py @@ -160,7 +160,7 @@ def get_image(server_): if server_image in (images[image]["name"], images[image]["id"]): return images[image]["id"] raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(server_image) + f"The specified image, '{server_image}', could not be found." ) @@ -225,7 +225,7 @@ def create(server_): if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) ssh_password = config.get_cloud_config_value("ssh_password", server_, __opts__) @@ -346,10 +346,10 @@ def query( ) ) - path = "{}/{}/".format(base_path, method) + path = f"{base_path}/{method}/" if server_id: - path += "{}/".format(server_id) + path += f"{server_id}/" if command: path += command @@ -439,7 +439,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -457,7 +457,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/softlayer.py b/salt/cloud/clouds/softlayer.py index 5c6892227ef..c0f282f84ed 100644 --- a/salt/cloud/clouds/softlayer.py +++ b/salt/cloud/clouds/softlayer.py @@ -269,7 +269,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -395,7 +395,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) @@ -513,7 +513,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -620,7 +620,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -633,7 +633,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/softlayer_hw.py b/salt/cloud/clouds/softlayer_hw.py index 2cfd2fbf38c..f8a92f8a8a8 100644 --- a/salt/cloud/clouds/softlayer_hw.py +++ b/salt/cloud/clouds/softlayer_hw.py @@ -241,7 +241,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -311,7 +311,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) @@ -406,7 +406,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -514,7 +514,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -535,7 +535,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/tencentcloud.py b/salt/cloud/clouds/tencentcloud.py index b2903b9380a..374f4a3247b 100644 --- a/salt/cloud/clouds/tencentcloud.py +++ b/salt/cloud/clouds/tencentcloud.py @@ -123,7 +123,7 @@ def get_provider_client(name=None): elif name == "vpc_client": client = vpc_client.VpcClient(crd, region, cpf) else: - raise SaltCloudSystemExit("Client name {} is not supported".format(name)) + raise SaltCloudSystemExit(f"Client name {name} is not supported") return client @@ -206,11 +206,11 @@ def avail_sizes(call=None): ret[typeConfig.InstanceType] = { "Zone": typeConfig.Zone, "InstanceFamily": typeConfig.InstanceFamily, - "Memory": "{}GB".format(typeConfig.Memory), - "CPU": "{}-Core".format(typeConfig.CPU), + "Memory": f"{typeConfig.Memory}GB", + "CPU": f"{typeConfig.CPU}-Core", } if typeConfig.GPU: - ret[typeConfig.InstanceType]["GPU"] = "{}-Core".format(typeConfig.GPU) + ret[typeConfig.InstanceType]["GPU"] = f"{typeConfig.GPU}-Core" return ret @@ -714,7 +714,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -730,7 +730,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -782,9 +782,7 @@ def show_image(kwargs, call=None): resp = client.DescribeImages(req) if not resp.ImageSet: - raise SaltCloudNotFound( - "The specified image '{}' could not be found.".format(image) - ) + raise SaltCloudNotFound(f"The specified image '{image}' could not be found.") ret = {} for image in resp.ImageSet: @@ -794,7 +792,7 @@ def show_image(kwargs, call=None): "ImageSource": image.ImageSource, "Platform": image.Platform, "Architecture": image.Architecture, - "ImageSize": "{}GB".format(image.ImageSize), + "ImageSize": f"{image.ImageSize}GB", "ImageState": image.ImageState, } @@ -893,7 +891,7 @@ def _get_node(name): ) time.sleep(0.5) - raise SaltCloudNotFound("Failed to get instance info {}".format(name)) + raise SaltCloudNotFound(f"Failed to get instance info {name}") def _get_nodes(): @@ -940,7 +938,7 @@ def _get_images(image_type): "ImageSource": image.ImageSource, "Platform": image.Platform, "Architecture": image.Architecture, - "ImageSize": "{}GB".format(image.ImageSize), + "ImageSize": f"{image.ImageSize}GB", } return ret @@ -958,9 +956,7 @@ def __get_image(vm_): if vm_image in images: return vm_image - raise SaltCloudNotFound( - "The specified image '{}' could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image '{vm_image}' could not be found.") def __get_size(vm_): @@ -975,9 +971,7 @@ def __get_size(vm_): if vm_size in sizes: return vm_size - raise SaltCloudNotFound( - "The specified size '{}' could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size '{vm_size}' could not be found.") def __get_securitygroups(vm_): diff --git a/salt/cloud/clouds/vagrant.py b/salt/cloud/clouds/vagrant.py index 836ea44badd..ac9119b70d9 100644 --- a/salt/cloud/clouds/vagrant.py +++ b/salt/cloud/clouds/vagrant.py @@ -256,7 +256,7 @@ def create(vm_): vm_.setdefault("ssh_port", ret["ssh_port"]) except (KeyError, TypeError): raise SaltInvocationError( - "Insufficient SSH addressing information for {}".format(name) + f"Insufficient SSH addressing information for {name}" ) log.info( @@ -300,7 +300,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], @@ -317,7 +317,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], @@ -328,11 +328,11 @@ def destroy(name, call=None): name, _get_active_provider_name().split(":")[0], opts ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} else: - return {"Error": "Error destroying {}".format(name)} + return {"Error": f"Error destroying {name}"} else: - return {"Error": "No response from {}. Cannot destroy.".format(name)} + return {"Error": f"No response from {name}. Cannot destroy."} # noinspection PyTypeChecker diff --git a/salt/cloud/clouds/virtualbox.py b/salt/cloud/clouds/virtualbox.py index 58b8ecd0242..0f7c169cef6 100644 --- a/salt/cloud/clouds/virtualbox.py +++ b/salt/cloud/clouds/virtualbox.py @@ -368,12 +368,12 @@ def destroy(name, call=None): """ log.info("Attempting to delete instance %s", name) if not vb_machine_exists(name): - return "{} doesn't exist and can't be deleted".format(name) + return f"{name} doesn't exist and can't be deleted" __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -384,7 +384,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index f6d8cbcef6c..91b1f1b3d25 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -306,7 +306,7 @@ def _add_new_hard_disk_helper( disk_spec.device.key = random_key disk_spec.device.deviceInfo = vim.Description() disk_spec.device.deviceInfo.label = disk_label - disk_spec.device.deviceInfo.summary = "{} GB".format(size_gb) + disk_spec.device.deviceInfo.summary = f"{size_gb} GB" disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() disk_spec.device.backing.thinProvisioned = thin_provision @@ -662,7 +662,7 @@ def _set_cd_or_dvd_backing_type(drive, device_type, mode, iso_path): if datastore_ref: drive.backing.datastore = datastore_ref - drive.deviceInfo.summary = "ISO {}".format(iso_path) + drive.deviceInfo.summary = f"ISO {iso_path}" elif device_type == "client_device": if mode == "passthrough": @@ -917,7 +917,7 @@ def _manage_devices(devices, vm=None, container_ref=None, new_vm_name=None): else None ) if bus_sharing and bus_sharing in ["virtual", "physical", "no"]: - bus_sharing = "{}Sharing".format(bus_sharing) + bus_sharing = f"{bus_sharing}Sharing" if bus_sharing != device.sharedBus: # Only edit the SCSI controller if bus_sharing is different scsi_spec = _edit_existing_scsi_controller( @@ -1327,7 +1327,7 @@ def _format_instance_info_select(vm, selection): if "size" in selection: cpu = defaultto(vm, "config.hardware.numCPU") ram = "{} MB".format(defaultto(vm, "config.hardware.memoryMB")) - vm_select_info["size"] = "cpu: {}\nram: {}".format(cpu, ram) + vm_select_info["size"] = f"cpu: {cpu}\nram: {ram}" vm_select_info["size_dict"] = { "cpu": cpu, "memory": ram, @@ -1610,7 +1610,7 @@ def _format_instance_info(vm): if "config.guestFullName" in vm else "N/A" ), - "size": "cpu: {}\nram: {}".format(cpu, ram), + "size": f"cpu: {cpu}\nram: {ram}", "size_dict": {"cpu": cpu, "memory": ram}, "state": ( str(vm["summary.runtime.powerState"]) @@ -1642,7 +1642,7 @@ def _format_instance_info(vm): def _get_snapshots(snapshot_list, current_snapshot=None, parent_snapshot_path=""): snapshots = {} for snapshot in snapshot_list: - snapshot_path = "{}/{}".format(parent_snapshot_path, snapshot.name) + snapshot_path = f"{parent_snapshot_path}/{snapshot.name}" snapshots[snapshot_path] = { "name": snapshot.name, "description": snapshot.description, @@ -1777,7 +1777,7 @@ def test_vcenter_connection(kwargs=None, call=None): # Get the service instance object _get_si() except Exception as exc: # pylint: disable=broad-except - return "failed to connect: {}".format(exc) + return f"failed to connect: {exc}" return "connection successful" @@ -2027,7 +2027,7 @@ def list_nodes(kwargs=None, call=None): if "config.guestFullName" in vm else "N/A" ), - "size": "cpu: {}\nram: {}".format(cpu, ram), + "size": f"cpu: {cpu}\nram: {ram}", "size_dict": {"cpu": cpu, "memory": ram}, "state": ( str(vm["summary.runtime.powerState"]) @@ -2684,7 +2684,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2730,7 +2730,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3135,7 +3135,7 @@ def create(vm_): ) if not datastore_ref: raise SaltCloudSystemExit( - "Specified datastore: '{}' does not exist".format(datastore) + f"Specified datastore: '{datastore}' does not exist" ) if host: @@ -3151,7 +3151,7 @@ def create(vm_): # If the hardware version is specified and if it is different from the current # hardware version, then schedule a hardware version upgrade if hardware_version and object_ref is not None: - hardware_version = "vmx-{:02}".format(hardware_version) + hardware_version = f"vmx-{hardware_version:02}" if hardware_version != object_ref.config.version: log.debug( "Scheduling hardware version upgrade from %s to %s", @@ -3181,7 +3181,7 @@ def create(vm_): elif memory_unit.lower() == "gb": memory_mb = int(float(memory_num) * 1024.0) else: - err_msg = "Invalid memory type specified: '{}'".format(memory_unit) + err_msg = f"Invalid memory type specified: '{memory_unit}'" log.error(err_msg) return {"Error": err_msg} except (TypeError, ValueError): @@ -3629,7 +3629,7 @@ def rescan_hba(kwargs=None, call=None): if hba: log.info("Rescanning HBA %s on host %s", hba, host_name) host_ref.configManager.storageSystem.RescanHba(hba) - ret = "rescanned HBA {}".format(hba) + ret = f"rescanned HBA {hba}" else: log.info("Rescanning all HBAs on host %s", host_name) host_ref.configManager.storageSystem.RescanAllHba() @@ -3907,7 +3907,7 @@ def list_hbas(kwargs=None, call=None): if hba_type and hba_type not in ["parallel", "block", "iscsi", "fibre"]: raise SaltCloudSystemExit( - "Specified hba type {} currently not supported.".format(hba_type) + f"Specified hba type {hba_type} currently not supported." ) host_list = salt.utils.vmware.get_mors_with_properties( @@ -4280,10 +4280,10 @@ def revert_to_snapshot(name, kwargs=None, call=None): task = vm_ref.RevertToCurrentSnapshot(suppressPowerOn=suppress_power_on) else: log.debug("Reverting VM %s to snapshot %s", name, snapshot_name) - msg = "reverted to snapshot {}".format(snapshot_name) + msg = f"reverted to snapshot {snapshot_name}" snapshot_ref = _get_snapshot_ref_by_name(vm_ref, snapshot_name) if snapshot_ref is None: - return "specified snapshot '{}' does not exist".format(snapshot_name) + return f"specified snapshot '{snapshot_name}' does not exist" task = snapshot_ref.snapshot.Revert(suppressPowerOn=suppress_power_on) salt.utils.vmware.wait_for_task(task, name, "revert to snapshot", 5, "info") @@ -4421,7 +4421,7 @@ def convert_to_template(name, kwargs=None, call=None): vm_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.VirtualMachine, name) if vm_ref.config.template: - raise SaltCloudSystemExit("{} already a template".format(name)) + raise SaltCloudSystemExit(f"{name} already a template") try: vm_ref.MarkAsTemplate() @@ -4435,7 +4435,7 @@ def convert_to_template(name, kwargs=None, call=None): ) return "failed to convert to teamplate" - return "{} converted to template".format(name) + return f"{name} converted to template" def add_host(kwargs=None, call=None): @@ -4557,7 +4557,7 @@ def add_host(kwargs=None, call=None): ("echo", "-n"), stdout=subprocess.PIPE, stderr=subprocess.PIPE ) p2 = subprocess.Popen( - ("openssl", "s_client", "-connect", "{}:443".format(host_name)), + ("openssl", "s_client", "-connect", f"{host_name}:443"), stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -4587,12 +4587,12 @@ def add_host(kwargs=None, call=None): try: if cluster_name: task = cluster_ref.AddHost(spec=spec, asConnected=True) - ret = "added host system to cluster {}".format(cluster_name) + ret = f"added host system to cluster {cluster_name}" if datacenter_name: task = datacenter_ref.hostFolder.AddStandaloneHost( spec=spec, addConnected=True ) - ret = "added host system to datacenter {}".format(datacenter_name) + ret = f"added host system to datacenter {datacenter_name}" salt.utils.vmware.wait_for_task(task, host_name, "add host system", 5, "info") except Exception as exc: # pylint: disable=broad-except if isinstance(exc, vim.fault.SSLVerifyFault): diff --git a/salt/cloud/clouds/xen.py b/salt/cloud/clouds/xen.py index 878f74f2a7a..810ff460227 100644 --- a/salt/cloud/clouds/xen.py +++ b/salt/cloud/clouds/xen.py @@ -124,7 +124,7 @@ def _get_session(): Get a connection to the XenServer host """ api_version = "1.0" - originator = "salt_cloud_{}_driver".format(__virtualname__) + originator = f"salt_cloud_{__virtualname__}_driver" url = config.get_cloud_config_value( "url", get_configured_provider(), __opts__, search_global=False ) @@ -550,7 +550,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args={"name": name, "profile": vm_["profile"], "provider": vm_["driver"]}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -580,7 +580,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) @@ -623,7 +623,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args={"name": name, "profile": vm_["profile"], "provider": vm_["driver"]}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -923,7 +923,7 @@ def reboot(name, call=None, session=None): _run_async_task(task, session) return show_instance(name) else: - return "{} is not running to be rebooted".format(name) + return f"{name} is not running to be rebooted" def _get_vm(name=None, session=None): @@ -984,7 +984,7 @@ def destroy(name=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1009,7 +1009,7 @@ def destroy(name=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1134,7 +1134,7 @@ def vif_list(name, call=None, kwargs=None): x = 0 for vif in vifs: vif_record = session.xenapi.VIF.get_record(vif) - data["vif-{}".format(x)] = vif_record + data[f"vif-{x}"] = vif_record x += 1 ret[name] = data return ret @@ -1168,7 +1168,7 @@ def vbd_list(name=None, call=None): x = 0 for vbd in vbds: vbd_record = session.xenapi.VBD.get_record(vbd) - data["vbd-{}".format(x)] = vbd_record + data[f"vbd-{x}"] = vbd_record x += 1 ret = data return ret @@ -1219,7 +1219,7 @@ def destroy_vm_vdis(name=None, session=None, call=None): vdi_record = session.xenapi.VDI.get_record(vbd_record["VDI"]) if "iso" not in vdi_record["name_label"]: session.xenapi.VDI.destroy(vbd_record["VDI"]) - ret["vdi-{}".format(x)] = vdi_record["name_label"] + ret[f"vdi-{x}"] = vdi_record["name_label"] x += 1 return ret diff --git a/salt/cloud/libcloudfuncs.py b/salt/cloud/libcloudfuncs.py index cee5ea724f9..2165e3ee442 100644 --- a/salt/cloud/libcloudfuncs.py +++ b/salt/cloud/libcloudfuncs.py @@ -61,7 +61,7 @@ def check_libcloud_version(reqver=LIBCLOUD_MINIMAL_VERSION, why=None): ) ) if why: - errormsg += " for {}".format(why) + errormsg += f" for {why}" errormsg += ". Please upgrade." raise ImportError(errormsg) @@ -186,7 +186,7 @@ def get_location(conn, vm_): return img raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -204,9 +204,7 @@ def get_image(conn, vm_): if vm_image and vm_image in (img_id, img_name): return img - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_size(conn, vm_): @@ -224,9 +222,7 @@ def get_size(conn, vm_): str(size.name), ): return size - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def script(vm_): @@ -257,7 +253,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -296,7 +292,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -338,8 +334,8 @@ def reboot(name, conn=None): # Fire reboot action __utils__["cloud.fire_event"]( "event", - "{} has been rebooted".format(name), - "salt/cloud/{}/rebooting".format(name), + f"{name} has been rebooted", + f"salt/cloud/{name}/rebooting", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/config/__init__.py b/salt/config/__init__.py index d94a690e8b9..a3e5a8bfdb7 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -2026,7 +2026,7 @@ def _read_conf_file(path): try: conf_opts = salt.utils.yaml.safe_load(conf_file) or {} except salt.utils.yaml.YAMLError as err: - message = "Error parsing configuration file: {} - {}".format(path, err) + message = f"Error parsing configuration file: {path} - {err}" log.error(message) if path.endswith("_schedule.conf"): # Create empty dictionary of config options @@ -2123,7 +2123,7 @@ def load_config(path, env_var, default_path=None, exit_on_config_errors=True): # If the configuration file is missing, attempt to copy the template, # after removing the first header line. if not os.path.isfile(path): - template = "{}.template".format(path) + template = f"{path}.template" if os.path.isfile(template): log.debug("Writing %s based on %s", path, template) with salt.utils.files.fopen(path, "w") as out: @@ -2800,7 +2800,7 @@ def apply_cloud_config(overrides, defaults=None): if alias not in config["providers"]: config["providers"][alias] = {} - detail["provider"] = "{}:{}".format(alias, driver) + detail["provider"] = f"{alias}:{driver}" config["providers"][alias][driver] = detail elif isinstance(details, dict): if "driver" not in details: @@ -2817,7 +2817,7 @@ def apply_cloud_config(overrides, defaults=None): if alias not in config["providers"]: config["providers"][alias] = {} - details["provider"] = "{}:{}".format(alias, driver) + details["provider"] = f"{alias}:{driver}" config["providers"][alias][driver] = details # Migrate old configuration @@ -3088,7 +3088,7 @@ def apply_cloud_providers_config(overrides, defaults=None): for entry in val: if "driver" not in entry: - entry["driver"] = "-only-extendable-{}".format(ext_count) + entry["driver"] = f"-only-extendable-{ext_count}" ext_count += 1 if key not in providers: @@ -3131,7 +3131,7 @@ def apply_cloud_providers_config(overrides, defaults=None): details["driver"], provider_alias, alias, provider ) ) - details["extends"] = "{}:{}".format(alias, provider) + details["extends"] = f"{alias}:{provider}" # change provider details '-only-extendable-' to extended # provider name details["driver"] = provider @@ -3152,10 +3152,10 @@ def apply_cloud_providers_config(overrides, defaults=None): ) else: if driver in providers.get(extends): - details["extends"] = "{}:{}".format(extends, driver) + details["extends"] = f"{extends}:{driver}" elif "-only-extendable-" in providers.get(extends): details["extends"] = "{}:{}".format( - extends, "-only-extendable-{}".format(ext_count) + extends, f"-only-extendable-{ext_count}" ) else: # We're still not aware of what we're trying to extend @@ -3869,7 +3869,7 @@ def _update_discovery_config(opts): for key in opts["discovery"]: if key not in discovery_config: raise salt.exceptions.SaltConfigurationError( - "Unknown discovery option: {}".format(key) + f"Unknown discovery option: {key}" ) if opts.get("__role") != "minion": for key in ["attempts", "pause", "match"]: diff --git a/salt/config/schemas/common.py b/salt/config/schemas/common.py index df136d537ea..d0ba546883d 100644 --- a/salt/config/schemas/common.py +++ b/salt/config/schemas/common.py @@ -25,7 +25,7 @@ class DefaultIncludeConfig(StringItem): description = __doc__ def __init__(self, default=None, pattern=None, **kwargs): - default = "{}/*.conf".format(self.__confd_directory__) + default = f"{self.__confd_directory__}/*.conf" pattern = r"(?:.*)/\*\.conf" super().__init__(default=default, pattern=pattern, **kwargs) diff --git a/salt/crypt.py b/salt/crypt.py index 5eba9ef5077..976cb027c92 100644 --- a/salt/crypt.py +++ b/salt/crypt.py @@ -128,8 +128,8 @@ def gen_keys(keydir, keyname, keysize, user=None, passphrase=None): :return: Path on the filesystem to the RSA private key """ base = os.path.join(keydir, keyname) - priv = "{}.pem".format(base) - pub = "{}.pub".format(base) + priv = f"{base}.pem" + pub = f"{base}.pub" if HAS_M2: gen = RSA.gen_key(keysize, 65537, lambda: None) @@ -449,7 +449,7 @@ class MasterKeys(dict): try: key = get_rsa_key(path, passphrase) except key_error as e: - message = "Unable to read key: {}; passphrase may be incorrect".format(path) + message = f"Unable to read key: {path}; passphrase may be incorrect" log.error(message) raise MasterExit(message) log.debug("Loaded %s key: %s", name, path) diff --git a/salt/daemons/__init__.py b/salt/daemons/__init__.py index f044f827b44..cb3b7c99c31 100644 --- a/salt/daemons/__init__.py +++ b/salt/daemons/__init__.py @@ -140,7 +140,7 @@ def extract_masters(opts, masters="master", port=None, raise_if_empty=True): entries = opts.get(masters, []) if not entries: - emsg = "Invalid or missing opts['{}'].".format(masters) + emsg = f"Invalid or missing opts['{masters}']." log.error(emsg) if raise_if_empty: raise ValueError(emsg) diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index 020bfb03198..82a3b1224aa 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -88,7 +88,7 @@ def clean_fsbackend(opts): # Clear remote fileserver backend caches so they get recreated for backend in ("git", "hg", "svn"): if backend in opts["fileserver_backend"]: - env_cache = os.path.join(opts["cachedir"], "{}fs".format(backend), "envs.p") + env_cache = os.path.join(opts["cachedir"], f"{backend}fs", "envs.p") if os.path.isfile(env_cache): log.debug("Clearing %sfs env cache", backend) try: @@ -99,7 +99,7 @@ def clean_fsbackend(opts): ) file_lists_dir = os.path.join( - opts["cachedir"], "file_lists", "{}fs".format(backend) + opts["cachedir"], "file_lists", f"{backend}fs" ) try: file_lists_caches = os.listdir(file_lists_dir) @@ -177,7 +177,7 @@ def mk_key(opts, user): opts["cachedir"], ".{}_key".format(user.replace("\\", "_")) ) else: - keyfile = os.path.join(opts["cachedir"], ".{}_key".format(user)) + keyfile = os.path.join(opts["cachedir"], f".{user}_key") if os.path.exists(keyfile): log.debug("Removing stale keyfile: %s", keyfile) @@ -589,7 +589,7 @@ class RemoteFuncs: minions = _res["minions"] minion_side_acl = {} # Cache minion-side ACL for minion in minions: - mine_data = self.cache.fetch("minions/{}".format(minion), "mine") + mine_data = self.cache.fetch(f"minions/{minion}", "mine") if not isinstance(mine_data, dict): continue for function in functions_allowed: @@ -616,7 +616,7 @@ class RemoteFuncs: continue salt.utils.dictupdate.set_dict_key_value( minion_side_acl, - "{}:{}".format(minion, function), + f"{minion}:{function}", get_minion, ) if salt.utils.mine.minion_side_acl_denied( @@ -1176,7 +1176,7 @@ class LocalFuncs: fun = load.pop("fun") tag = salt.utils.event.tagify(jid, prefix="wheel") data = { - "fun": "wheel.{}".format(fun), + "fun": f"wheel.{fun}", "jid": jid, "tag": tag, "user": username, @@ -1260,7 +1260,7 @@ class LocalFuncs: # Setup authorization list variable and error information auth_list = auth_check.get("auth_list", []) error = auth_check.get("error") - err_msg = 'Authentication failure of type "{}" occurred.'.format(auth_type) + err_msg = f'Authentication failure of type "{auth_type}" occurred.' if error: # Authentication error occurred: do not continue. diff --git a/salt/defaults/__init__.py b/salt/defaults/__init__.py index 35bdf162a02..5ebdb694a58 100644 --- a/salt/defaults/__init__.py +++ b/salt/defaults/__init__.py @@ -45,8 +45,8 @@ class _Constant: def __repr__(self): if self.value: - return "".format(self.name, self.value) - return "".format(self.name) + return f"" + return f"" # Default delimiter for multi-level traversal in targeting diff --git a/salt/engines/__init__.py b/salt/engines/__init__.py index d7dc6befa90..11baafb2b86 100644 --- a/salt/engines/__init__.py +++ b/salt/engines/__init__.py @@ -48,13 +48,13 @@ def start_engines(opts, proc_mgr, proxy=None): engine_name = engine del engine_opts["engine_module"] else: - fun = "{}.start".format(engine) + fun = f"{engine}.start" if fun in engines: start_func = engines[fun] if engine_name: - name = "Engine({}, name={})".format(start_func.__module__, engine_name) + name = f"Engine({start_func.__module__}, name={engine_name})" else: - name = "Engine({})".format(start_func.__module__) + name = f"Engine({start_func.__module__})" log.info("Starting %s", name) proc_mgr.add_process( Engine, diff --git a/salt/engines/ircbot.py b/salt/engines/ircbot.py index 1dab78dbbc5..8549caeb056 100644 --- a/salt/engines/ircbot.py +++ b/salt/engines/ircbot.py @@ -173,16 +173,16 @@ class IRCClient: event.source, nick, user, host, event.code, channel, command, line ) if (self._allow_nick(nick) or self._allow_host(host)) and hasattr( - self, "_command_{}".format(command) + self, f"_command_{command}" ): - getattr(self, "_command_{}".format(command))(privevent) + getattr(self, f"_command_{command}")(privevent) def _command_echo(self, event): - message = "PRIVMSG {} :{}".format(event.channel, event.line) + message = f"PRIVMSG {event.channel} :{event.line}" self.send_message(message) def _command_ping(self, event): - message = "PRIVMSG {} :{}: pong".format(event.channel, event.nick) + message = f"PRIVMSG {event.channel} :{event.nick}: pong" self.send_message(message) def _command_event(self, event): @@ -210,7 +210,7 @@ class IRCClient: payload = {"data": []} fire("salt/engines/ircbot/" + tag, payload) - message = "PRIVMSG {} :{}: TaDa!".format(event.channel, event.nick) + message = f"PRIVMSG {event.channel} :{event.nick}: TaDa!" self.send_message(message) def _message(self, raw): @@ -219,7 +219,7 @@ class IRCClient: if event.code == "PING": salt.ext.tornado.ioloop.IOLoop.current().spawn_callback( - self.send_message, "PONG {}".format(event.line) + self.send_message, f"PONG {event.line}" ) elif event.code == "PRIVMSG": salt.ext.tornado.ioloop.IOLoop.current().spawn_callback( @@ -230,13 +230,13 @@ class IRCClient: def join_channel(self, channel): if not channel.startswith("#"): channel = "#" + channel - self.send_message("JOIN {}".format(channel)) + self.send_message(f"JOIN {channel}") def on_connect(self): logging.info("on_connect") if self.sasl is True: self.send_message("CAP REQ :sasl") - self.send_message("NICK {}".format(self.nick)) + self.send_message(f"NICK {self.nick}") self.send_message("USER saltstack 0 * :saltstack") if self.password: if self.sasl is True: @@ -244,7 +244,7 @@ class IRCClient: "{0}\x00{0}\x00{1}".format(self.username, self.password).encode() ) self.send_message("AUTHENTICATE PLAIN") - self.send_message("AUTHENTICATE {}".format(authstring)) + self.send_message(f"AUTHENTICATE {authstring}") self.send_message("CAP END") else: self.send_message( diff --git a/salt/engines/libvirt_events.py b/salt/engines/libvirt_events.py index 3b77515f408..f09a298dc47 100644 --- a/salt/engines/libvirt_events.py +++ b/salt/engines/libvirt_events.py @@ -189,7 +189,7 @@ def _get_domain_event_detail(event, detail): if event_name == "unknown": return event_name, "unknown" - prefix = "VIR_DOMAIN_EVENT_{}_".format(event_name.upper()) + prefix = f"VIR_DOMAIN_EVENT_{event_name.upper()}_" detail_name = _get_libvirt_enum_string(prefix, detail) return event_name, detail_name @@ -333,9 +333,7 @@ def _domain_event_graphics_cb( transform address structure into event data piece """ return { - "family": _get_libvirt_enum_string( - "{}_ADDRESS_".format(prefix), addr["family"] - ), + "family": _get_libvirt_enum_string(f"{prefix}_ADDRESS_", addr["family"]), "node": addr["node"], "service": addr["service"], } @@ -680,14 +678,14 @@ def _register_callback(cnx, tag_prefix, obj, event, real_id): """ libvirt_name = real_id if real_id is None: - libvirt_name = "VIR_{}_EVENT_ID_{}".format(obj, event).upper() + libvirt_name = f"VIR_{obj}_EVENT_ID_{event}".upper() if not hasattr(libvirt, libvirt_name): log.warning('Skipping "%s/%s" events: libvirt too old', obj, event) return None libvirt_id = getattr(libvirt, libvirt_name) - callback_name = "_{}_event_{}_cb".format(obj, event) + callback_name = f"_{obj}_event_{event}_cb" callback = globals().get(callback_name, None) if callback is None: log.error("Missing function %s in engine", callback_name) diff --git a/salt/engines/napalm_syslog.py b/salt/engines/napalm_syslog.py index 3956a2836fd..e64f3c6b54b 100644 --- a/salt/engines/napalm_syslog.py +++ b/salt/engines/napalm_syslog.py @@ -209,7 +209,7 @@ def _zmq(address, port, **kwargs): socket = context.socket(zmq.SUB) if salt.utils.network.is_ipv6(address): socket.ipv6 = True - socket.connect("tcp://{addr}:{port}".format(addr=address, port=port)) + socket.connect(f"tcp://{address}:{port}") socket.setsockopt(zmq.SUBSCRIBE, b"") return socket.recv diff --git a/salt/engines/script.py b/salt/engines/script.py index 67277b14d5f..7b0e750d449 100644 --- a/salt/engines/script.py +++ b/salt/engines/script.py @@ -59,7 +59,7 @@ def _get_serializer(output): return getattr(serializers, output) except AttributeError: raise CommandExecutionError( - "Unknown serializer `{}` found for output option".format(output) + f"Unknown serializer `{output}` found for output option" ) diff --git a/salt/engines/slack.py b/salt/engines/slack.py index 93f75f8cd4e..27351d0fe4c 100644 --- a/salt/engines/slack.py +++ b/salt/engines/slack.py @@ -747,7 +747,7 @@ class SlackClient: results = {} for jid in outstanding_jids: # results[jid] = runner.cmd('jobs.lookup_jid', [jid]) - if self.master_minion.returners["{}.get_jid".format(source)](jid): + if self.master_minion.returners[f"{source}.get_jid"](jid): job_result = runner.cmd("jobs.list_job", [jid]) jid_result = job_result.get("Result", {}) jid_function = job_result.get("Function", {}) @@ -838,7 +838,7 @@ class SlackClient: channel.send_message(return_prefix) ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime("%Y%m%d%H%M%S%f") - filename = "salt-results-{}.yaml".format(st) + filename = f"salt-results-{st}.yaml" r = self.sc.api_call( "files.upload", channels=channel.id, @@ -944,4 +944,4 @@ def start( ) client.run_commands_from_slack_async(message_generator, fire_all, tag, control) except Exception: # pylint: disable=broad-except - raise Exception("{}".format(traceback.format_exc())) + raise Exception(f"{traceback.format_exc()}") diff --git a/salt/exceptions.py b/salt/exceptions.py index e351584bc03..57a6175de2d 100644 --- a/salt/exceptions.py +++ b/salt/exceptions.py @@ -284,7 +284,7 @@ class SaltRenderError(SaltException): self.buffer = buf self.context = "" if trace: - exc_str += "\n{}\n".format(trace) + exc_str += f"\n{trace}\n" if self.line_num and self.buffer: # Avoid circular import import salt.utils.templates diff --git a/salt/executors/docker.py b/salt/executors/docker.py index ebecae60c97..8c08fcf7ce0 100644 --- a/salt/executors/docker.py +++ b/salt/executors/docker.py @@ -22,7 +22,7 @@ def __virtual__(): "Docker executor is only meant to be used with Docker Proxy Minions", ) if __opts__.get("proxy", {}).get("proxytype") != __virtualname__: - return False, "Proxytype does not match: {}".format(__virtualname__) + return False, f"Proxytype does not match: {__virtualname__}" return True diff --git a/salt/executors/sudo.py b/salt/executors/sudo.py index 4d5a2fd71aa..799e77f5486 100644 --- a/salt/executors/sudo.py +++ b/salt/executors/sudo.py @@ -64,7 +64,7 @@ def execute(opts, data, func, args, kwargs): for arg in args: cmd.append(shlex.quote(str(arg))) for key in kwargs: - cmd.append(shlex.quote("{}={}".format(key, kwargs[key]))) + cmd.append(shlex.quote(f"{key}={kwargs[key]}")) cmd_ret = __salt__["cmd.run_all"](cmd, use_vt=True, python_shell=False) diff --git a/salt/fileclient.py b/salt/fileclient.py index 77e107830dd..fad1da72ece 100644 --- a/salt/fileclient.py +++ b/salt/fileclient.py @@ -107,7 +107,7 @@ class Client: Make sure that this path is intended for the salt master and trim it """ if not path.startswith("salt://"): - raise MinionError("Unsupported path: {}".format(path)) + raise MinionError(f"Unsupported path: {path}") file_path, saltenv = salt.utils.url.parse(path) return file_path @@ -273,7 +273,7 @@ class Client: for fn_ in self.file_list_emptydirs(saltenv): fn_ = salt.utils.data.decode(fn_) if fn_.startswith(path): - minion_dir = "{}/{}".format(dest, fn_) + minion_dir = f"{dest}/{fn_}" if not os.path.isdir(minion_dir): os.makedirs(minion_dir) ret.append(minion_dir) @@ -438,7 +438,7 @@ class Client: ret.append( self.get_file( salt.utils.url.create(fn_), - "{}/{}".format(dest, minion_relpath), + f"{dest}/{minion_relpath}", True, saltenv, gzip, @@ -457,7 +457,7 @@ class Client: # Remove the leading directories from path to derive # the relative path on the minion. minion_relpath = fn_[len(prefix) :].lstrip("/") - minion_mkdir = "{}/{}".format(dest, minion_relpath) + minion_mkdir = f"{dest}/{minion_relpath}" if not os.path.isdir(minion_mkdir): os.makedirs(minion_mkdir) ret.append(minion_mkdir) @@ -508,9 +508,7 @@ class Client: if url_scheme in ("file", ""): # Local filesystem if not os.path.isabs(url_path): - raise CommandExecutionError( - "Path '{}' is not absolute".format(url_path) - ) + raise CommandExecutionError(f"Path '{url_path}' is not absolute") if dest is None: with salt.utils.files.fopen(url_path, "rb") as fp_: data = fp_.read() @@ -584,9 +582,7 @@ class Client: ) return dest except Exception as exc: # pylint: disable=broad-except - raise MinionError( - "Could not fetch from {}. Exception: {}".format(url, exc) - ) + raise MinionError(f"Could not fetch from {url}. Exception: {exc}") if url_data.scheme == "ftp": try: ftp = ftplib.FTP() # nosec @@ -597,7 +593,7 @@ class Client: ftp.login(url_data.username, url_data.password) remote_file_path = url_data.path.lstrip("/") with salt.utils.files.fopen(dest, "wb") as fp_: - ftp.retrbinary("RETR {}".format(remote_file_path), fp_.write) + ftp.retrbinary(f"RETR {remote_file_path}", fp_.write) ftp.quit() return dest except Exception as exc: # pylint: disable=broad-except @@ -631,7 +627,7 @@ class Client: swift_conn.get_object(url_data.netloc, url_data.path[1:], dest) return dest except Exception: # pylint: disable=broad-except - raise MinionError("Could not fetch from {}".format(url)) + raise MinionError(f"Could not fetch from {url}") get_kwargs = {} if url_data.username is not None and url_data.scheme in ("http", "https"): @@ -654,7 +650,7 @@ class Client: fixed_url = url destfp = None - dest_etag = "{}.etag".format(dest) + dest_etag = f"{dest}.etag" try: # Tornado calls streaming_callback on redirect response bodies. # But we need streaming to support fetching large files (> RAM @@ -768,7 +764,7 @@ class Client: result.append(chunk) else: - dest_tmp = "{}.part".format(dest) + dest_tmp = f"{dest}.part" # We need an open filehandle to use in the on_chunk callback, # that's why we're not using a with clause here. # pylint: disable=resource-leakage @@ -830,7 +826,7 @@ class Client: ) ) except urllib.error.URLError as exc: - raise MinionError("Error reading {}: {}".format(url, exc.reason)) + raise MinionError(f"Error reading {url}: {exc.reason}") finally: if destfp is not None: destfp.close() diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py index f6a1c6cdc8b..fe4b3b8e496 100644 --- a/salt/fileserver/__init__.py +++ b/salt/fileserver/__init__.py @@ -320,9 +320,9 @@ def clear_lock(clear_func, role, remote=None, lock_type="update"): Returns the return data from ``clear_func``. """ - msg = "Clearing {} lock for {} remotes".format(lock_type, role) + msg = f"Clearing {lock_type} lock for {role} remotes" if remote: - msg += " matching {}".format(remote) + msg += f" matching {remote}" log.debug(msg) return clear_func(remote=remote, lock_type=lock_type) @@ -375,12 +375,12 @@ class Fileserver: # Only subtracting backends from enabled ones ret = self.opts["fileserver_backend"] for sub in back: - if "{}.envs".format(sub[1:]) in server_funcs: + if f"{sub[1:]}.envs" in server_funcs: ret.remove(sub[1:]) return ret for sub in back: - if "{}.envs".format(sub) in server_funcs: + if f"{sub}.envs" in server_funcs: ret.append(sub) return ret @@ -408,7 +408,7 @@ class Fileserver: cleared = [] errors = [] for fsb in back: - fstr = "{}.clear_cache".format(fsb) + fstr = f"{fsb}.clear_cache" if fstr in self.servers: log.debug("Clearing %s fileserver cache", fsb) failed = self.servers[fstr]() @@ -416,7 +416,7 @@ class Fileserver: errors.extend(failed) else: cleared.append( - "The {} fileserver cache was successfully cleared".format(fsb) + f"The {fsb} fileserver cache was successfully cleared" ) return cleared, errors @@ -430,17 +430,15 @@ class Fileserver: locked = [] errors = [] for fsb in back: - fstr = "{}.lock".format(fsb) + fstr = f"{fsb}.lock" if fstr in self.servers: - msg = "Setting update lock for {} remotes".format(fsb) + msg = f"Setting update lock for {fsb} remotes" if remote: if not isinstance(remote, str): - errors.append( - "Badly formatted remote pattern '{}'".format(remote) - ) + errors.append(f"Badly formatted remote pattern '{remote}'") continue else: - msg += " matching {}".format(remote) + msg += f" matching {remote}" log.debug(msg) good, bad = self.servers[fstr](remote=remote) locked.extend(good) @@ -463,7 +461,7 @@ class Fileserver: cleared = [] errors = [] for fsb in back: - fstr = "{}.clear_lock".format(fsb) + fstr = f"{fsb}.clear_lock" if fstr in self.servers: good, bad = clear_lock(self.servers[fstr], fsb, remote=remote) cleared.extend(good) @@ -477,7 +475,7 @@ class Fileserver: """ back = self.backends(back) for fsb in back: - fstr = "{}.update".format(fsb) + fstr = f"{fsb}.update" if fstr in self.servers: log.debug("Updating %s fileserver cache", fsb) self.servers[fstr](**kwargs) @@ -490,7 +488,7 @@ class Fileserver: back = self.backends(back) ret = {} for fsb in back: - fstr = "{}.update_intervals".format(fsb) + fstr = f"{fsb}.update_intervals" if fstr in self.servers: ret[fsb] = self.servers[fstr]() return ret @@ -504,7 +502,7 @@ class Fileserver: if sources: ret = {} for fsb in back: - fstr = "{}.envs".format(fsb) + fstr = f"{fsb}.envs" kwargs = ( {"ignore_cache": True} if "ignore_cache" in _argspec(self.servers[fstr]).args @@ -534,7 +532,7 @@ class Fileserver: """ back = self.backends(back) for fsb in back: - fstr = "{}.init".format(fsb) + fstr = f"{fsb}.init" if fstr in self.servers: self.servers[fstr]() @@ -596,7 +594,7 @@ class Fileserver: saltenv = str(saltenv) for fsb in back: - fstr = "{}.find_file".format(fsb) + fstr = f"{fsb}.find_file" if fstr in self.servers: fnd = self.servers[fstr](path, saltenv, **kwargs) if fnd.get("path"): @@ -766,7 +764,7 @@ class Fileserver: load["saltenv"] = str(load["saltenv"]) for fsb in self.backends(load.pop("fsbackend", None)): - fstr = "{}.file_list".format(fsb) + fstr = f"{fsb}.file_list" if fstr in self.servers: ret.update(self.servers[fstr](load)) # some *fs do not handle prefix. Ensure it is filtered @@ -791,7 +789,7 @@ class Fileserver: load["saltenv"] = str(load["saltenv"]) for fsb in self.backends(None): - fstr = "{}.file_list_emptydirs".format(fsb) + fstr = f"{fsb}.file_list_emptydirs" if fstr in self.servers: ret.update(self.servers[fstr](load)) # some *fs do not handle prefix. Ensure it is filtered @@ -816,7 +814,7 @@ class Fileserver: load["saltenv"] = str(load["saltenv"]) for fsb in self.backends(load.pop("fsbackend", None)): - fstr = "{}.dir_list".format(fsb) + fstr = f"{fsb}.dir_list" if fstr in self.servers: ret.update(self.servers[fstr](load)) # some *fs do not handle prefix. Ensure it is filtered @@ -841,7 +839,7 @@ class Fileserver: load["saltenv"] = str(load["saltenv"]) for fsb in self.backends(load.pop("fsbackend", None)): - symlstr = "{}.symlink_list".format(fsb) + symlstr = f"{fsb}.symlink_list" if symlstr in self.servers: ret = self.servers[symlstr](load) # some *fs do not handle prefix. Ensure it is filtered diff --git a/salt/fileserver/hgfs.py b/salt/fileserver/hgfs.py index c2c9f93ac5c..48d17557886 100644 --- a/salt/fileserver/hgfs.py +++ b/salt/fileserver/hgfs.py @@ -239,7 +239,7 @@ def init(): per_remote_defaults = {} for param in PER_REMOTE_OVERRIDES: - per_remote_defaults[param] = str(__opts__["hgfs_{}".format(param)]) + per_remote_defaults[param] = str(__opts__[f"hgfs_{param}"]) for remote in __opts__["hgfs_remotes"]: repo_conf = copy.deepcopy(per_remote_defaults) @@ -355,7 +355,7 @@ def init(): with salt.utils.files.fopen(hgconfpath, "w+") as hgconfig: hgconfig.write("[paths]\n") hgconfig.write( - salt.utils.stringutils.to_str("default = {}\n".format(repo_url)) + salt.utils.stringutils.to_str(f"default = {repo_url}\n") ) repo_conf.update( @@ -365,7 +365,7 @@ def init(): "hash": repo_hash, "cachedir": rp_, "lockfile": os.path.join( - __opts__["cachedir"], "hgfs", "{}.update.lk".format(repo_hash) + __opts__["cachedir"], "hgfs", f"{repo_hash}.update.lk" ), } ) @@ -379,7 +379,7 @@ def init(): try: with salt.utils.files.fopen(remote_map, "w+") as fp_: timestamp = datetime.now().strftime("%d %b %Y %H:%M:%S.%f") - fp_.write("# hgfs_remote map as of {}\n".format(timestamp)) + fp_.write(f"# hgfs_remote map as of {timestamp}\n") for repo in repos: fp_.write( salt.utils.stringutils.to_str( @@ -444,7 +444,7 @@ def clear_cache(): try: shutil.rmtree(rdir) except OSError as exc: - errors.append("Unable to delete {}: {}".format(rdir, exc)) + errors.append(f"Unable to delete {rdir}: {exc}") return errors @@ -694,14 +694,12 @@ def find_file(path, tgt_env="base", **kwargs): # pylint: disable=W0613 dest = os.path.join(__opts__["cachedir"], "hgfs/refs", tgt_env, path) hashes_glob = os.path.join( - __opts__["cachedir"], "hgfs/hash", tgt_env, "{}.hash.*".format(path) + __opts__["cachedir"], "hgfs/hash", tgt_env, f"{path}.hash.*" ) blobshadest = os.path.join( - __opts__["cachedir"], "hgfs/hash", tgt_env, "{}.hash.blob_sha1".format(path) - ) - lk_fn = os.path.join( - __opts__["cachedir"], "hgfs/hash", tgt_env, "{}.lk".format(path) + __opts__["cachedir"], "hgfs/hash", tgt_env, f"{path}.hash.blob_sha1" ) + lk_fn = os.path.join(__opts__["cachedir"], "hgfs/hash", tgt_env, f"{path}.lk") destdir = os.path.dirname(dest) hashdir = os.path.dirname(blobshadest) if not os.path.isdir(destdir): @@ -746,7 +744,7 @@ def find_file(path, tgt_env="base", **kwargs): # pylint: disable=W0613 return fnd try: repo["repo"].cat( - [salt.utils.stringutils.to_bytes("path:{}".format(repo_path))], + [salt.utils.stringutils.to_bytes(f"path:{repo_path}")], rev=ref[2], output=dest, ) diff --git a/salt/fileserver/roots.py b/salt/fileserver/roots.py index c79da1a616b..91536d737ce 100644 --- a/salt/fileserver/roots.py +++ b/salt/fileserver/roots.py @@ -219,9 +219,7 @@ def update(): os.makedirs(mtime_map_path_dir) with salt.utils.files.fopen(mtime_map_path, "wb") as fp_: for file_path, mtime in new_mtime_map.items(): - fp_.write( - salt.utils.stringutils.to_bytes("{}:{}\n".format(file_path, mtime)) - ) + fp_.write(salt.utils.stringutils.to_bytes(f"{file_path}:{mtime}\n")) if __opts__.get("fileserver_events", False): # if there is a change, fire an event @@ -349,11 +347,11 @@ def _file_lists(load, form): return [] list_cache = os.path.join( list_cachedir, - "{}.p".format(salt.utils.files.safe_filename_leaf(actual_saltenv)), + f"{salt.utils.files.safe_filename_leaf(actual_saltenv)}.p", ) w_lock = os.path.join( list_cachedir, - ".{}.w".format(salt.utils.files.safe_filename_leaf(actual_saltenv)), + f".{salt.utils.files.safe_filename_leaf(actual_saltenv)}.w", ) cache_match, refresh_cache, save_cache = salt.fileserver.check_file_list_cache( __opts__, form, list_cache, w_lock diff --git a/salt/fileserver/svnfs.py b/salt/fileserver/svnfs.py index b8582ff716c..8e13ec99353 100644 --- a/salt/fileserver/svnfs.py +++ b/salt/fileserver/svnfs.py @@ -136,7 +136,7 @@ def init(): per_remote_defaults = {} for param in PER_REMOTE_OVERRIDES: - per_remote_defaults[param] = str(__opts__["svnfs_{}".format(param)]) + per_remote_defaults[param] = str(__opts__[f"svnfs_{param}"]) for remote in __opts__["svnfs_remotes"]: repo_conf = copy.deepcopy(per_remote_defaults) @@ -239,7 +239,7 @@ def init(): try: with salt.utils.files.fopen(remote_map, "w+") as fp_: timestamp = datetime.now().strftime("%d %b %Y %H:%M:%S.%f") - fp_.write("# svnfs_remote map as of {}\n".format(timestamp)) + fp_.write(f"# svnfs_remote map as of {timestamp}\n") for repo_conf in repos: fp_.write( salt.utils.stringutils.to_str( @@ -306,7 +306,7 @@ def clear_cache(): try: shutil.rmtree(rdir) except OSError as exc: - errors.append("Unable to delete {}: {}".format(rdir, exc)) + errors.append(f"Unable to delete {rdir}: {exc}") return errors diff --git a/salt/grains/core.py b/salt/grains/core.py index 8dbcec294a5..17a1d683eef 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -289,7 +289,7 @@ def _linux_gpu_data(): devs = [] try: - lspci_out = __salt__["cmd.run"]("{} -vmm".format(lspci)) + lspci_out = __salt__["cmd.run"](f"{lspci} -vmm") cur_dev = {} error = False @@ -363,7 +363,7 @@ def _netbsd_gpu_data(): for line in pcictl_out.splitlines(): for vendor in known_vendors: vendor_match = re.match( - r"[0-9:]+ ({}) (.+) \(VGA .+\)".format(vendor), line, re.IGNORECASE + rf"[0-9:]+ ({vendor}) (.+) \(VGA .+\)", line, re.IGNORECASE ) if vendor_match: gpus.append( @@ -425,18 +425,18 @@ def _bsd_cpudata(osdata): if sysctl: cmds.update( { - "num_cpus": "{} -n hw.ncpu".format(sysctl), - "cpuarch": "{} -n hw.machine".format(sysctl), - "cpu_model": "{} -n hw.model".format(sysctl), + "num_cpus": f"{sysctl} -n hw.ncpu", + "cpuarch": f"{sysctl} -n hw.machine", + "cpu_model": f"{sysctl} -n hw.model", } ) if arch and osdata["kernel"] == "OpenBSD": - cmds["cpuarch"] = "{} -s".format(arch) + cmds["cpuarch"] = f"{arch} -s" if osdata["kernel"] == "Darwin": - cmds["cpu_model"] = "{} -n machdep.cpu.brand_string".format(sysctl) - cmds["cpu_flags"] = "{} -n machdep.cpu.features".format(sysctl) + cmds["cpu_model"] = f"{sysctl} -n machdep.cpu.brand_string" + cmds["cpu_flags"] = f"{sysctl} -n machdep.cpu.features" grains = {k: __salt__["cmd.run"](v) for k, v in cmds.items()} @@ -521,7 +521,7 @@ def _aix_cpudata(): # pragma: no cover grains = {} cmd = salt.utils.path.which("prtconf") if cmd: - data = __salt__["cmd.run"]("{}".format(cmd)) + os.linesep + data = __salt__["cmd.run"](f"{cmd}") + os.linesep for dest, regstring in ( ("cpuarch", r"(?im)^\s*Processor\s+Type:\s+(\S+)"), ("cpu_flags", r"(?im)^\s*Processor\s+Version:\s+(\S+)"), @@ -567,9 +567,9 @@ def _osx_memdata(): sysctl = salt.utils.path.which("sysctl") if sysctl: - mem = __salt__["cmd.run"]("{} -n hw.memsize".format(sysctl)) + mem = __salt__["cmd.run"](f"{sysctl} -n hw.memsize") swap_total = ( - __salt__["cmd.run"]("{} -n vm.swapusage".format(sysctl)) + __salt__["cmd.run"](f"{sysctl} -n vm.swapusage") .split()[2] .replace(",", ".") ) @@ -594,20 +594,20 @@ def _bsd_memdata(osdata): sysctl = salt.utils.path.which("sysctl") if sysctl: - mem = __salt__["cmd.run"]("{} -n hw.physmem".format(sysctl)) + mem = __salt__["cmd.run"](f"{sysctl} -n hw.physmem") if osdata["kernel"] == "NetBSD" and mem.startswith("-"): - mem = __salt__["cmd.run"]("{} -n hw.physmem64".format(sysctl)) + mem = __salt__["cmd.run"](f"{sysctl} -n hw.physmem64") grains["mem_total"] = int(mem) // 1024 // 1024 if osdata["kernel"] in ["OpenBSD", "NetBSD"]: swapctl = salt.utils.path.which("swapctl") - swap_data = __salt__["cmd.run"]("{} -sk".format(swapctl)) + swap_data = __salt__["cmd.run"](f"{swapctl} -sk") if swap_data == "no swap devices configured": swap_total = 0 else: swap_total = swap_data.split(" ")[1] else: - swap_total = __salt__["cmd.run"]("{} -n vm.swap_total".format(sysctl)) + swap_total = __salt__["cmd.run"](f"{sysctl} -n vm.swap_total") grains["swap_total"] = int(swap_total) // 1024 // 1024 return grains @@ -625,7 +625,7 @@ def _sunos_memdata(): # pragma: no cover grains["mem_total"] = int(comps[2].strip()) swap_cmd = salt.utils.path.which("swap") - swap_data = __salt__["cmd.run"]("{} -s".format(swap_cmd)).split() + swap_data = __salt__["cmd.run"](f"{swap_cmd} -s").split() try: swap_avail = int(swap_data[-2][:-1]) swap_used = int(swap_data[-4][:-1]) @@ -653,7 +653,7 @@ def _aix_memdata(): # pragma: no cover swap_cmd = salt.utils.path.which("swap") if swap_cmd: - swap_data = __salt__["cmd.run"]("{} -s".format(swap_cmd)).split() + swap_data = __salt__["cmd.run"](f"{swap_cmd} -s").split() try: swap_total = (int(swap_data[-2]) + int(swap_data[-6])) * 4 except ValueError: @@ -706,7 +706,7 @@ def _aix_get_machine_id(): # pragma: no cover grains = {} cmd = salt.utils.path.which("lsattr") if cmd: - data = __salt__["cmd.run"]("{} -El sys0".format(cmd)) + os.linesep + data = __salt__["cmd.run"](f"{cmd} -El sys0") + os.linesep uuid_regexes = [re.compile(r"(?im)^\s*os_uuid\s+(\S+)\s+(.*)")] for regex in uuid_regexes: res = regex.search(data) @@ -1033,7 +1033,7 @@ def _virtual(osdata): subtype_cmd = "{} -c current get -H -o value {}-role".format( command, role ) - ret = __salt__["cmd.run"]("{}".format(subtype_cmd)) + ret = __salt__["cmd.run"](f"{subtype_cmd}") if ret == "true": roles.append(role) if roles: @@ -1179,14 +1179,14 @@ def _virtual(osdata): elif osdata["kernel"] == "FreeBSD": kenv = salt.utils.path.which("kenv") if kenv: - product = __salt__["cmd.run"]("{} smbios.system.product".format(kenv)) - maker = __salt__["cmd.run"]("{} smbios.system.maker".format(kenv)) + product = __salt__["cmd.run"](f"{kenv} smbios.system.product") + maker = __salt__["cmd.run"](f"{kenv} smbios.system.maker") if product.startswith("VMware"): grains["virtual"] = "VMware" if product.startswith("VirtualBox"): grains["virtual"] = "VirtualBox" if maker.startswith("Xen"): - grains["virtual_subtype"] = "{} {}".format(maker, product) + grains["virtual_subtype"] = f"{maker} {product}" grains["virtual"] = "xen" if maker.startswith("Microsoft") and product.startswith("Virtual"): grains["virtual"] = "VirtualPC" @@ -1197,9 +1197,9 @@ def _virtual(osdata): if maker.startswith("Amazon EC2"): grains["virtual"] = "Nitro" if sysctl: - hv_vendor = __salt__["cmd.run"]("{} -n hw.hv_vendor".format(sysctl)) - model = __salt__["cmd.run"]("{} -n hw.model".format(sysctl)) - jail = __salt__["cmd.run"]("{} -n security.jail.jailed".format(sysctl)) + hv_vendor = __salt__["cmd.run"](f"{sysctl} -n hw.hv_vendor") + model = __salt__["cmd.run"](f"{sysctl} -n hw.model") + jail = __salt__["cmd.run"](f"{sysctl} -n security.jail.jailed") if "bhyve" in hv_vendor: grains["virtual"] = "bhyve" elif "QEMU Virtual CPU" in model: @@ -1215,22 +1215,19 @@ def _virtual(osdata): elif osdata["kernel"] == "NetBSD": if sysctl: if "QEMU Virtual CPU" in __salt__["cmd.run"]( - "{} -n machdep.cpu_brand".format(sysctl) + f"{sysctl} -n machdep.cpu_brand" ): grains["virtual"] = "kvm" elif "invalid" not in __salt__["cmd.run"]( - "{} -n machdep.xen.suspend".format(sysctl) + f"{sysctl} -n machdep.xen.suspend" ): grains["virtual"] = "Xen PV DomU" elif "VMware" in __salt__["cmd.run"]( - "{} -n machdep.dmi.system-vendor".format(sysctl) + f"{sysctl} -n machdep.dmi.system-vendor" ): grains["virtual"] = "VMware" # NetBSD has Xen dom0 support - elif ( - __salt__["cmd.run"]("{} -n machdep.idle-mechanism".format(sysctl)) - == "xen" - ): + elif __salt__["cmd.run"](f"{sysctl} -n machdep.idle-mechanism") == "xen": if os.path.isfile("/var/run/xenconsoled.pid"): grains["virtual_subtype"] = "Xen Dom0" elif osdata["kernel"] == "SunOS": @@ -1238,7 +1235,7 @@ def _virtual(osdata): # check the zonename here as fallback zonename = salt.utils.path.which("zonename") if zonename: - zone = __salt__["cmd.run"]("{}".format(zonename)) + zone = __salt__["cmd.run"](f"{zonename}") if zone != "global": grains["virtual"] = "zone" @@ -1267,7 +1264,7 @@ def _virtual(osdata): r".*Product Name: ([^\r\n]*).*", output, flags=re.DOTALL ) if product: - grains["virtual_subtype"] = "Amazon EC2 ({})".format(product[1]) + grains["virtual_subtype"] = f"Amazon EC2 ({product[1]})" elif re.match(r".*Version: [^\r\n]+\.amazon.*", output, flags=re.DOTALL): grains["virtual_subtype"] = "Amazon EC2" @@ -1299,9 +1296,7 @@ def _virtual_hv(osdata): try: version = {} for fn in ("major", "minor", "extra"): - with salt.utils.files.fopen( - "/sys/hypervisor/version/{}".format(fn), "r" - ) as fhr: + with salt.utils.files.fopen(f"/sys/hypervisor/version/{fn}", "r") as fhr: version[fn] = salt.utils.stringutils.to_unicode(fhr.read().strip()) grains["virtual_hv_version"] = "{}.{}{}".format( version["major"], version["minor"], version["extra"] @@ -1457,7 +1452,7 @@ def _windows_os_release_grain(caption, product_type): # ie: R2 if re.match(r"^R\d+$", item): release = item - os_release = "{}Server{}".format(version, release) + os_release = f"{version}Server{release}" else: for item in caption.split(" "): # If it's a number, decimal number, Thin or Vista, then it's the @@ -1703,7 +1698,7 @@ def _linux_devicetree_platform_data(): try: # /proc/device-tree should be used instead of /sys/firmware/devicetree/base # see https://github.com/torvalds/linux/blob/v5.13/Documentation/ABI/testing/sysfs-firmware-ofw#L14 - loc = "/proc/device-tree/{}".format(path) + loc = f"/proc/device-tree/{path}" if os.path.isfile(loc): with salt.utils.files.fopen(loc, mode="r") as f: return f.read().rstrip("\x00") # all strings are null-terminated @@ -1942,18 +1937,13 @@ def _linux_bin_exists(binary): """ for search_cmd in ("which", "type -ap"): try: - return __salt__["cmd.retcode"]("{} {}".format(search_cmd, binary)) == 0 + return __salt__["cmd.retcode"](f"{search_cmd} {binary}") == 0 except salt.exceptions.CommandExecutionError: pass try: return ( - len( - __salt__["cmd.run_all"]("whereis -b {}".format(binary))[ - "stdout" - ].split() - ) - > 1 + len(__salt__["cmd.run_all"](f"whereis -b {binary}")["stdout"].split()) > 1 ) except salt.exceptions.CommandExecutionError: return False @@ -1971,7 +1961,7 @@ def _parse_lsb_release(): pass else: # Adds lsb_distrib_{id,release,codename,description} - ret["lsb_{}".format(key.lower())] = value.rstrip() + ret[f"lsb_{key.lower()}"] = value.rstrip() except OSError as exc: log.trace("Failed to parse /etc/lsb-release: %s", exc) return ret @@ -2716,7 +2706,7 @@ def os_data(): osbuild = __salt__["cmd.run"]("sw_vers -buildVersion") grains["os"] = "MacOS" grains["os_family"] = "MacOS" - grains["osfullname"] = "{} {}".format(osname, osrelease) + grains["osfullname"] = f"{osname} {osrelease}" grains["osrelease"] = osrelease grains["osbuild"] = osbuild grains["init"] = "launchd" @@ -3257,7 +3247,7 @@ def _hw_data(osdata): "productname": "DeviceDesc", } for grain_name, cmd_key in hwdata.items(): - result = __salt__["cmd.run_all"]("fw_printenv {}".format(cmd_key)) + result = __salt__["cmd.run_all"](f"fw_printenv {cmd_key}") if result["retcode"] == 0: uboot_keyval = result["stdout"].split("=") grains[grain_name] = _clean_value(grain_name, uboot_keyval[1]) @@ -3277,7 +3267,7 @@ def _hw_data(osdata): "uuid": "smbios.system.uuid", } for key, val in fbsd_hwdata.items(): - value = __salt__["cmd.run"]("{} {}".format(kenv, val)) + value = __salt__["cmd.run"](f"{kenv} {val}") grains[key] = _clean_value(key, value) elif osdata["kernel"] == "OpenBSD": sysctl = salt.utils.path.which("sysctl") @@ -3289,7 +3279,7 @@ def _hw_data(osdata): "uuid": "hw.uuid", } for key, oid in hwdata.items(): - value = __salt__["cmd.run"]("{} -n {}".format(sysctl, oid)) + value = __salt__["cmd.run"](f"{sysctl} -n {oid}") if not value.endswith(" value is not available"): grains[key] = _clean_value(key, value) elif osdata["kernel"] == "NetBSD": @@ -3304,7 +3294,7 @@ def _hw_data(osdata): "uuid": "machdep.dmi.system-uuid", } for key, oid in nbsd_hwdata.items(): - result = __salt__["cmd.run_all"]("{} -n {}".format(sysctl, oid)) + result = __salt__["cmd.run_all"](f"{sysctl} -n {oid}") if result["retcode"] == 0: grains[key] = _clean_value(key, result["stdout"]) elif osdata["kernel"] == "Darwin": @@ -3312,7 +3302,7 @@ def _hw_data(osdata): sysctl = salt.utils.path.which("sysctl") hwdata = {"productname": "hw.model"} for key, oid in hwdata.items(): - value = __salt__["cmd.run"]("{} -b {}".format(sysctl, oid)) + value = __salt__["cmd.run"](f"{sysctl} -b {oid}") if not value.endswith(" is invalid"): grains[key] = _clean_value(key, value) elif osdata["kernel"] == "SunOS" and osdata["cpuarch"].startswith("sparc"): @@ -3326,7 +3316,7 @@ def _hw_data(osdata): ("/usr/sbin/virtinfo", "-a"), ): if salt.utils.path.which(cmd): # Also verifies that cmd is executable - data += __salt__["cmd.run"]("{} {}".format(cmd, args)) + data += __salt__["cmd.run"](f"{cmd} {args}") data += "\n" sn_regexes = [ @@ -3441,7 +3431,7 @@ def _hw_data(osdata): elif osdata["kernel"] == "AIX": cmd = salt.utils.path.which("prtconf") if cmd: - data = __salt__["cmd.run"]("{}".format(cmd)) + os.linesep + data = __salt__["cmd.run"](f"{cmd}") + os.linesep for dest, regstring in ( ("serialnumber", r"(?im)^\s*Machine\s+Serial\s+Number:\s+(\S+)"), ("systemfirmware", r"(?im)^\s*Firmware\s+Version:\s+(.*)"), @@ -3523,14 +3513,14 @@ def default_gateway(): for line in out.splitlines(): if line.startswith("default"): grains["ip_gw"] = True - grains["ip{}_gw".format(ip_version)] = True + grains[f"ip{ip_version}_gw"] = True try: via, gw_ip = line.split()[1:3] except ValueError: pass else: if via == "via": - grains["ip{}_gw".format(ip_version)] = gw_ip + grains[f"ip{ip_version}_gw"] = gw_ip break except Exception: # pylint: disable=broad-except continue diff --git a/salt/grains/disks.py b/salt/grains/disks.py index 1dfbeb737bb..f61ad6d6b34 100644 --- a/salt/grains/disks.py +++ b/salt/grains/disks.py @@ -91,14 +91,14 @@ def _freebsd_geom(): geom = salt.utils.path.which("geom") ret = {"disks": {}, "ssds": []} - devices = __salt__["cmd.run"]("{} disk list".format(geom)) + devices = __salt__["cmd.run"](f"{geom} disk list") devices = devices.split("\n\n") def parse_geom_attribs(device): tmp = {} for line in device.split("\n"): for attrib in _geom_attribs: - search = re.search(r"{}:\s(.*)".format(attrib), line) + search = re.search(rf"{attrib}:\s(.*)", line) if search: value = _datavalue( _geomconsts._datatypes.get(attrib), search.group(1) @@ -174,7 +174,7 @@ def _windows_disks(): info = line.split() if len(info) != 2 or not info[0].isdigit() or not info[1].isdigit(): continue - device = r"\\.\PhysicalDrive{}".format(info[0]) + device = rf"\\.\PhysicalDrive{info[0]}" mediatype = info[1] if mediatype == "3": log.trace("Device %s reports itself as an HDD", device) diff --git a/salt/grains/lvm.py b/salt/grains/lvm.py index 586b187ddb9..bb08de96e8b 100644 --- a/salt/grains/lvm.py +++ b/salt/grains/lvm.py @@ -33,14 +33,12 @@ def _linux_lvm(): ret = {} cmd = salt.utils.path.which("lvm") if cmd: - vgs = __salt__["cmd.run_all"]("{} vgs -o vg_name --noheadings".format(cmd)) + vgs = __salt__["cmd.run_all"](f"{cmd} vgs -o vg_name --noheadings") for vg in vgs["stdout"].splitlines(): vg = vg.strip() ret[vg] = [] - lvs = __salt__["cmd.run_all"]( - "{} lvs -o lv_name --noheadings {}".format(cmd, vg) - ) + lvs = __salt__["cmd.run_all"](f"{cmd} lvs -o lv_name --noheadings {vg}") for lv in lvs["stdout"].splitlines(): ret[vg].append(lv.strip()) @@ -52,11 +50,11 @@ def _linux_lvm(): def _aix_lvm(): ret = {} cmd = salt.utils.path.which("lsvg") - vgs = __salt__["cmd.run"]("{}".format(cmd)) + vgs = __salt__["cmd.run"](f"{cmd}") for vg in vgs.splitlines(): ret[vg] = [] - lvs = __salt__["cmd.run"]("{} -l {}".format(cmd, vg)) + lvs = __salt__["cmd.run"](f"{cmd} -l {vg}") for lvline in lvs.splitlines()[2:]: lv = lvline.split(" ", 1)[0] ret[vg].append(lv) diff --git a/salt/grains/mdata.py b/salt/grains/mdata.py index fe88f6ce2a6..009853bb7a3 100644 --- a/salt/grains/mdata.py +++ b/salt/grains/mdata.py @@ -62,7 +62,7 @@ def _user_mdata(mdata_list=None, mdata_get=None): log.warning("mdata-list returned an error, skipping mdata grains.") continue mdata_value = __salt__["cmd.run"]( - "{} {}".format(mdata_get, mdata_grain), ignore_retcode=True + f"{mdata_get} {mdata_grain}", ignore_retcode=True ) if not mdata_grain.startswith("sdc:"): @@ -108,7 +108,7 @@ def _sdc_mdata(mdata_list=None, mdata_get=None): for mdata_grain in sdc_text_keys + sdc_json_keys: mdata_value = __salt__["cmd.run"]( - "{} sdc:{}".format(mdata_get, mdata_grain), ignore_retcode=True + f"{mdata_get} sdc:{mdata_grain}", ignore_retcode=True ) if mdata_value.startswith("ERROR:"): log.warning( diff --git a/salt/grains/metadata.py b/salt/grains/metadata.py index d1dcd41643b..62166330472 100644 --- a/salt/grains/metadata.py +++ b/salt/grains/metadata.py @@ -24,7 +24,7 @@ import salt.utils.stringutils # metadata server information IP = "169.254.169.254" -HOST = "http://{}/".format(IP) +HOST = f"http://{IP}/" def __virtual__(): diff --git a/salt/key.py b/salt/key.py index b15b80eca3f..c2f0d97991c 100644 --- a/salt/key.py +++ b/salt/key.py @@ -177,7 +177,7 @@ class KeyCLI: if cmd in ("accept", "reject", "delete") and args is None: args = self.opts.get("match_dict", {}).get("minions") - fstr = "key.{}".format(cmd) + fstr = f"key.{cmd}" fun = self.client.functions[fstr] args, kwargs = self._get_args_kwargs(fun, args) @@ -230,7 +230,7 @@ class KeyCLI: stat_str = statuses[0] else: stat_str = "{} or {}".format(", ".join(statuses[:-1]), statuses[-1]) - msg = "The key glob '{}' does not match any {} keys.".format(match, stat_str) + msg = f"The key glob '{match}' does not match any {stat_str} keys." print(msg) def run(self): @@ -291,7 +291,7 @@ class KeyCLI: else: salt.output.display_output({"return": ret}, "key", opts=self.opts) except salt.exceptions.SaltException as exc: - ret = "{}".format(exc) + ret = f"{exc}" if not self.opts.get("quiet", False): salt.output.display_output(ret, "nested", self.opts) return ret @@ -311,7 +311,7 @@ class Key: self.opts = opts kind = self.opts.get("__role", "") # application kind if kind not in salt.utils.kinds.APPL_KINDS: - emsg = "Invalid application kind = '{}'.".format(kind) + emsg = f"Invalid application kind = '{kind}'." log.error(emsg) raise ValueError(emsg) self.event = salt.utils.event.get_event( @@ -377,7 +377,7 @@ class Key: # check given pub-key if pub: if not os.path.isfile(pub): - return "Public-key {} does not exist".format(pub) + return f"Public-key {pub} does not exist" # default to master.pub else: mpub = self.opts["pki_dir"] + "/" + "master.pub" @@ -387,7 +387,7 @@ class Key: # check given priv-key if priv: if not os.path.isfile(priv): - return "Private-key {} does not exist".format(priv) + return f"Private-key {priv} does not exist" # default to master_sign.pem else: mpriv = self.opts["pki_dir"] + "/" + "master_sign.pem" @@ -467,7 +467,7 @@ class Key: if clist: for minion in clist: if minion not in minions and minion not in preserve_minions: - cache.flush("{}/{}".format(self.ACC, minion)) + cache.flush(f"{self.ACC}/{minion}") def check_master(self): """ @@ -663,7 +663,7 @@ class Key: pass for keydir, key in invalid_keys: matches[keydir].remove(key) - sys.stderr.write("Unable to accept invalid key for {}.\n".format(key)) + sys.stderr.write(f"Unable to accept invalid key for {key}.\n") return self.name_match(match) if match is not None else self.dict_match(matches) def accept_all(self): diff --git a/salt/loader/__init__.py b/salt/loader/__init__.py index 388742589a6..160fe8e60d0 100644 --- a/salt/loader/__init__.py +++ b/salt/loader/__init__.py @@ -146,7 +146,7 @@ def _module_dirs( ext_type_types = [] if ext_dirs: if ext_type_dirs is None: - ext_type_dirs = "{}_dirs".format(tag) + ext_type_dirs = f"{tag}_dirs" if ext_type_dirs in opts: ext_type_types.extend(opts[ext_type_dirs]) if ext_type_dirs and load_extensions is True: @@ -246,7 +246,7 @@ def _module_dirs( cli_module_dirs.insert(0, maybe_dir) continue - maybe_dir = os.path.join(_dir, "_{}".format(ext_type)) + maybe_dir = os.path.join(_dir, f"_{ext_type}") if os.path.isdir(maybe_dir): cli_module_dirs.insert(0, maybe_dir) @@ -1246,7 +1246,7 @@ def grains(opts, force_refresh=False, proxy=None, context=None, loaded_base_name import salt.modules.cmdmod # Make sure cache file isn't read-only - salt.modules.cmdmod._run_quiet('attrib -R "{}"'.format(cfn)) + salt.modules.cmdmod._run_quiet(f'attrib -R "{cfn}"') with salt.utils.files.fopen(cfn, "w+b") as fp_: try: salt.payload.dump(grains_data, fp_) diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py index f077d245248..a3b795a3757 100644 --- a/salt/loader/lazy.py +++ b/salt/loader/lazy.py @@ -162,7 +162,7 @@ class LoadedFunc: return ret def __repr__(self): - return "<{} name={!r}>".format(self.__class__.__name__, self.name) + return f"<{self.__class__.__name__} name={self.name!r}>" class LoadedMod: @@ -185,10 +185,10 @@ class LoadedMod: Run the wrapped function in the loader's context. """ try: - return self.loader["{}.{}".format(self.mod, name)] + return self.loader[f"{self.mod}.{name}"] except KeyError: raise AttributeError( - "No attribute by the name of {} was found on {}".format(name, self.mod) + f"No attribute by the name of {name} was found on {self.mod}" ) def __repr__(self): @@ -328,10 +328,10 @@ class LazyLoader(salt.utils.lazy.LazyDict): super().__init__() # late init the lazy loader # create all of the import namespaces - _generate_module("{}.int".format(self.loaded_base_name)) - _generate_module("{}.int.{}".format(self.loaded_base_name, tag)) - _generate_module("{}.ext".format(self.loaded_base_name)) - _generate_module("{}.ext.{}".format(self.loaded_base_name, tag)) + _generate_module(f"{self.loaded_base_name}.int") + _generate_module(f"{self.loaded_base_name}.int.{tag}") + _generate_module(f"{self.loaded_base_name}.ext") + _generate_module(f"{self.loaded_base_name}.ext.{tag}") def clean_modules(self): """ @@ -389,19 +389,19 @@ class LazyLoader(salt.utils.lazy.LazyDict): """ mod_name = function_name.split(".")[0] if mod_name in self.loaded_modules: - return "'{}' is not available.".format(function_name) + return f"'{function_name}' is not available." else: try: reason = self.missing_modules[mod_name] except KeyError: - return "'{}' is not available.".format(function_name) + return f"'{function_name}' is not available." else: if reason is not None: return "'{}' __virtual__ returned False: {}".format( mod_name, reason ) else: - return "'{}' __virtual__ returned False".format(mod_name) + return f"'{mod_name}' __virtual__ returned False" def _refresh_file_mapping(self): """ @@ -514,7 +514,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): for suffix in self.suffix_order: if "" == suffix: continue # Next suffix (__init__ must have a suffix) - init_file = "__init__{}".format(suffix) + init_file = f"__init__{suffix}" if init_file in subfiles: break else: @@ -1013,7 +1013,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): try: full_funcname = ".".join((tgt_mod, funcname)) except TypeError: - full_funcname = "{}.{}".format(tgt_mod, funcname) + full_funcname = f"{tgt_mod}.{funcname}" # Save many references for lookups # Careful not to overwrite existing (higher priority) functions if full_funcname not in self._dict: @@ -1040,7 +1040,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): if not isinstance(key, str): raise KeyError("The key must be a string.") if "." not in key: - raise KeyError("The key '{}' should contain a '.'".format(key)) + raise KeyError(f"The key '{key}' should contain a '.'") mod_name, _ = key.split(".", 1) with self._lock: # It is possible that the key is in the dictionary after diff --git a/salt/log_handlers/fluent_mod.py b/salt/log_handlers/fluent_mod.py index 1086a926158..a23544ff871 100644 --- a/salt/log_handlers/fluent_mod.py +++ b/salt/log_handlers/fluent_mod.py @@ -181,7 +181,7 @@ class MessageFormatter(logging.Formatter): self.tags = tags self.msg_path = msg_path if msg_path else payload_type self.msg_type = msg_type if msg_type else payload_type - format_func = "format_{}_v{}".format(payload_type, version).replace(".", "_") + format_func = f"format_{payload_type}_v{version}".replace(".", "_") self.format = getattr(self, format_func) super().__init__(fmt=None, datefmt=None) @@ -236,7 +236,7 @@ class MessageFormatter(logging.Formatter): val = value else: val = repr(value) - message_dict.update({"{}".format(key): val}) + message_dict.update({f"{key}": val}) return message_dict def format_gelf_v1_1(self, record): @@ -286,7 +286,7 @@ class MessageFormatter(logging.Formatter): else: val = repr(value) # GELF spec require "non-standard" fields to be prefixed with '_' (underscore). - message_dict.update({"_{}".format(key): val}) + message_dict.update({f"_{key}": val}) return message_dict @@ -308,7 +308,7 @@ class MessageFormatter(logging.Formatter): "processName": record.processName, }, "@message": record.getMessage(), - "@source": "{}://{}/{}".format(self.msg_type, host, self.msg_path), + "@source": f"{self.msg_type}://{host}/{self.msg_path}", "@source_host": host, "@source_path": self.msg_path, "@tags": self.tags, diff --git a/salt/log_handlers/logstash_mod.py b/salt/log_handlers/logstash_mod.py index dcc54f5a68e..b3e30f83a99 100644 --- a/salt/log_handlers/logstash_mod.py +++ b/salt/log_handlers/logstash_mod.py @@ -265,7 +265,7 @@ class LogstashFormatter(logging.Formatter): self.msg_path = msg_path self.msg_type = msg_type self.version = version - self.format = getattr(self, "format_v{}".format(version)) + self.format = getattr(self, f"format_v{version}") super().__init__(fmt=None, datefmt=None) def formatTime(self, record, datefmt=None): @@ -286,7 +286,7 @@ class LogstashFormatter(logging.Formatter): "processName": record.processName, }, "@message": record.getMessage(), - "@source": "{}://{}/{}".format(self.msg_type, host, self.msg_path), + "@source": f"{self.msg_type}://{host}/{self.msg_path}", "@source_host": host, "@source_path": self.msg_path, "@tags": ["salt"], diff --git a/salt/log_handlers/sentry_mod.py b/salt/log_handlers/sentry_mod.py index c3a6209b1f1..a12366f9fcb 100644 --- a/salt/log_handlers/sentry_mod.py +++ b/salt/log_handlers/sentry_mod.py @@ -140,7 +140,7 @@ def setup_handlers(): transport_registry = TransportRegistry(default_transports) url = urlparse(dsn) if not transport_registry.supported_scheme(url.scheme): - raise ValueError("Unsupported Sentry DSN scheme: {}".format(url.scheme)) + raise ValueError(f"Unsupported Sentry DSN scheme: {url.scheme}") except ValueError as exc: log.info("Raven failed to parse the configuration provided DSN: %s", exc) diff --git a/salt/master.py b/salt/master.py index caea839427c..58386ff9db7 100644 --- a/salt/master.py +++ b/salt/master.py @@ -160,7 +160,7 @@ class SMaster: if "serial" in secret_map: secret_map["serial"].value = 0 if event: - event.fire_event({"rotate_{}_key".format(secret_key): True}, tag="key") + event.fire_event({f"rotate_{secret_key}_key": True}, tag="key") if opts.get("ping_on_rotate"): # Ping all minions to get them to pick up the new key @@ -401,7 +401,7 @@ class FileserverUpdate(salt.utils.process.SignalHandlingProcess): update_intervals = self.fileserver.update_intervals() self.buckets = {} for backend in self.fileserver.backends(): - fstr = "{}.update".format(backend) + fstr = f"{backend}.update" try: update_func = self.fileserver.servers[fstr] except KeyError: @@ -431,7 +431,7 @@ class FileserverUpdate(salt.utils.process.SignalHandlingProcess): # nothing to pass to the backend's update func, so we'll just # set the value to None. try: - interval_key = "{}_update_interval".format(backend) + interval_key = f"{backend}_update_interval" interval = self.opts[interval_key] except KeyError: interval = DEFAULT_INTERVAL @@ -608,7 +608,7 @@ class Master(SMaster): try: os.chdir("/") except OSError as err: - errors.append("Cannot change to root directory ({})".format(err)) + errors.append(f"Cannot change to root directory ({err})") if self.opts.get("fileserver_verify_config", True): # Avoid circular import @@ -626,7 +626,7 @@ class Master(SMaster): try: fileserver.init() except salt.exceptions.FileserverConfigError as exc: - critical_errors.append("{}".format(exc)) + critical_errors.append(f"{exc}") if not self.opts["fileserver_backend"]: errors.append("No fileserver backends are configured") @@ -773,7 +773,7 @@ class Master(SMaster): cls = _tmp.__getattribute__( # pylint: disable=unnecessary-dunder-call cls ) - name = "ExtProcess({})".format(cls.__qualname__) + name = f"ExtProcess({cls.__qualname__})" self.process_manager.add_process(cls, args=(self.opts,), name=name) except Exception: # pylint: disable=broad-except log.error("Error creating ext_processes process: %s", proc) @@ -913,7 +913,7 @@ class ReqServer(salt.utils.process.SignalHandlingProcess): # signal handlers with salt.utils.process.default_signals(signal.SIGINT, signal.SIGTERM): for ind in range(int(self.opts["worker_threads"])): - name = "MWorker-{}".format(ind) + name = f"MWorker-{ind}" self.process_manager.add_process( MWorker, args=(self.opts, self.master_key, self.key, req_channels), @@ -2123,7 +2123,7 @@ class ClearFuncs(TransportMethods): fun = clear_load.pop("fun") tag = tagify(jid, prefix="wheel") data = { - "fun": "wheel.{}".format(fun), + "fun": f"wheel.{fun}", "jid": jid, "tag": tag, "user": username, @@ -2226,7 +2226,7 @@ class ClearFuncs(TransportMethods): else: auth_list = auth_check.get("auth_list", []) - err_msg = 'Authentication failure of type "{}" occurred.'.format(auth_type) + err_msg = f'Authentication failure of type "{auth_type}" occurred.' if auth_check.get("error"): # Authentication error occurred: do not continue. diff --git a/salt/matchers/compound_match.py b/salt/matchers/compound_match.py index 2bce58f117a..04da7281e3e 100644 --- a/salt/matchers/compound_match.py +++ b/salt/matchers/compound_match.py @@ -111,7 +111,7 @@ def match(tgt, opts=None, minion_id=None): results.append( str( - __context__["matchers"]["{}_match.match".format(engine)]( + __context__["matchers"][f"{engine}_match.match"]( *engine_args, **engine_kwargs ) ) diff --git a/salt/matchers/ipcidr_match.py b/salt/matchers/ipcidr_match.py index 175dade0024..8cfbf4d3332 100644 --- a/salt/matchers/ipcidr_match.py +++ b/salt/matchers/ipcidr_match.py @@ -27,7 +27,7 @@ def match(tgt, opts=None, minion_id=None): except: # pylint: disable=bare-except log.error("Invalid IP/CIDR target: %s", tgt) return [] - proto = "ipv{}".format(tgt.version) + proto = f"ipv{tgt.version}" grains = opts["grains"] diff --git a/salt/matchers/list_match.py b/salt/matchers/list_match.py index 5b790666ee3..91520cbb13d 100644 --- a/salt/matchers/list_match.py +++ b/salt/matchers/list_match.py @@ -19,7 +19,7 @@ def match(tgt, opts=None, minion_id=None): try: if ( - ",{},".format(minion_id) in tgt + f",{minion_id}," in tgt or tgt.startswith(minion_id + ",") or tgt.endswith("," + minion_id) ): diff --git a/salt/metaproxy/deltaproxy.py b/salt/metaproxy/deltaproxy.py index 82c3c12598c..f77ccdcbd34 100644 --- a/salt/metaproxy/deltaproxy.py +++ b/salt/metaproxy/deltaproxy.py @@ -168,8 +168,8 @@ def post_master_init(self, master): salt.engines.start_engines, self.opts, self.process_manager, proxy=self.proxy ) - proxy_init_func_name = "{}.init".format(fq_proxyname) - proxy_shutdown_func_name = "{}.shutdown".format(fq_proxyname) + proxy_init_func_name = f"{fq_proxyname}.init" + proxy_shutdown_func_name = f"{fq_proxyname}.shutdown" if ( proxy_init_func_name not in self.proxy or proxy_shutdown_func_name not in self.proxy @@ -183,7 +183,7 @@ def post_master_init(self, master): raise SaltSystemExit(code=-1, msg=errmsg) self.module_executors = self.proxy.get( - "{}.module_executors".format(fq_proxyname), lambda: [] + f"{fq_proxyname}.module_executors", lambda: [] )() proxy_init_fn = self.proxy[proxy_init_func_name] proxy_init_fn(self.opts) @@ -626,7 +626,7 @@ def thread_return(cls, minion_instance, opts, data): # Reconfigure multiprocessing logging after daemonizing salt._logging.setup_logging() - salt.utils.process.appendproctitle("{}._thread_return".format(cls.__name__)) + salt.utils.process.appendproctitle(f"{cls.__name__}._thread_return") sdata = {"pid": os.getpid()} sdata.update(data) @@ -642,11 +642,9 @@ def thread_return(cls, minion_instance, opts, data): ) allow_missing_funcs = any( [ - minion_instance.executors["{}.allow_missing_func".format(executor)]( - function_name - ) + minion_instance.executors[f"{executor}.allow_missing_func"](function_name) for executor in executors - if "{}.allow_missing_func".format(executor) in minion_instance.executors + if f"{executor}.allow_missing_func" in minion_instance.executors ] ) if function_name in minion_instance.functions or allow_missing_funcs is True: @@ -703,11 +701,9 @@ def thread_return(cls, minion_instance, opts, data): log.debug("Executors list %s", executors) for name in executors: - fname = "{}.execute".format(name) + fname = f"{name}.execute" if fname not in minion_instance.executors: - raise SaltInvocationError( - "Executor '{}' is not available".format(name) - ) + raise SaltInvocationError(f"Executor '{name}' is not available") return_data = minion_instance.executors[fname]( opts, data, func, args, kwargs @@ -752,9 +748,9 @@ def thread_return(cls, minion_instance, opts, data): ret["retcode"] = retcode ret["success"] = retcode == salt.defaults.exitcodes.EX_OK except CommandNotFoundError as exc: - msg = 'Command required for "{}" not found'.format(function_name) + msg = f'Command required for "{function_name}" not found' log.debug(msg, exc_info=True) - ret["return"] = "{}: {}".format(msg, exc) + ret["return"] = f"{msg}: {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except CommandExecutionError as exc: @@ -764,7 +760,7 @@ def thread_return(cls, minion_instance, opts, data): exc, exc_info_on_loglevel=logging.DEBUG, ) - ret["return"] = "ERROR: {}".format(exc) + ret["return"] = f"ERROR: {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except SaltInvocationError as exc: @@ -774,7 +770,7 @@ def thread_return(cls, minion_instance, opts, data): exc, exc_info_on_loglevel=logging.DEBUG, ) - ret["return"] = 'ERROR executing "{}": {}'.format(function_name, exc) + ret["return"] = f'ERROR executing "{function_name}": {exc}' ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except TypeError as exc: @@ -791,11 +787,11 @@ def thread_return(cls, minion_instance, opts, data): salt.utils.error.fire_exception( salt.exceptions.MinionError(msg), opts, job=data ) - ret["return"] = "{}: {}".format(msg, traceback.format_exc()) + ret["return"] = f"{msg}: {traceback.format_exc()}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC else: - docs = minion_instance.functions["sys.doc"]("{}*".format(function_name)) + docs = minion_instance.functions["sys.doc"](f"{function_name}*") if docs: docs[function_name] = minion_instance.functions.missing_fun_string( function_name @@ -842,7 +838,7 @@ def thread_return(cls, minion_instance, opts, data): ret["id"] = opts["id"] for returner in set(data["ret"].split(",")): try: - returner_str = "{}.returner".format(returner) + returner_str = f"{returner}.returner" if returner_str in minion_instance.returners: minion_instance.returners[returner_str](ret) else: @@ -874,7 +870,7 @@ def thread_multi_return(cls, minion_instance, opts, data): # Reconfigure multiprocessing logging after daemonizing salt._logging.setup_logging() - salt.utils.process.appendproctitle("{}._thread_multi_return".format(cls.__name__)) + salt.utils.process.appendproctitle(f"{cls.__name__}._thread_multi_return") sdata = {"pid": os.getpid()} sdata.update(data) @@ -972,7 +968,7 @@ def thread_multi_return(cls, minion_instance, opts, data): for returner in set(data["ret"].split(",")): ret["id"] = opts["id"] try: - minion_instance.returners["{}.returner".format(returner)](ret) + minion_instance.returners[f"{returner}.returner"](ret) except Exception as exc: # pylint: disable=broad-except log.error("The return failed for job %s: %s", data["jid"], exc) diff --git a/salt/metaproxy/proxy.py b/salt/metaproxy/proxy.py index 04d4c02c75a..a9d51bb1958 100644 --- a/salt/metaproxy/proxy.py +++ b/salt/metaproxy/proxy.py @@ -166,8 +166,8 @@ def post_master_init(self, master): ) if ( - "{}.init".format(fq_proxyname) not in self.proxy - or "{}.shutdown".format(fq_proxyname) not in self.proxy + f"{fq_proxyname}.init" not in self.proxy + or f"{fq_proxyname}.shutdown" not in self.proxy ): errmsg = ( "Proxymodule {} is missing an init() or a shutdown() or both. ".format( @@ -180,7 +180,7 @@ def post_master_init(self, master): raise SaltSystemExit(code=-1, msg=errmsg) self.module_executors = self.proxy.get( - "{}.module_executors".format(fq_proxyname), lambda: [] + f"{fq_proxyname}.module_executors", lambda: [] )() proxy_init_fn = self.proxy[fq_proxyname + ".init"] proxy_init_fn(self.opts) @@ -375,7 +375,7 @@ def target(cls, minion_instance, opts, data, connected, creds_map): fq_proxyname = opts["proxy"]["proxytype"] minion_instance.module_executors = minion_instance.proxy.get( - "{}.module_executors".format(fq_proxyname), lambda: [] + f"{fq_proxyname}.module_executors", lambda: [] )() proxy_init_fn = minion_instance.proxy[fq_proxyname + ".init"] @@ -418,11 +418,9 @@ def thread_return(cls, minion_instance, opts, data): ) allow_missing_funcs = any( [ - minion_instance.executors["{}.allow_missing_func".format(executor)]( - function_name - ) + minion_instance.executors[f"{executor}.allow_missing_func"](function_name) for executor in executors - if "{}.allow_missing_func".format(executor) in minion_instance.executors + if f"{executor}.allow_missing_func" in minion_instance.executors ] ) if function_name in minion_instance.functions or allow_missing_funcs is True: @@ -477,11 +475,9 @@ def thread_return(cls, minion_instance, opts, data): log.trace("Executors list %s", executors) # pylint: disable=no-member for name in executors: - fname = "{}.execute".format(name) + fname = f"{name}.execute" if fname not in minion_instance.executors: - raise SaltInvocationError( - "Executor '{}' is not available".format(name) - ) + raise SaltInvocationError(f"Executor '{name}' is not available") return_data = minion_instance.executors[fname]( opts, data, func, args, kwargs ) @@ -525,9 +521,9 @@ def thread_return(cls, minion_instance, opts, data): ret["retcode"] = retcode ret["success"] = retcode == salt.defaults.exitcodes.EX_OK except CommandNotFoundError as exc: - msg = "Command required for '{}' not found".format(function_name) + msg = f"Command required for '{function_name}' not found" log.debug(msg, exc_info=True) - ret["return"] = "{}: {}".format(msg, exc) + ret["return"] = f"{msg}: {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except CommandExecutionError as exc: @@ -537,7 +533,7 @@ def thread_return(cls, minion_instance, opts, data): exc, exc_info_on_loglevel=logging.DEBUG, ) - ret["return"] = "ERROR: {}".format(exc) + ret["return"] = f"ERROR: {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except SaltInvocationError as exc: @@ -547,7 +543,7 @@ def thread_return(cls, minion_instance, opts, data): exc, exc_info_on_loglevel=logging.DEBUG, ) - ret["return"] = "ERROR executing '{}': {}".format(function_name, exc) + ret["return"] = f"ERROR executing '{function_name}': {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except TypeError as exc: @@ -564,11 +560,11 @@ def thread_return(cls, minion_instance, opts, data): salt.utils.error.fire_exception( salt.exceptions.MinionError(msg), opts, job=data ) - ret["return"] = "{}: {}".format(msg, traceback.format_exc()) + ret["return"] = f"{msg}: {traceback.format_exc()}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC else: - docs = minion_instance.functions["sys.doc"]("{}*".format(function_name)) + docs = minion_instance.functions["sys.doc"](f"{function_name}*") if docs: docs[function_name] = minion_instance.functions.missing_fun_string( function_name @@ -616,7 +612,7 @@ def thread_return(cls, minion_instance, opts, data): ret["id"] = opts["id"] for returner in set(data["ret"].split(",")): try: - returner_str = "{}.returner".format(returner) + returner_str = f"{returner}.returner" if returner_str in minion_instance.returners: minion_instance.returners[returner_str](ret) else: @@ -739,7 +735,7 @@ def thread_multi_return(cls, minion_instance, opts, data): for returner in set(data["ret"].split(",")): ret["id"] = opts["id"] try: - minion_instance.returners["{}.returner".format(returner)](ret) + minion_instance.returners[f"{returner}.returner"](ret) except Exception as exc: # pylint: disable=broad-except log.error("The return failed for job %s: %s", data["jid"], exc) diff --git a/salt/minion.py b/salt/minion.py index 61965b70aed..e6a9521766a 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -341,7 +341,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False): # **kwargs not in argspec and parsed argument name not in # list of positional arguments. This keyword argument is # invalid. - invalid_kwargs.append("{}={}".format(key, val)) + invalid_kwargs.append(f"{key}={val}") continue else: @@ -358,7 +358,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False): # list of positional arguments. This keyword argument is # invalid. for key, val in string_kwarg.items(): - invalid_kwargs.append("{}={}".format(key, val)) + invalid_kwargs.append(f"{key}={val}") else: _args.append(arg) @@ -368,7 +368,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False): if argspec.keywords and isinstance(data, dict): # this function accepts **kwargs, pack in the publish data for key, val in data.items(): - _kwargs["__pub_{}".format(key)] = val + _kwargs[f"__pub_{key}"] = val return _args, _kwargs @@ -413,7 +413,7 @@ def master_event(type, master=None): } if type == "alive" and master is not None: - return "{}_{}".format(event_map.get(type), master) + return f"{event_map.get(type)}_{master}" return event_map.get(type, None) @@ -1925,9 +1925,9 @@ class Minion(MinionBase): log.trace("Executors list %s", executors) # pylint: disable=no-member for name in executors: - fname = "{}.execute".format(name) + fname = f"{name}.execute" if fname not in self.executors: - raise SaltInvocationError("Executor '{}' is not available".format(name)) + raise SaltInvocationError(f"Executor '{name}' is not available") return_data = self.executors[fname](opts, data, func, args, kwargs) if return_data is not None: return return_data @@ -1943,7 +1943,7 @@ class Minion(MinionBase): minion_instance.gen_modules() fn_ = os.path.join(minion_instance.proc_dir, data["jid"]) - salt.utils.process.appendproctitle("{}._thread_return".format(cls.__name__)) + salt.utils.process.appendproctitle(f"{cls.__name__}._thread_return") sdata = {"pid": os.getpid()} sdata.update(data) @@ -1960,11 +1960,11 @@ class Minion(MinionBase): ) allow_missing_funcs = any( [ - minion_instance.executors["{}.allow_missing_func".format(executor)]( + minion_instance.executors[f"{executor}.allow_missing_func"]( function_name ) for executor in executors - if "{}.allow_missing_func".format(executor) in minion_instance.executors + if f"{executor}.allow_missing_func" in minion_instance.executors ] ) if function_name in minion_instance.functions or allow_missing_funcs is True: @@ -2010,9 +2010,9 @@ class Minion(MinionBase): ret["retcode"] = retcode ret["success"] = retcode == salt.defaults.exitcodes.EX_OK except CommandNotFoundError as exc: - msg = "Command required for '{}' not found".format(function_name) + msg = f"Command required for '{function_name}' not found" log.debug(msg, exc_info=True) - ret["return"] = "{}: {}".format(msg, exc) + ret["return"] = f"{msg}: {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except CommandExecutionError as exc: @@ -2022,7 +2022,7 @@ class Minion(MinionBase): exc, exc_info_on_loglevel=logging.DEBUG, ) - ret["return"] = "ERROR: {}".format(exc) + ret["return"] = f"ERROR: {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except SaltInvocationError as exc: @@ -2032,7 +2032,7 @@ class Minion(MinionBase): exc, exc_info_on_loglevel=logging.DEBUG, ) - ret["return"] = "ERROR executing '{}': {}".format(function_name, exc) + ret["return"] = f"ERROR executing '{function_name}': {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except SaltClientError as exc: @@ -2041,7 +2041,7 @@ class Minion(MinionBase): function_name, exc, ) - ret["return"] = "ERROR executing '{}': {}".format(function_name, exc) + ret["return"] = f"ERROR executing '{function_name}': {exc}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC except TypeError as exc: @@ -2064,11 +2064,11 @@ class Minion(MinionBase): salt.utils.error.fire_exception( salt.exceptions.MinionError(msg), opts, job=data ) - ret["return"] = "{}: {}".format(msg, traceback.format_exc()) + ret["return"] = f"{msg}: {traceback.format_exc()}" ret["out"] = "nested" ret["retcode"] = salt.defaults.exitcodes.EX_GENERIC else: - docs = minion_instance.functions["sys.doc"]("{}*".format(function_name)) + docs = minion_instance.functions["sys.doc"](f"{function_name}*") if docs: docs[function_name] = minion_instance.functions.missing_fun_string( function_name @@ -2120,7 +2120,7 @@ class Minion(MinionBase): ret["id"] = opts["id"] for returner in set(data["ret"].split(",")): try: - returner_str = "{}.returner".format(returner) + returner_str = f"{returner}.returner" if returner_str in minion_instance.returners: minion_instance.returners[returner_str](ret) else: @@ -2144,9 +2144,7 @@ class Minion(MinionBase): minion_instance.gen_modules() fn_ = os.path.join(minion_instance.proc_dir, data["jid"]) - salt.utils.process.appendproctitle( - "{}._thread_multi_return".format(cls.__name__) - ) + salt.utils.process.appendproctitle(f"{cls.__name__}._thread_multi_return") sdata = {"pid": os.getpid()} sdata.update(data) @@ -2225,7 +2223,7 @@ class Minion(MinionBase): for returner in set(data["ret"].split(",")): ret["id"] = opts["id"] try: - minion_instance.returners["{}.returner".format(returner)](ret) + minion_instance.returners[f"{returner}.returner"](ret) except Exception as exc: # pylint: disable=broad-except log.error("The return failed for job %s: %s", data["jid"], exc) @@ -4027,8 +4025,8 @@ class SProxyMinion(SMinion): self.proxy.reload_modules() if ( - "{}.init".format(fq_proxyname) not in self.proxy - or "{}.shutdown".format(fq_proxyname) not in self.proxy + f"{fq_proxyname}.init" not in self.proxy + or f"{fq_proxyname}.shutdown" not in self.proxy ): errmsg = ( "Proxymodule {} is missing an init() or a shutdown() or both. ".format( @@ -4041,7 +4039,7 @@ class SProxyMinion(SMinion): raise SaltSystemExit(code=salt.defaults.exitcodes.EX_GENERIC, msg=errmsg) self.module_executors = self.proxy.get( - "{}.module_executors".format(fq_proxyname), lambda: [] + f"{fq_proxyname}.module_executors", lambda: [] )() proxy_init_fn = self.proxy[fq_proxyname + ".init"] proxy_init_fn(self.opts) diff --git a/salt/modules/acme.py b/salt/modules/acme.py index 7952acc1aad..af87f48bf27 100644 --- a/salt/modules/acme.py +++ b/salt/modules/acme.py @@ -72,7 +72,7 @@ def _cert_file(name, cert_type): """ Return expected path of a Let's Encrypt live cert """ - return os.path.join(LE_LIVE, name, "{}.pem".format(cert_type)) + return os.path.join(LE_LIVE, name, f"{cert_type}.pem") def _expires(name): @@ -88,9 +88,9 @@ def _expires(name): expiry = __salt__["tls.cert_info"](cert_file).get("not_after", 0) # Cobble it together using the openssl binary else: - openssl_cmd = "openssl x509 -in {} -noout -enddate".format(cert_file) + openssl_cmd = f"openssl x509 -in {cert_file} -noout -enddate" # No %e format on my Linux'es here - strptime_sux_cmd = 'date --date="$({} | cut -d= -f2)" +%s'.format(openssl_cmd) + strptime_sux_cmd = f'date --date="$({openssl_cmd} | cut -d= -f2)" +%s' expiry = float(__salt__["cmd.shell"](strptime_sux_cmd, output_loglevel="quiet")) # expiry = datetime.datetime.strptime(expiry.split('=', 1)[-1], '%b %e %H:%M:%S %Y %Z') return datetime.datetime.fromtimestamp(expiry) @@ -195,10 +195,10 @@ def cert( cmd.append("--renew-by-default") renew = True if server: - cmd.append("--server {}".format(server)) + cmd.append(f"--server {server}") if certname: - cmd.append("--cert-name {}".format(certname)) + cmd.append(f"--cert-name {certname}") if test_cert: if server: @@ -211,41 +211,41 @@ def cert( if webroot: cmd.append("--authenticator webroot") if webroot is not True: - cmd.append("--webroot-path {}".format(webroot)) + cmd.append(f"--webroot-path {webroot}") elif dns_plugin in supported_dns_plugins: if dns_plugin == "cloudflare": cmd.append("--dns-cloudflare") - cmd.append("--dns-cloudflare-credentials {}".format(dns_plugin_credentials)) + cmd.append(f"--dns-cloudflare-credentials {dns_plugin_credentials}") else: return { "result": False, - "comment": "DNS plugin '{}' is not supported".format(dns_plugin), + "comment": f"DNS plugin '{dns_plugin}' is not supported", } else: cmd.append("--authenticator standalone") if email: - cmd.append("--email {}".format(email)) + cmd.append(f"--email {email}") if keysize: - cmd.append("--rsa-key-size {}".format(keysize)) + cmd.append(f"--rsa-key-size {keysize}") - cmd.append("--domains {}".format(name)) + cmd.append(f"--domains {name}") if aliases is not None: for dns in aliases: - cmd.append("--domains {}".format(dns)) + cmd.append(f"--domains {dns}") if preferred_challenges: - cmd.append("--preferred-challenges {}".format(preferred_challenges)) + cmd.append(f"--preferred-challenges {preferred_challenges}") if tls_sni_01_port: - cmd.append("--tls-sni-01-port {}".format(tls_sni_01_port)) + cmd.append(f"--tls-sni-01-port {tls_sni_01_port}") if tls_sni_01_address: - cmd.append("--tls-sni-01-address {}".format(tls_sni_01_address)) + cmd.append(f"--tls-sni-01-address {tls_sni_01_address}") if http_01_port: - cmd.append("--http-01-port {}".format(http_01_port)) + cmd.append(f"--http-01-port {http_01_port}") if http_01_address: - cmd.append("--http-01-address {}".format(http_01_address)) + cmd.append(f"--http-01-address {http_01_address}") res = __salt__["cmd.run_all"](" ".join(cmd)) @@ -269,13 +269,13 @@ def cert( } if "no action taken" in res["stdout"]: - comment = "Certificate {} unchanged".format(cert_file) + comment = f"Certificate {cert_file} unchanged" result = None elif renew: - comment = "Certificate {} renewed".format(certname) + comment = f"Certificate {certname} renewed" result = True else: - comment = "Certificate {} obtained".format(certname) + comment = f"Certificate {certname} obtained" result = True ret = { @@ -339,7 +339,7 @@ def info(name): cert_info = __salt__["x509.read_certificate"](cert_file) else: # Cobble it together using the openssl binary - openssl_cmd = "openssl x509 -in {} -noout -text".format(cert_file) + openssl_cmd = f"openssl x509 -in {cert_file} -noout -text" cert_info = {"text": __salt__["cmd.run"](openssl_cmd, output_loglevel="quiet")} return cert_info diff --git a/salt/modules/aix_group.py b/salt/modules/aix_group.py index ddbb452fcbf..b1e5f092e79 100644 --- a/salt/modules/aix_group.py +++ b/salt/modules/aix_group.py @@ -48,7 +48,7 @@ def add(name, gid=None, system=False, root=None, **kwargs): cmd += "-a " if gid: - cmd += "id={} ".format(gid) + cmd += f"id={gid} " cmd += name @@ -67,7 +67,7 @@ def delete(name): salt '*' group.delete foo """ - ret = __salt__["cmd.run_all"]("rmgroup {}".format(name), python_shell=False) + ret = __salt__["cmd.run_all"](f"rmgroup {name}", python_shell=False) return not ret["retcode"] @@ -129,7 +129,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) if gid == pre_gid: return True - cmd = "chgroup id={} {}".format(gid, name) + cmd = f"chgroup id={gid} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_gid = __salt__["file.group_to_gid"](name) if post_gid != pre_gid: @@ -150,7 +150,7 @@ def adduser(name, username, root=None): Verifies if a valid username 'bar' as a member of an existing group 'foo', if not then adds it. """ - cmd = "chgrpmem -m + {} {}".format(username, name) + cmd = f"chgrpmem -m + {username} {name}" retcode = __salt__["cmd.retcode"](cmd, python_shell=False) @@ -173,7 +173,7 @@ def deluser(name, username, root=None): grp_info = __salt__["group.info"](name) try: if username in grp_info["members"]: - cmd = "chgrpmem -m - {} {}".format(username, name) + cmd = f"chgrpmem -m - {username} {name}" ret = __salt__["cmd.run"](cmd, python_shell=False) return not ret["retcode"] else: @@ -195,7 +195,7 @@ def members(name, members_list, root=None): Replaces a membership list for a local group 'foo'. foo:x:1234:user1,user2,user3,... """ - cmd = "chgrpmem -m = {} {}".format(members_list, name) + cmd = f"chgrpmem -m = {members_list} {name}" retcode = __salt__["cmd.retcode"](cmd, python_shell=False) return not retcode diff --git a/salt/modules/aix_shadow.py b/salt/modules/aix_shadow.py index 3282603e01f..e58f93180fe 100644 --- a/salt/modules/aix_shadow.py +++ b/salt/modules/aix_shadow.py @@ -39,7 +39,7 @@ def login_failures(user): salt shadow.login_failures ALL """ - cmd = "lsuser -a unsuccessful_login_count {}".format(user) + cmd = f"lsuser -a unsuccessful_login_count {user}" cmd += " | grep -E 'unsuccessful_login_count=([3-9]|[0-9][0-9]+)'" out = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=True) @@ -63,7 +63,7 @@ def locked(user): salt shadow.locked ALL """ - cmd = "lsuser -a account_locked {}".format(user) + cmd = f"lsuser -a account_locked {user}" cmd += ' | grep "account_locked=true"' out = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=True) diff --git a/salt/modules/aixpkg.py b/salt/modules/aixpkg.py index 25c0b2dbdfc..a77cff26788 100644 --- a/salt/modules/aixpkg.py +++ b/salt/modules/aixpkg.py @@ -184,7 +184,7 @@ def version(*names, **kwargs): for name in names: # AIX packaging includes info on filesets and rpms version_found = "" - cmd = "lslpp -Lq {}".format(name) + cmd = f"lslpp -Lq {name}" aix_info = __salt__["cmd.run_all"](cmd, python_shell=False) if 0 == aix_info["retcode"]: aix_info_list = aix_info["stdout"].split("\n") @@ -344,7 +344,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if refresh: cmdflags += "--refresh " - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -360,7 +360,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa else: cmdflags += "--assumeyes " - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -378,7 +378,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if refresh: cmdflags += "--refresh " - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -392,7 +392,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if test: cmdflags += "--test" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"](cmd, python_shell=False) if "retcode" in out and not (0 == out["retcode"] or 100 == out["retcode"]): @@ -510,7 +510,7 @@ def remove(name=None, pkgs=None, **kwargs): libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -519,7 +519,7 @@ def remove(name=None, pkgs=None, **kwargs): ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -528,7 +528,7 @@ def remove(name=None, pkgs=None, **kwargs): ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -538,7 +538,7 @@ def remove(name=None, pkgs=None, **kwargs): else: cmdexe = "/usr/bin/rpm" cmdflags = "-e" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"](cmd, python_shell=False) else: cmd = ["/usr/sbin/installp", "-u", named] @@ -594,19 +594,19 @@ def latest_version(*names, **kwargs): libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) @@ -683,19 +683,19 @@ def upgrade_available(name, **kwargs): libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) diff --git a/salt/modules/aliases.py b/salt/modules/aliases.py index 01337791ffe..b006593767f 100644 --- a/salt/modules/aliases.py +++ b/salt/modules/aliases.py @@ -80,9 +80,9 @@ def __write_aliases_file(lines): if not line_comment: line_comment = "" if line_alias and line_target: - write_line = "{}: {}{}\n".format(line_alias, line_target, line_comment) + write_line = f"{line_alias}: {line_target}{line_comment}\n" else: - write_line = "{}\n".format(line_comment) + write_line = f"{line_comment}\n" write_line = write_line.encode(__salt_system_encoding__) out.write(write_line) diff --git a/salt/modules/alternatives.py b/salt/modules/alternatives.py index 64df8d78367..a71814b6ef1 100644 --- a/salt/modules/alternatives.py +++ b/salt/modules/alternatives.py @@ -241,5 +241,5 @@ def _read_link(name): Throws an OSError if the link does not exist """ - alt_link_path = "/etc/alternatives/{}".format(name) + alt_link_path = f"/etc/alternatives/{name}" return salt.utils.path.readlink(alt_link_path) diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py index 2f60a7444fb..ec87aa9969c 100644 --- a/salt/modules/ansiblegate.py +++ b/salt/modules/ansiblegate.py @@ -101,17 +101,16 @@ def __virtual__(): proc = subprocess.run( [ansible_doc_bin, "--list", "--json", "--type=module"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, check=False, shell=False, - universal_newlines=True, + text=True, env=env, ) if proc.returncode != 0: return ( False, - "Failed to get the listing of ansible modules:\n{}".format(proc.stderr), + f"Failed to get the listing of ansible modules:\n{proc.stderr}", ) module_funcs = dir(sys.modules[__name__]) @@ -170,11 +169,10 @@ def help(module=None, *args): proc = subprocess.run( [ansible_doc_bin, "--json", "--type=module", module], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, check=True, shell=False, - universal_newlines=True, + text=True, env=env, ) data = salt.utils.json.loads(proc.stdout) @@ -240,7 +238,7 @@ def call(module, *args, **kwargs): _kwargs = {k: v for (k, v) in kwargs.items() if not k.startswith("__pub")} for key, value in _kwargs.items(): - module_args.append("{}={}".format(key, salt.utils.json.dumps(value))) + module_args.append(f"{key}={salt.utils.json.dumps(value)}") with NamedTemporaryFile(mode="w") as inventory: @@ -263,10 +261,9 @@ def call(module, *args, **kwargs): "-i", inventory.name, ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, timeout=__opts__.get("ansible_timeout", DEFAULT_TIMEOUT), - universal_newlines=True, + text=True, check=True, shell=False, env=env, @@ -367,15 +364,15 @@ def playbooks( if diff: command.append("--diff") if isinstance(extra_vars, dict): - command.append("--extra-vars='{}'".format(json.dumps(extra_vars))) + command.append(f"--extra-vars='{json.dumps(extra_vars)}'") elif isinstance(extra_vars, str) and extra_vars.startswith("@"): - command.append("--extra-vars={}".format(extra_vars)) + command.append(f"--extra-vars={extra_vars}") if flush_cache: command.append("--flush-cache") if inventory: - command.append("--inventory={}".format(inventory)) + command.append(f"--inventory={inventory}") if limit: - command.append("--limit={}".format(limit)) + command.append(f"--limit={limit}") if list_hosts: command.append("--list-hosts") if list_tags: @@ -383,25 +380,25 @@ def playbooks( if list_tasks: command.append("--list-tasks") if module_path: - command.append("--module-path={}".format(module_path)) + command.append(f"--module-path={module_path}") if skip_tags: - command.append("--skip-tags={}".format(skip_tags)) + command.append(f"--skip-tags={skip_tags}") if start_at_task: - command.append("--start-at-task={}".format(start_at_task)) + command.append(f"--start-at-task={start_at_task}") if syntax_check: command.append("--syntax-check") if tags: - command.append("--tags={}".format(tags)) + command.append(f"--tags={tags}") if playbook_kwargs: for key, value in playbook_kwargs.items(): key = key.replace("_", "-") if value is True: - command.append("--{}".format(key)) + command.append(f"--{key}") elif isinstance(value, str): - command.append("--{}={}".format(key, value)) + command.append(f"--{key}={value}") elif isinstance(value, dict): - command.append("--{}={}".format(key, json.dumps(value))) - command.append("--forks={}".format(forks)) + command.append(f"--{key}={json.dumps(value)}") + command.append(f"--forks={forks}") cmd_kwargs = { "env": { "ANSIBLE_STDOUT_CALLBACK": "json", @@ -540,12 +537,10 @@ def discover_playbooks( if path: if not os.path.isabs(path): raise CommandExecutionError( - "The given path is not an absolute path: {}".format(path) + f"The given path is not an absolute path: {path}" ) if not os.path.isdir(path): - raise CommandExecutionError( - "The given path is not a directory: {}".format(path) - ) + raise CommandExecutionError(f"The given path is not a directory: {path}") return { path: _explore_path(path, playbook_extension, hosts_filename, syntax_check) } @@ -599,7 +594,7 @@ def _explore_path(path, playbook_extension, hosts_filename, syntax_check): ) except Exception as exc: raise CommandExecutionError( - "There was an exception while discovering playbooks: {}".format(exc) + f"There was an exception while discovering playbooks: {exc}" ) # Run syntax check validation diff --git a/salt/modules/apache.py b/salt/modules/apache.py index d50ff3b17df..3d9fc41c618 100644 --- a/salt/modules/apache.py +++ b/salt/modules/apache.py @@ -60,7 +60,7 @@ def version(): salt '*' apache.version """ - cmd = "{} -v".format(_detect_os()) + cmd = f"{_detect_os()} -v" out = __salt__["cmd.run"](cmd).splitlines() ret = out[0].split(": ") return ret[1] @@ -76,7 +76,7 @@ def fullversion(): salt '*' apache.fullversion """ - cmd = "{} -V".format(_detect_os()) + cmd = f"{_detect_os()} -V" ret = {} ret["compiled_with"] = [] out = __salt__["cmd.run"](cmd).splitlines() @@ -105,7 +105,7 @@ def modules(): salt '*' apache.modules """ - cmd = "{} -M".format(_detect_os()) + cmd = f"{_detect_os()} -M" ret = {} ret["static"] = [] ret["shared"] = [] @@ -131,7 +131,7 @@ def servermods(): salt '*' apache.servermods """ - cmd = "{} -l".format(_detect_os()) + cmd = f"{_detect_os()} -l" ret = [] out = __salt__["cmd.run"](cmd).splitlines() for line in out: @@ -153,7 +153,7 @@ def directives(): salt '*' apache.directives """ - cmd = "{} -L".format(_detect_os()) + cmd = f"{_detect_os()} -L" ret = {} out = __salt__["cmd.run"](cmd) out = out.replace("\n\t", "\t") @@ -180,7 +180,7 @@ def vhosts(): salt -t 10 '*' apache.vhosts """ - cmd = "{} -S".format(_detect_os()) + cmd = f"{_detect_os()} -S" ret = {} namevhost = "" out = __salt__["cmd.run"](cmd) @@ -221,9 +221,9 @@ def signal(signal=None): return # Make sure you use the right arguments if signal in valid_signals: - arguments = " -k {}".format(signal) + arguments = f" -k {signal}" else: - arguments = " {}".format(signal) + arguments = f" {signal}" cmd = _detect_os() + arguments out = __salt__["cmd.run_all"](cmd) @@ -237,7 +237,7 @@ def signal(signal=None): ret = out["stdout"].strip() # No output for something like: apachectl graceful else: - ret = 'Command: "{}" completed successfully!'.format(cmd) + ret = f'Command: "{cmd}" completed successfully!' return ret @@ -326,14 +326,12 @@ def server_status(profile="default"): # Get configuration from pillar url = __salt__["config.get"]( - "apache.server-status:{}:url".format(profile), "http://localhost/server-status" - ) - user = __salt__["config.get"]("apache.server-status:{}:user".format(profile), "") - passwd = __salt__["config.get"]("apache.server-status:{}:pass".format(profile), "") - realm = __salt__["config.get"]("apache.server-status:{}:realm".format(profile), "") - timeout = __salt__["config.get"]( - "apache.server-status:{}:timeout".format(profile), 5 + f"apache.server-status:{profile}:url", "http://localhost/server-status" ) + user = __salt__["config.get"](f"apache.server-status:{profile}:user", "") + passwd = __salt__["config.get"](f"apache.server-status:{profile}:pass", "") + realm = __salt__["config.get"](f"apache.server-status:{profile}:realm", "") + timeout = __salt__["config.get"](f"apache.server-status:{profile}:timeout", 5) # create authentication handler if configuration exists if user and passwd: @@ -379,9 +377,9 @@ def _parse_config(conf, slot=None): ret = io.StringIO() if isinstance(conf, str): if slot: - print("{} {}".format(slot, conf), file=ret, end="") + print(f"{slot} {conf}", file=ret, end="") else: - print("{}".format(conf), file=ret, end="") + print(f"{conf}", file=ret, end="") elif isinstance(conf, list): is_section = False for item in conf: @@ -389,12 +387,12 @@ def _parse_config(conf, slot=None): is_section = True slot_this = str(item["this"]) if is_section: - print("<{} {}>".format(slot, slot_this), file=ret) + print(f"<{slot} {slot_this}>", file=ret) for item in conf: for key, val in item.items(): if key != "this": print(_parse_config(val, str(key)), file=ret) - print("".format(slot), file=ret) + print(f"", file=ret) else: for value in conf: print(_parse_config(value, str(slot)), file=ret) @@ -409,12 +407,12 @@ def _parse_config(conf, slot=None): for key, value in conf.items(): if key != "this": if isinstance(value, str): - print("{} {}".format(key, value), file=ret) + print(f"{key} {value}", file=ret) elif isinstance(value, list): print(_parse_config(value, key), file=ret) elif isinstance(value, dict): print(_parse_config(value, key), file=ret) - print("".format(slot), file=ret) + print(f"", file=ret) ret.seek(0) return ret.read() diff --git a/salt/modules/apf.py b/salt/modules/apf.py index 406f2c9d417..c7de7e47895 100644 --- a/salt/modules/apf.py +++ b/salt/modules/apf.py @@ -45,7 +45,7 @@ def __apf_cmd(cmd): msg = out["stdout"] else: msg = out["stderr"] - raise CommandExecutionError("apf failed: {}".format(msg)) + raise CommandExecutionError(f"apf failed: {msg}") return out["stdout"] @@ -140,7 +140,7 @@ def allow(ip, port=None): salt '*' apf.allow 127.0.0.1 """ if port is None: - return __apf_cmd("-a {}".format(ip)) + return __apf_cmd(f"-a {ip}") def deny(ip): @@ -153,7 +153,7 @@ def deny(ip): salt '*' apf.deny 1.2.3.4 """ - return __apf_cmd("-d {}".format(ip)) + return __apf_cmd(f"-d {ip}") def remove(ip): @@ -166,4 +166,4 @@ def remove(ip): salt '*' apf.remove 1.2.3.4 """ - return __apf_cmd("-u {}".format(ip)) + return __apf_cmd(f"-u {ip}") diff --git a/salt/modules/apkpkg.py b/salt/modules/apkpkg.py index 365c9e4c941..e1240d28d15 100644 --- a/salt/modules/apkpkg.py +++ b/salt/modules/apkpkg.py @@ -597,6 +597,6 @@ def owner(*paths, **kwargs): else: ret[path] = output.split("by ")[1].strip() else: - ret[path] = "Error running {}".format(cmd) + ret[path] = f"Error running {cmd}" return ret diff --git a/salt/modules/aptly.py b/salt/modules/aptly.py index a3409abfc3b..6a0a653b3ff 100644 --- a/salt/modules/aptly.py +++ b/salt/modules/aptly.py @@ -77,10 +77,10 @@ def _format_repo_args( for setting in settings: if settings[setting] is not None: - ret.append("-{}={}".format(setting, settings[setting])) + ret.append(f"-{setting}={settings[setting]}") if cached_uploaders_path: - ret.append("-uploaders-file={}".format(cached_uploaders_path)) + ret.append(f"-uploaders-file={cached_uploaders_path}") return ret @@ -97,7 +97,7 @@ def _validate_config(config_path): log.debug("Checking configuration file: %s", config_path) if not os.path.isfile(config_path): - message = "Unable to get configuration file: {}".format(config_path) + message = f"Unable to get configuration file: {config_path}" log.error(message) raise SaltInvocationError(message) @@ -119,7 +119,7 @@ def get_config(config_path=_DEFAULT_CONFIG_PATH): """ _validate_config(config_path) - cmd = ["config", "show", "-config={}".format(config_path)] + cmd = ["config", "show", f"-config={config_path}"] cmd_ret = _cmd_run(cmd) @@ -145,7 +145,7 @@ def list_repos(config_path=_DEFAULT_CONFIG_PATH, with_packages=False): _validate_config(config_path) ret = dict() - cmd = ["repo", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["repo", "list", f"-config={config_path}", "-raw=true"] cmd_ret = _cmd_run(cmd) repos = [line.strip() for line in cmd_ret.splitlines()] @@ -183,8 +183,8 @@ def get_repo(name, config_path=_DEFAULT_CONFIG_PATH, with_packages=False): cmd = [ "repo", "show", - "-config={}".format(config_path), - "-with-packages={}".format(with_packages), + f"-config={config_path}", + f"-with-packages={with_packages}", name, ] @@ -250,7 +250,7 @@ def new_repo( log.debug("Repository already exists: %s", name) return True - cmd = ["repo", "create", "-config={}".format(config_path)] + cmd = ["repo", "create", f"-config={config_path}"] repo_params = _format_repo_args( comment=comment, component=component, @@ -336,7 +336,7 @@ def set_repo( log.debug("Settings already have the desired values for repository: %s", name) return True - cmd = ["repo", "edit", "-config={}".format(config_path)] + cmd = ["repo", "edit", f"-config={config_path}"] repo_params = _format_repo_args( comment=comment, @@ -395,8 +395,8 @@ def delete_repo(name, config_path=_DEFAULT_CONFIG_PATH, force=False): cmd = [ "repo", "drop", - "-config={}".format(config_path), - "-force={}".format(force), + f"-config={config_path}", + f"-force={force}", name, ] @@ -427,7 +427,7 @@ def list_mirrors(config_path=_DEFAULT_CONFIG_PATH): """ _validate_config(config_path) - cmd = ["mirror", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["mirror", "list", f"-config={config_path}", "-raw=true"] cmd_ret = _cmd_run(cmd) ret = [line.strip() for line in cmd_ret.splitlines()] @@ -453,7 +453,7 @@ def list_published(config_path=_DEFAULT_CONFIG_PATH): """ _validate_config(config_path) - cmd = ["publish", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["publish", "list", f"-config={config_path}", "-raw=true"] cmd_ret = _cmd_run(cmd) ret = [line.strip() for line in cmd_ret.splitlines()] @@ -480,7 +480,7 @@ def list_snapshots(config_path=_DEFAULT_CONFIG_PATH, sort_by_time=False): """ _validate_config(config_path) - cmd = ["snapshot", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["snapshot", "list", f"-config={config_path}", "-raw=true"] if sort_by_time: cmd.append("-sort=time") @@ -518,8 +518,8 @@ def cleanup_db(config_path=_DEFAULT_CONFIG_PATH, dry_run=False): cmd = [ "db", "cleanup", - "-config={}".format(config_path), - "-dry-run={}".format(dry_run), + f"-config={config_path}", + f"-dry-run={dry_run}", "-verbose=true", ] @@ -533,7 +533,7 @@ def cleanup_db(config_path=_DEFAULT_CONFIG_PATH, dry_run=False): if current_block: match = re.search(list_pattern, line) if match: - package_type = "deleted_{}".format(current_block) + package_type = f"deleted_{current_block}" ret[package_type].append(match.group("package")) else: current_block = None diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py index d143cdcee07..191587dcd85 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py @@ -205,10 +205,10 @@ if not HAS_APT: opts = _get_opts(self.line) if self.architectures: archs = ",".join(self.architectures) - opts["arch"]["full"] = "arch={}".format(archs) + opts["arch"]["full"] = f"arch={archs}" opts["arch"]["value"] = self.architectures if self.signedby: - opts["signedby"]["full"] = "signed-by={}".format(self.signedby) + opts["signedby"]["full"] = f"signed-by={self.signedby}" opts["signedby"]["value"] = self.signedby ordered_opts = [ @@ -224,7 +224,7 @@ if not HAS_APT: repo_line += [self.uri, self.dist, " ".join(self.comps)] if self.comment: - repo_line.append("#{}".format(self.comment)) + repo_line.append(f"#{self.comment}") return " ".join(repo_line) + "\n" def _parse_sources(self, line): @@ -287,7 +287,7 @@ if not HAS_APT: architectures = "arch={}".format(",".join(architectures)) opts_count.append(architectures) if signedby: - signedby = "signed-by={}".format(signedby) + signedby = f"signed-by={signedby}" opts_count.append(signedby) if len(opts_count) > 1: opts_line = "[" + " ".join(opts_count) + "]" @@ -350,7 +350,7 @@ def _reconstruct_ppa_name(owner_name, ppa_name): """ Stringify PPA name from args. """ - return "ppa:{}/{}".format(owner_name, ppa_name) + return f"ppa:{owner_name}/{ppa_name}" def _call_apt(args, scope=True, **kwargs): @@ -363,7 +363,7 @@ def _call_apt(args, scope=True, **kwargs): and salt.utils.systemd.has_scope(__context__) and __salt__["config.get"]("systemd.scope", True) ): - cmd.extend(["systemd-run", "--scope", "--description", '"{}"'.format(__name__)]) + cmd.extend(["systemd-run", "--scope", "--description", f'"{__name__}"']) cmd.extend(args) params = { @@ -473,7 +473,7 @@ def latest_version(*names, **kwargs): for name in names: ret[name] = "" pkgs = list_pkgs(versions_as_list=True) - repo = ["-o", "APT::Default-Release={}".format(fromrepo)] if fromrepo else None + repo = ["-o", f"APT::Default-Release={fromrepo}"] if fromrepo else None # Refresh before looking for the latest version available if refresh: @@ -941,7 +941,7 @@ def install( continue else: version_num = target - pkgstr = "{}={}".format(pkgname, version_num) + pkgstr = f"{pkgname}={version_num}" else: pkgstr = pkgpath @@ -1317,7 +1317,7 @@ def upgrade(refresh=True, dist_upgrade=False, **kwargs): ] for option in dpkg_options: cmd.append("-o") - cmd.append("DPkg::Options::={}".format(option)) + cmd.append(f"DPkg::Options::={option}") if kwargs.get("force_yes", False): cmd.append("--force-yes") @@ -1390,15 +1390,15 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613 state = get_selections(pattern=target, state="hold") if not state: - ret[target]["comment"] = "Package {} not currently held.".format(target) + ret[target]["comment"] = f"Package {target} not currently held." elif not salt.utils.data.is_true(state.get("hold", False)): if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret[target]["comment"] = "Package {} is set to be held.".format(target) + ret[target]["comment"] = f"Package {target} is set to be held." else: result = set_selections(selection={"hold": [target]}) ret[target].update(changes=result[target], result=True) - ret[target]["comment"] = "Package {} is now being held.".format(target) + ret[target]["comment"] = f"Package {target} is now being held." else: ret[target].update(result=True) ret[target]["comment"] = "Package {} is already set to be held.".format( @@ -1455,7 +1455,7 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 state = get_selections(pattern=target) if not state: - ret[target]["comment"] = "Package {} does not have a state.".format(target) + ret[target]["comment"] = f"Package {target} does not have a state." elif salt.utils.data.is_true(state.get("hold", False)): if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) @@ -1551,7 +1551,7 @@ def list_pkgs( if __grains__.get("cpuarch", "") == "x86_64": osarch = __grains__.get("osarch", "") if arch != "all" and osarch == "amd64" and osarch != arch: - name += ":{}".format(arch) + name += f":{arch}" if cols: if ("install" in linetype or "hold" in linetype) and "installed" in status: __salt__["pkg_resource.add_pkg"](ret["installed"], name, version_num) @@ -1792,7 +1792,7 @@ def _consolidate_repo_sources(sources): Consolidate APT sources. """ if not isinstance(sources, SourcesList): - raise TypeError("'{}' not a '{}'".format(type(sources), SourcesList)) + raise TypeError(f"'{type(sources)}' not a '{SourcesList}'") consolidated = {} delete_files = set() @@ -1973,7 +1973,7 @@ def get_repo(repo, **kwargs): dist = __grains__["oscodename"] owner_name, ppa_name = repo[4:].split("/") if ppa_auth: - auth_info = "{}@".format(ppa_auth) + auth_info = f"{ppa_auth}@" repo = LP_PVT_SRC_FORMAT.format(auth_info, owner_name, ppa_name, dist) else: if HAS_SOFTWAREPROPERTIES: @@ -1986,7 +1986,7 @@ def get_repo(repo, **kwargs): repo = softwareproperties.ppa.expand_ppa_line(repo, dist)[0] except NameError as name_error: raise CommandExecutionError( - "Could not find ppa {}: {}".format(repo, name_error) + f"Could not find ppa {repo}: {name_error}" ) else: repo = LP_SRC_FORMAT.format(owner_name, ppa_name, dist) @@ -2005,7 +2005,7 @@ def get_repo(repo, **kwargs): ) except SyntaxError: raise CommandExecutionError( - "Error: repo '{}' is not a well formatted definition".format(repo) + f"Error: repo '{repo}' is not a well formatted definition" ) for source in repos.values(): @@ -2068,7 +2068,7 @@ def del_repo(repo, **kwargs): repo_entry = _split_repo_str(repo) except SyntaxError: raise SaltInvocationError( - "Error: repo '{}' not a well formatted definition".format(repo) + f"Error: repo '{repo}' not a well formatted definition" ) for source in repos: @@ -2130,9 +2130,7 @@ def del_repo(repo, **kwargs): refresh_db() return ret - raise CommandExecutionError( - "Repo {} doesn't exist in the sources.list(s)".format(repo) - ) + raise CommandExecutionError(f"Repo {repo} doesn't exist in the sources.list(s)") def _convert_if_int(value): @@ -2425,11 +2423,11 @@ def add_repo_key( else: cmd.extend(["adv", "--batch", "--keyserver", keyserver, "--recv", keyid]) elif keyid: - error_msg = "No keyserver specified for keyid: {}".format(keyid) + error_msg = f"No keyserver specified for keyid: {keyid}" raise SaltInvocationError(error_msg) else: raise TypeError( - "{}() takes at least 1 argument (0 given)".format(add_repo_key.__name__) + f"{add_repo_key.__name__}() takes at least 1 argument (0 given)" ) cmd_ret = _call_apt(cmd, **kwargs) @@ -2729,7 +2727,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs): repo = LP_SRC_FORMAT.format(owner_name, ppa_name, dist) else: raise CommandExecutionError( - 'cannot parse "ppa:" style repo definitions: {}'.format(repo) + f'cannot parse "ppa:" style repo definitions: {repo}' ) sources = SourcesList() @@ -2764,9 +2762,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs): f"Name {repo} is not valid. This must be the complete repo entry as seen in the sources file" ) except SyntaxError: - raise SyntaxError( - "Error: repo '{}' not a well formatted definition".format(repo) - ) + raise SyntaxError(f"Error: repo '{repo}' not a well formatted definition") full_comp_list = {comp.strip() for comp in repo_entry["comps"]} no_proxy = __salt__["config.option"]("no_proxy") @@ -2810,7 +2806,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs): "adv", "--batch", "--keyserver-options", - "http-proxy={}".format(http_proxy_url), + f"http-proxy={http_proxy_url}", "--keyserver", keyserver, "--logger-fd", @@ -2856,7 +2852,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs): key_url = kwargs["key_url"] fn_ = pathlib.Path(__salt__["cp.cache_file"](key_url, saltenv)) if not fn_: - raise CommandExecutionError("Error: file not found: {}".format(key_url)) + raise CommandExecutionError(f"Error: file not found: {key_url}") if kwargs["signedby"] and fn_.name != kwargs["signedby"].name: # override the signedby defined in the name with the @@ -2876,9 +2872,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs): cmd = ["apt-key", "add", str(fn_)] out = __salt__["cmd.run_stdout"](cmd, python_shell=False, **kwargs) if not out.upper().startswith("OK"): - raise CommandExecutionError( - "Error: failed to add key from {}".format(key_url) - ) + raise CommandExecutionError(f"Error: failed to add key from {key_url}") elif "key_text" in kwargs: key_text = kwargs["key_text"] @@ -2887,9 +2881,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs): cmd, stdin=key_text, python_shell=False, **kwargs ) if not out.upper().startswith("OK"): - raise CommandExecutionError( - "Error: failed to add key:\n{}".format(key_text) - ) + raise CommandExecutionError(f"Error: failed to add key:\n{key_text}") if "comps" in kwargs: kwargs["comps"] = [comp.strip() for comp in kwargs["comps"].split(",")] @@ -3236,7 +3228,7 @@ def set_selections(path=None, selection=None, clear=False, saltenv="base"): salt.utils.yaml.parser.ParserError, salt.utils.yaml.scanner.ScannerError, ) as exc: - raise SaltInvocationError("Improperly-formatted selection: {}".format(exc)) + raise SaltInvocationError(f"Improperly-formatted selection: {exc}") if path: path = __salt__["cp.cache_file"](path, saltenv) @@ -3272,7 +3264,7 @@ def set_selections(path=None, selection=None, clear=False, saltenv="base"): if _state == sel_revmap.get(_pkg): continue cmd = ["dpkg", "--set-selections"] - cmd_in = "{} {}".format(_pkg, _state) + cmd_in = f"{_pkg} {_state}" if not __opts__["test"]: result = _call_apt(cmd, scope=False, stdin=cmd_in) if result["retcode"] != 0: @@ -3468,9 +3460,9 @@ def _get_http_proxy_url(): # Set http_proxy_url for use in various internet facing actions...eg apt-key adv if host and port: if username and password: - http_proxy_url = "http://{}:{}@{}:{}".format(username, password, host, port) + http_proxy_url = f"http://{username}:{password}@{host}:{port}" else: - http_proxy_url = "http://{}:{}".format(host, port) + http_proxy_url = f"http://{host}:{port}" return http_proxy_url diff --git a/salt/modules/archive.py b/salt/modules/archive.py index e7be041bc66..9651cc406d8 100644 --- a/salt/modules/archive.py +++ b/salt/modules/archive.py @@ -207,7 +207,7 @@ def list_( stderr = cached.communicate()[1] if cached.returncode != 0: raise CommandExecutionError( - "Failed to decompress {}".format(name), + f"Failed to decompress {name}", info={"error": stderr}, ) else: @@ -290,7 +290,7 @@ def list_( files.remove(dirname) return list(dirs), files, links except zipfile.BadZipfile: - raise CommandExecutionError("{} is not a ZIP file".format(name)) + raise CommandExecutionError(f"{name} is not a ZIP file") def _list_rar(name, cached): """ @@ -335,7 +335,7 @@ def list_( name, saltenv, source_hash=source_hash, use_etag=use_etag ) if not cached: - raise CommandExecutionError("Failed to cache {}".format(name)) + raise CommandExecutionError(f"Failed to cache {name}") try: if strip_components: @@ -362,7 +362,7 @@ def list_( "'archive_format' argument." ) raise CommandExecutionError( - "Unsupported archive format '{}'".format(archive_format) + f"Unsupported archive format '{archive_format}'" ) if not archive_format: @@ -379,14 +379,12 @@ def list_( try: dirs, files, links = func(name, cached, *args) except OSError as exc: - raise CommandExecutionError( - "Failed to list contents of {}: {}".format(name, exc) - ) + raise CommandExecutionError(f"Failed to list contents of {name}: {exc}") except CommandExecutionError as exc: raise except Exception as exc: # pylint: disable=broad-except raise CommandExecutionError( - "Uncaught exception '{}' when listing contents of {}".format(exc, name) + f"Uncaught exception '{exc}' when listing contents of {name}" ) if clean: @@ -549,10 +547,10 @@ def tar(options, tarfile, sources=None, dest=None, cwd=None, template=None, runa if options: cmd.extend(options.split()) - cmd.extend(["{}".format(tarfile)]) + cmd.extend([f"{tarfile}"]) cmd.extend(_expand_sources(sources)) if dest: - cmd.extend(["-C", "{}".format(dest)]) + cmd.extend(["-C", f"{dest}"]) return __salt__["cmd.run"]( cmd, cwd=cwd, template=template, runas=runas, python_shell=False @@ -591,7 +589,7 @@ def gzip(sourcefile, template=None, runas=None, options=None): cmd = ["gzip"] if options: cmd.append(options) - cmd.append("{}".format(sourcefile)) + cmd.append(f"{sourcefile}") return __salt__["cmd.run"]( cmd, template=template, runas=runas, python_shell=False @@ -630,7 +628,7 @@ def gunzip(gzipfile, template=None, runas=None, options=None): cmd = ["gunzip"] if options: cmd.append(options) - cmd.append("{}".format(gzipfile)) + cmd.append(f"{gzipfile}") return __salt__["cmd.run"]( cmd, template=template, runas=runas, python_shell=False @@ -696,7 +694,7 @@ def cmd_zip(zip_file, sources, template=None, cwd=None, runas=None): salt '*' archive.cmd_zip /tmp/zipfile.zip '/tmp/sourcefile*' """ cmd = ["zip", "-r"] - cmd.append("{}".format(zip_file)) + cmd.append(f"{zip_file}") cmd.extend(_expand_sources(sources)) return __salt__["cmd.run"]( cmd, cwd=cwd, template=template, runas=runas, python_shell=False @@ -771,7 +769,7 @@ def zip_(zip_file, sources, template=None, cwd=None, runas=None, zip64=False): egid = os.getegid() uinfo = __salt__["user.info"](runas) if not uinfo: - raise SaltInvocationError("User '{}' does not exist".format(runas)) + raise SaltInvocationError(f"User '{runas}' does not exist") zip_file, sources = _render_filenames(zip_file, sources, None, template) sources = _expand_sources(sources) @@ -846,7 +844,7 @@ def zip_(zip_file, sources, template=None, cwd=None, runas=None, zip64=False): ) else: raise CommandExecutionError( - "Exception encountered creating zipfile: {}".format(exc) + f"Exception encountered creating zipfile: {exc}" ) return archived_files @@ -940,7 +938,7 @@ def cmd_unzip( cmd.extend(["-P", password]) if options: cmd.extend(shlex.split(options)) - cmd.extend(["{}".format(zip_file), "-d", "{}".format(dest)]) + cmd.extend([f"{zip_file}", "-d", f"{dest}"]) if excludes is not None: cmd.append("-x") @@ -1058,7 +1056,7 @@ def unzip( egid = os.getegid() uinfo = __salt__["user.info"](runas) if not uinfo: - raise SaltInvocationError("User '{}' does not exist".format(runas)) + raise SaltInvocationError(f"User '{runas}' does not exist") zip_file, dest = _render_filenames(zip_file, dest, None, template) @@ -1119,9 +1117,7 @@ def unzip( os.setegid(egid) # Wait to raise the exception until euid/egid are restored to avoid # permission errors in writing to minion log. - raise CommandExecutionError( - "Exception encountered unpacking zipfile: {}".format(exc) - ) + raise CommandExecutionError(f"Exception encountered unpacking zipfile: {exc}") finally: # Restore the euid/egid if runas: @@ -1188,7 +1184,7 @@ def is_encrypted(name, clean=False, saltenv="base", source_hash=None, use_etag=F name, saltenv, source_hash=source_hash, use_etag=use_etag ) if not cached: - raise CommandExecutionError("Failed to cache {}".format(name)) + raise CommandExecutionError(f"Failed to cache {name}") archive_info = {"archive location": cached} try: @@ -1197,9 +1193,7 @@ def is_encrypted(name, clean=False, saltenv="base", source_hash=None, use_etag=F except RuntimeError: ret = True except zipfile.BadZipfile: - raise CommandExecutionError( - "{} is not a ZIP file".format(name), info=archive_info - ) + raise CommandExecutionError(f"{name} is not a ZIP file", info=archive_info) except Exception as exc: # pylint: disable=broad-except raise CommandExecutionError(exc, info=archive_info) else: @@ -1257,7 +1251,7 @@ def rar(rarfile, sources, template=None, cwd=None, runas=None): # Globbing for sources (2017.7.0 and later) salt '*' archive.rar /tmp/rarfile.rar '/tmp/sourcefile*' """ - cmd = ["rar", "a", "-idp", "{}".format(rarfile)] + cmd = ["rar", "a", "-idp", f"{rarfile}"] cmd.extend(_expand_sources(sources)) return __salt__["cmd.run"]( cmd, cwd=cwd, template=template, runas=runas, python_shell=False @@ -1303,12 +1297,12 @@ def unrar(rarfile, dest, excludes=None, template=None, runas=None, trim_output=F salt.utils.path.which_bin(("unrar", "rar")), "x", "-idp", - "{}".format(rarfile), + f"{rarfile}", ] if excludes is not None: for exclude in excludes: - cmd.extend(["-x", "{}".format(exclude)]) - cmd.append("{}".format(dest)) + cmd.extend(["-x", f"{exclude}"]) + cmd.append(f"{dest}") files = __salt__["cmd.run"]( cmd, template=template, runas=runas, python_shell=False ).splitlines() @@ -1328,7 +1322,7 @@ def _render_filenames(filenames, zip_file, saltenv, template): # render the path as a template using path_template_engine as the engine if template not in salt.utils.templates.TEMPLATE_REGISTRY: raise CommandExecutionError( - "Attempted to render file paths with unavailable engine {}".format(template) + f"Attempted to render file paths with unavailable engine {template}" ) kwargs = {} @@ -1377,6 +1371,6 @@ def _trim_files(files, trim_output): and len(files) > count ): files = files[:count] - files.append("List trimmed after {} files.".format(count)) + files.append(f"List trimmed after {count} files.") return files diff --git a/salt/modules/arista_pyeapi.py b/salt/modules/arista_pyeapi.py index 1dbd27fd872..9e9abb1a973 100644 --- a/salt/modules/arista_pyeapi.py +++ b/salt/modules/arista_pyeapi.py @@ -398,7 +398,7 @@ def config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Configures the node with the specified commands. @@ -509,7 +509,7 @@ def config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") log.debug("Fetched from %s", config_file) log.debug(file_str) elif commands: diff --git a/salt/modules/artifactory.py b/salt/modules/artifactory.py index 7eaf9c72458..0f5f8e000ec 100644 --- a/salt/modules/artifactory.py +++ b/salt/modules/artifactory.py @@ -732,7 +732,7 @@ def __save_artifact(artifact_url, target_file, headers): local_file.write(salt.utils.stringutils.to_bytes(f.read())) result["status"] = True result["comment"] = __append_comment( - "Artifact downloaded from URL: {}".format(artifact_url), + f"Artifact downloaded from URL: {artifact_url}", result["comment"], ) result["changes"]["downloaded_file"] = target_file diff --git a/salt/modules/at.py b/salt/modules/at.py index 9c646dfb2e8..449e0f79523 100644 --- a/salt/modules/at.py +++ b/salt/modules/at.py @@ -48,7 +48,7 @@ def _cmd(binary, *args): """ binary = salt.utils.path.which(binary) if not binary: - raise CommandNotFoundError("{}: command not found".format(binary)) + raise CommandNotFoundError(f"{binary}: command not found") cmd = [binary] + list(args) return __salt__["cmd.run_stdout"]([binary] + list(args), python_shell=False) @@ -307,7 +307,7 @@ def atc(jobid): if output is None: return "'at.atc' is not available." elif output == "": - return {"error": "invalid job id '{}'".format(jobid)} + return {"error": f"invalid job id '{jobid}'"} return output @@ -327,7 +327,7 @@ def _atq(**kwargs): month = kwargs.get("month", None) year = kwargs.get("year", None) if year and len(str(year)) == 2: - year = "20{}".format(year) + year = f"20{year}" jobinfo = atq()["jobs"] if not jobinfo: @@ -351,28 +351,28 @@ def _atq(**kwargs): if not hour: pass - elif "{:02d}".format(int(hour)) == job["time"].split(":")[0]: + elif f"{int(hour):02d}" == job["time"].split(":")[0]: pass else: continue if not minute: pass - elif "{:02d}".format(int(minute)) == job["time"].split(":")[1]: + elif f"{int(minute):02d}" == job["time"].split(":")[1]: pass else: continue if not day: pass - elif "{:02d}".format(int(day)) == job["date"].split("-")[2]: + elif f"{int(day):02d}" == job["date"].split("-")[2]: pass else: continue if not month: pass - elif "{:02d}".format(int(month)) == job["date"].split("-")[1]: + elif f"{int(month):02d}" == job["date"].split("-")[1]: pass else: continue diff --git a/salt/modules/at_solaris.py b/salt/modules/at_solaris.py index ee8e2e67b35..bebc6118c72 100644 --- a/salt/modules/at_solaris.py +++ b/salt/modules/at_solaris.py @@ -95,7 +95,7 @@ def atq(tag=None): job = str(job) # search for any tags - atjob_file = "/var/spool/cron/atjobs/{job}".format(job=job) + atjob_file = f"/var/spool/cron/atjobs/{job}" if __salt__["file.file_exists"](atjob_file): with salt.utils.files.fopen(atjob_file, "r") as atjob: for line in atjob: @@ -162,7 +162,7 @@ def atrm(*args): # call atrm for each job in ret['jobs']['removed'] for job in ret["jobs"]["removed"]: - res_job = __salt__["cmd.run_all"]("atrm {job}".format(job=job)) + res_job = __salt__["cmd.run_all"](f"atrm {job}") if res_job["retcode"] > 0: if "failed" not in ret["jobs"]: ret["jobs"]["failed"] = {} @@ -205,9 +205,7 @@ def at(*args, **kwargs): # pylint: disable=C0103 cmd_kwargs = {"stdin": stdin, "python_shell": False} if "runas" in kwargs: cmd_kwargs["runas"] = kwargs["runas"] - res = __salt__["cmd.run_all"]( - 'at "{timespec}"'.format(timespec=args[0]), **cmd_kwargs - ) + res = __salt__["cmd.run_all"](f'at "{args[0]}"', **cmd_kwargs) # verify job creation if res["retcode"] > 0: @@ -233,14 +231,14 @@ def atc(jobid): salt '*' at.atc """ - atjob_file = "/var/spool/cron/atjobs/{job}".format(job=jobid) + atjob_file = f"/var/spool/cron/atjobs/{jobid}" if __salt__["file.file_exists"](atjob_file): with salt.utils.files.fopen(atjob_file, "r") as rfh: return "".join( [salt.utils.stringutils.to_unicode(x) for x in rfh.readlines()] ) else: - return {"error": "invalid job id '{}'".format(jobid)} + return {"error": f"invalid job id '{jobid}'"} def _atq(**kwargs): @@ -258,7 +256,7 @@ def _atq(**kwargs): month = kwargs.get("month", None) year = kwargs.get("year", None) if year and len(str(year)) == 2: - year = "20{}".format(year) + year = f"20{year}" jobinfo = atq()["jobs"] if not jobinfo: @@ -282,28 +280,28 @@ def _atq(**kwargs): if not hour: pass - elif "{:02d}".format(int(hour)) == job["time"].split(":")[0]: + elif f"{int(hour):02d}" == job["time"].split(":")[0]: pass else: continue if not minute: pass - elif "{:02d}".format(int(minute)) == job["time"].split(":")[1]: + elif f"{int(minute):02d}" == job["time"].split(":")[1]: pass else: continue if not day: pass - elif "{:02d}".format(int(day)) == job["date"].split("-")[2]: + elif f"{int(day):02d}" == job["date"].split("-")[2]: pass else: continue if not month: pass - elif "{:02d}".format(int(month)) == job["date"].split("-")[1]: + elif f"{int(month):02d}" == job["date"].split("-")[1]: pass else: continue diff --git a/salt/modules/augeas_cfg.py b/salt/modules/augeas_cfg.py index 6fd455235af..adc4fa22b21 100644 --- a/salt/modules/augeas_cfg.py +++ b/salt/modules/augeas_cfg.py @@ -190,7 +190,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): cmd, arg = command.split(" ", 1) if cmd not in METHOD_MAP: - ret["error"] = "Command {} is not supported (yet)".format(cmd) + ret["error"] = f"Command {cmd} is not supported (yet)" return ret method = METHOD_MAP[cmd] @@ -199,7 +199,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): parts = salt.utils.args.shlex_split(arg) if len(parts) not in nargs: - err = "{} takes {} args: {}".format(method, nargs, parts) + err = f"{method} takes {nargs} args: {parts}" raise ValueError(err) if method == "set": path = make_path(parts[0]) @@ -217,9 +217,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): elif method == "insert": label, where, path = parts if where not in ("before", "after"): - raise ValueError( - 'Expected "before" or "after", not {}'.format(where) - ) + raise ValueError(f'Expected "before" or "after", not {where}') path = make_path(path) args = {"path": path, "label": label, "before": where == "before"} elif method == "remove": @@ -231,7 +229,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): if "arg" not in locals(): arg = command ret["error"] = ( - "Invalid formatted command, see debug log for details: {}".format(arg) + f"Invalid formatted command, see debug log for details: {arg}" ) return ret @@ -374,7 +372,7 @@ def setvalue(*args): try: aug.set(target_path, str(value)) except ValueError as err: - ret["error"] = "Multiple values: {}".format(err) + ret["error"] = f"Multiple values: {err}" try: aug.save() diff --git a/salt/modules/aws_sqs.py b/salt/modules/aws_sqs.py index e85417faf1a..428f4062dad 100644 --- a/salt/modules/aws_sqs.py +++ b/salt/modules/aws_sqs.py @@ -23,7 +23,7 @@ def _region(region): """ Return the region argument. """ - return " --region {r}".format(r=region) + return f" --region {region}" def _run_aws(cmd, region, opts, user, **kwargs): @@ -49,7 +49,7 @@ def _run_aws(cmd, region, opts, user, **kwargs): if num: kwargs["max-number-of-messages"] = num - _formatted_args = ['--{} "{}"'.format(k, v) for k, v in kwargs.items()] + _formatted_args = [f'--{k} "{v}"' for k, v in kwargs.items()] cmd = "aws sqs {cmd} {args} {region} {out}".format( cmd=cmd, args=" ".join(_formatted_args), region=_region(region), out=_OUTPUT @@ -245,7 +245,7 @@ def delete_queue(name, region, opts=None, user=None): rtn = _run_aws("delete-queue", region=region, opts=opts, user=user, **delete) success = True err = "" - out = "{} deleted".format(name) + out = f"{name} deleted" else: out = "" diff --git a/salt/modules/azurearm_compute.py b/salt/modules/azurearm_compute.py index 61ff7f85b2f..4b29e657dd8 100644 --- a/salt/modules/azurearm_compute.py +++ b/salt/modules/azurearm_compute.py @@ -156,7 +156,7 @@ def availability_set_create_or_update( "compute", "AvailabilitySet", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -171,9 +171,7 @@ def availability_set_create_or_update( __utils__["azurearm.log_cloud_error"]("compute", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result diff --git a/salt/modules/azurearm_dns.py b/salt/modules/azurearm_dns.py index e503712f264..537a4f7608b 100644 --- a/salt/modules/azurearm_dns.py +++ b/salt/modules/azurearm_dns.py @@ -146,7 +146,7 @@ def record_set_create_or_update(name, zone_name, resource_group, record_type, ** "dns", "RecordSet", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -164,9 +164,7 @@ def record_set_create_or_update(name, zone_name, resource_group, record_type, ** __utils__["azurearm.log_cloud_error"]("dns", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -394,7 +392,7 @@ def zone_create_or_update(name, resource_group, **kwargs): try: zone_model = __utils__["azurearm.create_object_model"]("dns", "Zone", **kwargs) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -410,9 +408,7 @@ def zone_create_or_update(name, resource_group, **kwargs): __utils__["azurearm.log_cloud_error"]("dns", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result diff --git a/salt/modules/azurearm_network.py b/salt/modules/azurearm_network.py index c8e520c3cf2..e22c92359b8 100644 --- a/salt/modules/azurearm_network.py +++ b/salt/modules/azurearm_network.py @@ -216,7 +216,7 @@ def default_security_rule_get(name, security_group, resource_group, **kwargs): if default_rule["name"] == name: result = default_rule if not result: - result = {"error": "Unable to find {} in {}!".format(name, security_group)} + result = {"error": f"Unable to find {name} in {security_group}!"} except KeyError as exc: log.error("Unable to find %s in %s!", name, security_group) result = {"error": str(exc)} @@ -311,7 +311,7 @@ def security_rule_create_or_update( destination_address_prefixes=None, source_port_ranges=None, destination_port_ranges=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -398,7 +398,7 @@ def security_rule_create_or_update( # pylint: disable=eval-used if eval(params[0]): # pylint: disable=exec-used - exec("{} = None".format(params[1])) + exec(f"{params[1]} = None") netconn = __utils__["azurearm.get_client"]("network", **kwargs) @@ -419,10 +419,10 @@ def security_rule_create_or_update( destination_port_range=destination_port_range, destination_address_prefixes=destination_address_prefixes, destination_address_prefix=destination_address_prefix, - **kwargs + **kwargs, ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -439,9 +439,7 @@ def security_rule_create_or_update( __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -559,7 +557,7 @@ def network_security_group_create_or_update( "network", "NetworkSecurityGroup", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -575,9 +573,7 @@ def network_security_group_create_or_update( __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -817,7 +813,7 @@ def subnet_create_or_update( nsg = network_security_group_get( name=kwargs["network_security_group"], resource_group=resource_group, - **kwargs + **kwargs, ) if "error" not in nsg: kwargs["network_security_group"] = {"id": str(nsg["id"])} @@ -836,10 +832,10 @@ def subnet_create_or_update( "Subnet", address_prefix=address_prefix, resource_group=resource_group, - **kwargs + **kwargs, ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -856,9 +852,7 @@ def subnet_create_or_update( __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -1014,10 +1008,10 @@ def virtual_network_create_or_update(name, address_prefixes, resource_group, **k "VirtualNetwork", address_space=address_space, dhcp_options=dhcp_options, - **kwargs + **kwargs, ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -1033,9 +1027,7 @@ def virtual_network_create_or_update(name, address_prefixes, resource_group, **k __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -1238,7 +1230,7 @@ def load_balancer_create_or_update(name, resource_group, **kwargs): pub_ip = public_ip_address_get( name=kwargs["frontend_ip_configurations"][idx]["public_ip_address"], resource_group=resource_group, - **kwargs + **kwargs, ) if "error" not in pub_ip: kwargs["frontend_ip_configurations"][idx]["public_ip_address"] = { @@ -1252,7 +1244,7 @@ def load_balancer_create_or_update(name, resource_group, **kwargs): subnets = subnets_list( virtual_network=vnet, resource_group=resource_group, - **kwargs + **kwargs, ) if ( kwargs["frontend_ip_configurations"][idx]["subnet"] @@ -1364,7 +1356,7 @@ def load_balancer_create_or_update(name, resource_group, **kwargs): "network", "LoadBalancer", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -1380,9 +1372,7 @@ def load_balancer_create_or_update(name, resource_group, **kwargs): __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -1562,7 +1552,7 @@ def network_interface_create_or_update( nsg = network_security_group_get( name=kwargs["network_security_group"], resource_group=resource_group, - **kwargs + **kwargs, ) if "error" not in nsg: kwargs["network_security_group"] = {"id": str(nsg["id"])} @@ -1581,7 +1571,7 @@ def network_interface_create_or_update( name=subnet, virtual_network=virtual_network, resource_group=resource_group, - **kwargs + **kwargs, ) if "error" not in subnet: subnet = {"id": str(subnet["id"])} @@ -1607,7 +1597,7 @@ def network_interface_create_or_update( pub_ip = public_ip_address_get( name=ipconfig["public_ip_address"], resource_group=resource_group, - **kwargs + **kwargs, ) if "error" not in pub_ip: ipconfig["public_ip_address"] = {"id": str(pub_ip["id"])} @@ -1617,7 +1607,7 @@ def network_interface_create_or_update( "network", "NetworkInterface", ip_configurations=ip_configurations, **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -1633,9 +1623,7 @@ def network_interface_create_or_update( __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -2014,7 +2002,7 @@ def public_ip_address_create_or_update(name, resource_group, **kwargs): "network", "PublicIPAddress", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -2030,9 +2018,7 @@ def public_ip_address_create_or_update(name, resource_group, **kwargs): __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -2225,10 +2211,10 @@ def route_filter_rule_create_or_update( "RouteFilterRule", access=access, communities=communities, - **kwargs + **kwargs, ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -2248,9 +2234,7 @@ def route_filter_rule_create_or_update( __utils__["azurearm.log_cloud_error"]("network", message, **kwargs) result = {"error": message} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -2396,7 +2380,7 @@ def route_filter_create_or_update(name, resource_group, **kwargs): "network", "RouteFilter", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -2412,9 +2396,7 @@ def route_filter_create_or_update(name, resource_group, **kwargs): __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -2567,7 +2549,7 @@ def route_create_or_update( route_table, resource_group, next_hop_ip_address=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -2605,10 +2587,10 @@ def route_create_or_update( address_prefix=address_prefix, next_hop_type=next_hop_type, next_hop_ip_address=next_hop_ip_address, - **kwargs + **kwargs, ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -2625,9 +2607,7 @@ def route_create_or_update( __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -2773,7 +2753,7 @@ def route_table_create_or_update(name, resource_group, **kwargs): "network", "RouteTable", **kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -2789,9 +2769,7 @@ def route_table_create_or_update(name, resource_group, **kwargs): __utils__["azurearm.log_cloud_error"]("network", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result diff --git a/salt/modules/azurearm_resource.py b/salt/modules/azurearm_resource.py index b1b865a81d1..a1a24af4c82 100644 --- a/salt/modules/azurearm_resource.py +++ b/salt/modules/azurearm_resource.py @@ -414,7 +414,7 @@ def deployment_create_or_update( parameters_link=None, deploy_template=None, template_link=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -489,7 +489,7 @@ def deployment_create_or_update( "resource", "DeploymentProperties", **deploy_kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -511,9 +511,7 @@ def deployment_create_or_update( __utils__["azurearm.log_cloud_error"]("resource", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -592,7 +590,7 @@ def deployment_validate( parameters_link=None, deploy_template=None, template_link=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -668,7 +666,7 @@ def deployment_validate( "resource", "DeploymentProperties", **deploy_kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -686,9 +684,7 @@ def deployment_validate( __utils__["azurearm.log_cloud_error"]("resource", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result @@ -981,9 +977,7 @@ def policy_assignment_create(name, scope, definition_name, **kwargs): "resource.policy", "PolicyAssignment", **policy_kwargs ) except TypeError as exc: - result = { - "error": "The object model could not be built. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -995,9 +989,7 @@ def policy_assignment_create(name, scope, definition_name, **kwargs): __utils__["azurearm.log_cloud_error"]("resource", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} else: result = { "error": 'The policy definition named "{}" could not be found.'.format( @@ -1146,7 +1138,7 @@ def policy_definition_create_or_update( "resource.policy", "PolicyDefinition", **policy_kwargs ) except TypeError as exc: - result = {"error": "The object model could not be built. ({})".format(str(exc))} + result = {"error": f"The object model could not be built. ({str(exc)})"} return result try: @@ -1158,9 +1150,7 @@ def policy_definition_create_or_update( __utils__["azurearm.log_cloud_error"]("resource", str(exc), **kwargs) result = {"error": str(exc)} except SerializationError as exc: - result = { - "error": "The object model could not be parsed. ({})".format(str(exc)) - } + result = {"error": f"The object model could not be parsed. ({str(exc)})"} return result diff --git a/salt/modules/bamboohr.py b/salt/modules/bamboohr.py index 5cdd05bee8e..e1582ff9a3f 100644 --- a/salt/modules/bamboohr.py +++ b/salt/modules/bamboohr.py @@ -175,8 +175,8 @@ def update_employee(emp_id, key=None, value=None, items=None): xml_items = "" for pair in items: - xml_items += '{}'.format(pair, items[pair]) - xml_items = "{}".format(xml_items) + xml_items += f'{items[pair]}' + xml_items = f"{xml_items}" status, result = _query( action="employees", @@ -259,13 +259,13 @@ def _query(action=None, command=None, args=None, method="GET", data=None): The password can be any random text, so we chose Salty text. """ subdomain = __opts__.get("bamboohr", {}).get("subdomain", None) - path = "https://api.bamboohr.com/api/gateway.php/{}/v1/".format(subdomain) + path = f"https://api.bamboohr.com/api/gateway.php/{subdomain}/v1/" if action: path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("BambooHR URL: %s", path) diff --git a/salt/modules/baredoc.py b/salt/modules/baredoc.py index aa867102bd4..7513b546919 100644 --- a/salt/modules/baredoc.py +++ b/salt/modules/baredoc.py @@ -122,9 +122,9 @@ def _parse_module_docs(module_path, mod_name=None): function_name = v if mod_name and "." in mod_name: if function_name == mod_name.split(".")[1]: - ret["{}.{}".format(module_name, function_name)] = doc_string + ret[f"{module_name}.{function_name}"] = doc_string else: - ret["{}.{}".format(module_name, function_name)] = doc_string + ret[f"{module_name}.{function_name}"] = doc_string return salt.utils.doc.strip_rst(ret) diff --git a/salt/modules/bcache.py b/salt/modules/bcache.py index 7e69b45ad57..acd4fdbcd56 100644 --- a/salt/modules/bcache.py +++ b/salt/modules/bcache.py @@ -117,14 +117,14 @@ def attach_(dev=None): "attach", cache, "error", - "Error attaching {} to bcache {}".format(dev, cache), + f"Error attaching {dev} to bcache {cache}", ): return False return _wait( lambda: uuid(dev) == cache, "error", - "{} received attach to bcache {}, but did not comply".format(dev, cache), + f"{dev} received attach to bcache {cache}, but did not comply", ) @@ -153,12 +153,12 @@ def detach(dev=None): return res if res else None log.debug("Detaching %s", dev) - if not _bcsys(dev, "detach", "goaway", "error", "Error detaching {}".format(dev)): + if not _bcsys(dev, "detach", "goaway", "error", f"Error detaching {dev}"): return False return _wait( lambda: uuid(dev) is False, "error", - "{} received detach, but did not comply".format(dev), + f"{dev} received detach, but did not comply", 300, ) @@ -203,12 +203,12 @@ def stop(dev=None): """ if dev is not None: log.warning("Stopping %s, device will only reappear after reregistering!", dev) - if not _bcsys(dev, "stop", "goaway", "error", "Error stopping {}".format(dev)): + if not _bcsys(dev, "stop", "goaway", "error", f"Error stopping {dev}"): return False return _wait( lambda: _sysfs_attr(_bcpath(dev)) is False, "error", - "Device {} did not stop".format(dev), + f"Device {dev} did not stop", 300, ) else: @@ -271,19 +271,19 @@ def back_make(dev, cache_mode="writeback", force=False, attach=True, bucket_size if force: cmd += " --wipe-bcache" - if not _run_all(cmd, "error", "Error creating backing device {}: %s".format(dev)): + if not _run_all(cmd, "error", f"Error creating backing device {dev}: %s"): return False elif not _sysfs_attr( "fs/bcache/register", _devpath(dev), "error", - "Error registering backing device {}".format(dev), + f"Error registering backing device {dev}", ): return False elif not _wait( lambda: _sysfs_attr(_bcpath(dev)) is not False, "error", - "Backing device {} did not register".format(dev), + f"Backing device {dev} did not register", ): return False elif attach: @@ -370,25 +370,23 @@ def cache_make( ) # if wipe was incomplete & part layout remains the same, # this is one condition set where udev would make it accidentally popup again - if not _run_all( - cmd, "error", "Error creating bcache partitions on {}: %s".format(dev) - ): + if not _run_all(cmd, "error", f"Error creating bcache partitions on {dev}: %s"): return False - dev = "{}2".format(dev) + dev = f"{dev}2" # ---------------- Finally, create a cache ---------------- - cmd = "make-bcache --cache /dev/{} --block {} --wipe-bcache".format(dev, block_size) + cmd = f"make-bcache --cache /dev/{dev} --block {block_size} --wipe-bcache" # Actually bucket_size should always have a value, but for testing 0 is possible as well if bucket_size: - cmd += " --bucket {}".format(bucket_size) + cmd += f" --bucket {bucket_size}" - if not _run_all(cmd, "error", "Error creating cache {}: %s".format(dev)): + if not _run_all(cmd, "error", f"Error creating cache {dev}: %s"): return False elif not _wait( lambda: uuid() is not False, "error", - "Cache {} seemingly created OK, but FS did not activate".format(dev), + f"Cache {dev} seemingly created OK, but FS did not activate", ): return False @@ -430,7 +428,7 @@ def config_(dev=None, **kwargs): [spath, key], val, "warn", - "Failed to update {} with {}".format(os.path.join(spath, key), val), + f"Failed to update {os.path.join(spath, key)} with {val}", ) return endres > 0 else: @@ -470,7 +468,7 @@ def status(stats=False, config=False, internals=False, superblock=False, alldevs continue for spath, sdirs, _ in salt.utils.path.os_walk( - "/sys/block/{}".format(block), followlinks=False + f"/sys/block/{block}", followlinks=False ): if "bcache" in sdirs: bdevs.append(os.path.basename(spath)) @@ -514,7 +512,7 @@ def device(dev, stats=False, config=False, internals=False, superblock=False): result = {} if not _sysfs_attr( - _bcpath(dev), None, "error", "{} is not a bcache fo any kind".format(dev) + _bcpath(dev), None, "error", f"{dev} is not a bcache fo any kind" ): return False elif _bcsys(dev, "set"): @@ -632,9 +630,9 @@ def super_(dev): ret = {} res = _run_all( - "bcache-super-show {}".format(dev), + f"bcache-super-show {dev}", "error", - "Error reading superblock on {}: %s".format(dev), + f"Error reading superblock on {dev}: %s", ) if not res: return False @@ -992,18 +990,18 @@ def _wipe(dev): else: wiper = "blkdiscard" - wipe_failmsg = "Error wiping {}: %s".format(dev) + wipe_failmsg = f"Error wiping {dev}: %s" if wiper == "dd": blocks = 4 - cmd = "dd if=/dev/zero of=/dev/{} bs=1M count={}".format(dev, blocks) + cmd = f"dd if=/dev/zero of=/dev/{dev} bs=1M count={blocks}" endres += _run_all(cmd, "warn", wipe_failmsg) # Some stuff (GPT) writes stuff at the end of a dev as well - cmd += " seek={}".format((size / 1024**2) - blocks) + cmd += f" seek={(size / 1024**2) - blocks}" endres += _run_all(cmd, "warn", wipe_failmsg) elif wiper == "blkdiscard": - cmd = "blkdiscard /dev/{}".format(dev) + cmd = f"blkdiscard /dev/{dev}" endres += _run_all(cmd, "warn", wipe_failmsg) # TODO: fix annoying bug failing blkdiscard by trying to discard 1 sector past blkdev endres = 1 diff --git a/salt/modules/beacons.py b/salt/modules/beacons.py index 0a759fbd7e5..e482abcf235 100644 --- a/salt/modules/beacons.py +++ b/salt/modules/beacons.py @@ -138,10 +138,10 @@ def add(name, beacon_data, **kwargs): salt '*' beacons.add ps "[{'processes': {'salt-master': 'stopped', 'apache2': 'stopped'}}]" """ - ret = {"comment": "Failed to add beacon {}.".format(name), "result": False} + ret = {"comment": f"Failed to add beacon {name}.", "result": False} if name in list_(return_yaml=False, **kwargs): - ret["comment"] = "Beacon {} is already configured.".format(name) + ret["comment"] = f"Beacon {name} is already configured." ret["result"] = True return ret @@ -154,12 +154,12 @@ def add(name, beacon_data, **kwargs): beacon_name = name if beacon_name not in list_available(return_yaml=False, **kwargs): - ret["comment"] = 'Beacon "{}" is not available.'.format(beacon_name) + ret["comment"] = f'Beacon "{beacon_name}" is not available.' return ret if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"] = "Beacon: {} would be added.".format(name) + ret["comment"] = f"Beacon: {name} would be added." else: try: # Attempt to load the beacon module so we have access to the validate function @@ -215,7 +215,7 @@ def add(name, beacon_data, **kwargs): [item in beacons[name] for item in beacon_data] ): ret["result"] = True - ret["comment"] = "Added beacon: {}.".format(name) + ret["comment"] = f"Added beacon: {name}." elif event_ret: ret["result"] = False ret["comment"] = event_ret["comment"] @@ -254,12 +254,12 @@ def modify(name, beacon_data, **kwargs): current_beacons = list_(return_yaml=False, **kwargs) if name not in current_beacons: - ret["comment"] = "Beacon {} is not configured.".format(name) + ret["comment"] = f"Beacon {name} is not configured." return ret if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"] = "Beacon: {} would be modified.".format(name) + ret["comment"] = f"Beacon: {name} would be modified." else: try: # Attempt to load the beacon module so we have access to the validate function @@ -310,19 +310,17 @@ def modify(name, beacon_data, **kwargs): _new = beacon_data if _new == _current: - ret["comment"] = "Job {} in correct state".format(name) + ret["comment"] = f"Job {name} in correct state" return ret _current_lines = [] for _item in _current: _current_lines.extend( - ["{}:{}\n".format(key, value) for (key, value) in _item.items()] + [f"{key}:{value}\n" for (key, value) in _item.items()] ) _new_lines = [] for _item in _new: - _new_lines.extend( - ["{}:{}\n".format(key, value) for (key, value) in _item.items()] - ) + _new_lines.extend([f"{key}:{value}\n" for (key, value) in _item.items()]) _diff = difflib.unified_diff(_current_lines, _new_lines) ret["changes"] = {} @@ -345,7 +343,7 @@ def modify(name, beacon_data, **kwargs): beacons = event_ret["beacons"] if name in beacons and beacons[name] == beacon_data: ret["result"] = True - ret["comment"] = "Modified beacon: {}.".format(name) + ret["comment"] = f"Modified beacon: {name}." elif event_ret: ret["result"] = False ret["comment"] = event_ret["comment"] @@ -382,11 +380,11 @@ def delete(name, **kwargs): """ - ret = {"comment": "Failed to delete beacon {}.".format(name), "result": False} + ret = {"comment": f"Failed to delete beacon {name}.", "result": False} if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"] = "Beacon: {} would be deleted.".format(name) + ret["comment"] = f"Beacon: {name} would be deleted." else: try: with salt.utils.event.get_event( @@ -404,7 +402,7 @@ def delete(name, **kwargs): beacons = event_ret["beacons"] if name not in beacons: ret["result"] = True - ret["comment"] = "Deleted beacon: {}.".format(name) + ret["comment"] = f"Deleted beacon: {name}." return ret elif event_ret: ret["result"] = False @@ -456,11 +454,9 @@ def save(**kwargs): try: with salt.utils.files.fopen(sfn, "w+") as fp_: fp_.write(yaml_out) - ret["comment"] = "Beacons saved to {}.".format(sfn) + ret["comment"] = f"Beacons saved to {sfn}." except OSError: - ret["comment"] = ( - "Unable to write to beacons file at {}. Check permissions.".format(sfn) - ) + ret["comment"] = f"Unable to write to beacons file at {sfn}. Check permissions." ret["result"] = False return ret @@ -603,11 +599,11 @@ def enable_beacon(name, **kwargs): return ret if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Beacon {} would be enabled.".format(name) + ret["comment"] = f"Beacon {name} would be enabled." else: _beacons = list_(return_yaml=False, **kwargs) if name not in _beacons: - ret["comment"] = "Beacon {} is not currently configured.".format(name) + ret["comment"] = f"Beacon {name} is not currently configured." ret["result"] = False return ret @@ -632,11 +628,11 @@ def enable_beacon(name, **kwargs): and beacon_config_dict["enabled"] ): ret["result"] = True - ret["comment"] = "Enabled beacon {} on minion.".format(name) + ret["comment"] = f"Enabled beacon {name} on minion." else: ret["result"] = False ret["comment"] = ( - "Failed to enable beacon {} on minion.".format(name) + f"Failed to enable beacon {name} on minion." ) elif event_ret: ret["result"] = False @@ -685,7 +681,7 @@ def disable_beacon(name, **kwargs): else: _beacons = list_(return_yaml=False, **kwargs) if name not in _beacons: - ret["comment"] = "Beacon {} is not currently configured.".format(name) + ret["comment"] = f"Beacon {name} is not currently configured." ret["result"] = False return ret diff --git a/salt/modules/bigip.py b/salt/modules/bigip.py index 219afea9726..6624b85c6f8 100644 --- a/salt/modules/bigip.py +++ b/salt/modules/bigip.py @@ -48,9 +48,7 @@ def _build_session(username, password, trans_label=None): if trans_label: # pull the trans id from the grain - trans_id = __salt__["grains.get"]( - "bigip_f5_trans:{label}".format(label=trans_label) - ) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{trans_label}") if trans_id: bigip.headers.update({"X-F5-REST-Coordination-Id": trans_id}) @@ -311,7 +309,7 @@ def list_transaction(hostname, username, password, label): bigip_session = _build_session(username, password) # pull the trans id from the grain - trans_id = __salt__["grains.get"]("bigip_f5_trans:{label}".format(label=label)) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}") if trans_id: @@ -319,7 +317,7 @@ def list_transaction(hostname, username, password, label): try: response = bigip_session.get( BIG_IP_URL_BASE.format(host=hostname) - + "/transaction/{trans_id}/commands".format(trans_id=trans_id) + + f"/transaction/{trans_id}/commands" ) return _load_response(response) except requests.exceptions.ConnectionError as e: @@ -356,7 +354,7 @@ def commit_transaction(hostname, username, password, label): bigip_session = _build_session(username, password) # pull the trans id from the grain - trans_id = __salt__["grains.get"]("bigip_f5_trans:{label}".format(label=label)) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}") if trans_id: @@ -366,8 +364,7 @@ def commit_transaction(hostname, username, password, label): # patch to REST to get trans id try: response = bigip_session.patch( - BIG_IP_URL_BASE.format(host=hostname) - + "/transaction/{trans_id}".format(trans_id=trans_id), + BIG_IP_URL_BASE.format(host=hostname) + f"/transaction/{trans_id}", data=salt.utils.json.dumps(payload), ) return _load_response(response) @@ -405,15 +402,14 @@ def delete_transaction(hostname, username, password, label): bigip_session = _build_session(username, password) # pull the trans id from the grain - trans_id = __salt__["grains.get"]("bigip_f5_trans:{label}".format(label=label)) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}") if trans_id: # patch to REST to get trans id try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) - + "/transaction/{trans_id}".format(trans_id=trans_id) + BIG_IP_URL_BASE.format(host=hostname) + f"/transaction/{trans_id}" ) return _load_response(response) except requests.exceptions.ConnectionError as e: @@ -457,8 +453,7 @@ def list_node(hostname, username, password, name=None, trans_label=None): try: if name: response = bigip_session.get( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/node/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}" ) else: response = bigip_session.get( @@ -593,8 +588,7 @@ def modify_node( # put to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/node/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -632,7 +626,7 @@ def delete_node(hostname, username, password, name, trans_label=None): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) + "/ltm/node/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -672,7 +666,7 @@ def list_pool(hostname, username, password, name=None): if name: response = bigip_session.get( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/?expandSubcollections=true".format(name=name) + + f"/ltm/pool/{name}/?expandSubcollections=true" ) else: response = bigip_session.get( @@ -991,8 +985,7 @@ def modify_pool( # post to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1027,7 +1020,7 @@ def delete_pool(hostname, username, password, name): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) + "/ltm/pool/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -1098,8 +1091,7 @@ def replace_pool_members(hostname, username, password, name, members): # put to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1155,8 +1147,7 @@ def add_pool_member(hostname, username, password, name, member): # post to REST try: response = bigip_session.post( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/members".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}/members", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1254,7 +1245,7 @@ def modify_pool_member( try: response = bigip_session.put( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/members/{member}".format(name=name, member=member), + + f"/ltm/pool/{name}/members/{member}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1291,8 +1282,7 @@ def delete_pool_member(hostname, username, password, name, member): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/members/{member}".format(name=name, member=member) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}/members/{member}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -1332,7 +1322,7 @@ def list_virtual(hostname, username, password, name=None): if name: response = bigip_session.get( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/virtual/{name}/?expandSubcollections=true".format(name=name) + + f"/ltm/virtual/{name}/?expandSubcollections=true" ) else: response = bigip_session.get( @@ -1925,8 +1915,7 @@ def modify_virtual( # put to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/virtual/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/virtual/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1961,8 +1950,7 @@ def delete_virtual(hostname, username, password, name): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/virtual/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/virtual/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2017,8 +2005,7 @@ def list_monitor( ) else: response = bigip_session.get( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}".format(type=monitor_type) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/monitor/{monitor_type}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2069,8 +2056,7 @@ def create_monitor(hostname, username, password, monitor_type, name, **kwargs): # post to REST try: response = bigip_session.post( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}".format(type=monitor_type), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/monitor/{monitor_type}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2123,7 +2109,7 @@ def modify_monitor(hostname, username, password, monitor_type, name, **kwargs): try: response = bigip_session.put( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}/{name}".format(type=monitor_type, name=name), + + f"/ltm/monitor/{monitor_type}/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2162,7 +2148,7 @@ def delete_monitor(hostname, username, password, monitor_type, name): try: response = bigip_session.delete( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}/{name}".format(type=monitor_type, name=name) + + f"/ltm/monitor/{monitor_type}/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2217,8 +2203,7 @@ def list_profile( ) else: response = bigip_session.get( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}".format(type=profile_type) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/profile/{profile_type}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2302,8 +2287,7 @@ def create_profile(hostname, username, password, profile_type, name, **kwargs): # post to REST try: response = bigip_session.post( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}".format(type=profile_type), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/profile/{profile_type}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2396,7 +2380,7 @@ def modify_profile(hostname, username, password, profile_type, name, **kwargs): try: response = bigip_session.put( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}/{name}".format(type=profile_type, name=name), + + f"/ltm/profile/{profile_type}/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2435,7 +2419,7 @@ def delete_profile(hostname, username, password, profile_type, name): try: response = bigip_session.delete( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}/{name}".format(type=profile_type, name=name) + + f"/ltm/profile/{profile_type}/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) diff --git a/salt/modules/bluez_bluetooth.py b/salt/modules/bluez_bluetooth.py index 043c404bb73..1813e7014ef 100644 --- a/salt/modules/bluez_bluetooth.py +++ b/salt/modules/bluez_bluetooth.py @@ -81,7 +81,7 @@ def address_(): dev = comps[0] ret[dev] = { "device": dev, - "path": "/sys/class/bluetooth/{}".format(dev), + "path": f"/sys/class/bluetooth/{dev}", } if "BD Address" in line: comps = line.split() @@ -113,7 +113,7 @@ def power(dev, mode): else: state = "down" mode = "off" - cmd = "hciconfig {} {}".format(dev, state) + cmd = f"hciconfig {dev} {state}" __salt__["cmd.run"](cmd).splitlines() info = address_() if info[dev]["power"] == mode: @@ -134,9 +134,9 @@ def discoverable(dev): if dev not in address_(): raise CommandExecutionError("Invalid dev passed to bluetooth.discoverable") - cmd = "hciconfig {} iscan".format(dev) + cmd = f"hciconfig {dev} iscan" __salt__["cmd.run"](cmd).splitlines() - cmd = "hciconfig {}".format(dev) + cmd = f"hciconfig {dev}" out = __salt__["cmd.run"](cmd) if "UP RUNNING ISCAN" in out: return True @@ -156,9 +156,9 @@ def noscan(dev): if dev not in address_(): raise CommandExecutionError("Invalid dev passed to bluetooth.noscan") - cmd = "hciconfig {} noscan".format(dev) + cmd = f"hciconfig {dev} noscan" __salt__["cmd.run"](cmd).splitlines() - cmd = "hciconfig {}".format(dev) + cmd = f"hciconfig {dev}" out = __salt__["cmd.run"](cmd) if "SCAN" in out: return False @@ -195,7 +195,7 @@ def block(bdaddr): if not salt.utils.validate.net.mac(bdaddr): raise CommandExecutionError("Invalid BD address passed to bluetooth.block") - cmd = "hciconfig {} block".format(bdaddr) + cmd = f"hciconfig {bdaddr} block" __salt__["cmd.run"](cmd).splitlines() @@ -212,7 +212,7 @@ def unblock(bdaddr): if not salt.utils.validate.net.mac(bdaddr): raise CommandExecutionError("Invalid BD address passed to bluetooth.unblock") - cmd = "hciconfig {} unblock".format(bdaddr) + cmd = f"hciconfig {bdaddr} unblock" __salt__["cmd.run"](cmd).splitlines() @@ -268,7 +268,7 @@ def unpair(address): if not salt.utils.validate.net.mac(address): raise CommandExecutionError("Invalid BD address passed to bluetooth.unpair") - cmd = "bluez-test-device remove {}".format(address) + cmd = f"bluez-test-device remove {address}" out = __salt__["cmd.run"](cmd).splitlines() return out diff --git a/salt/modules/boto3_elasticache.py b/salt/modules/boto3_elasticache.py index 1e52ea25a2c..ec644d92ccb 100644 --- a/salt/modules/boto3_elasticache.py +++ b/salt/modules/boto3_elasticache.py @@ -107,7 +107,7 @@ def _describe_resource( key=None, keyid=None, profile=None, - **args + **args, ): if conn is None: conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) @@ -115,9 +115,7 @@ def _describe_resource( func = "describe_" + res_type + "s" f = getattr(conn, func) except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") # Undocumented, but you can't pass 'Marker' if searching for a specific resource... args.update({name_param: name} if name else {"Marker": ""}) args = {k: v for k, v in args.items() if not k.startswith("_")} @@ -140,7 +138,7 @@ def _delete_resource( key=None, keyid=None, profile=None, - **args + **args, ): """ Delete a generic Elasticache resource. @@ -171,9 +169,7 @@ def _delete_resource( func = "describe_" + res_type + "s" s = globals()[func] except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") try: f(**args) @@ -211,7 +207,7 @@ def _create_resource( key=None, keyid=None, profile=None, - **args + **args, ): try: wait = int(wait) @@ -239,9 +235,7 @@ def _create_resource( func = "describe_" + res_type + "s" s = globals()[func] except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") try: f(**args) if not wait: @@ -270,7 +264,7 @@ def _create_resource( ) return False except botocore.exceptions.ClientError as e: - msg = "Failed to create {} {}: {}".format(desc, name, e) + msg = f"Failed to create {desc} {name}: {e}" log.error(msg) return False @@ -287,7 +281,7 @@ def _modify_resource( key=None, keyid=None, profile=None, - **args + **args, ): try: wait = int(wait) @@ -315,9 +309,7 @@ def _modify_resource( func = "describe_" + res_type + "s" s = globals()[func] except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") try: f(**args) if not wait: @@ -346,7 +338,7 @@ def _modify_resource( ) return False except botocore.exceptions.ClientError as e: - msg = "Failed to modify {} {}: {}".format(desc, name, e) + msg = f"Failed to modify {desc} {name}: {e}" log.error(msg) return False @@ -374,7 +366,7 @@ def describe_cache_clusters( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -405,7 +397,7 @@ def create_cache_cluster( key=None, keyid=None, profile=None, - **args + **args, ): """ Create a cache cluster. @@ -442,7 +434,7 @@ def create_cache_cluster( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -454,7 +446,7 @@ def modify_cache_cluster( key=None, keyid=None, profile=None, - **args + **args, ): """ Update a cache cluster in place. @@ -496,7 +488,7 @@ def modify_cache_cluster( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -523,7 +515,7 @@ def delete_cache_cluster( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -578,7 +570,7 @@ def create_replication_group( key=None, keyid=None, profile=None, - **args + **args, ): """ Create a replication group. @@ -615,7 +607,7 @@ def create_replication_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -627,7 +619,7 @@ def modify_replication_group( key=None, keyid=None, profile=None, - **args + **args, ): """ Modify a replication group. @@ -661,7 +653,7 @@ def modify_replication_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -688,7 +680,7 @@ def delete_replication_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -783,13 +775,13 @@ def create_cache_subnet_group( ).get("subnets") if not sn: raise SaltInvocationError( - "Could not resolve Subnet Name {} to an ID.".format(subnet) + f"Could not resolve Subnet Name {subnet} to an ID." ) if len(sn) == 1: args["SubnetIds"] += [sn[0]["id"]] elif len(sn) > 1: raise CommandExecutionError( - "Subnet Name {} returned more than one ID.".format(subnet) + f"Subnet Name {subnet} returned more than one ID." ) args = {k: v for k, v in args.items() if not k.startswith("_")} return _create_resource( @@ -801,7 +793,7 @@ def create_cache_subnet_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -836,14 +828,14 @@ def modify_cache_subnet_group( args["SubnetIds"] += [sn[0]["id"]] elif len(sn) > 1: raise CommandExecutionError( - "Subnet Name {} returned more than one ID.".format(subnet) + f"Subnet Name {subnet} returned more than one ID." ) elif subnet.startswith("subnet-"): # Moderately safe assumption... :) Will be caught later if incorrect. args["SubnetIds"] += [subnet] else: raise SaltInvocationError( - "Could not resolve Subnet Name {} to an ID.".format(subnet) + f"Could not resolve Subnet Name {subnet} to an ID." ) args = {k: v for k, v in args.items() if not k.startswith("_")} return _modify_resource( @@ -855,7 +847,7 @@ def modify_cache_subnet_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -880,7 +872,7 @@ def delete_cache_subnet_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -948,7 +940,7 @@ def create_cache_security_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -973,7 +965,7 @@ def delete_cache_security_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -1264,7 +1256,7 @@ def create_cache_parameter_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -1289,5 +1281,5 @@ def delete_cache_parameter_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) diff --git a/salt/modules/boto_apigateway.py b/salt/modules/boto_apigateway.py index c889f272648..ccaeb163ac5 100644 --- a/salt/modules/boto_apigateway.py +++ b/salt/modules/boto_apigateway.py @@ -132,7 +132,7 @@ def _convert_datetime_str(response): if response: return dict( [ - (k, "{}".format(v)) if isinstance(v, datetime.date) else (k, v) + (k, f"{v}") if isinstance(v, datetime.date) else (k, v) for k, v in response.items() ] ) @@ -379,9 +379,9 @@ def create_api_resources( conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) for path_part in path_parts: if current_path == "/": - current_path = "{}{}".format(current_path, path_part) + current_path = f"{current_path}{path_part}" else: - current_path = "{}/{}".format(current_path, path_part) + current_path = f"{current_path}/{path_part}" r = describe_api_resource( restApiId, current_path, @@ -432,7 +432,7 @@ def delete_api_resources( conn.delete_resource(restApiId=restApiId, resourceId=resource["id"]) return {"deleted": True} else: - return {"deleted": False, "error": "no resource found by {}".format(path)} + return {"deleted": False, "error": f"no resource found by {path}"} except ClientError as e: return {"created": False, "error": __utils__["boto3.get_error"](e)} @@ -896,12 +896,12 @@ def overwrite_api_stage_variables( for old_var in old_vars: if old_var not in variables: patch_ops.append( - dict(op="remove", path="/variables/{}".format(old_var), value="") + dict(op="remove", path=f"/variables/{old_var}", value="") ) for var, val in variables.items(): if var not in old_vars or old_vars[var] != val: patch_ops.append( - dict(op="replace", path="/variables/{}".format(var), value=val) + dict(op="replace", path=f"/variables/{var}", value=val) ) if patch_ops: @@ -1623,7 +1623,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region=region, key=key, keyid=keyid, profile=profile ) - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def create_api_integration( @@ -1800,7 +1800,7 @@ def _validate_throttle(throttle): if throttle is not None: if not isinstance(throttle, dict): raise TypeError( - "throttle must be a dictionary, provided value: {}".format(throttle) + f"throttle must be a dictionary, provided value: {throttle}" ) @@ -1810,9 +1810,7 @@ def _validate_quota(quota): """ if quota is not None: if not isinstance(quota, dict): - raise TypeError( - "quota must be a dictionary, provided value: {}".format(quota) - ) + raise TypeError(f"quota must be a dictionary, provided value: {quota}") periods = ["DAY", "WEEK", "MONTH"] if "period" not in quota or quota["period"] not in periods: raise ValueError( diff --git a/salt/modules/boto_asg.py b/salt/modules/boto_asg.py index a3ff1619b78..9d915c34ddb 100644 --- a/salt/modules/boto_asg.py +++ b/salt/modules/boto_asg.py @@ -120,7 +120,7 @@ def exists(name, region=None, key=None, keyid=None, profile=None): if _conn: return True else: - msg = "The autoscale group does not exist in region {}".format(region) + msg = f"The autoscale group does not exist in region {region}" log.debug(msg) return False except boto.exception.BotoServerError as e: @@ -430,12 +430,12 @@ def update( key = tag.get("key") except KeyError: log.error("Tag missing key.") - return False, "Tag {} missing key".format(tag) + return False, f"Tag {tag} missing key" try: value = tag.get("value") except KeyError: log.error("Tag missing value.") - return False, "Tag {} missing value".format(tag) + return False, f"Tag {tag} missing value" propagate_at_launch = tag.get("propagate_at_launch", False) _tag = { "key": key, @@ -509,7 +509,7 @@ def update( retries -= 1 continue log.error(e) - msg = "Failed to update ASG {}".format(name) + msg = f"Failed to update ASG {name}" log.error(msg) return False, str(e) @@ -570,7 +570,7 @@ def delete(name, force=False, region=None, key=None, keyid=None, profile=None): while True: try: conn.delete_auto_scaling_group(name, force) - msg = "Deleted autoscale group {}.".format(name) + msg = f"Deleted autoscale group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: @@ -580,7 +580,7 @@ def delete(name, force=False, region=None, key=None, keyid=None, profile=None): retries -= 1 continue log.error(e) - msg = "Failed to delete autoscale group {}".format(name) + msg = f"Failed to delete autoscale group {name}" log.error(msg) return False @@ -822,7 +822,7 @@ def create_launch_configuration( retries -= 1 continue log.error(e) - msg = "Failed to create LC {}".format(name) + msg = f"Failed to create LC {name}" log.error(msg) return False @@ -851,7 +851,7 @@ def delete_launch_configuration(name, region=None, key=None, keyid=None, profile retries -= 1 continue log.error(e) - msg = "Failed to delete LC {}".format(name) + msg = f"Failed to delete LC {name}" log.error(msg) return False diff --git a/salt/modules/boto_cfn.py b/salt/modules/boto_cfn.py index d02e82bc2b3..647bb185e42 100644 --- a/salt/modules/boto_cfn.py +++ b/salt/modules/boto_cfn.py @@ -185,7 +185,7 @@ def create( stack_policy_url, ) except BotoServerError as e: - msg = "Failed to create stack {}.\n{}".format(name, e) + msg = f"Failed to create stack {name}.\n{e}" log.error(msg) log.debug(e) return False @@ -245,7 +245,7 @@ def update_stack( log.debug("Updated result is : %s.", update) return update except BotoServerError as e: - msg = "Failed to update stack {}.".format(name) + msg = f"Failed to update stack {name}." log.debug(e) log.error(msg) return str(e) @@ -266,7 +266,7 @@ def delete(name, region=None, key=None, keyid=None, profile=None): try: return conn.delete_stack(name) except BotoServerError as e: - msg = "Failed to create stack {}.".format(name) + msg = f"Failed to create stack {name}." log.error(msg) log.debug(e) return str(e) @@ -290,7 +290,7 @@ def get_template(name, region=None, key=None, keyid=None, profile=None): return template except BotoServerError as e: log.debug(e) - msg = "Template {} does not exist".format(name) + msg = f"Template {name} does not exist" log.error(msg) return str(e) @@ -321,6 +321,6 @@ def validate_template( return conn.validate_template(template_body, template_url) except BotoServerError as e: log.debug(e) - msg = "Error while trying to validate template {}.".format(template_body) + msg = f"Error while trying to validate template {template_body}." log.error(msg) return str(e) diff --git a/salt/modules/boto_cloudfront.py b/salt/modules/boto_cloudfront.py index e9b72633ea4..33ac1b76652 100644 --- a/salt/modules/boto_cloudfront.py +++ b/salt/modules/boto_cloudfront.py @@ -256,7 +256,7 @@ def export_distributions(region=None, key=None, keyid=None, profile=None): {"config": config}, {"tags": tags}, ] - results["Manage CloudFront distribution {}".format(name)] = { + results[f"Manage CloudFront distribution {name}"] = { "boto_cloudfront.present": distribution_sls_data, } except botocore.exceptions.ClientError as exc: diff --git a/salt/modules/boto_cloudtrail.py b/salt/modules/boto_cloudtrail.py index 31d69846bee..0a789a86150 100644 --- a/salt/modules/boto_cloudtrail.py +++ b/salt/modules/boto_cloudtrail.py @@ -425,7 +425,7 @@ def _get_trail_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:cloudtrail:{}:{}:trail/{}".format(region, account_id, name) + return f"arn:aws:cloudtrail:{region}:{account_id}:trail/{name}" def add_tags(Name, region=None, key=None, keyid=None, profile=None, **kwargs): diff --git a/salt/modules/boto_cloudwatch_event.py b/salt/modules/boto_cloudwatch_event.py index 1fd40f018bb..7729cf715b8 100644 --- a/salt/modules/boto_cloudwatch_event.py +++ b/salt/modules/boto_cloudwatch_event.py @@ -215,7 +215,7 @@ def describe(Name, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} @@ -271,7 +271,7 @@ def list_targets(Rule, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} @@ -300,7 +300,7 @@ def put_targets(Rule, Targets, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} @@ -329,5 +329,5 @@ def remove_targets(Rule, Ids, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} diff --git a/salt/modules/boto_cognitoidentity.py b/salt/modules/boto_cognitoidentity.py index f675c1682b0..37943d28c1f 100644 --- a/salt/modules/boto_cognitoidentity.py +++ b/salt/modules/boto_cognitoidentity.py @@ -365,7 +365,7 @@ def set_identity_pool_roles( if role_arn is None: return { "set": False, - "error": "invalid AuthenticatedRole {}".format(AuthenticatedRole), + "error": f"invalid AuthenticatedRole {AuthenticatedRole}", } AuthenticatedRole = role_arn diff --git a/salt/modules/boto_datapipeline.py b/salt/modules/boto_datapipeline.py index bdbcebaa16a..b2cc6ca773f 100644 --- a/salt/modules/boto_datapipeline.py +++ b/salt/modules/boto_datapipeline.py @@ -181,7 +181,7 @@ def pipeline_id_from_name(name, region=None, key=None, keyid=None, profile=None) if pipeline["name"] == name: r["result"] = pipeline["id"] return r - r["error"] = "No pipeline found with name={}".format(name) + r["error"] = f"No pipeline found with name={name}" return r diff --git a/salt/modules/boto_ec2.py b/salt/modules/boto_ec2.py index 7ece2dbe6d3..f5f8a7fd3e6 100644 --- a/salt/modules/boto_ec2.py +++ b/salt/modules/boto_ec2.py @@ -685,7 +685,7 @@ def find_instances( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value if filters: filter_parameters["filters"].update(filters) @@ -810,7 +810,7 @@ def find_images( filter_parameters["filters"]["name"] = ami_name if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value images = conn.get_all_images(**filter_parameters) log.debug( "The filters criteria %s matched the following images:%s", @@ -1516,9 +1516,7 @@ def get_attribute( " command." ) if attribute not in attribute_list: - raise SaltInvocationError( - "Attribute must be one of: {}.".format(attribute_list) - ) + raise SaltInvocationError(f"Attribute must be one of: {attribute_list}.") try: if instance_name: instances = find_instances( @@ -1609,9 +1607,7 @@ def set_attribute( " command." ) if attribute not in attribute_list: - raise SaltInvocationError( - "Attribute must be one of: {}.".format(attribute_list) - ) + raise SaltInvocationError(f"Attribute must be one of: {attribute_list}.") try: if instance_name: instances = find_instances( @@ -1822,7 +1818,7 @@ def create_network_interface( ) vpc_id = vpc_id.get("vpc_id") if not vpc_id: - msg = "subnet_id {} does not map to a valid vpc id.".format(subnet_id) + msg = f"subnet_id {subnet_id} does not map to a valid vpc id." r["error"] = {"message": msg} return r _groups = __salt__["boto_secgroup.convert_to_group_ids"]( @@ -2231,7 +2227,7 @@ def set_volumes_tags( profile=profile, ) if not instance_id: - msg = "Couldn't resolve instance Name {} to an ID.".format(v) + msg = f"Couldn't resolve instance Name {v} to an ID." raise CommandExecutionError(msg) new_filters["attachment.instance_id"] = instance_id else: diff --git a/salt/modules/boto_elasticache.py b/salt/modules/boto_elasticache.py index 656182822bf..fdcec9d4962 100644 --- a/salt/modules/boto_elasticache.py +++ b/salt/modules/boto_elasticache.py @@ -157,7 +157,7 @@ def create_replication_group( if config["status"] == "available": return True except boto.exception.BotoServerError as e: - msg = "Failed to create replication group {}.".format(name) + msg = f"Failed to create replication group {name}." log.error(msg) log.debug(e) return {} @@ -179,12 +179,12 @@ def delete_replication_group(name, region=None, key=None, keyid=None, profile=No return False try: conn.delete_replication_group(name) - msg = "Deleted ElastiCache replication group {}.".format(name) + msg = f"Deleted ElastiCache replication group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: log.debug(e) - msg = "Failed to delete ElastiCache replication group {}".format(name) + msg = f"Failed to delete ElastiCache replication group {name}" log.error(msg) return False @@ -208,7 +208,7 @@ def describe_replication_group( try: cc = conn.describe_replication_groups(name) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -278,7 +278,7 @@ def get_config(name, region=None, key=None, keyid=None, profile=None): try: cc = conn.describe_cache_clusters(name, show_cache_node_info=True) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -357,7 +357,7 @@ def get_node_host(name, region=None, key=None, keyid=None, profile=None): try: cc = conn.describe_cache_clusters(name, show_cache_node_info=True) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -384,7 +384,7 @@ def get_group_host(name, region=None, key=None, keyid=None, profile=None): try: cc = conn.describe_replication_groups(name) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -465,7 +465,7 @@ def subnet_group_exists( try: ec = conn.describe_cache_subnet_groups(cache_subnet_group_name=name) if not ec: - msg = "ElastiCache subnet group does not exist in region {}".format(region) + msg = f"ElastiCache subnet group does not exist in region {region}" log.debug(msg) return False return True @@ -516,14 +516,14 @@ def create_subnet_group( try: ec = conn.create_cache_subnet_group(name, description, subnet_ids) if not ec: - msg = "Failed to create ElastiCache subnet group {}".format(name) + msg = f"Failed to create ElastiCache subnet group {name}" log.error(msg) return False log.info("Created ElastiCache subnet group %s", name) return True except boto.exception.BotoServerError as e: log.debug(e) - msg = "Failed to create ElastiCache subnet group {}".format(name) + msg = f"Failed to create ElastiCache subnet group {name}" log.error(msg) return False @@ -545,12 +545,12 @@ def get_cache_subnet_group(name, region=None, key=None, keyid=None, profile=None csg = csg["DescribeCacheSubnetGroupsResponse"] csg = csg["DescribeCacheSubnetGroupsResult"]["CacheSubnetGroups"][0] except boto.exception.BotoServerError as e: - msg = "Failed to get cache subnet group {}.".format(name) + msg = f"Failed to get cache subnet group {name}." log.error(msg) log.debug(e) return False except (IndexError, TypeError, KeyError): - msg = "Failed to get cache subnet group {} (2).".format(name) + msg = f"Failed to get cache subnet group {name} (2)." log.error(msg) return False ret = {} @@ -590,12 +590,12 @@ def delete_subnet_group(name, region=None, key=None, keyid=None, profile=None): return False try: conn.delete_cache_subnet_group(name) - msg = "Deleted ElastiCache subnet group {}.".format(name) + msg = f"Deleted ElastiCache subnet group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: log.debug(e) - msg = "Failed to delete ElastiCache subnet group {}".format(name) + msg = f"Failed to delete ElastiCache subnet group {name}" log.error(msg) return False @@ -666,7 +666,7 @@ def create( return True log.info("Created cache cluster %s.", name) except boto.exception.BotoServerError as e: - msg = "Failed to create cache cluster {}.".format(name) + msg = f"Failed to create cache cluster {name}." log.error(msg) log.debug(e) return False @@ -699,7 +699,7 @@ def delete(name, wait=False, region=None, key=None, keyid=None, profile=None): log.info("Deleted cache cluster %s.", name) return True except boto.exception.BotoServerError as e: - msg = "Failed to delete cache cluster {}.".format(name) + msg = f"Failed to delete cache cluster {name}." log.error(msg) log.debug(e) return False @@ -724,7 +724,7 @@ def create_cache_security_group( log.info("Created cache security group %s.", name) return True else: - msg = "Failed to create cache security group {}.".format(name) + msg = f"Failed to create cache security group {name}." log.error(msg) return False @@ -746,7 +746,7 @@ def delete_cache_security_group(name, region=None, key=None, keyid=None, profile log.info("Deleted cache security group %s.", name) return True else: - msg = "Failed to delete cache security group {}.".format(name) + msg = f"Failed to delete cache security group {name}." log.error(msg) return False diff --git a/salt/modules/boto_elasticsearch_domain.py b/salt/modules/boto_elasticsearch_domain.py index 5440435dc2d..ff11574685c 100644 --- a/salt/modules/boto_elasticsearch_domain.py +++ b/salt/modules/boto_elasticsearch_domain.py @@ -274,7 +274,7 @@ def create( except ValueError as e: return { "updated": False, - "error": "Error parsing {}: {}".format(k, e.message), + "error": f"Error parsing {k}: {e.message}", } kwargs[k] = val if "AccessPolicies" in kwargs: @@ -365,7 +365,7 @@ def update( except ValueError as e: return { "updated": False, - "error": "Error parsing {}: {}".format(k, e.message), + "error": f"Error parsing {k}: {e.message}", } call_args[k] = val if "AccessPolicies" in call_args: diff --git a/salt/modules/boto_elb.py b/salt/modules/boto_elb.py index a1aa8b16694..5c5d3c016b4 100644 --- a/salt/modules/boto_elb.py +++ b/salt/modules/boto_elb.py @@ -1102,9 +1102,9 @@ def _build_tag_param_list(params, tags): i = 1 for key in keys: value = tags[key] - params["Tags.member.{}.Key".format(i)] = key + params[f"Tags.member.{i}.Key"] = key if value is not None: - params["Tags.member.{}.Value".format(i)] = value + params[f"Tags.member.{i}.Value"] = value i += 1 diff --git a/salt/modules/boto_iam.py b/salt/modules/boto_iam.py index fc13002d5ab..54322e12eb5 100644 --- a/salt/modules/boto_iam.py +++ b/salt/modules/boto_iam.py @@ -1734,7 +1734,7 @@ def _get_policy_arn(name, region=None, key=None, keyid=None, profile=None): return name account_id = get_account_id(region=region, key=key, keyid=keyid, profile=profile) - return "arn:aws:iam::{}:policy/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:policy/{name}" def policy_exists(policy_name, region=None, key=None, keyid=None, profile=None): diff --git a/salt/modules/boto_iot.py b/salt/modules/boto_iot.py index b7b798487cb..7df25b47acf 100644 --- a/salt/modules/boto_iot.py +++ b/salt/modules/boto_iot.py @@ -149,7 +149,7 @@ def describe_thing_type(thingTypeName, region=None, key=None, keyid=None, profil for dtype in ("creationDate", "deprecationDate"): dval = thingTypeMetadata.get(dtype) if dval and isinstance(dval, datetime.date): - thingTypeMetadata[dtype] = "{}".format(dval) + thingTypeMetadata[dtype] = f"{dval}" return {"thing_type": res} else: return {"thing_type": None} @@ -916,7 +916,7 @@ def list_topic_rules( conn.list_topic_rules, marker_flag="nextToken", marker_arg="nextToken", - **kwargs + **kwargs, ): rules.extend(ret["rules"]) if not bool(rules): diff --git a/salt/modules/boto_kinesis.py b/salt/modules/boto_kinesis.py index 0c9e7b4b5eb..d2d999a733c 100644 --- a/salt/modules/boto_kinesis.py +++ b/salt/modules/boto_kinesis.py @@ -492,7 +492,7 @@ def reshard( # merge next_shard_id = _get_next_open_shard(stream_details, shard_id) if not next_shard_id: - r["error"] = "failed to find next shard after {}".format(shard_id) + r["error"] = f"failed to find next shard after {shard_id}" return r if force: log.debug( diff --git a/salt/modules/boto_lambda.py b/salt/modules/boto_lambda.py index 5a23660042e..87ef561c3c5 100644 --- a/salt/modules/boto_lambda.py +++ b/salt/modules/boto_lambda.py @@ -177,7 +177,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def _filedata(infile): @@ -273,7 +273,7 @@ def create_function( dlZipFile = __salt__["cp.cache_file"](path=ZipFile) if dlZipFile is False: ret["result"] = False - ret["comment"] = "Failed to cache ZipFile `{}`.".format(ZipFile) + ret["comment"] = f"Failed to cache ZipFile `{ZipFile}`." return ret ZipFile = dlZipFile code = { @@ -314,7 +314,7 @@ def create_function( Timeout=Timeout, MemorySize=MemorySize, Publish=Publish, - **kwargs + **kwargs, ) except ClientError as e: if ( @@ -646,7 +646,7 @@ def add_permission( StatementId=StatementId, Action=Action, Principal=str(Principal), - **kwargs + **kwargs, ) return {"updated": True} except ClientError as e: diff --git a/salt/modules/boto_rds.py b/salt/modules/boto_rds.py index a241935a5e7..9c65ee737ea 100644 --- a/salt/modules/boto_rds.py +++ b/salt/modules/boto_rds.py @@ -295,9 +295,7 @@ def create( if wait_status: wait_stati = ["available", "modifying", "backing-up"] if wait_status not in wait_stati: - raise SaltInvocationError( - "wait_status can be one of: {}".format(wait_stati) - ) + raise SaltInvocationError(f"wait_status can be one of: {wait_stati}") if vpc_security_groups: v_tmp = __salt__["boto_secgroup.convert_to_group_ids"]( groups=vpc_security_groups, @@ -337,7 +335,7 @@ def create( if not wait_status: return { "created": True, - "message": "RDS instance {} created.".format(name), + "message": f"RDS instance {name} created.", } while True: @@ -409,14 +407,14 @@ def create_read_replica( if not res.get("exists"): return { "exists": bool(res), - "message": "RDS instance source {} does not exists.".format(source_name), + "message": f"RDS instance source {source_name} does not exists.", } res = __salt__["boto_rds.exists"](name, tags, region, key, keyid, profile) if res.get("exists"): return { "exists": bool(res), - "message": "RDS replica instance {} already exists.".format(name), + "message": f"RDS replica instance {name} already exists.", } try: @@ -445,7 +443,7 @@ def create_read_replica( Tags=taglist, DBSubnetGroupName=db_subnet_group_name, StorageType=storage_type, - **kwargs + **kwargs, ) return {"exists": bool(rds_replica)} @@ -536,12 +534,12 @@ def create_parameter_group( if not rds: return { "created": False, - "message": "Failed to create RDS parameter group {}".format(name), + "message": f"Failed to create RDS parameter group {name}", } return { "exists": bool(rds), - "message": "Created RDS parameter group {}".format(name), + "message": f"Created RDS parameter group {name}", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -618,7 +616,7 @@ def update_parameter_group( if not res.get("exists"): return { "exists": bool(res), - "message": "RDS parameter group {} does not exist.".format(name), + "message": f"RDS parameter group {name} does not exist.", } param_list = [] @@ -663,7 +661,7 @@ def describe(name, tags=None, region=None, key=None, keyid=None, profile=None): if not res.get("exists"): return { "exists": bool(res), - "message": "RDS instance {} does not exist.".format(name), + "message": f"RDS instance {name} does not exist.", } try: @@ -868,7 +866,7 @@ def delete( if not wait_for_deletion: return { "deleted": bool(res), - "message": "Deleted RDS instance {}.".format(name), + "message": f"Deleted RDS instance {name}.", } start_time = time.time() @@ -884,7 +882,7 @@ def delete( if not res.get("exists"): return { "deleted": bool(res), - "message": "Deleted RDS instance {} completely.".format(name), + "message": f"Deleted RDS instance {name} completely.", } if time.time() - start_time > timeout: @@ -923,12 +921,12 @@ def delete_option_group(name, region=None, key=None, keyid=None, profile=None): if not res: return { "deleted": bool(res), - "message": "Failed to delete RDS option group {}.".format(name), + "message": f"Failed to delete RDS option group {name}.", } return { "deleted": bool(res), - "message": "Deleted RDS option group {}.".format(name), + "message": f"Deleted RDS option group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -953,7 +951,7 @@ def delete_parameter_group(name, region=None, key=None, keyid=None, profile=None r = conn.delete_db_parameter_group(DBParameterGroupName=name) return { "deleted": bool(r), - "message": "Deleted RDS parameter group {}.".format(name), + "message": f"Deleted RDS parameter group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -978,7 +976,7 @@ def delete_subnet_group(name, region=None, key=None, keyid=None, profile=None): r = conn.delete_db_subnet_group(DBSubnetGroupName=name) return { "deleted": bool(r), - "message": "Deleted RDS subnet group {}.".format(name), + "message": f"Deleted RDS subnet group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -1025,12 +1023,12 @@ def describe_parameter_group( if not info: return { "results": bool(info), - "message": "Failed to get RDS description for group {}.".format(name), + "message": f"Failed to get RDS description for group {name}.", } return { "results": bool(info), - "message": "Got RDS descrition for group {}.".format(name), + "message": f"Got RDS descrition for group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -1059,7 +1057,7 @@ def describe_parameters( if not res.get("exists"): return { "result": False, - "message": "Parameter group {} does not exist".format(name), + "message": f"Parameter group {name} does not exist", } try: @@ -1167,7 +1165,7 @@ def modify_db_instance( if not res.get("exists"): return { "modified": False, - "message": "RDS db instance {} does not exist.".format(name), + "message": f"RDS db instance {name} does not exist.", } try: @@ -1190,12 +1188,12 @@ def modify_db_instance( if not info: return { "modified": bool(info), - "message": "Failed to modify RDS db instance {}.".format(name), + "message": f"Failed to modify RDS db instance {name}.", } return { "modified": bool(info), - "message": "Modified RDS db instance {}.".format(name), + "message": f"Modified RDS db instance {name}.", "results": dict(info), } except ClientError as e: diff --git a/salt/modules/boto_route53.py b/salt/modules/boto_route53.py index ddacf0926b6..bee6cff4d3a 100644 --- a/salt/modules/boto_route53.py +++ b/salt/modules/boto_route53.py @@ -590,7 +590,7 @@ def get_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return None _type = record_type.upper() @@ -699,7 +699,7 @@ def add_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return False _type = record_type.upper() @@ -798,7 +798,7 @@ def update_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return False _type = record_type.upper() @@ -887,7 +887,7 @@ def delete_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return False _type = record_type.upper() diff --git a/salt/modules/boto_s3_bucket.py b/salt/modules/boto_s3_bucket.py index a696bd5d2ee..d461c320a76 100644 --- a/salt/modules/boto_s3_bucket.py +++ b/salt/modules/boto_s3_bucket.py @@ -774,7 +774,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def put_replication( diff --git a/salt/modules/boto_secgroup.py b/salt/modules/boto_secgroup.py index 2f0feb03814..9ecdb782900 100644 --- a/salt/modules/boto_secgroup.py +++ b/salt/modules/boto_secgroup.py @@ -510,7 +510,7 @@ def create( log.info("Created security group %s.", name) return True else: - msg = "Failed to create security group {}.".format(name) + msg = f"Failed to create security group {name}." log.error(msg) return False @@ -553,7 +553,7 @@ def delete( log.info("Deleted security group %s with id %s.", group.name, group.id) return True else: - msg = "Failed to delete security group {}.".format(name) + msg = f"Failed to delete security group {name}." log.error(msg) return False else: @@ -777,7 +777,7 @@ def _find_vpcs( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) log.debug( diff --git a/salt/modules/boto_sns.py b/salt/modules/boto_sns.py index dc160896e7f..2814f56ea41 100644 --- a/salt/modules/boto_sns.py +++ b/salt/modules/boto_sns.py @@ -236,7 +236,7 @@ def get_arn(name, region=None, key=None, keyid=None, profile=None): account_id = __salt__["boto_iam.get_account_id"]( region=region, key=key, keyid=keyid, profile=profile ) - return "arn:aws:sns:{}:{}:{}".format(_get_region(region, profile), account_id, name) + return f"arn:aws:sns:{_get_region(region, profile)}:{account_id}:{name}" def _get_region(region=None, profile=None): @@ -253,7 +253,7 @@ def _get_region(region=None, profile=None): def _subscriptions_cache_key(name): - return "{}_{}_subscriptions".format(_cache_get_key(), name) + return f"{_cache_get_key()}_{name}_subscriptions" def _invalidate_cache(): diff --git a/salt/modules/boto_vpc.py b/salt/modules/boto_vpc.py index 9b06a7b3db7..289a7a2fb78 100644 --- a/salt/modules/boto_vpc.py +++ b/salt/modules/boto_vpc.py @@ -243,7 +243,7 @@ def _create_resource( key=None, keyid=None, profile=None, - **kwargs + **kwargs, ): """ Create a VPC resource. Returns the resource id if created, or False @@ -266,9 +266,7 @@ def _create_resource( ): return { "created": False, - "error": { - "message": "A {} named {} already exists.".format(resource, name) - }, + "error": {"message": f"A {resource} named {name} already exists."}, } r = create_resource(**kwargs) @@ -294,9 +292,9 @@ def _create_resource( return {"created": True, "id": r.id} else: if name: - e = "{} {} was not created.".format(resource, name) + e = f"{resource} {name} was not created." else: - e = "{} was not created.".format(resource) + e = f"{resource} was not created." log.warning(e) return {"created": False, "error": {"message": e}} except BotoServerError as e: @@ -311,7 +309,7 @@ def _delete_resource( key=None, keyid=None, profile=None, - **kwargs + **kwargs, ): """ Delete a VPC resource. Returns True if successful, otherwise False. @@ -338,9 +336,7 @@ def _delete_resource( if not resource_id: return { "deleted": False, - "error": { - "message": "{} {} does not exist.".format(resource, name) - }, + "error": {"message": f"{resource} {name} does not exist."}, } if delete_resource(resource_id, **kwargs): @@ -357,9 +353,9 @@ def _delete_resource( return {"deleted": True} else: if name: - e = "{} {} was not deleted.".format(resource, name) + e = f"{resource} {name} was not deleted." else: - e = "{} was not deleted.".format(resource) + e = f"{resource} was not deleted." return {"deleted": False, "error": {"message": e}} except BotoServerError as e: return {"deleted": False, "error": __utils__["boto.get_error"](e)} @@ -384,7 +380,7 @@ def _get_resource( conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) - f = "get_all_{}".format(resource) + f = f"get_all_{resource}" if not f.endswith("s"): f = f + "s" get_resources = getattr(conn, f) @@ -393,7 +389,7 @@ def _get_resource( if name: filter_parameters["filters"] = {"tag:Name": name} if resource_id: - filter_parameters["{}_ids".format(resource)] = resource_id + filter_parameters[f"{resource}_ids"] = resource_id try: r = get_resources(**filter_parameters) @@ -417,7 +413,7 @@ def _get_resource( return r[0] else: raise CommandExecutionError( - 'Found more than one {} named "{}"'.format(resource, name) + f'Found more than one {resource} named "{name}"' ) else: return None @@ -447,7 +443,7 @@ def _find_resources( conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) - f = "get_all_{}".format(resource) + f = f"get_all_{resource}" if not f.endswith("s"): f = f + "s" get_resources = getattr(conn, f) @@ -456,10 +452,10 @@ def _find_resources( if name: filter_parameters["filters"] = {"tag:Name": name} if resource_id: - filter_parameters["{}_ids".format(resource)] = resource_id + filter_parameters[f"{resource}_ids"] = resource_id if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value try: r = get_resources(**filter_parameters) @@ -601,7 +597,7 @@ def _find_vpcs( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) log.debug( @@ -868,7 +864,7 @@ def delete( if not vpc_id: return { "deleted": False, - "error": {"message": "VPC {} not found".format(vpc_name)}, + "error": {"message": f"VPC {vpc_name} not found"}, } if conn.delete_vpc(vpc_id): @@ -1013,7 +1009,7 @@ def describe_vpcs( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) @@ -1055,7 +1051,7 @@ def _find_subnets(subnet_name=None, vpc_id=None, cidr=None, tags=None, conn=None if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value subnets = conn.get_all_subnets(**filter_parameters) log.debug( @@ -1108,9 +1104,7 @@ def create_subnet( if not vpc_id: return { "created": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } except BotoServerError as e: return {"created": False, "error": __utils__["boto.get_error"](e)} @@ -1222,7 +1216,7 @@ def subnet_exists( filter_parameters["filters"]["cidr"] = cidr if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value if zones: filter_parameters["filters"]["availability_zone"] = zones @@ -1462,9 +1456,7 @@ def create_internet_gateway( if not vpc_id: return { "created": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } r = _create_resource( @@ -1622,7 +1614,7 @@ def _find_nat_gateways( conn3.describe_nat_gateways, marker_flag="NextToken", marker_arg="NextToken", - **filter_parameters + **filter_parameters, ): for gw in ret.get("NatGateways", []): if gw.get("State") in states: @@ -1769,9 +1761,7 @@ def create_nat_gateway( if not subnet_id: return { "created": False, - "error": { - "message": "Subnet {} does not exist.".format(subnet_name) - }, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } else: if not _get_resource( @@ -1784,7 +1774,7 @@ def create_nat_gateway( ): return { "created": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_id)}, + "error": {"message": f"Subnet {subnet_id} does not exist."}, } conn3 = _get_conn3(region=region, key=key, keyid=keyid, profile=profile) @@ -2035,9 +2025,7 @@ def create_dhcp_options( if not vpc_id: return { "created": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } r = _create_resource( @@ -2177,9 +2165,7 @@ def associate_dhcp_options_to_vpc( if not vpc_id: return { "associated": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) @@ -2284,7 +2270,7 @@ def create_network_acl( if not vpc_id: return { "created": False, - "error": {"message": "VPC {} does not exist.".format(_id)}, + "error": {"message": f"VPC {_id} does not exist."}, } if all((subnet_id, subnet_name)): @@ -2298,7 +2284,7 @@ def create_network_acl( if not subnet_id: return { "created": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_name)}, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } elif subnet_id: if not _get_resource( @@ -2311,7 +2297,7 @@ def create_network_acl( ): return { "created": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_id)}, + "error": {"message": f"Subnet {subnet_id} does not exist."}, } r = _create_resource( @@ -2468,9 +2454,7 @@ def associate_network_acl_to_subnet( if not network_acl_id: return { "associated": False, - "error": { - "message": "Network ACL {} does not exist.".format(network_acl_name) - }, + "error": {"message": f"Network ACL {network_acl_name} does not exist."}, } if subnet_name: subnet_id = _get_resource_id( @@ -2479,7 +2463,7 @@ def associate_network_acl_to_subnet( if not subnet_id: return { "associated": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_name)}, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } try: conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) @@ -2547,9 +2531,7 @@ def disassociate_network_acl( if not subnet_id: return { "disassociated": False, - "error": { - "message": "Subnet {} does not exist.".format(subnet_name) - }, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } if vpc_name or vpc_id: @@ -2592,7 +2574,7 @@ def _create_network_acl_entry( for v in ("rule_number", "protocol", "rule_action", "cidr_block"): if locals()[v] is None: - raise SaltInvocationError("{} is required.".format(v)) + raise SaltInvocationError(f"{v} is required.") if network_acl_name: network_acl_id = _get_resource_id( @@ -2742,7 +2724,7 @@ def delete_network_acl_entry( for v in ("rule_number", "egress"): if locals()[v] is None: - raise SaltInvocationError("{} is required.".format(v)) + raise SaltInvocationError(f"{v} is required.") if network_acl_name: network_acl_id = _get_resource_id( @@ -2805,7 +2787,7 @@ def create_route_table( if not vpc_id: return { "created": False, - "error": {"message": "VPC {} does not exist.".format(vpc_name or vpc_id)}, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } return _create_resource( @@ -2941,7 +2923,7 @@ def route_exists( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value route_tables = conn.get_all_route_tables(**filter_parameters) @@ -3013,7 +2995,7 @@ def associate_route_table( if not subnet_id: return { "associated": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_name)}, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } if all((route_table_id, route_table_name)): @@ -3032,9 +3014,7 @@ def associate_route_table( if not route_table_id: return { "associated": False, - "error": { - "message": "Route table {} does not exist.".format(route_table_name) - }, + "error": {"message": f"Route table {route_table_name} does not exist."}, } try: @@ -3484,7 +3464,7 @@ def describe_route_tables( if tags: for tag_name, tag_value in tags.items(): filter_parameters["Filters"].append( - {"Name": "tag:{}".format(tag_name), "Values": [tag_value]} + {"Name": f"tag:{tag_name}", "Values": [tag_value]} ) route_tables = conn3.describe_route_tables(**filter_parameters).get( @@ -3598,7 +3578,7 @@ def _maybe_name_route_table(conn, vpcid, vpc_name): log.warning("no default route table found") return - name = "{}-default-table".format(vpc_name) + name = f"{vpc_name}-default-table" _maybe_set_name_tag(name, default_table) log.debug("Default route table name was set to: %s on vpc %s", name, vpcid) @@ -3755,9 +3735,7 @@ def request_vpc_peering_connection( vpc_name=peer_vpc_name, region=region, key=key, keyid=keyid, profile=profile ) if not peer_vpc_id: - return { - "error": "Could not resolve VPC name {} to an ID".format(peer_vpc_name) - } + return {"error": f"Could not resolve VPC name {peer_vpc_name} to an ID"} peering_params = { "VpcId": requester_vpc_id, @@ -3778,7 +3756,7 @@ def request_vpc_peering_connection( vpc_peering = conn.create_vpc_peering_connection(**peering_params) peering = vpc_peering.get("VpcPeeringConnection", {}) peering_conn_id = peering.get("VpcPeeringConnectionId", "ERROR") - msg = "VPC peering {} requested.".format(peering_conn_id) + msg = f"VPC peering {peering_conn_id} requested." log.debug(msg) if name: @@ -3787,7 +3765,7 @@ def request_vpc_peering_connection( Resources=[peering_conn_id], Tags=[{"Key": "Name", "Value": name}] ) log.debug("Applied name tag to vpc peering connection") - msg += " With name {}.".format(name) + msg += f" With name {name}." return {"msg": msg} except botocore.exceptions.ClientError as err: @@ -3989,7 +3967,7 @@ def delete_vpc_peering_connection( conn_id = _vpc_peering_conn_id_for_name(conn_name, conn) if not conn_id: raise SaltInvocationError( - "Couldn't resolve VPC peering connection {} to an ID".format(conn_name) + f"Couldn't resolve VPC peering connection {conn_name} to an ID" ) try: log.debug("Trying to delete vpc peering connection") diff --git a/salt/modules/bridge.py b/salt/modules/bridge.py index edc9c9dc377..d3959693471 100644 --- a/salt/modules/bridge.py +++ b/salt/modules/bridge.py @@ -51,9 +51,9 @@ def _linux_brshow(br=None): brctl = _tool_path("brctl") if br: - cmd = "{} show {}".format(brctl, br) + cmd = f"{brctl} show {br}" else: - cmd = "{} show".format(brctl) + cmd = f"{brctl} show" brs = {} @@ -96,7 +96,7 @@ def _linux_bradd(br): Internal, creates the bridge """ brctl = _tool_path("brctl") - return __salt__["cmd.run"]("{} addbr {}".format(brctl, br), python_shell=False) + return __salt__["cmd.run"](f"{brctl} addbr {br}", python_shell=False) def _linux_brdel(br): @@ -104,7 +104,7 @@ def _linux_brdel(br): Internal, deletes the bridge """ brctl = _tool_path("brctl") - return __salt__["cmd.run"]("{} delbr {}".format(brctl, br), python_shell=False) + return __salt__["cmd.run"](f"{brctl} delbr {br}", python_shell=False) def _linux_addif(br, iface): @@ -112,9 +112,7 @@ def _linux_addif(br, iface): Internal, adds an interface to a bridge """ brctl = _tool_path("brctl") - return __salt__["cmd.run"]( - "{} addif {} {}".format(brctl, br, iface), python_shell=False - ) + return __salt__["cmd.run"](f"{brctl} addif {br} {iface}", python_shell=False) def _linux_delif(br, iface): @@ -122,9 +120,7 @@ def _linux_delif(br, iface): Internal, removes an interface from a bridge """ brctl = _tool_path("brctl") - return __salt__["cmd.run"]( - "{} delif {} {}".format(brctl, br, iface), python_shell=False - ) + return __salt__["cmd.run"](f"{brctl} delif {br} {iface}", python_shell=False) def _linux_stp(br, state): @@ -132,9 +128,7 @@ def _linux_stp(br, state): Internal, sets STP state """ brctl = _tool_path("brctl") - return __salt__["cmd.run"]( - "{} stp {} {}".format(brctl, br, state), python_shell=False - ) + return __salt__["cmd.run"](f"{brctl} stp {br} {state}", python_shell=False) def _bsd_brshow(br=None): @@ -151,14 +145,14 @@ def _bsd_brshow(br=None): if br: ifaces[br] = br else: - cmd = "{} -g bridge".format(ifconfig) + cmd = f"{ifconfig} -g bridge" for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines(): ifaces[line] = line brs = {} for iface in ifaces: - cmd = "{} {}".format(ifconfig, iface) + cmd = f"{ifconfig} {iface}" for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines(): brs[iface] = {"interfaces": [], "stp": "no"} line = line.lstrip() @@ -179,9 +173,9 @@ def _netbsd_brshow(br=None): brconfig = _tool_path("brconfig") if br: - cmd = "{} {}".format(brconfig, br) + cmd = f"{brconfig} {br}" else: - cmd = "{} -a".format(brconfig) + cmd = f"{brconfig} -a" brs = {} start_int = False @@ -219,21 +213,13 @@ def _bsd_bradd(br): if not br: return False - if ( - __salt__["cmd.retcode"]( - "{} {} create up".format(ifconfig, br), python_shell=False - ) - != 0 - ): + if __salt__["cmd.retcode"](f"{ifconfig} {br} create up", python_shell=False) != 0: return False # NetBSD is two cmds if kernel == "NetBSD": brconfig = _tool_path("brconfig") - if ( - __salt__["cmd.retcode"]("{} {} up".format(brconfig, br), python_shell=False) - != 0 - ): + if __salt__["cmd.retcode"](f"{brconfig} {br} up", python_shell=False) != 0: return False return True @@ -246,7 +232,7 @@ def _bsd_brdel(br): ifconfig = _tool_path("ifconfig") if not br: return False - return __salt__["cmd.run"]("{} {} destroy".format(ifconfig, br), python_shell=False) + return __salt__["cmd.run"](f"{ifconfig} {br} destroy", python_shell=False) def _bsd_addif(br, iface): @@ -264,9 +250,7 @@ def _bsd_addif(br, iface): if not br or not iface: return False - return __salt__["cmd.run"]( - "{} {} {} {}".format(cmd, br, brcmd, iface), python_shell=False - ) + return __salt__["cmd.run"](f"{cmd} {br} {brcmd} {iface}", python_shell=False) def _bsd_delif(br, iface): @@ -284,9 +268,7 @@ def _bsd_delif(br, iface): if not br or not iface: return False - return __salt__["cmd.run"]( - "{} {} {} {}".format(cmd, br, brcmd, iface), python_shell=False - ) + return __salt__["cmd.run"](f"{cmd} {br} {brcmd} {iface}", python_shell=False) def _bsd_stp(br, state, iface): @@ -303,9 +285,7 @@ def _bsd_stp(br, state, iface): if not br or not iface: return False - return __salt__["cmd.run"]( - "{} {} {} {}".format(cmd, br, state, iface), python_shell=False - ) + return __salt__["cmd.run"](f"{cmd} {br} {state} {iface}", python_shell=False) def _os_dispatch(func, *args, **kwargs): @@ -317,7 +297,7 @@ def _os_dispatch(func, *args, **kwargs): else: kernel = __grains__["kernel"].lower() - _os_func = getattr(sys.modules[__name__], "_{}_{}".format(kernel, func)) + _os_func = getattr(sys.modules[__name__], f"_{kernel}_{func}") if callable(_os_func): return _os_func(*args, **kwargs) diff --git a/salt/modules/bsd_shadow.py b/salt/modules/bsd_shadow.py index d3700df5d73..3af23b710f3 100644 --- a/salt/modules/bsd_shadow.py +++ b/salt/modules/bsd_shadow.py @@ -110,7 +110,7 @@ def info(name): if not isinstance(name, str): name = str(name) if ":" in name: - raise SaltInvocationError("Invalid username '{}'".format(name)) + raise SaltInvocationError(f"Invalid username '{name}'") if __salt__["cmd.has_exec"]("pw"): change, expire = __salt__["cmd.run_stdout"]( @@ -121,7 +121,7 @@ def info(name): with salt.utils.files.fopen("/etc/master.passwd", "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) - if line.startswith("{}:".format(name)): + if line.startswith(f"{name}:"): key = line.split(":") change, expire = key[5:7] ret["passwd"] = str(key[1]) @@ -210,7 +210,7 @@ def del_password(name): salt '*' shadow.del_password username """ - cmd = "pw user mod {} -w none".format(name) + cmd = f"pw user mod {name} -w none" __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="quiet") uinfo = info(name) return not uinfo["passwd"] diff --git a/salt/modules/btrfs.py b/salt/modules/btrfs.py index ba09acffa1c..e2e7328a9bf 100644 --- a/salt/modules/btrfs.py +++ b/salt/modules/btrfs.py @@ -85,7 +85,7 @@ def info(device): salt '*' btrfs.info /dev/sda1 """ - out = __salt__["cmd.run_all"]("btrfs filesystem show {}".format(device)) + out = __salt__["cmd.run_all"](f"btrfs filesystem show {device}") salt.utils.fsutils._verify_run(out) return _parse_btrfs_info(out["stdout"]) @@ -111,9 +111,7 @@ def _defragment_mountpoint(mountpoint): """ Defragment only one BTRFS mountpoint. """ - out = __salt__["cmd.run_all"]( - "btrfs filesystem defragment -f {}".format(mountpoint) - ) + out = __salt__["cmd.run_all"](f"btrfs filesystem defragment -f {mountpoint}") return { "mount_point": mountpoint, "passed": not out["stderr"], @@ -140,7 +138,7 @@ def defragment(path): is_device = salt.utils.fsutils._is_device(path) mounts = salt.utils.fsutils._get_mounts("btrfs") if is_device and not mounts.get(path): - raise CommandExecutionError('Device "{}" is not mounted'.format(path)) + raise CommandExecutionError(f'Device "{path}" is not mounted') result = [] if is_device: @@ -212,7 +210,7 @@ def _usage_overall(raw): subk = keyset[1].split("(") data[key] = subk[0].strip() subk = subk[1].replace(")", "").split(": ") - data["{}_{}".format(key, subk[0])] = subk[1] + data[f"{key}_{subk[0]}"] = subk[1] else: data[key] = keyset[1] @@ -266,7 +264,7 @@ def usage(path): salt '*' btrfs.usage /your/mountpoint """ - out = __salt__["cmd.run_all"]("btrfs filesystem usage {}".format(path)) + out = __salt__["cmd.run_all"](f"btrfs filesystem usage {path}") salt.utils.fsutils._verify_run(out) ret = {} @@ -320,9 +318,7 @@ def mkfs(*devices, **kwargs): mounts = salt.utils.fsutils._get_mounts("btrfs") for device in devices: if mounts.get(device): - raise CommandExecutionError( - 'Device "{}" should not be mounted'.format(device) - ) + raise CommandExecutionError(f'Device "{device}" should not be mounted') cmd = ["mkfs.btrfs"] @@ -335,9 +331,9 @@ def mkfs(*devices, **kwargs): cmd.append("-m single") else: if dto: - cmd.append("-d {}".format(dto)) + cmd.append(f"-d {dto}") if mto: - cmd.append("-m {}".format(mto)) + cmd.append(f"-m {mto}") for key, option in [ ("-l", "leafsize"), @@ -351,7 +347,7 @@ def mkfs(*devices, **kwargs): if option == "label" and option in kwargs: kwargs["label"] = "'{}'".format(kwargs["label"]) if kwargs.get(option): - cmd.append("{} {}".format(key, kwargs.get(option))) + cmd.append(f"{key} {kwargs.get(option)}") if kwargs.get("uuid"): cmd.append( @@ -396,12 +392,10 @@ def resize(mountpoint, size): if size == "max": if not salt.utils.fsutils._is_device(mountpoint): raise CommandExecutionError( - 'Mountpoint "{}" should be a valid device'.format(mountpoint) + f'Mountpoint "{mountpoint}" should be a valid device' ) if not salt.utils.fsutils._get_mounts("btrfs").get(mountpoint): - raise CommandExecutionError( - 'Device "{}" should be mounted'.format(mountpoint) - ) + raise CommandExecutionError(f'Device "{mountpoint}" should be mounted') elif ( len(size) < 3 or size[0] not in "-+" @@ -414,9 +408,7 @@ def resize(mountpoint, size): ) ) - out = __salt__["cmd.run_all"]( - "btrfs filesystem resize {} {}".format(size, mountpoint) - ) + out = __salt__["cmd.run_all"](f"btrfs filesystem resize {size} {mountpoint}") salt.utils.fsutils._verify_run(out) ret = {"log": out["stdout"]} @@ -444,7 +436,7 @@ def _fsck_ext(device): } return msgs.get( - __salt__["cmd.run_all"]("fsck -f -n {}".format(device))["retcode"], + __salt__["cmd.run_all"](f"fsck -f -n {device}")["retcode"], "Unknown error", ) @@ -475,7 +467,7 @@ def convert(device, permanent=False, keeplf=False): salt.utils.fsutils._verify_run(out) devices = salt.utils.fsutils._blkid_output(out["stdout"]) if not devices.get(device): - raise CommandExecutionError('The device "{}" was is not found.'.format(device)) + raise CommandExecutionError(f'The device "{device}" was is not found.') if not devices[device]["type"] in ["ext2", "ext3", "ext4"]: raise CommandExecutionError( @@ -506,7 +498,7 @@ documentation regarding this topic. """ ) - salt.utils.fsutils._verify_run(__salt__["cmd.run_all"]("umount {}".format(device))) + salt.utils.fsutils._verify_run(__salt__["cmd.run_all"](f"umount {device}")) ret = { "before": { @@ -516,11 +508,9 @@ documentation regarding this topic. } } + salt.utils.fsutils._verify_run(__salt__["cmd.run_all"](f"btrfs-convert {device}")) salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("btrfs-convert {}".format(device)) - ) - salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("mount {} {}".format(device, mountpoint)) + __salt__["cmd.run_all"](f"mount {device} {mountpoint}") ) # Refresh devices @@ -535,38 +525,34 @@ documentation regarding this topic. } # Post-migration procedures - image_path = "{}/ext2_saved".format(mountpoint) + image_path = f"{mountpoint}/ext2_saved" orig_fstype = ret["before"]["type"] if not os.path.exists(image_path): raise CommandExecutionError( - 'BTRFS migration went wrong: the image "{}" not found!'.format(image_path) + f'BTRFS migration went wrong: the image "{image_path}" not found!' ) if not permanent: - ret["after"]["{}_image".format(orig_fstype)] = image_path + ret["after"][f"{orig_fstype}_image"] = image_path image_info_proc = subprocess.run( - ["file", "{}/image".format(image_path)], check=True, stdout=subprocess.PIPE + ["file", f"{image_path}/image"], check=True, stdout=subprocess.PIPE ) - ret["after"][ - "{}_image_info".format(orig_fstype) - ] = image_info_proc.stdout.strip() + ret["after"][f"{orig_fstype}_image_info"] = image_info_proc.stdout.strip() else: - ret["after"]["{}_image".format(orig_fstype)] = "removed" - ret["after"]["{}_image_info".format(orig_fstype)] = "N/A" + ret["after"][f"{orig_fstype}_image"] = "removed" + ret["after"][f"{orig_fstype}_image_info"] = "N/A" salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("btrfs subvolume delete {}".format(image_path)) + __salt__["cmd.run_all"](f"btrfs subvolume delete {image_path}") ) - out = __salt__["cmd.run_all"]("btrfs filesystem balance {}".format(mountpoint)) + out = __salt__["cmd.run_all"](f"btrfs filesystem balance {mountpoint}") salt.utils.fsutils._verify_run(out) ret["after"]["balance_log"] = out["stdout"] - lost_found = "{}/lost+found".format(mountpoint) + lost_found = f"{mountpoint}/lost+found" if os.path.exists(lost_found) and not keeplf: - salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("rm -rf {}".format(lost_found)) - ) + salt.utils.fsutils._verify_run(__salt__["cmd.run_all"](f"rm -rf {lost_found}")) return ret @@ -579,7 +565,7 @@ def _restripe(mountpoint, direction, *devices, **kwargs): if salt.utils.fsutils._is_device(mountpoint): raise CommandExecutionError( - 'Mountpount expected, while device "{}" specified'.format(mountpoint) + f'Mountpount expected, while device "{mountpoint}" specified' ) mounted = False @@ -591,7 +577,7 @@ def _restripe(mountpoint, direction, *devices, **kwargs): if not mounted: raise CommandExecutionError( - 'No BTRFS device mounted on "{}" mountpoint'.format(mountpoint) + f'No BTRFS device mounted on "{mountpoint}" mountpoint' ) if not devices: @@ -600,9 +586,9 @@ def _restripe(mountpoint, direction, *devices, **kwargs): available_devices = __salt__["btrfs.devices"]() for device in devices: if device not in available_devices.keys(): - raise CommandExecutionError('Device "{}" is not recognized'.format(device)) + raise CommandExecutionError(f'Device "{device}" is not recognized') - cmd = ["btrfs device {}".format(direction)] + cmd = [f"btrfs device {direction}"] for device in devices: cmd.append(device) @@ -630,9 +616,7 @@ def _restripe(mountpoint, direction, *devices, **kwargs): ) ) else: - out = __salt__["cmd.run_all"]( - "btrfs filesystem balance {}".format(mountpoint) - ) + out = __salt__["cmd.run_all"](f"btrfs filesystem balance {mountpoint}") salt.utils.fsutils._verify_run(out) if out["stdout"]: fs_log.append(out["stdout"]) @@ -718,15 +702,13 @@ def properties(obj, type=None, set=None): "d", "device", ]: - raise CommandExecutionError( - 'Unknown property type: "{}" specified'.format(type) - ) + raise CommandExecutionError(f'Unknown property type: "{type}" specified') cmd = ["btrfs"] cmd.append("property") cmd.append(set and "set" or "list") if type: - cmd.append("-t{}".format(type)) + cmd.append(f"-t{type}") cmd.append(obj) if set: @@ -747,9 +729,9 @@ def properties(obj, type=None, set=None): ret = {} for prop, descr in _parse_proplist(out["stdout"]).items(): ret[prop] = {"description": descr} - value = __salt__["cmd.run_all"]( - "btrfs property get {} {}".format(obj, prop) - )["stdout"] + value = __salt__["cmd.run_all"](f"btrfs property get {obj} {prop}")[ + "stdout" + ] ret[prop]["value"] = value and value.split("=")[-1] or "N/A" return ret diff --git a/salt/modules/cabal.py b/salt/modules/cabal.py index 8b4426c1400..fb2ccb61c8c 100644 --- a/salt/modules/cabal.py +++ b/salt/modules/cabal.py @@ -85,7 +85,7 @@ def install(pkg=None, pkgs=None, user=None, install_global=False, env=None): cmd.append("--global") if pkg: - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') elif pkgs: cmd.append('"{}"'.format('" "'.join(pkgs))) @@ -125,7 +125,7 @@ def list_(pkg=None, user=None, installed=False, env=None): cmd.append("--installed") if pkg: - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') result = __salt__["cmd.run_all"](" ".join(cmd), runas=user, env=env) @@ -160,7 +160,7 @@ def uninstall(pkg, user=None, env=None): """ cmd = ["ghc-pkg unregister"] - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') result = __salt__["cmd.run_all"](" ".join(cmd), runas=user, env=env) diff --git a/salt/modules/capirca_acl.py b/salt/modules/capirca_acl.py index 82189e48ade..2678556a433 100644 --- a/salt/modules/capirca_acl.py +++ b/salt/modules/capirca_acl.py @@ -481,7 +481,7 @@ def _get_term_object( pillarenv=None, saltenv=None, merge_pillar=True, - **term_fields + **term_fields, ): """ Return an instance of the ``_Term`` class given the term options. @@ -558,7 +558,7 @@ def _get_policy_object( pillarenv=pillarenv, saltenv=saltenv, merge_pillar=merge_pillar, - **term_fields + **term_fields, ) filter_terms.append(term) policy_filters.append((header, filter_terms)) @@ -597,17 +597,15 @@ def _revision_tag( if "$Id:$" in line: if not revision_id: # if no explicit revision ID required continue # jump to next line, ignore this one - line = line.replace("$Id:$", "$Id: {rev_id} $".format(rev_id=revision_id)) + line = line.replace("$Id:$", f"$Id: {revision_id} $") if "$Revision:$" in line: if not revision_no: # if no explicit revision number required continue # jump to next line, ignore this one - line = line.replace( - "$Revision:$", "$Revision: {rev_no} $".format(rev_no=revision_no) - ) + line = line.replace("$Revision:$", f"$Revision: {revision_no} $") if "$Date:$" in line: if not revision_date: continue # jump - line = line.replace("$Date:$", "$Date: {ts} $".format(ts=timestamp)) + line = line.replace("$Date:$", f"$Date: {timestamp} $") new_text.append(line) return "\n".join(new_text) @@ -632,7 +630,7 @@ def get_term_config( revision_date_format="%Y/%m/%d", source_service=None, destination_service=None, - **term_fields + **term_fields, ): """ Return the configuration of a single policy term. diff --git a/salt/modules/cassandra_cql.py b/salt/modules/cassandra_cql.py index 4e5ddcee71b..38e42f42bd9 100644 --- a/salt/modules/cassandra_cql.py +++ b/salt/modules/cassandra_cql.py @@ -220,7 +220,7 @@ def _load_properties(property_name, config_option, set_default=False, default=No config_option, ) raise CommandExecutionError( - "ERROR: Cassandra {} cannot be empty.".format(config_option) + f"ERROR: Cassandra {config_option} cannot be empty." ) return loaded_property return property_name @@ -510,7 +510,7 @@ def cql_query( results = session.execute(query) except BaseException as e: log.error("Failed to execute query: %s\n reason: %s", query, e) - msg = "ERROR: Cassandra query failed: {} reason: {}".format(query, e) + msg = f"ERROR: Cassandra query failed: {query} reason: {e}" raise CommandExecutionError(msg) if results: @@ -543,7 +543,7 @@ def cql_query_with_prepare( load_balancing_policy=None, load_balancing_policy_args=None, ssl_options=None, - **kwargs + **kwargs, ): """ Run a query on a Cassandra cluster and return a dictionary. @@ -642,7 +642,7 @@ def cql_query_with_prepare( results = session.execute(bound_statement.bind(statement_arguments)) except BaseException as e: log.error("Failed to execute query: %s\n reason: %s", query, e) - msg = "ERROR: Cassandra query failed: {} reason: {}".format(query, e) + msg = f"ERROR: Cassandra query failed: {query} reason: {e}" raise CommandExecutionError(msg) if not asynchronous and results: @@ -919,13 +919,13 @@ def list_column_families( salt 'minion1' cassandra_cql.list_column_families keyspace=system """ - where_clause = "where keyspace_name = '{}'".format(keyspace) if keyspace else "" + where_clause = f"where keyspace_name = '{keyspace}'" if keyspace else "" query = { "2": "select columnfamily_name from system.schema_columnfamilies {};".format( where_clause ), - "3": "select column_name from system_schema.columns {};".format(where_clause), + "3": f"select column_name from system_schema.columns {where_clause};", } ret = {} @@ -1190,7 +1190,7 @@ def drop_keyspace( ssl_options=ssl_options, ) if existing_keyspace: - query = """drop keyspace {};""".format(keyspace) + query = f"""drop keyspace {keyspace};""" try: cql_query( query, @@ -1419,16 +1419,12 @@ def list_permissions( salt 'minion1' cassandra_cql.list_permissions username=joe resource=test_table resource_type=table \ permission=select contact_points=minion1 """ - keyspace_cql = ( - "{} {}".format(resource_type, resource) if resource else "all keyspaces" - ) - permission_cql = ( - "{} permission".format(permission) if permission else "all permissions" - ) - query = "list {} on {}".format(permission_cql, keyspace_cql) + keyspace_cql = f"{resource_type} {resource}" if resource else "all keyspaces" + permission_cql = f"{permission} permission" if permission else "all permissions" + query = f"list {permission_cql} on {keyspace_cql}" if username: - query = "{} of {}".format(query, username) + query = f"{query} of {username}" log.debug("Attempting to list permissions with query '%s'", query) @@ -1511,13 +1507,9 @@ def grant_permission( salt 'minion1' cassandra_cql.grant_permission username=joe resource=test_table resource_type=table \ permission=select contact_points=minion1 """ - permission_cql = ( - "grant {}".format(permission) if permission else "grant all permissions" - ) - resource_cql = ( - "on {} {}".format(resource_type, resource) if resource else "on all keyspaces" - ) - query = "{} {} to {}".format(permission_cql, resource_cql, username) + permission_cql = f"grant {permission}" if permission else "grant all permissions" + resource_cql = f"on {resource_type} {resource}" if resource else "on all keyspaces" + query = f"{permission_cql} {resource_cql} to {username}" log.debug("Attempting to grant permissions with query '%s'", query) try: diff --git a/salt/modules/chef.py b/salt/modules/chef.py index 57946400eb4..4568e0c9458 100644 --- a/salt/modules/chef.py +++ b/salt/modules/chef.py @@ -36,7 +36,7 @@ def _default_logfile(exe_name): logfile = logfile_tmp.name logfile_tmp.close() else: - logfile = salt.utils.path.join("/var/log", "{}.log".format(exe_name)) + logfile = salt.utils.path.join("/var/log", f"{exe_name}.log") return logfile @@ -116,7 +116,7 @@ def client(whyrun=False, localmode=False, logfile=None, **kwargs): "chef-client", "--no-color", "--once", - '--logfile "{}"'.format(logfile), + f'--logfile "{logfile}"', "--format doc", ] @@ -184,7 +184,7 @@ def solo(whyrun=False, logfile=None, **kwargs): args = [ "chef-solo", "--no-color", - '--logfile "{}"'.format(logfile), + f'--logfile "{logfile}"', "--format doc", ] @@ -199,9 +199,9 @@ def _exec_cmd(*args, **kwargs): # Compile the command arguments cmd_args = " ".join(args) cmd_kwargs = "".join( - [" --{} {}".format(k, v) for k, v in kwargs.items() if not k.startswith("__")] + [f" --{k} {v}" for k, v in kwargs.items() if not k.startswith("__")] ) - cmd_exec = "{}{}".format(cmd_args, cmd_kwargs) + cmd_exec = f"{cmd_args}{cmd_kwargs}" log.debug("Chef command: %s", cmd_exec) return __salt__["cmd.run_all"](cmd_exec, python_shell=False) diff --git a/salt/modules/chronos.py b/salt/modules/chronos.py index a76590cb4af..3bc35e06bf9 100644 --- a/salt/modules/chronos.py +++ b/salt/modules/chronos.py @@ -37,7 +37,7 @@ def _jobs(): Return the currently configured jobs. """ response = salt.utils.http.query( - "{}/scheduler/jobs".format(_base_url()), + f"{_base_url()}/scheduler/jobs", decode_type="json", decode=True, ) @@ -106,7 +106,7 @@ def update_job(name, config): data = salt.utils.json.dumps(config) try: response = salt.utils.http.query( - "{}/scheduler/iso8601".format(_base_url()), + f"{_base_url()}/scheduler/iso8601", method="POST", data=data, header_dict={"Content-Type": "application/json"}, @@ -129,7 +129,7 @@ def rm_job(name): salt chronos-minion-id chronos.rm_job my-job """ response = salt.utils.http.query( - "{}/scheduler/job/{}".format(_base_url(), name), + f"{_base_url()}/scheduler/job/{name}", method="DELETE", ) return True diff --git a/salt/modules/chroot.py b/salt/modules/chroot.py index 78c974cc196..5be402f1beb 100644 --- a/salt/modules/chroot.py +++ b/salt/modules/chroot.py @@ -171,7 +171,7 @@ def call(root, function, *args, **kwargs): safe_kwargs = salt.utils.args.clean_kwargs(**kwargs) salt_argv = ( [ - "python{}".format(sys.version_info[0]), + f"python{sys.version_info[0]}", os.path.join(chroot_path, "salt-call"), "--metadata", "--local", @@ -187,7 +187,7 @@ def call(root, function, *args, **kwargs): function, ] + list(args) - + ["{}={}".format(k, v) for (k, v) in safe_kwargs.items()] + + [f"{k}={v}" for (k, v) in safe_kwargs.items()] ) ret = __salt__["cmd.run_chroot"](root, [str(x) for x in salt_argv]) diff --git a/salt/modules/cimc.py b/salt/modules/cimc.py index 132b513c2aa..90eb2b34c6c 100644 --- a/salt/modules/cimc.py +++ b/salt/modules/cimc.py @@ -115,7 +115,7 @@ def create_user(uid=None, username=None, password=None, priv=None): "The privilege level must be specified." ) - dn = "sys/user-ext/user-{}".format(uid) + dn = f"sys/user-ext/user-{uid}" inconfig = """""".format( @@ -606,7 +606,7 @@ def mount_share( else: mount_options = "" - dn = "sys/svc-ext/vmedia-svc/vmmap-{}".format(name) + dn = f"sys/svc-ext/vmedia-svc/vmmap-{name}" inconfig = """""".format( @@ -712,7 +712,7 @@ def set_logging_levels(remote=None, local=None): if remote: if remote in logging_options: - query += ' remoteSeverity="{}"'.format(remote) + query += f' remoteSeverity="{remote}"' else: raise salt.exceptions.CommandExecutionError( "Remote Severity option is not valid." @@ -720,14 +720,14 @@ def set_logging_levels(remote=None, local=None): if local: if local in logging_options: - query += ' localSeverity="{}"'.format(local) + query += f' localSeverity="{local}"' else: raise salt.exceptions.CommandExecutionError( "Local Severity option is not valid." ) dn = "sys/svc-ext/syslog" - inconfig = """""".format(query) + inconfig = f"""""" ret = __proxy__["cimc.set_config_modify"](dn, inconfig, False) @@ -817,7 +817,7 @@ def set_power_configuration(policy=None, delayType=None, delayValue=None): if delayType == "fixed": query += ' delayType="fixed"' if delayValue: - query += ' delay="{}"'.format(delayValue) + query += f' delay="{delayValue}"' elif delayType == "random": query += ' delayType="random"' else: @@ -923,18 +923,18 @@ def set_user(uid=None, username=None, password=None, priv=None, status=None): raise salt.exceptions.CommandExecutionError("The user ID must be specified.") if status: - conf += ' accountStatus="{}"'.format(status) + conf += f' accountStatus="{status}"' if username: - conf += ' name="{}"'.format(username) + conf += f' name="{username}"' if priv: - conf += ' priv="{}"'.format(priv) + conf += f' priv="{priv}"' if password: - conf += ' pwd="{}"'.format(password) + conf += f' pwd="{password}"' - dn = "sys/user-ext/user-{}".format(uid) + dn = f"sys/user-ext/user-{uid}" inconfig = """""".format(uid, conf) diff --git a/salt/modules/ciscoconfparse_mod.py b/salt/modules/ciscoconfparse_mod.py index 56924691245..2be0a5f482e 100644 --- a/salt/modules/ciscoconfparse_mod.py +++ b/salt/modules/ciscoconfparse_mod.py @@ -58,7 +58,7 @@ def _get_ccp(config=None, config_path=None, saltenv="base"): if config_path: config = __salt__["cp.get_file_str"](config_path, saltenv=saltenv) if config is False: - raise SaltException("{} is not available".format(config_path)) + raise SaltException(f"{config_path} is not available") if isinstance(config, str): config = config.splitlines() ccp = ciscoconfparse.CiscoConfParse(config) diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py index 051143eb856..d603a69ba77 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py @@ -145,7 +145,7 @@ def _render_cmd(cmd, cwd, template, saltenv=None, pillarenv=None, pillar_overrid # render the path as a template using path_template_engine as the engine if template not in salt.utils.templates.TEMPLATE_REGISTRY: raise CommandExecutionError( - "Attempted to render file paths with unavailable engine {}".format(template) + f"Attempted to render file paths with unavailable engine {template}" ) kwargs = {} @@ -265,7 +265,7 @@ def _prep_powershell_cmd(shell, cmd, stack, encoded_cmd): # the shell in quotes in case there are # spaces in the paths. if salt.utils.platform.is_windows(): - shell = '"{}"'.format(shell) + shell = f'"{shell}"' # extract_stack() returns a list of tuples. # The last item in the list [-1] is the current method. @@ -277,9 +277,9 @@ def _prep_powershell_cmd(shell, cmd, stack, encoded_cmd): ) ) elif encoded_cmd: - cmd = "{} -NonInteractive -NoProfile -EncodedCommand {}".format(shell, cmd) + cmd = f"{shell} -NonInteractive -NoProfile -EncodedCommand {cmd}" else: - cmd = '{} -NonInteractive -NoProfile -Command "{}"'.format(shell, cmd) + cmd = f'{shell} -NonInteractive -NoProfile -Command "{cmd}"' return cmd @@ -318,7 +318,7 @@ def _run( success_stdout=None, success_stderr=None, windows_codepage=65001, - **kwargs + **kwargs, ): """ Do the DRY thing and only call subprocess.Popen() once @@ -368,7 +368,7 @@ def _run( change_windows_codepage = False if not salt.utils.platform.is_windows(): if not os.path.isfile(shell) or not os.access(shell, os.X_OK): - msg = "The shell {} is not available".format(shell) + msg = f"The shell {shell} is not available" raise CommandExecutionError(msg) elif use_vt: # Memozation so not much overhead raise CommandExecutionError("VT not available on windows") @@ -406,9 +406,7 @@ def _run( # checked if blacklisted if "__pub_jid" in kwargs: if not _check_avail(cmd): - raise CommandExecutionError( - 'The shell command "{}" is not permitted'.format(cmd) - ) + raise CommandExecutionError(f'The shell command "{cmd}" is not permitted') env = _parse_env(env) @@ -428,8 +426,8 @@ def _run( "'" if not isinstance(cmd, list) else "", _log_cmd(cmd), "'" if not isinstance(cmd, list) else "", - "as user '{}' ".format(runas) if runas else "", - "in group '{}' ".format(group) if group else "", + f"as user '{runas}' " if runas else "", + f"in group '{group}' " if group else "", cwd, ( ". Executing command in the background, no output will be logged." @@ -457,7 +455,7 @@ def _run( cmd = " ".join(map(_cmd_quote, cmd)) # Ensure directory is correct before running command - cmd = "cd -- {dir} && {{ {cmd}\n }}".format(dir=_cmd_quote(cwd), cmd=cmd) + cmd = f"cd -- {_cmd_quote(cwd)} && {{ {cmd}\n }}" # Ensure environment is correct for a newly logged-in user by running # the command under bash as a login shell @@ -474,7 +472,7 @@ def _run( # Ensure the login is simulated correctly (note: su runs sh, not bash, # which causes the environment to be initialised incorrectly, which is # fixed by the previous line of code) - cmd = "su -l {} -c {}".format(_cmd_quote(runas), _cmd_quote(cmd)) + cmd = f"su -l {_cmd_quote(runas)} -c {_cmd_quote(cmd)}" # Set runas to None, because if you try to run `su -l` after changing # user, su will prompt for the password of the user and cause salt to @@ -486,7 +484,7 @@ def _run( try: pwd.getpwnam(runas) except KeyError: - raise CommandExecutionError("User '{}' is not available".format(runas)) + raise CommandExecutionError(f"User '{runas}' is not available") if group: if salt.utils.platform.is_windows(): @@ -498,7 +496,7 @@ def _run( try: grp.getgrnam(group) except KeyError: - raise CommandExecutionError("Group '{}' is not available".format(runas)) + raise CommandExecutionError(f"Group '{runas}' is not available") else: use_sudo = True @@ -544,7 +542,7 @@ def _run( if not salt.utils.pkg.check_bundled(): if __grains__["os"] in ["FreeBSD"]: - env_cmd.extend(["{} -c {}".format(shell, sys.executable)]) + env_cmd.extend([f"{shell} -c {sys.executable}"]) else: env_cmd.extend([sys.executable]) else: @@ -558,11 +556,11 @@ def _run( ] ) else: - env_cmd.extend(["{} python {}".format(sys.executable, fp.name)]) + env_cmd.extend([f"{sys.executable} python {fp.name}"]) fp.write(py_code) shutil.chown(fp.name, runas) - msg = "env command: {}".format(env_cmd) + msg = f"env command: {env_cmd}" log.debug(log_callback(msg)) env_bytes, env_encoded_err = subprocess.Popen( env_cmd, @@ -609,7 +607,7 @@ def _run( # Fix some corner cases where shelling out to get the user's # environment returns the wrong home directory. - runas_home = os.path.expanduser("~{}".format(runas)) + runas_home = os.path.expanduser(f"~{runas}") if env_runas.get("HOME") != runas_home: env_runas["HOME"] = runas_home @@ -687,7 +685,7 @@ def _run( try: _umask = int(_umask, 8) except ValueError: - raise CommandExecutionError("Invalid umask: '{}'".format(umask)) + raise CommandExecutionError(f"Invalid umask: '{umask}'") else: _umask = None @@ -709,7 +707,7 @@ def _run( if not os.path.isabs(cwd) or not os.path.isdir(cwd): raise CommandExecutionError( - "Specified cwd '{}' either not absolute or does not exist".format(cwd) + f"Specified cwd '{cwd}' either not absolute or does not exist" ) if ( @@ -830,9 +828,9 @@ def _run( else: formatted_timeout = "" if timeout: - formatted_timeout = " (timeout: {}s)".format(timeout) + formatted_timeout = f" (timeout: {timeout}s)" if output_loglevel is not None: - msg = "Running {} in VT{}".format(cmd, formatted_timeout) + msg = f"Running {cmd} in VT{formatted_timeout}" log.debug(log_callback(msg)) stdout, stderr = "", "" now = time.time() @@ -877,7 +875,7 @@ def _run( ret["retcode"] = None break except KeyboardInterrupt: - ret["stderr"] = "SALT: User break\n{}".format(stderr) + ret["stderr"] = f"SALT: User break\n{stderr}" ret["retcode"] = 1 break except salt.utils.vt.TerminalException as exc: @@ -1065,7 +1063,7 @@ def run( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): r""" Execute the passed command and return the output as a string @@ -1332,7 +1330,7 @@ def run( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) log_callback = _check_cb(log_callback) @@ -1381,7 +1379,7 @@ def shell( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed command and return the output as a string. @@ -1609,7 +1607,7 @@ def shell( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) @@ -1640,7 +1638,7 @@ def run_stdout( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute a command, and only return the standard out @@ -1841,7 +1839,7 @@ def run_stdout( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return ret["stdout"] if not hide_output else "" @@ -1874,7 +1872,7 @@ def run_stderr( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute a command and only return the standard error @@ -2075,7 +2073,7 @@ def run_stderr( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return ret["stderr"] if not hide_output else "" @@ -2110,7 +2108,7 @@ def run_all( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed command and return a dict of return data @@ -2355,7 +2353,7 @@ def run_all( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) if hide_output: @@ -2387,7 +2385,7 @@ def retcode( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute a shell command and return the command's return code. @@ -2577,7 +2575,7 @@ def retcode( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return ret["retcode"] @@ -2605,7 +2603,7 @@ def _retcode_quiet( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Helper for running commands quietly for minion startup. Returns same as @@ -2635,7 +2633,7 @@ def _retcode_quiet( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) @@ -2664,7 +2662,7 @@ def script( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script from a remote location and execute the script locally. @@ -2937,7 +2935,7 @@ def script( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) _cleanup_tempfile(path) # If a temp working directory was created (Windows), let's remove that @@ -2972,7 +2970,7 @@ def script_retcode( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script from a remote location and execute the script locally. @@ -3151,7 +3149,7 @@ def script_retcode( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, )["retcode"] @@ -3281,7 +3279,7 @@ def tty(device, echo=""): salt '*' cmd.tty pts3 'This is a test' """ if device.startswith("tty"): - teletype = "/dev/{}".format(device) + teletype = f"/dev/{device}" elif device.startswith("pts"): teletype = "/dev/{}".format(device.replace("pts", "pts/")) else: @@ -3289,9 +3287,9 @@ def tty(device, echo=""): try: with salt.utils.files.fopen(teletype, "wb") as tty_device: tty_device.write(salt.utils.stringutils.to_bytes(echo)) - return {"Success": "Message was successfully echoed to {}".format(teletype)} + return {"Success": f"Message was successfully echoed to {teletype}"} except OSError: - return {"Error": "Echoing to {} returned error".format(teletype)} + return {"Error": f"Echoing to {teletype} returned error"} def run_chroot( @@ -3322,7 +3320,7 @@ def run_chroot( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2014.7.0 @@ -3498,7 +3496,7 @@ def run_chroot( else: userspec = "" - cmd = "chroot {} {} {} -c {}".format(userspec, root, sh_, _cmd_quote(cmd)) + cmd = f"chroot {userspec} {root} {sh_} -c {_cmd_quote(cmd)}" run_func = __context__.pop("cmd.run_chroot.func", run_all) @@ -3711,7 +3709,7 @@ def shell_info(shell, list_modules=False): for reg_ver in pw_keys: install_data = salt.utils.win_reg.read_value( hive="HKEY_LOCAL_MACHINE", - key="Software\\Microsoft\\PowerShell\\{}".format(reg_ver), + key=f"Software\\Microsoft\\PowerShell\\{reg_ver}", vname="Install", ) if ( @@ -3862,7 +3860,7 @@ def powershell( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed PowerShell command and return the output as a dictionary. @@ -4065,7 +4063,7 @@ def powershell( if salt.utils.versions.version_cmp(psversion, "2.0") == 1: cmd += " | ConvertTo-JSON" if depth is not None: - cmd += " -Depth {}".format(depth) + cmd += f" -Depth {depth}" # Put the whole command inside a try / catch block # Some errors in PowerShell are not "Terminating Errors" and will not be @@ -4078,7 +4076,7 @@ def powershell( # Convert the cmd to UTF-16LE without a BOM and base64 encode. # Just base64 encoding UTF-8 or including a BOM is not valid. log.debug("Encoding PowerShell command '%s'", cmd) - cmd = "$ProgressPreference='SilentlyContinue'; {}".format(cmd) + cmd = f"$ProgressPreference='SilentlyContinue'; {cmd}" cmd_utf16 = cmd.encode("utf-16-le") cmd = base64.standard_b64encode(cmd_utf16) cmd = salt.utils.stringutils.to_str(cmd) @@ -4112,7 +4110,7 @@ def powershell( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) # Sometimes Powershell returns an empty string, which isn't valid JSON @@ -4151,7 +4149,7 @@ def powershell_all( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed PowerShell command and return a dictionary with a result @@ -4424,13 +4422,13 @@ def powershell_all( # Append PowerShell Object formatting cmd += " | ConvertTo-JSON" if depth is not None: - cmd += " -Depth {}".format(depth) + cmd += f" -Depth {depth}" if encode_cmd: # Convert the cmd to UTF-16LE without a BOM and base64 encode. # Just base64 encoding UTF-8 or including a BOM is not valid. log.debug("Encoding PowerShell command '%s'", cmd) - cmd = "$ProgressPreference='SilentlyContinue'; {}".format(cmd) + cmd = f"$ProgressPreference='SilentlyContinue'; {cmd}" cmd_utf16 = cmd.encode("utf-16-le") cmd = base64.standard_b64encode(cmd_utf16) cmd = salt.utils.stringutils.to_str(cmd) @@ -4464,7 +4462,7 @@ def powershell_all( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) stdoutput = response["stdout"] @@ -4520,7 +4518,7 @@ def run_bg( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): r""" .. versionadded:: 2016.3.0 @@ -4738,7 +4736,7 @@ def run_bg( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return {"pid": res["pid"]} diff --git a/salt/modules/composer.py b/salt/modules/composer.py index 7feb5d0f2ca..8e31c52a688 100644 --- a/salt/modules/composer.py +++ b/salt/modules/composer.py @@ -48,7 +48,7 @@ def did_composer_install(dir): salt '*' composer.did_composer_install /var/www/application """ - lockFile = "{}/vendor".format(dir) + lockFile = f"{dir}/vendor" if os.path.exists(lockFile): return True return False @@ -147,7 +147,7 @@ def _run_composer( # Don't need a dir for the 'selfupdate' action; all other actions do need a dir if directory is None and action != "selfupdate": raise SaltInvocationError( - "The 'directory' argument is required for composer.{}".format(action) + f"The 'directory' argument is required for composer.{action}" ) # Base Settings diff --git a/salt/modules/config.py b/salt/modules/config.py index 972a2e84c7c..044d7172c7c 100644 --- a/salt/modules/config.py +++ b/salt/modules/config.py @@ -522,10 +522,10 @@ def dot_vals(value): """ ret = {} for key, val in __pillar__.get("master", {}).items(): - if key.startswith("{}.".format(value)): + if key.startswith(f"{value}."): ret[key] = val for key, val in __opts__.items(): - if key.startswith("{}.".format(value)): + if key.startswith(f"{value}."): ret[key] = val return ret diff --git a/salt/modules/consul.py b/salt/modules/consul.py index 01f161e5fe2..a457569eb82 100644 --- a/salt/modules/consul.py +++ b/salt/modules/consul.py @@ -68,7 +68,7 @@ def _query( token = _get_token() headers = {"X-Consul-Token": token, "Content-Type": "application/json"} - base_url = urllib.parse.urljoin(consul_url, "{}/".format(api_version)) + base_url = urllib.parse.urljoin(consul_url, f"{api_version}/") url = urllib.parse.urljoin(base_url, function, False) if method == "GET": @@ -149,7 +149,7 @@ def list_(consul_url=None, token=None, key=None, **kwargs): query_params["recurse"] = "True" function = "kv/" else: - function = "kv/{}".format(key) + function = f"kv/{key}" query_params["keys"] = "True" query_params["separator"] = "/" @@ -203,7 +203,7 @@ def get(consul_url=None, key=None, token=None, recurse=False, decode=False, raw= raise SaltInvocationError('Required argument "key" is missing.') query_params = {} - function = "kv/{}".format(key) + function = f"kv/{key}" if recurse: query_params["recurse"] = "True" if raw: @@ -286,19 +286,17 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): if "cas" in kwargs: if _current["res"]: if kwargs["cas"] == 0: - ret["message"] = "Key {} exists, index must be non-zero.".format(key) + ret["message"] = f"Key {key} exists, index must be non-zero." ret["res"] = False return ret if kwargs["cas"] != _current["data"]["ModifyIndex"]: - ret["message"] = "Key {} exists, but indexes do not match.".format(key) + ret["message"] = f"Key {key} exists, but indexes do not match." ret["res"] = False return ret query_params["cas"] = kwargs["cas"] else: - ret["message"] = ( - "Key {} does not exists, CAS argument can not be used.".format(key) - ) + ret["message"] = f"Key {key} does not exists, CAS argument can not be used." ret["res"] = False return ret @@ -316,7 +314,7 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): if _current["data"]["Session"] == kwargs["release"]: query_params["release"] = kwargs["release"] else: - ret["message"] = "{} locked by another session.".format(key) + ret["message"] = f"{key} locked by another session." ret["res"] = False return ret @@ -327,7 +325,7 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): log.error("Key {0} does not exist. Skipping release.") data = value - function = "kv/{}".format(key) + function = f"kv/{key}" method = "PUT" res = _query( consul_url=consul_url, @@ -340,10 +338,10 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): if res["res"]: ret["res"] = True - ret["data"] = "Added key {} with value {}.".format(key, value) + ret["data"] = f"Added key {key} with value {value}." else: ret["res"] = False - ret["data"] = "Unable to add key {} with value {}.".format(key, value) + ret["data"] = f"Unable to add key {key} with value {value}." if "error" in res: ret["error"] = res["error"] return ret @@ -396,7 +394,7 @@ def delete(consul_url=None, token=None, key=None, **kwargs): ret["res"] = False return ret - function = "kv/{}".format(key) + function = f"kv/{key}" res = _query( consul_url=consul_url, token=token, @@ -407,10 +405,10 @@ def delete(consul_url=None, token=None, key=None, **kwargs): if res["res"]: ret["res"] = True - ret["message"] = "Deleted key {}.".format(key) + ret["message"] = f"Deleted key {key}." else: ret["res"] = False - ret["message"] = "Unable to delete key {}.".format(key) + ret["message"] = f"Unable to delete key {key}." if "error" in res: ret["error"] = res["error"] return ret @@ -635,7 +633,7 @@ def agent_join(consul_url=None, token=None, address=None, **kwargs): if "wan" in kwargs: query_params["wan"] = kwargs["wan"] - function = "agent/join/{}".format(address) + function = f"agent/join/{address}" res = _query( consul_url=consul_url, function=function, @@ -680,7 +678,7 @@ def agent_leave(consul_url=None, token=None, node=None): if not node: raise SaltInvocationError('Required argument "node" is missing.') - function = "agent/force-leave/{}".format(node) + function = f"agent/force-leave/{node}" res = _query( consul_url=consul_url, function=function, @@ -690,10 +688,10 @@ def agent_leave(consul_url=None, token=None, node=None): ) if res["res"]: ret["res"] = True - ret["message"] = "Node {} put in leave state.".format(node) + ret["message"] = f"Node {node} put in leave state." else: ret["res"] = False - ret["message"] = "Unable to change state for {}.".format(node) + ret["message"] = f"Unable to change state for {node}." return ret @@ -810,11 +808,11 @@ def agent_check_deregister(consul_url=None, token=None, checkid=None): if not checkid: raise SaltInvocationError('Required argument "checkid" is missing.') - function = "agent/check/deregister/{}".format(checkid) + function = f"agent/check/deregister/{checkid}" res = _query(consul_url=consul_url, function=function, token=token, method="GET") if res["res"]: ret["res"] = True - ret["message"] = "Check {} removed from agent.".format(checkid) + ret["message"] = f"Check {checkid} removed from agent." else: ret["res"] = False ret["message"] = "Unable to remove check from agent." @@ -855,7 +853,7 @@ def agent_check_pass(consul_url=None, token=None, checkid=None, **kwargs): if "note" in kwargs: query_params["note"] = kwargs["note"] - function = "agent/check/pass/{}".format(checkid) + function = f"agent/check/pass/{checkid}" res = _query( consul_url=consul_url, function=function, @@ -865,10 +863,10 @@ def agent_check_pass(consul_url=None, token=None, checkid=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Check {} marked as passing.".format(checkid) + ret["message"] = f"Check {checkid} marked as passing." else: ret["res"] = False - ret["message"] = "Unable to update check {}.".format(checkid) + ret["message"] = f"Unable to update check {checkid}." return ret @@ -906,7 +904,7 @@ def agent_check_warn(consul_url=None, token=None, checkid=None, **kwargs): if "note" in kwargs: query_params["note"] = kwargs["note"] - function = "agent/check/warn/{}".format(checkid) + function = f"agent/check/warn/{checkid}" res = _query( consul_url=consul_url, function=function, @@ -916,10 +914,10 @@ def agent_check_warn(consul_url=None, token=None, checkid=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Check {} marked as warning.".format(checkid) + ret["message"] = f"Check {checkid} marked as warning." else: ret["res"] = False - ret["message"] = "Unable to update check {}.".format(checkid) + ret["message"] = f"Unable to update check {checkid}." return ret @@ -957,7 +955,7 @@ def agent_check_fail(consul_url=None, token=None, checkid=None, **kwargs): if "note" in kwargs: query_params["note"] = kwargs["note"] - function = "agent/check/fail/{}".format(checkid) + function = f"agent/check/fail/{checkid}" res = _query( consul_url=consul_url, function=function, @@ -967,10 +965,10 @@ def agent_check_fail(consul_url=None, token=None, checkid=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Check {} marked as critical.".format(checkid) + ret["message"] = f"Check {checkid} marked as critical." else: ret["res"] = False - ret["message"] = "Unable to update check {}.".format(checkid) + ret["message"] = f"Unable to update check {checkid}." return ret @@ -1114,16 +1112,16 @@ def agent_service_deregister(consul_url=None, token=None, serviceid=None): if not serviceid: raise SaltInvocationError('Required argument "serviceid" is missing.') - function = "agent/service/deregister/{}".format(serviceid) + function = f"agent/service/deregister/{serviceid}" res = _query( consul_url=consul_url, function=function, token=token, method="PUT", data=data ) if res["res"]: ret["res"] = True - ret["message"] = "Service {} removed from agent.".format(serviceid) + ret["message"] = f"Service {serviceid} removed from agent." else: ret["res"] = False - ret["message"] = "Unable to remove service {}.".format(serviceid) + ret["message"] = f"Unable to remove service {serviceid}." return ret @@ -1168,14 +1166,14 @@ def agent_service_maintenance(consul_url=None, token=None, serviceid=None, **kwa if "reason" in kwargs: query_params["reason"] = kwargs["reason"] - function = "agent/service/maintenance/{}".format(serviceid) + function = f"agent/service/maintenance/{serviceid}" res = _query( consul_url=consul_url, token=token, function=function, query_params=query_params ) if res["res"]: ret["res"] = True - ret["message"] = "Service {} set in maintenance mode.".format(serviceid) + ret["message"] = f"Service {serviceid} set in maintenance mode." else: ret["res"] = False ret["message"] = "Unable to set service {} to maintenance mode.".format( @@ -1255,7 +1253,7 @@ def session_create(consul_url=None, token=None, **kwargs): ret["message"] = ("TTL must be ", "between 0 and 3600.") ret["res"] = False return ret - data["TTL"] = "{}s".format(_ttl) + data["TTL"] = f"{_ttl}s" function = "session/create" res = _query( @@ -1351,7 +1349,7 @@ def session_destroy(consul_url=None, token=None, session=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "session/destroy/{}".format(session) + function = f"session/destroy/{session}" res = _query( consul_url=consul_url, function=function, @@ -1361,10 +1359,10 @@ def session_destroy(consul_url=None, token=None, session=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Destroyed Session {}.".format(session) + ret["message"] = f"Destroyed Session {session}." else: ret["res"] = False - ret["message"] = "Unable to destroy session {}.".format(session) + ret["message"] = f"Unable to destroy session {session}." return ret @@ -1402,7 +1400,7 @@ def session_info(consul_url=None, token=None, session=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "session/info/{}".format(session) + function = f"session/info/{session}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1770,7 +1768,7 @@ def catalog_service(consul_url=None, token=None, service=None, **kwargs): if "tag" in kwargs: query_params["tag"] = kwargs["tag"] - function = "catalog/service/{}".format(service) + function = f"catalog/service/{service}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1810,7 +1808,7 @@ def catalog_node(consul_url=None, token=None, node=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "catalog/node/{}".format(node) + function = f"catalog/node/{node}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1850,7 +1848,7 @@ def health_node(consul_url=None, token=None, node=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "health/node/{}".format(node) + function = f"health/node/{node}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1890,7 +1888,7 @@ def health_checks(consul_url=None, token=None, service=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "health/checks/{}".format(service) + function = f"health/checks/{service}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1941,7 +1939,7 @@ def health_service(consul_url=None, token=None, service=None, **kwargs): if "passing" in kwargs: query_params["passing"] = kwargs["passing"] - function = "health/service/{}".format(service) + function = f"health/service/{service}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1991,7 +1989,7 @@ def health_state(consul_url=None, token=None, state=None, **kwargs): ret["res"] = False return ret - function = "health/state/{}".format(state) + function = f"health/state/{state}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -2378,7 +2376,7 @@ def event_fire(consul_url=None, token=None, name=None, **kwargs): if "tag" in kwargs: query_params = kwargs["tag"] - function = "event/fire/{}".format(name) + function = f"event/fire/{name}" res = _query( consul_url=consul_url, token=token, @@ -2389,7 +2387,7 @@ def event_fire(consul_url=None, token=None, name=None, **kwargs): if res["res"]: ret["res"] = True - ret["message"] = "Event {} fired.".format(name) + ret["message"] = f"Event {name} fired." ret["data"] = res["data"] else: ret["res"] = False diff --git a/salt/modules/cp.py b/salt/modules/cp.py index 07554808386..25b0fcbae91 100644 --- a/salt/modules/cp.py +++ b/salt/modules/cp.py @@ -182,7 +182,7 @@ def _render_filenames(path, dest, saltenv, template, **kw): # render the path as a template using path_template_engine as the engine if template not in salt.utils.templates.TEMPLATE_REGISTRY: raise CommandExecutionError( - "Attempted to render file paths with unavailable engine {}".format(template) + f"Attempted to render file paths with unavailable engine {template}" ) kwargs = {} diff --git a/salt/modules/cpan.py b/salt/modules/cpan.py index b92f081d308..27b96d416eb 100644 --- a/salt/modules/cpan.py +++ b/salt/modules/cpan.py @@ -43,7 +43,7 @@ def install(module): old_info = show(module) - cmd = "cpan -i {}".format(module) + cmd = f"cpan -i {module}" out = __salt__["cmd.run"](cmd) if "don't know what it is" in out: @@ -153,7 +153,7 @@ def show(module): ret["name"] = module # This section parses out details from CPAN, if possible - cmd = "cpan -D {}".format(module) + cmd = f"cpan -D {module}" out = __salt__["cmd.run"](cmd).splitlines() mode = "skip" info = [] diff --git a/salt/modules/cron.py b/salt/modules/cron.py index dc0a229062c..660ca9c768d 100644 --- a/salt/modules/cron.py +++ b/salt/modules/cron.py @@ -113,7 +113,7 @@ def _render_tab(lst): """ ret = [] for pre in lst["pre"]: - ret.append("{}\n".format(pre)) + ret.append(f"{pre}\n") if ret: if ret[-1] != TAG: ret.append(TAG) @@ -170,10 +170,10 @@ def _get_cron_cmdstr(path, user=None): Returns a format string, to be used to build a crontab command. """ if user: - cmd = "crontab -u {}".format(user) + cmd = f"crontab -u {user}" else: cmd = "crontab" - return "{} {}".format(cmd, path) + return f"{cmd} {path}" def _check_instance_uid_match(user): @@ -343,7 +343,7 @@ def raw_cron(user): ).splitlines(True) # If Salt is running from root user it could modify any user's crontab elif _check_instance_uid_match("root"): - cmd = "crontab -u {} -l".format(user) + cmd = f"crontab -u {user} -l" # Preserve line endings lines = salt.utils.data.decode( __salt__["cmd.run_stdout"]( diff --git a/salt/modules/cryptdev.py b/salt/modules/cryptdev.py index ec195245ccb..77e84683aec 100644 --- a/salt/modules/cryptdev.py +++ b/salt/modules/cryptdev.py @@ -49,7 +49,7 @@ class _crypttab_entry: @classmethod def dict_from_line(cls, line, keys=crypttab_keys): if len(keys) != 4: - raise ValueError("Invalid key array: {}".format(keys)) + raise ValueError(f"Invalid key array: {keys}") if line.startswith("#"): raise cls.ParseError("Comment!") @@ -269,12 +269,12 @@ def set_crypttab( invalid_keys = filter(filterFn, match_on) - msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) + msg = f'Unrecognized keys in match_on: "{invalid_keys}"' raise CommandExecutionError(msg) # parse file, use ret to cache status if not os.path.isfile(config): - raise CommandExecutionError('Bad config file "{}"'.format(config)) + raise CommandExecutionError(f'Bad config file "{config}"') try: with salt.utils.files.fopen(config, "r") as ifile: @@ -338,7 +338,7 @@ def open(name, device, keyfile): ) code = __salt__["cmd.retcode"]( - "cryptsetup open --key-file {} {} {}".format(keyfile, device, name) + f"cryptsetup open --key-file {keyfile} {device} {name}" ) return code == 0 @@ -353,5 +353,5 @@ def close(name): salt '*' cryptdev.close foo """ - code = __salt__["cmd.retcode"]("cryptsetup close {}".format(name)) + code = __salt__["cmd.retcode"](f"cryptsetup close {name}") return code == 0 diff --git a/salt/modules/csf.py b/salt/modules/csf.py index 63b3cb01ba6..0f7a27c365a 100644 --- a/salt/modules/csf.py +++ b/salt/modules/csf.py @@ -37,7 +37,7 @@ def _temp_exists(method, ip): def _exists_with_port(method, rule): - path = "/etc/csf/csf.{}".format(method) + path = f"/etc/csf/csf.{method}" return __salt__["file.contains"](path, rule) @@ -71,7 +71,7 @@ def exists( ip, port, proto, direction, port_origin, ip_origin, comment ) return _exists_with_port(method, rule) - exists = __salt__["cmd.run_all"]("egrep ^'{} +' /etc/csf/csf.{}".format(ip, method)) + exists = __salt__["cmd.run_all"](f"egrep ^'{ip} +' /etc/csf/csf.{method}") return not bool(exists["retcode"]) @@ -87,7 +87,7 @@ def __csf_cmd(cmd): ret = out["stdout"] else: ret = out["stderr"] - raise CommandExecutionError("csf failed: {}".format(ret)) + raise CommandExecutionError(f"csf failed: {ret}") else: ret = out["stdout"] return ret @@ -123,9 +123,9 @@ def _build_args(method, ip, comment): Returns the cmd args for csf basic allow/deny commands. """ opt = _get_opt(method) - args = "{} {}".format(opt, ip) + args = f"{opt} {ip}" if comment: - args += " {}".format(comment) + args += f" {comment}" return args @@ -178,7 +178,7 @@ def _build_port_rule(ip, port, proto, direction, port_origin, ip_origin, comment } rule = "{proto}|{direction}|{port_origin}={port}|{ip_origin}={ip}".format(**kwargs) if comment: - rule += " #{}".format(comment) + rule += f" #{comment}" return rule @@ -207,8 +207,8 @@ def _remove_access_rule_with_port( rule = rule.replace("|", "[|]") rule = rule.replace(".", "[.]") result = __salt__["file.replace"]( - "/etc/csf/csf.{}".format(method), - pattern="^{}(( +)?\\#.*)?$\n".format(rule), # pylint: disable=W1401 + f"/etc/csf/csf.{method}", + pattern=f"^{rule}(( +)?\\#.*)?$\n", # pylint: disable=W1401 repl="", ) @@ -233,7 +233,7 @@ def split_option(option): def get_option(option): - pattern = r'^{}(\ +)?\=(\ +)?".*"$'.format(option) # pylint: disable=W1401 + pattern = rf'^{option}(\ +)?\=(\ +)?".*"$' # pylint: disable=W1401 grep = __salt__["file.grep"]("/etc/csf/csf.conf", pattern, "-E") if "stdout" in grep and grep["stdout"]: line = grep["stdout"] @@ -247,8 +247,8 @@ def set_option(option, value): return {"error": "No such option exists in csf.conf"} result = __salt__["file.replace"]( "/etc/csf/csf.conf", - pattern=r'^{}(\ +)?\=(\ +)?".*"'.format(option), # pylint: disable=W1401 - repl='{} = "{}"'.format(option, value), + pattern=rf'^{option}(\ +)?\=(\ +)?".*"', # pylint: disable=W1401 + repl=f'{option} = "{value}"', ) return result @@ -279,9 +279,9 @@ def skip_nics(nics, ipv6=False): result = __salt__["file.replace"]( "/etc/csf/csf.conf", # pylint: disable=anomalous-backslash-in-string - pattern=r'^ETH{}_DEVICE_SKIP(\ +)?\=(\ +)?".*"'.format(ipv6), + pattern=rf'^ETH{ipv6}_DEVICE_SKIP(\ +)?\=(\ +)?".*"', # pylint: enable=anomalous-backslash-in-string - repl='ETH{}_DEVICE_SKIP = "{}"'.format(ipv6, nics_csv), + repl=f'ETH{ipv6}_DEVICE_SKIP = "{nics_csv}"', ) return result @@ -326,7 +326,7 @@ def _access_rule_with_port( ip_origin=ip_origin, comment=comment, ) - path = "/etc/csf/csf.{}".format(method) + path = f"/etc/csf/csf.{method}" results[direction] = __salt__["file.append"](path, rule) return results @@ -358,13 +358,13 @@ def _build_tmp_access_args(method, ip, ttl, port, direction, comment): Builds the cmd args for temporary access/deny opts. """ opt = _get_opt(method) - args = "{} {} {}".format(opt, ip, ttl) + args = f"{opt} {ip} {ttl}" if port: - args += " -p {}".format(port) + args += f" -p {port}" if direction: - args += " -d {}".format(direction) + args += f" -d {direction}" if comment: - args += " #{}".format(comment) + args += f" #{comment}" return args @@ -515,7 +515,7 @@ def deny( def remove_temp_rule(ip): opt = _get_opt("temprm") - args = "{} {}".format(opt, ip) + args = f"{opt} {ip}" return __csf_cmd(args) @@ -608,9 +608,9 @@ def allow_ports(ports, proto="tcp", direction="in"): result = __salt__["file.replace"]( "/etc/csf/csf.conf", # pylint: disable=anomalous-backslash-in-string - pattern=r'^{}_{}(\ +)?\=(\ +)?".*"$'.format(proto, direction), + pattern=rf'^{proto}_{direction}(\ +)?\=(\ +)?".*"$', # pylint: enable=anomalous-backslash-in-string - repl='{}_{} = "{}"'.format(proto, direction, ports_csv), + repl=f'{proto}_{direction} = "{ports_csv}"', ) results.append(result) @@ -635,7 +635,7 @@ def get_ports(proto="tcp", direction="in"): _validate_direction_and_proto(direction, proto) directions = build_directions(direction) for direction in directions: - option = "{}_{}".format(proto, direction) + option = f"{proto}_{direction}" results[direction] = _csf_to_list(option) return results @@ -701,7 +701,7 @@ def _toggle_testing(val): result = __salt__["file.replace"]( "/etc/csf/csf.conf", pattern=r'^TESTING(\ +)?\=(\ +)?".*"', # pylint: disable=W1401 - repl='TESTING = "{}"'.format(val), + repl=f'TESTING = "{val}"', ) return result diff --git a/salt/modules/cyg.py b/salt/modules/cyg.py index 9f7a61af59a..b76cbeb8010 100644 --- a/salt/modules/cyg.py +++ b/salt/modules/cyg.py @@ -45,7 +45,7 @@ def _get_cyg_dir(cyg_arch="x86_64"): elif cyg_arch == "x86": return "cygwin" - raise SaltInvocationError("Invalid architecture {arch}".format(arch=cyg_arch)) + raise SaltInvocationError(f"Invalid architecture {cyg_arch}") def _check_cygwin_installed(cyg_arch="x86_64"): @@ -129,9 +129,9 @@ def _run_silent_cygwin(cyg_arch="x86_64", args=None, mirrors=None): installation up and running. """ cyg_cache_dir = os.sep.join(["c:", "cygcache"]) - cyg_setup = "setup-{}.exe".format(cyg_arch) + cyg_setup = f"setup-{cyg_arch}.exe" cyg_setup_path = os.sep.join([cyg_cache_dir, cyg_setup]) - cyg_setup_source = "http://cygwin.com/{}".format(cyg_setup) + cyg_setup_source = f"http://cygwin.com/{cyg_setup}" # cyg_setup_source_hash = 'http://cygwin.com/{0}.sig'.format(cyg_setup) # until a hash gets published that we can verify the newest setup against @@ -147,15 +147,15 @@ def _run_silent_cygwin(cyg_arch="x86_64", args=None, mirrors=None): setup_command = cyg_setup_path options = [] - options.append("--local-package-dir {}".format(cyg_cache_dir)) + options.append(f"--local-package-dir {cyg_cache_dir}") if mirrors is None: mirrors = [{DEFAULT_MIRROR: DEFAULT_MIRROR_KEY}] for mirror in mirrors: for mirror_url, key in mirror.items(): - options.append("--site {}".format(mirror_url)) + options.append(f"--site {mirror_url}") if key: - options.append("--pubkey {}".format(key)) + options.append(f"--pubkey {key}") options.append("--no-desktop") options.append("--quiet-mode") options.append("--disable-buggy-antivirus") @@ -211,7 +211,7 @@ def install(packages=None, cyg_arch="x86_64", mirrors=None): args = [] # If we want to install packages if packages is not None: - args.append("--packages {pkgs}".format(pkgs=packages)) + args.append(f"--packages {packages}") # but we don't have cygwin installed yet if not _check_cygwin_installed(cyg_arch): # install just the base system @@ -240,7 +240,7 @@ def uninstall(packages, cyg_arch="x86_64", mirrors=None): """ args = [] if packages is not None: - args.append("--remove-packages {pkgs}".format(pkgs=packages)) + args.append(f"--remove-packages {packages}") LOG.debug("args: %s", args) if not _check_cygwin_installed(cyg_arch): LOG.debug("We're convinced cygwin isn't installed") diff --git a/salt/modules/daemontools.py b/salt/modules/daemontools.py index 84a9dc2eabf..7892cb561b8 100644 --- a/salt/modules/daemontools.py +++ b/salt/modules/daemontools.py @@ -44,7 +44,7 @@ def __virtual__(): BINS = frozenset(("svc", "supervise", "svok")) if all(salt.utils.path.which(b) for b in BINS) and SERVICE_DIR: return __virtualname__ - return (False, "Missing dependency: {}".format(BINS)) + return (False, f"Missing dependency: {BINS}") def _service_path(name): @@ -53,7 +53,7 @@ def _service_path(name): """ if not SERVICE_DIR: raise CommandExecutionError("Could not find service directory.") - return "{}/{}".format(SERVICE_DIR, name) + return f"{SERVICE_DIR}/{name}" # -- states.service compatible args @@ -67,8 +67,8 @@ def start(name): salt '*' daemontools.start """ - __salt__["file.remove"]("{}/down".format(_service_path(name))) - cmd = "svc -u {}".format(_service_path(name)) + __salt__["file.remove"](f"{_service_path(name)}/down") + cmd = f"svc -u {_service_path(name)}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -83,8 +83,8 @@ def stop(name): salt '*' daemontools.stop """ - __salt__["file.touch"]("{}/down".format(_service_path(name))) - cmd = "svc -d {}".format(_service_path(name)) + __salt__["file.touch"](f"{_service_path(name)}/down") + cmd = f"svc -d {_service_path(name)}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -98,7 +98,7 @@ def term(name): salt '*' daemontools.term """ - cmd = "svc -t {}".format(_service_path(name)) + cmd = f"svc -t {_service_path(name)}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -158,7 +158,7 @@ def status(name, sig=None): salt '*' daemontools.status """ - cmd = "svstat {}".format(_service_path(name)) + cmd = f"svstat {_service_path(name)}" out = __salt__["cmd.run_stdout"](cmd, python_shell=False) try: pid = re.search(r"\(pid (\d+)\)", out).group(1) diff --git a/salt/modules/datadog_api.py b/salt/modules/datadog_api.py index 7a18f903b45..ad775ef00dc 100644 --- a/salt/modules/datadog_api.py +++ b/salt/modules/datadog_api.py @@ -167,7 +167,7 @@ def cancel_downtime(api_key=None, app_key=None, scope=None, id=None): ret["comment"] = "Successfully cancelled downtime" else: ret["response"] = response.text - ret["comment"] = "Status Code: {}".format(response.status_code) + ret["comment"] = f"Status Code: {response.status_code}" return ret else: raise SaltInvocationError("One of id or scope must be specified") diff --git a/salt/modules/ddns.py b/salt/modules/ddns.py index 60bccff0719..54132ae21e0 100644 --- a/salt/modules/ddns.py +++ b/salt/modules/ddns.py @@ -62,7 +62,7 @@ def _config(name, key=None, **kwargs): if name in kwargs: value = kwargs[name] else: - value = __salt__["config.option"]("ddns.{}".format(key)) + value = __salt__["config.option"](f"ddns.{key}") if not value: value = None return value @@ -85,7 +85,7 @@ def add_host( replace=True, timeout=5, port=53, - **kwargs + **kwargs, ): """ Add, replace, or update the A and PTR (reverse) records for a host. @@ -100,7 +100,7 @@ def add_host( if res is False: return False - fqdn = "{}.{}.".format(name, zone) + fqdn = f"{name}.{zone}." parts = ip.split(".")[::-1] popped = [] @@ -130,7 +130,7 @@ def delete_host(zone, name, nameserver="127.0.0.1", timeout=5, port=53, **kwargs salt ns1 ddns.delete_host example.com host1 """ - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, "A") answer = dns.query.udp(request, nameserver, timeout, port) try: @@ -161,7 +161,7 @@ def delete_host(zone, name, nameserver="127.0.0.1", timeout=5, port=53, **kwargs nameserver=nameserver, timeout=timeout, port=port, - **kwargs + **kwargs, ) if ptr: res = True @@ -178,7 +178,7 @@ def update( timeout=5, replace=False, port=53, - **kwargs + **kwargs, ): """ Add, replace, or update a DNS record. @@ -197,7 +197,7 @@ def update( if name[-1:] == ".": fqdn = name else: - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) @@ -240,7 +240,7 @@ def delete( nameserver="127.0.0.1", timeout=5, port=53, - **kwargs + **kwargs, ): """ Delete a DNS record. @@ -256,7 +256,7 @@ def delete( if name[-1:] == ".": fqdn = name else: - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, (rdtype or "ANY")) answer = dns.query.udp(request, nameserver, timeout, port) diff --git a/salt/modules/deb_apache.py b/salt/modules/deb_apache.py index 0266cbc72eb..ce257fd1515 100644 --- a/salt/modules/deb_apache.py +++ b/salt/modules/deb_apache.py @@ -59,12 +59,10 @@ def check_site_enabled(site): if site.endswith(".conf"): site_file = site else: - site_file = "{}.conf".format(site) - if os.path.islink("{}/{}".format(SITE_ENABLED_DIR, site_file)): + site_file = f"{site}.conf" + if os.path.islink(f"{SITE_ENABLED_DIR}/{site_file}"): return True - elif site == "default" and os.path.islink( - "{}/000-{}".format(SITE_ENABLED_DIR, site_file) - ): + elif site == "default" and os.path.islink(f"{SITE_ENABLED_DIR}/000-{site_file}"): return True else: return False @@ -95,9 +93,9 @@ def a2ensite(site): ret["Site"] = site if status == 1: - ret["Status"] = "Site {} Not found".format(site) + ret["Status"] = f"Site {site} Not found" elif status == 0: - ret["Status"] = "Site {} enabled".format(site) + ret["Status"] = f"Site {site} enabled" else: ret["Status"] = status @@ -129,9 +127,9 @@ def a2dissite(site): ret["Site"] = site if status == 256: - ret["Status"] = "Site {} Not found".format(site) + ret["Status"] = f"Site {site} Not found" elif status == 0: - ret["Status"] = "Site {} disabled".format(site) + ret["Status"] = f"Site {site} disabled" else: ret["Status"] = status @@ -156,8 +154,8 @@ def check_mod_enabled(mod): if mod.endswith(".load") or mod.endswith(".conf"): mod_file = mod else: - mod_file = "{}.load".format(mod) - return os.path.islink("/etc/apache2/mods-enabled/{}".format(mod_file)) + mod_file = f"{mod}.load" + return os.path.islink(f"/etc/apache2/mods-enabled/{mod_file}") def a2enmod(mod): @@ -185,9 +183,9 @@ def a2enmod(mod): ret["Mod"] = mod if status == 1: - ret["Status"] = "Mod {} Not found".format(mod) + ret["Status"] = f"Mod {mod} Not found" elif status == 0: - ret["Status"] = "Mod {} enabled".format(mod) + ret["Status"] = f"Mod {mod} enabled" else: ret["Status"] = status @@ -219,9 +217,9 @@ def a2dismod(mod): ret["Mod"] = mod if status == 256: - ret["Status"] = "Mod {} Not found".format(mod) + ret["Status"] = f"Mod {mod} Not found" elif status == 0: - ret["Status"] = "Mod {} disabled".format(mod) + ret["Status"] = f"Mod {mod} disabled" else: ret["Status"] = status @@ -247,8 +245,8 @@ def check_conf_enabled(conf): if conf.endswith(".conf"): conf_file = conf else: - conf_file = "{}.conf".format(conf) - return os.path.islink("/etc/apache2/conf-enabled/{}".format(conf_file)) + conf_file = f"{conf}.conf" + return os.path.islink(f"/etc/apache2/conf-enabled/{conf_file}") @salt.utils.decorators.path.which("a2enconf") @@ -279,9 +277,9 @@ def a2enconf(conf): ret["Conf"] = conf if status == 1: - ret["Status"] = "Conf {} Not found".format(conf) + ret["Status"] = f"Conf {conf} Not found" elif status == 0: - ret["Status"] = "Conf {} enabled".format(conf) + ret["Status"] = f"Conf {conf} enabled" else: ret["Status"] = status @@ -316,9 +314,9 @@ def a2disconf(conf): ret["Conf"] = conf if status == 256: - ret["Status"] = "Conf {} Not found".format(conf) + ret["Status"] = f"Conf {conf} Not found" elif status == 0: - ret["Status"] = "Conf {} disabled".format(conf) + ret["Status"] = f"Conf {conf} disabled" else: ret["Status"] = status diff --git a/salt/modules/debconfmod.py b/salt/modules/debconfmod.py index b4cd3a1934b..7f7644fb84b 100644 --- a/salt/modules/debconfmod.py +++ b/salt/modules/debconfmod.py @@ -106,7 +106,7 @@ def _set_file(path): """ Execute the set selections command for debconf """ - cmd = "debconf-set-selections {}".format(path) + cmd = f"debconf-set-selections {path}" __salt__["cmd.run_stdout"](cmd, python_shell=False) @@ -127,7 +127,7 @@ def set_(package, question, type, value, *extra): fd_, fname = salt.utils.files.mkstemp(prefix="salt-", close_fd=False) - line = "{} {} {} {}".format(package, question, type, value) + line = f"{package} {question} {type} {value}" os.write(fd_, salt.utils.stringutils.to_bytes(line)) os.close(fd_) @@ -169,7 +169,7 @@ def set_template(path, template, context, defaults, saltenv="base", **kwargs): saltenv=saltenv, context=context, defaults=defaults, - **kwargs + **kwargs, ) return set_file(path, saltenv, **kwargs) diff --git a/salt/modules/debian_ip.py b/salt/modules/debian_ip.py index 8c901488d10..9953b5c51ef 100644 --- a/salt/modules/debian_ip.py +++ b/salt/modules/debian_ip.py @@ -366,9 +366,9 @@ def __within2(value, within=None, errmsg=None, dtype=None): "__name__", hasattr(dtype, "__class__") and getattr(dtype.__class__, "name", dtype), ) - errmsg = "{} within '{}'".format(typename, within) + errmsg = f"{typename} within '{within}'" else: - errmsg = "within '{}'".format(within) + errmsg = f"within '{within}'" return (valid, _value, errmsg) @@ -387,7 +387,7 @@ def __space_delimited_list(value): return ( False, value, - "{} is not a valid space-delimited value.\n".format(value), + f"{value} is not a valid space-delimited value.\n", ) @@ -549,8 +549,7 @@ def _parse_interfaces(interface_files=None): # Add this later. if os.path.exists(_DEB_NETWORK_DIR): interface_files += [ - "{}/{}".format(_DEB_NETWORK_DIR, dir) - for dir in os.listdir(_DEB_NETWORK_DIR) + f"{_DEB_NETWORK_DIR}/{dir}" for dir in os.listdir(_DEB_NETWORK_DIR) ] if os.path.isfile(_DEB_NETWORK_FILE): @@ -690,7 +689,7 @@ def _filter_malformed_interfaces(*, adapters): if iface_name == "source": continue if "data" not in adapters[iface_name]: - msg = "Interface file malformed for interface: {}.".format(iface_name) + msg = f"Interface file malformed for interface: {iface_name}." log.error(msg) adapters.pop(iface_name) continue @@ -1198,7 +1197,7 @@ def _parse_bridge_opts(opts, iface): try: port, cost_or_prio = opts[opt].split() int(cost_or_prio) - config.update({opt: "{} {}".format(port, cost_or_prio)}) + config.update({opt: f"{port} {cost_or_prio}"}) except ValueError: _raise_error_iface(iface, opt, ["interface integer"]) @@ -1630,15 +1629,15 @@ def build_bond(iface, **settings): if "test" in settings and settings["test"]: return _read_temp(data) - _write_file(iface, data, _DEB_NETWORK_CONF_FILES, "{}.conf".format(iface)) - path = os.path.join(_DEB_NETWORK_CONF_FILES, "{}.conf".format(iface)) + _write_file(iface, data, _DEB_NETWORK_CONF_FILES, f"{iface}.conf") + path = os.path.join(_DEB_NETWORK_CONF_FILES, f"{iface}.conf") if deb_major == "5": for line_type in ("alias", "options"): cmd = [ "sed", "-i", "-e", - r"/^{}\s{}.*/d".format(line_type, iface), + rf"/^{line_type}\s{iface}.*/d", "/etc/modprobe.conf", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -1782,7 +1781,7 @@ def get_bond(iface): salt '*' ip.get_bond bond0 """ - path = os.path.join(_DEB_NETWORK_CONF_FILES, "{}.conf".format(iface)) + path = os.path.join(_DEB_NETWORK_CONF_FILES, f"{iface}.conf") return _read_file(path) @@ -1888,10 +1887,10 @@ def get_routes(iface): salt '*' ip.get_routes eth0 """ - filename = os.path.join(_DEB_NETWORK_UP_DIR, "route-{}".format(iface)) + filename = os.path.join(_DEB_NETWORK_UP_DIR, f"route-{iface}") results = _read_file(filename) - filename = os.path.join(_DEB_NETWORK_DOWN_DIR, "route-{}".format(iface)) + filename = os.path.join(_DEB_NETWORK_DOWN_DIR, f"route-{iface}") results += _read_file(filename) return results @@ -2032,20 +2031,20 @@ def build_network_settings(**settings): for item in _read_file(_DEB_RESOLV_FILE): if domain_prog.match(item): - item = "domain {}".format(domainname) + item = f"domain {domainname}" elif search_prog.match(item): - item = "search {}".format(searchdomain) + item = f"search {searchdomain}" new_contents.append(item) # A domain line didn't exist so we'll add one in # with the new domainname if "domain" not in resolve: - new_contents.insert(0, "domain {}".format(domainname)) + new_contents.insert(0, f"domain {domainname}") # A search line didn't exist so we'll add one in # with the new search domain if "search" not in resolve: - new_contents.insert("domain" in resolve, "search {}".format(searchdomain)) + new_contents.insert("domain" in resolve, f"search {searchdomain}") new_resolv = "\n".join(new_contents) diff --git a/salt/modules/debian_service.py b/salt/modules/debian_service.py index 04c6cd5d37b..e11d9d18e7e 100644 --- a/salt/modules/debian_service.py +++ b/salt/modules/debian_service.py @@ -74,9 +74,9 @@ def get_enabled(): salt '*' service.get_enabled """ - prefix = "/etc/rc[S{}].d/S".format(_get_runlevel()) + prefix = f"/etc/rc[S{_get_runlevel()}].d/S" ret = set() - for line in [x.rsplit(os.sep, 1)[-1] for x in glob.glob("{}*".format(prefix))]: + for line in [x.rsplit(os.sep, 1)[-1] for x in glob.glob(f"{prefix}*")]: ret.add(re.split(r"\d+", line)[-1]) return sorted(ret) @@ -277,7 +277,7 @@ def disable(name, **kwargs): salt '*' service.disable """ - cmd = "update-rc.d {} disable".format(name) + cmd = f"update-rc.d {name} disable" return not __salt__["cmd.retcode"](cmd) diff --git a/salt/modules/debuild_pkgbuild.py b/salt/modules/debuild_pkgbuild.py index 21c2629332b..cc5217b7b72 100644 --- a/salt/modules/debuild_pkgbuild.py +++ b/salt/modules/debuild_pkgbuild.py @@ -90,9 +90,7 @@ def _check_repo_gpg_phrase_utils(): if __salt__["file.file_exists"](util_name): return True else: - raise CommandExecutionError( - "utility '{}' needs to be installed".format(util_name) - ) + raise CommandExecutionError(f"utility '{util_name}' needs to be installed") def _get_build_env(env): @@ -105,8 +103,8 @@ def _get_build_env(env): if not isinstance(env, dict): raise SaltInvocationError("'env' must be a Python dictionary") for key, value in env.items(): - env_override += "{}={}\n".format(key, value) - env_override += "export {}\n".format(key) + env_override += f"{key}={value}\n" + env_override += f"export {key}\n" return env_override @@ -139,7 +137,7 @@ def _get_repo_options_env(env): raise SaltInvocationError("'env' must be a Python dictionary") for key, value in env.items(): if key == "OPTIONS": - env_options += "{}\n".format(value) + env_options += f"{value}\n" return env_options @@ -194,7 +192,7 @@ def _get_repo_dists_env(env): if env is None: for key, value in dflts_dict.items(): if dflts_dict[key][0] == "M": - env_dists += "{}: {}\n".format(dflts_dict[key][1], dflts_dict[key][2]) + env_dists += f"{dflts_dict[key][1]}: {dflts_dict[key][2]}\n" if key == "CODENAME": codename = dflts_dict[key][2] return (codename, env_dists) @@ -210,15 +208,15 @@ def _get_repo_dists_env(env): if key == "CODENAME": codename = value if dflts_dict[key][0] != "I": - env_dists += "{}: {}\n".format(dflts_dict[key][1], value) + env_dists += f"{dflts_dict[key][1]}: {value}\n" else: - env_dists += "{}: {}\n".format(key, value) + env_dists += f"{key}: {value}\n" # ensure mandatories are included env_keys = list(env.keys()) for key in env_keys: if key in dflts_keys and dflts_dict[key][0] == "M" and key not in env_man_seen: - env_dists += "{}: {}\n".format(dflts_dict[key][1], dflts_dict[key][2]) + env_dists += f"{dflts_dict[key][1]}: {dflts_dict[key][2]}\n" if key == "CODENAME": codename = value @@ -256,7 +254,7 @@ def _create_pbuilders(env, runas="root"): Ensure the user has correct permissions to any files and directories which are to be utilized. """ - home = os.path.expanduser("~{}".format(runas)) + home = os.path.expanduser(f"~{runas}") pbuilderrc = os.path.join(home, ".pbuilderrc") if not os.path.isfile(pbuilderrc): raise SaltInvocationError("pbuilderrc environment is incorrectly setup") @@ -425,25 +423,25 @@ def make_src_pkg(dest_dir, spec, sources, env=None, saltenv="base", runas="root" debname_orig = debname + ".orig.tar.gz" abspath_debname = os.path.join(tree_base, debname) - cmd = "tar -xvzf {}".format(salttarball) + cmd = f"tar -xvzf {salttarball}" retrc = __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user) - cmd = "mv {} {}".format(salttar_name, debname) + cmd = f"mv {salttar_name} {debname}" retrc |= __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user) - cmd = "tar -cvzf {} {}".format(os.path.join(tree_base, debname_orig), debname) + cmd = f"tar -cvzf {os.path.join(tree_base, debname_orig)} {debname}" retrc |= __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user) - cmd = "rm -f {}".format(salttarball) + cmd = f"rm -f {salttarball}" retrc |= __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user, env=env) - cmd = "cp {} {}".format(spec_pathfile, abspath_debname) + cmd = f"cp {spec_pathfile} {abspath_debname}" retrc |= __salt__["cmd.retcode"](cmd, cwd=abspath_debname, runas=root_user) - cmd = "tar -xvJf {}".format(spec_pathfile) + cmd = f"tar -xvJf {spec_pathfile}" retrc |= __salt__["cmd.retcode"](cmd, cwd=abspath_debname, runas=root_user, env=env) - cmd = "rm -f {}".format(os.path.basename(spec_pathfile)) + cmd = f"rm -f {os.path.basename(spec_pathfile)}" retrc |= __salt__["cmd.retcode"](cmd, cwd=abspath_debname, runas=root_user) cmd = "debuild -S -uc -us -sa" retrc |= __salt__["cmd.retcode"]( cmd, cwd=abspath_debname, runas=root_user, python_shell=True, env=env ) - cmd = "rm -fR {}".format(abspath_debname) + cmd = f"rm -fR {abspath_debname}" retrc |= __salt__["cmd.retcode"](cmd, runas=root_user) if retrc != 0: raise SaltInvocationError( @@ -511,13 +509,13 @@ def build( # ensure pbuilder setup from runas if other than root if runas != root_user: - user_home = os.path.expanduser("~{}".format(runas)) + user_home = os.path.expanduser(f"~{runas}") root_home = os.path.expanduser("~root") - cmd = "cp {}/.pbuilderrc {}/".format(user_home, root_home) + cmd = f"cp {user_home}/.pbuilderrc {root_home}/" retrc = __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) - cmd = "cp -R {}/.pbuilder-hooks {}/".format(user_home, root_home) + cmd = f"cp -R {user_home}/.pbuilder-hooks {root_home}/" retrc = __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) @@ -539,7 +537,7 @@ def build( results_dir = "/var/cache/pbuilder/result" # ensure clean - cmd = "rm -fR {}".format(results_dir) + cmd = f"rm -fR {results_dir}" retrc |= __salt__["cmd.retcode"](cmd, runas=root_user, python_shell=True, env=env) # dscs should only contain salt orig and debian tarballs and dsc file @@ -558,7 +556,7 @@ def build( retrc |= __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) - cmd = '/usr/sbin/pbuilder build --debbuildopts "-sa" {}'.format(dsc) + cmd = f'/usr/sbin/pbuilder build --debbuildopts "-sa" {dsc}' retrc |= __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) @@ -711,15 +709,15 @@ def make_repo( phrase = "" # preset passphase and interaction with gpg-agent - gpg_info_file = "{}/gpg-agent-info-salt".format(gnupghome) - gpg_tty_info_file = "{}/gpg-tty-info-salt".format(gnupghome) + gpg_info_file = f"{gnupghome}/gpg-agent-info-salt" + gpg_tty_info_file = f"{gnupghome}/gpg-tty-info-salt" # if using older than gnupg 2.1, then env file exists older_gnupg = __salt__["file.file_exists"](gpg_info_file) if keyid is not None: with salt.utils.files.fopen(repoconfdist, "a") as fow: - fow.write(salt.utils.stringutils.to_str("SignWith: {}\n".format(keyid))) + fow.write(salt.utils.stringutils.to_str(f"SignWith: {keyid}\n")) # import_keys pkg_pub_key_file = "{}/{}".format( @@ -827,7 +825,7 @@ def make_repo( # sign_it_here if older_gnupg: if local_keyid is not None: - cmd = "debsign --re-sign -k {} {}".format(keyid, abs_file) + cmd = f"debsign --re-sign -k {keyid} {abs_file}" retrc |= __salt__["cmd.retcode"]( cmd, runas=runas, cwd=repodir, use_vt=True, env=env ) @@ -845,7 +843,7 @@ def make_repo( if local_keyid is not None: number_retries = timeout / interval times_looped = 0 - error_msg = "Failed to debsign file {}".format(abs_file) + error_msg = f"Failed to debsign file {abs_file}" if ( __grains__["os"] in ["Ubuntu"] and __grains__["osmajorrelease"] < 18 @@ -853,7 +851,7 @@ def make_repo( __grains__["os"] in ["Debian"] and __grains__["osmajorrelease"] <= 8 ): - cmd = "debsign --re-sign -k {} {}".format(keyid, abs_file) + cmd = f"debsign --re-sign -k {keyid} {abs_file}" try: proc = salt.utils.vt.Terminal( cmd, @@ -902,7 +900,7 @@ def make_repo( number_retries = timeout / interval times_looped = 0 - error_msg = "Failed to reprepro includedsc file {}".format(abs_file) + error_msg = f"Failed to reprepro includedsc file {abs_file}" cmd = ( "reprepro --ignore=wrongdistribution --component=main -Vb ." " includedsc {} {}".format(codename, abs_file) diff --git a/salt/modules/devinfo.py b/salt/modules/devinfo.py index d6c530aa2e2..ea9d3f5da67 100644 --- a/salt/modules/devinfo.py +++ b/salt/modules/devinfo.py @@ -293,7 +293,7 @@ def hwinfo(items=None, short=True, listmd=False, devices=None): cmd = ["hwinfo"] for item in items: - cmd.append("--{}".format(item)) + cmd.append(f"--{item}") if short: cmd.append("--short") @@ -302,7 +302,7 @@ def hwinfo(items=None, short=True, listmd=False, devices=None): cmd.append("--listmd") for device in devices: - cmd.append("--only {}".format(device)) + cmd.append(f"--only {device}") out = __salt__["cmd.run_stdout"](cmd) result["hwinfo"] = _hwinfo_parse(out, short) diff --git a/salt/modules/devmap.py b/salt/modules/devmap.py index 247d0293c2e..9f14ee6c9c8 100644 --- a/salt/modules/devmap.py +++ b/salt/modules/devmap.py @@ -30,7 +30,7 @@ def multipath_flush(device): salt '*' devmap.multipath_flush mpath1 """ if not os.path.exists(device): - return "{} does not exist".format(device) + return f"{device} does not exist" - cmd = "multipath -f {}".format(device) + cmd = f"multipath -f {device}" return __salt__["cmd.run"](cmd).splitlines() diff --git a/salt/modules/dig.py b/salt/modules/dig.py index a78e4875ded..79023236653 100644 --- a/salt/modules/dig.py +++ b/salt/modules/dig.py @@ -84,7 +84,7 @@ def A(host, nameserver=None): dig = ["dig", "+short", str(host), "A"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -116,7 +116,7 @@ def PTR(host, nameserver=None): dig = ["dig", "+short", "-x", str(host)] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -145,7 +145,7 @@ def AAAA(host, nameserver=None): dig = ["dig", "+short", str(host), "AAAA"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -175,7 +175,7 @@ def CNAME(host, nameserver=None): dig = ["dig", "+short", str(host), "CNAME"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -204,7 +204,7 @@ def NS(domain, resolve=True, nameserver=None): dig = ["dig", "+short", str(domain), "NS"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -243,7 +243,7 @@ def SPF(domain, record="SPF", nameserver=None): cmd = ["dig", "+short", str(domain), record] if nameserver is not None: - cmd.append("@{}".format(nameserver)) + cmd.append(f"@{nameserver}") result = __salt__["cmd.run_all"](cmd, python_shell=False) # In this case, 0 is not the same as False @@ -300,7 +300,7 @@ def MX(domain, resolve=False, nameserver=None): dig = ["dig", "+short", str(domain), "MX"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -334,7 +334,7 @@ def TXT(host, nameserver=None): dig = ["dig", "+short", str(host), "TXT"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) diff --git a/salt/modules/disk.py b/salt/modules/disk.py index c7e5f905c07..8eea765a30f 100644 --- a/salt/modules/disk.py +++ b/salt/modules/disk.py @@ -71,7 +71,7 @@ def _clean_flags(args, caller): if flag in allowed: flags += flag else: - raise CommandExecutionError("Invalid flag passed to {}".format(caller)) + raise CommandExecutionError(f"Invalid flag passed to {caller}") return flags @@ -108,7 +108,7 @@ def usage(args=None): else: cmd = "df" if flags: - cmd += " -{}".format(flags) + cmd += f" -{flags}" ret = {} out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() oldline = None @@ -126,7 +126,7 @@ def usage(args=None): else: oldline = None while len(comps) >= 2 and not comps[1].isdigit(): - comps[0] = "{} {}".format(comps[0], comps[1]) + comps[0] = f"{comps[0]} {comps[1]}" comps.pop(1) if len(comps) < 2: continue @@ -172,7 +172,7 @@ def inodeusage(args=None): else: cmd = "df -iP" if flags: - cmd += " -{}".format(flags) + cmd += f" -{flags}" ret = {} out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() for line in out: @@ -239,7 +239,7 @@ def percent(args=None): continue comps = line.split() while len(comps) >= 2 and not comps[1].isdigit(): - comps[0] = "{} {}".format(comps[0], comps[1]) + comps[0] = f"{comps[0]} {comps[1]}" comps.pop(1) if len(comps) < 2: continue @@ -344,10 +344,10 @@ def tune(device, **kwargs): else: args.append("getro") if kwargs[key] == "True" or kwargs[key] is True: - opts += "--{} ".format(key) + opts += f"--{key} " else: - opts += "--{} {} ".format(switch, kwargs[key]) - cmd = "blockdev {}{}".format(opts, device) + opts += f"--{switch} {kwargs[key]} " + cmd = f"blockdev {opts}{device}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() return dump(device, args) @@ -363,7 +363,7 @@ def wipe(device): salt '*' disk.wipe /dev/sda1 """ - cmd = "wipefs -a {}".format(device) + cmd = f"wipefs -a {device}" try: out = __salt__["cmd.run_all"](cmd, python_shell=False) except subprocess.CalledProcessError as err: @@ -419,7 +419,7 @@ def resize2fs(device): salt '*' disk.resize2fs /dev/sda1 """ - cmd = "resize2fs {}".format(device) + cmd = f"resize2fs {device}" try: out = __salt__["cmd.run_all"](cmd, python_shell=False) except subprocess.CalledProcessError as err: @@ -486,10 +486,10 @@ def format_( if fs_type[:3] == "ext": cmd.extend(["-i", str(inode_size)]) elif fs_type == "xfs": - cmd.extend(["-i", "size={}".format(inode_size)]) + cmd.extend(["-i", f"size={inode_size}"]) if lazy_itable_init is not None: if fs_type[:3] == "ext": - cmd.extend(["-E", "lazy_itable_init={}".format(lazy_itable_init)]) + cmd.extend(["-E", f"lazy_itable_init={lazy_itable_init}"]) if fat is not None and fat in (12, 16, 32): if fs_type[-3:] == "fat": cmd.extend(["-F", fat]) @@ -523,9 +523,7 @@ def fstype(device): salt '*' disk.fstype /dev/sdX1 """ if salt.utils.path.which("lsblk"): - lsblk_out = __salt__["cmd.run"]( - "lsblk -o fstype {}".format(device) - ).splitlines() + lsblk_out = __salt__["cmd.run"](f"lsblk -o fstype {device}").splitlines() if len(lsblk_out) > 1: fs_type = lsblk_out[1].strip() if fs_type: @@ -535,15 +533,13 @@ def fstype(device): # the fstype was not set on the block device, so inspect the filesystem # itself for its type if __grains__["kernel"] == "AIX" and os.path.isfile("/usr/sysv/bin/df"): - df_out = __salt__["cmd.run"]( - "/usr/sysv/bin/df -n {}".format(device) - ).split() + df_out = __salt__["cmd.run"](f"/usr/sysv/bin/df -n {device}").split() if len(df_out) > 2: fs_type = df_out[2] if fs_type: return fs_type else: - df_out = __salt__["cmd.run"]("df -T {}".format(device)).splitlines() + df_out = __salt__["cmd.run"](f"df -T {device}").splitlines() if len(df_out) > 1: fs_type = df_out[1] if fs_type: @@ -559,7 +555,7 @@ def _hdparm(args, failhard=True): Fail hard when required return output when possible """ - cmd = "hdparm {}".format(args) + cmd = f"hdparm {args}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] != 0: msg = "{}: {}".format(cmd, result["stderr"]) @@ -598,9 +594,9 @@ def hdparms(disks, args=None): out = {} for disk in disks: if not disk.startswith("/dev"): - disk = "/dev/{}".format(disk) + disk = f"/dev/{disk}" disk_data = {} - for line in _hdparm("-{} {}".format(args, disk), False).splitlines(): + for line in _hdparm(f"-{args} {disk}", False).splitlines(): line = line.strip() if not line or line == disk + ":": continue @@ -700,7 +696,7 @@ def hpa(disks, size=None): if size <= 0: size = data["total"] - _hdparm("--yes-i-know-what-i-am-doing -Np{} {}".format(size, disk)) + _hdparm(f"--yes-i-know-what-i-am-doing -Np{size} {disk}") def smart_attributes(dev, attributes=None, values=None): @@ -726,7 +722,7 @@ def smart_attributes(dev, attributes=None, values=None): if not dev.startswith("/dev/"): dev = "/dev/" + dev - cmd = "smartctl --attributes {}".format(dev) + cmd = f"smartctl --attributes {dev}" smart_result = __salt__["cmd.run_all"](cmd, output_loglevel="quiet") if smart_result["retcode"] != 0: raise CommandExecutionError(smart_result["stderr"]) @@ -819,9 +815,9 @@ def _iostat_fbsd(interval, count, disks): Tested on FreeBSD, quite likely other BSD's only need small changes in cmd syntax """ if disks is None: - iostat_cmd = "iostat -xC -w {} -c {} ".format(interval, count) + iostat_cmd = f"iostat -xC -w {interval} -c {count} " elif isinstance(disks, str): - iostat_cmd = "iostat -x -w {} -c {} {}".format(interval, count, disks) + iostat_cmd = f"iostat -x -w {interval} -c {count} {disks}" else: iostat_cmd = "iostat -x -w {} -c {} {}".format(interval, count, " ".join(disks)) @@ -874,9 +870,9 @@ def _iostat_fbsd(interval, count, disks): def _iostat_linux(interval, count, disks): if disks is None: - iostat_cmd = "iostat -x {} {} ".format(interval, count) + iostat_cmd = f"iostat -x {interval} {count} " elif isinstance(disks, str): - iostat_cmd = "iostat -xd {} {} {}".format(interval, count, disks) + iostat_cmd = f"iostat -xd {interval} {count} {disks}" else: iostat_cmd = "iostat -xd {} {} {}".format(interval, count, " ".join(disks)) @@ -924,9 +920,9 @@ def _iostat_aix(interval, count, disks): log.debug("AIX disk iostat entry") if disks is None: - iostat_cmd = "iostat -dD {} {} ".format(interval, count) + iostat_cmd = f"iostat -dD {interval} {count} " elif isinstance(disks, str): - iostat_cmd = "iostat -dD {} {} {}".format(disks, interval, count) + iostat_cmd = f"iostat -dD {disks} {interval} {count}" else: iostat_cmd = "iostat -dD {} {} {}".format(" ".join(disks), interval, count) diff --git a/salt/modules/djangomod.py b/salt/modules/djangomod.py index 9047667e589..b66479f9a32 100644 --- a/salt/modules/djangomod.py +++ b/salt/modules/djangomod.py @@ -43,7 +43,7 @@ def command( env=None, runas=None, *args, - **kwargs + **kwargs, ): """ Run arbitrary django management command @@ -55,17 +55,17 @@ def command( salt '*' django.command """ dja = _get_django_admin(bin_env) - cmd = "{} {} --settings={}".format(dja, command, settings_module) + cmd = f"{dja} {command} --settings={settings_module}" if pythonpath: - cmd = "{} --pythonpath={}".format(cmd, pythonpath) + cmd = f"{cmd} --pythonpath={pythonpath}" for arg in args: - cmd = "{} --{}".format(cmd, arg) + cmd = f"{cmd} --{arg}" for key, value in kwargs.items(): if not key.startswith("__"): - cmd = "{} --{}={}".format(cmd, key, value) + cmd = f"{cmd} --{key}={value}" return __salt__["cmd.run"](cmd, env=env, runas=runas, python_shell=False) @@ -192,9 +192,9 @@ def migrate( args.append("noinput") if app_label and migration_name: - cmd = "migrate {} {}".format(app_label, migration_name) + cmd = f"migrate {app_label} {migration_name}" elif app_label: - cmd = "migrate {}".format(app_label) + cmd = f"migrate {app_label}" else: cmd = "migrate" @@ -239,7 +239,7 @@ def createsuperuser( env, runas, *args, - **kwargs + **kwargs, ) @@ -315,5 +315,5 @@ def collectstatic( env, runas, *args, - **kwargs + **kwargs, ) diff --git a/salt/modules/dnsmasq.py b/salt/modules/dnsmasq.py index af9c8b8ccba..5aec67f959f 100644 --- a/salt/modules/dnsmasq.py +++ b/salt/modules/dnsmasq.py @@ -113,13 +113,13 @@ def set_config(config_file="/etc/dnsmasq.conf", follow=True, **kwargs): for config in includes: __salt__["file.sed"]( path=config, - before="^{}=.*".format(key), - after="{}={}".format(key, kwargs[key]), + before=f"^{key}=.*", + after=f"{key}={kwargs[key]}", ) else: - __salt__["file.append"](config_file, "{}={}".format(key, kwargs[key])) + __salt__["file.append"](config_file, f"{key}={kwargs[key]}") else: - __salt__["file.append"](config_file, "{}={}".format(key, kwargs[key])) + __salt__["file.append"](config_file, f"{key}={kwargs[key]}") return ret_kwargs @@ -160,7 +160,7 @@ def _parse_dnamasq(filename): fileopts = {} if not os.path.isfile(filename): - raise CommandExecutionError("Error: No such file '{}'".format(filename)) + raise CommandExecutionError(f"Error: No such file '{filename}'") with salt.utils.files.fopen(filename, "r") as fp_: for line in fp_: diff --git a/salt/modules/dnsutil.py b/salt/modules/dnsutil.py index bc25f3d3386..5b677d777ee 100644 --- a/salt/modules/dnsutil.py +++ b/salt/modules/dnsutil.py @@ -74,13 +74,13 @@ def hosts_append(hostsfile="/etc/hosts", ip_addr=None, entries=None): host_list.remove(host) if not host_list: - return "No additional hosts were added to {}".format(hostsfile) + return f"No additional hosts were added to {hostsfile}" append_line = "\n{} {}".format(ip_addr, " ".join(host_list)) with salt.utils.files.fopen(hostsfile, "a") as fp_: fp_.write(salt.utils.stringutils.to_str(append_line)) - return "The following line was added to {}:{}".format(hostsfile, append_line) + return f"The following line was added to {hostsfile}:{append_line}" def hosts_remove(hostsfile="/etc/hosts", entries=None): @@ -103,7 +103,7 @@ def hosts_remove(hostsfile="/etc/hosts", entries=None): with salt.utils.files.fopen(hostsfile, "w") as out_file: for line in hosts.splitlines(): if not line or line.strip().startswith("#"): - out_file.write(salt.utils.stringutils.to_str("{}\n".format(line))) + out_file.write(salt.utils.stringutils.to_str(f"{line}\n")) continue comps = line.split() for host in host_list: @@ -149,7 +149,7 @@ def parse_zone(zonefile=None, zone=None): mode = "multi" multi = "" if mode == "multi": - multi += " {}".format(line) + multi += f" {line}" if ")" in line: mode = "single" line = multi.replace("(", "").replace(")", "") @@ -267,7 +267,7 @@ def A(host, nameserver=None): ] return addresses except socket.gaierror: - return "Unable to resolve {}".format(host) + return f"Unable to resolve {host}" return "This function requires dig, which is not currently available" @@ -299,7 +299,7 @@ def AAAA(host, nameserver=None): ] return addresses except socket.gaierror: - return "Unable to resolve {}".format(host) + return f"Unable to resolve {host}" return "This function requires dig, which is not currently available" @@ -394,7 +394,7 @@ def serial(zone="", update=False): grains = {} key = "dnsserial" if zone: - key += "_{}".format(zone) + key += f"_{zone}" stored = __salt__["grains.get"](key=key) present = time.strftime("%Y%m%d01") if not update: diff --git a/salt/modules/dockercompose.py b/salt/modules/dockercompose.py index 7ebdf2207e9..bb71049d9ea 100644 --- a/salt/modules/dockercompose.py +++ b/salt/modules/dockercompose.py @@ -200,7 +200,7 @@ def __read_docker_compose_file(file_path): """ if not os.path.isfile(file_path): return __standardize_result( - False, "Path {} is not present".format(file_path), None, None + False, f"Path {file_path} is not present", None, None ) try: with salt.utils.files.fopen(file_path, "r") as fl: @@ -209,12 +209,8 @@ def __read_docker_compose_file(file_path): for line in fl: result[file_name] += salt.utils.stringutils.to_unicode(line) except OSError: - return __standardize_result( - False, "Could not read {}".format(file_path), None, None - ) - return __standardize_result( - True, "Reading content of {}".format(file_path), result, None - ) + return __standardize_result(False, f"Could not read {file_path}", None, None) + return __standardize_result(True, f"Reading content of {file_path}", result, None) def __load_docker_compose(path): @@ -226,14 +222,12 @@ def __load_docker_compose(path): """ file_path = __get_docker_file_path(path) if file_path is None: - msg = "Could not find docker-compose file at {}".format(path) + msg = f"Could not find docker-compose file at {path}" return None, __standardize_result(False, msg, None, None) if not os.path.isfile(file_path): return ( None, - __standardize_result( - False, "Path {} is not present".format(file_path), None, None - ), + __standardize_result(False, f"Path {file_path} is not present", None, None), ) try: with salt.utils.files.fopen(file_path, "r") as fl: @@ -241,15 +235,13 @@ def __load_docker_compose(path): except OSError: return ( None, - __standardize_result( - False, "Could not read {}".format(file_path), None, None - ), + __standardize_result(False, f"Could not read {file_path}", None, None), ) except yaml.YAMLError as yerr: - msg = "Could not parse {} {}".format(file_path, yerr) + msg = f"Could not parse {file_path} {yerr}" return None, __standardize_result(False, msg, None, None) if not loaded: - msg = "Got empty compose file at {}".format(file_path) + msg = f"Got empty compose file at {file_path}" return None, __standardize_result(False, msg, None, None) if "services" not in loaded: loaded["services"] = {} @@ -269,7 +261,7 @@ def __dump_docker_compose(path, content, already_existed): dumped = yaml.safe_dump(content, indent=2, default_flow_style=False) return __write_docker_compose(path, dumped, already_existed) except TypeError as t_err: - msg = "Could not dump {} {}".format(content, t_err) + msg = f"Could not dump {content} {t_err}" return __standardize_result(False, msg, None, None) @@ -297,9 +289,7 @@ def __write_docker_compose(path, docker_compose, already_existed): with salt.utils.files.fopen(file_path, "w") as fl: fl.write(salt.utils.stringutils.to_str(docker_compose)) except OSError: - return __standardize_result( - False, "Could not write {}".format(file_path), None, None - ) + return __standardize_result(False, f"Could not write {file_path}", None, None) project = __load_project_from_file_path(file_path) if isinstance(project, dict): if not already_existed: @@ -317,7 +307,7 @@ def __load_project(path): """ file_path = __get_docker_file_path(path) if file_path is None: - msg = "Could not find docker-compose file at {}".format(path) + msg = f"Could not find docker-compose file at {path}" return __standardize_result(False, msg, None, None) return __load_project_from_file_path(file_path) @@ -359,13 +349,13 @@ def __load_compose_definitions(path, definition): try: loaded_definition = json.deserialize(definition) except json.DeserializationError as jerr: - msg = "Could not parse {} {}".format(definition, jerr) + msg = f"Could not parse {definition} {jerr}" return None, None, __standardize_result(False, msg, None, None) else: try: loaded_definition = yaml.load(definition) except yaml.YAMLError as yerr: - msg = "Could not parse {} {}".format(definition, yerr) + msg = f"Could not parse {definition} {yerr}" return None, None, __standardize_result(False, msg, None, None) return compose_result, loaded_definition, None @@ -398,8 +388,8 @@ def __handle_except(inst): """ return __standardize_result( False, - "Docker-compose command {} failed".format(inspect.stack()[1][3]), - "{}".format(inst), + f"Docker-compose command {inspect.stack()[1][3]} failed", + f"{inst}", None, ) @@ -444,9 +434,7 @@ def get(path): """ file_path = __get_docker_file_path(path) if file_path is None: - return __standardize_result( - False, "Path {} is not present".format(path), None, None - ) + return __standardize_result(False, f"Path {path} is not present", None, None) salt_result = __read_docker_compose_file(file_path) if not salt_result["status"]: return salt_result @@ -878,7 +866,7 @@ def ps(path): for container in containers: command = container.human_readable_command if len(command) > 30: - command = "{} ...".format(command[:26]) + command = f"{command[:26]} ..." result[container.name] = { "id": container.id, "name": container.name, @@ -958,13 +946,13 @@ def service_create(path, service_name, definition): return err services = compose_result["compose_content"]["services"] if service_name in services: - msg = "Service {} already exists".format(service_name) + msg = f"Service {service_name} already exists" return __standardize_result(False, msg, None, None) services[service_name] = loaded_definition return __dump_compose_file( path, compose_result, - "Service {} created".format(service_name), + f"Service {service_name} created", already_existed=True, ) @@ -995,13 +983,13 @@ def service_upsert(path, service_name, definition): return err services = compose_result["compose_content"]["services"] if service_name in services: - msg = "Service {} already exists".format(service_name) + msg = f"Service {service_name} already exists" return __standardize_result(False, msg, None, None) services[service_name] = loaded_definition return __dump_compose_file( path, compose_result, - "Service definition for {} is set".format(service_name), + f"Service definition for {service_name} is set", already_existed=True, ) @@ -1029,13 +1017,13 @@ def service_remove(path, service_name): services = compose_result["compose_content"]["services"] if service_name not in services: return __standardize_result( - False, "Service {} did not exists".format(service_name), None, None + False, f"Service {service_name} did not exists", None, None ) del services[service_name] return __dump_compose_file( path, compose_result, - "Service {} is removed from {}".format(service_name, path), + f"Service {service_name} is removed from {path}", already_existed=True, ) @@ -1065,20 +1053,20 @@ def service_set_tag(path, service_name, tag): services = compose_result["compose_content"]["services"] if service_name not in services: return __standardize_result( - False, "Service {} did not exists".format(service_name), None, None + False, f"Service {service_name} did not exists", None, None ) if "image" not in services[service_name]: return __standardize_result( False, - 'Service {} did not contain the variable "image"'.format(service_name), + f'Service {service_name} did not contain the variable "image"', None, None, ) image = services[service_name]["image"].split(":")[0] - services[service_name]["image"] = "{}:{}".format(image, tag) + services[service_name]["image"] = f"{image}:{tag}" return __dump_compose_file( path, compose_result, - 'Service {} is set to tag "{}"'.format(service_name, tag), + f'Service {service_name} is set to tag "{tag}"', already_existed=True, ) diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py index eefd852c511..3a405862163 100644 --- a/salt/modules/dpkg_lowpkg.py +++ b/salt/modules/dpkg_lowpkg.py @@ -62,14 +62,14 @@ def bin_pkg_info(path, saltenv="base"): newpath = __salt__["cp.cache_file"](path, saltenv) if not newpath: raise CommandExecutionError( - "Unable to retrieve {} from saltenv '{}'".format(path, saltenv) + f"Unable to retrieve {path} from saltenv '{saltenv}'" ) path = newpath else: if not os.path.exists(path): - raise CommandExecutionError("{} does not exist on minion".format(path)) + raise CommandExecutionError(f"{path} does not exist on minion") elif not os.path.isabs(path): - raise SaltInvocationError("{} does not exist on minion".format(path)) + raise SaltInvocationError(f"{path} does not exist on minion") cmd = ["dpkg", "-I", path] result = __salt__["cmd.run_all"](cmd, output_loglevel="trace") @@ -99,7 +99,7 @@ def bin_pkg_info(path, saltenv="base"): osarch = __grains__.get("osarch", "") arch = ret["arch"] if arch != "all" and osarch == "amd64" and osarch != arch: - ret["name"] += ":{}".format(arch) + ret["name"] += f":{arch}" return ret @@ -120,7 +120,7 @@ def unpurge(*packages): ret = {} __salt__["cmd.run"]( ["dpkg", "--set-selections"], - stdin=r"\n".join(["{} install".format(x) for x in packages]), + stdin=r"\n".join([f"{x} install" for x in packages]), python_shell=False, output_loglevel="trace", ) @@ -317,7 +317,7 @@ def _get_pkg_license(pkg): :return: """ licenses = set() - cpr = "/usr/share/doc/{}/copyright".format(pkg) + cpr = f"/usr/share/doc/{pkg}/copyright" if os.path.exists(cpr): with salt.utils.files.fopen(cpr, errors="ignore") as fp_: for line in salt.utils.stringutils.to_unicode(fp_.read()).split(os.linesep): @@ -335,7 +335,7 @@ def _get_pkg_install_time(pkg): """ iso_time = None if pkg is not None: - location = "/var/lib/dpkg/info/{}.list".format(pkg) + location = f"/var/lib/dpkg/info/{pkg}.list" if os.path.exists(location): iso_time = ( datetime.datetime.utcfromtimestamp( diff --git a/salt/modules/drac.py b/salt/modules/drac.py index d752199fb7b..cb25d91f6a0 100644 --- a/salt/modules/drac.py +++ b/salt/modules/drac.py @@ -42,7 +42,7 @@ def __execute_cmd(command): """ Execute rac commands """ - cmd = __salt__["cmd.run_all"]("racadm {}".format(command)) + cmd = __salt__["cmd.run_all"](f"racadm {command}") if cmd["retcode"] != 0: log.warning("racadm return an exit code '%s'.", cmd["retcode"]) @@ -105,7 +105,7 @@ def nameservers(*ns): for i in range(1, len(ns) + 1): if not __execute_cmd( - "config -g cfgLanNetworking -o cfgDNSServer{} {}".format(i, ns[i - 1]) + f"config -g cfgLanNetworking -o cfgDNSServer{i} {ns[i - 1]}" ): return False @@ -127,7 +127,7 @@ def syslog(server, enable=True): """ if enable and __execute_cmd("config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 1"): return __execute_cmd( - "config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {}".format(server) + f"config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {server}" ) return __execute_cmd("config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 0") @@ -165,9 +165,7 @@ def list_users(): _username = "" for idx in range(1, 17): - cmd = __salt__["cmd.run_all"]( - "racadm getconfig -g cfgUserAdmin -i {}".format(idx) - ) + cmd = __salt__["cmd.run_all"](f"racadm getconfig -g cfgUserAdmin -i {idx}") if cmd["retcode"] != 0: log.warning("racadm return an exit code '%s'.", cmd["retcode"]) @@ -208,7 +206,7 @@ def delete_user(username, uid=None): if uid: return __execute_cmd( - 'config -g cfgUserAdmin -o cfgUserAdminUserName -i {} ""'.format(uid) + f'config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} ""' ) else: @@ -284,7 +282,7 @@ def create_user(username, password, permissions, users=None): # Create user accountvfirst if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} {}".format(uid, username) + f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} {username}" ): delete_user(username, uid) return False @@ -302,9 +300,7 @@ def create_user(username, password, permissions, users=None): return False # Enable users admin - if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminEnable -i {} 1".format(uid) - ): + if not __execute_cmd(f"config -g cfgUserAdmin -o cfgUserAdminEnable -i {uid} 1"): delete_user(username, uid) return False @@ -378,7 +374,7 @@ def set_snmp(community): salt dell drac.set_snmp public """ return __execute_cmd( - "config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {}".format(community) + f"config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {community}" ) @@ -393,7 +389,7 @@ def set_network(ip, netmask, gateway): salt dell drac.set_network [DRAC IP] [NETMASK] [GATEWAY] salt dell drac.set_network 192.168.0.2 255.255.255.0 192.168.0.1 """ - return __execute_cmd("setniccfg -s {} {} {}".format(ip, netmask, gateway)) + return __execute_cmd(f"setniccfg -s {ip} {netmask} {gateway}") def server_reboot(): diff --git a/salt/modules/dracr.py b/salt/modules/dracr.py index bb3192c370f..31a939a9267 100644 --- a/salt/modules/dracr.py +++ b/salt/modules/dracr.py @@ -68,12 +68,12 @@ def __execute_cmd( if module.startswith("ALL_"): modswitch = "-a " + module[module.index("_") + 1 : len(module)].lower() else: - modswitch = "-m {}".format(module) + modswitch = f"-m {module}" else: modswitch = "" if not host: # This is a local call - cmd = __salt__["cmd.run_all"]("racadm {} {}".format(command, modswitch)) + cmd = __salt__["cmd.run_all"](f"racadm {command} {modswitch}") else: cmd = __salt__["cmd.run_all"]( "racadm -r {} -u {} -p {} {} {}".format( @@ -99,12 +99,12 @@ def __execute_ret( if module == "ALL": modswitch = "-a " else: - modswitch = "-m {}".format(module) + modswitch = f"-m {module}" else: modswitch = "" if not host: # This is a local call - cmd = __salt__["cmd.run_all"]("racadm {} {}".format(command, modswitch)) + cmd = __salt__["cmd.run_all"](f"racadm {command} {modswitch}") else: cmd = __salt__["cmd.run_all"]( "racadm -r {} -u {} -p {} {} {}".format( @@ -152,7 +152,7 @@ def get_dns_dracname(host=None, admin_username=None, admin_password=None): def set_dns_dracname(name, host=None, admin_username=None, admin_password=None): ret = __execute_ret( - "set iDRAC.NIC.DNSRacName {}".format(name), + f"set iDRAC.NIC.DNSRacName {name}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -255,7 +255,7 @@ def network_info(host=None, admin_username=None, admin_password=None, module=Non if module not in inv.get("switch") and module not in inv.get("server"): cmd = {} cmd["retcode"] = -1 - cmd["stdout"] = "No module {} found.".format(module) + cmd["stdout"] = f"No module {module} found." return cmd cmd = __execute_ret( @@ -292,7 +292,7 @@ def nameservers(ns, host=None, admin_username=None, admin_password=None, module= for i in range(1, len(ns) + 1): if not __execute_cmd( - "config -g cfgLanNetworking -o cfgDNSServer{} {}".format(i, ns[i - 1]), + f"config -g cfgLanNetworking -o cfgDNSServer{i} {ns[i - 1]}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -331,7 +331,7 @@ def syslog( module=None, ): return __execute_cmd( - "config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {}".format(server), + f"config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {server}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -385,7 +385,7 @@ def list_users(host=None, admin_username=None, admin_password=None, module=None) for idx in range(1, 17): cmd = __execute_ret( - "getconfig -g cfgUserAdmin -i {}".format(idx), + f"getconfig -g cfgUserAdmin -i {idx}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -433,7 +433,7 @@ def delete_user( if uid: return __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} ".format(uid), + f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} ", host=host, admin_username=admin_username, admin_password=admin_password, @@ -521,7 +521,7 @@ def deploy_password( on that then setting the password is much quicker. """ return __execute_cmd( - "deploy -u {} -p {}".format(username, password), + f"deploy -u {username} -p {password}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -544,7 +544,7 @@ def deploy_snmp(snmp, host=None, admin_username=None, admin_password=None, modul """ return __execute_cmd( - "deploy -v SNMPv2 {} ro".format(snmp), + f"deploy -v SNMPv2 {snmp} ro", host=host, admin_username=admin_username, admin_password=admin_password, @@ -598,7 +598,7 @@ def create_user( # Create user account first if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} {}".format(uid, username), + f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} {username}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -619,9 +619,7 @@ def create_user( return False # Enable users admin - if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminEnable -i {} 1".format(uid) - ): + if not __execute_cmd(f"config -g cfgUserAdmin -o cfgUserAdminEnable -i {uid} 1"): delete_user(username, uid) return False @@ -702,7 +700,7 @@ def set_snmp(community, host=None, admin_username=None, admin_password=None): salt dell dracr.set_snmp public """ return __execute_cmd( - "config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {}".format(community), + f"config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {community}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -766,7 +764,7 @@ def server_power( """ return __execute_cmd( - "serveraction {}".format(status), + f"serveraction {status}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1088,7 +1086,7 @@ def set_slotname(slot, name, host=None, admin_username=None, admin_password=None """ return __execute_cmd( - "config -g cfgServerInfo -o cfgServerName -i {} {}".format(slot, name), + f"config -g cfgServerInfo -o cfgServerName -i {slot} {name}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1120,7 +1118,7 @@ def set_chassis_name(name, host=None, admin_username=None, admin_password=None): """ return __execute_cmd( - "setsysinfo -c chassisname {}".format(name), + f"setsysinfo -c chassisname {name}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1264,7 +1262,7 @@ def set_chassis_location(location, host=None, admin_username=None, admin_passwor """ return __execute_cmd( - "setsysinfo -c chassislocation {}".format(location), + f"setsysinfo -c chassislocation {location}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1367,7 +1365,7 @@ def set_general( cfg_sec, cfg_var, val, host=None, admin_username=None, admin_password=None ): return __execute_cmd( - "config -g {} -o {} {}".format(cfg_sec, cfg_var, val), + f"config -g {cfg_sec} -o {cfg_var} {val}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1376,7 +1374,7 @@ def set_general( def get_general(cfg_sec, cfg_var, host=None, admin_username=None, admin_password=None): ret = __execute_ret( - "getconfig -g {} -o {}".format(cfg_sec, cfg_var), + f"getconfig -g {cfg_sec} -o {cfg_var}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1457,7 +1455,7 @@ def _update_firmware(cmd, host=None, admin_username=None, admin_password=None): def bare_rac_cmd(cmd, host=None, admin_username=None, admin_password=None): ret = __execute_ret( - "{}".format(cmd), + f"{cmd}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1487,13 +1485,13 @@ def update_firmware(filename, host=None, admin_username=None, admin_password=Non """ if os.path.exists(filename): return _update_firmware( - "update -f {}".format(filename), + f"update -f {filename}", host=None, admin_username=None, admin_password=None, ) else: - raise CommandExecutionError("Unable to find firmware file {}".format(filename)) + raise CommandExecutionError(f"Unable to find firmware file {filename}") def update_firmware_nfs_or_cifs( @@ -1532,13 +1530,13 @@ def update_firmware_nfs_or_cifs( """ if os.path.exists(filename): return _update_firmware( - "update -f {} -l {}".format(filename, share), + f"update -f {filename} -l {share}", host=None, admin_username=None, admin_password=None, ) else: - raise CommandExecutionError("Unable to find firmware file {}".format(filename)) + raise CommandExecutionError(f"Unable to find firmware file {filename}") # def get_idrac_nic() diff --git a/salt/modules/ebuildpkg.py b/salt/modules/ebuildpkg.py index 1b268fa7476..31f1fc6d516 100644 --- a/salt/modules/ebuildpkg.py +++ b/salt/modules/ebuildpkg.py @@ -303,7 +303,7 @@ def _get_upgradable(backtrack=3): "--ask", "n", "--backtrack", - "{}".format(backtrack), + f"{backtrack}", "--pretend", "--update", "--newuse", @@ -549,7 +549,7 @@ def install( fromrepo=None, uses=None, binhost=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 @@ -682,9 +682,9 @@ def install( if not version_num: version_num = "" if slot is not None: - version_num += ":{}".format(slot) + version_num += f":{slot}" if fromrepo is not None: - version_num += "::{}".format(fromrepo) + version_num += f"::{fromrepo}" if uses is not None: version_num += "[{}]".format(",".join(uses)) pkg_params = {name: version_num} @@ -726,11 +726,11 @@ def install( # If no prefix characters were supplied and verstr contains a version, use '=' if len(verstr) > 0 and verstr[0] != ":" and verstr[0] != "[": prefix = prefix or "=" - target = "{}{}-{}".format(prefix, param, verstr) + target = f"{prefix}{param}-{verstr}" else: - target = "{}{}".format(param, verstr) + target = f"{param}{verstr}" else: - target = "{}".format(param) + target = f"{param}" if "[" in target: old = __salt__["portage_config.get_flags_from_package_conf"]( @@ -844,10 +844,10 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None, **kwargs) full_atom = pkg if slot is not None: - full_atom = "{}:{}".format(full_atom, slot) + full_atom = f"{full_atom}:{slot}" if fromrepo is not None: - full_atom = "{}::{}".format(full_atom, fromrepo) + full_atom = f"{full_atom}::{fromrepo}" if binhost == "try": bin_opts = ["-g"] @@ -952,7 +952,7 @@ def upgrade(refresh=True, binhost=None, backtrack=3, **kwargs): "n", "--quiet", "--backtrack", - "{}".format(backtrack), + f"{backtrack}", "--update", "--newuse", "--deep", @@ -1036,9 +1036,9 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs): ): fullatom = name if slot is not None: - targets = ["{}:{}".format(fullatom, slot)] + targets = [f"{fullatom}:{slot}"] if fromrepo is not None: - targets = ["{}::{}".format(fullatom, fromrepo)] + targets = [f"{fullatom}::{fromrepo}"] targets = [fullatom] else: targets = [x for x in pkg_params if x in old] @@ -1167,9 +1167,9 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None): ): fullatom = name if slot is not None: - targets = ["{}:{}".format(fullatom, slot)] + targets = [f"{fullatom}:{slot}"] if fromrepo is not None: - targets = ["{}::{}".format(fullatom, fromrepo)] + targets = [f"{fullatom}::{fromrepo}"] targets = [fullatom] else: targets = [x for x in pkg_params if x in old] @@ -1247,9 +1247,9 @@ def check_extra_requirements(pkgname, pkgver): # If no prefix characters were supplied and verstr contains a version, use '=' if verstr[0] != ":" and verstr[0] != "[": prefix = prefix or "=" - atom = "{}{}-{}".format(prefix, pkgname, verstr) + atom = f"{prefix}{pkgname}-{verstr}" else: - atom = "{}{}".format(pkgname, verstr) + atom = f"{pkgname}{verstr}" else: return True diff --git a/salt/modules/eselect.py b/salt/modules/eselect.py index 86c4d246a46..33a1e96709b 100644 --- a/salt/modules/eselect.py +++ b/salt/modules/eselect.py @@ -194,7 +194,7 @@ def set_target(module, target, module_parameter=None, action_parameter=None): salt '*' eselect.set_target kernel linux-3.17.5-gentoo """ if action_parameter: - action_parameter = "{} {}".format(action_parameter, target) + action_parameter = f"{action_parameter} {target}" else: action_parameter = target diff --git a/salt/modules/ethtool.py b/salt/modules/ethtool.py index 16f9c4a7b53..0fb0a16b98a 100644 --- a/salt/modules/ethtool.py +++ b/salt/modules/ethtool.py @@ -312,8 +312,8 @@ def _ethtool_command(devname, *args, **kwargs): if not ethtool: raise CommandExecutionError("Command 'ethtool' cannot be found") switches = " ".join(arg for arg in args) - params = " ".join("{} {}".format(key, val) for key, val in kwargs.items()) - cmd = "{} {} {} {}".format(ethtool, switches, devname, params).strip() + params = " ".join(f"{key} {val}" for key, val in kwargs.items()) + cmd = f"{ethtool} {switches} {devname} {params}".strip() ret = __salt__["cmd.run"](cmd, ignore_retcode=True).splitlines() if ret and ret[0].startswith("Cannot"): raise CommandExecutionError(ret[0]) @@ -336,7 +336,7 @@ def _validate_params(valid_params, kwargs): validated[key] = val if not validated: raise CommandExecutionError( - "None of the valid parameters were provided: {}".format(valid_params) + f"None of the valid parameters were provided: {valid_params}" ) return validated diff --git a/salt/modules/extfs.py b/salt/modules/extfs.py index 370e3066b46..5ceb16f3963 100644 --- a/salt/modules/extfs.py +++ b/salt/modules/extfs.py @@ -96,10 +96,10 @@ def mkfs(device, fs_type, **kwargs): if key in kwarg_map: opt = kwarg_map[key] if kwargs[key] == "True": - opts += "-{} ".format(opt) + opts += f"-{opt} " else: - opts += "-{} {} ".format(opt, kwargs[key]) - cmd = "mke2fs -F -t {} {}{}".format(fs_type, opts, device) + opts += f"-{opt} {kwargs[key]} " + cmd = f"mke2fs -F -t {fs_type} {opts}{device}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() ret = [] for line in out: @@ -183,10 +183,10 @@ def tune(device, **kwargs): if key in kwarg_map: opt = kwarg_map[key] if kwargs[key] == "True": - opts += "-{} ".format(opt) + opts += f"-{opt} " else: - opts += "-{} {} ".format(opt, kwargs[key]) - cmd = "tune2fs {}{}".format(opts, device) + opts += f"-{opt} {kwargs[key]} " + cmd = f"tune2fs {opts}{device}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() return out @@ -229,7 +229,7 @@ def dump(device, args=None): salt '*' extfs.dump /dev/sda1 """ - cmd = "dumpe2fs {}".format(device) + cmd = f"dumpe2fs {device}" if args: cmd = cmd + " -" + args ret = {"attributes": {}, "blocks": {}} @@ -264,7 +264,7 @@ def dump(device, args=None): line = line.replace("]", "") comps = line.split() blkgrp = comps[1] - group = "Group {}".format(blkgrp) + group = f"Group {blkgrp}" ret["blocks"][group] = {} ret["blocks"][group]["group"] = blkgrp ret["blocks"][group]["range"] = comps[3] diff --git a/salt/modules/file.py b/salt/modules/file.py index 68576d04391..09364804fe6 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -435,7 +435,7 @@ def set_mode(path, mode): if not mode: mode = "0" if not os.path.exists(path): - raise CommandExecutionError("{}: File not found".format(path)) + raise CommandExecutionError(f"{path}: File not found") try: os.chmod(path, int(mode, 8)) except Exception: # pylint: disable=broad-except @@ -678,14 +678,14 @@ def chattr(*files, **kwargs): cmd = ["chattr"] if operator == "add": - attrs = "+{}".format(attributes) + attrs = f"+{attributes}" elif operator == "remove": - attrs = "-{}".format(attributes) + attrs = f"-{attributes}" cmd.append(attrs) if flags is not None: - cmd.append("-{}".format(flags)) + cmd.append(f"-{flags}") if version is not None: cmd.extend(["-v", version]) @@ -828,12 +828,7 @@ def get_source_sum( "following are supported hash types and lengths: {}.".format( source_hash, ", ".join(salt.utils.files.VALID_PROTOS), - ", ".join( - [ - "{} ({})".format(HASHES_REVMAP[x], x) - for x in sorted(HASHES_REVMAP) - ] - ), + ", ".join([f"{HASHES_REVMAP[x]} ({x})" for x in sorted(HASHES_REVMAP)]), ) ) @@ -849,7 +844,7 @@ def get_source_sum( ) if not hash_fn: raise CommandExecutionError( - "Source hash file {} not found".format(source_hash) + f"Source hash file {source_hash} not found" ) else: if proto != "": @@ -879,7 +874,7 @@ def get_source_sum( _invalid_source_hash_format() except ValueError: # No hash type, try to figure out by hash length - if not re.match("^[{}]+$".format(string.hexdigits), source_hash): + if not re.match(f"^[{string.hexdigits}]+$", source_hash): _invalid_source_hash_format() ret["hsum"] = source_hash source_hash_len = len(source_hash) @@ -964,10 +959,7 @@ def check_hash(path, file_hash): file_hash, hash_len, ", ".join( - [ - "{} ({})".format(HASHES_REVMAP[x], x) - for x in sorted(HASHES_REVMAP) - ] + [f"{HASHES_REVMAP[x]} ({x})" for x in sorted(HASHES_REVMAP)] ), ) ) @@ -1097,7 +1089,7 @@ def find(path, *args, **kwargs): try: finder = salt.utils.find.Finder(kwargs) except ValueError as ex: - return "error: {}".format(ex) + return f"error: {ex}" ret = [ item @@ -1192,11 +1184,11 @@ def sed( options = options.replace("-r", "-E") cmd = ["sed"] - cmd.append("-i{}".format(backup) if backup else "-i") + cmd.append(f"-i{backup}" if backup else "-i") cmd.extend(salt.utils.args.shlex_split(options)) cmd.append( r"{limit}{negate_match}s/{before}/{after}/{flags}".format( - limit="/{}/ ".format(limit) if limit else "", + limit=f"/{limit}/ " if limit else "", negate_match="!" if negate_match else "", before=before, after=after, @@ -1240,9 +1232,9 @@ def sed_contains(path, text, limit="", flags="g"): cmd.extend(salt.utils.args.shlex_split(options)) cmd.append( r"{limit}s/{before}/$/{flags}".format( - limit="/{}/ ".format(limit) if limit else "", + limit=f"/{limit}/ " if limit else "", before=before, - flags="p{}".format(flags), + flags=f"p{flags}", ) ) cmd.append(path) @@ -1323,10 +1315,10 @@ def psed( # The pattern to replace with does not need to be escaped limit = _sed_esc(limit, escape_all) - shutil.copy2(path, "{}{}".format(path, backup)) + shutil.copy2(path, f"{path}{backup}") with salt.utils.files.fopen(path, "w") as ofile: - with salt.utils.files.fopen("{}{}".format(path, backup), "r") as ifile: + with salt.utils.files.fopen(f"{path}{backup}", "r") as ifile: if multi is True: for line in ifile.readline(): ofile.write( @@ -1509,12 +1501,12 @@ def comment_line(path, regex, char="#", cmnt=True, backup=".bak"): # Make sure the file exists if not os.path.isfile(path): - raise SaltInvocationError("File not found: {}".format(path)) + raise SaltInvocationError(f"File not found: {path}") # Make sure it is a text file if not __utils__["files.is_text"](path): raise SaltInvocationError( - "Cannot perform string replacements on a binary file: {}".format(path) + f"Cannot perform string replacements on a binary file: {path}" ) # First check the whole file, determine whether to make the replacement @@ -1536,14 +1528,12 @@ def comment_line(path, regex, char="#", cmnt=True, backup=".bak"): # Load lines into dictionaries, set found to True orig_file.append(line) if cmnt: - new_file.append("{}{}".format(char, line)) + new_file.append(f"{char}{line}") else: new_file.append(line.lstrip(char)) found = True except OSError as exc: - raise CommandExecutionError( - "Unable to open file '{}'. Exception: {}".format(path, exc) - ) + raise CommandExecutionError(f"Unable to open file '{path}'. Exception: {exc}") # We've searched the whole file. If we didn't find anything, return False if not found: @@ -1558,7 +1548,7 @@ def comment_line(path, regex, char="#", cmnt=True, backup=".bak"): try: temp_file = _mkstemp_copy(path=path, preserve_inode=False) except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") try: # Open the file in write mode @@ -1577,7 +1567,7 @@ def comment_line(path, regex, char="#", cmnt=True, backup=".bak"): if re.match(regex, line): # Write the new line if cmnt: - wline = "{}{}".format(char, line) + wline = f"{char}{line}" else: wline = line.lstrip(char) else: @@ -1593,13 +1583,13 @@ def comment_line(path, regex, char="#", cmnt=True, backup=".bak"): "Exception: {}".format(path, temp_file, exc) ) except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") if backup: # Move the backup file to the original directory - backup_name = "{}{}".format(path, backup) + backup_name = f"{path}{backup}" try: shutil.move(temp_file, backup_name) except OSError as exc: @@ -1686,9 +1676,7 @@ def _mkstemp_copy(path, preserve_inode=True): try: temp_file = salt.utils.files.mkstemp(prefix=salt.utils.files.TEMPFILE_PREFIX) except OSError as exc: - raise CommandExecutionError( - "Unable to create temp file. Exception: {}".format(exc) - ) + raise CommandExecutionError(f"Unable to create temp file. Exception: {exc}") # use `copy` to preserve the inode of the # original file, and thus preserve hardlinks # to the inode. otherwise, use `move` to @@ -1727,7 +1715,7 @@ def _regex_to_static(src, regex): compiled = re.compile(regex, re.DOTALL) src = [line for line in src if compiled.search(line) or line.count(regex)] except Exception as ex: # pylint: disable=broad-except - raise CommandExecutionError("{}: '{}'".format(_get_error_message(ex), regex)) + raise CommandExecutionError(f"{_get_error_message(ex)}: '{regex}'") return src @@ -1748,7 +1736,7 @@ def _assert_occurrence(probe, target, amount=1): if msg: raise CommandExecutionError( - 'Found {} expected occurrences in "{}" expression'.format(msg, target) + f'Found {msg} expected occurrences in "{target}" expression' ) return occ @@ -1859,7 +1847,7 @@ def _set_line( "Mode was not defined. How to process the file?" ) else: - raise CommandExecutionError("Unknown mode: {}".format(mode)) + raise CommandExecutionError(f"Unknown mode: {mode}") if mode != "delete" and content is None: raise CommandExecutionError("Content can only be empty if mode is delete") @@ -2235,7 +2223,7 @@ def line( if not os.path.isfile(path): if not quiet: raise CommandExecutionError( - 'File "{}" does not exists or is not a file.'.format(path) + f'File "{path}" does not exists or is not a file.' ) return False # No changes had happened @@ -2246,7 +2234,7 @@ def line( "Mode was not defined. How to process the file?" ) else: - raise CommandExecutionError('Unknown mode: "{}"'.format(mode)) + raise CommandExecutionError(f'Unknown mode: "{mode}"') # We've set the content to be empty in the function params but we want to make sure # it gets passed when needed. Feature #37092 @@ -2494,11 +2482,11 @@ def replace( if ignore_if_missing: return False else: - raise SaltInvocationError("File not found: {}".format(path)) + raise SaltInvocationError(f"File not found: {path}") if not __utils__["files.is_text"](path): raise SaltInvocationError( - "Cannot perform string replacements on a binary file: {}".format(path) + f"Cannot perform string replacements on a binary file: {path}" ) if search_only and (append_if_not_found or prepend_if_not_found): @@ -2577,7 +2565,7 @@ def replace( # content if it was pre/appended in a previous run. if re.search( salt.utils.stringutils.to_bytes( - "^{}($|(?=\r\n))".format(re.escape(content)) + f"^{re.escape(content)}($|(?=\r\n))" ), r_data, flags=re_flags, @@ -2595,9 +2583,7 @@ def replace( has_changes = False except OSError as exc: - raise CommandExecutionError( - "Unable to open file '{}'. Exception: {}".format(path, exc) - ) + raise CommandExecutionError(f"Unable to open file '{path}'. Exception: {exc}") finally: if r_data and isinstance(r_data, mmap.mmap): r_data.close() @@ -2608,7 +2594,7 @@ def replace( # Create a copy to read from and to use as a backup later temp_file = _mkstemp_copy(path=path, preserve_inode=preserve_inode) except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") r_data = None try: @@ -2636,12 +2622,12 @@ def replace( "Exception: {}".format(path, temp_file, exc) ) except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") finally: if r_data and isinstance(r_data, mmap.mmap): r_data.close() except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") if not found and (append_if_not_found or prepend_if_not_found): if not_found_content is None: @@ -2667,7 +2653,7 @@ def replace( # Create a copy to read from and for later use as a backup temp_file = _mkstemp_copy(path=path, preserve_inode=preserve_inode) except OSError as exc: - raise CommandExecutionError("Exception: {}".format(exc)) + raise CommandExecutionError(f"Exception: {exc}") # write new content in the file while avoiding partial reads try: fh_ = salt.utils.atomicfile.atomic_open(path, "wb") @@ -2679,7 +2665,7 @@ def replace( if backup and has_changes and not dry_run: # keep the backup only if it was requested # and only if there were any changes - backup_name = "{}{}".format(path, backup) + backup_name = f"{path}{backup}" try: shutil.move(temp_file, backup_name) except OSError as exc: @@ -2689,8 +2675,8 @@ def replace( "Exception: {}".format(path, temp_file, exc) ) if symlink: - symlink_backup = "{}{}".format(given_path, backup) - target_backup = "{}{}".format(target_path, backup) + symlink_backup = f"{given_path}{backup}" + target_backup = f"{target_path}{backup}" # Always clobber any existing symlink backup # to match the behaviour of the 'backup' option try: @@ -2709,7 +2695,7 @@ def replace( os.remove(temp_file) except OSError as exc: raise CommandExecutionError( - "Unable to delete temp file '{}'. Exception: {}".format(temp_file, exc) + f"Unable to delete temp file '{temp_file}'. Exception: {exc}" ) if not dry_run and not salt.utils.platform.is_windows(): @@ -2848,7 +2834,7 @@ def blockreplace( path = os.path.expanduser(path) if not os.path.exists(path): - raise SaltInvocationError("File not found: {}".format(path)) + raise SaltInvocationError(f"File not found: {path}") try: file_encoding = __utils__["files.get_encoding"](path) @@ -2858,7 +2844,7 @@ def blockreplace( if __utils__["files.is_binary"](path): if not file_encoding: raise SaltInvocationError( - "Cannot perform string replacements on a binary file: {}".format(path) + f"Cannot perform string replacements on a binary file: {path}" ) if insert_before_match or insert_after_match: @@ -2970,7 +2956,7 @@ def blockreplace( new_file.append(line) except OSError as exc: - raise CommandExecutionError("Failed to read from {}: {}".format(path, exc)) + raise CommandExecutionError(f"Failed to read from {path}: {exc}") finally: if linesep is None: # If the file was empty, we will not have set linesep yet. Assume @@ -3035,7 +3021,7 @@ def blockreplace( # backup old content if backup is not False: - backup_path = "{}{}".format(path, backup) + backup_path = f"{path}{backup}" shutil.copy2(path, backup_path) # copy2 does not preserve ownership if salt.utils.platform.is_windows(): @@ -3070,7 +3056,7 @@ def blockreplace( # backup old content if backup is not False: - backup_path = "{}{}".format(path, backup) + backup_path = f"{path}{backup}" shutil.copy2(path, backup_path) # copy2 does not preserve ownership if salt.utils.platform.is_windows(): @@ -3403,11 +3389,9 @@ def append(path, *args, **kwargs): # Append lines in text mode with salt.utils.files.fopen(path, "a") as ofile: for new_line in args: - ofile.write( - salt.utils.stringutils.to_str("{}{}".format(new_line, os.linesep)) - ) + ofile.write(salt.utils.stringutils.to_str(f"{new_line}{os.linesep}")) - return 'Wrote {} lines to "{}"'.format(len(args), path) + return f'Wrote {len(args)} lines to "{path}"' def prepend(path, *args, **kwargs): @@ -3461,12 +3445,12 @@ def prepend(path, *args, **kwargs): preface = [] for line in args: - preface.append("{}\n".format(line)) + preface.append(f"{line}\n") with salt.utils.files.fopen(path, "w") as ofile: contents = preface + contents ofile.write(salt.utils.stringutils.to_str("".join(contents))) - return 'Prepended {} lines to "{}"'.format(len(args), path) + return f'Prepended {len(args)} lines to "{path}"' def write(path, *args, **kwargs): @@ -3511,10 +3495,10 @@ def write(path, *args, **kwargs): contents = [] for line in args: - contents.append("{}\n".format(line)) + contents.append(f"{line}\n") with salt.utils.files.fopen(path, "w") as ofile: ofile.write(salt.utils.stringutils.to_str("".join(contents))) - return 'Wrote {} lines to "{}"'.format(len(contents), path) + return f'Wrote {len(contents)} lines to "{path}"' def touch(name, atime=None, mtime=None): @@ -3675,7 +3659,7 @@ def link(src, path): os.link(src, path) return True except OSError as E: - raise CommandExecutionError("Could not create '{}': {}".format(path, E)) + raise CommandExecutionError(f"Could not create '{path}': {E}") return False @@ -3745,7 +3729,7 @@ def symlink(src, path, force=False, atomic=False): path = os.path.expanduser(path) if not os.path.isabs(path): - raise SaltInvocationError("Link path must be absolute: {}".format(path)) + raise SaltInvocationError(f"Link path must be absolute: {path}") if os.path.islink(path): try: @@ -3758,11 +3742,11 @@ def symlink(src, path, force=False, atomic=False): pass if not force and not atomic: - msg = "Found existing symlink: {}".format(path) + msg = f"Found existing symlink: {path}" raise CommandExecutionError(msg) if os.path.exists(path) and not force and not atomic: - msg = "Existing path is not a symlink: {}".format(path) + msg = f"Existing path is not a symlink: {path}" raise CommandExecutionError(msg) if (os.path.islink(path) or os.path.exists(path)) and force and not atomic: @@ -3782,13 +3766,13 @@ def symlink(src, path, force=False, atomic=False): return True except OSError: os.remove(temp_link) - raise CommandExecutionError("Could not create '{}'".format(path)) + raise CommandExecutionError(f"Could not create '{path}'") try: os.symlink(src, path) return True except OSError: - raise CommandExecutionError("Could not create '{}'".format(path)) + raise CommandExecutionError(f"Could not create '{path}'") def rename(src, dst): @@ -3811,7 +3795,7 @@ def rename(src, dst): os.rename(src, dst) return True except OSError: - raise CommandExecutionError("Could not rename '{}' to '{}'".format(src, dst)) + raise CommandExecutionError(f"Could not rename '{src}' to '{dst}'") return False @@ -3849,7 +3833,7 @@ def copy(src, dst, recurse=False, remove_existing=False): raise SaltInvocationError("File path must be absolute.") if not os.path.exists(src): - raise CommandExecutionError("No such file or directory '{}'".format(src)) + raise CommandExecutionError(f"No such file or directory '{src}'") if not salt.utils.platform.is_windows(): pre_user = get_user(src) @@ -3872,7 +3856,7 @@ def copy(src, dst, recurse=False, remove_existing=False): else: shutil.copyfile(src, dst) except OSError: - raise CommandExecutionError("Could not copy '{}' to '{}'".format(src, dst)) + raise CommandExecutionError(f"Could not copy '{src}' to '{dst}'") if not salt.utils.platform.is_windows(): check_perms(dst, None, pre_user, pre_group, pre_mode) @@ -4014,10 +3998,10 @@ def readlink(path, canonicalize=False): path = os.path.expandvars(path) if not os.path.isabs(path): - raise SaltInvocationError("Path to link must be absolute: {}".format(path)) + raise SaltInvocationError(f"Path to link must be absolute: {path}") if not os.path.islink(path): - raise SaltInvocationError("A valid link was not specified: {}".format(path)) + raise SaltInvocationError(f"A valid link was not specified: {path}") if canonicalize: return os.path.realpath(path) @@ -4026,7 +4010,7 @@ def readlink(path, canonicalize=False): return salt.utils.path.readlink(path) except OSError as exc: if exc.errno == errno.EINVAL: - raise CommandExecutionError("Not a symbolic link: {}".format(path)) + raise CommandExecutionError(f"Not a symbolic link: {path}") raise CommandExecutionError(str(exc)) @@ -4090,7 +4074,7 @@ def statvfs(path): ) } except OSError: - raise CommandExecutionError("Could not statvfs '{}'".format(path)) + raise CommandExecutionError(f"Could not statvfs '{path}'") return False @@ -4118,7 +4102,7 @@ def stats(path, hash_type=None, follow_symlinks=True): # message in this exception. Any changes made to the message for this # exception will reflect the file.directory state as well, and will # likely require changes there. - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") else: if follow_symlinks: pstat = os.stat(path) @@ -4260,7 +4244,7 @@ def remove(path, **kwargs): path = os.path.expanduser(path) if not os.path.isabs(path): - raise SaltInvocationError("File path must be absolute: {}".format(path)) + raise SaltInvocationError(f"File path must be absolute: {path}") try: if os.path.islink(path) or (os.path.exists(path) and not os.path.isdir(path)): @@ -4270,7 +4254,7 @@ def remove(path, **kwargs): shutil.rmtree(path) return True except OSError as exc: - raise CommandExecutionError("Could not remove '{}': {}".format(path, exc)) + raise CommandExecutionError(f"Could not remove '{path}': {exc}") return False @@ -4352,7 +4336,7 @@ def get_selinux_context(path): if cmd_ret["retcode"] == 0: ret = cmd_ret["stdout"] else: - ret = "No selinux context information is available for {}".format(path) + ret = f"No selinux context information is available for {path}" return ret @@ -4388,9 +4372,7 @@ def set_selinux_context( ) if fcontext_result.get("retcode", None) != 0: # Problem setting fcontext policy - raise CommandExecutionError( - "Problem setting fcontext: {}".format(fcontext_result) - ) + raise CommandExecutionError(f"Problem setting fcontext: {fcontext_result}") cmd = ["chcon"] if user: @@ -4420,7 +4402,7 @@ def source_list(source, source_hash, saltenv): salt '*' file.source_list salt://http/httpd.conf '{hash_type: 'md5', 'hsum': }' base """ - contextkey = "{}_|-{}_|-{}".format(source, source_hash, saltenv) + contextkey = f"{source}_|-{source_hash}_|-{saltenv}" if contextkey in __context__: return __context__[contextkey] @@ -4700,12 +4682,12 @@ def get_managed( if parsed_scheme == "": parsed_path = sfn = source if not os.path.exists(sfn): - msg = "Local file source {} does not exist".format(sfn) + msg = f"Local file source {sfn} does not exist" return "", {}, msg elif parsed_scheme == "file": sfn = parsed_path if not os.path.exists(sfn): - msg = "Local file source {} does not exist".format(sfn) + msg = f"Local file source {sfn} does not exist" return "", {}, msg if parsed_scheme and parsed_scheme.lower() in string.ascii_lowercase: @@ -4718,7 +4700,7 @@ def get_managed( return ( "", {}, - "Source file {} not found in saltenv '{}'".format(source, saltenv), + f"Source file {source} not found in saltenv '{saltenv}'", ) elif not source_hash and unix_local_source: source_sum = _get_local_file_source_sum(parsed_path) @@ -4782,13 +4764,13 @@ def get_managed( # A 404 or other error code may raise an exception, catch it # and return a comment that will fail the calling state. _source = salt.utils.url.redact_http_basic_auth(source) - return "", {}, "Failed to cache {}: {}".format(_source, exc) + return "", {}, f"Failed to cache {_source}: {exc}" # If cache failed, sfn will be False, so do a truth check on sfn first # as invoking os.path.exists() on a bool raises a TypeError. if not sfn or not os.path.exists(sfn): _source = salt.utils.url.redact_http_basic_auth(source) - return sfn, {}, "Source file '{}' not found".format(_source) + return sfn, {}, f"Source file '{_source}' not found" if sfn == name: raise SaltInvocationError("Source file cannot be the same as destination") @@ -4817,7 +4799,7 @@ def get_managed( return ( sfn, {}, - "Specified template format {} is not supported".format(template), + f"Specified template format {template} is not supported", ) if data["result"]: @@ -4890,7 +4872,7 @@ def extract_hash( hash_type, ) hash_type = "" - hash_len_expr = "{},{}".format(min(HASHES_REVMAP), max(HASHES_REVMAP)) + hash_len_expr = f"{min(HASHES_REVMAP)},{max(HASHES_REVMAP)}" else: hash_len_expr = str(hash_len) @@ -5197,7 +5179,7 @@ def check_perms( ret["changes"]["user"] = user else: ret["result"] = False - ret["comment"].append("Failed to change user to {}".format(user)) + ret["comment"].append(f"Failed to change user to {user}") elif "cuser" in perms: ret["changes"]["user"] = user @@ -5213,7 +5195,7 @@ def check_perms( ret["changes"]["group"] = group else: ret["result"] = False - ret["comment"].append("Failed to change group to {}".format(group)) + ret["comment"].append(f"Failed to change group to {group}") elif "cgroup" in perms: ret["changes"]["group"] = group @@ -5226,7 +5208,7 @@ def check_perms( ret["changes"]["mode"] = mode else: ret["result"] = False - ret["comment"].append("Failed to change mode to {}".format(mode)) + ret["comment"].append(f"Failed to change mode to {mode}") elif "cmode" in perms: ret["changes"]["mode"] = mode @@ -5259,9 +5241,7 @@ def check_perms( cmp_attrs = _cmp_attrs(name, attrs) if any(attr for attr in cmp_attrs): ret["result"] = False - ret["comment"].append( - "Failed to change attributes to {}".format(attrs) - ) + ret["comment"].append(f"Failed to change attributes to {attrs}") changes["new"] = "".join(lsattr(name)[name]) else: changes["new"] = attrs @@ -5316,17 +5296,17 @@ def check_perms( selinux_change_new = "" selinux_change_orig = "" if requested_seuser: - selinux_change_new += "User: {} ".format(requested_seuser) - selinux_change_orig += "User: {} ".format(current_seuser) + selinux_change_new += f"User: {requested_seuser} " + selinux_change_orig += f"User: {current_seuser} " if requested_serole: - selinux_change_new += "Role: {} ".format(requested_serole) - selinux_change_orig += "Role: {} ".format(current_serole) + selinux_change_new += f"Role: {requested_serole} " + selinux_change_orig += f"Role: {current_serole} " if requested_setype: - selinux_change_new += "Type: {} ".format(requested_setype) - selinux_change_orig += "Type: {} ".format(current_setype) + selinux_change_new += f"Type: {requested_setype} " + selinux_change_orig += f"Type: {current_setype} " if requested_serange: - selinux_change_new += "Range: {} ".format(requested_serange) - selinux_change_orig += "Range: {} ".format(current_serange) + selinux_change_new += f"Range: {requested_serange} " + selinux_change_orig += f"Range: {current_serange} " if __opts__["test"]: ret["comment"] = "File {} selinux context to be updated".format( @@ -5366,9 +5346,7 @@ def check_perms( selinux_error = True if not selinux_error: - ret["comment"].append( - "The file {} is set to be changed".format(name) - ) + ret["comment"].append(f"The file {name} is set to be changed") if requested_seuser: if current_seuser != requested_seuser: @@ -5500,9 +5478,9 @@ def check_managed( if changes: log.info(changes) comments = ["The following values are set to be changed:\n"] - comments.extend("{}: {}\n".format(key, val) for key, val in changes.items()) + comments.extend(f"{key}: {val}\n" for key, val in changes.items()) return None, "".join(comments) - return True, "The file {} is in the correct state".format(name) + return True, f"The file {name} is in the correct state" def check_managed_changes( @@ -6150,7 +6128,7 @@ def manage_file( # File is not present, cache it sfn = __salt__["cp.cache_file"](source, saltenv, verify_ssl=verify_ssl) if not sfn: - return _error(ret, "Source file '{}' not found".format(source)) + return _error(ret, f"Source file '{source}' not found") htype = source_sum.get("hash_type", __opts__["hash_type"]) # Recalculate source sum now that file has been cached source_sum = {"hash_type": htype, "hsum": get_hash(sfn, form=htype)} @@ -6187,7 +6165,7 @@ def manage_file( source, saltenv, verify_ssl=verify_ssl, use_etag=use_etag ) if not sfn: - return _error(ret, "Source file '{}' not found".format(source)) + return _error(ret, f"Source file '{source}' not found") # If the downloaded file came from a non salt server or local # source, and we are not skipping checksum verification, then # verify that it matches the specified checksum. @@ -6229,7 +6207,7 @@ def manage_file( ) except OSError as io_error: __clean_tmp(sfn) - return _error(ret, "Failed to commit change: {}".format(io_error)) + return _error(ret, f"Failed to commit change: {io_error}") if contents is not None: # Write the static contents to a temporary file @@ -6260,7 +6238,7 @@ def manage_file( except CommandExecutionError as exc: ret.setdefault("warnings", []).append( - "Failed to detect changes to file: {}".format(exc.strerror) + f"Failed to detect changes to file: {exc.strerror}" ) differences = "" @@ -6277,7 +6255,7 @@ def manage_file( ) except OSError as io_error: __clean_tmp(tmp) - return _error(ret, "Failed to commit change: {}".format(io_error)) + return _error(ret, f"Failed to commit change: {io_error}") __clean_tmp(tmp) # Check for changing symlink to regular file here @@ -6285,7 +6263,7 @@ def manage_file( if not sfn: sfn = __salt__["cp.cache_file"](source, saltenv, verify_ssl=verify_ssl) if not sfn: - return _error(ret, "Source file '{}' not found".format(source)) + return _error(ret, f"Source file '{source}' not found") # If the downloaded file came from a non salt server source verify # that it matches the intended sum value if check_web_source_hash: @@ -6309,7 +6287,7 @@ def manage_file( ) except OSError as io_error: __clean_tmp(sfn) - return _error(ret, "Failed to commit change: {}".format(io_error)) + return _error(ret, f"Failed to commit change: {io_error}") ret["changes"]["diff"] = "Replace symbolic link with regular file" @@ -6343,7 +6321,7 @@ def manage_file( ) if ret["changes"]: - ret["comment"] = "File {} updated".format(salt.utils.data.decode(name)) + ret["comment"] = f"File {salt.utils.data.decode(name)} updated" elif not ret["changes"] and ret["result"]: ret["comment"] = "File {} is in the correct state".format( @@ -6361,7 +6339,7 @@ def manage_file( drive, _ = os.path.splitdrive(name) if drive and not os.path.exists(drive): __clean_tmp(sfn) - return _error(ret, "{} drive not present".format(drive)) + return _error(ret, f"{drive} drive not present") if dir_mode is None and mode is not None: # Add execute bit to each nonzero digit in the mode, if # dir_mode was not specified. Otherwise, any @@ -6394,7 +6372,7 @@ def manage_file( if not sfn: sfn = __salt__["cp.cache_file"](source, saltenv, verify_ssl=verify_ssl) if not sfn: - return _error(ret, "Source file '{}' not found".format(source)) + return _error(ret, f"Source file '{source}' not found") # If the downloaded file came from a non salt server source verify # that it matches the intended sum value if check_web_source_hash: @@ -6435,16 +6413,16 @@ def manage_file( if contents is None: if not __opts__["test"]: if touch(name): - ret["changes"]["new"] = "file {} created".format(name) + ret["changes"]["new"] = f"file {name} created" ret["comment"] = "Empty file" else: - return _error(ret, "Empty file {} not created".format(name)) + return _error(ret, f"Empty file {name} not created") else: if not __opts__["test"]: if touch(name): ret["changes"]["diff"] = "New file" else: - return _error(ret, "File {} not created".format(name)) + return _error(ret, f"File {name} not created") if contents is not None: # Write the static contents to a temporary file @@ -6577,12 +6555,12 @@ def makedirs_(path, user=None, group=None, mode=None): if os.path.isdir(dirname): # There's nothing for us to do - msg = "Directory '{}' already exists".format(dirname) + msg = f"Directory '{dirname}' already exists" log.debug(msg) return msg if os.path.exists(dirname): - msg = "The path '{}' already exists and is not a directory".format(dirname) + msg = f"The path '{dirname}' already exists and is not a directory" log.debug(msg) return msg @@ -6636,7 +6614,7 @@ def makedirs_perms(name, user=None, group=None, mode="0755"): if tail == os.curdir: # xxx/newdir/. exists if xxx/newdir exists return os.mkdir(name) - check_perms(name, None, user, group, int("{}".format(mode)) if mode else None) + check_perms(name, None, user, group, int(f"{mode}") if mode else None) def get_devmm(name): @@ -6706,7 +6684,7 @@ def mknod_chrdev(name, major, minor, user=None, group=None, mode="0660"): ) try: if __opts__["test"]: - ret["changes"] = {"new": "Character device {} created.".format(name)} + ret["changes"] = {"new": f"Character device {name} created."} ret["result"] = None else: if ( @@ -6717,7 +6695,7 @@ def mknod_chrdev(name, major, minor, user=None, group=None, mode="0660"): ) is None ): - ret["changes"] = {"new": "Character device {} created.".format(name)} + ret["changes"] = {"new": f"Character device {name} created."} ret["result"] = True except OSError as exc: # be happy it is already there....however, if you are trying to change the @@ -6725,9 +6703,9 @@ def mknod_chrdev(name, major, minor, user=None, group=None, mode="0660"): if exc.errno != errno.EEXIST: raise else: - ret["comment"] = "File {} exists and cannot be overwritten".format(name) + ret["comment"] = f"File {name} exists and cannot be overwritten" # quick pass at verifying the permissions of the newly created character device - check_perms(name, None, user, group, int("{}".format(mode)) if mode else None) + check_perms(name, None, user, group, int(f"{mode}") if mode else None) return ret @@ -6779,7 +6757,7 @@ def mknod_blkdev(name, major, minor, user=None, group=None, mode="0660"): ) try: if __opts__["test"]: - ret["changes"] = {"new": "Block device {} created.".format(name)} + ret["changes"] = {"new": f"Block device {name} created."} ret["result"] = None else: if ( @@ -6790,7 +6768,7 @@ def mknod_blkdev(name, major, minor, user=None, group=None, mode="0660"): ) is None ): - ret["changes"] = {"new": "Block device {} created.".format(name)} + ret["changes"] = {"new": f"Block device {name} created."} ret["result"] = True except OSError as exc: # be happy it is already there....however, if you are trying to change the @@ -6798,9 +6776,9 @@ def mknod_blkdev(name, major, minor, user=None, group=None, mode="0660"): if exc.errno != errno.EEXIST: raise else: - ret["comment"] = "File {} exists and cannot be overwritten".format(name) + ret["comment"] = f"File {name} exists and cannot be overwritten" # quick pass at verifying the permissions of the newly created block device - check_perms(name, None, user, group, int("{}".format(mode)) if mode else None) + check_perms(name, None, user, group, int(f"{mode}") if mode else None) return ret @@ -6846,20 +6824,20 @@ def mknod_fifo(name, user=None, group=None, mode="0660"): log.debug("Creating FIFO name: %s", name) try: if __opts__["test"]: - ret["changes"] = {"new": "Fifo pipe {} created.".format(name)} + ret["changes"] = {"new": f"Fifo pipe {name} created."} ret["result"] = None else: if os.mkfifo(name, int(str(mode).lstrip("0Oo"), 8)) is None: - ret["changes"] = {"new": "Fifo pipe {} created.".format(name)} + ret["changes"] = {"new": f"Fifo pipe {name} created."} ret["result"] = True except OSError as exc: # be happy it is already there if exc.errno != errno.EEXIST: raise else: - ret["comment"] = "File {} exists and cannot be overwritten".format(name) + ret["comment"] = f"File {name} exists and cannot be overwritten" # quick pass at verifying the permissions of the newly created fifo - check_perms(name, None, user, group, int("{}".format(mode)) if mode else None) + check_perms(name, None, user, group, int(f"{mode}") if mode else None) return ret @@ -6941,9 +6919,9 @@ def list_backups(path, limit=None): ]: if salt.utils.platform.is_windows(): # ':' is an illegal filesystem path character on Windows - strpfmt = "{}_%a_%b_%d_%H-%M-%S_%f_%Y".format(basename) + strpfmt = f"{basename}_%a_%b_%d_%H-%M-%S_%f_%Y" else: - strpfmt = "{}_%a_%b_%d_%H:%M:%S_%f_%Y".format(basename) + strpfmt = f"{basename}_%a_%b_%d_%H:%M:%S_%f_%Y" try: timestamp = datetime.datetime.strptime(fname, strpfmt) except ValueError: @@ -7019,7 +6997,7 @@ def list_backups_dir(path, limit=None): for x in sorted(ff): basename = x.split("_")[0] if i == basename: - strpfmt = "{}_%a_%b_%d_%H:%M:%S_%f_%Y".format(basename) + strpfmt = f"{basename}_%a_%b_%d_%H:%M:%S_%f_%Y" try: timestamp = datetime.datetime.strptime(x, strpfmt) except ValueError: @@ -7069,7 +7047,7 @@ def restore_backup(path, backup_id): # Note: This only supports minion backups, so this function will need to be # modified if/when master backups are implemented. - ret = {"result": False, "comment": "Invalid backup_id '{}'".format(backup_id)} + ret = {"result": False, "comment": f"Invalid backup_id '{backup_id}'"} try: if len(str(backup_id)) == len(str(int(backup_id))): backup = list_backups(path)[int(backup_id)] @@ -7078,7 +7056,7 @@ def restore_backup(path, backup_id): except ValueError: return ret except KeyError: - ret["comment"] = "backup_id '{}' does not exist for {}".format(backup_id, path) + ret["comment"] = f"backup_id '{backup_id}' does not exist for {path}" return ret salt.utils.files.backup_minion(path, _get_bkroot()) @@ -7128,7 +7106,7 @@ def delete_backup(path, backup_id): """ path = os.path.expanduser(path) - ret = {"result": False, "comment": "Invalid backup_id '{}'".format(backup_id)} + ret = {"result": False, "comment": f"Invalid backup_id '{backup_id}'"} try: if len(str(backup_id)) == len(str(int(backup_id))): backup = list_backups(path)[int(backup_id)] @@ -7137,7 +7115,7 @@ def delete_backup(path, backup_id): except ValueError: return ret except KeyError: - ret["comment"] = "backup_id '{}' does not exist for {}".format(backup_id, path) + ret["comment"] = f"backup_id '{backup_id}' does not exist for {path}" return ret try: @@ -7255,9 +7233,9 @@ def open_files(by_pid=False): # Then we look at the open files for each PID files = {} for pid in pids: - ppath = "/proc/{}".format(pid) + ppath = f"/proc/{pid}" try: - tids = os.listdir("{}/task".format(ppath)) + tids = os.listdir(f"{ppath}/task") except OSError: continue @@ -7269,17 +7247,17 @@ def open_files(by_pid=False): # except Exception: # pylint: disable=broad-except # pass - for fpath in os.listdir("{}/fd".format(ppath)): - fd_.append("{}/fd/{}".format(ppath, fpath)) + for fpath in os.listdir(f"{ppath}/fd"): + fd_.append(f"{ppath}/fd/{fpath}") for tid in tids: try: - fd_.append(os.path.realpath("{}/task/{}/exe".format(ppath, tid))) + fd_.append(os.path.realpath(f"{ppath}/task/{tid}/exe")) except OSError: continue - for tpath in os.listdir("{}/task/{}/fd".format(ppath, tid)): - fd_.append("{}/task/{}/fd/{}".format(ppath, tid, tpath)) + for tpath in os.listdir(f"{ppath}/task/{tid}/fd"): + fd_.append(f"{ppath}/task/{tid}/fd/{tpath}") fd_ = sorted(set(fd_)) @@ -7456,15 +7434,13 @@ def move(src, dst, disallow_copy_and_unlink=False): ret = { "result": True, - "comment": "'{}' moved to '{}'".format(src, dst), + "comment": f"'{src}' moved to '{dst}'", } try: shutil.move(src, dst) except OSError as exc: - raise CommandExecutionError( - "Unable to move '{}' to '{}': {}".format(src, dst, exc) - ) + raise CommandExecutionError(f"Unable to move '{src}' to '{dst}': {exc}") return ret diff --git a/salt/modules/firewalld.py b/salt/modules/firewalld.py index 2c5f35ea18b..878969d6d8b 100644 --- a/salt/modules/firewalld.py +++ b/salt/modules/firewalld.py @@ -39,7 +39,7 @@ def __firewall_cmd(cmd): msg = out["stdout"] else: msg = out["stderr"] - raise CommandExecutionError("firewall-cmd failed: {}".format(msg)) + raise CommandExecutionError(f"firewall-cmd failed: {msg}") return out["stdout"] @@ -48,7 +48,7 @@ def __mgmt(name, _type, action): Perform zone management """ # It's permanent because the 4 concerned functions need the permanent option, it's wrong without - cmd = "--{}-{}={} --permanent".format(action, _type, name) + cmd = f"--{action}-{_type}={name} --permanent" return __firewall_cmd(cmd) @@ -258,7 +258,7 @@ def set_default_zone(zone): salt '*' firewalld.set_default_zone damian """ - return __firewall_cmd("--set-default-zone={}".format(zone)) + return __firewall_cmd(f"--set-default-zone={zone}") def new_service(name, restart=True): @@ -332,7 +332,7 @@ def list_all(zone=None, permanent=True): salt '*' firewalld.list_all my_zone """ if zone: - cmd = "--zone={} --list-all".format(zone) + cmd = f"--zone={zone} --list-all" else: cmd = "--list-all" @@ -360,7 +360,7 @@ def list_services(zone=None, permanent=True): salt '*' firewalld.list_services my_zone """ if zone: - cmd = "--zone={} --list-services".format(zone) + cmd = f"--zone={zone} --list-services" else: cmd = "--list-services" @@ -387,9 +387,9 @@ def add_service(service, zone=None, permanent=True): salt '*' firewalld.add_service ssh my_zone """ if zone: - cmd = "--zone={} --add-service={}".format(zone, service) + cmd = f"--zone={zone} --add-service={service}" else: - cmd = "--add-service={}".format(service) + cmd = f"--add-service={service}" if permanent: cmd += " --permanent" @@ -415,9 +415,9 @@ def remove_service(service, zone=None, permanent=True): salt '*' firewalld.remove_service ssh dmz """ if zone: - cmd = "--zone={} --remove-service={}".format(zone, service) + cmd = f"--zone={zone} --remove-service={service}" else: - cmd = "--remove-service={}".format(service) + cmd = f"--remove-service={service}" if permanent: cmd += " --permanent" @@ -440,7 +440,7 @@ def add_service_port(service, port): if service not in get_services(permanent=True): raise CommandExecutionError("The service does not exist.") - cmd = "--permanent --service={} --add-port={}".format(service, port) + cmd = f"--permanent --service={service} --add-port={port}" return __firewall_cmd(cmd) @@ -459,7 +459,7 @@ def remove_service_port(service, port): if service not in get_services(permanent=True): raise CommandExecutionError("The service does not exist.") - cmd = "--permanent --service={} --remove-port={}".format(service, port) + cmd = f"--permanent --service={service} --remove-port={port}" return __firewall_cmd(cmd) @@ -475,7 +475,7 @@ def get_service_ports(service): salt '*' firewalld.get_service_ports zone """ - cmd = "--permanent --service={} --get-ports".format(service) + cmd = f"--permanent --service={service} --get-ports" return __firewall_cmd(cmd).split() @@ -491,7 +491,7 @@ def add_service_protocol(service, protocol): salt '*' firewalld.add_service_protocol zone ssh """ - cmd = "--permanent --service={} --add-protocol={}".format(service, protocol) + cmd = f"--permanent --service={service} --add-protocol={protocol}" return __firewall_cmd(cmd) @@ -507,7 +507,7 @@ def remove_service_protocol(service, protocol): salt '*' firewalld.remove_service_protocol zone ssh """ - cmd = "--permanent --service={} --remove-protocol={}".format(service, protocol) + cmd = f"--permanent --service={service} --remove-protocol={protocol}" return __firewall_cmd(cmd) @@ -523,7 +523,7 @@ def get_service_protocols(service): salt '*' firewalld.get_service_protocols zone """ - cmd = "--permanent --service={} --get-protocols".format(service) + cmd = f"--permanent --service={service} --get-protocols" return __firewall_cmd(cmd).split() @@ -566,7 +566,7 @@ def add_masquerade(zone=None, permanent=True): salt '*' firewalld.add_masquerade dmz """ if zone: - cmd = "--zone={} --add-masquerade".format(zone) + cmd = f"--zone={zone} --add-masquerade" else: cmd = "--add-masquerade" @@ -596,7 +596,7 @@ def remove_masquerade(zone=None, permanent=True): salt '*' firewalld.remove_masquerade dmz """ if zone: - cmd = "--zone={} --remove-masquerade".format(zone) + cmd = f"--zone={zone} --remove-masquerade" else: cmd = "--remove-masquerade" @@ -625,7 +625,7 @@ def add_port(zone, port, permanent=True, force_masquerade=False): if force_masquerade and not get_masquerade(zone): add_masquerade(zone) - cmd = "--zone={} --add-port={}".format(zone, port) + cmd = f"--zone={zone} --add-port={port}" if permanent: cmd += " --permanent" @@ -645,7 +645,7 @@ def remove_port(zone, port, permanent=True): salt '*' firewalld.remove_port internal 443/tcp """ - cmd = "--zone={} --remove-port={}".format(zone, port) + cmd = f"--zone={zone} --remove-port={port}" if permanent: cmd += " --permanent" @@ -665,7 +665,7 @@ def list_ports(zone, permanent=True): salt '*' firewalld.list_ports """ - cmd = "--zone={} --list-ports".format(zone) + cmd = f"--zone={zone} --list-ports" if permanent: cmd += " --permanent" @@ -740,7 +740,7 @@ def list_port_fwd(zone, permanent=True): """ ret = [] - cmd = "--zone={} --list-forward-ports".format(zone) + cmd = f"--zone={zone} --list-forward-ports" if permanent: cmd += " --permanent" @@ -780,7 +780,7 @@ def block_icmp(zone, icmp, permanent=True): log.info("ICMP block already exists") return "success" - cmd = "--zone={} --add-icmp-block={}".format(zone, icmp) + cmd = f"--zone={zone} --add-icmp-block={icmp}" if permanent: cmd += " --permanent" @@ -808,7 +808,7 @@ def allow_icmp(zone, icmp, permanent=True): log.info("ICMP Type is already permitted") return "success" - cmd = "--zone={} --remove-icmp-block={}".format(zone, icmp) + cmd = f"--zone={zone} --remove-icmp-block={icmp}" if permanent: cmd += " --permanent" @@ -828,7 +828,7 @@ def list_icmp_block(zone, permanent=True): salt '*' firewlld.list_icmp_block zone """ - cmd = "--zone={} --list-icmp-blocks".format(zone) + cmd = f"--zone={zone} --list-icmp-blocks" if permanent: cmd += " --permanent" @@ -863,7 +863,7 @@ def get_interfaces(zone, permanent=True): salt '*' firewalld.get_interfaces zone """ - cmd = "--zone={} --list-interfaces".format(zone) + cmd = f"--zone={zone} --list-interfaces" if permanent: cmd += " --permanent" @@ -886,7 +886,7 @@ def add_interface(zone, interface, permanent=True): if interface in get_interfaces(zone, permanent): log.info("Interface is already bound to zone.") - cmd = "--zone={} --add-interface={}".format(zone, interface) + cmd = f"--zone={zone} --add-interface={interface}" if permanent: cmd += " --permanent" @@ -909,7 +909,7 @@ def remove_interface(zone, interface, permanent=True): if interface not in get_interfaces(zone, permanent): log.info("Interface is not bound to zone.") - cmd = "--zone={} --remove-interface={}".format(zone, interface) + cmd = f"--zone={zone} --remove-interface={interface}" if permanent: cmd += " --permanent" @@ -929,7 +929,7 @@ def get_sources(zone, permanent=True): salt '*' firewalld.get_sources zone """ - cmd = "--zone={} --list-sources".format(zone) + cmd = f"--zone={zone} --list-sources" if permanent: cmd += " --permanent" @@ -952,7 +952,7 @@ def add_source(zone, source, permanent=True): if source in get_sources(zone, permanent): log.info("Source is already bound to zone.") - cmd = "--zone={} --add-source={}".format(zone, source) + cmd = f"--zone={zone} --add-source={source}" if permanent: cmd += " --permanent" @@ -975,7 +975,7 @@ def remove_source(zone, source, permanent=True): if source not in get_sources(zone, permanent): log.info("Source is not bound to zone.") - cmd = "--zone={} --remove-source={}".format(zone, source) + cmd = f"--zone={zone} --remove-source={source}" if permanent: cmd += " --permanent" @@ -995,7 +995,7 @@ def get_rich_rules(zone, permanent=True): salt '*' firewalld.get_rich_rules zone """ - cmd = "--zone={} --list-rich-rules".format(zone) + cmd = f"--zone={zone} --list-rich-rules" if permanent: cmd += " --permanent" @@ -1015,7 +1015,7 @@ def add_rich_rule(zone, rule, permanent=True): salt '*' firewalld.add_rich_rule zone 'rule' """ - cmd = "--zone={} --add-rich-rule='{}'".format(zone, rule) + cmd = f"--zone={zone} --add-rich-rule='{rule}'" if permanent: cmd += " --permanent" @@ -1035,7 +1035,7 @@ def remove_rich_rule(zone, rule, permanent=True): salt '*' firewalld.remove_rich_rule zone 'rule' """ - cmd = "--zone={} --remove-rich-rule='{}'".format(zone, rule) + cmd = f"--zone={zone} --remove-rich-rule='{rule}'" if permanent: cmd += " --permanent" diff --git a/salt/modules/freebsd_sysctl.py b/salt/modules/freebsd_sysctl.py index 6f809176f49..ad2a6ba3eaf 100644 --- a/salt/modules/freebsd_sysctl.py +++ b/salt/modules/freebsd_sysctl.py @@ -30,9 +30,9 @@ def __virtual__(): def _formatfor(name, value, config, tail=""): if config == "/boot/loader.conf": - return '{}="{}"{}'.format(name, value, tail) + return f'{name}="{value}"{tail}' else: - return "{}={}{}".format(name, value, tail) + return f"{name}={value}{tail}" def show(config_file=False): @@ -87,13 +87,13 @@ def show(config_file=False): out = __salt__["cmd.run"](cmd, output_loglevel="trace") value = None for line in out.splitlines(): - if any([line.startswith("{}.".format(root)) for root in roots]): + if any([line.startswith(f"{root}.") for root in roots]): if value is not None: ret[key] = "\n".join(value) (key, firstvalue) = line.split("=", 1) value = [firstvalue] elif value is not None: - value.append("{}".format(line)) + value.append(f"{line}") if value is not None: ret[key] = "\n".join(value) return ret @@ -109,7 +109,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd, python_shell=False) return out @@ -125,7 +125,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.icmp.icmplim 50 """ ret = {} - cmd = 'sysctl {}="{}"'.format(name, value) + cmd = f'sysctl {name}="{value}"' data = __salt__["cmd.run_all"](cmd, python_shell=False) if data["retcode"] != 0: @@ -153,7 +153,7 @@ def persist(name, value, config="/etc/sysctl.conf"): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line).rstrip("\n") - if not line.startswith("{}=".format(name)): + if not line.startswith(f"{name}="): nlines.append(line) continue else: @@ -176,7 +176,7 @@ def persist(name, value, config="/etc/sysctl.conf"): nlines.append(new_line) edited = True if not edited: - nlines.append("{}\n".format(_formatfor(name, value, config))) + nlines.append(f"{_formatfor(name, value, config)}\n") with salt.utils.files.fopen(config, "w+") as ofile: nlines = [salt.utils.stringutils.to_str(_l) + "\n" for _l in nlines] ofile.writelines(nlines) diff --git a/salt/modules/freebsd_update.py b/salt/modules/freebsd_update.py index 816c2b13e96..71904d7230c 100644 --- a/salt/modules/freebsd_update.py +++ b/salt/modules/freebsd_update.py @@ -194,7 +194,7 @@ def update(**kwargs): return ret if "stdout" in err_: stdout[mode] = err_["stdout"] - return "\n".join(["{}: {}".format(k, v) for (k, v) in stdout.items()]) + return "\n".join([f"{k}: {v}" for (k, v) in stdout.items()]) def ids(**kwargs): diff --git a/salt/modules/freebsdkmod.py b/salt/modules/freebsdkmod.py index 27793f758c6..db13306ceb5 100644 --- a/salt/modules/freebsdkmod.py +++ b/salt/modules/freebsdkmod.py @@ -201,7 +201,7 @@ def load(mod, persist=False): salt '*' kmod.load bhyve """ pre_mods = lsmod() - response = __salt__["cmd.run_all"]("kldload {}".format(mod), python_shell=False) + response = __salt__["cmd.run_all"](f"kldload {mod}", python_shell=False) if response["retcode"] == 0: post_mods = lsmod() mods = _new_mods(pre_mods, post_mods) @@ -217,7 +217,7 @@ def load(mod, persist=False): # It's compiled into the kernel return [None] else: - return "Module {} not found".format(mod) + return f"Module {mod} not found" def is_loaded(mod): @@ -254,7 +254,7 @@ def remove(mod, persist=False, comment=True): salt '*' kmod.remove vmm """ pre_mods = lsmod() - res = __salt__["cmd.run_all"]("kldunload {}".format(mod), python_shell=False) + res = __salt__["cmd.run_all"](f"kldunload {mod}", python_shell=False) if res["retcode"] == 0: post_mods = lsmod() mods = _rm_mods(pre_mods, post_mods) diff --git a/salt/modules/freebsdpkg.py b/salt/modules/freebsdpkg.py index 36de306b687..77ba7444cfa 100644 --- a/salt/modules/freebsdpkg.py +++ b/salt/modules/freebsdpkg.py @@ -175,20 +175,20 @@ def _match(names): cver = pkgs.get(name) if cver is not None: if len(cver) == 1: - matches.append("{}-{}".format(name, cver[0])) + matches.append(f"{name}-{cver[0]}") else: ambiguous.append(name) errors.append( "Ambiguous package '{}'. Full name/version required. " "Possible matches: {}".format( - name, ", ".join(["{}-{}".format(name, x) for x in cver]) + name, ", ".join([f"{name}-{x}" for x in cver]) ) ) # Find packages that did not match anything not_matched = set(names) - set(matches) - set(full_matches) - set(ambiguous) for name in not_matched: - errors.append("Package '{}' not found".format(name)) + errors.append(f"Package '{name}' not found") return matches + full_matches, errors diff --git a/salt/modules/freebsdports.py b/salt/modules/freebsdports.py index 3ab53e24f80..254212f0e16 100644 --- a/salt/modules/freebsdports.py +++ b/salt/modules/freebsdports.py @@ -59,13 +59,11 @@ def _check_portname(name): ports tree. """ if not isinstance(name, str) or "/" not in name: - raise SaltInvocationError( - "Invalid port name '{}' (category required)".format(name) - ) + raise SaltInvocationError(f"Invalid port name '{name}' (category required)") path = os.path.join("/usr/ports", name) if not os.path.isdir(path): - raise SaltInvocationError("Path '{}' does not exist".format(path)) + raise SaltInvocationError(f"Path '{path}' does not exist") return path @@ -109,7 +107,7 @@ def _write_options(name, configuration): try: os.makedirs(dirname) except OSError as exc: - raise CommandExecutionError("Unable to make {}: {}".format(dirname, exc)) + raise CommandExecutionError(f"Unable to make {dirname}: {exc}") with salt.utils.files.fopen(os.path.join(dirname, "options"), "w") as fp_: sorted_options = list(conf_ptr) @@ -270,7 +268,7 @@ def showconfig(name, default=False, dict_return=False): error = result if error: - msg = "Error running 'make showconfig' for {}: {}".format(name, error) + msg = f"Error running 'make showconfig' for {name}: {error}" log.error(msg) raise SaltInvocationError(msg) @@ -327,9 +325,7 @@ def config(name, reset=False, **kwargs): configuration = showconfig(name, dict_return=True) if not configuration: - raise CommandExecutionError( - "Unable to get port configuration for '{}'".format(name) - ) + raise CommandExecutionError(f"Unable to get port configuration for '{name}'") # Get top-level key for later reference pkg = next(iter(configuration)) @@ -345,7 +341,7 @@ def config(name, reset=False, **kwargs): ) ) - bad_vals = ["{}={}".format(x, y) for x, y in opts.items() if y not in ("on", "off")] + bad_vals = [f"{x}={y}" for x, y in opts.items() if y not in ("on", "off")] if bad_vals: raise SaltInvocationError( "The following key/value pairs are invalid: {}".format(", ".join(bad_vals)) @@ -396,8 +392,8 @@ def update(extract=False): except AttributeError: new_port_count = 0 - ret.append("Applied {} new patches".format(patch_count)) - ret.append("Fetched {} new ports or files".format(new_port_count)) + ret.append(f"Applied {patch_count} new patches") + ret.append(f"Fetched {new_port_count} new ports or files") if extract: result = __salt__["cmd.run_all"](_portsnap() + ["extract"], python_shell=False) diff --git a/salt/modules/freebsdservice.py b/salt/modules/freebsdservice.py index f053db695fe..a5fdc2cbad6 100644 --- a/salt/modules/freebsdservice.py +++ b/salt/modules/freebsdservice.py @@ -56,7 +56,7 @@ def _cmd(jail=None): jexec = salt.utils.path.which("jexec") if not jexec: raise CommandNotFoundError("'jexec' command not found") - service = "{} {} {}".format(jexec, jail, service) + service = f"{jexec} {jail} {service}" return service @@ -72,7 +72,7 @@ def _get_jail_path(jail): jls = salt.utils.path.which("jls") if not jls: raise CommandNotFoundError("'jls' command not found") - jails = __salt__["cmd.run_stdout"]("{} -n jid name path".format(jls)) + jails = __salt__["cmd.run_stdout"](f"{jls} -n jid name path") for j in jails.splitlines(): jid, jname, path = (x.split("=")[1].strip() for x in j.split()) if jid == jail or jname == jail: @@ -89,10 +89,10 @@ def _get_rcscript(name, jail=None): Support for jail (representing jid or jail name) keyword argument in kwargs """ - cmd = "{} -r".format(_cmd(jail)) + cmd = f"{_cmd(jail)} -r" prf = _get_jail_path(jail) if jail else "" for line in __salt__["cmd.run_stdout"](cmd, python_shell=False).splitlines(): - if line.endswith("{}{}".format(os.path.sep, name)): + if line.endswith(f"{os.path.sep}{name}"): return os.path.join(prf, line.lstrip(os.path.sep)) return None @@ -109,7 +109,7 @@ def _get_rcvar(name, jail=None): log.error("Service %s not found", name) return False - cmd = "{} {} rcvar".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} rcvar" for line in __salt__["cmd.run_stdout"](cmd, python_shell=False).splitlines(): if '_enable="' not in line: @@ -137,14 +137,14 @@ def get_enabled(jail=None): ret = [] service = _cmd(jail) prf = _get_jail_path(jail) if jail else "" - for svc in __salt__["cmd.run"]("{} -e".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} -e").splitlines(): ret.append(os.path.basename(svc)) # This is workaround for bin/173454 bug for svc in get_all(jail): if svc in ret: continue - if not os.path.exists("{}/etc/rc.conf.d/{}".format(prf, svc)): + if not os.path.exists(f"{prf}/etc/rc.conf.d/{svc}"): continue if enabled(svc, jail=jail): ret.append(svc) @@ -199,13 +199,11 @@ def _switch(name, on, **kwargs): # pylint: disable=C0103 # pylint: disable=C01 config = kwargs.get( "config", - __salt__["config.option"]( - "service.config", default="{}/etc/rc.conf".format(chroot) - ), + __salt__["config.option"]("service.config", default=f"{chroot}/etc/rc.conf"), ) if not config: - rcdir = "{}/etc/rc.conf.d".format(chroot) + rcdir = f"{chroot}/etc/rc.conf.d" if not os.path.exists(rcdir) or not os.path.isdir(rcdir): log.error("%s not exists", rcdir) return False @@ -223,17 +221,17 @@ def _switch(name, on, **kwargs): # pylint: disable=C0103 # pylint: disable=C01 with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - if not line.startswith("{}=".format(rcvar)): + if not line.startswith(f"{rcvar}="): nlines.append(line) continue rest = line[len(line.split()[0]) :] # keep comments etc - nlines.append('{}="{}"{}'.format(rcvar, val, rest)) + nlines.append(f'{rcvar}="{val}"{rest}') edited = True if not edited: # Ensure that the file ends in a \n if len(nlines) > 1 and nlines[-1][-1] != "\n": - nlines[-1] = "{}\n".format(nlines[-1]) - nlines.append('{}="{}"\n'.format(rcvar, val)) + nlines[-1] = f"{nlines[-1]}\n" + nlines.append(f'{rcvar}="{val}"\n') with salt.utils.files.fopen(config, "w") as ofile: nlines = [salt.utils.stringutils.to_str(_l) for _l in nlines] @@ -318,7 +316,7 @@ def enabled(name, **kwargs): log.error("Service %s not found", name) return False - cmd = "{} {} rcvar".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} rcvar" for line in __salt__["cmd.run_stdout"](cmd, python_shell=False).splitlines(): if '_enable="' not in line: @@ -395,7 +393,7 @@ def get_all(jail=None): """ ret = [] service = _cmd(jail) - for srv in __salt__["cmd.run"]("{} -l".format(service)).splitlines(): + for srv in __salt__["cmd.run"](f"{service} -l").splitlines(): if not srv.isupper(): ret.append(srv) return sorted(ret) @@ -415,7 +413,7 @@ def start(name, jail=None): salt '*' service.start """ - cmd = "{} {} onestart".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onestart" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -433,7 +431,7 @@ def stop(name, jail=None): salt '*' service.stop """ - cmd = "{} {} onestop".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onestop" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -451,7 +449,7 @@ def restart(name, jail=None): salt '*' service.restart """ - cmd = "{} {} onerestart".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onerestart" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -469,7 +467,7 @@ def reload_(name, jail=None): salt '*' service.reload """ - cmd = "{} {} onereload".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onereload" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -508,7 +506,7 @@ def status(name, sig=None, jail=None): services = [name] results = {} for service in services: - cmd = "{} {} onestatus".format(_cmd(jail), service) + cmd = f"{_cmd(jail)} {service} onestatus" results[service] = not __salt__["cmd.retcode"]( cmd, python_shell=False, ignore_retcode=True ) diff --git a/salt/modules/freezer.py b/salt/modules/freezer.py index 296a26bf5bb..329cff98c3e 100644 --- a/salt/modules/freezer.py +++ b/salt/modules/freezer.py @@ -49,8 +49,8 @@ def _paths(name=None): name = "freezer" if not name else name states_path = _states_path() return ( - os.path.join(states_path, "{}-pkgs.yml".format(name)), - os.path.join(states_path, "{}-reps.yml".format(name)), + os.path.join(states_path, f"{name}-pkgs.yml"), + os.path.join(states_path, f"{name}-reps.yml"), ) diff --git a/salt/modules/genesis.py b/salt/modules/genesis.py index 5c2be12388a..4b9dca2351a 100644 --- a/salt/modules/genesis.py +++ b/salt/modules/genesis.py @@ -153,18 +153,18 @@ def bootstrap( if not img_size: raise SaltInvocationError("An img_size must be specified for a sparse file") if not mount_dir: - mount_dir = "/opt/salt-genesis.{}".format(uuid.uuid4()) + mount_dir = f"/opt/salt-genesis.{uuid.uuid4()}" __salt__["file.mkdir"](mount_dir, "root", "root", "755") __salt__["cmd.run"](("fallocate", "-l", img_size, root), python_shell=False) _mkpart(root, fs_format, fs_opts, mount_dir) loop1 = __salt__["cmd.run"]("losetup -f") log.debug("First loop device is %s", loop1) - __salt__["cmd.run"]("losetup {} {}".format(loop1, root)) + __salt__["cmd.run"](f"losetup {loop1} {root}") loop2 = __salt__["cmd.run"]("losetup -f") log.debug("Second loop device is %s", loop2) start = str(2048 * 2048) - __salt__["cmd.run"]("losetup -o {} {} {}".format(start, loop2, loop1)) + __salt__["cmd.run"](f"losetup -o {start} {loop2} {loop1}") __salt__["mount.mount"](mount_dir, loop2) _populate_cache(platform, pkg_cache, mount_dir) @@ -206,13 +206,13 @@ def bootstrap( if img_format != "dir": blkinfo = __salt__["disk.blkid"](loop2) __salt__["file.replace"]( - "{}/boot/grub/grub.cfg".format(mount_dir), + f"{mount_dir}/boot/grub/grub.cfg", "ad4103fa-d940-47ca-8506-301d8071d467", # This seems to be the default blkinfo[loop2]["UUID"], ) __salt__["mount.umount"](root) - __salt__["cmd.run"]("losetup -d {}".format(loop2)) - __salt__["cmd.run"]("losetup -d {}".format(loop1)) + __salt__["cmd.run"](f"losetup -d {loop2}") + __salt__["cmd.run"](f"losetup -d {loop1}") __salt__["file.rmdir"](mount_dir) @@ -225,7 +225,7 @@ def _mkpart(root, fs_format, fs_opts, mount_dir): __salt__["partition.mklabel"](root, "msdos") loop1 = __salt__["cmd.run"]("losetup -f") log.debug("First loop device is %s", loop1) - __salt__["cmd.run"]("losetup {} {}".format(loop1, root)) + __salt__["cmd.run"](f"losetup {loop1} {root}") part_info = __salt__["partition.list"](loop1) start = str(2048 * 2048) + "B" end = part_info["info"]["size"] @@ -235,7 +235,7 @@ def _mkpart(root, fs_format, fs_opts, mount_dir): loop2 = __salt__["cmd.run"]("losetup -f") log.debug("Second loop device is %s", loop2) start = start.rstrip("B") - __salt__["cmd.run"]("losetup -o {} {} {}".format(start, loop2, loop1)) + __salt__["cmd.run"](f"losetup -o {start} {loop2} {loop1}") _mkfs(loop2, fs_format, fs_opts) __salt__["mount.mount"](mount_dir, loop2) __salt__["cmd.run"]( @@ -245,14 +245,14 @@ def _mkpart(root, fs_format, fs_opts, mount_dir): "--debug", "--no-floppy", "--modules=part_msdos linux", - "--boot-directory={}/boot".format(mount_dir), + f"--boot-directory={mount_dir}/boot", loop1, ), python_shell=False, ) __salt__["mount.umount"](mount_dir) - __salt__["cmd.run"]("losetup -d {}".format(loop2)) - __salt__["cmd.run"]("losetup -d {}".format(loop1)) + __salt__["cmd.run"](f"losetup -d {loop2}") + __salt__["cmd.run"](f"losetup -d {loop1}") return part_info @@ -284,7 +284,7 @@ def _populate_cache(platform, pkg_cache, mount_dir): return if platform == "pacman": - cache_dir = "{}/var/cache/pacman/pkg".format(mount_dir) + cache_dir = f"{mount_dir}/var/cache/pacman/pkg" __salt__["file.mkdir"](cache_dir, "root", "root", "755") __salt__["file.copy"](pkg_cache, cache_dir, recurse=True, remove_existing=True) @@ -361,14 +361,14 @@ def _bootstrap_yum( yum_args = [ "yum", "install", - "--installroot={}".format(shlex.quote(root)), + f"--installroot={shlex.quote(root)}", "-y", ] + pkgs __salt__["cmd.run"](yum_args, python_shell=False) if "epel-release" not in exclude_pkgs: __salt__["cmd.run"]( - ("rpm", "--root={}".format(shlex.quote(root)), "-Uvh", epel_url), + ("rpm", f"--root={shlex.quote(root)}", "-Uvh", epel_url), python_shell=False, ) @@ -462,9 +462,7 @@ def _bootstrap_deb( ), env=env, ) - __salt__["cmd.run"]( - "chroot {root} dpkg --configure -a".format(root=shlex.quote(root)), env=env - ) + __salt__["cmd.run"](f"chroot {shlex.quote(root)} dpkg --configure -a", env=env) def _bootstrap_pacman( @@ -519,25 +517,23 @@ def _bootstrap_pacman( pkgs.remove(pkg) if img_format != "dir": - __salt__["mount.mount"]("{}/proc".format(root), "/proc", fstype="", opts="bind") - __salt__["mount.mount"]("{}/dev".format(root), "/dev", fstype="", opts="bind") + __salt__["mount.mount"](f"{root}/proc", "/proc", fstype="", opts="bind") + __salt__["mount.mount"](f"{root}/dev", "/dev", fstype="", opts="bind") - __salt__["file.mkdir"]( - "{}/var/lib/pacman/local".format(root), "root", "root", "755" - ) + __salt__["file.mkdir"](f"{root}/var/lib/pacman/local", "root", "root", "755") pac_files = [rf for rf in os.listdir("/etc") if rf.startswith("pacman.")] for pac_file in pac_files: - __salt__["cmd.run"]("cp -r /etc/{} {}/etc".format(pac_file, shlex.quote(root))) + __salt__["cmd.run"](f"cp -r /etc/{pac_file} {shlex.quote(root)}/etc") __salt__["file.copy"]( - "/var/lib/pacman/sync", "{}/var/lib/pacman/sync".format(root), recurse=True + "/var/lib/pacman/sync", f"{root}/var/lib/pacman/sync", recurse=True ) pacman_args = ["pacman", "--noconfirm", "-r", shlex.quote(root), "-S"] + pkgs __salt__["cmd.run"](pacman_args, python_shell=False) if img_format != "dir": - __salt__["mount.umount"]("{}/proc".format(root)) - __salt__["mount.umount"]("{}/dev".format(root)) + __salt__["mount.umount"](f"{root}/proc") + __salt__["mount.umount"](f"{root}/dev") def _make_nodes(root): @@ -547,24 +543,24 @@ def _make_nodes(root): https://wiki.archlinux.org/index.php/Linux_Containers """ dirs = ( - ("{}/etc".format(root), "root", "root", "755"), - ("{}/dev".format(root), "root", "root", "755"), - ("{}/proc".format(root), "root", "root", "755"), - ("{}/dev/pts".format(root), "root", "root", "755"), - ("{}/dev/shm".format(root), "root", "root", "1755"), + (f"{root}/etc", "root", "root", "755"), + (f"{root}/dev", "root", "root", "755"), + (f"{root}/proc", "root", "root", "755"), + (f"{root}/dev/pts", "root", "root", "755"), + (f"{root}/dev/shm", "root", "root", "1755"), ) nodes = ( - ("{}/dev/null".format(root), "c", 1, 3, "root", "root", "666"), - ("{}/dev/zero".format(root), "c", 1, 5, "root", "root", "666"), - ("{}/dev/random".format(root), "c", 1, 8, "root", "root", "666"), - ("{}/dev/urandom".format(root), "c", 1, 9, "root", "root", "666"), - ("{}/dev/tty".format(root), "c", 5, 0, "root", "root", "666"), - ("{}/dev/tty0".format(root), "c", 4, 0, "root", "root", "666"), - ("{}/dev/console".format(root), "c", 5, 1, "root", "root", "600"), - ("{}/dev/full".format(root), "c", 1, 7, "root", "root", "666"), - ("{}/dev/initctl".format(root), "p", 0, 0, "root", "root", "600"), - ("{}/dev/ptmx".format(root), "c", 5, 2, "root", "root", "666"), + (f"{root}/dev/null", "c", 1, 3, "root", "root", "666"), + (f"{root}/dev/zero", "c", 1, 5, "root", "root", "666"), + (f"{root}/dev/random", "c", 1, 8, "root", "root", "666"), + (f"{root}/dev/urandom", "c", 1, 9, "root", "root", "666"), + (f"{root}/dev/tty", "c", 5, 0, "root", "root", "666"), + (f"{root}/dev/tty0", "c", 4, 0, "root", "root", "666"), + (f"{root}/dev/console", "c", 5, 1, "root", "root", "600"), + (f"{root}/dev/full", "c", 1, 7, "root", "root", "666"), + (f"{root}/dev/initctl", "p", 0, 0, "root", "root", "600"), + (f"{root}/dev/ptmx", "c", 5, 2, "root", "root", "666"), ) for path in dirs: @@ -636,9 +632,9 @@ def _tar(name, root, path=None, compress="bzip2"): compression, ext = _compress(compress) - tarfile = "{}/{}.tar.{}".format(path, name, ext) + tarfile = f"{path}/{name}.tar.{ext}" out = __salt__["archive.tar"]( - options="{}pcf".format(compression), + options=f"{compression}pcf", tarfile=tarfile, sources=".", dest=root, @@ -663,9 +659,9 @@ def _untar(name, dest=None, path=None, compress="bz2"): compression, ext = _compress(compress) - tarfile = "{}/{}.tar.{}".format(path, name, ext) + tarfile = f"{path}/{name}.tar.{ext}" out = __salt__["archive.tar"]( - options="{}xf".format(compression), + options=f"{compression}xf", tarfile=tarfile, dest=dest, ) diff --git a/salt/modules/gentoolkitmod.py b/salt/modules/gentoolkitmod.py index 19e7b45f6fa..da8f803a786 100644 --- a/salt/modules/gentoolkitmod.py +++ b/salt/modules/gentoolkitmod.py @@ -50,7 +50,7 @@ def revdep_rebuild(lib=None): """ cmd = "revdep-rebuild -i --quiet --no-progress" if lib is not None: - cmd += " --library={}".format(lib) + cmd += f" --library={lib}" return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 @@ -62,7 +62,7 @@ def _pretty_size(size): while units and size >= 1000: size = size / 1024.0 units.pop() - return "{}{}".format(round(size, 1), units[-1]) + return f"{round(size, 1)}{units[-1]}" def _parse_exclude(exclude_file): @@ -137,7 +137,7 @@ def eclean_dist( try: exclude = _parse_exclude(exclude_file) except excludemod.ParseExcludeFileException as e: - ret = {e: "Invalid exclusion file: {}".format(exclude_file)} + ret = {e: f"Invalid exclusion file: {exclude_file}"} return ret if time_limit != 0: @@ -221,7 +221,7 @@ def eclean_pkg( try: exclude = _parse_exclude(exclude_file) except excludemod.ParseExcludeFileException as e: - ret = {e: "Invalid exclusion file: {}".format(exclude_file)} + ret = {e: f"Invalid exclusion file: {exclude_file}"} return ret if time_limit != 0: diff --git a/salt/modules/git.py b/salt/modules/git.py index 4af2e548de7..4e2d2d0c5bf 100644 --- a/salt/modules/git.py +++ b/salt/modules/git.py @@ -61,7 +61,7 @@ def _config_getter( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ Common code for config.get_* functions, builds and runs the git CLI command @@ -224,7 +224,7 @@ def _git_run( redirect_stderr=False, saltenv="base", output_encoding=None, - **kwargs + **kwargs, ): """ simple, throw an exception with the error message on an error return code. @@ -323,7 +323,7 @@ def _git_run( ignore_retcode=ignore_retcode, redirect_stderr=redirect_stderr, output_encoding=output_encoding, - **kwargs + **kwargs, ) finally: if tmp_ssh_wrapper: @@ -390,7 +390,7 @@ def _git_run( ignore_retcode=ignore_retcode, redirect_stderr=redirect_stderr, output_encoding=output_encoding, - **kwargs + **kwargs, ) if result["retcode"] == 0: @@ -403,7 +403,7 @@ def _git_run( ) err = result["stdout" if redirect_stderr else "stderr"] if err: - msg += ": {}".format(salt.utils.url.redact_http_basic_auth(err)) + msg += f": {salt.utils.url.redact_http_basic_auth(err)}" raise CommandExecutionError(msg) return result @@ -564,7 +564,7 @@ def archive( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.0 @@ -1215,7 +1215,7 @@ def config_get( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ Get the value of a key in the git configuration file @@ -1293,7 +1293,7 @@ def config_get( password=password, ignore_retcode=ignore_retcode, output_encoding=output_encoding, - **kwargs + **kwargs, ) # git config --get exits with retcode of 1 when key does not exist @@ -1318,7 +1318,7 @@ def config_get_regexp( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): r""" .. versionadded:: 2015.8.0 @@ -1395,7 +1395,7 @@ def config_get_regexp( password=password, ignore_retcode=ignore_retcode, output_encoding=output_encoding, - **kwargs + **kwargs, ) # git config --get exits with retcode of 1 when key does not exist @@ -1425,7 +1425,7 @@ def config_set( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.0 @@ -1574,7 +1574,7 @@ def config_set( cwd=cwd, ignore_retcode=ignore_retcode, output_encoding=output_encoding, - **{"all": True, "global": global_} + **{"all": True, "global": global_}, ) @@ -1586,7 +1586,7 @@ def config_unset( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2015.8.0 @@ -1695,9 +1695,9 @@ def config_unset( ) is None ): - raise CommandExecutionError("Key '{}' does not exist".format(key)) + raise CommandExecutionError(f"Key '{key}' does not exist") else: - msg = "Multiple values exist for key '{}'".format(key) + msg = f"Multiple values exist for key '{key}'" if value_regex is not None: msg += " and value_regex matches multiple values" raise CommandExecutionError(msg) @@ -2355,9 +2355,9 @@ def init( if bare: command.append("--bare") if template is not None: - command.append("--template={}".format(template)) + command.append(f"--template={template}") if separate_git_dir is not None: - command.append("--separate-git-dir={}".format(separate_git_dir)) + command.append(f"--separate-git-dir={separate_git_dir}") if shared is not None: if isinstance(shared, int) and not isinstance(shared, bool): shared = "0" + str(shared) @@ -2365,7 +2365,7 @@ def init( # Using lower here because booleans would be capitalized when # converted to a string. shared = str(shared).lower() - command.append("--shared={}".format(shared)) + command.append(f"--shared={shared}") command.extend(_format_opts(opts)) command.append(cwd) return _git_run( @@ -2814,7 +2814,7 @@ def list_worktrees( worktree_root = os.path.join(cwd, worktree_root) if not os.path.isdir(worktree_root): raise CommandExecutionError( - "Worktree admin directory {} not present".format(worktree_root) + f"Worktree admin directory {worktree_root} not present" ) def _read_file(path): @@ -3081,7 +3081,7 @@ def merge( identity=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ Interface to `git-merge(1)`_ @@ -3205,7 +3205,7 @@ def merge_base( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2015.8.0 @@ -3487,7 +3487,7 @@ def merge_tree( base = merge_base(cwd, refs=[ref1, ref2], output_encoding=output_encoding) except (SaltInvocationError, CommandExecutionError): raise CommandExecutionError( - "Unable to determine merge base for {} and {}".format(ref1, ref2) + f"Unable to determine merge base for {ref1} and {ref2}" ) command.extend([base, ref1, ref2]) return _git_run( @@ -3627,7 +3627,7 @@ def push( ignore_retcode=False, saltenv="base", output_encoding=None, - **kwargs + **kwargs, ): """ Interface to `git-push(1)`_ @@ -3927,7 +3927,7 @@ def remote_get( ) if remote not in all_remotes: raise CommandExecutionError( - "Remote '{}' not present in git checkout located at {}".format(remote, cwd) + f"Remote '{remote}' not present in git checkout located at {cwd}" ) return all_remotes[remote] @@ -3944,7 +3944,7 @@ def remote_refs( ignore_retcode=False, output_encoding=None, saltenv="base", - **kwargs + **kwargs, ): """ .. versionadded:: 2015.8.0 @@ -4850,7 +4850,7 @@ def submodule( ignore_retcode=False, saltenv="base", output_encoding=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.0 @@ -5290,7 +5290,7 @@ def worktree_add( password=None, ignore_retcode=False, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2015.8.0 @@ -5602,5 +5602,5 @@ def worktree_rm(cwd, user=None, output_encoding=None): try: salt.utils.files.rm_rf(cwd) except Exception as exc: # pylint: disable=broad-except - raise CommandExecutionError("Unable to remove {}: {}".format(cwd, exc)) + raise CommandExecutionError(f"Unable to remove {cwd}: {exc}") return True diff --git a/salt/modules/github.py b/salt/modules/github.py index d1c3d0e16b0..54b5b1d167a 100644 --- a/salt/modules/github.py +++ b/salt/modules/github.py @@ -118,7 +118,7 @@ def _get_members(organization, params=None): def _get_repos(profile, params=None, ignore_cache=False): # Use cache when no params are given org_name = _get_config_value(profile, "org_name") - key = "github.{}:repos".format(org_name) + key = f"github.{org_name}:repos" if key not in __context__ or ignore_cache or params is not None: org_name = _get_config_value(profile, "org_name") @@ -142,7 +142,7 @@ def _get_repos(profile, params=None, ignore_cache=False): next_result.append(repo) # Cache a copy of each repo for single lookups - repo_key = "github.{}:{}:repo_info".format(org_name, repo.name.lower()) + repo_key = f"github.{org_name}:{repo.name.lower()}:repo_info" __context__[repo_key] = _repo_to_dict(repo) __context__[key] = next_result @@ -170,7 +170,7 @@ def list_users(profile="github", ignore_cache=False): salt myminion github.list_users profile='my-github-profile' """ org_name = _get_config_value(profile, "org_name") - key = "github.{}:users".format(org_name) + key = f"github.{org_name}:users" if key not in __context__ or ignore_cache: client = _get_client(profile) organization = client.get_organization(org_name) @@ -1833,7 +1833,7 @@ def _query( url += action if command: - url += "/{}".format(command) + url += f"/{command}" log.debug("GitHub URL: %s", url) diff --git a/salt/modules/glassfish.py b/salt/modules/glassfish.py index 558db0809e5..f98e7009d29 100644 --- a/salt/modules/glassfish.py +++ b/salt/modules/glassfish.py @@ -70,9 +70,9 @@ def _get_url(ssl, url, port, path): Returns the URL of the endpoint """ if ssl: - return "https://{}:{}/management/domain/{}".format(url, port, path) + return f"https://{url}:{port}/management/domain/{path}" else: - return "http://{}:{}/management/domain/{}".format(url, port, path) + return f"http://{url}:{port}/management/domain/{path}" def _get_server(server): @@ -183,7 +183,7 @@ def _get_element_properties(name, element_type, server=None): Get an element's properties """ properties = {} - data = _api_get("{}/{}/property".format(element_type, name), server) + data = _api_get(f"{element_type}/{name}/property", server) # Get properties into a dict if any(data["extraProperties"]["properties"]): @@ -199,7 +199,7 @@ def _get_element(name, element_type, server=None, with_properties=True): """ element = {} name = urllib.parse.quote(name, safe="") - data = _api_get("{}/{}".format(element_type, name), server) + data = _api_get(f"{element_type}/{name}", server) # Format data, get properties if asked, and return the whole thing if any(data["extraProperties"]["entity"]): @@ -242,7 +242,7 @@ def _update_element(name, element_type, data, server=None): properties = [] for key, value in data["properties"].items(): properties.append({"name": key, "value": value}) - _api_post("{}/{}/property".format(element_type, name), properties, server) + _api_post(f"{element_type}/{name}/property", properties, server) del data["properties"] # If the element only contained properties @@ -255,10 +255,10 @@ def _update_element(name, element_type, data, server=None): update_data.update(data) else: __context__["retcode"] = salt.defaults.exitcodes.SALT_BUILD_FAIL - raise CommandExecutionError("Cannot update {}".format(name)) + raise CommandExecutionError(f"Cannot update {name}") # Finally, update the element - _api_post("{}/{}".format(element_type, name), _clean_data(update_data), server) + _api_post(f"{element_type}/{name}", _clean_data(update_data), server) return urllib.parse.unquote(name) @@ -694,4 +694,4 @@ def delete_system_properties(name, server=None): """ Delete a system property """ - _api_delete("system-properties/{}".format(name), None, server) + _api_delete(f"system-properties/{name}", None, server) diff --git a/salt/modules/glusterfs.py b/salt/modules/glusterfs.py index 5de5110df35..b1ba1e2cb8e 100644 --- a/salt/modules/glusterfs.py +++ b/salt/modules/glusterfs.py @@ -73,12 +73,10 @@ def _gluster_xml(cmd): 6, ): result = __salt__["cmd.run"]( - 'script -q -c "gluster --xml --mode=script"', stdin="{}\n\004".format(cmd) + 'script -q -c "gluster --xml --mode=script"', stdin=f"{cmd}\n\004" ) else: - result = __salt__["cmd.run"]( - "gluster --xml --mode=script", stdin="{}\n".format(cmd) - ) + result = __salt__["cmd.run"]("gluster --xml --mode=script", stdin=f"{cmd}\n") try: root = ET.fromstring(_gluster_output_cleanup(result)) @@ -206,9 +204,9 @@ def peer(name): """ if salt.utils.cloud.check_name(name, "a-zA-Z0-9._-"): - raise SaltInvocationError('Invalid characters in peer name "{}"'.format(name)) + raise SaltInvocationError(f'Invalid characters in peer name "{name}"') - cmd = "peer probe {}".format(name) + cmd = f"peer probe {name}" return _gluster(cmd) @@ -288,13 +286,9 @@ def create_volume( try: peer_name, path = brick.split(":") if not path.startswith("/"): - raise SaltInvocationError( - "Brick paths must start with / in {}".format(brick) - ) + raise SaltInvocationError(f"Brick paths must start with / in {brick}") except ValueError: - raise SaltInvocationError( - "Brick syntax is : got {}".format(brick) - ) + raise SaltInvocationError(f"Brick syntax is : got {brick}") # Validate arbiter config if arbiter and replica != 3: @@ -303,17 +297,17 @@ def create_volume( ) # Format creation call - cmd = "volume create {} ".format(name) + cmd = f"volume create {name} " if stripe: - cmd += "stripe {} ".format(stripe) + cmd += f"stripe {stripe} " if replica: - cmd += "replica {} ".format(replica) + cmd += f"replica {replica} " if arbiter: cmd += "arbiter 1 " if device_vg: cmd += "device vg " if transport != "tcp": - cmd += "transport {} ".format(transport) + cmd += f"transport {transport} " cmd += " ".join(bricks) if force: cmd += " force" @@ -358,7 +352,7 @@ def status(name): salt '*' glusterfs.status myvolume """ # Get volume status - root = _gluster_xml("volume status {}".format(name)) + root = _gluster_xml(f"volume status {name}") if not _gluster_ok(root): # Most probably non-existing volume, the error output is logged # This return value is easy to test and intuitive @@ -384,7 +378,7 @@ def status(name): hostname = node.find("hostname").text if hostname not in ("NFS Server", "Self-heal Daemon"): path = node.find("path").text - ret["bricks"]["{}:{}".format(hostname, path)] = etree_legacy_wrap(node) + ret["bricks"][f"{hostname}:{path}"] = etree_legacy_wrap(node) elif hostname == "NFS Server": peerid = node.find("peerid").text true_hostname = hostref[peerid] @@ -427,7 +421,7 @@ def info(name=None): bricks = {} for i, brick in enumerate(_iter(volume, "brick"), start=1): - brickkey = "brick{}".format(i) + brickkey = f"brick{i}" bricks[brickkey] = {"path": brick.text} for child in brick: if not child.tag == "name": @@ -461,9 +455,9 @@ def start_volume(name, force=False): salt '*' glusterfs.start mycluster """ - cmd = "volume start {}".format(name) + cmd = f"volume start {name}" if force: - cmd = "{} force".format(cmd) + cmd = f"{cmd} force" volinfo = info(name) if name not in volinfo: @@ -503,7 +497,7 @@ def stop_volume(name, force=False): log.warning("Attempt to stop already stopped volume %s", name) return True - cmd = "volume stop {}".format(name) + cmd = f"volume stop {name}" if force: cmd += " force" @@ -543,7 +537,7 @@ def delete_volume(target, stop=True): if not stop_volume(target, force=True): return False - cmd = "volume delete {}".format(target) + cmd = f"volume delete {target}" return _gluster(cmd) @@ -571,7 +565,7 @@ def add_volume_bricks(name, bricks): new_bricks = [] - cmd = "volume add-brick {}".format(name) + cmd = f"volume add-brick {name}" if isinstance(bricks, str): bricks = [bricks] @@ -588,7 +582,7 @@ def add_volume_bricks(name, bricks): if new_bricks: for brick in new_bricks: - cmd += " {}".format(brick) + cmd += f" {brick}" return _gluster(cmd) return True @@ -607,7 +601,7 @@ def enable_quota_volume(name): salt '*' glusterfs.enable_quota_volume """ - cmd = "volume quota {} enable".format(name) + cmd = f"volume quota {name} enable" if not _gluster(cmd): return False return True @@ -627,7 +621,7 @@ def disable_quota_volume(name): salt '*' glusterfs.disable_quota_volume """ - cmd = "volume quota {} disable".format(name) + cmd = f"volume quota {name} disable" if not _gluster(cmd): return False return True @@ -655,11 +649,11 @@ def set_quota_volume(name, path, size, enable_quota=False): salt '*' glusterfs.set_quota_volume enable_quota=True """ - cmd = "volume quota {}".format(name) + cmd = f"volume quota {name}" if path: - cmd += " limit-usage {}".format(path) + cmd += f" limit-usage {path}" if size: - cmd += " {}".format(size) + cmd += f" {size}" if enable_quota: if not enable_quota_volume(name): @@ -685,9 +679,9 @@ def unset_quota_volume(name, path): salt '*' glusterfs.unset_quota_volume """ - cmd = "volume quota {}".format(name) + cmd = f"volume quota {name}" if path: - cmd += " remove {}".format(path) + cmd += f" remove {path}" if not _gluster(cmd): return False @@ -707,7 +701,7 @@ def list_quota_volume(name): salt '*' glusterfs.list_quota_volume """ - cmd = "volume quota {}".format(name) + cmd = f"volume quota {name}" cmd += " list" root = _gluster_xml(cmd) @@ -738,7 +732,7 @@ def get_op_version(name): salt '*' glusterfs.get_op_version """ - cmd = "volume get {} cluster.op-version".format(name) + cmd = f"volume get {name} cluster.op-version" root = _gluster_xml(cmd) if not _gluster_ok(root): @@ -816,7 +810,7 @@ def set_op_version(version): salt '*' glusterfs.set_op_version """ - cmd = "volume set all cluster.op-version {}".format(version) + cmd = f"volume set all cluster.op-version {version}" root = _gluster_xml(cmd) if not _gluster_ok(root): diff --git a/salt/modules/gnomedesktop.py b/salt/modules/gnomedesktop.py index 2ae41dd1155..15553f5fe75 100644 --- a/salt/modules/gnomedesktop.py +++ b/salt/modules/gnomedesktop.py @@ -77,7 +77,7 @@ class _GSettings: cmd = self.gsetting_command + ["get", str(self.SCHEMA), str(self.KEY)] environ = {} - environ["XDG_RUNTIME_DIR"] = "/run/user/{}".format(uid) + environ["XDG_RUNTIME_DIR"] = f"/run/user/{uid}" result = __salt__["cmd.run_all"]( cmd, runas=user, env=environ, python_shell=False ) @@ -102,12 +102,12 @@ class _GSettings: log.info("User does not exist") result = {} result["retcode"] = 1 - result["stdout"] = "User {} does not exist".format(user) + result["stdout"] = f"User {user} does not exist" return result cmd = self.gsetting_command + ["set", self.SCHEMA, self.KEY, value] environ = {} - environ["XDG_RUNTIME_DIR"] = "/run/user/{}".format(uid) + environ["XDG_RUNTIME_DIR"] = f"/run/user/{uid}" result = __salt__["cmd.run_all"]( cmd, runas=user, env=environ, python_shell=False ) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index 14949e993c4..5f890bce193 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -121,7 +121,7 @@ def _get_user_info(user=None): # if it doesn't exist then fall back to user Salt running as userinfo = _get_user_info() else: - raise SaltInvocationError("User {} does not exist".format(user)) + raise SaltInvocationError(f"User {user} does not exist") return userinfo @@ -583,11 +583,11 @@ def delete_key( else: if str(__delete_key(fingerprint, True, use_passphrase)) == "ok": # Delete the secret key - ret["message"] = "Secret key for {} deleted\n".format(fingerprint) + ret["message"] = f"Secret key for {fingerprint} deleted\n" # Delete the public key if str(__delete_key(fingerprint, False, use_passphrase)) == "ok": - ret["message"] += "Public key for {} deleted".format(fingerprint) + ret["message"] += f"Public key for {fingerprint} deleted" ret["res"] = True return ret else: @@ -985,12 +985,12 @@ def trust_key(keyid=None, fingerprint=None, trust_level=None, user=None): if key: if "fingerprint" not in key: ret["res"] = False - ret["message"] = "Fingerprint not found for keyid {}".format(keyid) + ret["message"] = f"Fingerprint not found for keyid {keyid}" return ret fingerprint = key["fingerprint"] else: ret["res"] = False - ret["message"] = "KeyID {} not in GPG keychain".format(keyid) + ret["message"] = f"KeyID {keyid} not in GPG keychain" return ret else: ret["res"] = False @@ -1000,7 +1000,7 @@ def trust_key(keyid=None, fingerprint=None, trust_level=None, user=None): if trust_level not in _VALID_TRUST_LEVELS: return "ERROR: Valid trust levels - {}".format(",".join(_VALID_TRUST_LEVELS)) - stdin = "{}:{}\n".format(fingerprint, NUM_TRUST_DICT[trust_level]) + stdin = f"{fingerprint}:{NUM_TRUST_DICT[trust_level]}\n" cmd = [_gpg(), "--import-ownertrust"] _user = user @@ -1290,7 +1290,7 @@ def encrypt( if result.ok: if not bare: if output: - ret["comment"] = "Encrypted data has been written to {}".format(output) + ret["comment"] = f"Encrypted data has been written to {output}" else: ret["comment"] = result.data else: @@ -1378,7 +1378,7 @@ def decrypt( if result.ok: if not bare: if output: - ret["comment"] = "Decrypted data has been written to {}".format(output) + ret["comment"] = f"Decrypted data has been written to {output}" else: ret["comment"] = result.data else: diff --git a/salt/modules/grains.py b/salt/modules/grains.py index d803a209549..c9f9d1481d5 100644 --- a/salt/modules/grains.py +++ b/salt/modules/grains.py @@ -264,7 +264,7 @@ def setvals(grains, destructive=False, refresh_pillar=True): try: grains = salt.utils.yaml.safe_load(fp_) except salt.utils.yaml.YAMLError as exc: - return "Unable to read existing grains file: {}".format(exc) + return f"Unable to read existing grains file: {exc}" if not isinstance(grains, dict): grains = {} for key, val in new_grains.items(): @@ -360,9 +360,9 @@ def append(key, val, convert=False, delimiter=DEFAULT_TARGET_DELIM): if not isinstance(grains, list): grains = [] if grains is None else [grains] if not isinstance(grains, list): - return "The key {} is not a valid list".format(key) + return f"The key {key} is not a valid list" if val in grains: - return "The val {} was already in the list {}".format(val, key) + return f"The val {val} was already in the list {key}" if isinstance(val, list): for item in val: grains.append(item) @@ -407,9 +407,9 @@ def remove(key, val, delimiter=DEFAULT_TARGET_DELIM): """ grains = get(key, [], delimiter) if not isinstance(grains, list): - return "The key {} is not a valid list".format(key) + return f"The key {key} is not a valid list" if val not in grains: - return "The val {} was not in the list {}".format(val, key) + return f"The val {val} was not in the list {key}" grains.remove(val) while delimiter in key: diff --git a/salt/modules/groupadd.py b/salt/modules/groupadd.py index bc0db925b18..0a30ec3df9c 100644 --- a/salt/modules/groupadd.py +++ b/salt/modules/groupadd.py @@ -48,7 +48,7 @@ def _which(cmd): """ _cmd = salt.utils.path.which(cmd) if not _cmd: - raise CommandExecutionError("Command '{}' cannot be found".format(cmd)) + raise CommandExecutionError(f"Command '{cmd}' cannot be found") return _cmd @@ -83,7 +83,7 @@ def add(name, gid=None, system=False, root=None, non_unique=False): """ cmd = [_which("groupadd")] if gid: - cmd.append("-g {}".format(gid)) + cmd.append(f"-g {gid}") if non_unique: cmd.append("-o") if system and __grains__["kernel"] != "OpenBSD": @@ -349,11 +349,11 @@ def deluser(name, username, root=None): retcode = __salt__["cmd.retcode"](cmd, python_shell=False) elif __grains__["kernel"] == "OpenBSD": out = __salt__["cmd.run_stdout"]( - "id -Gn {}".format(username), python_shell=False + f"id -Gn {username}", python_shell=False ) cmd = [_which("usermod"), "-S"] cmd.append(",".join([g for g in out.split() if g != str(name)])) - cmd.append("{}".format(username)) + cmd.append(f"{username}") retcode = __salt__["cmd.retcode"](cmd, python_shell=False) else: log.error("group.deluser is not yet supported on this platform") @@ -459,7 +459,7 @@ def _getgrnam(name, root=None): comps[2] = int(comps[2]) comps[3] = comps[3].split(",") if comps[3] else [] return grp.struct_group(comps) - raise KeyError("getgrnam(): name not found: {}".format(name)) + raise KeyError(f"getgrnam(): name not found: {name}") def _getgrall(root=None): diff --git a/salt/modules/grub_legacy.py b/salt/modules/grub_legacy.py index 7bb46f8be9a..08851e7954a 100644 --- a/salt/modules/grub_legacy.py +++ b/salt/modules/grub_legacy.py @@ -75,14 +75,14 @@ def conf(): if line.startswith("\n"): in_stanza = False if "title" in stanza: - stanza += "order {}".format(pos) + stanza += f"order {pos}" pos += 1 stanzas.append(stanza) stanza = "" continue if line.strip().startswith("title"): if in_stanza: - stanza += "order {}".format(pos) + stanza += f"order {pos}" pos += 1 stanzas.append(stanza) stanza = "" @@ -97,7 +97,7 @@ def conf(): if not line.endswith("\n"): line += "\n" stanza += line - stanza += "order {}".format(pos) + stanza += f"order {pos}" pos += 1 stanzas.append(stanza) except OSError as exc: diff --git a/salt/modules/guestfs.py b/salt/modules/guestfs.py index 2395bd2a1c3..e802eadc614 100644 --- a/salt/modules/guestfs.py +++ b/salt/modules/guestfs.py @@ -67,7 +67,7 @@ def mount(location, access="rw", root=None): log.info("Path already existing: %s", root) else: break - cmd = "guestmount -i -a {} --{} {}".format(location, access, root) + cmd = f"guestmount -i -a {location} --{access} {root}" __salt__["cmd.run"](cmd, python_shell=False) return root @@ -82,7 +82,7 @@ def umount(name, disk=None): salt '*' guestfs.umount /mountpoint disk=/srv/images/fedora.qcow """ - cmd = "guestunmount -q {}".format(name) + cmd = f"guestunmount -q {name}" __salt__["cmd.run"](cmd) # Wait at most 5s that the disk is no longuer used @@ -90,7 +90,7 @@ def umount(name, disk=None): while ( disk is not None and loops < 5 - and len(__salt__["cmd.run"]("lsof {}".format(disk)).splitlines()) != 0 + and len(__salt__["cmd.run"](f"lsof {disk}").splitlines()) != 0 ): loops = loops + 1 time.sleep(1) diff --git a/salt/modules/haproxyconn.py b/salt/modules/haproxyconn.py index a7b0e31b89b..712eb018d06 100644 --- a/salt/modules/haproxyconn.py +++ b/salt/modules/haproxyconn.py @@ -47,9 +47,9 @@ def _get_conn(socket=DEFAULT_SOCKET_URL): """ Get connection to haproxy socket. """ - assert os.path.exists(socket), "{} does not exist.".format(socket) + assert os.path.exists(socket), f"{socket} does not exist." issock = os.stat(socket).st_mode - assert stat.S_ISSOCK(issock), "{} is not a socket.".format(socket) + assert stat.S_ISSOCK(issock), f"{socket} is not a socket." ha_conn = haproxy.conn.HaPConn(socket) return ha_conn diff --git a/salt/modules/hashutil.py b/salt/modules/hashutil.py index cdddadc8d45..3517f2512ac 100644 --- a/salt/modules/hashutil.py +++ b/salt/modules/hashutil.py @@ -38,7 +38,7 @@ def digest(instr, checksum="md5"): if hash_func is None: raise salt.exceptions.CommandExecutionError( - "Hash func '{}' is not supported.".format(checksum) + f"Hash func '{checksum}' is not supported." ) return hash_func(instr) @@ -62,9 +62,7 @@ def digest_file(infile, checksum="md5"): salt '*' hashutil.digest_file /path/to/file """ if not __salt__["file.file_exists"](infile): - raise salt.exceptions.CommandExecutionError( - "File path '{}' not found.".format(infile) - ) + raise salt.exceptions.CommandExecutionError(f"File path '{infile}' not found.") with salt.utils.files.fopen(infile, "rb") as f: file_hash = __salt__["hashutil.digest"](f.read(), checksum) diff --git a/salt/modules/heat.py b/salt/modules/heat.py index c4ea3a5e9e1..5a86b2b1fec 100644 --- a/salt/modules/heat.py +++ b/salt/modules/heat.py @@ -212,7 +212,7 @@ def _parse_environment(env_str): for param in env: if param not in SECTIONS: - raise ValueError('environment has wrong section "{}"'.format(param)) + raise ValueError(f'environment has wrong section "{param}"') return env @@ -240,7 +240,7 @@ def _poll_for_events( Polling stack events """ if action: - stop_status = ("{}_FAILED".format(action), "{}_COMPLETE".format(action)) + stop_status = (f"{action}_FAILED", f"{action}_COMPLETE") def stop_check(a): return a in stop_status @@ -287,7 +287,7 @@ def _poll_for_events( time.sleep(poll_period) timeout_sec -= poll_period if timeout_sec <= 0: - stack_status = "{}_FAILED".format(action) + stack_status = f"{action}_FAILED" msg = "Timeout expired" return stack_status, msg @@ -360,7 +360,7 @@ def show_stack(name=None, profile=None): } ret["result"] = True except heatclient.exc.HTTPNotFound: - return {"result": False, "comment": "No stack {}".format(name)} + return {"result": False, "comment": f"No stack {name}"} return ret @@ -397,7 +397,7 @@ def delete_stack(name=None, poll=0, timeout=60, profile=None): h_client.stacks.delete(name) except heatclient.exc.HTTPNotFound: ret["result"] = False - ret["comment"] = "No stack {}".format(name) + ret["comment"] = f"No stack {name}" except heatclient.exc.HTTPForbidden as forbidden: log.exception(forbidden) ret["result"] = False @@ -411,19 +411,19 @@ def delete_stack(name=None, poll=0, timeout=60, profile=None): h_client, name, action="DELETE", poll_period=poll, timeout=timeout ) except heatclient.exc.CommandError: - ret["comment"] = "Deleted stack {}.".format(name) + ret["comment"] = f"Deleted stack {name}." return ret except Exception as ex: # pylint: disable=W0703 log.exception("Delete failed %s", ex) ret["result"] = False - ret["comment"] = "{}".format(ex) + ret["comment"] = f"{ex}" return ret if stack_status == "DELETE_FAILED": ret["result"] = False - ret["comment"] = "Deleted stack FAILED'{}'{}.".format(name, msg) + ret["comment"] = f"Deleted stack FAILED'{name}'{msg}." else: - ret["comment"] = "Deleted stack {}.".format(name) + ret["comment"] = f"Deleted stack {name}." return ret @@ -529,7 +529,7 @@ def create_stack( template = _parse_template(tpl) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open template: {} {}".format( @@ -548,7 +548,7 @@ def create_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Template not valid %s", ex) ret["result"] = False - ret["comment"] = "Template not valid {}".format(ex) + ret["comment"] = f"Template not valid {ex}" return ret env = {} if environment: @@ -596,7 +596,7 @@ def create_stack( env = _parse_environment(env_str) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open environment: {}, {}".format( @@ -620,7 +620,7 @@ def create_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Create failed %s", ex) ret["result"] = False - ret["comment"] = "{}".format(ex) + ret["comment"] = f"{ex}" return ret if poll > 0: stack_status, msg = _poll_for_events( @@ -628,9 +628,9 @@ def create_stack( ) if stack_status == "CREATE_FAILED": ret["result"] = False - ret["comment"] = "Created stack FAILED'{}'{}.".format(name, msg) + ret["comment"] = f"Created stack FAILED'{name}'{msg}." if ret["result"] is True: - ret["comment"] = "Created stack '{}'.".format(name) + ret["comment"] = f"Created stack '{name}'." return ret @@ -740,7 +740,7 @@ def update_stack( template = _parse_template(tpl) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open template: {} {}".format( @@ -759,7 +759,7 @@ def update_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Template not valid %s", ex) ret["result"] = False - ret["comment"] = "Template not valid {}".format(ex) + ret["comment"] = f"Template not valid {ex}" return ret env = {} if environment: @@ -807,7 +807,7 @@ def update_stack( env = _parse_environment(env_str) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open environment: {}, {}".format( @@ -829,7 +829,7 @@ def update_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Update failed %s", ex) ret["result"] = False - ret["comment"] = "Update failed {}".format(ex) + ret["comment"] = f"Update failed {ex}" return ret if poll > 0: @@ -838,9 +838,9 @@ def update_stack( ) if stack_status == "UPDATE_FAILED": ret["result"] = False - ret["comment"] = "Updated stack FAILED'{}'{}.".format(name, msg) + ret["comment"] = f"Updated stack FAILED'{name}'{msg}." if ret["result"] is True: - ret["comment"] = ("Updated stack '{}'.".format(name),) + ret["comment"] = (f"Updated stack '{name}'.",) return ret @@ -867,9 +867,9 @@ def template_stack(name=None, profile=None): try: get_template = h_client.stacks.template(name) except heatclient.exc.HTTPNotFound: - return {"result": False, "comment": "No stack with {}".format(name)} + return {"result": False, "comment": f"No stack with {name}"} except heatclient.exc.BadRequest: - return {"result": False, "comment": "Bad request fot stack {}".format(name)} + return {"result": False, "comment": f"Bad request fot stack {name}"} if "heat_template_version" in get_template: template = salt.utils.yaml.safe_dump(get_template) else: diff --git a/salt/modules/hg.py b/salt/modules/hg.py index 855fe2f2cfa..9e1d9de6be1 100644 --- a/salt/modules/hg.py +++ b/salt/modules/hg.py @@ -22,7 +22,7 @@ def __virtual__(): def _ssh_flag(identity_path): - return ["--ssh", "ssh -i {}".format(identity_path)] + return ["--ssh", f"ssh -i {identity_path}"] def revision(cwd, rev="tip", short=False, user=None): @@ -47,7 +47,7 @@ def revision(cwd, rev="tip", short=False, user=None): salt '*' hg.revision /path/to/repo mybranch """ - cmd = ["hg", "id", "-i", "--debug" if not short else "", "-r", "{}".format(rev)] + cmd = ["hg", "id", "-i", "--debug" if not short else "", "-r", f"{rev}"] result = __salt__["cmd.run_all"](cmd, cwd=cwd, runas=user, python_shell=False) @@ -80,7 +80,7 @@ def describe(cwd, rev="tip", user=None): "hg", "log", "-r", - "{}".format(rev), + f"{rev}", "--template", "'{{latesttag}}-{{latesttagdistance}}-{{node|short}}'", ] @@ -124,16 +124,16 @@ def archive(cwd, output, rev="tip", fmt=None, prefix=None, user=None): cmd = [ "hg", "archive", - "{}".format(output), + f"{output}", "--rev", - "{}".format(rev), + f"{rev}", ] if fmt: cmd.append("--type") - cmd.append("{}".format(fmt)) + cmd.append(f"{fmt}") if prefix: cmd.append("--prefix") - cmd.append('"{}"'.format(prefix)) + cmd.append(f'"{prefix}"') return __salt__["cmd.run"](cmd, cwd=cwd, runas=user, python_shell=False) @@ -204,7 +204,7 @@ def update(cwd, rev, force=False, user=None): salt devserver1 hg.update /path/to/repo somebranch """ - cmd = ["hg", "update", "{}".format(rev)] + cmd = ["hg", "update", f"{rev}"] if force: cmd.append("-C") @@ -244,10 +244,10 @@ def clone(cwd, repository, opts=None, user=None, identity=None): salt '*' hg.clone /path/to/repo https://bitbucket.org/birkenfeld/sphinx """ - cmd = ["hg", "clone", "{}".format(repository), "{}".format(cwd)] + cmd = ["hg", "clone", f"{repository}", f"{cwd}"] if opts: for opt in opts.split(): - cmd.append("{}".format(opt)) + cmd.append(f"{opt}") if identity: cmd.extend(_ssh_flag(identity)) @@ -284,7 +284,7 @@ def status(cwd, opts=None, user=None): cmd = ["hg", "status"] if opts: for opt in opts.split(): - cmd.append("{}".format(opt)) + cmd.append(f"{opt}") out = __salt__["cmd.run_stdout"](cmd, cwd=cwd, runas=user, python_shell=False) types = { "M": "modified", diff --git a/salt/modules/highstate_doc.py b/salt/modules/highstate_doc.py index 9f0b89bffbf..a91f77b2afb 100644 --- a/salt/modules/highstate_doc.py +++ b/salt/modules/highstate_doc.py @@ -388,7 +388,7 @@ def _get_config(**kwargs): "note": None, } if "__salt__" in globals(): - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" config.update(__salt__["config.get"](config_key, {})) # pylint: disable=C0201 for k in set(config.keys()) & set(kwargs.keys()): @@ -437,7 +437,7 @@ def read_file(name): def render( jinja_template_text=None, jinja_template_function="highstate_doc.markdown_default_jinja_template", - **kwargs + **kwargs, ): """ Render highstate to a text format (default Markdown) @@ -573,13 +573,13 @@ def _format_markdown_system_file(filename, config): file_stats, whitelist=["user", "group", "mode", "uid", "gid", "size"] ) if y: - ret += "file stat {1}\n```\n{0}```\n".format(y, filename) + ret += f"file stat {filename}\n```\n{y}```\n" file_size = file_stats.get("size") if file_size <= config.get("max_render_file_size"): is_binary = True try: # TODO: this is linux only should find somthing portable - file_type = __salt__["cmd.shell"]("\\file -i '{}'".format(filename)) + file_type = __salt__["cmd.shell"](f"\\file -i '{filename}'") if "charset=binary" not in file_type: is_binary = False except Exception as ex: # pylint: disable=broad-except @@ -591,11 +591,11 @@ def _format_markdown_system_file(filename, config): with salt.utils.files.fopen(filename, "r") as f: file_data = salt.utils.stringutils.to_unicode(f.read()) file_data = _md_fix(file_data) - ret += "file data {1}\n```\n{0}\n```\n".format(file_data, filename) + ret += f"file data {filename}\n```\n{file_data}\n```\n" else: ret += "```\n{}\n```\n".format( "SKIPPED LARGE FILE!\nSet {}:max_render_file_size > {} to render.".format( - "{}.config".format(__virtualname__), file_size + f"{__virtualname__}.config", file_size ) ) return ret @@ -614,11 +614,11 @@ def _format_markdown_requisite(state, stateid, makelink=True): """ format requisite as a link users can click """ - fmt_id = "{}: {}".format(state, stateid) + fmt_id = f"{state}: {stateid}" if makelink: - return " * [{}](#{})\n".format(fmt_id, _format_markdown_link(fmt_id)) + return f" * [{fmt_id}](#{_format_markdown_link(fmt_id)})\n" else: - return " * `{}`\n".format(fmt_id) + return f" * `{fmt_id}`\n" def processor_markdown(lowstate_item, config, **kwargs): @@ -669,19 +669,19 @@ def processor_markdown(lowstate_item, config, **kwargs): if "source" in s: text = __salt__["cp.get_file_str"](s["source"]) if text: - details += "\n{}\n".format(text) + details += f"\n{text}\n" else: details += "\n{}\n".format("ERROR: opening {}".format(s["source"])) if state_function == "pkg.installed": pkgs = s.get("pkgs", s.get("name")) - details += "\n```\ninstall: {}\n```\n".format(pkgs) + details += f"\n```\ninstall: {pkgs}\n```\n" if state_function == "file.recurse": details += """recurse copy of files\n""" y = _state_data_to_yaml_string(s) if y: - details += "```\n{}\n```\n".format(y) + details += f"```\n{y}\n```\n" if "!doc_recurse" in id_full: findfiles = __salt__["file.find"](path=s.get("name"), type="f") if len(findfiles) < 10 or "!doc_recurse_force" in id_full: @@ -715,7 +715,7 @@ def processor_markdown(lowstate_item, config, **kwargs): if not details: y = _state_data_to_yaml_string(s) if y: - details += "```\n{}```\n".format(y) + details += f"```\n{y}```\n" r = { "vars": lowstate_item, diff --git a/salt/modules/hosts.py b/salt/modules/hosts.py index 83f60ab2050..267fe056ad5 100644 --- a/salt/modules/hosts.py +++ b/salt/modules/hosts.py @@ -58,7 +58,7 @@ def _list_hosts(): if not line: continue if line.startswith("#"): - ret.setdefault("comment-{}".format(count), []).append(line) + ret.setdefault(f"comment-{count}", []).append(line) count += 1 continue comment = None diff --git a/salt/modules/icinga2.py b/salt/modules/icinga2.py index e3e758d2259..391fb4abea7 100644 --- a/salt/modules/icinga2.py +++ b/salt/modules/icinga2.py @@ -70,9 +70,9 @@ def generate_cert(domain): "--cn", domain, "--key", - "{}{}.key".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.key", "--cert", - "{}{}.crt".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.crt", ], python_shell=False, ) @@ -99,11 +99,11 @@ def save_cert(domain, master): "pki", "save-cert", "--key", - "{}{}.key".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.key", "--cert", - "{}{}.cert".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.cert", "--trustedcert", - "{}trusted-master.crt".format(get_certs_path()), + f"{get_certs_path()}trusted-master.crt", "--host", master, ], @@ -139,13 +139,13 @@ def request_cert(domain, master, ticket, port): "--ticket", ticket, "--key", - "{}{}.key".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.key", "--cert", - "{}{}.crt".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.crt", "--trustedcert", - "{}trusted-master.crt".format(get_certs_path()), + f"{get_certs_path()}trusted-master.crt", "--ca", - "{}ca.crt".format(get_certs_path()), + f"{get_certs_path()}ca.crt", ], python_shell=False, ) @@ -181,7 +181,7 @@ def node_setup(domain, master, ticket): "--master_host", master, "--trustedcert", - "{}trusted-master.crt".format(get_certs_path()), + f"{get_certs_path()}trusted-master.crt", ], python_shell=False, ) diff --git a/salt/modules/ifttt.py b/salt/modules/ifttt.py index 248e059b87a..9126ab06b33 100644 --- a/salt/modules/ifttt.py +++ b/salt/modules/ifttt.py @@ -38,7 +38,7 @@ def _query(event=None, method="GET", args=None, header_dict=None, data=None): secret_key = __salt__["config.get"]("ifttt.secret_key") or __salt__["config.get"]( "ifttt:secret_key" ) - path = "https://maker.ifttt.com/trigger/{}/with/key/{}".format(event, secret_key) + path = f"https://maker.ifttt.com/trigger/{event}/with/key/{secret_key}" if header_dict is None: header_dict = {"Content-type": "application/json"} diff --git a/salt/modules/ilo.py b/salt/modules/ilo.py index c01e9da213c..c8d104fe797 100644 --- a/salt/modules/ilo.py +++ b/salt/modules/ilo.py @@ -47,7 +47,7 @@ def __execute_cmd(name, xml): tmpfilename = fh.name fh.write(xml) - cmd = __salt__["cmd.run_all"]("hponcfg -f {}".format(tmpfilename)) + cmd = __salt__["cmd.run_all"](f"hponcfg -f {tmpfilename}") # Clean up the temp file __salt__["file.remove"](tmpfilename) @@ -394,11 +394,7 @@ def create_user(name, password, *privileges): name, password, "\n".join( - [ - '<{} value="Y" />'.format(i.upper()) - for i in privileges - if i.upper() in _priv - ] + [f'<{i.upper()} value="Y" />' for i in privileges if i.upper() in _priv] ), ) diff --git a/salt/modules/incron.py b/salt/modules/incron.py index ad13c6de6e5..ad99b27aa3e 100644 --- a/salt/modules/incron.py +++ b/salt/modules/incron.py @@ -56,7 +56,7 @@ def _render_tab(lst): """ ret = [] for pre in lst["pre"]: - ret.append("{}\n".format(pre)) + ret.append(f"{pre}\n") for cron in lst["crons"]: ret.append( "{} {} {}\n".format( @@ -72,7 +72,7 @@ def _get_incron_cmdstr(path): """ Returns a format string, to be used to build an incrontab command. """ - return "incrontab {}".format(path) + return f"incrontab {path}" def write_incron_file(user, path): @@ -121,7 +121,7 @@ def _write_incron_lines(user, lines): with salt.utils.files.fopen(path, "wb") as fp_: fp_.writelines(salt.utils.data.encode(lines)) if user != "root": - __salt__["cmd.run"]("chown {} {}".format(user, path), python_shell=False) + __salt__["cmd.run"](f"chown {user} {path}", python_shell=False) ret = __salt__["cmd.run_all"]( _get_incron_cmdstr(path), runas=user, python_shell=False ) @@ -135,7 +135,7 @@ def _write_file(folder, filename, data): """ path = os.path.join(folder, filename) if not os.path.exists(folder): - msg = "{} cannot be written. {} does not exist".format(filename, folder) + msg = f"{filename} cannot be written. {folder} does not exist" log.error(msg) raise AttributeError(str(msg)) with salt.utils.files.fopen(path, "w") as fp_: @@ -180,7 +180,7 @@ def raw_incron(user): salt '*' incron.raw_incron root """ - cmd = "incrontab -l {}".format(user) + cmd = f"incrontab -l {user}" return __salt__["cmd.run_stdout"](cmd, rstrip=False, runas=user, python_shell=False) @@ -236,7 +236,7 @@ def set_job(user, path, mask, cmd): # Check for valid mask types for item in mask.split(","): if item not in _MASK_TYPES: - return "Invalid mask type: {}".format(item) + return f"Invalid mask type: {item}" updated = False arg_mask = mask.split(",") @@ -296,7 +296,7 @@ def rm_job(user, path, mask, cmd): # Check for valid mask types for item in mask.split(","): if item not in _MASK_TYPES: - return "Invalid mask type: {}".format(item) + return f"Invalid mask type: {item}" lst = list_tab(user) ret = "absent" diff --git a/salt/modules/influxdbmod.py b/salt/modules/influxdbmod.py index 4793e54c8be..c8c1689d5d4 100644 --- a/salt/modules/influxdbmod.py +++ b/salt/modules/influxdbmod.py @@ -66,7 +66,7 @@ def _client( influxdb_password=None, influxdb_host=None, influxdb_port=None, - **client_args + **client_args, ): if not influxdb_user: influxdb_user = __salt__["config.option"]("influxdb.user", "root") @@ -84,7 +84,7 @@ def _client( port=influxdb_port, username=influxdb_user, password=influxdb_password, - **client_args + **client_args, ) @@ -674,7 +674,7 @@ def drop_continuous_query(database, name, **client_args): """ client = _client(**client_args) - query = "DROP CONTINUOUS QUERY {} ON {}".format(name, database) + query = f"DROP CONTINUOUS QUERY {name} ON {database}" client.query(query) return True diff --git a/salt/modules/infoblox.py b/salt/modules/infoblox.py index a779b6322f9..14402e437d6 100644 --- a/salt/modules/infoblox.py +++ b/salt/modules/infoblox.py @@ -61,7 +61,7 @@ def _get_config(**api_opts): "api_key": "", } if "__salt__" in globals(): - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" config.update(__salt__["config.get"](config_key, {})) # pylint: disable=C0201 for k in set(config.keys()) & set(api_opts.keys()): @@ -143,7 +143,7 @@ def update_object(objref, data, **api_opts): salt-call infoblox.update_object objref=[ref_of_object] data={} """ if "__opts__" in globals() and __opts__["test"]: - return {"Test": "Would attempt to update object: {}".format(objref)} + return {"Test": f"Would attempt to update object: {objref}"} infoblox = _get_infoblox(**api_opts) return infoblox.update_object(objref, data) @@ -159,7 +159,7 @@ def delete_object(objref, **api_opts): salt-call infoblox.delete_object objref=[ref_of_object] """ if "__opts__" in globals() and __opts__["test"]: - return {"Test": "Would attempt to delete object: {}".format(objref)} + return {"Test": f"Would attempt to delete object: {objref}"} infoblox = _get_infoblox(**api_opts) return infoblox.delete_object(objref) @@ -175,7 +175,7 @@ def create_object(object_type, data, **api_opts): salt-call infoblox.update_object object_type=record:host data={} """ if "__opts__" in globals() and __opts__["test"]: - return {"Test": "Would attempt to create object: {}".format(object_type)} + return {"Test": f"Would attempt to create object: {object_type}"} infoblox = _get_infoblox(**api_opts) return infoblox.create_object(object_type, data) @@ -186,7 +186,7 @@ def get_object( return_fields=None, max_results=None, ensure_none_or_one_result=False, - **api_opts + **api_opts, ): """ Get raw infoblox object. This is a low level api call. diff --git a/salt/modules/ini_manage.py b/salt/modules/ini_manage.py index 70ce447f5b0..f5aff8881e2 100644 --- a/salt/modules/ini_manage.py +++ b/salt/modules/ini_manage.py @@ -417,7 +417,7 @@ class _Section(OrderedDict): # Match comments com_match = COM_REGX.match(opt_str) if com_match: - name = "#comment{}".format(comment_count) + name = f"#comment{comment_count}" self.com = com_match.group(1) comment_count += 1 self.update({name: opt_str}) @@ -441,7 +441,7 @@ class _Section(OrderedDict): self.update({name: value}) continue # Anything remaining is a mystery. - name = "#unknown{}".format(unknown_count) + name = f"#unknown{unknown_count}" self.update({name: opt_str}) unknown_count += 1 @@ -512,7 +512,7 @@ class _Section(OrderedDict): for name, value in self.items(): # Handle Comment Lines if COM_REGX.match(name): - yield "{}{}".format(value, os.linesep) + yield f"{value}{os.linesep}" # Handle Sections elif isinstance(value, _Section): sections_dict.update({name: value}) @@ -521,7 +521,7 @@ class _Section(OrderedDict): else: yield "{}{}{}{}".format( name, - " {} ".format(self.sep) if self.sep != " " else self.sep, + f" {self.sep} " if self.sep != " " else self.sep, value, os.linesep, ) @@ -583,7 +583,7 @@ class _Ini(_Section): except OSError as exc: if __opts__["test"] is False: raise CommandExecutionError( - "Unable to open file '{}'. Exception: {}".format(self.name, exc) + f"Unable to open file '{self.name}'. Exception: {exc}" ) if not inicontents: return @@ -620,7 +620,7 @@ class _Ini(_Section): outfile.writelines(ini_gen_list) except OSError as exc: raise CommandExecutionError( - "Unable to write file '{}'. Exception: {}".format(self.name, exc) + f"Unable to write file '{self.name}'. Exception: {exc}" ) @staticmethod diff --git a/salt/modules/inspectlib/collector.py b/salt/modules/inspectlib/collector.py index 735f74d67de..d92646c9fc3 100644 --- a/salt/modules/inspectlib/collector.py +++ b/salt/modules/inspectlib/collector.py @@ -406,7 +406,7 @@ class Inspector(EnvLoader): all_links = list() for entry_path in [pth for pth in (allowed or os.listdir("/")) if pth]: if entry_path[0] != "/": - entry_path = "/{}".format(entry_path) + entry_path = f"/{entry_path}" if entry_path in ignored or os.path.islink(entry_path): continue e_files, e_dirs, e_links = self._get_all_files(entry_path, *ignored) @@ -490,7 +490,7 @@ class Inspector(EnvLoader): Take a snapshot of the system. """ if mode not in self.MODE: - raise InspectorSnapshotException("Unknown mode: '{}'".format(mode)) + raise InspectorSnapshotException(f"Unknown mode: '{mode}'") if is_alive(self.pidfile): raise CommandExecutionError("Inspection already in progress.") @@ -500,7 +500,7 @@ class Inspector(EnvLoader): subprocess.run( [ "nice", - "-{}".format(priority), + f"-{priority}", "python", __file__, os.path.dirname(self.pidfile), @@ -596,7 +596,7 @@ if __name__ == "__main__": with salt.utils.files.fopen( os.path.join(pidfile, EnvLoader.PID_FILE), "w" ) as fp_: - fp_.write("{}\n".format(pid)) + fp_.write(f"{pid}\n") sys.exit(0) except OSError as ex: sys.exit(1) diff --git a/salt/modules/inspectlib/kiwiproc.py b/salt/modules/inspectlib/kiwiproc.py index 321dfa8ff68..d3947ff5b00 100644 --- a/salt/modules/inspectlib/kiwiproc.py +++ b/salt/modules/inspectlib/kiwiproc.py @@ -247,11 +247,11 @@ class KiwiExporter: descr = etree.SubElement(node, "description") author = etree.SubElement(descr, "author") - author.text = "salt.modules.node on {}".format(hostname) + author.text = f"salt.modules.node on {hostname}" contact = etree.SubElement(descr, "contact") - contact.text = "root@{}".format(hostname) + contact.text = f"root@{hostname}" specs = etree.SubElement(descr, "specification") - specs.text = "Rebuild of {}, based on Salt inspection.".format(hostname) + specs.text = f"Rebuild of {hostname}, based on Salt inspection." return descr diff --git a/salt/modules/inspectlib/query.py b/salt/modules/inspectlib/query.py index 4ba5417a185..d7f06eae565 100644 --- a/salt/modules/inspectlib/query.py +++ b/salt/modules/inspectlib/query.py @@ -35,7 +35,7 @@ class SysInfo: def __init__(self, systype): if systype.lower() == "solaris": - raise SIException("Platform {} not (yet) supported.".format(systype)) + raise SIException(f"Platform {systype} not (yet) supported.") def _grain(self, grain): """ @@ -47,7 +47,7 @@ class SysInfo: """ Get a size of a disk. """ - out = __salt__["cmd.run_all"]("df {}".format(device)) + out = __salt__["cmd.run_all"](f"df {device}") if out["retcode"]: msg = "Disk size info error: {}".format(out["stderr"]) log.error(msg) @@ -464,13 +464,13 @@ class Query(EnvLoader): fmt = fmt.lower() if fmt == "b": - return "{} Bytes".format(size) + return f"{size} Bytes" elif fmt == "kb": - return "{} Kb".format(round((float(size) / 0x400), 2)) + return f"{round((float(size) / 0x400), 2)} Kb" elif fmt == "mb": - return "{} Mb".format(round((float(size) / 0x400 / 0x400), 2)) + return f"{round((float(size) / 0x400 / 0x400), 2)} Mb" elif fmt == "gb": - return "{} Gb".format(round((float(size) / 0x400 / 0x400 / 0x400), 2)) + return f"{round((float(size) / 0x400 / 0x400 / 0x400), 2)} Gb" filter = kwargs.get("filter") offset = kwargs.get("offset", 0) @@ -478,7 +478,7 @@ class Query(EnvLoader): timeformat = kwargs.get("time", "tz") if timeformat not in ["ticks", "tz"]: raise InspectorQueryException( - 'Unknown "{}" value for parameter "time"'.format(timeformat) + f'Unknown "{timeformat}" value for parameter "time"' ) def tfmt(param): diff --git a/salt/modules/inspector.py b/salt/modules/inspector.py index 02162cb564c..2d549e353a6 100644 --- a/salt/modules/inspector.py +++ b/salt/modules/inspector.py @@ -51,7 +51,7 @@ def _(module): import importlib - mod = importlib.import_module("salt.modules.inspectlib.{}".format(module)) + mod = importlib.import_module(f"salt.modules.inspectlib.{module}") mod.__grains__ = __grains__ mod.__pillar__ = __pillar__ mod.__salt__ = __salt__ diff --git a/salt/modules/iosconfig.py b/salt/modules/iosconfig.py index be0b58a5bd6..75d40756aee 100644 --- a/salt/modules/iosconfig.py +++ b/salt/modules/iosconfig.py @@ -166,7 +166,7 @@ def tree(config=None, path=None, with_tags=False, saltenv="base"): if path: config = __salt__["cp.get_file_str"](path, saltenv=saltenv) if config is False: - raise SaltException("{} is not available".format(path)) + raise SaltException(f"{path} is not available") config_lines = config.splitlines() return _parse_text_config(config_lines, with_tags=with_tags) diff --git a/salt/modules/ipmi.py b/salt/modules/ipmi.py index 3e5cf05723f..133b1161c6a 100644 --- a/salt/modules/ipmi.py +++ b/salt/modules/ipmi.py @@ -57,7 +57,7 @@ def _get_config(**kwargs): "api_login_timeout": 2, } if "__salt__" in globals(): - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" config.update(__salt__["config.get"](config_key, {})) for k in set(config) & set(kwargs): config[k] = kwargs[k] @@ -197,7 +197,7 @@ def set_channel_access( access_mode="always", privilege_update_mode="non_volatile", privilege_level="administrator", - **kwargs + **kwargs, ): """ Set channel access @@ -387,7 +387,7 @@ def set_user_access( link_auth=True, ipmi_msg=True, privilege_level="administrator", - **kwargs + **kwargs, ): """ Set user access @@ -896,7 +896,7 @@ def create_user( link_auth=True, ipmi_msg=True, privilege_level="administrator", - **kwargs + **kwargs, ): """ create/ensure a user is created with provided settings. diff --git a/salt/modules/ipset.py b/salt/modules/ipset.py index 35401c11529..b666bd0957e 100644 --- a/salt/modules/ipset.py +++ b/salt/modules/ipset.py @@ -314,7 +314,7 @@ def new_set(name=None, set_type=None, family="ipv4", comment=False, **kwargs): # Check for required arguments for item in _CREATE_OPTIONS_REQUIRED[set_type]: if item not in kwargs: - return "Error: {} is a required argument".format(item) + return f"Error: {item} is a required argument" cmd = [_ipset_cmd(), "create", name, set_type] @@ -477,7 +477,7 @@ def add(name=None, entry=None, family="ipv4", **kwargs): setinfo = _find_set_info(name) if not setinfo: - return "Error: Set {} does not exist".format(name) + return f"Error: Set {name} does not exist" settype = setinfo["Type"] @@ -485,21 +485,21 @@ def add(name=None, entry=None, family="ipv4", **kwargs): if "timeout" in kwargs: if "timeout" not in setinfo["Header"]: - return "Error: Set {} not created with timeout support".format(name) + return f"Error: Set {name} not created with timeout support" if "packets" in kwargs or "bytes" in kwargs: if "counters" not in setinfo["Header"]: - return "Error: Set {} not created with counters support".format(name) + return f"Error: Set {name} not created with counters support" if "comment" in kwargs: if "comment" not in setinfo["Header"]: - return "Error: Set {} not created with comment support".format(name) + return f"Error: Set {name} not created with comment support" if "comment" not in entry: cmd = cmd + ["comment", f"{kwargs['comment']}"] if {"skbmark", "skbprio", "skbqueue"} & set(kwargs.keys()): if "skbinfo" not in setinfo["Header"]: - return "Error: Set {} not created with skbinfo support".format(name) + return f"Error: Set {name} not created with skbinfo support" for item in _ADD_OPTIONS[settype]: if item in kwargs: @@ -507,14 +507,14 @@ def add(name=None, entry=None, family="ipv4", **kwargs): current_members = _find_set_members(name) if entry in current_members: - return "Warn: Entry {} already exists in set {}".format(entry, name) + return f"Warn: Entry {entry} already exists in set {name}" # Using -exist to ensure entries are updated if the comment changes out = __salt__["cmd.run"](cmd, python_shell=False) if not out: return "Success" - return "Error: {}".format(out) + return f"Error: {out}" def delete(name=None, entry=None, family="ipv4", **kwargs): @@ -536,14 +536,14 @@ def delete(name=None, entry=None, family="ipv4", **kwargs): settype = _find_set_type(name) if not settype: - return "Error: Set {} does not exist".format(name) + return f"Error: Set {name} does not exist" cmd = [_ipset_cmd(), "del", name, entry] out = __salt__["cmd.run"](cmd, python_shell=False) if not out: return "Success" - return "Error: {}".format(out) + return f"Error: {out}" def check(name=None, entry=None, family="ipv4"): @@ -580,7 +580,7 @@ def check(name=None, entry=None, family="ipv4"): settype = _find_set_type(name) if not settype: - return "Error: Set {} does not exist".format(name) + return f"Error: Set {name} does not exist" current_members = _parse_members(settype, _find_set_members(name)) @@ -620,7 +620,7 @@ def test(name=None, entry=None, family="ipv4", **kwargs): settype = _find_set_type(name) if not settype: - return "Error: Set {} does not exist".format(name) + return f"Error: Set {name} does not exist" cmd = [_ipset_cmd(), "test", name, entry] out = __salt__["cmd.run_all"](cmd, python_shell=False) diff --git a/salt/modules/iwtools.py b/salt/modules/iwtools.py index 353fea5ea28..d22b16133f1 100644 --- a/salt/modules/iwtools.py +++ b/salt/modules/iwtools.py @@ -36,10 +36,10 @@ def scan(iface, style=None): if not _valid_iface(iface): raise SaltInvocationError("The interface specified is not valid") - out = __salt__["cmd.run"]("iwlist {} scan".format(iface)) + out = __salt__["cmd.run"](f"iwlist {iface} scan") if "Network is down" in out: - __salt__["cmd.run"]("ip link set {} up".format(iface)) - out = __salt__["cmd.run"]("iwlist {} scan".format(iface)) + __salt__["cmd.run"](f"ip link set {iface} up") + out = __salt__["cmd.run"](f"iwlist {iface} scan") ret = {} tmp = {} for line in out.splitlines(): @@ -101,7 +101,7 @@ def set_mode(iface, mode): ) ) __salt__["ip.down"](iface) - out = __salt__["cmd.run"]("iwconfig {} mode {}".format(iface, mode)) + out = __salt__["cmd.run"](f"iwconfig {iface} mode {mode}") __salt__["ip.up"](iface) return mode diff --git a/salt/modules/jboss7.py b/salt/modules/jboss7.py index e68621ced11..1651da7ea8f 100644 --- a/salt/modules/jboss7.py +++ b/salt/modules/jboss7.py @@ -90,7 +90,7 @@ def stop_server(jboss_config, host=None): if host is None: operation = ":shutdown" else: - operation = '/host="{host}"/:shutdown'.format(host=host) + operation = f'/host="{host}"/:shutdown' shutdown_result = __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False ) @@ -129,7 +129,7 @@ def reload_(jboss_config, host=None): if host is None: operation = ":reload" else: - operation = '/host="{host}"/:reload'.format(host=host) + operation = f'/host="{host}"/:reload' reload_result = __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False ) @@ -194,7 +194,7 @@ def create_datasource(jboss_config, name, datasource_properties, profile=None): ), ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False @@ -213,7 +213,7 @@ def __get_properties_assignment_string(datasource_properties, ds_resource_descri def __get_single_assignment_string(key, val, ds_attributes): - return "{}={}".format(key, __format_value(key, val, ds_attributes)) + return f"{key}={__format_value(key, val, ds_attributes)}" def __format_value(key, value, ds_attributes): @@ -227,18 +227,14 @@ def __format_value(key, value, ds_attributes): else: return "false" else: - raise Exception( - "Don't know how to convert {} to BOOLEAN type".format(value) - ) + raise Exception(f"Don't know how to convert {value} to BOOLEAN type") elif type_ == "INT": return str(value) elif type_ == "STRING": - return '"{}"'.format(value) + return f'"{value}"' else: - raise Exception( - "Don't know how to format value {} of type {}".format(value, type_) - ) + raise Exception(f"Don't know how to format value {value} of type {type_}") def update_datasource(jboss_config, name, new_properties, profile=None): @@ -315,7 +311,7 @@ def __get_datasource_resource_description(jboss_config, name, profile=None): ) ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation operation_result = __salt__["jboss7_cli.run_operation"](jboss_config, operation) if operation_result["outcome"]: return operation_result["result"] @@ -381,7 +377,7 @@ def create_simple_binding(jboss_config, binding_name, value, profile=None): ) ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -418,7 +414,7 @@ def update_simple_binding(jboss_config, binding_name, value, profile=None): ) ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -452,7 +448,7 @@ def __read_simple_binding(jboss_config, binding_name, profile=None): binding_name=binding_name ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -474,7 +470,7 @@ def __update_datasource_property( value=__format_value(name, value, ds_attributes), ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False @@ -487,7 +483,7 @@ def __read_datasource(jboss_config, name, profile=None): name=name ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation operation_result = __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -524,9 +520,9 @@ def remove_datasource(jboss_config, name, profile=None): profile, ) - operation = "/subsystem=datasources/data-source={name}:remove".format(name=name) + operation = f"/subsystem=datasources/data-source={name}:remove" if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False @@ -552,7 +548,7 @@ def deploy(jboss_config, source_file): "======================== MODULE FUNCTION: jboss7.deploy, source_file=%s", source_file, ) - command = "deploy {source_file} --force ".format(source_file=source_file) + command = f"deploy {source_file} --force " return __salt__["jboss7_cli.run_command"]( jboss_config, command, fail_on_error=False ) @@ -600,5 +596,5 @@ def undeploy(jboss_config, deployment): "======================== MODULE FUNCTION: jboss7.undeploy, deployment=%s", deployment, ) - command = "undeploy {deployment} ".format(deployment=deployment) + command = f"undeploy {deployment} " return __salt__["jboss7_cli.run_command"](jboss_config, command) diff --git a/salt/modules/jboss7_cli.py b/salt/modules/jboss7_cli.py index 183d32998f2..bd0d7111e8e 100644 --- a/salt/modules/jboss7_cli.py +++ b/salt/modules/jboss7_cli.py @@ -158,7 +158,7 @@ def _call_cli(jboss_config, command, retries=1): command_segments.append('--user="{}"'.format(jboss_config["cli_user"])) if "cli_password" in jboss_config.keys(): command_segments.append('--password="{}"'.format(jboss_config["cli_password"])) - command_segments.append('--command="{}"'.format(__escape_command(command))) + command_segments.append(f'--command="{__escape_command(command)}"') cli_script = " ".join(command_segments) cli_command_result = __salt__["cmd.run_all"](cli_script) @@ -336,7 +336,7 @@ def __process_tokens_internal(tokens, start_at=0): log.debug(" TYPE: EXPRESSION") is_expression = True else: - raise CommandExecutionError("Unknown token! Token: {}".format(token)) + raise CommandExecutionError(f"Unknown token! Token: {token}") token_no = token_no + 1 diff --git a/salt/modules/jenkinsmod.py b/salt/modules/jenkinsmod.py index 46308a2062f..3d504d9f5c8 100644 --- a/salt/modules/jenkinsmod.py +++ b/salt/modules/jenkinsmod.py @@ -108,7 +108,7 @@ def _retrieve_config_xml(config_xml, saltenv): ret = __salt__["cp.cache_file"](config_xml, saltenv) if not ret: - raise CommandExecutionError("Failed to retrieve {}".format(config_xml)) + raise CommandExecutionError(f"Failed to retrieve {config_xml}") return ret @@ -219,7 +219,7 @@ def get_job_info(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") job_info = server.get_job_info(name) if job_info: @@ -248,14 +248,12 @@ def build_job(name=None, parameters=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist.".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist.") try: server.build_job(name, parameters) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error building job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error building job '{name}': {err}") return True @@ -281,7 +279,7 @@ def create_job(name=None, config_xml=None, saltenv="base"): raise SaltInvocationError("Required parameter 'name' is missing") if job_exists(name): - raise CommandExecutionError("Job '{}' already exists".format(name)) + raise CommandExecutionError(f"Job '{name}' already exists") if not config_xml: config_xml = jenkins.EMPTY_CONFIG_XML @@ -295,9 +293,7 @@ def create_job(name=None, config_xml=None, saltenv="base"): try: server.create_job(name, config_xml) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error creating job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error creating job '{name}': {err}") return config_xml @@ -334,9 +330,7 @@ def update_job(name=None, config_xml=None, saltenv="base"): try: server.reconfig_job(name, config_xml) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error updating job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error updating job '{name}': {err}") return config_xml @@ -360,14 +354,12 @@ def delete_job(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") try: server.delete_job(name) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error deleting job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error deleting job '{name}': {err}") return True @@ -391,14 +383,12 @@ def enable_job(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") try: server.enable_job(name) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error enabling job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error enabling job '{name}': {err}") return True @@ -423,14 +413,12 @@ def disable_job(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") try: server.disable_job(name) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error disabling job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error disabling job '{name}': {err}") return True @@ -455,7 +443,7 @@ def job_status(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") return server.get_job_info("empty")["buildable"] @@ -481,7 +469,7 @@ def get_job_config(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") job_info = server.get_job_config(name) return job_info diff --git a/salt/modules/junos.py b/salt/modules/junos.py index e2afa164f78..f368f28cd36 100644 --- a/salt/modules/junos.py +++ b/salt/modules/junos.py @@ -255,7 +255,7 @@ def facts_refresh(): try: conn.facts_refresh() except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Execution failed due to "{}"'.format(exception) + ret["message"] = f'Execution failed due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -286,7 +286,7 @@ def facts(): ret["facts"] = __proxy__["junos.get_serialized_facts"]() ret["out"] = True except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not display facts due to "{}"'.format(exception) + ret["message"] = f'Could not display facts due to "{exception}"' ret["out"] = False _restart_connection() @@ -362,7 +362,7 @@ def rpc(cmd=None, dest=None, **kwargs): try: filter_reply = etree.XML(op["filter"]) except etree.XMLSyntaxError as ex: - ret["message"] = "Invalid filter: {}".format(str(ex)) + ret["message"] = f"Invalid filter: {str(ex)}" ret["out"] = False return ret @@ -372,7 +372,7 @@ def rpc(cmd=None, dest=None, **kwargs): try: reply = getattr(conn.rpc, cmd.replace("-", "_"))(filter_reply, options=op) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'RPC execution failed due to "{}"'.format(exception) + ret["message"] = f'RPC execution failed due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -386,7 +386,7 @@ def rpc(cmd=None, dest=None, **kwargs): try: reply = getattr(conn.rpc, cmd.replace("-", "_"))({"format": format_}, **op) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'RPC execution failed due to "{}"'.format(exception) + ret["message"] = f'RPC execution failed due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -453,7 +453,7 @@ def set_hostname(hostname=None, **kwargs): # Added to recent versions of JunOs # Use text format instead - set_string = "set system host-name {}".format(hostname) + set_string = f"set system host-name {hostname}" try: conn.cu.load(set_string, format="set") except Exception as exception: # pylint: disable=broad-except @@ -467,7 +467,7 @@ def set_hostname(hostname=None, **kwargs): try: commit_ok = conn.cu.commit_check() except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not commit check due to error "{}"'.format(exception) + ret["message"] = f'Could not commit check due to error "{exception}"' ret["out"] = False _restart_connection() return ret @@ -560,7 +560,7 @@ def commit(**kwargs): try: commit_ok = conn.cu.commit_check() except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not perform commit check due to "{}"'.format(exception) + ret["message"] = f'Could not perform commit check due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -672,7 +672,7 @@ def rollback(**kwargs): try: ret["out"] = conn.cu.rollback(id_) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Rollback failed due to "{}"'.format(exception) + ret["message"] = f'Rollback failed due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -697,7 +697,7 @@ def rollback(**kwargs): try: commit_ok = conn.cu.commit_check() except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not commit check due to "{}"'.format(exception) + ret["message"] = f'Could not commit check due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -770,7 +770,7 @@ def diff(**kwargs): try: ret["message"] = conn.cu.diff(rb_id=id_) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not get diff with error "{}"'.format(exception) + ret["message"] = f'Could not get diff with error "{exception}"' ret["out"] = False _restart_connection() @@ -835,7 +835,7 @@ def ping(dest_ip=None, **kwargs): try: ret["message"] = jxmlease.parse(etree.tostring(conn.rpc.ping(**op))) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Execution failed due to "{}"'.format(exception) + ret["message"] = f'Execution failed due to "{exception}"' ret["out"] = False _restart_connection() @@ -892,7 +892,7 @@ def cli(command=None, **kwargs): try: result = conn.cli(command, format_, warning=False) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Execution failed due to "{}"'.format(exception) + ret["message"] = f'Execution failed due to "{exception}"' ret["out"] = False _restart_connection() return ret @@ -985,7 +985,7 @@ def shutdown(**kwargs): ret["message"] = "Successfully powered off/rebooted." ret["out"] = True except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not poweroff/reboot because "{}"'.format(exception) + ret["message"] = f'Could not poweroff/reboot because "{exception}"' ret["out"] = False _restart_connection() @@ -1154,7 +1154,7 @@ def install_config(path=None, **kwargs): cu.load(**op) except Exception as exception: # pylint: disable=broad-except ret["message"] = ( - 'Could not load configuration due to : "{}"'.format(exception) + f'Could not load configuration due to : "{exception}"' ) ret["format"] = op["format"] ret["out"] = False @@ -1249,12 +1249,12 @@ def install_config(path=None, **kwargs): fp.write(salt.utils.stringutils.to_str(config_diff)) except Exception as exception: # pylint: disable=broad-except ret["message"] = ( - "Could not write into diffs_file due to: '{}'".format(exception) + f"Could not write into diffs_file due to: '{exception}'" ) ret["out"] = False except ValueError as ex: - message = "install_config failed due to: {}".format(str(ex)) + message = f"install_config failed due to: {str(ex)}" log.error(message) ret["message"] = message ret["out"] = False @@ -1263,12 +1263,12 @@ def install_config(path=None, **kwargs): ret["message"] = ex.message ret["out"] = False except RpcTimeoutError as ex: - message = "install_config failed due to timeout error : {}".format(str(ex)) + message = f"install_config failed due to timeout error : {str(ex)}" log.error(message) ret["message"] = message ret["out"] = False except Exception as exc: # pylint: disable=broad-except - ret["message"] = "install_config failed due to exception: '{}'".format(exc) + ret["message"] = f"install_config failed due to exception: '{exc}'" ret["out"] = False return ret @@ -1299,7 +1299,7 @@ def zeroize(): conn.cli("request system zeroize") ret["message"] = "Completed zeroize and rebooted" except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not zeroize due to : "{}"'.format(exception) + ret["message"] = f'Could not zeroize due to : "{exception}"' ret["out"] = False _restart_connection() @@ -1429,7 +1429,7 @@ def install_os(path=None, **kwargs): image_path, progress=True, timeout=timeout, **op ) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Installation failed due to: "{}"'.format(exception) + ret["message"] = f'Installation failed due to: "{exception}"' ret["out"] = False __proxy__["junos.reboot_clear"]() _restart_connection() @@ -1440,7 +1440,7 @@ def install_os(path=None, **kwargs): path, progress=True, timeout=timeout, **op ) except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Installation failed due to: "{}"'.format(exception) + ret["message"] = f'Installation failed due to: "{exception}"' ret["out"] = False __proxy__["junos.reboot_clear"]() _restart_connection() @@ -1450,7 +1450,7 @@ def install_os(path=None, **kwargs): ret["out"] = True ret["message"] = "Installed the os." else: - ret["message"] = "Installation failed. Reason: {}".format(install_message) + ret["message"] = f"Installation failed. Reason: {install_message}" ret["out"] = False __proxy__["junos.reboot_clear"]() return ret @@ -1517,16 +1517,16 @@ def file_copy(src, dest): with HandleFileCopy(src) as fp: if fp is None: - ret["message"] = "Invalid source file path {}".format(src) + ret["message"] = f"Invalid source file path {src}" ret["out"] = False return ret try: with SCP(conn, progress=True) as scp: scp.put(fp, dest) - ret["message"] = "Successfully copied file from {} to {}".format(src, dest) + ret["message"] = f"Successfully copied file from {src} to {dest}" except Exception as exception: # pylint: disable=broad-except - ret["message"] = 'Could not copy file : "{}"'.format(exception) + ret["message"] = f'Could not copy file : "{exception}"' ret["out"] = False return ret @@ -1557,12 +1557,12 @@ def lock(): conn.cu.lock() ret["message"] = "Successfully locked the configuration." except RpcTimeoutError as exception: - ret["message"] = 'Could not gain lock due to : "{}"'.format(exception) + ret["message"] = f'Could not gain lock due to : "{exception}"' ret["out"] = False _restart_connection() except LockError as exception: - ret["message"] = 'Could not gain lock due to : "{}"'.format(exception) + ret["message"] = f'Could not gain lock due to : "{exception}"' ret["out"] = False return ret @@ -1767,7 +1767,7 @@ def commit_check(): conn.cu.commit_check() ret["message"] = "Commit check succeeded." except Exception as exception: # pylint: disable=broad-except - ret["message"] = "Commit check failed with {}".format(exception) + ret["message"] = f"Commit check failed with {exception}" ret["out"] = False _restart_connection() @@ -1844,9 +1844,9 @@ def get_table( pyez_tables_path = os.path.dirname(os.path.abspath(tables_dir.__file__)) try: if path is not None: - file_path = os.path.join(path, "{}".format(table_file)) + file_path = os.path.join(path, f"{table_file}") else: - file_path = os.path.join(pyez_tables_path, "{}".format(table_file)) + file_path = os.path.join(pyez_tables_path, f"{table_file}") with HandleFileCopy(file_path) as file_loc: if file_loc is None: @@ -1923,7 +1923,7 @@ def get_table( _restart_connection() return ret except Exception as err: # pylint: disable=broad-except - ret["message"] = "Uncaught exception - please report: {}".format(str(err)) + ret["message"] = f"Uncaught exception - please report: {str(err)}" ret["out"] = False _restart_connection() return ret @@ -2091,9 +2091,7 @@ def file_compare(file1, file2, **kwargs): # pragma: no cover if not junos_cli: return {"success": False, "message": "Cannot find Junos cli command"} - cliret = __salt__["cmd.run"]( - "{} file compare files {} {} ".format(junos_cli, file1, file2) - ) + cliret = __salt__["cmd.run"](f"{junos_cli} file compare files {file1} {file2} ") clilines = cliret.splitlines() for r in clilines: @@ -2147,7 +2145,7 @@ def fsentry_exists(dir, **kwargs): # pragma: no cover if not junos_cli: return {"success": False, "message": "Cannot find Junos cli command"} - ret = __salt__["cmd.run"]("{} file show {}".format(junos_cli, dir)) + ret = __salt__["cmd.run"](f"{junos_cli} file show {dir}") retlines = ret.splitlines() exists = True is_dir = False @@ -2168,7 +2166,7 @@ def _find_routing_engines(): if not junos_cli: return {"success": False, "message": "Cannot find Junos cli command"} - re_check = __salt__["cmd.run"]("{} show chassis routing-engine".format(junos_cli)) + re_check = __salt__["cmd.run"](f"{junos_cli} show chassis routing-engine") engine_present = True engine = {} @@ -2336,9 +2334,7 @@ def dir_copy(source, dest, force=False, **kwargs): # pragma: no cover target = dest + d status = fsentry_exists(target) if not status["exists"]: - ret = __salt__["cmd.run"]( - "{} file make-directory {}".format(junos_cli, target) - ) + ret = __salt__["cmd.run"](f"{junos_cli} file make-directory {target}") ret = ret_messages + ret else: ret_messages = ret_messages + "Directory " + target + " already exists.\n" @@ -2348,14 +2344,12 @@ def dir_copy(source, dest, force=False, **kwargs): # pragma: no cover comp_result = file_compare(f, target) if not comp_result["identical"] or force: - ret = __salt__["cmd.run"]( - "{} file copy {} {}".format(junos_cli, f, target) - ) + ret = __salt__["cmd.run"](f"{junos_cli} file copy {f} {target}") ret = ret_messages + ret else: ret_messages = ( ret_messages - + "Files {} and {} are identical, not copying.\n".format(f, target) + + f"Files {f} and {target} are identical, not copying.\n" ) return ret_messages diff --git a/salt/modules/k8s.py b/salt/modules/k8s.py index c62d1c79ebc..026cf6e1395 100644 --- a/salt/modules/k8s.py +++ b/salt/modules/k8s.py @@ -174,14 +174,14 @@ def _guess_node_id(node): def _get_labels(node, apiserver_url): """Get all labels from a kube node.""" # Prepare URL - url = "{}/api/v1/nodes/{}".format(apiserver_url, node) + url = f"{apiserver_url}/api/v1/nodes/{node}" # Make request ret = http.query(url) # Check requests status if "body" in ret: ret = salt.utils.json.loads(ret.get("body")) elif ret.get("status", 0) == 404: - return "Node {} doesn't exist".format(node) + return f"Node {node} doesn't exist" else: return ret # Get and return labels @@ -191,13 +191,13 @@ def _get_labels(node, apiserver_url): def _set_labels(node, apiserver_url, labels): """Replace labels dict by a new one""" # Prepare URL - url = "{}/api/v1/nodes/{}".format(apiserver_url, node) + url = f"{apiserver_url}/api/v1/nodes/{node}" # Prepare data data = [{"op": "replace", "path": "/metadata/labels", "value": labels}] # Make request ret = _kpatch(url, data) if ret.get("status") == 404: - return "Node {} doesn't exist".format(node) + return f"Node {node} doesn't exist" return ret @@ -264,9 +264,9 @@ def label_present(name, value, node=None, apiserver_url=None): # there is an update during operation, need to retry log.debug("Got 409, will try later") ret["changes"] = {} - ret["comment"] = "Could not create label {}, please retry".format(name) + ret["comment"] = f"Could not create label {name}, please retry" else: - ret["comment"] = "Label {} created".format(name) + ret["comment"] = f"Label {name} created" elif labels.get(name) != str(value): # This is a old label and we are going to edit it ret["changes"] = {name: str(value)} @@ -276,12 +276,12 @@ def label_present(name, value, node=None, apiserver_url=None): # there is an update during operation, need to retry log.debug("Got 409, will try later") ret["changes"] = {} - ret["comment"] = "Could not update label {}, please retry".format(name) + ret["comment"] = f"Could not update label {name}, please retry" else: - ret["comment"] = "Label {} updated".format(name) + ret["comment"] = f"Label {name} updated" else: # This is a old label and it has already the wanted value - ret["comment"] = "Label {} already set".format(name) + ret["comment"] = f"Label {name} already set" return ret @@ -316,7 +316,7 @@ def label_absent(name, node=None, apiserver_url=None): # Compare old labels and what we want if labels == old_labels: # Label already absent - ret["comment"] = "Label {} already absent".format(name) + ret["comment"] = f"Label {name} already absent" else: # Label needs to be delete res = _set_labels(node, apiserver_url, labels) @@ -324,10 +324,10 @@ def label_absent(name, node=None, apiserver_url=None): # there is an update during operation, need to retry log.debug("Got 409, will try later") ret["changes"] = {} - ret["comment"] = "Could not delete label {}, please retry".format(name) + ret["comment"] = f"Could not delete label {name}, please retry" else: ret["changes"] = {"deleted": name} - ret["comment"] = "Label {} absent".format(name) + ret["comment"] = f"Label {name} absent" return ret @@ -365,7 +365,7 @@ def label_folder_absent(name, node=None, apiserver_url=None): # Prepare a temp labels dict if labels == old_labels: # Label already absent - ret["comment"] = "Label folder {} already absent".format(folder) + ret["comment"] = f"Label folder {folder} already absent" else: # Label needs to be delete res = _set_labels(node, apiserver_url, labels) @@ -377,7 +377,7 @@ def label_folder_absent(name, node=None, apiserver_url=None): ) else: ret["changes"] = {"deleted": folder} - ret["comment"] = "Label folder {} absent".format(folder) + ret["comment"] = f"Label folder {folder} absent" return ret @@ -386,7 +386,7 @@ def label_folder_absent(name, node=None, apiserver_url=None): def _get_namespaces(apiserver_url, name=""): """Get namespace is namespace is defined otherwise return all namespaces""" # Prepare URL - url = "{}/api/v1/namespaces/{}".format(apiserver_url, name) + url = f"{apiserver_url}/api/v1/namespaces/{name}" # Make request ret = http.query(url) if ret.get("body"): @@ -398,7 +398,7 @@ def _get_namespaces(apiserver_url, name=""): def _create_namespace(namespace, apiserver_url): """create namespace on the defined k8s cluster""" # Prepare URL - url = "{}/api/v1/namespaces".format(apiserver_url) + url = f"{apiserver_url}/api/v1/namespaces" # Prepare data data = {"kind": "Namespace", "apiVersion": "v1", "metadata": {"name": namespace}} log.trace("namespace creation requests: %s", data) @@ -438,9 +438,9 @@ def create_namespace(name, apiserver_url=None): # This is a new namespace _create_namespace(name, apiserver_url) ret["changes"] = name - ret["comment"] = "Namespace {} created".format(name) + ret["comment"] = f"Namespace {name} created" else: - ret["comment"] = "Namespace {} already present".format(name) + ret["comment"] = f"Namespace {name} already present" return ret @@ -484,7 +484,7 @@ def get_namespaces(namespace="", apiserver_url=None): def _get_secrets(namespace, name, apiserver_url): """Get secrets of the namespace.""" # Prepare URL - url = "{}/api/v1/namespaces/{}/secrets/{}".format(apiserver_url, namespace, name) + url = f"{apiserver_url}/api/v1/namespaces/{namespace}/secrets/{name}" # Make request ret = http.query(url) if ret.get("body"): @@ -496,20 +496,20 @@ def _get_secrets(namespace, name, apiserver_url): def _update_secret(namespace, name, data, apiserver_url): """Replace secrets data by a new one""" # Prepare URL - url = "{}/api/v1/namespaces/{}/secrets/{}".format(apiserver_url, namespace, name) + url = f"{apiserver_url}/api/v1/namespaces/{namespace}/secrets/{name}" # Prepare data data = [{"op": "replace", "path": "/data", "value": data}] # Make request ret = _kpatch(url, data) if ret.get("status") == 404: - return "Node {} doesn't exist".format(url) + return f"Node {url} doesn't exist" return ret def _create_secret(namespace, name, data, apiserver_url): """create namespace on the defined k8s cluster""" # Prepare URL - url = "{}/api/v1/namespaces/{}/secrets".format(apiserver_url, namespace) + url = f"{apiserver_url}/api/v1/namespaces/{namespace}/secrets" # Prepare data request = { "apiVersion": "v1", @@ -738,7 +738,7 @@ def create_secret( return { "name": name, "result": False, - "comment": "Secret {} is already present".format(name), + "comment": f"Secret {name} is already present", "changes": {}, } @@ -755,7 +755,7 @@ def create_secret( if sname == encoded == "": ret[ "comment" - ] += "Source file {} is missing or name is incorrect\n".format(v) + ] += f"Source file {v} is missing or name is incorrect\n" if force: continue else: @@ -825,8 +825,8 @@ def delete_secret(namespace, name, apiserver_url=None, force=True): "changes": {}, } - url = "{}/api/v1/namespaces/{}/secrets/{}".format(apiserver_url, namespace, name) + url = f"{apiserver_url}/api/v1/namespaces/{namespace}/secrets/{name}" res = http.query(url, method="DELETE") if res.get("body"): - ret["comment"] = "Removed secret {} in {} namespace".format(name, namespace) + ret["comment"] = f"Removed secret {name} in {namespace} namespace" return ret diff --git a/salt/modules/kapacitor.py b/salt/modules/kapacitor.py index f3a47267a71..3cd8ff2ce9a 100644 --- a/salt/modules/kapacitor.py +++ b/salt/modules/kapacitor.py @@ -61,7 +61,7 @@ def _get_url(): host = __salt__["config.option"]("kapacitor.host", "localhost") port = __salt__["config.option"]("kapacitor.port", 9092) - return "{}://{}:{}".format(protocol, host, port) + return f"{protocol}://{host}:{port}" def get_task(name): @@ -80,9 +80,9 @@ def get_task(name): url = _get_url() if version() < "0.13": - task_url = "{}/task?name={}".format(url, name) + task_url = f"{url}/task?name={name}" else: - task_url = "{}/kapacitor/v1/tasks/{}?skip-format=true".format(url, name) + task_url = f"{url}/kapacitor/v1/tasks/{name}?skip-format=true" response = salt.utils.http.query(task_url, status=True) @@ -173,28 +173,28 @@ def define_task( return False if version() < "0.13": - cmd = "kapacitor define -name {}".format(name) + cmd = f"kapacitor define -name {name}" else: - cmd = "kapacitor define {}".format(name) + cmd = f"kapacitor define {name}" if tick_script.startswith("salt://"): tick_script = __salt__["cp.cache_file"](tick_script, __env__) - cmd += " -tick {}".format(tick_script) + cmd += f" -tick {tick_script}" if task_type: - cmd += " -type {}".format(task_type) + cmd += f" -type {task_type}" if not dbrps: dbrps = [] if database and retention_policy: - dbrp = "{}.{}".format(database, retention_policy) + dbrp = f"{database}.{retention_policy}" dbrps.append(dbrp) if dbrps: for dbrp in dbrps: - cmd += " -dbrp {}".format(dbrp) + cmd += f" -dbrp {dbrp}" return _run_cmd(cmd) @@ -212,7 +212,7 @@ def delete_task(name): salt '*' kapacitor.delete_task cpu """ - return _run_cmd("kapacitor delete tasks {}".format(name)) + return _run_cmd(f"kapacitor delete tasks {name}") def enable_task(name): @@ -228,7 +228,7 @@ def enable_task(name): salt '*' kapacitor.enable_task cpu """ - return _run_cmd("kapacitor enable {}".format(name)) + return _run_cmd(f"kapacitor enable {name}") def disable_task(name): @@ -244,4 +244,4 @@ def disable_task(name): salt '*' kapacitor.disable_task cpu """ - return _run_cmd("kapacitor disable {}".format(name)) + return _run_cmd(f"kapacitor disable {name}") diff --git a/salt/modules/kerberos.py b/salt/modules/kerberos.py index 30b0a356df0..e452b53b4b3 100644 --- a/salt/modules/kerberos.py +++ b/salt/modules/kerberos.py @@ -44,7 +44,7 @@ def __execute_kadmin(cmd): if __salt__["file.file_exists"](auth_keytab) and auth_principal: return __salt__["cmd.run_all"]( - 'kadmin -k -t {} -p {} -q "{}"'.format(auth_keytab, auth_principal, cmd) + f'kadmin -k -t {auth_keytab} -p {auth_principal} -q "{cmd}"' ) else: log.error("Unable to find kerberos keytab/principal") @@ -94,7 +94,7 @@ def get_principal(name): """ ret = {} - cmd = __execute_kadmin("get_principal {}".format(name)) + cmd = __execute_kadmin(f"get_principal {name}") if cmd["retcode"] != 0 or cmd["stderr"]: ret["comment"] = cmd["stderr"].splitlines()[-1] @@ -150,7 +150,7 @@ def get_policy(name): """ ret = {} - cmd = __execute_kadmin("get_policy {}".format(name)) + cmd = __execute_kadmin(f"get_policy {name}") if cmd["retcode"] != 0 or cmd["stderr"]: ret["comment"] = cmd["stderr"].splitlines()[-1] @@ -209,9 +209,9 @@ def create_principal(name, enctypes=None): krb_cmd = "addprinc -randkey" if enctypes: - krb_cmd += " -e {}".format(enctypes) + krb_cmd += f" -e {enctypes}" - krb_cmd += " {}".format(name) + krb_cmd += f" {name}" cmd = __execute_kadmin(krb_cmd) @@ -237,7 +237,7 @@ def delete_principal(name): """ ret = {} - cmd = __execute_kadmin("delprinc -force {}".format(name)) + cmd = __execute_kadmin(f"delprinc -force {name}") if cmd["retcode"] != 0 or cmd["stderr"]: ret["comment"] = cmd["stderr"].splitlines()[-1] @@ -260,12 +260,12 @@ def create_keytab(name, keytab, enctypes=None): """ ret = {} - krb_cmd = "ktadd -k {}".format(keytab) + krb_cmd = f"ktadd -k {keytab}" if enctypes: - krb_cmd += " -e {}".format(enctypes) + krb_cmd += f" -e {enctypes}" - krb_cmd += " {}".format(name) + krb_cmd += f" {name}" cmd = __execute_kadmin(krb_cmd) diff --git a/salt/modules/kernelpkg_linux_apt.py b/salt/modules/kernelpkg_linux_apt.py index fc8684d03fa..33cef3eaaa5 100644 --- a/salt/modules/kernelpkg_linux_apt.py +++ b/salt/modules/kernelpkg_linux_apt.py @@ -53,7 +53,7 @@ def list_installed(): salt '*' kernelpkg.list_installed """ - pkg_re = re.compile(r"^{}-[\d.-]+-{}$".format(_package_prefix(), _kernel_type())) + pkg_re = re.compile(rf"^{_package_prefix()}-[\d.-]+-{_kernel_type()}$") pkgs = __salt__["pkg.list_pkgs"](versions_as_list=True) if pkgs is None: pkgs = [] @@ -79,14 +79,12 @@ def latest_available(): salt '*' kernelpkg.latest_available """ - result = __salt__["pkg.latest_version"]( - "{}-{}".format(_package_prefix(), _kernel_type()) - ) + result = __salt__["pkg.latest_version"](f"{_package_prefix()}-{_kernel_type()}") if result == "": return latest_installed() version = re.match(r"^(\d+\.\d+\.\d+)\.(\d+)", result) - return "{}-{}-{}".format(version.group(1), version.group(2), _kernel_type()) + return f"{version.group(1)}-{version.group(2)}-{_kernel_type()}" def latest_installed(): @@ -152,9 +150,7 @@ def upgrade(reboot=False, at_time=None): chance to return, resulting in errors. A minimal delay (1 minute) is useful to ensure the result is delivered to the master. """ - result = __salt__["pkg.install"]( - name="{}-{}".format(_package_prefix(), latest_available()) - ) + result = __salt__["pkg.install"](name=f"{_package_prefix()}-{latest_available()}") _needs_reboot = needs_reboot() ret = { @@ -202,14 +198,12 @@ def remove(release): salt '*' kernelpkg.remove 4.4.0-70-generic """ if release not in list_installed(): - raise CommandExecutionError( - "Kernel release '{}' is not installed".format(release) - ) + raise CommandExecutionError(f"Kernel release '{release}' is not installed") if release == active(): raise CommandExecutionError("Active kernel cannot be removed") - target = "{}-{}".format(_package_prefix(), release) + target = f"{_package_prefix()}-{release}" log.info("Removing kernel package %s", target) __salt__["pkg.purge"](target) diff --git a/salt/modules/kernelpkg_linux_yum.py b/salt/modules/kernelpkg_linux_yum.py index a144a98811d..c37f8729174 100644 --- a/salt/modules/kernelpkg_linux_yum.py +++ b/salt/modules/kernelpkg_linux_yum.py @@ -199,14 +199,12 @@ def remove(release): salt '*' kernelpkg.remove 3.10.0-327.el7 """ if release not in list_installed(): - raise CommandExecutionError( - "Kernel release '{}' is not installed".format(release) - ) + raise CommandExecutionError(f"Kernel release '{release}' is not installed") if release == active(): raise CommandExecutionError("Active kernel cannot be removed") - target = "{}-{}".format(_package_name(), release) + target = f"{_package_name()}-{release}" log.info("Removing kernel package %s", target) old = __salt__["pkg.list_pkgs"]() diff --git a/salt/modules/keyboard.py b/salt/modules/keyboard.py index ed26c7362d2..7c15246ea95 100644 --- a/salt/modules/keyboard.py +++ b/salt/modules/keyboard.py @@ -63,19 +63,17 @@ def set_sys(layout): salt '*' keyboard.set_sys dvorak """ if salt.utils.path.which("localectl"): - __salt__["cmd.run"]("localectl set-keymap {}".format(layout)) + __salt__["cmd.run"](f"localectl set-keymap {layout}") elif "RedHat" in __grains__["os_family"]: __salt__["file.sed"]( - "/etc/sysconfig/keyboard", "^LAYOUT=.*", "LAYOUT={}".format(layout) + "/etc/sysconfig/keyboard", "^LAYOUT=.*", f"LAYOUT={layout}" ) elif "Debian" in __grains__["os_family"]: __salt__["file.sed"]( - "/etc/default/keyboard", "^XKBLAYOUT=.*", "XKBLAYOUT={}".format(layout) + "/etc/default/keyboard", "^XKBLAYOUT=.*", f"XKBLAYOUT={layout}" ) elif "Gentoo" in __grains__["os_family"]: - __salt__["file.sed"]( - "/etc/conf.d/keymaps", "^keymap=.*", "keymap={}".format(layout) - ) + __salt__["file.sed"]("/etc/conf.d/keymaps", "^keymap=.*", f"keymap={layout}") return layout @@ -104,6 +102,6 @@ def set_x(layout): salt '*' keyboard.set_x dvorak """ - cmd = "setxkbmap {}".format(layout) + cmd = f"setxkbmap {layout}" __salt__["cmd.run"](cmd) return layout diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index 9ca44b14337..898180b0c33 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -201,7 +201,7 @@ def ec2_credentials_create( tenant_id=None, tenant=None, profile=None, - **connection_args + **connection_args, ): """ Create EC2-compatible credentials for user per tenant @@ -262,7 +262,7 @@ def ec2_credentials_delete( if not user_id: return {"Error": "Could not resolve User ID"} kstone.ec2.delete(user_id, access_key) - return 'ec2 key "{}" deleted under user id "{}"'.format(access_key, user_id) + return f'ec2 key "{access_key}" deleted under user id "{user_id}"' def ec2_credentials_get( @@ -410,7 +410,7 @@ def endpoint_create( profile=None, url=None, interface=None, - **connection_args + **connection_args, ): """ Create an endpoint for an Openstack service @@ -483,7 +483,7 @@ def role_create(name, profile=None, **connection_args): kstone = auth(profile, **connection_args) if "Error" not in role_get(name=name, profile=profile, **connection_args): - return {"Error": 'Role "{}" already exists'.format(name)} + return {"Error": f'Role "{name}" already exists'} kstone.roles.create(name) return role_get(name=name, profile=profile, **connection_args) @@ -513,9 +513,9 @@ def role_delete(role_id=None, name=None, profile=None, **connection_args): role = kstone.roles.get(role_id) kstone.roles.delete(role) - ret = "Role ID {} deleted".format(role_id) + ret = f"Role ID {role_id} deleted" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -603,7 +603,7 @@ def service_delete(service_id=None, name=None, profile=None, **connection_args): "id" ] kstone.services.delete(service_id) - return 'Keystone service ID "{}" deleted'.format(service_id) + return f'Keystone service ID "{service_id}" deleted' def service_get(service_id=None, name=None, profile=None, **connection_args): @@ -736,10 +736,10 @@ def tenant_delete(tenant_id=None, name=None, profile=None, **connection_args): if not tenant_id: return {"Error": "Unable to resolve tenant id"} getattr(kstone, _TENANTS, None).delete(tenant_id) - ret = "Tenant ID {} deleted".format(tenant_id) + ret = f"Tenant ID {tenant_id} deleted" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -898,7 +898,7 @@ def tenant_update( description=None, enabled=None, profile=None, - **connection_args + **connection_args, ): """ Update a tenant's information (keystone tenant-update) @@ -947,7 +947,7 @@ def project_update( description=None, enabled=None, profile=None, - **connection_args + **connection_args, ): """ Update a tenant's information (keystone project-update) @@ -990,7 +990,7 @@ def project_update( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) else: return False @@ -1065,7 +1065,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args): try: user = kstone.users.get(user_id) except keystoneclient.exceptions.NotFound: - msg = "Could not find user '{}'".format(user_id) + msg = f"Could not find user '{user_id}'" log.error(msg) return {"Error": msg} @@ -1091,7 +1091,7 @@ def user_create( profile=None, project_id=None, description=None, - **connection_args + **connection_args, ): """ Create a user (keystone user-create) @@ -1148,10 +1148,10 @@ def user_delete(user_id=None, name=None, profile=None, **connection_args): if not user_id: return {"Error": "Unable to resolve user id"} kstone.users.delete(user_id) - ret = "User ID {} deleted".format(user_id) + ret = f"User ID {user_id} deleted" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -1164,7 +1164,7 @@ def user_update( profile=None, project=None, description=None, - **connection_args + **connection_args, ): """ Update a user's information (keystone user-update) @@ -1230,7 +1230,7 @@ def user_update( if tenant_id: kstone.users.update_tenant(user_id, tenant_id) - ret = "Info updated for user ID {}".format(user_id) + ret = f"Info updated for user ID {user_id}" return ret @@ -1308,9 +1308,9 @@ def user_password_update( kstone.users.update(user=user_id, password=password) else: kstone.users.update_password(user=user_id, password=password) - ret = "Password updated for user ID {}".format(user_id) + ret = f"Password updated for user ID {user_id}" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -1324,7 +1324,7 @@ def user_role_add( profile=None, project_id=None, project_name=None, - **connection_args + **connection_args, ): """ Add role for user in tenant (keystone user-role-add) @@ -1395,7 +1395,7 @@ def user_role_remove( profile=None, project_id=None, project_name=None, - **connection_args + **connection_args, ): """ Remove role for user in tenant (keystone user-role-remove) @@ -1462,7 +1462,7 @@ def user_role_list( profile=None, project_id=None, project_name=None, - **connection_args + **connection_args, ): """ Return a list of available user_roles (keystone user-roles-list) diff --git a/salt/modules/keystoneng.py b/salt/modules/keystoneng.py index 1bec255d60e..9a4ea9a8b19 100644 --- a/salt/modules/keystoneng.py +++ b/salt/modules/keystoneng.py @@ -68,7 +68,7 @@ def get_entity(ent_type, **kwargs): Attempt to query Keystone for more information about an entity """ try: - func = "keystoneng.{}_get".format(ent_type) + func = f"keystoneng.{ent_type}_get" ent = __salt__[func](**kwargs) except OpenStackCloudException as e: # NOTE(SamYaple): If this error was something other than Forbidden we diff --git a/salt/modules/keystore.py b/salt/modules/keystore.py index 6a4b7b90bf2..4dc0fdfc65e 100644 --- a/salt/modules/keystore.py +++ b/salt/modules/keystore.py @@ -161,9 +161,7 @@ def add(name, keystore, passphrase, certificate, private_key=None): try: cert_string = __salt__["x509.get_pem_entry"](certificate) except SaltInvocationError: - raise SaltInvocationError( - "Invalid certificate file or string: {}".format(certificate) - ) + raise SaltInvocationError(f"Invalid certificate file or string: {certificate}") if private_key: # Accept PEM input format, but convert to DES for loading into new keystore diff --git a/salt/modules/kmod.py b/salt/modules/kmod.py index 108bc6cad82..997c25fc868 100644 --- a/salt/modules/kmod.py +++ b/salt/modules/kmod.py @@ -83,9 +83,7 @@ def _set_persistent_module(mod): return set() escape_mod = re.escape(mod) # If module is commented only uncomment it - if __salt__["file.search"]( - conf, "^#[\t ]*{}[\t ]*$".format(escape_mod), multiline=True - ): + if __salt__["file.search"](conf, f"^#[\t ]*{escape_mod}[\t ]*$", multiline=True): __salt__["file.uncomment"](conf, escape_mod) else: __salt__["file.append"](conf, mod) @@ -103,9 +101,9 @@ def _remove_persistent_module(mod, comment): return set() escape_mod = re.escape(mod) if comment: - __salt__["file.comment"](conf, "^[\t ]*{}[\t ]?".format(escape_mod)) + __salt__["file.comment"](conf, f"^[\t ]*{escape_mod}[\t ]?") else: - __salt__["file.sed"](conf, "^[\t ]*{}[\t ]?".format(escape_mod), "") + __salt__["file.sed"](conf, f"^[\t ]*{escape_mod}[\t ]?", "") return {mod_name} @@ -115,7 +113,7 @@ def _which(cmd): """ _cmd = salt.utils.path.which(cmd) if not _cmd: - raise CommandExecutionError("Command '{}' cannot be found".format(cmd)) + raise CommandExecutionError(f"Command '{cmd}' cannot be found") return _cmd diff --git a/salt/modules/kubeadm.py b/salt/modules/kubeadm.py index 7ffd59be831..5e339794933 100644 --- a/salt/modules/kubeadm.py +++ b/salt/modules/kubeadm.py @@ -139,7 +139,7 @@ def version(kubeconfig=None, rootfs=None): parameters = [("kubeconfig", kubeconfig), ("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) cmd.extend(["--output", "json"]) @@ -226,9 +226,9 @@ def token_create( for parameter, value in parameters: if value: if parameter in ("groups", "usages"): - cmd.extend(["--{}".format(parameter), json.dumps(value)]) + cmd.extend([f"--{parameter}", json.dumps(value)]) else: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -264,7 +264,7 @@ def token_delete(token, kubeconfig=None, rootfs=None): parameters = [("kubeconfig", kubeconfig), ("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return bool(_cmd(cmd)) @@ -295,7 +295,7 @@ def token_generate(kubeconfig=None, rootfs=None): parameters = [("kubeconfig", kubeconfig), ("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -325,7 +325,7 @@ def token_list(kubeconfig=None, rootfs=None): parameters = [("kubeconfig", kubeconfig), ("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) lines = _cmd(cmd).splitlines() @@ -368,7 +368,7 @@ def alpha_certs_renew(rootfs=None): parameters = [("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -430,7 +430,7 @@ def alpha_kubeconfig_user( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -469,7 +469,7 @@ def alpha_kubelet_config_download(kubeconfig=None, kubelet_version=None, rootfs= ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -520,7 +520,7 @@ def alpha_kubelet_config_enable_dynamic( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -574,7 +574,7 @@ def alpha_selfhosting_pivot( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -627,7 +627,7 @@ def config_images_list( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd).splitlines() @@ -685,7 +685,7 @@ def config_images_pull( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) prefix = "[config/images] Pulled " return [(line.replace(prefix, "")) for line in _cmd(cmd).splitlines()] @@ -729,7 +729,7 @@ def config_migrate(old_config, new_config=None, kubeconfig=None, rootfs=None): ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -769,7 +769,7 @@ def config_print_init_defaults(component_configs=None, kubeconfig=None, rootfs=N ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -809,7 +809,7 @@ def config_print_join_defaults(component_configs=None, kubeconfig=None, rootfs=N ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -843,7 +843,7 @@ def config_upload_from_file(config, kubeconfig=None, rootfs=None): parameters = [("kubeconfig", kubeconfig), ("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -940,7 +940,7 @@ def config_upload_from_flags( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -970,7 +970,7 @@ def config_view(kubeconfig=None, rootfs=None): parameters = [("kubeconfig", kubeconfig), ("rootfs", rootfs)] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -1132,7 +1132,7 @@ def init( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -1297,7 +1297,7 @@ def join( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) @@ -1364,7 +1364,7 @@ def reset( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) return _cmd(cmd) diff --git a/salt/modules/kubernetesmod.py b/salt/modules/kubernetesmod.py index d66120925d5..11e2ed8958c 100644 --- a/salt/modules/kubernetesmod.py +++ b/salt/modules/kubernetesmod.py @@ -1099,7 +1099,7 @@ def create_secret( source=None, template=None, saltenv="base", - **kwargs + **kwargs, ): """ Creates the kubernetes secret as defined by the user. @@ -1274,7 +1274,7 @@ def replace_service( old_service, saltenv, namespace="default", - **kwargs + **kwargs, ): """ Replaces an existing service with a new one defined by name and namespace, @@ -1324,7 +1324,7 @@ def replace_secret( template=None, saltenv="base", namespace="default", - **kwargs + **kwargs, ): """ Replaces an existing secret with a new one defined by name and namespace, @@ -1379,7 +1379,7 @@ def replace_configmap( template=None, saltenv="base", namespace="default", - **kwargs + **kwargs, ): """ Replaces an existing configmap with a new one defined by name and @@ -1446,7 +1446,7 @@ def __create_object_body( or src_obj["kind"] != kind ): raise CommandExecutionError( - "The source file should define only a {} object".format(kind) + f"The source file should define only a {kind} object" ) if "metadata" in src_obj: @@ -1467,7 +1467,7 @@ def __read_and_render_yaml_file(source, template, saltenv): """ sfn = __salt__["cp.cache_file"](source, saltenv) if not sfn: - raise CommandExecutionError("Source file '{}' not found".format(source)) + raise CommandExecutionError(f"Source file '{source}' not found") with salt.utils.files.fopen(sfn, "r") as src: contents = src.read() @@ -1496,9 +1496,7 @@ def __read_and_render_yaml_file(source, template, saltenv): contents = data["data"].encode("utf-8") else: - raise CommandExecutionError( - "Unknown template specified: {}".format(template) - ) + raise CommandExecutionError(f"Unknown template specified: {template}") return salt.utils.yaml.safe_load(contents) diff --git a/salt/modules/launchctl_service.py b/salt/modules/launchctl_service.py index b1d2ec5a639..65bc04aeb99 100644 --- a/salt/modules/launchctl_service.py +++ b/salt/modules/launchctl_service.py @@ -101,7 +101,7 @@ def _available_services(): except Exception: # pylint: disable=broad-except # If plistlib is unable to read the file we'll need to use # the system provided plutil program to do the conversion - cmd = '/usr/bin/plutil -convert xml1 -o - -- "{}"'.format(true_path) + cmd = f'/usr/bin/plutil -convert xml1 -o - -- "{true_path}"' plist_xml = __salt__["cmd.run_all"](cmd, python_shell=False)[ "stdout" ] @@ -173,9 +173,9 @@ def get_all(): def _get_launchctl_data(job_label, runas=None): if BEFORE_YOSEMITE: - cmd = "launchctl list -x {}".format(job_label) + cmd = f"launchctl list -x {job_label}" else: - cmd = "launchctl list {}".format(job_label) + cmd = f"launchctl list {job_label}" launchctl_data = __salt__["cmd.run_all"](cmd, python_shell=False, runas=runas) diff --git a/salt/modules/layman.py b/salt/modules/layman.py index 0b8474076b5..6b61c649208 100644 --- a/salt/modules/layman.py +++ b/salt/modules/layman.py @@ -48,7 +48,7 @@ def add(overlay): """ ret = list() old_overlays = list_local() - cmd = "layman --quietness=0 --add {}".format(overlay) + cmd = f"layman --quietness=0 --add {overlay}" add_attempt = __salt__["cmd.run_all"](cmd, python_shell=False, stdin="y") if add_attempt["retcode"] != 0: raise salt.exceptions.CommandExecutionError(add_attempt["stdout"]) @@ -82,7 +82,7 @@ def delete(overlay): """ ret = list() old_overlays = list_local() - cmd = "layman --quietness=0 --delete {}".format(overlay) + cmd = f"layman --quietness=0 --delete {overlay}" delete_attempt = __salt__["cmd.run_all"](cmd, python_shell=False) if delete_attempt["retcode"] != 0: raise salt.exceptions.CommandExecutionError(delete_attempt["stdout"]) @@ -114,7 +114,7 @@ def sync(overlay="ALL"): salt '*' layman.sync """ - cmd = "layman --quietness=0 --sync {}".format(overlay) + cmd = f"layman --quietness=0 --sync {overlay}" return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 diff --git a/salt/modules/ldap3.py b/salt/modules/ldap3.py index 87836de7b6f..8261dc2f5f7 100644 --- a/salt/modules/ldap3.py +++ b/salt/modules/ldap3.py @@ -53,7 +53,7 @@ class LDAPError(Exception): def _convert_exception(e): """Convert an ldap backend exception to an LDAPError and raise it.""" - raise LDAPError("exception in ldap backend: {!r}".format(e), e) from e + raise LDAPError(f"exception in ldap backend: {e!r}", e) from e def _bind(l, bind=None): @@ -91,7 +91,7 @@ def _format_unicode_password(pwd): :returns: A unicode string """ - return '"{}"'.format(pwd).encode("utf-16-le") + return f'"{pwd}"'.encode("utf-16-le") class _connect_ctx: @@ -267,7 +267,7 @@ def connect(connect_spec=None): if backend_name not in available_backends: raise ValueError( "unsupported backend or required Python module" - + " unavailable: {}".format(backend_name) + + f" unavailable: {backend_name}" ) url = connect_spec.get("url", "ldapi:///") try: diff --git a/salt/modules/ldapmod.py b/salt/modules/ldapmod.py index ceac8cd5dc3..f611e1e287a 100644 --- a/salt/modules/ldapmod.py +++ b/salt/modules/ldapmod.py @@ -82,7 +82,7 @@ def _config(name, key=None, **kwargs): if name in kwargs: value = kwargs[name] else: - value = __salt__["config.option"]("ldap.{}".format(key)) + value = __salt__["config.option"](f"ldap.{key}") return salt.utils.data.decode(value, to_str=True) @@ -111,7 +111,7 @@ def search( dn=None, # pylint: disable=C0103 scope=None, attrs=None, - **kwargs + **kwargs, ): """ Run an arbitrary LDAP query and return the results. @@ -190,13 +190,13 @@ class _LDAPConnection: self.bindpw = bindpw if self.uri == "": - self.uri = "ldap://{}:{}".format(self.server, self.port) + self.uri = f"ldap://{self.server}:{self.port}" try: if no_verify: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) - self.ldap = ldap.initialize("{}".format(self.uri)) + self.ldap = ldap.initialize(f"{self.uri}") self.ldap.protocol_version = 3 # ldap.VERSION3 self.ldap.set_option(ldap.OPT_REFERRALS, 0) # Needed for AD diff --git a/salt/modules/libcloud_compute.py b/salt/modules/libcloud_compute.py index b902055df36..038ebd3c58c 100644 --- a/salt/modules/libcloud_compute.py +++ b/salt/modules/libcloud_compute.py @@ -787,7 +787,7 @@ def _get_by_id(collection, id): if not matches: raise ValueError("Could not find a matching item") elif len(matches) > 1: - raise ValueError("The id matched {} items, not 1".format(len(matches))) + raise ValueError(f"The id matched {len(matches)} items, not 1") return matches[0] diff --git a/salt/modules/linux_acl.py b/salt/modules/linux_acl.py index e1fcf4a9c8f..ae121e9c1b7 100644 --- a/salt/modules/linux_acl.py +++ b/salt/modules/linux_acl.py @@ -69,7 +69,7 @@ def getfacl(*args, **kwargs): if recursive: cmd += " -R" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() dentry = "" for line in out: @@ -186,7 +186,7 @@ def wipefacls(*args, **kwargs): if recursive: cmd += " -R" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' __salt__["cmd.run"](cmd, python_shell=False) return True @@ -233,10 +233,10 @@ def modfacl(acl_type, acl_name="", perms="", *args, **kwargs): cmd += " -m" - cmd = "{} {}:{}:{}".format(cmd, _acl_prefix(acl_type), acl_name, perms) + cmd = f"{cmd} {_acl_prefix(acl_type)}:{acl_name}:{perms}" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' __salt__["cmd.run"](cmd, python_shell=False, raise_err=raise_err) return True @@ -265,9 +265,9 @@ def delfacl(acl_type, acl_name="", *args, **kwargs): cmd += " -x" - cmd = "{} {}:{}".format(cmd, _acl_prefix(acl_type), acl_name) + cmd = f"{cmd} {_acl_prefix(acl_type)}:{acl_name}" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' __salt__["cmd.run"](cmd, python_shell=False) return True diff --git a/salt/modules/linux_ip.py b/salt/modules/linux_ip.py index 01cc0e285d5..a7f6e960da9 100644 --- a/salt/modules/linux_ip.py +++ b/salt/modules/linux_ip.py @@ -45,7 +45,7 @@ def down(iface, iface_type=None): """ # Slave devices are controlled by the master. if iface_type not in ["slave"]: - return __salt__["cmd.run"]("ip link set {} down".format(iface)) + return __salt__["cmd.run"](f"ip link set {iface} down") return None @@ -92,7 +92,7 @@ def _ip_ifaces(): at_ = comps[0] if len(comps) % 2 != 0: last = comps.pop() - comps[-1] += " {}".format(last) + comps[-1] += f" {last}" ifi = iter(comps) ret[if_][at_] = dict(list(zip(ifi, ifi))) else: @@ -114,7 +114,7 @@ def up(iface, iface_type=None): """ # Slave devices are controlled by the master. if iface_type not in ["slave"]: - return __salt__["cmd.run"]("ip link set {} up".format(iface)) + return __salt__["cmd.run"](f"ip link set {iface} up") return None diff --git a/salt/modules/linux_lvm.py b/salt/modules/linux_lvm.py index 03803497aa6..d53caa0e073 100644 --- a/salt/modules/linux_lvm.py +++ b/salt/modules/linux_lvm.py @@ -245,11 +245,11 @@ def pvcreate(devices, override=True, force=True, **kwargs): for device in devices: if not os.path.exists(device): - return "{} does not exist".format(device) + return f"{device} does not exist" if not pvdisplay(device, quiet=True): cmd.append(device) elif not override: - return 'Device "{}" is already an LVM physical volume.'.format(device) + return f'Device "{device}" is already an LVM physical volume.' if not cmd[2:]: # All specified devices are already LVM volumes @@ -270,9 +270,9 @@ def pvcreate(devices, override=True, force=True, **kwargs): no_parameter = "norestorefile" for var in kwargs: if kwargs[var] and var in valid: - cmd.extend(["--{}".format(var), kwargs[var]]) + cmd.extend([f"--{var}", kwargs[var]]) elif kwargs[var] and var in no_parameter: - cmd.append("--{}".format(var)) + cmd.append(f"--{var}") out = __salt__["cmd.run_all"](cmd, python_shell=False) if out.get("retcode"): @@ -281,7 +281,7 @@ def pvcreate(devices, override=True, force=True, **kwargs): # Verify pvcreate was successful for device in devices: if not pvdisplay(device): - return 'Device "{}" was not affected.'.format(device) + return f'Device "{device}" was not affected.' return True @@ -313,7 +313,7 @@ def pvremove(devices, override=True, force=True): if pvdisplay(device): cmd.append(device) elif not override: - return "{} is not a physical volume".format(device) + return f"{device} is not a physical volume" if not cmd[2:]: # Nothing to do @@ -326,7 +326,7 @@ def pvremove(devices, override=True, force=True): # Verify pvremove was successful for device in devices: if pvdisplay(device, quiet=True): - return 'Device "{}" was not affected.'.format(device) + return f'Device "{device}" was not affected.' return True @@ -371,14 +371,14 @@ def vgcreate(vgname, devices, force=False, **kwargs): ) for var in kwargs: if kwargs[var] and var in valid: - cmd.append("--{}".format(var)) + cmd.append(f"--{var}") cmd.append(kwargs[var]) cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False) if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Volume group "{}" successfully created'.format(vgname) + out = f'Volume group "{vgname}" successfully created' vgdata = vgdisplay(vgname) vgdata["Output from vgcreate"] = out @@ -415,7 +415,7 @@ def vgextend(vgname, devices, force=False): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Volume group "{}" successfully extended'.format(vgname) + out = f'Volume group "{vgname}" successfully extended' vgdata = {"Output from vgextend": out} return vgdata @@ -431,7 +431,7 @@ def lvcreate( thinvolume=False, thinpool=False, force=False, - **kwargs + **kwargs, ): """ Create a new logical volume, with option for which physical volume to be used @@ -494,9 +494,9 @@ def lvcreate( if kwargs: for k, v in kwargs.items(): if k in no_parameter: - extra_arguments.append("--{}".format(k)) + extra_arguments.append(f"--{k}") elif k in valid: - extra_arguments.extend(["--{}".format(k), "{}".format(v)]) + extra_arguments.extend([f"--{k}", f"{v}"]) cmd = [salt.utils.path.which("lvcreate")] @@ -508,18 +508,18 @@ def lvcreate( cmd.extend(["-n", lvname]) if snapshot: - cmd.extend(["-s", "{}/{}".format(vgname, snapshot)]) + cmd.extend(["-s", f"{vgname}/{snapshot}"]) else: cmd.append(vgname) if size and thinvolume: - cmd.extend(["-V", "{}".format(size)]) + cmd.extend(["-V", f"{size}"]) elif extents and thinvolume: return "Error: Thin volume size cannot be specified as extents" elif size: - cmd.extend(["-L", "{}".format(size)]) + cmd.extend(["-L", f"{size}"]) elif extents: - cmd.extend(["-l", "{}".format(extents)]) + cmd.extend(["-l", f"{extents}"]) else: return "Error: Either size or extents must be specified" @@ -537,9 +537,9 @@ def lvcreate( if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" created.'.format(lvname) + out = f'Logical volume "{lvname}" created.' - lvdev = "/dev/{}/{}".format(vgname, lvname) + lvdev = f"/dev/{vgname}/{lvname}" lvdata = lvdisplay(lvdev) lvdata["Output from lvcreate"] = out return lvdata @@ -567,7 +567,7 @@ def vgremove(vgname, force=True): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Volume group "{}" successfully removed'.format(vgname) + out = f'Volume group "{vgname}" successfully removed' return out @@ -581,7 +581,7 @@ def lvremove(lvname, vgname, force=True): salt '*' lvm.lvremove lvname vgname force=True """ - cmd = ["lvremove", "{}/{}".format(vgname, lvname)] + cmd = ["lvremove", f"{vgname}/{lvname}"] if force: cmd.append("--yes") @@ -592,7 +592,7 @@ def lvremove(lvname, vgname, force=True): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" successfully removed'.format(lvname) + out = f'Logical volume "{lvname}" successfully removed' return out @@ -625,9 +625,9 @@ def lvresize(size=None, lvpath=None, extents=None, force=False, resizefs=False): cmd.append("--resizefs") if size: - cmd.extend(["-L", "{}".format(size)]) + cmd.extend(["-L", f"{size}"]) elif extents: - cmd.extend(["-l", "{}".format(extents)]) + cmd.extend(["-l", f"{extents}"]) else: log.error("Error: Either size or extents must be specified") return {} @@ -638,7 +638,7 @@ def lvresize(size=None, lvpath=None, extents=None, force=False, resizefs=False): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" successfully resized.'.format(lvpath) + out = f'Logical volume "{lvpath}" successfully resized.' return {"Output from lvresize": out} @@ -671,9 +671,9 @@ def lvextend(size=None, lvpath=None, extents=None, force=False, resizefs=False): cmd.append("--resizefs") if size: - cmd.extend(["-L", "{}".format(size)]) + cmd.extend(["-L", f"{size}"]) elif extents: - cmd.extend(["-l", "{}".format(extents)]) + cmd.extend(["-l", f"{extents}"]) else: log.error("Error: Either size or extents must be specified") return {} @@ -684,7 +684,7 @@ def lvextend(size=None, lvpath=None, extents=None, force=False, resizefs=False): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" successfully extended.'.format(lvpath) + out = f'Logical volume "{lvpath}" successfully extended.' return {"Output from lvextend": out} @@ -716,7 +716,7 @@ def pvresize(devices, override=True, force=True): if pvdisplay(device): cmd.append(device) elif not override: - return "{} is not a physical volume".format(device) + return f"{device} is not a physical volume" if not cmd[2:]: # Nothing to do diff --git a/salt/modules/linux_service.py b/salt/modules/linux_service.py index d26fc5a9799..4289fc6003f 100644 --- a/salt/modules/linux_service.py +++ b/salt/modules/linux_service.py @@ -43,7 +43,7 @@ def __virtual__(): return (False, "Non Linux OSes are not supported") init_grain = __grains__.get("init") if init_grain not in (None, "sysvinit", "unknown"): - return (False, "Minion is running {}".format(init_grain)) + return (False, f"Minion is running {init_grain}") elif __utils__["systemd.booted"](__context__): # Should have been caught by init grain check, but check just in case return (False, "Minion is running systemd") diff --git a/salt/modules/linux_shadow.py b/salt/modules/linux_shadow.py index aa149ac4c8e..09fe73fdb54 100644 --- a/salt/modules/linux_shadow.py +++ b/salt/modules/linux_shadow.py @@ -368,7 +368,7 @@ def set_password(name, password, use_usermod=False, root=None): # ALT Linux uses tcb to store password hashes. More information found # in manpage (http://docs.altlinux.org/manpages/tcb.5.html) if __grains__["os"] == "ALT": - s_file = "/etc/tcb/{}/shadow".format(name) + s_file = f"/etc/tcb/{name}/shadow" else: s_file = "/etc/shadow" if root: diff --git a/salt/modules/linux_sysctl.py b/salt/modules/linux_sysctl.py index fe63cb6c596..3cb77e36017 100644 --- a/salt/modules/linux_sysctl.py +++ b/salt/modules/linux_sysctl.py @@ -41,7 +41,7 @@ def _which(cmd): """ _cmd = salt.utils.path.which(cmd) if not _cmd: - raise CommandExecutionError("Command '{}' cannot be found".format(cmd)) + raise CommandExecutionError(f"Command '{cmd}' cannot be found") return _cmd @@ -137,13 +137,13 @@ def assign(name, value): tran_tab = name.translate("".maketrans("./", "/.")) - sysctl_file = "/proc/sys/{}".format(tran_tab) + sysctl_file = f"/proc/sys/{tran_tab}" if not os.path.exists(sysctl_file): - raise CommandExecutionError("sysctl {} does not exist".format(name)) + raise CommandExecutionError(f"sysctl {name} does not exist") ret = {} _sysctl = "{}".format(_which("sysctl")) - cmd = [_sysctl, "-w", "{}={}".format(name, value)] + cmd = [_sysctl, "-w", f"{name}={value}"] data = __salt__["cmd.run_all"](cmd, python_shell=False) out = data["stdout"] err = data["stderr"] @@ -151,14 +151,14 @@ def assign(name, value): # Example: # # sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216" # net.ipv4.tcp_rmem = 4096 87380 16777216 - regex = re.compile(r"^{}\s+=\s+{}$".format(re.escape(name), re.escape(value))) + regex = re.compile(rf"^{re.escape(name)}\s+=\s+{re.escape(value)}$") if not regex.match(out) or "Invalid argument" in str(err): if data["retcode"] != 0 and err: error = err else: error = out - raise CommandExecutionError("sysctl -w failed: {}".format(error)) + raise CommandExecutionError(f"sysctl -w failed: {error}") new_name, new_value = out.split(" = ", 1) ret[new_name] = new_value return ret @@ -238,13 +238,13 @@ def persist(name, value, config=None): else: return "Already set" - nlines.append("{} = {}\n".format(name, value)) + nlines.append(f"{name} = {value}\n") edited = True continue else: nlines.append(line) if not edited: - nlines.append("{} = {}\n".format(name, value)) + nlines.append(f"{name} = {value}\n") try: with salt.utils.files.fopen(config, "wb") as _fh: _fh.writelines(salt.utils.data.encode(nlines)) diff --git a/salt/modules/localemod.py b/salt/modules/localemod.py index 8744535d1a1..e8cd9063ca3 100644 --- a/salt/modules/localemod.py +++ b/salt/modules/localemod.py @@ -109,11 +109,9 @@ def _localectl_set(locale=""): else _localectl_status().get("system_locale", {}) ) locale_params["LANG"] = str(locale) - args = " ".join( - ['{}="{}"'.format(k, v) for k, v in locale_params.items() if v is not None] - ) + args = " ".join([f'{k}="{v}"' for k, v in locale_params.items() if v is not None]) return not __salt__["cmd.retcode"]( - "localectl set-locale {}".format(args), python_shell=False + f"localectl set-locale {args}", python_shell=False ) @@ -204,7 +202,7 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/sysconfig/language", "^RC_LANG=.*", - 'RC_LANG="{}"'.format(locale), + f'RC_LANG="{locale}"', append_if_not_found=True, ) elif "RedHat" in __grains__["os_family"]: @@ -213,7 +211,7 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/sysconfig/i18n", "^LANG=.*", - 'LANG="{}"'.format(locale), + f'LANG="{locale}"', append_if_not_found=True, ) elif "Debian" in __grains__["os_family"]: @@ -227,11 +225,11 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/default/locale", "^LANG=.*", - 'LANG="{}"'.format(locale), + f'LANG="{locale}"', append_if_not_found=True, ) elif "Gentoo" in __grains__["os_family"]: - cmd = "eselect --brief locale set {}".format(locale) + cmd = f"eselect --brief locale set {locale}" return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 elif "Solaris" in __grains__["os_family"]: if locale not in __salt__["locale.list_avail"](): @@ -239,7 +237,7 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/default/init", "^LANG=.*", - 'LANG="{}"'.format(locale), + f'LANG="{locale}"', append_if_not_found=True, ) else: @@ -319,9 +317,7 @@ def gen_locale(locale, **kwargs): if on_debian or on_gentoo: # file-based search search = "/usr/share/i18n/SUPPORTED" - valid = __salt__["file.search"]( - search, "^{}$".format(locale), flags=re.MULTILINE - ) + valid = __salt__["file.search"](search, f"^{locale}$", flags=re.MULTILINE) else: # directory-based search if on_suse: search = "/usr/share/locale" @@ -332,7 +328,7 @@ def gen_locale(locale, **kwargs): valid = locale_search_str in os.listdir(search) except OSError as ex: log.error(ex) - raise CommandExecutionError('Locale "{}" is not available.'.format(locale)) + raise CommandExecutionError(f'Locale "{locale}" is not available.') if not valid: log.error('The provided locale "%s" is not found in %s', locale, search) @@ -341,8 +337,8 @@ def gen_locale(locale, **kwargs): if os.path.exists("/etc/locale.gen"): __salt__["file.replace"]( "/etc/locale.gen", - r"^\s*#\s*{}\s*$".format(locale), - "{}\n".format(locale), + rf"^\s*#\s*{locale}\s*$", + f"{locale}\n", append_if_not_found=True, ) elif on_ubuntu: diff --git a/salt/modules/locate.py b/salt/modules/locate.py index fd4f2e3878c..aa8e1a2473c 100644 --- a/salt/modules/locate.py +++ b/salt/modules/locate.py @@ -111,13 +111,13 @@ def locate(pattern, database="", limit=0, **kwargs): if bool(kwargs[option]) is True and option in toggles: options += toggles[option] if options: - options = "-{}".format(options) + options = f"-{options}" if database: - options += " -d {}".format(database) + options += f" -d {database}" if limit > 0: - options += " -l {}".format(limit) + options += f" -l {limit}" if "regex" in kwargs and bool(kwargs["regex"]) is True: options += " --regex" - cmd = "locate {} {}".format(options, pattern) + cmd = f"locate {options} {pattern}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() return out diff --git a/salt/modules/logadm.py b/salt/modules/logadm.py index 677e12f705b..9f50803ba40 100644 --- a/salt/modules/logadm.py +++ b/salt/modules/logadm.py @@ -119,7 +119,7 @@ def _parse_options(entry, options, include_unset=True): if "additional_options" not in log_cfg: log_cfg["additional_options"] = [] if " " in options[index]: - log_cfg["dditional_options"] = "'{}'".format(options[index]) + log_cfg["dditional_options"] = f"'{options[index]}'" else: log_cfg["additional_options"].append(options[index]) @@ -172,7 +172,7 @@ def show_conf(conf_file=default_conf, name=None): if name and name in cfg: return {name: cfg[name]} elif name: - return {name: "not found in {}".format(conf_file)} + return {name: f"not found in {conf_file}"} else: return cfg @@ -212,7 +212,7 @@ def list_conf(conf_file=default_conf, log_file=None, include_unset=False): if log_file and log_file in cfg_parsed: return {log_file: cfg_parsed[log_file]} elif log_file: - return {log_file: "not found in {}".format(conf_file)} + return {log_file: f"not found in {conf_file}"} else: return cfg_parsed @@ -286,7 +286,7 @@ def rotate(name, pattern=None, conf_file=default_conf, **kwargs): ## build command log.debug("logadm.rotate - kwargs: %s", kwargs) - command = "logadm -f {}".format(conf_file) + command = f"logadm -f {conf_file}" for arg, val in kwargs.items(): if arg in option_toggles.values() and val: command = "{} {}".format( @@ -294,7 +294,7 @@ def rotate(name, pattern=None, conf_file=default_conf, **kwargs): _arg2opt(arg), ) elif arg in option_flags.values(): - command = "{} {} {}".format(command, _arg2opt(arg), shlex.quote(str(val))) + command = f"{command} {_arg2opt(arg)} {shlex.quote(str(val))}" elif arg != "log_file": log.warning("Unknown argument %s, don't know how to map this!", arg) if "log_file" in kwargs: @@ -329,7 +329,7 @@ def remove(name, conf_file=default_conf): salt '*' logadm.remove myapplog """ - command = "logadm -f {} -r {}".format(conf_file, name) + command = f"logadm -f {conf_file} -r {name}" result = __salt__["cmd.run_all"](command, python_shell=False) if result["retcode"] != 0: return dict( diff --git a/salt/modules/logrotate.py b/salt/modules/logrotate.py index 314fc607cfc..2e29876da81 100644 --- a/salt/modules/logrotate.py +++ b/salt/modules/logrotate.py @@ -211,7 +211,7 @@ def set_(key, value, setting=None, conf_file=_DEFAULT_CONF): "flags": 8, "backup": False, "path": conf_file, - "pattern": "^{}.*".format(key), + "pattern": f"^{key}.*", "show_changes": False, } @@ -232,7 +232,7 @@ def set_(key, value, setting=None, conf_file=_DEFAULT_CONF): if value is True: new_line = key elif value: - new_line = "{} {}".format(key, value) + new_line = f"{key} {value}" kwargs.update({"prepend_if_not_found": True}) else: @@ -259,7 +259,7 @@ def set_(key, value, setting=None, conf_file=_DEFAULT_CONF): kwargs.update( { - "pattern": "^{0}.*?{{.*?}}".format(key), + "pattern": f"^{key}.*?{{.*?}}", "flags": 24, "append_if_not_found": True, } @@ -279,5 +279,5 @@ def _dict_to_stanza(key, stanza): for skey in stanza: if stanza[skey] is True: stanza[skey] = "" - ret += " {} {}\n".format(skey, stanza[skey]) - return "{0} {{\n{1}}}".format(key, ret) + ret += f" {skey} {stanza[skey]}\n" + return f"{key} {{\n{ret}}}" diff --git a/salt/modules/lvs.py b/salt/modules/lvs.py index a5f2aec02ae..212a5c6f0fc 100644 --- a/salt/modules/lvs.py +++ b/salt/modules/lvs.py @@ -192,7 +192,7 @@ def add_server( server_address=None, packet_forward_method="dr", weight=1, - **kwargs + **kwargs, ): """ @@ -228,7 +228,7 @@ def add_server( server_address=server_address, packet_forward_method=packet_forward_method, weight=weight, - **kwargs + **kwargs, ), ) out = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -247,7 +247,7 @@ def edit_server( server_address=None, packet_forward_method=None, weight=None, - **kwargs + **kwargs, ): """ @@ -283,7 +283,7 @@ def edit_server( server_address=server_address, packet_forward_method=packet_forward_method, weight=weight, - **kwargs + **kwargs, ), ) out = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -347,7 +347,7 @@ def clear(): salt '*' lvs.clear """ - cmd = "{} -C".format(__detect_os()) + cmd = f"{__detect_os()} -C" out = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -371,7 +371,7 @@ def get_rules(): salt '*' lvs.get_rules """ - cmd = "{} -S -n".format(__detect_os()) + cmd = f"{__detect_os()} -S -n" ret = __salt__["cmd.run"](cmd, python_shell=False) return ret @@ -395,7 +395,7 @@ def list_(protocol=None, service_address=None): _build_cmd(protocol=protocol, service_address=service_address), ) else: - cmd = "{} -L -n".format(__detect_os()) + cmd = f"{__detect_os()} -L -n" out = __salt__["cmd.run_all"](cmd, python_shell=False) # A non-zero return code means fail @@ -425,7 +425,7 @@ def zero(protocol=None, service_address=None): _build_cmd(protocol=protocol, service_address=service_address), ) else: - cmd = "{} -Z".format(__detect_os()) + cmd = f"{__detect_os()} -Z" out = __salt__["cmd.run_all"](cmd, python_shell=False) # A non-zero return code means fail @@ -482,7 +482,7 @@ def check_server(protocol=None, service_address=None, server_address=None, **kwa protocol=protocol, service_address=service_address, server_address=server_address, - **kwargs + **kwargs, ) ) # Exact match diff --git a/salt/modules/lxd.py b/salt/modules/lxd.py index fadaa98f27e..9ec22360862 100644 --- a/salt/modules/lxd.py +++ b/salt/modules/lxd.py @@ -180,31 +180,31 @@ def init( salt '*' lxd.init """ - cmd = 'lxd init --auto --storage-backend="{}"'.format(storage_backend) + cmd = f'lxd init --auto --storage-backend="{storage_backend}"' if trust_password is not None: - cmd = cmd + ' --trust-password="{}"'.format(trust_password) + cmd = cmd + f' --trust-password="{trust_password}"' if network_address is not None: - cmd = cmd + ' --network-address="{}"'.format(network_address) + cmd = cmd + f' --network-address="{network_address}"' if network_port is not None: - cmd = cmd + ' --network-port="{}"'.format(network_port) + cmd = cmd + f' --network-port="{network_port}"' if storage_create_device is not None: - cmd = cmd + ' --storage-create-device="{}"'.format(storage_create_device) + cmd = cmd + f' --storage-create-device="{storage_create_device}"' if storage_create_loop is not None: - cmd = cmd + ' --storage-create-loop="{}"'.format(storage_create_loop) + cmd = cmd + f' --storage-create-loop="{storage_create_loop}"' if storage_pool is not None: - cmd = cmd + ' --storage-pool="{}"'.format(storage_pool) + cmd = cmd + f' --storage-pool="{storage_pool}"' try: output = __salt__["cmd.run"](cmd) except ValueError as e: raise CommandExecutionError( - "Failed to call: '{}', error was: {}".format(cmd, str(e)), + f"Failed to call: '{cmd}', error was: {str(e)}", ) if "error:" in output: @@ -248,7 +248,7 @@ def config_set(key, value): output[output.index("error:") + 7 :], ) - return ('Config value "{}" successfully set.'.format(key),) + return (f'Config value "{key}" successfully set.',) @salt.utils.decorators.path.which("lxd") @@ -267,7 +267,7 @@ def config_get(key): salt '*' lxd.config_get core.https_address """ - cmd = 'lxc config get "{}"'.format(key) + cmd = f'lxc config get "{key}"' output = __salt__["cmd.run"](cmd) if "error:" in output: @@ -374,7 +374,7 @@ def pylxd_client_get(remote_addr=None, cert=None, key=None, verify_cert=True): verify=verify_cert, ) except pylxd.exceptions.ClientConnectionFailed: - raise CommandExecutionError("Failed to connect to '{}'".format(remote_addr)) + raise CommandExecutionError(f"Failed to connect to '{remote_addr}'") except TypeError as e: # Happens when the verification failed. @@ -742,7 +742,7 @@ def container_get( try: containers = [client.containers.get(name)] except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Container '{}' not found".format(name)) + raise SaltInvocationError(f"Container '{name}' not found") if _raw: return containers[0] @@ -829,9 +829,7 @@ def container_rename( container = container_get(name, remote_addr, cert, key, verify_cert, _raw=True) if container.status_code == CONTAINER_STATUS_RUNNING: - raise SaltInvocationError( - "Can't rename the running container '{}'.".format(name) - ) + raise SaltInvocationError(f"Can't rename the running container '{name}'.") container.rename(newname, wait=True) return _pylxd_model_to_dict(container) @@ -874,7 +872,7 @@ def container_state(name=None, remote_addr=None, cert=None, key=None, verify_cer try: containers = [client.containers.get(name)] except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Container '{}' not found".format(name)) + raise SaltInvocationError(f"Container '{name}' not found") states = [] for container in containers: @@ -1382,7 +1380,7 @@ def container_device_add( cert=None, key=None, verify_cert=True, - **kwargs + **kwargs, ): """ Add a container device @@ -1562,7 +1560,7 @@ def container_file_put( # and integer, handle it as if it where a octal representation. mode = str(mode) if not mode.startswith("0"): - mode = "0{}".format(mode) + mode = f"0{mode}" container = container_get(name, remote_addr, cert, key, verify_cert, _raw=True) @@ -1572,7 +1570,7 @@ def container_file_put( if src.find("://") >= 0: cached_file = __salt__["cp.cache_file"](src, saltenv=saltenv) if not cached_file: - raise SaltInvocationError("File '{}' not found".format(src)) + raise SaltInvocationError(f"File '{src}' not found") if not os.path.isabs(cached_file): raise SaltInvocationError("File path must be absolute.") src = cached_file @@ -1583,7 +1581,7 @@ def container_file_put( src = os.path.sep if not os.path.exists(src): - raise CommandExecutionError("No such file or directory '{}'".format(src)) + raise CommandExecutionError(f"No such file or directory '{src}'") if os.path.isdir(src) and not recursive: raise SaltInvocationError( @@ -1766,7 +1764,7 @@ def container_file_get( if mode is not None: mode = str(mode) if not mode.startswith("0"): - mode = "0{}".format(mode) + mode = f"0{mode}" container = container_get(name, remote_addr, cert, key, verify_cert, _raw=True) @@ -1787,9 +1785,7 @@ def container_file_get( else: dst_path = os.path.dirname(dst) if not os.path.isdir(dst_path): - raise CommandExecutionError( - "No such file or directory '{}'".format(dst_path) - ) + raise CommandExecutionError(f"No such file or directory '{dst_path}'") # Seems to be duplicate of line 1794, produces /path/file_name/file_name # dst = os.path.join(dst, os.path.basename(src)) @@ -2070,7 +2066,7 @@ def profile_get( try: profile = client.profiles.get(name) except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Profile '{}' not found".format(name)) + raise SaltInvocationError(f"Profile '{name}' not found") if _raw: return profile @@ -2326,7 +2322,7 @@ def profile_device_set( cert=None, key=None, verify_cert=True, - **kwargs + **kwargs, ): """Set a profile device. @@ -2527,9 +2523,7 @@ def image_get( try: image = client.images.get(fingerprint) except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError( - "Image with fingerprint '{}' not found".format(fingerprint) - ) + raise SaltInvocationError(f"Image with fingerprint '{fingerprint}' not found") if _raw: return image @@ -2585,7 +2579,7 @@ def image_get_by_alias( try: image = client.images.get_by_alias(alias) except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Image with alias '{}' not found".format(alias)) + raise SaltInvocationError(f"Image with alias '{alias}' not found") if _raw: return image @@ -3457,7 +3451,7 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): continue if not test: - config_changes[k] = 'Added config key "{}" = "{}"'.format(k, newconfig[k]) + config_changes[k] = f'Added config key "{k}" = "{newconfig[k]}"' obj.config[k] = newconfig[k] else: config_changes[k] = 'Would add config key "{}" = "{}"'.format( @@ -3484,10 +3478,10 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): continue if not test: - devices_changes[k] = 'Removed device "{}"'.format(k) + devices_changes[k] = f'Removed device "{k}"' del obj.devices[k] else: - devices_changes[k] = 'Would remove device "{}"'.format(k) + devices_changes[k] = f'Would remove device "{k}"' # Changed devices for k, v in obj.devices.items(): @@ -3501,10 +3495,10 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): if newdevices[k] != v: if not test: - devices_changes[k] = 'Changed device "{}"'.format(k) + devices_changes[k] = f'Changed device "{k}"' obj.devices[k] = newdevices[k] else: - devices_changes[k] = 'Would change device "{}"'.format(k) + devices_changes[k] = f'Would change device "{k}"' # New devices for k in ndk.difference(dk): @@ -3513,10 +3507,10 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): continue if not test: - devices_changes[k] = 'Added device "{}"'.format(k) + devices_changes[k] = f'Added device "{k}"' obj.devices[k] = newdevices[k] else: - devices_changes[k] = 'Would add device "{}"'.format(k) + devices_changes[k] = f'Would add device "{k}"' if devices_changes: changes["devices"] = devices_changes @@ -3562,7 +3556,7 @@ def _set_property_dict_item(obj, prop, key, value): def _get_property_dict_item(obj, prop, key): attr = getattr(obj, prop) if key not in attr: - raise SaltInvocationError("'{}' doesn't exists".format(key)) + raise SaltInvocationError(f"'{key}' doesn't exists") return attr[key] @@ -3570,7 +3564,7 @@ def _get_property_dict_item(obj, prop, key): def _delete_property_dict_item(obj, prop, key): attr = getattr(obj, prop) if key not in attr: - raise SaltInvocationError("'{}' doesn't exists".format(key)) + raise SaltInvocationError(f"'{key}' doesn't exists") del attr[key] pylxd_save_object(obj) @@ -3594,7 +3588,7 @@ def _verify_image(image, remote_addr=None, cert=None, key=None, verify_cert=True except SaltInvocationError: image = image_get(name, remote_addr, cert, key, verify_cert, _raw=True) elif not hasattr(image, "fingerprint"): - raise SaltInvocationError("Invalid image '{}'".format(image)) + raise SaltInvocationError(f"Invalid image '{image}'") return image @@ -3633,7 +3627,7 @@ if HAS_PYLXD: if isinstance(mode, int): mode = oct(mode) elif not mode.startswith("0"): - mode = "0{}".format(mode) + mode = f"0{mode}" headers["X-LXD-mode"] = mode if uid is not None: headers["X-LXD-uid"] = str(uid) diff --git a/salt/modules/mac_assistive.py b/salt/modules/mac_assistive.py index e53c750bd7b..7a81fe87a5b 100644 --- a/salt/modules/mac_assistive.py +++ b/salt/modules/mac_assistive.py @@ -69,13 +69,13 @@ def install(app_id, enable=True, tries=3, wait=10): except sqlite3.Error as exc: if "attempt to write a readonly database" not in str(exc): raise CommandExecutionError( - "Error installing app({}): {}".format(app_id, exc) + f"Error installing app({app_id}): {exc}" ) elif num_tries < tries: num_tries += 1 else: raise CommandExecutionError( - "Error installing app({}): {}".format(app_id, exc) + f"Error installing app({app_id}): {exc}" ) time.sleep(wait) @@ -100,7 +100,7 @@ def installed(app_id): return db.installed(app_id) except sqlite3.Error as exc: raise CommandExecutionError( - "Error checking if app({}) is installed: {}".format(app_id, exc) + f"Error checking if app({app_id}) is installed: {exc}" ) @@ -129,7 +129,7 @@ def enable_(app_id, enabled=True): return db.disable(app_id) except sqlite3.Error as exc: raise CommandExecutionError( - "Error setting enable to {} on app({}): {}".format(enabled, app_id, exc) + f"Error setting enable to {enabled} on app({app_id}): {exc}" ) @@ -153,7 +153,7 @@ def enabled(app_id): return db.enabled(app_id) except sqlite3.Error as exc: raise CommandExecutionError( - "Error checking if app({}) is enabled: {}".format(app_id, exc) + f"Error checking if app({app_id}) is enabled: {exc}" ) @@ -175,9 +175,7 @@ def remove(app_id): try: return db.remove(app_id) except sqlite3.Error as exc: - raise CommandExecutionError( - "Error removing app({}): {}".format(app_id, exc) - ) + raise CommandExecutionError(f"Error removing app({app_id}): {exc}") class TccDB: @@ -205,7 +203,7 @@ class TccDB: self.ge_bigsur_and_later = True else: raise CommandExecutionError( - "TCC Database structure unknown for digest '{}'".format(digest) + f"TCC Database structure unknown for digest '{digest}'" ) def _get_client_type(self, app_id): diff --git a/salt/modules/mac_brew_pkg.py b/salt/modules/mac_brew_pkg.py index 26c47a7a5b8..21069a84c09 100644 --- a/salt/modules/mac_brew_pkg.py +++ b/salt/modules/mac_brew_pkg.py @@ -110,7 +110,7 @@ def _call_brew(*cmd, failhard=True): runas = user if user != __opts__["user"] else None _cmd = [] if runas: - _cmd = ["sudo -i -n -H -u {} -- ".format(runas)] + _cmd = [f"sudo -i -n -H -u {runas} -- "] _cmd = _cmd + [salt.utils.path.which("brew")] + list(cmd) _cmd = " ".join(_cmd) @@ -496,7 +496,7 @@ def list_upgrades(refresh=True, include_casks=False, **kwargs): # pylint: disab try: data = salt.utils.json.loads(res["stdout"]) except ValueError as err: - msg = 'unable to interpret output from "brew outdated": {}'.format(err) + msg = f'unable to interpret output from "brew outdated": {err}' log.error(msg) raise CommandExecutionError(msg) @@ -637,11 +637,11 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613 ret[target] = {"name": target, "changes": {}, "result": False, "comment": ""} if target not in installed: - ret[target]["comment"] = "Package {} does not have a state.".format(target) + ret[target]["comment"] = f"Package {target} does not have a state." elif target not in pinned: if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret[target]["comment"] = "Package {} is set to be held.".format(target) + ret[target]["comment"] = f"Package {target} is set to be held." else: result = _pin(target) if result: @@ -652,7 +652,7 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613 ) else: ret[target].update(result=False) - ret[target]["comment"] = "Unable to hold package {}.".format(target) + ret[target]["comment"] = f"Unable to hold package {target}." else: ret[target].update(result=True) ret[target]["comment"] = "Package {} is already set to be held.".format( @@ -713,7 +713,7 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 ret[target] = {"name": target, "changes": {}, "result": False, "comment": ""} if target not in installed: - ret[target]["comment"] = "Package {} does not have a state.".format(target) + ret[target]["comment"] = f"Package {target} does not have a state." elif target in pinned: if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) @@ -725,9 +725,9 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 if result: changes = {"old": "hold", "new": "install"} ret[target].update(changes=changes, result=True) - ret[target]["comment"] = ( - "Package {} is no longer being held.".format(target) - ) + ret[target][ + "comment" + ] = f"Package {target} is no longer being held." else: ret[target].update(result=False) ret[target]["comment"] = "Unable to unhold package {}.".format( diff --git a/salt/modules/mac_desktop.py b/salt/modules/mac_desktop.py index eb58cf2888e..0c457080d28 100644 --- a/salt/modules/mac_desktop.py +++ b/salt/modules/mac_desktop.py @@ -48,7 +48,7 @@ def set_output_volume(volume): salt '*' desktop.set_output_volume """ - cmd = 'osascript -e "set volume output volume {}"'.format(volume) + cmd = f'osascript -e "set volume output volume {volume}"' call = __salt__["cmd.run_all"](cmd, output_loglevel="debug", python_shell=False) _check_cmd(call) @@ -125,6 +125,6 @@ def _check_cmd(call): if std_out: comment += std_out - raise CommandExecutionError("Error running command: {}".format(comment)) + raise CommandExecutionError(f"Error running command: {comment}") return call diff --git a/salt/modules/mac_group.py b/salt/modules/mac_group.py index 44b57f25909..0f4337cb2c3 100644 --- a/salt/modules/mac_group.py +++ b/salt/modules/mac_group.py @@ -58,7 +58,7 @@ def add(name, gid=None, **kwargs): ### NOTE: **kwargs isn't used here but needs to be included in this ### function for compatibility with the group.present state if info(name): - raise CommandExecutionError("Group '{}' already exists".format(name)) + raise CommandExecutionError(f"Group '{name}' already exists") if salt.utils.stringutils.contains_whitespace(name): raise SaltInvocationError("Group name cannot contain whitespace") if name.startswith("_"): @@ -72,7 +72,7 @@ def add(name, gid=None, **kwargs): # check if gid is already in use gid_list = _list_gids() if str(gid) in gid_list: - raise CommandExecutionError("gid '{}' already exists".format(gid)) + raise CommandExecutionError(f"gid '{gid}' already exists") cmd = ["dseditgroup", "-o", "create"] if gid: @@ -130,7 +130,7 @@ def adduser(group, name): Verifies if a valid username 'bar' as a member of an existing group 'foo', if not then adds it. """ - cmd = "dscl . -merge /Groups/{} GroupMembership {}".format(group, name) + cmd = f"dscl . -merge /Groups/{group} GroupMembership {name}" return __salt__["cmd.retcode"](cmd) == 0 @@ -149,7 +149,7 @@ def deluser(group, name): Removes a member user 'bar' from a group 'foo'. If group is not present then returns True. """ - cmd = "dscl . -delete /Groups/{} GroupMembership {}".format(group, name) + cmd = f"dscl . -delete /Groups/{group} GroupMembership {name}" return __salt__["cmd.retcode"](cmd) == 0 @@ -170,7 +170,7 @@ def members(name, members_list): retcode = 1 grp_info = __salt__["group.info"](name) if grp_info and name in grp_info["name"]: - cmd = "/usr/bin/dscl . -delete /Groups/{} GroupMembership".format(name) + cmd = f"/usr/bin/dscl . -delete /Groups/{name} GroupMembership" retcode = __salt__["cmd.retcode"](cmd) == 0 for user in members_list.split(","): cmd = "/usr/bin/dscl . -merge /Groups/{} GroupMembership {}".format( @@ -255,7 +255,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) pre_info = info(name) if not pre_info: - raise CommandExecutionError("Group '{}' does not exist".format(name)) + raise CommandExecutionError(f"Group '{name}' does not exist") if gid == pre_info["gid"]: return True cmd = ["dseditgroup", "-o", "edit", "-i", gid, name] diff --git a/salt/modules/mac_pkgutil.py b/salt/modules/mac_pkgutil.py index 538db2fcf61..63c4bd46b43 100644 --- a/salt/modules/mac_pkgutil.py +++ b/salt/modules/mac_pkgutil.py @@ -68,10 +68,10 @@ def _install_from_path(path): Internal function to install a package from the given path """ if not os.path.exists(path): - msg = "File not found: {}".format(path) + msg = f"File not found: {path}" raise SaltInvocationError(msg) - cmd = 'installer -pkg "{}" -target /'.format(path) + cmd = f'installer -pkg "{path}" -target /' return salt.utils.mac_utils.execute_return_success(cmd) @@ -97,7 +97,7 @@ def install(source, package_id): uri = urllib.parse.urlparse(source) if not uri.scheme == "": - msg = "Unsupported scheme for source uri: {}".format(uri.scheme) + msg = f"Unsupported scheme for source uri: {uri.scheme}" raise SaltInvocationError(msg) _install_from_path(source) @@ -125,6 +125,6 @@ def forget(package_id): salt '*' pkgutil.forget com.apple.pkg.gcc4.2Leo """ - cmd = "pkgutil --forget {}".format(package_id) + cmd = f"pkgutil --forget {package_id}" salt.utils.mac_utils.execute_return_success(cmd) return not is_installed(package_id) diff --git a/salt/modules/mac_portspkg.py b/salt/modules/mac_portspkg.py index 70cb23039fb..2113af467d3 100644 --- a/salt/modules/mac_portspkg.py +++ b/salt/modules/mac_portspkg.py @@ -62,7 +62,7 @@ def __virtual__(): def _list(query=""): - cmd = "port list {}".format(query) + cmd = f"port list {query}" out = salt.utils.mac_utils.execute_return_result(cmd) ret = {} @@ -178,7 +178,7 @@ def latest_version(*names, **kwargs): ): ret[key] = val else: - ret[key] = "{} (installed)".format(version(key)) + ret[key] = f"{version(key)} (installed)" return ret diff --git a/salt/modules/mac_shadow.py b/salt/modules/mac_shadow.py index d116f3e2077..c484d5db967 100644 --- a/salt/modules/mac_shadow.py +++ b/salt/modules/mac_shadow.py @@ -54,13 +54,13 @@ def _get_account_policy(name): :raises: CommandExecutionError on user not found or any other unknown error """ - cmd = "pwpolicy -u {} -getpolicy".format(name) + cmd = f"pwpolicy -u {name} -getpolicy" try: ret = salt.utils.mac_utils.execute_return_result(cmd) except CommandExecutionError as exc: - if "Error: user <{}> not found".format(name) in exc.strerror: - raise CommandExecutionError("User not found: {}".format(name)) - raise CommandExecutionError("Unknown error: {}".format(exc.strerror)) + if f"Error: user <{name}> not found" in exc.strerror: + raise CommandExecutionError(f"User not found: {name}") + raise CommandExecutionError(f"Unknown error: {exc.strerror}") try: policy_list = ret.split("\n")[1].split(" ") @@ -86,14 +86,14 @@ def _set_account_policy(name, policy): :raises: CommandExecutionError on user not found or any other unknown error """ - cmd = 'pwpolicy -u {} -setpolicy "{}"'.format(name, policy) + cmd = f'pwpolicy -u {name} -setpolicy "{policy}"' try: return salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: - if "Error: user <{}> not found".format(name) in exc.strerror: - raise CommandExecutionError("User not found: {}".format(name)) - raise CommandExecutionError("Unknown error: {}".format(exc.strerror)) + if f"Error: user <{name}> not found" in exc.strerror: + raise CommandExecutionError(f"User not found: {name}") + raise CommandExecutionError(f"Unknown error: {exc.strerror}") def _get_account_policy_data_value(name, key): @@ -109,7 +109,7 @@ def _get_account_policy_data_value(name, key): :raises: CommandExecutionError on user not found or any other unknown error """ - cmd = "dscl . -readpl /Users/{} accountPolicyData {}".format(name, key) + cmd = f"dscl . -readpl /Users/{name} accountPolicyData {key}" try: ret = salt.utils.mac_utils.execute_return_result(cmd) except CommandExecutionError as exc: @@ -117,7 +117,7 @@ def _get_account_policy_data_value(name, key): raise CommandExecutionError(f"User not found: {name}") if "eDSUnknownMatchType" in exc.strerror: raise CommandExecutionError(f"Value not found: {key}") - raise CommandExecutionError("Unknown error: {}".format(exc.strerror)) + raise CommandExecutionError(f"Unknown error: {exc.strerror}") return ret @@ -327,7 +327,7 @@ def set_maxdays(name, days): """ minutes = days * 24 * 60 - _set_account_policy(name, "maxMinutesUntilChangePassword={}".format(minutes)) + _set_account_policy(name, f"maxMinutesUntilChangePassword={minutes}") return get_maxdays(name) == days @@ -441,7 +441,7 @@ def set_change(name, date): salt '*' shadow.set_change username 09/21/2016 """ - _set_account_policy(name, "usingExpirationDate=1 expirationDateGMT={}".format(date)) + _set_account_policy(name, f"usingExpirationDate=1 expirationDateGMT={date}") return get_change(name) == date @@ -492,9 +492,7 @@ def set_expire(name, date): salt '*' shadow.set_expire username 07/23/2015 """ - _set_account_policy( - name, "usingHardExpirationDate=1 hardExpireDateGMT={}".format(date) - ) + _set_account_policy(name, f"usingHardExpirationDate=1 hardExpireDateGMT={date}") return get_expire(name) == date @@ -542,16 +540,16 @@ def del_password(name): salt '*' shadow.del_password username """ # This removes the password - cmd = "dscl . -passwd /Users/{} ''".format(name) + cmd = f"dscl . -passwd /Users/{name} ''" try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "eDSUnknownNodeName" in exc.strerror: - raise CommandExecutionError("User not found: {}".format(name)) - raise CommandExecutionError("Unknown error: {}".format(exc.strerror)) + raise CommandExecutionError(f"User not found: {name}") + raise CommandExecutionError(f"Unknown error: {exc.strerror}") # This is so it looks right in shadow.info - cmd = "dscl . -create /Users/{} Password '*'".format(name) + cmd = f"dscl . -create /Users/{name} Password '*'" salt.utils.mac_utils.execute_return_success(cmd) return info(name)["passwd"] == "*" @@ -578,12 +576,12 @@ def set_password(name, password): salt '*' mac_shadow.set_password macuser macpassword """ - cmd = "dscl . -passwd /Users/{} '{}'".format(name, password) + cmd = f"dscl . -passwd /Users/{name} '{password}'" try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "eDSUnknownNodeName" in exc.strerror: - raise CommandExecutionError("User not found: {}".format(name)) - raise CommandExecutionError("Unknown error: {}".format(exc.strerror)) + raise CommandExecutionError(f"User not found: {name}") + raise CommandExecutionError(f"Unknown error: {exc.strerror}") return True diff --git a/salt/modules/mac_softwareupdate.py b/salt/modules/mac_softwareupdate.py index 3cb894e258c..9ca40a2417d 100644 --- a/salt/modules/mac_softwareupdate.py +++ b/salt/modules/mac_softwareupdate.py @@ -311,7 +311,7 @@ def update(name): salt '*' softwareupdate.update """ if not update_available(name): - raise SaltInvocationError("Update not available: {}".format(name)) + raise SaltInvocationError(f"Update not available: {name}") cmd = ["softwareupdate", "--install", name] salt.utils.mac_utils.execute_return_success(cmd) @@ -390,7 +390,7 @@ def download(name): salt '*' softwareupdate.download """ if not update_available(name): - raise SaltInvocationError("Update not available: {}".format(name)) + raise SaltInvocationError(f"Update not available: {name}") if name in list_downloads(): return True diff --git a/salt/modules/mac_sysctl.py b/salt/modules/mac_sysctl.py index 9fe3cc60f03..16f67e09a3b 100644 --- a/salt/modules/mac_sysctl.py +++ b/salt/modules/mac_sysctl.py @@ -66,14 +66,14 @@ def show(config_file=False): # # Yes. That's two `kern.clockrate`. # - if any([line.startswith("{}.".format(root)) for root in roots]): + if any([line.startswith(f"{root}.") for root in roots]): comps = line.split(": " if ": " in line else " = ", 1) if len(comps) == 2: ret[comps[0]] = comps[1] else: ret[comps[0]] = "" elif comps[0]: - ret[comps[0]] += "{}\n".format(line) + ret[comps[0]] += f"{line}\n" else: continue return ret @@ -92,7 +92,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd, python_shell=False) return out @@ -114,7 +114,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.icmp.icmplim 50 """ ret = {} - cmd = 'sysctl -w {}="{}"'.format(name, value) + cmd = f'sysctl -w {name}="{value}"' data = __salt__["cmd.run_all"](cmd, python_shell=False) if data["retcode"] != 0: @@ -165,7 +165,7 @@ def persist(name, value, config="/etc/sysctl.conf", apply_change=False): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - if not line.startswith("{}=".format(name)): + if not line.startswith(f"{name}="): nlines.append(line) continue else: @@ -179,10 +179,10 @@ def persist(name, value, config="/etc/sysctl.conf", apply_change=False): rest = rest[len(rest_v) :] if rest_v == value: return "Already set" - nlines.append("{}={}\n".format(name, value)) + nlines.append(f"{name}={value}\n") edited = True if not edited: - nlines.append("{}={}\n".format(name, value)) + nlines.append(f"{name}={value}\n") nlines = [salt.utils.stringutils.to_str(_l) for _l in nlines] with salt.utils.files.fopen(config, "w+") as ofile: ofile.writelines(nlines) diff --git a/salt/modules/mac_timezone.py b/salt/modules/mac_timezone.py index 5703ab08784..26549c44882 100644 --- a/salt/modules/mac_timezone.py +++ b/salt/modules/mac_timezone.py @@ -53,7 +53,7 @@ def _get_date_time_format(dt_string): return dt_format except ValueError: continue - msg = "Invalid Date/Time Format: {}".format(dt_string) + msg = f"Invalid Date/Time Format: {dt_string}" raise SaltInvocationError(msg) @@ -237,11 +237,9 @@ def set_zone(time_zone): salt '*' timezone.set_zone America/Denver """ if time_zone not in list_zones(): - raise SaltInvocationError("Invalid Timezone: {}".format(time_zone)) + raise SaltInvocationError(f"Invalid Timezone: {time_zone}") - salt.utils.mac_utils.execute_return_success( - "systemsetup -settimezone {}".format(time_zone) - ) + salt.utils.mac_utils.execute_return_success(f"systemsetup -settimezone {time_zone}") return time_zone in get_zone() @@ -303,7 +301,7 @@ def set_using_network_time(enable): """ state = salt.utils.mac_utils.validate_enabled(enable) - cmd = "systemsetup -setusingnetworktime {}".format(state) + cmd = f"systemsetup -setusingnetworktime {state}" salt.utils.mac_utils.execute_return_success(cmd) return state == salt.utils.mac_utils.validate_enabled(get_using_network_time()) @@ -349,7 +347,7 @@ def set_time_server(time_server="time.apple.com"): salt '*' timezone.set_time_server time.acme.com """ - cmd = "systemsetup -setnetworktimeserver {}".format(time_server) + cmd = f"systemsetup -setnetworktimeserver {time_server}" salt.utils.mac_utils.execute_return_success(cmd) return time_server in get_time_server() diff --git a/salt/modules/mac_user.py b/salt/modules/mac_user.py index 7e4f1b25965..d5fd6e98665 100644 --- a/salt/modules/mac_user.py +++ b/salt/modules/mac_user.py @@ -79,7 +79,7 @@ def add( shell=None, fullname=None, createhome=True, - **kwargs + **kwargs, ): """ Add a user to the minion @@ -91,7 +91,7 @@ def add( salt '*' user.add name """ if info(name): - raise CommandExecutionError("User '{}' already exists".format(name)) + raise CommandExecutionError(f"User '{name}' already exists") if salt.utils.stringutils.contains_whitespace(name): raise SaltInvocationError("Username cannot contain whitespace") @@ -101,7 +101,7 @@ def add( if gid is None: gid = 20 # gid 20 == 'staff', the default group if home is None: - home = "/Users/{}".format(name) + home = f"/Users/{name}" if shell is None: shell = "/bin/bash" if fullname is None: @@ -112,7 +112,7 @@ def add( if not isinstance(gid, int): raise SaltInvocationError("gid must be an integer") - name_path = "/Users/{}".format(name) + name_path = f"/Users/{name}" _dscl([name_path, "UniqueID", uid]) _dscl([name_path, "PrimaryGroupID", gid]) _dscl([name_path, "UserShell", shell]) @@ -155,7 +155,7 @@ def delete(name, remove=False, force=False): # group membership is managed separately from users and an entry for the # user will persist even after the user is removed. chgroups(name, ()) - ret = _dscl(["/Users/{}".format(name)], ctype="delete")["retcode"] == 0 + ret = _dscl([f"/Users/{name}"], ctype="delete")["retcode"] == 0 if ret and remove: # remove home directory from filesystem __salt__["file.remove"](user_info["home"]) @@ -196,10 +196,10 @@ def chuid(name, uid): raise SaltInvocationError("uid must be an integer") pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if uid == pre_info["uid"]: return True - _dscl(["/Users/{}".format(name), "UniqueID", pre_info["uid"], uid], ctype="change") + _dscl([f"/Users/{name}", "UniqueID", pre_info["uid"], uid], ctype="change") # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) @@ -220,11 +220,11 @@ def chgid(name, gid): raise SaltInvocationError("gid must be an integer") pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if gid == pre_info["gid"]: return True _dscl( - ["/Users/{}".format(name), "PrimaryGroupID", pre_info["gid"], gid], + [f"/Users/{name}", "PrimaryGroupID", pre_info["gid"], gid], ctype="change", ) # dscl buffers changes, sleep 1 second before checking if new value @@ -245,11 +245,11 @@ def chshell(name, shell): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if shell == pre_info["shell"]: return True _dscl( - ["/Users/{}".format(name), "UserShell", pre_info["shell"], shell], + [f"/Users/{name}", "UserShell", pre_info["shell"], shell], ctype="change", ) # dscl buffers changes, sleep 1 second before checking if new value @@ -277,11 +277,11 @@ def chhome(name, home, **kwargs): pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if home == pre_info["home"]: return True _dscl( - ["/Users/{}".format(name), "NFSHomeDirectory", pre_info["home"], home], + [f"/Users/{name}", "NFSHomeDirectory", pre_info["home"], home], ctype="change", ) # dscl buffers changes, sleep 1 second before checking if new value @@ -303,12 +303,12 @@ def chfullname(name, fullname): fullname = salt.utils.data.decode(fullname) pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") pre_info["fullname"] = salt.utils.data.decode(pre_info["fullname"]) if fullname == pre_info["fullname"]: return True _dscl( - ["/Users/{}".format(name), "RealName", fullname], + [f"/Users/{name}", "RealName", fullname], # use a 'create' command, because a 'change' command would fail if # current fullname is an empty string. The 'create' will just overwrite # this field. @@ -346,7 +346,7 @@ def chgroups(name, groups, append=False): ### function for compatibility with the user.present state uinfo = info(name) if not uinfo: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if isinstance(groups, str): groups = groups.split(",") @@ -364,11 +364,11 @@ def chgroups(name, groups, append=False): return True # Add groups from which user is missing for group in desired - ugrps: - _dscl(["/Groups/{}".format(group), "GroupMembership", name], ctype="append") + _dscl([f"/Groups/{group}", "GroupMembership", name], ctype="append") if not append: # Remove from extra groups for group in ugrps - desired: - _dscl(["/Groups/{}".format(group), "GroupMembership", name], ctype="delete") + _dscl([f"/Groups/{group}", "GroupMembership", name], ctype="delete") time.sleep(1) return set(list_groups(name)) == desired @@ -472,11 +472,11 @@ def rename(name, new_name): """ current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) - _dscl(["/Users/{}".format(name), "RecordName", name, new_name], ctype="change") + raise CommandExecutionError(f"User '{new_name}' already exists") + _dscl([f"/Users/{name}", "RecordName", name, new_name], ctype="change") # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) diff --git a/salt/modules/mac_xattr.py b/salt/modules/mac_xattr.py index e2bbf1c503a..b7b742965a6 100644 --- a/salt/modules/mac_xattr.py +++ b/salt/modules/mac_xattr.py @@ -60,8 +60,8 @@ def list_(path, **kwargs): ret = salt.utils.mac_utils.execute_return_result(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"File not found: {path}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") if not ret: return {} @@ -115,10 +115,10 @@ def read(path, attribute, **kwargs): return exc.object.decode(errors="replace") except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) + raise CommandExecutionError(f"File not found: {path}") if "No such xattr" in exc.strerror: - raise CommandExecutionError("Attribute not found: {}".format(attribute)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"Attribute not found: {attribute}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return ret @@ -161,8 +161,8 @@ def write(path, attribute, value, **kwargs): salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"File not found: {path}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return read(path, attribute, **{"hex": hex_}) == value @@ -188,15 +188,15 @@ def delete(path, attribute): salt '*' xattr.delete /path/to/file "com.test.attr" """ - cmd = 'xattr -d "{}" "{}"'.format(attribute, path) + cmd = f'xattr -d "{attribute}" "{path}"' try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) + raise CommandExecutionError(f"File not found: {path}") if "No such xattr" in exc.strerror: - raise CommandExecutionError("Attribute not found: {}".format(attribute)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"Attribute not found: {attribute}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return attribute not in list_(path) @@ -217,12 +217,12 @@ def clear(path): salt '*' xattr.delete /path/to/file "com.test.attr" """ - cmd = 'xattr -c "{}"'.format(path) + cmd = f'xattr -c "{path}"' try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"File not found: {path}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return list_(path) == {} diff --git a/salt/modules/macdefaults.py b/salt/modules/macdefaults.py index c805536fdd7..77f0e580afc 100644 --- a/salt/modules/macdefaults.py +++ b/salt/modules/macdefaults.py @@ -56,7 +56,7 @@ def write(domain, key, value, type="string", user=None): elif value is False: value = "FALSE" - cmd = 'defaults write "{}" "{}" -{} "{}"'.format(domain, key, type, value) + cmd = f'defaults write "{domain}" "{key}" -{type} "{value}"' return __salt__["cmd.run_all"](cmd, runas=user) @@ -82,7 +82,7 @@ def read(domain, key, user=None): The user to read the defaults as """ - cmd = 'defaults read "{}" "{}"'.format(domain, key) + cmd = f'defaults read "{domain}" "{key}"' return __salt__["cmd.run"](cmd, runas=user) @@ -108,5 +108,5 @@ def delete(domain, key, user=None): The user to delete the defaults with """ - cmd = 'defaults delete "{}" "{}"'.format(domain, key) + cmd = f'defaults delete "{domain}" "{key}"' return __salt__["cmd.run_all"](cmd, runas=user, output_loglevel="debug") diff --git a/salt/modules/makeconf.py b/salt/modules/makeconf.py index 446a72cfd31..b95d3b7bf23 100644 --- a/salt/modules/makeconf.py +++ b/salt/modules/makeconf.py @@ -42,7 +42,7 @@ def _add_var(var, value): """ makeconf = _get_makeconf() layman = "source /var/lib/layman/make.conf" - fullvar = '{}="{}"'.format(var, value) + fullvar = f'{var}="{value}"' if __salt__["file.contains"](makeconf, layman): # TODO perhaps make this a function in the file module? cmd = [ @@ -77,9 +77,7 @@ def set_var(var, value): # If var already in file, replace its value if old_value is not None: - __salt__["file.sed"]( - makeconf, "^{}=.*".format(var), '{}="{}"'.format(var, value) - ) + __salt__["file.sed"](makeconf, f"^{var}=.*", f'{var}="{value}"') else: _add_var(var, value) @@ -108,7 +106,7 @@ def remove_var(var): # If var is in file if old_value is not None: - __salt__["file.sed"](makeconf, "^{}=.*".format(var), "") + __salt__["file.sed"](makeconf, f"^{var}=.*", "") new_value = get_var(var) return {var: {"old": old_value, "new": new_value}} @@ -135,10 +133,8 @@ def append_var(var, value): # If var already in file, add to its value if old_value is not None: - appended_value = "{} {}".format(old_value, value) - __salt__["file.sed"]( - makeconf, "^{}=.*".format(var), '{}="{}"'.format(var, appended_value) - ) + appended_value = f"{old_value} {value}" + __salt__["file.sed"](makeconf, f"^{var}=.*", f'{var}="{appended_value}"') else: _add_var(var, value) diff --git a/salt/modules/marathon.py b/salt/modules/marathon.py index 04e910dd5fd..6c2c73b429a 100644 --- a/salt/modules/marathon.py +++ b/salt/modules/marathon.py @@ -43,7 +43,7 @@ def _app_id(app_id): Make sure the app_id is in the correct format. """ if app_id[0] != "/": - app_id = "/{}".format(app_id) + app_id = f"/{app_id}" return app_id @@ -58,7 +58,7 @@ def apps(): salt marathon-minion-id marathon.apps """ response = salt.utils.http.query( - "{}/v2/apps".format(_base_url()), + f"{_base_url()}/v2/apps", decode_type="json", decode=True, ) @@ -89,7 +89,7 @@ def app(id): salt marathon-minion-id marathon.app my-app """ response = salt.utils.http.query( - "{}/v2/apps/{}".format(_base_url(), id), + f"{_base_url()}/v2/apps/{id}", decode_type="json", decode=True, ) @@ -115,7 +115,7 @@ def update_app(id, config): data = salt.utils.json.dumps(config) try: response = salt.utils.http.query( - "{}/v2/apps/{}?force=true".format(_base_url(), id), + f"{_base_url()}/v2/apps/{id}?force=true", method="PUT", decode_type="json", decode=True, @@ -143,7 +143,7 @@ def rm_app(id): salt marathon-minion-id marathon.rm_app my-app """ response = salt.utils.http.query( - "{}/v2/apps/{}".format(_base_url(), id), + f"{_base_url()}/v2/apps/{id}", method="DELETE", decode_type="json", decode=True, @@ -162,7 +162,7 @@ def info(): salt marathon-minion-id marathon.info """ response = salt.utils.http.query( - "{}/v2/info".format(_base_url()), + f"{_base_url()}/v2/info", decode_type="json", decode=True, ) @@ -201,7 +201,7 @@ def restart_app(id, restart=False, force=True): return ret try: response = salt.utils.http.query( - "{}/v2/apps/{}/restart?force={}".format(_base_url(), _app_id(id), force), + f"{_base_url()}/v2/apps/{_app_id(id)}/restart?force={force}", method="POST", decode_type="json", decode=True, diff --git a/salt/modules/mdadm_raid.py b/salt/modules/mdadm_raid.py index 7333101cbaa..85e5d1e6247 100644 --- a/salt/modules/mdadm_raid.py +++ b/salt/modules/mdadm_raid.py @@ -143,7 +143,7 @@ def destroy(device): cfg_file = "/etc/mdadm.conf" try: - __salt__["file.replace"](cfg_file, "ARRAY {} .*".format(device), "") + __salt__["file.replace"](cfg_file, f"ARRAY {device} .*", "") except SaltInvocationError: pass @@ -230,7 +230,7 @@ def create(name, level, devices, metadata="default", test_mode=False, **kwargs): for key in kwargs: if not key.startswith("__"): - opts.append("--{}".format(key)) + opts.append(f"--{key}") if kwargs[key] is not True: opts.append(str(kwargs[key])) if key == "spare-devices": @@ -275,7 +275,7 @@ def save_config(): buggy_ubuntu_tags = ["name", "metadata"] for i, elem in enumerate(scan): for bad_tag in buggy_ubuntu_tags: - pattern = r"\s{}=\S+".format(re.escape(bad_tag)) + pattern = rf"\s{re.escape(bad_tag)}=\S+" pattern = re.compile(pattern, flags=re.I) scan[i] = re.sub(pattern, "", scan[i]) @@ -335,7 +335,7 @@ def assemble(name, devices, test_mode=False, **kwargs): opts = [] for key in kwargs: if not key.startswith("__"): - opts.append("--{}".format(key)) + opts.append(f"--{key}") if kwargs[key] is not True: opts.append(kwargs[key]) @@ -368,7 +368,7 @@ def examine(device, quiet=False): salt '*' raid.examine '/dev/sda1' """ res = __salt__["cmd.run_stdout"]( - "mdadm -Y -E {}".format(device), python_shell=False, ignore_retcode=quiet + f"mdadm -Y -E {device}", python_shell=False, ignore_retcode=quiet ) ret = {} @@ -390,7 +390,7 @@ def add(name, device): """ - cmd = "mdadm --manage {} --add {}".format(name, device) + cmd = f"mdadm --manage {name} --add {device}" if __salt__["cmd.retcode"](cmd) == 0: return True return False diff --git a/salt/modules/mdata.py b/salt/modules/mdata.py index 8075922a5ef..94415b7c39b 100644 --- a/salt/modules/mdata.py +++ b/salt/modules/mdata.py @@ -68,7 +68,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on SmartOS zones".format(__virtualname__), + f"{__virtualname__} module can only be loaded on SmartOS zones", ) @@ -84,7 +84,7 @@ def list_(): """ mdata = _check_mdata_list() if mdata: - cmd = "{}".format(mdata) + cmd = f"{mdata}" return __salt__["cmd.run"](cmd, ignore_retcode=True).splitlines() return {} @@ -115,7 +115,7 @@ def get_(*keyname): for k in keyname: if mdata: - cmd = "{} {}".format(mdata, k) + cmd = f"{mdata} {k}" res = __salt__["cmd.run_all"](cmd, ignore_retcode=True) ret[k] = res["stdout"] if res["retcode"] == 0 else "" else: @@ -143,7 +143,7 @@ def put_(keyname, val): ret = {} if mdata: - cmd = "echo {2} | {0} {1}".format(mdata, keyname, val) + cmd = f"echo {val} | {mdata} {keyname}" ret = __salt__["cmd.run_all"](cmd, python_shell=True, ignore_retcode=True) return ret["retcode"] == 0 @@ -169,7 +169,7 @@ def delete_(*keyname): for k in keyname: if mdata and k in valid_keynames: - cmd = "{} {}".format(mdata, k) + cmd = f"{mdata} {k}" ret[k] = __salt__["cmd.run_all"](cmd, ignore_retcode=True)["retcode"] == 0 else: ret[k] = True diff --git a/salt/modules/memcached.py b/salt/modules/memcached.py index d8c2cf6d01b..4c6cc558e18 100644 --- a/salt/modules/memcached.py +++ b/salt/modules/memcached.py @@ -51,7 +51,7 @@ def _connect(host=DEFAULT_HOST, port=DEFAULT_PORT): values assigned to missing values. """ if str(port).isdigit(): - return memcache.Client(["{}:{}".format(host, port)], debug=0) + return memcache.Client([f"{host}:{port}"], debug=0) raise SaltInvocationError("port must be an integer") @@ -214,10 +214,10 @@ def increment(key, delta=1, host=DEFAULT_HOST, port=DEFAULT_PORT): cur = get(key) if cur is None: - raise CommandExecutionError("Key '{}' does not exist".format(key)) + raise CommandExecutionError(f"Key '{key}' does not exist") elif not isinstance(cur, int): raise CommandExecutionError( - "Value for key '{}' must be an integer to be incremented".format(key) + f"Value for key '{key}' must be an integer to be incremented" ) try: @@ -245,10 +245,10 @@ def decrement(key, delta=1, host=DEFAULT_HOST, port=DEFAULT_PORT): cur = get(key) if cur is None: - raise CommandExecutionError("Key '{}' does not exist".format(key)) + raise CommandExecutionError(f"Key '{key}' does not exist") elif not isinstance(cur, int): raise CommandExecutionError( - "Value for key '{}' must be an integer to be decremented".format(key) + f"Value for key '{key}' must be an integer to be decremented" ) try: diff --git a/salt/modules/minion.py b/salt/modules/minion.py index e93b2783c80..bed8f437f75 100644 --- a/salt/modules/minion.py +++ b/salt/modules/minion.py @@ -212,12 +212,12 @@ def restart(): restart_cmd = __salt__["config.get"]("minion_restart_command") if restart_cmd: comment.append("Using configuration minion_restart_command:") - comment.extend([" {}".format(arg) for arg in restart_cmd]) + comment.extend([f" {arg}" for arg in restart_cmd]) else: if "-d" in sys.argv: restart_cmd = sys.argv comment.append("Restart using process argv:") - comment.extend([" {}".format(arg) for arg in restart_cmd]) + comment.extend([f" {arg}" for arg in restart_cmd]) else: should_restart = False comment.append( diff --git a/salt/modules/modjk.py b/salt/modules/modjk.py index 9b1ec755f61..fb968a7a986 100644 --- a/salt/modules/modjk.py +++ b/salt/modules/modjk.py @@ -60,25 +60,25 @@ def _do_http(opts, profile="default"): ret = {} - url = __salt__["config.get"]("modjk:{}:url".format(profile), "") - user = __salt__["config.get"]("modjk:{}:user".format(profile), "") - passwd = __salt__["config.get"]("modjk:{}:pass".format(profile), "") - realm = __salt__["config.get"]("modjk:{}:realm".format(profile), "") - timeout = __salt__["config.get"]("modjk:{}:timeout".format(profile), "") + url = __salt__["config.get"](f"modjk:{profile}:url", "") + user = __salt__["config.get"](f"modjk:{profile}:user", "") + passwd = __salt__["config.get"](f"modjk:{profile}:pass", "") + realm = __salt__["config.get"](f"modjk:{profile}:realm", "") + timeout = __salt__["config.get"](f"modjk:{profile}:timeout", "") if not url: - raise Exception("missing url in profile {}".format(profile)) + raise Exception(f"missing url in profile {profile}") if user and passwd: auth = _auth(url=url, realm=realm, user=user, passwd=passwd) urllib.request.install_opener(auth) - url += "?{}".format(urllib.parse.urlencode(opts)) + url += f"?{urllib.parse.urlencode(opts)}" for line in urllib.request.urlopen(url, timeout=timeout).read().splitlines(): splt = line.split("=", 1) if splt[0] in ret: - ret[splt[0]] += ",{}".format(splt[1]) + ret[splt[0]] += f",{splt[1]}" else: ret[splt[0]] = splt[1] @@ -172,7 +172,7 @@ def list_configured_members(lbn, profile="default"): config = dump_config(profile) try: - ret = config["worker.{}.balance_workers".format(lbn)] + ret = config[f"worker.{lbn}.balance_workers"] except KeyError: return [] @@ -198,9 +198,7 @@ def workers(profile="default"): for lb in lbn: try: - worker_list.extend( - config["worker.{}.balance_workers".format(lb)].split(",") - ) + worker_list.extend(config[f"worker.{lb}.balance_workers"].split(",")) except KeyError: pass @@ -208,8 +206,8 @@ def workers(profile="default"): for worker in worker_list: ret[worker] = { - "activation": config["worker.{}.activation".format(worker)], - "state": config["worker.{}.state".format(worker)], + "activation": config[f"worker.{worker}.activation"], + "state": config[f"worker.{worker}.state"], } return ret @@ -230,7 +228,7 @@ def recover_all(lbn, profile="default"): ret = {} config = get_running(profile) try: - workers_ = config["worker.{}.balance_workers".format(lbn)].split(",") + workers_ = config[f"worker.{lbn}.balance_workers"].split(",") except KeyError: return ret @@ -418,8 +416,8 @@ def worker_status(worker, profile="default"): config = get_running(profile) try: return { - "activation": config["worker.{}.activation".format(worker)], - "state": config["worker.{}.state".format(worker)], + "activation": config[f"worker.{worker}.activation"], + "state": config[f"worker.{worker}.state"], } except KeyError: return False diff --git a/salt/modules/mongodb.py b/salt/modules/mongodb.py index 72b0ff00747..699dcfd48e9 100644 --- a/salt/modules/mongodb.py +++ b/salt/modules/mongodb.py @@ -236,7 +236,7 @@ def version( """ conn = _connect(user, password, host, port, authdb=authdb) if not conn: - err_msg = "Failed to connect to MongoDB database {}:{}".format(host, port) + err_msg = f"Failed to connect to MongoDB database {host}:{port}" log.error(err_msg) return (False, err_msg) @@ -283,7 +283,7 @@ def user_find( """ conn = _connect(user, password, host, port, authdb=authdb) if not conn: - err_msg = "Failed to connect to MongoDB database {}:{}".format(host, port) + err_msg = f"Failed to connect to MongoDB database {host}:{port}" log.error(err_msg) return (False, err_msg) @@ -993,7 +993,7 @@ def update_one( col = getattr(mdb, collection) ids = col.update_one(_id_field, {"$set": _update_doc}) nb_mod = ids.modified_count - return "{} objects updated".format(nb_mod) + return f"{nb_mod} objects updated" except pymongo.errors.PyMongoError as err: log.error("Updating object %s failed with error %s", objects, err) return err @@ -1139,7 +1139,7 @@ def remove( for count in range(0, w): res = col.delete_one(query) deleted_count += res.deleted_count - return "{} objects removed".format(deleted_count) + return f"{deleted_count} objects removed" except pymongo.errors.PyMongoError as err: log.error("Removing objects failed with error: %s", _get_error_message(err)) return _get_error_message(err) diff --git a/salt/modules/monit.py b/salt/modules/monit.py index 65d9da8286c..3f685f6f5d9 100644 --- a/salt/modules/monit.py +++ b/salt/modules/monit.py @@ -34,7 +34,7 @@ def start(name): salt '*' monit.start """ - cmd = "monit start {}".format(name) + cmd = f"monit start {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -49,7 +49,7 @@ def stop(name): salt '*' monit.stop """ - cmd = "monit stop {}".format(name) + cmd = f"monit stop {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -64,7 +64,7 @@ def restart(name): salt '*' monit.restart """ - cmd = "monit restart {}".format(name) + cmd = f"monit restart {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -79,7 +79,7 @@ def unmonitor(name): salt '*' monit.unmonitor """ - cmd = "monit unmonitor {}".format(name) + cmd = f"monit unmonitor {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -94,7 +94,7 @@ def monitor(name): salt '*' monit.monitor """ - cmd = "monit monitor {}".format(name) + cmd = f"monit monitor {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) diff --git a/salt/modules/mount.py b/salt/modules/mount.py index f27575fc8ed..f898c32e214 100644 --- a/salt/modules/mount.py +++ b/salt/modules/mount.py @@ -196,7 +196,7 @@ def _active_mounts_openbsd(ret): comps = re.sub(r"\s+", " ", line).split() parens = re.findall(r"\((.*?)\)", line, re.DOTALL) if len(parens) > 1: - nod = __salt__["cmd.run_stdout"]("ls -l {}".format(comps[0])) + nod = __salt__["cmd.run_stdout"](f"ls -l {comps[0]}") nod = " ".join(nod.split()).split(" ") ret[comps[3]] = { "device": comps[0], @@ -305,7 +305,7 @@ class _fstab_entry: @classmethod def dict_from_line(cls, line, keys=fstab_keys): if len(keys) != 6: - raise ValueError("Invalid key array: {}".format(keys)) + raise ValueError(f"Invalid key array: {keys}") if line.startswith("#"): raise cls.ParseError("Comment!") @@ -522,12 +522,12 @@ class _FileSystemsEntry: @classmethod def dict_from_lines(cls, lines, keys=filesystems_keys): if len(lines) < 2: - raise ValueError("Invalid number of lines: {}".format(lines)) + raise ValueError(f"Invalid number of lines: {lines}") if not keys: # if empty force default filesystems_keys keys = _FileSystemsEntry.filesystems_keys elif len(keys) < 6: - raise ValueError("Invalid key name array: {}".format(keys)) + raise ValueError(f"Invalid key name array: {keys}") blk_lines = lines orddict = OrderedDict() @@ -545,9 +545,7 @@ class _FileSystemsEntry: if key_name in keys: orddict[key_name] = comps[1].strip() else: - raise ValueError( - "Invalid name for use in filesystems: {}".format(key_name) - ) + raise ValueError(f"Invalid name for use in filesystems: {key_name}") return orddict @@ -574,7 +572,7 @@ class _FileSystemsEntry: strg_out = entry["name"] + ":" + os.linesep for k, v in entry.items(): if "name" not in k: - strg_out += "\t{}\t\t= {}".format(k, v) + os.linesep + strg_out += f"\t{k}\t\t= {v}" + os.linesep strg_out += os.linesep return str(strg_out) @@ -585,7 +583,7 @@ class _FileSystemsEntry: list_out.append(str(entry["name"] + ":" + os.linesep)) for k, v in entry.items(): if "name" not in k: - list_out.append(str("\t{}\t\t= {}".format(k, v) + os.linesep)) + list_out.append(str(f"\t{k}\t\t= {v}" + os.linesep)) list_out.append(str(os.linesep)) return list_out @@ -792,7 +790,7 @@ def set_fstab( test=False, match_on="auto", not_change=False, - **kwargs + **kwargs, ): """ Verify that this mount is represented in the fstab, change the mount @@ -871,12 +869,12 @@ def set_fstab( invalid_keys = filter(filterFn, match_on) - msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) + msg = f'Unrecognized keys in match_on: "{invalid_keys}"' raise CommandExecutionError(msg) # parse file, use ret to cache status if not os.path.isfile(config): - raise CommandExecutionError('Bad config file "{}"'.format(config)) + raise CommandExecutionError(f'Bad config file "{config}"') try: with salt.utils.files.fopen(config, "r") as ifile: @@ -932,7 +930,7 @@ def set_vfstab( test=False, match_on="auto", not_change=False, - **kwargs + **kwargs, ): """ .. versionadded:: 2016.3.2 @@ -1004,12 +1002,12 @@ def set_vfstab( invalid_keys = filter(filterFn, match_on) - msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) + msg = f'Unrecognized keys in match_on: "{invalid_keys}"' raise CommandExecutionError(msg) # parse file, use ret to cache status if not os.path.isfile(config): - raise CommandExecutionError('Bad config file "{}"'.format(config)) + raise CommandExecutionError(f'Bad config file "{config}"') try: with salt.utils.files.fopen(config, "r") as ifile: @@ -1122,7 +1120,7 @@ def set_automaster( config="/etc/auto_salt", test=False, not_change=False, - **kwargs + **kwargs, ): """ Verify that this mount is represented in the auto_salt, change the mount @@ -1144,11 +1142,11 @@ def set_automaster( if not os.path.isfile(config): __salt__["file.touch"](config) - __salt__["file.append"](automaster_file, "/-\t\t\t{}".format(config)) + __salt__["file.append"](automaster_file, f"/-\t\t\t{config}") - name = "/..{}".format(name) - device_fmt = "{}:{}".format(fstype, device) - type_opts = "-fstype={},{}".format(fstype, opts) + name = f"/..{name}" + device_fmt = f"{fstype}:{device}" + type_opts = f"-fstype={fstype},{opts}" if fstype == "smbfs": device_fmt = device_fmt.replace(fstype, "") @@ -1190,7 +1188,7 @@ def set_automaster( "auto_master entry for mount point %s needs to be updated", name, ) - newline = "{}\t{}\t{}\n".format(name, type_opts, device_fmt) + newline = f"{name}\t{type_opts}\t{device_fmt}\n" lines.append(newline) else: lines.append(line) @@ -1217,14 +1215,14 @@ def set_automaster( else: if not salt.utils.args.test_mode(test=test, **kwargs): # The entry is new, add it to the end of the fstab - newline = "{}\t{}\t{}\n".format(name, type_opts, device_fmt) + newline = f"{name}\t{type_opts}\t{device_fmt}\n" lines.append(newline) try: with salt.utils.files.fopen(config, "wb") as ofile: # The line was changed, commit it! ofile.writelines(salt.utils.data.encode(lines)) except OSError: - raise CommandExecutionError("File not writable {}".format(config)) + raise CommandExecutionError(f"File not writable {config}") return "new" @@ -1285,7 +1283,7 @@ def mount( if not mnt: return False first = next(iter(mnt.keys())) - __context__["img.mnt_{}".format(first)] = mnt + __context__[f"img.mnt_{first}"] = mnt return first return False @@ -1302,24 +1300,24 @@ def mount( args = "" if opts is not None: lopts = ",".join(opts) - args = "-o {}".format(lopts) + args = f"-o {lopts}" if fstype: # use of fstype on AIX differs from typical Linux use of -t # functionality AIX uses -v vfsname, -t fstype mounts all with # fstype in /etc/filesystems if "AIX" in __grains__["os"]: - args += " -v {}".format(fstype) + args += f" -v {fstype}" elif "solaris" in __grains__["os"].lower(): - args += " -F {}".format(fstype) + args += f" -F {fstype}" else: - args += " -t {}".format(fstype) + args += f" -t {fstype}" cmd = "mount " if device: - cmd += "{} '{}' '{}' ".format(args, device, name) + cmd += f"{args} '{device}' '{name}' " else: - cmd += "'{}' ".format(name) + cmd += f"'{name}' " out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False) if out["retcode"]: return out["stderr"] @@ -1365,23 +1363,23 @@ def remount(name, device, mkmnt=False, fstype="", opts="defaults", user=None): args = "" if opts: lopts = ",".join(opts) - args = "-o {}".format(lopts) + args = f"-o {lopts}" if fstype: # use of fstype on AIX differs from typical Linux use of # -t functionality AIX uses -v vfsname, -t fstype mounts # all with fstype in /etc/filesystems if "AIX" in __grains__["os"]: - args += " -v {}".format(fstype) + args += f" -v {fstype}" elif "solaris" in __grains__["os"].lower(): - args += " -F {}".format(fstype) + args += f" -F {fstype}" else: - args += " -t {}".format(fstype) + args += f" -t {fstype}" if __grains__["os"] not in ["OpenBSD", "MacOS", "Darwin"] or force_mount: - cmd = "mount {} '{}' '{}' ".format(args, device, name) + cmd = f"mount {args} '{device}' '{name}' " else: - cmd = "mount -u {} '{}' '{}' ".format(args, device, name) + cmd = f"mount -u {args} '{device}' '{name}' " out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False) if out["retcode"]: return out["stderr"] @@ -1412,18 +1410,18 @@ def umount(name, device=None, user=None, util="mount"): elif util == "qemu_nbd": # This functionality used to live in img.umount_image if "qemu_nbd.clear" in __salt__: - if "img.mnt_{}".format(name) in __context__: - __salt__["qemu_nbd.clear"](__context__["img.mnt_{}".format(name)]) + if f"img.mnt_{name}" in __context__: + __salt__["qemu_nbd.clear"](__context__[f"img.mnt_{name}"]) return mnts = active() if name not in mnts: - return "{} does not have anything mounted".format(name) + return f"{name} does not have anything mounted" if not device: - cmd = "umount '{}'".format(name) + cmd = f"umount '{name}'" else: - cmd = "umount '{}'".format(device) + cmd = f"umount '{device}'" out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False) if out["retcode"]: return out["stderr"] @@ -1448,7 +1446,7 @@ def is_fuse_exec(cmd): elif not salt.utils.path.which("ldd"): raise CommandNotFoundError("ldd") - out = __salt__["cmd.run"]("ldd {}".format(cmd_path), python_shell=False) + out = __salt__["cmd.run"](f"ldd {cmd_path}", python_shell=False) return "libfuse" in out @@ -1540,13 +1538,13 @@ def swapon(name, priority=None): if __grains__["kernel"] == "SunOS": if __grains__["virtual"] != "zone": - __salt__["cmd.run"]("swap -a '{}'".format(name), python_shell=False) + __salt__["cmd.run"](f"swap -a '{name}'", python_shell=False) else: return False else: - cmd = "swapon '{}'".format(name) + cmd = f"swapon '{name}'" if priority and "AIX" not in __grains__["kernel"]: - cmd += " -p {}".format(priority) + cmd += f" -p {priority}" __salt__["cmd.run"](cmd, python_shell=False) on_ = swaps() @@ -1574,13 +1572,13 @@ def swapoff(name): if name in on_: if __grains__["kernel"] == "SunOS": if __grains__["virtual"] != "zone": - __salt__["cmd.run"]("swap -a '{}'".format(name), python_shell=False) + __salt__["cmd.run"](f"swap -a '{name}'", python_shell=False) else: return False elif __grains__["os"] != "OpenBSD": - __salt__["cmd.run"]("swapoff '{}'".format(name), python_shell=False) + __salt__["cmd.run"](f"swapoff '{name}'", python_shell=False) else: - __salt__["cmd.run"]("swapctl -d '{}'".format(name), python_shell=False) + __salt__["cmd.run"](f"swapctl -d '{name}'", python_shell=False) on_ = swaps() if name in on_: return False @@ -1784,7 +1782,7 @@ def set_filesystems( test=False, match_on="auto", not_change=False, - **kwargs + **kwargs, ): """ .. versionadded:: 2018.3.3 @@ -1888,13 +1886,11 @@ def set_filesystems( return key not in _FileSystemsEntry.compatibility_keys invalid_keys = filter(filterFn, match_on) - raise CommandExecutionError( - 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) - ) + raise CommandExecutionError(f'Unrecognized keys in match_on: "{invalid_keys}"') # parse file, use ret to cache status if not os.path.isfile(config): - raise CommandExecutionError('Bad config file "{}"'.format(config)) + raise CommandExecutionError(f'Bad config file "{config}"') # read in block of filesystem, block starts with '/' till empty line try: @@ -1912,7 +1908,7 @@ def set_filesystems( view_lines.append(fsys_view) except OSError as exc: - raise CommandExecutionError("Couldn't read from {}: {}".format(config, exc)) + raise CommandExecutionError(f"Couldn't read from {config}: {exc}") # add line if not present or changed if ret is None: @@ -1930,7 +1926,7 @@ def set_filesystems( ofile.writelines(salt.utils.data.encode(list_strgs)) except OSError: - raise CommandExecutionError("File not writable {}".format(config)) + raise CommandExecutionError(f"File not writable {config}") except Exception as exc: raise CommandExecutionError("set_filesystems error exception {exc}") @@ -1969,7 +1965,7 @@ def rm_filesystems(name, device, config="/etc/filesystems"): view_lines.append(fsys_view) except OSError as exc: - raise CommandExecutionError("Couldn't read from {}: {}".format(config, exc)) + raise CommandExecutionError(f"Couldn't read from {config}: {exc}") if modified: try: @@ -1979,7 +1975,7 @@ def rm_filesystems(name, device, config="/etc/filesystems"): list_strgs = _FileSystemsEntry.dict_to_list_lines(entry) ofile.writelines(salt.utils.data.encode(list_strgs)) except OSError as exc: - raise CommandExecutionError("Couldn't write to {}: {}".format(config, exc)) + raise CommandExecutionError(f"Couldn't write to {config}: {exc}") except Exception as exc: raise CommandExecutionError("rm_filesystems error exception {exc}") diff --git a/salt/modules/mssql.py b/salt/modules/mssql.py index 9254d78fe5d..23ca6577542 100644 --- a/salt/modules/mssql.py +++ b/salt/modules/mssql.py @@ -139,7 +139,7 @@ def db_exists(database_name, **kwargs): "SELECT database_id FROM sys.databases WHERE NAME='{}'".format( database_name ), - **kwargs + **kwargs, ) ) == 1 @@ -160,7 +160,7 @@ def db_create(database, containment="NONE", new_database_options=None, **kwargs) """ if containment not in ["NONE", "PARTIAL"]: return "CONTAINMENT can be one of NONE and PARTIAL" - sql = "CREATE DATABASE [{}] CONTAINMENT = {} ".format(database, containment) + sql = f"CREATE DATABASE [{database}] CONTAINMENT = {containment} " if new_database_options: sql += " WITH " + ", ".join(new_database_options) conn = None @@ -171,7 +171,7 @@ def db_create(database, containment="NONE", new_database_options=None, **kwargs) # cur.execute(sql) conn.cursor().execute(sql) except Exception as e: # pylint: disable=broad-except - return "Could not create the database: {}".format(e) + return f"Could not create the database: {e}" finally: if conn: conn.autocommit(False) @@ -205,14 +205,14 @@ def db_remove(database_name, **kwargs): database_name ) ) - cur.execute("DROP DATABASE {}".format(database_name)) + cur.execute(f"DROP DATABASE {database_name}") conn.autocommit(False) conn.close() return True else: return False except Exception as e: # pylint: disable=broad-except - return "Could not find the database: {}".format(e) + return f"Could not find the database: {e}" def role_list(**kwargs): @@ -239,10 +239,7 @@ def role_exists(role, **kwargs): salt minion mssql.role_exists db_owner """ # We should get one, and only one row - return ( - len(tsql_query(query='sp_helprole "{}"'.format(role), as_dict=True, **kwargs)) - == 1 - ) + return len(tsql_query(query=f'sp_helprole "{role}"', as_dict=True, **kwargs)) == 1 def role_create(role, owner=None, grants=None, **kwargs): @@ -261,9 +258,9 @@ def role_create(role, owner=None, grants=None, **kwargs): if not grants: grants = [] - sql = "CREATE ROLE {}".format(role) + sql = f"CREATE ROLE {role}" if owner: - sql += " AUTHORIZATION {}".format(owner) + sql += f" AUTHORIZATION {owner}" conn = None try: conn = _get_connection(**kwargs) @@ -272,9 +269,9 @@ def role_create(role, owner=None, grants=None, **kwargs): # cur.execute(sql) conn.cursor().execute(sql) for grant in grants: - conn.cursor().execute("GRANT {} TO [{}]".format(grant, role)) + conn.cursor().execute(f"GRANT {grant} TO [{role}]") except Exception as e: # pylint: disable=broad-except - return "Could not create the role: {}".format(e) + return f"Could not create the role: {e}" finally: if conn: conn.autocommit(False) @@ -296,12 +293,12 @@ def role_remove(role, **kwargs): conn = _get_connection(**kwargs) conn.autocommit(True) cur = conn.cursor() - cur.execute("DROP ROLE {}".format(role)) + cur.execute(f"DROP ROLE {role}") conn.autocommit(True) conn.close() return True except Exception as e: # pylint: disable=broad-except - return "Could not remove the role: {}".format(e) + return f"Could not remove the role: {e}" def login_exists(login, domain="", **kwargs): @@ -316,7 +313,7 @@ def login_exists(login, domain="", **kwargs): salt minion mssql.login_exists 'LOGIN' """ if domain: - login = "{}\\{}".format(domain, login) + login = f"{domain}\\{login}" try: # We should get one, and only one row return ( @@ -325,14 +322,14 @@ def login_exists(login, domain="", **kwargs): query="SELECT name FROM sys.syslogins WHERE name='{}'".format( login ), - **kwargs + **kwargs, ) ) == 1 ) except Exception as e: # pylint: disable=broad-except - return "Could not find the login: {}".format(e) + return f"Could not find the login: {e}" def login_create( @@ -341,7 +338,7 @@ def login_create( new_login_domain="", new_login_roles=None, new_login_options=None, - **kwargs + **kwargs, ): """ Creates a new login. Does not update password of existing logins. For @@ -368,19 +365,19 @@ def login_create( if login_exists(login, new_login_domain, **kwargs): return False if new_login_domain: - login = "{}\\{}".format(new_login_domain, login) + login = f"{new_login_domain}\\{login}" if not new_login_roles: new_login_roles = [] if not new_login_options: new_login_options = [] - sql = "CREATE LOGIN [{}] ".format(login) + sql = f"CREATE LOGIN [{login}] " if new_login_domain: sql += " FROM WINDOWS " elif isinstance(new_login_password, int): - new_login_options.insert(0, "PASSWORD=0x{:x} HASHED".format(new_login_password)) + new_login_options.insert(0, f"PASSWORD=0x{new_login_password:x} HASHED") else: # Plain test password - new_login_options.insert(0, "PASSWORD=N'{}'".format(new_login_password)) + new_login_options.insert(0, f"PASSWORD=N'{new_login_password}'") if new_login_options: sql += " WITH " + ", ".join(new_login_options) conn = None @@ -391,11 +388,9 @@ def login_create( # cur.execute(sql) conn.cursor().execute(sql) for role in new_login_roles: - conn.cursor().execute( - "ALTER SERVER ROLE [{}] ADD MEMBER [{}]".format(role, login) - ) + conn.cursor().execute(f"ALTER SERVER ROLE [{role}] ADD MEMBER [{login}]") except Exception as e: # pylint: disable=broad-except - return "Could not create the login: {}".format(e) + return f"Could not create the login: {e}" finally: if conn: conn.autocommit(False) @@ -417,12 +412,12 @@ def login_remove(login, **kwargs): conn = _get_connection(**kwargs) conn.autocommit(True) cur = conn.cursor() - cur.execute("DROP LOGIN [{}]".format(login)) + cur.execute(f"DROP LOGIN [{login}]") conn.autocommit(False) conn.close() return True except Exception as e: # pylint: disable=broad-except - return "Could not remove the login: {}".format(e) + return f"Could not remove the login: {e}" def user_exists(username, domain="", database=None, **kwargs): @@ -437,15 +432,14 @@ def user_exists(username, domain="", database=None, **kwargs): salt minion mssql.user_exists 'USERNAME' [database='DBNAME'] """ if domain: - username = "{}\\{}".format(domain, username) + username = f"{domain}\\{username}" if database: kwargs["database"] = database # We should get one, and only one row return ( len( tsql_query( - query="SELECT name FROM sysusers WHERE name='{}'".format(username), - **kwargs + query=f"SELECT name FROM sysusers WHERE name='{username}'", **kwargs ) ) == 1 @@ -467,7 +461,7 @@ def user_list(**kwargs): for row in tsql_query( "SELECT name FROM sysusers where issqluser=1 or isntuser=1", as_dict=False, - **kwargs + **kwargs, ) ] @@ -489,10 +483,10 @@ def user_create( if domain and not login: return "domain cannot be set without login" if user_exists(username, domain, **kwargs): - return "User {} already exists".format(username) + return f"User {username} already exists" if domain: - username = "{}\\{}".format(domain, username) - login = "{}\\{}".format(domain, login) if login else login + username = f"{domain}\\{username}" + login = f"{domain}\\{login}" if login else login if database: kwargs["database"] = database if not roles: @@ -500,12 +494,12 @@ def user_create( if not options: options = [] - sql = "CREATE USER [{}] ".format(username) + sql = f"CREATE USER [{username}] " if login: # If the login does not exist, user creation will throw # if not login_exists(name, **kwargs): # return False - sql += " FOR LOGIN [{}]".format(login) + sql += f" FOR LOGIN [{login}]" else: # Plain test password sql += " WITHOUT LOGIN" if options: @@ -518,11 +512,9 @@ def user_create( # cur.execute(sql) conn.cursor().execute(sql) for role in roles: - conn.cursor().execute( - "ALTER ROLE [{}] ADD MEMBER [{}]".format(role, username) - ) + conn.cursor().execute(f"ALTER ROLE [{role}] ADD MEMBER [{username}]") except Exception as e: # pylint: disable=broad-except - return "Could not create the user: {}".format(e) + return f"Could not create the user: {e}" finally: if conn: conn.autocommit(False) @@ -547,9 +539,9 @@ def user_remove(username, **kwargs): conn = _get_connection(**kwargs) conn.autocommit(True) cur = conn.cursor() - cur.execute("DROP USER {}".format(username)) + cur.execute(f"DROP USER {username}") conn.autocommit(False) conn.close() return True except Exception as e: # pylint: disable=broad-except - return "Could not remove the user: {}".format(e) + return f"Could not remove the user: {e}" diff --git a/salt/modules/munin.py b/salt/modules/munin.py index ced668011f0..764135fc485 100644 --- a/salt/modules/munin.py +++ b/salt/modules/munin.py @@ -49,9 +49,7 @@ def run(plugins): if plugin not in all_plugins: continue data[plugin] = {} - muninout = __salt__["cmd.run"]( - "munin-run {}".format(plugin), python_shell=False - ) + muninout = __salt__["cmd.run"](f"munin-run {plugin}", python_shell=False) for line in muninout.split("\n"): if "value" in line: # This skips multigraph lines, etc key, val = line.split(" ") diff --git a/salt/modules/mysql.py b/salt/modules/mysql.py index 522b8858ce7..c3d234a73d6 100644 --- a/salt/modules/mysql.py +++ b/salt/modules/mysql.py @@ -263,7 +263,7 @@ def __virtual__(): def __mysql_hash_password(password): _password = hashlib.sha1(password.encode()).digest() - _password = "*{}".format(hashlib.sha1(_password).hexdigest().upper()) + _password = f"*{hashlib.sha1(_password).hexdigest().upper()}" return _password @@ -275,7 +275,7 @@ def __check_table(name, table, **connection_args): s_name = quote_identifier(name) s_table = quote_identifier(table) # identifiers cannot be used as values - qry = "CHECK TABLE {}.{}".format(s_name, s_table) + qry = f"CHECK TABLE {s_name}.{s_table}" _execute(cur, qry) results = cur.fetchall() log.debug(results) @@ -290,7 +290,7 @@ def __repair_table(name, table, **connection_args): s_name = quote_identifier(name) s_table = quote_identifier(table) # identifiers cannot be used as values - qry = "REPAIR TABLE {}.{}".format(s_name, s_table) + qry = f"REPAIR TABLE {s_name}.{s_table}" _execute(cur, qry) results = cur.fetchall() log.debug(results) @@ -305,7 +305,7 @@ def __optimize_table(name, table, **connection_args): s_name = quote_identifier(name) s_table = quote_identifier(table) # identifiers cannot be used as values - qry = "OPTIMIZE TABLE {}.{}".format(s_name, s_table) + qry = f"OPTIMIZE TABLE {s_name}.{s_table}" _execute(cur, qry) results = cur.fetchall() log.debug(results) @@ -386,7 +386,7 @@ def _connect(**kwargs): name = name[len(prefix) :] except IndexError: return - val = __salt__["config.option"]("mysql.{}".format(name), None) + val = __salt__["config.option"](f"mysql.{name}", None) if val is not None: connargs[key] = val @@ -581,7 +581,7 @@ def _grant_to_tokens(grant): if not column: current_grant = token else: - token = "{}.{}".format(current_grant, token) + token = f"{current_grant}.{token}" grant_tokens.append(token) else: # This is a multi-word, ala LOCK TABLES multiword_statement.append(token) @@ -1249,7 +1249,7 @@ def db_tables(name, **connection_args): cur = dbc.cursor() s_name = quote_identifier(name) # identifiers cannot be used as values - qry = "SHOW TABLES IN {}".format(s_name) + qry = f"SHOW TABLES IN {s_name}" try: _execute(cur, qry) except MySQLdb.OperationalError as exc: @@ -1328,7 +1328,7 @@ def db_create(name, character_set=None, collate=None, **connection_args): cur = dbc.cursor() s_name = quote_identifier(name) # identifiers cannot be used as values - qry = "CREATE DATABASE IF NOT EXISTS {}".format(s_name) + qry = f"CREATE DATABASE IF NOT EXISTS {s_name}" args = {} if character_set is not None: qry += " CHARACTER SET %(character_set)s" @@ -1375,7 +1375,7 @@ def db_remove(name, **connection_args): cur = dbc.cursor() s_name = quote_identifier(name) # identifiers cannot be used as values - qry = "DROP DATABASE {};".format(s_name) + qry = f"DROP DATABASE {s_name};" try: _execute(cur, qry) except MySQLdb.OperationalError as exc: @@ -1429,7 +1429,7 @@ def _mysql_user_exists( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): server_version = salt.utils.data.decode(version(**connection_args)) @@ -1474,7 +1474,7 @@ def _mariadb_user_exists( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): qry = "SELECT User,Host FROM mysql.user WHERE User = %(user)s AND Host = %(host)s" @@ -1506,7 +1506,7 @@ def user_exists( passwordless=False, unix_socket=False, password_column=None, - **connection_args + **connection_args, ): """ Checks if a user exists on the MySQL server. A login can be checked to see @@ -1551,7 +1551,7 @@ def user_exists( if ( dbc is None and __context__["mysql.error"].startswith( - "MySQL Error 1045: Access denied for user '{}'@".format(user) + f"MySQL Error 1045: Access denied for user '{user}'@" ) and password ): @@ -1578,7 +1578,7 @@ def user_exists( unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ) else: qry, args = _mysql_user_exists( @@ -1590,7 +1590,7 @@ def user_exists( unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ) try: @@ -1645,7 +1645,7 @@ def _mysql_user_create( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): server_version = salt.utils.data.decode(version(**connection_args)) @@ -1708,7 +1708,7 @@ def _mariadb_user_create( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): qry = "CREATE USER %(user)s@%(host)s" @@ -1754,7 +1754,7 @@ def user_create( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): """ Creates a MySQL user @@ -1844,7 +1844,7 @@ def user_create( unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ) else: qry, args = _mysql_user_create( @@ -1856,7 +1856,7 @@ def user_create( unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ) if isinstance(qry, bool): @@ -1876,9 +1876,9 @@ def user_create( password, password_hash, password_column=password_column, - **connection_args + **connection_args, ): - msg = "User '{}'@'{}' has been created".format(user, host) + msg = f"User '{user}'@'{host}' has been created" if not any((password, password_hash)): msg += " with passwordless login" log.info(msg) @@ -1897,7 +1897,7 @@ def _mysql_user_chpass( unix_socket=None, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): server_version = salt.utils.data.decode(version(**connection_args)) compare_version = "8.0.11" @@ -1983,7 +1983,7 @@ def _mariadb_user_chpass( unix_socket=None, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): server_version = salt.utils.data.decode(version(**connection_args)) @@ -2054,7 +2054,7 @@ def user_chpass( allow_passwordless=False, unix_socket=None, password_column=None, - **connection_args + **connection_args, ): """ Change password for a MySQL user @@ -2139,7 +2139,7 @@ def user_chpass( unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ) else: qry, args = _mysql_user_chpass( @@ -2151,7 +2151,7 @@ def user_chpass( unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ) try: @@ -2329,7 +2329,7 @@ def __grant_normalize(grant): exploded_grants = __grant_split(grant) for chkgrant, _ in exploded_grants: if chkgrant.strip().upper() not in __grants__: - raise Exception("Invalid grant : '{}'".format(chkgrant)) + raise Exception(f"Invalid grant : '{chkgrant}'") return grant @@ -2349,7 +2349,7 @@ def __ssl_option_sanitize(ssl_option): normal_key = key.strip().upper() if normal_key not in __ssl_options__: - raise Exception("Invalid SSL option : '{}'".format(key)) + raise Exception(f"Invalid SSL option : '{key}'") if normal_key in __ssl_options_parameterized__: # SSL option parameters (cipher, issuer, subject) are pasted directly to SQL so @@ -2397,7 +2397,7 @@ def __grant_generate( if table != "*": table = quote_identifier(table) # identifiers cannot be used as values, and same thing for grants - qry = "GRANT {} ON {}.{} TO %(user)s@%(host)s".format(grant, dbc, table) + qry = f"GRANT {grant} ON {dbc}.{table} TO %(user)s@%(host)s" args = {} args["user"] = user args["host"] = host @@ -2444,7 +2444,7 @@ def user_grants(user, host="localhost", **connection_args): for grant in results: tmp = grant[0].split(" IDENTIFIED BY")[0] if "WITH GRANT OPTION" in grant[0] and "WITH GRANT OPTION" not in tmp: - tmp = "{} WITH GRANT OPTION".format(tmp) + tmp = f"{tmp} WITH GRANT OPTION" ret.append(tmp) log.debug(ret) return ret @@ -2457,7 +2457,7 @@ def grant_exists( host="localhost", grant_option=False, escape=True, - **connection_args + **connection_args, ): """ Checks to see if a grant exists in the database @@ -2578,7 +2578,7 @@ def grant_add( grant_option=False, escape=True, ssl_option=False, - **connection_args + **connection_args, ): """ Adds a grant to the MySQL server. @@ -2634,7 +2634,7 @@ def grant_revoke( host="localhost", grant_option=False, escape=True, - **connection_args + **connection_args, ): """ Removes a grant from the MySQL server. @@ -2671,7 +2671,7 @@ def grant_revoke( if table != "*": table = quote_identifier(table) # identifiers cannot be used as values, same thing for grants - qry = "REVOKE {} ON {}.{} FROM %(user)s@%(host)s;".format(grant, s_database, table) + qry = f"REVOKE {grant} ON {s_database}.{table} FROM %(user)s@%(host)s;" args = {} args["user"] = user args["host"] = host @@ -3038,12 +3038,12 @@ def plugin_add(name, soname=None, **connection_args): if dbc is None: return False cur = dbc.cursor() - qry = "INSTALL PLUGIN {}".format(name) + qry = f"INSTALL PLUGIN {name}" if soname: - qry += ' SONAME "{}"'.format(soname) + qry += f' SONAME "{soname}"' else: - qry += ' SONAME "{}.so"'.format(name) + qry += f' SONAME "{name}.so"' try: _execute(cur, qry) @@ -3078,7 +3078,7 @@ def plugin_remove(name, **connection_args): if dbc is None: return False cur = dbc.cursor() - qry = "UNINSTALL PLUGIN {}".format(name) + qry = f"UNINSTALL PLUGIN {name}" args = {} args["name"] = name diff --git a/salt/modules/nagios.py b/salt/modules/nagios.py index 960b8b2e718..87f3ae639f7 100644 --- a/salt/modules/nagios.py +++ b/salt/modules/nagios.py @@ -32,9 +32,7 @@ def _execute_cmd(plugin, args="", run_type="cmd.retcode"): all_plugins = list_plugins() if plugin in all_plugins: - data = __salt__[run_type]( - "{}{} {}".format(PLUGINDIR, plugin, args), python_shell=False - ) + data = __salt__[run_type](f"{PLUGINDIR}{plugin} {args}", python_shell=False) return data diff --git a/salt/modules/nagios_rpc.py b/salt/modules/nagios_rpc.py index 5eae58b0b2b..9aee76a10c3 100644 --- a/salt/modules/nagios_rpc.py +++ b/salt/modules/nagios_rpc.py @@ -97,7 +97,7 @@ def _status_query(query, hostname, enumerate=None, service=None): elif result.get("status", None) == http.client.NOT_FOUND: ret["error"] = "URL {} was not found.".format(config["url"]) else: - ret["error"] = "Results: {}".format(result.text) + ret["error"] = f"Results: {result.text}" return ret diff --git a/salt/modules/namecheap_domains.py b/salt/modules/namecheap_domains.py index c3d9f3ba1d0..e12c102b913 100644 --- a/salt/modules/namecheap_domains.py +++ b/salt/modules/namecheap_domains.py @@ -364,7 +364,7 @@ def create(domain_name, years, **kwargs): for requiredkey in require_opts: if requiredkey not in opts: log.error("Missing required parameter '%s'", requiredkey) - raise Exception("Missing required parameter '{}'".format(requiredkey)) + raise Exception(f"Missing required parameter '{requiredkey}'") response_xml = salt.utils.namecheap.post_request(opts) diff --git a/salt/modules/napalm_formula.py b/salt/modules/napalm_formula.py index 1b641d71973..c69d376cd60 100644 --- a/salt/modules/napalm_formula.py +++ b/salt/modules/napalm_formula.py @@ -292,7 +292,7 @@ def render_field(dictionary, field, prepend=None, append=None, quotes=False, **o else: append = "" if quotes: - value = '"{value}"'.format(value=value) + value = f'"{value}"' return "{prepend} {value}{append}".format( prepend=prepend, value=value, append=append ) diff --git a/salt/modules/napalm_mod.py b/salt/modules/napalm_mod.py index 8f70c9ad62b..84a40ad04eb 100644 --- a/salt/modules/napalm_mod.py +++ b/salt/modules/napalm_mod.py @@ -322,7 +322,7 @@ def call(method, *args, **kwargs): napalm_device, # pylint: disable=undefined-variable method, *args, - **clean_kwargs + **clean_kwargs, ) @@ -561,7 +561,7 @@ def netmiko_fun(fun, *args, **kwargs): salt '*' napalm.netmiko_fun send_command 'show version' """ if "netmiko." not in fun: - fun = "netmiko.{fun}".format(fun=fun) + fun = f"netmiko.{fun}" netmiko_kwargs = netmiko_args() kwargs.update(netmiko_kwargs) return __salt__[fun](*args, **kwargs) @@ -1038,14 +1038,14 @@ def junos_call(fun, *args, **kwargs): if not prep["result"]: return prep if "junos." not in fun: - mod_fun = "junos.{}".format(fun) + mod_fun = f"junos.{fun}" else: mod_fun = fun if mod_fun not in __salt__: return { "out": None, "result": False, - "comment": "{} is not a valid function".format(fun), + "comment": f"{fun} is not a valid function", } return __salt__[mod_fun](*args, **kwargs) @@ -1177,7 +1177,7 @@ def pyeapi_config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -1235,7 +1235,7 @@ def pyeapi_config( context=context, defaults=defaults, saltenv=saltenv, - **pyeapi_kwargs + **pyeapi_kwargs, ) @@ -1271,7 +1271,7 @@ def nxos_api_config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -1327,7 +1327,7 @@ def nxos_api_config( context=context, defaults=defaults, saltenv=saltenv, - **nxos_api_kwargs + **nxos_api_kwargs, ) @@ -1915,7 +1915,7 @@ def scp_get( local_path=local_path, recursive=recursive, preserve_times=preserve_times, - **kwargs + **kwargs, ) @@ -1926,7 +1926,7 @@ def scp_put( recursive=False, preserve_times=False, saltenv="base", - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -2021,5 +2021,5 @@ def scp_put( recursive=recursive, preserve_times=preserve_times, saltenv=saltenv, - **kwargs + **kwargs, ) diff --git a/salt/modules/napalm_network.py b/salt/modules/napalm_network.py index c6156db1566..9fc5185553f 100644 --- a/salt/modules/napalm_network.py +++ b/salt/modules/napalm_network.py @@ -170,7 +170,7 @@ def _config_logic( revert_in=None, revert_at=None, commit_jid=None, - **kwargs + **kwargs, ): """ Builds the config logic for `load_config` and `load_template` functions. @@ -191,7 +191,7 @@ def _config_logic( current_jid = kwargs.get("__pub_jid") if not current_jid: - current_jid = "{:%Y%m%d%H%M%S%f}".format(datetime.datetime.now()) + current_jid = f"{datetime.datetime.now():%Y%m%d%H%M%S%f}" loaded_result["already_configured"] = False @@ -246,7 +246,7 @@ def _config_logic( time_in=commit_in, time_at=commit_in ) # schedule job - scheduled_job_name = "__napalm_commit_{}".format(current_jid) + scheduled_job_name = f"__napalm_commit_{current_jid}" temp_file = salt.utils.files.mkstemp() with salt.utils.files.fopen(temp_file, "w") as fp_: fp_.write(loaded_config) @@ -329,7 +329,7 @@ def _config_logic( # already done by the _safe_commit_config function), and # return with the command and other details. return loaded_result - scheduled_job_name = "__napalm_commit_{}".format(current_jid) + scheduled_job_name = f"__napalm_commit_{current_jid}" scheduled = __salt__["schedule.add"]( scheduled_job_name, function="net.load_config", @@ -692,7 +692,7 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument raw_cli_outputs = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "cli", - **{"commands": list(commands)} + **{"commands": list(commands)}, ) # thus we can display the output as is # in case of errors, they'll be caught in the proxy @@ -826,7 +826,7 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument processed_command_output = command_output processed_cli_outputs[ "comment" - ] += "\nUnable to process the output from {}.".format(command) + ] += f"\nUnable to process the output from {command}." processed_cli_outputs["out"][command] = processed_command_output processed_cli_outputs["comment"] = processed_cli_outputs["comment"].strip() return processed_cli_outputs @@ -874,7 +874,7 @@ def traceroute( "ttl": ttl, "timeout": timeout, "vrf": vrf, - } + }, ) @@ -887,7 +887,7 @@ def ping( size=None, count=None, vrf=None, - **kwargs + **kwargs, ): # pylint: disable=unused-argument """ Executes a ping on the network device and returns a dictionary as a result. @@ -935,7 +935,7 @@ def ping( "size": size, "count": count, "vrf": vrf, - } + }, ) @@ -1143,7 +1143,7 @@ def lldp(interface="", **kwargs): # pylint: disable=unused-argument proxy_output = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "get_lldp_neighbors_detail", - **{} + **{}, ) if not proxy_output.get("result"): @@ -1205,7 +1205,7 @@ def mac(address="", interface="", vlan=0, **kwargs): # pylint: disable=unused-a proxy_output = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "get_mac_address_table", - **{} + **{}, ) if not proxy_output.get("result"): @@ -1274,7 +1274,7 @@ def config(source=None, **kwargs): # pylint: disable=unused-argument return salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "get_config", - **{"retrieve": source} + **{"retrieve": source}, ) @@ -1341,7 +1341,7 @@ def load_config( commit_jid=None, inherit_napalm_device=None, saltenv="base", - **kwargs + **kwargs, ): # pylint: disable=unused-argument """ Applies configuration changes on the device. It can be loaded from a file or from inline string. @@ -1582,7 +1582,7 @@ def load_config( revert_in=revert_in, revert_at=revert_at, commit_jid=commit_jid, - **kwargs + **kwargs, ) @@ -1606,7 +1606,7 @@ def load_template( revert_in=None, revert_at=None, inherit_napalm_device=None, # pylint: disable=unused-argument - **template_vars + **template_vars, ): """ Renders a configuration template (default: Jinja) and loads the result on the device. @@ -2068,7 +2068,7 @@ def load_template( _loaded = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable fun, - **{"config": _rendered} + **{"config": _rendered}, ) return _config_logic( napalm_device, # pylint: disable=undefined-variable @@ -2082,7 +2082,7 @@ def load_template( commit_in=commit_in, revert_in=revert_in, revert_at=revert_at, - **template_vars + **template_vars, ) @@ -2255,13 +2255,13 @@ def cancel_commit(jid): salt '*' net.cancel_commit 20180726083540640360 """ - job_name = "__napalm_commit_{}".format(jid) + job_name = f"__napalm_commit_{jid}" removed = __salt__["schedule.delete"](job_name) if removed["result"]: saved = __salt__["schedule.save"]() - removed["comment"] = "Commit #{jid} cancelled.".format(jid=jid) + removed["comment"] = f"Commit #{jid} cancelled." else: - removed["comment"] = "Unable to find commit #{jid}.".format(jid=jid) + removed["comment"] = f"Unable to find commit #{jid}." return removed @@ -2290,7 +2290,7 @@ def confirm_commit(jid): else: confirmed = cancel_commit(jid) if confirmed["result"]: - confirmed["comment"] = "Commit #{jid} confirmed.".format(jid=jid) + confirmed["comment"] = f"Commit #{jid} confirmed." return confirmed @@ -2328,7 +2328,7 @@ def save_config(source=None, path=None): return { "result": True, "out": path, - "comment": "{source} config saved to {path}".format(source=source, path=path), + "comment": f"{source} config saved to {path}", } @@ -2664,7 +2664,7 @@ def patch( return { "out": None, "result": False, - "comment": 'The file "{}" does not exist.'.format(patchfile), + "comment": f'The file "{patchfile}" does not exist.', } replace_pattern = __salt__["file.patch"](path, patchfile_cache, options=options) with salt.utils.files.fopen(path, "r") as fh_: diff --git a/salt/modules/netbox.py b/salt/modules/netbox.py index 656087d0cb0..13b1ff63a71 100644 --- a/salt/modules/netbox.py +++ b/salt/modules/netbox.py @@ -190,7 +190,7 @@ def get_(app, endpoint, id=None, **kwargs): endpoint, id=id, auth_required=True if app in AUTH_ENDPOINTS else False, - **kwargs + **kwargs, ) ) @@ -1014,7 +1014,7 @@ def create_circuit_provider(name, asn=None): else: log.error("Duplicate provider with different ASN: %s: %s", name, asn) raise CommandExecutionError( - "Duplicate provider with different ASN: {}: {}".format(name, asn) + f"Duplicate provider with different ASN: {name}: {asn}" ) else: payload = {"name": name, "slug": slugify(name)} diff --git a/salt/modules/netbsd_sysctl.py b/salt/modules/netbsd_sysctl.py index cd18ea36e47..dbae3de3b36 100644 --- a/salt/modules/netbsd_sysctl.py +++ b/salt/modules/netbsd_sysctl.py @@ -58,11 +58,11 @@ def show(config_file=False): out = __salt__["cmd.run"](cmd, output_loglevel="trace") comps = [""] for line in out.splitlines(): - if any([line.startswith("{}.".format(root)) for root in roots]): + if any([line.startswith(f"{root}.") for root in roots]): comps = re.split("[=:]", line, 1) ret[comps[0]] = comps[1] elif comps[0]: - ret[comps[0]] += "{}\n".format(line) + ret[comps[0]] += f"{line}\n" else: continue return ret @@ -78,7 +78,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd, python_shell=False) return out @@ -94,7 +94,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.icmp.icmplim 50 """ ret = {} - cmd = 'sysctl -w {}="{}"'.format(name, value) + cmd = f'sysctl -w {name}="{value}"' data = __salt__["cmd.run_all"](cmd, python_shell=False) if data["retcode"] != 0: @@ -130,7 +130,7 @@ def persist(name, value, config="/etc/sysctl.conf"): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - m = re.match(r"{}(\??=)".format(name), line) + m = re.match(rf"{name}(\??=)", line) if not m: nlines.append(line) continue @@ -145,13 +145,13 @@ def persist(name, value, config="/etc/sysctl.conf"): rest = rest[len(rest_v) :] if rest_v == value: return "Already set" - new_line = "{}{}{}{}".format(name, m.group(1), value, rest) + new_line = f"{name}{m.group(1)}{value}{rest}" nlines.append(new_line) edited = True if not edited: - newline = "{}={}".format(name, value) - nlines.append("{}\n".format(newline)) + newline = f"{name}={value}" + nlines.append(f"{newline}\n") with salt.utils.files.fopen(config, "wb") as ofile: ofile.writelines(salt.utils.data.encode(nlines)) diff --git a/salt/modules/netbsdservice.py b/salt/modules/netbsdservice.py index e8308415930..c6ebc20dbcd 100644 --- a/salt/modules/netbsdservice.py +++ b/salt/modules/netbsdservice.py @@ -41,7 +41,7 @@ def start(name): salt '*' service.start """ - cmd = "/etc/rc.d/{} onestart".format(name) + cmd = f"/etc/rc.d/{name} onestart" return not __salt__["cmd.retcode"](cmd) @@ -55,7 +55,7 @@ def stop(name): salt '*' service.stop """ - cmd = "/etc/rc.d/{} onestop".format(name) + cmd = f"/etc/rc.d/{name} onestop" return not __salt__["cmd.retcode"](cmd) @@ -69,7 +69,7 @@ def restart(name): salt '*' service.restart """ - cmd = "/etc/rc.d/{} onerestart".format(name) + cmd = f"/etc/rc.d/{name} onerestart" return not __salt__["cmd.retcode"](cmd) @@ -83,7 +83,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "/etc/rc.d/{} onereload".format(name) + cmd = f"/etc/rc.d/{name} onereload" return not __salt__["cmd.retcode"](cmd) @@ -97,7 +97,7 @@ def force_reload(name): salt '*' service.force_reload """ - cmd = "/etc/rc.d/{} forcereload".format(name) + cmd = f"/etc/rc.d/{name} forcereload" return not __salt__["cmd.retcode"](cmd) @@ -134,7 +134,7 @@ def status(name, sig=None): services = [name] results = {} for service in services: - cmd = "/etc/rc.d/{} onestatus".format(service) + cmd = f"/etc/rc.d/{service} onestatus" results[service] = not __salt__["cmd.retcode"](cmd, ignore_retcode=True) if contains_globbing: return results @@ -146,9 +146,9 @@ def _get_svc(rcd, service_status): Returns a unique service status """ ena = None - lines = __salt__["cmd.run"]("{} rcvar".format(rcd)).splitlines() + lines = __salt__["cmd.run"](f"{rcd} rcvar").splitlines() for rcvar in lines: - if rcvar.startswith("$") and "={}".format(service_status) in rcvar: + if rcvar.startswith("$") and f"={service_status}" in rcvar: ena = "yes" elif rcvar.startswith("#"): svc = rcvar.split(" ", 1)[1] @@ -166,7 +166,7 @@ def _get_svc_list(service_status): """ prefix = "/etc/rc.d/" ret = set() - lines = glob.glob("{}*".format(prefix)) + lines = glob.glob(f"{prefix}*") for line in lines: svc = _get_svc(line, service_status) if svc is not None: @@ -249,9 +249,9 @@ def _rcconf_status(name, service_status): can be started via /etc/rc.d/ """ rcconf = "/etc/rc.conf" - rxname = "^{}=.*".format(name) - newstatus = "{}={}".format(name, service_status) - ret = __salt__["cmd.retcode"]("grep '{}' {}".format(rxname, rcconf)) + rxname = f"^{name}=.*" + newstatus = f"{name}={service_status}" + ret = __salt__["cmd.retcode"](f"grep '{rxname}' {rcconf}") if ret == 0: # service found in rc.conf, modify its status __salt__["file.replace"](rcconf, rxname, newstatus) else: @@ -296,7 +296,7 @@ def enabled(name, **kwargs): salt '*' service.enabled """ - return _get_svc("/etc/rc.d/{}".format(name), "YES") + return _get_svc(f"/etc/rc.d/{name}", "YES") def disabled(name): @@ -309,4 +309,4 @@ def disabled(name): salt '*' service.disabled """ - return _get_svc("/etc/rc.d/{}".format(name), "NO") + return _get_svc(f"/etc/rc.d/{name}", "NO") diff --git a/salt/modules/netmiko_mod.py b/salt/modules/netmiko_mod.py index 1769471f82b..d3cd44e10cd 100644 --- a/salt/modules/netmiko_mod.py +++ b/salt/modules/netmiko_mod.py @@ -486,7 +486,7 @@ def send_config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Send configuration commands down the SSH channel. @@ -564,7 +564,7 @@ def send_config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") elif config_commands: if isinstance(config_commands, ((str,), str)): config_commands = [config_commands] diff --git a/salt/modules/netscaler.py b/salt/modules/netscaler.py index e4d684c4088..94949f3527c 100644 --- a/salt/modules/netscaler.py +++ b/salt/modules/netscaler.py @@ -118,7 +118,7 @@ def _connect(**kwargs): name = name[len(prefix) :] except IndexError: return - val = __salt__["config.option"]("netscaler.{}".format(name), None) + val = __salt__["config.option"](f"netscaler.{name}", None) if val is not None: connargs[key] = val elif default is not None: diff --git a/salt/modules/network.py b/salt/modules/network.py index c72230f3335..3411144fb27 100644 --- a/salt/modules/network.py +++ b/salt/modules/network.py @@ -299,7 +299,7 @@ def _netstat_bsd(): ret = [] if __grains__["kernel"] == "NetBSD": for addr_family in ("inet", "inet6"): - cmd = "netstat -f {} -an | tail -n+3".format(addr_family) + cmd = f"netstat -f {addr_family} -an | tail -n+3" out = __salt__["cmd.run"](cmd, python_shell=True) for line in out.splitlines(): comps = line.split() @@ -382,7 +382,7 @@ def _netstat_sunos(): ret = [] for addr_family in ("inet", "inet6"): # Lookup TCP connections - cmd = "netstat -f {} -P tcp -an | tail +5".format(addr_family) + cmd = f"netstat -f {addr_family} -P tcp -an | tail +5" out = __salt__["cmd.run"](cmd, python_shell=True) for line in out.splitlines(): comps = line.split() @@ -397,7 +397,7 @@ def _netstat_sunos(): } ) # Lookup UDP connections - cmd = "netstat -f {} -P udp -an | tail +5".format(addr_family) + cmd = f"netstat -f {addr_family} -P udp -an | tail +5" out = __salt__["cmd.run"](cmd, python_shell=True) for line in out.splitlines(): comps = line.split() @@ -421,7 +421,7 @@ def _netstat_aix(): ## for addr_family in ('inet', 'inet6'): for addr_family in ("inet",): # Lookup connections - cmd = "netstat -n -a -f {} | tail -n +3".format(addr_family) + cmd = f"netstat -n -a -f {addr_family} | tail -n +3" out = __salt__["cmd.run"](cmd, python_shell=True) for line in out.splitlines(): comps = line.split() @@ -1012,7 +1012,7 @@ def traceroute(host): "ip": traceline[2], } for idx, delay in enumerate(delays): - result["ms{}".format(idx + 1)] = delay + result[f"ms{idx + 1}"] = delay except IndexError: result = {} @@ -1400,7 +1400,7 @@ def mod_hostname(hostname): # Grab the old hostname so we know which hostname to change and then # change the hostname using the hostname command if hostname_cmd.endswith("hostnamectl"): - result = __salt__["cmd.run_all"]("{} status".format(hostname_cmd)) + result = __salt__["cmd.run_all"](f"{hostname_cmd} status") if 0 == result["retcode"]: out = result["stdout"] for line in out.splitlines(): @@ -1432,7 +1432,7 @@ def mod_hostname(hostname): ) return False elif not __utils__["platform.is_sunos"](): - __salt__["cmd.run"]("{} {}".format(hostname_cmd, hostname)) + __salt__["cmd.run"](f"{hostname_cmd} {hostname}") else: __salt__["cmd.run"]("{} -S {}".format(uname_cmd, hostname.split(".")[0])) @@ -1490,7 +1490,7 @@ def mod_hostname(hostname): ) if __salt__["cmd.run_all"](nirtcfg_cmd)["retcode"] != 0: raise CommandExecutionError( - "Couldn't set hostname to: {}\n".format(str_hostname) + f"Couldn't set hostname to: {str_hostname}\n" ) elif __grains__["os_family"] == "OpenBSD": with __utils__["files.fopen"]("/etc/myname", "w") as fh_: @@ -1666,7 +1666,7 @@ def _get_bufsize_linux(iface): """ ret = {"result": False} - cmd = "/sbin/ethtool -g {}".format(iface) + cmd = f"/sbin/ethtool -g {iface}" out = __salt__["cmd.run"](cmd) pat = re.compile(r"^(.+):\s+(\d+)$") suffix = "max-" @@ -1770,7 +1770,7 @@ def routes(family=None): salt '*' network.routes """ if family != "inet" and family != "inet6" and family is not None: - raise CommandExecutionError("Invalid address family {}".format(family)) + raise CommandExecutionError(f"Invalid address family {family}") if __grains__["kernel"] == "Linux": if not __utils__["path.which"]("netstat"): @@ -1814,7 +1814,7 @@ def default_route(family=None): salt '*' network.default_route """ if family != "inet" and family != "inet6" and family is not None: - raise CommandExecutionError("Invalid address family {}".format(family)) + raise CommandExecutionError(f"Invalid address family {family}") _routes = routes(family) @@ -1872,7 +1872,7 @@ def get_route(ip): """ if __grains__["kernel"] == "Linux": - cmd = "ip route get {}".format(ip) + cmd = f"ip route get {ip}" out = __salt__["cmd.run"](cmd, python_shell=True) regexp = re.compile( r"(via\s+(?P[\w\.:]+))?\s+dev\s+(?P[\w\.\:\-]+)\s+.*src\s+(?P[\w\.:]+)" @@ -1896,7 +1896,7 @@ def get_route(ip): # flags: # recvpipe sendpipe ssthresh rtt,ms rttvar,ms hopcount mtu expire # 0 0 0 0 0 0 1500 0 - cmd = "/usr/sbin/route -n get {}".format(ip) + cmd = f"/usr/sbin/route -n get {ip}" out = __salt__["cmd.run"](cmd, python_shell=False) ret = {"destination": ip, "gateway": None, "interface": None, "source": None} @@ -1925,7 +1925,7 @@ def get_route(ip): # flags: # use mtu expire # 8352657 0 0 - cmd = "route -n get {}".format(ip) + cmd = f"route -n get {ip}" out = __salt__["cmd.run"](cmd, python_shell=False) ret = {"destination": ip, "gateway": None, "interface": None, "source": None} @@ -1953,7 +1953,7 @@ def get_route(ip): # flags: # recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire # 0 0 0 0 0 0 0 -68642 - cmd = "route -n get {}".format(ip) + cmd = f"route -n get {ip}" out = __salt__["cmd.run"](cmd, python_shell=False) ret = {"destination": ip, "gateway": None, "interface": None, "source": None} diff --git a/salt/modules/nexus.py b/salt/modules/nexus.py index 06a44f38a22..e8e212ce8f5 100644 --- a/salt/modules/nexus.py +++ b/salt/modules/nexus.py @@ -94,7 +94,7 @@ def get_latest_snapshot( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) artifact_metadata = _get_artifact_metadata( nexus_url=nexus_url, @@ -175,7 +175,7 @@ def get_snapshot( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) snapshot_url, file_name = _get_snapshot_url( nexus_url=nexus_url, @@ -241,7 +241,7 @@ def get_snapshot_version_string( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) return _get_snapshot_url( nexus_url=nexus_url, @@ -306,7 +306,7 @@ def get_latest_release( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) artifact_metadata = _get_artifact_metadata( nexus_url=nexus_url, @@ -379,7 +379,7 @@ def get_release( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) release_url, file_name = _get_release_url( repository, group_id, artifact_id, packaging, version, nexus_url, classifier @@ -688,7 +688,7 @@ def __save_artifact(artifact_url, target_file, headers): local_file.write(salt.utils.stringutils.to_bytes(f.read())) result["status"] = True result["comment"] = __append_comment( - "Artifact downloaded from URL: {}".format(artifact_url), + f"Artifact downloaded from URL: {artifact_url}", result["comment"], ) result["changes"]["downloaded_file"] = target_file diff --git a/salt/modules/nfs3.py b/salt/modules/nfs3.py index 048c8b18456..d692c5fb01e 100644 --- a/salt/modules/nfs3.py +++ b/salt/modules/nfs3.py @@ -125,8 +125,8 @@ def _write_exports(exports, edict): for perms in edict[export]: hosts = perms["hosts"] options = ",".join(perms["options"]) - line += " {}({})".format(hosts, options) - efh.write("{}\n".format(line)) + line += f" {hosts}({options})" + efh.write(f"{line}\n") def reload_exports(): diff --git a/salt/modules/nftables.py b/salt/modules/nftables.py index 5af8f7b3b85..347b03c0897 100644 --- a/salt/modules/nftables.py +++ b/salt/modules/nftables.py @@ -73,7 +73,7 @@ def version(): salt '*' nftables.version """ - cmd = "{} --version".format(_nftables_cmd()) + cmd = f"{_nftables_cmd()} --version" out = __salt__["cmd.run"](cmd).split() return out[1] @@ -85,7 +85,7 @@ def build_rule( position="", full=None, family="ipv4", - **kwargs + **kwargs, ): """ Build a well-formatted nftables rule based on kwargs. @@ -260,8 +260,8 @@ def build_rule( rule = rule.strip() # Insert the protocol prior to dport or sport - rule = rule.replace("dport", "{} dport".format(proto)) - rule = rule.replace("sport", "{} sport".format(proto)) + rule = rule.replace("dport", f"{proto} dport") + rule = rule.replace("sport", f"{proto} sport") ret["rule"] = rule @@ -456,16 +456,14 @@ def save(filename=None, family="ipv4"): rules = rules + "\n" if __salt__["file.directory_exists"](filename): - filename = "{}/salt-all-in-one.nft".format(filename) + filename = f"{filename}/salt-all-in-one.nft" try: with salt.utils.files.fopen(filename, "wb") as _fh: # Write out any changes _fh.write(salt.utils.data.encode(rules)) except OSError as exc: - raise CommandExecutionError( - "Problem writing to configuration file: {}".format(exc) - ) + raise CommandExecutionError(f"Problem writing to configuration file: {exc}") return rules @@ -519,12 +517,12 @@ def get_rule_handle(table="filter", chain=None, rule=None, family="ipv4"): out = __salt__["cmd.run"](cmd, python_shell=False) rules = re.split("\n+", out) - pat = re.compile(r"{} # handle (?P\d+)".format(rule)) + pat = re.compile(rf"{rule} # handle (?P\d+)") for r in rules: match = pat.search(r) if match: return {"result": True, "handle": match.group("handle")} - return {"result": False, "comment": "Could not find rule {}".format(rule)} + return {"result": False, "comment": f"Could not find rule {rule}"} def check(table="filter", chain=None, rule=None, family="ipv4"): @@ -570,7 +568,7 @@ def check(table="filter", chain=None, rule=None, family="ipv4"): cmd = "{} --handle --numeric --numeric --numeric list chain {} {} {}".format( _nftables_cmd(), nft_family, table, chain ) - search_rule = "{} #".format(rule) + search_rule = f"{rule} #" out = __salt__["cmd.run"](cmd, python_shell=False).find(search_rule) if out == -1: @@ -610,10 +608,8 @@ def check_chain(table="filter", chain=None, family="ipv4"): return ret nft_family = _NFTABLES_FAMILIES[family] - cmd = "{} list table {} {}".format(_nftables_cmd(), nft_family, table) - out = __salt__["cmd.run"](cmd, python_shell=False).find( - "chain {0} {{".format(chain) - ) + cmd = f"{_nftables_cmd()} list table {nft_family} {table}" + out = __salt__["cmd.run"](cmd, python_shell=False).find(f"chain {chain} {{") if out == -1: ret["comment"] = "Chain {} in table {} in family {} does not exist".format( @@ -644,15 +640,15 @@ def check_table(table=None, family="ipv4"): return ret nft_family = _NFTABLES_FAMILIES[family] - cmd = "{} list tables {}".format(_nftables_cmd(), nft_family) + cmd = f"{_nftables_cmd()} list tables {nft_family}" out = __salt__["cmd.run"](cmd, python_shell=False).find( - "table {} {}".format(nft_family, table) + f"table {nft_family} {table}" ) if out == -1: - ret["comment"] = "Table {} in family {} does not exist".format(table, family) + ret["comment"] = f"Table {table} in family {family} does not exist" else: - ret["comment"] = "Table {} in family {} exists".format(table, family) + ret["comment"] = f"Table {table} in family {family} exists" ret["result"] = True return ret @@ -683,11 +679,11 @@ def new_table(table, family="ipv4"): return res nft_family = _NFTABLES_FAMILIES[family] - cmd = "{} add table {} {}".format(_nftables_cmd(), nft_family, table) + cmd = f"{_nftables_cmd()} add table {nft_family} {table}" out = __salt__["cmd.run"](cmd, python_shell=False) if not out: - ret["comment"] = "Table {} in family {} created".format(table, family) + ret["comment"] = f"Table {table} in family {family} created" ret["result"] = True else: ret["comment"] = "Table {} in family {} could not be created".format( @@ -722,11 +718,11 @@ def delete_table(table, family="ipv4"): return res nft_family = _NFTABLES_FAMILIES[family] - cmd = "{} delete table {} {}".format(_nftables_cmd(), nft_family, table) + cmd = f"{_nftables_cmd()} delete table {nft_family} {table}" out = __salt__["cmd.run"](cmd, python_shell=False) if not out: - ret["comment"] = "Table {} in family {} deleted".format(table, family) + ret["comment"] = f"Table {table} in family {family} deleted" ret["result"] = True else: ret["comment"] = "Table {} in family {} could not be deleted".format( @@ -780,7 +776,7 @@ def new_chain( return ret nft_family = _NFTABLES_FAMILIES[family] - cmd = "{} -- add chain {} {} {}".format(_nftables_cmd(), nft_family, table, chain) + cmd = f"{_nftables_cmd()} -- add chain {nft_family} {table} {chain}" if table_type or hook or priority: if table_type and hook and str(priority): cmd = r"{0} \{{ type {1} hook {2} priority {3}\; \}}".format( @@ -841,7 +837,7 @@ def delete_chain(table="filter", chain=None, family="ipv4"): return res nft_family = _NFTABLES_FAMILIES[family] - cmd = "{} delete chain {} {} {}".format(_nftables_cmd(), nft_family, table, chain) + cmd = f"{_nftables_cmd()} delete chain {nft_family} {table} {chain}" out = __salt__["cmd.run"](cmd, python_shell=False) if not out: @@ -962,7 +958,7 @@ def insert(table="filter", chain=None, position=None, rule=None, family="ipv4"): family=ipv6 """ ret = { - "comment": "Failed to insert rule {} to table {}.".format(rule, table), + "comment": f"Failed to insert rule {rule} to table {table}.", "result": False, } @@ -1043,7 +1039,7 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): family=ipv6 """ ret = { - "comment": "Failed to delete rule {} in table {}.".format(rule, table), + "comment": f"Failed to delete rule {rule} in table {table}.", "result": False, } @@ -1131,17 +1127,17 @@ def flush(table="filter", chain="", family="ipv4"): cmd = "{} flush chain {} {} {}".format( _nftables_cmd(), nft_family, table, chain ) - comment = "from chain {} in table {} in family {}.".format(chain, table, family) + comment = f"from chain {chain} in table {table} in family {family}." else: - cmd = "{} flush table {} {}".format(_nftables_cmd(), nft_family, table) - comment = "from table {} in family {}.".format(table, family) + cmd = f"{_nftables_cmd()} flush table {nft_family} {table}" + comment = f"from table {table} in family {family}." out = __salt__["cmd.run"](cmd, python_shell=False) if not out: ret["result"] = True - ret["comment"] = "Flushed rules {}".format(comment) + ret["comment"] = f"Flushed rules {comment}" else: - ret["comment"] = "Failed to flush rules {}".format(comment) + ret["comment"] = f"Failed to flush rules {comment}" return ret @@ -1239,7 +1235,7 @@ def set_policy(table="filter", chain=None, policy=None, family="ipv4"): if not chain_info: return False - cmd = "{} add chain {} {} {}".format(_nftables_cmd(), nft_family, table, chain) + cmd = f"{_nftables_cmd()} add chain {nft_family} {table} {chain}" # We can't infer the base chain parameters. Bail out if they're not present. if "type" not in chain_info or "hook" not in chain_info or "prio" not in chain_info: @@ -1249,7 +1245,7 @@ def set_policy(table="filter", chain=None, policy=None, family="ipv4"): chain_info["type"], chain_info["hook"], chain_info["prio"] ) - cmd = '{0} "{{ {1} policy {2}; }}"'.format(cmd, params, policy) + cmd = f'{cmd} "{{ {params} policy {policy}; }}"' out = __salt__["cmd.run_all"](cmd, python_shell=False) diff --git a/salt/modules/nginx.py b/salt/modules/nginx.py index b684df5f6ff..21332816a5d 100644 --- a/salt/modules/nginx.py +++ b/salt/modules/nginx.py @@ -39,7 +39,7 @@ def version(): salt '*' nginx.version """ - cmd = "{} -v".format(__detect_os()) + cmd = f"{__detect_os()} -v" out = __salt__["cmd.run"](cmd).splitlines() ret = out[0].rsplit("/", maxsplit=1) return ret[-1] @@ -56,7 +56,7 @@ def build_info(): salt '*' nginx.build_info """ ret = {"info": []} - out = __salt__["cmd.run"]("{} -V".format(__detect_os())) + out = __salt__["cmd.run"](f"{__detect_os()} -V") for i in out.splitlines(): if i.startswith("configure argument"): @@ -80,7 +80,7 @@ def configtest(): """ ret = {} - cmd = "{} -t".format(__detect_os()) + cmd = f"{__detect_os()} -t" out = __salt__["cmd.run_all"](cmd) if out["retcode"] != 0: @@ -116,7 +116,7 @@ def signal(signal=None): if signal == "start": arguments = "" else: - arguments = " -s {}".format(signal) + arguments = f" -s {signal}" cmd = __detect_os() + arguments out = __salt__["cmd.run_all"](cmd) @@ -130,7 +130,7 @@ def signal(signal=None): ret = out["stdout"].strip() # No output for something like: nginxctl graceful else: - ret = 'Command: "{}" completed successfully!'.format(cmd) + ret = f'Command: "{cmd}" completed successfully!' return ret diff --git a/salt/modules/nilrt_ip.py b/salt/modules/nilrt_ip.py index 84612d7a17d..27243f2c70f 100644 --- a/salt/modules/nilrt_ip.py +++ b/salt/modules/nilrt_ip.py @@ -86,9 +86,7 @@ def _get_state(): except KeyError: return "offline" except dbus.DBusException as exc: - raise salt.exceptions.CommandExecutionError( - "Connman daemon error: {}".format(exc) - ) + raise salt.exceptions.CommandExecutionError(f"Connman daemon error: {exc}") def _get_technologies(): @@ -143,7 +141,7 @@ def _space_delimited_list(value): if valid: return True, "space-delimited string" - return False, "{} is not a valid list.\n".format(value) + return False, f"{value} is not a valid list.\n" def _validate_ipv4(value): @@ -152,13 +150,13 @@ def _validate_ipv4(value): """ if len(value) == 3: if not salt.utils.validate.net.ipv4_addr(value[0].strip()): - return False, "Invalid ip address: {} for ipv4 option".format(value[0]) + return False, f"Invalid ip address: {value[0]} for ipv4 option" if not salt.utils.validate.net.netmask(value[1].strip()): - return False, "Invalid netmask: {} for ipv4 option".format(value[1]) + return False, f"Invalid netmask: {value[1]} for ipv4 option" if not salt.utils.validate.net.ipv4_addr(value[2].strip()): - return False, "Invalid gateway: {} for ipv4 option".format(value[2]) + return False, f"Invalid gateway: {value[2]} for ipv4 option" else: - return False, "Invalid value: {} for ipv4 option".format(value) + return False, f"Invalid value: {value} for ipv4 option" return True, "" @@ -322,10 +320,8 @@ def _get_possible_adapter_modes(interface, blacklist): protocols = _load_config("lvrt", ["AdditionalNetworkProtocols"])[ "AdditionalNetworkProtocols" ].lower() - sys_interface_path = os.readlink("/sys/class/net/{}".format(interface)) - with salt.utils.files.fopen( - "/sys/class/net/{}/uevent".format(interface) - ) as uevent_file: + sys_interface_path = os.readlink(f"/sys/class/net/{interface}") + with salt.utils.files.fopen(f"/sys/class/net/{interface}/uevent") as uevent_file: uevent_lines = uevent_file.readlines() uevent_devtype = "" for line in uevent_lines: @@ -554,7 +550,7 @@ def _change_state_legacy(interface, new_state): if initial_mode == "ethercat": __salt__["system.set_reboot_required_witnessed"]() else: - out = __salt__["cmd.run_all"]("ip link set {} {}".format(interface, new_state)) + out = __salt__["cmd.run_all"](f"ip link set {interface} {new_state}") if out["retcode"] != 0: msg = "Couldn't {} interface {}. Error: {}".format( "enable" if new_state == "up" else "disable", interface, out["stderr"] @@ -582,22 +578,22 @@ def _change_dhcp_config(interface, enable_dhcp=True, filename=INTERFACES_CONFIG) interface = pyiface.Interface(name=interface) hwaddr = interface.hwaddr[:-1] hwaddr_section_number = "".join(hwaddr.split(":")) - if parser.has_section("service_{}".format(hwaddr_section_number)): - parser.remove_section("service_{}".format(hwaddr_section_number)) - parser.add_section("service_{}".format(hwaddr_section_number)) - parser.set("service_{}".format(hwaddr_section_number), "MAC", hwaddr) + if parser.has_section(f"service_{hwaddr_section_number}"): + parser.remove_section(f"service_{hwaddr_section_number}") + parser.add_section(f"service_{hwaddr_section_number}") + parser.set(f"service_{hwaddr_section_number}", "MAC", hwaddr) parser.set( - "service_{}".format(hwaddr_section_number), + f"service_{hwaddr_section_number}", "Name", - "ethernet_cable_{}".format(hwaddr_section_number), + f"ethernet_cable_{hwaddr_section_number}", ) - parser.set("service_{}".format(hwaddr_section_number), "Type", "ethernet") + parser.set(f"service_{hwaddr_section_number}", "Type", "ethernet") if enable_dhcp: - parser.set("service_{}".format(hwaddr_section_number), "IPv4.Method", "dhcp") - parser.set("service_{}".format(hwaddr_section_number), "AutoConnect", "true") - parser.set("service_{}".format(hwaddr_section_number), "Nameservers", "''") + parser.set(f"service_{hwaddr_section_number}", "IPv4.Method", "dhcp") + parser.set(f"service_{hwaddr_section_number}", "AutoConnect", "true") + parser.set(f"service_{hwaddr_section_number}", "Nameservers", "''") else: - parser.set("service_{}".format(hwaddr_section_number), "IPv4", "off") + parser.set(f"service_{hwaddr_section_number}", "IPv4", "off") with salt.utils.files.fopen(filename, "w") as config_file: parser.write(config_file) return True @@ -622,9 +618,7 @@ def _change_state(interface, new_state): if new_state == "up" else _change_dhcp_config(interface, False) ) - raise salt.exceptions.CommandExecutionError( - "Invalid interface name: {}".format(interface) - ) + raise salt.exceptions.CommandExecutionError(f"Invalid interface name: {interface}") def up(interface, iface_type=None): # pylint: disable=invalid-name,unused-argument @@ -708,9 +702,9 @@ def _save_config(section, token, value): Helper function to persist a configuration in the ini file """ cmd = NIRTCFG_PATH - cmd += " --set section={},token='{}',value='{}'".format(section, token, value) + cmd += f" --set section={section},token='{token}',value='{value}'" if __salt__["cmd.run_all"](cmd)["retcode"] != 0: - exc_msg = "Error: could not set {} to {} for {}\n".format(token, value, section) + exc_msg = f"Error: could not set {token} to {value} for {section}\n" raise salt.exceptions.CommandExecutionError(exc_msg) @@ -775,9 +769,7 @@ def set_dhcp_linklocal_all(interface): return True if interface in [x.name for x in pyiface.getIfaces()]: return _change_dhcp_config(interface) - raise salt.exceptions.CommandExecutionError( - "Invalid interface name: {}".format(interface) - ) + raise salt.exceptions.CommandExecutionError(f"Invalid interface name: {interface}") def set_dhcp_only_all(interface): @@ -863,24 +855,24 @@ def _configure_static_interface(interface, **settings): pass hwaddr = interface.hwaddr[:-1] hwaddr_section_number = "".join(hwaddr.split(":")) - if parser.has_section("service_{}".format(hwaddr_section_number)): - parser.remove_section("service_{}".format(hwaddr_section_number)) - parser.add_section("service_{}".format(hwaddr_section_number)) + if parser.has_section(f"service_{hwaddr_section_number}"): + parser.remove_section(f"service_{hwaddr_section_number}") + parser.add_section(f"service_{hwaddr_section_number}") ip_address = settings.get("ip", "0.0.0.0") netmask = settings.get("netmask", "0.0.0.0") gateway = settings.get("gateway", "0.0.0.0") dns_servers = settings.get("dns", "''") - name = settings.get("name", "ethernet_cable_{}".format(hwaddr_section_number)) + name = settings.get("name", f"ethernet_cable_{hwaddr_section_number}") parser.set( - "service_{}".format(hwaddr_section_number), + f"service_{hwaddr_section_number}", "IPv4", - "{}/{}/{}".format(ip_address, netmask, gateway), + f"{ip_address}/{netmask}/{gateway}", ) - parser.set("service_{}".format(hwaddr_section_number), "Nameservers", dns_servers) - parser.set("service_{}".format(hwaddr_section_number), "Name", name) - parser.set("service_{}".format(hwaddr_section_number), "MAC", hwaddr) - parser.set("service_{}".format(hwaddr_section_number), "Type", "ethernet") - parser.set("service_{}".format(hwaddr_section_number), "IPv4.method", "manual") + parser.set(f"service_{hwaddr_section_number}", "Nameservers", dns_servers) + parser.set(f"service_{hwaddr_section_number}", "Name", name) + parser.set(f"service_{hwaddr_section_number}", "MAC", hwaddr) + parser.set(f"service_{hwaddr_section_number}", "Type", "ethernet") + parser.set(f"service_{hwaddr_section_number}", "IPv4.method", "manual") with salt.utils.files.fopen(INTERFACES_CONFIG, "w") as config_file: parser.write(config_file) return True @@ -941,23 +933,23 @@ def set_static_all(interface, address, netmask, gateway, nameservers=None): "dns": ",".join(nameservers) if nameservers else "", "netmask": netmask, "gateway": gateway, - } + }, ) raise salt.exceptions.CommandExecutionError( - "Invalid interface name: {}".format(interface) + f"Invalid interface name: {interface}" ) service = pyconnman.ConnService(os.path.join(SERVICE_PATH, service)) ipv4 = service.get_property("IPv4.Configuration") ipv4["Method"] = dbus.String("manual", variant_level=1) - ipv4["Address"] = dbus.String("{}".format(address), variant_level=1) - ipv4["Netmask"] = dbus.String("{}".format(netmask), variant_level=1) - ipv4["Gateway"] = dbus.String("{}".format(gateway), variant_level=1) + ipv4["Address"] = dbus.String(f"{address}", variant_level=1) + ipv4["Netmask"] = dbus.String(f"{netmask}", variant_level=1) + ipv4["Gateway"] = dbus.String(f"{gateway}", variant_level=1) try: service.set_property("IPv4.Configuration", ipv4) if nameservers: service.set_property( "Nameservers.Configuration", - [dbus.String("{}".format(d)) for d in nameservers], + [dbus.String(f"{d}") for d in nameservers], ) except Exception as exc: # pylint: disable=broad-except exc_msg = "Couldn't set manual settings for service: {}\nError: {}\n".format( @@ -998,7 +990,7 @@ def build_interface(iface, iface_type, enabled, **settings): raise salt.exceptions.CommandExecutionError("Not supported in this version.") if iface_type != "eth": raise salt.exceptions.CommandExecutionError( - "Interface type not supported: {}:".format(iface_type) + f"Interface type not supported: {iface_type}:" ) if ( @@ -1049,7 +1041,7 @@ def build_network_settings(**settings): old_hostname = __salt__["network.get_hostname"] if new_hostname != old_hostname: __salt__["network.mod_hostname"](new_hostname) - changes.append("hostname={}".format(new_hostname)) + changes.append(f"hostname={new_hostname}") return changes @@ -1068,9 +1060,9 @@ def get_network_settings(): raise salt.exceptions.CommandExecutionError("Not supported in this version.") settings = [] networking = "no" if _get_state() == "offline" else "yes" - settings.append("networking={}".format(networking)) + settings.append(f"networking={networking}") hostname = __salt__["network.get_hostname"] - settings.append("hostname={}".format(hostname)) + settings.append(f"hostname={hostname}") return settings diff --git a/salt/modules/npm.py b/salt/modules/npm.py index edbb7b4ae1d..f7a40043de4 100644 --- a/salt/modules/npm.py +++ b/salt/modules/npm.py @@ -47,9 +47,7 @@ def _check_valid_version(): npm_path = salt.utils.path.which("npm") # pylint: disable=no-member - res = salt.modules.cmdmod.run( - "{npm} --version".format(npm=npm_path), output_loglevel="quiet" - ) + res = salt.modules.cmdmod.run(f"{npm_path} --version", output_loglevel="quiet") npm_version = Version(res) valid_version = Version("1.2") # pylint: enable=no-member @@ -151,7 +149,7 @@ def install( cwd = dir if registry: - cmd.append('--registry="{}"'.format(registry)) + cmd.append(f'--registry="{registry}"') if dry_run: cmd.append("--dry-run") @@ -222,7 +220,7 @@ def uninstall(pkg, dir=None, runas=None, env=None): if uid: env.update({"SUDO_UID": uid, "SUDO_USER": ""}) - cmd = ["npm", "uninstall", '"{}"'.format(pkg)] + cmd = ["npm", "uninstall", f'"{pkg}"'] if not dir: cmd.append("--global") @@ -291,14 +289,14 @@ def list_(pkg=None, dir=None, runas=None, env=None, depth=None): if depth is not None: if not isinstance(depth, (int, float)): raise salt.exceptions.SaltInvocationError( - "Error: depth {} must be a number".format(depth) + f"Error: depth {depth} must be a number" ) - cmd.append("--depth={}".format(int(depth))) + cmd.append(f"--depth={int(depth)}") if pkg: # Protect against injection pkg = shlex.quote(pkg) - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') cmd = " ".join(cmd) result = __salt__["cmd.run_all"]( diff --git a/salt/modules/nspawn.py b/salt/modules/nspawn.py index a1893ef8d2c..cd9d34e9e34 100644 --- a/salt/modules/nspawn.py +++ b/salt/modules/nspawn.py @@ -80,7 +80,7 @@ def _ensure_exists(wrapped): @functools.wraps(wrapped) def check_exists(name, *args, **kwargs): if not exists(name): - raise CommandExecutionError("Container '{}' does not exist".format(name)) + raise CommandExecutionError(f"Container '{name}' does not exist") return wrapped(name, *args, **salt.utils.args.clean_kwargs(**kwargs)) return check_exists @@ -114,14 +114,14 @@ def _make_container_root(name): path = _root(name) if os.path.exists(path): __context__["retcode"] = salt.defaults.exitcodes.SALT_BUILD_FAIL - raise CommandExecutionError("Container {} already exists".format(name)) + raise CommandExecutionError(f"Container {name} already exists") else: try: os.makedirs(path) return path except OSError as exc: raise CommandExecutionError( - "Unable to make container root directory {}: {}".format(name, exc) + f"Unable to make container root directory {name}: {exc}" ) @@ -131,10 +131,8 @@ def _build_failed(dst, name): shutil.rmtree(dst) except OSError as exc: if exc.errno != errno.ENOENT: - raise CommandExecutionError( - "Unable to cleanup container root dir {}".format(dst) - ) - raise CommandExecutionError("Container {} failed to build".format(name)) + raise CommandExecutionError(f"Unable to cleanup container root dir {dst}") + raise CommandExecutionError(f"Container {name} failed to build") def _bootstrap_arch(name, **kwargs): @@ -146,7 +144,7 @@ def _bootstrap_arch(name, **kwargs): "pacstrap not found, is the arch-install-scripts package installed?" ) dst = _make_container_root(name) - cmd = "pacstrap -c -d {} base".format(dst) + cmd = f"pacstrap -c -d {dst} base" ret = __salt__["cmd.run_all"](cmd, python_shell=False) if ret["retcode"] != 0: _build_failed(dst, name) @@ -182,7 +180,7 @@ def _bootstrap_debian(name, **kwargs): ) dst = _make_container_root(name) - cmd = "debootstrap --arch=amd64 {} {}".format(version, dst) + cmd = f"debootstrap --arch=amd64 {version} {dst}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) if ret["retcode"] != 0: _build_failed(dst, name) @@ -223,7 +221,7 @@ def _bootstrap_ubuntu(name, **kwargs): else: version = "xenial" dst = _make_container_root(name) - cmd = "debootstrap --arch=amd64 {} {}".format(version, dst) + cmd = f"debootstrap --arch=amd64 {version} {dst}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) if ret["retcode"] != 0: _build_failed(dst, name) @@ -257,7 +255,7 @@ def _ensure_systemd(version): try: version = int(version) except ValueError: - raise CommandExecutionError("Invalid version '{}'".format(version)) + raise CommandExecutionError(f"Invalid version '{version}'") try: installed = _sd_version() @@ -279,7 +277,7 @@ def _machinectl(cmd, output_loglevel="debug", ignore_retcode=False, use_vt=False """ prefix = "machinectl --no-legend --no-pager" return __salt__["cmd.run_all"]( - "{} {}".format(prefix, cmd), + f"{prefix} {cmd}", output_loglevel=output_loglevel, ignore_retcode=ignore_retcode, use_vt=use_vt, @@ -349,9 +347,7 @@ def pid(name): try: return int(info(name).get("PID")) except (TypeError, ValueError) as exc: - raise CommandExecutionError( - "Unable to get PID for container '{}': {}".format(name, exc) - ) + raise CommandExecutionError(f"Unable to get PID for container '{name}': {exc}") def run( @@ -705,9 +701,9 @@ def bootstrap_container(name, dist=None, version=None): dist = __grains__["os"].lower() log.debug("nspawn.bootstrap: no dist provided, defaulting to '%s'", dist) try: - return globals()["_bootstrap_{}".format(dist)](name, version=version) + return globals()[f"_bootstrap_{dist}"](name, version=version) except KeyError: - raise CommandExecutionError('Unsupported distribution "{}"'.format(dist)) + raise CommandExecutionError(f'Unsupported distribution "{dist}"') def _needs_install(name): @@ -785,7 +781,7 @@ def bootstrap_salt( needs_install = _needs_install(name) else: needs_install = True - seeded = retcode(name, "test -e '{}'".format(SEED_MARKER)) == 0 + seeded = retcode(name, f"test -e '{SEED_MARKER}'") == 0 tmp = tempfile.mkdtemp() if seeded and not unconditional_install: ret = True @@ -802,20 +798,20 @@ def bootstrap_salt( if needs_install or force_install or unconditional_install: if install: rstr = __salt__["test.random_hash"]() - configdir = "/tmp/.c_{}".format(rstr) - run(name, "install -m 0700 -d {}".format(configdir), python_shell=False) + configdir = f"/tmp/.c_{rstr}" + run(name, f"install -m 0700 -d {configdir}", python_shell=False) bs_ = __salt__["config.gather_bootstrap_script"]( bootstrap=bootstrap_url ) dest_dir = os.path.join("/tmp", rstr) for cmd in [ - "mkdir -p {}".format(dest_dir), - "chmod 700 {}".format(dest_dir), + f"mkdir -p {dest_dir}", + f"chmod 700 {dest_dir}", ]: if run_stdout(name, cmd): log.error("tmpdir %s creation failed (%s)", dest_dir, cmd) return False - copy_to(name, bs_, "{}/bootstrap.sh".format(dest_dir), makedirs=True) + copy_to(name, bs_, f"{dest_dir}/bootstrap.sh", makedirs=True) copy_to(name, cfg_files["config"], os.path.join(configdir, "minion")) copy_to( name, cfg_files["privkey"], os.path.join(configdir, "minion.pem") @@ -848,7 +844,7 @@ def bootstrap_salt( stop(name) # mark seeded upon successful install if ret: - run(name, "touch '{}'".format(SEED_MARKER), python_shell=False) + run(name, f"touch '{SEED_MARKER}'", python_shell=False) return ret @@ -932,7 +928,7 @@ def exists(name): salt myminion nspawn.exists """ - contextkey = "nspawn.exists.{}".format(name) + contextkey = f"nspawn.exists.{name}" if contextkey in __context__: return __context__[contextkey] __context__[contextkey] = name in list_all() @@ -951,7 +947,7 @@ def state(name): salt myminion nspawn.state """ try: - cmd = "show {} --property=State".format(name) + cmd = f"show {name} --property=State" return _machinectl(cmd, ignore_retcode=True)["stdout"].split("=")[-1] except IndexError: return "stopped" @@ -991,11 +987,9 @@ def info(name, **kwargs): # Have to parse 'machinectl status' here since 'machinectl show' doesn't # contain IP address info or OS info. *shakes fist angrily* - c_info = _machinectl("status {}".format(name)) + c_info = _machinectl(f"status {name}") if c_info["retcode"] != 0: - raise CommandExecutionError( - "Unable to get info for container '{}'".format(name) - ) + raise CommandExecutionError(f"Unable to get info for container '{name}'") # Better human-readable names. False means key should be ignored. key_name_map = { "Iface": "Network Interface", @@ -1051,7 +1045,7 @@ def enable(name): salt myminion nspawn.enable """ - cmd = "systemctl enable systemd-nspawn@{}".format(name) + cmd = f"systemctl enable systemd-nspawn@{name}" if __salt__["cmd.retcode"](cmd, python_shell=False) != 0: __context__["retcode"] = salt.defaults.exitcodes.EX_UNAVAILABLE return False @@ -1069,7 +1063,7 @@ def disable(name): salt myminion nspawn.enable """ - cmd = "systemctl disable systemd-nspawn@{}".format(name) + cmd = f"systemctl disable systemd-nspawn@{name}" if __salt__["cmd.retcode"](cmd, python_shell=False) != 0: __context__["retcode"] = salt.defaults.exitcodes.EX_UNAVAILABLE return False @@ -1088,9 +1082,9 @@ def start(name): salt myminion nspawn.start """ if _sd_version() >= 219: - ret = _machinectl("start {}".format(name)) + ret = _machinectl(f"start {name}") else: - cmd = "systemctl start systemd-nspawn@{}".format(name) + cmd = f"systemctl start systemd-nspawn@{name}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) if ret["retcode"] != 0: @@ -1111,9 +1105,9 @@ def stop(name, kill=False): action = "terminate" else: action = "poweroff" - ret = _machinectl("{} {}".format(action, name)) + ret = _machinectl(f"{action} {name}") else: - cmd = "systemctl stop systemd-nspawn@{}".format(name) + cmd = f"systemctl stop systemd-nspawn@{name}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) if ret["retcode"] != 0: @@ -1203,7 +1197,7 @@ def reboot(name, kill=False): """ if _sd_version() >= 219: if state(name) == "running": - ret = _machinectl("reboot {}".format(name)) + ret = _machinectl(f"reboot {name}") else: # 'machinectl reboot' will fail on a stopped container return start(name) @@ -1213,7 +1207,7 @@ def reboot(name, kill=False): # we need stop and start the container in separate actions. # First stop the container - cmd = "systemctl stop systemd-nspawn@{}".format(name) + cmd = f"systemctl stop systemd-nspawn@{name}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) # Now check if successful if ret["retcode"] != 0: @@ -1221,7 +1215,7 @@ def reboot(name, kill=False): return False # Finally, start the container back up. No need to check the retcode a # second time, it'll be checked below once we exit the if/else block. - cmd = "systemctl start systemd-nspawn@{}".format(name) + cmd = f"systemctl start systemd-nspawn@{name}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) if ret["retcode"] != 0: @@ -1256,15 +1250,13 @@ def remove(name, stop=False): salt '*' nspawn.remove foo stop=True """ if not stop and state(name) != "stopped": - raise CommandExecutionError("Container '{}' is not stopped".format(name)) + raise CommandExecutionError(f"Container '{name}' is not stopped") def _failed_remove(name, exc): - raise CommandExecutionError( - "Unable to remove container '{}': {}".format(name, exc) - ) + raise CommandExecutionError(f"Unable to remove container '{name}': {exc}") if _sd_version() >= 219: - ret = _machinectl("remove {}".format(name)) + ret = _machinectl(f"remove {name}") if ret["retcode"] != 0: __context__["retcode"] = salt.defaults.exitcodes.EX_UNAVAILABLE _failed_remove(name, ret["stderr"]) @@ -1314,10 +1306,10 @@ def copy_to(name, source, dest, overwrite=False, makedirs=False): if source.startswith("salt://"): cached_source = __salt__["cp.cache_file"](source) if not cached_source: - raise CommandExecutionError("Unable to cache {}".format(source)) + raise CommandExecutionError(f"Unable to cache {source}") path = cached_source except AttributeError: - raise SaltInvocationError("Invalid source file {}".format(source)) + raise SaltInvocationError(f"Invalid source file {source}") if _sd_version() >= 219: # TODO: Use machinectl copy-to @@ -1345,13 +1337,13 @@ def _pull_image(pull_type, image, name, **kwargs): """ _ensure_systemd(219) if exists(name): - raise SaltInvocationError("Container '{}' already exists".format(name)) + raise SaltInvocationError(f"Container '{name}' already exists") if pull_type in ("raw", "tar"): valid_kwargs = ("verify",) elif pull_type == "dkr": valid_kwargs = ("index",) else: - raise SaltInvocationError("Unsupported image type '{}'".format(pull_type)) + raise SaltInvocationError(f"Unsupported image type '{pull_type}'") kwargs = salt.utils.args.clean_kwargs(**kwargs) bad_kwargs = { @@ -1383,7 +1375,7 @@ def _pull_image(pull_type, image, name, **kwargs): else: if verify not in ("signature", "checksum"): _bad_verify() - pull_opts.append("--verify={}".format(verify)) + pull_opts.append(f"--verify={verify}") elif pull_type == "dkr": # No need to validate the index URL, machinectl will take care of this diff --git a/salt/modules/nxos.py b/salt/modules/nxos.py index d1bd109063c..0cf01667d36 100644 --- a/salt/modules/nxos.py +++ b/salt/modules/nxos.py @@ -258,7 +258,7 @@ def get_roles(username, **kwargs): user = get_user(username) if not user: return [] - command = "show user-account {}".format(username) + command = f"show user-account {username}" info = sendline(command, **kwargs) if isinstance(info, list): info = info[0] @@ -278,7 +278,7 @@ def get_user(username, **kwargs): salt '*' nxos.get_user username=admin """ - command = 'show run | include "^username {} password 5 "'.format(username) + command = f'show run | include "^username {username} password 5 "' info = sendline(command, **kwargs) if isinstance(info, list): info = info[0] @@ -492,7 +492,7 @@ def config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Configures the Nexus switch with the specified commands. @@ -562,7 +562,7 @@ def config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") elif commands: if isinstance(commands, str): commands = [commands] @@ -664,7 +664,7 @@ def remove_user(username, **kwargs): salt '*' nxos.remove_user username=daniel """ - user_line = "no username {}".format(username) + user_line = f"no username {username}" kwargs = clean_kwargs(**kwargs) return config(user_line, **kwargs) @@ -681,7 +681,7 @@ def replace(old_value, new_value, full_match=False, **kwargs): salt '*' nxos.replace 'TESTSTRINGHERE' 'NEWTESTSTRINGHERE' """ if full_match is False: - matcher = re.compile("^.*{}.*$".format(re.escape(old_value)), re.MULTILINE) + matcher = re.compile(f"^.*{re.escape(old_value)}.*$", re.MULTILINE) repl = re.compile(re.escape(old_value)) else: matcher = re.compile(old_value, re.MULTILINE) @@ -719,7 +719,7 @@ def set_password( role=None, crypt_salt=None, algorithm="sha256", - **kwargs + **kwargs, ): """ Set users password on switch. @@ -767,9 +767,9 @@ def set_password( ) else: hashed_pass = password - password_line = "username {} password 5 {}".format(username, hashed_pass) + password_line = f"username {username} password 5 {hashed_pass}" if role is not None: - password_line += " role {}".format(role) + password_line += f" role {role}" kwargs = clean_kwargs(**kwargs) return config(password_line, **kwargs) @@ -793,7 +793,7 @@ def set_role(username, role, **kwargs): salt '*' nxos.set_role username=daniel role=vdc-admin. """ - role_line = "username {} role {}".format(username, role) + role_line = f"username {username} role {role}" kwargs = clean_kwargs(**kwargs) return config(role_line, **kwargs) @@ -817,7 +817,7 @@ def unset_role(username, role, **kwargs): salt '*' nxos.unset_role username=daniel role=vdc-admin """ - role_line = "no username {} role {}".format(username, role) + role_line = f"no username {username} role {role}" kwargs = clean_kwargs(**kwargs) return config(role_line, **kwargs) diff --git a/salt/modules/nxos_api.py b/salt/modules/nxos_api.py index 2513d9b0ff9..b787043f354 100644 --- a/salt/modules/nxos_api.py +++ b/salt/modules/nxos_api.py @@ -181,7 +181,7 @@ def _cli_command(commands, method="cli", **kwargs): ) raise SaltException(msg) else: - msg = 'Invalid command: "{cmd}".'.format(cmd=cmd) + msg = f'Invalid command: "{cmd}".' raise SaltException(msg) txt_responses.append(rpc_reponse["result"]) return txt_responses @@ -313,7 +313,7 @@ def config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Configures the Nexus switch with the specified commands. @@ -401,7 +401,7 @@ def config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") elif commands: if isinstance(commands, str): commands = [commands] diff --git a/salt/modules/nxos_upgrade.py b/salt/modules/nxos_upgrade.py index 69ce8d2b5c4..25f662db8ee 100644 --- a/salt/modules/nxos_upgrade.py +++ b/salt/modules/nxos_upgrade.py @@ -114,7 +114,7 @@ def check_upgrade_impact(system_image, kickstart_image=None, issu=True, **kwargs if ki is not None: cmd = cmd + " kickstart {0}:{1} system {0}:{2}".format(dev, ki, si) else: - cmd = cmd + " nxos {}:{}".format(dev, si) + cmd = cmd + f" nxos {dev}:{si}" if issu and ki is None: cmd = cmd + " non-disruptive" @@ -254,14 +254,14 @@ def _upgrade(system_image, kickstart_image, issu, **kwargs): if ki is None: logmsg = "Upgrading device using combined system/kickstart image." - logmsg += "\nSystem Image: {}".format(si) - cmd = cmd + " nxos {}:{}".format(dev, si) + logmsg += f"\nSystem Image: {si}" + cmd = cmd + f" nxos {dev}:{si}" if issu: cmd = cmd + " non-disruptive" else: logmsg = "Upgrading device using separate system/kickstart images." - logmsg += "\nSystem Image: {}".format(si) - logmsg += "\nKickstart Image: {}".format(ki) + logmsg += f"\nSystem Image: {si}" + logmsg += f"\nKickstart Image: {ki}" if not issu: log.info("Attempting upgrade using force option") cmd = cmd + " force" @@ -367,7 +367,7 @@ def _parse_upgrade_data(data): g3 = mo.group(3) g4 = mo.group(4) g5 = mo.group(5) - mk = "module {}:image {}".format(g1, g2) # module key + mk = f"module {g1}:image {g2}" # module key upgrade_result[bk][mk] = {} upgrade_result[bk][mk]["running_version"] = g3 upgrade_result[bk][mk]["new_version"] = g4 diff --git a/salt/modules/omapi.py b/salt/modules/omapi.py index fd92162b04b..e5d01260012 100644 --- a/salt/modules/omapi.py +++ b/salt/modules/omapi.py @@ -86,9 +86,9 @@ def add_host(mac, name=None, ip=None, ddns=False, group=None, supersede_host=Fal if group: msg.obj.append((b"group", salt.utils.stringutils.to_bytes(group))) if supersede_host: - statements += 'option host-name "{}"; '.format(name) + statements += f'option host-name "{name}"; ' if ddns and name: - statements += 'ddns-hostname "{}"; '.format(name) + statements += f'ddns-hostname "{name}"; ' if statements: msg.obj.append((b"statements", salt.utils.stringutils.to_bytes(statements))) response = o.query_server(msg) diff --git a/salt/modules/openbsd_sysctl.py b/salt/modules/openbsd_sysctl.py index 35a49297404..348d164efd0 100644 --- a/salt/modules/openbsd_sysctl.py +++ b/salt/modules/openbsd_sysctl.py @@ -61,7 +61,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd) return out @@ -77,7 +77,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.ip.forwarding 1 """ ret = {} - cmd = 'sysctl {}="{}"'.format(name, value) + cmd = f'sysctl {name}="{value}"' data = __salt__["cmd.run_all"](cmd) # Certain values cannot be set from this console, at the current @@ -119,7 +119,7 @@ def persist(name, value, config="/etc/sysctl.conf"): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - if not line.startswith("{}=".format(name)): + if not line.startswith(f"{name}="): nlines.append(line) continue else: @@ -133,11 +133,11 @@ def persist(name, value, config="/etc/sysctl.conf"): rest = rest[len(rest_v) :] if rest_v == value: return "Already set" - new_line = "{}={}{}".format(key, value, rest) + new_line = f"{key}={value}{rest}" nlines.append(new_line) edited = True if not edited: - nlines.append("{}={}\n".format(name, value)) + nlines.append(f"{name}={value}\n") with salt.utils.files.fopen(config, "wb") as ofile: ofile.writelines(salt.utils.data.encode(nlines)) diff --git a/salt/modules/openbsdpkg.py b/salt/modules/openbsdpkg.py index 3cbdc0cadf1..57d28ed96b5 100644 --- a/salt/modules/openbsdpkg.py +++ b/salt/modules/openbsdpkg.py @@ -95,7 +95,7 @@ def list_pkgs(versions_as_list=False, **kwargs): pkgname, pkgver, flavor = __PKG_RE.match(line).groups() except AttributeError: continue - pkgname += "--{}".format(flavor) if flavor else "" + pkgname += f"--{flavor}" if flavor else "" __salt__["pkg_resource.add_pkg"](ret, pkgname, pkgver) __salt__["pkg_resource.sort_pkglist"](ret) @@ -129,7 +129,7 @@ def latest_version(*names, **kwargs): ret[name] = "" # Query the repository for the package name - cmd = "pkg_info -Q {}".format(name) + cmd = f"pkg_info -Q {name}" out = __salt__["cmd.run_stdout"]( cmd, python_shell=False, output_loglevel="trace" ) @@ -153,8 +153,8 @@ def latest_version(*names, **kwargs): # First check if we need to look for flavors before # looking at unflavored packages. - if "{}--{}".format(pkgname, flavor) == name: - pkgname += "--{}".format(flavor) + if f"{pkgname}--{flavor}" == name: + pkgname += f"--{flavor}" elif pkgname == name: pass else: @@ -233,8 +233,8 @@ def install(name=None, pkgs=None, sources=None, **kwargs): if pkg_type == "repository": stem, branch = (pkg.split("%") + [""])[:2] base, flavor = (stem.split("--") + [""])[:2] - pkg = "{}--{}%{}".format(base, flavor, branch) - cmd = "pkg_add -x -I {}".format(pkg) + pkg = f"{base}--{flavor}%{branch}" + cmd = f"pkg_add -x -I {pkg}" out = __salt__["cmd.run_all"](cmd, python_shell=False, output_loglevel="trace") if out["retcode"] != 0 and out["stderr"]: errors.append(out["stderr"]) diff --git a/salt/modules/openbsdrcctl_service.py b/salt/modules/openbsdrcctl_service.py index 4baa0a4c56a..8a80cf57acd 100644 --- a/salt/modules/openbsdrcctl_service.py +++ b/salt/modules/openbsdrcctl_service.py @@ -56,7 +56,7 @@ def available(name): salt '*' service.available sshd """ - cmd = "{} get {}".format(_cmd(), name) + cmd = f"{_cmd()} get {name}" if __salt__["cmd.retcode"](cmd, ignore_retcode=True) == 2: return False return True @@ -88,7 +88,7 @@ def get_all(): """ ret = [] service = _cmd() - for svc in __salt__["cmd.run"]("{} ls all".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} ls all").splitlines(): ret.append(svc) return sorted(ret) @@ -105,7 +105,7 @@ def get_disabled(): """ ret = [] service = _cmd() - for svc in __salt__["cmd.run"]("{} ls off".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} ls off").splitlines(): ret.append(svc) return sorted(ret) @@ -122,7 +122,7 @@ def get_enabled(): """ ret = [] service = _cmd() - for svc in __salt__["cmd.run"]("{} ls on".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} ls on").splitlines(): ret.append(svc) return sorted(ret) @@ -137,7 +137,7 @@ def start(name): salt '*' service.start """ - cmd = "{} -f start {}".format(_cmd(), name) + cmd = f"{_cmd()} -f start {name}" return not __salt__["cmd.retcode"](cmd) @@ -151,7 +151,7 @@ def stop(name): salt '*' service.stop """ - cmd = "{} stop {}".format(_cmd(), name) + cmd = f"{_cmd()} stop {name}" return not __salt__["cmd.retcode"](cmd) @@ -165,7 +165,7 @@ def restart(name): salt '*' service.restart """ - cmd = "{} -f restart {}".format(_cmd(), name) + cmd = f"{_cmd()} -f restart {name}" return not __salt__["cmd.retcode"](cmd) @@ -179,7 +179,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "{} reload {}".format(_cmd(), name) + cmd = f"{_cmd()} reload {name}" return not __salt__["cmd.retcode"](cmd) @@ -197,7 +197,7 @@ def status(name, sig=None): if sig: return bool(__salt__["status.pid"](sig)) - cmd = "{} check {}".format(_cmd(), name) + cmd = f"{_cmd()} check {name}" return not __salt__["cmd.retcode"](cmd, ignore_retcode=True) @@ -217,14 +217,14 @@ def enable(name, **kwargs): salt '*' service.enable salt '*' service.enable flags= """ - stat_cmd = "{} set {} status on".format(_cmd(), name) + stat_cmd = f"{_cmd()} set {name} status on" stat_retcode = __salt__["cmd.retcode"](stat_cmd) flag_retcode = None # only (re)set flags for services that have an rc.d(8) script - if os.path.exists("/etc/rc.d/{}".format(name)): + if os.path.exists(f"/etc/rc.d/{name}"): flags = _get_flags(**kwargs) - flag_cmd = "{} set {} flags {}".format(_cmd(), name, flags) + flag_cmd = f"{_cmd()} set {name} flags {flags}" flag_retcode = __salt__["cmd.retcode"](flag_cmd) return not any([stat_retcode, flag_retcode]) @@ -240,7 +240,7 @@ def disable(name, **kwargs): salt '*' service.disable """ - cmd = "{} set {} status off".format(_cmd(), name) + cmd = f"{_cmd()} set {name} status off" return not __salt__["cmd.retcode"](cmd) @@ -254,7 +254,7 @@ def disabled(name): salt '*' service.disabled """ - cmd = "{} get {} status".format(_cmd(), name) + cmd = f"{_cmd()} get {name} status" return not __salt__["cmd.retcode"](cmd, ignore_retcode=True) == 0 @@ -273,18 +273,16 @@ def enabled(name, **kwargs): salt '*' service.enabled salt '*' service.enabled flags= """ - cmd = "{} get {} status".format(_cmd(), name) + cmd = f"{_cmd()} get {name} status" if not __salt__["cmd.retcode"](cmd, ignore_retcode=True): # also consider a service disabled if the current flags are different # than the configured ones so we have a chance to update them flags = _get_flags(**kwargs) - cur_flags = __salt__["cmd.run_stdout"]("{} get {} flags".format(_cmd(), name)) + cur_flags = __salt__["cmd.run_stdout"](f"{_cmd()} get {name} flags") if format(flags) == format(cur_flags): return True if not flags: - def_flags = __salt__["cmd.run_stdout"]( - "{} getdef {} flags".format(_cmd(), name) - ) + def_flags = __salt__["cmd.run_stdout"](f"{_cmd()} getdef {name} flags") if format(cur_flags) == format(def_flags): return True diff --git a/salt/modules/openbsdservice.py b/salt/modules/openbsdservice.py index 58304aa9fdb..70fe9981f54 100644 --- a/salt/modules/openbsdservice.py +++ b/salt/modules/openbsdservice.py @@ -55,7 +55,7 @@ def start(name): salt '*' service.start """ - cmd = "/etc/rc.d/{} -f start".format(name) + cmd = f"/etc/rc.d/{name} -f start" return not __salt__["cmd.retcode"](cmd) @@ -69,7 +69,7 @@ def stop(name): salt '*' service.stop """ - cmd = "/etc/rc.d/{} -f stop".format(name) + cmd = f"/etc/rc.d/{name} -f stop" return not __salt__["cmd.retcode"](cmd) @@ -83,7 +83,7 @@ def restart(name): salt '*' service.restart """ - cmd = "/etc/rc.d/{} -f restart".format(name) + cmd = f"/etc/rc.d/{name} -f restart" return not __salt__["cmd.retcode"](cmd) @@ -120,7 +120,7 @@ def status(name, sig=None): services = [name] results = {} for service in services: - cmd = "/etc/rc.d/{} -f check".format(service) + cmd = f"/etc/rc.d/{service} -f check" results[service] = not __salt__["cmd.retcode"](cmd, ignore_retcode=True) if contains_globbing: return results @@ -139,7 +139,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "/etc/rc.d/{} -f reload".format(name) + cmd = f"/etc/rc.d/{name} -f reload" return not __salt__["cmd.retcode"](cmd) @@ -219,7 +219,7 @@ def available(name): salt '*' service.available sshd """ - path = "/etc/rc.d/{}".format(name) + path = f"/etc/rc.d/{name}" return os.path.isfile(path) and os.access(path, os.X_OK) diff --git a/salt/modules/openvswitch.py b/salt/modules/openvswitch.py index e0dc7ac2677..8063d0ad52e 100644 --- a/salt/modules/openvswitch.py +++ b/salt/modules/openvswitch.py @@ -175,7 +175,7 @@ def bridge_exists(br): salt '*' openvswitch.bridge_exists br0 """ - cmd = "ovs-vsctl br-exists {}".format(br) + cmd = f"ovs-vsctl br-exists {br}" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] return _retcode_to_bool(retcode) @@ -215,8 +215,8 @@ def bridge_create(br, may_exist=True, parent=None, vlan=None): raise ArgumentValueError("If parent is specified, vlan must also be specified.") if vlan is not None and parent is None: raise ArgumentValueError("If vlan is specified, parent must also be specified.") - param_parent = "" if parent is None else " {}".format(parent) - param_vlan = "" if vlan is None else " {}".format(vlan) + param_parent = "" if parent is None else f" {parent}" + param_vlan = "" if vlan is None else f" {vlan}" cmd = "ovs-vsctl {1}add-br {0}{2}{3}".format( br, param_may_exist, param_parent, param_vlan ) @@ -244,7 +244,7 @@ def bridge_delete(br, if_exists=True): salt '*' openvswitch.bridge_delete br0 """ param_if_exists = _param_if_exists(if_exists) - cmd = "ovs-vsctl {1}del-br {0}".format(br, param_if_exists) + cmd = f"ovs-vsctl {param_if_exists}del-br {br}" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] return _retcode_to_bool(retcode) @@ -271,7 +271,7 @@ def bridge_to_parent(br): salt '*' openvswitch.bridge_to_parent br0 """ - cmd = "ovs-vsctl br-to-parent {}".format(br) + cmd = f"ovs-vsctl br-to-parent {br}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] != 0: return False @@ -298,7 +298,7 @@ def bridge_to_vlan(br): salt '*' openvswitch.bridge_to_parent br0 """ - cmd = "ovs-vsctl br-to-vlan {}".format(br) + cmd = f"ovs-vsctl br-to-vlan {br}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] != 0: return False @@ -327,9 +327,9 @@ def port_add(br, port, may_exist=False, internal=False): salt '*' openvswitch.port_add br0 8080 """ param_may_exist = _param_may_exist(may_exist) - cmd = "ovs-vsctl {2}add-port {0} {1}".format(br, port, param_may_exist) + cmd = f"ovs-vsctl {param_may_exist}add-port {br} {port}" if internal: - cmd += " -- set interface {} type=internal".format(port) + cmd += f" -- set interface {port} type=internal" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] return _retcode_to_bool(retcode) @@ -358,9 +358,9 @@ def port_remove(br, port, if_exists=True): param_if_exists = _param_if_exists(if_exists) if port and not br: - cmd = "ovs-vsctl {1}del-port {0}".format(port, param_if_exists) + cmd = f"ovs-vsctl {param_if_exists}del-port {port}" else: - cmd = "ovs-vsctl {2}del-port {0} {1}".format(br, port, param_if_exists) + cmd = f"ovs-vsctl {param_if_exists}del-port {br} {port}" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] return _retcode_to_bool(retcode) @@ -384,7 +384,7 @@ def port_list(br): salt '*' openvswitch.port_list br0 """ - cmd = "ovs-vsctl list-ports {}".format(br) + cmd = f"ovs-vsctl list-ports {br}" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] stdout = result["stdout"] @@ -409,7 +409,7 @@ def port_get_tag(port): salt '*' openvswitch.port_get_tag tap0 """ - cmd = "ovs-vsctl get port {} tag".format(port) + cmd = f"ovs-vsctl get port {port} tag" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] stdout = result["stdout"] @@ -434,7 +434,7 @@ def interface_get_options(port): salt '*' openvswitch.interface_get_options tap0 """ - cmd = "ovs-vsctl get interface {} options".format(port) + cmd = f"ovs-vsctl get interface {port} options" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] stdout = result["stdout"] @@ -459,7 +459,7 @@ def interface_get_type(port): salt '*' openvswitch.interface_get_type tap0 """ - cmd = "ovs-vsctl get interface {} type".format(port) + cmd = f"ovs-vsctl get interface {port} type" result = __salt__["cmd.run_all"](cmd) retcode = result["retcode"] stdout = result["stdout"] @@ -495,15 +495,15 @@ def port_create_vlan(br, port, id, internal=False): elif not internal and port not in interfaces: return False elif port in port_list(br): - cmd = "ovs-vsctl set port {} tag={}".format(port, id) + cmd = f"ovs-vsctl set port {port} tag={id}" if internal: - cmd += " -- set interface {} type=internal".format(port) + cmd += f" -- set interface {port} type=internal" result = __salt__["cmd.run_all"](cmd) return _retcode_to_bool(result["retcode"]) else: - cmd = "ovs-vsctl add-port {} {} tag={}".format(br, port, id) + cmd = f"ovs-vsctl add-port {br} {port} tag={id}" if internal: - cmd += " -- set interface {} type=internal".format(port) + cmd += f" -- set interface {port} type=internal" result = __salt__["cmd.run_all"](cmd) return _retcode_to_bool(result["retcode"]) @@ -622,7 +622,7 @@ def db_get(table, record, column, if_exists=False): salt '*' openvswitch.db_get Port br0 vlan_mode """ - cmd = ["ovs-vsctl", "--format=json", "--columns={}".format(column)] + cmd = ["ovs-vsctl", "--format=json", f"--columns={column}"] if if_exists: cmd += ["--if-exists"] cmd += ["list", table, record] @@ -666,7 +666,7 @@ def db_set(table, record, column, value, if_exists=False): cmd = ["ovs-vsctl"] if if_exists: cmd += ["--if-exists"] - cmd += ["set", table, record, "{}={}".format(column, json.dumps(value))] + cmd += ["set", table, record, f"{column}={json.dumps(value)}"] result = __salt__["cmd.run_all"](cmd) if result["retcode"] != 0: return result["stderr"] diff --git a/salt/modules/opkg.py b/salt/modules/opkg.py index 72e7bcbb411..725a222b5d4 100644 --- a/salt/modules/opkg.py +++ b/salt/modules/opkg.py @@ -107,7 +107,7 @@ def _update_nilrt_restart_state(): if os.path.exists(nisysapi_conf_d_path): with salt.utils.files.fopen( - "{}/sysapi.conf.d.count".format(NILRT_RESTARTCHECK_STATE_PATH), "w" + f"{NILRT_RESTARTCHECK_STATE_PATH}/sysapi.conf.d.count", "w" ) as fcount: fcount.write(str(len(os.listdir(nisysapi_conf_d_path)))) @@ -135,7 +135,7 @@ def _fingerprint_file(*, filename, fingerprint_dir): ) ) __salt__["cmd.shell"]( - "md5sum {} > {}/{}.md5sum".format(filename, fingerprint_dir, filename.name) + f"md5sum {filename} > {fingerprint_dir}/{filename.name}.md5sum" ) @@ -532,7 +532,7 @@ def install( else: to_install.append(pkgname) else: - pkgstr = "{}={}".format(pkgname, version_num) + pkgstr = f"{pkgname}={version_num}" cver = old.get(pkgname, "") if ( reinstall @@ -839,15 +839,15 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613 state = _get_state(target) if not state: - ret[target]["comment"] = "Package {} not currently held.".format(target) + ret[target]["comment"] = f"Package {target} not currently held." elif state != "hold": if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret[target]["comment"] = "Package {} is set to be held.".format(target) + ret[target]["comment"] = f"Package {target} is set to be held." else: result = _set_state(target, "hold") ret[target].update(changes=result[target], result=True) - ret[target]["comment"] = "Package {} is now being held.".format(target) + ret[target]["comment"] = f"Package {target} is now being held." else: ret[target].update(result=True) ret[target]["comment"] = "Package {} is already set to be held.".format( @@ -902,11 +902,11 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 state = _get_state(target) if not state: - ret[target]["comment"] = "Package {} does not have a state.".format(target) + ret[target]["comment"] = f"Package {target} does not have a state." elif state == "hold": if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret["comment"] = "Package {} is set not to be held.".format(target) + ret["comment"] = f"Package {target} is set not to be held." else: result = _set_state(target, "ok") ret[target].update(changes=result[target], result=True) @@ -960,7 +960,7 @@ def _set_state(pkg, state): ret = {} valid_states = ("hold", "noprune", "user", "ok", "installed", "unpacked") if state not in valid_states: - raise SaltInvocationError("Invalid state: {}".format(state)) + raise SaltInvocationError(f"Invalid state: {state}") oldstate = _get_state(pkg) cmd = ["opkg", "flag"] cmd.append(state) @@ -1469,7 +1469,7 @@ def del_repo(repo, **kwargs): # pylint: disable=unused-argument refresh_db() return ret - return "Repo {} doesn't exist in the opkg repo lists".format(repo) + return f"Repo {repo} doesn't exist in the opkg repo lists" def mod_repo(repo, **kwargs): @@ -1517,9 +1517,9 @@ def mod_repo(repo, **kwargs): repostr += "src/gz" if source["compressed"] else "src" repo_alias = kwargs["alias"] if "alias" in kwargs else repo if " " in repo_alias: - repostr += ' "{}"'.format(repo_alias) + repostr += f' "{repo_alias}"' else: - repostr += " {}".format(repo_alias) + repostr += f" {repo_alias}" repostr += " {}".format(kwargs["uri"] if "uri" in kwargs else source["uri"]) trusted = kwargs.get("trusted") repostr = ( diff --git a/salt/modules/osquery.py b/salt/modules/osquery.py index c28d1685dc5..0bb7b6c994f 100644 --- a/salt/modules/osquery.py +++ b/salt/modules/osquery.py @@ -36,7 +36,7 @@ def _table_attrs(table): """ Helper function to find valid table attributes """ - cmd = ["osqueryi"] + ["--json"] + ["pragma table_info({})".format(table)] + cmd = ["osqueryi"] + ["--json"] + [f"pragma table_info({table})"] res = __salt__["cmd.run_all"](cmd) if res["retcode"] == 0: attrs = [] @@ -82,13 +82,13 @@ def _osquery_cmd(table, attrs=None, where=None, format="json"): if a not in valid_attrs: ret["result"] = False ret["comment"] = ( - "{} is not a valid attribute for table {}".format(a, table) + f"{a} is not a valid attribute for table {table}" ) return ret _attrs = ",".join(attrs) else: ret["result"] = False - ret["comment"] = "Invalid table {}.".format(table) + ret["comment"] = f"Invalid table {table}." return ret else: ret["comment"] = "attrs must be specified as a list." @@ -97,12 +97,12 @@ def _osquery_cmd(table, attrs=None, where=None, format="json"): else: _attrs = "*" - sql = "select {} from {}".format(_attrs, table) + sql = f"select {_attrs} from {table}" if where: - sql = "{} where {}".format(sql, where) + sql = f"{sql} where {where}" - sql = "{};".format(sql) + sql = f"{sql};" res = _osquery(sql) if res["result"]: diff --git a/salt/modules/pacmanpkg.py b/salt/modules/pacmanpkg.py index 25ed1177d9d..57df5f72cb8 100644 --- a/salt/modules/pacmanpkg.py +++ b/salt/modules/pacmanpkg.py @@ -567,11 +567,9 @@ def install( if prefix == "=": wildcards.append((param, verstr)) else: - errors.append( - "Invalid wildcard for {}{}{}".format(param, prefix, verstr) - ) + errors.append(f"Invalid wildcard for {param}{prefix}{verstr}") continue - targets.append("{}{}{}".format(param, prefix, verstr)) + targets.append(f"{param}{prefix}{verstr}") if wildcards: # Resolve wildcard matches diff --git a/salt/modules/pagerduty_util.py b/salt/modules/pagerduty_util.py index 10114b3e4bb..7485fa30e2f 100644 --- a/salt/modules/pagerduty_util.py +++ b/salt/modules/pagerduty_util.py @@ -347,7 +347,7 @@ def create_or_update_resource( resource_id = _get_resource_id(resource) return _query( method="PUT", - action="{}/{}".format(resource_name, resource_id), + action=f"{resource_name}/{resource_id}", data=data_to_update, profile=profile, subdomain=subdomain, @@ -385,7 +385,7 @@ def delete_resource( resource_id = _get_resource_id(resource) return _query( method="DELETE", - action="{}/{}".format(resource_name, resource_id), + action=f"{resource_name}/{resource_id}", profile=profile, subdomain=subdomain, api_key=api_key, @@ -401,7 +401,7 @@ def resource_present( profile="pagerduty", subdomain=None, api_key=None, - **kwargs + **kwargs, ): """ Generic resource.present state method. Pagerduty state modules should be a thin wrapper over this method, @@ -444,7 +444,7 @@ def resource_absent( profile="pagerduty", subdomain=None, api_key=None, - **kwargs + **kwargs, ): """ Generic resource.absent state method. Pagerduty state modules should be a thin wrapper over this method, @@ -469,7 +469,7 @@ def resource_absent( ) if result is None: ret["result"] = True - ret["comment"] = "{} deleted".format(v) + ret["comment"] = f"{v} deleted" return ret elif result is True: continue diff --git a/salt/modules/pam.py b/salt/modules/pam.py index 58254917e35..50b09262856 100644 --- a/salt/modules/pam.py +++ b/salt/modules/pam.py @@ -54,7 +54,7 @@ def _parse(contents=None, file_name=None): position += 1 break else: - control_flag += " {}".format(part) + control_flag += f" {part}" else: control_flag = comps[1] position += 1 diff --git a/salt/modules/panos.py b/salt/modules/panos.py index f5e22d268be..73dd05bd92f 100644 --- a/salt/modules/panos.py +++ b/salt/modules/panos.py @@ -228,7 +228,7 @@ def delete_license(key_name=None): else: query = { "type": "op", - "cmd": "{}".format(key_name), + "cmd": f"{key_name}", } return __proxy__["panos.call"](query) @@ -774,7 +774,7 @@ def get_interface_counters(name="all"): """ query = { "type": "op", - "cmd": "{}".format(name), + "cmd": f"{name}", } return __proxy__["panos.call"](query) @@ -797,7 +797,7 @@ def get_interfaces(name="all"): """ query = { "type": "op", - "cmd": "{}".format(name), + "cmd": f"{name}", } return __proxy__["panos.call"](query) @@ -820,7 +820,7 @@ def get_job(jid=None): if not jid: raise CommandExecutionError("ID option must not be none.") - query = {"type": "op", "cmd": "{}".format(jid)} + query = {"type": "op", "cmd": f"{jid}"} return __proxy__["panos.call"](query) @@ -1169,7 +1169,7 @@ def get_predefined_application(application=None): query = { "type": "config", "action": "get", - "xpath": "/config/predefined/application/entry[@name='{}']".format(application), + "xpath": f"/config/predefined/application/entry[@name='{application}']", } return __proxy__["panos.call"](query) @@ -1799,7 +1799,7 @@ def save_device_config(filename=None): query = { "type": "op", - "cmd": "{}".format(filename), + "cmd": f"{filename}", } return __proxy__["panos.call"](query) @@ -1893,7 +1893,7 @@ def set_hostname(hostname=None, deploy=False): "xpath": ( "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system" ), - "element": "{}".format(hostname), + "element": f"{hostname}", } ret.update(__proxy__["panos.call"](query)) @@ -1937,7 +1937,7 @@ def set_management_icmp(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -1981,7 +1981,7 @@ def set_management_http(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2025,7 +2025,7 @@ def set_management_https(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2069,7 +2069,7 @@ def set_management_ocsp(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2113,7 +2113,7 @@ def set_management_snmp(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2157,7 +2157,7 @@ def set_management_ssh(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2201,7 +2201,7 @@ def set_management_telnet(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2446,7 +2446,7 @@ def set_permitted_ip(address=None, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/permitted-ip", - "element": "".format(address), + "element": f"", } ret.update(__proxy__["panos.call"](query)) @@ -2484,7 +2484,7 @@ def set_timezone(tz=None, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/timezone", - "element": "{}".format(tz), + "element": f"{tz}", } ret.update(__proxy__["panos.call"](query)) @@ -2534,10 +2534,10 @@ def test_fib_route(ip=None, vr="vr1"): xpath = "" if ip: - xpath += "{}".format(ip) + xpath += f"{ip}" if vr: - xpath += "{}".format(vr) + xpath += f"{vr}" xpath += "" @@ -2593,35 +2593,35 @@ def test_security_policy( xpath = "" if sourcezone: - xpath += "{}".format(sourcezone) + xpath += f"{sourcezone}" if destinationzone: - xpath += "{}".format(destinationzone) + xpath += f"{destinationzone}" if source: - xpath += "{}".format(source) + xpath += f"{source}" if destination: - xpath += "{}".format(destination) + xpath += f"{destination}" if protocol: - xpath += "{}".format(protocol) + xpath += f"{protocol}" if port: - xpath += "{}".format(port) + xpath += f"{port}" if application: - xpath += "{}".format(application) + xpath += f"{application}" if category: - xpath += "{}".format(category) + xpath += f"{category}" if allrules: xpath += "yes" xpath += "" - query = {"type": "op", "vsys": "vsys{}".format(vsys), "cmd": xpath} + query = {"type": "op", "vsys": f"vsys{vsys}", "cmd": xpath} return __proxy__["panos.call"](query) diff --git a/salt/modules/parallels.py b/salt/modules/parallels.py index 27f187bacae..2f8ddf80556 100644 --- a/salt/modules/parallels.py +++ b/salt/modules/parallels.py @@ -277,7 +277,7 @@ def exists(name, runas=None): """ vm_info = list_vms(name, info=True, runas=runas).splitlines() for info_line in vm_info: - if "Name: {}".format(name) in info_line: + if f"Name: {name}" in info_line: return True return False @@ -453,7 +453,7 @@ def snapshot_id_to_name(name, snap_id, strict=False, runas=None): name = salt.utils.data.decode(name) if not re.match(GUID_REGEX, snap_id): raise SaltInvocationError( - 'Snapshot ID "{}" is not a GUID'.format(salt.utils.data.decode(snap_id)) + f'Snapshot ID "{salt.utils.data.decode(snap_id)}" is not a GUID' ) # Get the snapshot information of the snapshot having the requested ID @@ -461,9 +461,7 @@ def snapshot_id_to_name(name, snap_id, strict=False, runas=None): # Parallels desktop returned no information for snap_id if not info: - raise SaltInvocationError( - 'No snapshots for VM "{}" have ID "{}"'.format(name, snap_id) - ) + raise SaltInvocationError(f'No snapshots for VM "{name}" have ID "{snap_id}"') # Try to interpret the information try: @@ -540,7 +538,7 @@ def snapshot_name_to_id(name, snap_name, strict=False, runas=None): # non-singular names if not named_ids: raise SaltInvocationError( - 'No snapshots for VM "{}" have name "{}"'.format(name, snap_name) + f'No snapshots for VM "{name}" have name "{snap_name}"' ) elif len(named_ids) == 1: return named_ids[0] @@ -634,7 +632,7 @@ def list_snapshots(name, snap_name=None, tree=False, names=False, runas=None): ret = "{:<38} {}\n".format("Snapshot ID", "Snapshot Name") for snap_id in snap_ids: snap_name = snapshot_id_to_name(name, snap_id, runas=runas) - ret += "{{{0}}} {1}\n".format(snap_id, salt.utils.data.decode(snap_name)) + ret += f"{{{snap_id}}} {salt.utils.data.decode(snap_name)}\n" return ret # Return information directly from parallels desktop diff --git a/salt/modules/parted_partition.py b/salt/modules/parted_partition.py index 02c5ab5a49d..1c9a135b7b8 100644 --- a/salt/modules/parted_partition.py +++ b/salt/modules/parted_partition.py @@ -140,9 +140,7 @@ def _validate_partition_boundary(boundary): unit = match.group(2) if not unit or unit in VALID_UNITS: return - raise CommandExecutionError( - 'Invalid partition boundary passed: "{}"'.format(boundary) - ) + raise CommandExecutionError(f'Invalid partition boundary passed: "{boundary}"') def probe(*devices): @@ -186,9 +184,9 @@ def list_(device, unit=None): if unit: if unit not in VALID_UNITS: raise CommandExecutionError("Invalid unit passed to partition.part_list") - cmd = "parted -m -s {} unit {} print".format(device, unit) + cmd = f"parted -m -s {device} unit {unit} print" else: - cmd = "parted -m -s {} print".format(device) + cmd = f"parted -m -s {device} print" out = __salt__["cmd.run_stdout"](cmd).splitlines() ret = {"info": {}, "partitions": {}} @@ -268,7 +266,7 @@ def align_check(device, part_type, partition): except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid partition passed to partition.align_check") - cmd = "parted -m {} align-check {} {}".format(device, part_type, partition) + cmd = f"parted -m {device} align-check {part_type} {partition}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -290,7 +288,7 @@ def check(device, minor): except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.check") - cmd = "parted -m -s {} check {}".format(device, minor) + cmd = f"parted -m -s {device} check {minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -315,7 +313,7 @@ def cp(device, from_minor, to_minor): # pylint: disable=C0103 except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.cp") - cmd = "parted -m -s {} cp {} {}".format(device, from_minor, to_minor) + cmd = f"parted -m -s {device} cp {from_minor} {to_minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -344,7 +342,7 @@ def get_id(device, minor): except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.get_id") - cmd = "sfdisk --print-id {} {}".format(device, minor) + cmd = f"sfdisk --print-id {device} {minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -376,7 +374,7 @@ def set_id(device, minor, system_id): if system_id not in system_types(): raise CommandExecutionError("Invalid system_id passed to partition.set_id") - cmd = "sfdisk --change-id {} {} {}".format(device, minor, system_id) + cmd = f"sfdisk --change-id {device} {minor} {system_id}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -451,11 +449,11 @@ def mkfs(device, fs_type): if fs_type == "linux-swap": mkfs_cmd = "mkswap" else: - mkfs_cmd = "mkfs.{}".format(fs_type) + mkfs_cmd = f"mkfs.{fs_type}" if not salt.utils.path.which(mkfs_cmd): - return "Error: {} is unavailable.".format(mkfs_cmd) - cmd = "{} {}".format(mkfs_cmd, device) + return f"Error: {mkfs_cmd} is unavailable." + cmd = f"{mkfs_cmd} {device}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -582,7 +580,7 @@ def name(device, partition, name): if letter not in valid: raise CommandExecutionError("Invalid characters passed to partition.name") - cmd = '''parted -m -s {} name {} "'{}'"'''.format(device, partition, name) + cmd = f'''parted -m -s {device} name {partition} "'{name}'"''' out = __salt__["cmd.run"](cmd).splitlines() return out @@ -603,7 +601,7 @@ def rescue(device, start, end): _validate_partition_boundary(start) _validate_partition_boundary(end) - cmd = "parted -m -s {} rescue {} {}".format(device, start, end) + cmd = f"parted -m -s {device} rescue {start} {end}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -633,9 +631,7 @@ def resize(device, minor, start, end): _validate_partition_boundary(start) _validate_partition_boundary(end) - out = __salt__["cmd.run"]( - "parted -m -s -- {} resize {} {} {}".format(device, minor, start, end) - ) + out = __salt__["cmd.run"](f"parted -m -s -- {device} resize {minor} {start} {end}") return out.splitlines() @@ -656,7 +652,7 @@ def rm(device, minor): # pylint: disable=C0103 except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.rm") - cmd = "parted -m -s {} rm {}".format(device, minor) + cmd = f"parted -m -s {device} rm {minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -709,7 +705,7 @@ def set_(device, minor, flag, state): if state not in {"on", "off"}: raise CommandExecutionError("Invalid state passed to partition.set") - cmd = "parted -m -s {} set {} {} {}".format(device, minor, flag, state) + cmd = f"parted -m -s {device} set {minor} {flag} {state}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -737,7 +733,7 @@ def toggle(device, partition, flag): if flag not in VALID_PARTITION_FLAGS: raise CommandExecutionError("Invalid flag passed to partition.toggle") - cmd = "parted -m -s {} toggle {} {}".format(device, partition, flag) + cmd = f"parted -m -s {device} toggle {partition} {flag}" out = __salt__["cmd.run"](cmd).splitlines() return out diff --git a/salt/modules/pcs.py b/salt/modules/pcs.py index 8225206f51c..78415307dda 100644 --- a/salt/modules/pcs.py +++ b/salt/modules/pcs.py @@ -159,7 +159,7 @@ def item_create( if isinstance(extra_args, (list, tuple)): # constraint command needs item_id in format 'id= 0: diff --git a/salt/modules/pecl.py b/salt/modules/pecl.py index 2a649923f62..d5ff3543bfa 100644 --- a/salt/modules/pecl.py +++ b/salt/modules/pecl.py @@ -30,7 +30,7 @@ def _pecl(command, defaults=False): """ Execute the command passed with pecl """ - cmdline = "pecl {}".format(command) + cmdline = f"pecl {command}" if salt.utils.data.is_true(defaults): cmdline = "yes ''" + " | " + cmdline @@ -68,7 +68,7 @@ def install(pecls, defaults=False, force=False, preferred_state="stable"): """ if isinstance(pecls, str): pecls = [pecls] - preferred_state = "-d preferred_state={}".format(shlex.quote(preferred_state)) + preferred_state = f"-d preferred_state={shlex.quote(preferred_state)}" if force: return _pecl( "{} install -f {}".format(preferred_state, shlex.quote(" ".join(pecls))), @@ -149,7 +149,7 @@ def list_(channel=None): pecls = {} command = "list" if channel: - command = "{} -c {}".format(command, shlex.quote(channel)) + command = f"{command} -c {shlex.quote(channel)}" lines = _pecl(command).splitlines() lines = (l for l in lines if pecl_channel_pat.match(l)) diff --git a/salt/modules/peeringdb.py b/salt/modules/peeringdb.py index 6a77a35fa03..cef8771aef8 100644 --- a/salt/modules/peeringdb.py +++ b/salt/modules/peeringdb.py @@ -55,8 +55,8 @@ def _get_auth(username=None, password=None): def _build_url(endpoint, id=None): if id: - return "{base}/{endp}/{id}".format(base=PEERINGDB_URL, endp=endpoint, id=id) - return "{base}/{endp}".format(base=PEERINGDB_URL, endp=endpoint) + return f"{PEERINGDB_URL}/{endpoint}/{id}" + return f"{PEERINGDB_URL}/{endpoint}" def _get_endpoint(endpoint, id=None, **kwargs): diff --git a/salt/modules/pf.py b/salt/modules/pf.py index 3a52257c8cf..f66849ed3f5 100644 --- a/salt/modules/pf.py +++ b/salt/modules/pf.py @@ -126,10 +126,10 @@ def loglevel(level): "debug", ] if level not in all_levels: - raise SaltInvocationError("Unknown loglevel: {}".format(level)) + raise SaltInvocationError(f"Unknown loglevel: {level}") result = __salt__["cmd.run_all"]( - "pfctl -x {}".format(level), output_loglevel="trace", python_shell=False + f"pfctl -x {level}", output_loglevel="trace", python_shell=False ) if result["retcode"] != 0: @@ -170,7 +170,7 @@ def load(file="/etc/pf.conf", noop=False): if result["retcode"] != 0: raise CommandExecutionError( - "Problem loading the ruleset from {}".format(file), + f"Problem loading the ruleset from {file}", info={"errors": [result["stderr"]], "changes": False}, ) @@ -213,9 +213,9 @@ def flush(modifier): modifier = modifier.title() if modifier not in all_modifiers: - raise SaltInvocationError("Unknown modifier: {}".format(modifier)) + raise SaltInvocationError(f"Unknown modifier: {modifier}") - cmd = "pfctl -v -F {}".format(modifier) + cmd = f"pfctl -v -F {modifier}" result = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False) if result["retcode"] == 0: @@ -227,7 +227,7 @@ def flush(modifier): ret["comment"] = result["stderr"] else: raise CommandExecutionError( - "Could not flush {}".format(modifier), + f"Could not flush {modifier}", info={"errors": [result["stderr"]], "changes": False}, ) @@ -278,7 +278,7 @@ def table(command, table, **kwargs): "zero", ] if command not in all_commands: - raise SaltInvocationError("Unknown table command: {}".format(command)) + raise SaltInvocationError(f"Unknown table command: {command}") cmd = ["pfctl", "-t", table, "-T", command] @@ -315,7 +315,7 @@ def table(command, table, **kwargs): ret = {"comment": result["stderr"], "matches": False} else: raise CommandExecutionError( - "Could not apply {} on table {}".format(command, table), + f"Could not apply {command} on table {table}", info={"errors": [result["stderr"]], "changes": False}, ) @@ -350,16 +350,16 @@ def show(modifier): modifier = modifier.title() if modifier not in all_modifiers: - raise SaltInvocationError("Unknown modifier: {}".format(modifier)) + raise SaltInvocationError(f"Unknown modifier: {modifier}") - cmd = "pfctl -s {}".format(modifier) + cmd = f"pfctl -s {modifier}" result = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False) if result["retcode"] == 0: ret["comment"] = result["stdout"].split("\n") else: raise CommandExecutionError( - "Could not show {}".format(modifier), + f"Could not show {modifier}", info={"errors": [result["stderr"]], "changes": False}, ) diff --git a/salt/modules/pillar.py b/salt/modules/pillar.py index ba195ab3e39..5c6ff18f2cf 100644 --- a/salt/modules/pillar.py +++ b/salt/modules/pillar.py @@ -184,7 +184,7 @@ def get( ret = salt.utils.data.traverse_dict_and_list(pillar_dict, key, default, delimiter) if ret is KeyError: - raise KeyError("Pillar key not found: {}".format(key)) + raise KeyError(f"Pillar key not found: {key}") return ret @@ -264,9 +264,7 @@ def items(*args, **kwargs): valid_rend=__opts__["decrypt_pillar_renderers"], ) except Exception as exc: # pylint: disable=broad-except - raise CommandExecutionError( - "Failed to decrypt pillar override: {}".format(exc) - ) + raise CommandExecutionError(f"Failed to decrypt pillar override: {exc}") pillar = salt.pillar.get_pillar( __opts__, @@ -295,7 +293,7 @@ def _obfuscate_inner(var): elif isinstance(var, (list, set, tuple)): return type(var)(_obfuscate_inner(v) for v in var) else: - return "<{}>".format(var.__class__.__name__) + return f"<{var.__class__.__name__}>" def obfuscate(*args, **kwargs): @@ -538,10 +536,10 @@ def keys(key, delimiter=DEFAULT_TARGET_DELIM): ret = salt.utils.data.traverse_dict_and_list(__pillar__, key, KeyError, delimiter) if ret is KeyError: - raise KeyError("Pillar key not found: {}".format(key)) + raise KeyError(f"Pillar key not found: {key}") if not isinstance(ret, dict): - raise ValueError("Pillar value in key {} is not a dict".format(key)) + raise ValueError(f"Pillar value in key {key} is not a dict") return list(ret) diff --git a/salt/modules/pip.py b/salt/modules/pip.py index aa58d230bec..bd56fd7a638 100644 --- a/salt/modules/pip.py +++ b/salt/modules/pip.py @@ -136,7 +136,7 @@ def _clear_context(bin_env=None): """ contextkey = "pip.version" if bin_env is not None: - contextkey = "{}.{}".format(contextkey, bin_env) + contextkey = f"{contextkey}.{bin_env}" __context__.pop(contextkey, None) @@ -189,7 +189,7 @@ def _get_pip_bin(bin_env): bin_path, ) raise CommandNotFoundError( - "Could not find a pip binary in virtualenv {}".format(bin_env) + f"Could not find a pip binary in virtualenv {bin_env}" ) # bin_env is the python or pip binary @@ -201,12 +201,10 @@ def _get_pip_bin(bin_env): # We have been passed a pip binary, use the pip binary. return [os.path.normpath(bin_env)] - raise CommandExecutionError( - "Could not find a pip binary within {}".format(bin_env) - ) + raise CommandExecutionError(f"Could not find a pip binary within {bin_env}") else: raise CommandNotFoundError( - "Access denied to {}, could not find a pip binary".format(bin_env) + f"Access denied to {bin_env}, could not find a pip binary" ) @@ -412,9 +410,7 @@ def _format_env_vars(env_vars): val = str(val) ret[key] = val else: - raise CommandExecutionError( - "env_vars {} is not a dictionary".format(env_vars) - ) + raise CommandExecutionError(f"env_vars {env_vars} is not a dictionary") return ret @@ -759,7 +755,7 @@ def install( if log: if os.path.isdir(log): - raise OSError("'{}' is a directory. Use --log path_to_file".format(log)) + raise OSError(f"'{log}' is a directory. Use --log path_to_file") if not os.path.exists(log): parent = os.path.dirname(log) if not os.path.exists(parent): @@ -771,7 +767,7 @@ def install( f"Trying to create '{log}' but parent directory '{parent}' is not writeable." ) elif not os.access(log, os.W_OK): - raise OSError("'{}' is not writeable".format(log)) + raise OSError(f"'{log}' is not writeable") cmd.extend(["--log", log]) @@ -796,9 +792,7 @@ def install( raise ValueError("Timeout cannot be a float") int(timeout) except ValueError: - raise ValueError( - "'{}' is not a valid timeout, must be an integer".format(timeout) - ) + raise ValueError(f"'{timeout}' is not a valid timeout, must be an integer") cmd.extend(["--timeout", timeout]) if find_links: @@ -809,9 +803,7 @@ def install( if not ( salt.utils.url.validate(link, VALID_PROTOS) or os.path.exists(link) ): - raise CommandExecutionError( - "'{}' is not a valid URL or path".format(link) - ) + raise CommandExecutionError(f"'{link}' is not a valid URL or path") cmd.extend(["--find-links", link]) if no_index and (index_url or extra_index_url): @@ -821,14 +813,12 @@ def install( if index_url: if not salt.utils.url.validate(index_url, VALID_PROTOS): - raise CommandExecutionError("'{}' is not a valid URL".format(index_url)) + raise CommandExecutionError(f"'{index_url}' is not a valid URL") cmd.extend(["--index-url", index_url]) if extra_index_url: if not salt.utils.url.validate(extra_index_url, VALID_PROTOS): - raise CommandExecutionError( - "'{}' is not a valid URL".format(extra_index_url) - ) + raise CommandExecutionError(f"'{extra_index_url}' is not a valid URL") cmd.extend(["--extra-index-url", extra_index_url]) if no_index: @@ -848,7 +838,7 @@ def install( cmd.append("--use-mirrors") for mirror in mirrors: if not mirror.startswith("http://"): - raise CommandExecutionError("'{}' is not a valid URL".format(mirror)) + raise CommandExecutionError(f"'{mirror}' is not a valid URL") cmd.extend(["--mirrors", mirror]) if disable_version_check: @@ -1010,7 +1000,7 @@ def install( # Don't allow any recursion into keyword arg definitions # Don't allow multiple definitions of a keyword if isinstance(val, (dict, list)): - raise TypeError("Too many levels in: {}".format(key)) + raise TypeError(f"Too many levels in: {key}") # This is a a normal one-to-one keyword argument cmd.extend([key, val]) # It is a positional argument, append it to the list @@ -1123,7 +1113,7 @@ def uninstall( # TODO make this check if writeable os.path.exists(log) except OSError: - raise OSError("'{}' is not writeable".format(log)) + raise OSError(f"'{log}' is not writeable") cmd.extend(["--log", log]) @@ -1148,9 +1138,7 @@ def uninstall( raise ValueError("Timeout cannot be a float") int(timeout) except ValueError: - raise ValueError( - "'{}' is not a valid timeout, must be an integer".format(timeout) - ) + raise ValueError(f"'{timeout}' is not a valid timeout, must be an integer") cmd.extend(["--timeout", timeout]) if pkgs: @@ -1410,7 +1398,7 @@ def version(bin_env=None, cwd=None, user=None): cwd = _pip_bin_env(cwd, bin_env) contextkey = "pip.version" if bin_env is not None: - contextkey = "{}.{}".format(contextkey, bin_env) + contextkey = f"{contextkey}.{bin_env}" if contextkey in __context__: return __context__[contextkey] @@ -1673,18 +1661,16 @@ def list_all_versions( if salt.utils.versions.compare(ver1=pip_version, oper=">=", ver2="20.3"): cmd.append("--use-deprecated=legacy-resolver") regex = re.compile(r"\s*Could not find a version.* \(from versions: (.*)\)") - cmd.extend(["install", "{}==versions".format(pkg)]) + cmd.extend(["install", f"{pkg}==versions"]) if index_url: if not salt.utils.url.validate(index_url, VALID_PROTOS): - raise CommandExecutionError("'{}' is not a valid URL".format(index_url)) + raise CommandExecutionError(f"'{index_url}' is not a valid URL") cmd.extend(["--index-url", index_url]) if extra_index_url: if not salt.utils.url.validate(extra_index_url, VALID_PROTOS): - raise CommandExecutionError( - "'{}' is not a valid URL".format(extra_index_url) - ) + raise CommandExecutionError(f"'{extra_index_url}' is not a valid URL") cmd.extend(["--extra-index-url", extra_index_url]) cmd_kwargs = dict( cwd=cwd, runas=user, output_loglevel="quiet", redirect_stderr=True diff --git a/salt/modules/pkg_resource.py b/salt/modules/pkg_resource.py index 6308641a2f9..88e38b91a41 100644 --- a/salt/modules/pkg_resource.py +++ b/salt/modules/pkg_resource.py @@ -413,7 +413,7 @@ def format_version(epoch, version, release): """ Formats a version string for list_pkgs. """ - full_version = "{}:{}".format(epoch, version) if epoch else version + full_version = f"{epoch}:{version}" if epoch else version if release: - full_version += "-{}".format(release) + full_version += f"-{release}" return full_version diff --git a/salt/modules/pkgin.py b/salt/modules/pkgin.py index 8380360047c..3756f556198 100644 --- a/salt/modules/pkgin.py +++ b/salt/modules/pkgin.py @@ -40,7 +40,7 @@ def _check_pkgin(): "pkg_info -Q LOCALBASE pkgin", output_loglevel="trace" ) if localbase is not None: - ppath = "{}/bin/pkgin".format(localbase) + ppath = f"{localbase}/bin/pkgin" if not os.path.exists(ppath): return None except CommandExecutionError: @@ -124,7 +124,7 @@ def search(pkg_name, **kwargs): return pkglist if _supports_regex(): - pkg_name = "^{}$".format(pkg_name) + pkg_name = f"^{pkg_name}$" out = __salt__["cmd.run"]([pkgin, "se", pkg_name], output_loglevel="trace") for line in out.splitlines(): @@ -170,7 +170,7 @@ def latest_version(*names, **kwargs): cmd_prefix.insert(1, "-p") for name in names: cmd = copy.deepcopy(cmd_prefix) - cmd.append("^{}$".format(name) if _supports_regex() else name) + cmd.append(f"^{name}$" if _supports_regex() else name) out = __salt__["cmd.run"](cmd, output_loglevel="trace") for line in out.splitlines(): @@ -564,9 +564,9 @@ def remove(name=None, pkgs=None, **kwargs): if not ver: continue if isinstance(ver, list): - args.extend(["{}-{}".format(param, v) for v in ver]) + args.extend([f"{param}-{v}" for v in ver]) else: - args.append("{}-{}".format(param, ver)) + args.append(f"{param}-{ver}") if not args: return {} diff --git a/salt/modules/pkgng.py b/salt/modules/pkgng.py index e5f94b7c297..4aaa28eb5a7 100644 --- a/salt/modules/pkgng.py +++ b/salt/modules/pkgng.py @@ -132,11 +132,11 @@ def _contextkey(jail=None, chroot=None, root=None, prefix="pkg.list_pkgs"): unique to that jail/chroot is used. """ if jail: - return str(prefix) + ".jail_{}".format(jail) + return str(prefix) + f".jail_{jail}" elif chroot: - return str(prefix) + ".chroot_{}".format(chroot) + return str(prefix) + f".chroot_{chroot}" elif root: - return str(prefix) + ".root_{}".format(root) + return str(prefix) + f".root_{root}" return prefix @@ -154,7 +154,7 @@ def parse_config(file_name="/usr/local/etc/pkg.conf"): """ ret = {} if not os.path.isfile(file_name): - return "Unable to find {} on file system".format(file_name) + return f"Unable to find {file_name} on file system" with salt.utils.files.fopen(file_name) as ifile: for line in ifile: @@ -356,7 +356,7 @@ def list_pkgs( chroot=None, root=None, with_origin=False, - **kwargs + **kwargs, ): """ List the packages currently installed as a dict:: @@ -444,9 +444,7 @@ def update_package_site(new_url): salt '*' pkg.update_package_site http://127.0.0.1/ """ config_file = parse_config()["config_file"] - __salt__["file.sed"]( - config_file, "PACKAGESITE.*", "PACKAGESITE\t : {}".format(new_url) - ) + __salt__["file.sed"](config_file, "PACKAGESITE.*", f"PACKAGESITE\t : {new_url}") # add change return later return True @@ -684,7 +682,7 @@ def install( regex=False, pcre=False, batch=False, - **kwargs + **kwargs, ): """ Install package(s) from a repository @@ -870,7 +868,7 @@ def install( if version_num is None: targets.append(param) else: - targets.append("{}-{}".format(param, version_num)) + targets.append(f"{param}-{version_num}") else: raise CommandExecutionError("Problem encountered installing package(s)") @@ -922,7 +920,7 @@ def remove( recurse=False, regex=False, pcre=False, - **kwargs + **kwargs, ): """ Remove a package from the database and system @@ -1887,9 +1885,9 @@ def updating(name, jail=None, chroot=None, root=None, filedate=None, filename=No opts = "" if filedate: - opts += "d {}".format(filedate) + opts += f"d {filedate}" if filename: - opts += "f {}".format(filename) + opts += f"f {filename}" cmd = _pkg(jail, chroot, root) cmd.append("updating") @@ -1942,7 +1940,7 @@ def hold(name=None, pkgs=None, **kwargs): # pylint: disable=W0613 if not locked(target, **kwargs): if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret[target]["comment"] = "Package {} is set to be held.".format(target) + ret[target]["comment"] = f"Package {target} is set to be held." else: if lock(target, **kwargs): ret[target].update(result=True) @@ -2018,12 +2016,12 @@ def unhold(name=None, pkgs=None, **kwargs): # pylint: disable=W0613 ret[target]["changes"]["new"] = "" ret[target]["changes"]["old"] = "hold" else: - ret[target]["comment"] = ( - "Package {} was unable to be unheld.".format(target) - ) + ret[target][ + "comment" + ] = f"Package {target} was unable to be unheld." else: ret[target].update(result=True) - ret[target]["comment"] = "Package {} is not being held.".format(target) + ret[target]["comment"] = f"Package {target} is not being held." return ret @@ -2071,7 +2069,7 @@ def list_locked(**kwargs): """ return [ - "{}-{}".format(pkgname, version(pkgname, **kwargs)) + f"{pkgname}-{version(pkgname, **kwargs)}" for pkgname in _lockcmd("lock", name=None, **kwargs) ] @@ -2247,7 +2245,7 @@ def _lockcmd(subcmd, pkgname=None, **kwargs): if out["retcode"] != 0: raise CommandExecutionError( - "Problem encountered {}ing packages".format(subcmd), info={"result": out} + f"Problem encountered {subcmd}ing packages", info={"result": out} ) for line in salt.utils.itertools.split(out["stdout"], "\n"): diff --git a/salt/modules/pkgutil.py b/salt/modules/pkgutil.py index d81f44f9437..67995471f3d 100644 --- a/salt/modules/pkgutil.py +++ b/salt/modules/pkgutil.py @@ -59,7 +59,7 @@ def upgrade_available(name): salt '*' pkgutil.upgrade_available CSWpython """ version_num = None - cmd = "/opt/csw/bin/pkgutil -c --parse --single {}".format(name) + cmd = f"/opt/csw/bin/pkgutil -c --parse --single {name}" out = __salt__["cmd.run_stdout"](cmd) if out: version_num = out.split()[2].strip() @@ -298,7 +298,7 @@ def install(name=None, refresh=False, version=None, pkgs=None, **kwargs): if pkgver is None: targets.append(param) else: - targets.append("{}-{}".format(param, pkgver)) + targets.append(f"{param}-{pkgver}") cmd = "/opt/csw/bin/pkgutil -yu {}".format(" ".join(targets)) old = list_pkgs() diff --git a/salt/modules/portage_config.py b/salt/modules/portage_config.py index 15c0ad983da..bd2f18b5c42 100644 --- a/salt/modules/portage_config.py +++ b/salt/modules/portage_config.py @@ -192,7 +192,7 @@ def _unify_keywords(): if os.path.isdir(old_path): for triplet in salt.utils.path.os_walk(old_path): for file_name in triplet[2]: - file_path = "{}/{}".format(triplet[0], file_name) + file_path = f"{triplet[0]}/{file_name}" with salt.utils.files.fopen(file_path) as fh_: for line in fh_: line = salt.utils.stringutils.to_unicode(line).strip() @@ -239,7 +239,7 @@ def _package_conf_ordering(conf, clean=True, keep_backup=False): for triplet in salt.utils.path.os_walk(path): for file_name in triplet[2]: - file_path = "{}/{}".format(triplet[0], file_name) + file_path = f"{triplet[0]}/{file_name}" cp = triplet[0][len(path) + 1 :] + "/" + file_name shutil.copy(file_path, file_path + ".bak") @@ -426,7 +426,7 @@ def append_to_package_conf(conf, atom="", flags=None, string="", overwrite=False atom, " ".join(merged_flags) ) else: - new_contents += "{}\n".format(atom) + new_contents += f"{atom}\n" added = True else: new_contents += l diff --git a/salt/modules/postfix.py b/salt/modules/postfix.py index 64059bfe44b..a3971309d3c 100644 --- a/salt/modules/postfix.py +++ b/salt/modules/postfix.py @@ -70,7 +70,7 @@ def _parse_master(path=MASTER_CF): "maxproc": comps[6], "command": " ".join(comps[7:]), } - dict_key = "{} {}".format(comps[0], comps[1]) + dict_key = f"{comps[0]} {comps[1]}" conf_list.append(conf_line) conf_dict[dict_key] = conf_line @@ -135,7 +135,7 @@ def set_master( conf_dict, conf_list = _parse_master(path) new_conf = [] - dict_key = "{} {}".format(service, conn_type) + dict_key = f"{service} {conn_type}" new_line = _format_master( service, conn_type, @@ -291,15 +291,15 @@ def set_main(key, value, path=MAIN_CF): pairs, conf_list = _parse_main(path) new_conf = [] - key_line_match = re.compile("^{}([\\s=]|$)".format(re.escape(key))) + key_line_match = re.compile(f"^{re.escape(key)}([\\s=]|$)") if key in pairs: for line in conf_list: if re.match(key_line_match, line): - new_conf.append("{} = {}".format(key, value)) + new_conf.append(f"{key} = {value}") else: new_conf.append(line) else: - conf_list.append("{} = {}".format(key, value)) + conf_list.append(f"{key} = {value}") new_conf = conf_list _write_conf(new_conf, path) @@ -394,11 +394,11 @@ def delete(queue_id): _message = item if not _message: - ret["message"] = "No message in queue with ID {}".format(queue_id) + ret["message"] = f"No message in queue with ID {queue_id}" ret["result"] = False return ret - cmd = "postsuper -d {}".format(queue_id) + cmd = f"postsuper -d {queue_id}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] == 0: @@ -445,11 +445,11 @@ def hold(queue_id): _message = item if not _message: - ret["message"] = "No message in queue with ID {}".format(queue_id) + ret["message"] = f"No message in queue with ID {queue_id}" ret["result"] = False return ret - cmd = "postsuper -h {}".format(queue_id) + cmd = f"postsuper -h {queue_id}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] == 0: @@ -457,7 +457,7 @@ def hold(queue_id): ret["message"] = "Successfully placed all messages on hold" else: ret["message"] = ( - "Successfully placed message on hold with queue id {}".format(queue_id) + f"Successfully placed message on hold with queue id {queue_id}" ) else: if queue_id == "ALL": @@ -498,11 +498,11 @@ def unhold(queue_id): _message = item if not _message: - ret["message"] = "No message in queue with ID {}".format(queue_id) + ret["message"] = f"No message in queue with ID {queue_id}" ret["result"] = False return ret - cmd = "postsuper -H {}".format(queue_id) + cmd = f"postsuper -H {queue_id}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] == 0: @@ -510,7 +510,7 @@ def unhold(queue_id): ret["message"] = "Successfully set all message as unheld" else: ret["message"] = ( - "Successfully set message as unheld with queue id {}".format(queue_id) + f"Successfully set message as unheld with queue id {queue_id}" ) else: if queue_id == "ALL": @@ -551,11 +551,11 @@ def requeue(queue_id): _message = item if not _message: - ret["message"] = "No message in queue with ID {}".format(queue_id) + ret["message"] = f"No message in queue with ID {queue_id}" ret["result"] = False return ret - cmd = "postsuper -r {}".format(queue_id) + cmd = f"postsuper -r {queue_id}" result = __salt__["cmd.run_all"](cmd) if result["retcode"] == 0: diff --git a/salt/modules/poudriere.py b/salt/modules/poudriere.py index 5805145d2a1..5b7e88ecab2 100644 --- a/salt/modules/poudriere.py +++ b/salt/modules/poudriere.py @@ -84,19 +84,15 @@ def make_pkgng_aware(jname): if not os.path.isdir(cdir): os.makedirs(cdir) if os.path.isdir(cdir): - ret["changes"] = "Created poudriere make file dir {}".format(cdir) + ret["changes"] = f"Created poudriere make file dir {cdir}" else: - return "Could not create or find required directory {}".format(cdir) + return f"Could not create or find required directory {cdir}" # Added args to file - __salt__["file.write"]( - "{}-make.conf".format(os.path.join(cdir, jname)), "WITH_PKGNG=yes" - ) + __salt__["file.write"](f"{os.path.join(cdir, jname)}-make.conf", "WITH_PKGNG=yes") if os.path.isfile(os.path.join(cdir, jname) + "-make.conf"): - ret["changes"] = "Created {}".format( - os.path.join(cdir, "{}-make.conf".format(jname)) - ) + ret["changes"] = "Created {}".format(os.path.join(cdir, f"{jname}-make.conf")) return ret else: return "Looks like file {} could not be created".format( @@ -124,7 +120,7 @@ def parse_config(config_file=None): ret[key] = val return ret - return "Could not find {} on file system".format(config_file) + return f"Could not find {config_file} on file system" def version(): @@ -190,9 +186,9 @@ def create_jail(name, arch, version="9.0-RELEASE"): # Check if the jail is there if is_jail(name): - return "{} already exists".format(name) + return f"{name} already exists" - cmd = "poudriere jails -c -j {} -v {} -a {}".format(name, version, arch) + cmd = f"poudriere jails -c -j {name} -v {version} -a {arch}" __salt__["cmd.run"](cmd) # Make jail pkgng aware @@ -200,9 +196,9 @@ def create_jail(name, arch, version="9.0-RELEASE"): # Make sure the jail was created if is_jail(name): - return "Created jail {}".format(name) + return f"Created jail {name}" - return "Issue creating jail {}".format(name) + return f"Issue creating jail {name}" def update_jail(name): @@ -216,11 +212,11 @@ def update_jail(name): salt '*' poudriere.update_jail freebsd:10:x86:64 """ if is_jail(name): - cmd = "poudriere jail -u -j {}".format(name) + cmd = f"poudriere jail -u -j {name}" ret = __salt__["cmd.run"](cmd) return ret else: - return "Could not find jail {}".format(name) + return f"Could not find jail {name}" def delete_jail(name): @@ -234,18 +230,18 @@ def delete_jail(name): salt '*' poudriere.delete_jail 90amd64 """ if is_jail(name): - cmd = "poudriere jail -d -j {}".format(name) + cmd = f"poudriere jail -d -j {name}" __salt__["cmd.run"](cmd) # Make sure jail is gone if is_jail(name): - return "Looks like there was an issue deleting jail {}".format(name) + return f"Looks like there was an issue deleting jail {name}" else: # Could not find jail. - return "Looks like jail {} has not been created".format(name) + return f"Looks like jail {name} has not been created" # clean up pkgng make info in config dir - make_file = os.path.join(_config_dir(), "{}-make.conf".format(name)) + make_file = os.path.join(_config_dir(), f"{name}-make.conf") if os.path.isfile(make_file): try: os.remove(make_file) @@ -255,7 +251,7 @@ def delete_jail(name): ) __salt__["file.remove"](make_file) - return "Deleted jail {}".format(name) + return f"Deleted jail {name}" def info_jail(name): @@ -269,11 +265,11 @@ def info_jail(name): salt '*' poudriere.info_jail head-amd64 """ if is_jail(name): - cmd = "poudriere jail -i -j {}".format(name) + cmd = f"poudriere jail -i -j {name}" ret = __salt__["cmd.run"](cmd).splitlines() return ret else: - return "Could not find jail {}".format(name) + return f"Could not find jail {name}" def create_ports_tree(): @@ -298,7 +294,7 @@ def update_ports_tree(ports_tree): """ _check_config_exists() if ports_tree: - cmd = "poudriere ports -u -p {}".format(ports_tree) + cmd = f"poudriere ports -u -p {ports_tree}" else: cmd = "poudriere ports -u" ret = __salt__["cmd.run"](cmd) @@ -320,15 +316,15 @@ def bulk_build(jail, pkg_file, keep=False): """ # make sure `pkg file` and jail is on file system if not os.path.isfile(pkg_file): - return "Could not find file {} on filesystem".format(pkg_file) + return f"Could not find file {pkg_file} on filesystem" if not is_jail(jail): - return "Could not find jail {}".format(jail) + return f"Could not find jail {jail}" # Generate command if keep: - cmd = "poudriere bulk -k -f {} -j {}".format(pkg_file, jail) + cmd = f"poudriere bulk -k -f {pkg_file} -j {jail}" else: - cmd = "poudriere bulk -f {} -j {}".format(pkg_file, jail) + cmd = f"poudriere bulk -f {pkg_file} -j {jail}" # Bulk build this can take some time, depending on pkg_file ... hours res = __salt__["cmd.run"](cmd) diff --git a/salt/modules/powerpath.py b/salt/modules/powerpath.py index 4477d89651e..b03840d760e 100644 --- a/salt/modules/powerpath.py +++ b/salt/modules/powerpath.py @@ -88,7 +88,7 @@ def add_license(key): result["output"] = "PowerPath is not installed" return result - cmd = "/sbin/emcpreg -add {}".format(key) + cmd = f"/sbin/emcpreg -add {key}" ret = __salt__["cmd.run_all"](cmd, python_shell=True) result["retcode"] = ret["retcode"] @@ -112,7 +112,7 @@ def remove_license(key): result["output"] = "PowerPath is not installed" return result - cmd = "/sbin/emcpreg -remove {}".format(key) + cmd = f"/sbin/emcpreg -remove {key}" ret = __salt__["cmd.run_all"](cmd, python_shell=True) result["retcode"] = ret["retcode"] diff --git a/salt/modules/proxy.py b/salt/modules/proxy.py index 1aa5dc9f2c6..6a7478b0b8c 100644 --- a/salt/modules/proxy.py +++ b/salt/modules/proxy.py @@ -27,9 +27,7 @@ def __virtual__(): def _get_proxy_osx(cmd_function, network_service): ret = {} - out = __salt__["cmd.run"]( - "networksetup -{} {}".format(cmd_function, network_service) - ) + out = __salt__["cmd.run"](f"networksetup -{cmd_function} {network_service}") match = re.match("Enabled: (.*)\nServer: (.*)\nPort: (.*)\n", out) if match is not None: g = match.groups() @@ -45,7 +43,7 @@ def _set_proxy_osx(cmd_function, server, port, user, password, network_service): ) if user is not None and password is not None: - cmd = cmd + " On {} {}".format(user, password) + cmd = cmd + f" On {user} {password}" out = __salt__["cmd.run"](cmd) @@ -110,7 +108,7 @@ def _set_proxy_windows( server_str = "" for t in types: - server_str += "{}={}:{};".format(t, server, port) + server_str += f"{t}={server}:{port};" __utils__["reg.set_value"]( hive="HKEY_CURRENT_USER", @@ -394,9 +392,7 @@ def get_proxy_bypass(network_service="Ethernet"): return reg_val.replace("", "").split(";") - out = __salt__["cmd.run"]( - "networksetup -getproxybypassdomains {}".format(network_service) - ) + out = __salt__["cmd.run"](f"networksetup -getproxybypassdomains {network_service}") return out.split("\n") diff --git a/salt/modules/ps.py b/salt/modules/ps.py index a6b23c500d0..e659a702b18 100644 --- a/salt/modules/ps.py +++ b/salt/modules/ps.py @@ -560,7 +560,7 @@ def boot_time(time_format=None): try: return b_time.strftime(time_format) except TypeError as exc: - raise SaltInvocationError("Invalid format string: {}".format(exc)) + raise SaltInvocationError(f"Invalid format string: {exc}") return b_time diff --git a/salt/modules/publish.py b/salt/modules/publish.py index cc424cc3835..c3aa8757b2f 100644 --- a/salt/modules/publish.py +++ b/salt/modules/publish.py @@ -94,7 +94,7 @@ def _publish( matching_master_uris = [ master for master in __opts__["master_uri_list"] - if "//{}:".format(via_master) in master + if f"//{via_master}:" in master ] if not matching_master_uris: @@ -144,7 +144,7 @@ def _publish( try: peer_data = channel.send(load) except SaltReqTimeoutError: - return "'{}' publish timed out".format(fun) + return f"'{fun}' publish timed out" if not peer_data: return {} # CLI args are passed as strings, re-cast to keep time.sleep happy @@ -348,4 +348,4 @@ def runner(fun, arg=None, timeout=5): try: return channel.send(load) except SaltReqTimeoutError: - return "'{}' runner publish timed out".format(fun) + return f"'{fun}' runner publish timed out" diff --git a/salt/modules/puppet.py b/salt/modules/puppet.py index 8fd1e994c7e..82df2986f2c 100644 --- a/salt/modules/puppet.py +++ b/salt/modules/puppet.py @@ -84,15 +84,15 @@ class _Puppet: ) args = " ".join(self.subcmd_args) - args += "".join([" --{}".format(k) for k in self.args]) # single spaces - args += "".join([" --{} {}".format(k, v) for k, v in self.kwargs.items()]) + args += "".join([f" --{k}" for k in self.args]) # single spaces + args += "".join([f" --{k} {v}" for k, v in self.kwargs.items()]) # Ensure that the puppet call will return 0 in case of exit code 2 if salt.utils.platform.is_windows(): return "cmd /V:ON /c {} {} ^& if !ERRORLEVEL! EQU 2 (EXIT 0) ELSE (EXIT /B)".format( cmd, args ) - return "({} {}) || test $? -eq 2".format(cmd, args) + return f"({cmd} {args}) || test $? -eq 2" def arguments(self, args=None): """ @@ -193,7 +193,7 @@ def enable(): try: os.remove(puppet.disabled_lockfile) except OSError as exc: - msg = "Failed to enable: {}".format(exc) + msg = f"Failed to enable: {exc}" log.error(msg) raise CommandExecutionError(msg) else: @@ -229,7 +229,7 @@ def disable(message=None): try: # Puppet chokes when no valid json is found msg = ( - '{{"disabled_message":"{0}"}}'.format(message) + f'{{"disabled_message":"{message}"}}' if message is not None else "{}" ) @@ -237,7 +237,7 @@ def disable(message=None): lockfile.close() return True except OSError as exc: - msg = "Failed to disable: {}".format(exc) + msg = f"Failed to disable: {exc}" log.error(msg) raise CommandExecutionError(msg) @@ -319,11 +319,9 @@ def summary(): result["resources"] = report["resources"] except salt.utils.yaml.YAMLError as exc: - raise CommandExecutionError( - "YAML error parsing puppet run summary: {}".format(exc) - ) + raise CommandExecutionError(f"YAML error parsing puppet run summary: {exc}") except OSError as exc: - raise CommandExecutionError("Unable to read puppet run summary: {}".format(exc)) + raise CommandExecutionError(f"Unable to read puppet run summary: {exc}") return result @@ -357,7 +355,7 @@ def facts(puppet=False): """ ret = {} opt_puppet = "--puppet" if puppet else "" - cmd_ret = __salt__["cmd.run_all"]("facter {}".format(opt_puppet)) + cmd_ret = __salt__["cmd.run_all"](f"facter {opt_puppet}") if cmd_ret["retcode"] != 0: raise CommandExecutionError(cmd_ret["stderr"]) @@ -388,9 +386,7 @@ def fact(name, puppet=False): salt '*' puppet.fact kernel """ opt_puppet = "--puppet" if puppet else "" - ret = __salt__["cmd.run_all"]( - "facter {} {}".format(opt_puppet, name), python_shell=False - ) + ret = __salt__["cmd.run_all"](f"facter {opt_puppet} {name}", python_shell=False) if ret["retcode"] != 0: raise CommandExecutionError(ret["stderr"]) diff --git a/salt/modules/purefb.py b/salt/modules/purefb.py index 787c77446b8..cf9cdb4e2e0 100644 --- a/salt/modules/purefb.py +++ b/salt/modules/purefb.py @@ -150,7 +150,7 @@ def _get_snapshot(name, suffix, blade): or None """ try: - filt = "source='{}' and suffix='{}'".format(name, suffix) + filt = f"source='{name}' and suffix='{suffix}'" res = blade.file_system_snapshots.list_file_system_snapshots(filter=filt) return res.items[0] except rest.ApiException: diff --git a/salt/modules/pw_group.py b/salt/modules/pw_group.py index 99128d196bd..7c6d1fd5292 100644 --- a/salt/modules/pw_group.py +++ b/salt/modules/pw_group.py @@ -64,8 +64,8 @@ def add(name, gid=None, **kwargs): cmd = "pw groupadd " if gid: - cmd += "-g {} ".format(gid) - cmd = "{} -n {}".format(cmd, name) + cmd += f"-g {gid} " + cmd = f"{cmd} -n {name}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) return not ret["retcode"] @@ -81,7 +81,7 @@ def delete(name): salt '*' group.delete foo """ - ret = __salt__["cmd.run_all"]("pw groupdel {}".format(name), python_shell=False) + ret = __salt__["cmd.run_all"](f"pw groupdel {name}", python_shell=False) return not ret["retcode"] @@ -142,7 +142,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) if gid == pre_gid: return True - cmd = "pw groupmod {} -g {}".format(name, gid) + cmd = f"pw groupmod {name} -g {gid}" __salt__["cmd.run"](cmd, python_shell=False) post_gid = __salt__["file.group_to_gid"](name) if post_gid != pre_gid: @@ -165,7 +165,7 @@ def adduser(name, username): """ # Note: pw exits with code 65 if group is unknown retcode = __salt__["cmd.retcode"]( - "pw groupmod {} -m {}".format(name, username), python_shell=False + f"pw groupmod {name} -m {username}", python_shell=False ) return not retcode @@ -191,7 +191,7 @@ def deluser(name, username): # Note: pw exits with code 65 if group is unknown retcode = __salt__["cmd.retcode"]( - "pw groupmod {} -d {}".format(name, username), python_shell=False + f"pw groupmod {name} -d {username}", python_shell=False ) return not retcode @@ -214,7 +214,7 @@ def members(name, members_list): """ retcode = __salt__["cmd.retcode"]( - "pw groupmod {} -M {}".format(name, members_list), python_shell=False + f"pw groupmod {name} -M {members_list}", python_shell=False ) return not retcode diff --git a/salt/modules/pw_user.py b/salt/modules/pw_user.py index 6506452db56..cebb46c993b 100644 --- a/salt/modules/pw_user.py +++ b/salt/modules/pw_user.py @@ -75,7 +75,7 @@ def _get_gecos(name): try: gecos_field = pwd.getpwnam(name).pw_gecos.split(",", 3) except KeyError: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if not gecos_field: return {} else: @@ -136,7 +136,7 @@ def add( homephone="", createhome=True, loginclass=None, - **kwargs + **kwargs, ): """ Add a user to the minion @@ -238,7 +238,7 @@ def chuid(name, uid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if uid == pre_info["uid"]: return True cmd = ["pw", "usermod", "-u", uid, "-n", name] @@ -258,7 +258,7 @@ def chgid(name, gid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if gid == pre_info["gid"]: return True cmd = ["pw", "usermod", "-g", gid, "-n", name] @@ -278,7 +278,7 @@ def chshell(name, shell): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if shell == pre_info["shell"]: return True cmd = ["pw", "usermod", "-s", shell, "-n", name] @@ -309,7 +309,7 @@ def chhome(name, home, persist=False): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if home == pre_info["home"]: return True cmd = ["pw", "usermod", name, "-d", home] @@ -419,7 +419,7 @@ def chloginclass(name, loginclass, root=None): if loginclass == get_loginclass(name): return True - cmd = ["pw", "usermod", "-L", "{}".format(loginclass), "-n", "{}".format(name)] + cmd = ["pw", "usermod", "-L", f"{loginclass}", "-n", f"{name}"] __salt__["cmd.run"](cmd, python_shell=False) @@ -518,10 +518,10 @@ def rename(name, new_name): """ current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") cmd = ["pw", "usermod", "-l", new_name, "-n", name] __salt__["cmd.run"](cmd) post_info = info(new_name) diff --git a/salt/modules/pyenv.py b/salt/modules/pyenv.py index df39db80333..30d569b5700 100644 --- a/salt/modules/pyenv.py +++ b/salt/modules/pyenv.py @@ -32,14 +32,12 @@ def _pyenv_exec(command, args="", env=None, runas=None, ret=None): path = _pyenv_path(runas) if env: - env = " {}".format(env) + env = f" {env}" env = env or "" - binary = "env PYENV_ROOT={}{} {}".format(path, env, binary) + binary = f"env PYENV_ROOT={path}{env} {binary}" - result = __salt__["cmd.run_all"]( - "{} {} {}".format(binary, command, args), runas=runas - ) + result = __salt__["cmd.run_all"](f"{binary} {command} {args}", runas=runas) if isinstance(ret, dict): ret.update(result) @@ -53,7 +51,7 @@ def _pyenv_exec(command, args="", env=None, runas=None, ret=None): def _pyenv_bin(runas=None): path = _pyenv_path(runas) - return "{}/bin/pyenv".format(path) + return f"{path}/bin/pyenv" def _pyenv_path(runas=None): @@ -61,7 +59,7 @@ def _pyenv_path(runas=None): if runas in (None, "root"): path = __salt__["config.option"]("pyenv.root") or "/usr/local/pyenv" else: - path = __salt__["config.option"]("pyenv.root") or "~{}/.pyenv".format(runas) + path = __salt__["config.option"]("pyenv.root") or f"~{runas}/.pyenv" return os.path.expanduser(path) @@ -71,7 +69,7 @@ def _install_pyenv(path, runas=None): return True return 0 == __salt__["cmd.retcode"]( - "git clone https://github.com/yyuu/pyenv.git {}".format(path), runas=runas + f"git clone https://github.com/yyuu/pyenv.git {path}", runas=runas ) @@ -80,17 +78,17 @@ def _update_pyenv(path, runas=None): return False return 0 == __salt__["cmd.retcode"]( - "cd {} && git pull".format(shlex.quote(path)), runas=runas + f"cd {shlex.quote(path)} && git pull", runas=runas ) def _update_python_build(path, runas=None): - path = "{}/plugins/python-build".format(path) + path = f"{path}/plugins/python-build" if not os.path.isdir(path): return False return 0 == __salt__["cmd.retcode"]( - "cd {} && git pull".format(shlex.quote(path)), runas=runas + f"cd {shlex.quote(path)} && git pull", runas=runas ) @@ -193,7 +191,7 @@ def uninstall_python(python, runas=None): """ python = re.sub(r"^python-", "", python) - args = "--force {}".format(python) + args = f"--force {python}" _pyenv_exec("uninstall", args, runas=runas) return True @@ -287,7 +285,7 @@ def do(cmdline=None, runas=None): for cmd in cmd_split: quoted_line = quoted_line + " " + shlex.quote(cmd) result = __salt__["cmd.run_all"]( - "env PATH={}/shims:$PATH {}".format(shlex.quote(path), quoted_line), + f"env PATH={shlex.quote(path)}/shims:$PATH {quoted_line}", runas=runas, python_shell=True, ) @@ -311,7 +309,7 @@ def do_with_python(python, cmdline, runas=None): salt '*' pyenv.do_with_python 2.0.0-p0 'gem list bundler' deploy """ if python: - cmd = "PYENV_VERSION={} {}".format(python, cmdline) + cmd = f"PYENV_VERSION={python} {cmdline}" else: cmd = cmdline diff --git a/salt/modules/qemu_img.py b/salt/modules/qemu_img.py index 1424929e45a..4f4b0dde628 100644 --- a/salt/modules/qemu_img.py +++ b/salt/modules/qemu_img.py @@ -42,7 +42,7 @@ def make_image(location, size, fmt): if not os.path.isdir(os.path.dirname(location)): return "" if not __salt__["cmd.retcode"]( - "qemu-img create -f {} {} {}M".format(fmt, location, size), + f"qemu-img create -f {fmt} {location} {size}M", python_shell=False, ): return location diff --git a/salt/modules/qemu_nbd.py b/salt/modules/qemu_nbd.py index c27bde15a78..375cbdeb3ab 100644 --- a/salt/modules/qemu_nbd.py +++ b/salt/modules/qemu_nbd.py @@ -51,14 +51,14 @@ def connect(image): fdisk = "fdisk -l" __salt__["cmd.run"]("modprobe nbd max_part=63") for nbd in glob.glob("/dev/nbd?"): - if __salt__["cmd.retcode"]("{} {}".format(fdisk, nbd)): + if __salt__["cmd.retcode"](f"{fdisk} {nbd}"): while True: # Sometimes nbd does not "take hold", loop until we can verify __salt__["cmd.run"]( - "qemu-nbd -c {} {}".format(nbd, image), + f"qemu-nbd -c {nbd} {image}", python_shell=False, ) - if not __salt__["cmd.retcode"]("{} {}".format(fdisk, nbd)): + if not __salt__["cmd.retcode"](f"{fdisk} {nbd}"): break return nbd log.warning("Could not connect image: %s", image) @@ -77,13 +77,13 @@ def mount(nbd, root=None): salt '*' qemu_nbd.mount /dev/nbd0 """ __salt__["cmd.run"]( - "partprobe {}".format(nbd), + f"partprobe {nbd}", python_shell=False, ) ret = {} if root is None: root = os.path.join(tempfile.gettempdir(), "nbd", os.path.basename(nbd)) - for part in glob.glob("{}p*".format(nbd)): + for part in glob.glob(f"{nbd}p*"): m_pt = os.path.join(root, os.path.basename(part)) time.sleep(1) mnt = __salt__["mount.mount"](m_pt, part, True) @@ -132,5 +132,5 @@ def clear(mnt): if ret: return ret for nbd in nbds: - __salt__["cmd.run"]("qemu-nbd -d {}".format(nbd), python_shell=False) + __salt__["cmd.run"](f"qemu-nbd -d {nbd}", python_shell=False) return ret diff --git a/salt/modules/quota.py b/salt/modules/quota.py index eb99d67a4f6..39bd3c5b1ce 100644 --- a/salt/modules/quota.py +++ b/salt/modules/quota.py @@ -48,7 +48,7 @@ def _parse_quota(mount, opts): """ Parse the output from repquota. Requires that -u -g are passed in """ - cmd = "repquota -vp {} {}".format(opts, mount) + cmd = f"repquota -vp {opts} {mount}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() mode = "header" @@ -200,7 +200,7 @@ def on(device): salt '*' quota.on """ - cmd = "quotaon {}".format(device) + cmd = f"quotaon {device}" __salt__["cmd.run"](cmd, python_shell=False) return True @@ -215,7 +215,7 @@ def off(device): salt '*' quota.off """ - cmd = "quotaoff {}".format(device) + cmd = f"quotaoff {device}" __salt__["cmd.run"](cmd, python_shell=False) return True @@ -231,7 +231,7 @@ def get_mode(device): salt '*' quota.get_mode """ ret = {} - cmd = "quotaon -p {}".format(device) + cmd = f"quotaon -p {device}" out = __salt__["cmd.run"](cmd, python_shell=False) for line in out.splitlines(): comps = line.strip().split() diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index a11fc4a3ede..42f148ed476 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -44,11 +44,9 @@ def __virtual__(): ) (dir_path, value_type) = winreg.QueryValueEx(key, "Install_Dir") if value_type != winreg.REG_SZ: - raise TypeError( - "Invalid RabbitMQ Server directory type: {}".format(value_type) - ) + raise TypeError(f"Invalid RabbitMQ Server directory type: {value_type}") if not os.path.isdir(dir_path): - raise OSError("RabbitMQ directory not found: {}".format(dir_path)) + raise OSError(f"RabbitMQ directory not found: {dir_path}") subdir_match = "" for name in os.listdir(dir_path): if name.startswith("rabbitmq_server-"): @@ -58,7 +56,7 @@ def __virtual__(): subdir_match = subdir_path if not subdir_match: raise OSError( - '"rabbitmq_server-*" subdirectory not found in: {}'.format(dir_path) + f'"rabbitmq_server-*" subdirectory not found in: {dir_path}' ) RABBITMQCTL = os.path.join(subdir_match, "sbin", "rabbitmqctl.bat") RABBITMQ_PLUGINS = os.path.join( @@ -86,7 +84,7 @@ def _check_response(response): ) else: if "Error" in response: - raise CommandExecutionError("RabbitMQ command failed: {}".format(response)) + raise CommandExecutionError(f"RabbitMQ command failed: {response}") def _format_response(response, msg): @@ -99,7 +97,7 @@ def _format_response(response, msg): response = response["stdout"] else: if "Error" in response: - raise CommandExecutionError("RabbitMQ command failed: {}".format(response)) + raise CommandExecutionError(f"RabbitMQ command failed: {response}") return {msg: response} @@ -380,7 +378,7 @@ def add_user(name, password=None, runas=None): # command,\r\noperable program or batch file. # Work around this by using a shell and a quoted command. python_shell = True - cmd = '"{}" add_user "{}" "{}"'.format(RABBITMQCTL, name, password) + cmd = f'"{RABBITMQCTL}" add_user "{name}" "{password}"' else: python_shell = False cmd = [RABBITMQCTL, "add_user", name, password] @@ -450,7 +448,7 @@ def change_password(name, password, runas=None): # command,\r\noperable program or batch file. # Work around this by using a shell and a quoted command. python_shell = True - cmd = '"{}" change_password "{}" "{}"'.format(RABBITMQCTL, name, password) + cmd = f'"{RABBITMQCTL}" change_password "{name}" "{password}"' else: python_shell = False cmd = [RABBITMQCTL, "change_password", name, password] @@ -541,7 +539,7 @@ def check_password(name, password, runas=None): # command,\r\noperable program or batch file. # Work around this by using a shell and a quoted command. python_shell = True - cmd = '"{}" authenticate_user "{}" "{}"'.format(RABBITMQCTL, name, password) + cmd = f'"{RABBITMQCTL}" authenticate_user "{name}" "{password}"' else: python_shell = False cmd = [RABBITMQCTL, "authenticate_user", name, password] @@ -788,7 +786,7 @@ def join_cluster(host, user="rabbit", ram_node=None, runas=None): cmd = [RABBITMQCTL, "join_cluster"] if ram_node: cmd.append("--ram") - cmd.append("{}@{}".format(user, host)) + cmd.append(f"{user}@{host}") if runas is None and not salt.utils.platform.is_windows(): runas = salt.utils.user.get_user() diff --git a/salt/modules/rallydev.py b/salt/modules/rallydev.py index 219d0ab2baa..dc92ae93185 100644 --- a/salt/modules/rallydev.py +++ b/salt/modules/rallydev.py @@ -80,7 +80,7 @@ def _query( path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("RallyDev URL: %s", path) diff --git a/salt/modules/random_org.py b/salt/modules/random_org.py index f5d39cfbeaa..91db8756a41 100644 --- a/salt/modules/random_org.py +++ b/salt/modules/random_org.py @@ -206,7 +206,7 @@ def generateIntegers(api_key=None, api_version=None, **kwargs): for item in ["number", "minimum", "maximum"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Rquired argument, {} is missing.".format(item) + ret["message"] = f"Rquired argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 10000: @@ -332,7 +332,7 @@ def generateStrings(api_key=None, api_version=None, **kwargs): for item in ["number", "length", "characters"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 10000: @@ -422,7 +422,7 @@ def generateUUIDs(api_key=None, api_version=None, **kwargs): for item in ["number"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if isinstance(api_version, int): @@ -503,7 +503,7 @@ def generateDecimalFractions(api_key=None, api_version=None, **kwargs): for item in ["number", "decimalPlaces"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not isinstance(kwargs["number"], int) or not 1 <= kwargs["number"] <= 10000: @@ -597,7 +597,7 @@ def generateGaussians(api_key=None, api_version=None, **kwargs): for item in ["number", "mean", "standardDeviation", "significantDigits"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 10000: @@ -697,7 +697,7 @@ def generateBlobs(api_key=None, api_version=None, **kwargs): for item in ["number", "size"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 100: diff --git a/salt/modules/rbac_solaris.py b/salt/modules/rbac_solaris.py index 876eaf0bf70..3adf2eb974f 100644 --- a/salt/modules/rbac_solaris.py +++ b/salt/modules/rbac_solaris.py @@ -21,7 +21,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on a solaris like system".format(__virtualname__), + f"{__virtualname__} module can only be loaded on a solaris like system", ) @@ -459,7 +459,7 @@ def auth_list(): # add auth info to dict if auth[0][-1:] == ".": - auth[0] = "{}*".format(auth[0]) + auth[0] = f"{auth[0]}*" auths[auth[0]] = auth[3] return auths @@ -509,7 +509,7 @@ def auth_get(user, computed=True): ## also parse auths command if computed: - res = __salt__["cmd.run_all"]("auths {}".format(user)) + res = __salt__["cmd.run_all"](f"auths {user}") if res["retcode"] == 0: for auth in res["stdout"].splitlines(): if "," in auth: diff --git a/salt/modules/rbenv.py b/salt/modules/rbenv.py index b41ed1e8909..1f3ee003818 100644 --- a/salt/modules/rbenv.py +++ b/salt/modules/rbenv.py @@ -75,7 +75,7 @@ def _parse_env(env): def _rbenv_bin(runas=None): path = _rbenv_path(runas) - return "{}/bin/rbenv".format(path) + return f"{path}/bin/rbenv" def _rbenv_path(runas=None): @@ -83,7 +83,7 @@ def _rbenv_path(runas=None): if runas in (None, "root"): path = __salt__["config.option"]("rbenv.root") or "/usr/local/rbenv" else: - path = __salt__["config.option"]("rbenv.root") or "~{}/.rbenv".format(runas) + path = __salt__["config.option"]("rbenv.root") or f"~{runas}/.rbenv" return os.path.expanduser(path) @@ -119,7 +119,7 @@ def _install_rbenv(path, runas=None): def _install_ruby_build(path, runas=None): - path = "{}/plugins/ruby-build".format(path) + path = f"{path}/plugins/ruby-build" if os.path.isdir(path): return True @@ -140,7 +140,7 @@ def _update_rbenv(path, runas=None): def _update_ruby_build(path, runas=None): - path = "{}/plugins/ruby-build".format(path) + path = f"{path}/plugins/ruby-build" if not os.path.isdir(path): return False diff --git a/salt/modules/rdp.py b/salt/modules/rdp.py index e0c4a5d21a5..81dc1c77c6a 100644 --- a/salt/modules/rdp.py +++ b/salt/modules/rdp.py @@ -50,9 +50,7 @@ def _psrdp(cmd): "-Namespace root\\CIMV2\\TerminalServices -Computer . " "-Authentication 6 -ErrorAction Stop" ) - return __salt__["cmd.run"]( - "{} ; {}".format(rdp, cmd), shell="powershell", python_shell=True - ) + return __salt__["cmd.run"](f"{rdp} ; {cmd}", shell="powershell", python_shell=True) def enable(): diff --git a/salt/modules/reg.py b/salt/modules/reg.py index 5184d0423e2..5afaad95716 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -559,13 +559,13 @@ def import_file(source, use_32bit_registry=False): """ cache_path = __salt__["cp.cache_file"](source) if not cache_path: - error_msg = "File/URL '{}' probably invalid.".format(source) + error_msg = f"File/URL '{source}' probably invalid." raise ValueError(error_msg) if use_32bit_registry: word_sz_txt = "32" else: word_sz_txt = "64" - cmd = 'reg import "{}" /reg:{}'.format(cache_path, word_sz_txt) + cmd = f'reg import "{cache_path}" /reg:{word_sz_txt}' cmd_ret_dict = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = cmd_ret_dict["retcode"] if retcode != 0: diff --git a/salt/modules/restartcheck.py b/salt/modules/restartcheck.py index b2a2a30bb66..9f355df48cd 100644 --- a/salt/modules/restartcheck.py +++ b/salt/modules/restartcheck.py @@ -330,7 +330,7 @@ def _kernel_versions_nilrt(): Get kernel version from a binary image or None if detection fails """ kvregex = r"[0-9]+\.[0-9]+\.[0-9]+-rt\S+" - kernel_strings = __salt__["cmd.run"]("strings {}".format(kbin)) + kernel_strings = __salt__["cmd.run"](f"strings {kbin}") re_result = re.search(kvregex, kernel_strings) return None if re_result is None else re_result.group(0) @@ -347,7 +347,7 @@ def _kernel_versions_nilrt(): itb_path, compressed_kernel ) ) - __salt__["cmd.run"]("gunzip -f {}".format(compressed_kernel)) + __salt__["cmd.run"](f"gunzip -f {compressed_kernel}") kver = _get_kver_from_bin(uncompressed_kernel) else: # the kernel bzImage is copied to rootfs without package management or @@ -388,8 +388,8 @@ def _file_changed_nilrt(full_filepath): """ rs_state_dir = "/var/lib/salt/restartcheck_state" base_filename = os.path.basename(full_filepath) - timestamp_file = os.path.join(rs_state_dir, "{}.timestamp".format(base_filename)) - md5sum_file = os.path.join(rs_state_dir, "{}.md5sum".format(base_filename)) + timestamp_file = os.path.join(rs_state_dir, f"{base_filename}.timestamp") + md5sum_file = os.path.join(rs_state_dir, f"{base_filename}.md5sum") if not os.path.exists(timestamp_file) or not os.path.exists(md5sum_file): return True @@ -402,9 +402,7 @@ def _file_changed_nilrt(full_filepath): return True return bool( - __salt__["cmd.retcode"]( - "md5sum -cs {}".format(md5sum_file), output_loglevel="quiet" - ) + __salt__["cmd.retcode"](f"md5sum -cs {md5sum_file}", output_loglevel="quiet") ) @@ -419,7 +417,7 @@ def _kernel_modules_changed_nilrt(kernelversion): - True if modules.dep was modified/touched, False otherwise. """ if kernelversion is not None: - return _file_changed_nilrt("/lib/modules/{}/modules.dep".format(kernelversion)) + return _file_changed_nilrt(f"/lib/modules/{kernelversion}/modules.dep") return False @@ -447,7 +445,7 @@ def _sysapi_changed_nilrt(): ) if os.path.exists(nisysapi_conf_d_path): - rs_count_file = "{}/sysapi.conf.d.count".format(restartcheck_state_dir) + rs_count_file = f"{restartcheck_state_dir}/sysapi.conf.d.count" if not os.path.exists(rs_count_file): return True @@ -458,7 +456,7 @@ def _sysapi_changed_nilrt(): return True for fexpert in os.listdir(nisysapi_conf_d_path): - if _file_changed_nilrt("{}/{}".format(nisysapi_conf_d_path, fexpert)): + if _file_changed_nilrt(f"{nisysapi_conf_d_path}/{fexpert}"): return True return False @@ -579,7 +577,7 @@ def restartcheck(ignorelist=None, blacklist=None, excludepid=None, **kwargs): if path in blacklist or pid in excludepid: continue try: - readlink = os.readlink("/proc/{}/exe".format(pid)) + readlink = os.readlink(f"/proc/{pid}/exe") except OSError: excludepid.append(pid) continue diff --git a/salt/modules/restconf.py b/salt/modules/restconf.py index 1a2d4f7799c..b99187c87f3 100644 --- a/salt/modules/restconf.py +++ b/salt/modules/restconf.py @@ -17,7 +17,7 @@ log = logging.getLogger(__file__) def __virtual__(): if __opts__.get("proxy", {}).get("proxytype") != __virtualname__: - return False, "Proxytype does not match: {}".format(__virtualname__) + return False, f"Proxytype does not match: {__virtualname__}" return True diff --git a/salt/modules/ret.py b/salt/modules/ret.py index 9210eb4d7ed..1885b92a8b5 100644 --- a/salt/modules/ret.py +++ b/salt/modules/ret.py @@ -16,7 +16,7 @@ def get_jid(returner, jid): salt '*' ret.get_jid redis 20421104181954700505 """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_jid".format(returner)](jid) + return returners[f"{returner}.get_jid"](jid) def get_fun(returner, fun): @@ -30,7 +30,7 @@ def get_fun(returner, fun): salt '*' ret.get_fun mysql network.interfaces """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_fun".format(returner)](fun) + return returners[f"{returner}.get_fun"](fun) def get_jids(returner): @@ -44,7 +44,7 @@ def get_jids(returner): salt '*' ret.get_jids mysql """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_jids".format(returner)]() + return returners[f"{returner}.get_jids"]() def get_minions(returner): @@ -58,4 +58,4 @@ def get_minions(returner): salt '*' ret.get_minions mysql """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_minions".format(returner)]() + return returners[f"{returner}.get_minions"]() diff --git a/salt/modules/rh_ip.py b/salt/modules/rh_ip.py index b6ee34846e2..f1d823b1a82 100644 --- a/salt/modules/rh_ip.py +++ b/salt/modules/rh_ip.py @@ -202,7 +202,7 @@ def _parse_ethtool_opts(opts, iface): _raise_error_iface(iface, "advertise", valid) if "channels" in opts: - channels_cmd = "-L {}".format(iface.strip()) + channels_cmd = f"-L {iface.strip()}" channels_params = [] for option in ("rx", "tx", "other", "combined"): if option in opts["channels"]: @@ -584,9 +584,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): if iface_type not in ("bridge",): ethtool = _parse_ethtool_opts(opts, iface) if ethtool: - result["ethtool"] = " ".join( - ["{} {}".format(x, y) for x, y in ethtool.items()] - ) + result["ethtool"] = " ".join([f"{x} {y}" for x, y in ethtool.items()]) if iface_type == "slave": result["proto"] = "none" @@ -609,9 +607,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): raise AttributeError(msg) bonding = _parse_settings_bond(opts, iface) if bonding: - result["bonding"] = " ".join( - ["{}={}".format(x, y) for x, y in bonding.items()] - ) + result["bonding"] = " ".join([f"{x}={y}" for x, y in bonding.items()]) result["devtype"] = "Bond" if iface_type == "vlan": @@ -1076,7 +1072,7 @@ def build_interface(iface, iface_type, enabled, **settings): ): opts = _parse_settings_eth(settings, iface_type, enabled, iface) try: - template = JINJA.get_template("rh{}_eth.jinja".format(rh_major)) + template = JINJA.get_template(f"rh{rh_major}_eth.jinja") except jinja2.exceptions.TemplateNotFound: log.error("Could not load template rh%s_eth.jinja", rh_major) return "" @@ -1086,7 +1082,7 @@ def build_interface(iface, iface_type, enabled, **settings): return _read_temp(ifcfg) _write_file_iface(iface, ifcfg, _RH_NETWORK_SCRIPT_DIR, "ifcfg-{0}") - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1139,8 +1135,8 @@ def build_routes(iface, **settings): _write_file_iface(iface, routecfg, _RH_NETWORK_SCRIPT_DIR, "route-{0}") _write_file_iface(iface, routecfg6, _RH_NETWORK_SCRIPT_DIR, "route6-{0}") - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route-{}".format(iface)) - path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route6-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route-{iface}") + path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route6-{iface}") routes = _read_file(path) routes.extend(_read_file(path6)) @@ -1159,7 +1155,7 @@ def down(iface, iface_type): """ # Slave devices are controlled by the master. if iface_type.lower() not in ("slave", "teamport"): - return __salt__["cmd.run"]("ifdown {}".format(iface)) + return __salt__["cmd.run"](f"ifdown {iface}") return None @@ -1173,7 +1169,7 @@ def get_interface(iface): salt '*' ip.get_interface eth0 """ - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1189,7 +1185,7 @@ def up(iface, iface_type): # pylint: disable=C0103 """ # Slave devices are controlled by the master. if iface_type.lower() not in ("slave", "teamport"): - return __salt__["cmd.run"]("ifup {}".format(iface)) + return __salt__["cmd.run"](f"ifup {iface}") return None @@ -1203,8 +1199,8 @@ def get_routes(iface): salt '*' ip.get_routes eth0 """ - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route-{}".format(iface)) - path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route6-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route-{iface}") + path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route6-{iface}") routes = _read_file(path) routes.extend(_read_file(path6)) return routes diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index b8b802479fe..f4ff8da54d0 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -113,7 +113,7 @@ def __virtual__(): "load rh_service.py as virtual 'service'", ) return __virtualname__ - return (False, "Cannot load rh_service module: OS not in {}".format(enable)) + return (False, f"Cannot load rh_service module: OS not in {enable}") def _runlevel(): @@ -137,7 +137,7 @@ def _chkconfig_add(name): /etc/init.d. The service is initially configured to be disabled at all run-levels. """ - cmd = "/sbin/chkconfig --add {}".format(name) + cmd = f"/sbin/chkconfig --add {name}" if __salt__["cmd.retcode"](cmd, python_shell=False) == 0: log.info('Added initscript "%s" to chkconfig', name) return True @@ -150,7 +150,7 @@ def _service_is_upstart(name): """ Return True if the service is an upstart service, otherwise return False. """ - return HAS_UPSTART and os.path.exists("/etc/init/{}.conf".format(name)) + return HAS_UPSTART and os.path.exists(f"/etc/init/{name}.conf") def _service_is_sysv(name): @@ -169,7 +169,7 @@ def _service_is_chkconfig(name): """ Return True if the service is managed by chkconfig. """ - cmdline = "/sbin/chkconfig --list {}".format(name) + cmdline = f"/sbin/chkconfig --list {name}" return ( __salt__["cmd.retcode"](cmdline, python_shell=False, ignore_retcode=True) == 0 ) @@ -188,7 +188,7 @@ def _sysv_is_enabled(name, runlevel=None): if runlevel is None: runlevel = _runlevel() - return len(glob.glob("/etc/rc.d/rc{}.d/S??{}".format(runlevel, name))) > 0 + return len(glob.glob(f"/etc/rc.d/rc{runlevel}.d/S??{name}")) > 0 def _chkconfig_is_enabled(name, runlevel=None): @@ -197,14 +197,14 @@ def _chkconfig_is_enabled(name, runlevel=None): return ``False``. If ``runlevel`` is ``None``, then use the current runlevel. """ - cmdline = "/sbin/chkconfig --list {}".format(name) + cmdline = f"/sbin/chkconfig --list {name}" result = __salt__["cmd.run_all"](cmdline, python_shell=False) if runlevel is None: runlevel = _runlevel() if result["retcode"] == 0: for row in result["stdout"].splitlines(): - if "{}:on".format(runlevel) in row: + if f"{runlevel}:on" in row: if row.split()[0] == name: return True elif row.split() == [name, "on"]: @@ -220,7 +220,7 @@ def _sysv_enable(name): """ if not _service_is_chkconfig(name) and not _chkconfig_add(name): return False - cmd = "/sbin/chkconfig {} on".format(name) + cmd = f"/sbin/chkconfig {name} on" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -233,7 +233,7 @@ def _sysv_disable(name): """ if not _service_is_chkconfig(name) and not _chkconfig_add(name): return False - cmd = "/sbin/chkconfig {} off".format(name) + cmd = f"/sbin/chkconfig {name} off" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -244,7 +244,7 @@ def _sysv_delete(name): """ if not _service_is_chkconfig(name): return False - cmd = "/sbin/chkconfig --del {}".format(name) + cmd = f"/sbin/chkconfig --del {name}" return not __salt__["cmd.retcode"](cmd) @@ -253,10 +253,10 @@ def _upstart_delete(name): Delete an upstart service. This will only rename the .conf file """ if HAS_UPSTART: - if os.path.exists("/etc/init/{}.conf".format(name)): + if os.path.exists(f"/etc/init/{name}.conf"): os.rename( - "/etc/init/{}.conf".format(name), - "/etc/init/{}.conf.removed".format(name), + f"/etc/init/{name}.conf", + f"/etc/init/{name}.conf.removed", ) return True @@ -435,9 +435,9 @@ def start(name): salt '*' service.start """ if _service_is_upstart(name): - cmd = "start {}".format(name) + cmd = f"start {name}" else: - cmd = "/sbin/service {} start".format(name) + cmd = f"/sbin/service {name} start" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -452,9 +452,9 @@ def stop(name): salt '*' service.stop """ if _service_is_upstart(name): - cmd = "stop {}".format(name) + cmd = f"stop {name}" else: - cmd = "/sbin/service {} stop".format(name) + cmd = f"/sbin/service {name} stop" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -469,9 +469,9 @@ def restart(name): salt '*' service.restart """ if _service_is_upstart(name): - cmd = "restart {}".format(name) + cmd = f"restart {name}" else: - cmd = "/sbin/service {} restart".format(name) + cmd = f"/sbin/service {name} restart" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -486,9 +486,9 @@ def reload_(name): salt '*' service.reload """ if _service_is_upstart(name): - cmd = "reload {}".format(name) + cmd = f"reload {name}" else: - cmd = "/sbin/service {} reload".format(name) + cmd = f"/sbin/service {name} reload" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -526,12 +526,12 @@ def status(name, sig=None): results = {} for service in services: if _service_is_upstart(service): - cmd = "status {}".format(service) + cmd = f"status {service}" results[service] = "start/running" in __salt__["cmd.run"]( cmd, python_shell=False ) else: - cmd = "/sbin/service {} status".format(service) + cmd = f"/sbin/service {service} status" results[service] = ( __salt__["cmd.retcode"](cmd, python_shell=False, ignore_retcode=True) == 0 diff --git a/salt/modules/riak.py b/salt/modules/riak.py index 197d8689971..f8d893a8451 100644 --- a/salt/modules/riak.py +++ b/salt/modules/riak.py @@ -21,7 +21,7 @@ def __execute_cmd(name, cmd): """ Execute Riak commands """ - return __salt__["cmd.run_all"]("{} {}".format(salt.utils.path.which(name), cmd)) + return __salt__["cmd.run_all"](f"{salt.utils.path.which(name)} {cmd}") def start(): @@ -89,7 +89,7 @@ def cluster_join(username, hostname): """ ret = {"comment": "", "success": False} - cmd = __execute_cmd("riak-admin", "cluster join {}@{}".format(username, hostname)) + cmd = __execute_cmd("riak-admin", f"cluster join {username}@{hostname}") if cmd["retcode"] != 0: ret["comment"] = cmd["stdout"] @@ -117,7 +117,7 @@ def cluster_leave(username, hostname): """ ret = {"comment": "", "success": False} - cmd = __execute_cmd("riak-admin", "cluster leave {}@{}".format(username, hostname)) + cmd = __execute_cmd("riak-admin", f"cluster leave {username}@{hostname}") if cmd["retcode"] != 0: ret["comment"] = cmd["stdout"] diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py index 7bf45780f0c..1e3aa32e958 100644 --- a/salt/modules/rpm_lowpkg.py +++ b/salt/modules/rpm_lowpkg.py @@ -110,14 +110,14 @@ def bin_pkg_info(path, saltenv="base"): newpath = __salt__["cp.cache_file"](path, saltenv) if not newpath: raise CommandExecutionError( - "Unable to retrieve {} from saltenv '{}'".format(path, saltenv) + f"Unable to retrieve {path} from saltenv '{saltenv}'" ) path = newpath else: if not os.path.exists(path): - raise CommandExecutionError("{} does not exist on minion".format(path)) + raise CommandExecutionError(f"{path} does not exist on minion") elif not os.path.isabs(path): - raise SaltInvocationError("{} does not exist on minion".format(path)) + raise SaltInvocationError(f"{path} does not exist on minion") # REPOID is not a valid tag for the rpm command. Remove it and replace it # with 'none' @@ -495,7 +495,7 @@ def diff(package_path, path): ) res = __salt__["cmd.shell"](cmd.format(package_path, path), output_loglevel="trace") if res and res.startswith("Binary file"): - return "File '{}' is binary and its content has been modified.".format(path) + return f"File '{path}' is binary and its content has been modified." return res @@ -765,7 +765,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False): # rpmdev-vercmp always uses epochs, even when zero def _ensure_epoch(ver): def _prepend(ver): - return "0:{}".format(ver) + return f"0:{ver}" try: if ":" not in ver: @@ -821,7 +821,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False): ) if cmp_result not in (-1, 0, 1): raise CommandExecutionError( - "Comparison result '{}' is invalid".format(cmp_result) + f"Comparison result '{cmp_result}' is invalid" ) return cmp_result diff --git a/salt/modules/rpmbuild_pkgbuild.py b/salt/modules/rpmbuild_pkgbuild.py index 9d205392b1b..135afab975c 100644 --- a/salt/modules/rpmbuild_pkgbuild.py +++ b/salt/modules/rpmbuild_pkgbuild.py @@ -82,7 +82,7 @@ def _create_rpmmacros(runas="root"): rpmmacros = os.path.join(home, ".rpmmacros") with salt.utils.files.fopen(rpmmacros, "w") as afile: - afile.write(salt.utils.stringutils.to_str("%_topdir {}\n".format(rpmbuilddir))) + afile.write(salt.utils.stringutils.to_str(f"%_topdir {rpmbuilddir}\n")) afile.write("%signature gpg\n") afile.write("%_source_filedigest_algorithm 8\n") afile.write("%_binary_filedigest_algorithm 8\n") @@ -132,9 +132,9 @@ def _get_distset(tgt): # consistent naming on Centos and Redhat, and allow for Amazon naming tgtattrs = tgt.split("-") if tgtattrs[0] == "amzn2": - distset = '--define "dist .{}"'.format(tgtattrs[0]) + distset = f'--define "dist .{tgtattrs[0]}"' elif tgtattrs[1] in ["6", "7", "8"]: - distset = '--define "dist .el{}"'.format(tgtattrs[1]) + distset = f'--define "dist .el{tgtattrs[1]}"' else: distset = "" @@ -161,7 +161,7 @@ def _get_deps(deps, tree_base, saltenv="base"): else: shutil.copy(deprpm, dest) - deps_list += " {}".format(dest) + deps_list += f" {dest}" return deps_list @@ -174,9 +174,7 @@ def _check_repo_gpg_phrase_utils(): if __salt__["file.file_exists"](util_name): return True else: - raise CommandExecutionError( - "utility '{}' needs to be installed".format(util_name) - ) + raise CommandExecutionError(f"utility '{util_name}' needs to be installed") def _get_gpg_key_resources(keyid, env, use_passphrase, gnupghome, runas): @@ -325,7 +323,7 @@ def _get_gpg_key_resources(keyid, env, use_passphrase, gnupghome, runas): ) # need to update rpm with public key - cmd = "rpm --import {}".format(pkg_pub_key_file) + cmd = f"rpm --import {pkg_pub_key_file}" retrc = __salt__["cmd.retcode"](cmd, runas=runas, use_vt=True) if retrc != 0: raise SaltInvocationError( @@ -348,9 +346,9 @@ def _sign_file(runas, define_gpg_name, phrase, abs_file, timeout): interval = 0.5 number_retries = timeout / interval times_looped = 0 - error_msg = "Failed to sign file {}".format(abs_file) + error_msg = f"Failed to sign file {abs_file}" - cmd = "rpm {} --addsign {}".format(define_gpg_name, abs_file) + cmd = f"rpm {define_gpg_name} --addsign {abs_file}" preexec_fn = functools.partial(salt.utils.user.chugid_and_umask, runas, None) try: stdout, stderr = None, None @@ -395,7 +393,7 @@ def _sign_files_with_gpg_agent(runas, local_keyid, abs_file, repodir, env, timeo """ Sign file with provided key utilizing gpg-agent """ - cmd = "rpmsign --verbose --key-id={} --addsign {}".format(local_keyid, abs_file) + cmd = f"rpmsign --verbose --key-id={local_keyid} --addsign {abs_file}" retrc = __salt__["cmd.retcode"](cmd, runas=runas, cwd=repodir, use_vt=True, env=env) if retrc != 0: raise SaltInvocationError( @@ -547,7 +545,7 @@ def build( try: __salt__["file.chown"](path=dbase, user=runas, group="mock") __salt__["file.chown"](path=results_dir, user=runas, group="mock") - cmd = "mock --root={} --resultdir={} --init".format(tgt, results_dir) + cmd = f"mock --root={tgt} --resultdir={results_dir} --init" retrc |= __salt__["cmd.retcode"](cmd, runas=runas) if deps_list and not deps_list.isspace(): cmd = "mock --root={} --resultdir={} --install {} {}".format( @@ -564,7 +562,7 @@ def build( "rpm", "-qp", "--queryformat", - "{0}/%{{name}}/%{{version}}-%{{release}}".format(log_dir), + f"{log_dir}/%{{name}}/%{{version}}-%{{release}}", srpm, ] log_dest = __salt__["cmd.run_stdout"](cmdlist, python_shell=False) @@ -752,6 +750,6 @@ def make_repo( else: _sign_file(runas, define_gpg_name, phrase, abs_file, timeout) - cmd = "createrepo --update {}".format(repodir) + cmd = f"createrepo --update {repodir}" retrc = __salt__["cmd.run_all"](cmd, runas=runas) return retrc diff --git a/salt/modules/rsync.py b/salt/modules/rsync.py index ffecb3dfb89..311a51cf8a7 100644 --- a/salt/modules/rsync.py +++ b/salt/modules/rsync.py @@ -47,7 +47,7 @@ def _check(delete, force, update, passwordfile, exclude, excludefrom, dryrun, rs if update: options.append("--update") if rsh: - options.append("--rsh={}".format(rsh)) + options.append(f"--rsh={rsh}") if passwordfile: options.extend(["--password-file", passwordfile]) if excludefrom: @@ -182,16 +182,16 @@ def rsync( # get the contents not the tmpdir # itself. if not src.endswith("/"): - src = "{}/".format(src) + src = f"{src}/" else: - raise CommandExecutionError("{} does not exist".format(src)) + raise CommandExecutionError(f"{src} does not exist") else: tmp_src = salt.utils.files.mkstemp() file_src = __salt__["cp.get_file"](_src, tmp_src, saltenv) if file_src: src = tmp_src else: - raise CommandExecutionError("{} does not exist".format(src)) + raise CommandExecutionError(f"{src} does not exist") option = _check( delete, force, update, passwordfile, exclude, excludefrom, dryrun, rsh @@ -261,16 +261,14 @@ def config(conf_path="/etc/rsyncd.conf"): ret += salt.utils.stringutils.to_unicode(line) except OSError as exc: if exc.errno == errno.ENOENT: - raise CommandExecutionError("{} does not exist".format(conf_path)) + raise CommandExecutionError(f"{conf_path} does not exist") elif exc.errno == errno.EACCES: - raise CommandExecutionError( - "Unable to read {}, access denied".format(conf_path) - ) + raise CommandExecutionError(f"Unable to read {conf_path}, access denied") elif exc.errno == errno.EISDIR: raise CommandExecutionError( - "Unable to read {}, path is a directory".format(conf_path) + f"Unable to read {conf_path}, path is a directory" ) else: - raise CommandExecutionError("Error {}: {}".format(exc.errno, exc.strerror)) + raise CommandExecutionError(f"Error {exc.errno}: {exc.strerror}") else: return ret diff --git a/salt/modules/runit.py b/salt/modules/runit.py index 29f95bf377b..c38612f59f8 100644 --- a/salt/modules/runit.py +++ b/salt/modules/runit.py @@ -122,7 +122,7 @@ def start(name): salt '*' runit.start """ - cmd = "sv start {}".format(_service_path(name)) + cmd = f"sv start {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -140,7 +140,7 @@ def stop(name): salt '*' runit.stop """ - cmd = "sv stop {}".format(_service_path(name)) + cmd = f"sv stop {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -158,7 +158,7 @@ def reload_(name): salt '*' runit.reload """ - cmd = "sv reload {}".format(_service_path(name)) + cmd = f"sv reload {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -176,7 +176,7 @@ def restart(name): salt '*' runit.restart """ - cmd = "sv restart {}".format(_service_path(name)) + cmd = f"sv restart {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -226,7 +226,7 @@ def status(name, sig=None): # sv return code is not relevant to get a service status. # Check its output instead. - cmd = "sv status {}".format(svc_path) + cmd = f"sv status {svc_path}" try: out = __salt__["cmd.run_stdout"](cmd) return out.startswith("run: ") @@ -628,7 +628,7 @@ def enable(name, start=False, **kwargs): # if not, down_file might be removed too quickly, # before 'sv' have time to take care about it. # Documentation indicates that a change is handled within 5 seconds. - cmd = "sv status {}".format(_service_path(name)) + cmd = f"sv status {_service_path(name)}" retcode_sv = 1 count_sv = 0 while retcode_sv != 0 and count_sv < 10: diff --git a/salt/modules/rvm.py b/salt/modules/rvm.py index 28669a26511..92d9b92983d 100644 --- a/salt/modules/rvm.py +++ b/salt/modules/rvm.py @@ -21,8 +21,8 @@ __opts__ = { def _get_rvm_location(runas=None): if runas: - runas_home = os.path.expanduser("~{}".format(runas)) - rvmpath = "{}/.rvm/bin/rvm".format(runas_home) + runas_home = os.path.expanduser(f"~{runas}") + rvmpath = f"{runas_home}/.rvm/bin/rvm" if os.path.exists(rvmpath): return [rvmpath] return ["/usr/local/rvm/bin/rvm"] @@ -87,7 +87,7 @@ def install(runas=None): ret = __salt__["cmd.run_all"]( # the RVM installer automatically does a multi-user install when it is # invoked with root privileges - "curl -Ls {installer} | bash -s stable".format(installer=installer), + f"curl -Ls {installer} | bash -s stable", runas=runas, python_shell=True, ) diff --git a/salt/modules/s6.py b/salt/modules/s6.py index 23edface5a5..3f1c4656520 100644 --- a/salt/modules/s6.py +++ b/salt/modules/s6.py @@ -40,7 +40,7 @@ def _service_path(name): """ if not SERVICE_DIR: raise CommandExecutionError("Could not find service directory.") - return "{}/{}".format(SERVICE_DIR, name) + return f"{SERVICE_DIR}/{name}" def start(name): @@ -53,7 +53,7 @@ def start(name): salt '*' s6.start """ - cmd = "s6-svc -u {}".format(_service_path(name)) + cmd = f"s6-svc -u {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -67,7 +67,7 @@ def stop(name): salt '*' s6.stop """ - cmd = "s6-svc -d {}".format(_service_path(name)) + cmd = f"s6-svc -d {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -81,7 +81,7 @@ def term(name): salt '*' s6.term """ - cmd = "s6-svc -t {}".format(_service_path(name)) + cmd = f"s6-svc -t {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -95,7 +95,7 @@ def reload_(name): salt '*' s6.reload """ - cmd = "s6-svc -h {}".format(_service_path(name)) + cmd = f"s6-svc -h {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -109,7 +109,7 @@ def restart(name): salt '*' s6.restart """ - cmd = "s6-svc -t {}".format(_service_path(name)) + cmd = f"s6-svc -t {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -136,7 +136,7 @@ def status(name, sig=None): salt '*' s6.status """ - cmd = "s6-svstat {}".format(_service_path(name)) + cmd = f"s6-svstat {_service_path(name)}" out = __salt__["cmd.run_stdout"](cmd) try: pid = re.search(r"up \(pid (\d+)\)", out).group(1) diff --git a/salt/modules/salt_proxy.py b/salt/modules/salt_proxy.py index 315abf4314d..70572ba1f33 100644 --- a/salt/modules/salt_proxy.py +++ b/salt/modules/salt_proxy.py @@ -33,7 +33,7 @@ def _write_proxy_conf(proxyfile): proxy_conf.write( salt.utils.stringutils.to_str("master: {}".format(__grains__["master"])) ) - msg = "Wrote proxy file {}".format(proxyfile) + msg = f"Wrote proxy file {proxyfile}" log.debug(msg) return msg @@ -50,18 +50,18 @@ def _proxy_conf_file(proxyfile, test): try: if not test: changes_new.append(_write_proxy_conf(proxyfile)) - msg = "Salt Proxy: Wrote proxy conf {}".format(proxyfile) + msg = f"Salt Proxy: Wrote proxy conf {proxyfile}" else: - msg = "Salt Proxy: Update required to proxy conf {}".format(proxyfile) + msg = f"Salt Proxy: Update required to proxy conf {proxyfile}" except OSError as err: success = False - msg = "Salt Proxy: Error writing proxy file {}".format(err) + msg = f"Salt Proxy: Error writing proxy file {err}" log.error(msg) changes_new.append(msg) changes_new.append(msg) log.debug(msg) else: - msg = "Salt Proxy: {} already exists, skipping".format(proxyfile) + msg = f"Salt Proxy: {proxyfile} already exists, skipping" changes_old.append(msg) log.debug(msg) return success, changes_new, changes_old @@ -90,18 +90,14 @@ def _proxy_process(proxyname, test): if not _is_proxy_running(proxyname): if not test: __salt__["cmd.run_all"]( - "salt-proxy --proxyid={} -l info -d".format(shlex.quote(proxyname)), + f"salt-proxy --proxyid={shlex.quote(proxyname)} -l info -d", timeout=5, ) - changes_new.append( - "Salt Proxy: Started proxy process for {}".format(proxyname) - ) + changes_new.append(f"Salt Proxy: Started proxy process for {proxyname}") else: - changes_new.append( - "Salt Proxy: process {} will be started".format(proxyname) - ) + changes_new.append(f"Salt Proxy: process {proxyname} will be started") else: - changes_old.append("Salt Proxy: already running for {}".format(proxyname)) + changes_old.append(f"Salt Proxy: already running for {proxyname}") return True, changes_new, changes_old diff --git a/salt/modules/saltcheck.py b/salt/modules/saltcheck.py index 77a010f3fb1..7ca48953097 100644 --- a/salt/modules/saltcheck.py +++ b/salt/modules/saltcheck.py @@ -647,7 +647,7 @@ def _is_valid_function(module_name, function): functions = __salt__["sys.list_functions"](module_name) except salt.exceptions.SaltException: functions = ["unable to look up functions"] - return "{}.{}".format(module_name, function) in functions + return f"{module_name}.{function}" in functions def _get_top_states(saltenv="base"): @@ -874,11 +874,11 @@ class SaltCheck: if output_details: if assertion_section: assertion_section_repr_title = " {}".format("assertion_section") - assertion_section_repr_value = " {}".format(assertion_section) + assertion_section_repr_value = f" {assertion_section}" else: assertion_section_repr_title = "" assertion_section_repr_value = "" - value["module.function [args]{}".format(assertion_section_repr_title)] = ( + value[f"module.function [args]{assertion_section_repr_title}"] = ( "{} {}{}".format( mod_and_func, dumps(args), @@ -886,7 +886,7 @@ class SaltCheck: ) ) value["saltcheck assertion"] = "{}{} {}".format( - ("" if expected_return is None else "{} ".format(expected_return)), + ("" if expected_return is None else f"{expected_return} "), assertion_desc, ("hidden" if not assert_print_result else module_output), ) @@ -931,7 +931,7 @@ class SaltCheck: for num, assert_group in enumerate( test_dict.get("assertions"), start=1 ): - result["assertion{}".format(num)] = self._run_assertions( + result[f"assertion{num}"] = self._run_assertions( mod_and_func, args, assert_group, @@ -1031,7 +1031,7 @@ class SaltCheck: """ result = "Pass" try: - assert returned is True, "{} not True".format(returned) + assert returned is True, f"{returned} not True" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1045,7 +1045,7 @@ class SaltCheck: if isinstance(returned, str): returned = bool(returned) try: - assert returned is False, "{} not False".format(returned) + assert returned is False, f"{returned} not False" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1091,7 +1091,7 @@ class SaltCheck: """ result = "Pass" try: - assert expected > returned, "{} not False".format(returned) + assert expected > returned, f"{returned} not False" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1103,7 +1103,7 @@ class SaltCheck: """ result = "Pass" try: - assert expected >= returned, "{} not False".format(returned) + assert expected >= returned, f"{returned} not False" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1115,7 +1115,7 @@ class SaltCheck: """ result = "Pass" try: - assert expected < returned, "{} not False".format(returned) + assert expected < returned, f"{returned} not False" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1127,7 +1127,7 @@ class SaltCheck: """ result = "Pass" try: - assert expected <= returned, "{} not False".format(returned) + assert expected <= returned, f"{returned} not False" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1139,7 +1139,7 @@ class SaltCheck: """ result = "Pass" try: - assert not returned, "{} is not empty".format(returned) + assert not returned, f"{returned} is not empty" except AssertionError as err: result = "Fail: " + str(err) return result @@ -1251,7 +1251,7 @@ class StateTestLoader: all_sls_paths.append(test_path) state_name_base = state_name.split(".")[0] - test_path = "salt://{}/{}".format(state_name_base, self.saltcheck_test_location) + test_path = f"salt://{state_name_base}/{self.saltcheck_test_location}" all_sls_paths.append(test_path) unique_paths = set(all_sls_paths) @@ -1367,13 +1367,13 @@ class StateTestLoader: os.path.join( os.sep.join(split_sls[: len(split_sls) - 1]), os.path.normpath(self.saltcheck_test_location), - "{}.tst".format(split_sls[-1]), + f"{split_sls[-1]}.tst", ), os.path.join( split_sls[0], os.path.normpath(self.saltcheck_test_location), os.sep.join(split_sls[1:-1]), - "{}.tst".format(split_sls[-1]), + f"{split_sls[-1]}.tst", ), } # for this state, find matching test files and load them diff --git a/salt/modules/saltcloudmod.py b/salt/modules/saltcloudmod.py index acaed51519b..29a549490e0 100644 --- a/salt/modules/saltcloudmod.py +++ b/salt/modules/saltcloudmod.py @@ -40,7 +40,7 @@ def create(name, profile): salt saltcloud.create webserver rackspace_centos_512 """ - cmd = "salt-cloud --out json -p {} {}".format(profile, name) + cmd = f"salt-cloud --out json -p {profile} {name}" out = __salt__["cmd.run_stdout"](cmd, python_shell=False) try: ret = salt.utils.json.loads(out) diff --git a/salt/modules/saltutil.py b/salt/modules/saltutil.py index 57b18d007f9..fbbda03d89a 100644 --- a/salt/modules/saltutil.py +++ b/salt/modules/saltutil.py @@ -84,9 +84,7 @@ def _get_top_file_envs(): else: envs = "base" except SaltRenderError as exc: - raise CommandExecutionError( - "Unable to render top file(s): {}".format(exc) - ) + raise CommandExecutionError(f"Unable to render top file(s): {exc}") __context__["saltutil._top_file_envs"] = envs return envs @@ -162,7 +160,7 @@ def update(version=None): try: version = app.find_update() except urllib.error.URLError as exc: - ret["_error"] = "Could not connect to update_url. Error: {}".format(exc) + ret["_error"] = f"Could not connect to update_url. Error: {exc}" return ret if not version: ret["_error"] = "No updates available" @@ -170,21 +168,21 @@ def update(version=None): try: app.fetch_version(version) except EskyVersionError as exc: - ret["_error"] = "Unable to fetch version {}. Error: {}".format(version, exc) + ret["_error"] = f"Unable to fetch version {version}. Error: {exc}" return ret try: app.install_version(version) except EskyVersionError as exc: - ret["_error"] = "Unable to install version {}. Error: {}".format(version, exc) + ret["_error"] = f"Unable to install version {version}. Error: {exc}" return ret try: app.cleanup() except Exception as exc: # pylint: disable=broad-except - ret["_error"] = "Unable to cleanup. Error: {}".format(exc) + ret["_error"] = f"Unable to cleanup. Error: {exc}" restarted = {} for service in __opts__["update_restart_services"]: restarted[service] = __salt__["service.restart"](service) - ret["comment"] = "Updated from {} to {}".format(oldversion, version) + ret["comment"] = f"Updated from {oldversion} to {version}" ret["restarted"] = restarted return ret @@ -1400,7 +1398,7 @@ def find_cached_job(jid): " enable cache_jobs on this minion" ) else: - return "Local jobs cache directory {} not found".format(job_dir) + return f"Local jobs cache directory {job_dir} not found" path = os.path.join(job_dir, "return.p") with salt.utils.files.fopen(path, "rb") as fp_: buf = fp_.read() @@ -1602,7 +1600,7 @@ def _exec( kwarg, batch=False, subset=False, - **kwargs + **kwargs, ): fcn_ret = {} seen = 0 @@ -1660,7 +1658,7 @@ def cmd( ret="", kwarg=None, ssh=False, - **kwargs + **kwargs, ): """ .. versionchanged:: 2017.7.0 @@ -1681,7 +1679,7 @@ def cmd( # if return is empty, we may have not used the right conf, # try with the 'minion relative master configuration counter part # if available - master_cfgfile = "{}master".format(cfgfile[:-6]) # remove 'minion' + master_cfgfile = f"{cfgfile[:-6]}master" # remove 'minion' if ( not fcn_ret and cfgfile.endswith("{}{}".format(os.path.sep, "minion")) @@ -1704,7 +1702,7 @@ def cmd_iter( ret="", kwarg=None, ssh=False, - **kwargs + **kwargs, ): """ .. versionchanged:: 2017.7.0 diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index 1fab2038924..42458fb1c25 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -259,14 +259,12 @@ def purge(**kwargs): if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"].append( - "Job: {} would be deleted from schedule.".format(name) - ) + ret["comment"].append(f"Job: {name} would be deleted from schedule.") else: if kwargs.get("offline"): del current_schedule[name] - ret["comment"].append("Deleted job: {} from schedule.".format(name)) + ret["comment"].append(f"Deleted job: {name} from schedule.") ret["changes"][name] = "removed" else: @@ -290,7 +288,7 @@ def purge(**kwargs): ret["result"] = True ret["changes"][name] = "removed" ret["comment"].append( - "Deleted job: {} from schedule.".format(name) + f"Deleted job: {name} from schedule." ) else: ret["comment"].append( @@ -341,7 +339,7 @@ def delete(name, **kwargs): """ ret = { - "comment": "Failed to delete job {} from schedule.".format(name), + "comment": f"Failed to delete job {name} from schedule.", "result": False, "changes": {}, } @@ -350,7 +348,7 @@ def delete(name, **kwargs): ret["comment"] = "Job name is required." if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Job: {} would be deleted from schedule.".format(name) + ret["comment"] = f"Job: {name} would be deleted from schedule." ret["result"] = True else: if kwargs.get("offline"): @@ -379,7 +377,7 @@ def delete(name, **kwargs): ) ret["result"] = True - ret["comment"] = "Deleted Job {} from schedule.".format(name) + ret["comment"] = f"Deleted Job {name} from schedule." ret["changes"][name] = "removed" else: persist = kwargs.get("persist", True) @@ -404,7 +402,7 @@ def delete(name, **kwargs): "persist": False, } else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." return ret try: @@ -588,7 +586,7 @@ def add(name, **kwargs): """ ret = { - "comment": "Failed to add job {} to schedule.".format(name), + "comment": f"Failed to add job {name} to schedule.", "result": False, "changes": {}, } @@ -597,7 +595,7 @@ def add(name, **kwargs): ) if name in current_schedule: - ret["comment"] = "Job {} already exists in schedule.".format(name) + ret["comment"] = f"Job {name} already exists in schedule." ret["result"] = False return ret @@ -633,7 +631,7 @@ def add(name, **kwargs): schedule_data[name] = _new if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Job: {} would be added to schedule.".format(name) + ret["comment"] = f"Job: {name} would be added to schedule." ret["result"] = True else: if kwargs.get("offline"): @@ -655,7 +653,7 @@ def add(name, **kwargs): ) ret["result"] = True - ret["comment"] = "Added job: {} to schedule.".format(name) + ret["comment"] = f"Added job: {name} to schedule." ret["changes"][name] = "added" else: try: @@ -732,7 +730,7 @@ def modify(name, **kwargs): ) if name not in current_schedule: - ret["comment"] = "Job {} does not exist in schedule.".format(name) + ret["comment"] = f"Job {name} does not exist in schedule." ret["result"] = False return ret @@ -755,7 +753,7 @@ def modify(name, **kwargs): return _new if _new == _current: - ret["comment"] = "Job {} in correct state".format(name) + ret["comment"] = f"Job {name} in correct state" return ret ret["changes"][name] = { @@ -764,7 +762,7 @@ def modify(name, **kwargs): } if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Job: {} would be modified in schedule.".format(name) + ret["comment"] = f"Job: {name} would be modified in schedule." else: if kwargs.get("offline"): current_schedule[name].update(_new) @@ -785,7 +783,7 @@ def modify(name, **kwargs): ) ret["result"] = True - ret["comment"] = "Modified job: {} in schedule.".format(name) + ret["comment"] = f"Modified job: {name} in schedule." else: persist = kwargs.get("persist", True) @@ -807,9 +805,9 @@ def modify(name, **kwargs): out = __salt__["event.fire"](event_data, "manage_schedule") if out: - ret["comment"] = "Modified job: {} in schedule.".format(name) + ret["comment"] = f"Modified job: {name} in schedule." else: - ret["comment"] = "Failed to modify job {} in schedule.".format(name) + ret["comment"] = f"Failed to modify job {name} in schedule." ret["result"] = False return ret @@ -838,18 +836,18 @@ def run_job(name, force=False): if name in schedule: data = schedule[name] if "enabled" in data and not data["enabled"] and not force: - ret["comment"] = "Job {} is disabled.".format(name) + ret["comment"] = f"Job {name} is disabled." else: out = __salt__["event.fire"]( {"name": name, "func": "run_job"}, "manage_schedule" ) if out: - ret["comment"] = "Scheduling Job {} on minion.".format(name) + ret["comment"] = f"Scheduling Job {name} on minion." else: - ret["comment"] = "Failed to run job {} on minion.".format(name) + ret["comment"] = f"Failed to run job {name} on minion." ret["result"] = False else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret @@ -872,7 +870,7 @@ def enable_job(name, **kwargs): ret["result"] = False if "test" in __opts__ and __opts__["test"]: - ret["comment"] = "Job: {} would be enabled in schedule.".format(name) + ret["comment"] = f"Job: {name} would be enabled in schedule." else: persist = kwargs.get("persist", True) @@ -886,7 +884,7 @@ def enable_job(name, **kwargs): "persist": False, } else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret @@ -903,13 +901,11 @@ def enable_job(name, **kwargs): # check item exists in schedule and is enabled if name in schedule and schedule[name]["enabled"]: ret["result"] = True - ret["comment"] = "Enabled Job {} in schedule.".format(name) + ret["comment"] = f"Enabled Job {name} in schedule." ret["changes"][name] = "enabled" else: ret["result"] = False - ret["comment"] = ( - "Failed to enable job {} in schedule.".format(name) - ) + ret["comment"] = f"Failed to enable job {name} in schedule." return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -935,7 +931,7 @@ def disable_job(name, **kwargs): ret["result"] = False if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Job: {} would be disabled in schedule.".format(name) + ret["comment"] = f"Job: {name} would be disabled in schedule." else: persist = kwargs.get("persist", True) @@ -949,7 +945,7 @@ def disable_job(name, **kwargs): "persist": False, } else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret @@ -966,12 +962,12 @@ def disable_job(name, **kwargs): # check item exists in schedule and is enabled if name in schedule and not schedule[name]["enabled"]: ret["result"] = True - ret["comment"] = "Disabled Job {} in schedule.".format(name) + ret["comment"] = f"Disabled Job {name} in schedule." ret["changes"][name] = "disabled" else: ret["result"] = False ret["comment"] = ( - "Failed to disable job {} in schedule.".format(name) + f"Failed to disable job {name} in schedule." ) return ret except KeyError: @@ -1137,9 +1133,7 @@ def reload_(): try: schedule = salt.utils.yaml.safe_load(fp_) except salt.utils.yaml.YAMLError as exc: - ret["comment"].append( - "Unable to read existing schedule file: {}".format(exc) - ) + ret["comment"].append(f"Unable to read existing schedule file: {exc}") if schedule: if "schedule" in schedule and schedule["schedule"]: @@ -1187,7 +1181,7 @@ def move(name, target, **kwargs): ret["result"] = False if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Job: {} would be moved from schedule.".format(name) + ret["comment"] = f"Job: {name} would be moved from schedule." else: opts_schedule = list_(show_all=True, where="opts", return_yaml=False) pillar_schedule = list_(show_all=True, where="pillar", return_yaml=False) @@ -1199,13 +1193,13 @@ def move(name, target, **kwargs): schedule_data = pillar_schedule[name] where = "pillar" else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret schedule_opts = [] for key, value in schedule_data.items(): - temp = "{}={}".format(key, value) + temp = f"{key}={value}" schedule_opts.append(temp) response = __salt__["publish.publish"](target, "schedule.add", schedule_opts) @@ -1228,7 +1222,7 @@ def move(name, target, **kwargs): else: delete(name, where=where) ret["result"] = True - ret["comment"] = "Moved Job {} from schedule.".format(name) + ret["comment"] = f"Moved Job {name} from schedule." ret["minions"] = minions return ret return ret @@ -1252,7 +1246,7 @@ def copy(name, target, **kwargs): ret["result"] = False if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Job: {} would be copied from schedule.".format(name) + ret["comment"] = f"Job: {name} would be copied from schedule." else: opts_schedule = list_(show_all=True, where="opts", return_yaml=False) pillar_schedule = list_(show_all=True, where="pillar", return_yaml=False) @@ -1262,13 +1256,13 @@ def copy(name, target, **kwargs): elif name in pillar_schedule: schedule_data = pillar_schedule[name] else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret schedule_opts = [] for key, value in schedule_data.items(): - temp = "{}={}".format(key, value) + temp = f"{key}={value}" schedule_opts.append(temp) response = __salt__["publish.publish"](target, "schedule.add", schedule_opts) @@ -1290,7 +1284,7 @@ def copy(name, target, **kwargs): return ret else: ret["result"] = True - ret["comment"] = "Copied Job {} from schedule to minion(s).".format(name) + ret["comment"] = f"Copied Job {name} from schedule to minion(s)." ret["minions"] = minions return ret return ret @@ -1353,7 +1347,7 @@ def postpone_job(name, current_time, new_time, **kwargs): return ret if "test" in __opts__ and __opts__["test"]: - ret["comment"] = "Job: {} would be postponed in schedule.".format(name) + ret["comment"] = f"Job: {name} would be postponed in schedule." else: if name in list_(show_all=True, where="opts", return_yaml=False): @@ -1374,7 +1368,7 @@ def postpone_job(name, current_time, new_time, **kwargs): "func": "postpone_job", } else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret @@ -1397,7 +1391,7 @@ def postpone_job(name, current_time, new_time, **kwargs): else: ret["result"] = False ret["comment"] = ( - "Failed to postpone job {} in schedule.".format(name) + f"Failed to postpone job {name} in schedule." ) return ret except KeyError: @@ -1444,7 +1438,7 @@ def skip_job(name, current_time, **kwargs): return ret if "test" in __opts__ and __opts__["test"]: - ret["comment"] = "Job: {} would be skipped in schedule.".format(name) + ret["comment"] = f"Job: {name} would be skipped in schedule." else: if name in list_(show_all=True, where="opts", return_yaml=False): @@ -1463,7 +1457,7 @@ def skip_job(name, current_time, **kwargs): "func": "skip_job", } else: - ret["comment"] = "Job {} does not exist.".format(name) + ret["comment"] = f"Job {name} does not exist." ret["result"] = False return ret @@ -1485,9 +1479,7 @@ def skip_job(name, current_time, **kwargs): ) else: ret["result"] = False - ret["comment"] = ( - "Failed to skip job {} in schedule.".format(name) - ) + ret["comment"] = f"Failed to skip job {name} in schedule." return ret except KeyError: # Effectively a no-op, since we can't really return without an event system diff --git a/salt/modules/scsi.py b/salt/modules/scsi.py index e405865806a..83a3e8b169d 100644 --- a/salt/modules/scsi.py +++ b/salt/modules/scsi.py @@ -47,7 +47,7 @@ def ls_(get_size=True): __context__["retcode"] = rc error = res.get("stderr", "").split("\n")[0] if error == "lsscsi: invalid option -- 's'": - return "{} - try get_size=False".format(error) + return f"{error} - try get_size=False" return res.get("stderr", "").split("\n")[0] data = res.get("stdout", "") @@ -93,8 +93,8 @@ def rescan_all(host): salt '*' scsi.rescan_all 0 """ - if os.path.isdir("/sys/class/scsi_host/host{}".format(host)): - cmd = 'echo "- - -" > /sys/class/scsi_host/host{}/scan'.format(host) + if os.path.isdir(f"/sys/class/scsi_host/host{host}"): + cmd = f'echo "- - -" > /sys/class/scsi_host/host{host}/scan' else: - return "Host {} does not exist".format(host) + return f"Host {host} does not exist" return __salt__["cmd.run"](cmd).splitlines() diff --git a/salt/modules/seed.py b/salt/modules/seed.py index 9bce998fd38..657c7bccd64 100644 --- a/salt/modules/seed.py +++ b/salt/modules/seed.py @@ -41,7 +41,7 @@ def prep_bootstrap(mpt): """ # Verify that the boostrap script is downloaded bs_ = __salt__["config.gather_bootstrap_script"]() - fpd_ = os.path.join(mpt, "tmp", "{}".format(uuid.uuid4())) + fpd_ = os.path.join(mpt, "tmp", f"{uuid.uuid4()}") if not os.path.exists(fpd_): os.makedirs(fpd_) os.chmod(fpd_, 0o700) @@ -135,7 +135,7 @@ def apply_( """ stats = __salt__["file.stats"](path, follow_symlinks=True) if not stats: - return "{} does not exist".format(path) + return f"{path} does not exist" ftype = stats["type"] path = stats["target"] log.debug("Mounting %s at %s", ftype, path) @@ -148,7 +148,7 @@ def apply_( mpt = _mount(path, ftype, mount_point) if not mpt: - return "{} could not be mounted".format(path) + return f"{path} could not be mounted" tmp = os.path.join(mpt, "tmp") log.debug("Attempting to create directory %s", tmp) @@ -299,6 +299,6 @@ def _check_install(root): sh_ = "/bin/bash" cmd = "if ! type salt-minion; then exit 1; fi" - cmd = "chroot '{}' {} -c '{}'".format(root, sh_, cmd) + cmd = f"chroot '{root}' {sh_} -c '{cmd}'" return not __salt__["cmd.retcode"](cmd, output_loglevel="quiet", python_shell=True) diff --git a/salt/modules/selinux.py b/salt/modules/selinux.py index 71dae99a7a0..da7d0bc3bee 100644 --- a/salt/modules/selinux.py +++ b/salt/modules/selinux.py @@ -142,14 +142,14 @@ def setenforce(mode): mode = "0" modestring = "disabled" else: - return "Invalid mode {}".format(mode) + return f"Invalid mode {mode}" elif isinstance(mode, int): if mode: mode = "1" else: mode = "0" else: - return "Invalid mode {}".format(mode) + return f"Invalid mode {mode}" # enforce file does not exist if currently disabled. Only for toggling enforcing/permissive if getenforce() != "Disabled": @@ -203,9 +203,9 @@ def setsebool(boolean, value, persist=False): salt '*' selinux.setsebool virt_use_usb off """ if persist: - cmd = "setsebool -P {} {}".format(boolean, value) + cmd = f"setsebool -P {boolean} {value}" else: - cmd = "setsebool {} {}".format(boolean, value) + cmd = f"setsebool {boolean} {value}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -226,7 +226,7 @@ def setsebools(pairs, persist=False): else: cmd = "setsebool " for boolean, value in pairs.items(): - cmd = "{} {}={}".format(cmd, boolean, value) + cmd = f"{cmd} {boolean}={value}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -283,9 +283,9 @@ def setsemod(module, state): .. versionadded:: 2016.3.0 """ if state.lower() == "enabled": - cmd = "semodule -e {}".format(module) + cmd = f"semodule -e {module}" elif state.lower() == "disabled": - cmd = "semodule -d {}".format(module) + cmd = f"semodule -d {module}" return not __salt__["cmd.retcode"](cmd) @@ -303,7 +303,7 @@ def install_semod(module_path): """ if module_path.find("salt://") == 0: module_path = __salt__["cp.cache_file"](module_path) - cmd = "semodule -i {}".format(module_path) + cmd = f"semodule -i {module_path}" return not __salt__["cmd.retcode"](cmd) @@ -319,7 +319,7 @@ def remove_semod(module): .. versionadded:: 2016.11.6 """ - cmd = "semodule -r {}".format(module) + cmd = f"semodule -r {module}" return not __salt__["cmd.retcode"](cmd) @@ -375,7 +375,7 @@ def _validate_filetype(filetype): specification. Throws an SaltInvocationError if it isn't. """ if filetype not in _SELINUX_FILETYPES: - raise SaltInvocationError("Invalid filetype given: {}".format(filetype)) + raise SaltInvocationError(f"Invalid filetype given: {filetype}") return True @@ -393,7 +393,7 @@ def _parse_protocol_port(name, protocol, port): protocol_port_pattern = r"^(tcp|udp)\/(([\d]+)\-?[\d]+)$" name_parts = re.match(protocol_port_pattern, name) if not name_parts: - name_parts = re.match(protocol_port_pattern, "{}/{}".format(protocol, port)) + name_parts = re.match(protocol_port_pattern, f"{protocol}/{port}") if not name_parts: raise SaltInvocationError( 'Invalid name "{}" format and protocol and port not provided or invalid:' @@ -851,15 +851,15 @@ def _port_add_or_delete_policy( """ if action not in ["add", "delete"]: raise SaltInvocationError( - 'Actions supported are "add" and "delete", not "{}".'.format(action) + f'Actions supported are "add" and "delete", not "{action}".' ) if action == "add" and not sel_type: raise SaltInvocationError("SELinux Type is required to add a policy") (protocol, port) = _parse_protocol_port(name, protocol, port) - cmd = "semanage port --{} --proto {}".format(action, protocol) + cmd = f"semanage port --{action} --proto {protocol}" if sel_type: - cmd += " --type {}".format(sel_type) + cmd += f" --type {sel_type}" if sel_range: - cmd += " --range {}".format(sel_range) - cmd += " {}".format(port) + cmd += f" --range {sel_range}" + cmd += f" {port}" return __salt__["cmd.run_all"](cmd) diff --git a/salt/modules/sensors.py b/salt/modules/sensors.py index b96c3a32a4c..53b1970bf8f 100644 --- a/salt/modules/sensors.py +++ b/salt/modules/sensors.py @@ -42,7 +42,7 @@ def sense(chip, fahrenheit=False): if fahrenheit is True: extra_args = "-f" sensors = __salt__["cmd.run"]( - "/usr/bin/sensors {} {}".format(chip, extra_args), python_shell=False + f"/usr/bin/sensors {chip} {extra_args}", python_shell=False ).splitlines() ret = {} for sensor in sensors: diff --git a/salt/modules/serverdensity_device.py b/salt/modules/serverdensity_device.py index 23c228ea706..741e2c52b68 100644 --- a/salt/modules/serverdensity_device.py +++ b/salt/modules/serverdensity_device.py @@ -48,14 +48,14 @@ def get_sd_auth(val, sd_auth_pillar_name="serverdensity"): if not sd_pillar: log.error("Could not load %s pillar", sd_auth_pillar_name) raise CommandExecutionError( - "{} pillar is required for authentication".format(sd_auth_pillar_name) + f"{sd_auth_pillar_name} pillar is required for authentication" ) try: return sd_pillar[val] except KeyError: log.error("Could not find value %s in pillar", val) - raise CommandExecutionError("{} value was not found in pillar".format(val)) + raise CommandExecutionError(f"{val} value was not found in pillar") def _clean_salt_variables(params, variable_prefix="__"): @@ -98,7 +98,7 @@ def create(name, **params): except ValueError: log.error("Could not parse API Response content: %s", api_response.content) raise CommandExecutionError( - "Failed to create, API Response: {}".format(api_response) + f"Failed to create, API Response: {api_response}" ) else: return None @@ -130,7 +130,7 @@ def delete(device_id): except ValueError: log.error("Could not parse API Response content: %s", api_response.content) raise CommandExecutionError( - "Failed to create, API Response: {}".format(api_response) + f"Failed to create, API Response: {api_response}" ) else: return None @@ -167,7 +167,7 @@ def ls(**params): params[key] = str(val) api_response = requests.get( - "https://api.serverdensity.io/inventory/{}".format(endpoint), + f"https://api.serverdensity.io/inventory/{endpoint}", params={ "token": get_sd_auth("api_token"), "filter": salt.utils.json.dumps(params), @@ -185,7 +185,7 @@ def ls(**params): api_response.content, ) raise CommandExecutionError( - "Failed to create, Server Density API Response: {}".format(api_response) + f"Failed to create, Server Density API Response: {api_response}" ) else: return None @@ -224,7 +224,7 @@ def update(device_id, **params): api_response.content, ) raise CommandExecutionError( - "Failed to create, API Response: {}".format(api_response) + f"Failed to create, API Response: {api_response}" ) else: return None @@ -258,10 +258,8 @@ def install_agent(agent_key, agent_version=1): account = get_sd_auth(account_field) - __salt__["cmd.run"]( - cmd="curl -L {} -o {}".format(url, install_filename), cwd=work_dir - ) - __salt__["cmd.run"](cmd="chmod +x {}".format(install_filename), cwd=work_dir) + __salt__["cmd.run"](cmd=f"curl -L {url} -o {install_filename}", cwd=work_dir) + __salt__["cmd.run"](cmd=f"chmod +x {install_filename}", cwd=work_dir) return __salt__["cmd.run"]( cmd="{filename} -a {account} -k {agent_key}".format( diff --git a/salt/modules/servicenow.py b/salt/modules/servicenow.py index 5ac48ee72c6..04cff9cb6b6 100644 --- a/salt/modules/servicenow.py +++ b/salt/modules/servicenow.py @@ -137,7 +137,7 @@ def non_structured_query(table, query=None, **kwargs): # try and assemble a query by keyword query_parts = [] for key, value in kwargs.items(): - query_parts.append("{}={}".format(key, value)) + query_parts.append(f"{key}={value}") query = "^".join(query_parts) query = str(query) response = client.get(query) diff --git a/salt/modules/slack_notify.py b/salt/modules/slack_notify.py index 9ac29929bd6..b82367176e8 100644 --- a/salt/modules/slack_notify.py +++ b/salt/modules/slack_notify.py @@ -204,7 +204,7 @@ def post_message( channel, channel, ) - channel = "#{}".format(channel) + channel = f"#{channel}" if not from_name: log.error("from_name is a required option.") diff --git a/salt/modules/slackware_service.py b/salt/modules/slackware_service.py index 54bc3c2a77f..67948539d38 100644 --- a/salt/modules/slackware_service.py +++ b/salt/modules/slackware_service.py @@ -46,7 +46,7 @@ def start(name): salt '*' service.start """ - cmd = "/bin/sh {}.{} start".format(prefix, name) + cmd = f"/bin/sh {prefix}.{name} start" return not __salt__["cmd.retcode"](cmd) @@ -62,7 +62,7 @@ def stop(name): salt '*' service.stop """ - cmd = "/bin/sh {}.{} stop".format(prefix, name) + cmd = f"/bin/sh {prefix}.{name} stop" return not __salt__["cmd.retcode"](cmd) @@ -78,7 +78,7 @@ def restart(name): salt '*' service.restart """ - cmd = "/bin/sh {}.{} restart".format(prefix, name) + cmd = f"/bin/sh {prefix}.{name} restart" return not __salt__["cmd.retcode"](cmd) @@ -94,7 +94,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "/bin/sh {}.{} reload".format(prefix, name) + cmd = f"/bin/sh {prefix}.{name} reload" return not __salt__["cmd.retcode"](cmd) @@ -110,7 +110,7 @@ def force_reload(name): salt '*' service.force_reload """ - cmd = "/bin/sh {}.{} forcereload".format(prefix, name) + cmd = f"/bin/sh {prefix}.{name} forcereload" return not __salt__["cmd.retcode"](cmd) @@ -146,7 +146,7 @@ def status(name, sig=None): services = [name] results = {} for service in services: - cmd = "/bin/sh {}.{} status".format(prefix, service) + cmd = f"/bin/sh {prefix}.{service} status" results[service] = not __salt__["cmd.retcode"](cmd, ignore_retcode=True) if contains_globbing: return results @@ -179,7 +179,7 @@ def _get_svc_list(service_status): ) ) ret = set() - lines = glob.glob("{}.*".format(prefix)) + lines = glob.glob(f"{prefix}.*") for line in lines: if not notservice.match(line): svc = _get_svc(line, service_status) @@ -328,7 +328,7 @@ def enabled(name, **kwargs): salt '*' service.enabled """ ret = True - if _get_svc("{}.{}".format(prefix, name), "ON") is None: + if _get_svc(f"{prefix}.{name}", "ON") is None: ret = False return ret @@ -346,6 +346,6 @@ def disabled(name): salt '*' service.disabled """ ret = True - if _get_svc("{}.{}".format(prefix, name), "OFF") is None: + if _get_svc(f"{prefix}.{name}", "OFF") is None: ret = False return ret diff --git a/salt/modules/slsutil.py b/salt/modules/slsutil.py index df78b727f79..cf8afa76c37 100644 --- a/salt/modules/slsutil.py +++ b/salt/modules/slsutil.py @@ -181,7 +181,7 @@ def renderer(path=None, string=None, default_renderer="jinja|yaml", **kwargs): default_renderer, __opts__["renderer_blacklist"], __opts__["renderer_whitelist"], - **kwargs + **kwargs, ) return ret.read() if __utils__["stringio.is_readable"](ret) else ret @@ -193,12 +193,12 @@ def _get_serialize_fn(serializer, fn_name): if not fns: raise salt.exceptions.CommandExecutionError( - "Serializer '{}' not found.".format(serializer) + f"Serializer '{serializer}' not found." ) if not fn: raise salt.exceptions.CommandExecutionError( - "Serializer '{}' does not implement {}.".format(serializer, fn_name) + f"Serializer '{serializer}' does not implement {fn_name}." ) return fn @@ -570,7 +570,7 @@ def findup(startpath, filenames, saltenv="base"): # Verify the cwd is a valid path in the state tree if startpath and not path_exists(startpath, saltenv): raise salt.exceptions.SaltInvocationError( - "Starting path not found in the state tree: {}".format(startpath) + f"Starting path not found in the state tree: {startpath}" ) # Ensure that patterns is a string or list of strings diff --git a/salt/modules/smartos_imgadm.py b/salt/modules/smartos_imgadm.py index cfa74f055bc..8fe64d34830 100644 --- a/salt/modules/smartos_imgadm.py +++ b/salt/modules/smartos_imgadm.py @@ -29,7 +29,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on SmartOS compute nodes".format(__virtualname__), + f"{__virtualname__} module can only be loaded on SmartOS compute nodes", ) @@ -73,7 +73,7 @@ def _parse_image_meta(image=None, detail=False): docker_repo = image["manifest"]["tags"][tag] if docker_repo and docker_tag: - name = "{}:{}".format(docker_repo, docker_tag) + name = f"{docker_repo}:{docker_tag}" description = ( "Docker image imported from {repo}:{tag} on {date}.".format( repo=docker_repo, @@ -186,7 +186,7 @@ def update_installed(uuid=""): salt '*' imgadm.update [uuid] """ - cmd = "imgadm update {}".format(uuid).rstrip() + cmd = f"imgadm update {uuid}".rstrip() __salt__["cmd.run"](cmd) return {} @@ -282,7 +282,7 @@ def show(uuid): ret = {} if _is_uuid(uuid) or _is_docker_uuid(uuid): - cmd = "imgadm show {}".format(uuid) + cmd = f"imgadm show {uuid}" res = __salt__["cmd.run_all"](cmd, python_shell=False) retcode = res["retcode"] if retcode != 0: @@ -290,7 +290,7 @@ def show(uuid): else: ret = salt.utils.json.loads(res["stdout"]) else: - ret["Error"] = "{} is not a valid uuid.".format(uuid) + ret["Error"] = f"{uuid} is not a valid uuid." return ret @@ -315,7 +315,7 @@ def get(uuid): uuid = docker_to_uuid(uuid) if _is_uuid(uuid): - cmd = "imgadm get {}".format(uuid) + cmd = f"imgadm get {uuid}" res = __salt__["cmd.run_all"](cmd, python_shell=False) retcode = res["retcode"] if retcode != 0: @@ -323,7 +323,7 @@ def get(uuid): else: ret = salt.utils.json.loads(res["stdout"]) else: - ret["Error"] = "{} is not a valid uuid.".format(uuid) + ret["Error"] = f"{uuid} is not a valid uuid." return ret @@ -344,7 +344,7 @@ def import_image(uuid, verbose=False): salt '*' imgadm.import e42f8c84-bbea-11e2-b920-078fab2aab1f [verbose=True] """ ret = {} - cmd = "imgadm import {}".format(uuid) + cmd = f"imgadm import {uuid}" res = __salt__["cmd.run_all"](cmd, python_shell=False) retcode = res["retcode"] if retcode != 0: @@ -370,7 +370,7 @@ def delete(uuid): salt '*' imgadm.delete e42f8c84-bbea-11e2-b920-078fab2aab1f """ ret = {} - cmd = "imgadm delete {}".format(uuid) + cmd = f"imgadm delete {uuid}" res = __salt__["cmd.run_all"](cmd, python_shell=False) retcode = res["retcode"] if retcode != 0: @@ -468,7 +468,7 @@ def source_delete(source): salt '*' imgadm.source_delete https://updates.joyent.com """ ret = {} - cmd = "imgadm sources -d {}".format(source) + cmd = f"imgadm sources -d {source}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -503,7 +503,7 @@ def source_add(source, source_type="imgapi"): if source_type not in ["imgapi", "docker"]: log.warning("Possible unsupported imgage source type specified!") - cmd = "imgadm sources -a {} -t {}".format(source, source_type) + cmd = f"imgadm sources -a {source} -t {source_type}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: diff --git a/salt/modules/smartos_nictagadm.py b/salt/modules/smartos_nictagadm.py index 9112b44efa9..fb67c9602b3 100644 --- a/salt/modules/smartos_nictagadm.py +++ b/salt/modules/smartos_nictagadm.py @@ -35,7 +35,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on SmartOS compute nodes".format(__virtualname__), + f"{__virtualname__} module can only be loaded on SmartOS compute nodes", ) @@ -86,7 +86,7 @@ def vms(nictag): salt '*' nictagadm.vms admin """ ret = {} - cmd = "nictagadm vms {}".format(nictag) + cmd = f"nictagadm vms {nictag}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -157,13 +157,13 @@ def add(name, mac, mtu=1500): res = __salt__["cmd.run_all"](cmd) # dladm prints '00' as '0', so account for that. if mac.replace("00", "0") not in res["stdout"].splitlines(): - return {"Error": "{} is not present on this system.".format(mac)} + return {"Error": f"{mac} is not present on this system."} if mac == "etherstub": - cmd = "nictagadm add -l {}".format(name) + cmd = f"nictagadm add -l {name}" res = __salt__["cmd.run_all"](cmd) else: - cmd = "nictagadm add -p mtu={},mac={} {}".format(mtu, mac, name) + cmd = f"nictagadm add -p mtu={mtu},mac={mac} {name}" res = __salt__["cmd.run_all"](cmd) if res["retcode"] == 0: @@ -198,7 +198,7 @@ def update(name, mac=None, mtu=None): ret = {} if name not in list_nictags(): - return {"Error": "nictag {} does not exists.".format(name)} + return {"Error": f"nictag {name} does not exists."} if not mtu and not mac: return {"Error": "please provide either mac or/and mtu."} if mtu: @@ -212,16 +212,16 @@ def update(name, mac=None, mtu=None): res = __salt__["cmd.run_all"](cmd) # dladm prints '00' as '0', so account for that. if mac.replace("00", "0") not in res["stdout"].splitlines(): - return {"Error": "{} is not present on this system.".format(mac)} + return {"Error": f"{mac} is not present on this system."} if mac and mtu: - properties = "mtu={},mac={}".format(mtu, mac) + properties = f"mtu={mtu},mac={mac}" elif mac: - properties = "mac={}".format(mac) if mac else "" + properties = f"mac={mac}" if mac else "" elif mtu: - properties = "mtu={}".format(mtu) if mtu else "" + properties = f"mtu={mtu}" if mtu else "" - cmd = "nictagadm update -p {} {}".format(properties, name) + cmd = f"nictagadm update -p {properties} {name}" res = __salt__["cmd.run_all"](cmd) if res["retcode"] == 0: diff --git a/salt/modules/smartos_virt.py b/salt/modules/smartos_virt.py index 2f29fcefd5f..54aa8841822 100644 --- a/salt/modules/smartos_virt.py +++ b/salt/modules/smartos_virt.py @@ -22,7 +22,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on SmartOS compute nodes".format(__virtualname__), + f"{__virtualname__} module can only be loaded on SmartOS compute nodes", ) @@ -185,9 +185,7 @@ def vm_virt_type(domain): salt '*' virt.vm_virt_type """ - ret = __salt__["vmadm.lookup"]( - search="uuid={uuid}".format(uuid=domain), order="type" - ) + ret = __salt__["vmadm.lookup"](search=f"uuid={domain}", order="type") if not ret: raise CommandExecutionError("We can't determine the type of this VM") @@ -232,9 +230,7 @@ def get_macs(domain): salt '*' virt.get_macs """ macs = [] - ret = __salt__["vmadm.lookup"]( - search="uuid={uuid}".format(uuid=domain), order="nics" - ) + ret = __salt__["vmadm.lookup"](search=f"uuid={domain}", order="nics") if not ret: raise CommandExecutionError("We can't find the MAC address of this VM") else: diff --git a/salt/modules/smartos_vmadm.py b/salt/modules/smartos_vmadm.py index 308d41d0294..5a88d1bacfc 100644 --- a/salt/modules/smartos_vmadm.py +++ b/salt/modules/smartos_vmadm.py @@ -35,7 +35,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on SmartOS compute nodes".format(__virtualname__), + f"{__virtualname__} module can only be loaded on SmartOS compute nodes", ) @@ -57,7 +57,7 @@ def _create_update_from_file(mode="create", uuid=None, path=None): """ ret = {} if not os.path.isfile(path) or path is None: - ret["Error"] = "File ({}) does not exists!".format(path) + ret["Error"] = f"File ({path}) does not exists!" return ret # vmadm validate create|update [-f ] cmd = "vmadm validate {mode} {brand} -f {path}".format( @@ -171,7 +171,7 @@ def start(vm, options=None, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm start [option=value ...] @@ -210,7 +210,7 @@ def stop(vm, force=False, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm stop [-F] @@ -247,7 +247,7 @@ def reboot(vm, force=False, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm reboot [-F] @@ -286,8 +286,8 @@ def list_vms(search=None, sort=None, order="uuid,type,ram,state,alias", keyed=Tr ret = {} # vmadm list [-p] [-H] [-o field,...] [-s field,...] [field=value ...] cmd = "vmadm list -p -H {order} {sort} {search}".format( - order="-o {}".format(order) if order else "", - sort="-s {}".format(sort) if sort else "", + order=f"-o {order}" if order else "", + sort=f"-s {sort}" if sort else "", search=search if search else "", ) res = __salt__["cmd.run_all"](cmd) @@ -341,7 +341,7 @@ def lookup(search=None, order=None, one=False): # vmadm lookup [-j|-1] [-o field,...] [field=value ...] cmd = "vmadm lookup {one} {order} {search}".format( one="-1" if one else "-j", - order="-o {}".format(order) if order else "", + order=f"-o {order}" if order else "", search=search if search else "", ) res = __salt__["cmd.run_all"](cmd) @@ -386,11 +386,11 @@ def sysrq(vm, action="nmi", key="uuid"): if action not in ["nmi", "screenshot"]: ret["Error"] = "Action must be either nmi or screenshot" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm sysrq - cmd = "vmadm sysrq {uuid} {action}".format(uuid=vm, action=action) + cmd = f"vmadm sysrq {vm} {action}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -419,11 +419,11 @@ def delete(vm, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm delete - cmd = "vmadm delete {}".format(vm) + cmd = f"vmadm delete {vm}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -452,11 +452,11 @@ def get(vm, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm get - cmd = "vmadm get {}".format(vm) + cmd = f"vmadm get {vm}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -503,11 +503,11 @@ def info(vm, info_type="all", key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm info [type,...] - cmd = "vmadm info {uuid} {type}".format(uuid=vm, type=info_type) + cmd = f"vmadm info {vm} {info_type}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -541,7 +541,7 @@ def create_snapshot(vm, name, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm vmobj = get(vm) @@ -555,7 +555,7 @@ def create_snapshot(vm, name, key="uuid"): ret["Error"] = "VM must be running to take a snapshot" return ret # vmadm create-snapshot - cmd = "vmadm create-snapshot {uuid} {snapshot}".format(snapshot=name, uuid=vm) + cmd = f"vmadm create-snapshot {vm} {name}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -589,7 +589,7 @@ def delete_snapshot(vm, name, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm vmobj = get(vm) @@ -600,7 +600,7 @@ def delete_snapshot(vm, name, key="uuid"): ret["Error"] = "VM must be of type OS" return ret # vmadm delete-snapshot - cmd = "vmadm delete-snapshot {uuid} {snapshot}".format(snapshot=name, uuid=vm) + cmd = f"vmadm delete-snapshot {vm} {name}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -634,7 +634,7 @@ def rollback_snapshot(vm, name, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm vmobj = get(vm) @@ -645,7 +645,7 @@ def rollback_snapshot(vm, name, key="uuid"): ret["Error"] = "VM must be of type OS" return ret # vmadm rollback-snapshot - cmd = "vmadm rollback-snapshot {uuid} {snapshot}".format(snapshot=name, uuid=vm) + cmd = f"vmadm rollback-snapshot {vm} {name}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: @@ -676,11 +676,11 @@ def reprovision(vm, image, key="uuid"): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm if image not in __salt__["imgadm.list"](): - ret["Error"] = "Image ({}) is not present on this host".format(image) + ret["Error"] = f"Image ({image}) is not present on this host" return ret # vmadm reprovision [-f ] cmd = "echo {image} | vmadm reprovision {uuid}".format( @@ -755,7 +755,7 @@ def update(vm, from_file=None, key="uuid", **kwargs): if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret - uuid = lookup("{}={}".format(key, vm), one=True) + uuid = lookup(f"{key}={vm}", one=True) if "Error" in uuid: return uuid @@ -790,12 +790,12 @@ def send(vm, target, key="uuid"): if not os.path.isdir(target): ret["Error"] = "Target must be a directory or host" return ret - vm = lookup("{}={}".format(key, vm), one=True) + vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm send [target] cmd = "vmadm send {uuid} > {target}".format( - uuid=vm, target=os.path.join(target, "{}.vmdata".format(vm)) + uuid=vm, target=os.path.join(target, f"{vm}.vmdata") ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] @@ -812,7 +812,7 @@ def send(vm, target, key="uuid"): name = name[-1] cmd = "zfs send {dataset} > {target}".format( dataset=dataset, - target=os.path.join(target, "{}-{}.zfsds".format(vm, name)), + target=os.path.join(target, f"{vm}-{name}.zfsds"), ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] @@ -841,12 +841,12 @@ def receive(uuid, source): if not os.path.isdir(source): ret["Error"] = "Source must be a directory or host" return ret - if not os.path.exists(os.path.join(source, "{}.vmdata".format(uuid))): - ret["Error"] = "Unknow vm with uuid in {}".format(source) + if not os.path.exists(os.path.join(source, f"{uuid}.vmdata")): + ret["Error"] = f"Unknow vm with uuid in {source}" return ret # vmadm receive cmd = "vmadm receive < {source}".format( - source=os.path.join(source, "{}.vmdata".format(uuid)) + source=os.path.join(source, f"{uuid}.vmdata") ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] @@ -863,14 +863,14 @@ def receive(uuid, source): name = name[-1] cmd = "zfs receive {dataset} < {source}".format( dataset=dataset, - source=os.path.join(source, "{}-{}.zfsds".format(uuid, name)), + source=os.path.join(source, f"{uuid}-{name}.zfsds"), ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret - cmd = "vmadm install {}".format(uuid) + cmd = f"vmadm install {uuid}" res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0 and not res["stderr"].endswith("datasets"): diff --git a/salt/modules/smbios.py b/salt/modules/smbios.py index b27a2aeb2d3..9e6f7192ac0 100644 --- a/salt/modules/smbios.py +++ b/salt/modules/smbios.py @@ -75,7 +75,7 @@ def get(string, clean=True): salt '*' smbios.get system-uuid clean=False """ - val = _dmidecoder("-s {}".format(string)).strip() + val = _dmidecoder(f"-s {string}").strip() # Cleanup possible comments in strings. val = "\n".join([v for v in val.split("\n") if not v.startswith("#")]) @@ -158,7 +158,7 @@ def records(rec_type=None, fields=None, clean=True): if rec_type is None: smbios = _dmi_parse(_dmidecoder(), clean, fields) else: - smbios = _dmi_parse(_dmidecoder("-t {}".format(rec_type)), clean, fields) + smbios = _dmi_parse(_dmidecoder(f"-t {rec_type}"), clean, fields) return smbios @@ -334,6 +334,6 @@ def _dmidecoder(args=None): if not args: out = salt.modules.cmdmod._run_quiet(dmidecoder) else: - out = salt.modules.cmdmod._run_quiet("{} {}".format(dmidecoder, args)) + out = salt.modules.cmdmod._run_quiet(f"{dmidecoder} {args}") return out diff --git a/salt/modules/smf_service.py b/salt/modules/smf_service.py index f45ba48af75..4314c84c88f 100644 --- a/salt/modules/smf_service.py +++ b/salt/modules/smf_service.py @@ -111,7 +111,7 @@ def available(name): salt '*' service.available net-snmp """ - cmd = "/usr/bin/svcs -H -o FMRI {}".format(name) + cmd = f"/usr/bin/svcs -H -o FMRI {name}" name = __salt__["cmd.run"](cmd, python_shell=False) return name in get_all() @@ -128,7 +128,7 @@ def missing(name): salt '*' service.missing net-snmp """ - cmd = "/usr/bin/svcs -H -o FMRI {}".format(name) + cmd = f"/usr/bin/svcs -H -o FMRI {name}" name = __salt__["cmd.run"](cmd, python_shell=False) return name not in get_all() @@ -164,7 +164,7 @@ def start(name): salt '*' service.start """ - cmd = "/usr/sbin/svcadm enable -s -t {}".format(name) + cmd = f"/usr/sbin/svcadm enable -s -t {name}" retcode = __salt__["cmd.retcode"](cmd, python_shell=False) if not retcode: return True @@ -172,7 +172,7 @@ def start(name): # Return code 3 means there was a problem with the service # A common case is being in the 'maintenance' state # Attempt a clear and try one more time - clear_cmd = "/usr/sbin/svcadm clear {}".format(name) + clear_cmd = f"/usr/sbin/svcadm clear {name}" __salt__["cmd.retcode"](clear_cmd, python_shell=False) return not __salt__["cmd.retcode"](cmd, python_shell=False) return False @@ -188,7 +188,7 @@ def stop(name): salt '*' service.stop """ - cmd = "/usr/sbin/svcadm disable -s -t {}".format(name) + cmd = f"/usr/sbin/svcadm disable -s -t {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -202,7 +202,7 @@ def restart(name): salt '*' service.restart """ - cmd = "/usr/sbin/svcadm restart {}".format(name) + cmd = f"/usr/sbin/svcadm restart {name}" if not __salt__["cmd.retcode"](cmd, python_shell=False): # calling restart doesn't clear maintenance # or tell us that the service is in the 'online' state @@ -220,7 +220,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "/usr/sbin/svcadm refresh {}".format(name) + cmd = f"/usr/sbin/svcadm refresh {name}" if not __salt__["cmd.retcode"](cmd, python_shell=False): # calling reload doesn't clear maintenance # or tell us that the service is in the 'online' state @@ -258,7 +258,7 @@ def status(name, sig=None): services = [name] results = {} for service in services: - cmd = "/usr/bin/svcs -H -o STATE {}".format(service) + cmd = f"/usr/bin/svcs -H -o STATE {service}" line = __salt__["cmd.run"](cmd, python_shell=False) results[service] = line == "online" if contains_globbing: @@ -276,7 +276,7 @@ def enable(name, **kwargs): salt '*' service.enable """ - cmd = "/usr/sbin/svcadm enable {}".format(name) + cmd = f"/usr/sbin/svcadm enable {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -290,7 +290,7 @@ def disable(name, **kwargs): salt '*' service.disable """ - cmd = "/usr/sbin/svcadm disable {}".format(name) + cmd = f"/usr/sbin/svcadm disable {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -307,9 +307,9 @@ def enabled(name, **kwargs): # The property that reveals whether a service is enabled # can only be queried using the full FMRI # We extract the FMRI and then do the query - fmri_cmd = "/usr/bin/svcs -H -o FMRI {}".format(name) + fmri_cmd = f"/usr/bin/svcs -H -o FMRI {name}" fmri = __salt__["cmd.run"](fmri_cmd, python_shell=False) - cmd = "/usr/sbin/svccfg -s {} listprop general/enabled".format(fmri) + cmd = f"/usr/sbin/svccfg -s {fmri} listprop general/enabled" comps = __salt__["cmd.run"](cmd, python_shell=False).split() if comps[2] == "true": return True diff --git a/salt/modules/smtp.py b/salt/modules/smtp.py index acfa0d0d639..fc9d55f0cbb 100644 --- a/salt/modules/smtp.py +++ b/salt/modules/smtp.py @@ -156,7 +156,7 @@ def send_msg( name = os.path.basename(f) with salt.utils.files.fopen(f, "rb") as fin: att = email.mime.application.MIMEApplication(fin.read(), Name=name) - att["Content-Disposition"] = 'attachment; filename="{}"'.format(name) + att["Content-Disposition"] = f'attachment; filename="{name}"' msg.attach(att) try: diff --git a/salt/modules/snapper.py b/salt/modules/snapper.py index f5781a1a64f..f97d3d5f598 100644 --- a/salt/modules/snapper.py +++ b/salt/modules/snapper.py @@ -334,7 +334,7 @@ def create_config( def raise_arg_error(argname): raise CommandExecutionError( - 'You must provide a "{}" for the new configuration'.format(argname) + f'You must provide a "{argname}" for the new configuration' ) if not name: @@ -366,7 +366,7 @@ def create_snapshot( description=None, cleanup_algorithm="number", userdata=None, - **kwargs + **kwargs, ): """ Creates an snapshot @@ -408,7 +408,7 @@ def create_snapshot( jid = kwargs.get("__pub_jid") if description is None and jid is not None: - description = "salt job {}".format(jid) + description = f"salt job {jid}" if jid is not None: userdata["salt_jid"] = jid @@ -433,9 +433,7 @@ def create_snapshot( config, pre_number, description, cleanup_algorithm, userdata ) else: - raise CommandExecutionError( - "Invalid snapshot type '{}'".format(snapshot_type) - ) + raise CommandExecutionError(f"Invalid snapshot type '{snapshot_type}'") except dbus.DBusException as exc: raise CommandExecutionError( "Error encountered while listing changed files: {}".format( @@ -560,7 +558,7 @@ def _is_text_file(filename): ["file", "-bi", filename], check=False, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ).stdout return type_of_file.startswith("text") @@ -606,7 +604,7 @@ def run(function, *args, **kwargs): salt '*' snapper.run file.append args='["/etc/motd", "some text"]' """ config = kwargs.pop("config", "root") - description = kwargs.pop("description", "snapper.run[{}]".format(function)) + description = kwargs.pop("description", f"snapper.run[{function}]") cleanup_algorithm = kwargs.pop("cleanup_algorithm", "number") userdata = kwargs.pop("userdata", {}) @@ -619,11 +617,11 @@ def run(function, *args, **kwargs): description=description, cleanup_algorithm=cleanup_algorithm, userdata=userdata, - **kwargs + **kwargs, ) if function not in __salt__: - raise CommandExecutionError('function "{}" does not exist'.format(function)) + raise CommandExecutionError(f'function "{function}" does not exist') try: ret = __salt__[function](*args, **func_kwargs) @@ -637,7 +635,7 @@ def run(function, *args, **kwargs): description=description, cleanup_algorithm=cleanup_algorithm, userdata=userdata, - **kwargs + **kwargs, ) return ret @@ -755,7 +753,7 @@ def undo(config="root", files=None, num_pre=None, num_post=None): return ret except ValueError as exc: raise CommandExecutionError( - "Error while processing Snapper response: {}".format(cmdret) + f"Error while processing Snapper response: {cmdret}" ) @@ -773,7 +771,7 @@ def _get_jid_snapshots(jid, config="root"): post_snapshot = [x for x in jid_snapshots if x["type"] == "post"] if not pre_snapshot or not post_snapshot: - raise CommandExecutionError("Jid '{}' snapshots not found".format(jid)) + raise CommandExecutionError(f"Jid '{jid}' snapshots not found") return (pre_snapshot[0]["id"], post_snapshot[0]["id"]) diff --git a/salt/modules/solaris_fmadm.py b/salt/modules/solaris_fmadm.py index 7dae9d6b100..3c928c47c2c 100644 --- a/salt/modules/solaris_fmadm.py +++ b/salt/modules/solaris_fmadm.py @@ -69,7 +69,7 @@ def _parse_fmdump(output): # parse entries for entry in output: entry = [item for item in entry.split(" ") if item] - entry = ["{} {} {}".format(entry[0], entry[1], entry[2])] + entry[3:] + entry = [f"{entry[0]} {entry[1]} {entry[2]}"] + entry[3:] # prepare faults fault = OrderedDict() @@ -152,7 +152,7 @@ def _fmadm_action_fmri(action, fmri): """ ret = {} fmadm = _check_fmadm() - cmd = "{cmd} {action} {fmri}".format(cmd=fmadm, action=action, fmri=fmri) + cmd = f"{fmadm} {action} {fmri}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = {} @@ -260,8 +260,8 @@ def list_records(after=None, before=None): fmdump = _check_fmdump() cmd = "{cmd}{after}{before}".format( cmd=fmdump, - after=" -t {}".format(after) if after else "", - before=" -T {}".format(before) if before else "", + after=f" -t {after}" if after else "", + before=f" -T {before}" if before else "", ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] @@ -289,7 +289,7 @@ def show(uuid): """ ret = {} fmdump = _check_fmdump() - cmd = "{cmd} -u {uuid} -V".format(cmd=fmdump, uuid=uuid) + cmd = f"{fmdump} -u {uuid} -V" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = {} @@ -313,7 +313,7 @@ def config(): """ ret = {} fmadm = _check_fmadm() - cmd = "{cmd} config".format(cmd=fmadm) + cmd = f"{fmadm} config" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = {} @@ -340,7 +340,7 @@ def load(path): """ ret = {} fmadm = _check_fmadm() - cmd = "{cmd} load {path}".format(cmd=fmadm, path=path) + cmd = f"{fmadm} load {path}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = {} @@ -367,7 +367,7 @@ def unload(module): """ ret = {} fmadm = _check_fmadm() - cmd = "{cmd} unload {module}".format(cmd=fmadm, module=module) + cmd = f"{fmadm} unload {module}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = {} @@ -397,7 +397,7 @@ def reset(module, serd=None): ret = {} fmadm = _check_fmadm() cmd = "{cmd} reset {serd}{module}".format( - cmd=fmadm, serd="-s {} ".format(serd) if serd else "", module=module + cmd=fmadm, serd=f"-s {serd} " if serd else "", module=module ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] diff --git a/salt/modules/solaris_group.py b/salt/modules/solaris_group.py index 31663be1846..7e9fc1d074f 100644 --- a/salt/modules/solaris_group.py +++ b/salt/modules/solaris_group.py @@ -54,7 +54,7 @@ def add(name, gid=None, **kwargs): cmd = "groupadd " if gid: - cmd += "-g {} ".format(gid) + cmd += f"-g {gid} " cmd += name ret = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -72,7 +72,7 @@ def delete(name): salt '*' group.delete foo """ - ret = __salt__["cmd.run_all"]("groupdel {}".format(name), python_shell=False) + ret = __salt__["cmd.run_all"](f"groupdel {name}", python_shell=False) return not ret["retcode"] @@ -134,7 +134,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) if gid == pre_gid: return True - cmd = "groupmod -g {} {}".format(gid, name) + cmd = f"groupmod -g {gid} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_gid = __salt__["file.group_to_gid"](name) if post_gid != pre_gid: diff --git a/salt/modules/solaris_shadow.py b/salt/modules/solaris_shadow.py index 9441ecea293..36d34d81e72 100644 --- a/salt/modules/solaris_shadow.py +++ b/salt/modules/solaris_shadow.py @@ -144,7 +144,7 @@ def info(name): # 5. Maximum age # 6. Warning period - output = __salt__["cmd.run_all"]("passwd -s {}".format(name), python_shell=False) + output = __salt__["cmd.run_all"](f"passwd -s {name}", python_shell=False) if output["retcode"] != 0: return ret @@ -183,7 +183,7 @@ def set_maxdays(name, maxdays): pre_info = info(name) if maxdays == pre_info["max"]: return True - cmd = "passwd -x {} {}".format(maxdays, name) + cmd = f"passwd -x {maxdays} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["max"] != pre_info["max"]: @@ -203,7 +203,7 @@ def set_mindays(name, mindays): pre_info = info(name) if mindays == pre_info["min"]: return True - cmd = "passwd -n {} {}".format(mindays, name) + cmd = f"passwd -n {mindays} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["min"] != pre_info["min"]: @@ -265,7 +265,7 @@ def del_password(name): salt '*' shadow.del_password username """ - cmd = "passwd -d {}".format(name) + cmd = f"passwd -d {name}" __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="quiet") uinfo = info(name) return not uinfo["passwd"] @@ -296,7 +296,7 @@ def set_password(name, password): continue comps[1] = password line = ":".join(comps) - lines.append("{}\n".format(line)) + lines.append(f"{line}\n") with salt.utils.files.fopen(s_file, "w+") as ofile: lines = [salt.utils.stringutils.to_str(_l) for _l in lines] ofile.writelines(lines) @@ -318,7 +318,7 @@ def set_warndays(name, warndays): pre_info = info(name) if warndays == pre_info["warn"]: return True - cmd = "passwd -w {} {}".format(warndays, name) + cmd = f"passwd -w {warndays} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["warn"] != pre_info["warn"]: diff --git a/salt/modules/solaris_user.py b/salt/modules/solaris_user.py index f2c45f809b5..be705b2f0a6 100644 --- a/salt/modules/solaris_user.py +++ b/salt/modules/solaris_user.py @@ -108,7 +108,7 @@ def add( workphone="", homephone="", createhome=True, - **kwargs + **kwargs, ): """ Add a user to the minion @@ -218,7 +218,7 @@ def chuid(name, uid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if uid == pre_info["uid"]: return True cmd = ["usermod", "-u", uid, name] @@ -238,7 +238,7 @@ def chgid(name, gid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if gid == pre_info["gid"]: return True cmd = ["usermod", "-g", gid, name] @@ -258,7 +258,7 @@ def chshell(name, shell): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if shell == pre_info["shell"]: return True cmd = ["usermod", "-s", shell, name] @@ -289,7 +289,7 @@ def chhome(name, home, persist=False): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if home == pre_info["home"]: return True cmd = ["usermod", "-d", home] @@ -457,10 +457,10 @@ def rename(name, new_name): """ current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") cmd = ["usermod", "-l", new_name, name] __salt__["cmd.run"](cmd, python_shell=False) return info(new_name).get("name") == new_name diff --git a/salt/modules/solarisipspkg.py b/salt/modules/solarisipspkg.py index 6e6e4f6610f..1d720db0656 100644 --- a/salt/modules/solarisipspkg.py +++ b/salt/modules/solarisipspkg.py @@ -539,19 +539,19 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if getattr(pkg, "items", False): if list(pkg.items())[0][1]: # version specified pkg2inst.append( - "{}@{}".format(list(pkg.items())[0][0], list(pkg.items())[0][1]) + f"{list(pkg.items())[0][0]}@{list(pkg.items())[0][1]}" ) else: pkg2inst.append(list(pkg.items())[0][0]) else: - pkg2inst.append("{}".format(pkg)) + pkg2inst.append(f"{pkg}") log.debug("Installing these packages instead of %s: %s", name, pkg2inst) else: # install single package if version: - pkg2inst = "{}@{}".format(name, version) + pkg2inst = f"{name}@{version}" else: - pkg2inst = "{}".format(name) + pkg2inst = f"{name}" cmd = ["pkg", "install", "-v", "--accept"] if test: diff --git a/salt/modules/solarispkg.py b/salt/modules/solarispkg.py index fd0ab8d1add..370981b0e7e 100644 --- a/salt/modules/solarispkg.py +++ b/salt/modules/solarispkg.py @@ -65,17 +65,17 @@ def _write_adminfile(kwargs): fp_.write(salt.utils.stringutils.to_str(line)) with salt.utils.files.fopen(adminfile, "w") as fp_: - _write_line(fp_, "email={}\n".format(email)) - _write_line(fp_, "instance={}\n".format(instance)) - _write_line(fp_, "partial={}\n".format(partial)) - _write_line(fp_, "runlevel={}\n".format(runlevel)) - _write_line(fp_, "idepend={}\n".format(idepend)) - _write_line(fp_, "rdepend={}\n".format(rdepend)) - _write_line(fp_, "space={}\n".format(space)) - _write_line(fp_, "setuid={}\n".format(setuid)) - _write_line(fp_, "conflict={}\n".format(conflict)) - _write_line(fp_, "action={}\n".format(action)) - _write_line(fp_, "basedir={}\n".format(basedir)) + _write_line(fp_, f"email={email}\n") + _write_line(fp_, f"instance={instance}\n") + _write_line(fp_, f"partial={partial}\n") + _write_line(fp_, f"runlevel={runlevel}\n") + _write_line(fp_, f"idepend={idepend}\n") + _write_line(fp_, f"rdepend={rdepend}\n") + _write_line(fp_, f"space={space}\n") + _write_line(fp_, f"setuid={setuid}\n") + _write_line(fp_, f"conflict={conflict}\n") + _write_line(fp_, f"action={action}\n") + _write_line(fp_, f"basedir={basedir}\n") return adminfile diff --git a/salt/modules/solr.py b/salt/modules/solr.py index fca581922f1..9654bd36f6c 100644 --- a/salt/modules/solr.py +++ b/salt/modules/solr.py @@ -205,7 +205,7 @@ def _format_url(handler, host=None, core_name=None, extra=None): baseurl = __salt__["config.option"]("solr.baseurl") if _get_none_or_value(core_name) is None: if extra is None or len(extra) == 0: - return "http://{}:{}{}/{}?wt=json".format(host, port, baseurl, handler) + return f"http://{host}:{port}{baseurl}/{handler}?wt=json" else: return "http://{}:{}{}/{}?wt=json&{}".format( host, port, baseurl, handler, "&".join(extra) @@ -260,7 +260,7 @@ def _http_request(url, request_timeout=None): data = salt.utils.json.load(urllib.request.urlopen(url, **kwargs)) return _get_return_dict(True, data, []) except Exception as err: # pylint: disable=broad-except - return _get_return_dict(False, {}, ["{} : {}".format(url, err)]) + return _get_return_dict(False, {}, [f"{url} : {err}"]) def _replication_request(command, host=None, core_name=None, params=None): @@ -286,7 +286,7 @@ def _replication_request(command, host=None, core_name=None, params=None): {'success':boolean, 'data':dict, 'errors':list, 'warnings':list} """ params = [] if params is None else params - extra = ["command={}".format(command)] + params + extra = [f"command={command}"] + params url = _format_url("replication", host=host, core_name=core_name, extra=extra) return _http_request(url) @@ -311,7 +311,7 @@ def _get_admin_info(command, host=None, core_name=None): {'success':boolean, 'data':dict, 'errors':list, 'warnings':list} """ - url = _format_url("admin/{}".format(command), host, core_name=core_name) + url = _format_url(f"admin/{command}", host, core_name=core_name) resp = _http_request(url) return resp @@ -390,10 +390,10 @@ def _pre_index_check(handler, host=None, core_name=None): warn = ["An indexing process is already running."] return _get_return_dict(True, warnings=warn) if status != "idle": - errors = ['Unknown status: "{}"'.format(status)] + errors = [f'Unknown status: "{status}"'] return _get_return_dict(False, data=resp["data"], errors=errors) else: - errors = ["Status check failed. Response details: {}".format(resp)] + errors = [f"Status check failed. Response details: {resp}"] return _get_return_dict(False, data=resp["data"], errors=errors) return resp @@ -421,7 +421,7 @@ def _find_value(ret_dict, key, path=None): if path is None: path = key else: - path = "{}:{}".format(path, key) + path = f"{path}:{key}" ret = [] for ikey, val in ret_dict.items(): @@ -739,7 +739,7 @@ def match_index_versions(host=None, core_name=None): if "ERROR" in slave: error = slave["ERROR"] success = False - err = "{}: {} - {}".format(core, error, master_url) + err = f"{core}: {error} - {master_url}" resp["errors"].append(err) # if there was an error return the entire response so the # alterer can get what it wants @@ -864,8 +864,8 @@ def backup(host=None, core_name=None, append_core_to_path=False): params = [] if path is not None: path = path + name if append_core_to_path else path - params.append("&location={}".format(path + name)) - params.append("&numberToKeep={}".format(num_backups)) + params.append(f"&location={path + name}") + params.append(f"&numberToKeep={num_backups}") resp = _replication_request( "backup", host=host, core_name=name, params=params ) @@ -881,8 +881,8 @@ def backup(host=None, core_name=None, append_core_to_path=False): if append_core_to_path: path += core_name if path is not None: - params = ["location={}".format(path)] - params.append("&numberToKeep={}".format(num_backups)) + params = [f"location={path}"] + params.append(f"&numberToKeep={num_backups}") resp = _replication_request( "backup", host=host, core_name=core_name, params=params ) @@ -1058,7 +1058,7 @@ def reload_core(host=None, core_name=None): ret, success, data, resp["errors"], resp["warnings"] ) return ret - extra = ["action=RELOAD", "core={}".format(core_name)] + extra = ["action=RELOAD", f"core={core_name}"] url = _format_url("admin/cores", host=host, core_name=None, extra=extra) return _http_request(url) @@ -1099,7 +1099,7 @@ def core_status(host=None, core_name=None): ret, success, data, resp["errors"], resp["warnings"] ) return ret - extra = ["action=STATUS", "core={}".format(core_name)] + extra = ["action=STATUS", f"core={core_name}"] url = _format_url("admin/cores", host=host, core_name=None, extra=extra) return _http_request(url) @@ -1241,7 +1241,7 @@ def full_import(handler, host=None, core_name=None, options=None, extra=None): return _get_return_dict(False, errors=errors) params = ["command=full-import"] for key, val in options.items(): - params.append("&{}={}".format(key, val)) + params.append(f"&{key}={val}") url = _format_url(handler, host=host, core_name=core_name, extra=params + extra) return _http_request(url) @@ -1294,7 +1294,7 @@ def delta_import(handler, host=None, core_name=None, options=None, extra=None): return _get_return_dict(False, errors=errors) params = ["command=delta-import"] for key, val in options.items(): - params.append("{}={}".format(key, val)) + params.append(f"{key}={val}") url = _format_url(handler, host=host, core_name=core_name, extra=params + extra) return _http_request(url) diff --git a/salt/modules/solrcloud.py b/salt/modules/solrcloud.py index fda16a1ef55..7b594e3292f 100644 --- a/salt/modules/solrcloud.py +++ b/salt/modules/solrcloud.py @@ -314,7 +314,7 @@ def alias_set_collections(alias_name, collections=None, **kwargs): "admin/collections?action=CREATEALIAS&name={alias}&wt=json&collections={collections}".format( alias=alias_name, collections=", ".join(collections) ), - **kwargs + **kwargs, ) @@ -337,7 +337,7 @@ def collection_reload(collection, **kwargs): "admin/collections?action=RELOAD&name={collection}&wt=json".format( collection=collection ), - **kwargs + **kwargs, ) @@ -398,7 +398,7 @@ def collection_backup(collection_name, location, backup_name=None, **kwargs): raise ValueError("Collection doesn't exists") if backup_name is not None: - backup_name = "&name={}".format(backup_name) + backup_name = f"&name={backup_name}" else: backup_name = "" @@ -406,7 +406,7 @@ def collection_backup(collection_name, location, backup_name=None, **kwargs): "{collection}/replication?command=BACKUP&location={location}{backup_name}&wt=json".format( collection=collection_name, backup_name=backup_name, location=location ), - **kwargs + **kwargs, ) @@ -436,7 +436,7 @@ def collection_backup_all(location, backup_name=None, **kwargs): "{collection}/replication?command=BACKUP&location={location}{backup_name}&wt=json".format( collection=collection_name, backup_name=backup_name, location=location ), - **kwargs + **kwargs, ) @@ -481,7 +481,7 @@ def collection_create(collection_name, options=None, **kwargs): "admin/collections?action=CREATE&wt=json&name=" + collection_name + options_string, - **kwargs + **kwargs, ) @@ -566,5 +566,5 @@ def collection_set_options(collection_name, options, **kwargs): "admin/collections?action=MODIFYCOLLECTION&wt=json&collection=" + collection_name + options_string, - **kwargs + **kwargs, ) diff --git a/salt/modules/splunk_search.py b/salt/modules/splunk_search.py index e0d101cb2f3..51f46cfc7d9 100644 --- a/salt/modules/splunk_search.py +++ b/salt/modules/splunk_search.py @@ -130,7 +130,7 @@ def update(name, profile="splunk", **kwargs): if old_value != new_value: update_set[key] = new_value update_needed = True - diffs.append("{}: '{}' => '{}'".format(key, old_value, new_value)) + diffs.append(f"{key}: '{old_value}' => '{new_value}'") if update_needed: search.update(**update_set).refresh() return update_set, diffs diff --git a/salt/modules/ssh.py b/salt/modules/ssh.py index 44e7c67da16..0701e963867 100644 --- a/salt/modules/ssh.py +++ b/salt/modules/ssh.py @@ -83,7 +83,7 @@ def _refine_enc(enc): elif enc in also_allowed: return enc else: - raise CommandExecutionError("Incorrect encryption key type '{}'.".format(enc)) + raise CommandExecutionError(f"Incorrect encryption key type '{enc}'.") def _format_auth_line(key, enc, comment, options): @@ -93,7 +93,7 @@ def _format_auth_line(key, enc, comment, options): line = "" if options: line += "{} ".format(",".join(options)) - line += "{} {} {}\n".format(enc, key, comment) + line += f"{enc} {key} {comment}\n" return line @@ -134,7 +134,7 @@ def _get_config_file(user, config): """ uinfo = __salt__["user.info"](user) if not uinfo: - raise CommandExecutionError("User '{}' does not exist".format(user)) + raise CommandExecutionError(f"User '{user}' does not exist") home = uinfo["home"] config = _expand_authorized_keys_path(config, user, home) if not os.path.isabs(config): @@ -183,9 +183,7 @@ def _replace_auth_key( # Write out any changes _fh.writelines(salt.utils.data.encode(lines)) except OSError as exc: - raise CommandExecutionError( - "Problem reading or writing to key file: {}".format(exc) - ) + raise CommandExecutionError(f"Problem reading or writing to key file: {exc}") def _validate_keys(key_file, fingerprint_hash_type): @@ -241,7 +239,7 @@ def _validate_keys(key_file, fingerprint_hash_type): "fingerprint": fingerprint, } except OSError: - raise CommandExecutionError("Problem reading ssh key file {}".format(key_file)) + raise CommandExecutionError(f"Problem reading ssh key file {key_file}") return ret @@ -277,7 +275,7 @@ def _fingerprint(public_key, fingerprint_hash_type): hash_func = getattr(hashlib, hash_type) except AttributeError: raise CommandExecutionError( - "The fingerprint_hash_type {} is not supported.".format(hash_type) + f"The fingerprint_hash_type {hash_type} is not supported." ) try: @@ -305,7 +303,7 @@ def _get_known_hosts_file(config=None, user=None): if not uinfo: return { "status": "error", - "error": "User {} does not exist".format(user), + "error": f"User {user} does not exist", } full = os.path.join(uinfo["home"], config) else: @@ -433,7 +431,7 @@ def check_key_file( return {} s_keys = _validate_keys(keyfile, fingerprint_hash_type) if not s_keys: - err = "No keys detected in {}. Is file properly formatted?".format(source) + err = f"No keys detected in {source}. Is file properly formatted?" log.error(err) __context__["ssh_auth.error"] = err return {} @@ -526,7 +524,7 @@ def rm_auth_key_from_file( s_keys = _validate_keys(lfile, fingerprint_hash_type) if not s_keys: - err = "No keys detected in {}. Is file properly formatted?".format(source) + err = f"No keys detected in {source}. Is file properly formatted?" log.error(err) __context__["ssh_auth.error"] = err return "fail" @@ -568,7 +566,7 @@ def rm_auth_key(user, key, config=".ssh/authorized_keys", fingerprint_hash_type= # Return something sensible if the file doesn't exist if not os.path.isfile(full): - return "Authorized keys file {} not present".format(full) + return f"Authorized keys file {full} not present" lines = [] try: @@ -644,7 +642,7 @@ def set_auth_key_from_file( s_keys = _validate_keys(lfile, fingerprint_hash_type) if not s_keys: - err = "No keys detected in {}. Is file properly formatted?".format(source) + err = f"No keys detected in {source}. Is file properly formatted?" log.error(err) __context__["ssh_auth.error"] = err return "fail" @@ -1009,7 +1007,7 @@ def rm_known_host(user=None, hostname=None, config=None, port=None): if not os.path.isfile(full): return { "status": "error", - "error": "Known hosts file {} does not exist".format(full), + "error": f"Known hosts file {full} does not exist", } ssh_hostname = _hostname_and_port_to_ssh_hostname(hostname, port) @@ -1252,7 +1250,7 @@ def set_known_host( ofile.writelines(salt.utils.data.encode(lines)) except OSError as exception: raise CommandExecutionError( - "Couldn't append to known hosts file: '{}'".format(exception) + f"Couldn't append to known hosts file: '{exception}'" ) if not salt.utils.platform.is_windows(): @@ -1378,7 +1376,7 @@ def hash_known_hosts(user=None, config=None): if not os.path.isfile(full): return { "status": "error", - "error": "Known hosts file {} does not exist".format(full), + "error": f"Known hosts file {full} does not exist", } origmode = os.stat(full).st_mode cmd = ["ssh-keygen", "-H", "-f", full] @@ -1396,7 +1394,7 @@ def _hostname_and_port_to_ssh_hostname(hostname, port=DEFAULT_SSH_PORT): if not port or port == DEFAULT_SSH_PORT: return hostname else: - return "[{}]:{}".format(hostname, port) + return f"[{hostname}]:{port}" def key_is_encrypted(key): diff --git a/salt/modules/state.py b/salt/modules/state.py index 20e1e67a24b..6440d347ffe 100644 --- a/salt/modules/state.py +++ b/salt/modules/state.py @@ -145,7 +145,7 @@ def _snapper_pre(opts, jid): snapper_pre = __salt__["snapper.create_snapshot"]( config=__opts__.get("snapper_states_config", "root"), snapshot_type="pre", - description="Salt State run for jid {}".format(jid), + description=f"Salt State run for jid {jid}", __pub_jid=jid, ) except Exception: # pylint: disable=broad-except @@ -164,7 +164,7 @@ def _snapper_post(opts, jid, pre_num): config=__opts__.get("snapper_states_config", "root"), snapshot_type="post", pre_number=pre_num, - description="Salt State run for jid {}".format(jid), + description=f"Salt State run for jid {jid}", __pub_jid=jid, ) except Exception: # pylint: disable=broad-except @@ -587,7 +587,7 @@ def template(tem, queue=None, **kwargs): raise CommandExecutionError("Pillar failed to render", info=errors) if not tem.endswith(".sls"): - tem = "{sls}.sls".format(sls=tem) + tem = f"{tem}.sls" high_state, errors = st_.render_state( tem, kwargs.get("saltenv", ""), "", None, local=True ) @@ -883,7 +883,7 @@ def request(mods=None, **kwargs): try: if salt.utils.platform.is_windows(): # Make sure cache file isn't read-only - __salt__["cmd.run"]('attrib -R "{}"'.format(notify_path)) + __salt__["cmd.run"](f'attrib -R "{notify_path}"') with salt.utils.files.fopen(notify_path, "w+b") as fp_: salt.payload.dump(req, fp_) except OSError: @@ -945,7 +945,7 @@ def clear_request(name=None): try: if salt.utils.platform.is_windows(): # Make sure cache file isn't read-only - __salt__["cmd.run"]('attrib -R "{}"'.format(notify_path)) + __salt__["cmd.run"](f'attrib -R "{notify_path}"') with salt.utils.files.fopen(notify_path, "w+b") as fp_: salt.payload.dump(req, fp_) except OSError: @@ -1215,7 +1215,7 @@ def sls( queue=None, sync_mods=None, state_events=None, - **kwargs + **kwargs, ): """ Execute the states in one or more SLS files @@ -1414,7 +1414,7 @@ def sls( for module_type in sync_mods: try: - __salt__["saltutil.sync_{}".format(module_type)](saltenv=opts["saltenv"]) + __salt__[f"saltutil.sync_{module_type}"](saltenv=opts["saltenv"]) except KeyError: log.warning("Invalid custom module type '%s', ignoring", module_type) @@ -2340,10 +2340,10 @@ def pkg(pkg_path, pkg_sum, hash_type, test=None, **kwargs): members = s_pkg.getmembers() for member in members: if salt.utils.stringutils.to_unicode(member.path).startswith( - (os.sep, "..{}".format(os.sep)) + (os.sep, f"..{os.sep}") ): return {} - elif "..{}".format(os.sep) in salt.utils.stringutils.to_unicode(member.path): + elif f"..{os.sep}" in salt.utils.stringutils.to_unicode(member.path): return {} s_pkg.extractall(root) # nosec s_pkg.close() @@ -2421,9 +2421,9 @@ def disable(states): _changed = False for _state in states: if _state in _disabled_state_runs: - msg.append("Info: {} state already disabled.".format(_state)) + msg.append(f"Info: {_state} state already disabled.") else: - msg.append("Info: {} state disabled.".format(_state)) + msg.append(f"Info: {_state} state disabled.") _disabled_state_runs.append(_state) _changed = True @@ -2471,9 +2471,9 @@ def enable(states): for _state in states: log.debug("_state %s", _state) if _state not in _disabled_state_runs: - msg.append("Info: {} state already enabled.".format(_state)) + msg.append(f"Info: {_state} state already enabled.") else: - msg.append("Info: {} state enabled.".format(_state)) + msg.append(f"Info: {_state} state enabled.") _disabled_state_runs.remove(_state) _changed = True diff --git a/salt/modules/status.py b/salt/modules/status.py index 8489256f0b5..71fa6f49cc9 100644 --- a/salt/modules/status.py +++ b/salt/modules/status.py @@ -221,9 +221,7 @@ def uptime(): if salt.utils.platform.is_linux(): ut_path = "/proc/uptime" if not os.path.exists(ut_path): - raise CommandExecutionError( - "File {ut_path} was not found.".format(ut_path=ut_path) - ) + raise CommandExecutionError(f"File {ut_path} was not found.") with salt.utils.files.fopen(ut_path) as rfh: seconds = int(float(rfh.read().split()[0])) elif salt.utils.platform.is_sunos(): @@ -267,7 +265,7 @@ def uptime(): "since_iso": boot_time.isoformat(), "since_t": int(curr_seconds - seconds), "days": up_time.days, - "time": "{}:{}".format(up_time.seconds // 3600, up_time.seconds % 3600 // 60), + "time": f"{up_time.seconds // 3600}:{up_time.seconds % 3600 // 60}", } if salt.utils.path.which("who"): @@ -569,7 +567,7 @@ def meminfo(): procn = len(ret["svmon"]) ret["svmon"].append({}) comps = line.split() - pg_space = "{} {}".format(comps[0], comps[1]) + pg_space = f"{comps[0]} {comps[1]}" ret["svmon"][procn][pg_space] = {} for idx, field in enumerate(fields): if len(comps) > idx + 2: @@ -760,7 +758,7 @@ def cpuinfo(): ret["psrinfo"][procn]["family"] = _number(line[4]) ret["psrinfo"][procn]["model"] = _number(line[6]) ret["psrinfo"][procn]["step"] = _number(line[8]) - ret["psrinfo"][procn]["clock"] = "{} {}".format(line[10], line[11][:-1]) + ret["psrinfo"][procn]["clock"] = f"{line[10]} {line[11][:-1]}" return ret def aix_cpuinfo(): @@ -1386,10 +1384,10 @@ def netdev(): ): # fetch device info netstat_ipv4 = __salt__["cmd.run"]( - "netstat -i -I {dev} -n -f inet".format(dev=dev) + f"netstat -i -I {dev} -n -f inet" ).splitlines() netstat_ipv6 = __salt__["cmd.run"]( - "netstat -i -I {dev} -n -f inet6".format(dev=dev) + f"netstat -i -I {dev} -n -f inet6" ).splitlines() # prepare data @@ -1404,14 +1402,14 @@ def netdev(): if val == "Name": continue if val in ["Address", "Net/Dest"]: - ret[dev]["IPv4 {field}".format(field=val)] = val + ret[dev][f"IPv4 {val}"] = val else: ret[dev][val] = _number(val) for val in netstat_ipv6[0][:-1]: if val == "Name": continue if val in ["Address", "Net/Dest"]: - ret[dev]["IPv6 {field}".format(field=val)] = val + ret[dev][f"IPv6 {val}"] = val else: ret[dev][val] = _number(val) @@ -1437,10 +1435,10 @@ def netdev(): # en0 1500 link#3 e2.eb.32.42.84.c 10029731 0 446499 0 0 netstat_ipv4 = __salt__["cmd.run"]( - "netstat -i -n -I {dev} -f inet".format(dev=dev) + f"netstat -i -n -I {dev} -f inet" ).splitlines() netstat_ipv6 = __salt__["cmd.run"]( - "netstat -i -n -I {dev} -f inet6".format(dev=dev) + f"netstat -i -n -I {dev} -f inet6" ).splitlines() # add data diff --git a/salt/modules/supervisord.py b/salt/modules/supervisord.py index 90754afc70a..1e97e3b7632 100644 --- a/salt/modules/supervisord.py +++ b/salt/modules/supervisord.py @@ -26,7 +26,7 @@ def _get_supervisorctl_bin(bin_env): if not bin_env: which_result = __salt__["cmd.which_bin"]([cmd]) if which_result is None: - raise CommandNotFoundError("Could not find a `{}` binary".format(cmd)) + raise CommandNotFoundError(f"Could not find a `{cmd}` binary") return which_result # try to get binary from env @@ -34,7 +34,7 @@ def _get_supervisorctl_bin(bin_env): cmd_bin = os.path.join(bin_env, "bin", cmd) if os.path.isfile(cmd_bin): return cmd_bin - raise CommandNotFoundError("Could not find a `{}` binary".format(cmd)) + raise CommandNotFoundError(f"Could not find a `{cmd}` binary") return bin_env @@ -57,7 +57,7 @@ def _get_return(ret): if ret["retcode"] != 0: # This is a non 0 exit code if "ERROR" not in retmsg: - retmsg = "ERROR: {}".format(retmsg) + retmsg = f"ERROR: {retmsg}" return retmsg @@ -371,7 +371,7 @@ def _read_config(conf_file=None): try: config.read(conf_file) except OSError as exc: - raise CommandExecutionError("Unable to read from {}: {}".format(conf_file, exc)) + raise CommandExecutionError(f"Unable to read from {conf_file}: {exc}") return config @@ -393,9 +393,9 @@ def options(name, conf_file=None): salt '*' supervisord.options foo """ config = _read_config(conf_file) - section_name = "program:{}".format(name) + section_name = f"program:{name}" if section_name not in config.sections(): - raise CommandExecutionError("Process '{}' not found".format(name)) + raise CommandExecutionError(f"Process '{name}' not found") ret = {} for key, val in config.items(section_name): val = salt.utils.stringutils.to_num(val.split(";")[0].strip()) @@ -437,7 +437,7 @@ def status_bool(name, expected_state=None, user=None, conf_file=None, bin_env=No salt '*' supervisord.status_bool nginx expected_state='RUNNING' """ - cmd = "status {}".format(name) + cmd = f"status {name}" for line in custom(cmd, user, conf_file, bin_env).splitlines(): if len(line.split()) > 2: process, state, reason = line.split(None, 2) diff --git a/salt/modules/suse_apache.py b/salt/modules/suse_apache.py index 7c599b34a83..5501fa21ddf 100644 --- a/salt/modules/suse_apache.py +++ b/salt/modules/suse_apache.py @@ -73,9 +73,9 @@ def a2enmod(mod): ret["Mod"] = mod if status == 1: - ret["Status"] = "Mod {} Not found".format(mod) + ret["Status"] = f"Mod {mod} Not found" elif status == 0: - ret["Status"] = "Mod {} enabled".format(mod) + ret["Status"] = f"Mod {mod} enabled" else: ret["Status"] = status @@ -104,9 +104,9 @@ def a2dismod(mod): ret["Mod"] = mod if status == 256: - ret["Status"] = "Mod {} Not found".format(mod) + ret["Status"] = f"Mod {mod} Not found" elif status == 0: - ret["Status"] = "Mod {} disabled".format(mod) + ret["Status"] = f"Mod {mod} disabled" else: ret["Status"] = status diff --git a/salt/modules/suse_ip.py b/salt/modules/suse_ip.py index 9422c0d91b2..fdff55e37a4 100644 --- a/salt/modules/suse_ip.py +++ b/salt/modules/suse_ip.py @@ -197,7 +197,7 @@ def _parse_ethtool_opts(opts, iface): _raise_error_iface(iface, "advertise", valid) if "channels" in opts: - channels_cmd = "-L {}".format(iface.strip()) + channels_cmd = f"-L {iface.strip()}" channels_params = [] for option in ("rx", "tx", "other", "combined"): if option in opts["channels"]: @@ -557,9 +557,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): if iface_type not in ("bridge",): ethtool = _parse_ethtool_opts(opts, iface) if ethtool: - result["ethtool"] = " ".join( - ["{} {}".format(x, y) for x, y in ethtool.items()] - ) + result["ethtool"] = " ".join([f"{x} {y}" for x, y in ethtool.items()]) if iface_type == "slave": result["proto"] = "none" @@ -571,9 +569,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): raise AttributeError(msg) bonding = _parse_settings_bond(opts, iface) if bonding: - result["bonding"] = " ".join( - ["{}={}".format(x, y) for x, y in bonding.items()] - ) + result["bonding"] = " ".join([f"{x}={y}" for x, y in bonding.items()]) result["devtype"] = "Bond" if "slaves" in opts: if isinstance(opts["slaves"], list): @@ -667,14 +663,14 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): ) or salt.utils.validate.net.ipv6_addr(opt): result["ipaddrs"].append(opt) else: - msg = "{} is invalid ipv4 or ipv6 CIDR".format(opt) + msg = f"{opt} is invalid ipv4 or ipv6 CIDR" log.error(msg) raise AttributeError(msg) if "ipv6addr" in opts: if salt.utils.validate.net.ipv6_addr(opts["ipv6addr"]): result["ipaddrs"].append(opts["ipv6addr"]) else: - msg = "{} is invalid ipv6 CIDR".format(opt) + msg = f"{opt} is invalid ipv6 CIDR" log.error(msg) raise AttributeError(msg) if "ipv6addrs" in opts: @@ -682,7 +678,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): if salt.utils.validate.net.ipv6_addr(opt): result["ipaddrs"].append(opt) else: - msg = "{} is invalid ipv6 CIDR".format(opt) + msg = f"{opt} is invalid ipv6 CIDR" log.error(msg) raise AttributeError(msg) @@ -878,7 +874,7 @@ def _write_file_iface(iface, data, folder, pattern): """ filename = os.path.join(folder, pattern.format(iface)) if not os.path.exists(folder): - msg = "{} cannot be written. {} does not exist".format(filename, folder) + msg = f"{filename} cannot be written. {folder} does not exist" log.error(msg) raise AttributeError(msg) with salt.utils.files.fopen(filename, "w") as fp_: @@ -987,7 +983,7 @@ def build_interface(iface, iface_type, enabled, **settings): return _get_non_blank_lines(ifcfg) _write_file_iface(iface, ifcfg, _SUSE_NETWORK_SCRIPT_DIR, "ifcfg-{}") - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1036,7 +1032,7 @@ def build_routes(iface, **settings): if iface == "routes": path = _SUSE_NETWORK_ROUTES_FILE else: - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifroute-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifroute-{iface}") _write_file_network(routecfg, path) @@ -1068,7 +1064,7 @@ def down(iface, iface_type=None): """ # Slave devices are controlled by the master. if not iface_type or iface_type.lower() != "slave": - return __salt__["cmd.run"]("ifdown {}".format(iface)) + return __salt__["cmd.run"](f"ifdown {iface}") return None @@ -1089,7 +1085,7 @@ def get_interface(iface): salt '*' ip.get_interface eth0 """ - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1118,7 +1114,7 @@ def up(iface, iface_type=None): """ # Slave devices are controlled by the master. if not iface_type or iface_type.lower() != "slave": - return __salt__["cmd.run"]("ifup {}".format(iface)) + return __salt__["cmd.run"](f"ifup {iface}") return None @@ -1142,7 +1138,7 @@ def get_routes(iface): if iface == "routes": path = _SUSE_NETWORK_ROUTES_FILE else: - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifroute-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifroute-{iface}") return _read_file(path) diff --git a/salt/modules/sysbench.py b/salt/modules/sysbench.py index 9e56ddbbe71..1f44e77fb2a 100644 --- a/salt/modules/sysbench.py +++ b/salt/modules/sysbench.py @@ -79,7 +79,7 @@ def cpu(): # Test beings! for primes in max_primes: - key = "Prime numbers limit: {}".format(primes) + key = f"Prime numbers limit: {primes}" run_command = test_command.format(primes) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -110,7 +110,7 @@ def threads(): # Test begins! for yields, locks in zip(thread_yields, thread_locks): - key = "Yields: {} Locks: {}".format(yields, locks) + key = f"Yields: {yields} Locks: {locks}" run_command = test_command.format(yields, locks) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -149,7 +149,7 @@ def mutex(): # Test begins! for num, locks, loops in zip(mutex_num, mutex_locks, mutex_loops): - key = "Mutex: {} Locks: {} Loops: {}".format(num, locks, loops) + key = f"Mutex: {num} Locks: {locks} Loops: {loops}" run_command = test_command.format(num, locks, loops) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -187,7 +187,7 @@ def memory(): # Test begins! for oper in memory_oper: for scope in memory_scope: - key = "Operation: {} Scope: {}".format(oper, scope) + key = f"Operation: {oper} Scope: {scope}" run_command = test_command.format(oper, scope) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -228,7 +228,7 @@ def fileio(): # Test begins! for mode in test_modes: - key = "Mode: {}".format(mode) + key = f"Mode: {mode}" # Prepare phase run_command = (test_command + "prepare").format(mode) diff --git a/salt/modules/sysfs.py b/salt/modules/sysfs.py index 0192c038612..f86136c2060 100644 --- a/salt/modules/sysfs.py +++ b/salt/modules/sysfs.py @@ -62,7 +62,7 @@ def write(key, value): key = target(key) log.trace("Writing %s to %s", value, key) with salt.utils.files.fopen(key, "w") as twriter: - twriter.write(salt.utils.stringutils.to_str("{}\n".format(value))) + twriter.write(salt.utils.stringutils.to_str(f"{value}\n")) return True except Exception: # pylint: disable=broad-except return False diff --git a/salt/modules/syslog_ng.py b/salt/modules/syslog_ng.py index 5df09f233b4..d215d8057b0 100644 --- a/salt/modules/syslog_ng.py +++ b/salt/modules/syslog_ng.py @@ -79,7 +79,7 @@ def _indent(value): """ Returns the indented parameter. """ - return "{}{}".format(_INDENT, value) + return f"{_INDENT}{value}" def _indentln(string): @@ -161,9 +161,9 @@ class Statement(Buildable): def build_header(self): if self.has_name: - return _indentln("{0} {1} {{".format(self.type, self.id)) + return _indentln(f"{self.type} {self.id} {{") else: - return _indentln("{0} {{".format(self.type)) + return _indentln(f"{self.type} {{") def build_tail(self): return _indentln("};") @@ -231,7 +231,7 @@ class Option(Buildable): self.iterable = self.params def build(self): - header = _indentln("{}(".format(self.type)) + header = _indentln(f"{self.type}(") tail = _indentln(");") body = self.build_body() @@ -304,7 +304,7 @@ class TypedParameter(Parameter): self.iterable = self.values def build(self): - header = _indentln("{}(".format(self.type)) + header = _indentln(f"{self.type}(") tail = _indent(")") body = self.build_body() @@ -372,7 +372,7 @@ class TypedParameterValue(ParameterValue): self.iterable = self.arguments def build(self): - header = _indentln("{}(".format(self.type)) + header = _indentln(f"{self.type}(") tail = _indent(")") body = self.build_body() @@ -822,7 +822,7 @@ def config_test(syslog_ng_sbin_dir=None, cfgfile=None): """ params = ["--syntax-only"] if cfgfile: - params.append("--cfgfile={}".format(cfgfile)) + params.append(f"--cfgfile={cfgfile}") try: ret = _run_command_in_extended_path(syslog_ng_sbin_dir, "syslog-ng", params) @@ -936,7 +936,7 @@ def _add_cli_param(params, key, value): Adds key and value as a command line parameter to params. """ if value is not None: - params.append("--{}={}".format(key, value)) + params.append(f"--{key}={value}") def _add_boolean_cli_param(params, key, value): @@ -944,7 +944,7 @@ def _add_boolean_cli_param(params, key, value): Adds key as a command line parameter to params. """ if value is True: - params.append("--{}".format(key)) + params.append(f"--{key}") def stop(name=None): @@ -1040,7 +1040,7 @@ def start( command = [syslog_ng_binary] + params if __opts__.get("test", False): - comment = "Syslog_ng state module will start {}".format(command) + comment = f"Syslog_ng state module will start {command}" return _format_state_result(name, result=None, comment=comment) result = __salt__["cmd.run_all"](command, python_shell=False) @@ -1048,7 +1048,7 @@ def start( command = ["syslog-ng"] + params if __opts__.get("test", False): - comment = "Syslog_ng state module will start {}".format(command) + comment = f"Syslog_ng state module will start {command}" return _format_state_result(name, result=None, comment=comment) result = __salt__["cmd.run_all"](command, python_shell=False) @@ -1156,7 +1156,7 @@ def write_version(name): salt '*' syslog_ng.write_version name="3.6" """ - line = "@version: {}".format(name) + line = f"@version: {name}" try: if os.path.exists(__SYSLOG_NG_CONFIG_FILE): log.debug( diff --git a/salt/modules/system.py b/salt/modules/system.py index 5d1be5f6fd2..bcdce7a434c 100644 --- a/salt/modules/system.py +++ b/salt/modules/system.py @@ -67,7 +67,7 @@ def init(runlevel): salt '*' system.init 3 """ - cmd = ["init", "{}".format(runlevel)] + cmd = ["init", f"{runlevel}"] ret = __salt__["cmd.run"](cmd, python_shell=False) return ret @@ -100,7 +100,7 @@ def reboot(at_time=None): salt '*' system.reboot """ - cmd = ["shutdown", "-r", ("{}".format(at_time) if at_time else "now")] + cmd = ["shutdown", "-r", (f"{at_time}" if at_time else "now")] ret = __salt__["cmd.run"](cmd, python_shell=False) return ret @@ -128,7 +128,7 @@ def shutdown(at_time=None): else: flag = "-h" - cmd = ["shutdown", flag, ("{}".format(at_time) if at_time else "now")] + cmd = ["shutdown", flag, (f"{at_time}" if at_time else "now")] ret = __salt__["cmd.run"](cmd, python_shell=False) return ret @@ -592,7 +592,7 @@ def set_computer_desc(desc): pass pattern = re.compile(r"^\s*PRETTY_HOSTNAME=(.*)$") - new_line = salt.utils.stringutils.to_str('PRETTY_HOSTNAME="{}"'.format(desc)) + new_line = salt.utils.stringutils.to_str(f'PRETTY_HOSTNAME="{desc}"') try: with salt.utils.files.fopen("/etc/machine-info", "r+") as mach_info: lines = mach_info.readlines() @@ -669,10 +669,10 @@ def set_reboot_required_witnessed(): os.makedirs(dir_path) except OSError as ex: raise SaltInvocationError( - "Error creating {} (-{}): {}".format(dir_path, ex.errno, ex.strerror) + f"Error creating {dir_path} (-{ex.errno}): {ex.strerror}" ) - rdict = __salt__["cmd.run_all"]("touch {}".format(NILRT_REBOOT_WITNESS_PATH)) + rdict = __salt__["cmd.run_all"](f"touch {NILRT_REBOOT_WITNESS_PATH}") errcode = rdict["retcode"] return errcode == 0 diff --git a/salt/modules/systemd_service.py b/salt/modules/systemd_service.py index dd27106afd0..858495647f2 100644 --- a/salt/modules/systemd_service.py +++ b/salt/modules/systemd_service.py @@ -135,7 +135,7 @@ def _check_for_unit_changes(name): Check for modified/updated unit files, and run a daemon-reload if any are found. """ - contextkey = "systemd._check_for_unit_changes.{}".format(name) + contextkey = f"systemd._check_for_unit_changes.{name}" if contextkey not in __context__: if _untracked_custom_unit_found(name) or _unit_file_changed(name): systemctl_reload() @@ -377,7 +377,7 @@ def _sysv_enabled(name, root): runlevel. """ # Find exact match (disambiguate matches like "S01anacron" for cron) - rc = _root("/etc/rc{}.d/S*{}".format(_runlevel(), name), root) + rc = _root(f"/etc/rc{_runlevel()}.d/S*{name}", root) for match in glob.glob(rc): if re.match(r"S\d{,2}%s" % name, os.path.basename(match)): return True @@ -1451,7 +1451,7 @@ def firstboot( ] for parameter, value in parameters: if value: - cmd.extend(["--{}".format(parameter), str(value)]) + cmd.extend([f"--{parameter}", str(value)]) out = __salt__["cmd.run_all"](cmd) diff --git a/salt/modules/telegram.py b/salt/modules/telegram.py index e0f2f969045..3d1e73cca4d 100644 --- a/salt/modules/telegram.py +++ b/salt/modules/telegram.py @@ -104,7 +104,7 @@ def _post_message(message, chat_id, token): :param token: The Telegram API token. :return: Boolean if message was sent successfully. """ - url = "https://api.telegram.org/bot{}/sendMessage".format(token) + url = f"https://api.telegram.org/bot{token}/sendMessage" parameters = dict() if chat_id: diff --git a/salt/modules/telemetry.py b/salt/modules/telemetry.py index c55c94668ca..3fc4b902d5c 100644 --- a/salt/modules/telemetry.py +++ b/salt/modules/telemetry.py @@ -72,7 +72,7 @@ def _auth(api_key=None, profile="telemetry"): def _update_cache(deployment_id, metric_name, alert): - key = "telemetry.{}.alerts".format(deployment_id) + key = f"telemetry.{deployment_id}.alerts" if key in __context__: alerts = __context__[key] @@ -133,7 +133,7 @@ def get_alert_config( auth = _auth(profile=profile) alert = False - key = "telemetry.{}.alerts".format(deployment_id) + key = f"telemetry.{deployment_id}.alerts" if key not in __context__: try: @@ -209,9 +209,7 @@ def get_notification_channel_id(notify_channel, profile="telemetry"): notification_channel_id = response.json().get("_id") __context__["telemetry.channels"][notify_channel] = notification_channel_id else: - raise Exception( - "Failed to created notification channel {}".format(notify_channel) - ) + raise Exception(f"Failed to created notification channel {notify_channel}") return notification_channel_id @@ -233,8 +231,7 @@ def get_alarms(deployment_id, profile="telemetry"): try: response = requests.get( - _get_telemetry_base(profile) - + "/alerts?deployment={}".format(deployment_id), + _get_telemetry_base(profile) + f"/alerts?deployment={deployment_id}", headers=auth, timeout=120, ) @@ -248,7 +245,7 @@ def get_alarms(deployment_id, profile="telemetry"): if alarms: return alarms - return "No alarms defined for deployment: {}".format(deployment_id) + return f"No alarms defined for deployment: {deployment_id}" else: # Non 200 response, sent back the error response' return { @@ -276,7 +273,7 @@ def create_alarm(deployment_id, metric_name, data, api_key=None, profile="teleme auth = _auth(api_key, profile) request_uri = _get_telemetry_base(profile) + "/alerts" - key = "telemetry.{}.alerts".format(deployment_id) + key = f"telemetry.{deployment_id}.alerts" # set the notification channels if not already set post_body = { @@ -428,12 +425,12 @@ def delete_alarms( if not alert_ids: return ( False, - "failed to find alert associated with deployment: {}".format(deployment_id), + f"failed to find alert associated with deployment: {deployment_id}", ) failed_to_delete = [] for id in alert_ids: - delete_url = _get_telemetry_base(profile) + "/alerts/{}".format(id) + delete_url = _get_telemetry_base(profile) + f"/alerts/{id}" try: response = requests.delete(delete_url, headers=auth, timeout=120) diff --git a/salt/modules/test.py b/salt/modules/test.py index fe4c8ec9ae1..b98a0dbc99e 100644 --- a/salt/modules/test.py +++ b/salt/modules/test.py @@ -79,7 +79,7 @@ def module_report(): if hasattr(__salt__, ref): ret["module_attrs"].append(ref) for func in __salt__[ref]: - full = "{}.{}".format(ref, func) + full = f"{ref}.{func}" if hasattr(getattr(__salt__, ref), func): ret["function_attrs"].append(full) if func in __salt__[ref]: @@ -427,7 +427,7 @@ def provider(module): """ func = "" for key in __salt__: - if not key.startswith("{}.".format(module)): + if not key.startswith(f"{module}."): continue func = key break diff --git a/salt/modules/testinframod.py b/salt/modules/testinframod.py index eb7254a09d6..bac95da5c65 100644 --- a/salt/modules/testinframod.py +++ b/salt/modules/testinframod.py @@ -150,7 +150,7 @@ def _apply_assertion(expected, result): raise return comparison(expected["expected"], result) else: - raise TypeError("Expected bool or dict but received {}".format(type(expected))) + raise TypeError(f"Expected bool or dict but received {type(expected)}") # This does not currently generate documentation from the underlying modules diff --git a/salt/modules/textfsm_mod.py b/salt/modules/textfsm_mod.py index bcade66de15..e11dd5afbb7 100644 --- a/salt/modules/textfsm_mod.py +++ b/salt/modules/textfsm_mod.py @@ -476,5 +476,5 @@ def index( ret["result"] = True except clitable.CliTableError as cterr: log.error("Unable to proces the CliTable", exc_info=True) - ret["comment"] = "Unable to process the output: {}".format(cterr) + ret["comment"] = f"Unable to process the output: {cterr}" return ret diff --git a/salt/modules/timezone.py b/salt/modules/timezone.py index 26d37943987..115ec06eeef 100644 --- a/salt/modules/timezone.py +++ b/salt/modules/timezone.py @@ -144,7 +144,7 @@ def _get_zone_etc_timezone(): return salt.utils.stringutils.to_unicode(fp_.read()).strip() except OSError as exc: raise CommandExecutionError( - "Problem reading timezone file {}: {}".format(tzfile, exc.strerror) + f"Problem reading timezone file {tzfile}: {exc.strerror}" ) @@ -240,7 +240,7 @@ def get_offset(): salt_path = "/opt/salt/bin/date" if not os.path.exists(salt_path): - return "date in salt binaries does not exist: {}".format(salt_path) + return f"date in salt binaries does not exist: {salt_path}" return __salt__["cmd.run"]([salt_path, "+%z"], python_shell=False) @@ -273,24 +273,24 @@ def set_zone(timezone): """ if salt.utils.path.which("timedatectl"): try: - __salt__["cmd.run"]("timedatectl set-timezone {}".format(timezone)) + __salt__["cmd.run"](f"timedatectl set-timezone {timezone}") except CommandExecutionError: pass if "Solaris" in __grains__["os_family"] or "AIX" in __grains__["os_family"]: - zonepath = "/usr/share/lib/zoneinfo/{}".format(timezone) + zonepath = f"/usr/share/lib/zoneinfo/{timezone}" else: - zonepath = "/usr/share/zoneinfo/{}".format(timezone) + zonepath = f"/usr/share/zoneinfo/{timezone}" if not os.path.exists(zonepath) and "AIX" not in __grains__["os_family"]: - return "Zone does not exist: {}".format(zonepath) + return f"Zone does not exist: {zonepath}" tzfile = _get_localtime_path() if os.path.exists(tzfile): os.unlink(tzfile) if "Solaris" in __grains__["os_family"]: - __salt__["file.sed"]("/etc/default/init", "^TZ=.*", "TZ={}".format(timezone)) + __salt__["file.sed"]("/etc/default/init", "^TZ=.*", f"TZ={timezone}") elif "AIX" in __grains__["os_family"]: # timezone could be Olson or Posix curtzstring = get_zone() @@ -307,12 +307,10 @@ def set_zone(timezone): os.symlink(zonepath, tzfile) if "RedHat" in __grains__["os_family"]: - __salt__["file.sed"]( - "/etc/sysconfig/clock", "^ZONE=.*", 'ZONE="{}"'.format(timezone) - ) + __salt__["file.sed"]("/etc/sysconfig/clock", "^ZONE=.*", f'ZONE="{timezone}"') elif "Suse" in __grains__["os_family"]: __salt__["file.sed"]( - "/etc/sysconfig/clock", "^TIMEZONE=.*", 'TIMEZONE="{}"'.format(timezone) + "/etc/sysconfig/clock", "^TIMEZONE=.*", f'TIMEZONE="{timezone}"' ) elif "Debian" in __grains__["os_family"] or "Gentoo" in __grains__["os_family"]: with salt.utils.files.fopen("/etc/timezone", "w") as ofh: @@ -361,9 +359,7 @@ def zone_compare(timezone): except OSError as exc: problematic_file = exc.filename if problematic_file == zonepath: - raise SaltInvocationError( - 'Can\'t find a local timezone "{}"'.format(timezone) - ) + raise SaltInvocationError(f'Can\'t find a local timezone "{timezone}"') elif problematic_file == tzfile: raise CommandExecutionError( "Failed to read {} to determine current timezone: {}".format( @@ -383,7 +379,7 @@ def _get_localtime_path(): def _get_zone_file(timezone): - return "/usr/share/zoneinfo/{}".format(timezone) + return f"/usr/share/zoneinfo/{timezone}" def get_hwclock(): @@ -453,7 +449,7 @@ def get_hwclock(): if line == "local": return "LOCAL" raise CommandExecutionError( - "Correct offset value not found in {}".format(offset_file) + f"Correct offset value not found in {offset_file}" ) except OSError as exc: raise CommandExecutionError( @@ -555,10 +551,10 @@ def set_hwclock(clock): cmd = ["rtc", "-z", "GMT" if clock.lower() == "utc" else timezone] return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 - zonepath = "/usr/share/zoneinfo/{}".format(timezone) + zonepath = f"/usr/share/zoneinfo/{timezone}" if not os.path.exists(zonepath): - raise CommandExecutionError("Zone '{}' does not exist".format(zonepath)) + raise CommandExecutionError(f"Zone '{zonepath}' does not exist") os.unlink("/etc/localtime") os.symlink(zonepath, "/etc/localtime") @@ -572,13 +568,13 @@ def set_hwclock(clock): return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 elif "RedHat" in __grains__["os_family"]: __salt__["file.sed"]( - "/etc/sysconfig/clock", "^ZONE=.*", 'ZONE="{}"'.format(timezone) + "/etc/sysconfig/clock", "^ZONE=.*", f'ZONE="{timezone}"' ) elif "Suse" in __grains__["os_family"]: __salt__["file.sed"]( "/etc/sysconfig/clock", "^TIMEZONE=.*", - 'TIMEZONE="{}"'.format(timezone), + f'TIMEZONE="{timezone}"', ) elif "Debian" in __grains__["os_family"]: if clock == "UTC": @@ -590,14 +586,10 @@ def set_hwclock(clock): raise SaltInvocationError("Only 'UTC' and 'localtime' are allowed") if clock == "localtime": clock = "local" - __salt__["file.sed"]( - "/etc/conf.d/hwclock", "^clock=.*", 'clock="{}"'.format(clock) - ) + __salt__["file.sed"]("/etc/conf.d/hwclock", "^clock=.*", f'clock="{clock}"') elif "Slackware" in os_family: if clock not in ("UTC", "localtime"): raise SaltInvocationError("Only 'UTC' and 'localtime' are allowed") - __salt__["file.sed"]( - "/etc/hardwareclock", "^(UTC|localtime)", "{}".format(clock) - ) + __salt__["file.sed"]("/etc/hardwareclock", "^(UTC|localtime)", f"{clock}") return True diff --git a/salt/modules/tls.py b/salt/modules/tls.py index d54922a26c9..2cc3c09119a 100644 --- a/salt/modules/tls.py +++ b/salt/modules/tls.py @@ -169,7 +169,7 @@ def _microtime(): """ val1, val2 = math.modf(time.time()) val2 = int(val2) - return "{:f}{}".format(val1, val2) + return f"{val1:f}{val2}" def _context_or_config(key): @@ -249,7 +249,7 @@ def _new_serial(ca_name): # record the hash somewhere cachedir = __opts__["cachedir"] log.debug("cachedir: %s", cachedir) - serial_file = "{}/{}.serial".format(cachedir, ca_name) + serial_file = f"{cachedir}/{ca_name}.serial" if not os.path.exists(cachedir): os.makedirs(cachedir) if not os.path.exists(serial_file): @@ -271,9 +271,9 @@ def _get_basic_info(ca_name, cert, ca_dir=None): Get basic info to write out to the index.txt """ if ca_dir is None: - ca_dir = "{}/{}".format(_cert_base_path(), ca_name) + ca_dir = f"{_cert_base_path()}/{ca_name}" - index_file = "{}/index.txt".format(ca_dir) + index_file = f"{ca_dir}/index.txt" cert = _read_cert(cert) expire_date = _four_digit_year_to_two_digit(_get_expiration_date(cert)) @@ -283,9 +283,7 @@ def _get_basic_info(ca_name, cert, ca_dir=None): subject = "/" # then we can add the rest of the subject - subject += "/".join( - ["{}={}".format(x, y) for x, y in cert.get_subject().get_components()] - ) + subject += "/".join([f"{x}={y}" for x, y in cert.get_subject().get_components()]) subject += "\n" return (index_file, expire_date, serial_number, subject) @@ -302,7 +300,7 @@ def _write_cert_to_database(ca_name, cert, cacert_path=None, status="V"): certificate to be recorded """ set_ca_path(cacert_path) - ca_dir = "{}/{}".format(cert_base_path(), ca_name) + ca_dir = f"{cert_base_path()}/{ca_name}" index_file, expire_date, serial_number, subject = _get_basic_info( ca_name, cert, ca_dir ) @@ -338,9 +336,9 @@ def maybe_fix_ssl_version(ca_name, cacert_path=None, ca_filename=None): """ set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) - certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) - ca_keyp = "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + ca_filename = f"{ca_name}_ca_cert" + certp = f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" + ca_keyp = f"{cert_base_path()}/{ca_name}/{ca_filename}.key" with salt.utils.files.fopen(certp) as fic: cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, fic.read()) if cert.get_version() == 3: @@ -398,8 +396,8 @@ def ca_exists(ca_name, cacert_path=None, ca_filename=None): """ set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) - certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + ca_filename = f"{ca_name}_ca_cert" + certp = f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" if os.path.exists(certp): maybe_fix_ssl_version(ca_name, cacert_path=cacert_path, ca_filename=ca_filename) return True @@ -431,7 +429,7 @@ def get_ca(ca_name, as_text=False, cacert_path=None): set_ca_path(cacert_path) certp = "{0}/{1}/{1}_ca_cert.crt".format(cert_base_path(), ca_name) if not os.path.exists(certp): - raise ValueError("Certificate does not exist for {}".format(ca_name)) + raise ValueError(f"Certificate does not exist for {ca_name}") else: if as_text: with salt.utils.files.fopen(certp) as fic: @@ -468,9 +466,9 @@ def get_ca_signed_cert( if not cert_filename: cert_filename = CN - certp = "{}/{}/certs/{}.crt".format(cert_base_path(), ca_name, cert_filename) + certp = f"{cert_base_path()}/{ca_name}/certs/{cert_filename}.crt" if not os.path.exists(certp): - raise ValueError("Certificate does not exists for {}".format(CN)) + raise ValueError(f"Certificate does not exists for {CN}") else: if as_text: with salt.utils.files.fopen(certp) as fic: @@ -512,9 +510,9 @@ def get_ca_signed_key( if not key_filename: key_filename = CN - keyp = "{}/{}/certs/{}.key".format(cert_base_path(), ca_name, key_filename) + keyp = f"{cert_base_path()}/{ca_name}/certs/{key_filename}.key" if not os.path.exists(keyp): - raise ValueError("Certificate does not exists for {}".format(CN)) + raise ValueError(f"Certificate does not exists for {CN}") else: if as_text: with salt.utils.files.fopen(keyp) as fic: @@ -559,10 +557,10 @@ def validate(cert, ca_name, crl_file): cert_obj = _read_cert(cert) if cert_obj is None: raise CommandExecutionError( - "Failed to read cert from {}, see log for details".format(cert) + f"Failed to read cert from {cert}, see log for details" ) - ca_dir = "{}/{}".format(cert_base_path(), ca_name) - ca_cert = _read_cert("{}/{}_ca_cert.crt".format(ca_dir, ca_name)) + ca_dir = f"{cert_base_path()}/{ca_name}" + ca_cert = _read_cert(f"{ca_dir}/{ca_name}_ca_cert.crt") store.add_cert(ca_cert) # These flags tell OpenSSL to check the leaf as well as the # entire cert chain. @@ -594,7 +592,7 @@ def _get_expiration_date(cert): if cert_obj is None: raise CommandExecutionError( - "Failed to read cert from {}, see log for details".format(cert) + f"Failed to read cert from {cert}, see log for details" ) return datetime.strptime( @@ -734,18 +732,18 @@ def create_ca( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" - certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) - ca_keyp = "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + certp = f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" + ca_keyp = f"{cert_base_path()}/{ca_name}/{ca_filename}.key" if not replace and not fixmode and ca_exists(ca_name, ca_filename=ca_filename): - return 'Certificate for CA named "{}" already exists'.format(ca_name) + return f'Certificate for CA named "{ca_name}" already exists' if fixmode and not os.path.exists(certp): - raise ValueError("{} does not exists, can't fix".format(certp)) + raise ValueError(f"{certp} does not exists, can't fix") - if not os.path.exists("{}/{}".format(cert_base_path(), ca_name)): - os.makedirs("{}/{}".format(cert_base_path(), ca_name)) + if not os.path.exists(f"{cert_base_path()}/{ca_name}"): + os.makedirs(f"{cert_base_path()}/{ca_name}") # try to reuse existing ssl key key = None @@ -932,9 +930,7 @@ def get_extensions(cert_type): # possible user-defined profile or a typo if cert_type not in ext: try: - ext[cert_type] = __salt__["pillar.get"]( - "tls.extensions:{}".format(cert_type) - ) + ext[cert_type] = __salt__["pillar.get"](f"tls.extensions:{cert_type}") except NameError as e: log.debug( "pillar, tls:extensions:%s not available or " @@ -1071,7 +1067,7 @@ def create_csr( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if not ca_exists(ca_name, ca_filename=ca_filename): return 'Certificate for CA named "{}" does not exist, please create it first.'.format( @@ -1079,20 +1075,20 @@ def create_csr( ) if not csr_path: - csr_path = "{}/{}/certs/".format(cert_base_path(), ca_name) + csr_path = f"{cert_base_path()}/{ca_name}/certs/" if not os.path.exists(csr_path): os.makedirs(csr_path) - CN_ext = "_{}".format(cert_type) if type_ext else "" + CN_ext = f"_{cert_type}" if type_ext else "" if not csr_filename: - csr_filename = "{}{}".format(CN, CN_ext) + csr_filename = f"{CN}{CN_ext}" - csr_f = "{}/{}.csr".format(csr_path, csr_filename) + csr_f = f"{csr_path}/{csr_filename}.csr" if not replace and os.path.exists(csr_f): - return 'Certificate Request "{}" already exists'.format(csr_f) + return f'Certificate Request "{csr_f}" already exists' key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) @@ -1153,7 +1149,7 @@ def create_csr( req.sign(key, salt.utils.stringutils.to_str(digest)) # Write private key and request - priv_keyp = "{}/{}.key".format(csr_path, csr_filename) + priv_keyp = f"{csr_path}/{csr_filename}.key" fp = os.open(priv_keyp, os.O_CREAT | os.O_RDWR, 0o600) with salt.utils.files.fopen(fp, "wb+") as priv_key: priv_key.write( @@ -1171,8 +1167,8 @@ def create_csr( ) ) - ret = 'Created Private Key: "{}{}.key" '.format(csr_path, csr_filename) - ret += 'Created CSR for "{}": "{}{}.csr"'.format(CN, csr_path, csr_filename) + ret = f'Created Private Key: "{csr_path}{csr_filename}.key" ' + ret += f'Created CSR for "{CN}": "{csr_path}{csr_filename}.csr"' return ret @@ -1255,16 +1251,16 @@ def create_self_signed_cert( """ set_ca_path(cacert_path) - if not os.path.exists("{}/{}/certs/".format(cert_base_path(), tls_dir)): - os.makedirs("{}/{}/certs/".format(cert_base_path(), tls_dir)) + if not os.path.exists(f"{cert_base_path()}/{tls_dir}/certs/"): + os.makedirs(f"{cert_base_path()}/{tls_dir}/certs/") if not cert_filename: cert_filename = CN if not replace and os.path.exists( - "{}/{}/certs/{}.crt".format(cert_base_path(), tls_dir, cert_filename) + f"{cert_base_path()}/{tls_dir}/certs/{cert_filename}.crt" ): - return 'Certificate "{}" already exists'.format(cert_filename) + return f'Certificate "{cert_filename}" already exists' key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) @@ -1303,7 +1299,7 @@ def create_self_signed_cert( ) ) - crt_path = "{}/{}/certs/{}.crt".format(cert_base_path(), tls_dir, cert_filename) + crt_path = f"{cert_base_path()}/{tls_dir}/certs/{cert_filename}.crt" with salt.utils.files.fopen(crt_path, "wb+") as crt: crt.write( salt.utils.stringutils.to_bytes( @@ -1431,10 +1427,10 @@ def create_ca_signed_cert( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if not cert_path: - cert_path = "{}/{}/certs".format(cert_base_path(), ca_name) + cert_path = f"{cert_base_path()}/{ca_name}/certs" if type_ext: if not cert_type: @@ -1443,14 +1439,14 @@ def create_ca_signed_cert( ) return ret elif cert_type: - CN_ext = "_{}".format(cert_type) + CN_ext = f"_{cert_type}" else: CN_ext = "" - csr_filename = "{}{}".format(CN, CN_ext) + csr_filename = f"{CN}{CN_ext}" if not cert_filename: - cert_filename = "{}{}".format(CN, CN_ext) + cert_filename = f"{CN}{CN_ext}" if not replace and os.path.exists( os.path.join( @@ -1461,29 +1457,29 @@ def create_ca_signed_cert( ) ) ): - return 'Certificate "{}" already exists'.format(cert_filename) + return f'Certificate "{cert_filename}" already exists' try: maybe_fix_ssl_version(ca_name, cacert_path=cacert_path, ca_filename=ca_filename) with salt.utils.files.fopen( - "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" ) as fhr: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) with salt.utils.files.fopen( - "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.key" ) as fhr: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: ret["retcode"] = 1 - ret["comment"] = 'There is no CA named "{}"'.format(ca_name) + ret["comment"] = f'There is no CA named "{ca_name}"' return ret try: - csr_path = "{}/{}.csr".format(cert_path, csr_filename) + csr_path = f"{cert_path}/{csr_filename}.csr" with salt.utils.files.fopen(csr_path) as fhr: req = OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_PEM, fhr.read() @@ -1539,7 +1535,7 @@ def create_ca_signed_cert( cert.sign(ca_key, salt.utils.stringutils.to_str(digest)) - cert_full_path = "{}/{}.crt".format(cert_path, cert_filename) + cert_full_path = f"{cert_path}/{cert_filename}.crt" with salt.utils.files.fopen(cert_full_path, "wb+") as crt: crt.write( @@ -1590,10 +1586,8 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): salt '*' tls.create_pkcs12 test localhost """ set_ca_path(cacert_path) - if not replace and os.path.exists( - "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN) - ): - return 'Certificate "{}" already exists'.format(CN) + if not replace and os.path.exists(f"{cert_base_path()}/{ca_name}/certs/{CN}.p12"): + return f'Certificate "{CN}" already exists' try: with salt.utils.files.fopen( @@ -1603,23 +1597,23 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: - return 'There is no CA named "{}"'.format(ca_name) + return f'There is no CA named "{ca_name}"' try: with salt.utils.files.fopen( - "{}/{}/certs/{}.crt".format(cert_base_path(), ca_name, CN) + f"{cert_base_path()}/{ca_name}/certs/{CN}.crt" ) as fhr: cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) with salt.utils.files.fopen( - "{}/{}/certs/{}.key".format(cert_base_path(), ca_name, CN) + f"{cert_base_path()}/{ca_name}/certs/{CN}.key" ) as fhr: key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: - return 'There is no certificate that matches the CN "{}"'.format(CN) + return f'There is no certificate that matches the CN "{CN}"' pkcs12 = OpenSSL.crypto.PKCS12() @@ -1628,7 +1622,7 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): pkcs12.set_privatekey(key) with salt.utils.files.fopen( - "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN), "wb" + f"{cert_base_path()}/{ca_name}/certs/{CN}.p12", "wb" ) as ofile: ofile.write( pkcs12.export(passphrase=salt.utils.stringutils.to_bytes(passphrase)) @@ -1780,29 +1774,29 @@ def create_empty_crl( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if not crl_file: - crl_file = "{}/{}/crl.pem".format(_cert_base_path(), ca_name) + crl_file = f"{_cert_base_path()}/{ca_name}/crl.pem" - if os.path.exists("{}".format(crl_file)): - return 'CRL "{}" already exists'.format(crl_file) + if os.path.exists(f"{crl_file}"): + return f'CRL "{crl_file}" already exists' try: with salt.utils.files.fopen( - "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" ) as fp_: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) with salt.utils.files.fopen( - "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.key" ) as fp_: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) except OSError: - return 'There is no CA named "{}"'.format(ca_name) + return f'There is no CA named "{ca_name}"' crl = OpenSSL.crypto.CRL() crl_text = crl.export( @@ -1814,7 +1808,7 @@ def create_empty_crl( with salt.utils.files.fopen(crl_file, "w") as f: f.write(salt.utils.stringutils.to_str(crl_text)) - return 'Created an empty CRL: "{}"'.format(crl_file) + return f'Created an empty CRL: "{crl_file}"' def revoke_cert( @@ -1870,43 +1864,43 @@ def revoke_cert( """ set_ca_path(cacert_path) - ca_dir = "{}/{}".format(cert_base_path(), ca_name) + ca_dir = f"{cert_base_path()}/{ca_name}" if ca_filename is None: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if cert_path is None: - cert_path = "{}/{}/certs".format(_cert_base_path(), ca_name) + cert_path = f"{_cert_base_path()}/{ca_name}/certs" if cert_filename is None: - cert_filename = "{}".format(CN) + cert_filename = f"{CN}" try: with salt.utils.files.fopen( - "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" ) as fp_: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) with salt.utils.files.fopen( - "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.key" ) as fp_: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) except OSError: - return 'There is no CA named "{}"'.format(ca_name) + return f'There is no CA named "{ca_name}"' - client_cert = _read_cert("{}/{}.crt".format(cert_path, cert_filename)) + client_cert = _read_cert(f"{cert_path}/{cert_filename}.crt") if client_cert is None: - return 'There is no client certificate named "{}"'.format(CN) + return f'There is no client certificate named "{CN}"' index_file, expire_date, serial_number, subject = _get_basic_info( ca_name, client_cert, ca_dir ) - index_serial_subject = "{}\tunknown\t{}".format(serial_number, subject) - index_v_data = "V\t{}\t\t{}".format(expire_date, index_serial_subject) + index_serial_subject = f"{serial_number}\tunknown\t{subject}" + index_v_data = f"V\t{expire_date}\t\t{index_serial_subject}" index_r_data_pattern = re.compile( r"R\t" + expire_date + r"\t\d{12}Z\t" + re.escape(index_serial_subject) ) @@ -1963,11 +1957,11 @@ def revoke_cert( ) if crl_file is None: - crl_file = "{}/{}/crl.pem".format(_cert_base_path(), ca_name) + crl_file = f"{_cert_base_path()}/{ca_name}/crl.pem" if os.path.isdir(crl_file): ret["retcode"] = 1 - ret["comment"] = 'crl_file "{}" is an existing directory'.format(crl_file) + ret["comment"] = f'crl_file "{crl_file}" is an existing directory' return ret with salt.utils.files.fopen(crl_file, "w") as fp_: diff --git a/salt/modules/tomcat.py b/salt/modules/tomcat.py index d9f9f28e276..b1ff4a1364d 100644 --- a/salt/modules/tomcat.py +++ b/salt/modules/tomcat.py @@ -214,11 +214,11 @@ def _wget(cmd, opts=None, url="http://localhost:8080/manager", timeout=180): if url[-1] != "/": url += "/" url6 = url - url += "text/{}".format(cmd) - url6 += "{}".format(cmd) + url += f"text/{cmd}" + url6 += f"{cmd}" if opts: - url += "?{}".format(urllib.parse.urlencode(opts)) - url6 += "?{}".format(urllib.parse.urlencode(opts)) + url += f"?{urllib.parse.urlencode(opts)}" + url6 += f"?{urllib.parse.urlencode(opts)}" # Make the HTTP request urllib.request.install_opener(auth) @@ -257,7 +257,7 @@ def _simple_cmd(cmd, app, url="http://localhost:8080/manager", timeout=180): opts = {"path": app, "version": ls(url)[app]["version"]} return "\n".join(_wget(cmd, opts, url, timeout=timeout)["msg"]) except Exception: # pylint: disable=broad-except - return "FAIL - No context exists for path {}".format(app) + return f"FAIL - No context exists for path {app}" # Functions @@ -565,10 +565,10 @@ def deploy_war( salt '*' tomcat.deploy_war /tmp/application.war /api yes http://localhost:8080/manager """ # Decide the location to copy the war for the deployment - tfile = "salt.{}".format(os.path.basename(war)) + tfile = f"salt.{os.path.basename(war)}" if temp_war_location is not None: if not os.path.isdir(temp_war_location): - return 'Error - "{}" is not a directory'.format(temp_war_location) + return f'Error - "{temp_war_location}" is not a directory' tfile = os.path.join(temp_war_location, tfile) else: tfile = os.path.join(tempfile.gettempdir(), tfile) @@ -589,7 +589,7 @@ def deploy_war( # Prepare options opts = { - "war": "file:{}".format(tfile), + "war": f"file:{tfile}", "path": context, } @@ -707,7 +707,7 @@ def signal(signal=None): if signal not in valid_signals: return - cmd = "{}/bin/catalina.sh {}".format(__catalina_home(), valid_signals[signal]) + cmd = f"{__catalina_home()}/bin/catalina.sh {valid_signals[signal]}" __salt__["cmd.run"](cmd) diff --git a/salt/modules/transactional_update.py b/salt/modules/transactional_update.py index 71f6427b15e..c216d6e32ed 100644 --- a/salt/modules/transactional_update.py +++ b/salt/modules/transactional_update.py @@ -952,7 +952,7 @@ def call(function, *args, **kwargs): function, ] + list(args) - + ["{}={}".format(k, v) for (k, v) in safe_kwargs.items()] + + [f"{k}={v}" for (k, v) in safe_kwargs.items()] ) try: @@ -1062,7 +1062,7 @@ def sls(mods, activate_transaction=False, queue=False, **kwargs): mods, activate_transaction=activate_transaction, concurrent=concurrent, - **kwargs + **kwargs, ) @@ -1102,7 +1102,7 @@ def highstate(activate_transaction=False, queue=False, **kwargs): "state.highstate", activate_transaction=activate_transaction, concurrent=True, - **kwargs + **kwargs, ) @@ -1145,5 +1145,5 @@ def single(fun, name, activate_transaction=False, queue=False, **kwargs): name=name, activate_transaction=activate_transaction, concurrent=True, - **kwargs + **kwargs, ) diff --git a/salt/modules/tuned.py b/salt/modules/tuned.py index 8db9ea83e98..8b8b5c62534 100644 --- a/salt/modules/tuned.py +++ b/salt/modules/tuned.py @@ -110,7 +110,7 @@ def profile(profile_name): """ # run tuned-adm with the profile specified - result = __salt__["cmd.retcode"]("tuned-adm profile {}".format(profile_name)) + result = __salt__["cmd.retcode"](f"tuned-adm profile {profile_name}") if int(result) != 0: return False - return "{}".format(profile_name) + return f"{profile_name}" diff --git a/salt/modules/udev.py b/salt/modules/udev.py index 9a734edf4b7..0e4a7473eda 100644 --- a/salt/modules/udev.py +++ b/salt/modules/udev.py @@ -97,7 +97,7 @@ def info(dev): else: qtype = "name" - cmd = "udevadm info --export --query=all --{}={}".format(qtype, dev) + cmd = f"udevadm info --export --query=all --{qtype}={dev}" udev_result = __salt__["cmd.run_all"](cmd, output_loglevel="quiet") if udev_result["retcode"] != 0: diff --git a/salt/modules/upstart_service.py b/salt/modules/upstart_service.py index ee47f6d002a..c59da325e3d 100644 --- a/salt/modules/upstart_service.py +++ b/salt/modules/upstart_service.py @@ -159,7 +159,7 @@ def _runlevel(): ret = _default_runlevel() utmp = _find_utmp() if utmp: - out = __salt__["cmd.run"](["runlevel", "{}".format(utmp)], python_shell=False) + out = __salt__["cmd.run"](["runlevel", f"{utmp}"], python_shell=False) try: ret = out.split()[1] except IndexError: @@ -180,7 +180,7 @@ def _service_is_upstart(name): Jobs are defined in files placed in /etc/init, the name of the job is the filename under this directory without the .conf extension. """ - return os.access("/etc/init/{}.conf".format(name), os.R_OK) + return os.access(f"/etc/init/{name}.conf", os.R_OK) def _upstart_is_disabled(name): @@ -190,7 +190,7 @@ def _upstart_is_disabled(name): NOTE: An Upstart service can also be disabled by placing "manual" in /etc/init/[name].conf. """ - files = ["/etc/init/{}.conf".format(name), "/etc/init/{}.override".format(name)] + files = [f"/etc/init/{name}.conf", f"/etc/init/{name}.override"] for file_name in filter(os.path.isfile, files): with salt.utils.files.fopen(file_name) as fp_: if re.search( @@ -217,7 +217,7 @@ def _service_is_sysv(name): to Upstart's /lib/init/upstart-job, and anything that isn't an executable, like README or skeleton. """ - script = "/etc/init.d/{}".format(name) + script = f"/etc/init.d/{name}" return not _service_is_upstart(name) and os.access(script, os.X_OK) @@ -227,7 +227,7 @@ def _sysv_is_disabled(name): start-up link (starts with "S") to its script in /etc/init.d in the current runlevel. """ - return not bool(glob.glob("/etc/rc{}.d/S*{}".format(_runlevel(), name))) + return not bool(glob.glob(f"/etc/rc{_runlevel()}.d/S*{name}")) def _sysv_is_enabled(name): @@ -508,7 +508,7 @@ def _upstart_disable(name): """ if _upstart_is_disabled(name): return _upstart_is_disabled(name) - override = "/etc/init/{}.override".format(name) + override = f"/etc/init/{name}.override" with salt.utils.files.fopen(override, "a") as ofile: ofile.write(salt.utils.stringutils.to_str("manual\n")) return _upstart_is_disabled(name) @@ -520,8 +520,8 @@ def _upstart_enable(name): """ if _upstart_is_enabled(name): return _upstart_is_enabled(name) - override = "/etc/init/{}.override".format(name) - files = ["/etc/init/{}.conf".format(name), override] + override = f"/etc/init/{name}.override" + files = [f"/etc/init/{name}.conf", override] for file_name in filter(os.path.isfile, files): with salt.utils.files.fopen(file_name, "r+") as fp_: new_text = re.sub( @@ -552,7 +552,7 @@ def enable(name, **kwargs): if _service_is_upstart(name): return _upstart_enable(name) executable = _get_service_exec() - cmd = "{} -f {} defaults".format(executable, name) + cmd = f"{executable} -f {name} defaults" return not __salt__["cmd.retcode"](cmd, python_shell=False) diff --git a/salt/modules/uptime.py b/salt/modules/uptime.py index 34ebff403a1..702e01ec51a 100644 --- a/salt/modules/uptime.py +++ b/salt/modules/uptime.py @@ -42,17 +42,15 @@ def create(name, **params): """ if check_exists(name): - msg = "Trying to create check that already exists : {}".format(name) + msg = f"Trying to create check that already exists : {name}" log.error(msg) raise CommandExecutionError(msg) application_url = _get_application_url() log.debug("[uptime] trying PUT request") params.update(url=name) - req = requests.put( - "{}/api/checks".format(application_url), data=params, timeout=120 - ) + req = requests.put(f"{application_url}/api/checks", data=params, timeout=120) if not req.ok: - raise CommandExecutionError("request to uptime failed : {}".format(req.reason)) + raise CommandExecutionError(f"request to uptime failed : {req.reason}") log.debug("[uptime] PUT request successful") return req.json()["_id"] @@ -68,18 +66,16 @@ def delete(name): salt '*' uptime.delete http://example.org """ if not check_exists(name): - msg = "Trying to delete check that doesn't exists : {}".format(name) + msg = f"Trying to delete check that doesn't exists : {name}" log.error(msg) raise CommandExecutionError(msg) application_url = _get_application_url() log.debug("[uptime] trying DELETE request") - jcontent = requests.get("{}/api/checks".format(application_url), timeout=120).json() + jcontent = requests.get(f"{application_url}/api/checks", timeout=120).json() url_id = [x["_id"] for x in jcontent if x["url"] == name][0] - req = requests.delete( - "{}/api/checks/{}".format(application_url, url_id), timeout=120 - ) + req = requests.delete(f"{application_url}/api/checks/{url_id}", timeout=120) if not req.ok: - raise CommandExecutionError("request to uptime failed : {}".format(req.reason)) + raise CommandExecutionError(f"request to uptime failed : {req.reason}") log.debug("[uptime] DELETE request successful") return True @@ -109,7 +105,7 @@ def checks_list(): """ application_url = _get_application_url() log.debug("[uptime] get checks") - jcontent = requests.get("{}/api/checks".format(application_url), timeout=120).json() + jcontent = requests.get(f"{application_url}/api/checks", timeout=120).json() return [x["url"] for x in jcontent] diff --git a/salt/modules/useradd.py b/salt/modules/useradd.py index 604573cca0a..68f9c314ab4 100644 --- a/salt/modules/useradd.py +++ b/salt/modules/useradd.py @@ -106,7 +106,7 @@ def _which(cmd): """ _cmd = salt.utils.path.which(cmd) if not _cmd: - raise CommandExecutionError("Command '{}' cannot be found".format(cmd)) + raise CommandExecutionError(f"Command '{cmd}' cannot be found") return _cmd @@ -429,7 +429,7 @@ def _chattrib(name, key, value, param, persist=False, root=None): """ pre_info = info(name, root=root) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if value == pre_info[key]: return True @@ -911,7 +911,7 @@ def rename(name, new_name, root=None): salt '*' user.rename name new_name """ if info(new_name, root=root): - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") return _chattrib(name, "name", new_name, "-l", root=root) diff --git a/salt/modules/uwsgi.py b/salt/modules/uwsgi.py index 2ede5c17da7..71ced4a4088 100644 --- a/salt/modules/uwsgi.py +++ b/salt/modules/uwsgi.py @@ -40,6 +40,6 @@ def stats(socket): salt '*' uwsgi.stats 127.0.0.1:5050 """ - cmd = ["uwsgi", "--connect-and-read", "{}".format(socket)] + cmd = ["uwsgi", "--connect-and-read", f"{socket}"] out = __salt__["cmd.run"](cmd, python_shell=False) return salt.utils.json.loads(out) diff --git a/salt/modules/vagrant.py b/salt/modules/vagrant.py index f34eae5e98e..7c214b1f59d 100644 --- a/salt/modules/vagrant.py +++ b/salt/modules/vagrant.py @@ -62,7 +62,7 @@ def _build_sdb_uri(key): Salt node id's are used as the key for vm_ dicts. """ - return "{}{}".format(VAGRANT_SDB_URL, key) + return f"{VAGRANT_SDB_URL}{key}" def _build_machine_uri(machine, cwd): @@ -73,7 +73,7 @@ def _build_machine_uri(machine, cwd): never collide with a Salt node id -- which is important since we will be storing both in the same table. """ - key = "{}?{}".format(machine, os.path.abspath(cwd)) + key = f"{machine}?{os.path.abspath(cwd)}" return _build_sdb_uri(key) @@ -102,9 +102,7 @@ def get_vm_info(name): "Probable sdb driver not found. Check your configuration." ) if vm_ is None or "machine" not in vm_: - raise SaltInvocationError( - "No Vagrant machine defined for Salt_id {}".format(name) - ) + raise SaltInvocationError(f"No Vagrant machine defined for Salt_id {name}") return vm_ @@ -161,7 +159,7 @@ def _vagrant_ssh_config(vm_): """ machine = vm_["machine"] log.info("requesting vagrant ssh-config for VM %s", machine or "(default)") - cmd = "vagrant ssh-config {}".format(machine) + cmd = f"vagrant ssh-config {machine}" reply = __salt__["cmd.shell"]( cmd, runas=vm_.get("runas"), cwd=vm_.get("cwd"), ignore_retcode=True ) @@ -305,12 +303,12 @@ def vm_state(name="", cwd=None): else: if not cwd: raise SaltInvocationError( - "Path to Vagranfile must be defined, but cwd={}".format(cwd) + f"Path to Vagranfile must be defined, but cwd={cwd}" ) machine = "" info = [] - cmd = "vagrant status {}".format(machine) + cmd = f"vagrant status {machine}" reply = __salt__["cmd.shell"](cmd, cwd) log.info("--->\n%s", reply) for line in reply.split("\n"): # build a list of the text reply @@ -404,13 +402,11 @@ def _start( try: machine = vm_["machine"] except KeyError: - raise SaltInvocationError( - "No Vagrant machine defined for Salt_id {}".format(name) - ) + raise SaltInvocationError(f"No Vagrant machine defined for Salt_id {name}") vagrant_provider = vm_.get("vagrant_provider", "") - provider_ = "--provider={}".format(vagrant_provider) if vagrant_provider else "" - cmd = "vagrant up {} {}".format(machine, provider_) + provider_ = f"--provider={vagrant_provider}" if vagrant_provider else "" + cmd = f"vagrant up {machine} {provider_}" ret = __salt__["cmd.run_all"]( cmd, runas=vm_.get("runas"), cwd=vm_.get("cwd"), output_loglevel="info" ) @@ -424,7 +420,7 @@ def _start( break if ret["retcode"] == 0: - return 'Started "{}" using Vagrant machine "{}".'.format(name, machine) + return f'Started "{name}" using Vagrant machine "{machine}".' return False @@ -458,7 +454,7 @@ def stop(name): vm_ = get_vm_info(name) machine = vm_["machine"] - cmd = "vagrant halt {}".format(machine) + cmd = f"vagrant halt {machine}" ret = __salt__["cmd.retcode"](cmd, runas=vm_.get("runas"), cwd=vm_.get("cwd")) return ret == 0 @@ -476,7 +472,7 @@ def pause(name): vm_ = get_vm_info(name) machine = vm_["machine"] - cmd = "vagrant suspend {}".format(machine) + cmd = f"vagrant suspend {machine}" ret = __salt__["cmd.retcode"](cmd, runas=vm_.get("runas"), cwd=vm_.get("cwd")) return ret == 0 @@ -498,7 +494,7 @@ def reboot(name, provision=False): machine = vm_["machine"] prov = "--provision" if provision else "" - cmd = "vagrant reload {} {}".format(machine, prov) + cmd = f"vagrant reload {machine} {prov}" ret = __salt__["cmd.retcode"](cmd, runas=vm_.get("runas"), cwd=vm_.get("cwd")) return ret == 0 @@ -518,14 +514,14 @@ def destroy(name): vm_ = get_vm_info(name) machine = vm_["machine"] - cmd = "vagrant destroy -f {}".format(machine) + cmd = f"vagrant destroy -f {machine}" ret = __salt__["cmd.run_all"]( cmd, runas=vm_.get("runas"), cwd=vm_.get("cwd"), output_loglevel="info" ) if ret["retcode"] == 0: _erase_vm_info(name) - return "Destroyed VM {}".format(name) + return f"Destroyed VM {name}" return False @@ -637,6 +633,6 @@ def get_ssh_config(name, network_mask="", get_private_key=False): ans["private_key"] = salt.utils.stringutils.to_unicode(pks.read()) except OSError as e: raise CommandExecutionError( - "Error processing Vagrant private key file: {}".format(e) + f"Error processing Vagrant private key file: {e}" ) return ans diff --git a/salt/modules/vault.py b/salt/modules/vault.py index 8dc2e5868d0..0c524640041 100644 --- a/salt/modules/vault.py +++ b/salt/modules/vault.py @@ -257,7 +257,7 @@ def read_secret(path, key=None, metadata=False, default=NOT_SET): path = version2["data"] log.debug("Reading Vault secret for %s at %s", __grains__["id"], path) try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("GET", url) if response.status_code != 200: response.raise_for_status() @@ -278,7 +278,7 @@ def read_secret(path, key=None, metadata=False, default=NOT_SET): except Exception as err: # pylint: disable=broad-except if default is CommandExecutionError: raise CommandExecutionError( - "Failed to read secret! {}: {}".format(type(err).__name__, err) + f"Failed to read secret! {type(err).__name__}: {err}" ) return default @@ -300,7 +300,7 @@ def write_secret(path, **kwargs): path = version2["data"] data = {"data": data} try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("POST", url, json=data) if response.status_code == 200: return response.json()["data"] @@ -328,7 +328,7 @@ def write_raw(path, raw): path = version2["data"] raw = {"data": raw} try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("POST", url, json=raw) if response.status_code == 200: return response.json()["data"] @@ -355,7 +355,7 @@ def delete_secret(path): if version2["v2"]: path = version2["data"] try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("DELETE", url) if response.status_code != 204: response.raise_for_status() @@ -387,7 +387,7 @@ def destroy_secret(path, *args): log.error("Destroy operation is only supported on KV version 2") return False try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("POST", url, json=data) if response.status_code != 204: response.raise_for_status() @@ -420,7 +420,7 @@ def list_secrets(path, default=NOT_SET): if version2["v2"]: path = version2["metadata"] try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("LIST", url) if response.status_code != 200: response.raise_for_status() @@ -428,7 +428,7 @@ def list_secrets(path, default=NOT_SET): except Exception as err: # pylint: disable=broad-except if default is CommandExecutionError: raise CommandExecutionError( - "Failed to list secrets! {}: {}".format(type(err).__name__, err) + f"Failed to list secrets! {type(err).__name__}: {err}" ) return default diff --git a/salt/modules/vboxmanage.py b/salt/modules/vboxmanage.py index 39ca6ecb3e6..290de89dfe3 100644 --- a/salt/modules/vboxmanage.py +++ b/salt/modules/vboxmanage.py @@ -85,7 +85,7 @@ def list_nodes_min(): salt '*' vboxmanage.list_nodes_min """ ret = {} - cmd = "{} list vms".format(vboxcmd()) + cmd = f"{vboxcmd()} list vms" for line in salt.modules.cmdmod.run(cmd).splitlines(): if not line.strip(): continue @@ -147,7 +147,7 @@ def start(name): salt '*' vboxmanage.start my_vm """ ret = {} - cmd = "{} startvm {}".format(vboxcmd(), name) + cmd = f"{vboxcmd()} startvm {name}" ret = salt.modules.cmdmod.run(cmd).splitlines() return ret @@ -162,7 +162,7 @@ def stop(name): salt '*' vboxmanage.stop my_vm """ - cmd = "{} controlvm {} poweroff".format(vboxcmd(), name) + cmd = f"{vboxcmd()} controlvm {name} poweroff" ret = salt.modules.cmdmod.run(cmd).splitlines() return ret @@ -179,10 +179,10 @@ def register(filename): """ if not os.path.isfile(filename): raise CommandExecutionError( - "The specified filename ({}) does not exist.".format(filename) + f"The specified filename ({filename}) does not exist." ) - cmd = "{} registervm {}".format(vboxcmd(), filename) + cmd = f"{vboxcmd()} registervm {filename}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -201,11 +201,9 @@ def unregister(name, delete=False): """ nodes = list_nodes_min() if name not in nodes: - raise CommandExecutionError( - "The specified VM ({}) is not registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is not registered.") - cmd = "{} unregistervm {}".format(vboxcmd(), name) + cmd = f"{vboxcmd()} unregistervm {name}" if delete is True: cmd += " --delete" ret = salt.modules.cmdmod.run_all(cmd) @@ -234,7 +232,7 @@ def create( register=True, basefolder=None, new_uuid=None, - **kwargs + **kwargs, ): """ Create a new VM @@ -247,16 +245,14 @@ def create( """ nodes = list_nodes_min() if name in nodes: - raise CommandExecutionError( - "The specified VM ({}) is already registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is already registered.") params = "" if name: if NAME_RE.search(name): raise CommandExecutionError("New VM name contains invalid characters") - params += " --name {}".format(name) + params += f" --name {name}" if groups: if isinstance(groups, str): @@ -270,9 +266,7 @@ def create( ostypes = list_ostypes() if ostype not in ostypes: - raise CommandExecutionError( - "The specified OS type ({}) is not available.".format(name) - ) + raise CommandExecutionError(f"The specified OS type ({name}) is not available.") else: params += " --ostype " + ostype @@ -281,17 +275,15 @@ def create( if basefolder: if not os.path.exists(basefolder): - raise CommandExecutionError( - "basefolder {} was not found".format(basefolder) - ) - params += " --basefolder {}".format(basefolder) + raise CommandExecutionError(f"basefolder {basefolder} was not found") + params += f" --basefolder {basefolder}" if new_uuid: if NAME_RE.search(new_uuid): raise CommandExecutionError("New UUID contains invalid characters") - params += " --uuid {}".format(new_uuid) + params += f" --uuid {new_uuid}" - cmd = "{} create {}".format(vboxcmd(), params) + cmd = f"{vboxcmd()} create {params}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -310,7 +302,7 @@ def clonevm( new_uuid=None, register=False, groups=None, - **kwargs + **kwargs, ): """ Clone a new VM from an existing VM @@ -331,15 +323,11 @@ def clonevm( nodes_uuids = list_items("vms", True, "UUID").keys() if name: if name not in nodes_names: - raise CommandExecutionError( - "The specified VM ({}) is not registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is not registered.") params += " " + name elif uuid: if uuid not in nodes_uuids: - raise CommandExecutionError( - "The specified VM ({}) is not registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is not registered.") params += " " + uuid if snapshot_name and snapshot_uuid: @@ -350,11 +338,11 @@ def clonevm( if snapshot_name: if NAME_RE.search(snapshot_name): raise CommandExecutionError("Snapshot name contains invalid characters") - params += " --snapshot {}".format(snapshot_name) + params += f" --snapshot {snapshot_name}" elif snapshot_uuid: if UUID_RE.search(snapshot_uuid): raise CommandExecutionError("Snapshot name contains invalid characters") - params += " --snapshot {}".format(snapshot_uuid) + params += f" --snapshot {snapshot_uuid}" valid_modes = ("machine", "machineandchildren", "all") if mode and mode not in valid_modes: @@ -375,7 +363,7 @@ def clonevm( if new_name: if NAME_RE.search(new_name): raise CommandExecutionError("New name contains invalid characters") - params += " --name {}".format(new_name) + params += f" --name {new_name}" if groups: if isinstance(groups, str): @@ -389,20 +377,18 @@ def clonevm( if basefolder: if not os.path.exists(basefolder): - raise CommandExecutionError( - "basefolder {} was not found".format(basefolder) - ) - params += " --basefolder {}".format(basefolder) + raise CommandExecutionError(f"basefolder {basefolder} was not found") + params += f" --basefolder {basefolder}" if new_uuid: if NAME_RE.search(new_uuid): raise CommandExecutionError("New UUID contains invalid characters") - params += " --uuid {}".format(new_uuid) + params += f" --uuid {new_uuid}" if register is True: params += " --register" - cmd = "{} clonevm {}".format(vboxcmd(), name) + cmd = f"{vboxcmd()} clonevm {name}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -418,7 +404,7 @@ def clonemedium( mformat=None, variant=None, existing=False, - **kwargs + **kwargs, ): """ Clone a new VM from an existing VM @@ -454,11 +440,11 @@ def clonemedium( items = list_items(item) if uuid_in not in items: - raise CommandExecutionError("UUID {} was not found".format(uuid_in)) + raise CommandExecutionError(f"UUID {uuid_in} was not found") params += " " + uuid_in elif file_in: if not os.path.exists(file_in): - raise CommandExecutionError("File {} was not found".format(file_in)) + raise CommandExecutionError(f"File {file_in} was not found") params += " " + file_in if (uuid_out and file_out) or (not uuid_out and not file_out): @@ -476,7 +462,7 @@ def clonemedium( os.unlink(file_out) params += " " + file_out except OSError: - raise CommandExecutionError("{} is not a valid filename".format(file_out)) + raise CommandExecutionError(f"{file_out} is not a valid filename") if mformat: valid_mformat = ("VDI", "VMDK", "VHD", "RAW") @@ -503,7 +489,7 @@ def clonemedium( if existing: params += " --existing" - cmd = "{} clonemedium {}".format(vboxcmd(), params) + cmd = f"{vboxcmd()} clonemedium {params}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -586,7 +572,7 @@ def list_items(item, details=False, group_by="UUID"): ret = {} tmp_id = None tmp_dict = {} - cmd = "{} list{} {}".format(vboxcmd(), flag, item) + cmd = f"{vboxcmd()} list{flag} {item}" for line in salt.modules.cmdmod.run(cmd).splitlines(): if not line.strip(): continue diff --git a/salt/modules/victorops.py b/salt/modules/victorops.py index 3f41a0b8ba4..058e0f3ed4a 100644 --- a/salt/modules/victorops.py +++ b/salt/modules/victorops.py @@ -48,10 +48,10 @@ def _query( path = "https://alert.victorops.com/integrations/generic/20131114/" if action: - path += "{}/".format(action) + path += f"{action}/" if api_key: - path += "{}/".format(api_key) + path += f"{api_key}/" if routing_key: path += routing_key diff --git a/salt/modules/virtualenv_mod.py b/salt/modules/virtualenv_mod.py index e662b339214..36fd6c9d93d 100644 --- a/salt/modules/virtualenv_mod.py +++ b/salt/modules/virtualenv_mod.py @@ -20,7 +20,7 @@ from salt.exceptions import CommandExecutionError, SaltInvocationError KNOWN_BINARY_NAMES = frozenset( [ "virtualenv-{}.{}".format(*sys.version_info[:2]), - "virtualenv{}".format(sys.version_info[0]), + f"virtualenv{sys.version_info[0]}", "virtualenv", ] ) @@ -87,7 +87,7 @@ def create( user=None, use_vt=False, saltenv="base", - **kwargs + **kwargs, ): """ Create a virtualenv @@ -211,15 +211,13 @@ def create( if python is not None and python.strip() != "": if not salt.utils.path.which(python): - raise CommandExecutionError( - "Cannot find requested python ({}).".format(python) - ) - cmd.append("--python={}".format(python)) + raise CommandExecutionError(f"Cannot find requested python ({python}).") + cmd.append(f"--python={python}") if extra_search_dir is not None: if isinstance(extra_search_dir, str) and extra_search_dir.strip() != "": extra_search_dir = [e.strip() for e in extra_search_dir.split(",")] for entry in extra_search_dir: - cmd.append("--extra-search-dir={}".format(entry)) + cmd.append(f"--extra-search-dir={entry}") if never_download is True: if (1, 10) <= virtualenv_version_info < (14, 0, 0): log.info( @@ -230,7 +228,7 @@ def create( else: cmd.append("--never-download") if prompt is not None and prompt.strip() != "": - cmd.append("--prompt='{}'".format(prompt)) + cmd.append(f"--prompt='{prompt}'") else: # venv module from the Python >= 3.3 standard library @@ -499,7 +497,7 @@ def _install_script(source, cwd, python, user, saltenv="base", use_vt=False): def _verify_safe_py_code(*args): for arg in args: if not salt.utils.verify.safe_py_code(arg): - raise SaltInvocationError("Unsafe python code detected in '{}'".format(arg)) + raise SaltInvocationError(f"Unsafe python code detected in '{arg}'") def _verify_virtualenv(venv_path): diff --git a/salt/modules/vmctl.py b/salt/modules/vmctl.py index 01021c3225f..01334383f92 100644 --- a/salt/modules/vmctl.py +++ b/salt/modules/vmctl.py @@ -59,7 +59,7 @@ def create_disk(name, size): salt '*' vmctl.create_disk /path/to/disk.img size=10G """ ret = False - cmd = "vmctl create {} -s {}".format(name, size) + cmd = f"vmctl create {name} -s {size}" result = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False) @@ -88,7 +88,7 @@ def load(path): salt '*' vmctl.load path=/etc/vm.switches.conf """ ret = False - cmd = "vmctl load {}".format(path) + cmd = f"vmctl load {path}" result = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False) if result["retcode"] == 0: ret = True @@ -226,7 +226,7 @@ def start( name = _id_to_name(id) if nics > 0: - cmd.append("-i {}".format(nics)) + cmd.append(f"-i {nics}") # Paths cannot be appended as otherwise the inserted whitespace is treated by # vmctl as being part of the path. @@ -234,10 +234,10 @@ def start( cmd.extend(["-b", bootpath]) if memory: - cmd.append("-m {}".format(memory)) + cmd.append(f"-m {memory}") if switch: - cmd.append("-n {}".format(switch)) + cmd.append(f"-n {switch}") if local_iface: cmd.append("-L") diff --git a/salt/modules/vsphere.py b/salt/modules/vsphere.py index 95dc3e03c29..667257e0ee5 100644 --- a/salt/modules/vsphere.py +++ b/salt/modules/vsphere.py @@ -355,7 +355,7 @@ def _get_proxy_connection_details(): elif proxytype == "esxvm": details = __salt__["esxvm.get_details"]() else: - raise CommandExecutionError("'{}' proxy is not supported".format(proxytype)) + raise CommandExecutionError(f"'{proxytype}' proxy is not supported") proxy_details = [ details.get("vcenter") if "vcenter" in details else details.get("host"), details.get("username"), @@ -783,7 +783,7 @@ def coredump_network_enable( enable_it = 1 else: enable_it = 0 - cmd = "system coredump network set -e {}".format(enable_it) + cmd = f"system coredump network set -e {enable_it}" ret = {} if esxi_hosts: @@ -1662,7 +1662,7 @@ def upload_ssh_key( if certificate_verify is None: certificate_verify = True - url = "{}://{}:{}/host/ssh_root_authorized_keys".format(protocol, host, port) + url = f"{protocol}://{host}:{port}/host/ssh_root_authorized_keys" ret = {} result = None try: @@ -1733,7 +1733,7 @@ def get_ssh_key( if certificate_verify is None: certificate_verify = True - url = "{}://{}:{}/host/ssh_root_authorized_keys".format(protocol, host, port) + url = f"{protocol}://{host}:{port}/host/ssh_root_authorized_keys" ret = {} try: result = salt.utils.http.query( @@ -1997,11 +1997,7 @@ def get_service_policy( # If we don't have a valid service, return. The service will be invalid for all hosts. if service_name not in valid_services: ret.update( - { - host_name: { - "Error": "{} is not a valid service name.".format(service_name) - } - } + {host_name: {"Error": f"{service_name} is not a valid service name."}} ) return ret @@ -2029,7 +2025,7 @@ def get_service_policy( # If we made it this far, something else has gone wrong. if ret.get(host_name) is None: - msg = "'vsphere.get_service_policy' failed for host {}.".format(host_name) + msg = f"'vsphere.get_service_policy' failed for host {host_name}." log.debug(msg) ret.update({host_name: {"Error": msg}}) @@ -2140,11 +2136,7 @@ def get_service_running( # If we don't have a valid service, return. The service will be invalid for all hosts. if service_name not in valid_services: ret.update( - { - host_name: { - "Error": "{} is not a valid service name.".format(service_name) - } - } + {host_name: {"Error": f"{service_name} is not a valid service name."}} ) return ret @@ -2172,7 +2164,7 @@ def get_service_running( # If we made it this far, something else has gone wrong. if ret.get(host_name) is None: - msg = "'vsphere.get_service_running' failed for host {}.".format(host_name) + msg = f"'vsphere.get_service_running' failed for host {host_name}." log.debug(msg) ret.update({host_name: {"Error": msg}}) @@ -2329,7 +2321,7 @@ def get_vsan_enabled( # We must have a VSAN Config in place get information about VSAN state. if vsan_config is None: - msg = "VSAN System Config Manager is unset for host '{}'.".format(host_name) + msg = f"VSAN System Config Manager is unset for host '{host_name}'." log.debug(msg) ret.update({host_name: {"Error": msg}}) else: @@ -3236,7 +3228,7 @@ def set_ntp_config( try: date_time_manager.UpdateDateTimeConfig(config=date_config) except vim.fault.HostConfigFault as err: - msg = "vsphere.ntp_configure_servers failed: {}".format(err) + msg = f"vsphere.ntp_configure_servers failed: {err}" log.debug(msg) ret.update({host_name: {"Error": msg}}) continue @@ -3355,11 +3347,7 @@ def service_start( # If we don't have a valid service, return. The service will be invalid for all hosts. if service_name not in valid_services: ret.update( - { - host_name: { - "Error": "{} is not a valid service name.".format(service_name) - } - } + {host_name: {"Error": f"{service_name} is not a valid service name."}} ) return ret @@ -3498,11 +3486,7 @@ def service_stop( # If we don't have a valid service, return. The service will be invalid for all hosts. if service_name not in valid_services: ret.update( - { - host_name: { - "Error": "{} is not a valid service name.".format(service_name) - } - } + {host_name: {"Error": f"{service_name} is not a valid service name."}} ) return ret @@ -3514,7 +3498,7 @@ def service_stop( try: service_manager.StopService(id=temp_service_name) except vim.fault.HostConfigFault as err: - msg = "'vsphere.service_stop' failed for host {}: {}".format(host_name, err) + msg = f"'vsphere.service_stop' failed for host {host_name}: {err}" log.debug(msg) ret.update({host_name: {"Error": msg}}) continue @@ -3639,11 +3623,7 @@ def service_restart( # If we don't have a valid service, return. The service will be invalid for all hosts. if service_name not in valid_services: ret.update( - { - host_name: { - "Error": "{} is not a valid service name.".format(service_name) - } - } + {host_name: {"Error": f"{service_name} is not a valid service name."}} ) return ret @@ -3780,11 +3760,7 @@ def set_service_policy( # If we don't have a valid service, return. The service will be invalid for all hosts. if service_name not in valid_services: ret.update( - { - host_name: { - "Error": "{} is not a valid service name.".format(service_name) - } - } + {host_name: {"Error": f"{service_name} is not a valid service name."}} ) return ret @@ -3811,7 +3787,7 @@ def set_service_policy( id=service_key, policy=service_policy ) except vim.fault.NotFound: - msg = "The service name '{}' was not found.".format(service_name) + msg = f"The service name '{service_name}' was not found." log.debug(msg) ret.update({host_name: {"Error": msg}}) continue @@ -4056,7 +4032,7 @@ def vmotion_disable( try: vmotion_system.DeselectVnic() except vim.fault.HostConfigFault as err: - msg = "vsphere.vmotion_disable failed: {}".format(err) + msg = f"vsphere.vmotion_disable failed: {err}" log.debug(msg) ret.update({host_name: {"Error": msg, "VMotion Disabled": False}}) continue @@ -4144,7 +4120,7 @@ def vmotion_enable( try: vmotion_system.SelectVnic(device) except vim.fault.HostConfigFault as err: - msg = "vsphere.vmotion_disable failed: {}".format(err) + msg = f"vsphere.vmotion_disable failed: {err}" log.debug(msg) ret.update({host_name: {"Error": msg, "VMotion Enabled": False}}) continue @@ -4871,7 +4847,7 @@ def create_dvs(dvs_dict, dvs_name, service_instance=None): dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs_name]) if not dvs_refs: raise VMwareObjectRetrievalError( - "DVS '{}' wasn't found in datacenter '{}'".format(dvs_name, datacenter) + f"DVS '{dvs_name}' wasn't found in datacenter '{datacenter}'" ) dvs_ref = dvs_refs[0] salt.utils.vmware.set_dvs_network_resource_management_enabled( @@ -4924,7 +4900,7 @@ def update_dvs(dvs_dict, dvs, service_instance=None): dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs]) if not dvs_refs: raise VMwareObjectRetrievalError( - "DVS '{}' wasn't found in datacenter '{}'".format(dvs, datacenter) + f"DVS '{dvs}' wasn't found in datacenter '{datacenter}'" ) dvs_ref = dvs_refs[0] # Build the config spec from the input @@ -5155,7 +5131,7 @@ def list_dvportgroups(dvs=None, portgroup_names=None, service_instance=None): if dvs: dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs]) if not dvs_refs: - raise VMwareObjectRetrievalError("DVS '{}' was not retrieved".format(dvs)) + raise VMwareObjectRetrievalError(f"DVS '{dvs}' was not retrieved") dvs_ref = dvs_refs[0] get_all_portgroups = True if not portgroup_names else False for pg_ref in salt.utils.vmware.get_dvportgroups( @@ -5198,7 +5174,7 @@ def list_uplink_dvportgroup(dvs, service_instance=None): dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter) dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs]) if not dvs_refs: - raise VMwareObjectRetrievalError("DVS '{}' was not retrieved".format(dvs)) + raise VMwareObjectRetrievalError(f"DVS '{dvs}' was not retrieved") uplink_pg_ref = salt.utils.vmware.get_uplink_dvportgroup(dvs_refs[0]) return _get_dvportgroup_dict(uplink_pg_ref) @@ -5433,7 +5409,7 @@ def create_dvportgroup(portgroup_dict, portgroup_name, dvs, service_instance=Non dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter) dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs]) if not dvs_refs: - raise VMwareObjectRetrievalError("DVS '{}' was not retrieved".format(dvs)) + raise VMwareObjectRetrievalError(f"DVS '{dvs}' was not retrieved") # Make the name of the dvportgroup consistent with the parameter portgroup_dict["name"] = portgroup_name spec = vim.DVPortgroupConfigSpec() @@ -5489,14 +5465,12 @@ def update_dvportgroup(portgroup_dict, portgroup, dvs, service_instance=True): dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter) dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs]) if not dvs_refs: - raise VMwareObjectRetrievalError("DVS '{}' was not retrieved".format(dvs)) + raise VMwareObjectRetrievalError(f"DVS '{dvs}' was not retrieved") pg_refs = salt.utils.vmware.get_dvportgroups( dvs_refs[0], portgroup_names=[portgroup] ) if not pg_refs: - raise VMwareObjectRetrievalError( - "Portgroup '{}' was not retrieved".format(portgroup) - ) + raise VMwareObjectRetrievalError(f"Portgroup '{portgroup}' was not retrieved") pg_props = salt.utils.vmware.get_properties_of_managed_object( pg_refs[0], ["config"] ) @@ -5555,14 +5529,12 @@ def remove_dvportgroup(portgroup, dvs, service_instance=None): dc_ref = salt.utils.vmware.get_datacenter(service_instance, datacenter) dvs_refs = salt.utils.vmware.get_dvss(dc_ref, dvs_names=[dvs]) if not dvs_refs: - raise VMwareObjectRetrievalError("DVS '{}' was not retrieved".format(dvs)) + raise VMwareObjectRetrievalError(f"DVS '{dvs}' was not retrieved") pg_refs = salt.utils.vmware.get_dvportgroups( dvs_refs[0], portgroup_names=[portgroup] ) if not pg_refs: - raise VMwareObjectRetrievalError( - "Portgroup '{}' was not retrieved".format(portgroup) - ) + raise VMwareObjectRetrievalError(f"Portgroup '{portgroup}' was not retrieved") salt.utils.vmware.remove_dvportgroup(pg_refs[0]) return True @@ -5833,7 +5805,7 @@ def update_storage_policy(policy, policy_dict, service_instance=None): profile_manager = salt.utils.pbm.get_profile_manager(service_instance) policies = salt.utils.pbm.get_storage_policies(profile_manager, [policy]) if not policies: - raise VMwareObjectRetrievalError("Policy '{}' was not found".format(policy)) + raise VMwareObjectRetrievalError(f"Policy '{policy}' was not found") policy_ref = policies[0] policy_update_spec = pbm.profile.CapabilityBasedProfileUpdateSpec() log.trace("Setting policy values in policy_update_spec") @@ -5876,9 +5848,7 @@ def list_default_storage_policy_of_datastore(datastore, service_instance=None): service_instance, target_ref, datastore_names=[datastore] ) if not ds_refs: - raise VMwareObjectRetrievalError( - "Datastore '{}' was not found".format(datastore) - ) + raise VMwareObjectRetrievalError(f"Datastore '{datastore}' was not found") profile_manager = salt.utils.pbm.get_profile_manager(service_instance) policy = salt.utils.pbm.get_default_storage_policy_of_datastore( profile_manager, ds_refs[0] @@ -5920,7 +5890,7 @@ def assign_default_storage_policy_to_datastore( # Find policy policies = salt.utils.pbm.get_storage_policies(profile_manager, [policy]) if not policies: - raise VMwareObjectRetrievalError("Policy '{}' was not found".format(policy)) + raise VMwareObjectRetrievalError(f"Policy '{policy}' was not found") policy_ref = policies[0] # Find datastore target_ref = _get_proxy_target(service_instance) @@ -5928,9 +5898,7 @@ def assign_default_storage_policy_to_datastore( service_instance, target_ref, datastore_names=[datastore] ) if not ds_refs: - raise VMwareObjectRetrievalError( - "Datastore '{}' was not found".format(datastore) - ) + raise VMwareObjectRetrievalError(f"Datastore '{datastore}' was not found") ds_ref = ds_refs[0] salt.utils.pbm.assign_default_storage_policy_to_datastore( profile_manager, policy_ref, ds_ref @@ -6656,7 +6624,7 @@ def create_vmfs_datastore( disks = salt.utils.vmware.get_disks(host_ref, disk_ids=[disk_id]) if not disks: raise VMwareObjectRetrievalError( - "Disk '{}' was not found in host '{}'".format(disk_id, hostname) + f"Disk '{disk_id}' was not found in host '{hostname}'" ) ds_ref = salt.utils.vmware.create_vmfs_datastore( host_ref, datastore_name, disks[0], vmfs_major_version @@ -6695,9 +6663,7 @@ def rename_datastore(datastore_name, new_datastore_name, service_instance=None): service_instance, target, datastore_names=[datastore_name] ) if not datastores: - raise VMwareObjectRetrievalError( - "Datastore '{}' was not found".format(datastore_name) - ) + raise VMwareObjectRetrievalError(f"Datastore '{datastore_name}' was not found") ds = datastores[0] salt.utils.vmware.rename_datastore(ds, new_datastore_name) return True @@ -6730,12 +6696,10 @@ def remove_datastore(datastore, service_instance=None): service_instance, reference=target, datastore_names=[datastore] ) if not datastores: - raise VMwareObjectRetrievalError( - "Datastore '{}' was not found".format(datastore) - ) + raise VMwareObjectRetrievalError(f"Datastore '{datastore}' was not found") if len(datastores) > 1: raise VMwareObjectRetrievalError( - "Multiple datastores '{}' were found".format(datastore) + f"Multiple datastores '{datastore}' were found" ) salt.utils.vmware.remove_datastore(service_instance, datastores[0]) return True @@ -6969,9 +6933,7 @@ def assign_license( if safety_checks: licenses = salt.utils.vmware.get_licenses(service_instance) if not [l for l in licenses if l.licenseKey == license_key]: - raise VMwareObjectRetrievalError( - "License '{}' wasn't found".format(license_name) - ) + raise VMwareObjectRetrievalError(f"License '{license_name}' wasn't found") salt.utils.vmware.assign_license( service_instance, license_key, @@ -7347,7 +7309,7 @@ def create_diskgroup( for id in disk_ids: if not [d for d in disks if d.canonicalName == id]: raise VMwareObjectRetrievalError( - "No disk with id '{}' was found in ESXi host '{}'".format(id, hostname) + f"No disk with id '{id}' was found in ESXi host '{hostname}'" ) cache_disk = [d for d in disks if d.canonicalName == cache_disk_id][0] capacity_disks = [d for d in disks if d.canonicalName in capacity_disk_ids] @@ -7596,7 +7558,7 @@ def get_host_cache(service_instance=None): return { "enabled": True, "datastore": {"name": hci.key.name}, - "swap_size": "{}MiB".format(hci.swapSize), + "swap_size": f"{hci.swapSize}MiB", } @@ -7660,7 +7622,7 @@ def configure_host_cache( ) if not ds_refs: raise VMwareObjectRetrievalError( - "Datastore '{}' was not found on host '{}'".format(datastore, hostname) + f"Datastore '{datastore}' was not found on host '{hostname}'" ) ds_ref = ds_refs[0] salt.utils.vmware.configure_host_cache(host_ref, ds_ref, swap_size_MiB) @@ -7959,7 +7921,7 @@ def _set_syslog_config_helper( """ Helper function for set_syslog_config that sets the config and populates the return dictionary. """ - cmd = "system syslog config set --{} {}".format(syslog_config, config_value) + cmd = f"system syslog config set --{syslog_config} {config_value}" ret_dict = {} valid_resets = [ @@ -7974,7 +7936,7 @@ def _set_syslog_config_helper( ret_dict.update( { "success": False, - "message": "'{}' is not a valid config variable.".format(syslog_config), + "message": f"'{syslog_config}' is not a valid config variable.", } ) return ret_dict @@ -8217,14 +8179,14 @@ def add_host_to_dvs( dvs = salt.utils.vmware._get_dvs(service_instance, dvs_name) if not dvs: ret["message"].append( - "No Distributed Virtual Switch found with name {}".format(dvs_name) + f"No Distributed Virtual Switch found with name {dvs_name}" ) ret["success"] = False target_portgroup = salt.utils.vmware._get_dvs_portgroup(dvs, target_portgroup_name) if not target_portgroup: ret["message"].append( - "No target portgroup found with name {}".format(target_portgroup_name) + f"No target portgroup found with name {target_portgroup_name}" ) ret["success"] = False @@ -8233,7 +8195,7 @@ def add_host_to_dvs( ) if not uplink_portgroup: ret["message"].append( - "No uplink portgroup found with name {}".format(uplink_portgroup_name) + f"No uplink portgroup found with name {uplink_portgroup_name}" ) ret["success"] = False @@ -8244,7 +8206,7 @@ def add_host_to_dvs( try: host_names = _check_hosts(service_instance, host, host_names) except CommandExecutionError as e: - ret["message"] = "Error retrieving hosts: {}".format(e.msg) + ret["message"] = f"Error retrieving hosts: {e.msg}" return ret for host_name in host_names: @@ -8271,9 +8233,7 @@ def add_host_to_dvs( p_nics = salt.utils.vmware._get_pnics(host_ref) p_nic = [x for x in p_nics if x.device == vmnic_name] if not p_nic: - ret[host_name].update( - {"message": "Physical nic {} not found".format(vmknic_name)} - ) + ret[host_name].update({"message": f"Physical nic {vmknic_name} not found"}) ret["success"] = False continue @@ -8281,9 +8241,7 @@ def add_host_to_dvs( v_nic = [x for x in v_nics if x.device == vmknic_name] if not v_nic: - ret[host_name].update( - {"message": "Virtual nic {} not found".format(vmnic_name)} - ) + ret[host_name].update({"message": f"Virtual nic {vmnic_name} not found"}) ret["success"] = False continue @@ -8376,7 +8334,7 @@ def add_host_to_dvs( except Exception as e: # pylint: disable=broad-except if hasattr(e, "msg"): ret[host_name].update( - {"message": "Failed to migrate adapters ({})".format(e.msg)} + {"message": f"Failed to migrate adapters ({e.msg})"} ) continue else: @@ -8875,7 +8833,7 @@ def _get_scsi_controller_key(bus_number, scsi_ctrls): ] if not keys: raise salt.exceptions.VMwareVmCreationError( - "SCSI controller number {} doesn't exist".format(bus_number) + f"SCSI controller number {bus_number} doesn't exist" ) return keys[0] @@ -9054,7 +9012,7 @@ def _create_network_backing(network_name, switch_type, parent_ref): ) if not networks: raise salt.exceptions.VMwareObjectRetrievalError( - "The network '{}' could not be retrieved.".format(network_name) + f"The network '{network_name}' could not be retrieved." ) network_ref = networks[0] backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo() @@ -9066,7 +9024,7 @@ def _create_network_backing(network_name, switch_type, parent_ref): ) if not networks: raise salt.exceptions.VMwareObjectRetrievalError( - "The port group '{}' could not be retrieved.".format(network_name) + f"The port group '{network_name}' could not be retrieved." ) network_ref = networks[0] dvs_port_connection = vim.dvs.PortConnection( @@ -9834,7 +9792,7 @@ def _get_device_by_key(devices, key): return device_keys[0] else: raise salt.exceptions.VMwareObjectNotFoundError( - "Virtual machine device with unique key {} does not exist".format(key) + f"Virtual machine device with unique key {key} does not exist" ) @@ -9854,7 +9812,7 @@ def _get_device_by_label(devices, label): return device_labels[0] else: raise salt.exceptions.VMwareObjectNotFoundError( - "Virtual machine device with label {} does not exist".format(label) + f"Virtual machine device with label {label} does not exist" ) @@ -11212,7 +11170,7 @@ def create_vm( )[0] if not datastore_object: raise salt.exceptions.ArgumentValueError( - "Specified datastore: '{}' does not exist.".format(datastore) + f"Specified datastore: '{datastore}' does not exist." ) try: ds_summary = salt.utils.vmware.get_properties_of_managed_object( @@ -11223,7 +11181,7 @@ def create_vm( "The vmPathName should be the datastore " "name if the datastore type is vsan" ) - config_spec.files.vmPathName = "[{}]".format(datastore) + config_spec.files.vmPathName = f"[{datastore}]" else: config_spec.files.vmPathName = "[{0}] {1}/{1}.vmx".format( datastore, vm_name diff --git a/salt/modules/webutil.py b/salt/modules/webutil.py index 746c9a7299b..bb5109d1c2a 100644 --- a/salt/modules/webutil.py +++ b/salt/modules/webutil.py @@ -65,7 +65,7 @@ def useradd(pwfile, user, password, opts="", runas=None): if not os.path.exists(pwfile): opts += "c" - cmd = ["htpasswd", "-b{}".format(opts), pwfile, user, password] + cmd = ["htpasswd", f"-b{opts}", pwfile, user, password] return __salt__["cmd.run_all"](cmd, runas=runas, python_shell=False) @@ -139,7 +139,7 @@ def verify(pwfile, user, password, opts="", runas=None): if not os.path.exists(pwfile): return False - cmd = ["htpasswd", "-bv{}".format(opts), pwfile, user, password] + cmd = ["htpasswd", f"-bv{opts}", pwfile, user, password] ret = __salt__["cmd.run_all"](cmd, runas=runas, python_shell=False) log.debug("Result of verifying htpasswd for user %s: %s", user, ret) diff --git a/salt/modules/win_certutil.py b/salt/modules/win_certutil.py index efed109e2c0..9a0fd737ff7 100644 --- a/salt/modules/win_certutil.py +++ b/salt/modules/win_certutil.py @@ -48,10 +48,10 @@ def get_cert_serial(cert_file, saltenv="base"): # Since we're allowing a path, let's make sure it exists if not os.path.exists(cert_file): - msg = "cert_file not found: {}".format(cert_file) + msg = f"cert_file not found: {cert_file}" raise CommandExecutionError(msg) - cmd = 'certutil.exe -silent -verify "{}"'.format(cert_file) + cmd = f'certutil.exe -silent -verify "{cert_file}"' out = __salt__["cmd.run"](cmd) # match serial number by paragraph to work with multiple languages matches = re.search(r":\s*(\w*)\r\n\r\n", out) @@ -77,7 +77,7 @@ def get_stored_cert_serials(store): salt '*' certutil.get_stored_cert_serials """ - cmd = 'certutil.exe -store "{}"'.format(store) + cmd = f'certutil.exe -store "{store}"' out = __salt__["cmd.run"](cmd) # match serial numbers by header position to work with multiple languages matches = re.findall(r"={16}\r\n.*:\s*(\w*)\r\n", out) @@ -112,10 +112,10 @@ def add_store(source, store, retcode=False, saltenv="base"): # Since we're allowing a path, let's make sure it exists if not os.path.exists(source): - msg = "cert_file not found: {}".format(source) + msg = f"cert_file not found: {source}" raise CommandExecutionError(msg) - cmd = 'certutil.exe -addstore {} "{}"'.format(store, source) + cmd = f'certutil.exe -addstore {store} "{source}"' if retcode: return __salt__["cmd.retcode"](cmd) else: @@ -150,11 +150,11 @@ def del_store(source, store, retcode=False, saltenv="base"): # Since we're allowing a path, let's make sure it exists if not os.path.exists(source): - msg = "cert_file not found: {}".format(source) + msg = f"cert_file not found: {source}" raise CommandExecutionError(msg) serial = get_cert_serial(source) - cmd = 'certutil.exe -delstore {} "{}"'.format(store, serial) + cmd = f'certutil.exe -delstore {store} "{serial}"' if retcode: return __salt__["cmd.retcode"](cmd) else: diff --git a/salt/modules/win_dacl.py b/salt/modules/win_dacl.py index d9114a56453..b8b5aca3dc3 100644 --- a/salt/modules/win_dacl.py +++ b/salt/modules/win_dacl.py @@ -512,7 +512,7 @@ def add_ace(path, objectType, user, permission, acetype, propagation): if acesAdded: ret["changes"]["Added ACEs"] = acesAdded else: - ret["comment"] = "Unable to obtain the DACL of {}".format(path) + ret["comment"] = f"Unable to obtain the DACL of {path}" else: ret["comment"] = "An empty value was specified for a required item." ret["result"] = False @@ -603,7 +603,7 @@ def rm_ace(path, objectType, user, permission=None, acetype=None, propagation=No ret["result"] = True except Exception as e: # pylint: disable=broad-except ret["result"] = False - ret["comment"] = "Error removing ACE. The error was {}.".format(e) + ret["comment"] = f"Error removing ACE. The error was {e}." return ret else: ret["comment"] = "The specified ACE was not found on the path." @@ -619,9 +619,9 @@ def _ace_to_text(ace, objectType): try: userSid = win32security.LookupAccountSid("", ace[2]) if userSid[1]: - userSid = "{1}\\{0}".format(userSid[0], userSid[1]) + userSid = f"{userSid[1]}\\{userSid[0]}" else: - userSid = "{}".format(userSid[0]) + userSid = f"{userSid[0]}" except Exception: # pylint: disable=broad-except userSid = win32security.ConvertSidToStringSid(ace[2]) tPerm = ace[1] @@ -643,7 +643,7 @@ def _ace_to_text(ace, objectType): if dc.validPropagations[objectType][x]["BITS"] == tProps: tProps = dc.validPropagations[objectType][x]["TEXT"] break - return "{} {} {} on {} {}".format(userSid, tAceType, tPerm, tProps, tInherited) + return f"{userSid} {tAceType} {tPerm} on {tProps} {tInherited}" def _set_dacl_inheritance(path, objectType, inheritance=True, copy=True, clear=False): @@ -730,7 +730,7 @@ def _set_dacl_inheritance(path, objectType, inheritance=True, copy=True, clear=F except Exception as e: # pylint: disable=broad-except ret["result"] = False ret["comment"] = ( - "Error attempting to set the inheritance. The error was {}.".format(e) + f"Error attempting to set the inheritance. The error was {e}." ) return ret @@ -818,7 +818,7 @@ def check_inheritance(path, objectType, user=None): except Exception as e: # pylint: disable=broad-except ret["result"] = False ret["comment"] = ( - "Error obtaining the Security Descriptor or DACL of the path: {}.".format(e) + f"Error obtaining the Security Descriptor or DACL of the path: {e}." ) return ret diff --git a/salt/modules/win_disk.py b/salt/modules/win_disk.py index 155efa5fe3f..92fa81ed59d 100644 --- a/salt/modules/win_disk.py +++ b/salt/modules/win_disk.py @@ -53,19 +53,19 @@ def usage(): available_bytes, total_bytes, total_free_bytes, - ) = win32api.GetDiskFreeSpaceEx("{}:\\".format(drive)) + ) = win32api.GetDiskFreeSpaceEx(f"{drive}:\\") used = total_bytes - total_free_bytes capacity = used / float(total_bytes) * 100 - ret["{}:\\".format(drive)] = { - "filesystem": "{}:\\".format(drive), + ret[f"{drive}:\\"] = { + "filesystem": f"{drive}:\\", "1K-blocks": total_bytes / 1024, "used": used / 1024, "available": total_free_bytes / 1024, - "capacity": "{:.0f}%".format(capacity), + "capacity": f"{capacity:.0f}%", } except Exception: # pylint: disable=broad-except - ret["{}:\\".format(drive)] = { - "filesystem": "{}:\\".format(drive), + ret[f"{drive}:\\"] = { + "filesystem": f"{drive}:\\", "1K-blocks": None, "used": None, "available": None, diff --git a/salt/modules/win_dism.py b/salt/modules/win_dism.py index c79e1c910a8..11838bf8ed6 100644 --- a/salt/modules/win_dism.py +++ b/salt/modules/win_dism.py @@ -52,11 +52,11 @@ def _get_components(type_regex, plural_type, install_value, image=None): cmd = [ bin_dism, "/English", - "/Image:{}".format(image) if image else "/Online", - "/Get-{}".format(plural_type), + f"/Image:{image}" if image else "/Online", + f"/Get-{plural_type}", ] out = __salt__["cmd.run"](cmd) - pattern = r"{} : (.*)\r\n.*State : {}\r\n".format(type_regex, install_value) + pattern = rf"{type_regex} : (.*)\r\n.*State : {install_value}\r\n" capabilities = re.findall(pattern, out, re.MULTILINE) capabilities.sort() return capabilities @@ -101,13 +101,13 @@ def add_capability( cmd = [ bin_dism, "/Quiet", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Add-Capability", - "/CapabilityName:{}".format(capability), + f"/CapabilityName:{capability}", ] if source: - cmd.append("/Source:{}".format(source)) + cmd.append(f"/Source:{source}") if limit_access: cmd.append("/LimitAccess") if not restart: @@ -149,9 +149,9 @@ def remove_capability(capability, image=None, restart=False): cmd = [ bin_dism, "/Quiet", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Remove-Capability", - "/CapabilityName:{}".format(capability), + f"/CapabilityName:{capability}", ] if not restart: @@ -191,7 +191,7 @@ def get_capabilities(image=None): cmd = [ bin_dism, "/English", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Get-Capabilities", ] out = __salt__["cmd.run"](cmd) @@ -303,14 +303,14 @@ def add_feature( cmd = [ bin_dism, "/Quiet", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Enable-Feature", - "/FeatureName:{}".format(feature), + f"/FeatureName:{feature}", ] if package: - cmd.append("/PackageName:{}".format(package)) + cmd.append(f"/PackageName:{package}") if source: - cmd.append("/Source:{}".format(source)) + cmd.append(f"/Source:{source}") if limit_access: cmd.append("/LimitAccess") if enable_parent: @@ -346,9 +346,9 @@ def remove_feature(feature, remove_payload=False, image=None, restart=False): cmd = [ bin_dism, "/Quiet", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Disable-Feature", - "/FeatureName:{}".format(feature), + f"/FeatureName:{feature}", ] if remove_payload: @@ -394,15 +394,15 @@ def get_features(package=None, image=None): cmd = [ bin_dism, "/English", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Get-Features", ] if package: if "~" in package: - cmd.append("/PackageName:{}".format(package)) + cmd.append(f"/PackageName:{package}") else: - cmd.append("/PackagePath:{}".format(package)) + cmd.append(f"/PackagePath:{package}") out = __salt__["cmd.run"](cmd) @@ -496,9 +496,9 @@ def add_package( cmd = [ bin_dism, "/Quiet", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Add-Package", - "/PackagePath:{}".format(package), + f"/PackagePath:{package}", ] if ignore_check: @@ -542,7 +542,7 @@ def remove_package(package, image=None, restart=False): cmd = [ bin_dism, "/Quiet", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Remove-Package", ] @@ -550,9 +550,9 @@ def remove_package(package, image=None, restart=False): cmd.append("/NoRestart") if "~" in package: - cmd.append("/PackageName:{}".format(package)) + cmd.append(f"/PackageName:{package}") else: - cmd.append("/PackagePath:{}".format(package)) + cmd.append(f"/PackagePath:{package}") return __salt__["cmd.run_all"](cmd) @@ -584,9 +584,9 @@ def get_kb_package_name(kb, image=None): salt '*' dism.get_kb_package_name 1231231 """ packages = installed_packages(image=image) - search = kb.upper() if kb.lower().startswith("kb") else "KB{}".format(kb) + search = kb.upper() if kb.lower().startswith("kb") else f"KB{kb}" for package in packages: - if "_{}~".format(search) in package: + if f"_{search}~" in package: return package return None @@ -622,7 +622,7 @@ def remove_kb(kb, image=None, restart=False): """ pkg_name = get_kb_package_name(kb=kb, image=image) if pkg_name is None: - msg = "{} not installed".format(kb) + msg = f"{kb} not installed" raise CommandExecutionError(msg) log.debug("Found: %s", pkg_name) return remove_package(package=pkg_name, image=image, restart=restart) @@ -679,14 +679,14 @@ def package_info(package, image=None): cmd = [ bin_dism, "/English", - "/Image:{}".format(image) if image else "/Online", + f"/Image:{image}" if image else "/Online", "/Get-PackageInfo", ] if "~" in package: - cmd.append("/PackageName:{}".format(package)) + cmd.append(f"/PackageName:{package}") else: - cmd.append("/PackagePath:{}".format(package)) + cmd.append(f"/PackagePath:{package}") out = __salt__["cmd.run_all"](cmd) diff --git a/salt/modules/win_dns_client.py b/salt/modules/win_dns_client.py index 89ba38fffb1..d72e344bbf8 100644 --- a/salt/modules/win_dns_client.py +++ b/salt/modules/win_dns_client.py @@ -118,7 +118,7 @@ def add_dns(ip, interface="Local Area Connection", index=1): "dns", interface, ip, - "index={}".format(index), + f"index={index}", "validate=no", ] diff --git a/salt/modules/win_dsc.py b/salt/modules/win_dsc.py index 9c99efae61b..997a72fd787 100644 --- a/salt/modules/win_dsc.py +++ b/salt/modules/win_dsc.py @@ -60,7 +60,7 @@ def _pshell(cmd, cwd=None, json_depth=2, ignore_retcode=False): CommandExecutionError. """ if "convertto-json" not in cmd.lower(): - cmd = "{} | ConvertTo-Json -Depth {}".format(cmd, json_depth) + cmd = f"{cmd} | ConvertTo-Json -Depth {json_depth}" log.debug("DSC: %s", cmd) results = __salt__["cmd.run_all"]( cmd, @@ -75,9 +75,7 @@ def _pshell(cmd, cwd=None, json_depth=2, ignore_retcode=False): if "retcode" not in results or results["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError( - "Issue executing PowerShell {}".format(cmd), info=results - ) + raise CommandExecutionError(f"Issue executing PowerShell {cmd}", info=results) # Sometimes Powershell returns an empty string, which isn't valid JSON if results["stdout"] == "": @@ -267,7 +265,7 @@ def compile_config( path=source, dest=path, saltenv=salt_env, makedirs=True ) if not cached_files: - error = "Failed to cache {}".format(source) + error = f"Failed to cache {source}" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -277,13 +275,13 @@ def compile_config( path=config_data_source, dest=config_data, saltenv=salt_env, makedirs=True ) if not cached_files: - error = "Failed to cache {}".format(config_data_source) + error = f"Failed to cache {config_data_source}" log.error("DSC: %s", error) raise CommandExecutionError(error) # Make sure the path exists if not os.path.exists(path): - error = "{} not found".format(path) + error = f"{path} not found" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -341,8 +339,8 @@ def compile_config( log.info("DSC: Compile Config: %s", ret) return ret - error = "Failed to compile config: {}".format(path) - error += "\nReturned: {}".format(ret) + error = f"Failed to compile config: {path}" + error += f"\nReturned: {ret}" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -394,7 +392,7 @@ def apply_config(path, source=None, salt_env="base"): source_name = os.path.basename(os.path.normpath(source)) if path_name.lower() != source_name.lower(): # Append the Source name to the Path - path = "{}\\{}".format(path, source_name) + path = f"{path}\\{source_name}" log.debug("DSC: %s appended to the path.", source_name) # Destination path minus the basename @@ -402,7 +400,7 @@ def apply_config(path, source=None, salt_env="base"): log.info("DSC: Caching %s", source) cached_files = __salt__["cp.get_dir"](source, dest_path, salt_env) if not cached_files: - error = "Failed to copy {}".format(source) + error = f"Failed to copy {source}" log.error("DSC: %s", error) raise CommandExecutionError(error) else: @@ -410,13 +408,13 @@ def apply_config(path, source=None, salt_env="base"): # Make sure the path exists if not os.path.exists(config): - error = "{} not found".format(config) + error = f"{config} not found" log.error("DSC: %s", error) raise CommandExecutionError(error) # Run the DSC Configuration # Putting quotes around the parameter protects against command injection - cmd = 'Start-DscConfiguration -Path "{}" -Wait -Force'.format(config) + cmd = f'Start-DscConfiguration -Path "{config}" -Wait -Force' _pshell(cmd) cmd = "$status = Get-DscConfigurationStatus; $status.Status" @@ -541,7 +539,7 @@ def remove_config(reset=False): if os.path.exists(path): log.info("DSC: Removing %s", path) if not __salt__["file.remove"](path): - error = "Failed to remove {}".format(path) + error = f"Failed to remove {path}" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -550,13 +548,13 @@ def remove_config(reset=False): ) # Remove History - _remove_fs_obj("{}\\DSCStatusHistory.mof".format(dsc_config_dir)) + _remove_fs_obj(f"{dsc_config_dir}\\DSCStatusHistory.mof") # Remove Engine Cache - _remove_fs_obj("{}\\DSCEngineCache.mof".format(dsc_config_dir)) + _remove_fs_obj(f"{dsc_config_dir}\\DSCEngineCache.mof") # Remove Status Directory - _remove_fs_obj("{}\\ConfigurationStatus".format(dsc_config_dir)) + _remove_fs_obj(f"{dsc_config_dir}\\ConfigurationStatus") return True @@ -756,7 +754,7 @@ def set_lcm_config( "or ApplyAndAutoCorrect. Passed {}".format(config_mode) ) raise SaltInvocationError(error) - cmd += ' ConfigurationMode = "{}";'.format(config_mode) + cmd += f' ConfigurationMode = "{config_mode}";' if config_mode_freq: if not isinstance(config_mode_freq, int): error = "config_mode_freq must be an integer. Passed {}".format( @@ -771,11 +769,11 @@ def set_lcm_config( raise SaltInvocationError( "refresh_mode must be one of Disabled, Push, or Pull" ) - cmd += ' RefreshMode = "{}";'.format(refresh_mode) + cmd += f' RefreshMode = "{refresh_mode}";' if refresh_freq: if not isinstance(refresh_freq, int): raise SaltInvocationError("refresh_freq must be an integer") - cmd += " RefreshFrequencyMins = {};".format(refresh_freq) + cmd += f" RefreshFrequencyMins = {refresh_freq};" if reboot_if_needed is not None: if not isinstance(reboot_if_needed, bool): raise SaltInvocationError("reboot_if_needed must be a boolean value") @@ -783,22 +781,22 @@ def set_lcm_config( reboot_if_needed = "$true" else: reboot_if_needed = "$false" - cmd += " RebootNodeIfNeeded = {};".format(reboot_if_needed) + cmd += f" RebootNodeIfNeeded = {reboot_if_needed};" if action_after_reboot: if action_after_reboot not in ("ContinueConfiguration", "StopConfiguration"): raise SaltInvocationError( "action_after_reboot must be one of " "ContinueConfiguration or StopConfiguration" ) - cmd += ' ActionAfterReboot = "{}"'.format(action_after_reboot) + cmd += f' ActionAfterReboot = "{action_after_reboot}"' if certificate_id is not None: if certificate_id == "": certificate_id = None - cmd += ' CertificateID = "{}";'.format(certificate_id) + cmd += f' CertificateID = "{certificate_id}";' if configuration_id is not None: if configuration_id == "": configuration_id = None - cmd += ' ConfigurationID = "{}";'.format(configuration_id) + cmd += f' ConfigurationID = "{configuration_id}";' if allow_module_overwrite is not None: if not isinstance(allow_module_overwrite, bool): raise SaltInvocationError("allow_module_overwrite must be a boolean value") @@ -806,7 +804,7 @@ def set_lcm_config( allow_module_overwrite = "$true" else: allow_module_overwrite = "$false" - cmd += " AllowModuleOverwrite = {};".format(allow_module_overwrite) + cmd += f" AllowModuleOverwrite = {allow_module_overwrite};" if debug_mode is not False: if debug_mode is None: debug_mode = "None" @@ -815,7 +813,7 @@ def set_lcm_config( "debug_mode must be one of None, ForceModuleImport, " "ResourceScriptBreakAll, or All" ) - cmd += ' DebugMode = "{}";'.format(debug_mode) + cmd += f' DebugMode = "{debug_mode}";' if status_retention_days: if not isinstance(status_retention_days, int): raise SaltInvocationError("status_retention_days must be an integer") @@ -823,7 +821,7 @@ def set_lcm_config( status_retention_days ) cmd += " }}};" - cmd += r'SaltConfig -OutputPath "{}\SaltConfig"'.format(temp_dir) + cmd += rf'SaltConfig -OutputPath "{temp_dir}\SaltConfig"' # Execute Config to create the .mof _pshell(cmd) @@ -831,7 +829,7 @@ def set_lcm_config( # Apply the config cmd = r'Set-DscLocalConfigurationManager -Path "{}\SaltConfig"' r"".format(temp_dir) ret = __salt__["cmd.run_all"](cmd, shell="powershell", python_shell=True) - __salt__["file.remove"](r"{}\SaltConfig".format(temp_dir)) + __salt__["file.remove"](rf"{temp_dir}\SaltConfig") if not ret["retcode"]: log.info("DSC: LCM config applied successfully") return True diff --git a/salt/modules/win_event.py b/salt/modules/win_event.py index d8d9bde990b..71fc1ac4928 100644 --- a/salt/modules/win_event.py +++ b/salt/modules/win_event.py @@ -175,7 +175,7 @@ def _get_handle(log_name): return win32evtlog.OpenEventLog(None, log_name) except pywintypes.error as exc: raise FileNotFoundError( - "Failed to open log: {}\nError: {}".format(log_name, exc.strerror) + f"Failed to open log: {log_name}\nError: {exc.strerror}" ) @@ -680,7 +680,7 @@ def add( if event_type is None: event_type = event_types["Error"] elif event_type not in event_types: - msg = "Incorrect event type: {}".format(event_type) + msg = f"Incorrect event type: {event_type}" raise CommandExecutionError(msg) else: event_type = event_types[event_type] diff --git a/salt/modules/win_file.py b/salt/modules/win_file.py index a7a411c93cc..262b3842f9b 100644 --- a/salt/modules/win_file.py +++ b/salt/modules/win_file.py @@ -272,7 +272,7 @@ def gid_to_group(gid): salt '*' file.gid_to_group S-1-5-21-626487655-2533044672-482107328-1010 """ - func_name = "{}.gid_to_group".format(__virtualname__) + func_name = f"{__virtualname__}.gid_to_group" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; " @@ -307,7 +307,7 @@ def group_to_gid(group): salt '*' file.group_to_gid administrators """ - func_name = "{}.group_to_gid".format(__virtualname__) + func_name = f"{__virtualname__}.group_to_gid" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; " @@ -349,7 +349,7 @@ def get_pgid(path, follow_symlinks=True): salt '*' file.get_pgid c:\\temp\\test.txt """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") # Under Windows, if the path is a symlink, the user that owns the symlink is # returned, not the user that owns the file/directory the symlink is @@ -433,7 +433,7 @@ def get_gid(path, follow_symlinks=True): salt '*' file.get_gid c:\\temp\\test.txt """ - func_name = "{}.get_gid".format(__virtualname__) + func_name = f"{__virtualname__}.get_gid" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; " @@ -480,7 +480,7 @@ def get_group(path, follow_symlinks=True): salt '*' file.get_group c:\\temp\\test.txt """ - func_name = "{}.get_group".format(__virtualname__) + func_name = f"{__virtualname__}.get_group" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; " @@ -561,7 +561,7 @@ def get_uid(path, follow_symlinks=True): salt '*' file.get_uid c:\\temp\\test.txt follow_symlinks=False """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") # Under Windows, if the path is a symlink, the user that owns the symlink is # returned, not the user that owns the file/directory the symlink is @@ -600,7 +600,7 @@ def get_user(path, follow_symlinks=True): salt '*' file.get_user c:\\temp\\test.txt follow_symlinks=False """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") # Under Windows, if the path is a symlink, the user that owns the symlink is # returned, not the user that owns the file/directory the symlink is @@ -633,9 +633,9 @@ def get_mode(path): salt '*' file.get_mode /etc/passwd """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") - func_name = "{}.get_mode".format(__virtualname__) + func_name = f"{__virtualname__}.get_mode" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; " @@ -684,7 +684,7 @@ def lchown(path, user, group=None, pgroup=None): salt '*' file.lchown c:\\temp\\test.txt myusername "pgroup='None'" """ if group: - func_name = "{}.lchown".format(__virtualname__) + func_name = f"{__virtualname__}.lchown" if __opts__.get("fun", "") == func_name: log.info( "The group parameter has no effect when using %s on " @@ -733,7 +733,7 @@ def chown(path, user, group=None, pgroup=None, follow_symlinks=True): """ # the group parameter is not used; only provided for API compatibility if group is not None: - func_name = "{}.chown".format(__virtualname__) + func_name = f"{__virtualname__}.chown" if __opts__.get("fun", "") == func_name: log.info( "The group parameter has no effect when using %s on " @@ -746,7 +746,7 @@ def chown(path, user, group=None, pgroup=None, follow_symlinks=True): path = _resolve_symlink(path) if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") salt.utils.win_dacl.set_owner(path, user) if pgroup: @@ -817,7 +817,7 @@ def chgrp(path, group): salt '*' file.chgrp c:\\temp\\test.txt administrators """ - func_name = "{}.chgrp".format(__virtualname__) + func_name = f"{__virtualname__}.chgrp" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; see " @@ -863,7 +863,7 @@ def stats(path, hash_type="sha256", follow_symlinks=True): # This is to mirror the behavior of file.py. `check_file_meta` expects an # empty dictionary when the file does not exist if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") if follow_symlinks and sys.getwindowsversion().major >= 6: path = _resolve_symlink(path) @@ -966,13 +966,13 @@ def _get_version_type(file_type, file_subtype): if ret_type == "Driver": if file_subtype in driver_subtypes: - ret_type = "{} Driver".format(driver_subtypes[file_subtype]) + ret_type = f"{driver_subtypes[file_subtype]} Driver" if ret_type == "Font": if file_subtype in font_subtypes: - ret_type = "{} Font".format(font_subtypes[file_subtype]) + ret_type = f"{font_subtypes[file_subtype]} Font" if ret_type == "Virtual Device": # The Virtual Device Identifier - ret_type = "Virtual Device: {}".format(file_subtype) + ret_type = f"Virtual Device: {file_subtype}" return ret_type @@ -1041,9 +1041,9 @@ def version(path): """ # Input validation if not os.path.exists(path): - raise CommandExecutionError("File not found: {}".format(path)) + raise CommandExecutionError(f"File not found: {path}") if os.path.isdir(path): - raise CommandExecutionError("Not a file: {}".format(path)) + raise CommandExecutionError(f"Not a file: {path}") return _get_version(path) @@ -1081,9 +1081,9 @@ def version_details(path): """ # Input validation if not os.path.exists(path): - raise CommandExecutionError("File not found: {}".format(path)) + raise CommandExecutionError(f"File not found: {path}") if os.path.isdir(path): - raise CommandExecutionError("Not a file: {}".format(path)) + raise CommandExecutionError(f"Not a file: {path}") ret = {} try: @@ -1159,7 +1159,7 @@ def get_attributes(path): salt '*' file.get_attributes c:\\temp\\a.txt """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") # set up dictionary for attribute values attributes = {} @@ -1241,7 +1241,7 @@ def set_attributes( salt '*' file.set_attributes c:\\temp\\a.txt readonly=True hidden=True """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") if normal: if archive or hidden or notIndexed or readonly or system or temporary: @@ -1310,7 +1310,7 @@ def set_mode(path, mode): salt '*' file.set_mode /etc/passwd 0644 """ - func_name = "{}.set_mode".format(__virtualname__) + func_name = f"{__virtualname__}.set_mode" if __opts__.get("fun", "") == func_name: log.info( "The function %s should not be used on Windows systems; " @@ -1346,11 +1346,11 @@ def remove(path, force=False): path = os.path.expanduser(path) if not os.path.isabs(path): - raise SaltInvocationError("File path must be absolute: {}".format(path)) + raise SaltInvocationError(f"File path must be absolute: {path}") # Does the file/folder exists if not os.path.exists(path) and not is_link(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") # Remove ReadOnly Attribute if force: @@ -1367,7 +1367,7 @@ def remove(path, force=False): os.rmdir(path) else: for name in os.listdir(path): - item = "{}\\{}".format(path, name) + item = f"{path}\\{name}" # If its a normal directory, recurse to remove it's contents remove(item, force) @@ -1377,7 +1377,7 @@ def remove(path, force=False): if force: # Reset attributes to the original if delete fails. win32api.SetFileAttributes(path, file_attributes) - raise CommandExecutionError("Could not remove '{}': {}".format(path, exc)) + raise CommandExecutionError(f"Could not remove '{path}': {exc}") return True @@ -1425,7 +1425,7 @@ def symlink(src, link, force=False, atomic=False): ) if not os.path.isabs(link): - raise SaltInvocationError("Link path must be absolute: {}".format(link)) + raise SaltInvocationError(f"Link path must be absolute: {link}") if os.path.islink(link): try: @@ -1438,11 +1438,11 @@ def symlink(src, link, force=False, atomic=False): pass if not force and not atomic: - msg = "Found existing symlink: {}".format(link) + msg = f"Found existing symlink: {link}" raise CommandExecutionError(msg) if os.path.exists(link) and not force and not atomic: - msg = "Existing path is not a symlink: {}".format(link) + msg = f"Existing path is not a symlink: {link}" raise CommandExecutionError(msg) # ensure paths are using the right slashes @@ -1477,14 +1477,14 @@ def symlink(src, link, force=False, atomic=False): return True except win32file.error: os.remove(temp_link) - raise CommandExecutionError("Could not create '{}'".format(link)) + raise CommandExecutionError(f"Could not create '{link}'") try: win32file.CreateSymbolicLink(link, src, int(is_dir)) return True except win32file.error as exc: raise CommandExecutionError( - "Could not create '{}' - [{}] {}".format(link, exc.winerror, exc.strerror) + f"Could not create '{link}' - [{exc.winerror}] {exc.strerror}" ) @@ -1594,7 +1594,7 @@ def mkdir( # Make sure the drive is valid drive = os.path.splitdrive(path)[0] if not os.path.isdir(drive): - raise CommandExecutionError("Drive {} is not mapped".format(drive)) + raise CommandExecutionError(f"Drive {drive} is not mapped") path = os.path.expanduser(path) path = os.path.expandvars(path) @@ -1711,12 +1711,12 @@ def makedirs_( if os.path.isdir(dirname): # There's nothing for us to do - msg = "Directory '{}' already exists".format(dirname) + msg = f"Directory '{dirname}' already exists" log.debug(msg) return msg if os.path.exists(dirname): - msg = "The path '{}' already exists and is not a directory".format(dirname) + msg = f"The path '{dirname}' already exists and is not a directory" log.debug(msg) return msg @@ -1925,7 +1925,7 @@ def check_perms( salt '*' file.check_perms C:\\Temp\\ {} Administrators "{'jsnuffy': {'perms': ['read_attributes', 'read_ea'], 'applies_to': 'files_only'}}" """ if not os.path.exists(path): - raise CommandExecutionError("Path not found: {}".format(path)) + raise CommandExecutionError(f"Path not found: {path}") path = os.path.expanduser(path) diff --git a/salt/modules/win_firewall.py b/salt/modules/win_firewall.py index 75dbd3f964e..6d8dd025895 100644 --- a/salt/modules/win_firewall.py +++ b/salt/modules/win_firewall.py @@ -151,7 +151,7 @@ def get_rule(name="all"): salt '*' firewall.get_rule 'MyAppPort' """ - cmd = ["netsh", "advfirewall", "firewall", "show", "rule", "name={}".format(name)] + cmd = ["netsh", "advfirewall", "firewall", "show", "rule", f"name={name}"] ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=True) if ret["retcode"] != 0: raise CommandExecutionError(ret["stdout"]) @@ -228,15 +228,15 @@ def add_rule(name, localport, protocol="tcp", action="allow", dir="in", remoteip "firewall", "add", "rule", - "name={}".format(name), - "protocol={}".format(protocol), - "dir={}".format(dir), - "action={}".format(action), - "remoteip={}".format(remoteip), + f"name={name}", + f"protocol={protocol}", + f"dir={dir}", + f"action={action}", + f"remoteip={remoteip}", ] if protocol is None or ("icmpv4" not in protocol and "icmpv6" not in protocol): - cmd.append("localport={}".format(localport)) + cmd.append(f"localport={localport}") ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=True) if ret["retcode"] != 0: @@ -292,19 +292,19 @@ def delete_rule(name=None, localport=None, protocol=None, dir=None, remoteip=Non """ cmd = ["netsh", "advfirewall", "firewall", "delete", "rule"] if name: - cmd.append("name={}".format(name)) + cmd.append(f"name={name}") if protocol: - cmd.append("protocol={}".format(protocol)) + cmd.append(f"protocol={protocol}") if dir: - cmd.append("dir={}".format(dir)) + cmd.append(f"dir={dir}") if remoteip: - cmd.append("remoteip={}".format(remoteip)) + cmd.append(f"remoteip={remoteip}") if protocol is None or ("icmpv4" not in protocol and "icmpv6" not in protocol): if localport: if not protocol: cmd.append("protocol=tcp") - cmd.append("localport={}".format(localport)) + cmd.append(f"localport={localport}") ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=True) if ret["retcode"] != 0: diff --git a/salt/modules/win_iis.py b/salt/modules/win_iis.py index 68f67c01d9c..b20cc2fc7bc 100644 --- a/salt/modules/win_iis.py +++ b/salt/modules/win_iis.py @@ -84,7 +84,7 @@ def _list_certs(certificate_store="My"): ps_cmd = [ "Get-ChildItem", "-Path", - r"'Cert:\LocalMachine\{}'".format(certificate_store), + rf"'Cert:\LocalMachine\{certificate_store}'", "|", "Select-Object DnsNameList, SerialNumber, Subject, Thumbprint, Version", ] @@ -146,9 +146,9 @@ def _srvmgr(cmd, return_json=False): cmd = " ".join(cmd) if return_json: - cmd = "ConvertTo-Json -Compress -Depth 4 -InputObject @({})".format(cmd) + cmd = f"ConvertTo-Json -Compress -Depth 4 -InputObject @({cmd})" - cmd = "Import-Module WebAdministration; {}".format(cmd) + cmd = f"Import-Module WebAdministration; {cmd}" ret = __salt__["cmd.run_all"](cmd, shell="powershell", python_shell=True) @@ -306,7 +306,7 @@ def create_site( salt '*' win_iis.create_site name='My Test Site' sourcepath='c:\\stage' apppool='TestPool' """ protocol = str(protocol).lower() - site_path = r"IIS:\Sites\{}".format(name) + site_path = rf"IIS:\Sites\{name}" binding_info = _get_binding_info(hostheader, ipaddress, port) current_sites = list_sites() @@ -323,9 +323,9 @@ def create_site( ps_cmd = [ "New-Item", "-Path", - r"'{}'".format(site_path), + rf"'{site_path}'", "-PhysicalPath", - r"'{}'".format(sourcepath), + rf"'{sourcepath}'", "-Bindings", "@{{ protocol='{0}'; bindingInformation='{1}' }};".format( protocol, binding_info @@ -343,11 +343,11 @@ def create_site( [ "Set-ItemProperty", "-Path", - "'{}'".format(site_path), + f"'{site_path}'", "-Name", "ApplicationPool", "-Value", - "'{}'".format(apppool), + f"'{apppool}'", ] ) @@ -386,7 +386,7 @@ def modify_site(name, sourcepath=None, apppool=None): salt '*' win_iis.modify_site name='My Test Site' sourcepath='c:\\new_path' apppool='NewTestPool' """ - site_path = r"IIS:\Sites\{}".format(name) + site_path = rf"IIS:\Sites\{name}" current_sites = list_sites() if name not in current_sites: @@ -400,11 +400,11 @@ def modify_site(name, sourcepath=None, apppool=None): [ "Set-ItemProperty", "-Path", - r"'{}'".format(site_path), + rf"'{site_path}'", "-Name", "PhysicalPath", "-Value", - r"'{}'".format(sourcepath), + rf"'{sourcepath}'", ] ) @@ -424,11 +424,11 @@ def modify_site(name, sourcepath=None, apppool=None): [ "Set-ItemProperty", "-Path", - r"'{}'".format(site_path), + rf"'{site_path}'", "-Name", "ApplicationPool", "-Value", - r"'{}'".format(apppool), + rf"'{apppool}'", ] ) @@ -469,7 +469,7 @@ def remove_site(name): log.debug("Site already absent: %s", name) return True - ps_cmd = ["Remove-WebSite", "-Name", r"'{}'".format(name)] + ps_cmd = ["Remove-WebSite", "-Name", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -499,7 +499,7 @@ def stop_site(name): salt '*' win_iis.stop_site name='My Test Site' """ - ps_cmd = ["Stop-WebSite", r"'{}'".format(name)] + ps_cmd = ["Stop-WebSite", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -524,7 +524,7 @@ def start_site(name): salt '*' win_iis.start_site name='My Test Site' """ - ps_cmd = ["Start-WebSite", r"'{}'".format(name)] + ps_cmd = ["Start-WebSite", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -642,31 +642,31 @@ def create_binding( ps_cmd = [ "New-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-HostHeader", - "'{}'".format(hostheader), + f"'{hostheader}'", "-IpAddress", - "'{}'".format(ipaddress), + f"'{ipaddress}'", "-Port", - "'{}'".format(port), + f"'{port}'", "-Protocol", - "'{}'".format(protocol), + f"'{protocol}'", "-SslFlags", - "{}".format(sslflags), + f"{sslflags}", ] else: ps_cmd = [ "New-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-HostHeader", - "'{}'".format(hostheader), + f"'{hostheader}'", "-IpAddress", - "'{}'".format(ipaddress), + f"'{ipaddress}'", "-Port", - "'{}'".format(port), + f"'{port}'", "-Protocol", - "'{}'".format(protocol), + f"'{protocol}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -750,13 +750,13 @@ def modify_binding( ps_cmd = [ "Set-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-BindingInformation", - "'{}'".format(binding), + f"'{binding}'", "-PropertyName", "BindingInformation", "-Value", - "'{}'".format(new_binding), + f"'{new_binding}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -774,13 +774,13 @@ def modify_binding( ps_cmd = [ "Set-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-BindingInformation", - "'{}'".format(new_binding), + f"'{new_binding}'", "-PropertyName", "sslflags", "-Value", - "'{}'".format(sslflags), + f"'{sslflags}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -823,11 +823,11 @@ def remove_binding(site, hostheader="", ipaddress="*", port=80): ps_cmd = [ "Remove-WebBinding", "-HostHeader", - "'{}'".format(hostheader), + f"'{hostheader}'", "-IpAddress", - "'{}'".format(ipaddress), + f"'{ipaddress}'", "-Port", - "'{}'".format(port), + f"'{port}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -962,19 +962,19 @@ def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslf ps_cmd = [ "New-Item", "-Path", - "'{}'".format(iis7path), + f"'{iis7path}'", "-Thumbprint", - "'{}'".format(name), + f"'{name}'", ] else: ps_cmd = [ "New-Item", "-Path", - "'{}'".format(binding_path), + f"'{binding_path}'", "-Thumbprint", - "'{}'".format(name), + f"'{name}'", "-SSLFlags", - "{}".format(sslflags), + f"{sslflags}", ] cmd_ret = _srvmgr(ps_cmd) @@ -1038,10 +1038,10 @@ def remove_cert_binding(name, site, hostheader="", ipaddress="*", port=443): r"'IIS:\Sites'", "|", "Where-Object", - r" {{ $_.Name -Eq '{0}' }};".format(site), + rf" {{ $_.Name -Eq '{site}' }};", "$Binding = $Site.Bindings.Collection", r"| Where-Object { $_.bindingInformation", - r"-Eq '{0}' }};".format(binding_info), + rf"-Eq '{binding_info}' }};", "$Binding.RemoveSslCertificate()", ] @@ -1168,13 +1168,13 @@ def create_apppool(name): salt '*' win_iis.create_apppool name='MyTestPool' """ current_apppools = list_apppools() - apppool_path = r"IIS:\AppPools\{}".format(name) + apppool_path = rf"IIS:\AppPools\{name}" if name in current_apppools: log.debug("Application pool '%s' already present.", name) return True - ps_cmd = ["New-Item", "-Path", r"'{}'".format(apppool_path)] + ps_cmd = ["New-Item", "-Path", rf"'{apppool_path}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1205,13 +1205,13 @@ def remove_apppool(name): salt '*' win_iis.remove_apppool name='MyTestPool' """ current_apppools = list_apppools() - apppool_path = r"IIS:\AppPools\{}".format(name) + apppool_path = rf"IIS:\AppPools\{name}" if name not in current_apppools: log.debug("Application pool already absent: %s", name) return True - ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(apppool_path), "-Recurse"] + ps_cmd = ["Remove-Item", "-Path", rf"'{apppool_path}'", "-Recurse"] cmd_ret = _srvmgr(ps_cmd) @@ -1243,7 +1243,7 @@ def stop_apppool(name): salt '*' win_iis.stop_apppool name='MyTestPool' """ - ps_cmd = ["Stop-WebAppPool", r"'{}'".format(name)] + ps_cmd = ["Stop-WebAppPool", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1268,7 +1268,7 @@ def start_apppool(name): salt '*' win_iis.start_apppool name='MyTestPool' """ - ps_cmd = ["Start-WebAppPool", r"'{}'".format(name)] + ps_cmd = ["Start-WebAppPool", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1293,7 +1293,7 @@ def restart_apppool(name): salt '*' win_iis.restart_apppool name='MyTestPool' """ - ps_cmd = ["Restart-WebAppPool", r"'{}'".format(name)] + ps_cmd = ["Restart-WebAppPool", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1325,7 +1325,7 @@ def get_container_setting(name, container, settings): ret = dict() ps_cmd = list() ps_cmd_validate = list() - container_path = r"IIS:\{}\{}".format(container, name) + container_path = rf"IIS:\{container}\{name}" if not settings: log.warning("No settings provided") @@ -1339,9 +1339,9 @@ def get_container_setting(name, container, settings): [ "Get-ItemProperty", "-Path", - "'{}'".format(container_path), + f"'{container_path}'", "-Name", - "'{}'".format(setting), + f"'{setting}'", "-ErrorAction", "Stop", "|", @@ -1352,13 +1352,13 @@ def get_container_setting(name, container, settings): # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. - ps_cmd.append("$Property = Get-ItemProperty -Path '{}'".format(container_path)) - ps_cmd.append("-Name '{}' -ErrorAction Stop;".format(setting)) + ps_cmd.append(f"$Property = Get-ItemProperty -Path '{container_path}'") + ps_cmd.append(f"-Name '{setting}' -ErrorAction Stop;") ps_cmd.append(r"if (([String]::IsNullOrEmpty($Property) -eq $False) -and") ps_cmd.append(r"($Property.GetType()).Name -eq 'ConfigurationAttribute') {") ps_cmd.append(r"$Property = $Property | Select-Object") ps_cmd.append(r"-ExpandProperty Value };") - ps_cmd.append("$Settings['{}'] = [String] $Property;".format(setting)) + ps_cmd.append(f"$Settings['{setting}'] = [String] $Property;") ps_cmd.append(r"$Property = $Null;") # Validate the setting names that were passed in. @@ -1426,7 +1426,7 @@ def set_container_setting(name, container, settings): "ApplicationPoolIdentity": "4", } ps_cmd = list() - container_path = r"IIS:\{}\{}".format(container, name) + container_path = rf"IIS:\{container}\{name}" if not settings: log.warning("No settings provided") @@ -1450,7 +1450,7 @@ def set_container_setting(name, container, settings): complex(settings[setting]) value = settings[setting] except ValueError: - value = "'{}'".format(settings[setting]) + value = f"'{settings[setting]}'" # Map to numeric to support server 2008 if ( @@ -1463,18 +1463,18 @@ def set_container_setting(name, container, settings): [ "Set-ItemProperty", "-Path", - "'{}'".format(container_path), + f"'{container_path}'", "-Name", - "'{}'".format(setting), + f"'{setting}'", "-Value", - "{};".format(value), + f"{value};", ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: - msg = "Unable to set settings for {}: {}".format(container, name) + msg = f"Unable to set settings for {container}: {name}" raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values @@ -1521,7 +1521,7 @@ def list_apps(site): """ ret = dict() ps_cmd = list() - ps_cmd.append("Get-WebApplication -Site '{}'".format(site)) + ps_cmd.append(f"Get-WebApplication -Site '{site}'") ps_cmd.append( r"| Select-Object applicationPool, path, PhysicalPath, preloadEnabled," ) @@ -1605,15 +1605,15 @@ def create_app(name, site, sourcepath, apppool=None): ps_cmd = [ "New-WebApplication", "-Name", - "'{}'".format(name), + f"'{name}'", "-Site", - "'{}'".format(site), + f"'{site}'", "-PhysicalPath", - "'{}'".format(sourcepath), + f"'{sourcepath}'", ] if apppool: - ps_cmd.extend(["-ApplicationPool", "'{}'".format(apppool)]) + ps_cmd.extend(["-ApplicationPool", f"'{apppool}'"]) cmd_ret = _srvmgr(ps_cmd) @@ -1659,9 +1659,9 @@ def remove_app(name, site): ps_cmd = [ "Remove-WebApplication", "-Name", - "'{}'".format(name), + f"'{name}'", "-Site", - "'{}'".format(site), + f"'{site}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -1705,9 +1705,9 @@ def list_vdirs(site, app=_DEFAULT_APP): ps_cmd = [ "Get-WebVirtualDirectory", "-Site", - r"'{}'".format(site), + rf"'{site}'", "-Application", - r"'{}'".format(app), + rf"'{app}'", "|", "Select-Object PhysicalPath, @{ Name = 'name';", r"Expression = { $_.path.Trim('/') } }", @@ -1769,15 +1769,15 @@ def create_vdir(name, site, sourcepath, app=_DEFAULT_APP): ps_cmd = [ "New-WebVirtualDirectory", "-Name", - r"'{}'".format(name), + rf"'{name}'", "-Site", - r"'{}'".format(site), + rf"'{site}'", "-PhysicalPath", - r"'{}'".format(sourcepath), + rf"'{sourcepath}'", ] if app != _DEFAULT_APP: - ps_cmd.extend(["-Application", r"'{}'".format(app)]) + ps_cmd.extend(["-Application", rf"'{app}'"]) cmd_ret = _srvmgr(ps_cmd) @@ -1819,8 +1819,8 @@ def remove_vdir(name, site, app=_DEFAULT_APP): app_path = os.path.join(*app.rstrip("/").split("/")) if app_path: - app_path = "{}\\".format(app_path) - vdir_path = r"IIS:\Sites\{}\{}{}".format(site, app_path, name) + app_path = f"{app_path}\\" + vdir_path = rf"IIS:\Sites\{site}\{app_path}{name}" if name not in current_vdirs: log.debug("Virtual directory already absent: %s", name) @@ -1829,7 +1829,7 @@ def remove_vdir(name, site, app=_DEFAULT_APP): # We use Remove-Item here instead of Remove-WebVirtualDirectory, since the # latter has a bug that causes it to always prompt for user input. - ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(vdir_path), "-Recurse"] + ps_cmd = ["Remove-Item", "-Path", rf"'{vdir_path}'", "-Recurse"] cmd_ret = _srvmgr(ps_cmd) @@ -1919,9 +1919,9 @@ def create_backup(name): salt '*' win_iis.create_backup good_config_20170209 """ if name in list_backups(): - raise CommandExecutionError("Backup already present: {}".format(name)) + raise CommandExecutionError(f"Backup already present: {name}") - ps_cmd = ["Backup-WebConfiguration", "-Name", "'{}'".format(name)] + ps_cmd = ["Backup-WebConfiguration", "-Name", f"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1956,7 +1956,7 @@ def remove_backup(name): log.debug("Backup already removed: %s", name) return True - ps_cmd = ["Remove-WebConfigurationBackup", "-Name", "'{}'".format(name)] + ps_cmd = ["Remove-WebConfigurationBackup", "-Name", f"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1988,7 +1988,7 @@ def list_worker_processes(apppool): salt '*' win_iis.list_worker_processes 'My App Pool' """ - ps_cmd = ["Get-ChildItem", r"'IIS:\AppPools\{}\WorkerProcesses'".format(apppool)] + ps_cmd = ["Get-ChildItem", rf"'IIS:\AppPools\{apppool}\WorkerProcesses'"] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) @@ -2051,20 +2051,16 @@ def get_webapp_settings(name, site, settings): site, name ) ) - pscmd.append( - r' -Name "{}" -ErrorAction Stop | select Value;'.format(setting) - ) + pscmd.append(rf' -Name "{setting}" -ErrorAction Stop | select Value;') pscmd.append( r" $Property = $Property | Select-Object -ExpandProperty Value;" ) - pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) + pscmd.append(rf" $Settings['{setting}'] = [String] $Property;") pscmd.append(r" $Property = $Null;") if setting == "physicalPath" or setting == "applicationPool": - pscmd.append( - r" $Property = (get-webapplication {}).{};".format(name, setting) - ) - pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) + pscmd.append(rf" $Property = (get-webapplication {name}).{setting};") + pscmd.append(rf" $Settings['{setting}'] = [String] $Property;") pscmd.append(r" $Property = $Null;") else: @@ -2172,7 +2168,7 @@ def set_webapp_settings(name, site, settings): complex(settings[setting]) value = settings[setting] except ValueError: - value = "'{}'".format(settings[setting]) + value = f"'{settings[setting]}'" # Append relevant update command per setting key if setting == "userName" or setting == "password": @@ -2182,7 +2178,7 @@ def set_webapp_settings(name, site, settings): site, name ) ) - pscmd.append(' -Name "{}" -Value {};'.format(setting, value)) + pscmd.append(f' -Name "{setting}" -Value {value};') if setting == "physicalPath" or setting == "applicationPool": pscmd.append( @@ -2200,7 +2196,7 @@ def set_webapp_settings(name, site, settings): # Verify commands completed successfully if cmd_ret["retcode"] != 0: - msg = "Unable to set settings for web application {}".format(name) + msg = f"Unable to set settings for web application {name}" raise SaltInvocationError(msg) # verify changes @@ -2253,7 +2249,7 @@ def get_webconfiguration_settings(name, settings): [ "Get-WebConfigurationProperty", "-PSPath", - "'{}'".format(name), + f"'{name}'", "-Filter", "'{}'".format(setting["filter"]), "-Name", @@ -2268,9 +2264,7 @@ def get_webconfiguration_settings(name, settings): # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. - ps_cmd.append( - "$Property = Get-WebConfigurationProperty -PSPath '{}'".format(name) - ) + ps_cmd.append(f"$Property = Get-WebConfigurationProperty -PSPath '{name}'") ps_cmd.append( "-Name '{}' -Filter '{}' -ErrorAction Stop;".format( setting["name"], setting["filter"] @@ -2368,7 +2362,7 @@ def set_webconfiguration_settings(name, settings): for value_item in setting["value"]: configelement_construct = [] for key, value in value_item.items(): - configelement_construct.append("{}='{}'".format(key, value)) + configelement_construct.append(f"{key}='{value}'") configelement_list.append( "@{" + ";".join(configelement_construct) + "}" ) @@ -2378,20 +2372,20 @@ def set_webconfiguration_settings(name, settings): [ "Set-WebConfigurationProperty", "-PSPath", - "'{}'".format(name), + f"'{name}'", "-Filter", "'{}'".format(setting["filter"]), "-Name", "'{}'".format(setting["name"]), "-Value", - "{};".format(value), + f"{value};", ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: - msg = "Unable to set settings for {}".format(name) + msg = f"Unable to set settings for {name}" raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values diff --git a/salt/modules/win_ip.py b/salt/modules/win_ip.py index f1c11cfacbc..524a8d887c2 100644 --- a/salt/modules/win_ip.py +++ b/salt/modules/win_ip.py @@ -132,14 +132,14 @@ def is_enabled(iface): salt -G 'os_family:Windows' ip.is_enabled 'Local Area Connection #2' """ - cmd = ["netsh", "interface", "show", "interface", "name={}".format(iface)] + cmd = ["netsh", "interface", "show", "interface", f"name={iface}"] iface_found = False for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines(): if "Connect state:" in line: iface_found = True return line.split()[-1] == "Connected" if not iface_found: - raise CommandExecutionError("Interface '{}' not found".format(iface)) + raise CommandExecutionError(f"Interface '{iface}' not found") return False @@ -173,7 +173,7 @@ def enable(iface): "interface", "set", "interface", - "name={}".format(iface), + f"name={iface}", "admin=ENABLED", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -197,7 +197,7 @@ def disable(iface): "interface", "set", "interface", - "name={}".format(iface), + f"name={iface}", "admin=DISABLED", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -215,7 +215,7 @@ def get_subnet_length(mask): salt -G 'os_family:Windows' ip.get_subnet_length 255.255.255.0 """ if not salt.utils.validate.net.netmask(mask): - raise SaltInvocationError("'{}' is not a valid netmask".format(mask)) + raise SaltInvocationError(f"'{mask}' is not a valid netmask") return salt.utils.network.get_net_size(mask) @@ -258,17 +258,17 @@ def set_static_ip(iface, addr, gateway=None, append=False): return {} if not salt.utils.validate.net.ipv4_addr(addr): - raise SaltInvocationError("Invalid address '{}'".format(addr)) + raise SaltInvocationError(f"Invalid address '{addr}'") if gateway and not salt.utils.validate.net.ipv4_addr(addr): - raise SaltInvocationError("Invalid default gateway '{}'".format(gateway)) + raise SaltInvocationError(f"Invalid default gateway '{gateway}'") if "/" not in addr: addr += "/32" if append and _find_addr(iface, addr): raise CommandExecutionError( - "Address '{}' already exists on interface '{}'".format(addr, iface) + f"Address '{addr}' already exists on interface '{iface}'" ) cmd = ["netsh", "interface", "ip"] @@ -276,12 +276,12 @@ def set_static_ip(iface, addr, gateway=None, append=False): cmd.append("add") else: cmd.append("set") - cmd.extend(["address", "name={}".format(iface)]) + cmd.extend(["address", f"name={iface}"]) if not append: cmd.append("source=static") - cmd.append("address={}".format(addr)) + cmd.append(f"address={addr}") if gateway: - cmd.append("gateway={}".format(gateway)) + cmd.append(f"gateway={gateway}") result = __salt__["cmd.run_all"](cmd, python_shell=False) if result["retcode"] != 0: @@ -348,7 +348,7 @@ def set_static_dns(iface, *addrs): "ip", "set", "dns", - "name={}".format(iface), + f"name={iface}", "source=static", "address=none", ] @@ -363,9 +363,9 @@ def set_static_dns(iface, *addrs): "ip", "set", "dns", - "name={}".format(iface), + f"name={iface}", "source=static", - "address={}".format(addr), + f"address={addr}", "register=primary", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -377,9 +377,9 @@ def set_static_dns(iface, *addrs): "ip", "add", "dns", - "name={}".format(iface), - "address={}".format(addr), - "index={}".format(addr_index), + f"name={iface}", + f"address={addr}", + f"index={addr_index}", ] __salt__["cmd.run"](cmd, python_shell=False) addr_index = addr_index + 1 diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index f387eeebeb3..02f8bb90703 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -4651,7 +4651,7 @@ class _policy_info: """ add quotes around the string """ - return '"{}"'.format(val) + return f'"{val}"' @classmethod def _binary_enable_zero_disable_one_conversion(cls, val, **kwargs): @@ -4665,7 +4665,7 @@ class _policy_info: elif ord(val) == 1: return "Enabled" else: - return "Invalid Value: {!r}".format(val) + return f"Invalid Value: {val!r}" else: return "Not Defined" except TypeError: @@ -4805,9 +4805,9 @@ class _policy_info: try: userSid = win32security.LookupAccountSid("", _sid) if userSid[1]: - userSid = "{1}\\{0}".format(userSid[0], userSid[1]) + userSid = f"{userSid[1]}\\{userSid[0]}" else: - userSid = "{}".format(userSid[0]) + userSid = f"{userSid[0]}" # TODO: This needs to be more specific except Exception: # pylint: disable=broad-except userSid = win32security.ConvertSidToStringSid(_sid) @@ -4999,7 +4999,7 @@ def _updateNamespace(item, new_namespace): temp_item = item.tag[i + 1 :] else: temp_item = item.tag - item.tag = "{{{0}}}{1}".format(new_namespace, temp_item) + item.tag = f"{{{new_namespace}}}{temp_item}" for child in item.getiterator(): if isinstance(child.tag, str): temp_item = "" @@ -5008,7 +5008,7 @@ def _updateNamespace(item, new_namespace): temp_item = child.tag[i + 1 :] else: temp_item = child.tag - child.tag = "{{{0}}}{1}".format(new_namespace, temp_item) + child.tag = f"{{{new_namespace}}}{temp_item}" return item @@ -5076,10 +5076,10 @@ def _parse_xml(adm_file): modified_xml = "" with salt.utils.files.fopen(adm_file, "rb") as rfh: - file_hash = "{:X}".format(zlib.crc32(rfh.read()) & 0xFFFFFFFF) + file_hash = f"{zlib.crc32(rfh.read()) & 0xFFFFFFFF:X}" name, ext = os.path.splitext(os.path.basename(adm_file)) - hashed_filename = "{}-{}{}".format(name, file_hash, ext) + hashed_filename = f"{name}-{file_hash}{ext}" cache_dir = os.path.join(__opts__["cachedir"], "lgpo", "policy_defs") if not os.path.exists(cache_dir): @@ -5091,7 +5091,7 @@ def _parse_xml(adm_file): log.debug("LGPO: Generating policy template cache for %s%s", name, ext) # Remove old files, keep the cache clean - file_list = glob.glob(os.path.join(cache_dir, "{}*{}".format(name, ext))) + file_list = glob.glob(os.path.join(cache_dir, f"{name}*{ext}")) for file_path in file_list: os.remove(file_path) @@ -5649,7 +5649,7 @@ def _set_advaudit_value(option, value): """ # Set the values in both audit.csv files if not _set_advaudit_file_data(option=option, value=value): - raise CommandExecutionError("Failed to set audit.csv option: {}".format(option)) + raise CommandExecutionError(f"Failed to set audit.csv option: {option}") # Apply the settings locally if not _set_advaudit_pol_data(option=option, value=value): # Only log this error, it will be in effect the next time the machine @@ -5694,7 +5694,7 @@ def _get_netsh_value(profile, option): def _set_netsh_value(profile, section, option, value): if section not in ("firewallpolicy", "settings", "logging", "state"): - raise ValueError("LGPO: Invalid section: {}".format(section)) + raise ValueError(f"LGPO: Invalid section: {section}") log.trace( "LGPO: Setting the following\nProfile: %s\nSection: %s\nOption: %s\nValue: %s", profile, @@ -5738,7 +5738,7 @@ def _load_secedit_data(): Returns: str: The contents of the file generated by the secedit command """ - f_exp = os.path.join(__opts__["cachedir"], "secedit-{}.txt".format(UUID)) + f_exp = os.path.join(__opts__["cachedir"], f"secedit-{UUID}.txt") try: __salt__["cmd.run"](["secedit", "/export", "/cfg", f_exp]) with salt.utils.files.fopen(f_exp, encoding="utf-16") as fp: @@ -5788,7 +5788,7 @@ def _write_secedit_data(inf_data): # Set file names # The database must persist in order for the settings to remain in effect f_sdb = os.path.join(os.getenv("WINDIR"), "security", "database", "salt.sdb") - f_inf = os.path.join(__opts__["cachedir"], "secedit-{}.inf".format(UUID)) + f_inf = os.path.join(__opts__["cachedir"], f"secedit-{UUID}.inf") try: # Write the changes to the inf file @@ -5948,9 +5948,7 @@ def _getAdmlPresentationRefId(adml_data, ref_id): """ helper function to check for a presentation label for a policy element """ - search_results = adml_data.xpath( - '//*[@*[local-name() = "refId"] = "{}"]'.format(ref_id) - ) + search_results = adml_data.xpath(f'//*[@*[local-name() = "refId"] = "{ref_id}"]') alternate_label = "" if search_results: for result in search_results: @@ -6216,7 +6214,7 @@ def _encode_string(value): elif not isinstance(value, str): # Should we raise an error here, or attempt to cast to a string raise TypeError( - "Value {} is not a string type\nType: {}".format(repr(value), type(value)) + f"Value {repr(value)} is not a string type\nType: {type(value)}" ) return b"".join([value.encode("utf-16-le"), encoded_null]) @@ -6257,7 +6255,7 @@ def _buildKnownDataSearchString( encoded_semicolon, chr(registry.vtype[reg_vtype]).encode("utf-32-le"), encoded_semicolon, - chr(len(" {}".format(chr(0)).encode("utf-16-le"))).encode("utf-32-le"), + chr(len(f" {chr(0)}".encode("utf-16-le"))).encode("utf-32-le"), encoded_semicolon, " ".encode("utf-16-le"), encoded_null, @@ -6437,7 +6435,7 @@ def _processValueItem( encoded_semicolon, chr(registry.vtype[this_vtype]).encode("utf-32-le"), encoded_semicolon, - chr(len(" {}".format(chr(0)).encode("utf-16-le"))).encode( + chr(len(f" {chr(0)}".encode("utf-16-le"))).encode( "utf-32-le" ), encoded_semicolon, @@ -6492,7 +6490,7 @@ def _processValueItem( encoded_semicolon, chr( len( - "{}{}".format(element_values[i], chr(0)).encode( + f"{element_values[i]}{chr(0)}".encode( "utf-16-le" ) ) @@ -6523,9 +6521,7 @@ def _processValueItem( encoded_semicolon, chr(registry.vtype[this_vtype]).encode("utf-32-le"), encoded_semicolon, - chr(len(" {}".format(chr(0)).encode("utf-16-le"))).encode( - "utf-32-le" - ), + chr(len(f" {chr(0)}".encode("utf-16-le"))).encode("utf-32-le"), encoded_semicolon, " ".encode("utf-16-le"), encoded_null, @@ -6589,9 +6585,7 @@ def _processValueItem( encoded_semicolon, chr(registry.vtype[this_vtype]).encode("utf-32-le"), encoded_semicolon, - chr(len(" {}".format(chr(0)).encode("utf-16-le"))).encode( - "utf-32-le" - ), + chr(len(f" {chr(0)}".encode("utf-16-le"))).encode("utf-32-le"), encoded_semicolon, " ".encode("utf-16-le"), encoded_null, @@ -6643,10 +6637,10 @@ def _checkAllAdmxPolicies( if policy_file_data: log.trace("POLICY CLASS %s has file data", policy_class) policy_filedata_split = re.sub( - salt.utils.stringutils.to_bytes(r"\]{}$".format(chr(0))), + salt.utils.stringutils.to_bytes(rf"\]{chr(0)}$"), b"", re.sub( - salt.utils.stringutils.to_bytes(r"^\[{}".format(chr(0))), + salt.utils.stringutils.to_bytes(rf"^\[{chr(0)}"), b"", re.sub( re.escape(REG_POL_HEADER.encode("utf-16-le")), @@ -6660,7 +6654,7 @@ def _checkAllAdmxPolicies( # Get the policy for each item defined in Registry.pol for policy_item in policy_filedata_split: policy_item_key = ( - policy_item.split("{};".format(chr(0)).encode("utf-16-le"))[0] + policy_item.split(f"{chr(0)};".encode("utf-16-le"))[0] .decode("utf-16-le") .lower() ) @@ -7423,7 +7417,7 @@ def _build_parent_list(policy_definition, return_full_policy_names, adml_languag parent_list = [] policy_namespace = next(iter(policy_definition.nsmap)) parent_category = policy_definition.xpath( - "{}:parentCategory/@ref".format(policy_namespace), + f"{policy_namespace}:parentCategory/@ref", namespaces=policy_definition.nsmap, ) admx_policy_definitions = _get_policy_definitions(language=adml_language) @@ -7494,14 +7488,14 @@ def _admx_policy_parent_walk( ) path.append(this_parent_name) if tparent_category.xpath( - "{}:parentCategory/@ref".format(policy_namespace), namespaces=policy_nsmap + f"{policy_namespace}:parentCategory/@ref", namespaces=policy_nsmap ): # parent has a parent path = _admx_policy_parent_walk( path=path, policy_namespace=policy_namespace, parent_category=tparent_category.xpath( - "{}:parentCategory/@ref".format(policy_namespace), + f"{policy_namespace}:parentCategory/@ref", namespaces=policy_nsmap, )[0], policy_nsmap=policy_nsmap, @@ -8533,7 +8527,7 @@ def _lookup_admin_template(policy_name, policy_class, adml_language="en-US"): False, None, [], - "Unable to find {} policy {}".format(policy_class, policy_name), + f"Unable to find {policy_class} policy {policy_name}", ) diff --git a/salt/modules/win_lgpo_reg.py b/salt/modules/win_lgpo_reg.py index 3ee147aa812..6789b034a88 100644 --- a/salt/modules/win_lgpo_reg.py +++ b/salt/modules/win_lgpo_reg.py @@ -342,22 +342,22 @@ def set_value( "REG_SZ", ] if v_type not in valid_types: - msg = "Invalid type: {}".format(v_type) + msg = f"Invalid type: {v_type}" raise SaltInvocationError(msg) if v_type in ["REG_SZ", "REG_EXPAND_SZ"]: if not isinstance(v_data, str): - msg = "{} data must be a string".format(v_type) + msg = f"{v_type} data must be a string" raise SaltInvocationError(msg) elif v_type == "REG_MULTI_SZ": if not isinstance(v_data, list): - msg = "{} data must be a list".format(v_type) + msg = f"{v_type} data must be a list" raise SaltInvocationError(msg) elif v_type in ["REG_DWORD", "REG_QWORD"]: try: int(v_data) except (TypeError, ValueError): - msg = "{} data must be an integer".format(v_type) + msg = f"{v_type} data must be an integer" raise SaltInvocationError(msg) pol_data = read_reg_pol(policy_class=policy_class) @@ -467,11 +467,11 @@ def disable_value(key, v_name, policy_class="machine"): return None log.debug("LGPO_REG Mod: Disabling value name: %s", v_name) pol_data[found_key].pop(found_name) - found_name = "**del.{}".format(found_name) + found_name = f"**del.{found_name}" pol_data[found_key][found_name] = {"data": " ", "type": "REG_SZ"} else: log.debug("LGPO_REG Mod: Setting new disabled value name: %s", v_name) - pol_data[found_key]["**del.{}".format(v_name)] = { + pol_data[found_key][f"**del.{v_name}"] = { "data": " ", "type": "REG_SZ", } @@ -479,7 +479,7 @@ def disable_value(key, v_name, policy_class="machine"): log.debug( "LGPO_REG Mod: Adding new key and disabled value name: %s", found_name ) - pol_data[key] = {"**del.{}".format(v_name): {"data": " ", "type": "REG_SZ"}} + pol_data[key] = {f"**del.{v_name}": {"data": " ", "type": "REG_SZ"}} success = True if not write_reg_pol(pol_data, policy_class=policy_class): diff --git a/salt/modules/win_license.py b/salt/modules/win_license.py index 5311418abd0..11851398579 100644 --- a/salt/modules/win_license.py +++ b/salt/modules/win_license.py @@ -52,7 +52,7 @@ def install(product_key): salt '*' license.install XXXXX-XXXXX-XXXXX-XXXXX-XXXXX """ - cmd = r"cscript C:\Windows\System32\slmgr.vbs /ipk {}".format(product_key) + cmd = rf"cscript C:\Windows\System32\slmgr.vbs /ipk {product_key}" return __salt__["cmd.run"](cmd) diff --git a/salt/modules/win_network.py b/salt/modules/win_network.py index ad57ca33bc3..d3d9de5681d 100644 --- a/salt/modules/win_network.py +++ b/salt/modules/win_network.py @@ -259,7 +259,7 @@ def get_route(ip): salt '*' network.get_route 10.10.10.10 """ - cmd = "Find-NetRoute -RemoteIPAddress {}".format(ip) + cmd = f"Find-NetRoute -RemoteIPAddress {ip}" out = __salt__["cmd.run"](cmd, shell="powershell", python_shell=True) regexp = re.compile( r"^IPAddress\s+:\s(?P[\d\.:]+)?.*" @@ -492,7 +492,7 @@ def connect(host, port=None, **kwargs): ): address = host else: - address = "{}".format(salt.utils.network.sanitize_host(host)) + address = f"{salt.utils.network.sanitize_host(host)}" # just in case we encounter error on getaddrinfo _address = ("unknown",) diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index bc421a1f9bd..aff40b3d54d 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -489,14 +489,14 @@ def _get_reg_software(include_components=True, include_updates=True): return False if __utils__["reg.value_exists"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="SystemComponent", use_32bit_registry=use_32bit_registry, ): if ( __utils__["reg.read_value"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="SystemComponent", use_32bit_registry=use_32bit_registry, )["vdata"] @@ -518,14 +518,14 @@ def _get_reg_software(include_components=True, include_updates=True): products_key = "Software\\Classes\\Installer\\Products\\{0}" if __utils__["reg.value_exists"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="WindowsInstaller", use_32bit_registry=use_32bit_registry, ): if ( __utils__["reg.read_value"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="WindowsInstaller", use_32bit_registry=use_32bit_registry, )["vdata"] @@ -556,14 +556,14 @@ def _get_reg_software(include_components=True, include_updates=True): # https://docs.microsoft.com/en-us/windows/win32/msi/arpnoremove if __utils__["reg.value_exists"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="NoRemove", use_32bit_registry=use_32bit_registry, ): if ( __utils__["reg.read_value"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="NoRemove", use_32bit_registry=use_32bit_registry, )["vdata"] @@ -572,7 +572,7 @@ def _get_reg_software(include_components=True, include_updates=True): return False if not __utils__["reg.value_exists"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="UninstallString", use_32bit_registry=use_32bit_registry, ): @@ -593,14 +593,14 @@ def _get_reg_software(include_components=True, include_updates=True): skip_types = ["Hotfix", "Security Update", "Update Rollup"] if __utils__["reg.value_exists"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="ReleaseType", use_32bit_registry=use_32bit_registry, ): if ( __utils__["reg.read_value"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="ReleaseType", use_32bit_registry=use_32bit_registry, )["vdata"] @@ -619,7 +619,7 @@ def _get_reg_software(include_components=True, include_updates=True): """ if __utils__["reg.value_exists"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="ParentKeyName", use_32bit_registry=use_32bit_registry, ): @@ -636,7 +636,7 @@ def _get_reg_software(include_components=True, include_updates=True): """ d_name_regdata = __utils__["reg.read_value"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="DisplayName", use_32bit_registry=use_32bit_registry, ) @@ -655,7 +655,7 @@ def _get_reg_software(include_components=True, include_updates=True): d_vers_regdata = __utils__["reg.read_value"]( hive=hive, - key="{}\\{}".format(key, sub_key), + key=f"{key}\\{sub_key}", vname="DisplayVersion", use_32bit_registry=use_32bit_registry, ) @@ -726,7 +726,7 @@ def _get_reg_software(include_components=True, include_updates=True): for sub_key in __utils__["reg.list_keys"](**kwargs): # If the key does not exist in userdata, skip it if not __utils__["reg.key_exists"]( - hive=kwargs["hive"], key="{}\\{}".format(userdata_key, sub_key) + hive=kwargs["hive"], key=f"{userdata_key}\\{sub_key}" ): continue kwargs["sub_key"] = sub_key @@ -1040,7 +1040,7 @@ def _get_repo_details(saltenv): """ Return repo details for the specified saltenv as a namedtuple """ - contextkey = "winrepo._get_repo_details.{}".format(saltenv) + contextkey = f"winrepo._get_repo_details.{saltenv}" if contextkey in __context__: (winrepo_source_dir, local_dest, winrepo_file) = __context__[contextkey] @@ -1085,9 +1085,7 @@ def _get_repo_details(saltenv): os.makedirs(local_dest) except OSError as exc: if exc.errno != errno.EEXIST: - raise CommandExecutionError( - "Failed to create {}: {}".format(local_dest, exc) - ) + raise CommandExecutionError(f"Failed to create {local_dest}: {exc}") winrepo_age = -1 try: @@ -1096,9 +1094,7 @@ def _get_repo_details(saltenv): winrepo_age = time.time() - mtime except OSError as exc: if exc.errno != errno.ENOENT: - raise CommandExecutionError( - "Failed to get age of {}: {}".format(winrepo_file, exc) - ) + raise CommandExecutionError(f"Failed to get age of {winrepo_file}: {exc}") except AttributeError: # Shouldn't happen but log if it does log.warning("st_mtime missing from stat result %s", stat_result) @@ -1221,9 +1217,7 @@ def _repo_process_pkg_sls(filename, short_path_name, ret, successful_verbose): def _failed_compile(prefix_msg, error_msg): log.error("%s '%s': %s", prefix_msg, short_path_name, error_msg) - ret.setdefault("errors", {})[short_path_name] = [ - "{}, {} ".format(prefix_msg, error_msg) - ] + ret.setdefault("errors", {})[short_path_name] = [f"{prefix_msg}, {error_msg} "] return False try: @@ -1249,7 +1243,7 @@ def _repo_process_pkg_sls(filename, short_path_name, ret, successful_verbose): pkgname, short_path_name, ) - errors.append("package '{}' already defined".format(pkgname)) + errors.append(f"package '{pkgname}' already defined") break for version_str, repodata in version_list.items(): # Ensure version is a string/unicode @@ -1321,9 +1315,7 @@ def _get_source_sum(source_hash, file_path, saltenv, verify_ssl=True): raise if not cached_hash_file: - raise CommandExecutionError( - "Source hash file {} not found".format(source_hash) - ) + raise CommandExecutionError(f"Source hash file {source_hash} not found") ret = __salt__["file.extract_hash"](cached_hash_file, "", file_path) if ret is None: @@ -1581,7 +1573,7 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): # Make sure pkginfo was found if not pkginfo: log.error("Unable to locate package %s", pkg_name) - ret[pkg_name] = "Unable to locate package {}".format(pkg_name) + ret[pkg_name] = f"Unable to locate package {pkg_name}" continue version_num = options.get("version") @@ -1665,9 +1657,9 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): exclude_pat="E@init.sls$", ) except MinionError as exc: - msg = "Failed to cache {}".format(path) + msg = f"Failed to cache {path}" log.exception(msg, exc_info=exc) - return "{}\n{}".format(msg, exc) + return f"{msg}\n{exc}" # Check to see if the cache_file is cached... if passed if cache_file and cache_file.startswith("salt:"): @@ -1681,9 +1673,9 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): verify_ssl=kwargs.get("verify_ssl", True), ) except MinionError as exc: - msg = "Failed to cache {}".format(cache_file) + msg = f"Failed to cache {cache_file}" log.exception(msg, exc_info=exc) - return "{}\n{}".format(msg, exc) + return f"{msg}\n{exc}" # Check if the cache_file was cached successfully if not cached_file: @@ -1712,9 +1704,9 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): use_etag=True, ) except MinionError as exc: - msg = "Failed to cache {}".format(installer) + msg = f"Failed to cache {installer}" log.exception(msg, exc_info=exc) - return "{}\n{}".format(msg, exc) + return f"{msg}\n{exc}" # Check if the installer was cached successfully if not cached_pkg: @@ -1779,14 +1771,14 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): "ComSpec", "{}\\system32\\cmd.exe".format(os.getenv("WINDIR")) ) if use_msiexec: - arguments = '"{}" /I "{}"'.format(msiexec, cached_pkg) + arguments = f'"{msiexec}" /I "{cached_pkg}"' if pkginfo[version_num].get("allusers", True): - arguments = "{} ALLUSERS=1".format(arguments) + arguments = f"{arguments} ALLUSERS=1" else: - arguments = '"{}"'.format(cached_pkg) + arguments = f'"{cached_pkg}"' if install_flags: - arguments = "{} {}".format(arguments, install_flags) + arguments = f"{arguments} {install_flags}" # Install the software # Check Use Scheduler Option @@ -1800,7 +1792,7 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): force=True, action_type="Execute", cmd=cmd_shell, - arguments='/c "{}"'.format(arguments), + arguments=f'/c "{arguments}"', start_in=cache_path, trigger_type="Once", start_date="1975-01-01", @@ -1852,7 +1844,7 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): else: # Launch the command result = __salt__["cmd.run_all"]( - '"{}" /c "{}"'.format(cmd_shell, arguments), + f'"{cmd_shell}" /c "{arguments}"', cache_path, output_loglevel="trace", python_shell=False, @@ -2005,7 +1997,7 @@ def remove(name=None, pkgs=None, **kwargs): # Make sure pkginfo was found if not pkginfo: - msg = "Unable to locate package {}".format(pkgname) + msg = f"Unable to locate package {pkgname}" log.error(msg) ret[pkgname] = msg continue @@ -2045,7 +2037,7 @@ def remove(name=None, pkgs=None, **kwargs): removal_targets.append(version_num) else: log.debug("%s %s not installed", pkgname, version_num) - ret[pkgname] = {"current": "{} not installed".format(version_num)} + ret[pkgname] = {"current": f"{version_num} not installed"} continue elif "latest" in pkginfo: # we do not have version entry, assume software can self upgrade and use latest @@ -2060,9 +2052,7 @@ def remove(name=None, pkgs=None, **kwargs): log.error( "%s %s no definition to remove this version", pkgname, version_num ) - ret[pkgname] = { - "current": "{} no definition, cannot removed".format(version_num) - } + ret[pkgname] = {"current": f"{version_num} no definition, cannot removed"} continue for target in removal_targets: @@ -2111,9 +2101,9 @@ def remove(name=None, pkgs=None, **kwargs): exclude_pat="E@init.sls$", ) except MinionError as exc: - msg = "Failed to cache {}".format(path) + msg = f"Failed to cache {path}" log.exception(msg, exc_info=exc) - return "{}\n{}".format(msg, exc) + return f"{msg}\n{exc}" # Check to see if the uninstaller is cached. We don't want to # check for latest here like we do for "pkg.install" because we @@ -2135,9 +2125,9 @@ def remove(name=None, pkgs=None, **kwargs): use_etag=True, ) except MinionError as exc: - msg = "Failed to cache {}".format(uninstaller) + msg = f"Failed to cache {uninstaller}" log.exception(msg, exc_info=exc) - return "{}\n{}".format(msg, exc) + return f"{msg}\n{exc}" # Check if the uninstaller was cached successfully if not cached_pkg: @@ -2171,12 +2161,12 @@ def remove(name=None, pkgs=None, **kwargs): if use_msiexec: # Check if uninstaller is set to {guid}, if not we assume its a remote msi file. # which has already been downloaded. - arguments = '"{}" /X "{}"'.format(msiexec, cached_pkg) + arguments = f'"{msiexec}" /X "{cached_pkg}"' else: - arguments = '"{}"'.format(cached_pkg) + arguments = f'"{cached_pkg}"' if uninstall_flags: - arguments = "{} {}".format(arguments, uninstall_flags) + arguments = f"{arguments} {uninstall_flags}" # Uninstall the software changed.append(pkgname) @@ -2191,7 +2181,7 @@ def remove(name=None, pkgs=None, **kwargs): force=True, action_type="Execute", cmd=cmd_shell, - arguments='/c "{}"'.format(arguments), + arguments=f'/c "{arguments}"', start_in=cache_path, trigger_type="Once", start_date="1975-01-01", @@ -2208,7 +2198,7 @@ def remove(name=None, pkgs=None, **kwargs): else: # Launch the command result = __salt__["cmd.run_all"]( - '"{}" /c "{}"'.format(cmd_shell, arguments), + f'"{cmd_shell}" /c "{arguments}"', output_loglevel="trace", python_shell=False, redirect_stderr=True, diff --git a/salt/modules/win_pki.py b/salt/modules/win_pki.py index c90af40dd1b..e004f0bc9e8 100644 --- a/salt/modules/win_pki.py +++ b/salt/modules/win_pki.py @@ -90,10 +90,10 @@ def _validate_cert_path(name): """ Ensure that the certificate path, as determind from user input, is valid. """ - cmd = r"Test-Path -Path '{}'".format(name) + cmd = rf"Test-Path -Path '{name}'" if not ast.literal_eval(_cmd_run(cmd=cmd)): - raise SaltInvocationError(r"Invalid path specified: {}".format(name)) + raise SaltInvocationError(rf"Invalid path specified: {name}") def _validate_cert_format(name): @@ -155,11 +155,11 @@ def get_certs(context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE): ret = dict() cmd = list() blacklist_keys = ["DnsNameList"] - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" _validate_cert_path(name=store_path) - cmd.append(r"Get-ChildItem -Path '{}' | Select-Object".format(store_path)) + cmd.append(rf"Get-ChildItem -Path '{store_path}' | Select-Object") cmd.append(" DnsNameList, SerialNumber, Subject, Thumbprint, Version") items = _cmd_run(cmd="".join(cmd), as_json=True) @@ -216,15 +216,15 @@ def get_cert_file(name, cert_format=_DEFAULT_FORMAT, password=""): cmd.append( " System.Security.Cryptography.X509Certificates.X509Certificate2;" ) - cmd.append(r" $CertObject.Import('{}'".format(name)) - cmd.append(",'{}'".format(password)) + cmd.append(rf" $CertObject.Import('{name}'") + cmd.append(f",'{password}'") cmd.append(",'DefaultKeySet') ; $CertObject") cmd.append( " | Select-Object DnsNameList, SerialNumber, Subject, " "Thumbprint, Version" ) else: - cmd.append(r"Get-PfxCertificate -FilePath '{}'".format(name)) + cmd.append(rf"Get-PfxCertificate -FilePath '{name}'") cmd.append( " | Select-Object DnsNameList, SerialNumber, Subject, " "Thumbprint, Version" @@ -232,7 +232,7 @@ def get_cert_file(name, cert_format=_DEFAULT_FORMAT, password=""): else: cmd.append("$CertObject = New-Object") cmd.append(" System.Security.Cryptography.X509Certificates.X509Certificate2;") - cmd.append(r" $CertObject.Import('{}'); $CertObject".format(name)) + cmd.append(rf" $CertObject.Import('{name}'); $CertObject") cmd.append( " | Select-Object DnsNameList, SerialNumber, Subject, Thumbprint, Version" ) @@ -288,7 +288,7 @@ def import_cert( """ cmd = list() thumbprint = None - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" cert_format = cert_format.lower() _validate_cert_format(name=cert_format) @@ -331,14 +331,14 @@ def import_cert( cmd.append( r"Import-PfxCertificate " r"-FilePath '{}'".format(cached_source_path) ) - cmd.append(r" -CertStoreLocation '{}'".format(store_path)) + cmd.append(rf" -CertStoreLocation '{store_path}'") cmd.append(r" -Password $Password") if exportable: cmd.append(" -Exportable") else: cmd.append(r"Import-Certificate " r"-FilePath '{}'".format(cached_source_path)) - cmd.append(r" -CertStoreLocation '{}'".format(store_path)) + cmd.append(rf" -CertStoreLocation '{store_path}'") _cmd_run(cmd="".join(cmd)) @@ -387,7 +387,7 @@ def export_cert( """ cmd = list() thumbprint = thumbprint.upper() - cert_path = r"Cert:\{}\{}\{}".format(context, store, thumbprint) + cert_path = rf"Cert:\{context}\{store}\{thumbprint}" cert_format = cert_format.lower() _validate_cert_path(name=cert_path) @@ -415,7 +415,7 @@ def export_cert( r"Export-Certificate " r"-Cert '{}' -FilePath '{}'".format(cert_path, name) ) - cmd.append(r" | Out-Null; Test-Path -Path '{}'".format(name)) + cmd.append(rf" | Out-Null; Test-Path -Path '{name}'") ret = ast.literal_eval(_cmd_run(cmd="".join(cmd))) @@ -458,17 +458,17 @@ def test_cert( """ cmd = list() thumbprint = thumbprint.upper() - cert_path = r"Cert:\{}\{}\{}".format(context, store, thumbprint) - cmd.append(r"Test-Certificate -Cert '{}'".format(cert_path)) + cert_path = rf"Cert:\{context}\{store}\{thumbprint}" + cmd.append(rf"Test-Certificate -Cert '{cert_path}'") _validate_cert_path(name=cert_path) if untrusted_root: cmd.append(" -AllowUntrustedRoot") if dns_name: - cmd.append(" -DnsName '{}'".format(dns_name)) + cmd.append(f" -DnsName '{dns_name}'") if eku: - cmd.append(" -EKU '{}'".format(eku)) + cmd.append(f" -EKU '{eku}'") cmd.append(" -ErrorAction SilentlyContinue") @@ -493,9 +493,9 @@ def remove_cert(thumbprint, context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE): salt '*' win_pki.remove_cert thumbprint='AAA000' """ thumbprint = thumbprint.upper() - store_path = r"Cert:\{}\{}".format(context, store) - cert_path = r"{}\{}".format(store_path, thumbprint) - cmd = r"Remove-Item -Path '{}'".format(cert_path) + store_path = rf"Cert:\{context}\{store}" + cert_path = rf"{store_path}\{thumbprint}" + cmd = rf"Remove-Item -Path '{cert_path}'" current_certs = get_certs(context=context, store=store) diff --git a/salt/modules/win_powercfg.py b/salt/modules/win_powercfg.py index 5a76e98b58b..16428b48ea7 100644 --- a/salt/modules/win_powercfg.py +++ b/salt/modules/win_powercfg.py @@ -47,9 +47,9 @@ def _get_powercfg_minute_values(scheme, guid, subguid, safe_name): scheme = _get_current_scheme() if __grains__["osrelease"] == "7": - cmd = "powercfg /q {} {}".format(scheme, guid) + cmd = f"powercfg /q {scheme} {guid}" else: - cmd = "powercfg /q {} {} {}".format(scheme, guid, subguid) + cmd = f"powercfg /q {scheme} {guid} {subguid}" out = __salt__["cmd.run"](cmd, python_shell=False) split = out.split("\r\n\r\n") diff --git a/salt/modules/win_psget.py b/salt/modules/win_psget.py index 66302b4f91e..af978969a98 100644 --- a/salt/modules/win_psget.py +++ b/salt/modules/win_psget.py @@ -82,7 +82,7 @@ def _pshell(cmd, cwd=None, depth=2): in Xml format and load that into python """ - cmd = '{} | ConvertTo-Xml -Depth {} -As "stream"'.format(cmd, depth) + cmd = f'{cmd} | ConvertTo-Xml -Depth {depth} -As "stream"' log.debug("DSC: %s", cmd) results = __salt__["cmd.run_all"]( @@ -94,9 +94,7 @@ def _pshell(cmd, cwd=None, depth=2): if "retcode" not in results or results["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError( - "Issue executing powershell {}".format(cmd), info=results - ) + raise CommandExecutionError(f"Issue executing powershell {cmd}", info=results) try: ret = _ps_xml_to_dict( @@ -224,8 +222,8 @@ def install( flags.append(("Repository", repository)) params = "" for flag, value in flags: - params += "-{} {} ".format(flag, value) - cmd = "Install-Module {} -Force".format(params) + params += f"-{flag} {value} " + cmd = f"Install-Module {params} -Force" _pshell(cmd) return name in list_modules() @@ -259,8 +257,8 @@ def update(name, maximum_version=None, required_version=None): params = "" for flag, value in flags: - params += "-{} {} ".format(flag, value) - cmd = "Update-Module {} -Force".format(params) + params += f"-{flag} {value} " + cmd = f"Update-Module {params} -Force" _pshell(cmd) return name in list_modules() @@ -279,7 +277,7 @@ def remove(name): salt 'win01' psget.remove PowerPlan """ # Putting quotes around the parameter protects against command injection - cmd = 'Uninstall-Module "{}"'.format(name) + cmd = f'Uninstall-Module "{name}"' no_ret = _pshell(cmd) return name not in list_modules() @@ -313,8 +311,8 @@ def register_repository(name, location, installation_policy=None): params = "" for flag, value in flags: - params += "-{} {} ".format(flag, value) - cmd = "Register-PSRepository {}".format(params) + params += f"-{flag} {value} " + cmd = f"Register-PSRepository {params}" no_ret = _pshell(cmd) return name not in list_modules() @@ -333,6 +331,6 @@ def get_repository(name): salt 'win01' psget.get_repository MyRepo """ # Putting quotes around the parameter protects against command injection - cmd = 'Get-PSRepository "{}"'.format(name) + cmd = f'Get-PSRepository "{name}"' no_ret = _pshell(cmd) return name not in list_modules() diff --git a/salt/modules/win_servermanager.py b/salt/modules/win_servermanager.py index cab3d996e82..85bececc3c4 100644 --- a/salt/modules/win_servermanager.py +++ b/salt/modules/win_servermanager.py @@ -55,9 +55,9 @@ def _pshell_json(cmd, cwd=None): Execute the desired powershell command and ensure that it returns data in JSON format and load that into python """ - cmd = "Import-Module ServerManager; {}".format(cmd) + cmd = f"Import-Module ServerManager; {cmd}" if "convertto-json" not in cmd.lower(): - cmd = "{} | ConvertTo-Json".format(cmd) + cmd = f"{cmd} | ConvertTo-Json" log.debug("PowerShell: %s", cmd) ret = __salt__["cmd.run_all"](cmd, shell="powershell", cwd=cwd) @@ -70,9 +70,7 @@ def _pshell_json(cmd, cwd=None): if "retcode" not in ret or ret["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError( - "Issue executing PowerShell {}".format(cmd), info=ret - ) + raise CommandExecutionError(f"Issue executing PowerShell {cmd}", info=ret) # Sometimes Powershell returns an empty string, which isn't valid JSON if ret["stdout"] == "": @@ -227,7 +225,7 @@ def install(feature, recurse=False, restart=False, source=None, exclude=None): shlex.quote(feature), management_tools, "-IncludeAllSubFeature" if recurse else "", - "" if source is None else "-Source {}".format(source), + "" if source is None else f"-Source {source}", ) out = _pshell_json(cmd) diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index 604a22fd5bd..38356e87c69 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -113,7 +113,7 @@ def _cmd_quote(cmd): cmd = cmd.strip('"').strip("'") # Ensure the path to the binary is wrapped in double quotes to account for # spaces in the path - cmd = '"{}"'.format(cmd) + cmd = f'"{cmd}"' return cmd @@ -340,9 +340,7 @@ def start(name, timeout=90): win32serviceutil.StartService(name) except pywintypes.error as exc: if exc.winerror != 1056: - raise CommandExecutionError( - "Failed To Start {}: {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed To Start {name}: {exc.strerror}") log.debug('Service "%s" is running', name) srv_status = _status_wait( @@ -381,9 +379,7 @@ def stop(name, timeout=90): win32serviceutil.StopService(name) except pywintypes.error as exc: if exc.winerror != 1062: - raise CommandExecutionError( - "Failed To Stop {}: {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed To Stop {name}: {exc.strerror}") log.debug('Service "%s" is not running', name) srv_status = _status_wait( @@ -669,7 +665,7 @@ def modify( win32service.SERVICE_CHANGE_CONFIG | win32service.SERVICE_QUERY_CONFIG, ) except pywintypes.error as exc: - raise CommandExecutionError("Failed To Open {}: {}".format(name, exc.strerror)) + raise CommandExecutionError(f"Failed To Open {name}: {exc.strerror}") config_info = win32service.QueryServiceConfig(handle_svc) @@ -680,7 +676,7 @@ def modify( # shlex.quote the path to the binary bin_path = _cmd_quote(bin_path) if exe_args is not None: - bin_path = "{} {}".format(bin_path, exe_args) + bin_path = f"{bin_path} {exe_args}" changes["BinaryPath"] = bin_path if service_type is not None: @@ -689,7 +685,7 @@ def modify( if run_interactive: service_type = service_type | win32service.SERVICE_INTERACTIVE_PROCESS else: - raise CommandExecutionError("Invalid Service Type: {}".format(service_type)) + raise CommandExecutionError(f"Invalid Service Type: {service_type}") else: if run_interactive is True: service_type = config_info[0] | win32service.SERVICE_INTERACTIVE_PROCESS @@ -710,7 +706,7 @@ def modify( if start_type.lower() in SERVICE_START_TYPE: start_type = SERVICE_START_TYPE[start_type.lower()] else: - raise CommandExecutionError("Invalid Start Type: {}".format(start_type)) + raise CommandExecutionError(f"Invalid Start Type: {start_type}") changes["StartType"] = SERVICE_START_TYPE[start_type] else: start_type = win32service.SERVICE_NO_CHANGE @@ -719,9 +715,7 @@ def modify( if error_control.lower() in SERVICE_ERROR_CONTROL: error_control = SERVICE_ERROR_CONTROL[error_control.lower()] else: - raise CommandExecutionError( - "Invalid Error Control: {}".format(error_control) - ) + raise CommandExecutionError(f"Invalid Error Control: {error_control}") changes["ErrorControl"] = SERVICE_ERROR_CONTROL[error_control] else: error_control = win32service.SERVICE_NO_CHANGE @@ -898,7 +892,7 @@ def create( account_name=".\\LocalSystem", account_password=None, run_interactive=False, - **kwargs + **kwargs, ): """ Create the named service. @@ -1004,29 +998,29 @@ def create( # Test if the service already exists if name in get_all(): - raise CommandExecutionError("Service Already Exists: {}".format(name)) + raise CommandExecutionError(f"Service Already Exists: {name}") # shlex.quote the path to the binary bin_path = _cmd_quote(bin_path) if exe_args is not None: - bin_path = "{} {}".format(bin_path, exe_args) + bin_path = f"{bin_path} {exe_args}" if service_type.lower() in SERVICE_TYPE: service_type = SERVICE_TYPE[service_type.lower()] if run_interactive: service_type = service_type | win32service.SERVICE_INTERACTIVE_PROCESS else: - raise CommandExecutionError("Invalid Service Type: {}".format(service_type)) + raise CommandExecutionError(f"Invalid Service Type: {service_type}") if start_type.lower() in SERVICE_START_TYPE: start_type = SERVICE_START_TYPE[start_type.lower()] else: - raise CommandExecutionError("Invalid Start Type: {}".format(start_type)) + raise CommandExecutionError(f"Invalid Start Type: {start_type}") if error_control.lower() in SERVICE_ERROR_CONTROL: error_control = SERVICE_ERROR_CONTROL[error_control.lower()] else: - raise CommandExecutionError("Invalid Error Control: {}".format(error_control)) + raise CommandExecutionError(f"Invalid Error Control: {error_control}") if start_delayed: if start_type != 2: @@ -1121,18 +1115,14 @@ def delete(name, timeout=90): except pywintypes.error as exc: win32service.CloseServiceHandle(handle_scm) if exc.winerror != 1060: - raise CommandExecutionError( - "Failed to open {}. {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed to open {name}. {exc.strerror}") log.debug('Service "%s" is not present', name) return True try: win32service.DeleteService(handle_svc) except pywintypes.error as exc: - raise CommandExecutionError( - "Failed to delete {}. {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed to delete {name}. {exc.strerror}") finally: log.debug("Cleaning up") win32service.CloseServiceHandle(handle_scm) diff --git a/salt/modules/win_shortcut.py b/salt/modules/win_shortcut.py index 6bdb679d385..f3ae9d5942e 100644 --- a/salt/modules/win_shortcut.py +++ b/salt/modules/win_shortcut.py @@ -75,11 +75,11 @@ def get(path): salt * shortcut.get path="C:\path\to\shortcut.lnk" """ if not os.path.exists(path): - raise CommandExecutionError("Shortcut not found: {}".format(path)) + raise CommandExecutionError(f"Shortcut not found: {path}") if not path.endswith((".lnk", ".url")): _, ext = os.path.splitext(path) - raise CommandExecutionError("Invalid file extension: {}".format(ext)) + raise CommandExecutionError(f"Invalid file extension: {ext}") # This will load the existing shortcut with salt.utils.winapi.Com(): @@ -104,7 +104,7 @@ def get(path): if target: target = salt.utils.path.expand(target) else: - msg = "Not a valid shortcut: {}".format(path) + msg = f"Not a valid shortcut: {path}" log.debug(msg) raise CommandExecutionError(msg) if shortcut.Arguments: @@ -302,11 +302,11 @@ def modify( salt * shortcut.modify "C:\path\to\shortcut.lnk" "C:\Windows\notepad.exe" """ if not os.path.exists(path): - raise CommandExecutionError("Shortcut not found: {}".format(path)) + raise CommandExecutionError(f"Shortcut not found: {path}") if not path.endswith((".lnk", ".url")): _, ext = os.path.splitext(path) - raise CommandExecutionError("Invalid file extension: {}".format(ext)) + raise CommandExecutionError(f"Invalid file extension: {ext}") return _set_info( path=path, @@ -438,14 +438,14 @@ def create( """ if not path.endswith((".lnk", ".url")): _, ext = os.path.splitext(path) - raise CommandExecutionError("Invalid file extension: {}".format(ext)) + raise CommandExecutionError(f"Invalid file extension: {ext}") if os.path.exists(path): if backup: log.debug("Backing up: %s", path) file, ext = os.path.splitext(path) ext = ext.strip(".") - backup_path = "{}-{}.{}".format(file, time.time_ns(), ext) + backup_path = f"{file}-{time.time_ns()}.{ext}" os.rename(path, backup_path) elif force: log.debug("Removing: %s", path) @@ -474,11 +474,11 @@ def create( __salt__["file.makedirs"](path=path, owner=user) except CommandExecutionError as exc: raise CommandExecutionError( - "Error creating parent directory: {}".format(exc.message) + f"Error creating parent directory: {exc.message}" ) else: raise CommandExecutionError( - "Parent directory not present: {}".format(os.path.dirname(path)) + f"Parent directory not present: {os.path.dirname(path)}" ) return _set_info( diff --git a/salt/modules/win_smtp_server.py b/salt/modules/win_smtp_server.py index ab0e602fe79..44531a569b9 100644 --- a/salt/modules/win_smtp_server.py +++ b/salt/modules/win_smtp_server.py @@ -109,7 +109,7 @@ def _normalize_server_settings(**settings): _LOG.debug("Fixing value: %s", settings[setting]) value_from_key = next(iter(settings[setting].keys())) - ret[setting] = "{{{0}}}".format(value_from_key) + ret[setting] = f"{{{value_from_key}}}" else: ret[setting] = settings[setting] return ret @@ -391,7 +391,7 @@ def get_connection_ip_list(as_wmi_format=False, server=_DEFAULT_SERVER): for unnormalized_address in addresses: ip_address, subnet = re.split(reg_separator, unnormalized_address) if as_wmi_format: - ret.append("{}, {}".format(ip_address, subnet)) + ret.append(f"{ip_address}, {subnet}") else: ret[ip_address] = subnet @@ -431,9 +431,7 @@ def set_connection_ip_list( # Convert addresses to the 'ip_address, subnet' format used by # IIsIPSecuritySetting. for address in addresses: - formatted_addresses.append( - "{}, {}".format(address.strip(), addresses[address].strip()) - ) + formatted_addresses.append(f"{address.strip()}, {addresses[address].strip()}") current_addresses = get_connection_ip_list(as_wmi_format=True, server=server) diff --git a/salt/modules/win_snmp.py b/salt/modules/win_snmp.py index 0fc7775ea6c..a2cff764477 100644 --- a/salt/modules/win_snmp.py +++ b/salt/modules/win_snmp.py @@ -11,11 +11,11 @@ from salt.exceptions import CommandExecutionError, SaltInvocationError _HKEY = "HKLM" _SNMP_KEY = r"SYSTEM\CurrentControlSet\Services\SNMP\Parameters" -_AGENT_KEY = r"{}\RFC1156Agent".format(_SNMP_KEY) -_COMMUNITIES_KEY = r"{}\ValidCommunities".format(_SNMP_KEY) +_AGENT_KEY = rf"{_SNMP_KEY}\RFC1156Agent" +_COMMUNITIES_KEY = rf"{_SNMP_KEY}\ValidCommunities" _SNMP_GPO_KEY = r"SOFTWARE\Policies\SNMP\Parameters" -_COMMUNITIES_GPO_KEY = r"{}\ValidCommunities".format(_SNMP_GPO_KEY) +_COMMUNITIES_GPO_KEY = rf"{_SNMP_GPO_KEY}\ValidCommunities" _PERMISSION_TYPES = { "None": 1, diff --git a/salt/modules/win_system.py b/salt/modules/win_system.py index 0801d40aa93..e81248c30b6 100644 --- a/salt/modules/win_system.py +++ b/salt/modules/win_system.py @@ -509,15 +509,15 @@ def get_system_info(): def byte_calc(val): val = float(val) if val < 2**10: - return "{:.3f}B".format(val) + return f"{val:.3f}B" elif val < 2**20: - return "{:.3f}KB".format(val / 2**10) + return f"{val / 2**10:.3f}KB" elif val < 2**30: - return "{:.3f}MB".format(val / 2**20) + return f"{val / 2**20:.3f}MB" elif val < 2**40: - return "{:.3f}GB".format(val / 2**30) + return f"{val / 2**30:.3f}GB" else: - return "{:.3f}TB".format(val / 2**40) + return f"{val / 2**40:.3f}TB" # Lookup dicts for Win32_OperatingSystem os_type = {1: "Work Station", 2: "Domain Controller", 3: "Server"} @@ -772,10 +772,10 @@ def join_domain( status = get_domain_workgroup() if "Domain" in status: if status["Domain"] == domain: - return "Already joined to {}".format(domain) + return f"Already joined to {domain}" if username and "\\" not in username and "@" not in username: - username = "{}@{}".format(username, domain) + username = f"{username}@{domain}" if username and password is None: return "Must specify a password if you pass a username" @@ -918,11 +918,11 @@ def unjoin_domain( status = get_domain_workgroup() if "Workgroup" in status: if status["Workgroup"] == workgroup: - return "Already joined to {}".format(workgroup) + return f"Already joined to {workgroup}" if username and "\\" not in username and "@" not in username: if domain: - username = "{}@{}".format(username, domain) + username = f"{username}@{domain}" else: return "Must specify domain if not supplied in username" @@ -1060,7 +1060,7 @@ def get_system_time(): elif hours > 12: hours = hours - 12 meridian = "PM" - return "{:02d}:{:02d}:{:02d} {}".format(hours, now[5], now[6], meridian) + return f"{hours:02d}:{now[5]:02d}:{now[6]:02d} {meridian}" def set_system_time(newtime): @@ -1199,7 +1199,7 @@ def get_system_date(): salt '*' system.get_system_date """ now = win32api.GetLocalTime() - return "{:02d}/{:02d}/{:04d}".format(now[1], now[3], now[0]) + return f"{now[1]:02d}/{now[3]:02d}/{now[0]:04d}" def set_system_date(newdate): diff --git a/salt/modules/win_timezone.py b/salt/modules/win_timezone.py index d95f7338bfe..fde63eb7ff8 100644 --- a/salt/modules/win_timezone.py +++ b/salt/modules/win_timezone.py @@ -294,14 +294,14 @@ def set_zone(timezone): else: # Raise error because it's neither key nor value - raise CommandExecutionError("Invalid timezone passed: {}".format(timezone)) + raise CommandExecutionError(f"Invalid timezone passed: {timezone}") # Set the value cmd = ["tzutil", "/s", win_zone] res = __salt__["cmd.run_all"](cmd, python_shell=False) if res["retcode"]: raise CommandExecutionError( - "tzutil encountered an error setting timezone: {}".format(timezone), + f"tzutil encountered an error setting timezone: {timezone}", info=res, ) return zone_compare(timezone) @@ -336,7 +336,7 @@ def zone_compare(timezone): else: # Raise error because it's neither key nor value - raise CommandExecutionError("Invalid timezone passed: {}".format(timezone)) + raise CommandExecutionError(f"Invalid timezone passed: {timezone}") return get_zone() == mapper.get_unix(check_zone, "Unknown") diff --git a/salt/modules/win_useradd.py b/salt/modules/win_useradd.py index e557ffd8113..a9e9b2629b6 100644 --- a/salt/modules/win_useradd.py +++ b/salt/modules/win_useradd.py @@ -250,7 +250,7 @@ def update( try: dt_obj = salt.utils.dateutils.date_cast(expiration_date) except (ValueError, RuntimeError): - return "Invalid Date/Time Format: {}".format(expiration_date) + return f"Invalid Date/Time Format: {expiration_date}" user_info["acct_expires"] = time.mktime(dt_obj.timetuple()) if expired is not None: if expired: @@ -467,7 +467,7 @@ def addgroup(name, group): if group in user["groups"]: return True - cmd = 'net localgroup "{}" {} /add'.format(group, name) + cmd = f'net localgroup "{group}" {name} /add' ret = __salt__["cmd.run_all"](cmd, python_shell=True) return ret["retcode"] == 0 @@ -502,7 +502,7 @@ def removegroup(name, group): if group not in user["groups"]: return True - cmd = 'net localgroup "{}" {} /delete'.format(group, name) + cmd = f'net localgroup "{group}" {name} /delete' ret = __salt__["cmd.run_all"](cmd, python_shell=True) return ret["retcode"] == 0 @@ -633,14 +633,14 @@ def chgroups(name, groups, append=True): for group in ugrps: group = shlex.quote(group).lstrip("'").rstrip("'") if group not in groups: - cmd = 'net localgroup "{}" {} /delete'.format(group, name) + cmd = f'net localgroup "{group}" {name} /delete' __salt__["cmd.run_all"](cmd, python_shell=True) for group in groups: if group in ugrps: continue group = shlex.quote(group).lstrip("'").rstrip("'") - cmd = 'net localgroup "{}" {} /add'.format(group, name) + cmd = f'net localgroup "{group}" {name} /add' out = __salt__["cmd.run_all"](cmd, python_shell=True) if out["retcode"] != 0: log.error(out["stdout"]) @@ -774,7 +774,7 @@ def _get_userprofile_from_registry(user, sid): """ profile_dir = __utils__["reg.read_value"]( "HKEY_LOCAL_MACHINE", - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{}".format(sid), + f"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{sid}", "ProfileImagePath", )["vdata"] log.debug('user %s with sid=%s profile is located at "%s"', user, sid, profile_dir) @@ -901,12 +901,12 @@ def rename(name, new_name): # Load information for the current name current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") # Look for an existing user with the new name new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") # Rename the user account # Connect to WMI @@ -917,7 +917,7 @@ def rename(name, new_name): try: user = c.Win32_UserAccount(Name=name)[0] except IndexError: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") # Rename the user result = user.Rename(new_name)[0] diff --git a/salt/modules/win_wua.py b/salt/modules/win_wua.py index 9c4a0bc8f2d..c7799d5f6be 100644 --- a/salt/modules/win_wua.py +++ b/salt/modules/win_wua.py @@ -995,7 +995,7 @@ def set_wu_settings( ) = error.args # pylint: enable=unpacking-non-sequence,unbalanced-tuple-unpacking # Consider checking for -2147024891 (0x80070005) Access Denied - ret["Comment"] = "Failed with failure code: {}".format(exc[5]) + ret["Comment"] = f"Failed with failure code: {exc[5]}" ret["Success"] = False else: # msupdate is false, so remove it from the services @@ -1019,7 +1019,7 @@ def set_wu_settings( # -2147024891 (0x80070005) Access Denied # -2145091564 (0x80248014) Service Not Found (shouldn't get # this with the check for _get_msupdate_status above - ret["Comment"] = "Failed with failure code: {}".format(exc[5]) + ret["Comment"] = f"Failed with failure code: {exc[5]}" ret["Success"] = False else: ret["msupdate"] = msupdate diff --git a/salt/modules/win_wusa.py b/salt/modules/win_wusa.py index c4c5f21ea01..db9dfc6a55e 100644 --- a/salt/modules/win_wusa.py +++ b/salt/modules/win_wusa.py @@ -40,7 +40,7 @@ def _pshell_json(cmd, cwd=None): in JSON format and load that into python """ if "convertto-json" not in cmd.lower(): - cmd = "{} | ConvertTo-Json".format(cmd) + cmd = f"{cmd} | ConvertTo-Json" log.debug("PowerShell: %s", cmd) ret = __salt__["cmd.run_all"](cmd, shell="powershell", cwd=cwd) @@ -53,9 +53,7 @@ def _pshell_json(cmd, cwd=None): if "retcode" not in ret or ret["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError( - "Issue executing PowerShell {}".format(cmd), info=ret - ) + raise CommandExecutionError(f"Issue executing PowerShell {cmd}", info=ret) # Sometimes Powershell returns an empty string, which isn't valid JSON if ret["stdout"] == "": @@ -89,7 +87,7 @@ def is_installed(name): """ return ( __salt__["cmd.retcode"]( - cmd="Get-HotFix -Id {}".format(name), + cmd=f"Get-HotFix -Id {name}", shell="powershell", ignore_retcode=True, ) @@ -137,7 +135,7 @@ def install(path, restart=False): # Check the ret_code file_name = os.path.basename(path) errors = { - 2359302: "{} is already installed".format(file_name), + 2359302: f"{file_name} is already installed", 3010: ( "{} correctly installed but server reboot is needed to complete" " installation".format(file_name) @@ -147,7 +145,7 @@ def install(path, restart=False): if ret_code in errors: raise CommandExecutionError(errors[ret_code], ret_code) elif ret_code: - raise CommandExecutionError("Unknown error: {}".format(ret_code)) + raise CommandExecutionError(f"Unknown error: {ret_code}") return True @@ -202,14 +200,14 @@ def uninstall(path, restart=False): # If you pass /quiet and specify /kb, you'll always get retcode 87 if there # is an error. Use the actual file to get a more descriptive error errors = { - -2145116156: "{} does not support uninstall".format(kb), - 2359303: "{} not installed".format(kb), + -2145116156: f"{kb} does not support uninstall", + 2359303: f"{kb} not installed", 87: "Unknown error. Try specifying an .msu file", } if ret_code in errors: raise CommandExecutionError(errors[ret_code], ret_code) elif ret_code: - raise CommandExecutionError("Unknown error: {}".format(ret_code)) + raise CommandExecutionError(f"Unknown error: {ret_code}") return True diff --git a/salt/modules/winrepo.py b/salt/modules/winrepo.py index 227e81ee2e8..d7d39253eb1 100644 --- a/salt/modules/winrepo.py +++ b/salt/modules/winrepo.py @@ -165,15 +165,15 @@ def show_sls(name, saltenv="base"): repo.extend(definition) # Check for the sls file by name - sls_file = "{}.sls".format(os.sep.join(repo)) + sls_file = f"{os.sep.join(repo)}.sls" if not os.path.exists(sls_file): # Maybe it's a directory with an init.sls - sls_file = "{}\\init.sls".format(os.sep.join(repo)) + sls_file = f"{os.sep.join(repo)}\\init.sls" if not os.path.exists(sls_file): # It's neither, return - return "Software definition {} not found".format(name) + return f"Software definition {name} not found" # Load the renderer renderers = salt.loader.render(__opts__, __salt__) @@ -193,7 +193,7 @@ def show_sls(name, saltenv="base"): except SaltRenderError as exc: log.debug("Failed to compile %s.", sls_file) log.debug("Error: %s.", exc) - config["Message"] = "Failed to compile {}".format(sls_file) - config["Error"] = "{}".format(exc) + config["Message"] = f"Failed to compile {sls_file}" + config["Error"] = f"{exc}" return config diff --git a/salt/modules/wordpress.py b/salt/modules/wordpress.py index 792d4f25536..7ce4c6b3cca 100644 --- a/salt/modules/wordpress.py +++ b/salt/modules/wordpress.py @@ -41,7 +41,7 @@ def list_plugins(path, user): salt '*' wordpress.list_plugins /var/www/html apache """ ret = [] - resp = __salt__["cmd.shell"]("wp --path={} plugin list".format(path), runas=user) + resp = __salt__["cmd.shell"](f"wp --path={path} plugin list", runas=user) for line in resp.split("\n")[1:]: ret.append(line.split("\t")) return [plugin.__dict__ for plugin in map(_get_plugins, ret)] @@ -68,7 +68,7 @@ def show_plugin(name, path, user): """ ret = {"name": name} resp = __salt__["cmd.shell"]( - "wp --path={} plugin status {}".format(path, name), runas=user + f"wp --path={path} plugin status {name}", runas=user ).split("\n") for line in resp: if "Status" in line: @@ -101,9 +101,7 @@ def activate(name, path, user): if check["status"] == "active": # already active return None - resp = __salt__["cmd.shell"]( - "wp --path={} plugin activate {}".format(path, name), runas=user - ) + resp = __salt__["cmd.shell"](f"wp --path={path} plugin activate {name}", runas=user) if "Success" in resp: return True elif show_plugin(name, path, user)["status"] == "active": @@ -135,7 +133,7 @@ def deactivate(name, path, user): # already inactive return None resp = __salt__["cmd.shell"]( - "wp --path={} plugin deactivate {}".format(path, name), runas=user + f"wp --path={path} plugin deactivate {name}", runas=user ) if "Success" in resp: return True @@ -160,9 +158,7 @@ def is_installed(path, user=None): salt '*' wordpress.is_installed /var/www/html apache """ - retcode = __salt__["cmd.retcode"]( - "wp --path={} core is-installed".format(path), runas=user - ) + retcode = __salt__["cmd.retcode"](f"wp --path={path} core is-installed", runas=user) if retcode == 0: return True return False diff --git a/salt/modules/x509.py b/salt/modules/x509.py index 57c381ea382..ee1b2e378d2 100644 --- a/salt/modules/x509.py +++ b/salt/modules/x509.py @@ -188,7 +188,7 @@ def _parse_openssl_req(csr_filename): """ if not salt.utils.path.which("openssl"): raise salt.exceptions.SaltInvocationError("openssl binary not found in path") - cmd = "openssl req -text -noout -in {}".format(csr_filename) + cmd = f"openssl req -text -noout -in {csr_filename}" output = __salt__["cmd.run_stdout"](cmd) @@ -231,7 +231,7 @@ def _parse_openssl_crl(crl_filename): """ if not salt.utils.path.which("openssl"): raise salt.exceptions.SaltInvocationError("openssl binary not found in path") - cmd = "openssl crl -text -noout -in {}".format(crl_filename) + cmd = f"openssl crl -text -noout -in {crl_filename}" output = __salt__["cmd.run_stdout"](cmd) @@ -316,7 +316,7 @@ def _dec2hex(decval): """ Converts decimal values to nicely formatted hex strings """ - return _pretty_hex("{:X}".format(decval)) + return _pretty_hex(f"{decval:X}") def _isfile(path): @@ -505,7 +505,7 @@ def get_pem_entry(text, pem_type=None): pem_temp = pem_temp[pem_temp.index("-") :] text = "\n".join(pem_fixed) - errmsg = "PEM text not valid:\n{}".format(text) + errmsg = f"PEM text not valid:\n{text}" if pem_type: errmsg = "PEM does not contain a single entry of type {}:\n{}".format( pem_type, text @@ -824,7 +824,7 @@ def write_pem(text, path, overwrite=True, pem_type=None): _fp.write(salt.utils.stringutils.to_str(text)) if pem_type and pem_type == "CERTIFICATE" and _dhparams: _fp.write(salt.utils.stringutils.to_str(_dhparams)) - return "PEM written to {}".format(path) + return f"PEM written to {path}" def create_private_key( @@ -1130,7 +1130,7 @@ def get_signing_policy(signing_policy_name): """ signing_policy = _get_signing_policy(signing_policy_name) if not signing_policy: - return "Signing policy {} does not exist.".format(signing_policy_name) + return f"Signing policy {signing_policy_name} does not exist." if isinstance(signing_policy, list): dict_ = {} for item in signing_policy: diff --git a/salt/modules/xbpspkg.py b/salt/modules/xbpspkg.py index afcf54fb2f2..65376c7dea1 100644 --- a/salt/modules/xbpspkg.py +++ b/salt/modules/xbpspkg.py @@ -401,7 +401,7 @@ def install(name=None, refresh=False, fromrepo=None, pkgs=None, sources=None, ** if refresh: cmd.append("-S") # update repo db if fromrepo: - cmd.append("--repository={}".format(fromrepo)) + cmd.append(f"--repository={fromrepo}") cmd.append("-y") # assume yes when asked cmd.extend(pkg_params) @@ -578,9 +578,7 @@ def add_repo(repo, conffile="/usr/share/xbps.d/15-saltstack.conf"): if not _locate_repo_files(repo): try: with salt.utils.files.fopen(conffile, "a+") as conf_file: - conf_file.write( - salt.utils.stringutils.to_str("repository={}\n".format(repo)) - ) + conf_file.write(salt.utils.stringutils.to_str(f"repository={repo}\n")) except OSError: return False diff --git a/salt/modules/xfs.py b/salt/modules/xfs.py index b506cd965e7..c47201262d0 100644 --- a/salt/modules/xfs.py +++ b/salt/modules/xfs.py @@ -111,7 +111,7 @@ def info(device): salt '*' xfs.info /dev/sda1 """ - out = __salt__["cmd.run_all"]("xfs_info {}".format(device)) + out = __salt__["cmd.run_all"](f"xfs_info {device}") if out.get("stderr"): raise CommandExecutionError(out["stderr"].replace("xfs_info:", "").strip()) return _parse_xfs_info(out["stdout"]) @@ -186,16 +186,16 @@ def dump(device, destination, level=0, label=None, noerase=None): label and label or time.strftime( - 'XFS dump for "{}" of %Y.%m.%d, %H:%M'.format(device), time.localtime() + f'XFS dump for "{device}" of %Y.%m.%d, %H:%M', time.localtime() ).replace("'", '"') ) cmd = ["xfsdump"] cmd.append("-F") # Force if not noerase: cmd.append("-E") # pre-erase - cmd.append("-L '{}'".format(label)) # Label - cmd.append("-l {}".format(level)) # Dump level - cmd.append("-f {}".format(destination)) # Media destination + cmd.append(f"-L '{label}'") # Label + cmd.append(f"-l {level}") # Dump level + cmd.append(f"-f {destination}") # Media destination cmd.append(device) # Device cmd = " ".join(cmd) @@ -211,10 +211,10 @@ def _xr_to_keyset(line): """ tkns = [elm for elm in line.strip().split(":", 1) if elm] if len(tkns) == 1: - return "'{}': ".format(tkns[0]) + return f"'{tkns[0]}': " else: key, val = tkns - return "'{}': '{}',".format(key.strip(), val.strip()) + return f"'{key.strip()}': '{val.strip()}'," def _xfs_inventory_output(out): @@ -305,14 +305,14 @@ def prune_dump(sessionid): salt '*' xfs.prune_dump b74a3586-e52e-4a4a-8775-c3334fa8ea2c """ - out = __salt__["cmd.run_all"]("xfsinvutil -s {} -F".format(sessionid)) + out = __salt__["cmd.run_all"](f"xfsinvutil -s {sessionid} -F") _verify_run(out) data = _xfs_prune_output(out["stdout"], sessionid) if data: return data - raise CommandExecutionError('Session UUID "{}" was not found.'.format(sessionid)) + raise CommandExecutionError(f'Session UUID "{sessionid}" was not found.') def _blkid_output(out): @@ -390,9 +390,9 @@ def estimate(path): salt '*' xfs.estimate /path/to/dir/* """ if not os.path.exists(path): - raise CommandExecutionError('Path "{}" was not found.'.format(path)) + raise CommandExecutionError(f'Path "{path}" was not found.') - out = __salt__["cmd.run_all"]("xfs_estimate -v {}".format(path)) + out = __salt__["cmd.run_all"](f"xfs_estimate -v {path}") _verify_run(out) return _xfs_estimate_output(out["stdout"]) @@ -452,7 +452,7 @@ def mkfs( cmd = ["mkfs.xfs"] if label: cmd.append("-L") - cmd.append("'{}'".format(label)) + cmd.append(f"'{label}'") if ssize: cmd.append("-s") @@ -473,7 +473,7 @@ def mkfs( cmd.append(opts) except Exception: # pylint: disable=broad-except raise CommandExecutionError( - 'Wrong parameters "{}" for option "{}"'.format(opts, switch) + f'Wrong parameters "{opts}" for option "{switch}"' ) if not noforce: @@ -501,13 +501,13 @@ def modify(device, label=None, lazy_counting=None, uuid=None): """ if not label and lazy_counting is None and uuid is None: raise CommandExecutionError( - 'Nothing specified for modification for "{}" device'.format(device) + f'Nothing specified for modification for "{device}" device' ) cmd = ["xfs_admin"] if label: cmd.append("-L") - cmd.append("'{}'".format(label)) + cmd.append(f"'{label}'") if lazy_counting is False: cmd.append("-c") @@ -527,7 +527,7 @@ def modify(device, label=None, lazy_counting=None, uuid=None): cmd = " ".join(cmd) _verify_run(__salt__["cmd.run_all"](cmd), cmd=cmd) - out = __salt__["cmd.run_all"]("blkid -o export {}".format(device)) + out = __salt__["cmd.run_all"](f"blkid -o export {device}") _verify_run(out) return _blkid_output(out["stdout"]) @@ -568,9 +568,9 @@ def defragment(device): raise CommandExecutionError("Root is not a device.") if not _get_mounts().get(device): - raise CommandExecutionError('Device "{}" is not mounted'.format(device)) + raise CommandExecutionError(f'Device "{device}" is not mounted') - out = __salt__["cmd.run_all"]("xfs_fsr {}".format(device)) + out = __salt__["cmd.run_all"](f"xfs_fsr {device}") _verify_run(out) return {"log": out["stdout"]} diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 4e5cd8416d8..b4ffdc72ce5 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -102,7 +102,7 @@ def _strip_headers(output, *args): def _get_copr_repo(copr): copr = copr.split(":", 1)[1] copr = copr.split("/", 1) - return "copr:copr.fedorainfracloud.org:{}:{}".format(copr[0], copr[1]) + return f"copr:copr.fedorainfracloud.org:{copr[0]}:{copr[1]}" def _get_hold(line, pattern=__HOLD_PATTERN, full=True): @@ -115,14 +115,14 @@ def _get_hold(line, pattern=__HOLD_PATTERN, full=True): """ if full: if _yum() == "dnf": - lock_re = r"({}-\S+)".format(pattern) + lock_re = rf"({pattern}-\S+)" else: - lock_re = r"(\d+:{}-\S+)".format(pattern) + lock_re = rf"(\d+:{pattern}-\S+)" else: if _yum() == "dnf": - lock_re = r"({}-\S+)".format(pattern) + lock_re = rf"({pattern}-\S+)" else: - lock_re = r"\d+:({}-\S+)".format(pattern) + lock_re = rf"\d+:({pattern}-\S+)" match = re.search(lock_re, line) if match: @@ -263,9 +263,7 @@ def _check_versionlock(): """ vl_plugin = _versionlock_pkg() if vl_plugin not in list_pkgs(): - raise SaltInvocationError( - "Cannot proceed, {} is not installed.".format(vl_plugin) - ) + raise SaltInvocationError(f"Cannot proceed, {vl_plugin} is not installed.") def _get_options(**kwargs): @@ -295,26 +293,26 @@ def _get_options(**kwargs): if fromrepo: log.info("Restricting to repo '%s'", fromrepo) - ret.extend(["--disablerepo=*", "--enablerepo={}".format(fromrepo)]) + ret.extend(["--disablerepo=*", f"--enablerepo={fromrepo}"]) else: if disablerepo: targets = ( [disablerepo] if not isinstance(disablerepo, list) else disablerepo ) log.info("Disabling repo(s): %s", ", ".join(targets)) - ret.extend(["--disablerepo={}".format(x) for x in targets]) + ret.extend([f"--disablerepo={x}" for x in targets]) if enablerepo: targets = [enablerepo] if not isinstance(enablerepo, list) else enablerepo log.info("Enabling repo(s): %s", ", ".join(targets)) - ret.extend(["--enablerepo={}".format(x) for x in targets]) + ret.extend([f"--enablerepo={x}" for x in targets]) if disableexcludes: log.info("Disabling excludes for '%s'", disableexcludes) - ret.append("--disableexcludes={}".format(disableexcludes)) + ret.append(f"--disableexcludes={disableexcludes}") if branch: log.info("Adding branch '%s'", branch) - ret.append("--branch={}".format(branch)) + ret.append(f"--branch={branch}") for item in setopt: ret.extend(["--setopt", str(item)]) @@ -327,10 +325,10 @@ def _get_options(**kwargs): value = kwargs[key] if isinstance(value, str): log.info("Found extra option --%s=%s", key, value) - ret.append("--{}={}".format(key, value)) + ret.append(f"--{key}={value}") elif value is True: log.info("Found extra option --%s", key) - ret.append("--{}".format(key)) + ret.append(f"--{key}") if ret: log.info("Adding extra options: %s", ret) @@ -368,15 +366,13 @@ def _get_yum_config(strict_parser=True): break if not fn: - raise CommandExecutionError( - "No suitable yum config file found in: {}".format(paths) - ) + raise CommandExecutionError(f"No suitable yum config file found in: {paths}") cp = configparser.ConfigParser(strict=strict_parser) try: cp.read(fn) except OSError as exc: - raise CommandExecutionError("Unable to read from {}: {}".format(fn, exc)) + raise CommandExecutionError(f"Unable to read from {fn}: {exc}") if cp.has_section("main"): for opt in cp.options("main"): @@ -970,7 +966,7 @@ def list_repo_pkgs(*args, **kwargs): else: for repo in repos: if _yum() == "tdnf": - cmd = ["--quiet", "--enablerepo={}".format(repo), "list"] + cmd = ["--quiet", f"--enablerepo={repo}", "list"] else: cmd = [ "--quiet", @@ -1229,7 +1225,7 @@ def install( update_holds=False, saltenv="base", ignore_epoch=False, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 @@ -1443,7 +1439,7 @@ def install( sources, saltenv=saltenv, normalize=normalize and kwargs.get("split_arch", True), - **kwargs + **kwargs, ) except MinionError as exc: raise CommandExecutionError(exc) @@ -1502,9 +1498,7 @@ def install( cur_patches = list_patches() for advisory_id in pkg_params: if advisory_id not in cur_patches: - raise CommandExecutionError( - 'Advisory id "{}" not found'.format(advisory_id) - ) + raise CommandExecutionError(f'Advisory id "{advisory_id}" not found') else: pkg_params_items.append(advisory_id) else: @@ -1622,7 +1616,7 @@ def install( continue if ignore_epoch is True: - pkgstr = "{}-{}{}".format(pkgname, version_num, arch) + pkgstr = f"{pkgname}-{version_num}{arch}" else: pkgstr = "{}-{}{}".format( pkgname, version_num.split(":", 1)[-1], arch @@ -1746,7 +1740,7 @@ def install( with _temporarily_unhold(to_install, targets): if targets: if pkg_type == "advisory": - targets = ["--advisory={}".format(t) for t in targets] + targets = [f"--advisory={t}" for t in targets] cmd = ["-y"] if _yum() == "dnf": cmd.extend(["--best", "--allowerasing"]) @@ -1823,7 +1817,7 @@ def upgrade( minimal=False, obsoletes=True, diff_attr=None, - **kwargs + **kwargs, ): """ Run a full system upgrade (a ``yum upgrade`` or ``dnf upgrade``), or @@ -2051,7 +2045,7 @@ def update( normalize=True, minimal=False, obsoletes=False, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -2297,7 +2291,7 @@ def hold( if target not in current_locks: if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret[target]["comment"] = "Package {} is set to be held.".format(target) + ret[target]["comment"] = f"Package {target} is set to be held." else: out = _call_yum(["versionlock", target]) if out["retcode"] == 0: @@ -2390,7 +2384,7 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 search_locks = [ x for x in current_locks - if fnmatch.fnmatch(x, "*{}*".format(target)) + if fnmatch.fnmatch(x, f"*{target}*") and target == _get_hold(x, full=False) ] @@ -2410,12 +2404,12 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 ret[target]["changes"]["new"] = "" ret[target]["changes"]["old"] = "hold" else: - ret[target]["comment"] = ( - "Package {} was unable to be unheld.".format(target) - ) + ret[target][ + "comment" + ] = f"Package {target} was unable to be unheld." else: ret[target].update(result=True) - ret[target]["comment"] = "Package {} is not being held.".format(target) + ret[target]["comment"] = f"Package {target} is not being held." return ret @@ -2638,7 +2632,7 @@ def group_info(name, expand=False, ignore_groups=None, **kwargs): ret["group"] = g_info.get("environment group") or g_info.get("group") ret["id"] = g_info.get("environment-id") or g_info.get("group-id") if not ret["group"] and not ret["id"]: - raise CommandExecutionError("Group '{}' not found".format(name)) + raise CommandExecutionError(f"Group '{name}' not found") ret["description"] = g_info.get("description", "") @@ -2864,7 +2858,7 @@ def list_repos(basedir=None, **kwargs): if not os.path.exists(bdir): continue for repofile in os.listdir(bdir): - repopath = "{}/{}".format(bdir, repofile) + repopath = f"{bdir}/{repofile}" if not repofile.endswith(".repo"): continue filerepos = _parse_repo_file(repopath, strict_parser)[1] @@ -2936,7 +2930,7 @@ def del_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613 repos = list_repos(basedirs, **kwargs) if repo not in repos: - return "Error: the {} repo does not exist in {}".format(repo, basedirs) + return f"Error: the {repo} repo does not exist in {basedirs}" # Find out what file the repo lives in repofile = "" @@ -2955,7 +2949,7 @@ def del_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613 # If this is the only repo in the file, delete the file itself if onlyrepo: os.remove(repofile) - return "File {} containing repo {} has been removed".format(repofile, repo) + return f"File {repofile} containing repo {repo} has been removed" # There must be other repos in this file, write the file with them header, filerepos = _parse_repo_file(repofile, strict_parser) @@ -2969,20 +2963,20 @@ def del_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613 filerepos[stanza]["comments"] ) del filerepos[stanza]["comments"] - content += "\n[{}]".format(stanza) + content += f"\n[{stanza}]" for line in filerepos[stanza]: # A whitespace is needed at the beginning of the new line in order # to avoid breaking multiple line values allowed on repo files. value = filerepos[stanza][line] if isinstance(value, str) and "\n" in value: value = "\n ".join(value.split("\n")) - content += "\n{}={}".format(line, value) - content += "\n{}\n".format(comments) + content += f"\n{line}={value}" + content += f"\n{comments}\n" with salt.utils.files.fopen(repofile, "w") as fileout: fileout.write(salt.utils.stringutils.to_str(content)) - return "Repo {} has been removed from {}".format(repo, repofile) + return f"Repo {repo} has been removed from {repofile}" def mod_repo(repo, basedir=None, **kwargs): @@ -3070,7 +3064,7 @@ def mod_repo(repo, basedir=None, **kwargs): "The repo does not exist and needs to be created, but none " "of the following basedir directories exist: {}".format(basedirs) ) - repofile = "{}/{}.repo".format(newdir, repo) + repofile = f"{newdir}/{repo}.repo" if use_copr: # Is copr plugin installed? copr_plugin_name = "" @@ -3081,7 +3075,7 @@ def mod_repo(repo, basedir=None, **kwargs): if not __salt__["pkg_resource.version"](copr_plugin_name): raise SaltInvocationError( - "{} must be installed to use COPR".format(copr_plugin_name) + f"{copr_plugin_name} must be installed to use COPR" ) # Enable COPR @@ -3098,7 +3092,7 @@ def mod_repo(repo, basedir=None, **kwargs): repofile = repos[repo]["file"] header, filerepos = _parse_repo_file(repofile, strict_parser) else: - repofile = "{}/{}.repo".format(newdir, repo) + repofile = f"{newdir}/{repo}.repo" if "name" not in repo_opts: raise SaltInvocationError( @@ -3144,7 +3138,7 @@ def mod_repo(repo, basedir=None, **kwargs): comments = salt.utils.pkg.rpm.combine_comments( filerepos[stanza].pop("comments", []) ) - content += "[{}]\n".format(stanza) + content += f"[{stanza}]\n" for line in filerepos[stanza].keys(): # A whitespace is needed at the beginning of the new line in order # to avoid breaking multiple line values allowed on repo files. @@ -3365,11 +3359,7 @@ def download(*packages, **kwargs): to_purge = [] for pkg in packages: to_purge.extend( - [ - os.path.join(CACHE_DIR, x) - for x in cached_pkgs - if x.startswith("{}-".format(pkg)) - ] + [os.path.join(CACHE_DIR, x) for x in cached_pkgs if x.startswith(f"{pkg}-")] ) for purge_target in set(to_purge): log.debug("Removing cached package %s", purge_target) @@ -3378,7 +3368,7 @@ def download(*packages, **kwargs): except OSError as exc: log.error("Unable to remove %s: %s", purge_target, exc) - cmd = ["yumdownloader", "-q", "--destdir={}".format(CACHE_DIR)] + cmd = ["yumdownloader", "-q", f"--destdir={CACHE_DIR}"] cmd.extend(packages) __salt__["cmd.run"](cmd, output_loglevel="trace", python_shell=False) ret = {} @@ -3388,7 +3378,7 @@ def download(*packages, **kwargs): pkg_name = None pkg_file = None for query_pkg in packages: - if dld_result.startswith("{}-".format(query_pkg)): + if dld_result.startswith(f"{query_pkg}-"): pkg_name = query_pkg pkg_file = dld_result break diff --git a/salt/modules/zabbix.py b/salt/modules/zabbix.py index f09ca1df3ba..4c834e09905 100644 --- a/salt/modules/zabbix.py +++ b/salt/modules/zabbix.py @@ -189,11 +189,9 @@ def _query(method, params, url, auth=None): ) return ret except ValueError as err: - raise SaltException( - "URL or HTTP headers are probably not correct! ({})".format(err) - ) + raise SaltException(f"URL or HTTP headers are probably not correct! ({err})") except OSError as err: - raise SaltException("Check hostname in URL! ({})".format(err)) + raise SaltException(f"Check hostname in URL! ({err})") def _login(**kwargs): @@ -232,9 +230,9 @@ def _login(**kwargs): name = name[len(prefix) :] except IndexError: return - val = __salt__["config.get"]("zabbix.{}".format(name), None) or __salt__[ + val = __salt__["config.get"](f"zabbix.{name}", None) or __salt__[ "config.get" - ]("zabbix:{}".format(name), None) + ](f"zabbix:{name}", None) if val is not None: connargs[key] = val @@ -258,7 +256,7 @@ def _login(**kwargs): else: raise KeyError except KeyError as err: - raise SaltException("URL is probably not correct! ({})".format(err)) + raise SaltException(f"URL is probably not correct! ({err})") def _params_extend(params, _ignore_name=False, **kwargs): @@ -2143,7 +2141,7 @@ def usermacro_get( hostmacroids=None, globalmacroids=None, globalmacro=False, - **connection_args + **connection_args, ): """ Retrieve user macros according to the given parameters. diff --git a/salt/modules/zcbuildout.py b/salt/modules/zcbuildout.py index e4a8b36e403..6a908b0c258 100644 --- a/salt/modules/zcbuildout.py +++ b/salt/modules/zcbuildout.py @@ -208,7 +208,7 @@ def _set_status(m, comment=INVALID_RESPONSE, status=False, out=None): if out and isinstance(out, str): outlog += HR outlog += "OUTPUT:\n" - outlog += "{}\n".format(salt.utils.stringutils.to_unicode(out)) + outlog += f"{salt.utils.stringutils.to_unicode(out)}\n" outlog += HR if m["logs"]: outlog += HR @@ -224,7 +224,7 @@ def _set_status(m, comment=INVALID_RESPONSE, status=False, out=None): for logger in "error", "warn", "info", "debug": logs = m["logs_by_level"].get(logger, []) if logs: - outlog_by_level += "\n{}:\n".format(logger.upper()) + outlog_by_level += f"\n{logger.upper()}:\n" for idx, log in enumerate(logs[:]): logs[idx] = salt.utils.stringutils.to_unicode(log) outlog_by_level += "\n".join(logs) @@ -517,7 +517,7 @@ def upgrade_bootstrap( os.makedirs(dbuild) # only try to download once per buildout checkout with salt.utils.files.fopen( - os.path.join(dbuild, "{}.updated_bootstrap".format(buildout_ver)) + os.path.join(dbuild, f"{buildout_ver}.updated_bootstrap") ): pass except OSError: @@ -536,7 +536,7 @@ def upgrade_bootstrap( fic.write(salt.utils.stringutils.to_str(data)) if dled: with salt.utils.files.fopen( - os.path.join(dbuild, "{}.updated_bootstrap".format(buildout_ver)), "w" + os.path.join(dbuild, f"{buildout_ver}.updated_bootstrap"), "w" ) as afic: afic.write("foo") except OSError: @@ -689,7 +689,7 @@ def bootstrap( if (test_release is not False) and " --accept-buildout-test-releases" in content: bootstrap_args += " --accept-buildout-test-releases" if config and '"-c"' in content: - bootstrap_args += " -c {}".format(config) + bootstrap_args += f" -c {config}" # be sure that the bootstrap belongs to the running user try: if runas: @@ -703,7 +703,7 @@ def bootstrap( exc, exc_info=_logger.isEnabledFor(logging.DEBUG), ) - cmd = "{} bootstrap.py {}".format(python, bootstrap_args) + cmd = f"{python} bootstrap.py {bootstrap_args}" ret = _Popen( cmd, directory=directory, runas=runas, loglevel=loglevel, env=env, use_vt=use_vt ) @@ -844,7 +844,7 @@ def _merge_statuses(statuses): status["out"] += "\n" status["out"] += HR out = salt.utils.stringutils.to_unicode(out) - status["out"] += "{}\n".format(out) + status["out"] += f"{out}\n" status["out"] += HR if comment: if not status["comment"]: @@ -856,12 +856,12 @@ def _merge_statuses(statuses): if not status["outlog"]: status["outlog"] = "" outlog = salt.utils.stringutils.to_unicode(outlog) - status["outlog"] += "\n{}".format(HR) + status["outlog"] += f"\n{HR}" status["outlog"] += outlog if outlog_by_level: if not status["outlog_by_level"]: status["outlog_by_level"] = "" - status["outlog_by_level"] += "\n{}".format(HR) + status["outlog_by_level"] += f"\n{HR}" status["outlog_by_level"] += salt.utils.stringutils.to_unicode( outlog_by_level ) diff --git a/salt/modules/zenoss.py b/salt/modules/zenoss.py index 5f2408c486b..50855f2bebb 100644 --- a/salt/modules/zenoss.py +++ b/salt/modules/zenoss.py @@ -203,7 +203,7 @@ def set_prod_state(prod_state, device=None): device_object = find_device(device) if not device_object: - return "Unable to find a device in Zenoss for {}".format(device) + return f"Unable to find a device in Zenoss for {device}" log.info("Setting prodState to %d on %s device", prod_state, device) data = dict( diff --git a/salt/modules/zoneadm.py b/salt/modules/zoneadm.py index 0bb4a60e26e..515f9663049 100644 --- a/salt/modules/zoneadm.py +++ b/salt/modules/zoneadm.py @@ -64,7 +64,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded in a solaris globalzone.".format(__virtualname__), + f"{__virtualname__} module can only be loaded in a solaris globalzone.", ) @@ -145,18 +145,18 @@ def boot(zone, single=False, altinit=None, smf_options=None): ## build boot_options boot_options = "" if single: - boot_options = "-s {}".format(boot_options) + boot_options = f"-s {boot_options}" if altinit: # note: we cannot validate the path, as this is local to the zonepath. - boot_options = "-i {} {}".format(altinit, boot_options) + boot_options = f"-i {altinit} {boot_options}" if smf_options: - boot_options = "-m {} {}".format(smf_options, boot_options) + boot_options = f"-m {smf_options} {boot_options}" if boot_options != "": - boot_options = " -- {}".format(boot_options.strip()) + boot_options = f" -- {boot_options.strip()}" ## execute boot res = __salt__["cmd.run_all"]( "zoneadm {zone} boot{boot_opts}".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", boot_opts=boot_options, ) ) @@ -195,18 +195,18 @@ def reboot(zone, single=False, altinit=None, smf_options=None): ## build boot_options boot_options = "" if single: - boot_options = "-s {}".format(boot_options) + boot_options = f"-s {boot_options}" if altinit: # note: we cannot validate the path, as this is local to the zonepath. - boot_options = "-i {} {}".format(altinit, boot_options) + boot_options = f"-i {altinit} {boot_options}" if smf_options: - boot_options = "-m {} {}".format(smf_options, boot_options) + boot_options = f"-m {smf_options} {boot_options}" if boot_options != "": - boot_options = " -- {}".format(boot_options.strip()) + boot_options = f" -- {boot_options.strip()}" ## execute reboot res = __salt__["cmd.run_all"]( "zoneadm {zone} reboot{boot_opts}".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", boot_opts=boot_options, ) ) @@ -240,7 +240,7 @@ def halt(zone): ## halt zone res = __salt__["cmd.run_all"]( "zoneadm {zone} halt".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", ) ) ret["status"] = res["retcode"] == 0 @@ -280,18 +280,18 @@ def shutdown(zone, reboot=False, single=False, altinit=None, smf_options=None): ## build boot_options boot_options = "" if single: - boot_options = "-s {}".format(boot_options) + boot_options = f"-s {boot_options}" if altinit: # note: we cannot validate the path, as this is local to the zonepath. - boot_options = "-i {} {}".format(altinit, boot_options) + boot_options = f"-i {altinit} {boot_options}" if smf_options: - boot_options = "-m {} {}".format(smf_options, boot_options) + boot_options = f"-m {smf_options} {boot_options}" if boot_options != "": - boot_options = " -- {}".format(boot_options.strip()) + boot_options = f" -- {boot_options.strip()}" ## shutdown zone res = __salt__["cmd.run_all"]( "zoneadm {zone} shutdown{reboot}{boot_opts}".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", reboot=" -r" if reboot else "", boot_opts=boot_options, ) @@ -323,7 +323,7 @@ def detach(zone): ## detach zone res = __salt__["cmd.run_all"]( "zoneadm {zone} detach".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", ) ) ret["status"] = res["retcode"] == 0 @@ -360,7 +360,7 @@ def attach(zone, force=False, brand_opts=None): "zoneadm -z {zone} attach{force}{brand_opts}".format( zone=zone, force=" -F" if force else "", - brand_opts=" {}".format(brand_opts) if brand_opts else "", + brand_opts=f" {brand_opts}" if brand_opts else "", ) ) ret["status"] = res["retcode"] == 0 @@ -390,7 +390,7 @@ def ready(zone): ## ready zone res = __salt__["cmd.run_all"]( "zoneadm {zone} ready".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", ) ) ret["status"] = res["retcode"] == 0 @@ -453,7 +453,7 @@ def move(zone, zonepath): ## verify zone res = __salt__["cmd.run_all"]( "zoneadm {zone} move {path}".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", path=zonepath, ) ) @@ -487,7 +487,7 @@ def uninstall(zone): ## uninstall zone res = __salt__["cmd.run_all"]( "zoneadm {zone} uninstall -F".format( - zone="-u {}".format(zone) if _is_uuid(zone) else "-z {}".format(zone), + zone=f"-u {zone}" if _is_uuid(zone) else f"-z {zone}", ) ) ret["status"] = res["retcode"] == 0 @@ -524,7 +524,7 @@ def install(zone, nodataset=False, brand_opts=None): "zoneadm -z {zone} install{nodataset}{brand_opts}".format( zone=zone, nodataset=" -x nodataset" if nodataset else "", - brand_opts=" {}".format(brand_opts) if brand_opts else "", + brand_opts=f" {brand_opts}" if brand_opts else "", ) ) ret["status"] = res["retcode"] == 0 @@ -560,7 +560,7 @@ def clone(zone, source, snapshot=None): "zoneadm -z {zone} clone {snapshot}{source}".format( zone=zone, source=source, - snapshot="-s {} ".format(snapshot) if snapshot else "", + snapshot=f"-s {snapshot} " if snapshot else "", ) ) ret["status"] = res["retcode"] == 0 diff --git a/salt/modules/zonecfg.py b/salt/modules/zonecfg.py index a9040804797..57ae570b6b3 100644 --- a/salt/modules/zonecfg.py +++ b/salt/modules/zonecfg.py @@ -110,7 +110,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded in a solaris globalzone.".format(__virtualname__), + f"{__virtualname__} module can only be loaded in a solaris globalzone.", ) @@ -195,7 +195,7 @@ def _sanitize_value(value): return "".join(str(v) for v in new_value).replace(",)", ")") else: # note: we can't use shelx or pipes quote here because it makes zonecfg barf - return '"{}"'.format(value) if " " in value else value + return f'"{value}"' if " " in value else value def _dump_cfg(cfg_file): @@ -233,13 +233,13 @@ def create(zone, brand, zonepath, force=False): cfg_file = salt.utils.files.mkstemp() with salt.utils.files.fpopen(cfg_file, "w+", mode=0o600) as fp_: fp_.write("create -b -F\n" if force else "create -b\n") - fp_.write("set brand={}\n".format(_sanitize_value(brand))) - fp_.write("set zonepath={}\n".format(_sanitize_value(zonepath))) + fp_.write(f"set brand={_sanitize_value(brand)}\n") + fp_.write(f"set zonepath={_sanitize_value(zonepath)}\n") # create if not __salt__["file.directory_exists"](zonepath): __salt__["file.makedirs_perms"]( - zonepath if zonepath[-1] == "/" else "{}/".format(zonepath), mode="0700" + zonepath if zonepath[-1] == "/" else f"{zonepath}/", mode="0700" ) _dump_cfg(cfg_file) @@ -354,7 +354,7 @@ def export(zone, path=None): res = __salt__["cmd.run_all"]( "zonecfg -z {zone} export{path}".format( zone=zone, - path=" -f {}".format(path) if path else "", + path=f" -f {path}" if path else "", ) ) ret["status"] = res["retcode"] == 0 @@ -422,7 +422,7 @@ def _property(methode, zone, key, value): cfg_file = None if methode not in ["set", "clear"]: ret["status"] = False - ret["message"] = "unkown methode {}!".format(methode) + ret["message"] = f"unkown methode {methode}!" else: cfg_file = salt.utils.files.mkstemp() with salt.utils.files.fpopen(cfg_file, "w+", mode=0o600) as fp_: @@ -430,9 +430,9 @@ def _property(methode, zone, key, value): if isinstance(value, dict) or isinstance(value, list): value = _sanitize_value(value) value = str(value).lower() if isinstance(value, bool) else str(value) - fp_.write("{} {}={}\n".format(methode, key, _sanitize_value(value))) + fp_.write(f"{methode} {key}={_sanitize_value(value)}\n") elif methode == "clear": - fp_.write("{} {}\n".format(methode, key)) + fp_.write(f"{methode} {key}\n") # update property if cfg_file: @@ -530,7 +530,7 @@ def _resource(methode, zone, resource_type, resource_selector, **kwargs): kwargs[k] = _sanitize_value(kwargs[k]) if methode not in ["add", "update"]: ret["status"] = False - ret["message"] = "unknown methode {}".format(methode) + ret["message"] = f"unknown methode {methode}" return ret if methode in ["update"] and resource_selector and resource_selector not in kwargs: ret["status"] = False @@ -543,7 +543,7 @@ def _resource(methode, zone, resource_type, resource_selector, **kwargs): cfg_file = salt.utils.files.mkstemp() with salt.utils.files.fpopen(cfg_file, "w+", mode=0o600) as fp_: if methode in ["add"]: - fp_.write("add {}\n".format(resource_type)) + fp_.write(f"add {resource_type}\n") elif methode in ["update"]: if resource_selector: value = kwargs[resource_selector] @@ -556,7 +556,7 @@ def _resource(methode, zone, resource_type, resource_selector, **kwargs): ) ) else: - fp_.write("select {}\n".format(resource_type)) + fp_.write(f"select {resource_type}\n") for k, v in kwargs.items(): if methode in ["update"] and k == resource_selector: continue @@ -564,9 +564,9 @@ def _resource(methode, zone, resource_type, resource_selector, **kwargs): value = _sanitize_value(value) value = str(v).lower() if isinstance(v, bool) else str(v) if k in _zonecfg_resource_setters[resource_type]: - fp_.write("set {}={}\n".format(k, _sanitize_value(value))) + fp_.write(f"set {k}={_sanitize_value(value)}\n") else: - fp_.write("add {} {}\n".format(k, _sanitize_value(value))) + fp_.write(f"add {k} {_sanitize_value(value)}\n") fp_.write("end\n") # update property @@ -671,7 +671,7 @@ def remove_resource(zone, resource_type, resource_key, resource_value): ) ) else: - fp_.write("remove {}\n".format(resource_type)) + fp_.write(f"remove {resource_type}\n") # update property if cfg_file: diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py index 5d3404a4ab1..f37de2d2455 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -44,8 +44,8 @@ log = logging.getLogger(__name__) HAS_ZYPP = False ZYPP_HOME = "/etc/zypp" -LOCKS = "{}/locks".format(ZYPP_HOME) -REPOS = "{}/repos.d".format(ZYPP_HOME) +LOCKS = f"{ZYPP_HOME}/locks" +REPOS = f"{ZYPP_HOME}/repos.d" DEFAULT_PRIORITY = 99 PKG_ARCH_SEPARATOR = "." @@ -371,9 +371,7 @@ class _Zypper: self.TAG_RELEASED, ) if self.error_msg and not self.__no_raise and not self.__ignore_repo_failure: - raise CommandExecutionError( - "Zypper command failure: {}".format(self.error_msg) - ) + raise CommandExecutionError(f"Zypper command failure: {self.error_msg}") return ( self._is_xml_mode() @@ -482,9 +480,7 @@ class Wildcard: "se", "-xv", self.name ).getElementsByTagName("solvable") if not solvables: - raise CommandExecutionError( - "No packages found matching '{}'".format(self.name) - ) + raise CommandExecutionError(f"No packages found matching '{self.name}'") return sorted( { @@ -519,7 +515,7 @@ class Wildcard: self._op = version.replace(exact_version, "") or None if self._op and self._op not in self.Z_OP: raise CommandExecutionError( - 'Zypper do not supports operator "{}".'.format(self._op) + f'Zypper do not supports operator "{self._op}".' ) self.version = exact_version @@ -920,7 +916,7 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs): # Results can be different if a different root or a different # inclusion types are passed - contextkey = "pkg.list_pkgs_{}_{}".format(root, includes) + contextkey = f"pkg.list_pkgs_{root}_{includes}" if contextkey in __context__ and kwargs.get("use_context", True): return _list_pkgs_from_context(versions_as_list, contextkey, attr) @@ -988,7 +984,7 @@ def list_pkgs(versions_as_list=False, root=None, includes=None, **kwargs): else: elements = [] for element in elements: - extended_name = "{}:{}".format(include, element) + extended_name = f"{include}:{element}" info = info_available(extended_name, refresh=False, root=root) _ret[extended_name] = [ { @@ -1229,7 +1225,7 @@ def del_repo(repo, root=None): "message": msg[0].childNodes[0].nodeValue, } - raise CommandExecutionError("Repository '{}' not found.".format(repo)) + raise CommandExecutionError(f"Repository '{repo}' not found.") def mod_repo(repo, **kwargs): @@ -1316,7 +1312,7 @@ def mod_repo(repo, **kwargs): if new_url == base_url: raise CommandExecutionError( - "Repository '{}' already exists as '{}'.".format(repo, alias) + f"Repository '{repo}' already exists as '{alias}'." ) # Add new repo @@ -1472,7 +1468,7 @@ def install( ignore_repo_failure=False, no_recommends=False, root=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 @@ -1639,7 +1635,7 @@ def install( prefix, verstr = salt.utils.pkg.split_comparison(version_num) if not prefix: prefix = "=" - target = "{}{}{}".format(param, prefix, verstr) + target = f"{param}{prefix}{verstr}" log.debug("targeting package: %s", target) targets.append(target) elif pkg_type == "advisory": @@ -1647,9 +1643,7 @@ def install( cur_patches = list_patches(root=root) for advisory_id in pkg_params: if advisory_id not in cur_patches: - raise CommandExecutionError( - 'Advisory id "{}" not found'.format(advisory_id) - ) + raise CommandExecutionError(f'Advisory id "{advisory_id}" not found') else: # If we add here the `patch:` prefix, the # `_find_types` helper will take the patches into the @@ -1702,7 +1696,7 @@ def install( # if the name of the package is already prefixed with 'patch:' we # can avoid listing them in the `advisory_ids` field. if pkg_type == "advisory": - targets = ["patch:{}".format(t) for t in targets] + targets = [f"patch:{t}" for t in targets] # Split the targets into batches of 500 packages each, so that # the maximal length of the command line is not broken @@ -1766,7 +1760,7 @@ def upgrade( no_recommends=False, root=None, diff_attr=None, - **kwargs + **kwargs, ): # pylint: disable=unused-argument """ .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 @@ -2185,7 +2179,7 @@ def list_holds(pattern=None, full=True, root=None, **kwargs): ) ) - ptrn_re = re.compile(r"{}-\S+".format(pattern)) if pattern else None + ptrn_re = re.compile(rf"{pattern}-\S+") if pattern else None for pkg_name, pkg_editions in inst_pkgs.items(): for pkg_info in pkg_editions: pkg_ret = ( @@ -2327,14 +2321,12 @@ def unhold(name=None, pkgs=None, root=None, **kwargs): ) ) else: - removed.append( - target if not lock_ver else "{}={}".format(target, lock_ver) - ) + removed.append(target if not lock_ver else f"{target}={lock_ver}") ret[target]["changes"]["new"] = "" ret[target]["changes"]["old"] = "hold" - ret[target]["comment"] = "Package {} is no longer held.".format(target) + ret[target]["comment"] = f"Package {target} is no longer held." else: - ret[target]["comment"] = "Package {} was already unheld.".format(target) + ret[target]["comment"] = f"Package {target} was already unheld." if removed: __zypper__(root=root).call("rl", *removed) @@ -2386,10 +2378,10 @@ def hold(name=None, pkgs=None, root=None, **kwargs): (target, version) = next(iter(target.items())) ret[target] = {"name": target, "changes": {}, "result": True, "comment": ""} if not locks.get(target): - added.append(target if not version else "{}={}".format(target, version)) + added.append(target if not version else f"{target}={version}") ret[target]["changes"]["new"] = "hold" ret[target]["changes"]["old"] = "" - ret[target]["comment"] = "Package {} is now being held.".format(target) + ret[target]["comment"] = f"Package {target} is now being held." else: ret[target]["comment"] = "Package {} is already set to be held.".format( target @@ -2739,7 +2731,7 @@ def search(criteria, refresh=False, **kwargs): .getElementsByTagName("solvable") ) if not solvables: - raise CommandExecutionError("No packages found matching '{}'".format(criteria)) + raise CommandExecutionError(f"No packages found matching '{criteria}'") out = {} for solvable in solvables: diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py index c0275c127fe..583a6f158d5 100644 --- a/salt/netapi/__init__.py +++ b/salt/netapi/__init__.py @@ -53,7 +53,7 @@ def sum_permissions(token, eauth): eauth_groups = {i.rstrip("%") for i in eauth.keys() if i.endswith("%")} for group in user_groups & eauth_groups: - perms.extend(eauth["{}%".format(group)]) + perms.extend(eauth[f"{group}%"]) return perms diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index 52334728242..4083e8d231b 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -899,7 +899,7 @@ def hypermedia_handler(*args, **kwargs): ret = { "status": cherrypy.response.status, "return": ( - "{}".format(traceback.format_exc()) + f"{traceback.format_exc()}" if cherrypy.config["debug"] else "An unexpected error occurred" ), @@ -1946,7 +1946,7 @@ class Logout(LowDataAdapter): _cp_config = dict( LowDataAdapter._cp_config, - **{"tools.salt_auth.on": True, "tools.lowdata_fmt.on": False} + **{"tools.salt_auth.on": True, "tools.lowdata_fmt.on": False}, ) def POST(self): # pylint: disable=arguments-differ @@ -2189,7 +2189,7 @@ class Events: "tools.salt_auth.on": False, "tools.hypermedia_in.on": False, "tools.hypermedia_out.on": False, - } + }, ) def __init__(self): @@ -2394,7 +2394,7 @@ class Events: data = next(stream) yield "tag: {}\n".format(data.get("tag", "")) - yield "data: {}\n\n".format(salt.utils.json.dumps(data)) + yield f"data: {salt.utils.json.dumps(data)}\n\n" return listen() @@ -2424,7 +2424,7 @@ class WebsocketEndpoint: "tools.hypermedia_out.on": False, "tools.websocket.on": True, "tools.websocket.handler_cls": websockets.SynchronizingWebsocket, - } + }, ) def __init__(self): @@ -2578,7 +2578,7 @@ class WebsocketEndpoint: SaltInfo.process(data, salt_token, self.opts) else: handler.send( - "data: {}\n\n".format(salt.utils.json.dumps(data)), + f"data: {salt.utils.json.dumps(data)}\n\n", False, ) except UnicodeDecodeError: @@ -2650,7 +2650,7 @@ class Webhook: "tools.lowdata_fmt.on": True, # Auth can be overridden in __init__(). "tools.salt_auth.on": True, - } + }, ) def __init__(self): diff --git a/salt/netapi/rest_tornado/__init__.py b/salt/netapi/rest_tornado/__init__.py index 9ab2569c822..0d8fa5fa683 100644 --- a/salt/netapi/rest_tornado/__init__.py +++ b/salt/netapi/rest_tornado/__init__.py @@ -64,8 +64,8 @@ def get_application(opts): getattr(hashlib, opts.get("hash_type", DEFAULT_HASH_TYPE))().hexdigest() ) ) - all_events_pattern = r"/all_events/{}".format(token_pattern) - formatted_events_pattern = r"/formatted_events/{}".format(token_pattern) + all_events_pattern = rf"/all_events/{token_pattern}" + formatted_events_pattern = rf"/formatted_events/{token_pattern}" log.debug("All events URL pattern is %s", all_events_pattern) paths += [ # Matches /all_events/[0-9A-Fa-f]{n} diff --git a/salt/netapi/rest_tornado/saltnado.py b/salt/netapi/rest_tornado/saltnado.py index a0697bbc3fc..83d5226a039 100644 --- a/salt/netapi/rest_tornado/saltnado.py +++ b/salt/netapi/rest_tornado/saltnado.py @@ -944,7 +944,7 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223 ret.append("Failed to authenticate") break except Exception as ex: # pylint: disable=broad-except - ret.append("Unexpected exception while handling request: {}".format(ex)) + ret.append(f"Unexpected exception while handling request: {ex}") log.error("Unexpected exception while handling request:", exc_info=True) try: @@ -1611,7 +1611,7 @@ class EventsSaltAPIHandler(SaltAPIHandler): # pylint: disable=W0223 self.set_header("Cache-Control", "no-cache") self.set_header("Connection", "keep-alive") - self.write("retry: {}\n".format(400)) + self.write(f"retry: {400}\n") self.flush() while True: @@ -1622,7 +1622,7 @@ class EventsSaltAPIHandler(SaltAPIHandler): # pylint: disable=W0223 event = yield self.application.event_listener.get_event(self) self.write("tag: {}\n".format(event.get("tag", ""))) - self.write("data: {}\n\n".format(_json_dumps(event))) + self.write(f"data: {_json_dumps(event)}\n\n") self.flush() except TimeoutException: break diff --git a/salt/netapi/rest_wsgi.py b/salt/netapi/rest_wsgi.py index 4afd3d55ec3..50dfabe23c1 100644 --- a/salt/netapi/rest_wsgi.py +++ b/salt/netapi/rest_wsgi.py @@ -161,7 +161,7 @@ class HTTPError(Exception): def __init__(self, code, message): self.code = code - Exception.__init__(self, "{}: {}".format(code, message)) + Exception.__init__(self, f"{code}: {message}") def mkdir_p(path): diff --git a/salt/output/__init__.py b/salt/output/__init__.py index a8c318579df..c90932fa8ea 100644 --- a/salt/output/__init__.py +++ b/salt/output/__init__.py @@ -53,7 +53,7 @@ def get_progress(opts, out, progress): Get the progress bar from the given outputter """ return salt.loader.raw_mod(opts, out, "rawmodule", mod="output")[ - "{}.progress_iter".format(out) + f"{out}.progress_iter" ](progress) diff --git a/salt/output/highstate.py b/salt/output/highstate.py index 76ebac0d6d0..dc00885753f 100644 --- a/salt/output/highstate.py +++ b/salt/output/highstate.py @@ -571,10 +571,10 @@ def _format_host(host, data, indent_level=1): if "data" in ret: if isinstance(ret["data"], list): for item in ret["data"]: - comment = "{} {}".format(comment, item) + comment = f"{comment} {item}" elif isinstance(ret["data"], dict): for key, value in ret["data"].items(): - comment = "{}\n\t\t{}: {}".format(comment, key, value) + comment = f"{comment}\n\t\t{key}: {value}" else: comment = "{} {}".format(comment, ret["data"]) for detail in ["start_time", "duration"]: @@ -634,13 +634,13 @@ def _format_host(host, data, indent_level=1): changestats.append( colorfmt.format( colors["LIGHT_YELLOW"], - "unchanged={}".format(rcounts.get(None, 0)), + f"unchanged={rcounts.get(None, 0)}", colors, ) ) if nchanges > 0: changestats.append( - colorfmt.format(colors["GREEN"], "changed={}".format(nchanges), colors) + colorfmt.format(colors["GREEN"], f"changed={nchanges}", colors) ) if changestats: changestats = " ({})".format(", ".join(changestats)) @@ -732,7 +732,7 @@ def _format_host(host, data, indent_level=1): sum_duration /= 1000 duration_unit = "s" total_duration = "Total run time: {} {}".format( - "{:.3f}".format(sum_duration).rjust(line_max_len - 5), duration_unit + f"{sum_duration:.3f}".rjust(line_max_len - 5), duration_unit ) hstrs.append(colorfmt.format(colors["CYAN"], total_duration, colors)) @@ -762,7 +762,7 @@ def _format_changes(changes, orchestration=False): return True, _nested_changes(changes) if not isinstance(changes, dict): - return True, "Invalid Changes data: {}".format(changes) + return True, f"Invalid Changes data: {changes}" ret = changes.get("ret") if ret is not None and changes.get("out") == "highstate": diff --git a/salt/output/key.py b/salt/output/key.py index 13ee6f0f5fe..f89f95c7f96 100644 --- a/salt/output/key.py +++ b/salt/output/key.py @@ -84,7 +84,7 @@ def output(data, **kwargs): # pylint: disable=unused-argument ret = "" for status in sorted(data): - ret += "{}\n".format(trans[status]) + ret += f"{trans[status]}\n" for key in sorted(data[status]): key = salt.utils.data.decode(key) skey = salt.output.strip_esc_sequence(key) if strip_colors else key diff --git a/salt/output/profile.py b/salt/output/profile.py index d182da565ff..8f54c7017f4 100644 --- a/salt/output/profile.py +++ b/salt/output/profile.py @@ -56,11 +56,11 @@ def _find_durations(data, name_max=60): if len(name) > name_max: name = name[0 : name_max - 3] + "..." - l = len("{:0.4f}".format(dur)) + l = len(f"{dur:0.4f}") if l > ml: ml = l - ret.append([dur, name, "{}.{}".format(mod, fun)]) + ret.append([dur, name, f"{mod}.{fun}"]) for row in ret: row[0] = "{0:{w}.4f}".format(row[0], w=ml) diff --git a/salt/output/table_out.py b/salt/output/table_out.py index 8bc94eb3e46..6b17c901b64 100644 --- a/salt/output/table_out.py +++ b/salt/output/table_out.py @@ -346,7 +346,7 @@ def output(ret, **kwargs): ) for argk in argks: - argv = kwargs.get(argk) or __opts__.get("out.table.{key}".format(key=argk)) + argv = kwargs.get(argk) or __opts__.get(f"out.table.{argk}") if argv is not None: class_kvargs[argk] = argv diff --git a/salt/output/txt.py b/salt/output/txt.py index 71d694a2333..f5e652cdd14 100644 --- a/salt/output/txt.py +++ b/salt/output/txt.py @@ -26,14 +26,14 @@ def output(data, **kwargs): # pylint: disable=unused-argument # Don't blow up on non-strings try: for line in value.splitlines(): - ret += "{}: {}\n".format(key, line) + ret += f"{key}: {line}\n" except AttributeError: - ret += "{}: {}\n".format(key, value) + ret += f"{key}: {value}\n" else: try: ret += data + "\n" except TypeError: # For non-dictionary, non-string data, just use print - ret += "{}\n".format(pprint.pformat(data)) + ret += f"{pprint.pformat(data)}\n" return ret diff --git a/salt/output/virt_query.py b/salt/output/virt_query.py index d20e6357e60..935b9d213d7 100644 --- a/salt/output/virt_query.py +++ b/salt/output/virt_query.py @@ -13,9 +13,9 @@ def output(data, **kwargs): # pylint: disable=unused-argument """ out = "" for id_ in data["data"]: - out += "{}\n".format(id_) + out += f"{id_}\n" for vm_ in data["data"][id_]["vm_info"]: - out += " {}\n".format(vm_) + out += f" {vm_}\n" vm_data = data[id_]["vm_info"][vm_] if "cpu" in vm_data: out += " CPU: {}\n".format(vm_data["cpu"]) @@ -30,13 +30,13 @@ def output(data, **kwargs): # pylint: disable=unused-argument ) if "disks" in vm_data: for disk, d_data in vm_data["disks"].items(): - out += " Disk - {}:\n".format(disk) + out += f" Disk - {disk}:\n" out += " Size: {}\n".format(d_data["disk size"]) out += " File: {}\n".format(d_data["file"]) out += " File Format: {}\n".format(d_data["file format"]) if "nics" in vm_data: for mac in vm_data["nics"]: - out += " Nic - {}:\n".format(mac) + out += f" Nic - {mac}:\n" out += " Source: {}\n".format( vm_data["nics"][mac]["source"][ next(iter(vm_data["nics"][mac]["source"].keys())) diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py index 0a874daab11..21df2b9afb7 100644 --- a/salt/pillar/__init__.py +++ b/salt/pillar/__init__.py @@ -751,9 +751,7 @@ class Pillar: ) ) except Exception as exc: # pylint: disable=broad-except - errors.append( - "Rendering Primary Top file failed, render error:\n{}".format(exc) - ) + errors.append(f"Rendering Primary Top file failed, render error:\n{exc}") log.exception("Pillar rendering failed for minion %s", self.minion_id) # Search initial top files for includes @@ -958,7 +956,7 @@ class Pillar: **defaults, ) except Exception as exc: # pylint: disable=broad-except - msg = "Rendering SLS '{}' failed, render error:\n{}".format(sls, exc) + msg = f"Rendering SLS '{sls}' failed, render error:\n{exc}" log.critical(msg, exc_info=True) if self.opts.get("pillar_safe_render_error", True): errors.append( @@ -971,7 +969,7 @@ class Pillar: nstate = None if state: if not isinstance(state, dict): - msg = "SLS '{}' does not render to a dictionary".format(sls) + msg = f"SLS '{sls}' does not render to a dictionary" log.error(msg) errors.append(msg) else: @@ -1108,7 +1106,7 @@ class Pillar: "a sign of a malformed pillar sls file. Returned " "errors: %s", sls, - ", ".join(["'{}'".format(e) for e in errors]), + ", ".join([f"'{e}'" for e in errors]), ) continue pillar = merge( @@ -1358,7 +1356,7 @@ class Pillar: if ptr is not None: ptr[child] = ret except Exception as exc: # pylint: disable=broad-except - msg = "Failed to decrypt pillar key '{}': {}".format(key, exc) + msg = f"Failed to decrypt pillar key '{key}': {exc}" errors.append(msg) log.error(msg, exc_info=True) return errors diff --git a/salt/pillar/azureblob.py b/salt/pillar/azureblob.py index 4c26ba14b29..3b8c064201c 100644 --- a/salt/pillar/azureblob.py +++ b/salt/pillar/azureblob.py @@ -258,7 +258,7 @@ def _get_containers_cache_filename(container): if not os.path.exists(cache_dir): os.makedirs(cache_dir) - return os.path.join(cache_dir, "{}-files.cache".format(container)) + return os.path.join(cache_dir, f"{container}-files.cache") def _refresh_containers_cache_file( diff --git a/salt/pillar/django_orm.py b/salt/pillar/django_orm.py index 29a5eaaa413..641e6098514 100644 --- a/salt/pillar/django_orm.py +++ b/salt/pillar/django_orm.py @@ -125,7 +125,7 @@ def ext_pillar( env=None, env_file=None, *args, # pylint: disable=W0613 - **kwargs + **kwargs, ): # pylint: disable=W0613 """ Connect to a Django database through the ORM and retrieve model fields @@ -179,7 +179,7 @@ def ext_pillar( (key, _, value) = salt.utils.stringutils.to_str(line).partition("=") base_env[key] = value - command = ["bash", "-c", "source {} && env".format(env_file)] + command = ["bash", "-c", f"source {env_file} && env"] proc = subprocess.Popen(command, stdout=subprocess.PIPE) for line in proc.stdout: @@ -229,7 +229,7 @@ def ext_pillar( # (since we're using it as the key in a dictionary) if name_field not in model: raise salt.exceptions.SaltException( - "Name '{}' not found in returned fields.".format(name_field) + f"Name '{name_field}' not found in returned fields." ) if model[name_field] in pillar_for_model: diff --git a/salt/pillar/ec2_pillar.py b/salt/pillar/ec2_pillar.py index c4fe8e17519..7aa6cb008dd 100644 --- a/salt/pillar/ec2_pillar.py +++ b/salt/pillar/ec2_pillar.py @@ -184,9 +184,9 @@ def ext_pillar( find_id = minion_id elif tag_match_key: if tag_match_value == "uqdn": - find_filter = {"tag:{}".format(tag_match_key): minion_id.split(".", 1)[0]} + find_filter = {f"tag:{tag_match_key}": minion_id.split(".", 1)[0]} else: - find_filter = {"tag:{}".format(tag_match_key): minion_id} + find_filter = {f"tag:{tag_match_key}": minion_id} if grain_instance_id: # we have an untrusted grain_instance_id, use it to narrow the search # even more. Combination will be unique even if uqdn is set. diff --git a/salt/pillar/hiera.py b/salt/pillar/hiera.py index 55b8305db72..c799d4f195f 100644 --- a/salt/pillar/hiera.py +++ b/salt/pillar/hiera.py @@ -24,10 +24,10 @@ def ext_pillar( """ Execute hiera and return the data """ - cmd = "hiera -c {}".format(conf) + cmd = f"hiera -c {conf}" for key, val in __grains__.items(): if isinstance(val, str): - cmd += " {}='{}'".format(key, val) + cmd += f" {key}='{val}'" try: data = salt.utils.yaml.safe_load(__salt__["cmd.run"](cmd)) except Exception: # pylint: disable=broad-except diff --git a/salt/pillar/http_json.py b/salt/pillar/http_json.py index acebb3aaf89..b07a2573772 100644 --- a/salt/pillar/http_json.py +++ b/salt/pillar/http_json.py @@ -101,7 +101,7 @@ def ext_pillar( return {} grain_value = urllib.parse.quote(str(grain_value)) - url = re.sub("<{}>".format(grain_name), grain_value, url) + url = re.sub(f"<{grain_name}>", grain_value, url) log.debug("Getting url: %s", url) data = __salt__["http.query"]( diff --git a/salt/pillar/http_yaml.py b/salt/pillar/http_yaml.py index ff791c6cd8c..58df6248ae0 100644 --- a/salt/pillar/http_yaml.py +++ b/salt/pillar/http_yaml.py @@ -95,7 +95,7 @@ def ext_pillar( return {} grain_value = urllib.parse.quote(str(grain_value)) - url = re.sub("<{}>".format(grain_name), grain_value, url) + url = re.sub(f"<{grain_name}>", grain_value, url) log.debug("Getting url: %s", url) data = __salt__["http.query"]( diff --git a/salt/pillar/libvirt.py b/salt/pillar/libvirt.py index ae957639b7d..cbcba870e4c 100644 --- a/salt/pillar/libvirt.py +++ b/salt/pillar/libvirt.py @@ -42,9 +42,7 @@ def ext_pillar(minion_id, pillar, command): continue fn_ = os.path.join(key_dir, key) with salt.utils.files.fopen(fn_, "r") as fp_: - ret["libvirt.{}".format(key)] = salt.utils.stringutils.to_unicode( - fp_.read() - ) + ret[f"libvirt.{key}"] = salt.utils.stringutils.to_unicode(fp_.read()) with salt.utils.files.fopen(cacert, "r") as fp_: ret["libvirt.cacert.pem"] = salt.utils.stringutils.to_unicode(fp_.read()) return ret @@ -75,7 +73,7 @@ def gen_hyper_keys( proc = subprocess.run( ["certtool", "--generate-privkey"], stdout=subprocess.PIPE, - universal_newlines=True, + text=True, check=True, ) with salt.utils.files.fopen(cakey, "w") as wfh: @@ -116,7 +114,7 @@ def gen_hyper_keys( proc = subprocess.run( ["certtool", "--generate-privkey"], stdout=subprocess.PIPE, - universal_newlines=True, + text=True, check=True, ) with salt.utils.files.fopen(priv, "w") as wfh: @@ -153,7 +151,7 @@ def gen_hyper_keys( proc = subprocess.run( ["certtool", "--generate-privkey"], stdout=subprocess.PIPE, - universal_newlines=True, + text=True, check=True, ) with salt.utils.files.fopen(cpriv, "w") as wfh: diff --git a/salt/pillar/makostack.py b/salt/pillar/makostack.py index ef3b3d64cb5..f96092f8945 100644 --- a/salt/pillar/makostack.py +++ b/salt/pillar/makostack.py @@ -498,9 +498,7 @@ def _cleanup(obj): def _merge_dict(stack, obj): strategy = obj.pop("__", "merge-last") if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return _cleanup(obj) else: @@ -537,9 +535,7 @@ def _merge_list(stack, obj): strategy = obj[0]["__"] del obj[0] if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return obj elif strategy == "remove": diff --git a/salt/pillar/netbox.py b/salt/pillar/netbox.py index bbbf765e62a..1cee59c204d 100644 --- a/salt/pillar/netbox.py +++ b/salt/pillar/netbox.py @@ -1109,7 +1109,7 @@ def ext_pillar(minion_id, pillar, *args, **kwargs): # Fetch device from API headers = {} if api_token: - headers = {"Authorization": "Token {}".format(api_token)} + headers = {"Authorization": f"Token {api_token}"} else: log.error("The value for api_token is not set") return ret diff --git a/salt/pillar/puppet.py b/salt/pillar/puppet.py index b907ad1f321..792c3ec7738 100644 --- a/salt/pillar/puppet.py +++ b/salt/pillar/puppet.py @@ -19,9 +19,7 @@ def ext_pillar(minion_id, pillar, command): # pylint: disable=W0613 Execute an unmodified puppet_node_classifier and read the output as YAML """ try: - data = salt.utils.yaml.safe_load( - __salt__["cmd.run"]("{} {}".format(command, minion_id)) - ) + data = salt.utils.yaml.safe_load(__salt__["cmd.run"](f"{command} {minion_id}")) return data["parameters"] except Exception: # pylint: disable=broad-except log.critical("YAML data from %s failed to parse", command) diff --git a/salt/pillar/reclass_adapter.py b/salt/pillar/reclass_adapter.py index f47b4c52de2..ded9d664934 100644 --- a/salt/pillar/reclass_adapter.py +++ b/salt/pillar/reclass_adapter.py @@ -126,4 +126,4 @@ def ext_pillar(minion_id, pillar, **kwargs): raise except ReclassException as e: - raise SaltInvocationError("ext_pillar.reclass: {}".format(e)) + raise SaltInvocationError(f"ext_pillar.reclass: {e}") diff --git a/salt/pillar/s3.py b/salt/pillar/s3.py index 7f08439f8e4..deb1c9b2a26 100644 --- a/salt/pillar/s3.py +++ b/salt/pillar/s3.py @@ -276,7 +276,7 @@ def _get_buckets_cache_filename(bucket, prefix): if not os.path.exists(cache_dir): os.makedirs(cache_dir) - return os.path.join(cache_dir, "{}-{}-files.cache".format(bucket, prefix)) + return os.path.join(cache_dir, f"{bucket}-{prefix}-files.cache") def _refresh_buckets_cache_file(creds, cache_file, multiple_env, environment, prefix): diff --git a/salt/pillar/stack.py b/salt/pillar/stack.py index 0d72444418d..f8936ad4b4a 100644 --- a/salt/pillar/stack.py +++ b/salt/pillar/stack.py @@ -476,9 +476,7 @@ def _process_stack_cfg(cfg, stack, minion_id, pillar): try: yaml = jenv.get_template(unix_path).render(stack=stack, ymlpath=path) except Exception as e: - raise Exception( - 'Stack pillar template render error in {}:\n"{}"'.format(path, e) - ) + raise Exception(f'Stack pillar template render error in {path}:\n"{e}"') try: obj = salt.utils.yaml.safe_load(yaml) except Exception as e: @@ -506,9 +504,7 @@ def _cleanup(obj): def _merge_dict(stack, obj): strategy = obj.pop("__", "merge-last") if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return _cleanup(obj) else: @@ -545,9 +541,7 @@ def _merge_list(stack, obj): strategy = obj[0]["__"] del obj[0] if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return obj elif strategy == "remove": diff --git a/salt/pillar/vault.py b/salt/pillar/vault.py index 904c626b0e6..b51b5b828d2 100644 --- a/salt/pillar/vault.py +++ b/salt/pillar/vault.py @@ -203,7 +203,7 @@ def ext_pillar( if version2["v2"]: path = version2["data"] - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("GET", url) response.raise_for_status() vault_pillar_single = response.json().get("data", {}) diff --git a/salt/platform/win.py b/salt/platform/win.py index fff1010039b..ec63dbe319f 100644 --- a/salt/platform/win.py +++ b/salt/platform/win.py @@ -157,7 +157,7 @@ class NTSTATUS(wintypes.LONG): def __repr__(self): name = self.__class__.__name__ status = wintypes.ULONG.from_buffer(self) - return "{}({})".format(name, status.value) + return f"{name}({status.value})" PNTSTATUS = ctypes.POINTER(NTSTATUS) @@ -166,7 +166,7 @@ PNTSTATUS = ctypes.POINTER(NTSTATUS) class BOOL(wintypes.BOOL): def __repr__(self): name = self.__class__.__name__ - return "{}({})".format(name, bool(self)) + return f"{name}({bool(self)})" class HANDLE(wintypes.HANDLE): @@ -190,7 +190,7 @@ class HANDLE(wintypes.HANDLE): __del__ = Close def __repr__(self): - return "{}({})".format(self.__class__.__name__, int(self)) + return f"{self.__class__.__name__}({int(self)})" class LARGE_INTEGER(wintypes.LARGE_INTEGER): @@ -205,7 +205,7 @@ class LARGE_INTEGER(wintypes.LARGE_INTEGER): def __repr__(self): name = self.__class__.__name__ - return "{}({})".format(name, self.value) + return f"{name}({self.value})" def as_time(self): time100ns = self.value - self._unix_epoch @@ -261,7 +261,7 @@ class LUID(ctypes.Structure): def __repr__(self): name = self.__class__.__name__ - return "{}({})".format(name, int(self)) + return f"{name}({int(self)})" LPLUID = ctypes.POINTER(LUID) @@ -312,7 +312,7 @@ class TOKEN_SOURCE(ctypes.Structure): LPTOKEN_SOURCE = ctypes.POINTER(TOKEN_SOURCE) py_source_context = TOKEN_SOURCE(b"PYTHON ") py_origin_name = __name__.encode() -py_logon_process_name = "{}-{}".format(py_origin_name, os.getpid()) +py_logon_process_name = f"{py_origin_name}-{os.getpid()}" SIZE_T = ctypes.c_size_t @@ -343,7 +343,7 @@ class ContiguousUnicode(ctypes.Structure): def _get_unicode_string(self, name): wchar_size = ctypes.sizeof(WCHAR) - s = getattr(self, "_{}".format(name)) + s = getattr(self, f"_{name}") length = s.Length // wchar_size buf = s.Buffer if buf: @@ -375,7 +375,7 @@ class ContiguousUnicode(ctypes.Structure): addr = ctypes.addressof(self) + ctypes.sizeof(cls) for n, v in zip(self._string_names_, values): ptr = ctypes.cast(addr, PWCHAR) - ustr = getattr(self, "_{}".format(n)) + ustr = getattr(self, f"_{n}") length = ustr.Length = len(v) * wchar_size full_length = length + wchar_size if (n == name and value is None) or ( @@ -407,7 +407,7 @@ class ContiguousUnicode(ctypes.Structure): ctypes.memmove(ctypes.byref(x), address, ctypes.sizeof(x)) delta = ctypes.addressof(x) - address for n in cls._string_names_: - ustr = getattr(x, "_{}".format(n)) + ustr = getattr(x, f"_{n}") addr = ctypes.c_void_p.from_buffer(ustr.Buffer) if addr: addr.value += delta diff --git a/salt/proxy/chronos.py b/salt/proxy/chronos.py index 69b06d63e44..a138f39e78b 100644 --- a/salt/proxy/chronos.py +++ b/salt/proxy/chronos.py @@ -55,7 +55,7 @@ def ping(): """ try: response = salt.utils.http.query( - "{}/scheduler/jobs".format(CONFIG[CONFIG_BASE_URL]), + f"{CONFIG[CONFIG_BASE_URL]}/scheduler/jobs", decode_type="json", decode=True, ) diff --git a/salt/proxy/docker.py b/salt/proxy/docker.py index 7dca6d3f384..202a3e00f60 100644 --- a/salt/proxy/docker.py +++ b/salt/proxy/docker.py @@ -38,7 +38,7 @@ __virtualname__ = "docker" def __virtual__(): if __opts__.get("proxy", {}).get("proxytype") != __virtualname__: - return False, "Proxytype does not match: {}".format(__virtualname__) + return False, f"Proxytype does not match: {__virtualname__}" return True diff --git a/salt/proxy/dummy.py b/salt/proxy/dummy.py index 8656be31d93..12d71104a0a 100644 --- a/salt/proxy/dummy.py +++ b/salt/proxy/dummy.py @@ -30,7 +30,7 @@ def __virtual__(): def _save_state(opts, details): _id = __context__["dummy_proxy"]["id"] - cachefile = os.path.join(opts["cachedir"], "dummy-proxy-{}.cache".format(_id)) + cachefile = os.path.join(opts["cachedir"], f"dummy-proxy-{_id}.cache") with salt.utils.files.fopen(cachefile, "wb") as pck: pck.write(salt.utils.msgpack.packb(details, use_bin_type=True)) log.warning("Dummy Proxy Saved State(%s):\n%s", cachefile, pprint.pformat(details)) @@ -38,7 +38,7 @@ def _save_state(opts, details): def _load_state(opts): _id = __context__["dummy_proxy"]["id"] - cachefile = os.path.join(opts["cachedir"], "dummy-proxy-{}.cache".format(_id)) + cachefile = os.path.join(opts["cachedir"], f"dummy-proxy-{_id}.cache") try: with salt.utils.files.fopen(cachefile, "rb") as pck: state = salt.utils.msgpack.unpackb(pck.read(), raw=False) diff --git a/salt/proxy/marathon.py b/salt/proxy/marathon.py index 5347276bbdb..3be5b366333 100644 --- a/salt/proxy/marathon.py +++ b/salt/proxy/marathon.py @@ -55,7 +55,7 @@ def ping(): """ try: response = salt.utils.http.query( - "{}/ping".format(CONFIG[CONFIG_BASE_URL]), + f"{CONFIG[CONFIG_BASE_URL]}/ping", decode_type="plain", decode=True, ) diff --git a/salt/proxy/napalm.py b/salt/proxy/napalm.py index 4b9729635cb..13f2663cf0a 100644 --- a/salt/proxy/napalm.py +++ b/salt/proxy/napalm.py @@ -299,7 +299,7 @@ def shutdown(opts): __context__["napalm_device"]["network_device"].get( "HOSTNAME", "[unknown hostname]" ), - ":{}".format(port) if port else "", + f":{port}" if port else "", error, ) diff --git a/salt/queues/pgjsonb_queue.py b/salt/queues/pgjsonb_queue.py index aa42daa650d..f198c580b2b 100644 --- a/salt/queues/pgjsonb_queue.py +++ b/salt/queues/pgjsonb_queue.py @@ -80,15 +80,11 @@ def _conn(commit=False): conn_kwargs = {} for key, value in defaults.items(): - conn_kwargs[key] = __opts__.get( - "queue.{}.{}".format(__virtualname__, key), value - ) + conn_kwargs[key] = __opts__.get(f"queue.{__virtualname__}.{key}", value) try: conn = psycopg2.connect(**conn_kwargs) except psycopg2.OperationalError as exc: - raise SaltMasterError( - "pgjsonb returner could not connect to database: {exc}".format(exc=exc) - ) + raise SaltMasterError(f"pgjsonb returner could not connect to database: {exc}") cursor = conn.cursor() @@ -117,7 +113,7 @@ def _list_tables(cur): def _create_table(cur, queue): - cmd = "CREATE TABLE {}(id SERIAL PRIMARY KEY, data jsonb NOT NULL)".format(queue) + cmd = f"CREATE TABLE {queue}(id SERIAL PRIMARY KEY, data jsonb NOT NULL)" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True @@ -128,7 +124,7 @@ def _list_items(queue): Private function to list contents of a queue """ with _conn() as cur: - cmd = "SELECT data FROM {}".format(queue) + cmd = f"SELECT data FROM {queue}" log.debug("SQL Query: %s", cmd) cur.execute(cmd) contents = cur.fetchall() @@ -191,7 +187,7 @@ def insert(queue, items): with _conn(commit=True) as cur: if isinstance(items, dict): items = salt.utils.json.dumps(items) - cmd = "INSERT INTO {}(data) VALUES('{}')".format(queue, items) + cmd = f"INSERT INTO {queue}(data) VALUES('{items}')" log.debug("SQL Query: %s", cmd) try: cur.execute(cmd) @@ -201,7 +197,7 @@ def insert(queue, items): ) if isinstance(items, list): items = [(salt.utils.json.dumps(el),) for el in items] - cmd = "INSERT INTO {}(data) VALUES (%s)".format(queue) + cmd = f"INSERT INTO {queue}(data) VALUES (%s)" log.debug("SQL Query: %s", cmd) try: cur.executemany(cmd, items) @@ -227,7 +223,7 @@ def delete(queue, items): return True if isinstance(items, list): items = [(salt.utils.json.dumps(el),) for el in items] - cmd = "DELETE FROM {} WHERE data = %s".format(queue) + cmd = f"DELETE FROM {queue} WHERE data = %s" log.debug("SQL Query: %s", cmd) cur.executemany(cmd, items) return True @@ -237,7 +233,7 @@ def pop(queue, quantity=1, is_runner=False): """ Pop one or more or all items from the queue return them. """ - cmd = "SELECT id, data FROM {}".format(queue) + cmd = f"SELECT id, data FROM {queue}" if quantity != "all": try: quantity = int(quantity) @@ -246,7 +242,7 @@ def pop(queue, quantity=1, is_runner=False): exc ) raise SaltInvocationError(error_txt) - cmd = "".join([cmd, " LIMIT {};".format(quantity)]) + cmd = "".join([cmd, f" LIMIT {quantity};"]) log.debug("SQL Query: %s", cmd) items = [] with _conn(commit=True) as cur: @@ -256,7 +252,7 @@ def pop(queue, quantity=1, is_runner=False): ids = [str(item[0]) for item in result] items = [item[1] for item in result] idlist = "','".join(ids) - del_cmd = "DELETE FROM {} WHERE id IN ('{}');".format(queue, idlist) + del_cmd = f"DELETE FROM {queue} WHERE id IN ('{idlist}');" log.debug("SQL Query: %s", del_cmd) diff --git a/salt/queues/sqlite_queue.py b/salt/queues/sqlite_queue.py index 713bfa09ccd..b81d13ce5ed 100644 --- a/salt/queues/sqlite_queue.py +++ b/salt/queues/sqlite_queue.py @@ -38,7 +38,7 @@ def _conn(queue): Return an sqlite connection """ queue_dir = __opts__["sqlite_queue_dir"] - db = os.path.join(queue_dir, "{}.db".format(queue)) + db = os.path.join(queue_dir, f"{queue}.db") log.debug("Connecting to: %s", db) con = sqlite3.connect(db) @@ -61,7 +61,7 @@ def _list_tables(con): def _create_table(con, queue): with con: cur = con.cursor() - cmd = "CREATE TABLE {}(id INTEGER PRIMARY KEY, name TEXT UNIQUE)".format(queue) + cmd = f"CREATE TABLE {queue}(id INTEGER PRIMARY KEY, name TEXT UNIQUE)" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True @@ -74,7 +74,7 @@ def _list_items(queue): con = _conn(queue) with con: cur = con.cursor() - cmd = "SELECT name FROM {}".format(queue) + cmd = f"SELECT name FROM {queue}" log.debug("SQL Query: %s", cmd) cur.execute(cmd) contents = cur.fetchall() @@ -138,15 +138,15 @@ def insert(queue, items): cur = con.cursor() if isinstance(items, str): items = _quote_escape(items) - cmd = "INSERT INTO {}(name) VALUES('{}')".format(queue, items) + cmd = f"INSERT INTO {queue}(name) VALUES('{items}')" log.debug("SQL Query: %s", cmd) try: cur.execute(cmd) except sqlite3.IntegrityError as esc: - return "Item already exists in this queue. sqlite error: {}".format(esc) + return f"Item already exists in this queue. sqlite error: {esc}" if isinstance(items, list): items = [_quote_escape(el) for el in items] - cmd = "INSERT INTO {}(name) VALUES(?)".format(queue) + cmd = f"INSERT INTO {queue}(name) VALUES(?)" log.debug("SQL Query: %s", cmd) newitems = [] for item in items: @@ -162,12 +162,12 @@ def insert(queue, items): if isinstance(items, dict): items = salt.utils.json.dumps(items).replace('"', "'") items = _quote_escape(items) - cmd = "INSERT INTO {}(name) VALUES('{}')".format(queue, items) + cmd = f"INSERT INTO {queue}(name) VALUES('{items}')" log.debug("SQL Query: %s", cmd) try: cur.execute(cmd) except sqlite3.IntegrityError as esc: - return "Item already exists in this queue. sqlite error: {}".format(esc) + return f"Item already exists in this queue. sqlite error: {esc}" return True @@ -180,13 +180,13 @@ def delete(queue, items): cur = con.cursor() if isinstance(items, str): items = _quote_escape(items) - cmd = "DELETE FROM {} WHERE name = '{}'".format(queue, items) + cmd = f"DELETE FROM {queue} WHERE name = '{items}'" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True if isinstance(items, list): items = [_quote_escape(el) for el in items] - cmd = "DELETE FROM {} WHERE name = ?".format(queue) + cmd = f"DELETE FROM {queue} WHERE name = ?" log.debug("SQL Query: %s", cmd) newitems = [] for item in items: @@ -196,7 +196,7 @@ def delete(queue, items): if isinstance(items, dict): items = salt.utils.json.dumps(items).replace('"', "'") items = _quote_escape(items) - cmd = "DELETE FROM {} WHERE name = '{}'".format(queue, items) + cmd = f"DELETE FROM {queue} WHERE name = '{items}'" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True @@ -207,7 +207,7 @@ def pop(queue, quantity=1, is_runner=False): """ Pop one or more or all items from the queue return them. """ - cmd = "SELECT name FROM {}".format(queue) + cmd = f"SELECT name FROM {queue}" if quantity != "all": try: quantity = int(quantity) @@ -216,7 +216,7 @@ def pop(queue, quantity=1, is_runner=False): exc ) raise SaltInvocationError(error_txt) - cmd = "".join([cmd, " LIMIT {}".format(quantity)]) + cmd = "".join([cmd, f" LIMIT {quantity}"]) log.debug("SQL Query: %s", cmd) con = _conn(queue) items = [] @@ -227,7 +227,7 @@ def pop(queue, quantity=1, is_runner=False): items = [item[0] for item in result] itemlist = '","'.join(items) _quote_escape(itemlist) - del_cmd = 'DELETE FROM {} WHERE name IN ("{}")'.format(queue, itemlist) + del_cmd = f'DELETE FROM {queue} WHERE name IN ("{itemlist}")' log.debug("SQL Query: %s", del_cmd) diff --git a/salt/renderers/jinja.py b/salt/renderers/jinja.py index e19636dba00..f238bd281de 100644 --- a/salt/renderers/jinja.py +++ b/salt/renderers/jinja.py @@ -46,7 +46,7 @@ def render( argline="", context=None, tmplpath=None, - **kws + **kws, ): """ Render the template_file, passing the functions and grains into the @@ -56,7 +56,7 @@ def render( """ from_str = argline == "-s" if not from_str and argline: - raise SaltRenderError("Unknown renderer option: {opt}".format(opt=argline)) + raise SaltRenderError(f"Unknown renderer option: {argline}") tmp_data = salt.utils.templates.JINJA( template_file, @@ -71,7 +71,7 @@ def render( tmplpath=tmplpath, proxy=__proxy__, from_str=from_str, - **kws + **kws, ) if not tmp_data.get("result", False): raise SaltRenderError( diff --git a/salt/renderers/py.py b/salt/renderers/py.py index 3ce58ac405c..46ce1c03902 100644 --- a/salt/renderers/py.py +++ b/salt/renderers/py.py @@ -140,7 +140,7 @@ def render(template, saltenv="base", sls="", tmplpath=None, **kws): """ template = tmplpath if not os.path.isfile(template): - raise SaltRenderError("Template {} is not a file!".format(template)) + raise SaltRenderError(f"Template {template} is not a file!") tmp_data = salt.utils.templates.py( template, @@ -157,7 +157,7 @@ def render(template, saltenv="base", sls="", tmplpath=None, **kws): saltenv=saltenv, __sls__=sls, sls=sls, - **kws + **kws, ) if not tmp_data.get("result", False): raise SaltRenderError( diff --git a/salt/renderers/pyobjects.py b/salt/renderers/pyobjects.py index f8de8d1f9e8..a719b34ef5f 100644 --- a/salt/renderers/pyobjects.py +++ b/salt/renderers/pyobjects.py @@ -347,7 +347,7 @@ class PyobjectsModule: self.__dict__ = attrs def __repr__(self): - return "".format(self.name) + return f"" def load_states(): @@ -464,9 +464,7 @@ def render(template, saltenv="base", sls="", salt_data=True, **kwargs): with get_file_client(__opts__) as client: state_file = client.cache_file(import_file, saltenv) if not state_file: - raise ImportError( - "Could not find the file '{}'".format(import_file) - ) + raise ImportError(f"Could not find the file '{import_file}'") with salt.utils.files.fopen(state_file) as state_fh: state_contents, state_globals = process_template(state_fh) @@ -491,7 +489,7 @@ def render(template, saltenv="base", sls="", salt_data=True, **kwargs): if name not in state_globals: raise ImportError( - "'{}' was not found in '{}'".format(name, import_file) + f"'{name}' was not found in '{import_file}'" ) template_globals[alias] = state_globals[name] diff --git a/salt/renderers/stateconf.py b/salt/renderers/stateconf.py index e65664754d8..d487f2d4e67 100644 --- a/salt/renderers/stateconf.py +++ b/salt/renderers/stateconf.py @@ -116,7 +116,7 @@ def render(input, saltenv="base", sls="", argline="", **kws): sls, context=ctx, argline=rt_argline.strip(), - **kws + **kws, ) high = render_data(tmplout, saltenv, sls, argline=rd_argline.strip()) return process_high_data(high, extract) @@ -202,7 +202,7 @@ def render(input, saltenv="base", sls="", argline="", **kws): name, rt_argline = (args[1] + " ").split(" ", 1) render_template = renderers[name] # e.g., the mako renderer except KeyError as err: - raise SaltRenderError("Renderer: {} is not available!".format(err)) + raise SaltRenderError(f"Renderer: {err} is not available!") except IndexError: raise INVALID_USAGE_ERROR @@ -428,7 +428,7 @@ EXTENDED_REQUIRE_IN = {} # explicit require_in/watch_in/listen_in/onchanges_in/onfail_in can only contain states after it def add_implicit_requires(data): def T(sid, state): # pylint: disable=C0103 - return "{}:{}".format(sid, state_name(state)) + return f"{sid}:{state_name(state)}" states_before = set() states_after = set() diff --git a/salt/returners/__init__.py b/salt/returners/__init__.py index 5ad44a7ff65..2f184fa598a 100644 --- a/salt/returners/__init__.py +++ b/salt/returners/__init__.py @@ -120,9 +120,9 @@ def _fetch_option(cfg, ret_config, virtualname, attr_name): if isinstance(cfg, dict): c_cfg = cfg else: - c_cfg = cfg("{}".format(virtualname), {}) + c_cfg = cfg(f"{virtualname}", {}) - default_cfg_key = "{}.{}".format(virtualname, attr_name) + default_cfg_key = f"{virtualname}.{attr_name}" if not ret_config: # Using the default configuration key if isinstance(cfg, dict): @@ -134,7 +134,7 @@ def _fetch_option(cfg, ret_config, virtualname, attr_name): return c_cfg.get(attr_name, cfg(default_cfg_key)) # Using ret_config to override the default configuration key - ret_cfg = cfg("{}.{}".format(ret_config, virtualname), {}) + ret_cfg = cfg(f"{ret_config}.{virtualname}", {}) override_default_cfg_key = "{}.{}.{}".format( ret_config, @@ -209,6 +209,6 @@ def _fetch_profile_opts( return {} return { - pattr: creds.get("{}.{}".format(virtualname, profile_attrs[pattr])) + pattr: creds.get(f"{virtualname}.{profile_attrs[pattr]}") for pattr in profile_attrs } diff --git a/salt/returners/carbon_return.py b/salt/returners/carbon_return.py index 5dd6cd82dbd..91d5ceeb24a 100644 --- a/salt/returners/carbon_return.py +++ b/salt/returners/carbon_return.py @@ -198,10 +198,10 @@ def _walk(path, value, metrics, timestamp, skip): ) if isinstance(value, Mapping): for key, val in value.items(): - _walk("{}.{}".format(path, key), val, metrics, timestamp, skip) + _walk(f"{path}.{key}", val, metrics, timestamp, skip) elif isinstance(value, list): for item in value: - _walk("{}.{}".format(path, item), item, metrics, timestamp, skip) + _walk(f"{path}.{item}", item, metrics, timestamp, skip) else: try: diff --git a/salt/returners/couchdb_return.py b/salt/returners/couchdb_return.py index eff8c919bb0..0e39745c883 100644 --- a/salt/returners/couchdb_return.py +++ b/salt/returners/couchdb_return.py @@ -122,7 +122,7 @@ def _request(method, url, content_type=None, _data=None): try: handler = opener.open(request) except HTTPError as exc: - return {"error": "{}".format(exc)} + return {"error": f"{exc}"} return salt.utils.json.loads(handler.read()) diff --git a/salt/returners/elasticsearch_return.py b/salt/returners/elasticsearch_return.py index aa93542339a..8d329e313e3 100644 --- a/salt/returners/elasticsearch_return.py +++ b/salt/returners/elasticsearch_return.py @@ -182,8 +182,8 @@ def _ensure_index(index): "number_of_replicas": options["number_of_replicas"], } } - __salt__["elasticsearch.index_create"]("{}-v1".format(index), index_definition) - __salt__["elasticsearch.alias_create"]("{}-v1".format(index), index) + __salt__["elasticsearch.index_create"](f"{index}-v1", index_definition) + __salt__["elasticsearch.alias_create"](f"{index}-v1", index) def _convert_keys(data): @@ -235,9 +235,9 @@ def returner(ret): # Build the index name if options["states_single_index"] and job_fun in STATE_FUNCTIONS: - index = "salt-{}".format(STATE_FUNCTIONS[job_fun]) + index = f"salt-{STATE_FUNCTIONS[job_fun]}" else: - index = "salt-{}".format(job_fun_escaped) + index = f"salt-{job_fun_escaped}" if options["index_date"]: index = "{}-{}".format(index, datetime.date.today().strftime("%Y.%m.%d")) @@ -259,7 +259,7 @@ def returner(ret): # index to be '-ordered' so as not to clash with the unsorted # index data format if options["states_order_output"] and isinstance(ret["return"], dict): - index = "{}-ordered".format(index) + index = f"{index}-ordered" max_chars = len(str(len(ret["return"]))) for uid, data in ret["return"].items(): diff --git a/salt/returners/influxdb_return.py b/salt/returners/influxdb_return.py index ff78d2b02d4..76fdc15b369 100644 --- a/salt/returners/influxdb_return.py +++ b/salt/returners/influxdb_return.py @@ -109,7 +109,7 @@ def _get_version(host, port, user, password): # check the InfluxDB version via the HTTP API try: result = requests.get( - "http://{}:{}/ping".format(host, port), auth=(user, password), timeout=120 + f"http://{host}:{port}/ping", auth=(user, password), timeout=120 ) if influxDBVersionHeader in result.headers: version = result.headers[influxDBVersionHeader] @@ -224,7 +224,7 @@ def get_load(jid): Return the load data that marks a specified jid """ serv = _get_serv(ret=None) - sql = "select load from jids where jid = '{}'".format(jid) + sql = f"select load from jids where jid = '{jid}'" log.debug(">> Now in get_load %s", jid) data = serv.query(sql) @@ -240,7 +240,7 @@ def get_jid(jid): """ serv = _get_serv(ret=None) - sql = "select id, full_ret from returns where jid = '{}'".format(jid) + sql = f"select id, full_ret from returns where jid = '{jid}'" data = serv.query(sql) ret = {} diff --git a/salt/returners/local_cache.py b/salt/returners/local_cache.py index 632e11c22e9..4f62de3a5a3 100644 --- a/salt/returners/local_cache.py +++ b/salt/returners/local_cache.py @@ -89,7 +89,7 @@ def prep_jid(nocache=False, passed_jid=None, recurse_count=0): So do what you have to do to make sure that stays the case """ if recurse_count >= 5: - err = "prep_jid could not store a jid after {} tries.".format(recurse_count) + err = f"prep_jid could not store a jid after {recurse_count} tries." log.error(err) raise salt.exceptions.SaltCacheError(err) if passed_jid is None: # this can be a None or an empty string. @@ -237,7 +237,7 @@ def save_minions(jid, minions, syndic_id=None): log.debug( "Adding minions for job %s%s: %s", jid, - " from syndic master '{}'".format(syndic_id) if syndic_id else "", + f" from syndic master '{syndic_id}'" if syndic_id else "", minions, ) diff --git a/salt/returners/mattermost_returner.py b/salt/returners/mattermost_returner.py index fae03a0259b..d41841aa4a1 100644 --- a/salt/returners/mattermost_returner.py +++ b/salt/returners/mattermost_returner.py @@ -128,7 +128,7 @@ def event_return(events): log.debug("Event data: %s", event["data"]) message = "tag: {}\r\n".format(event["tag"]) for key, value in event["data"].items(): - message += "{}: {}\r\n".format(key, value) + message += f"{key}: {value}\r\n" result = post_message(channel, message, username, api_url, hook) if not result: is_ok = False @@ -157,7 +157,7 @@ def post_message(channel, message, username, api_url, hook): result = salt.utils.mattermost.query( api_url=api_url, hook=hook, - data="payload={}".format(salt.utils.json.dumps(parameters)), + data=f"payload={salt.utils.json.dumps(parameters)}", ) log.debug("result %s", result) diff --git a/salt/returners/memcache_return.py b/salt/returners/memcache_return.py index a5d80802757..455f0a4adc9 100644 --- a/salt/returners/memcache_return.py +++ b/salt/returners/memcache_return.py @@ -121,9 +121,9 @@ def _get_list(serv, key): def _append_list(serv, key, value): if value in _get_list(serv, key): return - r = serv.append(key, "{},".format(value)) + r = serv.append(key, f"{value},") if not r: - serv.add(key, "{},".format(value)) + serv.add(key, f"{value},") def prep_jid(nocache=False, passed_jid=None): # pylint: disable=unused-argument @@ -142,8 +142,8 @@ def returner(ret): jid = ret["jid"] fun = ret["fun"] rets = salt.utils.json.dumps(ret) - serv.set("{}:{}".format(jid, minion), rets) # cache for get_jid - serv.set("{}:{}".format(fun, minion), rets) # cache for get_fun + serv.set(f"{jid}:{minion}", rets) # cache for get_jid + serv.set(f"{fun}:{minion}", rets) # cache for get_fun # The following operations are neither efficient nor atomic. # If there is a way to make them so, this should be updated. @@ -183,7 +183,7 @@ def get_jid(jid): """ serv = _get_serv(ret=None) minions = _get_list(serv, "minions") - returns = serv.get_multi(minions, key_prefix="{}:".format(jid)) + returns = serv.get_multi(minions, key_prefix=f"{jid}:") # returns = {minion: return, minion: return, ...} ret = {} for minion, data in returns.items(): @@ -197,7 +197,7 @@ def get_fun(fun): """ serv = _get_serv(ret=None) minions = _get_list(serv, "minions") - returns = serv.get_multi(minions, key_prefix="{}:".format(fun)) + returns = serv.get_multi(minions, key_prefix=f"{fun}:") # returns = {minion: return, minion: return, ...} ret = {} for minion, data in returns.items(): diff --git a/salt/returners/multi_returner.py b/salt/returners/multi_returner.py index 9a030a2ae60..0017f6e7a2f 100644 --- a/salt/returners/multi_returner.py +++ b/salt/returners/multi_returner.py @@ -41,11 +41,9 @@ def prep_jid(nocache=False, passed_jid=None): jid = passed_jid for returner_ in __opts__[CONFIG_KEY]: if jid is None: - jid = _mminion().returners["{}.prep_jid".format(returner_)](nocache=nocache) + jid = _mminion().returners[f"{returner_}.prep_jid"](nocache=nocache) else: - r_jid = _mminion().returners["{}.prep_jid".format(returner_)]( - nocache=nocache - ) + r_jid = _mminion().returners[f"{returner_}.prep_jid"](nocache=nocache) if r_jid != jid: log.debug("Uhh.... crud the jids do not match") return jid @@ -56,7 +54,7 @@ def returner(load): Write return to all returners in multi_returner """ for returner_ in __opts__[CONFIG_KEY]: - _mminion().returners["{}.returner".format(returner_)](load) + _mminion().returners[f"{returner_}.returner"](load) def save_load(jid, clear_load, minions=None): @@ -64,7 +62,7 @@ def save_load(jid, clear_load, minions=None): Write load to all returners in multi_returner """ for returner_ in __opts__[CONFIG_KEY]: - _mminion().returners["{}.save_load".format(returner_)](jid, clear_load) + _mminion().returners[f"{returner_}.save_load"](jid, clear_load) def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument @@ -79,7 +77,7 @@ def get_load(jid): """ ret = {} for returner_ in __opts__[CONFIG_KEY]: - ret.update(_mminion().returners["{}.get_load".format(returner_)](jid)) + ret.update(_mminion().returners[f"{returner_}.get_load"](jid)) return ret @@ -90,7 +88,7 @@ def get_jid(jid): """ ret = {} for returner_ in __opts__[CONFIG_KEY]: - ret.update(_mminion().returners["{}.get_jid".format(returner_)](jid)) + ret.update(_mminion().returners[f"{returner_}.get_jid"](jid)) return ret @@ -101,7 +99,7 @@ def get_jids(): """ ret = {} for returner_ in __opts__[CONFIG_KEY]: - ret.update(_mminion().returners["{}.get_jids".format(returner_)]()) + ret.update(_mminion().returners[f"{returner_}.get_jids"]()) return ret @@ -111,6 +109,6 @@ def clean_old_jobs(): Clean out the old jobs from all returners (if you have it) """ for returner_ in __opts__[CONFIG_KEY]: - fstr = "{}.clean_old_jobs".format(returner_) + fstr = f"{returner_}.clean_old_jobs" if fstr in _mminion().returners: _mminion().returners[fstr]() diff --git a/salt/returners/odbc.py b/salt/returners/odbc.py index f7393876739..da98baf18c4 100644 --- a/salt/returners/odbc.py +++ b/salt/returners/odbc.py @@ -153,7 +153,7 @@ def _get_options(ret=None): attrs = {"dsn": "dsn", "user": "user", "passwd": "passwd"} _options = salt.returners.get_returner_options( - "returner.{}".format(__virtualname__), + f"returner.{__virtualname__}", ret, attrs, __salt__=__salt__, @@ -171,7 +171,7 @@ def _get_conn(ret=None): user = _options.get("user") passwd = _options.get("passwd") - return pyodbc.connect("DSN={};UID={};PWD={}".format(dsn, user, passwd)) + return pyodbc.connect(f"DSN={dsn};UID={user};PWD={passwd}") def _close_conn(conn): diff --git a/salt/returners/postgres.py b/salt/returners/postgres.py index a30ac590056..de7d436c83c 100644 --- a/salt/returners/postgres.py +++ b/salt/returners/postgres.py @@ -174,7 +174,7 @@ def _get_options(ret=None): } _options = salt.returners.get_returner_options( - "returner.{}".format(__virtualname__), + f"returner.{__virtualname__}", ret, attrs, __salt__=__salt__, @@ -204,7 +204,7 @@ def _get_serv(ret=None, commit=False): except psycopg2.OperationalError as exc: raise salt.exceptions.SaltMasterError( - "postgres returner could not connect to database: {exc}".format(exc=exc) + f"postgres returner could not connect to database: {exc}" ) cursor = conn.cursor() diff --git a/salt/returners/redis_return.py b/salt/returners/redis_return.py index 8a821630b70..9a75ae0f7a8 100644 --- a/salt/returners/redis_return.py +++ b/salt/returners/redis_return.py @@ -212,8 +212,8 @@ def returner(ret): serv = _get_serv(ret) pipeline = serv.pipeline(transaction=False) minion, jid = ret["id"], ret["jid"] - pipeline.hset("ret:{}".format(jid), minion, salt.utils.json.dumps(ret)) - pipeline.expire("ret:{}".format(jid), _get_ttl()) + pipeline.hset(f"ret:{jid}", minion, salt.utils.json.dumps(ret)) + pipeline.expire(f"ret:{jid}", _get_ttl()) pipeline.set("{}:{}".format(minion, ret["fun"]), jid) pipeline.sadd("minions", minion) pipeline.execute() @@ -224,7 +224,7 @@ def save_load(jid, load, minions=None): Save the load to the specified jid """ serv = _get_serv(ret=None) - serv.setex("load:{}".format(jid), _get_ttl(), salt.utils.json.dumps(load)) + serv.setex(f"load:{jid}", _get_ttl(), salt.utils.json.dumps(load)) def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument @@ -238,7 +238,7 @@ def get_load(jid): Return the load data that marks a specified jid """ serv = _get_serv(ret=None) - data = serv.get("load:{}".format(jid)) + data = serv.get(f"load:{jid}") if data: return salt.utils.json.loads(data) return {} @@ -250,7 +250,7 @@ def get_jid(jid): """ serv = _get_serv(ret=None) ret = {} - for minion, data in serv.hgetall("ret:{}".format(jid)).items(): + for minion, data in serv.hgetall(f"ret:{jid}").items(): if data: ret[minion] = salt.utils.json.loads(data) return ret @@ -263,14 +263,14 @@ def get_fun(fun): serv = _get_serv(ret=None) ret = {} for minion in serv.smembers("minions"): - ind_str = "{}:{}".format(minion, fun) + ind_str = f"{minion}:{fun}" try: jid = serv.get(ind_str) except Exception: # pylint: disable=broad-except continue if not jid: continue - data = serv.get("{}:{}".format(minion, jid)) + data = serv.get(f"{minion}:{jid}") if data: ret[minion] = salt.utils.json.loads(data) return ret diff --git a/salt/returners/sentry_return.py b/salt/returners/sentry_return.py index 0b660392ef0..6f477dc1c99 100644 --- a/salt/returners/sentry_return.py +++ b/salt/returners/sentry_return.py @@ -111,11 +111,7 @@ def _get_message(ret): kwargs = ret["fun_args"][-1] if isinstance(kwargs, dict): kwarg_string = " ".join( - sorted( - "{}={}".format(k, v) - for k, v in kwargs.items() - if not k.startswith("_") - ) + sorted(f"{k}={v}" for k, v in kwargs.items() if not k.startswith("_")) ) return "salt func: {fun} {argstr} {kwargstr}".format( fun=ret["fun"], argstr=arg_string, kwargstr=kwarg_string diff --git a/salt/returners/slack_webhook_return.py b/salt/returners/slack_webhook_return.py index 43357f53d23..5df1a1d641c 100644 --- a/salt/returners/slack_webhook_return.py +++ b/salt/returners/slack_webhook_return.py @@ -170,10 +170,10 @@ def _generate_payload(author_icon, title, report, **kwargs): text += "JID: {}\n".format(report.get("jid")) if TOTAL_KEY in report: - text += "Total: {}\n".format(report[TOTAL_KEY]) + text += f"Total: {report[TOTAL_KEY]}\n" if DURATION_KEY in report: - text += "Duration: {:.2f} secs".format(float(report[DURATION_KEY])) + text += f"Duration: {float(report[DURATION_KEY]):.2f} secs" attachments = [ { @@ -201,7 +201,7 @@ def _generate_payload(author_icon, title, report, **kwargs): # Changed changed = { "color": "warning", - "title": "Changed: {}".format(report[CHANGED_KEY].get(COUNTER_KEY, 0)), + "title": f"Changed: {report[CHANGED_KEY].get(COUNTER_KEY, 0)}", } if len(report[CHANGED_KEY].get(TASKS_KEY, [])) > 0: @@ -212,7 +212,7 @@ def _generate_payload(author_icon, title, report, **kwargs): # Failed failed = { "color": "danger", - "title": "Failed: {}".format(report[FAILED_KEY].get(COUNTER_KEY, None)), + "title": f"Failed: {report[FAILED_KEY].get(COUNTER_KEY, None)}", } if len(report[FAILED_KEY].get(TASKS_KEY, [])) > 0: @@ -319,9 +319,7 @@ def _generate_report(ret, show_tasks): del ret_return[CHANGED_KEY][TASKS_KEY] del ret_return[FAILED_KEY][TASKS_KEY] elif isinstance(ret_return, dict): - ret_return = { - "return": "\n{}".format(salt.utils.yaml.safe_dump(ret_return, indent=2)) - } + ret_return = {"return": f"\n{salt.utils.yaml.safe_dump(ret_return, indent=2)}"} else: ret_return = {"return": ret_return} diff --git a/salt/returners/smtp_return.py b/salt/returners/smtp_return.py index ca10015ef24..6c6394861d9 100644 --- a/salt/returners/smtp_return.py +++ b/salt/returners/smtp_return.py @@ -185,7 +185,7 @@ def returner(ret): for field in fields: if field in ret: - subject += " {}".format(ret[field]) + subject += f" {ret[field]}" subject = compile_template( ":string:", rend, renderer, blacklist, whitelist, input_data=subject, **ret ) @@ -213,7 +213,7 @@ def returner(ret): if gpgowner: if HAS_GNUPG: gpg = gnupg.GPG( - gnupghome=os.path.expanduser("~{}/.gnupg".format(gpgowner)), + gnupghome=os.path.expanduser(f"~{gpgowner}/.gnupg"), options=["--trust-model always"], ) encrypted_data = gpg.encrypt(content, to_addrs) diff --git a/salt/returners/zabbix_return.py b/salt/returners/zabbix_return.py index acf9db3f746..1b232aec2b3 100644 --- a/salt/returners/zabbix_return.py +++ b/salt/returners/zabbix_return.py @@ -90,4 +90,4 @@ def returner(ret): ) if not changes and not errors: - zabbix_send("salt.trap.info", "SALT {} OK".format(job_minion_id)) + zabbix_send("salt.trap.info", f"SALT {job_minion_id} OK") diff --git a/salt/roster/__init__.py b/salt/roster/__init__.py index fc7339d785b..a6b8bb2475d 100644 --- a/salt/roster/__init__.py +++ b/salt/roster/__init__.py @@ -45,10 +45,10 @@ def get_roster_file(options): template = os.path.join(salt.syspaths.CONFIG_DIR, "roster") if not os.path.isfile(template): - raise OSError('Roster file "{}" not found'.format(template)) + raise OSError(f'Roster file "{template}" not found') if not os.access(template, os.R_OK): - raise OSError('Access denied to roster "{}"'.format(template)) + raise OSError(f'Access denied to roster "{template}"') return template @@ -80,7 +80,7 @@ class Roster: back = set() if self.backends: for backend in self.backends: - fun = "{}.targets".format(backend) + fun = f"{backend}.targets" if fun in self.rosters: back.add(backend) return back @@ -93,7 +93,7 @@ class Roster: """ targets = {} for back in self._gen_back(): - f_str = "{}.targets".format(back) + f_str = f"{back}.targets" if f_str not in self.rosters: continue try: diff --git a/salt/roster/cache.py b/salt/roster/cache.py index 5a6018d69d0..0e8d85dc634 100644 --- a/salt/roster/cache.py +++ b/salt/roster/cache.py @@ -177,7 +177,7 @@ def _load_minion(minion_id, cache): 6: sorted(ipaddress.IPv6Address(addr) for addr in grains.get("ipv6", [])), } - mine = cache.fetch("minions/{}".format(minion_id), "mine") + mine = cache.fetch(f"minions/{minion_id}", "mine") return grains, pillar, addrs, mine @@ -256,6 +256,4 @@ def _minion_lookup(minion_id, key, minion): if filters[key](addr): return str(addr) except KeyError: - raise KeyError( - "Invalid filter {} specified in roster_order".format(key) - ) + raise KeyError(f"Invalid filter {key} specified in roster_order") diff --git a/salt/roster/dir.py b/salt/roster/dir.py index 2aa78dffe4e..8ac42a3350b 100644 --- a/salt/roster/dir.py +++ b/salt/roster/dir.py @@ -71,7 +71,7 @@ def targets(tgt, tgt_type="glob", **kwargs): for minion_id in matched_raw: target_file = salt.utils.verify.clean_path(roster_dir, minion_id) if not os.path.exists(target_file): - raise CommandExecutionError("{} does not exist".format(target_file)) + raise CommandExecutionError(f"{target_file} does not exist") rendered[minion_id] = _render(target_file, **kwargs) pruned_rendered = {id_: data for id_, data in rendered.items() if data} log.debug( @@ -99,9 +99,9 @@ def _render(roster_file, **kwargs): __opts__["renderer_blacklist"], __opts__["renderer_whitelist"], mask_value="*passw*", - **kwargs + **kwargs, ) - result.setdefault("host", "{}.{}".format(os.path.basename(roster_file), domain)) + result.setdefault("host", f"{os.path.basename(roster_file)}.{domain}") return result except: # pylint: disable=W0702 log.warning('Unable to render roster file "%s".', roster_file, exc_info=True) diff --git a/salt/roster/sshconfig.py b/salt/roster/sshconfig.py index a499fff5860..c4b3bdcb7ae 100644 --- a/salt/roster/sshconfig.py +++ b/salt/roster/sshconfig.py @@ -33,7 +33,7 @@ def _get_ssh_config_file(opts): if not os.path.isfile(ssh_config_file): raise OSError("Cannot find SSH config file") if not os.access(ssh_config_file, os.R_OK): - raise OSError("Cannot access SSH config file: {}".format(ssh_config_file)) + raise OSError(f"Cannot access SSH config file: {ssh_config_file}") return ssh_config_file @@ -117,7 +117,7 @@ class RosterMatcher: Execute the correct tgt_type routine and return """ try: - return getattr(self, "ret_{}_minions".format(self.tgt_type))() + return getattr(self, f"ret_{self.tgt_type}_minions")() except AttributeError: return {} diff --git a/salt/roster/sshknownhosts.py b/salt/roster/sshknownhosts.py index 9f8432e1672..6f895e2e7fa 100644 --- a/salt/roster/sshknownhosts.py +++ b/salt/roster/sshknownhosts.py @@ -97,9 +97,7 @@ def targets(tgt, tgt_type="glob"): raise OSError("Cannot find SSH known_hosts file") if not os.access(ssh_known_hosts_file, os.R_OK): log.error("Cannot access SSH known_hosts file: %s", ssh_known_hosts_file) - raise OSError( - "Cannot access SSH known_hosts file: {}".format(ssh_known_hosts_file) - ) + raise OSError(f"Cannot access SSH known_hosts file: {ssh_known_hosts_file}") with salt.utils.files.fopen(ssh_known_hosts_file, "r") as hostfile: raw = _parse_ssh_known_hosts([line.rstrip() for line in hostfile]) diff --git a/salt/runner.py b/salt/runner.py index 2a19636b8ed..d3501b8f919 100644 --- a/salt/runner.py +++ b/salt/runner.py @@ -203,7 +203,7 @@ class Runner(RunnerClient): arg = self.opts.get("fun", None) docs = super().get_docs(arg) for fun in sorted(docs): - display_output("{}:".format(fun), "text", self.opts) + display_output(f"{fun}:", "text", self.opts) print(docs[fun]) # TODO: move to mixin whenever we want a salt-wheel cli @@ -313,13 +313,13 @@ class Runner(RunnerClient): evt.fire_event( { "success": False, - "return": "{}".format(exc), + "return": f"{exc}", "retcode": 254, "fun": self.opts["fun"], "fun_args": fun_args, "jid": self.jid, }, - tag="salt/run/{}/ret".format(self.jid), + tag=f"salt/run/{self.jid}/ret", ) # Attempt to grab documentation if "fun" in low: @@ -330,7 +330,7 @@ class Runner(RunnerClient): # If we didn't get docs returned then # return the `not availble` message. if not ret: - ret = "{}".format(exc) + ret = f"{exc}" if not self.opts.get("quiet", False): display_output(ret, "nested", self.opts) else: diff --git a/salt/runners/asam.py b/salt/runners/asam.py index 6014429c792..372bc7dd742 100644 --- a/salt/runners/asam.py +++ b/salt/runners/asam.py @@ -226,7 +226,7 @@ def remove_platform(name, server_url): try: html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"]) except Exception as exc: # pylint: disable=broad-except - err_msg = "Failed to look up existing platforms on {}".format(server_url) + err_msg = f"Failed to look up existing platforms on {server_url}" log.error("%s:\n%s", err_msg, exc) return {name: err_msg} @@ -244,18 +244,18 @@ def remove_platform(name, server_url): url, data, auth, verify=config["verify_ssl"] ) except Exception as exc: # pylint: disable=broad-except - err_msg = "Failed to delete platform from {}".format(server_url) + err_msg = f"Failed to delete platform from {server_url}" log.error("%s:\n%s", err_msg, exc) return {name: err_msg} parser = _parse_html_content(html_content) platformset_name = _get_platformset_name(parser.data, name) if platformset_name: - return {name: "Failed to delete platform from {}".format(server_url)} + return {name: f"Failed to delete platform from {server_url}"} else: - return {name: "Successfully deleted platform from {}".format(server_url)} + return {name: f"Successfully deleted platform from {server_url}"} else: - return {name: "Specified platform name does not exist on {}".format(server_url)} + return {name: f"Specified platform name does not exist on {server_url}"} def list_platforms(server_url): @@ -351,11 +351,11 @@ def add_platform(name, platform_set, server_url): platforms = list_platforms(server_url) if name in platforms[server_url]: - return {name: "Specified platform already exists on {}".format(server_url)} + return {name: f"Specified platform already exists on {server_url}"} platform_sets = list_platform_sets(server_url) if platform_set not in platform_sets[server_url]: - return {name: "Specified platform set does not exist on {}".format(server_url)} + return {name: f"Specified platform set does not exist on {server_url}"} url = config["platform_edit_url"] @@ -373,12 +373,12 @@ def add_platform(name, platform_set, server_url): try: html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"]) except Exception as exc: # pylint: disable=broad-except - err_msg = "Failed to add platform on {}".format(server_url) + err_msg = f"Failed to add platform on {server_url}" log.error("%s:\n%s", err_msg, exc) return {name: err_msg} platforms = list_platforms(server_url) if name in platforms[server_url]: - return {name: "Successfully added platform on {}".format(server_url)} + return {name: f"Successfully added platform on {server_url}"} else: - return {name: "Failed to add platform on {}".format(server_url)} + return {name: f"Failed to add platform on {server_url}"} diff --git a/salt/runners/bgp.py b/salt/runners/bgp.py index 4603de029af..bee6d4698ea 100644 --- a/salt/runners/bgp.py +++ b/salt/runners/bgp.py @@ -331,9 +331,7 @@ def neighbors(*asns, **kwargs): ) ) if ipnet: - title_parts.append( - "Selecting neighbors within the IP network: {ipnet}".format(ipnet=ipnet) - ) + title_parts.append(f"Selecting neighbors within the IP network: {ipnet}") if kwargs: title_parts.append( "Searching for BGP neighbors having the attributes: {attrmap}".format( diff --git a/salt/runners/cache.py b/salt/runners/cache.py index 88a5c6be0db..89309af690f 100644 --- a/salt/runners/cache.py +++ b/salt/runners/cache.py @@ -327,7 +327,7 @@ def clear_git_lock(role, remote=None, **kwargs): ) git_objects.append(obj) else: - raise SaltInvocationError("Invalid role '{}'".format(role)) + raise SaltInvocationError(f"Invalid role '{role}'") ret = {} for obj in git_objects: diff --git a/salt/runners/ddns.py b/salt/runners/ddns.py index 9e4d5c64971..831f5211627 100644 --- a/salt/runners/ddns.py +++ b/salt/runners/ddns.py @@ -75,7 +75,7 @@ def create( """ if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) @@ -99,9 +99,9 @@ def create( answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: - return {fqdn: "Failed to create record of type '{}'".format(rdtype)} + return {fqdn: f"Failed to create record of type '{rdtype}'"} - return {fqdn: "Created record of type '{}': {} -> {}".format(rdtype, fqdn, data)} + return {fqdn: f"Created record of type '{rdtype}': {fqdn} -> {data}"} def update( @@ -135,7 +135,7 @@ def update( """ if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) if not answer.answer: @@ -166,9 +166,9 @@ def update( answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: - return {fqdn: "Failed to update record of type '{}'".format(rdtype)} + return {fqdn: f"Failed to update record of type '{rdtype}'"} - return {fqdn: "Updated record of type '{}'".format(rdtype)} + return {fqdn: f"Updated record of type '{rdtype}'"} def delete( @@ -194,7 +194,7 @@ def delete( """ if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, (rdtype or "ANY")) answer = dns.query.udp(request, nameserver, timeout, port) @@ -248,7 +248,7 @@ def add_host( res = [] if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" ret = create( zone, @@ -277,13 +277,13 @@ def add_host( zone = "{}.{}".format(".".join(parts), "in-addr.arpa.") name = ".".join(popped) - rev_fqdn = "{}.{}".format(name, zone) + rev_fqdn = f"{name}.{zone}" ret = create( zone, name, ttl, "PTR", - "{}.".format(fqdn), + f"{fqdn}.", keyname, keyfile, nameserver, @@ -317,7 +317,7 @@ def delete_host( res = [] if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, "A") answer = dns.query.udp(request, nameserver, timeout, port) @@ -336,7 +336,7 @@ def delete_host( port=port, keyalgorithm=keyalgorithm, ) - res.append("{} of type 'A'".format(ret[fqdn])) + res.append(f"{ret[fqdn]} of type 'A'") for ip in ips: parts = ip.split(".")[::-1] @@ -350,7 +350,7 @@ def delete_host( popped.append(p) zone = "{}.{}".format(".".join(parts), "in-addr.arpa.") name = ".".join(popped) - rev_fqdn = "{}.{}".format(name, zone) + rev_fqdn = f"{name}.{zone}" ret = delete( zone, name, @@ -359,13 +359,13 @@ def delete_host( nameserver, timeout, "PTR", - "{}.".format(fqdn), + f"{fqdn}.", port, keyalgorithm, ) if "Deleted" in ret[rev_fqdn]: - res.append("{} of type 'PTR'".format(ret[rev_fqdn])) + res.append(f"{ret[rev_fqdn]} of type 'PTR'") return {fqdn: res} res.append(ret[rev_fqdn]) diff --git a/salt/runners/digicertapi.py b/salt/runners/digicertapi.py index 44c8d02f728..a7450d7b8ad 100644 --- a/salt/runners/digicertapi.py +++ b/salt/runners/digicertapi.py @@ -113,7 +113,7 @@ def _paginate(url, topkey, *args, **kwargs): aggregate_ret = ret["dict"][topkey] url = args[0] for p in range(2, numpages): - param_url = url + "?offset={}".format(lim * (p - 1)) + param_url = url + f"?offset={lim * (p - 1)}" next_ret = salt.utils.http.query(param_url, kwargs) aggregate_ret[topkey].extend(next_ret["dict"][topkey]) @@ -132,9 +132,9 @@ def list_domains(container_id=None): salt-run digicert.list_domains """ if container_id: - url = "{}/domain?{}".format(_base_url(), container_id) + url = f"{_base_url()}/domain?{container_id}" else: - url = "{}/domain".format(_base_url()) + url = f"{_base_url()}/domain" orgs = _paginate( url, @@ -161,9 +161,9 @@ def list_requests(status=None): salt-run digicert.list_requests pending """ if status: - url = "{}/request?status={}".format(_base_url(), status) + url = f"{_base_url()}/request?status={status}" else: - url = "{}/request".format(_base_url()) + url = f"{_base_url()}/request" reqs = _paginate( url, @@ -189,7 +189,7 @@ def list_orders(status=None): salt-run digicert.list_orders """ - url = "{}/order/certificate".format(_base_url()) + url = f"{_base_url()}/order/certificate" reqs = _paginate( url, @@ -239,7 +239,7 @@ def get_certificate( if order_id: order_cert = salt.utils.http.query( - "{}/order/certificate/{}".format(_base_url(), order_id), + f"{_base_url()}/order/certificate/{order_id}", method="GET", raise_error=False, decode=True, @@ -373,7 +373,7 @@ def list_organizations(container_id=None, include_validation=True): """ orgs = _paginate( - "{}/organization".format(_base_url()), + f"{_base_url()}/organization", "organizations", method="GET", decode=True, @@ -496,7 +496,7 @@ def order_certificate( encoded_body = salt.utils.json.dumps(body) qdata = salt.utils.http.query( - "{}/order/certificate/ssl".format(_base_url()), + f"{_base_url()}/order/certificate/ssl", method="POST", data=encoded_body, decode=True, @@ -572,7 +572,7 @@ def get_org_details(organization_id): """ qdata = salt.utils.http.query( - "{}/organization/{}".format(_base_url(), organization_id), + f"{_base_url()}/organization/{organization_id}", method="GET", decode=True, decode_type="json", @@ -624,8 +624,8 @@ def gen_csr( if "private_key" not in data: data["private_key"] = gen_key(minion_id, dns_name, password, key_len=key_len) - tmppriv = "{}/priv".format(tmpdir) - tmpcsr = "{}/csr".format(tmpdir) + tmppriv = f"{tmpdir}/priv" + tmpcsr = f"{tmpdir}/csr" with salt.utils.files.fopen(tmppriv, "w") as if_: if_.write(salt.utils.stringutils.to_str(data["private_key"])) @@ -637,9 +637,9 @@ def gen_csr( ) if ou_name: - subject = subject + "/OU={}".format(ou_name) + subject = subject + f"/OU={ou_name}" - subject = subject + "/CN={}".format(dns_name) + subject = subject + f"/CN={dns_name}" cmd = "openssl req -new -{} -key {} -out {} -subj '{}'".format( shatype, tmppriv, tmpcsr, subject @@ -690,7 +690,7 @@ def show_organization(domain): salt-run digicert.show_company example.com """ data = salt.utils.http.query( - "{}/companies/domain/{}".format(_base_url(), domain), + f"{_base_url()}/companies/domain/{domain}", status=True, decode=True, decode_type="json", @@ -713,7 +713,7 @@ def show_csrs(): salt-run digicert.show_csrs """ data = salt.utils.http.query( - "{}/certificaterequests".format(_base_url()), + f"{_base_url()}/certificaterequests", status=True, decode=True, decode_type="json", diff --git a/salt/runners/f5.py b/salt/runners/f5.py index bac50c00cd9..13f33f31a1d 100644 --- a/salt/runners/f5.py +++ b/salt/runners/f5.py @@ -53,7 +53,7 @@ class F5Mgmt: wsdls=["LocalLB.VirtualServer", "LocalLB.Pool"], ) except Exception: # pylint: disable=broad-except - raise Exception("Unable to connect to {}".format(self.lb)) + raise Exception(f"Unable to connect to {self.lb}") return True @@ -123,9 +123,7 @@ class F5Mgmt: profiles=[vs_profile_seq], ) except Exception as e: # pylint: disable=broad-except - raise Exception( - "Unable to create `{}` virtual server\n\n{}".format(name, e) - ) + raise Exception(f"Unable to create `{name}` virtual server\n\n{e}") return True def create_pool(self, name, method="ROUND_ROBIN"): @@ -144,7 +142,7 @@ class F5Mgmt: pool_names=[name], lb_methods=[supported_method], members=[[]] ) except Exception as e: # pylint: disable=broad-except - raise Exception("Unable to create `{}` pool\n\n{}".format(name, e)) + raise Exception(f"Unable to create `{name}` pool\n\n{e}") else: raise Exception("Unsupported method") return True @@ -154,7 +152,7 @@ class F5Mgmt: Add a node to a pool """ if not self.check_pool(pool_name): - raise CommandExecutionError("{} pool does not exists".format(pool_name)) + raise CommandExecutionError(f"{pool_name} pool does not exists") members_seq = self.bigIP.LocalLB.Pool.typefactory.create( "Common.IPPortDefinitionSequence" @@ -173,9 +171,7 @@ class F5Mgmt: pool_names=[pool_name], members=[members_seq] ) except Exception as e: # pylint: disable=broad-except - raise Exception( - "Unable to add `{}` to `{}`\n\n{}".format(name, pool_name, e) - ) + raise Exception(f"Unable to add `{name}` to `{pool_name}`\n\n{e}") return True def check_pool(self, name): @@ -229,7 +225,7 @@ def create_vs(lb, name, ip, port, protocol, profile, pool_name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) F5.create_vs(name, ip, port, protocol, profile, pool_name) @@ -250,7 +246,7 @@ def create_pool(lb, name, method="ROUND_ROBIN"): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) F5.create_pool(name, method) return True @@ -269,7 +265,7 @@ def add_pool_member(lb, name, port, pool_name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) F5.add_pool_member(name, port, pool_name) return True @@ -288,7 +284,7 @@ def check_pool(lb, name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) return F5.check_pool(name) @@ -306,7 +302,7 @@ def check_virtualserver(lb, name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) return F5.check_virtualserver(name) @@ -324,6 +320,6 @@ def check_member_pool(lb, member, pool_name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) return F5.check_member_pool(member, pool_name) diff --git a/salt/runners/jobs.py b/salt/runners/jobs.py index 1d958b87a9b..f1ff0f8b492 100644 --- a/salt/runners/jobs.py +++ b/salt/runners/jobs.py @@ -70,7 +70,7 @@ def active(display_progress=False): for minion, data in active_.items(): if display_progress: __jid_event__.fire_event( - {"message": "Received reply from minion {}".format(minion)}, "progress" + {"message": f"Received reply from minion {minion}"}, "progress" ) if not isinstance(data, list): continue @@ -88,7 +88,7 @@ def active(display_progress=False): returner = _get_returner( (__opts__["ext_job_cache"], __opts__["master_job_cache"]) ) - data = mminion.returners["{}.get_jid".format(returner)](jid) + data = mminion.returners[f"{returner}.get_jid"](jid) if data: for minion in data: if minion not in ret[jid]["Returned"]: @@ -199,12 +199,12 @@ def list_job(jid, ext_source=None, display_progress=False): ) if display_progress: __jid_event__.fire_event( - {"message": "Querying returner: {}".format(returner)}, "progress" + {"message": f"Querying returner: {returner}"}, "progress" ) - job = mminion.returners["{}.get_load".format(returner)](jid) + job = mminion.returners[f"{returner}.get_load"](jid) ret.update(_format_jid_instance(jid, job)) - ret["Result"] = mminion.returners["{}.get_jid".format(returner)](jid) + ret["Result"] = mminion.returners[f"{returner}.get_jid"](jid) fstr = "{}.get_endtime".format(__opts__["master_job_cache"]) if __opts__.get("job_cache_store_endtime") and fstr in mminion.returners: @@ -306,11 +306,11 @@ def list_jobs( ) if display_progress: __jid_event__.fire_event( - {"message": "Querying returner {} for jobs.".format(returner)}, "progress" + {"message": f"Querying returner {returner} for jobs."}, "progress" ) mminion = salt.minion.MasterMinion(__opts__) - ret = mminion.returners["{}.get_jids".format(returner)]() + ret = mminion.returners[f"{returner}.get_jids"]() mret = {} for item in ret: @@ -401,15 +401,13 @@ def list_jobs_filter( ) if display_progress: __jid_event__.fire_event( - {"message": "Querying returner {} for jobs.".format(returner)}, "progress" + {"message": f"Querying returner {returner} for jobs."}, "progress" ) mminion = salt.minion.MasterMinion(__opts__) - fun = "{}.get_jids_filter".format(returner) + fun = f"{returner}.get_jids_filter" if fun not in mminion.returners: - raise NotImplementedError( - "'{}' returner function not implemented yet.".format(fun) - ) + raise NotImplementedError(f"'{fun}' returner function not implemented yet.") ret = mminion.returners[fun](count, filter_find_job) if outputter: @@ -436,7 +434,7 @@ def print_job(jid, ext_source=None): mminion = salt.minion.MasterMinion(__opts__) try: - job = mminion.returners["{}.get_load".format(returner)](jid) + job = mminion.returners[f"{returner}.get_load"](jid) ret[jid] = _format_jid_instance(jid, job) except TypeError: ret[jid]["Result"] = ( @@ -444,7 +442,7 @@ def print_job(jid, ext_source=None): "retrieved. Check master log for details.".format(returner) ) return ret - ret[jid]["Result"] = mminion.returners["{}.get_jid".format(returner)](jid) + ret[jid]["Result"] = mminion.returners[f"{returner}.get_jid"](jid) fstr = "{}.get_endtime".format(__opts__["master_job_cache"]) if __opts__.get("job_cache_store_endtime") and fstr in mminion.returners: @@ -598,7 +596,5 @@ def _walk_through(job_dir, display_progress=False): job = salt.payload.load(rfh) jid = job["jid"] if display_progress: - __jid_event__.fire_event( - {"message": "Found JID {}".format(jid)}, "progress" - ) + __jid_event__.fire_event({"message": f"Found JID {jid}"}, "progress") yield jid, job, t_path, final diff --git a/salt/runners/launchd.py b/salt/runners/launchd.py index 268668a79a1..87184e5c66c 100644 --- a/salt/runners/launchd.py +++ b/salt/runners/launchd.py @@ -48,7 +48,7 @@ def write_launchd_plist(program): supported_programs = ["salt-master", "salt-minion"] if program not in supported_programs: - sys.stderr.write("Supported programs: '{}'\n".format(supported_programs)) + sys.stderr.write(f"Supported programs: '{supported_programs}'\n") sys.exit(-1) return plist_sample_text.format( diff --git a/salt/runners/lxc.py b/salt/runners/lxc.py index f325dcb7b64..c12826f4162 100644 --- a/salt/runners/lxc.py +++ b/salt/runners/lxc.py @@ -40,7 +40,7 @@ def _do(name, fun, path=None): with salt.client.get_local_client(__opts__["conf_file"]) as client: cmd_ret = client.cmd_iter( - host, "lxc.{}".format(fun), [name], kwarg={"path": path}, timeout=60 + host, f"lxc.{fun}", [name], kwarg={"path": path}, timeout=60 ) data = next(cmd_ret) data = data.get(host, {}).get("ret", None) @@ -71,7 +71,7 @@ def _do_names(names, fun, path=None): cmds.append( client.cmd_iter( host, - "lxc.{}".format(fun), + f"lxc.{fun}", [name], kwarg={"path": path}, timeout=60, @@ -247,7 +247,7 @@ def init(names, host=None, saltcloud_mode=False, quiet=False, **kwargs): except (TypeError, KeyError): pass if not alive: - ret["comment"] = "Host {} is not reachable".format(host) + ret["comment"] = f"Host {host} is not reachable" ret["result"] = False return ret @@ -263,7 +263,7 @@ def init(names, host=None, saltcloud_mode=False, quiet=False, **kwargs): host, ) if host not in data: - ret["comment"] = "Host '{}' was not found".format(host) + ret["comment"] = f"Host '{host}' was not found" ret["result"] = False return ret @@ -390,7 +390,7 @@ def init(names, host=None, saltcloud_mode=False, quiet=False, **kwargs): time.sleep(1) if ping: return "OK" - raise Exception("Unresponsive {}".format(mid_)) + raise Exception(f"Unresponsive {mid_}") ping = salt.utils.cloud.wait_for_fun(testping, timeout=21, mid=mid) if ping != "OK": diff --git a/salt/runners/manage.py b/salt/runners/manage.py index 63ee54e4b66..65b3455f53d 100644 --- a/salt/runners/manage.py +++ b/salt/runners/manage.py @@ -537,7 +537,7 @@ def safe_accept(target, tgt_type="glob"): del ret[minion] continue elif minion not in pending: - failures[minion] = "Minion key {} not found by salt-key".format(minion) + failures[minion] = f"Minion key {minion} not found by salt-key" elif pending[minion] != finger: failures[minion] = ( "Minion key {} does not match the key in salt-key: {}".format( @@ -558,9 +558,7 @@ def safe_accept(target, tgt_type="glob"): print(message) print("") - __jid_event__.fire_event( - {"message": "Accepted {:d} keys".format(len(ret))}, "progress" - ) + __jid_event__.fire_event({"message": f"Accepted {len(ret):d} keys"}, "progress") return ret, failures @@ -729,8 +727,8 @@ def bootstrap( client_opts["argv"] = [ "http.query", script, - "backend={}".format(http_backend), - "text_out={}".format(deploy_command), + f"backend={http_backend}", + f"text_out={deploy_command}", ] salt.client.ssh.SSH(client_opts).run() client_opts["argv"] = [ @@ -845,7 +843,7 @@ objShell.Exec("{1}{2}")""" vb_saltexec = "saltinstall.exe" vb_saltexec_args = " /S /minion-name=%COMPUTERNAME%" if master: - vb_saltexec_args += " /master={}".format(master) + vb_saltexec_args += f" /master={master}" # One further thing we need to do; the Windows Salt minion is pretty # self-contained, except for the Microsoft Visual C++ 2008 runtime. diff --git a/salt/runners/mattermost.py b/salt/runners/mattermost.py index bb332de3411..828ff857939 100644 --- a/salt/runners/mattermost.py +++ b/salt/runners/mattermost.py @@ -129,7 +129,7 @@ def post_message(message, channel=None, username=None, api_url=None, hook=None): log.debug("Parameters: %s", parameters) data = salt.utils.json.dumps(parameters) result = salt.utils.mattermost.query( - api_url=api_url, hook=hook, data="payload={}".format(data) + api_url=api_url, hook=hook, data=f"payload={data}" ) if result: @@ -167,7 +167,7 @@ def post_event(event, channel=None, username=None, api_url=None, hook=None): log.debug("Event data: %s", event["data"]) message = "tag: {}\r\n".format(event["tag"]) for key, value in event["data"].items(): - message += "{}: {}\r\n".format(key, value) + message += f"{key}: {value}\r\n" result = post_message( message, channel=channel, username=username, api_url=api_url, hook=hook ) diff --git a/salt/runners/net.py b/salt/runners/net.py index a7865219b62..f330c0ba924 100644 --- a/salt/runners/net.py +++ b/salt/runners/net.py @@ -347,13 +347,13 @@ def interfaces( if not title: title = "Details" if interface: - title += " for interface {}".format(interface) + title += f" for interface {interface}" else: title += " for all interfaces" if device: - title += " on device {}".format(device) + title += f" on device {device}" if ipnet: - title += " that include network {net}".format(net=str(ipnet)) + title += f" that include network {str(ipnet)}" if best: title += " - only best match returned" @@ -511,13 +511,13 @@ def findarp( title = "ARP Entries" if device: - title += " on device {device}".format(device=device) + title += f" on device {device}" if interface: - title += " on interface {interf}".format(interf=interface) + title += f" on interface {interface}" if ip: - title += " for IP {ip}".format(ip=ip) + title += f" for IP {ip}" if mac: - title += " for MAC {mac}".format(mac=mac) + title += f" for MAC {mac}" if device: all_arp = {device: all_arp.get(device)} @@ -615,11 +615,11 @@ def findmac(device=None, mac=None, interface=None, vlan=None, display=_DEFAULT_D title = "MAC Address(es)" if device: - title += " on device {device}".format(device=device) + title += f" on device {device}" if interface: - title += " on interface {interf}".format(interf=interface) + title += f" on interface {interface}" if vlan: - title += " on VLAN {vlan}".format(vlan=vlan) + title += f" on VLAN {vlan}" if device: all_mac = {device: all_mac.get(device)} @@ -752,13 +752,13 @@ def lldp( if not title: title = "LLDP Neighbors" if interface: - title += " for interface {}".format(interface) + title += f" for interface {interface}" else: title += " for all interfaces" if device: - title += " on device {}".format(device) + title += f" on device {device}" if chassis: - title += " having Chassis ID {}".format(chassis) + title += f" having Chassis ID {chassis}" if device: all_lldp = {device: all_lldp.get(device)} diff --git a/salt/runners/network.py b/salt/runners/network.py index 2812bb3a94e..2bf46e80a98 100644 --- a/salt/runners/network.py +++ b/salt/runners/network.py @@ -31,11 +31,11 @@ def wollist(maclist, bcast="255.255.255.255", destport=9): for mac in ifile: mac = salt.utils.stringutils.to_unicode(mac).strip() wol(mac, bcast, destport) - print("Waking up {}".format(mac)) + print(f"Waking up {mac}") ret.append(mac) except Exception as err: # pylint: disable=broad-except __jid_event__.fire_event( - {"error": "Failed to open the MAC file. Error: {}".format(err)}, "progress" + {"error": f"Failed to open the MAC file. Error: {err}"}, "progress" ) return [] return ret diff --git a/salt/runners/pkg.py b/salt/runners/pkg.py index 1987b696920..5abf574d063 100644 --- a/salt/runners/pkg.py +++ b/salt/runners/pkg.py @@ -32,7 +32,7 @@ def list_upgrades(jid, style="group", outputter="nested", ext_source=None): (__opts__["ext_job_cache"], ext_source, __opts__["master_job_cache"]) ) - data = mminion.returners["{}.get_jid".format(returner)](jid) + data = mminion.returners[f"{returner}.get_jid"](jid) pkgs = {} if style == "group": diff --git a/salt/runners/queue.py b/salt/runners/queue.py index 36c77daaa98..d91418355c3 100644 --- a/salt/runners/queue.py +++ b/salt/runners/queue.py @@ -80,9 +80,9 @@ def insert(queue, items, backend="sqlite"): salt-run queue.insert myqueue "['item1', 'item2', 'item3']" backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.insert".format(backend) + cmd = f"{backend}.insert" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](items=items, queue=queue) return ret @@ -100,9 +100,9 @@ def delete(queue, items, backend="sqlite"): salt-run queue.delete myqueue "['item1', 'item2', 'item3']" """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.delete".format(backend) + cmd = f"{backend}.delete" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](items=items, queue=queue) return ret @@ -119,9 +119,9 @@ def list_queues(backend="sqlite"): salt-run queue.list_queues backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.list_queues".format(backend) + cmd = f"{backend}.list_queues" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd]() return ret @@ -138,9 +138,9 @@ def list_length(queue, backend="sqlite"): salt-run queue.list_length myqueue backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.list_length".format(backend) + cmd = f"{backend}.list_length" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](queue=queue) return ret @@ -157,9 +157,9 @@ def list_items(queue, backend="sqlite"): salt-run queue.list_items myqueue backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.list_items".format(backend) + cmd = f"{backend}.list_items" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](queue=queue) return ret @@ -179,9 +179,9 @@ def pop(queue, quantity=1, backend="sqlite", is_runner=False): salt-run queue.pop myqueue all backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.pop".format(backend) + cmd = f"{backend}.pop" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](quantity=quantity, queue=queue, is_runner=is_runner) return ret @@ -211,7 +211,7 @@ def process_queue(queue, quantity=1, backend="sqlite", is_runner=False): queue=queue, quantity=quantity, backend=backend, is_runner=is_runner ) except SaltInvocationError as exc: - error_txt = "{}".format(exc) + error_txt = f"{exc}" __jid_event__.fire_event({"errors": error_txt}, "progress") return False diff --git a/salt/runners/salt.py b/salt/runners/salt.py index 50fac6ab4a7..3ac499ae579 100644 --- a/salt/runners/salt.py +++ b/salt/runners/salt.py @@ -102,7 +102,7 @@ def cmd(fun, *args, **kwargs): return ( functions[fun](*args, **kwargs) if fun in functions - else "'{}' is not available.".format(fun) + else f"'{fun}' is not available." ) @@ -115,7 +115,7 @@ def execute( ret="", jid="", kwarg=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2017.7.0 @@ -159,7 +159,7 @@ def execute( ret=ret, jid=jid, kwarg=kwarg, - **kwargs + **kwargs, ) except SaltClientError as client_error: log.error("Error while executing %s on %s (%s)", fun, tgt, tgt_type) diff --git a/salt/runners/smartos_vmadm.py b/salt/runners/smartos_vmadm.py index 7575fdbaf18..b469f1239e5 100644 --- a/salt/runners/smartos_vmadm.py +++ b/salt/runners/smartos_vmadm.py @@ -100,7 +100,7 @@ def _action(action="get", search=None, one=True, force=False): ## multiple allowed? if one and len(matched_vms) > 1: return { - "Error": "Matched {} vms, only one allowed!".format(len(matched_vms)), + "Error": f"Matched {len(matched_vms)} vms, only one allowed!", "Matches": matched_vms, } @@ -111,7 +111,7 @@ def _action(action="get", search=None, one=True, force=False): vmadm_args = {"key": "uuid", "vm": vm} try: for vmadm_res in client.cmd_iter( - vms[vm]["node"], "vmadm.{}".format(action), kwarg=vmadm_args + vms[vm]["node"], f"vmadm.{action}", kwarg=vmadm_args ): if not vmadm_res: continue @@ -188,7 +188,7 @@ def nodes(verbose=False): else: ret.append(node) except SaltClientError as client_error: - return "{}".format(client_error) + return f"{client_error}" if not verbose: ret.sort() @@ -256,7 +256,7 @@ def list_vms(search=None, verbose=False): else: ret.append(vm) except SaltClientError as client_error: - return "{}".format(client_error) + return f"{client_error}" if not verbose: ret = sorted(ret) diff --git a/salt/runners/spacewalk.py b/salt/runners/spacewalk.py index 69fce4731cd..4936859b16b 100644 --- a/salt/runners/spacewalk.py +++ b/salt/runners/spacewalk.py @@ -71,7 +71,7 @@ def _get_spacewalk_configuration(spacewalk_url=""): return False ret = { - "api_url": "{}://{}/rpc/api".format(protocol, spacewalk_server), + "api_url": f"{protocol}://{spacewalk_server}/rpc/api", "username": username, "password": password, } @@ -120,7 +120,7 @@ def _get_session(server): config = _get_spacewalk_configuration(server) if not config: - raise Exception("No config for '{}' found on master".format(server)) + raise Exception(f"No config for '{server}' found on master") session = _get_client_and_key( config["api_url"], config["username"], config["password"] @@ -163,7 +163,7 @@ def api(server, command, *args, **kwargs): else: arguments = args - call = "{} {}".format(command, arguments) + call = f"{command} {arguments}" try: client, key = _get_session(server) except Exception as exc: # pylint: disable=broad-except @@ -185,7 +185,7 @@ def api(server, command, *args, **kwargs): try: output = endpoint(key, *arguments) except Exception as e: # pylint: disable=broad-except - output = "API call failed: {}".format(e) + output = f"API call failed: {e}" return {call: output} @@ -360,10 +360,8 @@ def unregister(name, server_url): for system in systems_list: out = client.system.deleteSystem(key, system["id"]) if out == 1: - return {name: "Successfully unregistered from {}".format(server_url)} + return {name: f"Successfully unregistered from {server_url}"} else: - return {name: "Failed to unregister from {}".format(server_url)} + return {name: f"Failed to unregister from {server_url}"} else: - return { - name: "System does not exist in spacewalk server ({})".format(server_url) - } + return {name: f"System does not exist in spacewalk server ({server_url})"} diff --git a/salt/runners/test.py b/salt/runners/test.py index 98df7fd4e11..b20e27c847c 100644 --- a/salt/runners/test.py +++ b/salt/runners/test.py @@ -116,9 +116,7 @@ def stream(): """ ret = True for i in range(1, 100): - __jid_event__.fire_event( - {"message": "Runner is {}% done".format(i)}, "progress" - ) + __jid_event__.fire_event({"message": f"Runner is {i}% done"}, "progress") time.sleep(0.1) return ret diff --git a/salt/runners/vault.py b/salt/runners/vault.py index 12225aea361..14aa9ff07b1 100644 --- a/salt/runners/vault.py +++ b/salt/runners/vault.py @@ -216,15 +216,15 @@ def _validate_signature(minion_id, signature, impersonated_by_master): """ pki_dir = __opts__["pki_dir"] if impersonated_by_master: - public_key = "{}/master.pub".format(pki_dir) + public_key = f"{pki_dir}/master.pub" else: - public_key = "{}/minions/{}".format(pki_dir, minion_id) + public_key = f"{pki_dir}/minions/{minion_id}" log.trace("Validating signature for %s", minion_id) signature = base64.b64decode(signature) if not salt.crypt.verify_signature(public_key, minion_id, signature): raise salt.exceptions.AuthenticationError( - "Could not validate token request from {}".format(minion_id) + f"Could not validate token request from {minion_id}" ) log.trace("Signature ok") @@ -354,7 +354,7 @@ def _selftoken_expired(): return False except Exception as e: # pylint: disable=broad-except raise salt.exceptions.CommandExecutionError( - "Error while looking up self token : {}".format(str(e)) + f"Error while looking up self token : {str(e)}" ) diff --git a/salt/runners/venafiapi.py b/salt/runners/venafiapi.py index 23118ee8f7a..e5794f906dd 100644 --- a/salt/runners/venafiapi.py +++ b/salt/runners/venafiapi.py @@ -138,9 +138,7 @@ def request( csr = csr_file.read() request = CertificateRequest(csr=csr, common_name=dns_name) except Exception as e: - raise Exception( - "Unable to open file {file}: {excp}".format(file=csr_path, excp=e) - ) + raise Exception(f"Unable to open file {csr_path}: {e}") conn.request_cert(request, zone) # TODO: add timeout parameter here @@ -160,9 +158,7 @@ def request( with salt.utils.files.fopen(pkey_path) as pkey_file: private_key = pkey_file.read() except Exception as e: - raise Exception( - "Unable to open file {file}: {excp}".format(file=pkey_path, excp=e) - ) + raise Exception(f"Unable to open file {pkey_path}: {e}") else: private_key = None diff --git a/salt/runners/virt.py b/salt/runners/virt.py index 317a7206068..669ded40137 100644 --- a/salt/runners/virt.py +++ b/salt/runners/virt.py @@ -246,7 +246,7 @@ def init( if "vm_info" in data[node]: if name in data[node]["vm_info"]: __jid_event__.fire_event( - {"message": "Virtual machine {} is already deployed".format(name)}, + {"message": f"Virtual machine {name} is already deployed"}, "progress", ) return "fail" @@ -255,9 +255,7 @@ def init( host = _determine_host(data) if host not in data or not host: - __jid_event__.fire_event( - {"message": "Host {} was not found".format(host)}, "progress" - ) + __jid_event__.fire_event({"message": f"Host {host} was not found"}, "progress") return "fail" pub_key = None @@ -272,7 +270,7 @@ def init( with salt.client.get_local_client(__opts__["conf_file"]) as client: __jid_event__.fire_event( - {"message": "Creating VM {} on host {}".format(name, host)}, "progress" + {"message": f"Creating VM {name} on host {host}"}, "progress" ) try: cmd_ret = client.cmd_iter( @@ -304,7 +302,7 @@ def init( ret = next(cmd_ret) if not ret: __jid_event__.fire_event( - {"message": "VM {} was not initialized.".format(name)}, "progress" + {"message": f"VM {name} was not initialized."}, "progress" ) return "fail" for minion_id in ret: @@ -317,7 +315,7 @@ def init( return "fail" __jid_event__.fire_event( - {"message": "VM {} initialized on host {}".format(name, host)}, "progress" + {"message": f"VM {name} initialized on host {host}"}, "progress" ) return "good" @@ -339,7 +337,7 @@ def reset(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"message": "Failed to find VM {} to reset".format(name)}, "progress" + {"message": f"Failed to find VM {name} to reset"}, "progress" ) return "fail" host = next(iter(data.keys())) @@ -347,9 +345,7 @@ def reset(name): cmd_ret = client.cmd_iter(host, "virt.reset", [name], timeout=600) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event( - {"message": "Reset VM {}".format(name)}, "progress" - ) + __jid_event__.fire_event({"message": f"Reset VM {name}"}, "progress") except SaltClientError as client_error: print(client_error) return ret @@ -364,20 +360,20 @@ def start(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"message": "Failed to find VM {} to start".format(name)}, "progress" + {"message": f"Failed to find VM {name} to start"}, "progress" ) return "fail" host = next(iter(data.keys())) if data[host][name]["state"] == "running": - print("VM {} is already running".format(name)) + print(f"VM {name} is already running") return "bad state" try: cmd_ret = client.cmd_iter(host, "virt.start", [name], timeout=600) except SaltClientError as client_error: - return "Virtual machine {} not started: {}".format(name, client_error) + return f"Virtual machine {name} not started: {client_error}" for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event({"message": "Started VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Started VM {name}"}, "progress") return "good" @@ -389,11 +385,11 @@ def force_off(name): with salt.client.get_local_client(__opts__["conf_file"]) as client: data = vm_info(name, quiet=True) if not data: - print("Failed to find VM {} to destroy".format(name)) + print(f"Failed to find VM {name} to destroy") return "fail" host = next(iter(data.keys())) if data[host][name]["state"] == "shutdown": - print("VM {} is already shutdown".format(name)) + print(f"VM {name} is already shutdown") return "bad state" try: cmd_ret = client.cmd_iter(host, "virt.stop", [name], timeout=600) @@ -403,9 +399,7 @@ def force_off(name): ) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event( - {"message": "Powered off VM {}".format(name)}, "progress" - ) + __jid_event__.fire_event({"message": f"Powered off VM {name}"}, "progress") return "good" @@ -418,7 +412,7 @@ def purge(name, delete_key=True): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"error": "Failed to find VM {} to purge".format(name)}, "progress" + {"error": f"Failed to find VM {name} to purge"}, "progress" ) return "fail" host = next(iter(data.keys())) @@ -436,7 +430,7 @@ def purge(name, delete_key=True): log.debug("Deleting key %s", name) with salt.key.Key(__opts__) as skey: skey.delete_key(name) - __jid_event__.fire_event({"message": "Purged VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Purged VM {name}"}, "progress") return "good" @@ -450,13 +444,13 @@ def pause(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"error": "Failed to find VM {} to pause".format(name)}, "progress" + {"error": f"Failed to find VM {name} to pause"}, "progress" ) return "fail" host = next(iter(data.keys())) if data[host][name]["state"] == "paused": __jid_event__.fire_event( - {"error": "VM {} is already paused".format(name)}, "progress" + {"error": f"VM {name} is already paused"}, "progress" ) return "bad state" try: @@ -467,7 +461,7 @@ def pause(name): ) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event({"message": "Paused VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Paused VM {name}"}, "progress") return "good" @@ -480,14 +474,12 @@ def resume(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"error": "Failed to find VM {} to pause".format(name)}, "progress" + {"error": f"Failed to find VM {name} to pause"}, "progress" ) return "not found" host = next(iter(data.keys())) if data[host][name]["state"] != "paused": - __jid_event__.fire_event( - {"error": "VM {} is not paused".format(name)}, "progress" - ) + __jid_event__.fire_event({"error": f"VM {name} is not paused"}, "progress") return "bad state" try: cmd_ret = client.cmd_iter(host, "virt.resume", [name], timeout=600) @@ -497,7 +489,7 @@ def resume(name): ) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event({"message": "Resumed VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Resumed VM {name}"}, "progress") return "good" @@ -513,14 +505,14 @@ def migrate(name, target=""): origin_host = next(iter(origin_data)) except StopIteration: __jid_event__.fire_event( - {"error": "Named VM {} was not found to migrate".format(name)}, + {"error": f"Named VM {name} was not found to migrate"}, "progress", ) return "" disks = origin_data[origin_host][name]["disks"] if not origin_data: __jid_event__.fire_event( - {"error": "Named VM {} was not found to migrate".format(name)}, + {"error": f"Named VM {name} was not found to migrate"}, "progress", ) return "" @@ -528,7 +520,7 @@ def migrate(name, target=""): target = _determine_host(data, origin_host) if target not in data: __jid_event__.fire_event( - {"error": "Target host {} not found".format(origin_data)}, "progress" + {"error": f"Target host {origin_data} not found"}, "progress" ) return "" try: diff --git a/salt/runners/vistara.py b/salt/runners/vistara.py index ea2d708e354..bd594764919 100644 --- a/salt/runners/vistara.py +++ b/salt/runners/vistara.py @@ -94,7 +94,7 @@ def delete_device(name, safety_on=True): if not access_token: return "Vistara access token not available" - query_string = "dnsName:{}".format(name) + query_string = f"dnsName:{name}" devices = _search_devices(query_string, config["client_id"], access_token) @@ -123,7 +123,7 @@ def delete_device(name, safety_on=True): def _search_devices(query_string, client_id, access_token): - authstring = "Bearer {}".format(access_token) + authstring = f"Bearer {access_token}" headers = { "Authorization": authstring, @@ -134,7 +134,7 @@ def _search_devices(query_string, client_id, access_token): params = {"queryString": query_string} method = "GET" - url = "https://api.vistara.io/api/v2/tenants/{}/devices/search".format(client_id) + url = f"https://api.vistara.io/api/v2/tenants/{client_id}/devices/search" resp = salt.utils.http.query( url=url, method=method, header_dict=headers, params=params, opts=__opts__ @@ -152,7 +152,7 @@ def _search_devices(query_string, client_id, access_token): def _delete_resource(device_id, client_id, access_token): - authstring = "Bearer {}".format(access_token) + authstring = f"Bearer {access_token}" headers = { "Authorization": authstring, diff --git a/salt/runners/winrepo.py b/salt/runners/winrepo.py index 9e31040884c..856115d6642 100644 --- a/salt/runners/winrepo.py +++ b/salt/runners/winrepo.py @@ -241,7 +241,7 @@ def update_git_repos(opts=None, clean=False, masterless=False): winrepo.clear_old_remotes() winrepo.checkout() except Exception as exc: # pylint: disable=broad-except - msg = "Failed to update winrepo_remotes: {}".format(exc) + msg = f"Failed to update winrepo_remotes: {exc}" log.error(msg, exc_info_on_loglevel=logging.DEBUG) return msg ret.update(winrepo.winrepo_dirs) diff --git a/salt/scripts.py b/salt/scripts.py index dd3af6247fc..662104a7142 100644 --- a/salt/scripts.py +++ b/salt/scripts.py @@ -412,7 +412,7 @@ def salt_key(): _install_signal_handlers(client) client.run() except Exception as err: # pylint: disable=broad-except - sys.stderr.write("Error: {}\n".format(err)) + sys.stderr.write(f"Error: {err}\n") def salt_cp(): @@ -568,7 +568,7 @@ def salt_unity(): if len(sys.argv) < 2: msg = "Must pass in a salt command, available commands are:" for cmd in avail: - msg += "\n{}".format(cmd) + msg += f"\n{cmd}" print(msg) sys.exit(1) cmd = sys.argv[1] @@ -577,9 +577,9 @@ def salt_unity(): sys.argv[0] = "salt" s_fun = salt_main else: - sys.argv[0] = "salt-{}".format(cmd) + sys.argv[0] = f"salt-{cmd}" sys.argv.pop(1) - s_fun = getattr(sys.modules[__name__], "salt_{}".format(cmd)) + s_fun = getattr(sys.modules[__name__], f"salt_{cmd}") s_fun() diff --git a/salt/sdb/sqlite3.py b/salt/sdb/sqlite3.py index 28419060789..3aba762fe78 100644 --- a/salt/sdb/sqlite3.py +++ b/salt/sdb/sqlite3.py @@ -106,8 +106,8 @@ def _connect(profile): for sql in stmts: cur.execute(sql) elif profile.get("create_table", True): - cur.execute("CREATE TABLE {} (key text, value blob)".format(table)) - cur.execute("CREATE UNIQUE INDEX {} ON {} (key)".format(idx, table)) + cur.execute(f"CREATE TABLE {table} (key text, value blob)") + cur.execute(f"CREATE UNIQUE INDEX {idx} ON {table} (key)") except sqlite3.OperationalError: pass @@ -124,7 +124,7 @@ def set_(key, value, profile=None): value = memoryview(salt.utils.msgpack.packb(value)) q = profile.get( "set_query", - "INSERT OR REPLACE INTO {} VALUES (:key, :value)".format(table), + f"INSERT OR REPLACE INTO {table} VALUES (:key, :value)", ) conn.execute(q, {"key": key, "value": value}) conn.commit() @@ -138,7 +138,7 @@ def get(key, profile=None): if not profile: return None _, cur, table = _connect(profile) - q = profile.get("get_query", "SELECT value FROM {} WHERE key=:key".format(table)) + q = profile.get("get_query", f"SELECT value FROM {table} WHERE key=:key") res = cur.execute(q, {"key": key}) res = res.fetchone() if not res: diff --git a/salt/sdb/vault.py b/salt/sdb/vault.py index 6e99e267a45..ffc0949dbcb 100644 --- a/salt/sdb/vault.py +++ b/salt/sdb/vault.py @@ -64,7 +64,7 @@ def set_(key, value, profile=None): data = {"data": data} try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("POST", url, json=data) if response.status_code != 204: @@ -89,12 +89,12 @@ def get(key, profile=None): path = version2["data"] try: - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("GET", url) if response.status_code == 404: if version2["v2"]: path = version2["data"] + "/" + key - url = "v1/{}".format(path) + url = f"v1/{path}" response = __utils__["vault.make_request"]("GET", url) if response.status_code == 404: return None diff --git a/salt/serializers/configparser.py b/salt/serializers/configparser.py index cb9c820758c..96fdbcde282 100644 --- a/salt/serializers/configparser.py +++ b/salt/serializers/configparser.py @@ -54,7 +54,7 @@ def serialize(obj, **options): try: if not isinstance(obj, dict): raise TypeError( - "configparser can only serialize dictionaries, not {}".format(type(obj)) + f"configparser can only serialize dictionaries, not {type(obj)}" ) fp = options.pop("fp", None) cp = configparser.ConfigParser(**options) diff --git a/salt/serializers/yamlex.py b/salt/serializers/yamlex.py index ec77d2c7333..c1f68f1c07a 100644 --- a/salt/serializers/yamlex.py +++ b/salt/serializers/yamlex.py @@ -209,7 +209,7 @@ class Loader(BaseLoader): # pylint: disable=W0232 raise ConstructorError( None, None, - "expected a mapping node, but found {}".format(node.id), + f"expected a mapping node, but found {node.id}", node.start_mark, ) diff --git a/salt/spm/__init__.py b/salt/spm/__init__.py index 6738d108a6f..34649f6d087 100644 --- a/salt/spm/__init__.py +++ b/salt/spm/__init__.py @@ -136,7 +136,7 @@ class SPMClient: elif command == "close": self._close() else: - raise SPMInvocationError("Invalid command '{}'".format(command)) + raise SPMInvocationError(f"Invalid command '{command}'") except SPMException as exc: self.ui.error(str(exc)) @@ -144,7 +144,7 @@ class SPMClient: try: return getattr(getattr(self.pkgdb, self.db_prov), func)(*args, **kwargs) except AttributeError: - return self.pkgdb["{}.{}".format(self.db_prov, func)](*args, **kwargs) + return self.pkgdb[f"{self.db_prov}.{func}"](*args, **kwargs) def _pkgfiles_fun(self, func, *args, **kwargs): try: @@ -152,7 +152,7 @@ class SPMClient: *args, **kwargs ) except AttributeError: - return self.pkgfiles["{}.{}".format(self.files_prov, func)](*args, **kwargs) + return self.pkgfiles[f"{self.files_prov}.{func}"](*args, **kwargs) def _list(self, args): """ @@ -167,7 +167,7 @@ class SPMClient: elif command == "repos": self._repo_list(args) else: - raise SPMInvocationError("Invalid list command '{}'".format(command)) + raise SPMInvocationError(f"Invalid list command '{command}'") def _local(self, args): """ @@ -182,7 +182,7 @@ class SPMClient: elif command == "info": self._local_info(args) else: - raise SPMInvocationError("Invalid local command '{}'".format(command)) + raise SPMInvocationError(f"Invalid local command '{command}'") def _repo(self, args): """ @@ -201,7 +201,7 @@ class SPMClient: elif command == "create": self._create_repo(args) else: - raise SPMInvocationError("Invalid repo command '{}'".format(command)) + raise SPMInvocationError(f"Invalid repo command '{command}'") def _repo_packages(self, args, search=False): """ @@ -216,7 +216,7 @@ class SPMClient: release = repo_metadata[repo]["packages"][pkg]["info"]["release"] packages.append((pkg, version, release, repo)) for pkg in sorted(packages): - self.ui.status("{}\t{}-{}\t{}".format(pkg[0], pkg[1], pkg[2], pkg[3])) + self.ui.status(f"{pkg[0]}\t{pkg[1]}-{pkg[2]}\t{pkg[3]}") return packages def _repo_list(self, args): @@ -255,7 +255,7 @@ class SPMClient: pkg_name = comps[-1] formula_tar = tarfile.open(pkg, "r:bz2") - formula_ref = formula_tar.extractfile("{}/FORMULA".format(pkg_name)) + formula_ref = formula_tar.extractfile(f"{pkg_name}/FORMULA") formula_def = salt.utils.yaml.safe_load(formula_ref) file_map[pkg_name] = pkg @@ -267,7 +267,7 @@ class SPMClient: recommended.extend(re_) formula_tar.close() else: - raise SPMInvocationError("Package file {} not found".format(pkg)) + raise SPMInvocationError(f"Package file {pkg} not found") else: to_, op_, re_ = self._check_all_deps(pkg_name=pkg) to_install.extend(to_) @@ -385,7 +385,7 @@ class SPMClient: Starting with one package, check all packages for dependencies """ if pkg_file and not os.path.exists(pkg_file): - raise SPMInvocationError("Package file {} not found".format(pkg_file)) + raise SPMInvocationError(f"Package file {pkg_file} not found") self.repo_metadata = self._get_repo_metadata() if not formula_def: @@ -396,7 +396,7 @@ class SPMClient: formula_def = self.repo_metadata[repo]["packages"][pkg_name]["info"] if not formula_def: - raise SPMInvocationError("Unable to read formula for {}".format(pkg_name)) + raise SPMInvocationError(f"Unable to read formula for {pkg_name}") # Check to see if the package is already installed pkg_info = self._pkgdb_fun("info", pkg_name, self.db_conn) @@ -439,7 +439,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", formula_def["name"]) msg = dep_pkg if isinstance(pkg_info, dict): - msg = "{} [Installed]".format(dep_pkg) + msg = f"{dep_pkg} [Installed]" optional_install.append(msg) if recommended: @@ -448,7 +448,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", formula_def["name"]) msg = dep_pkg if isinstance(pkg_info, dict): - msg = "{} [Installed]".format(dep_pkg) + msg = f"{dep_pkg} [Installed]" recommended_install.append(msg) if needs: @@ -457,7 +457,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", formula_def["name"]) msg = dep_pkg if isinstance(pkg_info, dict): - msg = "{} [Installed]".format(dep_pkg) + msg = f"{dep_pkg} [Installed]" return pkgs_to_install, optional_install, recommended_install @@ -465,16 +465,14 @@ class SPMClient: """ Install one individual package """ - self.ui.status("... installing {}".format(pkg_name)) + self.ui.status(f"... installing {pkg_name}") formula_tar = tarfile.open(pkg_file, "r:bz2") - formula_ref = formula_tar.extractfile("{}/FORMULA".format(pkg_name)) + formula_ref = formula_tar.extractfile(f"{pkg_name}/FORMULA") formula_def = salt.utils.yaml.safe_load(formula_ref) for field in ("version", "release", "summary", "description"): if field not in formula_def: - raise SPMPackageError( - "Invalid package: the {} was not found".format(field) - ) + raise SPMPackageError(f"Invalid package: the {field} was not found") pkg_files = formula_tar.getmembers() @@ -542,7 +540,7 @@ class SPMClient: digest = "" else: self._verbose( - "Installing file {} to {}".format(member.name, out_path), + f"Installing file {member.name} to {out_path}", log.trace, ) file_hash = hashlib.sha1() @@ -580,7 +578,7 @@ class SPMClient: Return a list of packages which need to be installed, to resolve all dependencies """ - pkg_info = self.pkgdb["{}.info".format(self.db_prov)](formula_def["name"]) + pkg_info = self.pkgdb[f"{self.db_prov}.info"](formula_def["name"]) if not isinstance(pkg_info, dict): pkg_info = {} @@ -592,7 +590,7 @@ class SPMClient: dep = dep.strip() if not dep: continue - if self.pkgdb["{}.info".format(self.db_prov)](dep): + if self.pkgdb[f"{self.db_prov}.info"](dep): continue if dep in self.avail_pkgs: @@ -757,13 +755,13 @@ class SPMClient: for spm_file in filenames: if not spm_file.endswith(".spm"): continue - spm_path = "{}/{}".format(repo_path, spm_file) + spm_path = f"{repo_path}/{spm_file}" if not tarfile.is_tarfile(spm_path): continue comps = spm_file.split("-") spm_name = "-".join(comps[:-2]) spm_fh = tarfile.open(spm_path, "r:bz2") - formula_handle = spm_fh.extractfile("{}/FORMULA".format(spm_name)) + formula_handle = spm_fh.extractfile(f"{spm_name}/FORMULA") formula_conf = salt.utils.yaml.safe_load(formula_handle.read()) use_formula = True @@ -815,7 +813,7 @@ class SPMClient: } repo_metadata[spm_name]["filename"] = spm_file - metadata_filename = "{}/SPM-METADATA".format(repo_path) + metadata_filename = f"{repo_path}/SPM-METADATA" with salt.utils.files.fopen(metadata_filename, "w") as mfh: salt.utils.yaml.safe_dump( repo_metadata, @@ -868,7 +866,7 @@ class SPMClient: self.ui.confirm(msg) for package in packages: - self.ui.status("... removing {}".format(package)) + self.ui.status(f"... removing {package}") if not self._pkgdb_fun("db_exists", self.opts["spm_db"]): raise SPMDatabaseError( @@ -880,7 +878,7 @@ class SPMClient: # Look at local repo index pkg_info = self._pkgdb_fun("info", package, self.db_conn) if pkg_info is None: - raise SPMInvocationError("Package {} not installed".format(package)) + raise SPMInvocationError(f"Package {package} not installed") # Find files that have not changed and remove them files = self._pkgdb_fun("list_files", package, self.db_conn) @@ -894,22 +892,22 @@ class SPMClient: "hash_file", filerow[0], file_hash, self.files_conn ) if filerow[1] == digest: - self._verbose("Removing file {}".format(filerow[0]), log.trace) + self._verbose(f"Removing file {filerow[0]}", log.trace) self._pkgfiles_fun("remove_file", filerow[0], self.files_conn) else: - self._verbose("Not removing file {}".format(filerow[0]), log.trace) + self._verbose(f"Not removing file {filerow[0]}", log.trace) self._pkgdb_fun("unregister_file", filerow[0], package, self.db_conn) # Clean up directories for dir_ in sorted(dirs, reverse=True): self._pkgdb_fun("unregister_file", dir_, package, self.db_conn) try: - self._verbose("Removing directory {}".format(dir_), log.trace) + self._verbose(f"Removing directory {dir_}", log.trace) os.rmdir(dir_) except OSError: # Leave directories in place that still have files in them self._verbose( - "Cannot remove directory {}, probably not empty".format(dir_), + f"Cannot remove directory {dir_}, probably not empty", log.trace, ) @@ -933,14 +931,14 @@ class SPMClient: pkg_file = args[1] if not os.path.exists(pkg_file): - raise SPMInvocationError("Package file {} not found".format(pkg_file)) + raise SPMInvocationError(f"Package file {pkg_file} not found") comps = pkg_file.split("-") comps = "-".join(comps[:-2]).split("/") name = comps[-1] formula_tar = tarfile.open(pkg_file, "r:bz2") - formula_ref = formula_tar.extractfile("{}/FORMULA".format(name)) + formula_ref = formula_tar.extractfile(f"{name}/FORMULA") formula_def = salt.utils.yaml.safe_load(formula_ref) self.ui.status(self._get_info(formula_def)) @@ -957,7 +955,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", package, self.db_conn) if pkg_info is None: - raise SPMPackageError("package {} not installed".format(package)) + raise SPMPackageError(f"package {package} not installed") self.ui.status(self._get_info(pkg_info)) def _get_info(self, formula_def): @@ -1007,7 +1005,7 @@ class SPMClient: pkg_file = args[1] if not os.path.exists(pkg_file): - raise SPMPackageError("Package file {} not found".format(pkg_file)) + raise SPMPackageError(f"Package file {pkg_file} not found") formula_tar = tarfile.open(pkg_file, "r:bz2") pkg_files = formula_tar.getmembers() @@ -1037,7 +1035,7 @@ class SPMClient: files = self._pkgdb_fun("list_files", package, self.db_conn) if files is None: - raise SPMPackageError("package {} not installed".format(package)) + raise SPMPackageError(f"package {package} not installed") else: for file_ in files: if self.opts["verbose"]: @@ -1057,17 +1055,15 @@ class SPMClient: comps = self.abspath.split("/") self.relpath = comps[-1] - formula_path = "{}/FORMULA".format(self.abspath) + formula_path = f"{self.abspath}/FORMULA" if not os.path.exists(formula_path): - raise SPMPackageError("Formula file {} not found".format(formula_path)) + raise SPMPackageError(f"Formula file {formula_path} not found") with salt.utils.files.fopen(formula_path) as fp_: formula_conf = salt.utils.yaml.safe_load(fp_) for field in ("name", "version", "release", "summary", "description"): if field not in formula_conf: - raise SPMPackageError( - "Invalid package: a {} must be defined".format(field) - ) + raise SPMPackageError(f"Invalid package: a {field} must be defined") out_path = "{}/{}-{}-{}.spm".format( self.opts["spm_build_dir"], @@ -1094,8 +1090,8 @@ class SPMClient: formula_tar.addfile(formula_dir) for file_ in formula_conf["files"]: for ftype in FILE_TYPES: - if file_.startswith("{}|".format(ftype)): - file_ = file_.lstrip("{}|".format(ftype)) + if file_.startswith(f"{ftype}|"): + file_ = file_.lstrip(f"{ftype}|") formula_tar.add( os.path.join(os.getcwd(), file_), os.path.join(formula_conf["name"], file_), @@ -1118,7 +1114,7 @@ class SPMClient: ) formula_tar.close() - self.ui.status("Built package {}".format(out_path)) + self.ui.status(f"Built package {out_path}") def _exclude(self, member): """ @@ -1130,7 +1126,7 @@ class SPMClient: for item in self.opts["spm_build_exclude"]: if member.name.startswith("{}/{}".format(self.formula_conf["name"], item)): return None - elif member.name.startswith("{}/{}".format(self.abspath, item)): + elif member.name.startswith(f"{self.abspath}/{item}"): return None return member @@ -1152,7 +1148,7 @@ class SPMClient: blacklist, whitelist, input_data=data, - **template_vars + **template_vars, ) diff --git a/salt/spm/pkgdb/sqlite3.py b/salt/spm/pkgdb/sqlite3.py index 7d1634c3b76..c6c0fb1384f 100644 --- a/salt/spm/pkgdb/sqlite3.py +++ b/salt/spm/pkgdb/sqlite3.py @@ -193,7 +193,7 @@ def register_file(name, member, path, digest="", conn=None): "INSERT INTO files VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ( name, - "{}/{}".format(path, member.path), + f"{path}/{member.path}", member.size, member.mode, digest, diff --git a/salt/spm/pkgfiles/local.py b/salt/spm/pkgfiles/local.py index 6eab896bf68..2b826a5d393 100644 --- a/salt/spm/pkgfiles/local.py +++ b/salt/spm/pkgfiles/local.py @@ -56,11 +56,11 @@ def check_existing(package, pkg_files, formula_def, conn=None): continue tld = formula_def.get("top_level_dir", package) - new_name = member.name.replace("{}/".format(package), "") + new_name = member.name.replace(f"{package}/", "") if not new_name.startswith(tld): continue - if member.name.startswith("{}/_".format(package)): + if member.name.startswith(f"{package}/_"): if node_type in ("master", "minion"): # Module files are distributed via extmods directory out_file = os.path.join( @@ -72,9 +72,9 @@ def check_existing(package, pkg_files, formula_def, conn=None): else: # Module files are distributed via _modules, _states, etc out_file = os.path.join(conn["formula_path"], new_name) - elif member.name == "{}/pillar.example".format(package): + elif member.name == f"{package}/pillar.example": # Pillars are automatically put in the pillar_path - new_name = "{}.sls.orig".format(package) + new_name = f"{package}.sls.orig" out_file = os.path.join(conn["pillar_path"], new_name) elif package.endswith("-conf"): # Configuration files go into /etc/salt/ @@ -108,7 +108,7 @@ def install_file(package, formula_tar, member, formula_def, conn=None): out_path = conn["formula_path"] tld = formula_def.get("top_level_dir", package) - new_name = member.name.replace("{}/".format(package), "", 1) + new_name = member.name.replace(f"{package}/", "", 1) if ( not new_name.startswith(tld) and not new_name.startswith("_") @@ -121,7 +121,7 @@ def install_file(package, formula_tar, member, formula_def, conn=None): for line in formula_def.get("files", []): tag = "" for ftype in FILE_TYPES: - if line.startswith("{}|".format(ftype)): + if line.startswith(f"{ftype}|"): tag = line.split("|", 1)[0] line = line.split("|", 1)[1] if tag and new_name == line: @@ -130,10 +130,10 @@ def install_file(package, formula_tar, member, formula_def, conn=None): elif tag in ("s", "m"): pass - if member.name.startswith("{}{}_".format(package, os.sep)): + if member.name.startswith(f"{package}{os.sep}_"): if node_type in ("master", "minion"): # Module files are distributed via extmods directory - member.name = new_name.replace("{}{}_".format(package, os.sep), "") + member.name = new_name.replace(f"{package}{os.sep}_", "") out_path = os.path.join( salt.syspaths.CACHE_DIR, node_type, @@ -141,14 +141,14 @@ def install_file(package, formula_tar, member, formula_def, conn=None): ) else: # Module files are distributed via _modules, _states, etc - member.name = new_name.replace("{}{}".format(package, os.sep), "") - elif member.name == "{}/pillar.example".format(package): + member.name = new_name.replace(f"{package}{os.sep}", "") + elif member.name == f"{package}/pillar.example": # Pillars are automatically put in the pillar_path - member.name = "{}.sls.orig".format(package) + member.name = f"{package}.sls.orig" out_path = conn["pillar_path"] elif package.endswith("-conf"): # Configuration files go into /etc/salt/ - member.name = member.name.replace("{}/".format(package), "") + member.name = member.name.replace(f"{package}/", "") out_path = salt.syspaths.CONFIG_DIR elif package.endswith("-reactor"): # Reactor files go into /srv/reactor/ diff --git a/salt/state.py b/salt/state.py index 08198e7f54f..250b46da4f4 100644 --- a/salt/state.py +++ b/salt/state.py @@ -156,8 +156,8 @@ def _clean_tag(tag): def _l_tag(name, id_): low = { - "name": "listen_{}".format(name), - "__id__": "listen_{}".format(id_), + "name": f"listen_{name}", + "__id__": f"listen_{id_}", "state": "Listen_Error", "fun": "Listen_Error", } @@ -1094,7 +1094,7 @@ class State: return ret elif isinstance(entry, dict): if "fun" not in entry: - ret["comment"] = "no `fun` argument in onlyif: {}".format(entry) + ret["comment"] = f"no `fun` argument in onlyif: {entry}" log.warning(ret["comment"]) return ret @@ -1172,7 +1172,7 @@ class State: return ret elif isinstance(entry, dict): if "fun" not in entry: - ret["comment"] = "no `fun` argument in unless: {}".format(entry) + ret["comment"] = f"no `fun` argument in unless: {entry}" log.warning(ret["comment"]) return ret @@ -1428,9 +1428,9 @@ class State: ) reason = self.states.missing_fun_string(full) if reason: - errors.append("Reason: {}".format(reason)) + errors.append(f"Reason: {reason}") else: - errors.append("Specified state '{}' was not found".format(full)) + errors.append(f"Specified state '{full}' was not found") else: # First verify that the parameters are met aspec = salt.utils.args.get_function_argspec(self.states[full]) @@ -2163,7 +2163,7 @@ class State: "result": False, "name": name, "changes": {}, - "comment": "An exception occurred in this state: {}".format(trb), + "comment": f"An exception occurred in this state: {trb}", } utc_finish_time = datetime.datetime.utcnow() @@ -2269,7 +2269,7 @@ class State: proc = salt.utils.process.Process( target=self._call_parallel_target, args=(instance, self._init_kwargs, name, cdata, low), - name="ParallelState({})".format(name), + name=f"ParallelState({name})", ) proc.start() ret = { @@ -2305,7 +2305,7 @@ class State: "comment": "", } for err in errors: - ret["comment"] += "{}\n".format(err) + ret["comment"] += f"{err}\n" ret["__run_num__"] = self.__run_num self.__run_num += 1 format_log(ret) @@ -2452,7 +2452,7 @@ class State: "result": False, "name": name, "changes": {}, - "comment": "An exception occurred in this state: {}".format(trb), + "comment": f"An exception occurred in this state: {trb}", } finally: if low.get("__prereq__"): @@ -3466,7 +3466,7 @@ class State: lkey, lval ) ), - "name": "listen_{}:{}".format(lkey, lval), + "name": f"listen_{lkey}:{lval}", "result": False, "changes": {}, } @@ -3581,9 +3581,7 @@ class State: return high, errors if not isinstance(high, dict): - errors.append( - "Template {} does not render to a dictionary".format(template) - ) + errors.append(f"Template {template} does not render to a dictionary") return high, errors invalid_items = ("include", "exclude", "extends") @@ -3968,10 +3966,10 @@ class BaseHighState: """ merging_strategy = self.opts["top_file_merging_strategy"] try: - merge_attr = "_merge_tops_{}".format(merging_strategy) + merge_attr = f"_merge_tops_{merging_strategy}" merge_func = getattr(self, merge_attr) if not hasattr(merge_func, "__call__"): - msg = "'{}' is not callable".format(merge_attr) + msg = f"'{merge_attr}' is not callable" log.error(msg) raise TypeError(msg) except (AttributeError, TypeError): @@ -4299,7 +4297,7 @@ class BaseHighState: fn_ = sls if not os.path.isfile(fn_): errors.append( - "Specified SLS {} on local filesystem cannot be found.".format(sls) + f"Specified SLS {sls} on local filesystem cannot be found." ) state = None if not fn_: @@ -4322,25 +4320,25 @@ class BaseHighState: context=context, ) except SaltRenderError as exc: - msg = "Rendering SLS '{}:{}' failed: {}".format(saltenv, sls, exc) + msg = f"Rendering SLS '{saltenv}:{sls}' failed: {exc}" log.critical(msg) errors.append(msg) except Exception as exc: # pylint: disable=broad-except - msg = "Rendering SLS {} failed, render error: {}".format(sls, exc) + msg = f"Rendering SLS {sls} failed, render error: {exc}" log.critical( msg, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) - errors.append("{}\n{}".format(msg, traceback.format_exc())) + errors.append(f"{msg}\n{traceback.format_exc()}") try: - mods.add("{}:{}".format(saltenv, sls)) + mods.add(f"{saltenv}:{sls}") except AttributeError: pass if state: if not isinstance(state, dict): - errors.append("SLS {} does not render to a dictionary".format(sls)) + errors.append(f"SLS {sls} does not render to a dictionary") else: include = [] if "include" in state: @@ -4443,7 +4441,7 @@ class BaseHighState: r_env = ( resolved_envs[0] if len(resolved_envs) == 1 else saltenv ) - mod_tgt = "{}:{}".format(r_env, sls_target) + mod_tgt = f"{r_env}:{sls_target}" if mod_tgt not in mods: nstate, err = self.render_state( sls_target, @@ -4545,7 +4543,7 @@ class BaseHighState: comps[0]: [comps[1]], } continue - errors.append("ID {} in SLS {} is not a dictionary".format(name, sls)) + errors.append(f"ID {name} in SLS {sls} is not a dictionary") continue skeys = set() for key in list(state[name]): @@ -4589,9 +4587,7 @@ class BaseHighState: if "extend" in state: ext = state.pop("extend") if not isinstance(ext, dict): - errors.append( - "Extension value in SLS '{}' is not a dictionary".format(sls) - ) + errors.append(f"Extension value in SLS '{sls}' is not a dictionary") return for name in ext: if not isinstance(ext[name], dict): @@ -4658,7 +4654,7 @@ class BaseHighState: statefiles = [sls_match] for sls in statefiles: - r_env = "{}:{}".format(saltenv, sls) + r_env = f"{saltenv}:{sls}" if r_env in mods: continue state, errors = self.render_state( @@ -4669,7 +4665,7 @@ class BaseHighState: for i, error in enumerate(errors[:]): if "is not available" in error: # match SLS foobar in environment - this_sls = "SLS {} in saltenv".format(sls_match) + this_sls = f"SLS {sls_match} in saltenv" if this_sls in error: errors[i] = ( "No matching sls found for '{}' in env '{}'".format( @@ -4714,7 +4710,7 @@ class BaseHighState: try: highstate.update(state) except ValueError: - errors.append("Error when rendering state with contents: {}".format(state)) + errors.append(f"Error when rendering state with contents: {state}") def _check_pillar(self, force=False): """ @@ -4767,7 +4763,7 @@ class BaseHighState: "__run_num__": 0, } } - cfn = os.path.join(self.opts["cachedir"], "{}.cache.p".format(cache_name)) + cfn = os.path.join(self.opts["cachedir"], f"{cache_name}.cache.p") if cache: if os.path.isfile(cfn): diff --git a/salt/states/acme.py b/salt/states/acme.py index 6cd9e165f6c..ae5a7a8399c 100644 --- a/salt/states/acme.py +++ b/salt/states/acme.py @@ -109,15 +109,13 @@ def cert( else: ret["result"] = True ret["comment"].append( - "Certificate {} exists and does not need renewal.".format(certname) + f"Certificate {certname} exists and does not need renewal." ) if action: if __opts__["test"]: ret["result"] = None - ret["comment"].append( - "Certificate {} would have been {}ed.".format(certname, action) - ) + ret["comment"].append(f"Certificate {certname} would have been {action}ed.") ret["changes"] = {"old": "current certificate", "new": "new certificate"} else: res = __salt__["acme.cert"]( diff --git a/salt/states/alias.py b/salt/states/alias.py index 6c2eb8959e1..48b153b5f6e 100644 --- a/salt/states/alias.py +++ b/salt/states/alias.py @@ -43,20 +43,20 @@ def present(name, target): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if __salt__["aliases.has_target"](name, target): ret["result"] = True - ret["comment"] = "Alias {} already present".format(name) + ret["comment"] = f"Alias {name} already present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Alias {} -> {} is set to be added".format(name, target) + ret["comment"] = f"Alias {name} -> {target} is set to be added" return ret if __salt__["aliases.set_target"](name, target): ret["changes"] = {"alias": name} ret["result"] = True - ret["comment"] = "Set email alias {} -> {}".format(name, target) + ret["comment"] = f"Set email alias {name} -> {target}" return ret else: ret["result"] = False - ret["comment"] = "Failed to set alias {} -> {}".format(name, target) + ret["comment"] = f"Failed to set alias {name} -> {target}" return ret @@ -70,18 +70,18 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["aliases.get_target"](name): ret["result"] = True - ret["comment"] = "Alias {} already absent".format(name) + ret["comment"] = f"Alias {name} already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Alias {} is set to be removed".format(name) + ret["comment"] = f"Alias {name} is set to be removed" return ret if __salt__["aliases.rm_alias"](name): ret["changes"] = {"alias": name} ret["result"] = True - ret["comment"] = "Removed alias {}".format(name) + ret["comment"] = f"Removed alias {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to remove alias {}".format(name) + ret["comment"] = f"Failed to remove alias {name}" return ret diff --git a/salt/states/alternatives.py b/salt/states/alternatives.py index de4e119c529..2f89516acbc 100644 --- a/salt/states/alternatives.py +++ b/salt/states/alternatives.py @@ -105,7 +105,7 @@ def install(name, link, path, priority): } else: ret["result"] = False - ret["comment"] = "Alternative for {} not installed: {}".format(name, out) + ret["comment"] = f"Alternative for {name} not installed: {out}" return ret @@ -128,7 +128,7 @@ def remove(name, path): isinstalled = __salt__["alternatives.check_exists"](name, path) if isinstalled: if __opts__["test"]: - ret["comment"] = "Alternative for {} will be removed".format(name) + ret["comment"] = f"Alternative for {name} will be removed" ret["result"] = None return ret __salt__["alternatives.remove"](name, path) @@ -143,7 +143,7 @@ def remove(name, path): ret["changes"] = {"path": current} return ret - ret["comment"] = "Alternative for {} removed".format(name) + ret["comment"] = f"Alternative for {name} removed" ret["changes"] = {} return ret @@ -156,7 +156,7 @@ def remove(name, path): return ret ret["result"] = False - ret["comment"] = "Alternative for {} doesn't exist".format(name) + ret["comment"] = f"Alternative for {name} doesn't exist" return ret @@ -178,11 +178,11 @@ def auto(name): display = __salt__["alternatives.display"](name) line = display.splitlines()[0] if line.endswith(" auto mode"): - ret["comment"] = "{} already in auto mode".format(name) + ret["comment"] = f"{name} already in auto mode" return ret if __opts__["test"]: - ret["comment"] = "{} will be put in auto mode".format(name) + ret["comment"] = f"{name} will be put in auto mode" ret["result"] = None return ret ret["changes"]["result"] = __salt__["alternatives.auto"](name) @@ -214,7 +214,7 @@ def set_(name, path): current = __salt__["alternatives.show_current"](name) if current == path: - ret["comment"] = "Alternative for {} already set to {}".format(name, path) + ret["comment"] = f"Alternative for {name} already set to {path}" return ret display = __salt__["alternatives.display"](name) @@ -234,15 +234,15 @@ def set_(name, path): __salt__["alternatives.set"](name, path) current = __salt__["alternatives.show_current"](name) if current == path: - ret["comment"] = "Alternative for {} set to path {}".format(name, current) + ret["comment"] = f"Alternative for {name} set to path {current}" ret["changes"] = {"path": current} else: - ret["comment"] = "Alternative for {} not updated".format(name) + ret["comment"] = f"Alternative for {name} not updated" return ret else: ret["result"] = False - ret["comment"] = "Alternative {} for {} doesn't exist".format(path, name) + ret["comment"] = f"Alternative {path} for {name} doesn't exist" return ret diff --git a/salt/states/ansiblegate.py b/salt/states/ansiblegate.py index 2ecc18f6e81..3de3dd5a36c 100644 --- a/salt/states/ansiblegate.py +++ b/salt/states/ansiblegate.py @@ -96,7 +96,7 @@ class AnsibleState: for mod_name, mod_params in kwargs.items(): args, kwargs = self.get_args(mod_params) try: - ans_mod_out = __salt__["ansible.{}".format(mod_name)]( + ans_mod_out = __salt__[f"ansible.{mod_name}"]( **{"__pub_arg": [args, kwargs]} ) except Exception as err: # pylint: disable=broad-except @@ -170,7 +170,7 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs= ret = { "result": False, "changes": {}, - "comment": "Running playbook {}".format(name), + "comment": f"Running playbook {name}", "name": name, } if git_repo: @@ -197,13 +197,13 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs= not check["changed"] and not check["failures"] and not check["unreachable"] for check in checks["stats"].values() ): - ret["comment"] = "No changes to be made from playbook {}".format(name) + ret["comment"] = f"No changes to be made from playbook {name}" ret["result"] = True elif any( check["changed"] and not check["failures"] and not check["unreachable"] for check in checks["stats"].values() ): - ret["comment"] = "Changes will be made from playbook {}".format(name) + ret["comment"] = f"Changes will be made from playbook {name}" ret["result"] = None ret["changes"] = _changes(checks) else: @@ -224,7 +224,7 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs= not check["changed"] and not check["failures"] and not check["unreachable"] for check in results["stats"].values() ): - ret["comment"] = "No changes to be made from playbook {}".format(name) + ret["comment"] = f"No changes to be made from playbook {name}" ret["result"] = True ret["changes"] = _changes(results) else: @@ -234,9 +234,7 @@ def playbooks(name, rundir=None, git_repo=None, git_kwargs=None, ansible_kwargs= for check in results["stats"].values() ) if ret["result"]: - ret["comment"] = "Changes were made by playbook {}".format(name) + ret["comment"] = f"Changes were made by playbook {name}" else: - ret["comment"] = ( - "There were some issues running the playbook {}".format(name) - ) + ret["comment"] = f"There were some issues running the playbook {name}" return ret diff --git a/salt/states/apache_conf.py b/salt/states/apache_conf.py index 3521ebbeb15..bda2eee00a8 100644 --- a/salt/states/apache_conf.py +++ b/salt/states/apache_conf.py @@ -40,7 +40,7 @@ def enabled(name): is_enabled = __salt__["apache.check_conf_enabled"](name) if not is_enabled: if __opts__["test"]: - msg = "Apache conf {} is set to be enabled.".format(name) + msg = f"Apache conf {name} is set to be enabled." ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = name @@ -53,12 +53,12 @@ def enabled(name): ret["changes"]["new"] = name else: ret["result"] = False - ret["comment"] = "Failed to enable {} Apache conf".format(name) + ret["comment"] = f"Failed to enable {name} Apache conf" if isinstance(status, str): - ret["comment"] = ret["comment"] + " ({})".format(status) + ret["comment"] = ret["comment"] + f" ({status})" return ret else: - ret["comment"] = "{} already enabled.".format(name) + ret["comment"] = f"{name} already enabled." return ret @@ -74,7 +74,7 @@ def disabled(name): is_enabled = __salt__["apache.check_conf_enabled"](name) if is_enabled: if __opts__["test"]: - msg = "Apache conf {} is set to be disabled.".format(name) + msg = f"Apache conf {name} is set to be disabled." ret["comment"] = msg ret["changes"]["old"] = name ret["changes"]["new"] = None @@ -87,10 +87,10 @@ def disabled(name): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to disable {} Apache conf".format(name) + ret["comment"] = f"Failed to disable {name} Apache conf" if isinstance(status, str): - ret["comment"] = ret["comment"] + " ({})".format(status) + ret["comment"] = ret["comment"] + f" ({status})" return ret else: - ret["comment"] = "{} already disabled.".format(name) + ret["comment"] = f"{name} already disabled." return ret diff --git a/salt/states/apache_module.py b/salt/states/apache_module.py index a61de00223b..61b72dc0825 100644 --- a/salt/states/apache_module.py +++ b/salt/states/apache_module.py @@ -40,7 +40,7 @@ def enabled(name): is_enabled = __salt__["apache.check_mod_enabled"](name) if not is_enabled: if __opts__["test"]: - msg = "Apache module {} is set to be enabled.".format(name) + msg = f"Apache module {name} is set to be enabled." ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = name @@ -53,12 +53,12 @@ def enabled(name): ret["changes"]["new"] = name else: ret["result"] = False - ret["comment"] = "Failed to enable {} Apache module".format(name) + ret["comment"] = f"Failed to enable {name} Apache module" if isinstance(status, str): - ret["comment"] = ret["comment"] + " ({})".format(status) + ret["comment"] = ret["comment"] + f" ({status})" return ret else: - ret["comment"] = "{} already enabled.".format(name) + ret["comment"] = f"{name} already enabled." return ret @@ -76,7 +76,7 @@ def disabled(name): is_enabled = __salt__["apache.check_mod_enabled"](name) if is_enabled: if __opts__["test"]: - msg = "Apache module {} is set to be disabled.".format(name) + msg = f"Apache module {name} is set to be disabled." ret["comment"] = msg ret["changes"]["old"] = name ret["changes"]["new"] = None @@ -89,10 +89,10 @@ def disabled(name): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to disable {} Apache module".format(name) + ret["comment"] = f"Failed to disable {name} Apache module" if isinstance(status, str): - ret["comment"] = ret["comment"] + " ({})".format(status) + ret["comment"] = ret["comment"] + f" ({status})" return ret else: - ret["comment"] = "{} already disabled.".format(name) + ret["comment"] = f"{name} already disabled." return ret diff --git a/salt/states/apache_site.py b/salt/states/apache_site.py index 6ba92b2a3cc..506e72bccfc 100644 --- a/salt/states/apache_site.py +++ b/salt/states/apache_site.py @@ -38,7 +38,7 @@ def enabled(name): is_enabled = __salt__["apache.check_site_enabled"](name) if not is_enabled: if __opts__["test"]: - msg = "Apache site {} is set to be enabled.".format(name) + msg = f"Apache site {name} is set to be enabled." ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = name @@ -51,12 +51,12 @@ def enabled(name): ret["changes"]["new"] = name else: ret["result"] = False - ret["comment"] = "Failed to enable {} Apache site".format(name) + ret["comment"] = f"Failed to enable {name} Apache site" if isinstance(status, str): - ret["comment"] = ret["comment"] + " ({})".format(status) + ret["comment"] = ret["comment"] + f" ({status})" return ret else: - ret["comment"] = "{} already enabled.".format(name) + ret["comment"] = f"{name} already enabled." return ret @@ -72,7 +72,7 @@ def disabled(name): is_enabled = __salt__["apache.check_site_enabled"](name) if is_enabled: if __opts__["test"]: - msg = "Apache site {} is set to be disabled.".format(name) + msg = f"Apache site {name} is set to be disabled." ret["comment"] = msg ret["changes"]["old"] = name ret["changes"]["new"] = None @@ -85,10 +85,10 @@ def disabled(name): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to disable {} Apache site".format(name) + ret["comment"] = f"Failed to disable {name} Apache site" if isinstance(status, str): - ret["comment"] = ret["comment"] + " ({})".format(status) + ret["comment"] = ret["comment"] + f" ({status})" return ret else: - ret["comment"] = "{} already disabled.".format(name) + ret["comment"] = f"{name} already disabled." return ret diff --git a/salt/states/aptpkg.py b/salt/states/aptpkg.py index 7a285bfc913..0b196e3503e 100644 --- a/salt/states/aptpkg.py +++ b/salt/states/aptpkg.py @@ -35,18 +35,18 @@ def held(name): pattern=name, ) if not state: - ret.update(comment="Package {} does not have a state".format(name)) + ret.update(comment=f"Package {name} does not have a state") elif not salt.utils.data.is_true(state.get("hold", False)): if not __opts__["test"]: result = __salt__["pkg.set_selections"](selection={"hold": [name]}) ret.update( changes=result[name], result=True, - comment="Package {} is now being held".format(name), + comment=f"Package {name} is now being held", ) else: - ret.update(result=None, comment="Package {} is set to be held".format(name)) + ret.update(result=None, comment=f"Package {name} is set to be held") else: - ret.update(result=True, comment="Package {} is already held".format(name)) + ret.update(result=True, comment=f"Package {name} is already held") return ret diff --git a/salt/states/archive.py b/salt/states/archive.py index bf47864f542..e99556f1eaf 100644 --- a/salt/states/archive.py +++ b/salt/states/archive.py @@ -114,7 +114,7 @@ def _update_checksum(path): line[1] = hsum fp_.write("{}:{}\n".format(*line)) if hash_type not in [x[0] for x in lines]: - fp_.write("{}:{}\n".format(hash_type, hsum)) + fp_.write(f"{hash_type}:{hsum}\n") except OSError as exc: log.warning( "Failed to update checksum for %s: %s", @@ -190,7 +190,7 @@ def extracted( enforce_ownership_on=None, archive_format=None, use_etag=False, - **kwargs + **kwargs, ): """ .. versionadded:: 2014.1.0 @@ -737,7 +737,7 @@ def extracted( keep_source = True if not _path_is_abs(name): - ret["comment"] = "{} is not an absolute path".format(name) + ret["comment"] = f"{name} is not an absolute path" return ret else: if not name: @@ -755,7 +755,7 @@ def extracted( # False name = name.rstrip(os.sep) if os.path.isfile(name): - ret["comment"] = "{} exists and is not a directory".format(name) + ret["comment"] = f"{name} exists and is not a directory" return ret # Add back the slash so that file.makedirs properly creates the # destdir if it needs to be created. file.makedirs expects a trailing @@ -781,13 +781,13 @@ def extracted( not_rel = True if not_rel: ret["comment"] = ( - "Value for 'enforce_ownership_on' must be within {}".format(name) + f"Value for 'enforce_ownership_on' must be within {name}" ) return ret if if_missing is not None and os.path.exists(if_missing): ret["result"] = True - ret["comment"] = "Path {} exists".format(if_missing) + ret["comment"] = f"Path {if_missing} exists" return ret if user or group: @@ -800,7 +800,7 @@ def extracted( if user: uid = __salt__["file.user_to_uid"](user) if uid == "": - ret["comment"] = "User {} does not exist".format(user) + ret["comment"] = f"User {user} does not exist" return ret else: uid = -1 @@ -808,7 +808,7 @@ def extracted( if group: gid = __salt__["file.group_to_gid"](group) if gid == "": - ret["comment"] = "Group {} does not exist".format(group) + ret["comment"] = f"Group {group} does not exist" return ret else: gid = -1 @@ -833,7 +833,7 @@ def extracted( if not source_match: ret["result"] = False - ret["comment"] = 'Invalid source "{}"'.format(source) + ret["comment"] = f'Invalid source "{source}"' return ret urlparsed_source = urlparse(source_match) @@ -1153,7 +1153,7 @@ def extracted( ) for error in errors: - msg += "\n- {}".format(error) + msg += f"\n- {error}" ret["comment"] = msg return ret @@ -1241,9 +1241,7 @@ def extracted( return ret if incorrect_type: - incorrect_paths = "\n\n" + "\n".join( - ["- {}".format(x) for x in incorrect_type] - ) + incorrect_paths = "\n\n" + "\n".join([f"- {x}" for x in incorrect_type]) ret["comment"] = ( "The below paths (relative to {}) exist, but are the " "incorrect type (file instead of directory, symlink " @@ -1297,7 +1295,7 @@ def extracted( "following errors were observed:\n" ) for error in errors: - msg += "\n- {}".format(error) + msg += f"\n- {error}" ret["comment"] = msg return ret @@ -1343,7 +1341,7 @@ def extracted( salt.utils.files.rm_rf(name.rstrip(os.sep)) ret["changes"].setdefault( "removed", - "Directory {} was removed prior to the extraction".format(name), + f"Directory {name} was removed prior to the extraction", ) except OSError as exc: if exc.errno != errno.ENOENT: @@ -1354,7 +1352,7 @@ def extracted( "errors were observed:\n".format(name) ) for error in errors: - msg += "\n- {}".format(error) + msg += f"\n- {error}" ret["comment"] = msg return ret @@ -1377,7 +1375,7 @@ def extracted( "errors were observed:\n" ) for error in errors: - msg += "\n- {}".format(error) + msg += f"\n- {error}" ret["comment"] = msg return ret @@ -1396,7 +1394,7 @@ def extracted( options=options, trim_output=trim_output, password=password, - **kwargs + **kwargs, ) except (CommandExecutionError, CommandNotFoundError) as exc: ret["comment"] = exc.strerror @@ -1409,7 +1407,7 @@ def extracted( trim_output=trim_output, password=password, extract_perms=extract_perms, - **kwargs + **kwargs, ) elif archive_format == "rar": try: @@ -1661,7 +1659,7 @@ def extracted( else: ret["result"] = True if if_missing_path_exists: - ret["comment"] = "{} exists".format(if_missing) + ret["comment"] = f"{if_missing} exists" else: ret["comment"] = "All files in archive are already present" if __opts__["test"]: @@ -1686,7 +1684,7 @@ def extracted( "paths were missing:\n" ) for item in enforce_missing: - ret["comment"] += "\n- {}".format(item) + ret["comment"] += f"\n- {item}" if enforce_failed: ret["result"] = False @@ -1695,7 +1693,7 @@ def extracted( "unable to change ownership on the following paths:\n" ) for item in enforce_failed: - ret["comment"] += "\n- {}".format(item) + ret["comment"] += f"\n- {item}" if not source_is_local: if keep_source: diff --git a/salt/states/at.py b/salt/states/at.py index 09b2fd0e423..5d211f7f7d3 100644 --- a/salt/states/at.py +++ b/salt/states/at.py @@ -74,7 +74,7 @@ def present(name, timespec, tag=None, user=None, job=None, unique_tag=False): ret["comment"] = "no tag provided and unique_tag is set to True" return ret elif len(__salt__["at.jobcheck"](tag=tag)["jobs"]) > 0: - ret["comment"] = "atleast one job with tag {tag} exists.".format(tag=tag) + ret["comment"] = f"atleast one job with tag {tag} exists." return ret # create job @@ -82,7 +82,7 @@ def present(name, timespec, tag=None, user=None, job=None, unique_tag=False): luser = __salt__["user.info"](user) if not luser: ret["result"] = False - ret["comment"] = "user {} does not exists".format(user) + ret["comment"] = f"user {user} does not exists" return ret ret["comment"] = "job {} added and will run as {} on {}".format( job, @@ -176,7 +176,7 @@ def absent(name, jobid=None, **kwargs): # limit was never support if "limit" in kwargs: - ret["comment"] = "limit parameter not supported {}".format(name) + ret["comment"] = f"limit parameter not supported {name}" ret["result"] = False return ret @@ -191,7 +191,7 @@ def absent(name, jobid=None, **kwargs): jobs = __salt__["at.atq"](jobid) if "jobs" in jobs and len(jobs["jobs"]) == 0: ret["result"] = True - ret["comment"] = "job with id {jobid} not present".format(jobid=jobid) + ret["comment"] = f"job with id {jobid} not present" return ret elif "jobs" in jobs and len(jobs["jobs"]) == 1: if "job" in jobs["jobs"][0] and jobs["jobs"][0]["job"]: diff --git a/salt/states/augeas.py b/salt/states/augeas.py index 843f82c8ba2..c1b7cef99de 100644 --- a/salt/states/augeas.py +++ b/salt/states/augeas.py @@ -70,7 +70,7 @@ def _check_filepath(changes): cmd, arg = change_.split(" ", 1) if cmd not in METHOD_MAP: - error = "Command {} is not supported (yet)".format(cmd) + error = f"Command {cmd} is not supported (yet)" raise ValueError(error) method = METHOD_MAP[cmd] parts = salt.utils.args.shlex_split(arg) @@ -276,7 +276,7 @@ def change(name, context=None, changes=None, lens=None, load_path=None, **kwargs try: filename = _check_filepath(changes) except ValueError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret else: filename = re.sub("^/files|/$", "", context) @@ -285,7 +285,7 @@ def change(name, context=None, changes=None, lens=None, load_path=None, **kwargs ret["result"] = True ret["comment"] = "Executing commands" if context: - ret["comment"] += ' in file "{}":\n'.format(context) + ret["comment"] += f' in file "{context}":\n' ret["comment"] += "\n".join(changes) return ret diff --git a/salt/states/aws_sqs.py b/salt/states/aws_sqs.py index 42b8a5eb996..68370410ef2 100644 --- a/salt/states/aws_sqs.py +++ b/salt/states/aws_sqs.py @@ -48,7 +48,7 @@ def exists(name, region, user=None, opts=False): if not does_exist: if __opts__["test"]: ret["result"] = None - ret["comment"] = "AWS SQS queue {} is set to be created".format(name) + ret["comment"] = f"AWS SQS queue {name} is set to be created" return ret created = __salt__["aws_sqs.create_queue"](name, region, opts, user) if created["retcode"] == 0: @@ -58,7 +58,7 @@ def exists(name, region, user=None, opts=False): ret["comment"] = created["stderr"] else: - ret["comment"] = "{} exists in {}".format(name, region) + ret["comment"] = f"{name} exists in {region}" return ret @@ -86,7 +86,7 @@ def absent(name, region, user=None, opts=False): if does_exist: if __opts__["test"]: ret["result"] = None - ret["comment"] = "AWS SQS queue {} is set to be removed".format(name) + ret["comment"] = f"AWS SQS queue {name} is set to be removed" return ret removed = __salt__["aws_sqs.delete_queue"](name, region, opts, user) if removed["retcode"] == 0: @@ -95,6 +95,6 @@ def absent(name, region, user=None, opts=False): ret["result"] = False ret["comment"] = removed["stderr"] else: - ret["comment"] = "{} does not exist in {}".format(name, region) + ret["comment"] = f"{name} does not exist in {region}" return ret diff --git a/salt/states/azurearm_compute.py b/salt/states/azurearm_compute.py index bfdd2dd925a..7b46a95b14f 100644 --- a/salt/states/azurearm_compute.py +++ b/salt/states/azurearm_compute.py @@ -142,7 +142,7 @@ def availability_set_present( virtual_machines=None, sku=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -254,12 +254,12 @@ def availability_set_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Availability set {} is already present.".format(name) + ret["comment"] = f"Availability set {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Availability set {} would be updated.".format(name) + ret["comment"] = f"Availability set {name} would be updated." return ret else: @@ -276,7 +276,7 @@ def availability_set_present( } if __opts__["test"]: - ret["comment"] = "Availability set {} would be created.".format(name) + ret["comment"] = f"Availability set {name} would be created." ret["result"] = None return ret @@ -291,12 +291,12 @@ def availability_set_present( platform_fault_domain_count=platform_fault_domain_count, sku=sku, tags=tags, - **aset_kwargs + **aset_kwargs, ) if "error" not in aset: ret["result"] = True - ret["comment"] = "Availability set {} has been created.".format(name) + ret["comment"] = f"Availability set {name} has been created." return ret ret["comment"] = "Failed to create availability set {}! ({})".format( @@ -336,11 +336,11 @@ def availability_set_absent(name, resource_group, connection_auth=None): if "error" in aset: ret["result"] = True - ret["comment"] = "Availability set {} was not found.".format(name) + ret["comment"] = f"Availability set {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Availability set {} would be deleted.".format(name) + ret["comment"] = f"Availability set {name} would be deleted." ret["result"] = None ret["changes"] = { "old": aset, @@ -354,9 +354,9 @@ def availability_set_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Availability set {} has been deleted.".format(name) + ret["comment"] = f"Availability set {name} has been deleted." ret["changes"] = {"old": aset, "new": {}} return ret - ret["comment"] = "Failed to delete availability set {}!".format(name) + ret["comment"] = f"Failed to delete availability set {name}!" return ret diff --git a/salt/states/azurearm_dns.py b/salt/states/azurearm_dns.py index 6002d24a821..91a1bd121c0 100644 --- a/salt/states/azurearm_dns.py +++ b/salt/states/azurearm_dns.py @@ -169,7 +169,7 @@ def zone_present( tags=None, zone_type="Public", connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 3000 @@ -304,12 +304,12 @@ def zone_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "DNS zone {} is already present.".format(name) + ret["comment"] = f"DNS zone {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "DNS zone {} would be updated.".format(name) + ret["comment"] = f"DNS zone {name} would be updated." return ret else: @@ -327,7 +327,7 @@ def zone_present( } if __opts__["test"]: - ret["comment"] = "DNS zone {} would be created.".format(name) + ret["comment"] = f"DNS zone {name} would be created." ret["result"] = None return ret @@ -344,12 +344,12 @@ def zone_present( resolution_virtual_networks=resolution_virtual_networks, tags=tags, zone_type=zone_type, - **zone_kwargs + **zone_kwargs, ) if "error" not in zone: ret["result"] = True - ret["comment"] = "DNS zone {} has been created.".format(name) + ret["comment"] = f"DNS zone {name} has been created." return ret ret["comment"] = "Failed to create DNS zone {}! ({})".format( @@ -389,11 +389,11 @@ def zone_absent(name, resource_group, connection_auth=None): if "error" in zone: ret["result"] = True - ret["comment"] = "DNS zone {} was not found.".format(name) + ret["comment"] = f"DNS zone {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "DNS zone {} would be deleted.".format(name) + ret["comment"] = f"DNS zone {name} would be deleted." ret["result"] = None ret["changes"] = { "old": zone, @@ -407,11 +407,11 @@ def zone_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "DNS zone {} has been deleted.".format(name) + ret["comment"] = f"DNS zone {name} has been deleted." ret["changes"] = {"old": zone, "new": {}} return ret - ret["comment"] = "Failed to delete DNS zone {}!".format(name) + ret["comment"] = f"Failed to delete DNS zone {name}!" return ret @@ -437,7 +437,7 @@ def record_set_present( soa_record=None, caa_records=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 3000 @@ -576,7 +576,7 @@ def record_set_present( resource_group, record_type, azurearm_log_level="info", - **connection_auth + **connection_auth, ) if "error" not in rec_set: @@ -632,12 +632,12 @@ def record_set_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Record set {} is already present.".format(name) + ret["comment"] = f"Record set {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Record set {} would be updated.".format(name) + ret["comment"] = f"Record set {name} would be updated." return ret else: @@ -660,7 +660,7 @@ def record_set_present( ret["changes"]["new"][record] = eval(record) if __opts__["test"]: - ret["comment"] = "Record set {} would be created.".format(name) + ret["comment"] = f"Record set {name} would be created." ret["result"] = None return ret @@ -687,12 +687,12 @@ def record_set_present( cname_record=cname_record, soa_record=soa_record, caa_records=caa_records, - **rec_set_kwargs + **rec_set_kwargs, ) if "error" not in rec_set: ret["result"] = True - ret["comment"] = "Record set {} has been created.".format(name) + ret["comment"] = f"Record set {name} has been created." return ret ret["comment"] = "Failed to create record set {}! ({})".format( @@ -741,7 +741,7 @@ def record_set_absent(name, zone_name, resource_group, connection_auth=None): return ret elif __opts__["test"]: - ret["comment"] = "Record set {} would be deleted.".format(name) + ret["comment"] = f"Record set {name} would be deleted." ret["result"] = None ret["changes"] = { "old": rec_set, @@ -755,9 +755,9 @@ def record_set_absent(name, zone_name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Record set {} has been deleted.".format(name) + ret["comment"] = f"Record set {name} has been deleted." ret["changes"] = {"old": rec_set, "new": {}} return ret - ret["comment"] = "Failed to delete record set {}!".format(name) + ret["comment"] = f"Failed to delete record set {name}!" return ret diff --git a/salt/states/azurearm_network.py b/salt/states/azurearm_network.py index 513206d95f2..ec872bec4c9 100644 --- a/salt/states/azurearm_network.py +++ b/salt/states/azurearm_network.py @@ -140,7 +140,7 @@ def virtual_network_present( dns_servers=None, tags=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -243,12 +243,12 @@ def virtual_network_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Virtual network {} is already present.".format(name) + ret["comment"] = f"Virtual network {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Virtual network {} would be updated.".format(name) + ret["comment"] = f"Virtual network {name} would be updated." return ret else: @@ -266,7 +266,7 @@ def virtual_network_present( } if __opts__["test"]: - ret["comment"] = "Virtual network {} would be created.".format(name) + ret["comment"] = f"Virtual network {name} would be created." ret["result"] = None return ret @@ -279,12 +279,12 @@ def virtual_network_present( address_prefixes=address_prefixes, dns_servers=dns_servers, tags=tags, - **vnet_kwargs + **vnet_kwargs, ) if "error" not in vnet: ret["result"] = True - ret["comment"] = "Virtual network {} has been created.".format(name) + ret["comment"] = f"Virtual network {name} has been created." return ret ret["comment"] = "Failed to create virtual network {}! ({})".format( @@ -324,11 +324,11 @@ def virtual_network_absent(name, resource_group, connection_auth=None): if "error" in vnet: ret["result"] = True - ret["comment"] = "Virtual network {} was not found.".format(name) + ret["comment"] = f"Virtual network {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Virtual network {} would be deleted.".format(name) + ret["comment"] = f"Virtual network {name} would be deleted." ret["result"] = None ret["changes"] = { "old": vnet, @@ -342,11 +342,11 @@ def virtual_network_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Virtual network {} has been deleted.".format(name) + ret["comment"] = f"Virtual network {name} has been deleted." ret["changes"] = {"old": vnet, "new": {}} return ret - ret["comment"] = "Failed to delete virtual network {}!".format(name) + ret["comment"] = f"Failed to delete virtual network {name}!" return ret @@ -359,7 +359,7 @@ def subnet_present( security_group=None, route_table=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -420,7 +420,7 @@ def subnet_present( virtual_network, resource_group, azurearm_log_level="info", - **connection_auth + **connection_auth, ) if "error" not in snet: @@ -449,12 +449,12 @@ def subnet_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Subnet {} is already present.".format(name) + ret["comment"] = f"Subnet {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Subnet {} would be updated.".format(name) + ret["comment"] = f"Subnet {name} would be updated." return ret else: @@ -469,7 +469,7 @@ def subnet_present( } if __opts__["test"]: - ret["comment"] = "Subnet {} would be created.".format(name) + ret["comment"] = f"Subnet {name} would be created." ret["result"] = None return ret @@ -483,12 +483,12 @@ def subnet_present( address_prefix=address_prefix, network_security_group=security_group, route_table=route_table, - **snet_kwargs + **snet_kwargs, ) if "error" not in snet: ret["result"] = True - ret["comment"] = "Subnet {} has been created.".format(name) + ret["comment"] = f"Subnet {name} has been created." return ret ret["comment"] = "Failed to create subnet {}! ({})".format(name, snet.get("error")) @@ -528,16 +528,16 @@ def subnet_absent(name, virtual_network, resource_group, connection_auth=None): virtual_network, resource_group, azurearm_log_level="info", - **connection_auth + **connection_auth, ) if "error" in snet: ret["result"] = True - ret["comment"] = "Subnet {} was not found.".format(name) + ret["comment"] = f"Subnet {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Subnet {} would be deleted.".format(name) + ret["comment"] = f"Subnet {name} would be deleted." ret["result"] = None ret["changes"] = { "old": snet, @@ -551,11 +551,11 @@ def subnet_absent(name, virtual_network, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Subnet {} has been deleted.".format(name) + ret["comment"] = f"Subnet {name} has been deleted." ret["changes"] = {"old": snet, "new": {}} return ret - ret["comment"] = "Failed to delete subnet {}!".format(name) + ret["comment"] = f"Failed to delete subnet {name}!" return ret @@ -661,7 +661,7 @@ def network_security_group_present( if __opts__["test"]: ret["result"] = None - ret["comment"] = "Network security group {} would be updated.".format(name) + ret["comment"] = f"Network security group {name} would be updated." return ret else: @@ -676,7 +676,7 @@ def network_security_group_present( } if __opts__["test"]: - ret["comment"] = "Network security group {} would be created.".format(name) + ret["comment"] = f"Network security group {name} would be created." ret["result"] = None return ret @@ -688,12 +688,12 @@ def network_security_group_present( resource_group=resource_group, tags=tags, security_rules=security_rules, - **nsg_kwargs + **nsg_kwargs, ) if "error" not in nsg: ret["result"] = True - ret["comment"] = "Network security group {} has been created.".format(name) + ret["comment"] = f"Network security group {name} has been created." return ret ret["comment"] = "Failed to create network security group {}! ({})".format( @@ -733,11 +733,11 @@ def network_security_group_absent(name, resource_group, connection_auth=None): if "error" in nsg: ret["result"] = True - ret["comment"] = "Network security group {} was not found.".format(name) + ret["comment"] = f"Network security group {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Network security group {} would be deleted.".format(name) + ret["comment"] = f"Network security group {name} would be deleted." ret["result"] = None ret["changes"] = { "old": nsg, @@ -751,11 +751,11 @@ def network_security_group_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Network security group {} has been deleted.".format(name) + ret["comment"] = f"Network security group {name} has been deleted." ret["changes"] = {"old": nsg, "new": {}} return ret - ret["comment"] = "Failed to delete network security group {}!".format(name) + ret["comment"] = f"Failed to delete network security group {name}!" return ret @@ -778,7 +778,7 @@ def security_rule_present( source_address_prefixes=None, source_port_ranges=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -897,17 +897,17 @@ def security_rule_present( if eval(params[0]): # pylint: disable=eval-used if not isinstance(eval(params[0]), list): - ret["comment"] = "The {} parameter must be a list!".format(params[0]) + ret["comment"] = f"The {params[0]} parameter must be a list!" return ret # pylint: disable=exec-used - exec("{} = None".format(params[1])) + exec(f"{params[1]} = None") rule = __salt__["azurearm_network.security_rule_get"]( name, security_group, resource_group, azurearm_log_level="info", - **connection_auth + **connection_auth, ) if "error" not in rule: @@ -1037,12 +1037,12 @@ def security_rule_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Security rule {} is already present.".format(name) + ret["comment"] = f"Security rule {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Security rule {} would be updated.".format(name) + ret["comment"] = f"Security rule {name} would be updated." return ret else: @@ -1067,7 +1067,7 @@ def security_rule_present( } if __opts__["test"]: - ret["comment"] = "Security rule {} would be created.".format(name) + ret["comment"] = f"Security rule {name} would be created." ret["result"] = None return ret @@ -1091,12 +1091,12 @@ def security_rule_present( source_address_prefixes=source_address_prefixes, source_port_range=source_port_range, source_port_ranges=source_port_ranges, - **rule_kwargs + **rule_kwargs, ) if "error" not in rule: ret["result"] = True - ret["comment"] = "Security rule {} has been created.".format(name) + ret["comment"] = f"Security rule {name} has been created." return ret ret["comment"] = "Failed to create security rule {}! ({})".format( @@ -1138,16 +1138,16 @@ def security_rule_absent(name, security_group, resource_group, connection_auth=N security_group, resource_group, azurearm_log_level="info", - **connection_auth + **connection_auth, ) if "error" in rule: ret["result"] = True - ret["comment"] = "Security rule {} was not found.".format(name) + ret["comment"] = f"Security rule {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Security rule {} would be deleted.".format(name) + ret["comment"] = f"Security rule {name} would be deleted." ret["result"] = None ret["changes"] = { "old": rule, @@ -1161,11 +1161,11 @@ def security_rule_absent(name, security_group, resource_group, connection_auth=N if deleted: ret["result"] = True - ret["comment"] = "Security rule {} has been deleted.".format(name) + ret["comment"] = f"Security rule {name} has been deleted." ret["changes"] = {"old": rule, "new": {}} return ret - ret["comment"] = "Failed to delete security rule {}!".format(name) + ret["comment"] = f"Failed to delete security rule {name}!" return ret @@ -1183,7 +1183,7 @@ def load_balancer_present( outbound_nat_rules=None, tags=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -1487,12 +1487,12 @@ def load_balancer_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Load balancer {} is already present.".format(name) + ret["comment"] = f"Load balancer {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Load balancer {} would be updated.".format(name) + ret["comment"] = f"Load balancer {name} would be updated." return ret else: @@ -1513,7 +1513,7 @@ def load_balancer_present( } if __opts__["test"]: - ret["comment"] = "Load balancer {} would be created.".format(name) + ret["comment"] = f"Load balancer {name} would be created." ret["result"] = None return ret @@ -1532,12 +1532,12 @@ def load_balancer_present( inbound_nat_rules=inbound_nat_rules, inbound_nat_pools=inbound_nat_pools, outbound_nat_rules=outbound_nat_rules, - **lb_kwargs + **lb_kwargs, ) if "error" not in load_bal: ret["result"] = True - ret["comment"] = "Load balancer {} has been created.".format(name) + ret["comment"] = f"Load balancer {name} has been created." return ret ret["comment"] = "Failed to create load balancer {}! ({})".format( @@ -1577,11 +1577,11 @@ def load_balancer_absent(name, resource_group, connection_auth=None): if "error" in load_bal: ret["result"] = True - ret["comment"] = "Load balancer {} was not found.".format(name) + ret["comment"] = f"Load balancer {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Load balancer {} would be deleted.".format(name) + ret["comment"] = f"Load balancer {name} would be deleted." ret["result"] = None ret["changes"] = { "old": load_bal, @@ -1595,11 +1595,11 @@ def load_balancer_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Load balancer {} has been deleted.".format(name) + ret["comment"] = f"Load balancer {name} has been deleted." ret["changes"] = {"old": load_bal, "new": {}} return ret - ret["comment"] = "Failed to delete load balancer {}!".format(name) + ret["comment"] = f"Failed to delete load balancer {name}!" return ret @@ -1614,7 +1614,7 @@ def public_ip_address_present( dns_settings=None, idle_timeout_in_minutes=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -1751,12 +1751,12 @@ def public_ip_address_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Public IP address {} is already present.".format(name) + ret["comment"] = f"Public IP address {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Public IP address {} would be updated.".format(name) + ret["comment"] = f"Public IP address {name} would be updated." return ret else: @@ -1774,7 +1774,7 @@ def public_ip_address_present( } if __opts__["test"]: - ret["comment"] = "Public IP address {} would be created.".format(name) + ret["comment"] = f"Public IP address {name} would be created." ret["result"] = None return ret @@ -1790,12 +1790,12 @@ def public_ip_address_present( public_ip_allocation_method=public_ip_allocation_method, public_ip_address_version=public_ip_address_version, idle_timeout_in_minutes=idle_timeout_in_minutes, - **pub_ip_kwargs + **pub_ip_kwargs, ) if "error" not in pub_ip: ret["result"] = True - ret["comment"] = "Public IP address {} has been created.".format(name) + ret["comment"] = f"Public IP address {name} has been created." return ret ret["comment"] = "Failed to create public IP address {}! ({})".format( @@ -1835,11 +1835,11 @@ def public_ip_address_absent(name, resource_group, connection_auth=None): if "error" in pub_ip: ret["result"] = True - ret["comment"] = "Public IP address {} was not found.".format(name) + ret["comment"] = f"Public IP address {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Public IP address {} would be deleted.".format(name) + ret["comment"] = f"Public IP address {name} would be deleted." ret["result"] = None ret["changes"] = { "old": pub_ip, @@ -1853,11 +1853,11 @@ def public_ip_address_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Public IP address {} has been deleted.".format(name) + ret["comment"] = f"Public IP address {name} has been deleted." ret["changes"] = {"old": pub_ip, "new": {}} return ret - ret["comment"] = "Failed to delete public IP address {}!".format(name) + ret["comment"] = f"Failed to delete public IP address {name}!" return ret @@ -1877,7 +1877,7 @@ def network_interface_present( enable_accelerated_networking=None, enable_ip_forwarding=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -2071,12 +2071,12 @@ def network_interface_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Network interface {} is already present.".format(name) + ret["comment"] = f"Network interface {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Network interface {} would be updated.".format(name) + ret["comment"] = f"Network interface {name} would be updated." return ret else: @@ -2097,7 +2097,7 @@ def network_interface_present( } if __opts__["test"]: - ret["comment"] = "Network interface {} would be created.".format(name) + ret["comment"] = f"Network interface {name} would be created." ret["result"] = None return ret @@ -2118,12 +2118,12 @@ def network_interface_present( network_security_group=network_security_group, virtual_machine=virtual_machine, tags=tags, - **iface_kwargs + **iface_kwargs, ) if "error" not in iface: ret["result"] = True - ret["comment"] = "Network interface {} has been created.".format(name) + ret["comment"] = f"Network interface {name} has been created." return ret ret["comment"] = "Failed to create network interface {}! ({})".format( @@ -2163,11 +2163,11 @@ def network_interface_absent(name, resource_group, connection_auth=None): if "error" in iface: ret["result"] = True - ret["comment"] = "Network interface {} was not found.".format(name) + ret["comment"] = f"Network interface {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Network interface {} would be deleted.".format(name) + ret["comment"] = f"Network interface {name} would be deleted." ret["result"] = None ret["changes"] = { "old": iface, @@ -2181,11 +2181,11 @@ def network_interface_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Network interface {} has been deleted.".format(name) + ret["comment"] = f"Network interface {name} has been deleted." ret["changes"] = {"old": iface, "new": {}} return ret - ret["comment"] = "Failed to delete network interface {}!)".format(name) + ret["comment"] = f"Failed to delete network interface {name}!)" return ret @@ -2197,7 +2197,7 @@ def route_table_present( routes=None, disable_bgp_route_propagation=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -2293,12 +2293,12 @@ def route_table_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Route table {} is already present.".format(name) + ret["comment"] = f"Route table {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Route table {} would be updated.".format(name) + ret["comment"] = f"Route table {name} would be updated." return ret else: @@ -2313,7 +2313,7 @@ def route_table_present( } if __opts__["test"]: - ret["comment"] = "Route table {} would be created.".format(name) + ret["comment"] = f"Route table {name} would be created." ret["result"] = None return ret @@ -2326,12 +2326,12 @@ def route_table_present( disable_bgp_route_propagation=disable_bgp_route_propagation, routes=routes, tags=tags, - **rt_tbl_kwargs + **rt_tbl_kwargs, ) if "error" not in rt_tbl: ret["result"] = True - ret["comment"] = "Route table {} has been created.".format(name) + ret["comment"] = f"Route table {name} has been created." return ret ret["comment"] = "Failed to create route table {}! ({})".format( @@ -2371,11 +2371,11 @@ def route_table_absent(name, resource_group, connection_auth=None): if "error" in rt_tbl: ret["result"] = True - ret["comment"] = "Route table {} was not found.".format(name) + ret["comment"] = f"Route table {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Route table {} would be deleted.".format(name) + ret["comment"] = f"Route table {name} would be deleted." ret["result"] = None ret["changes"] = { "old": rt_tbl, @@ -2389,11 +2389,11 @@ def route_table_absent(name, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Route table {} has been deleted.".format(name) + ret["comment"] = f"Route table {name} has been deleted." ret["changes"] = {"old": rt_tbl, "new": {}} return ret - ret["comment"] = "Failed to delete route table {}!".format(name) + ret["comment"] = f"Failed to delete route table {name}!" return ret @@ -2406,7 +2406,7 @@ def route_present( resource_group, next_hop_ip_address=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -2489,12 +2489,12 @@ def route_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Route {} is already present.".format(name) + ret["comment"] = f"Route {name} is already present." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Route {} would be updated.".format(name) + ret["comment"] = f"Route {name} would be updated." return ret else: @@ -2509,7 +2509,7 @@ def route_present( } if __opts__["test"]: - ret["comment"] = "Route {} would be created.".format(name) + ret["comment"] = f"Route {name} would be created." ret["result"] = None return ret @@ -2523,12 +2523,12 @@ def route_present( address_prefix=address_prefix, next_hop_type=next_hop_type, next_hop_ip_address=next_hop_ip_address, - **route_kwargs + **route_kwargs, ) if "error" not in route: ret["result"] = True - ret["comment"] = "Route {} has been created.".format(name) + ret["comment"] = f"Route {name} has been created." return ret ret["comment"] = "Failed to create route {}! ({})".format(name, route.get("error")) @@ -2569,11 +2569,11 @@ def route_absent(name, route_table, resource_group, connection_auth=None): if "error" in route: ret["result"] = True - ret["comment"] = "Route {} was not found.".format(name) + ret["comment"] = f"Route {name} was not found." return ret elif __opts__["test"]: - ret["comment"] = "Route {} would be deleted.".format(name) + ret["comment"] = f"Route {name} would be deleted." ret["result"] = None ret["changes"] = { "old": route, @@ -2587,9 +2587,9 @@ def route_absent(name, route_table, resource_group, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Route {} has been deleted.".format(name) + ret["comment"] = f"Route {name} has been deleted." ret["changes"] = {"old": route, "new": {}} return ret - ret["comment"] = "Failed to delete route {}!".format(name) + ret["comment"] = f"Failed to delete route {name}!" return ret diff --git a/salt/states/azurearm_resource.py b/salt/states/azurearm_resource.py index 5cd896c4252..e8c8f819641 100644 --- a/salt/states/azurearm_resource.py +++ b/salt/states/azurearm_resource.py @@ -192,17 +192,17 @@ def resource_group_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Resource group {} is already present.".format(name) + ret["comment"] = f"Resource group {name} is already present." return ret if __opts__["test"]: - ret["comment"] = "Resource group {} tags would be updated.".format(name) + ret["comment"] = f"Resource group {name} tags would be updated." ret["result"] = None ret["changes"] = {"old": group.get("tags", {}), "new": tags} return ret elif __opts__["test"]: - ret["comment"] = "Resource group {} would be created.".format(name) + ret["comment"] = f"Resource group {name} would be created." ret["result"] = None ret["changes"] = { "old": {}, @@ -227,7 +227,7 @@ def resource_group_present( if present: ret["result"] = True - ret["comment"] = "Resource group {} has been created.".format(name) + ret["comment"] = f"Resource group {name} has been created." ret["changes"] = {"old": {}, "new": group} return ret @@ -267,7 +267,7 @@ def resource_group_absent(name, connection_auth=None): if not present: ret["result"] = True - ret["comment"] = "Resource group {} is already absent.".format(name) + ret["comment"] = f"Resource group {name} is already absent." return ret elif __opts__["test"]: @@ -275,7 +275,7 @@ def resource_group_absent(name, connection_auth=None): name, **connection_auth ) - ret["comment"] = "Resource group {} would be deleted.".format(name) + ret["comment"] = f"Resource group {name} would be deleted." ret["result"] = None ret["changes"] = { "old": group, @@ -297,11 +297,11 @@ def resource_group_absent(name, connection_auth=None): if not present: ret["result"] = True - ret["comment"] = "Resource group {} has been deleted.".format(name) + ret["comment"] = f"Resource group {name} has been deleted." ret["changes"] = {"old": group, "new": {}} return ret - ret["comment"] = "Failed to delete resource group {}!".format(name) + ret["comment"] = f"Failed to delete resource group {name}!" return ret @@ -322,7 +322,7 @@ def policy_definition_present( source_hash_name=None, skip_verify=False, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -450,7 +450,7 @@ def policy_definition_present( try: temp_rule = json.loads(policy_rule_json) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Unable to load policy rule json! ({})".format(exc) + ret["comment"] = f"Unable to load policy rule json! ({exc})" return ret elif policy_rule_file: try: @@ -468,7 +468,7 @@ def policy_definition_present( None, None, skip_verify=skip_verify, - **kwargs + **kwargs, ) except Exception as exc: # pylint: disable=broad-except ret["comment"] = 'Unable to locate policy rule file "{}"! ({})'.format( @@ -552,11 +552,11 @@ def policy_definition_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Policy definition {} is already present.".format(name) + ret["comment"] = f"Policy definition {name} is already present." return ret if __opts__["test"]: - ret["comment"] = "Policy definition {} would be updated.".format(name) + ret["comment"] = f"Policy definition {name} would be updated." ret["result"] = None return ret @@ -576,7 +576,7 @@ def policy_definition_present( } if __opts__["test"]: - ret["comment"] = "Policy definition {} would be created.".format(name) + ret["comment"] = f"Policy definition {name} would be created." ret["result"] = None return ret @@ -598,12 +598,12 @@ def policy_definition_present( description=description, metadata=metadata, parameters=parameters, - **policy_kwargs + **policy_kwargs, ) if "error" not in policy: ret["result"] = True - ret["comment"] = "Policy definition {} has been created.".format(name) + ret["comment"] = f"Policy definition {name} has been created." return ret ret["comment"] = "Failed to create policy definition {}! ({})".format( @@ -640,11 +640,11 @@ def policy_definition_absent(name, connection_auth=None): if "error" in policy: ret["result"] = True - ret["comment"] = "Policy definition {} is already absent.".format(name) + ret["comment"] = f"Policy definition {name} is already absent." return ret elif __opts__["test"]: - ret["comment"] = "Policy definition {} would be deleted.".format(name) + ret["comment"] = f"Policy definition {name} would be deleted." ret["result"] = None ret["changes"] = { "old": policy, @@ -658,11 +658,11 @@ def policy_definition_absent(name, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Policy definition {} has been deleted.".format(name) + ret["comment"] = f"Policy definition {name} has been deleted." ret["changes"] = {"old": policy, "new": {}} return ret - ret["comment"] = "Failed to delete policy definition {}!".format(name) + ret["comment"] = f"Failed to delete policy definition {name}!" return ret @@ -676,7 +676,7 @@ def policy_assignment_present( assignment_type=None, parameters=None, connection_auth=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -768,11 +768,11 @@ def policy_assignment_present( if not ret["changes"]: ret["result"] = True - ret["comment"] = "Policy assignment {} is already present.".format(name) + ret["comment"] = f"Policy assignment {name} is already present." return ret if __opts__["test"]: - ret["comment"] = "Policy assignment {} would be updated.".format(name) + ret["comment"] = f"Policy assignment {name} would be updated." ret["result"] = None return ret @@ -791,7 +791,7 @@ def policy_assignment_present( } if __opts__["test"]: - ret["comment"] = "Policy assignment {} would be created.".format(name) + ret["comment"] = f"Policy assignment {name} would be created." ret["result"] = None return ret @@ -808,12 +808,12 @@ def policy_assignment_present( display_name=display_name, description=description, parameters=parameters, - **policy_kwargs + **policy_kwargs, ) if "error" not in policy: ret["result"] = True - ret["comment"] = "Policy assignment {} has been created.".format(name) + ret["comment"] = f"Policy assignment {name} has been created." return ret ret["comment"] = "Failed to create policy assignment {}! ({})".format( @@ -853,11 +853,11 @@ def policy_assignment_absent(name, scope, connection_auth=None): if "error" in policy: ret["result"] = True - ret["comment"] = "Policy assignment {} is already absent.".format(name) + ret["comment"] = f"Policy assignment {name} is already absent." return ret elif __opts__["test"]: - ret["comment"] = "Policy assignment {} would be deleted.".format(name) + ret["comment"] = f"Policy assignment {name} would be deleted." ret["result"] = None ret["changes"] = { "old": policy, @@ -871,9 +871,9 @@ def policy_assignment_absent(name, scope, connection_auth=None): if deleted: ret["result"] = True - ret["comment"] = "Policy assignment {} has been deleted.".format(name) + ret["comment"] = f"Policy assignment {name} has been deleted." ret["changes"] = {"old": policy, "new": {}} return ret - ret["comment"] = "Failed to delete policy assignment {}!".format(name) + ret["comment"] = f"Failed to delete policy assignment {name}!" return ret diff --git a/salt/states/beacon.py b/salt/states/beacon.py index 088c8d308ec..b83717ae2bd 100644 --- a/salt/states/beacon.py +++ b/salt/states/beacon.py @@ -104,7 +104,7 @@ def present(name, save=False, **kwargs): if name in current_beacons: if beacon_data == current_beacons[name]: - ret["comment"].append("Job {} in correct state".format(name)) + ret["comment"].append(f"Job {name} in correct state") else: if __opts__.get("test"): kwargs["test"] = True @@ -119,7 +119,7 @@ def present(name, save=False, **kwargs): return ret else: if "changes" in result: - ret["comment"].append("Modifying {} in beacons".format(name)) + ret["comment"].append(f"Modifying {name} in beacons") ret["changes"] = result["changes"] else: ret["comment"].append(result["comment"]) @@ -136,14 +136,14 @@ def present(name, save=False, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Adding {} to beacons".format(name)) + ret["comment"].append(f"Adding {name} to beacons") if save: if __opts__.get("test"): - ret["comment"].append("Beacon {} would be saved".format(name)) + ret["comment"].append(f"Beacon {name} would be saved") else: __salt__["beacons.save"]() - ret["comment"].append("Beacon {} saved".format(name)) + ret["comment"].append(f"Beacon {name} saved") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -184,16 +184,16 @@ def absent(name, save=False, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Removed {} from beacons".format(name)) + ret["comment"].append(f"Removed {name} from beacons") else: - ret["comment"].append("{} not configured in beacons".format(name)) + ret["comment"].append(f"{name} not configured in beacons") if save: if __opts__.get("test"): - ret["comment"].append("Beacon {} would be saved".format(name)) + ret["comment"].append(f"Beacon {name} would be saved") else: __salt__["beacons.save"]() - ret["comment"].append("Beacon {} saved".format(name)) + ret["comment"].append(f"Beacon {name} saved") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -231,9 +231,9 @@ def enabled(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Enabled {} from beacons".format(name)) + ret["comment"].append(f"Enabled {name} from beacons") else: - ret["comment"].append("{} not a configured beacon".format(name)) + ret["comment"].append(f"{name} not a configured beacon") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -271,9 +271,9 @@ def disabled(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Disabled beacon {}.".format(name)) + ret["comment"].append(f"Disabled beacon {name}.") else: - ret["comment"].append("Job {} is not configured.".format(name)) + ret["comment"].append(f"Job {name} is not configured.") ret["comment"] = "\n".join(ret["comment"]) return ret diff --git a/salt/states/bigip.py b/salt/states/bigip.py index 2b72e4b7530..9f494ac20c5 100644 --- a/salt/states/bigip.py +++ b/salt/states/bigip.py @@ -1628,9 +1628,7 @@ def modify_pool_member( # check for changes old = {"content": existing_member} new = {"content": modified_member} - ret = _check_for_changes( - "Pool Member: {member}".format(member=member), ret, old, new - ) + ret = _check_for_changes(f"Pool Member: {member}", ret, old, new) else: ret = _load_result(modified, ret) diff --git a/salt/states/blockdev.py b/salt/states/blockdev.py index c8218e68b3d..0f85f3485e5 100644 --- a/salt/states/blockdev.py +++ b/salt/states/blockdev.py @@ -82,7 +82,7 @@ def tuned(name, **kwargs): name ) elif __opts__["test"]: - ret["comment"] = "Changes to {} will be applied ".format(name) + ret["comment"] = f"Changes to {name} will be applied " ret["result"] = None return ret else: @@ -102,15 +102,15 @@ def tuned(name, **kwargs): if key == "read-write": old = not old new = not new - changeset[key] = "Changed from {} to {}".format(old, new) + changeset[key] = f"Changed from {old} to {new}" if changes: if changeset: - ret["comment"] = "Block device {} successfully modified ".format(name) + ret["comment"] = f"Block device {name} successfully modified " ret["changes"] = changeset else: - ret["comment"] = "Block device {} already in correct state".format(name) + ret["comment"] = f"Block device {name} already in correct state" else: - ret["comment"] = "Failed to modify block device {}".format(name) + ret["comment"] = f"Failed to modify block device {name}" ret["result"] = False return ret @@ -136,13 +136,13 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): """ ret = { "changes": {}, - "comment": "{} already formatted with {}".format(name, fs_type), + "comment": f"{name} already formatted with {fs_type}", "name": name, "result": False, } if not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" return ret current_fs = _checkblk(name) @@ -150,12 +150,12 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): if current_fs == fs_type: ret["result"] = True return ret - elif not salt.utils.path.which("mkfs.{}".format(fs_type)): - ret["comment"] = "Invalid fs_type: {}".format(fs_type) + elif not salt.utils.path.which(f"mkfs.{fs_type}"): + ret["comment"] = f"Invalid fs_type: {fs_type}" ret["result"] = False return ret elif __opts__["test"]: - ret["comment"] = "Changes to {} will be applied ".format(name) + ret["comment"] = f"Changes to {name} will be applied " ret["result"] = None return ret @@ -171,7 +171,7 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): current_fs = _checkblk(name) if current_fs == fs_type: - ret["comment"] = "{} has been formatted with {}".format(name, fs_type) + ret["comment"] = f"{name} has been formatted with {fs_type}" ret["changes"] = {"new": fs_type, "old": current_fs} ret["result"] = True return ret @@ -182,7 +182,7 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): else: break - ret["comment"] = "Failed to format {}".format(name) + ret["comment"] = f"Failed to format {name}" ret["result"] = False return ret diff --git a/salt/states/boto3_elasticache.py b/salt/states/boto3_elasticache.py index 0cf1a867851..d2d5774a4b5 100644 --- a/salt/states/boto3_elasticache.py +++ b/salt/states/boto3_elasticache.py @@ -173,7 +173,7 @@ def cache_cluster_present( key=None, keyid=None, profile=None, - **args + **args, ): """ Ensure a given cache cluster exists. @@ -444,7 +444,7 @@ def cache_cluster_present( else: create_args[k] = v if __opts__["test"]: - ret["comment"] = "Cache cluster {} would be created.".format(name) + ret["comment"] = f"Cache cluster {name} would be created." ret["result"] = None return ret created = __salt__["boto3_elasticache.create_cache_cluster"]( @@ -455,18 +455,18 @@ def cache_cluster_present( key=key, keyid=keyid, profile=profile, - **create_args + **create_args, ) if created: new = __salt__["boto3_elasticache.describe_cache_clusters"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Cache cluster {} was created.".format(name) + ret["comment"] = f"Cache cluster {name} was created." ret["changes"]["old"] = None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to create {} cache cluster.".format(name) + ret["comment"] = f"Failed to create {name} cache cluster." if check_update: # Refresh this in case we're updating from 'only_on_modify' above... @@ -476,7 +476,7 @@ def cache_cluster_present( need_update = _diff_cache_cluster(updated["CacheClusters"][0], args) if need_update: if __opts__["test"]: - ret["comment"] = "Cache cluster {} would be modified.".format(name) + ret["comment"] = f"Cache cluster {name} would be modified." ret["result"] = None return ret modified = __salt__["boto3_elasticache.modify_cache_cluster"]( @@ -487,7 +487,7 @@ def cache_cluster_present( key=key, keyid=keyid, profile=profile, - **need_update + **need_update, ) if modified: new = __salt__["boto3_elasticache.describe_cache_clusters"]( @@ -496,14 +496,14 @@ def cache_cluster_present( if ret["comment"]: # 'create' just ran... ret["comment"] += " ... and then immediately modified." else: - ret["comment"] = "Cache cluster {} was modified.".format(name) + ret["comment"] = f"Cache cluster {name} was modified." ret["changes"]["old"] = current ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to modify cache cluster {}.".format(name) + ret["comment"] = f"Failed to modify cache cluster {name}." else: - ret["comment"] = "Cache cluster {} is in the desired state.".format(name) + ret["comment"] = f"Cache cluster {name} is in the desired state." return ret @@ -552,7 +552,7 @@ def cache_cluster_absent( ) if exists: if __opts__["test"]: - ret["comment"] = "Cache cluster {} would be removed.".format(name) + ret["comment"] = f"Cache cluster {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto3_elasticache.delete_cache_cluster"]( @@ -562,16 +562,16 @@ def cache_cluster_absent( key=key, keyid=keyid, profile=profile, - **args + **args, ) if deleted: ret["changes"]["old"] = name ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} cache cluster.".format(name) + ret["comment"] = f"Failed to delete {name} cache cluster." else: - ret["comment"] = "Cache cluster {} already absent.".format(name) + ret["comment"] = f"Cache cluster {name} already absent." return ret @@ -637,7 +637,7 @@ def replication_group_present( key=None, keyid=None, profile=None, - **args + **args, ): """ Ensure a replication group exists and is in the given state. @@ -896,7 +896,7 @@ def replication_group_present( else: create_args[k] = v if __opts__["test"]: - ret["comment"] = "Replication group {} would be created.".format(name) + ret["comment"] = f"Replication group {name} would be created." ret["result"] = None return ret created = __salt__["boto3_elasticache.create_replication_group"]( @@ -907,18 +907,18 @@ def replication_group_present( key=key, keyid=keyid, profile=profile, - **create_args + **create_args, ) if created: new = __salt__["boto3_elasticache.describe_replication_groups"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Replication group {} was created.".format(name) + ret["comment"] = f"Replication group {name} was created." ret["changes"]["old"] = None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to create {} replication group.".format(name) + ret["comment"] = f"Failed to create {name} replication group." if check_update: # Refresh this in case we're updating from 'only_on_modify' above... @@ -928,7 +928,7 @@ def replication_group_present( need_update = _diff_replication_group(updated, args) if need_update: if __opts__["test"]: - ret["comment"] = "Replication group {} would be modified.".format(name) + ret["comment"] = f"Replication group {name} would be modified." ret["result"] = None return ret modified = __salt__["boto3_elasticache.modify_replication_group"]( @@ -939,7 +939,7 @@ def replication_group_present( key=key, keyid=keyid, profile=profile, - **need_update + **need_update, ) if modified: new = __salt__["boto3_elasticache.describe_replication_groups"]( @@ -948,12 +948,12 @@ def replication_group_present( if ret["comment"]: # 'create' just ran... ret["comment"] += " ... and then immediately modified." else: - ret["comment"] = "Replication group {} was modified.".format(name) + ret["comment"] = f"Replication group {name} was modified." ret["changes"]["old"] = current[0] if current else None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to modify replication group {}.".format(name) + ret["comment"] = f"Failed to modify replication group {name}." else: ret["comment"] = "Replication group {} is in the desired state.".format( name @@ -1010,7 +1010,7 @@ def replication_group_absent( ) if exists: if __opts__["test"]: - ret["comment"] = "Replication group {} would be removed.".format(name) + ret["comment"] = f"Replication group {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto3_elasticache.delete_replication_group"]( @@ -1020,16 +1020,16 @@ def replication_group_absent( key=key, keyid=keyid, profile=profile, - **args + **args, ) if deleted: ret["changes"]["old"] = name ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} replication group.".format(name) + ret["comment"] = f"Failed to delete {name} replication group." else: - ret["comment"] = "Replication group {} already absent.".format(name) + ret["comment"] = f"Replication group {name} already absent." return ret @@ -1113,7 +1113,7 @@ def cache_subnet_group_present( else: check_update = False if __opts__["test"]: - ret["comment"] = "Cache subnet group {} would be created.".format(name) + ret["comment"] = f"Cache subnet group {name} would be created." ret["result"] = None return ret created = __salt__["boto3_elasticache.create_cache_subnet_group"]( @@ -1123,24 +1123,24 @@ def cache_subnet_group_present( key=key, keyid=keyid, profile=profile, - **args + **args, ) if created: new = __salt__["boto3_elasticache.describe_cache_subnet_groups"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Cache subnet group {} was created.".format(name) + ret["comment"] = f"Cache subnet group {name} was created." ret["changes"]["old"] = None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to create {} cache subnet group.".format(name) + ret["comment"] = f"Failed to create {name} cache subnet group." if check_update: need_update = _diff_cache_subnet_group(current, args) if need_update: if __opts__["test"]: - ret["comment"] = "Cache subnet group {} would be modified.".format(name) + ret["comment"] = f"Cache subnet group {name} would be modified." ret["result"] = None return ret modified = __salt__["boto3_elasticache.modify_cache_subnet_group"]( @@ -1150,18 +1150,18 @@ def cache_subnet_group_present( key=key, keyid=keyid, profile=profile, - **need_update + **need_update, ) if modified: new = __salt__["boto3_elasticache.describe_cache_subnet_groups"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Cache subnet group {} was modified.".format(name) + ret["comment"] = f"Cache subnet group {name} was modified." ret["changes"]["old"] = current["CacheSubetGroups"][0] ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to modify cache subnet group {}.".format(name) + ret["comment"] = f"Failed to modify cache subnet group {name}." else: ret["comment"] = "Cache subnet group {} is in the desired state.".format( name @@ -1202,7 +1202,7 @@ def cache_subnet_group_absent( ) if exists: if __opts__["test"]: - ret["comment"] = "Cache subnet group {} would be removed.".format(name) + ret["comment"] = f"Cache subnet group {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto3_elasticache.delete_cache_subnet_group"]( @@ -1213,7 +1213,7 @@ def cache_subnet_group_absent( ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} cache_subnet group.".format(name) + ret["comment"] = f"Failed to delete {name} cache_subnet group." else: - ret["comment"] = "Cache subnet group {} already absent.".format(name) + ret["comment"] = f"Cache subnet group {name} already absent." return ret diff --git a/salt/states/boto3_elasticsearch.py b/salt/states/boto3_elasticsearch.py index ac50995660c..9a908f33ae7 100644 --- a/salt/states/boto3_elasticsearch.py +++ b/salt/states/boto3_elasticsearch.py @@ -72,7 +72,7 @@ def __virtual__(): if req not in __salt__: return ( False, - "A required function was not found in __salt__: {}".format(req), + f"A required function was not found in __salt__: {req}", ) return __virtualname__ @@ -377,7 +377,7 @@ def present( else: ret["result"] = True ret["comment"].append( - 'Elasticsearch Domain "{}" has been {}d.'.format(name, action) + f'Elasticsearch Domain "{name}" has been {action}d.' ) ret["changes"] = config_diff elif action == "upgrade": @@ -454,7 +454,7 @@ def absent(name, blocking=True, region=None, keyid=None, key=None, profile=None) if __opts__["test"]: ret["result"] = None ret["comment"].append( - 'Elasticsearch domain "{}" would have been removed.'.format(name) + f'Elasticsearch domain "{name}" would have been removed.' ) ret["changes"] = {"old": name, "new": None} else: @@ -476,14 +476,12 @@ def absent(name, blocking=True, region=None, keyid=None, key=None, profile=None) else: ret["result"] = True ret["comment"].append( - 'Elasticsearch domain "{}" has been deleted.'.format(name) + f'Elasticsearch domain "{name}" has been deleted.' ) ret["changes"] = {"old": name, "new": None} else: ret["result"] = True - ret["comment"].append( - 'Elasticsearch domain "{}" is already absent.'.format(name) - ) + ret["comment"].append(f'Elasticsearch domain "{name}" is already absent.') ret = _check_return_value(ret) return ret @@ -528,9 +526,7 @@ def upgraded( if not res["result"]: ret["result"] = False if "ResourceNotFoundException" in res["error"]: - ret["comment"].append( - 'The Elasticsearch domain "{}" does not exist.'.format(name) - ) + ret["comment"].append(f'The Elasticsearch domain "{name}" does not exist.') else: ret["comment"].append(res["error"]) else: @@ -726,9 +722,7 @@ def latest(name, minor_only=True, region=None, keyid=None, key=None, profile=Non pass if not current_version: ret["result"] = True - ret["comment"].append( - 'The Elasticsearch domain "{}" can not be upgraded.'.format(name) - ) + ret["comment"].append(f'The Elasticsearch domain "{name}" can not be upgraded.') elif not latest_version: ret["result"] = True ret["comment"].append( @@ -818,7 +812,7 @@ def tagged( current_tags = res["response"] or {} else: ret["result"] = False - ret["comment"].append('Elasticsearch domain "{}" does not exist.'.format(name)) + ret["comment"].append(f'Elasticsearch domain "{name}" does not exist.') if isinstance(ret["result"], bool): return ret @@ -826,7 +820,7 @@ def tagged( if not diff_tags: ret["result"] = True ret["comment"].append( - 'Elasticsearch domain "{}" already has the specified tags.'.format(name) + f'Elasticsearch domain "{name}" already has the specified tags.' ) else: if replace: diff --git a/salt/states/boto3_route53.py b/salt/states/boto3_route53.py index 7cd3ede3452..7b1a5fdf3ab 100644 --- a/salt/states/boto3_route53.py +++ b/salt/states/boto3_route53.py @@ -241,7 +241,7 @@ def hosted_zone_present( update_comment = True if not (create or add_vpcs or del_vpcs or update_comment): - ret["comment"] = "Hostd Zone {} already in desired state".format(Name) + ret["comment"] = f"Hostd Zone {Name} already in desired state" return ret if create: @@ -745,7 +745,7 @@ def rr_present( # this appears to be incredibly difficult with the jinja templating engine # so inject the quotations here to make a viable ChangeBatch if Type == "TXT": - rr = '"{}"'.format(rr) + rr = f'"{rr}"' fixed_rrs += [rr] ResourceRecords = [{"Value": rr} for rr in sorted(fixed_rrs)] diff --git a/salt/states/boto3_sns.py b/salt/states/boto3_sns.py index b47b4447288..feeca5602c1 100644 --- a/salt/states/boto3_sns.py +++ b/salt/states/boto3_sns.py @@ -135,11 +135,11 @@ def topic_present( something_changed = False current = __salt__["boto3_sns.describe_topic"](name, region, key, keyid, profile) if current: - ret["comment"] = "AWS SNS topic {} present.".format(name) + ret["comment"] = f"AWS SNS topic {name} present." TopicArn = current["TopicArn"] else: if __opts__["test"]: - ret["comment"] = "AWS SNS topic {} would be created.".format(name) + ret["comment"] = f"AWS SNS topic {name} would be created." ret["result"] = None return ret else: @@ -152,7 +152,7 @@ def topic_present( ) something_changed = True else: - ret["comment"] = "Failed to create AWS SNS topic {}".format(name) + ret["comment"] = f"Failed to create AWS SNS topic {name}" log.error(ret["comment"]) ret["result"] = False return ret @@ -246,7 +246,7 @@ def topic_present( TopicArn, prot, endp, region=region, key=key, keyid=keyid, profile=profile ) if subbed: - msg = " Subscription {}:{} set on topic {}.".format(prot, endp, TopicArn) + msg = f" Subscription {prot}:{endp} set on topic {TopicArn}." ret["comment"] += msg something_changed = True else: @@ -318,11 +318,11 @@ def topic_absent( something_changed = False current = __salt__["boto3_sns.describe_topic"](name, region, key, keyid, profile) if not current: - ret["comment"] = "AWS SNS topic {} absent.".format(name) + ret["comment"] = f"AWS SNS topic {name} absent." else: TopicArn = current["TopicArn"] if __opts__["test"]: - ret["comment"] = "AWS SNS topic {} would be removed.".format(TopicArn) + ret["comment"] = f"AWS SNS topic {TopicArn} would be removed." if unsubscribe: ret["comment"] += " {} subscription(s) would be removed.".format( len(current["Subscriptions"]) @@ -360,17 +360,14 @@ def topic_absent( if not __salt__["boto3_sns.delete_topic"]( TopicArn, region=region, key=key, keyid=keyid, profile=profile ): - ret["comment"] = "Failed to delete SNS topic {}".format(TopicArn) + ret["comment"] = f"Failed to delete SNS topic {TopicArn}" log.error(ret["comment"]) ret["result"] = False else: - ret["comment"] = "AWS SNS topic {} deleted.".format(TopicArn) + ret["comment"] = f"AWS SNS topic {TopicArn} deleted." if unsubscribe: ret["comment"] += " ".join( - [ - "Subscription {} deleted".format(s) - for s in current["Subscriptions"] - ] + [f"Subscription {s} deleted" for s in current["Subscriptions"]] ) something_changed = True diff --git a/salt/states/boto_apigateway.py b/salt/states/boto_apigateway.py index 32aad36f677..554f574c8a3 100644 --- a/salt/states/boto_apigateway.py +++ b/salt/states/boto_apigateway.py @@ -349,7 +349,7 @@ def present( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -434,7 +434,7 @@ def absent( swagger = _Swagger(api_name, stage_name, "", None, None, None, common_args) if not swagger.restApiId: - ret["comment"] = "[Rest API: {}] does not exist.".format(api_name) + ret["comment"] = f"[Rest API: {api_name}] does not exist." return ret if __opts__["test"]: @@ -445,7 +445,7 @@ def absent( "deleted.".format(stage_name, api_name) ) else: - ret["comment"] = "[stage: {}] will be deleted.".format(stage_name) + ret["comment"] = f"[stage: {stage_name}] will be deleted." ret["result"] = None return ret @@ -459,7 +459,7 @@ def absent( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -724,11 +724,11 @@ class _Swagger: _name = self._paramdict.get("name") if _name: if self.location == "header": - return "method.request.header.{}".format(_name) + return f"method.request.header.{_name}" elif self.location == "query": - return "method.request.querystring.{}".format(_name) + return f"method.request.querystring.{_name}" elif self.location == "path": - return "method.request.path.{}".format(_name) + return f"method.request.path.{_name}" return None raise ValueError( "Parameter must have a name: {}".format( @@ -753,9 +753,7 @@ class _Swagger: self.name ) ) - raise ValueError( - "Body parameter must have a schema: {}".format(self.name) - ) + raise ValueError(f"Body parameter must have a schema: {self.name}") return None class SwaggerMethodResponse: @@ -818,7 +816,7 @@ class _Swagger: self._cfg = salt.utils.yaml.safe_load(sf) self._swagger_version = "" else: - raise OSError("Invalid swagger file path, {}".format(swagger_file_path)) + raise OSError(f"Invalid swagger file path, {swagger_file_path}") self._validate_swagger_file() @@ -876,7 +874,7 @@ class _Swagger: if model.get("type") != "object": raise ValueError( - "model schema {} must be type object".format(modelname) + f"model schema {modelname} must be type object" ) if "properties" not in model: raise ValueError( @@ -927,12 +925,12 @@ class _Swagger: field not in _Swagger.SWAGGER_OBJ_V2_FIELDS and not _Swagger.VENDOR_EXT_PATTERN.match(field) ): - raise ValueError("Invalid Swagger Object Field: {}".format(field)) + raise ValueError(f"Invalid Swagger Object Field: {field}") # check for Required Swagger fields by Saltstack boto apigateway state for field in _Swagger.SWAGGER_OBJ_V2_FIELDS_REQUIRED: if field not in self._cfg: - raise ValueError("Missing Swagger Object Field: {}".format(field)) + raise ValueError(f"Missing Swagger Object Field: {field}") # check for Swagger Version self._swagger_version = self._cfg.get("swagger") @@ -1026,7 +1024,7 @@ class _Swagger: for path in paths: if not path.startswith("/"): raise ValueError( - "Path object {} should start with /. Please fix it".format(path) + f"Path object {path} should start with /. Please fix it" ) return paths.items() @@ -1099,7 +1097,7 @@ class _Swagger: stages = __salt__["boto_apigateway.describe_api_stages"]( restApiId=self.restApiId, deploymentId=deploymentId, - **self._common_aws_args + **self._common_aws_args, ).get("stages") if stages: no_more_deployments = False @@ -1115,7 +1113,7 @@ class _Swagger: stage = __salt__["boto_apigateway.describe_api_stage"]( restApiId=self.restApiId, stageName=self._stage_name, - **self._common_aws_args + **self._common_aws_args, ).get("stage") if stage: deploymentId = stage.get("deploymentId") @@ -1155,7 +1153,7 @@ class _Swagger: restApiId=self.restApiId, stageName=self._stage_name, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not res.get("overwrite"): @@ -1173,7 +1171,7 @@ class _Swagger: stage = __salt__["boto_apigateway.describe_api_stage"]( restApiId=self.restApiId, stageName=self._stage_name, - **self._common_aws_args + **self._common_aws_args, ).get("stage") if not stage: stage = __salt__["boto_apigateway.create_api_stage"]( @@ -1182,7 +1180,7 @@ class _Swagger: deploymentId=self._deploymentId, description=stage_desc_json, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not stage.get("stage"): return {"set": False, "error": stage.get("error")} @@ -1192,7 +1190,7 @@ class _Swagger: restApiId=self.restApiId, stageName=self._stage_name, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not overwrite.get("stage"): return {"set": False, "error": overwrite.get("error")} @@ -1201,7 +1199,7 @@ class _Swagger: restApiId=self.restApiId, stageName=self._stage_name, deploymentId=self._deploymentId, - **self._common_aws_args + **self._common_aws_args, ) def _resolve_api_id(self): @@ -1212,7 +1210,7 @@ class _Swagger: apis = __salt__["boto_apigateway.describe_apis"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ).get("restapi") if apis: if len(apis) == 1: @@ -1235,7 +1233,7 @@ class _Swagger: result = __salt__["boto_apigateway.delete_api_stage"]( restApiId=self.restApiId, stageName=self._stage_name, - **self._common_aws_args + **self._common_aws_args, ) if not result.get("deleted"): ret["abort"] = True @@ -1249,7 +1247,7 @@ class _Swagger: result = __salt__["boto_apigateway.delete_api_deployment"]( restApiId=self.restApiId, deploymentId=deploymentId, - **self._common_aws_args + **self._common_aws_args, ) if not result.get("deleted"): ret["abort"] = True @@ -1265,7 +1263,7 @@ class _Swagger: ) else: # no matching stage_name/deployment found - ret["comment"] = "stage {} does not exist".format(self._stage_name) + ret["comment"] = f"stage {self._stage_name} does not exist" return ret @@ -1326,7 +1324,7 @@ class _Swagger: stageDescription=stage_desc_json, description=self.deployment_label_json, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not res.get("created"): ret["abort"] = True @@ -1353,7 +1351,7 @@ class _Swagger: delres = __salt__["boto_apigateway.delete_api_resources"]( restApiId=self.restApiId, path=resource.get("path"), - **self._common_aws_args + **self._common_aws_args, ) if not delres.get("deleted"): return delres @@ -1366,7 +1364,7 @@ class _Swagger: delres = __salt__["boto_apigateway.delete_api_model"]( restApiId=self.restApiId, modelName=model.get("name"), - **self._common_aws_args + **self._common_aws_args, ) if not delres.get("deleted"): return delres @@ -1380,7 +1378,7 @@ class _Swagger: if self.restApiId: res = self._cleanup_api() if not res.get("deleted"): - ret["comment"] = "Failed to cleanup restAreId {}".format(self.restApiId) + ret["comment"] = f"Failed to cleanup restAreId {self.restApiId}" ret["abort"] = True ret["result"] = False return ret @@ -1389,7 +1387,7 @@ class _Swagger: response = __salt__["boto_apigateway.create_api"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ) if not response.get("created"): @@ -1416,7 +1414,7 @@ class _Swagger: exists_response = __salt__["boto_apigateway.api_exists"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ) if exists_response.get("exists"): if __opts__["test"]: @@ -1430,7 +1428,7 @@ class _Swagger: delete_api_response = __salt__["boto_apigateway.delete_api"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ) if not delete_api_response.get("deleted"): ret["result"] = False @@ -1552,7 +1550,7 @@ class _Swagger: _schema.update( { "$schema": _Swagger.JSON_SCHEMA_DRAFT_4, - "title": "{} Schema".format(model), + "title": f"{model} Schema", } ) @@ -1569,7 +1567,7 @@ class _Swagger: restApiId=self.restApiId, modelName=model, schema=_dict_to_json_pretty(_schema), - **self._common_aws_args + **self._common_aws_args, ) if not update_model_schema_response.get("updated"): ret["result"] = False @@ -1593,7 +1591,7 @@ class _Swagger: modelDescription=model, schema=_dict_to_json_pretty(_schema), contentType="application/json", - **self._common_aws_args + **self._common_aws_args, ) if not create_model_response.get("created"): @@ -1744,7 +1742,7 @@ class _Swagger: method_response_params = {} method_integration_response_params = {} for header in method_response.headers: - response_header = "method.response.header.{}".format(header) + response_header = f"method.response.header.{header}" method_response_params[response_header] = False header_data = method_response.headers.get(header) method_integration_response_params[response_header] = ( @@ -1821,7 +1819,7 @@ class _Swagger: apiKeyRequired=api_key_required, requestParameters=method.get("params"), requestModels=method.get("models"), - **self._common_aws_args + **self._common_aws_args, ) if not m.get("created"): ret = _log_error_and_abort(ret, m) @@ -1847,7 +1845,7 @@ class _Swagger: uri=lambda_uri, credentials=lambda_integration_role, requestTemplates=method.get("request_templates"), - **self._common_aws_args + **self._common_aws_args, ) if not integration.get("created"): ret = _log_error_and_abort(ret, integration) @@ -1870,7 +1868,7 @@ class _Swagger: statusCode=httpStatus, responseParameters=method_response.get("params"), responseModels=method_response.get("models"), - **self._common_aws_args + **self._common_aws_args, ) if not mr.get("created"): ret = _log_error_and_abort(ret, mr) @@ -1885,7 +1883,7 @@ class _Swagger: selectionPattern=method_response.get("pattern"), responseParameters=method_response.get("integration_params"), responseTemplates=method_response.get("response_templates"), - **self._common_aws_args + **self._common_aws_args, ) if not mir.get("created"): ret = _log_error_and_abort(ret, mir) @@ -1895,7 +1893,7 @@ class _Swagger: ) else: raise ValueError( - "No responses specified for {} {}".format(resource_path, method_name) + f"No responses specified for {resource_path} {method_name}" ) return ret @@ -2042,7 +2040,7 @@ def usage_plan_present( description=description, throttle=throttle, quota=quota, - **common_args + **common_args, ) if "error" in result: ret["result"] = False @@ -2052,7 +2050,7 @@ def usage_plan_present( return ret ret["changes"]["old"] = {"plan": None} - ret["comment"] = "A new usage plan {} has been created".format(plan_name) + ret["comment"] = f"A new usage plan {plan_name} has been created" else: # need an existing plan modified to match given value @@ -2097,7 +2095,7 @@ def usage_plan_present( return ret ret["changes"]["old"] = {"plan": plan} - ret["comment"] = "usage plan {} has been updated".format(plan_name) + ret["comment"] = f"usage plan {plan_name} has been updated" newstate = __salt__["boto_apigateway.describe_usage_plans"]( name=plan_name, **common_args @@ -2111,7 +2109,7 @@ def usage_plan_present( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -2152,7 +2150,7 @@ def usage_plan_absent(name, plan_name, region=None, key=None, keyid=None, profil return ret if not existing["plans"]: - ret["comment"] = "Usage plan {} does not exist already".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} does not exist already" return ret if __opts__["test"]: @@ -2172,13 +2170,13 @@ def usage_plan_absent(name, plan_name, region=None, key=None, keyid=None, profil ) return ret - ret["comment"] = "Usage plan {} has been deleted".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} has been deleted" ret["changes"]["old"] = {"plan": existing["plans"][0]} ret["changes"]["new"] = {"plan": None} except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -2234,7 +2232,7 @@ def usage_plan_association_present( return ret if not existing["plans"]: - ret["comment"] = "Usage plan {} does not exist".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} does not exist" ret["result"] = False return ret @@ -2277,7 +2275,7 @@ def usage_plan_association_present( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -2335,7 +2333,7 @@ def usage_plan_association_absent( return ret if not existing["plans"]: - ret["comment"] = "Usage plan {} does not exist".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} does not exist" ret["result"] = False return ret @@ -2384,6 +2382,6 @@ def usage_plan_association_absent( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret diff --git a/salt/states/boto_asg.py b/salt/states/boto_asg.py index 2734aec50c3..64d44574773 100644 --- a/salt/states/boto_asg.py +++ b/salt/states/boto_asg.py @@ -449,7 +449,7 @@ def present( ret["result"] = False return ret if "id" not in r: - ret["comment"] = "Subnet {} does not exist.".format(i) + ret["comment"] = f"Subnet {i} does not exist." ret["result"] = False return ret vpc_zone_identifier.append(r["id"]) @@ -829,7 +829,7 @@ def _alarms_present( if "scaling_policy" not in action: scaling_policy_actions_only = False if ":self:" in action: - action = action.replace(":self:", ":{}:".format(name)) + action = action.replace(":self:", f":{name}:") new_actions.append(action) info["attributes"][action_type] = new_actions # skip alarms that only have actions for scaling policy, if min_size == max_size for this ASG diff --git a/salt/states/boto_cfn.py b/salt/states/boto_cfn.py index 971514a3b6b..bd748eb410f 100644 --- a/salt/states/boto_cfn.py +++ b/salt/states/boto_cfn.py @@ -56,7 +56,7 @@ def __virtual__(): else: return ( False, - "Cannot load {} state: boto_cfn module unavailable".format(__virtualname__), + f"Cannot load {__virtualname__} state: boto_cfn module unavailable", ) @@ -177,7 +177,7 @@ def present( log.debug("Templates are not the same. Compare value is %s", compare) # At this point we should be able to run update safely since we already validated the template if __opts__["test"]: - ret["comment"] = "Stack {} is set to be updated.".format(name) + ret["comment"] = f"Stack {name} is set to be updated." ret["result"] = None return ret updated = __salt__["boto_cfn.update_stack"]( @@ -213,11 +213,11 @@ def present( ) ret["changes"]["new"] = updated return ret - ret["comment"] = "Stack {} exists.".format(name) + ret["comment"] = f"Stack {name} exists." ret["changes"] = {} return ret if __opts__["test"]: - ret["comment"] = "Stack {} is set to be created.".format(name) + ret["comment"] = f"Stack {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_cfn.create"]( @@ -239,7 +239,7 @@ def present( profile, ) if created: - ret["comment"] = "Stack {} was created.".format(name) + ret["comment"] = f"Stack {name} was created." ret["changes"]["new"] = created return ret ret["result"] = False @@ -263,11 +263,11 @@ def absent(name, region=None, key=None, keyid=None, profile=None): """ ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_cfn.exists"](name, region, key, keyid, profile): - ret["comment"] = "Stack {} does not exist.".format(name) + ret["comment"] = f"Stack {name} does not exist." ret["changes"] = {} return ret if __opts__["test"]: - ret["comment"] = "Stack {} is set to be deleted.".format(name) + ret["comment"] = f"Stack {name} is set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_cfn.delete"](name, region, key, keyid, profile) @@ -280,7 +280,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret["changes"] = {} return ret if deleted: - ret["comment"] = "Stack {} was deleted.".format(name) + ret["comment"] = f"Stack {name} was deleted." ret["changes"]["deleted"] = name return ret @@ -293,7 +293,7 @@ def _get_template(template, name): return __salt__["cp.get_file_str"](template) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(template) + ret["comment"] = f"File {template} not found." ret["result"] = False return ret return template diff --git a/salt/states/boto_cloudfront.py b/salt/states/boto_cloudfront.py index fbfe1602eaa..0bdd44d13bb 100644 --- a/salt/states/boto_cloudfront.py +++ b/salt/states/boto_cloudfront.py @@ -131,7 +131,7 @@ def present( if old is None: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Distribution {} set for creation.".format(name) + ret["comment"] = f"Distribution {name} set for creation." ret["changes"] = {"old": None, "new": name} return ret @@ -153,7 +153,7 @@ def present( return ret ret["result"] = True - ret["comment"] = "Created distribution {}.".format(name) + ret["comment"] = f"Created distribution {name}." ret["changes"] = {"old": None, "new": name} return ret else: @@ -198,7 +198,7 @@ def present( if __opts__["test"]: ret["result"] = None ret["comment"] = "\n".join( - ["Distribution {} set for new config:".format(name), changes_diff] + [f"Distribution {name} set for new config:", changes_diff] ) ret["changes"] = {"diff": changes_diff} return ret @@ -221,6 +221,6 @@ def present( return ret ret["result"] = True - ret["comment"] = "Updated distribution {}.".format(name) + ret["comment"] = f"Updated distribution {name}." ret["changes"] = {"diff": changes_diff} return ret diff --git a/salt/states/boto_cloudtrail.py b/salt/states/boto_cloudtrail.py index dc8a12b153a..d4cf62f5be3 100644 --- a/salt/states/boto_cloudtrail.py +++ b/salt/states/boto_cloudtrail.py @@ -164,7 +164,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "CloudTrail {} is set to be created.".format(Name) + ret["comment"] = f"CloudTrail {Name} is set to be created." ret["result"] = None return ret r = __salt__["boto_cloudtrail.create"]( @@ -192,7 +192,7 @@ def present( ) ret["changes"]["old"] = {"trail": None} ret["changes"]["new"] = _describe - ret["comment"] = "CloudTrail {} created.".format(Name) + ret["comment"] = f"CloudTrail {Name} created." if LoggingEnabled: r = __salt__["boto_cloudtrail.start_logging"]( @@ -223,9 +223,7 @@ def present( ret["changes"]["new"]["trail"]["Tags"] = Tags return ret - ret["comment"] = os.linesep.join( - [ret["comment"], "CloudTrail {} is present.".format(Name)] - ) + ret["comment"] = os.linesep.join([ret["comment"], f"CloudTrail {Name} is present."]) ret["changes"] = {} # trail exists, ensure config matches _describe = __salt__["boto_cloudtrail.describe"]( @@ -277,7 +275,7 @@ def present( if need_update: if __opts__["test"]: - msg = "CloudTrail {} set to be modified.".format(Name) + msg = f"CloudTrail {Name} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -344,7 +342,7 @@ def present( key=key, keyid=keyid, profile=profile, - **adds + **adds, ) if bool(removes): r = __salt__["boto_cloudtrail.remove_tags"]( @@ -353,7 +351,7 @@ def present( key=key, keyid=keyid, profile=profile, - **removes + **removes, ) return ret @@ -394,11 +392,11 @@ def absent(name, Name, region=None, key=None, keyid=None, profile=None): return ret if r and not r["exists"]: - ret["comment"] = "CloudTrail {} does not exist.".format(Name) + ret["comment"] = f"CloudTrail {Name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "CloudTrail {} is set to be removed.".format(Name) + ret["comment"] = f"CloudTrail {Name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_cloudtrail.delete"]( @@ -410,5 +408,5 @@ def absent(name, Name, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"trail": Name} ret["changes"]["new"] = {"trail": None} - ret["comment"] = "CloudTrail {} deleted.".format(Name) + ret["comment"] = f"CloudTrail {Name} deleted." return ret diff --git a/salt/states/boto_cloudwatch_alarm.py b/salt/states/boto_cloudwatch_alarm.py index 25600b363e7..5a931ef2ae2 100644 --- a/salt/states/boto_cloudwatch_alarm.py +++ b/salt/states/boto_cloudwatch_alarm.py @@ -105,7 +105,7 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): if alarm_details: for k, v in attributes.items(): if k not in alarm_details: - difference.append("{}={} (new)".format(k, v)) + difference.append(f"{k}={v} (new)") continue v = salt.utils.data.decode(v) v2 = salt.utils.data.decode(alarm_details[k]) @@ -119,7 +119,7 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): continue if isinstance(v, list) and sorted(v) == sorted(v2): continue - difference.append("{}='{}' was: '{}'".format(k, v, v2)) + difference.append(f"{k}='{v}' was: '{v2}'") else: difference.append("new alarm") create_or_update_alarm_args = { @@ -133,10 +133,10 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): if alarm_details: # alarm is present. update, or do nothing # check to see if attributes matches is_present. If so, do nothing. if len(difference) == 0: - ret["comment"] = "alarm {} present and matching".format(name) + ret["comment"] = f"alarm {name} present and matching" return ret if __opts__["test"]: - msg = "alarm {} is to be created/updated.".format(name) + msg = f"alarm {name} is to be created/updated." ret["comment"] = msg ret["result"] = None return ret @@ -147,10 +147,10 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): ret["changes"]["diff"] = difference else: ret["result"] = False - ret["comment"] = "Failed to create {} alarm".format(name) + ret["comment"] = f"Failed to create {name} alarm" else: # alarm is absent. create it. if __opts__["test"]: - msg = "alarm {} is to be created/updated.".format(name) + msg = f"alarm {name} is to be created/updated." ret["comment"] = msg ret["result"] = None return ret @@ -161,7 +161,7 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): ret["changes"]["new"] = attributes else: ret["result"] = False - ret["comment"] = "Failed to create {} alarm".format(name) + ret["comment"] = f"Failed to create {name} alarm" return ret @@ -193,7 +193,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None): if is_present: if __opts__["test"]: - ret["comment"] = "alarm {} is set to be removed.".format(name) + ret["comment"] = f"alarm {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_cloudwatch.delete_alarm"]( @@ -204,8 +204,8 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} alarm.".format(name) + ret["comment"] = f"Failed to delete {name} alarm." else: - ret["comment"] = "{} does not exist in {}.".format(name, region) + ret["comment"] = f"{name} does not exist in {region}." return ret diff --git a/salt/states/boto_cloudwatch_event.py b/salt/states/boto_cloudwatch_event.py index 65c460ca28b..1e718b374cc 100644 --- a/salt/states/boto_cloudwatch_event.py +++ b/salt/states/boto_cloudwatch_event.py @@ -182,7 +182,7 @@ def present( return ret ret["changes"]["old"] = {"rule": None} ret["changes"]["new"] = _describe - ret["comment"] = "CloudTrail {} created.".format(Name) + ret["comment"] = f"CloudTrail {Name} created." if bool(Targets): r = __salt__["boto_cloudwatch_event.put_targets"]( @@ -204,7 +204,7 @@ def present( return ret ret["comment"] = os.linesep.join( - [ret["comment"], "CloudWatch event rule {} is present.".format(Name)] + [ret["comment"], f"CloudWatch event rule {Name} is present."] ) ret["changes"] = {} # trail exists, ensure config matches @@ -249,7 +249,7 @@ def present( if need_update: if __opts__["test"]: - msg = "CloudWatch event rule {} set to be modified.".format(Name) + msg = f"CloudWatch event rule {Name} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -360,11 +360,11 @@ def absent(name, Name=None, region=None, key=None, keyid=None, profile=None): return ret if r and not r["exists"]: - ret["comment"] = "CloudWatch event rule {} does not exist.".format(Name) + ret["comment"] = f"CloudWatch event rule {Name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "CloudWatch event rule {} is set to be removed.".format(Name) + ret["comment"] = f"CloudWatch event rule {Name} is set to be removed." ret["result"] = None return ret @@ -405,5 +405,5 @@ def absent(name, Name=None, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"rule": Name} ret["changes"]["new"] = {"rule": None} - ret["comment"] = "CloudWatch event rule {} deleted.".format(Name) + ret["comment"] = f"CloudWatch event rule {Name} deleted." return ret diff --git a/salt/states/boto_cognitoidentity.py b/salt/states/boto_cognitoidentity.py index 41f8e3dc573..a6115f9f49a 100644 --- a/salt/states/boto_cognitoidentity.py +++ b/salt/states/boto_cognitoidentity.py @@ -108,7 +108,7 @@ def _role_present( IdentityPoolId=IdentityPoolId, AuthenticatedRole=AuthenticatedRole, UnauthenticatedRole=UnauthenticatedRole, - **conn_params + **conn_params, ) if not r.get("set"): ret["result"] = False @@ -298,7 +298,7 @@ def pool_present( if existing_identity_pool != updated_identity_pool: ret["changes"]["old"] = dict() ret["changes"]["new"] = dict() - change_key = "Identity Pool Name {}".format(IdentityPoolName) + change_key = f"Identity Pool Name {IdentityPoolName}" ret["changes"]["old"][change_key] = existing_identity_pool ret["changes"]["new"][change_key] = updated_identity_pool else: @@ -412,12 +412,10 @@ def pool_absent( if not ret["changes"]: ret["changes"]["old"] = dict() ret["changes"]["new"] = dict() - change_key = "Identity Pool Id {}".format(IdentityPoolId) + change_key = f"Identity Pool Id {IdentityPoolId}" ret["changes"]["old"][change_key] = IdentityPoolName ret["changes"]["new"][change_key] = None - ret["comment"] = "{}\n{}".format( - ret["comment"], "{} deleted".format(change_key) - ) + ret["comment"] = "{}\n{}".format(ret["comment"], f"{change_key} deleted") else: ret["result"] = False failure_comment = ( diff --git a/salt/states/boto_datapipeline.py b/salt/states/boto_datapipeline.py index 40735585868..0ed8ab42257 100644 --- a/salt/states/boto_datapipeline.py +++ b/salt/states/boto_datapipeline.py @@ -132,11 +132,11 @@ def present( profile=profile, ) if present: - ret["comment"] = "AWS data pipeline {} present".format(name) + ret["comment"] = f"AWS data pipeline {name} present" return ret if __opts__["test"]: - ret["comment"] = "Data pipeline {} is set to be created or updated".format(name) + ret["comment"] = f"Data pipeline {name} is set to be created or updated" ret["result"] = None return ret @@ -259,10 +259,10 @@ def present( if not old_pipeline_definition: ret["changes"]["new"] = "Pipeline created." - ret["comment"] = "Data pipeline {} created".format(name) + ret["comment"] = f"Data pipeline {name} created" else: ret["changes"]["diff"] = _diff(old_pipeline_definition, new_pipeline_definition) - ret["comment"] = "Data pipeline {} updated".format(name) + ret["comment"] = f"Data pipeline {name} updated" return ret @@ -595,7 +595,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None): if "error" not in result_pipeline_id: pipeline_id = result_pipeline_id["result"] if __opts__["test"]: - ret["comment"] = "Data pipeline {} set to be deleted.".format(name) + ret["comment"] = f"Data pipeline {name} set to be deleted." ret["result"] = None return ret else: @@ -609,6 +609,6 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret["changes"]["old"] = {"pipeline_id": pipeline_id} ret["changes"]["new"] = None else: - ret["comment"] = "AWS data pipeline {} absent.".format(name) + ret["comment"] = f"AWS data pipeline {name} absent." return ret diff --git a/salt/states/boto_dynamodb.py b/salt/states/boto_dynamodb.py index 8e563ba0574..505f0f11a63 100644 --- a/salt/states/boto_dynamodb.py +++ b/salt/states/boto_dynamodb.py @@ -284,7 +284,7 @@ def present( if not table_exists: if __opts__["test"]: ret["result"] = None - ret["comment"] = "DynamoDB table {} would be created.".format(name) + ret["comment"] = f"DynamoDB table {name} would be created." return ret else: is_created = __salt__["boto_dynamodb.create_table"]( @@ -304,11 +304,11 @@ def present( ) if not is_created: ret["result"] = False - ret["comment"] = "Failed to create table {}".format(name) + ret["comment"] = f"Failed to create table {name}" _add_changes(ret, changes_old, changes_new) return ret - comments.append("DynamoDB table {} was successfully created".format(name)) + comments.append(f"DynamoDB table {name} was successfully created") changes_new["table"] = name changes_new["read_capacity_units"] = read_capacity_units changes_new["write_capacity_units"] = write_capacity_units @@ -319,7 +319,7 @@ def present( changes_new["local_indexes"] = local_indexes changes_new["global_indexes"] = global_indexes else: - comments.append("DynamoDB table {} exists".format(name)) + comments.append(f"DynamoDB table {name} exists") # Ensure DynamoDB table provisioned throughput matches description = __salt__["boto_dynamodb.describe"](name, region, key, keyid, profile) @@ -335,7 +335,7 @@ def present( if not throughput_matches: if __opts__["test"]: ret["result"] = None - comments.append("DynamoDB table {} is set to be updated.".format(name)) + comments.append(f"DynamoDB table {name} is set to be updated.") else: is_updated = __salt__["boto_dynamodb.update"]( name, @@ -350,17 +350,17 @@ def present( ) if not is_updated: ret["result"] = False - ret["comment"] = "Failed to update table {}".format(name) + ret["comment"] = f"Failed to update table {name}" _add_changes(ret, changes_old, changes_new) return ret - comments.append("DynamoDB table {} was successfully updated".format(name)) + comments.append(f"DynamoDB table {name} was successfully updated") changes_old["read_capacity_units"] = (current_read_capacity_units,) changes_old["write_capacity_units"] = (current_write_capacity_units,) changes_new["read_capacity_units"] = (read_capacity_units,) changes_new["write_capacity_units"] = (write_capacity_units,) else: - comments.append("DynamoDB table {} throughput matches".format(name)) + comments.append(f"DynamoDB table {name} throughput matches") provisioned_indexes = description.get("Table", {}).get("GlobalSecondaryIndexes", []) @@ -478,7 +478,7 @@ def _global_indexes_present( index_name = next(iter(entry.values())) if not index_name: ret["result"] = False - ret["comment"] = "Index name not found for table {}".format(name) + ret["comment"] = f"Index name not found for table {name}" return ret gsi_config[index_name] = index @@ -591,11 +591,11 @@ def _add_global_secondary_index( ) if success: - comments.append("Created GSI {}".format(index_name)) + comments.append(f"Created GSI {index_name}") changes_new["global_indexes"][index_name] = gsi_config[index_name] else: ret["result"] = False - ret["comment"] = "Failed to create GSI {}".format(index_name) + ret["comment"] = f"Failed to create GSI {index_name}" def _update_global_secondary_indexes( @@ -641,9 +641,7 @@ def _update_global_secondary_indexes( ) if success: - comments.append( - "Updated GSIs with new throughputs {}".format(index_updates) - ) + comments.append(f"Updated GSIs with new throughputs {index_updates}") for index_name in index_updates: changes_old["global_indexes"][index_name] = provisioned_throughputs[ index_name @@ -651,7 +649,7 @@ def _update_global_secondary_indexes( changes_new["global_indexes"][index_name] = index_updates[index_name] else: ret["result"] = False - ret["comment"] = "Failed to update GSI throughputs {}".format(index_updates) + ret["comment"] = f"Failed to update GSI throughputs {index_updates}" def _determine_gsi_updates(existing_index_names, provisioned_gsi_config, gsi_config): @@ -779,7 +777,7 @@ def _ensure_backup_datapipeline_present( ): kwargs = { - "name": "{}-{}-backup".format(name, schedule_name), + "name": f"{name}-{schedule_name}-backup", "pipeline_objects": { "DefaultSchedule": { "name": schedule_name, @@ -794,7 +792,7 @@ def _ensure_backup_datapipeline_present( }, "parameter_values": { "myDDBTableName": name, - "myOutputS3Loc": "{}/{}/".format(s3_base_location, name), + "myOutputS3Loc": f"{s3_base_location}/{name}/", }, } return __states__["boto_datapipeline.present"](**kwargs) @@ -860,20 +858,20 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret = {"name": name, "result": True, "comment": "", "changes": {}} exists = __salt__["boto_dynamodb.exists"](name, region, key, keyid, profile) if not exists: - ret["comment"] = "DynamoDB table {} does not exist".format(name) + ret["comment"] = f"DynamoDB table {name} does not exist" return ret if __opts__["test"]: - ret["comment"] = "DynamoDB table {} is set to be deleted".format(name) + ret["comment"] = f"DynamoDB table {name} is set to be deleted" ret["result"] = None return ret is_deleted = __salt__["boto_dynamodb.delete"](name, region, key, keyid, profile) if is_deleted: - ret["comment"] = "Deleted DynamoDB table {}".format(name) - ret["changes"].setdefault("old", "Table {} exists".format(name)) - ret["changes"].setdefault("new", "Table {} deleted".format(name)) + ret["comment"] = f"Deleted DynamoDB table {name}" + ret["changes"].setdefault("old", f"Table {name} exists") + ret["changes"].setdefault("new", f"Table {name} deleted") else: - ret["comment"] = "Failed to delete DynamoDB table {}".format(name) + ret["comment"] = f"Failed to delete DynamoDB table {name}" ret["result"] = False return ret diff --git a/salt/states/boto_ec2.py b/salt/states/boto_ec2.py index fda59c13b5b..6e7b1d3ea06 100644 --- a/salt/states/boto_ec2.py +++ b/salt/states/boto_ec2.py @@ -89,12 +89,12 @@ def key_present( upload_public = __salt__["cp.get_file_str"](upload_public) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(upload_public) + ret["comment"] = f"File {upload_public} not found." ret["result"] = False return ret if not exists: if __opts__["test"]: - ret["comment"] = "The key {} is set to be created.".format(name) + ret["comment"] = f"The key {name} is set to be created." ret["result"] = None return ret if save_private and not upload_public: @@ -103,29 +103,29 @@ def key_present( ) if created: ret["result"] = True - ret["comment"] = "The key {} is created.".format(name) + ret["comment"] = f"The key {name} is created." ret["changes"]["new"] = created else: ret["result"] = False - ret["comment"] = "Could not create key {} ".format(name) + ret["comment"] = f"Could not create key {name} " elif not save_private and upload_public: imported = __salt__["boto_ec2.import_key"]( name, upload_public, region, key, keyid, profile ) if imported: ret["result"] = True - ret["comment"] = "The key {} is created.".format(name) + ret["comment"] = f"The key {name} is created." ret["changes"]["old"] = None ret["changes"]["new"] = imported else: ret["result"] = False - ret["comment"] = "Could not create key {} ".format(name) + ret["comment"] = f"Could not create key {name} " else: ret["result"] = False ret["comment"] = "You can either upload or download a private key " else: ret["result"] = True - ret["comment"] = "The key name {} already exists".format(name) + ret["comment"] = f"The key name {name} already exists" return ret @@ -137,21 +137,21 @@ def key_absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_ec2.get_key"](name, region, key, keyid, profile) if exists: if __opts__["test"]: - ret["comment"] = "The key {} is set to be deleted.".format(name) + ret["comment"] = f"The key {name} is set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_ec2.delete_key"](name, region, key, keyid, profile) log.debug("exists is %s", deleted) if deleted: ret["result"] = True - ret["comment"] = "The key {} is deleted.".format(name) + ret["comment"] = f"The key {name} is deleted." ret["changes"]["old"] = name else: ret["result"] = False - ret["comment"] = "Could not delete key {} ".format(name) + ret["comment"] = f"Could not delete key {name} " else: ret["result"] = True - ret["comment"] = "The key name {} does not exist".format(name) + ret["comment"] = f"The key name {name} does not exist" return ret @@ -283,7 +283,7 @@ def eni_present( ) return ret r["result"] = result_create["result"] - ret["comment"] = "Created ENI {}".format(name) + ret["comment"] = f"Created ENI {name}" ret["changes"]["id"] = r["result"]["id"] else: _ret = _eni_attribute( @@ -421,7 +421,7 @@ def _eni_attribute(metadata, attr, value, region, key, keyid, profile): if metadata[attr] == value: return ret if __opts__["test"]: - ret["comment"] = "ENI set to have {} updated.".format(attr) + ret["comment"] = f"ENI set to have {attr} updated." ret["result"] = None return ret result_update = __salt__["boto_ec2.modify_network_interface_attribute"]( @@ -438,7 +438,7 @@ def _eni_attribute(metadata, attr, value, region, key, keyid, profile): ret["result"] = False ret["comment"] = msg.format(attr, result_update["error"]["message"]) else: - ret["comment"] = "Updated ENI {}.".format(attr) + ret["comment"] = f"Updated ENI {attr}." ret["changes"][attr] = {"old": metadata[attr], "new": value} return ret @@ -560,7 +560,7 @@ def eni_absent( result_delete["error"]["message"] ) return ret - ret["comment"] = "Deleted ENI {}".format(name) + ret["comment"] = f"Deleted ENI {name}" ret["changes"]["id"] = None if release_eip and "allocationId" in r["result"]: _ret = __salt__["boto_ec2.release_eip_address"]( @@ -589,7 +589,7 @@ def snapshot_created( instance_name, wait_until_available=True, wait_timeout_seconds=300, - **kwargs + **kwargs, ): """ Create a snapshot from the given instance @@ -601,11 +601,11 @@ def snapshot_created( if not __salt__["boto_ec2.create_image"]( ami_name=ami_name, instance_name=instance_name, **kwargs ): - ret["comment"] = "Failed to create new AMI {ami_name}".format(ami_name=ami_name) + ret["comment"] = f"Failed to create new AMI {ami_name}" ret["result"] = False return ret - ret["comment"] = "Created new AMI {ami_name}".format(ami_name=ami_name) + ret["comment"] = f"Created new AMI {ami_name}" ret["changes"]["new"] = {ami_name: ami_name} if not wait_until_available: return ret @@ -887,7 +887,7 @@ def instance_present( if _create: if __opts__["test"]: - ret["comment"] = "The instance {} is set to be created.".format(name) + ret["comment"] = f"The instance {name} is set to be created." ret["result"] = None return ret if image_name: @@ -1014,7 +1014,7 @@ def instance_present( return ret else: if __opts__["test"]: - ret["comment"] = "Instance {} to be updated.".format(name) + ret["comment"] = f"Instance {name} to be updated." ret["result"] = None return ret r = __salt__["boto_ec2.associate_eip_address"]( @@ -1247,7 +1247,7 @@ def instance_absent( ) if not instances: ret["result"] = True - ret["comment"] = "Instance {} is already gone.".format(instance_id) + ret["comment"] = f"Instance {instance_id} is already gone." return ret instance = instances[0] @@ -1268,7 +1268,7 @@ def instance_absent( return ret if __opts__["test"]: - ret["comment"] = "The instance {} is set to be deleted.".format(name) + ret["comment"] = f"The instance {name} is set to be deleted." ret["result"] = None return ret @@ -1282,7 +1282,7 @@ def instance_absent( ) if not r: ret["result"] = False - ret["comment"] = "Failed to terminate instance {}.".format(instance_id) + ret["comment"] = f"Failed to terminate instance {instance_id}." return ret ret["changes"]["old"] = {"instance_id": instance_id} @@ -1308,9 +1308,7 @@ def instance_absent( else: # I /believe/ this situation is impossible but let's hedge our bets... ret["result"] = False - ret["comment"] = ( - "Can't determine AllocationId for address {}.".format(ip) - ) + ret["comment"] = f"Can't determine AllocationId for address {ip}." return ret else: public_ip = instance.ip_address @@ -1329,7 +1327,7 @@ def instance_absent( ret["changes"]["old"]["public_ip"] = public_ip or r[0]["public_ip"] else: ret["result"] = False - ret["comment"] = "Failed to release EIP {}.".format(ip) + ret["comment"] = f"Failed to release EIP {ip}." return ret return ret @@ -1449,14 +1447,14 @@ def volume_absent( log.info("Matched Volume ID %s", vol) if __opts__["test"]: - ret["comment"] = "The volume {} is set to be deleted.".format(vol) + ret["comment"] = f"The volume {vol} is set to be deleted." ret["result"] = None return ret if __salt__["boto_ec2.delete_volume"](volume_id=vol, force=True, **args): - ret["comment"] = "Volume {} deleted.".format(vol) + ret["comment"] = f"Volume {vol} deleted." ret["changes"] = {"old": {"volume_id": vol}, "new": {"volume_id": None}} else: - ret["comment"] = "Error deleting volume {}.".format(vol) + ret["comment"] = f"Error deleting volume {vol}." ret["result"] = False return ret @@ -1664,9 +1662,7 @@ def volume_present( name=instance_name, in_states=running_states, **args ) if not instance_id: - raise SaltInvocationError( - "Instance with Name {} not found.".format(instance_name) - ) + raise SaltInvocationError(f"Instance with Name {instance_name} not found.") instances = __salt__["boto_ec2.find_instances"]( instance_id=instance_id, return_objs=True, **args @@ -1699,13 +1695,13 @@ def volume_present( encrypted=encrypted, kms_key_id=kms_key_id, wait_for_creation=True, - **args + **args, ) if "result" in _rt: volume_id = _rt["result"] else: raise SaltInvocationError( - "Error creating volume with name {}.".format(volume_name) + f"Error creating volume with name {volume_name}." ) _rt = __salt__["boto_ec2.set_volumes_tags"]( tag_maps=[ @@ -1714,7 +1710,7 @@ def volume_present( "tags": {"Name": volume_name}, } ], - **args + **args, ) if _rt["success"] is False: raise SaltInvocationError( @@ -1730,7 +1726,7 @@ def volume_present( volume_ids=[volume_id], return_objs=True, **args ) if len(vols) < 1: - raise SaltInvocationError("Volume {} do not exist".format(volume_id)) + raise SaltInvocationError(f"Volume {volume_id} do not exist") vol = vols[0] if vol.zone != instance.placement: raise SaltInvocationError( diff --git a/salt/states/boto_elasticache.py b/salt/states/boto_elasticache.py index 475f165484f..b5520bfc7da 100644 --- a/salt/states/boto_elasticache.py +++ b/salt/states/boto_elasticache.py @@ -226,7 +226,7 @@ def present( return ret elif not config: if __opts__["test"]: - msg = "Cache cluster {} is set to be created.".format(name) + msg = f"Cache cluster {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -260,11 +260,11 @@ def present( ret["changes"]["new"] = config else: ret["result"] = False - ret["comment"] = "Failed to create {} cache cluster.".format(name) + ret["comment"] = f"Failed to create {name} cache cluster." return ret # TODO: support modification of existing elasticache clusters else: - ret["comment"] = "Cache cluster {} is present.".format(name) + ret["comment"] = f"Cache cluster {name} is present." return ret @@ -319,7 +319,7 @@ def subnet_group_present( ) if not exists: if __opts__["test"]: - ret["comment"] = "Subnet group {} is set to be created.".format(name) + ret["comment"] = f"Subnet group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_elasticache.create_subnet_group"]( @@ -335,11 +335,11 @@ def subnet_group_present( ) if not created: ret["result"] = False - ret["comment"] = "Failed to create {} subnet group.".format(name) + ret["comment"] = f"Failed to create {name} subnet group." return ret ret["changes"]["old"] = None ret["changes"]["new"] = name - ret["comment"] = "Subnet group {} created.".format(name) + ret["comment"] = f"Subnet group {name} created." return ret ret["comment"] = "Subnet group present." return ret @@ -379,7 +379,7 @@ def absent(name, wait=True, region=None, key=None, keyid=None, profile=None): if is_present: if __opts__["test"]: - ret["comment"] = "Cache cluster {} is set to be removed.".format(name) + ret["comment"] = f"Cache cluster {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_elasticache.delete"]( @@ -390,9 +390,9 @@ def absent(name, wait=True, region=None, key=None, keyid=None, profile=None): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} cache cluster.".format(name) + ret["comment"] = f"Failed to delete {name} cache cluster." else: - ret["comment"] = "{} does not exist in {}.".format(name, region) + ret["comment"] = f"{name} does not exist in {region}." return ret @@ -444,7 +444,7 @@ def creategroup( ) if not is_present: if __opts__["test"]: - ret["comment"] = "Replication {} is set to be created.".format(name) + ret["comment"] = f"Replication {name} is set to be created." ret["result"] = None created = __salt__["boto_elasticache.create_replication_group"]( name, @@ -465,9 +465,9 @@ def creategroup( ret["result"] = True else: ret["result"] = False - ret["comment"] = "Failed to create {} replication group.".format(name) + ret["comment"] = f"Failed to create {name} replication group." else: - ret["comment"] = "{} replication group exists .".format(name) + ret["comment"] = f"{name} replication group exists ." ret["result"] = True return ret @@ -482,7 +482,7 @@ def subnet_group_absent( ) if not exists: ret["result"] = True - ret["comment"] = "{} ElastiCache subnet group does not exist.".format(name) + ret["comment"] = f"{name} ElastiCache subnet group does not exist." return ret if __opts__["test"]: @@ -496,11 +496,11 @@ def subnet_group_absent( ) if not deleted: ret["result"] = False - ret["comment"] = "Failed to delete {} ElastiCache subnet group.".format(name) + ret["comment"] = f"Failed to delete {name} ElastiCache subnet group." return ret ret["changes"]["old"] = name ret["changes"]["new"] = None - ret["comment"] = "ElastiCache subnet group {} deleted.".format(name) + ret["comment"] = f"ElastiCache subnet group {name} deleted." return ret @@ -514,14 +514,12 @@ def replication_group_absent( ) if not exists: ret["result"] = True - ret["comment"] = "{} ElastiCache replication group does not exist.".format(name) + ret["comment"] = f"{name} ElastiCache replication group does not exist." log.info(ret["comment"]) return ret if __opts__["test"]: - ret["comment"] = ( - "ElastiCache replication group {} is set to be removed.".format(name) - ) + ret["comment"] = f"ElastiCache replication group {name} is set to be removed." ret["result"] = True return ret deleted = __salt__["boto_elasticache.delete_replication_group"]( @@ -536,6 +534,6 @@ def replication_group_absent( return ret ret["changes"]["old"] = name ret["changes"]["new"] = None - ret["comment"] = "ElastiCache replication group {} deleted.".format(name) + ret["comment"] = f"ElastiCache replication group {name} deleted." log.info(ret["comment"]) return ret diff --git a/salt/states/boto_elasticsearch_domain.py b/salt/states/boto_elasticsearch_domain.py index c0f1f8b059b..e682c463257 100644 --- a/salt/states/boto_elasticsearch_domain.py +++ b/salt/states/boto_elasticsearch_domain.py @@ -221,7 +221,7 @@ def present( AccessPolicies = salt.utils.json.loads(AccessPolicies) except ValueError as e: ret["result"] = False - ret["comment"] = "Failed to create domain: {}.".format(e.message) + ret["comment"] = f"Failed to create domain: {e.message}." return ret r = __salt__["boto_elasticsearch_domain.exists"]( DomainName=DomainName, region=region, key=key, keyid=keyid, profile=profile @@ -234,7 +234,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Domain {} is set to be created.".format(DomainName) + ret["comment"] = f"Domain {DomainName} is set to be created." ret["result"] = None return ret r = __salt__["boto_elasticsearch_domain.create"]( @@ -261,11 +261,11 @@ def present( ) ret["changes"]["old"] = {"domain": None} ret["changes"]["new"] = _describe - ret["comment"] = "Domain {} created.".format(DomainName) + ret["comment"] = f"Domain {DomainName} created." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Domain {} is present.".format(DomainName)] + [ret["comment"], f"Domain {DomainName} is present."] ) ret["changes"] = {} # domain exists, ensure config matches @@ -310,7 +310,7 @@ def present( ret["changes"].setdefault("old", {})[k] = _describe[k] if need_update: if __opts__["test"]: - msg = "Domain {} set to be modified.".format(DomainName) + msg = f"Domain {DomainName} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -323,7 +323,7 @@ def present( key=key, keyid=keyid, profile=profile, - **comm_args + **comm_args, ) if not r.get("updated"): ret["result"] = False @@ -368,11 +368,11 @@ def absent(name, DomainName, region=None, key=None, keyid=None, profile=None): return ret if r and not r["exists"]: - ret["comment"] = "Domain {} does not exist.".format(DomainName) + ret["comment"] = f"Domain {DomainName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Domain {} is set to be removed.".format(DomainName) + ret["comment"] = f"Domain {DomainName} is set to be removed." ret["result"] = None return ret @@ -385,5 +385,5 @@ def absent(name, DomainName, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"domain": DomainName} ret["changes"]["new"] = {"domain": None} - ret["comment"] = "Domain {} deleted.".format(DomainName) + ret["comment"] = f"Domain {DomainName} deleted." return ret diff --git a/salt/states/boto_elb.py b/salt/states/boto_elb.py index 73a3f7d62e3..7499f9c1008 100644 --- a/salt/states/boto_elb.py +++ b/salt/states/boto_elb.py @@ -548,7 +548,7 @@ def present( if __salt__["boto_elb.set_instances"]( name, instance_ids, True, region, key, keyid, profile ): - ret["comment"] += " ELB {} instances would be updated.".format(name) + ret["comment"] += f" ELB {name} instances would be updated." ret["result"] = None else: success = __salt__["boto_elb.set_instances"]( @@ -591,7 +591,7 @@ def register_instances( ret = {"name": name, "result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not lb: - msg = "Could not find lb {}".format(name) + msg = f"Could not find lb {name}" log.error(msg) ret.update({"comment": msg, "result": False}) return ret @@ -610,7 +610,7 @@ def register_instances( return ret if __opts__["test"]: - ret["comment"] = "ELB {} is set to register : {}.".format(name, new) + ret["comment"] = f"ELB {name} is set to register : {new}." ret["result"] = None return ret @@ -618,7 +618,7 @@ def register_instances( name, instances, region, key, keyid, profile ) if state: - msg = "Load Balancer {} has been changed".format(name) + msg = f"Load Balancer {name} has been changed" log.info(msg) new = set().union(nodes, instances) ret.update( @@ -628,7 +628,7 @@ def register_instances( } ) else: - msg = "Load balancer {} failed to add instances".format(name) + msg = f"Load balancer {name} failed to add instances" log.error(msg) ret.update({"comment": msg, "result": False}) return ret @@ -705,7 +705,7 @@ def _elb_present( ret["result"] = False return ret if "id" not in r: - ret["comment"] = "Subnet {} does not exist.".format(i) + ret["comment"] = f"Subnet {i} does not exist." ret["result"] = False return ret subnets.append(r["id"]) @@ -717,7 +717,7 @@ def _elb_present( ) vpc_id = vpc_id.get("vpc_id") if not vpc_id: - ret["comment"] = "Subnets {} do not map to a valid vpc id.".format(subnets) + ret["comment"] = f"Subnets {subnets} do not map to a valid vpc id." ret["result"] = False return ret _security_groups = __salt__["boto_secgroup.convert_to_group_ids"]( @@ -739,7 +739,7 @@ def _elb_present( exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not exists: if __opts__["test"]: - ret["comment"] = "ELB {} is set to be created.".format(name) + ret["comment"] = f"ELB {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_elb.create"]( @@ -757,12 +757,12 @@ def _elb_present( if created: ret["changes"]["old"] = {"elb": None} ret["changes"]["new"] = {"elb": name} - ret["comment"] = "ELB {} created.".format(name) + ret["comment"] = f"ELB {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} ELB.".format(name) + ret["comment"] = f"Failed to create {name} ELB." else: - ret["comment"] = "ELB {} present.".format(name) + ret["comment"] = f"ELB {name} present." _ret = _security_groups_present( name, _security_groups, region, key, keyid, profile ) @@ -804,7 +804,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: - ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} ELB configuration could not be retrieved." ret["result"] = False return ret if not listeners: @@ -832,7 +832,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): if __opts__["test"]: msg = [] if to_create or to_delete: - msg.append("ELB {} set to have listeners modified:".format(name)) + msg.append(f"ELB {name} set to have listeners modified:") for listener in to_create: msg.append( "Listener {} added.".format( @@ -847,7 +847,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): ) ret["result"] = None else: - msg.append("Listeners already set on ELB {}.".format(name)) + msg.append(f"Listeners already set on ELB {name}.") ret["comment"] = " ".join(msg) return ret @@ -857,9 +857,9 @@ def _listeners_present(name, listeners, region, key, keyid, profile): name, ports, region, key, keyid, profile ) if deleted: - ret["comment"] = "Deleted listeners on {} ELB.".format(name) + ret["comment"] = f"Deleted listeners on {name} ELB." else: - ret["comment"] = "Failed to delete listeners on {} ELB.".format(name) + ret["comment"] = f"Failed to delete listeners on {name} ELB." ret["result"] = False if to_create: @@ -880,7 +880,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["listeners"]["new"] = lb["listeners"] else: - ret["comment"] = "Listeners already set on ELB {}.".format(name) + ret["comment"] = f"Listeners already set on ELB {name}." return ret @@ -889,7 +889,7 @@ def _security_groups_present(name, security_groups, region, key, keyid, profile) ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: - ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} ELB configuration could not be retrieved." ret["result"] = False return ret if not security_groups: @@ -899,21 +899,21 @@ def _security_groups_present(name, security_groups, region, key, keyid, profile) change_needed = True if change_needed: if __opts__["test"]: - ret["comment"] = "ELB {} set to have security groups modified.".format(name) + ret["comment"] = f"ELB {name} set to have security groups modified." ret["result"] = None return ret changed = __salt__["boto_elb.apply_security_groups"]( name, security_groups, region, key, keyid, profile ) if changed: - ret["comment"] = "Modified security_groups on {} ELB.".format(name) + ret["comment"] = f"Modified security_groups on {name} ELB." else: - ret["comment"] = "Failed to modify security_groups on {} ELB.".format(name) + ret["comment"] = f"Failed to modify security_groups on {name} ELB." ret["result"] = False ret["changes"]["old"] = {"security_groups": lb["security_groups"]} ret["changes"]["new"] = {"security_groups": security_groups} else: - ret["comment"] = "security_groups already set on ELB {}.".format(name) + ret["comment"] = f"security_groups already set on ELB {name}." return ret @@ -922,7 +922,7 @@ def _attributes_present(name, attributes, region, key, keyid, profile): _attributes = __salt__["boto_elb.get_attributes"](name, region, key, keyid, profile) if not _attributes: ret["result"] = False - ret["comment"] = "Failed to retrieve attributes for ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve attributes for ELB {name}." return ret attrs_to_set = [] if "cross_zone_load_balancing" in attributes: @@ -954,7 +954,7 @@ def _attributes_present(name, attributes, region, key, keyid, profile): ) if attrs_to_set: if __opts__["test"]: - ret["comment"] = "ELB {} set to have attributes set.".format(name) + ret["comment"] = f"ELB {name} set to have attributes set." ret["result"] = None return ret was_set = __salt__["boto_elb.set_attributes"]( @@ -963,12 +963,12 @@ def _attributes_present(name, attributes, region, key, keyid, profile): if was_set: ret["changes"]["old"] = {"attributes": _attributes} ret["changes"]["new"] = {"attributes": attributes} - ret["comment"] = "Set attributes on ELB {}.".format(name) + ret["comment"] = f"Set attributes on ELB {name}." else: ret["result"] = False - ret["comment"] = "Failed to set attributes on ELB {}.".format(name) + ret["comment"] = f"Failed to set attributes on ELB {name}." else: - ret["comment"] = "Attributes already set on ELB {}.".format(name) + ret["comment"] = f"Attributes already set on ELB {name}." return ret @@ -981,7 +981,7 @@ def _health_check_present(name, health_check, region, key, keyid, profile): ) if not _health_check: ret["result"] = False - ret["comment"] = "Failed to retrieve health_check for ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve health_check for ELB {name}." return ret need_to_set = False for attr, val in health_check.items(): @@ -989,7 +989,7 @@ def _health_check_present(name, health_check, region, key, keyid, profile): need_to_set = True if need_to_set: if __opts__["test"]: - ret["comment"] = "ELB {} set to have health check set.".format(name) + ret["comment"] = f"ELB {name} set to have health check set." ret["result"] = None return ret was_set = __salt__["boto_elb.set_health_check"]( @@ -1001,12 +1001,12 @@ def _health_check_present(name, health_check, region, key, keyid, profile): name, region, key, keyid, profile ) ret["changes"]["new"] = {"health_check": _health_check} - ret["comment"] = "Set health check on ELB {}.".format(name) + ret["comment"] = f"Set health check on ELB {name}." else: ret["result"] = False - ret["comment"] = "Failed to set health check on ELB {}.".format(name) + ret["comment"] = f"Failed to set health check on ELB {name}." else: - ret["comment"] = "Health check already set on ELB {}.".format(name) + ret["comment"] = f"Health check already set on ELB {name}." return ret @@ -1015,7 +1015,7 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["result"] = False - ret["comment"] = "Failed to retrieve ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve ELB {name}." return ret to_enable = [] to_disable = [] @@ -1028,7 +1028,7 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): to_disable.append(zone) if to_enable or to_disable: if __opts__["test"]: - ret["comment"] = "ELB {} to have availability zones set.".format(name) + ret["comment"] = f"ELB {name} to have availability zones set." ret["result"] = None return ret if to_enable: @@ -1036,11 +1036,9 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): name, to_enable, region, key, keyid, profile ) if enabled: - ret["comment"] = "Enabled availability zones on {} ELB.".format(name) + ret["comment"] = f"Enabled availability zones on {name} ELB." else: - ret["comment"] = ( - "Failed to enable availability zones on {} ELB.".format(name) - ) + ret["comment"] = f"Failed to enable availability zones on {name} ELB." ret["result"] = False if to_disable: disabled = __salt__["boto_elb.disable_availability_zones"]( @@ -1057,7 +1055,7 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["new"] = {"availability_zones": lb["availability_zones"]} else: - ret["comment"] = "Availability zones already set on ELB {}.".format(name) + ret["comment"] = f"Availability zones already set on ELB {name}." return ret @@ -1068,7 +1066,7 @@ def _subnets_present(name, subnets, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["result"] = False - ret["comment"] = "Failed to retrieve ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve ELB {name}." return ret to_enable = [] to_disable = [] @@ -1081,7 +1079,7 @@ def _subnets_present(name, subnets, region, key, keyid, profile): to_disable.append(subnet) if to_enable or to_disable: if __opts__["test"]: - ret["comment"] = "ELB {} to have subnets set.".format(name) + ret["comment"] = f"ELB {name} to have subnets set." ret["result"] = None return ret if to_enable: @@ -1089,9 +1087,9 @@ def _subnets_present(name, subnets, region, key, keyid, profile): name, to_enable, region, key, keyid, profile ) if attached: - ret["comment"] = "Attached subnets on {} ELB.".format(name) + ret["comment"] = f"Attached subnets on {name} ELB." else: - ret["comment"] = "Failed to attach subnets on {} ELB.".format(name) + ret["comment"] = f"Failed to attach subnets on {name} ELB." ret["result"] = False if to_disable: detached = __salt__["boto_elb.detach_subnets"]( @@ -1099,13 +1097,13 @@ def _subnets_present(name, subnets, region, key, keyid, profile): ) if detached: ret["comment"] = " ".join( - [ret["comment"], "Detached subnets on {} ELB.".format(name)] + [ret["comment"], f"Detached subnets on {name} ELB."] ) else: ret["comment"] = " ".join( [ ret["comment"], - "Failed to detach subnets on {} ELB.".format(name), + f"Failed to detach subnets on {name} ELB.", ] ) ret["result"] = False @@ -1113,7 +1111,7 @@ def _subnets_present(name, subnets, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["new"] = {"subnets": lb["subnets"]} else: - ret["comment"] = "Subnets already set on ELB {}.".format(name) + ret["comment"] = f"Subnets already set on ELB {name}." return ret @@ -1209,7 +1207,7 @@ def _policies_present( lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: - ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} ELB configuration could not be retrieved." ret["result"] = False return ret @@ -1295,18 +1293,18 @@ def _policies_present( if __opts__["test"]: msg = [] if to_create or to_delete: - msg.append("ELB {} set to have policies modified:".format(name)) + msg.append(f"ELB {name} set to have policies modified:") for policy in to_create: - msg.append("Policy {} added.".format(policy)) + msg.append(f"Policy {policy} added.") for policy in to_delete: - msg.append("Policy {} deleted.".format(policy)) + msg.append(f"Policy {policy} deleted.") ret["result"] = None else: - msg.append("Policies already set on ELB {}.".format(name)) + msg.append(f"Policies already set on ELB {name}.") for listener in listeners_to_update: - msg.append("Listener {} policies updated.".format(listener)) + msg.append(f"Listener {listener} policies updated.") for backend in backends_to_update: - msg.append("Backend {} policies updated.".format(backend)) + msg.append(f"Backend {backend} policies updated.") ret["comment"] = " ".join(msg) return ret @@ -1324,7 +1322,7 @@ def _policies_present( ) if created: ret["changes"].setdefault(policy_name, {})["new"] = policy_name - comment = "Policy {} was created on ELB {}".format(policy_name, name) + comment = f"Policy {policy_name} was created on ELB {name}" ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: @@ -1342,7 +1340,7 @@ def _policies_present( profile=profile, ) if policy_set: - policy_key = "listener_{}_policy".format(port) + policy_key = f"listener_{port}_policy" ret["changes"][policy_key] = { "old": list(actual_policies_by_listener.get(port, [])), "new": list(expected_policies_by_listener.get(port, [])), @@ -1367,7 +1365,7 @@ def _policies_present( profile=profile, ) if policy_set: - policy_key = "backend_{}_policy".format(port) + policy_key = f"backend_{port}_policy" ret["changes"][policy_key] = { "old": list(actual_policies_by_backend.get(port, [])), "new": list(expected_policies_by_backend.get(port, [])), @@ -1393,7 +1391,7 @@ def _policies_present( ) if deleted: ret["changes"].setdefault(policy_name, {})["old"] = policy_name - comment = "Policy {} was deleted from ELB {}".format(policy_name, name) + comment = f"Policy {policy_name} was deleted from ELB {name}" ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: @@ -1412,7 +1410,7 @@ def _policy_cname(policy_dict): ).hexdigest() if policy_type.endswith("Type"): policy_type = policy_type[:-4] - return "{}-{}-{}".format(policy_type, policy_name, policy_hash) + return f"{policy_type}-{policy_name}-{policy_hash}" def absent(name, region=None, key=None, keyid=None, profile=None): @@ -1427,19 +1425,19 @@ def absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if exists: if __opts__["test"]: - ret["comment"] = "ELB {} is set to be removed.".format(name) + ret["comment"] = f"ELB {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_elb.delete"](name, region, key, keyid, profile) if deleted: ret["changes"]["old"] = {"elb": name} ret["changes"]["new"] = {"elb": None} - ret["comment"] = "ELB {} deleted.".format(name) + ret["comment"] = f"ELB {name} deleted." else: ret["result"] = False - ret["comment"] = "Failed to delete {} ELB.".format(name) + ret["comment"] = f"Failed to delete {name} ELB." else: - ret["comment"] = "{} ELB does not exist.".format(name) + ret["comment"] = f"{name} ELB does not exist." return ret @@ -1477,7 +1475,7 @@ def _tags_present(name, tags, region, key, keyid, profile): ) if not _ret: ret["result"] = False - msg = "Error attempting to delete tag {}.".format(tags_to_remove) + msg = f"Error attempting to delete tag {tags_to_remove}." ret["comment"] = " ".join([ret["comment"], msg]) return ret if "old" not in ret["changes"]: diff --git a/salt/states/boto_elbv2.py b/salt/states/boto_elbv2.py index d2eca045f0a..480d5b3b04a 100644 --- a/salt/states/boto_elbv2.py +++ b/salt/states/boto_elbv2.py @@ -64,7 +64,7 @@ def create_target_group( health_check_timeout_seconds=5, healthy_threshold_count=5, unhealthy_threshold_count=2, - **kwargs + **kwargs, ): """ .. versionadded:: 2017.11.0 @@ -121,11 +121,11 @@ def create_target_group( if __salt__["boto_elbv2.target_group_exists"](name, region, key, keyid, profile): ret["result"] = True - ret["comment"] = "Target Group {} already exists".format(name) + ret["comment"] = f"Target Group {name} already exists" return ret if __opts__["test"]: - ret["comment"] = "Target Group {} will be created".format(name) + ret["comment"] = f"Target Group {name} will be created" return ret state = __salt__["boto_elbv2.create_target_group"]( @@ -144,16 +144,16 @@ def create_target_group( health_check_timeout_seconds=health_check_timeout_seconds, healthy_threshold_count=healthy_threshold_count, unhealthy_threshold_count=unhealthy_threshold_count, - **kwargs + **kwargs, ) if state: ret["changes"]["target_group"] = name ret["result"] = True - ret["comment"] = "Target Group {} created".format(name) + ret["comment"] = f"Target Group {name} created" else: ret["result"] = False - ret["comment"] = "Target Group {} creation failed".format(name) + ret["comment"] = f"Target Group {name} creation failed" return ret @@ -184,11 +184,11 @@ def delete_target_group(name, region=None, key=None, keyid=None, profile=None): name, region, key, keyid, profile ): ret["result"] = True - ret["comment"] = "Target Group {} does not exists".format(name) + ret["comment"] = f"Target Group {name} does not exists" return ret if __opts__["test"]: - ret["comment"] = "Target Group {} will be deleted".format(name) + ret["comment"] = f"Target Group {name} will be deleted" return ret state = __salt__["boto_elbv2.delete_target_group"]( @@ -198,10 +198,10 @@ def delete_target_group(name, region=None, key=None, keyid=None, profile=None): if state: ret["result"] = True ret["changes"]["target_group"] = name - ret["comment"] = "Target Group {} deleted".format(name) + ret["comment"] = f"Target Group {name} deleted" else: ret["result"] = False - ret["comment"] = "Target Group {} deletion failed".format(name) + ret["comment"] = f"Target Group {name} deletion failed" return ret @@ -276,18 +276,18 @@ def targets_registered( if changes: ret["changes"]["old"] = health if __opts__["test"]: - ret["comment"] = "Target Group {} would be changed".format(name) + ret["comment"] = f"Target Group {name} would be changed" ret["result"] = None ret["changes"]["new"] = newhealth_mock else: - ret["comment"] = "Target Group {} has been changed".format(name) + ret["comment"] = f"Target Group {name} has been changed" newhealth = __salt__["boto_elbv2.describe_target_health"]( name, region=region, key=key, keyid=keyid, profile=profile ) ret["changes"]["new"] = newhealth return ret else: - ret["comment"] = "Could not find target group {}".format(name) + ret["comment"] = f"Could not find target group {name}" return ret @@ -326,9 +326,9 @@ def targets_deregistered( targets = [targets] for target in targets: if target not in health or health.get(target) == "draining": - ret["comment"] = ret[ - "comment" - ] + "Target/s {} already deregistered\n".format(target) + ret["comment"] = ( + ret["comment"] + f"Target/s {target} already deregistered\n" + ) ret["result"] = True else: if __opts__["test"]: @@ -347,25 +347,23 @@ def targets_deregistered( changes = True ret["result"] = True else: - ret["comment"] = ( - "Target Group {} failed to remove targets".format(name) - ) + ret["comment"] = f"Target Group {name} failed to remove targets" failure = True if failure: ret["result"] = False if changes: ret["changes"]["old"] = health if __opts__["test"]: - ret["comment"] = "Target Group {} would be changed".format(name) + ret["comment"] = f"Target Group {name} would be changed" ret["result"] = None ret["changes"]["new"] = newhealth_mock else: - ret["comment"] = "Target Group {} has been changed".format(name) + ret["comment"] = f"Target Group {name} has been changed" newhealth = __salt__["boto_elbv2.describe_target_health"]( name, region=region, key=key, keyid=keyid, profile=profile ) ret["changes"]["new"] = newhealth return ret else: - ret["comment"] = "Could not find target group {}".format(name) + ret["comment"] = f"Could not find target group {name}" return ret diff --git a/salt/states/boto_iam.py b/salt/states/boto_iam.py index a5bbd1ee8b3..d89573cf5ae 100644 --- a/salt/states/boto_iam.py +++ b/salt/states/boto_iam.py @@ -155,7 +155,7 @@ def __virtual__(): else: return ( False, - "Cannot load {} state: boto_iam module unavailable".format(__virtualname__), + f"Cannot load {__virtualname__} state: boto_iam module unavailable", ) @@ -207,7 +207,7 @@ def user_absent( ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_user"](name, region, key, keyid, profile): ret["result"] = True - ret["comment"] = "IAM User {} does not exist.".format(name) + ret["comment"] = f"IAM User {name} does not exist." return ret # delete the user's access keys if delete_keys: @@ -297,7 +297,7 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "Virtual MFA device {} is deleted.".format(serial), + f"Virtual MFA device {serial} is deleted.", ] ) # delete the user's login profile @@ -306,7 +306,7 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} login profile is set to be deleted.".format(name), + f"IAM user {name} login profile is set to be deleted.", ] ) ret["result"] = None @@ -318,14 +318,14 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} login profile is deleted.".format(name), + f"IAM user {name} login profile is deleted.", ] ) if __opts__["test"]: ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} managed policies are set to be detached.".format(name), + f"IAM user {name} managed policies are set to be detached.", ] ) ret["result"] = None @@ -340,7 +340,7 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} inline policies are set to be deleted.".format(name), + f"IAM user {name} inline policies are set to be deleted.", ] ) ret["result"] = None @@ -354,19 +354,17 @@ def user_absent( # finally, actually delete the user if __opts__["test"]: ret["comment"] = " ".join( - [ret["comment"], "IAM user {} is set to be deleted.".format(name)] + [ret["comment"], f"IAM user {name} is set to be deleted."] ) ret["result"] = None return ret deleted = __salt__["boto_iam.delete_user"](name, region, key, keyid, profile) if deleted is True: - ret["comment"] = " ".join( - [ret["comment"], "IAM user {} is deleted.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"IAM user {name} is deleted."]) ret["result"] = True ret["changes"]["deleted"] = name return ret - ret["comment"] = "IAM user {} could not be deleted.\n {}".format(name, deleted) + ret["comment"] = f"IAM user {name} could not be deleted.\n {deleted}" ret["result"] = False return ret @@ -418,14 +416,14 @@ def keys_present( ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_user"](name, region, key, keyid, profile): ret["result"] = False - ret["comment"] = "IAM User {} does not exist.".format(name) + ret["comment"] = f"IAM User {name} does not exist." return ret if not isinstance(number, int): ret["comment"] = "The number of keys must be an integer." ret["result"] = False return ret if not os.path.isdir(save_dir): - ret["comment"] = "The directory {} does not exist.".format(save_dir) + ret["comment"] = f"The directory {save_dir} does not exist." ret["result"] = False return ret keys = __salt__["boto_iam.get_all_access_keys"]( @@ -434,7 +432,7 @@ def keys_present( if isinstance(keys, str): log.debug("keys are : false %s", keys) error, message = _get_error(keys) - ret["comment"] = "Could not get keys.\n{}\n{}".format(error, message) + ret["comment"] = f"Could not get keys.\n{error}\n{message}" ret["result"] = False return ret keys = keys["list_access_keys_response"]["list_access_keys_result"][ @@ -442,11 +440,11 @@ def keys_present( ] log.debug("Keys are : %s.", keys) if len(keys) >= number: - ret["comment"] = "The number of keys exist for user {}".format(name) + ret["comment"] = f"The number of keys exist for user {name}" ret["result"] = True return ret if __opts__["test"]: - ret["comment"] = "Access key is set to be created for {}.".format(name) + ret["comment"] = f"Access key is set to be created for {name}." ret["result"] = None return ret new_keys = {} @@ -456,7 +454,7 @@ def keys_present( ) if isinstance(created, str): error, message = _get_error(created) - ret["comment"] = "Could not create keys.\n{}\n{}".format(error, message) + ret["comment"] = f"Could not create keys.\n{error}\n{message}" ret["result"] = False return ret log.debug("Created is : %s", created) @@ -470,7 +468,7 @@ def keys_present( "secret_access_key" ] try: - with salt.utils.files.fopen("{}/{}".format(save_dir, name), "a") as _wrf: + with salt.utils.files.fopen(f"{save_dir}/{name}", "a") as _wrf: for key_num, key in new_keys.items(): key_id = key["key_id"] secret_key = key["secret_key"] @@ -479,17 +477,17 @@ def keys_present( save_format.format( key_id, secret_key, - "key_id-{}".format(key_num), - "key-{}".format(key_num), + f"key_id-{key_num}", + f"key-{key_num}", ) ) ) - ret["comment"] = "Keys have been written to file {}/{}.".format(save_dir, name) + ret["comment"] = f"Keys have been written to file {save_dir}/{name}." ret["result"] = True ret["changes"] = new_keys return ret except OSError: - ret["comment"] = "Could not write to file {}/{}.".format(save_dir, name) + ret["comment"] = f"Could not write to file {save_dir}/{name}." ret["result"] = False return ret @@ -525,7 +523,7 @@ def keys_absent( ret = {"name": access_keys, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_user"](user_name, region, key, keyid, profile): ret["result"] = False - ret["comment"] = "IAM User {} does not exist.".format(user_name) + ret["comment"] = f"IAM User {user_name} does not exist." return ret for k in access_keys: ret = _delete_key(ret, k, user_name, region, key, keyid, profile) @@ -542,7 +540,7 @@ def _delete_key( if isinstance(keys, str): log.debug("Keys %s are a string. Something went wrong.", keys) ret["comment"] = " ".join( - [ret["comment"], "Key {} could not be deleted.".format(access_key_id)] + [ret["comment"], f"Key {access_key_id} could not be deleted."] ) return ret keys = keys["list_access_keys_response"]["list_access_keys_result"][ @@ -564,15 +562,15 @@ def _delete_key( ) if deleted: ret["comment"] = " ".join( - [ret["comment"], "Key {} has been deleted.".format(access_key_id)] + [ret["comment"], f"Key {access_key_id} has been deleted."] ) ret["changes"][access_key_id] = "deleted" return ret ret["comment"] = " ".join( - [ret["comment"], "Key {} could not be deleted.".format(access_key_id)] + [ret["comment"], f"Key {access_key_id} could not be deleted."] ) return ret - ret["comment"] = " ".join([ret["comment"], "Key {} does not exist.".format(k)]) + ret["comment"] = " ".join([ret["comment"], f"Key {k} does not exist."]) return ret @@ -649,7 +647,7 @@ def user_present( exists = __salt__["boto_iam.get_user"](name, region, key, keyid, profile) if not exists: if __opts__["test"]: - ret["comment"] = "IAM user {} is set to be created.".format(name) + ret["comment"] = f"IAM user {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_user"]( @@ -658,7 +656,7 @@ def user_present( if created: ret["changes"]["user"] = created ret["comment"] = " ".join( - [ret["comment"], "User {} has been created.".format(name)] + [ret["comment"], f"User {name} has been created."] ) if password: ret = _case_password(ret, name, password, region, key, keyid, profile) @@ -666,7 +664,7 @@ def user_present( ret["changes"] = dictupdate.update(ret["changes"], _ret["changes"]) ret["comment"] = " ".join([ret["comment"], _ret["comment"]]) else: - ret["comment"] = " ".join([ret["comment"], "User {} is present.".format(name)]) + ret["comment"] = " ".join([ret["comment"], f"User {name} is present."]) if password: ret = _case_password(ret, name, password, region, key, keyid, profile) _ret = _user_policies_present(name, _policies, region, key, keyid, profile) @@ -845,7 +843,7 @@ def _user_policies_detached(name, region=None, key=None, keyid=None, profile=Non ) oldpolicies = [x.get("policy_arn") for x in _list] if not _list: - ret["comment"] = "No attached policies in user {}.".format(name) + ret["comment"] = f"No attached policies in user {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be detached from user {}.".format( @@ -865,7 +863,7 @@ def _user_policies_detached(name, region=None, key=None, keyid=None, profile=Non newpolicies = [x.get("policy_arn") for x in _list] ret["changes"]["new"] = {"managed_policies": newpolicies} ret["result"] = False - ret["comment"] = "Failed to detach {} from user {}".format(policy_arn, name) + ret["comment"] = f"Failed to detach {policy_arn} from user {name}" return ret _list = __salt__["boto_iam.list_attached_user_policies"]( name, region=region, key=key, keyid=keyid, profile=profile @@ -884,7 +882,7 @@ def _user_policies_deleted(name, region=None, key=None, keyid=None, profile=None user_name=name, region=region, key=key, keyid=keyid, profile=profile ) if not oldpolicies: - ret["comment"] = "No inline policies in user {}.".format(name) + ret["comment"] = f"No inline policies in user {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be deleted from user {}.".format( @@ -921,7 +919,7 @@ def _case_password( ret, name, password, region=None, key=None, keyid=None, profile=None ): if __opts__["test"]: - ret["comment"] = "Login policy for {} is set to be changed.".format(name) + ret["comment"] = f"Login policy for {name} is set to be changed." ret["result"] = None return ret login = __salt__["boto_iam.create_login_profile"]( @@ -931,11 +929,11 @@ def _case_password( if login: if "Conflict" in login: ret["comment"] = " ".join( - [ret["comment"], "Login profile for user {} exists.".format(name)] + [ret["comment"], f"Login profile for user {name} exists."] ) else: ret["comment"] = " ".join( - [ret["comment"], "Password has been added to User {}.".format(name)] + [ret["comment"], f"Password has been added to User {name}."] ) ret["changes"]["password"] = "REDACTED" else: @@ -976,13 +974,13 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_group"](name, region, key, keyid, profile): ret["result"] = True - ret["comment"] = "IAM Group {} does not exist.".format(name) + ret["comment"] = f"IAM Group {name} does not exist." return ret if __opts__["test"]: ret["comment"] = " ".join( [ ret["comment"], - "IAM group {} managed policies are set to be detached.".format(name), + f"IAM group {name} managed policies are set to be detached.", ] ) ret["result"] = None @@ -997,7 +995,7 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): ret["comment"] = " ".join( [ ret["comment"], - "IAM group {} inline policies are set to be deleted.".format(name), + f"IAM group {name} inline policies are set to be deleted.", ] ) ret["result"] = None @@ -1009,7 +1007,7 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): if ret["result"] is False: return ret ret["comment"] = " ".join( - [ret["comment"], "IAM group {} users are set to be removed.".format(name)] + [ret["comment"], f"IAM group {name} users are set to be removed."] ) existing_users = __salt__["boto_iam.get_group_members"]( group_name=name, region=region, key=key, keyid=keyid, profile=profile @@ -1023,19 +1021,17 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): # finally, actually delete the group if __opts__["test"]: ret["comment"] = " ".join( - [ret["comment"], "IAM group {} is set to be deleted.".format(name)] + [ret["comment"], f"IAM group {name} is set to be deleted."] ) ret["result"] = None return ret deleted = __salt__["boto_iam.delete_group"](name, region, key, keyid, profile) if deleted is True: - ret["comment"] = " ".join( - [ret["comment"], "IAM group {} is deleted.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"IAM group {name} is deleted."]) ret["result"] = True ret["changes"]["deleted"] = name return ret - ret["comment"] = "IAM group {} could not be deleted.\n {}".format(name, deleted) + ret["comment"] = f"IAM group {name} could not be deleted.\n {deleted}" ret["result"] = False return ret @@ -1119,7 +1115,7 @@ def group_present( ) if not exists: if __opts__["test"]: - ret["comment"] = "IAM group {} is set to be created.".format(name) + ret["comment"] = f"IAM group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_group"]( @@ -1131,15 +1127,13 @@ def group_present( profile=profile, ) if not created: - ret["comment"] = "Failed to create IAM group {}.".format(name) + ret["comment"] = f"Failed to create IAM group {name}." ret["result"] = False return ret ret["changes"]["group"] = created - ret["comment"] = " ".join( - [ret["comment"], "Group {} has been created.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"Group {name} has been created."]) else: - ret["comment"] = " ".join([ret["comment"], "Group {} is present.".format(name)]) + ret["comment"] = " ".join([ret["comment"], f"Group {name} is present."]) # Group exists, ensure group policies and users are set. _ret = _group_policies_present( name, _policies, region, key, keyid, profile, delete_policies @@ -1178,7 +1172,7 @@ def _case_group(ret, users, group_name, existing_users, region, key, keyid, prof ret["comment"] = " ".join( [ ret["comment"], - "User {} is already a member of group {}.".format(user, group_name), + f"User {user} is already a member of group {group_name}.", ] ) continue @@ -1196,7 +1190,7 @@ def _case_group(ret, users, group_name, existing_users, region, key, keyid, prof ret["comment"] = " ".join( [ ret["comment"], - "User {} has been added to group {}.".format(user, group_name), + f"User {user} has been added to group {group_name}.", ] ) ret["changes"][user] = group_name @@ -1229,7 +1223,7 @@ def _case_group(ret, users, group_name, existing_users, region, key, keyid, prof ), ] ) - ret["changes"][user] = "Removed from group {}.".format(group_name) + ret["changes"][user] = f"Removed from group {group_name}." return ret @@ -1410,7 +1404,7 @@ def _group_policies_detached(name, region=None, key=None, keyid=None, profile=No ) oldpolicies = [x.get("policy_arn") for x in _list] if not _list: - ret["comment"] = "No attached policies in group {}.".format(name) + ret["comment"] = f"No attached policies in group {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be detached from group {}.".format( @@ -1451,7 +1445,7 @@ def _group_policies_deleted(name, region=None, key=None, keyid=None, profile=Non group_name=name, region=region, key=key, keyid=keyid, profile=profile ) if not oldpolicies: - ret["comment"] = "No inline policies in group {}.".format(name) + ret["comment"] = f"No inline policies in group {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be deleted from group {}.".format( @@ -1568,7 +1562,7 @@ def account_policy( ret["comment"] = " ".join( [ ret["comment"], - "Policy value {} has been set to {}.".format(value, info[key]), + f"Policy value {value} has been set to {info[key]}.", ] ) ret["changes"][key] = str(value).lower() @@ -1627,18 +1621,18 @@ def server_cert_absent(name, region=None, key=None, keyid=None, profile=None): name, region, key, keyid, profile ) if not exists: - ret["comment"] = "Certificate {} does not exist.".format(name) + ret["comment"] = f"Certificate {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Server certificate {} is set to be deleted.".format(name) + ret["comment"] = f"Server certificate {name} is set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_server_cert"](name, region, key, keyid, profile) if not deleted: ret["result"] = False - ret["comment"] = "Certificate {} failed to be deleted.".format(name) + ret["comment"] = f"Certificate {name} failed to be deleted." return ret - ret["comment"] = "Certificate {} was deleted.".format(name) + ret["comment"] = f"Certificate {name} was deleted." ret["changes"] = deleted return ret @@ -1693,14 +1687,14 @@ def server_cert_present( ) log.debug("Variables are : %s.", locals()) if exists: - ret["comment"] = "Certificate {} exists.".format(name) + ret["comment"] = f"Certificate {name} exists." return ret if "salt://" in public_key: try: public_key = __salt__["cp.get_file_str"](public_key) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(public_key) + ret["comment"] = f"File {public_key} not found." ret["result"] = False return ret if "salt://" in private_key: @@ -1708,7 +1702,7 @@ def server_cert_present( private_key = __salt__["cp.get_file_str"](private_key) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(private_key) + ret["comment"] = f"File {private_key} not found." ret["result"] = False return ret if cert_chain is not None and "salt://" in cert_chain: @@ -1716,22 +1710,22 @@ def server_cert_present( cert_chain = __salt__["cp.get_file_str"](cert_chain) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(cert_chain) + ret["comment"] = f"File {cert_chain} not found." ret["result"] = False return ret if __opts__["test"]: - ret["comment"] = "Server certificate {} is set to be created.".format(name) + ret["comment"] = f"Server certificate {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.upload_server_cert"]( name, public_key, private_key, cert_chain, path, region, key, keyid, profile ) if created is not False: - ret["comment"] = "Certificate {} was created.".format(name) + ret["comment"] = f"Certificate {name} was created." ret["changes"] = created return ret ret["result"] = False - ret["comment"] = "Certificate {} failed to be created.".format(name) + ret["comment"] = f"Certificate {name} failed to be created." return ret @@ -1780,7 +1774,7 @@ def policy_present( policy = __salt__["boto_iam.get_policy"](name, region, key, keyid, profile) if not policy: if __opts__["test"]: - ret["comment"] = "IAM policy {} is set to be created.".format(name) + ret["comment"] = f"IAM policy {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_policy"]( @@ -1789,7 +1783,7 @@ def policy_present( if created: ret["changes"]["policy"] = created ret["comment"] = " ".join( - [ret["comment"], "Policy {} has been created.".format(name)] + [ret["comment"], f"Policy {name} has been created."] ) else: ret["result"] = False @@ -1798,9 +1792,7 @@ def policy_present( return ret else: policy = policy.get("policy", {}) - ret["comment"] = " ".join( - [ret["comment"], "Policy {} is present.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"Policy {name} is present."]) _describe = __salt__["boto_iam.get_policy_version"]( name, policy.get("default_version_id"), region, key, keyid, profile ).get("policy_version", {}) @@ -1816,7 +1808,7 @@ def policy_present( if bool(r): if __opts__["test"]: - ret["comment"] = "Policy {} set to be modified.".format(name) + ret["comment"] = f"Policy {name} set to be modified." ret["result"] = None return ret @@ -1883,11 +1875,11 @@ def policy_absent(name, region=None, key=None, keyid=None, profile=None): name, region=region, key=key, keyid=keyid, profile=profile ) if not r: - ret["comment"] = "Policy {} does not exist.".format(name) + ret["comment"] = f"Policy {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Policy {} is set to be removed.".format(name) + ret["comment"] = f"Policy {name} is set to be removed." ret["result"] = None return ret # delete non-default versions @@ -1908,18 +1900,18 @@ def policy_absent(name, region=None, key=None, keyid=None, profile=None): ) if not r: ret["result"] = False - ret["comment"] = "Failed to delete policy {}.".format(name) + ret["comment"] = f"Failed to delete policy {name}." return ret r = __salt__["boto_iam.delete_policy"]( name, region=region, key=key, keyid=keyid, profile=profile ) if not r: ret["result"] = False - ret["comment"] = "Failed to delete policy {}.".format(name) + ret["comment"] = f"Failed to delete policy {name}." return ret ret["changes"]["old"] = {"policy": name} ret["changes"]["new"] = {"policy": None} - ret["comment"] = "Policy {} deleted.".format(name) + ret["comment"] = f"Policy {name} deleted." return ret @@ -1958,7 +1950,7 @@ def saml_provider_present( except OSError as e: log.debug(e) ret["comment"] = ( - "SAML document file {} not found or could not be loaded".format(name) + f"SAML document file {name} not found or could not be loaded" ) ret["result"] = False return ret @@ -1966,10 +1958,10 @@ def saml_provider_present( region=region, key=key, keyid=keyid, profile=profile ): if provider == name: - ret["comment"] = "SAML provider {} is present.".format(name) + ret["comment"] = f"SAML provider {name} is present." return ret if __opts__["test"]: - ret["comment"] = "SAML provider {} is set to be create.".format(name) + ret["comment"] = f"SAML provider {name} is set to be create." ret["result"] = None return ret created = __salt__["boto_iam.create_saml_provider"]( @@ -1981,11 +1973,11 @@ def saml_provider_present( profile=profile, ) if created: - ret["comment"] = "SAML provider {} was created.".format(name) + ret["comment"] = f"SAML provider {name} was created." ret["changes"]["new"] = name return ret ret["result"] = False - ret["comment"] = "SAML provider {} failed to be created.".format(name) + ret["comment"] = f"SAML provider {name} failed to be created." return ret @@ -2019,21 +2011,21 @@ def saml_provider_absent(name, region=None, key=None, keyid=None, profile=None): region=region, key=key, keyid=keyid, profile=profile ) if len(provider) == 0: - ret["comment"] = "SAML provider {} is absent.".format(name) + ret["comment"] = f"SAML provider {name} is absent." return ret if __opts__["test"]: - ret["comment"] = "SAML provider {} is set to be removed.".format(name) + ret["comment"] = f"SAML provider {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_saml_provider"]( name, region=region, key=key, keyid=keyid, profile=profile ) if deleted is not False: - ret["comment"] = "SAML provider {} was deleted.".format(name) + ret["comment"] = f"SAML provider {name} was deleted." ret["changes"]["old"] = name return ret ret["result"] = False - ret["comment"] = "SAML provider {} failed to be deleted.".format(name) + ret["comment"] = f"SAML provider {name} failed to be deleted." return ret diff --git a/salt/states/boto_iam_role.py b/salt/states/boto_iam_role.py index 1ff1abcc5c8..9ddcdfdee39 100644 --- a/salt/states/boto_iam_role.py +++ b/salt/states/boto_iam_role.py @@ -255,7 +255,7 @@ def _role_present( role = __salt__["boto_iam.describe_role"](name, region, key, keyid, profile) if not role: if __opts__["test"]: - ret["comment"] = "IAM role {} is set to be created.".format(name) + ret["comment"] = f"IAM role {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_role"]( @@ -264,12 +264,12 @@ def _role_present( if created: ret["changes"]["old"] = {"role": None} ret["changes"]["new"] = {"role": name} - ret["comment"] = "IAM role {} created.".format(name) + ret["comment"] = f"IAM role {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} IAM role.".format(name) + ret["comment"] = f"Failed to create {name} IAM role." else: - ret["comment"] = "{} role present.".format(name) + ret["comment"] = f"{name} role present." if not policy_document: _policy_document = __salt__["boto_iam.build_policy"]( region, key, keyid, profile @@ -309,7 +309,7 @@ def _instance_profile_present(name, region=None, key=None, keyid=None, profile=N ) if not exists: if __opts__["test"]: - ret["comment"] = "Instance profile {} is set to be created.".format(name) + ret["comment"] = f"Instance profile {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_instance_profile"]( @@ -318,10 +318,10 @@ def _instance_profile_present(name, region=None, key=None, keyid=None, profile=N if created: ret["changes"]["old"] = {"instance_profile": None} ret["changes"]["new"] = {"instance_profile": name} - ret["comment"] = "Instance profile {} created.".format(name) + ret["comment"] = f"Instance profile {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} instance profile.".format(name) + ret["comment"] = f"Failed to create {name} instance profile." return ret @@ -332,7 +332,7 @@ def _instance_profile_associated(name, region=None, key=None, keyid=None, profil ) if not is_associated: if __opts__["test"]: - ret["comment"] = "Instance profile {} is set to be associated.".format(name) + ret["comment"] = f"Instance profile {name} is set to be associated." ret["result"] = None return ret associated = __salt__["boto_iam.associate_profile_to_role"]( @@ -341,7 +341,7 @@ def _instance_profile_associated(name, region=None, key=None, keyid=None, profil if associated: ret["changes"]["old"] = {"profile_associated": None} ret["changes"]["new"] = {"profile_associated": True} - ret["comment"] = "Instance profile {} associated.".format(name) + ret["comment"] = f"Instance profile {name} associated." else: ret["result"] = False ret["comment"] = ( @@ -591,19 +591,19 @@ def _role_absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_iam.role_exists"](name, region, key, keyid, profile) if exists: if __opts__["test"]: - ret["comment"] = "IAM role {} is set to be removed.".format(name) + ret["comment"] = f"IAM role {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_role"](name, region, key, keyid, profile) if deleted: ret["changes"]["old"] = {"role": name} ret["changes"]["new"] = {"role": None} - ret["comment"] = "IAM role {} removed.".format(name) + ret["comment"] = f"IAM role {name} removed." else: ret["result"] = False - ret["comment"] = "Failed to delete {} iam role.".format(name) + ret["comment"] = f"Failed to delete {name} iam role." else: - ret["comment"] = "{} role does not exist.".format(name) + ret["comment"] = f"{name} role does not exist." return ret @@ -615,7 +615,7 @@ def _instance_profile_absent(name, region=None, key=None, keyid=None, profile=No ) if exists: if __opts__["test"]: - ret["comment"] = "Instance profile {} is set to be removed.".format(name) + ret["comment"] = f"Instance profile {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_instance_profile"]( @@ -624,12 +624,12 @@ def _instance_profile_absent(name, region=None, key=None, keyid=None, profile=No if deleted: ret["changes"]["old"] = {"instance_profile": name} ret["changes"]["new"] = {"instance_profile": None} - ret["comment"] = "Instance profile {} removed.".format(name) + ret["comment"] = f"Instance profile {name} removed." else: ret["result"] = False - ret["comment"] = "Failed to delete {} instance profile.".format(name) + ret["comment"] = f"Failed to delete {name} instance profile." else: - ret["comment"] = "{} instance profile does not exist.".format(name) + ret["comment"] = f"{name} instance profile does not exist." return ret @@ -637,7 +637,7 @@ def _policies_absent(name, region=None, key=None, keyid=None, profile=None): ret = {"result": True, "comment": "", "changes": {}} _list = __salt__["boto_iam.list_role_policies"](name, region, key, keyid, profile) if not _list: - ret["comment"] = "No policies in role {}.".format(name) + ret["comment"] = f"No policies in role {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be removed from role {}.".format( @@ -673,7 +673,7 @@ def _policies_detached(name, region=None, key=None, keyid=None, profile=None): ) oldpolicies = [x.get("policy_arn") for x in _list] if not _list: - ret["comment"] = "No attached policies in role {}.".format(name) + ret["comment"] = f"No attached policies in role {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be detached from role {}.".format( @@ -693,7 +693,7 @@ def _policies_detached(name, region=None, key=None, keyid=None, profile=None): newpolicies = [x.get("policy_arn") for x in _list] ret["changes"]["new"] = {"managed_policies": newpolicies} ret["result"] = False - ret["comment"] = "Failed to detach {} from role {}".format(policy_arn, name) + ret["comment"] = f"Failed to detach {policy_arn} from role {name}" return ret _list = __salt__["boto_iam.list_attached_role_policies"]( name, region=region, key=key, keyid=keyid, profile=profile @@ -726,7 +726,7 @@ def _instance_profile_disassociated( if associated: ret["changes"]["old"] = {"profile_associated": True} ret["changes"]["new"] = {"profile_associated": False} - ret["comment"] = "Instance profile {} disassociated.".format(name) + ret["comment"] = f"Instance profile {name} disassociated." else: ret["result"] = False ret["comment"] = ( diff --git a/salt/states/boto_iot.py b/salt/states/boto_iot.py index e14d1541949..bea8f9481f5 100644 --- a/salt/states/boto_iot.py +++ b/salt/states/boto_iot.py @@ -157,7 +157,7 @@ def thing_type_present( return ret if __opts__["test"]: - ret["comment"] = "Thing type {} is set to be created.".format(thingTypeName) + ret["comment"] = f"Thing type {thingTypeName} is set to be created." ret["result"] = None return ret @@ -187,7 +187,7 @@ def thing_type_present( ) ret["changes"]["old"] = {"thing_type": None} ret["changes"]["new"] = _describe - ret["comment"] = "Thing Type {} created.".format(thingTypeName) + ret["comment"] = f"Thing Type {thingTypeName} created." return ret @@ -237,7 +237,7 @@ def thing_type_absent( return ret if _describe and not _describe["thing_type"]: - ret["comment"] = "Thing Type {} does not exist.".format(thingTypeName) + ret["comment"] = f"Thing Type {thingTypeName} does not exist." return ret _existing_thing_type = _describe["thing_type"] @@ -319,7 +319,7 @@ def thing_type_absent( return ret ret["changes"]["old"] = _describe ret["changes"]["new"] = {"thing_type": None} - ret["comment"] = "Thing Type {} deleted.".format(thingTypeName) + ret["comment"] = f"Thing Type {thingTypeName} deleted." return ret @@ -366,7 +366,7 @@ def policy_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Policy {} is set to be created.".format(policyName) + ret["comment"] = f"Policy {policyName} is set to be created." ret["result"] = None return ret r = __salt__["boto_iot.create_policy"]( @@ -388,11 +388,11 @@ def policy_present( ) ret["changes"]["old"] = {"policy": None} ret["changes"]["new"] = _describe - ret["comment"] = "Policy {} created.".format(policyName) + ret["comment"] = f"Policy {policyName} created." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Policy {} is present.".format(policyName)] + [ret["comment"], f"Policy {policyName} is present."] ) ret["changes"] = {} # policy exists, ensure config matches @@ -411,7 +411,7 @@ def policy_present( r = salt.utils.data.compare_dicts(describeDict, policyDocument) if bool(r): if __opts__["test"]: - msg = "Policy {} set to be modified.".format(policyName) + msg = f"Policy {policyName} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -487,11 +487,11 @@ def policy_absent(name, policyName, region=None, key=None, keyid=None, profile=N return ret if r and not r["exists"]: - ret["comment"] = "Policy {} does not exist.".format(policyName) + ret["comment"] = f"Policy {policyName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Policy {} is set to be removed.".format(policyName) + ret["comment"] = f"Policy {policyName} is set to be removed." ret["result"] = None return ret # delete non-default versions @@ -532,7 +532,7 @@ def policy_absent(name, policyName, region=None, key=None, keyid=None, profile=N return ret ret["changes"]["old"] = {"policy": policyName} ret["changes"]["new"] = {"policy": None} - ret["comment"] = "Policy {} deleted.".format(policyName) + ret["comment"] = f"Policy {policyName} deleted." return ret @@ -603,11 +603,11 @@ def policy_attached( return ret ret["changes"]["old"] = {"attached": False} ret["changes"]["new"] = {"attached": True} - ret["comment"] = "Policy {} attached to {}.".format(policyName, principal) + ret["comment"] = f"Policy {policyName} attached to {principal}." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Policy {} is attached.".format(policyName)] + [ret["comment"], f"Policy {policyName} is attached."] ) ret["changes"] = {} @@ -682,11 +682,11 @@ def policy_detached( return ret ret["changes"]["old"] = {"attached": True} ret["changes"]["new"] = {"attached": False} - ret["comment"] = "Policy {} detached from {}.".format(policyName, principal) + ret["comment"] = f"Policy {policyName} detached from {principal}." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Policy {} is detached.".format(policyName)] + [ret["comment"], f"Policy {policyName} is detached."] ) ret["changes"] = {} @@ -752,7 +752,7 @@ def topic_rule_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Rule {} is set to be created.".format(ruleName) + ret["comment"] = f"Rule {ruleName} is set to be created." ret["result"] = None return ret r = __salt__["boto_iot.create_topic_rule"]( @@ -775,12 +775,10 @@ def topic_rule_present( ) ret["changes"]["old"] = {"rule": None} ret["changes"]["new"] = _describe - ret["comment"] = "Rule {} created.".format(ruleName) + ret["comment"] = f"Rule {ruleName} created." return ret - ret["comment"] = os.linesep.join( - [ret["comment"], "Rule {} is present.".format(ruleName)] - ) + ret["comment"] = os.linesep.join([ret["comment"], f"Rule {ruleName} is present."]) ret["changes"] = {} # policy exists, ensure config matches _describe = __salt__["boto_iot.describe_topic_rule"]( @@ -805,7 +803,7 @@ def topic_rule_present( ret["changes"].setdefault("old", {})[var] = _describe[var] if need_update: if __opts__["test"]: - msg = "Rule {} set to be modified.".format(ruleName) + msg = f"Rule {ruleName} set to be modified." ret["changes"] = {} ret["comment"] = msg ret["result"] = None @@ -864,11 +862,11 @@ def topic_rule_absent(name, ruleName, region=None, key=None, keyid=None, profile return ret if r and not r["exists"]: - ret["comment"] = "Rule {} does not exist.".format(ruleName) + ret["comment"] = f"Rule {ruleName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Rule {} is set to be removed.".format(ruleName) + ret["comment"] = f"Rule {ruleName} is set to be removed." ret["result"] = None return ret r = __salt__["boto_iot.delete_topic_rule"]( @@ -880,5 +878,5 @@ def topic_rule_absent(name, ruleName, region=None, key=None, keyid=None, profile return ret ret["changes"]["old"] = {"rule": ruleName} ret["changes"]["new"] = {"rule": None} - ret["comment"] = "Rule {} deleted.".format(ruleName) + ret["comment"] = f"Rule {ruleName} deleted." return ret diff --git a/salt/states/boto_kinesis.py b/salt/states/boto_kinesis.py index 5809ef711e5..938449515c2 100644 --- a/salt/states/boto_kinesis.py +++ b/salt/states/boto_kinesis.py @@ -140,7 +140,7 @@ def present( if exists["result"] is False: if __opts__["test"]: ret["result"] = None - comments.append("Kinesis stream {} would be created".format(name)) + comments.append(f"Kinesis stream {name} would be created") _add_changes(ret, changes_old, changes_new, comments) return ret else: @@ -155,11 +155,11 @@ def present( _add_changes(ret, changes_old, changes_new, comments) return ret - comments.append("Kinesis stream {} successfully created".format(name)) + comments.append(f"Kinesis stream {name} successfully created") changes_new["name"] = name changes_new["num_shards"] = num_shards else: - comments.append("Kinesis stream {} already exists".format(name)) + comments.append(f"Kinesis stream {name} already exists") stream_response = __salt__["boto_kinesis.get_stream_when_active"]( name, region, key, keyid, profile @@ -238,9 +238,7 @@ def present( " at {}".format(name, old_retention_hours) ) else: - comments.append( - "Kinesis stream {}: did not configure retention hours".format(name) - ) + comments.append(f"Kinesis stream {name}: did not configure retention hours") # Configure enhanced monitoring if enhanced_monitoring is not None: @@ -345,9 +343,7 @@ def present( enhanced_monitoring if len(enhanced_monitoring) > 0 else "None" ) else: - comments.append( - "Kinesis stream {}: did not configure enhanced monitoring".format(name) - ) + comments.append(f"Kinesis stream {name}: did not configure enhanced monitoring") # Reshard stream if necessary min_hash_key, max_hash_key, full_stream_details = __salt__[ @@ -439,11 +435,11 @@ def absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_kinesis.exists"](name, region, key, keyid, profile) if exists["result"] is False: - ret["comment"] = "Kinesis stream {} does not exist".format(name) + ret["comment"] = f"Kinesis stream {name} does not exist" return ret if __opts__["test"]: - ret["comment"] = "Kinesis stream {} would be deleted".format(name) + ret["comment"] = f"Kinesis stream {name} would be deleted" ret["result"] = None return ret @@ -456,9 +452,9 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ) ret["result"] = False else: - ret["comment"] = "Deleted stream {}".format(name) - ret["changes"].setdefault("old", "Stream {} exists".format(name)) - ret["changes"].setdefault("new", "Stream {} deleted".format(name)) + ret["comment"] = f"Deleted stream {name}" + ret["changes"].setdefault("old", f"Stream {name} exists") + ret["changes"].setdefault("new", f"Stream {name} deleted") return ret diff --git a/salt/states/boto_kms.py b/salt/states/boto_kms.py index aadc02093e8..3c542541304 100644 --- a/salt/states/boto_kms.py +++ b/salt/states/boto_kms.py @@ -174,7 +174,7 @@ def _key_present( profile, ): ret = {"result": True, "comment": "", "changes": {}} - alias = "alias/{}".format(name) + alias = f"alias/{name}" r = __salt__["boto_kms.key_exists"](alias, region, key, keyid, profile) if "error" in r: ret["result"] = False @@ -212,7 +212,7 @@ def _key_present( return ret ret["changes"]["old"] = {"key": None} ret["changes"]["new"] = {"key": name} - ret["comment"] = "Key {} created.".format(name) + ret["comment"] = f"Key {name} created." else: rd = __salt__["boto_kms.describe_key"](alias, region, key, keyid, profile) if "error" in rd: @@ -271,7 +271,7 @@ def _key_enabled(key_metadata, enabled, region, key, keyid, profile): re["error"]["message"] ) else: - ret["comment"] = "{} key.".format(event) + ret["comment"] = f"{event} key." return ret @@ -339,7 +339,7 @@ def _key_rotation(key_metadata, key_rotation, region, key, keyid, profile): "old": {"key_rotation": not key_rotation}, "new": {"key_rotation": key_rotation}, } - ret["comment"] = "Set key rotation policy to {}.".format(key_rotation) + ret["comment"] = f"Set key rotation policy to {key_rotation}." return ret diff --git a/salt/states/boto_lambda.py b/salt/states/boto_lambda.py index 2a0cb1c20a3..0ce5a513c06 100644 --- a/salt/states/boto_lambda.py +++ b/salt/states/boto_lambda.py @@ -248,7 +248,7 @@ def function_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Function {} is set to be created.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} is set to be created." ret["result"] = None return ret r = __salt__["boto_lambda.create_function"]( @@ -288,7 +288,7 @@ def function_present( key=key, keyid=keyid, profile=profile, - **permission + **permission, ) if not r.get("updated"): ret["result"] = False @@ -304,11 +304,11 @@ def function_present( )["permissions"] ret["changes"]["old"] = {"function": None} ret["changes"]["new"] = _describe - ret["comment"] = "Function {} created.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} created." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Function {} is present.".format(FunctionName)] + [ret["comment"], f"Function {FunctionName} is present."] ) ret["changes"] = {} # function exists, ensure config matches @@ -372,7 +372,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): account_id = __salt__["boto_iam.get_account_id"]( region=region, key=key, keyid=keyid, profile=profile ) - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def _resolve_vpcconfig(conf, region=None, key=None, keyid=None, profile=None): @@ -460,7 +460,7 @@ def _function_config_present( [ret["comment"], "Function config to be modified"] ) if __opts__["test"]: - ret["comment"] = "Function {} set to be modified.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} set to be modified." ret["result"] = None return ret _r = __salt__["boto_lambda.update_function_config"]( @@ -501,7 +501,7 @@ def _function_code_present( dlZipFile = __salt__["cp.cache_file"](path=ZipFile) if dlZipFile is False: ret["result"] = False - ret["comment"] = "Failed to cache ZipFile `{}`.".format(ZipFile) + ret["comment"] = f"Failed to cache ZipFile `{ZipFile}`." return ret ZipFile = dlZipFile size = os.path.getsize(ZipFile) @@ -521,7 +521,7 @@ def _function_code_present( update = True if update: if __opts__["test"]: - ret["comment"] = "Function {} set to be modified.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} set to be modified." ret["result"] = None return ret ret["changes"]["old"] = { @@ -579,7 +579,7 @@ def _function_permissions_present( [ret["comment"], "Function permissions to be modified"] ) if __opts__["test"]: - ret["comment"] = "Function {} set to be modified.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} set to be modified." ret["result"] = None return ret for sid, diff in diffs.items(): @@ -608,7 +608,7 @@ def _function_permissions_present( key=key, keyid=keyid, profile=profile, - **diff["new"] + **diff["new"], ) ret["changes"].setdefault("new", {}).setdefault("Permissions", {})[ sid @@ -664,11 +664,11 @@ def function_absent( return ret if r and not r["exists"]: - ret["comment"] = "Function {} does not exist.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Function {} is set to be removed.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} is set to be removed." ret["result"] = None return ret r = __salt__["boto_lambda.delete_function"]( @@ -680,7 +680,7 @@ def function_absent( return ret ret["changes"]["old"] = {"function": FunctionName} ret["changes"]["new"] = {"function": None} - ret["comment"] = "Function {} deleted.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} deleted." return ret @@ -745,7 +745,7 @@ def alias_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Alias {} is set to be created.".format(Name) + ret["comment"] = f"Alias {Name} is set to be created." ret["result"] = None return ret r = __salt__["boto_lambda.create_alias"]( @@ -767,12 +767,10 @@ def alias_present( ) ret["changes"]["old"] = {"alias": None} ret["changes"]["new"] = _describe - ret["comment"] = "Alias {} created.".format(Name) + ret["comment"] = f"Alias {Name} created." return ret - ret["comment"] = os.linesep.join( - [ret["comment"], "Alias {} is present.".format(Name)] - ) + ret["comment"] = os.linesep.join([ret["comment"], f"Alias {Name} is present."]) ret["changes"] = {} _describe = __salt__["boto_lambda.describe_alias"]( FunctionName, Name, region=region, key=key, keyid=keyid, profile=profile @@ -791,7 +789,7 @@ def alias_present( [ret["comment"], "Alias config to be modified"] ) if __opts__["test"]: - ret["comment"] = "Alias {} set to be modified.".format(Name) + ret["comment"] = f"Alias {Name} set to be modified." ret["result"] = None return ret _r = __salt__["boto_lambda.update_alias"]( @@ -853,11 +851,11 @@ def alias_absent( return ret if r and not r["exists"]: - ret["comment"] = "Alias {} does not exist.".format(Name) + ret["comment"] = f"Alias {Name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Alias {} is set to be removed.".format(Name) + ret["comment"] = f"Alias {Name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_lambda.delete_alias"]( @@ -869,7 +867,7 @@ def alias_absent( return ret ret["changes"]["old"] = {"alias": Name} ret["changes"]["new"] = {"alias": None} - ret["comment"] = "Alias {} deleted.".format(Name) + ret["comment"] = f"Alias {Name} deleted." return ret @@ -884,7 +882,7 @@ def _get_function_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:lambda:{}:{}:function:{}".format(region, account_id, name) + return f"arn:aws:lambda:{region}:{account_id}:function:{name}" def event_source_mapping_present( diff --git a/salt/states/boto_rds.py b/salt/states/boto_rds.py index e7af123149e..5d33a01925f 100644 --- a/salt/states/boto_rds.py +++ b/salt/states/boto_rds.py @@ -305,7 +305,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "RDS instance {} would be created.".format(name) + ret["comment"] = f"RDS instance {name} would be created." ret["result"] = None return ret @@ -373,9 +373,9 @@ def present( profile=profile, ) } - ret["comment"] = "RDS instance {} created.".format(name) + ret["comment"] = f"RDS instance {name} created." else: - ret["comment"] = "RDS instance {} exists.".format(name) + ret["comment"] = f"RDS instance {name} exists." return ret @@ -412,7 +412,7 @@ def replica_present( ) if not replica_exists.get("exists"): if __opts__["test"]: - ret["comment"] = "RDS read replica {} is set to be created ".format(name) + ret["comment"] = f"RDS read replica {name} is set to be created " ret["result"] = None return ret created = __salt__["boto_rds.create_read_replica"]( @@ -432,7 +432,7 @@ def replica_present( profile, ) if created: - ret["comment"] = "RDS replica {} created.".format(name) + ret["comment"] = f"RDS replica {name} created." ret["changes"]["old"] = {"instance": None} ret["changes"]["new"] = { "instance": __salt__["boto_rds.describe_db_instances"]( @@ -446,7 +446,7 @@ def replica_present( } else: ret["result"] = False - ret["comment"] = "Failed to create RDS replica {}.".format(name) + ret["comment"] = f"Failed to create RDS replica {name}." else: jmespath = "DBInstances[0].DBParameterGroups[0].DBParameterGroupName" pmg_name = __salt__["boto_rds.describe_db_instances"]( @@ -470,12 +470,12 @@ def replica_present( if not modified: ret["result"] = False ret["comment"] = ( - "Failed to update parameter group of {} RDS instance.".format(name) + f"Failed to update parameter group of {name} RDS instance." ) ret["changes"]["old"] = pmg_name ret["changes"]["new"] = db_parameter_group_name ret["result"] = True - ret["comment"] = "RDS replica {} exists.".format(name) + ret["comment"] = f"RDS replica {name} exists." return ret @@ -546,7 +546,7 @@ def subnet_group_present( ret["result"] = False return ret if r["id"] is None: - ret["comment"] = "Subnet {} does not exist.".format(i) + ret["comment"] = f"Subnet {i} does not exist." ret["result"] = False return ret subnet_ids.append(r["id"]) @@ -556,7 +556,7 @@ def subnet_group_present( ) if not exists.get("exists"): if __opts__["test"]: - ret["comment"] = "Subnet group {} is set to be created.".format(name) + ret["comment"] = f"Subnet group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_rds.create_subnet_group"]( @@ -572,14 +572,14 @@ def subnet_group_present( if not created: ret["result"] = False - ret["comment"] = "Failed to create {} subnet group.".format(name) + ret["comment"] = f"Failed to create {name} subnet group." return ret ret["changes"]["old"] = None ret["changes"]["new"] = name - ret["comment"] = "Subnet {} created.".format(name) + ret["comment"] = f"Subnet {name} created." return ret else: - ret["comment"] = "Subnet {} present.".format(name) + ret["comment"] = f"Subnet {name} present." return ret @@ -641,11 +641,11 @@ def absent( ) if not current: ret["result"] = True - ret["comment"] = "{} RDS already absent.".format(name) + ret["comment"] = f"{name} RDS already absent." return ret if __opts__["test"]: - ret["comment"] = "RDS {} would be removed.".format(name) + ret["comment"] = f"RDS {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto_rds.delete"]( @@ -662,11 +662,11 @@ def absent( ) if not deleted: ret["result"] = False - ret["comment"] = "Failed to delete {} RDS.".format(name) + ret["comment"] = f"Failed to delete {name} RDS." return ret ret["changes"]["old"] = {"instance": current[0]} ret["changes"]["new"] = {"instance": None} - ret["comment"] = "RDS {} deleted.".format(name) + ret["comment"] = f"RDS {name} deleted." return ret @@ -680,11 +680,11 @@ def subnet_group_absent( ) if not exists: ret["result"] = True - ret["comment"] = "{} RDS subnet group does not exist.".format(name) + ret["comment"] = f"{name} RDS subnet group does not exist." return ret if __opts__["test"]: - ret["comment"] = "RDS subnet group {} is set to be removed.".format(name) + ret["comment"] = f"RDS subnet group {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_rds.delete_subnet_group"]( @@ -692,11 +692,11 @@ def subnet_group_absent( ) if not deleted: ret["result"] = False - ret["comment"] = "Failed to delete {} RDS subnet group.".format(name) + ret["comment"] = f"Failed to delete {name} RDS subnet group." return ret ret["changes"]["old"] = name ret["changes"]["new"] = None - ret["comment"] = "RDS subnet group {} deleted.".format(name) + ret["comment"] = f"RDS subnet group {name} deleted." return ret @@ -761,7 +761,7 @@ def parameter_present( ) if not res.get("exists"): if __opts__["test"]: - ret["comment"] = "Parameter group {} is set to be created.".format(name) + ret["comment"] = f"Parameter group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_rds.create_parameter_group"]( @@ -776,12 +776,12 @@ def parameter_present( ) if not created: ret["result"] = False - ret["comment"] = "Failed to create {} parameter group.".format(name) + ret["comment"] = f"Failed to create {name} parameter group." return ret ret["changes"]["New Parameter Group"] = name - ret["comment"] = "Parameter group {} created.".format(name) + ret["comment"] = f"Parameter group {name} created." else: - ret["comment"] = "Parameter group {} present.".format(name) + ret["comment"] = f"Parameter group {name} present." if parameters is not None: params = {} changed = {} @@ -798,7 +798,7 @@ def parameter_present( if not options.get("result"): ret["result"] = False ret["comment"] = os.linesep.join( - [ret["comment"], "Faled to get parameters for group {}.".format(name)] + [ret["comment"], f"Faled to get parameters for group {name}."] ) return ret for parameter in options["parameters"].values(): @@ -852,14 +852,14 @@ def parameter_present( ret["comment"] = os.linesep.join( [ ret["comment"], - "Parameters {} for group {} are changed.".format(changed, name), + f"Parameters {changed} for group {name} are changed.", ] ) else: ret["comment"] = os.linesep.join( [ ret["comment"], - "Parameters {} for group {} are present.".format(params, name), + f"Parameters {params} for group {name} are present.", ] ) return ret diff --git a/salt/states/boto_route53.py b/salt/states/boto_route53.py index 2f2792c6449..39ed57aca52 100644 --- a/salt/states/boto_route53.py +++ b/salt/states/boto_route53.py @@ -210,13 +210,13 @@ def present( identifier, ) except SaltInvocationError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" ret["result"] = False return ret if isinstance(record, dict) and not record: if __opts__["test"]: - ret["comment"] = "Route53 record {} set to be added.".format(name) + ret["comment"] = f"Route53 record {name} set to be added." ret["result"] = None return ret added = __salt__["boto_route53.add_record"]( @@ -243,10 +243,10 @@ def present( "ttl": ttl, "identifier": identifier, } - ret["comment"] = "Added {} Route53 record.".format(name) + ret["comment"] = f"Added {name} Route53 record." else: ret["result"] = False - ret["comment"] = "Failed to add {} Route53 record.".format(name) + ret["comment"] = f"Failed to add {name} Route53 record." return ret elif record: need_to_update = False @@ -267,7 +267,7 @@ def present( need_to_update = True if need_to_update: if __opts__["test"]: - ret["comment"] = "Route53 record {} set to be updated.".format(name) + ret["comment"] = f"Route53 record {name} set to be updated." ret["result"] = None return ret updated = __salt__["boto_route53.update_record"]( @@ -294,12 +294,12 @@ def present( "ttl": ttl, "identifier": identifier, } - ret["comment"] = "Updated {} Route53 record.".format(name) + ret["comment"] = f"Updated {name} Route53 record." else: ret["result"] = False - ret["comment"] = "Failed to update {} Route53 record.".format(name) + ret["comment"] = f"Failed to update {name} Route53 record." else: - ret["comment"] = "{} exists.".format(name) + ret["comment"] = f"{name} exists." return ret @@ -375,7 +375,7 @@ def absent( ) if record: if __opts__["test"]: - ret["comment"] = "Route53 record {} set to be deleted.".format(name) + ret["comment"] = f"Route53 record {name} set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_route53.delete_record"]( @@ -395,12 +395,12 @@ def absent( if deleted: ret["changes"]["old"] = record ret["changes"]["new"] = None - ret["comment"] = "Deleted {} Route53 record.".format(name) + ret["comment"] = f"Deleted {name} Route53 record." else: ret["result"] = False - ret["comment"] = "Failed to delete {} Route53 record.".format(name) + ret["comment"] = f"Failed to delete {name} Route53 record." else: - ret["comment"] = "{} does not exist.".format(name) + ret["comment"] = f"{name} does not exist." return ret @@ -574,13 +574,13 @@ def hosted_zone_present( profile=profile, ) if res: - msg = "Hosted Zone {} successfully created".format(domain_name) + msg = f"Hosted Zone {domain_name} successfully created" log.info(msg) ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = res else: - ret["comment"] = "Creating Hosted Zone {} failed".format(domain_name) + ret["comment"] = f"Creating Hosted Zone {domain_name} failed" ret["result"] = False return ret @@ -608,11 +608,11 @@ def hosted_zone_absent( domain_name=domain_name, region=region, key=key, keyid=keyid, profile=profile ) if not deets: - ret["comment"] = "Hosted Zone {} already absent".format(domain_name) + ret["comment"] = f"Hosted Zone {domain_name} already absent" log.info(ret["comment"]) return ret if __opts__["test"]: - ret["comment"] = "Route53 Hosted Zone {} set to be deleted.".format(domain_name) + ret["comment"] = f"Route53 Hosted Zone {domain_name} set to be deleted." ret["result"] = None return ret # Not entirely comfortable with this - no safety checks around pub/priv, VPCs @@ -621,7 +621,7 @@ def hosted_zone_absent( if __salt__["boto_route53.delete_zone"]( zone=domain_name, region=region, key=key, keyid=keyid, profile=profile ): - ret["comment"] = "Route53 Hosted Zone {} deleted".format(domain_name) + ret["comment"] = f"Route53 Hosted Zone {domain_name} deleted" log.info(ret["comment"]) ret["changes"]["old"] = deets ret["changes"]["new"] = None diff --git a/salt/states/boto_s3.py b/salt/states/boto_s3.py index d5ab644a661..e80f25c8539 100644 --- a/salt/states/boto_s3.py +++ b/salt/states/boto_s3.py @@ -176,7 +176,7 @@ def object_present( combined_extra_args_keys = frozenset(combined_extra_args.keys()) extra_keys = combined_extra_args_keys - supported_args if extra_keys: - msg = "extra_args keys {} are not supported".format(extra_keys) + msg = f"extra_args keys {extra_keys} are not supported" return {"error": msg} # Get the hash of the local file @@ -252,7 +252,7 @@ def object_present( } if s3_metadata == desired_metadata: ret["result"] = True - ret["comment"] = "S3 object {} is present.".format(name) + ret["comment"] = f"S3 object {name} is present." return ret action = "update" else: @@ -276,8 +276,8 @@ def object_present( if __opts__["test"]: ret["result"] = None - ret["comment"] = "S3 object {} set to be {}d.".format(name, action) - ret["comment"] += "\nChanges:\n{}".format(changes_diff) + ret["comment"] = f"S3 object {name} set to be {action}d." + ret["comment"] += f"\nChanges:\n{changes_diff}" ret["changes"] = {"diff": changes_diff} return ret @@ -300,7 +300,7 @@ def object_present( return ret ret["result"] = True - ret["comment"] = "S3 object {} {}d.".format(name, action) - ret["comment"] += "\nChanges:\n{}".format(changes_diff) + ret["comment"] = f"S3 object {name} {action}d." + ret["comment"] += f"\nChanges:\n{changes_diff}" ret["changes"] = {"diff": changes_diff} return ret diff --git a/salt/states/boto_s3_bucket.py b/salt/states/boto_s3_bucket.py index d3a4067dd47..9baee1f5350 100644 --- a/salt/states/boto_s3_bucket.py +++ b/salt/states/boto_s3_bucket.py @@ -298,7 +298,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def _compare_json(current, desired, region, key, keyid, profile): @@ -439,7 +439,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "S3 bucket {} is set to be created.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} is set to be created." ret["result"] = None return ret r = __salt__["boto_s3_bucket.create"]( @@ -480,13 +480,13 @@ def present( ("put_website", Website, Website), ): if testval is not None: - r = __salt__["boto_s3_bucket.{}".format(setter)]( + r = __salt__[f"boto_s3_bucket.{setter}"]( Bucket=Bucket, region=region, key=key, keyid=keyid, profile=profile, - **funcargs + **funcargs, ) if not r.get("updated"): ret["result"] = False @@ -500,14 +500,12 @@ def present( ) ret["changes"]["old"] = {"bucket": None} ret["changes"]["new"] = _describe - ret["comment"] = "S3 bucket {} created.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} created." return ret # bucket exists, ensure config matches - ret["comment"] = " ".join( - [ret["comment"], "S3 bucket {} is present.".format(Bucket)] - ) + ret["comment"] = " ".join([ret["comment"], f"S3 bucket {Bucket} is present."]) ret["changes"] = {} _describe = __salt__["boto_s3_bucket.describe"]( Bucket=Bucket, region=region, key=key, keyid=keyid, profile=profile @@ -646,7 +644,7 @@ def present( if not __opts__["test"]: if deleter and desired is None: # Setting can be deleted, so use that to unset it - r = __salt__["boto_s3_bucket.{}".format(deleter)]( + r = __salt__[f"boto_s3_bucket.{deleter}"]( Bucket=Bucket, region=region, key=key, @@ -661,13 +659,13 @@ def present( ret["changes"] = {} return ret else: - r = __salt__["boto_s3_bucket.{}".format(setter)]( + r = __salt__[f"boto_s3_bucket.{setter}"]( Bucket=Bucket, region=region, key=key, keyid=keyid, profile=profile, - **(desired or {}) + **(desired or {}), ) if not r.get("updated"): ret["result"] = False @@ -677,7 +675,7 @@ def present( ret["changes"] = {} return ret if update and __opts__["test"]: - msg = "S3 bucket {} set to be modified.".format(Bucket) + msg = f"S3 bucket {Bucket} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -692,7 +690,7 @@ def present( ) log.warning(msg) ret["result"] = False - ret["comment"] = "Failed to update bucket: {}.".format(msg) + ret["comment"] = f"Failed to update bucket: {msg}." return ret return ret @@ -736,11 +734,11 @@ def absent(name, Bucket, Force=False, region=None, key=None, keyid=None, profile return ret if r and not r["exists"]: - ret["comment"] = "S3 bucket {} does not exist.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} does not exist." return ret if __opts__["test"]: - ret["comment"] = "S3 bucket {} is set to be removed.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} is set to be removed." ret["result"] = None return ret r = __salt__["boto_s3_bucket.delete"]( @@ -752,5 +750,5 @@ def absent(name, Bucket, Force=False, region=None, key=None, keyid=None, profile return ret ret["changes"]["old"] = {"bucket": Bucket} ret["changes"]["new"] = {"bucket": None} - ret["comment"] = "S3 bucket {} deleted.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} deleted." return ret diff --git a/salt/states/boto_secgroup.py b/salt/states/boto_secgroup.py index 983ef5b80e5..23ef79e32f9 100644 --- a/salt/states/boto_secgroup.py +++ b/salt/states/boto_secgroup.py @@ -283,7 +283,7 @@ def _security_group_present( ) if not exists: if __opts__["test"]: - ret["comment"] = "Security group {} is set to be created.".format(name) + ret["comment"] = f"Security group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_secgroup.create"]( @@ -309,12 +309,12 @@ def _security_group_present( vpc_name=vpc_name, ) ret["changes"]["new"] = {"secgroup": sg} - ret["comment"] = "Security group {} created.".format(name) + ret["comment"] = f"Security group {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} security group.".format(name) + ret["comment"] = f"Failed to create {name} security group." else: - ret["comment"] = "Security group {} present.".format(name) + ret["comment"] = f"Security group {name} present." return ret @@ -422,7 +422,7 @@ def _get_rule_changes(rules, _rules): -1, ] if ip_protocol not in supported_protocols and ( - not "{}".format(ip_protocol).isdigit() or int(ip_protocol) > 255 + not f"{ip_protocol}".isdigit() or int(ip_protocol) > 255 ): raise SaltInvocationError( "Invalid ip_protocol {} specified in security group rule.".format( @@ -509,9 +509,7 @@ def _rules_present( vpc_name=vpc_name, ) if not sg: - ret["comment"] = ( - "{} security group configuration could not be retrieved.".format(name) - ) + ret["comment"] = f"{name} security group configuration could not be retrieved." ret["result"] = False return ret rules = _split_rules(rules) @@ -568,12 +566,12 @@ def _rules_present( key=key, keyid=keyid, profile=profile, - **rule + **rule, ) if not _deleted: deleted = False if deleted: - ret["comment"] = "Removed rules on {} security group.".format(name) + ret["comment"] = f"Removed rules on {name} security group." else: ret["comment"] = "Failed to remove rules on {} security group.".format( name @@ -590,7 +588,7 @@ def _rules_present( key=key, keyid=keyid, profile=profile, - **rule + **rule, ) if not _created: created = False @@ -598,14 +596,14 @@ def _rules_present( ret["comment"] = " ".join( [ ret["comment"], - "Created rules on {} security group.".format(name), + f"Created rules on {name} security group.", ] ) else: ret["comment"] = " ".join( [ ret["comment"], - "Failed to create rules on {} security group.".format(name), + f"Failed to create rules on {name} security group.", ] ) ret["result"] = False @@ -654,9 +652,7 @@ def _rules_egress_present( vpc_name=vpc_name, ) if not sg: - ret["comment"] = ( - "{} security group configuration could not be retrieved.".format(name) - ) + ret["comment"] = f"{name} security group configuration could not be retrieved." ret["result"] = False return ret rules_egress = _split_rules(rules_egress) @@ -714,7 +710,7 @@ def _rules_egress_present( keyid=keyid, profile=profile, egress=True, - **rule + **rule, ) if not _deleted: deleted = False @@ -722,7 +718,7 @@ def _rules_egress_present( ret["comment"] = " ".join( [ ret["comment"], - "Removed egress rule on {} security group.".format(name), + f"Removed egress rule on {name} security group.", ] ) else: @@ -747,7 +743,7 @@ def _rules_egress_present( keyid=keyid, profile=profile, egress=True, - **rule + **rule, ) if not _created: created = False @@ -755,7 +751,7 @@ def _rules_egress_present( ret["comment"] = " ".join( [ ret["comment"], - "Created egress rules on {} security group.".format(name), + f"Created egress rules on {name} security group.", ] ) else: @@ -831,7 +827,7 @@ def absent( if sg: if __opts__["test"]: - ret["comment"] = "Security group {} is set to be removed.".format(name) + ret["comment"] = f"Security group {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_secgroup.delete"]( @@ -847,12 +843,12 @@ def absent( if deleted: ret["changes"]["old"] = {"secgroup": sg} ret["changes"]["new"] = {"secgroup": None} - ret["comment"] = "Security group {} deleted.".format(name) + ret["comment"] = f"Security group {name} deleted." else: ret["result"] = False - ret["comment"] = "Failed to delete {} security group.".format(name) + ret["comment"] = f"Failed to delete {name} security group." else: - ret["comment"] = "{} security group does not exist.".format(name) + ret["comment"] = f"{name} security group does not exist." return ret @@ -883,7 +879,7 @@ def _tags_present( ) if not sg: ret["comment"] = ( - "{} security group configuration could not be retrieved.".format(name) + f"{name} security group configuration could not be retrieved." ) ret["result"] = False return ret diff --git a/salt/states/boto_sns.py b/salt/states/boto_sns.py index d4e4c05133b..387a29868c9 100644 --- a/salt/states/boto_sns.py +++ b/salt/states/boto_sns.py @@ -106,10 +106,10 @@ def present(name, subscriptions=None, region=None, key=None, keyid=None, profile ) if is_present: ret["result"] = True - ret["comment"] = "AWS SNS topic {} present.".format(name) + ret["comment"] = f"AWS SNS topic {name} present." else: if __opts__["test"]: - msg = "AWS SNS topic {} is set to be created.".format(name) + msg = f"AWS SNS topic {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -118,13 +118,13 @@ def present(name, subscriptions=None, region=None, key=None, keyid=None, profile name, region=region, key=key, keyid=keyid, profile=profile ) if created: - msg = "AWS SNS topic {} created.".format(name) + msg = f"AWS SNS topic {name} created." ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = {"topic": name, "subscriptions": []} ret["result"] = True else: - ret["comment"] = "Failed to create {} AWS SNS topic".format(name) + ret["comment"] = f"Failed to create {name} AWS SNS topic" ret["result"] = False return ret @@ -264,7 +264,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None, unsubscribe=Fa name, region=region, key=key, keyid=keyid, profile=profile ) if deleted: - ret["comment"] = "AWS SNS topic {} deleted.".format(name) + ret["comment"] = f"AWS SNS topic {name} deleted." ret["changes"]["new"] = None if unsubscribe is False: ret["changes"]["old"] = {"topic": name} @@ -276,8 +276,8 @@ def absent(name, region=None, key=None, keyid=None, profile=None, unsubscribe=Fa } else: ret["result"] = False - ret["comment"] = "Failed to delete {} AWS SNS topic.".format(name) + ret["comment"] = f"Failed to delete {name} AWS SNS topic." else: - ret["comment"] = "AWS SNS topic {} does not exist.".format(name) + ret["comment"] = f"AWS SNS topic {name} does not exist." return ret diff --git a/salt/states/boto_sqs.py b/salt/states/boto_sqs.py index 0c3784070c9..6f0e4b3a61a 100644 --- a/salt/states/boto_sqs.py +++ b/salt/states/boto_sqs.py @@ -124,12 +124,12 @@ def present( return ret if r["result"]: - ret["comment"].append("SQS queue {} present.".format(name)) + ret["comment"].append(f"SQS queue {name} present.") else: if __opts__["test"]: ret["result"] = None ret["comment"].append( - "SQS queue {} is set to be created.".format(name), + f"SQS queue {name} is set to be created.", ) ret["changes"] = {"old": None, "new": name} return ret @@ -149,7 +149,7 @@ def present( ) return ret - ret["comment"].append("SQS queue {} created.".format(name)) + ret["comment"].append(f"SQS queue {name} created.") ret["changes"]["old"] = None ret["changes"]["new"] = name # Return immediately, as the create call also set all attributes @@ -238,7 +238,7 @@ def present( return ret ret["comment"].append( - "Updated SQS queue attribute(s) {}.".format(attr_names), + f"Updated SQS queue attribute(s) {attr_names}.", ) ret["changes"]["attributes"] = {"diff": attributes_diff} return ret @@ -293,7 +293,7 @@ def absent( if __opts__["test"]: ret["result"] = None - ret["comment"] = "SQS queue {} is set to be removed.".format(name) + ret["comment"] = f"SQS queue {name} is set to be removed." ret["changes"] = {"old": name, "new": None} return ret @@ -309,7 +309,7 @@ def absent( ret["comment"] = str(r["error"]) return ret - ret["comment"] = "SQS queue {} was deleted.".format(name) + ret["comment"] = f"SQS queue {name} was deleted." ret["changes"]["old"] = name ret["changes"]["new"] = None return ret diff --git a/salt/states/boto_vpc.py b/salt/states/boto_vpc.py index d0a567fad35..d65d3ca7255 100644 --- a/salt/states/boto_vpc.py +++ b/salt/states/boto_vpc.py @@ -227,7 +227,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "VPC {} is set to be created.".format(name) + ret["comment"] = f"VPC {name} is set to be created." ret["result"] = None return ret r = __salt__["boto_vpc.create"]( @@ -251,7 +251,7 @@ def present( ) ret["changes"]["old"] = {"vpc": None} ret["changes"]["new"] = _describe - ret["comment"] = "VPC {} created.".format(name) + ret["comment"] = f"VPC {name} created." return ret ret["comment"] = "VPC present." return ret @@ -293,11 +293,11 @@ def absent(name, tags=None, region=None, key=None, keyid=None, profile=None): _id = r.get("id") if not _id: - ret["comment"] = "{} VPC does not exist.".format(name) + ret["comment"] = f"{name} VPC does not exist." return ret if __opts__["test"]: - ret["comment"] = "VPC {} is set to be removed.".format(name) + ret["comment"] = f"VPC {name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_vpc.delete"]( @@ -309,7 +309,7 @@ def absent(name, tags=None, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"vpc": _id} ret["changes"]["new"] = {"vpc": None} - ret["comment"] = "VPC {} deleted.".format(name) + ret["comment"] = f"VPC {name} deleted." return ret @@ -428,7 +428,7 @@ def dhcp_options_present( return ret else: if __opts__["test"]: - ret["comment"] = "DHCP options {} are set to be created.".format(name) + ret["comment"] = f"DHCP options {name} are set to be created." ret["result"] = None return ret @@ -456,7 +456,7 @@ def dhcp_options_present( ret["changes"]["old"] = {"dhcp_options": None} ret["changes"]["new"] = {"dhcp_options": _new} - ret["comment"] = "DHCP options {} created.".format(name) + ret["comment"] = f"DHCP options {name} created." return ret @@ -508,11 +508,11 @@ def dhcp_options_absent( _id = r.get("id") if not _id: - ret["comment"] = "DHCP options {} do not exist.".format(name) + ret["comment"] = f"DHCP options {name} do not exist." return ret if __opts__["test"]: - ret["comment"] = "DHCP options {} are set to be deleted.".format(name) + ret["comment"] = f"DHCP options {name} are set to be deleted." ret["result"] = None return ret @@ -528,7 +528,7 @@ def dhcp_options_absent( ret["changes"]["old"] = {"dhcp_options": _id} ret["changes"]["new"] = {"dhcp_options": None} - ret["comment"] = "DHCP options {} deleted.".format(name) + ret["comment"] = f"DHCP options {name} deleted." return ret @@ -667,7 +667,7 @@ def subnet_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Subnet {} is set to be created.".format(name) + ret["comment"] = f"Subnet {name} is set to be created." ret["result"] = None return ret r = __salt__["boto_vpc.create_subnet"]( @@ -692,7 +692,7 @@ def subnet_present( ) ret["changes"]["old"] = {"subnet": None} ret["changes"]["new"] = _describe - ret["comment"] = "Subnet {} created.".format(name) + ret["comment"] = f"Subnet {name} created." else: ret["comment"] = "Subnet present." @@ -703,7 +703,7 @@ def subnet_present( ) if not _verify_subnet_association(route_table_desc, _describe["subnet"]["id"]): if __opts__["test"]: - msg = "Subnet is set to be associated with route table {}".format(rtid) + msg = f"Subnet is set to be associated with route table {rtid}" ret["comment"] = " ".join([ret["comment"], msg]) ret["result"] = None return ret @@ -741,7 +741,7 @@ def subnet_present( ret["result"] = False return ret else: - msg = "Subnet successfully associated with route table {}.".format(rtid) + msg = f"Subnet successfully associated with route table {rtid}." ret["comment"] = " ".join([ret["comment"], msg]) if "new" not in ret["changes"]: ret["changes"]["new"] = __salt__["boto_vpc.describe_subnet"]( @@ -759,7 +759,7 @@ def subnet_present( ret["comment"] = " ".join( [ ret["comment"], - "Subnet is already associated with route table {}".format(rtid), + f"Subnet is already associated with route table {rtid}", ] ) return ret @@ -821,7 +821,7 @@ def subnet_absent( _id = r.get("id") if not _id: - ret["comment"] = "{} subnet does not exist.".format(name) + ret["comment"] = f"{name} subnet does not exist." return ret if __opts__["test"]: @@ -839,7 +839,7 @@ def subnet_absent( ret["changes"]["old"] = {"subnet": _id} ret["changes"]["new"] = {"subnet": None} - ret["comment"] = "Subnet {} deleted.".format(name) + ret["comment"] = f"Subnet {name} deleted." return ret @@ -902,7 +902,7 @@ def internet_gateway_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Internet gateway {} is set to be created.".format(name) + ret["comment"] = f"Internet gateway {name} is set to be created." ret["result"] = None return ret r = __salt__["boto_vpc.create_internet_gateway"]( @@ -924,9 +924,9 @@ def internet_gateway_present( ret["changes"]["old"] = {"internet_gateway": None} ret["changes"]["new"] = {"internet_gateway": r["id"]} - ret["comment"] = "Internet gateway {} created.".format(name) + ret["comment"] = f"Internet gateway {name} created." return ret - ret["comment"] = "Internet gateway {} present.".format(name) + ret["comment"] = f"Internet gateway {name} present." return ret @@ -975,11 +975,11 @@ def internet_gateway_absent( igw_id = r["id"] if not igw_id: - ret["comment"] = "Internet gateway {} does not exist.".format(name) + ret["comment"] = f"Internet gateway {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Internet gateway {} is set to be removed.".format(name) + ret["comment"] = f"Internet gateway {name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_vpc.delete_internet_gateway"]( @@ -998,7 +998,7 @@ def internet_gateway_absent( return ret ret["changes"]["old"] = {"internet_gateway": igw_id} ret["changes"]["new"] = {"internet_gateway": None} - ret["comment"] = "Internet gateway {} deleted.".format(name) + ret["comment"] = f"Internet gateway {name} deleted." return ret @@ -1160,7 +1160,7 @@ def _route_table_present( if not _id: if __opts__["test"]: - msg = "Route table {} is set to be created.".format(name) + msg = f"Route table {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -1184,9 +1184,9 @@ def _route_table_present( ret["changes"]["old"] = {"route_table": None} ret["changes"]["new"] = {"route_table": r["id"]} - ret["comment"] = "Route table {} created.".format(name) + ret["comment"] = f"Route table {name} created." return ret - ret["comment"] = "Route table {} ({}) present.".format(name, _id) + ret["comment"] = f"Route table {name} ({_id}) present." return ret @@ -1245,7 +1245,7 @@ def _routes_present( ret["result"] = False return ret if r["id"] is None: - msg = "Internet gateway {} does not exist.".format(i) + msg = f"Internet gateway {i} does not exist." ret["comment"] = msg ret["result"] = False return ret @@ -1269,7 +1269,7 @@ def _routes_present( ret["result"] = False return ret if r["id"] is None: - msg = "VPC peering connection {} does not exist.".format(i) + msg = f"VPC peering connection {i} does not exist." ret["comment"] = msg ret["result"] = False return ret @@ -1323,7 +1323,7 @@ def _routes_present( to_delete.append(route) if to_create or to_delete: if __opts__["test"]: - msg = "Route table {} set to have routes modified.".format(route_table_name) + msg = f"Route table {route_table_name} set to have routes modified." ret["comment"] = msg ret["result"] = None return ret @@ -1357,7 +1357,7 @@ def _routes_present( key=key, keyid=keyid, profile=profile, - **r + **r, ) if not res["created"]: msg = "Failed to create route {} in route table {}: {}.".format( @@ -1412,7 +1412,7 @@ def _subnets_present( ret["result"] = False return ret if r["id"] is None: - msg = "Subnet {} does not exist.".format(i) + msg = f"Subnet {i} does not exist." ret["comment"] = msg ret["result"] = False return ret @@ -1536,11 +1536,11 @@ def route_table_absent(name, region=None, key=None, keyid=None, profile=None): rtbl_id = r["id"] if not rtbl_id: - ret["comment"] = "Route table {} does not exist.".format(name) + ret["comment"] = f"Route table {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Route table {} is set to be removed.".format(name) + ret["comment"] = f"Route table {name} is set to be removed." ret["result"] = None return ret @@ -1555,7 +1555,7 @@ def route_table_absent(name, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"route_table": rtbl_id} ret["changes"]["new"] = {"route_table": None} - ret["comment"] = "Route table {} deleted.".format(name) + ret["comment"] = f"Route table {name} deleted." return ret @@ -1650,7 +1650,7 @@ def nat_gateway_present( inst = r[0] _id = inst.get("NatGatewayId") - ret["comment"] = "Nat gateway {} present.".format(_id) + ret["comment"] = f"Nat gateway {_id} present." return ret @@ -1740,9 +1740,7 @@ def nat_gateway_absent( r["error"]["message"] ) return ret - ret["comment"] = ", ".join( - (ret["comment"], "Nat gateway {} deleted.".format(rtbl_id)) - ) + ret["comment"] = ", ".join((ret["comment"], f"Nat gateway {rtbl_id} deleted.")) ret["changes"]["old"] = {"nat_gateway": rtbl_id} ret["changes"]["new"] = {"nat_gateway": None} return ret diff --git a/salt/states/bower.py b/salt/states/bower.py index f6185825b04..e7966345273 100644 --- a/salt/states/bower.py +++ b/salt/states/bower.py @@ -87,7 +87,7 @@ def installed(name, dir, pkgs=None, user=None, env=None): installed_pkgs = __salt__["bower.list"](dir=dir, runas=user, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" return ret else: installed_pkgs = {p: info for p, info in installed_pkgs.items()} @@ -105,7 +105,7 @@ def installed(name, dir, pkgs=None, user=None, env=None): if pkg_name in installed_pkgs: installed_pkg = installed_pkgs[pkg_name] installed_pkg_ver = installed_pkg.get("pkgMeta").get("version") - installed_name_ver = "{}#{}".format(pkg_name, installed_pkg_ver) + installed_name_ver = f"{pkg_name}#{installed_pkg_ver}" # If given an explicit version check the installed version matches. if pkg_ver: @@ -199,30 +199,30 @@ def removed(name, dir, user=None): installed_pkgs = __salt__["bower.list"](dir=dir, runas=user) except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error removing '{}': {}".format(name, err) + ret["comment"] = f"Error removing '{name}': {err}" return ret if name not in installed_pkgs: ret["result"] = True - ret["comment"] = "Package '{}' is not installed".format(name) + ret["comment"] = f"Package '{name}' is not installed" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package '{}' is set to be removed".format(name) + ret["comment"] = f"Package '{name}' is set to be removed" return ret try: if __salt__["bower.uninstall"](pkg=name, dir=dir, runas=user): ret["result"] = True ret["changes"] = {name: "Removed"} - ret["comment"] = "Package '{}' was successfully removed".format(name) + ret["comment"] = f"Package '{name}' was successfully removed" else: ret["result"] = False - ret["comment"] = "Error removing '{}'".format(name) + ret["comment"] = f"Error removing '{name}'" except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error removing '{}': {}".format(name, err) + ret["comment"] = f"Error removing '{name}': {err}" return ret @@ -241,14 +241,14 @@ def bootstrap(name, user=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Directory '{}' is set to be bootstrapped".format(name) + ret["comment"] = f"Directory '{name}' is set to be bootstrapped" return ret try: call = __salt__["bower.install"](pkg=None, dir=name, runas=user) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error bootstrapping '{}': {}".format(name, err) + ret["comment"] = f"Error bootstrapping '{name}': {err}" return ret if not call: @@ -279,21 +279,21 @@ def pruned(name, user=None, env=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Directory '{}' is set to be pruned".format(name) + ret["comment"] = f"Directory '{name}' is set to be pruned" return ret try: call = __salt__["bower.prune"](dir=name, runas=user, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error pruning '{}': {}".format(name, err) + ret["comment"] = f"Error pruning '{name}': {err}" return ret ret["result"] = True if call: - ret["comment"] = "Directory '{}' was successfully pruned".format(name) + ret["comment"] = f"Directory '{name}' was successfully pruned" ret["changes"] = {"old": [], "new": call} else: - ret["comment"] = "No packages were pruned from directory '{}'".format(name) + ret["comment"] = f"No packages were pruned from directory '{name}'" return ret diff --git a/salt/states/btrfs.py b/salt/states/btrfs.py index 68ab8f869c9..2c17192754e 100644 --- a/salt/states/btrfs.py +++ b/salt/states/btrfs.py @@ -97,7 +97,7 @@ def __mount_device(action): if device: dest = _mount(device, use_default) if not dest: - msg = "Device {} cannot be mounted".format(device) + msg = f"Device {device} cannot be mounted" ret["comment"].append(msg) kwargs["__dest"] = dest ret = action(*args, **kwargs) @@ -157,7 +157,7 @@ def subvolume_created( exists = __salt__["btrfs.subvolume_exists"](path) if exists: - ret["comment"].append("Subvolume {} already present".format(name)) + ret["comment"].append(f"Subvolume {name} already present") # Resolve first the test case. The check is not complete, but at # least we will report if a subvolume needs to be created. Can @@ -166,7 +166,7 @@ def subvolume_created( if __opts__["test"]: ret["result"] = None if not exists: - ret["changes"][name] = "Subvolume {} will be created".format(name) + ret["changes"][name] = f"Subvolume {name} will be created" return ret if not exists: @@ -174,16 +174,16 @@ def subvolume_created( _path = os.path.dirname(path) res = __states__["file.directory"](_path, makedirs=True) if not res["result"]: - ret["comment"].append("Error creating {} directory".format(_path)) + ret["comment"].append(f"Error creating {_path} directory") return ret try: __salt__["btrfs.subvolume_create"](name, dest=__dest, qgroupids=qgroupids) except CommandExecutionError: - ret["comment"].append("Error creating subvolume {}".format(name)) + ret["comment"].append(f"Error creating subvolume {name}") return ret - ret["changes"][name] = "Created subvolume {}".format(name) + ret["changes"][name] = f"Created subvolume {name}" # If the volume was already present, we can opt-out the check for # default subvolume. @@ -227,12 +227,12 @@ def subvolume_deleted(name, device, commit=False, __dest=None): exists = __salt__["btrfs.subvolume_exists"](path) if not exists: - ret["comment"].append("Subvolume {} already missing".format(name)) + ret["comment"].append(f"Subvolume {name} already missing") if __opts__["test"]: ret["result"] = None if exists: - ret["changes"][name] = "Subvolume {} will be removed".format(name) + ret["changes"][name] = f"Subvolume {name} will be removed" return ret # If commit is set, we wait until all is over @@ -242,10 +242,10 @@ def subvolume_deleted(name, device, commit=False, __dest=None): try: __salt__["btrfs.subvolume_delete"](path, commit=commit) except CommandExecutionError: - ret["comment"].append("Error removing subvolume {}".format(name)) + ret["comment"].append(f"Error removing subvolume {name}") return ret - ret["changes"][name] = "Removed subvolume {}".format(name) + ret["changes"][name] = f"Removed subvolume {name}" ret["result"] = True return ret @@ -320,7 +320,7 @@ def properties(name, device, use_default=False, __dest=None, **properties): path = name if not os.path.exists(path): - ret["comment"].append("Object {} not found".format(name)) + ret["comment"].append(f"Object {name} not found") return ret # Convert the booleans to lowercase @@ -332,14 +332,14 @@ def properties(name, device, use_default=False, __dest=None, **properties): try: current_properties = __salt__["btrfs.properties"](path) except CommandExecutionError as e: - ret["comment"].append("Error reading properties from {}".format(name)) - ret["comment"].append("Current error {}".format(e)) + ret["comment"].append(f"Error reading properties from {name}") + ret["comment"].append(f"Current error {e}") return ret try: properties_to_set = _diff_properties(properties, current_properties) except KeyError: - ret["comment"].append("Some property not found in {}".format(name)) + ret["comment"].append(f"Some property not found in {name}") return ret if __opts__["test"]: @@ -347,14 +347,12 @@ def properties(name, device, use_default=False, __dest=None, **properties): if properties_to_set: ret["changes"] = properties_to_set else: - msg = "No properties will be changed in {}".format(name) + msg = f"No properties will be changed in {name}" ret["comment"].append(msg) return ret if properties_to_set: - _properties = ",".join( - "{}={}".format(k, v) for k, v in properties_to_set.items() - ) + _properties = ",".join(f"{k}={v}" for k, v in properties_to_set.items()) __salt__["btrfs.properties"](path, set=_properties) current_properties = __salt__["btrfs.properties"](path) @@ -366,10 +364,10 @@ def properties(name, device, use_default=False, __dest=None, **properties): ret["comment"].append(msg) return ret - ret["comment"].append("Properties changed in {}".format(name)) + ret["comment"].append(f"Properties changed in {name}") ret["changes"] = properties_to_set else: - ret["comment"].append("Properties not changed in {}".format(name)) + ret["comment"].append(f"Properties not changed in {name}") ret["result"] = True return ret diff --git a/salt/states/cabal.py b/salt/states/cabal.py index 4b38de6eda7..5190d850a9a 100644 --- a/salt/states/cabal.py +++ b/salt/states/cabal.py @@ -83,7 +83,7 @@ def installed(name, pkgs=None, user=None, install_global=False, env=None): call = __salt__["cabal.update"](user=user, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Could not run cabal update {}".format(err) + ret["comment"] = f"Could not run cabal update {err}" return ret if pkgs is not None: @@ -95,7 +95,7 @@ def installed(name, pkgs=None, user=None, install_global=False, env=None): installed_pkgs = __salt__["cabal.list"](user=user, installed=True, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" return ret pkgs_satisfied = [] @@ -180,24 +180,24 @@ def removed(name, user=None, env=None): installed_pkgs = __salt__["cabal.list"](user=user, installed=True, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" if name not in installed_pkgs: ret["result"] = True - ret["comment"] = "Package '{}' is not installed".format(name) + ret["comment"] = f"Package '{name}' is not installed" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package '{}' is set to be removed".format(name) + ret["comment"] = f"Package '{name}' is set to be removed" return ret if __salt__["cabal.uninstall"](pkg=name, user=user, env=env): ret["result"] = True ret["changes"][name] = "Removed" - ret["comment"] = "Package '{}' was successfully removed".format(name) + ret["comment"] = f"Package '{name}' was successfully removed" else: ret["result"] = False - ret["comment"] = "Error removing package '{}'".format(name) + ret["comment"] = f"Error removing package '{name}'" return ret diff --git a/salt/states/chronos_job.py b/salt/states/chronos_job.py index 7bea17b8335..dc016eb3718 100644 --- a/salt/states/chronos_job.py +++ b/salt/states/chronos_job.py @@ -97,7 +97,7 @@ def config(name, config): # if test report there will be an update if __opts__["test"]: ret["result"] = None - ret["comment"] = "Chronos job {} is set to be updated".format(name) + ret["comment"] = f"Chronos job {name} is set to be updated" return ret update_result = __salt__["chronos.update_job"](name, update_config) @@ -110,10 +110,10 @@ def config(name, config): return ret else: ret["result"] = True - ret["comment"] = "Updated job config for {}".format(name) + ret["comment"] = f"Updated job config for {name}" return ret ret["result"] = True - ret["comment"] = "Chronos job {} configured correctly".format(name) + ret["comment"] = f"Chronos job {name} configured correctly" return ret @@ -127,18 +127,18 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["chronos.has_job"](name): ret["result"] = True - ret["comment"] = "Job {} already absent".format(name) + ret["comment"] = f"Job {name} already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Job {} is set to be removed".format(name) + ret["comment"] = f"Job {name} is set to be removed" return ret if __salt__["chronos.rm_job"](name): ret["changes"] = {"job": name} ret["result"] = True - ret["comment"] = "Removed job {}".format(name) + ret["comment"] = f"Removed job {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to remove job {}".format(name) + ret["comment"] = f"Failed to remove job {name}" return ret diff --git a/salt/states/cloud.py b/salt/states/cloud.py index 5cc287db906..8b7afc71c0d 100644 --- a/salt/states/cloud.py +++ b/salt/states/cloud.py @@ -102,11 +102,11 @@ def present(name, cloud_provider, onlyif=None, unless=None, opts=None, **kwargs) # need to ensure ALL providers don't have the instance if __salt__["cloud.has_instance"](name=name, provider=None): ret["result"] = True - ret["comment"] = "Already present instance {}".format(name) + ret["comment"] = f"Already present instance {name}" return ret if __opts__["test"]: - ret["comment"] = "Instance {} needs to be created".format(name) + ret["comment"] = f"Instance {name} needs to be created" return ret info = __salt__["cloud.create"](cloud_provider, name, opts=opts, **kwargs) @@ -172,18 +172,18 @@ def absent(name, onlyif=None, unless=None): if not __salt__["cloud.has_instance"](name=name, provider=None): ret["result"] = True - ret["comment"] = "Already absent instance {}".format(name) + ret["comment"] = f"Already absent instance {name}" return ret if __opts__["test"]: - ret["comment"] = "Instance {} needs to be destroyed".format(name) + ret["comment"] = f"Instance {name} needs to be destroyed" return ret info = __salt__["cloud.destroy"](name) if info and "Error" not in info: ret["changes"] = info ret["result"] = True - ret["comment"] = "Destroyed instance {}".format(name) + ret["comment"] = f"Destroyed instance {name}" elif "Error" in info: ret["result"] = False ret["comment"] = "Failed to destroy instance {}: {}".format( @@ -192,7 +192,7 @@ def absent(name, onlyif=None, unless=None): ) else: ret["result"] = False - ret["comment"] = "Failed to destroy instance {}".format(name) + ret["comment"] = f"Failed to destroy instance {name}" return ret @@ -243,11 +243,11 @@ def profile(name, profile, onlyif=None, unless=None, opts=None, **kwargs): instance = _get_instance([name]) if instance and not any("Not Actioned" in key for key in instance): ret["result"] = True - ret["comment"] = "Already present instance {}".format(name) + ret["comment"] = f"Already present instance {name}" return ret if __opts__["test"]: - ret["comment"] = "Instance {} needs to be created".format(name) + ret["comment"] = f"Instance {name} needs to be created" return ret info = __salt__["cloud.profile"](profile, name, vm_overrides=kwargs, opts=opts) @@ -280,7 +280,7 @@ def profile(name, profile, onlyif=None, unless=None, opts=None, **kwargs): ret["comment"] = "Failed to create instance {} using profile {}: {}".format( name, profile, - "{}\n{}\n".format(main_error, name_error).strip(), + f"{main_error}\n{name_error}\n".strip(), ) else: ret["result"] = False @@ -302,22 +302,22 @@ def volume_present(name, provider=None, **kwargs): volumes = __salt__["cloud.volume_list"](provider=provider) if name in volumes: - ret["comment"] = "Volume exists: {}".format(name) + ret["comment"] = f"Volume exists: {name}" ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be created.".format(name) + ret["comment"] = f"Volume {name} will be created." ret["result"] = None return ret response = __salt__["cloud.volume_create"](names=name, provider=provider, **kwargs) if response: ret["result"] = True - ret["comment"] = "Volume {} was created".format(name) + ret["comment"] = f"Volume {name} was created" ret["changes"] = {"old": None, "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to create.".format(name) + ret["comment"] = f"Volume {name} failed to create." return ret @@ -336,18 +336,18 @@ def volume_absent(name, provider=None, **kwargs): ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be deleted.".format(name) + ret["comment"] = f"Volume {name} will be deleted." ret["result"] = None return ret response = __salt__["cloud.volume_delete"](names=name, provider=provider, **kwargs) if response: ret["result"] = True - ret["comment"] = "Volume {} was deleted".format(name) + ret["comment"] = f"Volume {name} was deleted" ret["changes"] = {"old": volumes[name], "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to delete.".format(name) + ret["comment"] = f"Volume {name} failed to delete." return ret @@ -374,15 +374,15 @@ def volume_attached(name, server_name, provider=None, **kwargs): ret["result"] = True return ret elif name not in volumes: - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" ret["result"] = False return ret elif not instance: - ret["comment"] = "Server {} does not exist".format(server_name) + ret["comment"] = f"Server {server_name} does not exist" ret["result"] = False return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be will be attached.".format(name) + ret["comment"] = f"Volume {name} will be will be attached." ret["result"] = None return ret @@ -391,11 +391,11 @@ def volume_attached(name, server_name, provider=None, **kwargs): ) if response: ret["result"] = True - ret["comment"] = "Volume {} was created".format(name) + ret["comment"] = f"Volume {name} was created" ret["changes"] = {"old": volumes[name], "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to attach.".format(name) + ret["comment"] = f"Volume {name} failed to attach." return ret @@ -428,15 +428,15 @@ def volume_detached(name, server_name=None, provider=None, **kwargs): ret["result"] = True return ret elif name not in volumes: - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" ret["result"] = True return ret elif not instance and server_name is not None: - ret["comment"] = "Server {} does not exist".format(server_name) + ret["comment"] = f"Server {server_name} does not exist" ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be will be detached.".format(name) + ret["comment"] = f"Volume {name} will be will be detached." ret["result"] = None return ret @@ -445,9 +445,9 @@ def volume_detached(name, server_name=None, provider=None, **kwargs): ) if response: ret["result"] = True - ret["comment"] = "Volume {} was created".format(name) + ret["comment"] = f"Volume {name} was created" ret["changes"] = {"old": volumes[name], "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to detach.".format(name) + ret["comment"] = f"Volume {name} failed to detach." return ret diff --git a/salt/states/cmd.py b/salt/states/cmd.py index 8518659061f..df0aec96ef8 100644 --- a/salt/states/cmd.py +++ b/salt/states/cmd.py @@ -316,7 +316,7 @@ def _is_true(val): return True elif str(val).lower() in ("false", "no", "0"): return False - raise ValueError("Failed parsing boolean value: {}".format(val)) + raise ValueError(f"Failed parsing boolean value: {val}") def wait( @@ -333,7 +333,7 @@ def wait( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Run the given command only if the watch statement calls it. @@ -484,7 +484,7 @@ def wait_script( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script from a remote source and execute it only if a watch @@ -629,7 +629,7 @@ def run( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Run a command if certain circumstances are met. Use ``cmd.wait`` if you @@ -847,12 +847,12 @@ def run( if __opts__["test"] and not test_name: ret["result"] = None - ret["comment"] = 'Command "{}" would have been executed'.format(name) + ret["comment"] = f'Command "{name}" would have been executed' ret["changes"] = {"cmd": name} return _reinterpreted_state(ret) if stateful else ret if cwd and not os.path.isdir(cwd): - ret["comment"] = 'Desired working directory "{}" is not available'.format(cwd) + ret["comment"] = f'Desired working directory "{cwd}" is not available' return ret # Wow, we passed the test, run this sucker! @@ -867,7 +867,7 @@ def run( ret["changes"] = cmd_all ret["result"] = not bool(cmd_all["retcode"]) - ret["comment"] = 'Command "{}" run'.format(name) + ret["comment"] = f'Command "{name}" run' # Ignore timeout errors if asked (for nohups) and treat cmd as a success if ignore_timeout: @@ -904,7 +904,7 @@ def script( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script and execute it with specified arguments. @@ -1154,11 +1154,11 @@ def script( if __opts__["test"] and not test_name: ret["result"] = None - ret["comment"] = "Command '{}' would have been executed".format(name) + ret["comment"] = f"Command '{name}' would have been executed" return _reinterpreted_state(ret) if stateful else ret if cwd and not os.path.isdir(cwd): - ret["comment"] = 'Desired working directory "{}" is not available'.format(cwd) + ret["comment"] = f'Desired working directory "{cwd}" is not available' return ret # Wow, we passed the test, run this sucker! @@ -1178,7 +1178,7 @@ def script( source, __env__ ) else: - ret["comment"] = "Command '{}' run".format(name) + ret["comment"] = f"Command '{name}' run" if stateful: ret = _reinterpreted_state(ret) if __opts__["test"] and cmd_all["retcode"] == 0 and ret["changes"]: @@ -1194,7 +1194,7 @@ def call( output_loglevel="debug", hide_output=False, use_vt=False, - **kwargs + **kwargs, ): """ Invoke a pre-defined Python function with arguments specified in the state @@ -1257,7 +1257,7 @@ def wait_call( use_vt=False, output_loglevel="debug", hide_output=False, - **kwargs + **kwargs, ): # Ignoring our arguments is intentional. return {"name": name, "changes": {}, "result": True, "comment": ""} diff --git a/salt/states/composer.py b/salt/states/composer.py index 79629271c17..9578507066b 100644 --- a/salt/states/composer.py +++ b/salt/states/composer.py @@ -137,10 +137,10 @@ def installed( else: install_status = "not " - ret["comment"] = 'The state of "{}" will be changed.'.format(name) + ret["comment"] = f'The state of "{name}" will be changed.' ret["changes"] = { - "old": "composer install has {}been run in {}".format(install_status, name), - "new": "composer install will be run in {}".format(name), + "old": f"composer install has {install_status}been run in {name}", + "new": f"composer install will be run in {name}", } ret["result"] = None return ret @@ -163,7 +163,7 @@ def installed( ) except SaltException as err: ret["result"] = False - ret["comment"] = "Error executing composer in '{}': {}".format(name, err) + ret["comment"] = f"Error executing composer in '{name}': {err}" return ret # If composer retcode != 0 then an exception was thrown and we dealt with it. @@ -250,17 +250,17 @@ def update( # Check if composer.lock exists, if so we already ran `composer install` is_installed = __salt__["composer.did_composer_install"](name) if is_installed: - old_status = "composer install has not yet been run in {}".format(name) + old_status = f"composer install has not yet been run in {name}" else: - old_status = "composer install has been run in {}".format(name) + old_status = f"composer install has been run in {name}" # The state of the system does need to be changed. Check if we're running # in ``test=true`` mode. if __opts__["test"] is True: - ret["comment"] = 'The state of "{}" will be changed.'.format(name) + ret["comment"] = f'The state of "{name}" will be changed.' ret["changes"] = { "old": old_status, - "new": "composer install/update will be run in {}".format(name), + "new": f"composer install/update will be run in {name}", } ret["result"] = None return ret @@ -283,7 +283,7 @@ def update( ) except SaltException as err: ret["result"] = False - ret["comment"] = "Error executing composer in '{}': {}".format(name, err) + ret["comment"] = f"Error executing composer in '{name}': {err}" return ret # If composer retcode != 0 then an exception was thrown and we dealt with it. diff --git a/salt/states/consul.py b/salt/states/consul.py index 181ebc9ea9d..f76bac8f7c9 100644 --- a/salt/states/consul.py +++ b/salt/states/consul.py @@ -104,7 +104,7 @@ def acl_present( "name": name, "changes": {}, "result": True, - "comment": 'ACL "{}" exists and is up to date'.format(name), + "comment": f'ACL "{name}" exists and is up to date', } exists = _acl_exists(name, id, token, consul_url) @@ -181,7 +181,7 @@ def acl_absent(name, id=None, token=None, consul_url="http://localhost:8500"): "name": id, "changes": {}, "result": True, - "comment": 'ACL "{}" does not exist'.format(id), + "comment": f'ACL "{id}" does not exist', } exists = _acl_exists(name, id, token, consul_url) diff --git a/salt/states/cron.py b/salt/states/cron.py index c8576727190..c06980fccfe 100644 --- a/salt/states/cron.py +++ b/salt/states/cron.py @@ -346,12 +346,12 @@ def present( ) ret["result"] = None if status == "absent": - ret["comment"] = "Cron {} is set to be added".format(name) + ret["comment"] = f"Cron {name} is set to be added" elif status == "present": ret["result"] = True - ret["comment"] = "Cron {} already present".format(name) + ret["comment"] = f"Cron {name} already present" elif status == "update": - ret["comment"] = "Cron {} is set to be updated".format(name) + ret["comment"] = f"Cron {name} is set to be updated" return ret if special is None: @@ -377,16 +377,16 @@ def present( identifier=identifier, ) if data == "present": - ret["comment"] = "Cron {} already present".format(name) + ret["comment"] = f"Cron {name} already present" return ret if data == "new": - ret["comment"] = "Cron {} added to {}'s crontab".format(name, user) + ret["comment"] = f"Cron {name} added to {user}'s crontab" ret["changes"] = {user: name} return ret if data == "updated": - ret["comment"] = "Cron {} updated".format(name) + ret["comment"] = f"Cron {name} updated" ret["changes"] = {user: name} return ret ret["comment"] = "Cron {} for user {} failed to commit with error \n{}".format( @@ -432,9 +432,9 @@ def absent(name, user="root", identifier=False, special=None, **kwargs): ret["result"] = None if status == "absent": ret["result"] = True - ret["comment"] = "Cron {} is absent".format(name) + ret["comment"] = f"Cron {name} is absent" elif status == "present" or status == "update": - ret["comment"] = "Cron {} is set to be removed".format(name) + ret["comment"] = f"Cron {name} is set to be removed" return ret if special is None: @@ -445,10 +445,10 @@ def absent(name, user="root", identifier=False, special=None, **kwargs): ) if data == "absent": - ret["comment"] = "Cron {} already absent".format(name) + ret["comment"] = f"Cron {name} already absent" return ret if data == "removed": - ret["comment"] = "Cron {} removed from {}'s crontab".format(name, user) + ret["comment"] = f"Cron {name} removed from {user}'s crontab" ret["changes"] = {user: name} return ret ret["comment"] = "Cron {} for user {} failed to commit with error {}".format( @@ -468,7 +468,7 @@ def file( replace=True, defaults=None, backup="", - **kwargs + **kwargs, ): """ Provides file.managed-like functionality (templating, etc.) for a pre-made @@ -559,7 +559,7 @@ def file( except Exception: # pylint: disable=broad-except ret = { "changes": {}, - "comment": "Could not identify group for user {}".format(user), + "comment": f"Could not identify group for user {user}", "name": name, "result": False, } @@ -569,7 +569,7 @@ def file( with salt.utils.files.fopen(cron_path, "w+") as fp_: raw_cron = __salt__["cron.raw_cron"](user) if not raw_cron.endswith("\n"): - raw_cron = "{}\n".format(raw_cron) + raw_cron = f"{raw_cron}\n" fp_.write(salt.utils.stringutils.to_str(raw_cron)) ret = {"changes": {}, "comment": "", "name": name, "result": True} @@ -579,7 +579,7 @@ def file( source = name if not replace and os.stat(cron_path).st_size > 0: - ret["comment"] = "User {} already has a crontab. No changes made".format(user) + ret["comment"] = f"User {user} already has a crontab. No changes made" os.unlink(cron_path) return ret @@ -597,7 +597,7 @@ def file( context=context, defaults=defaults, saltenv=__env__, - **kwargs + **kwargs, ) ret["result"], ret["comment"] = fcm os.unlink(cron_path) @@ -622,12 +622,12 @@ def file( context=context, defaults=defaults, skip_verify=False, # skip_verify - **kwargs + **kwargs, ) except Exception as exc: # pylint: disable=broad-except ret["result"] = False ret["changes"] = {} - ret["comment"] = "Unable to manage file: {}".format(exc) + ret["comment"] = f"Unable to manage file: {exc}" return ret if comment: @@ -653,7 +653,7 @@ def file( except Exception as exc: # pylint: disable=broad-except ret["result"] = False ret["changes"] = {} - ret["comment"] = "Unable to manage file: {}".format(exc) + ret["comment"] = f"Unable to manage file: {exc}" return ret cron_ret = None @@ -661,7 +661,7 @@ def file( cron_ret = __salt__["cron.write_cron_file_verbose"](user, cron_path) # Check cmd return code and show success or failure if cron_ret["retcode"] == 0: - ret["comment"] = "Crontab for user {} was updated".format(user) + ret["comment"] = f"Crontab for user {user} was updated" ret["result"] = True ret["changes"] = ret["changes"] else: @@ -671,7 +671,7 @@ def file( ret["result"] = False ret["changes"] = {} elif ret["result"]: - ret["comment"] = "Crontab for user {} is in the correct state".format(user) + ret["comment"] = f"Crontab for user {user} is in the correct state" ret["changes"] = {} os.unlink(cron_path) @@ -698,26 +698,26 @@ def env_present(name, value=None, user="root"): status = _check_cron_env(user, name, value=value) ret["result"] = None if status == "absent": - ret["comment"] = "Cron env {} is set to be added".format(name) + ret["comment"] = f"Cron env {name} is set to be added" elif status == "present": ret["result"] = True - ret["comment"] = "Cron env {} already present".format(name) + ret["comment"] = f"Cron env {name} already present" elif status == "update": - ret["comment"] = "Cron env {} is set to be updated".format(name) + ret["comment"] = f"Cron env {name} is set to be updated" return ret data = __salt__["cron.set_env"](user, name, value=value) if data == "present": - ret["comment"] = "Cron env {} already present".format(name) + ret["comment"] = f"Cron env {name} already present" return ret if data == "new": - ret["comment"] = "Cron env {} added to {}'s crontab".format(name, user) + ret["comment"] = f"Cron env {name} added to {user}'s crontab" ret["changes"] = {user: name} return ret if data == "updated": - ret["comment"] = "Cron env {} updated".format(name) + ret["comment"] = f"Cron env {name} updated" ret["changes"] = {user: name} return ret ret["comment"] = "Cron env {} for user {} failed to commit with error \n{}".format( @@ -748,17 +748,17 @@ def env_absent(name, user="root"): ret["result"] = None if status == "absent": ret["result"] = True - ret["comment"] = "Cron env {} is absent".format(name) + ret["comment"] = f"Cron env {name} is absent" elif status == "present" or status == "update": - ret["comment"] = "Cron env {} is set to be removed".format(name) + ret["comment"] = f"Cron env {name} is set to be removed" return ret data = __salt__["cron.rm_env"](user, name) if data == "absent": - ret["comment"] = "Cron env {} already absent".format(name) + ret["comment"] = f"Cron env {name} already absent" return ret if data == "removed": - ret["comment"] = "Cron env {} removed from {}'s crontab".format(name, user) + ret["comment"] = f"Cron env {name} removed from {user}'s crontab" ret["changes"] = {user: name} return ret ret["comment"] = "Cron env {} for user {} failed to commit with error {}".format( diff --git a/salt/states/cryptdev.py b/salt/states/cryptdev.py index 54a167f7018..d0f7f069af3 100644 --- a/salt/states/cryptdev.py +++ b/salt/states/cryptdev.py @@ -128,7 +128,7 @@ def mapped( ) if crypttab_result: if crypttab_result == "new": - ret["changes"]["crypttab"] = "Entry added in {}".format(config) + ret["changes"]["crypttab"] = f"Entry added in {config}" if crypttab_result == "change": ret["changes"]["crypttab"] = "Existing entry in {} changed".format( @@ -136,7 +136,7 @@ def mapped( ) else: - ret["changes"]["crypttab"] = "Unable to set entry in {}".format(config) + ret["changes"]["crypttab"] = f"Unable to set entry in {config}" ret["result"] = False return ret @@ -183,10 +183,10 @@ def unmapped(name, config="/etc/crypttab", persist=True, immediate=False): crypttab_result = __salt__["cryptdev.rm_crypttab"](name, config=config) if crypttab_result: if crypttab_result == "change": - ret["changes"]["crypttab"] = "Entry removed from {}".format(config) + ret["changes"]["crypttab"] = f"Entry removed from {config}" else: - ret["changes"]["crypttab"] = "Unable to remove entry in {}".format(config) + ret["changes"]["crypttab"] = f"Unable to remove entry in {config}" ret["result"] = False return ret diff --git a/salt/states/csf.py b/salt/states/csf.py index 4a66377031c..57118c75d02 100644 --- a/salt/states/csf.py +++ b/salt/states/csf.py @@ -107,8 +107,8 @@ def rule_present( return ret else: if ttl: - method = "temp{}".format(method) - func = __salt__["csf.{}".format(method)] + method = f"temp{method}" + func = __salt__[f"csf.{method}"] rule = func( ip, port=port, @@ -387,7 +387,7 @@ def option_present(name, value, reload=False): if current_option: l = __salt__["csf.split_option"](current_option) option_value = l[1] - if '"{}"'.format(value) == option_value: + if f'"{value}"' == option_value: return ret else: result = __salt__["csf.set_option"](option, value) @@ -395,7 +395,7 @@ def option_present(name, value, reload=False): ret["changes"]["Option"] = "Changed" else: result = __salt__["file.append"]( - "/etc/csf/csf.conf", args='{} = "{}"'.format(option, value) + "/etc/csf/csf.conf", args=f'{option} = "{value}"' ) ret["comment"] = "Option not present. Appended to csf.conf" ret["changes"]["Option"] = "Changed." diff --git a/salt/states/cyg.py b/salt/states/cyg.py index 957b194c724..e4ea5925979 100644 --- a/salt/states/cyg.py +++ b/salt/states/cyg.py @@ -72,7 +72,7 @@ def installed(name, cyg_arch="x86_64", mirrors=None): return ret if __opts__["test"]: - ret["comment"] = "The package {} would have been installed".format(name) + ret["comment"] = f"The package {name} would have been installed" return ret if __salt__["cyg.install"](name, cyg_arch=cyg_arch, mirrors=mirrors): @@ -131,7 +131,7 @@ def removed(name, cyg_arch="x86_64", mirrors=None): return ret if __opts__["test"]: - ret["comment"] = "The package {} would have been removed".format(name) + ret["comment"] = f"The package {name} would have been removed" return ret if __salt__["cyg.uninstall"](name, cyg_arch): ret["result"] = True diff --git a/salt/states/ddns.py b/salt/states/ddns.py index 8fd2e9c0508..0260fc10916 100644 --- a/salt/states/ddns.py +++ b/salt/states/ddns.py @@ -64,7 +64,7 @@ def present(name, zone, ttl, data, rdtype="A", **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = '{} record "{}" will be updated'.format(rdtype, name) + ret["comment"] = f'{rdtype} record "{name}" will be updated' return ret status = __salt__["ddns.update"](zone, name, ttl, rdtype, data, **kwargs) @@ -76,7 +76,7 @@ def present(name, zone, ttl, data, rdtype="A", **kwargs): ) elif status: ret["result"] = True - ret["comment"] = 'Updated {} record for "{}"'.format(rdtype, name) + ret["comment"] = f'Updated {rdtype} record for "{name}"' ret["changes"] = { "name": name, "zone": zone, @@ -122,7 +122,7 @@ def absent(name, zone, data=None, rdtype=None, **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = '{} record "{}" will be deleted'.format(rdtype, name) + ret["comment"] = f'{rdtype} record "{name}" will be deleted' return ret status = __salt__["ddns.delete"](zone, name, rdtype, data, **kwargs) diff --git a/salt/states/debconfmod.py b/salt/states/debconfmod.py index 0006e9696fa..4d399408341 100644 --- a/salt/states/debconfmod.py +++ b/salt/states/debconfmod.py @@ -198,7 +198,7 @@ def set(name, data, **kwargs): if current is not None and [key, args["type"], str(args["value"])] in current: if ret["comment"] == "": ret["comment"] = "Unchanged answers: " - ret["comment"] += "{} ".format(key) + ret["comment"] += f"{key} " else: if __opts__["test"]: ret["result"] = None diff --git a/salt/states/dellchassis.py b/salt/states/dellchassis.py index 6f95f4f20df..23487b6dfad 100644 --- a/salt/states/dellchassis.py +++ b/salt/states/dellchassis.py @@ -700,9 +700,9 @@ def switch( if any([password_ret, snmp_ret, net_ret, dhcp_ret]) is False: ret["result"] = False - ret["comment"] = "There was an error setting the switch {}.".format(name) + ret["comment"] = f"There was an error setting the switch {name}." - ret["comment"] = "Dell chassis switch {} was updated.".format(name) + ret["comment"] = f"Dell chassis switch {name} was updated." return ret @@ -755,7 +755,7 @@ def firmware_update(hosts=None, directory=""): ret["changes"].update( { "host": { - "comment": "Firmware update submitted for {}".format(host), + "comment": f"Firmware update submitted for {host}", "success": True, } } @@ -765,7 +765,7 @@ def firmware_update(hosts=None, directory=""): ret["changes"].update( { "host": { - "comment": "FAILED to update firmware for {}".format(host), + "comment": f"FAILED to update firmware for {host}", "success": False, "reason": str(err), } diff --git a/salt/states/disk.py b/salt/states/disk.py index 255cc225383..47d7177b59b 100644 --- a/salt/states/disk.py +++ b/salt/states/disk.py @@ -62,7 +62,7 @@ def _validate_int(name, value, limits=(), strip="%"): value = value.strip(" " + strip) value = int(value) except (TypeError, ValueError): - comment += "{} must be an integer ".format(name) + comment += f"{name} must be an integer " # Must be in range else: if len(limits) == 2: @@ -219,7 +219,7 @@ def status(name, maximum=None, minimum=None, absolute=False, free=False): # Validate name if name not in data: - ret["comment"] += "Disk mount {} not present. ".format(name) + ret["comment"] += f"Disk mount {name} not present. " return _status_path(name, ret, minimum, maximum, absolute, free) else: return _status_mount(name, ret, minimum, maximum, absolute, free, data) diff --git a/salt/states/docker_container.py b/salt/states/docker_container.py index 040e8553fd3..4cecd87230c 100644 --- a/salt/states/docker_container.py +++ b/salt/states/docker_container.py @@ -163,7 +163,7 @@ def _parse_networks(networks): ] except CommandExecutionError as exc: raise CommandExecutionError( - "Failed to get list of existing networks: {}.".format(exc) + f"Failed to get list of existing networks: {exc}." ) else: missing_networks = [x for x in sorted(networks) if x not in all_networks] @@ -192,7 +192,7 @@ def _resolve_image(ret, image, client_timeout): client_timeout=client_timeout, ) except Exception as exc: # pylint: disable=broad-except - raise CommandExecutionError("Failed to pull {}: {}".format(image, exc)) + raise CommandExecutionError(f"Failed to pull {image}: {exc}") else: ret["changes"]["image"] = pull_result # Try resolving again now that we've pulled @@ -218,7 +218,7 @@ def running( shutdown_timeout=None, client_timeout=salt.utils.dockermod.CLIENT_TIMEOUT, networks=None, - **kwargs + **kwargs, ): """ Ensure that a container with a specific configuration is present and @@ -1740,7 +1740,7 @@ def running( ignore_collisions=ignore_collisions, validate_ip_addrs=validate_ip_addrs, client_timeout=client_timeout, - **kwargs + **kwargs, ) temp_container_name = temp_container["Name"] except KeyError as exc: @@ -1779,9 +1779,9 @@ def running( result = __salt__["docker.rename"](new, orig) except CommandExecutionError as exc: result = False - comments.append("Failed to rename temp container: {}".format(exc)) + comments.append(f"Failed to rename temp container: {exc}") if result: - comments.append("Replaced container '{}'".format(orig)) + comments.append(f"Replaced container '{orig}'") else: comments.append("Failed to replace container '{0}'") return result @@ -1887,22 +1887,18 @@ def running( if send_signal: if __opts__["test"]: comments.append( - "Signal {} would be sent to container".format(watch_action) + f"Signal {watch_action} would be sent to container" ) else: try: __salt__["docker.signal"](name, signal=watch_action) except CommandExecutionError as exc: ret["result"] = False - comments.append( - "Failed to signal container: {}".format(exc) - ) + comments.append(f"Failed to signal container: {exc}") return _format_comments(ret, comments) else: ret["changes"]["signal"] = watch_action - comments.append( - "Sent signal {} to container".format(watch_action) - ) + comments.append(f"Sent signal {watch_action} to container") elif container_changes: if not comments: log.warning( @@ -1920,7 +1916,7 @@ def running( # existing container and the temp container were detected, # and no signal was sent to the container. comments.append( - "Container '{}' is already configured as specified".format(name) + f"Container '{name}' is already configured as specified" ) if net_changes: @@ -1981,11 +1977,9 @@ def running( "configuration".format(net_name) ) elif disconnected: - comments.append( - "Disconnected from network '{}'".format(net_name) - ) + comments.append(f"Disconnected from network '{net_name}'") elif connected: - comments.append("Connected to network '{}'".format(net_name)) + comments.append(f"Connected to network '{net_name}'") if network_failure: ret["result"] = False @@ -1996,7 +1990,7 @@ def running( if skip_comparison: if not exists: - comments.append("Created container '{}'".format(name)) + comments.append(f"Created container '{name}'") else: if not _replace(name, temp_container): ret["result"] = False @@ -2023,9 +2017,7 @@ def running( post_state = __salt__["docker.start"](name)["state"]["new"] except Exception as exc: # pylint: disable=broad-except ret["result"] = False - comments.append( - "Failed to start container '{}': '{}'".format(name, exc) - ) + comments.append(f"Failed to start container '{name}': '{exc}'") return _format_comments(ret, comments) else: post_state = __salt__["docker.state"](name) @@ -2070,9 +2062,7 @@ def running( if pre_state != post_state: ret["changes"]["state"] = {"old": pre_state, "new": post_state} if pre_state is not None: - comments.append( - "State changed from '{}' to '{}'".format(pre_state, post_state) - ) + comments.append(f"State changed from '{pre_state}' to '{post_state}'") if exists and current_image_id != image_id: comments.append("Container has a new image") @@ -2096,7 +2086,7 @@ def run( ignore_collisions=False, validate_ip_addrs=True, client_timeout=salt.utils.dockermod.CLIENT_TIMEOUT, - **kwargs + **kwargs, ): """ .. versionadded:: 2018.3.0 @@ -2186,7 +2176,7 @@ def run( for unsupported in ("watch_action", "start", "shutdown_timeout", "follow"): if unsupported in kwargs: ret["result"] = False - ret["comment"] = "The '{}' argument is not supported".format(unsupported) + ret["comment"] = f"The '{unsupported}' argument is not supported" return ret if image is None: @@ -2259,12 +2249,12 @@ def run( bg=bg, replace=replace, force=force, - **kwargs + **kwargs, ) except Exception as exc: # pylint: disable=broad-except log.exception("Encountered error running container") ret["result"] = False - ret["comment"] = "Encountered error running container: {}".format(exc) + ret["comment"] = f"Encountered error running container: {exc}" else: if bg: ret["comment"] = "Container was run in the background" @@ -2276,7 +2266,7 @@ def run( else: ret["result"] = False if failhard and retcode != 0 else True ret["comment"] = ( - "Container ran and exited with a return code of {}".format(retcode) + f"Container ran and exited with a return code of {retcode}" ) if remove: @@ -2286,7 +2276,7 @@ def run( __salt__["docker.rm"](ret["changes"]["Id"]) except CommandExecutionError as exc: ret.setdefault("warnings", []).append( - "Failed to auto_remove container: {}".format(exc) + f"Failed to auto_remove container: {exc}" ) return ret @@ -2298,7 +2288,7 @@ def stopped( shutdown_timeout=None, unpause=False, error_on_absent=True, - **kwargs + **kwargs, ): """ Ensure that a container (or containers) is stopped @@ -2402,7 +2392,7 @@ def stopped( if not to_stop: ret["result"] = True if len(targets) == 1: - ret["comment"] = "Container '{}' is ".format(targets[0]) + ret["comment"] = f"Container '{targets[0]}' is " else: ret["comment"] = "All specified containers are " if "absent" in containers: @@ -2429,7 +2419,7 @@ def stopped( if "comment" in changes: stop_errors.append(changes["comment"]) else: - stop_errors.append("Failed to stop container '{}'".format(target)) + stop_errors.append(f"Failed to stop container '{target}'") if stop_errors: ret["comment"] = "; ".join(stop_errors) @@ -2470,7 +2460,7 @@ def absent(name, force=False): if name not in __salt__["docker.list_containers"](all=True): ret["result"] = True - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" return ret pre_state = __salt__["docker.state"](name) @@ -2480,23 +2470,23 @@ def absent(name, force=False): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' will be removed".format(name) + ret["comment"] = f"Container '{name}' will be removed" return ret try: ret["changes"]["removed"] = __salt__["docker.rm"](name, force=force) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to remove container '{}': {}".format(name, exc) + ret["comment"] = f"Failed to remove container '{name}': {exc}" return ret if name in __salt__["docker.list_containers"](all=True): - ret["comment"] = "Failed to remove container '{}'".format(name) + ret["comment"] = f"Failed to remove container '{name}'" else: if force and pre_state != "stopped": method = "Forcibly" else: method = "Successfully" - ret["comment"] = "{} removed container '{}'".format(method, name) + ret["comment"] = f"{method} removed container '{name}'" ret["result"] = True return ret @@ -2530,5 +2520,5 @@ def mod_watch(name, sfun=None, **kwargs): "name": name, "changes": {}, "result": False, - "comment": "watch requisite is not implemented for {}".format(sfun), + "comment": f"watch requisite is not implemented for {sfun}", } diff --git a/salt/states/docker_image.py b/salt/states/docker_image.py index b2b887ffea3..b55790de68a 100644 --- a/salt/states/docker_image.py +++ b/salt/states/docker_image.py @@ -72,7 +72,7 @@ def present( saltenv="base", pillarenv=None, pillar=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2018.3.0 @@ -241,7 +241,7 @@ def present( full_image = ":".join((name, tag)) else: if tag: - name = "{}:{}".format(name, tag) + name = f"{name}:{tag}" full_image = name try: @@ -259,7 +259,7 @@ def present( # Specified image is present if not force: ret["result"] = True - ret["comment"] = "Image {} already present".format(full_image) + ret["comment"] = f"Image {full_image} already present" return ret if build or sls: @@ -272,7 +272,7 @@ def present( if __opts__["test"]: ret["result"] = None if (image_info is not None and force) or image_info is None: - ret["comment"] = "Image {} will be {}".format(full_image, action) + ret["comment"] = f"Image {full_image} will be {action}" return ret if build: @@ -336,7 +336,7 @@ def present( name, insecure_registry=insecure_registry, client_timeout=client_timeout ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Encountered error pulling {}: {}".format(full_image, exc) + ret["comment"] = f"Encountered error pulling {full_image}: {exc}" return ret if ( image_info is not None @@ -370,7 +370,7 @@ def present( name, action ) else: - ret["comment"] = "Image '{}' was {}".format(full_image, action) + ret["comment"] = f"Image '{full_image}' was {action}" return ret @@ -450,7 +450,7 @@ def absent(name=None, images=None, force=False): if not to_delete: ret["result"] = True if len(targets) == 1: - ret["comment"] = "Image {} is not present".format(name) + ret["comment"] = f"Image {name} is not present" else: ret["comment"] = "All specified images are not present" return ret @@ -458,7 +458,7 @@ def absent(name=None, images=None, force=False): if __opts__["test"]: ret["result"] = None if len(to_delete) == 1: - ret["comment"] = "Image {} will be removed".format(to_delete[0]) + ret["comment"] = f"Image {to_delete[0]} will be removed" else: ret["comment"] = "The following images will be removed: {}".format( ", ".join(to_delete) @@ -484,7 +484,7 @@ def absent(name=None, images=None, force=False): else: ret["changes"] = result if len(to_delete) == 1: - ret["comment"] = "Image {} was removed".format(to_delete[0]) + ret["comment"] = f"Image {to_delete[0]} was removed" else: ret["comment"] = "The following images were removed: {}".format( ", ".join(to_delete) @@ -513,5 +513,5 @@ def mod_watch(name, sfun=None, **kwargs): "name": name, "changes": {}, "result": False, - "comment": "watch requisite is not implemented for {}".format(sfun), + "comment": f"watch requisite is not implemented for {sfun}", } diff --git a/salt/states/docker_network.py b/salt/states/docker_network.py index 4ff8c95382c..f041155dd13 100644 --- a/salt/states/docker_network.py +++ b/salt/states/docker_network.py @@ -65,7 +65,7 @@ def _normalize_pools(existing, desired): for pool in desired["Config"]: subnet = ipaddress.ip_network(pool.get("Subnet")) if pools["desired"][subnet.version] is not None: - raise ValueError("Only one IPv{} pool is permitted".format(subnet.version)) + raise ValueError(f"Only one IPv{subnet.version} pool is permitted") else: pools["desired"][subnet.version] = pool @@ -91,7 +91,7 @@ def present( validate_ip_addrs=True, containers=None, reconnect=True, - **kwargs + **kwargs, ): """ .. versionchanged:: 2018.3.0 @@ -575,7 +575,7 @@ def present( skip_translate=skip_translate, ignore_collisions=ignore_collisions, validate_ip_addrs=validate_ip_addrs, - **__utils__["args.clean_kwargs"](**kwargs) + **__utils__["args.clean_kwargs"](**kwargs), ) except Exception as exc: # pylint: disable=broad-except ret["comment"] = str(exc) @@ -620,7 +620,7 @@ def present( # Set the comment now to say that it already exists, if we need to # recreate the network with new config we'll update the comment later. ret["comment"] = ( - "Network '{}' already exists, and is configured as specified".format(name) + f"Network '{name}' already exists, and is configured as specified" ) log.trace("Details of docker network '%s': %s", name, network) @@ -658,7 +658,7 @@ def present( temp_net_name, skip_translate=True, # No need to translate (already did) enable_ipv6=False, - **kwargs_tmp + **kwargs_tmp, ) except CommandExecutionError as exc: ret["comment"] = "Failed to create temp network for comparison: {}".format( @@ -674,7 +674,7 @@ def present( try: temp_net_info = __salt__["docker.inspect_network"](temp_net_name) except CommandExecutionError as exc: - ret["comment"] = "Failed to inspect temp network: {}".format(str(exc)) + ret["comment"] = f"Failed to inspect temp network: {str(exc)}" return ret else: temp_net_info["EnableIPv6"] = bool(enable_ipv6) @@ -773,7 +773,7 @@ def present( __salt__["docker.remove_network"](temp_net_name) except CommandExecutionError as exc: ret.setdefault("warnings", []).append( - "Failed to remove temp network '{}': {}.".format(temp_net_name, exc) + f"Failed to remove temp network '{temp_net_name}': {exc}." ) if create_network: @@ -795,10 +795,10 @@ def present( __salt__["docker.create_network"]( name, skip_translate=True, # No need to translate (already did) - **kwargs + **kwargs, ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to create network '{}': {}".format(name, exc) + ret["comment"] = f"Failed to create network '{name}': {exc}" return ret else: action = "recreated" if network is not None else "created" @@ -922,12 +922,12 @@ def absent(name): if network is None: ret["result"] = True - ret["comment"] = "Network '{}' already absent".format(name) + ret["comment"] = f"Network '{name}' already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Network '{}' will be removed".format(name) + ret["comment"] = f"Network '{name}' will be removed" return ret return _remove_network(network) @@ -952,7 +952,7 @@ def _remove_network(network): try: __salt__["docker.disconnect_container_from_network"](cid, network["Name"]) except CommandExecutionError as exc: - errors = "Failed to disconnect container '{}' : {}".format(cname, exc) + errors = f"Failed to disconnect container '{cname}' : {exc}" else: ret["changes"].setdefault("disconnected", []).append(cname) @@ -963,7 +963,7 @@ def _remove_network(network): try: __salt__["docker.remove_network"](network["Name"]) except CommandExecutionError as exc: - ret["comment"] = "Failed to remove network: {}".format(exc) + ret["comment"] = f"Failed to remove network: {exc}" else: ret["changes"]["removed"] = True ret["result"] = True diff --git a/salt/states/docker_volume.py b/salt/states/docker_volume.py index 86497b5dbd5..1d46a064c9d 100644 --- a/salt/states/docker_volume.py +++ b/salt/states/docker_volume.py @@ -135,14 +135,14 @@ def present(name, driver=None, driver_opts=None, force=False): if not volume: if __opts__["test"]: ret["result"] = None - ret["comment"] = "The volume '{}' will be created".format(name) + ret["comment"] = f"The volume '{name}' will be created" return ret try: ret["changes"]["created"] = __salt__["docker.create_volume"]( name, driver=driver, driver_opts=driver_opts ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to create volume '{}': {}".format(name, exc) + ret["comment"] = f"Failed to create volume '{name}': {exc}" return ret else: result = True @@ -168,7 +168,7 @@ def present(name, driver=None, driver_opts=None, force=False): try: ret["changes"]["removed"] = __salt__["docker.remove_volume"](name) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to remove volume '{}': {}".format(name, exc) + ret["comment"] = f"Failed to remove volume '{name}': {exc}" return ret else: try: @@ -176,7 +176,7 @@ def present(name, driver=None, driver_opts=None, force=False): name, driver=driver, driver_opts=driver_opts ) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to create volume '{}': {}".format(name, exc) + ret["comment"] = f"Failed to create volume '{name}': {exc}" return ret else: result = True @@ -184,7 +184,7 @@ def present(name, driver=None, driver_opts=None, force=False): return ret ret["result"] = True - ret["comment"] = "Volume '{}' already exists.".format(name) + ret["comment"] = f"Volume '{name}' already exists." return ret @@ -212,12 +212,12 @@ def absent(name, driver=None): volume = _find_volume(name) if not volume: ret["result"] = True - ret["comment"] = "Volume '{}' already absent".format(name) + ret["comment"] = f"Volume '{name}' already absent" return ret try: ret["changes"]["removed"] = __salt__["docker.remove_volume"](name) ret["result"] = True except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to remove volume '{}': {}".format(name, exc) + ret["comment"] = f"Failed to remove volume '{name}': {exc}" return ret diff --git a/salt/states/drac.py b/salt/states/drac.py index 29a3a6fa7a6..c3a7b4258de 100644 --- a/salt/states/drac.py +++ b/salt/states/drac.py @@ -68,18 +68,18 @@ def present(name, password, permission): if __opts__["test"]: if name in users: - ret["comment"] = "`{}` already exists".format(name) + ret["comment"] = f"`{name}` already exists" else: - ret["comment"] = "`{}` will be created".format(name) + ret["comment"] = f"`{name}` will be created" ret["changes"] = {name: "will be created"} return ret if name in users: - ret["comment"] = "`{}` already exists".format(name) + ret["comment"] = f"`{name}` already exists" else: if __salt__["drac.create_user"](name, password, permission, users): - ret["comment"] = "`{}` user created".format(name) + ret["comment"] = f"`{name}` user created" ret["changes"] = {name: "new user created"} else: ret["comment"] = "Unable to create user" @@ -101,22 +101,22 @@ def absent(name): if __opts__["test"]: if name in users: - ret["comment"] = "`{}` is set to be deleted".format(name) + ret["comment"] = f"`{name}` is set to be deleted" ret["changes"] = {name: "will be deleted"} else: - ret["comment"] = "`{}` does not exist".format(name) + ret["comment"] = f"`{name}` does not exist" return ret if name in users: if __salt__["drac.delete_user"](name, users[name]["index"]): - ret["comment"] = "`{}` deleted".format(name) + ret["comment"] = f"`{name}` deleted" ret["changes"] = {name: "deleted"} else: ret["comment"] = "Unable to delete user" ret["result"] = False else: - ret["comment"] = "`{}` does not exist".format(name) + ret["comment"] = f"`{name}` does not exist" return ret diff --git a/salt/states/dvs.py b/salt/states/dvs.py index 5b757c13678..6333395c490 100644 --- a/salt/states/dvs.py +++ b/salt/states/dvs.py @@ -257,7 +257,7 @@ def _get_datacenter_name(): details = __salt__["esxdatacenter.get_details"]() if not details: raise salt.exceptions.CommandExecutionError( - "details for proxy type '{}' not loaded".format(proxy_type) + f"details for proxy type '{proxy_type}' not loaded" ) return details["datacenter"] @@ -475,7 +475,7 @@ def _get_val2_dict_from_diff_dict(diff_dict): ret_dict = {} for p in diff_dict.keys(): if not isinstance(diff_dict[p], dict): - raise ValueError("Unexpected diff difct '{}'".format(diff_dict)) + raise ValueError(f"Unexpected diff difct '{diff_dict}'") if "val2" in diff_dict[p].keys(): ret_dict.update({p: diff_dict[p]["val2"]}) else: @@ -490,7 +490,7 @@ def _get_val1_dict_from_diff_dict(diff_dict): ret_dict = {} for p in diff_dict.keys(): if not isinstance(diff_dict[p], dict): - raise ValueError("Unexpected diff difct '{}'".format(diff_dict)) + raise ValueError(f"Unexpected diff difct '{diff_dict}'") if "val1" in diff_dict[p].keys(): ret_dict.update({p: diff_dict[p]["val1"]}) else: @@ -507,7 +507,7 @@ def _get_changes_from_diff_dict(diff_dict): changes_strings = [] for p in diff_dict.keys(): if not isinstance(diff_dict[p], dict): - raise ValueError("Unexpected diff difct '{}'".format(diff_dict)) + raise ValueError(f"Unexpected diff difct '{diff_dict}'") if sorted(diff_dict[p].keys()) == ["val1", "val2"]: # Some string formatting from_str = diff_dict[p]["val1"] @@ -520,12 +520,12 @@ def _get_changes_from_diff_dict(diff_dict): to_str = "'{}'".format(diff_dict[p]["val2"]) elif isinstance(diff_dict[p]["val2"], list): to_str = "'{}'".format(", ".join(diff_dict[p]["val2"])) - changes_strings.append("{} from {} to {}".format(p, from_str, to_str)) + changes_strings.append(f"{p} from {from_str} to {to_str}") else: sub_changes = _get_changes_from_diff_dict(diff_dict[p]) if sub_changes: - changes_strings.append("{}:".format(p)) - changes_strings.extend(["\t{}".format(c) for c in sub_changes]) + changes_strings.append(f"{p}:") + changes_strings.extend([f"\t{c}" for c in sub_changes]) return changes_strings @@ -608,7 +608,7 @@ def portgroups_configured(name, dvs, portgroups): pg_name, dvs, datacenter, - "\n".join(["\t{}".format(c) for c in changes_strings]), + "\n".join([f"\t{c}" for c in changes_strings]), ) ) else: @@ -734,7 +734,7 @@ def uplink_portgroup_configured(name, dvs, uplink_portgroup): name, dvs, datacenter, - "\n".join(["\t{}".format(c) for c in changes_strings]), + "\n".join([f"\t{c}" for c in changes_strings]), ) ) else: diff --git a/salt/states/elasticsearch.py b/salt/states/elasticsearch.py index ae9a37c3e8e..962ac1d8ddf 100644 --- a/salt/states/elasticsearch.py +++ b/salt/states/elasticsearch.py @@ -25,20 +25,20 @@ def index_absent(name): index = __salt__["elasticsearch.index_get"](index=name) if index and name in index: if __opts__["test"]: - ret["comment"] = "Index {} will be removed".format(name) + ret["comment"] = f"Index {name} will be removed" ret["changes"]["old"] = index[name] ret["result"] = None else: ret["result"] = __salt__["elasticsearch.index_delete"](index=name) if ret["result"]: - ret["comment"] = "Successfully removed index {}".format(name) + ret["comment"] = f"Successfully removed index {name}" ret["changes"]["old"] = index[name] else: ret["comment"] = ( - "Failed to remove index {} for unknown reasons".format(name) + f"Failed to remove index {name} for unknown reasons" ) else: - ret["comment"] = "Index {} is already absent".format(name) + ret["comment"] = f"Index {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -88,15 +88,15 @@ def index_present(name, definition=None): index=name, body=definition ) if output: - ret["comment"] = "Successfully created index {}".format(name) + ret["comment"] = f"Successfully created index {name}" ret["changes"] = { "new": __salt__["elasticsearch.index_get"](index=name)[name] } else: ret["result"] = False - ret["comment"] = "Cannot create index {}, {}".format(name, output) + ret["comment"] = f"Cannot create index {name}, {output}" else: - ret["comment"] = "Index {} is already present".format(name) + ret["comment"] = f"Index {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -136,7 +136,7 @@ def alias_absent(name, index): ) if ret["result"]: ret["comment"] = ( - "Successfully removed alias {} for index {}".format(name, index) + f"Successfully removed alias {name} for index {index}" ) ret["changes"]["old"] = ( alias.get(index, {}).get("aliases", {}).get(name, {}) @@ -256,7 +256,7 @@ def index_template_absent(name): index_template = __salt__["elasticsearch.index_template_get"](name=name) if index_template and name in index_template: if __opts__["test"]: - ret["comment"] = "Index template {} will be removed".format(name) + ret["comment"] = f"Index template {name} will be removed" ret["changes"]["old"] = index_template[name] ret["result"] = None else: @@ -275,7 +275,7 @@ def index_template_absent(name): ) ) else: - ret["comment"] = "Index template {} is already absent".format(name) + ret["comment"] = f"Index template {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -316,7 +316,7 @@ def index_template_present(name, definition, check_definition=False): if not index_template_exists: if __opts__["test"]: ret["comment"] = ( - "Index template {} does not exist and will be created".format(name) + f"Index template {name} does not exist and will be created" ) ret["changes"] = {"new": definition} ret["result"] = None @@ -369,7 +369,7 @@ def index_template_present(name, definition, check_definition=False): ) if output: ret["comment"] = ( - "Successfully updated index template {}".format(name) + f"Successfully updated index template {name}" ) ret["changes"] = diff else: @@ -386,7 +386,7 @@ def index_template_present(name, definition, check_definition=False): ) ) else: - ret["comment"] = "Index template {} is already present".format(name) + ret["comment"] = f"Index template {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -408,20 +408,20 @@ def pipeline_absent(name): pipeline = __salt__["elasticsearch.pipeline_get"](id=name) if pipeline and name in pipeline: if __opts__["test"]: - ret["comment"] = "Pipeline {} will be removed".format(name) + ret["comment"] = f"Pipeline {name} will be removed" ret["changes"]["old"] = pipeline[name] ret["result"] = None else: ret["result"] = __salt__["elasticsearch.pipeline_delete"](id=name) if ret["result"]: - ret["comment"] = "Successfully removed pipeline {}".format(name) + ret["comment"] = f"Successfully removed pipeline {name}" ret["changes"]["old"] = pipeline[name] else: ret["comment"] = ( - "Failed to remove pipeline {} for unknown reasons".format(name) + f"Failed to remove pipeline {name} for unknown reasons" ) else: - ret["comment"] = "Pipeline {} is already absent".format(name) + ret["comment"] = f"Pipeline {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -465,7 +465,7 @@ def pipeline_present(name, definition): if __opts__["test"]: if not pipeline: ret["comment"] = ( - "Pipeline {} does not exist and will be created".format(name) + f"Pipeline {name} does not exist and will be created" ) else: ret["comment"] = ( @@ -480,7 +480,7 @@ def pipeline_present(name, definition): ) if output: if not pipeline: - ret["comment"] = "Successfully created pipeline {}".format(name) + ret["comment"] = f"Successfully created pipeline {name}" else: ret["comment"] = "Successfully replaced pipeline {}".format( name @@ -491,7 +491,7 @@ def pipeline_present(name, definition): name, output ) else: - ret["comment"] = "Pipeline {} is already present".format(name) + ret["comment"] = f"Pipeline {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -513,7 +513,7 @@ def search_template_absent(name): template = __salt__["elasticsearch.search_template_get"](id=name) if template: if __opts__["test"]: - ret["comment"] = "Search template {} will be removed".format(name) + ret["comment"] = f"Search template {name} will be removed" ret["changes"]["old"] = salt.utils.json.loads(template["template"]) ret["result"] = None else: @@ -532,7 +532,7 @@ def search_template_absent(name): ) ) else: - ret["comment"] = "Search template {} is already absent".format(name) + ret["comment"] = f"Search template {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -592,20 +592,16 @@ def search_template_present(name, definition): ) if output: if not template: - ret["comment"] = ( - "Successfully created search template {}".format(name) - ) + ret["comment"] = f"Successfully created search template {name}" else: - ret["comment"] = ( - "Successfully replaced search template {}".format(name) - ) + ret["comment"] = f"Successfully replaced search template {name}" else: ret["result"] = False ret["comment"] = "Cannot create search template {}, {}".format( name, output ) else: - ret["comment"] = "Search template {} is already present".format(name) + ret["comment"] = f"Search template {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) diff --git a/salt/states/elasticsearch_index.py b/salt/states/elasticsearch_index.py index 48fcbf891c1..dcf0d442579 100644 --- a/salt/states/elasticsearch_index.py +++ b/salt/states/elasticsearch_index.py @@ -25,20 +25,20 @@ def absent(name): index = __salt__["elasticsearch.index_get"](index=name) if index and name in index: if __opts__["test"]: - ret["comment"] = "Index {} will be removed".format(name) + ret["comment"] = f"Index {name} will be removed" ret["changes"]["old"] = index[name] ret["result"] = None else: ret["result"] = __salt__["elasticsearch.index_delete"](index=name) if ret["result"]: - ret["comment"] = "Successfully removed index {}".format(name) + ret["comment"] = f"Successfully removed index {name}" ret["changes"]["old"] = index[name] else: ret["comment"] = ( - "Failed to remove index {} for unknown reasons".format(name) + f"Failed to remove index {name} for unknown reasons" ) else: - ret["comment"] = "Index {} is already absent".format(name) + ret["comment"] = f"Index {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -93,15 +93,15 @@ def present(name, definition=None): index=name, body=definition ) if output: - ret["comment"] = "Successfully created index {}".format(name) + ret["comment"] = f"Successfully created index {name}" ret["changes"] = { "new": __salt__["elasticsearch.index_get"](index=name)[name] } else: ret["result"] = False - ret["comment"] = "Cannot create index {}, {}".format(name, output) + ret["comment"] = f"Cannot create index {name}, {output}" else: - ret["comment"] = "Index {} is already present".format(name) + ret["comment"] = f"Index {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) diff --git a/salt/states/elasticsearch_index_template.py b/salt/states/elasticsearch_index_template.py index 61ae82e1838..c4574bd9dc7 100644 --- a/salt/states/elasticsearch_index_template.py +++ b/salt/states/elasticsearch_index_template.py @@ -25,7 +25,7 @@ def absent(name): index_template = __salt__["elasticsearch.index_template_get"](name=name) if index_template and name in index_template: if __opts__["test"]: - ret["comment"] = "Index template {} will be removed".format(name) + ret["comment"] = f"Index template {name} will be removed" ret["changes"]["old"] = index_template[name] ret["result"] = None else: @@ -44,7 +44,7 @@ def absent(name): ) ) else: - ret["comment"] = "Index template {} is already absent".format(name) + ret["comment"] = f"Index template {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -88,7 +88,7 @@ def present(name, definition): if not index_template_exists: if __opts__["test"]: ret["comment"] = ( - "Index template {} does not exist and will be created".format(name) + f"Index template {name} does not exist and will be created" ) ret["changes"] = {"new": definition} ret["result"] = None @@ -111,7 +111,7 @@ def present(name, definition): name, output ) else: - ret["comment"] = "Index template {} is already present".format(name) + ret["comment"] = f"Index template {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) diff --git a/salt/states/eselect.py b/salt/states/eselect.py index 36246efdd99..2b5196cea17 100644 --- a/salt/states/eselect.py +++ b/salt/states/eselect.py @@ -59,7 +59,7 @@ def set_(name, target, module_parameter=None, action_parameter=None): ) ret["result"] = False elif __opts__["test"]: - ret["comment"] = "Target '{}' will be set on '{}' module.".format(target, name) + ret["comment"] = f"Target '{target}' will be set on '{name}' module." ret["result"] = None else: result = __salt__["eselect.set_target"]( @@ -70,7 +70,7 @@ def set_(name, target, module_parameter=None, action_parameter=None): ) if result: ret["changes"][name] = {"old": old_target, "new": target} - ret["comment"] = "Target '{}' set on '{}' module.".format(target, name) + ret["comment"] = f"Target '{target}' set on '{name}' module." else: ret["comment"] = "Target '{}' failed to be set on '{}' module.".format( target, name diff --git a/salt/states/esxcluster.py b/salt/states/esxcluster.py index b8509b4a329..f4cd626f292 100644 --- a/salt/states/esxcluster.py +++ b/salt/states/esxcluster.py @@ -139,7 +139,7 @@ def _get_vsan_datastore(si, cluster_name): if not vsan_datastores: raise salt.exceptions.VMwareObjectRetrievalError( - "No vSAN datastores where retrieved for cluster '{}'".format(cluster_name) + f"No vSAN datastores where retrieved for cluster '{cluster_name}'" ) return vsan_datastores[0] @@ -200,9 +200,7 @@ def cluster_configured(name, cluster_config): __salt__["esxcluster.get_details"]()["datacenter"], ) else: - raise salt.exceptions.CommandExecutionError( - "Unsupported proxy {}".format(proxy_type) - ) + raise salt.exceptions.CommandExecutionError(f"Unsupported proxy {proxy_type}") log.info( "Running %s for cluster '%s' in datacenter '%s'", name, @@ -287,13 +285,11 @@ def cluster_configured(name, cluster_config): changes_required = True changes_str = "" if diff.diffs: - changes_str = "{}{}".format(changes_str, diff.changes_str) + changes_str = f"{changes_str}{diff.changes_str}" if ldiff and ldiff.diffs: changes_str = "{}\nha:\n options:\n{}".format( changes_str, - "\n".join( - [" {}".format(l) for l in ldiff.changes_str2.split("\n")] - ), + "\n".join([f" {l}" for l in ldiff.changes_str2.split("\n")]), ) # Apply the changes if __opts__["test"]: @@ -354,7 +350,7 @@ def vsan_datastore_configured(name, datastore_name): __salt__["esxcluster.get_details"]()["cluster"], __salt__["esxcluster.get_details"]()["datacenter"], ) - display_name = "{}/{}".format(datacenter_name, cluster_name) + display_name = f"{datacenter_name}/{cluster_name}" log.info("Running vsan_datastore_configured for '%s'", display_name) ret = {"name": name, "changes": {}, "result": None, "comment": "Default"} comments = [] @@ -393,9 +389,7 @@ def vsan_datastore_configured(name, datastore_name): new_datastore_name=datastore_name, service_instance=si, ) - comments.append( - "Renamed vSAN datastore to '{}'.".format(datastore_name) - ) + comments.append(f"Renamed vSAN datastore to '{datastore_name}'.") changes = { "vsan_datastore": { "new": {"name": datastore_name}, @@ -445,7 +439,7 @@ def licenses_configured(name, licenses=None): __salt__["esxcluster.get_details"]()["cluster"], __salt__["esxcluster.get_details"]()["datacenter"], ) - display_name = "{}/{}".format(datacenter_name, cluster_name) + display_name = f"{datacenter_name}/{cluster_name}" log.info("Running licenses configured for '%s'", display_name) log.trace("licenses = %s", licenses) entity = {"type": "cluster", "datacenter": datacenter_name, "cluster": cluster_name} @@ -495,7 +489,7 @@ def licenses_configured(name, licenses=None): log.error(comments[-1]) has_errors = True continue - comments.append("Added license '{}'.".format(license_name)) + comments.append(f"Added license '{license_name}'.") log.info(comments[-1]) else: # License exists let's check if it's assigned to the cluster diff --git a/salt/states/esxdatacenter.py b/salt/states/esxdatacenter.py index b341a1ed9bb..cce5b52024f 100644 --- a/salt/states/esxdatacenter.py +++ b/salt/states/esxdatacenter.py @@ -128,16 +128,16 @@ def datacenter_configured(name): ) if not dcs: if __opts__["test"]: - comments.append("State will create datacenter '{}'.".format(dc_name)) + comments.append(f"State will create datacenter '{dc_name}'.") else: log.debug("Creating datacenter '%s'", dc_name) __salt__["vsphere.create_datacenter"](dc_name, si) - comments.append("Created datacenter '{}'.".format(dc_name)) + comments.append(f"Created datacenter '{dc_name}'.") log.info(comments[-1]) ret["changes"].update({"new": {"name": dc_name}}) else: comments.append( - "Datacenter '{}' already exists. Nothing to be done.".format(dc_name) + f"Datacenter '{dc_name}' already exists. Nothing to be done." ) log.info(comments[-1]) __salt__["vsphere.disconnect"](si) diff --git a/salt/states/esxi.py b/salt/states/esxi.py index 566396e5e7b..7f0df24664f 100644 --- a/salt/states/esxi.py +++ b/salt/states/esxi.py @@ -226,7 +226,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500 current_config = __salt__[esxi_cmd]("get_coredump_network_config").get(host) error = current_config.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret current_config = current_config.get("Coredump Config") @@ -242,7 +242,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500 ).get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret # Allow users to disable core dump, but then return since @@ -295,7 +295,7 @@ def coredump_configured(name, enabled, dump_ip, host_vnic="vmk0", dump_port=6500 msg = response.get("stderr") if not msg: msg = response.get("stdout") - ret["comment"] = "Error: {}".format(msg) + ret["comment"] = f"Error: {msg}" return ret ret["result"] = True @@ -354,7 +354,7 @@ def password_present(name, password): __salt__[esxi_cmd]("update_host_password", new_password=password) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret return ret @@ -427,7 +427,7 @@ def ntp_configured( ntp_running = __salt__[esxi_cmd]("get_service_running", service_name=ntpd).get(host) error = ntp_running.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ntp_running = ntp_running.get(ntpd) @@ -440,7 +440,7 @@ def ntp_configured( ).get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret # Set changes dictionary for ntp_servers ret["changes"].update({"ntp_servers": {"old": ntp_config, "new": ntp_servers}}) @@ -456,7 +456,7 @@ def ntp_configured( ) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret # Stop ntpd if service_running=False else: @@ -465,7 +465,7 @@ def ntp_configured( ) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( {"service_running": {"old": ntp_running, "new": service_running}} @@ -478,7 +478,7 @@ def ntp_configured( ).get(host) error = current_service_policy.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret current_service_policy = current_service_policy.get(ntpd) @@ -492,7 +492,7 @@ def ntp_configured( ).get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( { @@ -510,7 +510,7 @@ def ntp_configured( response = __salt__[esxi_cmd]("update_host_datetime").get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( {"update_datetime": {"old": "", "new": "Host datetime was updated."}} @@ -525,7 +525,7 @@ def ntp_configured( ) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( {"service_restart": {"old": "", "new": "NTP Daemon Restarted."}} @@ -587,14 +587,14 @@ def vmotion_configured(name, enabled, device="vmk0"): response = __salt__[esxi_cmd]("vmotion_enable", device=device).get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret # Disable VMotion if enabled=False else: response = __salt__[esxi_cmd]("vmotion_disable").get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( {"enabled": {"old": current_vmotion_enabled, "new": enabled}} @@ -647,7 +647,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False): current_vsan_enabled = __salt__[esxi_cmd]("get_vsan_enabled").get(host) error = current_vsan_enabled.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret current_vsan_enabled = current_vsan_enabled.get("VSAN Enabled") @@ -660,14 +660,14 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False): response = __salt__[esxi_cmd]("vsan_enable").get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret # Disable VSAN if enabled=False else: response = __salt__[esxi_cmd]("vsan_disable").get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( {"enabled": {"old": current_vsan_enabled, "new": enabled}} @@ -678,7 +678,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False): current_eligible_disks = __salt__[esxi_cmd]("get_vsan_eligible_disks").get(host) error = current_eligible_disks.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret disks = current_eligible_disks.get("Eligible") @@ -688,7 +688,7 @@ def vsan_configured(name, enabled, add_disks_to_vsan=False): response = __salt__[esxi_cmd]("vsan_add_disks").get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update({"add_disks_to_vsan": {"old": "", "new": disks}}) @@ -779,7 +779,7 @@ def ssh_configured( ssh_running = __salt__[esxi_cmd]("get_service_running", service_name=ssh).get(host) error = ssh_running.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ssh_running = ssh_running.get(ssh) @@ -792,14 +792,14 @@ def ssh_configured( enable = __salt__[esxi_cmd]("service_start", service_name=ssh).get(host) error = enable.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret # Disable SSH if service_running=False else: disable = __salt__[esxi_cmd]("service_stop", service_name=ssh).get(host) error = disable.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( @@ -815,7 +815,7 @@ def ssh_configured( ) error = current_ssh_key.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret current_ssh_key = current_ssh_key.get("key") if current_ssh_key: @@ -854,7 +854,7 @@ def ssh_configured( ) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( { @@ -872,7 +872,7 @@ def ssh_configured( ).get(host) error = current_service_policy.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret current_service_policy = current_service_policy.get(ssh) @@ -886,7 +886,7 @@ def ssh_configured( ).get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( { @@ -904,7 +904,7 @@ def ssh_configured( response = __salt__[esxi_cmd]("service_restart", service_name=ssh).get(host) error = response.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret ret["changes"].update( {"service_restart": {"old": "", "new": "SSH service restarted."}} @@ -1008,7 +1008,7 @@ def syslog_configured( "There was an error resetting a syslog config '{}'." "Please check debug logs.".format(val) ) - ret["comment"] = "Error: {}".format(msg) + ret["comment"] = f"Error: {msg}" return ret ret["changes"].update( @@ -1018,7 +1018,7 @@ def syslog_configured( current_firewall = __salt__[esxi_cmd]("get_firewall_status").get(host) error = current_firewall.get("Error") if error: - ret["comment"] = "Error: {}".format(error) + ret["comment"] = f"Error: {error}" return ret current_firewall = current_firewall.get("rulesets").get("syslog") @@ -1033,7 +1033,7 @@ def syslog_configured( if enabled.get("retcode") != 0: err = enabled.get("stderr") out = enabled.get("stdout") - ret["comment"] = "Error: {}".format(err if err else out) + ret["comment"] = f"Error: {err if err else out}" return ret ret["changes"].update({"firewall": {"old": current_firewall, "new": firewall}}) @@ -1045,7 +1045,7 @@ def syslog_configured( try: lookup_key = _lookup_syslog_config(key) except KeyError: - ret["comment"] = "'{}' is not a valid config variable.".format(key) + ret["comment"] = f"'{key}' is not a valid config variable." return ret current_val = current_syslog_config[lookup_key] @@ -1158,7 +1158,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): host_disks = __salt__["vsphere.list_disks"](service_instance=si) if not host_disks: raise VMwareObjectRetrievalError( - "No disks retrieved from host '{}'".format(hostname) + f"No disks retrieved from host '{hostname}'" ) scsi_addr_to_disk_map = {d["scsi_address"]: d for d in host_disks} log.trace("scsi_addr_to_disk_map = %s", scsi_addr_to_disk_map) @@ -1199,14 +1199,12 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): bad_scsi_addrs.append(scsi_addr) continue capacity_disk_ids.append(scsi_addr_to_disk_map[scsi_addr]["id"]) - capacity_disk_displays.append( - "{} (id:{})".format(scsi_addr, capacity_disk_ids[-1]) - ) + capacity_disk_displays.append(f"{scsi_addr} (id:{capacity_disk_ids[-1]})") if bad_scsi_addrs: comments.append( "Error in diskgroup #{}: capacity disks with scsi addresses {} " "were not found.".format( - idx, ", ".join(["'{}'".format(a) for a in bad_scsi_addrs]) + idx, ", ".join([f"'{a}'" for a in bad_scsi_addrs]) ) ) log.error(comments[-1]) @@ -1227,9 +1225,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): name, idx, cache_disk_display, - ", ".join( - ["'{}'".format(a) for a in capacity_disk_displays] - ), + ", ".join([f"'{a}'" for a in capacity_disk_displays]), ) ) else: @@ -1244,9 +1240,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): "{}".format( idx, cache_disk_display, - ", ".join( - ["'{}'".format(a) for a in capacity_disk_displays] - ), + ", ".join([f"'{a}'" for a in capacity_disk_displays]), ) ) log.info(comments[-1]) @@ -1259,7 +1253,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): name, idx, cache_disk_display, - ", ".join(["'{}'".format(a) for a in capacity_disk_displays]), + ", ".join([f"'{a}'" for a in capacity_disk_displays]), ) ) log.info(comments[-1]) @@ -1273,12 +1267,12 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): service_instance=si, ) except VMwareSaltError as err: - comments.append("Error creating disk group #{}: {}.".format(idx, err)) + comments.append(f"Error creating disk group #{idx}: {err}.") log.error(comments[-1]) errors = True continue - comments.append("Created disk group #'{}'.".format(idx)) + comments.append(f"Created disk group #'{idx}'.") log.info(comments[-1]) diskgroup_changes[str(idx)] = { "new": {"cache": cache_disk_display, "capacity": capacity_disk_displays} @@ -1311,9 +1305,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): d["scsi_address"] for d in host_disks if d["id"] == disk_id ][0] added_capacity_disk_ids.append(disk_id) - added_capacity_disk_displays.append( - "{} (id:{})".format(disk_scsi_addr, disk_id) - ) + added_capacity_disk_displays.append(f"{disk_scsi_addr} (id:{disk_id})") for disk_id in existing_diskgroup["capacity_disks"]: if disk_id not in capacity_disk_ids: disk_scsi_addr = [ @@ -1321,7 +1313,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): ][0] removed_capacity_disk_ids.append(disk_id) removed_capacity_disk_displays.append( - "{} (id:{})".format(disk_scsi_addr, disk_id) + f"{disk_scsi_addr} (id:{disk_id})" ) log.debug( @@ -1339,9 +1331,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): "Error removing capacity disk(s) {} from disk group #{}; " "operation is not supported." "".format( - ", ".join( - ["'{}'".format(id) for id in removed_capacity_disk_displays] - ), + ", ".join([f"'{id}'" for id in removed_capacity_disk_displays]), idx, ) ) @@ -1354,7 +1344,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): # Building a string representation of the capacity disks # that need to be added - s = ", ".join(["'{}'".format(id) for id in added_capacity_disk_displays]) + s = ", ".join([f"'{id}'" for id in added_capacity_disk_displays]) if __opts__["test"]: comments.append( "State {} will add capacity disk(s) {} to disk group #{}.".format( @@ -1381,7 +1371,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): errors = True continue - com = "Added capacity disk(s) {} to disk group #{}".format(s, idx) + com = f"Added capacity disk(s) {s} to disk group #{idx}" log.info(com) comments.append(com) diskgroup_changes[str(idx)] = { @@ -1398,7 +1388,7 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): continue # No capacity needs to be added - s = "Disk group #{} is correctly configured. Nothing to be done.".format(idx) + s = f"Disk group #{idx} is correctly configured. Nothing to be done." log.info(s) comments.append(s) __salt__["vsphere.disconnect"](si) @@ -1662,7 +1652,7 @@ def host_cache_configured( backing_disk["id"], ", ".join( [ - "'{}'".format(disk) + f"'{disk}'" for disk in existing_datastores[0]["backing_disk_ids"] ] ), @@ -1710,8 +1700,8 @@ def host_cache_configured( changes.update( { "swap_size": { - "old": "{}GiB".format(existing_swap_size_MiB / 1024), - "new": "{}GiB".format(swap_size_MiB / 1024), + "old": f"{existing_swap_size_MiB / 1024}GiB", + "new": f"{swap_size_MiB / 1024}GiB", } } ) @@ -1746,7 +1736,7 @@ def host_cache_configured( swap_size_MiB=swap_size_MiB, service_instance=si, ) - comments.append("Host cache configured on host '{}'.".format(hostname)) + comments.append(f"Host cache configured on host '{hostname}'.") else: comments.append( "Host cache on host '{}' is already correctly " @@ -1766,7 +1756,7 @@ def host_cache_configured( ret.update( { "result": False if not __opts__["test"] else None, - "comment": "{}.".format(err), + "comment": f"{err}.", } ) return ret diff --git a/salt/states/esxvm.py b/salt/states/esxvm.py index 3a429aa8bd6..59df063745d 100644 --- a/salt/states/esxvm.py +++ b/salt/states/esxvm.py @@ -466,7 +466,7 @@ def vm_updated( { "result": True, "changes": {}, - "comment": "Virtual machine {} is already up to date".format(vm_name), + "comment": f"Virtual machine {vm_name} is already up to date", } ) return result @@ -531,7 +531,7 @@ def vm_updated( "name": name, "result": True, "changes": changes, - "comment": "Virtual machine {} was updated successfully".format(vm_name), + "comment": f"Virtual machine {vm_name} was updated successfully", } return result @@ -564,7 +564,7 @@ def vm_created( result = {"name": name, "result": None, "changes": {}, "comment": ""} if __opts__["test"]: - result["comment"] = "Virtual machine {} will be created".format(vm_name) + result["comment"] = f"Virtual machine {vm_name} will be created" return result service_instance = __salt__["vsphere.get_service_instance_via_proxy"]() @@ -614,7 +614,7 @@ def vm_created( "name": name, "result": True, "changes": changes, - "comment": "Virtual machine {} created successfully".format(vm_name), + "comment": f"Virtual machine {vm_name} created successfully", } return result @@ -628,7 +628,7 @@ def vm_registered(vm_name, datacenter, placement, vm_file, power_on=False): """ result = {"name": vm_name, "result": None, "changes": {}, "comment": ""} - vmx_path = "{}{}".format(vm_file.folderPath, vm_file.file[0].path) + vmx_path = f"{vm_file.folderPath}{vm_file.file[0].path}" log.trace("Registering virtual machine with vmx file: %s", vmx_path) service_instance = __salt__["vsphere.get_service_instance_via_proxy"]() try: @@ -664,7 +664,7 @@ def vm_registered(vm_name, datacenter, placement, vm_file, power_on=False): { "result": True, "changes": {"name": vm_name, "power_on": power_on}, - "comment": "Virtual machine {} registered successfully".format(vm_name), + "comment": f"Virtual machine {vm_name} registered successfully", } ) diff --git a/salt/states/etcd_mod.py b/salt/states/etcd_mod.py index 5bf2c0e9175..b86e89680c7 100644 --- a/salt/states/etcd_mod.py +++ b/salt/states/etcd_mod.py @@ -186,7 +186,7 @@ def __virtual__(): def _etcd_action(*, action, key, profile, value=None, **kwargs): try: - ret = __salt__["etcd.{}".format(action)]( + ret = __salt__[f"etcd.{action}"]( key=key, profile=profile, value=value, **kwargs ) except Exception: # pylint: disable=broad-except diff --git a/salt/states/ethtool.py b/salt/states/ethtool.py index 2d735fd37dc..25367cd8e48 100644 --- a/salt/states/ethtool.py +++ b/salt/states/ethtool.py @@ -86,7 +86,7 @@ def coalesce(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} coalescing settings are up to date.".format(name), + "comment": f"Network device {name} coalescing settings are up to date.", } apply_coalescing = False if "test" not in kwargs: @@ -109,7 +109,7 @@ def coalesce(name, **kwargs): for key, value in kwargs.items(): if key in old and value != old[key]: new.update({key: value}) - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") # Dry run if kwargs["test"]: @@ -127,7 +127,7 @@ def coalesce(name, **kwargs): # Prepare return output if new: apply_coalescing = True - ret["comment"] = "Device {} coalescing settings updated.".format(name) + ret["comment"] = f"Device {name} coalescing settings updated." ret["changes"]["ethtool_coalesce"] = "\n".join(diff) except AttributeError as error: @@ -171,7 +171,7 @@ def ring(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} ring parameters are up to date.".format(name), + "comment": f"Network device {name} ring parameters are up to date.", } apply_ring = False if "test" not in kwargs: @@ -182,7 +182,7 @@ def ring(name, **kwargs): old = __salt__["ethtool.show_ring"](name) if not isinstance(old, dict): ret["result"] = False - ret["comment"] = "Device {} ring parameters are not supported".format(name) + ret["comment"] = f"Device {name} ring parameters are not supported" return ret new = {} @@ -192,11 +192,11 @@ def ring(name, **kwargs): for key, value in kwargs.items(): if key in old: if value == "max": - value = old["{}_max".format(key)] + value = old[f"{key}_max"] if value != old[key]: new.update({key: value}) - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") # Dry run if kwargs["test"]: @@ -214,7 +214,7 @@ def ring(name, **kwargs): # Prepare return output if new: apply_ring = True - ret["comment"] = "Device {} ring parameters updated.".format(name) + ret["comment"] = f"Device {name} ring parameters updated." ret["changes"]["ethtool_ring"] = "\n".join(diff) except AttributeError as error: @@ -253,7 +253,7 @@ def offload(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} offload settings are up to date.".format(name), + "comment": f"Network device {name} offload settings are up to date.", } apply_offload = False if "test" not in kwargs: @@ -264,7 +264,7 @@ def offload(name, **kwargs): old = __salt__["ethtool.show_offload"](name) if not isinstance(old, dict): ret["result"] = False - ret["comment"] = "Device {} offload settings are not supported".format(name) + ret["comment"] = f"Device {name} offload settings are not supported" return ret new = {} @@ -275,7 +275,7 @@ def offload(name, **kwargs): value = value and "on" or "off" if key in old and value != old[key]: new.update({key: value}) - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") # Dry run if kwargs["test"]: @@ -293,7 +293,7 @@ def offload(name, **kwargs): # Prepare return output if new: apply_offload = True - ret["comment"] = "Device {} offload settings updated.".format(name) + ret["comment"] = f"Device {name} offload settings updated." ret["changes"]["ethtool_offload"] = "\n".join(diff) except AttributeError as error: @@ -336,7 +336,7 @@ def pause(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} pause parameters are up to date.".format(name), + "comment": f"Network device {name} pause parameters are up to date.", } apply_pause = False @@ -345,7 +345,7 @@ def pause(name, **kwargs): old = __salt__["ethtool.show_pause"](name) except CommandExecutionError: ret["result"] = False - ret["comment"] = "Device {} pause parameters are not supported".format(name) + ret["comment"] = f"Device {name} pause parameters are not supported" return ret # map ethtool command input to output text @@ -368,7 +368,7 @@ def pause(name, **kwargs): value = "on" elif value is False: value = "off" - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") if not new: return ret @@ -385,7 +385,7 @@ def pause(name, **kwargs): try: __salt__["ethtool.set_pause"](name, **new) # Prepare return output - ret["comment"] = "Device {} pause parameters updated.".format(name) + ret["comment"] = f"Device {name} pause parameters updated." ret["changes"]["ethtool_pause"] = "\n".join(diff) except CommandExecutionError as exc: ret["result"] = False diff --git a/salt/states/file.py b/salt/states/file.py index 5c084634350..e81dafa4a59 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -384,11 +384,11 @@ def _check_user(user, group): if user: uid = __salt__["file.user_to_uid"](user) if uid == "": - err += "User {} is not available ".format(user) + err += f"User {user} is not available " if group: gid = __salt__["file.group_to_gid"](group) if gid == "": - err += "Group {} is not available".format(group) + err += f"Group {group} is not available" if err and __opts__["test"]: # Write the warning with error message, but prevent failing, # in case of applying the state in test mode. @@ -644,10 +644,10 @@ def _check_file(name): if not os.path.isabs(name): ret = False - msg = "Specified file {} is not an absolute path".format(name) + msg = f"Specified file {name} is not an absolute path" elif not os.path.exists(name): ret = False - msg = "{}: file not found".format(name) + msg = f"{name}: file not found" return ret, msg @@ -741,7 +741,7 @@ def _check_directory( try: recurse_set = _get_recurse_set(recurse) except (TypeError, ValueError) as exc: - return False, "{}".format(exc), changes + return False, f"{exc}", changes if "user" not in recurse_set: user = None if "group" not in recurse_set: @@ -827,9 +827,9 @@ def _check_directory( comments = ["The following files will be changed:\n"] for fn_ in changes: for key, val in changes[fn_].items(): - comments.append("{}: {} - {}\n".format(fn_, key, val)) + comments.append(f"{fn_}: {key} - {val}\n") return None, "".join(comments), changes - return True, "The directory {} is in the correct state".format(name), changes + return True, f"The directory {name} is in the correct state", changes def _check_directory_win( @@ -859,9 +859,9 @@ def _check_directory_win( )["changes"] if changes: - return None, 'The directory "{}" will be changed'.format(name), changes + return None, f'The directory "{name}" will be changed', changes - return True, "The directory {} is in the correct state".format(name), changes + return True, f"The directory {name} is in the correct state", changes def _check_dir_meta(name, user, group, mode, follow_symlinks=False): @@ -909,17 +909,17 @@ def _check_touch(name, atime, mtime): "changes": {"new": name}, } if not os.path.exists(name): - ret["comment"] = "File {} is set to be created".format(name) + ret["comment"] = f"File {name} is set to be created" else: stats = __salt__["file.stats"](name, follow_symlinks=False) if (atime is not None and str(atime) != str(stats["atime"])) or ( mtime is not None and str(mtime) != str(stats["mtime"]) ): - ret["comment"] = "Times set to be updated on file {}".format(name) + ret["comment"] = f"Times set to be updated on file {name}" ret["changes"] = {"touched": name} else: ret["result"] = True - ret["comment"] = "File {} exists and has the correct times".format(name) + ret["comment"] = f"File {name} exists and has the correct times" return ret @@ -972,7 +972,7 @@ def _symlink_check(name, target, force, user, group, win_owner): changes["new"] = name return ( None, - "Symlink {} to {} is set for creation".format(name, target), + f"Symlink {name} to {target} is set for creation", changes, ) if __salt__["file.is_link"](name): @@ -980,12 +980,12 @@ def _symlink_check(name, target, force, user, group, win_owner): changes["change"] = name return ( None, - "Link {} target is set to be changed to {}".format(name, target), + f"Link {name} target is set to be changed to {target}", changes, ) else: result = True - msg = "The symlink {} is present".format(name) + msg = f"The symlink {name} is present" if not _check_symlink_ownership(name, user, group, win_owner): result = None changes["ownership"] = "{}:{}".format(*_get_symlink_ownership(name)) @@ -1035,28 +1035,28 @@ def _hardlink_check(name, target, force): """ changes = {} if not os.path.exists(target): - msg = "Target {} for hard link does not exist".format(target) + msg = f"Target {target} for hard link does not exist" return False, msg, changes elif os.path.isdir(target): - msg = "Unable to hard link from directory {}".format(target) + msg = f"Unable to hard link from directory {target}" return False, msg, changes if os.path.isdir(name): - msg = "Unable to hard link to directory {}".format(name) + msg = f"Unable to hard link to directory {name}" return False, msg, changes elif not os.path.exists(name): - msg = "Hard link {} to {} is set for creation".format(name, target) + msg = f"Hard link {name} to {target} is set for creation" changes["new"] = name return None, msg, changes elif __salt__["file.is_hardlink"](name): if _hardlink_same(name, target): - msg = "The hard link {} is presently targetting {}".format(name, target) + msg = f"The hard link {name} is presently targetting {target}" return True, msg, changes - msg = "Link {} target is set to be changed to {}".format(name, target) + msg = f"Link {name} target is set to be changed to {target}" changes["change"] = name return None, msg, changes @@ -1164,7 +1164,7 @@ def _get_template_texts( return _error(ret, msg) txtl.append("".join(tmplines)) else: - msg = "Failed to load template file {}".format(source) + msg = f"Failed to load template file {source}" log.debug(msg) ret["name"] = source return _error(ret, msg) @@ -1228,7 +1228,7 @@ def _shortcut_check( changes["new"] = name return ( None, - 'Shortcut "{}" to "{}" is set for creation'.format(name, target), + f'Shortcut "{name}" to "{target}" is set for creation', changes, ) @@ -1261,10 +1261,10 @@ def _shortcut_check( ) else: result = True - msg = 'The shortcut "{}" is present'.format(name) + msg = f'The shortcut "{name}" is present' if not _check_shortcut_ownership(name, user): result = None - changes["ownership"] = "{}".format(_get_shortcut_ownership(name)) + changes["ownership"] = f"{_get_shortcut_ownership(name)}" msg += ( ", but the ownership of the shortcut would be changed " "from {1} to {0}".format(user, _get_shortcut_ownership(name)) @@ -1416,20 +1416,16 @@ def hardlink( gid = __salt__["file.group_to_gid"](group) if uid == "": - preflight_errors.append("User {} does not exist".format(user)) + preflight_errors.append(f"User {user} does not exist") if gid == "": - preflight_errors.append("Group {} does not exist".format(group)) + preflight_errors.append(f"Group {group} does not exist") if not os.path.isabs(name): - preflight_errors.append( - "Specified file {} is not an absolute path".format(name) - ) + preflight_errors.append(f"Specified file {name} is not an absolute path") if not os.path.isabs(target): - preflight_errors.append( - "Specified target {} is not an absolute path".format(target) - ) + preflight_errors.append(f"Specified target {target} is not an absolute path") if preflight_errors: msg = ". ".join(preflight_errors) @@ -1448,11 +1444,11 @@ def hardlink( # tracker that complains about not linking the zip builtin. for direction, item in zip_longest(["to", "from"], [name, target]): if os.path.isdir(item): - msg = "Unable to hard link {} directory {}".format(direction, item) + msg = f"Unable to hard link {direction} directory {item}" return _error(ret, msg) if not os.path.exists(target): - msg = "Target {} for hard link does not exist".format(target) + msg = f"Target {target} for hard link does not exist" return _error(ret, msg) # Check that the directory to write the hard link to exists @@ -1480,9 +1476,7 @@ def hardlink( # Otherwise throw an error else: - return _error( - ret, "File exists where the hard link {} should be".format(name) - ) + return _error(ret, f"File exists where the hard link {name} should be") # If the file is a hard link, then we can simply rewrite its target since # nothing is really being lost here. @@ -1514,7 +1508,7 @@ def hardlink( # Good to go ret["result"] = True - ret["comment"] = "Set target of hard link {} -> {}".format(name, target) + ret["comment"] = f"Set target of hard link {name} -> {target}" ret["changes"]["new"] = name # The link is not present, so simply make it @@ -1532,7 +1526,7 @@ def hardlink( # Made a new hard link, things are ok ret["result"] = True - ret["comment"] = "Created new hard link {} -> {}".format(name, target) + ret["comment"] = f"Created new hard link {name} -> {target}" ret["changes"]["new"] = name return ret @@ -1724,7 +1718,7 @@ def symlink( try: salt.utils.win_functions.get_sid_from_name(win_owner) except CommandExecutionError as exc: - preflight_errors.append("User {} does not exist".format(win_owner)) + preflight_errors.append(f"User {win_owner} does not exist") # Make sure users passed in win_perms exist if win_perms: @@ -1732,7 +1726,7 @@ def symlink( try: salt.utils.win_functions.get_sid_from_name(name_check) except CommandExecutionError as exc: - preflight_errors.append("User {} does not exist".format(name_check)) + preflight_errors.append(f"User {name_check} does not exist") # Make sure users passed in win_deny_perms exist if win_deny_perms: @@ -1740,21 +1734,19 @@ def symlink( try: salt.utils.win_functions.get_sid_from_name(name_check) except CommandExecutionError as exc: - preflight_errors.append("User {} does not exist".format(name_check)) + preflight_errors.append(f"User {name_check} does not exist") else: uid = __salt__["file.user_to_uid"](user) gid = __salt__["file.group_to_gid"](group) if uid == "": - preflight_errors.append("User {} does not exist".format(user)) + preflight_errors.append(f"User {user} does not exist") if gid == "": - preflight_errors.append("Group {} does not exist".format(group)) + preflight_errors.append(f"Group {group} does not exist") if not os.path.isabs(name): - preflight_errors.append( - "Specified file {} is not an absolute path".format(name) - ) + preflight_errors.append(f"Specified file {name} is not an absolute path") if preflight_errors: msg = ". ".join(preflight_errors) @@ -1769,7 +1761,7 @@ def symlink( if not os.path.isdir(os.path.dirname(name)): if makedirs: if __opts__["test"]: - tcomment += "\n{} will be created".format(os.path.dirname(name)) + tcomment += f"\n{os.path.dirname(name)} will be created" else: try: _makedirs( @@ -1783,7 +1775,7 @@ def symlink( win_inheritance=win_inheritance, ) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") else: if __opts__["test"]: tcomment += "\nDirectory {} for symlink is not present".format( @@ -1831,7 +1823,7 @@ def symlink( ret["comment"] = "Set ownership of symlink {} to {}:{}".format( name, user, group ) - ret["changes"]["ownership"] = "{}:{}".format(user, group) + ret["changes"]["ownership"] = f"{user}:{group}" else: ret["result"] = False if salt.utils.platform.is_windows(): @@ -1900,7 +1892,7 @@ def symlink( ) return _error( ret, - "{} exists where the symlink {} should be".format(fs_entry_type, name), + f"{fs_entry_type} exists where the symlink {name} should be", ) try: @@ -1912,7 +1904,7 @@ def symlink( ) return ret else: - ret["comment"] = "Created new symlink {} -> {}".format(name, target) + ret["comment"] = f"Created new symlink {name} -> {target}" ret["changes"]["new"] = name if not _check_symlink_ownership(name, user, group, win_owner): @@ -1942,38 +1934,38 @@ def absent(name, **kwargs): if not name: return _error(ret, "Must provide name to file.absent") if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") if name == "/": return _error(ret, 'Refusing to make "/" absent') if os.path.isfile(name) or os.path.islink(name): if __opts__["test"]: ret["result"] = None ret["changes"]["removed"] = name - ret["comment"] = "File {} is set for removal".format(name) + ret["comment"] = f"File {name} is set for removal" return ret try: __salt__["file.remove"](name, force=True) - ret["comment"] = "Removed file {}".format(name) + ret["comment"] = f"Removed file {name}" ret["changes"]["removed"] = name return ret except CommandExecutionError as exc: - return _error(ret, "{}".format(exc)) + return _error(ret, f"{exc}") elif os.path.isdir(name): if __opts__["test"]: ret["result"] = None ret["changes"]["removed"] = name - ret["comment"] = "Directory {} is set for removal".format(name) + ret["comment"] = f"Directory {name} is set for removal" return ret try: __salt__["file.remove"](name, force=True) - ret["comment"] = "Removed directory {}".format(name) + ret["comment"] = f"Removed directory {name}" ret["changes"]["removed"] = name return ret except OSError: - return _error(ret, "Failed to remove directory {}".format(name)) + return _error(ret, f"Failed to remove directory {name}") - ret["comment"] = "File {} is not present".format(name) + ret["comment"] = f"File {name} is not present" return ret @@ -2104,9 +2096,9 @@ def tidied( # Check preconditions if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") if not os.path.isdir(name): - return _error(ret, "{} does not exist or is not a directory.".format(name)) + return _error(ret, f"{name} does not exist or is not a directory.") # Check time_comparison parameter poss_comp = ["atime", "ctime", "mtime"] @@ -2203,7 +2195,7 @@ def tidied( if todelete: if __opts__["test"]: ret["result"] = None - ret["comment"] = "{} is set for tidy".format(name) + ret["comment"] = f"{name} is set for tidy" ret["changes"] = {"removed": todelete} return ret ret["changes"]["removed"] = [] @@ -2213,14 +2205,14 @@ def tidied( __salt__["file.remove"](path) ret["changes"]["removed"].append(path) except CommandExecutionError as exc: - return _error(ret, "{}".format(exc)) + return _error(ret, f"{exc}") # Set comment for the summary ret["comment"] = "Removed {} files or directories from directory {}".format( len(todelete), name ) else: # Set comment in case there was nothing to remove - ret["comment"] = "Nothing to remove from directory {}".format(name) + ret["comment"] = f"Nothing to remove from directory {name}" return ret @@ -2243,9 +2235,9 @@ def exists(name, **kwargs): if not name: return _error(ret, "Must provide name to file.exists") if not os.path.exists(name): - return _error(ret, "Specified path {} does not exist".format(name)) + return _error(ret, f"Specified path {name} does not exist") - ret["comment"] = "Path {} exists".format(name) + ret["comment"] = f"Path {name} exists" return ret @@ -2263,9 +2255,9 @@ def missing(name, **kwargs): if not name: return _error(ret, "Must provide name to file.missing") if os.path.exists(name): - return _error(ret, "Specified path {} exists".format(name)) + return _error(ret, f"Specified path {name} exists") - ret["comment"] = "Path {} is missing".format(name) + ret["comment"] = f"Path {name} is missing" return ret @@ -2994,7 +2986,7 @@ def managed( nextp, __NOT_FOUND, delimiter=contents_delimiter ) if nextc is __NOT_FOUND: - return _error(ret, "Pillar {} does not exist".format(nextp)) + return _error(ret, f"Pillar {nextp} does not exist") list_contents.append(nextc) use_contents = os.linesep.join(list_contents) else: @@ -3002,7 +2994,7 @@ def managed( contents_pillar, __NOT_FOUND, delimiter=contents_delimiter ) if use_contents is __NOT_FOUND: - return _error(ret, "Pillar {} does not exist".format(contents_pillar)) + return _error(ret, f"Pillar {contents_pillar} does not exist") elif contents_grains is not None: if isinstance(contents_grains, list): @@ -3012,7 +3004,7 @@ def managed( nextg, __NOT_FOUND, delimiter=contents_delimiter ) if nextc is __NOT_FOUND: - return _error(ret, "Grain {} does not exist".format(nextc)) + return _error(ret, f"Grain {nextc} does not exist") list_contents.append(nextc) use_contents = os.linesep.join(list_contents) else: @@ -3020,7 +3012,7 @@ def managed( contents_grains, __NOT_FOUND, delimiter=contents_delimiter ) if use_contents is __NOT_FOUND: - return _error(ret, "Grain {} does not exist".format(contents_grains)) + return _error(ret, f"Grain {contents_grains} does not exist") elif contents is not None: use_contents = contents @@ -3031,9 +3023,9 @@ def managed( if use_contents is not None: if not allow_empty and not use_contents: if contents_pillar: - contents_id = "contents_pillar {}".format(contents_pillar) + contents_id = f"contents_pillar {contents_pillar}" elif contents_grains: - contents_id = "contents_grains {}".format(contents_grains) + contents_id = f"contents_grains {contents_grains}" else: contents_id = "'contents'" return _error( @@ -3110,19 +3102,17 @@ def managed( if not create: if not os.path.isfile(name): # Don't create a file that is not already present - ret["comment"] = ( - "File {} is not present and is not set for creation".format(name) - ) + ret["comment"] = f"File {name} is not present and is not set for creation" return ret u_check = _check_user(user, group) if u_check: # The specified user or group do not exist return _error(ret, u_check) if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") if os.path.isdir(name): - ret["comment"] = "Specified target {} is a directory".format(name) + ret["comment"] = f"Specified target {name} is a directory" ret["result"] = False return ret @@ -3173,10 +3163,10 @@ def managed( "state of {}".format(name, mode, ret_perms["lmode"]) ) else: - ret["comment"] = "File {} not updated".format(name) + ret["comment"] = f"File {name} not updated" elif not ret["changes"] and ret["result"]: ret["comment"] = ( - "File {} exists with proper permissions. No changes made.".format(name) + f"File {name} exists with proper permissions. No changes made." ) return ret @@ -3236,7 +3226,7 @@ def managed( ret["changes"] = {} elif ret["changes"]: ret["result"] = None - ret["comment"] = "The file {} is set to be changed".format(name) + ret["comment"] = f"The file {name} is set to be changed" ret["comment"] += ( "\nNote: No changes made, actual changes may\n" "be different due to other states." @@ -3245,7 +3235,7 @@ def managed( ret["changes"]["diff"] = "" else: ret["result"] = True - ret["comment"] = "The file {} is in the correct state".format(name) + ret["comment"] = f"The file {name} is in the correct state" return ret @@ -3253,7 +3243,7 @@ def managed( source, source_hash = __salt__["file.source_list"](source, source_hash, __env__) except CommandExecutionError as exc: ret["result"] = False - ret["comment"] = "Unable to manage file: {}".format(exc) + ret["comment"] = f"Unable to manage file: {exc}" return ret # Gather the source file from the server @@ -3279,7 +3269,7 @@ def managed( except Exception as exc: # pylint: disable=broad-except ret["changes"] = {} log.debug(traceback.format_exc()) - return _error(ret, "Unable to manage file: {}".format(exc)) + return _error(ret, f"Unable to manage file: {exc}") tmp_filename = None @@ -3293,7 +3283,7 @@ def managed( except Exception as exc: # pylint: disable=broad-except return _error( ret, - "Unable to copy file {} to {}: {}".format(name, tmp_filename, exc), + f"Unable to copy file {name} to {tmp_filename}: {exc}", ) try: @@ -3346,7 +3336,7 @@ def managed( sfn = __salt__["cp.is_cached"](source, __env__) if sfn: salt.utils.files.remove(sfn) - return _error(ret, "Unable to check_cmd file: {}".format(exc)) + return _error(ret, f"Unable to check_cmd file: {exc}") # file being updated to verify using check_cmd if ret["changes"]: @@ -3413,7 +3403,7 @@ def managed( except Exception as exc: # pylint: disable=broad-except ret["changes"] = {} log.debug(traceback.format_exc()) - return _error(ret, "Unable to manage file: {}".format(exc)) + return _error(ret, f"Unable to manage file: {exc}") finally: if tmp_filename: salt.utils.files.remove(tmp_filename) @@ -3450,7 +3440,7 @@ def _get_recurse_set(recurse): if recurse_set is None or not set(_RECURSE_TYPES) >= recurse_set: raise ValueError( 'Types for "recurse" limited to {}.'.format( - ", ".join('"{}"'.format(rtype) for rtype in _RECURSE_TYPES) + ", ".join(f'"{rtype}"' for rtype in _RECURSE_TYPES) ) ) if "ignore_files" in recurse_set and "ignore_dirs" in recurse_set: @@ -3883,7 +3873,7 @@ def directory( # Must be an absolute path if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") # Check for existing file or symlink if ( @@ -3927,13 +3917,9 @@ def directory( ret["changes"]["forced"] = "Directory was forcibly replaced" else: if os.path.isfile(name): - return _error( - ret, "Specified location {} exists and is a file".format(name) - ) + return _error(ret, f"Specified location {name} exists and is a file") elif os.path.islink(name): - return _error( - ret, "Specified location {} exists and is a symlink".format(name) - ) + return _error(ret, f"Specified location {name} exists and is a symlink") # Check directory? if salt.utils.platform.is_windows(): @@ -3995,9 +3981,9 @@ def directory( win_inheritance=win_inheritance, ) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") else: - return _error(ret, "No directory to create {} in".format(name)) + return _error(ret, f"No directory to create {name} in") if salt.utils.platform.is_windows(): __salt__["file.mkdir"]( @@ -4012,7 +3998,7 @@ def directory( __salt__["file.mkdir"](name, user=user, group=group, mode=dir_mode) if not os.path.isdir(name): - return _error(ret, "Failed to create directory {}".format(name)) + return _error(ret, f"Failed to create directory {name}") ret["changes"][name] = {"directory": "new"} return ret @@ -4050,7 +4036,7 @@ def directory( recurse_set = _get_recurse_set(recurse) except (TypeError, ValueError) as exc: ret["result"] = False - ret["comment"] = "{}".format(exc) + ret["comment"] = f"{exc}" # NOTE: Should this be enough to stop the whole check altogether? if recurse_set: if "user" in recurse_set: @@ -4082,7 +4068,7 @@ def directory( if isinstance(gid, str): ret["result"] = False ret["comment"] = ( - "Failed to enforce group ownership for group {}".format(group) + f"Failed to enforce group ownership for group {group}" ) else: ret["result"] = False @@ -4155,24 +4141,24 @@ def directory( removed = _clean_dir(name, list(keep), exclude_pat) if removed: ret["changes"]["removed"] = removed - ret["comment"] = "Files cleaned from directory {}".format(name) + ret["comment"] = f"Files cleaned from directory {name}" # issue 32707: reflect children_only selection in comments if not ret["comment"]: if children_only: - ret["comment"] = "Directory {}/* updated".format(name) + ret["comment"] = f"Directory {name}/* updated" else: if ret["changes"]: - ret["comment"] = "Directory {} updated".format(name) + ret["comment"] = f"Directory {name} updated" if __opts__["test"]: - ret["comment"] = "Directory {} not updated".format(name) + ret["comment"] = f"Directory {name} not updated" elif not ret["changes"] and ret["result"]: orig_comment = None if ret["comment"]: orig_comment = ret["comment"] - ret["comment"] = "Directory {} is in the correct state".format(name) + ret["comment"] = f"Directory {name} is in the correct state" if orig_comment: ret["comment"] = "\n".join([ret["comment"], orig_comment]) @@ -4180,7 +4166,7 @@ def directory( ret["result"] = False ret["comment"] += "\n\nThe following errors were encountered:\n" for error in errors: - ret["comment"] += "\n- {}".format(error) + ret["comment"] += f"\n- {error}" return ret @@ -4472,7 +4458,7 @@ def recurse( # The specified user or group do not exist return _error(ret, u_check) if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") # expand source into source_list source_list = _validate_str_list(source) @@ -4484,7 +4470,7 @@ def recurse( if not precheck.startswith("salt://"): return _error( ret, - "Invalid source '{}' (must be a salt:// URI)".format(precheck), + f"Invalid source '{precheck}' (must be a salt:// URI)", ) # Select the first source in source_list that exists @@ -4492,7 +4478,7 @@ def recurse( source, source_hash = __salt__["file.source_list"](source_list, "", __env__) except CommandExecutionError as exc: ret["result"] = False - ret["comment"] = "Recurse failed: {}".format(exc) + ret["comment"] = f"Recurse failed: {exc}" return ret # Check source path relative to fileserver root, make sure it is a @@ -4513,7 +4499,7 @@ def recurse( if not os.path.isdir(name): if os.path.exists(name): # it is not a dir, but it exists - fail out - return _error(ret, "The path {} exists and is not a directory".format(name)) + return _error(ret, f"The path {name} exists and is not a directory") if not __opts__["test"]: if salt.utils.platform.is_windows(): win_owner = win_owner if win_owner else user @@ -4552,7 +4538,7 @@ def recurse( if clean and os.path.exists(path) and os.path.isdir(path) and replace: _ret = {"name": name, "changes": {}, "result": True, "comment": ""} if __opts__["test"]: - _ret["comment"] = "Replacing directory {} with a file".format(path) + _ret["comment"] = f"Replacing directory {path} with a file" _ret["result"] = None merge_ret(path, _ret) return @@ -4592,7 +4578,7 @@ def recurse( if clean and os.path.exists(path) and not os.path.isdir(path): _ret = {"name": name, "changes": {}, "result": True, "comment": ""} if __opts__["test"]: - _ret["comment"] = "Replacing {} with a directory".format(path) + _ret["comment"] = f"Replacing {path} with a directory" _ret["result"] = None merge_ret(path, _ret) return @@ -4656,10 +4642,10 @@ def recurse( ).strip() if not ret["comment"]: - ret["comment"] = "Recursively updated {}".format(name) + ret["comment"] = f"Recursively updated {name}" if not ret["changes"] and ret["result"]: - ret["comment"] = "The directory {} is in the correct state".format(name) + ret["comment"] = f"The directory {name} is in the correct state" return ret @@ -5188,7 +5174,7 @@ def line( if mode not in modeswithemptycontent and content is None: return _error( ret, - "Content can only be empty if mode is {}".format(modeswithemptycontent), + f"Content can only be empty if mode is {modeswithemptycontent}", ) del modeswithemptycontent @@ -5584,7 +5570,7 @@ def keyvalue( with salt.utils.files.fopen(name, "r") as fd: file_contents = fd.readlines() except OSError: - ret["comment"] = "unable to open {n}".format(n=name) + ret["comment"] = f"unable to open {name}" ret["result"] = True if ignore_if_missing else False return ret @@ -5673,7 +5659,7 @@ def keyvalue( # the old line always needs to go, so that will be # reflected in the diff (this is the original line from # the file being read) - diff.append("- {}".format(line)) + diff.append(f"- {line}") line = line[:0] # any non-zero value means something needs to go back in @@ -5696,7 +5682,7 @@ def keyvalue( ) ) else: - diff.append("+ {}".format(line)) + diff.append(f"+ {line}") changes += 1 # subtract one from the count if it was larger than 0, so # next lines are removed. if it is less than 0 then count is @@ -5721,7 +5707,7 @@ def keyvalue( for key, value in key_values.items(): if diff_count[key] > 0: line = tmpl.format(key=key, sep=separator, value=value) - tmpdiff.append("+ {}".format(line)) + tmpdiff.append(f"+ {line}") content.append(line) changes += 1 if tmpdiff: @@ -5739,7 +5725,7 @@ def keyvalue( if not did_diff: diff.insert(0, " " + os.linesep) did_diff = True - diff.insert(1, "+ {}".format(line)) + diff.insert(1, f"+ {line}") content.insert(0, line) changes += 1 @@ -5765,7 +5751,7 @@ def keyvalue( # otherwise return the actual diff lines else: - ret["comment"] = "Changed {c} lines".format(c=changes) + ret["comment"] = f"Changed {changes} lines" if show_changes: ret["changes"]["diff"] = "".join(diff) else: @@ -5781,7 +5767,7 @@ def keyvalue( fd.close() except OSError: # return an error if the file was not writable - ret["comment"] = "{n} not writable".format(n=name) + ret["comment"] = f"{name} not writable" ret["result"] = False return ret # if all went well, then set result to true @@ -6086,7 +6072,7 @@ def blockreplace( except Exception as exc: # pylint: disable=broad-except log.exception("Encountered error managing block") ret["comment"] = ( - "Encountered error managing block: {}. See the log for details.".format(exc) + f"Encountered error managing block: {exc}. See the log for details." ) return ret @@ -6177,11 +6163,11 @@ def comment(name, regex, char="#", backup=".bak", ignore_missing=False): ret["result"] = True return ret else: - return _error(ret, "{}: Pattern not found".format(unanchor_regex)) + return _error(ret, f"{unanchor_regex}: Pattern not found") if __opts__["test"]: ret["changes"][name] = "updated" - ret["comment"] = "File {} is set to be updated".format(name) + ret["comment"] = f"File {name} is set to be updated" ret["result"] = None return ret @@ -6275,11 +6261,11 @@ def uncomment(name, regex, char="#", backup=".bak"): ret["result"] = True return ret else: - return _error(ret, "{}: Pattern not found".format(regex)) + return _error(ret, f"{regex}: Pattern not found") if __opts__["test"]: ret["changes"][name] = "updated" - ret["comment"] = "File {} is set to be updated".format(name) + ret["comment"] = f"File {name} is set to be updated" ret["result"] = None return ret @@ -6482,14 +6468,14 @@ def append( if makedirs is True: dirname = os.path.dirname(name) if __opts__["test"]: - ret["comment"] = "Directory {} is set to be updated".format(dirname) + ret["comment"] = f"Directory {dirname} is set to be updated" ret["result"] = None else: if not __salt__["file.directory_exists"](dirname): try: _makedirs(name=name) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") check_res, check_msg, check_changes = ( _check_directory_win(dirname) @@ -6541,13 +6527,13 @@ def append( continue for line_item in chunk.splitlines(): - append_lines.append("{}".format(line_item)) + append_lines.append(f"{line_item}") except TypeError: return _error(ret, "No text found to append. Nothing appended") if __opts__["test"]: - ret["comment"] = "File {} is set to be updated".format(name) + ret["comment"] = f"File {name} is set to be updated" ret["result"] = None nlines = list(slines) nlines.extend(append_lines) @@ -6558,15 +6544,15 @@ def append( # Changes happened, add them ret["changes"]["diff"] = "\n".join(difflib.unified_diff(slines, nlines)) else: - ret["comment"] = "File {} is in correct state".format(name) + ret["comment"] = f"File {name} is in correct state" ret["result"] = True return ret if append_lines: __salt__["file.append"](name, args=append_lines) - ret["comment"] = "Appended {} lines".format(len(append_lines)) + ret["comment"] = f"Appended {len(append_lines)} lines" else: - ret["comment"] = "File {} is in correct state".format(name) + ret["comment"] = f"File {name} is in correct state" with salt.utils.files.fopen(name, "rb") as fp_: nlines = fp_.read() @@ -6767,14 +6753,14 @@ def prepend( if makedirs is True: dirname = os.path.dirname(name) if __opts__["test"]: - ret["comment"] = "Directory {} is set to be updated".format(dirname) + ret["comment"] = f"Directory {dirname} is set to be updated" ret["result"] = None else: if not __salt__["file.directory_exists"](dirname): try: _makedirs(name=name) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") check_res, check_msg, check_changes = ( _check_directory_win(dirname) @@ -6831,9 +6817,9 @@ def prepend( for line in lines: if __opts__["test"]: - ret["comment"] = "File {} is set to be updated".format(name) + ret["comment"] = f"File {name} is set to be updated" ret["result"] = None - test_lines.append("{}\n".format(line)) + test_lines.append(f"{line}\n") else: preface.append(line) count += 1 @@ -6848,7 +6834,7 @@ def prepend( ret["changes"]["diff"] = "".join(difflib.unified_diff(slines, nlines)) ret["result"] = None else: - ret["comment"] = "File {} is in correct state".format(name) + ret["comment"] = f"File {name} is in correct state" ret["result"] = True return ret @@ -6887,9 +6873,9 @@ def prepend( ret["changes"]["diff"] = "".join(difflib.unified_diff(slines, nlines)) if count: - ret["comment"] = "Prepended {} lines".format(count) + ret["comment"] = f"Prepended {count} lines" else: - ret["comment"] = "File {} is in correct state".format(name) + ret["comment"] = f"File {name} is in correct state" ret["result"] = True return ret @@ -7048,14 +7034,14 @@ def patch( try: name = os.path.expanduser(name) except Exception: # pylint: disable=broad-except - ret["comment"] = "Invalid path '{}'".format(name) + ret["comment"] = f"Invalid path '{name}'" return ret else: if not os.path.isabs(name): - ret["comment"] = "{} is not an absolute path".format(name) + ret["comment"] = f"{name} is not an absolute path" return ret elif not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" return ret else: is_dir = os.path.isdir(name) @@ -7072,11 +7058,11 @@ def patch( try: reject_file_parent = os.path.dirname(reject_file) except Exception: # pylint: disable=broad-except - ret["comment"] = "Invalid path '{}' for reject_file".format(reject_file) + ret["comment"] = f"Invalid path '{reject_file}' for reject_file" return ret else: if not os.path.isabs(reject_file_parent): - ret["comment"] = "'{}' is not an absolute path".format(reject_file) + ret["comment"] = f"'{reject_file}' is not an absolute path" return ret elif not os.path.isdir(reject_file_parent): ret["comment"] = ( @@ -7176,7 +7162,7 @@ def patch( "included in the source URL." ) else: - source_match += "?saltenv={}".format(saltenv) + source_match += f"?saltenv={saltenv}" cleanup = [] @@ -7249,7 +7235,7 @@ def patch( # then remove. patch_opts = ["-N", "-r", patch_rejects, "-o", patch_output] if is_dir and strip is not None: - patch_opts.append("-p{}".format(strip)) + patch_opts.append(f"-p{strip}") pre_check = _patch(patch_file, patch_opts) if pre_check["retcode"] != 0: @@ -7300,7 +7286,7 @@ def patch( # If we've made it here, the patch should apply cleanly patch_opts = [] if is_dir and strip is not None: - patch_opts.append("-p{}".format(strip)) + patch_opts.append(f"-p{strip}") ret["changes"] = _patch(patch_file, patch_opts) if ret["changes"]["retcode"] == 0: @@ -7365,7 +7351,7 @@ def touch(name, atime=None, mtime=None, makedirs=False): if not name: return _error(ret, "Must provide name to file.touch") if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") if __opts__["test"]: ret.update(_check_touch(name, atime, mtime)) @@ -7375,15 +7361,15 @@ def touch(name, atime=None, mtime=None, makedirs=False): try: _makedirs(name=name) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") if not os.path.isdir(os.path.dirname(name)): - return _error(ret, "Directory not present to touch file {}".format(name)) + return _error(ret, f"Directory not present to touch file {name}") extant = os.path.exists(name) ret["result"] = __salt__["file.touch"](name, atime, mtime) if not extant and ret["result"]: - ret["comment"] = "Created empty file {}".format(name) + ret["comment"] = f"Created empty file {name}" ret["changes"]["new"] = name elif extant and ret["result"]: ret["comment"] = "Updated times on {} {}".format( @@ -7500,7 +7486,7 @@ def copy_( ret = { "name": name, "changes": {}, - "comment": 'Copied "{}" to "{}"'.format(source, name), + "comment": f'Copied "{source}" to "{name}"', "result": True, } if not name: @@ -7508,10 +7494,10 @@ def copy_( changed = True if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") if not os.path.exists(source): - return _error(ret, 'Source file "{}" is not present'.format(source)) + return _error(ret, f'Source file "{source}" is not present') if preserve: user = __salt__["file.get_user"](source) @@ -7570,7 +7556,7 @@ def copy_( except OSError: return _error( ret, - 'Failed to delete "{}" in preparation for forced move'.format(name), + f'Failed to delete "{name}" in preparation for forced move', ) if __opts__["test"]: @@ -7581,15 +7567,13 @@ def copy_( ret["result"] = None else: ret["comment"] = ( - 'The target file "{}" exists and will not be overwritten'.format(name) + f'The target file "{name}" exists and will not be overwritten' ) ret["result"] = True return ret if not changed: - ret["comment"] = ( - 'The target file "{}" exists and will not be overwritten'.format(name) - ) + ret["comment"] = f'The target file "{name}" exists and will not be overwritten' ret["result"] = True return ret @@ -7610,9 +7594,9 @@ def copy_( try: _makedirs(name=name, user=user, group=group, dir_mode=dir_mode) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") else: - return _error(ret, "The target directory {} is not present".format(dname)) + return _error(ret, f"The target directory {dname} is not present") # All tests pass, move the file into place try: if os.path.isdir(source): @@ -7640,7 +7624,7 @@ def copy_( ret["result"] = check_ret["result"] ret["comment"] = check_ret["comment"] except OSError: - return _error(ret, 'Failed to copy "{}" to "{}"'.format(source, name)) + return _error(ret, f'Failed to copy "{source}" to "{name}"') return ret @@ -7674,7 +7658,7 @@ def rename(name, source, force=False, makedirs=False, **kwargs): return _error(ret, "Must provide name to file.rename") if not os.path.isabs(name): - return _error(ret, "Specified file {} is not an absolute path".format(name)) + return _error(ret, f"Specified file {name} is not an absolute path") if not os.path.lexists(source): ret["comment"] = 'Source file "{}" has already been moved out of place'.format( @@ -7685,7 +7669,7 @@ def rename(name, source, force=False, makedirs=False, **kwargs): if os.path.lexists(source) and os.path.lexists(name): if not force: ret["comment"] = ( - 'The target file "{}" exists and will not be overwritten'.format(name) + f'The target file "{name}" exists and will not be overwritten' ) return ret elif not __opts__["test"]: @@ -7695,11 +7679,11 @@ def rename(name, source, force=False, makedirs=False, **kwargs): except OSError: return _error( ret, - 'Failed to delete "{}" in preparation for forced move'.format(name), + f'Failed to delete "{name}" in preparation for forced move', ) if __opts__["test"]: - ret["comment"] = 'File "{}" is set to be moved to "{}"'.format(source, name) + ret["comment"] = f'File "{source}" is set to be moved to "{name}"' ret["result"] = None return ret @@ -7710,9 +7694,9 @@ def rename(name, source, force=False, makedirs=False, **kwargs): try: _makedirs(name=name) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") else: - return _error(ret, "The target directory {} is not present".format(dname)) + return _error(ret, f"The target directory {dname} is not present") # All tests pass, move the file into place try: if os.path.islink(source): @@ -7722,9 +7706,9 @@ def rename(name, source, force=False, makedirs=False, **kwargs): else: shutil.move(source, name) except OSError: - return _error(ret, 'Failed to move "{}" to "{}"'.format(source, name)) + return _error(ret, f'Failed to move "{source}" to "{name}"') - ret["comment"] = 'Moved "{}" to "{}"'.format(source, name) + ret["comment"] = f'Moved "{source}" to "{name}"' ret["changes"] = {name: source} return ret @@ -8054,9 +8038,7 @@ def serialize( if not create: if not os.path.isfile(name): # Don't create a file that is not already present - ret["comment"] = ( - "File {} is not present and is not set for creation".format(name) - ) + ret["comment"] = f"File {name} is not present and is not set for creation" return ret formatter = kwargs.pop("formatter", None) @@ -8082,8 +8064,8 @@ def serialize( ) group = user - serializer_name = "{}.serialize".format(serializer) - deserializer_name = "{}.deserialize".format(serializer) + serializer_name = f"{serializer}.serialize" + deserializer_name = f"{serializer}.deserialize" if serializer_name not in __serializers__: return { @@ -8141,7 +8123,7 @@ def serialize( ) if existing_data == merged_data: ret["result"] = True - ret["comment"] = "The file {} is in the correct state".format(name) + ret["comment"] = f"The file {name} is in the correct state" return ret dataset = merged_data else: @@ -8196,7 +8178,7 @@ def serialize( ret["changes"]["diff"] = "" else: ret["result"] = True - ret["comment"] = "The file {} is in the correct state".format(name) + ret["comment"] = f"The file {name} is in the correct state" else: ret = __salt__["file.manage_file"]( name=name, @@ -8313,7 +8295,7 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): # Check if it is a character device elif not __salt__["file.is_chrdev"](name): if __opts__["test"]: - ret["comment"] = "Character device {} is set to be created".format(name) + ret["comment"] = f"Character device {name} is set to be created" ret["result"] = None else: ret = __salt__["file.mknod"]( @@ -8334,9 +8316,7 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): else: ret = __salt__["file.check_perms"](name, None, user, group, mode)[0] if not ret["changes"]: - ret["comment"] = ( - "Character device {} is in the correct state".format(name) - ) + ret["comment"] = f"Character device {name} is in the correct state" elif ntype == "b": # Check for file existence @@ -8350,7 +8330,7 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): # Check if it is a block device elif not __salt__["file.is_blkdev"](name): if __opts__["test"]: - ret["comment"] = "Block device {} is set to be created".format(name) + ret["comment"] = f"Block device {name} is set to be created" ret["result"] = None else: ret = __salt__["file.mknod"]( @@ -8385,7 +8365,7 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): # Check if it is a fifo elif not __salt__["file.is_fifo"](name): if __opts__["test"]: - ret["comment"] = "Fifo pipe {} is set to be created".format(name) + ret["comment"] = f"Fifo pipe {name} is set to be created" ret["result"] = None else: ret = __salt__["file.mknod"]( @@ -8396,7 +8376,7 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): else: ret = __salt__["file.check_perms"](name, None, user, group, mode)[0] if not ret["changes"]: - ret["comment"] = "Fifo pipe {} is in the correct state".format(name) + ret["comment"] = f"Fifo pipe {name} is in the correct state" else: ret["comment"] = ( @@ -8416,7 +8396,7 @@ def mod_run_check_cmd(cmd, filename, **check_cmd_opts): """ log.debug("running our check_cmd") - _cmd = "{} {}".format(cmd, filename) + _cmd = f"{cmd} {filename}" cret = __salt__["cmd.run_all"](_cmd, **check_cmd_opts) if cret["retcode"] != 0: ret = { @@ -8659,12 +8639,10 @@ def shortcut( uid = __salt__["file.user_to_uid"](user) if uid == "": - preflight_errors.append("User {} does not exist".format(user)) + preflight_errors.append(f"User {user} does not exist") if not os.path.isabs(name): - preflight_errors.append( - "Specified file {} is not an absolute path".format(name) - ) + preflight_errors.append(f"Specified file {name} is not an absolute path") if preflight_errors: msg = ". ".join(preflight_errors) @@ -8686,7 +8664,7 @@ def shortcut( try: _makedirs(name=name, user=user) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") else: return _error( ret, @@ -8715,7 +8693,7 @@ def shortcut( try: _makedirs(name=backupname) except CommandExecutionError as exc: - return _error(ret, "Drive {} is not mapped".format(exc.message)) + return _error(ret, f"Drive {exc.message} is not mapped") else: return _error( ret, @@ -8773,7 +8751,7 @@ def shortcut( ret["comment"] = "Set ownership of shortcut {} to {}".format( name, user ) - ret["changes"]["ownership"] = "{}".format(user) + ret["changes"]["ownership"] = f"{user}" else: ret["result"] = False ret[ @@ -8803,7 +8781,7 @@ def shortcut( ) return ret else: - ret["comment"] = "Created new shortcut {} -> {}".format(name, target) + ret["comment"] = f"Created new shortcut {name} -> {target}" ret["changes"]["new"] = name if not _check_shortcut_ownership(name, user): @@ -8971,15 +8949,13 @@ def cached( if source_sum: hash = __salt__["file.get_hash"](local_copy, __opts__["hash_type"]) if hash == source_sum["hsum"]: - ret["comment"] = "File already cached: {}".format(name) + ret["comment"] = f"File already cached: {name}" else: - ret["comment"] = ( - "Hashes don't match.\nFile will be cached: {}".format(name) - ) + ret["comment"] = f"Hashes don't match.\nFile will be cached: {name}" else: - ret["comment"] = "No hash found. File will be cached: {}".format(name) + ret["comment"] = f"No hash found. File will be cached: {name}" else: - ret["comment"] = "File will be cached: {}".format(name) + ret["comment"] = f"File will be cached: {name}" ret["changes"] = {} ret["result"] = None return ret @@ -9010,10 +8986,10 @@ def cached( return ret else: ret["result"] = True - ret["comment"] = "File {} is present on the minion".format(full_path) + ret["comment"] = f"File {full_path} is present on the minion" return ret else: - ret["comment"] = "File {} is not present on the minion".format(full_path) + ret["comment"] = f"File {full_path} is not present on the minion" return ret local_copy = __salt__["cp.is_cached"](name, saltenv=saltenv) @@ -9091,7 +9067,7 @@ def cached( # We're not enforcing a hash, and we already know that the file was # successfully cached, so we know the state was successful. ret["result"] = True - ret["comment"] = "File is cached to {}".format(local_copy) + ret["comment"] = f"File is cached to {local_copy}" return ret @@ -9139,14 +9115,14 @@ def not_cached(name, saltenv="base"): try: os.remove(local_copy) except Exception as exc: # pylint: disable=broad-except - ret["comment"] = "Failed to delete {}: {}".format(local_copy, exc) + ret["comment"] = f"Failed to delete {local_copy}: {exc}" else: ret["result"] = True ret["changes"]["deleted"] = True - ret["comment"] = "{} was deleted".format(local_copy) + ret["comment"] = f"{local_copy} was deleted" else: ret["result"] = True - ret["comment"] = "{} is not cached".format(name) + ret["comment"] = f"{name} is not cached" return ret @@ -9177,7 +9153,7 @@ def mod_beacon(name, **kwargs): data["recurse"] = _beacon_data.get("recurse", True) data["exclude"] = _beacon_data.get("exclude", []) - beacon_name = "beacon_{}_{}".format(beacon_module, name) + beacon_name = f"beacon_{beacon_module}_{name}" beacon_kwargs = { "name": beacon_name, "files": {name: data}, @@ -9246,7 +9222,7 @@ def pruned(name, recurse=False, ignore_errors=False, older_than=None): if __opts__["test"]: ret["result"] = None ret["changes"]["deleted"] = name - ret["comment"] = "Directory {} is set for removal".format(name) + ret["comment"] = f"Directory {name} is set for removal" return ret res = __salt__["file.rmdir"]( @@ -9256,12 +9232,10 @@ def pruned(name, recurse=False, ignore_errors=False, older_than=None): if result: if recurse and res["deleted"]: - ret["comment"] = ( - "Recursively removed empty directories under {}".format(name) - ) + ret["comment"] = f"Recursively removed empty directories under {name}" ret["changes"]["deleted"] = sorted(res["deleted"]) elif not recurse: - ret["comment"] = "Removed directory {}".format(name) + ret["comment"] = f"Removed directory {name}" ret["changes"]["deleted"] = name return ret elif ignore_errors and res["deleted"]: @@ -9273,8 +9247,8 @@ def pruned(name, recurse=False, ignore_errors=False, older_than=None): ret["result"] = result ret["changes"] = res - ret["comment"] = "Failed to remove directory {}".format(name) + ret["comment"] = f"Failed to remove directory {name}" return ret - ret["comment"] = "Directory {} is not present".format(name) + ret["comment"] = f"Directory {name} is not present" return ret diff --git a/salt/states/firewalld.py b/salt/states/firewalld.py index 2e090326ebc..ac299bcdbe5 100644 --- a/salt/states/firewalld.py +++ b/salt/states/firewalld.py @@ -302,7 +302,7 @@ def service(name, ports=None, protocols=None): try: _current_ports = __salt__["firewalld.get_service_ports"](name) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_ports = set(ports) - set(_current_ports) @@ -313,7 +313,7 @@ def service(name, ports=None, protocols=None): try: __salt__["firewalld.add_service_port"](name, port) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret for port in old_ports: @@ -321,7 +321,7 @@ def service(name, ports=None, protocols=None): try: __salt__["firewalld.remove_service_port"](name, port) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_ports or old_ports: @@ -332,7 +332,7 @@ def service(name, ports=None, protocols=None): try: _current_protocols = __salt__["firewalld.get_service_protocols"](name) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_protocols = set(protocols) - set(_current_protocols) @@ -343,7 +343,7 @@ def service(name, ports=None, protocols=None): try: __salt__["firewalld.add_service_protocol"](name, protocol) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret for protocol in old_protocols: @@ -351,7 +351,7 @@ def service(name, ports=None, protocols=None): try: __salt__["firewalld.remove_service_protocol"](name, protocol) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_protocols or old_protocols: @@ -364,15 +364,15 @@ def service(name, ports=None, protocols=None): ret["result"] = True if ret["changes"] == {}: - ret["comment"] = "'{}' is already in the desired state.".format(name) + ret["comment"] = f"'{name}' is already in the desired state." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Configuration for '{}' will change.".format(name) + ret["comment"] = f"Configuration for '{name}' will change." return ret - ret["comment"] = "'{}' was configured.".format(name) + ret["comment"] = f"'{name}' was configured." return ret @@ -405,7 +405,7 @@ def _present( try: zones = __salt__["firewalld.get_zones"](permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if name not in zones: @@ -413,7 +413,7 @@ def _present( try: __salt__["firewalld.new_zone"](name) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({name: {"old": zones, "new": name}}) @@ -428,14 +428,14 @@ def _present( name, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if block_icmp: try: _valid_icmp_types = __salt__["firewalld.get_icmp_types"](permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret # log errors for invalid ICMP types in block_icmp input @@ -451,7 +451,7 @@ def _present( name, icmp_type, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_block_icmp: @@ -466,7 +466,7 @@ def _present( name, icmp_type, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_icmp_types or old_icmp_types: @@ -484,21 +484,21 @@ def _present( try: default_zone = __salt__["firewalld.default_zone"]() except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if name != default_zone: if not __opts__["test"]: try: __salt__["firewalld.set_default_zone"](name) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"default": {"old": default_zone, "new": name}}) try: masquerade_ret = __salt__["firewalld.get_masquerade"](name, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if masquerade and not masquerade_ret: @@ -506,7 +506,7 @@ def _present( try: __salt__["firewalld.add_masquerade"](name, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update( {"masquerade": {"old": "", "new": "Masquerading successfully set."}} @@ -516,7 +516,7 @@ def _present( try: __salt__["firewalld.remove_masquerade"](name, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update( {"masquerade": {"old": "", "new": "Masquerading successfully disabled."}} @@ -527,7 +527,7 @@ def _present( try: _current_ports = __salt__["firewalld.list_ports"](name, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_ports = set(ports) - set(_current_ports) @@ -540,7 +540,7 @@ def _present( name, port, permanent=True, force_masquerade=False ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_ports: @@ -550,7 +550,7 @@ def _present( try: __salt__["firewalld.remove_port"](name, port, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_ports or old_ports: @@ -567,7 +567,7 @@ def _present( name, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret port_fwd = [_parse_forward(fwd) for fwd in port_fwd] @@ -597,7 +597,7 @@ def _present( force_masquerade=False, ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_port_fwd: @@ -614,7 +614,7 @@ def _present( permanent=True, ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_port_fwd or old_port_fwd: @@ -638,7 +638,7 @@ def _present( name, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_services = set(services) - set(_current_services) @@ -649,7 +649,7 @@ def _present( try: __salt__["firewalld.add_service"](new_service, name, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_services: @@ -661,7 +661,7 @@ def _present( old_service, name, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_services or old_services: @@ -680,7 +680,7 @@ def _present( name, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_interfaces = set(interfaces) - set(_current_interfaces) @@ -691,7 +691,7 @@ def _present( try: __salt__["firewalld.add_interface"](name, interface, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_interfaces: @@ -703,7 +703,7 @@ def _present( name, interface, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_interfaces or old_interfaces: @@ -720,7 +720,7 @@ def _present( try: _current_sources = __salt__["firewalld.get_sources"](name, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_sources = set(sources) - set(_current_sources) @@ -731,7 +731,7 @@ def _present( try: __salt__["firewalld.add_source"](name, source, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_sources: @@ -743,7 +743,7 @@ def _present( name, source, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_sources or old_sources: @@ -762,7 +762,7 @@ def _present( name, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_rich_rules = set(rich_rules) - set(_current_rich_rules) @@ -773,7 +773,7 @@ def _present( try: __salt__["firewalld.add_rich_rule"](name, rich_rule, permanent=True) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if prune_rich_rules: @@ -785,7 +785,7 @@ def _present( name, rich_rule, permanent=True ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if new_rich_rules or old_rich_rules: @@ -800,7 +800,7 @@ def _present( # No changes if ret["changes"] == {}: ret["result"] = True - ret["comment"] = "'{}' is already in the desired state.".format(name) + ret["comment"] = f"'{name}' is already in the desired state." return ret # test=True and changes predicted @@ -809,7 +809,7 @@ def _present( # build comment string nested.__opts__ = __opts__ comment = [] - comment.append("Configuration for '{}' will change:".format(name)) + comment.append(f"Configuration for '{name}' will change:") comment.append(nested.output(ret["changes"]).rstrip()) ret["comment"] = "\n".join(comment) ret["changes"] = {} @@ -817,5 +817,5 @@ def _present( # Changes were made successfully ret["result"] = True - ret["comment"] = "'{}' was configured.".format(name) + ret["comment"] = f"'{name}' was configured." return ret diff --git a/salt/states/gem.py b/salt/states/gem.py index e5a1ab26b8b..66477e60cff 100644 --- a/salt/states/gem.py +++ b/salt/states/gem.py @@ -118,7 +118,7 @@ def installed( return ret if __opts__["test"]: - ret["comment"] = "The gem {} would have been installed".format(name) + ret["comment"] = f"The gem {name} would have been installed" return ret if __salt__["gem.install"]( name, @@ -169,7 +169,7 @@ def removed(name, ruby=None, user=None, gem_bin=None): return ret if __opts__["test"]: - ret["comment"] = "The gem {} would have been removed".format(name) + ret["comment"] = f"The gem {name} would have been removed" return ret if __salt__["gem.uninstall"](name, ruby, gem_bin=gem_bin, runas=user): ret["result"] = True @@ -203,7 +203,7 @@ def sources_add(name, ruby=None, user=None): ret["comment"] = "Gem source is already added." return ret if __opts__["test"]: - ret["comment"] = "The gem source {} would have been added.".format(name) + ret["comment"] = f"The gem source {name} would have been added." return ret if __salt__["gem.sources_add"](source_uri=name, ruby=ruby, runas=user): ret["result"] = True diff --git a/salt/states/github.py b/salt/states/github.py index b1d3e480f2b..e632cf679a5 100644 --- a/salt/states/github.py +++ b/salt/states/github.py @@ -55,15 +55,15 @@ def present(name, profile="github", **kwargs): # If the user has a valid github handle and is not in the org already if not target: ret["result"] = False - ret["comment"] = "Couldnt find user {}".format(name) + ret["comment"] = f"Couldnt find user {name}" elif isinstance(target, bool) and target: - ret["comment"] = "User {} is already in the org ".format(name) + ret["comment"] = f"User {name} is already in the org " ret["result"] = True elif ( not target.get("in_org", False) and target.get("membership_state") != "pending" ): if __opts__["test"]: - ret["comment"] = "User {} will be added to the org".format(name) + ret["comment"] = f"User {name} will be added to the org" return ret # add the user @@ -71,15 +71,13 @@ def present(name, profile="github", **kwargs): if result: ret["changes"].setdefault("old", None) - ret["changes"].setdefault( - "new", "User {} exists in the org now".format(name) - ) + ret["changes"].setdefault("new", f"User {name} exists in the org now") ret["result"] = True else: ret["result"] = False - ret["comment"] = "Failed to add user {} to the org".format(name) + ret["comment"] = f"Failed to add user {name} to the org" else: - ret["comment"] = "User {} has already been invited.".format(name) + ret["comment"] = f"User {name} has already been invited." ret["result"] = True return ret @@ -110,7 +108,7 @@ def absent(name, profile="github", **kwargs): "name": name, "changes": {}, "result": None, - "comment": "User {} is absent.".format(name), + "comment": f"User {name} is absent.", } target = __salt__["github.get_user"](name, profile=profile, **kwargs) @@ -118,25 +116,25 @@ def absent(name, profile="github", **kwargs): if target: if isinstance(target, bool) or target.get("in_org", False): if __opts__["test"]: - ret["comment"] = "User {} will be deleted".format(name) + ret["comment"] = f"User {name} will be deleted" ret["result"] = None return ret result = __salt__["github.remove_user"](name, profile=profile, **kwargs) if result: - ret["comment"] = "Deleted user {}".format(name) - ret["changes"].setdefault("old", "User {} exists".format(name)) - ret["changes"].setdefault("new", "User {} deleted".format(name)) + ret["comment"] = f"Deleted user {name}" + ret["changes"].setdefault("old", f"User {name} exists") + ret["changes"].setdefault("new", f"User {name} deleted") ret["result"] = True else: - ret["comment"] = "Failed to delete {}".format(name) + ret["comment"] = f"Failed to delete {name}" ret["result"] = False else: - ret["comment"] = "User {} has already been deleted!".format(name) + ret["comment"] = f"User {name} has already been deleted!" ret["result"] = True else: - ret["comment"] = "User {} does not exist".format(name) + ret["comment"] = f"User {name} does not exist" ret["result"] = True return ret @@ -153,7 +151,7 @@ def team_present( enforce_mfa=False, no_mfa_grace_seconds=0, profile="github", - **kwargs + **kwargs, ): """ Ensure a team is present @@ -229,7 +227,7 @@ def team_present( if len(parameters) > 0: if __opts__["test"]: test_comments.append( - "Team properties are set to be edited: {}".format(parameters) + f"Team properties are set to be edited: {parameters}" ) ret["result"] = None else: @@ -238,7 +236,7 @@ def team_present( ) if result: ret["changes"]["team"] = { - "old": "Team properties were {}".format(target), + "old": f"Team properties were {target}", "new": "Team properties (that changed) are {}".format( parameters ), @@ -272,8 +270,8 @@ def team_present( ) if result: ret["changes"][repo_name] = { - "old": "Repo {} is not in team {}".format(repo_name, name), - "new": "Repo {} is in team {}".format(repo_name, name), + "old": f"Repo {repo_name} is not in team {name}", + "new": f"Repo {repo_name} is in team {name}", } else: ret["result"] = False @@ -297,8 +295,8 @@ def team_present( ) if result: ret["changes"][repo_name] = { - "old": "Repo {} is in team {}".format(repo_name, name), - "new": "Repo {} is not in team {}".format(repo_name, name), + "old": f"Repo {repo_name} is in team {name}", + "new": f"Repo {repo_name} is not in team {name}", } else: ret["result"] = False @@ -311,7 +309,7 @@ def team_present( else: # Team does not exist - it will be created. if __opts__["test"]: - ret["comment"] = "Team {} is set to be created.".format(name) + ret["comment"] = f"Team {name} is set to be created." ret["result"] = None return ret @@ -322,15 +320,15 @@ def team_present( permission=permission, privacy=privacy, profile=profile, - **kwargs + **kwargs, ) if result: ret["changes"]["team"] = {} ret["changes"]["team"]["old"] = None - ret["changes"]["team"]["new"] = "Team {} has been created".format(name) + ret["changes"]["team"]["new"] = f"Team {name} has been created" else: ret["result"] = False - ret["comment"] = "Failed to create team {}.".format(name) + ret["comment"] = f"Failed to create team {name}." return ret manage_members = members is not None @@ -363,9 +361,7 @@ def team_present( else: # Add to team member_change = True if __opts__["test"]: - test_comments.append( - "User {} set to be added to the team.".format(member) - ) + test_comments.append(f"User {member} set to be added to the team.") ret["result"] = None else: result = __salt__["github.add_team_member"]( @@ -373,9 +369,9 @@ def team_present( ) if result: ret["changes"][member] = {} - ret["changes"][member]["old"] = ( - "User {} is not in team {}".format(member, name) - ) + ret["changes"][member][ + "old" + ] = f"User {member} is not in team {name}" ret["changes"][member]["new"] = "User {} is in team {}".format( member, name ) @@ -407,7 +403,7 @@ def team_present( ) else: test_comments.append( - "User {} set to be removed from the team.".format(member) + f"User {member} set to be removed from the team." ) ret["result"] = None else: @@ -417,7 +413,7 @@ def team_present( if result: extra_changes = " due to MFA violation" if mfa_violation else "" ret["changes"][member] = { - "old": "User {} is in team {}".format(member, name), + "old": f"User {member} is in team {name}", "new": "User {} is not in team {}{}".format( member, name, extra_changes ), @@ -473,24 +469,24 @@ def team_absent(name, profile="github", **kwargs): target = __salt__["github.get_team"](name, profile=profile, **kwargs) if not target: - ret["comment"] = "Team {} does not exist".format(name) + ret["comment"] = f"Team {name} does not exist" ret["result"] = True return ret else: if __opts__["test"]: - ret["comment"] = "Team {} will be deleted".format(name) + ret["comment"] = f"Team {name} will be deleted" ret["result"] = None return ret result = __salt__["github.remove_team"](name, profile=profile, **kwargs) if result: - ret["comment"] = "Deleted team {}".format(name) - ret["changes"].setdefault("old", "Team {} exists".format(name)) - ret["changes"].setdefault("new", "Team {} deleted".format(name)) + ret["comment"] = f"Deleted team {name}" + ret["changes"].setdefault("old", f"Team {name} exists") + ret["changes"].setdefault("new", f"Team {name} deleted") ret["result"] = True else: - ret["comment"] = "Failed to delete {}".format(name) + ret["comment"] = f"Failed to delete {name}" ret["result"] = False return ret @@ -508,7 +504,7 @@ def repo_present( license_template=None, teams=None, profile="github", - **kwargs + **kwargs, ): """ Ensure a repository is present @@ -605,8 +601,8 @@ def repo_present( if len(parameters) > 0: repo_change = { - "old": "Repo properties were {}".format(old_parameters), - "new": "Repo properties (that changed) are {}".format(parameters), + "old": f"Repo properties were {old_parameters}", + "new": f"Repo properties (that changed) are {parameters}", } if __opts__["test"]: ret["changes"]["repo"] = repo_change @@ -623,7 +619,7 @@ def repo_present( return ret else: # Repo does not exist - it will be created. - repo_change = {"old": None, "new": "Repo {} has been created".format(name)} + repo_change = {"old": None, "new": f"Repo {name} has been created"} if __opts__["test"]: ret["changes"]["repo"] = repo_change ret["result"] = None @@ -634,7 +630,7 @@ def repo_present( if not result: ret["result"] = False - ret["comment"] = "Failed to create repo {}.".format(name) + ret["comment"] = f"Failed to create repo {name}." return ret # Turns out that trying to fetch teams for a new repo can 404 immediately @@ -652,7 +648,7 @@ def repo_present( if current_teams is None: ret["result"] = False - ret["comment"] = "Failed to verify repo {} after creation.".format(name) + ret["comment"] = f"Failed to verify repo {name} after creation." return ret ret["changes"]["repo"] = repo_change @@ -669,8 +665,8 @@ def repo_present( for team_name in current_team_names: if team_name not in teams: team_change = { - "old": "Repo {} is in team {}".format(name, team_name), - "new": "Repo {} is not in team {}".format(name, team_name), + "old": f"Repo {name} is in team {team_name}", + "new": f"Repo {name} is not in team {team_name}", } if __opts__["test"]: @@ -695,8 +691,8 @@ def repo_present( for team_name, permission in teams.items(): if team_name not in current_team_names: # Need to add repo to team team_change = { - "old": "Repo {} is not in team {}".format(name, team_name), - "new": "Repo {} is in team {}".format(name, team_name), + "old": f"Repo {name} is not in team {team_name}", + "new": f"Repo {name} is in team {team_name}", } if __opts__["test"]: ret["changes"][team_name] = team_change @@ -783,21 +779,21 @@ def repo_absent(name, profile="github", **kwargs): target = None if not target: - ret["comment"] = "Repo {} does not exist".format(name) + ret["comment"] = f"Repo {name} does not exist" ret["result"] = True return ret else: if __opts__["test"]: - ret["comment"] = "Repo {} will be deleted".format(name) + ret["comment"] = f"Repo {name} will be deleted" ret["result"] = None return ret result = __salt__["github.remove_repo"](name, profile=profile, **kwargs) if result: - ret["comment"] = "Deleted repo {}".format(name) - ret["changes"].setdefault("old", "Repo {} exists".format(name)) - ret["changes"].setdefault("new", "Repo {} deleted".format(name)) + ret["comment"] = f"Deleted repo {name}" + ret["changes"].setdefault("old", f"Repo {name} exists") + ret["changes"].setdefault("new", f"Repo {name} deleted") ret["result"] = True else: ret["comment"] = ( diff --git a/salt/states/glance_image.py b/salt/states/glance_image.py index 385244cb7be..b65ec5f353c 100644 --- a/salt/states/glance_image.py +++ b/salt/states/glance_image.py @@ -60,7 +60,7 @@ def present(name, auth=None, **kwargs): if __opts__["test"]: ret["result"] = None ret["changes"] = kwargs - ret["comment"] = "Image {} will be created.".format(name) + ret["comment"] = f"Image {name} will be created." return ret kwargs["name"] = name @@ -90,7 +90,7 @@ def absent(name, auth=None): if __opts__["test"]: ret["result"] = None ret["changes"] = {"name": name} - ret["comment"] = "Image {} will be deleted.".format(name) + ret["comment"] = f"Image {name} will be deleted." return ret __salt__["glanceng.image_delete"](name=image) diff --git a/salt/states/glassfish.py b/salt/states/glassfish.py index 913b7da2fb5..30778d17729 100644 --- a/salt/states/glassfish.py +++ b/salt/states/glassfish.py @@ -82,7 +82,7 @@ def _do_element_present(name, elem_type, data, server=None): """ ret = {"changes": {}, "update": False, "create": False, "error": None} try: - elements = __salt__["glassfish.enum_{}".format(elem_type)]() + elements = __salt__[f"glassfish.enum_{elem_type}"]() except requests.ConnectionError as error: if __opts__["test"]: ret["changes"] = {"Name": name, "Params": data} @@ -97,23 +97,19 @@ def _do_element_present(name, elem_type, data, server=None): ret["create"] = True if not __opts__["test"]: try: - __salt__["glassfish.create_{}".format(elem_type)]( - name, server=server, **data - ) + __salt__[f"glassfish.create_{elem_type}"](name, server=server, **data) except CommandExecutionError as error: ret["error"] = error return ret elif elements and any(data): - current_data = __salt__["glassfish.get_{}".format(elem_type)]( - name, server=server - ) + current_data = __salt__[f"glassfish.get_{elem_type}"](name, server=server) data_diff = _is_updated(current_data, data) if data_diff: ret["update"] = True ret["changes"] = data_diff if not __opts__["test"]: try: - __salt__["glassfish.update_{}".format(elem_type)]( + __salt__[f"glassfish.update_{elem_type}"]( name, server=server, **data ) except CommandExecutionError as error: @@ -127,7 +123,7 @@ def _do_element_absent(name, elem_type, data, server=None): """ ret = {"delete": False, "error": None} try: - elements = __salt__["glassfish.enum_{}".format(elem_type)]() + elements = __salt__[f"glassfish.enum_{elem_type}"]() except requests.ConnectionError as error: if __opts__["test"]: ret["create"] = True @@ -140,9 +136,7 @@ def _do_element_absent(name, elem_type, data, server=None): ret["delete"] = True if not __opts__["test"]: try: - __salt__["glassfish.delete_{}".format(elem_type)]( - name, server=server, **data - ) + __salt__[f"glassfish.delete_{elem_type}"](name, server=server, **data) except CommandExecutionError as error: ret["error"] = error return ret @@ -208,7 +202,7 @@ def connection_factory_present( # Manage parameters pool_data = {} res_data = {} - pool_name = "{}-Connection-Pool".format(name) + pool_name = f"{name}-Connection-Pool" if restype == "topic_connection_factory": pool_data["connectionDefinitionName"] = "javax.jms.TopicConnectionFactory" elif restype == "queue_connection_factory": @@ -285,7 +279,7 @@ def connection_factory_absent(name, both=True, server=None): Delete both the pool and the resource, defaults to ``true`` """ ret = {"name": name, "result": None, "comment": None, "changes": {}} - pool_name = "{}-Connection-Pool".format(name) + pool_name = f"{name}-Connection-Pool" pool_ret = _do_element_absent( pool_name, "connector_c_pool", {"cascade": both}, server ) @@ -466,7 +460,7 @@ def jdbc_datasource_present( ret = {"name": name, "result": None, "comment": None, "changes": {}} # Manage parameters - res_name = "jdbc/{}".format(name) + res_name = f"jdbc/{name}" pool_data = {} pool_data_properties = {} res_data = {} diff --git a/salt/states/glusterfs.py b/salt/states/glusterfs.py index aefe8499960..331053d2550 100644 --- a/salt/states/glusterfs.py +++ b/salt/states/glusterfs.py @@ -83,11 +83,11 @@ def peered(name): if peers and any(name in v["hostnames"] for v in peers.values()): ret["result"] = True - ret["comment"] = "Host {} already peered".format(name) + ret["comment"] = f"Host {name} already peered" return ret if __opts__["test"]: - ret["comment"] = "Peer {} will be added.".format(name) + ret["comment"] = f"Peer {name} will be added." ret["result"] = None return ret @@ -101,7 +101,7 @@ def peered(name): newpeers = __salt__["glusterfs.peer_status"]() if newpeers and any(name in v["hostnames"] for v in newpeers.values()): ret["result"] = True - ret["comment"] = "Host {} successfully peered".format(name) + ret["comment"] = f"Host {name} successfully peered" ret["changes"] = {"new": newpeers, "old": peers} else: ret["comment"] = ( @@ -181,7 +181,7 @@ def volume_present( volumes = __salt__["glusterfs.list_volumes"]() if name not in volumes: if __opts__["test"]: - comment = "Volume {} will be created".format(name) + comment = f"Volume {name} will be created" if start: comment += " and started" ret["comment"] = comment @@ -193,16 +193,16 @@ def volume_present( ) if not vol_created: - ret["comment"] = "Creation of volume {} failed".format(name) + ret["comment"] = f"Creation of volume {name} failed" return ret old_volumes = volumes volumes = __salt__["glusterfs.list_volumes"]() if name in volumes: ret["changes"] = {"new": volumes, "old": old_volumes} - ret["comment"] = "Volume {} is created".format(name) + ret["comment"] = f"Volume {name} is created" else: - ret["comment"] = "Volume {} already exists".format(name) + ret["comment"] = f"Volume {name} already exists" if start: if __opts__["test"]: @@ -251,26 +251,26 @@ def started(name): volinfo = __salt__["glusterfs.info"]() if name not in volinfo: ret["result"] = False - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" return ret if int(volinfo[name]["status"]) == 1: - ret["comment"] = "Volume {} is already started".format(name) + ret["comment"] = f"Volume {name} is already started" ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be started".format(name) + ret["comment"] = f"Volume {name} will be started" ret["result"] = None return ret vol_started = __salt__["glusterfs.start_volume"](name) if vol_started: ret["result"] = True - ret["comment"] = "Volume {} is started".format(name) + ret["comment"] = f"Volume {name} is started" ret["change"] = {"new": "started", "old": "stopped"} else: ret["result"] = False - ret["comment"] = "Failed to start volume {}".format(name) + ret["comment"] = f"Failed to start volume {name}" return ret @@ -304,23 +304,23 @@ def add_volume_bricks(name, bricks): volinfo = __salt__["glusterfs.info"]() if name not in volinfo: - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" return ret if int(volinfo[name]["status"]) != 1: - ret["comment"] = "Volume {} is not started".format(name) + ret["comment"] = f"Volume {name} is not started" return ret current_bricks = [brick["path"] for brick in volinfo[name]["bricks"].values()] if not set(bricks) - set(current_bricks): ret["result"] = True - ret["comment"] = "Bricks already added in volume {}".format(name) + ret["comment"] = f"Bricks already added in volume {name}" return ret bricks_added = __salt__["glusterfs.add_volume_bricks"](name, bricks) if bricks_added: ret["result"] = True - ret["comment"] = "Bricks successfully added to volume {}".format(name) + ret["comment"] = f"Bricks successfully added to volume {name}" new_bricks = [ brick["path"] for brick in __salt__["glusterfs.info"]()[name]["bricks"].values() @@ -328,7 +328,7 @@ def add_volume_bricks(name, bricks): ret["changes"] = {"new": new_bricks, "old": current_bricks} return ret - ret["comment"] = "Adding bricks to volume {} failed".format(name) + ret["comment"] = f"Adding bricks to volume {name} failed" return ret diff --git a/salt/states/gnomedesktop.py b/salt/states/gnomedesktop.py index 24c9df87796..6fb3c222a1b 100644 --- a/salt/states/gnomedesktop.py +++ b/salt/states/gnomedesktop.py @@ -68,12 +68,12 @@ def _do(name, gnome_kwargs, preferences): gnome_kwargs.update({"key": key, "value": value}) if _check_current_value(gnome_kwargs, value): - messages.append("{} is already set to {}".format(key, value)) + messages.append(f"{key} is already set to {value}") else: result = __salt__["gnome.set"](**gnome_kwargs) if result["retcode"] == 0: - messages.append("Setting {} to {}".format(key, value)) - ret["changes"][key] = "{}:{}".format(key, value) + messages.append(f"Setting {key} to {value}") + ret["changes"][key] = f"{key}:{value}" ret["result"] = True else: messages.append(result["stdout"]) @@ -108,7 +108,7 @@ def wm_preferences( visual_bell=None, visual_bell_type=None, workspace_names=None, - **kwargs + **kwargs, ): """ wm_preferences: sets values in the org.gnome.desktop.wm.preferences schema @@ -160,7 +160,7 @@ def desktop_lockdown( disable_save_to_disk=None, disable_user_switching=None, user_administration_disabled=None, - **kwargs + **kwargs, ): """ desktop_lockdown: sets values in the org.gnome.desktop.lockdown schema @@ -227,7 +227,7 @@ def desktop_interface( toolbar_icons_size=None, toolbar_style=None, toolkit_accessibility=None, - **kwargs + **kwargs, ): """ desktop_interface: sets values in the org.gnome.desktop.interface schema diff --git a/salt/states/gpg.py b/salt/states/gpg.py index bde4b3beeda..fb964f7425b 100644 --- a/salt/states/gpg.py +++ b/salt/states/gpg.py @@ -91,7 +91,7 @@ def present( ret["comment"].append(result["comment"]) else: ret["comment"].append( - "Set trust level for {} to {}".format(key, trust) + f"Set trust level for {key} to {trust}" ) else: ret["comment"].append( @@ -100,9 +100,9 @@ def present( ) ) else: - ret["comment"].append("Invalid trust level {}".format(trust)) + ret["comment"].append(f"Invalid trust level {trust}") - ret["comment"].append("GPG Public Key {} already in keychain ".format(key)) + ret["comment"].append(f"GPG Public Key {key} already in keychain ") else: result = __salt__["gpg.receive_keys"]( @@ -115,7 +115,7 @@ def present( ret["result"] = result["result"] ret["comment"].append(result["comment"]) else: - ret["comment"].append("Adding {} to GPG keychain".format(name)) + ret["comment"].append(f"Adding {name} to GPG keychain") if trust: if trust in _VALID_TRUST_VALUES: @@ -128,11 +128,9 @@ def present( ret["result"] = result["result"] ret["comment"].append(result["comment"]) else: - ret["comment"].append( - "Set trust level for {} to {}".format(key, trust) - ) + ret["comment"].append(f"Set trust level for {key} to {trust}") else: - ret["comment"].append("Invalid trust level {}".format(trust)) + ret["comment"].append(f"Invalid trust level {trust}") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -181,8 +179,8 @@ def absent(name, keys=None, user=None, gnupghome=None, **kwargs): ret["result"] = result["result"] ret["comment"].append(result["comment"]) else: - ret["comment"].append("Deleting {} from GPG keychain".format(name)) + ret["comment"].append(f"Deleting {name} from GPG keychain") else: - ret["comment"].append("{} not found in GPG keychain".format(name)) + ret["comment"].append(f"{name} not found in GPG keychain") ret["comment"] = "\n".join(ret["comment"]) return ret diff --git a/salt/states/grafana.py b/salt/states/grafana.py index e061b916fb2..b25a1d93d3c 100644 --- a/salt/states/grafana.py +++ b/salt/states/grafana.py @@ -189,7 +189,7 @@ def _parse_profile(profile): if isinstance(profile, str): _profile = __salt__["config.option"](profile) if not _profile: - msg = "Pillar key for profile {} not found.".format(profile) + msg = f"Pillar key for profile {profile} not found." raise SaltInvocationError(msg) else: _profile = profile @@ -292,7 +292,7 @@ def dashboard_present( " dashboard template was provided." ) if __opts__["test"]: - ret["comment"] = "Dashboard {} is set to be created.".format(name) + ret["comment"] = f"Dashboard {name} is set to be created." ret["result"] = None return ret _dashboard = dashboard @@ -330,12 +330,12 @@ def dashboard_present( update_rows.append(title) if not update_rows: ret["result"] = True - ret["comment"] = "Dashboard {} is up to date".format(name) + ret["comment"] = f"Dashboard {name} is up to date" return ret if __opts__["test"]: - msg = "Dashboard {} is set to be updated.".format(name) + msg = f"Dashboard {name} is set to be updated." if update_rows: - msg = "{} The following rows set to be updated: {}".format(msg, update_rows) + msg = f"{msg} The following rows set to be updated: {update_rows}" ret["comment"] = msg return ret body = { @@ -350,13 +350,13 @@ def dashboard_present( if updated: ret["result"] = True ret["changes"]["changed"] = name - msg = "Updated dashboard {}.".format(name) + msg = f"Updated dashboard {name}." if update_rows: - msg = "{} The following rows were updated: {}".format(msg, update_rows) + msg = f"{msg} The following rows were updated: {update_rows}" ret["comment"] = msg else: ret["result"] = False - msg = "Failed to update dashboard {}.".format(name) + msg = f"Failed to update dashboard {name}." ret["comment"] = msg return ret @@ -385,7 +385,7 @@ def dashboard_absent(name, hosts=None, profile="grafana"): if exists: if __opts__["test"]: - ret["comment"] = "Dashboard {} is set to be removed.".format(name) + ret["comment"] = f"Dashboard {name} is set to be removed." return ret deleted = __salt__["elasticsearch.delete"]( index=index, doc_type="dashboard", id=name, hosts=hosts @@ -396,9 +396,9 @@ def dashboard_absent(name, hosts=None, profile="grafana"): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} dashboard.".format(name) + ret["comment"] = f"Failed to delete {name} dashboard." else: ret["result"] = True - ret["comment"] = "Dashboard {} does not exist.".format(name) + ret["comment"] = f"Dashboard {name} does not exist." return ret diff --git a/salt/states/grafana4_dashboard.py b/salt/states/grafana4_dashboard.py index fa3414ae6b4..43d88734852 100644 --- a/salt/states/grafana4_dashboard.py +++ b/salt/states/grafana4_dashboard.py @@ -138,15 +138,15 @@ def present( if not old_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be created.".format(name) + ret["comment"] = f"Dashboard {name} is set to be created." return ret response = __salt__["grafana4.create_update_dashboard"]( dashboard=new_dashboard, overwrite=True, profile=profile ) if response.get("status") == "success": - ret["comment"] = "Dashboard {} created.".format(name) - ret["changes"]["new"] = "Dashboard {} created.".format(name) + ret["comment"] = f"Dashboard {name} created." + ret["changes"]["new"] = f"Dashboard {name} created." else: ret["result"] = False ret["comment"] = "Failed to create dashboard {}, response={}".format( @@ -191,7 +191,7 @@ def present( dashboard_diff = DictDiffer( _cleaned(updated_dashboard), _cleaned(old_dashboard) ) - ret["comment"] = "Dashboard {} updated.".format(name) + ret["comment"] = f"Dashboard {name} updated." ret["changes"] = _dashboard_diff( _cleaned(new_dashboard), _cleaned(old_dashboard) ) @@ -229,12 +229,12 @@ def absent(name, orgname=None, profile="grafana"): if existing_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be deleted.".format(name) + ret["comment"] = f"Dashboard {name} is set to be deleted." return ret __salt__["grafana4.delete_dashboard"](name, profile=profile) - ret["comment"] = "Dashboard {} deleted.".format(name) - ret["changes"]["new"] = "Dashboard {} deleted.".format(name) + ret["comment"] = f"Dashboard {name} deleted." + ret["changes"]["new"] = f"Dashboard {name} deleted." return ret ret["comment"] = "Dashboard absent" diff --git a/salt/states/grafana4_datasource.py b/salt/states/grafana4_datasource.py index b0ebe8d02d3..b3b2503071c 100644 --- a/salt/states/grafana4_datasource.py +++ b/salt/states/grafana4_datasource.py @@ -152,12 +152,12 @@ def present( if not datasource: if __opts__["test"]: - ret["comment"] = "Datasource {} will be created".format(name) + ret["comment"] = f"Datasource {name} will be created" return ret __salt__["grafana4.create_datasource"](profile=profile, **data) datasource = __salt__["grafana4.get_datasource"](name, profile=profile) ret["result"] = True - ret["comment"] = "New data source {} added".format(name) + ret["comment"] = f"New data source {name} added" ret["changes"] = data return ret @@ -168,16 +168,16 @@ def present( datasource[key] = None if data == datasource: - ret["comment"] = "Data source {} already up-to-date".format(name) + ret["comment"] = f"Data source {name} already up-to-date" return ret if __opts__["test"]: - ret["comment"] = "Datasource {} will be updated".format(name) + ret["comment"] = f"Datasource {name} will be updated" return ret __salt__["grafana4.update_datasource"](datasource["id"], profile=profile, **data) ret["result"] = True ret["changes"] = deep_diff(datasource, data, ignore=["id", "orgId", "readOnly"]) - ret["comment"] = "Data source {} updated".format(name) + ret["comment"] = f"Data source {name} updated" return ret @@ -203,17 +203,17 @@ def absent(name, orgname=None, profile="grafana"): if not datasource: ret["result"] = True - ret["comment"] = "Data source {} already absent".format(name) + ret["comment"] = f"Data source {name} already absent" return ret if __opts__["test"]: - ret["comment"] = "Datasource {} will be deleted".format(name) + ret["comment"] = f"Datasource {name} will be deleted" return ret __salt__["grafana4.delete_datasource"](datasource["id"], profile=profile) ret["result"] = True ret["changes"][name] = "Absent" - ret["comment"] = "Data source {} was deleted".format(name) + ret["comment"] = f"Data source {name} was deleted" return ret diff --git a/salt/states/grafana4_org.py b/salt/states/grafana4_org.py index 8d4aa5e1da9..c0167637e8e 100644 --- a/salt/states/grafana4_org.py +++ b/salt/states/grafana4_org.py @@ -130,12 +130,12 @@ def present( if create: if __opts__["test"]: - ret["comment"] = "Org {} will be created".format(name) + ret["comment"] = f"Org {name} will be created" return ret __salt__["grafana4.create_org"](profile=profile, name=name) org = __salt__["grafana4.get_org"](name, profile) ret["changes"] = org - ret["comment"] = "New org {} added".format(name) + ret["comment"] = f"New org {name} added" data = _get_json_data( address1=address1, @@ -148,7 +148,7 @@ def present( ) if data != org["address"]: if __opts__["test"]: - ret["comment"] = "Org {} address will be updated".format(name) + ret["comment"] = f"Org {name} address will be updated" return ret __salt__["grafana4.update_org_address"](name, profile=profile, **data) if create: @@ -165,7 +165,7 @@ def present( ) if data != prefs: if __opts__["test"]: - ret["comment"] = "Org {} prefs will be updated".format(name) + ret["comment"] = f"Org {name} prefs will be updated" return ret __salt__["grafana4.update_org_prefs"](name, profile=profile, **data) if create: @@ -227,10 +227,10 @@ def present( ret["result"] = True if not create: if ret["changes"]: - ret["comment"] = "Org {} updated".format(name) + ret["comment"] = f"Org {name} updated" else: ret["changes"] = {} - ret["comment"] = "Org {} already up-to-date".format(name) + ret["comment"] = f"Org {name} already up-to-date" return ret @@ -254,17 +254,17 @@ def absent(name, profile="grafana"): if not org: ret["result"] = True - ret["comment"] = "Org {} already absent".format(name) + ret["comment"] = f"Org {name} already absent" return ret if __opts__["test"]: - ret["comment"] = "Org {} will be deleted".format(name) + ret["comment"] = f"Org {name} will be deleted" return ret __salt__["grafana4.delete_org"](org["id"], profile=profile) ret["result"] = True ret["changes"][name] = "Absent" - ret["comment"] = "Org {} was deleted".format(name) + ret["comment"] = f"Org {name} was deleted" return ret diff --git a/salt/states/grafana4_user.py b/salt/states/grafana4_user.py index 813c4e5aae4..30c4c1e83f3 100644 --- a/salt/states/grafana4_user.py +++ b/salt/states/grafana4_user.py @@ -85,7 +85,7 @@ def present( if create: if __opts__["test"]: - ret["comment"] = "User {} will be created".format(name) + ret["comment"] = f"User {name} will be created" return ret __salt__["grafana4.create_user"]( login=name, password=password, email=email, name=fullname, profile=profile @@ -101,7 +101,7 @@ def present( login=None, email=None, name=None, theme=None, defaults=user_data ): if __opts__["test"]: - ret["comment"] = "User {} will be updated".format(name) + ret["comment"] = f"User {name} will be updated" return ret __salt__["grafana4.update_user"](user["id"], profile=profile, **data) dictupdate.update( @@ -111,7 +111,7 @@ def present( if user["isAdmin"] != is_admin: if __opts__["test"]: - ret["comment"] = "User {} isAdmin status will be updated".format(name) + ret["comment"] = f"User {name} isAdmin status will be updated" return ret __salt__["grafana4.update_user_permissions"]( user["id"], isGrafanaAdmin=is_admin, profile=profile @@ -124,13 +124,13 @@ def present( ret["result"] = True if create: ret["changes"] = ret["changes"]["new"] - ret["comment"] = "New user {} added".format(name) + ret["comment"] = f"New user {name} added" else: if ret["changes"]: - ret["comment"] = "User {} updated".format(name) + ret["comment"] = f"User {name} updated" else: ret["changes"] = {} - ret["comment"] = "User {} already up-to-date".format(name) + ret["comment"] = f"User {name} already up-to-date" return ret @@ -154,7 +154,7 @@ def absent(name, profile="grafana"): if user: if __opts__["test"]: - ret["comment"] = "User {} will be deleted".format(name) + ret["comment"] = f"User {name} will be deleted" return ret orgs = __salt__["grafana4.get_user_orgs"](user["id"], profile=profile) __salt__["grafana4.delete_user"](user["id"], profile=profile) @@ -171,12 +171,12 @@ def absent(name, profile="grafana"): ) else: ret["result"] = True - ret["comment"] = "User {} already absent".format(name) + ret["comment"] = f"User {name} already absent" return ret ret["result"] = True ret["changes"][name] = "Absent" - ret["comment"] = "User {} was deleted".format(name) + ret["comment"] = f"User {name} was deleted" return ret diff --git a/salt/states/grafana_dashboard.py b/salt/states/grafana_dashboard.py index 143eb35c134..4a1dc14ae54 100644 --- a/salt/states/grafana_dashboard.py +++ b/salt/states/grafana_dashboard.py @@ -121,18 +121,18 @@ def present( _ensure_annotations(new_dashboard) # Create dashboard if it does not exist - url = "db/{}".format(name) + url = f"db/{name}" old_dashboard = _get(url, profile) if not old_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be created.".format(name) + ret["comment"] = f"Dashboard {name} is set to be created." return ret response = _update(new_dashboard, profile) if response.get("status") == "success": - ret["comment"] = "Dashboard {} created.".format(name) - ret["changes"]["new"] = "Dashboard {} created.".format(name) + ret["comment"] = f"Dashboard {name} created." + ret["changes"]["new"] = f"Dashboard {name} created." else: ret["result"] = False ret["comment"] = "Failed to create dashboard {}, response={}".format( @@ -173,7 +173,7 @@ def present( dashboard_diff = DictDiffer( _cleaned(updated_dashboard), _cleaned(old_dashboard) ) - ret["comment"] = "Dashboard {} updated.".format(name) + ret["comment"] = f"Dashboard {name} updated." ret["changes"] = _dashboard_diff( _cleaned(new_dashboard), _cleaned(old_dashboard) ) @@ -203,17 +203,17 @@ def absent(name, profile="grafana"): if isinstance(profile, str): profile = __salt__["config.option"](profile) - url = "db/{}".format(name) + url = f"db/{name}" existing_dashboard = _get(url, profile) if existing_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be deleted.".format(name) + ret["comment"] = f"Dashboard {name} is set to be deleted." return ret _delete(url, profile) - ret["comment"] = "Dashboard {} deleted.".format(name) - ret["changes"]["new"] = "Dashboard {} deleted.".format(name) + ret["comment"] = f"Dashboard {name} deleted." + ret["changes"]["new"] = f"Dashboard {name} deleted." return ret ret["comment"] = "Dashboard absent" diff --git a/salt/states/grafana_datasource.py b/salt/states/grafana_datasource.py index e513802c890..9daf0efa79f 100644 --- a/salt/states/grafana_datasource.py +++ b/salt/states/grafana_datasource.py @@ -110,10 +110,10 @@ def present( ret["result"] = True ret["changes"] = _diff(datasource, data) if ret["changes"]["new"] or ret["changes"]["old"]: - ret["comment"] = "Data source {} updated".format(name) + ret["comment"] = f"Data source {name} updated" else: ret["changes"] = {} - ret["comment"] = "Data source {} already up-to-date".format(name) + ret["comment"] = f"Data source {name} already up-to-date" else: requests.post( "{}/api/datasources".format(profile["grafana_url"]), @@ -122,7 +122,7 @@ def present( timeout=profile.get("grafana_timeout", 3), ) ret["result"] = True - ret["comment"] = "New data source {} added".format(name) + ret["comment"] = f"New data source {name} added" ret["changes"] = data return ret @@ -143,7 +143,7 @@ def absent(name, profile="grafana"): if not datasource: ret["result"] = True - ret["comment"] = "Data source {} already absent".format(name) + ret["comment"] = f"Data source {name} already absent" return ret requests.delete( @@ -153,7 +153,7 @@ def absent(name, profile="grafana"): ) ret["result"] = True - ret["comment"] = "Data source {} was deleted".format(name) + ret["comment"] = f"Data source {name} was deleted" return ret diff --git a/salt/states/grains.py b/salt/states/grains.py index 8ffe5fe3cc9..2dd675255c7 100644 --- a/salt/states/grains.py +++ b/salt/states/grains.py @@ -125,15 +125,15 @@ def present(name, value, delimiter=DEFAULT_TARGET_DELIM, force=False): if __opts__["test"]: ret["result"] = None if existing is _non_existent: - ret["comment"] = "Grain {} is set to be added".format(name) + ret["comment"] = f"Grain {name} is set to be added" ret["changes"] = {"new": name} else: - ret["comment"] = "Grain {} is set to be changed".format(name) + ret["comment"] = f"Grain {name} is set to be changed" ret["changes"] = {"changed": {name: value}} return ret ret = __salt__["grains.set"](name, value, force=force) if ret["result"] is True and ret["changes"] != {}: - ret["comment"] = "Set grain {} to {}".format(name, value) + ret["comment"] = f"Set grain {name} to {value}" ret["name"] = name return ret @@ -182,13 +182,13 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): # check whether grain is a list if not isinstance(grain, list): ret["result"] = False - ret["comment"] = "Grain {} is not a valid list".format(name) + ret["comment"] = f"Grain {name} is not a valid list" return ret if isinstance(value, list): if make_hashable(value).issubset( make_hashable(__salt__["grains.get"](name)) ): - ret["comment"] = "Value {1} is already in grain {0}".format(name, value) + ret["comment"] = f"Value {value} is already in grain {name}" return ret elif name in __context__.get("pending_grains", {}): # elements common to both @@ -211,7 +211,7 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): __context__["pending_grains"][name].update(value) else: if value in grain: - ret["comment"] = "Value {1} is already in grain {0}".format(name, value) + ret["comment"] = f"Value {value} is already in grain {name}" return ret if __opts__["test"]: ret["result"] = None @@ -223,21 +223,21 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Grain {} is set to be added".format(name) + ret["comment"] = f"Grain {name} is set to be added" ret["changes"] = {"new": grain} return ret new_grains = __salt__["grains.append"](name, value) if isinstance(value, list): if not set(value).issubset(set(__salt__["grains.get"](name))): ret["result"] = False - ret["comment"] = "Failed append value {1} to grain {0}".format(name, value) + ret["comment"] = f"Failed append value {value} to grain {name}" return ret else: if value not in __salt__["grains.get"](name, delimiter=DEFAULT_TARGET_DELIM): ret["result"] = False - ret["comment"] = "Failed append value {1} to grain {0}".format(name, value) + ret["comment"] = f"Failed append value {value} to grain {name}" return ret - ret["comment"] = "Append value {1} to grain {0}".format(name, value) + ret["comment"] = f"Append value {value} to grain {name}" ret["changes"] = {"new": new_grains} return ret @@ -288,22 +288,16 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): value = [value] for val in value: if val not in grain: - comments.append( - "Value {1} is absent from grain {0}".format(name, val) - ) + comments.append(f"Value {val} is absent from grain {name}") elif __opts__["test"]: ret["result"] = None - comments.append( - "Value {1} in grain {0} is set to be deleted".format(name, val) - ) + comments.append(f"Value {val} in grain {name} is set to be deleted") if "deleted" not in ret["changes"]: ret["changes"] = {"deleted": []} ret["changes"]["deleted"].append(val) elif val in grain: __salt__["grains.remove"](name, val) - comments.append( - "Value {1} was deleted from grain {0}".format(name, val) - ) + comments.append(f"Value {val} was deleted from grain {name}") if "deleted" not in ret["changes"]: ret["changes"] = {"deleted": []} ret["changes"]["deleted"].append(val) @@ -311,9 +305,9 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): return ret else: ret["result"] = False - ret["comment"] = "Grain {} is not a valid list".format(name) + ret["comment"] = f"Grain {name} is not a valid list" else: - ret["comment"] = "Grain {} does not exist".format(name) + ret["comment"] = f"Grain {name} does not exist" return ret @@ -362,38 +356,36 @@ def absent(name, destructive=False, delimiter=DEFAULT_TARGET_DELIM, force=False) if __opts__["test"]: ret["result"] = None if destructive is True: - ret["comment"] = "Grain {} is set to be deleted".format(name) + ret["comment"] = f"Grain {name} is set to be deleted" ret["changes"] = {"deleted": name} return ret ret = __salt__["grains.set"](name, None, destructive=destructive, force=force) if ret["result"]: if destructive is True: - ret["comment"] = "Grain {} was deleted".format(name) + ret["comment"] = f"Grain {name} was deleted" ret["changes"] = {"deleted": name} ret["name"] = name elif grain is not _non_existent: if __opts__["test"]: ret["result"] = None if destructive is True: - ret["comment"] = "Grain {} is set to be deleted".format(name) + ret["comment"] = f"Grain {name} is set to be deleted" ret["changes"] = {"deleted": name} else: - ret["comment"] = ( - "Value for grain {} is set to be deleted (None)".format(name) - ) + ret["comment"] = f"Value for grain {name} is set to be deleted (None)" ret["changes"] = {"grain": name, "value": None} return ret ret = __salt__["grains.set"](name, None, destructive=destructive, force=force) if ret["result"]: if destructive is True: - ret["comment"] = "Grain {} was deleted".format(name) + ret["comment"] = f"Grain {name} was deleted" ret["changes"] = {"deleted": name} else: - ret["comment"] = "Value for grain {} was set to None".format(name) + ret["comment"] = f"Value for grain {name} was set to None" ret["changes"] = {"grain": name, "value": None} ret["name"] = name else: - ret["comment"] = "Grain {} does not exist".format(name) + ret["comment"] = f"Grain {name} does not exist" return ret @@ -437,7 +429,7 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): if isinstance(grain, list): if value in grain: ret["comment"] = ( - "Value {1} is already in the list for grain {0}".format(name, value) + f"Value {value} is already in the list for grain {name}" ) return ret if __opts__["test"]: @@ -448,7 +440,7 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): ret["changes"] = {"added": value} return ret __salt__["grains.append"](name, value) - ret["comment"] = "Value {1} was added to grain {0}".format(name, value) + ret["comment"] = f"Value {value} was added to grain {name}" ret["changes"] = {"added": value} else: if convert is True: @@ -464,12 +456,12 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): grain = [] if grain is None else [grain] grain.append(value) __salt__["grains.setval"](name, grain) - ret["comment"] = "Value {1} was added to grain {0}".format(name, value) + ret["comment"] = f"Value {value} was added to grain {name}" ret["changes"] = {"added": value} else: ret["result"] = False - ret["comment"] = "Grain {} is not a valid list".format(name) + ret["comment"] = f"Grain {name} is not a valid list" else: ret["result"] = False - ret["comment"] = "Grain {} does not exist".format(name) + ret["comment"] = f"Grain {name} does not exist" return ret diff --git a/salt/states/group.py b/salt/states/group.py index 6180b661a6b..b0a70ac9abb 100644 --- a/salt/states/group.py +++ b/salt/states/group.py @@ -172,7 +172,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Group {} is present and up to date".format(name), + "comment": f"Group {name} is present and up to date", } if members is not None and (addusers is not None or delusers is not None): @@ -196,7 +196,7 @@ def present( if changes: ret["comment"] = "The following group attributes are set to be changed:\n" for key, val in changes.items(): - ret["comment"] += "{}: {}\n".format(key, val) + ret["comment"] += f"{key}: {val}\n" if __opts__["test"]: ret["result"] = None @@ -233,7 +233,7 @@ def present( # The group is not present, make it! if __opts__["test"]: ret["result"] = None - ret["comment"] = "Group {} set to be added".format(name) + ret["comment"] = f"Group {name} set to be added" return ret grps = __salt__["group.getent"]() @@ -267,7 +267,7 @@ def present( sys.modules[__salt__["test.ping"].__module__].__context__.pop( "group.getent", None ) - ret["comment"] = "New group {} created".format(name) + ret["comment"] = f"New group {name} created" ret["changes"] = __salt__["group.info"](name) changes = _changes(name, gid, addusers, delusers, members) if changes: @@ -279,7 +279,7 @@ def present( ret["changes"] = {"Failed": changes} else: ret["result"] = False - ret["comment"] = "Failed to create new group {}".format(name) + ret["comment"] = f"Failed to create new group {name}" return ret @@ -305,15 +305,15 @@ def absent(name): # Group already exists. Remove the group. if __opts__["test"]: ret["result"] = None - ret["comment"] = "Group {} is set for removal".format(name) + ret["comment"] = f"Group {name} is set for removal" return ret ret["result"] = __salt__["group.delete"](name) if ret["result"]: ret["changes"] = {name: ""} - ret["comment"] = "Removed group {}".format(name) + ret["comment"] = f"Removed group {name}" return ret else: - ret["comment"] = "Failed to remove group {}".format(name) + ret["comment"] = f"Failed to remove group {name}" return ret else: ret["comment"] = "Group not present" diff --git a/salt/states/heat.py b/salt/states/heat.py index c4a63133ee4..2e86486c972 100644 --- a/salt/states/heat.py +++ b/salt/states/heat.py @@ -108,7 +108,7 @@ def deployed( timeout=60, update=False, profile=None, - **connection_args + **connection_args, ): """ Deploy stack with the specified properties @@ -168,7 +168,7 @@ def deployed( existing_stack = __salt__["heat.show_stack"](name, profile=profile) if existing_stack["result"] and not update: - ret["comment"] = "Stack {} is deployed".format(name) + ret["comment"] = f"Stack {name} is deployed" return ret if existing_stack["result"] and update: if template: @@ -223,7 +223,7 @@ def deployed( salt.utils.files.safe_rm(template_tmp_file) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open template: {} {}".format( @@ -245,13 +245,13 @@ def deployed( checksum_stack = __salt__["hashutil.digest"](template_stack["template"]) except salt.exceptions.CommandExecutionError as cmdexc: ret["result"] = False - ret["comment"] = "{}".format(cmdexc) + ret["comment"] = f"{cmdexc}" if ret["result"] is True: if checksum_template == checksum_stack: if __opts__["test"]: ret["result"] = True - ret["comment"] = "Stack {} is deployed".format(name) + ret["comment"] = f"Stack {name} is deployed" return ret else: ret["result"] = False @@ -263,7 +263,7 @@ def deployed( if __opts__["test"]: stack = { "result": None, - "comment": "Stack {} is set to be updated".format(name), + "comment": f"Stack {name} is set to be updated", } else: stack = __salt__["heat.update_stack"]( @@ -282,7 +282,7 @@ def deployed( if __opts__["test"]: stack = { "result": None, - "comment": "Stack {} is set to be created".format(name), + "comment": f"Stack {name} is set to be created", } else: stack = __salt__["heat.create_stack"]( @@ -337,7 +337,7 @@ def absent(name, poll=5, timeout=60, profile=None): return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Stack {} is set to be removed".format(name) + ret["comment"] = f"Stack {name} is set to be removed" return ret stack = __salt__["heat.delete_stack"]( diff --git a/salt/states/helm.py b/salt/states/helm.py index f80a766a956..95d1e393655 100644 --- a/salt/states/helm.py +++ b/salt/states/helm.py @@ -99,7 +99,7 @@ def repo_managed( except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Failed to add some repositories: {}.".format(err) + ret["comment"] = f"Failed to add some repositories: {err}." return ret @@ -154,7 +154,7 @@ def repo_updated(name, namespace=None, flags=None, kvflags=None): except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Failed to update some repositories: {}.".format(err) + ret["comment"] = f"Failed to update some repositories: {err}." return ret @@ -226,7 +226,7 @@ def release_present( "name": name, "changes": {}, "result": True, - "comment": "Helm release {} is present".format(name), + "comment": f"Helm release {name} is present", } if "helm.status" not in __salt__: @@ -332,7 +332,7 @@ def release_absent(name, namespace=None, flags=None, kvflags=None): "name": name, "changes": {}, "result": True, - "comment": "Helm release {} is absent.".format(name), + "comment": f"Helm release {name} is absent.", } if "helm.uninstall" not in __salt__: diff --git a/salt/states/hg.py b/salt/states/hg.py index f4c5592a41f..f4045514e38 100644 --- a/salt/states/hg.py +++ b/salt/states/hg.py @@ -32,7 +32,7 @@ def __virtual__(): """ if __salt__["cmd.has_exec"](HG_BINARY): return True - return (False, "Command {} not found".format(HG_BINARY)) + return (False, f"Command {HG_BINARY} not found") def latest( @@ -88,7 +88,7 @@ def latest( if not target: return _fail(ret, '"target option is required') - is_repository = os.path.isdir(target) and os.path.isdir("{}/.hg".format(target)) + is_repository = os.path.isdir(target) and os.path.isdir(f"{target}/.hg") if is_repository: ret = _update_repo( @@ -103,7 +103,7 @@ def latest( log.debug('target %s is not found, "hg clone" is required', target) if __opts__["test"]: return _neutral_test( - ret, "Repository {} is about to be cloned to {}".format(name, target) + ret, f"Repository {name} is about to be cloned to {target}" ) _clone_repo(ret, target, name, user, identity, rev, opts) return ret @@ -117,7 +117,7 @@ def _update_repo(ret, name, target, clean, user, identity, rev, opts, update_hea current_rev = __salt__["hg.revision"](target, user=user, rev=".") if not current_rev: - return _fail(ret, "Seems that {} is not a valid hg repo".format(target)) + return _fail(ret, f"Seems that {target} is not a valid hg repo") if __opts__["test"]: return _neutral_test( @@ -167,12 +167,12 @@ def _update_repo(ret, name, target, clean, user, identity, rev, opts, update_hea new_rev = __salt__["hg.revision"](cwd=target, user=user, rev=".") if current_rev != new_rev: - revision_text = "{} => {}".format(current_rev, new_rev) + revision_text = f"{current_rev} => {new_rev}" log.info("Repository %s updated: %s", target, revision_text) - ret["comment"] = "Repository {} updated.".format(target) + ret["comment"] = f"Repository {target} updated." ret["changes"]["revision"] = revision_text elif "error:" in pull_out: - return _fail(ret, "An error was thrown by hg:\n{}".format(pull_out)) + return _fail(ret, f"An error was thrown by hg:\n{pull_out}") return ret @@ -216,7 +216,7 @@ def _clone_repo(ret, target, name, user, identity, rev, opts): return ret new_rev = __salt__["hg.revision"](cwd=target, user=user) - message = "Repository {} cloned to {}".format(name, target) + message = f"Repository {name} cloned to {target}" log.info(message) ret["comment"] = message diff --git a/salt/states/highstate_doc.py b/salt/states/highstate_doc.py index 83bc4db149e..8af62692521 100644 --- a/salt/states/highstate_doc.py +++ b/salt/states/highstate_doc.py @@ -35,7 +35,7 @@ def note(name, source=None, contents=None, **kwargs): """ comment = "" if source: - comment += "include file: {}\n".format(source) + comment += f"include file: {source}\n" if contents and len(contents) < 200: comment += contents return {"name": name, "result": True, "comment": comment, "changes": {}} diff --git a/salt/states/host.py b/salt/states/host.py index eadb30c00a2..078e4b9f0dc 100644 --- a/salt/states/host.py +++ b/salt/states/host.py @@ -144,7 +144,7 @@ def present(name, ip, comment="", clean=False): # pylint: disable=C0103 update_comment.add((addr, comment)) else: # No changes needed for this IP address and hostname - comments.append("Host {} ({}) already present".format(name, addr)) + comments.append(f"Host {name} ({addr}) already present") else: # IP address listed in hosts file, but hostname is not present. # We will need to add it. @@ -154,32 +154,30 @@ def present(name, ip, comment="", clean=False): # pylint: disable=C0103 update_comment.add((addr, comment)) else: ret["result"] = False - comments.append("Invalid IP Address for {} ({})".format(name, addr)) + comments.append(f"Invalid IP Address for {name} ({addr})") for addr, name in to_add: if __opts__["test"]: ret["result"] = None - comments.append("Host {} ({}) would be added".format(name, addr)) + comments.append(f"Host {name} ({addr}) would be added") else: if __salt__["hosts.add_host"](addr, name): - comments.append("Added host {} ({})".format(name, addr)) + comments.append(f"Added host {name} ({addr})") else: ret["result"] = False - comments.append("Failed to add host {} ({})".format(name, addr)) + comments.append(f"Failed to add host {name} ({addr})") continue ret["changes"].setdefault("added", {}).setdefault(addr, []).append(name) for addr, comment in update_comment: if __opts__["test"]: - comments.append("Comment for {} ({}) would be added".format(addr, comment)) + comments.append(f"Comment for {addr} ({comment}) would be added") else: if __salt__["hosts.set_comment"](addr, comment): - comments.append("Set comment for host {} ({})".format(addr, comment)) + comments.append(f"Set comment for host {addr} ({comment})") else: ret["result"] = False - comments.append( - "Failed to add comment for host {} ({})".format(addr, comment) - ) + comments.append(f"Failed to add comment for host {addr} ({comment})") continue ret["changes"].setdefault("comment_added", {}).setdefault(addr, []).append( comment @@ -188,13 +186,13 @@ def present(name, ip, comment="", clean=False): # pylint: disable=C0103 for addr, name in to_remove: if __opts__["test"]: ret["result"] = None - comments.append("Host {} ({}) would be removed".format(name, addr)) + comments.append(f"Host {name} ({addr}) would be removed") else: if __salt__["hosts.rm_host"](addr, name): - comments.append("Removed host {} ({})".format(name, addr)) + comments.append(f"Removed host {name} ({addr})") else: ret["result"] = False - comments.append("Failed to remove host {} ({})".format(name, addr)) + comments.append(f"Failed to remove host {name} ({addr})") continue ret["changes"].setdefault("removed", {}).setdefault(addr, []).append(name) @@ -221,15 +219,15 @@ def absent(name, ip): # pylint: disable=C0103 for _ip in ip: if not __salt__["hosts.has_pair"](_ip, name): ret["result"] = True - comments.append("Host {} ({}) already absent".format(name, _ip)) + comments.append(f"Host {name} ({_ip}) already absent") else: if __opts__["test"]: - comments.append("Host {} ({}) needs to be removed".format(name, _ip)) + comments.append(f"Host {name} ({_ip}) needs to be removed") else: if __salt__["hosts.rm_host"](_ip, name): ret["changes"] = {"host": name} ret["result"] = True - comments.append("Removed host {} ({})".format(name, _ip)) + comments.append(f"Removed host {name} ({_ip})") else: ret["result"] = False comments.append("Failed to remove host") @@ -263,12 +261,12 @@ def only(name, hostnames): new = " ".join(x.strip() for x in hostnames) if old == new: - ret["comment"] = 'IP address {} already set to "{}"'.format(name, new) + ret["comment"] = f'IP address {name} already set to "{new}"' ret["result"] = True return ret if __opts__["test"]: - ret["comment"] = 'Would change {} from "{}" to "{}"'.format(name, old, new) + ret["comment"] = f'Would change {name} from "{old}" to "{new}"' return ret ret["result"] = __salt__["hosts.set_host"](name, new) @@ -278,6 +276,6 @@ def only(name, hostnames): ) return ret - ret["comment"] = 'successfully changed {} from "{}" to "{}"'.format(name, old, new) + ret["comment"] = f'successfully changed {name} from "{old}" to "{new}"' ret["changes"] = {name: {"old": old, "new": new}} return ret diff --git a/salt/states/http.py b/salt/states/http.py index bef03f01309..3cb5485e0c3 100644 --- a/salt/states/http.py +++ b/salt/states/http.py @@ -25,7 +25,7 @@ def query( status=None, status_type="string", wait_for=None, - **kwargs + **kwargs, ): """ Perform an HTTP query and statefully return the result @@ -129,48 +129,48 @@ def query( if match_type == "string": if str(match) in data.get("text", ""): ret["result"] = True - ret["comment"] += ' Match text "{}" was found.'.format(match) + ret["comment"] += f' Match text "{match}" was found.' else: ret["result"] = False - ret["comment"] += ' Match text "{}" was not found.'.format(match) + ret["comment"] += f' Match text "{match}" was not found.' elif match_type == "pcre": if re.search(str(match), str(data.get("text", ""))): ret["result"] = True - ret["comment"] += ' Match pattern "{}" was found.'.format(match) + ret["comment"] += f' Match pattern "{match}" was found.' else: ret["result"] = False - ret["comment"] += ' Match pattern "{}" was not found.'.format(match) + ret["comment"] += f' Match pattern "{match}" was not found.' if status is not None: # Deals with case of status_type as a list of strings representing statuses if status_type == "list": for stat in status: if str(data.get("status", "")) == str(stat): - ret["comment"] += " Status {} was found.".format(stat) + ret["comment"] += f" Status {stat} was found." if ret["result"] is None: ret["result"] = True if ret["result"] is not True: - ret["comment"] += " Statuses {} were not found.".format(status) + ret["comment"] += f" Statuses {status} were not found." ret["result"] = False # Deals with the case of status_type representing a regex elif status_type == "pcre": if re.search(str(status), str(data.get("status", ""))): - ret["comment"] += ' Status pattern "{}" was found.'.format(status) + ret["comment"] += f' Status pattern "{status}" was found.' if ret["result"] is None: ret["result"] = True else: - ret["comment"] += ' Status pattern "{}" was not found.'.format(status) + ret["comment"] += f' Status pattern "{status}" was not found.' ret["result"] = False # Deals with the case of status_type as a single string representing a status elif status_type == "string": if str(data.get("status", "")) == str(status): - ret["comment"] += " Status {} was found.".format(status) + ret["comment"] += f" Status {status} was found." if ret["result"] is None: ret["result"] = True else: - ret["comment"] += " Status {} was not found.".format(status) + ret["comment"] += f" Status {status} was not found." ret["result"] = False # cleanup spaces in comment diff --git a/salt/states/icinga2.py b/salt/states/icinga2.py index f8134630cc1..a764cc4f7f6 100644 --- a/salt/states/icinga2.py +++ b/salt/states/icinga2.py @@ -97,7 +97,7 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): return ret elif output: if not overwrite and os.path.isfile(output): - ret["comment"] = "No execution needed. File {} already set".format(output) + ret["comment"] = f"No execution needed. File {output} already set" return ret elif __opts__["test"]: ret["result"] = None @@ -121,7 +121,7 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): if output == "grain": if grain and not key: __salt__["grains.setval"](grain, ticket) - ret["changes"]["ticket"] = "Executed. Output into grain: {}".format(grain) + ret["changes"]["ticket"] = f"Executed. Output into grain: {grain}" elif grain: if grain in __salt__["grains.ls"](): grain_value = __salt__["grains.get"](grain) @@ -133,7 +133,7 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): grain, key ) elif output: - ret["changes"]["ticket"] = "Executed. Output into {}".format(output) + ret["changes"]["ticket"] = f"Executed. Output into {output}" with salt.utils.files.fopen(output, "w") as output_file: output_file.write(salt.utils.stringutils.to_str(ticket)) else: @@ -150,8 +150,8 @@ def generate_cert(name): The domain name for which this certificate and key will be generated """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}{}.crt".format(get_certs_path(), name) - key = "{}{}.key".format(get_certs_path(), name) + cert = f"{get_certs_path()}{name}.crt" + key = f"{get_certs_path()}{name}.key" # Checking if execution is needed. if os.path.isfile(cert) and os.path.isfile(key): @@ -170,8 +170,8 @@ def generate_cert(name): cert_save = __salt__["icinga2.generate_cert"](name) if not cert_save["retcode"]: ret["comment"] = "Certificate and key generated" - ret["changes"]["cert"] = "Executed. Certificate saved: {}".format(cert) - ret["changes"]["key"] = "Executed. Key saved: {}".format(key) + ret["changes"]["cert"] = f"Executed. Certificate saved: {cert}" + ret["changes"]["key"] = f"Executed. Key saved: {key}" return ret @@ -186,11 +186,11 @@ def save_cert(name, master): Icinga2 master node for which this certificate will be saved """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}trusted-master.crt".format(get_certs_path()) + cert = f"{get_certs_path()}trusted-master.crt" # Checking if execution is needed. if os.path.isfile(cert): - ret["comment"] = "No execution needed. Cert: {} already saved.".format(cert) + ret["comment"] = f"No execution needed. Cert: {cert} already saved." return ret if __opts__["test"]: ret["result"] = None @@ -201,7 +201,7 @@ def save_cert(name, master): cert_save = __salt__["icinga2.save_cert"](name, master) if not cert_save["retcode"]: ret["comment"] = "Certificate for icinga2 master saved" - ret["changes"]["cert"] = "Executed. Certificate saved: {}".format(cert) + ret["changes"]["cert"] = f"Executed. Certificate saved: {cert}" return ret @@ -222,11 +222,11 @@ def request_cert(name, master, ticket, port="5665"): Icinga2 port, defaults to 5665 """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}ca.crt".format(get_certs_path()) + cert = f"{get_certs_path()}ca.crt" # Checking if execution is needed. if os.path.isfile(cert): - ret["comment"] = "No execution needed. Cert: {} already exists.".format(cert) + ret["comment"] = f"No execution needed. Cert: {cert} already exists." return ret if __opts__["test"]: ret["result"] = None @@ -237,7 +237,7 @@ def request_cert(name, master, ticket, port="5665"): cert_request = __salt__["icinga2.request_cert"](name, master, ticket, port) if not cert_request["retcode"]: ret["comment"] = "Certificate request from icinga2 master executed" - ret["changes"]["cert"] = "Executed. Certificate requested: {}".format(cert) + ret["changes"]["cert"] = f"Executed. Certificate requested: {cert}" return ret ret["comment"] = "FAILED. Certificate requested failed with output: {}".format( @@ -261,8 +261,8 @@ def node_setup(name, master, ticket): Authentication ticket generated on icinga2 master """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}{}.crt.orig".format(get_certs_path(), name) - key = "{}{}.key.orig".format(get_certs_path(), name) + cert = f"{get_certs_path()}{name}.crt.orig" + key = f"{get_certs_path()}{name}.key.orig" # Checking if execution is needed. if os.path.isfile(cert) and os.path.isfile(cert): diff --git a/salt/states/idem.py b/salt/states/idem.py index a7caba30ecd..b324f885671 100644 --- a/salt/states/idem.py +++ b/salt/states/idem.py @@ -30,13 +30,13 @@ def _get_refs(sources, tree): sls_sources = [] SLSs = [] if tree: - sls_sources.append("file://{}".format(tree)) + sls_sources.append(f"file://{tree}") for sls in sources: path = pathlib.Path(sls) if path.is_file(): ref = str(path.stem if path.suffix == ".sls" else path.name) SLSs.append(ref) - implied = "file://{}".format(path.parent) + implied = f"file://{path.parent}" if implied not in sls_sources: sls_sources.append(implied) else: @@ -152,7 +152,7 @@ def state( return { "name": name, "result": success, - "comment": "Ran {} idem states".format(len(running)) if success else errors, + "comment": f"Ran {len(running)} idem states" if success else errors, "changes": {}, "sub_state_run": running, } diff --git a/salt/states/ifttt.py b/salt/states/ifttt.py index f7378576783..4ab7f68df02 100644 --- a/salt/states/ifttt.py +++ b/salt/states/ifttt.py @@ -80,8 +80,8 @@ def trigger_event(name, event, value1=None, value2=None, value3=None): if ret and ret["result"]: ret["result"] = True - ret["comment"] = "Triggered Event: {}".format(name) + ret["comment"] = f"Triggered Event: {name}" else: - ret["comment"] = "Failed to trigger event: {}".format(name) + ret["comment"] = f"Failed to trigger event: {name}" return ret diff --git a/salt/states/incron.py b/salt/states/incron.py index 6baad30808f..d290ca7b681 100644 --- a/salt/states/incron.py +++ b/salt/states/incron.py @@ -119,26 +119,26 @@ def present(name, path, mask, cmd, user="root"): status = _check_cron(user, path, mask, cmd) ret["result"] = None if status == "absent": - ret["comment"] = "Incron {} is set to be added".format(name) + ret["comment"] = f"Incron {name} is set to be added" elif status == "present": ret["result"] = True - ret["comment"] = "Incron {} already present".format(name) + ret["comment"] = f"Incron {name} already present" elif status == "update": - ret["comment"] = "Incron {} is set to be updated".format(name) + ret["comment"] = f"Incron {name} is set to be updated" return ret data = __salt__["incron.set_job"](user=user, path=path, mask=mask, cmd=cmd) if data == "present": - ret["comment"] = "Incron {} already present".format(name) + ret["comment"] = f"Incron {name} already present" return ret if data == "new": - ret["comment"] = "Incron {} added to {}'s incrontab".format(name, user) + ret["comment"] = f"Incron {name} added to {user}'s incrontab" ret["changes"] = {user: name} return ret if data == "updated": - ret["comment"] = "Incron {} updated".format(name) + ret["comment"] = f"Incron {name} updated" ret["changes"] = {user: name} return ret ret["comment"] = "Incron {} for user {} failed to commit with error \n{}".format( @@ -180,17 +180,17 @@ def absent(name, path, mask, cmd, user="root"): ret["result"] = None if status == "absent": ret["result"] = True - ret["comment"] = "Incron {} is absent".format(name) + ret["comment"] = f"Incron {name} is absent" elif status == "present" or status == "update": - ret["comment"] = "Incron {} is set to be removed".format(name) + ret["comment"] = f"Incron {name} is set to be removed" return ret data = __salt__["incron.rm_job"](user=user, path=path, mask=mask, cmd=cmd) if data == "absent": - ret["comment"] = "Incron {} already absent".format(name) + ret["comment"] = f"Incron {name} already absent" return ret if data == "removed": - ret["comment"] = "Incron {} removed from {}'s crontab".format(name, user) + ret["comment"] = f"Incron {name} removed from {user}'s crontab" ret["changes"] = {user: name} return ret ret["comment"] = "Incron {} for user {} failed to commit with error {}".format( diff --git a/salt/states/influxdb08_database.py b/salt/states/influxdb08_database.py index fac790a0824..e2bfe5989d0 100644 --- a/salt/states/influxdb08_database.py +++ b/salt/states/influxdb08_database.py @@ -49,16 +49,16 @@ def present(name, user=None, password=None, host=None, port=None): ) return ret if __salt__["influxdb08.db_create"](name, user, password, host, port): - ret["comment"] = "Database {} has been created".format(name) + ret["comment"] = f"Database {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret # fallback - ret["comment"] = "Database {} is already present, so cannot be created".format(name) + ret["comment"] = f"Database {name} is already present, so cannot be created" return ret @@ -93,14 +93,14 @@ def absent(name, user=None, password=None, host=None, port=None): ) return ret if __salt__["influxdb08.db_remove"](name, user, password, host, port): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove database {}".format(name) + ret["comment"] = f"Failed to remove database {name}" ret["result"] = False return ret # fallback - ret["comment"] = "Database {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Database {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/influxdb08_user.py b/salt/states/influxdb08_user.py index 19865232692..e482287e6dc 100644 --- a/salt/states/influxdb08_user.py +++ b/salt/states/influxdb08_user.py @@ -53,7 +53,7 @@ def present( database, user, password, host, port ): ret["result"] = False - ret["comment"] = "Database {} does not exist".format(database) + ret["comment"] = f"Database {database} does not exist" return ret # check if user exists @@ -70,16 +70,16 @@ def present( if __salt__["influxdb08.user_create"]( name, passwd, database, user, password, host, port ): - ret["comment"] = "User {} has been created".format(name) + ret["comment"] = f"User {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create user {}".format(name) + ret["comment"] = f"Failed to create user {name}" ret["result"] = False return ret # fallback - ret["comment"] = "User {} is already present".format(name) + ret["comment"] = f"User {name} is already present" return ret @@ -112,19 +112,19 @@ def absent(name, database=None, user=None, password=None, host=None, port=None): if __salt__["influxdb08.user_exists"](name, database, user, password, host, port): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is present and needs to be removed".format(name) + ret["comment"] = f"User {name} is present and needs to be removed" return ret if __salt__["influxdb08.user_remove"]( name, database, user, password, host, port ): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove user {}".format(name) + ret["comment"] = f"Failed to remove user {name}" ret["result"] = False return ret # fallback - ret["comment"] = "User {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"User {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/influxdb_continuous_query.py b/salt/states/influxdb_continuous_query.py index d769c4d865c..c21dde4e5e0 100644 --- a/salt/states/influxdb_continuous_query.py +++ b/salt/states/influxdb_continuous_query.py @@ -42,7 +42,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "continuous query {} is already present".format(name), + "comment": f"continuous query {name} is already present", } if not __salt__["influxdb.continuous_query_exists"]( @@ -50,16 +50,16 @@ def present( ): if __opts__["test"]: ret["result"] = None - ret["comment"] = " {} is absent and will be created".format(name) + ret["comment"] = f" {name} is absent and will be created" return ret if __salt__["influxdb.create_continuous_query"]( database, name, query, resample_time, coverage_period, **client_args ): - ret["comment"] = "continuous query {} has been created".format(name) + ret["comment"] = f"continuous query {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create continuous query {}".format(name) + ret["comment"] = f"Failed to create continuous query {name}" ret["result"] = False return ret @@ -80,22 +80,22 @@ def absent(name, database, **client_args): "name": name, "changes": {}, "result": True, - "comment": "continuous query {} is not present".format(name), + "comment": f"continuous query {name} is not present", } if __salt__["influxdb.continuous_query_exists"](database, name, **client_args): if __opts__["test"]: ret["result"] = None ret["comment"] = ( - "continuous query {} is present and needs to be removed".format(name) + f"continuous query {name} is present and needs to be removed" ) return ret if __salt__["influxdb.drop_continuous_query"](database, name, **client_args): - ret["comment"] = "continuous query {} has been removed".format(name) + ret["comment"] = f"continuous query {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove continuous query {}".format(name) + ret["comment"] = f"Failed to remove continuous query {name}" ret["result"] = False return ret diff --git a/salt/states/influxdb_database.py b/salt/states/influxdb_database.py index cfa2a1c9d47..1a99df01801 100644 --- a/salt/states/influxdb_database.py +++ b/salt/states/influxdb_database.py @@ -26,20 +26,20 @@ def present(name, **client_args): "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(name), + "comment": f"Database {name} is already present", } if not __salt__["influxdb.db_exists"](name, **client_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is absent and will be created".format(name) + ret["comment"] = f"Database {name} is absent and will be created" return ret if __salt__["influxdb.create_db"](name, **client_args): - ret["comment"] = "Database {} has been created".format(name) + ret["comment"] = f"Database {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret @@ -57,7 +57,7 @@ def absent(name, **client_args): "name": name, "changes": {}, "result": True, - "comment": "Database {} is not present".format(name), + "comment": f"Database {name} is not present", } if __salt__["influxdb.db_exists"](name, **client_args): @@ -68,11 +68,11 @@ def absent(name, **client_args): ) return ret if __salt__["influxdb.drop_db"](name, **client_args): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove database {}".format(name) + ret["comment"] = f"Failed to remove database {name}" ret["result"] = False return ret diff --git a/salt/states/influxdb_retention_policy.py b/salt/states/influxdb_retention_policy.py index 2c4e7fae9ba..f63ffd24c21 100644 --- a/salt/states/influxdb_retention_policy.py +++ b/salt/states/influxdb_retention_policy.py @@ -59,7 +59,7 @@ def present(name, database, duration="7d", replication=1, default=False, **clien "name": name, "changes": {}, "result": True, - "comment": "retention policy {} is already present".format(name), + "comment": f"retention policy {name} is already present", } if not __salt__["influxdb.retention_policy_exists"]( @@ -67,16 +67,16 @@ def present(name, database, duration="7d", replication=1, default=False, **clien ): if __opts__["test"]: ret["result"] = None - ret["comment"] = " {} is absent and will be created".format(name) + ret["comment"] = f" {name} is absent and will be created" return ret if __salt__["influxdb.create_retention_policy"]( database, name, duration, replication, default, **client_args ): - ret["comment"] = "retention policy {} has been created".format(name) + ret["comment"] = f"retention policy {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create retention policy {}".format(name) + ret["comment"] = f"Failed to create retention policy {name}" ret["result"] = False return ret @@ -106,16 +106,16 @@ def present(name, database, duration="7d", replication=1, default=False, **clien if update_policy: if __opts__["test"]: ret["result"] = None - ret["comment"] = " {} is present and set to be changed".format(name) + ret["comment"] = f" {name} is present and set to be changed" return ret else: if __salt__["influxdb.alter_retention_policy"]( database, name, duration, replication, default, **client_args ): - ret["comment"] = "retention policy {} has been changed".format(name) + ret["comment"] = f"retention policy {name} has been changed" return ret else: - ret["comment"] = "Failed to update retention policy {}".format(name) + ret["comment"] = f"Failed to update retention policy {name}" ret["result"] = False return ret @@ -136,22 +136,22 @@ def absent(name, database, **client_args): "name": name, "changes": {}, "result": True, - "comment": "retention policy {} is not present".format(name), + "comment": f"retention policy {name} is not present", } if __salt__["influxdb.retention_policy_exists"](database, name, **client_args): if __opts__["test"]: ret["result"] = None ret["comment"] = ( - "retention policy {} is present and needs to be removed".format(name) + f"retention policy {name} is present and needs to be removed" ) return ret if __salt__["influxdb.drop_retention_policy"](database, name, **client_args): - ret["comment"] = "retention policy {} has been removed".format(name) + ret["comment"] = f"retention policy {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove retention policy {}".format(name) + ret["comment"] = f"Failed to remove retention policy {name}" ret["result"] = False return ret diff --git a/salt/states/influxdb_user.py b/salt/states/influxdb_user.py index 7088a84ed8a..ea48c6854d4 100644 --- a/salt/states/influxdb_user.py +++ b/salt/states/influxdb_user.py @@ -55,20 +55,20 @@ def present(name, passwd, admin=False, grants=None, **client_args): "name": name, "changes": {}, "result": True, - "comment": "User {} is present and up to date".format(name), + "comment": f"User {name} is present and up to date", } if not __salt__["influxdb.user_exists"](name, **client_args): create = True if __opts__["test"]: - ret["comment"] = "User {} will be created".format(name) + ret["comment"] = f"User {name} will be created" ret["result"] = None return ret else: if not __salt__["influxdb.create_user"]( name, passwd, admin=admin, **client_args ): - ret["comment"] = "Failed to create user {}".format(name) + ret["comment"] = f"Failed to create user {name}" ret["result"] = False return ret else: @@ -104,7 +104,7 @@ def present(name, passwd, admin=False, grants=None, **client_args): del db_privileges[database] if database not in db_privileges: ret["changes"][ - "Grant on database {} to user {}".format(database, name) + f"Grant on database {database} to user {name}" ] = privilege if not __opts__["test"]: __salt__["influxdb.grant_privilege"]( @@ -113,19 +113,19 @@ def present(name, passwd, admin=False, grants=None, **client_args): if ret["changes"]: if create: - ret["comment"] = "Created user {}".format(name) + ret["comment"] = f"Created user {name}" ret["changes"][name] = "User created" else: if __opts__["test"]: ret["result"] = None ret["comment"] = ( - "User {} will be updated with the following changes:".format(name) + f"User {name} will be updated with the following changes:" ) for k, v in ret["changes"].items(): - ret["comment"] += "\n{} => {}".format(k, v) + ret["comment"] += f"\n{k} => {v}" ret["changes"] = {} else: - ret["comment"] = "Updated user {}".format(name) + ret["comment"] = f"Updated user {name}" return ret @@ -141,21 +141,21 @@ def absent(name, **client_args): "name": name, "changes": {}, "result": True, - "comment": "User {} is not present".format(name), + "comment": f"User {name} is not present", } if __salt__["influxdb.user_exists"](name, **client_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} will be removed".format(name) + ret["comment"] = f"User {name} will be removed" return ret else: if __salt__["influxdb.remove_user"](name, **client_args): - ret["comment"] = "Removed user {}".format(name) + ret["comment"] = f"Removed user {name}" ret["changes"][name] = "removed" return ret else: - ret["comment"] = "Failed to remove user {}".format(name) + ret["comment"] = f"Failed to remove user {name}" ret["result"] = False return ret return ret diff --git a/salt/states/infoblox_host_record.py b/salt/states/infoblox_host_record.py index 49f6f0fb15f..3b1cace0ed3 100644 --- a/salt/states/infoblox_host_record.py +++ b/salt/states/infoblox_host_record.py @@ -131,7 +131,7 @@ def present(name=None, data=None, ensure_data=True, **api_opts): if __opts__["test"]: ret["result"] = None - ret["comment"] = "would attempt to create infoblox record {}".format(name) + ret["comment"] = f"would attempt to create infoblox record {name}" return ret new_obj_ref = __salt__["infoblox.create_host"](data=data, **api_opts) diff --git a/salt/states/infoblox_range.py b/salt/states/infoblox_range.py index 6eb0d193ebd..20783323420 100644 --- a/salt/states/infoblox_range.py +++ b/salt/states/infoblox_range.py @@ -132,7 +132,7 @@ def present(name=None, start_addr=None, end_addr=None, data=None, **api_opts): if __opts__["test"]: ret["result"] = None - ret["comment"] = "would attempt to create record {}".format(name) + ret["comment"] = f"would attempt to create record {name}" return ret new_obj_ref = __salt__["infoblox.create_ipv4_range"](data, **api_opts) @@ -199,7 +199,7 @@ def absent(name=None, start_addr=None, end_addr=None, data=None, **api_opts): if __salt__["infoblox.delete_object"](objref=obj["_ref"]): ret["result"] = True ret["changes"] = { - "old": "Found {} - {}".format(start_addr, end_addr), + "old": f"Found {start_addr} - {end_addr}", "new": "Removed", } return ret diff --git a/salt/states/ini_manage.py b/salt/states/ini_manage.py index 5d5e7159bf9..9851d792734 100644 --- a/salt/states/ini_manage.py +++ b/salt/states/ini_manage.py @@ -70,12 +70,12 @@ def options_present(name, sections=None, separator="=", strict=False): for option in options: if option in original_top_level_opts: if str(original_top_level_opts[option]) == str(options[option]): - ret["comment"] += "Unchanged key {}.\n".format(option) + ret["comment"] += f"Unchanged key {option}.\n" else: - ret["comment"] += "Changed key {}.\n".format(option) + ret["comment"] += f"Changed key {option}.\n" ret["result"] = None else: - ret["comment"] += "Changed key {}.\n".format(option) + ret["comment"] += f"Changed key {option}.\n" ret["result"] = None else: options_updated = __salt__["ini.set_option"](name, options, separator) @@ -83,7 +83,7 @@ def options_present(name, sections=None, separator="=", strict=False): if strict: for opt_to_remove in set(original_top_level_opts).difference(options): if __opts__["test"]: - ret["comment"] += "Removed key {}.\n".format(opt_to_remove) + ret["comment"] += f"Removed key {opt_to_remove}.\n" ret["result"] = None else: __salt__["ini.remove_option"]( @@ -150,7 +150,7 @@ def options_present(name, sections=None, separator="=", strict=False): if not __opts__["test"]: changes = __salt__["ini.set_option"](name, sections, separator) except (OSError, KeyError) as err: - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" ret["result"] = False return ret if "error" in changes: @@ -198,7 +198,7 @@ def options_absent(name, sections=None, separator="="): try: cur_section = __salt__["ini.get_section"](name, section, separator) except OSError as err: - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" ret["result"] = False return ret except AttributeError: @@ -211,14 +211,14 @@ def options_absent(name, sections=None, separator="="): key, section_name ) continue - ret["comment"] += "Deleted key {}{}.\n".format(key, section_name) + ret["comment"] += f"Deleted key {key}{section_name}.\n" ret["result"] = None else: option = section if not __salt__["ini.get_option"](name, None, option, separator): - ret["comment"] += "Key {} does not exist.\n".format(option) + ret["comment"] += f"Key {option} does not exist.\n" continue - ret["comment"] += "Deleted key {}.\n".format(option) + ret["comment"] += f"Deleted key {option}.\n" ret["result"] = None if ret["comment"] == "": @@ -232,7 +232,7 @@ def options_absent(name, sections=None, separator="="): name, section, key, separator ) except OSError as err: - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" ret["result"] = False return ret if not current_value: @@ -277,14 +277,14 @@ def sections_present(name, sections=None, separator="="): cur_ini = __salt__["ini.get_ini"](name, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret for section in sections or {}: if section in cur_ini: - ret["comment"] += "Section unchanged {}.\n".format(section) + ret["comment"] += f"Section unchanged {section}.\n" continue else: - ret["comment"] += "Created new section {}.\n".format(section) + ret["comment"] += f"Created new section {section}.\n" ret["result"] = None if ret["comment"] == "": ret["comment"] = "No changes detected." @@ -296,7 +296,7 @@ def sections_present(name, sections=None, separator="="): changes = __salt__["ini.set_option"](name, section_to_update, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret if "error" in changes: ret["result"] = False @@ -334,13 +334,13 @@ def sections_absent(name, sections=None, separator="="): cur_ini = __salt__["ini.get_ini"](name, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret for section in sections or []: if section not in cur_ini: - ret["comment"] += "Section {} does not exist.\n".format(section) + ret["comment"] += f"Section {section} does not exist.\n" continue - ret["comment"] += "Deleted section {}.\n".format(section) + ret["comment"] += f"Deleted section {section}.\n" ret["result"] = None if ret["comment"] == "": ret["comment"] = "No changes detected." @@ -350,7 +350,7 @@ def sections_absent(name, sections=None, separator="="): cur_section = __salt__["ini.remove_section"](name, section, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret if not cur_section: continue diff --git a/salt/states/ipmi.py b/salt/states/ipmi.py index 3f408590b49..51448b66329 100644 --- a/salt/states/ipmi.py +++ b/salt/states/ipmi.py @@ -131,7 +131,7 @@ def power(name="power_on", wait=300, **kwargs): return ret if __opts__["test"]: - ret["comment"] = "would power: {} system".format(name) + ret["comment"] = f"would power: {name} system" ret["result"] = None ret["changes"] = {"old": org, "new": name} return ret @@ -152,7 +152,7 @@ def user_present( link_auth=True, ipmi_msg=True, privilege_level="administrator", - **kwargs + **kwargs, ): """ Ensure IPMI user and user privileges. @@ -259,7 +259,7 @@ def user_present( link_auth, ipmi_msg, privilege_level, - **kwargs + **kwargs, ) current_user = __salt__["ipmi.get_user"](uid=uid, channel=channel, **kwargs) ret["comment"] = "(re)created user" diff --git a/salt/states/ipset.py b/salt/states/ipset.py index dd8535a4d28..8132e0b5f19 100644 --- a/salt/states/ipset.py +++ b/salt/states/ipset.py @@ -87,17 +87,17 @@ def set_present(name, set_type, family="ipv4", **kwargs): set_check = __salt__["ipset.check_set"](name) if set_check is True: ret["result"] = True - ret["comment"] = "ipset set {} already exists for {}".format(name, family) + ret["comment"] = f"ipset set {name} already exists for {family}" return ret if __opts__["test"]: - ret["comment"] = "ipset set {} would be added for {}".format(name, family) + ret["comment"] = f"ipset set {name} would be added for {family}" return ret command = __salt__["ipset.new_set"](name, set_type, family, **kwargs) if command is True: ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "ipset set {} created successfully for {}".format(name, family) + ret["comment"] = f"ipset set {name} created successfully for {family}" return ret else: ret["result"] = False @@ -122,10 +122,10 @@ def set_absent(name, family="ipv4", **kwargs): set_check = __salt__["ipset.check_set"](name, family) if not set_check: ret["result"] = True - ret["comment"] = "ipset set {} for {} is already absent".format(name, family) + ret["comment"] = f"ipset set {name} for {family} is already absent" return ret if __opts__["test"]: - ret["comment"] = "ipset set {} for {} would be removed".format(name, family) + ret["comment"] = f"ipset set {name} for {family} would be removed" return ret flush_set = __salt__["ipset.flush"](name, family) if flush_set: @@ -310,7 +310,7 @@ def flush(name, family="ipv4", **kwargs): set_check = __salt__["ipset.check_set"](name) if set_check is False: ret["result"] = False - ret["comment"] = "ipset set {} does not exist for {}".format(name, family) + ret["comment"] = f"ipset set {name} does not exist for {family}" return ret if __opts__["test"]: @@ -321,7 +321,7 @@ def flush(name, family="ipv4", **kwargs): if __salt__["ipset.flush"](name, family): ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Flushed ipset entries from set {} for {}".format(name, family) + ret["comment"] = f"Flushed ipset entries from set {name} for {family}" return ret else: ret["result"] = False diff --git a/salt/states/iptables.py b/salt/states/iptables.py index 8917f624087..57c8b287cb0 100644 --- a/salt/states/iptables.py +++ b/salt/states/iptables.py @@ -737,7 +737,7 @@ def delete(name, table="filter", family="ipv4", **kwargs): if not result: ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Delete iptables rule for {} {}".format(name, command.strip()) + ret["comment"] = f"Delete iptables rule for {name} {command.strip()}" if "save" in kwargs and kwargs["save"]: if kwargs["save"] is not True: filename = kwargs["save"] diff --git a/salt/states/jboss7.py b/salt/states/jboss7.py index 1b018196244..9f1dfdb4c30 100644 --- a/salt/states/jboss7.py +++ b/salt/states/jboss7.py @@ -578,7 +578,7 @@ def __get_artifact(salt_source): except Exception as e: # pylint: disable=broad-except log.debug(traceback.format_exc()) - comment = "Unable to manage file: {}".format(e) + comment = f"Unable to manage file: {e}" else: resolved_source = salt_source["target_file"] @@ -674,9 +674,7 @@ def __check_dict_contains(dct, dict_name, keys, comment="", result=True): for key in keys: if key not in dct.keys(): result = False - comment = __append_comment( - "Missing {} in {}".format(key, dict_name), comment - ) + comment = __append_comment(f"Missing {key} in {dict_name}", comment) return result, comment diff --git a/salt/states/jenkins.py b/salt/states/jenkins.py index 4386577a420..b55b05a3716 100644 --- a/salt/states/jenkins.py +++ b/salt/states/jenkins.py @@ -55,7 +55,7 @@ def present(name, config=None, **kwargs): "name": name, "result": True, "changes": {}, - "comment": ["Job {} is up to date.".format(name)], + "comment": [f"Job {name} is up to date."], } if __salt__["jenkins.job_exists"](name): @@ -78,7 +78,7 @@ def present(name, config=None, **kwargs): return _fail(ret, exc.strerror) else: ret["changes"] = "".join(diff) - ret["comment"].append("Job '{}' updated.".format(name)) + ret["comment"].append(f"Job '{name}' updated.") else: cached_source_path = __salt__["cp.cache_file"](config, __env__) @@ -93,7 +93,7 @@ def present(name, config=None, **kwargs): buf = io.StringIO(new_config_xml) diff = difflib.unified_diff("", buf.readlines(), lineterm="") ret["changes"][name] = "".join(diff) - ret["comment"].append("Job '{}' added.".format(name)) + ret["comment"].append(f"Job '{name}' added.") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -114,7 +114,7 @@ def absent(name, **kwargs): except CommandExecutionError as exc: return _fail(ret, exc.strerror) else: - ret["comment"] = "Job '{}' deleted.".format(name) + ret["comment"] = f"Job '{name}' deleted." else: - ret["comment"] = "Job '{}' already absent.".format(name) + ret["comment"] = f"Job '{name}' already absent." return ret diff --git a/salt/states/kapacitor.py b/salt/states/kapacitor.py index 07d33b2457c..94dc7477c49 100644 --- a/salt/states/kapacitor.py +++ b/salt/states/kapacitor.py @@ -75,7 +75,7 @@ def task_present( if not dbrps: dbrps = [] if database and retention_policy: - dbrp = "{}.{}".format(database, retention_policy) + dbrp = f"{database}.{retention_policy}" dbrps.append(dbrp) task_dbrps = [ {"db": dbrp[0], "rp": dbrp[1]} for dbrp in (dbrp.split(".") for dbrp in dbrps) diff --git a/salt/states/keyboard.py b/salt/states/keyboard.py index 0670a431c08..d8c0ede0d61 100644 --- a/salt/states/keyboard.py +++ b/salt/states/keyboard.py @@ -37,15 +37,15 @@ def system(name): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["keyboard.get_sys"]() == name: ret["result"] = True - ret["comment"] = "System layout {} already set".format(name) + ret["comment"] = f"System layout {name} already set" return ret if __opts__["test"]: - ret["comment"] = "System layout {} needs to be set".format(name) + ret["comment"] = f"System layout {name} needs to be set" return ret if __salt__["keyboard.set_sys"](name): ret["changes"] = {"layout": name} ret["result"] = True - ret["comment"] = "Set system keyboard layout {}".format(name) + ret["comment"] = f"Set system keyboard layout {name}" return ret else: ret["result"] = False @@ -63,15 +63,15 @@ def xorg(name): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["keyboard.get_x"]() == name: ret["result"] = True - ret["comment"] = "XOrg layout {} already set".format(name) + ret["comment"] = f"XOrg layout {name} already set" return ret if __opts__["test"]: - ret["comment"] = "XOrg layout {} needs to be set".format(name) + ret["comment"] = f"XOrg layout {name} needs to be set" return ret if __salt__["keyboard.set_x"](name): ret["changes"] = {"layout": name} ret["result"] = True - ret["comment"] = "Set XOrg keyboard layout {}".format(name) + ret["comment"] = f"Set XOrg keyboard layout {name}" return ret else: ret["result"] = False diff --git a/salt/states/keystone.py b/salt/states/keystone.py index eeab1ce27c4..f3ea1f5ceaa 100644 --- a/salt/states/keystone.py +++ b/salt/states/keystone.py @@ -112,7 +112,7 @@ def user_present( profile=None, password_reset=True, project=None, - **connection_args + **connection_args, ): """ Ensure that the keystone user is present with the specified properties. @@ -162,7 +162,7 @@ def user_present( "name": name, "changes": {}, "result": True, - "comment": 'User "{}" will be updated'.format(name), + "comment": f'User "{name}" will be updated', } _api_version(profile=profile, **connection_args) @@ -177,7 +177,7 @@ def user_present( ) if "Error" in tenantdata: ret["result"] = False - ret["comment"] = 'Tenant / project "{}" does not exist'.format(tenant) + ret["comment"] = f'Tenant / project "{tenant}" does not exist' return ret tenant_id = tenantdata[tenant]["id"] else: @@ -213,52 +213,52 @@ def user_present( change_email or change_enabled or change_tenant or change_password ): ret["result"] = None - ret["comment"] = 'User "{}" will be updated'.format(name) + ret["comment"] = f'User "{name}" will be updated' if change_email is True: ret["changes"]["Email"] = "Will be updated" if change_enabled is True: ret["changes"]["Enabled"] = "Will be True" if change_tenant is True: - ret["changes"]["Tenant"] = 'Will be added to "{}" tenant'.format(tenant) + ret["changes"]["Tenant"] = f'Will be added to "{tenant}" tenant' if change_password is True: ret["changes"]["Password"] = "Will be updated" return ret - ret["comment"] = 'User "{}" is already present'.format(name) + ret["comment"] = f'User "{name}" is already present' if change_email: __salt__["keystone.user_update"]( name=name, email=email, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) + ret["comment"] = f'User "{name}" has been updated' ret["changes"]["Email"] = "Updated" if change_enabled: __salt__["keystone.user_update"]( name=name, enabled=enabled, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) - ret["changes"]["Enabled"] = "Now {}".format(enabled) + ret["comment"] = f'User "{name}" has been updated' + ret["changes"]["Enabled"] = f"Now {enabled}" if change_tenant: __salt__["keystone.user_update"]( name=name, tenant=tenant, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) - ret["changes"]["Tenant"] = 'Added to "{}" tenant'.format(tenant) + ret["comment"] = f'User "{name}" has been updated' + ret["changes"]["Tenant"] = f'Added to "{tenant}" tenant' if change_password: __salt__["keystone.user_password_update"]( name=name, password=password, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) + ret["comment"] = f'User "{name}" has been updated' ret["changes"]["Password"] = "Updated" if roles: for tenant in roles: args = dict( {"user_name": name, "tenant_name": tenant, "profile": profile}, - **connection_args + **connection_args, ) tenant_roles = __salt__["keystone.user_role_list"](**args) for role in roles[tenant]: @@ -276,7 +276,7 @@ def user_present( "tenant": tenant, "profile": profile, }, - **connection_args + **connection_args, ) newrole = __salt__["keystone.user_role_add"](**addargs) if "roles" in ret["changes"]: @@ -298,7 +298,7 @@ def user_present( "tenant": tenant, "profile": profile, }, - **connection_args + **connection_args, ) oldrole = __salt__["keystone.user_role_remove"](**addargs) if "roles" in ret["changes"]: @@ -309,7 +309,7 @@ def user_present( # Create that user! if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Keystone user "{}" will be added'.format(name) + ret["comment"] = f'Keystone user "{name}" will be added' ret["changes"]["User"] = "Will be created" return ret __salt__["keystone.user_create"]( @@ -319,7 +319,7 @@ def user_present( tenant_id=tenant_id, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) if roles: for tenant in roles: @@ -329,9 +329,9 @@ def user_present( role=role, tenant=tenant, profile=profile, - **connection_args + **connection_args, ) - ret["comment"] = "Keystone user {} has been added".format(name) + ret["comment"] = f"Keystone user {name} has been added" ret["changes"]["User"] = "Created" return ret @@ -348,7 +348,7 @@ def user_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'User "{}" is already absent'.format(name), + "comment": f'User "{name}" is already absent', } # Check if user is present @@ -356,11 +356,11 @@ def user_absent(name, profile=None, **connection_args): if "Error" not in user: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'User "{}" will be deleted'.format(name) + ret["comment"] = f'User "{name}" will be deleted' return ret # Delete that user! __salt__["keystone.user_delete"](name=name, profile=profile, **connection_args) - ret["comment"] = 'User "{}" has been deleted'.format(name) + ret["comment"] = f'User "{name}" has been deleted' ret["changes"]["User"] = "Deleted" return ret @@ -385,7 +385,7 @@ def tenant_present( "name": name, "changes": {}, "result": True, - "comment": 'Tenant / project "{}" already exists'.format(name), + "comment": f'Tenant / project "{name}" already exists', } _api_version(profile=profile, **connection_args) @@ -399,7 +399,7 @@ def tenant_present( if tenant[name].get("description", None) != description: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be updated'.format(name) + ret["comment"] = f'Tenant / project "{name}" will be updated' ret["changes"]["Description"] = "Will be updated" return ret __salt__["keystone.tenant_update"]( @@ -407,29 +407,29 @@ def tenant_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) - ret["comment"] = 'Tenant / project "{}" has been updated'.format(name) + ret["comment"] = f'Tenant / project "{name}" has been updated' ret["changes"]["Description"] = "Updated" if tenant[name].get("enabled", None) != enabled: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be updated'.format(name) - ret["changes"]["Enabled"] = "Will be {}".format(enabled) + ret["comment"] = f'Tenant / project "{name}" will be updated' + ret["changes"]["Enabled"] = f"Will be {enabled}" return ret __salt__["keystone.tenant_update"]( name=name, description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) - ret["comment"] = 'Tenant / project "{}" has been updated'.format(name) - ret["changes"]["Enabled"] = "Now {}".format(enabled) + ret["comment"] = f'Tenant / project "{name}" has been updated' + ret["changes"]["Enabled"] = f"Now {enabled}" else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be added'.format(name) + ret["comment"] = f'Tenant / project "{name}" will be added' ret["changes"]["Tenant"] = "Will be created" return ret # Create tenant @@ -440,7 +440,7 @@ def tenant_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) else: created = __salt__["keystone.tenant_create"]( @@ -448,11 +448,11 @@ def tenant_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) ret["changes"]["Tenant"] = "Created" if created is True else "Failed" ret["result"] = created - ret["comment"] = 'Tenant / project "{}" has been added'.format(name) + ret["comment"] = f'Tenant / project "{name}" has been added' return ret @@ -467,7 +467,7 @@ def tenant_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Tenant / project "{}" is already absent'.format(name), + "comment": f'Tenant / project "{name}" is already absent', } # Check if tenant is present @@ -477,13 +477,13 @@ def tenant_absent(name, profile=None, **connection_args): if "Error" not in tenant: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be deleted'.format(name) + ret["comment"] = f'Tenant / project "{name}" will be deleted' return ret # Delete tenant __salt__["keystone.tenant_delete"]( name=name, profile=profile, **connection_args ) - ret["comment"] = 'Tenant / project "{}" has been deleted'.format(name) + ret["comment"] = f'Tenant / project "{name}" has been deleted' ret["changes"]["Tenant/Project"] = "Deleted" return ret @@ -522,7 +522,7 @@ def project_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) @@ -558,7 +558,7 @@ def role_present(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Role "{}" already exists'.format(name), + "comment": f'Role "{name}" already exists', } # Check if role is already present @@ -569,11 +569,11 @@ def role_present(name, profile=None, **connection_args): else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Role "{}" will be added'.format(name) + ret["comment"] = f'Role "{name}" will be added' return ret # Create role __salt__["keystone.role_create"](name, profile=profile, **connection_args) - ret["comment"] = 'Role "{}" has been added'.format(name) + ret["comment"] = f'Role "{name}" has been added' ret["changes"]["Role"] = "Created" return ret @@ -589,7 +589,7 @@ def role_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Role "{}" is already absent'.format(name), + "comment": f'Role "{name}" is already absent', } # Check if role is present @@ -597,11 +597,11 @@ def role_absent(name, profile=None, **connection_args): if "Error" not in role: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Role "{}" will be deleted'.format(name) + ret["comment"] = f'Role "{name}" will be deleted' return ret # Delete role __salt__["keystone.role_delete"](name=name, profile=profile, **connection_args) - ret["comment"] = 'Role "{}" has been deleted'.format(name) + ret["comment"] = f'Role "{name}" has been deleted' ret["changes"]["Role"] = "Deleted" return ret @@ -626,7 +626,7 @@ def service_present( "name": name, "changes": {}, "result": True, - "comment": 'Service "{}" already exists'.format(name), + "comment": f'Service "{name}" already exists', } # Check if service is already present @@ -639,13 +639,13 @@ def service_present( else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Service "{}" will be added'.format(name) + ret["comment"] = f'Service "{name}" will be added' return ret # Create service __salt__["keystone.service_create"]( name, service_type, description, profile=profile, **connection_args ) - ret["comment"] = 'Service "{}" has been added'.format(name) + ret["comment"] = f'Service "{name}" has been added' ret["changes"]["Service"] = "Created" return ret @@ -662,7 +662,7 @@ def service_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Service "{}" is already absent'.format(name), + "comment": f'Service "{name}" is already absent', } # Check if service is present @@ -672,13 +672,13 @@ def service_absent(name, profile=None, **connection_args): if "Error" not in role: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Service "{}" will be deleted'.format(name) + ret["comment"] = f'Service "{name}" will be deleted' return ret # Delete service __salt__["keystone.service_delete"]( name=name, profile=profile, **connection_args ) - ret["comment"] = 'Service "{}" has been deleted'.format(name) + ret["comment"] = f'Service "{name}" has been deleted' ret["changes"]["Service"] = "Deleted" return ret @@ -693,7 +693,7 @@ def endpoint_present( profile=None, url=None, interface=None, - **connection_args + **connection_args, ): """ Ensure the specified endpoints exists for service @@ -740,7 +740,7 @@ def endpoint_present( url=url, interface=interface, profile=profile, - **connection_args + **connection_args, ) else: ret["changes"] = __salt__["keystone.endpoint_create"]( @@ -750,7 +750,7 @@ def endpoint_present( adminurl=adminurl, internalurl=internalurl, profile=profile, - **connection_args + **connection_args, ) if endpoint and "Error" not in endpoint and endpoint.get("region") == region: @@ -844,20 +844,20 @@ def endpoint_present( name, region, profile=profile, interface=interface, **connection_args ) _create_endpoint() - ret["comment"] += 'Endpoint for service "{}" has been updated'.format(name) + ret["comment"] += f'Endpoint for service "{name}" has been updated' else: # Add new endpoint if __opts__.get("test"): ret["result"] = None ret["changes"]["Endpoint"] = "Will be created" - ret["comment"] = 'Endpoint for service "{}" will be added'.format(name) + ret["comment"] = f'Endpoint for service "{name}" will be added' return ret _create_endpoint() - ret["comment"] = 'Endpoint for service "{}" has been added'.format(name) + ret["comment"] = f'Endpoint for service "{name}" has been added' if ret["comment"] == "": # => no changes - ret["comment"] = 'Endpoint for service "{}" already exists'.format(name) + ret["comment"] = f'Endpoint for service "{name}" already exists' return ret @@ -881,7 +881,7 @@ def endpoint_absent(name, region=None, profile=None, interface=None, **connectio "result": True, "comment": 'Endpoint for service "{}"{} is already absent'.format( name, - ', interface "{}",'.format(interface) if interface is not None else "", + f', interface "{interface}",' if interface is not None else "", ), } @@ -894,7 +894,7 @@ def endpoint_absent(name, region=None, profile=None, interface=None, **connectio else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Endpoint for service "{}" will be deleted'.format(name) + ret["comment"] = f'Endpoint for service "{name}" will be deleted' return ret # Delete service __salt__["keystone.endpoint_delete"]( @@ -902,7 +902,7 @@ def endpoint_absent(name, region=None, profile=None, interface=None, **connectio ) ret["comment"] = 'Endpoint for service "{}"{} has been deleted'.format( name, - ', interface "{}",'.format(interface) if interface is not None else "", + f', interface "{interface}",' if interface is not None else "", ) ret["changes"]["endpoint"] = "Deleted" return ret diff --git a/salt/states/keystone_domain.py b/salt/states/keystone_domain.py index a639aec50f3..b722238ae73 100644 --- a/salt/states/keystone_domain.py +++ b/salt/states/keystone_domain.py @@ -64,7 +64,7 @@ def present(name, auth=None, **kwargs): if __opts__["test"]: ret["result"] = None ret["changes"] = kwargs - ret["comment"] = "Domain {} will be created.".format(name) + ret["comment"] = f"Domain {name} will be created." return ret kwargs["name"] = name @@ -78,7 +78,7 @@ def present(name, auth=None, **kwargs): if __opts__["test"]: ret["result"] = None ret["changes"] = changes - ret["comment"] = "Domain {} will be updated.".format(name) + ret["comment"] = f"Domain {name} will be updated." return ret kwargs["domain_id"] = domain.id @@ -106,7 +106,7 @@ def absent(name, auth=None): if __opts__["test"] is True: ret["result"] = None ret["changes"] = {"name": name} - ret["comment"] = "Domain {} will be deleted.".format(name) + ret["comment"] = f"Domain {name} will be deleted." return ret __salt__["keystoneng.domain_delete"](name=domain) diff --git a/salt/states/keystore.py b/salt/states/keystore.py index de1586e1a5f..9e6abb72769 100644 --- a/salt/states/keystore.py +++ b/salt/states/keystore.py @@ -146,12 +146,12 @@ def managed(name, passphrase, entries, force_remove=False): log.debug("Will remove: %s", remove_list) for alias_name in remove_list: if __opts__["test"]: - ret["comment"] += "Alias {} would have been removed".format(alias_name) + ret["comment"] += f"Alias {alias_name} would have been removed" ret["result"] = None else: __salt__["keystore.remove"](alias_name, name, passphrase) ret["changes"][alias_name] = "Removed" - ret["comment"] += "Alias {} removed.\n".format(alias_name) + ret["comment"] += f"Alias {alias_name} removed.\n" if not ret["changes"] and not ret["comment"]: ret["comment"] = "No changes made.\n" diff --git a/salt/states/kmod.py b/salt/states/kmod.py index 0bb257412f3..92b8cb8e7b7 100644 --- a/salt/states/kmod.py +++ b/salt/states/kmod.py @@ -84,7 +84,7 @@ def present(name, persist=False, mods=None): # Intersection of loaded and proposed modules already_loaded = list(set(loaded_mods) & set(mods)) if len(already_loaded) == 1: - comment = "Kernel module {} is already present".format(already_loaded[0]) + comment = f"Kernel module {already_loaded[0]} is already present" _append_comment(ret, comment) elif len(already_loaded) > 1: comment = "Kernel modules {} are already present".format( @@ -103,7 +103,7 @@ def present(name, persist=False, mods=None): if ret["comment"]: ret["comment"] += "\n" if len(not_loaded) == 1: - comment = "Kernel module {} is set to be loaded".format(not_loaded[0]) + comment = f"Kernel module {not_loaded[0]} is set to be loaded" else: comment = "Kernel modules {} are set to be loaded".format( ", ".join(not_loaded) @@ -115,7 +115,7 @@ def present(name, persist=False, mods=None): unavailable = list(set(not_loaded) - set(__salt__["kmod.available"]())) if unavailable: if len(unavailable) == 1: - comment = "Kernel module {} is unavailable".format(unavailable[0]) + comment = f"Kernel module {unavailable[0]} is unavailable" else: comment = "Kernel modules {} are unavailable".format(", ".join(unavailable)) _append_comment(ret, comment) @@ -161,7 +161,7 @@ def present(name, persist=False, mods=None): if loaded["failed"]: for mod, msg in loaded["failed"]: - _append_comment(ret, "Failed to load kernel module {}: {}".format(mod, msg)) + _append_comment(ret, f"Failed to load kernel module {mod}: {msg}") return ret @@ -205,7 +205,7 @@ def absent(name, persist=False, comment=True, mods=None): ret["result"] = None if len(to_unload) == 1: _append_comment( - ret, "Kernel module {} is set to be removed".format(to_unload[0]) + ret, f"Kernel module {to_unload[0]} is set to be removed" ) elif len(to_unload) > 1: _append_comment( @@ -252,15 +252,13 @@ def absent(name, persist=False, comment=True, mods=None): if unloaded["failed"]: for mod, msg in unloaded["failed"]: - _append_comment( - ret, "Failed to remove kernel module {}: {}".format(mod, msg) - ) + _append_comment(ret, f"Failed to remove kernel module {mod}: {msg}") return ret else: if len(mods) == 1: - ret["comment"] = "Kernel module {} is already removed".format(mods[0]) + ret["comment"] = f"Kernel module {mods[0]} is already removed" else: ret["comment"] = "Kernel modules {} are already removed".format( ", ".join(mods) diff --git a/salt/states/kubernetes.py b/salt/states/kubernetes.py index ed78f34ab30..687ead546f0 100644 --- a/salt/states/kubernetes.py +++ b/salt/states/kubernetes.py @@ -136,7 +136,7 @@ def deployment_absent(name, namespace="default", **kwargs): ret["changes"] = {"kubernetes.deployment": {"new": "absent", "old": "present"}} ret["comment"] = res["message"] else: - ret["comment"] = "Something went wrong, response: {}".format(res) + ret["comment"] = f"Something went wrong, response: {res}" return ret @@ -148,7 +148,7 @@ def deployment_present( spec=None, source="", template="", - **kwargs + **kwargs, ): """ Ensures that the named deployment is present inside of the specified @@ -203,9 +203,9 @@ def deployment_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) - ret["changes"]["{}.{}".format(namespace, name)] = {"old": {}, "new": res} + ret["changes"][f"{namespace}.{name}"] = {"old": {}, "new": res} else: if __opts__["test"]: ret["result"] = None @@ -222,7 +222,7 @@ def deployment_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) ret["changes"] = {"metadata": metadata, "spec": spec} @@ -237,7 +237,7 @@ def service_present( spec=None, source="", template="", - **kwargs + **kwargs, ): """ Ensures that the named service is present inside of the specified namespace @@ -292,9 +292,9 @@ def service_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) - ret["changes"]["{}.{}".format(namespace, name)] = {"old": {}, "new": res} + ret["changes"][f"{namespace}.{name}"] = {"old": {}, "new": res} else: if __opts__["test"]: ret["result"] = None @@ -312,7 +312,7 @@ def service_present( template=template, old_service=service, saltenv=__env__, - **kwargs + **kwargs, ) ret["changes"] = {"metadata": metadata, "spec": spec} @@ -351,7 +351,7 @@ def service_absent(name, namespace="default", **kwargs): ret["changes"] = {"kubernetes.service": {"new": "absent", "old": "present"}} ret["comment"] = res["message"] else: - ret["comment"] = "Something went wrong, response: {}".format(res) + ret["comment"] = f"Something went wrong, response: {res}" return ret @@ -391,7 +391,7 @@ def namespace_absent(name, **kwargs): else: ret["comment"] = "Terminating" else: - ret["comment"] = "Something went wrong, response: {}".format(res) + ret["comment"] = f"Something went wrong, response: {res}" return ret @@ -506,9 +506,9 @@ def secret_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) - ret["changes"]["{}.{}".format(namespace, name)] = {"old": {}, "new": res} + ret["changes"][f"{namespace}.{name}"] = {"old": {}, "new": res} else: if __opts__["test"]: ret["result"] = None @@ -525,7 +525,7 @@ def secret_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) ret["changes"] = { @@ -620,9 +620,9 @@ def configmap_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) - ret["changes"]["{}.{}".format(namespace, name)] = {"old": {}, "new": res} + ret["changes"][f"{namespace}.{name}"] = {"old": {}, "new": res} else: if __opts__["test"]: ret["result"] = None @@ -639,7 +639,7 @@ def configmap_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) ret["changes"] = {"data": res["data"]} @@ -681,7 +681,7 @@ def pod_absent(name, namespace="default", **kwargs): else: ret["comment"] = res["message"] else: - ret["comment"] = "Something went wrong, response: {}".format(res) + ret["comment"] = f"Something went wrong, response: {res}" return ret @@ -693,7 +693,7 @@ def pod_present( spec=None, source="", template="", - **kwargs + **kwargs, ): """ Ensures that the named pod is present inside of the specified @@ -748,9 +748,9 @@ def pod_present( source=source, template=template, saltenv=__env__, - **kwargs + **kwargs, ) - ret["changes"]["{}.{}".format(namespace, name)] = {"old": {}, "new": res} + ret["changes"][f"{namespace}.{name}"] = {"old": {}, "new": res} else: if __opts__["test"]: ret["result"] = None @@ -896,7 +896,7 @@ def node_label_present(name, node, value, **kwargs): old_labels = copy.copy(labels) labels[name] = value - ret["changes"]["{}.{}".format(node, name)] = {"old": old_labels, "new": labels} + ret["changes"][f"{node}.{name}"] = {"old": old_labels, "new": labels} ret["result"] = True return ret diff --git a/salt/states/layman.py b/salt/states/layman.py index 00d65c458be..6a7a552f12a 100644 --- a/salt/states/layman.py +++ b/salt/states/layman.py @@ -31,15 +31,15 @@ def present(name): # Overlay already present if name in __salt__["layman.list_local"](): - ret["comment"] = "Overlay {} already present".format(name) + ret["comment"] = f"Overlay {name} already present" elif __opts__["test"]: - ret["comment"] = "Overlay {} is set to be added".format(name) + ret["comment"] = f"Overlay {name} is set to be added" ret["result"] = None return ret else: # Does the overlay exist? if name not in __salt__["layman.list_all"](): - ret["comment"] = "Overlay {} not found".format(name) + ret["comment"] = f"Overlay {name} not found" ret["result"] = False else: # Attempt to add the overlay @@ -47,12 +47,12 @@ def present(name): # The overlay failed to add if len(changes) < 1: - ret["comment"] = "Overlay {} failed to add".format(name) + ret["comment"] = f"Overlay {name} failed to add" ret["result"] = False # Success else: ret["changes"]["added"] = changes - ret["comment"] = "Overlay {} added.".format(name) + ret["comment"] = f"Overlay {name} added." return ret @@ -68,9 +68,9 @@ def absent(name): # Overlay is already absent if name not in __salt__["layman.list_local"](): - ret["comment"] = "Overlay {} already absent".format(name) + ret["comment"] = f"Overlay {name} already absent" elif __opts__["test"]: - ret["comment"] = "Overlay {} is set to be deleted".format(name) + ret["comment"] = f"Overlay {name} is set to be deleted" ret["result"] = None return ret else: @@ -79,11 +79,11 @@ def absent(name): # The overlay failed to delete if len(changes) < 1: - ret["comment"] = "Overlay {} failed to delete".format(name) + ret["comment"] = f"Overlay {name} failed to delete" ret["result"] = False # Success else: ret["changes"]["deleted"] = changes - ret["comment"] = "Overlay {} deleted.".format(name) + ret["comment"] = f"Overlay {name} deleted." return ret diff --git a/salt/states/libcloud_dns.py b/salt/states/libcloud_dns.py index a78a5d17dde..d9d6c41ff08 100644 --- a/salt/states/libcloud_dns.py +++ b/salt/states/libcloud_dns.py @@ -185,6 +185,6 @@ def record_absent(name, zone, type, data, profile): matching_zone["id"], record["id"], profile ) ) - return state_result(all(result), "Removed {} records".format(len(result)), name) + return state_result(all(result), f"Removed {len(result)} records", name) else: return state_result(True, "Records already absent", name) diff --git a/salt/states/linux_acl.py b/salt/states/linux_acl.py index 582b6bb8b7d..9143c91bd52 100644 --- a/salt/states/linux_acl.py +++ b/salt/states/linux_acl.py @@ -105,7 +105,7 @@ def present(name, acl_type, acl_name="", perms="", recurse=False, force=False): _octal_lookup = {0: "-", 1: "r", 2: "w", 4: "x"} if not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" ret["result"] = False return ret @@ -220,7 +220,7 @@ def present(name, acl_type, acl_name="", perms="", recurse=False, force=False): ) ret.update( { - "comment": "Updated permissions for {}".format(acl_name), + "comment": f"Updated permissions for {acl_name}", "result": True, "changes": changes, } @@ -261,7 +261,7 @@ def present(name, acl_type, acl_name="", perms="", recurse=False, force=False): ) ret.update( { - "comment": "Applied new permissions for {}".format(acl_name), + "comment": f"Applied new permissions for {acl_name}", "result": True, "changes": changes, } @@ -305,7 +305,7 @@ def absent(name, acl_type, acl_name="", perms="", recurse=False): ret = {"name": name, "result": True, "changes": {}, "comment": ""} if not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" ret["result"] = False return ret @@ -403,7 +403,7 @@ def list_present(name, acl_type, acl_names=None, perms="", recurse=False, force= _octal = {"r": 4, "w": 2, "x": 1, "-": 0} _octal_perms = sum(_octal.get(i, i) for i in perms) if not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" ret["result"] = False return ret @@ -692,7 +692,7 @@ def list_absent(name, acl_type, acl_names=None, recurse=False): ret = {"name": name, "result": True, "changes": {}, "comment": ""} if not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" ret["result"] = False return ret diff --git a/salt/states/locale.py b/salt/states/locale.py index 856e17d2747..2fd35a4a29f 100644 --- a/salt/states/locale.py +++ b/salt/states/locale.py @@ -40,23 +40,23 @@ def system(name): try: if __salt__["locale.get_locale"]() == name: ret["result"] = True - ret["comment"] = "System locale {} already set".format(name) + ret["comment"] = f"System locale {name} already set" return ret if __opts__["test"]: - ret["comment"] = "System locale {} needs to be set".format(name) + ret["comment"] = f"System locale {name} needs to be set" return ret if __salt__["locale.set_locale"](name): ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Set system locale {}".format(name) + ret["comment"] = f"Set system locale {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to set system locale to {}".format(name) + ret["comment"] = f"Failed to set system locale to {name}" return ret except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Failed to set system locale: {}".format(err) + ret["comment"] = f"Failed to set system locale: {err}" return ret @@ -73,17 +73,17 @@ def present(name): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["locale.avail"](name): ret["result"] = True - ret["comment"] = "Locale {} is already present".format(name) + ret["comment"] = f"Locale {name} is already present" return ret if __opts__["test"]: - ret["comment"] = "Locale {} needs to be generated".format(name) + ret["comment"] = f"Locale {name} needs to be generated" return ret if __salt__["locale.gen_locale"](name): ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Generated locale {}".format(name) + ret["comment"] = f"Generated locale {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to generate locale {}".format(name) + ret["comment"] = f"Failed to generate locale {name}" return ret diff --git a/salt/states/logadm.py b/salt/states/logadm.py index d2b33e32b4f..e1f81b4e014 100644 --- a/salt/states/logadm.py +++ b/salt/states/logadm.py @@ -152,12 +152,12 @@ def remove(name, log_file=None): res = __salt__["logadm.remove"](name if name else log_file) ret["result"] = "Error" not in res if ret["result"]: - ret["comment"] = "Configuration for {} removed.".format(log_file) + ret["comment"] = f"Configuration for {log_file} removed." ret["changes"][log_file] = None else: ret["comment"] = res["Error"] else: ret["result"] = True - ret["comment"] = "No configuration for {} present.".format(log_file) + ret["comment"] = f"No configuration for {log_file} present." return ret diff --git a/salt/states/logrotate.py b/salt/states/logrotate.py index aaeb49cec0f..d65d2ce28ac 100644 --- a/salt/states/logrotate.py +++ b/salt/states/logrotate.py @@ -84,10 +84,10 @@ def set_(name, key, value, setting=None, conf_file=_DEFAULT_CONF): value = _convert_if_int(value) if current_value == value: - ret["comment"] = "Command '{}' already has value: {}".format(key, value) + ret["comment"] = f"Command '{key}' already has value: {value}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Command '{}' will be set to value: {}".format(key, value) + ret["comment"] = f"Command '{key}' will be set to value: {value}" ret["changes"] = {"old": current_value, "new": value} else: ret["changes"] = {"old": current_value, "new": value} @@ -95,7 +95,7 @@ def set_(name, key, value, setting=None, conf_file=_DEFAULT_CONF): key=key, value=value, conf_file=conf_file ) if ret["result"]: - ret["comment"] = "Set command '{}' value: {}".format(key, value) + ret["comment"] = f"Set command '{key}' value: {value}" else: ret["comment"] = "Unable to set command '{}' value: {}".format( key, value diff --git a/salt/states/loop.py b/salt/states/loop.py index e99ab55abbe..a2434daeff2 100644 --- a/salt/states/loop.py +++ b/salt/states/loop.py @@ -95,7 +95,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60 m_kwargs = {} if name not in __salt__: - ret["comment"] = "Cannot find module {}".format(name) + ret["comment"] = f"Cannot find module {name}" elif condition is None: ret["comment"] = "An exit condition must be specified" elif not isinstance(period, (int, float)): @@ -103,7 +103,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60 elif not isinstance(timeout, (int, float)): ret["comment"] = "Timeout must be specified as a float in seconds" elif __opts__["test"]: - ret["comment"] = "The execution module {} will be run".format(name) + ret["comment"] = f"The execution module {name} will be run" ret["result"] = None else: if m_args is None: @@ -116,7 +116,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60 m_ret = __salt__[name](*m_args, **m_kwargs) if eval(condition): # pylint: disable=W0123 ret["result"] = True - ret["comment"] = "Condition {} was met".format(condition) + ret["comment"] = f"Condition {condition} was met" break time.sleep(period) else: @@ -161,7 +161,7 @@ def until_no_eval( """ ret = {"name": name, "comment": "", "changes": {}, "result": False} if name not in __salt__: - ret["comment"] = 'Module.function "{}" is unavailable.'.format(name) + ret["comment"] = f'Module.function "{name}" is unavailable.' elif not isinstance(period, (int, float)): ret["comment"] = "Period must be specified as a float in seconds" elif not isinstance(timeout, (int, float)): @@ -171,7 +171,7 @@ def until_no_eval( elif compare_operator in __utils__: comparator = __utils__[compare_operator] elif not hasattr(operator, compare_operator): - ret["comment"] = 'Invalid operator "{}" supplied.'.format(compare_operator) + ret["comment"] = f'Invalid operator "{compare_operator}" supplied.' else: comparator = getattr(operator, compare_operator) if __opts__["test"]: diff --git a/salt/states/lvm.py b/salt/states/lvm.py index a7a1df8b609..5b4bdad8696 100644 --- a/salt/states/lvm.py +++ b/salt/states/lvm.py @@ -50,7 +50,7 @@ def _convert_to_mb(size): if str_size[-1:].isdigit(): size = int(str_size) else: - raise salt.exceptions.ArgumentValueError("Size {} is invalid.".format(size)) + raise salt.exceptions.ArgumentValueError(f"Size {size} is invalid.") if unit == "s": target_size = size / 2048 @@ -63,7 +63,7 @@ def _convert_to_mb(size): elif unit == "p": target_size = size * 1024 * 1024 * 1024 else: - raise salt.exceptions.ArgumentValueError("Unit {} is invalid.".format(unit)) + raise salt.exceptions.ArgumentValueError(f"Unit {unit} is invalid.") return target_size @@ -81,19 +81,19 @@ def pv_present(name, **kwargs): ret = {"changes": {}, "comment": "", "name": name, "result": True} if __salt__["lvm.pvdisplay"](name, quiet=True): - ret["comment"] = "Physical Volume {} already present".format(name) + ret["comment"] = f"Physical Volume {name} already present" elif __opts__["test"]: - ret["comment"] = "Physical Volume {} is set to be created".format(name) + ret["comment"] = f"Physical Volume {name} is set to be created" ret["result"] = None return ret else: changes = __salt__["lvm.pvcreate"](name, **kwargs) if __salt__["lvm.pvdisplay"](name): - ret["comment"] = "Created Physical Volume {}".format(name) + ret["comment"] = f"Created Physical Volume {name}" ret["changes"]["created"] = changes else: - ret["comment"] = "Failed to create Physical Volume {}".format(name) + ret["comment"] = f"Failed to create Physical Volume {name}" ret["result"] = False return ret @@ -108,19 +108,19 @@ def pv_absent(name): ret = {"changes": {}, "comment": "", "name": name, "result": True} if not __salt__["lvm.pvdisplay"](name, quiet=True): - ret["comment"] = "Physical Volume {} does not exist".format(name) + ret["comment"] = f"Physical Volume {name} does not exist" elif __opts__["test"]: - ret["comment"] = "Physical Volume {} is set to be removed".format(name) + ret["comment"] = f"Physical Volume {name} is set to be removed" ret["result"] = None return ret else: changes = __salt__["lvm.pvremove"](name) if __salt__["lvm.pvdisplay"](name, quiet=True): - ret["comment"] = "Failed to remove Physical Volume {}".format(name) + ret["comment"] = f"Failed to remove Physical Volume {name}" ret["result"] = False else: - ret["comment"] = "Removed Physical Volume {}".format(name) + ret["comment"] = f"Removed Physical Volume {name}" ret["changes"]["removed"] = changes return ret @@ -144,23 +144,23 @@ def vg_present(name, devices=None, **kwargs): devices = devices.split(",") if __salt__["lvm.vgdisplay"](name, quiet=True): - ret["comment"] = "Volume Group {} already present".format(name) + ret["comment"] = f"Volume Group {name} already present" for device in devices: realdev = os.path.realpath(device) pvs = __salt__["lvm.pvdisplay"](realdev, real=True) if pvs and pvs.get(realdev, None): if pvs[realdev]["Volume Group Name"] == name: ret["comment"] = "{}\n{}".format( - ret["comment"], "{} is part of Volume Group".format(device) + ret["comment"], f"{device} is part of Volume Group" ) elif pvs[realdev]["Volume Group Name"] in ["", "#orphans_lvm2"]: __salt__["lvm.vgextend"](name, device) pvs = __salt__["lvm.pvdisplay"](realdev, real=True) if pvs[realdev]["Volume Group Name"] == name: - ret["changes"].update({device: "added to {}".format(name)}) + ret["changes"].update({device: f"added to {name}"}) else: ret["comment"] = "{}\n{}".format( - ret["comment"], "{} could not be added".format(device) + ret["comment"], f"{device} could not be added" ) ret["result"] = False else: @@ -173,21 +173,21 @@ def vg_present(name, devices=None, **kwargs): ret["result"] = False else: ret["comment"] = "{}\n{}".format( - ret["comment"], "pv {} is not present".format(device) + ret["comment"], f"pv {device} is not present" ) ret["result"] = False elif __opts__["test"]: - ret["comment"] = "Volume Group {} is set to be created".format(name) + ret["comment"] = f"Volume Group {name} is set to be created" ret["result"] = None return ret else: changes = __salt__["lvm.vgcreate"](name, devices, **kwargs) if __salt__["lvm.vgdisplay"](name): - ret["comment"] = "Created Volume Group {}".format(name) + ret["comment"] = f"Created Volume Group {name}" ret["changes"]["created"] = changes else: - ret["comment"] = "Failed to create Volume Group {}".format(name) + ret["comment"] = f"Failed to create Volume Group {name}" ret["result"] = False return ret @@ -202,19 +202,19 @@ def vg_absent(name): ret = {"changes": {}, "comment": "", "name": name, "result": True} if not __salt__["lvm.vgdisplay"](name, quiet=True): - ret["comment"] = "Volume Group {} already absent".format(name) + ret["comment"] = f"Volume Group {name} already absent" elif __opts__["test"]: - ret["comment"] = "Volume Group {} is set to be removed".format(name) + ret["comment"] = f"Volume Group {name} is set to be removed" ret["result"] = None return ret else: changes = __salt__["lvm.vgremove"](name) if not __salt__["lvm.vgdisplay"](name, quiet=True): - ret["comment"] = "Removed Volume Group {}".format(name) + ret["comment"] = f"Removed Volume Group {name}" ret["changes"]["removed"] = changes else: - ret["comment"] = "Failed to remove Volume Group {}".format(name) + ret["comment"] = f"Failed to remove Volume Group {name}" ret["result"] = False return ret @@ -230,7 +230,7 @@ def lv_present( thinpool=False, force=False, resizefs=False, - **kwargs + **kwargs, ): """ Ensure that a Logical Volume is present, creating it if absent. @@ -299,14 +299,14 @@ def lv_present( if thinvolume: lvpath = "/dev/{}/{}".format(vgname.split("/")[0], name) else: - lvpath = "/dev/{}/{}".format(vgname, name) + lvpath = f"/dev/{vgname}/{name}" lv_info = __salt__["lvm.lvdisplay"](lvpath, quiet=True) lv_info = lv_info.get(lvpath) if not lv_info: if __opts__["test"]: - ret["comment"] = "Logical Volume {} is set to be created".format(name) + ret["comment"] = f"Logical Volume {name} is set to be created" ret["result"] = None return ret else: @@ -320,11 +320,11 @@ def lv_present( thinvolume=thinvolume, thinpool=thinpool, force=force, - **kwargs + **kwargs, ) if __salt__["lvm.lvdisplay"](lvpath): - ret["comment"] = "Created Logical Volume {}".format(name) + ret["comment"] = f"Created Logical Volume {name}" ret["changes"]["created"] = changes else: ret["comment"] = "Failed to create Logical Volume {}. Error: {}".format( @@ -332,7 +332,7 @@ def lv_present( ) ret["result"] = False else: - ret["comment"] = "Logical Volume {} already present".format(name) + ret["comment"] = f"Logical Volume {name} already present" if size or extents: old_extents = int(lv_info["Current Logical Extents Associated"]) @@ -386,7 +386,7 @@ def lv_present( lv_info = __salt__["lvm.lvdisplay"](lvpath, quiet=True)[lvpath] new_size_mb = _convert_to_mb(lv_info["Logical Volume Size"] + "s") if new_size_mb != old_size_mb: - ret["comment"] = "Resized Logical Volume {}".format(name) + ret["comment"] = f"Resized Logical Volume {name}" ret["changes"]["resized"] = changes else: ret["comment"] = ( @@ -410,20 +410,20 @@ def lv_absent(name, vgname=None): """ ret = {"changes": {}, "comment": "", "name": name, "result": True} - lvpath = "/dev/{}/{}".format(vgname, name) + lvpath = f"/dev/{vgname}/{name}" if not __salt__["lvm.lvdisplay"](lvpath, quiet=True): - ret["comment"] = "Logical Volume {} already absent".format(name) + ret["comment"] = f"Logical Volume {name} already absent" elif __opts__["test"]: - ret["comment"] = "Logical Volume {} is set to be removed".format(name) + ret["comment"] = f"Logical Volume {name} is set to be removed" ret["result"] = None return ret else: changes = __salt__["lvm.lvremove"](name, vgname) if not __salt__["lvm.lvdisplay"](lvpath, quiet=True): - ret["comment"] = "Removed Logical Volume {}".format(name) + ret["comment"] = f"Removed Logical Volume {name}" ret["changes"]["removed"] = changes else: - ret["comment"] = "Failed to remove Logical Volume {}".format(name) + ret["comment"] = f"Failed to remove Logical Volume {name}" ret["result"] = False return ret diff --git a/salt/states/lvs_service.py b/salt/states/lvs_service.py index 8aee6a062f0..5a1981d4426 100644 --- a/salt/states/lvs_service.py +++ b/salt/states/lvs_service.py @@ -53,7 +53,7 @@ def present( protocol=protocol, service_address=service_address, scheduler=scheduler ) if service_rule_check is True: - ret["comment"] = "LVS Service {} is present".format(name) + ret["comment"] = f"LVS Service {name} is present" return ret else: if __opts__["test"]: @@ -71,17 +71,17 @@ def present( scheduler=scheduler, ) if service_edit is True: - ret["comment"] = "LVS Service {} has been updated".format(name) + ret["comment"] = f"LVS Service {name} has been updated" ret["changes"][name] = "Update" return ret else: ret["result"] = False - ret["comment"] = "LVS Service {} update failed".format(name) + ret["comment"] = f"LVS Service {name} update failed" return ret else: if __opts__["test"]: ret["comment"] = ( - "LVS Service {} is not present and needs to be created".format(name) + f"LVS Service {name} is not present and needs to be created" ) ret["result"] = None return ret @@ -90,7 +90,7 @@ def present( protocol=protocol, service_address=service_address, scheduler=scheduler ) if service_add is True: - ret["comment"] = "LVS Service {} has been created".format(name) + ret["comment"] = f"LVS Service {name} has been created" ret["changes"][name] = "Present" return ret else: @@ -131,7 +131,7 @@ def absent(name, protocol=None, service_address=None): protocol=protocol, service_address=service_address ) if service_delete is True: - ret["comment"] = "LVS Service {} has been removed".format(name) + ret["comment"] = f"LVS Service {name} has been removed" ret["changes"][name] = "Absent" return ret else: @@ -141,8 +141,6 @@ def absent(name, protocol=None, service_address=None): ret["result"] = False return ret else: - ret["comment"] = ( - "LVS Service {} is not present, so it cannot be removed".format(name) - ) + ret["comment"] = f"LVS Service {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/lxc.py b/salt/states/lxc.py index 98ccd67fcb2..05b7081d122 100644 --- a/salt/states/lxc.py +++ b/salt/states/lxc.py @@ -150,7 +150,7 @@ def present( ret = { "name": name, "result": True, - "comment": "Container '{}' already exists".format(name), + "comment": f"Container '{name}' already exists", "changes": {}, } @@ -178,17 +178,17 @@ def present( # Sanity check(s) if clone_from and not __salt__["lxc.exists"](clone_from, path=path): ret["result"] = False - ret["comment"] = "Clone source '{}' does not exist".format(clone_from) + ret["comment"] = f"Clone source '{clone_from}' does not exist" if not ret["result"]: return ret - action = "cloned from {}".format(clone_from) if clone_from else "created" + action = f"cloned from {clone_from}" if clone_from else "created" state = {"old": __salt__["lxc.state"](name, path=path)} if __opts__["test"]: if state["old"] is None: ret["comment"] = "Container '{}' will be {}".format( - name, "cloned from {}".format(clone_from) if clone_from else "created" + name, f"cloned from {clone_from}" if clone_from else "created" ) ret["result"] = None return ret @@ -209,7 +209,7 @@ def present( return ret else: if state["old"] in ("frozen", "running"): - ret["comment"] = "Container '{}' would be stopped".format(name) + ret["comment"] = f"Container '{name}' would be stopped" ret["result"] = None return ret else: @@ -256,7 +256,7 @@ def present( clone_from, name ) else: - ret["comment"] = "Created container '{}'".format(name) + ret["comment"] = f"Created container '{name}'" state["new"] = result["state"]["new"] if ret["result"] is True: @@ -278,7 +278,7 @@ def present( ret["comment"] += error except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret["comment"] += "{}: {}".format(error, exc) + ret["comment"] += f"{error}: {exc}" else: if state["old"] is None: ret["comment"] += ", and the container was started" @@ -301,12 +301,12 @@ def present( ret["comment"] += error except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret["comment"] += "{}: {}".format(error, exc) + ret["comment"] += f"{error}: {exc}" else: if state["old"] is None: ret["comment"] += ", and the container was stopped" else: - ret["comment"] = "Container '{}' was stopped".format(name) + ret["comment"] = f"Container '{name}' was stopped" if "new" not in state: # Make sure we know the final state of the container before we return @@ -345,7 +345,7 @@ def absent(name, stop=False, path=None): "name": name, "changes": {}, "result": True, - "comment": "Container '{}' does not exist".format(name), + "comment": f"Container '{name}' does not exist", } if not __salt__["lxc.exists"](name, path=path): @@ -353,17 +353,17 @@ def absent(name, stop=False, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be destroyed".format(name) + ret["comment"] = f"Container '{name}' would be destroyed" return ret try: result = __salt__["lxc.destroy"](name, stop=stop, path=path) except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret["comment"] = "Failed to destroy container: {}".format(exc) + ret["comment"] = f"Failed to destroy container: {exc}" else: ret["changes"]["state"] = result["state"] - ret["comment"] = "Container '{}' was destroyed".format(name) + ret["comment"] = f"Container '{name}' was destroyed" return ret @@ -407,14 +407,14 @@ def running(name, restart=False, path=None): ret = { "name": name, "result": True, - "comment": "Container '{}' is already running".format(name), + "comment": f"Container '{name}' is already running", "changes": {}, } state = {"old": __salt__["lxc.state"](name, path=path)} if state["old"] is None: ret["result"] = False - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" return ret elif state["old"] == "running" and not restart: return ret @@ -435,7 +435,7 @@ def running(name, restart=False, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be {}".format(name, action[1]) + ret["comment"] = f"Container '{name}' would be {action[1]}" return ret try: @@ -454,7 +454,7 @@ def running(name, restart=False, path=None): state["new"] = result["state"]["new"] if state["new"] != "running": ret["result"] = False - ret["comment"] = "Unable to {} container '{}'".format(action[0], name) + ret["comment"] = f"Unable to {action[0]} container '{name}'" else: ret["comment"] = "Container '{}' was successfully {}".format( name, action[1] @@ -507,17 +507,17 @@ def frozen(name, start=True, path=None): ret = { "name": name, "result": True, - "comment": "Container '{}' is already frozen".format(name), + "comment": f"Container '{name}' is already frozen", "changes": {}, } state = {"old": __salt__["lxc.state"](name, path=path)} if state["old"] is None: ret["result"] = False - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" elif state["old"] == "stopped" and not start: ret["result"] = False - ret["comment"] = "Container '{}' is stopped".format(name) + ret["comment"] = f"Container '{name}' is stopped" if ret["result"] is False or state["old"] == "frozen": return ret @@ -529,7 +529,7 @@ def frozen(name, start=True, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be {}".format(name, action[1]) + ret["comment"] = f"Container '{name}' would be {action[1]}" return ret try: @@ -542,7 +542,7 @@ def frozen(name, start=True, path=None): state["new"] = result["state"]["new"] if state["new"] != "frozen": ret["result"] = False - ret["comment"] = "Unable to {} container '{}'".format(action[0], name) + ret["comment"] = f"Unable to {action[0]} container '{name}'" else: ret["comment"] = "Container '{}' was successfully {}".format( name, action[1] @@ -594,14 +594,14 @@ def stopped(name, kill=False, path=None): ret = { "name": name, "result": True, - "comment": "Container '{}' is already stopped".format(name), + "comment": f"Container '{name}' is already stopped", "changes": {}, } state = {"old": __salt__["lxc.state"](name, path=path)} if state["old"] is None: ret["result"] = False - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" return ret elif state["old"] == "stopped": return ret @@ -613,7 +613,7 @@ def stopped(name, kill=False, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be {}".format(name, action[1]) + ret["comment"] = f"Container '{name}' would be {action[1]}" return ret try: @@ -626,7 +626,7 @@ def stopped(name, kill=False, path=None): state["new"] = result["state"]["new"] if state["new"] != "stopped": ret["result"] = False - ret["comment"] = "Unable to {} container '{}'".format(action[0], name) + ret["comment"] = f"Unable to {action[0]} container '{name}'" else: ret["comment"] = "Container '{}' was successfully {}".format( name, action[1] @@ -707,7 +707,7 @@ def edited_conf(name, lxc_conf=None, lxc_conf_unset=None): if __opts__["test"]: return { "name": name, - "comment": "{} lxc.conf will be edited".format(name), + "comment": f"{name} lxc.conf will be edited", "result": True, "changes": {}, } diff --git a/salt/states/lxd.py b/salt/states/lxd.py index 30991ab1e8d..35b87ea8371 100644 --- a/salt/states/lxd.py +++ b/salt/states/lxd.py @@ -172,7 +172,7 @@ def config_managed(name, value, force_password=False): ) elif str(value) == current_value: - return _success(ret, '"{}" is already set to "{}"'.format(name, value)) + return _success(ret, f'"{name}" is already set to "{value}"') if __opts__["test"]: if name == _password_config_key: @@ -180,7 +180,7 @@ def config_managed(name, value, force_password=False): ret["changes"] = {"password": msg} return _unchanged(ret, msg) else: - msg = 'Would set the "{}" to "{}"'.format(name, value) + msg = f'Would set the "{name}" to "{value}"' ret["changes"] = {name: msg} return _unchanged(ret, msg) @@ -190,9 +190,7 @@ def config_managed(name, value, force_password=False): if name == _password_config_key: ret["changes"] = {name: "Changed the password"} else: - ret["changes"] = { - name: 'Changed from "{}" to {}"'.format(current_value, value) - } + ret["changes"] = {name: f'Changed from "{current_value}" to {value}"'} except CommandExecutionError as e: return _error(ret, str(e)) @@ -265,9 +263,9 @@ def authenticate(name, remote_addr, password, cert, key, verify_cert=True): return _error(ret, str(e)) if result is not True: - return _error(ret, "Failed to authenticate with peer: {}".format(remote_addr)) + return _error(ret, f"Failed to authenticate with peer: {remote_addr}") - msg = "Successfully authenticated with peer: {}".format(remote_addr) + msg = f"Successfully authenticated with peer: {remote_addr}" ret["changes"] = msg return _success(ret, msg) diff --git a/salt/states/lxd_container.py b/salt/states/lxd_container.py index 065e267c5fd..a1f894c6ac5 100644 --- a/salt/states/lxd_container.py +++ b/salt/states/lxd_container.py @@ -218,7 +218,7 @@ def present( if container is None: if __opts__["test"]: # Test is on, just return that we would create the container - msg = 'Would create the container "{}"'.format(name) + msg = f'Would create the container "{name}"' ret["changes"] = {"created": msg} if running is True: msg = msg + " and start it." @@ -248,7 +248,7 @@ def present( except CommandExecutionError as e: return _error(ret, str(e)) - msg = 'Created the container "{}"'.format(name) + msg = f'Created the container "{name}"' ret["changes"] = {"created": msg} if running is True: @@ -260,7 +260,7 @@ def present( return _error(ret, str(e)) msg = msg + " and started it." - ret["changes"] = {"started": 'Started the container "{}"'.format(name)} + ret["changes"] = {"started": f'Started the container "{name}"'} return _success(ret, msg) @@ -274,18 +274,18 @@ def present( # Removed profiles for k in old_profiles.difference(new_profiles): if not __opts__["test"]: - profile_changes.append('Removed profile "{}"'.format(k)) + profile_changes.append(f'Removed profile "{k}"') old_profiles.discard(k) else: - profile_changes.append('Would remove profile "{}"'.format(k)) + profile_changes.append(f'Would remove profile "{k}"') # Added profiles for k in new_profiles.difference(old_profiles): if not __opts__["test"]: - profile_changes.append('Added profile "{}"'.format(k)) + profile_changes.append(f'Added profile "{k}"') old_profiles.add(k) else: - profile_changes.append('Would add profile "{}"'.format(k)) + profile_changes.append(f'Would add profile "{k}"') if profile_changes: container_changed = True @@ -315,7 +315,7 @@ def present( changes["running"] = "Would start the container" return _unchanged( ret, - 'Container "{}" would get changed and started.'.format(name), + f'Container "{name}" would get changed and started.', ) else: container.start(wait=True) @@ -326,7 +326,7 @@ def present( changes["stopped"] = "Would stopped the container" return _unchanged( ret, - 'Container "{}" would get changed and stopped.'.format(name), + f'Container "{name}" would get changed and stopped.', ) else: container.stop(wait=True) @@ -341,17 +341,17 @@ def present( if __opts__["test"]: changes["restarted"] = "Would restart the container" - return _unchanged(ret, 'Would restart the container "{}"'.format(name)) + return _unchanged(ret, f'Would restart the container "{name}"') else: container.restart(wait=True) - changes["restarted"] = 'Container "{}" has been restarted'.format(name) - return _success(ret, 'Container "{}" has been restarted'.format(name)) + changes["restarted"] = f'Container "{name}" has been restarted' + return _success(ret, f'Container "{name}" has been restarted') if not container_changed: return _success(ret, "No changes") if __opts__["test"]: - return _unchanged(ret, 'Container "{}" would get changed.'.format(name)) + return _unchanged(ret, f'Container "{name}" would get changed.') return _success(ret, "{} changes".format(len(ret["changes"].keys()))) @@ -410,10 +410,10 @@ def absent(name, stop=False, remote_addr=None, cert=None, key=None, verify_cert= return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _success(ret, 'Container "{}" not found.'.format(name)) + return _success(ret, f'Container "{name}" not found.') if __opts__["test"]: - ret["changes"] = {"removed": 'Container "{}" would get deleted.'.format(name)} + ret["changes"] = {"removed": f'Container "{name}" would get deleted.'} return _unchanged(ret, ret["changes"]["removed"]) if stop and container.status_code == CONTAINER_STATUS_RUNNING: @@ -421,7 +421,7 @@ def absent(name, stop=False, remote_addr=None, cert=None, key=None, verify_cert= container.delete(wait=True) - ret["changes"]["deleted"] = 'Container "{}" has been deleted.'.format(name) + ret["changes"]["deleted"] = f'Container "{name}" has been deleted.' return _success(ret, ret["changes"]["deleted"]) @@ -480,13 +480,13 @@ def running( return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Container "{}" not found'.format(name)) + return _error(ret, f'Container "{name}" not found') is_running = container.status_code == CONTAINER_STATUS_RUNNING if is_running: if not restart: - return _success(ret, 'The container "{}" is already running'.format(name)) + return _success(ret, f'The container "{name}" is already running') else: if __opts__["test"]: ret["changes"]["restarted"] = 'Would restart the container "{}"'.format( @@ -501,11 +501,11 @@ def running( return _success(ret, ret["changes"]["restarted"]) if __opts__["test"]: - ret["changes"]["started"] = 'Would start the container "{}"'.format(name) + ret["changes"]["started"] = f'Would start the container "{name}"' return _unchanged(ret, ret["changes"]["started"]) container.start(wait=True) - ret["changes"]["started"] = 'Started the container "{}"'.format(name) + ret["changes"]["started"] = f'Started the container "{name}"' return _success(ret, ret["changes"]["started"]) @@ -562,10 +562,10 @@ def frozen(name, start=True, remote_addr=None, cert=None, key=None, verify_cert= return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Container "{}" not found'.format(name)) + return _error(ret, f'Container "{name}" not found') if container.status_code == CONTAINER_STATUS_FROZEN: - return _success(ret, 'Container "{}" is alredy frozen'.format(name)) + return _success(ret, f'Container "{name}" is alredy frozen') is_running = container.status_code == CONTAINER_STATUS_RUNNING @@ -579,20 +579,20 @@ def frozen(name, start=True, remote_addr=None, cert=None, key=None, verify_cert= elif not is_running and start: if __opts__["test"]: - ret["changes"]["started"] = ( - 'Would start the container "{}" and freeze it after'.format(name) - ) + ret["changes"][ + "started" + ] = f'Would start the container "{name}" and freeze it after' return _unchanged(ret, ret["changes"]["started"]) else: container.start(wait=True) - ret["changes"]["started"] = 'Start the container "{}"'.format(name) + ret["changes"]["started"] = f'Start the container "{name}"' if __opts__["test"]: - ret["changes"]["frozen"] = 'Would freeze the container "{}"'.format(name) + ret["changes"]["frozen"] = f'Would freeze the container "{name}"' return _unchanged(ret, ret["changes"]["frozen"]) container.freeze(wait=True) - ret["changes"]["frozen"] = 'Froze the container "{}"'.format(name) + ret["changes"]["frozen"] = f'Froze the container "{name}"' return _success(ret, ret["changes"]["frozen"]) @@ -650,17 +650,17 @@ def stopped(name, kill=False, remote_addr=None, cert=None, key=None, verify_cert return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Container "{}" not found'.format(name)) + return _error(ret, f'Container "{name}" not found') if container.status_code == CONTAINER_STATUS_STOPPED: - return _success(ret, 'Container "{}" is already stopped'.format(name)) + return _success(ret, f'Container "{name}" is already stopped') if __opts__["test"]: - ret["changes"]["stopped"] = 'Would stop the container "{}"'.format(name) + ret["changes"]["stopped"] = f'Would stop the container "{name}"' return _unchanged(ret, ret["changes"]["stopped"]) container.stop(force=kill, wait=True) - ret["changes"]["stopped"] = 'Stopped the container "{}"'.format(name) + ret["changes"]["stopped"] = f'Stopped the container "{name}"' return _success(ret, ret["changes"]["stopped"]) @@ -763,7 +763,7 @@ def migrated( pass if dest_container is not None: - return _success(ret, 'Container "{}" exists on the destination'.format(name)) + return _success(ret, f'Container "{name}" exists on the destination') if src_verify_cert is None: src_verify_cert = verify_cert @@ -776,7 +776,7 @@ def migrated( return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Source Container "{}" not found'.format(name)) + return _error(ret, f'Source Container "{name}" not found') if __opts__["test"]: ret["changes"]["migrated"] = ( diff --git a/salt/states/lxd_image.py b/salt/states/lxd_image.py index 5fc991b6466..923726e7b26 100644 --- a/salt/states/lxd_image.py +++ b/salt/states/lxd_image.py @@ -180,7 +180,7 @@ def present( if image is None: if __opts__["test"]: # Test is on, just return that we would create the image - msg = 'Would create the image "{}"'.format(name) + msg = f'Would create the image "{name}"' ret["changes"] = {"created": msg} return _unchanged(ret, msg) @@ -258,17 +258,17 @@ def present( for k in old_aliases.difference(new_aliases): if not __opts__["test"]: __salt__["lxd.image_alias_delete"](image, k) - alias_changes.append('Removed alias "{}"'.format(k)) + alias_changes.append(f'Removed alias "{k}"') else: - alias_changes.append('Would remove alias "{}"'.format(k)) + alias_changes.append(f'Would remove alias "{k}"') # New aliases for k in new_aliases.difference(old_aliases): if not __opts__["test"]: __salt__["lxd.image_alias_add"](image, k, "") - alias_changes.append('Added alias "{}"'.format(k)) + alias_changes.append(f'Added alias "{k}"') else: - alias_changes.append('Would add alias "{}"'.format(k)) + alias_changes.append(f'Would add alias "{k}"') if alias_changes: ret["changes"]["aliases"] = alias_changes @@ -276,11 +276,11 @@ def present( # Set public if public is not None and image.public != public: if not __opts__["test"]: - ret["changes"]["public"] = "Setting the image public to {!s}".format(public) + ret["changes"]["public"] = f"Setting the image public to {public!s}" image.public = public __salt__["lxd.pylxd_save_object"](image) else: - ret["changes"]["public"] = "Would set public to {!s}".format(public) + ret["changes"]["public"] = f"Would set public to {public!s}" if __opts__["test"] and ret["changes"]: return _unchanged(ret, "Would do {} changes".format(len(ret["changes"].keys()))) @@ -341,15 +341,15 @@ def absent(name, remote_addr=None, cert=None, key=None, verify_cert=True): except CommandExecutionError as e: return _error(ret, str(e)) except SaltInvocationError as e: - return _success(ret, 'Image "{}" not found.'.format(name)) + return _success(ret, f'Image "{name}" not found.') if __opts__["test"]: - ret["changes"] = {"removed": 'Image "{}" would get deleted.'.format(name)} + ret["changes"] = {"removed": f'Image "{name}" would get deleted.'} return _success(ret, ret["changes"]["removed"]) __salt__["lxd.image_delete"](image) - ret["changes"] = {"removed": 'Image "{}" has been deleted.'.format(name)} + ret["changes"] = {"removed": f'Image "{name}" has been deleted.'} return _success(ret, ret["changes"]["removed"]) diff --git a/salt/states/lxd_profile.py b/salt/states/lxd_profile.py index 35c781941b7..a699252b4d7 100644 --- a/salt/states/lxd_profile.py +++ b/salt/states/lxd_profile.py @@ -132,7 +132,7 @@ def present( if profile is None: if __opts__["test"]: # Test is on, just return that we would create the profile - msg = 'Would create the profile "{}"'.format(name) + msg = f'Would create the profile "{name}"' ret["changes"] = {"created": msg} return _unchanged(ret, msg) @@ -145,7 +145,7 @@ def present( except CommandExecutionError as e: return _error(ret, str(e)) - msg = 'Profile "{}" has been created'.format(name) + msg = f'Profile "{name}" has been created' ret["changes"] = {"created": msg} return _success(ret, msg) @@ -172,7 +172,7 @@ def present( return _success(ret, "No changes") if __opts__["test"]: - return _unchanged(ret, 'Profile "{}" would get changed.'.format(name)) + return _unchanged(ret, f'Profile "{name}" would get changed.') try: __salt__["lxd.pylxd_save_object"](profile) @@ -233,9 +233,9 @@ def absent(name, remote_addr=None, cert=None, key=None, verify_cert=True): return _error(ret, str(e)) except SaltInvocationError as e: # Profile not found - return _success(ret, 'Profile "{}" not found.'.format(name)) + return _success(ret, f'Profile "{name}" not found.') - ret["changes"] = {"removed": 'Profile "{}" would get deleted.'.format(name)} + ret["changes"] = {"removed": f'Profile "{name}" would get deleted.'} return _success(ret, ret["changes"]["removed"]) try: @@ -244,9 +244,9 @@ def absent(name, remote_addr=None, cert=None, key=None, verify_cert=True): return _error(ret, str(e)) except SaltInvocationError as e: # Profile not found - return _success(ret, 'Profile "{}" not found.'.format(name)) + return _success(ret, f'Profile "{name}" not found.') - ret["changes"] = {"removed": 'Profile "{}" has been deleted.'.format(name)} + ret["changes"] = {"removed": f'Profile "{name}" has been deleted.'} return _success(ret, ret["changes"]["removed"]) diff --git a/salt/states/mac_assistive.py b/salt/states/mac_assistive.py index 8aee4ccffec..ad0de154452 100644 --- a/salt/states/mac_assistive.py +++ b/salt/states/mac_assistive.py @@ -53,12 +53,12 @@ def installed(name, enabled=True): if enabled != is_enabled: __salt__["assistive.enable"](name, enabled) - ret["comment"] = "Updated enable to {}".format(enabled) + ret["comment"] = f"Updated enable to {enabled}" else: ret["comment"] = "Already in the correct state" else: __salt__["assistive.install"](name, enabled) - ret["comment"] = "Installed {} into the assistive access panel".format(name) + ret["comment"] = f"Installed {name} into the assistive access panel" return ret diff --git a/salt/states/mac_keychain.py b/salt/states/mac_keychain.py index 7126a95b01c..fd1af09623b 100644 --- a/salt/states/mac_keychain.py +++ b/salt/states/mac_keychain.py @@ -95,9 +95,9 @@ def installed(name, password, keychain="/Library/Keychains/System.keychain", **k ret["changes"]["installed"] = friendly_name else: ret["result"] = False - ret["comment"] += "Failed to install {}".format(friendly_name) + ret["comment"] += f"Failed to install {friendly_name}" else: - ret["comment"] += "{} already installed.".format(friendly_name) + ret["comment"] += f"{friendly_name} already installed." return ret @@ -150,9 +150,9 @@ def uninstalled( ret["changes"]["uninstalled"] = friendly_name else: ret["result"] = False - ret["comment"] += "Failed to uninstall {}".format(friendly_name) + ret["comment"] += f"Failed to uninstall {friendly_name}" else: - ret["comment"] += "{} already uninstalled.".format(friendly_name) + ret["comment"] += f"{friendly_name} already uninstalled." return ret @@ -175,18 +175,18 @@ def default_keychain(name, domain="user", user=None): if not os.path.exists(name): ret["result"] = False - ret["comment"] += "Keychain not found at {}".format(name) + ret["comment"] += f"Keychain not found at {name}" else: out = __salt__["keychain.get_default_keychain"](user, domain) if name in out: - ret["comment"] += "{} was already the default keychain.".format(name) + ret["comment"] += f"{name} was already the default keychain." else: out = __salt__["keychain.set_default_keychain"](name, domain, user) if len(out) == 0: ret["changes"]["default"] = name else: ret["result"] = False - ret["comment"] = "Failed to install keychain. {}".format(out) + ret["comment"] = f"Failed to install keychain. {out}" return ret diff --git a/salt/states/macdefaults.py b/salt/states/macdefaults.py index 67383eaffcd..05e83c2a4d6 100644 --- a/salt/states/macdefaults.py +++ b/salt/states/macdefaults.py @@ -58,20 +58,20 @@ def write(name, domain, value, vtype="string", user=None): (value in [True, "TRUE", "YES"] and current_value == "1") or (value in [False, "FALSE", "NO"] and current_value == "0") ): - ret["comment"] += "{} {} is already set to {}".format(domain, name, value) + ret["comment"] += f"{domain} {name} is already set to {value}" elif vtype in ["int", "integer"] and safe_cast(current_value, int) == safe_cast( value, int ): - ret["comment"] += "{} {} is already set to {}".format(domain, name, value) + ret["comment"] += f"{domain} {name} is already set to {value}" elif current_value == value: - ret["comment"] += "{} {} is already set to {}".format(domain, name, value) + ret["comment"] += f"{domain} {name} is already set to {value}" else: out = __salt__["macdefaults.write"](domain, name, value, vtype, user) if out["retcode"] != 0: ret["result"] = False ret["comment"] = "Failed to write default. {}".format(out["stdout"]) else: - ret["changes"]["written"] = "{} {} is set to {}".format(domain, name, value) + ret["changes"]["written"] = f"{domain} {name} is set to {value}" return ret @@ -96,8 +96,8 @@ def absent(name, domain, user=None): out = __salt__["macdefaults.delete"](domain, name, user) if out["retcode"] != 0: - ret["comment"] += "{} {} is already absent".format(domain, name) + ret["comment"] += f"{domain} {name} is already absent" else: - ret["changes"]["absent"] = "{} {} is now absent".format(domain, name) + ret["changes"]["absent"] = f"{domain} {name} is now absent" return ret diff --git a/salt/states/macpackage.py b/salt/states/macpackage.py index 95650438286..feb12560911 100644 --- a/salt/states/macpackage.py +++ b/salt/states/macpackage.py @@ -113,7 +113,7 @@ def installed( version_out = "" if re.match(expected_version, version_out) is not None: - ret["comment"] += "Version already matches {}".format(expected_version) + ret["comment"] += f"Version already matches {expected_version}" return ret else: ret["comment"] += "Version {} doesn't match {}. ".format( @@ -129,7 +129,7 @@ def installed( out, mount_point = __salt__["macpackage.mount"](name) if "attach failed" in out: ret["result"] = False - ret["comment"] += "Unable to mount {}".format(name) + ret["comment"] += f"Unable to mount {name}" return ret if app: @@ -149,7 +149,7 @@ def installed( if ".app" not in out: ret["result"] = False - ret["comment"] += "Unable to find .app in {}".format(mount_point) + ret["comment"] += f"Unable to find .app in {mount_point}" return ret else: pkg_ids = out.split("\n") @@ -190,7 +190,7 @@ def installed( def failed_pkg(f_pkg): ret["result"] = False - ret["comment"] += "{} failed to install: {}".format(name, out) + ret["comment"] += f"{name} failed to install: {out}" if "failed" in ret["changes"]: ret["changes"]["failed"].append(f_pkg) @@ -208,7 +208,7 @@ def installed( if len(out) != 0: failed_pkg(app) else: - ret["comment"] += "{} installed".format(app) + ret["comment"] += f"{app} installed" if "installed" in ret["changes"]: ret["changes"]["installed"].append(app) else: @@ -223,9 +223,9 @@ def installed( if out["retcode"] != 0: ret["result"] = False - ret["comment"] += ". {} failed to install: {}".format(name, out) + ret["comment"] += f". {name} failed to install: {out}" else: - ret["comment"] += "{} installed".format(name) + ret["comment"] += f"{name} installed" ret["changes"]["installed"] = installing finally: diff --git a/salt/states/makeconf.py b/salt/states/makeconf.py index 632a11b2c43..9e5a19261c1 100644 --- a/salt/states/makeconf.py +++ b/salt/states/makeconf.py @@ -131,11 +131,11 @@ def present(name, value=None, contains=None, excludes=None): ret["comment"] = msg.format(name) else: if __opts__["test"]: - msg = "Variable {} is set to".format(name) + msg = f"Variable {name} is set to" if len(to_append) > 0: - msg += ' append "{}"'.format(list(to_append)) + msg += f' append "{list(to_append)}"' if len(to_trim) > 0: - msg += ' trim "{}"'.format(list(to_trim)) + msg += f' trim "{list(to_trim)}"' msg += " in make.conf" ret["comment"] = msg ret["result"] = None diff --git a/salt/states/marathon_app.py b/salt/states/marathon_app.py index 3d44503db61..95339b1d148 100644 --- a/salt/states/marathon_app.py +++ b/salt/states/marathon_app.py @@ -66,7 +66,7 @@ def config(name, config): # if test, report there will be an update if __opts__["test"]: ret["result"] = None - ret["comment"] = "Marathon app {} is set to be updated".format(name) + ret["comment"] = f"Marathon app {name} is set to be updated" return ret update_result = __salt__["marathon.update_app"](name, update_config) @@ -79,10 +79,10 @@ def config(name, config): return ret else: ret["result"] = True - ret["comment"] = "Updated app config for {}".format(name) + ret["comment"] = f"Updated app config for {name}" return ret ret["result"] = True - ret["comment"] = "Marathon app {} configured correctly".format(name) + ret["comment"] = f"Marathon app {name} configured correctly" return ret @@ -96,20 +96,20 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["marathon.has_app"](name): ret["result"] = True - ret["comment"] = "App {} already absent".format(name) + ret["comment"] = f"App {name} already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "App {} is set to be removed".format(name) + ret["comment"] = f"App {name} is set to be removed" return ret if __salt__["marathon.rm_app"](name): ret["changes"] = {"app": name} ret["result"] = True - ret["comment"] = "Removed app {}".format(name) + ret["comment"] = f"Removed app {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to remove app {}".format(name) + ret["comment"] = f"Failed to remove app {name}" return ret @@ -125,12 +125,12 @@ def running(name, restart=False, force=True): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["marathon.has_app"](name): ret["result"] = False - ret["comment"] = "App {} cannot be restarted because it is absent".format(name) + ret["comment"] = f"App {name} cannot be restarted because it is absent" return ret if __opts__["test"]: ret["result"] = None qualifier = "is" if restart else "is not" - ret["comment"] = "App {} {} set to be restarted".format(name, qualifier) + ret["comment"] = f"App {name} {qualifier} set to be restarted" return ret restart_result = __salt__["marathon.restart_app"](name, restart, force) if "exception" in restart_result: @@ -143,5 +143,5 @@ def running(name, restart=False, force=True): ret["changes"] = restart_result ret["result"] = True qualifier = "Restarted" if restart else "Did not restart" - ret["comment"] = "{} app {}".format(qualifier, name) + ret["comment"] = f"{qualifier} app {name}" return ret diff --git a/salt/states/mdadm_raid.py b/salt/states/mdadm_raid.py index 9d7fb7e9557..76396d858dd 100644 --- a/salt/states/mdadm_raid.py +++ b/salt/states/mdadm_raid.py @@ -130,7 +130,7 @@ def present(name, level, devices, **kwargs): verb = "assembled" else: if len(new_devices) == 0: - ret["comment"] = "All devices are missing: {}.".format(missing) + ret["comment"] = f"All devices are missing: {missing}." ret["result"] = False return ret do_assemble = False @@ -149,22 +149,22 @@ def present(name, level, devices, **kwargs): level, new_devices + ["missing"] * len(missing), test_mode=True, - **kwargs + **kwargs, ) if present: - ret["comment"] = "Raid {} already present.".format(name) + ret["comment"] = f"Raid {name} already present." if do_assemble or do_create: - ret["comment"] = "Raid will be {} with: {}".format(verb, res) + ret["comment"] = f"Raid will be {verb} with: {res}" ret["result"] = None if (do_assemble or present) and len(new_devices) > 0: - ret["comment"] += " New devices will be added: {}".format(new_devices) + ret["comment"] += f" New devices will be added: {new_devices}" ret["result"] = None if len(missing) > 0: - ret["comment"] += " Missing devices: {}".format(missing) + ret["comment"] += f" Missing devices: {missing}" return ret @@ -180,29 +180,29 @@ def present(name, level, devices, **kwargs): raids = __salt__["raid.list"]() changes = raids.get(name) if changes: - ret["comment"] = "Raid {} {}.".format(name, verb) + ret["comment"] = f"Raid {name} {verb}." ret["changes"] = changes # Saving config __salt__["raid.save_config"]() else: - ret["comment"] = "Raid {} failed to be {}.".format(name, verb) + ret["comment"] = f"Raid {name} failed to be {verb}." ret["result"] = False else: - ret["comment"] = "Raid {} already present.".format(name) + ret["comment"] = f"Raid {name} already present." if (do_assemble or present) and len(new_devices) > 0 and ret["result"]: for d in new_devices: res = __salt__["raid.add"](name, d) if not res: - ret["comment"] += " Unable to add {} to {}.\n".format(d, name) + ret["comment"] += f" Unable to add {d} to {name}.\n" ret["result"] = False else: - ret["comment"] += " Added new device {} to {}.\n".format(d, name) + ret["comment"] += f" Added new device {d} to {name}.\n" if ret["result"]: ret["changes"]["added"] = new_devices if len(missing) > 0: - ret["comment"] += " Missing devices: {}".format(missing) + ret["comment"] += f" Missing devices: {missing}" return ret @@ -224,10 +224,10 @@ def absent(name): # Raid does not exist if name not in __salt__["raid.list"](): - ret["comment"] = "Raid {} already absent".format(name) + ret["comment"] = f"Raid {name} already absent" return ret elif __opts__["test"]: - ret["comment"] = "Raid {} is set to be destroyed".format(name) + ret["comment"] = f"Raid {name} is set to be destroyed" ret["result"] = None return ret else: @@ -235,7 +235,7 @@ def absent(name): ret["result"] = __salt__["raid.destroy"](name) if ret["result"]: - ret["comment"] = "Raid {} has been destroyed".format(name) + ret["comment"] = f"Raid {name} has been destroyed" else: - ret["comment"] = "Raid {} failed to be destroyed".format(name) + ret["comment"] = f"Raid {name} failed to be destroyed" return ret diff --git a/salt/states/memcached.py b/salt/states/memcached.py index 14cfd6771c2..3499961671b 100644 --- a/salt/states/memcached.py +++ b/salt/states/memcached.py @@ -20,7 +20,7 @@ def __virtual__(): """ Only load if memcache module is available """ - if "{}.status".format(__virtualname__) in __salt__: + if f"{__virtualname__}.status" in __salt__: return __virtualname__ return (False, "memcached module could not be loaded") @@ -65,15 +65,15 @@ def managed( if cur == value: ret["result"] = True - ret["comment"] = "Key '{}' does not need to be updated".format(name) + ret["comment"] = f"Key '{name}' does not need to be updated" return ret if __opts__["test"]: ret["result"] = None if cur is None: - ret["comment"] = "Key '{}' would be added".format(name) + ret["comment"] = f"Key '{name}' would be added" else: - ret["comment"] = "Value of key '{}' would be changed".format(name) + ret["comment"] = f"Value of key '{name}' would be changed" return ret try: @@ -84,13 +84,13 @@ def managed( ret["comment"] = str(exc) else: if ret["result"]: - ret["comment"] = "Successfully set key '{}'".format(name) + ret["comment"] = f"Successfully set key '{name}'" if cur is not None: ret["changes"] = {"old": cur, "new": value} else: ret["changes"] = {"key added": name, "value": value} else: - ret["comment"] = "Failed to set key '{}'".format(name) + ret["comment"] = f"Failed to set key '{name}'" return ret @@ -138,12 +138,12 @@ def absent(name, value=None, host=DEFAULT_HOST, port=DEFAULT_PORT, time=DEFAULT_ return ret if cur is None: ret["result"] = True - ret["comment"] = "Key '{}' does not exist".format(name) + ret["comment"] = f"Key '{name}' does not exist" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Key '{}' would be deleted".format(name) + ret["comment"] = f"Key '{name}' would be deleted" return ret try: @@ -152,8 +152,8 @@ def absent(name, value=None, host=DEFAULT_HOST, port=DEFAULT_PORT, time=DEFAULT_ ret["comment"] = str(exc) else: if ret["result"]: - ret["comment"] = "Successfully deleted key '{}'".format(name) + ret["comment"] = f"Successfully deleted key '{name}'" ret["changes"] = {"key deleted": name, "value": cur} else: - ret["comment"] = "Failed to delete key '{}'".format(name) + ret["comment"] = f"Failed to delete key '{name}'" return ret diff --git a/salt/states/modjk.py b/salt/states/modjk.py index 0932715b129..f41a84010ab 100644 --- a/salt/states/modjk.py +++ b/salt/states/modjk.py @@ -26,7 +26,7 @@ def _bulk_state(saltfunc, lbn, workers, profile): if not isinstance(workers, list): ret["result"] = False - ret["comment"] = "workers should be a list not a {}".format(type(workers)) + ret["comment"] = f"workers should be a list not a {type(workers)}" return ret if __opts__["test"]: @@ -38,7 +38,7 @@ def _bulk_state(saltfunc, lbn, workers, profile): cmdret = __salt__[saltfunc](workers, lbn, profile=profile) except KeyError: ret["result"] = False - ret["comment"] = "unsupported function {}".format(saltfunc) + ret["comment"] = f"unsupported function {saltfunc}" return ret errors = [] @@ -49,7 +49,7 @@ def _bulk_state(saltfunc, lbn, workers, profile): ret["changes"] = {"status": cmdret} if errors: ret["result"] = False - ret["comment"] = "{} failed on some workers".format(saltfunc) + ret["comment"] = f"{saltfunc} failed on some workers" return ret diff --git a/salt/states/modjk_worker.py b/salt/states/modjk_worker.py index 120531356b3..5cefeac1d63 100644 --- a/salt/states/modjk_worker.py +++ b/salt/states/modjk_worker.py @@ -44,7 +44,7 @@ def _send_command(cmd, worker, lbn, target, profile="default", tgt_type="glob"): } # Send the command to target - func = "modjk.{}".format(cmd) + func = f"modjk.{cmd}" args = [worker, lbn, profile] response = __salt__["publish.publish"](target, func, args, tgt_type) @@ -58,7 +58,7 @@ def _send_command(cmd, worker, lbn, target, profile="default", tgt_type="glob"): # parse response if not response: - ret["msg"] = "no servers answered the published command {}".format(cmd) + ret["msg"] = f"no servers answered the published command {cmd}" return ret elif len(errors) > 0: ret["msg"] = "the following minions return False" diff --git a/salt/states/module.py b/salt/states/module.py index e6422e146f8..262e38b96d6 100644 --- a/salt/states/module.py +++ b/salt/states/module.py @@ -460,7 +460,7 @@ def _run(**kwargs): ) ) if func_ret is False: - failures.append("'{}': {}".format(func, func_ret)) + failures.append(f"'{func}': {func_ret}") else: success.append( "{}: {}".format( @@ -474,7 +474,7 @@ def _run(**kwargs): ) ret["changes"][func] = func_ret except (SaltInvocationError, TypeError) as ex: - failures.append("'{}' failed: {}".format(func, ex)) + failures.append(f"'{func}' failed: {ex}") ret["comment"] = ", ".join(failures + success) ret["result"] = not bool(failures) @@ -530,12 +530,12 @@ def _legacy_run(name, **kwargs): """ ret = {"name": name, "changes": {}, "comment": "", "result": None} if name not in __salt__: - ret["comment"] = "Module function {} is not available".format(name) + ret["comment"] = f"Module function {name} is not available" ret["result"] = False return ret if __opts__["test"]: - ret["comment"] = "Module function {} is set to execute".format(name) + ret["comment"] = f"Module function {name} is set to execute" return ret aspec = salt.utils.args.get_function_argspec(__salt__[name]) @@ -593,7 +593,7 @@ def _legacy_run(name, **kwargs): if missing: comment = "The following arguments are missing:" for arg in missing: - comment += " {}".format(arg) + comment += f" {arg}" ret["comment"] = comment ret["result"] = False return ret @@ -657,7 +657,7 @@ def _legacy_run(name, **kwargs): returners = salt.loader.returners(__opts__, __salt__) if kwargs["returner"] in returners: returners[kwargs["returner"]](ret_ret) - ret["comment"] = "Module function {} executed".format(name) + ret["comment"] = f"Module function {name} executed" ret["result"] = _get_result(mret, ret["changes"]) return ret diff --git a/salt/states/mongodb_database.py b/salt/states/mongodb_database.py index 4df6c4297ed..5445b3b880d 100644 --- a/salt/states/mongodb_database.py +++ b/salt/states/mongodb_database.py @@ -53,9 +53,9 @@ def absent(name, user=None, password=None, host=None, port=None, authdb=None): if __salt__["mongodb.db_remove"]( name, user, password, host, port, authdb=authdb ): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret - ret["comment"] = "Database {} is not present".format(name) + ret["comment"] = f"Database {name} is not present" return ret diff --git a/salt/states/mongodb_user.py b/salt/states/mongodb_user.py index a83cd9b5686..6494b0018a9 100644 --- a/salt/states/mongodb_user.py +++ b/salt/states/mongodb_user.py @@ -81,7 +81,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {} is already present".format(name), + "comment": f"User {name} is already present", } # setup default empty roles if not provided to preserve previous API interface @@ -93,7 +93,7 @@ def present( port = int(port) except TypeError: ret["result"] = False - ret["comment"] = "Port ({}) is not an integer.".format(port) + ret["comment"] = f"Port ({port}) is not an integer." return ret # check if user exists @@ -106,7 +106,7 @@ def present( # users= (False, 'not authorized on admin to execute command { usersInfo: "root" }') if not users[0]: ret["result"] = False - ret["comment"] = "Mongo Err: {}".format(users[1]) + ret["comment"] = f"Mongo Err: {users[1]}" return ret # check each user occurrence @@ -152,7 +152,7 @@ def present( if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is not present and needs to be created".format(name) + ret["comment"] = f"User {name} is not present and needs to be created" return ret # The user is not present, make it! if __salt__["mongodb.user_create"]( @@ -166,10 +166,10 @@ def present( authdb=authdb, roles=roles, ): - ret["comment"] = "User {} has been created".format(name) + ret["comment"] = f"User {name} has been created" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret @@ -212,12 +212,12 @@ def absent( if user_exists is True: if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is present and needs to be removed".format(name) + ret["comment"] = f"User {name} is present and needs to be removed" return ret if __salt__["mongodb.user_remove"]( name, user, password, host, port, database=database, authdb=authdb ): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret @@ -229,5 +229,5 @@ def absent( return ret # fallback - ret["comment"] = "User {} is not present".format(name) + ret["comment"] = f"User {name} is not present" return ret diff --git a/salt/states/monit.py b/salt/states/monit.py index b6de50d307f..4e1cd7dd514 100644 --- a/salt/states/monit.py +++ b/salt/states/monit.py @@ -40,20 +40,20 @@ def monitor(name): try: for key, value in result.items(): if "Running" in value[name]: - ret["comment"] = "{} is being being monitored.".format(name) + ret["comment"] = f"{name} is being being monitored." ret["result"] = True else: if __opts__["test"]: - ret["comment"] = "Service {} is set to be monitored.".format(name) + ret["comment"] = f"Service {name} is set to be monitored." ret["result"] = None return ret __salt__["monit.monitor"](name) - ret["comment"] = "{} started to be monitored.".format(name) + ret["comment"] = f"{name} started to be monitored." ret["changes"][name] = "Running" ret["result"] = True break except KeyError: - ret["comment"] = "{} not found in configuration.".format(name) + ret["comment"] = f"{name} not found in configuration." ret["result"] = False return ret @@ -70,20 +70,20 @@ def unmonitor(name): try: for key, value in result.items(): if "Not monitored" in value[name]: - ret["comment"] = "{} is not being monitored.".format(name) + ret["comment"] = f"{name} is not being monitored." ret["result"] = True else: if __opts__["test"]: - ret["comment"] = "Service {} is set to be unmonitored.".format(name) + ret["comment"] = f"Service {name} is set to be unmonitored." ret["result"] = None return ret __salt__["monit.unmonitor"](name) - ret["comment"] = "{} stopped being monitored.".format(name) + ret["comment"] = f"{name} stopped being monitored." ret["changes"][name] = "Not monitored" ret["result"] = True break except KeyError: - ret["comment"] = "{} not found in configuration.".format(name) + ret["comment"] = f"{name} not found in configuration." ret["result"] = False return ret diff --git a/salt/states/mount.py b/salt/states/mount.py index c820d268325..35777c6b403 100644 --- a/salt/states/mount.py +++ b/salt/states/mount.py @@ -71,7 +71,7 @@ def mounted( extra_mount_translate_options=None, hidden_opts=None, bind_mount_copy_active_opts=True, - **kwargs + **kwargs, ): """ Verify that a device is mounted @@ -282,10 +282,10 @@ def mounted( real_device = device.split("=")[1].strip('"').lower() elif device.upper().startswith("LABEL="): _label = device.split("=")[1] - cmd = "blkid -t LABEL={}".format(_label) - res = __salt__["cmd.run_all"]("{}".format(cmd)) + cmd = f"blkid -t LABEL={_label}" + res = __salt__["cmd.run_all"](f"{cmd}") if res["retcode"] > 0: - ret["comment"] = "Unable to find device with label {}.".format(_label) + ret["comment"] = f"Unable to find device with label {_label}." ret["result"] = False return ret else: @@ -432,7 +432,7 @@ def mounted( ) if size_match: converted_size = _size_convert(size_match) - opt = "size={}k".format(converted_size) + opt = f"size={converted_size}k" # make cifs option user synonym for option username which is reported by /proc/mounts if fstype in ["cifs"] and opt.split("=")[0] == "user": opt = "username={}".format(opt.split("=")[1]) @@ -460,9 +460,9 @@ def mounted( ) if size_match: converted_size = _size_convert(size_match) - opt = "size={}k".format(converted_size) + opt = f"size={converted_size}k" _active_superopts.remove(_active_opt) - _active_opt = "size={}k".format(converted_size) + _active_opt = f"size={converted_size}k" _active_superopts.append(_active_opt) if ( @@ -551,7 +551,7 @@ def mounted( if fstype in ["nfs", "cvfs"] or fstype.startswith("fuse"): ret["changes"]["umount"] = ( "Forced unmount and mount because " - + "options ({}) changed".format(opt) + + f"options ({opt}) changed" ) unmount_result = __salt__["mount.umount"](real_name) if unmount_result is True: @@ -572,7 +572,7 @@ def mounted( else: ret["changes"]["umount"] = ( "Forced remount because " - + "options ({}) changed".format(opt) + + f"options ({opt}) changed" ) remount_result = __salt__["mount.remount"]( real_name, @@ -638,13 +638,11 @@ def mounted( if __opts__["test"]: ret["result"] = None if os.path.exists(name): - ret["comment"] = "{} would be mounted".format(name) + ret["comment"] = f"{name} would be mounted" elif mkmnt: - ret["comment"] = "{} would be created and mounted".format(name) + ret["comment"] = f"{name} would be created and mounted" else: - ret["comment"] = ( - "{} does not exist and would not be created".format(name) - ) + ret["comment"] = f"{name} does not exist and would not be created" return ret if not os.path.exists(name) and not mkmnt: @@ -668,7 +666,7 @@ def mounted( if __opts__["test"]: ret["result"] = None if mkmnt: - ret["comment"] = "{} would be created, but not mounted".format(name) + ret["comment"] = f"{name} would be created, but not mounted" else: ret["comment"] = ( "{} does not exist and would neither be created nor mounted".format( @@ -677,14 +675,14 @@ def mounted( ) elif mkmnt: __salt__["file.mkdir"](name, user=user) - ret["comment"] = "{} was created, not mounted".format(name) + ret["comment"] = f"{name} was created, not mounted" else: - ret["comment"] = "{} not present and not mounted".format(name) + ret["comment"] = f"{name} not present and not mounted" else: if __opts__["test"]: - ret["comment"] = "{} would not be mounted".format(name) + ret["comment"] = f"{name} would not be mounted" else: - ret["comment"] = "{} not mounted".format(name) + ret["comment"] = f"{name} not mounted" if persist: if "/etc/fstab" == config: @@ -745,7 +743,7 @@ def mounted( name ) else: - comment = "The {} fstab entry must be updated.".format(name) + comment = f"The {name} fstab entry must be updated." else: ret["result"] = False comment = ( @@ -824,25 +822,25 @@ def swap(name, persist=True, config="/etc/fstab"): if __salt__["file.is_link"](name): real_swap_device = __salt__["file.readlink"](name) if not real_swap_device.startswith("/"): - real_swap_device = "/dev/{}".format(os.path.basename(real_swap_device)) + real_swap_device = f"/dev/{os.path.basename(real_swap_device)}" else: real_swap_device = name if real_swap_device in on_: - ret["comment"] = "Swap {} already active".format(name) + ret["comment"] = f"Swap {name} already active" elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Swap {} is set to be activated".format(name) + ret["comment"] = f"Swap {name} is set to be activated" else: __salt__["mount.swapon"](real_swap_device) on_ = __salt__["mount.swaps"]() if real_swap_device in on_: - ret["comment"] = "Swap {} activated".format(name) + ret["comment"] = f"Swap {name} activated" ret["changes"] = on_[real_swap_device] else: - ret["comment"] = "Swap {} failed to activate".format(name) + ret["comment"] = f"Swap {name} failed to activate" ret["result"] = False if persist: @@ -949,7 +947,7 @@ def unmounted( # The mount is present! Unmount it if __opts__["test"]: ret["result"] = None - ret["comment"] = "Mount point {} is mounted but should not be".format(name) + ret["comment"] = f"Mount point {name} is mounted but should not be" return ret if device: out = __salt__["mount.umount"](name, device, user=user) @@ -1041,10 +1039,10 @@ def mod_watch(name, user=None, **kwargs): name, kwargs["device"], False, kwargs["fstype"], kwargs["opts"], user=user ) if out: - ret["comment"] = "{} remounted".format(name) + ret["comment"] = f"{name} remounted" else: ret["result"] = False - ret["comment"] = "{} failed to remount: {}".format(name, out) + ret["comment"] = f"{name} failed to remount: {out}" else: ret["comment"] = "Watch not supported in {} at this time".format(kwargs["sfun"]) return ret @@ -1064,7 +1062,7 @@ def _convert_to(maybe_device, convert_to): if ( not convert_to or (convert_to == "device" and maybe_device.startswith("/")) - or maybe_device.startswith("{}=".format(convert_to.upper())) + or maybe_device.startswith(f"{convert_to.upper()}=") ): return maybe_device @@ -1080,7 +1078,7 @@ def _convert_to(maybe_device, convert_to): result = next(iter(blkid)) else: key = convert_to.upper() - result = "{}={}".format(key, next(iter(blkid.values()))[key]) + result = f"{key}={next(iter(blkid.values()))[key]}" return result @@ -1232,7 +1230,7 @@ def fstab_present( msg = "{} entry will be written in {}." ret["comment"].append(msg.format(fs_file, config)) if mount: - msg = "Will mount {} on {}".format(name, fs_file) + msg = f"Will mount {name} on {fs_file}" ret["comment"].append(msg) elif out == "change": msg = "{} entry will be updated in {}." @@ -1290,7 +1288,7 @@ def fstab_present( ret["result"] = False msg = "Error while mounting {}".format(out.split(":", maxsplit=1)[1]) else: - msg = "Mounted {} on {}".format(name, fs_file) + msg = f"Mounted {name} on {fs_file}" ret["comment"].append(msg) elif out == "change": ret["changes"]["persist"] = out diff --git a/salt/states/mssql_database.py b/salt/states/mssql_database.py index 532a93fa5b7..f3f44f0bd64 100644 --- a/salt/states/mssql_database.py +++ b/salt/states/mssql_database.py @@ -25,7 +25,7 @@ def __virtual__(): def _normalize_options(options): if type(options) in [dict, collections.OrderedDict]: - return ["{}={}".format(k, v) for k, v in options.items()] + return [f"{k}={v}" for k, v in options.items()] if type(options) is list and (not options or type(options[0]) is str): return options # Invalid options @@ -59,14 +59,14 @@ def present(name, containment="NONE", options=None, **kwargs): return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is set to be added".format(name) + ret["comment"] = f"Database {name} is set to be added" return ret db_created = __salt__["mssql.db_create"]( name, containment=containment, new_database_options=_normalize_options(options), - **kwargs + **kwargs, ) if ( db_created is not True @@ -76,7 +76,7 @@ def present(name, containment="NONE", options=None, **kwargs): name, db_created ) return ret - ret["comment"] += "Database {} has been added".format(name) + ret["comment"] += f"Database {name} has been added" ret["changes"][name] = "Present" return ret @@ -91,17 +91,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.db_exists"](name): - ret["comment"] = "Database {} is not present".format(name) + ret["comment"] = f"Database {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is set to be removed".format(name) + ret["comment"] = f"Database {name} is set to be removed" return ret if __salt__["mssql.db_remove"](name, **kwargs): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "Database {} failed to be removed".format(name) + ret["comment"] = f"Database {name} failed to be removed" return ret diff --git a/salt/states/mssql_login.py b/salt/states/mssql_login.py index d635a3c42e0..56316db60f4 100644 --- a/salt/states/mssql_login.py +++ b/salt/states/mssql_login.py @@ -26,7 +26,7 @@ def __virtual__(): def _normalize_options(options): if type(options) in [dict, collections.OrderedDict]: - return ["{}={}".format(k, v) for k, v in options.items()] + return [f"{k}={v}" for k, v in options.items()] if type(options) is list and (not options or type(options[0]) is str): return options # Invalid options @@ -75,7 +75,7 @@ def present( return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Login {} is set to be added".format(name) + ret["comment"] = f"Login {name} is set to be added" return ret login_created = __salt__["mssql.login_create"]( @@ -84,14 +84,14 @@ def present( new_login_domain=domain, new_login_roles=server_roles, new_login_options=_normalize_options(options), - **kwargs + **kwargs, ) # Non-empty strings are also evaluated to True, so we cannot use if not login_created: if login_created is not True: ret["result"] = False - ret["comment"] = "Login {} failed to be added: {}".format(name, login_created) + ret["comment"] = f"Login {name} failed to be added: {login_created}" return ret - ret["comment"] = "Login {} has been added. ".format(name) + ret["comment"] = f"Login {name} has been added. " ret["changes"][name] = "Present" return ret @@ -106,17 +106,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.login_exists"](name): - ret["comment"] = "Login {} is not present".format(name) + ret["comment"] = f"Login {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Login {} is set to be removed".format(name) + ret["comment"] = f"Login {name} is set to be removed" return ret if __salt__["mssql.login_remove"](name, **kwargs): - ret["comment"] = "Login {} has been removed".format(name) + ret["comment"] = f"Login {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "Login {} failed to be removed".format(name) + ret["comment"] = f"Login {name} failed to be removed" return ret diff --git a/salt/states/mssql_role.py b/salt/states/mssql_role.py index 5434c226512..2bd540233f0 100644 --- a/salt/states/mssql_role.py +++ b/salt/states/mssql_role.py @@ -43,7 +43,7 @@ def present(name, owner=None, grants=None, **kwargs): return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Role {} is set to be added".format(name) + ret["comment"] = f"Role {name} is set to be added" return ret role_created = __salt__["mssql.role_create"]( @@ -53,9 +53,9 @@ def present(name, owner=None, grants=None, **kwargs): role_created is not True ): # Non-empty strings are also evaluated to True, so we cannot use if not role_created: ret["result"] = False - ret["comment"] += "Role {} failed to be created: {}".format(name, role_created) + ret["comment"] += f"Role {name} failed to be created: {role_created}" return ret - ret["comment"] += "Role {} has been added".format(name) + ret["comment"] += f"Role {name} has been added" ret["changes"][name] = "Present" return ret @@ -70,17 +70,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.role_exists"](name): - ret["comment"] = "Role {} is not present".format(name) + ret["comment"] = f"Role {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Role {} is set to be removed".format(name) + ret["comment"] = f"Role {name} is set to be removed" return ret if __salt__["mssql.role_remove"](name, **kwargs): - ret["comment"] = "Role {} has been removed".format(name) + ret["comment"] = f"Role {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "Role {} failed to be removed".format(name) + ret["comment"] = f"Role {name} failed to be removed" return ret diff --git a/salt/states/mssql_user.py b/salt/states/mssql_user.py index f7acf30489e..60f8987d518 100644 --- a/salt/states/mssql_user.py +++ b/salt/states/mssql_user.py @@ -26,7 +26,7 @@ def __virtual__(): def _normalize_options(options): if type(options) in [dict, collections.OrderedDict]: - return ["{}={}".format(k, v) for k, v in options.items()] + return [f"{k}={v}" for k, v in options.items()] if type(options) is list and (not options or type(options[0]) is str): return options # Invalid options @@ -74,7 +74,7 @@ def present( return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is set to be added".format(name) + ret["comment"] = f"User {name} is set to be added" return ret user_created = __salt__["mssql.user_create"]( @@ -84,15 +84,15 @@ def present( database=database, roles=roles, options=_normalize_options(options), - **kwargs + **kwargs, ) if ( user_created is not True ): # Non-empty strings are also evaluated to True, so we cannot use if not user_created: ret["result"] = False - ret["comment"] += "User {} failed to be added: {}".format(name, user_created) + ret["comment"] += f"User {name} failed to be added: {user_created}" return ret - ret["comment"] += "User {} has been added".format(name) + ret["comment"] += f"User {name} has been added" ret["changes"][name] = "Present" return ret @@ -107,17 +107,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.user_exists"](name): - ret["comment"] = "User {} is not present".format(name) + ret["comment"] = f"User {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is set to be removed".format(name) + ret["comment"] = f"User {name} is set to be removed" return ret if __salt__["mssql.user_remove"](name, **kwargs): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "User {} failed to be removed".format(name) + ret["comment"] = f"User {name} failed to be removed" return ret diff --git a/salt/states/msteams.py b/salt/states/msteams.py index d061051c5d0..a4438825797 100644 --- a/salt/states/msteams.py +++ b/salt/states/msteams.py @@ -69,7 +69,7 @@ def post_card(name, message, hook_url=None, title=None, theme_color=None): return ret if not message: - ret["comment"] = "Teams message is missing: {}".format(message) + ret["comment"] = f"Teams message is missing: {message}" return ret try: @@ -80,11 +80,11 @@ def post_card(name, message, hook_url=None, title=None, theme_color=None): theme_color=theme_color, ) except SaltInvocationError as sie: - ret["comment"] = "Failed to send message ({}): {}".format(sie, name) + ret["comment"] = f"Failed to send message ({sie}): {name}" else: if isinstance(result, bool) and result: ret["result"] = True - ret["comment"] = "Sent message: {}".format(name) + ret["comment"] = f"Sent message: {name}" else: ret["comment"] = "Failed to send message ({}): {}".format( result["message"], name diff --git a/salt/states/mysql_database.py b/salt/states/mysql_database.py index c7561cf14db..0c0ce030ff4 100644 --- a/salt/states/mysql_database.py +++ b/salt/states/mysql_database.py @@ -52,7 +52,7 @@ def present(name, character_set=None, collate=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(name), + "comment": f"Database {name} is already present", } # check if database exists existing = __salt__["mysql.db_get"](name, **connection_args) @@ -91,20 +91,20 @@ def present(name, character_set=None, collate=None, **connection_args): ) if __opts__.get("test", False): ret["result"] = None - ret["comment"] += "\n{}".format(comment) + ret["comment"] += f"\n{comment}" return ret else: - ret["comment"] += "\n{}".format(comment) + ret["comment"] += f"\n{comment}" if alter_charset or alter_collate: if __opts__.get("test", False): - ret["comment"] += "\nDatabase {} is going to be updated".format(name) + ret["comment"] += f"\nDatabase {name} is going to be updated" else: __salt__["mysql.alter_db"]( name, character_set=character_set, collate=collate, - **connection_args + **connection_args, ) current = __salt__["mysql.db_get"](name, **connection_args) @@ -145,13 +145,13 @@ def present(name, character_set=None, collate=None, **connection_args): if __salt__["mysql.db_create"]( name, character_set=character_set, collate=collate, **connection_args ): - ret["comment"] = "The database {} has been created".format(name) + ret["comment"] = f"The database {name} has been created" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" ret["result"] = False return ret @@ -175,13 +175,13 @@ def absent(name, **connection_args): ) return ret if __salt__["mysql.db_remove"](name, **connection_args): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret else: err = _get_mysql_error() if err is not None: - ret["comment"] = "Unable to remove database {} ({})".format(name, err) + ret["comment"] = f"Unable to remove database {name} ({err})" ret["result"] = False return ret else: @@ -192,5 +192,5 @@ def absent(name, **connection_args): return ret # fallback - ret["comment"] = "Database {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Database {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/mysql_grants.py b/salt/states/mysql_grants.py index cefba9465bc..74e1c8346b5 100644 --- a/salt/states/mysql_grants.py +++ b/salt/states/mysql_grants.py @@ -77,7 +77,7 @@ def present( escape=True, revoke_first=False, ssl_option=False, - **connection_args + **connection_args, ): """ Ensure that the grant is present with the specified properties @@ -182,14 +182,14 @@ def present( host=host, grant_option=grant_option, escape=escape, - **connection_args + **connection_args, ) # The grant is not present, make it! if __opts__["test"]: # there is probably better things to make in test mode ret["result"] = None - ret["comment"] = "MySQL grant {} is set to be created".format(name) + ret["comment"] = f"MySQL grant {name} is set to be created" return ret if __salt__["mysql.grant_add"]( grant, database, user, host, grant_option, escape, ssl_option, **connection_args @@ -202,7 +202,7 @@ def present( ret["comment"] = ret["comment"].format(grant, database, user, host) err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" ret["result"] = False return ret @@ -215,7 +215,7 @@ def absent( host="localhost", grant_option=False, escape=True, - **connection_args + **connection_args, ): """ Ensure that the grant is absent @@ -244,7 +244,7 @@ def absent( if __opts__["test"]: ret["result"] = None - ret["comment"] = "MySQL grant {} is set to be revoked".format(name) + ret["comment"] = f"MySQL grant {name} is set to be revoked" return ret if __salt__["mysql.grant_revoke"]( grant, database, user, host, grant_option, **connection_args diff --git a/salt/states/mysql_query.py b/salt/states/mysql_query.py index 46bac68c201..d0bc6bedfc9 100644 --- a/salt/states/mysql_query.py +++ b/salt/states/mysql_query.py @@ -56,7 +56,7 @@ def run_file( saltenv=None, check_db_exists=True, client_flags=None, - **connection_args + **connection_args, ): """ Execute an arbitrary query on the specified database @@ -103,7 +103,7 @@ def run_file( "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(database), + "comment": f"Database {database} is already present", } if client_flags is None: @@ -124,7 +124,7 @@ def run_file( query_file = __salt__["cp.cache_file"](query_file, saltenv=saltenv or __env__) if not os.path.exists(query_file): - ret["comment"] = "File {} does not exist".format(query_file) + ret["comment"] = f"File {query_file} does not exist" ret["result"] = False return ret @@ -137,7 +137,7 @@ def run_file( return ret ret["result"] = None - ret["comment"] = "Database {} is not present".format(database) + ret["comment"] = f"Database {database} is not present" return ret # Check if execution needed @@ -252,7 +252,7 @@ def run( overwrite=True, check_db_exists=True, client_flags=None, - **connection_args + **connection_args, ): """ Execute an arbitrary query on the specified database @@ -294,7 +294,7 @@ def run( "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(database), + "comment": f"Database {database} is already present", } if client_flags is None: @@ -315,7 +315,7 @@ def run( return ret ret["result"] = None - ret["comment"] = "Database {} is not present".format(name) + ret["comment"] = f"Database {name} is not present" return ret # Check if execution needed @@ -413,7 +413,7 @@ def run( else: for col, val in query_result.items(): output_file.write( - salt.utils.stringutils.to_str("{}:{}\n".format(col, val)) + salt.utils.stringutils.to_str(f"{col}:{val}\n") ) else: ret["changes"]["query"] = "Executed" diff --git a/salt/states/mysql_user.py b/salt/states/mysql_user.py index 61f2caa936a..1c54de4ec5c 100644 --- a/salt/states/mysql_user.py +++ b/salt/states/mysql_user.py @@ -73,7 +73,7 @@ def present( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): """ Ensure that the named user is present with the specified properties. A @@ -117,7 +117,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {}@{} is already present".format(name, host), + "comment": f"User {name}@{host} is already present", } passwordless = not any((password, password_hash)) @@ -138,7 +138,7 @@ def present( passwordless=True, unix_socket=unix_socket, password_column=password_column, - **connection_args + **connection_args, ): if allow_passwordless: ret["comment"] += " with passwordless login" @@ -157,7 +157,7 @@ def present( password_hash, unix_socket=unix_socket, password_column=password_column, - **connection_args + **connection_args, ): if auth_plugin == "mysql_native_password": ret["comment"] += " with the desired password" @@ -180,7 +180,7 @@ def present( # The user is present, change the password if __opts__["test"]: - ret["comment"] = "Password for user {}@{} is set to be ".format(name, host) + ret["comment"] = f"Password for user {name}@{host} is set to be " ret["result"] = None if passwordless: ret["comment"] += "cleared" @@ -198,7 +198,7 @@ def present( password_hash, allow_passwordless, unix_socket, - **connection_args + **connection_args, ): ret["comment"] = "Password for user {}@{} has been {}".format( name, host, "cleared" if passwordless else "changed" @@ -210,7 +210,7 @@ def present( ) err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" if passwordless and not salt.utils.data.is_true(allow_passwordless): ret["comment"] += ( ". Note: allow_passwordless must be True " @@ -227,7 +227,7 @@ def present( # The user is not present, make it! if __opts__["test"]: - ret["comment"] = "User {}@{} is set to be added".format(name, host) + ret["comment"] = f"User {name}@{host} is set to be added" ret["result"] = None if allow_passwordless: ret["comment"] += " with passwordless login" @@ -247,19 +247,19 @@ def present( unix_socket=unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ): - ret["comment"] = "The user {}@{} has been added".format(name, host) + ret["comment"] = f"The user {name}@{host} has been added" if allow_passwordless: ret["comment"] += " with passwordless login" if unix_socket: ret["comment"] += " using unix_socket" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to create user {}@{}".format(name, host) + ret["comment"] = f"Failed to create user {name}@{host}" err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" ret["result"] = False return ret @@ -278,10 +278,10 @@ def absent(name, host="localhost", **connection_args): if __salt__["mysql.user_exists"](name, host, **connection_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {}@{} is set to be removed".format(name, host) + ret["comment"] = f"User {name}@{host} is set to be removed" return ret if __salt__["mysql.user_remove"](name, host, **connection_args): - ret["comment"] = "User {}@{} has been removed".format(name, host) + ret["comment"] = f"User {name}@{host} has been removed" ret["changes"][name] = "Absent" return ret else: diff --git a/salt/states/netconfig.py b/salt/states/netconfig.py index 2b050e8abee..17870ab4afd 100644 --- a/salt/states/netconfig.py +++ b/salt/states/netconfig.py @@ -67,7 +67,7 @@ def _update_config( commit=True, debug=False, replace=False, - **template_vars + **template_vars, ): """ Call the necessary functions in order to execute the state. @@ -92,7 +92,7 @@ def _update_config( commit=commit, debug=debug, replace=replace, - **template_vars + **template_vars, ) @@ -275,7 +275,7 @@ def saved( win_deny_perms=None, win_inheritance=True, win_perms_reset=False, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -452,7 +452,7 @@ def saved( win_deny_perms=win_deny_perms, win_inheritance=win_inheritance, win_perms_reset=win_perms_reset, - **kwargs + **kwargs, ) @@ -475,7 +475,7 @@ def managed( commit_at=None, revert_in=None, revert_at=None, - **template_vars + **template_vars, ): """ Manages the configuration on network devices. @@ -851,7 +851,7 @@ def managed( revert_at=revert_at, debug=debug, replace=replace, - **template_vars + **template_vars, ) return salt.utils.napalm.loaded_ret(ret, config_update_ret, test, debug) @@ -877,7 +877,7 @@ def commit_cancelled(name): """ cancelled = {"name": name, "result": None, "changes": {}, "comment": ""} if __opts__["test"]: - cancelled["comment"] = "It would cancel commit #{}".format(name) + cancelled["comment"] = f"It would cancel commit #{name}" return cancelled ret = __salt__["net.cancel_commit"](name) cancelled.update(ret) @@ -904,7 +904,7 @@ def commit_confirmed(name): """ confirmed = {"name": name, "result": None, "changes": {}, "comment": ""} if __opts__["test"]: - confirmed["comment"] = "It would confirm commit #{}".format(name) + confirmed["comment"] = f"It would confirm commit #{name}" return confirmed ret = __salt__["net.confirm_commit"](name) confirmed.update(ret) diff --git a/salt/states/netntp.py b/salt/states/netntp.py index e0efb1b14a5..561b5bbda12 100644 --- a/salt/states/netntp.py +++ b/salt/states/netntp.py @@ -178,7 +178,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): if name not in _options: return _ret - _retrieve_fun = "_retrieve_ntp_{what}".format(what=name) + _retrieve_fun = f"_retrieve_ntp_{name}" ntp_list_output = _exec_fun( _retrieve_fun ) # contains only IP Addresses as dictionary keys @@ -195,7 +195,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): if configured_ntp_list == desired_ntp_list: _ret.update( { - "comment": "NTP {what} already configured as needed.".format(what=name), + "comment": f"NTP {name} already configured as needed.", "result": True, } ) @@ -231,7 +231,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): comment = "" if list_to_set: - _set_fun = "_set_ntp_{what}".format(what=name) + _set_fun = f"_set_ntp_{name}" _set = _exec_fun(_set_fun, list_to_set) if _set.get("result"): expected_config_change = True @@ -242,7 +242,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): ) if list_to_delete: - _delete_fun = "_delete_ntp_{what}".format(what=name) + _delete_fun = f"_delete_ntp_{name}" _removed = _exec_fun(_delete_fun, list_to_delete) if _removed.get("result"): expected_config_change = True diff --git a/salt/states/netsnmp.py b/salt/states/netsnmp.py index 325ca88e9f7..f18dbd8b44f 100644 --- a/salt/states/netsnmp.py +++ b/salt/states/netsnmp.py @@ -246,7 +246,7 @@ def _configure(changes): _chassis_id = _updated_changes.get("chassis_id", "") if key == "removed": fun = "remove_config" - _ret = __salt__["snmp.{fun}".format(fun=fun)]( + _ret = __salt__[f"snmp.{fun}"]( location=_location, contact=_contact, community=_community, diff --git a/salt/states/netusers.py b/salt/states/netusers.py index 98b589cfb90..350fe5b471c 100644 --- a/salt/states/netusers.py +++ b/salt/states/netusers.py @@ -83,7 +83,7 @@ def _check_users(users): for user, user_details in users.items(): if not user_details: valid = False - messg += "Please provide details for username {user}.\n".format(user=user) + messg += f"Please provide details for username {user}.\n" continue if not ( isinstance(user_details.get("level"), int) diff --git a/salt/states/network.py b/salt/states/network.py index d3a2a2e203d..383b1b69243 100644 --- a/salt/states/network.py +++ b/salt/states/network.py @@ -482,7 +482,7 @@ def managed(name, enabled=True, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Interface {} is up to date.".format(name), + "comment": f"Interface {name} is up to date.", } if "test" not in kwargs: kwargs["test"] = __opts__.get("test", False) @@ -513,7 +513,7 @@ def managed(name, enabled=True, **kwargs): pass if not old and new: ret["result"] = None - ret["comment"] = "Interface {} is set to be added.".format(name) + ret["comment"] = f"Interface {name} is set to be added." elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None @@ -522,12 +522,12 @@ def managed(name, enabled=True, **kwargs): ) else: if not old and new: - ret["comment"] = "Interface {} added.".format(name) + ret["comment"] = f"Interface {name} added." ret["changes"]["interface"] = "Added network interface." apply_ranged_setting = True elif old != new: diff = difflib.unified_diff(old, new, lineterm="") - ret["comment"] = "Interface {} updated.".format(name) + ret["comment"] = f"Interface {name} updated." ret["changes"]["interface"] = "\n".join(diff) apply_ranged_setting = True except AttributeError as error: @@ -561,12 +561,12 @@ def managed(name, enabled=True, **kwargs): ) else: if not old and new: - ret["comment"] = "Bond interface {} added.".format(name) - ret["changes"]["bond"] = "Added bond {}.".format(name) + ret["comment"] = f"Bond interface {name} added." + ret["changes"]["bond"] = f"Added bond {name}." apply_ranged_setting = True elif old != new: diff = difflib.unified_diff(old, new, lineterm="") - ret["comment"] = "Bond interface {} updated.".format(name) + ret["comment"] = f"Bond interface {name} updated." ret["changes"]["bond"] = "\n".join(diff) apply_ranged_setting = True except AttributeError as error: @@ -626,17 +626,17 @@ def managed(name, enabled=True, **kwargs): # Interface should restart to validate if it's up __salt__["ip.down"](name, iface_type) __salt__["ip.up"](name, iface_type) - ret["changes"]["status"] = ( - "Interface {} restart to validate".format(name) - ) + ret["changes"][ + "status" + ] = f"Interface {name} restart to validate" else: __salt__["ip.up"](name, iface_type) - ret["changes"]["status"] = "Interface {} is up".format(name) + ret["changes"]["status"] = f"Interface {name} is up" else: if "noifupdown" not in kwargs: if interface_status: __salt__["ip.down"](name, iface_type) - ret["changes"]["status"] = "Interface {} down".format(name) + ret["changes"]["status"] = f"Interface {name} down" except Exception as error: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(error) @@ -648,7 +648,7 @@ def managed(name, enabled=True, **kwargs): if "slaves" in kwargs and kwargs["slaves"]: # Check that there are new slaves for this master present_slaves = __salt__["cmd.run"]( - ["cat", "/sys/class/net/{}/bonding/slaves".format(name)] + ["cat", f"/sys/class/net/{name}/bonding/slaves"] ).split() if isinstance(kwargs["slaves"], list): desired_slaves = kwargs["slaves"] @@ -706,7 +706,7 @@ def routes(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Interface {} routes are up to date.".format(name), + "comment": f"Interface {name} routes are up to date.", } apply_routes = False if "test" not in kwargs: @@ -721,7 +721,7 @@ def routes(name, **kwargs): return ret if not old and new: ret["result"] = None - ret["comment"] = "Interface {} routes are set to be added.".format(name) + ret["comment"] = f"Interface {name} routes are set to be added." return ret elif old != new: diff = difflib.unified_diff(old, new, lineterm="") @@ -734,12 +734,12 @@ def routes(name, **kwargs): return ret if not old and new: apply_routes = True - ret["comment"] = "Interface {} routes added.".format(name) - ret["changes"]["network_routes"] = "Added interface {} routes.".format(name) + ret["comment"] = f"Interface {name} routes added." + ret["changes"]["network_routes"] = f"Added interface {name} routes." elif old != new: diff = difflib.unified_diff(old, new, lineterm="") apply_routes = True - ret["comment"] = "Interface {} routes updated.".format(name) + ret["comment"] = f"Interface {name} routes updated." ret["changes"]["network_routes"] = "\n".join(diff) except AttributeError as error: ret["result"] = False diff --git a/salt/states/neutron_network.py b/salt/states/neutron_network.py index 3361675749a..2dc5bc0a3a0 100644 --- a/salt/states/neutron_network.py +++ b/salt/states/neutron_network.py @@ -98,7 +98,7 @@ def present(name, auth=None, **kwargs): del kwargs["project"] else: ret["result"] = False - ret["comment"] = "Project:{} not found.".format(projectname) + ret["comment"] = f"Project:{projectname} not found." return ret network = __salt__["neutronng.network_create"](**kwargs) diff --git a/salt/states/neutron_secgroup_rule.py b/salt/states/neutron_secgroup_rule.py index 3c65fc34308..219455a8447 100644 --- a/salt/states/neutron_secgroup_rule.py +++ b/salt/states/neutron_secgroup_rule.py @@ -95,7 +95,7 @@ def present(name, auth=None, **kwargs): if secgroup is None: ret["result"] = False ret["changes"] = ({},) - ret["comment"] = "Security Group does not exist {}".format(name) + ret["comment"] = f"Security Group does not exist {name}" return ret # we have to search through all secgroup rules for a possible match diff --git a/salt/states/nfs_export.py b/salt/states/nfs_export.py index ad572739d7f..27d6b853d54 100644 --- a/salt/states/nfs_export.py +++ b/salt/states/nfs_export.py @@ -140,14 +140,14 @@ def present(name, clients=None, hosts=None, options=None, exports="/etc/exports" if path in old: if old[path] == clients: ret["result"] = True - ret["comment"] = "Export {} already configured".format(path) + ret["comment"] = f"Export {path} already configured" return ret ret["changes"]["new"] = clients ret["changes"]["old"] = old[path] if __opts__["test"]: ret["result"] = None - ret["comment"] = "Export {} would be changed".format(path) + ret["comment"] = f"Export {path} would be changed" return ret __salt__["nfs3.del_export"](exports, path) @@ -157,7 +157,7 @@ def present(name, clients=None, hosts=None, options=None, exports="/etc/exports" ret["changes"]["new"] = clients if __opts__["test"]: ret["result"] = None - ret["comment"] = "Export {} would be added".format(path) + ret["comment"] = f"Export {path} would be added" return ret add_export = __salt__["nfs3.add_export"] @@ -186,7 +186,7 @@ def absent(name, exports="/etc/exports"): old = __salt__["nfs3.list_exports"](exports) if path in old: if __opts__["test"]: - ret["comment"] = "Export {} would be removed".format(path) + ret["comment"] = f"Export {path} would be removed" ret["changes"][path] = old[path] ret["result"] = None return ret @@ -196,12 +196,12 @@ def absent(name, exports="/etc/exports"): if not try_reload["result"]: ret["comment"] = try_reload["stderr"] else: - ret["comment"] = "Export {} removed".format(path) + ret["comment"] = f"Export {path} removed" ret["result"] = try_reload["result"] ret["changes"][path] = old[path] else: - ret["comment"] = "Export {} already absent".format(path) + ret["comment"] = f"Export {path} already absent" ret["result"] = True return ret diff --git a/salt/states/nftables.py b/salt/states/nftables.py index 2088e51efea..fa9a33fb929 100644 --- a/salt/states/nftables.py +++ b/salt/states/nftables.py @@ -438,7 +438,7 @@ def delete(name, family="ipv4", **kwargs): if res["result"]: ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Delete nftables rule for {} {}".format(name, command.strip()) + ret["comment"] = f"Delete nftables rule for {name} {command.strip()}" if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) @@ -642,7 +642,7 @@ def table_present(name, family="ipv4", **kwargs): ) else: ret["result"] = False - ret["comment"] = "Failed to create table {} for family {}".format(name, family) + ret["comment"] = f"Failed to create table {name} for family {family}" return ret @@ -687,6 +687,6 @@ def table_absent(name, family="ipv4", **kwargs): ) else: ret["result"] = False - ret["comment"] = "Failed to delete table {} from family {}".format(name, family) + ret["comment"] = f"Failed to delete table {name} from family {family}" return ret diff --git a/salt/states/npm.py b/salt/states/npm.py index 8f7415d1f58..1e8b942f90c 100644 --- a/salt/states/npm.py +++ b/salt/states/npm.py @@ -94,7 +94,7 @@ def installed( installed_pkgs = __salt__["npm.list"](dir=dir, runas=user, env=env, depth=0) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" return ret else: installed_pkgs = {p: info for p, info in installed_pkgs.items()} @@ -238,26 +238,26 @@ def removed(name, dir=None, user=None): installed_pkgs = __salt__["npm.list"](dir=dir, depth=0) except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error uninstalling '{}': {}".format(name, err) + ret["comment"] = f"Error uninstalling '{name}': {err}" return ret if name not in installed_pkgs: ret["result"] = True - ret["comment"] = "Package '{}' is not installed".format(name) + ret["comment"] = f"Package '{name}' is not installed" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package '{}' is set to be removed".format(name) + ret["comment"] = f"Package '{name}' is set to be removed" return ret if __salt__["npm.uninstall"](pkg=name, dir=dir, runas=user): ret["result"] = True ret["changes"][name] = "Removed" - ret["comment"] = "Package '{}' was successfully removed".format(name) + ret["comment"] = f"Package '{name}' was successfully removed" else: ret["result"] = False - ret["comment"] = "Error removing package '{}'".format(name) + ret["comment"] = f"Error removing package '{name}'" return ret @@ -283,20 +283,20 @@ def bootstrap(name, user=None, silent=True): if call: ret["result"] = None ret["changes"] = {"old": [], "new": call} - ret["comment"] = "{} is set to be bootstrapped".format(name) + ret["comment"] = f"{name} is set to be bootstrapped" else: ret["result"] = True - ret["comment"] = "{} is already bootstrapped".format(name) + ret["comment"] = f"{name} is already bootstrapped" except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error Bootstrapping '{}': {}".format(name, err) + ret["comment"] = f"Error Bootstrapping '{name}': {err}" return ret try: call = __salt__["npm.install"](dir=name, runas=user, pkg=None, silent=silent) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error Bootstrapping '{}': {}".format(name, err) + ret["comment"] = f"Error Bootstrapping '{name}': {err}" return ret if not call: @@ -350,11 +350,11 @@ def cache_cleaned(name=None, user=None, force=False): all_cached_pkgs = __salt__["npm.cache_list"](path=None, runas=user) # The first package is always the cache path cache_root_path = all_cached_pkgs[0] - specific_pkg = "{}/{}/".format(cache_root_path, name) + specific_pkg = f"{cache_root_path}/{name}/" if specific_pkg not in cached_pkgs: ret["result"] = True - ret["comment"] = "Package {} is not in the cache".format(name) + ret["comment"] = f"Package {name} is not in the cache" return ret if __opts__["test"]: diff --git a/salt/states/nxos.py b/salt/states/nxos.py index 6888413e859..6d413d45548 100644 --- a/salt/states/nxos.py +++ b/salt/states/nxos.py @@ -352,7 +352,7 @@ def replace(name, repl, full_match=False): ret = {"name": name, "result": False, "changes": {}, "comment": ""} if full_match is False: - search = "^.*{}.*$".format(name) + search = f"^.*{name}.*$" else: search = name @@ -376,7 +376,7 @@ def replace(name, repl, full_match=False): if matches: ret["result"] = False - ret["comment"] = 'Failed to replace all instances of "{}"'.format(name) + ret["comment"] = f'Failed to replace all instances of "{name}"' else: ret["result"] = True ret["comment"] = 'Successfully replaced all instances of "{}" with "{}"'.format( diff --git a/salt/states/nxos_upgrade.py b/salt/states/nxos_upgrade.py index daa22f6fcfc..f4960b777be 100644 --- a/salt/states/nxos_upgrade.py +++ b/salt/states/nxos_upgrade.py @@ -90,7 +90,7 @@ def image_running(name, system_image, kickstart_image=None, issu=True, **kwargs) system_image=system_image, kickstart_image=kickstart_image, issu=issu, - **kwargs + **kwargs, ) if upgrade["upgrade_in_progress"]: @@ -99,7 +99,7 @@ def image_running(name, system_image, kickstart_image=None, issu=True, **kwargs) ret["comment"] = "NX-OS Device Now Being Upgraded - See Change Details Below" elif upgrade["succeeded"]: ret["result"] = upgrade["succeeded"] - ret["comment"] = "NX-OS Device Running Image: {}".format(_version_info()) + ret["comment"] = f"NX-OS Device Running Image: {_version_info()}" else: ret["comment"] = "Upgrade Failed: {}.".format(upgrade["error_data"]) diff --git a/salt/states/openstack_config.py b/salt/states/openstack_config.py index e635366f696..bad221a802a 100644 --- a/salt/states/openstack_config.py +++ b/salt/states/openstack_config.py @@ -112,7 +112,7 @@ def absent(name, filename, section, parameter=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Value '{}' is set to be deleted.".format(old_value) + ret["comment"] = f"Value '{old_value}' is set to be deleted." return ret __salt__["openstack_config.delete"]( diff --git a/salt/states/openvswitch_bridge.py b/salt/states/openvswitch_bridge.py index 13c4109598d..2949dc53dbd 100644 --- a/salt/states/openvswitch_bridge.py +++ b/salt/states/openvswitch_bridge.py @@ -32,16 +32,16 @@ def present(name, parent=None, vlan=None): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_bridge_created = "Bridge {} created.".format(name) - comment_bridge_notcreated = "Unable to create bridge: {}.".format(name) - comment_bridge_exists = "Bridge {} already exists.".format(name) + comment_bridge_created = f"Bridge {name} created." + comment_bridge_notcreated = f"Unable to create bridge: {name}." + comment_bridge_exists = f"Bridge {name} already exists." comment_bridge_mismatch = ( "Bridge {} already exists, but has a different" " parent or VLAN ID." ).format(name) changes_bridge_created = { name: { - "old": "Bridge {} does not exist.".format(name), - "new": "Bridge {} created".format(name), + "old": f"Bridge {name} does not exist.", + "new": f"Bridge {name} created", } } @@ -103,13 +103,13 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_bridge_deleted = "Bridge {} deleted.".format(name) - comment_bridge_notdeleted = "Unable to delete bridge: {}.".format(name) - comment_bridge_notexists = "Bridge {} does not exist.".format(name) + comment_bridge_deleted = f"Bridge {name} deleted." + comment_bridge_notdeleted = f"Unable to delete bridge: {name}." + comment_bridge_notexists = f"Bridge {name} does not exist." changes_bridge_deleted = { name: { - "old": "Bridge {} exists.".format(name), - "new": "Bridge {} deleted.".format(name), + "old": f"Bridge {name} exists.", + "new": f"Bridge {name} deleted.", } } diff --git a/salt/states/openvswitch_port.py b/salt/states/openvswitch_port.py index efacfe5800f..a4591c6da12 100644 --- a/salt/states/openvswitch_port.py +++ b/salt/states/openvswitch_port.py @@ -47,18 +47,18 @@ def present( comments = {} - comments["comment_bridge_notexists"] = "Bridge {} does not exist.".format(bridge) - comments["comment_port_exists"] = "Port {} already exists.".format(name) + comments["comment_bridge_notexists"] = f"Bridge {bridge} does not exist." + comments["comment_port_exists"] = f"Port {name} already exists." comments["comment_port_created"] = "Port {} created on bridge {}.".format( name, bridge ) comments["comment_port_notcreated"] = ( - "Unable to create port {} on bridge {}.".format(name, bridge) + f"Unable to create port {name} on bridge {bridge}." ) comments["changes_port_created"] = { name: { - "old": "No port named {} present.".format(name), - "new": "Created port {1} on bridge {0}.".format(bridge, name), + "old": f"No port named {name} present.", + "new": f"Created port {name} on bridge {bridge}.", } } comments["comment_port_internal"] = ( @@ -77,7 +77,7 @@ def present( if tunnel_type == "vlan": comments["comment_vlan_invalid_id"] = "VLANs id must be between 0 and 4095." comments["comment_vlan_invalid_name"] = ( - "Could not find network interface {}.".format(name) + f"Could not find network interface {name}." ) comments["comment_vlan_port_exists"] = ( "Port {} with access to VLAN {} already exists on bridge {}.".format( @@ -234,11 +234,7 @@ def present( 'dst_port="' + str(dst_port) + '", ' if 0 < dst_port <= 65535 else "" ) interface_attroptions = ( - '{{{0}key="'.format(opt_port) - + str(id) - + '", remote_ip="' - + str(remote) - + '"}' + f'{{{opt_port}key="' + str(id) + '", remote_ip="' + str(remote) + '"}' ) try: if ( @@ -388,16 +384,16 @@ def absent(name, bridge=None): # Comment and change messages comments = {} - comments["comment_bridge_notexists"] = "Bridge {} does not exist.".format(bridge) + comments["comment_bridge_notexists"] = f"Bridge {bridge} does not exist." comments["comment_port_notexists"] = "Port {} does not exist on bridge {}.".format( name, bridge ) - comments["comment_port_deleted"] = "Port {} deleted.".format(name) - comments["comment_port_notdeleted"] = "Unable to delete port {}.".format(name) + comments["comment_port_deleted"] = f"Port {name} deleted." + comments["comment_port_notdeleted"] = f"Unable to delete port {name}." comments["changes_port_deleted"] = { name: { - "old": "Port named {} may exist.".format(name), - "new": "Deleted port {}.".format(name), + "old": f"Port named {name} may exist.", + "new": f"Deleted port {name}.", } } diff --git a/salt/states/pagerduty.py b/salt/states/pagerduty.py index bfdd82f28ac..2be04eff915 100644 --- a/salt/states/pagerduty.py +++ b/salt/states/pagerduty.py @@ -57,7 +57,7 @@ def create_event(name, details, service_key, profile): """ ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __opts__["test"]: - ret["comment"] = "Need to create event: {}".format(name) + ret["comment"] = f"Need to create event: {name}" return ret __salt__["pagerduty.create_event"]( description=name, @@ -66,5 +66,5 @@ def create_event(name, details, service_key, profile): profile=profile, ) ret["result"] = True - ret["comment"] = "Created event: {}".format(name) + ret["comment"] = f"Created event: {name}" return ret diff --git a/salt/states/pagerduty_escalation_policy.py b/salt/states/pagerduty_escalation_policy.py index 44e663e4ea3..3b3594587d4 100644 --- a/salt/states/pagerduty_escalation_policy.py +++ b/salt/states/pagerduty_escalation_policy.py @@ -96,7 +96,7 @@ def present(profile="pagerduty", subdomain=None, api_key=None, **kwargs): if schedule: target_id = schedule["schedule"]["id"] if target_id is None: - raise Exception("unidentified target: {}".format(target)) + raise Exception(f"unidentified target: {target}") target["id"] = target_id r = __salt__["pagerduty_util.resource_present"]( @@ -106,7 +106,7 @@ def present(profile="pagerduty", subdomain=None, api_key=None, **kwargs): profile, subdomain, api_key, - **kwargs + **kwargs, ) return r @@ -143,7 +143,7 @@ def _diff(state_data, resource_object): else: resource_value = resource_object[k] if v != resource_value: - objects_differ = "{} {} {}".format(k, v, resource_value) + objects_differ = f"{k} {v} {resource_value}" break if objects_differ: diff --git a/salt/states/pagerduty_schedule.py b/salt/states/pagerduty_schedule.py index 75f705f6086..5947dbc4b0a 100644 --- a/salt/states/pagerduty_schedule.py +++ b/salt/states/pagerduty_schedule.py @@ -65,7 +65,7 @@ def present(profile="pagerduty", subdomain=None, api_key=None, **kwargs): api_key=api_key, ) if u is None: - raise Exception("unknown user: {}".format(user)) + raise Exception(f"unknown user: {user}") user["user"]["id"] = u["id"] r = __salt__["pagerduty_util.resource_present"]( "schedules", ["name", "id"], _diff, profile, subdomain, api_key, **kwargs diff --git a/salt/states/pagerduty_service.py b/salt/states/pagerduty_service.py index f615aff7a7b..f17c7ef6087 100644 --- a/salt/states/pagerduty_service.py +++ b/salt/states/pagerduty_service.py @@ -110,7 +110,7 @@ def _diff(state_data, resource_object): else: resource_value = resource_object[k] if v != resource_value: - objects_differ = "{} {} {}".format(k, v, resource_value) + objects_differ = f"{k} {v} {resource_value}" break if objects_differ: diff --git a/salt/states/panos.py b/salt/states/panos.py index fb915bbdb78..5ea57dbf0dd 100644 --- a/salt/states/panos.py +++ b/salt/states/panos.py @@ -108,10 +108,10 @@ def _build_members(members, anycheck=False): return "any" response = "" for m in members: - response += "{}".format(m) + response += f"{m}" return response else: - return "{}".format(members) + return f"{members}" def _default_ret(name): @@ -354,19 +354,19 @@ def address_exists( # Verify the arguments if ipnetmask: - element = "{}".format(ipnetmask) + element = f"{ipnetmask}" elif iprange: - element = "{}".format(iprange) + element = f"{iprange}" elif fqdn: - element = "{}".format(fqdn) + element = f"{fqdn}" else: ret.update({"comment": "A valid address type must be specified."}) return ret if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(addressname, element) + full_element = f"{element}" new_address = xml.to_dict(ET.fromstring(full_element), True) @@ -467,15 +467,15 @@ def address_group_exists( # Verify the arguments if members: - element = "{}".format(_build_members(members, True)) + element = f"{_build_members(members, True)}" else: ret.update({"comment": "The group members must be provided."}) return ret if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(groupname, element) + full_element = f"{element}" new_group = xml.to_dict(ET.fromstring(full_element), True) @@ -1117,19 +1117,19 @@ def security_rule_exists( # Build the rule element element = "" if sourcezone: - element += "{}".format(_build_members(sourcezone, True)) + element += f"{_build_members(sourcezone, True)}" else: ret.update({"comment": "The sourcezone field must be provided."}) return ret if destinationzone: - element += "{}".format(_build_members(destinationzone, True)) + element += f"{_build_members(destinationzone, True)}" else: ret.update({"comment": "The destinationzone field must be provided."}) return ret if source: - element += "{}".format(_build_members(source, True)) + element += f"{_build_members(source, True)}" else: ret.update({"comment": "The source field must be provided."}) return @@ -1151,13 +1151,13 @@ def security_rule_exists( return ret if service: - element += "{}".format(_build_members(service, True)) + element += f"{_build_members(service, True)}" else: ret.update({"comment": "The service field must be provided."}) return ret if action: - element += "{}".format(action) + element += f"{action}" else: ret.update({"comment": "The action field must be provided."}) return ret @@ -1169,10 +1169,10 @@ def security_rule_exists( element += "no" if description: - element += "{}".format(description) + element += f"{description}" if logsetting: - element += "{}".format(logsetting) + element += f"{logsetting}" if logstart is not None: if logstart: @@ -1201,7 +1201,7 @@ def security_rule_exists( # Build the profile settings profile_string = None if profilegroup: - profile_string = "{}".format(profilegroup) + profile_string = f"{profilegroup}" else: member_string = "" if datafilter: @@ -1212,16 +1212,16 @@ def security_rule_exists( ) if fileblock: member_string += ( - "{}".format(fileblock) + f"{fileblock}" ) if spyware: - member_string += "{}".format(spyware) + member_string += f"{spyware}" if urlfilter: member_string += ( - "{}".format(urlfilter) + f"{urlfilter}" ) if virus: - member_string += "{}".format(virus) + member_string += f"{virus}" if vulnerability: member_string += ( "{}".format( @@ -1235,12 +1235,12 @@ def security_rule_exists( ) ) if member_string != "": - profile_string = "{}".format(member_string) + profile_string = f"{member_string}" if profile_string: - element += "{}".format(profile_string) + element += f"{profile_string}" - full_element = "{}".format(rulename, element) + full_element = f"{element}" new_rule = xml.to_dict(ET.fromstring(full_element), True) @@ -1380,9 +1380,9 @@ def service_exists( element = "<{0}>{1}".format(protocol, port) if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(servicename, element) + full_element = f"{element}" new_service = xml.to_dict(ET.fromstring(full_element), True) @@ -1483,15 +1483,15 @@ def service_group_exists( # Verify the arguments if members: - element = "{}".format(_build_members(members, True)) + element = f"{_build_members(members, True)}" else: ret.update({"comment": "The group members must be provided."}) return ret if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(groupname, element) + full_element = f"{element}" new_group = xml.to_dict(ET.fromstring(full_element), True) diff --git a/salt/states/pbm.py b/salt/states/pbm.py index 6e761f41957..8b2c3eb2a4b 100644 --- a/salt/states/pbm.py +++ b/salt/states/pbm.py @@ -152,7 +152,7 @@ def default_vsan_policy_configured(name, policy): # All allowed proxies have a shim execution module with the same # name which implementes a get_details function # All allowed proxies have a vcenter detail - vcenter = __salt__["{}.get_details".format(proxy_type)]()["vcenter"] + vcenter = __salt__[f"{proxy_type}.get_details"]()["vcenter"] log.info("Running %s on vCenter '%s'", name, vcenter) log.trace("policy = %s", policy) changes_required = False @@ -214,7 +214,7 @@ def default_vsan_policy_configured(name, policy): if subprofile_differ.diffs: str_changes.extend( [ - " {}".format(change) + f" {change}" for change in subprofile_differ.changes_str.split("\n") ] ) @@ -222,7 +222,7 @@ def default_vsan_policy_configured(name, policy): str_changes.append(" capabilities:") str_changes.extend( [ - " {}".format(change) + f" {change}" for change in capabilities_differ.changes_str2.split( "\n" ) @@ -240,7 +240,7 @@ def default_vsan_policy_configured(name, policy): service_instance=si, ) comments.append( - "Updated the default VSAN policy in vCenter '{}'".format(vcenter) + f"Updated the default VSAN policy in vCenter '{vcenter}'" ) log.info(comments[-1]) @@ -319,7 +319,7 @@ def storage_policies_configured(name, policies): # All allowed proxies have a shim execution module with the same # name which implementes a get_details function # All allowed proxies have a vcenter detail - vcenter = __salt__["{}.get_details".format(proxy_type)]()["vcenter"] + vcenter = __salt__[f"{proxy_type}.get_details"]()["vcenter"] log.info("Running state '%s' on vCenter '%s'", name, vcenter) si = __salt__["vsphere.get_service_instance_via_proxy"]() current_policies = __salt__["vsphere.list_storage_policies"]( @@ -401,7 +401,7 @@ def storage_policies_configured(name, policies): if subprofile_differ.diffs: str_changes.extend( [ - " {}".format(change) + f" {change}" for change in subprofile_differ.changes_str.split( "\n" ) @@ -411,7 +411,7 @@ def storage_policies_configured(name, policies): str_changes.append(" capabilities:") str_changes.extend( [ - " {}".format(change) + f" {change}" for change in capabilities_differ.changes_str2.split( "\n" ) diff --git a/salt/states/pcs.py b/salt/states/pcs.py index cd124c1a82a..662d8935134 100644 --- a/salt/states/pcs.py +++ b/salt/states/pcs.py @@ -229,7 +229,7 @@ def _get_cibfile_tmp(cibname): """ Get the full path of a temporary CIB-file with the name of the CIB """ - cibfile_tmp = "{}.tmp".format(_get_cibfile(cibname)) + cibfile_tmp = f"{_get_cibfile(cibname)}.tmp" log.trace("cibfile_tmp: %s", cibfile_tmp) return cibfile_tmp @@ -238,7 +238,7 @@ def _get_cibfile_cksum(cibname): """ Get the full path of the file containing a checksum of a CIB-file with the name of the CIB """ - cibfile_cksum = "{}.cksum".format(_get_cibfile(cibname)) + cibfile_cksum = f"{_get_cibfile(cibname)}.cksum" log.trace("cibfile_cksum: %s", cibfile_cksum) return cibfile_cksum @@ -336,7 +336,7 @@ def _item_present( # constraints match on '(id:)' elif item in ["constraint"]: for line in is_existing["stdout"].splitlines(): - if "(id:{})".format(item_id) in line: + if f"(id:{item_id})" in line: item_create_required = False # item_id was provided, @@ -370,7 +370,7 @@ def _item_present( log.trace("Output of pcs.item_create: %s", item_create) if item_create["retcode"] in [0]: - ret["comment"] += "Created {} {} ({})\n".format(item, item_id, item_type) + ret["comment"] += f"Created {item} {item_id} ({item_type})\n" ret["changes"].update({item_id: {"old": "", "new": str(item_id)}}) else: ret["result"] = False @@ -435,11 +435,11 @@ def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=Non authorized_dict[node] == "Already authorized" or authorized_dict[node] == "Authorized" ): - ret["comment"] += "Node {} is already authorized\n".format(node) + ret["comment"] += f"Node {node} is already authorized\n" else: auth_required = True if __opts__["test"]: - ret["comment"] += "Node is set to authorize: {}\n".format(node) + ret["comment"] += f"Node is set to authorize: {node}\n" if not auth_required: return ret @@ -463,7 +463,7 @@ def auth(name, nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=Non for node in nodes: if node in authorize_dict and authorize_dict[node] == "Authorized": - ret["comment"] += "Authorized {}\n".format(node) + ret["comment"] += f"Authorized {node}\n" ret["changes"].update({node: {"old": "", "new": "Authorized"}}) else: ret["result"] = False @@ -604,13 +604,13 @@ def cluster_setup( "Success", "Cluster enabled", ]: - ret["comment"] += "Set up {}\n".format(node) + ret["comment"] += f"Set up {node}\n" ret["changes"].update({node: {"old": "", "new": "Setup"}}) else: ret["result"] = False - ret["comment"] += "Failed to setup {}\n".format(node) + ret["comment"] += f"Failed to setup {node}\n" if node in setup_dict: - ret["comment"] += "{}: setup_dict: {}\n".format(node, setup_dict[node]) + ret["comment"] += f"{node}: setup_dict: {setup_dict[node]}\n" ret["comment"] += str(setup) log.trace("ret: %s", ret) @@ -664,7 +664,7 @@ def cluster_node_present(name, node, extra_args=None): node_add_required = False ret[ "comment" - ] += "Node {} is already member of the cluster\n".format(node) + ] += f"Node {node} is already member of the cluster\n" else: current_nodes += value.split() @@ -673,7 +673,7 @@ def cluster_node_present(name, node, extra_args=None): if __opts__["test"]: ret["result"] = None - ret["comment"] += "Node {} is set to be added to the cluster\n".format(node) + ret["comment"] += f"Node {node} is set to be added to the cluster\n" return ret if not isinstance(extra_args, (list, tuple)): @@ -710,11 +710,11 @@ def cluster_node_present(name, node, extra_args=None): ) if node in node_add_dict and node_add_dict[node] in ["Succeeded", "Success"]: - ret["comment"] += "Added node {}\n".format(node) + ret["comment"] += f"Added node {node}\n" ret["changes"].update({node: {"old": "", "new": "Added"}}) else: ret["result"] = False - ret["comment"] += "Failed to add node{}\n".format(node) + ret["comment"] += f"Failed to add node{node}\n" if node in node_add_dict: ret["comment"] += "{}: node_add_dict: {}\n".format( node, node_add_dict[node] @@ -806,10 +806,10 @@ def cib_present(name, cibname, scope=None, extra_args=None): if not cib_create_required: __salt__["file.remove"](cibfile_tmp) - ret["comment"] += "CIB {} is already equal to the live CIB\n".format(cibname) + ret["comment"] += f"CIB {cibname} is already equal to the live CIB\n" if not cib_cksum_required: - ret["comment"] += "CIB {} checksum is correct\n".format(cibname) + ret["comment"] += f"CIB {cibname} checksum is correct\n" if not cib_required: return ret @@ -818,7 +818,7 @@ def cib_present(name, cibname, scope=None, extra_args=None): __salt__["file.remove"](cibfile_tmp) ret["result"] = None if cib_create_required: - ret["comment"] += "CIB {} is set to be created/updated\n".format(cibname) + ret["comment"] += f"CIB {cibname} is set to be created/updated\n" if cib_cksum_required: ret["comment"] += "CIB {} checksum is set to be created/updated\n".format( cibname @@ -829,11 +829,11 @@ def cib_present(name, cibname, scope=None, extra_args=None): __salt__["file.move"](cibfile_tmp, cibfile) if __salt__["file.check_hash"](path=cibfile, file_hash=cib_hash_live): - ret["comment"] += "Created/updated CIB {}\n".format(cibname) + ret["comment"] += f"Created/updated CIB {cibname}\n" ret["changes"].update({"cibfile": cibfile}) else: ret["result"] = False - ret["comment"] += "Failed to create/update CIB {}\n".format(cibname) + ret["comment"] += f"Failed to create/update CIB {cibname}\n" if cib_cksum_required: _file_write(cibfile_cksum, cib_hash_live) @@ -894,7 +894,7 @@ def cib_pushed(name, cibname, scope=None, extra_args=None): if not os.path.exists(cibfile): ret["result"] = False - ret["comment"] += "CIB-file {} does not exist\n".format(cibfile) + ret["comment"] += f"CIB-file {cibfile} does not exist\n" return ret cib_hash_cibfile = "{}:{}".format( @@ -926,11 +926,11 @@ def cib_pushed(name, cibname, scope=None, extra_args=None): log.trace("Output of pcs.cib_push: %s", cib_push) if cib_push["retcode"] in [0]: - ret["comment"] += "Pushed CIB {}\n".format(cibname) + ret["comment"] += f"Pushed CIB {cibname}\n" ret["changes"].update({"cibfile_pushed": cibfile}) else: ret["result"] = False - ret["comment"] += "Failed to push CIB {}\n".format(cibname) + ret["comment"] += f"Failed to push CIB {cibname}\n" log.trace("ret: %s", ret) @@ -968,7 +968,7 @@ def prop_has_value(name, prop, value, extra_args=None, cibname=None): return _item_present( name=name, item="property", - item_id="{}={}".format(prop, value), + item_id=f"{prop}={value}", item_type=None, create="set", extra_args=extra_args, @@ -1008,7 +1008,7 @@ def resource_defaults_to(name, default, value, extra_args=None, cibname=None): return _item_present( name=name, item="resource", - item_id="{}={}".format(default, value), + item_id=f"{default}={value}", item_type=None, show="defaults", create="defaults", @@ -1049,7 +1049,7 @@ def resource_op_defaults_to(name, op_default, value, extra_args=None, cibname=No return _item_present( name=name, item="resource", - item_id="{}={}".format(op_default, value), + item_id=f"{op_default}={value}", item_type=None, show=["op", "defaults"], create=["op", "defaults"], diff --git a/salt/states/pdbedit.py b/salt/states/pdbedit.py index 8a2848f4d39..ea144b69866 100644 --- a/salt/states/pdbedit.py +++ b/salt/states/pdbedit.py @@ -63,7 +63,7 @@ def absent(name): elif res[name] not in ["absent"]: # oops something went wrong ret["result"] = False else: - ret["comment"] = "account {login} is absent".format(login=name) + ret["comment"] = f"account {name} is absent" return ret diff --git a/salt/states/pecl.py b/salt/states/pecl.py index a69a2ca1cb1..e690b5a01e9 100644 --- a/salt/states/pecl.py +++ b/salt/states/pecl.py @@ -73,25 +73,25 @@ def installed( version is None or version in installed_pecls[package] ) and preferred_state in installed_pecls[package]: ret["result"] = True - ret["comment"] = "Pecl extension {} is already installed.".format(name) + ret["comment"] = f"Pecl extension {name} is already installed." return ret if version is not None: # Modify the name to include the version and proceed. - name = "{}-{}".format(name, version) + name = f"{name}-{version}" if __opts__["test"]: - ret["comment"] = "Pecl extension {} would have been installed".format(name) + ret["comment"] = f"Pecl extension {name} would have been installed" return ret if __salt__["pecl.install"]( name, defaults=defaults, force=force, preferred_state=preferred_state ): ret["result"] = True ret["changes"][name] = "Installed" - ret["comment"] = "Pecl extension {} was successfully installed".format(name) + ret["comment"] = f"Pecl extension {name} was successfully installed" else: ret["result"] = False - ret["comment"] = "Could not install pecl extension {}.".format(name) + ret["comment"] = f"Could not install pecl extension {name}." return ret @@ -106,17 +106,17 @@ def removed(name): ret = {"name": name, "result": None, "comment": "", "changes": {}} if name not in __salt__["pecl.list"](): ret["result"] = True - ret["comment"] = "Pecl extension {} is not installed.".format(name) + ret["comment"] = f"Pecl extension {name} is not installed." return ret if __opts__["test"]: - ret["comment"] = "Pecl extension {} would have been removed".format(name) + ret["comment"] = f"Pecl extension {name} would have been removed" return ret if __salt__["pecl.uninstall"](name): ret["result"] = True ret["changes"][name] = "Removed" - ret["comment"] = "Pecl extension {} was successfully removed.".format(name) + ret["comment"] = f"Pecl extension {name} was successfully removed." else: ret["result"] = False - ret["comment"] = "Could not remove pecl extension {}.".format(name) + ret["comment"] = f"Could not remove pecl extension {name}." return ret diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index 917d2748778..97fcdff3930 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -197,7 +197,7 @@ def _check_pkg_version_format(pkg): for vcs in supported_vcs: if pkg.startswith(vcs): from_vcs = True - install_req = _from_line(pkg.split("{}+".format(vcs))[-1]) + install_req = _from_line(pkg.split(f"{vcs}+")[-1]) break else: install_req = _from_line(pkg) @@ -752,7 +752,7 @@ def installed( cur_version = __salt__["pip.version"](bin_env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error installing '{}': {}".format(name, err) + ret["comment"] = f"Error installing '{name}': {err}" return ret # Check that the pip binary supports the 'use_wheel' option if use_wheel: @@ -845,7 +845,7 @@ def installed( # TODO: Check requirements file against currently-installed # packages to provide more accurate state output. comments.append( - "Requirements file '{}' will be processed.".format(requirements) + f"Requirements file '{requirements}' will be processed." ) if editable: comments.append( @@ -950,7 +950,7 @@ def installed( # Call to install the package. Actual installation takes place here pip_install_call = __salt__["pip.install"]( - pkgs="{}".format(pkgs_str) if pkgs_str else "", + pkgs=f"{pkgs_str}" if pkgs_str else "", requirements=requirements, bin_env=bin_env, use_wheel=use_wheel, @@ -1077,10 +1077,10 @@ def installed( and prefix.lower() not in already_installed_packages ): ver = pipsearch[prefix] - ret["changes"]["{}=={}".format(prefix, ver)] = "Installed" + ret["changes"][f"{prefix}=={ver}"] = "Installed" # Case for packages that are an URL else: - ret["changes"]["{}==???".format(state_name)] = "Installed" + ret["changes"][f"{state_name}==???"] = "Installed" # Set comments aicomms = "\n".join(already_installed_comments) @@ -1105,19 +1105,15 @@ def installed( if requirements or editable: comments = [] if requirements: - comments.append( - 'Unable to process requirements file "{}"'.format(requirements) - ) + comments.append(f'Unable to process requirements file "{requirements}"') if editable: - comments.append( - "Unable to install from VCS checkout {}.".format(editable) - ) + comments.append(f"Unable to install from VCS checkout {editable}.") comments.append(error) ret["comment"] = " ".join(comments) else: pkgs_str = ", ".join([state_name for _, state_name in target_pkgs]) aicomms = "\n".join(already_installed_comments) - error_comm = "Failed to install packages: {}. {}".format(pkgs_str, error) + error_comm = f"Failed to install packages: {pkgs_str}. {error}" ret["comment"] = aicomms + ("\n" if aicomms else "") + error_comm else: ret["result"] = False @@ -1155,7 +1151,7 @@ def removed( pip_list = __salt__["pip.list"](bin_env=bin_env, user=user, cwd=cwd) except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error uninstalling '{}': {}".format(name, err) + ret["comment"] = f"Error uninstalling '{name}': {err}" return ret if name not in pip_list: @@ -1165,7 +1161,7 @@ def removed( if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package {} is set to be removed".format(name) + ret["comment"] = f"Package {name} is set to be removed" return ret if __salt__["pip.uninstall"]( diff --git a/salt/states/pkg.py b/salt/states/pkg.py index df57a7477a2..b0ab5f7ef73 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -310,7 +310,7 @@ def _find_download_targets( "name": name, "changes": {}, "result": True, - "comment": "Package {} is already downloaded".format(name), + "comment": f"Package {name} is already downloaded", } version_spec = False @@ -402,7 +402,7 @@ def _find_advisory_targets(name=None, advisory_ids=None, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Advisory patch {} is already installed".format(name), + "comment": f"Advisory patch {name} is already installed", } # Find out which advisory patches will be targeted in the call to pkg.install @@ -613,7 +613,7 @@ def _find_install_targets( "name": name, "changes": {}, "result": False, - "comment": "Package {} not found in the repository.".format(name), + "comment": f"Package {name} not found in the repository.", } if version is None: # pylint: disable=not-callable @@ -657,7 +657,7 @@ def _find_install_targets( "name": name, "changes": {}, "result": True, - "comment": "Package {} is already installed".format(name), + "comment": f"Package {name} is already installed", } version_spec = False @@ -773,13 +773,11 @@ def _find_install_targets( problems.append(err.format(version_string, "file not found")) continue elif not os.path.exists(cached_path): - problems.append("{} does not exist on minion".format(version_string)) + problems.append(f"{version_string} does not exist on minion") continue source_info = __salt__["lowpkg.bin_pkg_info"](cached_path) if source_info is None: - warnings.append( - "Failed to parse metadata for {}".format(version_string) - ) + warnings.append(f"Failed to parse metadata for {version_string}") continue else: verstr = source_info["version"] @@ -1815,7 +1813,7 @@ def installed( summary = ", ".join(targets) changes.update({x: {"new": "installed", "old": ""} for x in targets}) comment.append( - "The following packages would be installed/updated: {}".format(summary) + f"The following packages would be installed/updated: {summary}" ) if to_unpurge: comment.append( @@ -1990,9 +1988,7 @@ def installed( else: summary = ", ".join([_get_desired_pkg(x, desired) for x in modified]) if len(summary) < 20: - comment.append( - "The following packages were installed/updated: {}".format(summary) - ) + comment.append(f"The following packages were installed/updated: {summary}") else: comment.append( "{} targeted package{} {} installed/updated.".format( @@ -2025,9 +2021,7 @@ def installed( else: summary = ", ".join([_get_desired_pkg(x, desired) for x in not_modified]) if len(not_modified) <= 20: - comment.append( - "The following packages were already installed: {}".format(summary) - ) + comment.append(f"The following packages were already installed: {summary}") else: comment.append( "{} targeted package{} {} already installed".format( @@ -2048,9 +2042,7 @@ def installed( summary = ", ".join(failed) else: summary = ", ".join([_get_desired_pkg(x, desired) for x in failed]) - comment.insert( - 0, "The following packages failed to install/update: {}".format(summary) - ) + comment.insert(0, f"The following packages failed to install/update: {summary}") result = False if failed_hold: @@ -2113,7 +2105,7 @@ def installed( pkgstr = modified_pkg else: pkgstr = _get_desired_pkg(modified_pkg, desired) - msg = "Package {} was reinstalled.".format(pkgstr) + msg = f"Package {pkgstr} was reinstalled." if modified_pkg in altered_files: msg += " The following files were remediated:" comment.append(msg) @@ -2128,7 +2120,7 @@ def installed( pkgstr = failed_pkg else: pkgstr = _get_desired_pkg(failed_pkg, desired) - msg = "Reinstall was not successful for package {}.".format(pkgstr) + msg = f"Reinstall was not successful for package {pkgstr}." if failed_pkg in altered_files: msg += " The following files could not be remediated:" comment.append(msg) @@ -2300,7 +2292,7 @@ def downloaded( else: ret["changes"] = {} ret["comment"] = ( - "An error was encountered while downloading package(s): {}".format(exc) + f"An error was encountered while downloading package(s): {exc}" ) return ret @@ -2310,7 +2302,7 @@ def downloaded( if failed: summary = ", ".join([_get_desired_pkg(x, targets) for x in failed]) ret["result"] = False - ret["comment"] = "The following packages failed to download: {}".format(summary) + ret["comment"] = f"The following packages failed to download: {summary}" if not ret["changes"] and not ret["comment"]: ret["result"] = True @@ -2380,7 +2372,7 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): if __opts__["test"]: summary = ", ".join(targets) ret["comment"] = ( - "The following advisory patches would be downloaded: {}".format(summary) + f"The following advisory patches would be downloaded: {summary}" ) return ret @@ -2399,7 +2391,7 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): else: ret["changes"] = {} ret["comment"] = ( - "An error was encountered while downloading package(s): {}".format(exc) + f"An error was encountered while downloading package(s): {exc}" ) return ret @@ -2689,7 +2681,7 @@ def latest( # Package either a) is up-to-date, or b) does not exist if not cur.get(pkg): # Package does not exist - msg = "No information found for '{}'.".format(pkg) + msg = f"No information found for '{pkg}'." log.error(msg) problems.append(msg) elif ( @@ -2734,13 +2726,11 @@ def latest( if up_to_date_count <= 10: comments.append( "The following packages are already up-to-date: " - + ", ".join( - ["{} ({})".format(x, cur[x]) for x in sorted(up_to_date)] - ) + + ", ".join([f"{x} ({cur[x]})" for x in sorted(up_to_date)]) ) else: comments.append( - "{} packages are already up-to-date".format(up_to_date_count) + f"{up_to_date_count} packages are already up-to-date" ) return { @@ -2815,7 +2805,7 @@ def latest( ", ".join(sorted(up_to_date)) ) else: - msg = "{} packages were already up-to-date ".format(len(up_to_date)) + msg = f"{len(up_to_date)} packages were already up-to-date " comments.append(msg) return { @@ -2861,13 +2851,13 @@ def latest( } else: if len(desired_pkgs) > 10: - comment = "All {} packages are up-to-date.".format(len(desired_pkgs)) + comment = f"All {len(desired_pkgs)} packages are up-to-date." elif len(desired_pkgs) > 1: comment = "All packages are up-to-date ({}).".format( ", ".join(sorted(desired_pkgs)) ) else: - comment = "Package {} is already up-to-date".format(desired_pkgs[0]) + comment = f"Package {desired_pkgs[0]} is already up-to-date" return {"name": name, "changes": {}, "result": True, "comment": comment} @@ -2889,7 +2879,7 @@ def _uninstall( "name": name, "changes": {}, "result": False, - "comment": "Invalid action '{}'. This is probably a bug.".format(action), + "comment": f"Invalid action '{action}'. This is probably a bug.", } try: @@ -2901,7 +2891,7 @@ def _uninstall( "name": name, "changes": {}, "result": False, - "comment": "An error was encountered while parsing targets: {}".format(exc), + "comment": f"An error was encountered while parsing targets: {exc}", } targets = _find_remove_targets( name, version, pkgs, normalize, ignore_epoch=ignore_epoch, **kwargs @@ -2944,7 +2934,7 @@ def _uninstall( if __opts__["test"]: _changes = {} - _changes.update({x: {"new": "{}d".format(action), "old": ""} for x in targets}) + _changes.update({x: {"new": f"{action}d", "old": ""} for x in targets}) return { "name": name, @@ -2955,7 +2945,7 @@ def _uninstall( ), } - changes = __salt__["pkg.{}".format(action)]( + changes = __salt__[f"pkg.{action}"]( name, pkgs=pkgs, version=version, split_arch=False, **kwargs ) new = __salt__["pkg.list_pkgs"](versions_as_list=True, **kwargs) @@ -2999,7 +2989,7 @@ def _uninstall( "The following packages were {}d: {}.".format(action, ", ".join(targets)) ) else: - comments.append("All targeted packages were {}d.".format(action)) + comments.append(f"All targeted packages were {action}d.") return { "name": name, @@ -3096,7 +3086,7 @@ def removed(name, version=None, pkgs=None, normalize=True, ignore_epoch=None, ** else: ret["changes"] = {} ret["comment"] = ( - "An error was encountered while removing package(s): {}".format(exc) + f"An error was encountered while removing package(s): {exc}" ) return ret @@ -3187,9 +3177,7 @@ def purged(name, version=None, pkgs=None, normalize=True, ignore_epoch=None, **k ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret["comment"] = ( - "An error was encountered while purging package(s): {}".format(exc) - ) + ret["comment"] = f"An error was encountered while purging package(s): {exc}" return ret @@ -3279,9 +3267,7 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs): ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret["comment"] = ( - "An error was encountered while updating packages: {}".format(exc) - ) + ret["comment"] = f"An error was encountered while updating packages: {exc}" return ret # If a package list was provided, ensure those packages were updated @@ -3448,7 +3434,7 @@ def group_installed(name, skip=None, include=None, **kwargs): if not targets: ret["result"] = True - ret["comment"] = "Group '{}' is already installed".format(name) + ret["comment"] = f"Group '{name}' is already installed" return ret partially_installed = ( @@ -3461,10 +3447,10 @@ def group_installed(name, skip=None, include=None, **kwargs): ret["result"] = None if partially_installed: ret["comment"] = ( - "Group '{}' is partially installed and will be updated".format(name) + f"Group '{name}' is partially installed and will be updated" ) else: - ret["comment"] = "Group '{}' will be installed".format(name) + ret["comment"] = f"Group '{name}' will be installed" return ret try: @@ -3613,7 +3599,7 @@ def mod_watch(name, **kwargs): return { "name": name, "changes": {}, - "comment": "pkg.{} does not work with the watch requisite".format(sfun), + "comment": f"pkg.{sfun} does not work with the watch requisite", "result": False, } @@ -3637,7 +3623,7 @@ def mod_beacon(name, **kwargs): if kwargs.get("beacon"): beacon_module = "pkg" - beacon_name = "beacon_{}_{}".format(beacon_module, name) + beacon_name = f"beacon_{beacon_module}_{name}" beacon_kwargs = { "name": beacon_name, @@ -3741,10 +3727,8 @@ def held(name, version=None, pkgs=None, replace=False, **kwargs): if epoch == "0": epoch = "" else: - epoch = "{}:".format(epoch) - locks.update( - {match.group(1): {"version": "{}{}".format(epoch, match.group(3))}} - ) + epoch = f"{epoch}:" + locks.update({match.group(1): {"version": f"{epoch}{match.group(3)}"}}) else: locks.update({lock: {}}) elif "pkg.get_selections" in __salt__: @@ -3789,14 +3773,14 @@ def held(name, version=None, pkgs=None, replace=False, **kwargs): comments.append( "The following package's hold rule would be updated: {}{}".format( pkg_name, - "" if not pkg_ver else " (version = {})".format(pkg_ver), + "" if not pkg_ver else f" (version = {pkg_ver})", ) ) else: comments.append( "The following package would be held: {}{}".format( pkg_name, - "" if not pkg_ver else " (version = {})".format(pkg_ver), + "" if not pkg_ver else f" (version = {pkg_ver})", ) ) else: @@ -3812,13 +3796,11 @@ def held(name, version=None, pkgs=None, replace=False, **kwargs): and hold_ret and hold_ret.get(pkg_name, {}).get("result", False) ): - comments.append( - "Package {} was updated with hold rule".format(pkg_name) - ) + comments.append(f"Package {pkg_name} was updated with hold rule") elif hold_ret and hold_ret.get(pkg_name, {}).get("result", False): - comments.append("Package {} is now being held".format(pkg_name)) + comments.append(f"Package {pkg_name} is now being held") else: - comments.append("Package {} was not held".format(pkg_name)) + comments.append(f"Package {pkg_name} was not held") ret["changes"].update(hold_ret) if replace: @@ -3828,7 +3810,7 @@ def held(name, version=None, pkgs=None, replace=False, **kwargs): if __opts__["test"]: if pkg_name not in held_pkgs: comments.append( - "The following package would be unheld: {}".format(pkg_name) + f"The following package would be unheld: {pkg_name}" ) else: if pkg_name not in held_pkgs: @@ -3919,10 +3901,8 @@ def unheld(name, version=None, pkgs=None, all=False, **kwargs): if epoch == "0": epoch = "" else: - epoch = "{}:".format(epoch) - locks.update( - {match.group(1): {"version": "{}{}".format(epoch, match.group(3))}} - ) + epoch = f"{epoch}:" + locks.update({match.group(1): {"version": f"{epoch}{match.group(3)}"}}) else: locks.update({lock: {}}) elif "pkg.get_selections" in __salt__: @@ -3961,11 +3941,7 @@ def unheld(name, version=None, pkgs=None, all=False, **kwargs): comments.append( "The following package would be unheld: {}{}".format( pkg_name, - ( - "" - if not dpkgs.get(pkg_name) - else " (version = {})".format(lock_ver) - ), + ("" if not dpkgs.get(pkg_name) else f" (version = {lock_ver})"), ) ) else: diff --git a/salt/states/pkgbuild.py b/salt/states/pkgbuild.py index 68725fc362b..7888e97bb59 100644 --- a/salt/states/pkgbuild.py +++ b/salt/states/pkgbuild.py @@ -330,7 +330,7 @@ def repo( if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Package repo metadata at {} will be refreshed".format(name) + ret["comment"] = f"Package repo metadata at {name} will be refreshed" return ret # Need the check for None here, if env is not provided then it falls back diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py index 3aaa5791a27..35b8d3896b8 100644 --- a/salt/states/pkgrepo.py +++ b/salt/states/pkgrepo.py @@ -462,7 +462,7 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): pre = __salt__["pkg.get_repo"](repo=repo, **kwargs) except CommandExecutionError as exc: ret["result"] = False - ret["comment"] = "Failed to examine repo '{}': {}".format(name, exc) + ret["comment"] = f"Failed to examine repo '{name}': {exc}" return ret # This is because of how apt-sources works. This pushes distro logic @@ -544,7 +544,7 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): break else: ret["result"] = True - ret["comment"] = "Package repo '{}' already configured".format(name) + ret["comment"] = f"Package repo '{name}' already configured" return ret if __opts__["test"]: @@ -579,7 +579,7 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): # This is another way to pass information back from the mod_repo # function. ret["result"] = False - ret["comment"] = "Failed to configure repo '{}': {}".format(name, exc) + ret["comment"] = f"Failed to configure repo '{name}': {exc}" return ret try: @@ -595,10 +595,10 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): ret["changes"] = {"repo": repo} ret["result"] = True - ret["comment"] = "Configured package repo '{}'".format(name) + ret["comment"] = f"Configured package repo '{name}'" except Exception as exc: # pylint: disable=broad-except ret["result"] = False - ret["comment"] = "Failed to confirm config of repo '{}': {}".format(name, exc) + ret["comment"] = f"Failed to confirm config of repo '{name}': {exc}" # Clear cache of available packages, if present, since changes to the # repositories may change the packages that are available. @@ -704,7 +704,7 @@ def absent(name, **kwargs): repo = __salt__["pkg.get_repo"](stripname, **kwargs) except CommandExecutionError as exc: ret["result"] = False - ret["comment"] = "Failed to configure repo '{}': {}".format(name, exc) + ret["comment"] = f"Failed to configure repo '{name}': {exc}" return ret if repo and ( @@ -725,7 +725,7 @@ def absent(name, **kwargs): repo = {} if not repo: - ret["comment"] = "Package repo {} is absent".format(name) + ret["comment"] = f"Package repo {name} is absent" ret["result"] = True return ret @@ -748,7 +748,7 @@ def absent(name, **kwargs): repos = __salt__["pkg.list_repos"]() if stripname not in repos: ret["changes"]["repo"] = name - ret["comment"] = "Removed repo {}".format(name) + ret["comment"] = f"Removed repo {name}" if not remove_key: ret["result"] = True @@ -757,13 +757,13 @@ def absent(name, **kwargs): removed_keyid = __salt__["pkg.del_repo_key"](stripname, **kwargs) except (CommandExecutionError, SaltInvocationError) as exc: ret["result"] = False - ret["comment"] += ", but failed to remove key: {}".format(exc) + ret["comment"] += f", but failed to remove key: {exc}" else: ret["result"] = True ret["changes"]["keyid"] = removed_keyid - ret["comment"] += ", and keyid {}".format(removed_keyid) + ret["comment"] += f", and keyid {removed_keyid}" else: ret["result"] = False - ret["comment"] = "Failed to remove repo {}".format(name) + ret["comment"] = f"Failed to remove repo {name}" return ret diff --git a/salt/states/ports.py b/salt/states/ports.py index 2d9acff696e..072bb7bf4f4 100644 --- a/salt/states/ports.py +++ b/salt/states/ports.py @@ -49,7 +49,7 @@ def _get_option_list(options): Returns the key/value pairs in the passed dict in a commaspace-delimited list in the format "key=value". """ - return ", ".join(["{}={}".format(x, y) for x, y in options.items()]) + return ", ".join([f"{x}={y}" for x, y in options.items()]) def _build_option_string(options): @@ -57,7 +57,7 @@ def _build_option_string(options): Common function to get a string to append to the end of the state comment """ if options: - return "with the following build options: {}".format(_get_option_list(options)) + return f"with the following build options: {_get_option_list(options)}" else: return "with the default build options" @@ -89,7 +89,7 @@ def installed(name, options=None): "name": name, "changes": {}, "result": True, - "comment": "{} is already installed".format(name), + "comment": f"{name} is already installed", } try: current_options = __salt__["ports.showconfig"]( @@ -137,7 +137,7 @@ def installed(name, options=None): else: if __opts__["test"]: ret["result"] = None - ret["comment"] = "{} will be installed".format(name) + ret["comment"] = f"{name} will be installed" return ret else: bad_opts = [x for x in options if x not in default_options] @@ -152,20 +152,20 @@ def installed(name, options=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "{} will be installed ".format(name) + ret["comment"] = f"{name} will be installed " ret["comment"] += _build_option_string(options) return ret if options: if not __salt__["ports.config"](name, reset=True, **options): ret["result"] = False - ret["comment"] = "Unable to set options for {}".format(name) + ret["comment"] = f"Unable to set options for {name}" return ret else: __salt__["ports.rmconfig"](name) if _options_file_exists(name): ret["result"] = False - ret["comment"] = "Unable to clear options for {}".format(name) + ret["comment"] = f"Unable to clear options for {name}" return ret ret["changes"] = __salt__["ports.install"](name) @@ -178,11 +178,11 @@ def installed(name, options=None): if err or name not in ports_post: ret["result"] = False if ret["result"]: - ret["comment"] = "Successfully installed {}".format(name) + ret["comment"] = f"Successfully installed {name}" if default_options: ret["comment"] += " " + _build_option_string(options) else: - ret["comment"] = "Failed to install {}".format(name) + ret["comment"] = f"Failed to install {name}" if err: - ret["comment"] += ". Error message:\n{}".format(err) + ret["comment"] += f". Error message:\n{err}" return ret diff --git a/salt/states/postgres_cluster.py b/salt/states/postgres_cluster.py index de98d5ab92f..bbcf42eb5ce 100644 --- a/salt/states/postgres_cluster.py +++ b/salt/states/postgres_cluster.py @@ -70,13 +70,13 @@ def present( .. versionadded:: 2016.3.0 """ - msg = "Cluster {}/{} is already present".format(version, name) + msg = f"Cluster {version}/{name} is already present" ret = {"name": name, "changes": {}, "result": True, "comment": msg} if __salt__["postgres.cluster_exists"](version, name): # check cluster config is correct infos = __salt__["postgres.cluster_list"](verbose=True) - info = infos["{}/{}".format(version, name)] + info = infos[f"{version}/{name}"] # TODO: check locale en encoding configs also if any( ( @@ -111,7 +111,7 @@ def present( if cluster: msg = "The cluster {0}/{1} has been created" ret["comment"] = msg.format(version, name) - ret["changes"]["{}/{}".format(version, name)] = "Present" + ret["changes"][f"{version}/{name}"] = "Present" else: msg = "Failed to create cluster {0}/{1}" ret["comment"] = msg.format(version, name) diff --git a/salt/states/postgres_database.py b/salt/states/postgres_database.py index b5de4fa1f97..831bbecc068 100644 --- a/salt/states/postgres_database.py +++ b/salt/states/postgres_database.py @@ -89,7 +89,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(name), + "comment": f"Database {name} is already present", } db_args = { @@ -140,10 +140,10 @@ def present( if __opts__["test"]: ret["result"] = None if name not in dbs: - ret["comment"] = "Database {} is set to be created".format(name) + ret["comment"] = f"Database {name} is set to be created" else: ret["comment"] = ( - "Database {} exists, but parameters need to be changed".format(name) + f"Database {name} exists, but parameters need to be changed" ) return ret if name not in dbs and __salt__["postgres.db_create"]( @@ -154,20 +154,20 @@ def present( lc_ctype=lc_ctype, owner=owner, template=template, - **db_args + **db_args, ): - ret["comment"] = "The database {} has been created".format(name) + ret["comment"] = f"The database {name} has been created" ret["changes"][name] = "Present" elif name in dbs and __salt__["postgres.db_alter"]( name, tablespace=tablespace, owner=owner, owner_recurse=owner_recurse, **db_args ): - ret["comment"] = "Parameters for database {} have been changed".format(name) + ret["comment"] = f"Parameters for database {name} have been changed" ret["changes"][name] = "Parameters changed" elif name in dbs: - ret["comment"] = "Failed to change parameters for database {}".format(name) + ret["comment"] = f"Failed to change parameters for database {name}" ret["result"] = False else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret @@ -219,13 +219,13 @@ def absent( if __salt__["postgres.db_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is set to be removed".format(name) + ret["comment"] = f"Database {name} is set to be removed" return ret if __salt__["postgres.db_remove"](name, **db_args): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret # fallback - ret["comment"] = "Database {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Database {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/postgres_extension.py b/salt/states/postgres_extension.py index 963b9caa5ff..91726fbd58e 100644 --- a/salt/states/postgres_extension.py +++ b/salt/states/postgres_extension.py @@ -93,7 +93,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Extension {} is already present".format(name), + "comment": f"Extension {name} is already present", } db_args = { "maintenance_db": maintenance_db, @@ -135,17 +135,17 @@ def present( schema=schema, ext_version=ext_version, from_version=from_version, - **db_args + **db_args, ) if cret: if mode.endswith("e"): suffix = "d" else: suffix = "ed" - ret["comment"] = "The extension {} has been {}{}".format(name, mode, suffix) - ret["changes"][name] = "{}{}".format(mode.capitalize(), suffix) + ret["comment"] = f"The extension {name} has been {mode}{suffix}" + ret["changes"][name] = f"{mode.capitalize()}{suffix}" elif cret is not None: - ret["comment"] = "Failed to {1} extension {0}".format(name, mode) + ret["comment"] = f"Failed to {mode} extension {name}" ret["result"] = False return ret @@ -210,17 +210,17 @@ def absent( if exists: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Extension {} is set to be removed".format(name) + ret["comment"] = f"Extension {name} is set to be removed" return ret if __salt__["postgres.drop_extension"]( name, if_exists=if_exists, restrict=restrict, cascade=cascade, **db_args ): - ret["comment"] = "Extension {} has been removed".format(name) + ret["comment"] = f"Extension {name} has been removed" ret["changes"][name] = "Absent" return ret else: ret["result"] = False - ret["comment"] = "Extension {} failed to be removed".format(name) + ret["comment"] = f"Extension {name} failed to be removed" return ret else: ret["comment"] = "Extension {} is not present, so it cannot be removed".format( diff --git a/salt/states/postgres_group.py b/salt/states/postgres_group.py index 01209ddfd43..2668f01bc90 100644 --- a/salt/states/postgres_group.py +++ b/salt/states/postgres_group.py @@ -138,7 +138,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Group {} is already present".format(name), + "comment": f"Group {name} is already present", } # default to encrypted passwords @@ -210,9 +210,9 @@ def present( if update: ret["changes"][name] = update ret["result"] = None - ret["comment"] = "Group {} is set to be {}d".format(name, mode) + ret["comment"] = f"Group {name} is set to be {mode}d" return ret - cret = __salt__["postgres.group_{}".format(mode)]( + cret = __salt__[f"postgres.group_{mode}"]( groupname=name, createdb=createdb, createroles=createroles, @@ -223,19 +223,19 @@ def present( replication=replication, rolepassword=password, groups=groups, - **db_args + **db_args, ) else: cret = None if cret: - ret["comment"] = "The group {} has been {}d".format(name, mode) + ret["comment"] = f"The group {name} has been {mode}d" if update: ret["changes"][name] = update else: ret["changes"][name] = "Present" elif cret is not None: - ret["comment"] = "Failed to {} group {}".format(mode, name) + ret["comment"] = f"Failed to {mode} group {name}" ret["result"] = False else: ret["result"] = True @@ -289,17 +289,17 @@ def absent( if __salt__["postgres.user_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Group {} is set to be removed".format(name) + ret["comment"] = f"Group {name} is set to be removed" return ret if __salt__["postgres.group_remove"](name, **db_args): - ret["comment"] = "Group {} has been removed".format(name) + ret["comment"] = f"Group {name} has been removed" ret["changes"][name] = "Absent" return ret else: ret["result"] = False - ret["comment"] = "Group {} failed to be removed".format(name) + ret["comment"] = f"Group {name} failed to be removed" return ret else: - ret["comment"] = "Group {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Group {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/postgres_initdb.py b/salt/states/postgres_initdb.py index bde59f925eb..bb1a85474e4 100644 --- a/salt/states/postgres_initdb.py +++ b/salt/states/postgres_initdb.py @@ -83,13 +83,13 @@ def present( runas The system user the operation should be performed on behalf of """ - _cmt = "Postgres data directory {} is already present".format(name) + _cmt = f"Postgres data directory {name} is already present" ret = {"name": name, "changes": {}, "result": True, "comment": _cmt} if not __salt__["postgres.datadir_exists"](name=name): if __opts__["test"]: ret["result"] = None - _cmt = "Postgres data directory {} is set to be initialized".format(name) + _cmt = f"Postgres data directory {name} is set to be initialized" ret["comment"] = _cmt return ret @@ -105,11 +105,11 @@ def present( ) if __salt__["postgres.datadir_init"](name, **kwargs): - _cmt = "Postgres data directory {} has been initialized".format(name) + _cmt = f"Postgres data directory {name} has been initialized" ret["comment"] = _cmt ret["changes"][name] = "Present" else: - _cmt = "Postgres data directory {} initialization failed".format(name) + _cmt = f"Postgres data directory {name} initialization failed" ret["result"] = False ret["comment"] = _cmt diff --git a/salt/states/postgres_language.py b/salt/states/postgres_language.py index 3a06476c975..d8c5665ddf4 100644 --- a/salt/states/postgres_language.py +++ b/salt/states/postgres_language.py @@ -72,7 +72,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Language {} is already installed".format(name), + "comment": f"Language {name} is already installed", } dbargs = { @@ -88,14 +88,14 @@ def present( if name not in languages: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Language {} is set to be installed".format(name) + ret["comment"] = f"Language {name} is set to be installed" return ret if __salt__["postgres.language_create"](name, maintenance_db, **dbargs): - ret["comment"] = "Language {} has been installed".format(name) + ret["comment"] = f"Language {name} has been installed" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to install language {}".format(name) + ret["comment"] = f"Failed to install language {name}" ret["result"] = False return ret @@ -148,15 +148,15 @@ def absent( if __salt__["postgres.language_exists"](name, maintenance_db, **dbargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Language {} is set to be removed".format(name) + ret["comment"] = f"Language {name} is set to be removed" return ret if __salt__["postgres.language_remove"](name, **dbargs): - ret["comment"] = "Language {} has been removed".format(name) + ret["comment"] = f"Language {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove language {}".format(name) + ret["comment"] = f"Failed to remove language {name}" ret["result"] = False - ret["comment"] = "Language {} is not present so it cannot be removed".format(name) + ret["comment"] = f"Language {name} is not present so it cannot be removed" return ret diff --git a/salt/states/postgres_schema.py b/salt/states/postgres_schema.py index 7e77da04642..0052f4da1d7 100644 --- a/salt/states/postgres_schema.py +++ b/salt/states/postgres_schema.py @@ -66,7 +66,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Schema {} is already present in database {}".format(name, dbname), + "comment": f"Schema {name} is already present in database {dbname}", } db_args = { @@ -163,7 +163,7 @@ def absent( return ret else: ret["result"] = False - ret["comment"] = "Schema {} failed to be removed".format(name) + ret["comment"] = f"Schema {name} failed to be removed" return ret else: ret["comment"] = ( diff --git a/salt/states/postgres_tablespace.py b/salt/states/postgres_tablespace.py index a946b1b65fc..84da41f99ec 100644 --- a/salt/states/postgres_tablespace.py +++ b/salt/states/postgres_tablespace.py @@ -93,7 +93,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Tablespace {} is already present".format(name), + "comment": f"Tablespace {name} is already present", } dbargs = { "maintenance_db": maintenance_db, @@ -108,12 +108,12 @@ def present( # not there, create it if __opts__["test"]: ret["result"] = None - ret["comment"] = "Tablespace {} is set to be created".format(name) + ret["comment"] = f"Tablespace {name} is set to be created" return ret if __salt__["postgres.tablespace_create"]( name, directory, options, owner, **dbargs ): - ret["comment"] = "The tablespace {} has been created".format(name) + ret["comment"] = f"The tablespace {name} has been created" ret["changes"][name] = "Present" return ret @@ -131,12 +131,12 @@ def present( if owner and not tblspaces[name]["Owner"] == owner: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Tablespace {} owner to be altered".format(name) + ret["comment"] = f"Tablespace {name} owner to be altered" if ( __salt__["postgres.tablespace_alter"](name, new_owner=owner) and not __opts__["test"] ): - ret["comment"] = "Tablespace {} owner changed".format(name) + ret["comment"] = f"Tablespace {name} owner changed" ret["changes"][name] = {"owner": owner} ret["result"] = True @@ -148,7 +148,7 @@ def present( # TODO remove options that exist if possible for k, v in options.items(): # if 'seq_page_cost=1.1' not in '{seq_page_cost=1.1,...}' - if "{}={}".format(k, v) not in tblspaces[name]["Opts"]: + if f"{k}={v}" not in tblspaces[name]["Opts"]: if __opts__["test"]: ret["result"] = None ret["comment"] = ( @@ -159,7 +159,7 @@ def present( ) break # we know it's going to be altered, no reason to cont if __salt__["postgres.tablespace_alter"](name, set_option={k: v}): - ret["comment"] = "Tablespace {} opts changed".format(name) + ret["comment"] = f"Tablespace {name} opts changed" dictupdate.update(ret["changes"], {name: {"options": {k: v}}}) ret["result"] = True @@ -213,10 +213,10 @@ def absent( if __salt__["postgres.tablespace_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Tablespace {} is set to be removed".format(name) + ret["comment"] = f"Tablespace {name} is set to be removed" return ret if __salt__["postgres.tablespace_remove"](name, **db_args): - ret["comment"] = "Tablespace {} has been removed".format(name) + ret["comment"] = f"Tablespace {name} has been removed" ret["changes"][name] = "Absent" return ret diff --git a/salt/states/postgres_user.py b/salt/states/postgres_user.py index f76e5e38403..fa5f5f9ecbf 100644 --- a/salt/states/postgres_user.py +++ b/salt/states/postgres_user.py @@ -149,7 +149,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {} is already present".format(name), + "comment": f"User {name} is already present", } db_args = { @@ -214,7 +214,7 @@ def present( "SELECT '{}'::timestamp(0) as dt;".format( valid_until.replace("'", "''") ), - **db_args + **db_args, )[0]["dt"] try: valid_until_dt = datetime.datetime.strptime( @@ -238,9 +238,9 @@ def present( if update: ret["changes"][name] = update ret["result"] = None - ret["comment"] = "User {} is set to be {}d".format(name, mode) + ret["comment"] = f"User {name} is set to be {mode}d" return ret - cret = __salt__["postgres.user_{}".format(mode)]( + cret = __salt__[f"postgres.user_{mode}"]( username=name, createdb=createdb, createroles=createroles, @@ -252,19 +252,19 @@ def present( rolepassword=password, valid_until=valid_until, groups=groups, - **db_args + **db_args, ) else: cret = None if cret: - ret["comment"] = "The user {} has been {}d".format(name, mode) + ret["comment"] = f"The user {name} has been {mode}d" if update: ret["changes"][name] = update else: ret["changes"][name] = "Present" elif cret is not None: - ret["comment"] = "Failed to {} user {}".format(mode, name) + ret["comment"] = f"Failed to {mode} user {name}" ret["result"] = False else: ret["result"] = True @@ -318,17 +318,17 @@ def absent( if __salt__["postgres.user_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is set to be removed".format(name) + ret["comment"] = f"User {name} is set to be removed" return ret if __salt__["postgres.user_remove"](name, **db_args): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret else: ret["result"] = False - ret["comment"] = "User {} failed to be removed".format(name) + ret["comment"] = f"User {name} failed to be removed" return ret else: - ret["comment"] = "User {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"User {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/powerpath.py b/salt/states/powerpath.py index 829a6359e5c..0ee13997d0a 100644 --- a/salt/states/powerpath.py +++ b/salt/states/powerpath.py @@ -31,12 +31,12 @@ def license_present(name): if name in licenses: ret["result"] = True - ret["comment"] = "License key {} already present".format(name) + ret["comment"] = f"License key {name} already present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "License key {} is set to be added".format(name) + ret["comment"] = f"License key {name} is set to be added" return ret data = __salt__["powerpath.add_license"](name) @@ -70,12 +70,12 @@ def license_absent(name): if name not in licenses: ret["result"] = True - ret["comment"] = "License key {} not present".format(name) + ret["comment"] = f"License key {name} not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "License key {} is set to be removed".format(name) + ret["comment"] = f"License key {name} is set to be removed" return ret data = __salt__["powerpath.remove_license"](name) diff --git a/salt/states/process.py b/salt/states/process.py index d4b40f81f01..b75a7f7cd7f 100644 --- a/salt/states/process.py +++ b/salt/states/process.py @@ -37,7 +37,7 @@ def absent(name, user=None, signal=None): running = __salt__["ps.pgrep"](name, user=user) ret["result"] = None if running: - ret["comment"] = "{} processes will be killed".format(len(running)) + ret["comment"] = f"{len(running)} processes will be killed" else: ret["comment"] = "No matching processes running" return ret diff --git a/salt/states/proxy.py b/salt/states/proxy.py index e951e97e133..231cba04195 100644 --- a/salt/states/proxy.py +++ b/salt/states/proxy.py @@ -78,13 +78,13 @@ def managed( ret["changes"] = {"new": []} for service in services: - current_settings = __salt__["proxy.get_{}_proxy".format(service)]() + current_settings = __salt__[f"proxy.get_{service}_proxy"]() if current_settings.get("server") == name and current_settings.get( "port" ) == str(port): - ret["comment"] += "{} proxy settings already set.\n".format(service) - elif __salt__["proxy.set_{}_proxy".format(service)]( + ret["comment"] += f"{service} proxy settings already set.\n" + elif __salt__[f"proxy.set_{service}_proxy"]( name, port, user, password, network_service ): ret["comment"] += "{} proxy settings updated correctly\n".format( diff --git a/salt/states/pushover.py b/salt/states/pushover.py index cda8117a281..5b366153784 100644 --- a/salt/states/pushover.py +++ b/salt/states/pushover.py @@ -109,11 +109,11 @@ def post_message( return ret if not user: - ret["comment"] = "PushOver user is missing: {}".format(user) + ret["comment"] = f"PushOver user is missing: {user}" return ret if not message: - ret["comment"] = "PushOver message is missing: {}".format(message) + ret["comment"] = f"PushOver message is missing: {message}" return ret result = __salt__["pushover.post_message"]( @@ -129,8 +129,8 @@ def post_message( if result: ret["result"] = True - ret["comment"] = "Sent message: {}".format(name) + ret["comment"] = f"Sent message: {name}" else: - ret["comment"] = "Failed to send message: {}".format(name) + ret["comment"] = f"Failed to send message: {name}" return ret diff --git a/salt/states/pyenv.py b/salt/states/pyenv.py index f68dd947970..0d2a30020ab 100644 --- a/salt/states/pyenv.py +++ b/salt/states/pyenv.py @@ -122,7 +122,7 @@ def installed(name, default=False, user=None): name = re.sub(r"^python-", "", name) if __opts__["test"]: - ret["comment"] = "python {} is set to be installed".format(name) + ret["comment"] = f"python {name} is set to be installed" return ret ret = _check_pyenv(ret, user) @@ -156,7 +156,7 @@ def _check_and_uninstall_python(ret, python, user=None): return ret else: ret["result"] = True - ret["comment"] = "python {} is already absent".format(python) + ret["comment"] = f"python {python} is already absent" return ret @@ -182,13 +182,13 @@ def absent(name, user=None): name = re.sub(r"^python-", "", name) if __opts__["test"]: - ret["comment"] = "python {} is set to be uninstalled".format(name) + ret["comment"] = f"python {name} is set to be uninstalled" return ret ret = _check_pyenv(ret, user) if ret["result"] is False: ret["result"] = True - ret["comment"] = "pyenv not installed, {} not either".format(name) + ret["comment"] = f"pyenv not installed, {name} not either" return ret else: return _check_and_uninstall_python(ret, name, user=user) diff --git a/salt/states/pyrax_queues.py b/salt/states/pyrax_queues.py index f1c951a510c..7aba6a2750b 100644 --- a/salt/states/pyrax_queues.py +++ b/salt/states/pyrax_queues.py @@ -53,7 +53,7 @@ def present(name, provider): if not is_present: if __opts__["test"]: - msg = "Rackspace queue {} is set to be created.".format(name) + msg = f"Rackspace queue {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -68,10 +68,10 @@ def present(name, provider): ret["changes"]["new"] = {"queue": queue} else: ret["result"] = False - ret["comment"] = "Failed to create {} Rackspace queue.".format(name) + ret["comment"] = f"Failed to create {name} Rackspace queue." return ret else: - ret["comment"] = "{} present.".format(name) + ret["comment"] = f"{name} present." return ret @@ -98,7 +98,7 @@ def absent(name, provider): if is_present: if __opts__["test"]: - ret["comment"] = "Rackspace queue {} is set to be removed.".format(name) + ret["comment"] = f"Rackspace queue {name} is set to be removed." ret["result"] = None return ret queue = __salt__["cloud.action"]("queues_show", provider=provider, name=name) @@ -110,8 +110,8 @@ def absent(name, provider): ret["changes"]["new"] = {} else: ret["result"] = False - ret["comment"] = "Failed to delete {} Rackspace queue.".format(name) + ret["comment"] = f"Failed to delete {name} Rackspace queue." else: - ret["comment"] = "{} does not exist.".format(name) + ret["comment"] = f"{name} does not exist." return ret diff --git a/salt/states/quota.py b/salt/states/quota.py index 07fe25a87ee..6c032e42ddb 100644 --- a/salt/states/quota.py +++ b/salt/states/quota.py @@ -41,17 +41,17 @@ def mode(name, mode, quotatype): fun = "on" if __salt__["quota.get_mode"](name)[name][quotatype] == fun: ret["result"] = True - ret["comment"] = "Quota for {} already set to {}".format(name, fun) + ret["comment"] = f"Quota for {name} already set to {fun}" return ret if __opts__["test"]: - ret["comment"] = "Quota for {} needs to be set to {}".format(name, fun) + ret["comment"] = f"Quota for {name} needs to be set to {fun}" return ret - if __salt__["quota.{}".format(fun)](name): + if __salt__[f"quota.{fun}"](name): ret["changes"] = {"quota": name} ret["result"] = True - ret["comment"] = "Set quota for {} to {}".format(name, fun) + ret["comment"] = f"Set quota for {name} to {fun}" return ret else: ret["result"] = False - ret["comment"] = "Failed to set quota for {} to {}".format(name, fun) + ret["comment"] = f"Failed to set quota for {name} to {fun}" return ret diff --git a/salt/states/rabbitmq_cluster.py b/salt/states/rabbitmq_cluster.py index 8a845006dba..6af09e26099 100644 --- a/salt/states/rabbitmq_cluster.py +++ b/salt/states/rabbitmq_cluster.py @@ -48,7 +48,7 @@ def joined(name, host, user="rabbit", ram_node=None, runas="root"): ret = {"name": name, "result": True, "comment": "", "changes": {}} status = __salt__["rabbitmq.cluster_status"]() - if "{}@{}".format(user, host) in status: + if f"{user}@{host}" in status: ret["comment"] = "Already in cluster" return ret @@ -62,11 +62,11 @@ def joined(name, host, user="rabbit", ram_node=None, runas="root"): ret["comment"] = result["Join"] # If we've reached this far before returning, we have changes. - ret["changes"] = {"old": "", "new": "{}@{}".format(user, host)} + ret["changes"] = {"old": "", "new": f"{user}@{host}"} if __opts__["test"]: ret["result"] = None - ret["comment"] = "Node is set to join cluster {}@{}".format(user, host) + ret["comment"] = f"Node is set to join cluster {user}@{host}" return ret diff --git a/salt/states/rabbitmq_plugin.py b/salt/states/rabbitmq_plugin.py index 4994e52f95f..76342b87b54 100644 --- a/salt/states/rabbitmq_plugin.py +++ b/salt/states/rabbitmq_plugin.py @@ -44,11 +44,11 @@ def enabled(name, runas=None): plugin_enabled = __salt__["rabbitmq.plugin_is_enabled"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if plugin_enabled: - ret["comment"] = "Plugin '{}' is already enabled.".format(name) + ret["comment"] = f"Plugin '{name}' is already enabled." return ret if not __opts__["test"]: @@ -56,16 +56,16 @@ def enabled(name, runas=None): __salt__["rabbitmq.enable_plugin"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"old": "", "new": name}) if __opts__["test"] and ret["changes"]: ret["result"] = None - ret["comment"] = "Plugin '{}' is set to be enabled.".format(name) + ret["comment"] = f"Plugin '{name}' is set to be enabled." return ret - ret["comment"] = "Plugin '{}' was enabled.".format(name) + ret["comment"] = f"Plugin '{name}' was enabled." return ret @@ -85,11 +85,11 @@ def disabled(name, runas=None): plugin_enabled = __salt__["rabbitmq.plugin_is_enabled"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if not plugin_enabled: - ret["comment"] = "Plugin '{}' is already disabled.".format(name) + ret["comment"] = f"Plugin '{name}' is already disabled." return ret if not __opts__["test"]: @@ -97,14 +97,14 @@ def disabled(name, runas=None): __salt__["rabbitmq.disable_plugin"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"old": name, "new": ""}) if __opts__["test"] and ret["changes"]: ret["result"] = None - ret["comment"] = "Plugin '{}' is set to be disabled.".format(name) + ret["comment"] = f"Plugin '{name}' is set to be disabled." return ret - ret["comment"] = "Plugin '{}' was disabled.".format(name) + ret["comment"] = f"Plugin '{name}' was disabled." return ret diff --git a/salt/states/rabbitmq_policy.py b/salt/states/rabbitmq_policy.py index 120b6ec6f57..2e17f2fbc8e 100644 --- a/salt/states/rabbitmq_policy.py +++ b/salt/states/rabbitmq_policy.py @@ -79,13 +79,13 @@ def present( updates.append("Priority") if policy and not updates: - ret["comment"] = "Policy {} {} is already present".format(vhost, name) + ret["comment"] = f"Policy {vhost} {name} is already present" return ret if not policy: ret["changes"].update({"old": {}, "new": name}) if __opts__["test"]: - ret["comment"] = "Policy {} {} is set to be created".format(vhost, name) + ret["comment"] = f"Policy {vhost} {name} is set to be created" else: log.debug("Policy doesn't exist - Creating") result = __salt__["rabbitmq.set_policy"]( @@ -100,7 +100,7 @@ def present( elif updates: ret["changes"].update({"old": policy, "new": updates}) if __opts__["test"]: - ret["comment"] = "Policy {} {} is set to be updated".format(vhost, name) + ret["comment"] = f"Policy {vhost} {name} is set to be updated" else: log.debug("Policy exists but needs updating") result = __salt__["rabbitmq.set_policy"]( @@ -117,7 +117,7 @@ def present( ret["result"] = False ret["comment"] = result["Error"] elif ret["changes"] == {}: - ret["comment"] = "'{}' is already in the desired state.".format(name) + ret["comment"] = f"'{name}' is already in the desired state." elif __opts__["test"]: ret["result"] = None elif "Set" in result: @@ -142,7 +142,7 @@ def absent(name, vhost="/", runas=None): policy_exists = __salt__["rabbitmq.policy_exists"](vhost, name, runas=runas) if not policy_exists: - ret["comment"] = "Policy '{} {}' is not present.".format(vhost, name) + ret["comment"] = f"Policy '{vhost} {name}' is not present." return ret if not __opts__["test"]: @@ -159,6 +159,6 @@ def absent(name, vhost="/", runas=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Policy '{} {}' will be removed.".format(vhost, name) + ret["comment"] = f"Policy '{vhost} {name}' will be removed." return ret diff --git a/salt/states/rabbitmq_upstream.py b/salt/states/rabbitmq_upstream.py index 35e0b008454..21f39cc6ac2 100644 --- a/salt/states/rabbitmq_upstream.py +++ b/salt/states/rabbitmq_upstream.py @@ -121,7 +121,7 @@ def present( try: current_upstreams = __salt__["rabbitmq.list_upstreams"](runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_config = salt.utils.data.filter_falsey( { @@ -146,7 +146,7 @@ def present( action = "update" else: ret["result"] = True - ret["comment"] = 'Upstream "{}" already present as specified.'.format(name) + ret["comment"] = f'Upstream "{name}" already present as specified.' else: action = "create" diff_config = {"old": None, "new": new_config} @@ -154,7 +154,7 @@ def present( if action: if __opts__["test"]: ret["result"] = None - ret["comment"] = 'Upstream "{}" would have been {}d.'.format(name, action) + ret["comment"] = f'Upstream "{name}" would have been {action}d.' else: try: res = __salt__["rabbitmq.set_upstream"]( @@ -173,10 +173,10 @@ def present( runas=runas, ) ret["result"] = res - ret["comment"] = 'Upstream "{}" {}d.'.format(name, action) + ret["comment"] = f'Upstream "{name}" {action}d.' ret["changes"] = diff_config except CommandExecutionError as exp: - ret["comment"] = "Error trying to {} upstream: {}".format(action, exp) + ret["comment"] = f"Error trying to {action} upstream: {exp}" return ret @@ -194,23 +194,23 @@ def absent(name, runas=None): try: upstream_exists = __salt__["rabbitmq.upstream_exists"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if upstream_exists: if __opts__["test"]: ret["result"] = None - ret["comment"] = 'Upstream "{}" would have been deleted.'.format(name) + ret["comment"] = f'Upstream "{name}" would have been deleted.' else: try: res = __salt__["rabbitmq.delete_upstream"](name, runas=runas) if res: ret["result"] = True - ret["comment"] = 'Upstream "{}" has been deleted.'.format(name) + ret["comment"] = f'Upstream "{name}" has been deleted.' ret["changes"] = {"old": name, "new": None} except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" else: ret["result"] = True - ret["comment"] = 'The upstream "{}" is already absent.'.format(name) + ret["comment"] = f'The upstream "{name}" is already absent.' return ret diff --git a/salt/states/rabbitmq_user.py b/salt/states/rabbitmq_user.py index fcd14ce3757..ce29c5da1c9 100644 --- a/salt/states/rabbitmq_user.py +++ b/salt/states/rabbitmq_user.py @@ -105,7 +105,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): try: user = __salt__["rabbitmq.user_exists"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret passwd_reqs_update = False @@ -115,7 +115,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): passwd_reqs_update = True log.debug("RabbitMQ user %s password update required", name) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if user and not any((force, perms, tags, passwd_reqs_update)): @@ -123,7 +123,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): "RabbitMQ user '%s' exists, password is up to date and force is not set.", name, ) - ret["comment"] = "User '{}' is already present.".format(name) + ret["comment"] = f"User '{name}' is already present." ret["result"] = True return ret @@ -131,14 +131,14 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): ret["changes"].update({"user": {"old": "", "new": name}}) if __opts__["test"]: ret["result"] = None - ret["comment"] = "User '{}' is set to be created.".format(name) + ret["comment"] = f"User '{name}' is set to be created." return ret log.debug("RabbitMQ user '%s' doesn't exist - Creating.", name) try: __salt__["rabbitmq.add_user"](name, password, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret else: log.debug("RabbitMQ user '%s' exists", name) @@ -150,7 +150,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): name, password, runas=runas ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"password": {"old": "", "new": "Set password."}}) else: @@ -159,7 +159,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): try: __salt__["rabbitmq.clear_password"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update( {"password": {"old": "Removed password.", "new": ""}} @@ -176,13 +176,13 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): try: __salt__["rabbitmq.set_user_tags"](name, tags, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"tags": {"old": current_tags, "new": tags}}) try: existing_perms = __salt__["rabbitmq.list_user_permissions"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if _check_perms_changes(name, perms, runas=runas, existing=existing_perms): @@ -194,7 +194,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): vhost, name, perm[0], perm[1], perm[2], runas=runas ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_perms = { vhost: {"configure": perm[0], "write": perm[1], "read": perm[2]} @@ -211,15 +211,15 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): ret["result"] = True if ret["changes"] == {}: - ret["comment"] = "'{}' is already in the desired state.".format(name) + ret["comment"] = f"'{name}' is already in the desired state." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Configuration for '{}' will change.".format(name) + ret["comment"] = f"Configuration for '{name}' will change." return ret - ret["comment"] = "'{}' was configured.".format(name) + ret["comment"] = f"'{name}' was configured." return ret @@ -237,7 +237,7 @@ def absent(name, runas=None): try: user_exists = __salt__["rabbitmq.user_exists"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if user_exists: @@ -245,19 +245,19 @@ def absent(name, runas=None): try: __salt__["rabbitmq.delete_user"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"name": {"old": name, "new": ""}}) else: ret["result"] = True - ret["comment"] = "The user '{}' is not present.".format(name) + ret["comment"] = f"The user '{name}' is not present." return ret if __opts__["test"] and ret["changes"]: ret["result"] = None - ret["comment"] = "The user '{}' will be removed.".format(name) + ret["comment"] = f"The user '{name}' will be removed." return ret ret["result"] = True - ret["comment"] = "The user '{}' was removed.".format(name) + ret["comment"] = f"The user '{name}' was removed." return ret diff --git a/salt/states/rabbitmq_vhost.py b/salt/states/rabbitmq_vhost.py index 3aba14a55d1..5fb68e6d764 100644 --- a/salt/states/rabbitmq_vhost.py +++ b/salt/states/rabbitmq_vhost.py @@ -69,7 +69,7 @@ def present(name): vhost_exists = __salt__["rabbitmq.vhost_exists"](name) if vhost_exists: - ret["comment"] = "Virtual Host '{}' already exists.".format(name) + ret["comment"] = f"Virtual Host '{name}' already exists." return ret if not __opts__["test"]: @@ -86,7 +86,7 @@ def present(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Virtual Host '{}' will be created.".format(name) + ret["comment"] = f"Virtual Host '{name}' will be created." return ret @@ -107,7 +107,7 @@ def absent(name): vhost_exists = __salt__["rabbitmq.vhost_exists"](name) if not vhost_exists: - ret["comment"] = "Virtual Host '{}' is not present.".format(name) + ret["comment"] = f"Virtual Host '{name}' is not present." return ret if not __opts__["test"]: @@ -124,6 +124,6 @@ def absent(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Virtual Host '{}' will be removed.".format(name) + ret["comment"] = f"Virtual Host '{name}' will be removed." return ret diff --git a/salt/states/rbac_solaris.py b/salt/states/rbac_solaris.py index 551e5b9df83..74476640b33 100644 --- a/salt/states/rbac_solaris.py +++ b/salt/states/rbac_solaris.py @@ -41,7 +41,7 @@ def __virtual__(): else: return ( False, - "{} state module can only be loaded on Solaris".format(__virtualname__), + f"{__virtualname__} state module can only be loaded on Solaris", ) @@ -70,7 +70,7 @@ def managed(name, roles=None, profiles=None, authorizations=None): ## check properties if name not in __salt__["user.list_users"](): ret["result"] = False - ret["comment"] = "User {} does not exist!".format(name) + ret["comment"] = f"User {name} does not exist!" return ret if roles and not isinstance(roles, (list)): ret["result"] = False diff --git a/salt/states/rbenv.py b/salt/states/rbenv.py index c9c721f7104..34bce97ca80 100644 --- a/salt/states/rbenv.py +++ b/salt/states/rbenv.py @@ -130,9 +130,9 @@ def installed(name, default=False, user=None): if __opts__["test"]: ret = _ruby_installed(ret, name, user=user) if not ret["result"]: - ret["comment"] = "Ruby {} is set to be installed".format(name) + ret["comment"] = f"Ruby {name} is set to be installed" else: - ret["comment"] = "Ruby {} is already installed".format(name) + ret["comment"] = f"Ruby {name} is already installed" return ret rbenv_installed_ret = _check_and_install_rbenv(rbenv_installed_ret, user) @@ -164,7 +164,7 @@ def _check_and_uninstall_ruby(ret, ruby, user=None): return ret else: ret["result"] = True - ret["comment"] = "Ruby {} is already absent".format(ruby) + ret["comment"] = f"Ruby {ruby} is already absent" return ret @@ -192,17 +192,17 @@ def absent(name, user=None): ret = _check_rbenv(ret, user) if ret["result"] is False: ret["result"] = True - ret["comment"] = "Rbenv not installed, {} not either".format(name) + ret["comment"] = f"Rbenv not installed, {name} not either" return ret else: if __opts__["test"]: ret = _ruby_installed(ret, name, user=user) if ret["result"]: ret["result"] = None - ret["comment"] = "Ruby {} is set to be uninstalled".format(name) + ret["comment"] = f"Ruby {name} is set to be uninstalled" else: ret["result"] = True - ret["comment"] = "Ruby {} is already uninstalled".format(name) + ret["comment"] = f"Ruby {name} is already uninstalled" return ret return _check_and_uninstall_ruby(ret, name, user=user) diff --git a/salt/states/redismod.py b/salt/states/redismod.py index 4ff14c61881..47a4ac776c1 100644 --- a/salt/states/redismod.py +++ b/salt/states/redismod.py @@ -74,10 +74,10 @@ def string(name, value, expire=None, expireat=None, **connection_args): if expireat: __salt__["redis.expireat"](name, expireat, **connection_args) - ret["changes"]["expireat"] = "Key expires at {}".format(expireat) + ret["changes"]["expireat"] = f"Key expires at {expireat}" elif expire: __salt__["redis.expire"](name, expire, **connection_args) - ret["changes"]["expire"] = "TTL set to {} seconds".format(expire) + ret["changes"]["expire"] = f"TTL set to {expire} seconds" return ret @@ -126,7 +126,7 @@ def slaveof( sentinel_host=None, sentinel_port=None, sentinel_password=None, - **connection_args + **connection_args, ): """ Set this redis instance as a slave. @@ -156,13 +156,13 @@ def slaveof( ) if sentinel_master["master_host"] in __salt__["network.ip_addrs"](): ret["result"] = True - ret["comment"] = "Minion is the master: {}".format(name) + ret["comment"] = f"Minion is the master: {name}" return ret first_master = __salt__["redis.get_master_ip"](**connection_args) if first_master == sentinel_master: ret["result"] = True - ret["comment"] = "Minion already slave of master: {}".format(name) + ret["comment"] = f"Minion already slave of master: {name}" return ret if __opts__["test"] is True: @@ -184,6 +184,6 @@ def slaveof( "old": first_master, "new": current_master, } - ret["comment"] = "Minion successfully connected to master: {}".format(name) + ret["comment"] = f"Minion successfully connected to master: {name}" return ret diff --git a/salt/states/rsync.py b/salt/states/rsync.py index 79be3def583..4e01eb2e8dd 100644 --- a/salt/states/rsync.py +++ b/salt/states/rsync.py @@ -143,7 +143,7 @@ def synchronized( if not os.path.exists(name) and not force and not prepare: ret["result"] = False - ret["comment"] = "Destination directory {dest} was not found.".format(dest=name) + ret["comment"] = f"Destination directory {name} was not found." else: if not os.path.exists(name) and prepare: os.makedirs(name) diff --git a/salt/states/rvm.py b/salt/states/rvm.py index 5b7c4fa8e22..f593447093b 100644 --- a/salt/states/rvm.py +++ b/salt/states/rvm.py @@ -150,7 +150,7 @@ def _check_ruby(ret, ruby, user=None): for impl, version, default in __salt__["rvm.list"](runas=user): if impl != "ruby": - version = "{impl}-{version}".format(impl=impl, version=version) + version = f"{impl}-{version}" if not match_micro_version: version = micro_version_regex.sub("", version) if not match_version: @@ -188,7 +188,7 @@ def installed(name, default=False, user=None, opts=None, env=None): ret = {"name": name, "result": None, "comment": "", "changes": {}} if __opts__["test"]: - ret["comment"] = "Ruby {} is set to be installed".format(name) + ret["comment"] = f"Ruby {name} is set to be installed" return ret ret = _check_rvm(ret, user) @@ -241,7 +241,7 @@ def gemset_present(name, ruby="default", user=None): else: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Set to install gemset {}".format(name) + ret["comment"] = f"Set to install gemset {name}" return ret if __salt__["rvm.gemset_create"](ruby, name, runas=user): ret["result"] = True diff --git a/salt/states/salt_proxy.py b/salt/states/salt_proxy.py index 8a6ef6e2675..005ae65d24d 100644 --- a/salt/states/salt_proxy.py +++ b/salt/states/salt_proxy.py @@ -52,5 +52,5 @@ def configure_proxy(name, proxyname="p8000", start=True): """ ret = __salt__["salt_proxy.configure_proxy"](proxyname, start=start) - ret.update({"name": name, "comment": "{} config messages".format(name)}) + ret.update({"name": name, "comment": f"{name} config messages"}) return ret diff --git a/salt/states/saltmod.py b/salt/states/saltmod.py index e120e418875..fdd4692c0f4 100644 --- a/salt/states/saltmod.py +++ b/salt/states/saltmod.py @@ -664,7 +664,7 @@ def wait_for_event(name, id_list, event_id="id", timeout=300, node="master"): ret = {"name": name, "changes": {}, "comment": "", "result": False} if __opts__.get("test"): - ret["comment"] = "Orchestration would wait for event '{}'".format(name) + ret["comment"] = f"Orchestration would wait for event '{name}'" ret["result"] = None return ret @@ -796,7 +796,7 @@ def runner(name, **kwargs): "name": name, "result": None, "changes": {}, - "comment": "Runner function '{}' would be executed.".format(name), + "comment": f"Runner function '{name}' would be executed.", } return ret @@ -921,7 +921,7 @@ def parallel_runners(name, runners, **kwargs): # pylint: disable=unused-argumen "result": False, "success": False, "changes": {}, - "comment": "One of the runners raised an exception: {}".format(exc), + "comment": f"One of the runners raised an exception: {exc}", } # We bundle the results of the runners with the IDs of the runners so that # we can easily identify which output belongs to which runner. At the same @@ -1000,7 +1000,7 @@ def parallel_runners(name, runners, **kwargs): # pylint: disable=unused-argumen comment = "All runner functions executed successfully." else: if len(failed_runners) == 1: - comment = "Runner {} failed.".format(failed_runners[0]) + comment = f"Runner {failed_runners[0]} failed." else: comment = "Runners {} failed.".format(", ".join(failed_runners)) changes = {"ret": {runner_id: out for runner_id, out in outputs.items()}} @@ -1046,7 +1046,7 @@ def wheel(name, **kwargs): if __opts__.get("test", False): ret["result"] = None ret["changes"] = {} - ret["comment"] = "Wheel function '{}' would be executed.".format(name) + ret["comment"] = f"Wheel function '{name}' would be executed." return ret out = __salt__["saltutil.wheel"]( diff --git a/salt/states/saltutil.py b/salt/states/saltutil.py index 9442c5019cc..faacf85888e 100644 --- a/salt/states/saltutil.py +++ b/salt/states/saltutil.py @@ -29,18 +29,18 @@ def _sync_single(name, module, **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = "saltutil.sync_{} would have been run".format(module) + ret["comment"] = f"saltutil.sync_{module} would have been run" return ret try: - sync_status = __salt__["saltutil.sync_{}".format(module)](**kwargs) + sync_status = __salt__[f"saltutil.sync_{module}"](**kwargs) if sync_status: ret["changes"][module] = sync_status - ret["comment"] = "Updated {}.".format(module) + ret["comment"] = f"Updated {module}." except Exception as e: # pylint: disable=broad-except log.error("Failed to run saltutil.sync_%s: %s", module, e) ret["result"] = False - ret["comment"] = "Failed to run sync_{}: {}".format(module, e) + ret["comment"] = f"Failed to run sync_{module}: {e}" return ret if not ret["changes"]: @@ -76,7 +76,7 @@ def sync_all(name, **kwargs): except Exception as e: # pylint: disable=broad-except log.error("Failed to run saltutil.sync_all: %s", e) ret["result"] = False - ret["comment"] = "Failed to run sync_all: {}".format(e) + ret["comment"] = f"Failed to run sync_all: {e}" return ret if not ret["changes"]: diff --git a/salt/states/schedule.py b/salt/states/schedule.py index f7d9d56e2b1..7d05aed727b 100644 --- a/salt/states/schedule.py +++ b/salt/states/schedule.py @@ -241,7 +241,7 @@ def present(name, **kwargs): new_item["enabled"] = True if new_item == current_schedule[name]: - ret["comment"].append("Job {} in correct state".format(name)) + ret["comment"].append(f"Job {name} in correct state") else: if "test" in __opts__ and __opts__["test"]: kwargs["test"] = True @@ -255,7 +255,7 @@ def present(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Modifying job {} in schedule".format(name)) + ret["comment"].append(f"Modifying job {name} in schedule") ret["changes"] = result["changes"] else: if "test" in __opts__ and __opts__["test"]: @@ -269,7 +269,7 @@ def present(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Adding new job {} to schedule".format(name)) + ret["comment"].append(f"Adding new job {name} to schedule") ret["changes"] = result["changes"] ret["comment"] = "\n".join(ret["comment"]) @@ -308,10 +308,10 @@ def absent(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Removed job {} from schedule".format(name)) + ret["comment"].append(f"Removed job {name} from schedule") ret["changes"] = result["changes"] else: - ret["comment"].append("Job {} not present in schedule".format(name)) + ret["comment"].append(f"Job {name} not present in schedule") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -345,9 +345,9 @@ def enabled(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Enabled job {} from schedule".format(name)) + ret["comment"].append(f"Enabled job {name} from schedule") else: - ret["comment"].append("Job {} not present in schedule".format(name)) + ret["comment"].append(f"Job {name} not present in schedule") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -384,9 +384,9 @@ def disabled(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Disabled job {} from schedule".format(name)) + ret["comment"].append(f"Disabled job {name} from schedule") else: - ret["comment"].append("Job {} not present in schedule".format(name)) + ret["comment"].append(f"Job {name} not present in schedule") ret["comment"] = "\n".join(ret["comment"]) return ret diff --git a/salt/states/selinux.py b/salt/states/selinux.py index 08b2830fef7..24c48acd01b 100644 --- a/salt/states/selinux.py +++ b/salt/states/selinux.py @@ -88,7 +88,7 @@ def mode(name): ret = {"name": name, "result": False, "comment": "", "changes": {}} tmode = _refine_mode(name) if tmode == "unknown": - ret["comment"] = "{} is not an accepted mode".format(name) + ret["comment"] = f"{name} is not an accepted mode" return ret # Either the current mode in memory or a non-matching config value # will trigger setenforce @@ -100,11 +100,11 @@ def mode(name): if mode == tmode: ret["result"] = True - ret["comment"] = "SELinux is already in {} mode".format(tmode) + ret["comment"] = f"SELinux is already in {tmode} mode" return ret # The mode needs to change... if __opts__["test"]: - ret["comment"] = "SELinux mode is set to be changed to {}".format(tmode) + ret["comment"] = f"SELinux mode is set to be changed to {tmode}" ret["result"] = None ret["changes"] = {"old": mode, "new": tmode} return ret @@ -114,10 +114,10 @@ def mode(name): tmode == "Disabled" and __salt__["selinux.getconfig"]() == tmode ): ret["result"] = True - ret["comment"] = "SELinux has been set to {} mode".format(tmode) + ret["comment"] = f"SELinux has been set to {tmode} mode" ret["changes"] = {"old": oldmode, "new": mode} return ret - ret["comment"] = "Failed to set SELinux to {} mode".format(tmode) + ret["comment"] = f"Failed to set SELinux to {tmode} mode" return ret @@ -138,12 +138,12 @@ def boolean(name, value, persist=False): ret = {"name": name, "result": True, "comment": "", "changes": {}} bools = __salt__["selinux.list_sebool"]() if name not in bools: - ret["comment"] = "Boolean {} is not available".format(name) + ret["comment"] = f"Boolean {name} is not available" ret["result"] = False return ret rvalue = _refine_value(value) if rvalue is None: - ret["comment"] = "{} is not a valid value for the boolean".format(value) + ret["comment"] = f"{value} is not a valid value for the boolean" ret["result"] = False return ret state = bools[name]["State"] == rvalue @@ -158,19 +158,19 @@ def boolean(name, value, persist=False): return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Boolean {} is set to be changed to {}".format(name, rvalue) + ret["comment"] = f"Boolean {name} is set to be changed to {rvalue}" return ret ret["result"] = __salt__["selinux.setsebool"](name, rvalue, persist) if ret["result"]: - ret["comment"] = "Boolean {} has been set to {}".format(name, rvalue) + ret["comment"] = f"Boolean {name} has been set to {rvalue}" ret["changes"].update({"State": {"old": bools[name]["State"], "new": rvalue}}) if persist and not default: ret["changes"].update( {"Default": {"old": bools[name]["Default"], "new": rvalue}} ) return ret - ret["comment"] = "Failed to set the boolean {} to {}".format(name, rvalue) + ret["comment"] = f"Failed to set the boolean {name} to {rvalue}" return ret @@ -213,7 +213,7 @@ def module(name, module_state="Enabled", version="any", **opts): return module_remove(name) modules = __salt__["selinux.list_semod"]() if name not in modules: - ret["comment"] = "Module {} is not available".format(name) + ret["comment"] = f"Module {name} is not available" ret["result"] = False return ret rmodule_state = _refine_module_state(module_state) @@ -235,7 +235,7 @@ def module(name, module_state="Enabled", version="any", **opts): return ret current_module_state = _refine_module_state(modules[name]["Enabled"]) if rmodule_state == current_module_state: - ret["comment"] = "Module {} is in the desired state".format(name) + ret["comment"] = f"Module {name} is in the desired state" return ret if __opts__["test"]: ret["result"] = None @@ -245,10 +245,10 @@ def module(name, module_state="Enabled", version="any", **opts): return ret if __salt__["selinux.setsemod"](name, rmodule_state): - ret["comment"] = "Module {} has been set to {}".format(name, module_state) + ret["comment"] = f"Module {name} has been set to {module_state}" return ret ret["result"] = False - ret["comment"] = "Failed to set the Module {} to {}".format(name, module_state) + ret["comment"] = f"Failed to set the Module {name} to {module_state}" return ret @@ -263,10 +263,10 @@ def module_install(name): """ ret = {"name": name, "result": True, "comment": "", "changes": {}} if __salt__["selinux.install_semod"](name): - ret["comment"] = "Module {} has been installed".format(name) + ret["comment"] = f"Module {name} has been installed" return ret ret["result"] = False - ret["comment"] = "Failed to install module {}".format(name) + ret["comment"] = f"Failed to install module {name}" return ret @@ -282,14 +282,14 @@ def module_remove(name): ret = {"name": name, "result": True, "comment": "", "changes": {}} modules = __salt__["selinux.list_semod"]() if name not in modules: - ret["comment"] = "Module {} is not available".format(name) + ret["comment"] = f"Module {name} is not available" ret["result"] = False return ret if __salt__["selinux.remove_semod"](name): - ret["comment"] = "Module {} has been removed".format(name) + ret["comment"] = f"Module {name} has been removed" return ret ret["result"] = False - ret["comment"] = "Failed to remove module {}".format(name) + ret["comment"] = f"Failed to remove module {name}" return ret @@ -343,7 +343,7 @@ def fcontext_policy_present( sel_level=sel_level, ) if add_ret["retcode"] != 0: - ret.update({"comment": "Error adding new rule: {}".format(add_ret)}) + ret.update({"comment": f"Error adding new rule: {add_ret}"}) else: ret.update({"result": True}) else: @@ -354,7 +354,7 @@ def fcontext_policy_present( ret.update( { "result": True, - "comment": 'SELinux policy for "{}" already present '.format(name) + "comment": f'SELinux policy for "{name}" already present ' + 'with specified filetype "{}" and sel_type "{}".'.format( filetype_str, sel_type ), @@ -375,7 +375,7 @@ def fcontext_policy_present( sel_level=sel_level, ) if change_ret["retcode"] != 0: - ret.update({"comment": "Error adding new rule: {}".format(change_ret)}) + ret.update({"comment": f"Error adding new rule: {change_ret}"}) else: ret.update({"result": True}) if ret["result"] and (new_state or old_state): @@ -423,7 +423,7 @@ def fcontext_policy_absent( ret.update( { "result": True, - "comment": 'SELinux policy for "{}" already absent '.format(name) + "comment": f'SELinux policy for "{name}" already absent ' + 'with specified filetype "{}" and sel_type "{}".'.format( filetype, sel_type ), @@ -444,7 +444,7 @@ def fcontext_policy_absent( sel_level=sel_level, ) if remove_ret["retcode"] != 0: - ret.update({"comment": "Error removing policy: {}".format(remove_ret)}) + ret.update({"comment": f"Error removing policy: {remove_ret}"}) else: ret.update({"result": True}) return ret @@ -516,7 +516,7 @@ def port_policy_present(name, sel_type, protocol=None, port=None, sel_range=None ret.update( { "result": True, - "comment": 'SELinux policy for "{}" already present '.format(name) + "comment": f'SELinux policy for "{name}" already present ' + 'with specified sel_type "{}", protocol "{}" and port "{}".'.format( sel_type, protocol, port ), @@ -534,7 +534,7 @@ def port_policy_present(name, sel_type, protocol=None, port=None, sel_range=None sel_range=sel_range, ) if add_ret["retcode"] != 0: - ret.update({"comment": "Error adding new policy: {}".format(add_ret)}) + ret.update({"comment": f"Error adding new policy: {add_ret}"}) else: ret.update({"result": True}) new_state = __salt__["selinux.port_get_policy"]( @@ -577,7 +577,7 @@ def port_policy_absent(name, sel_type=None, protocol=None, port=None): ret.update( { "result": True, - "comment": 'SELinux policy for "{}" already absent '.format(name) + "comment": f'SELinux policy for "{name}" already absent ' + 'with specified sel_type "{}", protocol "{}" and port "{}".'.format( sel_type, protocol, port ), @@ -593,7 +593,7 @@ def port_policy_absent(name, sel_type=None, protocol=None, port=None): port=port, ) if delete_ret["retcode"] != 0: - ret.update({"comment": "Error deleting policy: {}".format(delete_ret)}) + ret.update({"comment": f"Error deleting policy: {delete_ret}"}) else: ret.update({"result": True}) new_state = __salt__["selinux.port_get_policy"]( diff --git a/salt/states/service.py b/salt/states/service.py index 650def38a38..ab14ed0abf1 100644 --- a/salt/states/service.py +++ b/salt/states/service.py @@ -190,13 +190,13 @@ def _enable(name, started, result=True, **kwargs): ) ) else: - ret["comment"] = "Service {} is already enabled, and is dead".format(name) + ret["comment"] = f"Service {name} is already enabled, and is dead" return ret # Service needs to be enabled if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} set to be enabled".format(name) + ret["comment"] = f"Service {name} set to be enabled" return ret try: @@ -220,7 +220,7 @@ def _enable(name, started, result=True, **kwargs): ) ) else: - ret["comment"] = "Service {} has been enabled, and is dead".format(name) + ret["comment"] = f"Service {name} has been enabled, and is dead" return ret except CommandExecutionError as exc: enable_error = exc.strerror @@ -247,7 +247,7 @@ def _enable(name, started, result=True, **kwargs): ) if enable_error: - ret["comment"] += ". Additional information follows:\n\n{}".format(enable_error) + ret["comment"] += f". Additional information follows:\n\n{enable_error}" return ret @@ -316,13 +316,13 @@ def _disable(name, started, result=True, **kwargs): ) ) else: - ret["comment"] = "Service {} is already disabled, and is dead".format(name) + ret["comment"] = f"Service {name} is already disabled, and is dead" return ret # Service needs to be disabled if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} set to be disabled".format(name) + ret["comment"] = f"Service {name} set to be disabled" return ret if __salt__["service.disable"](name, **kwargs): @@ -335,13 +335,13 @@ def _disable(name, started, result=True, **kwargs): if before_toggle_disable_status != after_toggle_disable_status: ret["changes"][name] = True if started is True: - ret["comment"] = "Service {} has been disabled, and is running".format(name) + ret["comment"] = f"Service {name} has been disabled, and is running" elif started is None: ret["comment"] = ( - "Service {} has been disabled, and is in the desired state".format(name) + f"Service {name} has been disabled, and is in the desired state" ) else: - ret["comment"] = "Service {} has been disabled, and is dead".format(name) + ret["comment"] = f"Service {name} has been disabled, and is dead" return ret # Service failed to be disabled @@ -380,7 +380,7 @@ def _available(name, ret): avail = name in __salt__["service.get_all"]() if not avail: ret["result"] = False - ret["comment"] = "The named service {} is not available".format(name) + ret["comment"] = f"The named service {name} is not available" return avail @@ -505,7 +505,7 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): [ _f for _f in [ - "The service {} is already running".format(name), + f"The service {name} is already running", unmask_ret["comment"], ] if _f @@ -524,7 +524,7 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): [ _f for _f in [ - "Service {} is set to start".format(name), + f"Service {name} is set to start", unmask_ret["comment"], ] if _f @@ -566,7 +566,7 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): if not func_ret: ret["result"] = False - ret["comment"] = "Service {} failed to start".format(name) + ret["comment"] = f"Service {name} failed to start" if enable is True: ret.update(_enable(name, False, result=False, **kwargs)) elif enable is False: @@ -589,9 +589,9 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): ret["changes"][name] = after_toggle_status if after_toggle_status: - ret["comment"] = "Started service {}".format(name) + ret["comment"] = f"Started service {name}" else: - ret["comment"] = "Service {} failed to start".format(name) + ret["comment"] = f"Service {name} failed to start" ret["result"] = False if enable is True: @@ -708,7 +708,7 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): # See if the service is already dead if not before_toggle_status: - ret["comment"] = "The service {} is already dead".format(name) + ret["comment"] = f"The service {name} is already dead" if enable is True and not before_toggle_enable_status: ret.update(_enable(name, None, **kwargs)) elif enable is False and before_toggle_enable_status: @@ -718,7 +718,7 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): # Run the tests if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} is set to be killed".format(name) + ret["comment"] = f"Service {name} is set to be killed" return ret # Conditionally add systemd-specific args to call to service.start @@ -732,7 +732,7 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): func_ret = __salt__["service.stop"](name, **stop_kwargs) if not func_ret: ret["result"] = False - ret["comment"] = "Service {} failed to die".format(name) + ret["comment"] = f"Service {name} failed to die" if enable is True: ret.update(_enable(name, True, result=False, **kwargs)) elif enable is False: @@ -757,9 +757,9 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): # be sure to stop, in case we mis detected in the check if after_toggle_status: ret["result"] = False - ret["comment"] = "Service {} failed to die".format(name) + ret["comment"] = f"Service {name} failed to die" else: - ret["comment"] = "Service {} was killed".format(name) + ret["comment"] = f"Service {name} was killed" if enable is True: ret.update( @@ -791,9 +791,10 @@ def enabled(name, **kwargs): __context__["service.state"] = "enabled" ret.update(_enable(name, None, **kwargs)) - if __opts__.get("test") and ret.get( - "comment" - ) == "The named service {} is not available".format(name): + if ( + __opts__.get("test") + and ret.get("comment") == f"The named service {name} is not available" + ): ret["result"] = None ret["comment"] = ( "Service {} not present; if created in this state run, " @@ -885,16 +886,16 @@ def masked(name, runtime=False): if __opts__["test"]: ret["result"] = None ret["changes"] = expected_changes - ret["comment"] = "Service {} would be {}".format(name, mask_type) + ret["comment"] = f"Service {name} would be {mask_type}" return ret __salt__["service.mask"](name, runtime) if __salt__["service.masked"](name, runtime): ret["changes"] = expected_changes - ret["comment"] = "Service {} was {}".format(name, mask_type) + ret["comment"] = f"Service {name} was {mask_type}" else: - ret["comment"] = "Failed to mask service {}".format(name) + ret["comment"] = f"Failed to mask service {name}" return ret except CommandExecutionError as exc: @@ -943,22 +944,22 @@ def unmasked(name, runtime=False): try: if not __salt__["service.masked"](name, runtime): - ret["comment"] = "Service {} was already {}".format(name, action) + ret["comment"] = f"Service {name} was already {action}" return ret if __opts__["test"]: ret["result"] = None ret["changes"] = expected_changes - ret["comment"] = "Service {} would be {}".format(name, action) + ret["comment"] = f"Service {name} would be {action}" return ret __salt__["service.unmask"](name, runtime) if not __salt__["service.masked"](name, runtime): ret["changes"] = expected_changes - ret["comment"] = "Service {} was {}".format(name, action) + ret["comment"] = f"Service {name} was {action}" else: - ret["comment"] = "Failed to unmask service {}".format(name) + ret["comment"] = f"Failed to unmask service {name}" return ret except CommandExecutionError as exc: @@ -975,7 +976,7 @@ def mod_watch( full_restart=False, init_delay=None, force=False, - **kwargs + **kwargs, ): """ The service watcher, called to invoke the watch command. @@ -1027,7 +1028,7 @@ def mod_watch( func = __salt__["service.stop"] else: ret["result"] = True - ret["comment"] = "Service is already {}".format(past_participle) + ret["comment"] = f"Service is already {past_participle}" return ret elif sfun == "running": if __salt__["service.status"](name, sig, **status_kwargs): @@ -1050,13 +1051,13 @@ def mod_watch( if not past_participle: past_participle = verb + "ed" else: - ret["comment"] = "Unable to trigger watch for service.{}".format(sfun) + ret["comment"] = f"Unable to trigger watch for service.{sfun}" ret["result"] = False return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service is set to be {}".format(past_participle) + ret["comment"] = f"Service is set to be {past_participle}" return ret if verb == "start" and "service.stop" in __salt__: @@ -1080,9 +1081,7 @@ def mod_watch( ret["changes"] = {name: result} ret["result"] = result ret["comment"] = ( - "Service {}".format(past_participle) - if result - else "Failed to {} the service".format(verb) + f"Service {past_participle}" if result else f"Failed to {verb} the service" ) return ret @@ -1112,7 +1111,7 @@ def mod_beacon(name, **kwargs): data["emitatstartup"] = _beacon_data.get("emitatstartup", False) data["uncleanshutdown"] = _beacon_data.get("emitatstartup", None) - beacon_name = "beacon_{}_{}".format(beacon_module, name) + beacon_name = f"beacon_{beacon_module}_{name}" beacon_kwargs = { "name": beacon_name, diff --git a/salt/states/slack.py b/salt/states/slack.py index 1ba0f4b4e59..df271f2be1c 100644 --- a/salt/states/slack.py +++ b/salt/states/slack.py @@ -161,11 +161,11 @@ def post_message(name, **kwargs): ) except SaltInvocationError as sie: - ret["comment"] = "Failed to send message ({}): {}".format(sie, name) + ret["comment"] = f"Failed to send message ({sie}): {name}" else: if isinstance(result, bool) and result: ret["result"] = True - ret["comment"] = "Sent message: {}".format(name) + ret["comment"] = f"Sent message: {name}" else: ret["comment"] = "Failed to send message ({}): {}".format( result["message"], name diff --git a/salt/states/smartos.py b/salt/states/smartos.py index 29c2bb72352..1309ad00c72 100644 --- a/salt/states/smartos.py +++ b/salt/states/smartos.py @@ -213,9 +213,9 @@ def _write_config(config): if not config[prop].startswith('"') or not config[prop].endswith( '"' ): - config[prop] = '"{}"'.format(config[prop]) + config[prop] = f'"{config[prop]}"' config_file.write( - salt.utils.stringutils.to_str("{}={}\n".format(prop, config[prop])) + salt.utils.stringutils.to_str(f"{prop}={config[prop]}\n") ) log.debug("smartos.config - wrote /usbkey/config: %s", config) except OSError: @@ -299,7 +299,7 @@ def _copy_lx_vars(vmconfig): for var in imgtags.get("docker:config", {}): val = imgtags["docker:config"][var] - var = "docker:{}".format(var.lower()) + var = f"docker:{var.lower()}" # NOTE: skip empty values if not val: @@ -321,7 +321,7 @@ def _copy_lx_vars(vmconfig): ): config_env_var = config_env_var.split("=") for img_env_var in val: - if img_env_var.startswith("{}=".format(config_env_var[0])): + if img_env_var.startswith(f"{config_env_var[0]}="): val.remove(img_env_var) val.append("=".join(config_env_var)) elif var in vmconfig["internal_metadata"]: @@ -362,17 +362,17 @@ def config_present(name, value): if str(config[name]) == str(value): # we're good ret["result"] = True - ret["comment"] = 'property {} already has value "{}"'.format(name, value) + ret["comment"] = f'property {name} already has value "{value}"' else: # update property ret["result"] = True - ret["comment"] = 'updated property {} with value "{}"'.format(name, value) + ret["comment"] = f'updated property {name} with value "{value}"' ret["changes"][name] = value config[name] = value else: # add property ret["result"] = True - ret["comment"] = 'added property {} with value "{}"'.format(name, value) + ret["comment"] = f'added property {name} with value "{value}"' ret["changes"][name] = value config[name] = value @@ -407,13 +407,13 @@ def config_absent(name): if name in config: # delete property ret["result"] = True - ret["comment"] = "property {} deleted".format(name) + ret["comment"] = f"property {name} deleted" ret["changes"][name] = None del config[name] else: # we're good ret["result"] = True - ret["comment"] = "property {} is absent".format(name) + ret["comment"] = f"property {name} is absent" # apply change if needed if not __opts__["test"] and ret["changes"]: @@ -436,7 +436,7 @@ def source_present(name, source_type="imgapi"): if name in __salt__["imgadm.sources"](): # source is present ret["result"] = True - ret["comment"] = "image source {} is present".format(name) + ret["comment"] = f"image source {name} is present" else: # add new source if __opts__["test"]: @@ -447,10 +447,10 @@ def source_present(name, source_type="imgapi"): ret["result"] = name in res if ret["result"]: - ret["comment"] = "image source {} added".format(name) + ret["comment"] = f"image source {name} added" ret["changes"][name] = "added" else: - ret["comment"] = "image source {} not added".format(name) + ret["comment"] = f"image source {name} not added" if "Error" in res: ret["comment"] = "{}: {}".format(ret["comment"], res["Error"]) @@ -469,7 +469,7 @@ def source_absent(name): if name not in __salt__["imgadm.sources"](): # source is absent ret["result"] = True - ret["comment"] = "image source {} is absent".format(name) + ret["comment"] = f"image source {name} is absent" else: # remove source if __opts__["test"]: @@ -480,10 +480,10 @@ def source_absent(name): ret["result"] = name not in res if ret["result"]: - ret["comment"] = "image source {} deleted".format(name) + ret["comment"] = f"image source {name} deleted" ret["changes"][name] = "deleted" else: - ret["comment"] = "image source {} not deleted".format(name) + ret["comment"] = f"image source {name} not deleted" if "Error" in res: ret["comment"] = "{}: {}".format(ret["comment"], res["Error"]) @@ -509,7 +509,7 @@ def image_present(name): elif name in __salt__["imgadm.list"](): # image was already imported ret["result"] = True - ret["comment"] = "image {} is present".format(name) + ret["comment"] = f"image {name} is present" else: # add image if _is_docker_uuid(name): @@ -533,13 +533,13 @@ def image_present(name): elif _is_docker_uuid(name): ret["result"] = __salt__["imgadm.docker_to_uuid"](name) is not None if ret["result"]: - ret["comment"] = "image {} imported".format(name) + ret["comment"] = f"image {name} imported" ret["changes"] = res else: - ret["comment"] = "image {} was unable to be imported".format(name) + ret["comment"] = f"image {name} was unable to be imported" else: ret["result"] = False - ret["comment"] = "image {} does not exists".format(name) + ret["comment"] = f"image {name} does not exists" return ret @@ -567,12 +567,12 @@ def image_absent(name): if not uuid or uuid not in __salt__["imgadm.list"](): # image not imported ret["result"] = True - ret["comment"] = "image {} is absent".format(name) + ret["comment"] = f"image {name} is absent" else: # check if image in use by vm if uuid in __salt__["vmadm.list"](order="image_uuid"): ret["result"] = False - ret["comment"] = "image {} currently in use by a vm".format(name) + ret["comment"] = f"image {name} currently in use by a vm" else: # delete image if __opts__["test"]: @@ -599,7 +599,7 @@ def image_absent(name): name, image_count ) else: - ret["comment"] = "image {} deleted".format(name) + ret["comment"] = f"image {name} deleted" ret["changes"][name] = None return ret @@ -905,7 +905,7 @@ def vm_present(name, vmconfig, config=None): continue # enforcement - enforce = config["enforce_{}".format(collection)] + enforce = config[f"enforce_{collection}"] log.debug("smartos.vm_present::enforce_%s = %s", collection, enforce) # dockerinit handling @@ -940,13 +940,13 @@ def vm_present(name, vmconfig, config=None): continue # create set_ dict - if "set_{}".format(collection) not in vmconfig["changed"]: - vmconfig["changed"]["set_{}".format(collection)] = {} + if f"set_{collection}" not in vmconfig["changed"]: + vmconfig["changed"][f"set_{collection}"] = {} # add property to changeset - vmconfig["changed"]["set_{}".format(collection)][prop] = vmconfig[ - "state" - ][collection][prop] + vmconfig["changed"][f"set_{collection}"][prop] = vmconfig["state"][ + collection + ][prop] # process remove for collection if ( @@ -964,11 +964,11 @@ def vm_present(name, vmconfig, config=None): continue # create remove_ array - if "remove_{}".format(collection) not in vmconfig["changed"]: - vmconfig["changed"]["remove_{}".format(collection)] = [] + if f"remove_{collection}" not in vmconfig["changed"]: + vmconfig["changed"][f"remove_{collection}"] = [] # remove property - vmconfig["changed"]["remove_{}".format(collection)].append(prop) + vmconfig["changed"][f"remove_{collection}"].append(prop) # process instances for instance in vmconfig_type["instance"]: @@ -1018,28 +1018,23 @@ def vm_present(name, vmconfig, config=None): # update instance if update_cfg: # create update_ array - if ( - "update_{}".format(instance) - not in vmconfig["changed"] - ): - vmconfig["changed"][ - "update_{}".format(instance) - ] = [] + if f"update_{instance}" not in vmconfig["changed"]: + vmconfig["changed"][f"update_{instance}"] = [] update_cfg[vmconfig_type["instance"][instance]] = ( state_cfg[vmconfig_type["instance"][instance]] ) - vmconfig["changed"][ - "update_{}".format(instance) - ].append(update_cfg) + vmconfig["changed"][f"update_{instance}"].append( + update_cfg + ) if add_instance: # create add_ array - if "add_{}".format(instance) not in vmconfig["changed"]: - vmconfig["changed"]["add_{}".format(instance)] = [] + if f"add_{instance}" not in vmconfig["changed"]: + vmconfig["changed"][f"add_{instance}"] = [] # add instance - vmconfig["changed"]["add_{}".format(instance)].append(state_cfg) + vmconfig["changed"][f"add_{instance}"].append(state_cfg) # remove instances if ( @@ -1067,11 +1062,11 @@ def vm_present(name, vmconfig, config=None): if remove_instance: # create remove_ array - if "remove_{}".format(instance) not in vmconfig["changed"]: - vmconfig["changed"]["remove_{}".format(instance)] = [] + if f"remove_{instance}" not in vmconfig["changed"]: + vmconfig["changed"][f"remove_{instance}"] = [] # remove instance - vmconfig["changed"]["remove_{}".format(instance)].append( + vmconfig["changed"][f"remove_{instance}"].append( current_cfg[vmconfig_type["instance"][instance]] ) @@ -1221,7 +1216,7 @@ def vm_absent(name, archive=False): if name not in __salt__["vmadm.list"](order="hostname"): # we're good ret["result"] = True - ret["comment"] = "vm {} is absent".format(name) + ret["comment"] = f"vm {name} is absent" else: # delete vm if not __opts__["test"]: @@ -1237,9 +1232,9 @@ def vm_absent(name, archive=False): if not isinstance(ret["result"], bool) and ret["result"].get("Error"): ret["result"] = False - ret["comment"] = "failed to delete vm {}".format(name) + ret["comment"] = f"failed to delete vm {name}" else: - ret["comment"] = "vm {} deleted".format(name) + ret["comment"] = f"vm {name} deleted" ret["changes"][name] = None return ret @@ -1263,7 +1258,7 @@ def vm_running(name): if name in __salt__["vmadm.list"](order="hostname", search="state=running"): # we're good ret["result"] = True - ret["comment"] = "vm {} already running".format(name) + ret["comment"] = f"vm {name} already running" else: # start the vm ret["result"] = ( @@ -1271,10 +1266,10 @@ def vm_running(name): ) if not isinstance(ret["result"], bool) and ret["result"].get("Error"): ret["result"] = False - ret["comment"] = "failed to start {}".format(name) + ret["comment"] = f"failed to start {name}" else: ret["changes"][name] = "running" - ret["comment"] = "vm {} started".format(name) + ret["comment"] = f"vm {name} started" return ret @@ -1297,7 +1292,7 @@ def vm_stopped(name): if name in __salt__["vmadm.list"](order="hostname", search="state=stopped"): # we're good ret["result"] = True - ret["comment"] = "vm {} already stopped".format(name) + ret["comment"] = f"vm {name} already stopped" else: # stop the vm ret["result"] = ( @@ -1305,9 +1300,9 @@ def vm_stopped(name): ) if not isinstance(ret["result"], bool) and ret["result"].get("Error"): ret["result"] = False - ret["comment"] = "failed to stop {}".format(name) + ret["comment"] = f"failed to stop {name}" else: ret["changes"][name] = "stopped" - ret["comment"] = "vm {} stopped".format(name) + ret["comment"] = f"vm {name} stopped" return ret diff --git a/salt/states/smtp.py b/salt/states/smtp.py index 2c8068363e7..1dd9fd9c799 100644 --- a/salt/states/smtp.py +++ b/salt/states/smtp.py @@ -86,8 +86,8 @@ def send_msg( recipient, name, atts ) else: - ret["comment"] = "Sent message to {}: {}".format(recipient, name) + ret["comment"] = f"Sent message to {recipient}: {name}" else: ret["result"] = False - ret["comment"] = "Unable to send message to {}: {}".format(recipient, name) + ret["comment"] = f"Unable to send message to {recipient}: {name}" return ret diff --git a/salt/states/snapper.py b/salt/states/snapper.py index 6a6a7d66973..2c61ab9722c 100644 --- a/salt/states/snapper.py +++ b/salt/states/snapper.py @@ -177,9 +177,7 @@ def baseline_snapshot( if tag: snapshot = _get_baseline_from_tag(config, tag) if not snapshot: - ret.update( - {"result": False, "comment": 'Baseline tag "{}" not found'.format(tag)} - ) + ret.update({"result": False, "comment": f'Baseline tag "{tag}" not found'}) return ret number = snapshot["id"] diff --git a/salt/states/solrcloud.py b/salt/states/solrcloud.py index edbb6baf74b..4858ecf84f5 100644 --- a/salt/states/solrcloud.py +++ b/salt/states/solrcloud.py @@ -38,11 +38,11 @@ def alias(name, collections, **kwargs): return ret if __opts__["test"]: - ret["comment"] = 'The alias "{}" will be updated.'.format(name) + ret["comment"] = f'The alias "{name}" will be updated.' ret["result"] = None else: __salt__["solrcloud.alias_set_collections"](name, collections, **kwargs) - ret["comment"] = 'The alias "{}" has been updated.'.format(name) + ret["comment"] = f'The alias "{name}" has been updated.' ret["result"] = True ret["changes"] = { @@ -52,11 +52,11 @@ def alias(name, collections, **kwargs): else: if __opts__["test"]: - ret["comment"] = 'The alias "{}" will be created.'.format(name) + ret["comment"] = f'The alias "{name}" will be created.' ret["result"] = None else: __salt__["solrcloud.alias_set_collections"](name, collections, **kwargs) - ret["comment"] = 'The alias "{}" has been created.'.format(name) + ret["comment"] = f'The alias "{name}" has been created.' ret["result"] = True ret["changes"] = { @@ -120,7 +120,7 @@ def collection(name, options=None, **kwargs): else: if __opts__["test"]: - ret["comment"] = 'Collection options "{}" will be changed.'.format(name) + ret["comment"] = f'Collection options "{name}" will be changed.' ret["result"] = None else: __salt__["solrcloud.collection_set_options"](name, diff, **kwargs) @@ -145,11 +145,11 @@ def collection(name, options=None, **kwargs): options, sort_keys=True, indent=4, separators=(",", ": ") ) if __opts__["test"]: - ret["comment"] = 'The collection "{}" will be created.'.format(name) + ret["comment"] = f'The collection "{name}" will be created.' ret["result"] = None else: __salt__["solrcloud.collection_create"](name, options, **kwargs) - ret["comment"] = 'The collection "{}" has been created.'.format(name) + ret["comment"] = f'The collection "{name}" has been created.' ret["result"] = True ret["changes"] = { diff --git a/salt/states/splunk.py b/salt/states/splunk.py index 272a516ff4a..54c175f5490 100644 --- a/salt/states/splunk.py +++ b/salt/states/splunk.py @@ -50,22 +50,22 @@ def present(email, profile="splunk", **kwargs): if not target: if __opts__["test"]: - ret["comment"] = "User {} will be created".format(name) + ret["comment"] = f"User {name} will be created" return ret # create the user result = __salt__["splunk.create_user"](email, profile=profile, **kwargs) if result: ret["changes"].setdefault("old", None) - ret["changes"].setdefault("new", "User {} exists".format(name)) + ret["changes"].setdefault("new", f"User {name} exists") ret["result"] = True else: ret["result"] = False - ret["comment"] = "Failed to create {}".format(name) + ret["comment"] = f"Failed to create {name}" return ret else: - ret["comment"] = "User {} set to be updated.".format(name) + ret["comment"] = f"User {name} set to be updated." if __opts__["test"]: ret["result"] = None return ret @@ -130,31 +130,31 @@ def absent(email, profile="splunk", **kwargs): "name": user_identity, "changes": {}, "result": None, - "comment": "User {} is absent.".format(user_identity), + "comment": f"User {user_identity} is absent.", } target = __salt__["splunk.get_user"](email, profile=profile) if not target: - ret["comment"] = "User {} does not exist".format(user_identity) + ret["comment"] = f"User {user_identity} does not exist" ret["result"] = True return ret if __opts__["test"]: - ret["comment"] = "User {} is all set to be deleted".format(user_identity) + ret["comment"] = f"User {user_identity} is all set to be deleted" ret["result"] = None return ret result = __salt__["splunk.delete_user"](email, profile=profile) if result: - ret["comment"] = "Deleted user {}".format(user_identity) - ret["changes"].setdefault("old", "User {} exists".format(user_identity)) - ret["changes"].setdefault("new", "User {} deleted".format(user_identity)) + ret["comment"] = f"Deleted user {user_identity}" + ret["changes"].setdefault("old", f"User {user_identity} exists") + ret["changes"].setdefault("new", f"User {user_identity} deleted") ret["result"] = True else: - ret["comment"] = "Failed to delete {}".format(user_identity) + ret["comment"] = f"Failed to delete {user_identity}" ret["result"] = False return ret diff --git a/salt/states/splunk_search.py b/salt/states/splunk_search.py index a12ca481e29..8c00b217e45 100644 --- a/salt/states/splunk_search.py +++ b/salt/states/splunk_search.py @@ -44,7 +44,7 @@ def present(name, profile="splunk", **kwargs): target = __salt__["splunk_search.get"](name, profile=profile) if target: if __opts__["test"]: - ret["comment"] = "Would update {}".format(name) + ret["comment"] = f"Would update {name}" return ret # found a search... updating result = __salt__["splunk_search.update"](name, profile=profile, **kwargs) @@ -64,7 +64,7 @@ def present(name, profile="splunk", **kwargs): ret["changes"]["new"] = newvalues else: if __opts__["test"]: - ret["comment"] = "Would create {}".format(name) + ret["comment"] = f"Would create {name}" return ret # creating a new search result = __salt__["splunk_search.create"](name, profile=profile, **kwargs) @@ -74,7 +74,7 @@ def present(name, profile="splunk", **kwargs): ret["changes"]["new"] = kwargs else: ret["result"] = False - ret["comment"] = "Failed to create {}".format(name) + ret["comment"] = f"Failed to create {name}" return ret @@ -96,7 +96,7 @@ def absent(name, profile="splunk"): "name": name, "changes": {}, "result": True, - "comment": "{} is absent.".format(name), + "comment": f"{name} is absent.", } target = __salt__["splunk_search.get"](name, profile=profile) @@ -104,14 +104,14 @@ def absent(name, profile="splunk"): if __opts__["test"]: ret = {} ret["name"] = name - ret["comment"] = "Would delete {}".format(name) + ret["comment"] = f"Would delete {name}" ret["result"] = None return ret result = __salt__["splunk_search.delete"](name, profile=profile) if result: - ret["comment"] = "{} was deleted".format(name) + ret["comment"] = f"{name} was deleted" else: - ret["comment"] = "Failed to delete {}".format(name) + ret["comment"] = f"Failed to delete {name}" ret["result"] = False return ret diff --git a/salt/states/ssh_known_hosts.py b/salt/states/ssh_known_hosts.py index 262c9cadb32..9502e827bff 100644 --- a/salt/states/ssh_known_hosts.py +++ b/salt/states/ssh_known_hosts.py @@ -148,18 +148,18 @@ def present( ) except CommandNotFoundError as err: ret["result"] = False - ret["comment"] = "ssh.check_known_host error: {}".format(err) + ret["comment"] = f"ssh.check_known_host error: {err}" return ret if result == "exists": - comment = "Host {} is already in {}".format(name, config) + comment = f"Host {name} is already in {config}" ret["result"] = True return dict(ret, comment=comment) elif result == "add": - comment = "Key for {} is set to be added to {}".format(name, config) + comment = f"Key for {name} is set to be added to {config}" return dict(ret, comment=comment) else: # 'update' - comment = "Key for {} is set to be updated in {}".format(name, config) + comment = f"Key for {name} is set to be updated in {config}" return dict(ret, comment=comment) result = __salt__["ssh.set_known_host"]( @@ -175,7 +175,7 @@ def present( fingerprint_hash_type=fingerprint_hash_type, ) if result["status"] == "exists": - return dict(ret, comment="{} already exists in {}".format(name, config)) + return dict(ret, comment=f"{name} already exists in {config}") elif result["status"] == "error": return dict(ret, result=False, comment=result["error"]) else: # 'updated' @@ -184,7 +184,7 @@ def present( return dict( ret, changes={"old": result["old"], "new": result["new"]}, - comment="{}'s key saved to {} (key: {})".format(name, config, new_key), + comment=f"{name}'s key saved to {config} (key: {new_key})", ) else: fingerprint = result["new"][0]["fingerprint"] @@ -235,7 +235,7 @@ def absent(name, user=None, config=None): return dict(ret, comment="Host is already absent") if __opts__["test"]: - comment = "Key for {} is set to be removed from {}".format(name, config) + comment = f"Key for {name} is set to be removed from {config}" ret["result"] = None return dict(ret, comment=comment) diff --git a/salt/states/status.py b/salt/states/status.py index 98cdffb3f08..5f84d07e16b 100644 --- a/salt/states/status.py +++ b/salt/states/status.py @@ -28,7 +28,7 @@ def loadavg(name, maximum=None, minimum=None): data = __salt__["status.loadavg"]() if name not in data: ret["result"] = False - ret["comment"] += "Requested load average {} not available ".format(name) + ret["comment"] += f"Requested load average {name} not available " return ret if minimum and maximum and minimum >= maximum: ret["comment"] += "Min must be less than max" @@ -44,7 +44,7 @@ def loadavg(name, maximum=None, minimum=None): return ret if maximum: if cap > float(maximum): - ret["comment"] = "Load avg above maximum of {} at {}".format(maximum, cap) + ret["comment"] = f"Load avg above maximum of {maximum} at {cap}" return ret ret["comment"] = "Load avg in acceptable range" ret["result"] = True @@ -69,9 +69,9 @@ def process(name): data = __salt__["status.pid"](name) if not data: ret["result"] = False - ret["comment"] += 'Process signature "{}" not found '.format(name) + ret["comment"] += f'Process signature "{name}" not found ' return ret ret["data"] = data - ret["comment"] += 'Process signature "{}" was found '.format(name) + ret["comment"] += f'Process signature "{name}" was found ' ret["result"] = True return ret diff --git a/salt/states/statuspage.py b/salt/states/statuspage.py index e8961aceca8..7d478ae82c9 100644 --- a/salt/states/statuspage.py +++ b/salt/states/statuspage.py @@ -207,7 +207,7 @@ def create( page_id=None, api_key=None, api_version=None, - **kwargs + **kwargs, ): """ Insert a new entry under a specific endpoint. @@ -259,14 +259,14 @@ def create( page_id=page_id, api_key=api_key, api_version=api_version, - **kwargs + **kwargs, ) if not sp_create.get("result"): ret["comment"] = "Unable to create {endpoint}: {msg}".format( endpoint=endpoint_sg, msg=sp_create.get("comment") ) else: - ret["comment"] = "{endpoint} created!".format(endpoint=endpoint_sg) + ret["comment"] = f"{endpoint_sg} created!" ret["result"] = True ret["changes"] = sp_create.get("out") @@ -279,7 +279,7 @@ def update( page_id=None, api_key=None, api_version=None, - **kwargs + **kwargs, ): """ Update attribute(s) of a specific endpoint. @@ -337,14 +337,14 @@ def update( page_id=page_id, api_key=api_key, api_version=api_version, - **kwargs + **kwargs, ) if not sp_update.get("result"): ret["comment"] = "Unable to update {endpoint} #{id}: {msg}".format( endpoint=endpoint_sg, id=id, msg=sp_update.get("comment") ) else: - ret["comment"] = "{endpoint} #{id} updated!".format(endpoint=endpoint_sg, id=id) + ret["comment"] = f"{endpoint_sg} #{id} updated!" ret["result"] = True ret["changes"] = sp_update.get("out") @@ -411,7 +411,7 @@ def delete( endpoint=endpoint_sg, id=id, msg=sp_delete.get("comment") ) else: - ret["comment"] = "{endpoint} #{id} deleted!".format(endpoint=endpoint_sg, id=id) + ret["comment"] = f"{endpoint_sg} #{id} deleted!" ret["result"] = True @@ -544,7 +544,7 @@ def managed( page_id=page_id, api_key=api_key, api_version=api_version, - **new_endpoint + **new_endpoint, ) if not adding.get("result"): ret.update({"comment": adding.get("comment")}) @@ -563,7 +563,7 @@ def managed( page_id=page_id, api_key=api_key, api_version=api_version, - **update_endpoint + **update_endpoint, ) if not updating.get("result"): ret.update({"comment": updating.get("comment")}) diff --git a/salt/states/supervisord.py b/salt/states/supervisord.py index 68ec8717ad6..4b0c7bbf23c 100644 --- a/salt/states/supervisord.py +++ b/salt/states/supervisord.py @@ -116,7 +116,7 @@ def running( # Process group if len(to_start) == len(matches): ret["comment"] = ( - "All services in group '{}' will be started".format(name) + f"All services in group '{name}' will be started" ) else: ret["comment"] = ( @@ -126,23 +126,23 @@ def running( ) else: # Single program - ret["comment"] = "Service {} will be started".format(name) + ret["comment"] = f"Service {name} will be started" else: if name.endswith(":"): # Process group ret["comment"] = ( - "All services in group '{}' are already running".format(name) + f"All services in group '{name}' are already running" ) else: - ret["comment"] = "Service {} is already running".format(name) + ret["comment"] = f"Service {name} is already running" else: ret["result"] = None # Process/group needs to be added if name.endswith(":"): - _type = "Group '{}'".format(name) + _type = f"Group '{name}'" else: - _type = "Service {}".format(name) - ret["comment"] = "{} will be added and started".format(_type) + _type = f"Service {name}" + ret["comment"] = f"{_type} will be added and started" return ret changes = [] @@ -162,11 +162,11 @@ def running( ret.update(_check_error(result, comment)) log.debug(comment) - if "{}: updated".format(name) in result: + if f"{name}: updated" in result: just_updated = True elif to_add: # Not sure if this condition is precise enough. - comment = "Adding service: {}".format(name) + comment = f"Adding service: {name}" __salt__["supervisord.reread"](user=user, conf_file=conf_file, bin_env=bin_env) # Causes supervisorctl to throw `ERROR: process group already active` # if process group exists. At this moment, I'm not sure how to handle @@ -205,7 +205,7 @@ def running( if is_stopped is False: if restart and not just_updated: comment = "Restarting{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) log.debug(comment) result = __salt__["supervisord.restart"]( @@ -215,20 +215,20 @@ def running( changes.append(comment) elif just_updated: comment = "Not starting updated{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) result = comment ret.update({"comment": comment}) else: comment = "Not starting already running{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) result = comment ret.update({"comment": comment}) elif not just_updated: comment = "Starting{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) changes.append(comment) log.debug(comment) @@ -268,9 +268,9 @@ def dead(name, user=None, conf_file=None, bin_env=None, **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} is set to be stopped".format(name) + ret["comment"] = f"Service {name} is set to be stopped" else: - comment = "Stopping service: {}".format(name) + comment = f"Stopping service: {name}" log.debug(comment) all_processes = __salt__["supervisord.status"]( @@ -303,11 +303,11 @@ def dead(name, user=None, conf_file=None, bin_env=None, **kwargs): is_stopped = False else: # process name doesn't exist - ret["comment"] = "Service {} doesn't exist".format(name) + ret["comment"] = f"Service {name} doesn't exist" return ret if is_stopped is True: - ret["comment"] = "Service {} is not running".format(name) + ret["comment"] = f"Service {name} is not running" else: result = { name: __salt__["supervisord.stop"]( diff --git a/salt/states/svn.py b/salt/states/svn.py index c041d4f27a6..aac0dca9fa9 100644 --- a/salt/states/svn.py +++ b/salt/states/svn.py @@ -101,7 +101,7 @@ def latest( opts = tuple() if os.path.exists(target) and not os.path.isdir(target): - return _fail(ret, 'The path "{}" exists and is not a directory.'.format(target)) + return _fail(ret, f'The path "{target}" exists and is not a directory.') if __opts__["test"]: if rev: @@ -123,11 +123,11 @@ def latest( ) svn_cmd = "svn.diff" except exceptions.CommandExecutionError: - return _fail(ret, "{} exists but is not a svn working copy.".format(target)) + return _fail(ret, f"{target} exists but is not a svn working copy.") current_rev = current_info[0]["Revision"] - opts += ("-r", "{}:{}".format(current_rev, new_rev)) + opts += ("-r", f"{current_rev}:{new_rev}") if trust: opts += ("--trust-server-cert",) @@ -173,7 +173,7 @@ def latest( fmt="dict", )[0]["Revision"] if current_rev != new_rev: - ret["changes"]["revision"] = "{} => {}".format(current_rev, new_rev) + ret["changes"]["revision"] = f"{current_rev} => {new_rev}" else: out = __salt__[svn_cmd](cwd, name, basename, user, username, password, *opts) @@ -260,11 +260,11 @@ def export( opts = () if not overwrite and os.path.exists(target) and not os.path.isdir(target): - return _fail(ret, 'The path "{}" exists and is not a directory.'.format(target)) + return _fail(ret, f'The path "{target}" exists and is not a directory.') if __opts__["test"]: if not os.path.exists(target): return _neutral_test( - ret, "{} doesn't exist and is set to be checked out.".format(target) + ret, f"{target} doesn't exist and is set to be checked out." ) svn_cmd = "svn.list" rev = "HEAD" @@ -288,7 +288,7 @@ def export( out = __salt__[svn_cmd](cwd, name, basename, user, username, password, rev, *opts) ret["changes"]["new"] = name - ret["changes"]["comment"] = "{} was Exported to {}".format(name, target) + ret["changes"]["comment"] = f"{name} was Exported to {target}" ret["comment"] = out return ret diff --git a/salt/states/sysctl.py b/salt/states/sysctl.py index 4498e672758..a417512bd1f 100644 --- a/salt/states/sysctl.py +++ b/salt/states/sysctl.py @@ -98,20 +98,20 @@ def present(name, value, config=None): return ret # otherwise, we don't have it set anywhere and need to set it ret["result"] = None - ret["comment"] = "Sysctl option {} would be changed to {}".format(name, value) + ret["comment"] = f"Sysctl option {name} would be changed to {value}" return ret try: update = __salt__["sysctl.persist"](name, value, config) except CommandExecutionError as exc: ret["result"] = False - ret["comment"] = "Failed to set {} to {}: {}".format(name, value, exc) + ret["comment"] = f"Failed to set {name} to {value}: {exc}" return ret if update == "Updated": ret["changes"] = {name: value} - ret["comment"] = "Updated sysctl value {} = {}".format(name, value) + ret["comment"] = f"Updated sysctl value {name} = {value}" elif update == "Already set": - ret["comment"] = "Sysctl value {} = {} is already set".format(name, value) + ret["comment"] = f"Sysctl value {name} = {value} is already set" return ret diff --git a/salt/states/sysfs.py b/salt/states/sysfs.py index afcaf609fbe..e63c6499bc9 100644 --- a/salt/states/sysfs.py +++ b/salt/states/sysfs.py @@ -41,33 +41,33 @@ def present(name, value, config=None): current = __salt__["sysfs.read"](name) if current is False: ret["result"] = False - ret["comment"] = "SysFS attribute {} doesn't exist.".format(name) + ret["comment"] = f"SysFS attribute {name} doesn't exist." else: # if the return is a dict, the "name" is an object not an attribute if isinstance(current, dict): ret["result"] = False - ret["comment"] = "{} is not a SysFS attribute.".format(name) + ret["comment"] = f"{name} is not a SysFS attribute." else: # some attribute files lists all available options and the selected one between [] if isinstance(current, str): current = re.sub(r"(.*\[|\].*)", "", current) if value == current: ret["result"] = True - ret["comment"] = "SysFS attribute {} is already set.".format(name) + ret["comment"] = f"SysFS attribute {name} is already set." else: ret["result"] = None if ret["result"] is None: if __opts__["test"]: - ret["comment"] = "SysFS attribute {} set to be changed.".format(name) + ret["comment"] = f"SysFS attribute {name} set to be changed." else: update = __salt__["sysfs.write"](name, value) if not update: ret["result"] = False - ret["comment"] = "Failed to set {} to {}".format(name, value) + ret["comment"] = f"Failed to set {name} to {value}" else: ret["result"] = True ret["changes"] = {name: value} - ret["comment"] = "Updated SysFS attribute {} to {}".format(name, value) + ret["comment"] = f"Updated SysFS attribute {name} to {value}" return ret diff --git a/salt/states/sysrc.py b/salt/states/sysrc.py index 2a620b4cc93..4c7b0d2a57f 100644 --- a/salt/states/sysrc.py +++ b/salt/states/sysrc.py @@ -47,11 +47,11 @@ def managed(name, value, **kwargs): for rcname, rcdict in current_state.items(): if rcdict[name] == value: ret["result"] = True - ret["comment"] = "{} is already set to the desired value.".format(name) + ret["comment"] = f"{name} is already set to the desired value." return ret if __opts__["test"] is True: - ret["comment"] = 'The value of "{}" will be changed!'.format(name) + ret["comment"] = f'The value of "{name}" will be changed!' ret["changes"] = { "old": current_state, "new": name + " = " + value + " will be set.", @@ -64,7 +64,7 @@ def managed(name, value, **kwargs): new_state = __salt__["sysrc.set"](name=name, value=value, **kwargs) - ret["comment"] = 'The value of "{}" was changed!'.format(name) + ret["comment"] = f'The value of "{name}" was changed!' ret["changes"] = {"old": current_state, "new": new_state} @@ -91,14 +91,14 @@ def absent(name, **kwargs): current_state = __salt__["sysrc.get"](name=name, **kwargs) if current_state is None: ret["result"] = True - ret["comment"] = '"{}" is already absent.'.format(name) + ret["comment"] = f'"{name}" is already absent.' return ret if __opts__["test"] is True: - ret["comment"] = '"{}" will be removed!'.format(name) + ret["comment"] = f'"{name}" will be removed!' ret["changes"] = { "old": current_state, - "new": '"{}" will be removed.'.format(name), + "new": f'"{name}" will be removed.', } # When test=true return none @@ -108,7 +108,7 @@ def absent(name, **kwargs): new_state = __salt__["sysrc.remove"](name=name, **kwargs) - ret["comment"] = '"{}" was removed!'.format(name) + ret["comment"] = f'"{name}" was removed!' ret["changes"] = {"old": current_state, "new": new_state} diff --git a/salt/states/telemetry_alert.py b/salt/states/telemetry_alert.py index eb94cb86b3e..18ec2bc40ed 100644 --- a/salt/states/telemetry_alert.py +++ b/salt/states/telemetry_alert.py @@ -96,7 +96,7 @@ def present( # del saved_alert_config["_id"] for k, v in post_body.items(): if k not in saved_alert_config: - difference.append("{}={} (new)".format(k, v)) + difference.append(f"{k}={v} (new)") continue v2 = saved_alert_config[k] @@ -108,7 +108,7 @@ def present( continue if isinstance(v, int) and v == int(v2): continue - difference.append("{}='{}' was: '{}'".format(k, v, v2)) + difference.append(f"{k}='{v}' was: '{v2}'") else: difference.append("new alert config") @@ -122,10 +122,10 @@ def present( if saved_alert_config: # alert config is present. update, or do nothing # check to see if attributes matches is_present. If so, do nothing. if len(difference) == 0: - ret["comment"] = "alert config {} present and matching".format(metric_name) + ret["comment"] = f"alert config {metric_name} present and matching" return ret if __opts__["test"]: - msg = "alert config {} is to be updated.".format(metric_name) + msg = f"alert config {metric_name} is to be updated." ret["comment"] = msg ret["result"] = "\n".join(difference) return ret @@ -142,7 +142,7 @@ def present( ) else: # alert config is absent. create it. if __opts__["test"]: - msg = "alert config {} is to be created.".format(metric_name) + msg = f"alert config {metric_name} is to be created." ret["comment"] = msg ret["result"] = None return ret diff --git a/salt/states/test.py b/salt/states/test.py index 18af36920bf..a09f6a2d28f 100644 --- a/salt/states/test.py +++ b/salt/states/test.py @@ -460,17 +460,17 @@ def check_pillar( fine[key] = key_type for key, key_type in failed.items(): - comment = 'Pillar key "{}" '.format(key) + comment = f'Pillar key "{key}" ' if key_type is None: comment += "is missing.\n" else: - comment += "is not {}.\n".format(key_type) + comment += f"is not {key_type}.\n" ret["comment"] += comment if verbose and fine: comment = "Those keys passed the check:\n" for key, key_type in fine.items(): - comment += "- {} ({})\n".format(key, key_type) + comment += f"- {key} ({key_type})\n" ret["comment"] += comment return ret diff --git a/salt/states/testinframod.py b/salt/states/testinframod.py index 493fc8ef2eb..d0107ae79d9 100644 --- a/salt/states/testinframod.py +++ b/salt/states/testinframod.py @@ -40,7 +40,7 @@ def _generate_functions(): modules_ = [module_ for module_ in modules.modules] for module_name in modules_: - func_name = "testinfra.{}".format(module_name) + func_name = f"testinfra.{module_name}" __all__.append(module_name) log.debug( "Generating state for module %s as function %s", module_name, func_name diff --git a/salt/states/timezone.py b/salt/states/timezone.py index 558cd1d6486..208d18e5f0b 100644 --- a/salt/states/timezone.py +++ b/salt/states/timezone.py @@ -73,7 +73,7 @@ def system(name, utc=True): # Check the time zone if compzone is True: ret["result"] = True - messages.append("Timezone {} already set".format(name)) + messages.append(f"Timezone {name} already set") else: do_zone = True @@ -82,7 +82,7 @@ def system(name, utc=True): ret["result"] = None do_utc = True elif utc and utc == myutc: - messages.append("UTC already set to {}".format(name)) + messages.append(f"UTC already set to {name}") if ret["result"] is True: ret["comment"] = ", ".join(messages) @@ -91,9 +91,9 @@ def system(name, utc=True): if __opts__["test"]: messages = [] if compzone is False: - messages.append("Timezone {} needs to be set".format(name)) + messages.append(f"Timezone {name} needs to be set") if utc and myutc != utc: - messages.append("UTC needs to be set to {}".format(utc)) + messages.append(f"UTC needs to be set to {utc}") ret["comment"] = ", ".join(messages) return ret @@ -102,7 +102,7 @@ def system(name, utc=True): if do_zone: if __salt__["timezone.set_zone"](name): ret["changes"]["timezone"] = name - messages.append("Set timezone {}".format(name)) + messages.append(f"Set timezone {name}") ret["result"] = True else: messages.append("Failed to set timezone") @@ -114,10 +114,10 @@ def system(name, utc=True): clock = "UTC" if __salt__["timezone.set_hwclock"](clock): ret["changes"]["utc"] = utc - messages.append("Set UTC to {}".format(utc)) + messages.append(f"Set UTC to {utc}") ret["result"] = True else: - messages.append("Failed to set UTC to {}".format(utc)) + messages.append(f"Failed to set UTC to {utc}") ret["result"] = False ret["comment"] = ", ".join(messages) diff --git a/salt/states/tls.py b/salt/states/tls.py index 9881505d124..9c0fc451711 100644 --- a/salt/states/tls.py +++ b/salt/states/tls.py @@ -30,7 +30,7 @@ def valid_certificate(name, weeks=0, days=0, hours=0, minutes=0, seconds=0): try: cert_info = __salt__["tls.cert_info"](name) except OSError as exc: - ret["comment"] = "{}".format(exc) + ret["comment"] = f"{exc}" ret["result"] = False log.error(ret["comment"]) return ret @@ -62,5 +62,5 @@ def valid_certificate(name, weeks=0, days=0, hours=0, minutes=0, seconds=0): return ret ret["result"] = True - ret["comment"] = "Certificate is valid for {}".format(delta_remaining) + ret["comment"] = f"Certificate is valid for {delta_remaining}" return ret diff --git a/salt/states/tomcat.py b/salt/states/tomcat.py index d4511911fd4..5b74573c143 100644 --- a/salt/states/tomcat.py +++ b/salt/states/tomcat.py @@ -142,7 +142,7 @@ def war_deployed( status = True # Gathered/specified new WAR version string - specified_ver = "version {}".format(version) if version else "no version" + specified_ver = f"version {version}" if version else "no version" # Determine what to do try: @@ -172,13 +172,13 @@ def war_deployed( name, specified_ver ) if webapps[name]["mode"] != "running": - ret["changes"]["start"] = "starting {}".format(name) + ret["changes"]["start"] = f"starting {name}" status = False else: return ret except Exception: # pylint: disable=broad-except deploy = True - ret["changes"]["deploy"] = "deployed {} with {}".format(name, specified_ver) + ret["changes"]["deploy"] = f"deployed {name} with {specified_ver}" # Test if __opts__["test"]: @@ -216,7 +216,7 @@ def war_deployed( if deploy_res.startswith("OK"): ret["result"] = True ret["comment"] = str(__salt__["tomcat.ls"](url, timeout)[name]) - ret["changes"]["deploy"] = "deployed {} with {}".format(name, specified_ver) + ret["changes"]["deploy"] = f"deployed {name} with {specified_ver}" else: ret["result"] = False ret["comment"] = deploy_res diff --git a/salt/states/trafficserver.py b/salt/states/trafficserver.py index c491f176bac..55edcd35836 100644 --- a/salt/states/trafficserver.py +++ b/salt/states/trafficserver.py @@ -209,7 +209,7 @@ def config(name, value): __salt__["trafficserver.set_config"](name, value) ret["result"] = True - ret["comment"] = "Configured {} to {}".format(name, value) + ret["comment"] = f"Configured {name} to {value}" return ret @@ -345,11 +345,11 @@ def offline(name, path): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __opts__["test"]: - ret["comment"] = "Setting {} to offline".format(path) + ret["comment"] = f"Setting {path} to offline" return ret __salt__["trafficserver.offline"](path) ret["result"] = True - ret["comment"] = "Set {} as offline".format(path) + ret["comment"] = f"Set {path} as offline" return ret diff --git a/salt/states/tuned.py b/salt/states/tuned.py index 91759ddb76f..fb5bd832771 100644 --- a/salt/states/tuned.py +++ b/salt/states/tuned.py @@ -51,10 +51,10 @@ def profile(name): # test mode if __opts__["test"] is True: - ret["comment"] = 'The state of "{}" will be changed.'.format(current_state) + ret["comment"] = f'The state of "{current_state}" will be changed.' ret["changes"] = { "old": current_state, - "new": "Profile will be set to {}".format(profile), + "new": f"Profile will be set to {profile}", } # return None when testing @@ -66,7 +66,7 @@ def profile(name): new_state = __salt__["tuned.profile"](profile) # create the comment data structure - ret["comment"] = 'The state of "{}" was changed!'.format(profile) + ret["comment"] = f'The state of "{profile}" was changed!' # fill in the ret data structure ret["changes"] = { @@ -108,7 +108,7 @@ def off(name=None): # test mode if __opts__["test"] is True: - ret["comment"] = 'The state of "{}" will be changed.'.format(current_state) + ret["comment"] = f'The state of "{current_state}" will be changed.' ret["changes"] = { "old": current_state, "new": "Profile will be set to off", diff --git a/salt/states/uptime.py b/salt/states/uptime.py index 590d1017066..5c284eeb2f1 100644 --- a/salt/states/uptime.py +++ b/salt/states/uptime.py @@ -53,7 +53,7 @@ def monitored(name, **params): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["uptime.check_exists"](name=name): ret["result"] = True - ret["comment"] = "URL {} is already monitored".format(name) + ret["comment"] = f"URL {name} is already monitored" ret["changes"] = {} return ret if not __opts__["test"]: @@ -65,7 +65,7 @@ def monitored(name, **params): ret["changes"] = {"url_monitored": url_monitored} else: ret["result"] = False - ret["comment"] = "Failed to add {} to uptime".format(name) + ret["comment"] = f"Failed to add {name} to uptime" ret["changes"] = {} else: msg = "URL {0} is going to be added to uptime" diff --git a/salt/states/user.py b/salt/states/user.py index 83693a809ac..5b968025772 100644 --- a/salt/states/user.py +++ b/salt/states/user.py @@ -577,14 +577,14 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {} is present and up to date".format(name), + "comment": f"User {name} is present and up to date", } # the comma is used to separate field in GECOS, thus resulting into # salt adding the end of fullname each time this function is called for gecos_field in [fullname, roomnumber, workphone]: if isinstance(gecos_field, str) and "," in gecos_field: - ret["comment"] = "Unsupported char ',' in {}".format(gecos_field) + ret["comment"] = f"Unsupported char ',' in {gecos_field}" ret["result"] = False return ret @@ -676,7 +676,7 @@ def present( val = "XXX-REDACTED-XXX" elif key == "group" and not remove_groups: key = "ensure groups" - ret["comment"] += "{}: {}\n".format(key, val) + ret["comment"] += f"{key}: {val}\n" return ret # The user is present if "shadow.info" in __salt__: @@ -774,11 +774,9 @@ def present( # NOTE: list(changes) required here to avoid modifying dictionary # during iteration. for key in [ - x - for x in list(changes) - if x != "groups" and "user.ch{}".format(x) in __salt__ + x for x in list(changes) if x != "groups" and f"user.ch{x}" in __salt__ ]: - __salt__["user.ch{}".format(key)](name, changes.pop(key)) + __salt__[f"user.ch{key}"](name, changes.pop(key)) # Do group changes last if "groups" in changes: @@ -809,7 +807,7 @@ def present( if __grains__["kernel"] in ("OpenBSD", "FreeBSD") and lcpost != lcpre: ret["changes"]["loginclass"] = lcpost if ret["changes"]: - ret["comment"] = "Updated user {}".format(name) + ret["comment"] = f"Updated user {name}" changes = _changes( name, uid, @@ -849,7 +847,7 @@ def present( # first time we ran _changes(). if changes: - ret["comment"] = "These values could not be changed: {}".format(changes) + ret["comment"] = f"These values could not be changed: {changes}" ret["result"] = False return ret @@ -857,7 +855,7 @@ def present( # The user is not present, make it! if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} set to be added".format(name) + ret["comment"] = f"User {name} set to be added" return ret if groups and present_optgroups: groups.extend(present_optgroups) @@ -900,7 +898,7 @@ def present( } result = __salt__["user.add"](**params) if result is True: - ret["comment"] = "New user {} created".format(name) + ret["comment"] = f"New user {name} created" ret["changes"] = __salt__["user.info"](name) if not createhome: # pwd incorrectly reports presence of home @@ -926,7 +924,7 @@ def present( spost = __salt__["shadow.info"](name) if spost["passwd"] != "": ret["comment"] = ( - "User {} created but failed to empty password".format(name) + f"User {name} created but failed to empty password" ) ret["result"] = False ret["changes"]["password"] = "" @@ -1034,7 +1032,7 @@ def present( if isinstance(result, str): ret["comment"] = result else: - ret["comment"] = "Failed to create new user {}".format(name) + ret["comment"] = f"Failed to create new user {name}" ret["result"] = False return ret @@ -1062,7 +1060,7 @@ def absent(name, purge=False, force=False): # The user is present, make it not present if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} set for removal".format(name) + ret["comment"] = f"User {name} set for removal" return ret beforegroups = set(salt.utils.user.get_group_list(name)) ret["result"] = __salt__["user.delete"](name, purge, force) @@ -1070,14 +1068,14 @@ def absent(name, purge=False, force=False): if ret["result"]: ret["changes"] = {} for g in beforegroups - aftergroups: - ret["changes"]["{} group".format(g)] = "removed" + ret["changes"][f"{g} group"] = "removed" ret["changes"][name] = "removed" - ret["comment"] = "Removed user {}".format(name) + ret["comment"] = f"Removed user {name}" else: ret["result"] = False - ret["comment"] = "Failed to remove user {}".format(name) + ret["comment"] = f"Failed to remove user {name}" return ret - ret["comment"] = "User {} is not present".format(name) + ret["comment"] = f"User {name} is not present" return ret diff --git a/salt/states/vagrant.py b/salt/states/vagrant.py index 4210715f92e..93650d54de0 100644 --- a/salt/states/vagrant.py +++ b/salt/states/vagrant.py @@ -103,7 +103,7 @@ def _vagrant_call(node, function, section, comment, status_when_done=None, **kwa except (IndexError, SaltInvocationError, CommandExecutionError): pass try: - response = __salt__["vagrant.{}".format(function)](node, **kwargs) + response = __salt__[f"vagrant.{function}"](node, **kwargs) if isinstance(response, dict): response = response["name"] changed_nodes.append({"node": node, function: response}) @@ -170,7 +170,7 @@ def running(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "{} is already running".format(name), + "comment": f"{name} is already running", } try: @@ -178,14 +178,14 @@ def running(name, **kwargs): if info[0]["state"] != "running": __salt__["vagrant.start"](name) ret["changes"][name] = "Machine started" - ret["comment"] = "Node {} started".format(name) + ret["comment"] = f"Node {name} started" except (SaltInvocationError, CommandExecutionError): # there was no viable existing machine to start ret, kwargs = _find_init_change(name, ret, **kwargs) kwargs["start"] = True __salt__["vagrant.init"](name, **kwargs) ret["changes"][name] = "Node defined and started" - ret["comment"] = "Node {} defined and started".format(name) + ret["comment"] = f"Node {name} defined and started" return ret @@ -272,7 +272,7 @@ def initialized(name, **kwargs): kwargs["start"] = False __salt__["vagrant.init"](name, **kwargs) ret["changes"][name] = "Node initialized" - ret["comment"] = "Node {} defined but not started.".format(name) + ret["comment"] = f"Node {name} defined but not started." return ret diff --git a/salt/states/vault.py b/salt/states/vault.py index 54de5b8f435..7239d20897d 100644 --- a/salt/states/vault.py +++ b/salt/states/vault.py @@ -41,7 +41,7 @@ def policy_present(name, rules): } """ - url = "v1/sys/policy/{}".format(name) + url = f"v1/sys/policy/{name}" response = __utils__["vault.make_request"]("GET", url) try: if response.status_code == 200: @@ -55,7 +55,7 @@ def policy_present(name, rules): "name": name, "changes": {}, "result": False, - "comment": "Failed to get policy: {}".format(e), + "comment": f"Failed to get policy: {e}", } @@ -69,14 +69,14 @@ def _create_new_policy(name, rules): } payload = {"rules": rules} - url = "v1/sys/policy/{}".format(name) + url = f"v1/sys/policy/{name}" response = __utils__["vault.make_request"]("PUT", url, json=payload) if response.status_code not in [200, 204]: return { "name": name, "changes": {}, "result": False, - "comment": "Failed to create policy: {}".format(response.reason), + "comment": f"Failed to create policy: {response.reason}", } return { @@ -108,14 +108,14 @@ def _handle_existing_policy(name, new_rules, existing_rules): payload = {"rules": new_rules} - url = "v1/sys/policy/{}".format(name) + url = f"v1/sys/policy/{name}" response = __utils__["vault.make_request"]("PUT", url, json=payload) if response.status_code not in [200, 204]: return { "name": name, "changes": {}, "result": False, - "comment": "Failed to change policy: {}".format(response.reason), + "comment": f"Failed to change policy: {response.reason}", } ret["result"] = True diff --git a/salt/states/victorops.py b/salt/states/victorops.py index 54cf5353a2c..f89265fe2cb 100644 --- a/salt/states/victorops.py +++ b/salt/states/victorops.py @@ -93,7 +93,7 @@ def create_event(name, message_type, routing_key="everyone", **kwargs): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __opts__["test"]: - ret["comment"] = "Need to create event: {}".format(name) + ret["comment"] = f"Need to create event: {name}" return ret res = __salt__["victorops.create_event"]( diff --git a/salt/states/virt.py b/salt/states/virt.py index 2565be0af4a..33f35b0d8c8 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -94,7 +94,7 @@ def keys(name, basepath="/etc/pki", **kwargs): # overriding anything existing pillar_kwargs = {} for key, value in kwargs.items(): - pillar_kwargs["ext_pillar_virt.{}".format(key)] = value + pillar_kwargs[f"ext_pillar_virt.{key}"] = value pillar = __salt__["pillar.ext"]({"libvirt": "_"}, pillar_kwargs) paths = { @@ -106,7 +106,7 @@ def keys(name, basepath="/etc/pki", **kwargs): } for key in paths: - p_key = "libvirt.{}.pem".format(key) + p_key = f"libvirt.{key}.pem" if p_key not in pillar: continue if not os.path.exists(os.path.dirname(paths[key])): @@ -127,9 +127,7 @@ def keys(name, basepath="/etc/pki", **kwargs): else: for key in ret["changes"]: with salt.utils.files.fopen(paths[key], "w+") as fp_: - fp_.write( - salt.utils.stringutils.to_str(pillar["libvirt.{}.pem".format(key)]) - ) + fp_.write(salt.utils.stringutils.to_str(pillar[f"libvirt.{key}.pem"])) ret["comment"] = "Updated libvirt certs and keys" @@ -145,7 +143,7 @@ def _virt_call( connection=None, username=None, password=None, - **kwargs + **kwargs, ): """ Helper to call the virt functions. Wildcards supported. @@ -173,12 +171,12 @@ def _virt_call( if action_needed: response = True if not __opts__["test"]: - response = __salt__["virt.{}".format(function)]( + response = __salt__[f"virt.{function}"]( targeted_domain, connection=connection, username=username, password=password, - **kwargs + **kwargs, ) if isinstance(response, dict): response = response["name"] @@ -676,14 +674,12 @@ def defined( ret["changes"][name] = status if not status.get("definition"): ret["changes"] = {} - ret["comment"] = "Domain {} unchanged".format(name) + ret["comment"] = f"Domain {name} unchanged" ret["result"] = True elif status.get("errors"): - ret["comment"] = ( - "Domain {} updated with live update(s) failures".format(name) - ) + ret["comment"] = f"Domain {name} updated with live update(s) failures" else: - ret["comment"] = "Domain {} updated".format(name) + ret["comment"] = f"Domain {name} updated" else: if not __opts__["test"]: __salt__["virt.init"]( @@ -717,7 +713,7 @@ def defined( host_devices=host_devices, ) ret["changes"][name] = {"definition": True} - ret["comment"] = "Domain {} defined".format(name) + ret["comment"] = f"Domain {name} defined" except libvirt.libvirtError as err: # Something bad happened when defining / updating the VM, report it ret["comment"] = str(err) @@ -1049,7 +1045,7 @@ def running( username=username, password=password, ) - comment = "Domain {} started".format(name) + comment = f"Domain {name} started" if not ret["comment"].endswith("unchanged"): comment = "{} and started".format(ret["comment"]) ret["comment"] = comment @@ -1057,7 +1053,7 @@ def running( ret["changes"][name] = {} ret["changes"][name]["started"] = True elif not changed: - ret["comment"] = "Domain {} exists and is running".format(name) + ret["comment"] = f"Domain {name} exists and is running" except libvirt.libvirtError as err: # Something bad happened when starting / updating the VM, report it @@ -1206,7 +1202,7 @@ def reverted( try: domains = fnmatch.filter(__salt__["virt.list_domains"](), name) if not domains: - ret["comment"] = 'No domains found for criteria "{}"'.format(name) + ret["comment"] = f'No domains found for criteria "{name}"' else: ignored_domains = list() if len(domains) > 1: @@ -1515,10 +1511,10 @@ def network_defined( password=password, ) action = ", autostart flag changed" if needs_autostart else "" - ret["changes"][name] = "Network updated{}".format(action) - ret["comment"] = "Network {} updated{}".format(name, action) + ret["changes"][name] = f"Network updated{action}" + ret["comment"] = f"Network {name} updated{action}" else: - ret["comment"] = "Network {} unchanged".format(name) + ret["comment"] = f"Network {name} unchanged" ret["result"] = True else: needs_autostart = autostart @@ -1546,10 +1542,10 @@ def network_defined( ) if needs_autostart: ret["changes"][name] = "Network defined, marked for autostart" - ret["comment"] = "Network {} defined, marked for autostart".format(name) + ret["comment"] = f"Network {name} defined, marked for autostart" else: ret["changes"][name] = "Network defined" - ret["comment"] = "Network {} defined".format(name) + ret["comment"] = f"Network {name} defined" if needs_autostart: if not __opts__["test"]: @@ -1974,15 +1970,13 @@ def pool_defined( action = ", built" action = ( - "{}, autostart flag changed".format(action) - if needs_autostart - else action + f"{action}, autostart flag changed" if needs_autostart else action ) - ret["changes"][name] = "Pool updated{}".format(action) - ret["comment"] = "Pool {} updated{}".format(name, action) + ret["changes"][name] = f"Pool updated{action}" + ret["comment"] = f"Pool {name} updated{action}" else: - ret["comment"] = "Pool {} unchanged".format(name) + ret["comment"] = f"Pool {name} unchanged" ret["result"] = True else: needs_autostart = autostart @@ -2025,10 +2019,10 @@ def pool_defined( ) if needs_autostart: ret["changes"][name] = "Pool defined, marked for autostart" - ret["comment"] = "Pool {} defined, marked for autostart".format(name) + ret["comment"] = f"Pool {name} defined, marked for autostart" else: ret["changes"][name] = "Pool defined" - ret["comment"] = "Pool {} defined".format(name) + ret["comment"] = f"Pool {name} defined" if needs_autostart: if not __opts__["test"]: @@ -2146,7 +2140,7 @@ def pool_running( username=username, password=password, ) - action = "built, {}".format(action) + action = f"built, {action}" else: action = "already running" result = True @@ -2160,16 +2154,16 @@ def pool_running( password=password, ) - comment = "Pool {}".format(name) + comment = f"Pool {name}" change = "Pool" if name in ret["changes"]: comment = "{},".format(ret["comment"]) change = "{},".format(ret["changes"][name]) if action != "already running": - ret["changes"][name] = "{} {}".format(change, action) + ret["changes"][name] = f"{change} {action}" - ret["comment"] = "{} {}".format(comment, action) + ret["comment"] = f"{comment} {action}" ret["result"] = result except libvirt.libvirtError as err: @@ -2301,9 +2295,9 @@ def pool_deleted(name, purge=False, connection=None, username=None, password=Non info[name]["type"], ", ".join(unsupported) ) else: - ret["comment"] = "Storage pool could not be found: {}".format(name) + ret["comment"] = f"Storage pool could not be found: {name}" except libvirt.libvirtError as err: - ret["comment"] = "Failed deleting pool: {}".format(err.get_error_message()) + ret["comment"] = f"Failed deleting pool: {err.get_error_message()}" ret["result"] = False return ret @@ -2389,7 +2383,7 @@ def volume_defined( connection=connection, username=username, password=password ) if pool not in pools: - raise SaltInvocationError("Storage pool {} not existing".format(pool)) + raise SaltInvocationError(f"Storage pool {pool} not existing") vol_infos = ( __salt__["virt.volume_infos"]( @@ -2449,7 +2443,7 @@ def volume_defined( ret["comment"] = "Volume {} {}defined in pool {}".format( name, test_comment, pool ) - ret["changes"] = {"{}/{}".format(pool, name): {"old": "", "new": "defined"}} + ret["changes"] = {f"{pool}/{name}": {"old": "", "new": "defined"}} except libvirt.libvirtError as err: ret["comment"] = err.get_error_message() ret["result"] = False diff --git a/salt/states/virtualenv_mod.py b/salt/states/virtualenv_mod.py index 729e16a8e28..957f44265bc 100644 --- a/salt/states/virtualenv_mod.py +++ b/salt/states/virtualenv_mod.py @@ -57,7 +57,7 @@ def managed( pip_cache_dir=None, process_dependency_links=False, no_binary=None, - **kwargs + **kwargs, ): """ Create a virtualenv and optionally manage it with pip @@ -171,21 +171,19 @@ def managed( # If it already exists, grab the version for posterity if venv_exists and clear: ret["changes"]["cleared_packages"] = __salt__["pip.freeze"](bin_env=name) - ret["changes"]["old"] = __salt__["cmd.run_stderr"]( - "{} -V".format(venv_py) - ).strip("\n") + ret["changes"]["old"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n") # Create (or clear) the virtualenv if __opts__["test"]: if venv_exists and clear: ret["result"] = None - ret["comment"] = "Virtualenv {} is set to be cleared".format(name) + ret["comment"] = f"Virtualenv {name} is set to be cleared" return ret if venv_exists and not clear: - ret["comment"] = "Virtualenv {} is already created".format(name) + ret["comment"] = f"Virtualenv {name} is already created" return ret ret["result"] = None - ret["comment"] = "Virtualenv {} is set to be created".format(name) + ret["comment"] = f"Virtualenv {name} is set to be created" return ret if not venv_exists or (venv_exists and clear): @@ -202,11 +200,11 @@ def managed( prompt=prompt, user=user, use_vt=use_vt, - **kwargs + **kwargs, ) except CommandNotFoundError as err: ret["result"] = False - ret["comment"] = "Failed to create virtualenv: {}".format(err) + ret["comment"] = f"Failed to create virtualenv: {err}" return ret if venv_ret["retcode"] != 0: @@ -215,9 +213,7 @@ def managed( return ret ret["result"] = True - ret["changes"]["new"] = __salt__["cmd.run_stderr"]( - "{} -V".format(venv_py) - ).strip("\n") + ret["changes"]["new"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n") if clear: ret["comment"] = "Cleared existing virtualenv" @@ -328,7 +324,7 @@ def managed( env_vars=env_vars, no_cache_dir=pip_no_cache_dir, cache_dir=pip_cache_dir, - **kwargs + **kwargs, ) ret["result"] &= pip_ret["retcode"] == 0 if pip_ret["retcode"] > 0: diff --git a/salt/states/webutil.py b/salt/states/webutil.py index d988c4e30e0..d83190f8ac9 100644 --- a/salt/states/webutil.py +++ b/salt/states/webutil.py @@ -66,9 +66,7 @@ def user_exists( ret = {"name": name, "changes": {}, "comment": "", "result": None} if __salt__["file.file_exists"](htpasswd_file): - exists = ( - __salt__["file.grep"](htpasswd_file, "^{}:".format(name))["retcode"] == 0 - ) + exists = __salt__["file.grep"](htpasswd_file, f"^{name}:")["retcode"] == 0 else: exists = False @@ -126,7 +124,7 @@ def user_absent(name, htpasswd_file=None, runas=None): """ ret = {"name": name, "changes": {}, "comment": "", "result": None} - exists = __salt__["file.grep"](htpasswd_file, "^{}:".format(name))["retcode"] == 0 + exists = __salt__["file.grep"](htpasswd_file, f"^{name}:")["retcode"] == 0 if not exists: if __opts__["test"]: diff --git a/salt/states/win_certutil.py b/salt/states/win_certutil.py index 392139d8a49..fa3c78e4af3 100644 --- a/salt/states/win_certutil.py +++ b/salt/states/win_certutil.py @@ -61,38 +61,38 @@ def add_store(name, store, saltenv="base"): cert_file = __salt__["cp.cache_file"](name, saltenv) if cert_file is False: - ret["comment"] = "Certificate file not found: {}".format(name) + ret["comment"] = f"Certificate file not found: {name}" ret["result"] = False return ret cert_serial = __salt__["certutil.get_cert_serial"](name) if cert_serial is None: - ret["comment"] = "Invalid certificate file: {}".format(name) + ret["comment"] = f"Invalid certificate file: {name}" ret["result"] = False return ret old_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial in old_serials: - ret["comment"] = "Certificate already present: {}".format(name) + ret["comment"] = f"Certificate already present: {name}" return ret if __opts__["test"]: - ret["comment"] = "Certificate will be added: {}".format(name) + ret["comment"] = f"Certificate will be added: {name}" ret["result"] = None return ret retcode = __salt__["certutil.add_store"](name, store, retcode=True) if retcode != 0: - ret["comment"] = "Error adding certificate: {}".format(name) + ret["comment"] = f"Error adding certificate: {name}" ret["result"] = False return ret new_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial in new_serials: ret["changes"]["added"] = name - ret["comment"] = "Added certificate: {}".format(name) + ret["comment"] = f"Added certificate: {name}" else: - ret["comment"] = "Failed to add certificate: {}".format(name) + ret["comment"] = f"Failed to add certificate: {name}" ret["result"] = False return ret @@ -131,38 +131,38 @@ def del_store(name, store, saltenv="base"): cert_file = __salt__["cp.cache_file"](name, saltenv) if cert_file is False: - ret["comment"] = "Certificate file not found: {}".format(name) + ret["comment"] = f"Certificate file not found: {name}" ret["result"] = False return ret cert_serial = __salt__["certutil.get_cert_serial"](name) if cert_serial is None: - ret["comment"] = "Invalid certificate file: {}".format(name) + ret["comment"] = f"Invalid certificate file: {name}" ret["result"] = False return ret old_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial not in old_serials: - ret["comment"] = "Certificate already absent: {}".format(name) + ret["comment"] = f"Certificate already absent: {name}" return ret if __opts__["test"]: - ret["comment"] = "Certificate will be removed: {}".format(name) + ret["comment"] = f"Certificate will be removed: {name}" ret["result"] = None return ret retcode = __salt__["certutil.del_store"](name, store, retcode=True) if retcode != 0: - ret["comment"] = "Error removing certificate: {}".format(name) + ret["comment"] = f"Error removing certificate: {name}" ret["result"] = False return ret new_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial not in new_serials: ret["changes"]["removed"] = name - ret["comment"] = "Removed certificate: {}".format(name) + ret["comment"] = f"Removed certificate: {name}" else: - ret["comment"] = "Failed to remove certificate: {}".format(name) + ret["comment"] = f"Failed to remove certificate: {name}" ret["result"] = False return ret diff --git a/salt/states/win_dism.py b/salt/states/win_dism.py index 486ff9720c0..b48aafdb703 100644 --- a/salt/states/win_dism.py +++ b/salt/states/win_dism.py @@ -64,11 +64,11 @@ def capability_installed( old = __salt__["dism.installed_capabilities"]() if name in old: - ret["comment"] = "The capability {} is already installed".format(name) + ret["comment"] = f"The capability {name} is already installed" return ret if __opts__["test"]: - ret["changes"]["capability"] = "{} will be installed".format(name) + ret["changes"]["capability"] = f"{name} will be installed" ret["result"] = None return ret @@ -83,7 +83,7 @@ def capability_installed( changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Installed {}".format(name) + ret["comment"] = f"Installed {name}" ret["changes"] = status ret["changes"]["capability"] = changes @@ -117,11 +117,11 @@ def capability_removed(name, image=None, restart=False): old = __salt__["dism.installed_capabilities"]() if name not in old: - ret["comment"] = "The capability {} is already removed".format(name) + ret["comment"] = f"The capability {name} is already removed" return ret if __opts__["test"]: - ret["changes"]["capability"] = "{} will be removed".format(name) + ret["changes"]["capability"] = f"{name} will be removed" ret["result"] = None return ret @@ -136,7 +136,7 @@ def capability_removed(name, image=None, restart=False): changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Removed {}".format(name) + ret["comment"] = f"Removed {name}" ret["changes"] = status ret["changes"]["capability"] = changes @@ -185,11 +185,11 @@ def feature_installed( old = __salt__["dism.installed_features"]() if name in old: - ret["comment"] = "The feature {} is already installed".format(name) + ret["comment"] = f"The feature {name} is already installed" return ret if __opts__["test"]: - ret["changes"]["feature"] = "{} will be installed".format(name) + ret["changes"]["feature"] = f"{name} will be installed" ret["result"] = None return ret @@ -206,7 +206,7 @@ def feature_installed( changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Installed {}".format(name) + ret["comment"] = f"Installed {name}" ret["changes"] = status ret["changes"]["feature"] = changes @@ -243,11 +243,11 @@ def feature_removed(name, remove_payload=False, image=None, restart=False): old = __salt__["dism.installed_features"]() if name not in old: - ret["comment"] = "The feature {} is already removed".format(name) + ret["comment"] = f"The feature {name} is already removed" return ret if __opts__["test"]: - ret["changes"]["feature"] = "{} will be removed".format(name) + ret["changes"]["feature"] = f"{name} will be removed" ret["result"] = None return ret @@ -262,7 +262,7 @@ def feature_removed(name, remove_payload=False, image=None, restart=False): changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Removed {}".format(name) + ret["comment"] = f"Removed {name}" ret["changes"] = status ret["changes"]["feature"] = changes @@ -303,7 +303,7 @@ def package_installed( ret["result"] = None else: ret["result"] = False - ret["comment"] = "Package path {} does not exist".format(name) + ret["comment"] = f"Package path {name} does not exist" return ret old = __salt__["dism.installed_packages"]() @@ -318,7 +318,7 @@ def package_installed( return ret if __opts__["test"]: - ret["changes"]["package"] = "{} will be installed".format(name) + ret["changes"]["package"] = f"{name} will be installed" ret["result"] = None return ret @@ -335,7 +335,7 @@ def package_installed( changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Installed {}".format(name) + ret["comment"] = f"Installed {name}" ret["changes"] = status ret["changes"]["package"] = changes @@ -379,7 +379,7 @@ def package_removed(name, image=None, restart=False): ret["result"] = None else: ret["result"] = False - ret["comment"] = "Package path {} does not exist".format(name) + ret["comment"] = f"Package path {name} does not exist" return ret old = __salt__["dism.installed_packages"]() @@ -393,11 +393,11 @@ def package_removed(name, image=None, restart=False): "Package Identity" not in package_info or package_info["Package Identity"] not in old ): - ret["comment"] = "The package {} is already removed".format(name) + ret["comment"] = f"The package {name} is already removed" return ret if __opts__["test"]: - ret["changes"]["package"] = "{} will be removed".format(name) + ret["changes"]["package"] = f"{name} will be removed" ret["result"] = None return ret @@ -412,7 +412,7 @@ def package_removed(name, image=None, restart=False): changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Removed {}".format(name) + ret["comment"] = f"Removed {name}" ret["changes"] = status ret["changes"]["package"] = changes @@ -454,11 +454,11 @@ def kb_removed(name, image=None, restart=False): # If pkg_name is None, the package is not installed if pkg_name is None: - ret["comment"] = "{} is not installed".format(name) + ret["comment"] = f"{name} is not installed" return ret if __opts__["test"]: - ret["changes"]["package"] = "{} will be removed".format(name) + ret["changes"]["package"] = f"{name} will be removed" ret["result"] = None return ret @@ -477,7 +477,7 @@ def kb_removed(name, image=None, restart=False): changes = salt.utils.data.compare_lists(old, new) if changes: - ret["comment"] = "Removed {}".format(name) + ret["comment"] = f"Removed {name}" ret["changes"] = status ret["changes"]["package"] = changes diff --git a/salt/states/win_dns_client.py b/salt/states/win_dns_client.py index 48d045bbd76..dcd56a4eada 100644 --- a/salt/states/win_dns_client.py +++ b/salt/states/win_dns_client.py @@ -53,7 +53,7 @@ def dns_exists(name, servers=None, interface="Local Area Connection", replace=Fa # Do nothing is already configured configured_list = __salt__["win_dns_client.get_dns_servers"](interface) if configured_list == servers: - ret["comment"] = "{} are already configured".format(servers) + ret["comment"] = f"{servers} are already configured" ret["changes"] = {} ret["result"] = True return ret @@ -90,7 +90,7 @@ def dns_exists(name, servers=None, interface="Local Area Connection", replace=Fa else: if not __salt__["win_dns_client.rm_dns"](server, interface): ret["comment"] = ( - "Failed to remove {} from DNS server list".format(server) + f"Failed to remove {server} from DNS server list" ) ret["result"] = False return ret @@ -109,7 +109,7 @@ def dns_dhcp(name, interface="Local Area Connection"): # Check the config config = __salt__["win_dns_client.get_dns_config"](interface) if config == "dhcp": - ret["comment"] = "{} already configured with DNS from DHCP".format(interface) + ret["comment"] = f"{interface} already configured with DNS from DHCP" return ret else: ret["changes"] = {"dns": "configured from DHCP"} @@ -208,7 +208,7 @@ def primary_suffix(name, suffix=None, updates=False): return ret # Changes to update policy needed else: - ret["comment"] = "{} suffix updates".format(updates_operation) + ret["comment"] = f"{updates_operation} suffix updates" ret["changes"] = { "old": {"updates": reg_data["updates"]["old"]}, "new": {"updates": reg_data["updates"]["new"]}, @@ -234,7 +234,7 @@ def primary_suffix(name, suffix=None, updates=False): } # No changes to updates policy needed else: - ret["comment"] = "Updated primary DNS suffix ({})".format(suffix) + ret["comment"] = f"Updated primary DNS suffix ({suffix})" ret["changes"] = { "old": {"suffix": reg_data["suffix"]["old"]}, "new": {"suffix": reg_data["suffix"]["new"]}, diff --git a/salt/states/win_firewall.py b/salt/states/win_firewall.py index 959021ede74..151519f8ee0 100644 --- a/salt/states/win_firewall.py +++ b/salt/states/win_firewall.py @@ -52,12 +52,12 @@ def disabled(name="allprofiles"): # Make sure the profile name is valid if name not in profile_map: - raise SaltInvocationError("Invalid profile name: {}".format(name)) + raise SaltInvocationError(f"Invalid profile name: {name}") current_config = __salt__["firewall.get_config"]() if name != "allprofiles" and profile_map[name] not in current_config: ret["result"] = False - ret["comment"] = "Profile {} does not exist in firewall.get_config".format(name) + ret["comment"] = f"Profile {name} does not exist in firewall.get_config" return ret for key in current_config: @@ -83,7 +83,7 @@ def disabled(name="allprofiles"): if name == "allprofiles": msg = "All the firewall profiles are disabled" else: - msg = "Firewall profile {} is disabled".format(name) + msg = f"Firewall profile {name} is disabled" ret["comment"] = msg return ret @@ -211,12 +211,12 @@ def enabled(name="allprofiles"): # Make sure the profile name is valid if name not in profile_map: - raise SaltInvocationError("Invalid profile name: {}".format(name)) + raise SaltInvocationError(f"Invalid profile name: {name}") current_config = __salt__["firewall.get_config"]() if name != "allprofiles" and profile_map[name] not in current_config: ret["result"] = False - ret["comment"] = "Profile {} does not exist in firewall.get_config".format(name) + ret["comment"] = f"Profile {name} does not exist in firewall.get_config" return ret for key in current_config: @@ -242,7 +242,7 @@ def enabled(name="allprofiles"): if name == "allprofiles": msg = "All the firewall profiles are enabled" else: - msg = "Firewall profile {} is enabled".format(name) + msg = f"Firewall profile {name} is enabled" ret["comment"] = msg return ret diff --git a/salt/states/win_iis.py b/salt/states/win_iis.py index 4c19e823e77..1f8c6a80d61 100644 --- a/salt/states/win_iis.py +++ b/salt/states/win_iis.py @@ -84,13 +84,13 @@ def deployed( current_sites = __salt__["win_iis.list_sites"]() if name in current_sites: - ret["comment"] = "Site already present: {}".format(name) + ret["comment"] = f"Site already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Site will be created: {}".format(name) + ret["comment"] = f"Site will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created site: {}".format(name) + ret["comment"] = f"Created site: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_site"]( name, sourcepath, apppool, hostheader, ipaddress, port, protocol @@ -118,13 +118,13 @@ def remove_site(name): current_sites = __salt__["win_iis.list_sites"]() if name not in current_sites: - ret["comment"] = "Site has already been removed: {}".format(name) + ret["comment"] = f"Site has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Site will be removed: {}".format(name) + ret["comment"] = f"Site will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed site: {}".format(name) + ret["comment"] = f"Removed site: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_site"](name) return ret @@ -176,13 +176,13 @@ def create_binding( current_bindings = __salt__["win_iis.list_bindings"](site) if binding_info in current_bindings: - ret["comment"] = "Binding already present: {}".format(binding_info) + ret["comment"] = f"Binding already present: {binding_info}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Binding will be created: {}".format(binding_info) + ret["comment"] = f"Binding will be created: {binding_info}" ret["changes"] = {"old": None, "new": binding_info} else: - ret["comment"] = "Created binding: {}".format(binding_info) + ret["comment"] = f"Created binding: {binding_info}" ret["changes"] = {"old": None, "new": binding_info} ret["result"] = __salt__["win_iis.create_binding"]( site, hostheader, ipaddress, port, protocol, sslflags @@ -224,13 +224,13 @@ def remove_binding(name, site, hostheader="", ipaddress="*", port=80): current_bindings = __salt__["win_iis.list_bindings"](site) if binding_info not in current_bindings: - ret["comment"] = "Binding has already been removed: {}".format(binding_info) + ret["comment"] = f"Binding has already been removed: {binding_info}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Binding will be removed: {}".format(binding_info) + ret["comment"] = f"Binding will be removed: {binding_info}" ret["changes"] = {"old": binding_info, "new": None} else: - ret["comment"] = "Removed binding: {}".format(binding_info) + ret["comment"] = f"Removed binding: {binding_info}" ret["changes"] = {"old": binding_info, "new": None} ret["result"] = __salt__["win_iis.remove_binding"]( site, hostheader, ipaddress, port @@ -286,7 +286,7 @@ def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslf current_name = current_cert_bindings[binding_info]["certificatehash"] if name == current_name: - ret["comment"] = "Certificate binding already present: {}".format(name) + ret["comment"] = f"Certificate binding already present: {name}" ret["result"] = True return ret ret["comment"] = ( @@ -295,10 +295,10 @@ def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslf ) ret["result"] = False elif __opts__["test"]: - ret["comment"] = "Certificate binding will be created: {}".format(name) + ret["comment"] = f"Certificate binding will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created certificate binding: {}".format(name) + ret["comment"] = f"Created certificate binding: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_cert_binding"]( name, site, hostheader, ipaddress, port, sslflags @@ -350,16 +350,16 @@ def remove_cert_binding(name, site, hostheader="", ipaddress="*", port=443): current_cert_bindings = __salt__["win_iis.list_cert_bindings"](site) if binding_info not in current_cert_bindings: - ret["comment"] = "Certificate binding has already been removed: {}".format(name) + ret["comment"] = f"Certificate binding has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Certificate binding will be removed: {}".format(name) + ret["comment"] = f"Certificate binding will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: current_name = current_cert_bindings[binding_info]["certificatehash"] if name == current_name: - ret["comment"] = "Removed certificate binding: {}".format(name) + ret["comment"] = f"Removed certificate binding: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_cert_binding"]( name, site, hostheader, ipaddress, port @@ -393,13 +393,13 @@ def create_apppool(name): current_apppools = __salt__["win_iis.list_apppools"]() if name in current_apppools: - ret["comment"] = "Application pool already present: {}".format(name) + ret["comment"] = f"Application pool already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application pool will be created: {}".format(name) + ret["comment"] = f"Application pool will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created application pool: {}".format(name) + ret["comment"] = f"Created application pool: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_apppool"](name) return ret @@ -426,13 +426,13 @@ def remove_apppool(name): current_apppools = __salt__["win_iis.list_apppools"]() if name not in current_apppools: - ret["comment"] = "Application pool has already been removed: {}".format(name) + ret["comment"] = f"Application pool has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application pool will be removed: {}".format(name) + ret["comment"] = f"Application pool will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed application pool: {}".format(name) + ret["comment"] = f"Removed application pool: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_apppool"](name) return ret @@ -605,13 +605,13 @@ def create_app(name, site, sourcepath, apppool=None): current_apps = __salt__["win_iis.list_apps"](site) if name in current_apps: - ret["comment"] = "Application already present: {}".format(name) + ret["comment"] = f"Application already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application will be created: {}".format(name) + ret["comment"] = f"Application will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created application: {}".format(name) + ret["comment"] = f"Created application: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_app"](name, site, sourcepath, apppool) return ret @@ -638,13 +638,13 @@ def remove_app(name, site): current_apps = __salt__["win_iis.list_apps"](site) if name not in current_apps: - ret["comment"] = "Application has already been removed: {}".format(name) + ret["comment"] = f"Application has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application will be removed: {}".format(name) + ret["comment"] = f"Application will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed application: {}".format(name) + ret["comment"] = f"Removed application: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_app"](name, site) return ret @@ -691,13 +691,13 @@ def create_vdir(name, site, sourcepath, app="/"): current_vdirs = __salt__["win_iis.list_vdirs"](site, app) if name in current_vdirs: - ret["comment"] = "Virtual directory already present: {}".format(name) + ret["comment"] = f"Virtual directory already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Virtual directory will be created: {}".format(name) + ret["comment"] = f"Virtual directory will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created virtual directory: {}".format(name) + ret["comment"] = f"Created virtual directory: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_vdir"](name, site, sourcepath, app) @@ -736,13 +736,13 @@ def remove_vdir(name, site, app="/"): current_vdirs = __salt__["win_iis.list_vdirs"](site, app) if name not in current_vdirs: - ret["comment"] = "Virtual directory has already been removed: {}".format(name) + ret["comment"] = f"Virtual directory has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Virtual directory will be removed: {}".format(name) + ret["comment"] = f"Virtual directory will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed virtual directory: {}".format(name) + ret["comment"] = f"Removed virtual directory: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_vdir"](name, site, app) diff --git a/salt/states/win_lgpo.py b/salt/states/win_lgpo.py index 125b1e9e895..669a3d44dae 100644 --- a/salt/states/win_lgpo.py +++ b/salt/states/win_lgpo.py @@ -429,7 +429,7 @@ def set_( ) deprecation_comments.append(msg) else: - msg = "Invalid element name: {}".format(e_name) + msg = f"Invalid element name: {e_name}" ret["comment"] = "\n".join( [ret["comment"], msg] ).strip() @@ -526,7 +526,7 @@ def set_( ) policy_changes.append(p_name) else: - msg = '"{}" is already set'.format(p_name) + msg = f'"{p_name}" is already set' log.debug(msg) else: policy_changes.append(p_name) diff --git a/salt/states/win_lgpo_reg.py b/salt/states/win_lgpo_reg.py index 7bd3919b350..1a01ea17c0f 100644 --- a/salt/states/win_lgpo_reg.py +++ b/salt/states/win_lgpo_reg.py @@ -252,7 +252,7 @@ def value_disabled(name, key, policy_class="Machine"): old = _get_current(key=key, name=name, policy_class=policy_class) - pol_correct = old["pol"].get("data", "") == "**del.{}".format(name) + pol_correct = old["pol"].get("data", "") == f"**del.{name}" reg_correct = old["reg"] == {} if pol_correct and reg_correct: @@ -274,7 +274,7 @@ def value_disabled(name, key, policy_class="Machine"): new = _get_current(key=key, name=name, policy_class=policy_class) - pol_correct = new["pol"].get("data", "") == "**del.{}".format(name) + pol_correct = new["pol"].get("data", "") == f"**del.{name}" reg_correct = new["reg"] == {} if pol_correct and reg_correct: diff --git a/salt/states/win_network.py b/salt/states/win_network.py index b0549ba6dab..c35ee8ed6ad 100644 --- a/salt/states/win_network.py +++ b/salt/states/win_network.py @@ -137,7 +137,7 @@ def _validate(dns_proto, dns_servers, ip_proto, ip_addrs, gateway): # Validate default gateway if gateway is not None: if not salt.utils.validate.net.ipv4_addr(gateway): - errors.append("Gateway IP {} is invalid".format(gateway)) + errors.append(f"Gateway IP {gateway} is invalid") return errors @@ -198,7 +198,7 @@ def managed( ip_addrs=None, gateway=None, enabled=True, - **kwargs + **kwargs, ): """ Ensure that the named interface is configured properly. @@ -262,7 +262,7 @@ def managed( "name": name, "changes": {}, "result": True, - "comment": "Interface '{}' is up to date".format(name), + "comment": f"Interface '{name}' is up to date", } dns_proto = str(dns_proto).lower() @@ -296,11 +296,11 @@ def managed( if currently_enabled: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Interface '{}' will be disabled".format(name) + ret["comment"] = f"Interface '{name}' will be disabled" else: ret["result"] = __salt__["ip.disable"](name) if not ret["result"]: - ret["comment"] = "Failed to disable interface '{}'".format(name) + ret["comment"] = f"Failed to disable interface '{name}'" else: ret["comment"] += " (already disabled)" return ret @@ -308,12 +308,12 @@ def managed( if not currently_enabled: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Interface '{}' will be enabled".format(name) + ret["comment"] = f"Interface '{name}' will be enabled" else: if not __salt__["ip.enable"](name): ret["result"] = False ret["comment"] = ( - "Failed to enable interface '{}' to make changes".format(name) + f"Failed to enable interface '{name}' to make changes" ) return ret @@ -331,7 +331,7 @@ def managed( if not old: ret["result"] = False ret["comment"] = ( - "Unable to get current configuration for interface '{}'".format(name) + f"Unable to get current configuration for interface '{name}'" ) return ret @@ -432,6 +432,6 @@ def managed( ) else: ret["comment"] = ( - "Successfully updated configuration for interface '{}'".format(name) + f"Successfully updated configuration for interface '{name}'" ) return ret diff --git a/salt/states/win_path.py b/salt/states/win_path.py index 5463cacfdcd..8b3d76ff391 100644 --- a/salt/states/win_path.py +++ b/salt/states/win_path.py @@ -35,21 +35,21 @@ def absent(name): ret = {"name": name, "result": True, "changes": {}, "comment": ""} if not __salt__["win_path.exists"](name): - ret["comment"] = "{} is not in the PATH".format(name) + ret["comment"] = f"{name} is not in the PATH" return ret if __opts__["test"]: - ret["comment"] = "{} would be removed from the PATH".format(name) + ret["comment"] = f"{name} would be removed from the PATH" ret["result"] = None return ret __salt__["win_path.remove"](name) if __salt__["win_path.exists"](name): - ret["comment"] = "Failed to remove {} from the PATH".format(name) + ret["comment"] = f"Failed to remove {name} from the PATH" ret["result"] = False else: - ret["comment"] = "Removed {} from the PATH".format(name) + ret["comment"] = f"Removed {name} from the PATH" ret["changes"]["removed"] = name return ret @@ -143,13 +143,11 @@ def exists(name, index=None): if index is None: # We're not enforcing the index, and the directory is in the PATH. # There's nothing to do here. - comments.append("{} already exists in the PATH.".format(name)) + comments.append(f"{name} already exists in the PATH.") return _format_comments(ret, comments) else: if index == old_index: - comments.append( - "{} already exists in the PATH at index {}.".format(name, index) - ) + comments.append(f"{name} already exists in the PATH at index {index}.") return _format_comments(ret, comments) else: if __opts__["test"]: @@ -168,7 +166,7 @@ def exists(name, index=None): ret["result"] = None comments.append( "{} would be added to the PATH{}.".format( - name, " at index {}".format(index) if index is not None else "" + name, f" at index {index}" if index is not None else "" ) ) ret["changes"] = _changes(old_index, index) @@ -177,7 +175,7 @@ def exists(name, index=None): try: ret["result"] = __salt__["win_path.add"](name, index=index, rehash=False) except Exception as exc: # pylint: disable=broad-except - comments.append("Encountered error: {}.".format(exc)) + comments.append(f"Encountered error: {exc}.") ret["result"] = False if ret["result"]: @@ -203,7 +201,7 @@ def exists(name, index=None): "{} {} to the PATH{}.".format( "Added" if ret["result"] else "Failed to add", name, - " at index {}".format(index) if index is not None else "", + f" at index {index}" if index is not None else "", ) ) diff --git a/salt/states/win_pki.py b/salt/states/win_pki.py index 658d979bef8..0e0724209f1 100644 --- a/salt/states/win_pki.py +++ b/salt/states/win_pki.py @@ -64,7 +64,7 @@ def import_cert( """ ret = {"name": name, "changes": dict(), "comment": "", "result": None} - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" cached_source_path = __salt__["cp.cache_file"](name, saltenv) current_certs = __salt__["win_pki.get_certs"](context=context, store=store) @@ -139,7 +139,7 @@ def remove_cert(name, thumbprint, context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE """ ret = {"name": name, "changes": dict(), "comment": "", "result": None} - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" current_certs = __salt__["win_pki.get_certs"](context=context, store=store) if thumbprint not in current_certs: diff --git a/salt/states/win_powercfg.py b/salt/states/win_powercfg.py index c65b80ad0ed..46aba50985f 100644 --- a/salt/states/win_powercfg.py +++ b/salt/states/win_powercfg.py @@ -88,7 +88,7 @@ def set_timeout(name, value, power="ac", scheme=None): name = name.lower() if name not in ["monitor", "disk", "standby", "hibernate"]: ret["result"] = False - ret["comment"] = '"{}" is not a valid setting'.format(name) + ret["comment"] = f'"{name}" is not a valid setting' log.debug(ret["comment"]) return ret @@ -96,12 +96,12 @@ def set_timeout(name, value, power="ac", scheme=None): power = power.lower() if power not in ["ac", "dc"]: ret["result"] = False - ret["comment"] = '"{}" is not a power type'.format(power) + ret["comment"] = f'"{power}" is not a power type' log.debug(ret["comment"]) return ret # Get current settings - old = __salt__["powercfg.get_{}_timeout".format(name)](scheme=scheme) + old = __salt__[f"powercfg.get_{name}_timeout"](scheme=scheme) # Check current settings if old[power] == value: @@ -120,12 +120,10 @@ def set_timeout(name, value, power="ac", scheme=None): return ret # Set the timeout value - __salt__["powercfg.set_{}_timeout".format(name)]( - timeout=value, power=power, scheme=scheme - ) + __salt__[f"powercfg.set_{name}_timeout"](timeout=value, power=power, scheme=scheme) # Get the setting after the change - new = __salt__["powercfg.get_{}_timeout".format(name)](scheme=scheme) + new = __salt__[f"powercfg.get_{name}_timeout"](scheme=scheme) changes = salt.utils.data.compare_dicts(old, new) diff --git a/salt/states/win_servermanager.py b/salt/states/win_servermanager.py index 2e77012df18..6f91f166742 100644 --- a/salt/states/win_servermanager.py +++ b/salt/states/win_servermanager.py @@ -28,7 +28,7 @@ def installed( restart=False, source=None, exclude=None, - **kwargs + **kwargs, ): """ Install the windows feature. To install a single feature, use the ``name`` @@ -137,7 +137,7 @@ def installed( for feature in features: if feature not in old: - ret["changes"][feature] = "Will be installed recurse={}".format(recurse) + ret["changes"][feature] = f"Will be installed recurse={recurse}" elif recurse: ret["changes"][feature] = "Already installed but might install sub-features" else: @@ -168,13 +168,13 @@ def installed( for feature in status["Features"]: # Features that failed to install or be removed if not status["Features"][feature].get("Success", True): - fail_feat.append("- {}".format(feature)) + fail_feat.append(f"- {feature}") # Features that installed elif "(exclude)" not in status["Features"][feature]["Message"]: - new_feat.append("- {}".format(feature)) + new_feat.append(f"- {feature}") # Show items that were removed because they were part of `exclude` elif "(exclude)" in status["Features"][feature]["Message"]: - rem_feat.append("- {}".format(feature)) + rem_feat.append(f"- {feature}") if fail_feat: fail_feat.insert(0, "Failed to install the following:") @@ -302,10 +302,10 @@ def removed(name, features=None, remove_payload=False, restart=False): # feature is already uninstalled if not status["Features"][feature].get("Success", True): # Show items that failed to uninstall - fail_feat.append("- {}".format(feature)) + fail_feat.append(f"- {feature}") else: # Show items that uninstalled - rem_feat.append("- {}".format(feature)) + rem_feat.append(f"- {feature}") if fail_feat: fail_feat.insert(0, "Failed to remove the following:") diff --git a/salt/states/win_shortcut.py b/salt/states/win_shortcut.py index 3f14d1f6a4d..a1fa46a2f9e 100644 --- a/salt/states/win_shortcut.py +++ b/salt/states/win_shortcut.py @@ -188,10 +188,10 @@ def present( if __opts__["test"]: if changes: - ret["comment"] = "Shortcut will be modified: {}".format(name) + ret["comment"] = f"Shortcut will be modified: {name}" ret["changes"] = changes else: - ret["comment"] = "Shortcut will be created: {}".format(name) + ret["comment"] = f"Shortcut will be created: {name}" ret["result"] = None return ret @@ -213,7 +213,7 @@ def present( user=user, ) except CommandExecutionError as exc: - ret["comment"] = ["Failed to create the shortcut: {}".format(name)] + ret["comment"] = [f"Failed to create the shortcut: {name}"] ret["comment"].append(exc.message) ret["result"] = False return ret @@ -221,7 +221,7 @@ def present( try: new = __salt__["shortcut.get"](name) except CommandExecutionError as exc: - ret["comment"] = ["Failed to create the shortcut: {}".format(name)] + ret["comment"] = [f"Failed to create the shortcut: {name}"] ret["comment"].append(exc.message) ret["result"] = False return ret @@ -234,9 +234,9 @@ def present( return ret if changes: - ret["comment"] = "Shortcut modified: {}".format(name) + ret["comment"] = f"Shortcut modified: {name}" ret["changes"] = changes else: - ret["comment"] = "Shortcut created: {}".format(name) + ret["comment"] = f"Shortcut created: {name}" return ret diff --git a/salt/states/win_smtp_server.py b/salt/states/win_smtp_server.py index fa5a9a76bbe..91df2a6586a 100644 --- a/salt/states/win_smtp_server.py +++ b/salt/states/win_smtp_server.py @@ -38,7 +38,7 @@ def _normalize_server_settings(**settings): if isinstance(settings[setting], dict): value_from_key = next(iter(settings[setting].keys())) - ret[setting] = "{{{0}}}".format(value_from_key) + ret[setting] = f"{{{value_from_key}}}" else: ret[setting] = settings[setting] return ret diff --git a/salt/states/win_snmp.py b/salt/states/win_snmp.py index 0b5dfac12d8..9d70ebc1b8e 100644 --- a/salt/states/win_snmp.py +++ b/salt/states/win_snmp.py @@ -104,13 +104,13 @@ def auth_traps_enabled(name, status=True): current_status = __salt__["win_snmp.get_auth_traps_enabled"]() if status == current_status: - ret["comment"] = "{} already contains the provided value.".format(vname) + ret["comment"] = f"{vname} already contains the provided value." ret["result"] = True elif __opts__["test"]: - ret["comment"] = "{} will be changed.".format(vname) + ret["comment"] = f"{vname} will be changed." ret["changes"] = {"old": current_status, "new": status} else: - ret["comment"] = "Set {} to contain the provided value.".format(vname) + ret["comment"] = f"Set {vname} to contain the provided value." ret["changes"] = {"old": current_status, "new": status} ret["result"] = __salt__["win_snmp.set_auth_traps_enabled"](status=status) diff --git a/salt/states/win_system.py b/salt/states/win_system.py index 1e8d66ec81e..0aa5438b0ec 100644 --- a/salt/states/win_system.py +++ b/salt/states/win_system.py @@ -52,7 +52,7 @@ def computer_desc(name): "name": name, "changes": {}, "result": True, - "comment": "Computer description already set to '{}'".format(name), + "comment": f"Computer description already set to '{name}'", } before_desc = __salt__["system.get_computer_desc"]() @@ -62,7 +62,7 @@ def computer_desc(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Computer description will be changed to '{}'".format(name) + ret["comment"] = f"Computer description will be changed to '{name}'" return ret result = __salt__["system.set_computer_desc"](name) @@ -73,7 +73,7 @@ def computer_desc(name): ret["changes"] = {"old": before_desc, "new": name} else: ret["result"] = False - ret["comment"] = "Unable to set computer description to '{}'".format(name) + ret["comment"] = f"Unable to set computer description to '{name}'" return ret @@ -96,7 +96,7 @@ def computer_name(name): "name": name, "changes": {}, "result": True, - "comment": "Computer name already set to '{}'".format(name), + "comment": f"Computer name already set to '{name}'", } before_name = __salt__["system.get_computer_name"]() @@ -113,7 +113,7 @@ def computer_name(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Computer name will be changed to '{}'".format(name) + ret["comment"] = f"Computer name will be changed to '{name}'" return ret result = __salt__["system.set_computer_name"](name) @@ -123,13 +123,13 @@ def computer_name(name): if (after_pending is not None and after_pending == name) or ( after_pending is None and after_name == name ): - ret["comment"] = "Computer name successfully set to '{}'".format(name) + ret["comment"] = f"Computer name successfully set to '{name}'" if after_pending is not None: ret["comment"] += " (reboot required for change to take effect)" ret["changes"] = {"old": before_name, "new": name} else: ret["result"] = False - ret["comment"] = "Unable to set computer name to '{}'".format(name) + ret["comment"] = f"Unable to set computer name to '{name}'" return ret @@ -147,7 +147,7 @@ def hostname(name): current_hostname = __salt__["system.get_hostname"]() if current_hostname.upper() == name.upper(): - ret["comment"] = "Hostname is already set to '{}'".format(name) + ret["comment"] = f"Hostname is already set to '{name}'" return ret out = __salt__["system.set_hostname"](name) @@ -197,14 +197,14 @@ def workgroup(name): # Notify the user if the requested workgroup is the same if current_workgroup.upper() == name.upper(): ret["result"] = True - ret["comment"] = "Workgroup is already set to '{}'".format(name.upper()) + ret["comment"] = f"Workgroup is already set to '{name.upper()}'" return ret # If being run in test-mode, inform the user what is supposed to happen if __opts__["test"]: ret["result"] = None ret["changes"] = {} - ret["comment"] = "Computer will be joined to workgroup '{}'".format(name) + ret["comment"] = f"Computer will be joined to workgroup '{name}'" return ret # Set our new workgroup, and then immediately ask the machine what it @@ -295,7 +295,7 @@ def join_domain( "name": name, "changes": {}, "result": True, - "comment": "Computer already added to '{}'".format(name), + "comment": f"Computer already added to '{name}'", } current_domain_dic = __salt__["system.get_domain_workgroup"]() @@ -307,12 +307,12 @@ def join_domain( current_domain = None if name.lower() == current_domain.lower(): - ret["comment"] = "Computer already added to '{}'".format(name) + ret["comment"] = f"Computer already added to '{name}'" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Computer will be added to '{}'".format(name) + ret["comment"] = f"Computer will be added to '{name}'" return ret result = __salt__["system.join_domain"]( @@ -324,14 +324,14 @@ def join_domain( restart=restart, ) if result is not False: - ret["comment"] = "Computer added to '{}'".format(name) + ret["comment"] = f"Computer added to '{name}'" if restart: ret["comment"] += "\nSystem will restart" else: ret["comment"] += "\nSystem needs to be restarted" ret["changes"] = {"old": current_domain, "new": name} else: - ret["comment"] = "Computer failed to join '{}'".format(name) + ret["comment"] = f"Computer failed to join '{name}'" ret["result"] = False return ret @@ -458,7 +458,7 @@ def shutdown( if only_on_pending_reboot and not __salt__["system.get_pending_reboot"](): if __opts__["test"]: ret["comment"] = ( - "System {} will be skipped because no reboot is pending".format(action) + f"System {action} will be skipped because no reboot is pending" ) else: ret["comment"] = ( @@ -470,7 +470,7 @@ def shutdown( if __opts__["test"]: ret["result"] = None - ret["comment"] = "Will attempt to schedule a {}".format(action) + ret["comment"] = f"Will attempt to schedule a {action}" return ret ret["result"] = __salt__["system.shutdown"]( @@ -485,9 +485,9 @@ def shutdown( if ret["result"]: ret["changes"] = { "old": "No reboot or shutdown was scheduled", - "new": "A {} has been scheduled".format(action), + "new": f"A {action} has been scheduled", } - ret["comment"] = "Request to {} was successful".format(action) + ret["comment"] = f"Request to {action} was successful" else: - ret["comment"] = "Request to {} failed".format(action) + ret["comment"] = f"Request to {action} failed" return ret diff --git a/salt/states/win_wusa.py b/salt/states/win_wusa.py index 17996c0bde7..70cf1f00436 100644 --- a/salt/states/win_wusa.py +++ b/salt/states/win_wusa.py @@ -61,13 +61,13 @@ def installed(name, source): # Is the KB already installed if __salt__["wusa.is_installed"](name): ret["result"] = True - ret["comment"] = "{} already installed".format(name) + ret["comment"] = f"{name} already installed" return ret # Check for test=True if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "{} would be installed".format(name) + ret["comment"] = f"{name} would be installed" ret["result"] = None return ret @@ -91,11 +91,11 @@ def installed(name, source): # Verify successful install if __salt__["wusa.is_installed"](name): - ret["comment"] = "{} was installed. {}".format(name, additional_comment) + ret["comment"] = f"{name} was installed. {additional_comment}" ret["changes"] = {"old": False, "new": True} ret["result"] = True else: - ret["comment"] = "{} failed to install. {}".format(name, additional_comment) + ret["comment"] = f"{name} failed to install. {additional_comment}" return ret @@ -121,13 +121,13 @@ def uninstalled(name): # Is the KB already uninstalled if not __salt__["wusa.is_installed"](name): ret["result"] = True - ret["comment"] = "{} already uninstalled".format(name) + ret["comment"] = f"{name} already uninstalled" return ret # Check for test=True if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "{} would be uninstalled".format(name) + ret["comment"] = f"{name} would be uninstalled" ret["result"] = None return ret @@ -136,10 +136,10 @@ def uninstalled(name): # Verify successful uninstall if not __salt__["wusa.is_installed"](name): - ret["comment"] = "{} was uninstalled".format(name) + ret["comment"] = f"{name} was uninstalled" ret["changes"] = {"old": True, "new": False} ret["result"] = True else: - ret["comment"] = "{} failed to uninstall".format(name) + ret["comment"] = f"{name} failed to uninstall" return ret diff --git a/salt/states/winrepo.py b/salt/states/winrepo.py index 23858551592..241c66c1ca6 100644 --- a/salt/states/winrepo.py +++ b/salt/states/winrepo.py @@ -60,11 +60,11 @@ def genrepo(name, force=False, allow_empty=False): if not force: if not os.path.exists(winrepo_dir): ret["result"] = False - ret["comment"] = "{} is missing".format(winrepo_dir) + ret["comment"] = f"{winrepo_dir} is missing" return ret elif not os.path.exists(winrepo_cachefile): execute = True - ret["comment"] = "{} is missing".format(winrepo_cachefile) + ret["comment"] = f"{winrepo_cachefile} is missing" else: winrepo_cachefile_mtime = os.stat(winrepo_cachefile)[stat.ST_MTIME] for root, dirs, files in salt.utils.path.os_walk(winrepo_dir): diff --git a/salt/states/wordpress.py b/salt/states/wordpress.py index e672e30be4a..5e208458ef7 100644 --- a/salt/states/wordpress.py +++ b/salt/states/wordpress.py @@ -53,11 +53,11 @@ def installed(name, user, admin_user, admin_password, admin_email, title, url): if check: ret["result"] = True - ret["comment"] = "Wordpress is already installed: {}".format(name) + ret["comment"] = f"Wordpress is already installed: {name}" return ret elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Wordpress will be installed: {}".format(name) + ret["comment"] = f"Wordpress will be installed: {name}" return ret resp = __salt__["wordpress.install"]( @@ -65,10 +65,10 @@ def installed(name, user, admin_user, admin_password, admin_email, title, url): ) if resp: ret["result"] = True - ret["comment"] = "Wordpress Installed: {}".format(name) + ret["comment"] = f"Wordpress Installed: {name}" ret["changes"] = {"new": resp} else: - ret["comment"] = "Failed to install wordpress: {}".format(name) + ret["comment"] = f"Failed to install wordpress: {name}" return ret @@ -99,30 +99,30 @@ def activated(name, path, user): if check["status"] == "active": ret["result"] = True - ret["comment"] = "Plugin already activated: {}".format(name) + ret["comment"] = f"Plugin already activated: {name}" return ret elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Plugin will be activated: {}".format(name) + ret["comment"] = f"Plugin will be activated: {name}" return ret resp = __salt__["wordpress.activate"](name, path, user) if resp is True: ret["result"] = True - ret["comment"] = "Plugin activated: {}".format(name) + ret["comment"] = f"Plugin activated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } elif resp is None: ret["result"] = True - ret["comment"] = "Plugin already activated: {}".format(name) + ret["comment"] = f"Plugin already activated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } else: - ret["comment"] = "Plugin failed to activate: {}".format(name) + ret["comment"] = f"Plugin failed to activate: {name}" return ret @@ -153,29 +153,29 @@ def deactivated(name, path, user): if check["status"] == "inactive": ret["result"] = True - ret["comment"] = "Plugin already deactivated: {}".format(name) + ret["comment"] = f"Plugin already deactivated: {name}" return ret elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Plugin will be deactivated: {}".format(name) + ret["comment"] = f"Plugin will be deactivated: {name}" return ret resp = __salt__["wordpress.deactivate"](name, path, user) if resp is True: ret["result"] = True - ret["comment"] = "Plugin deactivated: {}".format(name) + ret["comment"] = f"Plugin deactivated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } elif resp is None: ret["result"] = True - ret["comment"] = "Plugin already deactivated: {}".format(name) + ret["comment"] = f"Plugin already deactivated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } else: - ret["comment"] = "Plugin failed to deactivate: {}".format(name) + ret["comment"] = f"Plugin failed to deactivate: {name}" return ret diff --git a/salt/states/x509.py b/salt/states/x509.py index 0a8d988fa0f..14e3edff640 100644 --- a/salt/states/x509.py +++ b/salt/states/x509.py @@ -286,7 +286,7 @@ def private_key_managed( new=False, overwrite=False, verbose=True, - **kwargs + **kwargs, ): """ Manage a private key's existence. @@ -390,7 +390,7 @@ def csr_managed(name, **kwargs): try: old = __salt__["x509.read_csr"](name) except salt.exceptions.SaltInvocationError: - old = "{} is not a valid csr.".format(name) + old = f"{name} is not a valid csr." file_args, kwargs = _get_file_args(name, **kwargs) file_args["contents"] = __salt__["x509.create_csr"](text=True, **kwargs) @@ -517,7 +517,7 @@ def _certificate_is_valid(name, days_remaining, append_certs, **cert_spec): If False, also provide a message explaining why. """ if not os.path.isfile(name): - return False, "{} does not exist".format(name), {} + return False, f"{name} does not exist", {} try: cert_info = __salt__["x509.read_certificate"](certificate=name) @@ -569,7 +569,7 @@ def _certificate_is_valid(name, days_remaining, append_certs, **cert_spec): return True, "", cert_info except salt.exceptions.SaltInvocationError as e: - return False, "{} is not a valid certificate: {}".format(name, str(e)), {} + return False, f"{name} is not a valid certificate: {str(e)}", {} def _certificate_file_managed(ret, file_args): @@ -698,7 +698,7 @@ def certificate_managed(name, days_remaining=90, append_certs=None, **kwargs): ret = _certificate_file_managed(ret, file_args) ret["result"] = None - ret["comment"] = "Certificate {} will be created".format(name) + ret["comment"] = f"Certificate {name} will be created" ret["changes"]["Status"] = { "Old": invalid_reason, "New": "Certificate will be valid and up to date", @@ -763,7 +763,7 @@ def crl_managed( digest="", days_remaining=30, include_expired=False, - **kwargs + **kwargs, ): """ Manage a Certificate Revocation List @@ -845,9 +845,9 @@ def crl_managed( if days_remaining == 0: days_remaining = current_days_remaining - 1 except salt.exceptions.SaltInvocationError: - current = "{} is not a valid CRL.".format(name) + current = f"{name} is not a valid CRL." else: - current = "{} does not exist.".format(name) + current = f"{name} does not exist." new_crl = __salt__["x509.create_crl"]( text=True, diff --git a/salt/states/xml.py b/salt/states/xml.py index 67cf30a825b..48bcb4eb5db 100644 --- a/salt/states/xml.py +++ b/salt/states/xml.py @@ -51,20 +51,20 @@ def value_present(name, xpath, value, **kwargs): current_value = __salt__["xml.get_value"](name, xpath) if not current_value: ret["result"] = False - ret["comment"] = "xpath query {} not found in {}".format(xpath, name) + ret["comment"] = f"xpath query {xpath} not found in {name}" return ret if current_value != value: if kwargs["test"]: ret["result"] = None - ret["comment"] = "{} will be updated".format(name) + ret["comment"] = f"{name} will be updated" ret["changes"] = {name: {"old": current_value, "new": value}} else: results = __salt__["xml.set_value"](name, xpath, value) ret["result"] = results - ret["comment"] = "{} updated".format(name) + ret["comment"] = f"{name} updated" ret["changes"] = {name: {"old": current_value, "new": value}} else: - ret["comment"] = "{} is already present".format(value) + ret["comment"] = f"{value} is already present" return ret diff --git a/salt/states/xmpp.py b/salt/states/xmpp.py index 2186c37bbca..84b4a6a3017 100644 --- a/salt/states/xmpp.py +++ b/salt/states/xmpp.py @@ -54,7 +54,7 @@ def send_msg(name, recipient, profile): profile=profile, ) ret["result"] = True - ret["comment"] = "Sent message to {}: {}".format(recipient, name) + ret["comment"] = f"Sent message to {recipient}: {name}" return ret @@ -84,10 +84,10 @@ def send_msg_multi(name, profile, recipients=None, rooms=None): comment = "" if recipients: - comment += " users {}".format(recipients) + comment += f" users {recipients}" if rooms: - comment += " rooms {}".format(rooms) - comment += ", message: {}".format(name) + comment += f" rooms {rooms}" + comment += f", message: {name}" if __opts__["test"]: ret["comment"] = "Need to send" + comment diff --git a/salt/states/zabbix_action.py b/salt/states/zabbix_action.py index c3ff6a05054..159da05f169 100644 --- a/salt/states/zabbix_action.py +++ b/salt/states/zabbix_action.py @@ -127,7 +127,7 @@ def present(name, params, **kwargs): if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" would be fixed.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" would be fixed.' ret["changes"] = { name: { "old": ( @@ -151,14 +151,14 @@ def present(name, params, **kwargs): ) if action_update: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" updated.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" updated.' ret["changes"] = { name: { "old": ( 'Zabbix Action "{}" differed ' "in following parameters: {}".format(name, diff_params) ), - "new": 'Zabbix Action "{}" fixed.'.format(name), + "new": f'Zabbix Action "{name}" fixed.', } } @@ -173,10 +173,10 @@ def present(name, params, **kwargs): else: if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" would be created.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" would be created.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" does not exist.'.format(name), + "old": f'Zabbix Action "{name}" does not exist.', "new": ( 'Zabbix Action "{}" would be created according definition.'.format( name @@ -193,10 +193,10 @@ def present(name, params, **kwargs): if action_create: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" created.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" created.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" did not exist.'.format(name), + "old": f'Zabbix Action "{name}" did not exist.', "new": ( 'Zabbix Action "{}" created according definition.'.format( name @@ -235,15 +235,15 @@ def absent(name, **kwargs): if not object_id: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" does not exist.' else: if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" would be deleted.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" would be deleted.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" exists.'.format(name), - "new": 'Zabbix Action "{}" would be deleted.'.format(name), + "old": f'Zabbix Action "{name}" exists.', + "new": f'Zabbix Action "{name}" would be deleted.', } } else: @@ -253,11 +253,11 @@ def absent(name, **kwargs): if action_delete: ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" deleted.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" deleted.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" existed.'.format(name), - "new": 'Zabbix Action "{}" deleted.'.format(name), + "old": f'Zabbix Action "{name}" existed.', + "new": f'Zabbix Action "{name}" deleted.', } } diff --git a/salt/states/zabbix_host.py b/salt/states/zabbix_host.py index 0ec5204c435..a065c6a7aef 100644 --- a/salt/states/zabbix_host.py +++ b/salt/states/zabbix_host.py @@ -85,14 +85,14 @@ def present(host, groups, interfaces, **kwargs): ret = {"name": host, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_host_created = "Host {} created.".format(host) - comment_host_updated = "Host {} updated.".format(host) - comment_host_notcreated = "Unable to create host: {}. ".format(host) - comment_host_exists = "Host {} already exists.".format(host) + comment_host_created = f"Host {host} created." + comment_host_updated = f"Host {host} updated." + comment_host_notcreated = f"Unable to create host: {host}. " + comment_host_exists = f"Host {host} already exists." changes_host_created = { host: { - "old": "Host {} does not exist.".format(host), - "new": "Host {} created.".format(host), + "old": f"Host {host} does not exist.", + "new": f"Host {host} created.", } } @@ -206,7 +206,7 @@ def present(host, groups, interfaces, **kwargs): try: groupids.append(int(groupid[0]["groupid"])) except TypeError: - ret["comment"] = "Invalid group {}".format(group) + ret["comment"] = f"Invalid group {group}" return ret else: groupids.append(group) @@ -224,23 +224,23 @@ def present(host, groups, interfaces, **kwargs): { "output": "proxyid", "selectInterface": "extend", - "filter": {"host": "{}".format(proxy_host)}, + "filter": {"host": f"{proxy_host}"}, }, - **connection_args + **connection_args, )[0]["proxyid"] except TypeError: - ret["comment"] = "Invalid proxy_host {}".format(proxy_host) + ret["comment"] = f"Invalid proxy_host {proxy_host}" return ret # Otherwise lookup proxy_host as proxyid else: try: proxy_hostid = __salt__["zabbix.run_query"]( "proxy.get", - {"proxyids": "{}".format(proxy_host), "output": "proxyid"}, - **connection_args + {"proxyids": f"{proxy_host}", "output": "proxyid"}, + **connection_args, )[0]["proxyid"] except TypeError: - ret["comment"] = "Invalid proxy_host {}".format(proxy_host) + ret["comment"] = f"Invalid proxy_host {proxy_host}" return ret # Selects if the current inventory should be substituted by the new one @@ -459,7 +459,7 @@ def present(host, groups, interfaces, **kwargs): useip=interface["useip"], port=interface["port"], details=interface["details"], - **connection_args + **connection_args, ) else: interfaceid = interfaceid_by_type[interface["type"]].pop(0) @@ -472,7 +472,7 @@ def present(host, groups, interfaces, **kwargs): useip=interface["useip"], port=interface["port"], details=interface["details"], - **connection_args + **connection_args, ) return ret @@ -516,7 +516,7 @@ def present(host, groups, interfaces, **kwargs): proxy_hostid=proxy_hostid, inventory=new_inventory, visible_name=visible_name, - **sum_kwargs + **sum_kwargs, ) if "error" not in host_create: @@ -556,13 +556,13 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_host_deleted = "Host {} deleted.".format(name) - comment_host_notdeleted = "Unable to delete host: {}. ".format(name) - comment_host_notexists = "Host {} does not exist.".format(name) + comment_host_deleted = f"Host {name} deleted." + comment_host_notdeleted = f"Unable to delete host: {name}. " + comment_host_notexists = f"Host {name} does not exist." changes_host_deleted = { name: { - "old": "Host {} exists.".format(name), - "new": "Host {} deleted.".format(name), + "old": f"Host {name} exists.", + "new": f"Host {name} deleted.", } } connection_args = {} @@ -670,7 +670,7 @@ def assign_templates(host, templates, **kwargs): hostids=hostid, output='[{"hostid"}]', selectParentTemplates='["templateid"]', - **connection_args + **connection_args, ) for template_id in host_templates[0]["parentTemplates"]: curr_template_ids.append(template_id["templateid"]) @@ -684,7 +684,7 @@ def assign_templates(host, templates, **kwargs): requested_template_ids.append(template_id) except TypeError: ret["result"] = False - ret["comment"] = "Unable to find template: {}.".format(template) + ret["comment"] = f"Unable to find template: {template}." return ret # remove any duplications diff --git a/salt/states/zabbix_hostgroup.py b/salt/states/zabbix_hostgroup.py index 9822f160eec..052ba60fda2 100644 --- a/salt/states/zabbix_hostgroup.py +++ b/salt/states/zabbix_hostgroup.py @@ -45,13 +45,13 @@ def present(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_hostgroup_created = "Host group {} created.".format(name) - comment_hostgroup_notcreated = "Unable to create host group: {}. ".format(name) - comment_hostgroup_exists = "Host group {} already exists.".format(name) + comment_hostgroup_created = f"Host group {name} created." + comment_hostgroup_notcreated = f"Unable to create host group: {name}. " + comment_hostgroup_exists = f"Host group {name} already exists." changes_hostgroup_created = { name: { - "old": "Host group {} does not exist.".format(name), - "new": "Host group {} created.".format(name), + "old": f"Host group {name} does not exist.", + "new": f"Host group {name} created.", } } @@ -109,13 +109,13 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_hostgroup_deleted = "Host group {} deleted.".format(name) - comment_hostgroup_notdeleted = "Unable to delete host group: {}. ".format(name) - comment_hostgroup_notexists = "Host group {} does not exist.".format(name) + comment_hostgroup_deleted = f"Host group {name} deleted." + comment_hostgroup_notdeleted = f"Unable to delete host group: {name}. " + comment_hostgroup_notexists = f"Host group {name} does not exist." changes_hostgroup_deleted = { name: { - "old": "Host group {} exists.".format(name), - "new": "Host group {} deleted.".format(name), + "old": f"Host group {name} exists.", + "new": f"Host group {name} deleted.", } } diff --git a/salt/states/zabbix_mediatype.py b/salt/states/zabbix_mediatype.py index 4c29914adab..81417d58f72 100644 --- a/salt/states/zabbix_mediatype.py +++ b/salt/states/zabbix_mediatype.py @@ -49,14 +49,14 @@ def present(name, mediatype, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_mediatype_created = "Mediatype {} created.".format(name) - comment_mediatype_updated = "Mediatype {} updated.".format(name) - comment_mediatype_notcreated = "Unable to create mediatype: {}. ".format(name) - comment_mediatype_exists = "Mediatype {} already exists.".format(name) + comment_mediatype_created = f"Mediatype {name} created." + comment_mediatype_updated = f"Mediatype {name} updated." + comment_mediatype_notcreated = f"Unable to create mediatype: {name}. " + comment_mediatype_exists = f"Mediatype {name} already exists." changes_mediatype_created = { name: { - "old": "Mediatype {} does not exist.".format(name), - "new": "Mediatype {} created.".format(name), + "old": f"Mediatype {name} does not exist.", + "new": f"Mediatype {name} created.", } } @@ -214,7 +214,7 @@ def present(name, mediatype, **kwargs): smtp_server=kwargs["smtp_server"], smtp_helo=kwargs["smtp_helo"], smtp_email=kwargs["smtp_email"], - **connection_args + **connection_args, ) if "error" in updated_email: error.append(updated_email["error"]) @@ -236,7 +236,7 @@ def present(name, mediatype, **kwargs): updated_email_security = __salt__["zabbix.mediatype_update"]( mediatypeid, smtp_security=kwargs["smtp_security"], - **connection_args + **connection_args, ) if "error" in updated_email_security: error.append(updated_email_security["error"]) @@ -247,7 +247,7 @@ def present(name, mediatype, **kwargs): updated_email_verify_peer = __salt__["zabbix.mediatype_update"]( mediatypeid, smtp_verify_peer=kwargs["smtp_verify_peer"], - **connection_args + **connection_args, ) if "error" in updated_email_verify_peer: error.append(updated_email_verify_peer["error"]) @@ -258,7 +258,7 @@ def present(name, mediatype, **kwargs): updated_email_verify_host = __salt__["zabbix.mediatype_update"]( mediatypeid, smtp_verify_host=kwargs["smtp_verify_host"], - **connection_args + **connection_args, ) if "error" in updated_email_verify_host: error.append(updated_email_verify_host["error"]) @@ -271,7 +271,7 @@ def present(name, mediatype, **kwargs): username=kwargs["username"], passwd=kwargs["passwd"], smtp_authentication=kwargs["smtp_authentication"], - **connection_args + **connection_args, ) if "error" in updated_email_auth: error.append(updated_email_auth["error"]) @@ -286,7 +286,7 @@ def present(name, mediatype, **kwargs): mediatypeid, type=mediatype, exec_path=kwargs["exec_path"], - **connection_args + **connection_args, ) if "error" in updated_script: error.append(updated_script["error"]) @@ -307,7 +307,7 @@ def present(name, mediatype, **kwargs): mediatypeid, type=mediatype, gsm_modem=kwargs["gsm_modem"], - **connection_args + **connection_args, ) if "error" in updated_sms: error.append(updated_sms["error"]) @@ -320,7 +320,7 @@ def present(name, mediatype, **kwargs): type=mediatype, username=kwargs["username"], passwd=kwargs["passwd"], - **connection_args + **connection_args, ) if "error" in updated_jabber: error.append(updated_jabber["error"]) @@ -334,7 +334,7 @@ def present(name, mediatype, **kwargs): username=kwargs["username"], passwd=kwargs["passwd"], exec_path=kwargs["exec_path"], - **connection_args + **connection_args, ) if "error" in updated_eztext: error.append(updated_eztext["error"]) @@ -404,13 +404,13 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_mediatype_deleted = "Mediatype {} deleted.".format(name) - comment_mediatype_notdeleted = "Unable to delete mediatype: {}. ".format(name) - comment_mediatype_notexists = "Mediatype {} does not exist.".format(name) + comment_mediatype_deleted = f"Mediatype {name} deleted." + comment_mediatype_notdeleted = f"Unable to delete mediatype: {name}. " + comment_mediatype_notexists = f"Mediatype {name} does not exist." changes_mediatype_deleted = { name: { - "old": "Mediatype {} exists.".format(name), - "new": "Mediatype {} deleted.".format(name), + "old": f"Mediatype {name} exists.", + "new": f"Mediatype {name} deleted.", } } diff --git a/salt/states/zabbix_template.py b/salt/states/zabbix_template.py index 0e0bc6169eb..81420943371 100644 --- a/salt/states/zabbix_template.py +++ b/salt/states/zabbix_template.py @@ -487,10 +487,10 @@ def is_present(name, **kwargs): if not object_id: ret["result"] = False - ret["comment"] = 'Zabbix Template "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" does not exist.' else: ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" exists.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" exists.' return ret @@ -690,7 +690,7 @@ def present(name, params, static_host_list=True, **kwargs): "selectMacros": "extend", "filter": {"host": name}, }, - **kwargs + **kwargs, ) log.info("TEMPLATE get result: %s", str(json.dumps(tmpl_get, indent=4))) @@ -797,7 +797,7 @@ def present(name, params, static_host_list=True, **kwargs): TEMPLATE_COMPONENT_DEF[component]["qselectpid"]: template_id }, filter_key=TEMPLATE_COMPONENT_DEF[component]["filter"], - **kwargs + **kwargs, ) else: defined_c_list_subs = [] @@ -807,7 +807,7 @@ def present(name, params, static_host_list=True, **kwargs): template_id, defined_c_list_subs, existing_c_list_subs, - **kwargs + **kwargs, ) log.info( @@ -846,7 +846,7 @@ def present(name, params, static_host_list=True, **kwargs): defined_p_list_subs = __salt__["zabbix.substitute_params"]( d_rule_component[proto_name], extend_params={c_def["qselectpid"]: template_id}, - **kwargs + **kwargs, ) else: defined_p_list_subs = [] @@ -857,7 +857,7 @@ def present(name, params, static_host_list=True, **kwargs): defined_p_list_subs, existing_p_list_subs, template_id=template_id, - **kwargs + **kwargs, ) log.info( @@ -884,10 +884,10 @@ def present(name, params, static_host_list=True, **kwargs): if tmpl_action: ret["result"] = True if dry_run: - ret["comment"] = 'Zabbix Template "{}" would be created.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" would be created.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" does not exist.'.format(name), + "old": f'Zabbix Template "{name}" does not exist.', "new": ( 'Zabbix Template "{}" would be created ' "according definition.".format(name) @@ -895,10 +895,10 @@ def present(name, params, static_host_list=True, **kwargs): } } else: - ret["comment"] = 'Zabbix Template "{}" created.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" created.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" did not exist.'.format(name), + "old": f'Zabbix Template "{name}" did not exist.', "new": ( 'Zabbix Template "{}" created according definition.'.format( name @@ -909,10 +909,10 @@ def present(name, params, static_host_list=True, **kwargs): else: ret["result"] = True if dry_run: - ret["comment"] = 'Zabbix Template "{}" would be updated.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" would be updated.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" differs.'.format(name), + "old": f'Zabbix Template "{name}" differs.', "new": ( 'Zabbix Template "{}" would be updated ' "according definition.".format(name) @@ -920,10 +920,10 @@ def present(name, params, static_host_list=True, **kwargs): } } else: - ret["comment"] = 'Zabbix Template "{}" updated.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" updated.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" differed.'.format(name), + "old": f'Zabbix Template "{name}" differed.', "new": ( 'Zabbix Template "{}" updated according definition.'.format( name @@ -962,15 +962,15 @@ def absent(name, **kwargs): if not object_id: ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" does not exist.' else: if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" would be deleted.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" would be deleted.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" exists.'.format(name), - "new": 'Zabbix Template "{}" would be deleted.'.format(name), + "old": f'Zabbix Template "{name}" exists.', + "new": f'Zabbix Template "{name}" would be deleted.', } } else: @@ -979,11 +979,11 @@ def absent(name, **kwargs): ) if tmpl_delete: ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" deleted.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" deleted.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" existed.'.format(name), - "new": 'Zabbix Template "{}" deleted.'.format(name), + "old": f'Zabbix Template "{name}" existed.', + "new": f'Zabbix Template "{name}" deleted.', } } diff --git a/salt/states/zabbix_user.py b/salt/states/zabbix_user.py index e1236458801..bf7706ced08 100644 --- a/salt/states/zabbix_user.py +++ b/salt/states/zabbix_user.py @@ -191,14 +191,14 @@ def present(alias, passwd, usrgrps, medias=None, password_reset=False, **kwargs) ret = {"name": alias, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_user_created = "User {} created.".format(alias) - comment_user_updated = "User {} updated.".format(alias) - comment_user_notcreated = "Unable to create user: {}. ".format(alias) - comment_user_exists = "User {} already exists.".format(alias) + comment_user_created = f"User {alias} created." + comment_user_updated = f"User {alias} updated." + comment_user_notcreated = f"Unable to create user: {alias}. " + comment_user_exists = f"User {alias} already exists." changes_user_created = { alias: { - "old": "User {} does not exist.".format(alias), - "new": "User {} created.".format(alias), + "old": f"User {alias} does not exist.", + "new": f"User {alias} created.", } } @@ -341,7 +341,7 @@ def present(alias, passwd, usrgrps, medias=None, password_reset=False, **kwargs) usrgrp_diff = list(set(usrgrps) - set(cur_usrgrps)) if usrgrp_diff and update_usrgrps: - error.append("Unable to update group(s): {}".format(usrgrp_diff)) + error.append(f"Unable to update group(s): {usrgrp_diff}") else: if update_usrgrps: @@ -359,9 +359,7 @@ def present(alias, passwd, usrgrps, medias=None, password_reset=False, **kwargs) usrgrp_diff = list(set(usrgrps) - set(cur_usrgrps)) if usrgrp_diff: - error.append( - "Unable to update group(s): {}".format(usrgrp_diff) - ) + error.append(f"Unable to update group(s): {usrgrp_diff}") ret["changes"]["usrgrps"] = str(updated_groups) @@ -390,7 +388,7 @@ def present(alias, passwd, usrgrps, medias=None, password_reset=False, **kwargs) period=media["period"], sendto=media["sendto"], severity=media["severity"], - **connection_args + **connection_args, ) if "error" in updatemed: @@ -448,13 +446,13 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_user_deleted = "USer {} deleted.".format(name) - comment_user_notdeleted = "Unable to delete user: {}. ".format(name) - comment_user_notexists = "User {} does not exist.".format(name) + comment_user_deleted = f"USer {name} deleted." + comment_user_notdeleted = f"Unable to delete user: {name}. " + comment_user_notexists = f"User {name} does not exist." changes_user_deleted = { name: { - "old": "User {} exists.".format(name), - "new": "User {} deleted.".format(name), + "old": f"User {name} exists.", + "new": f"User {name} deleted.", } } diff --git a/salt/states/zabbix_usergroup.py b/salt/states/zabbix_usergroup.py index 0a054228866..347c0781cd7 100644 --- a/salt/states/zabbix_usergroup.py +++ b/salt/states/zabbix_usergroup.py @@ -50,14 +50,14 @@ def present(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_usergroup_created = "User group {} created.".format(name) - comment_usergroup_updated = "User group {} updated.".format(name) - comment_usergroup_notcreated = "Unable to create user group: {}. ".format(name) - comment_usergroup_exists = "User group {} already exists.".format(name) + comment_usergroup_created = f"User group {name} created." + comment_usergroup_updated = f"User group {name} updated." + comment_usergroup_notcreated = f"Unable to create user group: {name}. " + comment_usergroup_exists = f"User group {name} already exists." changes_usergroup_created = { name: { - "old": "User group {} does not exist.".format(name), - "new": "User group {} created.".format(name), + "old": f"User group {name} does not exist.", + "new": f"User group {name} created.", } } @@ -219,13 +219,13 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": False, "comment": ""} # Comment and change messages - comment_usergroup_deleted = "User group {} deleted.".format(name) - comment_usergroup_notdeleted = "Unable to delete user group: {}. ".format(name) - comment_usergroup_notexists = "User group {} does not exist.".format(name) + comment_usergroup_deleted = f"User group {name} deleted." + comment_usergroup_notdeleted = f"Unable to delete user group: {name}. " + comment_usergroup_notexists = f"User group {name} does not exist." changes_usergroup_deleted = { name: { - "old": "User group {} exists.".format(name), - "new": "User group {} deleted.".format(name), + "old": f"User group {name} exists.", + "new": f"User group {name} deleted.", } } diff --git a/salt/states/zabbix_usermacro.py b/salt/states/zabbix_usermacro.py index d1d9419ee08..e3612172de4 100644 --- a/salt/states/zabbix_usermacro.py +++ b/salt/states/zabbix_usermacro.py @@ -54,26 +54,26 @@ def present(name, value, hostid=None, **kwargs): name, hostid ) comment_usermacro_notcreated = ( - "Unable to create usermacro: {} on hostid {}. ".format(name, hostid) + f"Unable to create usermacro: {name} on hostid {hostid}. " ) comment_usermacro_exists = "Usermacro {} already exists on hostid {}.".format( name, hostid ) changes_usermacro_created = { name: { - "old": "Usermacro {} does not exist on hostid {}.".format(name, hostid), - "new": "Usermacro {} created on hostid {}.".format(name, hostid), + "old": f"Usermacro {name} does not exist on hostid {hostid}.", + "new": f"Usermacro {name} created on hostid {hostid}.", } } else: - comment_usermacro_created = "Usermacro {} created.".format(name) - comment_usermacro_updated = "Usermacro {} updated.".format(name) - comment_usermacro_notcreated = "Unable to create usermacro: {}. ".format(name) - comment_usermacro_exists = "Usermacro {} already exists.".format(name) + comment_usermacro_created = f"Usermacro {name} created." + comment_usermacro_updated = f"Usermacro {name} updated." + comment_usermacro_notcreated = f"Unable to create usermacro: {name}. " + comment_usermacro_exists = f"Usermacro {name} already exists." changes_usermacro_created = { name: { - "old": "Usermacro {} does not exist.".format(name), - "new": "Usermacro {} created.".format(name), + "old": f"Usermacro {name} does not exist.", + "new": f"Usermacro {name} created.", } } @@ -203,25 +203,25 @@ def absent(name, hostid=None, **kwargs): name, hostid ) comment_usermacro_notdeleted = ( - "Unable to delete usermacro: {} from hostid {}.".format(name, hostid) + f"Unable to delete usermacro: {name} from hostid {hostid}." ) comment_usermacro_notexists = ( - "Usermacro {} does not exist on hostid {}.".format(name, hostid) + f"Usermacro {name} does not exist on hostid {hostid}." ) changes_usermacro_deleted = { name: { - "old": "Usermacro {} exists on hostid {}.".format(name, hostid), - "new": "Usermacro {} deleted from {}.".format(name, hostid), + "old": f"Usermacro {name} exists on hostid {hostid}.", + "new": f"Usermacro {name} deleted from {hostid}.", } } else: - comment_usermacro_deleted = "Usermacro {} deleted.".format(name) - comment_usermacro_notdeleted = "Unable to delete usermacro: {}.".format(name) - comment_usermacro_notexists = "Usermacro {} does not exist.".format(name) + comment_usermacro_deleted = f"Usermacro {name} deleted." + comment_usermacro_notdeleted = f"Unable to delete usermacro: {name}." + comment_usermacro_notexists = f"Usermacro {name} does not exist." changes_usermacro_deleted = { name: { - "old": "Usermacro {} exists.".format(name), - "new": "Usermacro {} deleted.".format(name), + "old": f"Usermacro {name} exists.", + "new": f"Usermacro {name} deleted.", } } if hostid: diff --git a/salt/states/zabbix_valuemap.py b/salt/states/zabbix_valuemap.py index 2475b2b4e53..cdcf4cb8cd2 100644 --- a/salt/states/zabbix_valuemap.py +++ b/salt/states/zabbix_valuemap.py @@ -95,7 +95,7 @@ def present(name, params, **kwargs): if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" would be fixed.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" would be fixed.' ret["changes"] = { name: { "old": ( @@ -119,14 +119,14 @@ def present(name, params, **kwargs): ) if valuemap_update: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" updated.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" updated.' ret["changes"] = { name: { "old": ( 'Zabbix Value map "{}" differed ' "in following parameters: {}".format(name, diff_params) ), - "new": 'Zabbix Value map "{}" fixed.'.format(name), + "new": f'Zabbix Value map "{name}" fixed.', } } @@ -141,10 +141,10 @@ def present(name, params, **kwargs): else: if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" would be created.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" would be created.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" does not exist.'.format(name), + "old": f'Zabbix Value map "{name}" does not exist.', "new": ( 'Zabbix Value map "{}" would be created ' "according definition.".format(name) @@ -163,10 +163,10 @@ def present(name, params, **kwargs): if valuemap_create: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" created.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" created.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" did not exist.'.format(name), + "old": f'Zabbix Value map "{name}" did not exist.', "new": ( 'Zabbix Value map "{}" created according definition.'.format( name @@ -205,15 +205,15 @@ def absent(name, **kwargs): if not object_id: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" does not exist.' else: if dry_run: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" would be deleted.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" would be deleted.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" exists.'.format(name), - "new": 'Zabbix Value map "{}" would be deleted.'.format(name), + "old": f'Zabbix Value map "{name}" exists.', + "new": f'Zabbix Value map "{name}" would be deleted.', } } else: @@ -223,11 +223,11 @@ def absent(name, **kwargs): if valuemap_delete: ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" deleted.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" deleted.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" existed.'.format(name), - "new": 'Zabbix Value map "{}" deleted.'.format(name), + "old": f'Zabbix Value map "{name}" existed.', + "new": f'Zabbix Value map "{name}" deleted.', } } diff --git a/salt/states/zenoss.py b/salt/states/zenoss.py index a2b11e888c7..ed06e9a249d 100644 --- a/salt/states/zenoss.py +++ b/salt/states/zenoss.py @@ -54,30 +54,30 @@ def monitored(name, device_class=None, collector="localhost", prod_state=None): if device: ret["result"] = True ret["changes"] = None - ret["comment"] = "{} is already monitored".format(name) + ret["comment"] = f"{name} is already monitored" # if prod_state is set, ensure it matches with the current state if prod_state is not None and device["productionState"] != prod_state: if __opts__["test"]: ret["comment"] = ( - "{} is already monitored but prodState will be updated".format(name) + f"{name} is already monitored but prodState will be updated" ) ret["result"] = None else: __salt__["zenoss.set_prod_state"](prod_state, name) ret["comment"] = ( - "{} is already monitored but prodState was updated".format(name) + f"{name} is already monitored but prodState was updated" ) ret["changes"] = { "old": "prodState == {}".format(device["productionState"]), - "new": "prodState == {}".format(prod_state), + "new": f"prodState == {prod_state}", } return ret # Device not yet in Zenoss if __opts__["test"]: - ret["comment"] = 'The state of "{}" will be changed.'.format(name) + ret["comment"] = f'The state of "{name}" will be changed.' ret["changes"] = {"old": "monitored == False", "new": "monitored == True"} ret["result"] = None return ret @@ -86,9 +86,9 @@ def monitored(name, device_class=None, collector="localhost", prod_state=None): if __salt__["zenoss.add_device"](name, device_class, collector, prod_state): ret["result"] = True ret["changes"] = {"old": "monitored == False", "new": "monitored == True"} - ret["comment"] = "{} has been added to Zenoss".format(name) + ret["comment"] = f"{name} has been added to Zenoss" else: ret["result"] = False ret["changes"] = None - ret["comment"] = "Unable to add {} to Zenoss".format(name) + ret["comment"] = f"Unable to add {name} to Zenoss" return ret diff --git a/salt/states/zfs.py b/salt/states/zfs.py index b28517ed5a1..0c023f5fd4e 100644 --- a/salt/states/zfs.py +++ b/salt/states/zfs.py @@ -118,7 +118,7 @@ def _absent(name, dataset_type, force=False, recursive=False): ret["comment"] = mod_res["error"] else: ## NOTE: no dataset found with name of the dataset_type - ret["comment"] = "{} {} is absent".format(dataset_type, name) + ret["comment"] = f"{dataset_type} {name} is absent" return ret @@ -145,7 +145,7 @@ def filesystem_absent(name, force=False, recursive=False): "name": name, "changes": {}, "result": False, - "comment": "invalid dataset name: {}".format(name), + "comment": f"invalid dataset name: {name}", } else: ret = _absent(name, "filesystem", force, recursive) @@ -174,7 +174,7 @@ def volume_absent(name, force=False, recursive=False): "name": name, "changes": {}, "result": False, - "comment": "invalid dataset name: {}".format(name), + "comment": f"invalid dataset name: {name}", } else: ret = _absent(name, "volume", force, recursive) @@ -198,7 +198,7 @@ def snapshot_absent(name, force=False, recursive=False): "name": name, "changes": {}, "result": False, - "comment": "invalid snapshot name: {}".format(name), + "comment": f"invalid snapshot name: {name}", } else: ret = _absent(name, "snapshot", force, recursive) @@ -222,7 +222,7 @@ def bookmark_absent(name, force=False, recursive=False): "name": name, "changes": {}, "result": False, - "comment": "invalid bookmark name: {}".format(name), + "comment": f"invalid bookmark name: {name}", } else: ret = _absent(name, "bookmark", force, recursive) @@ -250,7 +250,7 @@ def hold_absent(name, snapshot, recursive=False): ## check we have a snapshot/tag name if not __utils__["zfs.is_snapshot"](snapshot): ret["result"] = False - ret["comment"] = "invalid snapshot name: {}".format(snapshot) + ret["comment"] = f"invalid snapshot name: {snapshot}" return ret if ( @@ -259,7 +259,7 @@ def hold_absent(name, snapshot, recursive=False): or name == "error" ): ret["result"] = False - ret["comment"] = "invalid tag name: {}".format(name) + ret["comment"] = f"invalid tag name: {name}" return ret ## release hold if required @@ -319,7 +319,7 @@ def hold_present(name, snapshot, recursive=False): ## check we have a snapshot/tag name if not __utils__["zfs.is_snapshot"](snapshot): ret["result"] = False - ret["comment"] = "invalid snapshot name: {}".format(snapshot) + ret["comment"] = f"invalid snapshot name: {snapshot}" return ret if ( @@ -328,7 +328,7 @@ def hold_present(name, snapshot, recursive=False): or name == "error" ): ret["result"] = False - ret["comment"] = "invalid tag name: {}".format(name) + ret["comment"] = f"invalid tag name: {name}" return ret ## place hold if required @@ -349,9 +349,9 @@ def hold_present(name, snapshot, recursive=False): ret["result"] = mod_res["held"] if ret["result"]: ret["changes"] = OrderedDict([(snapshot, OrderedDict([(name, "held")]))]) - ret["comment"] = "hold {} added to {}".format(name, snapshot) + ret["comment"] = f"hold {name} added to {snapshot}" else: - ret["comment"] = "failed to add hold {} to {}".format(name, snapshot) + ret["comment"] = f"failed to add hold {name} to {snapshot}" if "error" in mod_res: ret["comment"] = mod_res["error"] @@ -440,19 +440,19 @@ def _dataset_present( ## check we have valid filesystem name/volume name/clone snapshot if not __utils__["zfs.is_dataset"](name): ret["result"] = False - ret["comment"] = "invalid dataset name: {}".format(name) + ret["comment"] = f"invalid dataset name: {name}" return ret if cloned_from and not __utils__["zfs.is_snapshot"](cloned_from): ret["result"] = False - ret["comment"] = "{} is not a snapshot".format(cloned_from) + ret["comment"] = f"{cloned_from} is not a snapshot" return ret ## ensure dataset is in correct state ## NOTE: update the dataset exists = __salt__["zfs.exists"](name, **{"type": dataset_type}) if exists and len(properties) == 0: - ret["comment"] = "{} {} is uptodate".format(dataset_type, name) + ret["comment"] = f"{dataset_type} {name} is uptodate" elif exists and len(properties) > 0: ## NOTE: fetch current volume properties properties_current = __salt__["zfs.get"]( @@ -500,11 +500,11 @@ def _dataset_present( ## NOTE: update comment if ret["result"] and name in ret["changes"]: - ret["comment"] = "{} {} was updated".format(dataset_type, name) + ret["comment"] = f"{dataset_type} {name} was updated" elif ret["result"]: - ret["comment"] = "{} {} is uptodate".format(dataset_type, name) + ret["comment"] = f"{dataset_type} {name} is uptodate" else: - ret["comment"] = "{} {} failed to be updated".format(dataset_type, name) + ret["comment"] = f"{dataset_type} {name} failed to be updated" ## NOTE: create or clone the dataset elif not exists: @@ -521,7 +521,7 @@ def _dataset_present( mod_res = __salt__["zfs.clone"]( cloned_from, name, - **{"create_parent": create_parent, "properties": properties} + **{"create_parent": create_parent, "properties": properties}, ) else: ## NOTE: create the dataset @@ -532,7 +532,7 @@ def _dataset_present( "properties": properties, "volume_size": volume_size, "sparse": sparse, - } + }, ) ret["result"] = mod_res[mod_res_action] @@ -658,7 +658,7 @@ def bookmark_present(name, snapshot): ## check we have valid snapshot/bookmark name if not __utils__["zfs.is_snapshot"](snapshot): ret["result"] = False - ret["comment"] = "invalid snapshot name: {}".format(name) + ret["comment"] = f"invalid snapshot name: {name}" return ret if "#" not in name and "/" not in name: @@ -670,7 +670,7 @@ def bookmark_present(name, snapshot): if not __utils__["zfs.is_bookmark"](name): ret["result"] = False - ret["comment"] = "invalid bookmark name: {}".format(name) + ret["comment"] = f"invalid bookmark name: {name}" return ret ## ensure bookmark exists @@ -684,9 +684,9 @@ def bookmark_present(name, snapshot): ret["result"] = mod_res["bookmarked"] if ret["result"]: ret["changes"][name] = snapshot - ret["comment"] = "{} bookmarked as {}".format(snapshot, name) + ret["comment"] = f"{snapshot} bookmarked as {name}" else: - ret["comment"] = "failed to bookmark {}".format(snapshot) + ret["comment"] = f"failed to bookmark {snapshot}" if "error" in mod_res: ret["comment"] = mod_res["error"] else: @@ -724,7 +724,7 @@ def snapshot_present(name, recursive=False, properties=None): ## check we have valid snapshot name if not __utils__["zfs.is_snapshot"](name): ret["result"] = False - ret["comment"] = "invalid snapshot name: {}".format(name) + ret["comment"] = f"invalid snapshot name: {name}" return ret ## ensure snapshot exits @@ -742,9 +742,9 @@ def snapshot_present(name, recursive=False, properties=None): ret["changes"][name] = "snapshotted" if properties: ret["changes"][name] = properties - ret["comment"] = "snapshot {} was created".format(name) + ret["comment"] = f"snapshot {name} was created" else: - ret["comment"] = "failed to create snapshot {}".format(name) + ret["comment"] = f"failed to create snapshot {name}" if "error" in mod_res: ret["comment"] = mod_res["error"] else: @@ -772,14 +772,14 @@ def promoted(name): ## check we if we have a valid dataset name if not __utils__["zfs.is_dataset"](name): ret["result"] = False - ret["comment"] = "invalid dataset name: {}".format(name) + ret["comment"] = f"invalid dataset name: {name}" return ret ## ensure dataset is the primary instance if not __salt__["zfs.exists"](name, **{"type": "filesystem,volume"}): ## NOTE: we don't have a dataset ret["result"] = False - ret["comment"] = "dataset {} does not exist".format(name) + ret["comment"] = f"dataset {name} does not exist" else: ## NOTE: check if we have a blank origin (-) if ( @@ -789,7 +789,7 @@ def promoted(name): == "-" ): ## NOTE: we're already promoted - ret["comment"] = "{} already promoted".format(name) + ret["comment"] = f"{name} already promoted" else: ## NOTE: promote dataset if not __opts__["test"]: @@ -800,9 +800,9 @@ def promoted(name): ret["result"] = mod_res["promoted"] if ret["result"]: ret["changes"][name] = "promoted" - ret["comment"] = "{} promoted".format(name) + ret["comment"] = f"{name} promoted" else: - ret["comment"] = "failed to promote {}".format(name) + ret["comment"] = f"failed to promote {name}" if "error" in mod_res: ret["comment"] = mod_res["error"] @@ -833,7 +833,7 @@ def _schedule_snapshot_retrieve(dataset, prefix, snapshots): snap_name = snap[snap.index("@") + 1 :] ## NOTE: we only want snapshots matching our prefix - if not snap_name.startswith("{}-".format(prefix)): + if not snap_name.startswith(f"{prefix}-"): continue ## NOTE: retrieve the holds for this snapshot @@ -886,7 +886,7 @@ def _schedule_snapshot_prepare(dataset, prefix, snapshots): ## NOTE: extract datetime from snapshot name timestamp = datetime.strptime( snapshots[hold][-1], - "{}@{}-%Y%m%d_%H%M%S".format(dataset, prefix), + f"{dataset}@{prefix}-%Y%m%d_%H%M%S", ).replace(second=0, microsecond=0) ## NOTE: compare current timestamp to timestamp from snapshot @@ -954,15 +954,15 @@ def scheduled_snapshot(name, prefix, recursive=True, schedule=None): ## NOTE: we need a valid dataset if not __utils__["zfs.is_dataset"](name): ret["result"] = False - ret["comment"] = "invalid dataset name: {}".format(name) + ret["comment"] = f"invalid dataset name: {name}" if not __salt__["zfs.exists"](name, **{"type": "filesystem,volume"}): - ret["comment"] = "dataset {} does not exist".format(name) + ret["comment"] = f"dataset {name} does not exist" ret["result"] = False ## NOTE: prefix must be 4 or longer if not prefix or len(prefix) < 4: - ret["comment"] = "prefix ({}) must be at least 4 long".format(prefix) + ret["comment"] = f"prefix ({prefix}) must be at least 4 long" ret["result"] = False ## NOTE: validate schedule @@ -1015,7 +1015,7 @@ def scheduled_snapshot(name, prefix, recursive=True, schedule=None): if not mod_res["snapshotted"]: ret["result"] = False - ret["comment"] = "error creating snapshot ({})".format(snapshot_name) + ret["comment"] = f"error creating snapshot ({snapshot_name})" else: ## NOTE: create holds (if we have a snapshot) for hold in snapshot_holds: diff --git a/salt/states/zk_concurrency.py b/salt/states/zk_concurrency.py index 0bf709911fc..d376e51c955 100644 --- a/salt/states/zk_concurrency.py +++ b/salt/states/zk_concurrency.py @@ -102,7 +102,7 @@ def lock( max_concurrency=max_concurrency, timeout=timeout, ephemeral_lease=ephemeral_lease, - **conn_kwargs + **conn_kwargs, ) if locked: ret["result"] = True @@ -151,13 +151,13 @@ def unlock( identifier=identifier, max_concurrency=max_concurrency, ephemeral_lease=ephemeral_lease, - **conn_kwargs + **conn_kwargs, ) if unlocked: ret["result"] = True else: - ret["comment"] = "Unable to find lease for path {}".format(name) + ret["comment"] = f"Unable to find lease for path {name}" return ret diff --git a/salt/states/zone.py b/salt/states/zone.py index e4a1af32a32..0c908ed34c4 100644 --- a/salt/states/zone.py +++ b/salt/states/zone.py @@ -238,7 +238,7 @@ def property_absent(name, property): elif zonecfg[property] != zonecfg_new[property]: ret["changes"][property] = zonecfg_new[property] if ret["comment"] == "": - ret["comment"] = "The property {} was cleared!".format(property) + ret["comment"] = f"The property {property} was cleared!" elif ret["comment"] == "": if ret["comment"] == "": ret["comment"] = "The property {} did not get cleared!".format( @@ -246,7 +246,7 @@ def property_absent(name, property): ) else: ret["result"] = True - ret["comment"] = "The property {} does not exist!".format(property) + ret["comment"] = f"The property {property} does not exist!" else: ## zone does not exist ret["result"] = False @@ -336,7 +336,7 @@ def resource_present( ) # note: something odd with ncpus property, we fix it here for now if key == "ncpus" and key in kwargs: - kwargs[key] = "{:.2f}".format(float(kwargs[key])) + kwargs[key] = f"{float(kwargs[key]):.2f}" if key not in resource: ret["result"] = None @@ -568,7 +568,7 @@ def booted(name, single=False): if zones[name]["state"] == "running": ## zone is running ret["result"] = True - ret["comment"] = "Zone {} already booted".format(name) + ret["comment"] = f"Zone {name} already booted" else: ## try and boot the zone if not __opts__["test"]: @@ -576,15 +576,15 @@ def booted(name, single=False): if __opts__["test"] or zoneadm_res["status"]: ret["result"] = True ret["changes"][name] = "booted" - ret["comment"] = "Zone {} booted".format(name) + ret["comment"] = f"Zone {name} booted" else: ret["result"] = False - ret["comment"] = "Failed to boot {}".format(name) + ret["comment"] = f"Failed to boot {name}" else: ## zone does not exist ret["comment"] = [] ret["comment"].append( - "The zone {} is not in the installed or booted state.".format(name) + f"The zone {name} is not in the installed or booted state." ) for zone in zones: if zones[zone]["uuid"] == name: @@ -619,7 +619,7 @@ def halted(name, graceful=True): if zones[name]["state"] != "running": ## zone is not running ret["result"] = True - ret["comment"] = "Zone {} already halted".format(name) + ret["comment"] = f"Zone {name} already halted" else: ## try and halt the zone if not __opts__["test"]: @@ -631,14 +631,14 @@ def halted(name, graceful=True): if __opts__["test"] or zoneadm_res["status"]: ret["result"] = True ret["changes"][name] = "halted" - ret["comment"] = "Zone {} halted".format(name) + ret["comment"] = f"Zone {name} halted" else: ret["result"] = False - ret["comment"] = "Failed to halt {}".format(name) + ret["comment"] = f"Failed to halt {name}" else: ## zone does not exist ret["comment"] = [] - ret["comment"].append("The zone {} is not in the installed state.".format(name)) + ret["comment"].append(f"The zone {name} is not in the installed state.") for zone in zones: if zones[zone]["uuid"] == name: ret["comment"].append( @@ -761,7 +761,7 @@ def export(name, path, replace=False): else: ## zone does not exist ret["comment"] = [] - ret["comment"].append("The zone {} does not exist.".format(name)) + ret["comment"].append(f"The zone {name} does not exist.") for zone in zones: if zones[zone]["uuid"] == name: ret["comment"].append( @@ -820,9 +820,7 @@ def import_(name, path, mode="import", nodataset=False, brand_opts=None): res_import = __salt__["zonecfg.import"](name, path) if not res_import["status"]: ret["result"] = False - ret["comment"] = ( - "Unable to import zone configuration for {}!".format(name) - ) + ret["comment"] = f"Unable to import zone configuration for {name}!" else: ret["result"] = True ret["changes"][name] = "imported" @@ -874,9 +872,7 @@ def import_(name, path, mode="import", nodataset=False, brand_opts=None): ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = False - ret["comment"] = ( - "The file {} does not exists, unable to import!".format(path) - ) + ret["comment"] = f"The file {path} does not exists, unable to import!" else: ## zone exist ret["result"] = True @@ -944,7 +940,7 @@ def present(name, brand, zonepath, properties=None, resources=None): if __opts__["test"]: ret["result"] = None ret["comment"].append( - "Cannot determine of changes would happen to the zone {}.".format(name) + f"Cannot determine of changes would happen to the zone {name}." ) ## create zone if needed @@ -959,7 +955,7 @@ def present(name, brand, zonepath, properties=None, resources=None): if res_create["status"]: ret["result"] = True ret["changes"][name] = "created" - ret["comment"].append("The zone {} was created.".format(name)) + ret["comment"].append(f"The zone {name} was created.") if not __opts__["test"]: ret["result"] = True @@ -1073,7 +1069,7 @@ def absent(name, uninstall=False): if __opts__["test"]: ret["result"] = True ret["changes"][name] = "removed" - ret["comment"] = "Zone {} was removed.".format(name) + ret["comment"] = f"Zone {name} was removed." else: ret["result"] = True if uninstall and zones[name]["state"] in ["running", "installed"]: @@ -1082,10 +1078,10 @@ def absent(name, uninstall=False): ret["result"] = res_uninstall["status"] if ret["result"]: ret["changes"][name] = "uninstalled" - ret["comment"] = "The zone {} was uninstalled.".format(name) + ret["comment"] = f"The zone {name} was uninstalled." else: ret["comment"] = [] - ret["comment"].append("Failed to uninstall zone {}!".format(name)) + ret["comment"].append(f"Failed to uninstall zone {name}!") if "message" in res_uninstall: ret["comment"].append(res_uninstall["message"]) ret["comment"] = "\n".join(ret["comment"]) @@ -1094,10 +1090,10 @@ def absent(name, uninstall=False): ret["result"] = res_detach["status"] if ret["result"]: ret["changes"][name] = "detached" - ret["comment"] = "The zone {} was detached.".format(name) + ret["comment"] = f"The zone {name} was detached." else: ret["comment"] = [] - ret["comment"].append("Failed to detach zone {}!".format(name)) + ret["comment"].append(f"Failed to detach zone {name}!") if "message" in res_detach: ret["comment"].append(res_detach["message"]) ret["comment"] = "\n".join(ret["comment"]) @@ -1106,16 +1102,16 @@ def absent(name, uninstall=False): ret["result"] = res_delete["status"] if ret["result"]: ret["changes"][name] = "deleted" - ret["comment"] = "The zone {} was delete.".format(name) + ret["comment"] = f"The zone {name} was delete." else: ret["comment"] = [] - ret["comment"].append("Failed to delete zone {}!".format(name)) + ret["comment"].append(f"Failed to delete zone {name}!") if "message" in res_delete: ret["comment"].append(res_delete["message"]) ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = True - ret["comment"] = "Zone {} does not exist.".format(name) + ret["comment"] = f"Zone {name} does not exist." return ret @@ -1142,19 +1138,19 @@ def attached(name, force=False): ret["result"] = res_attach["status"] if ret["result"]: ret["changes"][name] = "attached" - ret["comment"] = "The zone {} was attached.".format(name) + ret["comment"] = f"The zone {name} was attached." else: ret["comment"] = [] - ret["comment"].append("Failed to attach zone {}!".format(name)) + ret["comment"].append(f"Failed to attach zone {name}!") if "message" in res_attach: ret["comment"].append(res_attach["message"]) ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = True - ret["comment"] = "zone {} already attached.".format(name) + ret["comment"] = f"zone {name} already attached." else: ret["result"] = False - ret["comment"] = "zone {} is not configured!".format(name) + ret["comment"] = f"zone {name} is not configured!" return ret @@ -1179,20 +1175,20 @@ def detached(name): ret["result"] = res_detach["status"] if ret["result"]: ret["changes"][name] = "detached" - ret["comment"] = "The zone {} was detached.".format(name) + ret["comment"] = f"The zone {name} was detached." else: ret["comment"] = [] - ret["comment"].append("Failed to detach zone {}!".format(name)) + ret["comment"].append(f"Failed to detach zone {name}!") if "message" in res_detach: ret["comment"].append(res_detach["message"]) ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = True - ret["comment"] = "zone {} already detached.".format(name) + ret["comment"] = f"zone {name} already detached." else: ## note: a non existing zone is not attached, we do not consider this a failure ret["result"] = True - ret["comment"] = "zone {} is not configured!".format(name) + ret["comment"] = f"zone {name} is not configured!" return ret @@ -1221,19 +1217,19 @@ def installed(name, nodataset=False, brand_opts=None): ret["result"] = res_install["status"] if ret["result"]: ret["changes"][name] = "installed" - ret["comment"] = "The zone {} was installed.".format(name) + ret["comment"] = f"The zone {name} was installed." else: ret["comment"] = [] - ret["comment"].append("Failed to install zone {}!".format(name)) + ret["comment"].append(f"Failed to install zone {name}!") if "message" in res_install: ret["comment"].append(res_install["message"]) ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = True - ret["comment"] = "zone {} already installed.".format(name) + ret["comment"] = f"zone {name} already installed." else: ret["result"] = False - ret["comment"] = "zone {} is not configured!".format(name) + ret["comment"] = f"zone {name} is not configured!" return ret @@ -1258,19 +1254,19 @@ def uninstalled(name): ret["result"] = res_uninstall["status"] if ret["result"]: ret["changes"][name] = "uninstalled" - ret["comment"] = "The zone {} was uninstalled.".format(name) + ret["comment"] = f"The zone {name} was uninstalled." else: ret["comment"] = [] - ret["comment"].append("Failed to uninstall zone {}!".format(name)) + ret["comment"].append(f"Failed to uninstall zone {name}!") if "message" in res_uninstall: ret["comment"].append(res_uninstall["message"]) ret["comment"] = "\n".join(ret["comment"]) else: ret["result"] = True - ret["comment"] = "zone {} already uninstalled.".format(name) + ret["comment"] = f"zone {name} already uninstalled." else: ## note: a non existing zone is not installed, we do not consider this a failure ret["result"] = True - ret["comment"] = "zone {} is not configured!".format(name) + ret["comment"] = f"zone {name} is not configured!" return ret diff --git a/salt/states/zookeeper.py b/salt/states/zookeeper.py index 2f629afa76b..e6674e9911b 100644 --- a/salt/states/zookeeper.py +++ b/salt/states/zookeeper.py @@ -133,7 +133,7 @@ def present( ret = { "name": name, "result": False, - "comment": "Failed to setup znode {}".format(name), + "comment": f"Failed to setup znode {name}", "changes": {}, } connkwargs = { @@ -161,7 +161,7 @@ def present( return ret elif __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Znode {} is will be updated".format(name) + ret["comment"] = f"Znode {name} is will be updated" ret["changes"]["old"] = {} ret["changes"]["new"] = {} if value != cur_value: @@ -189,12 +189,12 @@ def present( ret["changes"] = changes if value_result and acl_result: ret["result"] = True - ret["comment"] = "Znode {} successfully updated".format(name) + ret["comment"] = f"Znode {name} successfully updated" return ret if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "{} is will be created".format(name) + ret["comment"] = f"{name} is will be created" ret["changes"]["old"] = {} ret["changes"]["new"] = {} ret["changes"]["new"]["acls"] = chk_acls @@ -219,7 +219,7 @@ def present( ret["changes"] = changes if value_result and acl_result: ret["result"] = True - ret["comment"] = "Znode {} successfully created".format(name) + ret["comment"] = f"Znode {name} successfully created" return ret @@ -277,7 +277,7 @@ def absent( ret = { "name": name, "result": False, - "comment": "Failed to delete znode {}".format(name), + "comment": f"Failed to delete znode {name}", "changes": {}, } connkwargs = { @@ -291,7 +291,7 @@ def absent( if __salt__["zookeeper.exists"](name, **connkwargs) is False: ret["result"] = True - ret["comment"] = "Znode {} does not exist".format(name) + ret["comment"] = f"Znode {name} does not exist" return ret changes = {} @@ -302,7 +302,7 @@ def absent( if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Znode {} will be removed".format(name) + ret["comment"] = f"Znode {name} will be removed" ret["changes"]["old"] = changes return ret @@ -310,7 +310,7 @@ def absent( if __salt__["zookeeper.exists"](name, **connkwargs) is False: ret["result"] = True - ret["comment"] = "Znode {} has been removed".format(name) + ret["comment"] = f"Znode {name} has been removed" ret["changes"]["old"] = changes return ret @@ -374,7 +374,7 @@ def acls( ret = { "name": name, "result": False, - "comment": "Failed to set acls on znode {}".format(name), + "comment": f"Failed to set acls on znode {name}", "changes": {}, } connkwargs = { @@ -396,12 +396,12 @@ def acls( cur_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) if _check_acls(cur_acls, chk_acls): ret["result"] = True - ret["comment"] = "Znode {} acls already set".format(name) + ret["comment"] = f"Znode {name} acls already set" return ret if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Znode {} acls will be updated".format(name) + ret["comment"] = f"Znode {name} acls will be updated" ret["changes"]["old"] = cur_acls ret["changes"]["new"] = chk_acls return ret @@ -412,7 +412,7 @@ def acls( ret["changes"] = {"old": cur_acls, "new": new_acls} if _check_acls(new_acls, chk_acls): ret["result"] = True - ret["comment"] = "Znode {} acls updated".format(name) + ret["comment"] = f"Znode {name} acls updated" return ret - ret["comment"] = "Znode {} acls failed to update".format(name) + ret["comment"] = f"Znode {name} acls failed to update" return ret diff --git a/salt/states/zpool.py b/salt/states/zpool.py index 4c8c7b4f3af..ef7407a532a 100644 --- a/salt/states/zpool.py +++ b/salt/states/zpool.py @@ -361,7 +361,7 @@ def present( ret["result"] = mod_res["imported"] if ret["result"]: ret["changes"][name] = "imported" - ret["comment"] = "storage pool {} was imported".format(name) + ret["comment"] = f"storage pool {name} was imported" # create pool if not ret["result"] and vdevs: @@ -372,17 +372,17 @@ def present( *vdevs, force=config["force"], properties=properties, - filesystem_properties=filesystem_properties + filesystem_properties=filesystem_properties, ) ret["result"] = mod_res["created"] if ret["result"]: ret["changes"][name] = "created" - ret["comment"] = "storage pool {} was created".format(name) + ret["comment"] = f"storage pool {name} was created" elif "error" in mod_res: ret["comment"] = mod_res["error"] else: - ret["comment"] = "could not create storage pool {}".format(name) + ret["comment"] = f"could not create storage pool {name}" # give up, we cannot import the pool and we do not have a layout to create it if not ret["result"] and not vdevs: @@ -439,6 +439,6 @@ def absent(name, export=False, force=False): else: # we are looking good ret["result"] = True - ret["comment"] = "storage pool {} is absent".format(name) + ret["comment"] = f"storage pool {name} is absent" return ret diff --git a/salt/template.py b/salt/template.py index 1836259257f..7cdd8ed2055 100644 --- a/salt/template.py +++ b/salt/template.py @@ -34,7 +34,7 @@ def compile_template( sls="", input_data="", context=None, - **kwargs + **kwargs, ): """ Take the path to a template and return the high data structure @@ -209,7 +209,7 @@ for comb in ( ): fmt, tmpl = comb.split("_") - OLD_STYLE_RENDERERS[comb] = "{}|{}".format(tmpl, fmt) + OLD_STYLE_RENDERERS[comb] = f"{tmpl}|{fmt}" def check_render_pipe_str(pipestr, renderers, blacklist, whitelist): diff --git a/salt/thorium/__init__.py b/salt/thorium/__init__.py index 97b37d75b95..6dffc972a07 100644 --- a/salt/thorium/__init__.py +++ b/salt/thorium/__init__.py @@ -50,7 +50,7 @@ class ThorState(salt.state.HighState): regdata = {} if self.reg_ret is not None: try: - regdata = self.returners["{}.load_reg".format(self.reg_ret)]() + regdata = self.returners[f"{self.reg_ret}.load_reg"]() except Exception as exc: # pylint: disable=broad-except log.error(exc) @@ -68,7 +68,7 @@ class ThorState(salt.state.HighState): if not minions: return cache for minion in minions: - total = self.cache.fetch("minions/{}".format(minion), "data") + total = self.cache.fetch(f"minions/{minion}", "data") if "pillar" in total: if self.pillar_keys: @@ -176,5 +176,5 @@ class ThorState(salt.state.HighState): cache = self.gather_cache() chunks = self.get_chunks() if self.reg_ret is not None: - self.returners["{}.save_reg".format(self.reg_ret)](chunks) + self.returners[f"{self.reg_ret}.save_reg"](chunks) r_start = time.time() diff --git a/salt/thorium/calc.py b/salt/thorium/calc.py index b01b4d37c58..d5487966a54 100644 --- a/salt/thorium/calc.py +++ b/salt/thorium/calc.py @@ -48,7 +48,7 @@ def calc(name, num, oper, minimum=0, maximum=0, ref=None): """ ret = {"name": name, "changes": {}, "comment": "", "result": True} if name not in __reg__: - ret["comment"] = "{} not found in register".format(name) + ret["comment"] = f"{name} not found in register" ret["result"] = False def opadd(vals): diff --git a/salt/thorium/check.py b/salt/thorium/check.py index ee41cfb9034..48149f3c426 100644 --- a/salt/thorium/check.py +++ b/salt/thorium/check.py @@ -35,7 +35,7 @@ def gt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] > value: ret["result"] = True @@ -65,7 +65,7 @@ def gte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] >= value: ret["result"] = True @@ -95,7 +95,7 @@ def lt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] < value: ret["result"] = True @@ -125,7 +125,7 @@ def lte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] <= value: ret["result"] = True @@ -155,7 +155,7 @@ def eq(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] == value: ret["result"] = True @@ -185,7 +185,7 @@ def ne(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] != value: ret["result"] = True @@ -224,7 +224,7 @@ def contains( ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret try: count_compare = ( @@ -305,7 +305,7 @@ def len_gt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) > value: ret["result"] = True @@ -335,7 +335,7 @@ def len_gte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) >= value: ret["result"] = True @@ -365,7 +365,7 @@ def len_lt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) < value: ret["result"] = True @@ -395,7 +395,7 @@ def len_lte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) <= value: ret["result"] = True @@ -425,7 +425,7 @@ def len_eq(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] == value: ret["result"] = True @@ -455,7 +455,7 @@ def len_ne(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) != value: ret["result"] = True diff --git a/salt/tokens/localfs.py b/salt/tokens/localfs.py index 8e739ae11be..93cfffa934f 100644 --- a/salt/tokens/localfs.py +++ b/salt/tokens/localfs.py @@ -30,7 +30,7 @@ def mk_token(opts, tdata): hash_type = getattr(hashlib, opts.get("hash_type", DEFAULT_HASH_TYPE)) tok = str(hash_type(os.urandom(512)).hexdigest()) t_path = os.path.join(opts["token_dir"], tok) - temp_t_path = "{}.tmp".format(t_path) + temp_t_path = f"{t_path}.tmp" while os.path.isfile(t_path): tok = str(hash_type(os.urandom(512)).hexdigest()) t_path = os.path.join(opts["token_dir"], tok) diff --git a/salt/tops/reclass_adapter.py b/salt/tops/reclass_adapter.py index 65fe33b0a5f..9b04bb55b58 100644 --- a/salt/tops/reclass_adapter.py +++ b/salt/tops/reclass_adapter.py @@ -120,7 +120,7 @@ def top(**kwargs): except ImportError as e: if "reclass" in str(e): raise SaltInvocationError( - "master_tops.reclass: cannot find reclass module in {}".format(sys.path) + f"master_tops.reclass: cannot find reclass module in {sys.path}" ) else: raise @@ -128,9 +128,7 @@ def top(**kwargs): except TypeError as e: if "unexpected keyword argument" in str(e): arg = str(e).split()[-1] - raise SaltInvocationError( - "master_tops.reclass: unexpected option: {}".format(arg) - ) + raise SaltInvocationError(f"master_tops.reclass: unexpected option: {arg}") else: raise @@ -143,4 +141,4 @@ def top(**kwargs): raise except ReclassException as e: - raise SaltInvocationError("master_tops.reclass: {}".format(str(e))) + raise SaltInvocationError(f"master_tops.reclass: {str(e)}") diff --git a/salt/transport/base.py b/salt/transport/base.py index 2e4f68e4cc0..00e9315db3c 100644 --- a/salt/transport/base.py +++ b/salt/transport/base.py @@ -74,7 +74,7 @@ def publish_server(opts, **kwargs): import salt.transport.local return salt.transport.local.LocalPubServerChannel(opts, **kwargs) - raise Exception("Transport type not found: {}".format(ttype)) + raise Exception(f"Transport type not found: {ttype}") def publish_client(opts, io_loop): @@ -94,7 +94,7 @@ def publish_client(opts, io_loop): import salt.transport.tcp return salt.transport.tcp.TCPPubClient(opts, io_loop) - raise Exception("Transport type not found: {}".format(ttype)) + raise Exception(f"Transport type not found: {ttype}") class TransportWarning(Warning): diff --git a/salt/transport/zeromq.py b/salt/transport/zeromq.py index e2278dff055..64776d204da 100644 --- a/salt/transport/zeromq.py +++ b/salt/transport/zeromq.py @@ -455,7 +455,7 @@ class RequestServer(salt.transport.base.DaemonizedRequestServer): signal.signal(signal.SIGTERM, self._handle_signals) def _handle_signals(self, signum, sigframe): - msg = "{} received a ".format(self.__class__.__name__) + msg = f"{self.__class__.__name__} received a " if signum == signal.SIGINT: msg += "SIGINT" elif signum == signal.SIGTERM: diff --git a/salt/utils/asynchronous.py b/salt/utils/asynchronous.py index b156c020ab3..f0048ff1910 100644 --- a/salt/utils/asynchronous.py +++ b/salt/utils/asynchronous.py @@ -81,7 +81,7 @@ class SyncWrapper: self._async_methods += self.obj._coroutines def __repr__(self): - return " self.size: self.sweep() - regex = re.compile("{}{}{}".format(self.prepend, pattern, self.append)) + regex = re.compile(f"{self.prepend}{pattern}{self.append}") self.cache[pattern] = [1, regex, pattern, time.time()] return regex @@ -298,7 +298,7 @@ class ContextCache: Create a context cache """ self.opts = opts - self.cache_path = os.path.join(opts["cachedir"], "context", "{}.p".format(name)) + self.cache_path = os.path.join(opts["cachedir"], "context", f"{name}.p") def cache_context(self, context): """ diff --git a/salt/utils/color.py b/salt/utils/color.py index 37da77472a6..8ef55ccad20 100644 --- a/salt/utils/color.py +++ b/salt/utils/color.py @@ -27,7 +27,7 @@ def get_color_theme(theme): colors = salt.utils.data.decode(salt.utils.yaml.safe_load(fp_)) ret = {} for color in colors: - ret[color] = "\033[{}m".format(colors[color]) + ret[color] = f"\033[{colors[color]}m" if not isinstance(colors, dict): log.warning("The theme file %s is not a dict", theme) return {} diff --git a/salt/utils/configcomparer.py b/salt/utils/configcomparer.py index ef67e65e5f1..1ab770a5a96 100644 --- a/salt/utils/configcomparer.py +++ b/salt/utils/configcomparer.py @@ -32,7 +32,7 @@ def compare_and_update_config(config, update_config, changes, namespace=""): for key, value in config.items(): _namespace = key if namespace: - _namespace = "{}.{}".format(namespace, _namespace) + _namespace = f"{namespace}.{_namespace}" update_config[key] = compare_and_update_config( value, update_config.get(key, None), @@ -61,9 +61,9 @@ def compare_and_update_config(config, update_config, changes, namespace=""): # iterate through config list, ensuring that each index in the # update_config list is the same for idx, item in enumerate(config): - _namespace = "[{}]".format(idx) + _namespace = f"[{idx}]" if namespace: - _namespace = "{}{}".format(namespace, _namespace) + _namespace = f"{namespace}{_namespace}" _update = None if len(update_config) > idx: _update = update_config[idx] @@ -86,9 +86,9 @@ def compare_and_update_config(config, update_config, changes, namespace=""): for idx, old_item in enumerate(update_config): if idx < len(config): continue - _namespace = "[{}]".format(idx) + _namespace = f"[{idx}]" if namespace: - _namespace = "{}{}".format(namespace, _namespace) + _namespace = f"{namespace}{_namespace}" changes[_namespace] = { "new": None, "old": old_item, diff --git a/salt/utils/crypt.py b/salt/utils/crypt.py index de892d55597..044eebe7a77 100644 --- a/salt/utils/crypt.py +++ b/salt/utils/crypt.py @@ -112,9 +112,7 @@ def decrypt( rend_func = renderers.get(rend) if rend_func is None: - raise SaltInvocationError( - "Decryption renderer '{}' is not available".format(rend) - ) + raise SaltInvocationError(f"Decryption renderer '{rend}' is not available") return rend_func(data, translate_newlines=translate_newlines) @@ -160,7 +158,7 @@ def pem_finger(path=None, key=None, sum_type="sha256"): for ind, _ in enumerate(pre): if ind % 2: # Is odd - finger += "{}:".format(pre[ind]) + finger += f"{pre[ind]}:" else: finger += pre[ind] return finger.rstrip(":") diff --git a/salt/utils/dateutils.py b/salt/utils/dateutils.py index e219753da6a..2b680672eb6 100644 --- a/salt/utils/dateutils.py +++ b/salt/utils/dateutils.py @@ -46,11 +46,9 @@ def date_cast(date): return datetime.datetime.fromtimestamp(date) except Exception: # pylint: disable=broad-except if HAS_TIMELIB: - raise ValueError("Unable to parse {}".format(date)) + raise ValueError(f"Unable to parse {date}") - raise RuntimeError( - "Unable to parse {}. Consider installing timelib".format(date) - ) + raise RuntimeError(f"Unable to parse {date}. Consider installing timelib") @jinja_filter("date_format") diff --git a/salt/utils/debug.py b/salt/utils/debug.py index e1fda0a8aec..e74bad3dda2 100644 --- a/salt/utils/debug.py +++ b/salt/utils/debug.py @@ -34,7 +34,7 @@ def _handle_sigusr1(sig, stack): output = sys.stderr _makepretty(output, stack) else: - filename = "salt-debug-{}.log".format(int(time.time())) + filename = f"salt-debug-{int(time.time())}.log" destfile = os.path.join(tempfile.gettempdir(), filename) with salt.utils.files.fopen(destfile, "w") as output: _makepretty(output, stack) @@ -50,11 +50,11 @@ def _handle_sigusr2(sig, stack): return if yappi.is_running(): yappi.stop() - filename = "callgrind.salt-{}-{}".format(int(time.time()), os.getpid()) + filename = f"callgrind.salt-{int(time.time())}-{os.getpid()}" destfile = os.path.join(tempfile.gettempdir(), filename) yappi.get_func_stats().save(destfile, type="CALLGRIND") if sys.stderr.isatty(): - sys.stderr.write("Saved profiling data to: {}\n".format(destfile)) + sys.stderr.write(f"Saved profiling data to: {destfile}\n") yappi.clear_stats() else: if sys.stderr.isatty(): @@ -135,5 +135,5 @@ def caller_name(skip=2, include_lineno=False): del parentframe fullname = ".".join(name) if include_lineno and lineno: - fullname += ":{}".format(lineno) + fullname += f":{lineno}" return fullname diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py index b849ca31145..4ddf359d23c 100644 --- a/salt/utils/decorators/__init__.py +++ b/salt/utils/decorators/__init__.py @@ -116,7 +116,7 @@ class Depends: @staticmethod def run_command(dependency, mod_name, func_name): - full_name = "{}.{}".format(mod_name, func_name) + full_name = f"{mod_name}.{func_name}" log.trace("Running '%s' for '%s'", dependency, full_name) if IS_WINDOWS: args = salt.utils.args.shlex_split(dependency, posix=False) @@ -229,7 +229,7 @@ class Depends: except (AttributeError, KeyError): pass - mod_key = "{}.{}".format(mod_name, func_name) + mod_key = f"{mod_name}.{func_name}" # if we don't have this module loaded, skip it! if mod_key not in functions: @@ -264,7 +264,7 @@ def timing(function): mod_name = function.__module__[16:] else: mod_name = function.__module__ - fstr = "Function %s.%s took %.{}f seconds to execute".format(sys.float_info.dig) + fstr = f"Function %s.%s took %.{sys.float_info.dig}f seconds to execute" log.profile(fstr, mod_name, function.__name__, end_time - start_time) return ret @@ -291,9 +291,7 @@ def memoize(func): else: str_args.append(arg) - args_ = ",".join( - list(str_args) + ["{}={}".format(k, kwargs[k]) for k in sorted(kwargs)] - ) + args_ = ",".join(list(str_args) + [f"{k}={kwargs[k]}" for k in sorted(kwargs)]) if args_ not in cache: cache[args_] = func(*args, **kwargs) return cache[args_] @@ -624,9 +622,7 @@ class _WithDeprecated(_DeprecationDecorator): "Function '{}' is mentioned both in deprecated " "and superseded sections. Please remove any of that.".format(full_name) ) - old_function = self._globals.get( - self._with_name or "_{}".format(function.__name__) - ) + old_function = self._globals.get(self._with_name or f"_{function.__name__}") if self._policy == self.OPT_IN: self._function = function if use_superseded else old_function else: diff --git a/salt/utils/decorators/path.py b/salt/utils/decorators/path.py index 254593553a3..af08960b3e5 100644 --- a/salt/utils/decorators/path.py +++ b/salt/utils/decorators/path.py @@ -18,7 +18,7 @@ def which(exe): def wrapped(*args, **kwargs): if salt.utils.path.which(exe) is None: raise CommandNotFoundError( - "The '{}' binary was not found in $PATH.".format(exe) + f"The '{exe}' binary was not found in $PATH." ) return function(*args, **kwargs) @@ -38,7 +38,7 @@ def which_bin(exes): if salt.utils.path.which_bin(exes) is None: raise CommandNotFoundError( "None of provided binaries({}) were found in $PATH.".format( - ["'{}'".format(exe) for exe in exes] + [f"'{exe}'" for exe in exes] ) ) return function(*args, **kwargs) diff --git a/salt/utils/decorators/state.py b/salt/utils/decorators/state.py index 569df725f85..0d0fbf4254f 100644 --- a/salt/utils/decorators/state.py +++ b/salt/utils/decorators/state.py @@ -17,7 +17,7 @@ class OutputUnifier: self.policies = [] for pls in policies: if not hasattr(self, pls): - raise SaltException("Unknown policy: {}".format(pls)) + raise SaltException(f"Unknown policy: {pls}") else: self.policies.append(getattr(self, pls)) @@ -35,7 +35,7 @@ class OutputUnifier: "result": False, "name": "later", "changes": {}, - "comment": "An exception occurred in this state: {}".format(exc), + "comment": f"An exception occurred in this state: {exc}", } return data diff --git a/salt/utils/dockermod/translate/container.py b/salt/utils/dockermod/translate/container.py index 8dd21b7dc9f..6d8e012f9ad 100644 --- a/salt/utils/dockermod/translate/container.py +++ b/salt/utils/dockermod/translate/container.py @@ -137,7 +137,7 @@ def binds(val, **kwargs): # pylint: disable=unused-argument val = helpers.split(val) except AttributeError: raise SaltInvocationError( - "'{}' is not a dictionary or list of bind definitions".format(val) + f"'{val}' is not a dictionary or list of bind definitions" ) return val @@ -503,9 +503,7 @@ def ports(val, **kwargs): # pylint: disable=unused-argument if isinstance(val, int): val = [val] else: - raise SaltInvocationError( - "'{}' is not a valid port definition".format(val) - ) + raise SaltInvocationError(f"'{val}' is not a valid port definition") new_ports = set() for item in val: if isinstance(item, int): @@ -514,9 +512,7 @@ def ports(val, **kwargs): # pylint: disable=unused-argument try: item, _, proto = item.partition("/") except AttributeError: - raise SaltInvocationError( - "'{}' is not a valid port definition".format(item) - ) + raise SaltInvocationError(f"'{item}' is not a valid port definition") try: range_start, range_end = helpers.get_port_range(item) except ValueError as exc: @@ -625,7 +621,7 @@ def ulimits(val, **kwargs): # pylint: disable=unused-argument } except (TypeError, ValueError): raise SaltInvocationError( - "Limit '{}' contains non-numeric value(s)".format(item) + f"Limit '{item}' contains non-numeric value(s)" ) return val @@ -647,7 +643,7 @@ def user(val, **kwargs): # pylint: disable=unused-argument if not isinstance(val, (int, str)): raise SaltInvocationError("Value must be a username or uid") elif isinstance(val, int) and val < 0: - raise SaltInvocationError("'{}' is an invalid uid".format(val)) + raise SaltInvocationError(f"'{val}' is an invalid uid") return val @@ -666,7 +662,7 @@ def volumes(val, **kwargs): # pylint: disable=unused-argument val = helpers.translate_stringlist(val) for item in val: if not os.path.isabs(item): - raise SaltInvocationError("'{}' is not an absolute path".format(item)) + raise SaltInvocationError(f"'{item}' is not an absolute path") return val @@ -683,5 +679,5 @@ def working_dir(val, **kwargs): # pylint: disable=unused-argument except AttributeError: is_abs = False if not is_abs: - raise SaltInvocationError("'{}' is not an absolute path".format(val)) + raise SaltInvocationError(f"'{val}' is not an absolute path") return val diff --git a/salt/utils/dockermod/translate/helpers.py b/salt/utils/dockermod/translate/helpers.py index 2b090de0d78..948beb41e94 100644 --- a/salt/utils/dockermod/translate/helpers.py +++ b/salt/utils/dockermod/translate/helpers.py @@ -78,7 +78,7 @@ def get_port_range(port_def): "port range ({})".format(range_start, range_end) ) else: - msg = "'{}' is non-numeric or an invalid port range".format(port_def) + msg = f"'{port_def}' is non-numeric or an invalid port range" raise ValueError(msg) else: return range_start, range_end @@ -113,7 +113,7 @@ def map_vals(val, *names, **extra_opts): ( expected_num_elements if fill is NOTSET - else "up to {}".format(expected_num_elements) + else f"up to {expected_num_elements}" ), ) ) @@ -124,7 +124,7 @@ def map_vals(val, *names, **extra_opts): def validate_ip(val): try: if not salt.utils.network.is_ip(val): - raise SaltInvocationError("'{}' is not a valid IP address".format(val)) + raise SaltInvocationError(f"'{val}' is not a valid IP address") except RuntimeError: pass @@ -132,7 +132,7 @@ def validate_ip(val): def validate_subnet(val): try: if not salt.utils.network.is_subnet(val): - raise SaltInvocationError("'{}' is not a valid subnet".format(val)) + raise SaltInvocationError(f"'{val}' is not a valid subnet") except RuntimeError: pass @@ -146,7 +146,7 @@ def translate_int(val): try: val = int(val) except (TypeError, ValueError): - raise SaltInvocationError("'{}' is not an integer".format(val)) + raise SaltInvocationError(f"'{val}' is not an integer") return val @@ -159,7 +159,7 @@ def translate_dict(val): Not really translating, just raising an exception if it's not a dict """ if not isinstance(val, dict): - raise SaltInvocationError("'{}' is not a dictionary".format(val)) + raise SaltInvocationError(f"'{val}' is not a dictionary") return val @@ -257,9 +257,7 @@ def translate_key_val(val, delimiter="="): try: lvalue, rvalue = split(item, delimiter, 1) except (AttributeError, TypeError, ValueError): - raise SaltInvocationError( - "'{}' is not a key{}value pair".format(item, delimiter) - ) + raise SaltInvocationError(f"'{item}' is not a key{delimiter}value pair") new_val[lvalue] = rvalue return new_val diff --git a/salt/utils/etcd_util.py b/salt/utils/etcd_util.py index 512b4a6583d..25de49cf80f 100644 --- a/salt/utils/etcd_util.py +++ b/salt/utils/etcd_util.py @@ -143,7 +143,7 @@ class EtcdBase: ca=None, client_key=None, client_cert=None, - **kwargs + **kwargs, ): if not kwargs.get("has_etcd_opts", False): etcd_opts = _get_etcd_opts(opts, profile) @@ -201,7 +201,7 @@ class EtcdBase: wait=False, timeout=None, start_revision=None, - **kwargs + **kwargs, ): """ Read a value of a key. @@ -242,9 +242,9 @@ class EtcdBase: for k, v in data.items(): k = k.strip("/") if path: - p = "/{}/{}".format(path, k) + p = f"/{path}/{k}" else: - p = "/{}".format(k) + p = f"/{k}" if isinstance(v, dict): ret = self._flatten(v, p) flat.update(ret) @@ -441,7 +441,7 @@ class EtcdClient(EtcdBase): wait=False, timeout=None, start_revision=None, - **kwargs + **kwargs, ): recursive = kwargs.pop("recursive", None) wait_index = kwargs.pop("waitIndex", None) @@ -487,7 +487,7 @@ class EtcdClient(EtcdBase): if wait: # Wait timeouts will throw ReadTimeoutError, which isn't bad log.debug("etcd: Timed out while executing a wait") - raise EtcdUtilWatchTimeout("Watch on {} timed out".format(key)) + raise EtcdUtilWatchTimeout(f"Watch on {key} timed out") log.error("etcd: Timed out") raise etcd.EtcdConnectionFailed("Connection failed") except MaxRetryError as err: @@ -601,7 +601,7 @@ class EtcdClient(EtcdBase): if item.dir is True: if item.key == path: continue - dir_name = "{}/".format(item.key) + dir_name = f"{item.key}/" ret[dir_name] = {} else: ret[item.key] = item.value @@ -677,7 +677,7 @@ class EtcdClientV3(EtcdBase): raw_keys=False, raw_values=False, unicode_errors=None, - **kwargs + **kwargs, ): if not HAS_ETCD_V3: raise EtcdLibraryNotInstalled("Don't have etcd3-py, need to install it.") @@ -780,7 +780,7 @@ class EtcdClientV3(EtcdBase): wait=False, timeout=None, start_revision=None, - **kwargs + **kwargs, ): recursive = kwargs.pop("recursive", None) wait_index = kwargs.pop("waitIndex", None) diff --git a/salt/utils/event.py b/salt/utils/event.py index a1de7e5ab4f..983402875d6 100644 --- a/salt/utils/event.py +++ b/salt/utils/event.py @@ -306,12 +306,8 @@ class SaltEvent: id_hash = hash_type( salt.utils.stringutils.to_bytes(minion_id) ).hexdigest()[:10] - puburi = os.path.join( - sock_dir, "minion_event_{}_pub.ipc".format(id_hash) - ) - pulluri = os.path.join( - sock_dir, "minion_event_{}_pull.ipc".format(id_hash) - ) + puburi = os.path.join(sock_dir, f"minion_event_{id_hash}_pub.ipc") + pulluri = os.path.join(sock_dir, f"minion_event_{id_hash}_pull.ipc") log.debug("%s PUB socket URI: %s", self.__class__.__name__, puburi) log.debug("%s PULL socket URI: %s", self.__class__.__name__, pulluri) return puburi, pulluri @@ -467,7 +463,7 @@ class SaltEvent: def _get_match_func(self, match_type=None): if match_type is None: match_type = self.opts["event_match_type"] - return getattr(self, "_match_tag_{}".format(match_type), None) + return getattr(self, f"_match_tag_{match_type}", None) def _check_pending(self, tag, match_func=None): """Check the pending_events list for events that match the tag @@ -743,7 +739,7 @@ class SaltEvent: raise ValueError("Empty tag.") if not isinstance(data, MutableMapping): # data must be dict - raise ValueError("Dict object expected, not '{}'.".format(data)) + raise ValueError(f"Dict object expected, not '{data}'.") if not self.cpush: if timeout is not None: @@ -795,7 +791,7 @@ class SaltEvent: raise ValueError("Empty tag.") if not isinstance(data, MutableMapping): # data must be dict - raise ValueError("Dict object expected, not '{}'.".format(data)) + raise ValueError(f"Dict object expected, not '{data}'.") if not self.cpush: if timeout is not None: @@ -894,13 +890,11 @@ class SaltEvent: data["retcode"] = retcode tags = tag.split("_|-") if data.get("result") is False: - self.fire_event( - data, "{}.{}".format(tags[0], tags[-1]) - ) # old dup event + self.fire_event(data, f"{tags[0]}.{tags[-1]}") # old dup event data["jid"] = load["jid"] data["id"] = load["id"] data["success"] = False - data["return"] = "Error: {}.{}".format(tags[0], tags[-1]) + data["return"] = f"Error: {tags[0]}.{tags[-1]}" data["fun"] = fun if "user" in load: data["user"] = load["user"] @@ -1079,12 +1073,12 @@ class AsyncEventPublisher: salt.utils.stringutils.to_bytes(self.opts["id"]) ).hexdigest()[:10] epub_sock_path = os.path.join( - self.opts["sock_dir"], "minion_event_{}_pub.ipc".format(id_hash) + self.opts["sock_dir"], f"minion_event_{id_hash}_pub.ipc" ) if os.path.exists(epub_sock_path): os.unlink(epub_sock_path) epull_sock_path = os.path.join( - self.opts["sock_dir"], "minion_event_{}_pull.ipc".format(id_hash) + self.opts["sock_dir"], f"minion_event_{id_hash}_pull.ipc" ) if os.path.exists(epull_sock_path): os.unlink(epull_sock_path) @@ -1297,7 +1291,7 @@ class EventReturn(salt.utils.process.SignalHandlingProcess): # Multiple event returners for r in self.opts["event_return"]: log.debug("Calling event returner %s, one of many.", r) - event_return = "{}.event_return".format(r) + event_return = f"{r}.event_return" self._flush_event_single(event_return) else: # Only a single event returner diff --git a/salt/utils/extend.py b/salt/utils/extend.py index 5fbef75fbed..2317feb2bf8 100644 --- a/salt/utils/extend.py +++ b/salt/utils/extend.py @@ -174,19 +174,15 @@ def _prompt_choice(var_name, options): :returns: The selected user """ choice_map = OrderedDict( - ("{}".format(i), value) - for i, value in enumerate(options, 1) - if value[0] != "test" + (f"{i}", value) for i, value in enumerate(options, 1) if value[0] != "test" ) choices = choice_map.keys() default = "1" - choice_lines = [ - "{} - {} - {}".format(c[0], c[1][0], c[1][1]) for c in choice_map.items() - ] + choice_lines = [f"{c[0]} - {c[1][0]} - {c[1][1]}" for c in choice_map.items()] prompt = "\n".join( ( - "Select {}:".format(var_name), + f"Select {var_name}:", "\n".join(choice_lines), "Choose from {}".format(", ".join(choices)), ) @@ -272,7 +268,7 @@ def run( if description is None: description = _prompt_user_variable("Short description of the module", "") - template_dir = "templates/{}".format(extension_type) + template_dir = f"templates/{extension_type}" module_name = name param_dict = { diff --git a/salt/utils/extmods.py b/salt/utils/extmods.py index a7dc265476f..f1b8a826448 100644 --- a/salt/utils/extmods.py +++ b/salt/utils/extmods.py @@ -69,7 +69,7 @@ def sync( ret = [] remote = set() source = salt.utils.url.create("_" + form) - mod_dir = os.path.join(opts["extension_modules"], "{}".format(form)) + mod_dir = os.path.join(opts["extension_modules"], f"{form}") touched = False with salt.utils.files.set_umask(0o077): try: @@ -98,7 +98,7 @@ def sync( ) ) local_cache_dir = os.path.join( - opts["cachedir"], "files", sub_env, "_{}".format(form) + opts["cachedir"], "files", sub_env, f"_{form}" ) log.debug("Local cache dir: '%s'", local_cache_dir) for fn_ in cache: @@ -127,13 +127,13 @@ def sync( if src_digest != dst_digest: # The downloaded file differs, replace! shutil.copyfile(fn_, dest) - ret.append("{}.{}".format(form, relname)) + ret.append(f"{form}.{relname}") else: dest_dir = os.path.dirname(dest) if not os.path.isdir(dest_dir): os.makedirs(dest_dir) shutil.copyfile(fn_, dest) - ret.append("{}.{}".format(form, relname)) + ret.append(f"{form}.{relname}") touched = bool(ret) if opts["clean_dynamic_modules"] is True: diff --git a/salt/utils/files.py b/salt/utils/files.py index 6a70ca6f304..e5494911c28 100644 --- a/salt/utils/files.py +++ b/salt/utils/files.py @@ -130,9 +130,9 @@ def copyfile(source, dest, backup_mode="", cachedir=""): specified cache the file. """ if not os.path.isfile(source): - raise OSError("[Errno 2] No such file or directory: {}".format(source)) + raise OSError(f"[Errno 2] No such file or directory: {source}") if not os.path.isdir(os.path.dirname(dest)): - raise OSError("[Errno 2] No such file or directory: {}".format(dest)) + raise OSError(f"[Errno 2] No such file or directory: {dest}") bname = os.path.basename(dest) dname = os.path.dirname(os.path.abspath(dest)) tgt = mkstemp(prefix=bname, dir=dname) @@ -198,9 +198,7 @@ def rename(src, dst): os.remove(dst) except OSError as exc: if exc.errno != errno.ENOENT: - raise MinionError( - "Error: Unable to remove {}: {}".format(dst, exc.strerror) - ) + raise MinionError(f"Error: Unable to remove {dst}: {exc.strerror}") os.rename(src, dst) @@ -221,9 +219,9 @@ def process_read_exception(exc, path, ignore=None): return if exc.errno == errno.ENOENT: - raise CommandExecutionError("{} does not exist".format(path)) + raise CommandExecutionError(f"{path} does not exist") elif exc.errno == errno.EACCES: - raise CommandExecutionError("Permission denied reading from {}".format(path)) + raise CommandExecutionError(f"Permission denied reading from {path}") else: raise CommandExecutionError( "Error {} encountered reading from {}: {}".format( @@ -253,7 +251,7 @@ def wait_lock(path, lock_fn=None, timeout=5, sleep=0.1, time_start=None): try: if os.path.exists(lock_fn) and not os.path.isfile(lock_fn): - _raise_error("lock_fn {} exists and is not a file".format(lock_fn)) + _raise_error(f"lock_fn {lock_fn} exists and is not a file") open_flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY while time.time() - time_start < timeout: @@ -293,9 +291,7 @@ def wait_lock(path, lock_fn=None, timeout=5, sleep=0.1, time_start=None): raise except Exception as exc: # pylint: disable=broad-except - _raise_error( - "Error encountered obtaining file lock {}: {}".format(lock_fn, exc) - ) + _raise_error(f"Error encountered obtaining file lock {lock_fn}: {exc}") finally: if obtained_lock: @@ -346,7 +342,7 @@ def fopen(*args, **kwargs): # and True are treated by Python 3's open() as file descriptors 0 # and 1, respectively. if args[0] in (0, 1, 2): - raise TypeError("{} is not a permitted file descriptor".format(args[0])) + raise TypeError(f"{args[0]} is not a permitted file descriptor") except IndexError: pass binary = None @@ -791,8 +787,8 @@ def backup_minion(path, bkroot): stamp = time.strftime("%a_%b_%d_%H-%M-%S_%Y") else: stamp = time.strftime("%a_%b_%d_%H:%M:%S_%Y") - stamp = "{}{}_{}".format(stamp[:-4], msecs, stamp[-4:]) - bkpath = os.path.join(bkroot, src_dir, "{}_{}".format(bname, stamp)) + stamp = f"{stamp[:-4]}{msecs}_{stamp[-4:]}" + bkpath = os.path.join(bkroot, src_dir, f"{bname}_{stamp}") if not os.path.isdir(os.path.dirname(bkpath)): os.makedirs(os.path.dirname(bkpath)) shutil.copyfile(path, bkpath) diff --git a/salt/utils/find.py b/salt/utils/find.py index f6fc3bf9250..6c1b25631b3 100644 --- a/salt/utils/find.py +++ b/salt/utils/find.py @@ -162,7 +162,7 @@ def _parse_interval(value): """ match = _INTERVAL_REGEX.match(str(value)) if match is None: - raise ValueError("invalid time interval: '{}'".format(value)) + raise ValueError(f"invalid time interval: '{value}'") result = 0 resolution = None @@ -211,7 +211,7 @@ def _parse_size(value): try: num = int(float(scalar) * multiplier) except ValueError: - raise ValueError('invalid size: "{}"'.format(value)) + raise ValueError(f'invalid size: "{value}"') if style == "-": min_size = 0 @@ -279,7 +279,7 @@ class RegexOption(Option): try: self.regex = re.compile(value) except re.error: - raise ValueError('invalid regular expression: "{}"'.format(value)) + raise ValueError(f'invalid regular expression: "{value}"') def match(self, dirname, filename, fstat): return self.regex.match(filename) @@ -296,7 +296,7 @@ class IregexOption(Option): try: self.regex = re.compile(value, re.IGNORECASE) except re.error: - raise ValueError('invalid regular expression: "{}"'.format(value)) + raise ValueError(f'invalid regular expression: "{value}"') def match(self, dirname, filename, fstat): return self.regex.match(filename) @@ -325,7 +325,7 @@ class TypeOption(Option): try: self.ftypes.add(_FILE_TYPES[ftype]) except KeyError: - raise ValueError('invalid file type "{}"'.format(ftype)) + raise ValueError(f'invalid file type "{ftype}"') def requires(self): return _REQUIRES_STAT @@ -351,7 +351,7 @@ class OwnerOption(Option): try: self.uids.add(pwd.getpwnam(value).pw_uid) except KeyError: - raise ValueError('no such user "{}"'.format(name)) + raise ValueError(f'no such user "{name}"') def requires(self): return _REQUIRES_STAT @@ -377,7 +377,7 @@ class GroupOption(Option): try: self.gids.add(grp.getgrnam(name).gr_gid) except KeyError: - raise ValueError('no such group "{}"'.format(name)) + raise ValueError(f'no such group "{name}"') def requires(self): return _REQUIRES_STAT @@ -449,7 +449,7 @@ class GrepOption(Option): try: self.regex = re.compile(value) except re.error: - raise ValueError('invalid regular expression: "{}"'.format(value)) + raise ValueError(f'invalid regular expression: "{value}"') def requires(self): return _REQUIRES_CONTENTS | _REQUIRES_STAT @@ -589,11 +589,11 @@ class ExecOption(Option): command, salt.utils.stringutils.to_str(err), ) - return "{}:\n{}\n".format(command, salt.utils.stringutils.to_str(out)) + return f"{command}:\n{salt.utils.stringutils.to_str(out)}\n" except Exception as e: # pylint: disable=broad-except log.error('Exception while executing command "%s":\n\n%s', command, e) - return "{}: Failed".format(fullpath) + return f"{fullpath}: Failed" class Finder: @@ -621,11 +621,11 @@ class Finder: # this is a passthrough object, continue continue if not value: - raise ValueError('missing value for "{}" option'.format(key)) + raise ValueError(f'missing value for "{key}" option') try: obj = globals()[key.title() + "Option"](key, value) except KeyError: - raise ValueError('invalid option "{}"'.format(key)) + raise ValueError(f'invalid option "{key}"') if hasattr(obj, "match"): requires = obj.requires() if requires & _REQUIRES_CONTENTS: @@ -721,7 +721,7 @@ def find(path, options): def _main(): if len(sys.argv) < 2: - sys.stderr.write("usage: {} path [options]\n".format(sys.argv[0])) + sys.stderr.write(f"usage: {sys.argv[0]} path [options]\n") sys.exit(salt.defaults.exitcodes.EX_USAGE) path = sys.argv[1] @@ -733,7 +733,7 @@ def _main(): try: finder = Finder(criteria) except ValueError as ex: - sys.stderr.write("error: {}\n".format(ex)) + sys.stderr.write(f"error: {ex}\n") sys.exit(salt.defaults.exitcodes.EX_GENERIC) for result in finder.find(path): diff --git a/salt/utils/fsutils.py b/salt/utils/fsutils.py index 7dda4454e9d..c1ea06f1851 100644 --- a/salt/utils/fsutils.py +++ b/salt/utils/fsutils.py @@ -119,7 +119,7 @@ def _is_device(path): """ Return True if path is a physical device. """ - out = __salt__["cmd.run_all"]("file -i {}".format(path)) + out = __salt__["cmd.run_all"](f"file -i {path}") _verify_run(out) # Always [device, mime, charset]. See (file --help) diff --git a/salt/utils/functools.py b/salt/utils/functools.py index e164811393e..224d096957c 100644 --- a/salt/utils/functools.py +++ b/salt/utils/functools.py @@ -81,7 +81,7 @@ def alias_function(fun, name, doc=None): alias_fun.__doc__ = doc else: orig_name = fun.__name__ - alias_msg = "\nThis function is an alias of ``{}``.\n".format(orig_name) + alias_msg = f"\nThis function is an alias of ``{orig_name}``.\n" alias_fun.__doc__ = alias_msg + (fun.__doc__ or "") return alias_fun diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index 730e6b01993..aa9190b6ee3 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -216,7 +216,7 @@ def failhard(role): """ Fatal configuration issue, raise an exception """ - raise FileserverConfigError("Failed to load {}".format(role)) + raise FileserverConfigError(f"Failed to load {role}") class GitProvider: @@ -249,7 +249,7 @@ class GitProvider: return str(y) self.global_saltenv = salt.utils.data.repack_dictlist( - self.opts.get("{}_saltenv".format(self.role), []), + self.opts.get(f"{self.role}_saltenv", []), strict=True, recurse=True, key_cb=str, @@ -411,7 +411,7 @@ class GitProvider: # when instantiating an instance of a GitBase subclass. Make sure # that we set this attribute so we at least have a sane default and # are able to fetch. - key = "{}_refspecs".format(self.role) + key = f"{self.role}_refspecs" try: default_refspecs = _DEFAULT_MASTER_OPTS[key] except KeyError: @@ -955,7 +955,7 @@ class GitProvider: ) ) if pid: - msg += " Process {} obtained the lock".format(pid) + msg += f" Process {pid} obtained the lock" if not pid_exists(pid): msg += ( " but this process is not running. The " @@ -1001,7 +1001,7 @@ class GitProvider: ) log.error(msg, exc_info=True) raise GitLockError(exc.errno, msg) - msg = "Set {} lock for {} remote '{}'".format(lock_type, self.role, self.id) + msg = f"Set {lock_type} lock for {self.role} remote '{self.id}'" log.debug(msg) return msg @@ -1030,7 +1030,7 @@ class GitProvider: Set and automatically clear a lock """ if not isinstance(lock_type, str): - raise GitLockError(errno.EINVAL, "Invalid lock_type '{}'".format(lock_type)) + raise GitLockError(errno.EINVAL, f"Invalid lock_type '{lock_type}'") # Make sure that we have a positive integer timeout, otherwise just set # it to zero. @@ -1158,7 +1158,7 @@ class GitProvider: for ref_type in self.ref_types: try: - func_name = "get_tree_from_{}".format(ref_type) + func_name = f"get_tree_from_{ref_type}" func = getattr(self, func_name) except AttributeError: log.error( @@ -1174,7 +1174,7 @@ class GitProvider: if self.fallback: for ref_type in self.ref_types: try: - func_name = "get_tree_from_{}".format(ref_type) + func_name = f"get_tree_from_{ref_type}" func = getattr(self, func_name) except AttributeError: log.error( @@ -1593,7 +1593,7 @@ class GitPython(GitProvider): """ try: return git.RemoteReference( - self.repo, "refs/remotes/origin/{}".format(ref) + self.repo, f"refs/remotes/origin/{ref}" ).commit.tree except ValueError: return None @@ -1603,7 +1603,7 @@ class GitPython(GitProvider): Return a git.Tree object matching a tag ref fetched into refs/tags/ """ try: - return git.TagReference(self.repo, "refs/tags/{}".format(ref)).commit.tree + return git.TagReference(self.repo, f"refs/tags/{ref}").commit.tree except ValueError: return None @@ -2191,7 +2191,7 @@ class Pygit2(GitProvider): """ try: return self.peel( - self.repo.lookup_reference("refs/remotes/origin/{}".format(ref)) + self.repo.lookup_reference(f"refs/remotes/origin/{ref}") ).tree except KeyError: return None @@ -2201,9 +2201,7 @@ class Pygit2(GitProvider): Return a pygit2.Tree object matching a tag ref fetched into refs/tags/ """ try: - return self.peel( - self.repo.lookup_reference("refs/tags/{}".format(ref)) - ).tree + return self.peel(self.repo.lookup_reference(f"refs/tags/{ref}")).tree except KeyError: return None @@ -2485,9 +2483,7 @@ class GitBase: # error out and do not proceed. override_params = copy.deepcopy(per_remote_overrides) global_auth_params = [ - "{}_{}".format(self.role, x) - for x in AUTH_PARAMS - if self.opts["{}_{}".format(self.role, x)] + f"{self.role}_{x}" for x in AUTH_PARAMS if self.opts[f"{self.role}_{x}"] ] if self.provider in AUTH_PROVIDERS: override_params += AUTH_PARAMS @@ -2510,7 +2506,7 @@ class GitBase: global_values = set(override_params) global_values.update(set(global_only)) for param in global_values: - key = "{}_{}".format(self.role, param) + key = f"{self.role}_{param}" if key not in self.opts: log.critical( "Key '%s' not present in global configuration. This is " @@ -2645,7 +2641,7 @@ class GitBase: try: shutil.rmtree(rdir) except OSError as exc: - errors.append("Unable to delete {}: {}".format(rdir, exc)) + errors.append(f"Unable to delete {rdir}: {exc}") return errors def clear_lock(self, remote=None, lock_type="update"): @@ -2823,10 +2819,10 @@ class GitBase: """ Determine which provider to use """ - if "verified_{}_provider".format(self.role) in self.opts: - self.provider = self.opts["verified_{}_provider".format(self.role)] + if f"verified_{self.role}_provider" in self.opts: + self.provider = self.opts[f"verified_{self.role}_provider"] else: - desired_provider = self.opts.get("{}_provider".format(self.role)) + desired_provider = self.opts.get(f"{self.role}_provider") if not desired_provider: if self.verify_pygit2(quiet=True): self.provider = "pygit2" @@ -2897,7 +2893,7 @@ class GitBase: _recommend() return False - self.opts["verified_{}_provider".format(self.role)] = "gitpython" + self.opts[f"verified_{self.role}_provider"] = "gitpython" log.debug("gitpython %s_provider enabled", self.role) return True @@ -2953,7 +2949,7 @@ class GitBase: _recommend() return False - self.opts["verified_{}_provider".format(self.role)] = "pygit2" + self.opts[f"verified_{self.role}_provider"] = "pygit2" log.debug("pygit2 %s_provider enabled", self.role) return True @@ -2965,11 +2961,11 @@ class GitBase: try: with salt.utils.files.fopen(remote_map, "w+") as fp_: timestamp = datetime.now().strftime("%d %b %Y %H:%M:%S.%f") - fp_.write("# {}_remote map as of {}\n".format(self.role, timestamp)) + fp_.write(f"# {self.role}_remote map as of {timestamp}\n") for repo in self.remotes: fp_.write( salt.utils.stringutils.to_str( - "{} = {}\n".format(repo.get_cache_basehash(), repo.id) + f"{repo.get_cache_basehash()} = {repo.id}\n" ) ) except OSError: @@ -3119,12 +3115,12 @@ class GitFS(GitBase): dest = salt.utils.path.join(self.cache_root, "refs", tgt_env, path) hashes_glob = salt.utils.path.join( - self.hash_cachedir, tgt_env, "{}.hash.*".format(path) + self.hash_cachedir, tgt_env, f"{path}.hash.*" ) blobshadest = salt.utils.path.join( - self.hash_cachedir, tgt_env, "{}.hash.blob_sha1".format(path) + self.hash_cachedir, tgt_env, f"{path}.hash.blob_sha1" ) - lk_fn = salt.utils.path.join(self.hash_cachedir, tgt_env, "{}.lk".format(path)) + lk_fn = salt.utils.path.join(self.hash_cachedir, tgt_env, f"{path}.lk") destdir = os.path.dirname(dest) hashdir = os.path.dirname(blobshadest) if not os.path.isdir(destdir): diff --git a/salt/utils/github.py b/salt/utils/github.py index d24244e5a0e..4ee55c39a73 100644 --- a/salt/utils/github.py +++ b/salt/utils/github.py @@ -43,7 +43,7 @@ def get_user_pubkeys(users): key_ids = user[tmp_user] user = tmp_user - url = "https://api.github.com/users/{}/keys".format(user) + url = f"https://api.github.com/users/{user}/keys" result = salt.utils.http.query( url, "GET", diff --git a/salt/utils/hashutils.py b/salt/utils/hashutils.py index 02d234af068..4969465acbe 100644 --- a/salt/utils/hashutils.py +++ b/salt/utils/hashutils.py @@ -160,7 +160,7 @@ def get_hash(path, form="sha256", chunk_size=65536): """ hash_type = hasattr(hashlib, form) and getattr(hashlib, form) or None if hash_type is None: - raise ValueError("Invalid hash type: {}".format(form)) + raise ValueError(f"Invalid hash type: {form}") with salt.utils.files.fopen(path, "rb") as ifile: hash_obj = hash_type() @@ -182,7 +182,7 @@ class DigestCollector: """ self.__digest = hasattr(hashlib, form) and getattr(hashlib, form)() or None if self.__digest is None: - raise ValueError("Invalid hash type: {}".format(form)) + raise ValueError(f"Invalid hash type: {form}") self.__buff = buff def add(self, path): diff --git a/salt/utils/immutabletypes.py b/salt/utils/immutabletypes.py index 183dc3606ef..fde42753801 100644 --- a/salt/utils/immutabletypes.py +++ b/salt/utils/immutabletypes.py @@ -30,7 +30,7 @@ class ImmutableDict(Mapping): return freeze(self.__obj[key]) def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, repr(self.__obj)) + return f"<{self.__class__.__name__} {repr(self.__obj)}>" def __deepcopy__(self, memo): return copy.deepcopy(self.__obj) @@ -66,7 +66,7 @@ class ImmutableList(Sequence): return freeze(self.__obj[key]) def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, repr(self.__obj)) + return f"<{self.__class__.__name__} {repr(self.__obj)}>" def __deepcopy__(self, memo): return copy.deepcopy(self.__obj) @@ -96,7 +96,7 @@ class ImmutableSet(Set): return key in self.__obj def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, repr(self.__obj)) + return f"<{self.__class__.__name__} {repr(self.__obj)}>" def __deepcopy__(self, memo): return copy.deepcopy(self.__obj) diff --git a/salt/utils/jid.py b/salt/utils/jid.py index c3dbf8a078a..69d926469b9 100644 --- a/salt/utils/jid.py +++ b/salt/utils/jid.py @@ -27,11 +27,11 @@ def gen_jid(opts): jid_dt = _utc_now() if not opts.get("unique_jid", False): - return "{:%Y%m%d%H%M%S%f}".format(jid_dt) + return f"{jid_dt:%Y%m%d%H%M%S%f}" if LAST_JID_DATETIME and LAST_JID_DATETIME >= jid_dt: jid_dt = LAST_JID_DATETIME + datetime.timedelta(microseconds=1) LAST_JID_DATETIME = jid_dt - return "{:%Y%m%d%H%M%S%f}_{}".format(jid_dt, os.getpid()) + return f"{jid_dt:%Y%m%d%H%M%S%f}_{os.getpid()}" def is_jid(jid): diff --git a/salt/utils/job.py b/salt/utils/job.py index 3d4653d412d..66b0568887b 100644 --- a/salt/utils/job.py +++ b/salt/utils/job.py @@ -40,7 +40,7 @@ def store_job(opts, load, event=None, mminion=None): nocache=load.get("nocache", False) ) except KeyError: - emsg = "Returner '{}' does not support function prep_jid".format(job_cache) + emsg = f"Returner '{job_cache}' does not support function prep_jid" log.error(emsg) raise KeyError(emsg) except Exception: # pylint: disable=broad-except @@ -51,11 +51,11 @@ def store_job(opts, load, event=None, mminion=None): ) # save the load, since we don't have it - saveload_fstr = "{}.save_load".format(job_cache) + saveload_fstr = f"{job_cache}.save_load" try: mminion.returners[saveload_fstr](load["jid"], load) except KeyError: - emsg = "Returner '{}' does not support function save_load".format(job_cache) + emsg = f"Returner '{job_cache}' does not support function save_load" log.error(emsg) raise KeyError(emsg) except Exception: # pylint: disable=broad-except @@ -66,11 +66,11 @@ def store_job(opts, load, event=None, mminion=None): ) elif salt.utils.jid.is_jid(load["jid"]): # Store the jid - jidstore_fstr = "{}.prep_jid".format(job_cache) + jidstore_fstr = f"{job_cache}.prep_jid" try: mminion.returners[jidstore_fstr](False, passed_jid=load["jid"]) except KeyError: - emsg = "Returner '{}' does not support function prep_jid".format(job_cache) + emsg = f"Returner '{job_cache}' does not support function prep_jid" log.error(emsg) raise KeyError(emsg) except Exception: # pylint: disable=broad-except @@ -103,10 +103,10 @@ def store_job(opts, load, event=None, mminion=None): return # otherwise, write to the master cache - savefstr = "{}.save_load".format(job_cache) - getfstr = "{}.get_load".format(job_cache) - fstr = "{}.returner".format(job_cache) - updateetfstr = "{}.update_endtime".format(job_cache) + savefstr = f"{job_cache}.save_load" + getfstr = f"{job_cache}.get_load" + fstr = f"{job_cache}.returner" + updateetfstr = f"{job_cache}.update_endtime" if "fun" not in load and load.get("return", {}): ret_ = load.get("return", {}) if "fun" in ret_: @@ -120,7 +120,7 @@ def store_job(opts, load, event=None, mminion=None): getfstr_func = mminion.returners[getfstr] fstr_func = mminion.returners[fstr] except KeyError as error: - emsg = "Returner '{}' does not support function {}".format(job_cache, error) + emsg = f"Returner '{job_cache}' does not support function {error}" log.error(emsg) raise KeyError(emsg) @@ -160,14 +160,12 @@ def store_minions(opts, jid, minions, mminion=None, syndic_id=None): if mminion is None: mminion = salt.minion.MasterMinion(opts, states=False, rend=False) job_cache = opts["master_job_cache"] - minions_fstr = "{}.save_minions".format(job_cache) + minions_fstr = f"{job_cache}.save_minions" try: mminion.returners[minions_fstr](jid, minions, syndic_id=syndic_id) except KeyError: - raise KeyError( - "Returner '{}' does not support function save_minions".format(job_cache) - ) + raise KeyError(f"Returner '{job_cache}' does not support function save_minions") def get_retcode(ret): diff --git a/salt/utils/kickstart.py b/salt/utils/kickstart.py index 6674999a4e9..6869d2b5ba9 100644 --- a/salt/utils/kickstart.py +++ b/salt/utils/kickstart.py @@ -64,7 +64,7 @@ def parse_auth(rule): "disablewins", ) for arg in noargs: - parser.add_argument("--{}".format(arg), dest=arg, action="store_true") + parser.add_argument(f"--{arg}", dest=arg, action="store_true") parser.add_argument("--enablenis", dest="enablenis", action="store") parser.add_argument("--hesiodrhs", dest="hesiodrhs", action="store") diff --git a/salt/utils/lazy.py b/salt/utils/lazy.py index 832be90fc0d..87b356eac9a 100644 --- a/salt/utils/lazy.py +++ b/salt/utils/lazy.py @@ -77,7 +77,7 @@ class LazyDict(MutableMapping): Override this to return a more meaningfull error message if possible """ - return "'{}' is not available.".format(function_name) + return f"'{function_name}' is not available." def __setitem__(self, key, val): self._dict[key] = val diff --git a/salt/utils/mac_utils.py b/salt/utils/mac_utils.py index dbfc9f05f82..1614d2189b3 100644 --- a/salt/utils/mac_utils.py +++ b/salt/utils/mac_utils.py @@ -154,7 +154,7 @@ def execute_return_success(cmd): log.debug("Execute return success %s: %r", cmd, ret) if ret["retcode"] != 0 or "not supported" in ret["stdout"].lower(): - msg = "Command Failed: {}\n".format(cmd) + msg = f"Command Failed: {cmd}\n" msg += "Return Code: {}\n".format(ret["retcode"]) msg += "Output: {}\n".format(ret["stdout"]) msg += "Error: {}\n".format(ret["stderr"]) @@ -178,7 +178,7 @@ def execute_return_result(cmd): ret = _run_all(cmd) if ret["retcode"] != 0 or "not supported" in ret["stdout"].lower(): - msg = "Command Failed: {}\n".format(cmd) + msg = f"Command Failed: {cmd}\n" msg += "Return Code: {}\n".format(ret["retcode"]) msg += "Output: {}\n".format(ret["stdout"]) msg += "Error: {}\n".format(ret["stderr"]) @@ -313,7 +313,7 @@ def launchctl(sub_cmd, *args, **kwargs): # Raise an error or return successful result if ret["retcode"] or error: - out = "Failed to {} service:\n".format(sub_cmd) + out = f"Failed to {sub_cmd} service:\n" out += "stdout: {}\n".format(ret["stdout"]) out += "stderr: {}\n".format(ret["stderr"]) out += "retcode: {}".format(ret["retcode"]) diff --git a/salt/utils/mako.py b/salt/utils/mako.py index 4397ae8cc7d..7d467ce62c6 100644 --- a/salt/utils/mako.py +++ b/salt/utils/mako.py @@ -70,7 +70,7 @@ if HAS_MAKO: if scheme in ("salt", "file"): return uri elif scheme: - raise ValueError("Unsupported URL scheme({}) in {}".format(scheme, uri)) + raise ValueError(f"Unsupported URL scheme({scheme}) in {uri}") return self.lookup.adjust_uri(uri, filename) def get_template(self, uri, relativeto=None): diff --git a/salt/utils/master.py b/salt/utils/master.py index ce2dfe46bf0..6aa661c0607 100644 --- a/salt/utils/master.py +++ b/salt/utils/master.py @@ -109,7 +109,7 @@ def _check_cmdline(data): return False if not os.path.isdir("/proc"): return True - path = os.path.join("/proc/{}/cmdline".format(pid)) + path = os.path.join(f"/proc/{pid}/cmdline") if not os.path.isfile(path): return False try: @@ -161,7 +161,7 @@ class MasterPillarUtil: if opts is None: log.error("%s: Missing master opts init arg.", self.__class__.__name__) raise SaltException( - "{}: Missing master opts init arg.".format(self.__class__.__name__) + f"{self.__class__.__name__}: Missing master opts init arg." ) else: self.opts = opts @@ -202,7 +202,7 @@ class MasterPillarUtil: for minion_id in minion_ids: if not salt.utils.verify.valid_id(self.opts, minion_id): continue - mdata = self.cache.fetch("minions/{}".format(minion_id), "mine") + mdata = self.cache.fetch(f"minions/{minion_id}", "mine") if isinstance(mdata, dict): mine_data[minion_id] = mdata return mine_data @@ -220,7 +220,7 @@ class MasterPillarUtil: for minion_id in minion_ids: if not salt.utils.verify.valid_id(self.opts, minion_id): continue - mdata = self.cache.fetch("minions/{}".format(minion_id), "data") + mdata = self.cache.fetch(f"minions/{minion_id}", "data") if not isinstance(mdata, dict): log.warning( "cache.fetch should always return a dict. ReturnedType: %s," @@ -489,7 +489,7 @@ class MasterPillarUtil: if clear_mine: clear_what.append("mine") if clear_mine_func is not None: - clear_what.append("mine_func: '{}'".format(clear_mine_func)) + clear_what.append(f"mine_func: '{clear_mine_func}'") if not clear_what: log.debug("No cached data types specified for clearing.") return False @@ -515,7 +515,7 @@ class MasterPillarUtil: if minion_id not in c_minions: # Cache bank for this minion does not exist. Nothing to do. continue - bank = "minions/{}".format(minion_id) + bank = f"minions/{minion_id}" minion_pillar = pillars.pop(minion_id, False) minion_grains = grains.pop(minion_id, False) if ( @@ -823,7 +823,7 @@ def get_master_key(key_user, opts, skip_perm_errors=False): # The username may contain '\' if it is in Windows # 'DOMAIN\username' format. Fix this for the keyfile path. key_user = key_user.replace("\\", "_") - keyfile = os.path.join(opts["cachedir"], ".{}_key".format(key_user)) + keyfile = os.path.join(opts["cachedir"], f".{key_user}_key") # Make sure all key parent directories are accessible salt.utils.verify.check_path_traversal(opts["cachedir"], key_user, skip_perm_errors) diff --git a/salt/utils/mattermost.py b/salt/utils/mattermost.py index b8b49c32e75..17c2d6b8ffe 100644 --- a/salt/utils/mattermost.py +++ b/salt/utils/mattermost.py @@ -39,7 +39,7 @@ def query(hook=None, api_url=None, data=None): result = salt.utils.http.query(url, method, data=data, decode=True, status=True) if result.get("status", None) == http.client.OK: - ret["message"] = "Message posted {} correctly".format(data) + ret["message"] = f"Message posted {data} correctly" return ret elif result.get("status", None) == http.client.NO_CONTENT: return True diff --git a/salt/utils/memcached.py b/salt/utils/memcached.py index 11248abadd6..881f923979a 100644 --- a/salt/utils/memcached.py +++ b/salt/utils/memcached.py @@ -91,7 +91,7 @@ def get_conn(opts, profile=None, host=None, port=None): raise SaltInvocationError("port must be an integer") if HAS_LIBS: - return memcache.Client(["{}:{}".format(host, port)]) + return memcache.Client([f"{host}:{port}"]) else: raise CommandExecutionError( "(unable to import memcache, module most likely not installed)" diff --git a/salt/utils/minion.py b/salt/utils/minion.py index 9c53428c89b..39bae1a2302 100644 --- a/salt/utils/minion.py +++ b/salt/utils/minion.py @@ -131,7 +131,7 @@ def _check_cmdline(data): return False if not os.path.isdir("/proc"): return True - path = os.path.join("/proc/{}/cmdline".format(pid)) + path = os.path.join(f"/proc/{pid}/cmdline") if not os.path.isfile(path): return False try: diff --git a/salt/utils/minions.py b/salt/utils/minions.py index 3006118c239..7406b696eb5 100644 --- a/salt/utils/minions.py +++ b/salt/utils/minions.py @@ -107,11 +107,11 @@ def get_minion_data(minion, opts): cache = salt.cache.factory(opts) if minion is None: for id_ in cache.list("minions"): - data = cache.fetch("minions/{}".format(id_), "data") + data = cache.fetch(f"minions/{id_}", "data") if data is None: continue else: - data = cache.fetch("minions/{}".format(minion), "data") + data = cache.fetch(f"minions/{minion}", "data") if data is not None: grains = data.get("grains", None) pillar = data.get("pillar", None) @@ -323,7 +323,7 @@ class CkMinions: for id_ in cminions: if greedy and id_ not in minions: continue - mdata = self.cache.fetch("minions/{}".format(id_), "data") + mdata = self.cache.fetch(f"minions/{id_}", "data") if mdata is None: if not greedy: minions.remove(id_) @@ -408,11 +408,11 @@ class CkMinions: except Exception: # pylint: disable=broad-except log.error("Invalid IP/CIDR target: %s", tgt) return {"minions": [], "missing": []} - proto = "ipv{}".format(tgt.version) + proto = f"ipv{tgt.version}" minions = set(minions) for id_ in cminions: - mdata = self.cache.fetch("minions/{}".format(id_), "data") + mdata = self.cache.fetch(f"minions/{id_}", "data") if mdata is None: if not greedy: minions.remove(id_) @@ -649,7 +649,7 @@ class CkMinions: search = subset for id_ in search: try: - mdata = self.cache.fetch("minions/{}".format(id_), "data") + mdata = self.cache.fetch(f"minions/{id_}", "data") except SaltCacheError: # If a SaltCacheError is explicitly raised during the fetch operation, # permission was denied to open the cached data.p file. Continue on as @@ -702,7 +702,7 @@ class CkMinions: try: if expr is None: expr = "" - check_func = getattr(self, "_check_{}_minions".format(tgt_type), None) + check_func = getattr(self, f"_check_{tgt_type}_minions", None) if tgt_type in ( "grain", "grain_pcre", @@ -1048,11 +1048,7 @@ class CkMinions: for ind in auth_list: if isinstance(ind, str): if ind[0] == "@": - if ( - ind[1:] == mod_name - or ind[1:] == form - or ind == "@{}s".format(form) - ): + if ind[1:] == mod_name or ind[1:] == form or ind == f"@{form}s": return True elif isinstance(ind, dict): if len(ind) != 1: @@ -1064,7 +1060,7 @@ class CkMinions: ind[valid], fun_name, args.get("arg"), args.get("kwarg") ): return True - if valid[1:] == form or valid == "@{}s".format(form): + if valid[1:] == form or valid == f"@{form}s": if self.__fun_check( ind[valid], fun, args.get("arg"), args.get("kwarg") ): diff --git a/salt/utils/nacl.py b/salt/utils/nacl.py index 918eb942ca6..cac3455d1a6 100644 --- a/salt/utils/nacl.py +++ b/salt/utils/nacl.py @@ -58,7 +58,7 @@ def _get_config(**kwargs): "pk_file": pk_file, } - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" try: config.update(__salt__["config.get"](config_key, {})) except (NameError, KeyError) as e: @@ -146,7 +146,7 @@ def keygen(sk_file=None, pk_file=None, **kwargs): } if pk_file is None: - pk_file = "{}.pub".format(sk_file) + pk_file = f"{sk_file}.pub" if sk_file and pk_file is None: if not os.path.isfile(sk_file): @@ -167,17 +167,15 @@ def keygen(sk_file=None, pk_file=None, **kwargs): else: # chmod 0600 file os.chmod(sk_file, 1536) - return "saved sk_file: {}".format(sk_file) + return f"saved sk_file: {sk_file}" else: - raise Exception("sk_file:{} already exist.".format(sk_file)) + raise Exception(f"sk_file:{sk_file} already exist.") if sk_file is None and pk_file: raise Exception("sk_file: Must be set inorder to generate a public key.") if os.path.isfile(sk_file) and os.path.isfile(pk_file): - raise Exception( - "sk_file:{} and pk_file:{} already exist.".format(sk_file, pk_file) - ) + raise Exception(f"sk_file:{sk_file} and pk_file:{pk_file} already exist.") if os.path.isfile(sk_file) and not os.path.isfile(pk_file): # generate pk using the sk @@ -187,7 +185,7 @@ def keygen(sk_file=None, pk_file=None, **kwargs): kp = nacl.public.PublicKey(sk) with salt.utils.files.fopen(pk_file, "wb") as keyf: keyf.write(base64.b64encode(kp.encode())) - return "saved pk_file: {}".format(pk_file) + return f"saved pk_file: {pk_file}" kp = nacl.public.PublicKey.generate() with salt.utils.files.fopen(sk_file, "wb") as keyf: @@ -203,7 +201,7 @@ def keygen(sk_file=None, pk_file=None, **kwargs): os.chmod(sk_file, 1536) with salt.utils.files.fopen(pk_file, "wb") as keyf: keyf.write(base64.b64encode(kp.encode())) - return "saved sk_file:{} pk_file: {}".format(sk_file, pk_file) + return f"saved sk_file:{sk_file} pk_file: {pk_file}" def enc(data, **kwargs): @@ -270,10 +268,10 @@ def enc_file(name, out=None, **kwargs): d = enc(data, **kwargs) if out: if os.path.isfile(out): - raise Exception("file:{} already exist.".format(out)) + raise Exception(f"file:{out} already exist.") with salt.utils.files.fopen(out, "wb") as f: f.write(salt.utils.stringutils.to_bytes(d)) - return "Wrote: {}".format(out) + return f"Wrote: {out}" return d @@ -342,10 +340,10 @@ def dec_file(name, out=None, **kwargs): d = dec(data, **kwargs) if out: if os.path.isfile(out): - raise Exception("file:{} already exist.".format(out)) + raise Exception(f"file:{out} already exist.") with salt.utils.files.fopen(out, "wb") as f: f.write(salt.utils.stringutils.to_bytes(d)) - return "Wrote: {}".format(out) + return f"Wrote: {out}" return d diff --git a/salt/utils/nb_popen.py b/salt/utils/nb_popen.py index 7624d609713..3f6afd4b85e 100644 --- a/salt/utils/nb_popen.py +++ b/salt/utils/nb_popen.py @@ -145,8 +145,8 @@ class NonBlockingPopen(subprocess.Popen): return self._close(which) raise - getattr(self, "{}_buff".format(which)).write(read) - getattr(self, "_{}_logger".format(which)).debug(read.rstrip()) + getattr(self, f"{which}_buff").write(read) + getattr(self, f"_{which}_logger").debug(read.rstrip()) if self.stream_stds: getattr(sys, which).write(read) @@ -195,8 +195,8 @@ class NonBlockingPopen(subprocess.Popen): if self.universal_newlines: buff = self._translate_newlines(buff) - getattr(self, "{}_buff".format(which)).write(buff) - getattr(self, "_{}_logger".format(which)).debug(buff.rstrip()) + getattr(self, f"{which}_buff").write(buff) + getattr(self, f"_{which}_logger").debug(buff.rstrip()) if self.stream_stds: getattr(sys, which).write(buff) diff --git a/salt/utils/network.py b/salt/utils/network.py index 29c6c2f1049..f964e25fa54 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -672,7 +672,7 @@ def cidr_to_ipv4_netmask(cidr_bits): netmask += "255" cidr_bits -= 8 else: - netmask += "{:d}".format(256 - (2 ** (8 - cidr_bits))) + netmask += f"{256 - (2 ** (8 - cidr_bits)):d}" cidr_bits = 0 return netmask @@ -846,11 +846,7 @@ def _interfaces_ifconfig(out): if salt.utils.platform.is_sunos(): expand_mac = [] for chunk in data["hwaddr"].split(":"): - expand_mac.append( - "0{}".format(chunk) - if len(chunk) < 2 - else "{}".format(chunk) - ) + expand_mac.append(f"0{chunk}" if len(chunk) < 2 else f"{chunk}") data["hwaddr"] = ":".join(expand_mac) if mip: if "inet" not in data: @@ -1194,7 +1190,7 @@ def get_net_start(ipaddr, netmask): """ Return the address of the network """ - net = ipaddress.ip_network("{}/{}".format(ipaddr, netmask), strict=False) + net = ipaddress.ip_network(f"{ipaddr}/{netmask}", strict=False) return str(net.network_address) @@ -1216,7 +1212,7 @@ def calc_net(ipaddr, netmask=None): (The IP can be any IP inside the subnet) """ if netmask is not None: - ipaddr = "{}/{}".format(ipaddr, netmask) + ipaddr = f"{ipaddr}/{netmask}" return str(ipaddress.ip_network(ipaddr, strict=False)) @@ -1487,7 +1483,7 @@ def _ip_networks( _net = addr.get("netmask" if proto == "inet" else "prefixlen") if _ip and _net: try: - ip_net = ipaddress.ip_network("{}/{}".format(_ip, _net), strict=False) + ip_net = ipaddress.ip_network(f"{_ip}/{_net}", strict=False) except Exception: # pylint: disable=broad-except continue if not ip_net.is_loopback or include_loopback: @@ -1596,8 +1592,8 @@ def mac2eui64(mac, prefix=None): else: try: net = ipaddress.ip_network(prefix, strict=False) - euil = int("0x{}".format(eui64), 16) - return "{}/{}".format(net[euil], net.prefixlen) + euil = int(f"0x{eui64}", 16) + return f"{net[euil]}/{net.prefixlen}" except Exception: # pylint: disable=broad-except return @@ -2013,7 +2009,7 @@ def _linux_remotes_on(port, which_end): data = subprocess.check_output( [ lsof_binary, - "-iTCP:{:d}".format(port), + f"-iTCP:{port:d}", "-n", "-P", ] @@ -2214,7 +2210,7 @@ def dns_check(addr, port, safe=False, ipv6=None): error = True if not ip_addrs: - err = "DNS lookup or connection check of '{}' failed.".format(addr) + err = f"DNS lookup or connection check of '{addr}' failed." if safe: log.error(err) raise SaltClientError() @@ -2278,9 +2274,7 @@ def parse_host_port(host_port): port = int(_s_.lstrip(":")) else: if len(_s_) > 1: - raise ValueError( - 'found ambiguous "{}" port in "{}"'.format(_s_, host_port) - ) + raise ValueError(f'found ambiguous "{_s_}" port in "{host_port}"') else: if _s_.count(":") == 1: host, _hostport_separator_, port = _s_.partition(":") @@ -2302,7 +2296,7 @@ def parse_host_port(host_port): log.debug('"%s" Not an IP address? Assuming it is a hostname.', host) if host != sanitize_host(host): log.error('bad hostname: "%s"', host) - raise ValueError('bad hostname: "{}"'.format(host)) + raise ValueError(f'bad hostname: "{host}"') return host, port @@ -2332,7 +2326,7 @@ def filter_by_networks(values, networks): elif isinstance(values, Sequence): return _filter(values, networks) else: - raise ValueError("Do not know how to filter a {}".format(type(values))) + raise ValueError(f"Do not know how to filter a {type(values)}") else: return values diff --git a/salt/utils/nxos.py b/salt/utils/nxos.py index 2572a762670..5615e9216b6 100644 --- a/salt/utils/nxos.py +++ b/salt/utils/nxos.py @@ -83,7 +83,7 @@ class NxapiClient: if self.nxargs["connect_over_uds"]: if not os.path.exists(self.NXAPI_UDS): raise NxosClientError( - "No host specified and no UDS found at {}\n".format(self.NXAPI_UDS) + f"No host specified and no UDS found at {self.NXAPI_UDS}\n" ) # Create UHTTPConnection object for NX-API communication over UDS. @@ -190,7 +190,7 @@ class NxapiClient: header_dict=req["headers"], decode=True, decode_type="json", - **self.nxargs + **self.nxargs, ) return self.parse_response(response, command_list) @@ -202,9 +202,9 @@ class NxapiClient: # Check for 500 level NX-API Server Errors if isinstance(response, Iterable) and "status" in response: if int(response["status"]) >= 500: - raise NxosError("{}".format(response)) + raise NxosError(f"{response}") else: - raise NxosError("NX-API Request Not Supported: {}".format(response)) + raise NxosError(f"NX-API Request Not Supported: {response}") if isinstance(response, Iterable): body = response["dict"] @@ -218,7 +218,7 @@ class NxapiClient: # Don't just return body['ins_api']['outputs']['output'] directly. output = body.get("ins_api") if output is None: - raise NxosClientError("Unexpected JSON output\n{}".format(body)) + raise NxosClientError(f"Unexpected JSON output\n{body}") if output.get("outputs"): output = output["outputs"] if output.get("output"): @@ -257,9 +257,9 @@ class NxapiClient: } ) elif code == "413": - raise NxosRequestNotSupported("Error 413: {}".format(msg)) + raise NxosRequestNotSupported(f"Error 413: {msg}") elif code != "200": - raise NxosError("Unknown Error: {}, Code: {}".format(msg, code)) + raise NxosError(f"Unknown Error: {msg}, Code: {code}") else: previous_commands.append(cmd) result.append(cmd_result["body"]) @@ -321,7 +321,7 @@ def ping(**kwargs): def _parser(block): - return re.compile("^{block}\n(?:^[ \n].*$\n?)+".format(block=block), re.MULTILINE) + return re.compile(f"^{block}\n(?:^[ \n].*$\n?)+", re.MULTILINE) def _parse_software(data): diff --git a/salt/utils/openstack/nova.py b/salt/utils/openstack/nova.py index 90b0b1f8269..4c737ed6c4a 100644 --- a/salt/utils/openstack/nova.py +++ b/salt/utils/openstack/nova.py @@ -204,7 +204,7 @@ def get_entry(dict_, key, value, raise_error=True): if entry[key] == value: return entry if raise_error is True: - raise SaltCloudSystemExit("Unable to find {} in {}.".format(key, dict_)) + raise SaltCloudSystemExit(f"Unable to find {key} in {dict_}.") return {} @@ -213,7 +213,7 @@ def get_entry_multi(dict_, pairs, raise_error=True): if all([entry[key] == value for key, value in pairs]): return entry if raise_error is True: - raise SaltCloudSystemExit("Unable to find {} in {}.".format(pairs, dict_)) + raise SaltCloudSystemExit(f"Unable to find {pairs} in {dict_}.") return {} @@ -281,7 +281,7 @@ class SaltNova: password=None, os_auth_plugin=None, use_keystoneauth=False, - **kwargs + **kwargs, ): """ Set up nova credentials @@ -294,7 +294,7 @@ class SaltNova: region_name=region_name, password=password, os_auth_plugin=os_auth_plugin, - **kwargs + **kwargs, ) else: self._old_init( @@ -304,7 +304,7 @@ class SaltNova: region_name=region_name, password=password, os_auth_plugin=os_auth_plugin, - **kwargs + **kwargs, ) def _new_init( @@ -317,7 +317,7 @@ class SaltNova: os_auth_plugin, auth=None, verify=True, - **kwargs + **kwargs, ): if auth is None: auth = {} @@ -386,7 +386,7 @@ class SaltNova: region_name, password, os_auth_plugin, - **kwargs + **kwargs, ): self.kwargs = kwargs.copy() if not self.extensions: @@ -674,7 +674,7 @@ class SaltNova: try: volume = self.volume_show(name) except KeyError as exc: - raise SaltCloudSystemExit("Unable to find {} volume: {}".format(name, exc)) + raise SaltCloudSystemExit(f"Unable to find {name} volume: {exc}") if volume["status"] == "deleted": return volume response = nt_ks.volumes.delete(volume["id"]) @@ -687,7 +687,7 @@ class SaltNova: try: volume = self.volume_show(name) except KeyError as exc: - raise SaltCloudSystemExit("Unable to find {} volume: {}".format(name, exc)) + raise SaltCloudSystemExit(f"Unable to find {name} volume: {exc}") if not volume["attachments"]: return True response = self.compute_conn.volumes.delete_server_volume( @@ -719,7 +719,7 @@ class SaltNova: try: volume = self.volume_show(name) except KeyError as exc: - raise SaltCloudSystemExit("Unable to find {} volume: {}".format(name, exc)) + raise SaltCloudSystemExit(f"Unable to find {name} volume: {exc}") server = self.server_by_name(server_name) response = self.compute_conn.volumes.create_server_volume( server.id, volume["id"], device=device @@ -823,7 +823,7 @@ class SaltNova: """ nt_ks = self.compute_conn nt_ks.flavors.delete(flavor_id) - return "Flavor deleted: {}".format(flavor_id) + return f"Flavor deleted: {flavor_id}" def keypair_list(self): """ @@ -859,7 +859,7 @@ class SaltNova: """ nt_ks = self.compute_conn nt_ks.keypairs.delete(name) - return "Keypair deleted: {}".format(name) + return f"Keypair deleted: {name}" def image_show(self, image_id): """ @@ -948,7 +948,7 @@ class SaltNova: if not image_id: return {"Error": "A valid image name or id was not specified"} nt_ks.images.delete_meta(image_id, pairs) - return {image_id: "Deleted: {}".format(pairs)} + return {image_id: f"Deleted: {pairs}"} def server_list(self): """ @@ -1088,8 +1088,8 @@ class SaltNova: for item in nt_ks.security_groups.list(): if item.name == name: nt_ks.security_groups.delete(item.id) - return {name: "Deleted security group: {}".format(name)} - return "Security group not found: {}".format(name) + return {name: f"Deleted security group: {name}"} + return f"Security group not found: {name}" def secgroup_list(self): """ diff --git a/salt/utils/oset.py b/salt/utils/oset.py index 85cc0931328..3725306ea0c 100644 --- a/salt/utils/oset.py +++ b/salt/utils/oset.py @@ -85,9 +85,7 @@ class OrderedSet(MutableSet): elif is_iterable(index): return OrderedSet([self.items[i] for i in index]) else: - raise TypeError( - "Don't know how to index an OrderedSet by {}".format(repr(index)) - ) + raise TypeError(f"Don't know how to index an OrderedSet by {repr(index)}") def copy(self): return OrderedSet(self) @@ -137,9 +135,7 @@ class OrderedSet(MutableSet): for item in sequence: item_index = self.add(item) except TypeError: - raise ValueError( - "Argument needs to be an iterable, got {}".format(type(sequence)) - ) + raise ValueError(f"Argument needs to be an iterable, got {type(sequence)}") return item_index def index(self, key): @@ -198,8 +194,8 @@ class OrderedSet(MutableSet): def __repr__(self): if not self: - return "{}()".format(self.__class__.__name__) - return "{}({})".format(self.__class__.__name__, repr(list(self))) + return f"{self.__class__.__name__}()" + return f"{self.__class__.__name__}({repr(list(self))})" def __eq__(self, other): if isinstance(other, OrderedSet): diff --git a/salt/utils/pagerduty.py b/salt/utils/pagerduty.py index 44c039a9f6b..62c663196e5 100644 --- a/salt/utils/pagerduty.py +++ b/salt/utils/pagerduty.py @@ -44,7 +44,7 @@ def query( """ Query the PagerDuty API """ - user_agent = "SaltStack {}".format(__version__) + user_agent = f"SaltStack {__version__}" if opts is None: opts = {} diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py index c915d5621f6..fc2eabc9a24 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py @@ -141,7 +141,7 @@ class OptionParser(optparse.OptionParser): _mixin_prio_ = sys.maxsize - 200 def __init__(self, *args, **kwargs): - kwargs.setdefault("version", "%prog {}".format(self.VERSION)) + kwargs.setdefault("version", f"%prog {self.VERSION}") kwargs.setdefault("usage", self.usage) if self.description: kwargs.setdefault("description", self.description) @@ -187,7 +187,7 @@ class OptionParser(optparse.OptionParser): # Gather and run the process_

NHa6dYj3DHyFmx}LLp_gucYlOs2b>j)gw$W zp}H6SmsUI6^1YWXMc$ju5$LUZ?`KX2Wm>r2xULVa)$6gN$~42E|C#fm$rH((bhAT7 zl|uV#V|u8y^SA|ldCi;aM6Q_*P+qv^c$n^qQ47Ycx&J{A`*+$fn7Qc4ju_{0Lif)o zye)W*2zt}0L+&q@LzQVmw;dpjP;Nv#gUyujYtEBZh%)T{(|NRC=uw_ zr(6{g77OhY4Oo>7hQrYH{r1*ypywXg{J6l;UR7S3EILW2YC?X4ww5g*=%llr|3c8R zOc_}%vqHl=x7+D8d0_9S+`*uyw|tPt!_6T+uxIzjLKYwBCBgDP7t0}K`2^|xtNw%} zt+ws11qk}Yos*ssz(S3F4IQ;fDC>HOPa}bbU)^wpAQfs|O={KK+i4)sle-_iSAY&I zuuo}@gzOh{JQnoAUE4kqnBl#^q$o=P<-;s$&l4FEys&iJ>P7BhvEpw~M&tXUtx*RJd&f$o0q z*@LB#nO4^Y1E(A zOkV;;m!{%_q@fs2|R(FlL8Su6Nfy72(D+MExdPy^sW z8!kH9Wb{-Q1J4UdT?<#D%=}6o!=T>`{PSrd>WVDr35xC+c_dv z0$*>CG|&g2HK*@lHi|P%jH{^DMnKzK{e`AzfPrp$`fD>aWRaJfD{3S6W7Dk0dhqom zJ5HefmE)?VftfL+WSTNMD+BG_VJFh4R&@BjwF=+cJf6U_4d~bR-uI#aPa*-h!(Lf| zGb;nP3GQ9c^KPk`E1;QP)S7U6XUN$~QjF3?zHI?l_fFkP3lj7{?~dIlc$wOg1#gL} z!fx|hG+@y$pqs`GepKKx`^5w2{)m?D!7T;#fA;U63DgJ@Uq>iFI}wz~Yf@wVv-MYe zXcz!rEYQ4w&b;yY(E_kvb^z)Ggvn6yg_yL;$OnD&mPvK#B4c?!9@KaEY%{H8DYAx(v~hQVPFmk!@}J2gbZVhP(}{pT z8msK4lUZobvGgl?1@yu5myMM6>_eYf6QgZ@x@Lj4pZv}))F^He==&oR&r7lWa~Er2 zf8zVQ=o&$*>u+2vMMpVB=`1bfUw8T&iPjUXLYg<-luLhiYJYr3wyU6nFP@XlefENQ z7F(`ekCjw6qyXwW<%sdZ(=htXQt-kNFZH3-dQYyA^%3;4zu#ll`Ic&DDNaqPS`$dP zPdklbDA31`-tKncuWpCU>MMKBc3xWDr+w|J4ddAb+5C52i<+}j19uf z0lhI}_}HJK6%Z`wB@h4Rb3wpJ%^_I46r<9sn<>5o7yyOXHx!Oh%W7M>E2=7LeLBEeq=l0&vJ6FLa-L;A4oqy?jzYth!s_G4P z5iQO;!qJdQ-XFs14*LDhO?wEQWm6PhoL<3HnWig=lB$PV!gTCEMVg`(ZV&IK_?!{fR~Zt>3i6CSk)Gb#jzL5O~30pUF9n`w#TSy*8N* z92*K0+8y%NxEg-oQ{Yw66oHS9dm>r*@Gy9C-p{M zm9(woYu^Gt>%r^Hu9Ovz^Gb)dCxeM_oOY>gQOmb1_00!sse|ry&ADc$&(?PjZ-PL$ z&Yu|Q+wP#TK;M7jN|WqrIc9lybg*1z^i9@w(0NCWn<~PywLLe37~Bppn0%RMP|!7Z zrp$52!*VN#1K^jqjPn&R|HYV~SG1mYNO3&2kYC}(TSYn#!w-7i?|o6hn@|vsM|4Nr zaP})CuYO}ewyYO#zbM6{aiz47Rat$9=1${)6zEnXy3MpwnVUTqo&maxfk1!z`Jl_C zore|*B*_;BaT@t=kR0f*uixGH$%P^!vxVNkoC+Dly_rYQ^`T9>2#?k>CPR3_mKY}5 z)R-Mh(`A101Ely{UTT59_SGFGv@|hK#sE}PPH4y4&|wodrlsTaSl*n#&8Z&k`#nI5AB-i?+VMA<3AsAAg60Qx zvAm4O6==uIlYS{IQzS{8Tkp8akKUZ3-Bzf<&OF_Mt~~e#vy{(c12FZ|InG*KVr6R4 zUjlLQj#?6+7ruI)Sx{OV1YTYZqRhb#+M+=k4fNX64)ROO^EeiQ77j#Woet9PYBdt* z#@F}!fgo9-pB#K;Y2XIkTMk2u*wqKUExBpu!Wq&SE)BVLbKN@7 zPoH}K3jsSYw}!YFY7VL8$Cm7sfd1hAm{}C|-g$LV8o+9m>9p`ec1J)zI`>19JZ`O4 zbBLT4M7S%)ff_(j5R5O-)Yn&=OwT;iD7TNG)Ydld*p<)LK%g^bZZO*~d3-nzki*nM z(j71b`rNAeM?~m(OtJ^7F4~Tz8oyd>sD^uz=v~*IYciO7XHDKrSK2dh6al zFwvGg6DG6PtgU_~-`D0@J%PC>Tdd6L^jR{l(RFMMzu$HHY{TConaOl^t}y__5CmQ)7A^ zff`F@l2cgILDzh;Xu05!dz;JFtFecSgw^UVaB~**3i=<^|MtCRHqIkyL7|Jw49u70 zqyq-@!kWeAyv6~&F=G(E-B}}mp7F`JpGtGa7K9)P3uw|FY%f9I-J`o&kPa>kDI)-O z6n7Ztr1|f630|JzrbVRwtwl^AED3g1G~^*C&^;cQ@)Nd*B`;wDxUB_Kig)4S*PV;i?Mj2=0IIJSho;# z&1FBnRoFT#w_;_3a`obTW)JkEN5`4fTAp5HOhhFe-lCLP0_lUM&Z;$A^LZQ%#&Iw% zV2uKO=!ZWsc>?2mZJ)+)H7v~z8R&aI+~-LVR-W<94C%ZuhpnA?JcHh~8(o-FfL=BPBfVE2Y8E7OcR|5 z`u72~R|;>w+#O(YGd|l(mj(Uh#|Ms)vUzw=ixOS}nFY!?_E-b$ zr2=@YBza6sXEP&B5&EXV=2;bPiPxxqzO!Vt+H$krB-`)nRW3cVIfDq zI9L0x;u#lomH!+QKh0vyEL^l&3mBa|sZHw)XnfJn#|dwv^7ahggKJ&5ybo&%=vT*H zZ8k2lc*nHWgO!NWqt0Khw%y8o3%d6iQ;osT(zltA`NBz?7#Q@a6VLci8l0tXGl4VX zK7V33(0y!Xn1G@UepDLC`}ZTbMgjvdn`5 z(@2YiwV6oo@e~jGd1T~g(jy}>HQGXI)Lnrgv4KrH=oQc1HBbQZu@a8c-lgnzH{uhJ zLTvUxub=Y0rv)jC1vRWFB!%D_4=Gj%&>5{enuzV_Jgrhti=yGRhM|21>(LJS#-2}p zDGXKihO&fi=8UaL8X)^^DC5T7Y}BYc50E3_#$RbRKsPj=JVe;YVswmLbm{7JIKnqN zUB@#y=vx>ivE4MO9 zmnC!u{Oxq`K>dTB-jz%+re4r{+rGL)m|0K=5_YYzS%h1S2pA4EWlePU zMsOE`p7ZKKW>>tWk2O&qEZ)jaTXRnRsP7tH(}Vu-?V)B5Y+j%1lUAaZ-*9Jwei~hO zpUAJd-)eD+CFeM=X@IA&~wmdt{XPLzv_~^v2D@aL!%OPf$mtnnSb1Wz7h-+)!U=;MQUkrNulHXq-HI_0@8(^uCx{5B|G+(2>!?`}t0e_ii7K8m#pEhHz z`WA3~pl99ss#$!m=nskN`qW8e3_DlFOSodt5u-<$>268CRIDx&UX%#Cs$9-hg5I=O z*c|OEW#}1TH5_U~behSVWcM;>XMnzR&F;Su)#+Oc<)-AU5swybA?T(T_cgJeQp}js z!ffls0M`V%@~?ZD(Ed?<>b^x$N*;|xR%21Ak}9>CF|1&O{D^A?9eYo=NhE3NTg{0u zBpab47OvXnac!WVZrZ9+I`Qy6)wUSfEb1NtS7m!~WuUX(sWxe@^Gm2qE`jlDKS@49 zg75Jn9dzzpH-1mrWCc5Nua`WloTiT8gb5QS0d_UV$3WLUINa<#RF%NJwj9m01x$zE z0sb0qn1P0GS!m)trL13E;4U|yoSOi;cHjXf0#=IkCF?^+CdtJKkxn^L1@jeJWxw3y zf*<{>L3*N;Wre4{nsh?#3dcB(0(w$(7Zc$wWw>~%KnQY9h|*Nmn-pJ zL_4#HKpqMsf?}sh963|1QJ9e2=Vue--zT z1Z8}#5^;5>QY9tIr_xSs7js$A*s{k=XqlE3R&8{isXOE?x|WNA{_ccM(?9#Tio$A9 z7|E&ebS?(kyr}$F(!NRbnY)#5(+Ilmr}sNj!|&=hBZ7rxS_Gi6E1%s>Ko89T%{U9| zz>cN6ZfL5|&=2q=3cB<4U8Z%GVlbO|5QAM5plnsrGps(x?Faqfn=j0zhnBG}3b@s| z_fb^HzE|SDT%mD?N^G}3P3@eO+FnO!F6UJ80AWu$aQ>3)8L z4s(Z*2fB9egHIFQt4iRVukCRL$|eQ}y=CCFiv)Z|3E=d4#`bQ9?=3iK0knGJq=yCC znjU&r5SBTVqcW+_X^8^*xKBY-i+=lt;2%~z>qgd#858uddw2W0U|Q~G0X*YY^b{>3 z4eUmq{6V)r;oeUKwm4A;Y%86hzGTr6{ii35%pvJ#?-+DsXvE?@308{54zPUbI|G{*1W3<)~u<9lxv$Wq35Fq{ZdCa8?TMHDZ9 zZ34Zz`k}Ny7bOfHs=t>~|R&w0f7*%)GmcGi>CQO>m-r!J`cHPnX|d zwi$+GK5kzAjB<}~Ina|&nPij(t|fa=QcbIQNizyQ#sxtuwpshE2$p7n0l~1pEz}iA zRi*-+Y7O>0n;6h{5BOx0JnW-~xt1Wm6v}V@sIRM;wV-*{7#0NR;*&bRFJ;H)D@!pO z1H{{^W3k1$>>RDgpl`0aZm@t^-b|u97);|DpkvZ-Rs3`xQX-J(p@lPlK_{7`NgV#i z>!(7v10dA>+v7G@0|YcMY|oFpefou76bkgwF^g~zKhxJJyOK?e^sssN*GeBHTE+2>E}tH?Qrk@SESO0G@ek6K zd-?ONA2g^8Ehs}1u%Y9lYYC|0gkp-`w3ncZ`k3=%S1cWA_q8#zzF0ctqiBB27w{!@ z>UK!s2%~5|;i~T_>KK~rTdBBMNu>xL649@N_a#DiTKLHT^XO3hIy>3l(qgc2Qi6S(socF|Mnv-*z2LhCLc?ao5X!?i?aQ+{ZV@0c_N z);j1#x<2%OSeAO187lZDi^7-(NL+&tY5`6>nLkNMCuRTQ7ke+M2NPzAH1TUJO zgt~j%M-yhmw?xDq)2g7P3&qfEdgN^6!!q^{DvPJv=$yJw)&{=T)^K!nY*lC^w{#3q z@HUG2ysV6?9`BnrZ5ruesI!%hiUqqy`YQZmM=$4>bS?KUUo(2-jLDTmMvazhV3yMp z{t5#}U}eW1>&t~i!)7@KIbPS6T#nP*p7K)$m2DWbVNj6+%rmq|mjb?^dVi}W8uSU@ zSES@GvZ20C_2~Xt6Y{NrR%4)%qu)*X*W;r*R_Ir{$)}ULmAXKbkw!&lh_1e)g***| z9y9!8+${HQIMe4>wG7_U#owW-my;}fki#_&LXiSYqN<0BmXg8?^xdBKNSHmJnW`)MS zdIcJ8YH<{Kbs*tWZ)C?;(8UA|_aLM++*r({Z<>B)kNrS zrTor_X(6WCodOUAsVyD(L9eB04?y#)N1F)Bho9T%fSwr}YV@t4_j0IKHaFIrKJsy9 zq_iVrOiAq{^)MQauCAQ!RE@@wK0EDe>V>CL*pPNI6Et3u<469Y`?U--kp&;4oU^cz}VXU-069dyvC=m4xS8q-YQk#euGaZ>3 z$eI0vU39%O%v?+jB+YsDe+{HdfTl(|mrnD3kZfGiRipiVN%eO1#OZdWEORa0Ceo2( zaFe)OO|OrnX-z4`82lj}tv+ynP4iV$sLw2V`V5a-e`nfFMz13fNru#ucC+~VL1ivO zV(L#WTVd=aX4ncSXoU!Q+H^gvE2rx@i!MNJ#RDUKBei!kiZyx^>Mg4f{uO{z7%hg6 zL^t1bw$lCPNt*v104d~S5Z!L(fk2!m^)I?AEsbnX>0k6yMm~5DSWpRK+I+7cvjkRQ zKW2T82i1fkE{(Ex9wUr-L+qcK1!y>sgGO_G(w^vChOWxYL`u`G$w7T~8xeLWQI{U` z8lP+luTn6W;dUth*;wq{9-MG29-MOBsJVW>Pw&c-qe{Vc$5bf~n$FR|LMnHTMqL>^ z2zqC(k5Kev<>;6%khCUffd_sA0sCT6UsyZBG4&cVUwe$kX_Ok&7K+5+Bd9eBnOVI` zFu#ADQS)q(0)WpmY062;JPdHWmPgq(uYmup1l2-| zoHfLSFC;l_GU9>ajQ7x5S_k+@t!Z6@@sG^~bqF0eYM_UcBn|x~cZ_O>Gpy0?r17n> zD6Jusl<)w{2y$|H%?s30jHWfRWX|xys3t+l^4YzdS3`aQ4R5_nQ6H5B#*$1~Mslgl zbV(~EgTrfKJ#+d@)%K#t)a+W^$a>O&<%sJZ+CV zDdCbGo64M{oxEoi0kI_DmLvCH+ytYTG}U4(h$!u)7) zGJb@Z>n2UpztP|$!alC#sZi6fC!9KNwiE;PvO6=|VTQ4@sKkm4nxrkmLSCf4q=?3CtAUUinXS&#>a~#5Ex++$pE#@H@YJL*I40W9>DG9lm z{0bY`T5;=~5SAxehN4vpT1w3e$4Falw5Cue(_HR{3DW=doPt1p- zb0a;%5GL8kYvZo@CR=X=Lyi<~U$eY@SrKCD8}8^rE2cxl$atQhb%|9-|EeQrdcsw! zN)^4$1YyUCoXqA`;kfP$sR`~M_koE53%l&DSSto8MR#Fq{;*>3d?|if7C#{KNoK7q zMSkyk<)YBKO?d_xxDXKimrZ~aG1TjWvJK=|Qrw!B8p};atZ%sE&PaV_%k_rMb=JH2F}gI4V{v8iyQF3-x( zkFf%}4F4Pz*4B$CXNx0AF;t)4-Xq(9)0J2jCh1w)rCBNad}?2Ar8RI})7r6G8{vKB z1xAn;(GYl<(O5KO#+->48fZoCIFG13hgaY?7)CuvTmv(%{jZ+}gBo zVT-c(W5@dS|Kvf{4$K20Z@1%`4b}Lt++@`PAgJ{QZL07d+%zAUXr&z=+GZK4_JCSd zD>%)SyplQP7qH4)EoEq;mTD3N5QjT3l9aP(@gK zL_55&-ZG|Lp2pe^gg*JNtS74>Mvsm=xTiO-i@iD)ZqJxSOqY9A+qd3lS1amkjZkfq zsB+3ai>jH;GrxKn(7w~M6|As&*MoNZ^!MT!Iwn9>Fa|3h)$8D0VsKsxF38%7N}E~R z*$XiZg;qGNaBO=~o=FWh6FrlXI3yIEpl}GbOjR%GX-WGbNi~I1C`zsTX$(5^vziys zl`=01Tz>yV2fI9z?s{tr#1%`{JAo22qHUYD5T+zb+Q8zn+(@h3u{AAlCb}s^jn;$JFGc)(e z!mHtvu)~vegG|)kg4CMsQ|~G8tqS#6HMpI0`c11T-Cd53CB?H80ve!-%5Fk;cr6K! zrXblcn=OB+mH>fL7bHXgaE=GajouKn6820s9|{rQWO1yB8OondV}qKY5IT|Crum|@ zEARH})%Id5JxIB06pTPLQJ1nkFJ&WVhzq48woEdOTKwa|>2ir)L7&KM>i# z>r~GusT5^})Br%*g>8wPm62tLXbGNcJwVN+VGR>bAsY6#bM9q(R!1i9!_9ze`P2CS z-l}9u?vx5gfMm&B*-NzGqGP4xR?@*eyy1_QpU6U}!^M1*GeOZfZF==n>KK|bMfi55 zcDq@_1(KYv|d)6_xico@h6lUe7{aCQgLlJuU2XscmkxX6a7_ zYM{g;rBTxRF14Z89?@!4bGWjPT4HMYPB;2ZH~L*CXif-`S=VV~Y*5IR)-#g2EmmeD zom!}U2r@+W8e)uEHeh`r3kTY5Ravaj3hZM0u!)5!j+`)i!9e?Abg08xEa++rpT#tT z8T@~zaQPGtF%Oj{DobluFf=a8APcc1&v2Z6AYa3o)oTJQvpqlZ#Aih~O`V8r@&{K$ zbDRpYQhQ_43mdm@pvHM3S>|Hf#VDJ*}WQfr5k`F_kBQPOIR= zbM*xpVz04;TS*rYVUyrxdoFXCqXRR(8c9UwWk1F%<%O&3|FBZv6=ot!donbjAkT?{ zZQNdLu&97ug^%|4M=JRty-Imr@T&sy5_8^vENcCveW;!k4l z>M6NbyH9QU5j#w6;yU^?0n(41)MZZq7q$*t`vR;&EA;BK9@3a-iso28r9c})SpHg( z7Grx0H-foZrL8M9$Z2TCj+H2j6DITh9}f1JG2wJp7(n)SxT+csA4Z{ z@vH^43!7Rg)kg)grHC1nCf86W45;Ywa96=nePhXL%l3W}R?#Ilv4gMpBd=G|>cmbxTi#gph&Ri5!=Vot)RN|VKg zEd@$T7*Iuzj!Y)M8y=>=c+;`);qm{sQK9(#-x&;a^eMC^mROZ{G{{5$i}QDG&`X|@YPxN1sh!oN zvv|wRrcx-8h$SZbY64iTs{Pd(*=%;EtFgXIlnZecn z>qbD2S8IPvrKj-LP+==ldryvBCEENmt6W|lsc*?q<7@~HNb?FlPh1*%|4z zN!x9bou<-9sS5E%Jq>ddSve(et{sly>FADoxsPMl2jjywBA9%7H% zk+r8u;Iga&gUxP^+R>lvQ+~JyNxSY=TY;b#4$@p_0g{oGrb=gc>mna}iT}T9JUv43 zRV+YypwbrOzR)U`7R(6mq4TqJIH_$(>vh=?qifS+iSRnL7baFPW53LK#Jx7xYpFhO znK|{@+Cvg+wi7Mn(1|GmzxvNa%C)~=vdHty205( zb1DP=pOrFCAs6P5veUweB+mMjvBRj(4V7Df>fIQaPRrF+q!rRPtRbW?$Dv#?eSK0_ zpG{07y`ET=2glIuA_qHDZ?^M@xp^`u#FWbIEopkG52T~Pt|nI!#{4jyH;HxV^O*W4 z&aoh^pm-JS;U_rVFAz*2XP)EhB{iW*2!!d4lzEhlhiqmW2g>)13 zD`FXaO1D7Lrnccz204E(SMNdc=76CSoAil{c8WG&KUVx&typx=j%>og?yMmri$gic zy0!P6Dl55()28zC(G51f%hQ=yz3 zI()=@wYS1Jdg2sV^}BzEamU)+VNx%veHERNSX&^1fCKF+9Zd)S@h3GPMK9^YjXdC& zE<%aR{agg10|e1lhEUC+bOU#dl)|fvt&sEqX)z%r=`I9)^MePPZdt%dMd6C>Rpb9` z5%@-`BLbRp6;@CNV>vuFoXK|eBV?hUq>VnL7)l641wlr!I8lqrv(aLrPnr*rNnS?y zq2(3HLYU#FOW{VkB`-Jp5N+Icrg1r4&L*l;UY>UA@ASXgFi)PWg1sZ@W+S?tF4Zy8 zSKh={SkKE9Ba#*BKt5u@Dg}N-a%}k+Uq+v3rB-<OKOP|?uQZza zP(QDp5LP5`=H@_YgYI08GNEWj2rXycN{J2*IHv2`W|K?o@=Nq=ge8QeuTW5VH64pn zR|d*lBx%X2-E@Af*hDVW;^pAGsVCpm!}dup*tAAD=kc(bOv~#R`{vZRGS}snHOjlA zaTF5I#jJhgclL|@kPRPSpnVkNth|@(^BeU zDo}#PN>ja}_)cqcYc0)x6qsn_VzVoF7_>{yYbprb;#v_XoSj2B+= z6<&j^-1!DLwq=@0ebXx`cA0ae8MSuBVykpk9ySW4?$%VSm1ZhB#TL?+8HqCicFA;S z<(K>sLf7#cuM=iR`>W_m8)>X(C?OA*E|8|><{G+!RVCo6j6Ir_F<`8eJp5hLf<}=#>a6vMkVBtF++3?I~%sp7RV{Ev9iz8(!0B_tioFWA`h;Lq!Qp+lE z-6ZCqiWM0@k+YE0m-whDnP%jY;zKgTXG`Kk4JXdZ{3Z{OT{A}|*#MzuwDF;&KMrK^ zrCDk&6-a@aDO)Pqlskuq$aeV$*(Z0T(hRP?vpl&i4_S_2H`xrjL^6BqRcwKtES<1x zo}jA$>Je;d{{MJj)VbBc6C!1n{OJ4pu-(xE#e3C|@}N|lOfIB@tHavZ{5mYsae`J=nz)R% zQ^U36XDZ>iO?kQ6UE*I&A$5NTIb-I!^>Y7F%Pak~j`u!k6jV1U9*bwIOQlZ_rz{dW zo=d}sFO|h&9$$8aB60gW)>pY=#NvF}I9#_#+}4;)$@@}euvqtGaeJ!iP8c1dGVP6aNMVW!svBtr!> zu>xYD>tvBYWYwWtwjONs)-Fr7!h-GyOyZ1*QOU~VZ3|e|e4^tLi2&|B)Ki)9sfr4mJJNr)AcZm7I*if=-N^zU$u`FDg)VF49{ z40W2YDK%>-e4IeU0mI> zQL$oKh29IJG2>ix%ZvbFnnA#<2Nt!dQj%Bf@`&M%#Y2|F^}|pn4$9N;Cyk+;4U83Z zuKGf0P(trQn0Bb~COb7Qx#}`5iIN68w>4{fL@;S1P8rhhS@{RiE{P zEi@dN&Q?vfMXM#tHpP*=$W2+!oKjP|N`l2x;_4W`#%;NIVpkOncPyQ@yJU480g(b} zW1eA3HAXgDYEQQn#~xK#Ida)i(^ecfYTArrN$sIA^slSC|o5L|)$2{qm^5ZER^C@`O~VGw6y5Sf?z3CF(4%Oq5=#eje(X-pEAi znN>S883i$!u$mi(i4~xq*iu@Nl{cnglCgae0^ z9;NLshuteHmqlZhD}u=8#Vv;{6bvP8t1@v#dJY%m1W}II0_2R5$h*j5Z6wv2+0La5 zmWfyWqx97~E^w`Wg>kCXBV;~lNYRL-mXZ4DDZm;?C^F7)?Kqi^r^RKcyng)zkc3Om znwvI9=%z^0D`-&0!~+C1%g`TEqfu0>6g8LHIU(`nU$Y|EvAl+lwJfh&xO@TK4pz5N z=dv&?P1JH@uX!z#uWlhn8j+N$vMBs!<*3S$_X+;@M)y9I`YWom1vN=TKiKgZ>xSRc@pKx$F0X9W6!-W5T$qJ?yiKD`HJ z^5g{zn;NR>xrg*u^inrEl+;S^l_Wo#(JWlmWx^sg&%q0k74s$uHs>xmX*dQ#1HI&oUcW;(KG46*o8vt} zNA>mb3tDK?qN-A@ao7r0B4+~uQdw@`8bsxZnjKP4oZqGRQi=j3wyrzZ8B!7oR-H8l zAE6XZj4zL27|{AD9iQ`Sqz2OM35(EGv?P$rGXG(2YQ@8UaPNn=h&6 zh!$hGd@~F$=&oHCjp;-H5iMGf`DWn*i;Lx?-g|%=^nLbJch>4$FuhhPE4r#^4+XL) zfarwk{vLymG~X!`0qI7NP30&5g5ad{yR>47JtH zcm0tNh5O~X+;S~TlaQ0au))vQP-D76Y-AtOcql}z#<7_9h8 zdF6&ly_8`I(S%HyVvYER(qLKYsyc{XBySc7?!c!itLH(UKbcY90?`>ZQ1LQsJqFSd zE22tY(yN`=&4O>HV`S=U)UDonWPK+A8}&WEpQeIQ)pxi!Q*Ap|bW=rP3WB&HGS(*A zO;9Xjfx<500pbM8>}@`C2hh}zpgXSNEb1na>0=)WmJAIL4@3>AY(AP{TpjIGZh&J4 z=Fml&<}`rrk~AGSa10mx3+N5vXR3?zkha}%RwvVOv>C3oM|YR~D7AzgCdDqbMt^jT zXExEsR)I%1Ymg(}OQ#qe;|q@sjU^9L-_C;@_TzXbB8*sp9AhmCOt+_C=^49cqSxRk zP@pmCU0$f2%?vZ3eNk3e6LhBMLebR}&XfIf^CY(SpV8qXcB9@5KIQLg4VCF0Sbb2Qo*b#kC7Wy-{XDS(FnMVN*GUM)czK6;o~ zTCWYT7N<7DqcRneZ(HJVobhG`gtk>6hDNWr8?vh9sJX+FdJqm8E;*JDyy#Zk(r-BY zK=0B7@6<2iB`X^cq@jTC-Bm$KT$B1$aAkz>T%y7STD<8fF`%J@^@2G@%+qo=2o=MVS#*BE@$aMm;m!?m2w6yH1>h zjLFVX5)4oJBm>k_9{^2t^Z~P~p45~9blDa}?P%f8fxF=a#_b4H>%JYn8^c=&+8SEn zm5d7er#2PdD7dm|Bgc*&b!-v_lO%_cq|O~>k4xrgpOjg45E(wGv&#@sD8-l%)deOx zi6@olRiGH%fpI87P|JooUvdb;Jfv#VAhN^g)TV}_1yg406NgHrHVtGOP_o;$I%a>~ zYHUVJ97Zf2EMX}2G_3Qe79U(K4Cx{bgUzqk@DZ@fNbtMeam5IZD_}RD_Y$qfjb(`1MX>Mt%t7&Pi zYMRsB+OV*8mgVknSd28)mbQwErMlx{dSw0}uaJ0EvpfAnywEe2&Wh`xXAy{6TmyO< zyRMl(*a2Jw|8$6#gTBT;Hv@!oMbX8)4kpemu82F2c=QO?euwfnoEF>W7`E1KuqAV9 z1O0-ncf?E8-{aM4K!Mt0%!)BO^JQ_e#0b;|;Qz8P?M)lcMh_NeN=`~k*bXVXlEVm? zzC}DROXu0cT<-252Oaskw6t>i2?5d=IeuaR$o{L5t=yoTPa&W6z<3L!*4dlCNAxb|+H~f5?XoUy|wupB|x(;vpv=B1zJF+NjuY;#!@d;^bW&M4Ex*YLzLXWkHRe ztPL;p)-qyB3OU!XN&+sguc##~%Y>J5qGcp>*YY)M-k4#M0@iAeAkU)KH4K$DQdQnH zt$OJHWAAO(;yRLa(cjEflxWMEZFweR|j z*EO7B8$YiA$g3Cx3tFv!D_ z3LfyD9kaFZF#p3!eK>&^E7GBMpXGpZMzwP&L$Ko)%wnvd@m?$jlF;5gyShnX?ZIFO6 z=CrZWGG;O5i;fQJCKfQU_3HbnP;5q^9pOow^aW)st&bXdT9w+iyWd*=vG0EbVYvZ%#fIh|88-i)6xJ z3r(0dv1rL8!>#RO$6EF7TN$ee(AHZlL4)pzH-mVE?Uu&3Wff)JO8VJkXcf7HwuW4F zih(rZM)u|=A?EzC;JHV&gxbw@qiiYGDECoij#1T%Td{s$p*ADVZy|360V8~ZS9sb#;?>kP zaKE>PTyXoncZ3TZFGnom+ljmKvjTq!Ep;#Qnqzj=r$QzQ->WW3XN&Of3UHB0197sZ zOW+;$=0tqwY;Q1#cILc5dslWDh&X#vjI0J7<$lTsdSLmf?~ z*bjhCn~trx0%8H}ombn@QE*1`y0@j27sL|iM|t~eL`s&_zoo2nEn(uMHmC5)DN+r? zI<}F+w=3r%@iCP9Rtg6cgitDoK_Bvz6rE&gN&<*`GNYAT#jjXNMeVr-21gQ^amiDj zBRNZ-#@Gu|L%o&qGyGq5t{~s7n!$k)z8i$BgV^-8fg1e@jjO)bd$>&kcbq=i`^#W| z=jqno7Jg;EB3qGkOcTw`KthGTs3!)Q%w#0n@5LY7B1A$BXytM`L1rlqUFcvH^DRjL z@Po+p<&~|tzlCyu2d$1tA@HW+4CDbXe8vCUslY~M1)SD^%qJo8Tp6yw#ofQSfG#Yq z=O~5E^ZPtNNsyut2o)mF$nz%IqnE?;@$789w{;#h^e~#AB=cfcWj_Jem-Sg_k{0^MpY55;q%F~LK>HD`N%MFythd!pLp}fXYq52Unz(!yO znaaG^7#z(v49>0hp772iOFw&oRPZByyFTNwGOn?1&SnI7Jfp&+Ja1%^>RdUuNi+z! z&|ET^wZVtmnm8mMFXzOhwRM+fzuK7o3(r-4iG|H4nh|{nIZ!hZr-5`nC>*=z`{m@d zabru$j?aIbyc+4=^`-)gQWaFySP9)I4g`7{kFOJwIZ}xwU4;%&jvL2tO{~#YrT6g% zkk>oFN^sUhCRPf;GJlcK(Bu5~P<;J%Gz!6EWZ85!%p3%_bK=mJ0Xly5uBr3F=vrl5 z&90!uC(#zt0S;~XAczi=KHRoR(Xc=_ONcwE7vq`oBRd1=^{CPb^Kz7In?M(xqS_nN z*1TfFUV8GtyQuo69;RPpx-!D#Hv8hpBfha|WBzT76r-9cWN{%kq_LZ9XHILp0Aul> zf+*QpMX#;7Y?F41&vcshgXhu&5WN*k&Vx?3mE;IaWuSC?@*CJ46Z(%a6*YESw}_4v z-?bN}IT`!hBTwak;MEwgA3R%Z0An4+Qg`Q3Bd#hBII&Goz_fOciz@tm5HTbKa(rZ` z7r?*oSu%pTrW%e~v zgWuXNO~`5xIlglh=TSm-+$qd!PpFjV9h$4K0Kl8WGwcUY?}U81flPF^FXgI zq4M4VNwl^F_V_2r3oD$BcBc^ zVF8G;idv)bpfeM?Puw@iB#q|W&ePTRqSR3vkdD2 zGQ~)XMpf|~Op)b>u>n6LZqha0;p5$(96i-@d{lJ7ufQ`4WVt(k<~7?naA~w9`<;>A z7}AcM<4g*Yck=;oh%k*|gWT%uB2OdBDn@&3)CR=DPp((y^(D0_tdqdy^uFjVKfvik ztREH==o9gfF=$tinBEGWpVyZmGM91Z2R@bw(RvTL=M442EJe-B15zuj3ovlo2+Ng{ z#DQ(3H!xu$Wil|ujqWa9CB7+Z?EQV<*%g#BeyGpn>yH0}>8*QXm2bAI>7Z>BS`?7Qd&OqH*8+74@N}@hI zs#bxvN*S{0HlV{^Odi9B%3WHY6nopDx}xVUX(LJa3&~&hU!=}-o4OPw@1apm1ZA$g zsZ~>nmYYkh{}OBt^Dxm`;KO{I!}|+`D~uf7hMQz^A`$#Thh`B~yYMW+>UmWP8#M|s zxEd?v$t}|z5GyB>$uah!+@?)UO`H?R@i|N2fCYaMTXQAr0N~4@=u(RbJ)W_g3U-*m z3%)i`O*Oz+j|ZVxih)#D1)~*@Oe>M&ym}*TU|$g2w~R838BVN3{zH9Xu>6Dry2Q^` zrgznpHdVN17$yZHgSt=y0fP{+Es3+2ET3<*STSFdBtCK(51M0x%wO`im`2PXkc;X* za+YDt!mquRkUpO6>&&Y?|J3d|iPPcnF;wegVOZ{gsm4BMy8Rz2xMuxE$3x#kP0$e!m zJ*MAED(Yxd#l_ez#WxUk+p!XADr^i=39QPAV4>su2;qVz#u^!~zA4=0FCrx(;)>;QE{QA<2P=16`x${N@^2sp;A zIXMTcwZ}+lyQiu2i^`mR*0Jw4)kEZww}d0Ax?pPMcEm{{1UecVHOA)BdsTVLwnCO4JVT#Gz zN`q7$WAk%2pM3giX!N38`!aRJ97&?}`RH_Vj^l3dGnp`D_}vKPQv3iZt3^pfq%$MO zxxcac#pYk%Jv*HJ>F4in<9DsgyZG+*;p~$Q9Fl?!f*EB}6BE^Q{-pOi*+$1#XJ>DE z8z1|ACmDr$^$+X6|9AuFyx058ks735&9A_8drVSy6IU9R*wOSdQU$9)2x&aUm8Nso z1zQ{@ZlPFG|M?@1@QW;yx@<3$M+0o9y_^Q~*otYO!SC`cFdZZ{&tH}dKeV}#9`FvG z*g3=WFb(o~Zir_ZcQILRot|RXhRfX-LUCQoOUR8vWs(TZnw1bGm$cw7m$;Y$7Z{QR zTVbo7K-)l$+7{?>=EDG)|I#`G3z<+r*TQ81nIWtowxai>gc8a!n9@20%?TcYK5yD3 zcnfAuMIW-Tg|Rjq1>muC!6gf76SWf}B6g?iMqoW~D-dFNi?-w%V$n1zk(`D_mOwXW z5(09BK(^;k3=ul*(eeaYoG~|QKkbp;Y-o2sx5k|W{?D@Fz) zt;JO@(Ax^tzyqeb17L`=hc@Np5QMJwL@E4acbYmybhu+bG?wjtL{_epd$gGMi;st0)dNI;Z7qxY377>~(Y`2?am6F(;qUO+(6Eu(i&sp<1 zMV8-Yt=gzoM`;}Vm@&#!-ym(I-_+}=1@bj593%%$?%Eva$f3m`&Ze(s&}k4LEi8J_ zv1a4qd!V)v_>y+kih?_9s6#ciAvXS805Uu56e)Z$2M7s!_<6G<6pvFH3C+bCq{WE5 z7OX;_$a8DpDJ+Esfcq|dZvtQk&LBmT;+}&t2uD=%cRK~^ntrdnf_=%8>C59 z`0HXbE87la#!DvM8kv%my*hwUVi$>*lL~7Zywno-lupWjm4Fr=4QA zRj^Ysv%IvTuMgnWm_^O6{dAWt%X62j6a;p~>YLY1-PXqW>{|X*mslB?wJ*j$`MSi% zNK3TaB0rjaH0ymdTUL6Hx7F_{42G)YcetT$H*}~^#j(XqKpubT9nXDFZ3?Rk9W7M~m0Sgg1LXr<7 z0k+!#N<$3_33Q%=%cSAhMBy1jE~5vZ>Wtd>lTYySiyo>B0v29)$^Z4>mEosGvADw= z>lP7Qr&gSXu_RK8umm;wcJsJV6B+8gxY^BX<>v3q{%(fS9yK(+K$ z0JKF1cNAnoKjZNi8$vW?+d#ZSZPrUy6mwGS=G0w2)y*4aSY8km7OF z`Y|)z#i+lu!^BL7;FldFYye`pTPYLpX7blg0Aa5bbl;RM*jhum(W?v8UxTniuiB48 ziV7>T3r!`*sx9$POYcRz_=v0(sWyc{;Wx6BSq>NuxRHQQj# zitVMF0n1NZkb6WIPs04_nqiYLV1u#RW4O{J4zD8Hwh}||hU=L`(Ol*zATTO&(6pRE z5OX%N7a-iW2LjM4b3Te1P;wWeUn{-U85KnS$ONTc_*E)e6Qc}2)E{Jmg|;5#s=75U z^`2J4!EG$Sc9(i9bI3Vn5ER4$P3KQ>UcHzDDmH))$|q83T>M*MK+N%OBjZ1v z8!!_c_+m&>I{_qXZTEmc8*j1m5SPs5b8=p`KF4DbFLS-0!H2Do=~nQ&b8RG;t(l~R z1%}E5SVe)jJBXSUW)qE_>(BgK=A~T)QJ(onXchm_ip$AG;++tWot2P)pPPSJ-tI7O zG!-XY3}XsiW65!MkFIdw#Fr(EdHIPtZ!}X2dSGcDUe>DbcSYot5v%Cd926fSVM+Aa z<*)s)lT~0jjbZ8as6{n9vKMI-J+eDtv$p2F05iag`{L|-O;HK_>`X|aP9Qnk3kC8T) z;)dWVro@Kn(Ae-efbS-ev1q%4J038tj$YAavH^6Y()PLcz|@eh3f{wL!VEf&kiCVu z+AIrO2I&ofHLDgUCZkY;+bJ+;&9u)pneCDQ%l&VL=YkVA2R_B2EAIZI#?J{#hMS*C zK-Xw6ug~)hUtSUYk=W6rA6>>G+RC98qaE5IT=CjVb?7N18bVe)Ws97nh!4z&%#>H! z6EN60Kdz-De3zkJ05I9e!J0A<{(wIP1D!etMc6@55ufgrwj)6;A>E@zz4tg_1aA{ic~ zY>53h$UpKwexyAy{H|>%cQsuO2NrMGN%%NM5mkS%P|CkWiq5rWh@wFPrrdJVTkW}l zctcA0{w;)5^P^BvW&s*B&i*z<=nqzkwp$r>b>0o6|hwkNTcX^`y^;fp$4JMJys`>bB!B#Nx>_2;lS1#TRD|NuqjfAxJK6Y;J5+gtohP`tjh{3W?Jjo3sA&;3W{Di(+F8h#VtkG(-h?^U1w!>5$_k}aih@$%{RaR{G^2E&;>=^4)9mJ&RhvdKzkr0NNG2XD`moznJ~7-2B(4LitI6Np_wk?Vgl@iGJ0M_QZ%_**I#d}a6{b}f z2f1ivw1}Iv(~+wF$p{%!<0IG_I85|i6#t9mt=QSj zN?D+r@yR)%rAL_H1LML-I-c;7a+#L^I5sPQW~<{-AvQ?NTE)%TTCspVXe>1?qJ8L| z0wqS_aiBC#{+I@Rm0A)gkNV*DIgk%jGh+FPb|G;u6Y~DoVbkKqiCBc& zcn}wBCyA{OGg!E8)ToHwI`(e4X`6ReL~6lJJ+phDh^NoT@JwLN0D!w<6kn=mYiqcl zesp?#@9yV%eh=Ly{3pKDc5#N`^34S=z9&Zrjeb24I!8hLSEF+vO`X|aXjdGz!L{Fb zUG&8d*qOu`@CJJy#gy<#*yKRw@kF}=dBviYU?sLWcEWTM_Xvb0*rb4#mQv)j`7M+Z zVu=I+r)qjQwSxz!sDveIEGR>lb;rVmKmqhFvJEC%dIu2GPukd_krdZ_?Mwln^-yzC zmca<*Wb{z#3&)&sgJ{fURgD;Ifq>QkTAERTwA(tL<}{&4gSq6(nh@PWRbBXwZRCR?CP?Gw_%Lb(CfstYIxzjjyDU4}9dWkjNZT9WGD zuEtYX7ZtHK3gvcFGz5^yp(T{zp8))H7`K546?3_&9A z8T>U%f@x1EB*xMat5=r#chlzTN~XYtVIBI7@+cZrGtcUtnMMUf!6Bt!5rrhA1u14E zq;D$qoN6*VIy%}vhuxfN)Z6sTP)ai^M4zIBEw z<0;Fe?lDW=St^G!WvqYsk67a-w4s(fe?n*f-z-LAH(azcNi0#_&gCMuB8Lp;2B%D} zLCIcT2!oWnsU2-bX-tfStCL-6 zUzQk1_YwNIl>&gwl1-=_Ykte{OVjHRxQKITfG%bOIcEr@+d;p{)=x}d2bM@ZqKjL( zsdHxuepGN_m4p_THwI>xq5$d(M!kS-uf^uk_;5^o#dYO&0@PgtrigiE*g8B(`1t}T zpi_m3%1(E4m_}L}))UdrmE!Ab}bU$nG3ap~g{OKsq|-Mja32sV?jAl&7SLYEIBZVFdo_ zEG(EpKaDR}KNA)V?^ibCvNH<(VziDHX}C-hQQWtqb%rX1pj1-;{ulx%a08I?ljo9I zkqL_6Is8|z>dKrkGBE|NEQe)>?t`BcuBe9`Y>~)s)ayaOrhqb8P!qW=({lHc z(o@nM@C_D&H|i-<(~}T`?EhKc^rEd$2sA{O;a@vhW0$mX>5qVkCSiTdp5+UlGl|nw zBrAF+4zeI9+7lD_uh4}iSv$rsACRdLiMbQh!E`pU%AyH8VwCJq`G+w|0cWa}0Z7dW z&o4m-#hg3g!6+@>-Ziahg{&jT3idN&7I|IC?(0tcM2X`BzpNl-+3^G`JC6Q#!Y+Bn zZ;MbQ{;ZZQ&j+aS!XO_y*>fbE^*peg*<%&r} zgknm(Kx4}Ttu*~IY2c5HBl%jT6&B`V=+;u9ni(b-2aH37Pz#)4l<9ObwRb6>EgrpcOc34v zk>Q;lTY{c~O;PPO>wIyya{8dYYQrZL6-H{;2%Chb3|{SJ*6rb=>ETl^Fp)_rG8n z%sy`$vBNs15DG&$1~AG^Y=cq4^qpKW@YR1BS46s-w<(h)3=kUs%`VEgxZXvVODpUX zaT1i?LA_4B``OvdXoSg-7_^zNVxpHXF&xm8p@e>mK6|UYjdOPN^KI`^dO=feX;poc z3Dh}pcmZ4bFmYlSq~t>K2P~C%6tUOZVT0pg+)q|*#vIuTb6uoCWHu4B@WdgR5Y)BY ziJa)9t###7v`%@LGyYI#K!$1iAX)vaZ(r{BF;WKRz|+{{^P|)YcFTnoo5{6)c}MmF zJT^?pjX`20>B9ypBmz7O#{+c`sS_0a2Pve8wg@DxO(7+V?I_c#jXs>7U1Yb`1+)Z$ zGeKZMxzO<)O{EeV{Wnr=eU-Cmmi?YuUYFz`meFNwKL)dCzQ_STNB#@;`AGN$+3Rh- zEz_;CS7oI!u!a#_0SaU^+fX%`b~D>4PMT)|^@f62mK7VCbBvEU95!Xz{YxA=rr(1Z z@(N@%i6L%4I~uUi9x-TBJ;V$%5psr*B;sUBN6ycqAB}j2IY5v>NNb@>NX$j`ZWQi~ zdSdO zdt%%_z=#}!t9N~$Xlxy#b*tvDaY&h;n50}~$P{E{+RiPKi||4cv2~ng zPHfX`<=zwDhg`?KcGjC8e`GZQ3{~HlQ}k7;ncfyX%MQ@zMKO(?(G#9>opJRqlT=2@sJ@l?hQ3c?nZDfpd= zK_T+v-;!U0as0F^wlB#Vw9vd!&|M?*yiSMC&0WN8d|cez_!^gRu>k1M&&DyeiCKIc z$ts@-7mCs=S{8HD#w_=qPjMQBB^{B0i~VP>PFW5rp>3pAJdT5)Ub^KNIgGfA6$?V$ zQ?#SZFU>WtP;+$-0zoay>D3Dqq34np$Oi5U78YZrtYt1nV{M{&cQRk>O}Lp9IYc-k zz*0Gb8t~}dET1TA2G&&Ka>7>s-Cs8jKR*1}^OoN+XNWs=>2u*M{%U`Hc>e70viCiD z*jRb*kN+Cq_P%&`)-f{p-8ntrX)FN+c|pg0pc4;#G>=TnaX$C>Q@!6aOg~fYir9pmfPN`ECcM9qV!=RXD2MKJs`2ev9A(T&<&(SUo-A%5?I8ZB! zxM*dGnLtgs{>vMO&%XHFZ(q5${>kC_W)JB3;`Zv{`MZ_d8!Qvu=KNS?a*I$N>l`mk z0&2zMm0_?{!$AXq6D#uZ3u8(}0aYG;fubO`@IMNdgsnuog)C(|L|V0C{=xFbUn>lL zywNUv5)++A6zY#=G&&`$BcDCLT1A&qzQ8Iq$*J?@braH&S6t$<%b1WD|dvdsVmB-Y3! z)l!TJ{A0|NqNNy;hjR)Td6KdK5`Q9Ezvdh9#ptQq##BrOcJ_H79!qDLy+t9gVEKA|j(IHE@_8yn}+Tm8DUi zTEl!ZwtTP@p!InPNO}| z$BZAZ!?)0TL-hGU2c6r4$D;L^J$wNwTYve3;Fj?hQP2Oz) z?XuIG@&?d!>6Y=$(d6RI0HLSp>nX|@=`K|ozy5t%R%s0TVtR&Q7K~M99ogy@E31VF zao$bX&P*Rb*Z$={NY^c9PDl{Nic(s%9ZI2~Y~LkXMt{AZ{*J9(MyW2=5QoEA0z?UC zcR#~J;L_B_-H&FywHHZFE(_za*K<0=oiNDTHS&QsH^8n4mI?o6=!8~RktXRtA{WqB z&J+P7m)C@`8)88$??K@OrA1dF+!lTNNThH43h^2wF37Yc_W)c-GG7&W2X*`V#nf%r za>da!D9NRz_ay7|#WiG2TJ=&yO@TOvg=Ukh>5=M=WJR|E9+Pq4OOmXIunOX*#0ZZv zrWW^uP*M}@~xYjN9cgKMTn(p}HOyX8TjdnrguiF^wy$*rP zP*wCIGTOg-4wvYqQIg}*|+ssVi&=8xqI!Xj@s=+4w|vDk6q zEo4th@L&E`*SS$Jv*%uadGQ+H?Q&nOeM1xkVzLgG`=Y&h?l>z z{4nG~9mBFHK7moPHyWOj*CLBTu9=wyhCgr#P(9bNI(&e=P%PmLZ0c@}p1|1qE)`&d zibU}d#YN}~VgC@`Ny@1*KWE4-36>o)U+*g(cY9m-I@Mn4+3chT!a-WVj1`4RnJC_j zEyp*kjEU}XI)#!5Cu3-azrc}ERYs|IRnZHDOL$X_?NqwQ9Ai3s-D61%{H^eX*(C11 zTJXsZaI&$D`oc#1li$QNxdehfhmKV(oCaN-&qp(%@*)-J-LDH2s3F=(vy5t3gFNC_O1`Q`Rhyq4s4 z8J9H!#BItMGuTsFCaf78W?H+4g@Mo%9!$DOq&UjelTl@J=`202Ytg(sw0Du)F)@l5 z6NPB?=GBS@{s%nJW0MP?LcmmeV&LO~gE0pPHYi4$jP%tt2rE=wa63*6fSP9(^x>~k zU6s;GC`~dxa$V;lRT8^}SuiqQ;IUVh+|a#P2Rvj(Swoh3IU4>rR#pGm1@r)-7FOK{ zx&)=IwCTQ0(-y)M`(CzU=Su!lR?e1kI%t}U=0+#V}<}E z0y2!g**(Ca#3Q)uy4NeZqEbX}FHzYGxy8If*GmI6#+Z&a`N`_h?cU?@>8!Vfwjh%8 z-sk5-`}NECW&L<`k8Szie}`lo_r98(oQ#LKdG+)ESby%ne+irSc>TGWZnVpKf}mk}yT6@yjC7o-z1OX9kyVulD;+-w$C$)-4M^$p8N3CP~%7<;CW?57Bt zwa2@> zytN9!;hoD7g$QL`0;ZO-!Wt}AEIiYobT^EXlPv+y{krnu?D5|UX2+lW&ya2?iHZv) zYOpc=6WCDw3c_YzK4tcmv17dkj^YzX18N@nw0gZqE+JDo6bOlxPRLP#D)BRzixCT; z3?zDNO5TwNOe&MgbbCT$L%r1LNr5#e0w4qb`ZVxch7QT_*w)6T_WA(fd$TiLhp4D+ zoH~GIF@_;@GQ;(%m>OhwbRT}R^bWC(LM2#)+Zq*A615uxiRraJD4LXDWf(~q?x8qj z5H?p+BnXXhqZ+MS1!*+CU`|d%YHl|#7h5S5+WcP-+_nTKWSz4Xxur5wN=9s89lnfz zbk2FtctEZ^8+|S{L+{5R>H?PAh3YUFx%|sNSTYx@>YQ_zb>$(v zd}Km!28RVS4d(ie;afS|Vr#ZqMAMY(-Gm*|oE73>B)BOQf3?Va4i(FKNOT-u`}8wL z6K=3u3*s3mLPDIA@659`+{UZ}fkEsfSe%66NjpJXU=#!qPw^F&<8pGv7-}B9MJ3TI z{U4EHEx>3PnK5Z1;W{M$a)JZasjtR0(gW2|7#E%+KJwHP;+x{;rbwqy4xs)KoNhCc z6mt3;h8x^oBg|{aw-dQRycQVk`Hvu;n-VYfdF-x1L!&P5D2cl^r` zYl&E<3^t8NLq=QMT_+b1#mCzB{6~%2wrWIg3$^1M@d4wsTmc)bOCe^g{Ua3ZOA(Xd zKsL+wmk_$~lpPgj{hCX7?Za%(0vZ%Kcb>RxiJ@rR|Ljm z0$6fVjj8a6E*^?JBKgw_gqZPJ zV})1Ne)VQc#kohvwvw8`u6H04(pCk5b_O6~v#pE=8Wb(Wm}O+2!7ybj+X%x9(edY4 zs+d#Y5*D{c`2_D8?L`{(o>pz8cB9^?i5mc=mFlT!d=&2HjvQE~DA*p5ZPLuWxC-rZ z+qrz6;zQ{mO_!g{z6=A#{CU$)FB~~~N2Fw7XCDUgz}4n@OAc|1U`PzP*caPXb4tkd!x(&j{JKGk05U>tI2lL!ig-g66ifu1PEKRI zO3SZYO?9qQS+=mWW}^X~L=&>F;ofUb%Z}jwhnF1W&ptIT5Sms>~pT z0EZ4gwR>6F;uJyRvsfi-D&kAc!AmE_(Z}CB`|De$@)R5V`TO6DasC3Rf@vy*xLS6y zPKjv-Q)*F>^8+V6GfWp#b0u&a0W7}jCfy+JnC)BO(joL2DOO14S z-aXr>un@B8UPO#jNKc*WQbziY1ftL?KECxZAM{dhOJY>tZEhaHv4({MONUXXayEFR zA!Va+4{XlmY6$5vOt$D0@{_Ae#4>c9B;0(vU6)&U78bWdWoAzKxiTe_-0A)I{U?ua zmx;d*{O*Z5@mISmwu{M~#aZubPCwjWT^`LjYliV*gbp0=?T8_JPkyc$xnJe{5{?=n>uOg5 zm*%E9fPcM1i-eM&<8Eq82rz}UVw2R-qOd=eY0|eB$k4yn>ude3?oi*l)pH+033>Kh zj~RL8GqdQ?kKdwgk{<=9L^YIb-dFrabDh?wWS!|#shTJfmZz7CafIT9MMWMhs?@NiTn+!^bi*BSEET~>gDK`i= z;Y{_1DE29?=XQpba5*Aoq(z>)*HuEQnF+eEksFfGs@W+x9 zyt09S{a}l+diw{~LpI2vaVRdub=u0rNXX~)k&vb67tM%~=ZOXvL<4mR#Of#LWH@WX z?z?x+OQQD@?M8YsY~F%if?y!XUk_NY8Lo^txfsP1F9{B%!YCa1wFtXNW;Eu`7eiDZ znUH|Z6=LIP_9JD+f6Q=;1%8@L0?5hswnP+2v4T?#pzA-10@tyREE{0l+h#D!m-lz4#)RuzSu`>n~(B*B1Kp$ao_>@!rM1ss5t9J?Xe z-5T^T%hHn2#BySOKe{G^#)8}=8u%F#l2vHaDlX-yrqjZ`D}Y{~i%{X*)^IjRw;cx( zfh?{=riuQp2P3QlQ4*$X?eC^5aV)bNPc8BxAs56O@|VDp1aK$WjQnFb(#iN4VTNo1+!H0wjUNo*jI)#xn z5-v!lT5NaJVx7A=w6k;jTvSRHXOC<5*qvUypD=7QB=`*h!-5fQpxZs%bx{b!cv?u! zfQVd!bPMLm0ju6nut{#DBtF$&x4WRCU6#_O&dfZlu;4N!xU%wntzjqm7@ojzU7g`^ z*Q$5%)dP*+Wg5)4VG#l0qm#;oe##YPxMnH{r#FPt|+B41>t!C(BDzl}rSnXww5@07VLSVKs95d*Z&!P` z7Vycp2cg&S(*_C!*Fv5&tok%$z8RjK`WUK}TAiY=l8y}xbo2OI&<4~p%yZ=s*Dzj; zQOn$Xk80Q^M08C=w^+9R(R&$T+lRM+5Sv>yT0x5t4)et; zAc%Qh*;Z6BG>t6Zi5%kL9(7gPIPQZUC{hRigT5Bqhx^%-jN-OA&Wr);0TTu%ET%%a zV`_3ij(s<|&$BPM2wH1pucYU1A<=+at9;HcyaT*L5Gac(knMQDl6OU;#8~$L138b)?*YH z1o~Ms!-B&8`t=x@k_cd8=J5V6>Ho_OFA324Hz`*>kKl-w$zFI2INo5$c~rXCA=Cw6Id>YY;$%# zOO~!nzH|?OaJA{mF%B21yV!m}KNzwl_rfU(X@%%;BEdP7^Ukc#73>TS%?8c?B41-z z1e-g^%dJ)u)%ipI_P{LRB34a@Ov8-N%dQGH5dpC-L;FKxUJ|yYjr)(ehn=!KP@atk zPLY<4=8s>xW>iMPDBhW1;5|U<8-dEba5jTlt;~!F1d*G9v))n$mpz$mweOl79YC_9 z(4+W152uA<_as>a=fhDe;^oyn8EA&Nmh;H$BK9uKZ}pvDrx-b(NANWn4;ILaE==43 z9gF%fy^wk!UJ^rQAHo($B8V-_z%1-z_al-~i_<;0U@j{O59lN4%2*IzCa_E#gmD`S z+Uq}1001GSe`9q;1gNZ`CKr)Ls-XfjKo&&+3UbCR7Z{IJCQ6t?W!}B3QyWE*wXQL0 zd$`MHuZ9fRiP#QbARFq2#%##XQ|MgKZdIPJ;qxiHgoT!5mZxIHOI}h16yzQ4){TMZZR2= zXb;kD5SQJAXzkwc_;_#fI;w}8jhXLqx4`v6f0dRB$y*chVW~l^du)Jt^!E{K*&?-$ zVxA>sB@4mL$uQwVd}!}dkJlsDR;tEr#as`}IN+`o#pu|wiHubM4Xh5rx`5FFwKOy& z0+qz(_Bd<~<8tFPH<}V7N_O&9v2UO9m0};a7VEK)(te=`)S(k+vAEtgtL9pJQeFy! zv)l!Fk~4|AFL37Oh~>HegKdGJ_l>sq@hhGj*q}G&9>X5EE1jv}oUU z;T{aoSMX6m@Jh>R?}!=k1hp4NOV;j9dx`yrFmu)COQwCmWR^G_Ul>F%M6yMMn~wx0 zES%yY3u-$-6c$oYg9X)7@9{VsbYAHobhzs~bVY5AEgnv$Rz?;R%hlrq?i(C}9BLDuw21TohFB2r zVXbbR#UJ*z_y0}FRApijpD}!@Zf3nS7})%uP;LgrBzk*Kz8mcC{`(H5_s^gHw|}7| zkD~V=qtnsT364&VP#v*&evH%5XP6wG=Eg_5uY%Jko>?WCU8JJ_RJFC|I|i6OY2`5p zyy=yS5k{sOC^U@?fctm22l^JMckiJ97_VP=<+%KHf9f`=38;>*oCK1FXcn*NZ!7DH z*~IK!80U4kN*#%ey;42-7$w+w4n`cU8XVKnYeZL|xHvWcBOIi1il%pc1jj$;4GpMh zbbEfN{XRNsU#gPkaCwE&w*hHm z^(B6r9l+mO^l^|BC3o{v1FWPAhsNoRD6%7iKrfOuVUmR^*GH(xf5{?j#A80U-A25r zIZFdmjFF$+rXVPT!PH;q4DSYMUGT?T%)<^ew!lY81Eb4A1KX0tf>RNXr2y&5h75BN zX8|LC0BPpe!V17NO7chHmZfH(OSi6El}E})fR>%x&NT(-F$;AS{ORkU#pCs;C9X80 zWN6o#LNkmrM~IpVb>axA=t^3wEONp;?%4${Eb*#3Ng7gSMe*5I;n_W&kvSWsnutBr zpPiR8TJ^|-6sY-N@*QHD1+O5*XUMKnrIBGzNzCBLi&NA>hLrWor1^M^4}KgEdyjTm zyo56U$%6;`I|t~Ioqp+O9A92uUd%Q(Hcn7sVEqK))vM?0sKm1I&!7Iwr=NcMhobJs zpP5rVUl$~ifAkXfB_bP1)icslL5f9XDfmLVqvF!#pnO-n^qYSm$53)wr)2VndWcJ= zkVb9jXuQvlGXo@8K%__)!^q8ECof)r+M7?0pW_L)0ZPb^adV9dYZsCr4!&$d)AA~z zp}aJk9d#XR1k;?8Np}Ft3-N4(uTLkF3tL;LX`ZZ~@-i!=1?w&BOspji5+E{n*8A+! zPkGN3eqd_|%lJ8S1n%kAWYp0$Og6!xmJNroQ0fmAO!3Ksy(iz;D9||U&%7IsYpjnp z{10_^UeWtou{W4JUcf%#s2gcm{q0prAd_fQtk{gX;bXtaU9p$zfXwrb&-*0Vqth!C z1L6(nMyTK-j8}yRaF5<|z_yYJOL@$?HXTbTi#lNmB}aJw;Gb~6%8MZwrDp~qaQz2N zb#>wwc|pdSbJI{dRT{5N1Y))r`L6n@Oa_}Irn*dyQ#~`LKf`5V_6aA#T}t(3e2XtBd&!?Ls8MvEpb#?o-`*m#=1(IlZLMKM#{C_o%_VQ(ww8(1yX4o2^OP8x$qAbIrQF;hI7LZ# z%Zwe+3mF_gcbxcm!yDq!ATUZxz}lbdxo}+HrOZd64SOFQlf|06kRJK`<@N^#lE(1| zfq2(BkeD`Zf$&?6Z{5VQ#jwHI3(5{%+Ktr723(y*Uo8#x&KkE4`?uQ+ZL1C9F(qe^>VARz%>m2}R?zqui{R_@-@Rh=PKzUgb`8a!WktWm3bd?66(g0A=-NhG z!D919toM4WPlM*0<@LR#f>L|0-9y#IOD1kxBvx-clGWe6Piuq?Alp@g#?r*iOyu** zOf(hq8cESJsyRqMHd(v3dmlp7el7cwPc_$&{N*MlOG5L)gg~DESMSMQPk?Ys=8C(N z%kuhXFHy3XR81$C4XWAw@Bi_?WCnEGz4O3*if+OJzriA8SYr(eKy3~VYFZf@L4%XC z%idQz2jA`NJnsF}+j@Mz_h#WzEu4&|>4v<(z)lX24DQF>6bL2w@jG)p%t;V&|L_0t zKV@FgKaR39+^o#BtKRj6$Nu?Ac_Jr55pZD<J0-K*7gI3qqVyC#4X9fghHPx0oEv*4MEiGAm{$fboxFFZ{|T8jc$bOb&0O znd6dS$ln?^`KdOyA^?J3F6AgMYT|*vVnxPGE^kt;R-I^Ee z0eeWT#>YyS+OTF9!|@cJmnHn;Tsm+dgInNxPx#{Ma)QDgV_qQr21Yw7aazq*+&(b8 zVBHM&412>11TK$zYd!44fh=%q&=i{(lyTExZ~xDa*b+u@QdG59C9+ED)7TAn!i_3eV!&tkD|S+`9J#cJ#mddS`D(rO~{PW$d#k4zuKzDrBLD2Lg5l34XBs&>vVz6Mor% z-M{tW9oygkye#dG{RH@=o167Y%MNzrJS#D8U{f7OP^P(2-awj54YLrf&nWE!tX zFRt5t7J|$lW($j zBPVsU5`k1`Vp=nrP7#WXwqa-$%bB=FR#1xg*!oC=F@T%4EPcTC5XSS#mV@Dx2f;=u z%{g|&vOv3!d#g-OqBFq`9jDj#1K)0L>D8mAW7sG--sqAj1c#HJ0ebd5C25)6zTiWchM0&V`6}SGD_> zc7H=Sq}O6hr(SHFxc5{JBw9|8cq%mJLEH@(kQ|V01#PB5u61eRCu&-_Xpc}+8&d;J zzGPp~u|CyPt3<4INY(glLDa}Fo+?%&91R7HWiDdE>9Z!w^K;k(ycb}I$Z0mcWWDi91KT@aNA+~rEH8#fsF4gC+Jm%L z=h%9{AH017*A=G#o?RxAyB*IM@E!h$3d_{8G!bM_eCZs9T@r$^8(?_#LWfRBce5hb z2v4FLCgZ?b);oS_6Si#N#2d)?PIXj=%(5XaY}@yT>@bF+M$s3@|(+B+K`q3o0j@T$+-urG~>2Kxs%5H$E^cYE*2!R|LZcY41!0Ud_~ zu&s2TU`qQ~B*bt4VAPikg=!|vPff`=JGaVZWl@m(iQOge9Snx{21-j186)uQ^gwG4Z{V2Qi&OR5ARoo?%+Ub>O(v=pQS zYzt=m)cE-6OMcgn1Nuscv?U7DDU5#3*fih&ElnNk4|=Fd16AjcHLJa48_1e%esrF% z`c67b9#Lt7r9PMaGg$s+R5^z<$;8_w9d~%1uE(CA%+%7xJ3ryRRb7SO9>k@LFx}a+fP3D3rj&XJmc(qNm#ot4PBpS%y zBOR#q{dcBVNbQ4AT%|F%`F; zVk%^HBd^w^z8g-t8Td<1s>66&JSm4kliKFL2J77Eo!?+yJJac8`b*Br)8G;@nQp0- zYrMo1G`?oEw`fND$RgzBKvXwrEas_WgIsviCK(4yNE$8+hd&|Ahw+fLLobq4Gl(C~t$;=6})(+sfz_T;gj(ZpQ z>o9LIQ!2canTOxfcSL6MJJ3Y0`#V^b3(5u_wp8Gsuf_<8yZVy_h~H7qm@JA6gd8QX zhI7^2ZkKj}9!2O5u9^C8pPs#udDbDCJ5>w{ks|N)B?M-jG4EnI!%C4=fj~ zzcyI&1pZvG!dwsq1au3Ol!=B9bzD0ZR|99CGsIgZWI|zfix>mxBV_ctOzajj{~wa? zH^bKrr2FEILbR_nW&3;BTjo)!m&i0Jg)gGm({YvyzWnZ%(A1DoZ3ig~X5F zyN$&EqpWq)UD=L6!2bWY)tm7<7w5mERXa~~&$VkE23fYW)s0!_IU@h{EcH3_`L89% zp?DDyMaCy@y?L&90B(MTkYnyY(q^y|Kbs)cVfJ!#it9X;d}@A%cGUF^+8`5i%vkpt zD!`xcGE7_|VmEWRnV zy(q4JtW$Azz6Se<9l)&d>k^Rz}W4q|QQkLiUWuZV>6!v`%MXH$LfH`>Pa6V;VkzJe=n5?L-m5EdpoG;w*9YL4|fK; zkFgi@=n+#K`q*;82_Ot~dTRMT&F`MEe^`P^ zv0Eev*@g2kBGp2f`A_0CFBKS|BFetb%UC%ETkFkDnA8-7YZ8wu?H;cKwV2v`SShGe z*N|V`Kr-5alO;nGBW0WPL0k)j=Vd7gZ>bf*J~C*J>?GW9QFB!pYgqM?T3JYiAL4}R zw~z9|Z$Ekb;L+~(fkjyqc&)@Fu?d)4C=9btsLl%GV#=mBY z620DE+CK&AM#D26XOBY$Om5QG&pz{{))z;o6W+a7JtkD>1p!FFwWychb@yVA(Tk@Y zk%FF@WW$0)vOba7H(-?|>>Iz9e{932=K#f?TaTE}G3u59^TJx10}0kMl^uE3gW)Lf zseyq!dq*tl2~b$J#-Ds{x@Q6H*$$W;A%kU@PoP7iD}?)D#5sT=eDo?vlndc2Ey5M$ zz%XB#uHEx!0Mf>A(sweYJTjPGjV^Th*PcmuGbIw?l;asL*f@i%#{?~v2mKVNWsS;P zp;Pk^NuA~cb1>)YgZCgMjU?$Pa>_kdEF1fhJLpvp{d@N&s+Ub(y;B zR+gSX;B-@ z!F0kxXjJw{G}Tk$C4FSi(NJfIyjj%()mw&jX(&AzHJ-&8HFOnq>P~2oKs7O2v#aL; z{GQV{2nhT*dBtd+SxmB65`2U9tOm*_tzg7ORIO=tHJgt9b_L^{hk|f*p}J@!Xbor@ zL0{Q<2@FSSsbczX!&sTAGCujwjW8eD3ZaiCA!*hXq`X5US>B`uLzA zB9daeOw^n&sT<^z82ebCUlM*);Ou}^x5U3Q@ zFv|45644K#ePz!u767-Fzx#PA6Cqa?f$RNc>zhYj%r0Tvq_QiTcRCI~hrGD%ZH|wC zrLc=8Q1gh@85s{4pxS+ic;ms>@UVOxbZjXE9z@IHk2GmlG#$g6Btb9zZ&kamnztR> zXv5M2kPJ$AjfhJA0=q?B2vB&E%^1Xrs1gw`vDG!eWy_d8_GC8JUtg>t=@=z|*nIsB zt{Ztzz&!v{FWejeNsz)f4#>e}Jm!9yxG}?;knQVRPK1zElXPBaFK))};|bCOZKN7R zNJ*Sju-W=pMNI`c6=Cu{?4VOu4r?BYI)a+zB%ER;8EdNT8K&1yA&^grXzWJ5LV7Y} z0WUjvV`T!o5nj);ovtPI4z(5DofCx=Rnm=QPLu&68D!w%bgn%nS;$9~NP#=Je~Btr zD0QW<-PHv>J&TQD+k&M;xqYE4S5awldIH7aMJchz0ot=0> zc#0-n#zrD&RW0Rg1_nc>B~6h!?-B;z>g_wl!B9jw(uML%9>2oLLlwV(^kPjTuiUYe z9!uWAGv=2#9)NK3_Q8|AzYO+waJ$VGekC&jhg78N7cVc2tVHSp&n}*)Sod+70yLi6 z_$bz*%8C-2VG^Wot<61a^0WECrX$jY-5oSgh%slIjz*bpOe%R3CvNBJj_>AiW=GRJ z1X#1~zhFsfi;w^vonXA{6p5R;vm8|>Q;IR;l-fdPgu*iVpujZK!8Bf{&hTBW{Q=0M zR2pR`iE^=}hl6+LCo^oXz8u3i#Bh}cYW3Daac94TdX9*X_8TJ33c=5sjt6#8qCU{+>BJc7BWG`cWoV6K^JmB$7@R&scH+06x?OdOEUp* zUT*K&*U%QhPPeROG(77QVdXuyW?-jKtm*A&MoDnpBE$-?DRd~;Lk6p~A(hpJZYkmm z(R~)SdO}k@Ryu+uO(!7sA`lAJUc~X_^*QyQ$v$@toQ}YD8d*Y&Jxh~jhy+8F-mQ&8 zEN>u4nlVb@R7LvA$G}-Y>(sw*{NPu5F5)6KTQy0OG?EqEjki+li4y|%_SqCeP6Q^cc?2>|OvrKGM# z>snxRY{7;moYsFWnFwH-mCK9J$XxbTsOG3C2jQXU;Ij1_BF7)%D18-e@=Fumc2gMcOM&pBbozT5&$m(qa=pCXKKMo;oM5q`@_@{4Sx)G`3jq zR{3r4j@|@O<-vMz83S^n1(oiZnPK#KG2vaNxv?f8(?MG5`iaoc;7m||1?59P63Keu zLgrcE*J#242}Bv=^>LkzB7us+0{<=dQ4WZuA>t@rjvBRb_h zK8IR0{7%vq)u9nWqh2Rly!82zI6^y{aCohOfI$lf0x_ufpdz#Q15 z@4qcD@^k+SE7oPBlF9L38PNIw1ST^31&|0_IqlWRt1*{HbnN{qSYh9Vx#n^crlCU! zyGa*Xq1H&v0>K2G6tqkwA|mo`vc8V~a>*RCx-IS;gp=7?leaZAID>CV_?aBJ$a?Sa zh}%f`7AD84nV79vuN3|dLcqI)5s*X9Bi`OK3k{uwLSed|Z-24uR0?{S)u!=X_Ig!A z6u9)tgjuhk2NrW@np=!V<}j^M_vH5iLU#7Hs>`h$BHv)IbLAq%&B3us?&tykZI^*m z+^RxhVg(=RtVLdxCYE>U<1tYZBmyiuZnJe0@{S=vB*9wWNiVo`G|8HH-J8J%LY#!1 zLz&YxgZUHq#ec$=j0OD(|BrdlX=;c*LLFhJf<2>Cq~7$8j^%AzSy`Q-10i9U#;4^l z7>D_}yxf2|vFfE7xi!m!JscAlZ0$YVAAIxV{tf|-nWY{Gg{=W81jdruSy6a|MckA)sXwt>7qC3MJ_aPCq|rF&E@ z-lE4P$tm0^F@8bi5fF*DA^APoMHw=Hybx-!yN{2GQAV>=mfyblUIiFCGrw%X`=Zpy zMF|X}BnD!sk%oZUR#DgN`mB zhmpg3g(i(Ir5eYyqp&%nL4~&8{oxN5&}80-zcj5IQr0zLe|vaNFVID2Rx?s7+*te( zn^95$d0T!RbL9vcuXMaP8ezZ;(krFxO&zCss#-A6Hsr^I61vpt@v&p4N<$T;CbT(F8nrQ0#Gzcr1UDgQ=`Qn81x>bymrPx_%1n;tDinyX@$ zW{ugm1R78jdl!wSz+tHdw|QQO*ONylV;TNcAs9>reQ-MAVO8|vV zYU~$uhxuX%BL~}^YsS{i%<Z*8ed#6@W6-`H?H|R&-Y)fVXKtIw`X+%jl)$d z@&?ivW*4C-nUVuV+FyR^+aTtJG7}M&TzbotT~LA9o2e718SJv1vO85FLMmNHB2DVV zc3NadvM(iBa)_80HD$VNSH&@)B_@ni;Ef^Oz$i|yYPK)Ew10a80cW<*r5+x`!MVtX|ZRJS@1;6n!IhCREF4Qf%KcXL}Z({dT!>{<2umyv7aY{m&a4sd9+b&8WvJS(_7k!AF)P)nM zR>3onU|1=2>hSZ!FF^W8ntDeAkH~k}_+=?s4tUK0Vk6iXMbbUEMn!vYWf2nKWo7l!}027f&II+t|V54XmlqYH6B|Vk+l#C7h^O!s2#>(Q3}4VB#z=>j#YvbYQ=EFMtO&~`TDu)d%WG@H<1;7= zMvU(o653~@R&RIlX*Bv}VNJaX7oLvbx*?DX`8Iy>W=$us zXID7BCq9ZlMRxOmZhrd90v{kyU>lW+Z-O7l1wC5=q~!3g!T8u2pnm5Z&DSxLCNtax z8IT+Jp?hswdz^?9llV%@tq7u+!zT{OTqeoTph<&C(zg;2kRCd+S8_;d5mbj6VI|*Q zoL-%b&)>n8!vzw4r|}x=*=sdBUju7sFb^Y0)8GWN5$gExC>|864awEfs9b#c#P}>R z4%n`57c6tEJ_d7E%PpdTV&stirOd!5#8KElvGlZ3W@AWf#CdpU`WlQw*dNC>+2&i! z)88+iYd?M1K>_tZWdn(ax9Hk67yf2YM1Xb7$w9fS-YFehl^sd&Yte%-Y`Mj1U6d3*7KdR{b`{<62R79p}THATZ;RGI|6g;3{FS29_U)QiakI8~O8 zpw(}97+`j3M7F{FllqvW^VQ5o>r{HtO$p9h*(KDZKchAxb~M-4#>Xz2JKpi!_3-j8 zngqN}0e1s-_TZ<~_dH%EEac*)Il>PR5F==j=&0al15+f^XUn-#&buiwvbM%O86%~& zHJ>ma#f-aFi0{i4s-#N^jT+7cC%UQOc?3WCO#ZV$hVyH^`gwrYutWnrI=Y7h zhZm>j)z=m4{>{Dkpef2l1XY=U{eX8v}dB(};D(Yn|w4V=?4{UaR| z*Pu&XWSctjCW{R8+RCO1dxyl?v)er;!-BN$_2#y4;{SMn)AVSmdlT>Cvp{Q;&Rvl& z)LTyIZuJwz1WAevP)UzT>tmR1;g~DWg^>_wxBC5LUa#Jd6np#u(<8ZHX>*s~%KUT; zN<x@p|lXol1Iqv`WE z)+mjZ04_k$%2+$%txXk%nm~F{D37k!2O%i>T8txaMFQ$VQ@rL1bz-VQL9}LP{{R+5 zZ-D|g>E53}f@&8Ki29y0^E7Vfv~RecJ|lCud4+2=vGgPlAa46boi0IR$zv zzA`Os2g}^ar(MNC7Es9Vi-p4g1q%tfAP>m2G*su5E#1&KqQOiFg3b>s5{X_uggjDI z!$VoF4TKh2E{WeXW7;lpJp8*x@p{B`y<*es<>U%B7_OE^Obgr$GZ~^(x3e(tRE47! zg~Po}zQ=PNz!a0lC6%}b409$>?aQIGkFGW<1mc~DHu}6J+U0B=;TDYG+0d2o*2cmz zul8<5cs))6K1I1WoVBL>ZoNa{h;tkeQ|>%hr`&vROaz^$CyX-Uu3_E*6v#x0(PNZM?G}&ij+%T$kcl3@PKjnV(=z zezA}Wn?*_xhSyhC>o;u|VY3E?k=JsFlUUdiL)hKr*; zF6Ax9Yzc%DXW-T%>0GQOpTOKf!E)w4~`M9IcutTUv`gd7wN!zKmp zFn3%ZKu|h>aRyhlc5r$SrM4j|5yZ~mmaBAt6h172a(7!xK~r@yJsM$2I16bF3ir7f z+c`%TXcq$l{YvzP5OPvvrlzM8VTO&vO69xQOM{`A3Z5qG^Wmc>Uu`|wM_{%qwJ@g= z@^#81tb*si;YRm%0n6s5vfBoGI}dmMZ&H?W&AbDyv$e2cF$&NW{3B~aqAwjd1brdCNm%MLZu7wHg=ymb=3knO1BUWI#0`DfIFcJ-b=0qs;g`^5hBcC+;@+d^t z+-v$ODN|dE4U!={`M#s^knFth)C;o4$7ZRe4X5hmv;LPBVNC8qYh)7{Q*3o&aS}WE z;O-XGAEi#A$Urn87%T1^M+evy1baT!r_R>RovFLRYTjUcihcjC#gM*OM&dSiTbY_E zr5Cylm1b=RA1QhP{wA;2*oY>lZQ7dU_NU%&nECMr+}|7GfOD!KIvvkm&2EWmU@p9X zk=#9uw|cw0Lviv7wGqddEDm&X zu|PAjIfzGQrn0N`-d}Lq69V%&s+qmfu}@UBn}nIOjBl{m)*g$FV=qJ*E0v(rX<eikssAzZk;4ap>k!Lptys&!#BtJeG< zSBPo55w`psbt37L!V=^uazKS}6c!Ij*@*b6KgKHTRwRIbZe_jvZh-U4DXwut;!<>{ zDPe+OVNaevmC~&;c$NjCx4|n#Se7m1bxz?=u$A)lB2z;c&2Z3nZ){9FGP)#*s zlt+$0!NkIG_D_6>lsw)I+NOkgEd(&3I4fp@gTmyIfrgX& z*pyO$$8^Eq1h@V0cy|)cl1ApYo6`mQJsJ#yv#`UcPjD+YQds1%VW1UwZvz~Yfb0#v zp}O&>I93xzuhp}UGxyDtG!RSjU?ktjvA;s$#VWjD0y)63SrhO%b+W8^DupN=Qg_kH z?<`+qIe;tQEGTf!T>_yqbV1+{QGjR`T9cLzu$%*7*Pq}Zfx==9(T+jf9?b?9dbG*s zM@+p#QeoEKb(9Nh4k9Xzv+KKPeBe;%(0J&36l}K1mvuJpzI9VZ3&nFdPFVc4peX(+ zJn9!9>Sz3&z{Vdn06#C&3Ipx3WPg46K?zgRgLdJ9r{?Dy{a~)?J_E<9*rmP=z>Gcf zBb%JasE=UI3oQ;@LFDcP&N)3409P3h?9V3JYM`##r@Zuq(Lw6cj3hY{7`qsbHZGYv zI@dZis5aik1{br*20^}J-v}-j9j6mv$-ErUQ>;fX8pZZa*mr3uQyU%64xvpzy)S~iDx0bqzPTHbS(Qr2y9Cz9dl3?s+LC?7ki^cjn}((w`PEb-i) zdl563K`Qnq_=7ic)07V6BbNvDVkH)+TN{t3%baSlP@W~}007Piu2#?{H!)CI%vJaw zoXsdYmbbKyINVrF6-OIs@G7-=-Q-}SLQ7VLxu8jnE*Ff0ZbS+^*flSeQp$Wjo2pS^ z?lXi2$TmZbbGtXLn_}IP-7_;g{S`gh=xT+y#ACQY(=n>;DyoP|kZ?;_m4)S^%)DWJ zd|T19AR*BTG`1zJ1?7_DQfJ|IXF2X&Lyi@l^{hM)DYca$JO{}oN{`1cUL>mJA6Ttw zc+qa|Ig?9^Z6DGoWQCdnI#3K$ht*G<;5JMIInS8;ib4mN&2eB0m+m6Qn57ov6UG&6 zVRuk0<3I1b%^MZaK{lB~ijoe|N2x>$ko{W@r&xz1CgCm?uS&W^c}M zoeTU#Eb*B4b*e}PBNWVDoPr_Sb_et2SbSD9Az_F5F_`U!&>}!vD5&mJ9S@mKJm+^I|WDfr+GFRL3SB zN^YPz`g$;)g2z~H1>p#ePgfe3$)Veml*B!sG2$i-@`mOAb@Ili-(xi9(qSh%Bs74* z>{v1PHeW9Bb}ILo+J~j01;3voZxWNvZ=s9~f*OYbk{ghGIrf4UMP5~dE|Aud{1=D= z?VmA_#{&yvQXMv8(?f)2s+@B+WC$18bjFxz>NlBKO7ri;G4peYrlf^J@FMNN?j1wn z_G9c5*84qeS=1skX0Pe&58?+?4B>Sqjo8YXm?ifX{G;}Q&3FDcH%X%C7Uap!!Qt%I zK5t#m(f0~3AQ&%sTQ+a+W9zLLH$+ggie!XgP0nyp(h&#x@^TjgoHl;aH5*yh-7?#* zO}Eimcr<24iJF(WA#D)YR(&=fQ`Bi`c?WlZAcpDr|1=Z8oL4flU@y=OusvCMwbrWM z9v32#7+_&3IcssdNT32Iq%?JK;dNLOp95#{iB=XolQ?_PAovcKydx>X>ECc|g|K~K zhKsP)h8q0P*-BFa-r`1Ua@{l}0{{*}IZ53KD6Y;8&=B8y+JC}^%_tSy#mf8D%e#*s zg49%jRkKOt!vU||dtf7w|-*gRgPjw6<-Mkx!w3dC}O}+}IfXG(1B% zdL0VYv+d@~5r87Ry2;luHz2Hq$9%Sd6A}0@gkEs#WyXlI#V%CDoX3e}klL{wXbPG_ zDf#AX);LwnWy5q3Xv390n3PEh+hnaIAR4;<=C}hdls-`QB1;IHtn_|NVq&$qZ*|L7 z2-O+;+fSbS>+a6iTl?izIz{Q{;yv~Zj{i`08prs#`euE|t*DLt>$nPj3X6(Rigu9C zqbFPU2fN=qeX@73v$tPyLoQEEj!~1j3=<1DSI`{cQeld9T_Mh2U};tYC(-o%Cm3b0 zz4zpC1&wIP=SrnBNNGtCcQ<9#ltdODi+r$0_%d%g-7y=LRWP|xG(2S{7cU6IMvt8? zjsvod!{$u@Bw--MFULnp+JPO8$|q8eBi+sm8h&_+J+f2V#N(0j@zI#)e2tKi!KmcO zlv4x_wl_$(hY5omRJfS0FOHw%hb1}Umy#ljKS`TxhWsu3fC)Lhq|6>%BGEsq;%t;r zw3h&9N@X%Hg^4l8>E7T@JdFK3apv90oZVb%3Gi5M&>iU56zHR=ILHQ*7u z1KP=PhOKStkDvv{rd24@MP8J(qs>r0G8^}XW<`p`w|h}ZB%TnlYdl%p^DV%!B~4M! zaAb5=1We$B+YPMl6oBm~+U{)P83r6SG$N3gi^EAQ2fz9)g+P%`vOu|^(jTd=6k%t> zH_v%*6U~3x-2;YK2FH^#?CH|bf-pf*bV>b06p2BGFJSf;7FlB@pE4^2M-)ZBjDg}R zK&$JEIcD$Rwgqcwsv!7H0hp|=V3F%|OITc;7Ml#vYZPIU`fW8RW1PtyuKa|(pi@u8 zyt>3SLcB5-0DCT(Z_esQ17-qlU>|LR?PhDQFJ#sS!SAD57eatZJ3#+6QK*F z1t4J<*yae14R}gd*a?O&kHGx!LRBx}GDo-KqirA+>ilZW4i_TzEBylR;S8a5TnWM` zh$N9&AXpstL_q+au-gCU^?$)8{>97T+VB7Phd=&-0`&hO?_C?CI<9>0*Z5O(WH~Kj zB!M%YNeE!eLbjQ~z#xbx2S_8N1~k@f)RHm5oX`IJ{_9dzdv~`aY-i4kC+Cb&?_Ikt zt5&UBt;?;O&NvP2bJbnXW2RWrsF;A(-U#O>j#phkasKmLtB3~h{QGda{ThFi{V_(- zw>T>7lVF*gXVf}#sZiLk0!X%33U6LHJbtwb{{1jMS-tizfBMs(S@M@SmMS3%!jX41 zvaVR#vQ?v`Np3T;t4Vg20bsE9;0}OcYUjSuJ9q{jB?s*MusT zva?LXe8S&SMs$BfnuOPfJIp1$Zshuk6m6w{$$X<+BV-JHe`WCJKL_nB=QHxD2?5~d z1+Ol~^vaoT4zo}`)7pk~k<&6!_&kx+C}WbPGlYdkC`cP;5s+u(Kb?MuW{`EY*pH4} zf`Gkr_(HdYWV1Uy-g>)4i%SGyLQ~1eFYECoO9Fz3(>`)iXiuuNo&vFdCDu39z#cyH z2HPspN4-a*s#7gJMV7ZT8Ou^cSSpgQrDtp+cV#}3c2yFu=B!Gudg}=3%|?&aUSK}w zF3n{?>vec7QmN|*yrBv(|oBQ6x+n5KeZQR z?KEk#$UXcu5>)$)tu4ek3~tsP?A3X{7!<3rHYRDIAlam11bHR=*;zo$Y4%VIx&sM% zZ5ISe^_c{`!&hP#y)63E-ZyZYDy64vXFiH{B}ZHdED;aJR~UGRu`?D0b;JD z4z7b+vZm^mn%ooU?K>}YfRdj{8LlU))n<2IEZ=h3x0pOG6%ni14NNWSq%^Llin-or zqmSS0P7vcL^7sMsRY}MxX}XS&I8Ib7++1|i1$+b;6E6~An#cPhPp;j?GIMY3(Z)!d zg;^vfLq2l_(lwio&#Tqt!t)i!OyqgTx;%xI=uCAfff8|j>UnBAvvFzvG*75x7WhsV zyR}&?ZJ%4;ksm5VEd><`@xU}Q2?@Jsrsc*t0`}iPsgAjCXX~Q?mP(Fclrg#QSfcGf z>GQdA6MGeVDQ3m#)iU|U-s>w3+JTLxdgZs)1IYc#JdWVk=^68D^tH&iTUc;le* z?lKwTl2H!TN@7ZH$iAHP%bGcniR7+Bw;`6)DyavWIwiK;bULSLlA#MVj&17C_xlHT z@kw?$z=Z|hjL^QZVRbWfq9m@_BplkdYMOg^C>mV6CHF20%k^b?b5< zJc)9;!WpIzI~yp|Ak5m{o2|DLlO|dl_hp6JS+Fk(T$E+do}fG6g+;Aq?m8yIEs4~p zQtalSH=b8~<~Mc1*%4c>gF4cUL1Q^Ncl1K{`ZJKWk65&Y9)qXJj+B|%bD<4aG!$hm z?MG@qKiiN_By^%gl|*KN3^Yu*c;0lxsML|o#o^Rr z0n8>*rBdMXNtgW1nDRZv#F*s}H}@X}rk!PDI3{535LAhs-$_GQ1Q0r7`&C`zY-oyV zvG7rLJ#t>AZb`CG(N(OPz7i{E%<~R)Q7Z{bJIWPuQ({_qiO0NlPh?7${!X(zZ!EL# z74>7FR%V(_p=Kiq6v_}*EXK>bH*1)(7P}S_cH-Qmyh&d4w-`{&jO-_G5xa$4A&_qE zlK6|k!luYCPE^ReU3WWW!nT+74mECy7O}SL&SYz!enQ>M^~l_ZK#G^l(q+6fLS763 zJ|>~hd4rDx1$DjRC46OuxNRp?Jcz{hN2oGJ68OjqZX}rNY|^qf)&8&MGZ6a9%^OVT z)^jd>sbhm32geL^n$QUn^dnxY6XM^Fv&L4HbcMK&&yWszI+-^6dfTEz6Dw2~A1FYhGL z#SQd?_Xb`DW1v{c)hmO@&5>rqM<_RI57v>4*f!~=Ld+8K;o&~TKWSN6Vo6kt>lKw9 zU4IRus(*iUxJ!a3_IxglxqxuwuqffsQZuZ41IFu*g$Wzbv$W=0ls!P!||!r4$G9g zmChP|98+g!_>C3q)Cj`(@&BC4SO*IxxQ8$)BC1G$4vO;9%;;a_Y1Iy6T_bue4XVYt z3LHP~xV;zvf7eg}5Th&V1#(4fg$P&c5o0)&$kbJALQZY8wGdeR1QdE{Q%Iwkzr*6d zL|bzLBmM z+G!g!e3LmW$dPZpT5UV$?)Zj7zGVYsld$Zckap#bpxAf@sD*h+q5aEw8-EJ(l>i-_ z_BijR{-K8zWsg?p_Frfv-;g(N-ss@OsNG?wKjf>H^tB6AU(LGU)j6JhVYD(;%er2@ zbM115aY*Mic3r2lxK_A=mzNl4TY_fWZfv=E59dP|@}V$=dIH$XaYO8|w4w^re#eA? zl9I+#Cn=wIqwuDM2DPt7CIg6}f_eKG3iNx-9SM+y##TWY)TZ%0&AAlKF-63jef_xH zXyz-s$J~;#xA-C#se2Ejz0*phqF5osu>%7`(+JZa^MlD%wvT916X$TM9cs60T-n(SIV?8QF-5Sc^ zmU}x}5j2|aZ6jsO9FiXWuF-1?4W#`Ur*0c>I>Evq+H8)+5fUqeTYXG zhY=(Z@~ z3O{l;g&9<5cOEB*qnN$4Is`SsnKB&Lx6EpA#<6DMb@oMY?*uLNKXyxEg^a;}7{XY$ zG52(h%WUTz2cr+{JZMS!+D%SsXe$U>h$!J?Wr`H`VbLL01w#I`A#n{PI$!jjUx>7c z6a}9?n-Um8G;}~X4f3p$BH}G<&r19cJD~8@fX@f0oThf4jS}`R&HWBYT8G zVZKHn8-74xP@%UxiCyaGUJ4CK_;3R0xEzP;HzkjKpv)(ZQ#mU+bHzvt_SyA}j0EL& z0AHQRSow8WTV`E(V@wLiQBOAFaT1yS!XoF&FzQf4xM*$t&#F(@GXTD0YwYY))7N*8 z?>@TIyMzwRFRu*w%YAJ9cJuL9VQC7zSrmW+SX=z{Tls?bpKd}kDIMvI-pMM3l~9lOjiuG(j~rIq3Ilp8M$f01toI7|-b0&Z(M$_7=!&xu87 z5ZUM*k=O75Ph4~&zs4C zF4>wvy5rlP`$|p&gn9+FNs+i$@!OJMKxnsqC*cIK@;Pt7Z)qqxv1hwIny=~VP`c0HuYfk+(N*60= z2rrlzf9>eP>ID^lfi>vRhGW&`ygJTFbK>vFPndbQjT zAj-;f&Omc-D<>+n=0xL`C^~^jR2OQ2{ytxIsf)QQ!JL0-z|L7&BJ1K|3Fx zhwWZWY?&+4&;A8I@vm3&KQnji^56#fbn8g7$q_5MBO@;NfE9I;aVz_KHESV#)6 z3RfLPr6YI@4dQ`q;C^xC86sA2#QkR5;<)UvYHKl|lG2B*U^FQi+me`kL<79=$y&?> z;a&5evb<;}YsrIKXi?T;$V_n<_!*v4`vk>9eSFng=0z6ft;?jfaUOGTtl@8# ztt;Lh=B9X$H)tT#bavhJ_`LWnt8)U%7$+lw{Y{n=ZfPQg(Q2Z1% zwf3b9lC^*O1xW)qZpibsOfR5(#P<|g?`2_W5&Yp88|Xxd=iIwnds-$<)Ysm?F*m2* zY?EW{G_0a&g<^{@_=qze1eWX94&E90YVnpTns65W_i&8zt{XDV%^q%TZ=a%lAgFL& z{0dG77&h?byraZ(Hg_<1;Q!_vMSYkJL<6n$#Dp3SnmAXSHdpita|!?Nua7g1D!b zZ_MekT3!009mi*4lCQrdsS7#R404uot(=~=rP8U{h}t5rdKxQ>vE#L0GR}f$vs7TF zZYuic{Oxd|(ZBx)EWV-Yp&xyunc}q#f;j(RAh}?J4&RJ%mkdA#0ej7~Hr&}v4BoU_}PDh7>CkPBO2yX4& zyk){A;uBR|Zr(CdYA@v8bVOxBI=gvGn&1_?sJMBnbUAoNf2$waRrX*rrVGA`?!N=H z=~mvw@wKutKL9}={5aj!5kjD5?|_kq>S&Ct1tBjlg#A=J{5lVmEWmPPrE=*H2tXi@ zbz96ZoS9dn3E`TGS6O}Xbn^7%*{4>Vv+2Oeme6O5GKOhcvVCk0L5v`Tw?7lt{X0JM z{0#;il2nkLkQp)4XzaL!EU;-QHG#c(vDI}eTL=X=#4*tlwewqC8rkKL$u@aSZC^YY z=62dmwSu*L9=#Vj$YF9ADy?Xk?4pmTi+(14My*dhwhse)d?W&5JHk*Po}(6c2NrKDegfk| zU~2~jgMUBF`X+6o`6vjPrX0#N4u%AZf^Oq?8*~KHaAFcPtPFg?If^4nva#dn@~;Ht z+!+Es^z)TS#_o1~9~-OJu7m{EG6NNvZ(}Zh@0Q%e-P$mh?iZWKud;=ktCAu^fu0Nl zYn<>}W(VnyN?NQu>Gi#F5jGPw+MGmeXMGa`B|F`UMkX@XHU5%ryFk>uI_{~9zJb`r znJ%DTxIq$5P26Yj{uXS4X{WoDZEM+s>E8IX7}@iTT6g8Fl$F85X1=)|&%L3KPKKpG z%be!&a(A9LecnF!>{(Y-nV$D__cyF|)2*8~Z00k;(9n>xVcMT;!qgxeC#AFfh4=Ja zZ~D_DM`{C?_hNF1SlYB%U3W-jrB!V|LW3v0uAg-}j)Q}D8HC4V(`mL7oiFLr zuQTc?E60%{0E2geMQ^@(o--_?3>b9rM_XkM5>)UQMFMxN(h};x{}bnGCFpf*3lmsU z5g<@z`0&LkUe&nBO(2gbjiMA#0ZLs>Nzg$joj`Xes8d=e#(L4HGkwlIk1-k?yoW*u zog+)WVsTRpPb!001&~Uv3(?J8=8M8|FJ+O1=%Ych*`1UIZ7=N8;*r(K)|M_k*;@X` z^62XFpPzkt+4veS?ZlL~Ys>#}%cv~H|(cAshwRc(x}q{U9=$g}Z2-bR13aOCEV#F0P|`(zf1q!9LGSY|SNa{ySf z%6EcZepn7O8LCt-(gIdf9CSIw38qoa7Esf0%Fhh*w6Ps2kf$xVTf+txx=vLq%=C*d z71lw8cfWW$nEcNv`r_aP5%0veyLRrh&Gs{lG;xTgiQYNXZYDu8QsTsIA?Jg025D~Ki5%dEvk!q~Jjp)%#p8B>Yt0i2{xslx2CV;B0haCu`MxA`f4ZSQ)BkWjQaB0QAsl&tiAzG^v7>8MvS-fDn#UR262=l3OI`}XDn`pK-amJ0ZpJ|qGjWQL;SZ1)=wR> zNPN@hF_3_jV_%y0!QjhS5cyK}<^aJ59o0dj&Q&`9s*rK0w4h3C+_|u*AB6*Bl62!E zPOltH#_eL7nf1?BWo3r)N$qc1JT_<|q+_73C{aK7wXict&jDUw&xN3eUw@eAehnN; zCk9C48Vwwgm)0mAgpUG5iR73S3h=5UrJ^%)0@f+C2~5(5C>9+ThScfmht0G>YN334 zNOXC}v)>3wx{I5KCAJ}@prLT(3Z#yUMJXEGBmkL2%(Rs1X_rWR0|_3sC4PC?=3*0(Nqa$}M9R92MB#(!2)bG^V`8mgx5(l1XElPFs%ItkD)pnyuJHH{Jr9cJ;Jrt+0!Pbpak}bVli20l!d|&wGt8*D9^;cR zZR(P^he82LooHWtl4&>7sH3Y!8JaF^JmKHIyQC3aMFHupJqToyUqi-%7R3+Izi8KbQGCX99)u{vql?vtmx4erhu^3gyIkpqnv+q$7F>$9&Azv(cDCf>$5xenA5G1AEXRLwvpUo`GnYKbWziRTY!-Fy1tbnl1A za5VE(`&H9fMyK1q0eqJuoIm;oI)p1-#_Z!Kngfwvf-HG2g4%t8Lysy&7`JdS#913c zwnYDVkdE2cy@}PFu{rrkMGU?{wOEQ5O!*UXdh2r2M2bAzM#rIyLTPhw6h(CZMz8Li zDmrOUJ@*p> z=E<@2yFFZ6Ae6uV_)nkx@#XCB&siG01ZOhFcM@^j>19ZVF+BD-CIz5MN5q2##=~RDQDRQ- z@KE$h>5?aVHG!YicB0i{`6RKzmFZ%FldTU)Xlzp`Vnq4e+<*nR@_|Wq^%MA-CZAvS zj9(r5Tp1?5351R_W!*4I@6YxMf@M*m=A1-1B$0su=N2?ESP6DJW;wsC3(sf_zC zS=W*_P1GArwL?T~@`!Z$G?Ig<^GK;J=5^R@)agy+%hS!yaIKtS< zEer8HFwU7j_?t6?h=~mF4|oxP1$^ubF^L@4f(GNAq{&6sb(&UMJW&@$$Xu960U?KS zDqz=UrTe6{Lir^5-)tbTq-)0H37LQ`@9r}NAEgCIb4E!9|Ki?=V|u|+9bbg_#A;%5 zk_5dop6tFN3lNBJS>Yk%Oh=+kW_@UpEdvT>uK&r9gEf3sm_rXdc(9yU&QU?b$YC8N zR*+ucMre|v4u+3S{crYs@O1deo9+0N8#JyzNop3>So5^Nz`Rlsd3q$hm%t3^G>MtR|NqygoTHT+ zK%z+5Z4#67+#yYqD<-g|>?>phG9w%n1)_n1@Ue74%#L?SImaIkT`pi0=G}gH0SaUp zrgCCX8{s+=>QWak%R=Ah5SW}wdprzlXHedjtrU`k2_qG$K&>;dE)89Yj8>--|Mcv^ ze=nJ|3_pov30DRPYnNwrD-l}$?fJca&uW)~b+(J&ZBzKXdRm0E>T&h1EZSRHawGDy zWX`=!n}0*1kKTDeXGj%Fx0&(=>LgDTr0GH;63xVO{uuYHd4C=#pc)#dfA8G;`u=F+ zzaDMe+q^@9R@6{ z(4Aa03NlEh=~{6UxoPRkjiYqN6{YA%6|a4zfidxMS3xh0Q(kgbQVb{3wiQ||(ojQv z4cAQUQ*tb$TDqv0U(pRbjsE!2MLGP|Nu!MZN)0Fw7#K6!3fbZZ!yBd@N$d)>Z?Isz_IieD z#~qf%7z|*xu;GI-iL+J)eyhYezO#NSSHZkW z*z#y}`_99W>aw%AkD}be=un|F%@?H-h})8~4n!z)?8c_jE164#j=sc2SvxG;t^}>> zg7>)xB`KbJd9w9#ylmmzm!FsTf|ZZ@Gk);x+QX5k1k*+V-F`#bXP>M}g$V>M7)bn_n-T=`WK zUY*tLFIt7r)=$NHMn+f$R-n|G7tCBp@VTObNIj3;CI`<;2dA%3Jk+OfXS2N|Ot5jXMp;uoN*i-gFES~81>jv0 z_3GSV-}xH5mK>Q7=V6|+o8I0fQp(aT&S`Xe3>=QJsq7w@XY<+3)|AW-2J{tv&gpzK zd+<94+k2-we<1~uZ=>F#*< zALd?lZsWU$1WnHC^R}gWec)xj$2+mEv!MDA^T{rOFc$*B1Gl-J3xI&wSNK$t4*%Td z52+~!<{TFYpEK{=5Mn%Ke!g)3KnLzy);bp~TVUhsx_8cA<8N}#8cDFRytPWuIv%`LhQ)pA zFmIode{a9-2_j+%Mtk$fi6VADJ@z1a%3Mu$b@vb~r#Y?kWd(Vb4N2znUneT7btjS) zW1X(c^em~hk((u(7R$F}kCR!*f+AH@Xo?ot0huKO#2gBJ8Gdw$Y}3T~8E$DTgrwNT zdiKnW8p2+8?-ZwCfxGgy@j`1NZ=%!sw@)6+xW*3Hoz;&DSe16xk9t#J%=%CG$_HHn z)}Y%>ch;P1$$s6vC8;?nszrBmMx-);(I`xr%p5QdE}*qCaPdcS+Ys`m#wq~F4B!oR zO^1!reUp^7gmZ-(>dD0TMWFB!!jN0@dMMLFl^GZWm*rwWz$7#H8IX|uw_f_rW-Ph{ zwq0){&)TY@-e)%LBQhKH)H9o4(96RlyDPVQd-G66!H7i|A_dZR#M}d0f%nT)ja{@dwAl*I6dwn!2Tg>vmg~=gU#-a2-pSH*51pk+h+E?i{^N5J1>r-hl$dehA&he5#e%VC2s*Sn6lL$8<{w;4wYE|vT*tApL-%^Cw? z-}n)w3UnV2$n<-J+Y~$ccK<=c&tb6D-{c5!hp>Bp?ccRXDJ?bODFob%kqHo{P;TTej^%d>vV6Fpd8RX(6y*; zmJCVCWl?(7E=Ir0BJ77xz8==64`~vVVQOC9oy|4;C1%bi3Nv(PVh=lWu_tvl{<8y2 zmzbuf5q)*gCzXmqUoL>^#B(#TnRMION;!;d){=C zgRQTT5ljXMspT?eEpYhv$Ezz&q*v|2V8NiHE0=$z;>y9vYgpB?jJw@{Bz9IM3nsT+P{4MZ=d~1*D9qu%Uv`$+(TQHFi;*ym z11)7o4P+z~Eb(S?8x!j|;GOaPB6mi8Z4;QW(?^H2H^+G4|U7%C_!24Zbkj=Ko3<_A! z`qa+e;!E%)o71%nswFvbGmbS*FehPk`;|~!UY70~*G@03&Y20o(?=W5q=~Z(k>xlm z;>>F|;jlHq`MMgPxMvT#b;-0}fkctO`bFYZ&6)V^qel-mE#;uzMaXK2(u3)VH|i?bB@S~Rxx3d=DPXB(K*t?3Dz(5qZ)7;`Lfk9qN# z_=@HK=(Ncc_BRzxQN@&#LxMPnkHl%|0H;VPYJ`WOFEn9xDqAxU!CV=9&6||6Fe@R5 z$>W`jp%h$_N{xJB&e6*k7u)u8GH{mT| zr-yHF>985omI^VwHZpBePe`Rd`+SK5+uK6)_qQSQMxAAa{sKU|;s(025k;l7{x z%C`BOul{4|E8qKbKD#&dnIptGpZ(E4lQmYC@+2qIgW=Ti`)qc*{u%t2+0A+f@!ITG z-P8E_>_)lO6=DB%cEjG8`?uMxdIt|NT*tc)j{fQU+MBhSRH3CRZcjmOot$i-9x%xn4h zchh+yJRo^Z!yid|syyBH1~ws@Z$^$1*%+M|zk#XAmf6Xe>8_}KH8)2>AdU`PAV}lH zOcs`HF}{!YUS7X0c>t{>iWn01WW9!P&A2zJqEEN&>?f%yB7ZC0)u;wBCO09!k7<5lU$K`JAL8N_7Is)?Y@d3I`hn8k;6qKeVLm^Dps+jJYH1V`WP z{-PYZv(}^p)c}YKYz|C49Rb7u9Ze)UlW`l7kY2Fn$VTF}TO%b!B;GmnGVzz6*Us)x zgFGy+TYH?c$n{|7Ekmqd!_G*ZpefGi%MO*xJhVV|eWN7ey4H6yF_s%3p^pnGz-;5! zFr=C(J?a!_)=2DidMTWLJWyeS1Cq*f`K(KrEs6D*G>^$jnMed?J9&|~3{@#5F4WX? zhd9|I%;?vzH^&YqoVIU?P4|4P(RYkBTK5Ca^SsMvKl$IVbNYr?#e% z<9t3{m%Fx6yHsGzNs5V?Hx)~>+tFrCrULElMWxEx2UaNm;eWX1#*RPZqbNXdU)`J2ZK{QA~#FiSniR zCu?s@0?QoW3M$$0@z&eR!6ZAEBt);->WC|l-Nf|gcChk3Qtk$HdiwN+GtF{WKxNjuu!6y{OpxvoV-_Rc0Gs_n8wc* z%L1hfvdKWFkDJSluz0bNx#oLO%9AWE*-Pd z+74o4IRuXQRfcmJP)?dS_u)xX(eSyD-(SldB&H}YRJoFfQ-nMZI&>SZs5C+Cf7fFg zw)Rxq;%&%_;J$dH+p)rQuRG;#Pj0laXFfNk;l?Bpak{H>{nbZ?fWpB&yhnDLsm}yW zI>ZNsPQE4S4R{%$&dNL;LM=|-?@)w$tYCD6kPs__{)?t?!Ad?7ZnP;=@^6G1u?6-7+~kg$;+ zSa?zva?^t77Q0j9VVGK9?Qu7?$2mWWjN5#>KR$lNA{+^t<5x!Ex|~8kaDAbyH`4`N zoSpjc0`p_I?$rE9H8DqvyE{KY3jFNG!bfrt-67Y^E@te}uBy143kd7@QeEg1eL{AW zgcN@=lFZ{SJq>fYCNNEdm@2N#ZhNE7BOlQ6;V{20P@!5n0xiQ0DMAR)W2|3kv4h99 z*a5|)#Tix36=P*OMJa4%Yp)*A4SXNuF(h?T5jeg{Q(&u=pr^^qS)V0_cAYp9V2bDw zdQJ`3-=!8$9eJkEQB*u#31Shu(&4;_4EZN`Z&Fi@+b>%MMvCJEV9VpqH|~kCR9+S= z=DK)&?=Z?hq9I2aU*K7sb)jDH4(|c7%k5WzKq65+nh5K0G1CUrwO^!wR-P3OrUkOT z{#>b9)=u}n6{Ba?@`77u>tP$3m4PQ`mNMm#l=@lY9t}>nS#f+5UcCktL^dpUTG?gf zlkElyE;3mTrcSQi&uCKJE>@;GhzlWS^7ZZ2XUn%L3h(aJna0vAAFO35$g}JlU-v#7 zdw9Sm<;=J}jG;>JQ#3(d1)fVKcIOQGaaqAMJsi~*YRm$w{$eEL%>L%nPiMbq(Wkqb z`J?zWOs=ozA>d%|%qhT#ZtpNP+w56+{esRSHq0}tLA3rsQ%$`UZfO0Awtyhg4|gx) zT%CgjR|5__(uMv?*21Vz64`lOd!@1yH#I@PJk73@>v=2Nv+W02r*+FD>CnYjx_W&) zmGp(AfPmzV!Y?RhSG5i-Xx0V63dcJ{pBy7B#D}5pxK3Ip9cl?|rE9jp?8^XDs8Z<9 zZK{JHyyIxLb-ITiF{!;t0)jWO>?SWvBq(XIY#mLCT$@Viez0?DHJ)7g>QAPcDq4uU zcQR$W4u@qifZy*z*^*4i)n*ek*~f*Kj}0Op4;B?ZPbcJMIwptO7CDLzc5eR9DYdv! z?LQvmJ*B;m$M!0(WNGysR@66R6-B|T(&%r_$XbS?Ps1A#+k7jYbNZCYDZY)D62B=t zSgtVZ=Vf{q?#GvtW+KEyYz7Z4K3%yXaKh;VM-u&$y+}$+geM0BJI~0PQ8fQe z4KZ>QH+jF9VDiW;jaOc+3>I*-Cut>8<$_eB1=TwDGz1Hm9k4yiPC4#*xC&FY*bF-% z?v-0ffqD*<>hx*io&&Sm!Wsn~q|%18smJ{G0}y6f)b_9;;b;Cw8^?EjF!<6^`<0n5 zcC2zUO-|kd+Jn{HF4twAbR%D&+jOsPzI7}4U}mpw%Dq6RaRo!nujR-fwaa8%h`9M$ z86EWNc-QP0gQY)Rm0tu#-D6UZP9~T8``nvu({q+gQpdz(;_;hL(ppzgCB9+|H)YN3 z)Q+BYsQ>isQnDs(Sqv81r#mZ4S{*nlc28_zAHDeQ;gq WNq}rB^TyzOQKwbBClh z8hT*4M^Frf+)6p-hrR%}fVK+Y;E^&)%9+p|LBL^?ap2AQ=@oiCCcB2EUEp~K0aZ^j zG~Ba|kpWuN6P-{9Kw_t;5X7h`Ln(8?_pOlV?moJ^0um$-d(=XJ(zS47#kv`gJ=oUl z7bhX&X&Ky%qPIoVNTWW66j4MrlUkHEe^(jj%Hxz%a>lG7|E#KL`7E@mlu`3z$Efb7 zB>OTMA|+)CD%#cM0I zsVvmidLwbRisSuvh_6jIE;E)V1r<7t8k9i|aPu+NFht(uGjTysGKDOxr=&)#^3I`R zvOp2DC~$9q*AN1aBTeA6g=B(Bx?1^U@_dEB<^P@>9*}P;l0)R2EvKY$8n9Kfcg!ir zaLOe+c*k0tQ+G9XJ3}#mE(ATGmt>dM-`Qz-ulgLNa|X=qD-TgywkRd_0%{4W=MgH9 zDOuYV*3={keCaZxfs*_UW7wfHAMATT;rf7zLNR|Yl;_WvF27&F70mW<=79>MXy!5R z-w~m$wv0r_lP&ODf-Y9#+y#1zSj@1*hJ9DSb9)t)cSM}ucVO84*5+*bh#*Q5T%>Oj zLO|eZ8MvntF9GMfZJ=Mo*ZF0Zc(Id0O70`3W*rzL(2ua{Mu+y?zf1_Hk;xngaM#Zb z7h*6K9H8+PATe*|NAjLiZ*D3J<}_>!&YdlZAIh?))5&G2(jONFY-wdq_Lt z73@BJ`IcQ=*LTgTn3t6-_r7&-UdpRyWpG;|E0qUH_5n2ztI#KG0q`kY-Jrs>GV2Aj z-NPecOG$~^3B|rUjY?l++xTI_49)LV*)?asd8fYF*18xLsyL4(RDyG9NxaAWA&&(` z7urVw53X_jckRR=p3l`?dd{L(J+ShIuo|$~zw~p#EDC^yp|v;QTYq@h?UOiH$xLEN zK{y2VM4S>XR90YYHmC0hk+Uw8wmc97%Y^-p{#h200~W5?=W>KPb^by=r-XJwV#&1W zLR^6U8jCspLAZw+ssM&^s2W1AKYe2a2zpPZRiFt8A1P&e15(AB2Le$n78h7;QVDV6 zY6jDdk{S*c$hUN$6P)=~+XBRNIb_e7#5^(dUe&)G-%%>&_HB6mLYvX8pQG#7y*k?bQO}uc86i#~QELaUT(`(_Yn)80vvw1? zphGJA-xe;G+fgAPc4e7vJiS>WA6?h+RFzEw!MW5_)+(h!*|>k#z*jIk2|j>(GHmpo zb~8DJ-JXXL%`)So{xEii`Tp(JK6xUPyvMgH=~P)}>>zV6GZEY)%6M{QoI`soN|2-} zQe75W4x4-`2jnd;4@>jJbT019aOD zmzS4i)adR=f~vELohIJGaQ=5Cm0@k(Ot2a6<{%64m6o1q3S3BX-|jD%`tiqu`wt$G zt!J~DWu33gF{Q6q;fzD9CP7h3>l`phdywxLL`9-hi-XRBOnfQ+kFFTPlPrx6LDcfV zD~H#6fTFkL#m9G^Q7Fz7hiq9x|7)mpUygQhQoTf%MFjNWg0s!I{&GnszN!+9%mcDa zzQ9Q?92X;e-esZk)HMupHJBkL;nDi4^^8ja|Vcbb{L@vrnt&yDUn0ynD5GzP~oD1v#p(ZpohBqd8|dW+NR03fL&>%>ks2(=@{ zE7xf{Zebb%@J@d!fyXau;x^9+P)doZfJ5e|KP})T_9hy7SX`v9HdvkWp+VKPo?N0b zJR%TIjRz%iK$#?2bmN9jL<>osF`vXJ+otzMKD4yFMEE9y@G&PVIEz~hZjcYmizdgP zGSaz6hf#>M#2LWx&%$f2-%ZjMrs?Sb%Bh*{*FJB9ZI6QTIlj%<5%#WK-a~_Ab5E9& zsNq;8q1CLFXLDcieEZ-8Bau|- zKKKX4Hj+jUL-laIm^+1n>Qg8r)rhD!EbmZ83OJDPs^0Vz*DP!jFL!@(s}-4zo;@eQs;1hDH0Y4g$T`;Q+r7m(y`h>OP>2tf8TSb~Zr?|=kc z-aJoODXt`%hu6Q~Rgyss4Nh?c0uq{#A*Q3XoKx@&_yrLmd6||=sh4Vb8^#=UVe0N| zAK++c>yUGd!$=B1P%cXwS6*;MgS#MQkr6fva;CVuya~nd$xgax84IR-D^F>rb8?eg+3vZe+0@i8a48n@4 z8xL>eG_Q+9*$VCEm{g9IrhhTh-73^xM=S8fqelM;`!7_+lfNLchL}%FY#C)Uoi)X= z^qeKjw>;ZxZPTNAxz}+clDDq13vvdvSBgh!B4_L7#I1ArWY)&l){jaUPILOSP^SgH zmuzE9L|ME29!&N$;%`)+qV`r11H3pMJJep%iY$RYk*Nga7{+6wQMfuAM&(tlQ_}(bwxE;K-2OK5UT)>5T2Tj5Z_+_`izLA3({=?w&E_Ea70bCxO z?Cv)SjJ_T39SP^9F*vdylo9VnRJ({0;g#5!QmRui6 z1+9N>I25&EOT*U!A85D?e*O4M@vE+}9~Q5NZe1olNNB$MN3b(F*_a zc6)WObamyk&pw}ElK)>j)?mBud{1@vtm^lVUu_)_tLg|>&J2VYGXu1m7@}}aWcobB+ET~6H zzTY}lc4&x6JyG$jd@_q})Ycqqj+})ENWdvVs;@w?43eX!2n#gh6u)N0;Ej*>B^ifj zog$8v3iq_3JN1l9!t%WL=HRa^anA>nAE;TLzeTld$Y{pwGj2{H0Y65pqvZr7eI07B zG7tOpseFx3l`qJ@)zur9e!+scA&Y>!W$#GRpln00$*DkT8>BsuTrjZLZocsz4a<$u z;y122EXS0vN_c%Ojq8|T95M+-<*^UQ-4A6$*U7m_bACV6B+|X4w@$wTw*C^N4Q=>e zVy5-fUHHJ1Mdy*3eMCyLa}SB_;H<;p4m5d~dPieJ-ZkQ~Vmy{3(2=;JzO^{}nCK=} zKAo0M<@MH{UG(=4gQ16sumL0aHVm%Sfpo^o!OC^ZQ8mupZ+^r)rI<-!7Q{LsBk3{O zRZVu4gAsWXLr5i2txD3mGm=f&!${p}N$3sdwf@L?h3K1CfrgirCE8ZN66FNueluJH zDoGp;*wBe^3i)Tsg+FuXd`And9;CVm8)$W&iqsf9NuD6bu<_Qx&lw9u@j&I2v!z>_BevTq}}#Wc=GNb;R9If?Z+Uqw2Ess}uw{+fqvLod-g zr~HH5QFwUxdx$%8+Kb2c4A-)VUBO) zVqkyXs=-W`dVN>}>!(~(cUr{A)_<(IlMyuDUutixo5ZY3R=9+XXcsG15tn3|9uuB= zizd^OqHm!I)7;UBK_hrHbfHp(2gW#O3GJpmDzmW61&G9LU?|uS7Boa*Q68f{Uw*iK zD3QHgqWYR|2oU}2gQVIK&)9#5~s#)Q-2u`>PtKE(c@j_A{%^ z|61C@f#nR_5@w8W2Ic8Y%?-_zTP&VyBl0AyZElW67&d$k&=mHC3OTlA^DIf#fgl_SNtZi zuVSZcMrxQlFYPc64=@CAze!{Z(I+Uu=ulSdP{Q8)-iug)Q$wW^UDE>k*LmW_=JVngeA8$xmE&)M3*|M{jFU)bW ziE(g|G-i1|ExL0+g1&l;od3FBG+0bX5B@ViZc_+zer%|g1Pu3&+&Z2i#&NnThg9Wc zv^pteE@H~F85PF;(nOS{xLshd0uBu5 zgC}oS51uJQpx?DElJk!`L9l0lS8{;j>%32nS)>NEAZ{t{P)WNU@-r9H-%R)`hjnOUgBla$@ zw`TM-6_`C(B#Y1Zr@L%Br)1`sC48H|(UP(3^O2UJ z@bA&#F}ga2dT50*%K9u>s5yKXbx86kYboa>7-M25tE?28f)qFs|=b(~} z^+YCWFKeV}iM9Y@`QIr4CF=I}mKq?O%KO^g>{R_jyNH6jesa9Gd|OD5R=!91Gt(?| zCxrnnZY*r6{J_%Z%IqHHDfqlI;i2b+O|MztV7wJ!u#a0)MU>l)c>DK5JErzs&PKS)&} zy*Y<>4roZ^#=mdgzjqz~eK|ar{++IXI1<)cY*ze(bcCj@)0SrItx0d&t2AeCRXU@; z?|sJ6?&aXGHmsPIa||Oz^ZCPCiRjEERFOi;9eJpdMouhDTP8mEMx4Vj3~mJ{ViD)E zjDHS3lmH8xhFMTrh3r=hD$l=ZB%E>(jOBlJWnfv?6Geh{7Ev;$r;?%wm?h#SANO$` zIzVWT(j`NZ+NFuE_^q=)oq6ZHeyD_v$_j{0!?0a+&`iV@B{T=Utfi-B`4GO+lV_Q* zcN7OWA>k~leH)7or7^xLM+h=+RSMfUn#)B-bBYgt(8Z0)%K#TNJf*W7Nrsa?A1UY= z(w@X{IUl2g^<8gc;)^65F~@c;*{depp$kd(hYJ?&YCREQzK|)%X>D>!PNX110b6Jx z1y(2xY4j0B#-uo_kuoSi=f+{*j?gE>QRQTuYGSU(#-8z+CYzQomX%8>-?I)6;%z`( zrrD049T{}G;OTc7O$?0ur>FGXwendC2-!Nu4f=SC#FgZ(9v@3KLjZ^pMyhbN^#g%g zR;cLC>isI9bu|m>^+^PA7X_ROxs00->WzrS0g;6D{ABC+`QQa%(~M+tg$g|07EbM& zB(n7*hDF5=8do(){;n5|H_T7Uc7+*naeH3@f(wi>_~{>npX*d8gCfBs2ar>JIC~3#s%MYfGw>`8TnxwSf5Zsv2>*qNNf!+M72i1`dp|&$ zrx#XfJVX_txKBR(WY=JZjj8Q99QZsttSYRLZXu%>SWv3(GfGui?Kt27SlbfDAaqRG z?6^!ILWr9TE>?Ep8BKQL)+A)|GJ=1EW1lj$@j)|2oNRTc(flH0uoSk?%aZ!bXC5{R z1Q>B5Yk90E`hdp%{J=4i8(q@^a@I}X=DxEV`8mSuEr^c-_c%OKC_AzAqnzcF+BAYidkEYc8>0pe!Py$Qj|b($2$ zfCe3jM*4!XX{QI_C~C)LnOw^fo4lE-s#QB|P$;*umJjdE!ZpZM~2l1dQC?bA=w!Az((79ip z?7rG2&Tc213&MfKWP5jnojH?1T7&BrnO3S5aAIdeqjCxw7?jF32BiFP`Cintl~Q}J zJHWQKJ)H!6+`<8%EsrGu73W4`p|qQF&pRG_QWHCvrxZa%J!X&Pg;Dh7MtSMn3(+pH z#e4((YA81evqd;mK#ipV>QYOIN}mdf`N_wOc6S zT-$;u@={`3r>2Q7HB^wJ|A!3p{e$j$?Q81z>>eK;nEEf(OuLW$>w#&M^7O^21P2A> zJ-8A;v)-Z%8_txb>wvA?|-*Z`QVu<cHCaOe>B)G%cVc`$8Au{*|a2z3Ul9;CT9bbe-sMP(hV zb&_3V${Hr~LH&w9^r>dU8jQ63O7=5NeVYN|Z2l_V(^2XJxjnVteTdmH7ovF5@PEgY zl|u4~+-0)%43^}Ga|K__E1b0BD{R8yn`Jp4xx34kF}+{P)-0|fTg?@Yi;JA&qeK%HP{fvfZ@zm zhB&^9J6JOdm+-m>N}e;CsiMwI7-Nw{;3MQ`*njOfo*`3*Ah77y0437>o4fbFTD!YR zN}%IcKMtQ+Ksue-M44H)qT2m?U*Gx0%cWO+2ti1N`Lf5eKkBo|-pAFdU2D7%EH|u0 z+dSv_TWkcuMYAwqj*l$9bu^y5re+LFl1Sc6FXX8}@-|c$Pe%oFjO_Mk*zH7iDf`4s z-9Wl-KEUqUI_j(N$YKWdSqgNPY#@a<^b%)EqxA~loA26*zbBPLY^DBe_E0~gBmJpq z+P?)o-=n>-p+Qs}GyL!~vvwXVvU8|)X8WQKFmElX-$XQxc@_pYl>8Q2oQ||}nvme( zHO|K>ciiZ(dJKEqso2GJb*r=9b|nnj#WhB5Vi*uDYA0v1*iFj%*H>4)rsK-t@vBvDyy`wQ)>T>} zis+}n33DZCrsDSj*c#l;Hrui{x+a0Z@rgK3)$1>;!Oy%WNbOymz#UFjd9#@quDuC<|e*&%lSFW<5;BFAtgKTxM|YTyyLm#y^~)fmI4~*X%veAXms- z4NbKSx&%P#zCrc6;<|5ChTHDFZL6?o+(rO5rO%8aI0Zm2V+`-%52!$Rk)rj@^A%KL zFtbGF2kTzN*p69%#>30Z9@5%91|%aQv1D?kVsy!#9w=3c-PL67M>e~ix!WdL{B9Fj zmS=C#0|IKOuboWlPxz!toUJaEuHYGm8Tz4dpTW@QJN%0&rb7h1pTW{!--eGN;(9BrTWe?-P_mhx|f%s891ffwA(wFb^<#3x-gac z6{;wc({-9E3<+luLhR~3?R3T|9L5AIGiI3eSts57P-f^Pm!c`wD52Y#w#oQzMOB!JCf!G%vdIh{5Q?7W>%w9_UaZMDN&3^Y>Lk`&^cD=qnb7_(<{IK5o6Zv3L6&bB z;+Zi+TA;@AaXCwQh1l!FOcIu*g0}96;iyIQ!7G&0lWo#hE&TlV<>hyaKfJ&B#p2I$ zm`j3L?Gu->v_Q9i$v#)To@Ezlge+ty4vla zRbX9J1-tydL;nzUI+mYQ?Vj~E$BJJ%ETl$8&fI=OD#a^d!&3;DR{9=+bj zD61i>F9QoA-ifWKT;lRT9 zO+I{q2PeW&O!ShZ7Zdm>)A&l&f^uc#`OT>1)Xz`wr+BA+B5hJv9|ta+K2N3TR?Z&eQsj`YhFW6A5yy)g zTU?$=sbuFbjH6R@j5;ig{hs?OV_qA~vE+7SQDrSH2C<06vH7*ED;aA4yhqdeX;D@` z2>ks`vxy?LBy;c+!d4r5PzaZNbZRRd2u;*#+hG!m!Iy72&G3f5j6fMPm`|ZPM6?{) zSyW+WN0ml(J8I7GY$Db4)^3-t^kQVH>0&0Gx^zK8W$jo<)%GhvYbn*GurL^pF>GyT z9^@=G)i_FJD<5*^Or0_~=zIO2ZTym-jdo||@+KV0N-Wi3lKM^+ zBKR^cQqSu{2ZbYnI*Uc+_Qr#U8|!P2Hg01XeEjv-JoQvq=9ormhjeOHib>S4gAu-h zFoSm-G{}xPyt~nHNsxQkZ3(LHj8WqJ=4!A;*}$E{ZB;B)0K*C!yP*rDhokS;9^Sii z?;AVFc4Sx0P11Z7w{W+eGcQD4#36*EV2V@GKK3ffz{UDx1?xpLhg%+N=}SMUq8OLt~{!vk;3(6fGC8TwzHCMGUjTF ze*e*pFHlK8`l#KW9G*kvXN#)JrBbqXAimMGJJ-B_`KW!Q$N~vB67xRtL6r(8dosUS zl?(Tw%j0*#y+8cHj_EfXV6Lo>WDWGY1GDAvtGNw|>DtM%uWFiE{j^6W$Dy23Ld1px%;!9-qa z<^$|-;gAI5E`Y1*neW{h$sKevpACVlDB!Xx;g=Sz?I zsN{;5n2EX8q>y3uQ9hH*qwbTozEbEFIZ7=;Nu5U8?sj&Zv^Lm}U(nXJ{%pxb;(mEo z1{5)q1#di5B3_jV!f|QvW<10lS6k)MNaC4qMecv8!7{tjXzpWV#ervZp>J#@AQ`~F zejUN_@VH5;=LzQ_VoETfK<`qs8f4Go*jV6luz(nHm|!+9m()CDG`5oSXX0gghJ6<( zKH)fRj;}Gv_V49eXXoH=M$SKHRhh_xBWahNPI)s13{Ep|=`+#C*ByqrVizDnO2tay zy2n2#fS`+Tj$@Jcv{Di{&r4l_Y#;8O?&G$;Ob$SBN-3w_9B&(HWbpLl*{4tbuKzwg`P96Sj6$>q+TrTb-=WQ$kH1>K|J`?M z_ik_U!NIdXJU#f-VpFDj#>Z*p(=RSBeQ})+e}4Lp%d7hq4hJxxYi9SAjT0&5o6-HR zzuw$)WO6wklP^Go zN{^Y+bWe4j8u8jQ4maVVX1r}0Yq}y6hBG#Vf;a$ua_koyb52$ z>_wQ?^F-wvpSc11Yqg@dS|?>#^TF~-5#4yP8uAz zWk$AO-DX0a{bY2FO&{GEWM`u{yE|58=P5GM(@jYJ9svk`tYnyBok8U7V3`W$Kxjss zyG?&z8vNmM-K$l>BMCg^bP|Wb8VOuH=uIm)Y!aV1D6-J6B=j6@l_FN4K6saX(nw{R zvco#qlh452{y@tWo0~zz;x98)B%r-S)I+n2Mi<(XLfd!1YZ_n<&p;l*txuB90N{Lz z@+$!A7?JbUgntRXv5W>-1)p`tyO#KmQO6%WrJrUBoiX>X1=8dD@r

(^ieo$T)07dZ8w_s(kz`OS-tP|rIN^xgBdKy~0NEu_72Jv7#&0|KR(v}93a zGT^`mv&l5EvXqZBZtYA*@5d*&@x|%83A!iwu3Z!weByD@<aH~w5C*c7Bq>O`IhZt5=dvz`qaHaR^0HKopl7))@|g+syXQ z;qr~YUd0u;nJXvYpoxdPmcRIWdn;Zw^=xj?-4>&!w8ax+-U)Lz@;+ar122Q!VwK=C{xv zL8G@q1-X2ZyqIpi_6wdG2P4Xw+rRo1ZHzP6qelZ?CWNrU>8ppM)6oeox!J$i8Nsy` zm)<}}ww)=NHi?ha|A!;Q8hYwub=9Ap zde5+i;+KW=F+%7V@)IXb7=l!QjTRUAARJ+a=FUWPC-|jQYKYPr@P<*K`*#K@+p|t? zF%(s7wc4CkKz@;TNR*b~qUDu2IXO(ma3UT8j!Y2Y0AzMuOMuKxSIWOn%R|}~r^InV z*lh`xan7dE2PdGHgz&-elxUic8F8@Bl}2sW7J4D5tz;mnM%$Rt2~)^RvNaNS0+KgG z5|9jmYOf;3xPp%iYdwHH(6Bsl~T zr6G4wFRij2XWw$fP4-{AiIAXpv1@(qHD`05jJ)R5q74gnn4miR{K{SGs5Rk6-48k* zq7$F)u1VSu-3OT>4YTdtwJi|M3Q!c><}G-U2J-^MuG`zCW^3#BkmN`&t>nnUB30~X z1Mh8T8QLeyOdhHHlx`_Y$V@hBn|PZZ?F5UH-7^F>#Uds7BLF&N&=HkQujh>k=e-}S$+3sS2);zTnWn1*^RFrBJ{qt3 zLiM2`S1dAj#zYIlz)2c6*N{^r%xJLtSJl9|C*FS}E6?l<863#Gb{P_CgC)sz8ApE^GOuu&5(sID7RM~`vM8?2n}f6SsfNHoU_$wH zWP3~B435v4QW!)9#E@cyLb)Zm)0N z@yG~ats)GpH8Oeln}DxZJ{+mPr{)74Sa-wGa2lRGCs=*?ulK}M7PXL$#{fq3NW@GtZ00=Ikq;y6OZ(d~p!38ce zf%?p@iuhs}u zKSFoX@A^I4_WG%fQ}T+eMY6UNwxrlRBMRklx>E$pb(#iN7fj_EBw$sA9@?D|hys9# z@Uu)&NK1?C;j`Bluv?_|J7*zmTTZZyR;iqKyMYgYzfVd#Yx)O?F_WU|1<{b6eIZ{E zUTQK(e|alM3>PnMa!&+wAE^ihhh*3bcBxb{2gC@&>+2N`q+#nAI4aQU_4qe*b*Xv< z&RuAfqsm0;9saeRV7}law@_J=n>PZ1$FSZ8@`JYLh56Umfhkx@a=Yc0ns#eIeWgRj zRx#$D@Qc8bUO~o~#2#416pMva$_9LT6Xz%&G|*de59>zGP~jN6#0Xs`SB+PwtcK(q zuQt34NGR43R`xDv-fHHIdtTX|(}PM>K;5KLWZNAxO2o;?`NEZ0!oCW5&CPaREL1IX zO>wvnV;*eNu^Y(aw zY)lF-9zh_`R^MUVKX8R(gK=SM)yeR-cafitkv{Gi>3f(BPoXspr@WK_`%cO+)3V-< zMyK3*()!)DMHzczg9ZWc`9M@_Xk%>SdosRQ;K(I2BuCZVt>z~|?xR#ltrZXe(#FT0 z`#c4&y3J4h2Umoz{Sv+S%Gn(RJ5Q-E#?Pmqca;Pakygo-$jM&0D_dOXFJjT?s< zHthIgT0_bP%4T~+9Pyxvk8Gw`k{ElBi7`3U*6m{oRnePj#ogFR8iXpvzd@CA#YEIB zz7xZiiAqFR#G-mQq-ccLsPD}h+#7t!jLSY~+T;WRW!t+aD4zwiVoY(26}h!Lq{E zxb2`#lhv(RDHEGxIWe$L((xC{z8%4|fZ0TL)cv>kO4~SpzdoO$a@aEV5XZyTHueR; zNP3H!Jz(B>jk8$r9%0fGi@DSz82jqk$?x@2qqSB?9fI-+#uNtP>L(oR+OT?Ypvbd_ z|BK!ED?d1c`|cieYI(CaA}a|{z&WhK?}rx(zpa2BlKFb@54AF?>P=JgQ5o<=3>Eo! zm$aEov59;whPi2QRn?5+PZO|y&%a9ZX~z&bh#iT#DMSZ;3GmdTVA;45#>)}&*jS36 z&=8@L_RCV))3?vsx-+6lN*PMXSdK+i%0UXb`OTRmnl9$jnE7jW&Np3mR;j=q72+bQIb)tftg02CktZM@@W_0>jdabE=Ew(4rxn- zK~DQh`d&)fN#k2mO&6i%8F}J+u8^5rq|OJeiHQ|*333ycX>xvbH(Jw7iBaY4Oa;w5 zQ5sc(S6v^ed<&ILtkZ;DPwqH7315BN0y9w(NutsVw%zsyxmY2-nkcCTscGg$Giu@i z=EG}dwY|MuR@$p5-nD>hO)k^E|&O3%fuz*JQzjZh%J+1Y&h;P<;v zwq88i*?jUG0=>96&|g3L)1xPN2X+;*0T_e(yx6Z!qz~T)E)hYyjcM{jH6+PzmGzwY zsbm9XjfyvknNmhw+g`uXVWcYflH2q<}3!IxF8ZY5VKEG8-S)(2<8x!lFj8Czpy z>1bdJelCBhK$D?15wbTOp1`0}cutVW5`^38uF|ZGKIzKRU%79}Oc|F8A*z_E)bWD4 z-@n0yooWY8o10WO2#f}*#*pofQu&*m`D&IUD(o_fPDyZC^+CyrC+&BOSBuATP+8Sz zgxlL*8BeTKdm)Vb#u|JBJzl+m(7|-ONfMMH?(Wtg0)fu!Mb#F*@r3#*QJDZ$?M7u1 zUq1WaGsTH0Wl*@Y4cSzb{tHA$c* z2Txsz>_Cf`bre(K%?|ONZd9wkr4o^J~0QK}7_Z`z028MWg>JU$GEfSX{dUIkY z47l~NuD}ivDkCrg&Kqj1hSkJ(>t-)Cq{2oILw_;yY#USbOQ%9*TeObBrvDhB_&We4 zvm8=LsLP^u%9kxp6Iqdql#-VM`LmVs?WT@la?<8pjuz-!{`5CA|3nQ6BCcbnm9K## z)c6>x#AZgZn%wsGs5m$B z7g({{I*^X4CD|xAduK8^v%I|9HjV$K37d2?-jhkju_Ih;s|Ci-%oIahq$&68K}Uj+ zY~I{b=HjYojI+#7o@tv3m_nI=yq%Fl>*&Aa_9AGqf2Mnx-PD{@3FvAkFQbya3*4XIT*>p|2`#qMVp=9%Hm?+DPF z0?5fs{2QB!-;Hi;&0C}~vgTZJiB0E%`mJFfumdJa&k+o}av1}@nB;X^56(Z;DAX^c z)A^Dh!RogSJ7OPLtGmRWu0gQNB}Jl-E})im><>)W2Ye@l8-g3lXr2@+qsl5)u&hQx zVN9l7X`hNB6R`Py1k=m>PF=y#98e$xt8&>ztOImXM~tc;`cb??XgemS4C^j(ovd=L{i%!p-;&jlCTF-Nrw>Hiw@XV6MP`v1~;_Wax(k#|2C2-MfE! zwDZlg=Z_*wVXMYzfwLjbHq}3F0GEa71;zn<@iZEaElG6{ha-4xsXu;V%$lxJdFroW z)!jOf8{FSba35=B3z2nBk(cO%{&&_@N*ua%&|Iu+=0jDjm~YhE!d+T0H&K*_`67)) z;hKgN;BkRogG~Bi7}k3P4l!QWHP%Oe*&j*xPhwkBWt+k!026p-1wL>mv!UKArPh-d z`AKTnO~;Bjiic(&>0!c8q=9rUpF0rw_zYfp@S+Dtx>>5b?0gHx=IOjQECd3Cc|0;= zoIqF-QA254`y4%DY`plnN%$$Y_(+$CTVVG|@8(*RnqFfPc06~!6}dOE6jeAN*?P^e z5#085pkY)h-S9}H59i67nhlZ!f?LF~t#S4zEtTL(k_SHOQ9+NiQX$z{gn&0XE|dyNL~~je2uXx%T`O;lAu)tOH&jl zR;4wgl!l$_@QWscU2(66uOxG9S06Je(rPUu!%M>-&hDY#coykH7<2Xh$9j&JU z)u8Hl)SHp(q@Me#gc;x*^-J<6BI=>$@B&cl$vf-@1DCQVEvUFX2TJ8nDxA~;Ubo@f zQxdzKiE){AhtSj%ACge;k-bZ5$ET(~Ca=$`fy-@QCZEvp+JqofB@;FH79r4t#1E9s6qrQE#KLN`+kCN53JqO!H9WQvr{@+-}#i|}fBrdZVj=+?Tm zSZ<0~7BJ}xdZ*QhA>77mB#sn8Mk~5AtZ*50Ud~{UPW%~;$r6V7T$BF_u|HAjL9-y& zC)AhpE6D=i-oLrPMTagf4W>N7HNM%njMN*WO#f2O=+l#4p~lMfPT-sK!@LP7#=z42 z+;}m)kPQ}hT@?4^bwoTfd7kmzjg2*M%FR5)jT_GHjE7IJWqLMlY~1K{RHGSg@UxMU z1ja>NwI=imgL#TkkRci3FY^N}oj$B4@i7f2f^+`L}SPLFmcdw<5hWfvLg;9~9g{eiH8 z9BUAWE*eho8bxztk{VOIc3u{xTdxG`2A!cpEJZDCs+qUfQ8PD7j!X+X?HQvlmOxaJ zUzC=a0cAcj_l2GVTf2~u!aAz%5?`((I@L3m7O>9RWaFL4R?`nrY`!nxX4yrAV(-laxxjF;4g;qe0OZhC%{V)2ZI{>y4H7;jL(o%m^tF zEueAL{467nEr4`6OCk${hhWNaJIB<9nAZgE1_xtid4XvbuaP=T+(A=CiZfGCQ@gcP zvyr;CDF?#>QCf^?_Z8ZlPriz=IjTc7^3LoF2Ca{)F~A(kl_43W`+l!;23;?P(w>4P zRfAGvMdeO&iZRZ9mPqpR371~H3vnDPC+Ej_5@Yd>?sT6aOW=tUM%?CL8YBwNXeT@F zn&B=@eBv`275jHUxqKnCw_z#^bP!2#p7zykqu3l7>}=fjM$$r|}VB9*8px{FQG3k!>4qi{PrLzpk+BFF03!YuFM!oKXxne+Ry z@HXj2i?e-x=JlZ^^1l!+orW?0L_rWIUVcT~csrwaLut|S2)lR_s05LF5Or+NxZr0MKQy%H|63Qjj4ANQ$NH$b+ zo%+t0KyBcab%d~v7+J_>1(hvgWl?@|DNNT&NL{0^_1|nO^QYyLpi-~^Fb~aQN;i8Y z0I$WrZZWkoE!aYRNnO?$DM$I4$TVh{Szp)5ZZ*a}F&VUV3+4xRoF|d@3L$Gv#LE_J zfT(cRj-P6zd^JZfc}lw@%s zeZtdO=SvZy;2+4iK8ox}Aw=~fg;ueO%)!ZL^Ldj)>Sec{@$zwAs%zDRC!5G{4GCDj z=^Gzg6Am4V=jB|^WZ5pZ3*G4E4?Tp&y4~sQe+sE3aq=#UMKJJz zmGR9`b@*lI%eG2ZS*!bTyRWNNEL0!P8p(95Kt-K^ClLbirECB+NQ8z~_R+OMRSKX_ z5$sQyS&R?MH;6fVety_iU3`@w6~D#@NGv|0xQWkFapBmNz^-J0&DUtKoa2zOUL zkU?lSP%K*rRLh@AXnC0puP=vNi)yKXhD3Dx%T#a$GlXShzya$SLn3gxq=Qa^V*y}3 zy7ha^m-ZYs8MsyyTVHE1yCoLHY#6bjb{Rydrb++l)I{C0qd_Whk+Ci;&X;5w3C1Y9 z#Z1ONI^1I8G_kX-XpHu#F!>p4c1<4AQCcLHaAM#pQ_dDr*@F58UG2Y_rdhNfz^+m* zf@=Dma8~T3+TI6{GfSnqWGDO4pvvX;{lWtsRduO7Kj3cc_sccArT+mT<#HcbGLN!? zNqoax6|P6?SfFt8GM7=8!NY>Bgjvlm4gWoIvTQP#)E4ZWrj{Hm>-ipr9v4cj6y ze=JEcDXVrRgRZ;;*gwmXzt$|RBaB?vW8E^f3?Aiu*A<&gv<(= z{sUPHmlcApTA?$dluV;H5v%T-eIYP~H8AcrQn z**;Up#f~?QEe64=8``j!X5h6K-Q|eVS%^s~EhU_&lrY2Jwk-mwR%g+Gt1u;jQzx9m z3$TT4#Y4ZE1g&A+6jg|fIf?{`)@o({MNLWwu>oij2i4QeNzgDIeye8@n9|%SI#d>k z4$lNi2usFGb0JFzL&}ir=2+f}gfa4|e5v>p@@&gbvRsKU}_z$YXuUIH)WBuu`^^br?;@% z^67)ajP=Z4XT{_ookXDTye($8V@D2)`}Fi|cIMzyTFi6ZBxfPOt=|mz&1CJC>Ix_>so1+kn|@teff%EYB{xjIRzSb&!&1`A|q)>RFC7-Ds% z_arj>S9%L|Bn8iqrKJ zTC+XjJ`;;;YI4r`5XFKYW3t~S`^POSyRUe`{9G!oC7#(jkLUH~fY?l{AFpBUced;0 z2EVo?^tH%V+uJa{;ir<6`mn13`tvM~8kM0N;?9o)5C_#XE?I$rP@WjE=|i5OFs&`{ zSHw*QsVy?nrNsqnF4JC=5|n`E^(?i@%^4eP_01{*EDMNZ|GX7~rTJORvsy0yi-hhc zBZS1^P7Yom<;H?UySb!(%fnE>io_VQI``N}>V{-+O36v^Uc&t$HrE+LL!F4_{d>%q3860&}A+{oZlU7mPgOI0u4*i!IZ6^wJv}MuVn|gZd!o|C5o( zsH<(43?2dDcaE#r)u*m+LMr+IbEA8#!Fjbpn6<;5mCuqEs+>wOeki{B$~l*|PhyMi}Xt-miJ0b-SY&bnNw z#qE@X;wS^P%^zcbkUj+zZ8-V!5~_JN4N>u(fA2>*OR!hhIWUomo@KgTf;#(qZolb1Z4gD&i%5E^5sSLpk<*aP z+yu3q5|RR?M{D)QG9kw`qV;<{SD87Y`xVJ@VAY`F3@q0Af>xMDUlMWEywKk4!Mx;` z1>U%d*%j;{TzcCw114^?S1Q()(sk@7-Mp6>aXgd`-S<(I-S=KV!A7cq@R78}aqF5$ zwt`zK|7cFlab*IMI_bQ@pqYP8!74H(szNSGw8`T0CcZPOQdD3p=|r$o6yz&$d$V&` z?P%d^mH1pVnUfK2@(wYJuq2~SQYYFK5r$aDI`U?axwXa{qYbfJ5IuT%GTcqhk8ouj zQoYKq_kDRZMhuY=<+4z{W?4cb5ys+){U)<<0el18&ZDfUr1@QNo9D z=K=`}(!8rj+!2(*W;h*IGD)Wi*vO?W6%SP|8yg5G+!iD^ ztOCK@u8FuG3=d&3?O-XaGmxpprb?im})v)1IYjv>2(FR>wa| zmK0<&9ohX^>>i&$Aj-df@YR$pD&=;g8!QOradi6rQz8!Q53sa}lN*ZWA{;&)YKOT<+O()9*ku5jh=5Cy^MStllv zvQyn~we3Ct*ocyWEgQ6>*qS3ZiZ$&jzVDOmMh+HX;KR`X+UmUC*kd)X-eFe&u&{r^ z^!OyMjF+yGW^_f7vqZ(bnd&e65rS6Ho)dudAfxCi=5;;>!U!ypL1Rr&6bL;~F6L9J%j?8_w`8NZkgP#*+7z9Okg9;G( z#vDW-^!d5&=Y0a7kXB-lkN9cJOui}Urm9};KDF$pdx@@iFOi&o!NKHXE(nU*3t$mF z8=V}?2CsH#Qav7}yawfsmnoBPyz67-cr=?04?CxLhquJ2&@ zf3y1w9--~5`k=Qs_ZX;D`(tQ|7HL=a3e3zE6B0&h;oTXI@^X_l&a3-vc9M*st;U_Ks0X4 z9@W~2cDsRo2YzV<^Q}P3rM|b}Gb-jMBvv>(yLc|CjogPlV(un|7=TY>BF4EAf7TvG z)^2Xuk@`d1zh6V8;Vu~KvUP_C@;`qaVCt&*aRtuVPP6>4OX!QIMT2rT>c=VH8%nAJeZ+w!s)!V}?ga`T&-m-F&k-UBZ#~Xi$g@Uf#!*|2+k;F=&5`0w7_#NJOlI+zE0te|Lc<%8bho`!iJ3n4$ z`7w3{7f7^v#w#q)&j8;?gRhf}ADy{u-4y~+N8VQi78k+aoz6`C=%`Lp$k3Fs%@G?*fj^qoYDGC+*vQS1Mqm3XS;=58f?ro;+rl zUyV3}e04R;tALy!&~UZrWMDp`K$S`}NOe%?_%&};hOGo{Wfx-q)pCrsR$|?NPZweX zK@a2-eAWkH!jt?OBX=;atPT1x#J6d~U6GCYFK21n0>|9$%Abg;gT z4*xd|%91Ns{G`CB;2kmsJdb!cE5Q+HT_xN8{kAA%Pqsk%2MF5^Vld5chfL~uZHcip zTl=u!K>tFloTY*Nki=}3{<(}u{`9k+xkimpp)O5)l1%JiTw8s4gC?pQ2>t}6sA0`z zV_Cq&H!kVUDS5bHt^ynDs~w_ZXZ#q_x)Pi(vlK6X1@g1{VWIq_bY6$jxvfc+UTq$Y zhco*DTK_oJGbDWW%~sYO*Z7s^qeUWd68I8JTgsqq~wH_^AyuEScbn0#R0-Fn$zFhkI*MO$gXGdugCS$`R%PG?l=Axgq+OsPC>4x^kf0~~ zvswtcF*71^L5v=O@((Vlp!i-`yDutExsKIM!w2=R-!qHui-|E}w%LZ|hakX!|9%J$ z=YzrDb7j*jgykl%^!T&%JmHHqDfm;fG#yhxNNa%tlWJm;%L{Yb>U!IL7KFEVoRBX4 z<`s|c`3b9%PkljgwPO_5s?YpNAw>jy(GjZ>rCB}m+7(!82HkmIZpU1vvuXxXD~ZHQ zOeKOZuPx)5 z-oVs^eks-6WI8?s4x2+YyZACFwk@}h*#Fv{EIZ=A{?eum9=`|7vC^YZ%sZNP`QD-K z>z}hrOoNZs|1O~uWwq~bU;g>9_&0IvRmC6WM3Ny1zyj{CTRK&u6{l(?`%k2uB}Y`evsBA z`cP7#bO+vQ<=OSuQl=V0sSNQp!0nW-w2jRiG8GZI@@@=ABrNPfZ%gE9aWb9(Uk2RS zaXEE+3!1iG%Vte6@*&c#ffECDS8E;F%{jurOT@i(&^08mZBgfTc@yiJP7H|0dWgei zQGSG@?fqpJ@;P0}W>u7dXRjsItM-=v)jWrTOhx%sJho4`fyITFhGFjuO;^-RUhUE% zBX0DyeleV)Gw!S*>Fn79+-L)a5errei{58m7&@IxNR5tQ z9@K29g;&NFVDRYN`>OwDSrgxMp9V?f1)cU2arH0qz4O*kA%hazN3DdwCdHVwlpPMC zl*{a#07bh&N|a(@sk$cAe`un$2iuiqRSmN{L)|$D$Vx&!j;SMCd@P15tuzN!%~oH! zD%-dmCw0(M(-?8}3ROP>#Z6!uvr=L>{|dC8Su-xBB1zJNnlT;QzV@!=WjIn@Se=ni zL-wadMh%6he<{A)!j(m)%XK-U%glijr>r_;YFwFOZPepDTOh+~ld)qHt=TB-2iGb1 zE~SOJgC{FT37ZN9426zJXK`5*pcaz;QXAdQ7^1~=(W>!Ft`-5%dWl+Mm5>$NmIDo+ zHSE{3;w;U-CbA6MR$KMyOd+vC<{^JtKFPlVkGTdX-Dtb>ss1}LX<=?^mC~uXutKO~#PwJeJ993*VI}_T!niaGNm?Vt(8s6 zmYZ@Ly=J_G5gNIMO|%dQbD}=;JuX~|#6X-L^fulvBz3yhR+!O;Ofu=k#!?V{C+ryj zYP7p(ev-D-7)~X|uW^RHa~*7iyLXIYGcK+^N2%R_l%D4MXK5)qs&KQ^e0|#?&}#uR z4Z4ZUj{-C_y$q;-{ngjMg|h(9J%5GNGcRDp5~lzLmwDRM2ktkC5-hZ~e{=8@?l6PR z12`2R%j)3klc9dS?_V|!M)z2jpFd2d2jjsvlf%RD5Pn8q|9NB2zTZbo@4?2N6lLkh zaJXSw9)z^PqiAw^0rUDBcn87R6RQ~9Ef`e?p$=CixRKo&AhisAL*I?T_N@10>%pU^ z&mXZVdN!y-2Hj7QLI&Pmd*`$-NqQT~A4IswIS6yY!08m}?tVodr5VU?lsr;jJ)FEh zIht^M(4q^s#cf?kU)kR+Cf<3Cy8kT2o?jflo}65~66~G8OX}5Q*vCdw`=f;%wXe3G z;lI#=pF@Ac@f{=(#3gAsg`d_trZ17{aL3_4j;9C%MEuU9y}jY!!JE}!E zA6`y)NXI9c6|b_~%p}+3$MClOfB&BeFt>elPG2!h=4(c+;L*mZJ-RNpZuWroFIrO#TgMVDZeEjG5U~Sc|F24yA*O#{j{}lGqSZP70aLM`2 z;2*L~HS4Fp?1t;CklLSuc2UoLJ=5@mv@S+lt7xtPRyVN^;GM;pqi3K|9^e;ul^jW5#|!l{eIGo^P!S zxaSaltl@?v%r^oB(~LIS{43n4;0!rfdzHP1S9+82K+(4pQ~SJMgWGEnVw6A>KKqmD z^!yZ}r-KAS>GK7T!Qu1?f=(W=k?%p_xOftx=q6Y+O1R<4-vmv`A2kqu zenJClModi+tjg5Q^zkf6ANJYDlOqVT2l|rUrUgPfBL$8ma~h9Q!6Xplf+HiSTV#I` z4`WzJtjE~^T**w0<8J6R6&p>CWiEdiO7Y_w&vwzvn&iinj7~v)+ zTsCQ;+r}IQ&4xoS6g;duA^B(SBNzOR&KB5fIF1Wj-i*VdJxU)s zZ5;l1^S76tkNtDp3ygdBY(n0T_C8HYWDHOgFe_ob$`eXci6fjtd?rXZm<>$N6($3n z71*aH|KE!T5{E9&4W<0r8=vi+@4p?L(ZqB`5tiC`B>{T%Tw#e4*_HW+yhFM6YGd!m zuP!gszHyj8e)1CN0=Wnvk*d9ti-TDtrzrC_LR-JCo$&IkzAt%JF%uU!+f$o0wWf9liVV$onog8{7C(vJnV>`qj}?Bi}k}T6*OP$ zADtg?uW&FqlU-vyFwDsC7%{10KS*jIl8#S1$QazWS$y^U^oVNN7PO<6KNREXTm{lK z$)M?4F~Ky^1dX*YXUF`#18j-%kDizcB|^CNbSBA-B&UK7Mx z2*AXh%E~`U7JXq2&720ac#2a8=;BM}IYoD8C>> zhV53fdyk3X)S4`Fa&%L{k=EmBQCavQtfvU)XXXgpal*^i^^i5-k1SPd8{vplI1V_F zzxvM$h>EQfp5r~!tFxmSvq{&>-5F>QsfH7E_;bmsZIlL8nh!AK>!j2Z;c0iCxq9UTh ztY%dgMVEQ=+_AQ@wM-L(-`F?Db?&V;tZ{J@SCe)UX4EJ75<-@$L!pb@NJ7LP<# z4;B^0m&Bup7=^RTChROR$;aT3y*LK>eJ=h4q=Y^Gx+LzHj{@5k-Xz4k8;k^LzVe(h zs+zc3plL}JeY}$H48@MX+VD&1!=@;;LO%MBO*Q*q4vy*Yf~TE|SADp5k<<_<0no@i z)D)uZV^Axtdp?fPVIPWHi$a9{D!6|C1_@`$%ZRU4ah(7Lf_%eKlR9dugy-`#BQ}8#lLu5<(~$-uJ&Z7RH2tehYVHw-(tzkzQ1hBF z)bp(4`we#(XOp7|u7}iyY!&3lZ3)fen7x!*;uV~qUXr_Z%ubOTxYl{oDbvyQ&zswE z?9^{_dU$>egLQVN!Kp?CAh`Y=Q@b;HSW0f+<@Q?ejizZjjB4yo!S0UhVImlt3aRix ztI2$@=ebkH!x)bU?eMS7Ugs=DkM-!A43}iN$D)IewHfs4le5=rtKXfx#T}t15j#Z4 z-NE0@HU^t1Pa2=iFuetBGw$h^Av#~bk)aBi=NvA}2Ch3J zlW%!}x$g}>nH-MyGYx0hKo&_VW}M-GnB>en>c|=AJ@cH*02{s~}XRkYl z5o9l7<(A-v#}n|7|-od*| z?3c9g0^{y_9;jq*u5;2R)iP_W3*?;Dm1?+h49ql9Xhe{xV;Wcif^_4mhkEK*uD^T5 zV-En8zvVLWCka6(#8smN976b1;4}iM9h`umJHg@23bg^1A)Rr-v9FLI+ zM4|CDnSFX`r=GenzLG<0bahY+#4_+%Kw_nf))bjXRLy#%VP zcB7s_HoIcOfvr2OIq*#gzj_CUQeA2(;9nrQbB}$p`k}!@7k@X8LQ3H%4S@5+r$;y& zMP%9RgrPK(8*AEHJ4)b+cK8rSAo%3ob+EnGnsSTmwt|SWhP@`W>7u-EA*S1t4@B-4 z!6E^71+hgtX2abgfYMv+WZM?3e2jB?!cW)kL#uN~5=YYkWSCf{KNC?J%n*a$RtUW7 z!Y)?NBF)kcQPPNcLMcYbH_D(;fnv8+JWI@=(OUC`rBKPqJkVycD6_qq?Y*i*e!0BO zaAXHdkv9(2{8m`1od%SRz&-cuV$J)#lAhNVtH->bNw2f5`-i9JblKg*tJzi1Te}j7EawiPd$Sb}WD>RMVW& znmt1mov~S4_S?dm4Tb%F|00ec9nesce|h(8y~v(fGehf>dVYx?3#lD-W{kKrh+002 zU%wwt5kqr$@96{qM$-%0f*~jiIWUkTdhMG>_Fv!jN^!z;()h1`Tz1MB;uUVS^;ENhKn{9<*t5_8Bb1xG_NG;XwN!(+TqH$BFo{Ijo_|*PB~j619P;Rf zAW_h&Ewx_3{`%C2m<2l`T{**h)^4_ouj-0dQQ}>wZcV7VZnuGGJ2fiu$kV3Zy5@Wh za?Q$xoSq;TvE&KQdIqIMzqK?;Bs+(uR-`S^T%_N8owk+~@}xI(TQC&^IJR%|8DAq1%Kkj=$$`6sNaOi zLRE^w`feyqgd+miQNSR9ck1AL$!W+0gDXWP;U%|-!si9qX8n${Q5m+N^~i!#)kv_i z${hOBwL?4A$))nFP4ah#c6`_{#&n?-{pua4~O)tzq)nl@?RKgHvNb zWbeml(02`c4Ex|`-fF5P^1nUW*Vl5B&pnpYt6CDR(y)3sZ!6~pBE0_1%%#?h)OTH!wt(JV{jw{*| z{y+BKeZ8q8+ZX-6pJImXY#D+Kq`Oz|a!WGAA^kk( zLC%Yv-)~&1YSyeN$w1Os>%(7yt*M%I88vE*QRA9Iy5P8VCEi@-qef+#%+iLgoiG9Y zM{`T-IpdbeZsypMd=)pkG`~n!+N82a14vRRaspd3ed>%hCFW)tpL>qsifXwbuN7AQ znsys?^43kTR_nIeQ`?rNL++wWY3np{jYzyL>hU+o#rv(AT+Ozw>8Qiqx3L$YS%pvo z1oqD+`v@yIMaGBK&feY)T3y!oFYesO`~SRvpE0jOVz$4IP$vd?#BCxCAZ3!q8rkEG zfp|7ikttO0FJ4{QLCR;*nYnH8wokQyYim-*j6!o`*Rh8eiv4qv$}dfIP@g})PDBiT z_X}f~q zG6{l!`;}EHypmI6cx$q_pK(VDJEjCRs`L0$4KlDRe4M4a zMA#MvhyqfU5kT?9uD!9rPPo!+wDN+>i;+?Mm@yLKQfGcG<~x@tA- z79cX2S|~nLbKpJMh_;;$m?lI`fUzLRV8PAa`xF5Es5?EktAJ-NlQjUX-mJfVEL%cA zYgxK@FkRKbjBfj5cU{c(xZzRC^O8Awg;$J>_&HzJL1h__uFo+5KSvBeV0s96O5D8K zIo}_dCal^W&JHim4v^4{AMf|3$B2NBPW*vyR*&8uPD|MEUQi}s4M_;h1svI@C(ssq zREa2NJnmOZuN%e%#4~5PCLwbY>%XD4%wk&X)plCe{%VbDet0;{OIz^gh?rj_d7Y?0 zjyLokV_7~HjzPXhJt3r7Lx(P2>b|1 z)2yXDgZ32+0ok)Ad)eo#bt9CgHmZC}?m3fT^KhS1NXR#+OXvc&CR8&>q#<6(18zgC2|PW$_?@Ot(mP%9cyiRNZ5K_(jpmYft?{(( zhYd?YESVI7n2?PyNx0VVLI~{!M9+v{O{pH|3B>b)XQf4APh)u~KESY%Mla!k1TekG zbto>M>WP&%^&h5YLz1ibgzxLKj3s2J0Yhi&k)h=ojRJOvvQC6J#KF*sfIWHg;+)|R zQVbY}ux%ar$wGSJqiNEM!hyoy44FVf=u|cvqGE`%;@fHLk@QArG+r;?XXb`n8Qcxp zH>(_&4Opt@&CN;yW>E5n<<##w*+^G~+J>co}c-F!FqD?t~(NYdVKS^=Z?OTf~l&PptuD$qEz$xk4sQ%nX4x zfVN@!ECUOhLbG=GWcqx-3_nQh+4L>V8%q|!m{LwU?aFMsv)L*0RvDBc zhRo#yrRKYcI2E5M4s(}d+`E?NA5sM_o?g3qOIlQ`!EDrM{1}dX&`-nR9(co>(w>Ozgk15u;a|GB!{#BT&YsZ^TQucD@*9O6W8=)c!a1scG292aw1nA0xprq zS5H`f?4nxg3&guRumW8t^VXSE)m+z~=y5;C=SPQDE9HVrb>-dcq-f#u;_sH`>dmuW zz3Qwb{=Nff`d`y$T2tF;uD-PneQ|QPn*tbO{vC5(DsF^Nu4Q6ZTnDH)cCb%-r8>Cb zBq2rNtU{)>BuU@Al_2FB>>ipbB$7CvW^%;*k(~ZzmiSR-(kmb68VV%SHXt0xcig z;mi*ra4!-JtblxQ(0?hEzy`Occ$U6gKfWs`9F2HtvA) zb7CQa6=qLL4-(k;YBjwnuCH%xZ|*;S@^o|m(Tl%4fBNFVBY;wg0HhN_HCiRLmRj%NibSP-w!#6csW62Yezn!rjP41)4dLKD9p{b4BKCAObcgRCFQ%YWN~`eJ(jlcvBiqf+ExM9hPU0b z#hNg`%@w_)!A(xoWsD9PV5s9t&W7E&1h!Bbb5#nl86hP+2Lo*m){o86b zq;3*09f`{fyvird#N(by9($bRnb%oH!2o2B$>^K;=DlGP?fe`5CQ5hj5v;3$PGsjY zfieEn9jn8VFSrpK^lTU92Bt{eKGVA<7a2f-6+$aFLMVZvyCw(8uuD zL|_n;SVGFiq*$Ipl3>D%LQ`NeSrhmw_ktzA22;(Ve~dzwXo+BUv^(e>oL-9i=gHvo z9ATRWSY7Qb`N;fDq+7kMky5FIQ33zI7>+z~R{E7if-+6*&Fc5Jzve%`Sig;UI$i&hq(`+HE+3v~Ck?4C0?)e-bxtO-)E0n7g;wB;M zp7uS6aN2vTVF0)jIEz`s49}1Ur(z8Zl8kyFrQ;U53dS48EWSgX2oR8g#3|B!QG$rX z^fW>&ACxX5CM9`0oL%Net+4jUK|xLsA$_vX>8*CiJu$y9+3QMxoZpu4X&KnarQJKJ zVAW?<2@S=DFB-)H4j()}oyh@qvax_3q*2~IG9D0-Cy@EMg*-sgi}~mcg*gdTHM$R8 zQw;b0Ns#gi1wERCHQAiGmyZup;w-i_m#-sr&P@5R{v^3m_@v3w7u}XhfNH%qmGnp{ zsUah*RZv`pnl|Vu7b-aM#}}f<9*>Gz*6&-t4C}dPSujw1=W;!`@H{b;X!BdF(_hlZasBj5sQ_& zSJ$BOX8ShVwN&O;k>iu;Pp>81B65mUXj@G1bB>pAyF5;DwX+d;KXkaTn9c?e`1{Bf z2KyFx7`=V0dZoiIpY>YTRCu+{f)kZrBS7LFj;@9+1anTI;WUXGF~|ATLa#J!L`l1R($; zB%Q;x6qfy1(jl&)eOo!tMLUX)Kcc3_7tl(hNE~d;`%;k+rSw>Aa5{zkjeP&Mg#E${ zpH$Y+8WYWw^m9+_-yld!NIr^OQMl$V*hpHakaMW%U4&$y5M@vF0n=0>Er@b}R3;Q@ zPS>D72Ig^-DfsNLwu@DJkVdv&{9+9T8; zJOSE#(=AHL|!3(`()5PAD>?!>8DL!l!YX7T+EajXD3_3QQD8Ri)QVSdX9IJ4}SOt-C zZ=mqxA#%veNjsS!1^{@*lta@g6lvI5?lDfGCI^o!JM+T&V-M9~C)Lh*4=L@za%V&M zYr@0DKi&U_G)SJ%gLADn(YmG4?@4cfaZW;u`Y2Tp9=XF)78sB^m#jcHJ4J$MU>~c1 z!eyY(zoD3m-G~j~?QncSBW@|r3yuno*!p_f@ij6^^M@HY+}5kT(X}-n(}trchg2Qx zKk%{7ZpA-`TXEB=(By;79|nhr!D2ySLv;_Sc{o0K*ZZ&PF1Z%!J00-jk89B6+^V7D z7;X)xk3v|C@+9EmpHn~MW{k{L+&sMZg&`imCvcKn`~vgYlya`*LBLn#1*-K@mIR50 z24V5e6&yjIPlhP4@^W(e@Nz>Qic$^Z>V0}RPRTYWgL9KXdVPH`J?tTp zKXX5T9pq?UYvVCO{C6ZT%eF_@)hrL_=X}f~h|WZy$8Dvvb|m|h1pS2>ckfYgH`ts^ z#*@`+8>eGtnW=DAmmUyA3c2R{7%yaw)Zw7YVv*G^r;?h?ihQ+#!{?ovQFs+H6N5q+ zTR^D|HfTXyK+#6W9%!YI{tL-@+t8!Tm9kG;ZU<=z{CfB}>Sw=fTgM*=z> zwYC%SM(2|(fQYi3g69_k3=I^$Q{F{rKt;IDe-}up?#NIHhs9V1uNEJUCcj>2G_Q15 zp_!t78WbpINMy04rp&|}L{(m7%F#VaNMTKo|DQlh6Xo7qQtDK_P9rr91gRvh2OyLS zdJEhn)$72b@eFB3`@LCjn>7Z93~cZNnWeazOSyJ&2U$Cso*uq|0$hz0U}x@a=*9_E zJ=|o@OuZF?ql0pRzF}+>{y?cT$rv%5bx|xy)61Ws?9vjhigRciE={Mr3>!DNIRAWj zhe+a@*FepLbnMI3>hWY}^h43iZkZJGqc%Lz804JKIdI3Bz0_7h4pO(pG-+$|POFt# z)pm1T3U!3xuS5Vt7)MQS0l{PlU>+mwG*3bhm?*G~(@(+(GdRvcY&y1}Uj3lz!mc^2 zx_^Pbr#r$w2LtALFf>nwNX5b{F)M{k6Ovcb`u`lMgdnMW767Wz&-Ftlt?}t7KM<`m7?2#t;p@c8?l*vP)hcpssuW&zds1Ve+ zVS2qTuoI|4b&p{<_0H+063h8 zof$kr27L?A1(_)o5JNlYKM&z_xTqz{^D6Y^K;@;BQsq_}IVV-H6i^;<0}tc+j!?rT zgbQ;dXU*zkT}7`Z!+|L=(2hd7_KUxcTze)2N@Z4C5l4j!vtgIJ4M-4_whP_WuGi#` zQl=s5GJ}FnK=eVz|BrS>w`Cy4>vYf?ZH|!MFOp!TcC_5f%uzJ-Oe(r<#hY%@SUj=# z6(D49C@4g~;xSXe$1Z%FItZko*^Zn9S_)0G^#0Y~d)*&zcmH$kwUjXLbSe2z|HQ`m zQ060w(P~^0*H}(quBs*J>gcpbM(Y$|eSJ9n3(BaD-@*A5$+SDS9zkz`_>Pp3LjBdn zBBs;v;gBYbvFfpLNf?i47zt%O5T1nOia?y|>$Tsm-R@2fZwGF?g2xsF6aj{3JT(Hb z5FwPz_H4?@rYa@f8VI;MC-5x&9%p!!YOiD$$+6SHaC?9=me|>NS%La4{TgYm!dwCU z&b@D%)-~JRhO0u+HS^Kt!|p_QyMs=Ot?r7WgBxp@=pBz2$%Mg@Kv(PGMcXde1L2`$EMNTfIU>q$>5w9BPkV!b4TJOR$4igz#LwS zh(M~~%>`x?HysJQ*_`d>0CT?PaPz(=sYvkTU+Kb(v^YtcT#Pn!)4P zJvjch@)ZS&PHT5efDBp3Pr4Q_7vceJyq*u(>_A_>(uFNk-t@;mljik1 z#q6@|L*RP|(Y*U&zG;g!i=;_4FYjMcvzVPH2os5z&+X;918w62b-S^HV-j+-6$za- z3fp~4an02$awgPp$Zq%pf}E%hkY;l%=NkHp)o-`%;soB?+xhDHzs_piXq#uu{IZ}o z&{R>q&hO7#Wj*HmD2Fc@`&9??L+r1dxmq9o4OT~bEmM%r{R@p(ljL@ZsgcB|apVc5 zmF6DB)Fy1epLixybt34G$ddV33DJlIvdrGDRT~T)q$-~5mb!Qm{+kkJLM5C}Vek|o zKwr9mTHvi@-hnBUqs`Y*|I%JWj^(cXzZ?RICq zV{xDp&|gm_b)T3sD&l*QIdec5T!FuUVU7!*oGWvT1bm-@>n7a^>RyRsCFYhU!%Dtf zf?p-A>%7I-Rq}n#Jj$oRU-&R)mAst~SK?KH@(B#HgP5a*os6ti5C(i`o*Z#5&=VgI z;K#GZkF{(3EF4fzOS;SeRX>hSC*X-ZgCkV8iMd*N5KoYRxh^@azUp<4pecL()%EK8%?FQG{&hB_ z*u;+TOH4%#ddf(+5Un6h#NU?hi$Cpj498p8h^FJ{bW34l-ga?QwpHwq9$(#g-8%7o zT#;8LyZVZ~1_c9We2X8aw^rA_x?WnypqZ@(OJPkNc!>63VM06uF4g9XX6c~iE41mJ zjp5Ziq;ncHeT<~wDyLAEF(rN<9s|%V^x-Sr1NWaILGzp8IlY#nbMyibU@GeK#(>5N z+*TE`ut4a&=cKdDTA-IdRl$v+N+0G$#JHVzYKz@KCzLnrYB zXdC?(hm$LRDCkNO+dMF7^Mc`&Uq{JbKh*$(^h!5j~!%*Y{*)Rv@x=L7E5zlR$8~#hQ4(-L!HI~6t_edZ1irS0 zi&9sNAL(*I*LCuVtk2H*LlAu;xkx+o8aA|b?dAI1)y~f%ANk11mDV2>cD2SV>wYf& zR@MW5}5Mob2!d0q~Cxlc%Hf+>o6HtiY!Ywm2*(9#{UskD zE3?#V;ae@rw+nH}j8t+0!*xp>UDivr`^uf_8m9JQ_WriZFU2H4$HJSp)vm8{|z;l`)*Vt7~tsk>4Zs5QU?${v zQ_8gzud=Z}x9?)*u0# zQ;eX$%JinXtH5RE+t=TEN?Po0=i8;-U99gbP<+ zCx&GIMn{^qjI_*|XHQ7XHpXrJ^gQCV55V8a`AHw!Iu;&ge`nDuMlGwD%fDXgE{Qm# z72g{$R~Wr*>Aj58epnJ7=F8x36N_4g>dzmFDEx z%iomOFNC9Rv`p78NB$DIoDGS?38F}jYaKkcc!ul8NDq`8r3*yw0dG#32D|}8A4mp) z_FD6NEZrgWUz`OZmn)|Cf(hyZ10iUV-gxK*S7OLC=bZ%uzs0~pjGR(IoJPR#qSv5J z)z>u2T3^-_UDIlncT=RID=s-D$PNPj<{@^OHluK9v+_O)3~}*ADiR0_wQVw06Lgcl zUuSlo;MUn@wcvkU8u4k&nZmc20z6}()gUIOwA^3j?*+FFHZfZCp?3*e?S`^KJAtwt z@582uKoTX>`7WBWJ1WINR^F*O{I;;qMmvm^c?@u+bD*i*YkSa@t)q@dwikC^W8Vdy z$u2qB`5Fz;peU{&n?&_C9KKd z1?U=EZ*iw?VvzC>t@7#_@p1nFPvl9^Cu%*19DAgAa>IVj%P7NJ)Dq2t-fxMvs;tTz z?mdE}vWsXR0!MyUqTU4MCuN6_cp=w0g?>!Lr7rxZT16{hOwZF8L20S&nEG7RorF(> zjA<`tC-5tMhl`^)7y>Ej^ni}oSk)aYcoK{zt|zp~wB|Naid6Cs({UkeD|GM&SDz~Y zR-h4wt7mYeE+I<1Y&Q=n1i|i6(Q$c~DqU!m6oamHyVnrGh~%~OECmux2e`OUlr%M| z=)cHJn8F2GN~mzAG2hB91ps#us;(CR+T`63;v`)*pq{fqtSd=n1xUXeKv>3a>6H)D z{+OePupf;_UC~`57lzLT6Njcj8Kksfo){@>%&tVqEuHG-=$!CQva@ldl^HUwOa2*i zS&>%UeEN_Q_;4bn64rf9kONqpRG4sC-AAFIjUs5Y0*FN-y0pXe@b~`UZTBbqvA6ca z^=}ak`gY~I`nQv2DRjWQ!nExXpr-*2aTKMA;)0}PJP@G}IY`hOz`K*hG%+2^T({zI z3Bkhl3WS)Yh1)C}q^D^JUd@%on&pa6)QE$rMbmu=F0;9&UdmPjFk|_ zjpVZ;R|JxopclZSD`FlIB_F^jU=QtA6yOnD zM|?u0fZpx6XdB%`#Q6yQ)*^1q=-Jv!zIe{h&JSo3VSub1`gXpp0o?KqDFmrNlE;Ju zDr~QiSWu}&7@djsD-c0X58x!Uv7rA*%#+i##CYv9s+}MMU^cstI6gJ#5rSay^Br(= zP&7_tt;^!Zwro2M1{{IVX1#gc$pKg1S^9$(7y2uq1vwd zZGOUK<;zK?3(6CKE98ZaFKV>}J;OD1T3tIr(u>peq#fiQHbefs$zZT9enHnFm*T|b z7AJ-nPpO!R6#2adm=)&Hu)NQ^0KV%@m;mV>4rAy5iVsZjn7NErA(1jwhpcTfVCp0! z8T|J8-CN zA?;_7cVVvPDqsSW`&65U!k0`A(Mmlz7NmiUM@N!vyM{j7!(rN2*z%eXocDq30DZ}- zS?^eKozle!N9p9^0IYEQ59F_p7H#5Xokc@xmK>ko{)Bg~BgIN*Eo?0i6n}qzaqwt- z2G`N)_TYH%gPSMS0Lj47)mMMN1vfeS{q1!T#M#@oDl!5{0Fn6OG|`$HJ3bt1$u-@k znrRdLU?ttqEY}vTaNWQ?vQ4zTk2Bz2KPVd(K7IXK(@yGlzs09Dv`+39BxZz8tOC-R z!k~tUhoLp-v9Sccna)B}rUH=U;XW5yJOEnzywq&!gm&fdtik0ojD?pkabPLLHK^r+ zso^V@oM$XMqw9VxTNy#a;J1kFI%C7<4^_$m=_qu3L=F_OSBIPZe2ra!Rf*P%*+J+i zB=VC=l;7ZBVLR8aefi}H6qsLr*&D6n-|00X39s>BUP1YgBnkn5!dX>@mef}&Ksp3U z%oqIU5$8`yhtus1>rig$bWfW!_x--8G!#wr)y3+kR*g^5LMFXNQg~%$?GpOWR7&Gc zfB3Fki$x7{fC5J3;z8}8g`JqI=!{`aKlA2@BKOnk(U;g7RZVxhNCI$r z(I3RXhEKLnI>M*jr=6Nv0DS8g+ojCb_zN5!alfSd`zPBGvBI(2PjPB8uM0cd3nkAI zOUZyqLSIgK0fiXu1E+(L*_+^7(R8gifX~1d-LAmK$j%}W7HNZwpEZ!oZ-psE0zqH{ z^Mm-pvm|(TlIDHIKgr#sv$qF#u}DJsI)Btz1eI5`qOFa16aL0iWOYXotI$m@L-6hJ zC8mf_-0X$=YK%1THU1EC$?M-hu4|d1GodDcvM!x1OvIxVRzFK6>VOb`6p`14&{-p= z^eSXEka}A*1blohli%hXnv`}<4$S7Q2BwDAB#Rl2`Lc`!l&~_v3!AB<1c3&TSft>E z2oF|N&wgTR&1^yV9dtaq zTB?@u3da{CAP+4vH%7xBLL(u+emZJ-wsHoa+{?>!t@A(nGo;-j2V!vE8%kxS)$cUMwPK)p^6WCUap>f5)r{f=) z+21K#XM!UV@xoGuThk+LSx0Ng$?t0K*ga&0_F5bxjsWSqznYGFv-;ib|NM`}@jj9Y z4_?)eqXOvK51?b|Mc3E;Dy83~SCObbJ^m4S&LD)Qqb3VGvTx&B?90!R;>SpeR}$%R zvCX9}FYK}fmxG6c$%xKDv+C~o>B0SXg9DsN+O^jDHNoop<0w3p^S6F3?J}LZ7!_GO zZCS~2$F&IuwpAc7N|@wZ3hHlUT}t{kM{qL!ZRr8a zG)#()z|;sOS$b^Ma1KJ89QqHZSijDK3=2f|U#9X%t`t2vZe9*exYrCZoHc)vOOM@E zOa+o8aKw&IXQ}-oDxjSmg)6)bB6@1KM$|Je%(>n)VO6}|e57@~jKQ>*cPB8JuZzWe zI=jS;0!_i(W$izweLRO}uI>1DaOQkRZ8KFa`p7-Jf{DQJDaCK`L|G$-`(!?sul)G( zm5(mY;1<32U^3}l>ff1OdCBXLH?!RId-nS~)NDn~tCl{q##>Z2sLueS771$Ulw|=Qpahkp}4vUigQ6 zT${+p`YX47qoqK$puX{m;Q}gZM3f2T{FBGD84k_>8z~^V(K~07^7wtw9@(uE-fc+R zw6hBx@aA_=2mkHa(h3xF*KCLj=n zp(+Hu*Yp~k2nt*_)Ky3~v>G8Jl0ex`fDLib6zvF__qE|efXl~|XIn3}cON|8t)9Qw zeX_B+&fqVGK_iAtA{y1P1yK`21QYegNE5VHv3NV9jSy!cAr)wka3h8jGR^=WlJGRH zGzn4DkI>FB=X$+vpLlWdNU~&~q!EsPQ2M>~`~UpI?_>mbpH#=sd9VD(oj?4pwv|}2 zY?ak#Mnww-q2XL=5F%{GC|ZsPv_7k09}G146GBEVaUbZ*e!m+}-e~;XU^KosrZXj? zQD&2I|Kbq-7PB#PQ;kq)eK>uS!C{`1(T;dV?-`hc%v3}`( zTveD=%$pH;&!ohNU^h%W<9CC8oUY|B+QGDEgX2q(t?A(OXnj2=)Cq;NKI|0+W4b?1 z`Bj#(taYiR9dcNlhE9=;M@np>M;Igqs2bGSc!ATrv$?&mZ;7E`e|rD zI>|}o%EGnk5OJv)^&(r)+(!8(zY1IT`s$+^D~!W(K`U2f@ea~|Y7ra>%`|&!V@!6Hcw{AI(|u1nf3$wMe-e!z zM4STrd}>L*DeC#0g3tzTBce_HQ1k6#`55nhrFSqLpI*!cq=dkK>7>~Qn-i*@B0HVR zaQYzW1IEAPQ^VTmhq60JVEW+2n0Ijt{#sv!JE~!Ti4o}&pq`W+~&xRuZ|$x52azJ)MEUS^Ql47_d=ZkG6iw5)88AVa02~C> zfI>;6t$LdbOh^H&zbIvPtBsXWA?$Z?z2$SWQX_xS2R$8O?ipQ1;C0kd!Xoml%eA`x zFVxRgu8NKf1thJXqxdOdm>`ycoC613?$cpJj*kyLcvFQyxim=Rxbl{Oc|@fmL?Qev zY6isg9;%Zt!)TnbDcM;$GDFLaDsWPpF*6ZbfXLhI|9C`8_g==ihV zC38%}g?{oQv=rlu=^AgwP(7(1LO=kFI2`r*Xa^a5hVGHa>y0LMA!(Cqkqm(xHt&YW zx&|JT%g5;6qzHD1qL26hn5ydR|wSX52v_$PcSXH zVZl?X7Z$x%?I0fmQ!(HcD7oxBL-J@`;l2Yk6_o`@05C?HN0|wR<+R{?HR&gQYd2zQ z8RB_SFrh)paHP&!U1qQthFpMQhrxW&6okrXca5^-HX|E&CVZFWaH?2&O?hps{iZ@9 zo?dIpn~lZ=VNu@5)dWY3ZWe3kbV5ypYcGY7a4@hrO}P)AeI}(Wq&5yRS|OI& zds_S9?39gnnN`i4Tq_oe@CLPR$zqeCZB=dndT@%o50`Lh8=el&-;Ci#*u#_iM?LD| zXKpVF#vcq~WFbH<#9|EJGKCwWLlM^j_52vhm%l(63QA?KkPt#OaWwn^r$_H1o%0js zQ0z<(k-UgT@y@$<@BAKtJ*w`%#j@hgRmP#+*H@%G)$u4PtbJkXoq5q9(n0RCENl(- zVQ!0h{x+^c3CDOj8vJmM%^dXqOm%Ot`mJ`hHXm$!V! zjjTNm4_cI7Bu;!wLDJ+2rkt8qGC|Xz%P`1wcQ~H($uWU8hPlKys+`QyyamW1?`XUMG=Q`{2fZQRb5;629pG?%33!*(_s#yUAf&yPu=lyWBB;k6t@cKY#+ z9K5+5%TW~Ne?gsJ?>L!R(2_;h3{K;4AojX^OOowqJ3OmFUGZ47RU|exdTpa5NpYffCS-2$wuLPoAn+7A z1>3c$9_$>WB@0hH;(=I&(fIl+-Q3p+b_u1xeg)zX-V7)!(|aZ3zv}Qq=k=03jIl}` z7s%9nhun?>TN8dvZ$vsZ2*2HX4n{x$*h$#2Yhjo8&5cWz?bOL!omg$k8I~L~$ zqTZvl1XA%L6I&96o9zfPs~$)+d_`pBd#@W{W3T+-8{SGh2`EDDQ`SuKb;zc&SvOb6?u*K+ z4sa=f^4 zaeJ(@9LwfWf`UZB6BHx}ZbzVRb*Cf+f*D@p*%R~OK=_zL-3pI{3+%CE)ytD_tkSOI+#{rA)b4y?g%&3<#mMuBYv z{!qcWGTxB&HQTs!(DL6D;556s4o_W1Dw|=F!lqV1sA$xQ1NoM-2lEEa)Hs0&H*X*= zrzj-q*94jSdtCu09rQ)6Rju}R#1Z+gXQ!L$j_mp)E-|zMNtI?$bL`U{cwZ&Z)dDZd zZhStujvoVb!HZrbW*Kd;c2^+|oh{Y-P%3!C>o;xK&!ry&Zw8aUZh=-3 z73780&PX%|vF}%%=C#RC{W)^A)yMvUgqMA+L!h))xsJ%L2vUM*ThA@sC5YZ4JjqFx zuJMuluz{nQbKg99r}GlG56N=^31TXwDNTxE1SBVTZ8XkJX*yfQ8k5c%m%Q5g{`ZOr zKrJiG*h{=m)F91kMe?9Q8Yd`p1Gm%u3)z&UCF-uKlPJzy-!$v=Etub=dv7c;u}d`T z-Xp@GK4YYdi~F{h;Eh^H1dTz%VmMW~BXq{Nog;4|XYSwTP~g!ZX&H_#GAf?P(QHIY zS6`Ylk5ZS#Eh+OGx&G;XmwNKCJGLiEN40%8y->$xSkBk{XGNg>O#*Fw{Z)rwqzu;I z@ZT%Iq0)Q3hT6m5;BSJ;ZkUG0uVf1CH%x!q@!s0MqDqe!Ld>I1bo~YXu3xuet8WGuc~mCyBNJ0F%CvMtP%FG;KtKBVCtW;dVTt38*!R1J*d>Z zU6Ua|xb!h87{0+TBc9KJat(V+5LZN)CKn2e!Quy_i!-ko!$TM2R^l;pX+}*m9mT?whXP8X}R_{r^k4Ra+b~eB^2U)TI1h|lc=H_!af;1L*kk*Pg>gB7qmNrL@ z`3#XG$3-M~2!B0Tjp@A?o0Ml)C#L~Cik`0;kWfxbUZx~Y?HV*n%SgH}YQqW-{m7^Z zBRp0hK-WU+1D_hvEbLf)lJQd_+gwFR&FDaOHA(Ouo9pE6e+C~Ak}p~ZIfV&P$=M7s zA=17`LmPa+39@2FVe@{iZh+BWl}LC5QS2MmtjQ3u1#maHj*Fid zfq9)F!Cu@RX3jF(;cOxu=O_OuKmE)^&5vaf6OCJ3fP5Xc@zV$L(ZCB%2S=jC8Xlj_ z@=K91W(x|`maJ?LM3hraJcW{KC+H*=J@}jn^%uy5x;+qgXhdx9No<0D%98$QA|LU4 zI>cSey}RAX`5CB0^_LTr_=6MmU4B}#Pxs%lxHJU&3;4DU`b~dlx>6k`nQKDA8%!tW zvx&)5)nQp(u;2wA>|CBYeMP-hWtJoQ_S{(aIcS_(yU+S5A8e14(eB7ZLbpJmr(eAh-Ez>>97eq4bq3*J)?tbjR1+3b62>!GBFKkknM8fS=-Qs^&W zI`LN*AMr9-CGZeX7)sI6?C3=*SHl**upzZYuqP2Z9Ea;jI}}yb=x_ide2q@#n63##$r`^`Ji^K9KgA1nSr*wV&5GQUX+9U5yw;>)|1G>hP;;~Z)8_IWnlDSLP zr&wDe%?=LOoX*8tx3>^dm#nrv?gvuim*;&hyNQy9GDyzez*fD+N5GV*v;rrg_VJca z=WXK>CSjTfO{Pctwwk)@6KUdyQEy_u5S|=!iX&cK`?Zh4iGU7N3 z>D3B;Dmn3^kr74K!!^MNB+342*&zR#ll8xAoqs4KubzD~=2rMDM_*BnmQ9M;A#t#H zlFkwPB7Q+I+rSMkrg;3*5V3s>e&0Me=v5mhg9FIAEW^}0yN`p2hil`>aax5*!f0Ry zqc0SChsJv_f;VAX6{ZhG8gu!BgD+Gcb+mQ(KR4a!5`;;7w=*$|7I<=b!X%5lo=S1DZ-0}uAR&nVd_72 ziTQj`uXs>dmI@32q6f0zs&tjzTcv_n_ADzuwxCFy+@MkK7AI!QIDv;`qRLaTWHK^{%SvU!?HNjiCOS^bgGsMW*q z@$nF;9jev$_ostFg}QTo10GENb=|x1`~D+j6&gaqcs_tDDo9;_GC6!RI-QQnDQz*| z*xN#Khs+XI2F5I!K5Ctx_7HTczcVB zsNi;Wcyc!GSKaOE;;VP_2P$1rd3F3{%gyDR@d+!x6mQyc$(L-^o-Vl)Nm4Ud2FO6` z2kvT!WIBf(4FeRNdLe#t@bl}zoG$R79 zpkIsTgiI1B_4+z4UG|)p{`xyQ%YOQ9o2D4U=_xR@O&S2zd=KGAYG`}%C- z_H&#>*}{+WJWy9;N{L9Ayt@Jz8vnwMMa)@WkCouk9V0N3@Spg04vS<$ZE`G9+DaG> zZ^<03O86#RGP!yo9&zF6#34aWH05rx2DyiB>Nhn^%jRt_&zW>Hf-z1Ow^j^|)CZD-J zm1oHGSxWvGDcLknOVvEyc?(C)X@y@DR5Q_+Dn3=V=7yu(IP?&w?BQ_m1~=WitdVg4 zU@+<)$O9{)7pf)f@*@4G(;h0gK!F8|$XyJ4df#m4=@lB2Du|RNn^6>SwDRr-T*Yw) zplGHhUezQ*vX{GNXWF4eceqHYXWB#=>wRDn23@FjX?xg2((Qz3Li4(e87Xuonp&)? zW_OA^m3GY&ugyPDwN0gPi?Wxenm-&vd?)tb3@(GHFnv4fN)6;LwAsEDP(;dXRBUh9 z3fP;e|K!#BCaxZg$ES#8;*_)lqy#UHlEo31Nsp_{Ys%JZ)a)EeI$9)Ls;;foV4NH2 z(g-!1H_|{I!i{28%Q#%a{NUzz4e8ktLou2its+n9EhN}iED>lN!D~g;C2k5K7>vMw zAh!NYn)IcxST*v3GYxnp@(;1ba~{sqd*=Ko;r>lVx(hjTjWCD1t!5~v7~s`d^qd&2j`GZp%*-(MxFI`CufpFBV}(1GhR75 z?H!ZiT)P%!3odp3Re^Y1b-Nb2#ZzL53G>ynD~UJ9EDjNj^nP`(|JCZZ>w9bXef_KJ z|BCOT6KQmvcOB~)=>R}eZdsFihTA`vZKG@W;Jxno_+SNnO+$e919MjZf(I zU?zis^D+x>`G~VdsjO&ZE}W?;5~m!Vh!`uATXeua)zSJ`6VHcYy;(E#{>?q%Pl|VD zG*N?KQX!6r#awbo_!_p37aJs~IF(>HMKmBwe#x~VYuNVp>c*?T|FwEuef2NquyHI! zY?S?3ttS@NCJocduq^jd?fm&UDB~GQp7bRV8q-qYQpl`!s4dD1qg|XdM^3^-ln)|( z?h$m;K*DJcb$acgf7hNcZH4}WFHt;*%CZV&u^Hse;mB50)LEhvpLx0p%zkn)TH#6AwTOZyRvN|srnxTV66x(Z_ zl*cuBiEhcbpaC1GVi3b$STa9jNotPA2brUO%1sw57Z48F5@rbFKdZinc+{aURDXT9N+Cx)_@Vli1}#dhlLQt@+M9=Zj>A>Z z@dnHg`FB|ZIY4(IJ^?vWC>eEocd!}f)ERh{=KF2Po4S{gQ6~g7CDgicqIqUS+gom4 zh81kiONL~YaS>K@(jo}0!Xtlr2%AyY=3Hj9j$4Y<_KE|`33Rf%DF@(Vd!HPBG_$)# z@_Gu32-@QE;XU0O9ZOV|iuPx{^VP74NN9&V5IGENbj>UetU{Bd@0*$@XL^1*oI!5c zo8H))e7iToZ;@GSy!2Frvt5(W(|QLK_iT${Q-q*5?hlWcI*H1i>3XTiLAg_1JZ-=0TWLZblWHTd#Wk)%muJ(2_;IbJ_?+Ne{za7V;go65H`P)KTTZa0!FqBn8 zn+wa#KU6~+8e{l8WScLM@!hr{Y_bSt=jTY#PBiPR;W{gH7=m6$|B})X^nehxII@(^ z9|X4>1@O`xu60B#L?r_$D+oF90{ZvMN*D-wffzJ}q*y5SR9oF!3@qoRP8$}z_AOqM z8@pI3T3V;1!3X8D_+FuIN4*QBZ4wg*Q@VuVW><&AOrNd$Wt zE=n?_WHrft?Z$mxC9g~3GRcw^x{wRxoW{v$4ZaAY5GBTQF$v)&%^NuGcsf(ffIJ>y zSKkZf2955~#_(glh~PRC=dzaykRsHT{s2Anw*}q=pEBj$Mt4@@M@* zmlJ$0d>%Ed0i2Eb^9e1Djs7$8m>iU1ibGu;z?|6hAb6B&&fj9eCrl9qV`#Ld0?RJl z_(RTkzSr~ixduKsKRW4$L^fK7+Ee9$fM*~$V!(WHF+*Cv`sGDd@{!kqc^beBQU?39 z?l=-%Q|ssA&u81w6>Ueth8nJrP~@5*&BUm1Ax3=T@sBiy^RI&+zy4?s$=xe?41FlG zT*lGmlQ>9f&h*T%?4Fdt&dN;bJg%S)VM28dS9PtN4CvKsiGCu{hXxy^N03iPnL_e~YGE0sWU@o< z=mskMy>`0lz2|xlBg-~6xS%(zv!Kj+3F7S?=N&pDQ*vKhlk>BzGt6?^mPpH@E;jGh z=ILK^qW<@ynTF2uKI>CmsyobeM|9tWI;um4zw^FrzOeyk96v3Zb23QYbA8s$E-!K!YUQ%&vZg zATOJN3$y?CH=mEjhaU~~kI0;P3~}}zNpZKm2P{XUf44NuF|DN;Od7na@7ZswLbqJw zEyR4ZINYl(Q%#2B+$aCZi@n4dJR3_q?jKVJEOk!6Z%x9zs-S?v&Qje5TBja7Mr)2o zl_WdX)cJ+O58rgrm~O+YIGKgRdUIKlp%L)O8Vf=2!?AKEtWKNjwijBeRV-`0Rflll zHM{?1??uQKUJ=!`gPn9D7jyPmlK@~vt+&;5c`GG<{(Oq=O$+|4J~PQ&R*vX+!N)lh zHugT0G8_&x&dt71=#b~9a7r2&9N5DDL?SzyB(n*wVik!-!}^afVGo$5y&Na+3V7?? zy13G%I+N2taG$7hR{T}e6=yYvj1hNFi(V6Smb-6d!@6m4F@YC$@m`q*KusOj7hp%R z1Z%^4XpVlvN<2N793%PSXci=T6pzy$)$b>EzJ-;~E}745^*U6|iI-4NPo`=hS1k}H zY*!NW$h7WKZPtKKYyB@%Vs^cPSD83a&qF|5Lm9UJ$o-?5@%OaP^B@)W;w8RGy$j8- z#5eGQ8PQILN6010P8!1QgS^^k2NoSxdCfRT&v zgtB&-`;!l`f@0g~2-IOVJ{%J|vNL+VypjJ_^=?{|1XF_?q=U6CpRXI}JxheV2ikf% z7_Ela%Y(|>jajOrtWPZconU?Xc*#AezWn+&G~<%b8=iLNu9J3zzX^w!6a&kELykF8 zcD^hd7`+FB!=(2PAYhCK?|b+&ISSsCzgrgLy*N@?4@CsxWV2n)=~FtQb?pcQS2xVA zyfaY+?j1Cr7-LENlKr@v{ET1a<(G_8sKNzrx@xsn+pV-3*=u z7kp|8cosiDkhYhtR)1 zMvhT)b3vRyuod0=7bXSCMIP=y9FHZ@TG>lE$FjtZvXq>W^!9Ijt1z~UdalwH7@!zjGB+sVm>AtSS=*p8jN`-| zFJYO>me>#g>o2utBKH|MSDZT$ar5~@;e6_RypII(jcFCTh-W~6B0DG^)Nr^0$7MPe;1Pr9GMI3u+f^FqyP-Q&7W94wE+}uPUpZXlGx?PkjB1QPVXUxNPDbf#q7LBFEv{cJGnA=g-s_x^K;r65IV ze+PrZ9y4&@b@BW|gn;{qgg1G`u;S_PJ~=){+#@n;U=9o%H<38>$=&}VIX*1D(W(s8 z)D`ni%A^2R2!20vsm6*MzWyAAKdz?JPZGb*<^{roOa?!sLm9x+1EZY?nH|6>{hY_* z7)p(U3BXMQmE^&iAZ{MnJjCCJxTL3RG(~lYfY#oV?*p#vu@LHA`UUUtU!6m8WW#&$ z3?z=T;*|<1$#6Q`1HPM_o#Z_q#(U@QB4N?fD8c}bTR5)ysq*WNALj^e?e=4?HCj5f zaIG;7s3V}j`h9?SdF3LHF~g9Q;r?bKO|_)%fbKpOXziuV2%A0Z*P#vtQwl)jDR~)f4g}HykdL| zb^+cJBSFbSsBrAPg^oik%{)KM6+%wq`f%tXP3d)`niDXSY184rpdNQnB+9_6=JMyC z^UJLf3fUAz*N;KcD;sTdY=y-d);&s#FqPO<)GdB~OjnLC0MWda84=wsqIMY^3dI@h z0|Wo$kZ^<)ANyk6v@vTo&UlIpKQ}xp?25kBy~p1aF~m@i^h$*F$F>fP;8O<=;Tr6V z&``VglbmC*Z>WcEvWYgJ2-YTY?Kv{z!gAX3Lu~nm=iSKRw8R z@&d1J)v79gt}FAg0F*-nkH+PQNT(tq1Alr)@a(`dL90uYvXJNr6(a5bh@()gl%3Kkz(GXGbh&BVn5t*T& zy6K5$ReomORyCg^nhY3;O5TgHLNm<97^41?=?XzXYv=`7zJxVDz`;1G&Yc|iq%n;mu%Q$SUpcj z0deq^yr`1GLse$)KrTdiVK%Y`12za{F)i$Gs)g%=<3a{niNFFwu7$qPW(G>6sIc%& z-wVNcdD9WUc3MoN(V5yT7N3Vq|4<9r0z8wbE2sF)^B`G!geTS1J29t�Lurwyi|{ z0rL#Ff$O!We!%S+X{q1=P^}#gXFoBj8bL9&*GPhKMHHhiFth6{XimxK??y~_sM%-huwus!>(cKyU`s18r!0zj~1>xhg z+PXMALFy3rBHbSi#=Ys`U^YBlJClHjkeF?2hFp6WFgfHUG{t07Q zleNsdbJS*FI)$cS9F#)+@u6ug8&$8uR)S@cScnfmQ{pn-45$gn1r+gu7xfO*gx%__ zu@UuItD>#hhx`&W7@`~p!p&adA@bD0HD@1gCHq?scE9IG{Ce{I@r(V34|X=6KX|qo zR`=O={}cP}OYWk~%{?Q23sT%)g=IbYb!EcexjZ`>k1oN?k)dw{8n|cV2o7sZG)1lJ zW2BJwKmz2oZ)DDQc6hZI!CHp=58`nYnIkdAr4)P@VSByljyTD`9Q`;v|I7(fr}< z{MIX&{%fVh>&S#RJyWW7g?g^&aR&`72oas$Se6~cz#YpQ6X!3 z5HdL6ToFJfk=PRw&>KH?tPiM{sW}6t1s*G-N7536gQes=yeF5E$pm%)cX0~qAvzSd zTM%J&KBANp+UJPkvKAD9cyop7Qii zC5N5w6&(>)K#pRG1lmX=(Ixb1=TR(T%mKu(``KHV4q$+c9dz#{WfdA1q-5HyH506M zv+gNw7_yb_J7!~o3ejGFeT|MR$fTT55!?r?QL^*|-w5omhT6o9V0mJUd6RD#bac|B z?V#N6V7-CuPbt3jN>e0No&WV@OR|~Vtl%F8``loNrxOtV$>idkrXJA23rQ1=9)=^p z7l90#?wO=NTWfiVwN+*13}i18VdOjHk*s>~MC-AP7&7@a3#4$`H0-vh=rPL~QOlsN z$Px{K=Q_z)JhVskLDx^g!q)h(@p}5p$pEWR|0~@h zb1xz>!=h~2kiezv1T*{&M(`laAgaZ^DTJN(jy1}EHaO@Ekbvz5?EGqcg-fAzo>O3UYyU6Jp}Tse#EM|{!0Awg}OtiGmNMM zAXD1Z3@4nfIa=EUEkK=WY@K+h)gd1d04lvlfyR6d1rQLm`8$dk_9fAXa=4-s2^W9t zOI;7XHH6?-CJ-k$w>_9$Oh)P%AfUG6(~$a{?y7qo&v;{J?5t&gfgJZ7lW$A@kgQYJ zx7-|kPl8`-*kqfiLOISeyfAkcG1&)x{uj(R0)4p|%Qm!uHJ`0CUNqCkBoYf|Id}7; z-@+6}cPpOc=&t}LvD4tHki)n}P7*>8UuVA{33FF6oF*gh=nD&0m5gOCwBZh1$!WGs z5L`Wy4hFoMMN)TkF%hEJLhUk~&cM}}ts!-DnmDbzh5BqiOBq*}GHSjFj|Ql(i27cK zm)ipbhrC6N=B+Uj>0bud)68mBd|{jyo-4H49{dwt*0ZcT%d>)E!(W@kx4hZBd{OQ# zlD$)y!wdJ8-V1-Vt&@qLtaP6CKb#HXvuvmxky^5cVL|R@Qe2oO`N8@h4o9ej6JE+X z6F(Ci^Es|4Iteu+N=ZPOR5ED09d7I7ylJXP#Zl>{ioOdV!#D6>wW>1hBDJ6(}bn!lhYL4*q^g9Zu6{q+v6CZkJi1O%hODQ>yA3*EM!%BT~_R0P6JTc|#1 zK?y43CC-9&X>FM+Y~%Y*d6C|Rz$K*1`fr1t5nv=Iaw2LYEZ%SjvJBJ^)%B1T_Fcfs zBT79j5(z=Wj|y{%f4t?vK3P*i69Y4KF|BtaywYuf{0s>EO6Ne1>nFz}UvGd#&jT`LAs zd`RV+`V^G*IZ+HE1T#|l^cvIh$#@l*d2|f;A`yj3om%kPG%pcX@K-!>@;FCv^Xb~; zvCMJYP`uuq!&;xZ9txCMlZLHJyC{u8}c*h9|2o@6hpf}r*; zoPYd2Fy$9~nPLq~O2%)pewr5t03x)O{sj<*F?vl7i@T*!dm)U|IuBzcw8H-Ud3f2U zB?~DY*H5M)EPPGtmrCLeZ<+i8h$WbWl)EDA%|n%&NV_f9NSaOMkDv|=dw{s&!Y0K% zx)RZ8U)pj+$CqgsD`Akcg?el2-{#hAkW3>8%59F&s zF%!H%liQcjUccoDB;G4LFtmh-?9Au`+F>|Hk}68PxTc9za(R@Nz^)+&`cOW83(yvw)}u1=ui?`5Cb?bV#QhSjYrL+MGrOK zrbNR2;2c5w!B9JuYoAHOTp`*bqYMVOd#Q{0q7Z~e>1c@TukvBFgSK6aoO($U3|?$Z zyJ{{l3<38I%|~scCii5nQTv($(JzpV>=>D$5Z{H0hO2-72@bJXJ;1;9VEe)Di)~~g zK*SCk{qq9KIF!Pc)gkfQ>Po4x6xVI;UVho<@ViKxJr%3hM;$j3dz_)py`ZiF6lh*+&;^88|YBFJBAVyFC@>UNw1 zbUK3`Ga;|UG2v5)FuPMp?URGej>x`V-B3C>w1eX?kj6hJ-{f6z*+vN?hMo)#-}w4A ze?X!HI4Igeyi3Ss9XGLj%s02}v^MX}8(k0(10gcvVB3PV9Q1|4X%p50ZB9a%(931h< zCqw`?r*ZqH)Q;x%bnZJAa3-MLFP$iUaQ2i_fxYkgAFI@PCn1{?X-35^~!-*E*prc!FUC z{DUQ_fOP-Q%O{(=DXH-l`0waxt+Q3L7<7oi>3y}cDNz^dB@h3|h1E7WJDYyXjzq%g z^C+ed_AiBQ8O&>>G+5bCElv2SD0@F@>)@V659fP-8((Ppn;!Pb%0Q8;_n>N=TCTHKtqF5j!4WYp? zA{Ud*i^5qRlH%YyQE9sLoldd7sWDTlAC@W3|BmcZByPp6S`jC{R&oeB1Of>wS?mU> z8`sxC7Mi3CX&GlH<9=&rEj?9VRbQ8mjbLIeo+wVXxE2D)0Z^wFox6@O8&a(a=PImQ zOT36T*~M&3OC|mKZh|e2MD*4&BpN)gTrEacTo7;!3TCa_<9CDS@_{l%LgsV#9|)aYkD%v{YDbZF*7a%7t_Q_Vq7&5cbuy3mE2eG zLPyh3bP^g1ewGMsMH1$MlmiFC&#KLbvRDV`fPcW5d1y$b3v`eNHQA3Lvp;GM=T`ac zqhw)~p_=r#6~IKAWP(YeTt|}*#cvV4MLsL^9dA?t1;Hk!L(oo1$@kE&;X(LwF;-}( z>AvlD?Tt&)v_P}ibsIF}Rjv3M{g;ps7&}Y>tgRESibL0K-FpZ18@6K!&dZ8ir(?JC z`eom8{3MuL79X9n*4O*EL6ZOs^qUPZpaCu^vG3+~ut)!aKq!|1nK|-Touaf7GzNcf zox04NOTl#fnh-}LB_y2Y4_c@lh3?Ap6v_KUm{5!AVLyS8y(WtqZh0tS|RYz2kV8#;2 zFJCa@(Ebq&mZNXx=`N7BZy&sUwUfP6yQR=)RI?}H z+=hLInYgc`>G-)x&Sn)QnRX?t3a1ecwNZj7io+0gP$*QC|K>=G3mAlJOxM@jwWh_z zr-E=%W?W`q8#Ew5ec|QP?<6w3gcLXtL!xG0Wd(s)6ZMdfMRuRs}A#!b}T`;KZEp4O>X`e zLSC1V#$8VilQb|jWkXluV3)~6u`VIY&HFXj*wLvN8$h6``P$po2cV=|bdaXZidzq^ zM1vVbv~*T zqJyAtL;gh=Agd1T%jJKyL!U8HO{tj!rmVyU1|QT&M6O%jFZh-39xgL5oZ?JQaIAVW zvhg~!AIX=X$&Zbd+AZ!e@KE&!=%IJWN=Nj4#{0f7JU_UQ9`l2MZ{!ipwM>3dFP+I# z!)f_8!i;e`U=(w&FKOp5k>}2v+U=VUL z=IvGeq{nv?^x=gokO}WARTX0u^K{4Y*auHKs&e$#U^d*rT9;?|peXO5eAI&Y-lxd~QLJ7nPtixt&5{(R?TlgIn> z0r_&ZyScMV;6m-Nu`BC3W%P>^MU3PNM*!gZ-24jdj7h1sbKv-rMZ7QFGr z2!3GvM4jB%xj-cn@N{2Y_}K2%?WQA`5C!=P(j6F_SIySeQAlOGsEXky>t1h|-aY39 zQ(5xxPV1N$&};C~vI$UQDQzRhu^Z#I%GrkpvA0CXw#`AFlzqrYkPkU|^(?UAt#NYa zc>p)Ko&*vw>xTrI_23do5#|B{o61nS{fMFEPkse=+ACICN`@jXNK{xF=+tRKIBLx*l|R!Hy>Zskz^P;BLe-913_6dfMCVR3bs5R!R~C#dzqj!uTh%zvWJ zj?i9f2~Nt9_Ki2TX_bTD;4bJ+Qg)3r3!l#!yX+ld|8M7rZZfjBp1x9s#ZF$s)6wSp z`qgXRMZA^na&gn(ji?^1dcDPRrePPgsv^A^WhdtF==M|?|@E40)pq;5X%#LyiY99zWKNYq4hljR;+4+B`! zIT_C;4~#CeCJ%K40y+$(h%nc}KnA8J`o^q3fqk;@T<8l9a>qm*=w?0uff@K&N6jpE z4#pB}42xGP--euVS}9t_mz8Ul0H`u!c>j8J&;5&=FnNp|<@s?&3PKpjAq=6=nVbS) zn`ENr8XdU=bnL7vXSVhsq*~8!svi+2y=u(eq^j()O}4 zPF;ON`8h!S&r5gJbonJcwQb^R;T-GYjhr|^fTJ9$t7Z(Q_GS0p#mLb$U5f26>G{er z<=7r_&b2_|f%)Wp=k3ytNZl00f@TmwAG!|${l@gdaNT59I){kLh7YV3p+n;rH zi1>*ae1nKKs~oEBz3#mfX#(!~UDnP)fvC30-;t)88B(PHD78UGp?U{x(L|V_9Wa@b zjjNb$hu(hqy(J`>@S9Nh-lo{3vQ2scUxdUa33fu$bk6*(zZj~4`RBg4^nSr*SKBZL zc%cpbbw3I?o+xK>G3qM(e^$`A(pyh5uEq1=)4AUf%>xDZdNc>aCKO_}nRbKepf-7CgWh3M zy%~+)O{;e&L)fYX*bphD9sm?oU=$F#`w%k_TMW(Gjp~VnIOlyJX%lYvXvpXl8{$#O zRR`rBPzQEfiU#Nlo-G6Db#7Ge@1G7wZ%SI9e+fHshNu`B6%-VIb9LY;Bz)E_wRk68 ziO<@z&wU3O0%|to#d>(koO9LPV}EiW5AL6gXJ;tpy#}#@g&jj0xj!Q15sFxks=r_n z)!l!LNAK{*{o`We?J*WxJseM_aHBY_?xHF^5=k@dNcRZm3eHh9!`AwLIGBu1khU3O z+{p!$9&f6<&`s%|^-*s9Mm7c=%~6Euxk@ys+m=%o^HLEX5~ILKRGaEbjuwTZMtiWA&+)o5yodP~M0RJ59xTZIl)#bQ9A zi10r)-KZs9m${g}65Aq}tfQL%h;kK2if0t>(jU@~Dcdh~ zD6ieX+O;yCj2tv0F=_5bJmu}W?f<wW0NeRz^-eGMnQY@PR0x-K}AB1wv0 z_F_%34R*ugaKTzr&<~Sqe`W|D%n+P1E|*o)li#a^x+xB?X&@)eAc%2?)}rA(i$t2A zcWL1+d9)MMfyS^uY=54QccuvQpequ#=ku;0cRsX-uqwen+k(rK;c1% zM5_@N#d6*n%XZqE!Af&hdNXtME;U(DFnvokpD%T7OqT(U+CL z6g{QOKn~g37VzkKPfkWRL<=VxFG+86K_^d_zbHAH(8n4ea?f$PyM0NSe}Ibd6Ug!S zaR1E+p=Aft!VLkwmk|1okB3lj;)<|#V1M67;mH2lLA|p4lVeDLe;E$?3_rU&#Hai3 z^wZkmN$qNI#SGSVXbYujmQ}crQjU)6@>o!~6hyM`$7ciN6KYl*IKdZCheB#&;+vRb z2JiR*xsgiAF_sUMHLn~oQy|jpdYyQz|9zxu{ygz_DfW-!4*LKRvgiIH-TOeh&P!) z%X4~}0wh}{KN={sx*v838o$PJ5dFKi2O%9b%wap{zYJ`=<(#aXWoiY4ZldX+w7@C4 zeW{Nc8nNje!9{F%WSQ+_rYiz&<%j;UGU@~s(ZxQh-#vcv-M%7Yh1A{ox|jzGFw=v; zuJGe)ik)&*0S3iI`8)IA&{V)$h*40x^9Zxs&Z8j7(*YeAp_D8*0ul=xdVxRutweHnYT-p#o*_)tNim}DM1KKT%t27pdm+CBuxVjjp z2-XaxC{4675=mfiYYOcyiBTI~Nv~H!D}_fpE+x6)ev;A#D3y_O5ao>abgu4A4cXd$ zHR)PPf@qlys0R<F+Qt*HhMt}%vaFFHleMH*XNScL(Z>3Ek1%z}F zVk&_70Tu?$k||nR>YlZ~*uR{`1W&%l5#Rwa%aW2^nM3!Ux=oo5R67zatUd{S@|_O* zl`j=#>t71{lN6d%;s$!UK{^soXFY2$5yK^5OYC88^w*-ueb(gX~w37rsv@7}%ZaxSRAN1jj#1gTAjM2oJv z40qG)CuTJ2g~g+XbIbyXo>0heiqLp*b)F2TZ$gt5%#S`L3RByDan@N?m@-~PVQ)_( zFdJV5kfjz<=o2h`r3?kT5y#Ah2e}+DoD?4E&=bMo1C4~=uARW*%_TOaTkgEP2wzw< zmv04aSm7+tC{7qdtOId&ZfN-kK~Mdk*pj!(x2*vI@tacDcQymnK;1HT13LO9~S zk86~XdAQg9foAE*1ff){W_CmYeglZo1Z8+Yok79WU+LhYa5vy8q(ze2r$g5p`sM5R zQma@pLfW91Br`^65iE9KKM@*y5Y}Yglw3C*c6y*-3H69Cg%@z|+mMy3nsAk*ji9PM zl)2=GIE8!f0v~xXhP)W z*dS75%1G*EJvB}lTPC`Xmm`l}{xj<`1&v#x#+kGDDVXsomAQjHLXl65yTE7nvLG-scS4g>(!_^7y1ct^=nr@(*xC!FLqi68-K>?c`<-)fWq z)r7Wl^+PV`)HZBmg`(ycb?Xsoy0f4Ja+Df5${3YOFW4d*+cH$ z2b{9ui;@t+m`?HkOvE9ctxTgWU9NVZeuauE^hj8DELY`%H{qvo_=Y;J%K>xfq`lbT zZwkaw`-`I=b=^S$tn;{Gzk+t9*4VyWLPXXTH?^Tt>f|Zzs0`Q!?1)1vJV0U>FczD^ zQtFjKhR}{vI%PX#Vsu>bYHdlLF#5^v-}axs*nallDYCnQNTACwaw|;lBgs63OUc&w z61q4?*u;F4{Ao&QCV4yRU7XIuU?lJd3tb+xkCL}(%z~Rm>s16xQ-FCi#Pi>4|w zgdwTMnSI-G&f+V@WvogCLK_FLo1C=*Ek#5t!steb90w&zsY>&EJ3+GF7`67~$%`DH zgXgZC)SpyYs5e1>Q}f*!sPJ$wgw#KwW3WK)0zT?AAWH{Sc%!5rgb??wA=4Fc5`kJr z0$<(&Scu+_l8>|e@6e~*KMY;MsNSzDM@uEWbSy~LlJ`oDdeh1)d!fcCjC}BQQl@0} z<;m4UXi0$EoZgRsOq48bVct8G`pjaZ8Aj+2HL>D_fZce6_)@u}A`zO@^_b2sj=-C7 zvw~6j1QA-C24z)Vy@JH8h~kblvAD;RkuXyamkt~{z{u@AZLB;rG;-lb*q+x&U2wrs zvgJ+l(+Bhyb%$Y;AG&-qVqv?eFCf)%plU_x{5YC&VU7mDZ!12%IvVS`uwxV|NDah& zI-PKSF-*TB;TCtK^>y4Cd<5msk!B}+-^4CGc9zFd;nI-3f*i;0Fi<*faPHj7FKo=E2I6C$LzFMSCO!0BRQ9bioaIs4;Jt16veE;C?M8Od0Zhd#mP!iWK* zI0S#B7}?}PGwpG4yETG-2a_&k8R$YP(NR+>QA@8h0Gpd6{6#G7&%*Adp&A8qb#ZtU*=Y4dMl9eny^V|OQ;Vn}~o^z?wEeojMVUQkxT zt61Wv02oZ?kv>ROk8H@Fh6W>KafeR{vEMp-)q&$}=QZ;~(XpZLo+oxj63j&tB(#FB zwIrtuuk!)lPcpgZi;c=znOV{&_NR9Bj;A9*2GC<+k}6GzqIL|PI2ockhNSqG4vk9R zN^WW4U`6rGiLWytN_Q@LiE>zgNBHSzuEI?TS+YE(&bXq-OEgL8|IgmHZnt$D>HZ!) z1GnW_qM-&@@)cwpwxj~%1)Fq zeP~K{vr^hK?4qW_ga2nHr8tAM77)s0jqzs>Hbbg*y_S|Wnt-#U%suTXPCvULaux61 zRl9Xhz*-u~LNKvWtR%JGEsb#L&XL}_r7yanQVK&~F?U&0m_LGbcd@N6Ydad5*qVQ$ z9Whx*^c7rzbt(z3gVtemaMwh4%9KJGIXSAMa|!#fVYIYb3kL0wq@?=9yj#t^Q+uEf*1OQ;3ngMqJp+QW89h}eC_gE=5W>W|nq+A;Y60$@C5kSw=X*rWoK z8H(ER6neB|dv=Zs_251nd8iF$j+70h*|#QeLVRSIC1kitoKLX?1+LmeWT82HF~HJ>eePu2!{*j*v#(4~gT2qW(}DM$ zbV^T}dWh>w&8mch+y#XtOj67-IF>ACkH!icafKN%s~)nW*ZJlr&Z98Q7gDY8>WJo| zFujZTXacIIzHKl9;$U^q0M!F&!y=ZY7p7I|b{P zONQY0x6B7&$kKXvY=jM2D&<22G5xE~cQM-;Uv0uysUCVrXfI!Hj3Kc3$FgF8CdHEx zL8m8?oG<%lNXy>oA0b-1Q_cVtaU~06#1ZE@8n{HvAnZioITPf7MW}J02{Y*c`i!K^ z$Z5m^NU$b#G3jpDM;{P4mu6O#L;C6=dcn#fg%WpcAl3P(T4!$fn{t9&mRMy&-|QkA z&$r?_b^t0;h;g!Jrc36AfF<+8pQ~pLqSktW42`4%qVmB5b0DJj?!wFnjTcRyH7Fe5 zD68_R8rUdO1u7YWtq5584qt(KfOWs9r9PD%$QlzhzWC}}6gFu3{0eu#D`JX)l7h6r zN0X?Junew;$MvZ@55IZzeEZLjw;%5BJbD-jkyz&Et9bWe;)s$vNY*|_N@Did4Nz;H z4pLbK3<@|1XIht%34>!zV*Q(I3aw2 z_-&n)xE)Cxj3xod6colV8)|=Ni>x!B$l`-Ya?Ulu%zQm>uH*g15ZHN)Ip!qvW-4djx;bo zb9+=MyH*p$d|#Q!hG1bn2rj*fSs5B|b~A8tJ5l8Gr4vzH8ft)kpyqwbk;+AfrKvKJ zg}(9~w~Kk`K{~ZgNBoO11UkZovwzwth%GJbgizKf1ZP@Bv*z3j`-V`}#^5_5>|p(? zE!>=fi)?{PzD12DuPy1f1hjy@S$#tIVZ_Sb&;bnV}suj9;F)N&H4(fuf!b-Xo^ z&c2e`Gk6H(=6S@KAY~a(Y-01B4Jy1@GY;1bojc?~u`XE0dDrr6BoqRuRMnRrKq%)u zE`|gMFI>4AOFrX#?&v4&2dwzVqo|hQtaTUkk;^~JU>W@D)NBZZV zK77AtIE&Tnc^6Nw)Atfcrr2$ENLKfOI;8EV+2JmpzC(wB2fGS5K&}ol&1LrvEE_&1 z$vcl>V^yJU9zN|R?BC`n3}WSGgTCEDBpuDR1G7$dR5<$`0wJ*1bE|lgmF1N_t7#P& zPMgG--dY5z?m|ixj#8Mr6OBfLA-yoMLQW{#AQSfb)FgxQYqzn7_R_Lz^&bad>HaJ|JJ+TrXETH$<0pQiD#d zyh`0Oyk0xePO;;Rym%3yO7m?kU!|o7h#x#tk9*dfx6w*qb5eG3>S^a!W4|N|qcp8J z1xj*qRMi$4i54xNTKZQsh;SNYkw(BfdG=PC+{F6F6_^fsIv-2ca=iY$)o#WBa%Z9bID{fx*eVrLmKRJC)PF~)_yuY9! zhWqePk@x`_!07eejgyMkLV)~2{+On9(6OjGVMDOB3DDK+dS+Zu1l~x^wb5<6JT?1l z%Bf{q0ujxj9#fO!H2UD(+&kj3gu}9&I6Ze1>vdKqlF@S3*^#Xu*q*y;ir%J?)DMODXvb=bin1C5bU??{eu2oz+KS5>#*?5R$ve7_#^d|@JO{xH6^!IFSO)9!;?NTs zNbo_RBRW{dm$#xMf3F8bWKfc)mT`p78O1al^tuy-^~`3lifq*3dhMk+ z4&gDq9NAx^=Ubtq;TFZvi`eNgfAX zTVfIq1$?jP7Ji2iA}#k?JhGJ+=WQ>d8= zwBjS>JPBRt1t@llOvC@_#898Il*h>my8XnK9+KlDmgSuHwrg60ySNZ^h)YQ&5#dnO zk@XJwp@a@Hg4s(RSf62af%$3U>FOe_@dFuazFzQIEwXJHppMXp>Xq!{pTvWL_6%$5XIdvJ&*r`PcQ||JH7v zAX~%1B!~oMP8#LV0YNl6Q7IouE`GNVUQ3MN=c-e5nQjmIMeM=n!~o9aGhaq5HSv)sI29cDY3Ds$%Z&K_ zAgm1`LDSQCprz1+Xf>oZ;E9`t!N>9*hTOKbT$LY5p>p_9pJ*h>S4Bb+azS12j2@C$ zuAXG(TFGUbh|O|EGQ}4h`b8pHC%s>j_%BN0zw-#*YC0lZ@nwQ-=odu_Y)yHdJH@rg z?reH+e{#(KabHf6P(68hAHGfma^FBQ>hme$_3Sb?X2#`S>=Y-AnTmLp?)h)wJZ9Fa zrHM9m9Bf*$*)VGxBpdYOn4S$%SQbqZCi(WxXbck$9qosBPV(QY0awe}%?$6&$ri1Y8J>Uu& z)%-by8tJg$tAk)W@N&ZakXlZ8jq#&)ZJ0?%`B+1@tpmO*_E7E+c{o~f*U3?7DvaEZ z@0_*laqS&eo_197u89_+u@spguo>0Zni%H<*)5>#LfG+0|>!NwKC@k`&F z(x-8qV87>CX=%TdO{ErbJaw&z|1N=I%en~j-V$NYA_jAkA2BRpzUIg8C~Umo%avf} z`2jX5n0Gd1e`CpX`mZNQ?&d^H<4^yDho3IvflQ3sZ4G)k`Ny-w?z57o1Y?i<6ja-Q zOjoj&?R0FN@n_T~ZQ$4B7_CcpdA?3NlPUu4o!4J(m}_vO7o+nR7dR$!{)m)7dQ*#o zS@6Q^wF%!t%SP5WWlRYIRuLNa^5R9k34OP)K8#YW_3>_*`j2tr-?%XZ^w0X|eAxy+ z^PNDW!6jfN0{CX_1z#0)19>1Iaylg5JAxwYI?<7xYEfKrF$TL^j4=%Rpw)n7#en3G z#YPm#Sdhzi6$aozxe$%e#K%?VTLWnT@`%-8iGq@KfkXsrlFg&}7-?LvuyL+9F6?Ac zM^Mw5F5r}bmw=KFeS{#+}1t=~sF2;^5 zMjn72P|xqfDIo{QYDHp|;5aGb;C5nh|RPCt}At8d$|fy9Bp@!@4i2W7WDh9<$5P3V*Y%=)lJ za56dWVe2V-*3HfB2itq!Za=*H7tDr%&Us<_>L1Trh3%I5i`?kJTn%IFbCF|q1WG-* zERnSRW1pMg&CWK+5y1sWSdQ%;+{N&G-0Co2I4Bm%>o|yjTODMjUx!Ky)T>V8C_}DQ z?wdu~-hZ$U#Ri66q+LSdh&O=4teYhS?tpgH`2$Up0P~)wXzTv=-s3Ax&s`V-XrLuO z*9@|=5+7kkw$AjLH11(wB0igp!7}ohxCjY|;Zn1k49oU@A^ai*n~dx|qxkOL&f^_i zBXcDzn|V{6d0V&o9r^i0*`qME+Qt$FTg6mQN=* zX^fDU!QTnf;@o)8Xx`r2d$e~Y90%JmhiQsA=*w(Jl`d5Nah9|S3m>gvQVrPsn7|&e>24niSb11^ocY{OO z+cIE~I}|YJqZ|M@tiOJ=zr8#r$Rgfv|9@csMHPsJGw$=8kEwYkpF8NEf4x^7iEifJ z;EntP=8|1_7xMl&?A51_F3xeCl6qs?t9;|PGnBVB7cSfO7Iwzy<^X*{M$7j_U4Az_ z!CBh_{R5W>hV@SO#D9(a^Kdag3OB^x)%!7a9#yUn)(BwR%98XdA7m=RkP0>rTS%p- zKSIWm=?mUXepyu0SqNATShc(CU^>#vF|1nMg7KVrp8+$1ei3>`;GlqYY1|Cm;z2s? zwOcXTK*8y8hXSq0DHDO_t-^#MhCX@ZDVb>lCSg!oQqmE~P+M-9`Jq>9;YMPZQ;_c#`Mjj} zv^)R~V*^28*S@*g#4&0plzN0Z&}+|aMK*3TeO00b6yuE`fuq@Q_{v>(+J*Q-bOM>o z-W~+rjv62S0xL$D6(N z-+pzo$FIM=`SS{rlUSPiz@IRDK7MrX5lUl;V55p@#=rD36TXO0tp$B_X`k<@!;UofBBb#r@g001oEe6zrA_dTmR&%oBHt6Q&h(FH=P$q z2AJQ^Y(QxYQabSUm4oq0Vs{Qim7>J0j5>*0`d5*Ngt_l75>-0Mzk&BI5>UEq8SxY^ z9lB~|ZDZ+LO_@mRN(jFCPbB?isDy~wL%oa7q9^>-qCt7N1OF1mE`uKgLmLWp=cPz! zY=%C;f1NvY&BEUE&9p!MfB$y^t1?ai9wIB_r1QlQo*m-R`k6htL+*{Jc*JO5@>ccR zX$$|3(3w%^Ygp<=eb)Z(^%wU24pjfa`imipZ`?RML7WXnFZfRcJA9~!3X4*`a|bun zE9e2!tWO4z1cQmh)KvvVLn{^YQ>isE{YkiqR|`U*QbDmM3Qbl=8BV1FMtS}~GguYS zEmLKCIyJ5u26Y5K@p!)9@_7VgrZPp9Za#Ml?3@i{I&8lT^8)C;=BgZ^3UN%{CE zGCQJ?Or|Zn=6ulwErPfq#mTJT-|C^Ma(Y|_T3wx+w#spm*cUnuGb0_xUq$DOm9Jt* zs_ope>)|2^2E8Fd5@9G^Otx26bRa%JzUWj5@Tq)&esCj4j=OD7ersVbAn zX5EDU=aZf7$BYjsW+GKArA!{|lJ4La)V9moDt+6Qb3uJ8RqG$G!p3!RE1_tuDcP?s zXhUsKVIYv~oVcb()C@+tO5?KBiq5u*G;Ml9>K-k4xbX{?ps<=-=qS7=t%M(KAT1yI zGnxr~n?hf9?i!2|tB^4D@T|)FfZ-m_VwhqtXnPy5oa+qjhS-YS{&L=OGJ<|jP+opmNW-FeAK(gke+ZPy%6xYS#f}*a*YJO>V%I7+5$PRo zco6t1_dvswqs>h-V-|E`+xQ|cPXNtR zENP$bVH{>SrI#Iw?B0fNRuCas@{ zX=}(;NY$Xi=6CL_f!VU36o(~~Se+dOc0l&5+%k|3^sJ{5lxIq}giuW1XhQl+Y_ori*w~%~&SG^>&%hRLD`0|V2t^ctD zP|Ze=i?delr8Pa8@Zv+cmo^c=jU4;HM1f9%t23zBm~R}AfwUXb6tZH zdY&$juv0+1LVa6bj;y)9u-}?Yl|p*RYu_ppFs5XwCO~ss)@-u#L$jDq9(0ns&|R>6 z)uG`C#!H%cYp4j+&t~T=@M0iW2fGRKwcsU~O_g|g0ps~oFIWxvw+!-@Chrhf@Z z4}s=vOU`H`Kuw|zrhS|(#$^*-+_5tmgV=Dw90GFUF|hsdB_w26+ky98YsrOXC|>0z zpFm`k#s7tVC|C6`ki5%lZKLkPDBf!N!_o6VQ4hW`4YYZ z)|;?B(=CFxAizpKA(PG}t1bds!`!D}3?2?2-h z&PTp3M8d)$ag1Xsa;qo(B5(~LS}nk4ZMzx>xR{M%*gx;B&{YCIi9ikqj;rt$oiK5Q z00v<;qBhYHW;D~*VIYSqbg+Zi)YHK_az*oclOIOoKdyh)>DdHbLf!ZZ;8Jaq{fsAO z0lgmLZePSu!chXP4bg%_p_Bj`VCR8dXpXF_c*7LK3-o$4xtO{B$9PObuT8n2lr(qB zkmK0}RKw6csM5NPgolpyhgZ=J|Midm@_RX+0TqU6wdB&;05|V@MV3;dv9%hF`N~ZR zhvctSD;eiGk1w&E6LP^ z>VjR^&fhs$=~2O}(SU5z<3&xssSNL6ACBUKyC)+YTm#9(Z=0JhM+2PM)92|8DDT2euxUg# zr#J=>>*31@LgTqFGa}6i*fqZ)%>@tCy9>JRVzObRSowIiLfzXAiHd0iNk2#056VgP zk~4|&VXQRwsgz>TnQ)!msyiNy-pQmv+2`wi=-9a?$shn=k z(H$#S*yNOY+*xLsp@JQ&6fFhCC3u`@{F!@zm$nNz^olrbMTBW4(h}vPDIn9TKKfrX z5-lC;6M|wy%p)U_M~^amX|6SZfX_${~sXEvTy9JD=25D`;sHW%%rm15DRca$nOY^*a(58N{yz79D z7hdTxY>w$w86#~3w}i(yD1$5qNcxZV36-t1u;AKq z!*+J$Lh}$}!JHr*9g~(p`IYv>0!I;x^CO`_+skCohBZ$JAh8LhRj3QT1?J7BY_oZQ zSPe$Hd2^9r`weaP^rg*S!5hIGxhDZ#2JDO|gbIN8^kbxu=SE$0f~8cKFs)gy)j7_c zkUp&vVC+BQ9Q%|a0WK3lIeg^|+k{BdR2oPgp(?!zhBSI*#8A+|IN`8{`C!o;-A&M) znKK+%vx&CM7yNiwJFrp#D7tjaUS$zKQ+Ph0C2@nrPuLI;i@~x5dORG0#x+RDiPRff z?;zQ>B*if#U|`moH^GzaByHTeqeLyguyUjg0ZTJ_LC*}yR=kaXs1im~G+WlX%x9pA zDk1n8Dj9k-iJTgKf0UBY5O_Lzhr z*#teTNa@t`sY6K#LGrEM5%116^ES_KXvAB3`%SQ20ccK=w-hP%%3LX=8=-EFgZ1M} z89_<`3==!QnDV729tlXX=K`WVY~?oZ#h~0m=5_HPqy_7uI@uIQbIB+=H0IDxIe25k zoQ~z#E)Y>Qv$l*43rfTa>B-EEwxZ{b#dmdK5s=OaWOz_r6}lIcH39#l*-Z84ecVt@ z+VF>{k90n-WcL-2qBKiR=mDWA%^C(rjh*q1h`fK;^-ZHwMTpy9Z$Y zLd@iCWy%^qPTpI4u4q1+oA%o&gPp2kL+#%TA7I)i4?65fi$tWUg|~DK|zDQHb9pDvG8k5)I*X1_}%L zR@VEBw>e6c#F7WY$mr*O5A+{z+?VoL702xv@kC6{wK;W)J@2q?%YnOTXb zA&x#IDx6mtiwx<=jYSYAK1G2pR8n}2FlkzaHT=5 z4w`(mKA9e;$DSWzYcS``vlGekk<*3WMjCjl&0vw3U=dYDJxons>{a?wn|kX3x%b&m z^woUeG0i=n_TEOc@NDCI>giov6$zr>g-is5C5(NoR^0al$JI>BfBY1j{}%&k3G|pP z^cR6^ft@dz5K3O-DsKCHcgBM5mo;Ji0-#*c1|bUBC-hHb6 zPTQ^ekR0betX~6d76jTrlZBoOJq7u!u^T#oRy?748NPfw976>{er3%#6AIqLNeH9> zMxOP(A@b&cPafRUE3J1YC!@p5#l;^XEu7p4bnxU18`)v_eU+*^)TvKSu2uI5E`zy# z?a<|p2OKSiTTyeR3KJ~RY=$a`-@}c)$QZOl!HW~5g;~_xzD(z`W9;rvqf zN8?v54RDvrMNYGles3vw@8Xn68>OIrFADAtPr2kFq_GvpMJNc(4PT3*4*mTJ%#HB1x*`o$!9SX_qo-0Y@$wL1*axVN}z-I2O# zplPdiXcuP6`^2^?RcmD1*3cP_bAday08y~ewnlhe2$^o6pE_7!saUzT=B8!A7U*<| zx3z+sr-cDjVX1KOwsuA;wR47FZL|;}Z4H73Q_0gZI9H8=M%30E){^K@p`bOG?Cr6e}HEgQ;3u zOZU$XFP3N&3;h8S8MHQob&ktFT3_q#y1n{^D2A=o2ar-3kc^^epmBOJR;I@TN7WLz zh5^2?$j<-Dl68dJ#0k$`Q0V^T4U~h{LQF_%3PfueF`RHwp+psOobx@rNL1%I#Bx1| zRHJXh_>0_~Iomj9Zqv@uNnfs0Vcdt}+-TeWDD&)7ZIHA2ZIrKdf8gO*aZ&2dw=pAf zdX@!(E;~ZtLqK^6y0FkzU8@b2S-Wyp?Vut-+nPoUGA`GdjQb}pZw9e;lY6LUglx_e zkFBzX-T#p&hw8`RzYs)4F%>|ugnY9b7K@@afkQWjh?b&kAyTw`+;o>okfKf;u1OBo zO0K-j<%y3|#e;Sb{#{kEP;^ic2SiDe^B46Bj<3C}77V_q<18fbYu4h8sW}(7T6ITj znol~NPR!yh=AeN~$6Y(OI&){|R;QehaxTz7DUU0-=e60Cw;e<9Eu5B--EJy3t0=wI zDX~~0@K&dZvnImIb8UV+c!H%aYL?T0y-*d3FZG-94Ver*MCGgtC4!bzv{8^P8!H|) zTAenKiAs%!jcQ7^>_ERY3RH+y2Hu>7M%98|S*>`~sL~);R%$%dYE4@{g>(vUrxzrF z2U~c%|k=1c?kl`96|XQVD-S2iglNbMu$Qd-s7SSK`XUy0xv!J1!*#s9MGmH<3 z&rV)3aE}EMhKn&WssK8l-pX|{neep^7sx^vl)bZaTyDTo98OLoMhB7-XJycchxuh^oMv(oZ{puRfJ?B5b4Db zCy%Ec7yu+t1s>~l@Fa1Fp5x#Z*J1}g(w7`8VwFId9#V}ijt_BrfdKzpXMh1GP7Zj9 zWYL_h5Qf5682vXBYQm=PX&kH%85cV-T#Sf-_JxgR%&>uiy^oB0Sl!?JrsGd^T{0`^ zeR4wF4p5$-&8wz57QwP*!msSe3ad)n(o$4tqq@fW{8;@=9Zi%>Efk8?G`sfFsiN3k zs-Z8p7fqRg33KFl7z|8?;Gj2?MPz2OWS*1Zo&xnifBz)NEa-ZU%LbQC+NfhcVy~P5 z5D{ogjEAHXy+15aorpl3Wp-0kT_fMrP<6mLTrBGhsdJ{I-Kc z@nSQJ&w9A}qw^cR%|)_Jn!o`nDOr_p;)FFwMvi0W6o%xxaY~Y`%~#*fi?8V%o;4 zPdir%lNvsPUEQ95J2=?v0UcVqX)}7;)G->6w(EbbK3L zumCr?3@y|A5wCrOxBvZ@-Asw~U)Z9Unr(k;l^ZG=T3{M678WJ88z1u;Xd9{yN0 zdyf|2zx-SUx_5*u5mR7{c5d4!jJb0O%bQ`B$_!7Czed>gz|`CvP-Ff~X6gz|Vj?PW zYEZY5^4e_$g?Bc|u1{Baoo@fR^UVlqA+DAl4-gB^SXeO>K+VHr-j|o0Py^IZ3x|D@ zNMsAj#e4zZq}J_wv=Veq&PV=IcO6hMp&u9StIoTr;y_$AE!*OL*>;PLc6_6_SOyZ*(7H?Wf5rNGwt$xsR<<^24T z`VOwVssfbGO`|}L{5l|d4Y@ENpFF*<&=i4BiJ$ME9b~T2;LjMey1L^e(WS5Mh2lM89;%ek=fAV znhCBZ?jto)-BxyxaxYN7l$FsF0O4U`#rO*dC30=S$%PC&qF zp@T?@ENn?V4XxcRR$?2*0>ehVg}cbhIV)X@-d@%3c$L<- z;EMFda<}AFT7iYrynxDBq&EiVvb7a=nPV8|$WTcK7j$ijy?ml|3 zi#v$-p5NR4{`rGP_qMx@7#wM`f+@e9FuH9gt6`ar+Sh z&5>Vg(Ce}yukhaAdGxT`z%Z=u+FNRfNv7G11D`7F_96{s(zADo_c6qpC0tNJ3wa3Y zrL#?GStF{>ZqedaBIwg+rC(e%QBHI6aidXa+(su_Yf_G1pMpQ$>X>pG#x#5SOoAPr zX(n@ea)v*`Wg;#sZj9ml(blkc1y_x`W=x?fOqz@YVfLI=8?yma#+`+vmhWZ|lGfj9 z9~c>EjM*VNh<%IxEJ`f6Lugr2gCSOQJPSaCa3`kkG%!QomaQVaC_;}!uQL;{8asr& z*=R|ya&ld?Ke)KS2jK+76_u!+#hNIzg4d`jaz9FTz@-gN5EIiIv$bB}n;Nf$s1g7Z zbj=iI<8$KZl2d+U$f1C&Bx7v0PlRgT`-rKEFJ0*CixA*)Gr4+3kP2&V;%zF`%BFo# zkX@M$gTvc|9rb=OXAY5x^OAW7BOde~GR%3lJOV*Nk?b>&Oq5Qf=PAOiW{@)M;V!-0cB_`E}NV|&qFJRij%~Nbbs~*ADjN1=rb)%TJ%t_uE z{?-=G5;IlKO~6;ed##y3!%rmgEsc-LH{eZBzQSb~7^SJAp$~#znG5WrZ6fk*W2I;| zZK2&%9kfdItrFwR$pw5~FkcC8kr^-|!R$c+qStydPIgbBOH8*+99s*GTtfNu6agIS znVddJbQJMs=)sFr?xEmBE{0I8SSex`&zy3N2YjW;b`-f8*G#5W8WaC$WU7Vb6-s_| zV{lUVNfwHBS8|M!5gVrC=!0*Tu9gI`=}_5I)GR|?vUaS6*u`bpJ1f?Q78=3*HkEO) zVqC8A8)k3|`8$00pCgXCSlW}GK295OPX-vE#Cz?Kx4Ta;o>!|I?7`5 zD&$Bxk~`?oICvZG);>A0#17idHzJsXnL*P;s&VBPBVODi0FA-*m?Z@sZ~%>dAX6cl zkkV|HMNKnw%&wdbDi;LTKgv0=+X_Ut zsh*Xt@r9%ckn~zWBx(aD5#tdjK~QS5ZVp|QHprzj8F!J3MqExTflEz9k!KTPd_#^H zxlt(UFQhJvi}#=mo>*VI=6b+5MJH>g|G*=!;Id$kL_k0*ANU783a||degk3);ZA32 zx%0i1^hMjZnnDfT@^s$^3JY+xeK>@i!8Sw3l5Th0(UX{CIiZS~X4@rY`gqz<`_!8X zgX!IT27EUoU6PiB%GPe{Y=y06(!woqV&4sihkD&FX%I;<^u1m~Ne|2-tsq$<1j6xF zwM&YKB})mRVc>|}bzc(D3B-H?9}l*#w+ZwzBuF zlM@nVHqEO@WQVzjj8p&u=vnaE<}W zQi1|Gp{R87xDVjY#hM?UB~w?k1!tZaC9^Rn}#xIJm-~c#P9>w3u7=~=r%r-w7S{6G#Fk0 zw~94ub~o}Nn zR5nIoWfP{=K8%9o*%sy!^F~rUEol`LDjO3<+g9lErmYt>7;?v@Y=pwKF`sdwl8NO| z!%yC8zX}ufX;sl%j59#EYr>>u^Tsx0-Nd2^*7VNS08Sh3*$6*u$Ri;}GvU@l2_0RH zt;+`7?|@$({x3t(?Sv~>G~=xjey5@;LL;q5Y1O3Cylu!Q1e?jR zOfs%uRuyG1vm`Lkpr<+_B5y_PKqUDR$CD+xGQl<2V%!7ln&9KB2fCcyCV6Dek^)H4k#E^R8*3*?YQ?zpZfO~*qq|5w*M^u)+;xk=1=0UdPJh? z4)x9YjuO@T(Tb9t6r;D>l%#Z>N7DZWhNqWM`6`^IO{?>0lpoYkz9|U@g}+MhIFt-! zq2$6$I1%l-ur2eb-r>vs7zg^PIJmV!tVrvfzaS9i6nB|pCkc737o1+4vk_z|_LBur zAJ;puw;7jaH_ESt_b1^pSXxw?aUv%kN8a3&D`X0CD#S_T@yZOsj{j0upeY}?S$u(v zV_qZCmcVpU@fMa)lPEb&#x~55QQZ*8mG*49oxi4?FW1!5u9SO@W16S<_S10Ceb$69 z6232_CAhaCqQE;FNGey@Qi`>L{nXkbI|7L%N_E=6V!qN!2)dem-GDfw_avGHiam{z z$1k!0@R>;9r#>W}Qd(UN3ox@xkZsg1HnrtQ0I?VuKj{l8+G&)z^m(@}T-Wp_K%<9z zz9|}2V5z=Snof8G37e!{Un7aJ6l(xGc zlr;eWj8@JYWo#n6HSk)`3K&1Od?mg7=S{pb6S?tj1Y@LRyB zgkif_{0?KYv6f>p3QdT2)ecIj-lJJzu!VOVwY1~nC26SX_gI~H@*jzu(~hvpcruIe z(y~~>Ae!g1lg2~5vI5vhM^g!2ZWADKB<(hM{nS+-HL4v-rez8b@PEi9LMiuX!?tK> z6nhtRDxULlng++$7MJJub;wqS!rm=iv_uL93gQAwU7Nkr{*S%SfI6*nmyta;5q@V@ zu@rF`k=ByXkjZhxvpnksy)5FS06i2s2DWLU+JKK;kQJuLDAuC~#AY#6jGhr4NgSVbvt#i&A;4j{t$!AV=5%fgfAVyhB8Z zCfzqAGAyB^xNoCDdiUhw7>zuhd^1HjdM_!LVlsl5*A5xUS{lglAaTZ+%0!CNeSX@X z$~Em`ZNLJiKl2QP0qlrFqu*Iu8&Aw#DtpK{+_VF_UBu`n!rILjb#%v z_?likFOg(wqiP>d1<8RiaKaN}mic!@a=9ZeD;jKW-6zsvv-2@s0m868hBA*|Iw|%; ztcLxQk3C?!a+bvesuN@-u>Ui$ZIOg zG?YKwu-33ibfLV2j2##o6&*XsDbBYuH6^fA)Ir&Lb>@~$_Ax0{kIf%dO&*yv)eCCQ7Vx@d-^NAqT@x^!u`_AYGC}MSbVnvt|!VCug zN~jFgVK2O|IX}H`cbA01Rnupcs@ViTnc8d2FzMV!1a=rfuJ_WMEwst{7@%wHV+WzkF!Tk|5#=w`XzLYD#06lZUrogrCIl9Ap3A#V zy)VCPXscDY8$IS?S8*;_Uupo%(s6b0%Ua6cz5gWe{6lb{k*#lPbJQ$zy^TxH#s(= zJkFU48HFDz(SFlN_x3Yq38Gp}+9{|#@%-Ypb<2jsW5U^{9KRRYo1?KfjEyGy@S~W| z0;^B~EN26c5Qwn=dk35};H{Rl_^P>yWEon-?R2Ac})nNh|3}0Lv zliptNB*kS$3dFC6HZ)F_kAoEoNP5p7u%RqOcXpY7;kl7*dI( zApVo}N>Pg;fi(sIKLW4&`v4eix9K=_kCA5=G5qF1k?Fv*nThnEC&@?&dPj4pBAFSc z{V}GUVZqQFeS5j#oGVy_vbIHwQSw%@7$(O@I7g!ygju}ih;K*Z=W4l+1T9i8tX#M3 z2R#iGVM-(7C2MN74y>sZ?#a=)ni?d4TQyPd)sjOKZ>TOHPu zfNwUuxw-e`{`T{KfAqB<``pZs$-?O;Ayi4~pcyeh>YdKs_SXKRhnqNwCLU3_+maF@ zRpOCossg7 zH|$&r5=Z%yf`ea4F49lqDEw70W(%r7Yr?FW5-R4bXicEPd5d;=v*DG@B~EP8`@Eh@ z)&X{{`}Ub6y4%2sbOcFGaZ(ssVB)+alSYI<@P%a~x0P$&NYhWApb_<rO z3f?ex;K@)k$1SfL8$|zsHEE@jW4POzU`9`-ph6fF)evgU5=fIJ|UtIGHjipRwHHoo1joR4>01caEd0aj$DS z6$XtT(H*^(pzDkAAy1}ZIO2G_7pF=S?j<@W6i`~N^k7psP@Jp>oHkC*Gur{E?Cg!n z_2|G7prRF#tHf2vGc`ns-~w1C=a^EckpJl*)3un8Bv(}b)o=|b>Va0SnFQmqwE_Vh zp71bKN@|!#WF%C|A=Plo7(>VFYIuT&g$+y+m(mTX1vlIC44|T%JmVY(ZtuH44_b=$ z6<1W;sbEoC8nOgL2EK)#<@keE5=!LCR9T)(OeAp7uA1^z-_z+Tiny6}5TVvA%I0j| z(m}4>#wEtac1lIxAJ=s`HpowoG%=KVMMGacV1HR2*wEHWf$L9ARS8q&&lLl~I9(Zd zfukpG7jMN*;QW(I4EO9FGpevGiW|$@tY6xotb= za1e+#o|A0Y@Dx~$z~xK~Oh)4g8T7*ZZBZ;LuL3VaxbFbR6lL3v;1nnT*tngbPW{aab8cGKkl16LLgMNcWyv=?u-J%Q((14wdr6LIx2OCLKOCCus*m z4eZG*M;NOqcz(v4*Au4Wl}M>(F&qU?F((^eBsP~*x@GAwW1Otq)R4xbr0sD}d4(h6 zVOXH2t4F8XbGjY8BM812H?wGBVMl+k_!>~&XKpatgers_Nd7#VhFgzc(TP0>Nn9> zjckgrOMrEh0MCwnsaULU+Ybv>*ja)9FR@2qfwzQU&Np^&H ztn4GVJBBR>de?9@$}4}1-3fVvtw)R=yQVN86qFo1x#AC52aW!;qmkGHT_c~gY>?&z z$cZg8!%x`fq~Jx77ePV-*pVbTEPEsXaAWRFM`^qLC9c z6{+TE)Arz^eRV8ztKnz$lc7RML4e!?X}&rp_YJ%Bwc8j&(AA1IVbT4h#lG(&7b>Ib z5LD|x3(09??HJ9`*Fh36kd*b&$AJLR1Tm!LDs4grNtT>AXUxEM!b8{8iW1@qlN6Dh zR+7zHxrBVmh@qC{r#d@gmb^fr$>QXpzcDV5%5sj2Q(|uY#*8L{%4W5yb=Mtv$r5Hi ztJxF*sJQf#lD^ozaNA1%0hXKol(|ecIRfNo#yu?xF7ADigJ_(AGmS#NMcwrD0)`WY z0bh99xKFT_#a@FOpJnj}%IsJ`4CYZ%oBT=IePCa2()5@7ubk8w%RvDiSoU1q_YjhOeO*FVOUxaJf` zlX3;p%g*c&Ne-r?$*dgL9ZRei)@ zV%LpV$Lta zCoXQT{c1orUo6Er1V&qFB4IRiP8AR*x;0(uT?toNSU5}=t}u!6lMwL(uCDSO@*r*- zWWAfQk_QEfo?$2)DQRgV@~`ObOjhFJ_W7&fCC%vxXN_BcLgKK6NI3?I>S&OWL!}%% zt_^{81#fs?MHImmWZ|&F@pDN#)N7hzaj@?G*5hv;?L7$IqP^{JxBm=1lO4D9%-(IE z>R>-bbSq$fRv9BpN9oF6{4}3%TGG^f$X6!`va(sag?lCJ^rTV*r;SF~^U0YTYVnQt zku+wD2>Zywksa>VF?zJ_kc-}x+nnrmAORJTfdCnUDk}0p$6rkeDNMXf{RJA0-HJXP$stMoTAn1#_78*}al<^qtEit-|;3Kq_ z^boGCQtEsVpGPp_MNY<+naY!}VNYe5KCy(cqWg401)dk!*I*C1PfSOElrr0I10<|j&)FdJ6~fuq5pU-IqT z2N_-^;wx!}ENsiFeq6lBVx?yzs$_W=t zORVh_8&f8LBEPsBQd`YUx|mOT(bW6NjKZx#^{@kJD#D#ZQWepX(kc!tkX4G-h|)lO zH1^?#Y)WH)B^n`S#O&oRom@bLB&VhH)T^`9DoR@ioioTJk2JLS5!y0ZZaqoVOoGAq z(D%KK!Qd;w=@HeOe&H_>OR5d%Uj2S+Qb|bLWLlmQ+j6cqwj=Z$%cL{LURyWQ<&@Xj zUV?JWrox3G9C)>45m4}QhR5AtKCIS#hpT<}hDUwa#&#u#%5uU$y_Hfn@~~CRd$=Ep z%Nb%Ij?v!gwNQ<>vfVRw-y$E1)~#^D)pnEa%ZVy`Z>z1~rL`lOVWq)LnCNm;@3?Lh zG6bDdQ{2F<*Ua1X2Kk(^7J03;U?Q-3E?6dYfMUp~CEmXR4HPy)(G=a1p_$^Dd^}Vn zj)+sSA!Nudc|!J*?8*dJf*`TYH04s*_fqa#JtIw(oHR!reG%I~;R)wIB1!Dp&ysA1DgWdKuekLT)BRmjN35CJJ6$Zkt@fsb3UW77;}^*w&aO9b4bRcx5C7J1G~8n<`= zWZ0rIftMP^5Hq@<6x=+a1uW#rYus@?;KY?PzpL+{OvZVO%2I}pdD><|t8FB2BWoph znVnQMK=6+ebvTldY*d=$9>&XtCql`LFPfs(mO_$#mk_UJ z1?pC@>7oK(mQ~ainih=TF**zRM$*8tVr?j1H8((9sb;w+EGy%19{ED`vwGg2y(%ln z0M($;s5HkDDb=j47GVr>|FFs4WIUB{67rx{D+y4bej@O>!{M6h!?P~8R#E?pw&HTR zB=M{}V`S|Z4YsDo7c^KVk*yElXO?|maO8sLXsI;XBCZ^jl?7;)TC(ulC3Avt$~2_h zJ6VH?0M=1*jHV~*gVqH1OrTBQ{jTy{5&9~75jS@?f0u-tkmeIflE4y$N?6UxyxO8m z>t+pS>>ke2ke4K3jytT{LU6RqY5uN^O2<8rf4x9{nZVdvt{s8AL7yI} zKR*LWrCXyF=CxYfUv1DFxX(!EcTpkXbAIA-(O=mtHHf{|Lot=+Wkp;H?AUaaCf8C( z+(!%o$BuFoy$=Eo{%Ld?78LR0hjsE)_C`jn?pDBf_;Lu31{x=s>q?buqk#gcz}V3* zNo&o0EuKlFPVNzbeyEp#Mn?>eP)#pz?PO&<99JaRk_XUa7Sp5G@SEW!77b}aglf{~ z;3leI*tR=S@$5NSR#7ADa+;OGt9j57N}ai-7_JX0{Tt&Npr&#YNP8x9u5e$1EYk2I zwN9taq~Eh9q0@=KtJ!9JbLB>ZvR}d(UR=3JF#MA~gnVV__F_?!NpudilbUE=G?&C8 z=d%GsBjHMo{+fkUr%y<+Q6$%>(^*Wvlb@ETF4Cyf04j?#z$pqW24)!q67WQ|h~cGq zkW`Q%*d9k}Ph@_Ifb@ILywf-Qo@ff?EB;<^WWL^ZOPelXYVswMDC`)_m|?n|+30k1 z(oZ5Udt)S<*|3d1Zf(I4RIx~w`vEp$pH0>R`-ucjyOaUQ;kKc&;S0zbEMW3TBjl1 zz9-}7yyRgtPTTwoO`(9PA>oUO6?`@eHCBD2$b8`}8bSd|A>C_$ltmg~6b0IWsK04l zQbgVrm4rCDw&le}7jbTuNk0`5sjgBdkG6$L`7T*N8zy-2GOevPc1tQ5ZVsf#Pi@BJ z64)+=m^k51Vp)z&o4QbCG7yf|MPh6*4r`pj-;-rm+aL;-Ok62s6}zljm(936R}n6Z zQ|TN5w{pFbxG7*^pGm?NxGNCaoZ{9kDS9?LT;dpP8Z$VBCuh|Gv%9O&qecB0Vq5gq zraqZJX$?#Wmk(qw4O=6wk09!C@Yz7--}mJ zR>P+In)~tU%B>qeQ~Hw04@1p_Y7@q#x8f0bXfaCA9Cud`uMH@JB&{?V-nEHFAAbgA z5U7iSZa z;Iu6_2bF)X#>#Rmwy-j9K4)P5lz%It)L+lpb~oG0pTu8D`|cEsti8=I$cz?x4)1gV zv+N2?4RlAW$Z?kJC`WMUMlpLj?8^y53D4uacCfF*_8b?wPc^+%EIY-Pl;(IGKRi&7@ADI^TvGHo7GoV~c$#(&*bj-^w8o(Zn1Y8mu~+-RC##-%84A-o3^7 zblj^K$6Em;+Dsg0k7;u4mJO97S#$u~3Kwu4;O@io(djU_zA9I5u>$4dkl7(6e`e{t zNp6kAKnD{l41GCMY-04NKSF*tJ66+|Xo%6|VkVIjG<{3TDGmw7nk4d{J@d2t&=(9l z%twW$Gnx?AXKXNF&ni_;@h?X*dx%hwgj2jyzMVi6XC+bitvK8XD+vV22^t8^Mx$6& z$7!~b5K^s?sHd*Rn;fkmKndQrL$OOwb@26~3%Pz0XTS&Ndg_arvYh#ml^ce9~ z;~+E`^(tWy*NV@O*>&6&e=}R4PDERBi8Bo&u;p~cERB_Q;%>S6LQ!Ustb>Gvx!>Ev z)erSWgf~3zPH#xML5mcPwW4t>sy<%X^Zi~d(QfbJ7(ToeIu70~eM?%PAu%L^OK|3v z#-{a|g7H0Dp08weZns+`%i2lb#{`02XlWLSFE|roxt^8z!wto$Xj!Xrfem8f-K@zG zKOfkVoLCCulDVoC8RK<}01P1mMj9}!gjqzM?A>otHf~nDKztI|ophV*=yj`v7d6v8 z!3_miGuq#h{n(t!fs3_P4ka=+=R__O6Lbr^tc5!)H%u81ty-M)&Vf)Hnu(4j=~8VB z&WT%EiJG&6#lOTwXoQedQ(4~mih+;jU!-JYskgeCko;;^ysc(5lneAcg1qd1Egpt>;pfv0#=tW~> zoOO+G*{_hLCoMOc#Rh5?iWP#fGk}c(w zk`f{n%2TsU0IsAFAAp=#(9VUnZ8-d%sJ=v2r3O2S<6m4pj>2k%2T9$8lE95+A8IU_ z=wk+PdICC{J!s>_=={Y6w%0J|-0y4=BjTryXz;E^I)D=P6 zxouw<_8RD%8AjQc=JY_%v~=LK68`I>;o}SJZACsHLkEsTA+iVu$mnl)fm}=o`$G2~ zZVUu+ws1bcQ=4?({+DDz`Udn@zkkXL zFdO?8meVkBH2`HXSprj)Ilb=N-dA6IxpDJpf9>egwSRl|_VZ7F?tS&;#@|+NDv5{j zg8*APjr6Si-R3(r-`MVZL0)&;-TKkD%C6YWDps;3oL(#vyVjXe)2x!p2qQ`$!T`;Z zQqor3n^}SMgpU|A%w{qx$u8FP5>nNEL_0`XkITl_@G8)>4F6PY{gI8#-IGHrb<8dlS@{87Q~slqRAIc#Y0PEYgl=JxQ->aE;`~ zTK>tVGEb^3kXbvGzN1pYw&Je^#N4qKn>tA#V>73|Kse5Pg3aQdTiY$kQdwS=*OwET zoW&?}i>G~ix+f9(2-$}f22uK&jj*2we}jw6ps?nLG<1}}VkEaJc(Mp2mi#`rC;edO z2sRq)QkskgCHNq5DX=#@9{$KYrMYF6d;Z50ec4-Wwp&bk!Hx6A3pQs?;SwNHip?&a z069sfBor`Wr6qZ<7H_i2uP;W>V)|%VhACbd81Yq$?~F0ZTS$&@hJ6GL|DSY@PbM#9 z9rNHS;;KFOY#>0(ooFYWDwqi+4LmJrPg}UF!LtzQ(#l(H3+P%sMB+$ne?%WCrkxk1 zJr5%3;NTM|SKW2~E5hop7nAd0bz(8Ip#vMj%G>{1>ELd}_U_g@E2}?`R@!F4OvP$) zhX)pE8{&~Q>tqQ(gk6Q=V#wU;lCMd#bz7FR1Vd38{gq5V*!)Rt{KQoyK*=iNw~{&w z0*@fLhi*;|Kei`Z8O`1Zr&-xLAxXIHUy+@pQAyHQgr~c}+W93y1Tf9au~M32<}H}4 zr?x5E8o&q2uwqT~3ez%<8G33z+q?){kfSTuYw+ktcz^)g$)wCXYFwCi+%X9{&ylb) zxFPJaw%#=P7PcGZu~^Nz@FHB@Lj&y@s*c8oCl|7KQDZdCz`cbi-jm@>e7U$>CibW8 z+nRLiSOA`VpTb1=df1jaH99O4Q6<*mN7MUo1@e98iRFF3bGS+|Ks*B(^0S8#Uv_e5WKr2k7YkwKrbeO`Ob(!@nGZTqKhdn6>`4kbH#wf0F1LFqQOceYOaIKzmQ* z#KS#Ft*mR#u6Kxp70#Th1yNCwJxt(!2L(s@vhoLFJTYRJ@zQ3)*s7<}%E6MNDL{#M z!A?+xtZ@d)zXe=6ZCseOHBoZZYSWrO)M{iLxjstrn838=3Xi41N}H6-K~yp_P?{;- zQ^eD2X1fMDUL)M*PeW>l$ebFalgjp0Tt@-*Fp5N_P)u|>yS^vNrpD6irh`sfjxx1f zQ#DS+X6LD>hp&+J`ads*NNTEErGx#m6ZxHx5s4G`7Nk=(&%4MzQ*fpF7!M!x5hXI5 z?d3#?j^pW)1Z-%vHS!I2-~@ECeHh-txk_>db|)q`Q8>YuR9TmJqQPh&sm3*kcL4f0 zJWp;3VspApX@|L74XmT8DmlMx4VKdUlK}%~Y$yH1nNDaSCmFh2TVB?nWb1{l)dD#2 zFYcTM3#qDC4)$t0)-cn}orl-s-**a0%aF$*S_#^H<*7{KcF8l+kRrjSF^GtAemtLaXc_)Qoce@5y`a3oAW{;m$j;1fQ9^WbA7O}fBl zC#jW_a?vk@F|+E2Q~cJ>XtqtIrWx}_Slwa-8uG7JZ2)${?kmfORA8P-GUMEz$kS2J zs*}b3uH^d{R$pnomEbcg^$&hPJ#XP5SQsD-ZDjOK5S2-(2nhPky+pIA&E3_yrEX9*tSte~=CGB@9LRQR^Ag1p^2hv}Kvva$t^?2_eig{<(pZ*FNwY6y zVDx^SAa@@OMcgM?X>LX>J+!hjSc-5?a0GE2x4Of@QoJq22*1A*N(&YfI9xu;3ddp3 z(KNtc{NzvKFa2gyoA@4}VbZ(Ke2IN#LX78*H7~aLpN7azlU*pN;($SF$}B#yKYC9u z=73u`%Ql8|-aOlh;OX%>Iys%-N|(`LaC=gT3Q0``0=WtZ7bF%<+a50}#Si*p=#*1v z52seNWlwer$$8(S=H$*?SU`H!hRR)*&(EUG%&Dxxyb}l*d1|Bz{v{&sOj%pW0zywu zdunLB8RQRHbAI9|O1(J8krP@E>czkX8lsoCbjvmEU58o4t~d2$l%SH*)cXOz8qms^ zrTU|znymERU>XB#99ygB1VzL@@vJaBf3KPGES;J!U~Y$Dbp=nOg4%=oS6miamvH%JpF;Ut&lb&5z5jjwX4;a%f2A z3s%pg(J`hmLw8X7;RZ$;`osgC`Q{KfF(P>nSARvTp} zswIXpJ@yabp%1P&HqeqFpojb=7YGXAW%fkFO}F=!18h2VmG1RJo@$lD?Mh6LW22TL1IWbyS16o3{t4J)(j8@- z6J#RE&dzYmZ1hvBFF0Ab6D#Vx_lgoWP&!!SqefG_9abTU%>!TJ|1MXAE$?atM_lt| zR1m4)`B{}_xl*-*dGi~|WN>)WpUoch&j8>{SbL~2;F_?>(Gm7bur|{qWUbNN4mPRe zBWzEsq!IPm8ygN!Mb~=hDGnm|$#yj54Q)JO8A`y0Z6+yt#I+*>?VR>4HNYpNnK4#MON5`QOT#>8<9?E?^Rk!amjciz{+hixKc$ zr422Nu(=|%LMU)mv8tZa-m3LGSL+F7e5Cr|iX+7Js>mA6i*V!Z){BRU(hr~oU3;AH zrLsQF+45z+#EgY}sP^QFV+H5sa!eK5$g1m#?PJpf2csGBgzy5K1qs$ONCUwi<$x+| zOQ7!Jl#)euHSZuF5l>|J6Oi`$sKyD*M{wwFwhj z7Ha|_+u{3sbY|romGR*<&`84|L^TWq!7kN8SZYR)4VPB9_Qp#i1sfN{m{P zY7`@H$XAmYOKc>4NaZZ0+Tz;n063|nxzi_8v@47~AkagYQx`&M?RFbWGDFSVwyr%{ z;%6N?JbUWVvKYx`Hz34$`-f@;pVsEfE6yW=g81}rcK~l>9bxJn51BQGn~TPAAsd)K?N8DoYHpN zPH0~*Cx)whh>N5{&}Z=9LX11=}h}K4Uxv)QpotBHR`mmrQt~uQ64vRN-Kd;K=`~LB5Jw6IozFZsc+j=K` zY^k@}Xng)W)QbCjG~QirUS=1^$5{OEC`cT+odqb-T+y>wa$hT78$cj7rskfi7Eu0GMAGJI}#9X%!w?A%YZvz`N-ae)U===G`7hj#dJiBpY193l}Xv_~&=8>34 zf;_2l*WwaD5>lvlc(e16`S-Sv9RIXG9(TSN_x0-?|FS+9-e!aR{QG1&7G1Igyal{M6D&KE5TtU#DNzxQ)mcGK zixp(P826{L9gx|-0|o=9%969%@#6o%Q*k%|1-1G=E?`^i&t6VmcfKHNTmNZze&_fU zC$N}vLdeEzeK$NgMQ)7mE>2H}C!H@i`FCCpPhMV}u8$@xxp6~W5uL9IB<}G;A2`Z8 zz42DoGV*GjBTyfczKT)Y8vzR>$ow%Uv=29B@n$q>JR(i`L`m@^{Lc7JLJ_!Eqm1{_ zXfSpJU%x^m?SNjbepy0+D+)z|K{F93D^(9cc>WwlF0_7ec-{;SGFY%j1yI`MtxnQQ z(g~PN?Iu0rQ933vq!iyWT#CK5+o63clOjJUHk$CgPeJk`j+Oi&d{iCc8+VAnux5gKef@>UG&rIIut^O^=7lG7bC&?cx|Tn_utBc?D-ccxYcG z#!Mrl*Snj_-RZbKnq0^kN#|MZ=NJeHmcUZC`vD%gC>)7>R7WxjfcBvC0FJ`r>kOcQ zD;@0PrN9jtq>GT9;R6@E58xJ0fFAbgZby7w{|H8zj$BsG8|B7gR_njOO}-FO+FlQ0 z>rJCMx1`CzB|t%`2fTszb!QrTOKyKt6~m*+$;spmojKr{*oBz>sIU<@vBFt=awqFv zR7p9B3TBC_CzqxWT4kpNkP=LLC&WOck3{ESaVL#2qRJ2h`qS`h;l;i{twlY79#;!S z1%@rO`2s?ol3994Rt#&BN;4wmxzj3zvgBy?obUBudbJeW1ZGY~uQ)>|!=v*FwQtW+ zfIw&_8g`L+3(*FzaFM~qG@mK9!Vg+9ogUZC`U+5PthX&a4?zX^Wzm={BLe@KhWzQzJzyz#z>;!R_D_{{NWFs-*o=Z z#VKxD!y%fS1F(_EXS_+`v1EcJr}45r^%bu0{+IztL)=Ty5#gK@{SFH)M52>C%2Q4C zp)JK9Wc&?jhC^a2+6&eNv*0w%SLWgVT1vToXvkYy@51wEzX?tTi$%W9IrNVU}06b*KQ+gMC9B# zpUUT)i>=YidUyRrA6a~A3vNMYUbU^yBytJto`;5UA`w#Y6gho0o{kb4ThM9X^LmRc zg-b_rGKASD>=aTc+%vFH7jh7Qepgus)COXBCybP^+IqMb|X^qR%h+=o1~5II%J~W zGF-kc$6_w2E~Q#G1v#K{)i$^Ar9y!jTTk6-DhVhBd5Hap#(0%u@ZjlxZ9Mz!#?4Q9>%YCZ`tzwtUS{o-ljIG0 zv~j^$acURQJ^hT=(78ZOh|N&|^NnG^*;Ux}hS1e?>#;PuvJPCbhzc&#%p+F@Q+t=D zGB3l*mxhSzYcN0pnbD7zP`b`&(G$h{@bVaXuBK47i#ag`qv>QUPWFJlga~vxhGG`9I3#WziZbjcCG$gkr!4)3GI ze0;Fd`S=s5p!{<2Bvq*L zLrhWN1e|ElBj%_L1<=ESeM3-@&M<0!13ehkGdqZsOXd`ZmcX*P&QS7;FTU8_d-UhO z+<;n=>Ljz5H*TP_FIRhmFArAVe){p#jRSn1ee(04I){VK%E9VjMZP)AP&&`v3~t`I z@z0(8Aq*8bGcuI(H%av0T@}7B;I8D6Gb+6l9FWOpG>ieR<7xl&2I?M8PT?;abk<&X zy7s!;xxInt=M5T_JHNaAo6r74o7VWoKmBvZ+GQiOna~?0d;1Mk9UztZ5C$wsTBpHe zutPC#n(VAQyWj2JVjD;w0D#9sn#zz4Z`vQvV6=lVhJI7bi9m=qUQeA%>z(fq$O5|$ zo1ooJ(rzP&;9|znp?_){=)(XAcYL}njm+bgcFrcah>1J)>OHcy49YAP$*6EJRL&|w z?dyykhvDzn{XU`mY|D=;_IPR>S%G8dgD)o^`^w7o;y=n)WVJ>C&?AW5^1|4%qO;MZb_7Kbb-=y z>b|$-+_oDxV7(qrkLWY~S{g;X8qBqa!vLK*;}U1t12>wg?Hco1h;PrHjfX6D<-D9dX$N&J1524*Fgmv^QX|s20uJA;8R%+08Ep+|n8P{5|LI+B3V%HRrZ1{L+(8WwA9O!WH)k58UpWKi8OmAf zTewn@$%nouLsiz0aL&?!PA-oO$MP=jdTl>7zdbT=Q_~ZnfV30AuNDrH72MvbY8qBl z@XlisMhx?xHOfL0zQg!95gS4lxaBUj`8woS(9_I zl=IatFf5_Nt%JFhygs>mLxx-=YswVO+1c=rnaqODc#dnS9FdOgJ9;|WBD7XnBr9*_ zLUFl^V%9+b;cG-aAnn@m1&z`1W@Ml%pi%(APMOz0VynuwF|mwrftLXmEL_v$w;qIK zJ^`D7Wm(_#sfQ0B)WAC8#amK7&c2QbrlfFe$;u@=J(yA^XYClaWpyw^aDepibXBMIfBJn2W$PzBz^RSReIH5=-tXqlN z38SX*GNm%Iw6M>BoEb|O}vK=#_8sS$xPSv`E*kr0-T3?Yi^(3VZo5=Tcv ze~R8g5MAvfy5+}0BajYQxiEyj0?Ijs0CquUJtr_CZSD5U=3PR1wWV<~ziB8;1aH_n zn?Oujx8igW&6=tB5@DB6qIaon=IcFe<}pYQZLHlM&071j9-0(sH7x4Pg;ss9-q}%` zm&~u&sge3*a;Tz__BhHp$19C!4-6a4;cHoRh|5SJy>zN`10* zEks(Y^U5om0}4)h4%Ht>;?9i zkRMmE4v*iKE9veZRjtAL?VP(!JSK1^RF{)Eq6Ee88TgD< zqP0OlFKenCuF`Cyg2uL%V!bBGQ&1VWSS}uWUk4@=y(z|^t|?;*qicdF_-{(GU_}ku z)`wqMKI(*xMqYEG#QAJvJx$o#q#0`))HFxW;f$TTv0X)B6_T6aI@4ZVaAB=ovZuCWq!>b4mu|jo) zGYXJh6rJP3mR8~}HFBvdF*$_=@VWKD@G+bUGu%;`C7}2ib5>V6mc)1DM|o%EVbyZB zOOv70&OKRrXUo|Hmx8C)Cp0dx7E;h18c!Mm3$SI)hR-i>nYg?|127tWxBL9b-u>s_ zJ=%YqENV`WDm`lL*}^GlSbObu46PsAu9_rQd9s?g=Z#O8#RW~oO_mdfG_ZfpNHd0t z{r>akh{J%70I5gO^3yI(hfADU_Zcr(*_3Oe^vxOUGC1uw=%!Zmtl967z)SWKU4n%) z!aoVYZ+5=!&tN!*9g{7g^BgP_XWo=pB*trqForE-Yj@`suLeb=CVeG=kXV?g1nFbP zoS?q@vB}Dh>jya^Em%3dHp70D9NS@9#ry(e=q+B&8#^j2aEJ`S6|W=@+#;Y17E}Q` z$e<5Ri!n6%QmchnxQoC6W=z82hugWyPdofxUzax*ct2?q>7C?_))ur=(6cuWEehxA z+_T($d47IIKwC$n9_ZHB0Gf*vfQT)N;8pTFQW)z5KJ*z}THSi~^GN7=;@ zj_z+3Hineo!^y?DH1;p;9k;;LG7nr7=6m5{()SCZjAs5LoVwsEf@_ur8UKAK@AY{;^C*KP_Xr!=UHqsFFnVOC`yGh`QEW zrFsQE79Ne87nNtUhyLt+TS-9ZBebj-13X_T8pxr7+V%gEkbSsAf@UHv9(!Pi>$zmBQlM#Kc-D?K~^q zi@fLkR=y-7$MoIYui>EA4hLlt7+!p}IKpvv0wIsRfkhlIt`Ihi*9yke+nlqcN|mrn zrt?LBe*w&Pel662{4UDOjf33_{-Og#5VESoXEC@Dm#!lK2v^HPKuI#*umOWn2pi8B z(ftjMKm5P{JAuy?;W)eu0m-)|6ipUHp%tLk zkqb47`c+|Rv%DI=P1?m*SR`aVi?X$OOboN0Lb7f;N|S`eIjLP9 zc&ohG5XyyJVgVCL&ZQwVc57FhL0xZgqU%K31f$2dH){eycKHAOlG5JW&7Hwt7s4{!uW_!sWnc_=xg$e z;$_AFSSowaC~oAzg7&phB(7wZiodj=sc*FDKq_9VjTm;*Pt)>k!LWl+A7}yd>>eM41B-AcZywZ~#)WTGsh} zUhKZt{k~Xot119o+{b;c&}|W@$|W)~GBP4EA`%xZR_56Si~InwmuTLIGYIoB9d7)l zDuJv$xT4igqNxk0)R$2@3>XNCZXGC+px|I&1;+#7&WjZe2*M*0qex51&LlX475VZ= z>m5Ot^ilqk;H-6^L>g?HZCLxr4lctEGPU1qR1Lw{S+S^}hvm`afUahMwrBy6x3Qw2 ziv>4pvwr!i*F$Fu@GhCuFB#03hJE`E9fR`fOzjZ@Z2F95D;>f;R3mX3=7El_NMD!_ z<@lvCJ`${OGz^C#CXLLM+q}o%mdI9I9Y}bJgxRkTPVfA<#N?uAN@D}&4`o&`MV(z+d+@9-0bG^`>#9 z9;3fjRGBMdJ?B@TLp#|H%TyP~Y+6>w#>%d8>HB>`B`I5kT^k=Ivw@NkBP za<2ooP8KSjd6QmkO0DOnl@S~_Wkdsm_KU1qNC}tdsJ9T47EHZ4Z4Ld zc|^goRxT#ptGz;i8p*5Sau5k!b00;yT!k`N!pOHmj^`PHt&?Cgx6V5Tm1*Yc1>VvLJ2Oy{M!m94Fah@zwh--T(HyFF6ku;R^PQEGip47hZ1 z^fLh19l}6xjKEofJ-TCPgTGY*YI@~|-bCWW*A5>Vn{j1{QzT8`{#_|SFsvr(g4ois z;)w9b{D+Jfvmh*Oq4nIrhAYE1Njd2_P73=>ezo3rl2i_B3Uw!%QrJf*P~)@?cOrKY z2n=I=7w$v6M_>gB-{4wP;Zl&q!^I9L3c4puEAexZ41GByWC}=c=15_~!aF*tK zCio@+A*y)ge#Dgxqi&Ub|8O`$qP^kyqw%4-aqvPRBCzyHZq^y4=zAr9RC05;$wpKw zCDpY7BomD+*OKY*D+z}ZK>1t=?m7_OoVwOBDk`e&aqP%h4p+cFGYI)qgQjdv=FZ^<3Xc2>Yak^Yt1+6J4fX!t&Bl!2H! zWZ5wB9h4NLgNOSnQsm&)71(4AK1r1i6YK;xio@#@hR;B0bcFgOLwO37CKhO)uhJ3P zh9D5dJ#FQ_Li@GdM-a><30E+JO<0c2%!YWKJECjswAPhXtMwIDa~pmWU<4^R>ue*_ z+OW0gbs}~aXCS|@CRwc6HdGjG*Ib4dN@21cQ;xu&E=V(dNn+wH$Ej|j4N=9*l@+LZ zQ97*mWi=JaN_$p_1XMO05meoe>46 zi8y)*LcJkfeL;$J7EvzF>ry1dN@yUhJ1ug$qh*wIdQ(&t$jo?K*N)vC-HxM8(Vzcsc1IPB;UzOmuKT zN#$OkBr9T}RYh(Y>y)g{h70$G;}~)H{_gG0DlibA+-0QM-Ouo^l>DCy z*visYm%$qzEPY@p{O8_)99qJ=6DiD>x=kqyW(&Ci*H%CXakeXU_OH1Blop2B^&G>y#3T-;USvL(} zcs~uVvX08>V8=%HsW58IB#VOu`LV+3$~1yP;jAl`)-@lghtCq0z@OG&D!A$NF{7p^ zY&jkp$TtBqiehc6*)(BqJSb@4OWK{a+`hCEq}A8&nWdc)v?L3-pO8Vea;*v9&;r9r z2G}+%1tiqCEQ>N!=eltTcWK!4BzF+%nl3vELS!BM@Cw6+-Olds)%L@?fc%esV^=<& z+zIYI3pj*rSO9__G5X)2ePD%)Qh&R8Iymncc{@j*=?jLGIS7odzU@uN|L^~3Gx}@Rf96+csoCX0mQQ1*|)LEpBzVmVLbguT@7zeiP!AEFk{}E$ParjoV!f z_+P{_-e!Mt277(D|Nm_tRs8A}VtY{7eN*P$HV>JUcpdV&DNmhZ=b{XEnPghOwDqqM z-#16hxstuOdTJV4Cor*(8}F}f<9&oI)nflJ2^{*2q{Vw&kATQu&|L+A#KH!;X$F-ISF*?Be|pZ&^qYToB@{jK5Seq35uF3V2s zIO5|;=Yp3t*cR+JaM(&8EOOG>xUob_YM6Ee&Ak@Oz2{ZN$EGr$H40S^xQ zDru>xVMG_3XPkO@|paK$`tPQ*Y*_0W78GOj^_I$XxSw_Pij>gOaUO z9Mu1E2~zG<4FitDEoDng*o>?xFl!&0krH3&!W{<{24M+a^7%zcn>~CB$YxeZML4Hd z?a$#QP4nSLn;x-~L;#g*x#nkY3U(bKGbbIJd8n~y3I+%Fwe27!5%M8-`;I0NE7+OjG%rBldu zHfjAz$rQ?gSRMsi8Y>3&tP~1m3pyB2Il*)Z{{)y|iiC0?o*iL9Tp$I9xA5KeqxHSb z`9z^s>~ICA?`gjhlCV(}6rnILLJ&<@kn|ZjJ^TuhkWxc}1*XbyVwjDFlop;X#v^dH z2CphOQw4=O-p%@JBaASlk~Z8Kcp>r#t<2;YzjnN2v=W9?@{Ta6z|6-z{xW-fmM>+d zf^0it!zp;y#sUGi+mrF(U^>+cR>sIP>&NJ#ay#viI%@BzJb zR~$hZwZmMi+neh<{{DKl`)$PjNbE}tzX>T;i{~Mvw!HdXCC-pvHF$Bwjjjz&c~Cy`kkgC zYiobq{Lh2+-Gj$lPd1;eKi#Z;ZZ5X*-OkSDvpp}m_3ZKUWw|t+;L=JUmvP`K@Qd2z zcO1E%2*_)ToTz6ruVF~;ap(yCR)uERPsF5`k4|}f5`US6n-5Jh4(OamC(&OG z(~I4XP%jwalZiaLNUwfS+Qo>_Cj6V-*syZ;`ixG_`udo;>X6d;yV3BcciXSez}|m) zCr--goed8UU!RWqFn>#wZCjJ~{`99mCG>SUkXCV#O&zR%A0m$W?esc;S;Gl%Hdl>H zRuZVuCA@Y)2p!A6s{x zm0nkVUk^Px?8z0-5T*DnS@F#`E82$q74}->0FG zXUj_;PC4=H8-Ju`ZNLIu7_`RUOUW0Xm)9&cVj!>I;S$J)o~&P%@#|SPt+Mn!?ZkZv21(MILvy18LeziKQ$YHq`Z1-4(oq;k}JpWrwca35hL^WD= z9tYhu%hUupCQVakg*jng=Wh^eamBP`3#2mB4dLq9%;IQG$V_EQx3Xk@DPmT1-O8|v zKUqTsZcJY`=_T=QT0DeH574fd;nl1}P1(B4#kG`@RNM~7FnUWcMrkc21^|=H%^DdB zX0EeAZ1a4SL5r|zmkWXSX-O*w<7uK2EDfh-wE=NDCtO<#Pcw4Hu6lrJi|Pq}z)B`A zo}q@gc>3JaYNqxXr0vLUX({eC%kzerHA-1(YLx}$x4f?NL(*dLVM zw&`IenpNsO!_m<=#5s#;{}D{_a&0Eo@A}@iG<_d@y}m2v@^m2*#X-_QkL2BC$E6Sw zS~uWY+du%c3NCwqNI60q_;z(zSBzpb#bY=yCr%G1!!x}qRt_TgOpvWbYu#{Vftm4mKwf94B;0y&Ftoz<{6&nyhIB$SzA;Tl;=<=j-RYo9U>uwaB4Y?q7^( zw{5}1N2&RrJY%#=vs>X5QxwUQ3*6x2!q?S~l!G+;Y6vySRFkgS2`JB}1;CO$X_b zyM=Fe^CVk)f78Nho1E%Gz%1DecU7yFwxa2k(!-5hZb=bLW*sUrcdt!bTE<0(>xgvM zi^>lW+R&I_#dn=O&y5=q5D3B!Ij#e^wRJ^d)Rdo^-XVJpac>1=@00z^kxlkbX=-qK zcK)urBo$tCWPx>F*3O5LDCh4+u<9a*$Dsc`4~RE^Ivkvx!^GR|$i`B=eGL`I*9`ZT z&T0llnhb6gyH0`oz*4Fy5{I4ip}t|u?;+m~mwtbM13zR5!>WX_3lgOc^v8kt#UL}- z#gyjf)s#3BDbMNLkuI@S*fJfBQ8YY9oNKhX6In*%0bCNZGKi2#n|WxD=}GHiLf8|7 ziJdL+^PxKA5gv@o0fE(0?X(@qigv~)C$Eqk#xW`jCzCUM@fG`f&b*`=61rh-`bcYy zMkNjy4X3CgWR9b{zEZ~$%PVOtC1?41YJZ(Y@efwe!fH`P>;Ld#Nr3n@tQDIJUn)WU zjj5bS1^irXh3Igz1@cj5yoSuUt(m0eSu{O$6^yI?HONGn&teiiXM6V|cGY&H=w$pi z>>lxI4n`=TLu6w!ip^I8q+A;+wnmzmO`i$E@?l|T_n8m6kY+n zTr1&iRHV$rLH z`Nd7AE;;!sxtZ$>5+Woy)rdAy7e!W*R&c6Js!DR_Pipj+XLnA^m*&Gn%5A%-t$PcO zJ;J~uFG|;tCt?t>di7RfIElWDV#M?e)wAF^{SloMOO$?g*=ET#7u#-Lqs@s))2^>i z8UI+BZK0`R?tfDZ2YsK5I^S8G`lC#|W!8`zq5qp4%uW(yY7?xoKkcE+&fN1&Rrwh9 zOn$;4n@2Q;1Jj@#g@VTS(&IR3gFRTGX2V5P|GC{HP>3ME)TMqFGxiA=S4BMVm zpm|2tP-2pl=8`y&e2sbD2VNp4Z)ORQNh=JaX%iR6+=cyCx;n#rXdFNwt^#7>#4zi7 zH634oF0ofhK4VGVj1UK8@vLC32{*jAatg;x&0XI*H*QeFWZO>GLPMYyn2jX?rxz#4#+YaXqdAR{xoDWQxz@j)sOqcmo z)>v|l(+a!gKTC?_YFBXW6F?grY)hxGqjL>7lrYlyU>?HC(>o29REPHB7gO)6J)J#U zb6i|NK|uN?+OxUeQ4%0nMi}#&w)qZZ=7bT}p8(x*8(NY`%y0#BpPL+D(;z*ztb#B| z?@&Tmbd~D34O<|*>@B7JS%i+D1)n6$x^c>| z^S9BN4K#3W8z26-g*43fbtlDUlfXR&7q^}l7YUs33ln#0FpEk94y-h`%7-BqJ_BLe z)z~MaMjW>~Su`7f6N<{_kjQcptG{TPb*Z7VomI$`hVW*Qsn-qEXFk~~ea5lZNk&NW zJ7Epjig9n-383h|3(N}kb=>sk5-x}?-1`n&%bQ`p9v$xdq+$E#DDiP6NsULr{1bO` z9Vq0`Ymt`j{M{xv3J6+m+N`bmsF2d&uf{ddOr);ZuD?w;a~-{&wa9gfcKgBfoFPV{ zK2*Q`ZS_fI2Qjt&YiBW$n!^-vxI)tofzkAtf?Mjj`FwaChx*`jFgYG{1L64ynrlTq zm6fxe1t>=P0b{iW6CAQ`RANoy;KMlB8e$}3(Vl{jl!K&}4aXMc*GsY7i;i*Qm*RqD z^WaFRVVgi4!f*&zo#cpvPZKEl)3uZQ7-kAX-{}0Pj?K=exHnxz%HXWXBN;sIemY$) zJZPkYbPTrTysV?&;7})ZWeDBI;V)mIu5v3J5N4B^hB78tS%hO5<1h(lN&l9tAbaYv zbP+;Rj29tnqvLX8H-Ho=LCpxES=pEjjecpv=p1Ke8?PZX;pB6I;5~&Y;=zcyL0DE% z>-r;H2$c6>5H?r|7X$~VZj@7D=kALaYlj%v$=b`8@GuHBNo=^MC;JWX!*xH5V}O0Q zf~mM24IeX2%*!#~gqt>^7*?s=(;Jas=yBq7_wckg}}lJ&Bonz*uvDY?Ujs*4Gn?ra`l6t0a>gi8c!n96?!_nSdKbry;8 zn(vhW8UqXDDU;&Pr+hQtqNJ2Jb9O`uhxNE+b2nIs99<;!9eLyR;1H?r-@YEe3NeW+ z3eH4K)KOa%wv)a>3fh^FS)Pv;z;NKhmEz97GJ93Meo#YY-T8^s8E3f^wPm7($6%6m!a)Qg`)@#W#=?WZq|Z5QT3{s6h5kry znPf}+v?duy0Kr1T60xS}-Hc0I2d^%UXCxzWV$40EiEZ*92@;5q73ztArMMIj^`9jh zHmCLgq(QEW_=gZc5^t1oQmKkJ3l#TFa-A==58iGnx*G zsgu(mQ7rvp=EIAL9F|6vpm%sUp2!9WZWr8}r&4QGicKz%aLM?@qFiuE8-Qd$>WyMjJ>yp_YQTeOmeP6BS*)D9+?;q8DIwsM-yC zj$-L6qpnO9tT8#;cLLi7@5+U`fTIbYJi-pU6uRrwc9eX09Ro`wKJA>9BXg)D=8?`{cl?Up zUpO-2@qV`hK6qpYe?mZPrku|}TZCA6S2RJCyu`|~x0U-iYQn9y<5BMf=fr0N+=D6H zI655q0?29w-8yk8@Pg^Mj8SGi*Wd9L+5*tCz6PT*-NEpGS2T=;AP@oyCT=0Di^>q(cfL9ko z9JxzOzldVwW`cKG3rA_vA0&DrCN4$jUvhwnNs5eHm<2x$bN&$@d-iq<+fIH5e>c^OHQ z?Z+*EzoHn?!auv6Te+;>xrN*^pe4!)VqTDq!sB{G;_7 zp>9eLvh;(%uJZ$-F|5`|WUQ7D8h?Vhh=77K7)WzC+e8{gPW}D=9au|NH6pGP-U=fz8|R5n?l zkOOb4|DN?fNd5O8TIv^5U}P&T#<@xgd0#aWO5j?6Xs$poDG>4i1ck0x|j%?>QNO_o{6xnr!-#jbrci1i5Ls zZwx%hw91r~UUiIo5R@WdR1t9#aiSN~^YJMzr-%HZo2T*97WU8eVIRojXvbia?{JqE zI*u$Vu;9>~sV@7aNzMx7$JHetuW>|yq0~2~7#m|n^<}}c50ME}ZA6;%Uzyq!YbJ*4R&CeY|Fa(p+|kTWIz+51wxA zK3(72n9=ihqyAuWL`DsflcF3_9%Ch(4yPi5T&?qsy`3iq8{e+)w2wF%hA3|G93Mic z9pq!{xENh=+~4gz{&Rb;PkSd^As|DPTlsVBatir&Je>|-LGVG2#xd0K!*hJsEqy^) z%y8J={dc1uM@XMm$-bJPHer%NdlH&eqg~z16eMbD8aE8_bd_XeOtQXUw|S~)7FiQ) zDAenUnj(^W`nttPYo&Gb;F67q+nBVdS+Jv+tx4<-8fHRB^JxsTqqAu*oz8ZgT z=rZSZY*{mzp!cY<-sbZenLd9RHz|+8GGD1o4#(mWc^H40c)m{~JFyk)5h6xay>k;t zZdc;W14}G~n+vebH-i<(dc)(^xtPRUgbPUrBSHbu4czYO)?W4M9V|h}6SEC@2ezc@%TuhKhfSR$ zk(4x;{|WXbmoNy6ckRyYcI*%o8`rbGgP0|nBJWQlp5|3_B`{W;s#+K-8YjwxpqU0C zMPU$LT=y~%8?-U$>b-Udgc#?chLA{$xE__qfA^vwLx;~NP`SkRe!{yhh^b`XfH!;} zR+!y$ZbOn}E^QC{5*!(M!oZ`tq*?gwKR^0^F5sKU4s#B?^y-2kerzvm3l>c3=b?NU z43{^;rt#w5zrpJW%iO@`ug^X!w=tNNzM1r12}L8h(Rq~B{R|?V2O%FIj5-8*@T)|K z2B3L(r}`Y&2%xYu+Fyqy{H;WTA$kG_AOFLV!rU!F?t`o}H&xhcWvkRqAoVScY_KKl zY=0?7-Y4nrh+>v3_B(c!m2Pa^u)hl59*#M0QTlh_I77%Fk%0aHW{L22t(aHV<%hdu z{Y+F{fCL+M@}+<@!N^i!S-QQU(37<YxHh}!EG_~YZOYv%}< zF=vgQsGxKDioQYM@-TMNA`VfqeoW;Zfn>zn4;)k!^)c#Ebr$w17fVA@o!&k@>rSjCTckHO_8SfN4&jvZ_sCHJ&#zqI6qqX^NMMo zE12Po8XcgBwbTfCz$;vsovPcp+ug_Kv*nBKi+d~o+FLn#`TqAGmhaM2(NTdp5>3Bp z217q5TvPB#Cu@EF(G8@nrCe7#wBMoCLG5Uam# zAXcb_MgzqKf7`oV2+c-y9iz#RKep~oL&Rm5-tR+0Bi44eraUjV9 zXM{mmm@fsGwaDvhw4=-ygFvK1&h#Q{>UKUPUGqGk^D=qRY|Y1}y0VhD$RX39`(~qg zS0RNq>@2J%2zYNSGBg1W)Ok@nY{Cp%0Cu*Hu=`QU3x+ZLAcA<1&!iC$aZUzwq0YlX zSe+j88 z>@4q}w1Xg{GY11fvW6v`15zyH zbU?Z>XTABXBDfs~Y{|^Ng)+>keT7_wBgy_dV}h?fu|k)3lEoma1B6P)4P9GYE+EqI zpou`!Q3krm2FfY$MG%^j&gQkvnk1gjKC9C~fovAN3gxBX&!D<;qS+lk2^7w&^D~o= zHh~3g0#xvW=?((A*$7OheQVv0!|?@QH`)Z%MLRSR08j#p`98C#m(Vx8$hoPo2V+o1lO^nl zbBrv{_hFGb<))D6g8P`cXMX0Mzd*4BxsZO5CIs9H;dhMp)_ZOC{VIm|=q898xeAA8 z7r5_c?CEVh`pm4ARM+V~=<2WFrq_M&<>=xRSr+eu%2pm!-3MP)FFs%S z*Ox!v>pu8oA1*%2)qejoWWQa-pJfzyG1z=rz4&b9=ybuOh20yz?UzF*uLKwN!d)RTn*!xB z#ANy6wBin~Ww;{tamswd?7|}IDA7acX z_(#OT9a!Ud$Kf&@6ZIR&urSam^Y+1@xiB!1--sn%Zvy#l)nl@}Yh0X-mus;`M5h7S zA8>oz63Zd%BJP0NzSC?N1=K><^1UX2Tf(Few6qW3RTwGZ>B>8vxc@=JhZCmGC2&V~ zRs5LZK)};RIC^UosV12|-jk0%#$i}yPDixzKTxLfuryYRYTg#EXu=NH5=jTtd@0wJ&^< z>XQtb(JY)A*MyZM1QgmN9A10J<_^;lji6!zVbF5rxMz$9om?iaQ^_IE#9 zz5Sqzq3?g-_-+4?ww>H+#6}1(?ZPMENhNU=uV985Varfkgw)SSfOP^5rW4m}?BwcB zNkNUAxEFl2vjnfvTGIv+c+8<4Yo#f^`(y0vxToO^Cy9u{)^o4BOHB9;%UlW#CJp%^ z->7HFDUa~w9s~qjFx?|FJtEWIVDff21#6xT2Gwsq|HGgE+z3trOSc1?M7bTr2P%X# z{B9?m)eaq_>hB}jD0NXjfH51+y8HV}aQtnAROhAkDxoc+w~@XK?=s&y_qAritT*q| zweoDzNcNXQj55|BEGz^B1d3u6hH43;<%$!9LCiwweqHhiaCu2cK?^6@+262PhcGQ$ zfo!Rm2g6O;G9x2nQ)PLb9B_Uew4d6xR7r+n6@oyMZXUAB3d4#Uif@?uSi2>QBM}a! zFFM!(v+c$hWITAaz7scqU2%XghKa=p_eH3qlk*-IZWo+iE=PsKjYvz#IXIk5Atzyt zj_5#7UsLpom5V4Q#81IE+&e*V*Q)_SzW!9Z!z$_Q!{J?|or6 zZ=%K3)BbN9h82fFiQ=~X@k4%*b;3qigb7;Sm2hU2&8^n_t#3P|6cwD7Yl0s*+0l@~ zQD`ZnjFJFJs>1wahPrjFer;|0$@(5{9DjPSy}t3+^=~#0b~eA+{15C53H3DY4>q?c zZ*AuEI+n1Kxcbvi=k5=5%xGcxEQu1YU%xq>Qv_DBIVEsU)tnOhkJ<{fFxGivySK7* zZ`Q~@pY#5UIq!cr=l$>7-?xk?o%hCa+HDJ&oIOzTPItr6 zDTLMfkIQP8kh`65A6Q}G$!8`-j#L0{@)rL{N=?zkWt6O{T6;miHlj-Fwh*=ADj#!+ z-RqCFn31;OCJdx?nA%h}(z#RW#mWC-LQe3G>X{b)XSf)P=T)0BABo( zB)xp~42%Iac`y=r8*vyjgGM-Xi@-I1>1vR(^IOjEDE$+1mZ08PRI~A#70P;4(JX?Bm0zTLn1WfC~;lj){u(Kyr>8@~In# zyj8!FR)D5;NO2XKW!7Y!zLbf}8iC^gRQ30@9qKZ@dE0RgrRiub;ZIwFQG_kZ0HqP1 zMlj+cE+W?o?+pw_|77s`m;)RhS%^iiern>7CY) z-8`lgUP+l?T4ur#0iZOh=D`>ot>c?T?$MYF^Ibx!!Vh2wx)qIf+g~PB$pI|~n!NL1 z`9o=OH40;!Pvrz90S5HvNWfRqU2EtFWiUGeTFnfZHJQk+-l7>3ZKpPdjUI)g$s*_> z<42u^EzDU-VM}m?{~ozc3gd#okPuWY5RA3`BXok)S;l|0%^FI)H2=nawNA3%q{ZUF zQTo&>zi>wXk}E*alCxs3qwiQqA*+{4$kZ#j>=aOu7&J)9EBD<_ViO|HnobYFmf_9u zFO9NJI>~?=?PfI!?EK~j;pRNIj?}E?S)NtnArFCIo;VhNLRzesE1vh!Oda~gR~Zrd z56hgeEg^*#+}vTKplDJ$KFS1JE_kVqeC26p4VUxQ8+9gC)XZn2n2Cmt1CMJYu**@u zOdZDCDmdi8aZCk(d=xlXv#r~wJi|BZg-HPfDUWEjgLHlawK&ewY6o-MVjF&`*O33kGkBW0%OI&7EfZ;80@8a z$blm-vjlU3`61`bg}#)3S&LD|w$YUKnOw;PJIZvuQmMVVjt72#Q*zOe5c8u4Ui=jp z0BP2^X*eNwXzHp`ZFqu_$i9>Aj5n&J_kXSOAS8i*KI#sEqLd^YG5mWS-61p!()uNo z2NNb+I76WprL5_n-*_Ti0qU3XqJU_Tb4t&Oz!F}FM)OirJGsCU%6K2|*Mh`iaLmUG*^;xHB&sLS1ToKSMRsjPcI-YvLS;Px^g@3l@v6 zRc=Fsz%A~Bw*m|#e4{P{YC=NLJ!LbGx3L7yRAB#$RJZ$JeLMo zh@U7G=rvl8TvFC;$#!Qp@I znMPTpLGNX`d0@4J1bFW}z&~}+WQ23zy9|shYfG=-bbRBVd6N*|H%i7eM1%)%&J)I} zB805ON^-iK436kc$kkPOXpUq{#frz45Efj0!QYIUYDf>ds-uO3kn5rC>fn-lZc_eGSy23ZsaRbcTsGD&h+uU(ZlY(S5k&#LBcilyT7-`e zB6H9j=+xTaQsMaH-`T=6OMn~@7yg>L3lN=n@rq=Cv!^kiLfwHsoaUwAcRGR!odlX- z3!JC0QOz{(HyfaQQ)o3iT_D#2jx)5j?T^W3mrpSvvdK*j)k+0`{70-|zTM`HB+G^E z&D%ZEAG~9YsA5Y7hEZ+1lVY28mD3UXuw{xr(MIU#lVwyA*LCN{_pNAczQI|_AXoII zwldrM|t;}90wfQ#?N~IG7_tX!rz&uH0YNWrmzDX+N#~XBF zi-Bpjtiu-A$e7Hv66tPSZ{jXeEIuT3+}t0SDC9JCnTYj1-8G+x*JBRH9t` zi2Dh6IkcIdLkGgAbaLXXb$;{W2e|FOq(`!Zvrvj`p26Du73F{!(G%=srfzi=i>sgx z9FXQhT`{Kh(%v@-^=yWDh zJHKhbVTwO%EJ!mm5f%8}W$;vh8-|hMr-qvr)?Rp;aQ#So??bCsw;>9zXk=#Pc3y+F zK9hj#SHSTFUA>bla(!3Oc+k}vDPyx6*@bRstt_HJi3iL2MVY)|;UCB7Bl9ne>ZB8r znJ__Nb6p%V%DyhK9z0%h4&?G`ji<7aVoiYs+ro4HFEPpx^zDA$B8%JGZFAiyvD!xc23K^(VR6ujNF9wXVT4njphy|JX1n z_7qPg_{%>SCK%)i!MHen9UT|^ee1meEO0g8^P2_=Xd{&M4OaI8<%k~>0nJYYw5@@a zke0JtK)ZueBnRE!2-zBvum6@8wHEfj*W1_pFO!)Mkk|EkIkDDHhP|ovfK5>oVSSBk z(f*9$oTLz(N+P2ZrQU7ynqecvG{UL4|7Yg$cTOOAeq{(|!$-6Vo~=-rnTQpSAS{&@IqZ5oyg>&E2v zVDUWDwc-s+L^87w-~e3;<0!3Y6@W2cM*J)p=_RfD6WUa@8A-?k3*2cMF<3QYYX49?n}8`alf{fHtT4W zOA4OhTvDzgP^f?uQz0BD&^_#{5diwW5oeB3Md-**uA&SU0_LkXw13^yM-nK+#wESYBvin^u1s-GuBL3ROQ#H+_GYXDyk)K&;pA~PvG&9GETYw~UnTXPHAwTXNbK_>~QpR?_X5Mc?pu=yg4 z>_>K4j#Z99Mjq(rr92RO5kaHH_nV$@9LNG^2<#O?GvpP1E9DgmA22xZ71tXx0Iu4e zdPjnEJYA(CgbM>f^kZ2xhNHe;d!#sZaRz@me57NGOkhJ0Tb6&so z&RYuumO~DVzIuX2RQ!>qcE=Y`zq?HF5SriXO(00{87m~+biRT(mkYmMk<%F7W&3R+ zemYdqG{PtOF99RW&jAj?jt5a(^Z82}ZS+hHVyiXBdE|LNvJxR&pCfIW(VIj(`Yid-M!lNPX5tM%4hsEkhQrR|ZIo6ri{N_(sz?W#+%Fk>T z`_UE{1NPwFIm}14z*W&H#$Zc106(kh%szqshCUZZSySbC9qPa?IqPYq#X9(Ia&n0Y z()Oj!!p+Zfm^}Lkaw)I2;7n0 z7RNn%Nb1e(21J<`zY1BmwlK46PzfvUzV3a#@p^z{u@|S8SikkEGdsgL_a?p3l&0M0 zXWTTVU6a(u`g1}2HZ`>5P0R!VI?Vs{DSzc)t=d<&8Jsdd}wJ` z^Ev+EWO#OdnFY7&HReJ8L@yq_1QCWB^O|12I3J&kd;Lqa9jnZ19M+atxDbEZMYyci zye_szhbI?(9O#|Dz6|Q~YV$hTN%A#b0#SLj`JEunayobflhLL6NNUaN;%i)FJ3-FL zOSB)W%xnCwgLiMolm2BIk5%S1{s_l;TwY+0mjFJiHLr_r$EQfb4t;lV{t&CoYkc?O z_!yCNmqAXfGOuy0vDcKn76&}knAh~K-ambbrbCT+O+Oo-508+6nR9wMA*fb!URUcA z#GJhu;PNW+ic2A?tU0r*;dK2KV(G`D!NUABt1`23>|$Ujyyt+)!tE^V5);!@d1i+P z2j}BmIZbZsC7#~KlB=DnD@qe>+QEM|RinZo88TR!C+tTzoQ2(R_Kle7H$#6M1bD%T zWeflD5({;_*~V>}*hhLOatN=~DXxL$0$?6M#)D0@PH>jVn+U!zr~voUr9RTB!-Qsz zwRLZc)XuKgWWkb0TN45~#j(OJ@RXyG!^6QD&d5(-t_+tbs5^{jVQ;q4_oQNt4wsG? zVHQr)u|&2;qlk^}^2&XK!Zmi9*l1~#nk)Blnn?3fX^-@ydJJ7`w@l0cGxBmJ)shqX z#A25?_3&xkq!&Zz>|JT{LYUMhukj>EK80{vz+}R>I~7}T?dqv$YgJpA%oYu<#LO9_ zqT0|-#&CU+sDHVTDO|$hJ>by)*4`8k&xglwLIOwN_ue^H8WOGH6|>T;zCPBs)-ovj?EsEj`0KYa zbl7Ayev5l&bbqfV7i{@xGCmE3R{w@rSnJxa-h4JZ0cXTmaB4cLz8v-R>qGyt+8^9U zmAh>`RM6lKhn$;)4;vFr{7A%;PjRPaZ1*Aw=Xh9bY_iT_w?@DbcF@0LRAj8c=Kv|~ zPij*#Jb%q#TqG}_49UBX1SY>|!n!RS#lo`Jl}$y8(FMwGd_Ko=`J2vQzi3B|6$p$m z=}Oyi!iAUFVpGFv;aF4-qQPc#?iIDuYD?(EN5ymZ5eRSmBMHxrK{P=4NIb z)lN3!0KoS0e$8RC6t9<#xG(Z(iOWUTCAS%c0K*BW#RhdWMQ##zwIh;|JHt47QbTs8 ztn(WCwmD6AWW_kPoW_WovO)mQt8oP19-DBixQ@WpZwq4aZ-(cWD(}?LTnPww;wi42 z$hMLIxb4omT*4G^?d0g!k)uF3A@A-d%uRPU&({*DfqNd-7jB!tq?PE;M29Cl&6Ugp z5D(;HLsZqg(R>w8a>Gxpod`+WZ8X|-Js{m@nKQzy_PIpWZe7~_P zw^J!U^T|T9!d@SZ&mWVWb!CcDb{4fg_@05{;ZN-mg$kw|?Ybl)PP+-3Yr<}`M2{U) zo!+yB>Z*k8nQWGcd_=uiRQeCN;1qu1)mv2nBZnxoCu5QRk<3C=E=+5_2LudwA9s=s z!e6ef?f!LZ`{2>@z12^2m%RB-jIj=E3Tb}<mk{#^QfNv`9;IOX5Y=RQl(ZuZM$+>go7@E(Yh-mk7<3 z2M!RlymPJy-Z3VTCH%6~oSou2h@iZwW?zJwBS@(_1vdC^?99T*yd1t5f%^bKVJ zPqLUGXnI(TN%wOs1q^1XyW_=HaI?|mEnKY!!hx``boEJRsVJ>}b;abtQjtRmoduFT z=aqT(C1%!3xL>4+xh^3$+a6M(abBM_8PT-z0y6L{2PL31;V<>Ey3r>P7Ge}s9G@s( zb8Vs!c%h+t)vkYOXrl#e??R0rp+{#$<-F{IDBT%WHb?QiGriCCLEIwk(~M9p1K$3) zYNCFqUd*WB8RSkJ9@5XXtYutNbJfpGhQr=4oBJx7q$nz(O2%o~zhNy1_ zFj7%L>s5W6X5t3Yb5UNzDnm`C2Lgph@8QJ>R*bne(w@ra5>w>XvI23&v630K^3@(4 zhCMiGT)|R?#=O54e5%n4%LvlMK+3*_hRJ*paAy|9mmzX95srQgCN62V(QSpXhIW_<8AhYfiz82x4zr;5-Z3rm= z^RVPZfY&spU&YiNqy)tUh!>KYUW+CDX4eRwm8ykHV3vaP%mgpt&P0NeJAPV0Kp)hv z4(^7mIzoh;lOVH6orI}xNML{j1t@oP|NrUP;1Gvm(Lu9io!3J`37>qN#_VUY?v10{ znst6#4;r-E5VOIKuu%Lro3kfiM>IxRi&gjU!!tO3(^kE@x~gkA8gyp$fI46kFnUWT z>;XpX0fRN)aXVomQrMp^a1&D6Ve=4vrbgw!+FvSNgJ+lz{ml+sKNQZUY!H3$IECCd z85WKy5QV`u@&4G@ws&3hGyf+Ww#6cyu2wk8WS&(^ooASROSujEq~_IA$%S%+)bY+A zVuwJur^r*yJr`E2twpS79-LxOhR!5Je_HKt={-~HlVfB_8qo-Z^PIQ|R1dvinYkpi z6qgO9gN6_1hX)tFCOnEJC*9`#-O9A@G2pU_WPAy9$A?ZLdP^OiWL7vZR#k^(81Hp3 zfSv5m7=<=l+Z~eJ25q=QQWsrg9<~s;KqqBBk@Fz-VRyix25LPWBTH{;`87nCa0p13 zE~Y$oTQ{K*10q$cfWk=t_?EL=C01`hqcHqe$t;Ea`^%O4Q}q^r7id6oeQ)qxt=Ja` zL>K#sTng3}#5S24G9Q_+(uxV0YDgQk}zX9UP2_?$79ehqd-UN%mBN7<0)n6Z0cm=Ea6vr7tBNR^b zTg!$ll&rRB&T-8+?bzeYMfjckOUQjQ5$>59TDDb`eC$G<7fcDZ(Hd>^;0=1maUS!T zGkOgYXuy9m&XxOv(ez?6zz(9j#^z5D*+7J0fhSPeL*NGFb3#6omRrRRzUpHkjH|e2 zbJZ{&VO*edY+)nHp4ML`IS}`L{b8<0RJ`yLI1RQ%9YT$(7!$R|BVY;gWN8|8ojevDm^i)U|FdBr{xwi6lXqHPiY7^&UVVIKVOI z*#Yp_g`N8DA&)YVEd+6C;>*)ny%-JuCmP0_t{0e^q&EyF1BBq4s@@D}qdLEG-?>E) zVX;gj4jXzAjuZ|o<*3rz01xuP+Nq_F4SzYS8G(3FnvD#9NzV!5q^-Jbnr$!faFk2g zIEI^`kbB**?yV=&??6dqI-8(!XlUg=R#z}udQtur+P5u}-LmG3j!)`KTnnYgh%ML6 zu?b(F*l!TyujF6{OIY-C8jbYJrud1QM*b^VOWZ;*AQ9Dq#2W}_iG;c*LM(7_N$R}; z1`~SEn2hh7P89hT1>X%toS!7H7>G6wC2TbKl5XN9!Wn~@$w~>0WQ!5TdSQsxv3DqV zOIHYxeaIU}F3u`KGoJLI2l(O$NLLo6Q&Y3xVLK>7&fQ4vuI3r0)Mw*ZGC(CtG5Ru5VU2 z=ntBl!MNOH&ZGu}>kL^f6ZQjcRMq!6)w!n{m5_p} zGF^C3;TD%SqdV2><2%*h{4iKzLSu$#v9a@fg{aKM{eHLUl4#WtiB!}9}j!D zpYhATt-iAF$QE(ZUwtJWUF;t7rlY29=Wu-XZZbT6O~ZB{w{!M)hV0jf&WMvbC}KY0mp_wYHo&l z7q1W6&lyV(-!?}*Y%~Q|To6@v|D{KxYY(Rm>K@E&c_u+U7HespeTn;;QeaL6@$^o| z$bH?mz+{<7by;t1wT&&Hy6}vKCYn|OdrLG9I3}DUCj*ssg+@3IOlg=SG&^wLwPv1? z9`q$bbnRS1m4G;0O1|+|lrYUtsTdhb3nJo?zMv#QR${I=hNBNIpyeog#~2ySJRn$W zk}s6QN=_MFPH^cFTEKjsHox{W2 zm@0EY#?1u*zdwQ6Uy}24-9$V&bPsi2-Q~}RChPg%Ewv8Ly>ggvV;M60CEJNEGxl5z z{$a}RyglJ}hik+O1Ar3k4Y8~?Bos{FWS3Z0bW{5+9| zS)=hZiZ8sG%nvKB3#pqc-UKl@l=H!0u!N{)|Bz0cQogD_G2E10uoypyD(51(Rn{8z zK3Rguhjlo>#hWmHDt}Kni}$N;##k@?;gJN~;}BOi43Iv24v@g3MvF@7CNcp}ECY#- zpLHH?bM@&nEEf><#B67AVjexfp-TSGIvCqKzgMXz!@Pvc%7-ks_rjdUY)RLX1a2!}iVF?j40^z}F z@2q}(Pv}^Z)F81Tk8t$6b=F{IW}5;J2pucw)an+ChNbvXMU&uHKmT0alU(pv8{+QC zr#SF~CuO;IwXXha1I+F1X@P`1)5lhi(|v$(O%6EPbZ~~&VpXz<4-FoiG7}kM3uoH| znMMXpqcW&`g^EXOeP~f#Ht6b0%$*>(#EkTPWd$n4dJ43s4*elqK)w8JX%s6&X?jT) zXw*l%d3_GDj*U&*>IKe3llWHqOa_N)dDLr)MbTkAc z;UMw6>i&R4yU-&0W8{FER8!bSu_G-j_oCb>_jN?VN=9r_*JF*<`sQT(YHjU&yuI&Jr)HQT1?D;pS@|&=yUEH6*G`Uu!h58v6x2f zu0$r=x>0QhOC3RWG~7*k?|<0ztF!C0_@u%BV?uqz&w-@`yEE5%nH ztpc!nC6*{Fa4lok{8bZnAK7yOZE#+Qiwoz_G0?YR+gFR4t)gucm?2Wxf&&oK!4pv{ zLvJ#8{6qYtXLdzbbwx-x5l-x2mW2=^O=A+b#5<0CbWF>&4idf)m74iOjr4Vi;R>btt7WM9+M2(w{q z2A-rd#NkW)Jp=GcHb*fVoI@0-$nVs?RH6WlC7M_x?jmKBm2Vt>IWaZk5Q>*Z28h{k zdWMU0aJT9H^fS5A)KI99f@ry5ULXsd6(IoSH<+4G&vgPqN9 zHva?r-RCMhmao5g^89PO{lZke#7@156GqsY%a&k?iH}&@maK->!f(NTm&Pl%W;})1 zR_|<^+c4yn40Bvskf$Wx%UTVcVLc>VC5i)i??uR3i;RDHabA1D;txBboTPAUKqgbX zudPKa$rL2I^qei;ad3&A6> zm)?ZEc1bEXyN9GmXx=_Jy~%+S@+7DU7){spf21Z^`CxVR4tJv4%^< z*`U7+y9ryVZ6Xw+0xirUNiJMv2&}?S`-z*15+_|4qzWd{En>_%JCWgKX%k zzMKeqY2C|rPlNR_()7^OWz!VL+c?(NCd^7^`#!WlVH@6C!&f$N>*GoY>(t%@!(sdt9mWa?}eh|AyM7z0}Nz@g6 zL(^!D-RwjbyJ50QQW7tw5vJ*X-+PR34-FPWveX{D!)R>|rs`_iI~tt43yAm0u$dQL zIMMu)-Ok-^_rcn}eU@)8clq_f@^2)*asTuEFYv$pC}=Z}%+==fqmAt9HZr$Z%}?_X zd|?-~F^BSt`p$YD31%%c2l0u-;@Z8d{;c$mg=TLVBoLp1cy|wOiie?rUOR{{#Z^4_ zt9^E|w)S6J+fg3sz_&AfxwpQPzg#{3`|S6x{{BT{0q0e9NNL*VUhvp_KHRMtNAntyIPu%(Gj7goq+@2g;I9tSaroJBj%){?0oNA`yw6SVn4?uSEFrT0>8kXaT zhVU*r#|bgXer-)6Z4zpFVcoo}jnezE>_E?>;VQ}& zr@jg9q$0DCq8bAWWg*gW%~6gktKd!R|AwK#djr)H)(fs)bwIR7Q~`s+Fv6 zPHP}!vk{Y~RSkJ82VW#PHs&7<(s(|?Rd_88Yf=E|yR6GGuH2W1b4pL1vPpBsPT44W zkEHH>@^9?7$d1Z3vsxLrH$f1*siHdUjp#S#R59p3$oe6O?CTRt;ELiK#>TElifnPA z_|^?ThU*LiXmnHibaq%P+vcaBK|TUkd4#;eh{zfs*vJipg2c13b{irh8;TW0Al9Vqs$l8`CFXXKSqq6k^LqSWDh=;f`K7c;X;SSi{ z|84|L1~3fz-}7q5O^@Tp0xPw)CHSdNkwuC8(Snt4Z3r`$>D0J5+j6STr?_rg%3_ z=z9l_j$raTRjjbKwz0FhzPFid``i zKQC?_+AJClY2LXXB(@%(O`N~8GR-|~oG>&rBM8^dTT<|c4rMOqW}5fnjaEZ{sdRz1 zI9kOB;RC2)R1L7kV}G`j|B`VCgoh_cPf))}fK}SI$8>b zw2B`rmtCkO7t>wwC`mTk1UZZBu~yuKlPjsRzr;3L(GgdT*e)j{@@f4|Z+Jq*!}*DU zjR}x@FoJh{bDicLU0n6tAEpyokgu$dd-=k9Ib>=c{8D0P9+3TTxz@YnYp^dB`+HJ& z8=0XgS;a?aS!nZi#W+X{i9``Np-8Spg!4?sZ-$Jv(o|tnq$Z<4EN;Goqu#~IIWmn> zupXWwPLzqUBx>}kXUYxHncJ4SF?2AkrGPUJPs_9H_OuYo`-B&9 ziXB{&hFg(v2{GSWtAX@1U-ppxK%1z;-4k|ikTDW69fvF0w zQ6GWbz4foRo^0*?=K;Sx*~FG{PdDxI{mus7{h|5Y*PDCmc>8%v)%7Ra-^%-z>W?m@kS`ytJb(7&Ki8@~3Ct5lQVshEB)0<|2Fvsq z&Wk+gxSD$STeb<=Cq;hEDifQr$Io3P)1JW9@N3YE-5k> zEep#wa)UmDS+uAT*=FFi4P9Y*jHg3pa4f3J^fy#MGkZYG~1+f)a#N{P{ z7OvUXcEG`$9!na$X1^R`{pvrNga*cxAUfcOr%zN4BXe--Wa+5QsceaA+afoxSGmiA z#}lP)r~SWRJnE04o$ZOf+Fgb}qNP7)G57+Dh{C6IdvWRm7(yRVCWllkxHJFxYpyopl#$<*Z=L6A~O4Kqpq$0bCabebpg! zJw?fn|MFAop3E#(QkH)mEMm5H0t|Cz?S}ik8Xj5Dcj}vV$w~h2rZcOJXlkL7H z`Y_BJ97=RAA7i-@+j^{D5m7kB45zNe%^{A0kRWA2-qbvp-a;g_wh`?N&M%n7%9G78 z@g&kFkqO?3Vg;6uoO|eF&)H8E5h+k4cMy}!)>5h1kX2}#If)p{chWOAvialIQme>D zzG{<+2EIqgDr_C4iK9R-G!D35wI@-o5er3Qk_Km7u}C%%*jbA9^^;+5YT9hcwU*L$ zWHXe~&yO5lwi?Z3(!NhhGP5(g@bZAxzP5Ly(}6yHp9q!7g9&UK$zZvI0+^sCmHy=# zL^RgxQ|A%$fzeVn{YC}V!^LT1{#Ct^22vu*;CIagStgkCig!e)td`jU-`B8`h&!${ zFlB4J{5LezOn!;p6wcQc5n3O^*+2pGc9$TXjd&5I$xbDql43mZF3iq@HxSH_)Z>%k z2x(;zpQ=$|LJ+%>u!{y09uDf;&g)|;=m;N#*LO+0P9p_29JEA!x1Ev1j8kF2q^F)B z49OyMC>ha^69ZQwRIicUr&?K|Bq#$5$k)Z?!-Yi?BqX^8LjO8~^a2HmaQS`h`nh?K zGk_fbTaE59q7YzKYhB0{4S#AL>%!ecQmwT=k6vN77F)wRoYjqyGVom+pHyWYNs)qW z;ziP}w*o1AW{*(&P9QMVIwmd_jo6~H;B_*Jzy+tm>dez!n`MN$!p5h+F3;O&oxz8ZoW z3btZt$JH#58Bf4X@x!kY=8~tWIXA0vBRI<-DuKummx9~Yw`0$i%uK}PWm<9eMDv4o z4c%6&1l90mZ$aEJ@kn0LHb^f;Sq?+lYmT5fJvwfjSKkI=<#|bq=p}V zO$7P(8^KV3qwF|G(Y!t#N5(g2q9`xZilKF7!HyuSRf1{wvA0BzeZ3LvI1FX4IdbOo z=(tJtj%NI*dV@O;(eShSngD*-k%B`p(G$R|-uDL5{KodUmw=wmKVU zMX6SVeQTR^cgbs%fEud&HSy%%Zv;sJg0kZrL-YD{^tkAdq+xExl*V+lU`P(iGU^on9Js#nFJL^S#Ls$0Urdq?H#Z_f#8s$WHUFSRPMs zes}Cm!C-$ieG+HbyVzN8iX{;jp@{g+Vrai&s1 zg1d`5(k}+n`yb3W4D9m*jo$d1wvDx@UJ1}$=E0nnrTJOPHvpa*cum~Ky$h?ytJTx3 zy*t&{yN~Wv-)uiA#*xFdml%nyjk)jz1)v?Y6sIoc0=YPYA+6%bDS>?!eDhEhCGB=t zlCH#e0}0HNYa^|PFkQ+A=k=QjWs7y~vPa8s7wb35IqjXMxOWj=79Uev$%$A2!Y0#n zBcd6fUZycc+dLZ$jqt&=y4hcIY`Nl@CqM63=Qq7}7S==POe=wkxZG1H+fD*Ds&LwG-S> zUkQ9(P+WKmK*4`-H8)NdakTK=BX;Eo7lFP0ba$_j4Co2p*NlLqjL7Xhf zk%i;aOy=Rmiw<23I`j|Aj<8d|I#rR9Dj**o{I}I=IHeRIUUaPD!H7ZJC&RxF`t>%F z+REC{v7Aqy=~kEcwIQ)^Jx0d5(nzfp-1u4VLcQXob{t!BkXq|bDMZh2%cENB&u9gA zP6`dy5Slg-J57)p8{o{h)CZ}g?hB38!^v-3BgrXl4vCEWbU2yN^|c@fh5xC(tYf_q z5^GA~upfDk(f?u=`X50(n2CIPH+5Q3AFJn`+st|8MzphTJJP-C43x8hR)iN2;E;ZL zaax}?wy}!?e7(x);=x_I*|Tg6_3_u* ziu0I|O>kpP_GIM3Fwt|+k1;C@jpQmNm!=0A5_rB3yoQu42&EHkz6{=XV1vP3!G}k~ z32#$k)fXPW@^bk@eUNM{z$I?ElH^~$m7TIIKZ+Ou@MViDZ*=fgJ`E2cXdAfE>%1fl zHW(KffARC<6bYYGd*R2(zzk{G z+$Y{&El|i_u%jMv$Q=UTi4v*S{Q0nHlgnzZ+{Z*A@T&U=(Yyyck2ikzyWjn5f|djX zX_O37-D4=1E!*N%ib;;?Iy1rgoDEHsV1yDtez{Cv zX_!$}4z0f~Cx*=>%c_&K6xkIEC4|JEDM75SdZ*|pTPP=h zE%1{}1$z!ToyDf2f@Tp)L=JPms(HQHtOO6|74vJZ&(2=0!3bOej#)#bT`gcQYZ1f= z_bFA)Akv2`Eyz5=4`EHhCf)~T5jQIql|U0a$KYOxXXRw*3OX2FoDL>KTqvfcn@QJO zl7`~2i<#ihCG04$UW0s!E!UdQD=&$~HlsCbfble%n+K*FDX=4AyOhi!Y+PwgbNtb1Z*ix+%pkKnIE8k(A0?sWYhrtG3kj@Z z2%o@V9Z&Hn=^<|A{OthOqn^JVyHyoS1>2OC3toOh7!Mh-bk$=Sy>N%ZXu~Z!Z+OX* zgj_1s*5fW!O{|+87r0VaRpOSa5pe-q4M&pEYY;|d6FFNNoIQ+0s+d`SCJdMw#Fa+K z>n-U$>6~Nc<1*n)=DQXL%oAU4UV3GxD03N5lwMBdirqlkOL})NsXC8 zrUVEjxEHke3n&mM11yB-S$&wO1*QYooaBY|VZCrN*-#?luefKpW|5619bBzw!`N!$ z)k-EvB*%|_^r6!|bDFR(KZ-!Lc^}llznQLg#UMMUSDm7p>2S~DX9Xwk6*C}j-?>%) z(`la9VFL*_Ft=h=0Nt_PoN;R0xF5R6h4#4)V3UiT~B({;g-uJk@Vbo#hw0iI0eo$lCp13 zJ^eWTh$##{yVfI4(<9KpHfau*LMTQZAl!LtI~^ zqSX$sgCsL=pd{t}wX`vw$<#CvVEx3nq1au7Ev}2 zISsgJY%yT#qY%HK5Wmkg8P^%)w>dKX=IL1~@KHZi!M}KcmOwu6&6^wyc%0Gg?7<6x zVP^*i&(@!A?ryJdY#tmi7;V3(YAKuGFn|;)$gB#pA`-1!5-uJiA~KUKWAos<-OZhY zN1NL_n;S4KKB7wM=d`hlEA{{_#1CT2ad_lVBZ6XbscDr@LJ+W^o_r+aUy6_;(Fc5A zhGtu)4E8$r`MVtbHh?3xzni7u8NCP{N9fze=QQ2W(noT=Slp>4$M1Z;`xIH}h7swJ z?-nmEL&HVYEAid3jhpAYEj=WBw=Cf_s(iP6o5XMClMwj8M?(Gu33>e$1nu5oqE%gn zWOtF}oNhbmO0Wi-$rmn&6N$iwRs}1HJMW9z_wf7%#e@2|oPP_Y7D*r*#^F@k)R5<) z{3t3^bd%7Vq5IWaT$iXOIMp_wF!!001rpi6h=~~X#w5q6X)KqPc_Xo1hE&asDpqbL z&^dB#QvK#xYrXM=tJdLn3Qenhq)f?0K=aH^P$s+@TU}jS98uH!I4woE&$Ybbq4EMP zG@U)Sv}km*Z-2Mt(#fK%ofTz8qDYfH#*%YgO?@P)f0$406Pb-nQIjXBpg`+Pl0xB) zI%fKyi??)IeJ+s_@T?KjOqrx7HNq>BGGy>PS?=%*=JupX7|JE%LTQnqT@N?JNX62A zm$ZlDnXE6hJaGi^?9{A+*(lMiwGwMsxg0oTWlx5$4L2fzAl+NWvoqm^oqe;{PL_B4(R_G&FbWw?-`lr{RZ*oAP19+-NXc4-R$# zTfiXl8ofqr9Fts~Fy9q|=Ys!mWo=jxi{ZOKx0T7^K?PVzM`e3*grbhvb)?(a6dEZ> zx9l(iHBejS6gjhcgrES2|I&fWN8oQ8c#*mN05O|vB7)&{7KMP33H4=Ti_HB@9H8dH zWKh>#XZy%DjMf?C<(Z6`oztQtk$h~GZZ@QWfN%u{OVo}$5{e{5kz?>zbQa3SB3?u6 zlP*JOu*5X0<{iGEXAym8P9R*Lc3BC~)vgT5d(SBOYl{piN3!UQHN}0@XE5t>3pQTl zg-$|9V&~1xEeedP6YUfP0*zgHVGlg8By@5iV8C)LBwp@w$|UaWwH3?BTZAtC*extn zR`ky;-yCqQ7m{qtscu1~Q&qLGnPGo>zkiElx{pZR)z#HI)&4CEBl#5owr3yi?2mBL zr!?GfXBgoKxG@IW2x!AD`l92=v`}Rq6#k|sgM2)LV0UHEd)eaihQm}wf?;bJ^=W;E zCWL{+>N?4DYsa{RhBg9Dvu%lRG%)$tb%-Bmq@0E!cyK}k2(hhvC=sp6@oNKA8q-h% z#Q1Qwiah+m_P3lEB&%b-puD_dx{1Tx@FHP{vzEv$b7J`8i(=^SxYuW zIlck^C05cSU?yKjJ~=j-Iq_s9$hz4Y@~U%J5NpQuQ^-8tO1g%acEh*HhWD0&qu6h2 zz-D1UExmdek!1QPyY!dM{k1M4gt=(wSHrGEa;pJaTh>12*iJq#jf*-+7`9=g@wV59 z?a2{m5im`Q*xZ>RnRLJ|+CzWxq2vg8Z;gD&gIQUKA9r=3f=o-vw7HlR4bn2?wr7&K zxgO>rjk4XeusT0{?+Ke{)Y6!y#3iEhaz<&RF2!JN5fhY#O)^JT&z9~!q7#~vyw%6f(s`JeSuEIXtt^=6>74P7*H|VYI7#qq zbaWioPhO~LLNoXtC7$I0#=MPuHj^dT24{#*4Rl)qnUt6d;kO|#rjvbA`_iz%=%w+o z0X7RZ^~RF|b3yy7r^*eOOKM*lG>;Xob50^Un>9}!79;2!{MbmU{Dh}aL5lH)SLKef zz(hmhkPzlJT*mivQ3=t4O+`A6b>|{7S1mdo#=HO?J*icgzgYLOy(ZDYwJoPMe=*=V z^qkf&`(}N9k|`m7SVBIR-t?ItZZHA6X*SSRzDCgN;cGeQb)?qdl16MhOt-G4v)@@W zXtGOrvYdwI7odXeQqnU2oNniRcYpO?-~Z{u@@F5wcRQ;;QRXV@)CjccEQo0GrD9+S z4s196r9le%SUFXCE|r{z>W-cn#BlzhcPPeC=Gv6`*!1+qE7%dUPc)2~{w8TEQdI(+ zJMSA6Xc>E-hAZJPxp#_ad)aL~uB3DH`)?({RBqb41Iu=;O<|9qA+|D=(eWRBits;Q zEgU0dC-7b1L;`kB5j2Rc*mL`Z2n<>nUc5AfG^c--qk6SOSkNQLU$JVa!tZ2A_$BZu z^zQ@JK`V}Vyb=K;ih?>U*!N8v7Wpp@qFm)7h9rq?laggoqG=HWtOf~UAe<#D3Mo4Z@FwrDtm!Jhm&fZ9J%q5>M9A@!3U-4TYM>TQKRWb02-JT z`fp=YI|Fbis3wd*##uSGKzJ}b=#UXtfZHVDM9qZf(mH zyNBn<(F;qnuj7)F8G|5RTrUFM4=N~AxH~#92#f{(456~|Szrw;LL+yBS3*B9I?FJc z0nW^s%$@+y64%y|bJ%8vQV0MFv&kAI(;#JcabNhGm5!unm|oDoHtr=xs4z-a_wH1` z7saC^2A_GwSAOrgg#}xc-qn?#>exB|i;fO@MP>_XU*Ku1s;5EaDgNB5C5zHYh_s!M zR^*U6aZHT`zRnz3IbfnX>(cyM>5Ce)(zre-dxbB}U^KK=KxnzH(_cPPkRAscCyzsD!BJ!X z*G86MM8_^O$z^|dF`3Yg@+x6AYCxdnI>QU0P1&YXT3BGqx}XxyniATzW_s%g)(*nu zGbtnpHW@}mS1&S3QYdyy%pmWJGuUe5aQ+VC`O)yF*}K{^C7yLQujReAEtq_)mO}<9Z!bC;k7>oG#NQG929k76c&D#8c^@HuL zt)>3Uw+w$l2ugB~uT}e_TdNGkqI>Ku{IC%mAdA&8jyrsu0T5i#sj%3-ReDZC#(4zL zYFQ0@jj75Vp>A(xQ_`=_X(&ZudsF{zQ$DA$9N8Zi`V|&>7Dn?I93k)XpU1-!NIlmI zAn@RBHupr>O1ao+#*v^6SqMe`kaR(4^>E|^tzBxiELVNWrRE*5eWSHjW6aM!Y!)s* zOMk;4s&%=BoF2q=IS@DvSFhZq{aEB6cr2jaxf-F}8{T@k$OP`zqY>jctbE zT8(B6g?)4dyb>D}lN4@;32KqUS?;{1(-3JK*~)!-tEVXrRa0i0M<5ND0I1qo$L)=I zcWY}R;_|1~2h%yAbPe9;tw3O4*NJEv`%FwHQs#0!*4mAFc+TXMURLfaQdO=D%=2SL zf&Y)acinF5NYX_A&r@uxSOZWNDaqBn&MLJmi>73oUAk~c+11mc%>|Jlg%U`x0Mar` z_PkF&N59zlzPRLV=LSHE)m?Lru(U*A@4Q4tMnpzNL`E*1QNa1y&L8;=Lr7OAZ@?1+ z+~qlVNArSTcoP$OIk!03mig+I)kQ`jqrfxiHZs%)VW~tEZ2CRrgRthxCH5(F19(5- z>~yG%D+4=&z-ie{%^IZ?vEOcc_7pVSW~Md{YsrL5MeC+CM3qu-7SR4=Z61qp!!#70{kUEI1c40j$a;i zxfj2FgLCPV>19#WTm3sMMcLSK0>kscDeh)2oBjTLG~U~u zPI!IU(_e-M2>0TRC?=UUcms$^hvv=2XnZbaOxh!Gvl)z#7gL^?W4=O4F7EsJZi=Iy zE+=sA7yppThv_)uh1&>#7$ETk<=dguW$Z+H>z35=%TAV+Xv%HLBpK+wuS$kvx>h3N zB+X{ToT1C4geezO+i{&ZF6DLEh>}pfrphwgmX#Ha5R3ro4Va}Q5Q&s3_bjP$*cwu^ zV&F^iMG(8&m+$1~G|iIERK2tehqu;sIF{zWwOFZUL0Y#qaB8BTLUqtFLRi}-&>*9p z6>#hl-ijy&S;BEy6v#2eg2fYL%%=Y!$F>`yH59Jki2f>MdF9MsP<~__>2%Ip?p&EX zv(tavJKAJ>>P>fK`q1>RuV>%F7SN{+}@>V$FRRrGQ1$GnE^j2#IwuU>BfhI{n?-Al;F8)*>_{ljy+ z4dfYUh{&`bc}+rSQ&oje>=jow_+WZGQZu(eJS}5^03@UK z;e*=rI9cG;o*U?DS4bMm-mSOwnb6Ip3SW977`@LM5c}S<_dy4Rbk6n z?&w%jTS~o`N15#+F2mAeCfMe+O*4pOJ_?MR04u%u3#^~L7n9(CMm!RtZzN`cj!xl{ zEHEO$B0(x7c;#-0maI#0AW=-u%L^(Dwr$a%A3O;D!EnWe%OReSlFKjB%P3M=lt8P| zWcBcvm2j8EH{-!^HG&3EA0e+43}n^U!F{a!iX_;7y+AYoW7+Jhcyd?8d(0Rdo}Mdb zu#HfO@?p`ASVp$Ab$T=b5ih!dNv}1MwsN6FVUe7D=T`m2?Ev2Db=M+uS2w7(AP zpQ>+dN=<^o%s;d-J%&s86e%ALhLRj7W{jo+>08uhulM`eUXK^*Ql~XWLKFo(>kJ#i zH`t)m3N6`J80fYA-S+;|m(QB|;anoA_XNJ}%gIGEI5>b>cgmCkNN~c4K0KXf+vH|& z#E2o-)3{fi^3;H>7GH^iYiU1Rb&V93pe&z8o;pzyvjE; za$FEX&1zSu4qFDKW!!t41?a&8vwX-KxvwVdEVa$>)Aqj!>QnK?_8DHuo=RzEyl4%q zJ%ZgO0>UGWsFK2+aCFdDWXTM*a4{>Q7my%*?U6z$QZIW=5fNtG-3CU(+L@86`=^gC zP7ioTDk+|M8=YEZY2(0TX^VFnxg3;EK7_7Pq-YJp%U@qu>@1tIwZ6m@X#%7e&f`Z(lW^1J$4FEBszz@OaWHe#lwAmJUM1y8M34GfeZ; zY{Qi((rNe(pyx;Ex%$fsQ`mU7XXvcDo0#hE}Yx7L{7;e?7+YU zF~q@pdlZV3>1G&K$?_b~3arl6-uquY{OqS+2eV&afBEQPa|Z{GZu8OF>gzkrkNvOk zg%3Wv!y+rIA_lU);*_!*ejTL^a?~%%beLFqgpf z0Z<<(yE&5m2rP;;-=9p7kK}?WkXjL!A_p*Kk`6HMKMpjd4URSbuFXYT1i$|2@sGE^ zdW=kW9>&xA6{H~ixsQ`?Sc)8SaM3Cg->v*MGBwGFd9Fw%HdaIr%P;kDNt+LhrTGb+ zBKuYR0SI0%v5|Day9&n5_(0pv&Z+v~E=6sBEs*Nbw+KS|3MUuhiyDf(4@^WQT-V>` z#N$t6%UPER2H@55!s%aK5`n6=WsAk~-U?DBP1urJv0&DRQ8aN~as-zknhdJAvILs( z4FPu&G=;-8|8{^Iv_w}oPLk+q6kWqrbBJoy^|y(MuHGQzd2%|wY+(xBu?rkZgaDPc zVHpAk;y>p=KE~a3WXxjWVPK5}n$Ynk@V44dmU)-7Q2%%=39{CdoySmVs57m9E{aWW z<$lgfg~;XX)tDA)6Iv>DBMswMS)y_Ok$W#yLvu%r8)8IC?bVLA0?9#-N z-K7xvhd}O;+d(X}i23GdnN2`KU{~akgfep>*v%hb{jUFduy%BB?T_;|5)4e|Q5k68 z$V7AF9CI~p0e;*jX^RmTKwr`FfkzstP(^IVDdJPi*p*|(vUt?(Y6y!xof8LRX|gwi zmYiIvTEvogW2WSIkctZHqHHh-T<&cndnUN@BtC-TBMx$ecIu(~=4xRbKVWYMPdV1Q zjU*~1y>z1*#U|Qkv-#cA%|GpLJbMPx{ex0p`r`W+U%&kR#gqNbmoIi-?QCqlc(sdy z_uB>Wc5CxhQSJ-V>0GpBakb%Lwky|`!@D%-J3P#Tx5Hz=Edfdtzu_T+;SMBmSkbbm z1rA@~bWfv1G*Tuw>peCYdUR|WD4{YJ0zs4pT45q9sycm%yR-{2ZT1Ozz2pYy3{f0U z&458+BPzj^p5P>KL%UBMSynxRIDubLll0?&D#ZHQm#G3*R}4_tgt>SO=e%)GD|NU* zs`HK!%92+ZiqpWHB1#X$l2b-l7DbO%Gfc!usY^J{mA!^L!{gyE{T{bRPy>6fH`e}r zu=Y2uSMlrq`r41T@5bNdD^!&8&Jp3&=zyZ!bu}MHMsiv%$yGvlI`6WlcLN?$ri}Dh5KqNj44LWO5Tx^(j1D_qWa(aC8HyS9 zIU*+z*_ToeyW$6X2qqL>auk7XlC`^-Bcl#UznM|T+K->72iuEkKDBySPLh5nyNaT) zi1)r7jO{M=4OSQ{%GB1~1+9?hlv@24nnGT^eDYF{AMyy5=BOgg&zk><%nmrdeF_OR zyM)u`mw=W6P9Ic~MqmyU%thJ@DTTVBO@!@A1U@lIiz8O3<*cC8Ugk^l>7_5LHOY+ME#C z1w9$RdS)iEAk@XZ7il|#`+6TL|`!SROr)kVI(;UEyVO!RLHFTZikA z*60n1MINN7MQZu_tq&BHBiEa6ECn2xz%f6L5AKEj+i*akoCDQG`wqb@EihB+HP&Y~fj zK+<3v0@IRR__NBcd#akE^=E;Q*L^Lkij;P55GV;kPn);r=Vy2M->mt5=UE44m%?f~ zq&8BQLZ6bd;ZBjZkKkKGP6$aNONY=p1obyt&t4(U_J@sUTTgK1@BY*08(Ys>D}v5t zpuz>1l*Z?x(YnuZsOn3jwc+E3)ob=qc(h(BVxx{k%X!-&VNC{g5!o_RyAYBbF7m~E zn5q*sACdxw*khttu;cn7=8691EMi_{&LU>Q7aAU-q$zPBmM>2D<^AX#Jzsut1-|Jd z;>&1yz&D4J1F13vaj0y@I#ipKM5^R78UVBzrExM9&GSpwx*~g21hjP&L`=yNiTtqh z5mzDiau|z5MKZsHcM0^kl+eje#Yh*5yv9}JN>w^L>Qopk-bzMfI0)C0EmhWOx835Q zpb0LESrT*S($%HBK~wDek_6VD#pz57tI15Y2_ zeRu$$-sy1ssAKJ0gjeZeK2}T3Z7Ja)!r}&{gdsLjL%QZl71rA1ES#W3wa)anxw9nw z<&*R=I!T=VF3meG92`*ot8?KB%~r{FK9#h{gZ=W82)31r(>IfgG!_MRMD9g5gJ+=M z`x48DO=M=nPJ_85ubZa5%W}qxFLgYO&2_YI2W0?r5Dhs2Yv9MC=yN4q1`KxvzWYGT z+NpcZ5dSWcyJkoUCEBYrQ5s;i=FMUkYsq%=%y0XHZxKFfm>qs4W9 z{VuF3>TI`Wt0Y3;_%XOLMKnN%1s6PI&1Cx^s0v7-YhbH+%=biUIAUNlY-Dg=BLsmF z4ov}L#|oX(zrq-I+isLfkko~xWN^t|Z;7Fak+rQ+q~nQ^91)O?@eqs}I|e|oB{w{# zS3&x~`8Q_sDDr=P1{d%W^ujjkR&KuWj{vk8h>vaq70Cr_i^nCFL(EmgK_OYZY5rZ_ zK$X@q5Ux0Z7G)FR5`kaX#3AD6Oc{ar$Z7L&0E`Z+ikC>_u0Qg>Fi0P~9Ui>%SfiOl z1(|RrNt&#ffyZ$0_H+#)JmOw;=8Tu5dXxT_VkF2^f0+LDor^ld{%6Be4-X!w!?fZT zRi9qkK>D3=3l@T*u?v9#=E8t#1!1l|k^lq7owwGgg&?G2v+am}@L>Dd#;b2$?mXY$ z-q`%p#WYtoOW^W@^c85l-#$=+X;Fd8T_bH_m<)IhaZ zf9;V?4IR1&&C^hvRG|UYlwI~7erXP0qPYCrFbU~gU6X*gt7T-NFY!l{@p$qc_jY0* z32}Ddp^RAF=h0dft?eZ~e-eKsf|1h77okX+JrqKs?fac`AOpdF6`AWuS(kxTXC(9?(-MBo)FFrzy_%v0`N|nFB7>X_p&ks7 zJnK%Pra^-XCDwa;`25$cqV*-x2hW7_I3}R}h$nAPIYB}kWI;sM-g8C_N!q@%<0)bX`BkCM znE~4D_l$Vb6_K(8nvAuFtmL3YVH0+cHheNVetVwjFlY#tncpavbYib^*M|4lK`+=6weS4+M7#-n$`=8N@v|98>T)(zg|k`JG*xc)NPD8g0;_J`BQ^@@P^&k5cq6q1#ozt?rJiMT^!r${yIbshDvH=5RV+*n zCI5b$NK9Mu@9o`5{v`fNBqK#fwi=h%jj4hxQ_!}$xMHH9tU7mmvbOrdg9i}P+%m@H zA?e>OC{aA>i5E|to*E?B6q8aXEm>#U1O25)zM3o;e#X)?IEBD^FY~}cb^i19Zi)v5usdGct7Z>CjJ-&iWqG!YDIoypnZio{o_zM#xLa328890!H1Lbid&hux6 zEpN_jO=)|fotExrs4TJ>Br_>JoE*sTfHK z4@6aq9KT`Y3u`Pw434&AWkd#-E?CvX1jYM9Mkv>!;S6`a%L4Pxkhq~(wBoWsj=5pX zT$wB_2*u%FR`e}GKK&%|=t9>Fl&HS~QPxf`banHOMU)DA z2%Tw=QDi*Cm7#F%<0#sA$V?;u&;%RJJppIFZkxWcEDe{-_Z(KZ`sxim49UyO3^W}E zlQ0tX1^Uq-S(Hm2G1(Umr&u9lI8&ed+%x0S-?B0#&Riy=`NGc%xft_Hh?(*QmPvR; z)}h5 z5U4a8T`cpoC&D~`Jy;fBY{@@yy-Cnx>x7^=*W$bM7dgn|gT5|{%~OI}#JW%i6IL*C z?h5mbtkr7YYIaR))jQL%#Kiff8D>E+@BAtL`)Q&Hii9Z5(F;of;=iClLt2SZ7$@y; zG>YC&IUiW#@~AFHKBM4Y&AS1G8(J)%Kq*QWHs3RnL=8#>GKh7258RGzicwQnfsrR4i~}0%mZt=)tLY6bT~wG8@+tc-X~+Y z0S|{~u*xGZI-FXfJ4q&dB%`!;$~(|rjK;HO16f9}5k74mo-*MGzCQLZ>xaWfxR=Q9 zU^M#=(_G30tVzg4xRh~nK0LrBD_Fa+>MD~!6o-dmYJ4)nILT13>S$QQNl_`JI_zTJI0xWCCL*4f2L3mO*a zg2fDrtvXN^pyK?XalWm$Q)tRaJBs7N?b#4FOpv8!TTA8yp;H6;N9Pnl_N`WzA+1^K z4HAcsjz$ME$$~wh0uX%jn3uRbLr@~DB!2l#B%6?~%;mnpy0|9IgGh;xr)?$aEv^bg z@YbHz=oi<7x0tyDuTc}|-0{?G#aNShvCy?v`$-Xx7nnbF8y0*tr<6IWw+H8M=k_-} zcnjw@Ov8*l%1Zhi%U@h_wuz+W=O}`>5FDYw#_j|$3@~4sjIyAC+g|)JBSudArYFtG z#tD?qs~DBp!(B^=GwG;i%u}sq?>cH`?9~(6Hs_5f|71h2fGZFz-BhLx2`(jy3{<1pli|+` z?t4a0T^$wF#zk!IbRyJ+>jO-8_`jSm8z*1MsPVU}-{l904XyN8c4kUk+9wi$^~NIv zR!lE%0JG>gPVxNS!_0OKw?wn61q*TQ1>J`TRiXsNG2lf7_5Py^psV5ETWir7_X2c8 z$!?IcJS-4ijJi$Yhpu=X*Wv@9GgwDHqEhapq=v{8;VME9)-IgS{ z1Sms8s6b?dDqX-`10|t@r4SQJcR`Sf%3o#uL#A#CfmjYfw&i7hZ>cpGIaZjcvEp4| zT>~)=NeMxXUaag5_6|y&EtnB#VNxoi7d*k{!L({Io)~P!(=d_6bBZM_{>lcPov~8` zU>Fxd!$sv?G`~+^&{!z+X!T&B8x?t>=lN6VeRs`b!TA@9#T`4wgv=9m>=Z?AQq*~` zi${x&mmF-6Jj={-psmG1j>8YdZ(hU^6`}bB?397BBwA*$;K@03Sn!s?Olt8%TxU|d zoGfEu0+m)GiqdLba9&B?5ld+&OCTyO-UY+;mjVLh;@2hn90XZW;^stGjV_R`j24HY z>^)xuI7?RY#(D;CUU2~+6sQ#hdIDAUEHFg&)C4~(b&LHg;m<5X3#cixNwpW6EA_aI zX$ki41^s3=udZ3!wWCpq>D<`d{`mFtd$g**V!l`?X~E3CNF?mUqWyXcCEb}=NcvEr z8M^Em$(8V!!c{_$Q+@(SSI-fLa?!|P6FpEgbp*qni3_v*1C4es$p(+4@yw6a!|?#z zYP%SjNF7Y_OPe-CVF{pJdhexjg@7}c#x#?~b z$7E=*9Fd_iyeDObA2))`2us;_j?IO=Iy%j<1AF~wdVUe_kahAZxZG(o_=B#8(rt4m zIYzy?a!`g)e@%S)_ZvZHfTQd<$L69w12XkY0Nv6!{J_vW_kI}~JFw}cu1TOf=3;Yf zdUNHV0;dO$9Au1szY%N(ILeN5Y%c24v58ZplM@6s(yzZ9r^A;KJcidJO!!N@1;=L6 zXgMxJXi|a{n*6*Gw5BkX5agI$qGv~L$oR1UwPxWCUe*>`<+S=;ovCw|8g+Ny3{DeG z$ue`~db{Pg472{4X!Y+mg3|y;*>R50MSVIpgNGUUC(f`k)!E%}845qw!d%(?8CSLG z1(H`-3!R8`Z?z-R8z{$Pi1gP)q<_B=LeCSk3J$nvmO&;eI0#LG&$OMT zarz{-}z@zbQ;51UZTmP`i2tmbo?!<+>78C>hCsMBo}ag$wEt zIbcx^5De#UI|2}llCyY-XV^EfP2^ob)RW{A@Y2V-tLvPWVn)rJrrNs1O8 zp@2M*NMlcXa=Y0&N1BS+ggY?g8}slOmk`BlI0u+%gu7&X%6KD$XO2gIV^Ve0Lx;+^BOB3Uz}k?g@gKr9lrLl(mtj^+kW z%!QcW%m@jbOovA_vWZWHu1p%)O4R6q0KBXRg|u(Fi)SO)WDKwqmukeP1iTw4Wz+FU zj}?$CC;GiC%ej%Z41NutS36;G3Xw(mF*EG<;@8Ndnh_y3ogg4`hL`T-d)-6Rywu5M zGJ^NQ52KR|nMpL6cIfF|+Hjg9i)U$M9u)fH5%VH`P?qr~?C&zbe>+mYj$*6>ehkVc z|D)l3d;C%0es{bW+w-AqVM?eroDe$MAGO1+WDve4e7baZ$xC<3 z6A)NDHM7>`Ui=!aOpON|p72Zq;()1~Lo{HS9l;idYvpktu7nUFLfEapZ*lRu-1`n2 zlVnIcybvEWk3C?ob2km$!GQ(*yYlt9n#qir__o!g6+pJL4M{la&hY#~bgowTaY!rV ziyp^=b2)D>5S~1NK7eC$qrc+bN<@}pz(=Fu)Ru7j(>ykf#q_DD<&)*hi@fP&-3J zk>Em6<$s${?!*s;2AF&1;`lAUZ+Ry^G0q_bLGDH3uW{7TV;o1y~)1MycWJ}7=MH(5YD?GOixD%PSej~7hAwai&j%Qi0$)#PQi8nS!jPg?I4JRRf_iJ;u!$%%7ib&GfBhHpLPAI!HG+;0PWk0 zH|uaZ-1XC$^gzhb(RIAM(kRf`a)W?wzlg)~F~9}LMKlh=Osh0VtC9|NT?7?izW%U; zTbCX}byai{F9=2y4V<8rbmQqj3~ar<=}vQh{oeXL7xyP8qw@wj>RVY%uR0r{%jE{N z;~~V0X2zJ;&|XeV2f+wtC5Cr7Xr62A)go9#R;hjkYdLxA%>|DMxQQ}A7k2(aB!3&7 zL3tib-{4q52f)|o(X1i38S4fIb(_MMxz~OE4WkGEQ3#raNsm>;Q8q&N3*M z;46!E*XdmrR+;)6V6l%fOh%T`poYQm9MXz*MGd zbO5qE%X8kBWO(2I7Rx~g2*$)#X%S9-P}}z+RAd`mUI!JA>aK>JqV@du08{t8R|D43 zW?-F-VK*2cQ61cj)8_3lwia=%Spf5FIBcMeWKfjo*S%cB-3Sb8E65ReiqrYSW=k); zu@xjNP?FFZnft*BTslUbcbDA zIcU>FL+s@ua?1iEyLDwM62Zw+vfcv;jlzuev3o>1oAKG(!5uj4&hh`wCiGBvhsNe5 zNTMS%rFjvYyY69{#~8uHA_0}$>zif@flzSf*G z-dD_#QOW)2F?;MH)nuO!YqWFNNnB(%QMSij20dbc7$x(`V870U7nprDzWA_HE%>8H z8ai2am}Y;Qt827J>8%@4lSl_+I?7>L<{b@~W*^=Rk7h8$9yV_-os2mTH#%(Wl9&?Y zDnzYOiXX+xoYlZiV0E)x`N-1|uG5q@17)L1;AOf1k)Q+Bnv==luw{=h@w7Z|hiM5= z(fXJe)C{yvqJNSED=x$C)}a|{kt!MZ7|fVP$*u&ulo7+HaCAZEgQEuPERROZ7R4@M ziR|8m2T`P&nuxQYI?3N8%_TRXEtGFDaBmKugT808$-zkI8)KRd#GdUzXe8(~$j-<4 z;nqWL%^ux)(BP|>yn(VIe%^ZMQB9YRZvEy-H@qJAP1FX4FiXHNe@pI}xphas+~XI& zdFmE5ms@f>)vfi0E(*B{2x<)|jp1&x+<3d*C$kQbG*b94a5)Xx5;B;*&(4Mibf6s0 zpN=F#E^RDDMklp-Sle7C?7%#krmI6A?fHY7#;`R7yaq(3rmms&EnY z=d)mLAS}F<;6D>_OKpqu5V|(A?jl4`5+6l{T6{dY#gfbM+%>r`P?Z{G=a&fu$L z^obikZG3gy!X6x}_v6=UOLHadM-RqOT!CTk2r!|s$~+FG#PD^%^IcfWP6CgwGR-ly zMth2P%sb=#nYWjM^$z_)*wy5wgh{H6sZ+J%p^{ z#T|jg!~!MjeFr%$B}-rVm1i%tD^B32keua1awPoY>QOMFwKY4F$@#{3G?;ChlNi2G z$@rN)9G#qL7WSD`u(DwR@syxNg0?gP9{VY);jjjKe#sb06N~t!{P=?!{>os=YGS;_ zt$3uDkZBSwbEU9(!3geOFJUqk^eAW@(%K`)fl%W{`hSkRuqPKMiS0**6Qdlv0clsg z5r_gP$bWx)6~vSkZv>iP-@ghZX{8&10;WxPLO8%N7U!jBD6e)SkkD#0I=%u7Ug6_= z7nRcvM(YOE&wG~`F|IKq0fU{x6S0cy4#!6(3!Wq?kC}Ny+D9%MugkOsx(P82xxg{boiStdus{X6EcV72~g$ zAFkKHX#MMg!EXD3^KgFrW`>GQmt;5gxt-eYj;Zz6%MaCS2p4N#3x*m%;_g>~yRo5$ zOM)p}Y-bJQRL5X*$r6hfm2X7E1iOfloEw{#04-Dv2V-vrUl1yx=_vL5(Gq~A4NxkD zsyBkMLcuTyXYMu=ePszCi)L1e25tt_s~s9o=`NUy!}0N(nOu!>G^9yzT!Nuu2Ad&O^C!b8AF3x(kK>G-sHyz=G|9-(H6En3*xLjvkWaTc{b zo%{voo)NVjA`$-r--=kYuq5-=E;(r}7gykH#|hls8iISR6B==ET5d}>5ePX(z_mYL za%URO^x^zazKa4a^~l!ap&dWMn(KF100lvpN4ex$%%o5*6HrX}hDHn$Zc>n{%jkGc z0qKnaiSf)|yA|R8yo7X=>}q#m|E49h9I7hEm=JzoFi_L7+PiqLDo2bJtDD=PVYT*@ ztrj|jM%fWC(yHpLTn_C@8}=52B|!OxxrD0=21jo`@pa@@7oJ6!-OZLMSHAM@%AuGF zoEIWy^Cw+nx)NRs_)1W6tS;BT<22>CIz}aciAJKpnTyc5os{ioHA~11iD~0RVfy<< z5ST$!0+FL{nZ6x)Dq!kpGeXRYbh7rQNGc~hty6+&xYC!zl771p{8;~GmpNwU_vbi? zGIcIqTE#kXv*R(@AWt~bmIvea zT+lW=)A;jo4c;6a-v8nc|J3`a!KKo@dtkiqodJBDnrs)R+5=7?jt<^2qKfl24kUwf zC2+g(c2|9jJ-J7y`N%w4V&NfH^?C=LtmcGwrYfP7O(nNR7gLGCD~QHHSc({2b7tvV-vqu22#s0@i4A~7Vl`xwBNn9o) z7a-JYToeaL(jA4#CO@x%}_X zvD%H&)I?s#qK&#zu)Yq>k|;0O-CKtAE`}NS)rQMtR1Af$9V`kk-BumcT7zKD#KOWI zVnqMZQa^T2a#-iZU_N)6t3^8}dUqKU#~irSX5J36HxS*nWhCf{PTLuXMW6fl{H|?C z&A4U&hz;Ff>%@r~(9;^Ar%(HkCHEnI{W7K^yQO(|cmgHI-)_t0%skYi&n>h-AET-o zp0lUn4&+J=4}7xw>A?f%qXRL8K<|c4Jim;#6ky96-LNdphFJN$RdH(jk8)qDsk@M7 z>AXKf^u&V)G|hP7*XfTRTi4Gos(`&YU_m+*y9u-tCf&Ky(A-YGwWyP>UBAo{cVF?) z1BM0FgQ;|&>Plj%sEFLfyw7;>{A@6qhE$C%AzndOCR(Yvpz6gKbA$Ol680&H_kQPdcZRoU+Q6u=9a_*7pzLdkO;~I>eGr8tCVrrk zbGkr^0(01E@Ewf`NJE5o_Yg{mgi=V{17{)shK7*LsCj5F{{=rj$IY4_LhI54yCkXS z*Kz*TfBn;!4;tLW`I>+F>$g`|e&ZFJEBBj~FYpD#cw*hWUKxSABG7D>j43`ONm2;X zMbv;6M;i??03wOuNcdLAj5eCjoBKb?i+aVGmq816do6a3gIR~0tLd%h4d>uVVPGSF zny{~rp$&P7K$aZi1Ua(wf&gN8=PHmo{N-$n6K4He4d_(hxzl`6U`jyIX$Fn@L>r^Q zYGBPqmf|xb%A%>?n&B9S-SP=u*ggrMY$%XOf)ckODy)jR-##tc$fl@njcB1U zTGoScF7*rR=*}e;t3MA1DBC=o;>Y86r)M}$A$89$nLy~#biFdHR$3$wlvzC}HDMFe1Hul{(lZB*|xb>~2GCbCm8CEn&+DEXG4~Bp6Zg4D1 zp0~E3h9*!mP=2VUdG6}Ws=htDS~WEYA{%SifCW%Zl$D72b)o4GxjhfR22MAj@{E|2 zfoobo1!R0}n3!GO9va_@%frJIyf?ei-S7^1aOh_$~8V&k{S zo>-D=l~<9gmJr9)aRo=sb-+mwFDZBJ(R)x)u>Jt5^T~MfemKn#gFCnrU0f1u46)?s ze1NW~EjT0rIpspTa`yHtf=<*8-$TkeCi=ZEzl_&^XQK`oQYxJkD_=fPQM&eV>IY}+ zu@4D2xYLAu*%;@$<5i|_#Sk(GOZdq@w6O{XQAv(X1fyw+4(Bu@)6Yy%V%^t0^wEQw z^y{zMm_3lj5@cYmjk8Or;-s>h-;(hsYrX8Nk^z@vG02iAA!#hm=-s=})G6_sx1(do zmzZoGO}`%^(aO&}Cw+PuXuuf>6AKLk8@jan2sFcIwx=W9N^yRPqRD!Q&7T`)U{ZT+ zp$sYi{}`Kr@+@1Ov=?rbW2fbio_p-1o4ow5~f+WaB_1A*BTTk9-k(}%AbF4w6xG1#t5`1 zp@%0KrmujX7S@O%y{f?xS;LPL5NRpEkRyv2x)vH+)bNqi)k0&9Qm=^6N9nj7QIaIT zB+LJDTy}^+m>}pFJbyoFk%}m^lhb`Dv{NPbi~vOUu$XvG4;$@@>X}-e3P>{XV%tK5LJfpYSAq?=SJU{r=}a zqz&*r9wha@SiiT%^jF#m-{Z++K1m9}KeDEI0NIxoy8oD76ZtTgmh1CsWs}H@fE)~? z)k6LtZ9y}Vz$P@gfS!NotvEQYwQs8y8+MIhSqcSh$=3~mJ*`{As3h;iEB{QzapLXl zsiox_1(j>0H;B(re{cPd`dM8A z8M>8l{T`KZY57jGc3(CCpu%K`BzEauOqON$d>cRj(M1TnJ6a=?UeK~qC2QJe(Tp2- z4kk|;rf0I)$}%!h@V<@Ck_($NIeBJggRpCuOMGcVz?&4 zdyH4Gp%izI+c$gboNTL>P6XAmx5I;X?2DNjG2gEI)6P$K)!KM6k$@em9v~)dm^HiB zJ?yJrHvhzRUIp!&pK!9;NJVAI6uz(Bo2DDAd`1B45K12>3 zxJ3*=Y>iLefTO8E^L_>8o&Yw9M##Db^y_;t@dEDNz3L@62v6e1r&<$`=Sp3twRc`C zU+`+8CEL%2onTtFVN0*3C(m0Z70o8#GBo2=#W?n<& zR~*1W5 z5E>KU%_=A+8=)0iVoK>~YloO~d~NwbjcVXcSSHhDB0;AkKJCPz{p5cCNK5{v93?2M z<2!!5_HyrsgW2A9$4{^p&~lu4?zdjrfj|6N zv@IoIx#JCHPk$L6Ah4$dON#9N4AV1$2!1}*M%<$RYAP|X#}~9fP)fQrp^%er;Ifct z(!Y9Tlfh{0 z-hsP$$iue;92XTS|0U6hkAEIaX;=h!%9?QOP^$YXPE#h{nZ8k0EHGMc0S;!Oy`u@8 z^^BkE%^0SY0XFGe%9>=gv{#l2p533F}S8B8yp(4B0H0J#Z;1qfTi; z=RhpUXv%gLI^+VSy0v1N^S2IO1MdxfL48s_gUR2F2H+QdaJJEex^`heJ;9wY(2wmG zRb^dk_x*{eFGw-L#M=_4;S*fn(@F0?=n4}98^oZXV}V*hxJ&$VNpr1tfA|ahCdSO2eBm?^3{_V$gjb`5r2k?Xs)f`e8 zB#U97G**QHYO^950hqY2uwS-eYPRJtSk{kTBvYt$6+sH7v+?L0=PDT5twTX58N5r{ zK{*^YCAz=$-`dmmzk0BDyIE~+_xJjzxDi{>zPI}89xQz}i!vvByPwO`@1AZv!PdxL z!OL$ib`kz{yZ?Hyc64v;kBIGR)^Cfw#^3_FWgA_MtqMR&k=OTaBOBpa?a?VYyLf|j z4ARvhR-C-k`N^!Orsm8VTD0sTR77~fmknG6Q z2Kl{(ff9Z9=b^8S3zYyM0txvu0HJ`$q|AYX9MCgUA}xtHGncH~HJ(XFlA+IXOg`r6%Bx-P`RXBgV?zJNhnS9AOIPj`R({H`#H7`;ru zbOFfb@+M5Qd_~#vvEqTa3Zhwp8G{(8&q56aj&S}h5F*GZ2(C8LWc{La=iXF8&ibcA z_|$L(VKC*Hz=e8^Jo6X42ZPS4BV9UhSkI_86Z!-!#^t6Osx3L4szl(0fF!U5S46CP zYm6anejgmTzh7Vfy+ZeUu7{#qw~?4qy~brGN^GTg#u=0%UP)hs-9f?eah{SH;cR>s z0AM^yR4U3@Y2nLI@y&E{0>$SQQ)<@6C^N1wmQBhuSTpHJ>`|{6f)u~`;j3O&!X`3+ z_F*h}oZs=}7&?yj{^hOTe|M`{JH6kKYm0lpIo|milsCOlN0I>twNb;hT^0GNjPGLM z>LjOo%YN7&@ieo~JV@Agk$kG(EBj5p%- zuK6jLo3mFo?CtUIZ-_ABDEoU)e>oURqH4I}N*bR>E^#l?HM?R@h}+;R?30$7Z`>)S z!ZRRji3tyt7Ei1RaLiza$XwzsKhIyAwx%!_I#Na5T%=-!QFA&u@~i1p3E)u|RM_$n zCaZz>^jQgRNjEHbRjERH>JTX=CJLMtfPrSF!!_E+sSCIbo>n#8;Of}0o$Sl{5Bn5C z-f@!2?$DU=D!F$jgXufVkjXLdvvMfLe2@WSQN3NYkM(=FdO-3%=)!hK%DfOOzeMn; z0ZkfL0>>m!YcbXfrS-QyHDKyOxazEiG*SP4%$#_Wf#uAmL>%LlZ6r& z>(I3a(*kt02@X>2^%A{k54%8hy(X`90)LNpSX$TU6KCvubL+z?9F@QA?VaB0P@;kY zWNR2t;PkL4XB^}fBUMBq3#bU3E8+@7bjUd)V%(r7HynlO23gDwPBu>tahV*C7S$}Q z`JxK&oqLl(fCNUz*c%RAwKeGoiidOnPh4t1Zm=z^NyriJI6?^9(YnFM_)x}T1>~Sz zPKDS|M9UUArVSqOK%H16z-DAU*gwK)I&jwP99Lt6mMEn9;XqhoSAN|S|9bDo*FBwN z1&txlFq3#_bY@oXtn%7XgCKy=Gx?Zy3*E0WmTVt+3F+Skx)VSUbl1C;V&j&lJ3#}b zkc;aB*4`|7hPz-nNJoOK3$K;&@bnl)|1X>E@3!~1UcB0WzVUC#Y!c!X-27>@^|c^f zY+1XZ1_=g<{GIvUd) z9x<7P9Z?N55$tjUyWWsAzC>u?ksItlt}0$(2lU$?lW~_SLW;E*Nvl=}1*siv(ibyR zWir-r$Wd);aR9Xuuv6GQ2k&y+@Nt13KEikpCldGoc?HiBxat_kK(KS1fd8f~_Rgq* z4Ui%_#s(%R%nN;uQv4MbtJ8PCTBrs7;;O;P*{>1-w*GlJN|3cE$yHJ!2$+&eJU8D| z2E1}`a!5NWm;oFbg1|&h_S0nnMA!=(X7H+(h(iTfI)@CNjY73pXbA;TbWgoT*_s@! z*bWq0ns29ObNpOs$m}0ug%F6gV?=_hQ0O9|C^L$xZL%UjE_t|I=paoLbs7>Q6?e3l z?d{NR)Ew1n)@4QHaIdDGasd3KgUEWXLl`$KT0PzI@=1K3(BV>=YGr?wugXSc)^2O7 zt146GN$XG)stSOw&P)1$f=qxgS?uOH60kxYWezdSb}$E0gV81EGMHv9E)eq>C9aqM z1^cOtRx(Oe2~jMyS0~UV3A0LYSD2LMsum5K8B~)K>x-x5#_bo*dHy$N6U@b&>Hm1M zgsmFJFS<9gA6PvSD^`!I$&GMz;#s}|OIxf}?h6h)xD<)Zem)HqmS9>GhfaPp!S3mo zlksB8kbBJEZ8J6n0imAAA=3dxYgnViqO$&#hUxzG0vX3!%4k{?nExHNcn_MMJS{ZZ zur-?7wJVUz^Y0Qid%2J+q9{#jtTzLS!%Up_4NpewK@pif@*Op*1whxq+y{q|i| zKm}C-67S~7rJlj7xPF*Uo0YrTLYl7*u#+na64vqB5Pxzs;Y922a5^<^e>8Wn)N|1Lc!2nKI~f0xp9t}7$cjuP$4ALn3) zWx&ymv@q?VEI)e?HyB(vn^D@w{>uiRuJ`QpQ}Pt#nZ@2nu3(>^JOwIQ7Tx@>Fw^Yu zzi&ok1YTtCwy+&W)DCi%*f+_v`h0MTgcW6ga}u2$zt)Q`5iT8@&~z#BcLCzI8kY9- zNY|X)Dqe75wiba7o>ZDl@JA!HbF{qN+j<$!_bEWTNLejt#1{J;iE1Q8SaA9P>6W}@ z2d28&-S;?i4>J=?)Vv=Bw%UVtybzVAbnGN1AFY&fx)XaKY1!@sP*vG0#zggab+Gi1US59xk}jzcK7 z@2_ww?%o`#V8Fw@z4+EYM4IoV_--eL?YkwT-~;v=;EyY?GBn^zRqgL%b6 zGyWG(ISK}wZZcfY_9jVy@zyCaki%U2H%^Vx6|w>dKFUL}k6|%FJa|F|9F=@lMjlq| zvEa^KUV?uEM$?Cp5Ok!vx`aDdA`=+4*-mQ;*kF9f%n;;OF%#1dP_$WLY(yWlrwyxW z@^DeBu$(X#T=t#@}7U9st0U=Hpy0qp_T zcbYZ|+X%eVEQ=IqZw_lZs4{Zf>_W~%Sd;@qN}$A(6^b+GbBxlhhplSqBBM$)A84ICX#}qtDr7%B+co27l_f6RPcy z7seM=JTGR2R->k9YOBWB8KXe@GPP(7s$OQ6q@fSm90}9M`DODLx^xb49-S^7A8$(e zVaj6dDN=g;j5X^|aI<0_)Nl}9b80m~U!GMZ#9tJTk+|n#G#&Qpk0sWzcm?Ps^LM+7 z9K$XjW8q-V@A5HD^YRwuH6ZlO2m#5LWdZ2LIFTjqaVJ;-L*QRz(<$GnPcBwSb!sra zBF|VW;4du{oIQfteW)KeTLP_unXn`3&5Uo}ZktkU02xXR4|uuf40WyN*DOSju2X|P zh{7al;Eh(vhXLZPhB zq%>Vd2oc5H+9S9Zf$(J5f^72(vzX92)z>w`RiSd&R-p6Hv_dDoafmK2V6i*m-#eN39 zouF!I&>R6pPUJ}_oNS5@GsVx*kCH*DOnOUsSJ-2Cxb0g#V;DA>%C1O|r1KQqa@FK} z6MznIY)F)oj<67x&H&N1{A4&ihNhLj#ipaP@dzqOrt=Vt%(rkai3Y~eh?`>y(<0KPgW50X_mKU56w-1sjYT!RD#M^y?&6H>M>_QykS+*p z^2u9YDt8RgorvCuz^+Bk!;o-V+*v9yp%$|jn?tG*#Ni+at0K;W_EpT1C{}a>l{CVR z0~~9QaP67VpJy@BJ<-}D{>2uBP1x#Lftin7s5pEpT^|Etso~PJX!Q2x)T|(};dSm6`lE5fmiYB7vH+G@S>Op-i?0 zdNge{?^Z+c@H*v%H-a{aBN}7H(MjPJs1q%z5a2L*xWWqECra1Ka)j} zccR06gy^*4C~keLmI_RAhzG$XGH9+!FVe!B4Ehukd07r!j(^q<4CzGP+uz@L`SR8N zez9TV``-Qad(2nWu4F?fcUi2|7R(WD_*7G&8eYJ6svFik$T8u^LVjeV#Hh+dKH0ir zjdv^uywpCO& z+GLeU#-U0)FRrn!?+7@9aY70WBn-;>Z_!)Zh9J)TgzzdQ=)I@WAzU=xJ%(MkO~|!N ze~%Fa>&Kd0;E3fgpa0hTNCJx{U|Z}b9Kv|`F`#23WBBJu2TF5Uqj58h6wdqCcYDP${1w#=Od(kmlHa)TRR;9)B^MUr|ME|tvq6B_BFgRFE5 zhs9f9uzdum$N&RERP;SVx^P^darGr2!2I8dJ|;V##r$In(5I!l(C2TLMV|@fm++)b zVgAF}4?)R?fSACg*XMs%Cf1N3PkU)Y?~6lHWO*KvOqG8h*yRudjF%mr+F@vr z^)}g)2-f63eFMve?<|xXf{S7$dyq_32y1>(%-atua(We``=!mo#F(CN1#i(#UPRZIqKJ3p zmd3EssN6TpPtxgXIF$Rac2@b@o?_q(#)>?!MSywXx9uDLE*fd`v>ntxP z(D)ImHqE=!$@^1miLt$|?2Hl$Hz32=dMzyjz3*q+ba65)i~uVziINGJrIwVsPMf zt28T7Q-i0iSqa`)`Tq;@J-jDhGdL1pl zA9DK~wyUNuyIQfaXl47+(V<~Xi`tKN(PSe_P@^+7Q5Fn0fs(}=8?~fuvtoyc@bvP- zT(!bV<)zC>C_1r?eC7!AsyH*9v{N-YdTX}!_5@^?mK4^pR#7x|?8Qx(#~K_{5cN^? z7Fi<7c2mU~!}8Wc{n&njdUll4T^yM4p$Q!U6@z{MMiT_75NlDcWa36$+3QnHdB zBWzp}sxGJTG4>NmBiP~fnp=gy5P4&GL+?f;&TN8|yD@NiNCQyby z+LNnv)yA(8oyS53#~H^G7_U%@s@jH3fa()N$P*z|C&+@+l&iHt;P?QPc`^f!w#wGJ5_K>I4aV;Wh}zPO{%{V{T1K}B zlgNV%#6x1#fg{Z@q0$qWjb(*CWdLf%P=fus$7g0qNFQXj8iLGE2DVkq2bL0PxUhs$ z*^w)RwUtD#?m~CQ1ss+eaVEd22@!z;27b$snX`yKG9>wJWKf0x4?~fC0)mF*W(El~ z81Ql#-*0AE;lLa-CQU>l3q!pEcETbK1M34Vnh!c^2yBZeke#(!PS8M&z=dcW`$9Y@ zST>u%nIYe{?BeZRGo&%DC#xYscX+57>o~cw{bW78&}b}WgX{)CWLjQ%QvxrchJ)z{ z(T4yVJKzIe!2%z>`ea$fznAb3Gj;-|#d%>ja(4l*aLk7;X58 z0TUj6eoF`M<53)IAsa(tGulaAthOK^LjRl!g@aZ2AVNo{`>I1EJ($@;5)kun@7rVK z9xqwS%I^%1>Hy&d?=KK3ObKVCAs{~iKP2xXffJK6*bA9ZEdi+Po5c=rQ-UN6?Ae`V ze3*RfU{A-f;H03)*7ctJ~cG+eW3g#!N$j_UWmf3=BO%~9{|=WCBY zwahC)8u@db2@pwrB2+-n&4S>`tkPsuq~BlP9`ny{$Wt}FNmTPzu2mpgvcQI^fe<=) z`w=(~`CD%m-;QSfjT4i|8ea$k$0O9izpp(~>Dqs?@#^XR&NrKX_`@Imm|t1^>15>+ zCo9Jn$D`A|&B2)+4uDc5i|p;@IWpbJ;VZ24N4WJ(LTk6BJYAs$H76IyS;Q1lLq^#^=RjF(SF}H@h=?qQ$7XOgl0$ys zO%waTy)B<^ELwPcwtJE{u`9q1Z^r9Z=zN>v0GZ+6(Eo~)66X67PA|kJOos5UOtIz_7hlhf|>zoLoKz67gUd?;A?!RrZ~*?+$nLL2W(?UAoHec7WjmpTBx2)@E)(ow(pB0_N*X63I631do4bl zE;JSerwTY8r=j>e9jfTVEr}#_+$uGiTtLjZ)RRrA@Q3ZnfqY?s#sp;$c969yF(q~f zUU8^xj2+vdm&Y$$#TD9Da=(gT#lh7NLQn}6KF7(R3BqZ?|1zq9_ck~^#aSTm zpKP`$)I-lYGDf57wUU0|z=>641}=caRvSl`xjBYxK$1S+3VAthrEtDP#|{$|s>m5# zo>GACXa+IDK@Mt#UTj5@0B?SdciwMN^gp0?OLyIku|UzvEQUbWeU;E{MyMqsghz!x?r{$Oo~BsFcZg zh%_3wibwwsD#D^VFXjH8J^ho^ausvqw80r8Xnr)-z+sLhT9>tQwS6%f&zcRatRUXg z=HV%0u<`Y=e_21w5Zg~&zw zoe4Ipn!CQ+|3C^DRmkp1AzAE;aWI)ubL$DUO?@VHHs1#6p!VRpAhub zYDYqWt=*TB;vVaeKE!5)?a^|F10PI84F$})$|tCZXif7v2&Q2qNzjI0f{4U)qF}Aa zpghpVbC)(N3Ql-l8u&0#V4w#NYTdF$^dl{}@Wp7&Y@Yx{Ls#-M+D@#fK+Hn&rS)1# zlkc5KiPQNeTc;dtI;_!#+Awjp$Ze5(IykJrKP;tEx)lcN)&zAzCnKo>Dkl)tK<=R0 zFc-mE(DYnl0kB$p0kjM8nt)3_b{Cg}{$@z^0>{@n@LQ9AZM<$qNw@%B>sMu_62qr$ z`f}U!xR0P{wmpEXT~tZUBBFcHE3S&#mNwO12ie=!i>+6-8cYu09fZg`f;9lDHKtxS zCBEOLS?7=*3?(gbph6Y=TR1l6EF2dYCV}N4y5>YT6J|s}CtlWjQH`Y3P{LNdwa)RX z-U)F%&Coli};@L~w3aBf-&9R-4JVXp84{F(73Xzb7u=tqa zZcm4dO?hH{e9W-hqX7c24_ssL=9-TJsQ4stmX(BQxgBCOWVWc#xQ12U93iBKp=x=Z<2$+7+H z`){{i?87Lq|HIRr-L01|pyS{GCysDdIBnzX4Auwj5^*QE=Nv)6j4BcTxg)g%KoxC& z%cYWEWpmGpC92t0n$%Jl(33Zs@UuT|O(+Cg@zzm96a);TP!vmBtNC*4-ymz0((oo=A`3VYO`A|9%T^CEJBXIm$(DpgkO*<{3A- zyVA@Fk~Q8_lPSN8oGEuhwNN_*Ia>!IXoy&WO{(oh`6 zlFcO*QaqE^+eGv25HW&cdcK&_k_Ivn<*DT#b|MLKAoagE#m!}X#_)BJPi~ts^6jE? z0a*tbRNZhu6*>G)AtgcFfuXTervX!4QpA00kN(*DcM&OZjElzdZMN_%FbFBQ-hS7} zb}Y>pHr_dhB5=<%S_ZD-gkNa_*kVL0Go&H3o1uh0_%*RtNYVt2c#Z3nSad_)r)Vr@ z4W2NhPvYxM!$O#K)z?d1Cqw}j<q~fXj|LZG zi-Ez-IZBGNccU{Hwv}omLIEKOAr@Z(NAEOmcn0za$!sN21W#-bN$f~--!V#K=y$l5 zDd_V}G(m*8;&3s0?NMMPyC4UGFkvUu?^VgIbvaSg)czzPy>FsiP0xle9bcPNO z2DBq!`~j6Ac8Ad}Mqf=|r^5@m+^f+E=Vw(HqmW`z2CXOiy{cNZ?FI#Jzk_IH&R5qP zWb=da!a!2M4i_vFE;{de=0yn`Iwt{1hDN0aoL|#4jm5NOoWQwLO(*JwGM}MT!uu;o znB;2zRGAE{8csK<5SFtE#gY;<4w6l1nbZ=GB($kMFubp+VXx65mU0Lw(2|myqABg+ z=`S#=q#}vH*uh_^fXu(tL~yXJWadOrcWDUyo^Uq?~ z34SOrOHyNmht>?Rn!=ehky63Q;EW>(xVChh8wLR;&4EGu3r$WAWDm!UPnecP({M5o zr)T6$!Bu(jj9X=y$D|{T4%b(G9E>?jKuoJK-@4|^<^%`&h;t}%4I+tq1o>W07#T=j z_^~}LhBK##av!!NwV+sqrC*>azc9ePy_AJnkROn*5`q-d5#dzL==6}DTBt7+yvgXa zme@`Yc~+0^)_suA{(+{nA*-OpT8-I|+hzobZcj+raMe$-{jx5)0Tc+x%baZaky8{Q z5;2puU!pOB&GA@kGdN?;rvZSKw1MXH=6+=m(JB>Ngv$t^!S|e9?%wZz^#EubjQ3`r zuYQFeIFPlvD)8e;zqc+G><-K@##O9cznzRokSq7)X|wVLaI5>z{qvKv-n!mbqo^>; zIT(hXt2t_+)E`$!^p3a1;9} zcWg=%*KK(7*~ac}*|hTkEgd|9$nnpCHJ_flKVdc=?tRridwaI})m_0iAfJOoTmdr% zrF3;7>d89%!i(psO}&)~{rvO1SR(fVy|-1<8r36OPwm~5VU&W3xNu?@_e_O#PpPbi z#fna23x+ti6RifPyzI>otQ9&h8r9719m1_H)l|jL2T`<2)YxE{mRt;GpgsB9UDQQ% z(6#mOzpd+{;;SlAOi9@PRjpdJxmZe%wp~V{H!B3|Jt)i}_>Z+#HxoyWR0?mk*6FLv%}3NxxUn=4dh4QnkoE(s>q3*oxIB39ZXMNJu3Fq?8p!CnAE1 za1wg{fYI1k7<`1ji@k}#%tOlTK0#6=6$LMQA#p-I;~g(fB~C0a5Tc-#A48sP$n_AH z9J-2iwID8`y2Nb>8gj^hYM!#>=Qc79;RxvwXcP`voQj*0l*cy5a?BKLLsReYkjF%6 z_ZBJaRQBjGY1y=bxLbuE!4KwNtXM#c4wl(EO z5|-05Iy`&=seeoCp*>)x89io&jI1qpwuyV%f6|XygyhM#O}^NO(2pYn+^cWAO^?SZ z&)ZPT76S_yep9^{>bP+?4F^CNv1)OEo{%dX;4ug)#M(eWge*p6Q-oHHFaPH2Qs8w{ z9~83Z3-C3cPi-ujv4}P^ERkX{(mvvl@3y$G3bmA7)*wKq9 z;B?G0bY_J#4<#?5^Z*vlE0`m+o5~RNVv2pjyaM!GmfYu{x%?Gz*8+XO@XA5Yg+hb3ujb%WYFOn~t+Fw=M@!0FZ;2w-v`+ zqX{2y02`V^(Rd-BQV9^I#wa(AKp|@Dw-y*FI<9dnebB-b&Z)j^CoGIvF?zQ@&92-V z0a=0LlgM|(MiO zdG6xK2S<8?kEra>Hw=o3z$|XyK`x-l5`x+ohAazw)aK`7x_bRJ6PQ-u>`Xu}J48+j+#NyDMxziTU$kA=~@6L3s`0Wc>}Nmq-VjH;SLUc?Huq zjo0s_O&G?p<&GN=*cPdnU0Qd!NlQK}2O;`86zx}mzS9S51^7zbHKjFw`CtLJCFB~-Rm zMcsgInb?ewx-KC9VKRcRGil_k+8Er<(JAA=;sV?Za-A4w1L!aAa-TCiCi-0t z5iGfAND+b(Cs#8^w#_WCMjENpe4sX^Fs#djJNq+O=#RlQz4g@D5XzP_Og}~@?})$U zh0>BDDbCYnU^dx6lxbVIg>v~Ixotc-mZiaA7>e2fBy7cS;zG{neyP8(DwGoF$QN2) zIdwCTG`GTJS{q3=1ir&>$*mPKB49hT8K@LNve=S?)g%#D=pkuz@z*~Mhi8=WVlg$K z#9#ya3vMa1xGNFNvH^u1$C5L=-{YlagHuG`YZk8A==gMyX8p-Uc!WC_sO`h)Dl238 zrG#gg{cs^lK&S^6tkwi$-GSn8>Y$x`wWf>CL{u6fJnrr&>E;%2#w@#RSd8Q&(qIjy>kzBM?DNgmzde5n%phr$xl<%K4lzMu zPlq9#91Z(E((m8abJ3n+jz}WWPOzFbhttWK-yW;Rz_(`)|9Sln>wnBv3z@kBYDKx2 z&LW{`hWCRo5)LmZm^2|{aHhMBPgxw4#Abw{;Nr3WbOJs|+id zlY$_&eVHv6#V9UacdxGweCqP8?1gj?d!cG2x7I|KiTuK%^UX}o%4kNbeM+Z$-DBc~ z124_D7KG{d=cDo7&hP{qMTTF^E^!Fy1eRIx&EHn*HjHl!y21jhnL5;`1{Dr&XxPXR z^Ty1iSIr7j%glj5*o8UMN?>yZ&AeJG(<6|Nyh@@B9(N>c@w;Pib=?FhCE@t{e(D#~ zB-Paxmg%q7xhu+yv(u{2v)LS{p*fB3k$BSlTJK@F!GZBCj#?>kL zl!s?gc9H*ef!m|u?u4Y|eq^^Z31>JZheVuWb#aw1ywFS--7R=md;TS^F^DwKY`SzE zT@Gh=aU0ZM4Kgk;Pfwx!Fw-xo23JI&FmiF55fTMjgd(dpTf~*nyN+;;_eem& zy_O~EMbB<(Fl$vg$IU{y3nGyt{B8-2UochCJ<%3wCG_NM7$HV3!0Gd4Jf9L#- zWZdf)?;fH2-T!eQ8{1tOL#@$}Ff{b?K^P<~PK-O8(eGkgR<7`nZtj^l_At;|!b|hC;I>0OT%0xI4|R^{9#mniAyhQK%TPKX zE06%I6RHCnY)21+5vE%pqgzG=9SxQE>S*Y6QnXVS#@XuXh{96pgJo#^1)`-_O861L zd-tbH1Zxjxt6!~1Trh$=5on)GC00ljI-SV-Qkqv6D=#*MWRMGm_ zrJVG8+v6dxw^E!_$+*+NZ+42K2=upR$2UnAhC6=c$4N@7#~Jy}G5tx^T%>Boa8gq? zg9XB(AokLL&N8o>MtFDw4H?NDqvkX~!tS^f@a5OWitQO2cxK{d(h+d0?RFAd(}%$4CK0ZxZ|&fXnI@NB&Cf#)_!8#A_-ur?wf{Rj+kgh_IZ zte>j>!FGJXu>K-~ypvqniNBJC$J&T%dwW5@7J*{!S`wYh-x17{zUixopdj=B1xZ;S>fgI@#mHKA<#m0(D7r~BDCl# zm{3+??O2{SW;m*IfD2`@X`V8e3OST{y!sx#N}yexHxNrrvjeu~AFzAxt#g$|#eVNs z9P5=m#q4Z6I`8*B;PAEFiz)4|%6aRN=W!;p=rxzi`~7T*Y#pu%yd{m2#{r$=DUqK! z+R2C(;4YgWhQ6_GJ&+wVu+*uVbWlu&(E^dC_2p3tKBqUwMc#yvP~04L=;TVe z$vmv&tt6vYdgA~5DE5qm;(juiD>WI8z-?oin*vmN#R7yi0TNBBl@o6SOybO%_1Wt} zb#mB6a3Yn7OGq%Ui=Jx`bSWH z*05nTFT!mqUf)X9U2WpiZK1@#*O$d0OwP2Iq%_e#7b5RpwWamu`DDf{7Cip17x6Kn zF(QTA#0laggdxYHd6+~6KJjk#<=-?pb3Mhk;7Qp>vRldGedG4hq|2mtT?(si{ zymeTGnX&@6d~DDgX+YvS8$tvGs^mGhHj;)IcX~5k;rL=ocV#RQ;41C71=tlM?pP4vCfsP; z)pOP=AmSP=@>*f=SL!8|yB~!1moNiU=xZZcN)=upQ7%0-|97HTP*i>vn08+VbJ*|w zZFJUaS?{7FX|Hv1q4x^%VPG?oXsq~Z2iCX0+up+=7qlFOM4JCDQJ0PL6|>-bQ9B}` zrJ7hM$`ioU+#+gT_b#U6-j9lAs!djQ)OFQHteQ8ZEx5W>n6@P<&S#@b>{`#UgS^Q= zG|PxZpU_ltCJL~1#dIi7kWqj^$p~H6HBd=1$WNuVGS5j-lc#n|ngW>-L)s|sEQvB( zQyZaAn>NJGT2hPv%@!_}(KrRReW#gIAX; zx6rM=0v(wpLSn0aIUs4h$RvJ?&^8YbaET(KU>|+3QJ_nD%VO6`p^T$YE;QsL15!6aFltQkVlPS20Piv|F9T&ls! z*2pYL`9n1_1y>BJuxBYBF^Z#{v_o{_DF;irHr;jl1V{M0)bnqcK4PGwe}i=3n9w_B z3h{%3yn9sqvakb*^#Tbfrss&G1e(v^x<05Ng#6^kIXM?7fqeu&wg?j% zDyW|#1K!eule7LCXEdq&T8)=KG9M=?M+PbuuX|-@GMFGJUjQTM8NXSjpEni>MM+&{ zR+O?@8T^I7ks`meSGao@FoUJA{~1o#{{mf;7f67!rW2fh3}EQQdL{ddy5~qz=0{k$ zGZCtrFgnX9tf=C;DeTIsoRa3 z950-=8B!I>5#G@hoD|Rljf>{NzsLnKH9$IKA_rL+x6v}@9RmQdEH~|t2^Bu^QPP3o z?Sks7+|rGSO*!%@R|xT3>>v)kKF@T*VFQY@1M@R?VvqM41R2C5?Er|&+ zg|Ub}6$N^xt&1R=AajxG8?umXV_gs-!{F3F#GH|PkW_`BEJ?+NSqS9>4=a*Kh(cCK zfVg&LIIIekuVC$r?NS|&uqeBW-8*mb>JWiObqmUvc|xZ0(nbpO^S2Rf(N}^XkgG~h zwt!*X!XO^py_@J<5wXAhj>O&W^j0Le6_LT!^x?C1pWUDzT}?_lgv3 zy&0B}ixX)ZU+?d;cGAWUGRG2wP`+cY>G037$@viImBaEOr9?(6$=V}sWvii8xHpVy zMZfc+FWi1nQdqJN@4o!w8(2(mh=UzdH8UNLD=d-_bExY*$w#aRdyZ3mxNQ}lO!4cd zdAk!{a+zX{xfuCmhr7NVZd-Q%dpl5j?0c|96$Z6=@sii6Q#9|8FjE@Dj2Pu_GpoP} zbh81nD=@;+(oayGl?<1-FqTFQ^-dze$SJb&PLSepbbg5i`ZoS0=U;IEPU2$9&s6iL1#%S*no&=$Ws=*jY4XZA0SID zlqlqjViq?Xg2GKqzI&my3Ihe>@Tw!oRU>uRHN{E9t4bvo2LnuJv&jKdP+;dG;tNOo zkc|sV-u_YHn998(N*i_mB8Y&GanGd8wBEXng-m~bf`-v~wi%EpoWCqgG z9EDs_?G0OgDN!$S%YAr^W+7>LkMbL`13zKQ+i>qHkIMg`SR%Ug+#iSJdxTM5SgZ!2 z#?pBJha_<|z?!S6WVs>o5#E0B^3`pY#G%tbyjOrliDqcPB(MZ(0vX`03X&!JHFGb` zKQKxRas2J9N)9D9fJsntI&Idauc+Wj zMvZeJ5u^gnS(4oJT6j?R8(`Q`R`Q#IEgp2(F=ae!ilwu5b5P=OZ$ z6dUCr^ioh&|1o7&beVW-@7RL`Kq|EryBsVju7JwNA0czHtX%CGcYZleo=uSFNcbL1 z&|oUKrh*#+hdckzjBe4#wGkl6PGv)FSP&I^CuBBG_9Pq%rc4lxMdnP1h!-~C2H^Ln z%`HjmTj?asw)Ms3c7mIB?NUg| zqEA7@%S*|+c*WBPTqeW9f(|0>vK^n4+1BYR3N28jja8YjJ;a?MjK~M(Q=}D!s{xiq zCe6nRIy%fGaxiI^lDIj%pxol*NZNC7>|}hwbvzp<`Rg;2990@qP3H3mx6P3N2?Ecl zEg>euqRr;o|I6On?>BX1X`}!5RVcJGGBma!oyqSVh5*Jm3Ec$v0m<~VO+3PuZ8f&! zkz|MioZC4Ua&GKA&-$pZU0afk>F${qbs9^1*Td2@g)% zjoJ#YqcBAwuR#|^prythFFQ*=Sk0bTnwP8`_0E7ya!{On*y}^3^~K6O)VT5HbSl}{ z#Oa^mH*J*PiH~^kCUGt#`+RhYTn4m5ouF(@&V`hXLY9ie+lrX>2AOh6BwR4V(FMEp zi`#MnV{7FHOS}@?U6zVGyL`jn#i%sizcKpRu;A#fF-YOcu0J4PIEc0fp+rI)jtU&? z1RdG9eeb9Mi~)Lzu7Y=zgSr^XlOfD#zmCf0)BH)3yFqP*-6F~}nC*2+A1*mEW6dc@ z4u{#@N0b{y6)vlfT%yxEfc6iAu_;_L0+$7D${m8(BWt%{|s z@Y%rz5=|S+h%G2ZB?{BUNM`^avD|ZNa(Zt*&7WK{)pb)#3I@rAXfQQV7bi&` z4@qi9F+#_FGFLY3$rg5;`g72AR3t@;&LV4)O>%JMDLfva^ke8^=7HjUW9u)zd-CkZ zou}&?e_sE7bLZLS_nUt)Rxk7!h<+9=34u1&PG#w&Eho6a;g`ZU>~!RRcjpR|f}*@4 z{~}SX4*lut11hVFLE62RZfd0MNt?-O6;XhbF79@^ya$ap;Kiqc%_2Yn38-ZoS2F(h z_qvcGQWG1tc+N|sz<`TDi4>3^O=|0x^!Er{FGz5KAh6U1TXQ+rHK)V`=b9q(Q^?af z1MnDOf(B?I;+z5}%UFF1@$7kQnZuGlSB%lw%$W4~MHDfWq4UIVzzdYoNVlzJnCJRhEKaL#ET%xW{itl=3$i|oa#&im`!rt`;k*HO|p{(XLl z%S2JFtqe7h$0v`41Qy`)A;bAtom1fVDz|W2H4s@LvE(3YCbJT*??|fs)qCjXNO@KS zb3n#E4yQB0MT&iH1pV!l0da8sz;T6r5jwcYXk@p4CL>^jH6)s)U;=J2!fK!T7O}<7 z0|kCnr@&^T`IGo7>E!i9?z%SRJr%dUld`pU7B3pE)>HlEs+ z^P@#ia9D+~|JAZ_yv|dUR<@;x83;2|3AyWH7fE;E48_XW=0#pbi;OU7JEF1yKYw{_ z1p)%$FGVBYVQ(3s>c!KUM`K#@LFWjT`w}b8awuk8Chz~1a4+vTPjdbS{7VRdyexS<4kv1q#U!srva@U1)|2NrUD7Da=-ZHDHz~_Q z5@nCfz+F7sRmv@%LM0vSpVgYx)Eu=pJcX~9ULnnE7POo|g|EC8Ydop7aMb(lEHqIo z;I$tingUi`V=(?c+kY&E7RuZ|`w4p{?xHo<5#D;LEIkX<=z~&K_>O18PpXKr{d{u7 zMS(lIC25J6bB$IYeuvX^Q58^5#3}vbU_2g;o0A5=__TOuN4oa<((m4nnlUBo+=_4j z4|>y{!(@*+eLPLY5Hw9_Run*(UHbOEB%&}g_2UkZU8j!+OGJD?_2Y!w(TUiunVd2Zs#+CUc)n>2yV(c2Uv8fAV<7Hia)h9CICwb3 zi8yTd4bN6*_4`dSSBWCGbUHq|&+XoCVPhi@bO*mHa3__;vJJJ;sBz0>YVWqX6G(L= zVreGcStuUzp-m8=*F zoyS4Oa$#5j8!k(va0M*Hm1Gq-S4CkwsvPMwv5UgG$b@mA4{p&T!xR!wt!@3Xwv7)M zh@3XLdKVA3?*9Je>NVt*COhfUJE)^aColpTGTZ>E_3)^OZU7)oa*A=B(n0!E!-ZI| zxJ#Wcut|-3;Bkhdi(FS=DFv`wzw}mqyRq_bt1mwc2-ZpiE_=UJ0Z+xGfw5jcGAk<% zS2Kv8Uk7YcP&##ZHwD_-J>v12{Gtk(R=k$9El*TK@?)mnT0~x?Wy7#GEbZUD)iFK% z)-6q3Qi>68SMaF-D}{v#YxZdUG$mCjydsbeTHyZ}dP1mL(8#_Nv2fr%3-vB|3b;5} z%yc+WyU`#oz!M*p64l|4C1e2cXEuThCEZB&5i3~|OMrws8dRx1+C0u`R=(>5bGnIB zmNFrUt(B8YWzta6DnAMjNXNrAlW4Au@HCjYjn!a2?xz%NV_Rcp(dx4@&L-JK<5Xnz zFDqxLsqplUg+R9CSvd$<{E8}`t#SRE)ytwpS%?ZC{JQkA%dyGrXq_*2_xf*e!lGy~ z&J-KtCpe{J%Z!~lQ7yLy0&A5}Cwq>Byh%{3X)}R=1s%hc;uS>@2>n=0V!?5F8)s@d(%7nFi3U-4XxINxtA=y4Jnc*aD{|{z4 zLWgn;G4dWcV;g^7m=y(bn3IOq`A=M5{zO?x`m6qA4o3dhhQ9M1&s2gVhY3yQAviC^5Sg9g zwp0x0XMjoq3A5v7o*K~IFC~rem$aO|xvkinSGsjDc&0ge<-lI_wV@|&ry zlzKDJ_4N+28SUVnx1ArJJbwZA39=dDaW1?4M6Gor#u8=`X%(fbgY3bM8QZ)srj6cR5CHM7f1q8!)GB_^SnAAo%orpEhvLHOC^o4 zI!Bdw5dk~W`~crlzE**ie1yUUjjUKfjtXnle5P3`=YUm`AP*defzP|(`hf(=Kp7obcCvD|_v`-N7w zVVsty1IIi*8V+|F%ptvxo{eLZ(b)(79r{h?sX^DtG$r6UR=9mqf@ZTRE$!gAXF!Bk za#YTug$xd#^{^-6r)?#2nJMl1CjG+JpZjI(d9ZAwy;V?1Tx}+w#BT-H{}e-XeUH4R z2zww>z>DERT~=0Rvu=Jl4dJb4oCzJl-_Zcvnu+e6Y_{TzMIg!b8&rr|dIl#Br_UZToqExEoQ8b)O>~!RhW0AdX(-izbv=ob?#-8z zM?|^iC-W_ZnWR^odk^=PS8gUtHR6@u_=%M;pj=0h5^UEHnU>W2urhi%7-^T^132 z4gr7D-m3u*vD^7wIW@o|u9z9#wAlj-p-Oj((`tSIO?$w%NBgbKRh?At~`K{$SAfkxJ4jg{n()3mcIzx5!lv^r1Z8pyXM*=0kX z8 zq)0g~f|QbMid()*@XMbBy)mce8gRi@hzM3onCjEKbP$g<<)p!UGBhs1fO^!!7W`;$ zus`VUZAi+fEaZWG^Fy#5h9bH_7Di4NIfQK#!FHEGXG{%8l*9$XH~ds=mF}0ux@f1! zoZ*iy*@n(jX;4_rpP2x>)Aa?q(p?3oIc5R}>fm1#GS=Rx=_H^H)bWHt6stj@(}fep-}VZJZun2&t&4F5hd zBV(I(>^>j%zWUd1Qsar0`KipW84c+ycfTZ&q}Hg;lXM@AQSV+5`)Q`WHE?wn@(RSc z$fx75N%cY~PNX$fBlBD*KOR1k<-{+#By`vGj?MrMvvLy^)NcpFSh&`QOpOsC!TcK{ z26y%#ws8qj-Y^maAURWLR!>A0Ooy!{tDwen+JI1OnAHzJW_I4zh>Qj2um*)-7Ph>0N~)pz*_|a5?PEQ6PhN3OPYo96VCVjX_NRHdVwvhX^F>e_ zLoypr+PZsAU{x6g0{sK*&>K53XKDn;>vixBVC+E zX2@4~3R`Gp$lkpAq?d}zl>Kc^0n%VL^nxaqsA9pO$+c;${&8tEWASHBqaVgv2k zPB+5IctwfgbGDwHlSnI!xoVP(%sVl4!Oay6D|4c7V9~nvIoj&_H>4q?b?xw%D<)R; z5^3?WG&|E3SVwu3a9BL~bVzVcu8!8t6obR_{5FH*2n0W5yn|tRAvfP7SmaNBu+VyM zMhM6?z-13(0==>`dc|b3*!6ge3t=)cW4%Pa*rfY>i05L<5sS#m!Cv=eJG5?Rp+QeS z0qcBlFmyYby(J$(bB-_X*)_O@`)0G~-;!GOc&b6P*0(svXTi9QfjcOKqa?-p(9h$Y z@z(jbY`txGQ8+tSRPRw^4sw@Iz7Erl&(Zm6cSX=9Nj*z|>*#3jcP@842Vgu^{L%2V zPCkeRn(6Lq5lG?=5G)iv<`k#rTra>Yn_WalE0$jim4pTt#Y?C#W4@~RsR*f>d~xK+ zdM=z^V3%KrhmhAIJk^!B9<%`ZpF`kR!4+X%{j6Cjz-8f)u`IPv0MyI39C?G)B#LY7 z+~I5IrYuq6sC*3iAU{o27iTDH7AITCRV2FfjkBczlZK2i3>f|!-eg03D>isT!gRry>}d!HM1yJ@~Y>8mxC?YK+6gdj-ktVubt)>Y%J%CHqvA} z!6(80f?$~BZHzNIA-F*Ei!#JsB@>R6BDn$s4v^tdWfn5qh?fN!ANM=2kU#IW<}j?z zT@4p?7M;va9TRgo^@3;;oCoYUGRnVYV;2QF#wMga0QHA(_`|x${kn2fWWH(W)lP@v zRc85h7UQuVX#7>IHyD4Y#ruWRHSic(*Yeeu`9tGocs`R$#b{x|61m1jJDWA_i|_zi zSDBJ_K0pMkx-W$|ioYuk+PZGR$lOT}0~aEhC25qw#ks58?dkLa^E+#It1B#GC)`mF zmAj=3v?kYvGA zA3Va{h>`;r=g!0p1~$!v)3BtN_2caT-#q;^b|JB&sAtsZ9w!$^?ZFV*#st1|=G4W` zr0qFk6Y^wqgk+Im_op~-!@W&>l}^Gq0K(hD0TRrk?W4i#KGHhMJsO^Qgjs!#2M33g zAOs2*TuEBADbjAg2B=7yGQgQf%ksy4SR@1Ygq;fGgb{4Ey9r_uJ}`5GF&fduY#Ii| zq=tPcz5_>ZZHXAeEm|>}Km#RB#|b4>*J~RL$!bU@-?v8L+e2PmB~yEy>}}MP<2Kq zfyvkOqA105p>vwBT1e;2(8@_@VsCwKkNfL9SYR#7Mm?4ff&S;X2HR&Q#f<@*jL;B> z#f!smGoo{xeOpyS2?*cLK8H9TPVX~l7inmvtn_zby>s=+#w@R}F#sqNM9dVvJf~)z zRWB8pZ$kKNwsK2kJU~1@~A{wVU131YnC8LypO$0j86~`ST zOtYV0O>1VzHg$&EF-pbnW~t${0(rxnl}SvW+?f>4(_rc_$4KI!OAPT`zwwMo0E{@AdV9z z&1lGb1_rr7Qj5ZCNkLpa-e4uQvW2OU~UhC2)C z$C|33(sh&pik(nWq^|y|$=Y;uT579%Fqp1@8Y{h!wew@Mo8?cCdfk_4a4j1VY2Rp> z#3nhNq1s3hCoV4;-@+7%*wOAOU;LZ@tqtVx;6md#JeV^KZ};yr3g)3$Y#d3(iewrZ zsB)BrYnE&}8!OW%BY_}ZndGhb-*Zf86{5Mb9Or!I>U7O=vckQ?7R1?z%b=XO3%1&L zPM+2@w|;!90?q0MS2pmZV7>>0;=UYoF*{$zid0j3M>oHW6DF@CC ztXx0=(H4$js2adr8K8Pkn*pmcm7q=v{A(}b3I4?!^XTH%!4%kWG|!&vFm(_*=a^?@ zgb|cvY}F}t92EF(0hu$($i+;w21r+6A|9P0acPAW8-5ps0R|&P1oG$W#X+)_p>zZ8 z63CKFGzncqau&%R!ptn8@akxMu!htMOk$ACJ_*x@p)^6genXVxt*-Q~3o?wZeNak$ zf#R~Ri+HyNnVqNB;>*9@>e|U#2n91euSzIk$Vz&7U{wrCxh(XZV_26nf~d08Z4WLt zaxz7ZtqdTgG=v%g2!v3^(33=wT|?8L;QiJOETMOSg1P(*2q9z;p(hIoq>PjyFaL0L z^_u44Si0F|8c8&j(Q};0WF`CXPJ_6ffLiVIoPvbBgz%;c|)+E?N`?J{pl7EFGo) z{JNeKw+ahpxjCrnY;$DBUmQq=ZzkUEyrG%w+F7};1z3}Y)TCMjgM*AZeW*;oj{Q)@ zxHg3a0Dui)a8Ph<{}9`6UP?A3e+51gE24`53R?Fh8ChL(NWr>PNB!fUT3^A z)CNk7_O=pqi?b7sX^G8ELO6BRH({)im!QCU6Ym*7%%UrmI;^Yn#fnz2UF*(>C$Y7a z%SfMybgkmMg5`t*u^WD@>H3;ZM_n`*myv#(%`P719H!)7u6P2oVa*0k42|Qcf6&|2 zV|lvk21j#vZ+t`c)@&VF6b_XlY7-d?vN6?Ep}0=iju^a1)ls8~SP})cVmO;dhdEu< zY6{MMyn2k@i|31$1tXI6R~R#YIv@AOV)bO2iJWZsUb@17DK!Y(Wd0yiVR z%U~j0u^BHV)$PYzZo?+r<2gAmf>@cKSr}ND0JgfZs0_h=&K*LP0o_EtFI@!|m+sRp z9P%bt!tq4hlbF&XnKXfOg9g4wrc1+mZE>)4Px zC@|x?d11>3y8=0P=aC_D5?u9V^dk>&%Zg|$xcE*^xA5In9Q@)2a=PuoE5En8s|cRh zkwvhKyTw-#q=_;MTm#M-XkT%O@`Al+Y}sfQC_AeI>ZCObLR4KX`Hc+R+4;Q}ytr}3 z0aw}H(gZl+AW&SQ1Ts}N<*IW66Q@gxIE-=GnBprb87sAtWe1G~`q_$NyR+0`T(X1+ zBOwU(E^(F^L4MHMe`R`@-NVsq>|62FTmLxF6PF&Yu^EvMK_8Zb^9~XeV5q^O+O+ss z%p?s^Hg}D@EjDk-WBrld@Qxmt;kEnaS6_>k-zX%&{h^bd{7z7S&1W3T#_+yPZ=yh` z0ru&b?^Rx|tdugZ$v|Z?FwE~z)3cXL&U3UZ$>l1qmY+(3btyK%l~2z$cfNc0XmjVm zlmB@9=*jwnAasy&1>b$(1v_BRi6k#FMV64WG(W~fiqb20z;>|fw|j_5tw1a+R3o_n zP_0A-xCGtWH+rvUr125f($e_5oc?7fmV~ngjsV=q!wDb*1qYDGc`#Yb#+|9e}f8)5E>jOlH+hv9^yg+Z$`)cwrhYAGMei+cQ|DRRP3t# zotnjo<2-m2b2n;pI=x||P`BfAdwX`nO^3QS>VLyxB4a7N{)y9nqTfUD3VE~13W@Wv z;M15$+d^cy)5%f4f3ke@20u08WFdYyiS@%TeA@yADCxzM2TvqH*JQT`c85D!c%^|v zLBU0i3tL_fad|Pw3tSc?hCp1Nb{=;5*S7v8W(E1CAsB{d#~{SU3L*$mId~SLT%Pl` zZRDT`O2u;b1*6Dpees$~2yS0lkoM@48id^XDt9hZFyV~bxWC$Yafk>oyXuP9AwxmM z89J05!mYFd*|c&z*kibBZ#u;)Kn2{mJU$%`Ia<#pV2g)|FzB?$9rYw&P8UKj_P^!amH7W{lh?rw3_jO;$>iXE&l1Xey6 zt=xGFJoh)5-ha7!+iKqVkKR~DzmI6Dh8hLT7yYbuZ?AdPT6BH1Ya9TQc@8v#RxSWB ztKE5sf0~glRQUp|+B^Z38g(ce^eL;+T~TezQ3_3Jx?EcgVquAAk3Dh21Cpc*5~cwD z0q3&&ROnhkyiFTcED`pTp$6m#yq+>a{}#<6ee!UB#r2St=WtK=MQv)3Tq!=~!!?r=5l)Q8$5+w7M5JVq zOP`hVl{>KdFF`raxZ)?$poJXMrNDmLXv@qZ7LRKAIW%TpO^ayCQ33@@&4i(tbu~S> zVdFH#mbbW=bDyOJO_~1pf0^=o9<^}+#je8!-8MOSY*)V- zS5Jg?e_5SiORpQ<@O0v;EwTKfGNGjx;dQ6Grp%Wz+ z_1#T$0rzUiXJJ*7{>X4*pWa*=iBUGq8nZ?fPMGV_3(ptplgD=^Jv!ZmHy!ukcs~ow)9Aq$D%M)$pP#Q5zl^KJjbDa@^I)tZd9K+lh9j@^bmU~_xrum&U0A!NT@OF+%<=K>-pTwY0+2DslyO)&dagL!1^`gr^u}sDRz(n84Y7_%jilubxlHbqmy28V z&OJyHq&v4rq_le8L6M_Ay&bnwx8VX&?Ivx0j<8C`A&i4nORi(<1*e^#d2yVsl#-D( zwy7D<#36(oAzYtD|JvJe@8krlHigkp5O8JMxD0qEdg$$PkT81LEadGARM84gGD4<`@xR;Z#W<(iD@2nHXeil|*$5IWbL^7i! z;QDOkP6DhF(KM;z8xG94>-=D-~n z3&Eyt5RdA+hF1v^bt1MRc`LJKBc30+q{%>*c8}`{*JT0+?5Cu3M-d~0)ajNeum89i zvxwt#K_rt_8(#u;qMQ_SGC@Qh&6XXcLK*MSK(S*kT^YMZ#WH}y<`A)0w{o<6%na48 z3If`1pg-Pp)iy&CCmGz_XIt2^)XSQl6je_edY@BoR&(o zi?=w!mBvg=`bYbv`WI&;*0CVXXo(A^L|LDMUPzB;!9=O3=9g(IuO-_~Crn%X z@Vnc0k)wx(AZ@)DG|{k*=UJ*(o#1Fmv^sr9uJNtoprq*a57 z!<(VZ7l8~#2pD8^KF7B9yWdfdLc}m0`k=QX0j1`$CXbQ?NO9%?9J0Obqq?KYZRba) zuK~pmqvPLto!dwJaft8t4vu?+qi8&b>gYXo5CI70gjvm%s|HzED>KK~=h;2i>@w9} znD;+n19hAKe23-m@4w65nH1Z8BxicI*T>`DnSO66_~7*Tq(9bz`aKd8+n<~vkKl36 z5Hsh?pQ+jR7%toS^XcCBj0E(ia~lEgmGfR_pgYwLMgs5cA*tcys*6Y8 zacRWt#66dWBH^P*i`Wbi<>CuZhO%-;E`)+&T*@jnu2K=A7)K+`10=2~(a_9Vmy_DS zVyGK{h`SSDz^{7;{Ye7^mW?sl+dmDFSsC{p^!FqhHHpZM2e&YMtZHjfZy^mqWpM(^ znA=p;E)r!KfqFPZik3m*l1rencPaJmarY}d4@Pnl4dN-X)gfLC=BcA2kE7EFxkXQo zC3KtUYI30m;^*~HPr}B;1=2Xm8nvAO5)~W!!QFt8X8awgKmZ=E+~HrG$I&^KN|B~G z!BHQ2YK}ZFoDG6SZ78K29QUPqtc@#fv9SLjCJxXeTG6TXWf8Oj5el;0I0I4J>ujPdJeOc zAwI0!Y+dWfB+SH0f8MjXm~#1$l3w=O#Q~IX3)d<|ONW9EokZ?F#d)dm8=eTE4$R$i zn{`?*Oj0k|idS^ItrMD0gm}Kub3Uyhv{z^b^E8LffHxmtHwj5SLmLsMRM-8i#-2-! zwLQInRMC!VDp#gqUU1f_>}cC@?!wepUw)qVPivgoyccq*X`B9uNqmKc;GpHScR+4o zj3+2YJWGtLEXY@Q3K5CZ^)_at`oeuFI8Qg&-$#D);S@1KIB&Wxw=%hag-K0I+-=}R z2`pN{fr2Ax1-1}qjG~xht(1Xr@|ks9gmna+RkiIQvejeDpHXL`m?t8MexlPUydDe^ z8{54!k5;DABo-;zVF&^bYvtcRh^|4clXw4A_pC7+dpiul%A41kp zX$!cyo>oZIZ_~LA2v}A6Ekrf)Cgh-?BUbAehkf-FG>%2%+6Ykw6##g4eLcrP#5;7v zF#wx!~0BImx#66(g!E z9*E2%_RuZFEmEO4Inh%Fm0#H&ZV%mE(xlQ`+rul8u{9jpwKC;Fpv2c92vdB+t@d=j zYvHr%a4yv$lPw#@d$WfRpKL#T5)`!im}+7d;vYcp?A$RPG`y z%KkJR9Bn^6>P@-%RDCxd?V^*-Uy&UG@r6+wimjfoFO*(#D;K)pi#6u9c3iVwyeWKrq-yz$&6>kH`TMKf;)*g`|t{^aZ!f&a{( zB03y)B_{)D%hz=W5v`qJLrjZe!)?&t^EU5sTa5bqm2v;SPY2`vm0OI0y2f?XxpMnW zAL(4ich+u8zbgj*9Td89?Fx&1K(2YI95+Joa?4u?O-Xa)9IVPKI<81X>4rVwKo;Mu zuCC!fc=n)qyy+vK_4IIUI`XSC)}%|;(Qf(eygjV-UQI^4xasfH_=I~my(1sNWKGfb zabuW=r5v?()Dh^-a77TV7~SBVL=XD333&cPas84%?|~eQVC1L83_tH3pZ1U7llraS zxs98O@ndz2AFcaUxZQ7v07_CUHi}35xjL4gc@^KYqL+NWYMA<(lr^1>+igaUG4b_E z&~YN$b3M;DzSO(j)HbDd&WGv^fEsvnPT*Bissw|(*q(&dHBE;A3#Fxd(ZlM!k~2B8 zuJ-seXKeLWa0G;W>ipds1vV?DN+8#IqG^CZ@dMw2{K;du<(Y2A>9C4Yi2y>1&r$JK zt5_SmBEzhN?Yzy`>LWt0cZ$xg+qS+d?WO8(8n<3o8Ri9-a#t^Ni7MLmj7yp(*dH70 zpNR+OztGTsQ7e;+uOx&*k|fc)Q{Xt=4@-0?Q}C76(_INQ4O6Z6-xYDdrBy=bsNpj7 z)-AmhmFri7))n_Y+D3IFG3&ITN+fw5CAzNln6D_SnJ-1j%mH*TauJ~~D|f7$>yqWp z%Bn_y4bcWrakA06>;UU18U^FgcS{Q#Yi@PzB~Kn9gJkth8kZUnJHu3L*%-6HdfOT;<8P>L^d`JS3Th2EgoQl!M@Lj}80-TD-5x>d zaht*0`~;ier9lQf{WL!Mk?D1Kd_lI(K)01urh+mg^4FU5vK6v8x2+W z%(3PxiPn;ZEinBJ!7hM9ng<4USc}^;TqHTP$x4u#rv0I^$5zx5g)P|1R+rIQa!I{9 z5Hbv~zb@59NfV)Wx;1Y#igzPnMk=r6@+u^J(pHe)5P70y_{gjeZ-*Scb;pG*&#PDS zc3N<-)x{;9!wJ){t%QZm+0|8Lk4)fkF#M#P-*6eyo3|t$^Mjz=K#$GmEDv!6w0w+> zh22~Uc%L2?10WpkP)Isw+tw<(O5fat>5ju+E5}GG&>t5!yOhL*Og*?o6|HrPf*d>C zOnZYd0mMqEE*~aEUB%62T{*~lLvIquST+M!XnggTc>@~Ep@YuK@MdRa1&K7L)3a~C z{DG1F3Wj5#T+lfVlnl4Jkyv>A6dKs^vb9s7Fh-4}4aM0}xmiR&6m1xtEasw+m67O( z-}hlUYLE-uF<`H_4@eC@@>w;VuBxn;NJmXdNF($BMip+vg^XUFoSu++C!K?%(W_T@ z8N!crAwt477PG>3Vk%32QQeZ6n>{wPzyfFO`I5oz1ttY8H`6m?g+1_+A`Qx zSSNjmx*p7GxRS&$MgS-e$IG3#$nJ|Z>jgr)2BL6~o#Woga)4)f39hJe=B@ZxW*6fM z7iU#iInvwl8ZBu?z9&=o;kuyBc?Y>q=le%b?(h7#{_M}4_xkGi7326tb;wo;mG2-CTdx*`P%UiC-uo)Q{xNF)W z5Z3)O>D@LglJzSfKHGf$0ud1wNt}R_Ei(vbY~ODDu>Sb*=A)g*&&gStPlzCBXkc%;2e%8x1$M&pqz5Brn9ka= zcK&nc>H5Z>*S|+|4z|^M%I> ze#zkSyd8sO;qe(Tz?MuNrdrQ1m!w)UPiBy^I=-C8mZ>XXRsV-x1?LcZrNk!!z z=u;69ib51f#&)@t=}46WsxhTtfDWx0tAi?tX(%#thwepeh~F&{EutiPGo}1WyaDY| zv2+s)i!r9a91VVZ8Wk*rbL@%R8SDLIG~COw1Sbkz6#qd?R(TKEM!0a2xu-MEmRE^8#A!fj;`Rkx{7kJ*3CPSH*cX=Typfa|X|S;t;f91l*k{`1i7j^UiX}FJ z^f$7?@O_8M?2fK>*LG$vr|X?7<@&sG9Y=QVW4-P?ezN)O*^_4=cbz}@xPT(<}?rW0nD)AeEkp6)r4PsgCEc@;wpyN6r1MK|Qmy`dxO4U#1B3YZw#X)>I zL4V#!Tzn_d)jQMNvKga#a6w&6RWMV(9J3 zdceOrY8inV+0qiY;TS) zGY+W<&bq`bULriw;2eMwEH)wX3^*>O9ic5)%813v)VC{uEGyhR_iiXRTJSD?4nK3S z^K-EC7^uSLj5|RDdz58rqf#~Jy+vxj`UD}6!0#8JvHI$CaD-Ae%Uy7c3t6riw^U;_ zMBU9WW0U+$T;R*yU&Wz^lQL8F)>7q*d$F9iZy?3^9MQ& z6r)?W(u!gxCE5n|T_)3;H?(iCF$Q$mgglcsiUzsyAQAjp?PhDWn|U=|o)iqqR<$06 ziXJP@?k;@+H&_2C*vq=gebH9#s|Cy9%4B9clo1=~)%I>A3lg|$pv7wDd4q+ zzD!;%Q{{zj+~_cAQf=5uyC0?63n_5FQgd{5zQlolT=*lVZ185|o*yzLyrV~Dv^zSQ z@NlKh5v>~D(T4|o)*OQSYB?1~@-i#BfFoAIg5FxHj566hL7Xld;Kwzl2O*SL-88}m zSMDg?Ra?U@YX2vR4oEneN%Dk&k+iXir=o+zh9TN7At(H_b(erJXMJ0J#1_kL0etcK z;#TLWLOsFR5Lfx^vOS0;e&7zXm2K@|*>u|6IH7FlGmx~d9O%m7l`!<8Nw0Wv0X3aQi^D6!2L-@;#;kmt%x|PDpg5)2_uQcIqe7FiT&|kp2F_u zq)A?i4cVWNnzVik@bYEVHM9tYTtH2ksaX7-JI&AeZMnT62olYIybB(SH7Usv=0%(!*YV-LpSeA?n z8;J+lO5$~b-FLru^B)G}7zS1iE>=$oZrLxcR_SWf0mkF2*@ZL5*@PtDWK4Jw`@v|x zgP;BtG)Ve*hPdoj;3WL;^#rac(E~X~I6}?qlT6#y&YjMU+Mv!oporo)p<6dz76Xif zO9ti)4M|}X9iKPMK6=B(s{L2bLDy@GHzF+7m<|f|~ljB9aDL@qO^l4VAEX< zVJxhZ%vs^bi&CYgP7|#s!)l<8s8qAr1Vm{@^#x72VHCn9V`okIXR|Vs=&Y&e6>?I^ zm~4%Y5~}t^$hQUU8D(0Jg1WLulROQa76m#X&Neibl$ukc+?n0Hpg|^p8=OII{QXF^ zh#1J0lBxR*vJ=wXjkMrIS1&kB3VN2jRHc>HOmpHq;tpqocRh##Ia7e8wC#FG=|plj z3+~nJPFo9NcLuH^ttCT_t|WPr5K{5R230&QM^U^^z%Jf2mh3Z&^q5I=gwYmpUG@c4 z$F+`jh9B2oLrGybm%R+#A+}*ryxTLCzxT-jdqP7S-4?PTiqi_twa`cGYLOypUDM}8 zK5W_+l2jkRf|0o}Us!0a-UXVQCCQp+YF#9WY#U2N2bf-Y-Am*q#q1?ag}Awx4D^}{ z%fTe9sSq-)vT!^@7E1p{!au9WFkAK%i7R*BM4rP6`~cMwF!dbSI1m^&J*!mnm?o{E z|2C(=-`eDDdCLY4gK(*#Ce*kbCfw`#U#}aW%9()|h^ToHFuiLL0WL*sz zinW_l%2LrH=P!QpC-K+CMskr6%!WLH=y!oGT%Aw-J9GGWFpQW4r&W26yd32lW+d@- z+3egDFXy1_qDAovgo`Z7WZCECvZ4M=!Z$!l18OPY&rDfcwx%0|w$Gwr8D@)hr-#AJ zSb!Cy0^Iq~@!T6J2L@ouCrsG`%>YPP>v{ZNG)@8l$&yV*w9ZryXy+6uiNkRb3r|aH zD7mpiG?*FoD|ck)>p^%d%2HBHxz3E*!JgLp?H>kT_)tgO5{86r}R#j^bedx->P)$03L= zid>L%7e)AaNZG**I??W0cNM#^*ePJ#LYNMj$yIn}3jva}D?9j>Cc@|FyZ)?=q_XJb;Bo8b+h zO->2SXP$kutuh|G^tP2DML&!Ulqj%QEe_QjEeRA2Wj%Sfkmq5M3HA;D1`o?RJ6XB2 zh^w=#GtcW;mS5NbT2@@d7h2Xy-J(&Yryc2GehGQTb&xd^w=QVg%vurAv@qubdWqZZ zRfkOk>a1qUl(qK&Zjg%PrAhsKAx2nq|ML81PTo9lwv}{d1C(okV^;(rF84(Ixc8@u z_wdq3(1QM+1iz#iQN(9q?yd=Im+qN3rD>_w{U;f+m0WlV(@Md+RhjvOep!W|F!Bq# z*1Uz#aow$E$xgyd$!z8W)ubmgOCb3P{e2H|Q(4rK<*RnO0ohqH0_8B1HO8N_{6fi& zH|I0=C#HNXA7{ETQ@pw4O$(=^Fi0ER=TMl7guc7StV-Ey|(9282BFt^cwym@Vgg7cbus=Dn0 zaGqoEFEBrIAmmg!Y@Z#R7j|%pgUe>-6Z1Dp&62ZO-cVCO0(aAJ+}@FI1~wU0jcvkm zgVG_1NGF{TT;)&Ju%h=Na;FpIsyI2q4Sc?(>>N(i1u}&EvlO7|Y#rc`%842)cM@%5 zBP^G#moG!lUaupyytf5dor4UX=54g*Yw+=cyLdHS794~ztk4K~Q261iM_6!*Ve@IU zpxB**-dj6f>mvnkduBk-S>oQqJV15cKHb~^;wQ4j3WA&ias#=aS<{7C6RpGZ1r}dy z@53ZmBzN)JjEz+#3*)|?oZJgWhG>6w)97mFA^kGU!(z8C8CT`r49_ayR6v{W2Q8|J zEtDLTrp7uH4l2ya&qEdpQ`>%_v|j2&G*Q2ZH|jYMjqHF1#v=Ar z0oc^~4Ey~GI)=O^!F#P53W!z`1T6IwB94% z`1}5Uzdz`|KbXEh>c2mlUa_MyJ(M`>Pmp7qpKJKPsioguN%YezlB(+4D`=TQ^t}Pf z?^oRTZg}XOSPbR|KK8Q?ucX5ooQ>=dnieaj;@SXi@s7?TH>v$j+rXG7Qyf^{71!6z z8`IGf%o=mjrH6OBz@wb%>3;hyj}rF(JNukB@ISH%E9TR?&I!nlV+~xdBkVd8b@Ow#AS==TegMNz!wR!4VOBx*TS?~ z!&!&K6;OPw4YdUoi|d(7#umg&1{g({3*1a_v-s{I0`dY)(T*k3BNHJ2{Os~LOBW2e zi!)G_58Ft*1i*eXuYz4H7d!U?dhW5FW#c z+f7Ab3xLg`L~ITrNqE1J4<`LPb6}823lFTz!u38r32dWD1vH%x%IV5W4x6A9OdlOGQ8OtQaYM zPxn$urA<4H)wF0?mR+_fLJki9$`T1WiEB9m4#lUBIS5L=sr8i&Er2Dvm>3epqO{3W zGWNUH3Lz>bV_T0b%g;RNsHLzDRR_Mn`t}z1*C(jHHnWn6>h#r(1_ua|zep9IHsRkz zoX_vE+tgIN1^z7=a>$Mht2f$W+(m zX=pmPWE!Dn?D;YV3d!Dwkvtk+Y^a-F{eQ$@C#SE>0KeF1XHG0E9(A&(Q4v0!>0i)- zXb_Qw{y_zIB`P7Uw-Di0RVQ!7Xd9`p{aWMk97N3NbEYojz0PPOI?cRr{^Wz)$R@m7 zwiM>FXBKU`-U6SlTHx&3*_{ZPAkwm@mDN_LVQgr=d}xygOEN;;Y6-$)tJ|9*0oJQY z_vKc1macCyQ|?J}VTLH7(B{k5q08{ARRSI=LuakZ@cEda#2^>76qA*AAxOAF7G|e4yEaAxxoFgS+WxI<3(>@OH9wbhz?ltg9PH3XrZ zArg15#*=hLxHHKdzSyIvl<>_--wO4mZV}PA`+baEFad+0iD+l^X@uDKHZH~8x~Lp2 z)c88PBX%0godXoKxxVfXlEt0OxKq5BPD*7gPGqx+|3(CDtB2F_`GWEM_4S zug(Hvi*?q=Dh+iLtsA2dUtU!qjSXW|!6Zu7`8joG0zwhf)Lg3|){7+=suxJGlfj(K zOfrAI@1x6eamzQ-x2#C#VE?zRM?>};t@eN7Y7|AGv3=3q)tD}9uB0ourmH0Hw?Z`$ zC2?Kx#==4AmW&cimRf@=)EkcS$ZI7FfvY|3wWc9e*WkI?1UvUnqTr;RW9ir)MP0>l zHbDj$%jV-tRxo?Jm@V%e)%i$+W!8)RL->&dBE&=(kr^q+D^&rL@z9pJFRB6`b*2a@ zrL4Bwggf2i!H~O#$Guly}X0JQ9yw#piX zN#HA^5t6ObuNK@obEH1Oe7DN1TUb2esnsV%57q3v7v;RRFW+;UrmuMBm-AS`3 z{DluzUkZ#?T77$REniaTT_!XAK>S1`efN&+waNXL58 zFC{M|Mdg`f-`ri^-g|fR`X4`BUEW^Z-uuH=Ngz%f5f>g}%Z<#^uBDC--Y{Wt>9q^Hi_<$Gq+zU!J4x*LmHqL*2q!aUI`K5UIII zBFyKk@9kY;mNV5boi-|~aNQ3s<{Rw}5ZLnu39848Z8)5v|69E!sa}%FtI_Dlp0$Wh zi;y!xDSt}puyHnnZf;`MwFcQw^ZkwR-pBqqI`zWQsS-GEy7$MQ06G@;0E83oL_fOR02_> zsKLh;Ga^h{E2oKN%V&*tlcBME^0QIY$IWv7T?;jt{XJu*Mwh&A%0}n$s}iv~bM7wX zuvWUJ+F_zWKM$6tkt@tOtk9UpbKxhMf_Wf4h>1k!fRr?PfhiLzO7n=%1MGQ`=5!8p zbt*j<)^bK>NMe z*C>)nFAv?p)uQP)b%_Oi0;Z$w9Z~cxDD1(zy*VQ-x0N1b&B-2a()>(1%*0`6UnE=# zVvA%86-2T)bPYL?4_Bp1+WI^ORE*DOE;Ng?88ZioWu7-Nhx>$vB~{}*=uDzHQ~@XR zKzi=@ngdN}&;j|(0T$-~SXGSMy zQPWfbuj+r{>_HPn*=ONyEV*8Fdqa0XG(}5M*4t&a=p!6?v)@IjmKK$_WW(QlgQP|e z2DrTl!SNVs@w;f(dw(<-B2GPP$WXNr_R+WF*P`f8)4|bpc{6%Z29@^*2gSqhdb>E% zbA~Ato$XrZz8(wobFn9?e`%nsSc#@u!<7z?{WZUNF-Zd%bWNU?ppLi4`IT7sm3N6^ z{$b5i$x;>nfVjVF;;!d$3%S&-R#C3+s?=mE0Iq@$=m9rs=x^<#;!L`so{G-t|(f-oCcx}WeMTxlPkn4#v&fhJ0L zH^y@C=@*uX$=16ojj@7c_uvgW?!CrVL2qwwzMv*0a^mfvj9FJt@#dvfuMG(b-phR{+qf)N%#sXeB8ochq>a;uUcoZ;a z?tWROf+}=iLcPp4k;+@OXkj@y0f*j6*#%-L5PniDEFLDQ|9HqRAtGqtY=^KIP)+>*x zm9F<@5rE=1)OS~#ua&$=Bc^EcD{lt8KLELYt6t+B{AL0~N1gW`D-(1(cxH7Go&~1I zV=Ho&u6%ho!p*2n_%**Z4=il|H0=L+B9}1!%#Eu}PYAx;_4~=uQ|AEg%c0Pv@T5RC zXLRDu1UVhAZXvL}Z#!c|;vH8;i_OHfG_1><2m{H*=gU&Cr>!X&2sPZjg}cdwz23UD zi*rcRen~YUoDo#W94#QfgfOhDgx~?EZAqoGq6JoDtrG8WYq!5 zTEsXEPI=7PvbV}W)sValk`7;qrBUn%-BrNgHh^pQ+) z^DY2)T~V=6tg=O>DCA|VX|DvHpOA(=-eZA8`VAJLRm)-Ce%l*!KmATQMCO0b#))L( z*#AA+lY@}2`kkW@0NcYIGpkFu9|5!aV}CN~9RUBU-P>#4ESF9|5200eP-G!-@5_CI zbg6qj?{pomyh+B07R zd`8rB;s&E!AT1tnjN;0B3)&D?yCQfCMsOV%IYpYYMB}=3>*vj9_n$o9 zOqQra$G;GQm2>ZWlL&79H}7Z=s+Q{m_`b;EG4H{R0)?G^F2uH)6jidR}vg${W2!2gP>#|#6awDJ%K zD7#UFd$=J2d`D%+GUDdp7oHq-q0r)xx-|ew;j6+bw?Me!DU zrCJKQkfiy-M1(>Os6ZN`1_onmG(0-%ygh`nOvT<yRbI!e{snhS zFgt>iBstmWHU6a+z{l5hAAm0v{1t22%u3h%=(~{Nsy>mFmakwvt~sZ+6i(EuQwn0N zg&dfDqw&rtmk06}q1?uDI4>=O)inkRw@XXs8KHgv=PI$m-z8D}@2AwL^w}OlSo!6y zh3SBrc+qsgxLFYwbL%w5!pU4L!jodf*o#1uu|h2A)`Cfg$Pe8z_q!>Bas^J!gOxil zmT_ToD4~a&ZKEqbR;WU$_P&n5uZ*~6v936vWCX&}oR`iTHIL^A>yFKwAJp{3eto>! zP203{S?Lknkcgn3MT7t9aVO5}8n#3pSt5qqsx6Z5k6rmZ~=Fj@S`TKVT; zF9PGl)LuKIyxLuXjEy5r052{!n6Yl_i({eLcTpL{T(;5IrcVWP+)Z}yATxI>tkwHi zxr1Zc!YWj`I2ybf_r_l81xBnsao7b$raiqsF1*zsM`eD>wmtB;yiazz=@KDH~eL< z|LXMM2RN#Z8u1$@ArSD8vFajt!AsfSu%F&i%sj6%14o`7ogNH^+xn-iL5a3_4n8>C zCFCAD;qeFOj3zkhO`#|pW3i90EskJ}wuk}?69B`3H}UDC^%vhgdG_PZ)Afx%uYbR} z^KA3`&A&jxb>IE6eD@Ys5B^>G=Id93>HC$z$(wK9ulzQhyk8NdU%mVO@bJy?dlbRq zcn=wMb!F?9wU>Xmx`cx_=IwGe;6hJL1bdl8_=-${Gie0jI7W_N?EH`5ob1sECRw%}k2m$b9;RjN@YCiz>$rZfw8kD*PU*^fkyM9vD^uMwxEgY37o|k%WqmuoXXsKeKZ@I5?bk`ivzo zi$odCR2m+DzZ{4add&pkz+0$t>VnovE{tn{rxY?Tfh82e^`NRTfMgQd*HvjbQAw314$5nX(Ne9 zU4kfXBM_!TUW_16vQ7dR2bdK28EL6Mo-_SuCY^Bd7$V}q=KY_(FL@RL7j0n%^r}uQ zHU`11x4F<@u6JZVL4bf(hNKT?$FD|5xEnIAXlYehaTc{3SL?m#!XX-5Kw z`|$CLo#zk#x+(V5|EZ1qo3CdLTy)Iy4gH(17aX~^oxtBd-QRqj6ienBqL-|4{W}bF z^TjumUfdnWsc5LI+{ZLRpunZ2h~v?(``|W{CqQQqx-+a@VoSvMF z#@N&nC1QdI>?6@&y;2nC8M!$ipf~I;xfOv3L4?gNcR`ZVos%h2c7jpex`jetU_X5y zcl9(Qx-hv9q1exw8!G*B)5G>Dd^K;R&lMS|GAY z7)wHxLdS@pJ_6`Afr#JVKSEd|w2?3#TEm+JM?{;z&cXEn}Kd8AA}6L(%vQ zH6(#ID6l|h=T{XAPz8I?n}L$?RQ7pCxP{EjF^rE`{34*StCdKM(=JupIsZlJe1Q|8*&0h)>DGweAMf>j)duhuvY{19h=lA z*E@e>I1dp4)Ee44X%Ub>uD=An*p3^N?U6P8jmLZc-gcG0Sh{!L< z4IA@W5vLRO(S&dd-yR#beJVr;g@a(G; z0MfYt7EmO$sBD7NotQAF=?1LQ%om%d${Q}Ioqk+z;<<)Cfm)4HS z-?U|Xu`sKIxA~1~0uf7@F7`x!t47VMsL$BZxSXO@~E}t4cfBxwGBW$Pj@#X5>?a8&}ts5)< zwhGH`d8@bb+skXP@FZ`Lb5?}?$P~%OD3{} zKhqCbx(&+72nr`WS~!3v0tZJC#Y@H5Jv?B%9gkrBH8TFRHGW5n{ndlj(Cm%Xe_Q=O zza4h|h`T*^J73+n`LA`_VO z^Di&j_$RjBQ(0cCTJLA}@;2_C+<99fzNudPSnNIh^4?q9ttE8#VwMo$(>C5=GhTx%fD_pfl$67gH?Gp6ok2U=5+6u{SqHg=e<=_+ z#UAF_HwpbsHb=5Tvl2Z1YL5~7F-Ca&ss>3U7!HqfYd5~XOi55A}9;Tsxv*#?V z8P~~;GIe=2nWjj?2`w`>-(+24dbzdFb3fJqoqj9@!`9+^w5x0O$4~phg5gq@k6^xd zPg1a?yoEAi1@kzUl;Gxhe5HYR+6?+%g7P@-C5(>rAvps=k*20`9;(a~l7t>Fq%zc? z4Q$!xM%i=9lF5)G>m}C7EJf82TUU*gy+24^V)+NbQkJCns+h#tD6k^b)ll;tG&CA5 z+wdH;I@1~rbZ->E$0!~S zp-xB!ANu>8ZS3ON#zF?GEVy)L4zdjqF-4SUk@aUz+O9KcPAq)va6Lh?72lreGvvs3QEL$ObQ{Bl`!$ zp}XXWoTr{XqLui-i8;LNJ zw1dWI!EqyQnvx6D7)aR$ADRW6hWr{}3P5brJO}{!bd?xj8f|pC0N>8YV z!KV}~h%k8&5Nz%hqS>$_KqMCLm_A&`>v3<0ElaSbL>ykXypMAe`XzNz5vp^XbQ0l* z&ux5c$4Hb98IYB!N3>NRH*g8ToM&p^(|)%p!LY&{WGZ1=NXoWohom@FDSlK;X+?}8 zwA;Q+w_aMInG4nSx}>LaeyQSMG-ck-@VEgU7MQr`QK|H$iOS*{PZ1qskI`;1={h|m z51RraD;nV1=J>djWBMGGihfvo5t)LW01D;Pp@axR)@k~HP9Hf}m_vD(DgGib8mLIU zX*tyVrFi<3%b+Q#ytl@BF!YOOIE(`kb|Klsd3ahY&2!lPX(9K*FhuDko)}6}JO{G3 z$!+FzOo>xL$!kjFZ#WUI3LV|O%0erzN%kC)Uvdoug zO8hyop^YP`dGXK;wP8Qsf|xO9IdUYFXI|o?l&D*qeX}bUL)KdSd3SQo#>}p11JRsf z=WP_nj$2#IQcf>4-~*g8YeC`p2aLuL2!DC)P2Na=`{m5WKBI7tE)Teq{unW}yZy^+ z@$lgC+Cs4PU>}=~Z7r_b`}0yC?BBK~nNJ~aPFWRLVX!xjTkVX+bpcE9ts)^xx>Pho zFpOzZXoWMl85+hA1E`bwlAHw_$^Bo0|E3h&6zI4XQ=Mh1lr@Z3 z%9cd9x8>|y?p|TvqE$i0UFqO*p2~^nP{vNJNEUU(^2j-sUT1<0B$(_;skbmKC0BOJ zG6+*tSNKa*lX$}?8@TvLp7}t|I#=MF7aXp3uOR<}7`Hn(H9y+x8@{j&QyDAx)+%Ch z=~D~k&M}UlBX4!ZE!PYi;Gh?pmU9nAQhiFuRZs3!^y5XdCqTDancaH_ka;o(XNaFScP_rUW17^q{SD5ZxSJ9QLyy5i zH1-i9jotNlA;{yw(FEB7`bfb%9CmIGnNb~I@A;SVI*>oxVH|in|9rYPKEoZUqc@$~ z(E7)#zxAj04vujya1{>F3tb|D1r7xRU?xg*7+A>t0X-M-UOar5rTuumx&Cb9hn??! zdi019zgQ<0HoYrZLG1P8^&fGZvvbpgT(UC`3c)d<&1<-p3aFiCruzjid78tO&@699$Q=-hkIbGljYXVT#P3p zd=6DvlG{S8gU9#b#vbE9mF&(ls|aGH48T`snp%W+#9IhW%V1T+3j)sbk1|ZH;hl2d zH=si8MQ#0kuxz$xUHlU%h2|=%N~T$F-G)JTv42fU!O5&>=pCTe#E!JanYEcIu`TW$ zgE{ls1YblJamNvYX~ur%O%mwL=VYP)YD^m&lAs#R;eldjn7z+4g*DhRQ+4NBZJOY8 zY|N9n1S-?@Ob)y-J1VxC2U(v?DW;s`Yy#wDF2pbNBbbrqC7+qL(1r9B+%kg7j`_Y9uvcx|~AY zbY5LurQ(+y^oY;Z6za6Z^eVK=iUX`$86w0A$l$Z)a&gV&QwN~fDye8jSsYADoQlVy z1nmh%Cs?oSdz9MKV(HAn?Q0iPp1#ASVE^C$JA#87nQ3+r0D)WB_VH{NkC16dAKl}D zLS&SL*>mRVmtV>jMiRWK?_@!F04`3Q<49pFrP_ITJ9eX$i145eECH_iW}!3jRn92s z7ej@rU=WCEE!r#G$i-XuOHF^9m6+@whmD>x=6@N)>SPrf-Z}1%aZ6fwZf+*sP|pas z3b)CmgzEUUpkWA(q(DNJ>pY$iSC(PW{8u`k+y&y}`z>TZcFk5u03& zU#qP*CZ@?AG}UngXy#yLB50rsd-R%JGRYQW#Fx^>n^mtjFY!Of=gfYUbc5c6qkg z48UDX%_%l}-dT|KwsSh191iy3o^H-bM#V;>O#$t8q#lq7h&vPe4OSH{{v7Nh4A{I+ zdb1V1u`PIFa6MyavSs8Km@uVPiOEz1n@0v@BYt?FSjW1`uY-t84qIhtT22l7U zG$0!hlg@TqN=|y~lDd>A79P8&TMVF5MrcN>JTz^5Ax?Z)b5^9jVw;X}VpE+uP-F2$ zhNOWw<%*?v{vtcm8G$#wc}r%exyz7j$+RJ3xf=)5GI}}eLxAhNlJFULI-wq?j5W$Y zWt@nVSaI34F#WYC64e+|jxC4sR=sewW&$ub#E81uewYHolcG4X&oEaNNp!iqM*0tI z)*$^y+!us;z$?8*ZzXrFr;e6ncEXwRJ2;)f6D?**lI&A~DweZbH#SSjPAQbK{i7fI z)5Fmo>T!oA$>yWakr1D89PmXX>66pVF9<%IQczVsw5I1j`GQF-#r5M5C)1@hx4za% zvWD3r|mOBDP`1=kwgivDusf@=UtL9G9anhh;q&#TKLU@qG5xp37G& zHqkYla~V^B$_1J9>Lc0UV0y-dfQ?tg70GpkaMh1TuaRa7iq|nT2Wp&?!NIVHEMU;$ zvaROLG1S)wJ!rC1Y#8s!mwS`b@te`n>i(Gf#Z8ChbL%$bV2_)?;Sn~0KhN;uGrWxu zN9Zk?D|`d#({Kzkd-edcFX>3f+b`g4o-mXUeyvm+N+2(V$xCfs+ww5x-las(osf?H#^ehH)C zMI^=3AePP=ub^N)#F?tTISP`d#-q{nAu_Ze$Z$|;bJ{y-*1-)|LvFb@y5TuS9ZAEb z9$@#%KjD-UlroDfN+4pFtuGHp$NkoqZ~Lzx5G7}3v)SDv$mSn#zA9;4FqpVYWGdnu ziAw7Jrigu53zDi(XHt=XMsy-oE7B7ZP-VGsXaW0(sU=4_Jg7|bo88F^7%--KClD>3 zt4A)F$4R~4pzq4K-l-fC%87|Ae;;GVa8-=b@Am3we6WVR`MeRv{@%U1yuAvL->==h zDrxjh9N};pR4mPXphG8??4{5p<*&TY@*OnvuUPD>B=w~?G#G$(ilUgGm zLVF3W;?}ouHRnaH>g=+oR!x6#s)0HJEH@~IMwp>Dr}h>jsajSrCap(8X_`Dfi|O*z z@=brzI#OgFpXjbTGUCHNF5&{@&@!{i@Hv?9ec{g?+>^n;5}n{{T$H@D2+<~Dn}`W& z_BN9&fz$8N8?SjeVWGnO_0t^Q#645eno&)GPlPZGQ|lk#h;#$du&^hiQ(miu^Jv&T z98ULh^3_|?aeNtoMZiAEr-fR)p#xV|DC)>eod=gL52Tit)@X3sJ@4{v0jh^Pd@ zD4`n%d({93&NmPi0=YK%51f~Jf(r)^HxTJYL5Jk}jQmu*TQYL+G=GwKkJxM(yx~w47hY+zuRQWQ83pU;M*CMqu{PpKAa+5aeL2EuqT!6VFgf= zrodBDe6oAYq5-S6fSEO_joqA!jr!RZUNntpQ@V^1*BvygQYN35v}_`CZmfj4e=xGYBMirWOc$Z0rlTw;+spQsg9jdmq zk4}@-%hnQk!=G^PS{8!<8#u*%WJsMieF^2TAtWiV{Hi#j39T-0=73?AO0n!cZ*}b= z5z@QzAgtILCYEpnt4}3acVjGYE9-!r@ROiFXW{xfFdz)}1=gvFA%DrgS35}jcBviR zH!Gp7vjpY>xrB$PQ*hu6$5kM3i-TbbM(9n&AR>8%QB~2%)|S8?52XSsB4INTn=m*Q z;U{LTXz$t?W!8Nh>wFNrff-;#E~Ri8C1HCKs>`wrroEq;ga)XqYKHg2zd_{?eS%uW zWV~DG6lrUWY9&>YFBUp0x1I*!%dqsT3-H2tA$soirr$QSF81jk zANME2P<_#}dm)w?uVpDLjNq(bjFn+Wb9r6RPGrlb&}pjtuS&_@%)A+EQnA&nBV(~C z@>1;tY$aw8Z$Y?=V3Eqx3361l35tlQSQ7ZLdkz%UrY?ccyEf`784inOMWVvMc`YTV z7HyTwVVM;?eF43pN(0)RDG+brtwktJ)T(ed4{U&N#L)4OX5!E>@LztC(JZ29%+(C{ z=A}@EY@&%`#>n!Lrus>S@aYu8IsL|IPLKkH`NH<-&8j`RHtxMu%d`+7?Q5yAhVmtw zAg_2q||$yA0m|a>9l6P@yJ?hv2lnK$><22e9j{t_;@? zs?H#tx!Ko2rq9JUlybaJM>dtdsw87;Ni^hTJ#Z~Y=9N>M?TvVlQ_qE{FEASM1>z0d z3pjO%FhcPdCChpKdRqi(4`3_&eNfiusfw^AV4_W130g`pAjKE2nm15}WwiR+0Jp{l zYNr&t4AvPMtWb72w_O1tnNo~s);!|f1QyrnvAP639Oxq#Lt?qU3(zNeMeZ9ZwTWB= zev2 z*s_!Y7Es7X=?7^%5Bj)WNha^+jT_Bwyfn`EN5?PHM8f;H%AlU>_8m7xf`(UVd|w}8 z540d-Z-#&23K>t$gKX6*a>Hv>wq5wD?pWrV(z(oM%1Zf-pK_i6^kaaGd5kVXE!p8- z0TU_Ewqlu*3|LHD6c7%V<)3#}Zi57z{&Y#x5dqlY!M3r~AK3BpT}c^(SSZ-pT(oCTe{35RUZ8|8*Qy zC+#1>Q)AEP;Humr;6+HBETpxWAgWBmW<0dJ-#@lIz9a>j)yh{_e${x(_j{)m5zHT|iiOFBP) zNBPq1HZnoSLM~I{uLNN^_jej-lK|f%qDZ42n8#6)A7E3vC5G2yv}u84pBIRaU^Z|> zUvpy7f)Y{4_hMO^mn6&r5s=Spr`d{y(gwUF`bT&rvyn|skGwTIZc>ejnC*fQ3!~9H zgo0=Vr4`(~pT^+AjyuM7>lV~d?{As*SfcHPTWFdQfjFexkWyh)G6oRv&^y(| z1DAZu0#;68FLl|5nARAanZz_{!_Oy&(4j(l#Y)Ngh^3>bkT%z^;R`zT>4_ss11_C7 z4s2`=LTyQJ+a-!2#<#Yjm1eOa*^1a4k4NKXR8;pi?(Q3n?|g@} zVUX%b5hGDO!nSz}g*8(S0B^d}?< zlKqzAn{=IAQc<_V|f~y`e)M_pO6-q9mw;FAhLMhthv0t&p z!_Sguh|U(?x)rXc*Cgd*)$)X*`JIFu-4g%L1i^yKh+!PxyBe6RI2GUV;fJ+%+?&k# z3+EH9Jjdx;Tt9(QaxzO!F3Xi6l5Z4;iYFi>>YV~2nMqfpUp(ze*!4s-Vw3e7*-Pal z5IfIpxhCVhwY|2@K;(Nb|8Vc>U54leM=8F?dGuJdf;Qvm^qcX|lrT(A$Rt)0o>euL zA8~5@z9{iDLM}Cyvt{oLi3f)(su32xGehPgL7htLnBr8ou15Yo%M zw@}P+g5Y;tP!k;R?RPdT0xivP{&VH@O6|@vId<|?HOS3haf}EjI*U^)QiMCdnn$&G zTV|>9yik5e+5OSs+umP0x48(xMqcsfZ>vM>L!?KUzLNypbB?w|1}c6yHD{8Cxt)`| zm~$e9Jci?IG>EwT-Pfa2(*c*$NiX6+Z7jz zs*>|NZ;WFAr1lWyb+EFsYTi#P=%|TRVcX&SzE};-qYG3OYYY`Y;8fKk6c>kM4W~f@cM}jKXB17cI0vPAy|fQs zH!h9DVLp%wBGpIZvrUUH)L|x+l(I~AAeI5LHdFoM;n-yy0^!>BxlOA!CYcQ+DGy5B zbh*0$T}|%ZqMpK=E(6+e^EA}R-Y#uNOB8_nv0|t(ukh+i{_VyPn0o+F>Oh&{ggrR? z9VA7C1=qnrNE*r_{E?9$pV-3ufTpl1=&rSPMGE* zsgemnyV3a~Za21eZ~`;s0v(VR4VFeCi_&^AH0Shqy+(!|(HVsRf-ZQ5v{q-l?F=a3 zbRpYtXeo>e{uwc*o(P)c{`6pl6x2w_qk<>DYCMrIKq9+GeJrZelVk}n|F2}^+=oVc zXv!>%E94(AzZL7+N4N!@G;boes8K||Vput;=@kNX6>KXMzbIQ`1M^A7BY&MXRgM30 z(qZsw=V`82+`84D?Dm+DU)L*n|J*`hfZVQBlCP4t3|QYsVbw|u6>KdwU>~R@0OT^k zIc{u~?kSzM!p7!ja_Z8w4-^eFF*B>Je%{AGcDs+{-h0=PcM2*B8ir}Ee9E$BU`>!H zVOfcd&dWbxv%dk;U+rAk9&Y2R(BL&_#ZqONa2N&i<|BSSVsw;5$?8r#8b19A*iHq_ z^-%%r{3Of_p$n0(gLXAi=EBUF__A?aoLUz|xC|)8t}6jP01yS}Btd#2mlni3$K#*K zNt5}oB@d?j0(;S^0u|q=A>PT-wkBni5jeS_(4tZ2g)n_x zgmVmEC&!4Bahp+WgUqX5$|#}aG=`RU3jT2^JyoLlME7|YG@#T2lEm>D&jb(q=Z)Yq z(A7grN}fS{i$v(sSb*xuZLkF*v?bD${5qbcaY2Kvl+MZ+3~3HeiV^IyWGWTYG?d-w zGDrZ|H60)@H0awLMU}NBVwB723wZmEC8rf@G(=$o#|fVK)ydX+oJ+Ke%tK4$azVIl zXeiYiqy*iE>)re&|xfot(k$EZzLD-Nn&m zXZ!Q;>BxfNxeec-Mg%KqUp=O!oXYZ{`6v_>k~YKgck{VRYqN4s>U@LUDV{2 zcnEUVz(6qcz$7@+ZTNPgM~iY(0M#oUZ40{Cn17;kT-D1!)X4Tdn8HU7$>O?$IL*;Z z2{zjj=Mpm4^$sLh4S$sqy`O};Yw-~3CZarqTJdF4)~Q>8L#uy>h^$h+xreMA_L9Fy zXUxYdgT&_j>*L<|^~L8@yZAdyt9DclQAZ)Jb_`M$QtqT$`(^u@Yzu(sbe&m4zMOJ= zSme!?p-xCeD=b1ST2c=*`}bI{m1^>$7g*or#dvmbcv9YwTV9QeRpK$k)e( zj~19~$U+Vdcuea+Wqo?on}UrUt8bU}B2ke1*bUCus}HHxEDITmWQy|Y37%MR$v7n7 zpd@*kTkEccvm`(Ce2B4$RA+FH$<0VeZ34$!&uvp06f`Bo96f=5I^c&55P0u$0k0N^ zXOSb7$lNL&u$QX!(L~AT?IdQ1x%BO%dAmVRK{xlY8GP6q?;*Y2$&QS3@ran`GyVkjEL(vqLJffq8H&x5ZhDm9W#?_guOfHjBZs&Gm z*{^T~*QsduT3{XSxo%%M7lBgOS94LTO5-8zbTN04=c^i7Fw19=HO#*FF*v~u;HKCc zL1fbV1(|`XmMqq_hl@R#yV`SOU+10!_Bv*@mxT<_0m3xy;AO(j5WK=Pj>ya&!X1+4 z^B5MwSa9iNGGzqZa=#xo`N3^%Oqi;2|36ZM)KtXgvyb|ot0!;RgFECrcKuZciLH-& z|37>0+TGNZrHy`m>sRa$=SU7%CRD1c%T2hGKou2yFr=zqOx&_9V+C1qOE%yl`8{Wx z?`NEGzV{zH&oeLUw)d7~a8gM(8VR*X)iE0(e=cSid{i>+3Dppn8k}wzeKsn-4ZM1tf>LoT8b$gU8$0? zJ{ud~-G6fD@z(uP4_mm*8k;o`G}+|p>UiDdrPa|&&g#2xVjHQG$tmCq=C&7_b8}SF zj20$tYaVB2otAm~>}yyZn3z86(;k_e)cCCQwhiwmM4@ptYd6w6e?9mg2;I{CPv#PV zYMV*gd@Hf`2A5dadOI8G1LmaY;X*$(7;BZ09;z#Y!uza0CYJp$S?YtmaHInq4B9pD zgMTjY(;-0#jzf}ht9Sv{OPmK7Zse@Pi(eh8tL2KhB|=;wyTLO_zcHx|hs%@DN=^>N zspQ*eDoMV~HR0qz&Ma%4QA&W1M(z9GiaQUe8pvR7xp?<{dwczbaJ2QCD?fn)NcnCR z9!LgtwIq`K7&S6TL~#Tyi-xiv&tyczf{v)srFXZnbz_>OwsDluW*$UKJMQ$_J&0Hsr$o{`fUD+CZKK5+CNAmthGB>c!q8!;Hk_aNXY!X>(7^2}SDt}oH+i<*N+RW#+5DxC$Hd4fR`Q^>z zic9}!BB7iq2eWSJewfqe?a!;r-R-T*t3r>pBg{hcw72yr>u<4IG^B86^YpU|G2>MZ z5Pux)y3OCj=gGM?ji(XIbeIo35D<=j_1+i2W{QMhdzu_cw+F;aCXXlo6Sbu+)!iaw~x7KXkX+%qDL53L+wQ}2sz=T@ipTXN4x zofgjNq~TbKniU5CKlO9`*hd03Pr?Q)U5ZskuBFYFdm@aRd-1nH4K}Z>GiG zFN9UyF^`2Bzaq#=sm+CmlFtVr1UvN}SfkwnSzM^nU;DdY{I9FE*GtP-5pk3n&J(Z} z2ttJrlwBsg`@Z^IYS^qlxPSXzl}JL3LKruh-Q|K5933D_t=_CY7jX(d91}0E;#t-E z+>!1)LYD84W8N1j=B4#-9P{`y3Q7KL{!Jn}v4J7D55?2zzegc0c_$aQ@}}=0X#MOL zN9jJnSp{?r76~|t;1?Lue#8&#&jik6gVme2eq3M27u!Akd3d@@U4Q)pTvh(3`IF!Z ztguARb14C=<<9lo{v>=6L^C5LkbN)AmxKrW6Y+y8iKC%^;dqmr5BGk-L27ci$pIvE zDbO`{%vH%}2G%RNde+t?(ULgtw@Nx(ec;F~aIm?z`c>7}_R)jpXYru9sCt58S1PV_ zO7EQP4#=;N9-Qu8z@-m*`OteGNkpK02FJkfh$xTi9c1lM6qSarAYYIJsAGqo&L# z1y{gM8&y(imDXx~!T9m<>Fx-Hc9Zl|u~PQgvv#vy%o^if5djBM=*HPM#zROri)DU zhncgdOs)+T%h1s2wDw=v;~{S2O@K zpCZy5XmSqRZJkQRaCqGZI>)il4>RytC^{2wGHnGevUAT@3pMa_UgWq-7SXupr-CWr zWxX^=UW&J(c7E*U>IB7yHTgOa3=BTrKcL5d{-r|+l#|PXu0NR^o1h2;-->z_$(H7Kf_+0p3gquLS}VVJ*&2H~$LOXDl4k5^d2IH4%? z^DllD0^BRtr2==*PfNC=eYP#!yPCUjYZTVC{JIyeH!+j>(v9h~6@_hDpS>dLlKI=G zd25~wa8)YNuh(KjFM(1tDz~|w*q8Vc?#j6zwyePiFm=0bpGh`5 zDX~Yv;3jSjzv}cL!JyU@QZc5u)qvsYq?SvI8LNo9$CjU3KNOZ_-@O)4-dnevTKA7X zMmRk0$P^J_f^sbqlC_JP#Q*YThpj#dNg4ny{eEYEpet(Xxs{;LcTWv@!Epw#-*Bpw z=z;?vDxrz6QHgSiQd0vAlau72@DpV#j~K)T=gYnBQ2p}imzo+a&4*rMo{z7KPLpN( zlZMHHw?2J*?{Om4YwE9k)NDYaA#kACuyjmgcX*FbJF7e^IJto`WapMY{aDQ?%I?JdSJ1r03+FBx~vH?E^-sq2`U#AQzS!b>F2U4-+5_Wtj z^=cU*cpGzM}o|@;K$?gyErJr*; z*-b<`{>4vns`QIC;&`!VR@Xjwe{Z;--JdA)9sBhA?#0}UioH~?AyEUN#51F7bDU0s zl8$2)GY8;;b1-{;ExGTMKf{eD{z@-cb99tDU>G%UV3Bj|-S@cn-0o>^Z}GeF3r=%f zjtRq6fL()hikt{I)#qQ1OyoiW@4r#o`~Gh(;{F?y3_|TU5KA%mYwm&Sy1^E=DmOrQ zp;)Y67c10__3Qle1_b-0j+RnWg!LK%iOkbbwxVulc!JJIVrycY5uBF0*Fe5=PRyyX zw>ED4&4<(*ijEh_Wm;Zls9@VRIbN#GiIERize`8R%P>urox0H6cmZgJ9b~Xma^PB_ zZwAh`kbtscOx;>yE4=tJW&j!Pvhv_VeBt-_%fue4;igQfQ1brSn<1zdLYEdP>wB7pKAOwZb=8hSt0 z_}c;MUM*}a@TY7%m{R97WPYGuG^cLzapYB<7~gC@HETDJt#n`e`;K*+QCwO($L;Ii z*Q8e0+Lo-Yp0376@}DIb25*l?w10Lg@_U_1iy+G`>N2Evd=X2zjT#omr~>eQYYMw{ zA!}-0sX@q6yc-rFi{HUPH^Z3#%ZKzZ+;4#>VfKk{Ce68fu&E=>ux^76QWLBk;QTq~ z*e6v9M`upDg9Hi8`FECl`$k2lq`(^v1}kR#=PAm9NPRjXknns|XGd~*_1dhC1}A+I z$EtgsmmxRuxcuwu^5tq-FvO?da!eP~pBkw(7V!IK7N9WJleJ`FN^yGoEfQ3jxHB{t zD1KQg%ZieZhA=(~-7J(D-+TUyMk;0gfnG|Kj}o|fQ|G>>9<1-a|NGh#AAIe}fUF#M zCL7h~S64)#(U?B#cSFFu41_7gp$brLT z+tNj(JICMW3teo{vXgxDArv^wGzIJZSdX)Lv4nQN8uh0yk;f!yS(%T7!C$76SlT*x~t~kEt?%rPOZoN!9gFj zzMFY+d@o&Dq@wzp4VviM_urnd$Stl#PXFWR8VUVg%-UUoXw1KvM7Xr-#aVgJrcu4 zas=|pmqvlOw?U)HcET{E`sxN;9*QcVFkBNEYR^(7Ju+$Ko4Bclo!oe6aj9irVRWTmBkJ%k-aJ6!h2JW~aAbx$MWyzy zaClAA*`TK5LtZOrN-#`zZZ5pQeQdbmV7UOwi6VhfF$B_`;~;;to& z#`Utk^Q>^Veox2bmInP~qRB?{h?Y0)-jWK2JWHw%zMOy2 z-wY$w$Hc0QRTS&OeHP8Jyv{;ukl{GJZcdt-8rtwW@7VZKpoK0SBr$t_f#Nn7h0pVj zDZ0T;f;dl*z+*Cxl_FZer9%1Kj^1hEtrAmw!dXyF)0)ek62OT+|C~u^j;srqL(x$= zg_7bM?8>FZoL^2bB6Tou1m9LbqHQP8X2+db4L|LeHQWX?TL=XK-pxY;RqR5Gx|JO! z{0KwYzRN?MWXIn zdP1#nnJKH~?2%tGY|GgNYpy}yPlzueRF{r3dAI@j%bmc@QcY6SJ*%2gP0us!C*WczN+s0@L&HQ9JF6e zURT$_Ao10$-5>Oe-u|l_=^KCkum5}cU;oe1pnBRzeYL>|uJPA@7)&QegIg#5O>aCn z;Y&$Ubu2-7EY36{KK5r-J+Hc6z2I8taByUruL}(;A}T8x3g1PRWz09Rq1<|nJ8iWp zY)&V18Vr_=4+X?u4n&o9wqbY?3jNrcm_wYk`j4^RJbPnC`t zB~A*kFfXEF*^J^F1Vm(-eT9tHkU*`Hv}Q7@ZXl^H z8)H7WSn2PVV=kXfVot6Xa`V)w5y_ViHa5cMfPJfch{d(Ca+OP^RO$R&?dTSWBl*u! zxICn1?^O?@>kKLKgQrh7i6A__eJ46bTe9@%sddG44ohgF#bE7D7EgKW5ZuTNTWJfF0G7u+~u zY7k$`YYo>QB|SZBYQOg1(j zvFsU3^GxoBI0@%?c1+7BC@1i*6f)!l_Q5;+2v&c^B{DLTfx zH0g1FloQCp;}Tk0Ibyf`f=0Pq@@Y}z%4Wc-+N-+%br=MS^4}vE6_yp8VkFN%xsDbGOVZeR=UF|OUshZPk`VNof)f&HatBPwMsRsftk6EO5`WJF`IPSx>bds zO*jkxG!0d4O8kPKq>XE^wy+C1U@Z}hvTg6e=E+(M8&0`QpIy;RtQIY!M6^j(nINfl zWfJ*(Om*1h5sB>`cuX0bNp?t+g~=$yn_!-mNN=a_fwtA%u?uocPlF)rJ!{VsW`{aT zxsWV$RVJ!Hc$gjTKyunSnd~ULB-bw5P%g+DEySK>me4fu55*Pfvk^0L3=8W=#RNydQV{qss%oM zDCN{n7eb9zs1}IvQ7g3ga4AT!VH=cg8BpPTBUNkZH%TR&SCP^1SH1qd${ud}t8-5$ zy9M^;d!`C`uY-K-!6P)N!jL)pl523?Sc!<7N+ZyBN@nIiD;s#S>6NR?Gn^8n`^x$pw27_3hm{qZ`@%9w) zKhO*J=@CWCvKO@0cGZ9M{=?vBKinIwGPtkk&+s(c75g?fv;_yTe978RjY;Y}7`)O+ zGC6XSk?RKEUi~+iW}uQH+CUHi!X31H=o*(V*HAM+gP0kcM?9z4CS+lc{Bx&20vwT< z#(^mIluu#|ba-$@Ez#Z18m_TAI~{nX(1O^k1%kv#Zzsjvi2DFC8^e zEI7fa6!EVW2T%`d3SGw~HBcdYqxE1R60d(0_Lq<-Q6Sso=Pzh-g_Tyk1m#j5ek=46 zG!r&m2Vuz-l7M}4@+YnV)O5vl49YE}n*w1x$#y^);m6*s`o`5T#`Q67a^T{A$aD3O zrw_|Zq^K2$@E4HELf66VNuW?(1aSM}b*2o=+f4j&dQ`*R*w1rqk>$3KcU%*p!_ja* za~$GOurKg3LyQX}T>iQZ0q+jfbQ#8wNW<5Y#JXS|oQ}r>)~4$t8j(KRbSu`pK|l#+ zR3a(noe^<9VjuX}rUYfIaqf~9pm;JDsl(iJh5>?XiP{4WF5B_N^@7vzb*6gsUliZ;PJO6N@gA~1=>yAjjW^X0{7RV8Blt5DI9q}<( ztNzKZOPK1#`6(qnWbf&qlvvyUJH`Ar9CP;;OU_$C7LDQO>9Uo%1}Rt)6$g1%WZX0X zeH3P!Qjs^z>Z3QH!+R?CD1|O|zfR%F z>OimON5q(zbOS*nQ3LsgEQP#-^d+S-Ln-8RoOqUkr5BmW zDZ$`gcXv8@H5g|TW{;u>m~O#oE#V~1*Z7fFEitCPN_nhN9ncqoRFv>b<(835drSUI zr26#hc(q-RDCl+)t#~#V9Esb7X@EJHOcfmNi+in|{l5DLxPSH)X0k{G51&Y`pA<8- z&WJy8Wq|?JXWisH3$quzjqR<5DUOjgfA>xfRAM+;NYR2-mX`f20CV1@ zCa8=A_bqe#owr@Sm>fxh#0Y-{!=;N<*$hhsR)~liazlCSq>PjRWCH5LwEHU?ltMX_e{%OmL6H$T?5(vNUS$n5?I!vHgsEP}XmgwHsv z773@*z?DvZ1)zO~UL}C>0UV2F&%^|X#Ski_LVcDPsCFIyl8!ss`q^WlizZZuPZ8KP z9N!UtMzeL;ny^#!kByJq;KH}~Y25sb{iJXEy^L|8rbqOzHnAnS(@f@@;|4uJAMP_g z_Fy=eDs!!iEDMj?FDg7BMnXKuZ{or{?A~^7GJUxo>aJSkgVkFFYMo!GkRx{?>@twD z>hPt@bH8Gy*-B{ZzR-13pjcMF&S86$~_ z9c}tr;%FScY)$H`g?(`i@M)Y~-4DT%3AIGKe$$JTU>47WGh8tB~V766S5~ zxlRYAi)L~BI$?6yuH88P@)6U;q+*Em8QVy}?-uI*^^e$20GYreHheP$0&RYIcQk|m zv2{Gyo8Rq(4jw1kI_tPWaWm}DsNNvR=j%>ZTx@oIcYM+)IE5q(duK{llT*4nn1A48@4_GPYf9S!(b!8wMFOQ*ER@`vl}X!*D$XB?^;Gd4uDUF6=_K zP3T?$I3Gr52QYm2NJydOViyTkR^_r7oweh{^Y9_U;#*Fd_r)d_Ip6KTu{++KsR$Cd zMcj>)Z>J+g{hVXQ_VqL4*6;M~#Y|xt%3};cOLCODob3wKpP8lJcn>1-vzrhgr@})O z8RXNHJ)dsxb{)xoJpOWZd-u~JtkR-fmNqzB=4RyEhl9OWTZ1WFKkmOpM3xsUp$=OJ z??9_bnsUeh#Pfb3&?1{o@7_467I9Kb!p84QsfR@CLlA@lN>ir&MRPIrN zu8o|Z*+eWd7&LUG>}o+z%C?*UeAH1tP)9}dHx6&6g{o#$d`S=Dwj4&ws;wlnvooaf zI4U}q4z^w+(qvZQ2mdTu%vGBgJRQOz{V${b(QzN=elV)8V|t@o$A`yd<{Gf%=@Nw~}p0Qb{Rit*geOX(*zn z3O1sWz$0tlN4Y6&Y?5QGb&~-&d5;NTWNtxLaju^ zvFu`@Z9GuO#nuT3G?=Oz33Pw)#Zz(XqV&& z_s6d@m75x}`5)G0NZCTvqC7clH({iEZqrD`(6kH1InF6MN6a1Habv+0yqV!a!z{do zb#(5D5d9WRBEi;%2_zk~4K5nM4&s}31}Z~zX0OL3~SMV{#~ZA zf~P^*1p@OMM?+>{ZWupHZkip+1>h=F#dvpZXNo7_sB9jQ8axd9kfsBq* zgCM*qeoGFCbP)ydfWr04j5Zrqi^n-*XI9ZPC>~d;tJo3rpGfVAP?zomUZ+GTWYlL< zb0p1-N<2wwRT9H|QGxRL_x-hhTwVK9?}b*OWME)EVM>}||LhUuvpd0j5O+5|eF|iE z1KxYc?}5x=pmW(rat>7840$2K{^)E!a89I`EsBf50A%z+Mp~@@n@DUoT2bG}S;St( zoU)2-hJ|?0s>mA>ejtc0(onLDrP29rsw*e@ZMj=w)ywS=lAh2B_Lk5J{uxXQ=pi1-JD@*{fRvnc z=}2+L7AO|_rWIbPxX>L9*F`|E88$M)k#yI(+VEziD9Or}0a@FTv&tkIN{x6DfYih? z4-@xC(IR3E>~85pP1^}7Vpr6-ue>Ubs9Z^H|H)3ICWd$4OIG0St?m8Gt2ftIBq4Cx zgQW$I5EMkW5D!f;htkERHDZPG8L>rMe35W$*|_Q8b$og)dD602~BlpH((w^n_*TumS z;ORDL?={GAIfj|hs=+V$iPBDp9I3f6H3W`Cr>A6tzjz+!~y&efP!XRnJMz;y*$@=AMx} zTbYxaD{6~S>Z+WjI6U5PCJXqcG4Fb6-kXPtKEEkH z@wYNZb~zU_y>tHL045YVYDzAZ>^tyJ2{h3b*IuXtYY!Ha7NDgg7;oY(JXceU@!V@K zl>JLW36s@Nhok+6!J#tuU`snqe{bAul_|*YeA4meEq%HCJ;(zY`j)Nu_nckh<9KfQ zSNdswQvWvpCjQmH^y0}{$oQ5a2T{{qf+V<=sKf=^cYi#WG^qI@apw-oYuPISxnfU| zg*_2|+}a>lg9Qzh@tXFZ-iKqeV{p^`!N-9<`F0jBY8e`8}fdo)2B zHzKA6ft13Ksey^-P%+yT8_k{I0m&xs8h|m(X9f3YB2^WyuHA6!QfSJ-F45FP%^eCE za$K$@75}Pt+`OMIL%H)=|u(+YDgyb~ou|Pdu}$FM5BJgou;T{$Ls=%t^*uGa6InwyXv< z+~-LAudbJ_$Q=#z9R9-!!}MXB-A6UHIqPJWMp>hV(=;y?xYkGIY83k(!p0XS%3T7; zk~}g9Bkomy8vudfkpUamKB^WVyz~^&fq5&`fJdyug@Ev11%yDpivi*7ye#E`!0>%R zh@e}U7+~jU^Xq_R{e0K$Jh$QPvpbuNPLV3|7?h&w!eL>bVdfA|rKUXG?r|;xwKW;rM>4bVcd=yUr~-Le_!-GO~u#-fz`AosaIr{&Gm$^i{WButU|`Bf^h zSLne3EPKP*ZCmO>n%Lou2bL*GTu)$k5DJRJx4q3fLUHzB-~1%x-PT9K)y5B%mg2;W ztF7<8l~kR~J;?uQ#|MlLhHtA=&E{$3KzT*tkKh2s(n8wKmfi4luR2%xm)Ax|9Pla9 z1dssx-xwTfh*$4ck-$5^$4C zYa?BTN~&mj93L6dY^kT4`v!#jUTazN6$sb;wmFFqL69T^z?O_8pLFd@yrFy?xg$)z zPr6AEs(!WOD5gdQt|PM60z^?~JJ)RrL3vedbhZ{-XdFi_h{S@*oD#I4W?Z?(iU^l@ zM^nR#ZYL%|(gaAz-Ye=UHkxTFh@)?y?l7m>!Q^zje+Buk;RUE<7V-w!If|1Z@D*f= zm^~aNn{Ek zg`zAAr|xv5iP#WhZ*v)7X=qktbIN*6CZ`&5ov7cT9TdPp8k=AY1$UYuNbH29{Zi`O za|siXR5+7kR+_Uz8qR8-Gn%J^L0LjNgkOMWh&^px6@hgaYKwOv(-9cF+Zjp@5)zH@ z2TD<5AHiAng~7xLmlIircLbubTUdfuY~nywAGu^B*1y@9LwjL^!HAc7P*K^_AYbp& zY5qrd=nr&<7KB{jd;EU>#OuEk6@$5MVja_v{-&PiOpZ2H7?}QZfOkN?` zEtEP5If8BKie;7-m1c0Vr$`n8ZVRV~)F;(+sN@Rn$>8L4s&yINLqr^8L-xte0zMBk^~+*9zWW+)d(oJZLAGH0Yi5&;}W;;Dri};^Kf5`w}fdsgDGZa$HjTfKHw+ zsMx$pF{jDdr2&@V?KyO**lw^HN~mz`Zwv3NFZCN#?BqI7005zu`%tLFP>{f9!E#7> zYeY3{X}CdNxJk{<4D|^oSWDw_if&zD6jxCG6~PAxrL{~c>nFqGs@L(V!=5-Smr3S(}>TxzyIVC*^cf_Hy8lxrx(%H68$vJ(Dc5BLsDG`!TH+|dMW)hk#Y!nNASZGNe{Ip zW~WC2d_M`Tl&0olSx1ducrBDw<9b+UW8oqi99-+mNKT>EuU!hUn-udpwmzdXZ~K_6 z_iWTRo+KEGnDfcGgVJSOdf+?Bn3$X!Gx&Y3-W}BhGoQX0&b-(}v?lyqd`^l^SIFOy zmz!3L;5imDe=FyOzSe=OagRvt+y@J{=)tJ_ds=LhPM{7^RT@peGH9GaD2|mAZ6QG+ zZm~Y_T`F3jIF`A~Mqm|hH~rZL;%JuS(l#i`F9=>V5zXk~V-PWDY_Sk};KSgL%*-ht zXteSNvX9Aiz5N{sa*hJ}3TXsB#Cr%hAizVi&2VR>E9 zn9*qRMwQN4)#V6s!$TPeglWiXDQBx_Cn_D(xqUcfg|SRR;8^xuMxjcBmnR$T7I3@5 zDzb!(0YMER_*drb&QSmMyN}w(&!BxggP~=6b8$|fXo6gzzA)Bv>+I-YGCtD~xG|hK zd<6fA<0xWp%q#>taE|nj3*sPQbg&vak|RRZ*W^nVjA{>Zw}JX&*gRk*sC`dWLF{2L zz2%O6iEzKX=V7Wo$-#Q3#|x*KHmtZ6#a&piE!7NFW_BXm%2LnZ!0Td2D4Jck#h#bF zq@*hgEeiQ+VsGrRK5XdCZGfyAvx8QRvuW3kTcYS z>wQYj`K43*Lr{M*ob52$ffcN~`@<=vO*eEJFzaDn>|m}{@Gh7P`IzY0G>e6egE^17 z>mEIJacv<1siKIQ{@4@y)Fr&)v+i{+RhXDAiS|Nv>{G6GVR)yKWn6}dIC^E$^uh{= zE0FsFD3+Dt4Xv;Uy(Qt<=3Ipbp>M^6fSg>ot;KN!hwgBQbc)ZWqdR9x<{f_6P|$c? zx?~y3`r%ECRE!Ur3pYefqJ3q4%zGFGvFvT`9kvdD@zH#@=&*TJ^B3#Tn4$VdyFI>x zZXtQYes@L-usY_1nR-8^{he#)s0$3t===C|G&*O;31G|Y$=3(WqMT&gH>l-Ub)^ZJ z+_r)Jj9>)+KVxoGESu8Be$@><1xS@gXQ`fP?B z-ORb@#>QZ_*FO&Qf&^?~qkvv1=J{E#k#$asB?ao*gWP08hm^Z${WLKXYke zydi0#hF5sT|A{vwx`5hEiGTe;D~s183>fqSY8FS-c1|vKqIaN=>_3aM6;4D#)Q!aA z(7K(&Uye^wI}M-KuU?jyUNBH;sgh~sLQHw5nM+@PDX&bV-U4#aOLP!FLw0o@gPT$9oQ7y-x$IO8ocZ7G{GZ1qqMV{+eKv za2RrxPt>{BTGu$3LN^|!gl_rauvZsu_AkR`vX|MQN%B0t@5C-^<0M8E!0;&5c^uKRz`V>g zdtq?ioTIT!e2wxancTZDMIuqjEKXpsud@hVAe8zy0m4t)mU6S$+Z=&BA}2dq#-H8U zwS-rq_j0Q2hs&aIg8E46pWFQ&(UjXWgi~(ME+e*kqucv@b!Cpi_PN?QVwe1g zz2kX^q>wNU_u0-D!q#ol1D{!30)c~IiQzGl_9RD}Eexh?Av_a5;}8u8S$QOzYqJl; zmMF6~Eg$#i!!I47ToSG^)*X~gK_R|)EPx~4#so6%Wb5(ww(m^>F7{TTfpnzQ z7|{~ln;TjeQn7LYk&G4Ew|r-f9h|y`dxv7B-T;14(-m3KRI+QS=^;bex;XVQ2{zb6QikY-Hj? z5p=;P2`=zY5553KwFF(Tm49dz5|_v~@zxSXN!YCVZvRuS0SLtO+Y7K^2SNdBN+WrG zlYx&b6U$&Nw1R!v`tleFK8Q>-S*UA2LRcKfYr^T@;F069tCPtnu z&>Uo+ak$L`Hf8>{1RIvID1MqhUeSHv6|aU~P# zl~iGJ$(If8mRg`h-A{tIWW1fkA=9ISd%^`xLmA291@+l-|A*K$Ey;S}QoNAfzSmzH zPKxH*N5kBqm*djDXk93;4X+tFF5WAVrQt=5@k%j<)HeXG4GxWWv)P+>dFUDj6tlbO zJjp#S0D}EI;CCsXckYZBaG;5s<|0r!)ON}0R65Z6CS|2V>Dp6wQ7Hl8T$|h) z7kpQ2vJqX`f3Y5ITKenH73$&~ttdlX#H%&Il;SitHfjQ2?S*DJ-jp+tEOeLv%O;`+ znpj{B1HoFZd7MSwzSb`stuVgRsboOKTRzm^YHu3pVGI8ic|n_mP;{RF!4}l8fAu{@ zhsJNc0*_*C+yTFklmIN9sf}eqU_xu2h^zdpa^aUw;JDxCoxXY(CN9v4mzGejeQ_C| zEOZNxX2ozKO~9)=b_Mnl0#ej9Oh{;&5wb*T7a7$CB=ak667Spu@$Sp3KS>VSWO1z! z3inb=nSU2}JU!_@WyfOJ{rIpEhk9BNAB^$ zHw8+|Jx{s3Fn#Zooy0EJZqO>yKk44P{q+9Mldtdc_9o#A2_PIne3lt9Bm_N>tA+O= z^W3Nl9BB=v&GWMZS?(?%fC=*Rijip~>zPN3M5T2oBsL&>m_Xng3;Ypl8Cev6VVLO2 zWN$J;?2M>k@IOXTcb0iKui;YEzRM6T9s>1b2B|?@Z1rjkZ)VB&Ko$vaH`+Jd?-+(o zB#hNV5S{I9=S)RYK^Q*SQ27{{Q6c`y=Vou3k8|Sz-vY^khhWM5NC?kS^Vg=-5fE7& zisIm8U$2nF#w2#kWjGj3VW#qYDdGja1mp3u(H#UN7l^)k;_ssCxs{G^w#204 zrZ}%rv|LG}_1^^}S=_Bq>Q_LNe4iN5bXXW1U?GSt!g?)uIf_&~=X(B<@622JTX<;K zo`DN6C2s9|S0a;c_7baB@-=!O8aeuq8YfT5DQcZF;{#ExXgdv7hT0>&8`HE%d*ZXb z4}m1%rf>jyO;Kk>?Vxs#4(6)1!}_6!R;}zsldvw@CQ@J?rWvpj>rk_Z+QxhV_I1fG z!I6N|8yl&SCXu_0Js1!uv-z*kzGZ+sLv9B_?T4qk;y>1L5okMNnoyK)h9?hBca^9V zUO9Y!)L;DmqkjAQYvHbN;WX|HPj*jH3hbnHG7GzCe)I6 z#=jwhK+K$Gq9g-58AQVS$79|LXoMVZ12`b)mkLTe^Y}2I%>0#Zc}=$j6of6ojzc?c{ihn7QG}*Q!SkP#Aij{xVq;8XuZ3atr3GgVp?G{|OT2X>t z(kkm-A9C*c+oE|ZYS!kQm`wI1BS)#S=8MucIu?PM=wj^2c3TByZ998z6XyOl)c;Tx zj%BpJ6o*UpPkYDuX--{{Ufj?bArBEb*O zVa5MOP*kX@C|KkjIPCA6QgFvywQ58m$MFU!F()>4%S3v93T@U!t+YvEfLlrEydGWq zB5k8cOxmYSK$hcedd;0Q}SN}mn>UO@J`1QY}N@Jj;Me2Wd zcMEjD^}{TnGNCI8ZM1n}DN(4m6A2a;zl)SkXRpgMK2YS%w>|?OARSE9LOwaik2qX+A=5K<{(6k{4YneuzlskgF(pUh6o5hPcg-0U*)CFoxF- z=aA1k44*YoBmDwGMs8tdcL@=4Q{;BQhQb8N_5veA&XSVzxlOMnesb&8@c0;}EF1?U zC`OXdUJ9LZ^~~Le7DYC@UZ*VzGFeMB!bgId!1*b>qq|y{2aeJdu~QR%iE>9XG^vn^ zPcxgk@maHJ!E$+>*Bv()N#^L6?oO{l@T!q}%75;F)Qpg3t&7Mc?S$AsuVm~P)|0)abc0wm*vH=T)EODI z^d0yTdxIC7aCQ++b6E*w5~y^pzv)kz%ItH502FT=w* zM#NwK#Sf%-WL!*>f%Dq};&npCMhcQ;X;5;3)dV5$(D_tb8@78tNWodm&y^(inGY$B zQ->D6ZHAb(&rpV60aua87MZ7!q{TRf5GP3pP-{(yny9a2)m{OqZG*>3)^I1}BHr&L zl|QVTO|hA--3X1k`P&$#&J9{mvMmqZdlQzbBD0N4y8=FrSXfCe7S3dCz3if#f}E_r zxudZ``pFyDRvV6I!!q*Y%uZ!*Ug36$b^x9qqp359Bk-;VzO3z|+S|d%6NV-;$tNPP z7I*VNQr?{1Fg1&5J*n-{f<62m+23}G?3^Z=3JDp zs<2|VYhMmuL=rwHB*LJ75kj&IfLeg_5H_u;q}3%Husr-gev*X?ZDt@f1h7$&9(Pl( zYFtE733}}YfBJVo;Z4o10NNuegq;igNI677h+=x^d6FX$WWuWx(wdl1`-ia>=a^=c5+6ji}$D*o500#5>_)2&!Z^8}dqZ^-A^SYW3rf zRp(Fop&Y0$WG&l-nS6Z$3mX$@+B4arlcW>j+W46(aKqnO)Z93Ag@8=@3ypf~V6I?9 z_!oCRg@Ug`G;f!6-J{z4GAhUKy4$@!z5C-&tCv|9xYK(}Q8wM9f>+BL>eBWH5S=K% z*mft>rY^>GUO-4&R(3JOxo3tnRq2-$QW_B3x{Fjfmw}Se8h|DcN-dMAu+iwEBA%1! z8)7^Bn;HyYeriL|Xr^s(V{viKrw>E07-`TaHh<2Df*PXS5~K}_tn1Vb@}t42cs&S# z4T9H7t@1U|@B?tJCJfe54_Pz{lR}jB=9BR{5Sqz%Sn*tgsjswE(qjXD5{WOhFg2eQ zeI@>DFDn>I*Oq!P?VRx})1BM1ngELfzO+qt&PYuwYk_oNXmM|X;W#)DCftaq)e7(g z(B~7awO2h~ICGn-P&J(7+6jIVu1$i5BsVSMrIzcf5lgAcGF`K60em8;AwspGk|?nZ zFep=^iz&`X5#UkbgzjKEIYI(IP~1oj6@sRQMCYpDKcA4-21lo$7P^BG=t!;{%2vG# z8wPpc)nK63V2UQ3Kb?k;Py)jJK!)%hhT0pz0-)K+uD80E@@#`#;vVN zM97SGaF#l0u-I7#`jo>Yw*~O}L+RK=0WP6QBp2k!Mw+35&>k;hN!6B`ZlT3TjYJ$5<9%WWqkBqet+L(qp{n!N5lTi{=o5;K!?w(zgf;;^+rrCr{R46 zc^aC2KF?b3R_>J}>0ZXi)?bZpmHxF!jK=a&Dk2bM4hwcV-m5oUsL|+`9-0s74y+KV zmM3F6>Dd;6Cl=HNI*ACLNhDszLKB(|mVrkVGL0Nf;53Mfi@?ypJO+qYle;t|+m#GE z$kvC;H57lvRUhse5sx`e>W_wT@0sfj z>qd1r2eyMCG>P^{e`JuK1JgH$h`Ph&xxMi|pdb^q*9H6n!p8@xYm6>FOq74tm;GEW z=B%d(xCB(r6>AXF)<1nLpn%$Fdq@gPBE0^)-%%z*)C9h~YhiJTPdIQZi&fdQcoO>= zh-U-M$7P;{ssLY55Q;U~O1l3SCLieY4!!!z>HhSrk2vAi)%5|yhTcC0C%0Zg3?0QZ zB%zILA)5MakkCfhye4SIB|q8JQ$b8po{#j>&KOJ__z1> zWA=LMFOK7#D!zxL86{xDsR=Z;sH@UEspLMXwMQo$$&?wS{~F*p)@}CG=xNQYpLgDj z(R)3xDR<8^^>4tEPRGOlM0FyYJu0~@;!&{2Xc8S^O+*9KN`4I4!_>=UwZq48wo1OBm)kGY1i4=t=Ii&;NudJyk|^32yHo)f){~=(s{Ew zL6R=h>`Oc-^)yRHki0*}6v{{mcaff$O{Kbr8>SebcRgWI zYvL)3;idpttx&v?-#BgEQhrsiT}LZ<#bJ@dZ?enuO~rdDTo3^y19>8aS z1*Axn)yArHz%nUeqs3<+AEAYSteAk>`Lvsr{uG{@{J7sZIXOa|_PqiQj?#2q2lUpG z9v(|PE)quRH;`V~QAJyp%!}3j%s1WoYi3Ak=%Q=|Q%Grs5yn92Zw+~-0zfSA^NN`e zbcsRr3190p!}q0jiwifL|=MlG-!Gu{z#ww~RtnDwo;P0W*G^KKLlU@#5q?#A_9pb7JMFzakF-WGPDzx3Emr^_B=JefVMRSgY{Hv&8EDzceD>57kMvXMzZ+FTTk0p-#>sw=hwgZat&NPY}U&xAAA37 zQ!-x7+j^^g_G{hwWCgbII^jk8p1h|bvmt%l_FwbDx$DUaeA5>%9ea+`{`A?_+~dyF z`=_&C?P*U|V0*3;UbN@Qdo6qZYhF0_JXwM7`QoKx&u>3_`uNe~+xK?vJ^SlsE0w2z zr}%Fi@G=B6{w2vbtwJS5{-+T6d=a+uKIgUl)1%{ggg$?}W&gc5t?tf>@4Ewpz5I&c zKrG0Y;)vjLUkHgOj~_qX*}Q%CFSox5+&{;ONCa7`&MmW2I9}jky!F?B7lcRSf*dSd z!P>D}`<*M!!;`yD?lTGG=99;NzJK>=8(j7fzIHNLgZC0mCV^50j47p~>RY4<-B7u( z%2>@NSCGhHCgHeN_sgF&&L;_|%Q`8oC zJ(#z4Ii_ukkH_oR&TrEFa|Gx&t{w)@aD^apIqp13Jx9pX$vaq@j7s?%(49+$OaY1B zgkVV*M0y@JE9KIAlLnGpkSw8g&o(xwm6VHP?@-2_nWl9h?6|9mG3qsC4~Br}AZKL{ z4UF%%316PDa&hMba8nnKb4A0BKR7zOWpYr6eysBIQY9Hb{5fVcf5G zI~CqkPtwqY;;09Aa&U={{MVwua^B!yuT=9JeDN=fT3q|G-h#pO@Hf8y7UjoK`5P{T zb0+!wYxNHDS$>J&)cMo=a^XV$P%OkNhJSP{UE)$GJ!zR=kJP~{YXlWeK6foCb@n2Q zyCgOGKJ5H{r47Dg4ymVc#6sD(_$4y&jR#1|El66XX-$10bSZQxU^k6r zvJPf7(xBJ$m<-(w!kly- zVW;)@EqjR3q;Pu!UCdsO!*DpReK_7xlIY_&iR^%$BfT-G60gx-4+n4f>ulUVhUfB0 z2mYiC=B&+#{Wd~OwyFdkTQ^1lv~}UL${aV!?M6!9yE;;UUWs5DJ8{8lkHMC>hL=z` z_fAS;E$s=4+{(@~gwlRx0Hr6XW~j;JU<167n;@K!TX3a{8xZ&MqEXNh*JcPzwi(7D z1<{UAQwD5ph^KHe@-=Nf*xb4Q_>s9AwV%&NkVz2RSnd<+wrQQ1uhdC_>BDv;+= zVFl0GY=m4($YY?zQ<%$uza=NiL-R;W8Vh6vVk3tX1WQGV4#)$t*h63L~7^2|`wb-;ynSJJvd;p^Jq z@&uhH;lVsUCf;boG{>&-eh#9WWMS2b2c{hBFs5Xj5$0N^fAzt$(c(GQj4%zIfrEpN zfoYc=_Q$g~@NNn7WwPA-`U5|Q*6W4YOqeeBZ?uc{6SdANePW zJN^xSCY1KcDWb%V1_`a*l&rIe)RE2Vo~^=n3JQC7ygEtqDR_TB)qyCbSZbi{oOQDA zQf9@@1d|*^kOc|tn-;&a04>>7Ty^{{B5K*I_6Stm-?t+(IALPK24p0!U)$}^hI_pf z%P|v)Qxh2)U!BJ$|Jur_KNjkH%jn#NaoHc`KMSosTV0`5D~@V~Sq>myVGfXI zkM{r2O&&+G5|5J4UdbOM){s5|I@>xJ}QmD$< z`OHB085Yp_%=*zk;`-zn;rJPp#)e*&--rC|xR;?*JFYpeZ$Sr?e_DVM$Z0bN1JbSi z^!x734g4o6$ju*7J!+N8ffS+IW>D`szq^%uv9a2H{{8xk%d6|%-sPLCcz3(U*KV$S zN@UQX1#xQpMhZ597{5GR1I3dz&%Zz}v-R-TwIo|ylnL?)%TzJRP^D^{D$aV#tk%yl zuif3{=T)#$Tbj%i@xz*Q{oV8L`)mKWy7s3XWJ=c5#cP0(GIaqIF+8Kx0U_QCk3-t) zeISTp^YZAMAkBrM>w}k=%sl#)3@pokR|5hpk{cUF48J)K_AABt$oiIMeVJyqX^8|L zNqN9uL9xkTM>ZKB0#Fb(7buX~!a_eZ`4lg19q+&0=0A^yd$7?AU{rSH(=`kF|ARD& zc?G}FNQ#P(6vxVVi6@iY!Stj;t=<3nf5#~HJF2e3Br}=q9Zqh&oJ?Mh25Ity_m(I) z1Do6=s<;-U8KOK(V`FOTE;QLva0ntO6|VL;uLvN>s0JBmA!9~PoSaU_Gl@pf`n&E! zq=!A^R?r{`g!<7E-Ta|LA@9sQ{{x#Ay&wq%-$mSDsE-;^=4%O{)PG^wN=x4`o&OM* zjMz%+F?4JMS$f3&vpff8h}}Oy7B;5O;gSaw6lXAcQl7(QAS|HaJA%RTU|VK352r1n z+iVVlt^ff%b+N!YWF7Uqkj>pDU4)#M z9Ll#Zp=1pegQ5XelSb+eS@j*HhMDzWHkubi;P=^<@;+h3PrmJ%yvO>C61z5qI$RA< zv$~Le{Nak?)}k%~Lh!w)3Iw>!%>|l`QKZl`lbuf|J+jDbZ)Y=KE{>Pubh<_HDn3PO zRMAAC6N#`6Yaocdbd)3B^Ug?_M?>O5^hX*eb>wj=IXLN0&ngshg2FUB>C7~8ThCFo zwR!LFNrJ~K)h_Hra3SsQu^6+4j5{L=6XNPQso~7;$CjBE--=k)@P-)oUk%PAa8^(XWg29{0xA3)yMEr}N{F~&Si4Rw7CU*G11C-9B zY`@HURbSI5&`g_V%ACbUTeUVw!)n;(liD=aZa6V&1VK%qlC?Pc%Bh zJC77AtIyzt+<<8Yl?>x%gF)pQ*9=mT=vvlrwoXLD4T+>&>5nVkYE|~Ims{vKK0m!n z+vA6tzH~M@IKkv4PG@g~yQ=-QnWX!?B7Gk9&!pe&O9>`zUm_m*5SMaAMMtQF_w2v~ zLD!k44azNLd@DKn{4*j?Be@F{LqN`Ie-63X@nCOwFdXcoY?Yi;M2t##vV9y@Se*A^ zbe{C8uYqydit(+%g3$Dprwh;4om>$nm`x0|BHEs&exRR)F+$KoRJ( zEHBow8W?v`MFkSyt@nq5U+Rv`#0hbW-B1pESe?US#QQDyd7+`x`T^V4KVHD9!9G`iw4eGzAFYb>*7o)n+uOfi z+upvmz5OLk9krozZdnYR828gBz`Trd=iF)jneND%E`2t;RF?XoEV@ex$SOZ0G2o#0 zvRBFF!rC5FJgzgT*4jQi#|E?2UiCLti4s8J&{3R~Zr$;*x;?{VB#k6`z8NBpnu$+P zl3FBOUZtGw9uec^UM1P<`T?zht)WS>Wf^diV_M*S9d&5aA5c6ZKMX$0e5GF;Q4#B?%gdvVUYI-xVv`2A(spGhfPG901 zP3bm9+zB+wYAd0@<*ohxWN*EX%16lGJzKZ8dq?|nkEMSCGxnrBsp_YfB90~ygiHcS zeeadLHy!-v=@8-PNS;w4x7u`yq|GsvbR&_mR}9=W8kF?dM2GD0V;>8rRM_W^q!OGV zI&BB6Kc(bhyzCU_!xZO=^L8XD2W;l6fZr6t-d9x@xxvQ}N@}lFH!2jQfCC4Zn3SRz zrq##ENchQ-D7bXO?raxyTpi5bweE2$FIDeWbRIuJg_eCmo}dYIUtCMt7p7l_O@o0E ziOrEW8mt&<582M?c<>gSNhHPrO1}*!(*zMX$%NxYdX%9B`52COu#QKR@Rw_kaA5rgK!jrBo+Se!=B3PQ{nK@FkIGU+cbZqi{x8*DS; z#^zd+n=mp9RJSZDZElw+DRMgE?UWoowJduFF!IneS0Ij1?iyjS@UfGk6B zVpJS}@BpD;@Rmj-Sh`DphTGGV!BO>S0vmh3y1qM{`~!Z|d#}nw&zeB>KCNmGz&ns0 z%$*s`Bj2vC<-S0ONfJFRuOS_SzQ=P!p9=X=-9je7K1E}-;g1kxHo}uf^3zJ6$U>@V ze+W&cc+YPT%!FC#Q1(|#Tfc3fk(s9$A{5dRQ;X7p-hkKZV3=0XN0{djp3j^oe~wR& zaP!mLL*ElrhK>|c;ZJd?npN8}^KijskFy+(rH6n5w7ViO!x6Pr<2SC5XBLwyZv-Ib z=_+Y3Ay=br2ZQA3lvWD}n(~zH6k23eCxVpI&^fY%RNkOLiN@{lf>H_8~mOtzif+g#jvC&k*GWafoR;6;^^Eq7BoVm=I$V z8nMK)a4_g)5WJpneRGGsRvZ};p8ASg@~0!t(O+2Q4(GYO8AoJ6m) zfhR=8d9`7Q5y_y#*>{8KE&$wI^et)GIK8bCTxR3e4$)~F^GlaC_oTW4W{;d|T~i$T z$KAxovtL3?amkJGV%P5TW?&4v1dbwpCoozh7=PJ#XoNF?8eUaMhF&vp#x3@~_%k_j z>DM+4WwZKwKe?hhqn)!WhjV8a@Dy;eVBR%2mnMRQ4&?o-{A&XzJm3iq7}7~h?L-+f zXt@_oE~tOxEO`yR3`Im7rVP?eI^esIYuHUm3$aT(O3-XNy4T&Eox6{2Z*A@DKyBA2 znd6SW5-4OBd1D?us(!4PtL(|cyH69?1oXlTgf%L#K1Kj9iU3Yx2c8U=-Vq6G?!i#C z2S@m`hrpvgeo<$R@Z7)lpZa*~?C4-JKHI)aAC58X+uL8`AkNN!j7RbAar@!pKvCP@ z8}B16>eoa5faLpLfys&62T%)zcdEa_>bG|Yb^QeXBKpe@lfz~KEKa=;zZmgD@6r2j z0WATIoR@iCAe;Fc&@JrUmeXQ4@Wntx?C>J$%25+6diKjTBMRl5w8Dhm_LnDA1clko z{t!iNNk41Sfsrzsn|2lO#NLTCE}@6)nLX}!{NfVbpN>J#U(M^)rjz(P)G6Uz8eefI zhcXhVW@0E!NlYvcM&|5?i^p<{3_JY_UI>qDuw@b`52yEOZ$Xjz;k1M?0850%Mk;1+ zY-r9b3vzS9zIJ2y5-x{>@9u7OWqsOD`S{-CM3A((4Q%CzVYym+6|U`^SzVnpYphOD z{e!RSezstf0P&uKRk{WHg>TpCG!l^e60?dGOZbWa^qqng%c)@oXGU=ickH_V{G#Ol zhJlVEx*7*gfp^W*Y3Z?X>JF}!0WeccKpWM%U2ePC^MWl;o6OsGZP&Q<)GyCw+C`iOEA@MQVAB+YB9)o0|dxV8C=v!`@XdD4f??T5u zGur{ekYPK3+rWYOL9kR3F4K6kz}sisbPo7KC1$iK%Ihj>0;P#apSY6cjG3-QdV=b< zfu?N?c(-|YoT6UqR&I{^Cp6@5Yz$|A11p@oX(&*^!%O_7mKh zAUdc6;~G?P&;+k~f@tvM{m{2`%zmZY%!N~Ej4goPR4vD^<(#*kv-2a69nws*jm$!h z4~x{fSf}n4w8o;UohU6#v(HZ;@4`QjWB$RzNB4HVe)weTY1OLIh`9;pRx%5@V=>@Q zRvAV`&>Biy1M%cO5LtR~EeO|SR{X@YRF{Ht$mG~2BECvI_o)6u)o9(PkB(>&B&*t+ zOt~b)b3#-sS70_=XHXFneSljA=Y^tb!E}lvEZx1+P65G&t18@Ct8-s~U?2ys6($Ff zSzg+7%Z-h#zdYRBx%c?#Rw6!x3!3d`;g%g2TBk7#w&98fM+P1iob7~;pPC6!aNRx0 zle45m^Z;22a9luZhh{$(oDr|<8FI5Q@)n*WXf=~NK>B3$kF}@{i7$MOk%J@kC6OR6 ziScq*nDy|B-ubS7dG+d_0&qEA{XE(%Fz=#ipk}qb1Y-*^HA5lJt zVjBNi`PsKNEPZ7l4uF7;{(Xw zGvIHt4b%l*G9pz;C1Q9JyoQ$=cqwu`0cV>pw{_&2iw;cQ(AragR3fnylvHQsgyhWT zV(m){K)Z@#;*$&*5B`$a#b#WMOA?VT)g&bXXr8nbR?LR}iT%Ogt!4yq&#_CDM7wWr zk1cm68$lL$>*$qiZ2%$+{D1u8A0daeB{cf573@zyQh2u^OOcg8`-W>Mzk~OmS_Ssc zvz9jf>bA<8P@CwkM12AJ6}L*^N4FHnix5Fc;h?yaNWgm@;)GN=`TZZR9wD{B7^F|c zHHBSZs0BOn?ZQvd2Ca2bNC^iD8ZpuZbFu-qKF4VlTW(GNX z&k|uaJ(;TG{FV=Ohyar{l4wY!t!GZGP&5*6(W zf&+_rj@NLxb%Y$X=FLV%`0kc)NodoM?S3j1uq~(rm0oFyFEBK2Z7KW|^q;{f)WgMH zA{bQ6$Mf?F)Ct7PTw!U<#7t0k8#z!U%9-d@a#we}(IB3{Q`MWtA0pfhG~XU(zASF# zfns@l_7pI9B6Y^QD;^ZIqVG1@8iRdJ+t!3Rc3JNzXE_-|_Qs&08KYEs8DC6D>2m6b zFD57o_uMcLHH9WM^CC2mt^1F@R&zqa8f@7u0=I!Yfx=SyiftA31#oZs3vBw{L-@Kp zef;F#ced_t-hOf$zv5f0O%#=_(_Oytt>`Kd#>6$!X3>n6QGn*Ig(D=(XXlLuH$G6b zAq6QEDOkf4GEKb&gh`P@?Q2cO3`1F6uf0;LLwa-_DZ}VZM}ewowv9 z7nwF|uv4`HClQ4(I~_>~yP}R6Q19D~d}^K5iAD=;a$30(!0BhR&$9ozO(>iIKIVR2 z6^yhsmH5X-MuqfzIG&fpmkmo~<#&l>+hoze`VrlR&`WBqyn%r26@k{5^n6^3dHN(V zsE1<5kUDYfo7RkOl=Vd^eIxG$HpMs!r+5_XA^5|GP=X-$hX;}ziv`ILwI$BC#<;l- ze44QC=r!?e?v=tvG+PeM7GO{0_1e(UaydF?G%Qh_o+MdM;6n|+YKCNzDIOrLB}{$% z7xZi8#C_RJFe;rq6gjeg<>hlU4?~2$)8h77*Wyzmb~Z8hBd`}dMV)7rS*-{E&KDgJO0lQzelx$uihGIv0br^rRP#;j0G78`5-oNF;}ZnxYV4`IBUs z$pAuPCu4#`WYbBMLewNfPZ3E(NQ7c`IzXMmfWE^oR>gPwDh*-yOOrgr7GfXEuj=)l z9=YiBem=IXVNo&?W`~)aOd~jw_uz-Ry^Wc1HgN&TGL`KzM@71vY$<}_TmVB5lYz?( z4a6`3RWefYCZ=q=9;d2vgqV+!;!KTWaTnk@E?c2FZ&4V9(YBTVS1x2 zJOfPwAK<001X(b8;0knXDEfBEE`b)dS_!bX=}^izCaV5VU=wO8K!Edv0Y42Nq}PRo ze2@DQSjI2FTR5H*GQol-{zB{uvjg@e9+B^KvRDvL>fuUqdQ03|}g1U7>mgFluV9xMF5_BeReoHNA<9I?g)k~(>MEcny*-vfe zPOwTY!<`Wpa!%e>UCspA2qZ2tAvWcj5~L6ghA25Z23+2y9^e!B;(AYn%aSklE_ITN zs73=>eU!9cm)Dw@ZqK3J$)>W})HW_UYWc7ujGl@eIY73ZIVXavlZben1Ux;#7?CeR z$CB0qINd`gwt%k`m1wQ>(G3MyxW$FAI`5CZ{bc1Y5wtQ^hEDsGN%_Xh0!uSK2zc_w zFu$U~P6&H{mPF*xQx7WCkWUXzO@-6da zjEE*Igi9olYj%k3%%RN`C5ViHhXArvsS|_!aRuWXA%K@2^!qp^z76tNbn3myXoQkq zXaU;<48SbLy| zc`IaMXOS=aBl&fGeIJPc5Cx3mG-KMMvr4}R-4g?IJ-J&wN4j+8V|#b)%1@U!D)_k5 ze$5}MLszRe`QMM>&!2{G$u|fy{E(#bwIdT(t__fNKB6wqgKn#{X+54%*VC1^m|eJt zoI;|0rBg_n3gRBhNC~(pKrAzlFS7F+z_)UG9QTZU^AoP;AY*CmP|f}+eqnE%6Y6m!{ zNCmx+@5{CUhuGHF#xe%$VD_xyK0vBC(K z?YmXAjR~eI_zgmK8CuSm{-_qG(LQUUjklT~&B1YToMd6fePn4jH*9gJFd>N|H*T)$ zR3&^Lt6uqHBc8E{ICWGh`?ij?GK3Sc96Lx@VTp%;K5t_;R^n%lRXO*Aw66 zd%v7ZLW@)M3MB{Zh6Q%=ml_m^Sx)C&R< zytE`f((VKu>UM?P4AemK?IP}}TZyq5ZS% zDoXuIklmtp9VR*5dxt>kc&{R(Cy&ih0X^Tc#WO!-9MUJ8*cPxxv$F|2dWo~*k5yQXI7YUf2>)3gX|k+37mhqP2?~E+kNCV zWEaJfy)-h8fS1^Dvu}Hce!HnK!a0#)0UEPY8a}tMtog$loWtmC1S#+;Wb}Ia^;Y$R zh0!k{KT2(FbKTp-PnP##kDF~|-Y8)Z{#D~{EG6M5cC(@+bnwdf+7?KEE6`i|i^Xct z2ri-{wug7XJ|!{YklRCYsN6(A>c&roFvg0?eT$PzvJORek-NwXgvmG%c!ng)uSA1} zsYY%gHhmjPEV`C-wZ;geW?P1{AH5>!tk(bR&SwD=byeYClW^TJF@(8e$3qE5=)+f< zoPWVceNDJgIqwLNLM)Kpp_=e;Lfr^pDu$@E^)J3W{KKn19vt-g zv*Wkb8~U0uDumVm@L-=KNYa~lY(BTz4V2nDM{ru`u#gbMNx3+u0cE3-Dh4}SI}g9c z#W)lNq@=-}%0M&IP@MLA8Ooc1b^n{F74q7X``_@jbkz19kTrxL2+9a-!RU4H8hHeJ zm*|!&;U_j6Fb!GF?kv`pLe(=Hna-jXMt8Wn(f3>v<0E8z0nm0*XZ($~uCnM3R zm_h^Vx6BQoDgD=zAp-vQ_TXNL$k35w9_kB1y_rs6gdZ|TJB)Bl<Su0~2!lBNWkc z2c<6UR&0)|TZ*2rq1-V;Hc{9`QeBs{KhgVW#9tEYUcedu>f5^v7Hua^dVA9k@si7k z7&YRfU`6#nJDY9h&OmMS*67b6A&_tW&qr|r*n*IEUe4IaItx}8or)UPRuZxWY%P&~ zBB9}Z*~uYr3v|fBzZI5}lLE($2Fw7>WOnT$hT4&q$e7dE??NmNN6v8LT;c#PxFhy{ z%+ATH_Wc1!BZ`V;DZhm}2yo}F{!Efx-I=_6 zIqZ)o)%72GyY~Anq)y%M?GA3pBsBdvssR^iFYTJZ>uVUP0&A{r!Ih&*)4+QD&0x3< z`B+19T>=+PdKj(oaDLIX@$1mK5QQ6FLl2BRQmPog%O4Qw2?$bgVEi7RER z1A~$oYsytmPsczsR7}9VA+6r{J?f!?usRp)0=fxV$G2qY}*)oTb>5J``b8UwL{h|&tBxj3h}Y3VY=Dz^;?g=B9idW=#! zDEUl^iD}v(BCHWkm=;wt$+{2h3^*lwo5lS_y|se{!h&{$i@|E`HMy=PX2UPQhJ^95 zlR5&xl>$(c+SNa*0c~}Ac3Db1-sBZ-@AB#f|GCwD{{8xk%ed-1%EoB+ut+96oUGk| zK5-l59AfJb!EcaHS-tCI@9_EWk@*~Wv5&HdTAYzze(?g{l(lcKy-3X|93V;(35t`N zoJ`>CL+6;{EJE?`5?qI;yKAADyXvt=f`_&|abbYT&%2s;2x?AONKQgtV5-)oa=c5b zY~b32*+N*5`bzZ@#vGmzOpt}-vXSEnkLv|C8U54Vk&qoJoo6WFhamkh>wrFuyRKXO zBRW{cK67+UMUFXqGdy{4x_fVeV&vl)(y|ZUx~!zMZj~nxsPVZ}LNsdDj0m25q|sH0 zAdmOBVcv3`>wlF8$+xM4({KJM^O~}`?&C9%A9%iEy|+j~g69u@2XTqtTq}Hm*h8bk zDn`u*Ysze~Sq94THFY43`Z7BJgF0^q1I+96rlpzuV9nd~87ZbEJN5Qou{@zL-{ zqZbJ96dxvY0_mhk^K1rDU^F~A3rCY3*t&(Wh7|MNPGU_IQ6*!duZMksaPTJr z5CK6y3Wy^ls||mGKv*(Y=c2kB{yH}YuUodH8PNm;IDtg6W~>)rkM&hv2Cq>0n!tfJsm3K(HE<(1qMs*OvQVi2t(Dy~ zGR>{o;n$O?QYoD2T%zFtKR-1ikGr|L-NV}!l*jecC*YIe*!Y2voD|5x=RZ!+L{H3W z@u5@*$9Jjm;Kf{e6AW)yHY}7^H5#NiH5Nb?r~oFs%!wyU$v2Y8cxOXaQwRwp0Ug6* zF8xe*NBwX)`LGmXb)D&4;LZ?NDL~X1vyU9?ACNu{`?F^01A;~y;akCE!2_wra!XLM z;2ZhE8R3vo#R_@liQ!M+J5{>m>~K#0@gs&#JJdjE4mRqciC`fV@YJxfI#?t5dLlMm zfp;@2q)5qFoe-}YXb*%&BRSq+A7m;E-%Hs*E>!g0Q)Hk%+3roIFIPpn?Fv6wMVR(8GFNODQPb%T7=L)F znh-9vL$(qcB!uLSk8~bdQtMjJ?g!$x9WxT6`;oAO34SZ~X! zeL8ssSp`I(7zmU=9+h6ADb^)~qg4g|0xEFl?b->4StAw^)smrGPFe%PTe2JA<=+M! zrjSHuPN=|USl}I|4e=a@l!bcZyk7$MnxP=LXY5XAFEBtK=b?Z#JY|QRP}LvdetsV^ zLmxhlRDFd}?Z~?Ix=Lb7^umgX=5YU)T)`z16UxrTr36!Cp&X8Fyq#U85N_C98(%j# zP*!eCF>LrMA<4~rfTPNx)ha%S4-f#z5UpYeU*hLyL?m`!N2ca)KeAb)|FBV!scHad z1DkC;2G06`Z;O=!A{wNImec=h;3Y>T3xLB}|3EX@H_K%nl!!yy_;62_F5~z~Zdz3hbW>+B^?h4jOKo#(wei+Q2qoKJ(lerRzYc&kd@IaJZfgcA%!%;Y5C+9b7BzJb1kI zR20hV>(X`=Aa0(pqoH1aG*0pVXYbwj+PJcH(f|7?DsIw}9Rt4LbeiSZV32Kg+rUCN z=`54hPapy6fJ95eHgU3EXTQODf&F6V`^FgaT2(?gN%uPYgkN_IRkP-G%yGYPT|rPS zzJ3zJY2TN2%kT4CyeR8qzqW6|JdJi1(gm;JK~DR@cEA8(#MsFm1jAdL4Q>JNrcM@*b* zO(yK0qMOPiVn4q~`;m4lP&&)WK<2HK=o2g^DaNy7tG8~L!dlE39u~!3q&5oc!1Ste zH50QCju$8|IsqNuZfEW%GPxQay&ll4J%jQaHjFL} zyKuw=eHMedJH$zv$4NyX`GjhGqm-z^IIE*8l-En-qco8FYqNwO==p{S27?FzWn zjB-&mU#7rrZ=G8V`571BAbXK_Lnz>n`OEpR2wk~29N;1@V)HHZhM@tNWAxs3aS`VB zOL*I;g8>${t4i`xkbsnxvRu*PD>%Ol{o5|3 zNgSd!fGN5t4gp!gk6I01@a=^Lqz|?Kky!eWGY0O>!KK=kI`b;(8a)`!aoA8c!+0uy zl>$rEdF#X$7tiJDxEPSx=Q!h-IcjtyINmUG#XEDJYuN->ItPac@{liNL;_+DELAGl z{7K1Xjv08pKTA}|O?9Mz55;YBk)dNmFe2g>dl|_uvL3P`h!M(RvkLwbNgs{lE@t5H?!GX zN)cO{Z&k+?HN&C%o`dTLd-MxsFn{zQ$4Wc_CpIXk%%TiQM~vx_i=6iv9Y=b9`67_B z=xhwiBDCPZ?DCM&_~v%%5v*MO*6>{^@Sn>epZ-m2uf4Ui-PzhK9v6@9A)AQ=g0f{-Yw0U3S1$EROiSRGwacr0Rwk?s6&fg6&iJa>Ca0@UxwR^By32g z1UN#8TM5ts)#tqs6Rf)+-e1oHFwYLBgSj`;ja6lI|LAm7qRmWCmbL#{8>STMa)@nd zE}$^R9zf%5(tj-fr|a_+W;{AUoDV6n?JS)xv9Zo~6=&#n4bQvM@^m!%p>}PE4k`mo zyclV4{TkRToj>mwfAZb@c4zOeo&CL5YxcNNv+G9>jng^!WdlY4`UC}<(UF)ztR?`F z-r#6T-<9Ik`u2-A>n~dVlX%|lrKN;!Y}B5=Yxy;rgn8GTCeM)G06Xo!!Dse{MLQqd zU-|NnQoxgTUO@Wd!$&KB{^~C)A!NzU@z&;dC@}kK>)GBqO0w*(@4t*w#pMuLYV6N- zHY&u8c~N#S+)$@U@GW$n%*n2y+XiI*B}sBZchSaA;3PHM)Oq)!i8>@mLiEo|IKq;3 zP9%9;1SlgHQS5^*jQ}W7huk)U`0V*kx^x)-u@A8qQkyv@$mxIdFkthO8CbTU4t4xg zgd=Sb9ciELJ|-r4BEHs7;Z%zUj@~|@^U)ezu06rPP&t(%pvefrPcR!1G7ufpTl?dE zq(@s2m+f=9&*oq9dbuscT<+Ytvx@((W&QvW@MRxx*B96`{%z!+{!9)h@z-$snR8s3 z4CubX_Y~l=EyYbF`Z^z+oFeaqmcNRF`y^X78c?kasSJdOHKQdFB#8i zTXY`?8+QTdT-<|reTn>2hrjED>4Yl}tlG`i`ApwrfZ~tjZ~c| zzA}}?+BUnmVfVqBfiKt{5a^$%o-X$BDfh<}K^tD4A9_Q!3(-+_%wH=YpKto(30=^0 zfFmTRVp~tig$$Jr*iEH>cD%akTE#e=w}(HU0$V29=Qmi#tQ#c83d?_w_oR8y`vNZh z$hFq{;`SG}mn)q2`;+-rNb7`Pp8f=wAfL+5fA~EpZqA@Mxd(SBJ2TpZ_jjPFnWQw3 zMDLnjhSvj@GghrK_YGWdawLEfFl|s7Ab_7<5_gJkA<4>RGS&rt7R+=i4ao9JsUvEy zrswdu#fZYXQyr;yP*pR`DR@U-ySWJ82u2;4WPm7R@(*Ox2jqn~Fx#)GM2J|u(_zt` zlAT6*am4E3??ps$>)&gK2tB_Vq5kO@fjUc2>SS@@H)EnN@t?h3*J9}F% zwzk(_0sI;pJFjAbY8ed1 za4@WHY|hypR}sy?9R*I#@YX}KW3k>-OhAtv^w>EYbs<(r5fdH(*hhOYVQ{RyalzMj z1aIjl$xaiM6C0}IxXeTj>AZWzBwLazvkol^7i73H$)S?Vp}>FZXJ?hTZ-HE<2$Wc< zlWP-F8C)D!;xkSI!EUu)b37QSyc8=^eFWOajnC3Kl!S)t2 zb{{0WU3N-MN9(}n>BKTG!(<$>kyNpQ%Dd$>?vmtN-!c!bnLiP~WLuy^C~7Pdz0LmQ zXgoNy3+KR)0L5cBh`?e5N~!F#1FfckbDs8V<;+Sa?svmS{Rmt{>KRfmpP+SmI(d7q z%vjpG8|(gdao$1hmqOtx)C*@O&R-0Zkc@G>a!U~tTHa6zBy?K>_8IvQu9UqopVdY9 zn@9yW+#VPJwF)$+>JH&|s&q4|v=5Ro(U{Ec356vDVvaf>Djy^(JDk3U#AINvG~#-D z1UmNNYPXAm?cFdO2m$CrpT#!XhUv%BhXFQr^!9IZ67wEv9t zi{qjR{p=y<0liT{=OcX8iN|6-YOGVW^!WHN3vU2Y;sEkiopCi04l zoey$~j$Oj#=^7yt*>db3pVT5`1nkQY#*_&GGh`wg>IO&%g6D*pUq#J6(tkkd3#TK@ z9%yxzH-WC4Sa3mtb?ck&?(FTm6J`4ttstbfL`^J;u~|2Kd*fy6b*uClyB779IN3K= zb<_AX`f+ppDoP|9y)F)cma<&Wd>#6oT+{K&%EPcT*YsSeR}MOHX9gi8QYFqK%_%SU zQeL0{L(#ZXQZ{i0hN7$V+Q}X%Z;x{~op$n49d0;|l}dPk3IX9| z4B;O1#)VuHDDdo$1L$l?rlyg$3Le?FpzVNHPQgCfh9Z z`qOqZ#O_I^CFVew&`Ugl3AZ%vGW0ae*#tI~lmbO`*&`~JJBj4O6)JUXZnym?k#*Dc z!+!;!xzk)FCz?Zi+&G8W_?`QG=6+cm?y9v@JtX8g@U;8O27d04eY;Ep6 z18c`5qjp=UFuJIK5`G_W0RQ4o`lNRHe%eTsPYzNwn`P);IPG3R27tl{2trgr>OsK0 z1^m%>fWbi#6Q<6b+Ng?5ak}}Ah^Af zU?+v=>>6Ro$h*b#p3Dv*TCn6?1a@?2SkB_hrcQ-ol&QUFg065>T;VS15*F@70P!W{ zn~Gx;{9$}@_!u)#V)L0@SMBp-GGo8hZo>@qy65iS3?|Z34$H2(D>JZv=-p4sT1V3; zOEDXwegtyhJ?ZsuZ9t!lQ|uOmf9=l8&$N$2>3oc2uzhMWmVN}xN`|}1yJ2{|ETu&z z@K8LuJY-E4pZe~<(Ee}B-=2;JljZduvS{?j%NxMxOArjQvDQ)^O7Q;H?z@%ZkarT| zwoH)PR7pc&U*}0lfq)7u51-ir^HFS{%Gt$CK{k^<17BY5M{stGM*66$wrVPx`&E?_fUAF z`QP{WLG$5*V$rrK+mV+@x&jI{x*S6ee^2fm6Vg-XeDI9@4v@!A21yqieS8XQMd@ok z)X#syRCJb1i1*xnvbluQ;c){N-%B)?AUtlIyKL|yl7suCGZTvB7icHu&tvAe#u~)? zqb7-)oLM~dmMTE7QfR=alfyOT(#PH53D`d%gtJRYb7;G}Y)1rT5rV{mrwUeq&%m{? zELhYJZ;W>4N3{#Qpc8+Bv*i&JY3q~6c*4*~XgLp{KcKDM{foOLl5|ijzlOXF{q|rwMS1kc{AV^GDrXV{k`1K@a(y4$4>u!9J>bUUV_Zi8Z% z8oo!N_0jvu^Rw76O%_WBbJy&z&GL?^hLU!(T zmzOZ5dZd&75QuWxe^YbK<0y8KXks|4wD$x!4&n*FG*wCfQ-os3pdCb12s-W@2|Ddi zhXS9WTx^+RO>=i1PttE%%`AIF{`K=Q>cB0Hhqtfdfp~HGQ!@_oc>^)e8c0!hK9c+H z218w}faH#64MhT$59Gdz2C^7mzlB_$ozumN>%&3Xba%yBh?|Ywl{YZhrao@`nm;ug zbg|<6qGrw9(b)3r!`IOYWa`)6H6f_$!=9c1yyFQIxUstTIi85-FAeKJIRYJNmrpC( z3mdHFURx5QfPHsGzeksm7DL_|a}p1xI1%5t z%&{B^#~pQ4CbInxs4YD0`){n@xS>vzOj|q}?uAZ{FOmh432H-6*FR6%KldqkYg)S` zc1ZRmd%=#gGx6-Lrz~~z&raV?#8#&)9cFjyRsgpJn0KcrVvdxl{sfIC23qJMQLwFg z#z~KuZ4PgtR~@Max&W5CnAVmDheGt}V1nGh0azQ@6-mMxsH8Yu>ilczI~a?Ow9D2J&d7F; zqdK8C-IH{a%iw~27Vb4iepzo|aMPYLHa_q(5ieW~a%AWUQ2aM61PP!6lwneJmjn9> z_akH|*mRj49WTiKuDu;xE_nG8P-V*%#((C5VNkO3M+yN7clibyoLsDEGcHaWMr($w z)n|ofywHpY+5+$g%TZ{zylj1dzk)8AdK8pfChb~wAG|-MV+Ip5=o4y^q(#)&-$dRZ zq}AluPl^Y%glLl^Q2fLU5iHF`Mur4s3u|sKO3F$5x_ze2;OHDBgdMQ@v9NX<3YthN z`LZL;;11_mGg1|r(559cA^V{-2@}t^CArwz5%)!N>!$0VK%lu}-13yBhZALIwZ0kCBB&}KM8-L?DcHM<>vk`85W=B9w(h<3wQsi^e4HwBqGrNP^K&60_D^#BPI${n~0E>2~Qdl#ti#@@tNv+i!J$Y!geXe62Qvj*vA%aY} zKv5#6hM&425y6QN@a&1QA%7sqQ&EXMQKPs5PtKoeTm3J;SZB_5eB-RcjNWYRyaJNZ z?jpR#kAg>!|Ca7N^jpl2o6S*z8f8t$>bU+JUz4en_TiA(ls^W@LMpkfXsI30TT^Uc zRfF(LqwhX~)O{!U2$4#qJeC{JeF@@QYffid{w#=*2CE6(S9e@X?6jY#Cx_l`ot$ru z;oUdx-+(aO6aMSxrl&76#j-un$88X&K}ExfBdqOdA{hjx zE~;EvzIwB{F}Us z{=fnkFI8ou>q*ug_aH>TPa(%#QJ35XKN0qSl=UC8U-1axqDCE*dNb9%pRG!SJgK;^ z`X1apt~w$&Z9VUrGa5`#llG+F+bV~txxNVsZi4xNHqJ(-4cE*)3Od`Q6opO zyjNH<2*5bLe(ab(^LEa*b^$Y$Bj4~R0G<9F7m_{j31|?&yaJaPDP2VmC5`ul-G~n3 zr$7;azlCVx*gzNt>5K{l-U}CBXJGv!i!{xs-*4)3SIf=sS7U+ z6a~F#Aurd0q!RK$;Bh2!sf)uDeyhIsewd0srycWm;E7XzVK5KWm)d zgUYGeXElpwdMVzKXK>(xPz;BnqyAq1816;GqY7jSw@9d|aA|N!P^~Fe^B$cdNsiZl z1l1L%j!kUKKng6gFaal2EFLEWhL9~0v`mOnnq+3}E02{94y3pypqVW;T=M{#wfh{c zCOQ_|0z_eOmu7Fgq)Swoq85CAMExL6fEw`(1dpYyzJn%0Kgw@{17CocG5F!PXo^{1 zZzOA&_Qm{R&Bk}j=gYm~e^3;9&n0B5X8eY_H3I30?pyqmZ?M~YqY)|?r+x3@rZjK3 z(L1s%#E${(B58ww2YyA)t3w2o^EXTotnj3`9MX>z?(Im$Lkn0THA^{z8%(=>d3ZjU zhC!KsW;{j6?DQ0-CoVH6CY*mb9mG5 zQ+=UM!70C^1B)Q4Qbw||5~?6Lkykx91M(4n8s7~1?@Kp8XC!daSVj?O#sQ>o6y1Mq z5p8TTc06BsQ9~I7s&>udLljk#k0K*pV52}7(vJdO737AN$D@lrD(W416CjY<`;fJe9SXYW@I6fVFO91_{?o!S&sz90p&d}1{c(G)M=59 z`=euRR3lY}$%Sc%euaC9{f65Rhlm!T#*?Nts?8!cyAN9x_d_`;orYU%X0|Y;Af$i+ zj@HR_IVGD*764ulVW1m>g!8$=lEqC+J*1+dQRENqivJU~+K*o)(CDWyMPEW#nYpNo z6#ISVk}?IDUypyVu+h%xI86|MCg_05aGfZN?5jZ_XV;Bd>`{uNqeot zTGEMQ?x};Nc1JLdpEZa`qxdN$XE`t22#1MWK`8kYLn+7L&nHQE`YAqEl@IoCUY#hv zl%1@T4_()lGRZBG4Y@1;DQnnkEk+{`4z_X`GP;|t_i&f_B>bhn)m$_53kgJ+k1hD; z(ReD=Ns*TWCAFYoEE`B1vqJt7uBgc7CJvxFVe}V0Z+ff#(m#+8gKFHU|D=IQy&J1RrSPo zVKn?z)jToWavJ=Z4{ErENr0Mad^tA&$+#XjRs)et&iMs*MOTm9xg@*Q>Q2R*j*uL`?DBiP~OfltC;<*OSkHTCya z9X9%tG8d1-Mw!>MzH5Qy`@9xzE{gD#X4H#eh$=|CdTVg!d_ccP-}VSN*9kRY>D9N> zP+$CQiO&Gg!kdR~M3GqJ{8)K$AvERC_1oPgz}s(Zb;StJ7-pG+>I}2%5z_G?gNA)c z#|4Bceyjv(bJRuel2HWy<7eF?D2JBc{(XJ%zq*S*B8g-1y>}qAF5j-iNlG2)@ZSo+ zP*-392={rMq|JRDz@AUSU*Wg8kgK8>VAoi!{@a_0t->*%#x58K@UG#1W~ z>1zYr0b){db==23Ul6;E+Mwq$MED+J_9FDVeJM`7;Q>04e0d%+3>u=0Hw{FtB9IOB z%u!9{`b&@dx5k|hV_?u2ojO{rK+&HlMyN+-``wcYL^cneIHUI$G@AkE{M(OsipAj6 zx^&ZU0x8e+296jddlAt9D7W~!#fxRXg3Fz|WT4koxS)<8)?gVpzMo9q+DCw)YIM)* zwkBA*hWLfMT_$xh#7yvzfLM36bB=T#5D_m^#y#co>c1OOeg%LKuhf4XKoHbGnahr` zkSzV-JGa<6T4bWN2D_T~uKT*SNRY!QIm;66J+A_P0<@)nm0>TkmfFiGg_dP<0E#x_ znW9fb1>0242Os)9Nd#+eEX`F}YY5h8LsaXpq)?piv80B|o!IKxkPuZ`*=C}h^LCy4ur||cv9=YHndD|T?M=yqX@uW3Fb7d$ij3~ zesv8vW_n%1qOc#(AwtibjD|}b4N!tkw$+_=EA~34@Hp!-+ASWHj29YS~8ncXo1bArQtcXGTOa0F-M_jWo1%P>TTvK;3pjo6MhAbn3S$n zz7jzto@4$!edwHtKP+d5i{LL#wSpdaEEvrPRIL{fdZ+wlk(OF0*N+P3ppk8gX>m zZ2a->|NZvhVEOw$(tscz)ZlBM%9jovKKxCr+>XoO=XZ1Jkx%0ZkoR`ereKx=^grYYHBj4TIK{Ch|GMyIR0{z1jC$G->C*7kfC=R_;{j>FgU=LIctj409YCoXba#J%!J~f9#lDVro(!7c|qKq}z4zRAUVX_OBP z0RzcMppA50NxP>16CWXJIpU+a6>hft_H6^si7`M&`xKdZb8u@mHavKFkWwf?e}InB z_{wo@)?*CCHUp;JW4!|;`x;B4FebA^7SAIj4nxAUP}!>MvBXY$9>g4>hYX}_WK=Qc z9Y9tK#Qc1_wY|CXZQECFd-i7Qm5(r}n0-b=KriyUL@Q_5XcXnT>>^jl6nQw2L~qzd zRZm1KoWRm*S)P^T+{MY9bjQfm2?sU2nGDWwY0nRhSiv0^1(oKyS@=T2A@FZblk5^Q zKH&9XTgjkHkHb0hhZls5yoeQX%M$pdy_CTB{IH`_QSe6SxE8^4Yg*zLoe{j|m^9x3 z45tu*A!jpd5_Y71ED2$S@cI?<71nfVpTyhbFz)Ys;+%XUj((mTaC0?#1BMQqI@?01 z2KMTYOF8HAWO92WxO7g7_R;D8`G1C}u5wm9#%H4m{BhP!Mx&FnK7_Zk5^I@ekTMPv zl8ccvcRfg4k=+TX_2E6_7?%qkS}hzQc`4Xh4V6&PiQY!O{iSyyby}uSh_l*fX}KtI zQMk`=naNU>xxylB3wJJXV6GA#SuW;eG#Qf$Yr|e1iDmfBTE<^7DYVJ8`B$RNgY5;I zhhlVe8AP>U{ap%2AhR@`6~So1MF`zcYGWN5A{}~A5k-;%Ja!!u8&v(EeOC&&NHITj zVqe1`~u7Sg;N@(Sd z+V;6oU*(Q1BQjC(A*zU+YyJ4f_e+hu+?{;SjW78a@lCYH;#@1+5)pjcYyWylraDgEI~6lJlUmy zJa|U2h$5S|tK{qL$P(NP&{y-ma2oi&(;d@9N-O{U(2IQ>d@deahyCp|k zPS!cva(|d?2wsRstE(7xU+GE8jDw75Wl8ion8>vxGHbfLg2;O8(8Q{lL1m&~ZWN`x zRE!pLInEzg-FW>7u?!I5lXS0ej!3suo=53e4530-Z=16C1Z&(8G#guLqw86@!^!7z z!$Kd5Pyug-3DUL}!RQ9FfpRUVsl5(lu;IhSatUy8a4TB}H6vf-Pw*WupZ_D4bs zaRc!C)LE#Jpjr^0)|qL1JQzPc7)mWq-zzbT%{8LXFOUwRJG?3c{2aBSVq0!Modevx zH7b)+Bc0kz5`^e)K8*KR>~6H1HAw>`>X3RD1@N^8H9jP4=;~l>dSY!4(f8? z()|wiE`p&H^Ee`yccAh1I*I5Ux%JodZFhQgwY9gWvJY33_ivEQ$nl6W*s9CM@oLvC zH+ky=Y0+iVDn6GZO84KGRL@?-_@(+>9VS{ZzP9RA^IoBRcUa4PmY-?fE%2CYnv4*^ zdJ6^EE~vY8I#|#+@Pv+4!(%9%L9NCoC{r?INksnKv48Re|E^iF4>IZh&{~U-o~7KL z4CvHdz8|~RdUND+6m`SQz%bg-)->Vh@;%aTkm26G$v4PGF~AZrXLVISTDMQ4kKLaA zE`#1c1_h6+0;8srzD9~9%j3V;9KA;vAWA-t5BAA(F`JIpsAe5)bf2MU?^*xA{i5%8 zC*uQHfcgKE{&?*54VraPcoPKzGTMhm($bdP)~sI&nC}VzC?5!bm-X| zDLTgwv**43$r$Z>uQe4!W*2)mfO15pD-lb+Q{lqmS%HZah^gUn+(whIOR7`y8fQ>C z9CzWeK(<=1PAuS7rY+O2@l6cO?ip>^4Jc01i3VqWXL9*QQ6Smz77HpTh5L$gnP55^?P&`e5VFA~Pf zU(ln`#TB4#JV2Bos05D9w!(hnI`ONYzh*xQr;BT5h&#WDHjM!1b;AUR;n3NDb`i?J zK_QReESqsHW9t|AD}uwn`D}lRcx~H+nI{cQv!P*`L^G8K{x3OY)#Z4Isy*O6up$Fw zfRIym=!dup7{CtRQPP?lpqFSzG3s@DW6eswT`3sbJnAskYu3(&-VX{bYdLdj?t0Ih z8Qp%Pm|`#?p;C4XR&bf~N1Zv)Q@TwtT>?ccrACU7JdRl^ z((_19l~HqMT+!5wQDPq6P_y=N=Jo;XUj-iUnt7MF#WLP8|7*p1SU7(c+{E>OU~AUx zfb{F$oDHCu79CXOgeYjF_7m-xB!$0eH+f-H$4b%EP|g-``!1N2%-` z{L_|M2;^vu!@pawf+Ox11YI0P$E};lm<7TGOSy;mkX8fNICaM2G%?6zMC$^Y7->63 zDXHQ;E4Ot8rMQo2pE&H(XabNin;c8g!s;;^f}w*k4SBT?IMs8w(r%JY)ZbaRJAU`l z6Xoj=v|u-Z58Yjla(>QnPXb&>p4d;kBsMmdI3IYo#iGc}V;OY+OTb#->!6J~jR(Ci zZpVN&6P*9G07o&0mMYs?g>HZmtz9fbOS9Pz{XVJ?0<2(x8J^TbP!k6OmA>56@-6h= z-4vL}>Z<2IpFIkH{0xEejBO`9miE1~P$uG*dQE)LAT`FsiZXMzm|Vb%*X_ z0felt8|sr}3-|GC8NV4doi z?6mQ;HmFG~-kHR+A|Ro4ENprIy?}x%=L8HeM;RN6C*)FctU!{1BN9Vv#4|URU~4_S zJfu<)CM%k*eAaf~>^6$3-oIa>D1rCJn6%ltegZ9xu7@#ostCjfg7G`3orahdRqUa} zADr$Wt#;ZQFI%r$k?O!cb_zp$4vmyMFUKxANdRxd)Jn~4FgCJZE1L)iTO0mfY7~hW zUIZvLBDvai60;svsSU8z_$t!-VP=8N#5le?Aa!s9;Gio)C)OPp(gT$C9;&?EI zt*Xy!eSAG7rAxFB{#k?1fRhe5~=d9xRo5Ua>KByK| zo?LbBnLQJpUBoOm=%8kQ1{0?T2FyhoWJ26L`(PaAtmOwabNzgMH{lcn=9B5^t?@w3 z2G{L_@3&_8Ci@aucrB*^$@9?|YNix>SMGPz^{nYc&FIuRJ_FbCd~~LTsSVt0I&T}i zV2$tJHjbr1hnhRy4Qw-gZa#D3_>6`TzzDK@t~i)0^=Q#=WpvVh3X1O+r=uVG95-B_rRK{BTq1l{b5IBqu05#VY?;xZ=`t%8 z7PXy!VR{KlXBYO`-IBoxtO5OwIIm0?1(XrkYy<78C+0KUDi>ho4;~?<5AG|^Bo`9& z?xK72L-zzx9806|2?}^+QAW5F3K-yitRV<41{J_6{(~LDP4;ql#eNWF;-ZRWz!l%>tuQz%rV8`W#mtF(BgmW{)BU(4E~~<8P2j%WSK} zZcLt{e2*Lvyxp9i9KXdvOR&K*&Jx%+q1CNlP`v=xQ}~608jRi(`1M7AGafZGQK*=5+J!4nkACa#kUDG( zDuN(E?189@PT)fh#SvV``(vhegr6$}6F3ibA3XZfLkIDs-^1iWKh&HC?%pJqWcdR3 z=%=4%Q-cLuC18tL1mp7uC`SOig=Pj-rE4WG4G{rWVFb@{N%9hvCdZ@G0RmgVlRUcu z)Z>fzUO6a=4zC*Pp&zyH2_F&otD506xV#mETk|pKEPb_}Ui|CEfKubt2{vw@(>WcJ`8ZXFD7g>|w?O7D{%$#e)$<1>kU{5#=P5SAb> zNN@+ur8`d#;8RXshDA(e1!0VzqtmX)5FNHE?>K@S*+%rNxY1uAS)tA2m4>VZ97*Jp zYm=o~72K8;5OaO~Le(e4?`r2;)TlVztW{BWge7twavbSg0KCER94KFc-gLdF03_ym zrghbs=f}%FNvR=l0}CM6y+GIby(UJHs_Tdsve8+wV=NAY{!hC?O;O+}WIfd*Y)gj4-b7CR( zvaIc5@FhAKP8aP+&Ic0_i(@}crb>gAi(UVCe2yR)^4J$iKS%X{~Tq8#P( zjOb)?M%jbDPaPa2+}q$!G^{GD&d#xut@BHXT8J7Wvgd4o`UxQG3_QZ<9C9gOXnx8c zgguX$rcfB~oO0{CoN()h_!MFI5|6x#nLZB_MPH83c-yF5ObTNCimtN-ZpFpxq0!hN8vND4iOLI7D9?iZ!1KKN>y$saL&cn zK~<|==!=@^rP^#^_Nzc&5hmqg_+y_%c9{sd#ZN2y%Q_7E!LH|Bt;?ZUo3K8b=bl;j zB%dWnLuY?IGG-QfkTeMUG4-k&KZG zt!&311GJZaR#ySXC7B1s_&kA(irpe&W00?i&mfh{UHI0b^7&+WIv&C1-=CbKA`H4)I`93_ zb+*XPM4C9qVFO1Tk7i6RkrLfPaoq6TaC?b~cqc$-Q~(R4yXU2avWhrqL!*Iz;JE7S zP%=8KC^xO5;m-y2ml;xOEN^Pyru!l3zUBH$UkcQkoKb~}s?cIOm|yv@cP(B^p)Q+P z)RAIa_137wxDofqV4E18qiq9eR3L&*1Su4zhnFbcGqoBD7nB=NrkCIc!IAoSY?63t z`)w68<}C^;Jo|n`Gvb>PSRxcLnCyxd%Co`rnT+aWAJ09fYD#?Sq;?NOi%wo&`f+g4 z$VWPI^u*pH9!u4i43-5&=ONIY%$Gn4PPW&4>_SWR=SMVRJi90QdQYSZUUW zJ-P4Am3wglBDM`kIXyk|=Y9C$gV*wE${*nR$6yHWBF=uL*anvjOsfJtxaj_eqq9r6 zw)-8UQb4ukeM~{s`rz|2AyC$rDc7;DF|ISTpO?{3ko@Wi{(nx6Q4znr8v_DOs`b%*3E@QPTsV!KzrnanNhxksOP9 z+d$8PC(cf23QKVq@~0sC8{w&J7qPc1DpO>8`{*x!$+w1GIa*sujJYilygCdU-%$BZ zAJi){*bjefV@VvDcO;77%aj^Q_P9;`o})8Wnhfo>By7o8)LPKDvdqLb8~YF}Z-L?_ zf0%$!h}7P6OsMWj!EE3$hY zLG-TyBJ+aAEd>0#DFHPoO9&mTaZxGAh%(k|$nM{}_jyo^AyvSwDv*lS1;VG6@8Sfc zBfWt(2i!geN5Hod1!E+f4S9`zJR2OUhO$JAO6p^D@L3g#%I~V9Q!NCoiEi1OOCcd9 zewo)%deqRA9%5=QCv9s*$42G+SeRskTL9~TGT+k?G{}7v*34Q0>isscPk{{WH(wB6 zmlbAw${&81sY`&_9^C_OtLjKU0)la%QSc0W1s{D{aV7a(WsI=vkpBVpSFA*SNX;nDS&;v+ttPo3eukFb-IX29l@BFkNK z{#%V0U5f}qxJUfgFjzbWC{UTtaNk52FCv69Bt?D*4RmtBTxasmaA0YZap1y3NMe+m z3Yl@w!g&5q5;QrvN@0^Pz?%F!1Wpc}!ff~}0v%u#PEo1n8g&aR>uAnlh&J+`bS&E9ZhsmxL2|LmhXQ}+Y|c}tPz`+>c~zyu}T{h z`wK9@zxY%7u+kQVJYH%@pTic#USoTdjH1{cJ7yklLRR8lRg^YWiqVE3xUdgAoUP(x zqX3oU5k483ZorunYl8J6H32Knb#W1h3gMs0(WT1?M-jmouH#DpDJTwkbJBTfG!?H9FCJhzCo>H}qu?Eh<0mjU@ZLMGw+p zu6x2T9StKL0?s7QHJi##A-8rfghA^d{O?xe&)YSKLKO69Y#w`1mq9TGZ;H2c8(QY+ zeGi>&uvXuwio5|$-8>ER0u(r-BR@&;)R_9GYzLlpioj!lkit&14_q`BgE|cov8K>H9tb7gL!O4+Kyj%2Hwj z986-ex|zpAX#g|C9Nf|#(kM+i0ro^#pCdqmi#Il$;1D&>c7hnk(@=ajx*XGSiW&nt9s-ZuEk1`A1Yo3#++A{00KFUEv=$%SyZ>|D^tpU1c&LX&qH90)=*8lEs|!zB{r0C!!DE`c4zyAUoy zf<2$q2ow=rDlI2=^p_p=Eh2&{fZ{Z^IGr3&Y`5LXnRdzd#C{!X>s1}UsnIAII-0#t z{X!~lvxeHE!d*<}ObdwmD*zs;eP0)c|0>fKn$U?Yk@(>Bk-ooB^Y&D*~?5_-z@?J ztfYuyNGzv#aH}C@cpm} zhXa%qqR|*BrkRH|rq9dn2DnurB@;fVwPtaKO`|)`5r;#4UOW;-GQL&YPyCV+Yy7u3 zrz`4?(K>;H79_d?r#<-PfIho$TuWYzXsgjgJah2wWK_@- zOeopS@zZYDOp&EUn)qRHkXM2*iXPuF;i+v&(vS9B(? z79DNG2;lro{p?TLFBOrkvs_9gv+S<~tBgheO<)yB1kfbRwU!5#yt#gfU{o6f##Q~6dtMGzV)L&2A+C$&9cd50vyEaaB$;KqP?YilUxyyP6{T3#nuz{qt7yBL_; zB?PlZh&8+08Kdd1y6t^_5#9EO{Ytj`CRe>?gvzU~$(gW@?6e{t>;F49KVO7k{zmHC zp99DOq6MCh#)5A5g?d!kZEg?di55FZ5{X$TKhEh04EFppnz}XXj5dKe}Ah&r7N$03Nq)AZawd>jgIlwGmhkq0< zddVq0`j=Mm%6eo~hC$NcWRd3u~>Jm2OEHs48q6ZenHju+}QbPktGp z4eFBU6w0KQ1Euq-Kxn1QQw4F?b9rG(X7nXtEOUAuuo7kuY#V87vyyOv`-w2Lae_$r z09LS;51gL~W6f2H^nKZUhoa{wno@gntN_0I=prQI#N3LB2HJrP4*!qSXkI;_vJh zVRUN3y!s4kzY+7AX!?OcVC745aG^34$6Ga*>S-gHQ4NVOzMrDm{&i|rqIgutgmyP! z0hbPj-$DKBqIyHxqi9*8=;VqinT4-{UNX_o3(<>#symZmrp z=G`3vT?qh{k(Cq&N8rM&$!C~J?+SW+q?+gMCBw_^C`Fr-L$BJnnG5(=G0zdz&LXu+ z{xDI~$dA22a9I!VMOBrD+U8>h5F_Ln9#P1JjRC2t=K8kuiUY0Lz zujX#TlE;tySSsRx$85?JisB7?57_{21KCLeab`&t21}p$=aL{r z-i;GpOYb&{HkbXf)k!Wxl87^fQI1&2M%Yxa9g^1O;nIruK}+bBbA--vcOn%QSPW+9 zgVS?=1jVKY0`|rqEDqMw$p|wCs%OQcA@U0or58}tEML>C6YiwTJuK?ODks)>pz4%2fFz43 zD7)h$$p)6AZuJ#cf<}6+b7$!L+8Ja^(7l(*lM{*QGQ>Pyuxqjoy3?&D?z0_T-$=Gi zCGnq6jB+!9;D&}2WZU6#&j`F_U)4CLiUTrzi5o}Ai(4HLmw-a)nwx>7W*17$t6(yP zV>>dPQ3}v?7lDVGCif!5`i_o~eK_qXT(#($`AQj8#FL<07oVIH4A;?Hx?VTdp?0~L zF1irlRf%6s5&-#4a_-`ee9u!vC=h+Bc=9p`5i7$LIKj&~1XhJ_5^r1HRPh%?vMi|u zIgz}V%lDV=gX#?!c%p<&qIflQM6vy0H)OitiJ?OTnpQ?8WmZwb#|YXuN`wBtNznHs=}{acm)I#NFIWWXxmKo?g=tyA5QtkT0wt!_ngW%A-bufm{1=+8`IfP`D zdCOnig=+>I#!)t5Nsv3{uAEjshF}5P;;?zqb~$fuo29m~_jbVxpWIjVw|gcN`qEhy zDIQ_Um3m%fk`L5qvBz>@KKg4TD9;sN(2Qn*hRmD$#C=~*1<39rEtG4h1C^@fDl|0w!PCrduzUjIXvnP;UO0z&|qdC#wnpYvy7iW>GJqi|{I9K!Li zWk7RtOj>kjHB)X&v2e(^$Qld36`S?)ay;MTQ5xS_o~j}xHEAR88U$p%$v2SXTj+P% zToM?Eqvv@1iFf#-iyGXz#mklRgJAYjq~N&vQGz_fsmcabh)x)Aua7$Lr~tt6EXzCv z6wx$7l%ZGk@Cb5dh4dC5W**azIz3Gm?fGf#HngAP{z>PbmvAR*Qd;4(q3Xo@RThAI zdK%A6bd88gJkgUSE8X!Aryqf0~$G-GLLa8=7&CiaIxkqWSsdZG?<6 z;g|xpdxI#_fJ$y4;+D}dD>-XVTE7$ZpyYbw!Wy8&O`}$@5(As?Y1s0EmSI;ckoVhn< zR>QQv>M@gDMrYNnqU}YS`L=de!?eHZG5ySVP8BoD4hStOK&jj)A1ph*YrC=8)Qn|- zaQ&2PT3mZK(14%X<*7Ic>!Erb_I2$`-b=j9_b7Z;@g{$?vHrUC>eW`Mlg(CpapT#> z!>R#3>u$e!^(yb_vwr2%*57t__V!DS(SPaL-bM)teD-?tQK{W-`>&;EU1F@#Q`}*> z?K4-yMg;MhjsCj#>``5dB*4TYd(w+L!B)p~U75`#xa<5dq#0|35&;MXpe6*YAZyFgDWaO3f+Az>dnkW-q>tU{{b(#N3I37Wq*6kVwF8vh#>*G@7GR zJ?fHCkkYyI4!bHGBmAzMs3KXLI(%i?IlZP#e*pE;vgu* zCE+2#E}f89sV@=AWhL+UdBZ3eB%LQv>nk}c+bSB2K|a3f&>A33#X3{&&6@R~l|Pks zf3E0@XJ+=4S$$c8VHvYSgF{W@+hGWBEq+eqoO4}@6x%3s&u$CN`Uh$*WWUNpkTnJW zXNP6qMtoDm|1BJKpCQ2Ntp93+94FL5d43wFj`X)$$wJ?Xi`_BBI$tGcF!J?o{Q9z6 zv2JOG05jA#04^!DB23qVpmJIOK;+EE`Owz|dnB#~knt7){JwA8GF%Lr560rG0N+QS z?@wG47}bdjH9A7ku2^Qe697{r7dwD#*I<8=Sp{Vl25)*u_C{Dh00djK%GCoQ=Ss*q zgd5wwLTK#yMt2XT0d&82@jWsDCA%L339kSrDnhRKXEYlh|9$~GI>cWo3~BnFdW|?pS%wTIvNJG$T3w7Xk9`-!0e-SP4#CWUDB^yW(>C(1REDD2__kbTCot}>nav0j(E$)5!<(JU~vV}m$TUuNd ztZ=Prt`B{tLkGPS)Ti8LcS=!S}K>!noQD;-_Kz`_-B4l*0v=Y;0^Y2$peJ5{=(v%R*6UDUjUkZtCY=Y%AcDAFLP zqmEEbiEZa25KS%!8O+0;&%HHzY#M3At&yXz*h1Hi!Ex8^ptb#_>t;8_} z_?{7I0JJ277l;CWmy~oHdt0wtOiG6`Ww0zug)wtPN?D^6lUMn3t=up9)RsZUEZj&B z>Zc=@H1(f~j?!sq-1+EvTLZt|JM@@DP6}7V^Wq8>g**DEkW>JRn7)~|7R!%wW7E#f zGBbylCzB;s5*qfW{DZ$g9rV8ba^=g1D|!KqoAaqrFaSBVg$WX49Odas+)G72)ZJbo`qhmpXi<) zi$UMDsCc0x#ba1K(0pZeXZgI8Z4=<)(nm^Kxj4Zg-Qx^Zk%@tWLwkMOxZ`kO(-B!s$@z+-HH09(EjpP3M9ahzU_j)+*h z>h_?hUQTub&OCV5?Y$OxV*~DeEyu7mox;^0rlXOK&#@|cQ5v!Y>jwDOMbr6mDOWP_ z!%pXQYyaiWW~Y<%m)i9FD@~)13?}mw@=dnHDa3r;yBdMydSRt|fo$3RYefPst|YRE z7V$3aG~WSp2>%LDI7Y=D6}~3jVgIw@8I+_n7U0zx6ugnpg+8IJj-`zl;?eC^Pkk|^ z>-R#s{=p-`SvW+cDQ7#HI|pIdz)anDBUH>|7938a>$e*nvKTJN-ajvy7LjRlEO9@k z&tr}&u#hh_unbcs=&5(Gn6cCXisM@|L?VaO7$1UPwasy7Tq0|Vl`Cm4Cb~h7ABqx5 zum)XGwcIOSI0ZDRxGWT@QSq9oY{G;crqP*3mfw2Dv;t#2qJndU1+NL+|ekTWH| zfm%Z263DCxHl@L$bg&%MNUjLIsn(ir`9l{*)e!ieg4C@|^uG-_1hQeYh7@T&$KhL@ z(9%MpyXE?fV1SQ;i-G=TY(dG`k1^jwPPSsXEYVftFm@5PU8g-chDRKi^Wc8ET&W5z zZ@#)$@dlYA@X^Z3!|dH;a{6Ft;yZm%`TEF)jNZnOyP$?_z**g?w>Mt4Ubo_J1lm(s zTvq+oIx9=q5h=1r`1SFL)T^C`7;SjI9R~rIN6}EBYA&*VlX$}$QM7Zql2x%1`kU!a z-lmp3ucJ)SN%H|_pgNvs?F>1f zy$6Q6^d$}$UhH4S$$1Eq%vAGib<%Q(->>oIetfX z8Emet?Qk?YE51Di2LcU{=tH6G96CK}x44jkcXUA0p@MqIsYfOBk8~;~31HXUh&3G6 z4BxWy;>tH#6Qbuwo9#)-wZefMuL-zg=vpBAN>|{Xll_81hNM)eWljk|2eBU-EbsRN z3SzkA(kVmvvF>^IN2G^)A1lo;Jih&w@f1SWB{Ya<2FEzdoB@wsk<@U0d9aI}Sgkw- zY9yMb6kKb!WOsf4WsEv7vt4$;d+X2LD+ARh*SIMRguEuhV)-K#hd(cWWD=d9mtEt@ z^2hfmJjCpY0ga>kkLgV~JR6-XC7ZsC3LJk~zPGY`|G_d+>MR~3#SgeZ#OTha4URk@g4~CQoba#_%{e4J#T)tNcEQSY;%(`ly?qE*bNHJ3(MsN{ z*PVd97oc(2;O9R)ehP8(4}VyO#6oQ=SyA3s{EL&CQmWZ7wI8mGG-@8*F1DE|eI3;f z5G^$<9uK?v>zeyzsn>tP4*B!HkPc-~JcG)4(8WD`{EwwW`+W_$^?FN((v+=XCh{Tp?*>S4MC|ZtYooQ@Zm}y_gz%{>3B~rC+d9I>s?QtCG@SJ#S!23q&O-z4**fQlLW9pFEAJ%6aZwH zuaJ*2I~E-{!~IG_Y#+Rzrkhw(=UtzT3@SP?8*q6gw$^>z>U_Jtx4pIfqWGz3b+&i* z0jcuqn|5n2c_$B|2Ai$jz19Z&y*ESq>>0ALZf)!b#v(#P+yfvWZaU3K3Y^Ud{iucM z;&O7@WTMN}RhDHu`hj|cvtHCL?}D#U#qGakfia>sEW`H>$>h+vrzLV|w4}ii*oK?$ zWL&e|7-`Rs1+c>W?#-O$3TvqjYVkTs2a>PD)<3#PmY*_s1gNs&j~WqK0ur7=tLJ8rkm00LOlHR1fSC*Uz`^j^RBrGDa64yUcn)&FDN9 zN~vhU>%0LaB`ZF}q^}CFIye_{R;n_hma-1!00dM^Jz9FCz{Ba_r!-%Etp8OZF7>VB zo1g#iJNrTV(;Vyvb$6a6X|yzeCQaK+cAgV)>6hBxk&}bFj6u#aur0_K1$q_|tuc${<`uF$|jwfuVhZ=L_#|E?oBz`@hB+TdLt8SaZX zQQ>Zda2o-09IeYWyAWlqtofXpg}SdTP_yRC1Ah=k#hF zGS2=Ofx(ywqGT(l5q4DJv#vWp2?_~SbfTh$?q^JR?03eCSf8$>Ll`nW#A0DE%9`q& zs=C$rWX-cZ4d1zKOjoC@i{~6WtY3+Rz|&5Y#YxOPCwCWQfV)6tI{$?dDLq8VHqGP0 zhF2v}HjgiC2^w%`0{al0!SIG)>n3k6bVPopzm*yopsJJUplRM4f}>n z%EQ+1U5V8P|8m54tXQ=-Enw7Z&QSO`8-rGj0F`;ijv1&wrZS&BZ4Gk<$UxmT$&q&#pEEMHnLSx0_rV_nbcqlXpYVGpVMG zTg!1I(SSWGuQAhJF4)dHgQ)h3e&H(W`%6%XT2SeG>X9D2?;yNl&kipcDtB9!-29XE zjpvf<)wVEKcT@0}?={0L=2KFPa#DJ{0b}u5(39{lcGTFjKqbO1_MTe~8yfVk$io8A zKxqP*B76iPwEd-|U0^@gkK{HD^^dK;bY8Ngn&ol?>_?KO#!pJ^0cmGpkw1qQRPszO zNh0jX4YMph@xUDb0|#J-hTj0=5$5Aet;~Y1Vv*|)b{X?i${zhuPF%8pMh-eqQv_4LzWY+RJK>4 z0j!&tXTlUqTYC%N;Q)cz#!+{58`U|&&w{(1^KS1Q4+qCM=ogsveULfV;=U4FOWS= zRUKtnCEpgzh58#BQ3zso!x8{+w?omczj_sP1vihF7ymfCPM;r*^ydqY70q|}h@04{(>lHA^tElv+>Z{B)?nb4Yua&FOjs=9GW zO)X|XI56vGJ;|(kYZux&)|Svd^Qq^6ABem4CfuOePMf#dTCgqJJL!P93cPi+Pfv^H z6}&!%quYh#W4UD6SU-4-!s@Qtx{Fx@B}B(U6M+#yR-C+p8+cj1U75sk4$qJQm{z)^W}xyO*IUwtNjUlJ~aSk`AWU6AY6M7QY?a-at;b^%A zo0oU6W|N#BE=mU=a|swf#@V%8l8xG^PI>3%WU!PRa06hqxJa>?C<}jJ`3^1duUg0< zKeoaBnHyw0&^ZJNZf{O#^Pf6Ah)?}849S-1{0n&g3IAotvl0SeMwNhAF(8+Y(@}ZE zMGlT`q&cX>0%7_Ur(C8GB5;T%FS|<-Wlm?-ytNIH0|=7T7q%VcEtX#h{xU z0eYGa(1(K7v_O2QgTMNt@PIbQWnBA}H$Q;g|D???pL)z*)FHY}IoSf-q$H0o!L42S z8TJCNg7HYDVpqg_Cn|<$ZF5G^Mzf_@Bb_>lNCa`jWcB^!as5)>ee zRP2i(dcjN748=<+fgKXi zsRS%Zuc)9CxL-FO_^))lh>NXFG!KSxrkk!|P42Re`&POtJF*ABb*8!ahI6*1KH>&p zxx7nNojH1~Vnjt}p+U58_ExvgsRR_=-?|T?gSk0OVy6XYBCjMH=cX_y=pX|?@Y(}x zGA=?|LIa~l;u*nIeaP5e_rD_Se~$HYU!xtXIxt5C^}wR>!dc6;i6_J}te8+$_u;q+ zT++RM9lDPuShu7A1HU`#Aky{|oON7S`+@rfw@(yjkRN$VA;4~&j-h&PqmJuo@%V^; ztQ}1r{P`Y_SiY6QZhxA_jL&+sIds0|ZHCw0^^!ol3M=!(-^c?dW1o(zOZsO#%_AK6r! z3(_evo^)9wKwtTXtQ!zJDEh^6CDZYAL|Y|nV{Q-Pd4t8b6ujy1aLSjZaxyt537=vd zo#dy{jpClLp+GK2au4E>xLhJk|230UTTjv4^1=9-o|xMME;l2QY-A`hU_?ITPh?>$ z>BXYsD3iq22UJHnniiYeZGmJYvVjpB;0$53bgO3G$QWwMpVolCoWJfIL`2G$Qg#S*b#;IuNCCsOyT{N!)b%>jmYom4 zQXQfH$!sj-IAQ{#DXWCIq8PSH{Vc!=-7XvnX# zOEi0&(Ak1bW&KR92C<6nb$loE5F|W7`}OrLz()AhSQiz`s2Bt~uanLM>1x4Ee>|An zxr_fxhN8I!2=nL7spwvj5=0VMFElxJ=e&C%9@8SMC{oG~o1Jm3YKsO=665R;y9=`{ zu2+TClArL$PAbAX!+2b&o0!o-cm}k;slL?=pYyjr9ppsOa^QDbb5Za+#7d~r;B{H_`ZKQ=^rir(7#&5{29Boc<({h z+dkvuTp~VZxb7h%1k6j4z)yIYy)4vOPI4C zpZC}L_!D7*@aqEJ0aM7IJ8p5$#dW_AkD43B&Cy>@BGOi~{+JI&L+?0~2lwtjgtNDw zj~jIzgGnpePsQ-&avJ)H?ZKS}w}_E<)HKlH4D2aQloor(Ctyn8uSUJ>Il{oiw+-uY zi5ifdOF2z+U|@JhT%;}#d^kX)XOHGnwOmWQACZt#;AgdA^UpxmJPSclUO_+1f-H+_UeB{gn%p$?eE-`vF$V0Y52O>d0xD3 z?QOh7XY0?lUTy7vC)0YqwZF|FpJUARVt0KH0f28_t?w1PZ}xU~+N}bMbiHkEwKra^ zBR$sU66S*Oi`F--?fn7?VG$FVE`8_Q?baR_lC1k#3o~AS_NvA4T(?~L<`!ZJ_qoLI z+XgljlYMo!Xz#W*w)jiyZ!PQ#TwU*4*X`DSzCk0rEH>9)ufJ%uU9Zh+b_=Jr@n#Qs zAg}=JP5aHW_WsuXoBdYtVrOSl&VX*S2#0JNHM>*1+Tr0mFA!aF7vt@(%QVmvcCq~* zoYJ#5?Je2Qt?m8R-rk$t{jHtt+W>@bu~pcNb$q%h8^5#dX3F(r^LF;WW8d5#Ii9=4 zw=a=>2w!2ZWf#}ELmE>VH^Z<1s(sg8Sa`ABdhu%OMQa-&ooKYf&c5Ahw{GK5w=mBa z?3tr~yN;m&Q5c@5h&k%7TYfhkyyFOP=AnvSQwz*9*WX|I~@1%!o;25_Q9!f(es&w}=g#F6OJ z{;;0jHt=Cw(rtMe`c-&&AS+VqHMIb^@gQClFL^QUH-PN*Xn=$0-iVekGcWSzS?dK( zVE4^4#D^DuZG9&XBP;0w0*rj)7Ldq{rkE_*Lo{~`qF=<_khLLtrgOPnd_hqe@!H_x zI5}87rMW!u&2OVbE1C)S>K}q}!~`MW+$oxiNu(e$j6|h`dVP{AX0wqg#&UpTa!r3W_wW9CRZzcs$@)=#zzlk*5hosRIyr_Uv}Ue-8)rh!DVBl$}90# zu;|;;a#SHl<_cVnSBM}h^)j;1*?zfgb8C0es1-v0Sj{@7MD&O36fI@VOSTsasOZ`| zLfuzUZ;9-LP!>sR;rf6mb|=XI7$mmvbuQV#*Xv((bX+bT)CJV=d@r15Q zI%&)~S^RE@4w(-CZk-}-K~#*|CoO9^TN-!vc0_?ywfo=2NABrx=E(3d0gYbOX23;9)(GBn!pkWb4q{qf%>*~AS8p5B2K|mU?taj zqR|(&lhG4)AP5`~fM2-J=BSbNwVQfnVls9Bp)+gZXLA?7QGG4E7FcIEhD+AbtY>Dc zo%X|#G0R2vM4J?$&756>xe3$bZwox)&rP>FUMZTaQ^OZMaxb19!3%ll0h`7qB+4Hu|!3a_FM; z41F1TT3uCto_yg5v6GofB%V$;qHy-oc0i6)uX&m6T{D8DjH>}&^-)5I+~-v-1pt$M za9NjhT5_e|Hj)co_QA2Cor5BGDdOeqty>F6&U>s|loh>@gjQcKTMUIAtdcfMW?`OO z3I?3H>wf++Pn2GTigz%CPfe~B;361kHH zp^9~w1`H$W3h*^2VF8E=33fd~AS26Q+gDM}Nre=p1Ymw(cSV>_iMjSbzxV_;G@hFU z^+6q0^GA0n*OAb8g!&t1B$l1w3YP4&Vc`zFIpR(fC-y+ z7{L6srqk|3uF;v}JbTEz-Kh`r(9HKS{=v3#cRNnA!#@aI5`x3V{Q21>eJZnqP#onV zlib?AoeH!?nn-k|oCKa-NAMq)>wGNXvQI1_uOc*Fu?Y+UV{eUFdc3Ud;_3kGl|MB- z?-R)}hD=1+>3gb!x>)oC23$qH`nmqMrjz?i#do7iu@MoOxho4bi5MQb0S!<`AR!OS z&RY)4pp%RkHEuBEgD~W!)X>5b1b_N%xhsj&dxPHapyBWl`P-c~Pl<<(JT=HN+v`#5 zh)e{UHxt!%0Zhnupc{HCeLgnZMO`ZUNty(K$&AP~(qq4y)iAq9870YnzjY;E7iJ1PuJCtVK$B zDu&>r1@Q2b?g=@23N(6)m4|T*hB}|)zFVp}=cN~t3g*$|p0-&`NEzY%6cXS0#bKA5NCS^Q%6ML{2o*b1%iofoAT>eeHC4Y5h{$>28I)YV0by0T>9B16T~ic zr%d#Q?7NismpzlFa`7U<1pT8$)L6OfEk1bo)x8IQUU_(biQW;hsYI!K7KQ5r6t(`c z=>I4IQstbm6xX#71?4Q0c#-+$3Y1$)<)QMdWfCa*UJ~M%DR2^Hgd@ z-bRd9!nP2SKa0Db51bp1Eu-%fgsZuU6~ND$Ul>H|Q1jJ-lW;9_njB3&=1~4eQH#;c%X1=r1#=qpalz#sI{=~u^nk^{Cw}kc|yIytdO1qscq2;G{ zEqFo77QD&gRnQ9nd6Et04Fq2FT#MZ-X}L8Fm@*}CZUI0KGna!gsZtW3DUhWB=mPlh z!|nvhiOCQ|k=jU6jKzB;KnU@*8RisFliNn5@q-dq5(!lZgiZj~Q zcudFEC+JYc8zVWUN}Y~npMikA#W^VO%Z6y7P<`Okf>D@g z;JQkJjV-`nM>?z4>X9*waqzEoqaDNfi!XGI+Va=Er*m&tS%zuDyrrgJ=%tr0FM1H* zl7uTEcBkH`QBr_tbb>z-#{D1uWxsW!JcR%zO2e7gwepMi!hTQ^+$7k-A;1}6La%QF$Rf5RK5j&oB;RUbTM0{<=kw^qD|#}RN7?ur_vI&bV;;)gFELJ3 z-lo(TCAVpw`PD(I!9=V?`aK2ur^Ms_oBS|tmKpuUVEXd%(7R!{>~N7IhJU2^OOZT` zUzSJCnTbo!bNh_(zrVXdKu%C};FE??VEL8ZAgT@B|0bV>+_q;p?f*(Ig)$kgv)Sv_ zgJLOI$=^l6A z!(asyn#9#`cGnw)yz%NKsw7e6@ri~nAP-Rv!lopv_?OzfykN8-V*|qU@RU?kW~XiJ zi!3zT?jXJ8v?RjLu?;7-4(TkU?BxF#vyjn9)z=s~g4GSxk+=~R9tCA`KqMN`i)bUR zu_DM2GwD->qgMA~@J39;j=s|x3@0X3HwcnD3QiXdv|I`+T4wUO(1KOOmeFGQ-NR+) zMeV48tsoaNL|G5j1HGnFCopfVZY)85mkIugu3zzOy}6rI;Ff+XUm68#NNp0n{wWSq zzpA10#t_Y8uZC*Ai6EPQ&h(MFkxeRMRRL7c-UaJ@rE)b{S4=9(7XGMfa%Oq=Wo=+> z-(;+b2r5*L)fT3G!Jogty!5+1=u`ATY5lJ(JV(zzdswYOx+X4%{wR(~JNRF4X_Wsk zegZ;87PGTAnxNoH@dElnR8W3AmOqzHrX8&IhIP<&4 z2nB~n<2b)>4U<8mM$ULJO6HRzTW+K?!sRRJjB4!m&W7oAFqtQ&Ugg;l9$r;xOrw8$oeo-s(BaU(GZ`48y-beS~@b*6JgX4IU(tD>)%s zeX!;5;rxpS*DgMdC665th*RMr7-(*{Bw}cU?dRzTUy{sHgJzaxSy}ui<9xJNCH*`ZUJ{;M9H{v6zcv9FE9is6j+M2CE9OABi7P)Q(Qw2?AN@A`{#B1=2q?+2JoHUdb7wiF)9g*%sFwp_CN#c1yRmiC$*D;2WNVa1K zHxvK)1xOG=WoWTEgdz_I>JqmHcM>+^k2HPArYJLqa7+YDA{bLPWP)TjM}2%7N(t&W z8oL+>>&)WY*9{Z=^wO)W}9_3T4j4 zGY-*QVPERv9V2u)hnL7<)cNOSe|)7`hf`;_hT92=`StsfQi6tCyf$)wWsO3-u*MI& zW>KgxQo}KEG;YJ6lFc27#VTx$-!_8V4I-kijfQT_5eePUqtdn7v879uSrN_P{InT& zJZ)98wZ*0F+I5dDpccYv1%=*43dS+sYL>*8l6bgkx!MF`=ja=1B<-+h zTm3lwct>jiF6niv1uC)2$dpX;GgI)`wWYhjo({aay1L*F;Neqn zBC=sP$_rGDyPMR6Zmu^hsi z=e?P#NV!CvZxkIGjg+4bVamyj^`3M0lg_^o9an=RIj|zNZXHEz)a0PoX(;4{{FDsU zvWFEw2wVwSN<@F}M(LC(OBPP*GFx3wrayU8QkZgVplj@BL(J@SW7~?CWuZMRM?&Uvd;L#d7$y}w@nN?tZn|*}5+}xR!6B`SSv0H8M3Ob9;cL;XOsMnH8v|^o;8>XMc z4idM#7=d`fP<77OfD;S`M*0fud10!z>C!Y7YRqgD1w|l(YmHM$?_m!St$TVFBJEs= zM_8kJmZ55$zQQX5UWxT6mMB<$Li|XdC&dptKg+~!68q{0VV{4z1mEvx!?W>67!G)J z@%Uri@E6*b^h!eOs{Qi)>(}ou&s||ERBZelbeM{~DJ6%)C57+s{wuzy-l~*{5E9F5ZV@r;*FEB3**6ZCa5BJFh_To=5$E?MlF+Gjo>#Ev-OhG?cn`ShPpCXSL z_*q&^gA(|kP>y_>l!Q-{vSpIsdP-55_+Sr%D>CYdg1c%`bLbzoGCVSoiU@=M&Is0| ze~*10R*bPW<8o25q)Awe9!rZaLllXLlQB%chn3)HiQWkl)yu{3Zb#82rs0t zrQ-(^cKS&Ro<1$a_S4Ux{P2QYz|9kxGQpv=C(&~bqy55HtEoIa;WK}7&jOSAM#h6? zwvxB*X$VzMXYGzAe;M;n5m%&?qlbSHC75G>grp}Cx`Gd953H$^h8D@@0mH5^r<;Nu zQTTK){QL@1dBq1FFNg7{ulY$s86q&cNUVWzdeaqt$g4lUQMNGcIBraDr+-G=hT@}` z(bSmlfh*6)Jew$6hy#n1vy=_W^GBtE zq^1ZTm2I97(kD6vxbZd09DP0i18xV=|G%C;GR}Y01XJPeCr{)WCt_F6rieF#$u`z4 z8qjAoy0amIl(aidfhFNJg;|{lw&Txuf^A-}K|R__UIS_CtN*IkaDq)+)%W8MV>~?I zVKN-mtO%8%VQH3?zkLe7n)>^P2*2?z+LE|`rpQn(bOX_Myi3F3cPi9NSIpGFCT8G* zMWf#j4hs(s5q_Z9hBAWJ?-#?-_4#=CDjwnBLR{r&-QNu+<9j@?f=pU^ znTeiSnNLRX^*b)vF8|>y#6hR$xuWsM$?X`A)Y8<)Ndui0-i|l%yovbxSr>)%?(y;{ za+Z3Nt>p)C5Qrx}5$^a)KgPTf2OBea_6G$)%;xOvpWAri@!gNKM4!HULk~kZ3P2Ns!5>K32M7m?TKh05srWgttAu=o~i65Z_dLc(z3+psZ&p5MEh8QY6Mp)WK zxqU|Pi=LD+1xS2}UR#|bmSqFcJvI#p?9jTZ!*QQ^#LRGxgh_f2IJH2L+jEW`Z0q#o zZ5z*Q5}f9S?36{&wI3UZ1_GH#3yKFLEFfUz?6c&lUQ07$bV5oU2p~?BcdQdSzI`d3 zKa{lNb zg;j9LxHreFFYqDjWDp2hF*RPFiOlh>pgcw?3#DrBbMM9`|MrH2W`k0`0`DlU0#@5boq zkg|uVYB~<BnWRrp-ZuD4lWD994e8sg+b;zrAi`x!+>*} z-iOpfF&mxPjrHi>uh;^}nIWgE*oOC zSb?OP^28-Ar&*;_?7-Nm_{_ZYL~ZFu8V@OTJgq948nc>O8Jk4eleovb9KaPB8RCq-5BQM--0?`p{ET$$QPU7Eh5Ns$dft z69oNu_tN64Y?S6&quM4>4n~`-DfB10e~O&xS)^6~^vf_T*dHSujc1m$8IdrzmOMxn zxr-A~N{yg&K~fq>jp-+Al{x#2Kn#w4O+LY*nh(5U^y3kZSws`tZVSeB$`d9vZEnL2fLrFF|jz!-;$4Ytm*K`O*Zi(15cx5LW z$c!ECA)m2YS}h>cZjUQbx|4H{QH5T8!t26xRRYF~mu_QfIr2KkNQ{xACZ?ZAh$0L$ z0TJ@KoqQs+bo4p=5RdTe3ydot*qVKV%qq03f^=Vkwlt%gOkOY7pUNR5>*` z|6S)nnhkuW-EFAaKa-pkkGQ+OF@|IkNudi}$NFYwO>Dq_LcYi?t<;H03x< z(VpK92bhiuonhsSDQg%`zEE?;+Z+SRT~eforG((R8PgE1h4yb@cJe8kS`(_*q`a2K z7}_nBK>ow`6zSp@MFvS)WEWwhF&hZUW{-{sDWuF%E&52hugVt9mDi>aN*lzo<-Spx zG%{!j6hS3)Hu0(*Uc&X#90P}v&mw*0Dk@#vLXYcsu#{i7r@z}stEy9oxPn!py2~_y z-8q055kE&gFi`ObRaP2oa4sk_bLWu87Xu%*5Q zz8V^&IJI!zA+>IH-yRL`h6|H7^K+9ip_~v2&3$X}`tkhji+4Y^RQ#p={Qdds7iq15 z5&97swws+9Y+9dJ6>x~{@VHMI?FbRk6L~c2=2+nW<6wJ#N7HnN0trJsC_}s@PR-lM zZhgA#>9Jw5q~UnR0}r201jV^Llj+F707;FInvk<>Vh$@8L^*Nrd9oY|;fBaLt{gS- z2)!Ct3aRL=5VtfI7nq9^vAg3b&Zz*xZ-7#7_UNp~?1-VrNIc~9a(UX?=4^E&7z%_M z4#ZnrC634#NsVyzKhm+evF=D=>Vu{T)Wz~~*O|)uM9d9XL+QEBG!}_t;+UaWveLyP z1FIzLThZa8(5i;zM2c1ZqwbD#kqB&)^zst@cpC%hjI22T8QS<36I9(WP$&{}Dpv0( zdOeZ%fkm(YkqBZFN30wsna+9>_RwsQQl!v_U|UXdQ*M;Dm%SZKdH?BEnr5&u8^PJ{?JFHSB`uHIdmE=G06W$;ezK6So%IOjCoC1fKNr{rs2~?5*$lH3X+QP!PfezCG&?-#=1^&%p)C(U8&r$5znYQ6{Nvsf{`Z11(LcQ9O)0slvix=3P|JgjjCy z;wRP&SUb!k>~ioHBb*nSSd=_Sw``o5f3BlRC~Fzd?(o#+NQ8iUlM!9v5Er%dt_Z#m zy^^Vdj*@^xs=QB371#;9uo?F{6jU|rB&Lgu{FC=OoW}ipkCa5s-Y8jlG44(eo=Net zPRQ@FmoH-lk>-jhxTcD6EYEqMgY&O3e z&R@hhu7>XSaYEq4>^3HY0ptt)liM%u0&Tr;gt>zwOydNTRFON{o>Mw6{7h;LB@;L} zy&N6n4j4fQCX;?D>#P=nqroQ)o)oa&64LrR~e zB(Jb|OL|&<`C2Yo^FU*qnHZIe#T&&8m$+=CcXpg7&{dWyAqer%LO@K=uR%~KnDJ@JjW)*!SvTEcxDUFZ#5bG??@YQ~))~H|O=bJ|l`EI~Q zbEA2E{ZLNA$2i4D-}_8=?yd_glhmY=f>J;<#hIW?8fbj|)8D@S`MP)vQZY`XgPXAi{@|Z z2FPf6etGit^c7NA&QEke#E624Mk*8Z#mUtfeYvyUJlxzq+T1>fn)^?-x1a3ntH_se z{_zaw)VLtdnUG#p^R8Oh`!j^xyu0{>9{M41+Rr-5-@1T_f~IxVj}8lq)NZX>Ud&1X zp3FAkM1J(4*^0MrkVSb!bo{Raco*M6x!T^!c)>%eSAe4X3 z7))m}`Z>T1F=ucFDm7u#GuMx`BWJof!HIEGZA6Y_t_tIBp-@*zMW4ofoD7vaC?&G& z!re|%6XCDRxl#9-VU5`J(d52BlBF%Do-o9JdV8qcM@cPUCOVuV%%(VXnNf?eh~pJ8 zBIGHwg`<}GHCv@M4rRzlw65DgE*nxNLf1$n;y2|V@Yt9GE7=xEZT)aK;P@tKa4K`f z?s@@1(Q`Ed!iGf~!d~UlhXh3Hx($>e0fCVuAbu;7fXz`ZCy<2X#HDRZqJXfFM4mCm z4n=qnx$HnN2@+|Z>ZwmOE|+JiF)0&IqLbu{WS0;tT2RtDmB1?2T?TETrufWcPRLiS zL+K?+cdtmg3WZ|O`CH?08JCiE7P%5~RfN*K=duj_RFH~gmo;0a4u=I2&0UVQFmgGB z%6fd?y5}>E&+UN}u4kbyA>iDuPw$lB+fXp!VH2oYPmhPw5a#*rab z%hxF(P#?d!Y(kC}V+9hl_$rW{<5D3h%66Y}`GWWy_`36V3SWjO9jYWu=cCMi$XV(T z&gC2Obeb1PG?W)%O|yMV1b$pUGM7;ZSRvDnXFc_a2Wy6yQ`AY&sSk@ptr#fsozv@> zf=oK&GHTo0OxAu6;aDLYeZD>%_eRTpd_Fi6*8oM%huq#v*>ZvavJvT;piD3M9)}SO zDDq8k0wBYO*d9=Tu>KVsM2aOqUtAJxx)RZDqa@?jRs+VPKbbYuxY1oQN|ZoAGZ+Q1 z;C~JV6&;Lwx09%*YocI&M9V2358({;@3>llJLJekL1E_}is|71o6fNQ2S))M$O7-Y z$7&7jsrL7vcBCcfu(S?WKA57vSF&B99tWt;N$kW zw4263Z-#-ZhT^p`pY<9>YaaT?k;Fo|EH<8mX~Ohrx``B*2IstNN|XYl3F+XRcDln6 z?v3D4c#B0Z>KQJBIhfP%HUYjgv%CvH&X*PD%R8HZ18*aTOcAFDz>QX@fM;X2fxU>| zAf~<=b`yg`f_At8$i*(#Vcmpv(9VK%1bK1}$^Go;y09t4Rgo$<8zEj_odwNjZfJ9A!CGj~v2q2WMJ^B;T4-%p3+)@!>kKgu zcht^8YC$?U$4ey|u~v8uvB#dhi4({)%5!Avu7KABPa{W+icgkSAmE~~h`fy#RCcv( z8q;#Z@nNt?yyJ}RY8|j)EwnP$7l2pBaV<4*pl!^2Mi78lr%v0bEpQt%YBPr5O)sez z24os#_0eOzCU_e86^`guVA=%tAV)chRgfFt7V^uObMgaF&qPaW2pwn}GaR)Lw5~sQ zX~0d zIU~)OZ3H%fB}!GaPx?rY3=jx%Cga&=hg#cGNn^37Ty;KA#*@4I01_VQxX?E0%0?>F zKJgc(X)Gu56u8YVJ?j=C2X#Bg5;St=5@-+JH z7uv%89!4Pmtw%LX$TZ68W5{?-@HFxkE*l`wvI5@@hBOINL(AzP^KXJ%$bYFt&{Ps|Fa8&} zQO=>ukFhvW3Luu-uS|qRrP(kL>BoZ<0M4%p;~3bhQ~ zSYARxBgi1Y;nLN5VW7w$^6vBfT|BDV1p%Fb`oHPPzN(lRI0Nw|*H@`NwhBH2eGAv4 z7HtyUd_^TnW6B`Oo~PD_sxq^&WRUvtFPH6?c$tx3c&SRsLXtt~FK=GA={X^O@2Dyv z3yDkU9P^t}^f70vPQ^3|m&lvWw5?i|?u7~LBIbbN`HOjV>?sU32@b{tY_~j7n;$J$ zg%&5vd1u_HdNHD=ndjT~RfQ9INFL8{GkS5jyW1P=bq{wB4*G{X{q6nzop^Wms7HSu z?=}x)=7UNv$Laq9N!2o$L8gXJMV^ZMPN!1P`TQxJzrW_p2NaH?Kiqs3%8tO3rt+eU zV(!`i#OPDWGXd>f#FTexBbh_NJ0=5^B`7ioM6R}xv7Ny+0%?+8AE)#PDc=qgH=m^( zRB{DjryrRHV6`#15GhM&h#R48owR_vbx0|RXR2_d+8u)seN~(*rHoo(Lb<*&xPk zI=;cj>IG!(SW1~}euw+qtXXIyRhe2R!b~m)Y7i|5zWZsgE)_&J6gbR6#zrd3fZluL z6ENoR?%$frqNb@%T)Wo4>5Md=vBn5YCvfvA*+u-q$u8;-rQr?ri$$TTI{jw1v-&{fb%Bw5_@1*b}QDRU+lEAdT@TKv4JzM@%~7-AeAbOkKX z+sGzdb?Ppr48ku|#^3!V9(EnUcf7tv@q;0SjlD5RJ&W}(mR_XsH8i?XEbz-R7ZY6L z^6qCeb^S{*8wSb}tngGH_AZg}Q(-hb@-PsVU;|I{!tutaT&qjH`jhprrO`FywFCV@ zH7@Bj=#$Z~GneS%zDBrihI2@*$ou=`A>=R5y^mNm{xz?wm@$v)YP=2oo2F2W(-zwt zjcwhU;h?X^qaK$p#%7vAMNX$EZWw<#Hf{7Jcoc?Q>&kkD*+E*0oryR8rWX_aOVO%w zfrll_5S~p?U;b`Q{TIkekiQgfSgwb>L{^6U+SX87jY|^Vc}=nD&S*_u4RN4RmSm+B zdyks5(&=A{w2znovhw6t*}r(!1<8lTTArc2aGw^3{v}W@3Ta7pex&jxr?;q?zovkWi79|ERn1-(X&YAvaTuQo9#C8x11WqV zOrQ|y+8D5K1rWbnA8iX&0O{7p@w&Qgp$Z^-zfbq%|L{#EQbzuu)}@eu-TpO5Rpb5DA%q_x#=UHKnYczpH@y{9Qx9<{@7W2GFOf z=p}Rx0UQ(0aci?G1r44<;{4qz>jI=?Ajl!}7Kv3=yCGn+kc)~nm3(=1YH6pZpXwwB z{XO&u&o<2N^#@fHN-^4Sa20h-5x>BDC@9+#uQXl`6Dgd<%t#rS<)&AXh6i6T6Y-3# z-a6<@RAot5Icd;Zq)y=_?Rg2}>rn#DiAGnfh50*#+Q!!y#H)3_YHxZR1yPD3MbOSVATBtN?yO zNg*jDhY0y_y2O3iiT47PrlWuH6Ex5ilKgXLG(--^ivGUts|Q^M3sQ}6SVB2l@~;X5 zDj^#tnnIG|d`6$tP;7!j$oLPA2v*@jVwPt%4&oK~LY2fX!xteg%U4|eC`S*MEhvSt zG$$(^>SQsKAPwh-HfY$VQbEu4X;BJkI6tRy=dgC3yokg3!a>E_S#oiPbMuN$)z>>_ z4$5#|E)Y(aN4;yA>L$K$E)dgOCldy`A|6QDS6>GVEJXxKlSlDl4MZJGB?;>d&k75V z!+}Ow#LA219TL4MWntF27k{k4g+PGCPa`X$|9Uw7umV8>4EHC0vzGyqMF0mxILa7VNYnlIIWE_N{d>AiRtxFgwl%c$+edYLu*Oqnh<3(G{ z6TL*Y(u5%dMPycYg(QYRLhDdCNl~LJB2D^WZroQ8s*5Uw^y(ru6uJaKEuR(pTUOk1 zp}4-5zx=R7y}p%HSt4rK2#ZAF@^R6bt(6UduPhg>c!Xkql|pZFAe0!?zY1d(C*mno z+_ILB8{E^4YxR2--C%@`1c&i!86HFp10-O7L}k}XmM+bRjWdLsO7UG0Ru}!wys{%2 z@x}2w)OxIXexYcIt}&K^ehCO}S>@nD5;U;{5nRdMh@liTHKHK0D?|xRq7qFJ$r*=m zRZ`W8V~VqA3J6=+G8mw9khyp#S?r>d4=POI1XwuK$=^Zb7enN?8;>Wh%7Ke7fC&n~ zBwVk?fQ>7FIE6u|_{X{!NaG7;0=NIx%Y}t7hz+U-v7FH%M8b)l!mEu8_OW@$1K8sO z7tYyFm|Kk}AI1Pi)QM`Jw-)PSCJSpBhI}1bO+=b2AL=r!C1P5WLTS!Cn1dMO9e)D6 zN;DzCq9O^&CmL@6Q_?L=fL9y56uKZ57Psr8Z{i9ej-zZ`dAM5}11Wp~OeDms=XNGI z8p*Hu37<*3YvT#wHBFWTxkgw@64gDkgt8%td=D)FF(uK8drMSrz1Q<;wYiZHNg)o9 z43hT~1gkM(p$a2SNtKK45<#KGiy7{XR@reS>^Hyx(mE}Kp?tg)ci7g%go!Pb103Z# zystbQjWo^@+^lOvz=S|mg7&Lrca7vVwh|n??yQpojV+XeS2t@{h7`(hUe+}hxU|SK zER^zvy6Cs2d1>Pd<$|ugt%(7RDwH-|u38gqjjA+lz0|I5ku(z;X8<=;CY<(iYu%<~ zAT7a8vhwK8tR^7Ek_T}HTjF}r%JDpbM!npU7td1!t45h5r4SO*>0gnOiKRe@f;XmD zB}OT`W@5=A7~jFy;ZdWf*oz|Xb8aqbj3UY-APP|@X&)zD$^hvt0#D#Aatcc$jidwz zD^X5>D^U!aoBmEGq&1cjJUCe~xwgSi-@#CVwv$m(fwqI8fOd;@G?a{JU4T-al?5D; z8N#!GG6=k13`a--SuSp0#Utc^<#MglFRYAnLP2$uC5Bu=+L5bDMXhO=3v zqde}DjirDf1wv&a!73CjG`S?tsB5oqa5btvY9@|cVo9K|>cAx!atUFBRFwiii%?_p zvjTQN7ZJeTW(5L(&Lx276IPq08bL0Zw-X%te!fR(6I_F+QaX!gkBudlpxTO56`g|5 zCnCd!m5E6Bd?K?+57`vr`h0ae0Qs9}a!Fpscaw#dTM?Z_%KX$rhdoxa-j7K>6Ny3XqP2lMj6A{`cj4F&tB(cX#rs z@pmBFoHHigHzbIuSiVdMN3hgF8^+4%WJK9Qg&Dn-81f+xWlMEyZPH03Rh9+4TlfOJ zXxw2;osE|?$K{Z(jUO9r7%Mq8rjoMwj-e7ocV>`y73>R0!bKb=i?_==6v6od?6`=- z*b&eDegSq|#9{0R8~6p-aS;cyvzQIXH(!Ds2XPoXSNGHS^fvB&xW0ZpLC%l?uq7nlYf z+?h%kXd%Rye6tv7Lh*rB=lMfpopDZ?l~ z;q`tt{8B8Y@P{x*P9WaGn)I=1ubVM1?hvNv)vqOr;J%$KUQY08+`1Xd#2>`m5@z*o z?TU8kpbcT=Jzlm%xxJ5c;7h`mR(ajxDk2la>TF0-r?=eJ&YlN#2utc-UqKbi;Qf~F zSHpujlOgpS$n~}G|JC0stw#z;!^WA(#O0v3ySsb55>1IClZG(yEu7$XZoC1zU_o1$ z!suxiVWlowgf+@c4q)q*&g;f2(f1+Dr;a^Ej48K9@-D_a`jpBk+aoZij>Yw7tI7h& zr3$+~bJrh*^L4tMdEea%)<+DB$qL~Mr%nf7Kg5)9uz)-2O{S>Ih=V$uCtPfjI~YzQ zTIV=9sKa?;-FKC5ot$|I;k#i7b*(A zY6KlT{t;mkZL0RU8ZnI_gADStU<19O2|X(M7khXlXcl5VuB$Ta;-Jru_H2BE*iHqk z0x$!q3LsR$t6&RIx66b+w7~T*mgEy(Hw$SIGp{E%!=6U7O1BYsHBl82b~jopk#><4 z5pUg(7oE@R>9&Kbi1hpMhcO;Q!qi6`a6KIOQ3f(14xZP_h=Veak*gRL-ta>0T3JaU z^)n+lPL6UbD5HzQPv~{$uG{a3wiSq&;28wCj8GNS448+sT~N+Pn<)K@WvfITpv=-! zZF8g41RX@VJxmtlRjIm|a><^LM_9{NC23;GCHH2@cN12n zXQ9a@h(xLWk`pjou~b&nMmEk|R_O3;b)7P?WRXJ&?kdg{R#5=vA=TclXj(~xL__<# z0VL63WL~XG(8S{JVRq`Yp5yu#YqASKKhhRQu`9?)0OlcWCknkHm4=JSPgX5x6?&sU zGZ0Tc#N**VE9vZ&f=#0y-%PNx9N%1Dx2E?!AJ?Czo4wIc>?l?1%{dx#8W=%YSl@lV zzl*(rqH(u@d{}(h5N$kQxxPgJ{1vL|`}*L5Qag+M#T=JsFnyBnTlQR<&S#C$IM~IA*)*0wXWv;JLl=tpFOUqn7sU2wuSkTPoXr7?pX&=IW5UtDjAE;92 zkDku%dc9@bn8_xMk$4UU5nBOciA8-#;VAFh=0(`}rb{-;HquCkUTYMDn6glZwpr2~ zpH3zphTgbDA!-5Y=URN%{$t0hZGos80QaNMHH?MWHFN>;_N%L_3!k=yQ)m#15HjuE z?Y%XSY5+|jx&8H!+YcmnupV*;LFD$fx7R@qXadPK*F&xuNN#66mj!jN^U(yY$wo&?XJhF?1ovD{q=ZaKoex5_qW&5JD>?9w-%eZ zza3^X_qW$#Gl3?scWbek`+=U={(3wypb6{UdY0Gyz~xn*dalDglBkM$c{S^d=hMk- zu_8^4CzxQn_x|$rx~Mh?nVkHfs#USAw^Gd>$Sn=dV z2G)FLa72itp}4Q^6|BUAi_9X8*HHSnjy@VnJ}RVJyf8&srifmdbXDxTd9$CR}F5i4wI z(c9o9m{82?)ivmfx@#D9+JaheQ&=joq|s^%7bF9R=DO+%r$llCA_qjj2Hp5;OmM8z; zlpqf8uXMj{!19D!!fm$Elu&Lje0esms7O=^vfRERnbUaWy`+($&rFJ7Dv~Qbq)f1? z9y4$&o@T#Blh;iRSh26cUZI>hf?IMW!wIrEMf7oY^O1iI(Hd@uJGK&}06efmI}0c(KXVQ6`G&m1+&H;5RTZZU2Ge1ri98S;x3MVM8Z0TsH_%np2XsH67;;(SBVt#CDPMyWyA#_E{h7DMruspgcP1k~3k*rq868*O5YXs#Pp*w@6JD&iRCs>-80H{hx zi>8EZ1w{>6p0v1wUb?3ySU6GTZDQ`;PVh#G`a7hf83xPsgjs*{b zDvVSju7JV`wr&GGUv5|eFF9~3Y8vbUazhy{<=;yaWGJokAtNVf+HmE`iY*gkDM8eL z3MWbTizy;)9FvQWLI{hN<`KL2q&#_f7+9LL1y@KmDfM8~WjB5e8tMV6waxi0spP~c z`Aws!$_(+CIuFYm3@<-kELB-Le;0ISUv_|Qm7F+>s-!yZUG0VqZ1 zHPS3|9*k0Z2SeBfL;xi`&Op<>-ALRFqU>mZfE{`Gqu1@;paNMs>-hi&a zf)In&h%()GK+6+S0%-hNiR=p`XC&AH1~+Nkuwg5aS8qEhIh13-g$`yxuM@B^Jvvc%f!aoK{sRVy zMdKmRC>mZ2l~@r|^<`%`TF&z89A-1)$5DkH-NQ0wM*~%JHH6jINZ?E3aE$jQ@HOy2 z=-qHpb(nH7Rgn*G4lo@kdv~QV%R^Lxu_+xS5buZ&$fY?4Y11|aT}1hqDzFAtV!T#;J69uFMs-ra6&aw%sjAC_xJYBD$VyMV zHL)5uUL+M68h7qilua5#HC8IlYFm^QNWWQ*7Q-pjv^QHp64_WPutYP)?pK*0L2qT_`l&KrX#Ye=i|X7ghJA~kb+DLGa{?TuR*(>sYpmmHap308om-6 zS$Xw&5=b+Xg{2ZpI3Es7hfgzN!&V|M2a9%Efm^^d8-5(CutV2N>Ev5)S<4NOWGIED z5=(B%e>qlM=rSx|0bmPPylqLw#D)o{hB({VXB#-AqaLtQH04MIl9H`UP#8{QPpy{a?mLnnRJs=oaWMnMrN$6QnS%C{c|5xqE%7RrPu96) zZSY*0fs%7xun=-ZD%oVRfM#^2iLl~XYY|U#heJc@fe}DnMs;I@8txMFP=ghd!7eC2fU=bY~Ns-T6nwTdI*khhwcb4PcZ7HK;f)w?F-ky3foKHIoJUSX`)oh>;5>zY@ zF)KCS17$^Y9LNx2hG5-mfG3sG}Hi^$=u3pID*8PfFQS<=5yl3C!PWM8TY zTGEaxx+(ZV!o2vQ4jY~l>V>Z4LU|RCmjpRJqqumqjCPrL$p1Qjm#bogMl{R7BG&rE zbagt-0B313Zh=qF;qI9xlw$5o(BA%&l;bq8C;nS`2`TOtXP}Kw|K*%lgkzr+CVhfln zLB*eJ>qYo>@-BZbPYt|~()WJT8N-2}aXl&6JSvFMEwF02kbYWb053y$z6h@}Ch|Kt z7`XyVnt8bhaIQrYFEpN=o=oS%d4Soso91FeI@7RU=zl1Ly0sVQ`{~V$sxY@csE|~K zsLh66Og~OvEf!NY-%>wv<(_Wt!P?GU-pzR8rd+BmB&c?a7}o4&d56Mh((gtMwEkqK z!jdxLhUg@{Z@IacOi-~DuijCiT)LqxAk#>BCs`h&0868L6W>j+KNSKi!J&jpBSfO+ zaNsR}oZDjomPUt3!ZjsIGpGR5C^HYMa~Vt@TJso-i+|0$&>-?VU&6%WE_`{u1#$(RiT|q8P5iJDViD*iv9eD`X9;kp;8_%3` z{hR37jX1@N`%(8kg0sMpn+FfrGthr0k!FhK;(5!?c5}Pi92^|)$H%*SJNt2`*Nr;| zoo?^AfB4{+2N8azv*AY^NJWTdErz{lV}uA`Jp01~@#V6Miumfgfea=_)P@g8C|nrN z>Kn|*BL)#z3G;9e)oY4ZeddWe{y13?fRN(Tr;&t?5=erciD+rmZofFcY`6Jv)c|D? z{(&h{>)-gd-*UOWi5HSzAE#r~H;BFhJE-eEc=ANb;ZcgK#d0>b+n8KvhH#SF)+0KT z5z=~RhUzqlP|6Kh?Qv9dBwu^vG_04iDW@PRwp9Jm;mD$ejCT1B2kAP0UGb9 z)J;5QHC2Q@Z#Fr`p7zw7jcI)kFo zI>92ei{z?7v?NIUChxPDHAFTPIDUKZn{T31f-+7Wa3zeiIdhV4B&PRi)E~|WtgilT zw_l#WK5MrhfrkyXrAeA4u*9R}O=uxYyM~pDZJGEiY0mR4%PWA|323ngH4!KlWG;km zNkcNy@q&$8zLPX>6rW_vLp`gWQ*jN`K+hmpU1Zy zywvam4u#aN(M!2Y?HV_t8Kq9R7#LAD7Xn`VS3+a7JSzj+G&c4N?=Bl>XT-|ltS+dn-c+lBjx1W zckV`LVF_7zrfuYk|2y|#+wnpFushi6>>o9o-9cx+H`v?m?e}{9gFz=g=h13BceW3Y^Nu3i1=?D#&Hi-b?PmA5+dMel+3)wd z=+MD_Z*RN1cW`jj?DV`(@@DOt`K%55Z4>`dXB&gC(;pmk_P37?2RpspqwT@bpufL^ zVLIH+k(cc`Sbv!mx(5gSo#Vs(!vWYIbPqen2ir#&_oI0CuzAqk&ZFRZ9B@@E7sRBq z-;Xtl$y?(Xa#Z66-&A&lDX zAMG6Pc8+^__)X`iXZ&H}?;Y$94)=F=5BD*r_Ecz`GFF*A0%y9doK=G{Rvk9Wrrv;VYc9Pc0Xd!60E9;`>w(>yW8K#-X0VBcz3tChnd!mkB(po^Ja89n2`F!qO{%Xb`N66YNy{j zK01o`j`w;8-Q(W&-tN)PZryiNO0lLq<#ySlyK?;c`McK72RhGBQ7vklel@9*c$ zx|EyheqhqskGGGH`@66*2Zx9K{!TaUHMh5S_D*hJW~Mi8{$b(=tLQ~@ z5Fc%KVb449?)L6scMnHA$Afr(FHeWlPQ2sQn{~x#m-MxMj|L(;- zOrgU=uTvuDV^$2!yDczjHg}G(UchN+?l*T2_h^zH?H@L~y-o-AW;@RYI2#CaJ7H2d z+HW2o9v*iwIrn2=-`nX7U?O*pd+}lSU~rV9X>;GkBmJ34tvT4<-#rA0UhfcEx8LmS z!a0fu&HnxYyq7$^cD60{pOS{(nH7h5)Fg8YqYoeS@u5Bp!bt(|g7h~nJ{zP%#hqqv z`=B$xNHhm~N5{v5qvQQ!ERs7rN4p(Z9d)Q^of~ejZ;i7Y_8Ox)yKi)wQVa5W%@e?_ zts0+9lyiNVR*?JaqlM$xGCnX93-W_~#40+&Of<+L&LJA=6*I9Q&p3w|Z6M(cJE>^4 zdo0E+#6`{_WO>F7>n~%Tiav$-%6X(5|G1IkFf+j*r#X+HNv*posGL<4RYf1h?~B9!}9B0QbFE)9;vkZ-tf5jF4-WrK8LLB%s1>m z4Px-`*w3he!74NQTQf^Vsbk z1yJTEik0v~=;5aD9QIOygp9AaT&y5cQsf+vi`&kO3jxVyO@A{dRiv5Xn31{ZA0{$W z$1ehO+{pwnWNKo16M)H=7h-n6#P`Pld`VJ=l36nua1+^S05aAn>>aPKThsn$h0qnR z(aKC3X}VgFv~!X|nuh$?9waT9Nn^6e9^~3i+>FXLoLt-qIqFWGCfT=Ki@F^>{mx2S zRv`b}F1-`j)X>iK@Np;3GVhIj8ZGP@4tZr~K}0R67Nz{GLQMzTF~xw$FgX zo>UJ_&DI7nGZRk>#8e*roFETsOucca& zMh~pjZ#CjFnXn9Pl`Oc@d{qOBHTSLIAW6b+`i)K*4ft)*dDcu8~?&P>RB zRicc^zat-UG#oE@lDFs+g*!{M-Zgmz4k+S?TU&Qi<{^Wsvu;--H+51x{rc-$*sIaY z4jfZTxu1H<4X8#sIDyp9MY4_?{zE1w=2S5tO`jqYHdjM?o=nvuh8-7WMZ$JsYZ2{Y z&n(lf>#piwpd(2hY>IM*BQ=mk-Ev$h4+{-^aPdIxyF5I70BJD>+epk_qf?(ty(Xc8EAXdV>+rd>`$&c{W- zW*pmQxarX;aVRKFpq=~SaNR6YEw6`baNaCZFFRE1k}py)H}dPk7ipLk%XNW^G|Y+3 zy5L1x=EPcE@FGn!vmIR6B4ta5N3ChyEYi2^&4@AdJ4Kpj1uC5`>=Y@UC+O&+C{jH; zifBM*7;q6qjAnY;MPshc_!Hl$DR#^P`MS_=@i7N{BU@@m|{)D24tQJCuFvStu( z!7(zd&$h@bamUxHfXcoW8pP>yo4i+wd>z!jSGt-s#nn;s0%|6&B#)Y8fd8@itt2i% zUi{Zys|lSkQRS~0)`)YC#HDXjZ2s0NBRs;zj-+<&tbUqQ7f_eA-P`{17BmVGOy;O% z{p3j(*A?p;Vf|6GoX5B}F0RaHUK;lu!Ke*Mc)}Da4Wtky7tcw4`pUUzXE@s{P*Yek zNO?T_O2k||8RVRGs1hj?M+O-~!77nZ@J6MA-yTO)IO1_+=-rbi+z@(8!spm-gTyB>(=>9z_F&n{NMSl=i695oN*In#nso^cLJaqr6Az;#)15(7ZCVr_1?m zeZxfcm==Pz30bF-7(|kO=I)o+rHydCtbTEF^{U-EyEwT#xq5er3%w>%!k|%XU{w%y zT~v_)^B1o!+J8Q~Y@NS*+dh90efKol-#*yhj{fsMqpy&`jw1j4dhOM#Kfh6}YLDo< z`d4bPX~&;YI(uHP{SybVZL#3+O|&*nWx-w_0KfhkeUdxFZ< z)+v=bmTD)d!;re}Jjt+!a8DcfXKiA??kgfALuh4|KWF_`tFAG2zeVu~3-T`(GaIP& zlA%7jD>}tlTpLTYfqH`)ttf|di*=qbb>`8AZced@4Z3ydN{`_5atxKKCos?)hOmjq zfh`x!gZin-TxQg)av@=^olY!RAEwrFU_1>fC?Qk@YPEc?KMd-)Tw__^w zgfe}0W)@`fHqc)9@P&ZCb*)E6VT*XO5aZ(C=CiaW7D zjil%kl(3H#4|SB6c=;y!G+f-GH99z-EN57fXwjp-H6A=j%yDWOLh_Aoxc`RR9nq2= za|PU}6J4|}H@6@2KYPryvQH8J!X@nRE)+-+hx8*&2nHpvM4E;~@jhjC1on6?dZxQD zcZjg1tJl=YId_nb{^1A8oWZRcosCQ<{3$Jl7LztSppu^iUKdBJF}y-Sr3R7f#YO*U zpwx01&s2-FF?A6vCQ&@5@|JL{C?6EBtMQ;qg9CNNxYpyFEn2sti?fqUe8lA|=Gcup zUBN>7evTJc`F$et3+u9`ni!k&vCxqCbB6}_F}d{jlO?9keFQ$>kYKpQpbn{N9Hqoc zB=uNC;0R)+*)&|tBQQVe&*E`ZPl3VObHW;TVkqDHpcuwCOePT=MjMl4fQ+IA6l?N< z0f-a97K+ut*z(_MNE?KtuU;^I%o;kx{2)ANIF8iLnYu`jdN3Oa7)b&JP6^du0wPg2 zCfgs~3_sFAn*_22T&51+I_4|lQ+w>s{#xFY`;n73XTbOr7r%511p?QWL-$HsX zJKZ5zyukZa;~uRe-wybbXLFIExdqK-i=zO-tWE?I6q6#~qQ3T%M&r|`PvlH&;!4Zb zWOmb_6LtK5bDM=1*m#c`H`IN$q)&2nz+@mxvG;)Js#2KghzyJZZ#-0KM5m>Srero# zqv>nNq$MBQK0fUDe2N7Jw+`e}LmM5YiZRQ;EI{XS`O!UMHF?9%wZF@%!3itFkgf)P zj5Cnk4d-*HBI^>2VwMy;)86ueGny64BHLNJ1lS~q@8fyh4d>AU|CL$?L>nG-c|MILFS{10uP5w|yS-8Fkx5!gM)sTN8Qi4KojlUfWj{r1jtnU| zBD4-f*r%`%$utnC%&ym?WEKSFQI$n%!J<20q<&IS6nmz}NZ6gP)ih|cp1HtKJB>&5 zlTi5g3_?j%bKupW1|)Y-YNH{mOIee4j@1(@FfE7dGwJ1JhzU!pcZb#!n0qm+9!D{J zHu4qd=bNZAr5tivZqO7>)L(Mh!a@t@bryddPL^}5IYfz&66X>lRu@L4Fv>wBClOf1 zkF>}UoZ?u5In8;Lew9GH6`uo?nu}h|P!Y%Mngfo4IU`96<0bnM{dgNwUrBY;NBG-= zCR2;*l5-gznA5*PNXlaR^yw=J}Jvai&hSQibnQH#q2D5t4KqzU zyFqgLuE)G%6QEXQv;T6zj3Zvdw4~)w$r+tDp{a?~ZD(oF*9O1L(jc}~%I46&#x$ls zy;GUKSb^OP(DcM5IysY!AsN&| zCscKNIDO=o)AOJY9X6AoHA&mDzsB8GB}S~T$$|+9$o?d2ZVE|iAOK|#c>d#+mj^s#7cLz7}T)H(XG`A@5LK6b6a zgvuBV?@UC8PuRatnWN6XuD|*HN%!BDPiBAli{SNmJ1qfwTO{awgVCp=@wD=F#`n>L zwh!yv0MUj<%r`~Q-1EANDzz5dABy#vU69cJ#f^PdK}9WWWp*iYz?`Lqb|LoAxKqzP z;q`gVf-Bb$Wa2G1$RSRb5__p}cI^O84(LaFMBcq_GSsVkS4t5woh!}IN?s8Z$LAHT zt~}(YWDc@7J>d6clDDKkuYZ}$m{V7H7imtX2{|W16#3z36-VOc8Ji7u@G0BI2v$q| z%(Pd|0g?mlDxkDbHVKlH{fRJ8={4dMt6w*!lczp~hWJhpoy9C*ZjD1Bd_U*UtWz-s zpk|zw393)a&(v4XWXzTXk}Cj&$KPAxDu|)o^ zr?7K;_}%y1+R^B_Gs$&)9Uz2yu?lMC4zg85$d zQwcU$MTT>~1l+#b#{{K%c5-pLl+FoF3n&@S4tn51^s0fu-xU30#4*C5a@y!ySCs4^ zj+XlwN+1@?Upc9BBRM%LQh*bE##A?;-0n-ukf6o*s#5`-tViFr2lODk$mbi5hiy#3 zdJSJ}N#^m*_mM#;dcujqSz190v?)J~KjinAg6iB+h>5?ZyNl#pLP|7~vLq!((GXRx zc)+|N9#WhkDknsbb>foGm>}cB{Yie-v1zQKL%jP79k)bVERtP@9!XlzW zaK`0dAe61)%`&5vXP<6Y^Iq*^)iCpP@m`F4d{1u}vqbV@29T#7mqADhPMGFPCl6 zgpLj&F~I}tnhLKQIb8I)2x+9HN)<7LR5>{Y29g9qXroWqB*IoI`OxH+*~1xvmU0dd zvMXz85wLEu^2`-N0>QdfYWC^GAO%ivLib@|UR-EbaBhGuz)LTh% zuD}d(p07D0Fy1Xr24e^C71F(gmrn!n363#Te6}2q$v|M2Kw0rxRcNS$O7eTKJSmVT zpOHfEcC{qmw^+3kX&C({F2VvHZGk|%jJ z6;rA|!PbHu0J=XQt%M+=tean(Vf~VnQ-`Otx=4mqZjf?>Fs{OK`c-2C&YZhCp);Ik zHJeLnNDA(eK@x!$h|Xn_<5Ed{?#%T{D_cT&{o8h}1T)Ak3(qgiD06PHNz9m8keCj>s!cb2pqCyR z3#Tg-sm@dmnudn#cg9?}gb;!1= zS;VzbRb4W)FT;G;xhW|%aFtTba~p^iQ+&a9Qb?{lisP_Xj(-uQ;cQXbuZn|e@h%{)1$Aeg*}Y`- zC1-j5yY3H>u%0EimQMBkCAu*69O36ne$*wZ%ew~M7!M%RGcR;^0frsW>XwsifnmXA z5W1wqml5Q*^TwO=s|f!G2<|MAdZjP-no_E1g|TvR7kqj`B1Pe=C1u{ySRykQ+a-9H zQo=HdG8|8rxQR8Jb?y;BRoD4&{R6V6A8|cpLje5=eUcxmZ{JPn$`)J*fYVKyyUso0 zwv&%QMG?9Uc=z#Vz>#|K?;M+ujLFEf(BinSa56XGz--EWpgtuSWk)0uqa!Yl=CL-x zQ;$!OV=`I{H~T}}@}fuGJ0qFvU7y8xkfcxP#gByO;FaTYFFG*A{WZlTOUL;S?hf&@ zmK35AT~w^7bn?65XUxPzoE$fCfryll$rirHG+|sUS{xNY2zfjZOB7tY!B+1B^*%`m5S-?7gs& zFh6;yR3Do^bJ8LWNQxT57j5x;w26s)w>#X_nDli3K+3E6Gi|imi%E;E9~NJYGGF7I z(RyN>=@wg5e9&C_36FLpHKYJN`j1$0?(U zJx&>ooN@BC@(co+We>v6S_eTmB>&1WkcxROExpoH^RkEh?35SmKS4i`uB6%-`b=lS zbs=HCX+t*hCw#BYhP85PlF|_qOGjd#$S9@M!qsTe$eErrQhe}%ZA~(1@u>?bCsrG;TkhYjq>-~yhI>kApPrPTLaiBPi97t=)y8kW2bB>THv z+#oGN08+SWu8f&)v}obVnrb9|m(x`!mQ| zVzIQ;m`cX4(giXnmtY5NetYok_qc>l@d?@$XGQ{4{Qz0!0lp%)r|ouVxd6id?~NK* zRY%h0Am|7m&)l5!J5xB>aAlv_K40w$JDJ*6yZ!d$%~|W>Y^ zoDcaC^Xze)2Ri^%KcUJC*w#inTSx4{b2$k37_<0p@{yxK(eBpvR`gycbHksf?UUe4 zVMe72+(g()oR1f07dSsVxjK6R|3gKZ&Q&%CpV!in9_g^clv3g1E)+lG(bV-E z;?8*UC7#my|Nh?z`q3KRf$48i+f@%M)g@gc6y2)B6)`0U0>&9 ze<*c`dIB7c2OTL!*-KZdM)emdXx%~eDDeyhD|!@F+Zaqnqsgb&!|?~+qnKq7belVr zqJiPx7E=NHE(Lry9OLCIJ`ePK+4-!#r0Q_zZ?D>KPX3a@5r5`tC*~SP)7qfI#};|t zPZn?KhD}Zr9uUYdrwPuGQRHON$!|3u{xg?QA3B^z1))RUl^QFy)7$w3K}Dw^g%&vF zsN|tXC+K`OugUOcjI&Eh!|L>@ZVerYCG^-vs#9)J0FU;#aceo9f-z`}!8tcJf_J|> z8;+5{GhFm1JsFeEs46g=YlNu;U9KbtGBP-gjUSD!<=fB#^Hti9AVqnM$k%9qTCyh7 zDQCjd<|n4h3y3(Igz=$`fRgU_(7AD`oK%jac{+q#;v>@E%OESU+XD;qXL>sWRm{o~>AsP1(9np$$R

dF08X@Kiz%0)ikz+vc5uOiE3A^CnOXg}x$qtiuH6FQuJ~vPBfv(PvXS`DjH#C_ z`KsZUvQC{5wNlSk<``%$xlEOR}f@AjO{Yo-)`| zUlV)k_b>VhK5_NUI~bI z0U7+L9Ri|W@O{1{N0^2tQ9jV=G1ntrSC1KCLUu~*K=YaDp3N5 zk0^+at8EJ7sB`bR(nJ+44O(*BM^O>crDxJ7;hT-R+*rbmB`OId&ZBiWB#9a5BWi0C z_j?5IR8?KQUNM44;3ratMI!#cFN#Om7MUSRIHuSIB9wT2!ii!p;_)!<>remiAQ$=^ zbCmXH1=-(fvhEkOr2!UO(CfFH7?FGs4oNP8 z38&(u%!ofQij)`1-1y<`d%hBZOd{s?e{;ChRAIh!i%V%vC{>llr3%~9N`36iB9?B_uZz^fB@X;4zq=h!a!PZ$=E0Q$JC_T^uNB!W1G@ zvlqs06kj2G1pi_}tB;>NdH449U)$dyzB>je0l_1XrheTN|NzN>K z9WW1)>_BKbviT1xI1RG!~p@v$7+uRtdgyY zS<&4ALmOz&jI#n!vdfNpa0qAj_sQSwrRM{JBS=4vhBlwY2| zPHSi}&4ESpfgX1`6s##6T@aH46OJCS7~{^d(sB-&Bz%Vh%20*48*cR6#K7|*O&X>^ zGeCx8UL9QRHgehEje435X>Vy4pTPjFmGdk>-Z=v>5jwn$A8?-^lUWLZZTaSRKmuFB z)4N`~K?_k&A*a!2N{%$gmP)qJb``jhO~5%Vl6~5}k}1oZWpo`b!d#Hfr-boWUt6Bzi~F*3=v_z1SKVvL`%RYm~h<#;qgHL1&b_`U>`c6wmBhcv339y{pzdW%RJ%o)7d&dr!M6 zDv^LKAH88g>kLhPxidw+4^F1#zInKK9R1IHf$wJjLtx@#RhvZN$G_j}Iw4RG0RXvp z?(RJCH%y8zdR=yn^A83}Q!Pd4BY%o5$HRY!!X#Sh=mvA`S4e}t+59g497Er+$Ra0A z95vE6ORA9|=Bd%d(6No7+%kZE!QwCY%w3UH9Njq_$|Qn)4Ta%fC?8Ht4()DeI6X@g z0k8Ve{Qhbk6Fg5QG*9(3&f!$eXU)1XJq`IAvxm)-m|_DFDNIezEXGbz!EVY}Aff2jGn&PStA)zUnBO$Wkh9ub9868a1;6p-<&;T`rs7{I$ zBGFaZAZ(+d^F@4785Tn#3`I^_M%qg`izAsQwd|$Yke6jn#T3;`iV$|H${=~&@+;j! zav(9tk7W&-bWc)_wo6$~Z^o1ErZgpjiZr2e`4jzgzF`|h-$XUBGgD?4?)40g8~T&_ zoXpzhc!IqWxq@^%f?|B~lW4-h5whp*lOP2K~;~G6!K%PG% zsBP7Fxu|X77fepNjfb#?xPx6dF!>|%)6en{PKsaMKjPRR>oq37{7wyxc*aSqn9r|G zkBvO8J8Zb%DG#K*bVEQ{{(r}xCcHBvHNpBaKWz2F*r=SimNuP8b4H=H6 zTN&^M*ekdhO}g`_{_vZvUpkMwzdelR_t^D*ek21KQU}@G5_Kr>{0D$w=_IQsK0+db z_>8^8VF?| zR|B3}4O0S$Db5YUduQC8m8drHh};LdW5jcTs=9E=TSVV+`|qc}HGZ}Q1mc^~j}%_V z^rf%Aso|0f4KGim&VUXC1j#ytiI~RUe%*)$qs|RN>}W)hLrk(fu?tD0w37HmPAhc= zZnl=7Y@KK;wWA-=mY)xz8ew(y_ibm6=N@N^m*5Gb3-xV~?$#QjH@4{!sG?}|J2f52B6O3RI7q&ME{afer2$KhH@=}c?#pONH)JixA3{3 z>6IN}QjN(ISB*tqV0*bVwBX_!9~(&$2B9*H0%P{A0`!H9nGB=vqHVSnlbJRZDY3}L zVsM9ZIku^0gcnyYq!OSOB65scbcdAQt`cLq$ztJw-Gn0vt#K9`!a+Yz3hk~&Mgm|@I zQFeVo&u)$2L3({64)7!%U-Hn~g)*xYbD7d<;o~Ip-YdHHO8(iamorCD$auVzt!f_?2$H?e@$E1^e6vHn@hqMKgw=9Hqw1LKvL? z`)y`ks?=e@LT!_xb5fp3alS{eM0 zqDFME?e5)a)!)YEfU&u3k!Z2wyd$g}t{1sogC&yD?4obfQVoE#CDG;`IE*&8eFg(q zQN@&RFxY?c!`q4_jINlCG0+!VnhP7akrPG?AI(Fs`=f z6zi2=1@e7r9#r{fVx0>mDnQd8txrkk&Et_{!2Q_gU?{o1K}e500_cBQI?gvc_G_OhQtR<>Bxu z)Z~G*y19@XH#5?-ge7Hhsd5#6Euni19Kr4v{zQIGf6h0XJzJbix4Qv zjIEF+Z!1>m^9#y4Q#2V{Ax)X9unJX?525KM*$<2~J(;ghN0T{r8^5yQ@;OMQ4{-OL@IZ@jzxjiO6n>*d&t#tONqA8%dbRGn-{veY5t>PF#dAodGtrEjj(&Q> zv8vo^CD(yVx*9{5P}updvvNIoa`o4Xvo^-?vAAL+KX`F+`Q!Op94I5R2ay2GOr#gN zg>qKxNr@==RpMT!U$#_nIx&|*XLtYFC6wyW;aW^v5k$dxOZBgqny@w zF{szxk3WnjpYSX<|`X&YwhI?}h{?gzQ(9z1!j%r{@2HJB^kd}P(XSET2SLOh zp*iTwCUQO9_LLwh)M=~s_2TQd=@udbp85L~{u7~zcGMBTT4psYt6a8x5lx-GnixxE zWQ0*Lz?D>Ff-TGAWO0s!q0h*7J%dcGt7U4Z(G!`$YcaXZ6K!EJ-ePZ5B`oOJFpQ9V zSxRlB`TR-#;hys3WlAa#$3EfsW-;kcaI4|tWXRdRAHX&xmheLwpdT>!)>Nh=n z@_TvF6`lPb#!JI>``y_$u8VwWXa9fY#ed=KJ6iE?a`tb=c+?cjmvlJRvY1-udvaOT zC;7^!aF&<SSO(&ptAwSZFTZaE%5DV= z2Y+++yN^%NH2s+1?@tKK>KRW6T-;9oj|k?gusb&2GO>l;4x^O_m;AhM3*gM?8-60- zUyuO9?!@ULLkcND8me~G5iGnGl>1iAGkf0q@Rh@(X);#EqJIPXQM zhbrA^UKD|#9w%d@Fsgq|%-O9lkY}%7wqKrKwyrWdj4V>l>EX+eNewPt5BpnsoKL+n zks55(Jy$G@^0G6&i3GR0gi1$ZeflQ_r%0O2YJx@liUgm~ z!KB=vFzr%_Lp06l$1pF(aEer)Q0kN=6h>X85DD5@)Cd2jDk^f^I1$IzWlp&XRuXDm zsK-pjR1HC+P%m((lgY^cja6Nogq@x72BSk`zTJjVo+erihGYS=*C2@KQTBf!O5()rm{(UsF&xNI3O5rHRlNz!pZ?Qn_7emZ#D3SyJwey6TZNP(2&7HQ*> zTM6!7VwI*+N(;q4^7+={?Xgx2=XkwLjY)u%RnsB~C(qpE%2=TjN|Gbx5N>T@E7W*7 zosa2tFD2{ppXgb+D?5%6#PH~@YTb5+h?euOl5gF`Tyv_XM8=x@Rg%x6KvV_~o(#fc zzu(e-aCet}<^N)W;dfl>dXy>%Q7Vr?W;$pQMi0N9Kjb6^#fW*W&2VI-a;jFC^jZvA zLoU-hZz#bW#R&DxPAR7tZuvkxRnx>s^FREiq&v!TZWpG05(X3i#(&*W)aNK-=cfAP zx&VCA;C;eLn-}60cQ^$ebGoX5mpFV^k!>V2-SMOs3Z@yh*2dzyQ)eOhHULKDbI5p50lug;8?htvz0Wj%z1 z2rv99z9i_>*7YdP5dbIlYkG*++u$KS5!-_)Nz{q?J-zy9>?cRxS<{#ULA_A5Vy z`l~1r_A83c4M&f@r>0x~_5CCKyYU}G7<8tAe;66c6uTCvlxcr~cL`ADPj;26!IEvK z1f-5o1QIZtdbWxF$j4%K?=EVrL?SqLO$u;DSKSrMKjF>oWP3&SO8G{Z&IGynok&|l z3Y|(uqgKD+*%5wK4^Jt`WIGf$TdDutTRGkx=_wEg++`_YV%Ol;utj<`!^$S#Bv&v^ zJU0Hl9whP7x$t{r~K}X?I-5ktY1zzoM*08z4;pBqiB0Tc!kppu{$} zAt=j!2^psd6iAo=3XK9J(USVi&}PrRnX|7w`%KT$0EaV!o#%`R66|wKV)gf`U-CW? z`9$8ldGD<%aPipPtRoS1>*f*}TSi7kM!GcgHl@glw^JD+dJ&H_>>g82g3T?GED(qH9P(frI9_KlQU4_<48Ms3!s&{ZXUtYp(ENH66*5T$s?sn{3=&U zTp#zpUO$4TLp>#|#j0qtHa9jl{&@vz{xC;ART|gcWJ*AWshKJkure(kKYVz~Usa8K z8Re0Y>da_aF0fXVp}aJ5cA#IPa*<7QX7ohq#_a6$iQeAn8@FoXBekBXacI=*)lYjz z=H_}o!nkX_*T$#HGq-wf%ueE9lI{teLYBVK5*B9y!KKQ~1krfngqt^ki0bIvgq%A{ z?IA(0v^77A?;LcJ3?n(N4vi>)bq(V#Wv}>dUNvnC*$wwn_sh`GNl(E z>FTeQsS+3(Hd7z}B$=PoRKsNoXi+Xe^V3s2B_7DevgI?u^owUseJRsI3S~v4u?kk3ts;RlE)ej>S57-p%Pl%@7NweTz?Keww{-02QQrN| z&itR8qbWhlan9epnFueS~U^Nry8!A5Y< zfrN>5JQKDs^n|oYk&AXIcEs^THuP(2v5o8R5@&z&1S>yA+Lf^xm@w7xS`Tc;>eTy4 zI*kkKCUDJS52me?m}qUj%)OrjnZvOSi+j0-KAOTQ3Eb#a8U22FVy@y>X;|UEKJ6fe zTk2@DM-NEV-r;7(;+!duPaw;Jum9o)AK+FP82)H*;PUY4flHSM`una7oQ9M&zblc@ z4Ds(-ORtk~o>;Nq4qL0sNu%J7QoT41|pK+A}sIoT>I>=5Y7% zo_BDAPgPbVGnL8er?91At-slGRP1HX%r1vO2AiIpFUz`lGQhLHOSOh{`y7=YcGivc zzT6!+RCrTm5&qKNCMF5%C_89@Tv49Ejv3Qr#Z)L+4K|lfX#J%gl#-Uqn_pu)P*~!wNwX@0IIR!gJ;(CXSSn?vQDl9r0!CiRZ*Ygvh3X z$Bh6cA2hVRk-cu@;6FfpIRV z*M?TE9)tm`*V)6;YH#XI@=Corwf6$^tgQwEFoR{D`Y~b)5Gzsm^fh17<$(_degKI$ z=6EJ}^TD}`r|{x<&Vo&JPt>r=ku9lg$*0?IIrY;a5R#aJ?9V?w6<@6~F_tG8k}+m{ zB)N>0*Nbb8i+Hs~6IYJ8NOLX`M&as*%8^?f+F%|4{?@+K0!>B|cb^km;6k1hIY6*p zev@2zr)?xYP-dN)Ze; z6SR!&%iMj|4hAxnT7iKTq$8n8b9ORv>DSunU4oT0S6fl9?Gpfc+g0bp@= zXSM{z%`(pqiFD)03s0(iV2|3~^SSEv@e%I^;p==ghLPt2EZdj?;uPAi7egEGZwA|} zX<)iKl~xk4BH?Rr^Uh)mqb5;faOc7CdmZEINyUyizo`r{{f71W^w7R+gR~0ukjGw@6x;A}_hOOKsUd zFRfEQAt@ccaMVaN;DFEg%ZW|&bCD`+-_ppKO!>Ws$M&>Dz=!R3){a?2dl&xx=N!x@~y zc8laiZ$>W3+z$1Dj5`RO(!DF<9zLKig2YE6yGSV9x)RbT7BM83ngTttsbUQ^GJCF4 z9>r4Xw7==cHZ#LQACFIrjv$h8aH3qh;Y1>XlGgLR&B2+T!DYhP*y40BrMlzGjFy|> zRo#jHKXJnM5Fs+tV}4h_xZutWFp+s#%sNBGT@CBe``U(h88(EX_SG2?FTo^m5Vo=j zoFi-SN*{7%pE=j}0T{RQM-2UU?*=ZM_HQ~;Z%$qO=mOG)|4{1uVd~BAU;N&{W%(I5 z13R&1TZ8?5m(E_$UWSJ7DxMEClH&R760vAB&pAb%3m7wKnAWzS%dBd&dT^o5%*xI3 z2d;@wspqPvJ?fqH&(md5#pm%Q5|hbFvBgbhYQ8KmT&txV_779~RZDD4by9ORYBrJ~O94Q@j z38Q5yvQGzSlPTAoN-Hfz1uQo-tBAk2sm669%Ufv&^V`=`z+XN5-qjQ334{Tk_@p$1 z&nF7ERy*XTgrGe+pA)u;`BR#7Afk`XIK!~ijq7wpbq+;yaJ=A_HfR-ihi@8d$BvYM z5WzE!MG4lYMmdE@UHRn3g9a=4B4+98`~WGRro@Kf7K0tcD+8wMmCyZpK5O+yZf6=D zo=?+Ep2}qH_urg$!TGbw#JGe9m`^?5;gPp?0XEpQs5oIs-xhw5FsFFl7e>-REcJ=_ z(lJ#K=Ix@`{1 zsOinPnOfx%S1&m=SS%U8p`y@wBb((Z^~hs7Jp3ExBX=Gxo90pku(gGAoEyT@!rjwG zeLpQZiPAovYkial$QK@D62XjhRYfv6!2{)h3@iXd%|+S+_u4w!RO{&s<14zUKBrE| zmuW=6Vii7(fAk!vo`(pP1_9JioBanhQX}>DjKW;Rw(YO}+FS*Hox{6Pu3gj&`(2$# zUH{_UA9U%jKJ6Fp_Am5uJeq}^3_DrNtT3~dWu)~IhM+2qClAVQ(Hfc>#7|0vJarJL zm03BW{E4wVI!Zn+09)p~EYn-zcILr!y(y|J1;y+XVN@Wnu-QK!sC zXxig8E&L+515LFJ=~j7kI6O4e^M^8*v4o%1l4Yi&Spc<6do9$BTPOO(D#@O9=6UL1 zy`QsM)jD7J&czT3Rf?_#Fga_SN3ibsuIy>hbHp*wd6Y3$5*%eJh!aUEg@1zObqs__ zsDpz3(gFaEXFXj_065+f0P20w53YN^B+5kr+(6=xVo~$p>JCtht?uLMH98QyaL=jd ztvS+6ZzMoB!CCk5_91=~-2=e~A+bPQfaQz~nG40Z{`Kz5%h-MSzMMMt(Yl&j!yV?r z)@bI8DASjea8?wFIOGr@65nJGj6#*=9*upWtr!Fe@|al~!|TI}*&`D`f78&f=RA~U)zX*UwYc@qDy6T(ZnIKyM@WkbqRCytX-)l? zJhor&f@bt-yQU9PO%74{S)fIyc5T2={~S_1PNuWPw_8^-9OmTRZ@W4!4!-dM^)dVj zBu^{2>Z4sKF!Tzxu^Dr$?T|48RR!Sk_f%#*@4hXEh~g8M)YyMB=j8j)-hJ{yLVo~+E? zs3NlpXL3mfhpTZgThB67v{cnqs0>R7h?{(Cw@OIbHa-P&0oRMe@qD<{A!7v0-(@X- zT;>omZOX{I@I^@1)p@u_68GZ~r}2h|PoKR!JS+Nb{%09+4Zo{b!H(7>Z+W9hVS$PhyTbRtEEu7<16ZW9H;P~D1tGo)A7^{%JPhTQXOlP%eI#S>!fLgruX( zXBq6`ahzR+5r{@cDr&A6`5?JlxaC*-b{Af%^p)=Z0kZT`(EWp013Q z=O!%U4rV;Ai=-%vk$APMIeCCS@fykDoIP~14pJy1r9U5#gf{qe8kSrcdx{Df&9#s! zoTNYqYDj%-Zo%pyfpkRDZIHGmQNxlA&Bw2456QsL9wJd1)w?hOi=o7A@hk_$Hp_L3IGnC6qkm0 zZJ+d_O5BY)2gB;qB@Fkk2u%5+{0vfy31SB z?l*6^#JgQad{XnOw|0Wv>#zIkcBUHCZU=6o3w!Tq#r6jd|tt44p#fUV--x6zn_C_qrA4!f;IHcs` zZAHu&PDgj2)Jk2QCrigV50wz{E=|&Lq&st1PvH=U=b7?sX#%ddiPACa2<^s=y<2)S zzcJi2F@lY?5?Yz8!uEaBHCB@iH5&&UfG~{VG*nQudtp|++`{_gaBO+!j3<}(-$8dp z5F_Xyw8=(Ngo*b)|Nw-;Y(tt!q^RVOzBkjrzj&60G&HlBy!==&EwajICENOeoh zXFue%II@Qa?;;oi4$Lk)hQrjsy|{Ge`V>w@$vJE&5#&%%XE(_pE`9lUwdeJen8)7d zZU~Lu_6~_l9%tNCE!I#&ujjgktkwlJL@zrxe$;QY$;|P9bL?9ek6KORW=S24-kgIw zg_NBfy^>+H)LCaB&N4*&4JK9smCqfD5sQu~U=S(e7{m&`JSLDOQ7$9=HsH?fSacay ziqOZ64OQz__IWVq=Kom}Bjk6~-NTyG$+=h@R7O$}xzvAoz!Q zOFy25+gIr_&|l{)s7PqRBU0w2&w>GWfCuwu!dJv0=V&Kh^5L;*YZ{u^hdv!tY8vBcdv1C^s(>x6R%0E3OvD5{VnrHd)qlBv~H;_ zC1J$spK$r3Qd@Y%UaOgV5UsXa_Qb2;rlze9s6+lOn9b!??!qVT1_wf^#r3=>nu z7=$>bRwile^0*BYX-$@wjEsUO7jjDEx*}<}No-}c!gTZawWc^_3=Y=L*F!JZ{3UXEUx1 z(!d?CbCDUyXeEYZt@QB?I5`l>1y_a*%XjIzz)S^k|22{z4PjSD`Z=bF9(ak0#OI|P zWn7`smvUaVS>%cE?^mVD1m^x^e?@*Ih1t$GzFYdkHX8bx!yKxITwCPgJyV?-0ae6T z>HL^N7l}Q1pC+&1>jjgjN4Gnh{l}KA(7&dtW?bj?ySbKYWIwZu$77`vXhf=IK({biy-v zs?PCja`F(NIj9UvNx&*x>cc5tDdU2xF0a-&5HXB9ren%re-_D&!(cWpI|5212+WqY z;Fw|D6Z{8r6`mgp+v7Z*-4hx_2n#k5RJ%p-x3Xy%UR>>w5EDb3!Tx${UkVaDQb9@~ z$meHO+`~3KAv*Ldwi|tT7G70(HE$*$;tIBQ%q>xqZ2(|S_M1i6{We5C+~$*p3PBvP z+&(9pBqJIZKVHk(=XCDeq5g?#4Hx3!ehq$+h%&pj+mGv@x?M0FhDPUcncoqVh@!3x zAhDcNwMt=--oQQJq}hVd5ixN!wKM0T@s1p+c5N=e@13pO?6Nic$%XbEaC( zGaBLL5c&MY(`V0|eLgC~l7;>6^!_-$>2WjXQ^+$Jvvg=~FqhNjve@Nn(^6e)d^&9+ zv7lYBqq7#`uISCkn3Q^2;)QM7yi=P5EPsC)(<0E-wuS48({W0x{DAX(=p)cWTN0xJ zv8mmfoEV?FnF$VfKW9!X7)x>ntjMYyONum)ye;x@T&YY<$ns3j4<^oyxhb(DG^!>r z8)Mp^l2|Z3c7eGAs$I?`mh!8bMu9e&k#m|bKXNadkGsfmmXZF(pY7w*E$2V-Lpu$h zqB%Q=y@G{MUQN`n%wF#G0r|#VQH|BBSaQyZ7@)fJ*^P0m?{y(6NFJYp>7ZME1sI|$ z;@9BPZFLkt@+Zq-6HXoBpwdz4O$8a}Q}dm^2vV<3V9hPm0}XV*sdE%r-v~eeg5em! zm)JET4$JY{Fy3f?nT#;vr9!Twq)+ELLHWdYl6bPz{i(M#d{^UZv`sjlNkQa5#uXgH zr!M#P4y;Aa6I)O7*r7ztt5}As?)YiZl0?g?h0*b(0fy8!L1W0^xJ#O;iKxYlE zz_xwkcWa3s9GW0|;y}cWnIn946hIn00jzZ-*j~a|!r2^~niVZu37cVGuP)NU!p9`W!aBz4Tsnpxx^&kC_Y`I99XD zG_mcm`(#Sl1l*xJeXaXFSa!uT=n=WD@A&5p*%jxOxnqqTm!K{L7vWDS>G^q`o zK9_|cd+czoEZYn==h%U*BYta%Q4lx~2K6S)TI#qKGoQ*{Id!HJg3xg-{3WgJMR=_2Li6U+hf7*w@Ggg8lx1NZ1O_#xZYR|mBMshDLU5Nlil;Wb;D6EbAT zPV_Q`YNan+RSZmU83iR^bJr5tAn#}KTU-T0$-F*=t(vUbac?b3gbSgx+3bT~vOBu@ z6LJo`J`ac*OfkI4+cx3F+=RVt1~zv7PS=mV>^(Hp)AP-)-Y+{2{SI%95}pWHL^;w8 z*H}7cz(l#G%c+WGrMQmt;+WluQ*itd>5*!KbJNohrpjnn2KQ1^KH1C5-S6&S<7$D( zb3|CczIUJ0lvR}KE=w~Jz~lJJ%Ey0m%}(LQM2Ck}{GI6opO4^(7}hxc;4PAr=V3`| zr)Q1qFUk9WavhW7Q+lusGbD2nNzIPQ^5^#Rr4KI+pS^Hp_5Vv~;GgxI7>#c9b`pp`+ z1~1ypEEU-0cVD2-Y@^a=)BfHq>@J~3;Sjr@Yl!a_53zNh2O1*%kZlk#;Ju>JrhCrk z>@lSB7jMPTXXaBdxS3X4&80%nwL5ko$Z?fm z1xTz+t!<w7UC@-wJt+oeTS{! z)ll-b!5YjDb1jPGlVquSC(Q>e(4JW^rho(+ zLJAU2!eW=to=J9SZCxHt`@SKmqZL&D`}?(>;hVPqwHRU*{2>R`!P%BLsam%-Wo8Si zF1BK-t8+TMK%MQ&nGVmkXKKufnySlhH7*UMZ9nBy5MAc6gg#Mk67KQMNj@|^Q^f*o7Uv=|nkjh|dY8~#n39#! z74IvRY@|wcOeG2`)%g(yLw$my%DImnQEjwLx9D>q);o8f}M38_M3-rO6(RkIsC~C z4TR=4o@AAfeLsCE-G-P%NHmnQoT)ip+AX95nl!wh zDodLZ%8DJsOO=_4(iKqU#0iBC^DVN=ThRlhO_wDha!k!&qXAb_m*0P8zlgE+wapLClYj8G?_Doe~PdZR|^h}!=sZQUTL2h9r9!5r?x4I>* zP^sMv?xpwB)sL6j0|Px<@^?W<-nBL^WuWDoVK@^*PAh*f2X%}Uoo?X@hK0x`2)1SE z6iwy=Z!H??D15&XH4#9JB;iFkHIh+8EXxrFSu0R{FitH^132o|%e4HI&wNu6B$ExeTRK z^-B1G#dUp&3`TJkS|@T^>rL+HAg`iSrb_L>FuUIS?$sX+^?Y(D7_StOPvD_(KcJ=u zDvQ&cDl(4FUZj&2+oS-XRFf_(tMyjUVseSRZ&;SPGIHxkpSz;xL(%h>(epQ>=O0DS z9m#VZW)rNwF*GEjl{qf>xS%#g$>DZe>hLW5o?J|hdMChVj_zrB!TYN}>itAZboLw$ zcd8YQK4hWuz31#4^;&c;1we(s$rp9~#dCIzdT6;TherjSU-wwbBa46_5@-USCW-=B zM5eD2a7z%aq>a3O67qX+5cSZBHUN5_c(n(5cX!h50YE?U5j4`N4JEzg zp+rXLk&#zGu%F-!42~AFgVa)95Hh-4UdyL2XjEQ$Frc@xN=B=HEyV`%leh%Nr{*eY zkP7=rMk3N5RZ2A;LKDqQfzma%jh_K~I)BvJ<9g}o?7&z5#&!03VUxZ3%!f)OE1W!E zt60}q;8>u$9QvM~p137Oc=qtK_$PE3AO=zPHEblF`EKtB%i)~kE84u7-tAh-X71(= z5GwxCS!+&IA%R?bi(h232094rz)_5Jwg88D<*425}BZ z41iV8i4!4)JYEVtduPZ=vU2iF;Ie>c*oK-;mq4PO#Q>IiTD(+4rdnKS(0m#IK}v(SCdaB%IpxGLR&a5o zdB_U(3jGu!*9r)MAc;-# zXI;EpJnu~4_}1$Ud6en1<&+>JNr)m7LkJztptu-O%nj+1J`~xeiF^eSDz#>6Kj<{0 zOsGIS=Lph5C|~PR5L+ib5sP6x9)T?_Q-Zn+E89%s?!=}*JYDAN!$1RSODa)r{!-1Z zt)6$Mq!U{_nWnQu6RqyZoC!fu;O%AiNl8KI;Fn%A01I#D11)co$u}4Ri@#RlIEPlO zoK0CIwtP__QfXp*avYlqVnrazR1e-HmqNUlYLzPsa$-f~Dw#GcY#)lHjz_gi4yICl zET3V+{vOoW#;%L-W8TNdZmEt2$nF9OXFz&uy=em$J1I&Y;a{l++EB%9j1qQKh)j93 zPQROqYKx6OC;CBM-%g?^{6ysf8Q5@F5G?1MjlN3;{(Bf;7&~+Uzkd!bXeulk#&UvW z3MpNT73D5p{HD^0*yEGl$~L4sM8CFFb1YE9VWQ-k2cD+vPSbTR!Q%_*xfZ?VYrF8c zaW+;p_BM=T(JMjkjvKraV!Y<1KYGLPpv<{?(P6&26@p12d)Ac0gDF`fLZDO8MOy}| zvquFYIl<$Pe1?{4_&Z!71en^j4ds}H&budqrVH#;L%JBL_C3&hPB{i72+Mh+T8>wG zA{jVAD?VNza3l#zAe$jstJEOdnArQ0`=hP#~f;u zI|Tm`UN<@N^y{6~uKYUuLW<5T*I@G}btR@@)RE1V$8>iFs~fk5`9$*#5dY&fl*^v$ z$zLG^Yk~k6>yRYO5E?|gA#!S#rntNdsnj0Fuw15D~0qX&4&Su3gPoSwTjf$Pw{ zM;ECj`fngW0^ZAv12ApAgxXFv`iMr(PTeO{EjbA%JaM1kg2FyK5Y(g4fKqx%I1=94 z_)QTjfsz)e*15r1MTB zV6W(gRmq+@cnSG+7}!8_8gU~bO(k%8XUMhe0ty#?vCucGH_aiv8n4bIFyf~YA+q8e-7?;Nm^37 zflOT37M+}wAU$`6J@!=oex*FseFm=0U;L*kMld)&i2${CWh)hF``-WY7;Ys)^5Le_%Ii zO)PqwRy$Xjx;}fOpmMWrYjf9RK+j)Ork;Y@0crDr=M0fkUA*B4KhzC4wGMEwq*OYG z3!5di$+Yk-^*Wdo`=%)#VQ1;PDRE@pVYnm#jN+cr0L~dsOWI~hPda2s6lwU-dFvn) z^W}z|tzs7iHn0JJDU)9VMd`FZe|O}BiUjF2^2-_~s$_o3HG~ups%=gdAuBnwI(~51 zUPrhxj9Uf@b7T8rRLPpZB~8>Umaq@yt|s^E1mA3oAvT-dx?+M6g~_HYZ&U!=!g>hL z?nqj-2|^(Y27XynTtRpFrG&6iz@H_}AX#$<+p~<}&j!SJ2%8Y)fcCM_fRTZ-<4w`y z$DyUZaAiSNoAOd7RMD{BXX!ivkH~Sea;t?oLWtBB5S8F;%2d~}-7y92muc1b(!F%` zgDRb1WyOjuCU zM|?^{h_#b=HEA^A!QAzCx+Aoc{y~6|#)C*Sa*hI>QU@p}mVBUlx-um4m?q%yv-IcZ ziP!dYGkaRK#bF6y$~pJ#Zr!_CsZ2A9>xkd^fj3l>qFqDKNNlejG`OmubF)728p}qr z z6$KFF1k&4Df*~OSKKLydj59FgFov`cPh6o1=a){2V-muW931_^&&`xr1qJdO;70rS zix#jXgO-m>0r^DG&8nhz-s7RDE{O+Z3?e25lq4Avj&Iw2<>Sl)ILPyuj6w+9uPypM z{al_iPV29C(+{|tE|iv)dL}i5-(wQKKuS~1RfkEJg=@GoSwdy8=8+v2+%e~l3At;? zb*Wuz9nw^KcdUGEyfXDZvXV=1Ru3Ev;wA7$&_3R{T^;=iHuftsKPi1s{_$wJ^zL=} z^V$3EPtWv(RIoVM;^COKK93}PTt zdxe=0!fd}!RnG@+VjprwW<;TchL4cGb;zVzp;lD1hf1)V$N73nsa$62_O=yEvYU=L z9A#0=l0lQ=d3C=dfL>!I+~+%V5yy)x>yB(!ozlx;2Br8*Vx^1>6Ey;4wo4 z3YYlU=5sP3N_q+b;|s)5FCIBeia1d<>|=4a3%YM2{4EEfOn^OZ}GzlId4MjwdQ(v$*GiH#%8) zcf2362X%nM{3tgISA9)9Wsr7ty$K_oIAQXhxr^!jwC7TU+p8#rF;*#Fw;fDD<+kN?m7Nu@7q1!>iM=;O>!aPjoI1h z+KJv?v{LIqDiBFX(EF`--hTVrw%x>Z27MDqDsifMy*gR`N%d1T8sQ;>FaQv@{T8WC zQ&qBE*VImQn1FDVKC8~$EaQqZO=uyx9V!S?s^WOlq?5F$DTr+OQ<63Roq+3XlR%YC^Oy!|A-9Rz8ak+d@1CA6pJ-;aLgv^w% zXHX@}{yNy#IgEzd@DvxX?;}&Vz<+@&Dq#&B%#Bgt#pwN7G`}=~&E}f4rlvC)BFx1Z zV$Fk3sk>4)WX#U*S(nsxJNDs*Gv`0|Ii{~U7R!8T7 zm(xhZLad^4{5F{HBKd3lmjv0xz8q+K6U_yzlre>hr zJB?DjOiRP9TvuAe^>59W2Ir94T@$A>=@+tjjp9Zt0ZJq1T$|!Sb@r@8S*T-14#{9x zRYY(pY?z?SIG!_GHIOwO0c^_A@v$*naf)}>DmP#*79PSUYBX64Y)TPM{scin#F%m$ zK(jPtWA3~*`?GG}=b}xHX7jhgHCX5#b6v%}4wHq4xp6KQ)-DzaUIO(VEx9~U1f3y_ zu1BbbgjpSnrx{Q=RtX+UidZaRu&EZpo)W=}i=!vnlX1c*d6SqM!StLnB*m;Bjvs?s zPY!%7pJh&lEHp#p>9#+2b1p7hy;l#vclAVh zVrp*k#3v=m=JN?*2Z#|g5i5DFcczK^xAO~$CjY7vk!Ad$OMW;M{BTu%_$2t@UHRc; zC-5W_s85iS5wpCZCZ%x;o-9!v$^;9+t78c6Pe>^3*eAoX_Co%~l4S1!L}cYDhv%bx z1?1lF3>%~MC7 zRks}(Cq`r3N8}Y8u?e)SXjnNZqcIs4DD%VN!GTMCm;0_HfB_>rM^*5l2Z_|x@mU{!nDq5cPqE}ujtn0#W;smHFi$mMzP7>@#)&! zWbbGdPlB+MrILFw|=PO z^`h^ITJ=C19aNEM22BeiMBTqnRem6i3XixmDd>5#h$+9`&sVA1buuBbXHV)f8YqN`QsW{_)Q1kr5ZWZ?R1LdV*4yCE}8H)99v*0LcHwOZ|TWoo=K>VN&c=QxNn z!0ZyTGEI)&W<15Rda~g8)QJk8w9c~1eIIFt!EvW5xC|J#&A$7oKEGd^n?vRdi@mW> znqt?qPkYe>sH}R|qck~-N|yn@BkvA@thcH~BhDKuj%lkZ9&_9sPMgFoJ# z*zf_IGgWt)g7e1spBWV#{pvN=pjTK3NtQqf758AGM4$<@Of#1qm5?5dG5tvA8Dl)% z9a_;lOGuqZ3l{Y?>?YvLbI6!ES@Dd{0$dzL2O(14AF*bzz|kAU@HekhEM9b}8G99U z#p13a`-Vjr_J4Hw@&In^>l+-t)OY1WIdF%2>s?G@@J_DG$}FjZjC=8Tx;n3<_BnNm zNyJU^i3?xQ7?7z)CRmA@!f9$pVz(A>h{5+9%rd1}e90_md$-hq{8M_Lx-!==V4-|{DG`oE z=h?Hjy!vC}ps^{LR0{zD1?Q?o?Ra;%XDUiFrmj=~bGvrUbFI#C@o1}S9A>@EOU~-z z?U!)nxLe?HB%@YEgp#Q-F{R<%uTFJ}Z@c8Q8T`{zwp*Y*aKf3u86%0}VLHU~R1tZjFg6_B{_w-^pT`OP>(Jmn zH?w7+&@o#W-u3a>8*|rWG1)tYg*7m9v-if0PvO?7)#fU--ftg&=a?XMZ2a@eXo^8` zm^0u`OkCnu%mx@0jRo4Zcv~tF0L2%H^WD<>h>b!l6%NZf6ehjKC`91TSXGQ}S9cgC zajX4oc^LUX%evJA;fy4HWTJ}enxu7C39tQ#ML<-sYP)jJT;-;Sd1vlkLz6*gckvR- zEf9hxEd*$L9gqJ4@%R#*#6;2;<|eOIW|AL3cwN9BMs}2+TFATZL0BhhCAA?JWaFx-Zn@%VxK70EGB&Kt0TERs=vxdMG` z#_r zhD1||?-%Er@CrLc_~zm}tjG)N(zwguwn(om{6*B%rMhM=4PLx_W%$$&ht+8rWeTu& zSAKYD0IC960)%1G_4@kz2L=ZRP7hx>3$N#QOK;{C>i@9s!Usv2xAMxIzj*rWnX^fu zx2cW1@7lDotL%RkoU-V_6#tc(vTOzF0>`Vi_VhhG*zIwt@Un)7l-r`9*Xw*$)({R1eAvL6U& z@*z^Xna;!g=>AP07qnPIvY2%ZpUz8dU=6U{yk^s@2C49yMVUzbygU+dm}Ig(ceO*Q zThWOH7=K7uM^MuSC#5yvs{*$_2A4k^7~DuHzbbfnb4G&R%vBnN=uO>hrP3LzleF?t z2~O~k>x4@ja6?7fSN7&`cSJnz%J!~I^rqQ$f`C7*Tte;!?Bz-duGwxqH3v(eJaN4` z1E&Qt9-@+5F5{fl(e|B=-3elx&<31nHbf>l8S>-JlqH3=DR8;Z+O3p`5_^H*SmZkn z)Z$!OFbTCQEkH#(4~1ekm<1>zvJ;X{gUO11neaN#RDYbebx@L<0+;P2ZAEoWg8Ir* zwbFF8XpLV}T2&6KAYg-UzZ74i^Ie(e*>b14MQYag(@+iN-TZpjtBmzm^b)4Avg4d|qJMx(Zia z=}$`E^lqHMa+I&3b}YiI=bnW3k07K1aTW-ZaLnC8Nq|M4pJjx-(LgJfan1*dj+773 zd5}?hwd77Q_-RV@VvBL2?sJb*wG|p@Z=4QFz1{qv13f#13t?gHluODaID%<1B6}Hf z(izutREq9aHofoIQ1tlR)c7CZ%3S@SVDv(pFH?G+1${KqP#ozf2lreb?+icY)IpvX(tf!VZPgVq%zIIp%bcL2DOR&|q}zttkyK z31^IO5x*pS)XjXfOC!H(hrMR*qgETgl74sr-<<_$; zG7$q7tR-WjhYZ*hIz+?`1nqR?HyX=m@d(pR!_Hp z?rZ1t_;f{%P0z?V>SH-CK9d*6^Iu4Cqcl(pU=#QVu|k5|@@m*{o$c!U!>*y3p{Xy2 zX1*MnI`oI=6jljBr8Izwv7Im>v^|_-N88=Uj+AhN(FenWm(HENGJN6U@WA;?SAK}j z9Brg4d<5r?xzS;hHjigb4XK`z3pNyuCkP~v8j4;G=>oV8=|P2{urawKpzM-4th031 z3G(}JkvN4{q~21NT>eDt_(oCmg+~-Y@%R0efPV#M*oDw^`I0h1_hzy@-Q|~$Zdn!a zoRqaeLgD)086-68=i(1ZVDYB=q=O2{V6`E^h5EA+rk1w80z)NhvqMM*7<@9ISl2qc zX*eHx`n}+^y~X%u5$z0d*x?SJa{RLFK?V&pEgRNYvKZ7LP#GN(m$*Oy+#Kn$uDNv} z%v)IwqAi>xqyOe;)(UVgE7xJ(lHT%D@L-mW-1XrwahQL+8%wdpAM?2Z%l0VpxINmX6TF4eV0EzdjYRfp)mTY|A!yASE&FP zeTCmoU;KCw)lz{k`tH==Y5Z=nE`g_3_aG>`qHfY6XFDJgXu`=UsC$`C_v?syMig-A z;$TS%7HN2hf4cRoWpxGBTbLeBi%LJSi9z9(R~Rdw6gJmvqLFiEvZPrPWrZ~u?Uf2V z1u`d>%|MeN@A9YRaV$nBvZD^QqDI%r)*2DOKVI8q4-H4Sfq95b@Vd7lY1;KmY!LDd49VDz1YWmFU1oM- z5iv2U%TxI5JR%%e(n&`EH7L^Qvfl<*5DCQ2OOa+^+5b-n62qQtRt_Ns%?86TT%mjC z-AbJJhQ+|>qLG^5y2t8cws5u%zR2nNoOuAor@$?5B_4(=ESk8;AA7Wju|81osU28+ zD4a&|Qo!oUUkSxKEUbSPDJMRw%yda|+lzzYAcPdk4SGTr3PCTCuELGnIdbbdPUsZ! zP(VPZoZL8t0RloaX@9gl(`NflFCMi0YqimKfQO1KY}wH^g_Slzrc%yrnL-#KP-X;I z^tCCGH6mo1zFLfbQ4c<&armlM5ZY&J!MRsJHnR5APAomdCV!S z!;31&Zzh?Fp};aQJ7_jWWo!vukvt2+k|poh75_k)xj8-U;(G6!rf?grnSMyJe5Au+ zbvd{kJ!4+6?HoKDc)ZF1G4RQtIaYUWUJq@o*lXBRVX3@ipQQq zxV&nlpO?Jn^4ww6{r;{XZR!ixph(07He4pe2ois!B-=vV9pYcQj)r1G&`?aq61lIO zJ%&z1P#sExx^cU%!=OMi|Iy5SVl%dCRNtU#tFE>|CyHJ&8&2CUhd+AD@{1-ojPx7htCZl4>i3{N73&<*T4 z188mJwEk>vI@CQc2U}QTY`ijowIW+kxUww_$awS=w+u>-(}zv`;0He_UFf@V_WJ{+ zv*$0J8#s^5L3q4)p>%ezba|lf+_@i?PJQ$Nj?4IdglyQwAJ$~g0;PPqOP5>*36}$U ztU94M)YCx7Lmls9-&Op~-?ubTlffye@1 zT{#Ef1new9 z#DS>+#I^Fs&E(h&*#Y}fUfc{c*{&oKugyvBZr^%sWM=M~hml_d)aePFm52XiVxk+Y zDijnYFkfjAD=0@BOoTNw_3nbH=>0z_7K2EpWjXP+fW@YY*TD7(WgZ4damn-z3 z>F&~b*?hLbNW6pm!JVWLsUUr{Dl2SkU~e8<7oVoE0tqw*_gE1k zNp6NL!Jn%Oz44RERQJvD&AB&@ zl-_{acHbcZxOfb^co|CrU{=60u&&0DTu7!*wG%$Pa{e5)CiR^ux0#CGy8wj;=ZWV_ zj}cY(mEpL-0cUvl@>02J>q&#iF*|(N58izd!d#!5D9^yTf`G7EO%#sK29t7=t(zvG zzOZER4MD}!D#H=mz*Lc+OCJne>AiGu@Jet0#f#rNJ5ZARC5kS|!z6d#zz#7>Eoo74 zflwT^)P`k+WBN?ZDjBWRciio(Y0_Lj&2wbNYDq|kpE$)#ONOPj%u~iY`UUWT}$Wa;0gx7vt8rl#RmhY$_5f8xt z9NfGq8J$ODOq#<1+mu!3niGqx$!swhOR<|@aEfed1mUC>{!Y`utq$<3)*$ZUeha^I4oWsO~3T}J3vv08f>{$s_(WR25 z)Qsy+l&7xGVL^*}ol})LT3nwEJ)ar+{5wbA&{y*HSn?I6q=NkVE&ugYQub6* z_LM6-aBS%FQ++6ZO3Ulx0Dc;HBZ!zFP)}C@R1N<>T>|dhr}NoQ<%fI84^J19@6Y}y z`2LrZ?@yPL@6Y~9^8G1>&4w`!1?D?LpZ5W3>5~w_yWmLeHtgb4HnOaZmY+zK1V86& z)yRVf(f9TUDro$Ow)%x9h4@c!2GtEdRpF4N8Ov_ngl&Sij%2q$Qmvp{w+{h`M|HjB zm6`)MY%g@F4KV)?DNm~AW7 zRkRPicYL)2m+s#HY^iu zH`elJubdqiw0vTonS>WQrAX#Y>}o4)EH&Dwx$s@wU>>SEKZdo9Wc1y~j=z08*rAoO zNirCDQgED>(jCY&gG5-93Q9TkG^Lrz^k{GI*$*yUygUFI&QLVKsWe3*=$%S%jmkn5 zJ`lGY?!pBy(0E6?hdw`Z=96#A)h|v4hll&m^$iXV52M2yvy&5ETzplDFHChEblVp8 zV+`w%*_YUM3CA8ONnYswi{~%(T`>gML?R=UPYR=8I zc!s=*Ml>4?!I6oCMC$Me5{i}qt>{Ggel7Su5`350%gV?cY2U~AJ>Ey^K8y%k> zf|-PLE#E*R7-ZpyW2y_QIQ6cc^G^YQStBP-l=D#|aK`a))O#<|zj2;fDuErRt8O}E?+o%;e&P&Ulvcg_zEg(OnxYFHaZt7Ze_ z$q;M-0%PDDl48L$5z56wQ1FW;x1no8(_fsM_)5p0o!KzWU?)&GV^|%CnK?}c+Ps5P zSEYx!ujJp^uP}uQrknPp9?ncpxhYgaEPQn7(!k|HEC`^s4s*UzC!J}=kW$j7u#Ai6 z(y}p1rI>s=tR>IBrzKZvr~cdzti_YCR7&_lp5%i|R;R%XuC+8kxucdk0;TKKxWFw# zi?~4Q$VZ8VWxKy|iR#lNwQL@qIs{fU(t*>McyeL8U6>x_V-E>1TejDz~p1ZNa0Dt|E`oCDXlTnUG7 zg~~i12^PPqZRa0W(YDyNhy%-}>10iJOr=pK^JxASCkE#qh?P=Ji%aN;Q> z#U%Aj36h1lifvXaMhluQwOKr?0n@)EPl05nHHOWYF)__D<%tX#OVCDWN_P3F+}jGz zxt=l0(=P#W*ovM$(7(uZN~RbqTrd_YXzOKwO(&EH1{iki)uq))zzT&$@Jdv;8PC8; z`;}<__zu87RuEPTE-;OuF92I4!YW1@gVaecuY$qx{Xy0j<~5ZA-0BH!O${j+kA*#R zNY-dB1!~y2z=heqL#TC&x>gu6c#=uB)QN-#oxCcL^5=dxS8w{A6p4Tlyb53uPNn3l zz-ubFp(wh}&6;E`P9CIZv3J0jV;Gt2fEqXl?3Z{UWvEsZtH~9VjY;Ux2@lgdxp;Q2 zr!1Csmjv}iAY3n`LDD)C?Z;RN*dq`t`BgrN9+oFh z2Y^%{+_@5w5}rKwGT^cmf$sxil5%S|RX^fwX_vjS&TYMf+IWmxGomIy1aKBE5X5*D zIWhmGu^YA!quCFO%@ciLl>l{lt3~MxsU~a#Agr0uC@ErvdrjB@obKwxm?p6V!)EJ* z_`9(+5U`sRx6`H4j(iH(Alq^xh?ypX;UzA9>{(XIsw~6t$bP6GEJmV=*m-znZZu!>x_h9=?Q&i+g9ynU2glfDPpV{}?Oz5XZ?8H18D zzH|^EiNkjGfqhSaX5fVzlv>*}~sz6Foah-}(S!OK4(uJP*Fm;?jCmlMpLzmd3V zF@$_1DzQi>H|Bi*etIioc=-Ill@BkT9v<%LJW(3ZyX{6R6S!*_!QasFne7R$AB2V^ zTqJv0%DOF(*2D=2a{!9}c_4YKF%;9>`1N8?U}DZKD`J%a^=xh50A6e)C&W~naC*e3xj^1&AR)!GEW_kR4?Ti<@`oj1Sr z*0+lx$yM$h5L67(b9XTjO>u&ZUVuX3aq$z<9QJ0ZsJ@AOM)=`io3oHH@4AqfCF{6A z&k+VU9RwTGGRx_tVjC6bE`B_4IcV!h1CO{_^{_$`K#%MU1?UlO z_hzu*L@i;lgK-NcHi}~QCpwe)TbMYj4rO+B6dwV-ReOTWu1#l3wx0I`S3hRD8Qf1Q zdlE<=$DstcDHvSH8^3OQAPc?XM7M`IjQ2{3T*`ik`?-l8R5V~4C8Lz!5|GmkfuLsX zixQ+wizTMK&`#A|VZ&0wHy&#zFXsXMrMY;ZF%KnVOvax86)0@tDR01h)pEovhkb&g zu@`qDgD1a-u>$gQuCioVD$6VbaNGgk9_q1%TZ;p%nif_Q=--avXA=~P7idK*VOy@I zB4sZ(ggzk}ZP4N-%|>-S7B}d5D%RVt%CwTxIQiDJhJe$_7K|EW%w2o9nbKnv%@)!t zq*Bg&=~dO>+%*9LY40TEiKMp|C74jh>$d~URdO`wrHnV2cRj!ZbVej@i9nl)YIs>| zt>&W$I!y#Mhegd~Gv)+ckOMKss>u6Gv4cFCUI|_0Jl0DgESFY+b~rGeLMbQ~gAmdA za*yTvtHIS@a7|il#uu$u+L@nTvL-EZbOh2ZD#aO>YFB}(v8};rB(r`Op_Y%DKcZL* zDjMr2N>`M(bd*eff%#*z7AOCtR#2rSD#7)7VjTgeIA6CBJ+<00eSh6 zL3P@$yx+!y*W_f;_EY+}$0c)>@s@)w5+pwK&Ce$%4#mw$MDlPI$NVR%2pJVvk47D)N(@h6)^;5sQMa!b zRgsfpx&(qx%oTRqsd>d*hJ!S^?7T)^`D@kDTWyub$@0qeGU3P_na!ia8p2vlF`{gfUkf-btNZJ61}lOy+$IQ%TYs`q7FAJZkCu)O6kQC)rD5TW%<^1L0nm^V z&p0~&3nx2=s&Gqz&?#$&@+C|yA8CS-Tf+Uw@sCEbp<9$fZH8sS);vU6<U^sNN71m=y5%)_>z6@9_`8q;i(#f zKV}CF8+-m>2$5DI~(&J~&oH^|vv7g@5pFYve)lS*j#u7nNcz1wyd6^))^hN32cT2|( z!583NdRYG|p$`}k<0eLTE~r>hSr!RkIfF zpdwNr-F|^Y7V71fIY_FRKzu?*Ofc?520K2=0drH+*z1J*;4n0u+2jyz7~^jpf|DA1 z3N_qffSE3EQaY&t+q{eYXpz~N8k|VGL|q_fRX60~3`A2@fguAcM9negT_Ffo$2LUPxHM|dXG zPbO^4CcFad<)7{C>X^)~5+S_7-R9^An?vKsY$Ye-5>j?d;)j%!Nf%Za4eJSl}z>HQ*%s&YQH9q zKlvr43W|G`T`~wg`^r@a;k#HT=7f5CRf^7=F2ngH-J`e~{t$N^3lNraItL~IUs!YYN zg~0a1!>7+)mKd4d%avMnZU)KkdJ+CFS&Di=D9t0=*)x4(x^Pc;21)bAk@H^5CXA4! zY2b`&K~Ib%$EeDg4U#QKuaqNZPSHJcEISumuakiutcm?DzwaW@e1g`_cTSzXLhpu^ z(bN~G&R*!d{KM!?EZ+o>J0u}MA`bG=K465t(`HM~UJYCFiaL=l7d`3<1?k;6U3X}f zDmocUa%)j%A9_Do>MW~ks`He4y5^qx-P4GBI_;it23+b5xF=kHB~NGElXGx&e&C+2 zyLTVDryK6+ta}=FPrvV;e(avU=bmo5CrK{?$R^y=dG~~%a_R4adzx}j7u{3UJza87 z)9&dnxu-vHPnX>j0>z{iNo|52oIA8rXpN^?_wFP2gmc7F^84=TQ}^_-d-}{h{lGna z?w*7%(8?|M^#8f1pSY)A{AKs}i$CV`U*Yq=;qz@i|64x)l+XW;&p+eyzvuHEKK}BMsg;7{^xvN;q$-XGtxlm`+v#jH9r3m2@SpOT_<8ux`AmE~{Fi*@_#ggjKL4@9$3yb-!+*<1_i~;s4+>`Rn1ld!}-Ec#p5iJ`eBnne6iL zfAjhO5d0-RlN}ze@R{U)xW;EA_XGF5fjnPA-VKWL#%(@Rd^di^XNv2_AMu&ux$)Qd zOmc6K+#4kK2Fblaa&M5_8zlDz$-O~xZ;;#@B=-i%y+LwsklY(2_Xf$mL2_@9+#4kK z2Fblaa&M5_8zlDz$-O~xZ;;#@B=-i%y+LwsklY(2_Xf$mL2_@9+#4kK2Fblaa&M5_ z8zlDz)yD?uy+L|!klq`l_Xg>`L3(d2I{N(rS?82~r2hu#zd`zMkp3H_{|4#*i1dC! zd_SVNKcculqPRbzxIdz}Klul)zelA1Bhvp7)$x;m#P{TfC#2USs^dq0i|@$~k4c|L zRJTt^&qw5sC#2^is@q3DXML*IC!CHRkzbyWevim6Pe`9f|JdQ{38#-oGO!{@(I=Xqkql%q{k!j&m;2BBl6E9>!1Adi2U=2{PSm&w@3fUwfD&2`7iGI&kXvKAKw7~j*gZLpo{Tb!)(f?$5PCt+S7oR!ZJo-PZZ}=sDJz8RW zt1Qpy<1zW;G4;V?>IeT!{&@V?UH!+L9{e-;<1zW+G5Nzkb9#RKcUYhN@%ZoYnf&mW z@IEF#JSKlW=JfiQ{P>vkfBa8apVR5%f5vA{pO60qpQ$e%Q(rtLy&sd_k4f*xr1xXe z`!VVLnDl;3eesz3;xYO0G4;h`>Wjyu_hZugG3ou7{P>vkeN6rEnDq6})EAG*pO2|8 z9#MZjCVd}KUpyv#ACtb1mmPf{(|mYLdOtRLuk$_YZ~kTXy!lrgzBZ{pHp#!6W59vADf&%HmT1xsSh?e{!QwG zP3ogf%Ks+if0OgaCiTrG^}#0f(T#nh<{0r|0QS0U(&*P#`jMN&r>b{o)Vs?#PCzjU{ARKcuM%5 z65~$^-!qQyDdBrYc%M>3J)_2YN)7dt@IEDnO7>Nmv7b_7JvI2qu}`U?pHhQKmQ^iJ z4t`3F{gfK*DaZSi94#4LwLCSPq<__Ca=2u3)n{tFr!h{lr!iv^4C*J)HBYAPyZ|1C%-*2dQl@hBmSOIBRnI%o>3z_BYvJyBRnHM zo>3z_v+;9=ct(xzj2hvYjh6!X%*IEJ@XW?TjquFir$%^2jqr^8`ivUk8Ts=WX8@!B zGiv;24hJ4QGT~czb(q|HWl0! zEsSl_bBpr4%^81-7RNT}yG8llriR}lzigA4AMS0&MeYeQZTcqz6 z<$cTOOa9)Xyl+w7w>Ou|@gcru=VF9=0j}Ta^E8%KsMS zW1I57Mfu;R{BKcSwkiKxl>cqY{}$zEoASR!`QN7eZ&9AMsn56myVDQb)aP52uWjn{ ztv}^^&PUree#-l{jhFJiZR4Z7Z`*h%@7o4H<$c@WrMzz&e3bWXgNO3I&G~Sf{I<>c zaGU(KO?|LUe%j{zxJ~}qUgUVlFWb}y+vJb!RlX-bY*Qa>lm0uD{~gkMhw`>V{O(Y` zc8Jd%%F_<`*>-s1J514?C3q9rFJU<$Z_zzC-!mA%E{so_EO4 zJCxrY(r<_K+adjSNWUG@Z-?~TA^mnpza7$VhxFSa{dP#d9nx=y^xGl*c1XV+(r<_K z+adjSNWUG@Z-?~TA^mnpza7$VhxFSa{dP#d9nx=y^xGl*c1XWn(r=ga*rop7rM&J^ zU++>rcd4IuDUZ9<$GeojUFzRm%G)mW?JnhOm-=;=^0Z6(?~?wzr2j7Izf1b>lK#7- z|1RmjOZxAU{=20AF6qBZ`tOqdyQKdv>Ay?*?~?wzr2j7Izf1b>lK#7-|1RmjOZxAU z{=20AF6qBZ`tOqdyQKdv>Ay?*?~?wzr2j7Izf1b>lK#7-|1RmjOZxAU{=20AF6qBZ z`tOqdyQKdv>Ay$%?@@mDZaaD3qki7|8K0?-_x^~_)W3UwjnCA#dzAk@%Kskae~Ay$%?~(p{r2ii2zeoD-k^Xz6{~qbTNBZxP{(GeV9_hbF`tOnc zd!+v!>Ay$%?~(p{r2ii2zeoD-k^Xz6{~qbTNBZxP{(GeV9_hbF`tNZ?zi<7M{`>#d z*++Zy*z6lT>GUKkA1G+_Gtg@8@%L~{r}ARv$hp9HSV+D`fUnA<34+?-=?Y7xX-@p zw<#Qr`@VOYYmNKV7xmi|n8tn181>sU*&6q$L+ZCFM2-8LMe4U{wl(fkuhef-up0L{ zv(#_XbZgwFuBqRqur=;;wyEEy`PR5k{Zqe91>CsL6-@m$MY3_9I;nn}LfN>_RZRUh z#jOZBh zHtthf)qhIyYTT!OsV@?q`l4~~B73hd8m}(0ulk~K<|5TXebM-Ek&2+cXk52Q(XTHW zk1bNz>x;%wixltrqVdln1-iay+_Fd!t}hyIEK+Fei^d6y6w~^m(S4BgrskiHk zl#BWzHFbTFQcz!{Zmutq=j)5q#`Q&Vczu!jx4vZjvt<0UWc;&a{Ig{Ivt<0UWc;&a z{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{I zvt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0U zWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a{Ig{Ivt<0UWc;&a z{Ig{Ivt<0UWc;&a{IhKQvuymcZ2Yrq{IhKQvuymcZ2Yrq{IhKQvuymcZ2Yrq{IhKQ zvuymcZ2Yrq{IhKQvuymcZ2Yrq{IhKQvuymcOuGNV$i8f3UpBHY8`+nQ?8`>>Wh48t zk$u_7zHDS)HnJ}p*_Vy%%SQHPBm1(Eec8yqY-C?HvM(FimyPVpM)qYR`?8UJ*~q?Z zWM4M2FB{pHjqJ-t_GKgcvXOn+$i8A^Uoo<;7}-~h>?=n06(jqKk$uI;zG7rwF|w~1 z*;kD0D@OJeBm0VxeZ|PWVq{-2vacA~SB&f{M)nmW`--WJ6;m54rZ!egZLFBuSTVJ+ zVrpZ>)W(XbjTPgc72}^3I#_$p1L`l@l=s&UJznc=Hk zh16G#4_A%ut7i7D(sNv2HI7;}PFOXwca`4b`l|8Rs`19EnZ2v@AlFxo>sF1Xt7by3 z(&VqN8n>((l~>J#T&2lhUp4+&HM*~w3Asv>zrJc5wQ8KO$^~$Jl_r0E)p%^xXu8Tp zXnmC?c74^jW!0#>%7tisl_qw5)%a)C=)TIuXnmC?c74@2YSlPll?&4PDoyPAs`1#G z@y43*#+vcQn(@Y(@y43*#+vcQn(@Y(@y43*#+vcQn(@Y(QF+a%yk<0AGn%d$1=oy% zYxMfp*GzA$8BN!WrfWviHKXa8(R9sdx@I(8Gn%d$P1lU3Yev&Gqv@K_bj@hGW;9(h znywoT*A0j3hQoEk;kw~)-Eg>WI9xXzt{V>54TtN7!*#>qy2;nN$=ABc*Sg8qy2;nN z$=AAJe%&y?Zt}Hm^0jWXST|a%n|!UCe61UG){Q#rrj6HaS-EcXS~q&F8@<+zUh77$ zb)(n1(QDo4wQlrUH+robz1EFh>qf72qu098Yu)IzZuDCB^fDP-HyK_)Fq*EJygx8nJTO{3Fj_n?T0AgXtkDrwe_*s&vw7!%(c*z&{()h2jqa`b z1Hc=QYuqtc)E$H64(*7>9a67x$6Qf&NWI1#!rQn* zIyCN>E9wsE(6~c7H0}^vjXR`6;|{UaxWi#K?vM_RI~-`^4(ZUiLpn6>5TlJdl!?Y2 zVzhCGGSRq0$6(_QWukG1HbUc%%xUsR)IE)#(;jKuCC4>>ZVscn4cg4cWvx~U4 z(!Oror6e`(nhWVJC8=?j`k--_TCH)H`k--_TCH)H`k--_TCH)H`k-;w`1vmNLE|p9 zTH`KfhQ?iLwZ>h}42`>VuQ%>;W@y}{J=>T!{LGsa%o~2@O$z1>Kl3I9^M;>!lY)7} z&%8;&yy0iwq+s6gGjCEbZ}^!vDVR6>%$pR<8-C_Z3g!(z^CkuJhM#$pf_cNwyh*{l z;b-2YVBYXEZ&EOC_?b5;nCHr-vA~(UF;5?PV}UbyW1efB#sX*Z#ytJxjRk7!#ynR) zjRljYdHTv53wJ0N^IQ)#7C4hP<{4knSl~?Fn5WinEYM-yn5WinEN~6in5WinEYM-y zn5WinEO1rVnCDF1SfInYG0&O2vA}g+W1cg4W5IOhJZJL80#|;GdDEf`rW58(i!PW> zm^UrDU^-#mwCIBAgn84V3#Jq1O^Ys=PM9|>x?nnC-n8g~>4bUHq6?-I=1q$(m`<2C zExKSjVcxXpg6V{L)1nKe6Xs2eE|^Z3H!ZqgI$^jm33 zSTLDgpw`_q5m}(pePR-F&veQ?laPC+LGGD6+%tV~&$$1dX@`5p>-S6-+%wL;XOe%< z`1qd5`90&>dnVQQj7RU84Bs=<+%t*2XZ&~1>C*3niyJviJ z&*bW!amhWCqI)(^+%qn@XIyg6B;=mW0ryNE?wQ8FXWW0!^!q*I^?Rnx?-^&`Gj{v` z*?YIolI2?xpd?M_L?s0@M)J{n>2kcu=)}uSm)cE6Cthw+3|?-!q-?qzY`Pq5GCJ{c)2;cY zdjp$pyElFA-*ij8=`;PN+vQE4*Ee0-H+>f0bb;D(`Pp*$*>d^Wa{1YE`Pp*$*>d^W za{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE z`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`Pp*$*>d^Wa{1YE`>^HqVax5;7B|CRZaJ5? z$mQKNj{NQ#M}BvWBfq=Gk>6e8$nUOkapZT`IP$w|9QoZfj{NQ#M}BvWBfq=Gk>6dT=I*Xhb9dLMxw~uB z+}$;5?(P~jcXy4NySqls-Cd*R?ygaDcON--9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+ z9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+9yxa&Id>j8cOE%+9yxa& zId>j8cOLsVKlX8c?Bo2{$N903^J5?9$3D)FeViZrI6wAre(dA?*vI)XE#&TFTFBkU z)Rf)Ft|^ac4|gBa9_~J-J=}dvd${|U_Hg$x?cwfY+QZ$)w1>NoX%BZF(;n_Vrajz! zOnbPy?tEW&zOOsq*PZX{&i8fa`?~Xe-TA)md|!9IuRGt@o$u?;_jTv{y7PVA`M&Oa zUw6K*JKxux@9WO@b?5uK^L^d#mjSu9fSqmFupR>#mjSu9fR9 zE$c2V>n<(pE-mXWE$c2V>n<(pE-mXWE$c2V>n<(pE-mXWE$c2V>s;~fu5*2|yUz9P z?mAZ^yX#!d?)+z$jdkbyy7PU*`M%+N-*CQfINvv%?;Fnd4d?rY^L>M>qumYq`nwxk z3;n?dW5Zdx;Vj*7mTovpH=KbR&cF?4;D$4B!x^~Y4BT)AZa4!soPit8zzt{MhBI)( z8MxsL+;9eNgf=?^H=KbR&cF?4;077^2dke5Acaf9SJ*cog{*speFIXsBz%Q^15(J$SJ*co zg-gO$*f$_0)XrYNLgZd=rM&VDjaP`=lfrR$g~&ZA9Eewl+>^qQc!kJ4DIAJdh}@Gx zVSn{|E(u@xhQ_Pk(>%PwJ_cLJb;c{~V~|4WdWC%qQn>VZg?$WCC~vQ@k3kBTgs-rV zK?;q^E9_&C!X@D=>|>BZDShP|EU$jgCE+XIV0nf82lk7G`PJ{aB>bnp`5S50T+nFJK%*{$#&`;7)Mn6V=s=@BgT|N&Xw+!XX#PN> zPJ_m{3TV`7&}bAvqh5nXLjxK$8#J04(5Ty>(b#}S?FNnJ1~lq7Xf!yWQNux_$pMWz z4jPRPXw>q5dibrk@8NHK{2qSm?R)rJAHRp+dix&!*2nMRx8A;ozxDBZ_^r3^;ctEX z9)9cXd-z))zlYy?`yT$*$M4~{-oA&w_3?Z7EzROTJ^ZbY-@|ViM*+>p@8P#JjiCAX zJ^Yr&5i}pahu_jXg68A*@LL*4(0u$JeoGSxnvdVZZy9+3Ege6aNziB~F{U(>pwUu- zMpFqIZ6#BQk)6G-Nxnve{R;bi$v96tF8(76sD9*o>nv5DiX8P0i2eQK!%OHEm-YN>OU zs#$8c3qeP*d;OMPysx}`2y>X(-Kcb2+ksV^+mu+&9Mtyt=krJ9zyY^j!| zu2^c-QdceYD@*;QrP`L7u~f%WvzF>wYR*zUOI@?nZA*P=sXLbX%2MB0>Sva^YpI`G z>erU~D@*;K6ii(3)d?5~PC9FE)0Aw}kZjY8Y}1Hr(}Zl(fNaxzY}0sb({y0p&&s3O z*rw6grpef*!Pus`*ru`Arm5Jbq1dLG*rt)#ris|5f!L;b*rsvVrfJxwVc4cw*rrj~ zrb*bQLD;4_*rqYqrYYE_A=suF*rpNKrU}@l0RW5 z{5`$6zo$3=;mLj{`+@MJX&^dTcjXqwKyGCjlcmXS06JNkOA`P#S(-}*05Dma>;u4zrO7S;Dp~rG)dzeLOK&hub^tKR z+T&@m2LMWzpX~Xb>;XWM<^Lb~JBR;!4*&PG=HLG({!Z%*z#}V<));_CmZtUnp4Rbu zTGQ`;$KN@e0L;<+0oaJ+1%M-M4*-ztcaGmbaQpypWWRfw>hlj&9{?QL@1Euo?;kjO z0pQ4f=WGRlBTIAq0dQn#&PD(@vNUHO032DG&LsejEX~;l07sVQ>;eETO@B}I1>lkW zPIUs{k)_Em03KPI`~u*SrO7V<9$A{|1i&LpQ=I^KWNE4s0FNw9egg2w(p0Aabo3p^ zo9YBWBpZLK(?3w10BB_IlfM8ovh?3FKlu%SBYWTZ{dblIppoVWz>)qAKqE_2e*kD? zY4RU{MwaGm2|y!DbG8Jak)_FR02*1E<`aNMmge{a(8$s>p8zznG|eXfjVw*`2|y!D z(|iKZ$kNnD02*1E<`aNMmZtdxppm7?ZvYrsn*0TTk)_FB02o=C`~`rKrO96a7+IS9 z1%Q#I$zK2%S(^L>fRUwXE&*U?~G%P^Yvor+{r!F-862~yC3i|208$K*#{r40-9G2i4lm&q8 zS&{T?|3KXa_@0$W-F=B;97+J1p1nX}1bUvO|0n)V)=L=KUhvtDH3Ga!UjUeu{muX$ z;Pfm_+4!E)2yiRQPiN^LeRkw*fw;B)E`e+<;Qyw%_#@3P(5o~9(5&otiaXG(EKP3! zXjYb{`2sqRrKt{oqVxleN6P~`kNysHD@_CK%FKK{|$>+fh7<%H-i0^$+N2DlgACp*;Psnf?vOkIT7d z^c9C;y(4f6vLk=j7jW^6xqM_niEDPX0Y7 z|DKb7&&j{%YJRocw!E{yiuEo|Avi$-n31-*fWsIr;aT{CiIRJtzO3lYh_2 zzvtxNbMo&w`S+asdqMm3g8KS`_UHxm^9AkC3+m$w+M5^DzZbMGFQ{)XXir{Hzh2OO zyr4e4Apc)bUS5#@FUbEF0Uj|y1rKulsMo=M;_?FkB2rv_06;{F%MSpENOAcA01+uJKL8*i#pMS8M5MU< z0Dy=TmmdHSk>c_L03uRcegHs3ipviGh)8ky0RRyxEc_L03uRcegHs3ipviGh)8ky0RRyxEY#@CJ`ylcVH5c z;(P}t5h>1hU=oqydY#@CJ`xaH-Je*irWof5|QGv z0ZbxN+-?Aqh!nRQz$7BYM5MU<0F#Immmgpfk>c_LOd?WTet=0tipvi$iAZtz0VWYCEtPYNCT9UPe_#ia#D z=1HM*zXMDnQe1w3Nkj@A{2gEtk>U~sOd?X~Z1n4lN zZ~?ai+!<2bwg7jA6fWX+fFMJPTN@zA7zOA{?7R01=u4z{zkt3(iuViXOQd+efWAbE z%MZ|(NO9W&^d(ZA01^N;xE~`LaBE@AD z=u4!ytO9+B6qgO4FOlN10c0go+_wCkZ>RbY0wT$>05r)20T4-~_`m}qiInh`4+a2{ z_?8a_0Fg-XZUO9w6mJedij*P%Lt3&x4w1rc3FHtd?3O?dkwO&|$RSc#vOo@zLKS=o z$RSdwf&w{23RO@bhe)9c3gi$eR6&6pB84g_kVB+U1qE`56sn*=4v|6?6v!b`sDc7H zL<*TBkVB-<1rW#~qX1yYMhuWcM)?i-C6Gg;kY55hL<$u}Acshyq6p*=DO8k~|A9tA z0EVot|3D)l07IlW2Y*9F5y&By!yPJt93qA8p+F9i!d)tX93q7dqd*Rk!ksFC93q7- zq(Bal!rdx?93q8Ir9cjmLRl5aAyO!-0y#tq6;~jKNTK2ix$Ag*H z0T?2Mla&Ark;2L9<#%oqp12kL&TYaIx1!&yttbG7NO3C)fFV-ciUMGW6t|)P7$U{3C;)~?aVz?r+k_`> zMZa@>|1OLMH5Xr5G%@^+ii@u(lHgkUUFZXM3SI(Whv{9atY`kQd|lF{X>e&9H4(laR~$T4=FBBfc_!Hr3cVIq`0gA`iB&k3_$;o z;&K4!A5xs_fc_!Hc?{?uQk5Zj(WPmzyqOn+yWH+;n*Y&=0xe(gUC$QWyky37{WRoXeYT zRRR6OUbqe2^jUe+E#{`r!JBR$H(d-j-5LV=hvm5K+jPkU(2v!=j1E3#LTz&xbLyF7Kmdg*If2?0y zE?-G7Bl3b>zz|q)-m!%PgdD){!r>kV46nFSC&1tEPYN znv3tS*l6I(EX?CeNPL-v6iTmrnS~U3qVi=HQfLq5%PgeO9?F+lNTIEhFS95`fUC52 zfwCfnvMNwkq);*i%8C@qp+H%YLa7rdD^e(90%b)CB}$;INTK`)loctI7J;%Ng|Z<~ zR-{l81j>pO@?D^;NFkR6%8C^7RG_R#AqNG@iWKropsYwCcLd6c6!Jo#tVrR=3zQWp z9C?AVB84-NKv|K(nMk0lNFjFw%E~AJt}^Zb%8C@{4xp?^aqa-hiWKJ#psYx7?f}Y) z6z2}0tVnV00LqFK=MJE(NOA4}%8C@{4xp?^aqa-hiWKJ#psYx7?f}Y)6z2}0tc>#5 z#~Dyor1&@k%8C>pXFyqz;^Pb`D^h%%0cAysk29dGNcm43XFyqzLd!2uR;2uA&qIqO zz*WW_Kv^-*|Lzo88v(9j9@-WGt|En&M1ZSEq21VBcfJG4%1T~$z5~jN6z4mjtVnUb z1ImgN=R2URNO8Uc%8C@{JD{vcalQk}iWKKNpsYx7z5~jN6z4mjtVnUb1ImgN=R2UR zNO8Uc%8C@%Nb(Xqia1|-eWdK)^;#>xB z6)Bv%cL7{Qit`INRirq-fKx?^a|bw8q&RngQ$>n%2RK!vICp?kMT&C=I8~%LcYsqx zigO1zRirp~fKx?^b7#Z315_%G54j_FQA!a6DShjeZ)XUC6e%1-L69PazLp?Jk-||G z1SwMJYYBoBDI8}(kRpY?)~nxz_E5hBL5g|kYrXRAC&7zio9Sx_UKA;mD8Y*&g}#>H zMUg@o6TB!==xe?DJ$)@fkYerRyC6uBLSIV|q)4G82!a$T^tA**iWKUyAV`ryUrP|A zNTK`)f)pwAwFE(m6iSpJNRdKc>y>YZ0W62hY&=m9@I=<*iCz(&xcJ5swF6I7S3J=( z!V?{PJW*%xL?y-(y(2u)-NzF(2~SjQJke*u69aL0q7}u{cg74n{kPULJTVxDC)!p# zaT>uBbrVkv$l-|=7f+mA@I=oHPYfI2iFO!IoO1BQI2fK7n8Opb9Z#Hy@Wfaco@k`- zL>qu7PEUAZJPc1XU3j7;#}g+lJTWGQCkE;8L<@o^8aX^ME(QoBE}1~1T>*`X3>sr& zpmEs*8m$dzRA$f^9|Mi*3>s|^XjEv>7$XCXDh(Pf6KGUw&=@BJjcN@V?GC%7(W_H&}b<^qp1Xq zwh}ZNOVDU7L8G|@jrI~W8cfh=F+ror1dTQmG#X9NXf;8j*#wPt6Eqr5&}cb9qv-^V zz9eXzph2Ub0UDR8pwYtwjng)0T&;q}Ic4w|f3e+Y2Y#M_6Hx0AW$dM8<| zH);v~u2$OJq_voImut!F-Ic{w^Dbx$w<=4uab%YKqYFoq^OgB}t(jbHb!*Lqdaa$D zTvW=Lj=eL!&{{do{O4P3EpD;bXe0}*)w}Kb(sDPcG^2+HMvvoE+aR3&}sGB z3pG?!)fP`2KHNiT?8}X-t;SuH(ztPHUS4i4B`9bW*jn|)Wb}>2UUNYjQLcT1vOA-t zmH9HVHEPY$(WA+|!wLRXYm4<}ZM1ah)AH2W+3E7Nt5>IIO2?Ap;6%~y7q5J!zrQ=+ z_qhvm7pL+5d%{U6z#EaE@`YCOcCFnlW0YG}w03l)b1WI@w(y_Dc55X$l{7J`Xj(#S zu+`A9$;rLnKYAj0&{t=*CSzA#sjt+QYn5uPjYE zQ1o(PZS`ii)^1iB5##q$Pw{JoH8d*Cr5?0;bVQ!^>_Ikrafwiw(B97IV9qph83#%W z1ioBp)G^|nQ5k1dfx+c^j)HfJs#sXAE!+wX9v!(|X{SQwW$igI1*Mo!SYwMSuGYG> zg>{HsKZJtWFHG?wN>N2|50Q1th?aV!kRG0 zbZTN(Rgc~Zu!l*d-LBjn6-z7gP?U#R3QI#du+OHFX!V{9%jF+b=4uNvC&so}t5qAK z=&i*?GgQZoS^KGJP$^czpt`%QM(d8+-Tl{;e`j#nz17tNmz{m5xa=Ng)Or`QaanA7 zWdRm!RL%R|12yo~!8MuiK%n8UV3Z&NOYi_rCGWla!N(u`^!<-M_;|l#CzThLHk?WI zLA*sH4j>@|i`k?0(B>eY>blWR?6>bQF2w~6uf4sn%n|#6wGSw0kJ{@$TJ-};+N=H_ zhxP5(?!x#j z+`@uSRqcOj(l&-4`u` zW%OXJ8L6Ow^Z5S){$Iua#VuLXZax^ifQ7M4SFiEn68_r$MKsP_Jg_n)$jVXLwGTf` zZFri$u*}XvyEk9d#;Atm)TvWe<0rCW?q32OO(ymC6TU_sxGqMst??XE;%hf6E42=S zAhqPHtL3SS7jB&GiMLg$&aO7T5E^jZ%j2RozA7o>SwiPtzGH1 zkTa8Us?}VqFXf2Sx1m($>Zq}c#YOu@E}hGLp$Xk-0AWAiHctP0S-<+iO4eVug$Y376XCWZ%mc)YIPR_`( zG$#TYvXP1;%WAuRyV9*e#Ith4Xi~nYNC1k9ska8aIp1nEieIVLZeN1p!}6&QaNzfK zyr3pv;Bu>7$6Qjs{raU zy)RODwT(FAH*@VC^i*rfGje|goR_EpOIYpABjB3G7t0b}L@~XE?x=MH;*=A$KCzOB zz5RQO`a+g8MvSXSWzU5UoF?LSojAvw4 zMb7GoE71U}d0eTi+W5aMIa9rdrImlM>-r~w#cfws5@`+`A5N$lOTnBphdCj~5a{fX zH!tv2ipm-=E`@o)ymXWbbNo1CcJ}I2FIlK8EW_Xo9UZZJdkw}}wg}hsojI31ZO;Xcr1+JWIPN=6B`*-OZ zBZz}x!F#UWj%b~QO7m)`eVpZoDJ{;@Tf{Vjkt~&z39-4AEiqcgLg|k4impyfB-rbN zo7`6~M5LK$8PIy!X3S{3abMLvfyM1_v~bzDC7Eb~IfLjz6B~x-gLgPe)0oSL z>7&`{wQCqD1mWR;PTN)=c{_F*qc~cED^+c^$EtN%I;B;khv!;q=GwKD7JQUy3+AQ< zhq2OtyS|J~53sz^p_Za*8I$@q@F^E7^#=4e`3ieXtvljlhF9t<*z#O~saMu!-kq)0 z5?R)ECMPE5drO^heDG(yS?fwdoHk&4s+srfusbnrh8Dv?xDBe@@Nm9~> z5*Csrk;PIf5vksVv9=1L!5U9W6QyJvTbr(<(fcy{J6i@wW_S%9OZl8uFlD}Xqzq%H zu}58<#iZJ;b-Kba$&=bMX=`A1+N`6gVUQdV!?Qog7=(rlY1D`BVW{C?mcfJuR-B`y za{1hanQ|H1-6iOjEUZV%yb2?=czN^~&n% zr%*lEl^?lLL8G&6JwQtav4G=%Cd=4oJCGUs)J26QJH>svAOR{X=4YoF=O82526HM& zv#7h9=E>CPlf`+cN2n1wq%Qe~m3a*w5hkd#JhTmwiijW+RCq()GM^7~kQ948%K0_w zIC=8q^p*4eQ8gIudr^i5Wp9y~-Q-N_=FZ;@!I8sBA5>OQbrZ^UZT zen4WQ24u>ahq1XOrwmYz#A4Gy)Kfl5ZDqB47fvwEedl_q_KnUmV={ze&gs(E;n0sX zRsM~{MVIc4idmQGTdZs8zG~6lh2ovk(Ff5al4b2;qk^Df)3hvzZ&0YD2IF}STRiy=NYldm5%)a**ZOkk zr5weEymXgkUn0{8DM%cEni zkAp@z_r`S&nsEzaHRwHQ^ay?j8`KcHmy~s0Gh-pI#Q!qy)jMbBJFNx|D2PLZfC#D{ z`nHtxi8f)+Y}jE4es^&9P{F_#3%KkJHyc&&l<~f`a@YvTTX1H(^=7FhC31lc)?s6`V0BLpQw!;*i*@l;R!{iRx4jnYU21ym<3>4rWmb}i8MP? z^%Wx?feA~ohWQJDWqV{xJ?%X*f?<2)2-C+N`NC)!Pxi>IrWP~!KpqT`wya%|VaZa` zR3tyCI!E)Twg9%iG*GKk=I)=Xk^1(Jz!2_5epkVJgwqP;UN0WCuJl$s2jIqT^ZyqoDAm zw4O{? zIMhSSPP^;_C0#GkPOzAO!vs})d$FLPkdo+Ii zU6Y1JDwc~}4alFeDARu_D{CuWYeYgcF*hJ$ZyE<2l^MM9Lq;a;>42dq3Ih+w+862F z|KOQ=QMLR$MK~!n(D^KMPYT?UNC48d%km>i1;-G^D(i2go-;<;{PS!EU86Fz1t$;% zFg~CI5YGs~Vq}JfGq*>yrs!zv(gTh`Xc?Y!ZmF%-Q(r|^!*P8o{X!I{U950WE}6@O zXx4|$db)-}RjJ}4VFiyTM~)?#iC8Ky6J76Mqc`2ty>2$8KY*i6(iUT=JeM@ho0&Cy z50V;o0Hg}Gz23@D_iNu& zWK-yVr`wx9+WBPSK^-##!nkr!y|4A+7O77p^&ymUjQ{}6H4`C0;lRUJP$;X~Emxtz@|oY@%$ z4oxwc9AuyR6gP1F$Fngbo#ob@z-|fv)Fx~~#KOhqyCM0^4?j*$E?|!7)}VP=5zDqy zxEEQS&>N)}wIh>5a)nh(fwoTO%&V4~vumM1GAoQcuDjw|3(f`do+wVc6!{6UOAuSK z{PZ8ZEv@igs1{f9I^8K;q7lQC8p7P`*I^Iz=F`9&N0YH6c6r5)9Vs2L6SH1Ns8vSd z{(V(dJyP43A?C3T+rWy^ZaZckuP<`V$Bo%z$=JJD8zsfU%;)?^_e}1Efq4+G#?(gV zm&k+LhNb2a(cb};l;Wb(?IQ{`Hi^z&o4a!H%Gq;+c8Z2>5b4`hLF?as*P>!U(t02-7}(FJ z&z_r}88ocHKOMOFW{$|v0mA`X5i$4iaTW$j6Vilmpp3IIN&$T zKAQli$}37%@Sq)VQ_mFVGQ^OUO-NCDIy8?%2iaOdUe%r43@@beb?faM?#_< z%r;iM$wd5>POY&xIq8EDGf66<0%SAA?a-nnC!$bgk5PbYOW25md~y!=k@1CEU;TI0m|Gwk&yMm>le zV?9xrlVm++cvTNFr!#`=lYI1n-Mg-h76m^%24XYB`w^G(qlS}_*P;;<(Lr48G?oHq zacI$M9xX-9kh4LD<*iK5q*(c<-6^tY`GJc$SGsU{>f*I?(^t>VeV)2|v?$t^Yn@tj zifL2>JZMJrUSVtEN@k`%yD&R9JyVv62R72$n*=EzI~|0yP)!aW&Xo``F|Oy*^xWrH z&Xvz!xq`|nr^aR)x1Q_s!Ip%5)+UpHBBjI09C z7G1@8an>9?_MoR0J4tR3j@c!Gf&upXEeMrj%{2Y9xtX)&FQ$JE<52PmW6bw3XvHk+ z#Vem(n8MvF7)gJ@^Ns07#=zVcuS}htyKv=l!D|b8-ZJy%?A41G=E`$tXFi*rD_@2CneJx8+WvqJKCeX4WjC*B0Tsgy9T#swWI-e551EvrH`G*@uR9Bs#PhwGlHU2UC zb2^#x;&F7p1-u?i<{ zA>cL;l6rC{yB7KshSu&bXv29)#dHHD5yS|?y@Z>3h#K&v%r%C*530w~@*fL#12oI0&~XsuB*CAqhQJUFitUmzwq(PE|7!1~n; zF)G9+lC9ej;(IW0XB9{B>i!4&H4}FKcEZ;Vv%G(+yB4Vr#l=L*%zQh2u8HTC8_QY_iwNqzqquVX3Cszo^|EwT9%TKCF-i+(OQrd-vHf z8eA)Gcm?rni4|9lLoxGY>&6`HIY`OS9t@jQ(H-XoHWyb`Agi5BN78!qK*6w)Dyk>U zyKzN}xKLKR(`w(+<$w&o{1fm04b=ySf6KC|Z<{&%tnS)X2@8Xbn7feI8Tg(itzk5txiMO~Tk>3iw!TE)*D?hh(M(I6q)3)ck00$fkY64_=&?lfPOl4NUsWxo|}mJGOT7 zA~Nn%h}{8=O8YVzst(ONmgH)SU8??3ai9Bkr2(^t8MH!gJGoW6Ye(>9ypE_9KZ2N= z0!n)8a^q!Qb}}Nb>OYu$^|P^%6X(ER^KtR~SS&Q=amF1uoP4n6U}~2|GHr&GDma;9 zB4AN&;|6Zp2@e$kV|Zp z1|fCZL8b%G+ZT6l;tl*DVp2mS0T!9YNtIUifcUD;@B9Y0;-LhyR{+N>DLC?!4?;k%d z0Uh}_+gn(ubvlz;8k<|P7fZ5LZZ8N$pGw|UdH2mkY|_9cKwYCI=<8mqH;MfT5g~KD zL3JpT3?~DOiLu}L1erX1NEmboeL9QFAQc-?H~KLX#wC+x)B^{IS&1FB;i)vR-B-P9 zPL16)5re9R=FTzz+maQ)5*U(zy@9JNrLLBS4S2|+SUE2rT)T2r;y<&2bP`3K*6fps zc1+4n-#Dp-dWJ96%*&EVuD96DmQ42RCv`|qf6Wpv0S%#L$T9kZ_;A%qx1tEeB6jGD z@(TCnr86+#avfO69q6sjBB+N)36jb}yM+@JS`htxJ zI7M5xAW&%EIfXAyu$`YYT4)>Ux>c)LXhVB`OymvIRtui^cyjajO^!Dv5`6)G5$ovG zvEm)jp5uKjiFL<0W1=g9LeZ7J$-hW_WYA3u0wkk`)Z0;cmfZ=BqMgYdbU?7*a3xCtmMs6$|ASXjGC%8(*l@z2$8#zXG12Ysf@@1_2t06L%$2dJ|s0HCF< ztRJS(*H0R9YfynXR8?6K6uktOH%$$p2BA7tMnq3mN*!y`06BlRPtN}Z8-u|rs4PR! zie^cfU_H)hqYRL%<9k6NgARW1(*Y_a@9kHoj8(2wu^t^dWC{n(3W~&%O_TDkrm6== z3*A%i(nPFSuSy~qmciX-sX)aUBB&lrPGNMhZ}U2OsPE>?26Qaej~T;_@X1cE?272W zmU=V*B>jWtx__neD*YZZYgB8RAvbXZISq5g6>|$MyNzSPgkV4KSAK1dip)R67RMqn zJ!j=sS{No0zEmi%e0hk(Qgl+0HL)lX*I?gExxQQGSWwS5dL8+q!XVK+k4Vl}0EI;K z1pdhiI#@?IUOwf3MIV;*9jrvf_ZjGjA5(@bN;Q%%Uz44v#HCreINrd@I<&{UC)t3( z4~bMt$LP}3t^yJbJ7;PIm6p1x zeeDd>l@^@S$FO3^dOhd0GlTseEvjE&=g=+dy)ZkjuRw0~=OJR-Z%yqDiEhzlIf&hi z4HzOK?x0{A_jV2!$l|{B%cZP!et`9qn5noI44FDx4!%tI7iK!k<+8|&%FN)YK3XUu zbKcu7S}A(Auv7%0K-lo=5K+r`%|#Z{Cf#UaxAJUWA7&kgP3K2weLVNkOxGASaj+j{0o~77$ed#`qvN!nlV-laq2nZu6j7rn+vCEUu8-Q z{yhs#BP6yWh+`xkRT>x$Vzv9#T$Mmyy$%cs6|M==noN_26;4P7ZjF(V&IdTg8( zp@Z2;F^wCAE#^I9Mt$SG|FDq+(cPE3GNU$Hr?PP@j7N!;an{DU|Ssx@sEV40psU(A*uJmmNaIMxI7WZI-S&;Hv z_Fuyypu&F!YhbnfnJvM7qQ^xJaR?(EiN|vP+I|-JW`JPRBc<}$vGxkSsK`KUtoDKw zJ71IN0Cu&bY5X!SG(pX9B2IK|3EOlydzq}@@V^9f^{8vQ^N)yt9mzA*)M)|%^(z|u zDNo5BrJsVcGO?W^&5@$tZ{sWuJ}`CH1;$q2IF1XbP7e?yxT)7%LIc!r;TUKr&X&PA z`hZ&rvICDTla)^NsY-8TsiUpJ7c}uX0zClmI-@dp**7I$x?|)(V93-oELZeulzA(SvHlNJKSyvqHV>ly%{p1vK|8lY!5)BVKH8s%%Wp#3^3Jl#?m*&RV&ajo1*!NVdhDDE4$CQV}Ro)%ppN! zoOP5iZ#ojOu48^@Q@C{;Mox}i#yaMnK&oVWybJNKwpPRB6vj$A-jf`zYVP!c|9`>Trt!o^r;V>hbiql9X z$t&Yo4kM+=)%5JYEbGA3}__+qXr1 z;9#7%C__~8W_(EErZhvf4v_$R#=^z zDT+4hMCPMY9D6I79us*F7gebiKU_J{{37KPa#lI@P)Vei-k*HbA-8iFeD_EvZ9IK{ z#^DqWrRPF;@FaRAv%`bNrMu&q?QS|0L-emeeXi>XEtlyp_M8-R6AkMWQ4VuW1((2e zHX1n7U@?IOLIo2|!F&T{fmh)z@=oR45;q9QOqZwNg??vf?^*55#JlAFn7%W_A4~Nr zOk4$OR5dRwZ9vBB8qm@qwT6E8S9)MK&<8Wqq`V{OCPGh)1?`}FhjVh`33{H;|9AK6 z3gXQI^J0TG#KPz#i7!>)0I%VU+d(i)y>=8BCgb|?uW|nO^0kW>HIO$V{o32s$Q4RG zizZiD@a0oGzh(9c?)AY6Aa}J8-|m&`UUo`G8brH6+$-xgzO3Gmi%c*Le*9Pt#2h*# zC|P=r8~WvixBwLv#2*U^^VYmUcSFuP_gkW?_%;=)?5x%n>Wf%1yJkq_?U;OvO3uNn z1V|!CW@@HT=nps69F+oRiob+*;exPtEV9`u6q)`NnP)32J%AJ$=pWvNeLI78iZR!C zVNL#cVl+$S&ZOu?W%wAa-jW?H3B!}%QwTMD@?BymwlyD|KuA`mmO`hJw;VW9C**i5 zuI;rAp)0K=+?cZJ`f7tH$7f*9h1irtD|AKTa)twyxv%!P#k$a};>Zft7$HiXajNiL z$g3B`&E)ZzW;V2Bt3S0`T#wl@EH%>mT>E6gIdf^V<%CS9a$DBpcA6Pcnf{sz44(yT zR2!G{%RI?Q8SiR0a7m$Cw#c1@ci@EFS*^}TLO(b!KrJCeA?^b#fMLyzzJc7tCQAlV@>Z5+wj3-S z|Kh|JF2So^$F(Rq7mL%&HbS@q(Y`w>!+Yf1^u_79=>*>(o=?utT)E^~eCXuk#P*U? z=98~JpPrePw=3gDEX(DTRw@tOPy!mx}th32&eI4vHCN727&QA=ShAXHdpH^{ha}L?l(Cl0B74 zvR;`f%qQMTPW4`2n$v;(5u`XO?7vv)4f`FuG?KZH{;%i~plmsHdMkPlkk1}5SJ#d= z`ovAoL^3h6ai{0YT3cNE^pNoatWJXMIxRTt`wY3YmaA7ym3)7@Ab{`lbN;fcqVQw2 z*K7NVXk;1DY5A0`<1ClX;_lvR*FH@E#}eOI)^Op3M9Dd;;%vq$V(T*f+FqD^)DdOt z6+=u>fE&U{NiD|=pEU7mU`gBU%3b8)l&AH)FY}B}*eWLP9Y1ahH?Ie{V}Lg7b#N^c zo1&bOcvV%-qibWvPS3Zhcg2M=nB(lkmAPyrM`jlRWU!2b80?8&UAQMrevpiQJ~ww2 zmL7H8i;9oh@Ze~Av{HR+AMoH1$wCBQ#%#*%(lSoK0Wy%EQ1uRsVCKdE_Arj^x_-WL z6j4&aEHo~O%`5rWGApa~acn^VUc(1a-az(HjxO#v@OqqDhg;Ty z&JBGXR4hEwYgB!*FMto2e3$UGSj>w-C!}Mzr4%WJFGJ38D6ubI{V>fCLdx_46Ap+u ziKyi(hO^B=LjTA2zQ0f zI9u!;`HY)OQy7=Dzfweh15|jH>bOdtj*$=CJ{pHG3`hCY2jc~IH~&mcwb9>S`^e;4 zvwTf249htD*~juV8u-gf=ug;@Jnxt=VysOt`dB=PyL0}r+>RSVflqqf;^eOON^N|( z%ROKjuYyj5G!t|F3-;&M@Q2;o^Zm;9h(mDfSq9Bk1rWv$~WSMKyt=lMfm^bJb zhS+jcvD0e*^J8MDEp%iy9L8=1clMmkT~oI{g()(Wy@*U0kko%36f*CO8`+ z_BiB*4T-2~#7hmGRX#`Q{dYeRai!T?^;N|Mktn9X6i7>Yt5~AfpgX)C24;>ybLHDo z0%+}!?^d#c_r9xcs`-_NB&&U;P#F`7c_Rxza`w~Nt3ZlFP|jKyMk&OZLtNrW#^h<- zc#>c3eZa^`epn3B4h<-3&InwkvO;T}60b=gN0Yt=sbpC&#d9fscHcnm)#8Ch+OVDX z>_a5o89CO5hXsnH5TZetOC(TEvve}D0Dx_mO*uM=-6aXtVC4YSkiqD%0EjfVoYJ4f z-18r_(LN?3jy&`t&15EF1iQ?2Ibj4-sm1DhTtwkpmy3(is!%B`t0r7HwH0t$qM%!< zoP9+Hp^2owFOw)ij_4{dh;#V-gx_oo;+88Sa4m3$7CY9@fkDCp`9MRWgKkRt%kvwM z1B9=W+LXcTv>ba?!6V+m{Fp@P3bhM>)O(`ss?Q>p0?0li>wpe?$qSIp3IdA$SA)%m zGFgBI36P&w`)uBbnC^AI` z<=vJh`wZ-m=A~mPl&Z@OMHMI5~;PUjP>U?lG=dgB9 z-@|rMyLKB_`FZ<2de`g3Bz|{gp_VCN4zx>C)86BJwf<_KyCjttz6;}-3Df7}a-3v> z(`hD%z3#vlS1`_W>J}9V{PMw(?`OvDdKND;TUbz(tkkMmIWi~c+F^6KQ?sw2;}BmZ z8d|Pg#__?b1OtSBN3O!v$EsLbd+MhAccR;xxZ_c)n{sra-D@Tg7X;U^-1qp{&D2Pv zAYkU|k^)oi;17Mu$7VE_4UUHy^;2@mN5_))j(_k|POdl?hw!E#t?ZQaw}Z ze-BnFKP>(B#9EWn+*uq%fX9nQ>CTgF`+-sQrKatgql&r$KHm(r;oxX9x%xR{pf_Pk ztF=g(RX!jhi1z}962>1VEnB#-0@ElFE(xFAyfO0S*_ra?vzMmPEqp5V1U{5{Q|`U# z8E$OwNgz`UsN7#SiJha+_u53ySAKXJ{lP)gZy;W_Hj?X^wCl7p_`pB zo@N#hum}FG%wtlq4plmIY5sZyzv0FZEypME=$VyTEC;v=vsZ3!u(Oq)~X zM@a9827^PFa6SN;a!WeCoQg@vDJ#cD2LC0w2dRz*`{MyS5$u#)J%VucEwu* zoRYu=l;nARn%4Q)XTMoSd11Czae2zFa;pgo@qUG6m?6j_+KUNO0?g44Pf$S%IZ~Ym zL}+tT<(a=Uqvz5F@zN6wg_5Z2dq7!V)JVQ)Xq=awpKrAq_ia)>udq_k$VJ3M@YTlg zY90R@T2eij7D>^KDFP;P??Bp6(g z?EHqAW*)j}X7Ac`@!I=lp^?@MUxmSpa`%f&5r8K%ft;BZxOX})t|sR`#1$u=-T zE#B%fm3PxHC&c2?7vGc_VPFl@&8p}-C95Qd^JIzJ^!SlY=%6^fQjX$Ryr2vu8NlfMIBlONO9u*F!NUxlA3@5$e=#n@M$yqHK9St{g8 zzz!|$2Uh3h@8A;TSA7wyj~tq;ntl0QhcI`i4=vM=9%&o(X>c8SeGu24Vo(c z*Rp_*pTg=%HGCXg4>Js?qSswiTuSe#)~92=&}zsBQM3+w98!m72#ezUpcQq(rq5IP z{bFb4S645dz5H2_VW4f;m1~G^t6*Qj*BlvcNMVS=CQ}P43{xi-NcEdk?iL zj*H^h1_P(E2A0d6SQ?A`VwG{bjx~y$&u3SnRTH?R_3D(DuQ#KBumnv5+Lx2na_>^# zi7^9E7*=!(H81B1%!PjP8mqEzfa)u25ee+nAaxK&8W*{ZDwPMbfyI6>1$tVdw%WM^kKRupv|HtwE1~GH(eLK9s^LJ4 z2q&wOb}Q|Pv}S;_BAa9aUSGZ?Vd98ZUC1?3M-wG{Z_&pwbT3Bl4m;ZRKofnaAtpw^a~CSRgfWYbKkh?d)KfdGR3^ zSx>nvV2>72cPHt5YA>MofzDabevnBo{lz9X`-N1SoRpMq;^!Su)M%@ih_Sw3w^C~_ z$y&yHm1BPzRfQ#8Dr;B@I)4B9FDhfdK0fvr<*)D8p}vvGT$k=z-}GdJbT`M!lA1-$ zgKY&|oRJgdU_Xu{G;wNj1)uVS^~RZR>?qMElt@+^U+IH6x2s<$7XIs$oD5A6>rN*Q z{O}rrna)olos>Y6Py}wvD|b7;YCuBu3mEACM6c7Hn8!X%t$7=$MfeeBz1bS`QN)m> z>*+(K+BXQJbZf@B6UI86aD;EBq}=E!{cGFkDv66&lu7BHN$grtCZ$^@bV_tqcVTpV z4x+Zf>dWBB-jx}4)6-1r)0`5Vl6lymVl1GI-L4Y6oXLraP8Y^jqY!bM-pC#y-ou!r zzD&fkut|9+(=PFD#;~|B-v>)>|0o`$Gn*41Mp+(1cFkit)oa!fUy%)W9*W7nVRQS~ z!C%A&PnT*{Y-b#-zNUP0{$Q_Y+r+VZy%_#!30>$3 zPFBK-lukynosnpqRv5d3P2J{FMw;U=@38z~9MmEpc(10d+-||=_OtD)SiF@xmBpHF z!;QwDBszCtrd$?FDV^haZZns1-$$^xFlJ)2F|}mMmbiz2hRKSpqo0H{2iITAP9}`2 zjm+Og?y|V~^4VG%mQ~#Ul34@Z6%0#ui_n}2iSbB*a^759%9$Zo-T;SVDjX4^t1od3 z*?)`*H=lgS`3=S<@g~9ETT*S9#O%5Q*5PMm_gahxEHyd}53#6n6u3+Kp4L^0# zpF$NgwQjGS`5F_pKB8mw{zBY8S-KDFBWkpj!>N<@ci**f!4Zw+KI+2a0{-d00!*#J zih2?2(NxlOG4BH}mxK3`ELo*yViZ`7!7=5)#4un<@(yBOxqk(uT#h}HQ4#M1({f)w zhNX@3|J)~}i>F`X@BKti(8!zjLse1z-qr$=|Fqw~Q4w*kbU@3t*wGH$hdPvBqbt!X zGB7-qkoM|6mN<5zAmr4l@Kxoqgq;HQKo9qWA&Ul3tGYHjJ(Cu7KT)qBB^>-|a8*~& z&dz>yW#*if`RA(&AB_LJ{KfRoL)%f+NAH~JEMI;1?v=Mjj=sB8?Ts%tu21~(#K(Wt zzP-}@>(+@kzxrmjQ#roU_{%Hx_dfXLdkZtiKCZv>mzO5q{CIY<^^0UcuV$yGuGuH* zS>yerer4>}Zd6WU? zhGm|^WS_2*OK_VR)X?J%d=?$oM@;JCYWfO0`>vIzOJITX(CyjMF>(Ev-)pqEhvwGZb+20|icQ2$oDzEqc^*qj~2BR1y*BP7ANJ~~fv z4|*TwN6w7lU-o^W4|p~BKK5RCmGr6|6PK6K@R}Yu@raPL5CN7Z779o8)My$BL{G5G zu1gH>uWkLtElh)6(x3GA(M;d1?U06HoyKAd`Sd^-1jhtZ&%YH8vlOXIGhG0smB+)s zzs7|(@WJcBEeyHPOn=t3CB_EQ>^DQwhUh5C0X*ncBDX_St30%&3n4k&m+71{5{iK! zkG*kS6;nca_fQoC59O8Ro5j6VNQk6l1P&dVM;mVGV_53S1z)iR*+${yUsMDN&W)fp zJV=u3x#3~Tap`PneXn~TSc1nn?OuY2TV5&)20fIKZ=3&M=QO-+l8pA=hGF)h;GvznQYDM+UlGkDORXb=Q02v#XEc7h8 zlo7TAaK41r1u+L38+nV~x>$_jw=9Fb17T6&!w1)+`mi6M1QwNB+;QE84-q$IsmAN} zx_58g*R_hbP2J{7!lDQ+jw^}4;sxMK205&tB{+#w(2{Ugk9TA2Y(y9@m|>0rIFimE z5UseElr*za-dZdoBMDI9*O3iDbA;1UHmeEc$qdmOWt|yQf^*x{Rt7f6ifBvPnCm|4 zeNF3D_Sk<`qcZI&Zl%i*)j;f4rXHQ$DI(HBKRI$0-@8g>H8(ST#H{6;pzBXM<66`cp{2Q@uPmnZuHyExcEQ~M^FOpwEYBaRTLB0GLF z1WpZbu#<4?)MB##2I%pl1A4f!Ud8cjp5!euvN%Uh3ri1EPR{QYrMch-h|Ncp!{{u8 z$36BeORA8g^NG$0w)c)hD5lWyIgv9N6Oo#y*nY?v;H-&`f2Gk$l|LB6p}E9_O9snC zOT$C*bBLIQ!IZ(`REBt=7aolXT!uZz;{?C2rM0DAlRgbCJU8GvtkR;OV0Y>WB0~Fc z#~}>29M8ikn-mH?kB0Z>ofp*wEts?EE~tNHV*oRhvOIQM%m9fg@{FlZW4|?8ty^#s z5n@Fl1BUMv@%&XNiAW)48Nn%TfxmkoFr#su`CeF zEMA#=Sh~ey7n*UcruL0bMP<9lfwyf=(2~PkK!Ht5hQDsFe+?7^xv^j!GN%#S_tiSi zPo{uK;_!5O*x1BrsFpM_t|V=o0|lf7gckVP(4+ODG^Kk|&Vv$eg$wT<`0=nk^&?!c zQjVGIq;td)?5I7acVc&eBH0l;Ssg!REaDFL)pKED8+ ziZ(N~5qdN@?BimSER#1}#M6U)VS`MxK~Kp*pi7nc1<1hCa{ZUL8Y|7#>aW_JZtwP; zZ|?s3?59)brq6%&`GtS?#l=gPuU!30+z7t*_r3Q&`0%5TfBF}1oOyHP zC%<^>Z3G|6$@Q=AJve##uW!C{>e%>+$%#+yD=Mjq2P(1)hVZThfT516kDrjgCzFpp zkcW5PaT(GV#^YN(at0P(J`1CO3#;knVRq#xZqB?bS2XaSp!6;lV6Tb*gn)2sD#&lx z2a3{xHt`LEY_Ffdr*{sI-~>QR08`NLY8^0-vUV)vn)JnK-N%(}S-=5RTkQ$Yshg)K z4r@(%kVCnkYYH!mDl790Zg!XDTmtMaf7NO{9S2+UinUklbuE;2>bhr!bRt4ax6X+GZWf z0nC1V6ZyL4edc7--GRS z_i0M%I7kc9jodR80MX$>>1uBt7<8$2nny!d0x?8ushG!WGZ*}F7RlpshFEYM#8TS4 zF4H--TV?aG(k${9Y<5c0bF_N8OgAoZm=;^e;t@p7mV8*F)svyrwkKyOuhzo*;N3JX zA+{4~;Ucd2h3cg}&KB^&dm>V%nBTZ<>+c#&u$EtNY|#sG%pRzw7bZRdEQPWIhAi>5 z=W-3T<3?zUKBEqf4;o$&$4&B|!C6lT;QQkr3&d4QHYTX&i1ET&Wfh0lfR&V%I}ef4 zkIBdq%7#P^mP)6+9zP^5%+YBY9n?xQEKWNkBj_EIQA&7IA$o^+$_CycoRoJkj6pc{ z+A_LiRbepY60bBKAu@m+-jyh=9Js^TlO8on_O=3+9~4%bDl1JBJv^y|slhTkp*QJt zR<*L}nYkfTVlZ#v03Y7<-eEv0fRY0alU|yxt;i?hq|4*Ur!ua{s`pzpi*!ZneM1g< zr^gfD_{FH)jk~W`>h3RgSC8Vz*&BLL(d*G8s8VjQp580i@m#CFJ zEF#BzR0S}m&6W$PY)iR6+J;o6^l!KSDCzHgPlOF)@dIjI3Kp>gxTz=x1wEVJWuf+9{GPPp!4csT-<9!`sl z;nRc`i_vlkieEr5(tKyabkrTELk%wGEx)Q6Zul!MWwXAt+-=+)(;JzN%5e`BWJ7sJ z>=e1S!jKhlPubce%`J_OyU&WS%qjpwqaQ_bgip$5zo4Zg70zf?G9hM6%)>e2N2=LR zg6IQLMUn&siO}-{@S8i8o(+-tf!|eF143D(c1OrIx zrlz-WMDz4wtyYzN4+y_cI~cQAse>s{v687LIfF%9a$|@>D}TW#573R<1j5p94^Kf+$K;%Hd7 z8C&3O?(JaWvn977Wn>DxESz3nz=bJ+M%ViR{sqJ{E){(q<>glM95~$WVYzg>CZ1%N ztKGlM5MfGuZ3R0l#k%l~`rL)S8?L(l0-4f*HwJSY;AB8UCns}-#PfQt6p<_$F<*X& z&4BNVvB&ZB8?&_)XqBdc2!RVVC)8c{sbpHNgbD0ZmaNA`p(z||w^R0AG8|w#Mw~j` z&RMB6#Vap@VS$e>o_l<#$|⋘gd^l|59umnM&jp`Ikblx(KHiw3?0b<%^!t%Mm-7 z7WKjShvV-hqnh(5EVt(ttX|AE%YK=)I+-kd`2I&9RgZr-|KWS@{`CEKtJUN4@BKw} zapC=+epLJLqsoW=YPiXh*5XYQM?3D@1qq|VuMRoAjI>t-t3js#@O-NFjeZ+-97{1! zy7g|Oc52#aNGtRdJ_Ld*ubmzad;&fQ7Sri|dFm8Iw$)tnWcaT$D3WHQu6v zUa@Id0Pv8ktPxZ@i9}(k*)UE zTG%Ak(0b(DZsEu{8v+f!vIgtcMstb!!Lj89owN#^@?5F>a?kRltbG)vCwX`PHXIi% z-iqKC-t-L(eCZ(w8?;RG>~zqUiTH)}27&@bE?vms!?@tM--5E;&$WmEe-i01j?BbP3O_o*CZjpX0= zd056@&H6$9lb*9o+nGK|E3zqX*M9%T?YH>?CsqL(1)X6t?<PKPyhM*Rr2U)^jsn2^%E1_xT~}V3)CCuRYO5H zyvnFrJ3C`L;2A)jNbx0#8R{N)oucwJx81t#Vi-eS-oV0U>uxrXqpiW>Gy1icN8 zv8`0oPYkJ}FL9u>TzFcDOJZNx4`eh9^31g<-WM*O5hYe~>ZJTPOggjvNkTMJevoCZ zVJKskb+;Ai5oW)w$&4oNAIT>-{Gg;}u7OluI`!>U!bjdU|eOesoHJ9V(D zy0C-`xc+QWi2g>X(e!{Jw|z@NwP-OMjkD4as0Ls*KrPt`1oU~XFKr&WB|%Fph^bRL zz9F{DP9T@uDwG|d=ze4WJ02j(HL|1UBLH}P1WU2r;$nTFE`y4-(+ZH8WDx*c!P|pq z4YXCzCQ3i)l*R=OFyA!cks99Adh6-Gw3;cwX%Jo5Z)xo3nU!1pqXB65k3asHFdY+b zqj`qp{PqMmMHwH**IoC^E z*r>=`O%lk_pm-7I`bJVWqz5-nI3U4IIZf*Pm)H%zeIp;8ZTGcK21Phzp?R}b7#9z7 z*!5TOVFu%0*h}Ix^nYByp}b7YN3K8vBcqf14n@GnK(0~D zX?|D`D}324zN6Q7eZs)rwEIGcSv7A-FMPgGdHEztPvRILm%+xqi3#QfiVy$`F%!WR zP~eBKx|Io59a{67L>F`?L#6>~Us{`;PG|Y37G7`(A7X}Q)E-~@HSCNkQYsX(D#&=5 zLGkblOaz+>@iPXA9AXQ_xE%%6)6Ym*U|5(Piqh{tp)d-DwZVjy@3~6ljEEweFx(4A zi0_ZGprddOOi(j7R3U{jK0e6k9Y0@15%yC@p?Nk2;B1NoUXsxkHjZ=P&~KLFuZiRZ znb*z?;DSgeWm<*PN1;#=OP6h{WQZ(41~llSWpYe1N4G}=;mYsLgS!e-$51oe(sWzT zyQ22rW;8#)9Dg`RW+z`%U~`Lr)F?P}i^FlM^S0XrF4rVEJr;l1gv^T0Pq`#yt$gVm zr>v~g^OH_8`jd`C8NoB>e2`hQP7n&jg1gIz|4Qg4vk4dmLPSBiDpFo+>O3VQNGXuM z7^_vURN2xpuLI45FR59&=Xx3yB=6~n&{pTZefU@P)wAZ?M}wX>)}?7%KgbwV5|n7` z0MQdnq@5%!#Kl5Y!i=-65e9EUhRp(W+jbU%Q-Xa(@=3NBO^ms}#U9*W1@T*p|8On9GLw5!|n&WFiS#d3Y(yxL(=a`+su|XTSpW%M6eTih|7lnXS6OJ==+-HXVMY} zM@uJHpY?q>^m|9%T$nU-MT@tQy*(N#mE#*&GP}oQmF0#(K8@sMXSmTf6nl_2FZ@sSI9#91r~ z_c1UCQ>rJAioP~;5arRyai1p%dQAY$;0Q>NG!Bc&T5uvlc*Q+RTQ4jih~Mn3!Z*dl z%v;g;qD|z;7CLq^P3qwLJRCy0QIN#>g;15Lv%G=u#BDj8|8JM4eCYbb>)*bHtV_N> zn1GI0ldgz0cLKAA?P5xcS)G)}v*`uV~ChN)@LQ1&iSn^aFuQ z*Z6gS_SO)e*}SwuI0?0m%+)x`R_)=mufZ#w5T{b%gmI7@AOyA}A(1@nec=S8AeQdY zu(U6Tpf_vSOmE-%T3dt-cOM2Z3S#{$$qKGR;#*B9mW@l_AG8(wCd(NH|3A&hQ@tkUd|&yK`|-xllgsL6QuGA>Sj zEI3<^&~WHJ41Vz@CR#aqpa>vkAzJuq5vXh)en(WJ#>znsqJi_b?(exVTL!|QeErN^ zk;3WUvhY%gx(V@aV^OuNq_B>-ifo2(ZAE7)-#DBB1VlzDW7RiKA)Jln7ZgygJfvc; zfo>?FXmqOk)MDN=4a(h9TxQ7%CmZo>IoG7uJ(TY}keBH3CJpW4jGle^7S-Oa;~Poi z$<>1>ojm!Fhe=&!v^3NWoX3{j{(!_{|1)azWgJ$Y6dl7R9KOKf?_r^u zb^-4LR;@Q50{CdJTxpe8aFk1ywOS9%%}ofko$d6aaAG2`l)9Nz7G)<}GU%Qv1@-25 zavqJ+6i)gJ0=kwJ)gIYfHbv)0862n;nun5~JaxTpE*hcv)88l=30w5=GpiP4I zIJJyb9|C2y@ul(P=G3*>xht3O4e;ri^4!@^FHYY?6kFs(WkH*u$JX?WVK~typ=o?1 z44c(@M@aHZ+4!Ibpmy?b({|6sAmXE3{&h~hGzD4IGY8s2zeQu)LeXa*3U;RL)ZR(3 z+&?}sr;V>-B@hl~NvK5xBOM_>+ILdOcFZq+U-iS!Vimm|9RxfnZI%{;>@7lok;8S zD(x8JN&OSInS8F=(8(5G%NI?wQ|7RT+lcD@kRvb})F%sbaT+>b(#}RYqmt6SOfFh^Dcn5!?_&@+7 z?>rFY?to+uAUqQ2&+e)eEe8iMf{~u0dECMtkuip2%B}WLn1|XCZjj}rPxEuo&yGx= zGPS`KN8BxTW+BkvUVL^tI5jp`HKIe4@x-5I3sb$>ce~4pOQkknr}-R3A-L?Bi_oc# z%QOjzgXe2gNZM`vG|^d{=~~A8*{-eB1dd(<&3fC&X3X(roc0%o<)+G^1lIM&pV^dE znX`Z-26sMfS-YlRDZx~kIWtvY^kIMOWcEoqi?rZwio|mEnQ&%Jdx%n?FZe1BCJ+5E zX|TL-(0QWCya+K{oa)uE>jhdpORG%8`*!ma3o9JqmGRM9pboh&4nf{=YKLTf7E=mW zNBxNSi!-7r@$yc3?`e%XTo=Ia3q&&w>wx`+2EISw?^Uf z({UJNc++)G;E~|tBHEX(LF5}hI8_}oq+g0MF|=_In|8J;U)oGF200YT>6bxyB?;$^ zF5CLhbwS)wn{J>|*kYC<0Hh`@86ZSwFgAWJGqfSon=_S09oxuMWM7dAj|z-bC_?b9 zWI*;ZSNUa%#0hP8PetpcF59)jHwj*xLC9EKn=D>0(G=4fQJ=InyYiGF?!; zQFNR_wZ_hrm<5e0x{l8tV%dOSQKKL0DStDHqaw*H+^CLhl%KO&G0U6GioT%H#}sYQ zTy>mNkd+*N$?u;3zwEtxe^f`VF8nw76f2I|Z4%mGAU6j{2$+n|K;U3A*>gxv<4Xe` zeA{k2gctbk@AEv8>au!uyA5Q{p8XrY`GqRFXs6e_b(yqJP>Iq0kV{u< zlALFJU8<>WmJBv1UYgh_0Aml+CGn5Sg?)@cd{QL-HJNhS;r{swO6*S&r?+gvn`XYX zb=6|tzjYYy=Da@+3kk{kLL9NJ3M*mu?Jt(u%75Ov|M1?*8lUx!+hW(o?E4nx&LpF` zUxvHb@E`{vP8sVkF`~KV*VNEW6t^j)4trxxzvt4+kk)U^#jozlrVPxnjWV!pF7>k} ziB~FkTR=z~o_nfhf#F|UwD9>L3Z}{rUhXvcA$G;0_>{fS6cyWtUNQIzXPPmNn~gf|37>^(Ysr6hbv}1cABjiV>LaA=C^wDjyyko-lA@;KBfMN27mKwFniRx$tZ$ zOUw%wzB%tVt1=8s-TOpqGjJ4XQ2=_N%N$dp!HKrm= zxsjW;qYC(-$+R58J-gH4_<)pRAKk;;nl$+j_7J;TnIte4ul1xC6y*1!Rp18I#5e22 zV!Y~tq}3=@4!9up_?*T?GSJYv&*?uUH!f|6}s&8&u{oQz}M ze{#6g#At!)@;Z98p2c%NTZFL>aJJ#_+?DGNF267V+hJa5A4aWMXlZzp%3=^4q1N*n zOiRo|1?Bnq!R|IsJqw28-muEN*1iHui|8i5?Bs{<`{*^njOOW@{&h%Z!RF3p;bC?^26zu z!o&745b_E0HvA~;DN|q!Eu3Mf$|5^uQ5Kmt)k4y6f!3XUr2pL64%bO7C^|{PcL77h zNV51QDV>X4y^}uDgPO&Y;R`ku?kj;3pL#7*3<7OBh|y14M6Dt8R*eJLS&X?PHw$#w zs|r%Mv4f)pZ&4|%E+k3O=&l>bEBo7dllLjDvRG|z_I^V)Dnv&a*b@<6LksGr^T~Er z9yDmbU2G58FJ2(mjFK_zh^(;&p!^)-g47|1+y)223E>wJMWaW6^q1JgrOL27FO=?=q(fYUIYAry4OG+nZX8AI5uU zmw<$w!nAF7bGQJdT`0|TV%rdflG(ird$I8EC%+>dd*n*ImlxX?gDfHRDm6a{6dpYL zaZ~_?Pykgi1#s^0&PP^0Pyr86KqCpyaY~Ow0wQ>`)h?u|bjFp1X}t}egCLr=v<(0& z6`>`0`s7MJqG+2e!v%*0^!i?Gw#fuN{y~zMNu5=NJYzlBV?1w}C?-icF^txsp)0_r zop1n5ttC^T)$(-4JOU+cy?|Gg_iMNMh~S_H*^NFBZ-~Jy9z+RsJKG+w)m!F=ba)^j zI~wxvP)d7*E?phq(q3*HSr=g@-QI#f;9z@y)M`F4k--3j^@|s5?)arSkf915Y>W0C z;7wh+5v8(_Kn8l_90Ouk3E;RjMPVjlOssV(5Ux>&fW%2&-FsoEHFaDGo`lIqyO5)%0_kHv|9uA`2zA{>iE;3wn1QC zi3#7Vs8qtPbi9Far@8CjT)hJpIfD1<7Bg21`a}Zcku%i?+3g`muB*c@4uwtiBz8_y50TK`PajZqw|-}@8JUT7s$nfpW7R+@n59W zJm$onkE`Q{yCZm)fLRL&fGj2eztoudJ)u&%NXIFByLV!=>wMNR3ossyG@%! z;%t$uCR1~a;XpGrn&u0Z4f8Z?%aN19GWCh{;??RM`fTJzY-3SNHiy=n3&w@UVehG1 z@K@s1!T*&Ub0EM$d@Mq`LosS&Ig5sW;dgT#1|^A7eaKh`oLBNAo_yF_yA;dX%r!~3 z`Iwe#BVRUpV8DKKoN(msE>6aYx)j}Kl#QAB9{rO%sn z9AEV4`GWvpxM?3YL+;`G&p(|rwr0YG_s6-VGo8}R#5>@))qkEs353#!vAQfxH>yEj zrCh=hfY~`X$#m3d8RoTX=xB3DGC&=3jk^GNAiCOxvepj1wR#|aIco0_Rk9?Je|gTP zC`7wc{^-Bdj>eBm-qQ%i#t#q-PKqkgAbuL!@xy^9g2%VrNqcJd8H~+;+OVK@JTDT6 zScd)Y;oSe0OAY_8)LjxGt*RiSJZ1AE?242m(~Mc`sIQDwS`@LBp;UxpN2$vgzBQpX zeSmo<72m=IA@oI@nm$&C@haBs@gwticsZ=SICuq807+3oivVo82=mf;$fQ+kosJF2 zMLac|Edj0_AiSI8X<+$mOJ|APW^#c@z-{azO|N-IT6*>Z+SFwBwumwH`xtJfTEK{+b&k78kb1Zd36ZU1d=~JH}bmAfdicfYg8%olfc@NL^a^b^8MT|HXwq z4&@;88KATs?Z4iG)Z+uj5hgSa`tEV{X&Hk@y*Po&g9W^?P5pnsIs;U~_^s@drQg6* z{7wheesYD^Phs~doG7NXV|jSYwsB6eg7x_K5UfMzY5;+ygggrflv2Lr(PDhUu(E)9 zj%rVgiS$N8Um7%~B)<8XY!Al5c-2*WdvmOY+=k&Jt?L~mK`bO=blH>2VF$Ew%Em{` zKu)&INA`e|n<s5dcb@MD@Fz~ois&=xa7aNi3N}(Aay)O4DT+$VTu1r@Wx6R zbo{S#>~hwVE)Jgwz?u3g=fLn|<4Ar#4r4XoG9a8gw4! z7jcWmwQoWY)FsZ$Sr>{(u|go_a56Fz!iyG}P?Bm-Kehyk%jvk)w=0tvv-^{}rs9Gh z1K9_h^}F>M&P?fxJl%)8&z6_r1+|R})|vDszGCz60VlKw0%0szVRJ;lPOI1Gc(HsAA4vBE_kAQ9&NLVL=SascBU zHa9v2@NDVnuk(Mq^=P0=kdQ3!$^ZTCw=XU{#R`26KPg=M@&`6i%g9O3a2o*XidnF} zCB3)(a)=NYsC_`=M)TCxvS^7f_M4~R48!Ncqo>Wn_V5s!7(u{3t!t@9CpfS?k&L)$ zIf(!31VO=y6~=iQeXv4=fyc$ho`*4Jyf=Rf>}d9YF1xLh_%vSeLtRlAOQ_4`cM6F# zI3yr{Yva)cG^a3*ZmLj!t`=e^hj&IH$@3$qcV3xtf|MvwppZxy%S|E;Li??pL3A z3%3#-Sui#)ODsuP;t{UZy~o?zPto9%ZP*6(hKPZc0D6^o4w{k?7d-)3 zWBT}VZhCq+tBaitJa3jXZ9qi;8NC5rapq`X#IlVhVS_xeYbueXk9SCY3LT>O2piK0 zPw2qUrP2HR=M&m_W#6K|)XpBJDOa_uTw2s#gcnvo^Bo{dT^BB<(@Cbv#*Iq@!bKcOGJ3}N3+@12B zH4pZI5LoJ|d^oaL?8X(fC_>fo1$v}F)3{K1a`m}`sI7OxaLK05UoA5Z1~ z*n^81Chd13Yz2K(BSc3XG|=4Q)t&n=MEy>eFvcbyVmnB=daIFRkXysBYk9|XCNTFN z7qcO%VQ3DoyiXz8nwT!i4CmYcQm?t-xMoN^b! zq)^_^a0M^|{|epTl+SykXMP#aYPe+H9z9seRc7hSTm`^_Dn!;i`Bs5 zi;I`69bzO^>Y62%Mli$2LfTzm48ZOk{LU1Qur}x%=F&e#myS1{kNTSje=PpPvI!6a zWw(=S8YW@Tav_{Go2y@c?bGw;PRG^7B}#raWhyxRPyVwEIEkG#^(yZ}6e-u>u_ zs19qh%{+t@8k-?QWmg?n7qVMHm?2Fmv5JuKEFC1IQTz^d2tKZU#W@64GobvctHdbtu*vsgy60E$>$630MbMqW zMCYCsuc8=y7A(l&T+c-*FCe?L_aXmHdQZIC=gCBFLSz99c>y;i<1PyQqy4u6rLh<% zAPN#cl&xdAM<6){!*rWNq9%d*y z-Y>y2mBEe2B9cTRg@0VM*&-OR9_f$!I1b4h$+>gcj%FI3d!3a_hSpAykzu1k2eMw4^%yn}OiUYz@FQ-M;8jdr)FP9I%D;po4*dL_cnyKphGjxE9&+ zt(zkO-eU1dYC;ut>&?46E4!i{-xqnzpVvvuBKzvPItX-UkpgSIzGtkGrz2(oeV96B z5UAJk;GxZC#?f7X;|KW(&Vr++=_&gm8!HI)Tul-s#Zk$p^G-K^gvNgz)Ip4KLV{JA zw|?FR3XbYU>kg;Wp!VpXLDmO@jL1V&qj{j02)z z4Q~j0%UO4g)^F3r$Vbac8ful;n+q@_(j}0e?mhVN*1feSJnq@r-EpJJ05SlqQ>b8Y z*%F03Vu5yf^9ZR>^X3BL1u{APPP1ti=5t8Js*uO2otB$p8Ry~0N14yUMfy2F42)ZR zM~<$G=nwDP<_!y#0eD0fx2h;JAwq-*PZ*CF3ij&zV6{V}f@v2LfKimQm&$7@;Vcyb zIELX)3kD{2Xb(qe$JBP6LFnX_12Ru6@KvUw~cXuaYNZ;9hf9(x#|I1?Y$kEMi9o z(+IM$3Q{X^JDz2lM<+otpbZ@0@=|jQ7S+T1uz{L^a19H8>4Ecu{zCXr@0X$6F`ihd z>-#sYv>$nzZ-6OiIFLj6R|uuX(Ft@&xXO}gkB+x-+$#z(!K3o?{46o&g~cx}d`4H# z)RWc38~Lli;Gg9(V8DZ8F~Ybg*o(or6Vw%iuFXG}ox`0(I10p#)bGd@4fT%eEIYAM z)y3SMytj7o-|?nwz=3?N*XTL0%Lpx;z1S=QuuBL!ZSaBzx)1Gj3rtZA?QDv zMYy5_6@lCN>fo=mWYU@mJtM6RE$0EQ1i?`lh$k&23rzRNv}hu9iBU`3O<*cv5l*ca z#q_*7+&h6HAY96l#m^P*A0I~`(;;5S2}}#osdN82zm2#f+r4zFq_==BjY~Mem-znx z4UVLPp^R@^pw)q5K0N#xJTYx`&h>4Hv@k&>qPxMEstIgj3}bU05=CU{Poj`cd<*I4 zO?T(-C|~GX9>u$)QMMKnEI2r54Qk!dbu`BZyZ~V|!b$EXv!Z*77;b0xU$6b|d$HvC9CAnr*pdP0r`)IfS_p84B4#0Z#OA>LZz z5(R+ScVO2myU#o3a3q&Z3HG-^zKd`}D#wvr}i11Yi(!zAfvmhHLhnlEw+{J+#N zexk2c*s&UJZH#|Fmg?kXbuq3Sq_-h%5WSW7#n@@ zSrMG)Lek+*ncIrh=^!U3tXHMGM%)?>j7yBgDwkt9k73&q=1; zQgMbFsC;N~;N8FJr`dr2 z`!w+JuLxEet4TpZ{pCfP~GiiOj z!U+fgECq}49#8WH3eCbWs@<0Bc^-K-vj;gDzJg@9zsU79`5FO3F*YBnj}9d5zi?@= z%MGGd9Wti+vo&3!Z9>BUx+3d(0P=$lis!Ln1|ZoDrXqL9AktLneX&Z>L)oRx*)H}$ ztxzZ+G}piY&xKc z&4$CW{a<5qY)0QfacUX~P;krA02qb<4gxU5D>vtu&t#U*i_n@Dq%(NJ=4Jq=>38ow zx&A#uOF#LD}w=O0jeQszVfg41Nb8-!budMF zW!NX^N&b0Lo`2aJiYcEp>%-A8EhlOK=JZ!`iypm3EWjS?@t>W2u?K|U9mm@>vn?*C z?o(}up3tFmnJ`u~Vg`}x54SO);-ybS4C*b$<>??sXlHQy-fDVH^*Cai1*J~tx*^q= zkA_N)w~4@ViN%OkL+ng85-9x9=T{@KK(7S04O(g8^SK8*HBpvhog&LYx2mbpm4O_wxy}C zlB{F;+eKTGPi%A2nN!);Z8?TC;0`4 zm`~jE8#{sas(GWQO6WtefnK`_RHG`rV_?4*6^;oRj@_`>(0RMSoTqNKb4e9lZqD9{$izyPG+IDNeijqNHO25sW8AooQ=%XF*bNnz5W}Qf3Q*{`*wWkA@=@p~bqHd5K z7nC$+i|{j%BsLf~`O+1%94{Hs1ZoeWDYo=zEY1BSEULF5)ADS>RvrslTmXEJtW+x= zxLukbHRrF)3&n&Rn2rN5OkF4dL~ZczHO(vX$XlQ-mjE+TY=I<{g~Itaj|p|A7dX%C zM9e#xU&$L`4USOwy`4QQZn0{Q>qV+Kg#E%I`Bc+2U{4Dd?3zjCXl7yT_bCsijhCq9 z7xYgrF~s2T37~=sL={Xc7w!09GK@c1BizVV$lpCccikGa2vT_O$7kBPdC(RPG_o^; z^tf3H<0ZqA+ElC{vmVcnM!R6u2p1H0Y%9d2wJ+RmuPyRyoIbXq;Ozs9S?M*=I2J&r zj`NFGuH3~c0&0(NLoa19>D`)Q5o z+UaCx#1l#v)bM=;(+vs8)hj>B??KIh%@6G$YgI7{GyE}fMAnnsF|S_m*kDz=>h>0# zo^MfFvBo$^|B$e24YdX+lQD88F}(;%(zJ<*5Z_6&ash}s$NvP@K5JHJ#6_;4jVAg{ z%L4SOWX{at4NqSYqtd>;I6x{m9*l7B06EpjrECwRQ?kHLt&1*YnrKfFE}J1zetW{J z6>Y@ykK};Ow(4YGax)P;G>Kxa{fY;y`ueRkPP#(Jz7*Wyk*~lHl4dYXemzZM4Y^o; zW3O8t+bFZ)-Qnx)Ij zOW!UpebxMQe?5TaGW@K01eYATxMkSDuaKkQh-WD9?0Gc_R0u?LxHuUiwlNh-g7(TE z!>toChYc`LI-h_)T`4=Mp}2$CP#hYNUK9ZmI>B~PWfCCfOEU#y*7!F1SEMWMR!JAB z=TVo~t6{r`Jb`IqN`OGX`_2Dad+_rl$QYQwFuR@M?)K;g=jb9wCpRcX-$C`g!ASRL z;K`dgmYQ3hE7>6>>A8z@Q59cXGyCQ8($%?l7t6|SsXg31K`PDBd)CHuV6!}}^0m2l zzhM9z1I{s(DNBZs-5tEDw5UqSoTf{K)e)u%qK+Ip;>#o2{yFqstc&I)DX z!Nc{{2S4XK4&iC)G;rPirU>_YkOsg6LH0QGM+Qh!Z-!gEWWKS$FmO!bAa{V)teKk# zDyQ8xwFYYqc`GgpJJ?5yN6jAHs5q^X%|o~jP{9H)W+cawjmy2Q5pfk= zyC!Z`fnF{?DWuGTY4z28y;!tw^o*EV<<$!Ui$QUV{cav<^7+Sxm$m`wR(^GaC3Kc<=&kN}ggjkOoN<(Sivj+5L()~RpNq?p50G}-uY!2}eWqT% z(8~%ML@4=n0N~^BANd_}8vO#JSJJjO1u@iraRZE(Zh!Gd<~lk80r+DqGCu0nWMz5s z>QF`QH|_n795Q|U0+Z4H*Y&R7pW*EnsoA%}JA2Rn-c}P3?~AuF2l(_BGEeZ2=51=W z3x=+DXNI=T`Uye7@UL81ULwQC+odH8?F6=&FTaN9yN~^L#J5-cEh;8x--0Dau!(O9 zAG=vF4(t})&|W(mv|V`YdN(_66CyrqCX;E}&y8txlk037dbIGbyQ9Z?FFo61xpr8o z_z734OpJn`H(t;EiO!WNHZZ+r-4rS8lKH&$8SekZfgHtqdq3GY%IgtR6N=-;%T0lhM~ z?%=X9~B2pW0ja zn8)|K@u_HfUzpIrXp3hD2RE2UW^?1{#+8JV4;aB>do-4+I)hSS{wvi?GtugVq8z2R;m#n*VBoDiIYl})P(&1C8yp%WR% zmYYud=wq&jqYaw>Ej|o71#Tdxb0}L_WRlKu0PTJPO$E|zn1VY-w>Ygw|bb^Xqs;sXH6=xwp(*PvXk{9{$y^==b?i) zlODK(oF8dVOU+~*APK+GqC2k4K?ZzELvo(d}WKRs-aA0 zm0W1@t{i>jovv;5jV-smI|F!d{4o1Qsl@YVu=}D;2Tw=4AWkyt7L^yV2f-2~iMVg= zX?#4X6kz2JwI4x$dg>lf)&;g%uSNbrb)JFD@;KJ!w*ti%DPYoXA|dcnzmJAX0zDUM z$Or2@t(6h&X4OY)&l%`c@t&+1%hrQKg?;KgB+x)e@Y?;9Se0LWePc@FIL;l}TCk;) zyt!4oak?=3H{3;nQ*Z_d4c)hlovP#aBm$qzdC-Mxl-NxQ1+f^kn4cwis`y~+ie02x z+zX{T{hN*xqw*F?S}B`2K;Lu80pS306T*zQ!#9C>Y~mSyi^f$cp-FhM|HS;Gm0Vt% zZXsTL$eJjceNQw_MHr{vspo@7%={#o&xXq{Mi}1&VOk z05d5dAR8z*bMJ>Pg?=!)vxh`$&|Q%pH*bk4(#~#b3=0o!2AUyhF+cc;Ff*4ozr4Wt zHmp`es7>N4Fh2*=LL3uVVDFH1)!S4LiGnZ?*sVJw0}|3W(Bb^FaP@ky`twh6(JQtg z`%Fi${55zjk*cXwQ!(Ko6fqf($#%g6>0>R{9xSlpHbg!pE5wbuc$eQe5&3u9oJHsG zHrO4|=XpSHnAjPZ`Ut1@-i$2}dLkqM@(x9t^?qFvLV|ZhCU_bUz`^#x0EyaRvO%ZM z0)}X#8+6oi3J8CLlG0{5t3IpbIEw*mvNSgfL`gkw3v^@0=VLP6dz_zl%Xrq+G%?R) z3VOFydb?))Bbb4M$+*~NRDfIxX|3RjBRV3`t6LEOGwcb~@*+LSx~d!fpQ zu!SELq5*7p23PX5FHEhOcaHnb&E<)L@J9&x_7&!!m~}&U;RoCbtQh zAz^bJG;i&apNNCGN5|>%fz_KfL70NTb~2*Tw5)#?8BLqYK%v6$F<6k{4U$6X+LCuq zQz&p<>zD<`m}9#yx-CRsQ*1ZIPCcQWbj}_!bGRSW`#gOYpU6B&i`j(Ft(i;37*O7Rh7#y~|*!W#TOJge7 zDO3i~zZ|(V9igXFb+i6yo)As*5SI*y36tKiQn91k`((+8q7GJ6XxE6(tOsUhKD|io zqw?$_p-IYkokTXWd;7sDsW!SbKVIO0a9e%=e&SR5g#L2o0QR1~Q0mT=up~FagEkcj zOv*uc-ioAmo}V1u$AVC?Qw%F?1a`Gt#WP8G0$MZEV2WH5v4xq)XRx<%2#$1{d&^20 ze}?Pn#E=cu)D4`#vG~!J)0Dq-f8FH2fBRq`-pyp@B7lGmk_8yOZra2Ox64qSKj+3`=5hc6Y`d@E@{EtXS7zq`EZ_z5^3zK+ z-B$AtT!l*KyxgTLq=1g(1Q$gzg9J3a`q>~lAK@~jefMq)HsW`5ajQvHP*h+xtx-|| zkWz~K^x$gio{wo4jQUtY28OK{lWy(JbqK|=Dtr!fI+mqpD+lfnCr{p#rVa72iA|1U z3G+Jd_zLdA#bkV@`RX#fOZA^C*YNA=S6?<4n_ma}gZ+a8(hv?5UgHu%kV^c-Y5)@w z@lR;u@>mmla9V%iZRq!@jeOmP;?-~n?^Hp-pQkj?uD!iMpL`Ahzb4mhSECb{*ONb3 z*U;N_%wH@9YtCb1^g?B3!h);4*Hn*{h z&G0$A6`3^T56vU?y+8hd_bR3Xhtu|+7}0AD(cU7tmG(j0Hm~lu05_Fp1h>g;?9$0p z&KjFT-feW zUwjb@0y+4#K2gJqKAGS7%@3ZD8y&tVtxrohlSY>WiT5sA2*nWaKYtE)6vI=qU|YRE zJ;T^8HuCUcpoS@ngw3PYpY0wT@Jdfxc9-zOf#QA)iw~BsHo?M4C^2VZ2G{cXOyMR+ zbTIEv5YFH+y?>0TeJnb3z~S&x3;)F|gAu`i5 zu^=zxvDn-1h9ejdk&l-FN$KPUuB1H}OWis@B|atui&KNT?=eOqdoNLZOLFWe;v%xm zD%zFnQ+%#mL#v07lJ7DAzFV6sbObpxDBW6*C@WuhvtqyUAxMlOSY4XTS;rgTDQ`u{LNR_TE#1H ztA{r1RiMUN7-v0~!28B(5YHBZ;XZ)&5V8iJv}IKB6_bb|%S;^}fFC`?;)6pZf>JZs zgi&klzi*VpKP@gIu%jRa*`^T_0c!D|PA>iw^ukBIg20=V-w2I`r=~gNW{giZnNMds zVFI7Tcj9}sqN;~_c}4kIIZu?YnyelswLcs0iS}n@KDqpC+$YLcAXg7#@M~Vl)!acJ zu40ToieMJg{)1{#;RzE&-$X@C-4Lfw>n=wJHSUvHa$k)t(b)e}zxNnueddwgmX7Zq z$D=znjg4Mhn<5WIkkVE@&8a&z;ME|Wl$Np?%&yTwUcRmyo7OlV-{s&P4=UWgmRgfe zr8r87wRlmNfUHp#3V|tSqEX4I2e?*e5bb+1D+rSLa8y8;5}jT@G2H5=7k(##L$Zsi zF578K{JeRjteP-p&_RbQ0{Tw97GU-}I8vnT7IKxD8gY=s7z_n06Oox?!!`t<#aiTA zY*vs1K4T8afYF$Z0uaO72W3AVqgMY{rpy*bxIAMW*wU4UUxJx?>r- zkXet`TJp;BGE17Q3XwdON8cJkX?Ys2+nQYHy19i`VzS(FESHWM9hFlG>qX~UAi(33 z>lPD)7seha+9Z>jIt7L(o8ozx==|3vR`r_#LKq37U1TloBRPNh!omLMY8ipiaYaL_ z+^4wZ6H3azUW%^mP1;QE{1`c-G(Jy}MVG+P#&kIbG-ppc;MZC(+cYAAX>VoTX~cW- zUJ5uhAm1*O{pVQ3NQZ(e|2B5P50GdSM@}#VT0XjGJI|T91S$lzh*Bo9H@55EhP@DW zLEdolDs{w2c&QrNXpuV`{h(C5O>Uoe0x0Yl8kj#MJJWF(_{ z1H$Jn?7A&{S+VOldEY#FzBu}?T@(maD-**s{VH^$3G)L^AZh3k^HV*&{b+^BweH+n zzxCs-wUws=m8M>VX2KF@wDJ@k|K-8j`qPU@|MlbG=Uewzo2hhY!aIJw|Qw zbm!57hyN{SY0RZv>*P1h?J|xgMz7!shviAjmqd|+eOOR&c+QwO_Xe4L+Kc5rdFs=8 z@1A;o?w-8>3jWMnr;?l&_;hyR zdrRUBV?5)`{6bBclf3badWWhA=buZ7<)$#16n$6dCPaPw2$X1`{Hdh4dbe5m&(*c{ zwN9e^sQl7UHcr8}nbpQvh;P{3rjWSJb(~3Ly!RTLD8&7(mrt9M;~nKrvjE(FKVC~B z;_hV>n+Vu;x<8Ly`(SJI+X54AEnm8{J^X!95HBKL_!2%{f)gsTvtIgg@#{;& z{Y!$luO+zaF_6+$FJ*mx&IPimJ`e9<4mQwfg7-NXKex#z4*ysNgrQSC5l=NrmX1FxJ)WzubDXwz7_kWPlBi zmZ`d)kScBE58N39v)FUXfIxLd`4L>Lu{+l+u7|m_a+9U`BoN8X6j|R60fJTZ=}2^$ z_Fv@0;|9-v+8C9yM6Z58bUa)NQF9+zRr#ueE8@m*2$=NsYiS~~>bZd|e6q8q@}w72 z$-9Z%26(PeWvT))EstBaq7za# zQm0c`EHzZvBPqlNDNbl`u8?t?`Gr@94Xlo?7ihsPlcylw7}p4+up{u9}QiUe#$CmEQIUr{dpPKGbt z{f0}TVG~|t*aTwjkb$lI_ZFU3oQSv57ocCsDdn$Tq)HGMH}Tc&@#@l|!4GPW8G1h^ ze7qq6cFnTM4}yub zJ#&Ei2<=&j2+;Uq=aBggKM=l;i9e^mvdLNDE7o@h7s#)oT>S0e2Z?8W);z?9!o!4G zw!y6jxLuE%i^P*uzGmgUwUv7-x7Q(_+mbC(PO0ty`JCa5agn+0BTaDc&Gsgne#i5_UPjUT3v|S2!ZeyO`RK-V`&*5PEDAas z3<@|f#yMU1kt8k7WvgPCD}QY5p140c+&@?o91iC`8jvAlieOg_aHzJ1*c2d4jXn&* z7YNbJ*Q$~6;278zlL3XJWw@_=MCdW?TgW87vmXaw4=hVJ2}8s}OD%<3>mSg>`p8I_ zCUWZ%sHkGO26ZH690Sonn1`V)1d0&BuYC%TJ7{~m&k9BWiLa;Q(-jdez{2eI5(jnp zt|msdj|(4Eq1i$J6-MoHcWQU6f1lO7Ra^`qG}ZZFSP-up@;{Clw{+FS21#*yYvX7N zZXC9j3c=(Pl#)NU{DnNZyn+1TW_KqJ{uFp|{ra<=KN3zR;jsm)azpvr?(>YJZ|z{$ zH5a9i1^F75QftohdEyvpPaZ~VvHv+_Az-Hy#m4}?H5Y#(-Ao*i&vrW5egBzg4d$Of zSZ>aWjjBV$veBGw&MGA%#LX1;D;zE2<|AI?qtGgfP9ASnIjzzN1(C@wK5zE6zeL6* zT*3hn19o48+#u5HYx7z?=ZQC>%@n(XkUUW z@0e5q8z=l=VL1&^Gl0ZJaRnqE9UYD@DX(2@fGLe9Z}P^5B73Vxhwa(rdLaV3+oi-( z6K>%@X^8P&ieWwJ8Ghiejr$}e+7<{)7Dxn0=~7EztmAl*RMxUW;&hRfquzk0laj3? zxHOEM?!_TMyDX=+jZ}71dj(KH!k#4iBBjEk9e9{jV~fi0{JRLWIFUsH?>xCrdQmdy zFvhDevJmhzq%t1eAyKrutW}QSH108w%uExCo6cvb+TM|NCfWx4TM1GZ@ z;wc1M*LAw6FkP1@*0zsq1{~K-^bm=78m`+le9YKWQ+jtvt9GUM6ukEPxYiA|Y>&3t zc^}lrDL5{TMbb3f$U9*wMq3+@c;ntz%mrdxyAo{GOvMl8L80#ZJUn`iWUG1ry#}RO z?4ed!UM+F%4o%iwj*>QDX?^#Hx`vN(Ff}G5HY20yqVU9=xRz?qDL?@r%dw4}86@tN znh6~_SQcz|7*)lgGjJJ-PZNoSjtd`)jhz- z`~yj_*AAYw<*fc^EkWvXoMG(1rt!~IlVPRsyHU3f&^6OFo10@E0zJ?p41kxrAy^SE z$P`0yfi4s?*kqsyZH!<(#fBph(NE*(hfEa-gUiG1I(o$6#*F$nE+-h*$9ZnzZg4WK zNL?RO#}Od?QvNkllyYj8eLvloV`FH4NCmj>6N6xgun=5?%a3s8`Wg>Nu|t*(FkRpa zvJ=F$fuGO?S|?;&doUF67>buT$g){vi(5-lu1~e3Cr6^>`DBBV%(>^E~D(%cUfmBxE7YQ$9i_IJ?xz(^M};;*@xVsjjTtm|*7<>vN-`}bGZzq2e$xSy7eeVU{v zz0%Z~rr1V_ouNWR5)nVx0-6Ev{b|b9&{`>zH-~a#P|PV=VcHl>%E@f;j`>N*s931D zN5kg`oIuE{3^{CJ{?#FlMN>O3z(ID0N4cR+{;J+?7TL)SAd_`?ghT}oGX!f8V?(pVTJi=WP ztuzm?Q625zCKsMvl(1GEplFBTWxPMb-7zhbGEQly69kQG@64J&(Zg1Bnnxg7b65l9 z>leW}p2IW-du#HhHDDkCVy8J1MBRv}0HhEAE80iA`Hwbg?M{9GWjERJ zs=xH5y!Q_WNi3}zlef&0*eR~2s|`sXbip`A>@*F`kY9od(ceo%1h~y`1ZL>YJ7K|d zVhd6tA%m`v{^1794U5A+aH$ZShrlyaO|*4Y>n0zR=@t1ZkFx86j)3}QoC4Qxb(TB+ zDjmmme5y`X$G`JfvwrJ9#)tGV8ICOrkFAO^B&XtmJu?9TVTQ&VV`i!jM5444-05c9 z2|`bY_+kJ|6ko6}dhGMr6kvnY72htU$P0uOjl7+84j1@rp0-(oqo5s6<`ay+6JC~+LI&>6th2a`2`8Dk3oMw{#j2ZH zh&6BRH=E7E=4;#_=|>^`<|W>|+`(>Lz1_pxJ?t;l+kye7)5tc^nrD%kowLStXltg= zTPyIRHCJfYC@$JnQx|#p>%}JB^g1?HmFgHT6N-{eIZvuDk!?4pLI9wW7Xprd%QpX0 zWt&N|L~LJNc}_n~)8*pg?@Gs(pK+8f{XG5WZL`J|T>G$O-x&MV(NeLw`OU*`o3EPt zKc1nb1bjK7v>m6fT|*;S@qYUFI8YzsDWFYiGsLfiGX214uQh)yhiiA-;&8Y0$5QXt zzUe60>5TZz<&Kgen-u`OZNB}gqhzN8A+G8hhtt__(Il|cSu(`EqUhVEb3_sWi(>dW zrDT!}t;V#Hm7q8YPWC<<<_j@0pdIf$sLK{W{%^b&)g>BjQE;(&-mvYC9ew%DS6^QH zS~nHWQt@R`^Xn_$u*xje_HwnaSiVEtBzWDT799B@Y{J}r>-PhsKtd9EI6fXTizX91 zAW!6uBCRX&0~LM#+La*|@tR^F2DMBE{X*NH_iKn5)@?xczNO_JO31>sSHO!#!hlGsE-I|RWkBvn^X}g7HpOM{^Yqma)%rq2B;SU$)XsNEGqq* zq!gs%!~&z0tbY^651d*JJ@@vUySc7CzP~^PVE|XI=Quq70)puF@DG2yU{0_*`-V_n zAH&QvdmD?2zFp%1IOJ^W-@X6_SvknM!;z{Xbj9)p`RDu&`jbOA_?e}*UtN_DVuc5J#Ir_Hx7nV z0&U{D)A$5#c0gu9{lKi%GQ`t~LhXvepp6w-!}z|Kz@(9}H9^`jd4}X`M;oL}WNjX0ry+pJ!rC=QTLkIQDoC?bI@K;~FMifkw2} z^J$X9Mq@YJS{D}^b8}`i>h8f2I5mWf;WO-a$Ym^(7U$5)=I-wlXIFM~L}*J`oT=2O zS#b)2>_Kr@LkD~Ko%>Ry=h-gOFVK12w>NJHD@N2bkx1GpWUd=r3cAH@FKdQSG-~f@ z>{~P&o>0l2$**wr!)Uk<65PR+B%ojiED!xjINld$Yvs+q4sY%#uo5F^<8u6n%OkF9aeEc2AxI=Ww-1$9Zu)6MY$N4UzKbARVM(z&K@tT;>gmijW$gGP0%7^od{s zsO^LO-Z4G+url7~5Uz!tTlel2CyynM`>4lpen2Q0bJF}3blLB34nbo$p2t-R2n)M$ z9s6`TmHk;pV)BF(W3Sci+XPN*SyxL;hns46+?;&vvN$a?^oq8gVNZI$em7Y4J-Y>c z4F3oUmQ$5@m91wI&HQ_=)U$ES`UOc2(SBRhhhTkr8_aS1~`KpQsGhDE9 z{~f!ry~PK2j$Z@hpAT@dE@r?nE@&i3T(mvBKrez_*@b!R54RBz&B9s9h3T6P`URu=${`)G)xOntP;K;ShPSv_E2BVLREix zXM0)idmx0;sbUO26?CdH9075=uLHsd^d@v@1d8p;UKCfLC=QCKayBN?YYhjk4o42N zEkbJ$QbW~0lV*)l#}>_{cXWMW=cdSzDMtU#cu6y465hjfyzz3lkKft{FWD50E=i6y zg5tWjuMHinl&3UAW$d^Wa!~!?2w7102L!d9gAtMSb&L5r^$GvoM$a|1S91Y>9F1hL zxhuy8s{b58&YlhpzSSTyh>Vb}OgH1CtST^I{Dg(Pd8Am?=SRcg{)GyCJM=z&f2f_N zJ|47x&(OXeGBlwES5x>w5UYh|;bdRlG>Wo_HB6ygJC#$VA}tV0qRtB2T4&7fJ*jQe`E|J_kKgt8TnnsW(GmXDB7gu6XV@18gYd*S3 z-lo~`W6jwVI_oJ`AQ-9Esdu=y0S;bNH$p+~0Vh{Z3k@uOlILBd|yQu?Z9rec34taQ@|r)~5-QkM2;O=xLI z7opO_Kt~Zw!jkaL&f0|2^Jad%^eYN{I) zvmc-P)Qun0a-Y}n?m)umjb?8Lmv`{@0-_JG1DmnxXt~{}bxJd)!e8xLDWYM<% z=S@Na#mndbgLN3IX9*gtE8}GH8g4Drsc!v+$8GM4*!u82?y;!M9lX>o>b2n1Sq>0wOX_SmRULq*d)7f-{GZNathIreF5aU} zGc@Fub%^4PW=;Kl8cwy*cn`cpBwz>AG3^@FAQg-;F^C&nr})62VT;auhqD%)>mckA zYD|5-lD#4=CqG+{nM62usk!NphN==k+u8P~zw=2FgPq~DNbv33_FN;*#)Je!*I<0U zc>QG6*pBQAXIwuepsHWb&V1Mh&e&{JYqh2UyFP!$7R#!wR<&K6u{qT#+rd(>m~|Bv8d;spV&_7n+w*FR6Sf4v zWlR*C1-C~)D7+~kK_|+n3t+4_kU%d`jt8K)8mup;gxd?0}89!i}f*)WEeU599 z{Nz?V-oOJ@i#m;Ar1MaZWSd)u)MUfxRilDTh13KiPshzw$8qBX2}VbV5jey=+1<@U zxvXRfu*SjL4J*(bH)xiIl@t)196y5+kl0q$P)~M8kG>XOaDZ(%Grks>8AlDwmIA?` z6LW~;Tg}qOv*94^cf!zroxtV^0PQUx`>bM3XB~!bk-#*m9qCh(TbP}F$Q7y`E5T)wEcEk1-V?=D#RQ8B#5p1^HM=&;jx~Fi0m)Q}4WP-NlV%%ggaKO&CZBz@JwO zwhxG1av!h*S(u~|cMNN*{fzC4#yfn5 zz`cjOwhW+TvR|IwfK|CHIu8SKJfR-qU^QHV>}8^Za^J+VsO!DqnjBlvKjS=<;mQKA z=^1nge)py__n@Ch0agsay~m7)7i-VVq4IsPHht+8E6zM7bTUU%8@TGLjiY_?3+b|u zufb~y`5GrTFLnSb>}&s^(f=xVt*oXL*=YsiKW7OggX>-D5Z31}VfRRLkpNHlaZp-w zgY`KFj1du`D;Tge5hv^++#t-sb6Co(;S;RDZyscyp#hVHoTnP^I>&X3TikV}pflTQ z^ZO#-WL{62W+B*SNp)#H!&M<6pbfqzry4KMhLSZt^5A8Qe9+RllFUKI<>LV1z+`T| z+Dj@ai=l|6wFpI|9)fes;-$A+wE><0R<5$*3RRAklEk@M4Xp_~#ZH{wMIIsY72nIa zHZ5=&tR$S+-jq-fuy=2~`FG}j_{Qk*T|!vJY)|XPy9VXU|MBeIHkSD_19flpuL=w2 zO-R99gY`;+<$@E3a4z6OE-{ltu!1C0F`KV&>~sqL9asATk$8g0?zwWD(e-#6Jg;dA zOf4s1d5_biI=mj9pvDdNFa$cY_bzo>huh+DpPntL~|iZgicz;2(o?b z-}G7aP7ODiAq~Km(W-AC5?z2_K*DD5%Oz#}GD++E=Ha82p9T-^-bDod;P$PD>yL5% zylihD-dbN@dGzxDm$t1u0$7=m1t*O5bO^`z!iD7W=U6qp11bwxd|I^~2vT$+%lMgN z*;(S7=HX;pX)&R}#7>_Cnl=J+PF$>X_%g6utZuMlU@|BL%9+zgo{6$>K_Du+L{jQ4 zQ_`eTCcT?fa&8`J=3AcBdf&PD@kQ?`;aU!`B=#1QQA@)mp|NE(fRVJMw{a~}Q}FC$ zU;bVBTFkvo=)cGCZ5c%0rT8q^D-h6aE)Q5+w&wXe z|0;wXr(mvCt{Kz3z_%-cK@JG&A6z%7fG2dbPOw^^J)_%1RU)lr7J^##KxOO@7)C$& zDAT(LZj#G9k~=a<5cbLn%W9(lF1ef)y&vThZ`ODOfv zj7)^ImZxWfEqKlIPW}o*g=_EfWh3ktN?2A*4lY^iizZ_^gF%a3oHV zDY4!(fs)CT$uvB0e4hv7r9IV^Uc+LBQ{4_nPnLdr(#*38`9|V80hBhTV75=LOf72z zh<2~0vR$LGoeLDG;$Yb)5PFNvRJG{zsyjaokF| zFd515P>8vdND*}|6wbT&Jyt3VK3>dF3PK0AmW+9qScWpLN9p5^8j~9xh^l7nd7K~A z)T3(Zmt`nSHma(o?~^vQsA|uuYd@nh4O&&rY~eyRJg5%-MuosbRViMk{sdsCECtBv zm5{2rxNP~6>Lz00B($?T<|4$lilvh25Mnn-u$}}>IM^9PGWy(f9&>-ek9uV&M#hlhBGDmW6iWq zlvMO$Q~p`BC!~~9o8?jlJ`xq;cZ`E*%7egDL0#zyXvXi7dh(-vOZ0&c{B3Wm*~6E3 z##h2;i-U||cNKT5pKQSooE8x+L*YmzFmYU?kg$Ho(YlTbacOl3CymS#uzwWS?JBZt z9;UAJvcNVjch_~sldn+aOo<3_Vh>jUUOtEb8ov{Y0uQ!gD8>MDA2yZNH>c6MchG1| zHYoMZ%H3O!@2xj+%amW?I=M*#MDpzb>cPExxSF{esQm3LKv}J(8>phm0Lq=9s{!NN zv?(L;DY+OX+mehKfFGJ{%Z%$hZXa%)93$?Kdv0_+NfP=dxL8$qt2881#d%Q+| zr>&!%LtKPTsa=A&0S-OjzfN|T;U|idzI!i_$VxzfeEx!~v9&6DwCl%PUW;vSaR(8i z{48T!Tus0)06S*>Q&^-Rrvl0hAMT0hx&@8dFbM)E^+Sj_hBdhtZj9Y4!RP}(%wrL4 zSPr&8&tT88g%$%L;|L^b+1sfuNySpA@oXP%qiK$EtF4)diHq6}6@ zrRjG-A%WsE1)|`ldj^ES+;?E96U{U#ch$<2M*mg1+xoVdPULao!FvrT)6%|Z+*H9I zw)fHKtHR9>zHUTa%`F%i5l*A))a?z?3Y#rkq0c2;@{Zur#ow-K7696qn1?HuD!|R3 z>3Hi!&_0v#v;8~}D=7f!TQH5|8fGvXHZWTUa6$cvzF#Ych*GeJ2&sf#%c1fTY zf9^eew2Fny?2e$0{>{HakazxzwNT>2v=bG&yEEL~<~Tx1Ra3?fp^gRCNc?Pb{q-T$ zh}>)xpoMx`vn9Se%b7$BKn(?LTw`-?O^dK!(lTHy2Z_a50*A+P%G+xdxlm=GXNCef zsxw%MD*xp0wJ_DI@Y_EV&4nS%AMZh?Z8@WG|SdI_i=pEChDYmmx<^l!Fuv1DlOssiX@$qvJ zYUD;MDJ}jkj68f7Ja0vbkD0j1lDRrR0-#`SNWHB96-b#I%~Kj*pEg^&8`zf?n;&mC zuZ|ehfCxW%{bt^Xv#f^hlDc~ge29TilV)L_ITzPbBpmilXM6?H{jRK7* zT2pSMS7M(+Kplt#Zr4X_gzMG&Y8LRL*8|0Klf=;)ZEOB+j9zS4E93xemXdF<7c(>x zE?~M%)xmM_ut9S$E)-Ohd|$q2pcVxzs}X3)i%}WKgYqVCgWCdp zc^P}J{p5`p{NETH<_rR{uy^VIE_}ay{)xLBfRG1q{@aDmaf+(CEl#U*Y`~dt z;ybcx?*{NKMr-A1Q9?2La-jP&xDqBb?h-a@1{gF(ZsU|VVcOcK5Z4M980%Ccv!UCB z7Qo)h*+J7i!dbLy-pDkS|I|tiQ)!ho@8fxJdUYr!C#-fKe`hR?%>Ki@ zRA&_rvsT&ktF4_J4=CCH*_GU{By+ z!~)qbWfBlK)4~i~yW3iiHy+S!1ab#BwjTIi^?~KJ0EvQa~Aad$%(AW=z=p)UnDz4K%{d5Xq#Xd#b1m!v&W~j(`3f5V} z-x-U$jFW1$usGB7|G%64xapSQuludHGYmW?Wybkn@k9ZtQ>~aa8Z1@N{!kfsD)i zM0(d2uW?M*6N?@95_@DOpi%P+ZkBimE*!17C1uYL_cAYE?_$2zq(i%wCvyH^-QM~AR}`p`AY<1^-cDlNO0M2Y}x zD;CgoGP*3A26!^Ul%1??Y&>Wo26fUGD}+P`HCD3O}*K zh{F@yHB=nH4Zz|d-yEH69s8y^Pt#EU=CdLEZopVusm1K==vPOyMDuL9>R$N~kO_X# zPQQfw2e{)2=F^)uuFJn7CHA<*fSYVZ$muLgrh*7P62Sl>8m_06m<>j;Pz1Z9gLFOE zZ;Cct_Ec8p9!xt#(IV1YWGhF>-(n2LF?^g(9%eq^mp`Am0S+z7v`jj=o0~#gbG;?L z4E@ZL!ez^ZE8B&w0`m^Mj-X^QZC_auQ+|#z!T#~`@?dh4P^#Snjb0%#8#3L$ByUOO zaU5o!o{X&n9D+r8Sl+oWAoU0o*oox{7>)E4a&PElnLpXNSBAjB5~dSaIS1%mm}p4~ zkeyeKjt-DLueX1odpWRK&mpHfl0)I#Y8!WIqK9ZTWE!{q%eqIGvtJYg)J2?9C_KA8 zaEvZ9;W9uS+6GeMPzPZo_%5Q{cWI3y>}YpG`RGt@duNCh3$721o{S3t2_x`CB|V|( z^cj-tP!Tihq?4-QaD2rCTHVSMI4Wudrd%~|Aqv?KrAAS#xvlhC)S`?!Vn+!DO6Jal zap?HA_3!8i@?a&mPlHc@;CjX;F8umg_s)yx1t#d{KS%j*bwc73ERU zmY$dX7+dOS#(6tt%mf0)3yT}sW1iI9>|~DOqjZ=ia1?78(a6&Uk1-x$jTb@yC68_% zVO@Mw9x=JeQ+dRvpj4}#u$d_}affb_%w%XS1l4qtVK@|z)89`+WX`61$YgXyE+DP| z+%mg|6cR?k1vwg1<_Qii{@Y?kt?gFLsH01UydCBvsA#2Qx0E}Ua<<{VkhEF;1&ji6 zO$LQDjjSpH{Cm-^r>u%Z7R!iy?@ZF>%<{%{{^(;3#jc4B8Mn8k!Lo-mye;v>3_EsR zV@x0O3Mj}u&?9-;f<4d=Lh?0G)mL5x1Q13^T>a>ok*T1-~aG zZ<{|9li%NlBNK8ltTyMdLB*6xhh{D|yhR2K9J0aDt1WKaVjjC@3z1a^d)N&jxn)?A zO!6UxI?^Hpf+un%Y>ja5dA5OUq1hv!`z3@5%t4R%hI0-mouvE8dxRnnL)j>F|s}F;M6bTfY`R=qM)1B|hD?}S7c)E}T$pesLWR%E=Jjh{`n+=eXMg_0=MJFV2ibRQWCl&sV57!%Of)8JO5nDs*SfXQx z*kcC}0H9FB+}t3lF~XUlC zm)4;X=mMkRe?%ZN49kfW8YUc=pj{;DVgumJ!&m z)>*VyvF*?pxW00OBJ;xjB<(XcxmD=GE}ENE!Sz8M@zsli3<2}E9-kZ`9W6guTmb#N z0?^DCtIkH=+bHd+_n6*OjaWz(;dF@sIyxa6r9^z_3_C8YH2$7Vr{+KUeT#AoQ}bgx zZT?i=xX9n>k}N*F-q_n!17)(zX&W$uW!+X7+fJoV<3PH(vcz3hGv~`xU2x&S@V1Yu zrm+%)rEoBSo{C^;?W0g3K4tOFEk>T16D}$)R*Lhq3(}$e5H&vI8(<8+1|F3cnDJ1p zj>xW9=qD#O@qS*tr-B1}7)F zZAT|sjpr&3mfDLA(VPXM3hw8nZ(~}!};#lTCleox3X2zPz97LuH z`**;{8$Bbpu<877#vDQhpUNmCK=?AA%ry6x{KM+QR`-N{@O;lM)Xl|9j+)=T+<=9t)qpZ~ zw%*ZZ-g;$bLVwAFD2N*IWGU|SG5jdzUey2C+wv~ICF{X@xpH~w%l_rB`d2PDm%m-U ze0h24GWx!MRGj|;m;`y%aP@G?xKj&0Rk6}y@TZW4rEiuZ&fp{*QF#OZp1B!k4!00q zP80vO!MtDXU%uL3x&~9^^3^Ywkpl5;^S=&W>^FA~;wsBL@2K$YgxX8XUw*ZG`5V^W zzz*D1yCRh8VHT?S0ZxxxBJ^hE!X+tnh=2SvfUGg7G+-B>vTQP|JOgd0QqY>*1k@hM z>Pa-qlF*Z0A!#M`(vB5f{mz8}iUk-zt!L!j0GHlE5;JdG#2g%$SVqyVs01M`V9VFw z8V=A?h za9Ils7HI^~zY=ADoV}BB07VmCg<<_&uiw=su`!@rP*e-o8 z{k$MhqS<oR4!Dk}laW=qY)+#6sH@Df?J@6bukbWCO57r8yNv*-IJ z){sz3=7i%T9NadWJNvopWGTzxEuj^^u4F9hx^^}JGgZN4__da@%1YOi3<1l2#!F4; zwIct@!)#NTw27DfUb%Wr`oBC~X77ADjBHdecI*q*IhV);%YaF^I0&CyvOeSrYTRi> zs)hv@+zeN9oY{=L1@~8wAs2@tuuptB7WN2)byN7siz#!rd1~rdyf%nV0|u6df#$u4 zJ)mB2LVLC%$Vk%@0s0= ziOSFe1Un*#YV>si4bZS#0FHUuK$3EXu2<=m*)+bTJ*9`)JP)D3hEBtNOhT3b=2@vl z4lzlwTRBKbPZrQkLuZM{Xd$dwX-re518D2S7vf_w_4-n5W37cNAft9k3mN>xU8f6QGhn=gCYFVx zF6`%`{rB2|V1;PhL83IF(h#OKo!R;14aItQWU7K#aJ8SPF>NPFy<0Oz0Ly)A<)&?< zgGH+yUk#X=EN?pQ3-J&g-U%NyOJ9c`^b+9{+rMef7c511JMMhlEFTzW&u8 z)_;gG_16Cw5p~>o-)HZif_a?7vDsO09}rB(zBf1l|K3KyJEzTnxAmvZL4u~31@Cj> zJly9sDrpip>vT)4@Yi;(s0FbplYtzpXuG4umH)hT|KYurY??HIXRYw6ov;|>GfNzg zuLX_-6XE?O?mKNl*xH{q8#O$|ln^c47ah_`>%*{@#?ghx_nw)PeQSO8xp}-V)StFk zrp%AEus8Es`BNt+0aMHiF180f>`h!Mx6Gk9ua=LqO5Da)H8x>^1O(G(A&hq2%f#Er z(%!TM;!S=)~>9M>8At zQ*$33|2U&(RQFsO*mgJiZ!0~X4;t19-2Y?e`wT6im#HpMYdL<2HFqfRPsTjuZ13Qy zBqb;w6i|9Hmzn4kPQbHFQ4MJgsOpakR^@S8!z(ToF0ibE_|Mhsf=0fO-t&9@Bypqs zwv=`zj;F8h!)=u?H$v8jT2t0RgF0&AC*1)`H%hC67rDjS9SAMhKA3t$L{T+i%m}fO zJr31;C0iP*ujSL9F)S>7n_3^kLLSc;7V@XFV4>)YH=$No$Ssax!K!tLyc*t=#S^aS z(1B_{FrC69W}aCWPk3d4=~Bows{3@HkwDdiXoZTg`b>3f7Ee8eKBz6}UsMrgov z(6W~;<%~DSEij$L;BW((s-W@8V6qHb?9$iJ7?jSF*fHI$7W^L#p+s!qjx3nAxaxhK z8xq|`2&xEHaCT!SKBqe@)G{g6vd%V$baQf^g{J`2ayhBVU{n)$3bPe(O4$QP&CB=ZsN!{e%3P{etxBjpStWg19(W#(B1aIaAdcT<4CIN z2!M<5U?QQjU1f3p39eCY;E^Ai!%|U0msBk#Xr6K~kNbud^T<7m=8~$F2_jq#K-v8` zcXmK4IW8D90qUTaWRIC-hvl&YXd&i68b0_8i;E$o#ZSgIgHaSH7Rgv*5V_hq*e#|J z=B?W~=!G~dW+Tv90GEt5g(WjgM8<^z-Y!=2x8c#wv)8;+7ONJ{ZfW6JGK@T3cXmdH zyBn_+hG3?Z2oj3R#{)J}odv(<+8v?}+0jQMncKosj3OW@#xPDf_Hlv~dfUysN^}Hj zCVknMjK_A6m9$NP45UnlUW)0;$IN=!X4eKn6v#S0u2LRN8BIE)tScXTi~t@h zIBh9yZuW*);w_iiPlmAr5pr9JMG7jw{;B|?NQa3Cv1SfR{cEPa*eF~#wi$SKfaElb z;~~|-B+EE}2FWZf!zRP&17HJ>>>*}&I(S%{ZSZ0&(}8pZS$_uKj9uEk((biD3Z%_f zLq-4O#0DP|J9g?ZBeZr#(}p&1luW4UB&CYf7!Q=bU!;(k7A?(kw3$Mih(KvhWJjcQ zcH*`bj%(`8#W@H7YtvQ(S&7(*=iS7yM)3dCOFlCpyBN6B>JBrBrr*A$&(9pPoX(Fa zHF~Z3e4uEXhWgftacO|p*)L8lPEDe44_nkl4~axl2}M)kFXUvOQl{xSb)j2i85SzT z&sZa7UMrn1BI`G(3uYtNf*0zxX-YJ$ddwBcad;uT2Ph8`B&-!?m@-d^txY@U^{a)(;MaXw*19IJDYtQ=(V4=_NlD?5N+$upw}D z&oz@aMWIX&e9N$|zH{ps;jKd+zx&;yy}6 zMwi6pOyWwf-{_<^aW`;)#N75ben%7-l4xPE7YvX^%w-FF#LkPsE08`EIhB}RkPl2Z zX1_?%_AB5Y*`tV>KOyWD%(G0QVxtUp*(I5=M4z37fOZRP#kXT9>HLxuy}C8{kj#`J zfwg8zkC12BLo=L^jZc_JHU!9z0fk}Z7upg&+z~PB+Y8eVw3=){!m#P!w z1aBdZ3JuQb1OCuHq(QbdNtZ=RGX;A*#Z18>MX>!k_yQ>oSL}f3VPEB4cF0(TouBp# zG6>dK(0zO^1C)|&5IPxbrY7Ger%=<9@gOT`fvFu*zkSZM#3X=R{Mq<5ugRqgjc$PL zI6{VE854xe=WZ~whFe7EO1o$Q*J80S{9{_40(dz-;mJyX@WYecZCV8!1wIylohs{kVz6iqkpAattCteA}W5IMn zV)|5u)l3Sr`@_cv7xO4@n(Q3XzCI}&wc`#MlMrRmi|Y!&7TG{YS6l=TUsJC?AzrGeLi z=yXcMP8Z_D*f|?%D75k!HKTkA^Ka?4Gl|5}|Vipj`9wzDrjsG2Ml0$==P&}R9&{lxF>e?|E+ z7Fkn7qbtVFu4rl1AngH9;+Ou^^#@j3U;G_m%0;gq3*s*Y1kBjBG2rQK^A~27^M7x{ z8aw=BV=wHn@lk&vhsSdnVEdJS#Bh$yYWcQVQxnZY=E?19_|ixP`iCfR2_>$KHykL4 zznqxzcl)V5ajo*2JW<9OMS33NLw3lLV@SjE#+7CAtK@aPr#OO|I@jgLFLMRlf+8&oS8SNlWFUd~eEZ-Ct}VxztZ-kGT?L0Lw~@s`Sv*lLOI}YA z!1xrYMtJWW+}eJ5*uQ;mmBMO_EK8Irp(@73uRsFDrAp`u;a>&%Hxqe7;ANHmP4O88 z;!5iDw^}Hv3_#MyIQ3#pzF>@`fd#QG@Yx+3Y%-*ze+2qw`8iKv7XB-kYazO0$Zybb zK9I9Pi4zFq3Pd+tWubUhxqrGKU7(<}TOsKkWHqipDsd))YFo*hIauk(l@5~YsaDmp zq)b{_Da8UDKa3HjvV=-Oq7aw7ab15>E-JbZz?Z~Wlkri^VlvjYhJsc|G&ipEzuj#x zGZ=tOli+coYG*dcV+LCRGXVrBGT8I&nRXdU-0`Ng^W+INg~JrismGgl<7e4Bc~u5 zD=U+HUhLp%H~OFA?=${_cm6tMHBgeYH&}mWbI%}zmdCz zbF9BI^}oaGaZ+p2{o^1)$eG~G7F!(4T|FHu_DfoLip5ZIbpka$IDe!tkif2en-1 zC$1eQ_H{oCbAQXp75~kuJ2s_%v+DnWtXgZJV%5eQaKE3W>v~Vd%yy?RW_~^+W1f*K zk8{eJqhA^4=vS0!H_O#jXb9k7^EFte?yKxzz-qSQn@@VSg-H57g~PM`%;C}Z3|u=H z;aQlrinBS}pZ&2rZ!yGB7tbj{;O_a>AEGcF|1f6J@5I4cX6 zrS2g4_uukrwg`8|OtkFg5E;ThuVRA}O!x0Es@h7N!V|5)%v@2c?LC+xsidejksr>) zk__hA7?S&j&#a(tZx*849pt3m+*Oe~(nfVoEMLrFV8W6rD z)BK-n5SM=(3h(J|N(D6NeiptO$}D9xAj(xqpI)2B#)vHtR8|EXz1yrlb55&l%cfC+ zjG0W_Z8bbt!XUE5KUEuGKB^&M0D`+*RP89WCK|o1OQi^tDA$h5Y3|p_;nd#&HL(HM zXCB?XfA@wc(SP{g!c_Mj_MKkSv7Y8XoV=4!TGqD)XI7@XHvCtv4w#^ReH83dHkl?fDXtexo0pbn@d@RLCorKZ ze+z)3QkB3IC0Qdp)>cW*BmsqI8;#L3at!Y>sCVJ=KBKDxISft92n|!WDgPhYrPsLRxu8vza}6_gnj`v?HOcOcV>ezx@6N9W zlT)k(m*AqaXWBE&F0~B8hD&z3X`iQs@s}oR0MKV}fY>s?OCv9fXuDE2Fh;~q7Uj$A zP|3f{-%Bb*Mgxg4@WK}FZ&76w*`MTt+ZvDxcws`88cMCT3ZsA*Ewo3d!j4--ivnK7 z6?xu4M-?kjm8L?F6?#j9Dtd(^eDqbw1GJ)EFWXdEv7;jvFoz?rVZwsC>8@b~ytFHi zyg1s=j=l|f)I2N!Na&hyxdgxqiSrak6@*ZHQH|{}9Gqe>-Qz(4AB@F) zh|(RC=bk)nC4jUnbsc~>kjElGbPnp$mjZ?`WQ;a_nS-U)mjZ5L z0CVsWALalcwKccV>C4=vrZ01w5nl`yAz;q_K60Q${yk#h!T#y!0EzwRUtqM?mL4^D zqk5n;*R$tVz_6<}9^dbdW)phkqLtC%ONPe)f_`C+!(Po`WNzbAtJO9WOBWDXVH_dk z%;8r+0DxRq3UMHU_+Y8ToYTQrbJUv}bzf{p?+^k0(%A6OVlxz`)vNZ?xA;zrTk8X(BcqF1q6z4D2$a0Bo zS|`a$GINCrL;|Zf+6p_2BD1xGZak&0b&Dn8FnX_fVqO-vMUB?Nk&$ySa}0f5(Q=ZO zRxkNpA1Y*KB1ubSH+?L^!e*TVB>)(W_V6R(v@86i%XgP3B-7#=bf1t!HMTzV!{P_C z=e(dur&IWZ>_H3*$C8Z(J~du{e|&tPcLq(` z9YdfPq?AKop8zDKUMR^?I&kSePSOEgGCnL~SV%(@t=Qcl6DxIK5{&c8WLx)S2g`ZK zHn2$<)s+`6-!3jf*d&+)yGyxDr$YE4!3P$hr>hXjQX?}9GXyF8>wr0Th6u>3&dwsB zUf8Aqb{P|%TSfViD2M-_#f87o-4;#AEn|J zN6$TyBJojV0W)NgDo3$wQ;JWP^u}8$Tz89~$!WKUjFGCp$x#GwZtY(Rf>AV5{OoGa zLpspk`N8P~L3%ATNvl1C{h01epf+Q!dKru{p83U~@>D>2-9w~Ch_@^^rb|Y`;HRad1)Xm#lX$dTfA*Zu<4u5H$gy-WU zs^_!KwCyJgQwjJeCfB}cf0OO`A^HX#@Y{(N8gz6DF&n`cPst#nlA4B%V#qFnk=z2k zLPkBkdfOzY>6SBgvB+J>hq$Eey{a3W?ss`}C19$&xWc##>WlMC@woUVMzF*j9gQ05 z;Ck_2alnh8#aWMnxOL(1fkRx3K&{|lYZMo3(IL1GedMl};EyO+%%J#LPe$V`?ErBP zyu-(npL)`Vfh48-ykTED9X~^bF{ISQ-bUW+SUWNaS#i-4BchO53*t#~c)8$Com2O& zKhn+3+1dUVhag2J2}Bbtk?#vb3P^Rk%9VYgXz@5-+Vf+T9kGxJ2zExXAn0+Gd!^1S z4Wczu0;`;lB3{mWNRxa>Pg!<2Bb0uVW#g zti-8cS;3--!8l-e3qhc|tz?pgH({F^vLzeU!R;1QtJ_F6gb*L?Y{h7n;~wwP?i)d* z-%Zgmqm5#6xO=`#n;*6EiYy*k(r`q@Hcp&DMG@Z`X$@j=lCY$ehOT>848<;@ZNqbN zzG3PRqb1#<$6*cGJc}@PkV@7qRig5UomVSf9zy5mibJ@vQJn3@A=>$eIEIV($RMfd z7%pNYB-w~w6SVZEyZwg6P5E)ZSok*ANxXHwg`W3fd52$`xRF{Kdw zmE2T`uBo7!ox_$l9PJ}DN*&=c+Lo&T5H(CrFn^7A>!L!G&E=5z8d|TQZda>6PG-|n zDC?bhzJebiLVaTc-~F1-2MiZXeRW7s0R#U2&y%y~EC*9yq0qp77lBtfGQ=h9Stjb& zV05-c=v$U5&;)C+g7|gOWWI@@qKp;jcXqb*K3*u|#o%^hmx|?mF^E~*!+lt{ly+Y|=6R z9a4|j0W6*&m{@sV9!%~WR8HH(Xwtx!X)6w=Biy!wy%&RH6E@U57&_Uma@|xLgFK_` zQr(v5GTs@catKuoqVE}en)c8Ap2@-a8B%xpz+J4dO;<3^z*w|+Z8P>ldJ!np8ZZCtoBU(CxvE>o=|sH*XBDZ#LI|w{`tG{x?XyCj?ca-cN5>%G*>fg%s9E6+|ia zPkUpzkhpiL${cODdX1HbUhnD|_9%7}1AR6mx?H$;ZUDZJ5^P^NFK9>r4Sh(&HyUQtEf-b$g4G(fx+Zr zrpmTT>EtmP{T`5+LcLxt3ZP4fo z42fJy*r*`8NXV3PN1=d+xrZr3VRivRAh!rDGCq~2^cV@kpH8vIx&1y;m2tEUOlcz= zDU&hTW?)Ak0RWA^tr%%gJ&6H{iWt;`=ErdNp;}SoOq{_%2Q#r4{gun5VpRjC_*yO#{6xGxHn6e zHWV8Rl~z6;G^|s&gk4=SW)P)&=1I@9W%DJGpnPSSQrXsqe=%X#L~0ZtL0fkGjM5Mr zobTy^f!dAMUTyA-4@QhJPtZi7QER{TdF`YtOr-2VlRaT2GRhMjIavMVhx6Q#^FTUv|2%LgoZ&|=CMNdUB>2Gk5564g;3BG0+;fXK{ z6{sE1opr9@P=T5EvH~J;rPg4JD@|>s4v93VaIqk#WNb5g?A@$ietBX8laauAVyS8d ztjc@O;=#|hVYvq>Z8ONV9(ePUkF+^86WuEF`%m%)vS2-494Yv{+Fb_iV(N3n!8=25 z5OAT<-}vPBOGkg>Q=4Ij3}8#T2*bF?c=mH4-DFJoJuEa>1u-mmXS6%Z?j-)a%7II< z2y%-aqM=H{cVv=e^#1X**j-{VrgJaV04{JuTF!h6%P)Qe4q)O@vIvGgLqSh$C~QYa znlDO(3E9yGnE2_AVJK!M7AFv8V(&s8S|9B(lr`Eb2A^x;Ufw`}K<{*vG1#EJb8tF_ z&5DT|?MoUhE?f=n=)i*S+iC_5ys$QKmca@Iw>LBYU+^|-F%%thVSg-YSQ*0$_;pt! zx)#VLz69R`&92skIHIR1v@x$A`KmJYv1Y+4bRb=z!yYAjiGazZi!}x?@-LhQ{?GaN z^i@8=eeBc&u!-bdz(DmdN|N%GwVI=yZ}Ea`lTqJ)U@j^ABbVg5>EoZ?r5`01y!4^G zcSl(E13_FBIGZKmw3l2g^-Mi{S;3AK-{>ubRM>rtIRWB=@#KVu6yyjIfy1M_>|TwI z&T$R&v}~5$>^?h+px!Fw%wAb+{L|j}^dw3lqaO_?j;5jU`HTP8ZkeI)Der_iVh)NG{Hy{AK1zkT|x- zuh;I~S=-v&ShE&rY+Bn|`{VfV5H`K(>EZr+YyOSkjZe?{X{b-}g%F4@u;P3?y#C4X z#`WgDGSU@Qycs_xo1g$mjdw{A8>7BWb z;C*j2nofW0?zY-XMBi14`>|5mK8~}C!R}nM4VKOTn<+xmY<}F___+D-qXtR5H$T<6 zYWHt8$yGXpI%gY($JBrpyUBy-0vyd*6aE;ffisrI!o%;+#b=;C}%ScOacP0QK!Nm00Uu`oLfRkg&Z&4 ziA*z~%?$m0c9F{vhE|VoPaaq4&z{eL)R*uQcs>DqpCY&xJPJ%-La2Z(GWNtXG#DiB zPhUc_NZSHLMp&7Sp=&|Q>Te!6HoF$l@Y%b(lnE;JjBzH_+uXg(>g$4QmObW`uL1#R z0c@gVZnB(}7HVjI8rz%Ku@u@F6T1qRJps?=r=NaGN#puQ8Zle*ULckD@#g7$zj+L$ z+lBu9(7>B-v$@7UYCZMvo9M&z=!jtgSMkP-H2dLtSxyf(Z4V>66c|5oeOKY=er|oiKP- z)9gT2=laB7|M7+00xsHRp#}f$(C4#(!?^uTgFrvHOpJf`#|QYUZd0q+f(A0h^-m#O zKJSKDjnwvopTVYA8Bf}vn5%Uc&2%HBz# z4n93V66^xU-ldtJkGB~%0q`8AohFwz2v+PCVZb=>giytomu$KCTV3klNf1l!p7X)5 zlUsKYsr+mNO6|#pQLy?%8T#N?-=QctqI=@etJ!}a!n2|%>V!b0Eh3V5a`-+YsvJzW zE7?Fcn!EqG^KkdkpYAHh4V;;P{B6x8303hyP1m+t|l zS77bj;t;pyJe1!IS1ymw4iNui@IEr;!u1d2J@$?$7w*bMUtZdPJ;J3XOTKEUB_s!1b53bC`N1b_u(Y)CRJIau!?Y&~J$~YNZ zJ;owV)D8d6-0M|y1=q@%opLt3MduKPW{?_PW~B9sYbk7N1dN{6$|}~#;p7Mx60ia~ zoo_;miF&yp2z{iBj>D2`)uT8< z*d(|F8QZf9vhre5EE0RSKJAL zk|2%1#)U2t^3APujB{?HI^M;M)E+~^a)@DEoEr|fN*p+q#dwHPR6KWBEf*R}<87@N zwGZq^^+l7gcA3h=^(sKGkas>g!tU`|x35TE*8Ci;Pu9u;1(C59>_u6mAT(CQUX(>_ z=r)c33wu|VqMA}=WF8o{Mv{n@b;8H8a>90)i zVyBZ{2l|S+L(RoSOCLkJq4y{}(;+V7*i-be5YJp=6iPmmM`ydIU^^}&%ExpX_j`b2zh%@Ec64@eh=yc;PT4iBBgsS7R(BkvP zOHHevGnI}#%Lk3GsTjN&x*NWe&H<2xAaux0*!~!#ZJvye6 zPQ9`FrCUiP)paXD28Y?T4GD!Cl{iuRuV8%q_j=8}K-dNxIaCjB zCJ*ok;dHHRVQq_?gav)`?4=1ZNcK=St)L#9isMQx08h~4JE9xu}`<)YR+ zMc{?vHm=X^GUFHXkf(Eu*jV7~n0rBNDE#Ra>Jq9p!6}&Vp6`^wLQ z3;L+)xa9eU>+1y_RTJLvfz}QF^Thmgi!HaG%;vlFPbIM{9YhJ?>gR(-Anv~l822|N zkozmgP8{V21?m$vV-XeGLF#sf6hRQcX{WpD++LOJb+kg{;HbCrsHiIz>PEG0wSc!u zDk%JFG^3boML#xdf*Y+9oSGoGZ9Kq#W*ZwDoAN-*-#|?^L{j((AMu<%X7su7HLiJ% z=Bo$#+<55D^z5SUp~9aVYu}81oIFGP7P#zx&G=mRfK@@xidw1ri_tJ{Z~w}+)@A__ zi*^>^^(gX20VCC`{!@^#D6!Uw6Df{;Zk3n*DG5_@3{6@)4msrI6zWl?1DaJ4fR z^fc=;UuBOSGU=JAvm=1x58gjp8Jxvas=kQp$W_xBrW;o-3f;9amaxVcW0<>|cbpOT zH>VcqV)wevb4J`9lf=Ucl3@xL8J&sUrD1$@g1}3-Yv*X9j-z3X%VjcLT)jgo3^e9-SOrGW zy}7-L5l@&LKazcbYc;$jYR*n=ERkY~HCiQ&x7hPK%Vb>^;LFMV$Z_T9>IV{*ayrNMU=Y$Nwo=?HW~iOAFh z0dz!Lik7?00X!n9?&aox6=cWHfh!?aiRm3m4hK|;<{}qn37=O$J+Npvip)8DIYGz@ zM682vCwQr)3Jmk~RMil%g|iq-Ge^2)*y`=^Pa~*$lTsk-pjh-nFTB6iynOlcs+YYA z$G&U+`x@GhE)cu${EWf87$AX-CRt7We)sTx9fnkIUF~4<8m}%nV;5POTiq`CJUf57 zKRK-j)$|Xyrd^9>2PF{6q69 zT25;V=|d%;v1n5I>DEM3Q_MtYT_e1GbC6aTP&5d?E?w0Dx9b%QYg}T=r4>qpTAq!(3e8Y;^4qnYhu?kkMUkJk zHT=~|vkRLq$z^Nvbcc#EshFq*yGL$o`PQjax{j4MP480{;x%^#YHf}RtpUi)YQXLF zI}u;pzxVw;2qPne0-b&Te|Yg3%U?9QL9aUaRyr|qo*dcs&<3eRenC4ldO&_JpuuQl zcncm?ro$F&mOca44d|))ie8385xum~M#mm=NH}@!jb)Dt25qa2Tc02N?)mWq7j0^I zx0xz`H!Po_W!Kw0&0-#{17gQm;!H&K^tK*HrB?`M;U|gy1Sy)|dPl+ShL)Y4Q$GL_ z#hyZ}U7ZjVbOPPxdV2czEry4NX)d1=i3= zwV)gei2FG%aEHr}cVasRRA4|-_Zeyg=nObKiM-dzdg0MTe#*=7WFHi_Hx16DWymvxYToIa;fubDkDON0}+OV-duMbgm1xC70t9mO}NPolego_M-{- zsu>RM?Kx3?B6k-0#AO3&_n4W_#=t#f%vwEdUg3aBY+&*NrCP|u zFg;EX=q7x_E{n_9NYVs05vT~P0@(v1n8Gf(bBgew7}rd`2q+Vbwv|>z%h{(3lfrNk zrc<}lAbZz{80ZSN(ZK-|C}?>2crbZ(Zi<5DvfnSeLjOKq4=BvH_YnB-{P>t&g^Im9 zgUOe+bJM3AQ@uf7M+mEwh2eU5aCnZp@|1vGPJ*zGG}W-pYOHclblDbDvO9k&X)%H5 zmVmSP6zK(y#R)f4v~~J&GAnW;?lAh{4EKOcNIOTm^P`;QTp10qa*)smXzG~vt}w9Y z)9DL~kk2K>(rcl{KaKa!$&zN<;*%#&^eGgWxDB++%D{-42ypq2(--3{t)+$lSP4It z%U52jGSyYJTp6ld=NbI&3K~7RaUx*5aY9%iI;GU7Sr|@obqAaD*Gby6XTV}vrjM$r zNu!Wn9QXmhekL&EuTNaRJIoibN}TJq+3W`u*=lZc6I|!<0ay=3nE~i}tTrwX@+SC` z*KMGD0VE<4ezujM>H}WUw>`5BCNOESdBM*DfC_|})skjIXdeIwxw$?&Y*y*0 zT}^_E+N;iKbq`fcw^D}(K8dfLM>Z>ZVy7;m=@~TC@NhKntj+T*4R2{i9V&m*dVrF3 zo8HLB+vY&{o6TVF1;QUttz&euzNjIMXYb7)-(>LwPVwiPHdN+tLqs_T8tPo+CJv!* zIQYg3?ABln(jy^f7g|FIQ&({(Yx!QWQhPyA^E2N6$yP<@d0c1fiX|a>6F%z?fyKMN zWih1w+RZYG^KbFDttAGztk)h#4qFO6kQc-UGTO{}_K| z%D6-gNGftCPH`%e)(ovb9y}e*;2>~1_+eu~ovkh2$=kj2?am{=^>-Nac*h;;dDa(pn2 z1w;($@#yemgnPwkHoofK+(UeLfDgWqya8|rp#$Nvc{qK_cnQ!m6ZAmPo+FElE9OB+ zfv||sj(F9a1vm*iXt?abx4V1`XvJkA3s+4~cY4kPx^ReNL|{m+se^09X}eU1gQv_A ztrx?e%&>jvAvoSk-797?cl1YmP`k3vFMekY*3&o=<(u2HSo<_0+e^%rYwi+ktBvkW zW=rt}qOYBUOQ%P8ht`TOnvR-`kNI#E;A?$XsA!fFyzc~IqLRJ~*OX}62ye+V-mxIC z&NKoXkf9Vh8pNOkGl$cUn|p^D+jmjqn=Cq<)DasX4uBpdq6yZ=4uCR0@h&Rp<&Q8H zK{rSv#u3;jIUTdca40z`In?FuL8JKzp)c^?6d{5qAbO*|j*J#~H|ua8sh41EnF`ba z_O!g%gHH}jTHX;a5O^gPpx{PpHsSX1>?MvF7zcLB!BR!%scv%jio7o7nnvlmY z<13;m<1b>K*ucRB0{8d-@O~Y7giUF$a(M z0YudlX;zE5PEP)84?ntc&oS#mV+v1rWsqdJuLo(9(c9kEh*K{`PpfLY*!<33GxX z3UiUQ;^M!1geiR<;v!M4m$3E@p8{>?zFoby1p+ZX!`*IP3s6+m=j7LahVF&j>V)1)S}bZ%sRu_-ff9aLbcf5 z%gwJqHcGV%b(>}_6;~~+yH44J{QNvsATjV9*pNlZHFA&w~w%HSJ6Qwq-nIDQ}D%%PPOoie{aEZl^{Y+ZUuJe#XU%phqnGBe##lx&uQ#gRpkChm?4OH~;tY0TXF+Mq*Q~$p5-V-FIoaUTfK;7-C28vi zIH$yZx%7K%F*to$uz(Bt>u1WqVdA>}6mgqhQrFDYfYlkg>6o6h?t7zSE;B?GXuNS* zeP)~+O%yPi4WI#{cbaESMB>DygV7Noc#7G=M%oov5_nT%>l|+w`Ga7AZiU?K0#ix# z#JU;OK@<8E(h3>NBlrh3MHmm|;y2zC^Fz)eF9`;riWFEX!+6oYnHGor(1 zFJTp9_e#!<5Lckn_?$3PvH)tJ*aZExv!|mUn8x4h?mWP&RXjLTY#!rrTe@(-64i#~ ztI$7LYoTv!A+@ps8iqmy9Xg!V9b_IIOaJebXwhM@z~DGASxncO1UQ0A0U|7WfJ3r& zF$!UeB8?A!?mmU5&p+G6PB~Qo;3^(4Pv}`AT3bpd za2disj6|?ng*Geo#tIOIj91!aKN$l?tJtw(xOPgcF_7WZQh-~?JrT0vi;?t_HXU{l zj`pUO%LJ89BABcOu?zeN5dgMGm{>3(Uq_522365zq7t(^J%?&(S6#!wf!muHDzqM1 zWW_I81Mn)+qUAMkfiS_2`aFA%KdOemX)uZCFp%n=Y_sc5^sk_tb1TDJ+*OUm#yERE zeOZmsAONQgWAtU?xDr}P-wTA17sYVXd&F@XSvb!iX4V8D`(H`K<+1Z|=XS$5Usa1@ zIIHajXh<(&1PNmRR3G4~7s&#}Fd1u!-4&UhuuB1gZefadv-9npZ$S?&@-=A)w-b_y z6851fxSJ|bAyv`T6$BqgmlG&FthMm@=3U)CKWM%%gKBes0>SPcs-GSJ?RhjcmB3x@{L z7{j9jHi9){{5=eK@c8}N4@%)IdBzU(J`1&Q5m!iTk3JO(fGzkE*2S%6O)W?+U2AR* zuC_-3+c4KWhH-UpYaoE*4&?*ZI+>WY#o!ajh4qd6nGh*;M*_TyXhM=aDfY^E&*&Dg zLEpAG3>Bu<67;Bt(q!@7>-*u4ma~dQ>%=Y$q2XFU(zCd87M6slIoyB00-+A6LYFPb zGmRR{Y*6N+hf6!74PkRdc;awF%#kepx!<%vTHwPs!VArp!nasL+~AEa#9m1Qkh*Z* zHG3L_I6LRX#f9*OunztU10c!3W|fj>2yFKmrZqa}{7^1xlF4?g$(C_a%th1Rfrirq zMb@`9cU1nM^3vp{x%U$W0e7c;YTK%D0h9ua-U}Aa3or?{(+nK^Z>ewCBd2UxHk~P; zkBZ1M{FITmmfsnngqNey?xl#a5luQ1CEDxXM5qAJ<)$lk08Qqcfm{SGZ2K4vz0YkX z`}{#Lu+@{W7Si2pGi<&QWWoHd5qugUxt~Q8m&M39G zmITL&0nQC0fszc5VCG5nAP)gq!ps17Hjn_bFZjW+z+1ixzttXOMGq85I zN0Dv?S#j#g9b3@ze-O-f0get z^MzjGBmrD}19-byE$Ah_&K0GTpZ8Q^;JL?H1~oSHux#C+pRQ$yg#lL=>_|wmlG@Xiq%S&irZSo-LP=V0~ zqtFKtR!H|4jOTE4~RA$7)B=mW-y|lyzFRhDCDc) zGS*yKV_%CW=iExy++w$NF{W6(L8_CQUkC1&&la;9WzgdK4(yo78Qa8P9*h~m{n9`~ zH@R6q?X3Z=y|&-^a45hu#mbOM?s?C%?|0~0K>?u}i*cZMi5-eM-<=_y`}e8b5f>CC z3O`zCd@#xYJGTzw7^9In^L0x;Va4GsKmBMyI3;nae6MBWd#r&W(@x8b;~GLW(>w8E zjirVy_o68DnoFv)!yQPoi|kUGqK^g=63alS6{bHqJXa8Q?l`<+5>!WN>jcY+I_27b zX_*3B!BIAJp@AnJ&H35xz2i=wG7iQuZz-QaHHH|nq#9qXHQWL;{wg7PX68mSHwsy2e*U+cpE02Szfmb|`|-U* zHY^7DPUy5fVm8;zHG}gnta)n?4%=l4=g8)Mf}BOp>{!A<=rzmBegbSm}O zN7gJ%kLEgQ6?+@R_0Hz#l?Ob4;|yGGPNQ(*ywDh64wtaKocT8U#3SaC_4}QY9<0>0 zZEn%~;Pn~?um*D@2C?=ta?@3b?6K_pmquk>tvIebcH5-bu$blC8XL;YC~%!$vP8(jcIm&IJZt`PGDehH5&MgJ;4j={UF5(iw0|uZU1&Qqp%7I(}r^kYL|RRLTk@Q zhi8{JU1b4$7c@h*|CE$YRa+wjcC2&_IQ?%2XRwc0wBPcwl_M!C8TLzu^_Go}b!}e# zmFWr!zX}{5`h27c@b)A9FfLN*cvgXIb_mCx31UnA)h-UfP>aGvsJY5x7ux8DfP`$4=$2cJWfBLBCg=}f#VImSwWLQlCcD#9D1R{N)U-*G^L4p4OW+(` z>MXrSSd{yFit5ARWriVG*BFvEo`_hc1xj@iEn6+c#kxf!Z`D&;AY^4Q^8G!_xuW z?PXw0dN_QBHNc?-j)#wfA7VNKS7(c)6Q+jB-{8J7F8Y~Z6NpfN9vBb+Ci_G`M0HDN z77`&^tlA--mmAlsA(_?78<`~^02>vNhF=!J!0eLRWG{kuSk=0 z>Cv%2fz5C9%Hn%iV$K=j3vpqz$UN7vY9O|%)PsIxzUW3h`BQ~<_)rFZu5I+m6whMC znAJrKV=c&F07R@MO!snp%HR`$yFAK{@Th2S-$L0jPVm~`li)y^G!h4wf!9w!;u#iC+|x_$9?!R#5Jst0X$Hi z*>A0h8+{;qVz2E=z;?5?asTc&U+w(yvg)YZmFD)N=1GQ#CootB-RQFW+a6Z7$~?x| z`0!wB3xSki(|SQWVCD>Q?N+{Ww z>tb!CM}$i{dW!L6*gIJn z2L*28yVqKrG?wsk$eWieeXU)8^xfB&=Xbtq>)lqp9uTv@5%Gzmm?s;A9}!0W3~+q1 zVLt_BPZUxmkBSqyMEke`;y&?S*b1vZagWB_R&)Q}pYAFHa|s{#ZOR#KWl~aYH)dR3 zywpBqu4}BUP5LUhHnWn4`z5Xe-Tvl|m=99__vxmQdUFv3Q0v~C6nLyY2asJlt@UES z?-($G!*U;A?-;x%uXP8)cXMmOn5|&q)ovAMSuO&MyFyIFkA4abdckbfG1M()i9B07 zt-Y=<`Bj84Q?L{~PKO*ubGo2Z@iG42khr?myp*_P1Q{)nxNLE=mIz{&t>c+XiX_xY zWn^70P#Fc^@i}Bvn#IO_WYqfYrK32CWD@@V!dH^_($zX+crkJeFpFQL7ll5#2*z2L zCq5C{Dqjx*X6oW&SI<%L?o1^JqMI15Qvbk zZOQ!T@+1SxCQVHqMS_f8S+KfOmRgt>Q*9X4@Lf_3s{pTKwC*3cUi9to&!3hl8~Zrx zIVO2d=NcSsIzda7uH9UxHSEX5w}G6ffgxV_Ny$+3o`-yy-%moD@gV_B^PAukv4t=9 zBC887pe9I@?gb9t&ai0Gngby>MXxE?QP^yJ_%)*qm;gKKhGt%S+p{YPA3-FbasYR} zsN8Lyj`m)_x&yTV9C*R@PAp?4s!t9sH(*_!PxtfvLNWnhKcoMG(?Dlv8r5{{Gs6%? zu`?Q~7|G(Oq27mAKV_Is1TYfiRk>~W5x>BdyBX4;fa_)}v;XEj9hfm#Lazq ze{ukPRh7))8;aJg_l!R{wBxg_t!i4rB-w5!oRHn>15yD}nG5e$*uM2WEb>Je1K}pb z-!&<0;I=&7Q1#B=dRnNajfPCiSS(+^{qiAh8o))^b-ov}VP;LLYh|;2Cx2?|RSR

vs)dR(LLDtusS-JrdQ>XxHGpL)VeOoH(ehODm0m;P3V##xIdQFL zeer2-S4tuot&l(zD%1?5rs?Kq@quZp$(LoDe^y~PvNU?8@ZyAS6liOs!dPATU^O## z8U$|R3tahoHa*4Zv>dI<__~?O1)tVWnZPwZ?ozLVbgrpc zs3=|_C6NVR-&n(~@fS@V32L$cJ4!V)5TmFYU&=_~qw&F{f}N|~&y)m@-MI_J+AiQq zqKRIz9tG;$umxWd1y*Pw7LA)&a2C-*FKf~&FwdJrfkk7`BEJ(=H^`I?0VkO3uhA^x z@$?$>DQk~Q5w}ZaTkKS&x6Lg)_7t#6ZHY2*N2~0mT_zL0$kRebY%Ysa*#u~|jU}Ze zs;d^)hk{8UAx^nzT*n(PhPR5Dq33o?qV94UcVhOVjD!iuyWs)S1A*zzK$B!_%g%Hv}MVVUmn z5fGVb(PA8WEyHzei*FUD2KVTir;};3_BG;g(U>u6{)~{22$+SaSNjOja>&dKSJ$G6 zq-_tYL^&$l%biRIF*JgPA>?HPA=dSQL_dp%gHloOH;s*C>1^HjF+X7hoOwB(O+nAz z?aWOzzjRz~4`|Ilt#c^&%XQ`oCp93pbN6d{NGV1P)bXJQ3@w_!|1(^XSdP>H84i#k zj^U=)2?>$VUWvuvN0Zf67Nzs-ITARKZ`4L2+nfcbCQ%e&gp$%DPw|nYDYYMLJT9Y* z_g?HemO=tosNbLd1!I8AfEyi@i881YW>psg@6*!%R~!bZU{ z5;SVJHlmc4Ya3tH|K7aov2ZE)4;l(ziRkbRZC?m0Jek4h)b%fo1=@(zO0kTp^9GlN z79n47!pXLhTWM_oM)!J6G4>#0D$>Q;79%14oQ9QJ$@`Fh#U9MRi7)<_dlbV-xOW*u z{k?GSvT^-F-1{AYlsNTW;9ibZxObVABpWft@W!4Gd0}s7-*a?^z|yUuWRWDQ5!)jb z5TpO^n-*{+1hrTz!I3771gHX^8$=D694l@!GZ`Wf&q5LlF* z(hb>um@7{rf&bJ-haMee*S)L*cO9PKsu?b8(j^LXmZ^+!I|i_e zA9!U&i(8@nCSzZzrSRd?BRYm=B2lm;0|3p^iM{uX2YC4hR=01+0g>%BXgR9a(GaZB7A9m39v zYopR`A`(8X0GlH-Jo0ZvHfjaN)M$qWn2Z^nA%nQ8 zZl;3@Af8Z%b%(d^-NEW4H6}mXYV~L@P0&ZW))_SYxa0}Z*%Uh^ek@fzraREmv}#Gi zl+mO&XwJ*hNPRy3X@qo9fjM24^@px6XjI6=BGlsfs zYMBI&V0wn9#2!*h_c=hjZx%gKrTJszA83{wkkns zipNpzM;y^*EHc*(%BXH7m1dv0gvU3vGD!nP-a~Ifl@$XLkE?C3GiFl1RKOE+M<6Bz z^=w|V=xaCxOZ?w4?GPxwb$x z`=@`2M@Q7cMQ97uB<<6>-6Ek!Cy?|b$KN|dz_YC_CNbEXzoYi7;YE6|IFZTGb=<%}BPMwXeSe%eH9ntTyzDAw01pZS zj$MqyGZlt=(9EJfBl5x>E2I7jAU0Qr;8e)7DBi$&KzZI*E(to=jW1Z1SV9q=Y!Bud z#(Ky|9GQHgDn9yhrR$M-px=P=b0)}C7KYAaptKHOT4!nm3=KC3FpN}O8;eUN8UO&2 zr5+(6! zw1%+%2%om_r?BEXCF#kT@C|4OVA_YM8S6?sor=XBxmT)Ed>(LA9I1tCcV_FCFn*Dzdm$_#X~`wxa*?GouNxq%YzJvc zkADRD${jgrvQ>XMI($*AdYKyq9Fh+{Q$Vdp0+2+c1=98(0ye27ccCblPcAOT_zA$; zVOWFz8XgVzn?G(%wq^=?W5oLLKvj6vrqxu&O+tpcXtSiLTqWB3*;gSv)?%B`7ny<% zz?tI@`r)RvUhAff3sAtJVmO$EkWkkMSg7AFfQFb=yFwcjVxR@5ZnJM`;0RC!y7^xf zz7b4#kE^7OsqO@8chP5$f=vjM-h@jvYxLF4r9*F&1zov2;`qq!fZ&1oen^x}!WNrK zeTIwZchnc{U?g+Oq7a4(7g3g*aa}ST(PJ{Xh;pECQ%aMjV<3X6BX_znjPM?HH_1Ox zxw;3A7=Zx6;u&sXXb3Rzh!G*RD?-X2njk`K^prKsEi^4!ml|w@z-Xt44(_cNqrdZq zZ{=0mc7jba=WY0iq5L@l4=blGgrV>XWiWmb%>V#WF zUJECmbs6qF>;sl6;hW!rE0|64G$>HWI!l54{lh+{>YUjrQMza?;tyYpC-aMdd z@)&2LqcOINoFGLfXqQn;Y|!2&V2!)8zULpCFA?xZ`5M^0#wN{PFH|HSXis7eqQz+f zgJs?a52<~VRFTTU{07ooC@(5{0in#dKW^>lj4H=%YKPsVx=u4B9M@^Qt+6a1J5E5L z!qd|!bFD`K(lSY%9Wfe&WqafH)j5|*T~j9>j;-v2IWMX*NdjFnP=nWcUI!gmAERdq z;2`6Se`nF=BVY160M0L_ht393iCQK{!X$tz8fJw6U>O0cASqxx@5+}RuJV={u8N9i zxoIEDfb!)KX`QbCkydauh+Ma$3nt(?&%dc(Leo-$S}@FMmm><&H)9+aUA1s*lGiDP zHI9aZHuWj$(jtQUL^N5Lz)1Lp(re(ng7Ju9!0Sx~6lVo7L=cAo1xglFU=8FRi9Ljc znAs!X(wRru0O@yT9B3rH%yUn1LJ9~CM2)**sX5bMfyqQPrt`v)%|V@Ut`Fcti)^ph z8UuFBLd&>|ba|i|CrbBusXXmIIwk77bZN~%f5BnlAq!C@?dPw*?1f5H>yFDL(u&zq zkYz3p@XqPzct!>eSCbN1kbQTsyF0Kj?_WIn52ihzW@@edk=8>(e;;+QkDZ3xAnEOR zSzwDOG3_Gw1XD?#AAxw!xF^3++Bte+Nuyu1`xa=BzumZa5_tKgt;Q4SD=hj#-bg~ls}~Td?5k~kY+B_ngBq_j!i0Bb41d?m_8c%UT$aG@qHC-wianA-HweEvh7G{1^L9d#5UN3=mV!fzt z3QhpX0vNjpYnZsGlsT)j-lpnt96nob60ghc_zD_=STlseGL|)M1U;Y*Cs<7J5)zw) zN=x{k=VBi$kg@0$LB?!yjEE|BqR4$Yg7%>XR!jry-=1aqoY;r=x-%Aw-=-!lb|nsr z5ee)`CXkOKX?jsS;yPp3p&B>@XyO!Y@C9F%&4LaE?I) zF^4~7P()N5Siaq3VX5Q|UJroK#1IzgWYWRjMRsiNuZiA)p&bqYnah}eA1hC_#SpZM zc7`~0y&0_=?R0XPPOeM2(WjMztT?>&y4V8~6rkP>`iX29hbxrhDaW#N(1D6F_xY zgpt`=-?n(w5Ifn{(dpy=yqkqIr<{=T$%B5jh0sE<<7_as%SOZ4gZN2dH#w$x2`-10 zM=vHP4SJ_1$mtmA62PSH^P7(-6fs)tD@>URkCS5)OVJBnV>13R zd||-sf*7BVo#?Q&JT4ysN5%15kkmAyOXbULBrSUNbi7NQrQOe<-lD9fb;o{bB_2~= zy=)76#rKnaLunECFzvw4*xNNNN!kd-l|h6XmBEYPFv#VYAbQH-VX0KKpQ zmG~w5Pit+vX?y|!S882=H7NPKIU+AsM+}RBjKLB%2vP}HDy-q#Q2Vs9Mr9TmrnOlt zHqSz`mDMjrW&{m)j^aMJZE5B(+xLlNba7|UqDQ0txmv$VP9KUScI-ln9Uh6;1;Da% z4H*D@)7z*IXDq-HC4iGy@t2?~okBE3U|`GCU}HQB@KiAbBt~>?01ks-d4Nbz6ilpH ziG=%;u~J2%h?(%Vw%{so?78>Qm&&5ma`M0!rBsoWM|qd>_ADmZiy`8%Kq7pjS+*Z0 z3O$lh{9o&0BH#`3eGDq*?u<+q1JVIj{hFj6$ZCUA0<(&+0@@yLQeOGYK#vbw%>V{M zAYWApfGVglE8Qq7;lU~e*aUG&ojQS8MLCb9Ds-0tV$w7~c6x9)rq$P+Q=#Is%detV zVC2Z+lDW?gt(AvrL7Xo@{&f&8KJs-9nPgnrCeh49EmuFD*c+16w301qPbwHX9du=2 za`BVz5{Mo8)Lzj2bkO0ba=BSE2uALi*J)VDtz2DFj07RIESuU%s)@BPVYUEE3KVTa zU#Zbcd2NZXw6wr4SPK0|8x}=k4sAf1>lkoX&0!XxQ_msVNm>~=E+Yjn=CGgv46P#F zUilYnSYT~O%vu7QceLG}cp7lpzs?;i$C>uaPv87*bvME3)(9W>SmUgU>v=cWes%h9 zmuYgZk9%?b9Q#mTMkjW$HOF;f=m1=g_)n5KxP!3t-t8?Fn3`!Xg9U*N34l443o=(_ zS0*}ip4eEsd|+{UfM2@KT6tQd-uz+3c)M%Yhtw>})c>TDX$qEK zoU82u@jI4$qdG~ zG9z|*9lPpAbhoS|&z&AkmlRQ1vsF9_L+bK16^rHgzhG!p4B3OU+OVl*`BlQSLKR6j zF1f0~d6Is~a8qSiFS`0-dBgmecnlkEuO;LAFFj%*)FkdYtT&)rIp`_fKWURsmP%Qj z4jQ_ZLK}8Ed5S#AavBb=XL<#*Mp!8RKr!<*wmw_~KQG;XX^Fi{t3Ebc#&5asp~lPS zFoD7O9GHB+A%CE-GN;oYCm`Wz`@>sEmRV$y{$hHLWO}-^7g1~#&!Pmu*~%b#0QiLjg+ex*1b1V zpI=6^SM-^}M|=Y!A-?pIs9w}5cpmta(l0oFM;9)z`1q30Owdh0;;jip@ZsiXC(lp* z?cdr?*jQh@B17_aECNV+l1vcps zi~pl+lE%JxlT>8+Cb1X}-P@gCuk6Pwu&psfyWBGtz@DXY+P6zJrs2ot@>A%4t{7G$ z)eGOhNfCt2P4PrI{1>fOLw`D*9=}<0?|v<<$E+#XGSg0#L4_YCz& z=WGDO#$w_f)jRi@Kp|xKx+C zT{Gp8QVUC{91c5{JNez@-`~rkfX~juir-xM`Ws#3W^d(&v!e@paU#3?aDv0E7+yON zcC9b5*}uwtH}}sdI`PBkWJdB+VxaL2XtrdGHEee}8yjJ7KGIUf&`)xqFGT~VQF zi^RsBIQ9pjtF7h%ZM!I+^xjaAGr9ZmGu#2!+RB0{Z#Yh8zQqeBYAr&la|jy7#Vz)2 zr=|_wv+6S8t9_W9-(`3Uu0s{u!T?2GeISdp|0JmR&wv#^>ebFgBUuO>qnThAKVV>{ zz0=7FZy-ij9L}@T>3PJ@0Nny*^RMy&OQU#KK40r_)aQND?AC-sb7^4SDejR2)8;@v zX;NG8$bcy;ya?L&sG>=bu%eXlSA{V^jA+!IJ)azegNADX(~?Py1dVhj40N78(JcdC z?Cg6F#zI4(!8A2kZxBbrRQT;&p4)pHd`eAOFSO~#tDtPIrHt3RrjIG=+JHrZOnsQA z4d-Jy`Y=WS?)U=OX+(d`MNa+j0@AGTQucD9_2fy-+X~Z!6@-F;&qhe9oE&wUkxg8) zDPL%%e1&XCsLw^U%3dM*aWT?ZgFZGYmfz$hvTE^kKmLo-;nwB zU(^#6r)`m=QOq|SM_HUxkHC0bBWV7jSb+p@^3yHg<3OlgRmqiVnTeOd0U;U^X5_ZT zGxTL!Q8YUoK7G~B-+31v=99h28AONYxHHcf9jMB7&0a!B0-$c-9QNnr6uuG)^W$lm zXE{-ILQV`3q%+S`u)?`s>7=49JEcY?x0_XbNS;D(p9Dc=t|H#?{&4x9s9G0Oc_7p< z4ECi8{F!iZ)^vsa2W zu3Qg8Jp$eNZd_x--pqBL4$6|fk=}%0;w=b6`G!?8VRmT@P|a>a^YtAj0h9?cU0|)p z?I4&(J7?fZkmXQbT<2wRvd=90m2ALdACPHimXoNk(WKH$ZizJm}M6oT$|}ahNK?_BFf^^ z@gdHRI9tGxMh0NN)ojA=QCSSZEkPl~4?4yxZR6Z7t_4zfZC&PsfyI7Ct$8mE-_E(p zwe=3ZAi?PXSwLaZW({tioZyO0CjBTyDlBG_=$dd$Cnqi#FH^Qiw4{JS+}uH3h@9>g z)$S}yoT}&P8cN0}Qjja~2F3#J2JR>xhs8SMP{<(_O&F76S-|+Y%^mCynpX})HS6CUwM+tpkh zYn>#WCQo@V%g6ukc<#;XqA(UE+2{f%f3A^#yt5CO{MXqx)c22d_GJSjj|A@HZ+G~4 zI^XW-1CZux)<@r*dBCqE8Kc{aCuwYW)G8Hvy6_w=bm^TSiF3_Tkx-SDY9gcb5W&b| z>B@8Y6(JBTKm^(e_9|aDjD`z|VAuLcTyvXo3j1DE#Y)A`%y`v{g*4@qpPl!?D4vvj z!xM{uPOmw{nczAJExAQoQjGJC<@<;hBU!xbLkx=Fx)*+Rv0e%htsYHxb~Vei3!&?S zbF8Tc!0#q)C3tP9)u^IR+^?=_>YgMCf;5(mC6sU|~~@zuvmszAe-;>3?r_(IVm;iom> z&1Nom*M@*nqHzCq;M7$b-Mlys*46-)h}r^tZ4KxvqsEH{@$h5EdVHB~p<>WzBzqA2Z9|9{JoxMl zqkNynws`hQF@3pN92K_REO~(<`dk4-I=WKar8te+HEIFqrxE^b{Z`|zN5_b~6S~{T z1ylwt#~JW|XmIRSKOErhEgt^qK@aP$c)AV!nKWWv->(K+R-Pq3hZ$+{nY?@h3zYz~Y&@pjEZs zJjuwrS;Y3%K9a!ux*xXn`v3@ zc7te!aQ#w&vMFLJp)!`TbFJRUGNt!jy;KG2=HpYUZ|y2MnYrZjPe6stMJQEg+)n5N zKQA%I{ILDN06PBt(YN1JP{Fyi=YS~A2r{&L0``FpL-lz^>#WnfUc0`wwYL8XGnz1l z&a0vS9?syx1yu0;wFMuq!lf8V;x^I55$posc7`t}``D)Muhq|9@CFLbo=;y6_s&mg zMn_yxB(Foj_wTQDzV>P#q8iTR(Rio;B;Q{v9=yoMDDrZ8y3d%;v*F~3=V6S&&%aXz zsG*I+>~rJpG_U!MA)It*L@PU(om*oBZJR*JR89hvm_3uI$`Ap@MFz9}d~^s|c+(g} z8Ls2Yg<}Sg(u@?s!eK_^%lJ#~_%mv?iR!$}=#Uo(Uzz%&h%>bW+3lbOo`V8oH@ks1kBGJnzRKYmQJ$C59tMP2$Xl2+8j;Hpp8fv!?(9)CJ9^#4wK|+R0 z$2qWOcB8hMd#R93a}(x-1hg#IG=H% zfTEV(we^$e@jUXqzv`N;8ish6xmMSi=*UO#y_Jm04j!~=6G?FM@ROnpJbU~jCdT*R zc`I97^_?J~0^n*~eSj5nzS7VV2J8bLP)bd$_bL$br5oE840oA3t*RX9%P z?mON>njG%KdmOi}E`uhr<vKI-U;m+b5j-O95Hiw3{!(=zk*@8Sv)qSrzKsidO}bcZ5@p?* zNjx`=;Z9&e5(hu6v6Qo96uk5F{^lsR4j1y1g$cC8cxt5ZIzyU3Gyij zN4O7A4wA!bYu2UDr%g*rOpW0KUl~Kue5Kde2Ao&hHr?m2dgNN0(T@m@LQPiLZX676 zl5P63LyYo8a|4fO zSWm4R`zb03it{S+YolvXMSsjTjhi^TSiht3?&)+2SJutzskOP{MX}#~(p$__7S<^J z(Kdg-xvcCSG0^X?Yh61>>TQOM)O_;EM<27%)Ntgk!@k=h%mC?-r^F6j4a+) zuWN1apNq7XI%c+9M)eV@?^`4Tg`?^IY{j)IDrE32p*LmM9o}o+ha0Z15)h9D^L`p% z(pe=%QqlI=OOUu%vk79YBCn{okvDUNx(9HQe(So^bBL*}jy3Rivas0t9#-jkx9q4dp54aVPGf&BTuWj7F`^{H7f4uA!Rq{%6 z`%&{GqnsyeWKt9FnJRM-!MH|R*UVi%9@t?j<4hNGnvD++kX~oDw|h8IcDwGH?3pfA zxLQ9uo1Ec(du9XqsciA=6poKjQZRS$-~-P8ee%q)j^>4y9+g|7sPGvp?9Nq?crOv5 zYl^-j)g1FKEu3RfRg)}s7Z#LaV0k9dvd<(Q`)3j*RAKQ<43w&gB$an7IBJz~+ za7mgfXl@p((pcQ@a*)B(0h>2nE69HI-Pf19pt~Eq^U%BYIhccTeFPMPDR7ZAMJ4=J z#a|OnJC4s_Y1x9cG;NV?#0CBWz-vrjSC+6CJj1G}I1D{=GllZ3f?GX6O6e_n~9Cbm`lN6`785v=FsQYqi|XRJ)NCgMX7LeDm#2|1=0Z z<$TM+y>lVHUWXJ3W-Ew@CYG>bEU}fj3hhjNPrO6y&kPKNp7X1v_$;p!1r;j3Y6 z#FMDxlZ_|Q*ORpd{bcl`1Apmivt}3RpZFTulFgpLr$fv8vknjnYYW~n#ti+LN8R`7 zLd^y@g(O|M2D?!F5XK~nVSO34Zcn+D(VfEcL`DZr-N}=oby^y3wUhnE;yYcc zJRi(nS?D&k+G6y?Z@smW+a!qGP?w&YGq(QTPOTjf(V;nhh;Zc-OdPkSn~$#ExZ3C~X9bmR_j~2FCy>|G{I*dHUaEKDycxCJB zITed}!5}Y~4RgZkv*HT;f+f&gl8Lr8(R#EjCEL^5!@~H>H(AP_-;1bKiF@<#k;hTk zo0kr!C<}ZKyKbLddf5nzhL#MpFgw%c25isz#HzvB6LB3A< zztd@-#mG;RAA6{Y0O!DT&!?wpFXs2IEWK<9R73rh2g-cM7H(aX-E|+uwc835GP?E+ zoCN=Cdir9~cC{+ckL&Ya9IR5tq*nhS-xRUS-TRJ%{rJSvYRMSjv~&b)lNeU4sd23X<%yq zL!zB$dd8w5Iwb9aL0IS`e7uKC*3WQ}DQtTMZzxzWTu_ZQ+bA>8rBNjLG7lq>+OqfP zu(Fn>%5kqOTQ?miIlgoQXDyLdY-MOZ->HjOzfq#IJK^fm^xzuM>`@mA=Y&p^CN!0a z?GlpgxT9rly4l^qwbvcSj<;2*_B2C!fYJOG_~LeS5mN&fwX1`)^1=UeMifdcZ~YM50gNU_FnogYD+PID`rb!k#z(sRV{hkY3V z86n3`p5k1ey%Gkw%=o9zr-**_6U;@t3_z(7$RYZts>*Q#Iz!Wxgn06S=v@AbqNuE) zQtg*6v7$8UeR%a#YF7@y7!>uXA>Bpo5nPlTwle!~2AQ<^I+{W8@T10iG+l&5Tk2^G zA?*m92zYN8JW8OpH-y{YG~sk2v5+-t-&nqB_Q0KElLCb{xV8yiVK^*Ur0uoajr@V3 zVmdfIpPa4D`H@;ri0+NHo=u^s-u(2_7@dvfEATG+2uM3Qgo}Y<$yuC?jv)cFRt;t2 z9(`Q0xsBt8Px=OV(hYj@Z6{_JaN zqc+4x(Kg*%?O8|1Zg~Md#y~l;ZFM-eVmn-Xs{~K3a@V+041_5X`#DRi;!DR161oE<}+Ywh7fV3OYoG_xs z;TWZuc9fYzh((!t!VkwOAAm{{R(pC%0^?_6T82ScG+~ld-M*W^9%UdanK8#qXSLmJX*%+06pj;I3Qec zi0mP5@uar|G5bz{wqM2BwHFpx$$o35{3&iFT(jkX!j%x7#nJTp(xO?C8M?GMQL4B# zT{HxAA(7jYW_n@lBimD(P;z*fueJ-$my<(`hT4O&3AZU+o{h%}@2dgh4u~Aq=+%wI zU^Q||BReC+S+dSw$y1?jh3_uzAETDvU5v2{d&@k;m3qt%4ge>J#(5!M_Uz7L99ZGT zor(E<;b!rf#w9~bU*>43s#oB|E+1077D!k?zc zQ}A8sHBX0^;PLRE#rg0zc0l|g%}vixw_VILhG;hcyrj(W&d{sQ3GqrGS3egmyhc7S zO1vUwH!rHZM~zJ#WKauIEI~mRiwSSoRGn1X1~$!&jT;*yMBPB^>F>t%jqC*S;l_s> zBSanj?{nU2JD$u?u70eFf3)$@2GJM<6Gk(yepdxQ-uQT9G=uNL_2Z>)gJ#0cP@6~D{z;63jZsQvPHS*9Fk`P=8N{@#gu zM7rt8m~&LBGU!*j7#n=I>nak^CRRP(WEOo+u-u7=9=X+hILjUn7#^J=C2P?VLh0sd6jkYsjGcf*$y7D@rmLIi{mN`1<@g3g zeCV=S=QwF!=ZYwCYgaj392uV?^hPc>h^q5u_*B@NH2oK1FS%0{1Nswz!CmB|tG}bF z=Vl?srJK7pAMJ%r5)^?OxWFwU#uRG~TWrgB zTZNZmwF2&am-4M;ZciO83**?EAB;H2M0-*o(KuHsuviXphoz zQq{#O6rww>1_)kcr&b}Xv(|t2XmoNpiT$W*6MN0B^m}+qlosU`O{{#UQTYoaSglg_ zvMffUOmP^X-+PhzRJjngISjt|*%!h?IohsR#7b)I5>^=AvY)Z%8Wy1mU`e9GTVQ+9 z7vs#Z0{~2Txs3Oo!($tFu|VViw+*1yo6zEy`h>F6wguMK)~eL*`yFC_@EQx5c42#j zN(w}ZX-e>t7c=_9QC8@tOF9m>NZr|j8lcV=-s4BreKp#YEI#(Nxjvkm5 z{_UY>MvicIrUV;LikydpP71DO`)2V_bXmNe?~?P;oY0oR)3zo$M3Ccf%)d>k0vybe z+SAiL1n`?2N40N_LI2A+or@vM$C5_0OLg1N99BD;L|Ru}m}~3^+LRPfSIZ*8pZTG; zQ|ts^l|x+sz#4_j(V}#@R;E*;uh^Iip02G3GQroJO>| z4qc>eKc;aJ%T221sDgRO6|yIF_IQxXh%%u&C>^0z$l6YU=1p@_pbk?syBILq5D0?; z-)gQ~hIOH+;I<-zPT6bJNGj5nQhD&ej)m5oe3!BY8RO-%F$c4}aE37>tzq$AIL&s? z!Z;#)MnniP0)S>;7NOq{9+2V zX(3~3s%z_<_Q%+u#HJ=Mp0k1jb8(qoQ-o{r@;UA5JOUg3WnqB&ig=k)$~924L~rg-a4%Pl zyN-v{&;nw@gd#;&iXM;7a1j`Omi|8N2Nu^@7Bnw?L2CYQtv@O*rS@xydR&RR;5X4i z5FGPsk39Fb0R95lo*S4;2Sk*v1;PR+n%zqW++pb!#3&d`?RA|nJ&oX3&_b9ZI{-)IV z)IP0=UBm!5(jc0>2ERCbzl3I*xi6D}KDrsg5m$gXzFqGhlz37=+rG*FCVB%|5yGT& zspX{d5@0GsICHWhs|geJRx2=SpY+E@iegEIAX7@-I2yybu$z&*z ztdF&)Fe*qgq@LL&J7-QxyQXb@Ze+7%Ru0macj{S(5H5wehiYq%WBB}lJ(@4nA-zmac zD7hHP*~LqPIuUiJ5W`!<7GUpc39Q(Wf_QhznFP2N8DAo0hI|;cl6Yw3KTfw9I7;f} zJ{$AyDnY&K;6$P?6*HkY`9Mp!ZS)e5hDd3rQ(XK%qN!P~9u$2hMY^tELJrM$BqL%Y zhdBWIw{S0pD0#$-=J)O(dXI^f_yM^Rnkt`kM<~$RfsvM?i@&au8F!*nn{5pPstaPX(AAj; zVQCMgm;4HNRO<;4cC7^*xgczv%etL1=Th8A1(g8G)s_Pzzr1paSxRWZz*ZKmT&>43 zQcYS72k?v4FGf$1NASSF!c`8V0@b@{rsnP$+OhoT)AM7Co`xjyh`QHk6;l>=IjO#w z0J@+ig2Vc$oZ+p15$cwhmnlSt1&=B~1ih(^+r=1NpahNL{JDwvhp1q1t3Ox%U7Gf) zHF57kpcyM28!5R8o1KWBgDxNs&8;ls4&<6Io1?Rv$hE2h898 zR%0wL^;)UcZD?Fqx(uLWnn;>G<5+d-Pqppka^(|IclTP$7IZibGk5bAdjmy|Osxjh zh<^Z2X53alKrHxkJES0(0MkW5u9h{ChHhJQ{E~jiaRAI6xW;PQ<1u{-{4jF~OUB@< z@iAM5@r}2pIQ=57m#Lab?em#EK0kU&M>Ck+AOWd@DV6rmkB$(52&t-t%Y+M8Vgd+r zZA;@b9~Qhi>mh-PYnl)zHIO7w{t-tF9+ilb#R`;IqK(fql(`F!o7XKkPU)G3){jO% z?e33H&Jeh))k9jUJ){@&f#LAIM1~q@Tbn(YAD9ALl?|QG_gM}_ztJNQE5bCrON}ge zvuC`JrXJ?B-PKpqcw5PGCHgs&vY4wkePtkg3Ox4_7#zdyg}*CwRZ?x zbp8G2F>t;8`=PnMb^S(jO@BBi&C9qF#ImD1Km1Y=`3*MVS83aAhgKbxZvwqR{(ttq zyg#nvxb|=8Q(Qry2b8c7q-0w#Nt+@m3kkPy@$x9W$p9FVV*&#N1BhZMe)o6Isj6P? zy)yu5*-73nav}|GZ`IY+)z!6ifOstl1M7$-#s4Db4Jph9WnR8Z&>rB`Af%0s(?6Zy zmS}GewqB&j)tQyS`9&)ANCJWKURl7R8ag2r@{mJ=v<)w0cGW)Ag%|5(cjUBr?6aFt z!PemBe1g=ttKk5$*ym}jx%-!=kB3kGb?1?v7zT~4LShDzC$@lr1I)bcp zNRMEZc?pX%t~2x-H|J1ufC*0I2d3SCd zMTnfN(nBhJhWoH*>NyG**G69MNtuZG<;&P3OW~as~U>K5rSW02%K#2s~fa;Kb>GiSthU;{*hq# z$H~#z%)~OB&n}a$cuHfMeQ*)+`0SYHj-)Fhm+@)?&BhbGaRJTeY}K-oXW$=6uOuRPD~~R zGXwYB@>QgwgNuwLpcQkcAQqB88+ykoQZ}C8bIkM$%$#4Ym!Ay1{QkukS~0YB-++>y zQjwQ+)&L%Au4_LWz1<fe?Nadak6NkNDzJ++LuX z6E{FUk@b~{-e9+A3+^=Pdy&S=-~B{)z`la(;j)9^r&YUkm~f8Xun@Ba+Z00g+&!+I;Hy2F8Y2@M zz?O9c7pqwwdl%xh@I{=!`Tmtb3t&qjA8}Np1HNhiIX}zql;7xm-HNK>vPn#lJhL-} zh7W<7QwCaECLu`KXE>Nl*@zCHggZo*Y)W9f)Utimt@^RSARe;{FA0puwj|>{5FPDJ z0PB7@w6RO|vIhm`E&{r+Q{V-$e)M8}_IA2w)z~pa41(6`G0)~HbA6+^La$Ds`=+aA zq1uHPF@nIsEx?d97vEfbIh)fG5SZsKE|cczVMi6iO=JE@e~Fkge^nw6z3?j3uiEsj z&Gq=5LdvszjJwNd+z| zcWXy~LT^z!_5WED6QN#@f@+r7x`8nvyh)(-NRJz0tUp@@7pANfU_P@n&Oc}#{j;8q zeuV$n^sGJW{@Qd{PH!h)tclQSQeC@2&y~S(0Y+pehNP~RUr1B&{FA~eU z8l9{vc^b>_y%v=(pIVL>frsO{u);B9hdi@vxF2nEL6O>tSuZ|o4f zfrQlW#vSJ_1j-PWbvAUli5+KE=Uq;p^?b9g%U|p*;HTJC{kWk};~6|}<_uU1Vm{(l zHKMABr-IQTb+Ktt<_x=aMdSWPi`P3YNx{e;_&V=7thl3mD?N-F6i%{SDm{K>jxz4W zZ=S40Tt3}I5cPZCp1VSn{>iyP`1e3te97;GHmrz77Vp)^iihpoi3(fz5x-l3{A^Z7 z&8s7mE}Gq=UH<i>R(4*` z)y|hcKKO3+R~1-BuvK*Y9N=ubG!~s6kqzY7H|~$1%t68|ObXY#+3dz4KJZ5e&e$HB zEqbbh$W7mCli)Daz+++(d;E07>8iG0{rWf2d0q!ouR4U$@J3NJ;VWL(4mj+=@NR^? zqiTMH_%qHKuG|t+B0@aK)W823`hz>)JhaE^c$vbz`V?{pjz_)vr@RbE3`t-p47ZAn zn!)7k28o?E*tuhI;A}C3(tI+tzsprAYK#w&vZ44pYgFtbDT~jdfWv0au!6)F!=ACZ z;;C-yd7vSrGKiojXV4#+f+2R~7^-pkd{Gr0`1#hp&b}uWG4WCmPFv2jl{)?JOlC-K z_qNDKL710x5Dl-T3`=o;i2k%Iz9ysUjHDB zZ8us63Ur2QzZQ5Ud1EOFA2T{t-H3Ajp5T0r*X{8i{glN&+qwF`QE)yHUIypmAmgU_ zTq|!}#y^y7rmQ1AQ+~*d#=nx5bv4u9Pd_*;pF2+nO99ywnT5!d%7Hz8KY-U$Z&Kb3 z;W1TKWMZQ;yDWYV)7i)_ub-QvjJ@28PQVJI4!L6P0~@0#GhgrM{^BVFh-8)6ziZ8v zFSoD#X8X#O<+Tb@&MM8Uiw3>v^AgYeO+COO)$L%xj=CFjrUmiFq*QzEGnV1`yXCS0 z-2C(O5HTQh2`yDgp5pR*@!14bH3J1w>-3U_V}OvV)1gQi`LPCO){={$*rd?gnH3Fg zq}Ll&W6Z{*v~Q?_dKp3&lhFB#BoKh8qI+kY_ZRU2@skBoyY#^M>IxNUI%!-}=cW9R+L<+cgH@|BD zNtx{9vMw0*^1JNmmKVX;d0Z-)ab1%J%U0f`$GHenh&QKS&VC*?2jJ3X#3Qjw-E6Ze zk)^SRdIdogkc?q1;p=_j=r(|qB#sp8&5>HD@NsXBC5Sz?C}_Rg@jHOJw1OD7c=Ydk+u7zMb#!7` z18mA`DSH4dUhFHzbe$CTwFRx@;>+wm=`qyEElB#kep6cjqvweHH5wz?dlZJY$iC&o z0(OBOO36LMXCHO_CQi5Lfo+B%R)pTkwJHt`z$2Y7qxR}6(MvV6$8l$rb9j-(olXu zTS3`E%cEsW)v_d!PGytzh)ON9Wu>F<8LbZX=rIzrrylBos8y<@7=)7JTY7Y~N8Jqg z$fkM&?Z5#91kH!0b+g;NMPBP6VsD$0)u;hHDc}QyR%{Ksoik0dhUFU12X@Z!G%mKe zGH+N*V*<7ZGyh`G1`mKQHH%%AJZIZFM=&_Kc}ul~tEkF^c7z7BdjiKH8lv2&td#Vb zlplJsdft=Qntz9FL&!6Y)xSe`0WHAE`0(gQT9AB4bo$i7>ZaZ7Sgy$C-;towF6??# za&$1G`HB7Xbd!yFyJz-z0389a7hxBa*~(RI002*iibW!LU;?g!Qh^$_Gys6CwK?~u8>l1R2?Q&p*U=r zI^-Du0heuKCn+PVZt$>dXiaWSXK&CFU)Yqsj(Xvj-h=cYf&759Q-x*=7@T7qyklPN zqLvHjMB`$Tx4t99)V67+REkF357&y;mo5j9N+NnJpG-hqN7xdT`nIGgphWYznn37) zyRsTvq`agS-6y8GbLTRCr-|i0`=|BWt!s0Yy^9g@)o*^gsAUiPG}JHRpiYfoS|52w zg7Z#&F``fm-)i5szn%q?ZD z)Fwl%M-=SG`+SwIb6(h;frP7&i=IOdMgWE(@Vs={&^)EKx8d8wR~P+gsT0TbO2`<7 z^0MO|(6ljcC#78E{3PAEW8!GNYJQOdO@PSW93P%JDAHm(JoK~^&Oth!ECrR5`@QyR zjJILFPUXET`tI+!f}PY^4^mlTVi4PBeBX)B14vB2j6arRaEaYE&wQP50o|-5&0uE6 zS*~Qv$>vyr-fAQ*0-7v;3mp{bQp-kaZsEYu1?#O{11cH8jB%iP+B(=UpAz#<%5{l; zA=~q?)Q9ps*N-9RNbo9x2 zn=uftiklTO**uak5G5%c%C^4-18FF{qm>=D>NP7DZ(M(if7TBV*Z23=U%gtNOx9;P z4-1EZ$Wur{xn(h82yCp%abm2v%E`o8hs3LAH%75IuSm>1ZjT5}fO=XU#%cPu{J|9n zDI=sf0iQ%L0**_j315G4f=9*oF@N@(qTNMBjfQo6gN2^DOof{h%liSr75Bz<{Hr^< z4_u0L=m{`XqvF$>@or0+jaiD&Zd^A4OtMc*uYZ7wI4i^fQ?DJ_{wo2^nRAYSCTgt( z=}E*o4;L>cCs3YR@A-FM|0?Y!s+0cI+NYm=%~{xOUBsQwOLX85>l8@iPoAKbYCmRJ zp$sYCUk%6mc&cTJ{0rq@3ARLSxbDy`5dBD=hs^|0!6G8IYuF2F;Qw%JZZzNGDuJ*! z#17#QRW_1p;2DT?T}v6u{sdp-MnLsFnN3O0hd`?GLL-AbRt6-;KI#L z_iux|XA(0gmb>_{ev|lhvrydY^~v^nD?~+7m{in~NQV8{)Y%4Bo^*=nEH?}#&rw8N74BxZaHAzPEFryTRU@c3$g z@vWghMn)h!z@Qqr1Uv%=q%FKFP{Jx?SBv)13Zx~1qj|V_8`i1<2e>+&^@pv9gr7+DfNIN>kjv;JG)$Rhbcb-}F2X>ts_II3k z_XqZy+O@hBb@Z8tgmLcX(n?gWD9Zpuu~g6H0VJVm@B<~~Qc~?{3Rjd6lGKQy~Air*h;WwG1VF_gRGG-f;bnZu($0Czz0JF=ANFNOoyU7 z-F16A&>p>5>&z(X%Xly*+}XJrQhWWS zGbM!63njdadW=Y$p+B3xo-&G8bFkYG56yJXD$~UWpMv(zmCXQMlS#wKZ`j-#%USs4 z&bM}n=M3K*2vgU#35mAOCJqcnkPtg{0P0gvC#7+Xhs(%Fz|0Dl*3q;d<~Zj}BP}-VzN6!jUj0ItKsL0ty90xS{fNfoXy7}m0;YH@W#(MN%jM7M&s#Y%WO z+O+T_=5isTo=c55)+;eJRxo6YU?i5WxOH6EfuG$gZ0zMn*v95itloUTbJD)`um~jI z1*!N5ekHm;eDrkZ;e#iXP$jRLne!s1gJkdQwH(;S&O^nemC)YkDkaiAslJu-7NZxH z;m`k*sS}BS>WFUh^&VI8d}8I|_!d;x&welyE7ElJi}yUDoH=AT4S`)T+U2Es72K zVR0d$FG)5!8^RST3JmF2SlD1VedjqPxYTBc8aRFOhSTzjA(uC@I5SgPpyg*ki)r5x ze>&n*M7uER>kg6L=UwW_#b}qeG=L6giU4u!^0Jq508}};&a))x*(HJ>@>J^5;=EZz z|D`-+o;L=?iubEnmX?xvDxp_H z)W8&l7feosttB;LC-+avE@XXTPlRamVcCUxHZEDV?yl~p5FH!Y&I+4CX%#VJ)}J4h zT)|vV{>LN|LUx?FseAHTlPwh5)xb`6Is#qc4_mgmDSO!8{|_m9+@07|W=;>82Y@jw zg}*D_K}l(ONM6dwGhe^rsd_3cU+@;hDxd#E*@|emrFzo9&^pEasn8z)q^vIJ*XyXq zeC;s?WorH#5Y!Oet}E2cy}aaRo37<5NBW7Q)6s!dGxgWXfgVz50jk6wf<_X_JVO34oN2{LxlM7-705-!xL?O99z<5>F0r@UG>vcs#|Cin4y}`=UJ+g+{i9kie~{Ayo=4eABehbkNWW97 zOBRFb+hJkmk|%`_t5Y(Iu=Bhg!e>DgcTr#FT9&>~2gZ<{n^zDa%k@W`MF_RUm~`%bDIP6K=AW zJN@UwE0T75X@S$IgF)iTkkxFq#65<_W;H(U+>8gNe5nZLTd->M>KCbafiv~Du$RtT2|wir!KL*WK{-t1%+i1Jh*a2d*`#(Fo@MaYXyuscR5?8z=TJp=2RQ9 zqmQD&%4X5x_wyLO!z|Kfq(#m3k@1ER4|XJ^;$&2%WWkfEa}2oT8(hDIAVv)`xSMwt zo-JLzA4mx%pLgE-7Ux%VNSF7ADW+vL!FI>COyVdKCDVtRy;nP=-*Dm#{26LrG(PM) zh6-7XI*!)J`xlUjK5IHa=krP+)ye^|z;z7Mkh{BEE7FaQ4<~1MrvtHbsY%ihIuCTC zb6Iy#0?bj>>FU<63*{z9|5zCDUJsq)m=1LxnN8+`R#xhT$ppZ!3b5M87*N9Qd*nMH zjMTV5^Z9||oeNji$}bko`O;8AqzI`~4Rl`|S_S|s&D#^1WB7WJU!Z~6ci&2gDY*uU zE_86=!-O2go}|~!jKc*FGg|q;P9vfLy6Rw?J+aC zzn|_Tv*m7};YRPjaK3rEZHj?)f?rb!V_z>A2`gQk^TQ8}i_P1B19KD1nybocLW1vS zxIMg|gA0I?lcpY7(!)zxZb$okJJJVo)3~eF?372g#luo$s-y{3)E8wgB-6Fp5Icwr zlQ~wD?!zS;e2%)wkVL@*RKom^5no?)%7@0#N@_RjDXD}^U)1^t$5Gt0Lz0T|%*uqn zXkdcN3IENDgr6V-q7yngCKt~(Bcz`Y@ygitP7Mn<`-YL3i_nIaD@k1L_@c5327o}} zEgYTfxn0d4_)IuLtrABU8+#>phQ2!P&*-wKv3`>-%3MQXNwY1>XNJPuWig97xdsOc zZOgZdvm9cm$j`>B9U(H5E5Ac1P$^6?Aw?cL5>IOhTgU3op`yu2i5}8CYHmOI6D-K( z-4NQeq;d=IX?uvgSp~mBGD`Q!sGKqAts@o(^$VI$wQW;B@PRfXB#dcOB#E-{mVd|7 zl6Zn=-HQIbd2uj;LyY2G>Z7(J3lri}rad@fihh8=GX*h0F)Ic**>oXfBhVbd^c4%v z-ljhY;O(Xp=)g6zE|j?qQ$nP}q9})AO3~?^BU+kmngI`^gDUi9z~)ChbXU-39`n^C z$YC=Bwpp(unMt#WC+S~po*r##J{x8BrzC?QXTaYO{|@Uo*bdwaQje(y5W@Cb^J|D& zKqahJ)=GVS)^sP*TDerWcP3p0Ydxpb`U(8opo!Eb{l% zWngG6ew6VUYu_Lb!@m%LYxH39XzA28aJLpes@8T1(qp;&ZM1qiTKkCva-+ zP3xje5ytTaLwSy7!eCL)L24D4250WQ1dPdyO~f4SpS+3dx8JLg-{?U3+sHn3@3>N! zA+P9MVQds4b}>j)hRx1bn7Us$$DUJ>NgkyowzC3G&NBqq;OLN9%P4F33UMIC7_J^j zb&=c>xzq8gnT2XyhCR$1!o?b4dpI|vTUA9@@wazndYzmSDT-AcX);nqq%YT+ucYva zvoMqo?(w~R`{?XopDcq;K46xuz0s_G_w?x_>Xm(-8sR;v*|ecHbdY$OyA!FP`&9Iw zRP71jf=1_f3zU50yAO>Osf%m04c!p49>;pIIS(lvI#Bu;zaw*ndH7@;j(f-|eU=lp zlfN)s!e%f=+`u_o^uy~g`u=Et|89G2>WjGhWArS^V3(%zdI!)j-QMhbFx!fbB--G$ z4?HS?1|okTMA%&Ebq!duFblSrZ&T?tuYxGU@gjvlz~BL(!%CZ7++_@FXTQl-_+ic zPYtjk4`JwTC1dOD#)T&j!4fps<(i}w`EqkVYb1)*{FNXGS8AltJ3vM$E*Z}cyfTIxh53Gh5m6e}8}Sr|X&hwO zEq=e{gB{}W9-)YDC$x$#t;7*;tRx?*L%xGK5G$jXM@9foTn~YgPYHXmE!OHQXrcAF zJ%mwccL=B4bhxB(TKyqHDXuve$qHFW%yEi~qs1a(ScE&gs|P8gkw7UFeryf6t9Hl8 z3CeDdVe(H~Dz7EGFR8WeTH9F=6gWm!Zf=gcW;kYI(Xili~xtq|}KF{njZI zSmh52|I3E0#0d#~8BgeI);b>iJgMm#0gkSvBk%=f*C$(dnsm(>Ty*+HTwFqV&$)VD zv|HNt?WcCr)bb+5=GK~o(^Wn9c%G;=bLWN5Z|jxw-n27~Jo}a-)mpd^&aJ$gn%h)< zdx^pVGTS?L9()j2PDvnwDT6-4$p>61us56=ITtmm(B}*mIy2bfh)1V>14{E-aH8ir zhPVaXJp&R#4%C?z)EE@@PxKxX;5bU+u58CTauZ|U)WncQ)3)42A+`RdLyHTfKGtvY z4#e4Fm$oYkUj^zv4LQ7G@&(xjKcB^uIEl#Wjn6Djq3BD;Zbi8t)RU{Aa!+8*EtTf& zS7W^Rl@gzX3qO>IlBu)e1HllZL(g3k`i_&yk4zxMEb)`QoXIxDa69_=A7K~6+sSPy zQ-E17vSat$>p@K3i9Fw}A9IB2`S7@5`v4NZxnlhP2*13=2h@%{2hs_me{vqS-7%ac zk=oHrSaUb)WhsT$n=d!6ZEQ(^MK+oralOaIichB*;XqLJ=i#A5g)tN_IpU?Nq#RUp zDo%Of%XQy?MDc#c*$GrTcEY=#sgL;$p5%DLkzMCX@tDVi;xFSN3O;)3F}eLqnRbkN z{X@CR%}R8~GU~VHtoK~>q|UK1qc7iPqJx^7q8q$>JfkZk7KXt$5Y~lRZ0y0!8wD4= z$cUsSwA(#8eTA0XvZcU!v7tX|;GQ9M>Rbfq0!@Ng1pEGz>%TvKb^OUEzIpW6O430M zY*!@gm@xLcPeAD_(1RWw9F6$E>i$HDVpf~s@Y|hxcZWkP#6~mNMDqXrqm#|3xq*QY z=B|;bol3*xzWhiz8UM!_QicwX_|{e`)wr=w$wIluaI@pR3w(hHy^H_Gqd;1j`PGs6 zSLrm==39bu+qzRb$BNL=u-CE%wjk0&A*9B7kA_f+WCn1LsIfG`$dd9=q;s zBW2;l(k6Rc7jfhyveI^q_ z-d8XPKxN@VNv2b{hSXS&%@&}j8(Je__Jz@PF2T>E>Cc)wowv3qJu@90_$*HTqm#FS zhxReEC32y_1Nka2>Fwczr*|Jb9p2e_{5w1shDUVx&n9;9=9@QfHq(ORK`kIbJtt(b z=4Z_xBcv4m?_gm_uWgUT&L38f9bW$306~T|deZn`{^sjnU%m3>)oW?2d0YNt_G;|K z|I%&a`-K}N60aAJAN~(NV1J^0UPr8c#V#!m%k+dM_&0=9)OX$*EHoaE>9xEJz-Q=s zC)0>~kkHZ*-Ym4pP#(E!Ly{Ot8Pw815oThC#$NA8Se@-Y~jmno96r-(Px zu-Rt^16F-&G=sWs;IsXK95wLZZ2I}2oTiO?3g$>r(L}gr#cCial`Ry9c@K9{xRAh` zDNp6@Pt0UMQ{YM%UA%{w^2x~&Gk<}ZSXb*h>Od(gV>w{m$2mWGIp*4P4D$Rgp-5pd zJAI3Tl&dh5EBVpE{xE+FT9Q&go2hcsN7$xVnKY=TI8Y@%K|@nVtVUUl_{a$bxNXZ` z0Bwl%s^|;F{MAD~9BC?N?e^SEjX2GOXjYKq3MJ>$yZ0YGe0=NiUo#4nSjvcL_iTb0 z?>vB9J7r=~TGG3-n(`$AfG^;V;{B(E_ z9VCAu=5F7IvCtAk*nshJEH3nWud%aX1zF!an4sz&$3>Asn_qo=7## zMKS*&>|vZ$hxm`E4`&nBj`vy23?E5iqtjFPmg>Vs(bfKu5(B$DZB|Qk|6=m;3_cKG z8tQ7*y^Jpt7*ccYO*A1Vze5Q6c=kkMom%zWM04e<;%=G*Q)>Hs z;!d3;Ks*Qwargi`iwZqp2KoN)cpfK>i?xef;1Eysu6F7&L+7%$uKh$)h~DPW5(o(- z#vPW-pn#?7?r`)IdDwV31L@tke*c>^Jw(c3v9NcFrZEeTb%q|3&ki7C#>>&}+f&CQ z_U^joJulIdBJsZganLJqn@e}xkShUb$2g7M_6G% z!!~Q2wjU0E#Xsx!@2}svQ%yRtmWvN!_wo-Kg>dSaM8Y@xT<3|oU_$P{iCLtE8&F$P zX9(SiUZ|k2APXCI6_0HScU7acOHMG|}l)?~kpw*UzH%ECEG2fVEc5$oLYcu;k3 zygqXT?l&}3lcVAl^=cfWxye4J-yNqQIDwAF4U%B<5=c&4y(Uf15xe$61QU{CW24+f`O#n z!a&iW!iX>rwBT{t8`tf>3%bg5YgMbR$Xb*^+csn;>CiI}5EcziDY#<$rp13sp2Oxj zy^*wbgLm{)d0!ml@3`~dZ@inn=OI4GFqDE%Fq&UZ^x=`kfBqS=PmJ|szVH)OK3@8X z9?lVeP)*yp2a_OSY?4$uA2VrxBjeiI*3~cZ|8`8U)Bm=UO!}bwh@cDJbEcf8xvXcU z#2&YxA^4S2+6E2FQ)-N23esC8~-F1 zbUt~!DfxeI`0DiVU=w@!d|CP8)UsHkHN;J)t9nlAhLBHrS4IAI=r`(rpcZ-X?A|>& zg$@9?Unf$vsyxpAREn6>vc1+zm)kT*e|a36QljMXjdd5jxB3r`Th!?Gk4b>}MwMRYhlvTOSALjZ5eybdAXGwmvN>%$xAWY?3Um12={G8=zeJ(#{W9UBc?{b}c6itOL zKdZ>7HCgh+F}M&<$m^48Dz&H$5}mXyNh4Pn1x(8?BY+9H!_o1iumVt(d~auaTONLc zCvzFERDghy7CA1j+#O{5gzqEL2WEW4Mj$6A$dLS$xw<^Gqd;c5ih`#yj)4NX$4zLA0 z7BQLX_BTuyCk^3!y!nZ2^z>CUAo?YlAVv))zf;S6XA~hDQ@fnnw?u5xX_k@=m2TEG zycRqs7?o$CPwdemrUehLqCRb*Y)z?V@^BgSswG5+YBA3`HE(7K8!m$xNv=@LB9fpY zn2o5R_|GvPbT=<^W;B{iUmStfSx5VdJ5^e@(5|H(Lcg|Db~<3OKZ>0cvj_@6EQ`#r zL6N~>sChF{Prs&k%>)5`MnrHVa%hpt80!hJ{<@CGxm0Cv>B=?xrG2M`kEu%0H{buF z!ye3-_X0}dPjN&|rem7l|231O5TQ!UD0Lf=KBptx)fKLd9Ym`ywIHv~aChe0k^6cJ z2_VDP1_U$0gbmFAjc7i`&A{k|&{#J@@fH);?Iq-@Ck!nR){xcl>X*_t7d47~1N^DR z=S=~5yZ#@GNu~NlC++%A`|1~+wCg|Wt6y}|u79_$e$h$0{{QK#Uv$#0|JT0yMJHBY z24eTm$c`UiI;5(~1H^nlg6GfN`=i>RQAkUDeXvn8=i3lI^s?P+ds zx}MudXs;c~284MvDqP$96}!aoUd=JZl0XA*98gT9tkgO*UyTkHW}S+?uuUmwdvrFhmSyD47EaN(>J~ z67mAJImk_Rf3gbx z0ys=JF;X+G!qTPoQ)F2T)7}6oPsn~Wc@`zbcCxKNa?RxtS#~y^{0AM2Bvqt1PtZ#k z|8R5`&BQB7ZTTCyGzG2Hcck$u7-%MJg##W+-J7ERrl%{l$at}eVQQ>(bUe;8#s&gsCOz-}1j@3tqpNyJ8}v6w#AEbZQ^A5mRqdd#iT?0& z0TZ**{-f1x8Q7!|9`Y$z91{XyjG}u8bok%p=J)#VHk=i7#j+W2fPNA^WQMoFWO@ow z6g)0*JOpUS2z7K4Sa2W>5#m>I-HXX)4i!3-#GsZ_ooo^{t4+4mu!;;d5hdl=F2o?+ zksiS5$WC%IkI({?!wkZ94r@TDkE&x|fIyX6uoTSfgE)%GA`@nAh@bt7Ta+$hBdHqP zO|%eI$CBo7HGJggfmINAf`OYefpXZ8K!yyP@$K$=#42u9p?>Fb7 zBV*y+Rhfh7Xla;^zdi`lrdI_z>_HYqBxF(ZcQ92Hp3-&tyTX#5;^h*C4ICQonmUflBtxP#=q z;v#`}$%6|S=HoKkn$XZt6+=4W)Lv<=(#-%)U`RPAQcV@;YsE)QaLSB!CX3+v%Rdn zZ7!hugZ5R}BY^n$>C2^s%(uRxw10O&&3lMNje0pAAingR7i!b9!TkHVyKB%{o-|lm zCoB%BA{ER>Z~rk74Gq8X*9Re4Ck@yhj5@%x{piPXD(lBFi;>GEUoWiw*dI61lEqnU zb$gH-1@o}mK`L05PGmLQfM~(VhuEE1lJsJN054V}l-*}KdF~U2hTP{o|JKrU#@5Ji zf+g=hcv9DmoS8OXX)zU`b}h|f@Y=lEj`Q8;dlz2Nq{IthM&YqKcbBM*m)%*lmqA`D*N??FsqmCj6Fn?8udgu>_wE<~I_TBG*TWMf`LXg$U&Q&4v1f_L*<(=Hkd8|@b?yG4Poyuh?W zrERuj$}gkrdrk{m#8~RomXs5Jd;sOVp!j-p zJmy8%sV92Dh4qb}Dz=rQLXgAhs}n?HN4$mYkA&-0xcVV)+bM4By1@MTQDa*Of#M9! zXgDZkGKh$v$cC$oKgq;^lNKl#QQKUHnM~vj&$_@=Yzfg|GVbQpOF-pdktG9u1#1Pm z?P>EAauYUvC(5L5h=pEyv3CGnUB;h4)y_@Kp`Vs*2gBmRH3%yAnF9x)cTHNzFGP1X za1MIT3iKo1F`XULEhd4w2}d$E^4wka@Ta$j;{!<07HRB%zUvaaIeIHn6JARZDB^Be zF$2vF!4?XVh>yW%R-zqno2zKSfOfx+iB#~dk5vW;!#yazM_i%56Oi?rgaZ!qGyL*C zGh_%_n(94y^1%y$7d_}1>GI6PtE`8!;o0en-x6k^noDE0Yy0y?!@}Ws%Bap%r-hl= z9rZ9m6_90dD;~D;nAsVSdXd?%^!6-t%{mL@@Q-W)II(EQrx9jE!lC=CHaz@`5n#di zj9W-bcX)WFJmC!z!s1v&BC1yt1a7^AhX-!;%9XAjnCc8?Cigu`yeoDTks5jLDrSvy z2cDr;`L}0xAOCfD`@3fk{uR3hk0grM)=3(&k5b{IHn7tQdL>$7J-lwozM5lM`Ps$C zs;b}Ts&A;5{MyR)$?DQmn_ggL-MG7yU$GI3gC#)6+Leb5~sOZZkTlOAc7Khu)q2>343lEPh@v#x?utk-``C6x$xiRIzoxU^U z=j2cfHz;(TgC23lv4k%dAH3M!&Py%U<;??MXzyQOCEq)vKauI@pm5Af~S^9t8%hr*%^roeHlUuVW``UnksXc(wBsE+}AHF6YJH31eU}OYY$V zV)ALmFvF7>u210rBpcA+?BqZc)?Zbn<|{Qg7$FTad|MY(&sDq)JiYdy@urvEf@W1M zZwW!^4i-kOFk{+y@jB0bbHDj(^WFAjd)9n`D6lJ(3p8h;Cnf_$h+;7KarN@=A&i_d zP-pn+=rA5s+n$4*a>m3P-(On*daf=?3$loHnL`jDU(daIbTY*0Q&Yz1`1s(h8#B3H z;Dxz5v?HXP>Kp19+m)1*f6p1+HCR4q9fyg#gBK@~vMpp^N#xu<4BE8!3J?*Ago;n@ z-n)DIX>(`i$u6p^8*ezd-Sf}6m=EeU=l zf%Dd?_*7DX3Jl&x5>)9Rv@e!NpNOI=R6C}s49wWI#H+_-lLV?82Gc^Wt=(n&utpzv@mf>(-S)!VCk6L`yD6zCikUGB61 z%U_rR9wIzFGtUTT&;~Dy1iH&rev<+KeFvkLy8AwD2kfQQ)Ci_17~=+ia!ey#U!Pvu z-)A%}`-Hp!kM_OSd5DrrT_t69a3*ux={M{$HvMAWJR%gbS`;-A6b8$t{BUBn9 z7;U)YMVP*woNUemKZN`8uBSzC5WJ)NcLxZRB5+73EAk})$fM^RfjVbfeRi*E; zpu@KP zA1$+qLe>Q&!RTw*q)GdGS$l;y*m@N31+7Mw?+nv+*VO>AG0zckVRDy1`_5%x(bxOt z)|2MAS<%1_i2*Ho_bv^Bc<~_CHmNmp$^#^nft(d@-`d@ji%r{CGz+W*<;3^cgRc8X z)T{E6VtPr}y4P570RbYNkOzAsKCP|HN>o+wyeOBZk9gUY2>l)KTX^2-7BRnp#7G8K ze2d#TREm+_fU~fGdUn^|Xlah58Q9ad^#z>nKQ}jM> z$Qe0K_a4~hO}jq7dZ%qpRY|``CoYeI;akvf=kgfKbi}0Lt#hJ=6La**MGGEQILsM% zX}QC~amxv}7aP_aC{mT#W0$1np((Y6D<2Mr>7}SKqH}YB=PiS-+X+Av!Llv;w3=V!A*FVs&ooMm2)Wx<3NBy%>&$ zhp-M6hIP|b@wGhrg^ShcBNK1#;g?vh>wU|0_1gAVU*rESyj(_GSz_#2 zF7B16#-nH#0hqiC^-?K}CMAv9+itn}$4?w$9tl)CFhMhy3O|Gh-r}F(Vch*)d@Hu& z@=DbBVoQY6tZ#vmOeNZT9JFQa9;7-)^P4%idK;bTa05OW<5h&TSfjP1K3vo^9p^2s z7$A}(#zKPn0aUVHEgfqlY*f1a&9?vA~pPn=ik^k>_1B61&$%dIWA?aUUF8W@?4ADrPyRz>s z+M+8Xxd3zhW~a(rBK+X{!#ixX-n%Oz{Ay-cQb)C?3j3jnKN*Pf(qs2iSbdQb3tM@Y zT$rp;{hCR^MQ<$F8xT?Xd060-X9BY!kZZy=}KdXD1paw#V%?UtR1;m7bM~t ztf+rNNz$*2(8R)9!*9&@Rv zwiWWd4-&qkJ4R?3sLD1#CTCrK!iuMEfa>%c2=3))i=;M5WJZEI)ghT>KSD38DU{H# zp#3z8Uj+1qQ*;G33}++2dx4&mP=TalbxAFDfO}_lO=F>J051lXRaS3#NyBY-KDvTo z^l;KB@->XPX0#O*x-gRe03lHaDzo_M8s2KsP=h)KqZUT>PEF+vW=W2!U`5{0qF%S- zpy%*UX1nJDwYFpb_h!8?09&PXchI~B3i}o*U~p~=KAeDdiq`>OV3?Y~ageYeBVDnPy^Ecr^E`yGIR@ z58#pAm}5Sr0GL~3cn(=dR9)~_MW^iYxqVLy-Eg8|B(W=Eg(u#YuLPzF0NN<1fhZ~} zEQq-k9Po14Ad$JBK4Eq6a^19`S}aL`>CV}8$5Czu8$@g7-ix)*=2MQ7Tpinvn=A!L zjdu#8?!Ymuq0IJ`DWgl6RGu@B-HWTxIwy#pPE6);BP*EEP8IxKtR zP)>xDi&^>iL6zH?Xw%7VRnV&3F@0$1w+i*%3szEH)9eNh@p)M(l_&eVC@SO{O9{f+ znKKCP*Q9{#4Dxx$^Mjq0&L1xDM&x;%lSE6gODhn#S=CLsH`+ElrjN4O3>C~kqF^JO z);b12g#2^;rn*K@iGPUot=})S12aeXx0||}bub)5_=GKW?={95Q2xv^Tyos1i{L~7 zg@a{d3ieYE&V8`dUL#{DgoCImd8#HvrfJh}kxDWKa5IEquxkSBp%V<_a)XIAt@}Yc zWTbt38j7^DNxE z1(XN6PW_YU{Et{ABf`IDLwJW=G2asbXR$5(6CI3Y#)XBHM9O71s^Fev7vLM}sbU)m z&qnD{w@ozOxA~-CeX7T#vdisbf0-gVdFP@|_>0Fu*n(nQIy1nH^a3#};f5Lx5WkFD zKaitm9RNz3SvaGRau?fF)v!x@pMyx8I8Ms>uSvv!wpQGx9}-Qlf0T0*I)FMV!}p2+ z`X0t zY(h7~;m4A2cB-x-e5UZl7bE9gbQezXkOKiykTN`#PUr}2RTQ753ZI-C4~A7122PZO zk;H2vhjSs9xE6;5ZEik&c<14EBY~O^hFkhEgkvI;c!+Q0$+jSMh@IS7Jd;!b$@5nF zM+%*AaQUiE_lR3p34W&$`H+v=n-LQ8t=sq3GT(^U4LD7eFEA2CcKYCXTh*xAmw|CZ z5*3?k8 zRGM6e4}2lxj$vCXBu5-1kL7JE?LpWxX?jk=2p;NeBE8)M&K zqmJOYZ_Z$>CwP3Q22M~2U%_99jzzT4^d$m5_0G`Y^ywHtLfIpRjGA9NfCgvW0<`r$U~~I zJOj^OYhr#(#{I$9F5d(!E)SuA=(smZ(v>ai-hGx zy!rdf$spxoazSFPleXN>u_MZF+GlYUS?QEe{50x$g)Dn~rc|&jsMm_(I*u57=Gh4BVodf)zX21iaS&iz6g}FmmXFHmF4mZRN;f zr_B}GBBzCH4++d?bU>Zr2~`b;T@_5$t>3QUF8ucB%wmMWigw7IEKV9s!&nJ9 zAs&jy;VS0mx&o=4>H10}P8{tX>S7!7iB&ano!HW`{Pz(d82Adx8dvmH{ zw+Cai-o@*3XUELOnI^J9WFFDk8CDa6r<^u=)a!rg(KbP0S*cK)DLs+A^LV!XNwc-l z+&g+nPKzd*g6bNwNBf6(strQ>2yc}E^s5`qA5rTFV;>#NwwoOrU-`@M$Xgmt?SSLy z_yDc0ZQxluNSSy%3S&3Rsot_r0LT-*Sjsn1(B{jH<`#3E)1B*A4URq^OBnoWqj`oj ztaw(OTf&IuOv%*Q16RMHIu0*VVI46szL>`aN58+`&`Rq4ycd%bX!H?SKAOEoO-u`x zZGq^#QCQ&!PIR&4w7kwf;lmp09mvEYZ!|c28YSYk=4)Io(F~p=W^UCOfW)BIDXpsP zyhUG3z>3;?dSMErKz_qIn80uF0$#$irhz##5MGp^;Vo^eh0~uy>EqKq^of6b_W%uA z%)qJ$siZpJ%j6EhmW;>X!_xXqTr}*5Z>+59G~?C!&6Cj^d~CCgC}oNc3neyn1Up+A z__1pdgjYANc)r;IMw`yIJ!(d!%dbvPkGD7T)6N@5CoeZ``8MBmPxALDQ@GCNvgNJy zK7AWkeI6qqSKZ-M+1%Q=vUzy4e}<@k_Hgm4VuX;V9wR)xsudq|UyzUBBKqcdyO1Wc!nODqkfsK^ zOamq4a3;7Y1qzY2oS3iXSGP*B=2ffoHO-+~FFCL{9P&FqBm}T}TS^;MaMkv^VGUDG*hg_tA5DJ)pla>s_Q% zR_^H&Ky$@Q9ldde7H8=tx-6OXa+Q2REalrI&2>fAvcG~3v2$~Yl$$bI&|(G+r57b{ z(DWg^BZhQA;9yZR3Sd6V{XUQ1Z=)EYvTBL+%og*T9K1!)c zpwCgec2rRYRV{ASP7uv+WX6GdDEnquh?ebaNMw8%*{G=+&}hb?oYPD%S`JGVU3F0u zr1}0`bcaowLQAW2te4_gyGv`1t+j58%orcr|^xdE5>KZOQ)chXi zjoDRGXt1MQ<~uz>avu^4`pEkm_*pN z!Q*x`R1vQgBuoxz+8O(f8M;(xG9%IoQJ6x$ipmvPsdDfJ=ONx_n!fhVh~xAPr<49i zE`|Xt$G@JZ9(A~A zEt27<`IUz+4^Mj<@N=h;-;lY*`Nn6W%=&w$*)eqVoi@eCZUfR)u=4`jnW+bsG3_=m zLX~~&?>LJBMc4MR(?Cg1a4Y3Akg*T*w@!79O~=VxJALY}e2j+~dF^dAh|iryDW67e zkUmA_I3Pjaz)#_JXV)+(GEPf(Jn;_aGTEidFFVdv?YM@Lk5T}(7eh2s1ixGVI><8sQS?d zs%?1RHmp@`cFqhOF;!v(J|9V}^LKWZG^BUx;vtf=dDoAk163=wJo+gF!1k}MalHaeorn0D2BW|N(stad%yHl%S5q&w=IUWVm$wOFVc zGN~Bw9!#8%;kTG)=f@6qKpYX}Qnq^AdBpXf2hq->E-gd{!InF1Gjr}6m!-j=dz)r9 z-Phbtr;Dyn_b}`0H2g;UQ4vn1ai8j}Z*a%Xbj;s;9;Icb-Dy~|?mmE}I%pBMe@hEy zQd$zheGKUa@zMV*D5Th=6$A9|A-RU|cfOh`Ok`rJ-X(-$YSACcAV!(F-K{%SnA#IG z%@oTN^RORE<)>X5y8c4x+5yI!!fFg;AG+__n3ul@*}v8or) zDzKA^nA_CC3a&k~0sTW-=R}Swh@*(4?DhR{n$v*y&|KMWrCb`SLd zJ1@%vv!qr5l&RdnDUqmKlk`#5p^HA^ypIgdJoVLGh)~v9mYx>1Ddgik)8b>oOtA&p zba^4_o4dy-RU?MBx*!cd7jMK42RWB0JIrTP>_~ zk2Y3XxCvO{pCPMMqDoBy*b_x|^iSH45d7u-z2QSx$cEoNeflUl3uR_A&w*YpYb0YD zbdqaX?IHvAWUohHPpA4WB-wWQM?V^nUZ;15oUCHwwbiscrr-!a9V8Xsm(K@mv|ciX z0k-t$>GPMr+mm=7^m&e7`vqOvaZA{rn7K+FuGtF(cjZXf+@-5Os4!o=Y4IOY&!B6! z-Txz~7}o+MIA1Lsqn?sc_rYJPj0{zBoJna`#gky)MsAW=Xwad6`scX%|AKgNZC>|a z4oAoArR=J~9zTD2$Hwz2X-kxZW)g*|7QKDAaK(NoX)-o)*+AR5cc7YbHI#ev@Hr$s zSg?L4XT9ETzNHJwQ};gs0rB+gwwS=r4kkjl!ytkuh5r9eZWG-9H}u}Ofmm$v-p-!l zI=+oC>z__HfzRL3S&-?+)dlfnrzh^pvMze5NIPY8D|lIAWji=j>0(k)F^0fKp5Y0P zco3uSDV5R#EAhVQE&fYPrq!$&92AKfm^Tslr*PjndvhX5UuD^`8pKSjc7JzT3Tl_r zuYnoe7Mk5R-$+q23(S(+BypbTJ5J#yF`e{u~~RUocx|`exgN;zkP9Lut$Dtwv*X zjd{i33>2wX#)3wZCYhp46>kxp@WhDUfGduP0JU9gl8JIZ=#g^+fQnt@zOYIPqJ*uD&oRcvgI^3^&?OF4Ly0TLszx0Q1W1wB^)Wsz;=!b_I6BrE z+Ia2#L@?XS;1`FOng3QyeHrVoiOt73u8Uu|GnR7 z+93Md0lpyhXuc>aE5?=ggrvlvr8*%(aNK_*t=Em49KAbgt6?CnDo3O z#-QTJNMu3Ir2lU(eu_V^`PjpA5UJsS3H#{)H;CK!c5rqZ;MSUtp?yMU8YJ9@`{fP1 zvV1}rf=_OJyL0dEaERI)NP_nx4)3Fr&8WF?{OTC)4H`)@MhuhtO5^;;+2mwAJYrNq zD%H3K(f0OeAL+fIP=%W=;5>#J0ZMUbz#r+?@U|669_nub6B*oD(Bdh7T(m(0f4|)5 z{?UHb&?B2YxZ(b23V&1jlES|R?Pl<@)SE@0eb(Il%dPv5?%jRjU+8`LS@UE}H{LM> zCx{>~Pma!*!VE~py&!c$m(T%UCc)bz?2j#*6+Bo|RDm!if8nwVq(0<7(c;P3-X88X z+i*m7=(;V~4Ms~1qwQzSA5lVATRK0d_V5|~mnTSCX4i;$ut7lVj%=OruS2|w zF1py6HC9jWPQ`Ok!ribSf+T$!$pvj-Qx>w&i^=#vubd?B)`9FG*r5Y6a(uD`R`$sf z$!G~HOl%)b$Mgq2gu7fuIp&0N)d5L8eDoAiHc!&0=hs1VH#asmeo&3==3&tX$&rhT z<;a~p$2t(W8`t%po6+#GBJ&vyG;Ykk0`FqH*ku%;x>YB@WHh}8M$%e{3}9OJ>$d#G zfRJDCR-bt?fUuPP1xbzYm=fH?bx+lZ&HDPfW`}^I5#%LYOZeogKG`({?(M{3)2tUo z{7a-3MSHU!Q?<7v`Y)r6_pRUMmJOVfnrts%!tGV*BQ?^#(V30gG+$th)<5~v7Y z{M>*-)MNVB&%P2UOx1GJ)Mx%w_SW7}7{GQ?+1t->!-tcD7?2P9bMx8${?}h$yH*VP zGrZgR&I9B8ye_K!_UhFy$7Qt)$UNB6G%mLl7O z2%h$xI!t)5CE=gxlc7d$PceOW8qPR@R_P++nSMZPrX@@LFIuINfaa6q#i+6DYd$gN zzJ6}nAcJK6pIqx)=r_BUPLK=iQOa46E~k($;Y4t>*OwImT-rsYbDk^7JwV0)gP;(F z%%^c%(1_`d5F(0%M98KJG{So_h?X7i;l&l`Y#O+6;R6o>FmE0PFu55!*>IVZvb;g} z5wN-J+Cl|IOLdD&E=Er%lJKrW#NYUl5XBGWeFb4&>6HpqP7_AzeV}oQXd50x$m@il zr&HuR9iO}!9U~$NRyq+k^r45N*C;(h6)=7|i{mX6FkCo!yq4S7io=mq3nuDDZ7i=1 z0zZq_@{9P7#!tG!mW}n*%TTH1OgR3x=_GB2RCj?qD6nD=lqW{84hi7!!$cw zuefNv9WQh9tPEcxLs8NH3LEP-q02&jr(GoK6I=`!p_m`lAJwVQG=o{snsvRXsk2nfx&xO~2l)z_V z>^yPJ2k((*bVSUTg620Amu?+O21H91S}1hahoFzvzJkm>bbY+`Nt2GfH1w8ut5t`n z-#hAuoW64g?wn>_NUj=NDnaQvy{!0u4=^6C&HxN0^nk^!o;%U)e{sal?B)xl!PB_9 z=F43$giv(&;dc&WY7c2Aj`0>dJoQElSW3JVV~2zeQHLi|gQ3!@KP&?;8Dycrynf#d zF6~#8IY90s|5gCc{yNjl`8HZ3fqBIM9VYYyY?=pPA>j(41R`&Xo=d0hoT6r_785-MYysi;%mOX$A>tn7opA9+Orf*4`s>OXcbek1~mIFIp3@dSj zL?qoN>?i9-(6VQPqRt2H&ZQ-u3PwO!AjAJ<5QXFli4y2CQ+KvYe-ml&e13OS26oHPlI(pwl5*zAmw#)7wX92m6Y6x24Z_7$kO$z6lYjCQBI@x;|)Z$0y%E86Uz2;(Pu*l11-#Dv!#nYrnsL1_=^It55Ly z1LE45)&%<08GE8a@z0afSI>@Lo*?B$(&)G#&{FAyop^<3x}Mbm*x7u%f;_Frr$v1a z7p5pUv+iN$c>#^|tGZPb0yN}CL1wpBW0+JYd?0ntzy)=BB8EY{mV5<)O$q>_}j*(#E zvMMk7Fon8326}30>MqtcWaE4OPW12*9VC36=uJKt&E8HCw_&ISD_?7_B44ryX$?G8 zTrNz1FA(+4_vKq+o_(EtZ)#*TCI3!Tk{2*0qRo|NEGoj5#CZWC)p+N%72#;lt9nR* ze;@@PnoXs-$Ez2ZsP7m&leRx0+r-TT?5ejayA|{GIDDFWFl40ST zB331N7EB=ywZ$Ef8$rHwDfmJ-ve*OSmA($=HnHl6lcs_itu6)^9;Ih?3NyPQ*YFWq z(jSo%O9HITi85v?D|er!6BS_#oAl9P#1jM z;N-K%R7~(G`Ep&QgP>rz$!?#hyzJC$fLe5(OJ)J*t?M8FIs-iJ#ejv(~=j!@f) z?H`|mg>ri{V}KR&A`iU}yo{PlZ=YS7T99zLvPF%?OQm+OhB=QEpaRSH*db7O8q!vH z@B`Q=ZssTPzOMI+4wmu14d!k{Vn3MNa!a1dY?n}Td81jrG+id&bzNByY#J?+d9*I> zm}43#50EOWM+wvg5dbl(aZTUemO69tpWOCBSrQ~F!eJX*rPvWrM!;zWNryPKM62Td z;lz?Q18F^0JXN+`!R(dDwuqI2O9O`NC4$!4uULbW6*D2p5bK2JB*MBNpBN|6M|=QT zqKYHRZ!gaKqY(;;!_Ks*km=ySre(x|d~jjqKbuYv-nk01qYi-~M1no0+7RYQLKe@K zw~gVJ?u;bkq^YY>l!oC}u|Hx5U{+ilbs&XSy4DOX%^;rg^{`9W7?!}LU`iqgKo;Fq z6_Dx&nKMN0KR}h_b$;m9IXIfW9F$c^+n^xFu(mIZATFZNwPI~9ZhUhSH|F}?ncD!H z95Z?*F3{Zi5uAcnE$w>@nHivHe{fHzF%N-MmN!Cv3>OQ7ZCYT`UD82n;tUMi> zDfTyRDWpUR6$2zFqSoS5T+lQ=UrAYo10c>*}oA%%g}# zH_&K+@dmUgK&i}Q#ap11|9eNk!Mx{BT5ynp9YF$eeuL-|$cQ{%O4ns`2NDde!UDmu z@%bwRa?0Ap#tfmE^wpBD2sv8v(orssQB1<)yt#qO+qe}lOG`l3;3e*MXS*A?lfbPS zXoQ@N5Fd-zoZsW4?;Z`Y@WbyOK6zT;w*>QSs+X*|49H2h2L=FQ5~ZcTW6J1(cTrTG zH)2{rQQw`T=>S%AJXCy$H|0Tm$o7pxxA{Lik7f`g>4gJX2j3|z;Vn5Bim)S@?93;w zwXGhg{LJw1JrS|F`uzWH{_w@+^xx=WbN}egl)Z0$CdM(3m@bocKcM^3n{zu1asw&E z@nvWf#foV0FZ{Ezi%T+Id&8;sQu&7C94&UzJS?v@X?M|Y>A|i0ce%JRgzbpB{{k-f zpuLGC$Fnmk5>}fNJWs{vtYXOr+~e|nTjz4ueSN_@DgH-SDU;baAse-DY1QtYy@i~7 z$ZQI{Fc%|aDDt*vH=%-&ki7g@1he1#QPjUqzp{O%$NL*ox@sQ}DBVdd@;ysQUuhJ< zxC|#GxE}RZOPJtfmIq;vBpiADqEeu@wk{PlQBeY&LL#70cyqjWFo8=ej%VD@K)7eS zAjf5ClDIMC?9)3l@@d9TLe_yiO+Piv_vqwp1t646`X~O|OK;QW{K!6#nk9t+o z0{`hr%zyF`7oM#6XhdfqV-z1F)HC+|;uDV9;$*QQlbB$h#W-^GEMAP`l0zzFtEvVL zom;cn8CV`1f#l$4$|pPgQ`*RM)n>LkFhZQS6E63hW4S0p7ywLaHx^2(vwP^Rtc?jpo$*|OZZf>t?x$klYi(eY&X z0wUyCj*F(WD?gH|Y@K*OewsWKVr&~17t#?#WWvQu8|989?a)G;1l`pX=S{D6 zeqS(!`1hRMiv#3wk~|ImpCvP_9W}hn#kxKnpVIll*3o%Ix_H=u^T4XCdm9SwzKU>2 zOmccCW25Jk<-)idPR>yJrXis`;S@+f#?VTZ`Z2RvG>cm{v%#hCJznT1dri{ZjHJ6JLyXCR#^Wat z6W!W2O&d#4uiuPP+!}ICa!!*Nr0~H>RkJ5tgJA?|n35KE=v^e{GVdkj+UL9O!1L+Z z$<(T#H}vpiJhle7$DF>IK<+=0oIV}xO{SZsrP%yx>*}>%U;XvhUtYcP)z+6+zW(|u z8mGy?+r(ves!ZS+B+VTb_yFcJoaCM&mn>PJ@x}xM1TNamK`Q9o_5JFQHc3P|9`HCS z+queoaYw?e-FkWdO;@@(tpKE*_qs9buv$seQKqC8*SI&ZVO#YdRbW|0p@q|Q1jMN>tF>LVqFAi7~CJIIP$oR+c z!O=1E1UG-OCm~e5JXngB37t+Yi$+!?N({Ae9wf04_) zvj(X_TJqa89YHIKt3kI@A;Y4GG?1bd26jq{=vUwyj0GdgY28-c@BBK6dJ< z4kW-@mNO<-NI1rDhlewn4Wg@3s!PIzpJ_efu{Y0pPlftZ9P~HcqhFhHIvsiTq{CU9 zKO0SmWtdEEk9dues8z4Yr5Tdt$HH7f)_&$uFHBmJv+9%WIub>3vioVs6Y3nhYbB`o;;e+S1^Evl#ef8QbWc{6%m){eg2d3pBe+(6 zS?mfPF+5<4pAJbJyFHUK)$kBL2uS!fNA3DC2E#1WXMyhd05gFtNLHp=obRiYMKK0W z@Z3Pmgvn068=%a3`LbhCzo(D0@Bi&=GG<6{L5y@{u{M~jHx}7Sq|@H|G%Pz8S{kSa z2oWX|1}8VjI)v?Qu>44>vgBl4`doIe6*#_Wx5e3_7>JhTnKEP6KykarsixPO#0Kif&2$1;d1iIk@2w=ByRl7ox zWOhY}8w$3L6#5^(AVDCq4&|L_YK4Wa1R$4?Rb{eol}Mpyb-^M-+M;zanbW*#wy(i(@pAk50_04utBp*0N}U?V6_KadOpnJ)KS zq;(8PM?(J%Ymt$bwxnUBLKt*eFSfTy%xXcyi5fUcdH)dFb0aWu!BngRGH@Q8;ef(Z zNeU#r&@T2yPOW~#njc;Cm(ErsgwY7*O@eWfNIF;pk8*8n$;sHZSpOkQLW(#-WLKyT>kt4st&2D@o!DnhFAboZdyP@s<)#( zc2@WBoUen}KY6=;a)$Jmi3Bvc;P)-O zcJH1EgiZk&bLnug0iGa+a~tCDQ#3s!$Stqyu)yiu3cDc*)i$lOoSI<(xTp#!t-sI>eJnFL-OJs&6$_27s1 zP8w!@2_ZWw1(Hw=MvQi83zI**Patz=)vC?E3j_7mtchcwP+KhQFHH`-GM~5ITC=*) zZnLcw%9;>_aBV{1FqmEGl!9yO!|4IT?y$&ab9GSyR0_5REg4=%%I_s&jjTL)+NbAo zB;*>xO_;JiG*>iqrzw%^QYka6YIqof(`4hmW(5JpDdYkI9%nBHSikw^6)09hkgLnA zi|{tX@h&BrT)E7t&nVpPXZ#)S>-dtVmWfz>KXd)kttTIBoLAh1s-xEV0FZunsz5(r z82FR}wj^!~J&!9Rbd7v!jqe&!yMaroq5=t_Mow7jCWj`s=Tq zIH=LFeVQn1{pRl3!RsKYInHQ#S@Q{m)U{YDBUWmapbSbT&R+~-aT}2IJrAV;t(`Ql zrwDo^b=z#@JimgMS~HYbjL_Y8$ddR~ZR0gez2bGnyV4{ASDIsRq}DJu8@R@s8tWf& z@GjmvBDdmx#$8mMoki9~pAEK*ou7XAVG)0TSV{e{@`B-R6KHW;#|xwjgOGr$4&3F7 zkP}mz7K#Xy*y89-=kvP&;{8ARj1JGk;t&E04e!zUtiB{0M`7?T*bL=^`P{a4!ZqL7 z$d_IWf*iZL7I^!_Rbd# zl-MtWTMMv9Ls%X=gza*Lz~stxz@LHUV0h{7wQ_m{hZ?`nlb2jXmEbBiB%H3f)^>2B z6m9W$m@$oHC|On@;%^S>yBvQ>31)W8bL7P&TV4Ee20W34_h@P5@(f902oN%LI5!2y z|5njI$qYyV{_l?aSfT5a4g@Szp~+64O*}LLFVYO8avpfx(g_o;LF~T?^S+AgQ|bB( z8cfghB|s=}%1`BH^DA)~p@4%3j8X!Ap6-E?c*I-Oq%6Q@HG5ewKDx|t&bn?XjE>CW zS1IoBo%+#WDcbQyxCdC_QWU^_AujdK|J@SSZf<7D%tkE)6R=I89*(9Q*sc==W=v?# zA%6wf(VYehxiHhtb9iwfND#QujHpU1C@YmR2RiYQK6v%e3Z=z<&UFbTP~PyyNzARb zprQ1+M<`#EzaR}KQHtmYPXcq7#+&lIDurKwys+RSVEZ@gSg2KpzPjT!5cYprJfA{l za{Da$gd-Tg(p$hh2HXs@ix-Lcfq}Tm2_R&Dj_=F^6IHLaED$IeZli6D-NkE4Ed`>w zt!+nW<;<~UK71@}(O)I-2Y4=X+Cc3ZYDHv z)L$AwqWe!TiXYnsj#R>3B6(HQxlFTKTD2Z5ItakGXFJD zXbHd0ha;e3{iPZlIw&EFVNuY6$^5YF9qp*t0+4Zb&j7CVQo(63vjD6{wBEC?jDO^q zvXE0k0434PQ;9`VA%;Y(e%HGD)-Ug$4lF ziAd}QK0>bwhH5)Qk-x?sjdh5?koCvJh)43HompFNAs!q7#ldN0)M@Tw2=MZ-A7OAe zAlV4Mx*8&J8QXf*A}uy1QR0KT$wev5FoX^RSsE^G6_X15P{ljqaQ9^h2R3+ij|jIW zczbPB4riNoj?6a6==6p+5)Zf>Z^x@$iQ@cBz9i`0L}V%FPR8?ohn!&KU z2qeM#+*)pneTAgHum|9Q_czD%n;>C{Eh0u82YW;iq|xwjmo9K}=THd2RmyPgc@jsy z5W{;@wy?BjX3T^zjXl|3{~ zAw)fnlO(#CJPSS!VCU^Y>yUf=OIBHBx5@;vTmToncWkP>V(r7P z|BzQ;9E#o*R$FpdDb)&biWO7(iNZ;d41(5p+|$M<#F?%8r)g3J&7-hdKUcVcmZXp7 zJCn%6?pu#WrTCrujY2c@aXUerjE_{8RI?2f%o~=EKXOD7!+>lky3*kGxftB*RfB(8 z`ilEPa?bfGYprlwHKR0RX2Q$Y3BDITligdyg4uqmoFJA11V(JI5eU6c@v2j`gspaY zbM=lDSWDEDsKHh~$}@%5#HLzOqGB<3+=>AADzb+WlH9@1gYK@0!gk@ZPi|pQmPzPh zq<|!r@WXgQ!8y7LWU#u{C<5P(4r4c|QBo8ajrR%yA2y9KG@%uWkzyK5%7z1$;3)rU#aG!J_zSN|4Vmr1U2(a zk$lIsDlVN^OtnN_s*{&=@eSBovr#h}Jers)!nrcum<=ysxnvYWzynRGadb|QQR~k* z;_NSG__NPcT#_dkO%Yg(fNk>u*ICUF&fg-S;xYhiBBe>f=;~y8iu*-zJ!iQsfyIVr z?Dy5>%6L7a1Fecyyt7t5OJ4y1D3(^Zj)X|et)mPU2|o~QfD#vG7|;VzL~kxL8Xwuv z^_(ny-8EgwB$e~8wbyMLSvrg6_K6}*t2Jp<@YOD_>5b?x;ZDsfs?+b=Q78eRBFEpWn10`PI+-J zzj$`ctP%sTEz`2Yf)l}$=aWyhl6>(-ghWTToY=Ez*j#&0Um-g#UpdDGk37E!eJn!3 z&_m>H$NNd(B)U33(pGsEw&r+n$n!s?>{1Xypi=5jkPwD*=k_2FW4Txk$u4%G-rf%7 zk=?79mau6c3QWgiMsEY>0v;qIgCvB-0RtmI2s#>cP7E|li0~=46TCCCMLSFeqg}=g zOU{sL zr!)f(^L?Z*kU6u3!VU~%IHZ^ZnNyC?FA&WIsp=Foh_IzGY}I)O*|tf^@xDPrZIRGj z{NYFB=??`0o%&^~Ydp+>H%Pi(KtYU35YEH_(_VFxVKqeR$nR z%72v2)%Sh`4kMxR!NF0~c%(xek&XN~fU?Tsmi2avx_A<=-`t8Kq~d_AwH4xYfX3RN zHFvO$t&0Vq?B`00fXUT*z{vycp92u{X)Xjt6)HgP;L1x4WT3@R$eGqSiF%7LvSYFB zl30)}6!J(YF6@e2-{u*d5*Uo(%2jm1quJf1Pv4C3HIDD7?c-4@-rYr&sE&j)%LlO7!P~jDZyT;LrfhdbPrv4#S3eXOJc0)nklj%$SJq8d&oou#r;_HeVeb zjyHcC!B=s5y1DV@cpbS)HdV#-%+cd|>TytZIVF(n78?_a2DxAs<;BERL6lvTKQdDH z83U}+_bCDHWX@p*KEV26&R=2u_jJ?d{HArY|p9-u7~6?Zu5-;cute#d&owv8MHC%!dZ+0 z_6=9N&Ld7dS!L!4mm6N{BdSQhU12u}Q(8-a=;rFBjbRe+pxyfB3DXsAU`p$weP~Q! zz)E%&5adgB5+Rt><}hcjkqGjp7iF=uNzII zm#T0l&AAY)jM6Q0DQZXiNSIt!XO`z(jO7Q7y$}J<@&sT3nFLZ+EP1EZOhsP>^TP&p z@{I?u*m9>Cy`IeQo;m+0|GBoYwXwC8x?xRZ5qrD7k6e535?fDPv$+bkyY=g$<}FV2 zaJ+6lPDQ6zuWbGL%2!v>by0h#c{84_!wu_beFm`~CPn|}>c*9gYemKT&2$Ex8`AEz z{@FssE2&~6Kit8--El+t8dL>0+~mF1+{bSj;$Y)uv(yv^dk?b@oms$My*HEj-`GwA_juFI?Uf9g`G`PiU|@Sj~_qk z^TiR=H{Bnd@ChHB@yAT1K0&&R4J?4HF5U-HAEaair|{AFlry91yu|^Hn3Li`ydaoS ztE{uLP0tS?6LgAB_dS_Ye{pCbHZ8vI6YBRl$;IunrDkN$1*tDLGf4efZS?k|eAlgJ z`M`nSImtE5SWz(xyvaw!^o{HMcVasawTjS@@+()(-$^I@VDH>76qepP38s0vc1_FOy_0$UBO4tZb8LBq??x=#;Knb6!qy6ZHts~8*dfP zywh0%{?_cZnt2LNq<^uqI;9DN3U~uDy_;HqJf7TZw2Q2bw27Fxp5on_*+@XmFn1p- z+{pm7M+JpQZm!QiXAhr$zTG$%;3h9h*>zF+1b-H#E)}rC?K3?T9SJ*{2SR^Q*WfGq zvR&V)5i{u2Y#!OviWan(NyP&PnWFyf;&V~kWs9=reVE%0&kmc%CU(dgSF|8Q8SfW8 zKh+1Mw{4!vy-ob-^UtMnIGyZH4ko8>i|P;zVHKVr0dB*G8H%25d5Wr!Wz#BZ&|lbU z31Gt~$=Mgm8e}&4`RA19xv7d?4aYFme&=Py08qsSPt7e*wcxcyZKWEfTDG?h^!_KO z?UrgyVwbTC#IFA)Vn<>}o}vHHmom%8F=cY_8MWTf{GfL;t5en3-u~?6^bMYLV;+NG zP4JCLQ!gIu#6cN1_%N1S* zo$>D3OS~(~oyuor9TXFdS#=$UrK+y)dsQQ=F(&ntK+H;z9dXYnc+-@GC2=uFDEq`|mWY_3G(7had1w;I#Kpz$Nu$-knk z``=V2{ZO6qsYyetD3-3#k80Obx$aSVV zt}BZR0oR4QZ7z@a05_>x17Nm&-TYi?hcAm+xZOliXQnVELOg(w zdZS|6KcX9H)=V`WzOkvM9e>%^*sRHHpY8|N92R%;toDv#TcfA+z`~zAFPeGZm;uH* ztU?8>LvwHl4?w@uOC@3LSizS}DvU=8(_GHRks3W8Bnsj*1Rdb3y5L{7I7MysDg&C&MqW-3 za9h!t9-Eoj(Z$vr6e2ysAT>n00cmL+#u@WZPnyZHj*L7af+!ATXc?LPq%L)3Z@V*_TE~72Hwol331z$@gpew_3F6n%!T%_@X z(p|z6B2ORU5fiv;9D>L~;N-nHj25{+$nBusXtwi$ujpYXXJsS2@9_uh*3q_jT@j5v z>utLOUYMOBciQXf%L;IAgzC7_Yo!clf}@GD_Gakj>md`0Y?O5Bmhxgi?54L+mp!tB zB8*H?%jTs8O(J59(lsTNGHS;TNIlKG$z1?aTqqn9sd5WuFK(?#4f_L+t4Z_gm_sm! zo-;h^`)OG_Q?@;aklSBNHhcp`DbC*d?BJm{KT(o5b&Ea2M?bIww7{t&jzA8Lon;3k zdvaDMejSK*L_V_`EW%=qKF}5sXMO#z`6xnn^lu@to0^Qi+EG zd#XAYSBk8UZm}?VrO2;nvWjM=t1Z^Whr=YVC!afWp-l5mqy0bj-n~Dn>qr;=8-I#z zS)LXSk^o;ahXAn**w#51bGXErA9#8ibpsu@x)rr#tN`z4f1l^6s&(1DyCq?gapuJH zo1or%?RBYDt8S|<@r}RFDd|!tMv_u2KSNsM9bI1S@6@r;Z7wMDHhY%7^AukKM6o6C z?I?oQozc6{;HkUi{woA*rSJ~URYe}W<;KB3%`x4sWR>=Y)aB*)#Y^7$PH5Ss>g|X< zhWC&S&d&u`4_J#+2VTJ#1Yc$d7XIPTT&h3LN!z7jHrUM`?3*j5p@x%t?(7gAyLYw2# zmH8eStPo28UqW&sFqFd206!@Y;U8WA`=n#TiV8*NTTdP!9ne5$Ls2Il1q}g4n9vhj z;9s_I8=^ZXPdyu>K#@ewQ6(_F_#QJ8t;vdkjpRQd@jnjoQc0raiwAhcHfF>ua*MOC5ovq9R;f8(ii8JmwB47Q1en}`?0inKRB%% zpt6(d1^3vR>0TUWG!*)RjyO3{X>k^e$z{;r7> z6I4D{^@#IjVt5%>6;n|PkyT&6+k8&#HcyH=+k26i^6quZObPqWL(Y?UfIjhmrY8pO zS(>IKFvxMStq4FcNoh})$Z0t=CIKQ1n`;dPCQy1z&7d?8((kivoUWdf^SYKYlxeRXhagN(sW|7L>uQ0c{PaeRw zXC5F-J?mzl}yi|!Jd)@&UUy{XiQzg{?;|UVjok} zcbQ;X=J}@AA=4U2{-N?L2wzsf{wd5*rxME3g+eeD@#EALN+TPaWteynQ(FI^R0O}4 z1vArm|28AhGHP7wB^}(>dkQoeY6NW7%dn13cm|oyZ@=<#v!E zcGyXTOvYK)Cf;a{;dF-#ACPS3s858{+#9?szJK@eH@o-xw|5_unr=!a?q=ptc74;6 zW>y)wJ1^xCThIOCUScTxI09vwa>x4tpvQj;G1{zrih|I7NcM0h388*Ckf% z`uvvo-roGhHMcKU2q6p2gn!ckq*%G4UxCb90w+* zMtB0oGxI){?%#Mef|NicWkV{HAz5ve&SHe5koVlmUO-am&1l<1C5;Fse0vH(iEgSgb(x%a65e;Mgd|6K)9=%0FSGGPYnJc1kE^;}sBvA3am%+N1j-plw6<9IKrx=b0)R{Pj zt;R7b{on59T=*JqBBWB~W&{ej?Ui8hvvT9Q|B*I3q#KDyMxMe|!%-$AHxE+)LU71peW*-&7x3MTh?Whx~j0KrY0k|C{ zMzxo0-`sxB@wgs|ONE~QJzf?!8x4vH=RF9M0DE}AJS!yoe2r`?0sh2`v}@%T&Sql& zTyR&F0qq%k&ARntQ3}_suf|^G&1K_`Z4fO=V81iPWeF$w9nus*_#8|TBe{>7pXIzt zQ2SIsOYXGP0B?{o6Za zzoD}s^!*Zfqu@j5ng}0tm}87wuQ14*M{$RA>Tcz(2~`%C%B@gYo?NtdHLgsrsp`v6 zuIcc7g^E_PI#M`>I&xk^W_bk}aUiz#73HK|!&_o|p}JW()|-t*9@SI@hsV5GhbE(- zgPgL|tPL4b?8ODuw)cI+frLHF=Sy2nTiK-6B_j@Y(i}_8T4njHA~AO!tB!;afVI&% zV`OXo@W9uJqbVcp*U~o0K}J2l<^Ht+k~)0CJ=UbvIOWjQGP)i9aUHGMxTn0aPK%_- z8hEnt7(6PkdbQnPIgDH=K`AMPX_4Q=1%2zd06uC!6}6l!rXvLelrI14)kpCrKB&4+ zp(KBbpqpyKeTD&W*}6BdS$YrvpQf+xL8JCSlnbztq(EBxI5n%nOf(SC(!CEIHGxR2 z?bVSL62wH1UeD}W!ksYPbBcU(9Y;4B)G4Ed5P2N?z%tz8LN%e6&Qc2fh{{{Q7Ni8| z!!>X+*n|l&5B?~`Ahng}bkO$>vmNp|-Lef=r*0MToKm3094W#@xC>n4xloVv$2wRMq z!=yLTdJXf)pqb3}kZ%DW>83%o;2%G@Ywwt|6A>2iG7k@9P-xRjO#~oXX7&NuM)r*3 z2~sEeM;*zuI$Ti_(y&%pafM-&NaX#8>Khlk9bGoSyT(aG-c#+9p| z{@a~j4iK3*zwz1UU;Nv{@rx;Pu^oIVBa-ScDVB1(AV`4Og^K+w2vhj}ZP@L= z`@i2g&+Wsz(9rjK?QqVW>@Y|9zCo*5jJlz21tm4vDf)1tS?~%9?Gakn{!eJoN6_tp ziV5?a#1PG>6k$tpwitax^9}3^vatd&y)-{NT1~@37%N45IlN>OV-d- zZWWp3(8dKUS(5WPqFXbXp+~7yqcvD+I?cvd|I#x`FE`ULl1EHs?dbHpGpi*&uum=S zL^e!+(pLclD?e*(^rU^dQ31z1_h>^|46z0Mi2jhK7}lA{=wGCdArDNcL15}y9hEQZ zS+7dSLGxHK#V5Uc?6H*|h7ztUdR5ChPmFK9O=h9jKUJ2(1#2IDGhZDt=|DZ1%Jyf) zty&3DIMPZxYT+>#r46%_Q&qOgZFw;RK^ag7`t&W!e;=--$YT%Nr++0hmcqOMs*sC*M%G25I1d=Or&RIb&*K5bAg;5#kX!9w; z*39Amw4lz~I8NHKJnzfusajlJI#e=!wdV^H*gM44<#CtYTsqx5b70+tglpYtBHXVz z8-t7DU-o8Bc31fiAaa$8kxUJAcD3H~GbCPYI!cn6r0kpiOP55IyK7gE^ zR-EaDk`eSedrf9|O`0??_6<@E2!1+zIkLrd3tw$Jz{Qt(?%CHFhJt!-Wz*gBUw%a=!eM_K)Xb0RYa`C-HZh+fWUShT|<+hG!P*sY-WWz{)57jMEAyPJo00{wjI=EtiWCaF<{eNlDs1b;& zuRDL<`R@MRI}cO;+yGV$A}R5CYFs`qchvf7?WKLTSf*!zbw|V1_YFRa2&(nzbeoHO zJ{{H~L)jatmr&fPN)$FBtr%0smEg(#-e?mwOL2(}fB8fR6C9ERvSJw>=xI|t6Jloi z2Z6jLd=$dOY1h@uq>S@&j9BL~`5+PR1;Txy;u>`#2vU0f|KEqO8?=7~RsRNN1l*=n zkq#&%xZ)r}{&s5+oazUY;~YQnwOkWYAp$erBHb7T?V@~uOi6i&Wj3b2Pwjz~wj@&s zf5WCDIk@-jD-rf1??w#iA-8*-0XBr4m7(`v0k)vh2N(J~A3NU&>X$d%z z>`iD_xfD&}lU$?mlay2r{{NqNWQ#X)BSJ!|YGj&-EC~lB12_@9dog5o(e-I|0RO z$V!N3Reii6<-#gK1yVN}RSopbi5o|j)!p3{i!Ra~0PQkHnz0IwF73tqEL&5xL2~{| zo>su7W6FdWER-NQrkvOFZO{MB8|0UT2A7gP!{eHXVRPQB*%UdkjF6>Sx*=s<03=LI zBt8o~b%7z-6TSIFS-e;a#O}Z#(fqOTp06Pbod4;T2Gbp@Er2#r=z(S$xo@{Ekemr9 zq<{_gz1KeG+hLNPsY{-vi^We%DLeGgY}&h(s!XRZ#jW$C45~2^S6Vw#8g$@^42l9q z+jiN9rV>fdiVfom9TnRco42Ih*UIlJ^hU71p(qnimDd53=P9Ga4Kc3QB0W?Vxxd7b zMsXbzcg2&w^ttLDBZx%%{1PtSZ=R{nt3ei^m<(Z9DX++Iv*Pz*-X?s6H;N1tb{2t& zvL?ixik?Q`K>jS9T!1(Zdo})(vIA6(5PTMhQHLS1TnaAkv5q21hA=$r)9BO`I=X%{ zm9S5MU+H|557O)EN|A2MNQHra`hS^?r>$E=P?fUFj54(m6$tcdJRQzn73H9j;o(~t zJZW^XE_nZrm~{%;ya$0igvehA_1r6%8I(g>(dOT>8Z+X8DTi;~jIXz4$zttMwv98u z%>fc{{@gb=xUYvDOZgEd&Gz$V`>%~9M=MY7g|gw{u-Tp$?Kq5e-14(u+g`iWtUY~- z|IKMhD&4#4cE8y?d~SpDgaoq0y~4F?lfm(HkEvi{)=ame1qo^1esKMdT=fU6mu>XM z?jo=oEL{&BujROZy`zT3W>J+eNp&9?H9ZOqI$U3F!^ zjFb8Jm!r{W3YVcE@iBwloJix5nl=x;?Z%a@tLLlJ49_%R-E=Y=4BKUzHL2}tG6?a! z8Zo;*|D~>C{=S$jIwVQkS4g$Lex#b|$qw4`ANEE&h5K+dpR%-aGIKqIi4q)D>A8C~ zfZ$uE@d3#I=0^=FZAoQICmc18ro~o)f-Y>6Y2a4GOX}*S&~tqmt7PIB<4yB5FQ_G! z|A|H!;hg^GO|&^%KUpuSVE`q>=kvz2YK^tLP10SExZ-M_4V8qmtt*-tq}?QsgR%^^ z-lE#*=)=&ZdKG(jE!teTa1XKzD!*1|BfouESAO+HT)6NjbAq_Wb>`OQMsba^&HgPY z-8$Gu8#V(EUQ&izlYL)RxCJc|;4J4LCJY7hh9d+pJ%^Vs*-%l0TOY8ZcGnkOHMr9U z)fbR0{y`DPmgDGW?Qu_c;jlY-Mna10{5j`xl>Ac^2jeQN?h zG1*bD;IBud7l-qw+Ay(<5(MwNn6^eqb+eH)v!^Hh^vGvG*2Jrbhocpxv~AO}MA&iR z^5nW2C7-{lkhWgQ5AR*-XcrW*^VG&oiWb-+m`-wY&E_TNHu|`5Ar9`Yi_C%!DN^g~ z<}X$pUNq{^pKTS8B#IC`$4k#QhS0p~q79e@js}dXQEWxIwhQ@I4IHsHuk=h&mgAES&$gx+DjWyfA{^R_m{5vqPO_ghO>K(;`Fp&uz-zA%0C+%AUMOr zdvUO#iLta|98}Wj!LNSTBI4*kh#$DmCG3b@8e=b@LB9~(Z}}J z*JM6_E#^l$0_3{sNPhAOBRg5B*Iquvui~W(6?}h=O3c=k9qOX9154G^hebCJ82OtJ zIa)Nu#Q|h$Wc@m-TR%+CoB9K*I-0wEaOS$lHd$+*FM;c_$K`^~RQ1?CDEuzDHm#3H z_8WAIt}nXI?<9RB)beue2iUh66rxnL_=~i)S^5Vbqf5dU%HDGMQxh}oCREaEmYyqv z_Gynx6MTr)r8EpPIx)U_#2>kEZJO(8Lsj$2`Ao_g+$SXFt-;i)r_8>y zi{RlYqmb1T#K?n}CzvbZ-t~A>J*CGT9q7BSX0xBlN%#zq4Wae8ql2%$v9X)4VZsVE z=S}nMg^j)Wym}mUaT5^VG|$Va$1L!;oO*uT(Sg2i?vDc{`<-_;@m z@z-o)m+0}|Saa4+*_mY+3e+y|)S?Q>V#$WV%0*D%tk8sDJexVm`hky z#n}7>hCYF@Z-In`lnEVQRqg4JrJ2N(LvQ$ge8Yixd4Yx5p6 zafDqfal7m$26-Cxn0>R-pKN6iX*FfHH^wy!IxsE3CCYi~; zp=K85zv}x=Pq;!Ii;rrhD^btPF3(^r>sFOwgiw|iJko84Gl4KId#PeXqT+gvzR@n) z15;#N59_bci`GN6K@axna1iIsm%0%HEyi{+N0abC@ z7CuNf12KJvnxf5cF;@&zQZ`&58W!vgrXIQxXfsTnq~jx8aNts7ih{j$S9!*7d-=8x zi=PW?YYNexGwv3a%*tW+cvKEKJm(b- zq)uv@q8x&WqR@|NP*^3CkVf6Vbc{E>iDN(4{#<@WBCw4R>Rk* zr8G3$i=(UqM#{$-U^25;ydoslBX(KE>=?#i6i+`n2XAMbhAG&%j6Uv>5Bn5r!3MCD z*EZF+z6#uGqj-Y)x9)upw6AF?)*w0#b!A~Z3nrEh)S3*k*{OTudnMOxnCcL>A0x^M z3llcDpE_q^W^0aF=sA5$q@>pU=C{0BFAsTD@TG|1u;>slF%E38Ux$6*pPQ zy__2!PyNpI9AEx+SzdjH78%!t3(I+)A9X)}9p9S8t>yc?T&blED;x1nx0lIWmPL%x zU& zf8*)iH5lcNTrv`SIgWK%K<2Sd@3I@P%U$l7`u5O;u`(+&pQ zY4tO|Dt#|lbWwh8M|z%W?u~vyF%H5AX$23CQT}8PMX&ZJWd%Ni13yilGyHlmh3`Sy zL*H5$7OHV_1;9Kx$c3Gb7yR%v9+9LlOONatQFxeAQvCiN5;Q+jQ9owyvB@tOZ_ld- z;jkn>)^3@*J`im0f@8QC<-|WL@<}XK_fz%2gvYiJYBwPjL!-*hyM7Y0e^@fSyL;t% zO8Xh;`Y0@hwAlLbKdi9dJ8Tf7L@Ux4m}h9Myxbs0$sDPBV9EToffgwV=0}Bt_l5UZ z!!OABS&H~Q(w+L!8h*UTkT3Zy6c>ZNg%w&@QxHgJUk+!ZIjhkt^%sqiYy0E*oR{tb z$ePC^fZ*cX=<_}dWOPs5AAXKQu2!2j^-uqB26CKIZTYLrYAllA0zl6|z?AUBP!i$N zz3kD!UoTPY44!=a^8oHq>52zo@fQ_dj%-hU>2%=&E)r~ZDb$^BF_%ph?94MqZ<-i; zp@1O>>53p7#Mz4tq_R6i>8R&8Foo0e$NwsI_}^ISu!9)#q!!ney3n-5_dw8OZow{# zLUdc<)@8H`?a`Bv$!Mg)nTxg`>ns>p^|cGTxKXDeEcaPXCV)9Sv^8+-o2w41Uo#=WPvDI)L}oeK)@H1jY3*w5mKaKSfl#kmWy zs_P(O$BBis#_4)9+O$x+Xa-r7|Fz1*JV|clG^3(EivrFs@u*1vGd<14hxa?k^8QQO zaNZTPW`3qc&ul7`1jOe;S=8BDE@(o}Le|5AyylW3g+sLo0EjAJXj?^TGLbO{Y?2my zmo>g!BDRNj?}t+{)2 z7Dmw!@+G`fs<-I&Uv*L3TL0e5q8Q90S7ey)&r}sQzh0^p2Pp-0=7&b(0Sd>D* zGsO^6okb)==uAo2%P&nII~=`$Y7Ne#0$iSI0kD&X$>I9rGLA%!bul(%cxU$*o&7+d`8PjTYnpBHpj9prwxyvJc zgV1E(@cdV#_erOJWvuTxdy0^RH?6SOBIVG^aNiiN$W^o$?;DNsn(|-e>N@BKz_^rV z1j)!s-!g&DLhq#K{lbnT|uiD}RHM|gqDuti@3D2~iJ15cS8V$*lNwX1T@RPtt3l2R z$H+2!yoQ74#LP38Rcs2fM|`vEzL^w9;u~ftk@JNa9dbrO`#n@&R!18=FKT6*KD0@+ zpQqctTdbRit2%INp!YB(x71L|yGHL0jE8u>W8_SLmznnmM^4mBwAokrXvt=OgHdwx zW32QL zIeu(ugiXGBIo?A#P6}?=!T@i%havHFGSH8_;vpG4M^ zqcR6d`l{4f{4;IzX$2Ow4o_v`BOsN@=aI@J_*$*2*Z`#}vYQjH5bCv3S2jGY6q4ps ze(*?2j)QlJit|1e?@49KJTCtni*E}W_3vfB%8<#BkfbCd)DdZu`hFnrt0=>aUlzR4 zod?kbon<5PZGKmdZx|i;{RYz2XEqi5FMoYr{CX^^KCFee@Cf>{z0viz9dEy@R?0er7EUk)Z?C=H$giH|yzPTQ>&dZ(m+_%4`on&j~(N!==Z zyDP<|9XQuVf$tL^2ucjq8S(f~XpjjNih%hUBtH?g*u0tbHPZv~&2tgyNY%(qVcGpB z#So%*GlW%1^q^N~9RnJT+*iuj0A7CC4N5YE*{yT((J1HEidCVmW1bM^4pBtAg?Y_S zO97jXK5)lW-lE(ptCJWE8R24*S6N)-!QY`ciN-6-DcS^}22OgtW&oNVCqA-NEiNsFJY8S5b3})o_3{1#kmt@_N#aMuz|~NO5>rIGlf7 z-6~ zU@czg!W5aRqLi6H^IcgZYw9IydCA1Kl)W~T17kwZXUB(B6EB5sa*5R=E?wFBeVT$b zbW>Aqmny=bad*+QziVNGlm%LR=BuW@*nA}$yM+Fl4GiD7)Z#8aE z^}%q6e5NoEPls^w9Pc0C{)j|%SARu*S-B>Ao@*_wso%pieuPQRJpp!nhTHWIF7W1M z9j>x_NGdrR_770MCSOL0am6LL^@&prQ^C}$KqCXipC9B98==Ad!x;iIAubHiR#S)d z9(NS*k49dt0oLl#K&fQ3PdAnGL&4?Qq55JbE+8!Z%T>5}e~i3jEYz_2jsrw>GAhdB zDmn8s*(V*uu@L30~PC78@|%!S})WiWvo`~V3+4!~bCA%|wFJWEK% z=zoL?@$KxD3|#gYH-QHSTt>dHKp+hgyt9z4yoYU=o;lWYkNpcoG5w66xZ&xspk{B2 zUNHdqAxay`>L0H7(-VX@O>wP4cL;0{Bh|4iUWR~9q?OwD^AYxOXdS@49@!SOj5JLt zk7EP1^)YB}J^YjA5d-ppB9KSJG3ph)h`N#lzC~t5w1DPh1M?fN3<9zF6|}3_VyNYLd#?Nt!%a&Wnb#cH$2pP+KueEK+rhm}DH$jvitzY(OVGT^S{Y||*JQ^Hodx=Hfn-h%CiO76# z>`6liG7^#IqbtqEnpGpfn3Lg$YZsdhzUdR%*VG7JxbC^Oxru6`$UBpZa^lIOW7KQ8 zdZqc_$J2(hZ7zR)?b9pQu3T+?cNzbc9~(rlD;gU%7>$Gj{!#8RDNA1?&moe<(Z`Q_ z$tmlY^iBg(FO#|slT#n=>p#zaVpJBj-qKAhA8Lm?6CpKnb`6{|f zFK+;u;NCFALVK4$n!4IxEcdrsHz1d{;TSs}_LF2#xQEp`QZxrr_HR=dp>XlZ)@#iF5)SBFK>C}z-+$Hr>cP&fJ7M!% zm=+R1AHE<8#(c3qB*?B?)keZDAw@3NG0D7a^SQVCq%j5M!Z@J!gpF8( zcb*ZE42TIaFl%oRwRz7|#K6S(ixrNiDB>>V#sBo5`>`0^qCFxL3?taHHXmCA?+4nhB`aw}$cuESfK&|8)k=j!X)q=Uo4>?4BUzymHazW@0F;qTvU-pnE#k7@24xpi!glJT%^=6gLq^PFk1o>!59{5J|3*Uq57eHS1K=8q z`_dPbsp6jgm5&v2|b%3+7>DKOw~+T1+(Zsl1;NqzUFRIeDH4((Egfo zPlW^t+ssCbEsq>8SU9a6CXM45P@#nE2>dKJm6tK{!sqc_c=4ncyUwn(>$>4x(paUx zeImq=xZCr2h<-ZEY;K~Cmzpb=ov^G}nhf5sqcQ5BSR!r7e2OFEwjKW~j?AxHws(KV zmB(b%JQg1h?T7`=s4yiboAS3P{4qnwz;L^{qV1Q=%nKqgFELh<8!)=Wg zsF}1;oEK@i?Pr-?^%g9H9}i&~1edA}f*;Q>Vy)WTCq3U{iDUfRpIA%`Wwi1k?1|V2 zCvDZtidn#(_%XEV=ltId2w@^sHs%y&SkM#RGz=K3be8jhQWj_WtUf9DYQ@HMFQJE- zGbs%af)+QFbkIr(@bZWWy$ZadU&9O~X-V8&6@>H0=7NkWBfmY-c~)&PPy`Q|1fI}E4=43V+-D_kSc z@vgLf=-BL$l4VTjqu0^%+uDw#MVtvAK5jlor5%=+0Ew$sXZ2>E>O3N;Qr|+vEd7w# z59-s@tYNCkzl523Jel$lMP7JQgWi&wUTQu&)0R_ysJ9#m_roH=m%hP<1OksQqCERH zGuYmE{lTxAr)#gvUY=O++K+Fat~ngfHcN^r+6#8tqWedXV1}gnd>4NXewj^Y`zL3g z_0DkUbH?c>D&a_!@^N&Iz1sp^0x4*Yd=M=%ek`o)^E1IexJwsDGnjh|tjParoxnh< z_r&EoD0@vS4PZW(=A(~6vV(kzOvfxqHO@o`L%#42NwClOrIAqo4jMW@;pcr7b~()x zTJ4XH1~vNo$p^TZ3y1-Tthc)i=M5OCD}7WWxO4PUGTdc^+DMn3BPcI%+XP)X-Ff_R zslm1ThD3D5Z%@r_VCSoc_jewB%e#VC2b+T-?iIHq4d%9$4tIwH@C#A1Mc)S_i()HA zxSXv-8gWw=q7J#K-2N-au1Z$W_4eGk=$?Dr?Jl#$jU3%oR^T|nz>0?W>*F^dx z_03Zc|2%Lr;sN=fxsUbt=Pw|OuKj@7z?wUs2f;VXYBF6|x(MF9KRP@i+`LM9t~ij! zOw&XS5;EAZ37l)d?7-X}(BCLxRq#vW71=#BG{z1cq-8EJo_4tDdH5(o8Dk_gsO*(E z>7rN@1z%lHF1!+GZx{`Um%3j45;pO{J^~_;-mWTe=NdI{5&b!=63u_bE%JXsA$@U7 zfjt?s;cIz-i%F7U-ulZkq#VQSNui7L-_Y76cId@UVRiy%g7S5^Ihy|!N7q*3{L(Uf zf9ViY$8W;KQuG_fyQbNZxhQ)-$h3vy;&(03@Gd1A4c#2(Gmw;*1j#e_PP`<{rUtbx z^=`T8QNs#`*fv{&S?5WKu;)->v1N3pfrkdxUQbgZ>;`8t8=9B;ypiz;dMM9@&O00B z(_}r^uKD2!A=1pGyjg46NM#6sSX_N8C8C<1Nz|xE4NV(HiAxCfvLwBlX1Ic!z%nm) zkTgGd){IcE=!TFCG`1cIwhVc|#8IzjYpx2X&$kU-&ECrI)WZb}z{+k(&~cdKB15$< zPMYD2uEc2>e*n^)z#t0E0YS64w6hBY$Pd{*hozzx16CQ{J#bMhq;~^+wUjxPk#xxv zpm)?DA-Ztk8K(D>{={76vqFEDIs6%@8;#+MCe!@Ut*qb*fY_iDekZ-Q^Z6YO4 zgNe;8V*$%7#%ntr^kS_1tsqJ8tpiCmrI$W!5@?7iEwGiQZsME7fjEXX!NAlOw}}(f zxwW7VI1(!MfXO(Cv-y(VXAa~;74#bm(4bbl6hhrr_Y{>6n<#j9S`_U;CoauJRK~E$QIYQ+Li|*M07| zHPr#L6YVVdf}@lwI?08{Nw5K;dwIGR%nYRL9nf*obn5Eb=c?d;Wsj?9O844)Y1PWa zR_snT5lI1}mjx-^|Miq@2sBL3Z6kGESUsnzftxx|K^WfLy>bihc7=o!6AFxXg05qzNaUHpJ|D(tpK?A>gXj{;Y)C7ym&sD@va|f zv1>E>5#s*rV~Y0#n|+HxMyB*}kiE%lZWHP$i*F%c zEG&pZ2FDX*Kv&WISH{F%(P|}4f(~bp-X?Y`%@8B{G*AQtx zn1Iuyay7OE$nsbslkW>IgBP1tqHg(-;NnLFIFo&-{TTC^jzED>NrI_y#PGWGt%?(M z?oP@rlQ^^fZe18id@1@tpKb-?BzNnzFX7oyf~4ak!yZSz{`@79Dgg*(hvx^EeeHOu zMII78&@b0ofG&_8#_NOntf45Eu4907 zE}>}UAJ=s=Lqx=+)h-{Z2FVX!mIhdl`#Ch*3%IQ^zH`D?z#=>mC^6@V!(h&A*I zoLj;)3zdSVf?7CGK%t-bNs2C;o1hlPpb$KQwZ;ol8j^~*gsz|0CLW^+LA8CUm_MNS zKO{nKg5pHSh`Rwe4wXCc7XIzu^`{Z|21XiOvS)I;M{Y>INInOK6hf|0QLL5^BnnRp zLth1Y4MTGOZ0j=m?Oi9Qada}1!nJGCC*ZIBV5ERQ#Nj0iHNIkK*9+O24oeaK;s-dV z9@HmHIbi6VbqOK}1j;`cq6apy)5J|d_(hqhYmJjnl`(7woS{dQ4UW= zANz!EVkI^ZIdD=QbLE}Rd^phwn2LY_5)z%cWTfrjTECVD6BBk}bk%NilEKLY&_JQM z2WTmo`-5i5CHGYGGm5@`{GFXy*28%x9NjQ0M z)dT#S{Ir_hu^+KMu5bDQW6%Lj6};NPg}*3&8K)FQQ3IL1y>F)(L7g=qd5c&axQ8W| z!MCw(=q~C401-TUI1yv3`HFBw(=mlLp(dB2aX+L7+zV(7Fjs?WefXanOrZEiSrp$q zKRURGwC^7xp=+8th#7b$`^~oqF@;3wV%Gj5&09l8iq&Ob(F8&Qd&fOsr?Ws(PQ&C@ zJ1FoSEneaxI1RKu2^#M<8t`xb@~821^JeQczguSYY*3lnjp(dR-Q7%G+l+^)bKQjC(i_2|UEN1>Eq*=nlf~Cvi|{rY zEM~i^eYDXBj6o{@yCKqua`&@LLM}D;aS6S9@9XdTcm9krd=GcOzsJoHlmRC|tLC6o zZJC)^k#UT4JD!gJI%bSJcq=(5?z6X4i3`J9KVn?yD3~g{&@;b-*55S2qsRVm-dJQw8Kl-&_n>SI?42#br+ERt= z075N}b!1EHy%Pue#hai>b(r)`pE zlF8f7em9N;;9>u^o#DcaD>D#~=Lmjy2G$7_4Kfc_RT8R1 z-h{7|ZkjKdUEwLkJ}Bk${)5r{0Kwm*H;nNmL;Pz1hkxE^Ou8f~hS6K!U^KYL7u1+8 zGl&mv0-X3OAY=e@B9EX`HU#>xYmspN#f)=BN6wy#>7)Td+_3%*2FPv!;^9JmOawVL3|wg{E0ZNz+q#?ISpIM1BTcJBwukqc z3Mr#$nGh-VSxU_(AlVta{852k{>1Rhe;9&QKk{}%kj7bboTg#YXcJHknK(kBET`j~ z*t>HI%3pf2JOPF zb>TtEJX^mh)6m99E^NK2Hpd_8pCUgke&-ypb=Mei;lUYZ0ftrn_omr796Uor%))Us&SDmCz~8CnrT^YE-^~!_vj<~wtFIMZ{4IUXKQN2GA;4xZ{>xxGZoOHUg?8o3 z`SCONG1G?fAzian={kj#=v5yq3C=1V`8q&1*Gqmu3DA@ZMR`vq{n#^I37~bxwW?`? zQ~d$^xAUaz3AyWHP%nU)?i|96R$3ipQclHwxFB47oJ{1rA=*gG#)6ARkPavW5(;rr zAXU`k;6Y5(h1#+QMD$6jP&CX21j2~^s~ZKdEXFp*!tm0S5{#%V^@?4!a)d5iA0Mg! zO01qx&V=qs=ACpBHle0&P)xLEnIEnDxP7z>{v2Ej0TK3Cz{Z!KEr%3C(~3-d?4AjB z`2yA`an@F0eJz=xy%Z>WX+wOHh5JB-nNMJcz;!vJU|6;iX|Bpug>qg%ij#r!bO{?7 zC-B&>jA|T#sR6e|Qm$|-SahUCaE0)50OQXHhqly_s-^-#?mzg1@`B*w1Q09@ z8`X7XJ8mxR_?@plY~chQa^fSyh?F6rm>i47a(N-Sn&?Wyy)Yx!XQ^ob76VI)VMv~h zZFc?!#b-PbfNE&gU~#x}n2^tIfnieDp#Gw3IB87HGcZwvIJ>0QqrfETMlPozY=-q( zANI=?LR+?OF+P$?tUq&jJ90K*QkfdLy?YFEBcPy@c2KTW;-AZWmLPeki8Iwo+)vC~l4%UDp9~7_-q!tL?>x zXR;vv3?FEKIK{aD@c9tbP$$vVrgTBl`+iEGhbj>R;8p^aBg~oa=Ml_8qNR2&6NRkL zWdhU!!*%l0Y_#W30v97{`D7rZY(|YTPpcYneHAA&5|dVz1KaKf&i1m^N#ndl!ng?? zT4_oFf0{5UVAz04qYkamWb?hs;Jim#s`e+^}M|tM?Wbgt-wGfg+Y)$FOaJ?4iw76vpJ59Xud(uT1 z1n&-J9Mrv}V~3%r%{S1?@b0lRzLa{Xq*;UMmc}>GTy)wh6Y;8f3$+lP}U`PPJr8I_i8kf#?yg6SXbJdrGraKu@=k z#$Ho%ZkO#M;i7Fz@BU;p0ky}m18z>M8wM*@%VKgU#8FuP_)Q!viD9@V{&|d>S+53| zDR3u8GRfjRoZJ~;!N?P3V7h4dMj{R2^axUCZzoAuAA^^cGqHuwui=Iy#8Q7mA=3oK zkY-%IFqN(Eni$HP!pDUdEdE_!MbqP6;f0+U{ObVcqX4NUZ=zL;JfS=Hy&*E+@8e41 zY4U}+4-qY#4TRs6ui)d5v}am!uphwp$0m=Ii#{_gYQb|&eTnJEUFYV_SP6vCVhr*B z+=yuSw#mO85^v+KlBdI$fU|42SfpwJ17W#?<09ON4KxY&Lplv8nD3l{B%$Rxg3S9z zGdG73mlrmiZPm=Sa#%Dn&$(pG32+NT_>~frUBWe|P8J zH>A+@x`fDS3h6ZEDa3Y%GF>7(L`PkK+F+0(6NdqN(3^r9Dw506xM!E>FNgufW*!0k43Nsa%X`(i%uCU1>XlFxN^WbrmasED`mk&YGlP> zA>;$+{3VdBJZGUyQ%wu|7Y$UIM|?RS(Wf~1PA1|h*P4xsJY{zFDu>VYFnnc~=dcCG z8;!Bl(-tc}K12o)>Jn*c>H2b zV%WJX%sOfKG*W5ga{Q?o^1@vhS#s(pok7s}MV9QgjoiAJv@SH^#=UtnJi3e#W`+v{ z$f?rhf0=Z&Y|z7uU9L)soAnC-_#(qk(Pr~dJjN$ zE4^jDU}ZX)t0b;5!H|qP?t?SM0d}8B4Nk&Jt;s>4TzU0+Ud4IA@R0?Gf^U^~tmO9> z)={JfD=`s3i9A~*gaIA&Ofl|o_a4tY~LmUVGkd=X!%^fA<{o#It5J-5n&zhb4yRti~N-wp% zmd?Ph0n)DtG@&SEU_3*CD=T^n9hp*+9wuB1D7$K!ay%Lw7-S-`ms`Pd)rc5Q^_uvM zY{4W|r0}xbE@dJP&|$iOlQH!XN$>(OgNok4-#Bmqkgy{CuK7%pBlR9~g=l+BM{~60 zV3(TB#r|xOfir~-$-W3GS&zl=nS5#FEa^b$UY9<07N0Zl zq)*dvtPdeEywrhdYx+9;#3G?@N`Ns(J;BLXp`A#yh)T(&=lhqY^Jb!h54J z9H?436;ZpA-5?SM#0BSo4r)NQS{?S~Jxvn}{*j^ zj?^#tPMSCPeiqBj{jYkI?!Zd;JwWIsLxZpy;7XT?NMwUPtRRs_P||8l52x2Bv--o5 z#-!Lw`*{s|B3z1=DddrHX*RUmb}aVHP7*((396%k(Wugk$FQ`IS^*;yXU0g92|K3= zQE?NDj)~vYs8h#gm@0$bPU%b9tU3ZbQzVUt&3reQMxcB~WRHj`1sRxM5c|ddK5BMd zbPA#nZ#oS6A!SV`{d;$#-9sxSUr1BljN(l>&`w-PoMEJ}^ERgp742F>Jx&7Q8OF+I z|CGT}!}iJ)xsXLUyfMblLQlXin;=&K$9}uFEdI{%t!fe77c(jTe2=r&M%kopA2Ua%|M#Z3 zH$rX%Y&yJ_G2;YR{GD`i{B31YKi|CaX>${i;AWvc)Z_Xmtc)#}U5Goq?^q=#;_&dm#G?-` ztjP1xxEaVG0BUOmb6C_EIatY`p?T6)@eaWiNVR=u+vmlO^LcYY$I`Q~2+HJ3t+t z!{)2Q@$kiHt=ZVU-TeNG%ZNnwv96xd%~!L*;qcX9@{@o2`S0_$pPusV!{h0*W0vLq z9yX=s0sP<(qn9soFNp`1tND~UNdf|~7bH~Rxk~U&WoQP2hXF}WrSLXFf(MUr<~7E1 z6lTCB1YOw4*&(yxD<-W^t1mXgqH&x5Z~M02K+L!G+13FNcXQM8 zJLw*S^6Gexqpjg}3~VPSK%Ew9E5Ij`+k4wDk(qTH*=G^v-8DMgp`kyfa@wdY*IfDi z=bviL_846ONjSxZ^F#BPfh|1%2=RGI&YFr$w5VxN52$@PBqMKD8}rJV@_E*UjT%Sl z`}>cO5#eF7wm!L@TW*erjBJP~h3}^<|Jk6J=ZH1+B3Dgrk1MPCfW!qEoQk!B5H0^U zx^X@Kox)}5#}geIj<9K~zee6)#qmOJY?> z2lfh}e~FMBm{^EVt}pV8dEV|~*pmDQUKtr$egMp4C?hCGF=dlq79{5|k#8N_D_1|m zzn}9^upxA0TDgJmnHYpqi98c8NjrGTo{f%Pjd19Y!Sk{>7xHXe&N#S^P_)0= zOTK`b@e8fB$#{z=w=)cjU_$KY>A()O|Y9FKAHWQGzJD}#6QD$*~wHpW98~B zP2l#7ObiGDFr757Q2M$im0}O4PT-HtlauY~j}3DB{3`Mr1EuwAp=HM2Y?66dv9Ed(mH;J}h>u zPB5=&qp4DcK#(DK@(fci&qyc!ED~`z1%*wqINP0GS_TUpuyp@X7i8+fCT3q2P7KPkUcv2nAk7wy}(2Km(`S&HGZ58Lx% zty*N<#x1=Cf7*pgOOMX({*R|WVRxtH>0!0VEna8j;dnD+CQ__O(+r0rQPO~(y{f;H zy*AYzbWy4dI5^uG!<@=FO5aK+{EzL~V)EG#Zd0$rC<7j8KD|??K_Ng8nQOSk{s9`A z(vd_La(3V3Y;1X0|Fg5w@`%eqLU*I|I;mbi#Mkrn#!o|7_U;VDsy^M)(wcR+oY{)@ zkpfIvm9iHEif0qC%YJQzI5Z$Zx}_@E9=AN}Ke| zdV=7OWC&)z!|hV@&@I%GURWM<zvIM&O+zfLt z@xZBM_F@W~5UR}q;W*=FgM1BH{!uR#4hqVlhYSsH%{N;T!@apUrjDfzi0QxJHsKbc zBwdEzE_%lN2g*cgExmBgGgNfer2clY*-?Y)5J0ub?J89UbfI>>GV!ErL z>4srH$;?GC$c(YvCF03s{7k7xStgKfvwH*>9c2H$l8R``C{|M_;3QR-OcgOC+w@+RDVUFkTv2=V>}lg5<|!rM&pl~E3od{#g`pz z2(?-UJo&N9ac)&#){ma>?W5-E7CZ~*;}>?asuN0{#@^00hxKOX(W9MP-+p)J-lP8R z?Hg}~WZ@r3Q(aiI;JwG~`jO^-h&S(Kk6TJ!9f96+_#;ALbFht4<0nzFO z+!&GM3k-AZA?nkh?A~5umx?glE6*dS%JfCvf!1MqxA}A*vCs3u6S&iGi|3{^1{o?r z@}$)QB4(k(hh7=lY5neuh9E)Dls{J$T~w)_0gTme$_>Q>nOY#f%WW6+XK3$4$y=hM z)C_>0Rv)xjN3QKDRGA)0u|-nhqsQ=6;1_!NU*gaIWtUQOTp?R$GJA{8(S6vl3q49* zIE$eoj00Lnu0CWY6AsI!vK`dMyH@uJ z)Yj@l4Xrp}8bA3f?}psN;e2}SS_bdqDf4?!Yw?&&Yyb!LjbC_#1`h^Q?OW^q1qf$fgH1JG*Kz8`Yb!9gJ9!Xwp!q1Hshhf0E$x(RYe8U z1Z82l4^c#N2v4s0?u#kx zY4~|~BqVV=mxQPr&6ij(tZiY=<5O0h#Xbhc#d%oT^_?lwpU0YVke`{aG)!?^&bn}1 zvLGIxW!`c>2neJVLhQ#bVOZh;)k?>ExVk`I>?7E1`f9WEyJ9Nk&bI&$($g`l5fr;l zi1nUnce)po(6*%C9h1uY+?rPEAWe+h@RpllXZx(cPR7iomQ|^16t`>k# z04%zR4uEI8z0mDnMIZc2zkg7s>G2eGU*JS#d_0+hjgr8>6}~wAtb$=`8N{IK9I=vk zeFT%SY+JR7H6NOr@KWMU+!!Rjzk&^ER&MiH%7!Xw1%6^Je&kblkL-w19v%Ub0R|qI z2$By83v5x&_>`teJ`yY|Ap-R5wj!-eB__Gcg@K^W;J>hZV>e~j>*I!e2*EFGw2o=U z+m`KP>$#IKJk6L8Nc#S_+O%}ZL%rY5RvR_I20Vl<11gD3yM(v^P{{$6!g3)ZgeXuD zGq3>(D|)OlU7&*zaDFe039eoW4$--8P@HDQtlA#6I0DbJiXtZ8Hp|M!3u90BO0?ZN z*kA|eA%crqUC`?eaFokSBZ5L#h7t;tiH6w8;1xOatz`U%*T3pY$_x+uw**-o8f(x&uPwdI0W zs1p(?VzMK@&eS2sX+dxzt{Y{+uq(#6VMtex=t~Ft!y+}za&L<+xSj1{Q}zs9c5_BR z^0?A8cbL5F5zS1+O{VLIMt$OW?V|G%v|@u-!8|U22Um~9gXEBLK=na%48l!+QJ^Mk z!oik_YiQi_Z9$JR|9W~~fEK+R<8B*yJI0fF^WE-ucNz&YLqx19G?M{Kt=vhaZmX)S zcGNsxp9&!-VU+|qKXE;(V>q}Aa+!6&W?F9uu;dZ?1e=a`RUfLuXgW~YwZ`8f3=r!F zkBMa509nSh4Pcx*P2+v&Iy$FOwXk6W?X?T26?iLU+u4Jf0&7dnr=@nG#OTpWvsPf{ zkpUyd#>m{P1)#ncKY?}hg386Hzw2AVgjozJ5R@%xV30e32cV(bf;pk#4Lp+O%xxDZ zyy>mMzXSJPbe4vb#}Elg17K$zVXLwc+>E9&)?@?5B^3m5 zkyU5%%k0%+g<361K)F09r)_Ig`8uguv8PEkUAr}y_IUdXZ+8+P0U?>2d;?P^0}&c0 zAf*RKFdX+uaj%Kl#C2I($K>=;Zb@s!#7cEfn;x8-$mrVsPRfoD22S{VxzAO(kukZ_ zp+u%vGfmNJv)dn~JvB|DHAgK|Co*JV%<^;*cwy--WNNOpI+6NKJGN-mT8~B@560g_*h}LS7wiBnJf zSQoK{kj@xDF+%Rlxg4XcOZ0<>Cq0Bj?ZI~RLQZ{U@PWKvjowqls6d->9`}u)_<8c! zgmQ0rtOIU=aOF8IPmlAu>cABPEu4YC&@NUM__ve}oZ4GZ(!cBJwKHNsE|v;)>G^XN zHY^?jlmWp^LXudtK#z%*=c5e?X@rtM4j_mJ4a*`s=e<%@Z3UaXIHlhl75PxJKZTCC zfv5#WZ9d7jKM!fiRqP)+PM3DfkFA|CxZ4hoUT(h}jal^^Zdw8(9cs(AI`H`U&k~1T-Tata&RK@=jTJ3yNGB05x}n(#d=^qp%Mz^I9cAHVNFLj`xlckyvt* zA;P-oVFAB9bK`C?5hPYj%!8pUKpI>nU|>tZE%WDCRn2Yl&C8rj1Q~{C$GKS}IDC|m ztsG`7Fr?XpUc(rD?{Id|sAinhCRb!};|v5`K=oB{c^7trvu!-_9<*K4<&JF5mzsPk zGY^ycXGnoHP#_vYwN@TMI5hCctXuw>%dQtY@I!@P9E%%a!c0igfNCS}3U8Y!sxB8{8l^l@eg{+K{ob>h#^mo|bSkv+w=S7YYPBcj3u z*Y_F4gEz&4bO|V&!ZK_;(K>ck6E~kj@z$P56@tA1-vhfT>@CB1A0TZS{-}mYzoX;y zfT!M7uAr5U21DGE{epJ<_k`^a_w<|p@;9Hq@_%WI<#Yb#zb~;Pz+=u@_~uBEh-)q9n zb)c#8Kf8PoCzJ#N{#zkfn%C=v9`CS^_v4ph>g|VZPOaD(qH3+&YozErp#hsf!=9&s zmuW1tEvH861rI`wHEbwNJFCWC#i=~Gq_du#A!3f+CyW6|?Pdh7C;67iFgY)Hp~LHF zHXTd~gB-5o62Dp3t#oHAfOTari-|LVMPGyBA;IT$ zvmnA3R<#KnD-X2P^Mopghl3NFd%+}@;fdKpVr0!RJdc-86jW&56!K+)cBWF*dsM-| z_!n2Lz15{rtHQo_O3%cFsMoaidVT&@C$j%4T$y#r5F&%I^V63Xq&{O)YZj@&ITje- zoVLPf2P`$yELdcQ zAiV;ET~O{bvY0BC5DT#velYN`=-OuFAxf}*|ZF?AHmel zy1_3OCd{Dg5Mk>4Ej2_ccxLukH`4RB0$a%)Q#P7}os~JpPFG+I(cYc_zla>1sLr1S zp6nuA@4KBpyOdQP+`P6JC!gX6s;Slto*@VsKw~r$um=(kXdLtv7N z4}C4~3ZA^o`_3n9(&f9!mB zx4Ffn*B>B&_><;K&lA*K-uhzesy{<6$Cp5#KTQV1W(Ncn>9?lM^`G%`3(B;9e)(b_ zB>=aOUFc^0(XE${SC-<3;y%ErBmG#E74_@bIvTsimqU+><%)9+h48dzzz`H7bU1NK|zgUNU> z-{|Tau8}qd*v}aT7*F>m$FRR`hd48j%40la7FEb_D6mv^YnBb{7$T8}%s@N(fOw1> zuK5X4iT=WxIK1zAKAYfX6-a%pA@E`e@KVECP6qpv4~8?rfB<70_hEE|l!R7N9kXlK*za9j zNj%hWsVVW2?80bNbh@}OA?UAIo$&iUc>tiGHS)?^n-Mk#SM@54;I#S z8xNt8akFB+F;&|%d$m49ykxUe?y1AvHgL&iaY&qXe!O(6I0I{P$qIX=e<<^SDA=}n zF$7T4&yQxGH5+SNTjG->NNXTYM9j?z%Lg6t(Puq;`9bV5iLiY}yFY|1-niI|kWCKx z!l8{}lVt7mm|BuSwAJ|0rVI~kHhLdzDF4LX8#kxpUoS~|@#*|`PuD*h!_?6G8JDO} z*J*U%NblYs1MXz z{S95FpHomGE(3GW?iKM1wCNS%B1brcooqdw zu7UjtuT4{jKs9PAap@0M>EmBw?SHdao0uFWy-u~lh^ELO#6d`bl2dU3H>H1t^fPQc zq&nDWGFQ-TF9;5_5zBWJ#K$@U-Y|(C6&PcuO|uINuGM~I*8fNeIB3wr3FJ{o?a%~S zZP4OuAh%jq6iSWZ!mqrX>|cK08>u#?QT3yy}t&ehQz9c3YNMMqzD=q|QloD29ZRtmZP;hjg1 zcJF=jkUz0A2;zHi=ezrl{sSvtdwMzk52u*TKS2RC9n_KP@IeirE`S_(%!aJ1ci1Ly zz_|r-9w880OXdz8 z{IqFfjK0R8=|3VW^2{CVAAN};X4L5i3g(1)R*_})jAQJNVH)L6fyU#`)&-PZ==D=n zECtA_=gdI$!{Okde#6s=T!Hg%P%z|RX9^{UrDPqDWfyfr>Z+aX=*3)(V16>yqq{iK zhl9y|rX=_lUb%3=g_hXw_qiE;f7|~GSr~u9Lj-dc^LWVQk(w;W*Ky;WWzm9mV_Sbh z0*S8sNUwq1Vak_&#Ofl)lOYM2+^uM5evVl&JsAc1$ZLo|b9x;cYTEW{Obpn9J+gle zPDVowRZI*GF^z@&RIOvYquFL*JFO7%dVdPiwL8R7)IvT%RRED%I0M06Xq3;?58y5j zIcACeYQzkHv>q3N%Mra|{j=+ZsVn?oPlF}YlOp)); zGsCZ?TN`bz^@wtk1*zohf+7&)f}`Nq=0++6$Qmq@6MVuw_J6KKQs5!PZ~6g%eDAZZ*si%(}}D&CIoWn_-l*2PN?Z8hIg@tYjdz6;1l>=%HKPNmqm3-|`ELehR5m~2ZD{gTM zk&XAaSbwP5&h>@f@m(PH0_q@%u${Y@aeJHI7aC#BKs36z73dOZ)QL4dvG#-#-n0-V z`eKydHSs^O_{92Ps$<2Dp`2<}u!EZe?Gbk7_$k8f*&y}fWC-=9I0OH%(_u3rY{;t5e-L~{HC;dRaj3uU zIusK9?C26Nl5D^F7*K#)Nlg*-V2s z=B?HtDiz~W3G>`RaxoHoADK{)J#+T_dFr8o?9aIqqcMGW#n~6};cBj8yOY`$roA^$ z=SRa^ycr9Imr%0R9LR#pR|$;ZK?X(1zM&2jP$J7`1_%P9tDAsJ>gcjI0@r=<#;t&Q z9H8C!?DEA{Z&Z7513P040G{^#5P9uDbWu} zb2Tf6pg7EMwueNWQ&L1 z&zk(keP=xlJc3E;1^BI5Uo@8Mp|15~MxoDc=#Pu`+vbM1@@kwN&l#=>;A~!rH;|Al z(%(CPh_|jb@TOF(Rq(a6NONw7(E(Mm*&Vhb|3KgTJbKTNLVB{m8;Xu_VBBECOE$=* z%a^Jtf&-@h@wY9h=(M$*a>%!~>-t~Ux_t}yecJ%CgEO>$fSAWZha5Bnz_uG}4X(_D z-eRv=)lVi#zzAx+kJ>4f3ASX&@`&~A#&DW0KQ`gbpdwR?HX#s$(`Yw!sfC^TpWba) z?r1#ok3|057Mkc^ziUJMkOKHESfe6Yu{qf9%lK_RMkxpL6nP~AZ^q9zKuu=P{(?J; z4M!F-x8}L0W-Z0Hh6$56w z*H$j8wWLsWNm6k~^Ad+-4}LAf!x4$`4^mlXunqjt=ZI$CA(=PTA|7Y+@cIe6BV9l3 zVL=<>Y>=iFQ?{#1yO;Qt^WFiE;baU)e4-AC=6CsYW~v_N4XgPNJF=NL#rIC!7EkvM z6;|K9OFoQ)(I~PA=JIVeNJlnzk9toa|Bvy3t4OEA&?(G2@469`KrLJFnMsLj?(c~<)oCAO{5IQxV0L<1e8fZ1D0P7NO(8G z7;HhQ7pP0Uu$)1ympm&#j2EK~C={0VxYYtPDUd`0A}sH?^FpKnd~KZBl>(uyeyg|H z^tKEL8xF$ zFBjvVX7h)dgMrl(wcZ8i9?b4EO7Es&N-s zIUL3|@5uH)2b{2bc)Tss>3*PQidOx%1*+Vu6rF5eM+OYFsnji=kPlscds%gfi-z`i zsrxyUmW)O)#A5ui>#V|Ca$NbYo~BdS85VOeT}D@8CA!%zw_oh$hA-i(PwG0yAx78v9^NGb|hfU8O^&CkDV{zmG zxP4i7U`$55UVV6+y>7pn|A@@Aj~^Gg1os@h)^`9ROo??kQ z!1C1?IQ?aNtU&;U#VR{vJZmpQHfp^|6BQaHuWb>uaBDhZsC)#g!6VHhP@IUIjCt6F zi_4sI;$jw*x20;2*fYC%m`4>#WoEM#+G5KuPLOa*aSDxb>*4K(tGcOHC0s;hIYdv6 zGM3(t@S3@b=bTd*9TE|EAFq?O?`e8cat8n4ic+CD&ck}aVU1T%4DQdGeR%~ZeB%SE?aKu{q`4@ zD+Y}fo3rBOLN@#rA_+y065LmK8h$h=;4=_y)qS{t9Ir zINg&)iGzBaTtR%FAUgplE`B2y-F^qxtxqg++5y%NYQ?>WYqyd2(!2ZpgIinc4<9H2 zrp0=z_}>r-o6}S7+~kvDfa_g2p6z)VEu7_#iCDJ$5rKHo(*B#-L-+WbQmmribD^kO z+X{rH_$#5919q{UBYoc|v>0cQ6&-Zw8lBlM5d9&TJ$0Gsi;;&D>AhqK>9{|=#hIyH za0u&=W*5@8v|2$FX+@xN7;t{9j_Y;2x7C_@wcRn4;g0DnP5Sm%H5oGrMVoqI4_5e> z;mavjT$T^?`Z3;K{~TKabq&~><_mgd?woqW8N9S=_jb%8k3%xZJOQ^cM5+W zfF{Ch61Ca4ST#>i@hM=FZ@`^1!M{&leDiu;fsg}#X@lg?!?cm)qeksvFk$6%e^xT@ zTc|OC!Q8Z2R6z5165QS`I~S~X5TAgPR2f0-mOhrRj;_4r6f&ON`68$B=E-YBmWN8G z@X1;2R4z;{cT%>#&+CI#a8!i*h(AGjt#6?CUhaV^6AtyMyg~vDFy+I+=vFt{!2@OV z=WrIOQntgjpg!QPPH1ok0rQ?XPa}d%KUZ(St58jY6M@oPa&XEi z-a#`xo< zrNE!>a}P-ZHTRfkz%nSnq8)dYz6LkQp}2lhawJ~|`6>`Hl5g6@MZ2?4KS5Ua<(>ZH ztBbsD7q{&iJ-0yU#<`myh*IAlAG~IH1pi? zf_Kbo?7Z08Kv?7e&maONshu&7_@tu9^hs7z?0uQQCzZwb6I=tut6~oJ8F>(BQ;k^y zuWX#gazZcqLCc|nMPd%M`eJ=oN=#013~8x^w5*9xwlLc-$byUTu_SeRft?KQpmSO^ z?exwv#V2Zrc#kn_`w7_9h9xhVl)?=YL->^28i?R*=_=ZVEj1`Z-UQ9)-S)yuE?e;OU7`g0#r9~uC~D6ag1WHnAVgE07}efj zFoK}~V@EU$Re2bEIWBFETApI*L?8xi3T~m`h1bot`YNSP;gS`d&G}G(B(<%k_=V@pIR@^1cMvlaDk&Y=#lJ0uSc<+VR?xNycD*u! ztvz^zHM8$RuBKt6x~RQ#mc|Dz7&M;sZz{umx$HLm*v(;!jZxFP{p$R{_s5*x&3-mq zp5JxZy4~-1CjNKFGMH<4yTI*e-PI{L^LV1R=Xcp^iw;E*UE||$Q4`u2j@@%^tg*S- z?t<4^MKamNe$2%@A~;m#MBwcjR$`upwH}cJ@CSV7GN-c@J;w=d#&zsA^^ta>LmxT# z&;jNgtes4^c&~li9b!*(_SDB2ly?|W)qcpF@~OB*1OZNijHnlo+yvem30G(kCk~DP z3$pO_W0_&qNT9>H@Q%RA{>COHuk6PGXR3on?M9Sp$HRF%R&|4imx^J>D;<@zJ88gN z^wECP?xLDR=_4v?t!Xj>IL)|V7DfotkE2e`fG3wG1i=N=z&Zb%iSsNDr7`}?Ch{$XXvsB z(SkMzRkny+!fJk;u^e->$$)TL>h0A}2FqEq4dmrDXi^4n*WWgxX)HM3JO(U5jqulO zF_KuRzY=&n_OW;e3RGkWfEhy$hMo?+WHLJb!H-z+#o?UAs8_fAiZJA@m?Raq07QtZ z8r+E{6JTyp9k?^w8*+!|p3(@I#0K1e!{;o;E9{uY=d|N^MURcKvR)d4QhWJ1V+Y`< zyKSkP4o+ex16~AH0E?kJ zXu>?}HfVZ=f!*1Q@iRCF^ftXpI$d@nKjOWUQebdXB$GFDiTGWKnM@Ng^KJ%_AT!QYQ1Y2H3Hn+W4I=7Zo52a|{Wnk0*#{(UVfWY3 z_U7r+wPRL=Ne*SsK z7_rS#PsP_k-_a(vqOjB2ib3k2FddR9;=>pR3E{!__wMzZ&loY+c-H)lgSNz29f0zH zBk^mV`F5PjitXDm#h}0P(_rcC;`WWD|NHUP?d$mWr*v$@?&&QCV!;nj9CEvbqU1g< zT2m7!0!ZfFjq2xAD#~~NS-cFP6fBTb5^V$7fn<%}LUKOYPHGtj%#-9CuW$eI?~ggX z;nK6UrMr)>mXplL#76sW^b3kz?4dgMfwB0=&u}1KjDErE7^worsk=NkOH3%ONqb51 z@ZuIh9-xowS$cUApdmUeTQ$AbL(n2aTzo9&83jHE&tQF@EY=G)AE&K1O?CZys^!S; zH+g9(XD>#3FBK7|%+GiO^VqdiQ@dTbpBpHr-DDG)qlY(TH6?c-lI+s&e|9#mDLc1rc61zylm@>Z+=vT-=k9mLuSonHnMy7)vjD^8G z6&AJ9{?@3Hg@wk@?T0LWvF~v*^WKu*;_kwds|Pf8pDrC7V#;(fCG89+d(TI|;H&=1 z0CCc92ULR>SBfaOy!&<$SjwY7e86B`uG2NoW1JQ4&IJQE0~BqNfrNS5=hQkX&DDGF z^St#A4;d5|EQ*NzNwMGoaRLQ$r#;bmQ~YXmz)60!ib*aG244+sEW!!=`0Cs3pX3Q% z)T7I9KM)Qa3^GFh^F48}sik@^B&Za&<2RX@fWX;~%*qagg#xcvZnfp52jkt@hQIvH zyPfTw$8eeNJYM-efpraJi<5E^bVUdFZEA3O-7)`*g`A*Ftp;242xsJN%9P|a=2v*T}P_~a8j8|oMDxI6Jmwv8nZ^~ zIe9P9YbovvHuIhsb|&6MyCzlU;<=`rri|{dh!v|3*cUGDeKOlF=x`it_+mO)iANXR zl}eL8s+!`I+j8?y(=eeRw2~;+usBArqui<%&Q9;c63vABl-Pt#2o{7 z$^^0EihRyK-1nk7@`o;hgWR4o=W)Xg& z@;=tB7WWKXvW=rgV}#K|BXEXqdI7V%Hh8p;&=g$ei{*zm^k6zY!X<7*KLmpQ8+N2K zRQ4)a(LNh4f!~!K zbjH#>h2seDCHy=*|K|0Y3M#|-$^QoA&GQ-07BY|TCi#etF=yNM8Nzsw{wC%8@;9hd zt5Z;wTv>&eiybdt{@h7FiDf%0W$+YDh`C({d(7M3n&t=vE@s}y8e6^U=sjk{M!5?~ zJD$Hs??!M*i4+>0Uk82YoB7lc0U+z<8EuxE%Wy0(7;QQc0_)i`pd$bxVUSh727yVj z1d8i5c4E&nSF`Sb1I*p97EpRVK?+R(v$a5yLP+^1go-QF06PE;iPWITZu*PirF$dd z38p$~44w=%y#IDMToJ}5#zvf+>@trV_eYj;Z=JU2Ty8pdHVVxtzVDoRpmq&;h%<`!Us$|3Gpp1cE)M+pWMr z?$PkaBt0b|eeBDqc$pO7V7p%DZibP@Yn5Z?rUw2uQJMW@4 z&P?62O7y_M%8;8&SXkpk=qY^Tgqvv6c5+f=ZI>qUsUs)`yl40;NvjGF8h<%qgkfS>MUikl-E2Wvp#_qa^nOR4gZ#g3g2 zEI;xB+VQE`*^C#?Jh5bSd9&M8v^N`kuDdVxnHipTr>|M(`j^6>WSoIP&l72gk-&a~ znABOI?hJCQLIj9b?kHey%_`%YzT5*5`eA|gA(IXeUZEqeLtOdSGvY)m9|;pTfzLe! zx3+cD$hs$Se(^;?oovjqe8yC9T^#<9l+$0a#61LGo3^0M?+d4IEV}>%$%moKI(IG7 zOGKX+-7?)k<^5ESZ~WuSo3@=2TOT36tNx&K<2i(HylMBqOnGk%sjZl|9iq)+dvW0S zz{tGXw(KW=$4%=vj~<+4;Y3BSCa$t@v1GXRhe3aQ=QB?28=Dg@2=#+u{LP#X;ML<^ zBz#7~b(npC6P?hLW$nl$S z^k0nKY5lqS-P<yI zLMRsSG4onCg}G7Werp98`l8m1f4Z3?3DUE-;D5D_Nvzf1l2I1z5(tJ7FzfHOa5?PB z@HygU?4lD^j>hqjR5Y01kX9a^?e(29bIvY#xQajdV)@grZZ3R6KY%9P1zTu!F*QPQ zCQhHvk7;+sM1ujLL}cLGCMV*8^vK3q7f5Usi=n=_45{uAV~ysa7%MAg0}Rt;?ai`@ z$DV5x{j~kl>f@_8@R@zOv)zHI{B3j03P~wI7wWl3!QTTgnthcI!FAAbDw9IK(Ta2vNGmMv{MR2{BJty&7Pxbl7gQbz1)+%Lm2qT= zVk>^o7DQ?5I!El@@Y=!I{3IuUA=StYBdXguVS4H~bO;+v)O%8!3fe?OojHX7*tv|; zO9Mz8Bl>vKB<)5oNAZSxKAJj8;T?m`X)>8@slQSZt!vKflbqoQl7dQGwse)Hgyst@ ze)s2#9;bLT~?VplP~EfjrG=POxkY* zgu6RQ2lel$2tiq6p}7ynvs;#==Zg?*mP0r4SCSt#^e3!Y2zSOlH^#MAS$6|d?U{&D zeX3p`rOdm&@@~>-)y8OpFVB1fc<&;L_}TVkoEBn|&mfFC$D`3_MhLw@G@}u$d@zjU ziZuNMx6MB|CSgFh7%uJR=?5lHY1o{qe5BnV_mK^w_KePU*Qc`BPCGe;j7J)IG|Z!IEq8nq)iVbYOIwHRFj+2FEAC=TG+$K9U?ccZ$NcTG#{kZMLovwpiDXewQ$dP=VeiH9puhbF z3DD^j8HB;z?=HsR+=+?s3!?;(2vZS?a3Js7@R;w=F3VGHO{Yi4>A5zkK|16qk;wGOFE)f~Kr_hxqCJDel%B zS%mZqLBy!Qii;MIAtg3yTgXIApc7js%bzaVA3L+fPgfD3 zYt;%o@^Vy0BSJGb_&uWsn>_`SS)k@FhMU* z_QK@Pq4Lg9Q0OHUPd{!Tc9;#8(mWj(7$xVlq^LnACK)=~;H2avallAL@=t>u3w)b+ zYF}j}rD3Ztj8V6_hI&e%n9XnHC|KbTrzvHAs~RKVdwqgxjwZve^+qRqKI60=P2#Ty zkv>DLNwwrTpq2wMauc$NI5}HMo`WVEnsf>sZ4zIuN?mJ2UGm zhYoBlSh+rg$uRpj)`6Sp$Iz1#TQ7v5_RgY8_1q(SGF?lW93}fF3esZKAj%S?oN+WQ98`Kzqa&u zWXJ68EVY=QaUe+Ve*kSIK`*_lR>war->0=RHJVGd0h1R;Rr_P4G{BheeZFL?C$ttU z4Fj?F?2%QH(m!k?=CT9$W!7R*#*(q<;6YiDk0)SXhRoK0pLPwn^XZ2jv6|1|%;{Ki z(tFLP?)^;I7k&l0a`!wz_z8aTFTTLP=pY|pFg(C2EPt9$6~LBV7@V;XPSn{{>=x(n zo-3%wNf})$7Aba{mQzncOp;P#Co_dGM`y%&QPNiQT@E*G_eHAi?u)1IRR7~Lghp2@ zD>=R<`&h(tx~EAIaP+MTXvChYCn~v*5#`RP1hfw=t(;^NtSz_(pON<8ee~|5FTOf@ zarDtgoN4c4WJRIMLX?K-^?%&hy>)NB-&@50z4_>peg8SW`e4 zD8TvK>G*iG%NwP0Cj`&nUR?#L;Dk_L4SIdt8Nhy^BlO!{e(spy&AB@m37&<~ar)!) zkDAXB>G-_+>CV5-rV~VLpn;WOYBsx#`wD2H?Y(|9noSSj``+0=#m{E5I}EA3Jx0N3 zth zF=n%kqjb*Woo~SG&uQYXp#Y)OCaxl$*VPXQOu!`@JN{qQ=9vdhG>ZRjjt+2PTO0aE zBP{s13zhkeQv*(r^0Ow4`Awpo{OF9vxe-tdB5lp*`;+m(4%f!+V)w3$(9=+9z5V%} zUr;Etn65u&Uo!-?sld^v$S&uIy&pH0u-S26vvvss&OXKeHy^`C!9(W5!&3zMzFs;6 zGbKaCi8D%~@-nS;ON$OCu$}?MdTZFVl~9|6SJvh zR-zypHcK>znWRgMkhK}`ts6xTX*&h%0`dT1VwRbTZaMU}6BtzN{n0Ov2VQ&k)zQ-4 z!C2LI{re@lwtrb!j3Ms9IX}_m-Y`pWDF*93pep)tZ~AH?T+l?(P4zJn7zkO_taocV zeTj0uFS|y=)tj@GK)@0%{8q~qs6j&fC!h50{QKJdjeB=C{Rz#JPkQ$-FW8H=kAZey zFV0Z*OYhZDJVXe<4CbS~xC-ZX*FW=~ceKq-^IvFoHHLU=_dg1b@?UR}&5GMZ#z-#( zS)BRL+a9C=A|YqJw@ioSMrV86HS`D0!boBT5&$4zWwe+8Xwz;s#cU9mIXz+_L7a}W zk%BgVMD_0t#1Rtq_=i*f8QTQ3c>G7rB5?HyC|zVCV-s8(Da#e?f#6hPNn1ZYUnnWb z2@a3ATN*;(I{P8+@m0Ju!Ozaix0r(6h`YJA6)m%}fZ?GnoN5aZq=S*Ox9iK- zum4}5L$KEUG{V|sc<}n~;D7)8m(OCFa;vBp6eKSPj=|DLH?IHXAA85AkT!;4sVSYG zAP}#;>e1hi$78K1FPKwB!FciQ2;sT5+DZANPME+imSOXBkM~-v_BM>u#R4)5-Z&-6 z=Mx0~#>)Dt#9$R2Lu~n;IFphejc`RV*C(h8`v@1Da>I+!zXy#57`LH%2pd5((3_=; z;8NZ*Dc<$ybKrfRQJSbda7#pKk0o3tWKnP%UIUw72YjXwIF7%5^#VoFpN@D^y!+}% zb+qwnkXQ?Q|pwOjwT_U#=M1-X6a-*>-%bdPQa zO61w<%8E_3LnOm~_~=r2lopPlHRH1|7%x$uxrCX1b3A2zR`E`Gx)W=3@c23b}vi z7w^I+j4GhqnNdm}n~UEp_im4#4Nnj3;%DCB<{hZ#6!K>H{pOclR zAG`}eKYSeh4NR^5u(p10?VEdddUx0F+`GNW=X$sGVuaPUnSw22)`)}Lhv9TEd=2t` z`Z^$$kk+-}zQBT0eS9j-#s4gn6@TJ7iT`r3$zOT`0C;5@{x_NWmG;0rJlC1vYZy@&TCs!}wv0vK-#4zG9<3anE**}alc`Q8fq%ZFX};QSBEb2+2ka!> zY_+!rK?3FdS?nH28q;J+Z79)?92H60G#1-Z#zOth`j2=l%yNm3LlEQ`#+8wXjp+zo z?LGM4|L@+5DcladwaNbR|NdVET#n{d02mt7HT~`CS86&Ojt(aiBqf~u?5tyHe+vHd zbEs}@e4P79>b!xU+v+&9{+a20vYd)9((La1jN-8OhbJeQz&Zakv!AaoBWRWXUV1t@ z8TyaUY?`JtrYWaCsCwEDDs;1zrz70doks7N8QJQ4p`!dCb=*LNb62Mi;o(%e7WJx3 z3EypPZS>YQ){AZ~jGesh{F?t;0r$r#*?2EqD1dZFGW!8i2jB^W_iDO_90G(z%VTxP zeRYVDeuY#9vuxoCvX6LLWWG2nbnHfLZpdOFWtX3SbP2w%BxhXl0jI1*O%^8`Nsxd! zxGI6uEEV$6UB=^mn24^MI(#T633C$WGT4}~=1d-}Y&a`9mUnJ8m$VWC14oeF6@(lN zS>xKD_P&MqprEyasAC$;;Ei0az0+e}5`a+h5x6HDLrCQTw()}t=QQPE5)L&=%C03~gd}~r+*^O9`^uoap}6ERxCOQ3x>0oBH~Eu$Q$92N9!_hh z0M!IE%_jPwo$0hxkToC^GP1ELm~KrZQec~pS)#g z-CN-Erg{hK#EWY^yy2>XA*2Oj!)u&=f>+zK1~HbvR*rqmM06&?CBKlJcW{dORG?J1 z#HG6(!{1~4W-wZQzT9o%t$q!S86*ZLO5k&z(7Uji8ZMTE=z_e-Rx9awwwllN;Xl5G zNr$m|oqBd{vBuZQ#yeYq2amjv$(p*osLdK5l*+)bv|6L9G^NTujJFrCTchcF8?NzT zGD0t8xwgK#fax0Fbla}+wr#w|oB7sjv?v!O*<2eY3}WNaenoq2W|Cs(Hn2?;`_J|& z8(*B%Vl6 zjz}D+7xG3xZ|`hTMXxEB#T()hIqK&Dk#{Oe z{_Hvf+C9EU_t9ybrJMBPoz8G3yzi0kT8TFX?p&JP$2pJI$013y2y1}TuOK9MAX05l z@O^_>oQ?Z*OuY*lR39fObzl&JRQyD*p>FoDlGP(3U7&gU=`psVsj3Z91O`i9=2+}t zh-ethjjYk{E&>IW%d-pSzw6C*xvxoD(E=kEzkGI=Fsb|0)@5W+J(h#}DUOTx{W`^p zTNuKnMze1~Vwrug8R%(TT_sUN62ZSbSX{cvUk>2RVL5p*0NwP(5g4XmD!F(x)(Xn} z>F}Tgn+ux9TdoT0u^aTY)FjiGT!H?*>Cx+5O!W8_oZ=&K1#+qaBfxOS=)NLFPsfM& zsQxs@12VrE!JV>?J7~d6e96UC?Py2jT8zobwFfoYg*m{xD+eIDy^$T=El@5RF$TV! z!!L}4?EAcd8n-<{Y*;5)uaaAX9~$r_)u2zZW-yBsdQxvGE>opMrx=jd?y5c%2rk=f z+hKfi^WEW7ou!a5m)IzzUHSM+Zm_*q`(l!}*B{-vwe|4P|FgS!XJhTr8vX>AEW1fF z?@}y&pM6vcUrqP|qM<A@dL7xjj;=A;R?@piowMJs~no+Iz1{)q_TeR8x z?qBMYl}1~glFo-WS$lvIU&Ucp;VHn;C_#_@5@_1(8`w(R>bBW)qo*(_bn%n+G1klX3r%d)(+20cF5BKkWT*YZLSVB~wvSAPaJV z(kcp;-#y<)>C?t$4_&U;XEeOsb@TI{E?hr7J}}L(W0+E?l)N{#^n1*V0--&%lK+3e zsc|q8Uz%ITIP@_W+`wpi7xxT6ZDqivwuk*}?}5DV;tuPUW)ehcHpTuFmLCg-a9d(u zh<}6=*twMXjtji-(yeDu+3hy#ObT$as_G-oonXHkt%V^O!|v8|*aqD@B_SxH|9IQ? zBL5;{Xm-N#vMts=DTZ#JxybwX{030g47{KC;JnHA02XQ9)td8ZJZ98I-hq{p4(83( zNlzppZihHO}|2 zzscJb-@!i^9D&pfsAXagSdUYhWH=Z>pIEgm*rPPCC>*$SKFSEy*BHZTHAZR$gc&{0 z5PUJ(M;AdNQl0wWU(na>JFos2Zq|_7U`$vBX}w(hOw#ru;{u>pbUeqtiGf}r^i$Hc z+rXhh7)@|U2ch`x@dXqs7I6Vyhh<%G)pP&iAq{#We&*a6Odop}Yk;hSrW zZU(q5S8os$jCJLWi&$422)*HS-YqVp#ye<{Ub`4c`lh?;fSdBPl%X|whH=K{47WIT z>o^1ZGbkp-e)!3PP7Q#mKQ1W7Pwh4Er*ROhyX9GgGqFdUl`>17(l0GnlO}nvovi;wL>uH3a-_I2;eIFj-(VqOX)l1F+Zdx>tEo>>D67DBhbx8HD)DGDjs zN9HFhR3n540mKmY^4!yyDD?x=fsy)yx(BZNHur*@RG>Hb{XLt({W0g$S0y0|c|`(i z>!8*k$V1n{#j=BACKC9c6>IU&{|Jj37Jmx7?IGsUvjlEj|ECM22?P$(XP{T>!YMk=|7|hhj(Y=g&xS#$tk`-5FOR2{jqsanT^UV<1=%oF0aM%Z zG=JxxrtW{4savovdiXoc)HaLwKfy%Jn=OpIsOVDo)WWd5E0dp^MFUyqn3d6WLq4R; zo%!*$9a@ViEn?Yob(WMA^uBT=fz+uuCpqyUvx$P8{yynM(K}86&deu@b}6{6Goc8r zy7+NmEh{bL%+#y1j?fi^^SLO8LZP%e6RmYe>eF%!v zqqB48uJCZD7|FfRc{o4JgFBBQ0n~?iPI2+$!(V@LSbVv3laW|IkKiJH0H4?VvpVyt z{R;0~H5g`DyXF5&bQKI*`{jcU<&pOvAdU5KPS@^kt2y!i6IXXd-I=JvWDGl!xxjQZ zAPzHgOgPI_9R-OL>Ci|n;QtaAHCFY)uIMg49`d*l^}mAL6F2egt;3|mLz+xbn-BRV z7xF^~fVIMKOSh2YTmu#(?g9#H&Kw{``Vyo+?*EE)Rpgl@H}YH#M~66#n!P|03rrkPDavRM+ToXqAtLUEn8xP z+g6!_hXlz!vb6e=T=IsbX!E*f>jywJdg%&KwShFR{~9{R1gk@L1_ksyBR! zxKkcp9W&q&%!}?Q_jN2`kM^Vp@opFI2EDJl-(eXo zPz7H*8F@{ib6C6L=p_3}CyuBH9vt@zCejV^FV18f%mDTh=b9!SmFH!+X zc8vx(>V@ILb^_OK6~3*cS1RbD(N)&-TKfvP^L+(~s1TifHs0iQ-6x8QDb@*j?CLh) z9b32b!fN9iyz%)SklP?-h^J003pDWpoxbPjpZj)RKUhp)1s&XSE|A-@Nf%Kx7D9fV zpoQvPCWDWI8yi=Ql?Rlp(}gu=d>Irl{P3mpS4%e!N5=?gE#uw$_LX9jsxbI60E^dR z@HjtW;aTEAUw|pNVQ@Bg>@C`-z|^HnEa8U#B%rXR4ca)-kNCLyX@_G=$~?Ec^P21t z%W>>RK!FtF@p)MS7deP&Zt%)A;k8f;h3#su%sGGmwVS1}{*{NB;UB080QL>^kwtl9 zC4!2gzcw+>+IwL0#P$hdsLNN0TlKtcdeB9wjkBZZ5E^m}-8d%_ElXMJ>zpZAm*7ZL z8ywzi9#qK~9^Oc5xzzVV+rCi}#G(o+#ZU9f)W71~)}Csm%22z=oc@h)6=%CK{8^wH z7?{$6&z!LydFS;F587Q(t{0_%X=OGrWm~Fmr7zUJuPoI*`qm)jp`8z5Hw;2^im@9@ zCMJVoj8GT?D0PKFRBIyZTu^UjY30*mD&iT|wo`=oQXti&ums+jzuq=_Q-#`cm|_O) zPs-(QeR(^Vqj2!r9R#uP<6^~G|5;=Ko%!JOa5CuG1-z))S;Dqv6~>eXLR7+WYesy> z>|)DsB%`>xuLe3(Kko6wx!VNlS!9>k)7WF^lGVkzQ_tJ-fXq+4(rE>PF86osVcReO zjkcu=CoFx)D9cBUj*)`le~JX}LUC$Nj+ca0nCxm42ZjJSBOyh2_IyBG;sN--9(Qt(P$No_t});zg=yQI27Y@e+sdA52l- zaeNF8uOjdEJrd**;Q;e2rHMe1M!Ah^ilF@F7Cb^jBrMDzdl4}}3lz%qgdvItsF4YK zoQgQr@4YFiZ!i;5)#kn(pL}=vlqDU`G`)i;FPc%Kb%cRyP7x04Js8k7J!CaN&qs{J zl&QL^hk+b2$Q)`zEHm@-Sg{mf@71PP_JTW$t zB~;;3X%Sz!g5x~6yV0tvDw>3-FcLE6j7xJ+jNZw|G#!0T-rfecfvC(6j*-|QjNckU z@fic_8|Hc>t<2*F;|cG59u{Q~)P=DDNQiEz1EB$X7nqg)TQH8aQQCc@;6q#Tl<|4N zJX{D-gFKT}x1pbVHpn%|xXcvQ>f$VHR{RLer&if6%v%$Rx_F6+5s+3XNr(xSf&LlN zcwcVz1IWOA$m)panu{mpR^3Ql^W8YNCzMM|pxxoR`&pRNy4eig?Ok;ftk9A-oM}6?3rHz8UR39~F$*{av9@ zGVC%w7Pj6i6JL8jF;eBGld~28A!x9ff=%4j3l!!|DinYRT~$!TJ;k}Id{92dUJjKr z`1&p!*F%6)WxaJV;PioY6zqX;8r5XpnwqljWWuJgTl31eDL+uppJ6U#VDYlLX#P=d4v8eCVD1AZH@Q2=z&f1uB5Fy|Akf<7z4 zjP~Jse1rKoafjdXE*8J3PId^l08=Yrwsn~^bZLQZ zXV6&c^1Fxk?|7hEB3ov>7L5u0^xV|fBVt; z4;%zcqZ*gzU1@A7@8}?AphWFR~V%;bS0n(sZz<l(VJ?j9bEN620&miJjpnnOYV(w8Me$+~ z`(~(-F^AUu}di>`4wRekOvAUEK`VV&=u?P}4h}VWPcbLyEoS0EJ>N?#EU!}IZt_L@`k%&v4 zbBmb@tU>6AttShM^#w~yp;Qd3@8SsCRSvBhQNjO(uRbJg(1xwWk1F5W7Tw-+Ng3?Q zXG8VjE#`fP6|NdMPpszsXu^0%CIZkZHUz27t4~#Mcby+|4@gja4E4(^t)!3GT@pYk zw)l9e>gp+N)t1uzIB>=8?j7!fl^wq1=SxSZ2SC4ivr|M%rMyaR!HWT5W0h6H+4CC1jDp}KxHiz zMPLH~60?X?6O|FrTfUxi4yV%}9esf95VEM56)x>!zMQQGvpRJ88hTtR5^d)u>!H(g zLpHn!EFr7H+ZEnI4a$&0Io~&HwNA;ZD>-wH%Q0d`_*9U3)yz3~G-8z1i=!XxFso|F zn5x_ge=T73rpFJFK+ks8*5|)r9*P9vTWWc1(WTFJ9=kMqNOQcFCzd7z_L+gEtPH@w zBxHHI2?Q;MgUQ6M)18Y3^`L5gtykPcwz`_W0*^L>(e@Xy^%SvS2@nFDCLUt;tSR6G ziv<^SygW!iw)*rPB=n`h+)qj%aN`iTq%RQ{45S&un`aqY0&->$rnq|Y_B!FD1#Z_A z6HCqhxfkR1F5YGz}>AEi5Y}@Pqqa~GIk2jiJPHNl^?*>^lJ6a7ZpHI@ko+QrVQKL69J>Itnzlf! zj5#7Xu46N9T4{#ZK9|_=)wV!e9A4lg%rzn0+LoAa9cmNbY#1-LqV|kbV-Rogm4hVq z4#gc>`*G!iwCv{gm|d(KDl(w!EW_&*;G^|xl1ns?%14v!{$e3p%41seE%Q+0p|mZZq{ys@kTdCe|dR@U4tcjo?33+dbGZ= zwaXyX6heWh=VvDarV9VerZp6)Yr%0aeyToKq)ss_7J=_}-6x0IDITw`!n(wXBFl54 zQ@cIrJDjQ^a1A9HQCs9Aifwq2PplsB!Y&I_+f}{gQ~Zq>V05A8jY}bRVSamr;{cw7 z8IInpUpDp~t$wkAb?cDof0_*wI}bws#M@{xfzCRyhRA~vYIFCwu1zRC~}LLyn7aZ|RBdo&2^;P$>qnk66WMvOmC(f*ml$;9O;agMUGzi5R>W zI2eH1mR|X(2QKxE55<|jvu1vFG^XahV4s#KWB+8<3uy3V?|SnUU+)0U9bSAp=wJEv z&8qeB?#cw@PCkqpsDr*e)W+Z^wIqSc0)L+5e@6dUf<3wrhk^q7==aM}y-E&xfIz3sA4 zKX>gXqA740DE0|;j*^!6HP^iGR`pkY8hm$W?e<#~j()rGa1;Ofe(UY+JNNEv-C67n zb~djr+FjZh6ieiODCuVGt^CKgRAa}6=jz7e{Q350j|==p9~Yt*k*p8^&a(42RNH=2 zkrz8t5Jr>gVw6|~tb^H(d;yVfoYeMl!CNgD4i#84WAA+hvb^!xKQH4F!Q~sP|8l+W zlZjrEW5-QSps_3m93X1}aqchx0qsn#Jh}{8YQ?vMysqFa=@Afrb9a`i<+=XNSGGYqt7MH(!1oAoqHVErA?*_3G8~6gNcMY;_5qx0$Wr z2Dl~vLHXL-LO2KKeb44?>H<$EaceX%1)hh^%s75>KS=UZ-e5S}S@XZ_7UBBcccX)& zP53QGldiXZq!br@VCyZHzQ zHAnDi;lRWEWsGwVR7B*PLfK-t<=zhf0v`0psA47+DEbNH;lWYgj!vHR4PE^w*H9b~ zB4OC03O*XL=BK+;(g)ahPsr?_6nF1kLx0f)ccwWy^4)y7oA4WHRl&{zE)*+i&xr0} zYCnOq@YQxZ1;iP zpZgFKHx|(zq{jhVO$*wJ0k`|so67NcBP1wniarOqm7|a12E9>uxI4rFNAx7UCH?FY zu>n!%(#*)*RWt;NCOf~`nfKb&-9sal0=C@Py99$zgbvkF1g?NlkYi9DZ_fjRj$6pg zY}qgB$)1-j)>vhj^lQQ6pv`bmiKUNyW{!T_oXI0&PxUanU24M@$3(uLIjg2tk5Mzv z^kMybYTd;|knGybVasU`H(y!F;(tWf*v%@bih_-#Wp5r-QQtkDjZ+-E3bEquE-!Hz&(7HfUri`>INTt zdiK}SO(@kyxgZ+Hv2AR;h+7G~F?7G0lo~4<nS zjm!RqLuyviu$=Q%v!0kmc_|j&!zlZdt() zDEWXp_LOsL@U=u#O$LVx6QCZcN^)=DT1=v)#fZue;!*|4xk#cQWp=;uV>&wFzJQL+ zvoI=Ze6I?Qr8;JfO}GWghPH!w@Z*_yr#%G8r>9BZVaLud{bj%a`I(Mt30nCRG>fBi z1U9^4Kr1d0ri$0-My^#DKA~fZ=}7${-V z2MonWB>tv~=Ny`S&9>E1V$Z=-SZ81$eX@?InZaE^)1Kd|>kyXu(8j`mX{xZemRLLI$Q3SZ85&SN7GjNKYZm*`# zUVZf7SD3OahIWN%@7Es2ih=T( z7|Vn$O5PDbf;YhgmVAr2iZ@QR?^=w>H;NXh!9;8V*e&?jq-8nvv$qG-EPZY~J3DI~ zDF_qP)aafKuwB>keKUdU0rs|a6I7l|A|tm4(*}Y}^Q21(6n`oE)bNALluW95d)SHp z+(nkPY$i-^;H*6O|9c7q@8t}UU@d+ZpiV9Ux=mOnMkpOt6_gU)1L$Y&fY_~TI5$Pek)7?S=qRQayVhG z67bZj^cAAbEB|`aOJ1ZDv-&T+Dh>cNVFwW>QsGw4!}6X4 zR9AdXV;7FHJy;P>O``x)JRYM&lq(tnU@e?qx&^Zd#9*-i!~Hd;tRt{V*um8J>c)J9nYIx&oJ+tETsz<->UT zSLpMmADXZ;P0^k#-ITS*7t-k3ek8VTS}Be7D4V37vW{AsJ4!)495Vi7E_;h)R88$# zlo06>0jkrBnE6);lR~bWWV4nW#l$k?@L6~1;4dsG12O&WsRtd zrk4dI%tc~$=$nSt3%V7a&@nOH{1R0WI==ka@`hvEssnQ1(nxyL@E3CvHay1Ua+Wnj z{M#m(OZvh6dLM@TxgFkP3y>epF@?s$kRqaVj#}Y(pqNM%NHKczr6`(T9C5@m#Zt0~ z=ORljKMbNi6p|3TXpWzfRV2FRMra_2a{z8Kz501g5WQ~RQ1pl*@KRUXIGgjKa7fjl zN^xV9?35nC6Q36iVDVta+Xx;-8<-pKZcz zvm;oSbKhn&ESE9C7N7Q(@5QO@o8OmL$Ap3`IRi{V|LfwYU;qzI)$ZoTK2N9H4u0JE zb%P^&Cr#>qf1Vs$WiF?A54LPTou`+4NXBfaDtK)v{(?0ZjHlJUiNFmWjW)tEq<4l} z&qbW$-`s&lA;rN|x_!!Q1%}FuOr@icw2DFpQz&*i4K<K9M+>=J_G#r{h=-$am&fO3%^#Q~BG`O9r z$2&#A;1!R?6)2QWZRAWfIS`E*CjI)hCDbYl1cS8rh4o0YHD+c^P~P?ENg&;Ypebm? zn>GE4*wx~n&bahtn_fg*G{f+ZKan6o&3(?yh-vMZ*{cl}!-I$^+L_&{y$_ zC=0n$K@b*8rkYoEX{3u%&0`j8g01~CvM6b0ie|gQ^LHD|FO>W8rztuxXE>m>2ua1x z8um60Xq2kmSKy7zk7n<_y(Nq6?=GtWVa@AS2_0f8bCD!XKV__>e@i#S)qZ(ev3_`0g8B_?X)A4zcla}pUQq?vA^q% zL#~_?Rih0KyKV@iqEdc$%P$pPlfd^mG2{l%q)l`qEf|pzqhX{*TBF5TNCVw&jD|0J zLk6YO&BGe&2&={Z1?@tA!5)so*or5LIeyR-vpn1yf?1RB*hNd0}aO_+*SzwXfzOFIM;eKCxhC9z8g_XZf zsgxi9#{5#lXY{8WOs7ZmQV|aVA9aWd&A(T5sOaB=K|NBJ251FfnV|SR|43EB#%Y6`e zO{r7HedEH9=`H%?usxIZ+V+<1@>U|tM$J695Gx?k)Keo*+1EcPt=WvbQK|^G$alQt z9nd}15k`nnt4GScMOtPKFt_1k@9-$nWBa?v54sT|&j(Dqr#YfCqFNdK*hWc_kKB3K zPP9jUb-&OpR7o{3D-=YhocCEEqLARhE)1yST^3gvcwbCROnmDMl$u11%z;#%W%qPK zY%~|r)98U%3S?(5t=>xt!I~8;ypBd|;@c68RsM79Gi1~AS>O)%y%S(IPY`5wh@6#R zwp-ZePaaH9#?M|qalQb}owhk{0m5Hy`#i&~87eO;*1e);9{W@rkj`;y>b2ep}Ir4T^?u65bDZq z@Cp7ONk}@PL!2Q_5>uQZBL0xEW0$%;14dsW*ao7QM%v5K=!nqGkhP48UK1Q-5+G^}LC*@x(0vYvzl;y<3>=rXby;Y?_T@KOCkr1P=~(uLy@P7?b~iVW&y~mGlC&v=z!$IJbBMkg$Uad{?%BQc;JLwg^fkwPk5qXgtNMei-KO_ z1l;#n^=bhJx`w?cB5mJtbXdq~@paIm{jwG0IT5m-km~@|6$x7QZZ@)1yLwc+0WZe;=mh8`iT*ycZpZAhYnxn@PgXUwMvU%v+mSQ#eL!0Exsm@$l0 z(dVu@BbS*4{H9pIdWWTTZEUafT-(JJijoerW%BcK=^w@MA!wYOW_ZGi>Rc|Q48lGr z_Ks^Zv3a;-=6=y}zVCCXz43@k#0_t|)=yGEyeUO>3G1!l!QSbC_Bkn$vx3+k9x)kV zh8Si%Dt4+8WeiiC4!Af8!3f2tLb_HYY4oBlv0}bq^+m^2ytz-MvT3vguCw?ka$Im8 zxM|v<1!n~C_^yE{0iC z{k$!@O&TNqCR22?H6hrRVgg^omtfC($Y|wSNY~V+LGtc|-?0VP2i@>F2LOC{cN5yZ zwkb+p2mDvBvJG~k4~mcNLCmO0+`W}z_KW<*zWI&dbJ{V4;Ay!JwsaTY&^CY|G7m^5 zTxlM*si3x;$S2@zPAZX>--h7cF*icEhSAOa`>UIq+TF#bG0v+!gK1*#kpt)t!BC72 zp<#pT>y%P9k8_|a_Arlptg9_9lEyXMJA$5prykpL;P9Uy8c`5rm3~o-22Ur7VhF@5 zc!#nN*GOfXTaQqe<@WBqJ9oF5Jm#*+0NyoeBHuNMguP8GcnLSM3p-OA%gqHvQ3!^T z#&aU4?8%Hi6-Aeo2E#wu0kdwV(4}%IF5_}Xq#-$KJYc(DX)Z`gUHa? zjXA`Wni(_pzClF!#ZxO?)Pb4Q2IWU$F4(=kLu2!YAcc!KH*0LG+o&6S3|$;*BrdDO zOe|%_5gLaHSa@fbJYj`4&>QaI3Xy&4&nHtMfy5I!4OpWxii)W_W-We)6@xkn0pAookYtv0IU4$TLndaX0c(nElRR&8=vofw{&=fx_Um&d1A<*kOBs^e7G~ zD&|Q`E@`bo`5{uF!q~J;FVpd^^7P>y&2*K?TMO;^Bcae&>xU_hCezdBkh|oSG}=tF zbybB#0#_K6N^F;cI!Z2^2NthAV`KEbZgQ0Lt=;w5Zcr16=F{pVn8`f0MA*;TcNvJh z>p&GwZNAVoAimm(YgIfhG~EQ3Q52-(pUxcYC;-7s(r$u!cIFL0aOfRrs z)agQImsu=_BlZQU;SF%l7Y1aUMhY4M@0#onkM|Qu!EIrb!89NS>urQbD<37p(OlOt zF_f0#^~9)=k`3LahvZ~>f=jeroef)3{tEbx++mUW3)a(O2GC?ET|S(vtVF`LR3Nt432Kt`B0ghRK=NjB8^o_!Q$@1RF8(FrKJsby? zaz1-(j$%btv8tT-tU&K6Ku$Tcq7(2lTKFAE&Y zHJA6I7OzfSarHHr5;=%jXk^3Gh++UxY2ica+UedqA?u*LG!-Mc8P5xK*am1r@AMv| zX=cD=_r)TlZs=Y>AI%N@sM`ak?TPAvRtA$>&OCRfDCM!lnQJ5%#ph2t=H_r~X5Lq~ zD@+ZWAU7Ogg%lLjQaFtvl@=YB949d53DPtQK<5Q8idk`b%|Wuf2=6vWWUQJd&cQra zN-pyFS4i*TOa+WmL|BYKjrm~o?8Ir9vvSc>%V!7+I>6?sxXDj9hr-f`VI+mKCPaaC z&Mircr3LS_X z8>*Kdz7X5C&4_ZoX{{<jR}2J-uZAmSn^s2B}aow zE(CDd`zD}>$k>+gU1NspVZ%dP{6D}SL5n;wGouKwDYtY3i&qPu#avdPrFR_}5rm-y zS6(NlPWa3~5mG&xO11fbJC@lS`bOby2q=x*ig+&{#X|9D>-mH9Ma&DNA2z+@qDUbO zxsMp^0JmVOqiEW<+l8RE@>GzLonB=s3SYv%cl+V@Tj&jv-^&cVTFFBebUA|~uiPW#q zkziJ@i#EtZ+BK@+9BwXA%j{2sEu_~XS)&kLnGW@`sVmV4)^BrV4 z^h1aYT&pVs#6&(0)z{(M_yyrSy%}aQ1lNz4cI{dB7b+-?{OAdfC7&46!B1Bl!nm;R zp*qM)dot5$SE;82ZEiW%a z6nY+03w@NJ^bbA9VWG_+Q0u+stcs;6@K}a)5?Ww8vg<-{8Gdpv1ma zbk`U5u$G~>Q0M)41_>{RyM94?1I2%ZI<@u+*UV3k`7oxlsz12XNXdjAq{_v&bHG5R zpr_|HN?QJvCWY#DV)>i|ePSqIm^LUUSAmKF0x%5|L}0_=Y}ork+{kFAOPy8F8H9Dp z2r_9EX*R8iIzBELif}*Im#J+ra{RNxEZn&4>7ltPxkvN+~ra*T@j zWlHe&0n#+C*m`5Enjhc@i6y`7Bm7r;#Q;z94H|5%+C|8-mw>%&+VW7CI(;&WVqPif1;Un1dRAZG0&hiKbYM0|4wBa?~fz zm3>7zS=)!ez;5RpwG7gbrql0Jg1eqAejZ`Ee ztaO9*r7I+|4Zbmir|${T^n`0ep7LtEZ#FZ3%uvdWi8Z7`agta>ItKw;yZFPIsD};h zwlo|xQ#%?Bznhm={6M0lMz}-UbiH*Tn>IH52o=s_UtJK%+)=h5T09^`hP(FLHFK+O z60PuROb<>EC(Nsl%RP#fVR#ZYLMee`>zGn8WV#zqKbdjGC5Q33iBO>@A}=lu=~~-D ztYv??rwnr$OU0H6+mq0qLybCXHO7JB^1MQmGzqp`Q5xltj@)?o$5U16lQet$q=+$w zHU*McgfR}EPT}-Icg9gYo);0%xT#;Wckaua3IzpHU?%`aqJ88 zE9lMt9r+cmQ^i&VhHcZ?S#`K1s{dwMp{tCfl^m_LCih|4-F$_ORsH|R5K;%*1^jc_ zuB!xoUr*lB7T{v#{VbLcqHz5IT-K)Cr-UD<=rRrK=?UQ@GCbP zYlHR%Ki%fG;B`QIBP&pVS8_`i<$aAmLKxatt0Vg8vAi&L`B1Btzp z*G>EKf4QgOnPkPZd+))1QEN$;oIz5P?!^FpBC2rYnog}Hvf zMw(g4{coojbC$4W*gTvpxCu(z5DYeil)GPLTFFcf(uP!4?8)6=qacvY$L* ziPCoPnJD;P;8p#FIwx>YZImHUMQLJ!BIP6Ya{`hIeT*-xow>Q$J^i#E0a1Yv8=Otj zCht8Iivvq}-6Op-xas{iIe9_3BlAg)uyCF#WNQw3iWy_m#C+49b%a4z@_U-dqH3}h z!N-U29{}NSW>x(%MS4-$+0}kXBln>3^n1#qP9VV6d(2C(&2rXVNdsex&ISq%wde>U z+1A+hXY6-tY`RGuO2TJ*;=EFaRhWQVl0jpY3pO2VY@ zO#)IVk3yS>#i!F5yT9uNUg+{ijqqa&{XOK=C#INB;YKhuMG&7 z@hO99VcHH&w`46%uqOyfSX`F9;L)>~Cy1Q-xg~U)`^)-`(2wLK-^VHDgu1?&$zI;a z$JQ2uQ_Zr#Aoyqm4tq~_anQCY@R*Whr!FlvWdlNxLajYSDQ{y2sraQHCe?tmaky!( zR8rZ1K}Uf{=_ts;L)@GlIAlhGUc0|N8K1C}zX1_mX4e5Mm?OagG$VswN?BrX9n7c# z0I)+?AX6ZXAB>6g(>z`;#D3NVXs4dTzDNbw*+OWhcfoyESs5g(n~cD^EJ*|3&aQZsfx%a7UU?hPnVX&AH=l+t3biF`YjNelowk_ zza^adRJ0`;Flq2b>ru9eD@5XF2qxp?5oP zTw_&fjo5_>EfeFVb|p^f<{W7%rV~3jkKr3D=w=>=M9?7JxarCztSwWa8AJ~g3RRvI zp{1hq0C#$p09UJXq!phxTU9y^Mszwv69L|4A2 z4U$0etv|=r5W6k<5&?hg`-{7aaKti1v_h_J1*nTT7QrRsl55<| zVuYr$72NUWAlF}uTsP+Q32#23XClC2+Uhbqlo6cbQSg7>nfg25nJPbBzU0&>ytwsL zHyG`#&GyFQ+{zw4(%Bv>1#p#lu4T`+hEI`0TwIV!kI@r6Js1^5D8y^9vt7mN?c=f} z_`9Gzq8EOjPC{v~S!j~_pdSx}oo-LJBSwNzJ+^zOtGZ0p`)5;h0k2CGYoR18yS1~& zd2bQ!U45E8>+6&H($i|nRMqjnzaWj;E_t%-cBL)AvIEo7tR-bk(%e8qP4ntg z?5(f@sGyn?Tjn;8uO$-r+|KuUjuq<;ESIjaVehl0q~#--!t`?JRs7C_gW4Txy@&== zr+c4uz=o78BxiBqA&3o7EHTt_{N`j?l?|$aYdwhDPH>qeBYQJunAps z=34%zn*FCt1+#hulqwoum=?+TybKX8%zX-f@hQO7@PZPKqmZo6Sg{T!L$VAa`Ge^KrSw$2O^sjlAzTOOk2wU zjo1k0BHaYx_wM=*5L(UxB+JAIe}f?5CEPgMz_s!QUz%VT8~#{;Hl76t_BiAw!hbzG z(y25OBjJL;K?;v-xaR5*D6=Cfz@0`$oC}wWjSyqvWnl1&Ryhxbm2HU6)2671z-)I& zD}xxKIHw!Hui^8E!6>xwRO5uj#2@t))SMHxj;SUv!L4e+SL90{t<~*Q`4JtW)chG3l$5IKXlqbMGqsQ`g1@08P7Jx zM~of!S>(?{bPTBOZ5h8uGtQ(szVr1LRo4}NGc^}4!))OUFs<@{XEQGR49R7zK)K+F6_68(8#)uv&fW<$ zKyywX8#{3PNa4mFAV)Bh$5{!z4bBTwFV=tgMwo3s_7&ob4qi|$PXaK(XKNqWPf&w; zo!1dC)= zyLd!UHzwLxy@yumi#*uS3>7cM3Y{|W*0LYWzfy=xaCnQxGbw)r&Oy?%R*1VN#o43~29oDC) zGJw}ydm|u-6KY}OohC=?rBViV*oU=e>;fihyDoPTZa(axgVE}$K|u16veU7hTp{+r zb0;b+z7YoOM|TF_V;u#wBB9A=%sAeYQOQkH54{Q0?wt4z;!*y&RAfu9YL1%LrMief&oRCq8mCT|3t`V*gRkl`&j)0q|ka})>KKaZ!U2%!>RrZ0t8 zuXA2zo$~ovlj8-(o!%ELJ-$6-%He;QBTlh`k1%#DAK_?EIe5L9Gg;WMbyLb1Vtmv< z3ppzZxM_WStJI`++?oQ< ze67(kH3Y6BfQuX#V{s8}=hGpT36is~#%SGU>>bVMX`ocV(Twp_W2as(P^U~B2v5fd z(mREFEyimO(I9P2S*1EQN+Vz%g=3H|ivg2>r^XTGN28P+Ee%QjxFIS$g7OU8wshSp zSOrpVp)m>;H7Fwj7}n{zOBiY{DZbCk`4vgp^hRUll%Zkz+$xcbMbu7p%sG{DW$dC) zO!O7f5l0pIz`|Bs8TM+|8si&o-`0B3DyhKy+=?P9KBRl;;Qr`bx#q8d&N?Y@P#&OJ}*WeMGC=P;qSSGzMj%WVo*AVa%7>~1) z)BW*uwv5sUH&ugZZ+i3^N)cjpKf8Y8dhcJE2#pIHp3nAixH|AM-Ou4Ke0mK1V0n7{ zd{N*1{-wPA+-nOo_+$$uuP=6Df`&^6V+4+w9cmS({mcaKAnfGnD9<;-H2S>tMlR*z z;6n`rmpMzoq)o;}7Y+Xv1`Nka@~_xV#xdY1d7s|PhZTMrcUG1Cq%n$j;$U4b?jxj> z$Kw8OMgMJzFYwYw;cu)#PChF#N5O=DHTM~SasOc z{dW0-Px|+UPe%tx?7i7*z0>o%u=MW17+271X-)*!B z-GlA1d+<*iWqe0;@xSv>WlLeQnY7GP8Ru}Qy9y?bP&J)_1s)UF-pby-r8oafxNXhg zm#JZ$%T2v~EWhSCZxZga(JY)c;LyT!&V(o#mJN`UtKj1X)M@1Z87#YGxnSA*2qJy< zb;WW2TXX82NOb3A3p{k9JK(-uxq>Io#UG8JGI)$QlvuCfK)0sfJ0)TUS7!bObEgpY z3k?w&nTVcYV#a~FF%iK7lf#ZA;huS}+)3TN2%1l)-nTdKA_cyz^JHUz=xHnas+IS{1KB=SRC3&>Uh zknzW7+3Hk?_$TRY~G=P=L?6hqM*w9F2K`ZhiP} zfHDC4#&oSCUK?nUr&6dO2WJSKAi*aBZPpp6DtG|@e;S>~lA7Zg9bgESM;FRXhU z>f>V=Uen7Nf(`wG3y^h%r5EhqA?0qCj?LGK`ZvBe$0S} z-`SJVsUHW|C@v^VkEHaX+8Ioui67ICjtk}XJLtrl_7;R&Ix_5n-4`@ zgQa1!o?C-P#tJ<>+7Vq%5Mzfnni_tZjj7!<=hOJm#)uJdo}Ce5d?_3QzN!850&z<> z5iwxhP^y!cdD~~Yz1y7%D56D1P`*RqW2~rL4k%$ImT)e-G11=)adgyxd8!O@(xSmt zLv3#_1a}aIVUdO;`Ybtn$)fo>vuFD>qx90H^V&8hITE1xLB;W^>2J58DZ)$&znDi+q4ts z0GTE`2TWhWiva3fT>wBS6EPM6dS@K%<~ zn-v#KWAa|%zzFiv0*i~K>UX&NWPr<&4IxN9{ELCEv_gPF2xF5Xo2CVIH(c0R3vV#Y zyM;IG;N4}RL;Im?-zGF^>~h;Qw(A+2H8EkQ5vL}sB*0fa=4Mq0Nx#3j+ zyFY`n6qpeB7|;Oaezp&M1#_QyG32Tm&H9hkzkUVcN;an6Y1gV(YgS-R7vqu*8&;w< zKCm?-+2Sq!O=pHI1GQm#IUaf=Ml@MZ3LFa{IZlar!3Df1z{mxD8NUw?FImkRXnF z(Q3_#JYaIha~enn>v8V$=M7AM$QgX6<(f}+>`?t4QrM7m;MWtyIScQI_M858*5S3{ zz1g<6<3z+_nhK3P5ghO6MPi&w(jdcyUC0>T8xrPgbYzaDxc)isr0S?PlKc_(6fA-~ zi#0>y9UH-&xd8!lMD7B+cQtrs}$ zjc%~dacudwotu1@BR0m{7>!=`hK$i9F34j1E^1&xaj_7~VC~_XBWwtHZ37kTWe!-l z-r{8q6EmLTqhyi@C06iRY$&jDA9Y9toDEO!KdbG4iJ-m$3N0Y8>=|z#g>My3-m!(k zbuf3%&B2iRYip)Yn%P;dg1VkqL1SM3fCsh}O4I3vAk-Uh&*nTdA%<%XhH%hUBPfK1 z_CsUUgpW275E5`L&Q7do0aHL#4V>B}CT4<#?IXG?rUH7Hdsox(=oR2{ zfCExf+J&(KySv(>u7pO@a+4>4X)UqGBkl@V??60uZE;ND6oGk4%1g_Jx*}nT2nk;g z?)x^;p5gd+nka=_rc!aJFOpa{-o$yA!hGWtNxulg3JUe@g{nQE7Y7Sv20E@}^s>uV zk3~n-fCi^x=)qU4gS1a4ZZmNY8MaN~PcKRa1wCEu0CT7-!Jlw(={%Qy2i|#LZh945 z7%{E)#x}mKiNAqs)Tv>$y#~e|;UOfluHuBK#Y+^&;x@=-E!mDC$njR9M+amHF-EM8 zm-N)#@fI{3qnu6-ags6Uli$f!>Q<)Gw*rxyCC-$@qnB>xlNsMQu4olI11pyezykQC zn{iMe6Yyw^vX=Gk3yN^-&svZYwB7zZ7x*L21z?ekpD|7(f@U80gZRCPs3;WfK?^s_ z*6c1x=v!vhr1GdTz;JX1o`P_h@pK;=Opb=RJw=paXlOQw>0-HZ#6Fr}`3uu)7nH?3 zJ~*}BtfCVAyEm(B^bUo4-mLmfRPV0g&JtZ?^=@Uh$ikLo2jDJt-Fj)f=|0MI9i@Ol z{0(zuymDH>qAgO=bR8Iaycog$p@wvV36ULoU|8rZ;`-L@$aIvbWUu@qe80eHqhs)73(iTuU<)6P5qulhlsz4tyrSH-Tbxa=JpUHOIr>3) z%0g_={l~d{+4~Ebc|Zi_jq8xbR)9gMCKtYqa@V`lb<66TOIKyAsl^x2!JVHJHF+A= zey#@GzYW`48ZT2qNu=*}x#9-&bPuz|-Pg>3jUs;NN$_CNQev&@?ossXVmc>O2A7$d z!wbwru`N2ICNP4qM%87zmc93c!p`r?hLC#&{lfJp*4YC@IeN+UjatKZa`( zpNM@ouhq_JJU~!fcA)%*{3dm#eYu76Zp)i(w(CM+k}{_0x|XdcqIHjWL3Nh1 zL@)(|Nhq61$dXp$wB@f}?OkE$FFP}_f-d~Vh7gqQ9O3JrW9)S~&iP;ac+g*_yV!ov zx9DPyU`fsNYw}p4;_&I{*xA;gy8X@(;vzk0BF)h_oiOU%dlMB_0C>)bS67SG2|(=Q zYoPB#)FX#`8yk~;3IfRgYHa@Def9;#pB{`q#)C0=Zy8J3@?`U9%nMKRb406cj?-jFCjn2f$YMu$sr?V7ibD|aFbNsXD zP;U@FwEv48>uV|S{=XR;B$y@lOC0e}Hu%RSQ|&-4e-2*{O$j$Ha;3VB^e)*Qh*&^O zLHgM=Lp*~6ypWz#b=-Rj;>3j<6J?N_=jCLKQzC??AK*G&yYT*-;S3jN8jC}2&!_l* zXih)f-~6`M+qm=SN^cw2OLYBH>Q|3@z3bOkuV3%2*nbxaOXnLv5r$68t7+;0QgPoe zZ+7!uKbgT+a>EDNI;*g%_Ml0>1Bl&UL3?2AB0hSI<}T~s0Y?0YOL^aQf0{>nvkKr~ zXhC&FXKdcdy(^?c_a(YGAG&fbyR5y`dG~iBu5TS|8^V4X%h-BhU1CM_V&GX?%i0hBreiu zvcDGc`%sW^tL_xJ6zR)PW%FHQK!rrieBonnl16J`LCM!<*z_&XR%#s(>9ADWGYKWo zi}eU)I_Tf)lr01`_CWbDA#dC9wUI8qRc(F=$24p>>1^|XOW?j;<5p2#s4+9!rp3e@ z7Kx~UGfmHLfp0FdFsye=IVzZVWwez*Ne*z-ibcVy9&1R4(d3;Lw|0|vRv|KBTaZ=Z zC%j48E=@DwIC_YyBvuqolhS<%iI@-ZiJFvbjt($}5(oVW=;V!ts)pR&4 zPbV!5p2F-R)R5hX{jk*BKy`wh3;BJ9vEtu9`|U0jtzStXN4odRR*M4Vgf`m+=ByG?1s*un^r(rzfm^ z&Obf&1d=s?1WzcRx=#K`?)8a{LyX93rVg>VQP?NJXv9^sp06l02kx z7cwMCCBB1KFDQepzQX7)rBGxJ*t6fB6fdB_l7W~m!&-DR&rfjYwa7Fs9Z`WHlW%`e z>~Bf2;r^n|4z7kT++p*MlO6>{TR3CNn5@T_dkS%sk{`h}a9D!Vg` zqT_#Alfv|BV?P98$~NrYd#(1DZCo{brOoPa$LFvxLQ7Z*Z5luAE$LHMtP1!^mPzKoPE?ge_o6VPO(jB}z4LvPlh#uf7GCRu0$S z;y58(jW6g}(N{|DL8hRsAP2iAXT=lNMXjCsP?zlHi`GpLh)u@{s|nik!3v5bT+tzt z!Od8rtrS7g8tvf>1<_aq9S@skkrv%pqk8@*|UNkZJXasltQFn~gMdl|VPut2I?Be!ATLN25I|??@ zNnX|hDx5_|r~hwn#B2s$dxU*3x;-FZ7|Ql1Pa#wKd?TR;oD^92WB=%HEwTOz-gM@e z=GcV5&vFtW%ROZECJ%=?lTM2T>&!=h2qlYGG!EZ4dtVQ#4Y8iJPaS0ea{Vn}uRQ_+ zO5Y|;A}i%&znbn3Z_JdtoiP^;g@j8v2Ll?+>56- z^`#ftfpnPYDV~&{yGdzKlF7y1?&!w{HqRPc*lPao@Uxs1tfIGR zW>+(C{*z^*?QxT?VSC{a6{qmiDl_i@M~ljb@&Ya6I;!E@bEBt#*FWd$57b?y~jHW|C3VmW^ub z32i>u9jbB^OqA1s?j=lDqP359I(Dk76U}%X=C`fM=Mbub;F@lRxn}9ui(h~=aSrT@ zMSQiAQ@BBTC{O#cKj!6i@ zsM4vS8kG|**PKHtmkduX0E5L#%y7JN1t;O&ni>zwE@-a+#dZLG(cCrpsVi+JoKw(y zuD6?%M6UOrRuhC~Jp+g1K%&{V#fV|feBk;NJ$;<@0o463zf4e>Bf^R@c``1siis98 zP2y~}pE_|<&22T9^g3c4JQl1Y(XKXT!%<8nh2A|jGr*KO0U%{4)Fxp`E#SbAgYr7(uYA_H8PBE5+P1}P@_ku zNEl;&c}VTd>N&(2zzQ#!FVpIZc!{krx$rOAl29g2xg?I{eHcjp9`Jq=tP6P5s5bhD zz)4|^=3vW0>w!X?D=T-|)L?yZel>riM1Y*IH*|{AuoUWo2Xa(RZEi z*48&RQ}=YV?V}bWh+bZYbBYmU)xnapIkIgoz0Tiau2ALlD4?}aPH4s|i1R)4F8|@5 zU{J%(@2tr9AAE4H)I(t)xMU$y)5o#;-6kn9AL9TEHDJBweK&B%VGAdzdx)3X({f8(3 zf0!@&YQ6IGqQ1?dAjCjTul_X01 z892lV{t(G9JPgpeS+&iL*&+|l-}qy7=vvhk4e_fw{{$^+Y#XJ1?Rs6oZ|Kchh^ln$H#zFJ=`Jy_-y$b zz3UNxulVd6bi=6#u&!o~E|z!MtjjKz@z$oYL$HOvWgumF2cO$#I|5jU1xCpX4f4`B&S-KhTm%j!8Tng)X=~le(-?h@5Ul-`x zDSAjt?hU_=4}~RxWQ)y36|7w%ydWAbuT277cZ(NVX#TzgoGuqH654#sj4cohdlRJaKu^8ha+sn8;n^$U*()0o9+Ijrgwe{rHSgZ$^6u1{?}+<| ze9~xugno9?@+^akmh~}+s7oxO7q$=|Wm?%01F@^_b-fq=>-Vn($^Lafg1*qrj=e+E z8*D0(AfT%Y#8*q@Z0jttoLHo5NEL!1e*y_cLfuS4HwDV_PSNYqty=Re_?9K2B={0; z*!9<#a7s5sRd&#S?p}0sjL9{GE#A)A5Fl0utu`_=NCJnosHI9jDi608iByPGCz(UwEkti8Wy1bp} zXeSHW<%CloGo#YRtBIQBw1UzP!O-LYsvPMta>9-@MwigqLWxYeNmwRPV4TuTQq$B) z*My~i+$DFQCtJ}9g_G3sqI8{;?NOy6)<7&}ulB4%qu5HjYKJ@T(cx8;6`+f7W9h~> zx0Vq6-9spS2rmHc?Mt(wWM9X_*AFCz_GWq5)!Uv>IS3@?A0`r1$r-bQH<$iGE05%lr6TVs4K#vrK`o zOnM=!bio~@(=Pb6+vNjM^Pa2)43tC(07?KuoDe{AWS6~p?-G=vXc@fGDSS2zOOl6!eYRo9NpKG5M6vstiww zxdenJuneTYhR8)WpNy=AN#@mToFuKV>O>`gF^?>hyIJ&de$q6=6xU-(m?E9*B#A31 zl0@Gz$s1^%{F*i`bGX)Vq&gGMVXX)WtKx1seTXoX#o1^ZnR56RS7ruJns z8sh+Shd*b;bLk7qc_*n>(K}EsQl)Yx379c1uVDwEFMTZw*8MK7ZC5;R=7%_#$d@0{ z!w+5P)-H9ci5mVudB#=TktQ_LpDjo;OXOD)(6XkpL|B&vim5>fCN`!Ywj-Tw`cw^p zR{3HHy|OWPgj)MPku2NU7?M!VM?`5?WCqkNk@_TzC2&mZ5%W@XCZZ&Exl}H)$nxfX z0pDhXP`DUBlD$LKaiF9Ui1-3Zd1ofy@WSwGVk<8drr0GCO<;=^O&A+lX<;;PsRyx# z41jDSQ{;0g42k$bR+#2%t^I?dP&>JDkbvi0kdnf!2yi(0_9ehh&GRF zxezF}2wd-Mw_CtKaH3c1BL@v=4;f=gfM&0VFS?>@lQl%pEdrm{jGyK;TZ%O^Ehe$I zq=l0!Pb`?ElPx6^%7)CmOp~NyPzY0rohR)8bQ;>*$c$f$w@kE=mv?9{*|gndAzroC za#yUq@j_OGqEC4r#zUNb#;Nd*mh| zqtN1*{L(jKg5|FzT*N>Hq9u>*ck5d^MVd-8Fhxn|mcuv4Fw_>y7|$H=WrjR35M_kf zxWIxrx+FAlxCy)p1uk)U#acv$$rX_18D{xHZeL+a((Yh8`T(Xa zjJKD2?(PFhBTV#Yp-h?%k|z`_AZ4j-a=C>{%_iqq%O+?f3@Jt76W7srs}KR`4)~?q!=L642fDt*o53`J;GLIYZFN=W3QsLd4Qn# zczB8`MY!d{>NOyR`5!En=@o(=uWe!r6jh9HMYGDs;)@+z?s3@LV;v^1n~8_m;CzLv zDWXh*x_h+tVD-tyDtAxW_%Gel6I^1-ouJ?O?bV3nYxm#_o|<9N3+`GXTMCmy)d&`u zjXAIP_HpCpV7Ir@@(}*ZQTOseFaCA=BcGd6pbOqrHuU!k%v1gCh{Y;H0ZT zZ+&IYcF(#4YxK1}Kt}9|jvDjBZveqnK5vgt&JOVy4@+=y0N~)npmX5%`bX_69Ml2h zMKdFA((79X1e+p*SNM$GIUFP24L&w_zcEM-`g_=mx89c$AUnX&OBDj0fTlp+?K<*q zHz4nJ1M+Uyk$1ZRdAIAxyWN1i+d`flz-}Ok-hhYVc#W17+GwO3+iC9X;;(qo}Y#YtM zu{Z@U2C;etz)axP=f235^xcW|h-G;9j%+_yfBz}o8{Yo(CpNfJ^j`h6d{usxt7!Gd znAs%2!E9Nx9 znH>mE87UR$5>)u1faa<)R!HSO7Jxx0SO;7I&DJbm*~u_V+W=UJngsCJ+idAem^TKq zV`;1d4MBcQA8;~CoE2_4h~H>wjiWz9l6990qd65AW_XvS&VRK3j0$4@0kh0!gtC$} z9}v})0=OL8svDh-c_J4)f4qNs7!QF;6u3t|BktK=v!ZC*8%S6}$$hXnB*?Z0%}Ji! z*5>B_xO_oZuW82#{mv>j5}gaJ{~4a5%o;9UL4N)Sr~jDW z;zA}>DlcS*GN4eh(K#yk!4ji_sZfp0@}D@UCp_fp<-#naUh6vvc7w2GrF95Yws3$V z2uCZ+L<}7E_Hive&LxwAx7Ci5)?5RA^$uiyIIl|D*#u%8lWsHeLaN!AavOAN?Wo1X zOrIL9O_806nw)Tu`_wz!Us>7f8PpK7$g5Z1*IGAmZthjDcbtwoj(KcR^lD#8lWqvn zOqU}>fY-XVc0P!$Wt0Y-$Ak-lcAB}OIl_#Tc$cr|ZooNhl(l`X0 zqE@3&FT~IJN9BNiuGk@%08-$!32KJ%%9ZmLrkqMFj6DNJO6jo9d*;K&r_oL+!22gu zGA%^LG>sMj-w!DwF4i>RFs07)dGIDvI`Id1=^f+WoYd)3=SFMCF0O+3<(XngFNhr8 zLk4mAvNiKL?hS6e9@-^N8u$1ZRro?^-E84ct#tDw#G3**`P93$Gl#@QJO!#I#4uT0+ zC^c4;#we&olO1!mAHcU$U~OdCiFr=c1Zd>42l7K`N5@%gr)I$TfxOMG2nMW9q6i;W_wPQ5wN?acN1j)-Km6%f@)qP$4Z@H2x4K z-4U`hPe&6+XdtbR{;KY^13h$=+Xlv0|mRWX?JS)+DK zK0bN%VkA&JxKS!nYr+Q?JY*z)#-D-CH~Ef=3VQ{>`h*{u);jFkHG;}t4`CMYCKQl zho4;~f)h9a$k?T^St)?`?wt#hn*GWW8&ip80*r5=7Tt6;BLQ|RYPdlPtQ4Rp5NUgs zjP;Dyd?uWkYqQ%MouHIo6yJm+z?)V-oPKcrq_VJX0BJpN21D1lIxTTIz2;{*Y?w~J zf2uQLI$xpyUnSWYh9(yNLi&Rvf|?kP-*A3{6q|{6>+>2{IQX0MT2|Tk`gu*Oy!>6+ zGzZDCQ^_s7fbxeat@7?)v|O6fGWP$X-SU)nH9^q1pjm?xl2j9&S?Us%%D1{e({vLJ z8hLR|?ax&~8|q$;bM+?VCeN;B)jhz~m3Bpd11S&$Y!{a9#o%Pj?)lJqvj9_=nI=119iZG1qU}w)Z z)`S}W2+r_a+H%i@7JE1}R&;H3YK-qx%WtrU0(LAU>Dz6*(dPlybR^_zmD9qu9-O^= z4d;#4?)QicV$b`4rIZi`+dkrU--D-5w!L@-ZDLSCT%#*VrY?PMSOfkM)U^Gzrgt;a zgdqbQC2ru|zC_)w6P8zQFCyQGL%;ji_~0sYs}?ZHtKZHpDo(17RP8w}z~<^Y43=V! z+Ef(sqG~$PgsxSL1Q3qVoPG!Xczrto`l)sUORS@TZ_1$B7VlP?=XLh_69?lX6c!y` z@v#D9gxa>o@PqjS>MOO^(ARCzi}$KNX(#j3;$7kLJsJ*Q+3I083QNUA7X&g?rva-s zv(ma_EOBq9g+18rX!n4A5SeM_fl=|wjP1qkcl(Frj=^v+zdCq{+olgJ!2tn&UqN5P z>I$tqAAhlReSZ1Hm(K@Ve_wg=B_GV$ldI1MT&cK-LRC-_3RHJf3ysPb<%-#Md1cK| z5*-B58*kZFR6@G1R;-%+S}il~D+!{@Y-XkN6TvuR8qH+n+6`NG5fK-$ES`=>i#z?n zBG?=n8{$zHZr!}MxYzq>k&K$D$OygNZZY@4`k5eWLr*KvWaNyF$kNm&d8GmKO$bP=(`rUQEJ^(9OG9SS4u!$dz+uHSm#o_Oo>wT5R*`dlvqd}lEQ?@k>v zCGyXnV$;Va4EO$x=hMeyLS^G3s|Ya(OaSSGBV6o=axVNtpRHlLV*oMmQwxHsukCr$ zLeJKot@%RP z#o7bh^oDkQT&tsm8_yU3#-J&>ySu$(*bEu6&7sGU{dN-wBGCH@5rh0Y7!L>d%M=7A zO;lrBhj*r6qMF+3lmBX()ZOc8@_+HgCnS70-BLxBHxA&+-SiTlK(srLv@_b6%mW%D za}_O9dXq~I9~(=FRiS7v8eeODxAq7;*ZHsekJcXE-(2nd6;{IP{U?(CrQq^j=AsTy zsQC8raNK{>K^h1o5HfurRz58s%^A&E$x1L?8KM1Q3@N)!(S;n0VGFs9%*91Pu0b#nd&1D4k%S?wRn8FOVVI}3z6!p1PNIAPFrM=wv0AYe^)y+rjnn7`V* zrIg*C#buM*^mq81bz+7S61J>&h*G69YW{qzeJT+sVT$#aHZ+s`&Su&w;G+|cmoHqwNrV7w9Gq31ypR#$7=SFdRe zKFSjOH0i1Dl;trASoe7HP^m2C3fwT zVNp9{$%z@U)kSkTmlIdl*C9MNA@O3S|9(z{<%1iA2FNLwJ&fw2U-)iw?Vr2`G-0`9 zw16jN>Br>bf@6E5(Zwr-Mi(v6CT@y?Ge8s3k{Br>*AVn^?PLnll#CReTn;7DL8%VL zN2pbdok$WKTmmKI|zqjBK-o1*d5zZ8@P=~ zc+Y&72q_>1CB=^pv?c!VLolwO$6*}SWYrzR4PB`sIZrI6gjNC|(HnG=K%)q&jtAgV zNIQ4#F0}leo~RTAN<}HS3_q6Z!?ObB6lt0bbjD8#s%S~wQ(dW>x^%Zi0;vSd2uB6P zIZwpr4EYZS3@zxy!DY6yL5()rIsGc&HG0+KZSd--LUYf!?`kSflNZB4{UKb@hqDU7 zGQ>tlT788ImpDch({*9(j0Bb= zAqPLdFX?eLadR1go*+!sj?DP>-UI#i(L(FV504&E0CW>6fmL`9A4Jyhb;u6toDo7o zX1s>C!i0HbI%isCu1mVSA$kD+pm!kt7@4#1FdpEv8-cyx55VZZ9Pq4~@!V8m^qFY> zv^4aGBD?6HS7`6y5bBR?H|7a5 zAmyzwkHK^G=W9wh?H<0COyr)J5uD6Vn>`Wf+&qn*(zGs5Ozd%jSV)P1215_R?!4tX zq=_qPq21Spukd@JDzJwDHOK2n3v5TX6&42x>Ly$Ef#%UB!uaU{lejE|i?|Kaoggv> z77pQNisFt~$A;CZEiD5)4t9LU;K~{LYF1I^euBbH>|-go8u0H=eH#lqos{!DMgrVqwUI+|_MBhScM_va``zvp5lbGzOz^m9a5{T}-Cy^BD;=&BH`mKr?=8jC_tDs0%b2 z8#~+&`5Kf4O`8C+!$r7%>mw^=@TVDka_JPqQTUsh>qsoQa2T$aUUoD zU=xAVNL5H62YJjhf4c=SL3AT9p=h@oBbL1=6ACi>5auv8l0`=#m}d{xSB;+9&;Pqk z62g^v{$Xy2Ks(Ox5KY~mu!YBHzwU55#Et`ws&jd;gNk|p_!7er$HJ*;w$Kfd!pu?D z4bi;O0qmBgoTQgs9Gu5KD|$+DQf}S`uBLzSzvCrdF8K=lUZ>tqDp}66h2G#xq#A^qVq0`?z#Xbu* zEHnhSO~9bGew-|8UKD6mey{d~ZC^#hV$caZVQ};_@wjrxE7XRK20g-UN&Nq^IIAr# zWVOz&dbeiw{wg>--bJGS8$+87Q^#8kw4ghXyb=E1>Cw>{^7;q89vv~7#oTcCYT=e{ z(+q9>{^%`^l%0d#N4=NbT^ylvK}e~H_y8&@00`Wy22ojO|KR&5H)tA zfCdR+#iPp>2%zzUh8sugvrT;%ja6UQI3@k2n>xuCb~CAyRmxt+N!@@N;M!{B z0ohtepT;?F(SQWHak_(G3d-$ZcMj!Jp8#Wtf7daEE{u|R;4h)bhRju^J^OQ;FRz;0U;aNNUjgPt`9qOf>r(d|>+~HNA1LlL&Uz%+>KDv@RcF({?Yd#kY-*|wH zFr2y8b|y{|S=QNf>qls`UhHEmcXsbBqm8?5Tvc=T=2P zV{^+xW(#2rmO0caB|_p0_>j^hpihV2J@v4+SqQ1W-|y`y=!HRgBZxp|CBnLA42}4* z1jPD@Fq)ASlgEq~U_A|=fg}FY<3PJDUsJzM%W}*p5&%T&yY3;<7Qi~DOL1{zAc`A} zNT0}c9TKLAdjCGn6gL4GDF{`L7EOc&9jpLUNI>2@&`oVl3jWhX*G8A!n)sSNfM)zLIPzZDhoQ-;ll8@6^$^MqmRMs3BW z%}tkJ&-!ned})yB>80%1AN~rH_Ji$NAHB&qng zvRs68o85GnF@JVZ-f&4Q!7aZQ#Uc-?p4R)EHOGyaufSvT|gc{KONm%m*9H z3~c+kmFoGk>3_Bm%ht=9; zW1YP8_viopmU&IyaG}-yc@B@RU(-Vue0+Kpj-x_E(wCHf8pcQ~h5w)9bvB*jGVkpkt=jt+Ewa!e<)Jc zuct3jM~@p2d;dUGl(rAu%&Nb_V;0Z~5`6TFG{2J9AYMWH2vJNu&y9YxxFYv3(LIB z3xOZp<^?MRB@%n{mRUm|5jgiqU%(^Fv>GjIz>-;wiS*yfo?r419uNcrn3FX~YZZl0EpiCjA=o|} zOK-O1x+4_#L{J+RH@4F1xMN~7cNcl{=9oDOho^|2Fy$H9-~;;&m!6o5&b#Fpj^|up zIj-LSk<>1#%>Y|munsgpzaT_YwRo`@8uLH6|8USfWVkX2l?@sCo9Y$ zH(cHwW_rU8atK`(ps0}O^=qaU?Sur_)6uqwvSv_mH~3fZp=rBTk4{cNwfg4xkVk{u zg@Jp9@v#RL=jtt%Xtde-YZTGMu_5Fqb+T9hmGkJz>*IMx^?1=uZC)Tl+~Q0R2^?0G z5RANpKC;wsSO}$&ud{~oH>k_J%L>o?w_j}iz2V^(D35G(gTH;6xCs*W{`%_oosDOY z);2p2S0AlC?mW2vZ1V@i;op_7o;>ZWK7NK10YU@7LEst)?W458?httlz@0$|j79g} z)EE?TQX5rC<*c?;iHG9sLwt4zU7>eMI{WlqE5H5n%P?%N_}fYt2w)_(1Rw$lmwx+v zU*Owsv9v2KJI5rA2JTtM45kr~urJc~@n~BSHt+MEs%wcL!lRj=|1+0Ny}Kk*#YNS+ z5^Z$GJi-__Q}%T92lJO-<752azb5%s0!34{T9|rAb>!se5E9jUmdX5Rpyla7548v0Fl(>9?VY`vhK zgfW6#?w6gnt`&lSXqajS5J!)RLfHc}_qa`6lRt5B7Y;^nd#fIs1`++z*v0#A$_XWv zZMh=)QtZt+mJIUgXMH!hb*na%TBg);HWg5<5^=g z!bbXXV&kHswUV?s-%`qI0(5#Qtk;aQe?zDOin9_K3e49at8VK-l0jylkBnptOI2TT zfr_|5Xxd+Gfj*+I>=gFz_m;IV3^Sg$Js3-DyMy|z)X5c%`q8!sZP1Eo=>CX{WDwN* zv6+E(Ny2LImjzK~*--w4>@6TFk&^cZ*S&~D9OGSk@B^JS9<@h_$KGIg`jYATx~T*u z`f+v@=NXc|_7NLW;3^3VZ&RiH*&>qxT7c_JeI*9VasINAiAYEzWf{=`A&6hyzSikFiGrkJ|&mza|fP@vuj zoLXexDc1=LnX;K=iyZM^1XjIu62?czpMWO%5c3x9x@i&M2H-IwD<{yNWZ79Z&Tm`B5x z-~QC^y}nB`6-N?u!sn}7Bp%S$Q=JDai``o07>jlIT|6-T5Uk<8*PXlE&04s5tMw=Q z8HA#aW;J8)1^9^|9s3Fbly3$}F+PT;TYb^Ke&gn?+h2YC&C>D$N$INYiuGc{jPW3k z0flA21v)A|J~`druMoe6e}jQ1$h!g=Xqt$r(zZ4SxxMn2tU7(eiotUpRGLDwHfl+> zbS)TEF-sPP>Yz8mabRT6Agwa7E+)}U1Zl>H z*a#fD@Ch1>bL+W0JA$Y!ZyCzAnijl>%#AV@eGGK z5&yxlf*B?~&TvCk3S-8O`S?Xitc&F7E#e_$2_g|;ym&IYaYKL2-&odNNm+)wx)Y>w zSF)Gr%Q6=N3Q4Ru*o{ITGmlXxecm0!l!Y_%cz1^3GPpcYPlrg+0A~sq z2{VreGnyzTi0S9^8=f>TAs4NWPe(}lP=U#seo5gRa2SLex&P4+M;>>OO>ilS<&Muk zPy0Y{r}J=az0<)KRD03UxM%EyjUV-aT60{jwSmsL zq(y^>B4rYzEEj=a=kGznJ+?EnNUy|gFV6?h2Q$(FI}dv)x}6Oo16iSf3sE!&T0}*VRq!BTXfHOCqefzFm^4i8%QIjq z1fJe%T!Uz31+h@ti@fI#igDC?JwkRoRpYw-*m+oJ|NH*qXOC7lphBp?_~*0McQEECkTi^a5-(?4uaDE4eYT4?8>grjGaj!%-4);A zel4`I{IY2IS?h;mnGq1tN8p*kD+akvccCTIS*6N2=`GOw`5Ee9eZKhl5zZhU;K&Dl zgtR^3l6>Bd5hh^CJs@o@G`~&u5l>`XJXamun4bq@U@!UZ?)aw|OIyp=aN-8(7gppi z-uxY#ApaN-2aDg%Uelooil}dq3xCqVM$bv_?&3A2kxjIpTlnJYw^KfeBm$Ib)F}&KBnuzWny;;y#jw7w7o*yV2hMyU}>e|8BnPo(zw!Rw0TnJ4E8$Vt_yK^ZelE zi)+y|K#t#i(BFEz9!~u1U3M~Re3t^LoCart)Iz)75(@?yghx^R&}ljN%bkUB%NR2~ ze#_XWUqRQvJg}6(UMvZ<&Rf3l`Ea!N41@q7U78?E+m6x`Ypa5*8qD9fL$H zymzvjJKJQfkFaoIqrzO`(PdV8f+4L?4cM@7SHt+U~28{3;qCAVE@JJ<_<8_C7S zulO0lL11Fv10RgQ>%_;x*%4~XF)IM)%U<%g1zsctWOP|{XeG^VdwW}-cY)7?UdK8d z>pgf4R#+ZQ?YzByhAeveY!hxWYJoYjw&v$yckaE=`<2$S-iX|XiSnrl7Ib=QvSd5W z9)%4l9Qm-UsPXb%q=4tIb`c^S_r zL@L6{gd!K4e?5d-P#%HnXERTV#X`!ujfYY&ws!X@9}f`7c`(yAPZ-F2xS5f z8i{K|6^cm5rx?U<+(YJiUVA96IhkTtosU*l*r$O5{Z<9U^s!r~p%7npM@*-mYt5_& z2hfC{-~rdIOfN?6F^<#*PON4IwnTUUj|vh62gVCC@-!75`9(8FqMlAUla64bOa(s4 z0Ul(8&zG1v5wo$f%rV>aDoL{fuPvgsr#j$(p)yrD^R-O98>KmTm&PMv*t}?|>zDaD@&mS4;FzO$w}X zG8=fX#LR|t$`clBt6i8VRNFX2KBT$c-$#NZ@oU z$8ZWBQT)Lx=&3z4P*^zgR2O&e@b7z}kzzxY4;2E4#<_cl@BRYROnWijEw=NzpnpUR zFV!{LHT8N>;~ni9RAy>)j@o>AINX5_n0Pr0VVK?F@fnIvopdcuxCq0iyN8URMR%s>6TQ%er()ziKKp$}JZE5SrZ^9^r1Cj$0UZMv#s9Fmwhwxl-?Xkwc+>jUUcaAq90VlSaeVb-Pv8 z&xTV9;{-ns@XMya>#W^BHK_}{rAZcDChgVu)^oVxCdpR&v&AnzqhrbhE&K(~7z+bz z+f9>r&*%8Bu{Xw@Ic*sofnZ>*f(C>+h?yo>u@=4z3$`m=jQjV+Z{>qM=K`J&gm#QvDtsv)6`htBAq^y-f6Qd2*Q;Ob|_A zw$co!sQg|x?oi@t0$(AHtEj@$Ml9vlO$bU~CETPZHK|b}*UO_Nbr`HOfstqdWW+3cz7&$Q5EAoQ zo)n)#Or9VSAg6_M-8T?bK5otYXs+K%YlbL~5t2g~8=oa4(cQJyG6f(}E@;@%6C^0N{rO1*dA{f2*Hp}fwsBM)52})Dl`XyI@P=ZCcki5z4zo?ky3CbMz@dna z+j1dhj)43r3*P>){wQ}3L(*c8ckkH0=k@288W(-}2gd&mAw-975# z(h|8Fh+wj~AhH)<02N_eyaH6uERr{1xD(=h9*2b(IWvlLPRt~FLa z;Iw%eqi*S}KrLdYM33Bd%kiiDiqR;>aLwkNZ!t`pe$nn``t7WHq)Oy5l3rZO^qmYD zhlx9h6d$hDx^&Pu`brAwrwsUu1IOrBOZFGY8y9U72YlGz zosbkdG|i?2^rm{Vn&dy(x|}$xYk;I)_H~t zaB#oClmE08Ko-B&r4Hd%oBL-UI5uOg{M_6S({#+C#_$huufatlkA}k!oi#tzUMUE=bFk+)bw@&o7UBUW%9UCN>tAP=5Ce!Ti*bHh?UtAAUH?*)`#ck_H8j9d@v zpkYNeR`0Jr_}fKT;#U1|bm{Rc=-}}7eZ%ngf7txn)Afyu#y>^`eR6a@t#JYH2w??d zZdJAW#Rf)!taHkvd9-ujsDNQzGxd2}iS2vkd+n<%hZMe1w}f7sKjxBK?@DTb$SI#i zSYDzN(HE0j^(HP#S?{o!70WI;%;g0_G5alCmBCPUn+KOG&wIxR3yoh*z94q@CLeRl zw&Ce;6l6d7@^$y{RR?JeV6utP2YbguoV+3bi3hHfN5g+*q=+}4JbmIKDSH{9pZg5d z$_};LTE?uSsC_QEjXcb(EiS}IKyc77yq*F2V9F|TlW;bqKgh&>G_f0WGVR+fZ_R~Q z{J7&FVL0y+@!u*VFalN`Bm05UD;@9vG#_+}cj3{MDe#{ILz`}Y<+J9&&3~i8(UIXA zid@U?2;?zGGf9Xq>0~N$)*D534_O7s4qHTfIrt!J=dHGBf6x-!UC|z)0z!I@-Mml# zZoPhr^gOtGtYzBpxrG+t$$3B6T0p)SeQ9NdCZJOmmwkQ;Sy(~0BLTJ$cr5}s@LNo%}Cl7(Er zc0Etv+TsAYT24?&vfo4lh0E+a!DhI1RH?JJQuay$B@G8LZfA@!)-@7gxwPgxYGNF% zbhdFa8Hstmf$bYlP#61*@v0tuv6t;;`5F@wXgFw}S4YZ`nY77Eg(8)nz%We{uBBVw z@kWNdZ$eW$+Ey1D;+PzAmErKlmK@6$Si|TeuI$QAt_H=p_)f{A3O7|5(yFXr5l)eB zaMm(Y9R4-sn}BKB4pxpu>oqb-hz6=pr7LK{xF2Uzw>>fwADOGTF-`r@S??7I8#fk+ zMusnnnZy*L!kE6inOZh%0%8CCJi^oFO5uA^2` ze~7ykJW?@**v?5LF}mY~asM8T9+rq;eu=C8M*NoeDadHnyOAnt`_!eeiFy(1^zIBj zQ+xB*ge!Fxgdfn;h-dncsT-Xmq5Xq*_c=^EeT4G zM=DF~b$rfTHI;%EB_LlG22kLJb`B=-Gs|nnXz!H~{C`K<^KSQ;Hpv4hmK|Pl4aYDN zFcq+xf|?=o=8>9%e=E%!)1<+mEGnNzh+N?^;0yKPsS2O9?(glvOyV9D12Xwj-S63U zzq~cV;5s10{03zUVhof5!ne^RcM_ea)Ip2^KD%*I=kc8Z#bP!X1ojROKDBY*=?NkP zf`lqIjoS>GJb?7kyVe^9E}8mWhdTzX0ekayh8FA8IAVPI8M0!JhA4(}F33E0Bjbx( zf2`~?xZE59zqL7xY{-~mz>=n6Anmno)h05DO*?&M_pLuDC?|;Ryqw|C^s{FDCRqxB z)MhN9jRO@_Z?Wz4h`H)mg2VvII)VYK>ke%x!@6nMak|46kqPymxT+9Vx~#wIm)!mN z=-V=+C@HInU77TTn=-%t7R_g^q`?o554t-&o^V0QP@)#v_W^v#QGW-Ait2&@h$Z`G z{?#XKI#>Qd8+C@pIJ=~Ivgsb`(lgMCK(SrQ%ZFse+M`2UpL^KREx2rfidX#oM(PLA zi#`6L2Onw6VU~;D!L=5kIt%jCWa2}*a-KsZ>N7Rm=5!g7sQH@V>4hT2@45(5IfQj4&kwyxp}2%Fn`a&ivo7?^;ot|(LT-Qir?zRgVQ!hBp-Yy{=@T% zTMd(dPRIN`7Z&UkDglsWJ5N~IE(BD@I7uBsXU*a4zn&4BiYqYaNxpz@ujA5|M zhGOPAo5`|HUC-Y;=#EJx!EnuiwU8L|_b|z_xe+}sY)AF9FTW&xD_Are*Ud05@rH>G zgOcfpGlt~P3ko!=>2n^7!Nibvfh>>7R$)-&b{sL}#yGOE{T^RT$-w~oXmtE*cyqHl z>sL2KDr6~*|8L|8vs5m_77l&3Br|J6)yoVFYe?u#WS=Zj8|z~Bu#svu>68%~Sj2|; zy>Q8=AI>H=(O=Fff$u7>7{W6bkXxEsl3(g=e<{a=-G?9trI)I{6S z@mpaa$0H``;Z!}YYr~Ux_!-JfAW%(Tk(E|}QCwt5AXNzi$M8z~yLeF>Jn8Uteyc-} zYY(#noI8vDFfJ@sRuYt*$DSL;+VwWaNK?dFB5pwHhv=nYSXjP{D_T3m2Gm2kB#vl< zFCq^CktLfYLx58NFkb@U&G#MGKCF$agQ(Rp<)tHL)<=m=zcQp$gbg_1_6ti#vq-HI zMCgu&Mb8-0XSWt_WwIm|&pCyQCHW}sG;0{NiQh)Yn(+s|te*I6IF)MV_xt5W+Wmnz z&d0RMtj&KFUpqU|6V7&i^$}7a@Bi2RwMX~=`e?QF-P-D-hxz30<^h)2=W3f0JJV+V!7Ol`?sB;xZ);xAfssbrvhp*2Zf0lG%Cn-OnZk!I6__g+Wqbl;&AhZWy| z09+^!;|n%U=2L|M(o+|S@r7Al>21j$(WH=yc%-Hu$=7dGS>ch2b@F|&&;i*;FP{%SLg0P_GNx{u)=t$?XG)_g*%#yk(q z0NdHW$g$4O`BcAJP)v9crp6}qS1ju4n?6o7NHe)f!rEad#f(oNe?{-E^jNnWPmyxX zvQR7;l|{$20N*^26+u353nHaF3<@Sulma2H7^BivDg+WxntnQGE^JVk5~f%~83#>g zp-=Xjs*TaS!B4O*tA0WwDFa2k)-au)i1-!mg6G~;#GvZ5tPB#{{%JJP61dS{J1v8) zPdXJ$k2|^;hXXpZUYT?5#BC5eZBBZP_-=zC63g)sS6gA=c~V13CRT$0=?6dcdG;Fe z6%7~>og^11Efmcf;5aN9ASLZT;Ir&=CbwhKxG5$zjqc3cV*iR#hq)!1tx?`o)9f4~ zoMxK^WE>(Hh6##isvn3;8%mSs9FSnDq2Az$6hv#L@oSu7al5vGRRm?(Nnu6evj&zi zTsX@h(2-MYJQ~%=KbHtmk%vM_OoXYBhCm#tfXviJU=i_YY{BXa_Ij1~h*h47^wQRB zFjlyE4^%6`SDn4^vg|P`683ldNcq7pCjEJ#Gm!TaO3}dy^zbL3U`#phpm>#Rsty+; z0ZPUl&O?&6Ej!5sMs`J~d9RJ1bC?(>cTtah$4uLAiv>(T{M_u}dWd{tdKD2Uq{9}i zhvAdv6b=~PV@uFctda-KY>Cs-)G$^-Y-;4hVOtH;J$+G_g|s7jiSa94*7pi>&kZ3- z;6r-`4U##91`81_USlxD2y1VlC3#jvCzC*HqnS473*eKbQ+gugdAR3^M=`Zj=S0?0XrHORXb8oRsDq{(=mAAI+MIQhh^_m> z7m3kuoT0=WW}%GQKs8DuQBZs1(J9_90E($o3>w&e24ObxPvDhpZ}2A zCR^`ZCXUr^V&bSXP{ZH3{fVW8Si03t&6Ay1^VTfl!&<)KdyAHtd)OH5Ifv=D%!0(~ za$oO-Xx~b!O!ykK2xGU8<0;6bxRKaOpTe9(=q0*Y)77%D+!2il$m~nqMTi;KKA$d1 zY|8vN^RU(GA{VQhi=$VQaz){*8##Oxm@+Y9gHAv{9RkgMQhwZ@n17ykgUHa!sdgU- z|9ny5iahq8FH`9YQ)KELlK4YB61leN{V?qP7 zB(RAa66|{fN?B2_LeZcJT)bo4mqtqc#Hh%YuSA%b&F1M`_{n$l@KX^|Vv`(AQg$3h z+UYT_le#tODpY^Kvb)LZks=_aIuBZETqE~7(&)IrN{@N+U}CRG#xb^OvY3xf?2UQQ zFMwM1p=UIKu2iYQLRcufFvP*O{e7h7^~{=0IU+dhw7*YYi3NsnRR!PdD<{Js?}iSu zjq8Zu37Lj=M90MAgqx&1QQZgISPyV`2|0Vh6Fh*4?_mGq8LD5{+#(3!)^5cpBz6kO zM45`54+GsF_lzp%1@ zyh@ENGKP^b_PnH3HyS}P= zcxXZJ1_tnsjhun4XE;5ygQ~U-W)zQGlwP&)HYq|m6LhqWa>djdM15d%&v150gxg%+ z3Nz}^aE48sea7c~G@dHSsDL&D4XpzOg~sQ8eqB*uDBoHz0ev^UMYe-U#XM_2q{v`ipZI zBvqks%1nY*TuxEE1BbJyd5zO!+;~;07oNDiVR0T@27u#xz@4574f^C{n7#^D%`Kd3 z;;T^JCRIJ&rPXrveUX&rT1#NeHhjgyiZ=UdZy_$e{4&qc^*-iHB2>;<*e_Dz1cXqN zk}ADbmkvwXFk-b$pc}`0Nmf(Gy09Y*b`dBag~X6*!BLf7y?hCH|T z5l(PQ9-XH|ys~%iNksxHIYz7)*e;(S24?4JA>)yiMAsDZm z3CjLcSx}fcAb6lwHoBluRpj&OU1;C}DYE3zy|Rb*DgQ3TPc1PB*aZ0~96Zhjtyr z%!Xd^JoypsM?$bl$$fWc{$qGBXgwVEW@6w;_%wXG>;Sco8}T{0X5drafPgGRZsXy! zmz{AEWHDk5!&vV5le1&ism66{0QC^3dk*hD_TTjB-Em(FaM<5Z8I2QwFX9ONA}**} z^cxNqP$OZ{_QyL1Cr5`Y56ox_HX9e!>v*x~c9C=^K*o!LL?wf5+S7B~>WqK{1N4uh z-6p<+KVXdIbb++cyc#Z{FwOxpmk@{lEtrsa0Tw4fp{vuhn==OCl}P~;@mx$d^HuH( zAzVZD9sQG10yfcHni!m`izl$4gE1p`GK;<5x@-JuS{y&KI>~qM+T4 z1W`~_``hc{a0OQF?w$Cl(pNl;o5E7Qb7)c6qsgI|GVUAW<&ppFBM$AHcON+M_`3*6E8T5Wpw00x68TuLDE> zL0|u6h-N_6+79~E8MqD^b`H1q;tU?H>VP!|M@q#mxiM0i1lD#pVg4y{aIH>;gd`BA z^P!l~-kIm-B#26B9>j04`out8UQhv{(ayx3XsKQBHf{;vB52jv#V?gWTz&qT5J9+4 z>Z8k`qVRl~SD3_ALfBt)k(mH%?H=nmW5bREzq92tXOn(Ux(P(qXIQNeRd(smXjR#edI3E0owIdJR zKuO43I0A?8x*P{4y}+gi6#!CKQVW1#P6j6#yY`8OFIEC>1f6BJ`d}R}*%kOc!H&AI z{MnRX5;xCcU40YKZa5O3QFcq(Q9?BK{l8tkNG^obYZR=1=!Hw_g;@W8zgoCFOG$Mp zLJWyy_P`V+5wpXMG$>gHE4APn9Qz)eTvM1eN>|;>?7*8RLVuM4JbKJ83;B(geBL0x z<1?3J6*19ZAQFR{5mmIVgIoxe3+0@WE~*YOVy5kM5BrmxrWO^Vp3v8Y@ zf!Zu+;GE1iO{AuW@`>fm?1?%S1ZE;o~E$ zqoWQ-c1}8#cX1$D`^dw?w2f^@0_-D5Fg>kcw}JvmX{+uFD$W-@Koxf0&FfMS)PCcg zAiT5{C2!CbX9i$(KPr$#`^tLImZG81%~7i7;wj__b#~>c6eQ3-3;T)c-=}*H_?gI! zO!XxSasn)snG%2^V1HAX5!|Wt5xCQn-(X$@V5_t_SY5M%+{$={I(1k!+G_iY5&}Ky zobK+UXeW#D`k%Yl)X<|edUPt9cZlp`V06?y%-`mT*qi>pxQSqMxTu!`k|`kYGBO*^ z=8S!yA9?edxq(Npe^Biq@2e#a*z2LNip2o9MTg>$YH3-hY1Va8GeYZt(44p!m#uv3 z@H9`_2vYdw`ADDvgod>>#zLpT$LSf!mvj)UXG_J8?6eAATJ}v?a@dN2Wk=$#^(>+_ z6nTuVLNQxyl05BaZKr8@(7EmWM9FLRQ8MKf6n4y5lW4BsLL7!`gH_L8{A4U8*z76A zSTGjqP4sb^OB@CbLAwfg^pQPjLVBgmhSVMEwHMIp)NW$9dO;@T~sIY zDrN$S!J>A8gW1hob5ty~&}8|Y8Mi21RW=ue2zh15A8c;14ZgPPo6FhR;%a>-ycsw} zBW@3;uvP>`ig0H3V|b4vU5Bk7$X8?50A`NB4lmP6m(k%Yc)VLU>MdTC=b<_zxIYtl z4n@4^GJcWhCIU`8?*6dEY9BW z^?;=T89bw6%rnOKpk$oWnIH5{STHksS=G~X`bdEd*qVq=VP8bwSGv|<7686;(myE< z`TWR03nEaw`@;iX?M;H#dV=#pEA7?+LNHi2yhBavGo)Vb;+oq^=N>`6vyXfSJBAdn zH+6nr@#gpFxN|z{^G=n1ay+MZi(6FIF4grI<|OWq3_#aZs~kDUoFVSFWh|K_x4QHH>b!XV`penHzFD_W@Nwha zJf5^=ixluvBe_nhN59rAH{SSN5wN&m2caO_hRJa;ySSM4BCZZZB#b9sfjw;2qP7Bl zDCQ*(_2BFn$tpAtlmvu)6<&NSS!;BJOO4bCleY86wcr{qPX!jabbDfu%q5xMym}lU&Kz=2_}-7$mbDzvEW*WU1MlQb-Sr zv%Kng%f=#;yujjun9Q6|#IbWUeu=MKv+8gFs;}ev5L}ZH(R*ZNstYFBSBLw+b$mOU z#{M~-#vzfLvj1?)V|IMN13$6{da@1j+;Cv!==h}5-w&Iij|A8q6oK<#IxH2eV`Y9- z^CN81$uVlgtaJx%y~_}ZBUND>?e&Y3+O{-%Jr)Ex)@C18&{JUb4pnWK*r9bSsp$n- z`x?>*Q7doAO0*~|P_%SnvWqTfcZS#(xbRPHzxtEt}?YvZ7cTPTc+S5rTa-5*|jip#^$ z1r|7>)+TD3FcqI=Y~iyTYA-T;pPY5q-k`sbx{Zs=W&-a9C*vWaqvL(|7$ETI;^8-N z3Dt;s)i5=Whsc)2w9tYnLSFLGT2+Oi=@g4^%({j#;YS=K(I@ciIbtQf?h)TWB=W{U zdmJu<`Ew@@CBP1`C?p||5-|D33Nxq-(u9VZ@+n$m48&K6vmvpfoFu9jjQU_dW)`Yr zHNmvwcf*h%xq1D1ipqG(8%2I`|jvQpX6VhfJTdUx|E7Gq4UJX)G)YL{xD)K>f;BMH`|b z^bS|is^L|74=2??a)>2B!&5{DSFTjl+uOn_`gw7|&V|4pz*XBbii-i#4pkX#1Q`5K z)E0`caFvBLtPndq;PP`Zi)al#XmJZtI;`NXArCBQAK6_L=CV!7>Yw3K8a0&uVU7G| zwC+l!Mc@az3TPkO{o=x}Ym+&Q5UBsTjS8YC95b)L&+Qc?sFkR-s$#Bj%>$mhTG6}j zEmFdHD`ZN{2De=T-H1sKPzloF!!3_%!W2v&CaRG|E4EExk@p6t>I=R%Q1&?kW`;%s zDMVMR?LMM}ji@)kt)4Lqsa|GQ<@}?v4upouu98uZT~?8Dvf!v5(v`F{i0ngSA7onw z>~?Z6w~aJ%hacp?7x`ehCv4E5+Ry;OUAiB*UlVFNQe>JO%T130UdpXBY*W7=z2gr* zJ2KBM<-u<%>Tp>HKG-gt@rGcFNn9L`$Z3I@3@#sUY3SxMA(vk_RM0Ln{7~Z{Pcif7 z=4+7o*+w6`RK3BJ-AjFF`GNJM!3vw4sIPIYuZifu2c@|bxr#+#soW7Qp!ChpkRCR3 z<7H^)=3qmLC`b&#Xi2e#(BP@kP$@98xLlymzrcGmv&9+OA#9ur{e1KNJ^2O4p4;dT zUOD?sx|Ak`w5{1?|5kt8_wLL~r|mJLtzWm2%_JZ~WnmY3MvjBME=i~pOV$~8_w9B; zn8J;LmC27WhS^(giWGi|hR;!m=5Og*mQ1o>Q3Hn><|FXU1#ONqDdtqn@E3<1Oiggu zX_ouU`Q$V;++aORk6QSI4rUIaV93R!WX)HzFJf`V^`HyCNH4jik}$`@DM-!9C_#OH8pHC)pwfO_mSEuvT*~RSKYMyh8>7Xt;D$-O^N;?`Ovy> zrQRnB5GKHTTgU0cntfbxXntoV`$V$Ie9f4iyrH+>DQg*s@)0Gcu?L>a_GND;?y0 znj)qvM;&3F@VX{v`HgUZcUAJor^ghfzH$5z5COv-`hm=@I%ZWpjTwnMJaM3l$oJG5lO%k0V; z9NAFbWLEm{5ZOK2`Q%14oM7JW^SXOBPPyQFWwF<7>tvqh0d>YU&t79$aa|U+HJF8G z4J1D_6!NB#NRCY1-onY7lhocGsadkQ3jp~Q?oE7!9q@&JjE95mI24A^@snqdTL*AB z$1Nl&^m$d<5q5=X9^fbnE@bKAY$o4WkB+Qn$uC%G5Y z5I(0H;@V;cIMHMsz;3oabUcEe>#iQ0DN?8Ma;8%(ibr|jm_0=PK*>gxIFdo_HLv4d zLIn5xs|0;;%oAY?Z;lQZIO;{{0*(K`_5ui0x`1pu6yoINl^1=wsg|t=YYVL(5QPSC zyV(B*jk56J$j*x(<_CgBVk#@2@S-_j7`1BpyIvUyBkuGEi++bFDOGb@7$1m2w7}qF z6911lHUCV3Ih{WnpCZLVRE`7<9!Mj{Fh?UzMLjLi(KriJV?_9*gYKy zKxcU=Uu1{#kUcnLKuRSXdGy*yd@*nCZW^oW&guj+sh3@VYpEF$5C_M*Y|CV~zy_HbgUj{?3p`xC(nR(Bu{ zn04Z4f}GUtkloQvA85w8VtiyrkH}gF5LW8EcpUY#qzupvnC2AMYWERfmmnrBiXH)m zjdJOX5FhJFnG%xmllv?DGR!jX0j8NYMc5wZb}7i#)VXbp-MwS~p4;X9YLdzH-ss&j zx#aK?-BprHn!3DHUyjN$&Q<9vOQN8Thq`Ar_RmD}xBx^O`hG?gJXGnUA~2$x2M0r4 zyG#|)B;m;vx_6tplH~l-bwG$74S@vrc@dExi&?=Q7A2dWO_rz6?^K_@KiW-&*5|1h zkcz4=z1JYmu+Rhc`;)0ufsZ&{TR}j4Ur(lbV!2VRcpqGcq=|F;`{=>EYPODXV+7#r zH=%;w`$Uk_4$UNCFTTWvY&i$48DrEwvo@c|mQ&BtjyT(vuz*PcFU{cUx9HO{k1 z>vTLxfk5LAKl`7jKdiTSm-E!t9!botH`X?rS}QHcI`+ODq$%x5=&0{kO7%cvA@#2 zj+fR$-PLXQI8IPjLV$+9azp+DGPA4`re^ta5T@x~bVN$6@dOJugi6h+R;=Aekjca_ zX&$kHE)RTWp=It?4we?**(ZO%H%tvuV-EKt*My7j@3mu%)uOLqSj7 z8jOqI@iB(e!`(i9ktDL;O(?l3mQUpTn(=p=2WJ%K_rz>|Sp+`14XeLcs&kQjAz&cz z$oqNU%o)*Mge8IW6!Y*1k>Vcow-C%RII<%%Es&L6m3;HoAJHoLJHNAN6=FUh+EZNS zMCd+X@Ggc29Z2TG8HgvWoSP4*Ltk(aS|N7%$p) z^Zd@l(BjohrHGELKKZY;^`}oBER~E$}WMI$D)s4*! z?X2_$KlMk$0l`vFjNkKQRAtDCYy9fPa5%mkRKN1b=Z=tnu#bftjX}Ygx%+8hy6;on z8wN(xhv3}7a4?Tk7lXa-C}|yw(yi^|Whf%Kzt{?~Vz~&+v9M@SRLB5E1IC{#@ciy0 zI?^{0&iTkErxHCEYvRitc~bVPr5DMyYzn{_ZC^GFBY7ht$SYMQEjiPO1xUvYB^#^> zve3c%=S5@8o(h|Qhn?ZuTI#~|kCWv9H8^em&uG{yDPEwRK&j<{MeP1{Z#ZjMLns-bOqzdLGJCpzjjjhSvgH) zFuiw=v#J(q0onJilj8y0$dsH~Qz+s|-BBsOm3Ny!WK~fRtFYuAk6w!vu&JYJ{kuQ0GBp@DBF1GY}4k{r$ zpSda^&F7A7J(M1M(A$00aOPPQ#+=90WhU?Urpt5V>UCynKx4`*%)r#r3x#ln%Icdd zA2b1U=lK)K{aV0HbcXr-@?w++afmDPqKAO6ySA7zLmdzHDxuYMenuoRhumu26?dnW zAG)x;c$rjl7OrJ%5Ltqt%nk0QUA$Er(;}!yepJvM-%Z<`RnN97i;78bWSIMi_NXzR z;s1G2uf%4v$V_T(gBQMK0s$r0L`BY!X8sC&5|gQa+d-bvECz6>(8~7!QCMIoeFpeU zWUC*PwRy(M2jQmY9UP!Qv`1jlt!2f$kgnQZ%*~5{BM!zY^Nu+cOwYo#w3C7Mb9>ST zBr4dW>{=>KvEKXVDaaTZm?tRg&>f#VUzuC@;_CCk;t^x1)iLovAELRYX;X=Ueg10e zhRd{QYY*OH=2-p))ajCTWZm)5blFEi+2?$S>StU;-8nI}_co3s4ql-RDKM&Vb?7~% zbt8DBFse*tDa_CYV)UEjs~zt2+G$w39YN4+;pCyn1Ui17(6_!Z(CfwFu9H)u;R zW}2;r!3ZzFowDZ@u+Qf-yQnqBebFjTtkND%69jjN*@~38^Y)R_Nc=j!xnL|&llTHF z#pEAsDd5VeiEWOMS$?Jn~_SE)$95OC|{vT%FrKrR^e1K_rtsb2^;_b-uog~Za!!fqdAocl%%uv$GZ zg4J_>pn689P68le<2z?U(#G&O-AHbANgL8vZS%?nyeG2MQgfB}LP?NGEHx|=LD_7w zm4O4$dZ@9-%l`r}-l0SZu5YN}!hVrhml9xcmz$w*AujFA2aB=i$42 z3V}H>fKTm;=K~fuGgcQ{sz8sFNNNhJ>UiO-7MAs#A_az2?I2S>5|Idsv!H^cjJq_= zlt7uIH3@*-PMiSY;An`W`{n9fYhC~5tFH?4HyKv1v2TKWN|r&0sufI~Z?zj?09o|j z^mb2?BaICTFNr|w4hS|gk19-u);`X5IK}jbZHDJB7kn#RMrfP~c|fOu8QZJ}2cL7h z;2))|BR^E9j6vdVNBhpokI(o4DiQKHtHq`(_YCayj{SZFWLu+K=xjSBq1Xkk&=_@( zXkIcCTyLq$@yAOvvDX>v7KgTFDG)Zd{a0?XQu_`<%MAuXbs)*J50U2J?_s)l3 z@12~EaK{^;p_UeX177Qd%Vb6)fDzRe@kS5S8RPmR75+p6f2Nu>eQUgg{DF_oS=)fTb`vgpfl$Mmk+o)f$ z1DPtrWO3gTg;kuTtf!kx<$xkzb4+u?&^ozGfUi)G6u-FJu^5(h6D5^RCqfUq3ltTs zKaxr_O_8mL57B6ti+mi-qUviV7R+-AZZe94=B!|J{vJwbCgj6%V5bgbfq_s}^$^jj z1dJAya*!V*aVYu-#bPF`DE=J1T`pbL(S(Hrm-Ld8S=o9zxq$*NQEM*Xt<&D5jd52> zp76NR=BL@kj*ha1c4%oD@GFHi0*Ogyx4%O#IGRXD*zb)Qvup#uh{n*v#p>8Qhasp* z40B~~X#e6y&cPU&XW#;4MLai5SYh5P?F}3pgU-R8Jwd)kW#zRZTS&4{shfynV_m(p9Ko>XT$U?gD!`i$5aN$ z1#|h24;yIZu9}$Jrr9N=&Z0;r923Tg8@@wI+q!CDVm7)>k_b5FFOxWqj&N292dq|~ zK5}&wgf~GI=wgbrn{GTAlcdtjpgiX4MS)}fS}S>M9HNR7^^i%fN-<@(Mm1%e zIokSYpsV3%9rRS}&1Ft`kH$g=eah`go^D5K{6UtGlruU@rZYl!ossU>22qj!j#p1i~P^sD_h?|N_aNotu!pL_Fe z_u$=l{BC?u1;R(q4Y&T@?cpf)*^77oJiUqwHv$H0c$UVlv^$Gd^4BpP-dXDtpF2SP z!0MoeCF?P_`*vk+>+kz7uI~5V&21fy@PmD2?VjKKDfc<!knU z>giDi&zoDH-PCU9bRRPQ-N_Iry*kXztsPjgXnD19Y__~n4y_Ae;Iwp4PRCaZ08_qudRC7pZtRrSee;g);nn)o>-|;wD6zwaX&$qv_6%;p5Yk*aXi68wI&kf?QVk}=mmpvzk?Iz+Ms%+e%kMk5A+0; zypN^+$z*+;LwpUGTDEJq#q&C3ur?0V$e9pPx=k(k* z@$I>OhCk<@jC*fVNBB7{53Z=wkuG+{pT{{xeO9-r@E|iv|58wB113qlSrZR-BK%n z%*!AUL-fH>=!~I$v_K`S)g6#Il?aLZKCt~FK8EVyn9@MySs|Ct>LQo$UYynms%IEl z;O(FmIf6vjfQ+ly>K-z>XSOxJ z$3^da$H@PC?7{FG%+h<~H02V6!bZP%Hf4h6-7}?1pSpd@Ve}qn+AK!R+h$QH0MS9p z7wpCK-uQ#|H9Uc@8+TXXYZ4AVb2!50djRLe?@N_sSH#L%U`}`qanP^g$3%|KWF(++ z0?)cs{TZSdXt5-X*p{W8+8o#+3MCxM>;}d4v|G#RyhW2Mu(q@x+c~CPS2SP;L^%Iz zm@GH}rq#!tt@l|@w>AaLw~V+nO`_JMX&P(DeDBL}LrkhgCv&WD!SqFG3abczFAs-1 zF!idz1C9wWa>riIIHsD8c8K z7lqvnI<9QC#?m`9mf$e)d5V~%A3B}y)*h{PI?f6R-Z^BrX$`EAwlQNodb#DyzDF)h zd}6a>R)y}q_F%jfsbMhlg2|fOQYnv|hIg7U-bEyfb*UhWY?{Xh-H|F5df>H~9B!kq zxpDPUZ|O|v+e(MbfUx1mi`f12pMQpMz{gIrbVG9pB-&Vqu?8uO5xGTamqK-<%B~Cd zC+MisXTmmd*IM_`H#nL%w5EVF&NHCg$TbUP>;W^Z%Ck2-rOn1)$Gw+SWMhOq#=}EY z^Ue|W2g73)AJO@fjkBZu;o$7~1B8)ayA4jBKO7!C!1Y&$z0vdgRJ+)~{bAH!wHyCd zR!SJ20fIR@a?)A@77@qhi0j`yXx&;~`WhF|AvnrfE?+I&T)3S9sO=PRBHAO+5Ac;) zKPgYP_|EYKsOS)HHljq$3m3W0U*!axcn~xP1SUtd<~Sax5R9H9^M@tH@&gyRv3P7m zQX`8P$+QvMV)JC3u*tR7JZ%>L*oH)DFm#S zRZ!R7UQy5(_d-)s_>d9F;&sseb=x)+>L2?T7QpnEoB`%v)%8gy+YU%E(9fUz{K=hf zdC%r2&SJQJZahvr)}}Umv}U2Qx1YFm^=Ewb$t)@y;7UW>?_F%i6atNjKe*jc7lAqrgy4%r5H~GrpA3(>X#XeO{%;o)Gp^;i!M`W_J%BdUrsa zI*AHi{KV^~sh{~cXv^4PPO9X)0&NM+tSNMO*vA2(6V%%=8XBt_AU$_kSI{iT@Dry{(>z3;s&;+DqX1m7q#8*2cm(Qv6#mqpnafVplMF7 z`yCYIitnA%5P0W7zYA6o_+Txs`WkNC5oYf#EG)dxv{qV=P)v^W5QE230!k=U=pU4M z<3c(u$!9znF0_6`S^Zs{HdHZ2^~GXeU``$?>@B=pXl*kY>I*N))ZXUKgdXu)-!Iz5 z4m^)Lj?U)6>H*aHsbK^w)n{o}p)0K;F6Z&eP+TSi@m~`<41KM&1EsR3a#g%LxmY=c zrkj}y!~3D?7{11yCDXBsMq)QY=P_!Hnn>K%>+mo$62=4j&RZ|@+@YC=JB^$DV)#|N zaj(QUOpET|EJpSMcPGr)4tV@_z!tB3h8rg!Sk$FpNpvD8r+{+)@b@1*is5VIdW~a% z5+DFVvS@Uhl<|^7rK>oaAkxW~5$X$$QQyl~L!EGir{SwI57P`=ckfX1-Fp#}`4QV1 zSTV@GF~u+h6A4{+>-|5Ew9lah!gd{*07OH3tH3zt!`Z-Tp{WipMu_7d$O^*z6tJzlO=}KHp!|0qyPX6;$;m@lJEr3rovC{hLI=|DmAbM)fc~_5j@AwaS&e%c%xq`L1P7@*rwCe(X zm$ehAeXTsD)KFR_Yjf5T`@v36ZA(C0RZoZI*>3;@xMR0JPIq;FHyptfBauO$a>=n{ z*_!+R*?aqjxQ^`H_iy=Av>8nrjnyF8nal)Rc(9CZ&XFY@K;z^J2O&TbF>j$kvLfrd z-`}%dYS-Sqy8(?oNzT1=mo!TO{P}J3=K!r6SFXn5dLFf@bUfiRTh{?;dw8%`T(=Nyh`|1ATqo4X}hlq43bc!q1n zJm22fdB_~Cie3d$-Czmg49d>`20cTF9T+#sUi72^vQ+ji z+$qxNLPfY3x8ZJ3xej&X;?;0C8c`_qUM?_eiKO$zuK!kdE!9(~RXIMhg9m1uGd*8PT85%*wJ#(OFDM07s*4zXi*#Pt>yqgB+rN1 zk{~m{bz+680V=Jh3$%E5^S^8MX{^7eNB3D-w;$4@^Y(VXt`yXeUL#Pds&D8a)}!dn zS4>+eon>GXHtBIq3u9iV_j*qE{t&e8j^ka3AfXd(_m*Db9Wi6h#B z4KS;O$U*Uwlyf1Rr&m^F@F!xIs$x|lX1j+yV0Ye%u@mt zGX2biehY&Sc469J3Q!$5HT_=cgSzJymw&kOnUCY#Hm%`2W|D&j=KX2oJa*Gu_$XAF z+dQ&j?OmN^nbh0u>IJw~nqkA+pAG{vWN{4NB(M&sd96KS;aF;Smtc31)f{Yi;vOPs zK;sVPem|abXQC%@E+`YA50u;<9>cIe#*J9^+8qH2IALyi3{t^MSuop1YOQH9xd6U$ zXE6L9@5J&LF<{7^-%0{&k3=fZWCz+XeUFz1bn8UcS&3?NpzrzCmr`rp$e$($ya{R5 zyEHgyj5zf>4o@88;PT@+ra0nU9=}3$l69=SAT-Z}x8{2mS{h>TpAnzqs%T>$^k#8q z*;7`fhqPD>J&QUY?!P!EPwOmH0BpeYJJsuLgX#0}#9l@dwn((z+F7?LWxs?i*mgOD z=)EZbXKqVd1mUvY>itCgLW#xFetIbV_F!)7`0MpYj|ZD8Up-hItbK!hxJDU1JNyNR z&pzKe&Z7q?DmZ#sTSXN70$v`F2($6sqaOy?&np!3_I{o@l+Q?ySy^9S`Pc1-L5w$M zL!%LN{G6Tz61kS^t9KWg|ooIA)xU(C&^ZU2PuIbbLyC!!ob(s z!s5B}1>SC1p?vU$4X_X8n zSz%)eYHD+y?(Y?Dt#dO6$9~|$g=W1gVy2c{#@}TW+Z0XFb|?IHukg^L*-1rR9=Va7wtlZ`;RgBUttfh#`3Y9#QgRfH;z4t7Zw zN&-z$^WH=R?SV0S_{ZXL{rV^GDOn5t&MeVuC% zeLwf>>w#`)2?>BhR)OMw>r?p4>Vwt$oA^4vS%36>;Y@=cbSVKpLG`o2`s%l<|MGY+ z{I{n&2akSSdU_W>%5d;t?fbRO!QH~av6cBR zC$LkffFf-Vhp=tdT7{6}MvM+;65FjiL+E*Ref`n;;O^be{@E3@ciuyL!g->4b;A3h-{WQP|T1XlDwR+O*|;04h}Mm&t3v~nJY729AAPPg^$t!Q9^ zfwnX=1Z)h5t9;skcwhPkG*-<>lOq`KN>1I!Hv(jvm|ztQ!SaB}Om6XNdvDY$98ahl zZP^JOyKd^p?U9_xYhLUgVpfXRni<^g#&(Mh1>HT8!CfV@V?sobYUc&E5G09taY_gY zx2=;{Zc=CJ3I?qh9XT;gVNcoBJ2PKjgOG)Ac*`MQtxkDiNGi8*q;*sJg~v#Mxl7{(F5!l0yYSHz#;p!A>i z#j}Or494l~pQNd=J+6S6f;tvySLUQ%^_KhQ*qKJ?Pv@krYCFp9`{jj+d|fEA2|- zDu_IUAK@}tYsEcvXeu`Y)w7WGt8Z$nt5(tiIa8TxKzaogEeUUif>yM%)XR*!%Y-Tu zaUR^*ku^rw5IQ^OCuiee*UZ$G^AHQ!cb7dQ-(SgE?R9kS<>oYC7%!7fsO2_Z&`?n|`LfQo zof9X8XzJl+>TaPow9kajq&!!A227_hQp38SDZff3e!GA@dHl6JU(bBQJsWJSZl+aw54-g7gO&TM0q|`A(*NBO zRE-ELqe}vQxNP}tXta+UmE(p>xgp15eYJ?MIX$1&S1);euo2o%ZDrj`boKA4P>3y) zkwgq%Tr?CDg&E^2sJWKkLMIBl1SPkHk**A&D^RXj+|61@N)#};sm{BUW0?HdW_jMtyAk*%-V+G(DeowM@r>p^Xw z)F9A+s+B*zzehOm^?N(i=~CF0fgHE+_gq_NL zXviu6qz0YpP4%67f}O)edmZJjT7-tv<9Dt3Qiq8L&+;BWZg*&)3PrH_kk)NmH#dvR zr_jQ#vCOeXIzwzHh;P0&neV<1h{y$ulmcHFPi1WMqm+vvp+21qe|E?mBB@*dEmep< z_B^32^s{HClqbt(^5-k*m;Jo>;KjU01dN5;ijCcMAbIQ%mNgfN)oTwoA2kAXe$H52 zv|=CrJ6nqrbYs3?+KwC{U6){ zJ)srcY=$1*8vJ$T!IRYu=M&W%B5Cx=M>n1Q#w!Eec1Fu^Qaj43AQ$cp?phnCQz}ep zrvSb!tPx*NFtrgb;c=|OuLeYJAn!)(k^aKmNcJi?#rCWi!X!?~(Li`m0HJ~?O+d(6!PlSW?05kou>C!*FjA8nH|}!wCSwR(Vs@$~7?P?Ps>2@~PC902Q^V(-g>W83 z2gUHwlVni_(AhY+Oj$sP!JIQB@UQP5?T9)^038qhbN`IQNR@bE9)4oX><|vU5{Nq| z)J+yFbHQ`9|MTwQ1+d0+062*3_tiK8BfLPEb{6S(N+h_SbNrN}Vv$*`P)T>1isIM| zvwe=^(gXt53pT&9TD3|O$M!5glZDhd6WgUAUl`Ik9Q@pzk!53v;Br6Y{dGF47I+D!RE`v9dSTJa|X<69!;QH#FYG@l#o^X8p3rm6MIvl`0T?Omx&J zR*mxMca(qCSYN1?#U~LsHN|E4c%4(e=9pvH(enT1{9xj|1)cj^tj#xaci9S*!tLm zow!|AV@=O}y~~Mr)%zS%7T<0#vOW@?&UBW%@%h|Ttp-~yI!i|o9#hND&FtR# z)zQw+IFt06vpr(SdBnP1dI5Eej++G5!C=EnE0B!>Kh7BbXB@O(eGBeDUC2B^=NX$ zE)cE84g^j3qx+&j&K8JQJ*^-M)YnkWf zQ#<2zONEX2Vd7Ux4RW%XOpAt?7cp=e;d1mNVyXCjEmW(=agDLmg?l|YKmKy6oIY9ZJ0=Kqrv7IHPk6!s%?-{cyO%1p7re> z+{pSeI#ybgN3x`~!9$SA=O-sljB78C(O&fteK|b;37AQI7sqyzx4U|QHqp4)rgc?s z5`!e`n0x)6YOibpk#f%Tx#uNw%JH~&bJ$mrl7lW0MZ=g2~j)NKXhBnoMu=Zq_k>CUJ;?HOVek08%2qt>6xv{-q4aDpMj2vWtdvq4IArZ@TV&>1unik1 zwBGc$(FPbp-oj%Wj1dv$N6mcL|9`1|H%-0Lf6W_^s0LVB++YvY=endDhTF4CK2dQ< zTWV9qEI%co>@0RJtNW`n(Lm1Y0-e)LqkLDc?aEqlc(Y_;7i`VtsXpY?L!)qndKQEX z)ZM-9lkipROl8Vu1nDz~x0-}uSH=QB)ecs(G+0$bKN$h`I(Jwsf{B`6VItB#P$woy zCs)PZmzhd6$~T2PV7V_9HdQc*u*YJwmR^>Bn=a+blHz;LEY45((~yuzu40T0^+D84 z?^WM3`q7^7#d7c~M%yy7ii%ND8sEN$O;f>Sez5xUE+R`u^ZhQ#WVF_IixJ44KAVVLe7k8jG_~3M)>G-71+>3w)#A4Mwp{kc)JYVUyK;H5MQwTABuKTI(N;2+nEzGHeb!150HF{|r9|12d z%?Xy1 zsX7xH=6pQuDu0#P4O_GEMy*F0P7F~-PJ2G^A;u=~q9#ErZq!33S6bW|X!tD_d&Y1b ztXHevzqrged}6w$1A1oZum|O?w49lbx)Q6<6@DT%U~a8k579<4s?ZARFN|Tb>F$$p zd|~DThBKU9>ZekRvn(Ps4!aFwf?-M@g&rCL$CZHz#Y8HPMBTnbSsNIQs4qlw?L?Qb%%*=h)aPQywMF=WuMg)6`ERFvP!e%sZobXv3xYJ6L~MV z@M{}0T`W$e9c;_%jw?jmwjSK$Fri8p@^>~dX0C69y{75Yp`HyzhA|iCoOKH&;N@k~ ztxw|xR>+@8Hr4jE0Tie6nN0Q~Fmm>4Y-J=t5t1>DbCr?%sTPSUHsq;gQpcaHKR|vX zJ6ochGICbViJgl`KK7bUGEo;kszl~s=%r{t9+!)utWk2_l!?TW_}0yDA3XYM<-x|& zq4+On1h&&C7Cu1)2;`4yCRr!KtG!ch>#wWpPlw-aZa&`r?$O4ku>1b@;8RP;?FC1G zs_!Wf*~-NJ9$X3@gvU~ddH7`KSz=~OK@QnQafZk&n+h4KZiZA~by&kAqa33!CObiL zm*K|*zNRF6P3?tu;^skjH#_aYaT^ZTagE&V7*nNywmwA?ZuhJJk7GcS2}y!HtJj9W zGs+iZmoC13bpOfss}D&!fAq)}(o57r;fuqC!6De>YT;_L(cvB?F;#TE>12KN{}6@W z+pf(x2fNoB#Z;KKzkNp3?~XS#2_$HeKYtE=FK4PgTL zm7QwAAW#)<(LKCZfGkFmQ=Ir0-?O3MYJOTwjeyl^#sa^3t?km?R|Zk3Hr)nIj27hiDAf)wS2K%Ii$3w-OAstDUkyILWHet^grw#&O216>8ru4em$5OXc;bkf4Y(!U9e0$p!q6RyMThZ+ca`?-dGC zXJk`Y&ECPz>zxBGzNWGR3XS3~XfpCLcvV8qUxIL94{?ugLH~>DVg^i5#GM8Ef2E1? z?f$s%PegIQRuJsO?k*Z^_yibOHFYgCydEROYzOnW z>l*E@p8EKL@}kAL13B4_D5Sh#f5k0yLB&CN8tB9D^4XoGJO6Y!UJ4L*Ybfsis(88{ zMV2LKlT6ThRXa{JTp9~We}bScBcAVBuodF1pME;H`{~l1e_p!tkJmubuY{Jrn8!aP zB$~W@YMKe;mqKz-6dc`@XF{glaGOaE;$d0YxIIf`YI0axz)une zBeSP=TaC&n%}3Fkr6noq#JY|tF~x0wz5uBo0>zhCYq%61bOX;ju>sA8@Iu9SP#K52 z{Dq?L_c9~TX>HnBJ@It+XF_CRpo1Q1?x4q+v{dE>cTa~oWegu$xf)j5x?-YaXYtj% zfg}$ewb4OILlxgw=0di$F0;?-d8}9qsFkla9$nxDas;U`DzyLGttuSQ};Od`%rZgxh7?bii?sg zm$mm1wnI}#BbB!Md1JiY#nN;e#(<(?H+PQ|pU#7=Uf@YdLOh3@eoy_;4Gz`}M(6hL zuKrai4&l3AP@S4V`Jfp7{4IOgq89OK>>@cp%z~~d$@bHa{!LKTWCy-*m{S_J18m$5 zrqIW>*1!y>3Ojtl7SLR&C%$`jaH?ab%sE10lr3087xwA}_Fu|mxZSFlvgF=)X>pN+ zkFl1-v^r&f@b{NgN&TlgcmI4>okt1W(y?tj+Zb(laa6uROCztlIq9AsKb?F2R;8aP z?a0*xb8O?sXcVQ+QZ}||#y0IX_6WAnf%OzU8*UA? zOG}nD=-Kj(*NdSQ#%D>C5$_+*4+e9hk&x5gf~qy5?D*be-@(1@n*M2E3QgT%ViM+M%Io75 zqD|%Qru-scqcx^_6RkSRQG11FYj}$|R2F4Zi~Rh|{kHZK*VgBvHq?*LagCLZJbT^% zl1%1KH`wIii=`!Qn?utg#lm?r8ci833FhQEi9cmIZrl)?NAYl&oLY2Y7!#qTb_2Oc zJIB6wF^@ZgFSNxu5UPYBH7<&r)Cv1Ir@=3)jtE6C4L{t)Y#~Jbo5w~{hw;t~iki?u zrS6$FNzeGExF0xYV1@%dCpx16#dnBpYLbpdDM&xql`81iXz@g5;E4$ae~xvB%lZDP zIX9SuZh6!F(<*VcYZs4N#zx$mX_M(<_U8U;lBDmMApJElyubU3+>juX+4!}lb8zH2 zUs+78?Y)a5T_Y#pOw*fOh4#WnE9V}@Kypt)N3D}A6VzvWB^>8sdlq{b{=#ax3M;e? z1*23S7q|M$QY7?83g+PBw(IQqiTR!*J4#OuUg+O3dtsLgtF7NCRA_IH?L60(x%l-U zoWIqd@s2N3wQTbC6AbCE@St>GTc|TOeS`)099z=ZKn4nK;Q4tcfP(ix5c7kNy%muW z!m=oQ)=M3_;FSAlgbl9{wC6unoQqV1Q@Y_gK-KE?UEwsj?XBDfiUHXg-b2mh20D4D z^C!L?a<{x-!z+=F{%gkdaj*xUNF`WIoRqzmG^yF-rmwh`cfyrDEAD;#*DLcgO z%~mMNuvR)RAtdjeh74CtCs6!R=uO6p&>ueV%8R^Qy|Y*-Z65s^(h?4 zPQO%*Tkn0wVNcH~em#2e`2dye#tk@jG#!j6)?0tpw0N-gaP{8S+}2$42nNZ03*^;| zP77pe*0dnu>C3@r|363){!tmc7T=p3bUdKroBFiwzQBau(GQa`KL3z0jR<3HhUG4a z!D!dS!UT5YSrBE_D_3~Hq`qK;n%S>xpxrlnu!sfEk@38uZQ=p=&Swq{UGn4qKD)DK(#_{UEcm5*u6%JIXPp~*##+V?xhJ6tcwp)g_&J9~ubNTE8eOu%x} zN9G;YhKpw+%Fy_o-{&W^dFaA=99fUpV5d9Jb-L_ef2`C+{m+dR4I7P=8l5lgV=}c* z&hm+ML<=k3#lw95yTP|yv1T>gOHUGau!xtKg(wEHlLVIF?;n{^h$FxT`83;YctyY^ zAAv~5v?(QK)H^YTecigzYJ6RQs5hv?dp6z_n0%DWVd5;u?oV1_r$^?tn1|tn`|TAi zd2vL{h=`^RK~_|&7#dv13yGVt%C$VUX}Y?2eO@d$qszD#Y(LKKA{}Lvq)qmXKOJv9 zVc}w9myj$}U<;aO-5b(v5n9XCe)M>gIP`|BTCBwex@9l&Y3G2d3( zF(0+}V-Efognq{B6B~VA1igb5_PY>lG}4ca7u5y6{ZVjbH_+5k7-_Yq*VoqaW8O(D zhTV;v-hG++uA7;~mMuoh6?EuH&99!uaUi=IpiBo9)%F8!yzXAi=U}42aZyr(9r#q6 zPPn

(OrGqB@d_T8(OD`3#Mcfw{3OM(&bG#n&rFE;U{8S{1<1G%vXUS50)^tZkts z$`H4|9;|(hL{+1KicTEzgU;=@5ktH8-rM6QL|9jl9=e-pOSr-!pg&qMn}+H;VLr2=}o_ncCU4z zPu-Et*UM&6H-;3{$brRgp& zuB7QO8tB74Sh9H=m8@hBw762Tj@*(#(8Gr~Z0kMAUZ;T747*9IlWVIr^<89w?qgF{5abD)ua>?)UgwHkD9!zhbpI{k}nzubNxcpUbu1fJihs& z!%GvBH(wmuRWYU?y0FxY9CW=4d77^bCV9`prZRDpqDK-+yH&So9}jVupI|MY4OGU{ zue8sQN2DVvZ&1auExJmUFD^|27s@Jh1=_+x;zK%=NG=N+6_-%%9CCu%F%I9&xMkVD zx`dXqk`ibY8p@n9cc^+7?&vr;nCs@J4hr=a2M|wQgFU{N{@;hblx1LvGoh*^rsPu! zRP0(@+4RGa%F_5WNt&#us|d4dkV%X5R=TM7z-nDETOzh?XF7aB+gCMlqYI283b?(#G=vOOyS+qBIU?7=97A5|D5VR z179f(ADWo(5WG)PMWt+#K1BLvF(7o1Z2&32G{rcn3FLaHlAbG) z8T&mU>N)pV(XOl?Esg|W`s2Eu<60`)@CuwNsa^aX*v-pblLM~rJUUK6DQ{xnBmZL1f6R&$p3Fi0Mo{E&$WV*8@3NuYG*2sT`QP*v}O>& zNhc#R_KLrq7yXP0hT>U8&PK`yp6q{k*f0|a#n9gG@+V-_J3>6%66I+cC!IZh5_S z9Eot=ZajAz&jG2QmK{ePg+3NY#ii{4{jKh7L1{7R;lZB&H!~f{pGyySdaVpS6u}_v~F^F4vsKKHX@>kG$PIg|3>;D~fO?Kbz9Ntr4~i#Rq+>I3pswZ^F64)%ZsB zM^U)K!3fSdzMBVcq;lHjp|K9;gSUbIV0W6vp9fyz><@hBiMp(;UfJu`Xkylm0Xq&{ z&e7BzTMAV4oM!}#IOCaJbQbj5ZgzffuF64R=??>MRi4<>dQ&EN^6+1G|M@x$3s$Ry+kx4B?rK{wLHo}p zHN+@D%I#(AI$F@&jMW`y`MgS-2N&sk=isG+0xvbD`?H{HZqam2UmCeTZ)y}YS!13f0R?R3RC&$ zl)fYF^o(+>*xTWEoM5eL;CA0Qn}== zR)uC^KVUdbDA1Iuoc`qE6o^yq^r%>0B$XWO*=c7i@wKnxxHjd3PADHVK7|U+{&K== zYgGR?>Swh|_5sNTzovfXt6OVPQoBPHD(YF%OFR#P(Jy;~rqjLa$|$no^oJ`CA*{T(!?_VDi9uY*qrCd5im7;+H*Uzh9Lw={JX1C(YLO=12Ni4DKGatArm zf^%NyoeE>b^GG#t2`CGo4oM{7fpK9u))8Lhf>zTwWng-`XE%&i0W;P z1|Z-|Y`}pS!Y?ll)?4(Lc| zwGYb9o5l`OfzcN!TXRL|Hf77*z`CrsK_&Q;3DlB$nhMjWIOO+5bWc@lXlXd9SqLNP z*=2bo&7L%~tKlEU%Gx}kVI$Zexvo5Hn_=P&?Xy^B;C*^q2}kC9IZic=L|TtTT-jce2V_mi%f+h`;vxnrIXCtteROt zH`%X|L)8NKJ;)Q~f$LW?NI6>oAJ9}wOU_g#4nivE#*Us09#L;sgyqa3oFd# zs2uN5_?atEsH!SYk=BR z98PKUDbWK~28rGeV1p_Zpj*Y#KKKQjQDw zbqNkoBV+mmleZZ)n)?&05L+wo-lXvH=_279>24AQz6>8I4er0%IVLqGMFHlX1Hffa zV*PYK_vqqGRT4CugZ8ib<5$*{NnVqA9wZIX4_`Q@WIqgsTfl0??2ismIgDri!asC8c$b_gB|AhLaW1O-*x$(kcrD_ z7gJ`W(*gWVGsBrkYeNnkj}D@ROYSDfzKx!?6i!^)V9~GOKl^MZ{6W zF*g}?*@!z6<|{1yii}(gDh}}l7)Z0ehjt6;^|(Gvpr}};n)Qd2I@ABM4smsm!*StB zXe+I*$5+zV|WWWD@gX@aVGd#P}fvxbOw`$>Z@;jKUd*VxGQShJ+p%lTPrn{GP@0Zs^(kE zeKhvC0tY{TaQ#r+WzV-sTPOdTkT?~EuqAr~43_!~P9obP$hYCTtTWQk8LlmCm*X}~ zXRGtgahz!yJ<*uL?5E40YCfW|N!jAC8d%1?Ye}%zAYCvqS(@+WaPk=9mp9dZ5ZU#1`Mm9g&KlIeKjqgkk?7dU`SYnqwXvr)lkJ)`F?y75h`q(D%a7RLed=|eX3kKC0Zv~}NOG@WPA21Bxo*F^PAIeB>Ki3g)?2foAjl7Dne5(}R^EoJqt(hIath=N&m8G!< z{MVP+rdyl+Gvb%dUQ)3C{dt82R%h`EkAun>h!vQ|IIO2DFbzk>9ugGII5|j_vDIc9 z>UAp1(98dCvI_+Ix*vqs+69@~4Vt=lQ`jtCi{F-|OF=vBrhtL3s7pIy6V9*iS7EUu+^J+1A3RIhXa)JLHcgHqR#3A!UJ zZEbuBfR`Vwy&!x|X)r-tKFU~_H%CW_eHL}A*3Yc79D_8L2@8C~?ToVgqr1Z{ z>{9wviUW|nz&BTKW|x_j+IG%%M$N{f9@oU|@lD?>>f=P)PiMkfW4BCv5;?Xq<^A-* zT8Oz0V3)N0te!-Vo5PSfOKM#q!&4g>7I9gGQJGtI8664?U$8}^?2{=%@Wrn@(T}*h#7pmCu7#RrzwRDnIuU%RF96S zA+>ze{kO#GA08`NisWnNmCmtbSp{twNEApn9Dj8-FJ33slGT9wi!Wy~UC=2DL(gi9-py&bZ-p$gn{gOBjeW6+88Su|-B>$$o zx5zE6E9=bcss>f+(S}n{xk{Q&Yq-e@pr2w97c7>5xd&1m%+d0}p7nW&{y5>NDPUdS zEG^Ms`Dls{(cyuh{110jc8BfVPmoXxny>_Aff}X?{yDrx$-!dLws3E3dK$tji!wUB zj#U}J!H%ij2n+iF)ycO#7cZa_QJbu6TTzVCcv#XHMUv2@A=R$9nI*~@R~Rb!Fj3a8 zoDJ@AuNJhXhu{jbsx73dy*=|Z!r#gx(hr#a^bTKW{N=_;^T1LYt)_35psACg_GBj| zdkTUJ*$Vs811`gFFqE3&ZLhMqlb(w*-$X}2XvLIDgRIXNP*@;Oe5_RRY&>SMsO3}R z71c^pakVf)i77D~V{ldJmoizgZ?}&sewSOgKvC*hcFS*Sf5r*Q_DArf+N1Jq6#UMy z=B2c-UI%Q3CSP4{Fz$;*I%m@QwKm1zF9AyUzWbN4!u}MI;5cg;U&TzGy?iY>f_{?& zbgjjrKhyxbfohD2f|~ofd2BB`NZrWWG_){d3`r2nE-K`Zl3fJR9f1Mh)o`1-I+rfB z#F2E5xN_Fd9l`u^rRAzM+0%~Mrzz~|Ox{Jb3$in}0vD#1s=U@~Y1s$gXgNO0!S&Mz z@8C)j5s4VLYuUwas+oU&g2BSoMK*;IBXspKI%6W zPt@M_fW=fI)XMepQx~f??DF6rV)M#;t|Y3P=c=6z-PNg_ek`I^4GPI;115D{8e+eg0X;_59A(ja%!zYtz|1x8w3^oi+!o1)U1*~lYP}f*-2y? z-Dzm2$6C1QNuN@stsW#7LxD7PVTdluMT;Xudt<>q(TX9oX7R)i#~BN=tra<(?IUqh zHc&GWXdX@c=-}u5smk{yo^Eps$CSE`-^uCRjOLv+SttAzXE-xI4DSW>O|(0ig}ZE& zQHDo|q6#uMVx=2z=xk2mv-N9Keo>-rUuHue$7vgTbqhj}ot})1b((lOL3z_hE|*)J zlNl(`dK)qxWUJt`*1$Py?C)!9f9zOY)IFvUTN|Hjl0w2ZN0l;Ah*G<1Mo?1$}SkeL;91vC|SZ3`-p z6Y$1B#%z7%y2~9by?k(w>Q?DfYOhb59IY0Xa+g~6!bF=^VYVAL@GkfkwsH04Y4yx_Rkzhx!Lc-PT%h~1N=D{B6 z33$;TN`w(Gm*{aUdFzmgxI2C@v-=k#QoZYAceQl1GeOzC(^}=t@iDevkoLr7LZ%l7 zA+pdYKVDEyCyR7#WG2X;rtFRHM$56HW$8H5XcHpi1Us@B-d3+=?)sN-jo1e<)8fFG zP*b+uK+Nwt!tTD3%Q@(PX!91VOe!O-)$rxlNrc1a)Q1-;KV)Gl8PB~22WRJRGqb(! z&2#_^x5K^m+nDT36=8Z_e4rINZ4J!tYM|uD&9a7SJDo_hNw2a-p+2d(trFsj(1INh zd&5=7s1kcbjL#@yu3PZ%u-RS6GPeeb)tJYo4LUv1Nt%#9cuL>O<25?s-k3dQE{0bQ z#qualHuF*7@h>q+DuSB^2OFM=8PPkCmkJ*?>5u=XUT`1uj=R|rm!%7=;z~M7$xEe* z+Yw2kx^Xmk9;}XfvVNfXzQ44OqG*;1pM16dYUg~*|Gm#8U|f^1b)Q=?xnzAWe%rN; za0Ko|RP40xi%rTMj}KL3;_Ba6Khb=$=T*u|o^Ne%(e=Ll$&w1(^hQ7C_D%}8ecpO# zSz$DU)YguL0+@wxLe*3J6LDL_M@9^GyRZ8*=egbZ>$UamZLTpHE?%5dFWqj9P1Y6n zGueGjQ<}0NLV!3ut z+oJhm_;5i55mecDa_*CZB*!LJSccX2+k2EY*<)zKow&@d=!F9hY{v;u>7}rnM(@ck zN6R}G=O?-jbF{4PsxUOedaukj@5ZwGZn^q%d-c%+^;%iz(|eS|Q+)7RBP8{9Y)<|5tvQQvZBEeP=$t#<7PF*tg+Sfl z%-pZh3G?Ecg||nCUcK5DNVh2Dgj)-wwuq8^=j+4`gDmB1Scfx|?fZ`&ezW%N_G7Mv zzGsteR@eZv)n(T2tKH`JYkpMJ{^^@yVPTQ~&*i_>eq&*$ZjPqCgSU9qT{Z2)YMV{& ziJBjH2QZ_(le5Jn+7^Gf4C=mbnQLI_Dx*6LA2fK+ry3j4m^H4x+27&TLUy1L#Lpy2 zN%!=dFXP>PmkY>xXoTYrHRm?3ecZ-7O>UTrEImn^Xux5R4&I!c{iIVC>>88^6jf6l z#+;_wIXgH}YS_*>K4#n(JA=7ztwYI)Xj5jbBhdaki_Y8|I%AS+|y1q;NlE z>&R^v$%3dx+u*7w$GghDDuXzpgSy+eyZ`9>$B#Bv*S8-$y1(*Zn~Q57ZLDoRTL0JC zSkx4!%|GQUHP~SS+z>W}hO9<^@=+K+ltE3g~zvEIoE@;yIp1edi% zUKl))vx1%IHk(dL(e5Zwc?Iq#ws#Cm(v_aOB{9!)6p{@VD9a)aNWqnNr zP`4khe82jBVX$$6ON5{{IZ{}a#x9ly_aCjZ`Ca$eSl!%Qd-(0f?ZL+SedjubE!p-08Uw1QlNV6t@DW;C}Md&=&)jjFe@Zn_Yi7wIHI zrZ%grVDL%m0t~+)VG2@FAP%o=b8NAR4 zklh$ci8uZ;C{SYRno(7clg|qL{@pFV!uYGz?^ZUqAq?y3u0NFMch0tWesr1^&MS6y z7CtON2D4GN?f%$F6jj!S&=eNiO=j}6#~>jnPj~`-6-&l?M5RTi&7s8R>SfqmUH^Wf zS9|ECaA@A{0K3G}uIo-h1Cq_Rvi|MHM1S4))^&E&?w*T2x&L$f`NaWl!w$)8uCM%c zZDaeZCuz9}`P0KFdQh#QDs9L6M$7BfKZEikhi@t^5XtUY{chviI zh1|5BDa@hlR9C&+WxYR+?diAl+$?GtD>d6*)=(5^INKlPyhiph26NI4OOnT{^CIhN z0QrWbc^T1-#yjLH?H4mpyUbB--Np6Aen^ob+njqa%Q9`ex#nAS^@%wyLqmX=(P!gWB$Sx(8Jql>A` z^VVotHWDPj^>>23Cc3|Twa<+A&8wFT+QnOlgtF?9zcf#6iu3^Lns_;iojKfenq}c9 z05(J)9$+QD&}Hsk8|nifzhM_QS6&|b9RrV+$&I5hqR`fD=VNsVS1o5i-Ceh&mRP(? zh=iNk{>FI@8w=L_J&xZQ(`+s5$_u#e71q^aeb#RJ(wa*o_d(c66Xr+C2yf>_f5l9j ztvmfot;CH>2OtBIWCyi1H&??tlZrzTY!h;!V2^pGw#YVWQLkqq6|LjxFjQO^~C&2`dPCHm3P%vs_ zV<>Wk>M^cqxuJMNyb*oh^3g>;jv1S~T|ByOA{6oT#o!;a^FVJ8aTX|y6wP@Y^q6m& zHPAk*4#9?xA-u?yHV#DGed_8sB3pty8%ex8(^V4bd&a6)q$rGoofj_%EFy&LI&G_C zq?chvP~Km^_*$2~i>WTe8&QzqA(JU5sQU5B{r|o4?W&nhbt>iLt}SI9LJxn6*4qBo zNuz~}u4xh|NU#E>eW)-n3Y*`~o{^K-rRO3aEt2 zalmnTxJQMV%e1wL(T~Ut=9*gux7n~Xaa%I8d3HJ;j7|opyu7XdORD^3@De}M;AZpf zGh=!U+DZa?NN0t{?P_TT5%z)?y<<41Q1pqH+uVu1i`_L`{I{*~ALh6AKDo6u{>1*f zh@M~{@gHkdN2JKX#!g4`!03pVPw#pH6)`0trhfBjByIZ4 z+0s3u1`IdOU!9%2u_FcR^3xvea~a{jrC`nnTx86|VW0A;!{#$@5v*5}hFT?FPR_8v z5*|Gh+Nm8APJRi>Lp;j)zrFX|PdmjkRtB zhj1YP{ge^DJ30C3(h-a{C#>!Deak(b^t?Yju@C@kJPnXAAmq_LIVPy5Eo2vo6LUG+ zRRSY{McZ6b1qnc~&*V+vx>%UJJCyCtSC6T55QQ*T5_IKcl~!^V!U3CDqSYjHw#@83 z3G1zQ^G{bs|IhZ1i0k(f)IM8Rok(y}Oe(vF0FmInjI zK2T8MfTtZCY+O92JoY*HC4;#d<$=wJ+Pt4D#OTGOs@PoFaS7>mdodbX%E&_X9(1*= zS^e-!(CS8sl=@kQ|Cl5bG~W#;+t>^D2J1v1@F3C^zap&}4LGe9^ zc|2Y?IeSS8*4h4IPSw0(i+30PBr+Btg_wuZiBMt9nf@7-&m6T*!Jpo_;}FxUK_IV; zECS>cNp75GgHWEI?5T8oD^m-K%n$6fXxz@eMdELM);bZVmZRkpRg_d(mbcG6*LfLe zlX?2Uf^UPED(3XTj@Pl`1ZA^zp0-H919tD{BoQ*TyfXrc@b#0YcYYi#=NMc->Qxo|Ly6W(LewA$<~7Z_g4OKQ|mRnc~=|4x@%x? z9kuB;D)_gi`7XzNUx?jFiqE)N`}h)Ydcnw9l<~8pegN|ABm~AIn+v+@wG#Jn=&aMK z&WX0e%$D$|HloCi`JdP&|C>2zOzrY9+YM(AX#?w@iebYyB=RLMSlDVlMdT+R|2E>0 zmiZ?USO-$!zS1pA_|^2vfw_jdTt4_yVQ6rVZEM(Zru{>0!5XqqWM7@^H5FIvD~M7` zNVvUf8I}>>?TiJ>B9r^voK^XSD^#9|cG)Q3cu@K3gTx2*7@mk3;xf6i7R09uj9s`5 z+y_Lby_=M@z0JOnKT`XlHaWsn)cT}fv}8LK2VYick(J=9sr02lYgxmNRugt$IP7XG z@Z+ieumEAw6_$x*aHR>6J8ZtXzTpRW*D?5RgvB=t2xB>{TA#-1LCw=wrn@AcCXttb z*}h1}l$fqgF)Zm7rkl?iTVc4`$ejx#*Tx-Dx72M{sV}J3J7*r>Lp*IFt_R^}8|=J< zukjmqm-{?3qtM+2$}t>a##ISe&?ue6V||MnmyPk1*xkjMXtHbh07pAN?QaW&jCoIH zm3q*he=n4DzNjxo`ofF?G0b3-;yTUF?{r-B)@hSWhcPzP{u!N0=3ENeG>EPTQiU@l z@lJ(Lk5#bC0(pY#N`OVWgD-m|98ATZF?*3|nuc;}&38hi8hS{ielXfIKLNiN5fBPPtK!a&VGck7wpENcBlve9+#y^wZvV>KBFhAOO zrEY3&^VmJ7O$5Ci+BM{ns&zORjW=FAa3WiFGMhqI3Dh=UT~1XDFolp(ohfN_N=(&N zw#wL$;LCwvZE_o02By1%*}n%zJ1>>*b)D4XqUm(pH7*Du8|W&j8v@ak{a&7E9TiTP zGR&VkH5V38O!23~f(92mYEEMlYwb+6G7Aa&@qgfQzsbKL&U|(C=IAX?vB~lj*5bwZ zY>~vQMP+2!OZdp~2^oog`yV9cc9oID{?Gfn7|CVV1MP!dnR!`G$@mJP^u~dAgWUsOcGB5-m z?uc%lqxOY?FjZUagjZ{=wVj%m$@){&w~2myOI|vDqxY7reRKDX9AIH_8JI8<@8O; zz>M|DB)1u~DMT}g@!|gd>HOUQzK!V-(e69pWmY5-N5KBh zk%dSth!kfVHKV7Wn)_pdqI%-@Pvy=sketqYxt3Kfkz#ND=(AnNV`jGzZiZblu?bVD zP&p>f+~Upg*{&{YxU3mVblz~#q+YMoExr68&tJ{+$Hm#015(Y27-#&#HF@ZbD75bm-Oy-IHadH>{;dr7B&$VIxkdJ)JtAk)mk?pLzY zy`3%9odjpE-o_Nbr2dL^(4SYF(cCVk!x}N=zi+h?E8BBsa>|dn2PeuNC;|490}=+Vnbsp zp0WxaHV%c&;^Pt;lL}knBjQ&W3COZtTocq2QCPqZX6oeo z;)7dU=cSWZ?(R{(j&(l%>EM)HZ7zec?q$!}%nrB!r-`6f7)r}HJ22eglR0(p3Mvbg z1?QFgA%c)OyS{G)pLbLNdKLRV{7X}JP}x*5dKCb*#Cj7czVSkIx_k&a=>*cdeoW0R zI_}-eM&!|83gyM9Igh%U`#inh7-Glzu@N~Dh@0*I>(Rf-iC}!Ipa1+ z1do?Hd(1m*;V3)C zv}kidc1j9lZ|p^xHcL9r?U7I8gbf+xv?|kB851&w(Q@vE54TjSu*wK?yww%v_vXO7 z+^c#3|Ad`z&l5MkQP9HqZB91xy~7S;JNh;xB&oyuBgr8PZ%?4MMbVSp#BsC1zn{E1 zK7GzP*jI~XrU0cXL`S4Fjq-p#vBh3cg%Ae`XD;F(c=BAU>H$!i>KEQ(uj4U?vNuT) zl8`y3yNqqA5+A6tI=LJ|VOT&G%}#)E?Hy~!f#rQz`tzMX-7Wlc3(((EklL`_-Jah4`i0NsZ&=aQ7^AD|nRRxO~`c9eQad2TpH? zWbdy;(icI=Zbmj-6H1XdNF^wBsN5rykePVBmJ5P_{F&^^^g>`}KOOd*a^vu%+2Fk| zXCJFfb`%(EbV3cC)~M`#W4;rsqhL}g)Z!@UN$H>c`2t?@;8)X61DN%5yA#9FHKSeV#$?g-G`d1RxzEf}^ONz)LspJHXP{Ts|Fzpk^Tvh_2o;PI zx%RCn20S-D(ts)rT;qejGk9lm)$-!HzJ}iuxZA)eAB@iJ-(CHyW0vA+u^GA;wRc0~ zY#s3yA5=tJt4tV$ss4~Hqyg0P?u(a7dz3Q5U#>;5gFr+L!_+Q)&u3iCr<~_=7Rh3U zq)hTNT&=`RaTq2}yD5hgge=FNBi6lX$(twKOl8;FQSmB4XcAZ5ruR5WzrQ;_^g1{R z!qBE+DIq?X>)n@k2ak5`&RnBCR#qtnh?y@sQAxOTW>E}CPFapPS!p9HOEdoHqkN5q z0_x9K|AQ(!vaPZN0E!fvC=XpCyMrQM+7;0C>&o+39e$Ww@gA(8>C!-&9@Kz>sH;sG z%X`RJWVis>86DV2>Afa+I-~LT1JAt!Wj+IP{rH8)$}ZdT*9U z{LIR&l?^LahwE%pj>ejsY;!_NffL`9`OC*~=-^z+V|#IMrd%e@QxUz_gI8p%pj*hK zGS4?*CM6)_o&3lnd}YP0S8`}8=2RYacidJzodhF9NM40e!Kz+0*?g6B+w?CPfAa`g z!a~?nXwf24I4)k`k!wTQ#)Nh4Yn1`hR!QG5f9FWv0No`K+z&jr3!`v6GPgQhL-~J_l%$wox zri)ol8?f7-y3qgB4QuTQOdtHUv%${TdnX+FsTlagoN^}S`F?tE{9_AOg9)5~Tlkg2 z;M}Gm6jUF!a3y5sgBq(b;HtZj$4iccY>6Q{+!-$2z3un<440nXz5UtkKmPbWJ{xd{ z`7Qs%sipbg`Ecpe+r!=A(r5L@pYr)XMhBqU7i`H;UAp{qvde3AW|()N2Ba_e^$|=% z3_sXja|8C-2^8X7q5$yOBmf}c&h6ocgCX=A|FEiiZJ0z4cgx_^KXBNuiqIZ(wlJWf zr7s}RI1>7T%Wzc@Z%DRU(Bi@I?%@R|VLoHr#YQzYjYe%+=p!@WedFD#%|#3jIM+S2b- zhK_a!oDadT@=$iiukqJ|;6p3D-IO~hy-EfbGD_X3^|ld@Av`H%LwP$Dpzu0Yz7qAy zp{RKm-_Z%JwLTaV zu9n(6VZeIC24s!rzshJ*cZ@0Ik+}9!n8w+D6`#5qC#pR-j!1W|qqRt|ErvEGrluoS zxt7gbTEi7y;$!qq%%QEPVFe)KW(faKlWOR~SK^aTgqAo-68o_rIu>iWIT@JCVq|g| zPm8@P74BbGzJD-Xh5Of?BT^f3r}wIG)`2s;mb%mW^vWt+>#J6O5;@{c`rkAa?s{K$ zRXF>)h|QRF9}EpYtyMVt+*P<5Cs$G7>{AKyTt#0N$10=s@l<`&W~$AT!dUgFqDmX5 zX00v*CAPo6zPLOcMyrweBAON+LD+iidBaSFY)YyXjFzngJHl!4-&6{# zU2a`xWZ|k5V>Ra!2*n>xX&j%j{}?UzB%8edNb;+1h%X28Hpnl>C&wd8=R*U$HJE=& z{T`|TGzouG#uix!$nBG}ZMw)Fc&uE208D@4&oN+e8#lECN-B*t7N>GeEe^|Ud9VSi zSRt|Po#$i3&ADWOckbO2q-*s*#nVqFC+#eJFW!`li#2>;rt&<(js<&1^Q7_|_|jq!i_)1Sg= zzW9fd(@Je3sV6RSrcqrGwj~N)iKeSHoyc^DwBj7>eMAgtA9*UMQ@dp5CP;c$_-JW5 zt&0vRRb6d(OZ1T0l*BHMub*5{>YSIdQTdDo#q}%n+od@k-gmXV`z{4V^OfYd#AlyO0wmZ*6>DOR#F)g3e2f#^l2ELgPqL5P3AD=t&RwJ zDF+xh&GXm;h3#lms|b+HE_odz`bDq&5uNdu(Bt_3K)mKOq=nmzEwJb-DFdU-*yUDC z+7dfkxxGEGmA1mr6|qTC2$V1WuZL%os;6GYQ;0OlFi5ISFPybRo^4Ae^p=91SL?f- znK-L=a?9h^f@}30S(MYrs=lY>YW-#&A$ikN!JR|$B7b1ZC^4kuLYl**%i+z%xjqRj zs*Ge%a}Ouat;TCw%-ATcfo+S(m!NdT>&~x}?0Dtbwg&YIg%n*N%l#;F{Av+(1++{i z0!~3t2jHGuys2}LuA~(^qQLe6sWn`t;;Z3loxkV@Cxi};Z+*En{xa5N3PM>)g&AN2 z!@3V;RlF11j%`&ftiZC0Cq9OFLUS3H^<@QKtUH4u?b@G5h3VF-+frxG^3$xD0oqDVAp_6#_pL#53j+PpcYSnfIg$}7p5ymR|b)g z-;tFyo3?{KiMMDDa;S6ejuw&$Vlq^Xls`sM(q2zY3Q|=O;qVZBnnR{p4#ycut^rnp zjAZb010)3*+@xy~dA;iNIkxMh@7&SEI+EAPY6=16gqzbOCY&1ecdC#tELa>EVQ=Kt zJ`mC`oH|2kDI3((hoG!np$j$eJUn`vCoC+hsQG5f5t+`x7R#=g^Bg2rPZrIihnuSp zsme!D{o6%HN&VIHY}G3@`aO$=e~rgG!Q=EtT&+9T=S=^2z=?j<^VdwD+Ia`n zOiK{En|zi-^knlF{%%#3gvCRQIWhUyPxr$ zNAZWp^Wz#|ek)Kb#EIO4ky#>!E@^yY2NIIK*#L%)CwG`H#1RtrlD=<~KLQ&h*`BDXg*ZBx3EGeQY(nEQkP2w!Wsf5QyYLAbkmU zm+9LF1dm|Vw(9XE(3${?tB6Z0NzofRM%-!a<;R-)4nbZdO4Q`s8eCmjdRxHOaNMY@ z2Mms@=n52MM$U9ylbgKX#N>!X-8x297`ww0d2j_K+by)}Mj zaS=4^<}SRy8<;s}w@S(^NNukPcM#<*=M?RocC~FLzND?*CFp9SK`LgqsVPftoUCKl z73wYJEsIMk2M_`OPuh@W%3z}GuHSGEmhpb=ZD(pdp?JgvcBw8)Hn(7-V<@B`M>924 z`jxVI=T51*7hTFkM8iHB{!o9FtTzm-k`H;GHb`|d@Y!qq}L zr9>duWtJ<#$gUFG?j8()UZ!(fqOe?Pcz{U3{(iInoD)0BMZen65Je}0J;(Yr9r-W? zq@6kKHz_q?K6~-Cl0bmMHhy(-frFmx8>@jo1$=g@e`F`m1CK8M>*r*_C2~{T)~`b; zYtr*3ebnvGUCp!Dpg7#bWV#AbOlJQ1{x4GDFsO+dlr+;@(-qi8DUcDS6p*$DHRC!q zbA)%ahi9WrOi_nn*NIbA5C7EG?G(21zIys8S@%RNLl?g7yn+#d92hX1MrYPGtXXX0?$^(-PBuKrYuf9i z`%=vl`Twuhud-S&R25N5)61h27;|lsxFho!F2`vbr?yJ(^(+Sq5PDx`)HSlEl?q((mD!Z#dR=9u{=2cMCSB~l+XUn0N!e(>5u2K> zU)vu0HI?i3)@=#6;`Ee)bbSsyjYOtQF4XVeW`Z~sB;r#e?Vo0POD88=pJr=)n~LK# z=W1p~dP*^fq^!?>@yi$Yep&uy`Q9)0`2W9reD9YpmgTJfWb4hsyZ0l~OfFk@DH0?v z?@)t*KVP1p?l4G9r};gby)>VR!(3{yM#5R6M#Z$O9ubQ4e0ro?cq^opIIrNXX3r7Dhkd_ifx^O z1nFwG$oPi3O8m;>J|?0GORecnMcpTgJBBMzEMjfmVijiRRr8n}Jf>t3=aw=d-ASm8*@wc(HQrQ9o7}Kssa|}4n;~ST(1)jiB z`0Sd>5|B_*i`Cbo2FvlDr31ECGSmP;Hmm0>SaEr`??7Xt)mFQFxOR;8&E2w&N~;6w zG%(G26g&NHbMrCFZg=Wh3dG;w2`^V{K}lQdL=#|9TnnbSf-x(*8jK2uoq{sH(w({@ zmBSoN<3{hf?5nsJe$8ls9}JjC`_KGVGL~Lb7dDGeE1?Paxc(w`6QMj67j^F+OEshz zAq&4uv0thZ8u?pA9FnLwwHeQ;u&B9E%R(0$@ws|=8r|Bpc8(6%J>#KlcthnzVl5TW zc6UzC3BPSu1PRT%^}Dzk#l)N4ZMrnrPu^n z5ACe^J{Qc|fa|tfssdo1b^3+HxpkEhweDb`8d!hM6eP`EfyqBSM#NWb(uyf~%A9{y zC`~N*5GkH4O{WHGXEqJv^VZ@pMn8>2<8~*un0`J2IL zZKA&s0y8Dk?!}BW;QuBlC5B$3RJ2bv&+CH|t~$pf>lf7Prl#rC-|(Q&r?OI2YjHvI z43F@T8?U?LE|?I3;JmW@y}?8dSkhXOPXOEyVR>Pf2ejZBE$3YVC9&39Pwa;ltNnX# zfRHeS)si=;>ecK&%o4K=uw@>cy!0#6kajYGPcL*{i8IzWT%0T|9iC9nXznszJK#o# zllQJS!zF#}T`npg4<7ye_Gtf5&WqEiTz2#4qeHM!ev;i>|IA>1R8FX0+0EzV3{%c) zUl)~@E?%DCfZadc#u3XwF>d9H3I~2zxNdfFX(OFF2N&Ci+_AChLzsv$G%@`Ejb5A5*~+gZUygn z&N1){c_6r*?V>Hm`1f zv8K1SIq&2)dU6BNO~beY0dW#6o=;$YVt#aDB=)hO&S`QnoBhsNm_88$C}%Eu*S#HL zuows-KWq~zb=b+a>ayEK47IHVF;3b*JiW7N@Wk_`GxaJo#r(CondlXE?XFJ8@s$p* z#-^GzZ)X+YAkTW=*S%gF97{ozHQm&#+q#>=Gc;=Rm3H*C2H)g!9ZqPvxaz>t=h&Cc zhu0qaez%9K4vi>n^T}QUn?Q7^sO+&dGEdJg0^>uv!+hoP0Iu~xo0z-1aA%HkW;i}* zdT;K@<~O51lVuNE(cZoSMVy#EHlKRgP09h42t~w4L7P1tEjuN=Iyl_ZI^gr>@W-xx zCWDS&gog|0Wul+JNsdevX!RPT^>K|MLBV`GmmMVHTO^$J1A= zTj95tf(lnLNf`s$k*tmaZJKca?qt{7>cS7M=IXRm?FKiUz7qlWMHBPMHiZIH&AJom z9axHc?3h|Pn4+&F;l&F3gxbJ{?l4n%kg&AkP_H2A=lfj1_mah{7Enz|1t z)7xG;!_L%4%SzWfw*7AN%?^4;@#z{Wr_H%KNU{B4I*+MZ9hK@G>?Cz0Rx5823_5CQ zUux=F1Oh*ekY4o){F)*_p{7QCgBkWVHsmztkfMz!XKM4-;iM~l&@jyo;1ils{}ydq znnq<=6Sl}Ky7Ip}l;9jK-oZtMW{x&}{pkDTqb)XMe3t!&%KpgeCDY#Pdlnhd9iWyo zLT8NC+H=j~_VS>%soQKLFW8b33--{lOs-&+XpxMu=s>ef6q&YTj!;=a7PC%ji$o$T zZT&|27EGgt%@V%)y0PgEpE?62an#7^rZPw^QTY@E_G0LIDtCiHuLW+NfF#w}9w``@ zYC|2VVy?Qb4a9DH?%)~R ztyRJCKn)RKraZam^_mvNvkm$c94V2eX(deYuSzjOdloQTn)|HIq@*%PO;AJ zF0J&Ek6Vw*KJX6;q^~r_k*XQ5tWN&Th0Qxi48yDhnEG1sJToxnpa*8rM z>{ZDb;D)WD5&3+~V_VIId%N^W0vpyyb$~&KEUZby(G}dR-QLBG$NX><5pHjuyrZ!@ z%JUeT9CxL*K~tQ|vm@LA<~N142ie3GUHT`J;fb8ZSS%FTq^!rbUf)+v&byDA0&mlu z&#Z-nwhzb5#l(s_s$i?ktZmp8rPHj$9LvA0Iv!_uBJsb=6{n;(nX9J0rLo$viaFHw z#h2nGvrXGCor$=Y+8otJ6O&NslA&}{b%z>$@qFj`jxnX&Dx+mRa!aK%zq+UGj9b?n zV`qM9hx503yKKb6@k#pg`hgtm+?#toH`u*5w>Q@VaMb$*dDN3uEdIF|?XLg5XMTVw z_z96rDZR#t*bl;TH2q>xC~D(hPZ&H}q~Bq3HMmrI=k!3Nal)#w3FVD(<`658NL>Dh z!}HH)4E4ojgZLN)!#bY?r6f6v+J8M@H>*do6gJc@zijJL7rmwhcXo?Z^BYXLy z!QhL%w>x_$i_0HPqbRh_(9rR2sjb4fxU+gWT?}VztQg$|2XkMT%)4Xb+MjoA;Cvdd z7nda@9O*xgmi=uFhJR{sTmyF6TFmKtN5%|# z!8Y#YZCZ8lH5VfJqc6}lm{5C@Xkw#f>%w18*$~#k7G^sC?~Vl1+M0X5HFwE~J(5=5 zo+*G}dz<-Y@uLpib^$Pcp&52K!^EUrN0~CBjGX;M@bi7HFjqux63vSzhkL^BM}hDb zGxAQn#mvz(KX1%m6NA8aeLk?=S;P4ZuRN%lPmJ}&j%jXR{Jh9+-f1r))TwW@yBjVK z&z(-C87S&38Qg3%GH6E~<`rR~7^i5OVSO@awE)1E^2I=*s@l?_OZ@lkJ@s+^wmEDFm4u8V97A|0lYO z*w}A`VG~7XW0I*73a3Qd6}`}gK4l-mp~nf?bFpyj zW4YZA&6IymX-@)R+u~aKObh&h;5aW41XBUKHh8|26<{BLrY<9sYT|(C->aZVE~xY_ zSXxF<(ag1~#o{DV8~_)FGr&*|MNZkQ>U~qGL}ZW%lrlabL!u+UFdPT}uyb_!`9S`G z#`y4r487#VbY+Gc7VvvDj55b(w!1s*a}C?C*nJ?AYPL+3#2A|Y0U^B6w z+w*Q;^y;4Y;(10qRGquzP7mBia^sIrcksVG9-nQI7E1^ru9(}za8aV!&R{Ih-@cM& zUy?FmKa?C`QeLTdT;yfR6yAU|Xp->`j!CcJP@r;x@{*CYbMNY{mGFN_LtxY>wo@?%PZwr; zXg7!`U)u_5nsH+#QPf-9kvXQ@mpf;B9NV%xyVTmO0q)0BR;;4tfK*VRnJs?AEehvn zoLC#U3v?xZcJVb146Z@JXD`6{NAFA-F?>ra`NLr2EvDv?rS~0Qj8#>K5$sj`C-0MT zZ!+gj{7%)*TaN=reD!DU_iJ|%{@m9m2i#p}uNLjU-IP*pa65a68}sdajuQ@=(lfT2 zdpB-zc^d!o3F)ucd#u|$cz7V}EiJ8nzqcjj03JC|~{AFAE=W{4iA7Ys4KNV6| zEGMX35_-;YQ|OCCr@aGK{qSuUMRBLz(qI)II9UzUI|yf1=xUu~F7z<@EHBwrZrK5}Xr*i?r9_0tFf#pqoDS zf8O0cRoiZVe^2c0#`JzI1m9m@+g!W9^59xHUiX_(oD-=gFdR1m>k&d}wu2QD2ft{j zdESx(;aZ`?w@K8TpJZRYjOyb@Cn$=D`Mv*2JiE)KVG7Q{k~LhH&8)9KTE7;Ci)95N zpX_?}#V*pxg$X>w&RNSLJe|6q5NhJGKFT~&&K$%S5=kjKI9{;$O(9zKFctX>NajMthxt zj>3hZ(=+XV-B@{hu>V7xIQg}3xAyRxN7usK*Zbrx9kN^Z_Mcz81Sgn0 z|1W!Q-q6;Ow2%IuPjSL!M)Cp}J1gXJnkxEN_tGvp1p|ARz{EdqCL znY@Z~XXK_@L}VKNWD${;ve&*N%WL26vl2*MzxmV~kc}#PZH!FYHzt`C(B*6ZD5uEY zlVqiN0!aGH-pb^8??M)MeK~ygbh{rd^Z=e+K7x=7EO{s|a;+w{5z|gqS!R-o(x?1u zEn>MKBLTxVAaYPf)*GE$m7K&7Et?7Gy1@!KkEjPu#^Br!5KD>RxGVXZ5dS7Yt#=g*R9YNATw$mOg)hDmnAZasFd$HeYuNS>I}ZTa7%W(#Zn628^KfpeU+*yml(uA94)@Ub%Io(C@K;J)&m45J!G~(@4+|$VU?Bykth)< zhEkDfhjohrFL99alnueM0csPo3JfUcz5Sn|{{k1+ncc}Tjj{A(G&CI@RC7U13nSa= z_p77x^RqD$h`dBp)WzN+w7n%7)m<$7rdyPmQmC zu=Hf>>B6lAB_3oeH*?A23CtB&_1rel!7TZ}ti7zJA%2dj+~EHif9b2V<)iQj~0g3m3avZLmk2Y1-60upk&AT zZ&&NZ;W-(+fp`TGny!=L-9N>#0P(A< zy{Gn+R>SOUx>lQ0Q8g+NRmI!@D**g6aLrIC)iVTD?pLEIh5OvnNtRfS_r?UDLgcvS1Ux1?v9WYegZpuQVfa@V}3G z1hmk7VrG4)HwRRLdSspS4``GX%t(L$g^*>#T?(v7XNQKcAy(~m?=7?ZR6}tX^o|j} zhrl)X0#1j)FEysk{}p0sr5D7rji?-srnnwwMU)>WFXwN`t@%F z4E}=spEJL30+%X^<5E*pec?Zh@O~q`6`Lb+-kuJJXYv$D=IsFfCmuewySujWba!{L zv$VLl1aHv65Z;&z-V@q8@T2$r{i9*k*}@DS^^cE-Rrl3kJb;FNWkvG5&i78oxN{wh zbgO@Suyg--@C2d1XXo+T$_gkAPk7qr6K(CU2%pq?{R1?!=#4B^b~8aJne=-!IKU}^ zOLVIh6r9U-Zpnm~%AdNnN!;=0&@n-E0&)y>7^av4PSf_}U?Bk>id|V+U1<_H)_;{@tEwfuFj_W?q9G4sOsK?4Y$zc@xbgU?Zzwd;C9;Pn8c+ncS6 z9n(jH(xkp@++P<0f~$K?)KlG)4QO1|8UO-_6jLHY?U?zkaZdZ>jJGi%ilehM1x&U8P-!0qd+GOZk{A4y z$!_&07%RdKdIx0Ve3Jofm4QkolYw$DM9gjoYe1ynnET@5Y5#l)KluIb;NVYReD=ky z&uZ<=8`pK_M9h~wiT&||yiquF!K|Fh$P5K2{`y+V!?bkOJTh=7;q$OgXmbe<^NN9& zNy!NXT3gWkcnw|E5ul`IV~PBfu-JJI2g@&{1({IH*hS5KB-nh@PuVRCV`lfU7b1bB zN;Td9sZH-wu`Wt!VwZ+x`$zxeNG{I@^GeK3eL@^dw0vsk3Mzv$kW4b|^xn@c;d z{xGf<_7TlVd2{oBI@QfP)zU%#)e`YOmlF@Rw|;N`sOqZnj??MmBX0Kqh<^YR{{Srh z!M|4|lkfPbY5Itf4*QGuH6|oD#&NvU^FvS!+_6|!Xak>u2|J$g7PN~sj4wIBUc#<% z^Pm3r*9<+$bg=*dG|HCt8@tB^Oud8qaknja)~gmq$vX=}b=de9Mr6I=1k2M9(l~eH^YgdW0%!0WOy@V?QuwVuWmpGWnjCzYWRv0tJCdAc7m)*%)n;uK+Y*h5-u z$cX9wl|Y@L!bL}2Hde}y!j`%~BDgbgUMXc+!#I!ga@XQByPbDCqq{q&^S`c3{Y<`EGaj*}k9Aq?h2Y_q~ziRT?u>%1Uq#h1uivAyC9(8@|n zUsl`Lic?kLg@f3IVRl=n$m~%$93SaMj0TZzRMHqCPpjjdSgcue4{L7#5NReXe47OmLfLUALUcbM+`#-mf%KfxHm8Cp2&z3-bm_iFVgw zdAaf1lf5CV9L_d^^wiN~I=Vq7{~~kbO}#df4?ASzTXHG@msQ0NO5I9IZEZirLB*^D z%c9h0Nh!AV_~K-*kDP(Y2cpc1#|lV2J+sq7e`xPCZ!%f zd-%{_^xvk|JNwEj354Rf1p|R!Vq!|0;B_>6S zELNibhu-l8Zf#0GESBPbee*$HKnt^2IRTq{f5%ywtTc1c=sY|TWf8@Pjnn1+z&Ws9P6nqix$V}O z!cDC@C%j=UlIv&oT-SN>;tPABi#B=jRe166Ve)wShRoF*7gPFpSs%;dNuQ%*40sOo zoj(0ipT0|VTdeuJ$-gdpFK~XSj~VVq5psKQw+BOGCaLigBOdr;VC#l(&K>;goQev@vlBwzP^kRSD*6MXOBQu*faPD_ZKhU;uny>vh+z>l1{(E7wId& z^%<(&l+xi5EX<~EbgQI~Tj}F`aB%&^8p*4h*S{oG$*A@+51pjjV27Cu!#G39)9hBTusS zK5K>V^ICg+lEWuYvi7pokiBV`7Pglx8O&X+hlXitg}6RRG9eiT>Qj`?kn#a=(FAhi zMk#9XNLH$_n`Ll`o5F9FzvgYKMwHUjzlg8tFt~ZW7eB*zvhm-PNsy*6{c(ud)U`9U z6_PYl4GXRBaf0f$-AvHh2;`+Ku?`5;8ARI!m3chzxi)P z__wfr-;eO)kc(-r?|aMjjZYut_)oXKe>q3EMN#LyI6{J$d|{Cd<^&4P*jl>2fh?zs zHg8C|PKHiAGMTp~S|YTecX52KC)CG5#teoV73f@ss=ml2)FhV1lEBgb&FGWjGp~^k z)Tgb4_Hflt*D-NGQHMY0#hg`rJ2*#5f}a@}AQrqOn&K>qa$I%CNN^yAHJGt1O(eoa zBw9-0g_X}kQ|Pq(g=V|dP#%n!hz%2Ml(8*`j4;5yB-YZbH2Pv<3XT&Y9!ONgj78`e zo`?}cYHVy-kV=S`QoE<%1I`W|AFfa;t=#8GHSsP?gW!UJLUPIB7@4iI1~9FTyk8N5 zdQJ~)ZH)8%(y3(rn0Z_*6spTNGsw>}z3(xzAAVBhY^II@Gi~PJ5&`zUc~*q13anx^ z)TYI}4h&n`JpFd_kyY_^mCTdRtd7>qw8?w1pN0i@Bbh?$LoKwSghV;SiSlsVyqOG+ zw{Iom37pM|=Xn0@TToyhgf91X`MmRSAM~6*MB=<5u0pCqX_uFkSUa<+U0CBjFX7U<%ipMR8c`lwQshEPLc4|Td zZje-kXL6lM1-HbGU4IW`Bdu+%8dA+N|4aRO{gI#{@AU0k*xgwY*g<@xxoX11oYfn_ zOw}Kv`c^Y|A%kZPK=3-4+e2Gn-t3xI2HcfALp?vEK62CmTB74rjO^+^IUk;pNefYi z)`U15bvAiY0$0Q!lcqW<Qg zhl3elzi5uu2vccrHrI_LLjc3&sQi(B2+6$Dnj*hMrxy>!66#J@iI>ZR4)|0i1fe1Z zIRi}Xwo;oP#+V)sMsQ8Zo{`~-4Z!qku#)sH)|37Hv~I1Aw&Y3uy*fM^T>>eu&6eW*j9~XquKoV{2504$3Mb{S;5vesTH;q zfEUg;*O|kOmkwSq#j{P`gxM*gx7dJx>V(EONtB2e2%IE+>EC6LxQdUyp6*=7 zym$;Ya)iq`kfCseG~A7eVIzkZZ*7Mts#&Xfu82}8f{_1lfgE$pbr#}b59B%(doclE z z^U_Wu$Mo6FP~12`Ihe%wP~10xOZhNb2FZ^RnQ(-2Nh{UdqIUC~J3!iO`n_#@-McFo z+KX$ya9nd&uFn5@GQ-Gz%u^Tc`8;MHeA8?=wCsFh$*K4G%=KB-q zTLa2qRuU%+1`ybxap0~V#!pO|-bTcycPI;c=6pyh(t8Iipc}-&Ys+#u?g}nv zZN~n*wH7aSHG<)(k|#rCbcYOt`yc$8=XBQmJL%GS#iZ4e_GOEv8K~B+*LzG_>YB6> zxec5c+|TCLo#FHJ#PATLh+Ql^#nb)^LrYtR-U7XG z64}&6kVd4qh?vf*TOsUFRl%^aU1r=!`Tc}yLtH)}^*)s=@f=a<2HGIHBwL}q#f+Pb z6aA)6MEboouul|J7U}JqqP8Hp~np#J^ua{4?>$ zW1T!N4`yhX9}r<%vQ(o$g&h#?$rcimvQf^Rha%WklugH2RxFJiQ5q_3zF=Ol?4 zgr?lQs!_*u?y?Rax7Jbef%H_?(iiRZX3&QnPy9Q(mQlk9@JW*t_Bta9Rrs2TXM+Cd z;Gn(zqdpGFQDKo*ykQ)UyMPRY$YnVhC)!#K95zF;6A5q^p{IUsVqQ%XL8{5Ll!;8T z{aKcsiR5rtuDCtmHP2f^3{tDDrh+B0bWy0Dpxpkd8)QSqu zy!c8R#F_8mSWdh{eNbBmb`9#g!ZPp$VwjMcKNb^4u__9rjBzH6*7I~Eb&&UYEV z$eXi}VZ^C6qcyQZ>io5Ea}|5k=&NSSOc2tIWnx{8(rv7pn@Al(Av*0vSA;;R*rgW6 z@ts{jJrjgB57M{&!jzhJK@$12U=kn%wyxLzAyXhv#6o{qatBOfX9BNozma{JNIYp* zwtAP|nY}-^mtSUg_PUqcp;=A#m4p`{2D541u&93$*0HeAOe8GYypOpO#R<`!Sj0uU zcLy#oFaq2$Q6U3+;W>Vv@_D*R`evhwLu*~4TKs?}= zcp^TVTmyZ~3#-t#8stbwy97lZH$uZkI?~Z@O{r?wot3q5+|2QFO8sE@%8Tb|3on{= zB2(WE1M~jyBvmS9M8Iy3AHo3$M+~O^6T!nk~diBS7 zg||cjfkW7+Y=B{9%ck%rS2(O9b_+Xo$Jq;#z4ef;aFgdlb1ZL64Lyk`#m+0^-eFDZ z0;dXm4)iuWPdq9we&Lgg=e>o))rAK)7QTM*?z3OT$)Y=>&^c2dh>u`{tN3h)yK*7= zcIanOMp`fvMO-2uH0c6`^}+<5Y((U3=onfPIX9(YK+;DJ1}4!Er)>pKYpuk3S|Y_7 zvBXaa-yyP;onxxKmtr_BZf3AGwNrxxHbC*jDXe#~C1l-Dv!2p*)@KvSZmncR%Aw`) zA_TgrkW!|p*$m%SlqO0P434}%;XD@Bsn4@Sy%<_~;GVW7HNo#{sCd?TCd8%RhrieuG z!HWVBjc^w;%E@463r|P2u~yx#zPzz~qfuvsW`%TYBP9QzNSE{slZ`B`PKP;3cEy*n z%RD4ysRGYcAKA1Tj5?D#Dw@a^-0w|WoV{#OBNoC?qHB*rp>iu~&Ow?E&udhOSzhDx z0EFkvInf-*CGfy7u_fVc|1SRT#9KTUQhD(5Hi>>n@cRPmv5q$mDq2fJ1OL;Hxj@{5 zM&&Bvip{wTHgRIYW+qA+eE$XKVNXi!?Q_+X#Nhqs>cBIb+-FQ6$S4ur2#tSm&-S|- zLHW!1&6E@e%Vkh)93u4>J_;M^~ z;m$jb_}5lXqAzhoT~kH-Hwe0Mh!~W$=Bw=gA53TZY=s5-@6C1~B?L&pcYbHKgWkwE zOA)cgb}~NPD2{xUizAujh4vf8|Hg*Cp4?En*<}h0*+x@?H*ZXCur967BAnk`E?P~v zBH4LO#LQV&iJoj!CA%(0Rku1(2o07}k0lQVsKG17?gyI~t~w7 zio6A@PxU;}7dy0pbaG6X;)z$uSrjWh*HU(_UUaXy=>E~D`&F_PTf>L#rEv^B;@*m% zHW#1ELL#l~sIBa1uGa2(TiNq^*`=1UOG#04<1`}p===mZT9M7^{H^87>URG4f4%7} z9!nUZ$5i{=;S?gwPMsSar0@L(?s6Of?L6Clu<%tHZKYyL8|8#}lljwxGw>a!zq^9;jOZov70OFJL^AGZW}2)&9!87 zxD2C&Msg9#W6!1 zzKX#Glwm$atc4W=4k?<}B#{787Oi5jBe1lyQW~aGya_sgq~kho(N?rX8@g&|e z7d8#xKuE3n7PiRE(LsOosE5qX zi_^87aFO{$up)!@Svh4;B1W3Ch2oinmUQQEl8?tYJx<=#Ss**rTPNWyInU_nN(z#$;E-!`^{$M_=pn9mwSQp9leoI0= zX~}b5j&y@#EGk!?lB&BZ<{4qwaN1eYQFNAm+8JM4>O_CCBy7Org}dG7wCVryd>Q}B z*K1e0JB#)WZ~N;no?lydao3;h?4|A8WPEey-A{AfyLY%pPW2r8^8BZr8w)#cmJeAR z#~ZF)xq595XEp-y%i(xJ{4VWCPJi?1ujx}c!p^79)2EWLhfiOmPbGa1o?cHM${BV% zTuC2(ErVM6iB|1=xSCA}<;7NAymOq=qF%gGG%fu!pLV0UhS1oeKgHq_G=xb7ztp>U z8fJEGz`f!{Q4Kyzr6m{^{=lZ^&Zmd zA?Fp7ZsgU4DU5L_QkozxVu7}^_W|B5#%mT7Dom$%c7h;_;t?-=C?3h)-al~cXi`;` z<*cMVa`R8^X$Wt&%(0M5WB77>ra@&o2Sw`E#;r1mBRGZg$wgA4U$!;`8qDJ4cOORL z*l*gPd@}Y@?&N5D>2rYE zR$K$w@cV|sophtq5R2MO7Z30=JMgW$T~2H$qgzzR)Xw97DrKllWpm# znFPH&Rc=-Lz4LBo0hLaAZ@L%`9>XctW%~?2qNP+l=&!3)Imw6@izx9D_hene>&3qh z2dCY+g}J6N639jG>9_|uxCzMO_?;iAVr1(+{+av9bb%I%&WBmU6N9=iTD|kbFk^%y zf|Czeab|Bg^oAFd)x#9nMAF5q7(-7C`bDlAxRe$bVT45>E?l_4fc1{p1Nfj9kep}Y z%-4@3mZKs+!Kl*V#OW0Q(STyXEAWt^%PLZjtTAZ=MluIZ5g-d*5QA|*lG8PqngY`%CIveHp{gl4M4+LT%&f#*x`G$(K;Vj~ zj~4Ev4P&Of1p(Ah%z|RwcxLV?PjDP`oZKO=yBr9icnl6ze@Nd4B?T=T$XK@`qki!9 z76=0`PI+y@t7YM!_4IW*0GB``Z@PamV$SrZ6iw5;QH9lq5*liuQBpZwdyLXV%8WnV z_y$`P$UD^GZ%B;=mN`c7qL;e@rO&Oj`dq6%pC7!40eiLx%pg>@#!<)Cb`cy% z7q3E6v!lb}f0`GJCyRy^`Oz0ZmVQCuNI_b{f}*v7VlZC9Fd25#Yat$}t>0um>W!p( zUmy-I#=mLsDR;WqKdR0UJX&m&vAX%>q5#>@YqICYim~6xfu6Mu*(Ts_;PHYnKNDnF z$L0sK0sa*WfrwYYb-hn)gT4g_dC^2zA4?M%=%TZg#dF49zfKM|XkBG96%BHg1DE#J z4o$OY=QCnp7)NW~I=nw0OlsgN+L0m%#+x=EnsB&WbO;t}?m@Y>j0bV~=CYqpt5(k6 zG5tydE|htTwW($Cg*||U>eJP*(yT_KmDP?FfL@B&!`TV$izA#kM z&L9vd*oqtoo=cKOJCZtL(UaHQ%JLSaIsr_NEjx?Mi>m6w3Pu5jbJwqfi~w;g->U@R zxR2+U4+MswrzVn{MvjQX7mDuKrqBjeu?pmRUbr-NPkSeQTr_uljN4I>J{vpIU;nzh zwY~auyVUi9XQQodN@C&%xUsTywHp6CIAhEJGIrqdnLaOw@TuY7!cQah3OA7cx%==#V&wEl6ygaa;67GZx@YWd5eSP@9)#l9+v z72$DK?B=baSP|al#Y)(UI43V=H)wDeGK9ka=*5!Q5-C=A7p>TGqJitQ6;4AhS2nlY zJijGImW%21=E|`yH%|mq_a9atZmcC&WJ1T zUe{i7|MbUewqUCoN4GhsVit$ZlkZobR?m>tCtUshpMCGx6I>1}!vXQ@rPJF3GN_O_E`^hGA2wyLI7StYnNmXd89;lAKN}B zURuVcS{9argB2*(X<|uW_g4_R0zq%8h(DO(LgCd0#s$ji*RzfQzd5 zx$5m%LS3A3_+<@XaRPpER0e=5zM{HC48sQCCHXxEok*XC;|oDRoN5>beB?kUh07A@ zDvO6giTQrVK}m%s4lrvo{#dw!nF?K}_Kz5c3g5R5H36)_{T;v&qwe{TgGg&ci6b^m zzdBHz7Mln-;IM`}%U^%>*~0S8g`1yk-?*_N|Np;Jb9$n>z~v2Y4=*$4d~k>r#e539 z0Td^%5h5U|GcWd(1b{1|_tR)v!I`7o-S1Z)ZsTULM^A8B^V6N~&XsR)4yn4fbN9}b zyK@L+2ljjTS|e)e>|hQSzOJn^nc8wpqP`21pT2djl+ zuoc3^-Hrtg8SF&!Rp3C9BoC9cJR(igE*w#$*7bmtd6cK}>-scKmNu9iXmyAajg$}< zd+QQ}A=R(BNX+|9pUK3dRoq{Y)?q&|B0(IBeIxeb0XTyIpknqVTL1~j5LcgUREX}N zPEvLMy7_QZmzJy$>lngp=-8_Xhmn~1@Ja_%z==F^y)kTtbV~$7!7QKxmAHvCR8BxZ z;_?ACXBGL|Wx6ZeB#B(cNau*1d0%h^ z=id;Z9dU0xVFEQtl=qTJ0$-1Y<@LE7m4TJW6kEuCgp;=5kxC>7QR+d4$TJ@NguVQ& zUPUgKr(=bIY=RKcA{O|bkLxtgk97L;T>A5&h1KJixVKv}8&(wTR#qOZ;er+Yy7m1k z>;vKZ&CkD}=n#H?zI-z@ZW_cM?k==v&8gJK7&82&fD0s=K~YK%vfu-E;(o$2?foqm zpuX+DgfA5=InXy)(@Ww04VJQ^?T#w2`PVYkv`Ib(s@*~s2wcj|pWd6XLM*Rg2Ue-aFS3HlO zfSd3-js%@>xX90h@nV5yZtTc0;kYMpfl1PZ7`Ik-LjE{-S)IQ<%NhKl+#PLvHo(C7 zsns7I^#;{AEleK*r`V_KpwnU;ph#M>Wk{yA zi$wW}a$`#_Z_osqHmhkN63p)*(q~*-r`S7y_={87h~{v`Vk_cxPqJpxHQ@FKG$o01 zI1_bt3G0RO0AZPXT>o;-28dPUOkXuMu4v6el2eqs7FqhYTbYbhdl%*lL}K!7m;@?RrshspF^MdlOXaY4@!I=!rUd+Y7V;qdgW$N{~VeQYvU8IMj|?t|Xm z0EWCL@D7~r4-l|^`%s?T!|4guSwz=&to#E=(A=#KVK9U0b@p~NczJ}B+b}=y>BG(UP!N!( z5{6XB4p34qMsPdwBmyB``s5QT$?A)=5$)UuVj%RLp5xmovU(zB_!C$ItJe2BYe>>R z8k`}o+s-z;CGqDsvse7f$?@##UAmzLIa#2JXdi zjmIU*OVKr^Z4()4woatdrfA8RsDP2+Al2#lWvaY}&uwOeDUt1bdvSOOqrrjxoYtFF z(m$8&%2w^Addlj|+#xsxY|{ti82meJR9>9adC4lgj()}}O8YzdXRAMTX081Dt?0Eu z?|Ar9o0v9y>j>-mCGBgMsk?`NU4Ft)5n^XJ^>TW&h^IE!?%K!Q)a$hz5t)|9kj-d<;(y?fcMP_jNf1|1hrL zuzDw`1jh-J>!0E106jveZHt%pba+QDj%;(&SFbF-(1v&-p=R1Gyeg*$y!GJz!woe1 zY5+?mnW5KyHil$_Fd~s`C?U?H3y6}8!%Ifh?VP;D3z(cc%ZoP{wN6A{5%bSg5iD76 z;ZE=1pv$UTy#1taq}i1a$F$h!LhN|j>%HE^`4Mn5t4y_IKIjCzx)WNs6*Uu!yHMHB zW7p4f(HkcNi9k2u8elJZp1p1E#{r*idXAaeE^u z$DPR}mysLr^+xvEZDX&9g9?P)GCi>XM<0LbJk*VePcKf5HS5WWf|(NVlAr~Jf#qZF z2b8C)3M^k)%;NO5Z2RIWyP=@qT#Z-L4SWAboLg=hR^9W*fuo4 zQ@HB5qhOcdJqV)cS@qD0_zTi-w(3X5ofuaG$75&`4%#!>t7?s}`TpHKga-4-{rP?F zevxx^ul(vuzIoA+p%=(9Txp=lbsKlYrK6-hkc0sydT3v;UL!%B3)`w(TS-@mkpL%_ zrrFq@&PJ_4nd9E_zAY`$S0)5Cx1gn{55A zX|a_%{&Het*4a+?3_6at}MVPir=_>1`)SW@E+RGK%R79HgI=Y*~vqNE3!Q zoz+5qSU7F73qkZsd=e*|1^Hpi$d({eZN%GzLl#ZjO(LcFil2DKLw>cUvUAw6Mv7Kq z3kjBF`fbxPfvW^iiiBoy67%!V%OV6Rg&#$7TqHfREL#JGI7VXGq@3F%vw4k@w%keYCdIK1a2I)+UiQ1$OcS(*%9zwxx#1jSLm-O}vXf$w z+p(+(Z><|%U(a8xtZY8n-q?J+`VbqHQfWGx1fbZ&71=`ESPz>;m+@t!fd-Iuu{o6K z#HO^ZJ(~n-bPe83p)6t?PBXQgh(@8hD4||!)FAK1B}014s2+XHZ{fHL@Z$SgyyE4 zv6(tnnbcDyXWq?Zu91eh1#pQerDcMJJFLZKaIh#eNi+zpCjCqtCuTb~rJ7#+%`;2h zbjz&A0$fD#*MxajUA-K|sE_M0K;?2~1b9e{fHgeW?3Yb&@Z~e7go#MNWXC~Ine9sq zk%Up%wbpH8Fw5GitWGaH4Omj<6fiNQOkQc5576cqhguQ+3WfvRi)9nytr_-VcOFTw z?7@W`J+Y;O699gbUu|GG)z&+y7(L3Qd~iX-paCPrdv`Dq86e-%qT!vk5NzFa+a;7x zf(+PMF-7w(J^Q>U=B+3MRS)-cs!Kq(xqu|Y;$?C59$ies)~e}9T_0`>niAvnjQ9aZ z*Oe_2W!<)08@#PzTLE0W3GWjTVd7vw;g2akmjm#vR^<``GjT>im$iOtpejvgR`5&1 z3sMz$RbY{!z0(0kfl^QhJ~|2NfaerjrqQ@q3fXO7=lHf# z;&o^k^hEH1bqC+g`6a=a{NlX;{r0tOC{O!1^=BsMVKGP z!8IahC2Wvk(UiL2q#BOEMr)E&7~Ec`=ZD?SZH7GE`NR13l6(ocxy`Ku!o9rm?{wP) z{aRKB)sgTdcC1t3sz{=K@X-_y8ahb?_@pgs$A(}A#A+M6gAK+!JauXIDFT?s;QbKa z#KCIYWNr3yx|Y>WK4QgFo@Yc|-7}!>tIVpNxBhGFIQww)P++pk6ITHu*abe*mI`XI zE)4JP>9roMieaoi^wk3#ug4ZI`fcI?uZDYnhg+PEaDIXVW<$N+xPg*Dt$r?f#vuGe+GjG2jZX?wmH?Rd&i7l6@dhoxn2)A1wL`7 z-)J-dQcu0n3axPi^!9%9d<2YCtFXZ9Br72lWKhucFXF@DT5wX0ludh>QwXI|7#1cH zI|jic8O_=&)mrOb%oZV zw$!OC=gR_X5ZDifI20fp`wjLJ>%G~G1TtveZDc`ZDeDcZAOLnU>5yC-z>&yPj0uV7 zATLrFU@vVXX|P0#U;$i0gdB*`Q!rw;&|7$qb}cGNktc)(dooQ0Hn`X|QD{c>xPDk8 zEiN3)s>T(UfXNC@zezW-#rLOk@w@;HWCo5nc)MiZkzrOtyc)e8j2W@cPY?ra8?UKU z-b}Vs%DOfju`yf%hKckFr%^M#T4xg}R*_lX(Vsd)NF)=O3z)J4mmdf}kobM%AF;c6 z_ceqC47a`!)>sCD3j=u@n4F52$KctJqCn<)Ishkk_IYyjb?+@LH=Ll_d{}**5QtT& zFcn&IzSFwoAA6tR!h-I1igZl9EIS)*5xqysh%8;jf1qhfq*8A#J|5ZAYF`n!p9%$&tfLqiG zn9L6Xl_hwttq9O~D90dD+fBgtQl==Oy_}$>83e?iAz{r=IEPN~7CVxc zCL3D1rnqa$t+NSY#&ucR%;p$ukYBO2BXa{}PDmiW-QcVgJrvX(HDQzN`C$UXcJJfJ zmbPr*JuU|1al&ExWC}QitI3-LSYRd}T)F3SeX?mJ9|)O=(_U(WWd(kaA7jj@ZKj1q zzWANfwZQ>zrh!`k3O3o|-JMewoQs<`fAZ7nX6MVv4O@}`>>T6%gbs4HST@VBa0Vs; zZob0FabPK8HX$LtPDBp=jJk^nGBt@5WU9DnZ#QWZga}>_+8Lbgs^2}*ZA#csk10MR zz;WIz_jVv6EF4^KQ2p_b2wszh%L$(W{FI0je&-$yAe4c;$v_qY5!*uv5HhG9I3D_M~Y!);kly_ zzL2LPVIwwMTq2KM4i7h`k$mNP3dxs}Ad@wdDLG*cm9%Yn3pieQ});uB4_~v8?46qAju%<@hjspKRZ2t-7|xSZl6U zYeJ&tqac$MO<~MY@oTcaleOI<7bWdX5{M!`CW}M!<0zTLIm4bloAeU8DG_!VG3&m` z4bH7v1T2g^0k$S9rJ(qfCFu0o3*s3g!YO!~&=lpRvLS0EF&%&B(Gy;@>Lx0;DK~17 zC2i>L0A2|D{Hp=nWLHXI2HKMDY3*5(wEQ1Be>Rt~6y5M`2yKr zmK%i(@81pW3FC?*CY?{RE`>(4N}ZCQHrPBN0gWXEaw?IJHG>`G9q1Gk&jke~9h;$8 zgi_N*>b6Ov7yA>aO)I6A%&dPao>3X-9wA+EpD5Ut33Bz!Y1;4<+K>STk|@c5+h}(l zS++1QFlyn8PB$*1lc#r(jHy~!;P_*W0ic0lNulgt!np{vszww zB0bp1r;>wQkpcx00`?egLopJ1q<7*iZJGbnQJ~BZ)9QIO6OEd{2QpA*C2j)XXViPm zQR9<@BN_wXJ6p4fpmH^|WW|E5(Y}Py@E9j~X)+M28=5%a$Ps-ATh$mw#dr+*=He}E zyAtO;>Yu<#FUG7}i#Hq<8G#17UT@5NJ#|iqJ&mI=M^mZm-Ge3#yTNEz&X{&P+$K7U zyStCpx4++9+ucR>NTxy^0tVXF+Ci4>L!vbhSx~?Y`^Eb1v#s@~yKC!6M16mCdwnh4 z%@HT;NrwO@eb#yEp_H@w(LODgr()^mKUY?MSbzHM=GMmcUw0pGK7GW45uXwn3GF9c zFWgZu_Fx3nbACV_`L18<+>!OlyI%BCo$wQU7On1TC3z=iq;!bBv1plvJBNLoyY+ER zWSW0@^zdJ~N_yipT*KYGN_y2A?$4%?{Px(Z4{&(_K>JE*cY+?PZ>WZbb{9Ob`c z^&n|gkcFM&LhJ~#P_c)v* zuXth?s;cLI7{9;`YFXru#8>Dr6jLg~{K?MftgL`_h=3#QrCqZ4{OiF%n$I3W*tRAn zI{uMw;24IA71XZsonBq|eb{4zrjSE?D*x*Y6d^fXo_rhh88L?n7I@d^2>v0t>{E}TKT@9zL*W<< z$rej4lQm{jCe3ZhT_)eY)d`il;4nJz3%H+QVvB4Q(+J=e04dD>5ZZXjtNIQ^64P9a zx>bzLL9|FX5A>S5>P{OnI8&))z0AyUbE1N4^fJ>Nv zz3t%W3e7PTJT$2Mqu#Jx!YxQyXkii|N`bxd6Npr&VIsu@6bS}OD68rZWB!*ws%-Ls zC!AbafymlBgQ&=vIF7$qZQL3M~B$mS7s&O0y3}iHjdYo|#`WFU zn!T9ZT5t4nEUnr0kY6FnA!GuWj|oc>HjDv~%FO&?pTc*uQwic|&5)a`<>5EgwQKW( zrcHw_&TFVLoFKT;#4*nstDkq|O$YZBQxM>UWRK+n`g|ohg!8-)05H{?QAjcqnkb8QU=?g@^` z|1nPQyz+xTE8*-9Hw>94{3ROk$C1LXpmzKr2r#@);5;ssI^z6qu?g~V4b&M0UT>0r zBb)w}&MZi~Fza(}buB(&gc~Bj@)RIsp0Z}e^{bL;o`ImG@fxTBtBy!NbcEf~LikO7 z${Q9oy!G~Ucs3pYD&iV8jKuH67?4Y%w+7rL@u)bgn>n^)7zfj8i5HP(GXx6ZLKwuX zs{9AxTiu8pNp?CDL$CWJO#6fAF2_ieh&?uM)aWlcLe zy;e-Ln5o*XgvQ$8g8TQt#8F?8iT~43@xAm{kJ^o+`Hi?(&hK?jd|y+kB7tEKCp>U} zp1PDRSh`4m%0*nW+?p$3gakI&jwF&oQtyePi6nr@}pi2iM-n@0~02 zR0W~Nopga2q@e9~Rv&L|+^5D$HYC*%c3OhNK5X17Tv!q^D~~|b>&Rv%dCC0I&Ge2x z){jh@zls4KB?FvoXfhxfPGp`4NMi#1N0M&spEjIgnsGM* zzp0KYg8WTIXO4h7Wq{x4a2BPOeYcwbvJoZ}kgXDm7uVI-t;nfwDq9jn;CpH0nx$3q zKJ53JRS4k#5>+|m%@WS8aQ{Tu|0vM=&WZgQmqs<59Z@4GmaH3aGVfOBZtP|b&- z`FOa;sNNh5#p5d5%@BhG&x+k?0I`P^B)fWD;!%W4uA2?NI|I_M_C(8a@v1N^`)m|a zp^MM6o2Ki+753JUGPMB0lW4W{T22$UAvxS7$6#e>lT-Wkko>wK|6Pz}K`d*19Oj@4 zR$5M&OuQiYQeB=77cSMSgomcxMsv=khl{?kn)=+pwz;E8s(VmUSWa|ob+ zW*k%Fc@mDt>o+9X>@2)`^$HY%Sn7$Tn1mBX!~UOc<%KajPl~*qnz56GQIs=ys}y!P zu5^jdgqXGUZ=ZdatV1>uS-?c#FE_%QmmlHH4>CfSYyV0I62c+Y-*ccj=#BFoW^(xw zh4Z3QCjCPpqX`c|>uEDrJS`K;TZm98Pi-J*AD&=d-om@P?3xB%UV)A zxgFv%qmSL}s#mo(c6|w)9uH$X2bJYsqoL#&m&q^ezukvb$}()VfRv|6A$`loqxag+ zrMPTRY~De*2+~CmV}jVGQc1y&d~r%{eSKHf3=NoYg>CIUa^#zYSQkmMoSyeBFxU}c zIaP(d(@$&TtXa%_7^RdFeNZ+LvSB4Vns}v-#I0D;vanNq6;Og%70j<@7gd!tIhU4W z({?A^UQkaY%wkbfE;gnZ9jhC0B;2w$mwCeoVTH5KAY|*Nl<=6OA84X`Jg~LbC!Q?C zSk!7d#(BAf(mhO^LwUnyC3b%gj zlPjihl1`!%HQ>G^Da6_tUqosiApq%eys~nC^U?B`VBl2e9j!o#+ z(eUE<0KB*At26jpn^G+JTr6U~QutK^Dg- zP$tFOCbOgta}kv{G)!58X2GyK*V93gxyM6u{`NFh!J|L zsL2=hC!7u#O9YZsFg77^GXreeBHc3(&5(Z14%i zX2^8^bRAycr|Z}zBx2p?3)`UP*oAs{J>NJ&>ziUj>q3*Hs3pqv5&o62=sT#)s}G;8 zBWCw0xl9-dHOu}TZGyUG5_cxgGHQUhTAr_T?akAM!YuG>}mek)Gg} z3q5KhgYyooG*13dTrbYxEXVOioB$&qmrz$@C~b>FB@ab$h*KH7f@321+GwiIoV*3K zQ(XJBZmI_|b`kJMM?m2e*5wf;*+hIx&SQ+v`uo8RhBOOz%p=x08z49iT<IAIZ8PYc9$xu4utN*W_Hu;68mxy+h*0tql**%dI5AP<~E%cNSSwEy_bW>ya zY7*DrGdpFCJmoE|(Wo~(g{19aXtsDtjdj&}lcU6{#6p(WbJ%)+QUc@D1sI@#biNhG zhQvJrX6>lEaVL*S?fe03no+={cdLT9$K(g&xhw+Qn?$OYn~2;FZD8j-sQz$JQPn^@ zW$A?qPB8>N%dO;?y}HQu)Fz4=PB^7V78EWM+c$eN-D-%@LC#L<#n~YRM`85{vz=Ew#2x%fmhwkzULhIVC9QHwa4t?}a z5o(hjYL|dW)i{91w3jlQjINYI%oobBta0INNt%h1S@xYE*i4k@D z^c1Q#UE_=&glM#P4EwF@! z+t+i$baLGRwZ#%1$ zCKyeJYYo+9WZgdIAL7t!2oq}1W!ghg$)s~XKF_iy1Hf7VGv)DHLoyZ$I>iM$1Ij@N zPk8I;g;n6X;$ZYohe)i!wK*OF@u7E#i8>ep)etjeP+7}>?6gk-B-+8C6e)0u3$-rb z43CdTm4#{#UNNK?wn9nhxvlLO13KSFM)w2iY=5dw_I3|&bY=g1*B^rAi>%|OC$%gU zn`{)Q75TA}O;lu}3HO@6I6wSqONDUh+LXP9zB?>RIoZKV)|i}_Y&_{NZ!jtz6DLpO zCrA}>nsK6M>4J?%cr@DraauAmOgCfx$sgy1F4V?D7r+_pjL1Als_}zZJj@xoX7^;P zKr(PDQ=+Hm7o{Z_6J?ahrHf^v1YY2oE$E<-2vsV@f$<$b&0BnAi!8&q8xhs7S7#UF zqYPY$vyo$A)Im>rKa&JsOFoHgB#L&;9)Lx6)=;n5B@a6l!y0|FS)xNQ5JyJZ?#*>h;6J&(fsq)uPZr?pSI{W04rK_JnND-?JPnmO5B4BRp*m`?% zIE1SPncaTIbqgR#Dc{|{Qa$MH4VdKzhlWr02QaeSK9nc-##)DAi+8O21MIN0Hwmfk z56|9e${Df|S|3iax6)`yyC97Q)fuir#QxN(2|@zy#)6)45i`WiEZSRU*W z*wJKk(B`e){@k{H-&9jHHbC%BiVm5gPLQ# zKkAQOg6Ukk#*avLh6!)$i#)67eryRVT2XSrn{e7OM#M-+gNZ6hWFc7}#PYk72O6H0GPitFF8Hn1W3uVFbXS28tWV z7>N<6gKMPe?uTSUfsrwuYGSx)`p(;(NZBB&q)s>ap0_=b-cul;GbTS35oEihzVuBy zk%#RsD=z`O@s&H3*mR?`Yts~1maW(bP#fKaInt_RH!Twppz&its5(PrS;1S-erTv0 zz9mhzFc}4pT>|CdM;qmR=hi$e**Gc_@*@n>qvVRQV4a8BwT0t41O;oHTaJ5)%%Qpl zk{u;LoRHHc){6C(67>754~!^jV#=5jNZaP&J}(^Ng)PYU4NWKAj<^%qo$TOUWTxP) zQb4aKos@BB6P`%iGR|mYG(+Q%Tx>)p_=fR9$his)$#9}(IV{Muckpla>AVIi|Z zQ6(E>(s!L-ufOTz)ka%m{fd)MHRE?Em&MWa>FSg*QG~r7@a%@sev}E z6iv4#X?gu#bsu4NOcI7-qz+WogEiJ*3nvu$CTK*kTMXpHL^uEuUlp5@?`efj4a@!9jPrqbT*u0EbycrUL2T;MN28;^-|f4s^YSrp_DffK9x`WN7dx#bs+NG&xa@ z#5xP}n@>BVCi+aO+4o4i(BinC;MAVBQmM~ofn7!J%!g%L#kvl!niruO*B?0d=sR@; z8VXz}5T*t7D1o+z2g#&^`oZm>sR%iN?rZA7b{+?0gU*hx7UDBaOC}Ze51b->{ZUyE zqmHaEGDDEDWSz$O5}0zpdBdStJq(Kl>GK1+(cB)d`b<-e2!C==^o9HyTyrPzBa((j zeVjQNLHczoWStGd_Jxca#nk;X7e*^t`5>E5QO!hGbxyf)3hxvo_5XEdX+-jODs8<( zpj9S9`9e6OUzaMGxh6$Dp)J_gN&3Om+{+%b==jDS=x5Vlv;zNm%ZBeuH z?FQ4?2O|I_xbEmte1SnYLd$K3oEp28@hPrA_U-)9cRQ~Q3c&S77kdlJq3p50{nt-c zfW!nH?pBI0Wk@`53L0+RkD~EbZ5li{Pn;;l9^#M?Z}l zVS}Bu9=!Rdntqh`VQg--6=#)@oT;7y9<2M6oM4WCf%@|y&C$b34ds+}a`^FRnx@$1 zK_)y2qyei~gpYdrn_G)X68VH=2!?+eEj0d;f9F*QhZC0Oa{&wL4-%Zk)tDCNcX;cP zJGHcd=N&s-+d=rd-G=q!>eI&?kITeU-dZHD<|hhyBT0Z9IDHc+AuZ83SLgi%#b*6%+wIZ5K1#IVpieW|?Ih_@09OrU~@<75dF zrMeL;+!>68oA3lKvgFk~;bFC_aNe-i%NwJF{K3zP% zyk>^Vx9-3cRaEtlM-6mC;dM3K(p=`S{SpA6!wno&mD5<`*GnU)MHwyH5~oFGuZ`QMH{yyw%`;-nP#UTMz-uEf z#j4%S82;)~Ntj9_V?s1q(y&3`($0jo;;>w>8}H)SNPjc{ zJh4qi6IrU|_z;0aHy%!s2&*$X2SP(`bNcgRk4MHvw7X z!E(hgr~AHgC0vlC&@8&mg>0{2sT2*cMequ%-Ho;C&Y!B!Z+v#+2G_Yxh?~!#K<}8b zuLO90L}v-ymOD@Thj#qt0TvbIZX091aS;)biy#>eR=u^o4YI3qbOO#w1+=%TFK^&e z!o$-1fCGMeK{baLf_)xu{X#B`@gic77Ek-cLxW5`r@-MzgP~lrETcHvN_0l z2<9U2W^-YRu+5bTVVY-#VGgB8gqTa3j-ZObhy+6e3>$52tIUf!b~2qAO-B7iIf;ha z==gM4y=Jx(SXnL5lT6%tLxHxI2^$wvruDy?4$+R7iBl#|!G*cD}K`viOY$%=xT(d(TKmaqI+5@l?%hv{x)UP9X!c=1L(WS?+O+nsN5(>0YHmv-n zMUaAW8;)A~s!6Og*j~W6T(MRHH+*WF}C6#Im%t>2u$yp1N2~F&D z$vT~7JNeGV>;eHrCShz7CXkg|h`S)m`k;sMQ8CfY!YBAbf|zm!(;=l+J4ITZ_*;jE z4aJYu8+VOB7OAIZVW^n+`8ts}uD|_4!rW?6= z%D3gb1N!KoFS|00!`^+^zQ*pJW!pFv11khPHq7BRLSyjjx|1=Xj1uqVjQu{FzRgTI z=f8mr9s}{O`ZE(lK{#y`v3dZf8Rp8lV2K^m=ol9d{H90a#kAtpB+4(aDs_d?rNP}x z^0M$7KHD@?_^A!PSkdWOwP(!fstE_l7X^Fq)u!YgU42;eH;fS%xPXqX-xes4GXuIUy~?^OC#$K=t2^0bHKY>)x-_eycKDSJ zg9psyk%Ble91r6#3%&?Cj>K+=L=8`5POaa(!`N3Q@1#s;8d<6P;gUq9m6}M(r&><* zAS%aaE&T2>vIe|?LaI-T$CtFxqjjg$xC#F;_CHGDGVdz!d7{dzunvl7aPEooym5yt zov#l?gdX%Pl6RoU95SZR^Z^G_PiM*=w$hm zVViH;h)QBj_XkoJ#H(r#`;pKH>&w|JHx5`p`JvANqrJv`GDL)PfvQfpUD3#V40CXI zrJOPnG}K_RK#No)hSSdBaJaJ98wHzBX>fDuli`rZ`liYU28u)E5=tsahIdnpXfb|X zdcyWU&_gHIKr?j#V=@fkG&XWAa5YA>s!(l}*$(oBv5>6ySin^n*J2EN-f4m24G$gG#9>Ct;s}6d7-Z zG;f>7Y@oICPs?Olmr_#HT|Jqj9bnGWUfU+@X_8nfrREZGPR=&)7UFLn6l5f!w{jRM zd<%D!+PE_70(Bs(l<$*8a}Hamst~EtnuI?6U9|LDW^c{T8H)Wj>7yLGEw!YC>UQJ( z(LfS9UvlB4^O!bT3~h#Koltus>53#Az@HMnopjPhnPJWuz8=n)%r@Clg|pmL_qR;% z_kg7 zT$90^hA-pK{ewotsp=MNkIK}vN#Ji@0%MsFj90+;Y02=K81CeF=|rz|{x;$!DU#R= z=M~!$9Np5Dsw7$O^SEXADV$o*JMY* zwsAtLOku%Kl|{fX6ou7YWc~@y))Eft2Gj{V0^;frO3LhXv+o8t;ExnSS`VgzXhCdl zOGjFxC;_>AH)4tY8ScaY2zCoA+uR?ICKlITR-aQoYh6@&4@ZgF$k zXzZ|eiL!a*=c34^h3-}z`O;w;R;m|BF{B-VIBjh~zj7~{!}6T1yr?O9x?X(A;3cJ`}@W*sN34qGhTD4HG99X1r%SHQ$|=4$B$kG~JLSgxKpP z-JrphAhP%-(1`o3H*0InhO2qVQ^r zjR+y0cPk#0qxla(-Lc68QcFgSmEn2>nhNhjL(GIABCAV~q=sb8rVBDTAT7}cS=I-u zlN^=~>lE=sHHV$=d9K@()N1{jGJ=G}>hOVltX@AKl+`b*AF$j$FZi|qRo`lFF5Z$G z6~TN*uzS5i0mN?ITD;-Qv6(=7V>%sc+~6LdN&>#+N~+G{?(U=Y?e90&c6Xr>#PG&R zFp0VL^+0!p0x-;wg^jPRKY6--ANRJcrD{d+$$-2xMvkz$b}$^J;TslhYUT1&L*4vm z8sPnS^Xa42hd>5z(lfoiv}x>N)6s}l+poiQ9i!gsU44TC19!BkbQn%)9y)&5 zKi@xc*e6iesrZEhVTe0;8g->YT5r5IJV}K#1Eg22Z9bA{2<<^Buq3pMPJh`!m9^o% zCV_((`ogEV89_*f`W zyZ^FHllCH1^{Zz_tiAxeW!mVF%8KIMM3tLt*M|e*@!{x7B%>sYPjrP;z2M@8jZQW7 zQqXaIS31y=t(x`19h+2Fv9ra67%kZas{jMD<>9p2}itZzXh0Cjvu_tx1 zILsO?afkC|@lhzg|4}H`OytVN>OwJhkoLUf!V>GLzFm@jh#d+TW{Pv)xpe0UTNi9= z_3cY!Y;L)UG4{90*eNK@GWPEzOlRvq5s`_4CMhTpk$vqllTAN)K2`AIU_)})aZ@kf zzn82sdnIwV4;;$&n)xM8`=cu};Ade0 z%{vg67x^a0OZCLAmpp@_=ZI4B_U%cQ&igLQ4=1%X?6@LHlw#XQ5s3m4WU#3s639Ih zWdC)t65;IxMpFt{QJjuN3PFnv)cqh6)=Oz%t&@MDIGFJ~7!;C~(qKag#hPHBW;_X_ zRP#wPR1PyV?Q$nq!DUP)!rhupCbhOH(_W@+a!+TA>?ak78-WjML95B<1KDF-`TF&f zkK*?IQrw0iQyBbJ9F@hXQK)(%UhtAnNE(z9dT=bjL=)j_{dJj!{h$CbZ55KWW%8i>i*`VN2`z5 zm>3vG6(RfZ!U#qgpaVqp_V$lt*Y0B@hBZjDelVYh6Qif-xax^yWGs|!c}fhOBXcv` zg+!1yj-ynAL(SP_Z857eG<{K~Rjg6r@~ZcXR)HpjNZ`=x0q^hwjM`J9p@zfLVR6N9 z1nwAzo4yYVH{D$A!oOh6uQI~SQp}fU4wVPj)C@#vDKC5vH=mhX)*h)@h*&xgvw+i$ zjy6Mzhq@Khw!QxJ(Z*wVYv|4*rM4<#vB`0wO(Ey7V4CAT}d% z5_}?VOM7j>==xvouglq5!{~4yNh>5lJ>p%M2N0RdUml%<%=h~eBuVwH-y7A^BWyE) ziqc(9@du2F4?%aao#DuF0D4ZAg*Xn8mfJgA6ceMi+(yyf(#(V%@>r%si-oAUA3gwS zN4zGJ5yphc__%F=xfHI;XrjXoGTBCvNSf0;gT}<-wQQ4H4y54~9uLnS@S6GXB5rT) z8~igaDOz}dz3Tt{e}-5FTLT>Pt8V`tPY=0);n^atbswJILly;uAtOWDIK9;lUOtJh zJeI9YH?d@Zjuyl(+is@p^Sg(e->yE~eZ2Z;ee22U{dE{RJG(EBhkL!_hSe^tIBC_^ zjG5_8fK9JxskhTe9M_pF`A;3r$p zeePBhZ?{VDnq7e7j43<#mt2A+mXLfbh3cK&J=NBW#TDvl6=y4wcY3Zeook6Hvjok^VT>J{3?FN<0D{ zvJ|7+1!tg_q+l}fKB^Y7tB=eI&NeQm)(<->Z?$zydBi-CYXoS2LcSpzO!?MAlI(4b zJ6iE(_a7$T>a~X-eW*r1?Gqp<=@J|HFdt%OP zX+7<~?4H%>n*G$h*y7qHI-2uivOKo=^TDa#C&wrLNqCw+62Gs3l(el$qKTp=h*;UC z%12}Ch|_J4ln%Wg{%y?dJ-NcKISj?{OZppYr^4G`gcFFv?G zX<@4%IH|~cQnH^?YhVWO!STYY$CxldzUP!luhHfV>q5XewI-UJ&mn&vWZDW|UBA5^0c7saV+@A^DKC&OKF<0?K4(P(wswMZz6g;=)%GskGt|sY2}8dnTw@GN zA&l>mO1R`=`@Dd`?#a#}u^SACnGzI9X|&pt2!2@Cjq|2KFF@{v7!w zA5R2DX?Zq4%Y@o#Q9~vtrgiHm)%6;hW6SK)w5R$U*3&w%wk*s$WHPJRc z6gAOJAxk-2_ZAzkABv$uYJ@C#;NeY$O1&$5#o;YZ;*(tKzU&`yr~nEsH4J*du+8gI zteL)ZYk`#yB5rcJ4-4&}zfT`sIL7RT!P*6^axD=h2k9M*B-8{`&`Y+Yi+5o$+agvV z7w(h|NS&;myXDQHD=VANwx2xP-qjP9&^9;a$VlL$p}^DCAB_vt@upmQk4`j8>+6gs zaHJL#W_$;xH%oh3pi+f@&KW<>l&nxFYqFJEVSkZB>Gn=h9yT1L6*>ophSMa?BS~?r56|g30W<#; ziiuF^jV|#wSFuC+zL@gd+S3qZJ4MjFTd?wb(u!|ZB`EJZ^ehfy+W3=gDzoCZ;NkbC zj0Bu+@;w7>B3?dvLqSIGuL|l;R*&;`twuTX**P^1x*BuQ68$X;Qw}W4+C(^95>4=DoGwk6fS;9!kLsp| z35J5-PpFgyTa)@l+F$FP_uOd&ohK7m^_`2fxU>%)m5${1 z9a9wI-czW%snC{%+%Z4{>ewL0RKEn0>W}|865m1g!TFw#rfY{uW)c(80}- zZL8>c5=;*dJiNP2FU)@%4Q0>=!ntv@$!PEdcIQ2kmAV&Q%A&<2Fr=VX1N)V%5quFT$`x;v%+UCCevcY2Ah05veyboex3${g_w zJoiVnISGE?v0}!97F&r5YJy3{84UBOCBW&=UWPJe7m@0dV$^~$Bn~3!veZ;stk_bw z%TesYRfZd3fI~qkY~(gYi?l_@G-HUSTbnxO$aU zCjPCJPl#NqNQNWN5ZzhY8DD+AGukkRm{$kVVcia}r>;}t^E^v2@{ z8hcSxml9w?NbiawOzv8CU?pPPtx}9FiUw1a&G&Dhg+vBvX#ahvptG=mq}{r8v=f5l zyu}4SI;BbJtt0r|@j`KjrszE5vg`b^fNAQ#@n4*?#(KzqfK<9kZgLW8r?=10cIAV4 zr}_rz!7dP_6Q@IJf%1fN7F6r~4#rY#65*bJQU*xrk@q>kJ>4ISavd71@5|F|R=I&{ zo8Ctx%|x?N4or=QznyktyKB@Mgnr|*w6Btm^;qbtU#FVN7{=9jpxL6*u-wB;8op$niwEN=vi=s|krCKvzTahg&nWpX5&%7rC z3B>l%c76Z1*sc?ma9a2e`r&azKbSMEIMZSDM?3mwT47a~BTbA>I`>u@!$$AH^Jh$^Bav@{DD{;gR*B0id_&ov??n50jCp{ml~-cMIz zza-enD_~W$CrmGtq#TY+dzy`Ov7DqK1P}k?0%`RR@)m1K)y%EBu2r`8&sbQ=yd+DL zQ!^F0ms?g@M{Y#;CoQVD0Z!7kO3PYQuS$toPP4!i@cRE_?_JlUII^_S|8o^-M(h$c z;$+(0jWM+PRiWMu?DORiqia*Nk;utO>?+2}B*OlrX+-JEEk(?g5%pA!LY_A& zps9)R^NlS5r7=vwzJakk?gQN7xK}DaA8ZYPN_f}q5KSrQa%U{7@{{6Re_x1XGS#+` z6m|I(Q?sEi&c>{fX%NdCd96dWEDK`Fv;ic$TkX+Jr`q_PJ9s`GPU;4xHgZLDt&+Bt zuuo;=sj-&4T#C1f&3dP-8HySPC1!B4JJg)k=dp@|`J0)=ZY@LO2^$eW1UfxMNioMu zh=d#+YDEgB{tjX4$x;2-dIQZOLe?+#L8yMQk#b_Q`x;Ck|~Yt*IQe+9(&}!HN&; z)RXlQ1XLYJ8PKO3KL4l(7#~SOZUnkoNNo7M$UFDX<}&24HqLYs za`|T6yJuE4xCd?`uH8_a`T#?zE7dQ*xasMZn8=h^qLEmiHYy!rP_V)+N8uicYRlf< z!DXwj<82b$w^myftPj_NSo^Y(oH;0yt|ON%9)C|D=^-l=85chZpIteg9{0yTjRwaD z05=a_k(b+V`8E$-sl9@yC|B)k$f7`isE2op-sb zhZVWv5_Zsz(1unOs(&M{{^RKh5<<@0T@sXSS?htMNZYkO%$568d@TJjeNyjhrCDPo z^tA=eQhr?Py-vVpq0}K0T1c762k|sxFuVQn?#UQ2b1wp~gifK*&+XQ$g2QOV@4HUr zK#2(@b6xY@2jQ`H8TbECKom<#ToaLzF}GM9_4Q)!q`ombLvz_x(9NZDj_<<-+eoGY znL+Ku?vgCJ$)vsE|1CIkG6l=<<@%Td0fay?Zh}PJV%4`gbSFhJFHheN2Uik3L!#iq z1btj~4^72lq%LM-puVz~TAula!PDRekIWPr*K$E!E>?4XRfp@a{|;wW0VoY1V`zTW*my);+52PC^TTrMRpo8{wy+TG2s}fXFf*jJ2dAH@rnL za8RS#8(b4ZTm$aX20T$*wX3~U7nPX1i2Ry=fgSR*%;<`eWx;gNq-dwNOvWt&VgVII zI?mgrq;ly5(W5v@nQ{>Yky5PXrRb!U1_F2swrz+}SNEr~G-XjlImqp*n>n4!EOH{# zv1-0JZ6vO3FUr3>&)Sw!FD=LKi>AlRTe%tm>)@SEFOYa6QL_7p{1gof5dIH7E*;?o znH=uMv%g`xV|iP{J(^0Cr<3W?d^FemM3KbGg*;$05Q=#!&lcs`n69`^bq{M1HxERj z+gh4`PI*EZZn=A&YC(XP(aj#rnLQ7?SweNi-K)k33ZkS@1{++yyH%7?aUnFSTJu4} zNf1rI(8Oyd7+#s z*<(ugo8Y)f&qB&Fb*nE)&YQ=}fH?9qlOXlnnHTn7a#vpR0>%LyC~+BB(;}JC<_8|* z42zPhD~AvF{pg*Tn&;WQP+Re`%*O88inu1ZtV3M)gX#F>a3X%i=CMW-1YDwtkxB{( zY%(3Ntm{}uc${&?e2Etc(k<{ym)G7asK3tPh-AQJ%3Omfo<4k7KWY}JAXCDN{TA3u zWSB+I5$B`VgS%X>`XWXXN)$YB?KW9kxqsRIm!R8LW|c6bavQ;_&E=ddYNw729nD2d ztxp2St1VRx=dY_RH^Anvn?ME{O~CT?CFV)OmBSrZ$+HIHl6O}GlR=EsnNg|Z$V3Zs z+8nGJY4wIKY>Aje%sI`ORzeg7>u>raT!k?X_q)%z2IX!e$#)l+QYJ5aD&oQFIuB*hqVL-L%Y3DoS3d;p8a73J(&q{ItCTSvU z60Y(A0S!eI76_E(_-UfM3acAxUciioP+aRR(rLBT+CG*)iug=gH4cDq17YEOQ=-}; zs9nQK_kzeWb*Zg2_QIsYC{rEQVt+0(pv>sDQP{(BCoWsN$~`g$+DpVtVPlHwX*~$$ zfwDondO;XbLJi>Tt*n}GM){$?YDCX8vbbXwxbrPZTE{jSIBpF;(K z!xg9>9c>@?_mMckfT0iGzt>&1r7otDds5Y~&s>tJp5w339u2X8W@9%^!}yWx7SEB| zi}%PWbGq*G4bcI*6Rq1P+8Ppn@e{HtNCrtUXSivdm$CRBj(M_gFIy4`VC^+Ft_^@( zV(4eGZf}0SzWLXU z&FYu@#mgTaKY03Z!vhnVi_20h80&mHDOt9y;Wmy%j2#==}c<;z4RN@DpX zR!by0uia&zSWDs~r6y0}$HHlg!md+Kqbrdf!6zjB_UR!i5pP$|TB+VyB-3Q68zIQf zibz>>^+k0{Yqri?5@x`;GtI4q!!4Y;?rmUiy)lJxF9M79MjUHIs=*~_)bBYSp-x^} zyMz(rP>iI(z*kt2Yx0cxfR4#lv?x^H4=4K)({mGLi8r5Z?LlTR@v>i~lbz8kUo^Cr zq{0vAs%bluYuNC!fQ)<`1W>o~YvAPsS?H0$HQxX@VQ#h2Hro6GnwYoHh%|usz6IHO z<7+m!g$7?oZe!@vNL2%njY*&SJ5C=9M^Y6aYBSx~1Wab7li4LZhfdy~4w-`kpFcrr zV*e}(0X0s)>>+buFu(7)@&9=8{YQ=g{g1=38wyLF7Ed!1Jq(-IsmHv92fupw^vT2N z?#Ut2(p!;oURH?F%opR;x&jRvym>G^1XrOKC+&H)ck|i}C>On#FCMM^DLo~)f(l@9 zhh+ywP?$5O@$$SIA0f3Byp8>bu%cN7qD22uLV%;cj)3{ ztc+cCICN02mB`kFJyi|Gw_FpE={oosH&P=wYxi)?)%r0k+MSbQWDvu-9ZYT7ZP0Uk zMfqDgsKinJcH}Ugi%>CkHJ#*t7Iv>Gom1W8?CW z=}Qq|gh4Ga(cFIQ7z1C|fwv0nNIoOf`2o*5+)-2*kahO{Fi5JvM10m{r8f7{lc{cD zt#M6&K5G3-lO{gr_fKE+_hm`e1nJs6++uUMDj72a`j_Xj>v5;Gw%KLe)^m=kcd6yp z=1|tUO|=Mn*Q&oH{RfOD&uTCMJ!CVo9YBSJH>FDZ@3j}ODaw@()n#VW=`pmuHZ5j; zdbl^8oYpy!7=Kt+@MNHrwkF z_bFRS;ZDgXkwP%AFWMo6Lcy9SV*C6=M0q>;>Q!ATw35JV=c5x*scojnDA#j3TxR<&v=9NT&78H> zfdMN~9KYZoHjyDYQGbGD7L28|=Yx*yf=}YFWZ^6!%g&z&%gr^lm;D#motbfGh>=XT z*W$9PYY*OjeDD1@Zfx9%HFW;5sa>Wc)9>yPyx387+kY21qNsg!`8O_hbg|DkYf(wN z;CXvsyVLeJm}3_To=3gAu)jMh(WhdW#-ku zJayGBU17K~nm0)zNj>kBoWPiB$?s1knYLE7qGkC#DAJnaJ{CcO3ha0c2hXJ0x=x*6 zq>hmTu7HWyNbKjTIQq2rdegZ+9VK+V94tnTmQCPz6}EZ9&s-=c!^;FkglFv@Qhp9+ z4l_&|882H$Y=L*=$q`faN~MM%B;lDq=`9PuaG0HrS@3Sfcre_CnJAbvXSh|tNMkj% zh@_hw&+0D)wh=m@TiVcT8Tt?hYu2NLfWYBOt9{;oGlUG6y{IxKQXjNSpD5jy7_1d( ziFI%Xv^VXjY!j!YVJ~H_DHs@|4qR#cf%=~H;&=$ z%O%E6d;Rnp2U<>{nJgXZP42)g+oE{5>QJSpAG_MBAq(qu7jZkZQ9Ce}l&T{wc_Emq zw_WfgCBp}?JdC~5W0YvYDLU(oYD`L(i2-rUke7K5sy+pM`4t)QD4onHL_6yN66}ZO zfZ8j}5uuEY@FfN_VBy9X3AFP|x*15(+j6fSI!S1Yn`Mh0P=12?l?z%TkiQiec34NKeKV;xKB6Etnpro z=GB?N@)a2S1mcnw^f&{s1pttpG19NFFVH-3JJ>8(Wu!6)%ow?zFEQU!-d7E-nG29`TCQ?VyMuhz%o z>DxJN`oR?EauEI<5?UP}gkw8UF_9K-h^x7VgR9ke^z*Qq|2#T6LUB3FV{VoTp+ma| z{mH&RA2D7%zwP!>e`f?Y!n5fyF4Y?iXVu+3dGeiYJzYa{`Wojhz_aQgxyFbkKr_sQ8KfqNKF?SLO3oksO`ghX=v@qAkC4B_6G&rt-y zqQuFtLKOMoXu|vShQyv5+iEr9aKQYydcN`EQ-}Q(tY3R z05c*=!4}O+eFRNM>&B!3{J8-gN?YfKGrBUGU_KunpUft}G29*bgoE%f)6zFGMT7i? z)f96vdpnvp9c#-XJ;&o2(eCK}#5_R`EzI)-6Sb)u<%I;PMn>m|FMW(dPqRIoYF`w> zs!lY^eY&ugutzNRqyF(OsOy#dF3Et=WPUWRjQ_YRo@RfVv*r=5l$BM zPmU3(UOk%iC&+`iJFUJSzM0PYV48RLN5|jojq&qjc5N~|F0gZfA@FheWeof%Tt4oc z%vk7=`GWOQJ*Cs|Oab+h86Vo-7A`$I**z}g-xsqtAhFWsuiDw0V^Liv=h}Z69@jWFxOX2@7A15W7c{!8)*({$v^3`Xn3GqR zBN_6b{#yCvIEgcmR=5=p-gg_c*{rNjs_cn3un2gmwg7YiX(8Y?L*8*419EWAX4Fg&tR9kBJk_3OWGb^{b=F@s$XYFH&hb(Zqw2NNYnU zI*h1|%_PHrQK+_vwZx(1c&e-A0giUqkC=!@Wzr(xU(nbJO{&=id&h};4|~cm+2&Zk zP_a-HI48-|KpCdCmyON?I1^mNiK)(vmf8##+sttlX55!4#CI588^(eJC!s*CD(s@$ z9DsUc6uTy{Lxsh&t7~9^=x|DPNIwaW|1E?E93`V8$!4r8$H}aw$5)!5d<1P$eLIjc z;58SZ+rMys$wGmWus|->K;8tDYu@O-!2;<3!P=;=0yhsLQOo;}D}+9-w6R4TJMo1o zBTKNi=|(|7VFPCnfBi#ZEsCRa@D^c_4X^~9_c|R>VERNXF9$zyMq7Z7U|4ej?D2w& z-RaTkY_xxHT+t+lhixd*aiRe=ShiQIqw%m0iTP%PV~(u%{o@B4KWuK$PTw0rj}#m6 zEkc>#lCv{W14v&S9vAoL9ESQXmz#*9&#(W>zl0du4o62&A)qS>Eq-1-AL4R@Ih>@3 zo1(J1JDttwQE&mqW~<}VBXO?^q_oW8-px7Bzx~huJNuvi4~1X!4-pnN#u)DY*KjsH z9DaA~Pnxa;F>8OA9zVi8l7j#q_zHZ@2xh}6UhMdd1|HB8OCTgm&vDMH@bIyFV}fHs z^VO{M$8giYA3S<9oST}MEJfS5*E1zF;a6~|W8U8%@_QAVul%uinW5b4@(C$hWIs!) z)H&Gy;vi5UKUi6at(5r{X~i zi~9o9flqV4)ZBl_%Kd)2KiVzKS@wL9;`V8#KKe`{#Nc>zI4sOnE3t_Gtg@1L{%rWT4|IGY)RMxVv5}O?4M; z+1a(f50AgwKSZ+MJa|VpuwrKk0c5XI#fauc*i#q`VMHQaW}wP!cs@TqW$a2Y4oa^# zkNdknH%+t+$p|^GF5SI^Tl|K*qdtu61Mw+U`>^WZaE5-+;z2RPZiPiEo&ja_6!yQ7 zW6}(%U{9F^U^TSYfwXN!YWhB~dz?nkXq&iY2z@mD&g}RbU}?A?a#{4QuWtP(QzyRu z7MDRWEO_PSt5%(1H<6?31U_w%j zq)K*%jVtS5VYxmLyR*63B4TfjQ@{Bu<0_Hz+@9hCHrEty9hJ#u}ZlkRc9EY7v?azk8Np~B&*pPykud|s`cMnE$q!koT+BPBR>^c>-<=mMm4c zhP*1x7NEKS@QnO{!a8!bcQ_19Rpit6&xsuNEu zLOy(UROqa_r#YVA<75j;#U++9KL_~*m@ z;X6Lx>aYF%HUGJ>_UG+yzFvF%`4>sLb5Y_TX?G8{Aq7`2{p;OTCJ>U4t_R~j?HaA{uBQG{$(l-*cM`mdiwr=QU2_wm2E)VnB zw?lI)@^b6u>xc`%2Q>=}&|crb>%f}%o@91IZk*xSJ6uy?np6OOOWI$nZZ@v{VRh&u zg}eL`1&4*~8V>Gy2{b21RLJ>rLg0YM8c04{(5#I9aad=3`rrf`RTEn>uI5Dy>%0T$ z9LJi|LG!SllZTW;Drd{SEjn6;8^Aq9E(19$(ck~J1|;!@^GBjf_O9!lJ!}ILkWUa% zKw=5AFr1^**2?HLX16|D#WQ|MedA3|9AA1Xa)7w;R1WcF9W-a3S07*)nEKBMWeIv9 z;_h{X2xp&^bBj=2yLU9j?L=9Z)evFx#Fxg;Q%hHdPJ}3%)niM-4Ig0#aZ{EzS9y>H zgsh><3udMg4OVqgiyK!d{PAW18GmWmrSYB6>Jlbc9A@FzSE&_XsoY4wak7LyWIfc* zxW_s8jFyt0vK9P6cZ2EDz_44PmAqtZ=Ca-2bH+AHSJHzybtIu2stUJq}+t%#cafQx@o19 zE5cW(A{Z^z9thd2q!#N8GeF(~N=R zq4Na84*Wq;z}s_-4VtK>oPGNI;l}ee=md#HU;rts2{5TPLn7sL4aqIp4+NH+waDt( zo*#_%j-l*OsQ}3bN+j(P4ZXd6dNiWo&YNLD1yPQ*KZ2dLKVwvdHA+bo$Hmf-<@I*X z);K**OEq5Lf5)@a!qW_T-2iHZT%pI2yxjv_jnby&B5bOJBv!WdolQ31@Dq=#)_*0G z=?p?>qKzx8GwBn(G^(nAKuJKx2!KLSd!QsBBh+4Xc!FpHMAlNd84U*uc!VfUa!?}m zPUg(Q7{Mm{Ex9rC_1{#iioQ%Ayb9}@rAfU3y+&UeE{eW^6WZybH{Adn*mSs6+`uPY zoBs`piuCJv{j??2+!Dh22CvXf1`Fj1k05kBi~)Qoa}t8EY7wJn+$D%jXL2{#_040w zA=WXt8mhf%qYgdmm(^C!fr-!YoQKWLb<~Lt*R#!i*F=ZTIigQ}m0)uLp3{Mt+3FV14Jtv|e8J2a zQxJmo?@-I7Za!d}QClE^fCmmp=eU&6qIc@+Pr+e@lht8CW8Oc;R=6&sxFIeSNy-Vt z@*%QL+bu1ks(o90lgd_LU0EdZTz8CD`hL$Y5M*jPE})yv;_kQ-9~gE|H&bX!o1G2b zDW>(8h^g(JAhO(k{`pG0W{@76qBq%v{O7;F+u4i_c2TC-EB$``iCz9KB zBDuW`k=(8mNxe=hk=(8mNxfD(k=(8mNxfPdk=(8mNxf1Bk=(8mNxfbhk=(8mNxf1l zk=(8mNxfDFk=(8mNvOAoNYrF5GLY$bP+BqdS-y2EWgqYx;IakC;o=&tWB=Cev?dbD zOnxqPS4aJ=Kctm#Y60C9`>Lby)*sVq*lySz_Q$2({#09PxBg_+T!-|vwgNeB3|Otr z@M0(UIISSxWH zNh`_2)>ecso5f(M)#O-7P?YRm<1>U~B*5#r5BTR2Q2d$p9Qq81E_on%>x!m&jE(1B zA9p?sam>hPdo`JPTUs1zbp6oj78{RHwl{u1P|RvFs@BGL;hclV&&a9akBmUu%8o^q zAS1XIkG}=0dCUO{|6ES`#=QzO2~*r6!##1w-kh zl?r4hNlLcNQGyC>%B&G1a`OtN*bQ13so^vAcB^>4bEjR2+rptIV7lo6Kf}&^=-Gkm z8K&vaH;!eq6HMDX)uqexOV@CAg-L;6>P{!fPX)*?&#&~NZs;v4l+EYVZE^N&mAg0= zFSU(pv**}=W4vS6$gk++cn>WbKStWgK)C(1sBOop&QB-J$JP2zM)N5Pxfq&HP;sF& zA0d4phKtWmgO6PZ%_pN!wET`VpO5@ZG@lHlMDuyuj@53O#~E9VirzysvT}WuDxJI@ zF%g=mhJ4<>Cf>iZGy0^BvvK;T0*A}D5`S-Hy;>F9h}!u_V!1Z5a}%A`{~%6l16_{T zR9a28)wFK1R%^jnuyS z+&^~wUw*lDd470#?%xnx9E`TF zVY7wNG60GTCx0Ku=O)^(pZ2d7>|ZsaER>yLPAp{vC{wpYFKh!Uwq4qU$~T!32jr%x zRT^%TxeHpPknMu1Pe43{YG@@EL90x96uQ9mXyTMKPfc^THvud%h9!)2=8>Vdv*?p* z1?+y}ky{F|kD`dSf~T@P5vC$dl4*STG4FdGuyP zn_TEnDj#_A)@xM_J^b8r9g5H>B_U&m#LgDW?a56uo8>RW(m>9}*+j(CD)nO0inNQb6cvV3nt^Rwwu9GL{XsYwW|pJ!}Foaq1q zYD{779F-Lgb(Y%BlHPbg4Izh~DG`U@CpZ#49CV`@M|?Wru^7je1wm^&F|^hR20;Vqev&c_2An<}Gl^)xh`lxIJfv&Ky8q?uXr4UCPvry3}Tw*T-+kA++U<%GaSnfB$k-@xP%M^ z_9vXj5{l|X52VXR5O|B2K_sG93M&2DDyP%H%>RmAxoU9-iLEx=VTv}2OJhb?!05-Ekm+-BNbmG ze=l4;OmsU&nxW}Fvqy`dZQKNe3r-p(cTt_kkE&<0DRQjfY&stN^~H;42#b)UA6I$M zqCYvsvO{M)#0w5m3$H!vMR5-~9ykv)Vqb?Ja{cMgEPhtK0MS8f!LbNbU=kJl(da~c zv4BH-lNdt$^{_yEl}JDQ4JlYW9?v9N2m%9t=RNl>DO`yR?}h8&?b^+z_PxovRC#pT zbkbxV=RmLKZl|OG3gwThbnb~64dl7FJn-ETtT&r!sqWG5^qBZ}xX+PJ8n-{3wp7Ad z%e~P%Jr82vQ3vLkl@HZyeJiZ?w5%8l3RhP~xQ8%FfMAUy)57zYKlF0$5yZ4$A4lT{ zO#7jG7`+`F4j9fP=I@IytfbDvWe7HjsZz-x9v``%R{;b%9c*`{UY_6G+5d(V^7Y>S zH$o2gkOG6p+i}aGzPX1&*YCZWFoT0O4AysFfZ(v`V%5>a0k+y2>jNaUmbD2I;PJn{ z9nU=nU649Bx#ysbos+#ipfBnQ&Q9Mq#mTG5ysNfX!_k_H-SBhc}lYQQNZY5{xIN z2*Km09WG2-yZ}-Qhv)?Vnc@#L8!{9SmpE$f4CK|M1N07#k%Eo^DwQRJC}#dxKn%;_ z{LI9l&3*_mEJvk|QzHhEEP(lmb9kgI@7s(*<2-m2M zg}5RuJS1@;ZNk2z($Ult8unhDA-lQ(q@7c$ICHZW{Aa7u;X-A8f*axIbKIQKDpTNH z!@bpX7g*uI*z1EZDZ+`*gu^jp46c-@3zyK!^5S6*{5G_iI08(f!9dk!W3wp&Jp1Ox z)9*oj3we9>%P(DpbaCQVM$^ux z6(e|WB#|u9#BbzpffZ*32xsnKuLKAp<08NbC|e{H!yxO-#Cc?BXUWxCzj_4P;(r{Dm#_C!d@;-3;>_(gT$B{AC2Y-915?0!J}=<7w*=pP+KLC_ z6M_Mco12lrg()yNPjJ*scm4}bVs1oK*gBLue{@06v0HP?{M$M9LL*MP+%k#YAv>b6 zR-l}=eNY_-=`DJ5AQyxmCCwJLFw16Jy8T#mCj?GM3r;POL1ZZL(6S` za&$DMUn^G$*Zo+!AMJzBWq3z1_c?DS6JOmOY)CLe88&gCRH?mfuWF|eKd)x}x7!Rq zyHiou0~x|{;$ExO;k9Da=}^r2@UCjk`9Mp4)oWHtR|2P1KP&nmD<$3|FM_`w_L}#+ zXd_Tut{k{#rBIYWMUz}>0khU>nO2qdcZRkZ&=?<-3>`wqR;}@h$x3OEcvfQja5&o^ zYLxJ*0%K$E`J{*kO(LS}2NQZaBzdiiBh;s_%R2J4%2u1sfMj+1A%pprHw+aaS4EfD z7z>&Sf})&$o$BP+8&-+~7rXNCMuM5@nh`*#o2JjiXW=|a3bZaVHiYCvE-aZLTp2RL zxGWuFm^=r^^xdXL^xT+`dWpTwd{x$!L;?^#Jj4p`xlx;YkRJx{64Ht=Tj@~AbyZr) z_OML1foEE`SE~g*HKU<8v3OS^6w|QYt$xl2oMtv(&9r zE_1)hvMuCS(=5^~O;;k)_UYyS*9U|-xAS~DtW`|A+B(k?whIypYt2| z&t2V{lmwpbp4a3vhHQjF6EjLuFz8mnaPh?HRhSnVME4Y0WNf)?{cFFTa{eaeP>N?!)Y*u{&{I3 z9#bUY8VuYC+cA+)^>|S%vLZBRQ>JfmfAx9Oi#IrLkgyxuFE=-yZ$I2X;_?UUFE$?5 zd^x0$rj%QsGwcK!6A74PHXn|8#cUsj3wGXG#9g-bAlpT}vI~5$gRKRGsCX+#5ND}J z@Ry+Vt@y2@e2KfBth;KU9?Rkomg@Q$z{r#j4>-SAU2mjz$O{@dy3M9QPbhn+nK6vLh@}s+QbzFSQIdVGvd;%m;}`6NT|f{~cm0 z4|mWaw~le&mu@)De+FSd=!yc%oqVKUw}Wvzyw62|yNbwy5e|nPLT9Imi3@9SS&33T zIZ29R?;b-FihcrLE-%mZzuJ;hBrcG7i+hIm(5T$(t2Cf-3W`m=clE8@GXoMPUPEx5 z_iV1?(DjPMq8nXRn@V4Y93<{hhUtSm2tsQhJ%UaSh{5jSPL#eOHQ?6t4dB&g&1i@- zr5&KMHU@SeU*^>+XAC(Ke3#zoLa4~m7P?qqVpzGd4yGV^^aVfl2L*z$EJ%)c8Y7OUgU?iU_BossIV-Ia|Y=v9g4X&v38HaM&y>d z<~`H{u>WVJFE9Bk~a*?J|dZ|-IK6u<0@L)O~_m9v5?#qCCzYk7oeBahEj;v8A31arE9KdHO~ zS&fq^!H9v7x3qB6CBfqSe880GqRo)UHVZS-9J|KUOB)%5}76i)PrbX=1MW{9|f`i5|y!3`3V6vUlf_HY#%yY9ElG>Mw-a z;X@4ifNE1h=-QC{yV5^7o`N+UjfXI8zPHQhg&tIsOI}-3p+!T#flJjzbZ-SJFKp^a zZeUlBMG=J#CC<$XVxmv&9kNf%Lk>eMF}j0cidnN|wFS~R?i^^a>j}2_X;G?v3W+0f1GFJ44|>&n_ZxqBR&2dXHfk(#vnI+0;b*YEVhi6^FwL z2>subsQ^DWpJw_Hr=~VvJbe5^B04!5NpdGgKxzbsxC2}OB-oRb*2kw|cc6*66`&5C z?mwTHrggA z*4rBEmY_oDYjrT%KN#ab+F#rk(vvMU_*0etk^9qlK?F9A#ErJvJMg_XwFW{ddmS#H z)adS-f=}pyq32{_eHv_ngBk#+1>CKEwl|#a)kwL)E@XOkF)xDFTG^}B&3t04YaU4# z{TI3@EKz8@vs(8o#`SUO)y+Tt@sb{J+AS>)FQ`c-RuYl|-{Tc-Ai+^vMOI#0TN%~q zl282uEIolEkaw5Np)T{VJ{)ob+aT~#$=@(>Vuo0jiklBFC95teo$G%7O4uvb8=$|@ z1w8KcE3H3ohJRhz?p}+v8VM2$>oP6s-&<8-FOW`5gNt~fOcD0Sm;;=e6nz2LJ0Hu9 z*FrIHGpLhDBHDQQ!OZq#8??l>jIsG8d0>TCD>>d)m>V6CQXuk-ETTYRH}E&oam+P^ zgC%mYHmoby&2Y=rugUX~t?V)`xwLL>mDUZbp{I3B<;x@96g+)`NQ9f#TAKDCxeC;a{mP z<9gBXw9J6&a$KMcw+7F`0{>xxq3U?A0;Y6kZIvtLnOe1A??l-VOq`t1N|t751*>&Sv9EjhOu63kgV& z2Ff$SnoTxUep;YOF8Ns>{!p%Rk?D2|km*~nvrV>RuhsUp*tmT%y3&+jf1|F|z~1>e z8erV)M->nlAJHY;=z%bm0QzH_?uUkdqOZDP4=mGk@9x3)UhkT-HZz-)&4Lt0SFZK$ zUT2XOK7!7lBVPmeh78wd9@w8s1FI85Hs#tWY-BOpV33V?*WUrK%gsH6@QiWVzrPR8 zUqeA+W%-tY8h(09x0{A3Ur##5syLbP#-_;7{Wd|_r*qCdINRF1TAlJbY*-qTY2I#kFd&HU z12%(eFk@^0S7#t>ayGUa-9y#l?sM#5{TB9aL*q6%(t3J-ocQT@cbQ>*h;y^*E5RP{ zaQ1c-&f>N@+8!kHbylYvLCH7sR?L@)J;A>xm!O-W>~Fz-KO4oA!|^Ist&O{_5j`m0 zyw%<*H*+RP(UJ3JZw!)9T~G8I8gIekcIrx&c0%vubctKZ<|*&O5br$!Y=8q@h3h0- z9~)tg+&}5b+W5>Hp%JmTk=6y~!=iW9$wz~0;h{M~6uG!y4@QH*aPoUCjzGBTtZu9d zAbw0ILG^e7R}&!SKmz!5KJhMM?C0w+7+`>yc8v!Kb>Xdo$7)TBL|!6X!GjzFAT|k@ zHfqZ+(4Eej6$s^8-P;ME0RjoG5&y6R3D7szJrL`rbus=`W(^WY=5e{@7@*N}s`+{p ziT+!=pxG&I_*P5#;bTPqyms`Ng?K-dk zPX)GqukVZ|*L9Y~S9}eH)AP{OC?GNsx&eg{oDkkmPjX=iEsmfzDe74kAAyfg?`Y{?OnzthsW0c(ftF&QIst@L(fk{qSgeFq*AGmneYAO6g~JdUU$V z@q$BXTM2*if`$((5V;E9C!B>pGhM30^`w|;(ce_Kiya>BL|0&6sZP*r6j1`mkd$eQ zM4_KY6qFRvbuwY}AEMo~NaskL*JgTjGG3wOrFR*Y*anfYx?%(ZOwiKmGjEo0CpKI2 zk6IgO(sntLt)@-gb@2_B;-*K^$s%2@LD*mj;HY9xt4&j|$Ii7~QtK%UP-+Acbf zof%Tl*Ld``s{Hzs|5mS7V)s2p_y_{<*Wk{WN0^o7GB<$EvDBBFq!kxLIdk{wXV=lX zsPyGTwymH9K{V7A2sh?hR4Di_JepLtvp~8M)udsku7%{P6IBK)iTa3)9%5HmtN32G zH*~Ff465M`?KX5M1t$5u30OH&E1VCKU(hF{4FO9BPapZa-J#rh;%x-oK8JCk?L*4^ z0Q-m4iHB4LZQ4M)Q0`=ISR5bHBoPd>;j>;n`|C3(eX0QZkPLFhQR-r6QB?J~5&89d z1gQr5jSz6`{=m!}h@{^!WaDu3E=0QqRGJDKPm(fG!UQxG0#3t(;540@{UkGnOj;wY z3Thez_*6oyB}QToA$qQfB$gMxhOY2EOeUlvWfUGcHqRcw0Re!UGE5L8x(VV5U`f9j z4H+GcjzVan$0Vv;s6%OB5XK}<20z(JJ3s3mBZFko=8Qwj+D!QMuL;z39%)D$u3LyU zcZMIVY_a@9_Tw7Wg6j?}M1%c{$&2!1me=^xxA$cTsFise{3Z zcsM(otG+W{na2#(M(uiyo~8MC=Ke+V)&O_eF>s*_)cabNWoC|!$kAN2KttZ<@5nMY zdHx*QTP<`kgf)tHK{PmF&!i0amLz>H>(DuyYiKVJB1bynwk@3aD8fWW)JTzsSE?VK zaJQ=MoD-IWI7MIws1-?$Bwi7EBp1b1!kT#;qwSa>nN@O+k(pLWTpq=&mQ@3QMV7itz!>gs|-CK8W8V0S8Q7>MbR z^Rd?DZZhPyfnMO@VL8(o4h{=<<5XkQrVdcc5$aJkD zi57fk0B1GDZNokk}%%E>nN8${VPMShN7{Qrfv&_F}$2{adfPb+5WU7{0kq^jwN#WgB5D-L^Ui z4R<>L5dQ!s{-HAhk(W5CFh9uA$ySJq9($tCr(yWJ`$2#OTSXhqtrRxHPlk0At^=&4 zTH`A6ZA~wp%&V=qv?J}p%J}Krptv{ViI*WgxK(mgWj&)r99se)+@T&Zd+Xl+brTa1 zr4xwlm=0!$q(J%2X2~wSq|AxMSy(5@BLC4`4=~Pf@1LBP(;xppCU=0y zBjc*HO=IEx>d(Mscb2ok4_Z|z<<2&w)_C=8lM0Ju$laa5~`>!&&R$fFaO)Y-TK2`deKy56sF2bGcqI6tPQ zBiqR%KZlU#^*~Kw{hx~;F%;{_>Y zGC_ajaacL<+ajz~6@{vyrDVMRJ-H&#&*yt_?}gf{eGhzBrJ$FTD?31`EUDiajdOGa zlggqZtUIe8nrX6p!*RWQ+5f3UH+4|3p7aYAr2&g?3JhXjcq+S*&eeOj4WZs$!ZZN^?~(KnTe=5#@x^s5~*DoHhfGc=tOX1NP|ICDX-PYUoV zoDu>-OfhLT;I%eAWFcU%K1m(3^!5OW-W0;DshUS>W!y)8GByfNHZ&K>3u4IZSNbxA zC$!}Vj}l(z5S%=tu&x<5R&SU<;F%5$f3<6~PD)Y~S}gXj2b$*S5qW|moQ<#un+kzAhD4vXi;A$?E#1ARL}Ln=>RVZKp?`A92^O3E5=*5 zVNz2##NyXV-QwyYbGqQI1S7}h6F8#e76na))7@{Wvs#0?Qh@r>7#(*@4HKvU)wr=K ztPRhEBEz-w#G zd%rwGe~5V8d8JPRh#|As^ccb!X57kwxH@4efb`XLkp-3LPD*9zco)?7Z6Ht3%x{%kPhePjxP0nDp5HJ9xPQsV7bhdbMN zpoxUQk`bnli45Mumbug>$Pz;+s(pou1@8cqwGn7Wd$j@EpKy;HtU%GKB4}JH+KiR0 zk$|PT3qCcJ6fvVUN{UNjbK_vYteR!!%g3nv`vp>&iK;%&N9pPRnC$G4@cO7g1+pP@ zst@1@Z0~M$la^2KN<9az7PyH59j|ZUHR{eG4R03ff5jedR)-^mx)Z#eFqv~h*^M>Z;!AZ3Gu_7+@Pp3lLC-&UMeoP!w_{H{vANTiW^%I!ChGpG{8Se@=kQ*Qm!2ujrnZcD&DvvP~19ZGoQ+Hug1oSLA|iDpmfmQS*S zCHsRW4s<6-Gs!017%kRXTMF(*OPM8mCV*E)bAt)$USL50is^yEn>58>gj=$Z#4;jL zli9+Sq=H)Ay>{)|Jz8M2H-NRkMO;UycdP|nEEZerkHK*Vr`{%Dk0(b9ts}3=en_5o z>G~_Aa(K11^`D2YKR>*Vm}AMLXR1OJ+N}dkaR%r@e>V9xDA&9`-NNz!S-X(+YjO;q zv)%!sN^fovMZz`H2wI@pPLd~4HFAWOFz}dWvluZ@LeFU(#nu&^(7l;K|LjJNQD!oX zi#A!X;Tg=APusZUQkof6AZzX z!wn*BuMBV-y^7w4Im*<(h}8(KVDy!K&|lqIsCyeWK~^}KmcZoUN}-`h z*N&rlk0FrQdT3n6R8O+L!d=#Mj*?wh!+Y>0$xd6ERKWY<%>mMvM-GN_N1aoLC>A6| zLjU>9mq8Tl-SYsp#Jk~Se=?yf5RYP+G<4migaWwUr4NL;!D7~N}AHe^<*Ik5^ zWIew#T;nyBQkTKov)L4abUs&l{cz0H+xso93h^HA_h-xB6A}@3%u|JD#o7y2x+s(- zjr|t*lJ1trRMXThEk!rHWhp0ON3;RT8q=t{wyCIDwkQmy-6A=eDrPW({L!+TR91e~ z>xHH|x2L>6I7{qn+ek&4e8@;mk~w^593gnT)oi=6)>!C*VSHy`C~@cd^U2N_mm7s0 zA9U*acw4U&8?V-9v;Ju)S?A?JWBKH>!34JXY`UWZ)&s9>< z4L}$!!SoV0EiD+SSFa&)9!fBcaKfM9=S5u9zg2hN_Q!+K^xE6u4z3v+?N7ej$9bjk zHPGWdxs5B^IFJ2k%UNJyglt{{sky5@B6gb2kL5!s=N-JP2HE6l|rnzzbJ)`DVzL_zZy_x#G9JObSg2SG7!>(%Sq-zAIP zKN*b&!&&sxQl+*gY$d3F0pjT_KD<4RJy8DYwP>4&x1!uh4;pxj4#1g)3Jb&&@#ylL&Hdg@14%2#`ie~|~ z<`DO@jRzuA!aHjzG-yhSPa&7cky5)Nbk_HYDf^x=aUFTkKr*mXb)Hl^#Ls}$@FYM7 z{+?0sojX5nJiq^R^YM%SwT*A`4}NasQi2BWZ+|AnHU&We5KJ8hR0hMHll|>bx|Xer zkjF4&V5||Jv*I)IjW0E0ZFlbM!duA;zgSJ2Xf~1QmS@ZYFH6{0Zd|yzt(x@58qp0` zOplzDri$tS2uMlQX#L1k#VNlF)ae?K0sQDxyf|l6z$dnHkNdM@I8VmgdfE0i+*}8^ zsY*$iF~~YQ%7!*&nh1I0WTJRIBR$u4Cc&cCnHdEGPo;C^>x zp$+fG$drjI@R2*nQ+kEB*X<0xFpGEYz>dNw%93m@d&?dn!;^qctqJa95N`d)oM-5>3SpA8qC zEO~50Qh|K~E!E@Z#Fb>e9ln!tQI36no`YtUhgCf|m|@ZV8)7}@)!p%Mh`TOw&wB9U zIe_l8yIxHt2dsw8gy^T8{_H2a$Nbixbk(QtcxzzxR4z2e$oUHFytihg9;*4My}-S^ zfHK>xS?2+dB#JqEIU5dU{kM;1!~aH)xCl%bMPg1!7+5B}>deH_pBNv{n#YZkM`+m2 zLx+Lj6mg>dMN&nsG@Z=Du)rL?baYqvbBW`+{;Br0{32iER8g17C9>fHD!F=V?<@ZsX z)c&5ThdiiVI$6Yp8R*!r0#-JO5FC%`ze`mI0`7r7+E8}%AlLG6t^f>-3TzdLOtKUj z9D^zN4?QRIlcOWtj9ab$u=!YQXl@B6AA>Ho(oDm~(&!KafI$FP;e4uTxpl?!&PF73 zoa~;$MQ&UaddH-9T=5{%z;pLmpAj3+1H+Kof)qK;W6OvY60ez8q>qlvo2v$Y+(+5e z7ofD#f`JErcSsjD{HtLti95S*7jQGEDc5&WB??*TVDyZ~)3?>>^n?}=u{C2xa&c}T zHysV3q@%pGnvVg)(s&>aP+a8+gc4x2I-2Z`PX=t1K9a$3JUYbXSTi}`QH@7G539?* zj64$4Ef%#fg)(9)uEf%*nKH&hf?kd(eingIHjjQEGDJ{r`qGdztU&Lsv;;r1yl(;9 zjax7q1u&WVjQx~AnEN~vX$e&{TCylZG#FsirPw5pzxe6pWaiF5BK1j)!H8*VXP!=z zh#_#(@vL_2*=H20a0#9HjQ-x!Xm){yjke7xJ;-hE;6J9_)i%|}3zQ;1#^TqOyVt$1 zdaikcg!B=nJl!^Ra~JLkD+<#H48aO7TE&ksA|EJl)+(mMTwNuiDvCE7XI4 zxjYq=wiyeHQ;RK}v$oY})e}Sqd`Dvxi1h_#<(J1cR@kE=wtq_`x33?^cw_PSiv=rZ z-Sb#bmdXw7lFkC&d64d)OX!izr2_1sxRWkQ3ZojsvUHuA<)DT>uJ#lf>Dw4n`|1~Q0~%$+!w+n$<7-P4|wtn z2`I5lksJm0fj|+Sb7Sw;wXcvDM9!Y+foJ$0C)JnNZd|KgBDc@`@30Dgu7L1o?uxzg zt2noDgt^g6_tXxL7NLYjR%1T%QwLney=&XsPc~ls_31-iNQd1xcbayMQxdyM=2^H) zOM@i~s*N->jBqE87oN_I?U$Py&$l0LJj1n}DQrsiOM=4wqXBtP6>3r@<6?C_WP zJ+>E);W&#j7w>gOz|-oW6NrTnXDb(AOR}8?%;fQ=gL{tG7fILagxU)8|^Qm zIt6PP+7mZZg8-YTN!(E#tI}t*h9~n{wG9H6H#TBO;$5{Djm2mAnYzdpjL1N0n{QFU zxio6yC{ML&!gMaJ%twFMLvFQdeA)>;ELr$Jbt0sVoI4s{2d9%lP)K2Q;~F3-+%|^4 z1dB1{l;tsWlG7savE~E#IplRZ@&UAg9MFz}F+oIwZtAuN6G_1G;2)$;8+P9qrKqMS zS;``?2w!ucBf42otaJQr13KWj8)(CX>gr3wtGJEu=Aec>Jh@#_y?cOz6>>LReJUuj z5##g?gPCl+sUuzooB1#5Em${gXbE#E&5GhoTnpMSct$r4kB(38>!=q`YdXxO=XRMv zoO_0w@aNN9$9y`1h3K!bqK`EL&U_=Gb}cLiiKUmG0k5=xlFmH|%^`G8g2Tf>oNW@+ zYG1Gh%(SOe)US&qh}!k5Elv|#;?}B$a>O-mZ(V88rZ_WNe&O(P=X%T7(Ecwf>{sZA z7m*(w@=(F4f-O9T-*CmViF~eXL<-m=-RA?#Lqax@o2BeR9BHMV>(c^uPKXMl?Fq}&r zZ@9Uk#Mb#q9OPEm95C)hZ>pQ?gEu?`U!0)oKNRWhG|0#e46`sveQnp~HcYWa_tkgs z?QPjuw}zM!OAvaqg+8HN z4xhuO+~f$gN>g8WD)BCg*<4~mTi{-0H-^JBW*mTM(Z(Np>cjN--oL+myz#;!aD@Zt zY%V(W)iHi{C^}*?0ji|u=#H3rKJ1TGrT2vjZB^o9^=b8OZ~?e7I=qj21g%cX!5mB{ zBoEx>Un2d{Y{aOIIr$aiauY}MUjGdQ5j0^+fJ#qJD$!@aEeqm%{=x8qY1IU z?zkSzrbkD?3knKBzToj5`2fi_5=s(JuJo+jrC}3{$~o@A8e*fG5vojg zJl?|ww}QtQG2O0eY-G!_14i`T2Vs1YsTOXbMUfKL;})_^=cK_khRYYhC5L+mD#nS9|M5g+D_*I7jkF=SDGh)4%i zr(z2^rn?Xm&aqua8fx$5)@z`Jn9H$I@6CZ@$q3f3tSf9lk?aer$*-OxA@!SF63}Rr z3w~wk*v?5wyL*8?xJeCC<6XWOIwQf}LPXFI)fi8n+ODzQ&#?-TnSe29sk<1>;DFF1 zVUX1WP>k=9nLF#0TdmUMpMpo)bcaE#_FQ3W&iSTm zzcu_Tr8pKa+-mc|A zYH)}%Ly|Cx@>%kfBap!>E)uXKYpHeqy$5;|A1AyxW_y=$-!9{|ovRh^DQZ=W%0!2m z>j(r$j4w{{i+q=i52+(&j=TaDKBNUMy`aia9MCksQg~AI=v1NW#7Bk zXJi*HAxoOQjWHC?Wf>)&FGUaD&&yCUVxd1lBdU;{%;r$PY;-$AoS7u+_fRDYo3PYb zmmh~iRBXGvboJ7!cQ+oA>>9<<-NuYJC=q{WYVhX$ty_QVZj<(f%o7_n`co+7U!ugo z)zuN#&^-j`7qpDl0dl$7U2PaEK)bmve*j@7;)g$inp?CUvSmF-{2FhB&H8~@_^~|=28iaV z&{w;ab;nf_YCbU6Xpit(L-^=o4cHP4AtA9gj6&>`Ad9YOgSDcXce_NLX^boZcZBdsT{z`zd7 zF+;{y-4l2pTKEcHU(G4ft+^5#Vg5(i{XuPpBlD~YF1h|aHB^uM15el+K6_mXkpT@F@FiOAPNi>Mp-b(vTu9ZjJ*VY6wO z3La1&YXV3czxC~HVyaM&cT?6{U&};%^M)8Rv<2CZ+?wXy*r9nxbTZJw$cV6jtZNB$ zh3eNzs4VRC1Bfu-LYE2i_UUp)WV2RhG{4p_+3F3)$c-=@ETHBR(ONfpw)V~)m6+T< zT-BpYoClxPBr-J{LkxN1t!6It!P^_O}m42q7EKGl%`n*{OF z!r@bJdO03A$u@N%XXMNp63@C-=QG5=g^8=f?=;iQrsU16M1aC!Qhz61h?dZ{jMB<8 zSO$aD1rx{nw;Z_x{4KM5NJvAzF*bQECwN1>w# z&^hQRt^8qh6sRj%x^?a)RNXWhI_M=pw}4*sBDZr8OR;aeIZhkhhVlv*DvvnmWs~(W z8R3ScI+qyYs_WnC5Pb z*uLHQd(8AH$49C)VXvuu%=X4uc9&+U+5?V{Ew4+uUJG>+myO%(U%q}Ba^-Thbr~G@ z^6Tod;o#1f^UIfenGCO~!&FO?cDx1Dsj*qNMg*xz`L2Ge%cd>d`D)$(qHf)^K#{l5 z04W$K=Z5S0<*?-Mtd-#motOo2E?~{TsbhO-?B!5amz7tPFq;}s%YfR_Rv_X}8KNJY zHyOJ61z!Dt)4BS!E%CDFcd-iPbXQAO&YTg8YK0s!OQn>ttHh7apH*gIl9-TAX4#9* zC1*`XVA>zbfoZIkeqO?hXlJ#Y{8mTaNgP;>51V6;W31p4hCo<3Rsk9x!HLnxIF zvZXL^gS)F*8CVesaOj;kdk_coO`ZYBEohqWEO6c&La58lAsw&l0kBC5*@D8`aewZ| zP3Pas&FooqNO;2abT)!Ny^qEf1)qPe(h=KvymT((0`{)Hg=c<@W(yCJgLIAU2)2%h zk8+Eqk2ITvj$Sf*&(=D0oMy}7EKt+P4-+R_&S&c8a%`5viGxO1V73(0yC0#%Bg zh$FC!CG%ve_V=SY@iM<*&-MDKy!9~rM3)nxA5X7HnMk{um137yyJ!FIC^_Cxxrp5e#ItlRyZ-xtoh|vH~1FsSofsG*qzAlZBhsX`;?(R% zVBNKzX3<(fEZ+V;llWjO4@bA*dY5dV;LBoK3wGZJ9E+#9rAqD;Yzq#5@csJcrkto& zRe{?_?FYyIu+)L-&C|oZ>EyKaW>#JX;`#JUL1WhDj^oy@_tdsP624I0$d`52;C0Cc z{y)@#)i4GK%y^u$1$;O`xHB!s%$7b)iO3gdh|$O2bx6&mHYiU@sZ2KyK?(7qf-E?k zrkFo3=*`W8F8DK*Xt_baOwdU4k2wWS{L9UQgJi1RImV$PYylmaoMVuNepM#ZcI3*V zn3g?nR}1UupdwW@W16}asG-gwQs{R$LzkSNYh4j%Jv*0azP^zfGdoJ|jpWwT#-Tgo zj&k-6-(7WO&_ou6lwCq6>SG?k?Et`;3cbTjg52RJqGzgk6g}fUl+CguAeTi+oU%3{ zJCjS~z1G;Jp!8BKCTRtU28*jOWfTQ0O=$8?2Nh$fO!s36*kunTc0!_lbaWD(jkL=h zSsIaAh>4lsN?vB1RKcb{W4!y-&TRVga1u7zG#tZdIs$8G1gCXujOGuA$e_gi9qeOc zL)?lWaT<;^MfZ#!5llwcG{=faF!t_78OrovRMs>L2@_lxXCDGu9QN)|7DBox1VzmE zX4FJ7NaI!>37I-A)FRi#$r|ZL^`#KMQivx?OM9@8Y?uQ<8g-fWRqiE*F{Q2TAQ|V+ z%?gWf(Hf4kM8%GXnnkr+LSZH+(Ws7^ck z!0|@JBzyEWtBfAP9nwg7;;f}9tUvJdv7N=M79T)%Ij83|O*Qx_o&mKdJm@)f_l~J8 z)pr+gXc+>~y0ARExezp@L9I3il!x`X__1@$p`oxxAz+r&Xs_vNUxxw&#oXLp)Y|;J zR}6?yrMrg1>f<3X#f5T9}yz9IC&zK zkT0NQ~$WdECdQAigQIE6=q2Afq znh#{fy7`A%gbrN$3iRUxAS9hO)%~IjGFH2`0HgxwM$L>HHeItN5bGYgE5>+aDkx8aielmxIX_s z`smvt^mUvcdnA*c9~xA=yAVC|@$uhYDk;sbwyuXDD}~Kv_Ha(tEbM1sVD;v&6M{{= zecEPbAI9azO8jJOQry$^Qc=%L$_KfQrAF-5tN8p2L$$*+`Eib zL{J~ajo2hx0K%_DrZhL+Qk~tz_M>IA0}IyFZr5kC{%O5q9Oi>&p`DsaQQu(?2R?Es z3gi`achXVZ{Y%Jw#r7vrF>%2yK}WG(mbj#$8G;nj2?@)Qo!DXbRAu-PkZ#E)bo1o< zVz^`()y`c2BYKX-A;#I1z&wBAB~S@EWM#F*tF!mdg1YiP41|^ZQ$O<&`qmB|H8}Co z2>}}`u9&u7vgRVXy+Y&`(suM9@@G8RQCoY0o5C>`>#WWz+=S!)M}|)Z+M;38*l;bj zb46RjP`A5qD zqhX>HfW}UfvYjiy0|c6@V8vdcY4xjfl60IwZpZ!-fI^ct9TJ|c6%S5u$@cIC-Spl( z4<6}DXX>FocJC|fo415&FFV2@J{rPM*wt2uv!Hz8+$8W?-3ExE&5Hq1#8?}6@{;qb zSUMM^R5+$qemJ6||B9h-5Sv7u-u)Wb4N3ycFB#y0Gy_qOheD9x@y^C&1;t6(!qcIcy0D5?i40`0AK?;8)ma*Sw?KmKm5JnM{ z@CT>3n1ZHBaZf>Sk`CtFIS$nG^VoA=g?+lkd$&e;j^W@{kbDwnOq0+81=g**Dg0JG2*u7WQg|f?~!8pV92SLk9UCn`j+#VExUBQHqx~66SfK_w7mu zjB%}B|K-zhigO>Qh({G3PhfP72J5r^lS3S24=>Jt*nw$@+T-k$CA`Ww187fZ1|iq| z6I`D%tNwhdG7g0Oni*`X z*oT9+Ou}H|49NvEDC_SF(Z+V`R5o8OPn2V1d9O6zHrau7>zpV44O3N*=}PsbSQza@ zT-K0PDekC{4QD_eRi(obcF`c!si|e)iT5Ewmo%#r7`j}a=n-bLXEPkb9=*}B%QlUf zZNV8tfYKPIj3NlXLpOC=Kmn+^>3f5-Gn=?lJL(#vPxyL}dJ;UNP&9;B0L~;|F?oy< zArY1crF!#WPzrRTpX@yVmibx584;-OuU_%rU--}UmhHuewtyCCVf&3N$JP9OD&Yv~ zEqDt}C(U4Km_KoEw~b$}_MYIrxaxq};c;mW^5@~#t%QICsDzAKcXn0whFMscQY|se zZN|cA8srpFQhybvGjAfGHdfU~jVghmVkT)m_y%QDz1{STdS<#NSTaW2Vn?ZN>iPUN z<(IAT@^Zvh`V%b{Qzc1-_gW3~YXi29xoiTn&&z~8K^=Q@V1GILz-soMjLZgPf2!|< zx#4&cS!GDTO7{>r`_5=QI`%sb%P2t9o1-8%1cND}foF=Sg=2Hal7ueEq|0Ohef&Q45cW0CZ=cz5c|GAR;(i>e>FlR|)1ZPUg^9#5Vm zS`Pwq5#FWcLLx37)zJo}X#Id|d=`yTN{Oz{EySj-D_ ziW}&6h6sLMFxP4Ss#C4qtA#)31g8uy%Ed%8@=zn2@uem))7xrIglMjS<47cD0V^Yt z*a#_YSM3&od3l2R;)@39x&3oya?;QV@#Tbp>K(Zzqn)yhk+}V^6o0XR1~2=MMt+9H zl3qe4!H*TmR%PPZwK2t%%1FQ3AK}^nxx~3;CRF@c zlv6yzBUNnD!rV1gq4V5Z4$k;U9M=zroME0+T$Na<;smR9Z3bB*%X|GTP^1sotoG4% zUAgN%b10yz^;Wh77&ytZYv{vW%1hlrpWO0nCNwNy(Ga^PcjUJghG393h>Axg8i1E88n8;oG|C!2Z*SrzTlI(Y3^rn1e+*`3X7fY;Scj zsnC;>Guqlbvp|htN+7h6PopIx8sW-@lEr#DBLxqpW88;+1`;XVGXBBSnJ;n2vs!Xz zpHZyw5<1Vm;y>;*wsQgY+r|izcSs)^L(z;UyJs&1#02&)Sbnd##v-KtlDVKh?iDC< zEd@!GT1BG0n4pQFryu9qj(j zx>98*=%wm{h&JYr<=f#0$XI}pgysr89PQ4g$Mn-mgfw(6>@|2Q#;m(sqoM*_62NCl zzZfjKmh_U3!`@4DJ?E2_GSbkVoY^+4n13wJ25aPrKaJu(3LH<&{hSd`4uZ#-F*i<- z>>;=L8Bx)h8M=<9&FCy$0HLNy%y85(A9Wy};PlAsbX6N!J};}mv;;W@d#p_Jy0xS{ zg(QHF@jDq2lEekPTxJ?axlN>zYBS@IoGjE#O4mDpJ*9ULXt`1k)oPmB^GcGGN&9vnp8gUCW$sO0!l%X_IAuCTNA2L6|MrN@4-r833VC;;#8B8SHaadC8< zAijntf{+X?M$0Ul;M3D?X5AOlZn~8L>5FOJJjMpep~_KzV`{+)E=TqAQjJ%~$ERir zCP88A^Pd^n_}_+Fzt_k{M$U)P$sczF)rkzgCIN~?)+bf=(zCu~O=MK#;St(I{<5VF z#~VB5XC(}QlNx?t-um;Ot^WXqsb7bqcL>*Ed5#y(w)xxPEH7)PY4a6XJ(jBva9CU} zIY6$r<36#+%`1?KdCDjs2vw`iwy!FqqmZ%TS-r_3lKe0@SzAFcrzM;R`5E^A@=$hZ&zp^U9qiP zLyN%mkJs)k16<+A1;h2@W1bSh(Z2*pbl)~)8*ai6LO_VFYNg#k*K)U} zCOa}_NFQ>}4>@IlYrLSNo4#&bX)-<~ig@8BoIw==h1IWp!qbXv7qH`q`}72d-kB1F z>qwSs3S7&2ZHo>9i&C!x8MrkmEBF{}&^zl~tZ-t>THO?Q5VtOWON;Nb(Hu9RDg2>a zP6lyvyba{lp7iI?O8yGmAl&C6y^$mV5DYEYDHoh6%;JF)s8xzI$>90$_+&QGNCFjs z2;5Gw-q?XKg7o2bVi2ZsioqOpb=pqgZiDvXBAcBhgve$YN3uRdUXpaYWS7Jg+CLm3 ziWVYaUU^o}w&0Wt4K_i7Pc_QJN@0C<*qp-Uw{N)sxmoTO8kLPj-Yum*UE&k z02uJWXfPN~th2J9R4&;v_GM(Ed3(gCgy0h}%L2oOKu{=%v4s9y8bGi`MT}R2Z@zf= z_=o7(SV83U)Q=6ak`s#vxb@`aOuQnp`4oDjh?4^m5*k`-3TaF{4g)b1o6zV&vg4-k zLoOG}uVgP-NC5w^hXkh4{I7!fW)rNyD{kKh;JgX`wGKcchaLcgm91?(x9Lr=o8YW? z2NEbju03pMS}ToQ91caU4fseN8S#}zp)I)AmgedEtxC7K9J^RryLEExq!j=|O5`p%TWRB0>~tMF4F6`$1R zl>>>CU9V6)+*PZsidRa*2|@U(fP&IO8wrlBSui9yg(Ud3n*d4YxZTg2%eBZryF&Kr zI70F=*@vpt`GLU-%xl)6Nyh4{geXBx0xMoXdI}!fM3%BJ6|fEjuN4PF`lt-wo%qw^ z;V#*6P+wDy_#yn&TyPDp_wOc&sMptLBn&^bQECQzzLJ=8R1b*jwZ|H3juZ;3>Rc2i zk8pJ*7Np?Tc=qj|ho@L|-k&@*mh@la&_#o9fn2dh2MA@K`U29?Oo;G)XJl%yAEqIV6 z^u+g7u;S!tDrL$dB6i-pD^*CEg%(MY_CAtgD~U9B?V3cADqpGN>w}2I`9N5IzU+-o zTpM@eD3nXYo)rx>Oor4HaA)44N=MdR6R&6B-I?5#uHP#Ffbd*OY#143a+WW6WrQb5 zo|l#B9$D+!%{a9lf_gLficW{zkxX2==t9!#s% zx5M6ejJ(hClg^NXAzgxcQ-Q8%;-m?J^|Z!ja%k2E0~ka52V?w4AuY$`=X8+=m;-af zGJWLBeD%uOJ$NU?nZDXP7~{wmb3rRfgi`i;2SI5+^H7(Z*#?KGW8^u9-LHJip<|RD z!^`#A9$blZGX)K{;e1=!1?~lXwQ{_$Bk79R!35j~FnVqr;qmmcyCatG@gXz3^y=mx z|9DCD>)l)@@Isd5G9eQ%$s3XuYh_fb#ENTcE2BtbeBvK~_5=|QOr1K1NTEghwmZqYco)n(^xVyLkQ7N+(DvtfjOl zzZY4#7h0*cm8^0vkZ^5(1l&HG9*L)1@&oMp%p)O{-Yd+M0`OSFy+!9&@I-h6`0HlD z$qovLN`AGHbD9~>6?mm0%t{v(2|GY41Ntbq2B1#Ncl$^177oGJ;Y0tnF`FQDr28q+ z`mLPS2|IdN$J%&#RINi%d3&w8k6#a`ZzuY@(LBMnWL3Lc$csU_51S7A$e@)KKC0ju z=-p2qG*+YIjBVAcqOrA`+7vi)8|AUSQD0$p`L-~_e9R6Ti?XX1oEL^)I6bMuX8hCA zi-7h86!qHJ7}|}o-Ki28;|=kz4G2-`QL5m4g`fd>vf|Uy0!|x>&|;yVaM) zoGMC!$4-EpxJ$1l{<94)td)Sn$^-lIXRj+TrW&eIhNPMobzuf@NjD5&k08`){G7D`YAFT|*Hgb_l1 z1q)-h1E`k#Hf*K^kaWIkijNPXP_In;t(-T*G3c&IsKOzcjBL004kv_0nJgB(M8XGS zDlB(fH+a*Sei#X6`=$zDWJ(**gt0`_o*H=y zP4P1+%x%k(O~zFfvG&Cml9f^_H?huIO|M)1Nk$u7lCwU&=MmeZ{e5hchM^`_!yLOoljA)zU@r6GxM1ScRClu*NzY1o214Q}`3uj+_iei+ zZo~*Zbp(E>86g|`3@>s|2B%kIKlFWwG|*9m^Fv*>uk7g}od}lgjPS^IrqvJ4*uYc| zlp1G@*SPr2sXP>#E)>~G0X50yR=fA7W;w|i-|I+$OD;ub-4LDZ;p68U4_-V)82skO zv-Rie_?mO06_~c*)7#r9%Uk-cU%Pf45C|6M*LOyf>$`;F~wQNaIDR6tjb505qk*!k&PVow>b zuss;T;|{o+U=q6YvpYRHh41MdkBDhoh2?DcumW}dn=DASt8PvpZzj7~$%11exsp;B zw|{1<&9ZA%+r^nDfLv7JTcU zfX6+ofhBgfl2(`IZ0w6eO?KH-Iv2Jl&#@PlAe23Y5$X1(_Ee{(CCFj9$hl^~itl~3s>H5ihCVXT#c~f1US8Kc6TcIP3wD2_^eXUYWfAZhz)k@L@ zuSSrO;jh7+t=oX^=0Y@p&aoI5W50_|UQXn^D^x4+CFCETz|AsEJ#?~ z?xyirEzV^>dr5NR2QmR}FN-W&$9A}#xRpS(|DU~gX^!j4(#7WWD^fDlnUn~SVpVl_ zp(#ob2ubLs2o?ZI)j_hL1dsso639en0;E`!CU#)NS4u|bYhv(|Q z;9uhJTaW!Z=VYD)z^YPTqN_z9b3fKzd+oK?d%r?i35GISX0cnC#T04lGzjC1AZ~ZQ z-p$=;-6qUyF%Hq)cghbxw0}CE8FVq&5@(44dl2+-*ULRwc9CtFb`lp!8np#?7?Ls1 z_8}}l2{0TZR2Nkxq?&{%AQ+ugJd*n98YQLiCZU;R%-hTjmUV};A+D|gudU)x#I1ot z7PCr)1j1@?VttR*%hLZLK#`msGshYpU zL8n^czSmAUODvdZee8%4M47aiE!U0_gF3-8l7j(GSWLNK+=w3eGV0?eA0?qVbITRi zORaG4gAzpwUX?R!TTGqD?Ol$BKj`&Z;SYu(m34oVce!@KeuNygizM>j*5Dq9+<+d+ zVIX$BMG$g!G=?%fo5tf6BkkU3Yixc-B9;d)1DAy2&<;+IR#(#ybW%`45$PD9e7W@! zNmTB3I2YilLB#{OFVkzM>cNac>llo0(%IUXY9#7@e|mD~Px${A_37@j_ zRDmF@_(8d2REzthQ+wyh#kTcN-OjxSojZqvmv?xA-p|P~*grHB0dEQ5MuwLK0P!Ed z#D92A>!U-{lM}%uxH=hB-5X+|RP>KMZ#{Gel1>t~ACxS;|HaS-%;5K9pFiQLtt3r#2w`B29 z6WpzM@4?@EOuc;U0p=j&3u;v0Sm9JvhXu7k+0d4<-)3-oS5~+Ab$B3@!S>C?Z9~|` zv%KWkyp*BMt0z(w(!ji#T&$`jC(T}1>^2@94H@5oj41!G^_*=xh_CpWp;`WzH$`wW zmnmM@G7*zM^j+)7c%3gVDP2pn?68jth5zCq%NlnMP5@Cd=2tCHjo85UwQArD>gim- zR5}fEtA1>SiW5P;eNg$^$=;zxq?89!UB1C4Hd1J@Fsjt)T=BE(M)brAGZ2f zxG%!RscuKZBtMv1Aml1$DO{88D%^Szh&sL3gXx{o_?Cf& zkWSh~KsOHvuK)f#fDFhTpD+iZvzUKId90DHWZ|`B!MQwlVaZJS`x*ual>I(MOl0p? z%^G1HLNYGHw~}tqLe@PLH=Y)UFD&H~un@ zLV{RDF8|A)Ml|=j2&-}T@J(E^YA|cOWviAZxl7_*CVM;8;4;@d_)e9*hAOKBRDGvqww@Rj;HI?VsE|P( ztW>+OT84-dxS$)PRKwbqxd^Yw{QO^k{?~v1FF*fl=jZ?W@BjJdfBpIY`uTtV`Tzd; z|NQy?`T2kS`TzL$|EY8T^6Y##nZ9_Pzbq5_ukE8u=_$0`qs|&5C&rhD2+q9UU+E7o z^pA#)U&CAQaF9J^d^RUed(5#HTDM8(L8eG2d8 zX_Ar3gCR9UL-m)e8)P2UWBiaM`lgPLaL|PZXP;Rkua8eJ&qgqg9$uVGAsr)leo^=j zWC+Q*nmN_u;Fi%ISDa40J6lHzxmU1Eko6hyU2xWV%qv4QS)d$2a4u$u`p#1=OCw*F zePtu-yXo3x+$y%Jby*PC?@RO)@yihsrjdxy;t`vwYKDpn%MWzj6tXi6@DdP}+RegT zVI}A{`x0a5->fyKi%PGRD}{B!TbX=T_$#x7^RmpIFX>?bQ7c*BP6yOU%Kdn2*v>X7DN8I% z)%&_C#e7+h@Xr40g=&Xaa2`-^c8`eX{D@rcpW+d$620_6af3?q{@HNJP13NPI;>WF zE2R;iXUKM-R#1wzrl!ld=hALh5P`?qr|;7-!qNzGF8C4#gjlpVD`6V9G6*(_gpS!2;>0sJ;rka}PPG;9Kf?W;o#K%Yk6U z`X!2;TiMulCdtFw#Mn+6+Ek!XwoyS)EAkBsa=M-K?2F*E3A|*_^xkNIOj#g2;becw z4+3_0y`wPY;D?T0n9vsRN7x_j*|h04RL)7?%HAt*wv!3ePSyhO8wDFsWeY=Q2bPWm z?4(~p2SzOVrObfym^2k5&RZiW*Xkixf}Ct+a7j*VTxWCda7o)A)@mmXZ_@ z{*}t^YWL{4OkOU_KX-{bykTcDd}3ITt6iRD?|HA_nlOKbb>dsh6uZDd2_;g%nB)_F@q|d!3%H4%xxx4l(=npf%!6svRi}&sh(7F?u{S%u(A)#Jp5tj zqviak{M)~+`TQg2$v<{BcRqhi3ecY)JG;XRs3+ymj~$dN;1j&@=SLr-9KZa#9UQ;= z-S6&wy!_k0U;g;+^51oS>^vOeecu7@ld}PyVDle*4$nN)Cnls12a{o^6X5u<^Sj^u z9fnxGdkqrQKvj?9uu^VzS<~VpUKyA5fjK96R{F{3iIq z20UR48;}%N8-GhTR!O4>E-a_6#cK81IKX4Pqsw!rp{fGwOc_jX_$TCnLmXDJfeFg) z*(L^UoH;%B{<|~YhA3}6;W?4lT>qBDE-!P&V_BFgOOnq*+XLa)8@;t7hY0L;Xjshegy`a(W?mxH&f=qXOjC$q& z&_Oz}HYh>y`H+ST8y;$+o)7vcyjULS`n3m&*0I$H9WMV{E0tk#w8SM;=~1tI%l}3` zmm6U!L+W1m2?9ilz-CK~6EdC+zzb*~W5Zm9jAzp1x~gJM`jtz_1g!R8ml(%`Ljqn( zYjz7YA5N8+z!w^i;tdD|F6Y=QXezPFMOA!bM&YFc+y=Tq)?g-PaoQ8*2OAo@mm(*b zp(%M-b4383al(16qP#xh4MQR60pbE-kef&;s&dql zIhpmZW7wq3B;x>FuZh~}!XpfFLCqSeB+S?~-Xb=4dB_s1v?Mj|jmGw$L)invD+zBd zk(k-cR(&HBv`%D39kv0bGSwTMke9wJ)^0-i|zIAD+OCD*{UOt>gGju4Hv zF2q;D$q5Wcr~_k2!r9T*K|oP4IC+;@fp9#=@r&@TNY=?U0^IOE166ijjYnNP4Kbd) zU>VQz!35d-QW*V=;c(0Quc1FFtD4?sZK2VCg}ug|BP0P)!!gPZl*0W>@yjkWACPZ!7v{i&4@qi81U;xt->B{8G4(Lat z!dF*IY~`PShnGOW-X0DP#;^g&`?kt&o#%o6^iD!zr)07T*5fI~5%B9FT;g#J>)4|0 zaE0hV=_moeC9*h+Hoxrz%59OUaMWa#_&3h$L%%8U%vEwLZBLGnH~kow#x_3H&e$&NnQ$mh4sO1U$I(#Erayu^9F-GU zOh2ucpNoHRwiMKLzzW>^8Wp!<4@pu=36ZPupfSX@N9Jd z&I1Np3iQbZ;WLB-V^i@sa8lV()H~+y<(_$8IU^jna!A(YwyNUFd&;m_7I!U3IX(H* z%*nkjcoKyYBvk?o&XNm1&ft7V|F?=nenU{rB4Dd)S`=FgQ3gVYA|A+;z2l)|WB+L^ z`{fO?A5OPt5S-gB1j>j7=okC#thixsGwu^gGMqW zIWh}gp3uNkfvXh{oXrJt)rAz(sJf7pmqz=KjOE2MAA3Qu$hTGcaJ`YPmDN?75zYnJ zv>@QEvfg67c45k5sM-ZoeA>~HO?%dYybv6pcMKm=FpL$qBM0Y?u`-UDF_;?8JB8c( zy4?2?Z^Yo%mqpNvUfqU-DJg_9*Y0k>GlB4sQ!ONn=9+ECbM@`1C__d>;Orc7f27K!-VIk&3|RXu9exEleYv zb=Jkr0q{jOVTvngD1pGQBDd#X{K-Fwex7*UHj%2o(@6c-8}QBwJu zzI|LLuezSy6~+;sq*`4RESA$O6FcvavUq&==* z4I+4G5L=TAex{tX68v(K>+URc4a@oP4pR=fKanl2oT9#l54zw zg$@Z{ii^~w&+qsX=_>!LhRSS*@a7y(OB20i{t!9wfmYHmV!7+DPD~|Bp$t(WDUu7A z5dHz%6DcDSLfAKcUCWcdt$Q4at-%jKJm6f6{wi@Ah)cTHQdr$SSH{gn+AiYn^;}eC z6q#tYIU#Ox&9-7iO?&wzGdA?5GtUa5y;14zHJQj<9kF3|Arja(4QgP`T`p^vovduK z@&f8M(MZ>Vd6b*rmPQ)joxjwwhfhN&LXLB}#vr05CCh7&ZP3m{_$f+|rRWB!ikn7? z23`mAg2lPG-!2@!(&3GE1CI!ZLUAy0rSZv&dK+$jvClto<(`DIRC|mTWYplIgC7n~ zFH!L4crw0}TJIuAc+MmFpZz3j6r7<-@DW~|vCX?}3wJi)PDEu2GrWiiS#qM8r*aOV z1iuHe9Ca0t!Vi&SIrmgfXA?m1gRJYY-*Hrx+{&Xzx^$%A_~l_awG=TcOb3p^W9Ep~ zSoDajjCvZw;n-5B2K=c)G&7wY>{;*d;5W%h=AZn@0Fny?@8_6twlwn*k&J!^opJDTUR(;#oFn~-dsj?M;nKw^-Ax5- z-U2wdUg1NYe;-2Yx9AX2^hhD`-y<*ZPyFBdZ>pcxkm!<~sno2E%XJ<2ipQGzpB(jK zON;S>Do2r1dPAntj$EZU>ufp(I0TZB?40QA<=k??$bNs}v9q{5??nXZ;tYVqa4q79 z&Z*q4!t6{NX(M7Ntp%Q-2q{^djc2O~ZgORAaaCnlfFUb3sEu_qgg31dm}*$1%F$6K zGLG)K$7YLHMA>(t$s!mEbP}hE)FLBBv4E#OT66+wR2(64T0t--@CxM>;V#ld_M^gs zt{n8B>$fvyIEeG4q!(IRt56YBzDTGMSMVt-Js%;y0^V6h>N7|N_AU!G)^Z0Ol$-85 zp*BdoAvU={YR#boN@O=uZ-+H2Oj2mcI0aps5t)0=%OvPDy}pEDUt)ogJ;A#K`(7h1oC;4oPhMdK>%Fe>S1 z@OLdxKwRr3dEU;OMiNy=eEhp;Xar&IdL^Nv$@KNv(RlQFS(*GXD~W3Ji09ZNXZ3yx zL;OljqPYN`vsX#LuS&H%h^2hu9F8gbwahKD>t9sSfuDYL|I_o6bCz>uVb)zp7l>j+ z#uxs@tte_UBO0wv6+Sz7(LW9qgnD=!uWj`pjt}`nH18u8bfn1%wR}!4BpinpbvQY& z9S|n967KB|lJ!^%ozEypzek(v8;^H3IFvxCuPH#tM1>=i^V`3qi$tP%C{c9u*&IxC zC=lQI)vvgJ@G&Fo$5!+V>2Y{V08!oeZG`d!gJ&wGgCpErQKrxEe%cAvzG&g2tc(%a zShbXqRL|k!N5^_Li-0^YS}I>Ax2^P(<6qxxe9jois6J{daIG#>!4P`$aXgZlAOt-m$y_pLa`eKA%{rM(?2b_LYR=D1K0qRG!Xx1Er&3nLK*-ZZyE3kdkTs<9pEuMS+-8A-xBfb>g#1mFE|ieMnAR`Sir=c&El0SB1oPS90Pn^h$cslv*MuPP5@|9l z?{;tHx5(ERGj2nzhz!=~{CedsrIqyO8%Q*7K7;%0g>uuMLp6WL$ ziG(Wm`lpEiFtov|@o4Rzx4zlkd${q%+Bc7O!6Qw(&c6M8Yy08G_M?rR9W<~IxvatZ z*4Izg*4Z6KBRP->;}k(b*uL_TQofL#v2JB)lI(T{uRJ~;Odc8nfio$pidm)bcfknc z!fWVK-ou|+yFIOhDi>9EWp8i&(b~=qUr~ewfk=f&IBWYv4)xfZd=FPT+_gj!Zj>9J z395WT>=8E>SKY?mH#-~K*r_LY19EM5<6)xeS1&y!_eA~dQ4@>DE~Lj-S@jNmjN1RS z{~F0F@(^!@RY%|Pk~LGs#V85~j6eQQh)a+=t^7`eh-s&(9$E)4#Eb-a8Ccj2iVuu{ z8s(%_+-e9Kd?YJDNS^##%5Yvl-oGxg-lT?nwz_yC>Pkh6WFer60cA%lGu^1$dI`kz zP}fzXuFh)*t^K5~Hz&m6v$mVjI79mxUHfl2qcyLNzldOIgp*S(tL90WJlpdGpya%` zVorf3ld(!x1R_$)NGOzK89ya4nba2d-@ADk4*;U%ik(@#9&4oYIr&qL{q>)@u=V7^p0%R<;%VA!kR53;3JoLCTh-tT5`S7V`G zs?M+w-dYZM6`UPdA(hso<{g+YdmR$X{3lE4s0*QH#xPewhu(6^jnuL_=j72iqE{ZQ zwJ^k93nj%^V7bL7i=n3ITr=ENPz3J3AbxP`+zfKUK)RIh=MA7Gj&&`ZKv9&MC#`7* z^R8>38$(exUcglL>B0yr!E6}zD!3CV1Fsse*m;6u!Bd^C}p5wHNL0?brbw`azvM;z3yPG>WNz8VtNf- zEA-8>aI_pf+a4V85jPm!@IVYI+FZQ$OfMl%JY%fXnc6m%&P5|wJHQKX(;+g%dt#_l zHJfG#Yw#@t`-|ahEvZ(OE7rCUG~h^8GuDik5Q}pT1?Dl_x=mh~t}M`sFTH!bXy)TZ zqQ8CE`5F}k5fUt!O>nO74;Y8l&&oD}Eys6U+Zxa_<93J?4EF6^uV_`{<<=9Uo?-X( z%{(Zn={fI)BOxEahAJaO9~mY=Ai(Ns+E?6^rE~F}-|5PJr#23uwt*M)Ay3s43WF?mCF%{&S6$KHlv6*A%0}lNzLeT*K%@x4Q|1`HuQOM$;d0rq zs-3ghk7ct|M`eSLDh&#Si;aqRRqMJ0)r0L3XICtP@?a@`vn5{st1LN{jO#~pf$@_d zGH!2v`PHroYo$dBt)=wZ0hE1&F%Blb2#Xz^Veh5nQF_3lwLL!*J@JL5i`LTdbiBY( zDfy4-m7iGF?Yg$UG>!oODGUpW!xHI`Lb4G0%?{ckE(7AglW0$Ek_xJ;YZ64n&>K&l z>ve&E=BReDr)pK#wK6SWaV%~(TXG#h+}XO%ud>B)ocX9)Xjf}jUS8p;y?psWge4+> z<~}>)oDaGRByPd?esLNTPVAq>)Yg{P(fa+Zg2LUcetMO?^-<=dXQ7>~S?}z9bvPor zXYQ)sbASCNVTaV&ZTk0BHq86aSb4Tn$X!b6kQ?#VYog$@>q*-=j5Zy1=3f0W?bW4O zn@6tv>?-@$0vp->&E2s=pqsaAMe~_EH~Gbw(M-ead04w`Gb7LBjRQ;D23S5YaA&qdm2Xxv#_vq_`vI(Z(0Mw{smk z{`vXV?pH`W5c_bmZrT(e*z0-(nCpiZaMrAJHhwsV%^LAENYG&ck6wFN=Dc}^dBn@4 z8ZCdl3f;}$Qlq*Sar@9&3C0|1Gq{}*yt6}A?U0)zIN7k9ZHsDlEE&Cu4YDD zn;gHC(Gcc`pzkSc!z>+*aBa+htgGqWLvW-R z9LXG(w6l6;!UU3hENwo2%_o9cs2QgT=F9Jw_7FDw?Z)=gE(U+ueg3@~uNli6Le1Dv z$Cad(F#9f(;0^#WOg$)TF_{bx4-turazm^bJv_ieb*OiT$Y?I49E8#9{0#RXwA{-B zJd4<3Atku<@5sV7k2(lOmf2Wx8^2E&l6$*zD32}R!h%A92~mcNvmOmmG8>O&4Tw&j zeSRnmijD^?i+?kl&%c{ojz;39IOocwfWL3TcML!FWda+%ON`bpR(PAJnqE#A>kUW% zDE6I92$@(PO5-W#oLutpJGe#^s^gdBP%E9yi!MGrJsSh`{^_g!Yx+(un9h!wNRMdF zalYS?ydj~j?=?D_xOs(#`PdR~PP|0+tKg`E;Aq`jUyWxyv~{|0!q29ILFeS+;(Yba zoma13tsIXoSAg(4)A7;8D>yywoDTO7?wsL0um0(slZ&&{y%BOI?|?pqoR@cAqonZ< zEBvNzI5-qXQUgc^9gkQV4Dq+qJ9qE??r(qh+h70gcX#%Y#|gro-uYqwa1XY#^N;Vz zaR1#!|9J1?dwX~9VPLnAhjS5JLxQT(Tz)a;+k?srgN+<^8O&tdJhA>lka99^u-FN8 z{U}cn@TBU`5>K7|z7`(aJOVjQKnU1cxE4|lfc&aR6e@+ODTBM9HX~V!xG3b!^9>a0IjPxQ@u;QR<2p z3|BmO$vSgyGtL>GUSYiMV&D?>1!Kofc6>AwXe)~SjiV9N#wBn&EFv3wnG9D zB$O1wc~kJ#jHe)8fRo#fuoZu_0BZdt%gghoDR3lD?nETb8DAd&0D+>|kO7CN2uxbR z0S8K#^k_Uf)}6V+qPQl<9cp5;2pjx)o%h0r^ANfNBlpGp>5H70at(8~C7jNtQbJEi zo{Slo5**86ZeX-z0uVTq08n!PGREbE=N6YANFrx)li^F&{thQp_PA!v((6rtQ)@e* z?iH>fKD{9$-zPXhy=q$s zHo8AhD65_D-Zlbk&M!2Irk2>iI3c!-H80#AD-lVr)04kOW(=hAKrRDM#!{zl4}UqTtdQtwsbx$^cJBu{^05 zIOH3iXfLG!hb8kMHT&D6v&ngBSbgQ5L=`>FB{IT`o8ohRe;N5(PP3s_fM7+kx`YH} zlDHC%pU4aR(_($%ot8p9<6v>*d|)}qx>YTXTqMbqyL)#`{1_)j-tPk9$*Z|VsLzS2 z`yw%|7Do&FgQxL$zQR%9^7vCzslN7orwTmtNFZv-bNHuhUE?Kg3~&wu zy%>*C@DT5GL7G?l34TLaSv<(mMj9w(my(VSKoeHWSobJQladlHSy0nZY&)thAXS$}ww89x*_iLKW9li#k!qdF zk)%YXd^E)Llm2VG1p29xs!OMQ7e=-%VMe-oWXZ#FVMD{pVgq2s=TPza#wGOym?*M_ zfukkT`#f}Lb!P~>ww{8mC+nA%%MSuDZL*X3k<^gTEEc!tw@fgJnt(B7llm!Mu7mZ zq@%fFpAS+Yvo;$_bj%a^;so&+CgPrRw!_0rG>~cx1$)>MRVY)Z!r%!n4Cv7L8Yw3c zcUlpS2qr=SY0r5?^OvTW6ssoQs8rFOSQPK3;+2fJJ(;vn4N@MH(uhjnjhr+CFlX5? z05fb%V_tQeVZR@XxSk&rE4wSmp;})qG?aa#kX=j4Ja3`~h#5!O1n#=`Oq-dbe_Ruh zYEFPDM&=F5Rs%)@sG`LLQ0pP3fg_WoM1`$d300b~y;69f=PS6ui7U znPJ&kAgtbZ3nkTkK^JTg#7h?lq#k<_R7HJJ4X}$S_%FYf6e9Gb`h%IcGrM=$ocjjP zGZe7Y&%sXm%Yec)87O5@ zbj9{II1wwq)?q3^ZoQERdzl5kj zW<{Jh^=GknoGc?UBfToJ&id!Q;2#S{9>$yWWQ3AqaOV-vbi9Yc6bC20?wddMmY@Fd zljk3Oa;vxU(XF3YnAcf_G^vm|x4~ApBrTqP{Cq{`T7EE?9`w%#yCnIZeR;36#TO)y zurIL)u`hk0l%64umGGyt6GO$E0(wOX3alyZElne0f8xSL-;^)16Kl&2wvkT25}R?* zce&+tx#bdd0#@2K9Iq)xbm2m?dS};$^}#ACV8vrD+KJkJUALepBf(;5jpO|x1E1!F z^ZCFk2lToW@8IBn(CHqH#~>Jl6YTdV;S>HYYMBhaXkb^2mhx$5hf9g^OG1|HW?MWu zie#StFcJhylrX6J=qO`-e}UMi2-@vRJXI1B1okSvG6D2W;1b3M;vi(h@vlTSz=!Qa zjuMo&mqekEEGCObI7J?ZVM^ZKsudrF_p(JQmE&(wha*0G*B6q>Wx|BL8k>}Vu7ruV zE0dRKQ>2x*4-v+v0T9#OTY6D@H7>m*wY-QcC-!RYycl!;(xvig?SOXqRK@Wq2PMN> z>%VT{JDjvA2J6+^eivqM0{5vkg1JGBNY>rsfBh%gc;XB%T5aJHq7{7<{yS>}f6=0= zY$J6lkx^5})|?HOj?S;@4xh5&j9*Eg29Bl8r)p%8hATY;EWW2!6Zl4<H4)S7QGgy ziMyTLz>)3}`mO=JK7cI@{vXAaS S)DvQdW{rYcW#*euF9ID!XK?Nyen;7~8(+$B zVh~}vMQ_(HTEBvl^8WnZQJySuS4QJ;d3@L;ac_LPh&yQUWna}Pq#T&Sx4KBK6cKd*H_b9N=0?p$Z%K_QB9o94AI0hZQx%Avd_jor}j%JAxzu zcGNi zgCvP|f(V4r#=Zqj#V`bB)S4SAq{t%66N}OO;qO-^SV--Q@E9ObCQBN0`kc~%h$K6j z8u7m@O*9<>ms@6~G}nc9TVvR#7&xoukJCR3TafIG!hsauq+9xJcdEv$`60W(@e45Lwk zfW&BQV?nE*hLu+(h$oXVOD}_6n47V~%<6ERkwx*xWZQ5aBUuNpV3??+>Gmj%8zp1B z(YY~wvO=y`wd06`xUEYP&=0O?G5(=(IG`zpOngt9tGg2~|KhBwi^ZNkjkAf$6#5`g z>2^#VlyqX5`<7(mr^E@RGl#A`9A+JSPho(*zbCm&NELPHYlfgVvjMi)5AW^_r!llD z;_D|IiGXDuVhg=1F~hvYyCu9)P%1CRC?GvXxbmidLuoR57`K7y9%`@*5)H7AX2avmn=;*`#Nx+Vw_`x*Aw< zJnI3Of6#S+nqzKa%gr2eon_%8o^@-!uogJrx~dyE-iDs);m*HkJlfgP-on97$G^g{ zPP^ZXO-1ptAm;5zYv0y}w1p0Iw$l1jRKuKcoU@Kihj~MS+Ze1a5n_^kNAXGheA5%u z_=7me)B==_Vyr|TrF%LE*Y6*}hHwIL-(_~aY=TA4?SC??eHWS-8`3uRX?;=N%-<+u zHE@zV{_p9tSIf^oT8fc>db=?W4-}s-&I1e`MenR%e+|~JyzGCpeQhU|>*}>gk8NAr z0F>B$T<$O{4=5jr#M>Lc|7LT0;~_-j?A7tDC%ciE$l2n3ctlrVA7MVYKK z&_gj`vn9gFU-*;t;TNb8f#}uM)qp41BlQ!+{_zXGvm5#XP81NH9zjPSnSZLn|oxkgZKklQ{ zM-e#?_3d2GDnp47UqFPj{Y4S6 zrqwNGVZn!%I3dGA_^cfkP?Sl_d^(E}ep%UhWzfoN{TvA0X5EZ#?Vk|YkYC=)J%^)% zF^ZzWy^@VUH&#tul)?^Eb0~4C*2Ou~6i`ry1OcegLpBOVObHH2=rp zBl3Mf1fe-!%HRjqJ(I`M#Z>QXZ*|r0KRGf@rJM=69p=V-OSXxT4Gq8xTXfKB4FCK- zzW_uJ7xOX2jfz6W4w2uN7~zerDQkN5iW|~Pi^fay5)u@O(S{U+N*H1|_{P9EYhd7> z6X&!z_mG1nXJAz*+zzsmIAxivxsi1Jl@5;l(C&x^btH$o9kB6^qSVs_uSstTaNcD; z%%T09%OtxYxexDhfoA0brGEJ})*lwLyS#yl*tg5mLlS=QBqP}l{&n}eOI_x}0m~7w z766m*==Y{?c8ps{7zt=0%c%JdZ=2%&{m0JzSN+q&;dtfMU>{pHJRW^^eAXYHuE4$a z0DbQKN(}k}h;pP1xT*^~Tn^>*q=6_d>*XLLhLz4FK5$EE-OKw}^>D~n@09MVD%}rF zcN$Ng?SgH@Kj%f7#Fo$gaCRF1n%7UC>V5Y4<=tFnINCaMAJ>?U$V66;TicKNtpc41QBh(ZV#qVO8N3up1ml$3Q&PuUfL~MQ$whP!ucCl=q zPOb?z?5rfm@Ay+2GQ=<9ni{(*3OPs&jEI}q*_oJ64>>K5 z_x}^0glM3KtSy!j*EQpK*pTyRq;84e1hdaU-#z@XW!w@&U&egU?rx<;aFL*VQ^tD| z+|FZDNz)`&xMshqHkmcal5sW3$blNh78oot$B9qQjgcnR}&bZ5kDSZ+i2k?KkGb)y)m+dnOBA-?{0W{_leRFYnE zlYKaob^Fs4_u-R^dsj`2)#7lCdjAwR@#x~H*OfccTnAddosI>KS2;ydr9(c?gW};+ zvGdkU+7Pvp*h8x4uq2p9Fx_AS+^OxsAnhMfg>q{|Fo(`G&P3Q#vt?2xKjA4?12C9k z13;Yss4{mJo5R~Ysr4keJOpPcm}_cOETJ(jS;Z?(dY+X%Yw#H4SC0SDM|FHS9@^SV zGXkX-nlR=@Xsop_7T$ONHKk{)Cw#8cS6Q)}$3YDF!G@Yn>pZLb;a8NLlJ{&H*o7Kq ze#DuutQX2m`FK8Q&*w5|it!RG7j5yHFq;smd7BUqSF&*nWzZ zo?_3P2z8|Q#BPaOyNHZqwsiSf;xMw^isM_b%{($AMbnW|AveAAjaic7N_u(gl$Uum zV2LW|Hv@1n_ePZ_g!td+5x|`t(fD?@$u2?X5gx45C@O#HeiGGPS_^1(XBa{=PVwx4 zj2AQ-oc%;K#?nG%=@)n2h@GeR;5pk*{xOVqgqg~-kHjQ4LJY8uZvqu4h4TTB-oHm ztUK6IYNEEvYlB@HVaTfqbx;$ga`!!7F9|kQgFe6Mm`~^?5@(T_Trm3?o>~ z;#ie75S|sz7B&Xgv~qTrFSA06iAOOdV8LWjWFPR8N~pg8`qafZFViqk;yhjbzHF zPKvu%e@O*(d2B2eKt}ZgM3J~iHmhH`F^!sFs<7&SB48ahs;U(rXDO;l;~jg4p;}ft z5E$R9MWj-%`y->h8v2s>{B)M9Bz;xT>y3e6|5YDxn~PU7B^uyq|EfiRQ}bsLM2lU( zVQNIUH%RfUbNOMa{*~ybb|e*>wM2%aZ^(`;PE_WG9f<6d6W{FamFzd!vj}E#LL$V3 zWxmDBr5#r@w#2XHYDEL5$znr;0&88Vj+7k6?$4B!nIFzNsm@S#6WWStRi$y*dUt5?k*tU%l9gOCs65eMOZr!+oJpmOHOOtk-tv6&|Fv9mZq>JVC>Err5yq ze0waH3L}DH`dwtLSt_VUzHB)71%m-EUdm7=n{Tf3J$h+^>-bQjTa2A3Ijn} zUr1i69=kdnGg~)a{N|4r4r)3yRr$S^FqIosm$U65v4xQ%10|tIXZcs51Mgch7X$b$ z(!!44@U5xAVa2u7f*z_o+xySKlQ)yY=TN2r{eDb8t5VQRk+RV)p&R=}`Vy=I(Qr!a z;)~p%xCwX1k8xs9>f4a)(m<8i=f;ppU=YXw)fW^JBoysVm%_icArZbIiBYrKhQ zy!v~23k7{wzfNQVsoj%&YVdgSEzf%*AKCKf=(^i}g2BGiYn^24>Vm$C3_f2$u_|)T zzI_YDXyku199QepM(DVj^bqr<^UWXnZ~$R!w5M*}`Y_w9?CfYaj2&joq?BDL_E%;I*nL zQkLwEXD9ok@hPN(C*bKmG@k1(98&H*v}HvQ>#KA7_Vx`gfB&vn|`-iam0my|G5|0rBjh0?a;A_Cn^j=wI{gIO9sQ4lF5 zOpy^)80+Z=Q>q&uOrO(+;A|i_Cn$RGnb?4f6{R|4zyPVl?CL&k`VKsZKk-DAq#I6? zk^k~?M)@(wsfNarVP{)^4J=ameN;MjyMJ;mu5=$1XcS(ZG)?{Y~a$I&}vPd@D3edH(vNC&Q2gs^R+o~f) zCV-eQ5lZPuC7nPqO?Qe57sxk9urf@1xF(RgJ;jRy*~>H{ctD!5fWwNIVY8deu;!Vh zVKCP}i*c07V<0=??vav&YF&pNlvX`J(wE&)_f~#=o0k|=;mP1^{1Od@qt35a?m8s( z@^F9380?B;>odHXb9_9Q>r6>zBHvtW_{m1-s6iw_|-d=aof3>II z$g?6cRJsh?dF#FW;Ap@%e{43R&m`_E5ZtKqhp!)9k=jx@r$2o-KC6*)`kjYcUsH;K zKEj!lG)scZ==R5F=<;xUpjp?@M`FJS=wFPIkraS$?KDI**KWt?16 z$@876lseDxjHg^D1^e*5Qh7h2@PseUJUU62HisgG-67PoQK9>H2{cztpt;G^l(IBk zOimF>3dvGlycO{jgNdYP71?1lNDLXF?|EXlcW`Z?R6+j|mfA_@i~jx)#Y~={qUh*g z2#xFhk$m#m^!3@%c=Wn41uVc&&Hi#;NtNx0k7dRn#8BQ9>^WwDqrNM1VZk2pf?U;< zn=v~v0f-dpug?`zPyxjI!!7g1A%_-k2-!KW;r$+P#dXbqpH(|p-zL1=S}^a_P>y?A zr2{vVV<#u$={fV8IgRd}+#B+mlnsSzo02b^yzZRzQJZytfL#Pyq-N;hN@w!|8R(iR zD?=Y3oA3x|;genbiL#4cN_x%ws3tA5>_k)xl&9nI3rR}G(&|va)OUyz_^*tj8gep` zZDYlps+$Q+7~WJys?K15*Go+Bz&!Ccx3~-o$fkqfHgW5Jh zwr1w8bST$)%1e9ej>TyjsNI;1V?j5R@kDRh&wFit*xZCM9Z|tLsW-f?wT% zl98h3k!OSHJju7HhIPRiXRdZ`@!skRzcr4as}ychVE|?YE$`orJdF7Fy%dtD8W4?wgzwBmVQzM);%hrGTKjGrivYs~N6!gC zJR%i@rW`ei;SS@`0&Y;+Kb_AiXCSmrPeEwj%5oisxPFv&6;l$*CcNGfAq37v!UBXl z1sD^gIJ+^e+^mOWGokfg04cD~uVvBbi8W02rG~s+VgR0mANT+k^OyK9xqNDU9@0OP zsBR)TpmGh*0B~U+x3AM8C#uxr=PW<}%J&&XFgb=45V-FRo_>`LU;%H2iTo(Nfkfu< zlW$*eyJl`ta_*BZb5DIbZ`rujnYRJ1aN@U2YU0vru;b@Fg|OXe7jZ$n)mrP#Mrb_n zKdK{0`3X;bI^~}eDLC;dQm$~`wR`<(Z%aOME^VL$XNHJybJU;bIsg_v%_$OUC}Wet z1!OysE^v1HsO%{Usa7igwA?bg>IkrXRWH&P_0FpYR!EYkRcDTK4lkP293`#T60YeZ z5kPbZI6u6~O001{6G+g=W^CF^Yn%gB@2n|*4c3&VLLbdFK*z!haYCfy=i ze`MITfabL~@NHHHRKE>1z@!=|nJe^WX!`nXsN(iX=kM*rgi06W9_mmD zAGx=$_&8QS3@z;rE*iR>^Liyj<%X~uQ-2rPPH%{|#q=*(7KX zf@i?pJIGTCZJ@fI4$n}IL8>YJXqI=igQV>Ozg6iTEW{wiKU(S1{!VTzqH(peg{Mg{ z5*d~5(TBQY{n3TT(&g*2fr4e1!47T9nQGsl`|?i$lu1x{%EC-TVko0xqowW?JQ8Nb zcr#D<02{UK@*;-A5pM7y>flJM=lJX#j=B9)SA6POeqD`I-zhqgWE;IEsr{9ZAeywS zdYV7V%7fAHDyzyZpLG0fRBd_>yxn#w4UD2+U~qPR@%rlNs?35<=$-^j6&!Xo8F*H{ zw$1GLs>YP~H-^c^B?whW9R}}Fx;eN|q`=B4NdxSP+O9-V2q?g;!O1JJ3t{jG2s^}R zf~-69zN9$!^!#*q(d)kHJ^S(2@~14#eG0eeSp zoIL^^uuDP!VRa?$*iKH9y&)y1#1*FCM38a_MhHICOk&`$5p{_pi7?5IO8rWn&JrR& zP$d(H`x2uQn#=rt{M#F=^SdS2?^~?$8!(DI4*xx_*5ajvk)Z+qt$dktos?B4Btg{M zU?I4IRUZ7Mmzlv+ZD?fk4EBO4*(zrqlSQCgE(Pp^Y;jr!C^DXdIQ z=Y=r--bJyqHouH_K0y^L zK^c5k(i_qdZ{w7jQ~{4=;1!$lX^t;m*-<7oRjL%C;&q*y8)jDeX2KhCS8i1$p=yy4!U6tz-9f#lNGN3l`J{4Vq9hxyRv(mS*Dpyf) z9A&Ny2LeyHy{Zp?H{+FB!|cov|ZMPe2gSg7;juq z3tijVqpg%c%^YPih)Z<}dlFDCEZRsCa%&?kGQ%77C*1Ukb1NqGYBg-_qXFf~$UWAn?kq3w_a~pck6-cc z`=Xv+%QBx#03SR;9}xxw6O6t}pV{iSH@@8X!`{yB_U7X+aWi&%PyhIA`uw9$Z}mQ1 zeK!5E_v!ujp5f=#`|;Oj-5-}c^FmGYI>_(8*+M9NI@YJF?_<38Il%J|IUs&k!UwlL z#Hi0?#%|f zHSe2@d0Qmw)Q)P`Bdkojd}lG#?vYm;hkruChoGDW-oW^Skn3;p7?qVswXtPA2{IE& zS52r@K~P}9>=`TLQo)DhAE$XcR(6_5uzIc_fA|WlN9btcf?y;o>?IxCM--ZiTs^Pm z$>peTRzV;iRIWhuU{Rxkdo)0T66}RYgBpSPFWX3xL7-?4GZz2u&!uXWyeHvQ<%8dDhU zNG^dR9h@kE;ZvQfqNzl+CL0WV`IGm-WtG=|0)F3JQRT6QnXhy|x^;!A1qF&f$#YbI zpMLy&#eTc@e1+t6elR`l;|HV@v=ML@N<>?FujeYqOwd(n$guba|0;55H(s>^_oXEBA z;2#o>Q;8oPJuIM=yH%=)Y?tu(IsGUebEPWmO5Bg+GH~Tc316GMdlsthStuBiknD+T zj$+D_>Eszcc(%slfXFKUGX1WJBJ@oh9|1idf&b$j6!zWGJfCM(jbTf2H=pT066C}T zqn5qa_1&pTXICDc>})UpS~T+0Ap#*JB7*N!oywYBP4FzGfBLuoCs4J zdKp02etkFG>HDlL{#v&8>;5^Q(OV*L5#RgO)s3$=w!hqXypC6eACyqlt@fD{xd|$EmcWc{^MWwr9|HoT^9`RcKaC!INlw9)yE8!tdls?;q^Oe!YH_SCIBkj&RrDpjbL@~H!>YAitPl>{>G$aR}iS2t%3ARjfhkJ5^bSb?yFIgFLJ zbeX2y+c%#LM=)*=FAm2C7OK-wMGv=N4{8rCX(%pdgXy$?i~u!59IhJ{y=cZ5HKV+s zR0TIrb@Xac)YXt$ z-)7c<#LB45J@Ftoxte#me(L21uZaB9 zQ7k@s|AUX0rVpNeaBpe)yz{}Ym!|jc$R|({X5txNJGojU2ZQ3z$ET=?0^Q9ic*$rt zQ!1KFE+TU35SklIq8I0zc9bJwNE*RyDsNx!| z<>$V1HsK8IUk+i^K?1Xy2F{qts+}Z-Y9IOn4Odtn41mO%vyc~q*JfTKAGPk0u|!$~ zgB$b@PH2`f?!%(e=uY{A33}xzF&^Y0qS69qk9=uQOZiHEwgmrZ(bzqG+(|x$>0)p1 zV!R`0M=WPKIuDhD`!p1?dh@}Q;h+TTmQ*yvtZ@nKQyU-&1SWXTkk~|RG^Fab>V9JA zxXWU#2o!HfHReR-c2XMz>gWVaJ(Z3DsHLmVw@6v={K z2xD5KYH`a*E8r?QM<@yqT2&%x^Cr-m9zq=Q!1@({NbJU}tHARV*z`V%_Ntn^XNW5k zlnXgv%0%E?hhw?OQ(lkfYEOrwLCLRj&`?gyxvHU;5Xyb${maWsFBn@I`tvQ9jjcy< z@qVGaa|1USb%5&Gwx2J=pNGrH%s=68xi!@e6SAAq0cYYSV`z~$0Ga;9TGpCv2>5_px(5rs%) zKR`Jv;F&*Iqx|Cn5-w2rp#DEm4U=S~Ag7w<&_h5^$dK|PaAFaJWDYh8%b(&Stk8W{ zK0QO5f0PitIsoA5I~Y%-I$u&()<1L+l0}GEH%Msp@?yMve2GgO47!|5VX2-71;BJf z932DNeB=DUJ=``ET!K7>epHHaecJijc!FLS;RmNjHTFA3yg3p)k*b(5V7HU3q2700 z=g@U+2uDK)R(k6}a1!Q{3AVw?fGm7*UH&o2332Q0^RR@hJ6NY{i!zo>$?>a%_`J@fpr>?F-S>o3 z;l3JAN~C2QNFiBTDY~k_YWPrN3&d zX32}OUx-1R;mYGRY1pY2J*bM(C}p-IGR2Ng+LRd~b;$F;NYro|0lKZ7-`u_H9P-bw zV3^h_a>2q2#vZ+`1zT`2w2H8|;dPmGmmv;re*Sf5xC0|CB-5VY5%(8DQVvdhgK6UA z>oy2)gfx2kT1C_eT$m>)KnJa8vW!xS<3sEN6vM&AD^})P+gab-WRBj(=j#tQ*B8JR zgj3i@gPw(g)7c&uhj2+A+KF!@D$pcF{P-YlX`ukShd`mTL6^nF!(YAb6dzQ}sDl9j zTfOeq&h9@y*+76vHagX?t)2K;dRrPXD8({H3*zJusf)dk5&RD{+$iu2ToKHB8e)}# zKeGW*SZ;hdDa)pnAxymYbCIOPnx0}63!+k8J&3?kF7*>jss`u~ZX+PN4aUz@TQH?W z=TK##^C_|qQdPpn&~KaA)#7Ux2I?|TxpZNT^(#+LWVUjAA@%O(tlSo!%#g3_oqj$; zKQ~iYroF~{51fj2+#&77b#-5}ZmLgHLsqR9Z!c1*IuhZVX6ODsC=X|n+MnNOQ_-&3 ziTzxieb}E2FQn*uL!{=4) z^-F(3xo9b>now8O=ObgU)>mmAb&^u%sUjQcHTAIW;+zC+dyRZ(+(bFEK1KKKzr8f)i?HALehQCz|W>$-0CPR!!fK8IkLd&ZtxW$AwP8@N< zQr)z*m6o^Pf3vx!T#lO z6XI@YMIJ)oUMv(Hvjk3RVM-J5Z#?;C*Pb;g_wi;4Rlo^eI09pCGyo$jz6tQ&3GOol z_bW;p;fA=f*a3Ofl!njya4SU5n~E6a3lO^qMPo%}zR`dO1SEV1xz$H}yGX-`gE#C$ zT(U6KpRTf)yCr0w_aVX@vQR$1F);?T{UNMgHUw(lEx$yuIlfe&FeKlCUhE76WdG)JuB4BoqoJ z1~e*n4xb;n&!eheP*M7;_p?z%t^bLxo%CHJ_b~)Nn_Se?DO0VeDk=Sf+-b&Gl|-s5 zNkmw1VS0_qJHQOqfn=Yq`k2w|>r$zRDTRGHzr8cfj4aQ|u6G}wT}jZc%1 zj-`v&=P=6EDs7z~b5(A8?Yr`$Cy&-PAL|j<%M+vV#??_nS)VB{UfuXiEldINgFz>x zgA-rJ)Kl#M#n1KC%m7yW!cShc3%-dbp!&7YW3nWN3sK)u;2@B7tBdn1V95d{yfY4l z2=Wka^KD@4m7s6ssu3JB_7T|-aV$LD_f?+$wLi+BoGA==63fo5DZk`!2h^WbnhR># z>T0%K(2Z(-oUCNurJ`jJzVOnb2>wAgx1&;yvX7O#h>P^EXMzN3tcT|+g9#ni50@+t zddl#8@1lPk>T}FkY5S!nd&-p?UCanBj+pYO-;(ou#~c@il6tBLD{;VgrV3`o6R%1M zmzN}bp!|B$TR0T$!Eu;Er;$>t0N-sdN!THrZ-B+WfXfK>YwN9%enIaXGxB0NDBXZ}prU(7@1% z-`kb(N$1!3LlYi^>*>efXMg*f`XRC_1kYLA!?P1Sy5&@s1lzgyTfmaE$ha!z$=<`T zFL~P*Z(-Os!mRKefRiy3iQ^jQ-XE3-mkDfTfdRmO<~1p4En|uU%w~KWj={nR2~*x- zXWFeC#u12_gfFCal8iAFy+K^sQ+lffZrTA?+8&sP$HAZYX0KB46$6^QkE8 zHj}|$VWW@cZ1gXGtB?=s7k%!`sN0$l5)s8Y&|Cj7@-~qtvR~^$#Z}-oC=iGDVYNn$wwOyhwAQcTiCKwUkQ20HmNMZP~EhKnSg^PBj7;dJ6GV9 zU4h}PmuIukF7$_M8X9Dj|l4mFJ?~r$rlLr2uPM+>34|~zm+8@29z=dgVcV3S#<@5gOR5PpkaBZFr+>JROggbbn z>g3MF_>P{X6%@B%USA*o5f_i7;$-oV?cIs$j!hRHvitNPng}2Kgu1Hgxu5SO^r+}4 zGN!*F%a7>dM{9;Uge_%p)GoC0f@}VXE+@GKT<^M{Gr4wJc-8hFHru#kRU@Oy^=RaG?jf`+x-M^* z;c9_nq|U{9Hz)0WECAu;hBv!}7NrVASAXwzm>+;^CbZh4nJzRf?R6~*)^sVP?Z`}e z)Xb$n8Vp2f(21$@Flj%>b@uE)Vx2O}ly!wURDZMM%0t7&5@G6p31}?g&k$^*BJp5- zd^(Q#FsYSGHyRUoLR+@EVNcVo!|y?$!JSR$s*#dGP;+!#pvuAtl|mZ2peOF681z)u zCgH-jxRJ-y>x$TSou(;jE5m!!Qf34aE@V>^OuY#R=Z?xfAY1y`ktw#G@TQlLt4>1G zcn466Aaq#!WNu%pWPo}nC6ypZY+iBDco0fqpx2FsK-G3>_nRl!Bm}`E!()`BR zC5<9qN<1Y~Abog*{dt-ff3+|hp zjVEi{Yxq^D5_RE`yA|6K$qKYClYiS!HzKJkeMx@bZ9aau_1z8)e>|p2hm~pZ+Ls;#=xZ$`#U|hKWfd*6 z2R=E}=XE{dFtL`-R}jFh#JlC#68Sy+L4^(`W%F-gzb1NyL&RRFcP2=J9h&mh=@1es zEO?Xc_S|L2Z22Cs+aT#1gGgA`U2+#f@%A}#>Y;T0Vhq;WUVL{mjoG6mf%J! zQke-t1~}-$*PtYpG@&t+FERH~zQuVKIO#(jGk%p8ns6~|aIuC`C}fo} zIC4OwoC=9}k?(*NUzu1Q@WzOe@Sw@>pjOyqU|V!JVuldefSCvZG+#&fV6u;Yl<{b` zn@J1OOY-NnXhxv~!KI)#q2DPZedx<+n6c;yQ0105tq_GXF*BTg9dR*-T9WyiKn{wL zacihjzUfUMDubN~Bu?NH;r?>~)JdCQ6KbY0t_5s)WP^4v5bd9iqqr6I8Td;&QUlEy zTp&07Em4r$kV{yfT!wDAKUaFDVz=>3smc&rKyBvr)@I zEn?lT&-8-64k9;L!^AH7p4KX{zZ#I5PRx^>{{81a%0ydnfxqk}_bS6GWC2H2j&&j=yY@QdWV90J`*P|D0BFn4PBQtomvj zKs4YdOu25N8w`KRlQP{7&E2fT5kO1MD+iznBn77gf^7&0Uvrc*g%dX*<6*H#h!JP@ zMs=(@%O3pU$nRxO@ci-VA8$YZ2+yM3mS1jtxO684&6Ys)@SPtBZ*{h(jM3^>IkAA*`P@ZK2Se zHW5oeGbEgeKMs+;tb|!|3~3``%762J3*7Nz&VGR6$rn8z6=k*z)LEIl3C9c2X2}Z$ zqEtzAOxD1Z-Vy71+T|ef1v8i)5P+|QnlG>zh?|-YRJSG!F+$R?0hne0^tVX8AXP zUCuFZ^@tfT1w%r5-I%amovEBWo_Fhl+u$(+v`+DCXN}=2`OcY|@t=e;w!JoFb%!+Z zonzmWl9NItn2Y#x%tTcq>PB8K#x68&d(d$Tv?bSgRUJ{vb7jP~LPQD-S@K@JaQC=x zC}=B(t5*JY{;W;n9ue4r-Py60!r)qp7o%As-g3{Yh%Xag3i1_k=OSKwH+b1;bZE$8_OZP?p5XEl)fUr zE|kiGw})l0;R`B#NGHR?Ls+8g-ADT67tr?i`_Q+QEtlg~?e|3s$aU%*C_c9XRD2rQ z-i_R&i(Q}#IghBe(Kba7RtHiZUIt=BK`0i+M31z{BZRay;jNtFts=QcT=!L8Y1x8m>UBwtWKJ zS<>kYaQmm$vLC(^rEuEG*<)vOq=~RRLwG?edI1@x<1w~}GZ6$4%rIn7l?H85@zflf zP4O)aO*7oFIjFtvnr&qi#t-@h%0tKfV(vBj1UA-kAv!u<88oYTz72dBZR7=k$gnh}ZBeA6**3`UC z8SPgPV2k6eqX}z2KHHu25$P$Bax<3;hF|BvFPEC4Z}~w6jh@7&#mMe2v>4@74Qny8 zm&c6E+TQS;F|Q`me%UVP95ayz?p238HO);+9FmnGw%H8xij#^;WPN$_E7uDiBkO=V z+iHnD8%&M|TCQRb)@uY^SPP4A+0#G6$1K>cJ&P}N>nMFBnhb%J;A95jIZ)7p7@a+P z1?>5r_wXoS#QmfsNu{W^%{q-Q-Fx0In!=jeaf$W`7_rAE*;lZt|rCK@`C`zOpZ)|&-y5qFLQ6hHi!Bb@ zKZk*5a%goi6h)`6RU-Tz_DZ~&u~{Z`^TXN}%UjYQU^bHD2Ri|4xOChB!D zf5Vn&_#l{AzrzsY3s&UBR$mS>u9NT?qwxS9NZfzFDuw@92qrxnpqP2bBHgiaqw<3h zSD$d?#FA@FESfI@7jse6$;SzE7l$ZmZnq3VjUnOk4nr|13nxM)1$=xuo?f!jDN8|U z6fwQC1HK=`%Vuv6WIBE^D5tSA6h>W&bGA4|jkNwaF@47oOB@;*#Rj}2;$K%Kr8vTs zu-qpGZy3u)Ek5i#!h0OiSK=(EySUVhBg3a(7Vin7o(NbCqngU8(FQ8dA%_(*NG1yE z2#D2zxTa`LPaa$X4nLITwlX`P>etGe1N8H--`@9aCg7}P4`p7WS zznc0ynT!#`HGO9Pe$IEk2Y8^felel-$@zx7Z$&Qk1(KrJ#ckbdot={b?t8wbD);@` z`T6PaKs>7A!9;zkskAugpX<};tnda$;*e%1@!r}yU2?Wz0YO~(YZ09-P8_~jM5*wh zgz@ABo=k&WjsuPSAx40mBO@C|qYw3C1REW)f{wh3fd|$)J(J>>m)UJOd=IW_ADs^O z2ZzH8oFDZhA2JOD@Izoh0UqRlP%$P5_g4NM&eJhfgUR4*{1Oe2bNp*0hIv;A$tM`N zZ4!5QM&s-L1T4MtRew7EfB#G8{+ax_f&kO;sC)&-(!Pn%(h-2yY#s5+I)X32a9Vt- zNqfbIm~`84SbPHxMB3Q|mFeaNAA<0{(@Q97fWKa;teE5IU=uyID1u!MCjJW-ZwiN z+j|c;o*=VtZFl2gjTb!GZCunIN*dmC^X*ABRTmT^vGIye@TO!#p~;&1iIyyE$+!Dz z>uWssw$i<`V&Cm`SJEMtA3%e7jJi>oD_RX4O0}4i#ilc+=Z$Ne3ztwusKW>&a)GH{ z)R|n4Dt653nx!N%jRzY)3@lhRaN$o>2G zyBk|ybboc9ubMpoui-10dczo;U|_}vwN8j-Qy*CEGf>-bx_bYP^alg^up?2h!2cO- zLg0SN)o_O(Xw^fSnRP)P%SR7C)bQpJDheEq`97qxNU@{qU3Rj5m)?IidcPc$&1;I3Ccv{rLUsuUtee`Q-$OOM zc-9=&NXQ(OKcT&xiP%F|V23rqD*H48H}6ca_tN>kp9v)%6Y47X*2dZfJt{j`fBA}_nopWb~wv$cpo^gBzs2f5CjY%`LXYj zO*%#$^(0e9=AwP8r1Mi9Eh9pS>AVpfte98MI&%O@I+Doc;y?-rHi!~oa#ict16)X~LJuX|s_p$9aR7z7>Ysb|BH$l@yX zk1PpmdeOhQ#EZH}wYq;t`)RcLMSACO@i8F3si5z65|gKz%86WGE+;7MAw&}Ex}1zW z<%@7?L;J+qnOITP*OPlun!X7{Z3E-lAp`!^cY{+P0Dfkz2&|XT8$(~VeHc>3q@V1n zF;%N~pBRLp=s{DrZ&j)3-9k@qdkZ(fnijeQ`6GA;>JE#JhrytAoX6%OtWOCjKfnDe zXg;AOv$vC$SP4Ld(pHnzt;B}JqF?QfaVriL0NIFg{y#p9W9n_C$H+KnqJnIrQYYhc zVE&YqwAf2+*kTi()Tdb@P3e*qTSd@>O<(K%0XM4cOa^#Ph&55+pNCOgTKa8K5<+oO zfVwYyyxy%?_`Bvj2ZDeSfeHY2WDP%9VQE7``z?7evLf>uO=h5E*sdQf(Sha+nGkX| zZnBHJ@@zJU$AC$MQ!3={IB{iBVzPkY3q1N%*>H6ssc{Q@4NbJn02Aw{gJXG>9X<_e z3F$aS5B5*s0gR2XVy|m~sE-k1!Z)mR5-H+K8L1$t;sNetO%hcMz)F2_iBcqP0Vfw2 zevif}_t)hh_wJH!O!cJw(=P2Gd;6D1M}tZCIcoEQowMW9F3v{xd3xK3Jfz>9kHL() z&y|s<&5L`*c7*HG-BVs0C>f{Wg2C&24gAyaX)f~tR=(LS&_neAxvHa=n^RsOP63li z|F!wAYseqMaHe!5q7?x0ipG?{z4qBO0(Swc)0+UQT%3Ln1!*=RTGJ>T=LA}iTwPUq zCH(|Lv^*B@EGU9V&umz2BX*aBk6Mydue-cV4(z9$kmG1r+MO*yRBA-S4M%VWjiKVo z2U}t>K?MYAA@^|Ild>e(T?)@g2E^U`;Thf)KkhG|gtl<`7MN}bM?Mz^zI>TE?SXwe# z?f#DP=R(WqR{#ezWR}AUqMcauMB`$~nrGxw4i7JEWq6mCgQ>E@Q0phcCVGTk6^6hV z5~?U$(W(2MSZIR@&5NzVK7WQ-QCuz0-1;7VftjUXJkj}E+BwtOYifd!S`9=PAEi(; zmm3KUGcc3c+-i2cz`4Q^JB8uAa0ioI-le70rKRm$ygmh?H+V|S4*4vIX)~ViuJ^V0 z2w#Db4<;m$WB8G$pZ6QRGu}hxH=A(N!;7MW#%okV9uY~;oia34!C?euixPtw)gUWC#~Ej8i8-8O9*pvB1F(h9dhX$h8UG z%|zk>F3pQU(i$nReddYXEf-+CokoVNxw2qIB%nucyJ)JQx5uYd(Dah?7#H*UHA!0| zJ`t7H3)I@PA6lKZ1ik)Rt`2U4-W2@BdkNQrw`Q;#fD^Ya3<&zF@9Y;7b%VuSQt6Rh z>EX<~{EUz4&H+qP`CJI_=>UDj1vbQk{AnGxa z^|(F&SX#ISTRlZk09nOU9Ii##;f07Nj@+7fk}i&`cL6d%!1OQ_1hA;QB**$gf3Qkr z4JxZwl`?RD*|S)+fKce0v&S7BJR7Y{_gKI>vRI_f{jjX5w z>dDVF#}%(8&Bi^j}71%v!wQepOBYq2iM`W zO=QFeTUnBA(a7Ux^<56;lg!NN&@pFn2w0ta0VIg#HZOD&LV^#%9QM(CG-%`pT?0_w zCu)^!%JofoilAo(hTh8JJwevfNfuZ!xHc}!SP^IT_6H;vTPj(@l?@M#ObDHuU21?d z?4<;sRBs@oU#;1-7#TMcvK~0!OtiC-U|~t=p8p65#fUkl_|V!A(1Mh8o)iOi_6>jv zb=Q$H;%`j}?oHw0m1V%X!=F(0N2~&BgP>bGX2n>~*^CB_N-IWnXLc?S)vD&nb2Dzu zelpiB6&>VkNS4d=Vt@$a9^RNdLQ>I-5h6TQYHupM;Pc4TV9I8osKT~(__B{k-&*K8 ze}IJy6VJjN8+0CryeI_}Zp*%oYsjwW(hj7-z;|gd7%f3nI1zh2gk!uGPKR&yEII;x zhwqe@W~F7ei8gU@H$~37Z8rG$D)GwmdImMKv?R~#Xa;2cr)A^BFxRq&c^H0g#XlCB zZI^Lf^XAbs2>I`(t99pQ+2`W&9vteQEjwxB)>HYypRG$VLjQB#WZsTya;5HE z>&`w37(}jKoAn8|xT)A7M8Z8nqBM8Dq_H0iV{s$Dr60ULI~tE(>tImG5K!Qjefi9+ z__)ClT=DhVANC$?KHk`SwDI`M-LJ^n?%g%s7BUpX(W~~9@Y%l<#KjvceCcdc930Sx%m-nv?%!oJSeOJNr_`22A6%#$JB{KS%KPYm5=5+a=2X{*4PvOo(&SNLm5 z2WN{YNN3J$}WYs)Lh0 z!nr`%v06=BY20$G5&?sW?|fGy2v5J`Y>0DMMp14)zx%Y4Nqvs7F9=v;*JWI*^Y>merNx5jA~m9KEhe@d%PexQ>IM*b035RKloS> zIP^6x`0A*u$guUps7|J?5Q0jfPoWTRLk}Uqh-1Pyi2Goml{^u`f=<Gn2h=8S3X-A(yWl!iK936g6;>v@?5QZMZZ>@(q^t7>ClzhopjjWZcl5L60 zLxd)iSd8Lj=hU(1Izi)EXm6)4%&oF#Z*=EKDLUT*D;C7|!TxhKoNs6A=2($C$RU0T%B z1ME%#+@;Ec&idzR3WR-M#w@v6!^8PuUHD*1PU!8UfbvuPG#DXyVvNE=KAA(3LU;4* zCG#k>MproGe*XAYL4}hyGV)MfDKd_TA6#@6z3FUU;xqlA7r|l$)&j#Z^n0%aiA|Xh z%2z0oxXaAg;UYqbBBsH0X5+<0m-r3~zBV%B1}%I;7)BfJM7{p?zuo&s$Df#;?;rNV zuMhZW2``Yh%!k#*)r?JDc`nEx(t7Kka4x%meE$^p7vV;**-u2`m4S0Q2T zP?LEW!{xhEHF+#chh>SDOyliUK$bA4bs+vLNgz{pio`bh!$qQ$U)WFJ&?`?$|EO{< z^Q)YfaO)*mmW-|AB4xtddG)Qf;oHN@GV0;uB>YK6k;T!_j5StaK~kV3Ph~Q}jo-S9 zd+ExpbMufHHryzddQ05*m!iqLX-Jy88`J7<$?oIcVi@WcNr7+b%Of^zf)5MHY?xsH* zmeL@tADs@*!>dIJ<;xD+7-($Wp86R{UMMnJW`{Y*%#7a|8Y>=3mxQi!P~7NSIP?mv zne^t3VIk&nm4nsCEhkv2b_S!M>(bfbO~7CE_0=x{7g6GxVa}F$6xB<310?E5a=&0( zIG9HUqem5SZuhxY{mSRk4Iy1O*+~}=N?OOEGbzYZDnJi#*^BwMkst&UJOVs~-Dl6b zk`h^CHLje;WFom_HjqjE8jD_s2^)1gkmcF^|Nh7S9#R06gwx^i2@+6GP%lMn+|r=) z?DF1kfA?_!fncQY%dk&uJ;|`CL{i(QgyMfND3EOTq8^A}2Ow&=LbB4Ptu&{K-FG*l^oL>sPs>LHk6-|lE<#oeV+;SnKi(2&Gi>Ws@#6pi}+7gfC@%0;Q$I#gybvVqlY5Ht6Tfa)3N(E!x~ za7o?nEK{Tk%aHvKuYtlh&I(NB?)zGGXs2`$Joq-$Ys9chu}!$U;X7t|yz%8J>sLVD z)tJ}5Tu)>qW&#$rE!-RbxpT*yjG>hToQUlj?~QaGePMq4-Y#aclHe%&2(#np1w>e^fD~-P=6O7~NQ_gMAOado8xGCufa14%U6UBe#kjT;mxP@=JC~{T<~- z37+Be4!3H_(QPA?Ac%mP#bZ<83q(mZ0EXkls%^;4T+KF((26MOg(GZcZ1BgG4J=TQ zaHq_KUs-Mgr!5xEpbZ3j4p=f}++jeaKXG;OY8+Pre*i);EYUQq1)Z_^2!}>xaXRH? z;lHu{Mt(Uw?HJdooKXab<2Zy(ihPFS%kJG`kO8|JC3Y0;VHTs{T0fNNy$vMq$dxug zZCVon-X|L`K8fL1RKu?0`1Pa@-jsBSqEKind(hxLa4|&v2Np8XGKc`zjJluwRxgEJ zL;~S;w+jt_LL!D_4I@3 zbBUjj))9PJLa{n^lw<3n3?)nDYROzS1sPtfHo3AjLL(h5S&y+0jszNKB$E_cMZgHT z9LLpnc7)5BhcaNf!E@)2lDjXi@Zb?owzDOI2!@j!HnbreA;@USI@mK=iwvaD2fwb+ zzwX~{l-|;p+J4>*hw(sDsq_&dexZRZ;vC;|WjvIr8FZtOf9 zEWU*!VV-UXo?@BCOZW6h6%}{R0cP4DXE|>-$hsngS)vZA88(6Rep| znN%eUwOjtoGK1chZ&<~G-Pf(6Fr)~~GU|SZ19|#Q#;2;Rbr_FMd&f{-KgIuqfKyWo zassDeRhnq^hT^MSt5wRDLGNL%%M{FC`AGB6lUbEO%Ca%ZVwJmGJHz1wQ=|B7B=$$~ zA&ekY7-gMRlM{&_3PB`@r;7tTRM3(clR%hRsH`!ce&;pjB|R1!s}iXtc_vLYP6tW% zrKS<;xs@P<5j596@b!0Uc4F~UobrsCJ|~O*@Bz9+m~7QyhG?`rvb1e+0LGOCAClwK!Db;*&ELK z#3{s3(tK*K4|uJGD0Bmik%K^F`AG0cqDk^(G*^QS{j`&8DQZcU3WsY;97qI!h)(mk zJACCJN{J+zD9*_L zHKCxDpwn#&%D%4N$ia3dkrUrJJL3#FKLwlUys-WEk@WA50j+k=Yxh=Tb%sPSHk6G1 z_;ys9${*fHLaA1;A-pbPmEqiah6&`3i1AFxV-VXsJ9hz>!8?<=a6I1EWpxusT2lJQ zeR??Dli);yA@oF-`!Zp7;KWpPiKdGKe-91e*n*^lcv)}|QCR~rYD}0-!Bq1`zoWHE z_&s4iCn9Uqc31==aG4Hr~S*>e%c9t*Y%O&$HA7QaeSXWA@eC{lDDK zy{&wa`4QIC5_D?7h z>cZQnUCdC?(d`LxGp|B9qPZpuT=6I@C<>)d%hK`{y%l(AftNaQ$rK6^RnA1Y#E~WM zE?5N<90wSQM?H)>wdDj?2ufzdGAyajDCy$SkIELFGY1rAAwBI_7wGVz6%QP^i<7WN z3QSPFt)~R6*P>?zI$}9eYO720Br6>Wfq1`Y%@)!P@WerCI^lr&4NL$r8TXP$;bU+5 zkr8D{|T0*ty@*9!cr_v=hR-LSG~!QgnwPFSCxjOs^6>` z8Hj|gh?D?+WfRioEzf`t=Hve$^RbNv{yUkDbJkcWwV8da@(5yJxmLw5{f>G~oDrzg~ISZzb2Lt45|*kKtE% z_8u=Xm+uWg3$;qXp~_aU><|z7P~U9b@%wDi&C}?b?UKAx)>BeK3dZRn)7kLS@Db86 z@K$KPWtV>Pdi`X~vcd>Ve)qrs@9}g<);RFbj(f-+!$-@YKN%?rIAaWO%kBwiPIU`Ke5p{Mk}>;s(%T59j+UU%Un%d6ONlwX1%mN2x*W2>X6SM zV_vyBxzac=R5<}Gs-uLdF|EcEtDBIEVTe_ZHpV+5Kx01e2UlI{s^gX{B6Hi=R{J7M ziQuc0JU#*sT_Bh91U4zolah%Sk-I@izY_z8Q5KaO&hZIP2R^UWR!rZUNjjvb1F1K7 z*+|(InnA>1o_7%qW+-uPj3nG;FbHf-)y0f!>rB)doLl@N9kjnKfHFt-Q%n)S z51hI0fVLP*V?Taa)6Am1fNMuDP=a)VR~aUQg9-)tPw|*NV+;s749+h| z_(B^;)O7S5D^IJ-9vu0#xBBpc*TI+Dw4o+tmN@p{q@Pzqrl1J>}4_`*Qr7g)OHp=GY;fVDt zLly}tkfGpX?=+o8p4Gis(FWnB%bU9?5FPF?vZvBKbXqRO9DLjo!?Uq}MWoe|zXV;9 z9m=n3Nbg3I0|m(_EgtaT9^omolK|a z6Hvka#qner>2%A({*-_4_iqM=Uw?7ui_h*TTN(LtJbf@$%v*CPeO=wtoV;YOkdQa7 zzjDf9BC#awHJe00FBz%Wyh1UVQOwLh&=>U#C{%~gAqo=8_-{Tv5#9uy{1bTFQEg39 zxA3UAUi%WNhW86s>Iheq=eY40-+zCwyG4$qvd4=yu+wnI5#Bnc(@Nfym1~)Wb=`E( zs$)G;fu%tzi|9O>VfG4{W|$Q(=13T@+c}z^<00U?8Wrqzf*g_$$pqK`n6R@SWYWY$Z zS$v6$Kny0=hp+8-l)G_v-}8RFch;z%AWZ}W26{Mn-miW>IR6 zqiftXqZ28{B!u%=l|CHN6Uo}q=LMYAnAl=-eA|6C4sugYZ*{8xbD zVG44-Hfuvc%L(QCU%H&dbLp2*GFdoK3sx}1k!Nqtoc+o$7 zJyTEBx4?dRhQiCx_4Kw1a%fQ#p1NurFEJ3kMmfw`!q@P#1j5mT(l`J=GUd_!X;c6o z<5s}%buzICR1&E<*{pMOtWEV0fgi{hDBw-{{qKKYI*@U8StVFaPo0i7d6fdF!&{?R z{WZDzhu=zKBlkhWz&FycQCN_m2E$atA&!a@jsx)okUQ)5BH#wM-|K8R8VN6XIm7xlZvziian3V;-h9sZSF4aX>7%4N zHj0iRSYe2p0^vulMvVi@!C=3<#1KJUt;uM#0g!-}TN*hVP+fV1&&MwZ6PGg05<=FF<4Zugj8xDLA{O{-Nr)s-sb)r% zy`h>JEfeTHu=sWEYcMfxfBuJZ7}8EN-E`JNTt;eQUviXaKc87x#-95aqZ+L`+D#&mRXaDvxsnQ6&``^gZG za_~>2cbuIsJ|Yl-At<^HNppq_BMXsDs>C={kBb5}-{m6hjEx|(WZDq9Rj8Unx3f-O zQkfmSLYKwix1_)^*^{gO1_}hxs8ARX_(x`E9r*O?LUNN`!|AKzF3yS#juwTC>Z6<{ z0(~mO<%4#XAam4-e;c>%Uckl`v`~8DWDxc4pCzKl0#GTV+ek@T)6Y5Af2ZTN2xV@S zifgcz=39a1(_^IEIctqd_oma)=v0ebzp^7Ep^3jsNS{+tT}s>51YHsY} zToj{*4O>R`GnqWHgzhvXg0v~uMeqO}F6E&Rp-@!Wf^gbCWeC2@YU+-`jhSLjYqqCYdd>e zYrEe+TKi!G_H|>^oj+}E?cIO8yVGi4e|#_9BkCZ(nJscz_WHeV(#Q95N?v%?mmtc^ z5+u?7Rtt@k*sj?3hR1zsM$93Did`z+@9E?qC%mJA9{>$%$Xu04mc^+>$st3@C*9G( zw0COvF|y}&rETp$OBZJ--zpzdS&}j2ljec4SI@G+mV#p?T%1P1HEsaS5{#RAUWj=Z z(Tg6K9Kiyb5e)X)TOs9%#gF`Mam92!Q3ezmRHSR} zQeA5mJ>+6|KqKDO#m*^SHh4K~4rb=EMq4U+4ZDpZhLc}H%wYDn5Hp-4U$2@Hh3U#> z`6^_&zuiSB1Bb=cjnnnWTF2wj#reO2Xc9md7fre@ZXHFF{`DRuk`DNfl1Rs66r6N* zL8kuK5=n%Au1KDs#`X>$?UGED zkC8Dnc*OwDF%xIH*6n==GXV3C6=wC-Hz`o$rAvt9_qK|;(rjBY@#u*qi%>O4f~hlo z%bq&rVnUYEXsn(G5RxE!r|?=I zA_~VSkmuC}$Ygh#{K7G1Fk4ddaE+neBq^{u=nWZN#I+|x6M?2f1EAU1(Keo;1^&_n z;g`7177GX7FhmzMVj>s!3>SF{T%Zr0(Mc*AH5I>kJ=q4@m^tCO4>dlWL)q)PW?f7O z*ig4Om?Zlk-yZQM>(^OK&^}7Nj@cTbW!8eb8t`1X+eAvkwI-y{S>DAYsqOPSH~;v1 zn1J*`BKOVH-jIcS(K}t~4_EvFgJp$}$#DO6>(*y~yz^OD2dCqYZNS-JJZ5-aflG)$ z^RO)AiUcu63bbTcMe;z()*)(2Ps`8KDt0USjE_f-5NRv;J zB$Kexc?6)-3;L1>+Af|=oG>{~3?h?n%KI=SaYJGvNqi*iIdU!tC0+zz#FnJX4|T_C z*9$11%CFkQi`TH1@FhSx9l@nyY2bPI(nd5vQNHdmNVwGDEu*}o^vi^5DW6)xwaxq6 z8mdij9r*uk0=5ECq`P`Z6^u+FuhJ^uL3=c)@)E}6;RnC@{s@<%S@`cc$h-q4)zjWNJY06s)ek|!`514z>q`i3{)0wk0mJ~_M>yhZ z3D#y&!t_YO{2-RKbOD8B1kTmpa~NCBt9is(YE>o(EWllv+2%lnFxpmW((AW%zc8Uv~$dp#Y2`x&w-jE zCxPn-{=NuPxfnJhBdK37wnNgE>wTQA!Pqwl{Sb*=BinMtt8a z@|@~QJo#r6WbJf^`{;ax_i5(kl^NJBqMAq3~{MMaDT>1oD%iq`Xodh^z|%!b2qB;nO%l#R*ocXPq@rqg1#$lnbqp zAn@@+fKzQf>EnjDm0>+NMONGNS!cPrKdN4jE;N&kM`P%}c6i2T9jB6CcmuhuC)3F{ z;LDhW(?%X#Qm#?te>E?+Aubx1oyhm2@#su~Qba*;uB*f@xpf}23RnGX`3@gI0W^K&F(BEAV z@DP81e8LNL~e;T*j zNU`(Z6MZJq0dNcqH{d-X#(cYSN^IH4j?(Dla$(NooR8mb?Uo4#6;B$;B%#)oUSkk&bd=k!4+bvZ+xHCBLip3zOK;EL!FJNf^ z6t;BW!eSw-lncngfHW?Ax!bXm%lI)a2n96D&z7+?q}9s1T48XLhZsjFA)D$O(2R7+ zAW)3fRmC5~!ACblBDiqOL*s@XHe2=Mequ+1?pp0)<4fOz!W^=NOkuOGsvtt`m9F|% z1f=MiW}jk9EzOkqQM<`KDoIr2;DC{ zpF+m=;><1W!^e;*p;~J2p#D?_6zEsYRC)SUs9uVbMbjy&?gYuF{2`Qv25Cx+IVVWT0lpvKAu_ zb3VldQxLRuWCcM+Fr}CdUyW$m;q1p7B>g=63O$DgnY&SqYTxyDVQu28bWO z3Gk6}aUgJB&*G&ZbAF`+3*ZjegeJm%;tmX~2TQ2N8o`M4kx9i`EU#jb@fkGxqdmaXyy$G;Lw zHus!j!yCPlqEQDTtqH^$n6*(ODc3s3JxajJ>2+YISxKo%52SjI8lCOm%pu#h?DYqa zA3l8i=e?c3{P1w|(VuppSX_qu1M2~xcP09ah{%d_h<<0|;e#5@7x-+XFfd$w_cZg? zE&xY?)wolUjeM6{FC-e906nJK$|FTlF6ZY%3-e_1PvmR1_a%vt4cH2vbux+O8`W0K zR{Sv(am0`Zr|UUOt}Q~ZdFH7XeYOE6WMcP2 z#B-nk%t{JqR%8bg_rdcRHxVL(MQ)8A_sO~CS({ENVTxPPdBZ)xO|>p$V0QKTGkPTs zs9^8)PR~zzIuHG;0defgA2jq=?}?x5)h+x_y+57R=nv7x+I%{$!*!dzvcdDe0Hx@R zjD;nou5?Pi9nKLF3z-1QLAM`3Y9^?IlXBAY8^$|o1+66wQfQXO2t z7kI`qBB_=%y8wVxDByBwV?&%;#SsgZ;In*AYGNn`fr{nG_OfykMjT}vMxU>iaqU+I zQZV8%3Qi%K!J=l_deV#l-+=tzN2n0L>Op_Ln@39#$^T03c&D5!N{jUb;gSQWKKTBK z^>U5|uMElnY$Q9nS-5&?9(9PSuArHW1VITTs}ztR*a3WiG;3(t;EoTf2HWt>+`z%H zNU1dfnX7Q={zrB=MQjnyNhGf!gs2PdyVq%O^oW4a^XuMH2s_wTiWN#eJr z6?O!Zw$iZ(y8Q-uaD@bPg`ZtHhO4yuos-(giQP;RVGLysDlQI1RdxS!umKo*BGPQ4r2+sw+yUr+eoR?;ku$%)v#ldBtP$dML`A?##`bR#3Au{h%v~NDq5H2Ss6G@X*j5D@hPSa45aj_K- zN27B%I#94w@-;O|->Y7TM=Mel_D3qkh<6wJb?au;LkZBcbI)YOk|@^jloZI}=9e(h ztFO@NO9>~G7{t6PDdBUx7!Ljm$pEClC{+wWj!g0s1RnjM%f^e#>^C^gt@)hr8%$S36WYaboc8%NW&K+xC(pK?&I~{$4{yk7pIi4`%*79gM111JP;fq zb6NR8qY|9Bm=yY7)*L`VgrEZ3g%s_;n;W1{2`>nvoMM}^_K{7*eXNs}`@{t=R8)x@ z%BpcP7ja8AMC6#&j3Pw5`z0j|Gf3`v!8wDWSXe8MBy{{h5va`|^6O9r(Rzj|9Yibk^Zl7m&pO zlxe@P8j2R;;wJ7wR?6H$w08G)Sq>dE*7|Z)EKCO_)Lg7+kGd}*O`K!3{M_$DFrz>W zgu`UO8b{3C;E8*C`LpF)(86@t>P%#T@anVWn>FmoPUdOwAZuS}lD;0%=VLS<6kDtfOe$DvcP0NP07dQ*}{nTn?Tl7PZ2a3ShgboGC^qcP&yo!A^-DJ&P%1 z?vVob@LXT|EVS-U+>^^L`a!6?u*i@TStHhdV*+hQxCRzUhFw}G3*+>O2A z#TiPL98bEErCc^6pWK6|{1^$MWI2iGzNZBa&IYd_kEByu`dAvFF+pmQq|9+o zYZVfF%T;(2PBYCY_-~k+n8oDk9ar*N^xA3Ra~rPXd<8TBy#1z_82; zhg=WCWBVfCl4wJ(V2V z$y2#^8q~I`+h0CjmOr5euVBBb8(w~wAYi-B&aYi_SzVl1(7Yso&X#1?a9+tDdT@ws z?$?zyCO`hIDDv;9xH!A-YE*0PQ4^M}!H#{8%Jriz;1)qk?ACCA) zc<56YPY2Jx7d0IY9n=EF8@v7x1nzV&F$Hn^eNZ<%98`rs$*|3zgP~sIG=(n%xy)xs zH=yr>560OoA+`ahz=!uKJbU~LLX3n&_n?_{d}#uoa!}}YGOCb0yg|qdK&5UD&yTy; zmaE5TGv;X0PW5a!T*NuVKsq?x^R%S}hn$cPWk|ISq0M7c7Op0!^Y7*gVN0iAv9%IN?B+~h_n{H~5c6z93k6%Pd zS>k@tVJkg?mPbm1e-Vfx!r2CC@|qMu(;l%8-Fz}Y^dE%oHer~zT`L!I3H@LoC2zPn zrIHLZf8W*HT>j2_#EuAoTnnpgu5FlpAAkR5l`pMGonEd{it(m0*p+U8-wnNL`sdP- zJdFp3;{%@g;!rC~{-Vu|yB4={P@9ispVKihW8yj5J}D$3UX=U-%cANBa8i9ge5j;K zf=g5f)4fFCAc_e>9!`(CovV|T$(_TqmWfTx=eB$dvOL#jY$<>`O+Zv5@$jXyqH z-n;SB?^XtA+_}LX+)!xac;@@0+nJp7Zh!to_&6L`LLUjMJj8TD$#7{%?fMoyLT;rk z?Gq}>m6tsTEtOu*2DuF5!XaSfpYR&I46^O-Jh4(VHZAn0N27P37gX9R;D!gjOAl)TxT~fcgD>&+fo%pr4DMkNPg!jr3byGqpX*BXW;bNp~41RUt8!E zB4Az-0Em%Np{CEC9Xet-$yq3crH3Ps#M$Kd8Y2W%_Y*mdCU(%D#Yd-3|l+vscSrRMm8jk=fk4&8k`@tdjvmgW!*X$G{-tjm37;(%Ln>>4C z%I$3ybh_!O)KUiow=qF&LZ?8-<8bBXdWCdyxO|T)#PHzKJ%B=k*Q?0K^!_k1cfES} zc>Pa%kG`#V$fKGYGAIM4Fj#XX&pWqn|1q?Z?L1OGRPdC}ZRm~v;1dmzL%%_S_NvcX ze}Kdtq3KA;Qkyo8N3TA$$NO@^V2+REK; z$KI1iz@BYUfrhun6cNN9kIsKEjiPCUN9_2tKztk+gk^@#554hoB-?L>C#orE$V=7- ziS#XRU;q0E95IBx`NMLx14)U8}~P+haH7F%p3FcU95cc5$&DHc@H1%ygoY`4bw+Vn|8F>CFL#c-zb># zO=o5coI>X+$mKne%ztu8VXQ7Kn^OZVaXu%2Z5mi-{qRNU5iwv)NhwX3^gU{uh}kxB z5S5NrQPb_a8+Qkjoe=6q!g-MgnCO%((y80ocy$g(JMaa!TZXvn)&7Ovde*D(HfIsd zZcC~N)=IFPcSY$uLlLG!%Q%(kmOIN=o(-Q3H(tR^T?fhVQJn78$u)lXXQ-sKVS|a! zFRxq=dKHxzN0cPrLr`!6B#R>denvaa#>p0Hw2NJy+0eke@8LyzZ=2B7jeunD9$!om z2)u7k1J?J?khmQE4}vP~w)$*{cw+YRYoZ;&qiNqD)nGibLLu{i>#zjaPCJA{JZ9GxOd%*H%8*hvRkj@%q-n zSgxr-qZ2VS)F(1gYeTWG@6A-Bi)rcKei!+?3n6?6dJKXXp(s2yg=dIbBs9!mWMS_9 zWou*ayNyR1+iMTuF}bCrk$ks#|KSF{xa|VmJ>3~y24^>q0xWD73BKN8hI`kDHV`?S zLCFB6{GY=c!l7z9CxZa=bW8(^ZJQXWdtPz5mua#Cp(oxb77YmH^XKzw%w7f4;NLZXSr@4Uon277h?nI%Z1r1R}b|O zrWy~X1z$cmUKXnE|)AVk3?Zi-8(UukM|C6nyG5b!uc<2d@7eK@tYhsE3Kegkpl04=fZDCL z5Q(p=w=T@P-W$U5e%!fGr@)3#M`m*t{a1e6&Z^i{O%fCJ1X zdYn-yO1jGza{mVEpXfy*I+y{h05dBi&0pZPekBFVZ??Y>wz7i~_CD@}By&KaK0-kt zPXhDtlsZs0p5!pPkWZ3|uZI3r6Ga?=?<;zO7 zh#f+Nn4XN@G3w;N;%E%3eeuWJcWx?P+0lN8gnLMY#3pKuw3?sCTQXUDqNL9)%NNB) zjYW;TH|L3|%p8FC3@sf8H-ZR5q{BI&a8OtEnqgs!7((S={K-Fwe>Flb>veIwch(;t z_q#Rpc`jl}3ZSX}@I|-7&rvN4c{1S>EFD4a+;$;wkz})35&}tF9YKmZfT(tqv?R7? z)h8_}NyuyC6)WHcI05;_f9$5C3Y0FsePY8*00=C}E#Y9_K(c7zs1iNigxQs5*Z8=} zD&htuY+(nD7T;58T{tFVW06ec9{f@+nTv7aXTV#NfUznzUT%2icv&RQvL6u@h;}B9 zdB3k9Y6+~jGMG~|TQzW3Mimh?2~qd}CK7dwzki7EJgd2&qMC@xR8j0815_%WP2jbb zx0p|ncZrHUgJV2%672$HJH$SvgXtfmPHvr?Z_LpsBZ#VTnsHjXA5v#&i{4X?1SX+= zRs!HDdq$CoN~g*Y&wXZ!#Nk>rAwmlXXl?s1daCjEzW#k}S%8R(NCXoAi4Fbao`M_>F2;1(BXQ__ zkkCalq;Uw$4Q#}}`PX1*mpSS^JhQ? zO0zZM!%t4-%eWO3T>UW<8)0#fW8 zxwrn~5k$e7g@Qm=9_(v^+PZp4z^uru7yYEGkPF|Vf5!%C*5Oh;*tQTto|{m5mVhMx zC_w#n^#z{1FyE6;9z<+SuP#rR$RittR-dYc6wj)nA~6G8AsPnU2DxY1POF*%VeK`Y z+0h>DNI79KB(M7N5k0jFcP;%YiS0+N+MlGC2e$9Rwe zb#TXcR^VcKh#IkbUd+GSxfrt88}(j}P;``aBCCZ;va$3N)LxmauJ$Jfz4QK>9f4}_ zmz|ASb%Wyq3OqrNkn%MRZUX9)!Xi@M1_&*WIw-^3GANxDjTb&-ftpPt*qQL9Y7r}l zQgP?ug5xngtoW83m2og}gddE?s>JT`J046=F7_F+Sh4U$_!o5taVc%(^P8Wcu*^PP z$X4bDQw0UVhIGS9z#+6*1EZvlEQ94@TC~ij@IM~lk;z-gR0!J$TwlB?wIN$nJXrKaRIGxy}36S z;vVP#1bbj4)1s$I-59(#g=?hyJzTv~f-40DnNo;J7(OH}r0~@EJO-D`fMT~3>sL@u z6buq;QG~Q*-1$}(UIUkdsBak`8H;`uGdl#v2=hxuvTG9@Z%2k-hb;aU0}J=)xHY^i z;r9Ae@=`$`awStPKl9VflIF22btm_bpM?p{b%W???-c5KxTycLe*JT{LTCob+88z# z8w-arwF1=%!YO4dwW`7ayyTTRadGLq_8Q$lo}+7O3)L;1I>EaKg6iA#WGGyU#5`GX zsIb|J@eA!xLoQD{uU~GAUs9T`Het!=7`PnChTWO&`DJD(0ia)8hioL_a1@JPr(B^@ zq+sC2k(2i21YswQNutP;J=3+;vHoWkDI=jk+))FXOb-V`=Yv+%O9iK9#2W=A{LY%O z^EZGz%pa9*6r0In<4!HH($^9Vhj7klKlFSVK1~G$r#FeumS8DdwCzl^N@5Qs7w{@1 zc7=rnF(Wtwg--Fbt`t5qQVh7|?j@$v5EI@D8$|}ivs=(RU*i9y0PfNJm50$I>Alpr zB=@51PY^O3%hsugZ^AU!yu|&2cLLxZ>DJ+)CX7vGS?)q7VALR zuhTUQ^)}EG1QSoX=k?uXlk_JZ8T{0!-Ww1GrLq#YY(Z1M`{kESU-9cDSXw>e5eXK^ z9udUxJ~Fds*S~-A=udk)oBwO0Vdd=1nc<{|$$-ML7^iK&*p@&0nB;k+ef?1Xo3GHn zam+VtH0Nsp%h%*v%BC}Sk<%qRxyVu)X-Fncc+;2R|6X#}*{zP3`X>ba2=%_43flG> zq5^46XDrUbB~mEvwfJT#ugJ+}hJ*%EI~>NrPYNv}^R2&~#VUHFK#>DwHmTl!iINx0a_fuF{&2^n zO5%RsHgftIQ!W10sqG2%pohrO|?sRdx=!sXBs~ zo!pl{pFn$q4*?_SXNnF;41D~$gW4;S5eaN=Jbqxn1ei>KI6|@zfJl5>W3e4ap5NNM z{p`6mJp3~?>{wa^2de_;MS$8VRe=xD7nZjshJg@7A#!{(K0y|)q1%>Lw_uCQUbyr4 z7^60A^Eyp?@W;&kZAO8tlw*Ey?6o`gNb&7gO)T~hW%HBa;FXBN=&#dv;4ltf!W+CY zQ2;_Qc6>jQSTC8!={?|?IT1@&p|EM`j+;(j|A3?;)of>b?w~m>+VoKGC~JJzxN4@4 z&%gjj+AR3Z6ndm(Oc<)v!Ad`%=_%G9M^2Z^gj+3J7{!unG`fnUWwx%QWj1fpKKtAj z$8PRX&*F}<2vhb=8LT4$XCDfQ!DMY&UEp0#Q+FIJ?iwtQK@q!eRQO_ODs_gYY>}mw zw?uVRjcwpX3x;)84*M@w_=Tiq(YX}HCD@r}n0>=<)tc;3aI!lR_8ZcvyGiuRW92nS*{_}-BLAE*u|qej-tR{0(# zT2SLDpfKhS?%e3`5RaaHt$r&288Cw86CSTi=qYKDgK-q|w<=O456 zX`q7YFXbmpE6)XX+1>nMSZ0u^0Igfg;q*p;o$D#k_M6N_!WN|oLjP&UiV#F zrM}CAVCxk9E=NHy^Mt-4DcCGQkCmtZmjkB|!K=@y&q6T?k!hLHD)5@&HA_?te-m!L zWH6wXT2Xor*1ekIzqp^$^m1zy+8Wd}j0cumy3HkUuLG-%|HM=C}-MD)5{TK ziVq;t!Hs+z2GkHW5Y9`cMiq)FAUZ3j3cJh6G4n!FtoRT1eKHy* z_h1Mw6t1EccsM2DjzLv05O7-WJ&X*3!*c>j{*u&sul`=Fi3ErME8w{KW%JvTgn~5J zlj==M0IrggSM>#g27Q$sC1o3fdmS)5dhqPo04qKh`vH`=n$y?XCYsENVI!;u!*zU`s#u-(!TBn zzb6Fn?7Z6dG^w;9e^)Vpq6cppXJ8X8RfsX;CN+cO<3;MD@tTmLE!;Eo#h?Xrz_Qfn z*u&kvS%7eSM@c&b%}8NiD1Xfr>-lBV&y1AiKqj+aVP#-N%{y^7i0~st@dbJnf-LSy zx)M7$Eti!7)VwC!JGuzmCgy(Iq4-oJ5{N4mi{V$0Td03Tqn;lg&^!uoA^ z*dIN4NC)%5Z``*|9i-o}w@@$euIaI;6sa=f8U=NC+{{;{r|VZr2Ir%9nSUjf(Wz{K$R*iovj`pPPHYpWx=MXTFA2Qk(}Da(PGY-$nX%<0qJR_mPn|lgR8pcs)o#8)cf4_w$7IekC0b+Uc8^3vBkq6m+sHv z*ID8E#YZUb5YOwmMR%ZPC5JTR#rlLu)MCw3k%zs6N0`obLl|9`Nc*Rn{c_wp$AjpQ zr{d(KpxgU2@Hri$6})VNQv_~5Wv~d(Zl~o;=!!MrSbyy0(zV_ei2;NPC91_`>C)n# ztUB;vm{U-*sKtX`bzooMV-Z&R`Ofaz?vtIp?Txkjf5DLgE30?-I_qgI@Xt1$uxA@V zLI1F+)$Ydj52*cR4RQGr_Ys-aTuyp_^ASe6sY1&kQ8$17`hj~~!_x<_nXFJdb`mxC zSlbrc0iP#^LCODQZFSuiQ!dxuQ1A=(3QQ=soETo^H!n@O32jlOplBlpPVt%GjTH=v z&*^a0Gm9%LzGQpsTJh;1R_HIjvAPJwr+vIP!}pMikKy){+5$U>vR>2xmb{FUyD@b_@AQMBa0$}${;ewcuyUJ$$RTewsl=fKtbClsIzy&3W;gr z5wdJ9P?(q}E~(W9GB3y%cW&Ie^;v~ck84B4vIRDHmapz$b4nmF`xk>##0cO*j<({h+h0gq=m#UdA8$g% zOGj!|4ft3BEVpj|UOIq;rEVo_SxR-utj!;M(BA3bP|@YZ&eGW-EA=XPyoiQ(Q>8CV z<>L#~s*4k&<_pmvbi=Fd*>{SM|KkGtLMPPW#o0O5GR`3XOwqD=dfGomMH<=|%s~bT zWJ7%>)9j9M`DjI4z2_s`10u!b;M|dRTjrrhO52#{NDA=h(&AePF7eo}R#$ol;?Bo` zjcBEouSAXbv5+D5=?r>4QsGAXe}%8@N;Z~m(}U9yXqNs(fr&57oU=2A<`hFnVrUJx z^l^d<#b5@+6vjg2`Cz(*e;R-&y5S5&NEOJLy z^I|Yk_DUPx(JjnIx}7!9eUxh}RBLEEYe6AghQ#tbjGXn+ZB>~74n($~TwCg$_Qq#f zL)%$9^vU|&asR(iQAlo|2SlWc2Zi3ca|dZ)q;uP`NRoGShu107UB!Zt=1K(;*`_0C zZiiJD0ZAPH5}`Z%G@anq9o^Y=kKe)0vR)bNx@9{U&r02p3fvxq>X$Xv4ck>fPGvk} zw5*wK+qbCQa~w5GhMRi0u#J18GKJkcmAE~QfU0|CFuanj;B(#8x#L(^3%+0(24`(C zj&A-Fq=V4;c&0BM*^AF{dp_Z?&von9x1Pu&Gu7z;55@vN`X*A=Qum%` z6EN|&{;a0T*fn~hqQhO}ONPKbO3O_zSl9|5gZN(oz|Q$-9PuuhR8z5meK+xPsCsHHPL;t~nJo`3d zcEKniGC0oWRX0?ezGJaN`o2DPznVM1I@D7I1@$2LjBEgTC(gA7O^w6V+5z-Fh`2B$ z60}bS$W1XcWpeN}9)OnoD)Ev+4Di5ht9oWmwFGHU%2P&Fot}H`O{HEW5o;oW-$AMX zJTrLkOo-LyL{qO=@?y}#?+6nz2{o*PXJ+r>l%?)828aeM9fV*h-4ZY1aRdQSb5a5d zQ++qQSb2zqmRHv;l?+GhL{)(sH{hVenQ-F_PlZhJe`xA|!whi8S13(1s(L6Zzye9> zkdmsk8j1|gjJUo{znh=mz7zV9UU+v)icltKW#YLh5#7%J+IVz-Z})q8Hc(Ia!3HXV zBRgYeh3L}LnhY&*j2{>61w!4WI$^K>m)Z8XDz-q1+359zT}c^|glMN9EZ8)Yzo5+JtZ zh7eqaTx;Vp(XU2~`|^a9J}TAiux>rlK~Ni=7WM>XN$*NoeFUww&f^|c-1s?jx*ID; zUj7axwaBg)g0kpKeH4U<_!O{g@SAd*0eN^c_C5l9PF(d^4t%U&@fhPT&1umF%$Wlv z{-8gQcm_Ji#S+*)>Y{|yQ{+=q;>Z=3BfOBw>n*xEI8K>@N?21TDJ2$F-@^+kB(7sau39he%!OF`Dh*9@ z|3%Rg6xQAm41p9Sl;yZ;Gk`JfryZ0?x_JAnvH#dgLyP^2zc->wrh5&RAri3NdzjRN z(2EV!<0uhLCvb;hwI;GN{HYq4RBn@GTg(iR39yJsBg ztUUGs>}*=~3mkb))IcL>=*55!zLGKwQK8hIsa_6e<^yuof(r87f~qEXG!l3~~N+>2V&)}YT4!Z{KOjz6j@7eVKu%o*; zk7tP4U|m2a66AU!^q{qzyNhTXv?Ah{PoASyyW;!D;^Yh({CGET1xx2_47!9|pA`3K5 zam7by(f~`^`5I9U?^hyO@t2ygxs2hiPQrKa zd4}KNwhX^VFIrfFad`5ELN@#iHNSog$7e{?0b#W$4ASCcQ*;L*0a|WI=CK5}gck^} zS8R^w3Ye${so^P4mwJl(Glv~=9Nq|@UaO99K25ybSp!NraO36?4x0g?+wx#hd!VtS zb-Fl5Ft@)WtJV_c$voCZZguYBl!gSF;bugvzBG+o-PUdXwE7lN!`@h~Ql9i6tP%qS zj3E9_NbEV=V61RKWujtTrLrW^U$?@Kv}f zcx@7!8x<~4ZkwyZsAe$vRdr}x0=PF^H27KxNCi`*dH?>#-C_yp(dIj4tf#%}#{Zvj zI!Hl;jC5&}dtymRsJkHXpvAtWA?&*qoa6s34B;1&e?}*hTHYOzyk zC(riF`ukJewgudc!5MC`~w>wWV)ki~0`g`{~?JvSvNqCl~y!X>!Vj zT4+8@x;0iN&8AFXE{}S@&C8kPKLy9^y zM!V#xnl$&fglvY#B$QvEn6$~F*TO-vXAAYQ!YfxNSC(O$00JLL4mzL+&d>HxC#V+9-vy?MfKF?U3*xYUZ}M0+Gke+kYB+OlJv!(&tF` z4e~$4pSBAJV}KL~;1QB9FUB69ZKe-Jch}HfMwN_#4o5q(E8fhiL?)(AN>6QsVb?dH z8}+A%!y#I0ItpDAl3(E;1SN)9*5lLHY-{9LBb{{SmfdW{QHp0AwS_;n+|e3Qke?A* z!BrW_BE@RBm56Iu&t{C9pY^fj3rO2H+5?1^NZ^DkFCi{Fisl5p^*|4xG^!=QBx1bA zHW^SV<@P^0hChTV9_%U;lPf~);N>_APG<&*I4uH2?sm2)O*29ZumZM>K9!D)zKWL` z34Tf=ZPckLLjP*S*-T>UE&A0cOi=ZH2yE_7+Wn)@Zjr6r_R|_1o{UaiD=;d+iOwtwy`nR{7+W?V ztJfMtD2v2OK$u6O4z$NhxLk#8r8Q`SwL$)c=x?*UnpxxV%abAs?eRwB;`C=zBm|<8ZdA+lfgN2wMEZny@1nFAof)tpnn2mpr!4uj16 znsF8ggv}>{k9Wy~VaAB!^R;1p^n1Ty^&~kSl5METpUac%qGtqfnH3pJXea?_frFyf zy5Y3IWdE&Bi)78UEo(Y5u>RRcMy)~p$VleYT>+lo<=hA<*rx5lorIU$6NS6&M5S&2 zOIv>bbxkvaKERQ-?4pG^4nk1NGowpRZFRmZ=m&#?N|Uxl<*lV=7sf}kIsnah!^$(% z_LgdnXYKsYOPn^EY>e>hP8RCRjk}Bb!ttJvTn+{;@(LA9SGnlO1T-O}OB3sE%mc@m ze&v!h$+}HR9u&+;=4a3a%p~8z-(+GZOnMv72F!yp4;04gzks(`AQMM`*InR+lGi9R zf7bdorZA4Jb8V3Y8*B_Fyd_^HKJe-3;rTM2WLkN6e`}?;KUq1Mp1}=n!HUT;|MX=` zrVz`=!gt;uF25W+M_3BwBBVe6S|Jwq)E{h}=5o_69)f7(C~+2waqZARv>CBw+}LbT zsHxCwNoz)p*3ntw=f8nLB{&z;J)0hJG{2P}Bj@%_fw$*(Q*> z@`+NP2Mm0+w5TMvQ0b?{h+OJR+z@cHs@pBxNiKW1FCp=}1xkLm2unFk;ij4y>xt{0 zxj(?uxBdQ5gC=~eP+B)wEqMrj*AqkzTchy*5~mf{;eo%z(+|QN4{&kuu+5uqlxsBG z6n|9eVgPzB5#v}GUYzaoO%ml_?Te!aNo62bd5Vp;c3%7?Nz*|BJQ6Qo^$#xOg1+sz zlMhH*9A>AlVQBSu4*-|B$mq4rH)RYS4lq_5okRI5Cb;*TCvymLZncv6dnR%tf`&Y3 zrXDP&u_2e@25QnoG1x>>WNDB_Lt41t|NUKl`}MdYEMYEF%$Mw*y+pBYJY16OuOiF~ zDLf-sz}0HeM`M^~EydYTD>%JJ>Rdod>72i&km5GIqkMA2yrXz}?;8iHvIE%OyHr_h z-$WF&@sYf!lFh*22s5E4CC%x8c zlANV>NwYSd7J)2uaud^+u^*d+uwkv8W12A^^ie?18Z;UUL#eqjDg@$or(J~g$SK#@ zdH`q2x>;%16nd6lUv?vQESIv>`*ISrNj^sC5trTh4qYsjdua-cQgI>DbB!J=j6E;A z%-tY~+r;Z-=)%x}(>g;(toYl8lkadXLOcq-C>^Q9!!DFPn**z6q;qtn@7iI1@dXJ8 zuJ5p>vcI!%65Vvd$|s(AEQxfZd*c0}tPL-eq8VapE7HOYP(8II8LUOUz#(Y@{yP#V ztoE@jtV+`LC=QV93aQDYJziZdvi{)r;VtW!gWn2i0Z7I!H7rgNgypsx#MsYW_`dvVw zZVHh@=^M1!Afii2i@RLMsHrooe#W9n^FLQ-z1Qxd@>-+xU5NqnGtsygi1lX{O3=Ob z+(+h5!t=l$L^IuF;VT$6kT~*)G%xk?y9u7Rt5{D)H<^Ir$KVe6f44q28Ii=9*{+t1 z%@3QijrmQ?X0}wacnyTweTmht0#*g@Y1o0IErwvW1d`WYjF43tYn^b(tDama>3gX7 zgcrBv@IZQ+olMtpK@SGs)I5h$mx$!U;-G&;iH;0wHkDTp0wJ@2B1#*f7T@r-u!28+ zj;il)j6!dKANxR#EbN7NrDS(tJ#+JbUUUSmhQ;fdoT=O+r{Hf^t3NjHR&sGQ#;6y= zB3os5Y~jaADtz0Owc7nQ!kIt+(%3BtnX?Cf$|I9Cu>zMCR2bLAo`#p&8!8RCIZB1@ zKx~tzYlo88?8Pw2HJWrqzb{gUYT^~bsXvBXG`U%bPdi7JWIP^DJ}@5(@Mqv#s>1XR z`IdqdaAU7h&#ze*p-wmIM7dbP8$@uxi$x=S#9Bz0h2qhz zMHZ5*`(c|A&xZ*98Hi7Uc3oYyVDU}B<-21a0syha#jr1J=V4zPnXrwS1<6w8Y(dbm z?6PklR)|O|GJaU2f8*U$VX~^@P|U5DF-7wM4P|Lvdprb{*EFVFHW*~&hc*u0aZT|u zt57A$xiy(Zv?L#?wjx_te5(j2uJ*7z&Mgn5%3Xy6PsnS=1d__v6HKIcu3MNt1r%|B zlIF1)%donM#8AuM%Kavw(`djAP4-i)tu%vp7koZq(czzmn$*WHmPPmA7Y=!FG^ zBw7j>(>uWri~-hULSb?gRgjx0#0cSSIV$ushkDyvO74=eCCSwY_z`e1XD)B<8Y#Mc z(87~Ga)`^x9Va*?YW*+CqqV(!dn*3d-`~O`NnKEXAYiDpDf@DJi{z1zx&A9qNXoix zR6^xi0_WETf{fvc90A=9=MI853CNLU__TH4}tuEs@a6odQk zi=zEH4w6M|m(;x7-Th0&vWzW)MZ9=Re4t>Lu@0WfTKZQEVGTOtLmTov3l@D>jc()Y&qeFhV(XvbHd2s#cBSU{q7dDD{M*}fPJbl4>c zT!W8_4idh}-tF`cPDa(ODpml()nF}RWTlMopo5e$T49MGpqgckPzlFdb(+5CW5r$y zspWeXgO*}9iCsjX6AP4oa?KwX3u#*GLK|n-`X`mIg*-q%2K?A7wA|$GaeB*7A>x1e zlfY(d4tzwkk`R+ETSR}%UH2)48Ee*9*+$Jg@+Avd-%Go!!AvD1rHi<6R~DFHBFP7m zQ+8_+0YuPe2p9XRRn^}j%L^SBJa1c~rPGblrQs#_WZNzqa53b|x;RbtU?#MK34xuB zQh?j0ga+dxc>_cr3TdMXHN@f-dH2EB1_*Wq?no_i6B@=QYh%I3c3<8~$73b6b>-qo z?P(OSD!G-;T-SeWQJZBpIkCBm9THKe`%q z2ZTSxiAiQ4Lz9=e%n5G0;HH<9E5?a|3Xb$7V;(ki1o`OjHDc^+NCPjx4A&v`5Z$zd z7x=5SHA=)9+qPD?B?X|iL$xg~Ol`bQv5N)p5?ZaV5vBd}{;cd83Gg9}lDy;MsrU#E z0zOmxw4o+YJqn%;@az|#-GbdT9&kfjb4~S`7h=S>w6VLPq*=INi#PBBx-7OqWo+|A9t4+EBsDvQ3P?pU*DgA&VeuIb; zDuC6TPPkHuA6x{>r)WDZKe=r{7 znrI+nS(HDD0sRK}l4nJ5;3C&ko`~x%NrQby$N|^b+_47W|5!54XoZA=^ZJ)BC)Xvib~cmC=a{0_ru2S_mA)I?JakjL8#$COgK4CMW4+O!S_Bz zL^!ZGd3|Aq04Vhvdrx*Yw)gIDY;A9>^AX{c5K|(MLb!&(xdh=%CWT5JNnuxQSe~c9 zB%biBlQnKdtU*#BHV0T{Z-X_6ZKu6<;!V$B^Ufj01A1@?=R+9KJr`Av$BsNa-hJ$&Pla>VW z|6G1bB*{DRQy9kP*yo_TNQTRh5LeMcj(tlcqyHTXG0Nj!Yup%Lu09RzJ;8Z>w-Q!LsdVHKBCjl_&-R98!N0qZ_<18}50mREx7 zIb-<|V1u>6yyMZ&#b8#pF!j>A_#t3_8{GEK`?JCx+j{faOG#)u?y$iWvtJYSGR06E zVq`N>dmG{d3J=~Vh1qQ-`L)nWxOEC1YjIkMWWv{S-3!U{_HJSuB_s}_X0F4gZ?wNs zUsJNuWzv9aec!$f2SOb0hy%+D6u%wp2Z7<&qL5k0@wr>*Wd?Q$FS)$pUV@dMp5 zu1gAWg$R%2Qt8Gt@m+|px80WmJZr(NlTpmlL%4;#)U6cuSB+0JhHy3w77m~bJT8x{ zOX!UK;RH1@Gtg`q<@TEfx20AAL-tIpny6TG z*5hhB1H@UDyxr(%_Qfa*)5uApI~+6#HUm9~ebhqE{>fLhq}&^>aLE?1T{*cO&yr=$ zdc%rOv$bL{s|}y3RpR;J7JRR+?*3(KWAD3-M;qH~4-=o!oJA(7F-dGa{dC4+^OVYe z&WbnhKitTco9t{7ttyWq#(Ka5A@0nOE?LN($%vJX5upt=4@%B-w^p0#LefNhH@F8S zG8E#xHKMlWODGM2_oWl+$O%)wE)nhOj(0YqD(QPxczpJdkdqRuX=I&z_9#*>6>~;V zEQugD{8dJe>(2OfNESY*%Uw*KT|vO4&k_Ym>6iIdi3vNCPGc!X9QP83arQEnw0;v9 znp<`mT$^ODqd@AT1B<3|%b%;OD1U{;xe!Q=yOj2;{wW-P5fTzY^XRN@ajBuByz>3# z8FJ%p3bptNGt4N#)c5LJzDb668_$*Jy!Jh=U&uzye<2YkuH>I1nm9TTo(*r*n&)G3 z-ai-|fd%(3@PPVQj$T&d^6-Pqj0wl^aB0#$a`}&Ns7i4bMk?)4wI?Wi{F)$8J&1!a zUS&?gFy=0(QD*T=D+@f|@NE5bB*(D5c&vXFG&!2etMHL3+ujQ(s1x*n7>DKDMTTC& zQHxLY7=8R?H~A*41yUeJJNVKy`~`Rmr*};rCM9w95N!=FF5p)TT1pmjhfYQqFi6?J zh_*MqaW_fqmw6&kY^3ju737}xPExwN3TiP#Bx`oeg{`l<2|#|g$9>%+O5!6gSaXV) zayCxFpT8#(-ucO=(>`^cc_Qx)seCiV$7(qk4_>Ek1+J1Ln-(%vb$$PIbimL)pU#1} zL%B}_N50vg005A;(9)IT(?Z$a5+hsMNvLWnQJv{ zMap+-CT#~bt;8U^tfK*MZx&*=0lS67&7_Jl0dJ*=C#1xL34@|lJ4Rg~@4+!J!Fy;O zJn=9X9*ywWAL@PBnbYlj|NW0Y?ESd0y@Q8rI<@;~&69#5+LgZ1{vH?$&s!y&WK(xH zA3b=S7$SkBXHTP6+;oiVhFy#f9czzuYY{;O2h}&w=BL;u#jPnTB z#9Cyd99$5FJhJ%$Cp{=sCe2QkbCb#>$~AF38_e|yT_zsXXbx=*ERv=W#1~sE_ZHg4 zI2iP>OXzeJ1eca_sfz~b6YG52I+{eV@vH)I|I(?`j|F{o;O7J(+8$SOK2d${nO-@dT@4BKkd8!zyb4Q$_AgP;%tq$a)B z?4AT{bq^Mb-m9<@O*U|g@!_$XU2~7LrO*54VB@X;jhqjgHNiJ!)6HeCj;2GFGReDP zq#_Sa>fQ(sF<*1Rvf~a4MRd+#6?-5<*#$ArIHaz?@lB8jG)&@&xC@B1K zC`Vj8xMJ#(P0Q>hs>+hSq*lZm#SSrnAJWxlrXRMM2|f=9P=-nzf%jp=gwlunebtN` z+>`}MTI~r=i)<~#U0r9)HJ|j|ui8mUxEuAQryajfojhSGKtvR=bG)>zztzvTb?zmU zeDwoD;7#zX@c~RR*<_qe3CYMkG!=$EeT|fjLBLjW@Oiu0LP+MSIk9q$(CEmT#$^)0 z$cA&k9m}qnm*PVdc^xDlKhZoQ)~t!IB2uIcpQx$nmPF`m0JR#>Ju_O;>MMa(xt_eR zn$KP?g)Q?nWZ*z2Ox}~bS+USVi;DfU!-x+$piojK#XD7DHP$NGqy zlyc}X0TPuUY*bw3z{_l}wUR6nOprfKZ8Cs5r#j2@;jyz z6s4f{d&ih%ga_0PruYy#2yThPNyZpv%&y1ak47)mn;UqlokQ3NEZG6|Q!cySHxMzJuog`40`Qm;1jvv?x70)M@kG9(xSc zmK>V*|LUU`t5VHXH1im-O|(zd*<)QGw_a6P$_1iem@4w(OOi6S+&9G;M2p8dG5E{6 z=UK7nwi|0{S%ti5-z0ZQ=ypEVA@97E3 z(xMOLrL1%jUCJlp(aW$=O@_V1uH}{}9wh}$8_~myBJZ7+N`h%3*{BVAgpvVo9Od}$ zcGi(-DLx7oG_wt6egi%ndU~+$OJVr)@eBKU>p4{N9=LYIIF#{9d)2RkFnGjuDq zuL03)8j)R6YFx_`xxP(zy{srD{_fSuHNNsYI6FTD_}xy$)#kt=-CK)&{?(G2FGbhrkrzW^c?hjkK7k4ycKFR7OFH@Y+BSR>wZ%B z6JG5Ri*wSIgm?9j8>8^z7o|Tv=x@^))?Yh};-Fy% zH>+dpyB$HYXHwny2uzO$w%LF3^!86BO2S#kRqDQto;Qsv6#xE6R}NB3Wo8*fQCszN z|M}|VXL+F7Hn9MifW9rU)}l3qTG55w3&)sF9EFdG&s-l%Eq{9l$@uN2}qpgS^`^`wzh&d{2q zm=FGGSFXd6t*$M*-LvGJ_lO?#U7Xhbf%@3Rt4`H`_CZ~zFrW&MHtQe}AS}#*Y1Q=e zHwJdBG;IcD)A{Pc4MNMS*_J#L<#!Hkl-^tBvvJ?1*b^{c_WSgX2?od&S0};@jwd26 zmEUcSp_bi#>n%3r`f$MX3F>XwDiq|5GNeYvPo9i2ob~XsA_$z}HKsXE+BvD-y zY+)HVSb@4YCGVLKuYB|o<8u=%0!1ekx@SxZMiGJG^qH|4WF-myuhrHgAs1oH<(E&sT^ ztB29kpQ?zbYRxXwOQQVv_=05zJeX^u<6P9@6%2!8(Ry*aBN_~_BW`SWxq+fA_SURKN(LJ7tmIx+lb9+A@ucRCUSGKPSAAUYF z6EUu&Ty(knpg~yYK4)E@llE;?p~!$;Eo@_nj=qlO^;6@r_B;v@b?J|JWnM0X@UN*P zIXgi0avP~O_ls?|4H$7~A3&l(MbJh#a2zuI)~l>U-dq^N;-2N2Vb;jnTd-_kd<_SV zS6i_5hy+?!!~s=U`B0bKgB`y&7*OVCtEt!}1+KYl(U>+BRov?|YWBvE?)?{o5iT>t zVOfV_j4%P;h$@LQ-IYwNl?^Y0;{a(*y0zdt!kW-DP9OyW5;&c`ji>`cYgKJpR!v`* z7Y|^$8L=vAo!;^r3NMVVFs{({1M{*cKcH0%}2wdUfNW`_?FkLwG%& zAH5t;7dM29L%oGKvUW+Yw;>Nm6{sx^OsITQ;sGdCX%<>k;GXe#fEbv(4+LqTTqa2- z%Tg!fXVTNpk^&386-un3&9mngn%ORUstgw0qgs+2G9gYcW+W!B4{u#EYS!Er%IwfZ zK6>k&#DbuGbp;kUn`E$-{Q`oYN;^5Bq~#^I%8n-@5z@bD!)nLN+9~r)UNag!k*#a& z<)#2)3G^ZeVy*OvW7GEe5EhKx^q`(0tDprGYa-wj)P%m}iWLN^V*7nOM#QxORY_#F zZ*~-Vt4X%eu1ET4_fkP`Y*$X#zKO1hBEtf;DG%(@h}5wX3b49b z(6|(k%Zh2S5$2qEhND^)3GFK$BxM!D#VkC9@5~p}W~^l)AwQWkxD7HG_>Ds!?l)OJ z!n8$2)305%0n#$}4VtA_68vtc5G%I3wYp@D>zFr**p%iOzQ?_{p_*9=@@RKXvLt=o zF@$FDl@31J9Qzh*#vTb5QS7IDt_lx7O}y8>cyynWmKj?9=5i`)h;UF7WYiJSX4}Ci zu|gr1lwZ=H2@^Y8lVjC#_<0;SR~KzX{)=R`w(`LOgx5+*kLBLLLImjs0kBCVJ)&XyBrj7e%qDx#I^TWLLzfEN%5`jFLBe8vt3{ zZ{GO}Dj7)Bgua$*!LbmAD!t|@%vt(DDv6Ch>5tKfw0)3BvEZng1g+|tF4VEt{<)au(7kXw!Xn4fY02EEft#>2Udr{ znmH4ASvms8@K9hjZi>MZO|bGTV}|JP;Pe88M6}8$ob}bW>(%)MFW|VVhD41YRM-eE z5Z<`p2Z$CjrGSncfKgcV)b$66ViW~JS!2T z`O3;Yyd77aOsD4)B<=#J$ua`H%ftSZfAIHj28Uk@oR{uIfI=sp8<)wlllC2bP~JDS z6q}?*+e6(1$6>MwQG&8{azOLXCEM>cJNIymb~<^FrT@A>$QoamI>v7PgS}+Ap{k36 z`gm`04jItxtaPtjTVW2CLwy~o`>3q5z46`N&ep@t-MvST_cnfDg_vK`Pw#I$-27p0 zeQj&^$@a!IDZk9ndefQ(H&+ZfZH)+IZGFpF;In5}iZ!xnOlH$NDM&@Z+iB3dpul~L z7ZNxP^n|O;`D`2khrT`d89hwF%>@_Sd2h%H%Yh=;$A20D{m-jcI?I!bebBzo4@BO$ zg+#en zc_;oGh%M$_rC&>vl4LQBY)($LY?{xJ|HZ}WY)uQPZ3oB(dr^LjeJGY!@Rw^U1v>R5+iz;y zdC+uW+b(M}n@mp_@%_pDV4B7b!$7l}s410;rAh;L;<4u6mGlb4Tpz+(<2* z3oOK5QuG_z71UKv(`v1CA27_t8w#}wvI9r!TbaRYLntUXBKG#Cqa7*7-+We-HR^vg zdcz?+vj{yG#~<6KIY`ZL5_9m{;sr4;^D1yITK>U7{~SJX-8;E(jbHJWF#ymMG|kME zRMl~wlNly&ASsi7p7vC7RC$m?Edf6rob<-2lAhqiSuWl6hC=hNaH_Ao@Z!>fABYy)aTFVOpsCjLKSK$6uPpmM8~ z|L74lbHT!cEt7dyHgRM0zu-gUQ4 zcd!WT;VH_$o^(4C8QY;DIC9PgFmBu(Ol0D2kQee^+7-%p77IKb;H>!foyU*D(SSqi zn1-VkXtfER4RQ8m&JP_%dWP4GY+5{q{^MYTJZ~splU3=;eF@5Ix_EfDB$FQ1uSEkD z4{$0hWgfqEaOLUM$xlcq#+V=}X^Th6$1HA$f_p#3&yY7U~QhF~RjPX!^L;0`>ZIus_CCU2TJVmf{z2f5f-Q*p0}ldnE25^sQW1DMhLX z49*9yl%!-A9H``GX_+`TWGF6Z4O*K}X~lXDNPsyRzjg;?P`J8^ zY7dXMVbDF=Xqol_Zu;RScH6MP9KUYptjeQxua>M~KF*8;(y}83AmWLo$TugcjgCe> zQN?G;;1{)VybzP0HO0*Eo69D36Vj$tf}~@e7oxyq0MDMlBlxz1Q`)i*gbG{W)NS+R zPelWz7=EI}kzya}E5{s2&6y_fY~uMTczH!OZBbe)e74S{VYkCOQNt|IzRq1&8M zS%7?H@MRCp{ee3k|3JS5s}J3%9M5Vwtih>)Hl|uEHeF zBgCE@Q1!0pbu>8c;vW-dtE=nZZ>;}m?}x|tH}*FEV|`<57uCLY!a2sV_!Bjw25A(P zA_2`0IlY#$ij#zX6WMBn<;9{$`uE*>2_c=a`W>jB zZKCR*4DHbbMnor?Wh-#T#%T)?6u)3RTZ`{gP>EzKREoxwXXm1cCrC=~Ny)RaWA;_y z>qub;B5^N^DQQPX^CUqek*NTiockmlj-SQFvaQCLUiMC(E1~~FtP(Hjk+Yov(a&Q1z5GTC!CJ47W;Jmng36y8SW<_B}EMX>FY1Y1lT-=&# zS#huminZ7bemyV_ZUEVEiLSGbt59Ru47h}a1U-54T2-FOa#ihwM<7L;v)2T4J)a^1 zemWiCDpiomxN9%QP)MuH!XP21P}2Ns!TVHp1X1K_1nDGgFk7)=>-tK+^EWFfvcK-dTekH5nZsh{y7B zs_9Tw_GhI^pjGeFcJOw>>MUCrNNSljt*rC_$SAv`$70F`2x;77^ipCi{T0>;q#OU) z!&N<6-PSUSAM%(qV2OTvYw(&BQ+q}ebT6vKrG#)bkeXjCH=y%WYTX)=;Hu(Sg@c(h zJLS3OsZ)TmcQ!e0c0GmJ>6>4zXuLP{O{r9AkN@?bsNl4^eteplVk5W~1OoGK2=)VW z2gk|(bR*d_Ob#mS17ybQyUC4bXJu8r@lxAUikEw5u_F*zq zI|nEK`~MvxetcSeh3iZsv>n|$9*vGq;Wvtb^~$?_i;LkS1QrH;@bz{dp7pQx`O)(E z@)&_%G8ndiDug!r-7?A8Zi6@Sj zS*tJA)z#H?>*_bmzPZHQbLCQD3+GZZj_YJ%RkUDT1_{7c;m)|X2}$o{aze8oade2HQM79=wIQFJCa) zsmx@YzD-7>f(XYIVgkOk?x!gjssFE3Q35!xtKw@TV7HInn7N z`S=HGN{=Q)U?E_OAMdsmbju_AM<**QwTGN_>vDeHl~StBibcHE(m)gBtPu7x8bZQn zp=TvbZY^hrPZ9GeS-q_t=k#-Hv3i;?&wph?Wh6)t%W7;nX1o*4^lx7cpjrr41A%a? zb;N)hvY3}wQ4o+q$J1izA>VuEDL`sp>5NKydkbw232GWw~PI zU|cp}hhnT!vAMU8h1}CRRon{Lhfx!F#yNG^;TeZ|()+u(drCvLM8=h4PT7!Plrvx} zMto?t9=(lG59x10_F~uY$SgKkC1(!OmeJ~r?SzcW4Tnw~vToRv;FPr#z=AIg5s1*B zEM2hT#)8%Ueu3ptg+2l9b<2#^HbS4GF<6ShU|vTIhSl6hVDWhJE=0x*yIB>QWE0Yn zF{={nY>;59({lEP93bv*x`*)TgojVTI+y;)I4un^M3&S3kpx1)t7+L`A;R($D--h2 zhHy9;^TIyH1y%xU9iqvDw%QaB&3bTvsDFgJ9zzM9h$m>_jpTC2apYmh0PBFwBt0Y- zOUN!*vf-4hn1FKi2!T$wFIP>xrw$bUy%POE2sOtkWf9$OqrNN1lwARBk9tEeP7&3~ z346>vi{lM_-F@eUZ00LbZ@oy>=ZMmiN|@maqO<*xDxg)k6>Z0Mr>P0;4 zsq;|B9toWxK<%MKUfgPV>tK}-QhF%>X|Am$l}mvb$gc*#5=Q@J7-s;ql97Ri9y&Gx z-8YxY(uI3jjz^MHZRBdbM3ZSy7hlwEQn1<>`8$;67*jg1Zp+SPH^>KJ4w`|Jz-de4uQV!vN!#2wZ}Cj}SXZ?_$Z~!NP9A0J_Li z0Llm341R9J8LPKfoeEeZa7@SvzkiC?qs>!12zFBtBDfJQs7{YGAW)7ocO_|JRM?}! z=cn{xfW1C6*{-79g?V9hHEcU(KrvSe6aXkMQ798*_fRhW+)0(Vr8;td`uf_=Zm8z#+^Okj{n^Gg4s5gPj#cw@zO1RUwzc*6PpyX=kJg?)-ql*Z z&hKmLgm5kooU3!&l5&>D^Kf%#?c2v2tw+y*3mufJbEmG(v!?)Ud*gqeZ*Ffq3@{ex z)z$rdUELqn9&bKe+udmGVDg@<5m2jh`xffRTpNvJ}=$8&m_5SHEjWfqf{PLEkNVT ze22sZKhmLCZ_*Z`KtwI*Ldh(6NgBmD69_sq-QpZVBQt{fu403RAys7rBoQmiba!EZ~U*IDQl+I_%8;VH942?DJ}oO{z#%xQ`R)$#BO?m zKR%XDLMy?FNde7EAVG?y+eXJqqDfsTQve#N|;3oYIw!l;&3ho z28}jC)S_Ur607sHG8^eCd0dff!%#uWRbx{MPY1=K>1ci;;^)>wGdklUB+IkJz1tG_ z1+Iji!8DyRcQK+X(PdpkOW-cEQB3aL3iW?xHn&b|Jv{Z2jZ6InUBo9rV)<8}Lp(rShE8TZ?W{00xg ztSk1HJ;#q^O#jSTR;>Oa=J`82z#?M0DDymmjld6_zo7We5CDCAf?AA~sKD_wB%#ajT1bU#;SdZsGHVzX%OsnD*Qr=)! zuM=E+$hQiD(#{SM42mW8eY0mFZKh||M4`9BX%u>ud&i9eSvdORLque>z)lb=f8eSh zczv&d^Td6&r%wFIi_p3%7VEKu4p zQXV~)mZO0S7<8EPOkZ`k(SokGrW!Nh64H-5k!5WRp*$zD1>x|FMgV%EfJa_4mI7Jav=Tb-Xf}Stt7Gh0^)UPa*mD29 z{u|(0L7&bgVn~F^ zZSC1omnr)=I~mdo&3NY{7o-A=Jv+Jf5z?M4qJQxWJ@Mv1B_(VS5jW3|9om8pQ9$nC zA%r@ZWRW3f)Z1s$U@_x=#OC7nq$?dm%*Nw<@nMLc;sB!I0#b;sppUV_ATa0|lc^ae zK*nCoh+|IhcIfS%df`t9`;oXjHziD_#p4Q?25)N&1D06i{7i-=F6%56a>KX|gQh#V z@3&KmbX2w%ys9B?#?Cbq*o`UoKK6*&Y4mX+{m8&ac4JT zHdZ+v!pcvMM19JzY4?qPvmk06q{5n`BS##o$K|Jv!54O9bP@QhP&Wj=ONSv(C_0I`<4skt0lKq*B*5-a4i|;v^Da$5Os-TlSU7}e z%C96YQ>fXf^gmP^35;hH<&G-_jCldzDrw;?Pk}CU-%_cM9f%F}A#2H7FNTyFxoTuv z7C!fbbNWLbw3xR?nkr4AGI0kqqRE)kR|C3KU}w00k57d>nK9obo3py*&FlfQ%q2rh z#Z+%Iv8~Go^hvQubCHJPsJ*&&CP~;|Wi!wgv)a8kIG4+$opAa+fiVc2J`hflnd>RT zu^yMDXo1fgdn#;2FJ4ynNxr`>M}u7QHMdpeqX*b7{E!0rfhJ1IT6KX3DXNDq-MkTbRxCy{AWG2gl6uDDjFTO? zo?=0OZKPPU5Yhz2F5_I>JAflx#}!q0Rm{P9+p(qc5IG+GVl8LW{mh&5+!I7OcL@>;kc~$K&w5@yF$x%Z3e#V^=w0 zi6-d4reJU{zzz;n}KTwVEb@%ec}7ZpN5@ zB(UVUQqgS6fO6!eV@){NMGbo~xdbd{#My>))qC;yMLq*BOI9H(F{KI!!Ew^CM1NDa ztpp2=U*DW?e!h|9&3+(zj|aGR&;PV>X;J-GvpxF~dlc3VV(;(_1T|$~3Cd%|L8T0p z9`#Q1Y>m2Cc65o*hK<4|*{OFjl&PE^tx*?{ls*2IRcSh>A8gJW{SlL2$m=SL;x&2W zj|^)w@di(LW=I#c%9c#ncj+uVA%-4P7oG*0>drzp0%h1AuL5*r1Tm}KMl78djd9>PFx_O0Q`%ZP)EEbp>5dS)M9Nd`wndE>mF5p0^jGlqSdM9(d9HgQOa?SEMFXDJ{X{t z=?Xttz03+{A)2~Xk+z+z4;>|_q70zJp(s8tvhkGxG%B24i~BatW>-^e3g%1Y>($WO zJRTe~f!0ht*HJoU9}=^8V@dAJRb4|i%2}rp26ovEy5iSe4tXhk?$I1CzUF=D)QZ*t zNGbk80MkWgIy0d>b;+lE2v&>W5wWBDB)APTOKMv^zx3N3#58f7EGoM_qzs%hlztbG55{biW zD+{@}61VV-5nnJ`MgrEu<-zc1<<i$FlwS^4VC;v-3%up)r@U@!eNEi=)!0I}Y8$SSp=;>1p25 z9u`uVJ?8EDeD;5&$DB5_*bS>Ic51EFp z?^k=PqmM@yp}-X#WpurIwR&>0I^yLWzW`)$R-02WCQ3cEY2#e0t1A9H!f~M;F;NGn zd@jtpsk#h>2`rU(3uLzIQ26HpF*6mxiD~kzFTaZ4h~-ZGLVQ1gS+o$#NIZ`UYRI8yOS;*ixVBp??pc&FN3=b z-j2FGAZ2E7y&^PA9 zMQ_w?BYmS7L9*oCiKD3f(LfSQNlvh!#)G3{~!K2U^gp z@%VI9qXZ41oncH~=lOE^ju^Zk8~faPf&mvYlXbzLoGEwxx!*Bv-7M}b$=$CFT!IR^ zWxBrReBI>17U0Zs3MT?>+`gWlB<oBD7?g-7Bi9h2SI>opXe5=Xf+kAkD!!u9n` zvjM&6nD_rQR=`#Q*mo+_8HZ>=?|2AGT$)FkDna@uaf*P1Ud$|e*D2Bz^>efa}d?9aU8nR{9B{X z{3QDe`zym;ep0Uv%QZX|TgrmY>?3;pLA^GA*&bUaB%;gGGA=f((xb;~-?fltZ1ZvJ z`P0pH+<95At$^`KNP7DXZU<^J>lian6kFeK75DEIzgxb&3}y+Q-#h9fup7Bdg##Z9 zkoOO{0oAP@qCJQn_ell>Pd#=kIs(R1!IT8=4|s3ax^=NB9hc~^jB;Y)a(l9%2)rS} z{FQ|moz|aKe(9Yyu@fS0WR#JU$}qjtH(zEiI5n3?)8AI40dAh1hghy+!qDK}@)z7O${N~BiLnEG!H6293qN{M zY-#>f)_+c@c92|7Jok|#~SwOLf^ciulKo`Od5b@)tfeVP1>3q44^Hr|~!`rvM zDgkHPIwzbT-Gt1a0Oelz-3Fi0!+Nq{5Zyj_uN3^bUS`@Xil%ae+v_?+~OfR zYkMEUf-MNh87FYT_Tc!yI*|jBBcK2bpu5x4vrLy1je*&Z_*keEZJb zKR2i}+nQQj!Zjo4Tt^;5R#zR3{yAKyL_G8Ubt)N+2~`s#1W_-V(BycZ2*N>+aB~}+ zQ_x@bmiIbe{CPq27>As4D9c4tQKo>43D=CbVtmahHEvH}e~=rP7Yp; zdU)q&kBhl+gbQW)`e@ii)>eEursoQOPujx)5`^Mgzx_sv431$>;R9sI?jOmw)5#Fg zMtPgVZimH2JtRpR^4qxEKIUJLF}#WRa@OU2br8^NR&4FkGW;h<|I78o7wzWZt>zzI zp5OiO-hcn?hoyy;9=bCe%{mQc-4*L>J`D@z496K@qA%9C|A?N3@J1mel2pYo|A-L= zzO&Hl3)9`eNhsF82h$M<9+*D`z5iuzbmK*{-TeE@FYs*@|6l&Xzz==iEVi~czH5EA zy|LBWeEP%2_HN7u4LNdm0kZKXz0FL7X7v@TZ9e)+?C*W?&EnqTUI)0}TY4{lmkRmA zf4}^oOIX{Rbqa#4L|G>XW5EePvQmLZU~iE$@b|UmpGgL!0rx$8-D|$Q5q`Z~+FM?_ zvG@X2P*`h)@8Pl33NM7DqOGTlk`y{npA5l`{MVoq3rcZ^1SuBg2Zf^W+5D8g`VoAf zikIT#00d$~B+}$cIbS~RSbk{;{}KoD!`;BVd)Ds^ve`fe!S!=4NTvJk;21ZbY<*EUXRz*+T*ul;crxu94&uQ5f|8O5IPs!KZ?Z9oN8MD}bq zOnVF7oevn?-L_aOBPYoG5d2sJzvnRd30CYdrVwx9D*g;Za)4ibB%VUTxGLbTn}+8I zD1xe$V-`}SBxQi$%kw~TBPN3Zgw7}}oZvDt91eP7PogbV!05Pp=^=g4arfJ^ zqFFp-plk64v8?u~Sc_2&OXmWU8B7z%Ea@$X5H8)ul@!MfFktA*X&4F>W4Df}Zfa20J!sa!n`lq<{m^q4>0~P1+}bmwT$6tktCt; zxiFP>RD!;Z^7`#gNxiZXP^{ol$C)b$-MJmDVx+|DOdt-TL|vPKt3qY&9)S2^n$iYu zExXH_ZY7O&dWVN7vUqqrXv37Z=zD1fP$SKYYo-}B{xxiaY=K*me8B_Xb-o%*Z38F) z(1F&YFgw^m-Izfd?)x1_nE#>4eqgKVjn5>-UuEji z{Lt1E%~jKd{PHx{(hz3RTputCk8uCuaSzHBSYohJ(Ho)`>ozZar0>YoEoPwHhoO;Y zA9+EH(x*HB>3s?LjVojvV%`J~k}A=8)Su@(M>M!R1x0p~3}B^0Ub%95l}vb*-6#{r zm-Awgx}5;z96>;KMQ)dB7FW&QG-$UBMUME0-7bh>Ud)z$E@JV8n@~F393c2H%<06e ztT^$e=Tw=39=vvvzdyEAm+Y`%BRboW&942{Y(Di7Pzu3tTlEdjs zB>?)TN-J?<>1Zp8u@=PudgS?5kP|?nP2{+Ah)&61*-)g%fY`(W3KjVb9RBf*<45Rx z3y(8VBg^nI%MAS&oK?nCRe}l2qdaLs5$B#R7RHFZbWA~F-5S>+ZZ*E(KmXuApF6ip zMnWapg(J#RH#ul}ADqyNEf-I_ z2MAzkV+`os(f_D8?!E37e_1JR76Yu0;aeQnD9#2GrihI5D;tpoz=;fk>U+pRWDQcd z6JvBtnA4~R&)2v(KSDifA7Ysf7zyjqZavGN%q#3(r6EcY9kT$M{Xx^jDF-l&V@u#* z&=pg_z%hz$>8}>-7js*%N(gPWfY#+m zsym1#S7keB=SBGUy)@?Ovo&uENl)M4o6?&5EhMDxoKVFc-3MzI$0sMaGS)re-xQr; z%H8tkwBrILsK!`wlWyI_v)jw!3hG2vbA-yVym*Nmy#4 z%FD8GiIR7DF5riooa{QbNHNi#bF>8{M)YVBu^Wnx!QMyWg`-z>=C!2z`3YT5&1!*Se5)`Sp`tIod;Qupi$9p%`MC3LaOyB4uX+Wj*XD5gQC zOy9Lyl*B;^w3N{E48n+kM|s_SLxsPPRn{^fbl17MWIkmq1-wc#+-SN(O}NYl9>3*$ z;OXvEtc7U#(5As(eG1)eSvE7%Hb}owMHoo8FzpEtM_Z_`mF=YVJeT~keH+H_C+&CZ z{$O(qU$SjG5t;b9G`|4HJd~WAqO2PT*nVsx&cF}-lwdv5;NXYK4#D92k`CV;RS3m- z*EJ#*LRbsSlaXIb*SPU}HR)ut>h~y7@>PhfyhWNp>)?wp1t2WQ52=csIi6C<@O7+a z59@Igalu{ECYQFOFi*F|*MN`>2=q)IMY6s+G|6fx&!H`c zvuc-D8|RlG_a$xM8W?eoaidj&PnKh#J5ZD}%jdKtv*+58*{*2GHYg0=N>=Xv)0a!| z-f>O%!HT@3%g2F;MT48NK^3CH@PZ)W z(=3#;=`>&;Bi}$IQ!cC#o471U%{iVSo=roS+gnOZ{935*V@d0@`)~Yaat0%!6DTlW zF%1X_X97_y{%~PlB;nS!8$=xgs|Ivxv8vR_n!p zX#XusAX`|>-{@L$2BtbK)$eJzfg=!#(XWPTDZh$3RBlnXd3*8+J9Z$<8R;(CTf;^k z0d;}w?{LW#@tcd6Le3f(M3HB zD{)CSV=&7x#R{loJPq39F`l=tcsUt_@!r@7La9wjPI+OzN7zu#s@4|=ccm@j;*|)k z1hIi{K>pzhXqE60%5D~9m<&WYFxs|1PN+7~*wJxOT)Yfn7NFuC2xiMIJt*Q1qMB}? zNgwYc)UvYf8mkwQWEn>jTR0p_}qbRc<9vXfQ(me*g_L>l5D1slIkz& zxUrH;Pfjf@!x6OXIL^iILkS-V#UK+-!OwSsM_tw)|Oj5 zR)!M$0`x@FNehuaSi&-^^8-#2yb zWGhLQOx~x&TW$G0RhAc0uzE_psC>R8xM;)vT~>)azYBoRGOE)^u3&Vw6?+4AKubRmPJylI?3`sPx$>X|- zjSF2gvA??Gy*nNb3Sn|P*mFTx&g<(aaZ+dQ~vRk z3ftg2I51ORRGadb&}6{=px%(d5VF1)oo^Jo(44hWq&kGJc|5$^ zOJk@FD*$JOujk>$qqXOccUwES(Co=tYiDa?9a=`C=0KySioEsZ%1Fj}9bPxtnj*{n z&l4B`=SzJicm+<*iBW&d`5!p59?&bapx<1{wly7uBzaL(Qs>fgkw6yiAM+-i$_;Yk z9ilW4%Vp#ONkPk3Sx-x%A>h<oyIdfQZLMSthCFy-2|^-@i1hOma3?9ckvrz_7DhKHmqV&#qJG1I4Uwh<6NG;qFiv0NPKALV zERbTz3@yOVIU0e(nwnF!ju$b6Ay_aDVY`L96pk-P@}0MgK-B|ADifdD?NS@YDM}b- zbMEXtnn{*JZ=^`Az-7KTxdsD$<$Qjzv99T+JgRB&G~7Ti)PufCDlvhv)gYwtS2X$@ zS|{DQ#hVisBuSg6>QpE8a)$}6VykF^64!|=%4t1>wJ3wAv%9CAs_I)o6Ip9Pv1H>Q zGvGoTE0T>%@#?9NMO-&y97aV-7C*e0f_7wYu)R0FHHQt%Mkd-bF<7Fr7z)F%l~$PK z26zR*oph3RE*kl$jbq)C-x^9W#0w<$*PC~KgOmUJxDDZ8Ttt_CX3HT(k|?e1V^L>B zM+%675+IM|a&eBueQ5@ZuI^I4H|TwJJSW`SkHgpL?<#fBSL6!a^kX#%wAkl1v} zV$)yIK%zCk()BZ0wcc4vW-s=i{ryagn4h)IXJ3v5Hfq6`jO_eseLg0mTL z(Cg0(Cl%EaI*lrG$(?X)xoPa#fRK>%fVN)WVFCV(I<&#e>wyUs z(*1D;v>kV;=%q)xTywQ}a|Nd1&6i2><{r<8H%D)6Y!VDb26tqI1?73C2>M)zt!n7)s|jtfxeh#M*6JXtzAD<_syS%Bxnr8 z)9`9gz!;GQC)h3EB}Z%QaY?eKfuCsdOSxeKk_Z+r^em5G1Jvp`NTw#TjCOHm%^RJ9 z{9?mxw0niiu3^@b>%)rlI=mv>a#nb4c9XZ=KsN2#r7v~?Au_a$dk2MgBPTWhgs;h% z0?*Kq`GJyAxwu*4ed2msiuId!uND&a~s2iso>nhd;*l6d2gX% zCDVGG`&r&L@1OhDJ_KbT+I*7Yk#GMp!0*6n`5T?22zq=)cCz-B2BD25&{Jn-d(kMW z3@utS8c0PwncmsvB{DF5vZ-;?>thgPsv^u)vn`t`q1C#03nhum%$?Xi+)~UI%Vp?I z7YWo}BTr^OhgIEZG@7(v&$0m}%PRprl5E$hz*CB}@JYR7T5v%g4m+!38N74`@lCpf zZ`dCf#h?`y@F#z7!0hAlEqmpnZS<&knOBzC6q?PcJ)bn7gr&ssA-Uofp{N@Mf*IYs$e>^jKMAEOL4)9 zzEVc@Y1xyF(1Cgp=b5eZX{^IKoP{e~Rr--^X%uQcTFx;K>1;GQy|BY@HQmitcRC@> z)<*5VHCy#$YX3O*Yid4A&6fo!c!R79kEn^Lc;0un^8G+b)>q@%)Ey+j@3e=Vx-yus zDE>i2dT-2{V%N&ekj}6*MvmrxV(dc(|13tW2R@;~dsXXjwvwYLm?0b59?tn;%g5Hx zgLueXDqY_4T0oB)K`(QG@yXFP+sqfN1#n*7V07n)Uen-wZx*EoeXC`)wPeQTp|Kcgnh3u;ZcFy<&}Y(wBeAKD2tRBnWE0Y!<2!hS}5 zFuZ~dcrfuZdX0mS@|LePl0W!ah)jm^Nf}C6$8Xzb@bu$oliUHJf#iK;+*WV7q1;W3 z$HXmmFQ58Okl!3fT)NFO&LrATyAw5>QR~(j*3DZa%9S1U6L)+g7(Ec8ZT6!7iX!Sf(Kmq^x) zp6E4s-Gn9Ss>Uj1tEIaOa7Js9aD@@E9{$+c;1CrUe1kD5$;IGfY$7|rv~F`(hhRN) zY0Z1O;h0pA2neXm)aF2>2&E3ccz`B1T0hmw6;T&jfki^7F~=TDFnZPE>jCAxh@xwnY5~mNQZEP1^uKla{?F_PNyISWn8Fb zTkj}GTgdYS6Cw|dvm3T9l@&kOP53lv+QQT1q>(LFVOdC-(ZS_s=*bY7tDt%c#l|Mn zZvOxU;CuBE_&Ro>gSc9u;;)wpFoJ>J!(*6p$atWq0jwDerq|ge7L6*4HQQY{a9jK% zLA4GY+(?m5?E9$@aIzk_(J|z~&=P>%MKz0eiudaTuLh;C8f(`n;Rso1>Mqx%6j7l4=dST!W2cI z4Pq3}#7Zj&^*3PfHYMLVk%qQ$AN4CnOm*KXO&<7ZPD&c%*S^7CPAek|gnPL`=L2!G zq?l^M;~to)k7}qm4NBa^3*5ECzYB=U*}%vV82llUJiNu#3N>`A6c|oZuIJ0j zoD$OJec4z7pZERRo^@09*9wj+P^!F$ts`m>+)}~-N-;pbcSqj$iffCc_$9&2-z+s*LLuP(PW5|%-C1B1;T$g#5OHnV5TpS)dyau zUEV;n&7oZbc@r$KjrcQ+egSt!k2g@dH|jT#n1@m+IYD+JJ6Y9nIgTjVhB}@p zxIS={)Fnf*NA69+zx~lV8;b}X#?swTv9<#Yh=&(J#ADV;aMD3w z>Lk}t#>si~K0&S%N!>O7;`YlD7d6lw4Tb&zi>nt=aG=};qHM!R0ZdJX(i$E2;Ai$V zZx*=jCD1?ap&O2@4)clrb)|3pjg_w@W!qi4+yqjdj0d^jK-j8MWIFH{ zstA-wGlUFY1m~ikN?DQkX9VAUe|%Ve!2*q^I3})&ix^ry2d>@akT-d&s$O#CCC2u! zyIQ>XeDpH1GPsWT7uFn@pHBxvXvI3^k}4&bB;vwurRm~UqSfme7gMyrIh+hDBLBL5 zLSmJe!ax#kIQtl8Nv#heryU^80*^KlP@7--<2*|4P`TFo;Q|>xp}kCS&*k=#3(M%R z?(kL)pDk3faCf}$puy$-t;D%f$gGJOe%rYw~H~aOSCW!(dGdWQ(zUloZgc*Wx%!ltVK4M zgm!i6fD&BQ)E&av;Y}P~DhJev5aEfC5Gb;`8U@0yKik+|-)J#Zn~~nWNx`zSY}Uih zV%B>;37jiaWj$Qu!KNBdov9&Ujm4u`=1;e!j#>buTq7zi&^n`Q?Sx($*r$@iyWI0s zSOEq?_6}SvNv8$7kS=fcG>khR1=plnhU=*N(!=;xn=JP|bsPkwTqOrrhXp%!9kgK* zXT^ZtkNYWGR6F+!AhO`pF^8?Rj@2&4X^w>R)28dRH|8L+hn5#j90+)1HWb-MC8$zZ zh0=*3J+g^mH6ykR@^ss5;*e2{a+Zrn;JV#+ZRk1>n&!y`=aC)?mmP9LtG7PcVx`z4 zAj+nr{qUU5o?&r;p0X`^{Q({URJJ1 zBVKK3hPkk{@9vib)|~SvpOr7elzdquj3(AVZmCtX;@Yp77BJ5Dax=iJbCa^Xim3rB z%Q#%k+!*@5K<0j$tK?WH5Q574QMR^-pVT88o^u9qLelr~h^3umCQ!+YaUmq`N$|ws z*JCAt#f3j+82^!8@*r}ILTu_@8k1Vi5>Rn>K&@;22Xzg=8R`Azr3Rl5dwcl*c6T)3 z&6=st+@Gxpu*Qz_f1)?M3bM<&#EXBqI|hWo!B}v47b_|;qpwS+HO0as{ENH1b|QJI z;ygR{xSFX|ZW7{;2(ovt4^uc(XKcYEs;RIG%hw!b6v}(I|2dq@U(} zSfU<$g-%!l+PC6+ zLV*0ULs*{rXZi>3j6Sa=vaqKqJwH2~p;x&PxZLaO{@|_Z;I#vz+UCMdYeo|Z!jX_= z+{GM!y8F7rVBC)>p}80mh0GgAP4#EHw!us*pfs12h=@fopS?GGfp*cem!`(oq-<17 zct6;M>x^>^!lqPQ*7cnuk=m*D4p4-K)z45?m=i^|MBQ3Ts5UM*WyU!4DwDaR9o$++CC){Q}YkH!r2jS zYbjs_&6@?1O(3f1Fg~yDk5c%Hm=I14*J|!eb~^B++vFSwkTgbl^8hlT`&~ zZ5%`4`LddpOK)qNHAH8(%p^F9_KYg>SH|FLa7mWz57SoP4#LBEP%7Pxu?{2l@5rpG ze^U=~04~rPVgh>_+g+}}0J`Wa>t6gf%4eJR`MzW&j{(>~fmsniR2Uj6_YUaY*jG#2 zU~qbA?8QHM$0%!9n0`i0BF9c97hHP(z}79Z5i~3^C1jh03-sN%+wagtBT2k1AOfx) z9LweP!;-u}jPN>ljEeQqeZ;&{cRIV;W@&=6h2V*yrZ`(S&IO7wIK3s)VF#Lp6D2*N z`r^?-WoyCb$6p4HI4)chp=Q27StCT9WUvz}3kG6UMOKc<+v^sA#;tbsDrbFu(g9o) zXdrtv<^3f{JUFfA!WRmrGhq!LFvnWnvoK?;1C%Yt7vP&}r0;B_d>3i+{t)b5GMJaW3VA z_d3Y*3_Zk-jJ^5yRWsqq?ruzWkgJBh{mHoNDUHOnTAa^Q|H7Afr9{wMOoKEHr$BQk zvH^cH{_T$*o8Y&Aq;zf;-#7&R|3)LjpVu(hWL-WCn=xH_>n7HVr-H{M+54D5e3{a z#Mt?9D(V6A4xqm{a!`E3S~P?Vy2*F&r1MaZ93ouXG6Z1;6TnoaLE=P4GfKE0MHQ%X zNHa4M45>)Nq$3Cy^OzHkp0vd2v~!=Z4Muai?MF zJ7QCkHtrbdf9qm>efz2l0>I4^OdKlGs$rf?KriGIhcB18%8E)K)yko1BUU7hGQtkT zT%pRLvJ&*%V$X7W@3a1~8SFwg=6hpFtLy@TvfI!Vev!aqL3uH09cWTEi!VH%ZZ<^0 zUVyURvgjaf4gf0hGj-(5*WmC_VFT_-9M_UQ^KH&XlzWKXynzy3QdKWbakGXrlXT*L z2v?E8@R~H*o03-$A&iN|6VbfyhN2p<>s?Aa*=W`ZeOG}{WVo#A=*k$mI~5}tul56U zfi86tpGaA5_YJjD0c(a?vxUU?GCu=WEpp_SS7epes11Z=@ROTj+^Q=1v&juI)ibxV z$du!dod6xs21=G?A}u&RgY!>^#bLLN7j*IuqtXMLyaP1`EC;$3~8 zR>D09073!*PPjXoozPWxf2p1+sm{9lRCSW03(HBlQ5p6slo1$AI%XFszT7g4_iP8P z{Z*3l37N_eQL>OxmqgvTrMmgp;mKi99Wah;GLSU}i3;J|nbv7otZ{d>a-S=7HF&N9 zNhN(69gw5+x*gDvoGOtcNjVnE0}Sd1M-zV4S~Enctzi$bkFqp_3sMtIOgFZ*-BpVGMQlD4o0uCqyTstRnni<{KvaoGF&+ zXVe^=y06A=#p6Ox>BHUBTJOY7LafS)MJd(@T#AuDm7ZH?!O1Pq)fAi)lB#N9!Xi~c zMW)1`AQMsINDJZ2aH`)EErGi`B9TVKxunfyvE;0DIqRa-P>Hn8!e|s^j)5f3kG1)U zM&Z9=y}G?r+m8(4b*A5dOST#q4Sx}(*IeuQRIq>(sGQf!0B$^L_n zl)Lz3cqOBu=T;X?DnkUPO=_ga6GncJEVn&0Yj;o%BkZJDSU6};j$Vb^%TR?To3u~` zr4TZu6oK)RP)haf6Edg^Xh=gTr_m5w;T*du#yBrcKUHMGcKO+diuyXmn!d;hjZgix z7{*8Aux!L9)b$g=UNP~~uqUkYuTMweapD(c9W;(hJZp*4tJ2F7Hd{`?6%vtcipH=` zr!N)>qAf2LEI@VrV8%t>j01rM67%Tnh^vf;#BZelTyjN~7mJ4XGW0}YtXM1;lDq#9uMqRRU0(&XL6|Z-=rIXbPye z$gJ1Kof+5`WHOR<=?09}<6y30AooW~Mkad0o=H^rVXu4Kv4c;pA_tVTnEnzzm(GIZ z%Dr7RZP~sy(o6;wSdW)MoEgCZl{KUR{oo7v28jcA6muE$ZW|@Jhmht^%smL{6j?U* zUnzD!PHL@a&&j4GG1B^T@2@7iR=ek7Fe>hAt`%SdAB$U%Js%po=>Go2Sx#9(f_`N( zdScz32Y0r%+)#=}OWd0?#-^gM+^EmIQq?`t?z;1Z@K=F<4Bm=0S);IgJ1}fZ zkj#F2$QT*M%%san8+9V$b+kf@TXSYtdh-6r=7!k?xm z9{C<2Nzoa|SXM+a#MjCFrarhi_PI$lE5UjmK?{E!x%*lTf*=tIpLG2*SB7W=F3K5A zmgv$fI-AUE>ZsZKj8q!O^6w#VF3ymOL-TolRL)rnS{Na{Pz@{29hUo`5({VlJNdKi+ARCxr4A%&ttD5o%_ zot_PQP+MiGF#%K`M|669@C%4Nki~8mIMNTlck!mjtbeHYcyoQ@>COgwmyRW@hVfh- zWFFJ7NuR3>z>NkI<_S4KL$w>ZW+W zM9?N)cx#x3t{{08Zs@@97uMoNX8Mwlve%>DK#3~-9tmGoC=W; zN(C_%0-`m$FoJ^+w?H2PcgQHkA;(kl?c62< zvCc|kvzBv$vd10dy-_Qobera|94~w1f5EKgy}Wn3-01 z@iLv^VHWIF31GR8eBMP7PZkb==f_Jveoj`PB>_;Jwko#^hQGqwzG!0LGRmbRdC1vP z;nko;K~>Ts^s#TwUPO%AAndJ;hG>zMJ+PjRMqSLT6efjl<6T^liHB~-U~%)yR!p6h z5{jBW4~UQ~5lW8qxV6?v`!tR3P!=YL0#>a(K!-!<9%>H9Pzk$gN|xFiOBhxw#*^|Q zj@?FOf2OB*tR_7)Vv{M2oO@sc9gl}jC)YtX{&8E=>XWn@|G1?;{=pxg-}y>^eGam6 zo47O?Gxbk8j)3Y*k7LCkzb)giAGc&2HVO=9$~Xdw0w1V8ACBpMWSit-4P6;wI38Jx zyrk2dzhpZ|4V9H9+4_zdME$DL*%ML-0We!!h(?C?$5Uf0P>{gAIFLchjIZgUsOls~ z-vUK%@8Kq+Qq-{{zH8o3hDC0cJctBtLoI8~hJG7q?VQJ>SsUqoQ8)iXVbYE3Aj)OA zFiLh*E-{;(N*;w27i8g|0NhqApxf^;PJjaftr01ZhZQc zl40gjGs%-~r`M)=y^KvQ@GCZH4+_?n8on?iHa)t3MeA&6m8B1Zp~qJRotDb@g! z|FanY>ycv!@$3 zi#^{xh4Jp2-e5v&MpYWD5wwDXSCRv{QwngA6xdPg4>z`UzhCuo9^vC>!QG99c)MNL z4^P_fdMA?;m@{EPrJD=}#8)D6!cf z^$S2TD&?KIC+%a}py6iZXs*`v`tJ7Q*82Br+tU$%&2l`%am9mIxNid~Kat6nH>bez zJ;2F}eK^>Wb73&ln9@R(jw>SL`R=3NPY33SA2-T2e;SH8l~aw0y~(ptfOa6wU(u=1i&%cI&3N#AU}5$ke!HrKZC$;v@#hxg^X1 z3ryk;D)>0y)v$Rm_j%c9Jv(T)Abm!-oHmrf;9|8u1_(qfeiUvTK0bb?;E(8at_F*x z?wB%LURu98B@Mf8d;J*!teG$@Dm$$3F;k|o{#PRCDta? zDdH6*C6)6L0}>}=G#iSQf@hkhaKj|HJ9s)w1J$b(@{4-c5p7S zSQ3s{c8nYENg0}BI1h{?2sfRMkV?o6<_tj$Wkh<25|<{ljNgZuL}MKHc219X_&bSk zloDV`lM#XmJXRDsw1BKw2-!nyt(EJIHcn2*Snj2G6FbI@&Rp5k!D-wT0kSv~?FW}* zDPt`)#-f6ymcpe&r2cFb(s{Fmz*_wHKpLBCxY8XFV4FoWjcY}NXDr0%spMjcvV=fD znv~2|Y(E=>b4goyT!|S1snd5k&e#|~9$_*GX`OVWEFFvu>8}V2ZtGFJX%l5`VewHq z8Shm9kQ3lWoA$>C1I$3TB~CALPku^zYK*-tu1Oi=}TC|NMUO#TU(&@@{GM8#Zz0!_v~i3d~G0 z5fQW59iA0(r8M2_?E=Kz-G#HvpO4SyFAdt!@V2~+;dak8_C93sN+mKdf^qL4TsEY4 zTa&|D2m+{?!F83h4#U?G0x}B^Gu@>doWnjL#q)H zEOda8wSGsC0)AxeAZjqIriGK&7KOqk?9 zTVR}P`YvjPj=p@!Y_zMApVpQ5>LtRl8(-YIwR-DT+$v#xBtgt*7h{JogxhMv01zdz zi@NV}=Spy{oHX-n4h^RKElF z5d;hrNwCGh5yJ)Y93Y0rH%s&^HlFXUOYD`>7`T+GQOKXEf@g+<|_IxcFFMOkTwC9^4a@A#Fb0-PnG*_PDjR{p^R$he-algQR6o)>_ZE zH%Y=kAMRvmAFr;gV9R;agX5$*!ZD7MwqrSXY{xAYCcGrdL&r|?m+l6s?47ol1iT7a zOmjYYx)JM*_38&%B*0)Kq@)n3DRmT>yh=Foff~|Dyu+BZ5RVj%r=8hdMKN6QMie*U zJJS~IXWW23a`h|rXInOLZ+=LMqm(s!PagKVxKc?Wa_do*op{7=a}xa$bV>QsDQSUONnLbyZYz z6kNdmirS`fOT+UoGM@Xftc7X#rz!Svu5X=KqcwM zvbrkub_dGox4Y0GM!h#k5Uw58f`Wof4qmnf(L(9i%~7{oyc&;BM_}nkC_UNd0il(@B6z?WZVrY= zEA*2#cZAb7ce|r;b7uk(cm)O!T!3#?wvJAb%)>#N&$fBU-}lTLm& z3{>Xl(sz(ycseadHfO}}hjVZ+7h+c;`~W|Kd6_V~e6%at;PujVr9^>m3o8tw3Z`;tG@60IzETsaP4fAtDmPSUnuC^bO4f)ZL#FsM>LzH%J|g4>OO>PhYflOyhTg z3z;Ltxm22QQxuUn@Y!ukXou2(ug}vc;gWM!rqy38FC=QG^Tj#7{kN=zGzW z8a;h!Fa;5v^@Ca;z8ObUnjgJD&&&vC)cNr{B*X-rBkqt@JK{BAdM(&@{Y=SLs*Kve zD&gLsPWImjVG;SIyMH{)j~|>(C62i<|Mp=%JUOvCg*aHnG;huhHW_PB&XQ735q^HE z-NQZm=g`#^Sxy$@3_#t={kj$tnP$|aPBbAT7=D2pSc4(^W+(<4qC!aN*H zxUG+882wP7R*=Wz^v|dPm2BWo=-Q?;ALME_!B31h8P!&FMlU-lp*3(Ws(Si?RA2@B z9QXn66pW;$fKW_?5-BNP2`{2sp1C2qqYeUdiq?M#($Ql5**TLG-2Ubv5O!4JUH&y# z0}pnUCQq>DONC(s3U#Z{7XoLKwmwATVl!cj0#`Ii##a*X$}5&I0klvo=g3!p?}b1Y zAHodKRi!$5H5|OvgZ39hJJgdeJ7{nPtrnkC62|g_P^GDN;F74JY!}B=QxMWucTQMjs0=R6e-tHpJe&0h2=3L~!-eedpHE$}+xPYZIz>O!|rn>KtsKKDg zATABXzc-mehctC4(KaHwr4){^Tnjo#LKO%_KGF;oqse~ID|oGy$dL}u9=OyJk9O>h zFEBgw*;;YJNQ1qLW&*ZPCz8XVfa<-QVF~1=t^%#nc(kqnxmzIu{Ea9phKsl1 zHm_%jB(|$MGY4!_dzdpdq2eg13+P$f2elwx+P{kpsWi}7=r3;mLG&)L(}i`TH^3sg z0f~gS5MY8k-4RlbbeQ1Hw*#uy8<2Z_*jjoZ)g%ybXDpW$f7c%3mhs~2x7~eMYfeti z^4uM5gAXZvVL2(Lf-Cm7+#(tRg&ZBpp%qC!OzDo-bLCSPa)Q_!mtw=4d|^d~HEGO~ zM&)H)WrlN|KN!IdAtra7Ynr~JiBU^+6yHeDK%aJ`yi3_mAVOHtUn&u@6lwtqvo8 zh~>^#Vd3`Q4mxK>xYL{sRie-}XGwQzZv*DO;}!!$%2q6BG3)I<_p33CX=12_RN6(7 zT_hv&^(e8z`#IuzC@zvXt($YRy0vM)wYNj@D5Ff$=V zfI~mMC4MOK6ha!3Xd#9ZyxpFnsUJ1A z6k-I+6%-W7$$R-VWljzF`?Y65)?vhnMmDH|YkDaD)iB zi2So;K@PG)))=RbGM%7Z`*5DOJd|z9Af;m1qoP=d`IW_QR`-T`{Uro_EH2+b*vH8T zDINWw@m1mo%7}`FM$3Yf@_`QJRetGV+Gu?cP${FAO;VF`0y5;b$<>+CO9(98%ry_8vNxepe!K(i{M&_5_71G z*B)udNGp#ER78dMQM&G5#f?7XznYu?SC=lR6tt-AAE?*}lit;Z3>tsF^AhOjEF>3<-asS1r-=TrB>EKL#>0nC%K?1$uLd1FKOP*kc?k&o&VD1{NM*NRz|Y%1o80 zxL8B53mgdlte*>%4mN`#>Vc9BmGee&^98j#7yw5DBGW~qAXD*S`!&K^P6f{n9|>+N z_wJODMT_IA5}}CdAQq8qMumui+is10uTK>$=(qg9+-iM&3Rx*j{a2EdQt)!^Dfq%1 z{PfW4_k0}-_fSdQHdGPmTLnT69%chnfCx+qP2c99fp8`F0cWujs zWNi6n*5r~$X$#)#8&X{UaX~@tgOjdAG+8$*2=YOQ$Mr_Rs|gzC1@e>^AL#Czr7}Dj zU@IfkuCBb~q)CNa`=s#VM-WA)T?isIH|UIN;?2f9}67wm)9$+)Ho>ku~fxl$PR$*ku2OQ_(+9{3?NEd(W{5jWGisVxbBST(XLtSWSAn!jZV7b*-Hm zT-Cn#R8*m9{NI?;%fd>SRv}A`;q(tn{;a5wC*81SAkr&+38&i8*a|G2D=iq^<)aQ` zk8||c!%<#BTR5W#YFBR>79d0O5OR-OANru46R7y`B)M(Zs3hNgCys-L&D)5pLL|s& z8M{2K>S!X@DIoVb(`)1XUltc%{AG3Jo9i#XSX#v~#+4QP=Fb~T`1Rs1@@;XCU+vj- z+P9a!dC%;~Xx)p!CWDaKW9xMT#D*`hx>GWI&F$?g*nsUIx*EoFDLQS#8c{s44f`}i z7U)8N6cN&FzIR@h1Hc-3BS&w1Ci0?{{IaSf1MZ~7xXrI#CY@6pv`^53II!PcVqh;C zf17lNXAKDoR&(|5q9cxJ!+*F`!-p0b8n^w2q-_tskyM26I&tY+p2v4I?KKH^Ym@{s ziBV-18aF91P>RA+qV$>AXkRY-)B7u8>dQ%=1WOGd^!mb4ke>L23C-h0rWZ#gDsG%$y4(wdb{WK@qh&u{4w;yDkVgU=`Ot=65PvYCU`yu#x_!tUlW`XhN-vIeNj9(aD8Bz5vGLYo#*R3erO??=4Hv!1Bt{jinnRO~rjjVwD@sLVt4d7!irb z&rgX`J9468!>yM~#mZfTN8b)W3tx=t+()l+S0c_-n~&JT3I+u z&KR<#%SKCUUcfKmcyaNYudnSbFA0W8=7L{oAdqU!{H&}<1wpda@GHt~nS5S{;mpy1 z-L(c27v2TpFL^{8rGfh?lRP99(nAh(SvD|Qjm-c5ex@$4!^~UZH!*ihhpO%6jQu5B zK&Z(Rp{2~~Q_6D#t-RZ!R0pgtj(UES2AEt_To|W$O1zn%s?v7J9!Hk|Wvkhm@b+}z zS8P=`e1Q8%?QHeNkli!Hh7@bB>5usOum{Ul|G{u_g5Px0#4)@vEU_`97S6IoL@tz6 zweLy$l-Gwcx)_oDeK0bnwRD`!`8a$)a8!mhok_tjD|n_!S?a@w3!g#GXr8(#&6UBc zWm_pYKRxTCZ)y*!FW!1__sf?{?qE2q9pYrNYd=wqSCHD<_^f+V&$%z$UglXd)g|5j z5g8H%74-VOkMZis#JE%m50l7x3oNMHPzvX53!2~S85)04nKfHTeE;#FZRs_#-V)E! zI!=i*PF33TvAa=k-%XIp9zG%_xZvHZlDyuGq&&7DegbB)hv0!TH#G-pDzT8JZt=h; zLba2P>@U?oE9lGHMnM+;{>{K2ol4|j9~}jM*I{pX;yI8gmVSj|uSW+J{NFptfGQU8 zHRRYTU4C{D!=sP@t8QdDOCnEONgM-x|JX&2oZ>Ccy7W5z##qkXLi_0T-!NllP(BP1 zI_R*$MuL^}+INRfqi&IOL>#!Dp;S2NuzlmIAP8WxV1@D#P+u)f*Y=(SC?SUF&RvaB z;+m{jktNZ8W##*|_5c1ODULU-A44S_7W>1&YaB$d@yL-G<0lD9O6ee#PEaPuyq2iD zZZq=YZ$nS%2$_G*h(quiL>xiJnTA5=1}h7MbT6pA*war&%$tXZ)kXp{_`kd#2FcgD zV~UXO6jZiRdFQ{RsBz0e34|xM5tXKV!eWw27P!jAY3)?6BKS4pN_KqU+@m@ne3h5t zMN^_D=NrtLWvYv8u*hp!Np?D1XWEH7)8ggHFhv`96{}4>wwcdR*%`%|_kocrbYF0;$w^14Tv> zq?|>KkpF^r;RK5{f(P1PV?1bx-q6rD4OboeWNFfsy;>7;#M;D%*so%%%x&1Y83XvW zMVAX889hHR!$z%8mY27AH1J}O+K0>%^0s{p;f4CrTf?=R1_%X6Q81Nkhw4JIq!NqK z;APlN;z|G03N@HD9?z}AX1D#lRRJAJ zDdjEdGX50RM5`StSPo9ZqO33H=wx2c{p@sXyJxDMWv_9fcYz6aiC-!fpF znnVPxtVm5!5b0JNOvc4^#|i^b?co+?Qmihab>VDsG>!29gd`$Il{_RbgjJ3gL5c1x zg+x`+bothdH255>i3pTv$|2uVsy@?bnUX>bgb?m9Njc|9dRKYMPbiWS@o-j(hN$m| zKXJyic2EwJ>K^j|_&F4AiX5^Bn@B`3y+>FFcs_;>)y3mGhG**nwtCN=K*+|E_4@k$rZODCxkH9(4BbMhn%} z1lpKx8mL%jDe03IT1pEz?rI>RqlCb@o}vpI5%i&lpD<9V4QLU$9ABg)}jDL7zTx!rM8Gn>~V{#(0;@{B(J9M#x2kHSsmmZ?G-UVN=>b0!F!U=yqZ{3=kS^)?$2MnNXu5mWxwZF^3|Qb!qts zwK0P@F1#p5pWxqOqLJ`21V)x7+U;ThFUVLC6-nsE`adIF4HIePGQ$W)8BpU+dbz9tpO0u)MMm&rT4)zrt%sZ2trksOE6dCJADn!C5WX|FNIW0-w+&wj zp%qx!g7GxR;mRCNcyx!712p16UWX_LLtJ84ljSB8%WpGmZ4y}E>;zZa-$FNGC#=?? zrf+utwkMh{O%Zu0P!&mN8DYC6Qw~Ie_KBTj6N(U?BHv;+SePy+8&y$*v2gq2)#nPg znln>a(K;G%<`b|2@CiqACh`0`6G0Zywm$pKR&mkry%Zr9BHb)30c8(+NB(iCg4$>- z2XP?NwTNROkB7T}D?3iQJwW=#G4mMzzyI4uY``%xJ9cr++QF;AgQLOV2!6kI@7M*0 z`76`E9Zujh*@6uX?&|F>d?;V<^U?C@@({n$gsD8jDP zdV}08yR9{@wf6XNTHJoI)+76<_!8H8_-y_8lZ~gltsmANZ$4bx-F)^`>P3B7_;y^& zMwr#X(X;^J9WyaS;+r86k^_xyYLLe5ZSA6c#OwoVi&NZ0MrnkR^qubuFfdU8z3FTM zd>*%yIti=zc7T9tK4)qh;~O+?^O0*7(F?qd2-*Gce1JSW;B49qqx0Ho&otXOvhN&w zd-yIIdBeCSi83m91rHz#$$JnP9reRlh`|V?3i+rygvd4Q_#M(A(s^N#85%Uv9vuahqLry)?; zCw{{wd+_=RT?o}WBxJ}FCfgZJfO1zGDN?;Yb5v!<>W4m|84+c|O%uWdQ0v06;i z3Cy@mu9v%kC|W&Gd97OI{AV1_pgY7do}6u7Z9vF9>}8_WRot_={@<-9&mL~H)}L)` zuWv{e-yKXi$&YI8`8h6GYax;qlY(q;oe!8m|>(`6#9zXkb z?QyZSw!QXb1J{4ypHR+* z#6@FW(Sa7MQZrQ@iBdV%6E4fepCCeZpo)w&P8chW8YI~`u9qlAxX1CPh?$5aW@Q{^ zp{(m#M)COslz9=}(W^+mYz7<~w?IN1MHEP!Dhc3g-Z2(B98g>#kjd~#rBdxi@#Jjh ze;zZke2h|%`fuQWJ6#NXT;Mi2d*J5|Q;2cnbmd|1ot9nuc4upC_j_ya!Evwu+FxzS zV3>Eykm@_AF&ZuNe#nhZk3F@L(Ye~r<`&P)3Qjw%6gP56`DA5K+Ro08&$b`BW>~J=%&Wm@Tm``Q&vtfQO_qsk`Z-&F#Xtinf=YtmTT0f9 zo_3g$c^xh1(5-*Jw!O3AyFjc3TZ(%j?n6(YHe4JlXEK(HheG|R)5ne2LfVk*(K`>d zj>}y=d;EB9*U!j-HWhV6awA8C>Sm`>isvH475@!7mF2P1hT`g01ct30BXKLo-sv5R z&3#;`><5K*2zE5O#)i3C8Po3^KwPM(rk7*jdvTspcKfuK(KRlp$C_zk&8*yBzP$o9 zb&SJ2jw_P%vB+Ezd>y{Q;b!pp(6`4Fdxpx2OMeTAw+#yt@034^ zi~uQB7&N8DxCWZ&zJqhF3Aq6c09jZ@ZDx_i>VZKB_m&jM2FHEtTJb$1c+ZM`(jk5e zACq0k`)lZ1<5DHt2>9;whB!0^tB2H}jib2cl2l_uvTYRL6-#rU`Gw;i-vs-TEoiZ5 zwH|Fg-hkU~NgQ`!$JycOFr;A)eZpp?j1epQc!KN3MQl+vKkWW(0+3o<8-;bl2C*+Y zVSpkK5PV&Eiby<^ParvggC3rd?Qo3P<@t3q#u;OI8#pbI2Ax}&^X9{i5!%v6CS!ps z&f!^rcwO6qtc)AHpbF!q9N@)iK^nd?o=akZbl&ga%;)PBg`-I`ht!4OK&1sF!$9}B zxfeHH&e;xzXOr<^^Y?Q&tkoJEwjj08gz}p*X0ltru7RUr@ zIR%(kkl{vhfAY+<{C)px5@ke}r5pc=9EHILCouB+niX4{qL&v%~mvc5?jT zr7vsMrD^|A8@R&;ZY+=AjcA_k4ziaDlCQGGYkX1%OUl{qOqB!ViNSN+sAD|#i%vUzC%iAC^rdIurNoep5# zqu~k?N+Ey#8!BP1=H|foUK9)0i{|mTxLdrGv%USf&${qC74s8bIJ8b?>z4Hl(IXxr6@8d9?oyG5NRW4tsNRCi>r7 zxXrH=;qNWn;a7^{_ZIH*E9L5Y3+G=pW!n(RdhW-q)(^1Lz?6YEUo}a$5V+@d{(Ez) zg(~ataP4m3)o+`U6CK+KYV2<8?Cvnk0x#m9&6V-V>B?KD88z9~sEG^MKCssMGYCt* zlKYj_SwRmx{m9ULPho=I{{z;9;|jcU>Hl~Xb6)u2)1o;l<`-_y7x(e!&b%7CaJ-sx zW0l{6K+2W*v}j^7o6n@Cv?5au%mN;^fawjWD(?NGcyX)whnHXME$d$-MA9!y-xM$X z{CnK&u6=iJe%wA9twgQN&na+O(~t%Fy`xv-V`O@K|32*&@4&PBuN(E9@HJZ=b>}|Q zZAQd$h#xo#3=R(_KA_5g)A+bF5(0^CMXrz&i4ZSWP_Od>4(njO&p=O~RS`wjpR8yqx6ST5kRN><$H%ZO$bwKni)Kei!!0AfB0l>}P2hi=V{dbx zoxBDYESjfDX*{nW>dR7IXggc?M!y(%LNX)BJDxd+*~AJq_a!rDc3;mPX@KwDE}DOTcXF6v$+gy8&u}AzSt5;L`|a`(PD@Vq<&uSy_VD%K zRk!z7bg_aB@#Jjux8oiJW?YLiT)9zq7g*`(N zy{1|z?V95Yev6KXthz2nShqREZv|>6OK#nk1qSe_k zkTo3XHP~ljEXu@a~jh@=PK$vur8_#lq_9JodcLxEU@O^%Zzkr;v|^2P=)$M%*5L&(Ao9td|v-R4}O1@fpXfhH45U zD+>@gX~ACkn1-EQ+qXz*_@i2MW^Ugih3c!e_})w3?-$NZD*y0)#sQNvP$D&^*4d9m zf`#)`Z2th|e4aW!1Q@^5n1lS5=Q7a$V3{>Q#L_{=s8?bgyvC~cK}4fD<7V*h?(W=M z^x&_o?5(a8A3#sa&8#ubBs2smjnt(dAd>j^JI~;uMgZFuA`*O=+fkW~|HT!z_vYtS zRJn$A3dxN0K`n+Y7cUDxC|SpjJ~J}e+HQ$WjS)*pBs z6{CAePt7J#BF~bR@f`O!4Pe#3H$FHOL67Q21Z+|~0yye!ge#Z3<;JU8s~URLQYGLS zfFK~Zy@)0mOq~!Fxx=rjwmHmw26NXKl12LzsuGHhR{R5Q^}q*1NhYV?9S`=~$D@1mqLAV- z&<|@IDv{Fpvkzh1f?jq9KGL*Q0%3G;R*a?<`LR7@1YvcV`*WXtEr4=g9^qH?lfORu z+S?z@x2OYa&Lh(85U$31^D?me%eGB^jkJ7bPL;TQV)+U=?M8vBK}zTblT zXbj=Sa4EJ?Se$9M_QC%!&xorZb|N_q0GkwT(sK*2%>ePVn}BsdD~5#w)|_~k67vyg zoOa&0IE_J{#Sb72WdgOdO=|$Gui#;De||@+dK;He!@*9|vUE=C7p$@n^1$1iJ!*L_ zvFyej(Q4!c3s-(b%+ic5F{N;Q%8iH6W@%Rt`>tXDQJoa6*fTCc6fC$Vik4oJczo7k zrIuDu;n9Ez=Ig3$Qw>@k*J`pdxIWC423s^vCfdhHI+RRojY=TQI*z*?A&;w!NUQvo z7ZovYz2TtGfKZRQWV#Zhd15i(mLKl47%kX^2^CI_(K41PW$WYKvhZ(OcIW!=g11fv z9h|5dt<2q62J67Tsz2Zhbul?3Fi!z_ezlm-5HU~lThPIad9i}(Q{FPdD&N7FF{Xtc z76W}lui9XkG^dX~e9!_A%pP`6ArB#GBRq#FsYc5ABeung|G2gMfj8UV;+cv+gg z+rO7S@%pRfTcy{qlypwI&GDc~y@c|hv<1U03S%S;s^SquKT0)1^H}2CI+T)OZ+}9k z!D_K6PGiIf(NG{k#m7j-NiVMh9*fj~ZAwQ(-HUnBqh0TVBz*@>>Vq9xANUb5mpL>?e>n3lAkhTa1v_Hg9usj{ zfJ@N7=KT?HzS0kAMlmDu4q(BNrkRm<%6qwiX4WM?z&$`(xL5IR=sEwII}PAwjiJLd zCuF+;RxbmnTyMI;(Z2(Q`fj~tG>VSn$o5%KE4Gb%pzodldgLWS%K!zQk`9;o{?ov$ z`<0mFnhHg-lgEjV$RnR7ET%yAXLDpQGD9j>_QYm>zLa!n2z|gdM_wZ|YR^&LwuKgw zbj=R}WVjj$mP~e~%_iT|4JMXpHvS%)z^&W_;=j7sL)Wh)3P}7TKoBX}&+DV%e&r~U z%yz$uq0BKby0~7n7``P)FNr%bggG1#L>(}5Fi~G>LmC%)$TyS16-e#Q#xW;kAC6gV z*DW~6u)e9;<$_A9XyLj?oG#DJCq;>3I&9|@Z>e2kxT zrfePXSGWK*wlR1Qei2Q~DTqOE#wM_)DA%m*F#)8Ajlga)n1I<0K{Eu6xU+oI=rGwu zLE&wnNkabSUE>bKNAuFKJHvnngn%dw?WJQOFzeM_1Brl93<*9lYZ!eXVbM{MD-?Gd zV^k`|g?jGEX^|-tNt-09jdL3yQUm>%Ismo{CaxoLMYb%gjxZih4V%$>qW^lH92FFO z0Q37RZ_Esl#PIzpw(?iI0+lyf0}WU*3H2d^vh4(znWIwLrmexlsooWsU;*nbU};NG zS`*G<^m&0QS2%uUA`6x-tlaN-Pt0)taR9Fe#BezN_T#VgJp)l;GG4QdiWB<{$O7ES z>oLx+2$xYtaT#_0!67^Fo;~45OSQcT$#9&^+<(9Y$OwR%t@r#?7zl{3uwOqoY6KJ< zn)`Evf3;SBbFi<(C+1UZ5W)(lE&AvO#M-QS;CBWPzu083Xq{mQ_MBkplGkDIyGA)Z z6eh!=f(bG|fAl=PU(Aeuj286&p79T3*#C>2#xSI3HD~x1z9chNxdfN2=WqeM$$7>) zKtlQS;{1TE8Yt@QT5DpUGl~SiO4OM?C47S^*q4X{vJEBKdZvIb_%n4-q#3?APmVZx zFqzixL1g&ckb>T}UM%-l04@B1M&L`P&R1*p>EunHcaVq!2N#xi&*+&P=u#5*?a?mG!wVm}Xi(pFIOrbMDX_ z9Ee>cHWB_A2-#t&XmH)yTR4aTo$!ecA$6eg!lpMl@)gLd_7G~E)lo2*Y!MBh$7u_` zpFBPdww9|_MB_L#!S#nR1e9gkqy)IVjC0)qlK6$9zCg6W78BP(WSgAb;Qj-wKx{Tk z@(xRliO4vTzKso;^?Ll~p)UZ+u6GplpgZra$;8qpT0zya2o{LhGUlwZ7Dj%s$qit) zR?>rslo<|xdO)zl%_=!ViqU`ykmR`yLkiG2x+WXw1|Fbd*Kp^y8*euJxE{SL|or-SdXm?10_tV=HEk;fsEUJ2@dvIxR2?}fOC{&C4nS9-?- zKxO6Vw|3ZPP|5YYzk$u8_wW}cjxmN3-G~i9=j9_1*a4o|9To!1HvgBOrb1Rj$PHfq z@+9fQ4do(1Uk+}LYrzc?lo-(yVC=EKH{V#|HeByOO%ZC_gYI$iH0y0#0OS$asWmK; zTqtz$ff%by>@xj(5Yr_5yk~3%VH8ri!{3m_UCil9FcsKz3;z~V&f^G}Y44x{w|Zfp zupoA@Dddoc^W+Qz-2k|6cE-ys7xRGhQY5{!K~S*qlkNxUN6<@%$-^~xFKYiCY%mA| z8m=L{#CTCA06Roy{`Na)V<8=X_Z_yzq}devfT&i)C^!t<54y1=-2xw>OHk}fZ6r%+ z>L@c$KGHk9RS#(@?f8dGsfCNThA>ZBN?zRd+$r6A=zG@Ce|;p~Ck+%uYbbuCZ>Xnl zp!$@B?~6%-Sf@|)$_0J+cE$vD_7I+LKpv)%_#3RV#B+EPK$8nPL~(+6s4cQc4Fua9(CChJ|utZ zD6}>M-oz!soLCr66>1wOOZY3gGF;tsrLm?L^v}{)U23l3^I`z!^;RDdN)Hc1RBmBj zh+O9izeDcfhx36`1yC;dQ`=1@8N*W zd@}7zhmQ7pG6K9KbLoG7;o^w|$P+!uNPX%n2PB4<#_s$2*W`)H=eHb{0~y_qporiAl0` zc`+me+STzR0w&H4>|e7j9)j(?c>S&mXrQO-M+Bvqztd6C7Kt^2UE7#n*?XkNA1N^P zvPTh6%==)C&_B3~2@1GqIgNcZ=@gMWrX22|*umoD|xgkOz2-*Vg9^Zjp`nyrfiUXx$<`n}^@@hf6i zU<5UoeHtY?uml(&zxj62V|8N@LCS2ZAFaRfDK%n_<=fLlWtKaL5ng$KK+qZ zp9D`*0dPSp?9j|fkj@H56v#^yt#N=fi?j032O?P>kuP-234}#$!0VCH5Iz01g~$#R z+ui)|@Uaa7J$`TupfLR5;m_-bA1|@qUtO&q?_d_>eSj4OtigoVWvv;fMu6j`$U{)AT6!gG1DBN z6zwgh#ZDtAf^j;c^+$$2-XlBCZ1Wdbdavg2Jx5{`hUNHhMrc8r_A3y=P$t4DIE;Kz zmS*as}!IaDT%eh!%_my=}uu(#!ooConX?Y~LRXLvbGU^8{34j`0r*_@Z(u@0E3X zu!+AG13`c)01u`o%0@q7Su5_4Esh1jLf#XNYy%Mr`E&_sF<&q#`$j^x?Mi{S5#q;N z1h2b7_tj)?W$zaS8=HW1=8~_v`~*44*4hjTnY9s<|fj+KO zWIi_cxIJ-gXzg<PWQnfJ5&hye!(xW81!{$F$>w)6qGf2O9HE!_;ifYzV(0p@Q=?D#L~kl&wwu_d=4 zJHWT5XADmWfG}l+4P0s*$T1E7$`+CwJt0(w z`i82)Ts||HlF<$QvV40#JWzlQn*n)N{`mA)7yBuOER)L_TPS=aup}}AfHB5QnL^t( zfZ5%eI>VT~1Iy5ZP$5c*H2d*8*G1UCcYk$Vx48S!4))#o%5|^#UtQ+W{wSH^GNr1- za(Ko{)0gFgBY*^8UN2tRLL+z+dvwbO$8#|&%&L#3BEb8)B~MvfK+Zs9`bg#x!bq<9 z5V{eoY)&63Lq2>DyYm3+*Y@SGx1x={A3u}Zf zfW}e2z^lcqrjEx||1#+KG9;ZA?;tu1#n*6#cp^4uiVL9**H3u97hWoC49B*Oc##xkS;B{El4 z3$L?S2>3vu1>52Y=3JCaKdg5k2eorLId%*r9-r{fQfgU?U7Hjnc4K1t!{P#P- zS?wM?i`ZKLuhbc?ItZDfAT4o=dBzp%FLD!-?7>x%$-(n>CUic5l1jGU+4LorAchjX zvey@X@do&!vlid--}sAju?)KF7r|ugl1Us-UPPAN4=fW^3s_p>KT+yymID_eDMhg2 zyjU7a2lFqZq$8A4qDx`6D;6*H(Z$-iD6Ny$K%&@>FIVV-hO;KcnYU?6WQa?C~L0m$>VXk zG-&`uVEl>UQqWy6b)da0(;X82^B7Lfg0MH+87q4cMP`3OUN>D*zEVC(%9O(MrJRWg zUmG0|xvL^vlWi9NlL7^R-QgMfXa*|rc@Zaa<|^2Le1VjE5J_w{kC1POTS7D;?gQc? zrk&MsfhZZ4)WflWFE~Ft*smrIqwAoVwNJf^Jtl;=Vw z2K0)U5;1=KEoiBPbrIqDfS-XU-v^cvnBaCeWjV?=s9W4ZCTCj72Qzkz#sXE z;a!m4u@v3(y*XR)8zXL)g9Tq3jCIIw?q>|fBT=7v2hNfHaF%cp{SQjbZ1d7L??~Du z5bSIa9sCUt35fm-YHLX0?;sZaJcCo)U;m6!cw^&f06)J4_Qmn%AKCLLvRSWKSl9c` zUsx;F^^=gRpEmPu>-hfRh=1@_HNVoyZ;)sQxqymHyzuEoI4I?(r^+$No*A2yD<{h% z`9y=cex`aqWSuK;KU4BfK4{(dV6S*>Q^!J|mJAQ+Cf8Z;AqA^jwsMVzcThOW7 zaXfP`fyn_v{Ml)ZVr60Q;MxMp=}v!rV}B11g7crIOUO6>WM&dm(~H%7i3`c54y&G!Dex{T4EH1*RHutqTL_42ZUHSqxa&EZ{Att>)i(j%=;7$OtEiB z*JBRCH-ZmEX+0Nngxs<{yzKXSKlpZW|HyY|=SXgSLUJDXR>pCZ7}fHAw8fIM&Hv^b z3`UJezP;CQ4u=;uQEHgPSkB0QU^ zbY5x455^v+ZU0KBh^Tw?PBv=*%unwwt^t9Nd4BJHVK!DiwX2W$NbK{wfW^NR>p~r! z$rE|=_YrVF$cEi-2{}y{u4n5B&-vjWv<`!ivv-UNT$K! zQa?Cmh~MMY=<&3VRIYIMM?g4>aRHYCj~4h9uns6Rk$(?Vj-YUSCUxLJ#e^%NLx8nZ zv@v-y8u0N(bYmY%5WIm<5A=nZhe3QyRKyW_^04_b(fb2=X^Y%_HhF^44{D1f-RvJ^ zo#)!VBJ{CAIens@t~)x*XvmlRlHm1BKgdc`O_igmAMoB3d(FvndU6@;YK0he+mnQ1kR6wNc_z;#S^6vPbGeZQ8WzW(MrMrIn8bUr_r|)lve8FHht(A`y-MhmWl zr|4-b4FwBOh3h0GO14$6VNxOrYtJZdh{9S*9H{Um0?V)vB&At^iDeE7R zBN54&-_uQCI-EyZ3LOko6W?L5v*y^v-jnRj-0>)83|Y;PH|g7RPxuB&oP=plEDl_) zL0-ymQiR-2kURj%E-e4 z(Tm*Yn9u?DLLsY;c~EOgz(JsZhz5T0lv@Do6d3383;;F4m(Usw8*HZJB~}{p!VC$k z(TpSq>>Jy;J9{9GfWs?9EOGhJ%X1?$u;rV2137TfheP{&*xRr68zRm#W8vmuFdIvQ z`P0R?{Q|1s^&!-` z;I|B&5Q2A2k6Th<+7jb(?I}yvfPA>{I!CSpmnZ1)N@qA@!1(Te_*XDj4k;I!ITN9KU1+wb`c{;j~C*qyVk53aig5P0VZ6HTK{LC*O z+QA+fvh4^(oW1qI<4^Kqv-NoT_-51sNF@{J8*t0F(0vlNfRGAKoM8?K(tvX7_MNAJ zbH(+(z(yAXU7;iEL+X}|0>lFN1}eE2lsXld*ZRiH0>@CEIf%GDh%>do{S)wx^^Mqi z^NL_L0`1~JDV)~YIyi_B9CK8_Qnq3~R%zdau~wZ1e#Fn;{W@9 z|BL%!|AyVyOJ!OPH3l6rI4|%+v+o^g=o^L(g^JO%W^+j@-~}bd0+EFhjnb`vTSWQ+ zBzs2At3DaLaeW}~;=%*Zz<^3srl8}%2lF;%w;-K!3p%vLQDPAs=tcyVGc_-qbLSn( zV$g+A#}-F!8rYGvt><_sTcPM|kS;h+q_Sk{c=3v%QA)5y&SIoy#GEOy0olQ64kD=z zyX8D`o9XOHt+X=&p|vS-y)WIWDjlUNZ(x^R&)J9+ z_fEag%+G1hprC}h2dWIM~nWGWIU z!xecNSj)lc=o;bRhj26|(V51(UMAwz^`weww{g8DmsCfp>?oA-Rn+QRD2hAXsEoJM9;F4%BJ+j_fkBi=cvzkz67fxrNvD}sS>ZF zP$?DiWfjB6&}}Z2ib|NKdzy@Li!yl!^q-59^HQAm7!;U z5@{SsElQsixUEb)CdDN^<^|xzQz!!&7`G-+y#q!!JddOqlR#4agGryd`1mIW&v5zu zRW^`cczKxzFzV+%crHrTg*m136ZTZhh%WfdFlR(>=-)-Uk@ISpSC1XXAnOD9%diYj zu6LBb28{m`_wb;8prWQ9^zXqO@M;=1w6L9F18MU$$+qVv>?sW@%|?;0FW;pe{ueW zoSRr`6wm=mt3motl8HEGV#tN}%`yrSCfv-QuDA1Qv#m|J*dG=Y`3TJ@Hsa-7im5;u zQIsc%eV}Ydl%a1HqH`Jv!Joj;K%`_TB9cd=!y%O=k>nj#z-EGXxyT@ozfn1J4sMowL-E%X z-`lcOe%7vC!q3&VU2Xdr7#Tobe)<5{GcaXh4{a}>foEZ?xIHZ~ER$ufL4ie$+{fkZfVpLbktzrgp? z?w`!B*mA6@-!P2uV)W3tkdN;A8Azdc#4j{^oG4XxWbu+Li`BaZ{yl2iV~mx+J^$rM zCO>G}hjRHHlhw~Jbn&9eupxH;nQ5Ec-m^3R$pQz*0|#}J5)p*aziYtA@&vt%ilCGw zur64x)e7mgz$lxev6s(nBs8(Oq~}!2d>9P$EeH?h`S2&W!2(-z-jEcxthojHc64hJ z)@N6DNvf@pYx;J;{8TR2439^F_7|Fye)`rl_`?$bVX#IhOyf)JA%y$)r0ApHH}g5PDeG zcA5K8GCj`M-B&^^L*rkB%BU%#nduNg;IEkRXM|S^bK*T^E_@_j3QDh==~xW~sRM!S z8NJojI94;;>7g&saTwTm*Q5wSB2tzomqZqGWN0gqos=nopcmr-FT`216sPY4u=61c z|Cxam1KC&(@d#yFd&s_N#j6ZnUkvJIkjw5H7n4Fdb4oNtVwq*3wnRF>6oWWawxL4y z^D$#;S!N`T7wIcfy_-`6`vDR0Z7U-M03s+@eR<~h`|8r{Or%LOueeBS+wL5hc`Kl| z1gFN8-96aWYTA7%48}?i3{Fs4cEL5HHF#}3QRO&$?MO|-QRzHz-~~0 z(a%^J{$T5+w8K9?{PT@_L<-3M@e%4IbM~+9(Zi=5zjfE3&YbVziwyrjxY6@mvRF4) zXnkb*G_nTRy4ls9Z2vtQ4yYv=GF*DQkt8~qC7r2 z;WzGuNXk{34cs5;NU+7sO`8oz7H3L)j8d`on?*qU#!WTNPq?eBNY<^0U_p_<5BG#~ ztI-vx$(93vHGm0L?CzW`W)7sLNB&?YnJr+tXUU8qn^O^7`^tX$`2ipO4Bhb0Ou@K5 z|N8U8FW1P?n%48W1FMNx-aSrVG&*zq){{$YOpj@Th-P@4lN9wjh~DLQMfcZ&plnG? z+#{9oTa;FTkIAf;Y+URz%!SxbEQ|XuJ8%Wh`;A-p^TS_RqaWD~yj=%d%bO)7YsO!6 zA1T1*Ywsh*e8WDX6$PsN8|@=I?5_xqw2!#TycEGR(D-F`kUyC}G~>*^!j3?60$78+Wn=*E-;B(n zJ_Zt5GX{7<1wh~{%c62jGb_v%qz5F5p;Gh?6D5dr;D0S*#>}knNGHv@!(+0EAP(3RY3gk}YK%1_{gdHV~Rsex^S^5Tp?E(Bk&;ayjehka3Io zm)n9<*hIvkwWtmsQl!H~@y4U*v?y-k^;39Ooz6(Z4XG#S!2%e>6WoCNWuTAW1^h%& z<%&XH9H|-Ol;H#JWQ+~+w@^(9c-N5Kigy8ErIRqfed4pW0Uj953Ak6PYeHN%>&xs1 z=gFBQV%j!j3TJ_z>m$7Brw(%#j8BCY*NpFZ8>3F?%HBfOKWXoPC&cQYLVUmf2FeuM%Z5fnJ=ybgk2hC2f5Ln;AMPI2)A z#l1M=C<>(79zz`Y;>^&C%V4)j=&!LQKUtFnn+vgNy(TNw!!yzy`x@N!JqtFyyZ(3X z{8|Nj-ID&c)Uq$av;E6!mQ@Gnip{5AIOH+3sSpg%Ed;8hTSz*B+goVw{0>pKzdmo) z*IS!7pMQOAH!O@;+O60@Z*HI7*&SG#;FkMHd;B`fV^=8%3j7SzU7s?m#02C|i81=b zN&q5JJe;T;Lo^p>4BY@KJVuwM1>GycxKNoVPX+9@} z-D6Jp07I7BoEgbz4T88|FMtMN>@9v;DhY>yupvlH+z-mMxc$r~LT$wWNL#{`hbU1w zaMU=RU^Jxy;zEKpWG=4xcr*AyU)5=?x{qev-{*J9)b`sC{1YVyI&g6xdA&RUDT21T zOqmJ35mhaDmI`1YI~&BM1#+3Vv_+BvP{8&}GF z4W_LHljq4s%Cx>;`h>7reuoJD2+2^0fNlQg#R5t2&?<(SxpI}nec=&BCf6>UJ*Q(#NsFYa z8^nd9;G4BMEKZoV*k)8&n}(MwewhK^8@GkCZjanP{JPG^bU=RN-L=g5X7{v8w%(br zKqDXy>V2UEVQ7tZCo$Y4w{2KDpc{fw5L*Nt|8{Y86}WYuQUL<&{%H1mN&^G`BTBh) zH!$c%8SrU%F=jI$GL&Gm9@>ykUWO_S+fLSf1cjh%Fvl}3mS%|ICzE-nNM=R{STXe$ zuM|WY5wb0U#uDh6nj_S!=ZktfjKOmIyTBM(m7jqzGY|=&mPMoI;ma~Q|3Umk%-Vrw z+KAV&`HQOfYj#7&DGTLl@Na; z@%3^krje0h(l;yvHlKR{e!;e#wdyu)`U6n(s&#WRLUH+%74q=Lc#d<)an>IJ1Z8CaHv@q8BxY&L=IhIinPoi|;x~c)=$!-M6a)rl zkTpWIxmPUcI&1Jre%pkdtUa^ulHiAKH|p6i6UJnoZ9eyUqlBinJqkCYyOy=ddUR$ zuvo7i-8bvFAsTnrW3{^Cr3INi`&klYS_3|?7F!4np?YDZWr3FDrD%d0XG$QYL&?RX zY7pDbBSx5~AB)^3n>X}%EOO+MLw|;GIB#*`<$bZ1c1M!D8yh7)pq~$~`}MJA0$5%$ zXHdiQ<)^>IzuTuaFcpp1`TBpy^QB-@|NT=2n@x<`e~#C}TH@5`=i81~h+eOs@Td64 zS{K+B&v$uIi6)q_!j@EJMkzBtc$R*F?l*h;NJni7{bUydQX=R7dsOfC;yy4b?zdkc z*W+2TVT&sSgaZVzAl$%9Pk?amP5$B_&j)C`myl~%Mdq93+z{3> zCjLoKU~>?YaEP2A*!gQ)>~lE=1R#RLV8?kgU8{k>VV?qCHur1pe9tG!usLA_b5Q1F z#KS7c*@%4eVQMp756S&OuiI2y{y`!z56>ORn|A5)YKzfXzlb}! zU`;$PwQU_P+umK+84rnpuFk~z%62*rminY={RjW<+xwh94-R5Ga>q?oz|K!rbk8gM z0evQODCJ(*V$K4GpZ&1;ux5>K%-Yt1wCoTB*sj19O36TgD2eRe9G?i+*^-1snvTn0E9p1z6 z!oG;wvox5@aU76=>VHh9yWTEXHt0#uXmuc<^XweZW0E0?TtQH?6dYR@3Qq3Q%%KX9 z05cXONg*SHi@3QpUvzW1#Cxj%KJTlEdtbRdWhObVndX;@tC@LhgoTL*cVZuTofQ}N z{v$Vdc1=*1>B^h-RZa*S_9*aCXG-~-E;9uP&UX+VflI*( z#IVb34oeCZO8QIw(qes-@QtPHA-6j?FRq}4gkd8}>Xi>4%rHvwm7qJ1HgIAeP{gv? z)mvF`AeqfqT|GZ9!eoDd#pC3;srT_KA3Psb9Mj0C>>TA2PEhz z=MDe{grxIG&RxIx;%!{K7#PM)Ab1-6>tc5?{?}RfnWl?zf3I~@WumW6)6dJd4^IdG zyWD#2k@IM(1-=SHd)|S|!M_$?`vygisWiDk0z!nh{3kB@dR0@vDy`jgYKi+oi~dRe zGAe5M!I`$(WtCgVAHbaawI0J725n#)!89KDd@j~Nt!yeU>myzg;tS86(#Ara#e{h( zIRQ6Lc#5E+?v)D0n#FnQ7dd3b`+F0|C(JMYWu1)B#N5}ZUz>1j^Jd+D$@%Vwif8oidN>Ns1aE9C=*jxe4&{qOOqKv1@1?OJG)4IsjAC11`YIs(#FT5ZV zSWxz44|OV5B;w5&-18xCl#T+TA3g)(QETE>i)wZFSxCkP@E4UVzU1bw*1zGbODK^* zRWd(&!WT&LzI9-RL~mxDqeoF5^9Gg#1$m>Dz%mwdnn2)#lA*l=j5N$(#qHxXGNONa zs11U;J5-pHCszi9k<;XmwEW!FpT(&_`HjmYYG;Y5UT@7yCfF+=dc)?lP!buH?R&TC z@$-(@tjBLN9Hvklgo0OL5*r{dAo$3QEsHXx{@@aoH8|3>SuTs_XtbqgA&lJ7Tm`u_vPVY8q^uWse!6Nf2Jiv?KZEKgAizKKgi&bX4 z6Z$7E(q^M%2V>3yM9fN zspnR-Lblk8%S?^!|2}^;GP}sIGt(GAD~w$+<;3Rz>E^ziDJ4zn{FiM#gnqbJ^);kf zbH96guMtq}(r0=w-}4!pzURV4SOn|cumZ2$*+0BP^nd(i&+uix0=G|X&?g%H#~u1j zXv7{jeb?1T>?i$vfrGqgc11*Pkcen}dyw?z_UXOjW!}bcHhy-M7P7g=?1&j$Lb2vESF?4;?S)k6+HLx`41tXg>dCgK6-f@VX(tFVqOJ#>M<^*y_8Dc>?)2 z=z;Enx41*k$#fTSfTHoeIm7-t-+x5@;E$xMLrqv-=H|Qxp{cmL2&n8jy~j!GbR@G1 zg{ksFR`)))K!B!m|F&PW^k9IBl=R=r zr%3R$9!}^D&luh5(eLZs>`Oq|Z2pKuQI}Bp;)!0Rg1&cwlB7z*p^HC^d-ZtpM5BF$R!Sk){MdsCKCi(_ka7_>Y z(8z!t`F+UzJ%|Eu@k{Z}f*w4WVFnk6^ph330W3t>iwF%}oR|3g4mqJ$pGJ}{dOnY1 z>l-l!x6I8S8XCleKN*3)VKc57wLkPm&}2V(6Yh`~Gf`~|$wsfJiiP^#vURs?>X+C( z6YXE8pZhW#r`7pg;rQlOaqH z`J0*2%Ea~wZsYdau~t`l|AMJvrmjDwX1cYPx5J2uyv=LnW-Yee6@ySt90ZZQoaW|g zVfGlc`2X4Jib~-cFcGs@J#ovs69zkBsf#YsW^7 z-UjZ_YEF>3=-+t>6gGXgytOzw>)!lvkHJ*3{W~9nc^U3z4*NGciRTJ4{~Imge&W3A z1-zO-&-&n*Y#?t}ML*{pVU6%CF1|`tCqB4`jGxOrB)$+zp)*R+~lvVjkl+vabc;KG{0>oTG^#4o_;y_g8Y znv!{TpSX8+q2u2)F^07RU-eMl>b?FlC4bg<2+gNe1N&O)wif(WC94S<&$DUN z`46apGky{0(@DK_h1PJSe<6nI=Acap^;xidX{_H3tS@GJHN!VqZ#WC`PwAi1pZzwH!Q8RW!@=Et zha05brB%F-%6}nWedLpJ>{-n^Fr?>#FN|I8P)c|EJekul)@Lia$~q%%2xVZfYDyse zv^i|hH_u$fUfEL}3XkKdxpYq55Fyy>eV~a^QC0+lO%JOlv&qwZWw^}WUA#GB#dt+& z7pg(KCd0O?Gw$zQ?d@=a;EuJ+K9#?%TKgY7<`$-`ET)t`3du@sCq*+Ws2WA5QBHEo zyM!h{|H!XIGc#AgQ+e?$T4riW%w^(mAv0Cm{EbRg)2}EniDK3$s7>D^-=hp8#-Qg! z-gxpt!N#|F&>M@0V^x-!#hQ|H*-DW<(bs9JflFfj(AXm16AOr8n+w>XmEh~B96c{5 zPUVeh)zY6F|MUJ&e{p9y4EHF>HYn27A%id?M3 z<(T5pitBx}*oak&#e}5p)A5q74z;M9kUbSOYV4cEs%BKY)nhj?nYQYsQ?ph*wrZY5 z$Ge%}|DMiCoomqsYcKEj{Zgf36wzK{AJlRK{M@yNN~~E6xI5E|QJF?|-KY{P>S{w% z8i{CmnJA~)zF1LB%cVxTlh`bZ$=oVCtxmLPsu4S-_L8Q{2Q8-U#n0NnC}<=3q{Y;u zrgx6osS?QPla`jO9HJ*Vtr)qgA~$q-T#akx)IKG%C1zsEM3E{-MQ_&A?pCe2=q7U$ z{Jv<{Ca0FSdTRNqC#`Jk(+2w>7E>beQW>*1+c&&%d>7fK)ZC;!D;=d~St+-@5jP$v zTFKbQjYc{%Z>9#jPEIb4mAC=NQ13+Uc-Pxzt+F=^?62&$FPjcSmi;M3itS};kdfy& z$zm*((qe1BR?RN=UH_z?Q$xFTHdctZN7F=TUCS<0k>P4ys~mgVZ9eXH*1Yl}G;XCw zZLOzCdNdH&1;=q$V$zv3JVR%DvJZ7~rG7W62d1Z$rtSv2q}Nqh?DFl|W)dC^5Bp5& z81iP0t-La*gjMgP?^;i?bFZ{o>^qB7st~9j-G^z!?W(UE!OWo^DmIKVPN){&MNX~J zblyMgcd1~x6WP`mzWrb|@+pzZFxigwBC})FZB%P}DdMYp3$4<)6=@a%;efmzA*F(AfAX1B!_5jMY__bCI7nHaV%_)!HR3 zr+T7Q?{U@3c@BY0bE@a+TCHO^lhJ5u*b1q^QCRnPvbo7R*@|anLsMiqF)|wSz0v6G zV|$!-$*oIrG3ip|3XVZlTqikCaFi^D6}cZ)6&d%U*w`oOx|G~`MQNyUC3~!mLd)vl z=sFc!>u_J499xsDM=3WYO|8(i=%$NBrxx2MqS1AN?wzvNqKaXx6a(KEJ27;c%Iq78 zQmiE9y=HHxigpq;jLPMn~3HIM*;bIYYzr0Vvk!ii0_y^A-s)G&}J z`sd?f)OS)>MyR7K$CK5#weokB#B|<>6`O^_DX^8cO_w6sF5s%UAsgznr>*PMLJz6?APmV zcpCAJwZ0~GJBiw%>HdMEV>K7MMaEJ>2dY1|dnS@cau%{x$p_t&M=+ zI{-c-F}X$^09N@1=}oG-iHZoXXViTpSyd~BRP;uUokZl=sFxOPum6xf$rFw#*Lrf? ztq`K?)zUy0rDM0AbEo3DT{~H22(NS88|7MHlpU!fEvhCYA`n2zt&*n{2l5LvrqyFL znf7#iMWf_B>>AVfIu%dv+P>mGIq2l_y0Op4RG@76nAhcf4bL?5nWT+04|_PeBuSu1 z)yjzz3PzCzTEQG}*O@81&Xl8Lt=!qCIT_1J>LI|^Tl7taz}uD1ta<{)(c9jGhf$-M zwoa*&ZR6-aq)zgHZ-J&K?redSQoHN6H$7-aIiA;2iT?E=aQvOf$+4(1EM^p=7_G*F zQExaN?F5snrK=t*TgEKb5he^Xfm`_p~6;#7T^WX|Y^ zGWE*7*RQxHn_5~gul%0PFwv6(TkmlKVAVRyiIhxcf^|7NYpU6qvo&6OM)TY%<%uqb zMJ3;Bbqf1Lyt?-^2JX7w?XNAz-tlx$S5ihST#k3TfsGQ5XHPKh6;m-FK3Tb57QvS6 zPbhN2w@U11i~43#@_IYNMyt3ir~{ursDu}rz-c}x#s<1CwA}mmhlW;@G{34x(}55O zR==nX+@8=R;wzNA)w;Lc@Dv-tery@`91q^cCYoH${OVpqP~UerTeK5 zTKf%{KbATH^2g1seC;j*esLFPN5N|;sQG)vR~5lmMU_KL&1&+Pu|>*2i`K^KA+F0h zhc!c&V)5>z<10-%Q$P5n_`a#DWe_F)!9h#2XJw_*_I0;f$-PeyiK5GVC{`R+a^V?nyeWMg z>=kp{`6-rmZ)@S)VVggdtB|XC0!O($3@^t^zi(0L z&W3vQ&|G$xf%UA?j*PR%P`H0g6sGB2rr;V5wQWc3yvQb)XsEF2O^4g*3+PA)hOeTf zG@+$M^i{NU8vUE0rGcg}C{YP5HO^>BIW{4Lc57}foC5tY0gOv-mjc*evhPf*n^wKL z$<{eKlR9I?ZDP@F!yDOXioYJy$6hUFkc`Ptlop@kSqgurPW1nrKKA6R5EwfC3mH?A zCku#vmA%SQbV}VH>P@guz_cVM4myd-K^@6Oj{7@$w8EYl)kMSx%-huz$OR;B544J8 zEl~yUHOqP0N$_gZj?wUHhfGYKTKt-uVcSJ>IvJV#oVgW~QM0ZYrNqQ5wdy&>=%sYI zZ*e(sfu12!nEP^t=I12PU&-Z7sgq1kASQd-WzUI-2>vg3O*)aCVzzoznVqi5p&FMV zMvaOPY#ZaK(NJagsDYWyclG^b+w;!jN@E`OhsI;I+HDs@hkbieY9>R6K`N&&%8}@1 zsm#NntaDNG2c3yg(_fDSg4o+iRPVX6(N=08Rl38rJJBz04R2W)lun*>Av-zFbmL|EzF*T0w8d_&?JC<24>z<-3yy>TV38hz` z`hAUK+LxOJkMVHPz3o?0gZ?Qk>m!%m4jtp;bSx0sv`V|3au}$6DO_3ZGip1%50|3- z_9?jZOtzkOw=`6eqeZIHZ28mLLf)5wR>rH5>#%oECQt;%k1_vb6DT*gfz+{6?C%GY z&_=36d(&8}F>r#ng>Pk~Q6+gEqFFgX3@3avst- zUGhQryAGiSf)Es10m;1ke%$?|Hd4L0nCj80bobTkXM6n$e^#s7L5*=efg;a!NpV*X z-P&Z@s2hi@EJppbYhDlsu{2hmU0>#mE;_l%xNpHDL`>OX) zOLS6=ZP1tw-Ti37TZ$)!jp!ic^ctm|>MspbokB_KYr($Ki~4~H^11wJI9ycJX6AHg zd2)TFUC1{5QCHE(y^LclsoBhwHg42A1*rUtyMqT zifT{*dYW41P)d%ryG*3LZMdtULwC}z71xq7 zlO(&zeQBX3I{Riz8O;-kas8xpUjl*WAVB&Y5YUS5eUu~bn7S{;D&ze@Q|5eTs$9g~ zPbj2^Px;0;?W$<<-sF`ypCl2Zl(1Bd&4}U# zgCt`ahjqL<(zaRxT(;4cZ)7^AY6RaHALTQ>RX7p}dZd$)3B*ISxVt?Y`O|eRt*c;u zTIKf437Ik9tEB6t>C`n=yMfW57Hou;BUf!b(yQ(Cv{UW(_K@NV<>f5p9xIZPYDRmm z)3zT>)hes%tQpD4-qU(o%ckbtlXn|Wb_br_eAyiKj97m;>v&GfP9afA)v9XUwF-xh zlliihN%ne?fE02&*NU&>e@Uo|4H0MwHA{JD%#e;A$cbxTqVp%Afq|vTb0g~s=IZL_ ztGrf5CtfRa#$q$MI=Qc2Puv0FF_hXC7Hfk{&wzzUy`Z;h-7QEt!&pL-QuKx){+X1g zSj?*Xfm-pDV#Tr&2cy!9@7)1tRgO$Uj$iiLDA&S65I)k3%lKJj&os4h!L`VwBq|s8 zDX!>-T)9y(fkihFUrXQz7ENzp&`nm4P;d(kN~{fyiK@#5fz`+yQHA0=rB)7*NV?b1 zMv4&$NIOd+@nFw1BSt%wSe#D9UOMM<4u&JmH`jK~YN%4&War(4GF1acBAJ<#)ahiW zRcnEAJtaqzA$?Ixt5WV*ZjK_;SUKfvwwo1w>()Zq@gzTt^_8t>;Bsvf5odNYIQ4VM zeR?_#_w%J-auAla&EQxm&N{V8wLA-?^`3Vq%|rgEF2^$RaAy=^hFg$7g;$ebBW=BQdn*1N?(h6jT&hF zBHr0o^-GqUNJcs)5BVO>^@JM~z&mj_YI{(I$*c{Pmc+6NJ{SWXelKocMSM{j7<$x5`xeznyOA~~v1Qh; zDQCEm!RYX$E~W9Q6;JtxnSz{~yTjnb z+`e!-qXREx^w@kVuaiEfk%&y%CF3;l@1iaLY}<(WQd4Kdl{uw{oj@U5$mc@-S<^3- z+Q-3oUk(ix;b6_33-0}k$-j=#e7_w=n}+n$?}E`rc8nGqAM(2D(?-oRMq|&4?AdRP z(T;D$Xs)q8Tpw@4C-pE|smVw_zH+%Bv@8ehL(f?*Pt&QPR}S@+y(b*2MdG{FED#M& z8>4L^ACs!P^*q~C{lk#HUCPP9X>jxoqw`^DUJuQJ-TkuCsT9JYUb7#aclzBzdV17$ zTFVoP1k!0&B$b)@=6bQ99YX1{bQp9F>S^oIySvn((2m89#iiFcb_0QU+t9p~*}nls zOMN0nvw?{XqwN7Y0WuBeki>#9cQ0ZzB^cGqgNYG4rHi%TI#&*~j*-yT8Jn~(FHS>A4=PW%M)>XCt7{m$&@{s zYg%-MvQ6E!UA9AwY#X#btN13{4)#IV5ST~8eZyE4NmgGaJJ!`2{WApJKXDnsJ5ZX*-v2;B??S%*1 zj9e+htF?TH_@#azsBfEd zc{$8QJj-KzKF!4sz7)(sCG9Y)9^9kZPIqVb-EKHD)>`>g!r6$qhU=6kvIjjM9~xs(Ns14$aeF}Wat))yhOiNjIqp8DP zAscPTl71-azE(TrlINvC>U7E|huL@-32)Z*pwAVXPulzL$h%)J<4LU(8IJey!d~Ar zru$?=srnP;`Y?HLx09|wL>@>r&9jI*b80fZZx{Q8dsRVs$ax!xUAyR0KYm*6iML=h(-bg=^R_g5I{BFWV9;iW~ zxnLal&@y$0wb)!}mQF=4$g58?G~C&4Exm5l;2M=A-=X+X>fLn`vMF@R@+PIiQ%Rri z^V}OLtHNB@IF1d*oJSRF0#aMdU`QV|cQC&Vy7kh$?Mp9u)9N^ttezm3?b_2rKr4m0 z8iAz4L(}R6K37a`lVJMJH|r%IK3<)5T@^@%7kcg+4Dz2nGxzKnJa&b~wE9LZ)vJev zJG0ZbwS_h#i|~8=+$+};|%qxQ{b&&TTPafL2je1 z)2GusQ=A6WTFHINR!_6TA+>BD268Vnj0YQ<-z}%|d+@pL(kZi89a_!ou2a%uQoeOK zECOn}?JOOXRX$j&cBZ{z%5|H4 z;uR{NECf^fr^G9p);>_Yi*l-0>_Tx|Ilw_kt_yZS6`mzb+2S|avj%(_RGU6|tt%ep zKx07GKO|0alYgt}>bSdxZ5?hY=ErBRN+ChX0m$^QtodY=G7mGA;% zr!PO|zCg5;7o8xld>~s=Y};y%I>C|O?acIdyTj10O-jiX9gY3%eIqN-z=H_j1`Qq?dxVI`%*w1R%%+U*9sn1 zV|5zUjAkYhPb|lyS~I$;OU6luZEU5ql}W5@^x}a?E*u%g=OO3nSXo3|<3Ow+jPb=0 zG)LUB(v5LjJZZHQWyBSIQnJJh^ENHbg^I`Mc^j=#(OW;xC&jGKt)BGq+~qn&%6CjV z60CvH{;RTQR+#nGh}WI+xwi8cO zCILhBg>(H$u2MagO3F+tb-T4i2ck1sFvq*N3PBqgj zW73aKL&s@BZmZQzao=5lsmdnC

cEe?l6V;jmG)4g@v}z<1pze zvtgsMa@LO1dZpEc5ilA^PfEUe)aUgyB8^^Y>93w@k)1!{8z(g-7#LMn5xwFnu7aI@ zWV7oa&zIAU$*1jB1Euk zrDs{TS5f1ZxUr?B4YyEZ%-@&>4EJ5s2n{84soa(aZDyU^1tszq65Jvtd5lJ53kwBoi$%*CQ>~0Lp_+k0d0^^@vcT?b%4tw6eTU3aobMTF6Tx zy}aqkNZ8BB!sQzulSP>Gh661lJRaE!Z13Q;aPdxR(|*At{mOTjJN6iA0h)5$k9m~& z@n+hEv>bG1r{VduQjH!mYiFujZbu_I*B}`SO6sbR-TAxy!_1j*hf@1`t{qwR;~`(Z z?r)?U>G2@uamNcir*Grz_=oGtd=M%x+nI8!*;{6MT5XUB_vYEvZhl%w>)^4LF81o> z#dxV4o$lnU=NcMLk354(el?13_4#_2Ym~RWO|#$27L|FkUms7F8-3Cn#`N_rX=u^( zP;F;MIjI~f8~x%Tp!cKxY-c?Mi`j zuk8I@g2iOfuS#*FSeZJ(j(an{sR;tRP!Y9pPMYY{$3F=M%5zYyUj=)Zcz4=}>x08#KJm9op}dmWs>STm zpIE2euG+qBbc((q{GwJc+wQ~dsoK^n>xC3)hU3X{TiNEPF*%WrZd2c>e&o-#O77}-7FXKULcAN;mXbzb5F9wSu3R9I zPK2aL!r9&Tqgt+U=*sSW;yWqlDCtV?Uzo)cP@mO_s_2#;cxDmu- zOkto{oGPy6q>?Rd(?wTE(v^|hRn0a>)9E3os0H7A)Nmd==}2(Zn{>iPPfHu>W<7za zXz5A@qIp#rtGga55he8OEB+HzWT>NfBU1zBaa8YkPzcohybnb*K%QO`nP})W4&jn+ zdu=l>b@YU%IcO&)EPy2yXTOihUkKcz-_WO3cNb3Kt&>{U6c(*OUP$>WaB-_b%BZ5{ zDV@{h6UV`8JmuAWwPm6X(F7UpMV@^-OE;`cO zd8Q+SI@o+@KHD2_+$*tF(wEpPu~pKS*ekJB(r4|}GlK24g04|(q=Uouu(n+`c5s_% zWS3n;sx-He{4!V0?hg~CzYn{E;q}V!jAyOAJ5!s;UFfF{siBl8j{Gk8zfHsbWTYKg zB!+FLzMYl&0r$G7c$%$5aO#W?_p{Qn;6AwyKG*<_mXY_zR^4Mf7mpU()0i(7bB?1^ z$O7q_QVcirK4geZ{8X)%bKP0SNH*Qwea`KI#rCd(P8bR0xH2zPX6~%APe_xTv)V{H zYrR9?srwR}rZ(z!BiUW8TAvr3!@N?S55h*jylHjIuEp`N*{0iFpqbz-TT6x4b3@O@ zC7Ja7|Mory2%xa-}BAN-z3Q~U6_hjqY)Ju}>6+-d;UqmRWKNv!RFbzkGu_tFo zC?sL?XTK*xNg4k>2qmANB{PB6E>&x$tDfMl(Un8+bewssm2R_H>ExAay%P)=-a`DK z*Sp&ObQ-O9l|(vJu12M3xwMK-g7EP0l(Uu7)RSvQ;BmKTc1vmX=pO5(L$MvID}!n= z&r*xPhzu4;YXE`&;bshQN={!pZ!uA7d85g)xkN6pSDI&O=YtQIhscl z(!7>*4tm9?XX~8iRS)rgN|jL|Qpr`F)7m~3&?cHo+pL$~ z)~P&%R=-`*w2{BKULV%;?y)sh_tBcGkl!|gla3L{Y);{DU;w|fY-rO}k7216sScCw zLiZ(vQYzoZ<3H;*^_pDxhvrkDw*N!%DGaTQ;AQS%UZqiH-* zOXf$_b+M(iCjD4vR@0YZXK%4Po#GSd)GFS7u2P<7jZ#i=Pc!-G%+o#fXPe-rEBQ{% zLp(h#__Rzp-0K?SMSty8N1a_*ji$85cmc*(i!Z$GcDxgg_k8TF=rLcDv%`2}`Ud-0iZuMoaLS6J(DDIAX&ocl1016LfwXQFci{t(o#0~-E>4(x7yF5&J{RRe>y$^BLU9A5l((PK5ZB7 zt!?lUgUerp0_r!F9~}C(=jSS^y6KQ}Jwym8!7AX|2c^~Z;MwiYzy<4cO9w&y26(P^=+{DHgi~voFhOj{T6d$o6isK!++5dT)p)K^?|<2dnVTN1IkRfsuQ`Lh=L*?6Mv3#92ax-WdX}1$791K9od>WLYnA~KQ z?8nSGG9giGDy_`2H%T!aZ1UYzb{~cBd!ec6>it0&w;Vc%G)9;i|;&U~M4?VaN@Nk@^!?lAeot-4Vj1wZ)9 z>hp`C7yKw6y|a~MAN?^Nj)IvWd#0L^!H(}ZXo+Xpyw(K>hogWvb6_{}`^)5B41Bkk zy>ky3GT_(_Ti>3iw&HfdL|s-nPH%*TX#A_5iVFYi69H3ab>PS6z6qSYz3I;5IW1#m ze4@pkJ)ZIVEnyuX4{`qOhGacL4p;r`sz*yoTYiA*#NVJECE4 zG-w32H)owbn4@ytJqEL{D%)~xZyqR`s%27Y{Tx2aTZ^uyLAwU>@l=-@bB;1iRq&(7Dsl8=%9Qa<*7YYh>*hnDV7cdy|RM7rqXvy?ag z->MiUW^6l)1xzc;|o6okWU zC@)*zrdvqGmtEtlHMhA5z#%FRDwmD>)P&~ebl!s=d`qc(U-vhEwI8x>%`3}+!>YP| zHuKSdF7D>WOoxL~7JZZL$BlN}M*YH@NDvMer^~w2(Tv<6cIOeLjFDSjq z=uUP+V1x1UJw^^{=$n*3l-AWAi@wZlogu}=dCN`hyAjv@6qxBo@!^;FU{-g?exq)PnJH9sOpuu@K z0_qLtcZ|+(g7J**bmQSuK)mc=Mv?$W3{YxsP#bE90_$mEyrTjF1f1-1B9K`KJ9k)u zylQ^~^Ndo0_uXDp1=PmAI%tjrTs4rDz58VoP0?!@-B578$m}1#apt^#ZMlj>iH7<4 z+ZVw|d;0mpZhIGOK%dPmb?;izv%s5{J-X6g;t_Btwj3|K{1*0UIxMxcxw_c#9b z5^(}oARItd0aGR53vBfaKEG>tBWwNWj_Ui^3Urp^ci|>D@m?gj@86i$UtbHyC9n9R z_5^f{{PTt149ahWy?2PgS4;3W1^DXIt^7}(lpjrYqM@lEaN>s@Gp?ToB~1v;0Gg+I z(0kQd#RvRCQ9908bupk9jOPfTm0ZUPKzsmJlYnU~~z;1q}5M)yHC zj`?x0+RM&p60GE@RTk7Sx?G5{XhSVhtH{_El`_(t+G578FV_bmmrR5mq%tHlG0k$I zj-4c5@fFJ3pDM5*zMJgM$p|N$?VGIP_bxj)CfRRD9k2@@;osk2c{t1}($-93dRXK&{J!g! zTZl(VHci82FxN(K4sBXWS;d)h6s2yPMos47zQ@gj%C7Ega>f%Qv&bnFZ<@cywS3R7 z>DCIK&9Wn}G^iD)3JbV^a&xNRyY8MHVUh?Nsr5J>c*Jb+US zz{GI_z>+8x@FmfW%rvNjE8v)*0KkGpUcT*b#k6y{{IgnYg)a>^>BnlUO4AD!ib8{J zg0|Q6QMPqQD}KK4&sH8)0N8|Rk=nO92zKqC>}4_CHn>QRZ~&F(e8W^{{`pYfz29^OC48y%3xV(^QZ@SXf#rBP@Dc#WIDwlY2 zWi=Z5w4Y1Rh4vpxrUnw=lNXz4}#Rg&vwB#Lc zrCq4hd4QA9=h$C?_H`Ao}AeT#vZjN{ys;x^lEQwW~6F7^% zy6^X`!jK4mw0?-4ccm4&Jyi0q&@Gm^5lBlh4&;GU>Eb#kZs_Tv`{2>6jJH_5}2*3RER(F zhv1!kZ{PWD+Nt4DlbI^Hd3riL1X<}q#>wgFzK@ux-klZ25=a&pth{`^C}yrv=)@5` zjyC#Z^)Qc{sxp?1Pn25!>}9QJr#!S#;o0)!P~tU}C=up^&coG`Ox~Q-qxK+BZh9gV zrCQewNB7C$%sa_(^V>OLL_uyF(%nBE!~ zb0MBcJ1r*FciYz6oURdJX(PI<@X@iUqU5Bx$JfiIzN>{PCuG>E9;v!)>x>)Ps4fPN z>=D5bZ$w`qTC)b>UU)S*N9!s3abXySj`Co2Fp+LFN{bPwy{}QqiRFe77vrS#=BGQ! z_e!CkmPWiUr5qmZzu&2Y{Cf#17Hszg#b1R ztJ*i(=$k3x-EQ@AU;rN@mq(ufYcCM|Qwwr@P@Nm^!n*uvzxac4+cIzkXqk-Bd-$uFXj*Ll4M<44YSr( zA{Nj>G*_)hVZ!}JrZ+F!Dw2W_t6$XH*46bHJn*W+_GER}W(pEL@a&Lh3#tr`)W zb?kt~eIL{_t0y^=(nEN|;_QA;)|qW-7kkm`TYeks*&>oD`E= z>jsA?p~vKy6H`=zobXgpKa-H&9L~cvuiI5g*tx#J9*VdfQx(IX$eiXS+FYBn0XxjQ zl7G^X3|W`-AD701fA+zGWMjGBnh$m5iLsI{4aQ3ZERAnCnezumQPsKdg;9iJsK1+Z z!1w;HU;dzZ{N(vs@oxZ)7tKVFMHxR(3TwxbDnAT-dKWcS7Wik@1*O9H{BEt#2c|96SAz^VbrPmws z5L#5Kfq#HP*<7ZSjqtQjZs|qXsP&G59iY8GU9j=wckwFRU=*&{lAcvIihFMy&!zqs3B0fiCr_t$<|EMIN3)mG%<_f7o6k-l@-zVO!G zna|(3Z2CWN**?v60$*CtXM-LQuzK~E`J)Gu$-kl;4nq8)iae-Odv$a$j*zKY z@x!^E?yGAOs3R_YxFL*6SKxR72jNhSAT!}aT7Z*(=Kyire*(6?iMe6NxB5h$J)2tw zM-D4SkHma5!!?~F9d>SGW&Ckn+tZK7)}CFZmwKkiadUVe8zYGEYxk=+^^-;|iZ{+v znrU5M@b+#+7Bgb`CKhdbcd8X8&<;ET}!Ul*J~ z-_#->H0U2+%m4iDUOPAEcYo@~V)P%qyBB(cf4#eZ#a!0Or*ayDp17n1U0(bQh4Yye zi@O|E`!ZT#y8W=90%|0_%*~?GqJF7*vJ3}F--ng#v<6mv_? z`tcyzU2gG%--wYlknu{5pwUxIp5M9VK?1)^MUeYE@VCLz0(fdXhoaiphwk~vpNEQW z!G=kOnKnxI=Q^iD@YB3!T|_xw0KMy<2xjkI&tI*c?~LXb`s6?aGJ+(&XAr353nM!`2WG3k$A_UV@V@`VC2mB)N=8gSFL z0#um3T&miE9E<8{>XCm3>cvU-PZ!_Qb#QrAopQ!e;38z^WxANmC3>mfS)<{_GPIahpZh`HV;)AV~S{ixty3OIOe-YLrO6?}Q|2QAci zC#nAY+HXm!U-2|6vH0~*)sNx0`-Epqn4AP2&{Jjd#V-ztH&)@V1skaH|B9qai3L?m z6cB{Fhw;44kNGZdLVA`?#F}2GDD;0#WDM>rJVKS{v{%h>Gh@9}bk}W)0yXp2AE*5; z+le-1*{vqlg>Qt_ZF9A|ECJ)MrQ=muB2wZc2yY$;>u6Cc5Rs<)N)8{qx~Jj*>e90@ zh^-EjC*sh8XShkb$$u23L?4@jzS72pNd zo($2#{>^y6-I05`VN(c+;nlk2n;9WOb=%yt`%kGnvXBbv<{7j_cGM!s<$1EWz|%Fk z!+#zR{Le|M+^l2`Fxajww#pyHoy%qBd1PDX&`ZR5C1W2&OqR0wxF!t z+-qS*6KU;IjA%oP|A^R6YCB%2wKh@vTfEvZ2X^Vny`DP}am#xhe@d8feFfnBXg=g4#dcwW_7)KH3Fn$#n}M&1fEeBDbzHL{& zzLxWE@A~W1@t3##pT28oD19(!e)G2f^sb>*^GnLus~7qfGxj54L-5Pqx*mP;7O$^7 z2ozEv10~XI8lw|z*KBlqpGOJcH_VP}J;1 z`1jsi?>(S)CZGVVQEz`0H^4(2d4s<9$^k_-O48=@^Sp`t>Ewfsd?@QfjzaE4F`I-S z6m@w$g+Mb_*~z3M)tm0*?mX?IaxTy6I&8a~8oBUB(bGcE?y$zdV{Ut;YCf=4RNYfz zUZzt!j-XR4r2g3&j`t|^j_Y>G)eNkwio2+`=}A8}eKH8Cs@^XQ@g8 zy&v3*`h=+TGGo4`v| zl{Xge%N730G0VauC;#CaKm4kQmiHU=ivSxA^*=pd|LKkT^*&vFG55YbU;lig!Vv%W zHs<#jGhymi5#L=F3qo+LEnQYRsu$O7_0kq!uvu=R#l~8cW{H|TpEkhrs&B4+exeXz zmI96(hRN3}c|IL<(4v^v)eXia4YW_4qF6{`$7nY&o{Jkq6WacPFp0XUMQ<$cj@yGA zgdh=oK8O4!+)6#$JJJ(B^GtBb)0ou5RVtn#2qjy1{BqfL=T@sdynV2cwkD!(d#v3t zH%SR`((Z;$BOcQ{Lb}hQ4G~ zd@j9=fb`4kg80WtdN8Mwj_=9CKY$2WPE`;Dd!|62$or|$8gC(=`6@}qRDpOO0dOLH zA+poK!bltSw}!xIT+o@jjO0q^A;f?6o` zOLVwA-G(XFsHhAFb6I=6E4O|*SFZmM#$(W)_I1DxdV?5C)^Br|T*lbwb)fQh7UZGV z6goo&ns>M>!N>wEx#moeIfika%IZ43(sJV(OHdW`lRq7*BswO^33!@ZyOk)EidNsLl_H^ zaQl%Eiu*oB#p}Gnr{lv;?6Y>qiQYI#n`SYjw^r8kY>iwAYF8@u>rkB(qFxTBclRPT zL2C?+3E|e4kfbD>CVw8b&&_JHF3&FOqW&%U+_Uop2mx{D-4FD_h`cBw?FkRl{D|(J z7kUyRcQYPXpp)-C(7t@)YeBa1*~9;RbW#?*%cIm0rgPA!%prf^pT03nfSYSV+mo&^ z-!Ncr6tEH|5I?F6zCI*14^Yf||tIxgI*Bj82ZR@Km2WI%$`yNdPpyt;n z;mh;-Y7@Qhz5Y@h_QDB9o8{PtIhnypzt+xHbW8Birm}O9`jfR)m#AFj8!k}Iz>cvdAz-f-!o5LmAHTM|?W}=g!`8_)UuYej6d!$x0 z$c9|o>T_u6koxvw--G*3BRW>n&}(Fj5^VMFR)~RT%h8BdcU|q8R;Eq0!*x171*0V$ zF^$=fpr}EIgz3I@FAAJ*e<$j{fh`o65bNmySEOzfovf@bDqIPa*vpI?Kv`r9-1M!f%* z583xzs7ZIfZpc2LD-i3QVfNg808(B-GrA+AUmmRQ)ZXv)>>tE5A7C~JO86qCq3y?* zlLr+hk{K?}r+n(y9C6&>)!nh1fXq8pmm=PVoF?G#@gCiGmt%PvR`=N$SnLC;lu-I!U>gACpz6?rGF`5A2;)I0W+LPa~QiLZq^m@ zKVb!VriLK0y{8riupqYjnp^wgI!%u%)1xpXwq+XkT_8)-qv4~&zGit|dC-d_m$iL> z?1;mi;xP|$iO$oAS`)j56dDrsB ze0%+vuYp1E^^X2#J^gm@{>$PI2140w$<@wyv>P>3?0s1v<$kpe&4+FHvvu^5+tzy`6C|aU zjujvxy;-8=Vt2TmgkXZRyg}NScX=)$v6RcRQ*J8VoFdwV*`HVfh|eoU%Ezf)tmks% z%5JB1K7N=eUIxU~y_H<)L9~e%?RPdrqADPD+C&qunYrVz@frspvE)%Tt|MO{4^Se6 zd0Ey2WT8E{QmQ1r5iAGrI`*zaXu}ibqdqG38hjC3!3c1tdbm~<-1c435r|dSk_r;8 zDb?YJg4wk+Tn+(7(74u2`bG=z~{oi(pUcI8f z)`IPuIXnK_sp0;AVJ*-{^<4-AwV?i?7T9O7(!9J4FQfGz>H+$jdhqrdL|sj*AA;)t zzUlg7J%9n$cl+~?p~he9fsBD>=@mFuMqkf3Kh=a4JEE}F{I0P4S`#Rqj*))c`H!@? zqv=}m*3YZxoWgvf(*32@_dzG}V>9t5ggi{siY8l3@;ALR;x>9!!@XO0u*WLYtGShY z2T`wDJcJZjh;uXXnyWIH+s z4WgQl!Gv{m`v9ywc3WRalX3maEEQ}8!>!4c*24uoqBiJ{=|fMJaOiie177ggy>x)y z>T2{ti~(g|1f+yhGZZ|NU}&O>`VyVa$EdfS(lJJj=aEp{b#9$EwlT~P9;pPj8~h-o zzt;p86s@mb&)0F9MU`QHyJ5=?Qw7@R)`2;>s>RG!&n!&7i7Bk#3k)lfx!P zYqnwyYI^iX%)guj!lZ?XXHT`mE-C15fUt09PW$XmJu&UN=`_yFqGVrs+-N^B@cfU2 zOwjCo7oXW(z9ei2iQq!GuoOs7rA`GIt_@cFRODATxwW@<#o5jPwLQ3LW01^lIU^ZO z!=VEi_5Bt(QuoKyNPnygALhCb#x`IMp*AFOe|y~j*MAn~@z=Tl$6A3SzUi1G+wXzl z`@6}fz;{1wX5P$pIp@9(p>Jk8(fy{4{|4#+_ZjgyNzk|dKuh%%y!@62HpfzpF5=DyI}qs5%;&|uy1Cc zxA7~710H+^!3E%hbabVcZz;ClUW7RY3aU_i6R;YExI6toMY+BCF2I<;;p%ta#kXI~ zPqM8~Q^VU?>=knGMx*?l;qW6*^IvORSKL1K`oa*_T?BXxRwXDHoq378>A*_of-rI* zI;4K^IW3Wzxe$^RRe;A&l~#(K?qox8R6G5S=wY|4ICdbQgS%E$JKdaizNTGBat{Df z=OV-W?@-P)ba*r`yap$my<;FI2eR#R*E*ZjF$OD>IYbB>i93v7Y0J?N$keO`>!M1z z!CvyyElz<-8HE;izCLOf8Jv7c@WcjcqEWWG%4isiKCNl_X`5@IxZVYd+MZ};1+w>J zSqzOE5(Pw2M6^U1cXsGHy!D=9=_W}{r}wo*1n4<4Krx0D)p*^msoK1;q*z3k4mBXl zEZg$Ns$Fi%z6MDPjLKzt({AwvTQrn+@7Q5dmN&$M2oLdbs*IX45NSv24K*#S`j&Iq)#7L*;DVU>c1K4;%qg6M z5d1orWaDTLi|p+-v**OCCxv@0KE(KLQ!}Y8=BaAiVuQ3BT(s`S@kTeBdcK=1L{kU_ zVL!E|yU(qK5G;bNe%&O4A!8leme|!Hdu#k@XTziLZ9a#5#!~F z06m(J%B$Bo$dy9;)?(g^$?uUOFWTK(mhr8h|JR!d?)iJ%)ZZ$S7``e}@vS0R0!Sty zB!~lU_A4Ypd;Np^#lH0FWO4M@w1pMKEgaofbLl-F7~IDoUw|T_|G1s{<(dz-oBzRK z0vaXv;@(0`t*BEUd7v{GtifRR{WS=-nSMy4karHuJU$%B5I}r<3$S_{tbcT^09^IU zMet2uJ~BC6{^rv9JVU(9LR?R>UUJqrBIxThzKja!|iFqYNwi9dT^W<6_LFmtU6f4;n`hS#5GrIZKnE* zMN~X!=O5mwA7|k}o}Z;thPqJ?00a-zZsCBP@W#J=;Q9!89`D0pI7xsZ;9GnHC~My= zfIjbHMHvwU>T;7+3Ivw zm_U~Edspr236Yug^&Sm_=z;+&Ot$wbTs;xOlddx5W}86|D~1RVARUCBn%*?dvy8*D zcZYM7V|%433;bpk1ej#jdoZ;i(Fp<`=JRyZ?1dz4AV0;nM|y%oUAsdHF$_=Xq&^oW zfPDf4ukkf8r0AZdy~~+9nhUzVpeQ0MIVO291HK%s8W?K2FCw8j<|~hDo=77P(^;mq z>I!ZHS`cmmx}^z_D(sqg>mAyoOO&b)_K2-Zw~2mS<}=N!93!tgF;%)mF%}lUSD;2y zL8fNOnQ%j%iByzj=5=;*rNeTMgF7TbEUyi?^&Z9L1EUc*LWi+%*pY!{5>H3I!Y)!_ zmOalD+^W{@!Fb!55ql;!0w;%O@{e0}C4Ib$d_If@ze{reYkNlYUP7LH{%p^PTyFcn z<>g80AGeucp2oJ3&wfS>zlY}8?>RD`F*0BN|3@mr+jR3I-QnepeU}oiUP7IBanAP_ z-(Jgk;ipE?OX=+Ey!B~pFl^j=eonDotL_RicOm=nZJ_pQSRTJ#@Xg2o2h)GE@U1@W zsdzVr;UcmupX5pzt$mhZPGVjpr!!fckIdtI)z{ip>@%}=ju20%=CLoZ)!|sNJhb%g zP7YDSr*m_;D+SfrS>1}y>~P#^+&bNzPkn|Q`nuk3E4>sH(RJ@JOvGw+aF}+wLZ+`= zd%@llpSL5INce9^N>1hmMl?#ljDn}<6T2umv zz=c6777T!m!#twPJG3N8ckMyE4mtKn$>qj#s;F)_fVnZ^_Nm9^6w~bdx0WBX z1-d?s%yt_y-S)v|hjdRHrS2TgcDe&dni*&A>gnuTh0|Z@SrZj^iwP;I!Jyz@yIyvWC(*ZQO1!%pts)$Fy8uyM|ozYv+ zYGIbobTwOx(A6b)!Y>EOlWyt&*yJ|!pdk&ib;>-OiEMVM=4Q)DKEcK}dX`fwyRml9 z<4C|)RpXk&zChG1J{()0ydSJ{-#nqc7Vr~!=yAloUq@0p83B;@`12+_AN#q3wUVUj zsz&K^D^Z)tFhF{_3M6z1D0K&E5mgYR!8BpGMBhE?A_2We!mxNb?Y8o`-(BH`FM{6K z=I*gi&uQ+V#$-b6hKRhFdnC_lrH`L2Sgri1|~R=gZA*mC%nb*XTk`2co)SQv$#JyfcYX`##R z$!Q6tQ#hXXUM_AU_(fAYRY3qCvS&j4e(H{O3xRPVljU`)_sPzSRRX3Y2kVl&JtE4 zr=_2pfv!aIMDhN%i3mnFsCZ9Rg>O$=VTToB2M+%6CUcP5++-7h($d=OJSJVR1_t&J z0M4aJ$AV!1${Mvd?i{5?nOeurS*(D%7vCPu=Gr5{(^=a`_4+9+3>WCeaz9EzV0ZVn-TTpKwFU3- zQx$a2*aBpXj@-D0ac!t_?(S>4`7%?B})LsCowy0T_W9uBj?8j-Xx_zsfY00D&`73f5xt;S zY09qLVvwg~@7C?9*{=?ZU7qcJQf;)8xn?YDAAHR13>}VoD3GRz3^YE0d~YqqD7V<> zN3g%$e73~M4wOF8Zb)&M{oOWtA*?1WWUyS19__f!={wms*|C=Q+)gg)Fqy6uFU70+es?X3xO>hwL zy>?me%}rS8bkN|v+Bz@F@O$_%m`mPY{CI5yIqMHo?5~aAmkv*K&*cewXLhMl3BAaf zoVGcae9DvLuNTPP5C_n-yaWIAH8p#k_iz7{;H8?Yw+OH772yTTpcZ;wEac!Ty5u|b z>KYgRdFxMod`utba`yKqr=T+uCWX6oeW77O=(UBgrU}WRVf)q2yfKNTr2Nxkf@#Bx zWuRqL9qAew%?q!VDOl=B0zKCC9OZOhCSoRoe@Wt*R<|}mDLampA2I-*zh(!gv%@?> zV?E1q@Q4I+@g`~+Avbi8wCYIZSZKzeiWA4@`6z{#`AUEi?<#N7ioRrNb?%qb)6yO{ zKniU7rnyGDszo9?hNPz9rmBX8m@w$V)>S)PZe6*E51Uf(XR_Jh+nBJr`}M9g7PXb7 zeT2m#;#|*SvN^Aqeb<&(Bu$qc_#p62Z^hRR^sV(d_TnuvRzMiEt!z!P>P~cgmk9ZT zOI?EADkW91d>J}pj;tH8vGG>TePUi0_LKRratw4?NXDedFvUtE_TX;kn4u!V0MU)6dw&MO)( z>q`dhl_0OCO>h}@Ha7=bsS$(Dz7oRqqQgET9tC7RbU6s{WWSA6J6Xl?-Kz48Sr0&G zPCbbvd8$-y#lRdv0tj1FhgWWx)s}JaWS4bxHBpS}m}%;#=1E_`ES+B~c_aGS6<;-R z{5;QVBHUw=UA4~=VV5#d4)o64AdW(8Bzd=u}yv&?tS2)2mU_nEL8Yir2@ z%c{BObH94*w)Vw1iI-9YLFsL6Ie9w-E+e0-)9eDWAG(|_f-b`nh85{T92zm~;|VV| z_lOHIRnqbe>)aIP+-a++#ihq=@I)UGCo*uakcmQSlznR(!@QqvL-M#Y<@&P0sYtX= zp*E!jdY{?>V_c=UnMwgsqiB-k#U!t^8R$X=awn|nplEq)srV7V-VT7{&-8}4PZC-i z__l4uqK{@0fG94Pk^XhrvhcJKMUVE?W;EnbsqmF3Yku*t)4DlewMe#jvV;nnf{56O z9i$LxX!*_yvSjSW8a*fP*O_LZ_+FI@QRl1cUca%Dja=HUgdg()nAR#*S_MLr*?Z+q zqj|$X;9xzfnJ3W^!|aqz>pK@i95LbDq9cQ+Rxirr?!?`Ki>9-eor##V0^;w0UFp!F?veVT!@$;mwxF zJk^znw3R+6hJvpP>ahve$5Op@)Pmf`f7hM)TDSkp|FlDS@PXq5z~m$h-SdNV5rlDC`S!(mx=Q zPnOqEHnGhLvTv`3F*br(4CAO&YGEbNmJq1&c>oFu!y9^(%$KpLugJb(4>Xy;LE_v5 zz-;$XpCd+(>Dy%$0!Ajhv615=dLf)f30#>DYN)Jng%b z3RsZq7?!;h=2`uGdCSl61(&lV(J% zr^jHtNpE|;ixy24*t(CN&bhs|UZ1sXNOz_G)Czp%o9J4(n7s&Lp2d=r4lICRDznNp zT$@CIvyxhXo6_s2y-_`hdzLD>bXb+fIhuK=8>;F%8%Ecz(wZwAg)zOeA!Z~hLCZ0L zqeeI^J0BRNw7)^0H+w)HC+C3>Ya=%pkPh+(pO^dU2fJkcAToi6-#m*|coZe*s1sFk7+_7$4W0GPp|wy&IA1jfJn)h;Rv%-L!EQ z2xZSKZTV$%`t9Q1TnjG#S2im1HgW)w1rV{r@E@iCusv2z{B$!HJmrQ{i98mX9y`G^ zG$h;jyPn&L=NNLk{o`f5K*~q4JdSLi@CjO6sQcxCbk*8Rv!?X6Gm>Dkw3VJf!OqFf zNTM7uMvETt9Og#MVr(s_(!<2tF#$2$E7I90i)Pi-OiN7`j_DSH$7YB+cXB|90do}H zv1+s)OsCPYOHGJ&*2)=mF@`OpweGmn5%{WU;{$zkRh?=nd#@2K#IFmYzE z$Aw^-ob4yl8RF2vT-sfmPw)d=CSnNz1XHVZ3W5UM-nTsd+HovvrnXJ9z6N!+3fJ~o zCkqgTDh=MBz+dKpYcXl}xSn5S$Tt$fu%_lr6-kd>RYjP(4(vUBz}(wZ3t7$BK1!y3 zN?dN{s;-y{8w=)e9bp(8bq10Gh7eHV`XxN8+JY*q=50DmJEqxfon31PRWnLL$N9LM zHtOBl?Yx6-nHPxjhq8s>G3%u5om>07Q^wJaT*kd0 z4qh<^01n(~hvPmjt`5NR49|mJ2N!Tob~ z?Dg&Vr?E0ur7b9*{@3AN0=?;vdZ@oKUS2ZUuYdiuRaw7k{o~tA=AUYP{+n9=BjU;O zu~*Dc9)e!{1hcXe@a;aTEI@wWMIA7kS-o5ENb%Kq?b8>P> zB`uYcjm~>ZK7g*hPBo8Dxno;a`$uj(e15Jl-Y4)K5)g0(z0?g-k>s)x=RLcfH+LS6 z?qPnH0U%HBY%3?SMKPV_kY#xl0YJ%hI{(n<@`V8!YZBAnP!ixVSCdXt9TrUc3Z9iz;-!a;7mX4fCBqC7bbS^s;mO*R-Alj zh>ToUAOra&N3&7qZNT$IEA%a+`(>`!r&|5mTVL-p0oo^ULIV3qj%h=m;UaMc2jVe1P$y z5p-#!u<0AEkRezX1-s=1jy6yB@!ZguHuKT#cA8trZ`-5g(_0U-dTQ+3!b8)5r@;oN z@Noc~16@6Er+r>;=V?N5bzGN8sKge$X`c?gPyWW5m{!i&(ouSuE?wf67IP^W%HdRvXypb zu4l+1!soT1>!+;|#&Cd+E_UDP_Jvqn9j1bvp|);Zk;gM&meE7CISFTi&6$B`m3G6B z1`hNUKWPnqjpP2I`3h^W`o0E#HeYqv?%70bx~RoI=E+Kcyw`O` zzhSotYmS~voTqGo{beY}9Y*%XDBvi~Gi-WaUAE9l@ef&$>RVCDfgE9ps_7tN-W?HY zFv#TODI2?2hr@&u%r(;1%2Q5mS|4pQ?<{3y-X#@XH? zQm$Ao;%>{q4PA$Z%F1W|^pNn~bTv1-?lJa96a&7enT;*MJS2>X4|I7wtQzfDD*V*h z(G7eAQjY?MGPj|76I4XztXck{-uE^i@+XhvPsI}lBT}*B*RouY17#HwZ1L{4b3w_S zu>wvRckt9%Tpy(FUW-h*NrQzs6X{`AXyK~ebn$c}dC-+4_1(iJ>U@3nv_crRibHnG z69w$SaAjdqjIJ_1CCfd-n`sNCx+U|KBpAFryQz^90ZT!W&Y|9O*kxNZg|>?&UdoLa zeJ%%E^XZGaLo|^n=}mCI+*h>b4I!f%fI72sW7qjN=`i1J`EqOPGC8XY6+O3+TF&}O zfrA;$uEuIIb{INHkYdTPKJCXe!)}!32D?ouC`DR`qci!`_Qc^t*;R&SHGZheTw6Oh z95FmEsQ|sWHx?y=L(~RFWjjOM-3Cd&@^@8#cvEk80lm@y=0QB}N#Z@>lTX$JCSn7Z zl)J%a`U}Z$?SWYDDJV^eUGB*I#HZSzJ^;~U!{MO<9j2f^gi8yAP=F?q6p`qUmfd1F zxxL>1y7E)=^~=S-T>De=bp=3e{!h)<2=A1^ zW97qKLw31YDR>__5Mw@^(qflX_sQhlGV2RwBZn&oqikfa1?hY)$05+D5!H7=e#DHY^VpwZlb2b-$O$C^}mV<1y3*7t) z9T);)?K^E=;&T^d%$*>znGuZHzBjprO)inpE;g9cdU9=!@62{BXj~v&4&0#Icho_U z=rOOBEmpYJrUm&wei-yr%@?80PiG}v-@$FP>^eTuLr=d$mLfqr`XW>gLfJihD2}kZ z%&-ju95L~j{p_%cdYuz<{pf=zmvS_#*_+BqJ@n@_y}#V)sfnKsc~S6jzir?#y`z*^ zYdg(N@$06XA6hiyGPn~hiZiY&%y^VWmq279eyuU(sdM#?jidTHCcQ01cz%POWc~~k zZO`1nhq~zD25sHoP$6s!vrabHMbTbHwfqWO8fm$_bnkwCa-Z`$x*zgrXcdpjc6&9J zPZ%gma)=c?K|}`^9k2j&n}l!2^EHDhgDy!IG|4T_9K;J`aFfkBY5+!GZxM-kJOh}s zTqy%~NVW~Tw=#m@3p~+i?L@~%@g`K4BXU4NzIv&U{06Z)dTn|#vRR&kxk>_r4X#xt zqJs^;828D=qa89;5o-q+bw>fO5kgSj_pQxxyke&>9O8lH1808v1O^qnX@;*3U- zMnORkKK;8env9IftgOACecpWrbw#BaX{Z7J)!plNM}Hmp`T|8<@>aYdKZXCdKl~{P z5b8Nd0VHs~f!Iv7#8tR(Z5-ozzJQoJ6741t9rO9YYq z&oBSqzIx=}y!?Or>cQG$E=qsA{68sHeh60h-e<@F(35B4!b6>Q+8`3sD&~rp+;yIG zoq)$UW?s_bOsq9^FWlOlYbpwH+W`6VzCHPBdr&yGT!~c!%OZj~w1DLmLA!71>lke0 ze4U29+qi^hl`FK?TUkCgRNLGsCK zleJz>G}=taR0evh13wIZGC)B9o?V!hU`jyuOM^jaCe#BUo*$mL9a|?3IM4EBPf+A( zcW8#q;H_mZ6fX`-;4%kd1}mbaQa2Ja8BkP+4>yBl5B`YLuxkJ-V7Dt4=Ow! z76BiZ_a+$o?I``@DJsnEtkdV{YSy)9zpAyt@#dSvm@|wY3Su4hDl|WyO`Z3452Vo9 z>Wxz6^&^JnkXS&O4jt=w$_CHd=!T&D#aDP6r!kD$*Q+WyQ)+*1nMb28y1{HbGHa9fL%`JSK=hn z&fz5Tp~;Kb&`3!=)#!@$_C)+xRr{!U>|(ksVRmCv+(==!OF&^dn5|>E01ZC>EIk;s zy4;*NJdwUjTQ~4>YD_)y`2r{$nCfLLbg+0zjLsJ9+lz-Ht8+rVD-Z0}fB=Fvk*zcN zUDu=xo`E}`Lr_fBPc5M?Zf#67A+7iyt_;TPxAEC+dNWk`SgU^9K1I%DF28Ng|L~l7 zsLLIVCf=jP9%3jX_k1t3B_L51K9jHSS=;9x68^0 z>!a;G&)t?ghi&qwqo;<=?)op-yn-#ScS6yH0_a>ihz%|?^FnNrbK4MR*O3hLQNYz1;Ai-XftCfW?bHQQ!v*$=OMr=k zMDCRl>L5H9Vq(!B&gNZCw}REl8O#g9%W|>v>*4qX05EsoL0kKjC-(4maAt;Brm*cS0eMc%+&}^! z(sP9*OL&WgINLP61b!T_|2+`%0b6r~R~s4Jo1G{Rw)7UkbTI*^^StN(#bQl$-)4{V z91)tm5(gVevwH=W}a&&aN+GH5;OI zaPFwgp*xb@P-_scdMfN10PqC->7<0;Y#nFeh3k=sFJ~Fy7v^omhjQ3FNB41mN)e6w zTJ7-dmTHS_w(4%0e=_pGG>=OI>$6pq7n*HeiDJBHoP6d_N_xkNN$^@EU#ye^cz_LJ zKHM~g3=a&UN_<@=>7_e%z;)jSYqgFhk_{Y$V5 z3m41;a{=iRWviP3WwCIu@4L&9Q8KDX)+XU?@(VlOH{dM6LZ)#gD{bv8=eERFCi8{8 z-dB36kR?|rNZ5>MwoWd`iPE*?1TwhgWgBFcsu3o!rJVsR%>`$ZU6HULXwdzlFKk`Z!BI5 zu&pnj@l;`{&B)A;&knn<3-#SW7Fzw%&)1{>;}%2SJu`p19l}fTn(g_RGSL$44)n8h z*a-sn^AxgyFNVp5a|C}geVREZW7{;XkK1zHQ zUH>ggoW2>D{V7VoWcUoWI{$f;n7wGDi7;1-AyvRe z3&VB|X%E$(RIii31q4%XxV(by`X1Q9jbJPtrLpPF!Aft}{k{cR+kNvaJ)B<`)Yxv@ zET;t?qRFb=c;%zpL zl?Y^0Sn+9Mz&(Lh_x!$9Y;JQmH#TgRT@4n%rsXI!*DI@q`1-#TDUd9DnUI2Mv`raG zHtZ;ttYIN{8~plk2NA*Rpx=C4N^f=HjLj;LIdg+sXH4M_hrRI#ms)FpP;5)Fi!+4V zRI!I$zV7G8Apk%(jVa^t&8Pk2miq`l$oKg35q^GYMLb`NYQn{ik)En{e@djY(V`}a z?et2jF33t-)i;TDJIun#TTQl25)^h5DUbt6a%fgL6YHxt16BYn>o}F?JErdI;ri%L^vOV_HHEo*7;mHd zr8wTjqXfby#g5HR&2%u{6^<*wMr;saFEX@hOmQbYjC0&xj3mex;H0Uyl0OnIL)Grc zsP5{XJa+5F-QyB15~zh%ogUqTCzf#ukdcZhD04s>J};%jkr@8uMKo6JcXq{I4_*iK z_(Sfxa-gW*S*Y^q7(JpZsl-q@9<(!nD7h(;PC^W7A7Bjg&jt9n*-MUArWSMlxikD8 zGG2?*z`Xl+CB10#Wg)Bb%bxuG_rI{zn6UIw&N7LtDjT~=wLJ^$57<(lDCaJ>4wCoRl8afo^s1zN zbS~BBCwmn?dJ^1$+318<-BGlA{5e<)J=OgE&h4lV#>Gkjgq?tGmG{5fy6r66(oW#Bi2+T+%7V`ZyGSAdq#>f4&z!;P({ z?q#4G=f;ImknHZwl0X^?Gf73rY>p`o_rLG%QauSoHv zZ`)7|hZ`veg8x*Vf=jSUh|zs4uu#_}?!&bF1xzF+&7%C2honECSita|&lm2Z_LyZV9`og20uULiKR>T?6iYs-fX^OcvRB!z_}ee!U% zx_M55vE5iC*OXJQuJIr$^m@2w=PoF~+{E&gG-x6<-W9UJ>=0%o_Z@j2_H7{^H(dU9 z#{YT|-Fno1l;&^#Ilo%L{8NCCaA<>boBSg{h`am2%6~QO5V-F_f_Gi7HX7Z<6V;dNhHN1tar3=@;@3eH~%IFX|(J`DbIb+h{V#Q)|AjvxJXmz`#;+&opB zVAb~(B%mP${io#fvA+iiFk`XHL3%sBbpR&;k(CL;z;2*~=YBfm-_Lk}6F*;u4&ToA zc@&yidmsO#=)t=7=B?c(AmZqMJ~KS=zk7n;1c_e~wtGTeRQ`_gv58t=lFjaXKY@8< zS;em18w+Z}!luesC2TsBJ2Q#S=`(~2v_v#q-{Tr8062a&YKvLj2a+Qzrn?Qd5N`Jc zh11+KlZu`Y?z`qf*jXH@_l5twg^zyUrNv@Rq?8vG9gI2GieJ!+YA4)$Tv+(ql0F^% zrSTzYZm3Q&6ZB{B&LuCipANfWy!2OvNNLt92H17CC-8o+5x`L z@&MA5JTeKDz|?mI=pJR6X5wK~a3KK79zaztVjkB|*m_y*wwDoY(k71|Wb!=q0jRK8 zC)w3)<2_@Es_ey6DeETB;DadlT*Fnzc#5|Jr2}<@Om;iX>CLkUSbXd886;HRn>)AV zYCudYRP`a`plt)Kby0-t>@`N`dGOnr`$7}Topb4R6erW%LV~W(k_9JM5c<6Cnr(l$ z9H#kFK@M;Iq+do4pl|c6{W8r>RTfy*HaJUWFvp+S>N7EJei5vU1}qEs7=@mBuRx{D z?p!uEITJwZKtc4paZgFBK*Mr|tfx|C5K$|34L#3)ye3~I$_qp(OAo+!4I!A{z}IuK z+%Dq42Qs5ngoHn&@b|Ma0GubXR6bX)Cl6LxxaS7=p+y*IExb(*y3^9*AWI`493k)0 zI=B28A@=q;=*DaPP+8GI#HfRz2X~Vxg!Rx0=(js0Q z&hSLDN$9tZHP_FtEDGr=9v0(Y4f*f*uiv&Q^Um_R6OCVhG$p4_dAh1$!BjN@sL65} zr2TGx7jM;ySyee$hVkK9R%#jDHZn`^P&~D2k;c}%b?W2Ij&V+FnrGbGbxX6;0*@bI zaD6-~WCN;7KTj>4(5b#`6I1dN%f`#TRsr+3gu{)bq)Tx+c?&yH&U?iLZ(j@0&OmbD zGavX8KpRr_z-c6&NT#kd|9(kiuz24m%Kq35_Hio&`$S$YB7D4929>u@PlLb%icnXr zWXisb=Lbo{eEg}wBA$s~&HE(qIYK^~gIb?f73S@*`UeBi@43S-*FgW6 zKXmh1M4})01J7CIuhy~t#!RqE{3k#lBK~xv!d3{pS>T_4nFN83sQPjsi(hv}Z zM=1Y5LnJH6euhw+G>|R|)_%+s_02^7r9>zOA5*@?O*ZnEC^wF#s*)B%}VZ! zGX<`nXaV~ENa;yb0Z=%y*B}IsHI+j5!%!AypHnt82p!2z&riL7kDoa}2HFlgmMA?y zN%Rz&rJ>0Zc22R#jWCkb0`LJh(6B_RKEWPUdsjdfIdq3BcIz&l+I70j-f1SyhV{|y zRh%eKTMXT{wzzhZbQyE^d%{PxMBThVSY`Xm1FZRwN;sO1A{FXm0OrBb&&&Q)tPc_Y z2!_>yIYv+UE|?dI!rcbAhSU0SMfX~6F#BB}(Kb4zcEaYJu>+?uq=NQ~RiE~YcxPF3 z+KQM08)LDEswIZ+_lvUK*^BU|;+oJd<>fI?v?@778^JP}>xPM?+vpJJ9X;;H4xuP) zDYbn(Io=&Kqx7Z0axWPuZ+NO?MloY-!+Ol-BHBACxxhuVW5sRWX0o-ZQ$0C#uu6L9 zxdj*oUXj5f&!L)6W+&H}ZbnKB{>si4BvLjJ9~T^9$fJ5cxXO0DP|^_!;rdDP%LRGd z$Iz_6$WYkx#4f|8-5C++x|Qtxt)fk*z6a_@o=+^ z?5Lmd7_>&Dr_^I&)927S(oe}L#}VPSI{eo5j36mHPp(ztbg_wSG!GJ_6w_^^3e2Mj z5@y%M=*fSmqfgV5tR(rgUE;VkZmlZkG&O+teuQlBMDIqWKzD5#e5O9~0I>};q`#h^ zeYi?}no7M(t={Ws0C33q+7SmRzFd#)1cF^#unQ}D(ZoIG_R1VDXE(u&`~CMK5hZDj znEdg0`8THv^4sGDHno3qu7Q&vh%kkfE|tWIs{r{4N*9n!^~eDYT{|>I=nqW;AA-!? zR}Rv0)hXc0aq|Rdef#>NO@Xs|Y zhB0Ar1O;t~1=PX7NLp-{(>*}cdP>flHiuryiZnu!vK-Ykb`-VnsW{{hn(4Rfsb5tz z?*RytfmiWNiEO(Ktm3{o`?Y1-uBRTB=6QhxepH|lm@=I5UbvTbt&Gd)f#dilyo5y- zorh^fnfL=IIgEp8gOVQ5y&4FYm|gJ#*6jOo!J)1eUdTOiqEf3m9jQ_4FU3veo+)fk z0h@CTOWUjX!tW&_8_;X$Z16*U7QxMw8qephHp^@&*ZFdPI2^CWsn-ZqMOKXnJ;u#b zO$iDV&wRC%Id77iD|TSQJ2S4LovS3Hu2s+`+X}nIK(Ij4Up4McaaBTZQeUnxwG}s) zHRAKI_U&_xMbdctU^;X+MeF14Ni(QjEUX(p?m6vz6}>Yn9nye@3ZFL;{PACDEBy5< zcJZH51NjOIjU2d)z3Y^DF8SrA_8;%v|133_zNZGSbl}wq_>mg8EU^{r=>Ox?!1%AE z27=+^Dip^P3^GjDJ<=$h98cC%>4(^?r8>ijVR0z;u36qQ(b93=ndCb(gY9UWWr%RD zxz)L$fq<04;AUw88*(~!=i3^rLC@&2qlsmKO-usZuo~6}*a)oWm&!#LD*~gX;OKdG zg(N9|mluc*{;O?}@=&fDtt~n5%Mz&2iF6@I+ z^red;dbjN$xwslSoKI~p-Q{B>v~o<5%oQt+v@tYDLxOh3GkO}6P8ygEyQlLp?oJ0u zULC+({kmH@TDi7e-`<_Q{TT?lg;qmS|EM%RBUc`6`A$$(K|`K^c;v2iJuMQK6n7#$ z9jnMa<>UngMBS9{&_x!lAwARF(To+kNxaqo(4VwX*9Q4W30?#;+%3(8E?~tyVrXU~ z*L{`{<{@fy&+#Z&o`80wZsdkJXmpU}2^Fb=wg+gZVHITkZF13Kq3@>?7D*!}19-pvCi!RSdhzH&EZ&rOQOr z$;;52TpA1dAty;SArE0qUmbr#^e}qW+s_65d!GWr?-l5J zdwT(6ncw#&z7`)}3ybkh5C%2CyygHJG>5Zb3%LPLgKYEummh!kT0@t(F$~}bf?^B= zaroRtho;B_eA$Q1dw&RdHHe_cp#GQ;e`_&pudxgclEIrK2((5+@(UXta0d{O&mP1~ zCV+InnrNB^7cip<7yIpFHNwv|4z7NObVzo|-JQ5Fw|XC?+m2lEcMvR$;7rG& z1xcMNJj{4+9M!CEoNEvVd~~M{$NjBA)@5CKeTrjovm`V=fYA0p?Kr$>C02W}z(kXYh zI>4LBh0Z;q9>XIG$N(wU(gh)}A}0e2H2awFb)u%Zxr*^37#FyuZ4TkH+$PMTL3&wJ z`W*+3>zn%t;Hon4KJ7L*t8I63Td^)d+4$(Zo4#r7{CRXQT9sAOP)v*Z3W&`O)EDmd zxuPRCz9Y8-c~)lmWexf9)k2R$SrVDFwAU6rxsGu;?e&%8pAA|&$f)*MOzFPMhz4*< z|G511X$CRxe?6`r_C+>`hJQ7;`Jo*CH)DPwc=e$5k5mgPl3!UCan`qcTK5DoG`R3J z!GU|)L_FLVTpUnGind6W)*}X2Xv0Yc?QLfa#vJ5V4~JPT+@%5eIvd~4zZrI6!-4}$ z=HIx&#;|jNvmscsmjn5>+4b$Q;{Wz5`!8&5fqH|)Z~|znPw)bLj%sL2d$d`(%3woO~WY7GCj$YT*&DaW*4yK z%^ozW)CAZo=<$bv2xjA7gg&Hr7=0|o)iE0P<>fNvd-?{sw0r@d&@-c*xA$kKEuy23 z((E9`3}|&qBBXhhIc{&J8EWwF5K>`R%qFBd4Tp`*gHTiQ+VQK=<&EJyNFh^Fs3M<( z0~lyq{!)c?q?_+SEy&czRmn0yVuBXD&R&I6iU``Fyru&j6wYQzC`ajFJ5t0kUJIfh zUeTU+r5o2fKirDuTJHvQi*4LJ@Ot{&oro8hZ|W7bhodz;5QxT~r;n{Ib7Gl~Df_!a zX_nxZL$n>GfB*#JnDtP;G6p>;j_`Lky5ITv{I=yBiF|Y0^rgE1_~H;OBzl{PDA0f_ z;7s7@_J;Kj^g{qw_)&GxGvD6Of8g%Fn7Fox_bqf zjO)zy-WR^RMkD0H*Ouj0&U3pwz&yJz2l>(Fv>u7TSG$Zu3p**(@ftaX<&Wr<`Y%r8egSLfttX1-r(Cpj!8oHrfAHZVdbVov#I47|g-+F`7#KKV!+xUT$G8V|q_kNw{RQTle^{Gv>MN}7 z|HW5P+x|uTW^?P~==)QBDS+q^a)r;)H3v4#fB%&WEcxxwlO0zy=S?pbtYYENlM!zo zH0`zXm!U5-csVyFNZ9ohGmCh_bjtvR&?hK(-q?b6GYcM2CH}tH@OljS@*o_1KZAnp zvV01!;rgs9s$H&v^b{z>;g>-=WKGt`3j*6s&@jMat&zWjf&awXe;!Fxz%DVkFg81v};G!ZsDUrrzb8BW#YBjKg2DZRhUl_ePnc(bZ3FavOd}8 zV(nYB)+~sC1ffNbKGq`LF5Qa{-ib1DLQ~B$3W<$1FSvxMd74Pd9rSB0uM(5x09RW0 z%A~@kjiqFK04wF*1az@}cc-tG?&EO;h(jRo3TqSTb`t+w6$_Kh>xQnAl>({_C{#0_ zqxN!#+ZhEHMIjWo^J9Gt$2dOdfJ;cNS5lfr?q1aLoRU`pUPLYN{ruf&{MfBwm(f%BE4@oRQs;xs#)`;IdOF-YpnlaeNXg zk*U>0e>=oN(6kqT1|P92^sIEsEve%K8Ev(l4))=Bq(#U!C>q}<&Jz*4N#9Y~<7(Rx zw-1)|HZ4~7deOlLTONz(dH{st-3#xq#0AR)xWTCLklL7B+;%)wk8#(pU4S4H?nXht z=6JYo8RMUNUk)@2y1&5X^RF$KLjbAwnjWuzII7-{tUsPuk2y`deWqzZd(4CUS5=U} z`QJ{hohyj25%(sEnZ-6hm$A>`-pURy?IKytU*p#(-G3NPIB4%G6Y;rlVZ?q055w}c zLUr-stJcDDSb2bXJn|u^`LUD=0!lZ5(+hUAglg8zfb;zPSU8_(;6{Ir4C(t2jfAaO z5J4z!KNUnX{y+WHr&h4Du;jHFtN2hT!-AJ8zt+}vhXB4_p0gSgs^|Pu7xS;Ya6YVX zK>oY%z%M8llECT5t?!{5 z{-|1Vzg%wdJUs3B=RhyOnw{`)!bFPA5T?aZx*iMNNluPSW-cG8s9NXAiHS#14j|=P zhYR~upvInAHAGG?fRVaC<^n1XpcrGxY0KDh62X#}Qs)$Z^t5xmmDCe3Il1+Plh%cD zzqwMa#~o!IXj$H)pzIe(c8QKlzfQ=|z593J+mfgM}@>aOzF0fW@F6O5^GPE{#u7r}^C@eGWVvrZ6}xaxf`F2;z>a z*lkUU1%4R2n`pCV=L7$_lEGbG-WlxcqD;lX`dpuK-=vKhC&Kz&!HHaE`-tK|Pe&Mr z-8ZSl=DX5D?wWWx+jyRvd9?eV(%%NlNDtS6omn>!;d(D?rc>eRo|)h*FtFd*#2{|=lN!*O6R=$RrV4PLls%iAsK>J5jYkd?{H5CK zFmGZ?6C9@2!>OXGqr{w=c%1;9*)@uj?Yi2OEl1=kTPiN}f}R8;ePG2Q7Ml`UZ1Gxd z5)l4k6&^_AU`NLk#o9pNq1U_QRSGuR8+EFJP(E7uND{kKYa_XKB2Jsd=E1YUVF@kZ0BB|qKU6;h z5Q4t^AOwEW%SQ3-G@V@(ZP6M(X)P7Jf)8Qg9}iGaih+bI(?PflrevEl+iQv+KC%5J z;x~fG9@9;#UcJa*@0(1MutBzW*X?S1-zUc%8d}42u4%OIcR7I<2;lf0hX&OeaD28Z z?uwp)chb8Smqysw9d@LA&SEjTDbk`?Sw~s8cx(gCQb`i6AE8|Dt~k)UuJ&C7fc1;7xWXhPeHa9ss|Ne!+2%EF3#K7oK+0jn=in5yXa_0!w`TXx|X8S7dR*yf53d8 zL;KSOJ72HJfB%C00R@73M6?!~0W#WOI^@1pLaqq>3gfw5d^qHaFB_FPjevcOB^cyx z-cn*PiUeIeY%_#^Lu1CW#XT`Xila#-8q(rbke|5E;3ly@+YLcimxU;M4v2Q#-j0aJ z<`Td0*8c4b``~|%M!$E_^&VhU`jd+;!aFzFQRAgx!7t$lYjbCFK zx0nf8`hCs!%wrvQU;t08Op*5)JZDN9U28$>0@K;3@xp^f!)jtKu%viQ!Ut7HXQsG& z2p>;)FM|<U6%(t>el?5AABZ62|CEb+ z?)EQ%by>c?H-9-Y|BtcY-!w|a{hWd0(MLS6?9B>v`z)Baf*KI4vbh@!3xC;1fb97T zrvUlD1oIQCy`8+7%T~T;*vTNhHA@w7AZN@14$Ogb1WH(o0OMQtM;bq8@jfVH5moYC z+t)m=@?9S=tALVO0-ND(fIdcfJNKdUdj4GE0NeQG<_fbfklrTnHGM6jgP;zm2`{ZF z++!e?^F23bJ5{tfUj(qjQX60-rC4thaT1*9fzoY(4Bmq-hV)AFKOdX_ZsH<{2eSL^ zn3<7bpY}&QH`9`>rv#gPZy!VA3Ki^1DHd!1NOzc*2{3#kzt;v{Bzu|fZzZp?9r)_0 zB3Y$M3dvpj{NOThZ0pKDR^(qZvULB_@Q%=c*y67ZNcRT-W1cwqFr8I-JhMf~vtT zxKW$kGp^+u2LtjeE=!<-9TZ{o27%pIJm2_-e%n|2N_1oZcJ3Bs`T!N%=D-{;PZn4o zXBq%v*p{4PFzWH!wlH!j*bkcxivV+FG{^E*?fYa_C2y(=4cq-#wJ>c?q;m-a_Lv} zvZrXr=%@W^0S1~n3%dD+8Dzo8(zTP{KSQ5n99=K7V{w}!Zw?hq}leb9z7RW8`D^m*jIjFGL?EzGd zbzAodI9zk92HS0xi$mdA8=zU=(K}@0(C=X^v{aIN14Dt_Ky&}9)x)VnWYBY9%80_T z5iN^a_t`A46aCPJC+O*c!pSn5r$~iu@i3&jv8&lJ^t6Y2+q2rpk43?(d2+`+cfE`w z>Qc{cnQ~f^8IWB0%y1%zKCnT_9~LM~xD<6cO+I^pLErV#VZPw`iXOBrc?AHNQ!z%j z)V9UQ+>1RlZ4RsSL9&3LOLqnEBn3j76kojnv?Fv*_>gMg-07%2VenfTjPu}xHXAcg z7e%U$S?ZsHisy*7l;7L#FD1ICLv;UO>3_$FeKey#zW%Y`Nav>XV*Fcx(SS6KPa#0l zJstZ^fT_M5tpEQEFv`THp8-aC1(<~oGegI|R3pp_J7?bGP{1(c;=OD|cigV7(zxTHgXSjcQ>)+># zuN!}M00Ip-_a*`V@G<3|%-UF)G_)wzYZ3<2aPSi+yl28SdOYdqu+4q2o_BLlA)GRG zU#ZA&@4%Tt4;1%#OFC~Y$_ceQ;&<=^x=^I28I;{tv{FAG6PNBUKnbR{H-@`mae4FY z#PT=BVXfVXbu6VwcLO&n6jp(VN1mH4yTn$Ju}=&zr-8{3;86xq*~zrf_)y`C0jQb< zuqy&0B{nbaDhEvC+)*ZQI0dj@IbFtb zYiB5w1ts3fmEE68c?$CGP>yT!_B{92O%>YWgqTNi&4K4SEOXw=G=4l$yoTN2?Riy! z7YJ42+$zYQAaE-!;Y93O(pYF$BXB?jHrC!b{+KUjaXBCv_`m+#dxzED-$<8dUCpPg zMwiC@2nIYFEdBeqvSk7ZshY(GZ?_UuM(@R$#Tc-Xwu{(hEd($y`P?0PaeY3Lmd~8U zVSF%$>*fRq@k)TBf<|fMo#D2zm#|L-@^hdI!Gilo(9sLF{uXq8teOqpr$7qf21EY( zjj(g}_nFu`xYB->=JM*wmjlonbiCeQgB>+4u5?M#I+GX(hQ-Hm5#;)pM#)!~N0uWwXRyhxwIirzzZJh&9Xka`&FL+;9X$)b zc?XI^Q!v52vS63Pj#rMNVPJH=-2UL6%11x|KIQidj6%=RB?bf4zv|Opepo^8vLvCFpo%&h~*hjzP#K`E)neL0S?%;Ah&lsfD5`A zFe`!RTx3hbF$VQhE7E+XT(61+*a~5=$mf%Fih}g9nOSX)Lt@~veJtfBW;4J~S7 z^?+LIiWo4gRX>L?l@Q5N7tWruZ@Y{y?F@Vr1=L8d2HmSd`CD&Nlvuc5p+dpgS96Yi zYtD7k!6zfYBML%B)RkABCiS`4tTqebK+_T|N`kwQ-NldVUcz)))l9JZNNU)EuRP=_ zNdTT}0MwSPvv{)sMem_>49sDrA&p8&zu~9kWNN;Er`)As&AVZok0h+OUHPzeR$I`~ z?Jdy&J)weZqgxCujqFe?H(GW}EM39(ha5|yN5#t7jSjbzKmn5|weohw4<`GJyrAp? zE;s4J<+zSu&-Vy?KB@>1fklTvD&hhBs;|w%_5oXjHx?}97TS2yE8^xEDwY&NGmO4Z zKCh}Jd50P{oDMs^u%l($uv;QAd|vXAl&N+2&Nf!;-sIshd|AL|d@WL4gR-vp}s4=JtT*o%?S9%N99ouv7!!AM9xj9nt~b$}3Qu zxY=+JuDhB?vrQP@zY`ojfAd5I?wDi`*ICkkxn{DKk<)B`RJ1^cmOBg%Zh%ML5cs0eSxdev1d#DVK8nAoDI!Y!29Pas3S zUysX|W{aI)5b&+%d+*0pZ1AuBelVP{zygut6o53%H}QNA&x4p$8Egfh(LO89~Dj5HQV&$Y^bZHt9Zo#I+(=4EEav z0F$if(#Xox-Dmhwu-28(R+Uq#lIq*70F4s9oBA2) z{!BW0zCs=GQF#3>)G^<>S^sxK-8UD}XCGc({^Osw)O?ZuOvZngO1dG0Iza^ATOi|4 z^Kc$CmGI!}v4Z>K+xi~Bk^dxue+%FlaMa%@tPsJ$s`a1W7Tk+}18sknMiy{l;Tu#i zM}@PC&l4Tk(YXEyo+pI>kiDduYj=G)chI%SyW`OW2g$PTGQYp!Mvkg(BxStmEP0R0 z9EZ`6MQ4K3RSKjoxPNv72F_B;NscxbNv(Nnb9y=`+>N(=N@K01;Z<^bEX+v{QTn(9 zA+kuifr9#bs(!9_Gf=x;2A7QRRO{IT!_?SV))I^Rodc%EjelgDXI5K7R35|6YSALs`wend1wa*XioD6HFvg!5SQ^`1(v zC(9ir>pa}GO#uH7VY)NAtlgl`yY_^6?rl#d$hzWTOCC&-@w3$&F=ymz7rk>>8>&f4 z)aITUHdToA){?&1R#}0@UZ|lK_2zbkHw@yN^O!rw62ReR1FT^{xPxLKa z^qkDNvBNnhzZ}&s7~M}7@hi83lNta6?@?wB4%e3z-W%2Krvbe!T!rY=YO4XX~*UxC{C5&}Ph5(1m5@msY9TTSz9PGV(#oWUOefDe-g51%I( zlYq1B&zy;$N<{_G62A(5&qC{Ly6^GADiTz1&yjD`NP zvI5^UdZ57^?3=P(osw;f9w(LGZb0L#%lZijFa?HrgpThQ4ld#@6C%Kq;({jSCPt^LeS{lwX03dTxF zy9#ynsl$Fk#XB7g&yOwA5h=#PoHb}b{+B2ix=VHk%2u5HAx#f##5j?;{zH|wJ$9Qq zDgWBmU34G+`hVV3uk8Q(8e;u(#QRfS2U!NJRtBGS9VDa1_q<2s;4FnDvu|R8v;PGI zu0mFus-WM$Lel|eH1B#wAcTvbGTZMFKBTXUr8P)&Y&)-aDd%BjzQM|P^ph5m>hpG{rq@x1fG2pFPqyT zNXg@cX;l6!fV^#j>WR}G?w3#Yh8-_S@R1o|F%a|=7QS87dqe=n{L5ShE|B*J|M=Pb z?xTUv?7#lm{O+Scz=-F+{Mr2OqnY7UzyEAN*`fYTYxq`OerF5zuzL?Ug3e%sRfA+N3iZP+>*;W$OP;b<)9btiH)%GcNRf#Qcw#G&}iH%Y{ijdWKC* z_mv6IbSj@P9GFDZCfqfELhNoMm^-nRyR-}PX()|#Gr7}=J;)5&j7PTWXm3*=fFK1) zHDF~V^k|!eWe{SUZ}~?ItX@?i(KBD$6tZgdu9}G5B2h^Hwza4vf_?Zrrnu%b+Rr-fM;XTgbWoLNH(C(YeXlyL-v>Tb1d7vZ4hu5LkZ3c9IN+fD;$p=H_@xA04QS>qn;wbf6fOrF zu$j^XH@kd*AvesdfhFZP(BXKf^0R_25ePcL;{76xAYq4d9iU9IG{B$X?>j&-PT0o3&I7NK7i_*c+|z23?ExgB#3{(S>oU1>tz zKa+C;K3H$xIKP5t4R5hmW$+dLajL!!&#yu=RX)R>04yQElff_T3{N&Un7L_20l&4@ zV0tdUervClE%56GM6dw}tqMM)RR$;S6&PK2_{;!rI{!ckJZk)QekaKLTVZEO8+?#( zuD^J~*#T~E_>5-W7SMS72fQWC^*Iwp_MBURu3LK1!kQWU1)tm8$C@R();sO%+iLF5 z&@RA@!7o99e|TxC5ZsYdu$*}Dx@H}~`}K!d3(kd?O3bff#)Zv40WODE;`t(|fg~V( zy;{2k@3H$kH@}4chu<(WzG2F|E)JvyiQzhee+<2Y?f19(_&TJ0&1l)TQ4P5FsG1lr zAK(&)wpk5U&pQ%g2}CClokQloWUvXgA1(t2jf6`|t5jwr49E&FiEIID3=CzBL-=6I<)#UoWx_KzKEC8fg_67`Npz^B z{FVF={e!Tygf7q027NqJ_Ca-_=|7(3X>p4s39_r@%Jq!&j_8j=ZElzZJe)w5MpD#K zX9083z`AP-Hn|q*WLJG*jn>)W)8j#3^RV<0?2Ni^MYA?`mnk0Popn)-oq??ROu4(j z1FG`{2DHF`8q$6wPaLdEU5~IW^qxL(|0aF{B7#$(Kvr7A*qSY{}=)$?fIK=dKuph+85giniK zeFBA{@M>MrhZ73K32;)ubx)EJQNhW?+`%zrfZpTm+y{{3>c^8yz(#>XCvsSja=aFm zGAl1L#D^0b22M??9N-D7dlX1z{6qUQ8U=_>VTHvgv=8kMJO<74_s2k=arkJK%xMa^ zVQVT32JH8-nF!!|)w=p60R7-Jx1QR>R&xn7Z#F6AkJ}h#!YyQS5G~%$W&}3!&j+G> zi!a3&ua>7_|MFE6EnvM^s7c@U1$6JnlOz7VY2kzZnjiAN%@0-i^!-+UYdy%@`L~Va zmd<4s58fwk3yiK}sMo8|z!dv#f|(gjKcHXD!7~17_0*x^{b;tXo&W2&OrW(tqSWIMuT za<(-4?CJ+I*kl_&zirQVWO0?JCdbLZo z)e6^!$EaJYIx=w~@9Jm-^{OF3xEJ4zb|hQ{1nN zPghY^U(db{Nu;F@{JsWcCqGO2S0Ne!02%jtfbM<-XwhE*o)$vnmip4f5Rl(SDQ>kF-1jbq zD}sa(v{QZ!kG+~0fKm8-4CpxRtHJXw$_ib!oI5=KJB=K8rSAqnPvibk&&-V+>8Nlc zWJuF7|B|GPW%kQx4{j~jzsXi!jS3C{SLY!MOCC&DSPC5hBrNM7AnQY3D2M~LE{8te zhs03FTktj5?6CblJHn>;xw^^KLFqi~1_qVWg@T2ABml8a?=Pp_0QPA6OAIoQj7nKS z)Il$Dws`_1i=wkp@Eqi;Hz&HCC;(hWX>>n1+pCARVW=?|vOAU35;;D`M-sXO2TEhj z-P}`s2q66{Ee#A+s82H*DEZegSk?iP^EO!iRfP|X#MfZi{JAIayU{N65iZbe{xbFz zETBSHVvuFp7O~4p2|TzeJRAyXpL!L9KP87{2GgJ~7wju7&45D-?SUt-n3)Mg5frT3 z{U6@mY)Nq}iPpa7De4|O#vlo#OO0p-4QSv_BbsL<#M2)akr6pmR%N&KfBrTrvrHNy z5Q+Bo?Y`ExDp)w-K{!MQP`~M=)qkFMJ(wHA(X_w8p&CwEU*}#Q`UuMp`F3=L6R3I! z;b$!8i+TGxnFNbott%}m00Dq%-G!WOQ1xn=kN^4X`*C82?niP1Qk4gZLXZRb z{)Hb+iH|E;EtjI5e(oIzr;h_OY;PH$Z{c4Ry&Kn^W&)x}yJA-Xny-s`--G)(e8(|D zhXlODutC530Slx16Z*Y;;2AU>fQR+P&srXX7mCo?Rk!e(@!RWu`2MNd>I$C?bS)bA ztkRDjjCOy^DtP4pad~eqz%S(m#8!eb0K_#AeVIbHqmXTIV%gIj$}RXVA=KY4RsLH) z6gHJ5^hG1J&e=E&Ba!rwo^Yph2M@Wve8?t$iZ@}hUTQhyoZPI}*Ymg)6KLaxddY3l zXfk2~kB}Sym!Pe&yRrzU=CQvw=k0@t5qyj>Rh{n2cs|>!`z-GaeSm@8V{3ucFcyn5 z4;eMbf$p)Jd=Me3z$wqTAc>(>@y=!@02}@=h;VeTZ2tNjy_5eu zfB4g;%qq*Y@cFeVYk(W+k5ty~Zs7d7#bfBM@7+I$o9{p5w|$A5`HT!cPIcg0bl%Mz z6zhasOYfBDSKT5On^Vr(Z+ z=6~Ceb+CcM52h&|j^Ybi4fJgA{I8fsh_qjpq|ni8s9%>K_!cn3Y~l&dH~24rlQFsd zn7@PEXL*ddzSI|sE&AmjFYi;oy!!v*@;>C$lU2L5oo!+M*R zkSGfaWaqf_MY`=zC!!3PTQY68q{j4mGB9#oyL%S^ zl(4G~d;6#{Pk~jiFgEv`ho4QrT8hl@jbL{GMTHlSfy!I^O zVW1d}DgkX-Ub%>x9!KD}sb?hVM@e~&w~HCcYouN$>8lEeK(Y?cynI$2LEA%fW7wdlEmJ0m)3$xyYaGw808Y!qIM zRV%%W-Mo4lh`9+NTMQ&2BnfVf8x zv@iSpPXcD;cB!-N$wf6#M`I~Q8hvKXI{@nX3iC#Pfw@#$k}4(%bUv$^j!xotGGVp^ zlSUA);5*a{mh4?nf{X22+NsR~h7bO{gqpH2dieg%ui#*P`#hl(T_P#!n~;ow3cg}U zpddd4St1J~8-)V7`_V{V7+q3+9X4vQmobr3svRokW_ldwfm7O!(d2|EN+DG53$&28>K+ESL+QpdDL;1wc zYwt9WgmHSN4UvgXBv zIHe~&RXTpJ0q^N+jOhQn9_v*9#du*je{q=T-@0D@xEnynj3ysnyTLyxuCmW2;h3g z+8l4s7tEy6mxX{?u8NMw+aMksn!H%9>rTnI+K;lbWrz(~XsJapZeR0Y-?a|gUYWxT@X9EdkVkmjdqh>b zt5Ih8+d;4xV20bujg6*y?WRfm$XWin%Py>gqM_oTo1@j_!WzPkTIY0Fq`qKK2;ku9 ze~*1xy>nkwne72zxdWg};H$~}+9#UZd6L2XC* z&7}T#yZq^H0i*tZe!F~&j{Do)0$(q3vC@AVLVqW_{PJb|zL+zjj2~s`(ty0R_Yw-7 z&*6c5QHdVp6zURFT0%ln4Osk$WPuooi703ejdQFSTvcR?#1>(kp4g{+8>?KY5o#WRQ{tmK~1Jspyo6UYUH zl1q~X%{(93j-r^RwIh14Ew`!F7n;&fQ&2Ga5$lnwRx_Agz@udsV62+fBkyed)p*1I zRb30bD)5p-Mfiv1{LcznW)UQeKLkwwt>t!wnHW|7W*;4%zeu(t0% ziu480_rqhLEnofVt^f2c{_xJ+Q zB94%r%Rp9}GFE-fkvApEfN*pMy6_rqkYLh^+hah$3UPbp?QJFM`t>mTJdWVEok>mE zVLj<-w}GZ_a}1-ny&HT@m{{svw+=Bdxhw2p*~fcuI^4&7a0a%^%#0&dTIDK&Vcm&A zHi5+gNe_$1Y=;C#5nLuOM%a0tgaUm!nJcopqUPniGEz;S3j0SpNss5(C9x{<4HS&ppkGJ9e ztgJ5AC%G3+BV=bXQ3r1B&2`J6$0g5myP>BR2pOAZFNSjJm?Q~-Jjt#Gh#&xN_cELx zZpd{DcF>5KWwBU2;egY4Eq+CB17bz_Jc1-l8*2Pw9zz+k9jC#FI1iIZ84CZn3vLwi z61H)9Cn49MYAi!^!Ia*jPZ1jR*1*&1UeWBPpxUeuyoMUYYf|_Hu{Dj3CA?u&U+KlH z)X@Yzl?3Ifb`gcnxKyeYNkdc&gC_Yv>so0P2ktQfV@hemU@7!s(0hWX#sq+p`>Q!USfqnD=q(|7m8Z@V~uvl)m$CA1X?Ze0pxsO7=F zvaJ1;4(7J)-Q@KgD&bC{^N%Mym2~OYKuZJa{m-uKuZa=Q%W=`2SQR0=QfDew+8`@N(P{MyFEsuuT3PF*b&us(|Uhy+tcJ(vL1*| zC$8$gl)2VB$~+2_EK9XdsKIN1ZcIq^nTeazWrGu!PW2nUR`YUw%9AF=CEL_%qc3x3 z(pqgdHkgp7o7JNlnl;bx>#9cf>RsJdH&CLiHOLIow*vx@C>puFx^UCB0j?Tyj6k$m z@5RN@M?18=vr=|jKeN-&Sy1F}Rej^I@_yDe$QPdY1yc z?oTW+(nEj3gRM9gm5$m z12h03C<0|Ihk0u$`Z(nWujEdJOD302fC=yR2lL1ZDi>S$0W`3*5gz1X9c_smuc~S=Wp2uM5n^&4qNhAp)U?(YUAyR8NCmrAqYt!UKJ#He>v2{hk8y7p~Kw6q}KiLe6QDBul%AN(1}%zaCWtv{zv-x65F?ea#J2GNh< z=6^f#3fyNJ>_1GNm?g4z=`v}L0IqQPVHs?5Z?m_Ie7+c)Zl`}yR5ABo2DMtpr3LV` zmk)gjivu||SZS8GZkoW3{PzaY?`=QJSA*or`9_>vMZGv$VqpaRczG;~0uB2ZH|do# zFm|4z`w=&hP$vtY+Ln?O3?Y}rh;~lH2H`X~LM%p+R@fA%b%B{iB8Y>Uyq(6cedtkd1?;)yr6}xLF zk?UjTR$KF?!f}6Mj^WwkZymVfnO&_?y9#zK9L5wHmZ9El7NbCCvivrqdu`9Q(D&6* zG`&&CD(=ndj6>T<`YTDp#TnZjiDY6<}5tzKFaR;WXzaN*HK0-~BSBQDL}D(5!X zcToJXkFhrDGZ2$jZ0!|%8RnhlKIB6&C9vf&$SmGs`>gG>b4%=tJK!!|n7_=o8!SVL zLFj}K9k)STK9C9^VM6wJtS?i$n#Y#Dw#?XV2PZX(gZff3=hP6eo zM1(RYDBK2Flu_5nXhod#2Yp6VAa6HLf|&*A2s5s{!Xapj+(Q_C+-}9}!P2NtRmn`8 zEna${1!7oh-N78M0Z0B|J<2UmJ`VFCueEcSY0}2t9C>@QDkhnu^-Q-);t$l^f^Vvw$bI)zCI_;W)xNNxMsdz^zksRe{&o@ThTwByM8=&EiNT+B#{8r7A62|12_ZNnP5|5 zOy$?drpqt-CW{MT?nu59GC^poh}#fg$Uv3wOBmHx-=VYrzHq=tk_!LSSr#tu&hov6 z&NA3=#kzQ$UrJrsb+n1k_O6s*e*nuuay^Q#83R3YdQtI%=fox(>>H}5cpi@|v{hFV z?&v}U$rKC$V6I0jx2G#MPeD$cHmB*tU$N@kY_5{v+<@j*BG2l4HMc&(vN^JDlbd0| zznm7@c->(uYG6RrF2eUaq#mY(_Ax-Yv1t=rb|&JU+WkpIi6Jrl_SAc|mIsA#dJfV& zC(}7{d3%7nmnPYVnS+;ir=P~w+Z1KD30^`t02ocQ4)U=WD+M(P6SAX}xEV~E9N^14 zRI?%teXu77F%BSO-sYmB-5ty%V&n5F8JwdMUk-|oZrcA^f^1kmIbcf+mq_L;4( z2ZL%W^Fa+Y0Rulc#=0K*0;D%*T^b1cww>pW-A(nl60znKd#oCIJ3s;f1>YQ>MUP&} z1JlbA`Zo{l&I3&=hB1@gjK7??SNc@Bfi;jC2=~gGz5BY8=%{qAg+Ym z55>ALoJVDOl^l6v;JcK$Z6aeI*ip-`yVMLgTDxEs9JEk*8*GBx{J;!eg3@JJQHPX` zA!_exI8PU&qfNv)>1iC(R2}-rBQ6I-zua6I(k4`Ij*i1*`$zeqw_44!uoIXm4c-P^ zFI1?bzdPJ%dHYG+%6Sb3E2hbY|bXS_jIa+%0FonaznAXH(CaP1fS>E>5r%l@f zCwi1yo(rdSryGl}3gZktCLJ4;0-vsR@;O%ZpzHT@SI1Od=ZzxSbbdabj3Ij+lv28M z^wm1Qfc60$`xUP%EM-E55}2VCCO^TB+)@+C!pwgelfpcJoM_GE;4^2)1X^ee331F; z1*AceTpD=TI0?yRQyBOCY72s)iIIw%ObG|ju;WlGo*fZAU9AJ^6?k)+e zE%wEJ^r-TRB>fOl!EI$e3S;oAJ6-8%TV_%uQA$~(y)YjwFA?&Q(CaPQX?uXB3>2;) zS+cfX8JtM-@hoxR2RQGa~n-RisKdl&2QC z*#{C;h~yGVr6=83xO0<~&jER)6_8Vdk86F)?N@5F*^s=u*GcH!dV_93QS9i7k4`MCw>NT3qonxqj_q==o2RZ@`rIgvnAd(KKWF zYu?XSH~6+x%sN$iQF^)%o~2WETbrY-b(;r8Alq(T*b1QLVT%aMiNL@~rlc3nDj$;K+|TH?t>- zT7LEFdu=KW_3Xr=Q0sz%P?ENyZ`3u{6kK0B)@(cXVLK2<76QB;keVg zfQe*enP__9S) z=$GtM%RqMV&2VzQE>l@z_CP8KZP^@rXkUdnoDezC$q`^N1dbc@EwaSsp^cvKS+yukqa#2Ns{0~kz*mBPJ zCP#w7GQ3+Q12+(`M&FYTQ~CKZIGZgW!Ac=N`ff|7`Pa|jzx@bS|MnUDw;#dk-#&wX z`v{<8{Wr-H@Q;4SRb(nCu0}{%FPthn7shKSDC|KuDD_;|)7F?n#Ek0_OE7D=-~qAG z(gCwp*^bBT2apXNhJ{4HVRKMa|4!r(*gcX)=yoI4H`{vTX2cALtH}$*tueKpw=`A{ zcJ)JINb=xZlB)=LGe+XS)@#x~(^`Sn)P+J`$&;MKJRx?QS5w`%=Vp8I+AF}n4LrH0y@bcQomqQbkd4~>cHx_{B_}p7RB}=Ps&+5zcDGUYi1Rr^)fE9k*r{8E{D*KtOrA&|eZQ$E|e~jElVI@x5aXgNC za`4+tdXZefE*-u$^|rDu%x=d=fru22bqp*Eu%h0N;^vhfKc*}%Y%{MW;u9Ti3Y7w2{N`rr1EKW!llwsg|^FG>`9jtp2H ze!q?UPSOc9n)g>0teUk+??MoPKVPu&!@N5j6-aJ<-wSV@lIp-#(t{rP1ltPas(#-x zmLTCD#XhSKwGX=#m+wIde4|Ti5B6+c0g*irbwNJ#h9CaY5Q2RO0Ixp_R#&hsz;*yP ziV100rtm?G%HRfBtR$b0{exol^YT8g4xIk~`{jLJ-Rgh6ydPKpzYolRQmiso%Rofy zBGSP3e*CzyI*yWPwL`EMPs^Z}Fzpmmd|))}N@w*%&TahKLB9j#Fi6Et!$Ns5Yk#fH z+xaBiWY&JFHdDeJd0FEjY9WC!d?STMIu#gDkJnGXS>MzKOMe))SC)?XU#x;@J zJw);vXR?5a3#KaQS-e98UpqpE$bsI?xDcE&swF!tWO2Sdm>62CYY|eXE?tJL&a8|# zUg8_{`E^(;MPJj80%nPoBBEt~t4|V&xLFuo9lN$q7xEfmBpANy?%Cc^pF%5(RwCf~ zYy>o0_3BWNJPk|go#al~HEG(z>yjhv#lIu9HUPPWQ;9Q=J{=A6MzlD|6EBhA$hkGh zM{yA>6hzk_g4LC4QedWiYuv(bCYCP&s`=5ghy17Oq`fGLx)1jx2QlzC9Fr-aAT{Bw z{`d^`25v3T|5E*{jsAujR3Eq3?c)vrG!nGp-wjy(v#I?r3$-d#$Ze9s`Ee9RfgY}n zl*g4W`$tH-YU<;3$jNi{z}A}wF;+z=ne?86a82GkzRJh$JQo<`7mO>&*NVND|1jul z!O1tfPMG@GhMO(3&bEpgiVu{3DHlqlPdq>1Een~Bn(kLe?{Hn$&v~7wJh=MTUA5I$ z=j75u`xWGU`mu6$8*$u$i^(1i8QR3#S4MKd+{+O1VJXhueasw*PKUDtVu@Sc;TpLM z6IZ;vcG>#%gfH#B*iU%14g6UXvXbB2lJ=t0vz#N_L%Ei@8#+}Iw5GN@P3UT~RJ`E< zZjgdcU#+1b@cES1bJDhZ1TZKdZe|b0fZISQBm}OsjvP$#H<$6Y3vU;}z8;N=fEix@ zuM4#?rF|d3sQO#A|JUv}!|6XQ)7*YprtzmXZO~AeU!Ney4amWn! z1t3nKqJ>}&h5ksT0`*a#1Jwk)PjHa=`{rOm6L7yo(L>uD3}+vw0oWakA3lPwjRj)a z!O$V8Q^z(y1k1x5o=l*3@Vz*cqk{SKwU=M7gI1y-$^uV&l#P zlpde+hl^tC7JgA%>?Y=PeKVei%(r3)h8R+bw>YQmY=8%ql2*rW9gy(M~|L zkKFJ(KoetU-LY@mUh*N&>UCsttvV@Jq^efO2k-M9_2Avf3tv{iC1`hj;*iI~^_vT% zZXzAz=KzSXeI)&LOkPYFZ=8*4dIyxpp3K^4T4> z24?MmOe%4p8Hyf&D8uP_%W6HMM5B5+%+(g!q*ApD=`6k1LQ#sgpFs+*CSeNiWRxmb84f)9D=BrV^(0Fu zmHlJ*OjUQKTt!B9Oh`pOl<9rbY`Qgr<*Fmf-Kb|qyL$@M`TS+Wq>`lqdM#crIDcsP z`~0yu7D!M;10Uh7?Mgu7JAITy;XQFQ3I@=ym3{y7KYKWXuXHOA3g0KL2B6G*9g%Vk z9g-%H)v2rPa(5#PWxM&VDt?QKNu`hp3c^A{jqWInNYQ~ zBzLSb_RU>W8EvCZ>Z5Bfl2A;qIG+hMW+_{7x~?IK`^)KGW3N=J?5?aEb!!|EGzv)< zzr6UF=O4OafZtrD`hqZ<;wa=+g4xr{CQ=e8d{5H5oq7JAF__ZsqbvQYBGS=TiqCna z(Co~H3Otzaqnya!OQz(9mg?gkPPpB(A|&gP9kmnTTEJjmL)+YEa7w(%{o@LLy=`iu zh>r3rYar2Dv?hV~lpV2+kOp|Q^kuw1)u5g=%QOn|asuLIm?BMX6ijU1E6AYJc(UB6 z-A#Sy7$#pgqc{|+vFpKOwDG~XhMn)(S>FvN6lJ$fv2T!wPHoY~sz zd%aPbQJ48EWV^&@+LTV@^#NV1&IT65rz(|Yrd9WCj#^zpSWIzWuZzdr3K;tGH-Ks` zo@E`Ex1ERZ?ReyQ|G;ds)`ZXi&d+F<2_z0#?KIY~CUUojbRY(p&SkuRvL`~`yzYa` zqJ4E9s=?cdkOvlb(&otADDPHMljC)2q-y!GPpDdig}r&Ut7@DvQL$f~E3U`(U`fFC znba;LZBlm1vQM~MGFGg!S>~-9K!Cl=?K-lQ#2Z&l$UX zFNLq3xUFAX_my_Cs@t>^6IY=ap4ah#%rSNc_z`ux(5>{C_ga2Ar?yAU!XrLg;6(`) zd!@PucFRF0h3a+?54~lI3wAC>o&SSz5ui!wqImm@?0aa*gntRlXIb%^qT-7c{HN-I z8J0d`^VLVxm~(u`^w`zM!v(V${Inr~ulw8TqWHDCSlldMDUncJD9e8AUEeZ+4;P}I zPu!<@h4HN& z=)yS<&UVlW{Avfj*yq~=@bzFu{q(kBj`?4`>lI|7|Kr>KZ{PLOMfqC`@An-%dSDXg zjIn3Zkxx8+4DV})H5%_2h|m&mNAtWQ3=#vS*`2whB;1TvVT#E`wx5zHExZ zNPEepS;COQbeIz>jqasngnih*BE+2Q`a!honV%sCnUAZParm|L+{dVUQw77`Z7`d< z??yIOYtzR(WOD^F2PmLNCSxwQJ&n7Y^nU3N5wnB1OXy@J>dm!RFjx#y2dmU^FU+V-Ol@MnBB%YN*YCI49r7q>bbq>&J18G0qd)qPaWdv7(NRb+MN z_@$s%NzTDQNChi4hY_W!5ch2Xs)k_a>20mA8~a(69Xlk|-8JKQ%JJgtp<+7SM|1y@ z;LPZ3@Dyz#mR}de5smK%&Q&YJSHr_m5TysO(;bk8n0SXDgHpA3ajKp6hV_U^&Gy^Z zwwQu>ALBBFiu$K@sn-XT9g6cn51Uru2LKholnv6HLx^m@Jo$aEsQ18*Um;Aph9MeR z$Wo%2-5juEKAwvsEc%d3$cAeYo2J*T!%arlA0Wn$-6vGB>w4>p_O8zkHsWfh=eC7` zpiVt24@sv@#gx_wk)}X+rN{CrOV#?`aPmQ(@cXAK`1jMBueJA^Z~PC#n?J6(-Fwab zGM8vHGv2L+qV?{Sgmx#|H=Z|sf1*qNAFa6{mgT?J-0;UW_sb&w*>w9%@P%NJ#SQ*# zy?vkNfG7L$*wT3W=sus=pHFj;>iA27?~lK1u{b_Kw&Q#pDS-gThsX-BhWWA!d=urp z535UX!{@n^+rIVF?=ckkCBYy74&Cnpl%JA*f4H%J&wGVrr-XH2YATs#y^C6?dM-2) zX|pF4$3#9u@0FqrMj>zKYGr0La@~Z?^OTbohNPJxhskt<3{6&i^{9V8ZsM0YJoSfc z-}->-5x3%M;#egID~=9`0d|S~;DOO-0!c?{K}Nzh9;p~@fv+a1;WkDZ6ucrF3}4}U zE6U^cNG>%niqM=b9Sj~zLNzKoxHBIP~Of;?l5UP;lbFPo6Y`WVPtsU9?qM}>O~wlk?0PX zm*wSfImG^Of;n{Q+glr>vRD{aL)0KfvxcV$ogGl5u-*=mAaa)q(r!}E1$w>EGVzG3 zH_W9VMCp7#zwAS=Q;Tw?^3dybEp_?+isJ`}2=)>Ak+IemNTLSo?lfbFn5jS4R0j~u zk<-m)FH|5aN_w>6`V<1yA5KtMFPKTqMuvv32HA%A;A{D6A?6>!X-*#rZrssW8(+GT zWQ{IJg=cf$I_OrqD1HMvGs_SEUDfur&hqI!`6zU~Dv17Kt^cId{Z{k-arJ$NW3*pm z4~=Y}fmqhECO+UsujVdyi|}vErMKO$|9`al_R~uG2#NxnrTF85D8RZ`3oM|%fdKLi zEX!Hxm$(kJ919=|T4&43`>pa_ee-fJo@Yv-4#&X4(r1`Os)?i@yaUlhF)r-AB zp2a)$X7O%o?^bmAe$t0DynHv|zFaNPHA{ag`j-R1SKZD%Kp=3v>z4by(Y7={Yn(R5E zX>$7cl%qKVL_i}Ilx=nZa`Lw{!n{7$n{%W zb*C-KaWy*}Yx4j}>LpMg1VDni0JG36x{Rz@M3O?Xi0cC@w!w9Nt^tPYQHhs({6$*< zD8h6k?z!DHxD^hN?!+R=i?XTnRUc@$*+vdKyJ<=$91bl`B$Y!H?`x@L(vB`odfeZ_ z0wxr-agA2VZtGpaF~;^!>aj;n?zs_LFf2*sc~i&t#m{qA6R4CG|ez3J|2KH}c#KoV=EiPG0ecF7dtPN$Q@Nyrn_-_Y@ zSN~Wze_sJFork7)^k2T}OP7{QlEcsX3aYXNj2 zstR=W67dDbOF6b(h_*9L|WT~-c7S5zQMpk<@1f$~4E0?pQ z{jA&~%jFq{$Y3-)p&hp7;`yoo`0LD@Eb6XhWcGUgXv^ng$k_H{5~bUa3nLpmnh@|l z$V_0-DgrDSuJ@2ep2N7+cFDF)iDE#?jRnWr>y|%-&2-^tbQ|>>NW#1o*Ke!gnaUWN zO1~kl7bWa!k>xB>SWx9i3i+YR`ONG7RaAo_5Co0)XNiR7ihs`MszkGHtQ8@DQ-)Wr zaDz-lfQiHA_7z&kd}Pc4hG-Gj|IU>4?mxZHLLXnPciU_wZ&kyjiR}H&ehDABLjSmo zE`a8>pi`BM5c-CMBv)lG?T8&qb&Y(-UOs+k@R&Xy=P>(%i}mzAq;&wdr~ z_0`^|xt~B2ZT25xTpq}jLPt)9W~+3ceGm)j^E8bMo^UJB0X4RonjRqbW}*%TG^RE? zL7BP)k!&g#2NiMPl8&E z&E&di{cxxjxcd^*{&sJ`Q9pkznKGcUd7j^RR`~P#u?5e{K2@t;+#5e}>)v(Z$E?>PKsTJe~T`pxKTuXD+vFN#bVZyw3 z9vf9jn7w02Lq2Edt00hQVyg!Pr_y45C=W*mG}!m)q}1m$t|8Ds+3NL~ZO?Ln(HT#y zuJWF|g=^$$pPBhA32xLtRwmzH%Li6JMER7au_2u!MygVdrj@|L7}CN) z*H=KkZYHw$oF%HX0{X(wQ~b9y&M&L#-;ewdUG_7d&8T`$2Zt|z*snP`2kOg{vhInS z!%*#?7qje?&OSF$K@0O->Et43n0P*4pdp;fdtp!^N)$I;71oS-AkzGCUxn1>%nDKv zLV!lx+&v`dP2&g(v$LTef)^fpj_*C3H3kL%bJ!y!)9wPc9Px+Kkt45@b$^>N?cn4Y zyE;*rd$MrI$LS{Ka(Z@fYPDTY_8+BAKwS2^D@x@62pIgBHqYBj$NTOjmXo^8E-2W; zhycGZyf7!YKdp3mFhM%a5XMa?3$cPOX}2lEec)t1if~dtIZnt!2Ww?eEKt2I>JIumanUazSSk zfocT;ZsA~^Ev_{dQ_bX^83FXmpB{r#_y>>rV+Dnl*V6k0hS|49tHeG(8m<4h3jd(h zS;6UB&^h%Ay#Qv>um5IgeqRC@?kHHA_wNAZzx9y60+iqC73!^Cfl%CsiR@&hydu0U z71l002oM`ydYFCV0)5y6&T)e=_w)8*pN!E^%E7)o@pk&r4W2?!qI6Wj64(#>pK0tEjHAkUsOT z2p#?IRPCXPW-jwe$)-}@)RjoeVw~*!l!buJ%))`F*vO@)2hGJ&QlAYkmRTRwupC`+ z{<84%0x)$z68Lcj{u`w7?^3uLCi-H__Jfgw|za$I~zi13$Gl7(p?TuHL1ZMDG!_oamV6mf& z!HMWWMTN=R_xErBLwtU7?vHQLi$8U0SF|IX%p?IEonyZgwM}2#F%s7G{doV~k?w

PPkMBq<6g3m|LMKomV4({c1p-kz8 z--UZjpGR0XJv?`wkNYN;`b6pCHl|{VJ`5|a!;|7kQzQvSyPfVz6iqAUY2T;Mq9si&zEj}Zw zT8dT7sR7X3ffVT9)r#g-mrVT%73z1gPV|=%bz>St{a=@^9@8-DKI+%sDH(q~{r~v) zKi0PErH})=$G6({AN@?jiv=IzH);4Z?JeaTT=U_2g~b)hQw~(xRtL8S7%PenYTGvm z6Kpgc0K)~qq7OItN4@TOwt{@1C@`KbZaf3{@5fDrA;l{k<}dG>W5M}Q6Lb%*n5~zDjmX#U~_HecoKnlNv60JNKZF=?=0?4j+ zZ9zJG`@4>xad0g^{8I(*3Zj5c#bFVu!i#2Lt5b4sM?mL(Z#>YB*eT#~f&rTV{fY2n z=P^m}O)nMq$76utg8vVnF5e1ghPnOn&K6w!umxk)!voU$2Tu7-e;xqBo`A(=w*c2o zH!xy2PhwA*%izD)6XF>`t}K4r(G;@K4MoG3dwBtp@(g*SR%Skc`;L8D8Fl^ESXN9U z$t2^gbKVJ@$yA&uTO3F)pqyVmiX{Q*DFZPd!i%0aq5<;59u6Zk1f4%WAK<6s6F~MD zd~QYzpUby@O&wk&!mNgUJa6dZzuNX@AWQ6k1G1-{F%pVLCl(a<#Q7d@&Lrfn##fsV zDibnYFVr((+Y3~1?ai1T*vVPVrvgtD8<>sHo?Y}7-ab#F)QUTWgfft(^lTT1+kJXC z${6*aV(cue_l@;H_FUc{4z{@QmEICI67)bwoIZ+m_$6a*zU=^PctMLYyYLf(P%yTtSaPxr^zSDxs~2G4Ha55WbU zxGdz9OxhdIHHXGv$uP8=CX47i4Waa`Y{|Z2JAWHS(`OD7*t?kQ!$|z@o_raJ|FM)O zEy4ozCgzd0amqImYne2&-*Fp{oK5_NLEJ12E%XO^SoL-{9yiH-d!6>T{0dSFmkvq& z2tCCbxi@=ey|(-gf&JWtW6LZW+^F1NK22P2P@RkRpgL>eXu1~lWLGV2RG4m_FD#eD z?4^7K@a=Q^e7(~O0O!}m{aI1__3O&U8Bc39Vzh2^;@A6iZK%hII%V+VZR~`PR?7cZOaK0tQvb(g{&#==)6&mgmZs+XJ%8?>tgK`9|HIP1fGz&M z^xIem{mw+Owv+v#Uy~S4|7B7AdAa{w-IvvV^KoClFq#`Dce@?fmLKLiBAJ#k4WCA^Tjp<{yj>K!zJ;~sJ zA#N`$zGs~grWR*O0qzIjQnX-X#Xi?AL1TMY7$A_K9p?MI zfpNT_ArUkmFbw((8x&eVBH#4oGr0H>VU{A>tuS)Eww;`hEbfVb`P)l5v>fuX|u7R0#askAQe}b6bcGfSO)o(^bALj{Pycb;zCbE0u zq-V}KN-x>*kEt3sn`#(Vx}WV6dya*1YFS$D+b*Aoc5rtYAOwH~NXmQhmh;C@J?PLG zl&hna0O;i~j&@y0N^04tW5gRnidl3e7RcCm^(1E*i#8+eNO{uRL~O|_y=GmvU5Yc++>DE%Bzn_Nk8M46`|z_AV<#fslT6F z`M|~^sotKfcT$cWqmJ%z>K_}~n2{S1yP3-ecaFCYcp(*K#)r@6rq$OluB;w8wz_tH zMX|!4-A_h(2TW1D5Shup{?A{hf7(3$v`KJ}rT2aK>V3m0d?0!DvUBn^M1lU@2%xan zA4^rp0#k)Wcm_xBcdZIOqUVQ?Xt(sgA*tvZJo(p$EgGZ-Cil(E^agOIkd(3qfb-H^ zp|^MFoP93Epg9IuFT|2T|6AF;m*Uqik7X413oIYpo`^@zGl3z~$O8 zZ^U5kk}wfPnw?wxW<|8dV2-Hlv~<3Ej9t66P12c;L!1?= zWzz9M6zQ**Pzz9Lg|?q~n%5jAT?4n_CjpfHgpJ&cHB)CicM*3)|I=9eMn<0%yDbwUy5sjm`k zKf&w|nE9|?_FU&q$W_^}E++RnL`Waj zK(Ffo2J{xEoT(0uRqgMjgD^+<96Ef&#KDdJjgR?LN6LnMv}pC>>KxE>d?BOLEjln= zg`a_&`HOV$$LFqoeX{;RyuMQm9J5XGNZpIKE6Ud3-D;3IkdZxgzjxGq$#@B9fSP z&P>L1-x$Z2g>un$9f!6zUe1XfkIy+`?#v!cg{O(e*5~5>0xbO1g<6K;9_Y1MpJ<}7 zeV4ciu;ruZnZ>|=m{kb$=%kzL1G+%IcPXIO!7cjCU#YEl9(LX-n`t&os~DR6@!}@G zN6GW0=ME)Iy+fRI&+$shqr){7w!A4GXn<_R^mX5wJ9*#Jv_G{+woiFu4)nE-4o^&3 zHse?<2V-v>Ku2JnbYW|?ezY0GL%BLV4i7mVg#XLjn{_FwZC$(f{EB^VJD;GSa!FlC zU5L=W8!Az1MGE=#XAo6J=E}8l@3&~@Tx8442qQuXoO8@Edhbs%T~__-H3)`#cP|ui zmD5us;L-RRxC908Z=X!tUQNKdk)q@DV~AQgpMVugMg?zP5}P#xwci3U72dJu&M5; zJri5~MmbU@LLqod{SEyb^cUkcY;0 zYu`7d!H%Hp={a1pB5?Z?28r|DPPymEaMOp!fDP1&0{cCjg|86f9Utf}t?-u@!QvFn z`rSegMNxQ%YDD=9y~>Fl9$e&qI(xpEq~FQ}`&JInU;O7n;ZvzkbAqJ(HE9XG~EjVM=R~^$$-Zh4t`5AIAGfT z<7e|rxqy%(3TL91QRBuhJkkz_P_tplj@4zzH3HEDE!(O@Lnao`g&qBeA)qX3x+clhB0O5W^t;5c_ zrF(xIM1<;Le{9VoX=;kHb=aeG7+8kG##zD%Rn>?_?S|+vXa+=)>KL*S}T1A#9Iza2R z^rqEt&klv~kj*({XB0h(v7@+troIwFK3)TZ1|fpr)fWk>9J?#)iMM-Oa4xyV_Z__j z`prQS+bTxlv;>jSd23D5CDC}$=|=N-mjGk?oFO{6BDSgk`qOL|^TC6QcEoLs&s!n3 zstqyGo~DZhYq|L_@!K=P=sQujk8qfQsU&A?ZkOJbmG$eRBPZq&U=#V;4+P|} z%XD|<7=OA$qSf(nF2Q9?t`%f^_P`j95rs5HIL}twTwH-$dOYtua{~#=)FT*B;M{6}=K{k}J>%D!> zW?v$Ox=|&EtU6cjiKFc2?+=bl@)JyAM&*Gkq;48xE(^Pgd31tm7}+w(xPxr zdlz$`K+h;(aO|@|XwcLSqg6u_1l%(p8xQjI#DXuMcw%kNFir{X_T4~$H^V{%lv%kY zsE;#pIB{U`f1D0yh&g@T_xc_!d$|n_=rtBXDDJb_a}v`^sONp1b?o{GS%`SOvb(-V zyeZ~i#!-`I-qAJb8Rjdd_faVvlGHp~{W$R}dN;Pd%&m2`J#*BCRGGEdrUBh(_n!9C zusK>~1P4-tm8xB@>BK1ON7cA%M9@BXlh=dYBlJsub)~Kq+L@b67_T_vCE*&lO-+Wp z57553YrAkLZ*i~6&Z>`q*v#dJV70$!a~#poS&Ed`6Y?C;%m>ooizVazohENEf8Tcm zb>AP0`N4P;F?a24!w~&Hl?y`JIFG)2!aVXrfeg~*{|W}=vsL}4&I5Z{+SAond)gF^ zFDx9e_IY)8{^m7oh6fypf9sI;zn}Y|^YG?1{)rJ{ZBE0d-fiKu!jbO_mItK;!18{4 z{<~5b`97Ebo}cv|F!eDkT)tTz|K!jE1q(Ee0rxk%pj;_KmCq*R+f46WrD8$W!^en| z8!<8P$WLA1uMk2otX#i;-dqB_p3p2O{uuoXLI1zDExyVS^If2Vd@59iM|Of#Rrexd z^~2YS^l)X|*Y-j-rUbwt5BB?e&6(C?MQ+x?X*E~e*l%Ie9FHXBMaTWs(;%3H8*62A zy#_k~6>Hv&qCg~;_hIWZn-pbpRtyZ=_)Z6RM7r-o5tq<6^4{_EWS*zU=D^;p=(qFYN?m36U_*`}9V48GI z148rNmDix)%lK@$enb#1)4Dea-|t+}zlxm|4Fs!W!E#sS(M{y0HAh%84W5 zbohgRx{7<<9srYfqY8I&4tvN%)$0`KTp>hw`SSzf_%BYC3MC%xA$eEuHRrx6R`>ql z9$$s9&ejaCA)2SoH@EgGbbp+nwuS!Jb_40}m3Iu1eRz_}-LW|iXfNLU7XWIjxO~-h zuGu>{iiY&e-L{9Z5O!H0h6oQ0+2^`KW1q5ZxqQV~8@LBPci{$W54EkE^0?}m$*lbL z-af6pL%Y(|x@^KO8B^Omz|{7*zT98+RY0)E&02@PcAOfQa&`dVJ!X(jn?~_gwRaZe zt#-haF;cJhvWuP>(iIDLr{W)5v(IZdKGUxy^q>9Ae_9|pX;~o0FZQXaar@Kh#h&)* zB$Lcq*U0VxNt(Y2s9L%?KOkUVBgs8lEAFb_v?dIUE>BpYWyOD5&lGSk2FXGI~vbTK@@Iee3Z8-5#j-Zv@h1 zP1^;YnSna0lmxPe&Hd+QasBx$q1p4f{_!wbTV%{1wi5W^iy;rpVIMZVk7hB<@RmT_ zPg}{)*W?q7_IH;A`Pel6t!wh9OM?6-*W^!^1mXX1O+IIH|Hf#pLmC5eu=(1p)wGxi znAegEK`t^1t@yAO` z^wFIP@wqjw*llNn+5rivc#-xUr>DDQejVbo6i+c-1FDI91#(C2E;%p>3~kaUAhAV zPS|0I1oFebyzyZes4rboDuvh^d#_v1VIFr7>%@8lKa}UDAQhdOfgXGFM)7n}#Jt@! z+}ych)C3@)NSOM{0sDTnm4Qkw9M60(|odHWE^vlYRS~P*M4vbQA(jViS0ptzggcQh$8jiOmrZTe0mZ|GjQ5og;AbUY8m_R zUrYck{gpb}dozZsK9n4MEX`tqK}mnDh>_zHQ?T_{6>jb_(7;3L`AJ0P{Y`_JB;DQFL?z6InCrZmzi*Jh#H|2`T6 z&`A03_L46P3-s|y=*v~*Tc7T8ssA=;194m6En>2d&e~_mt3$DEZKJLHP@QJf-|J$9 zo4Fs-zZ?DS3qLlh+cKRC251CcKXYkQh%Q1Tup@%D4FrnN^mZW=^nD=7a`W`zfURO1taep4@58iVc$W%U%;=8=f8OUfV=wTCDQ-9*AG<5 z@4>#y1^n+`KjhyzoP1utKW$Qr$LL5kFqbizL8gE=2ndF{qSSkzD1caqFAy(dS+D(Z z#jcK~LY&519!TyL52m#ze0`$18hRv}cw-?9V&P-# z(FbxVfO{0;I!rJvh#RcqmFhC$9+J?=xo6emjG=2yO1)c8I6Humd~Q-%1YorgHl+7S z-CIh?_uk!a{Y8=ajm&0_+!EE>oB(=0(}Bvzn#Q_{_+yMb9Gw=w&20Skm6ZgSp zDkFe2Acw3=p$WU(Cm!QrMTJjG5|{~~DflRZ`}-^9{f+E==objl(xhLM1#k9D1r#ok zKtl92QHS0yt|xKr1R=0wQZSE$^!R|P#0t2?U^1CMr43&Z&-90Q3GO!sM)Bi$qZk|d z?kn^5zLksTaJ~TEs<`PuA#8Uv&fT#aTby9lbFRyc4@|Rig`D9=nVD;O$b>sXx8ioF ziHj_Uj8J53Qmi5mKd|23C$i8o0pPKMu%<2fr0+fBNouVDUIWj-P_w@uIY_SPoCx1X ztcI45hf>_8l0yrAM|(M#7tWqwp@2A^iBWz0$r8er51Fp+D zyfMhJLK|^Jl}SI>!p#rx3*-k+3|3y|h35pWfL-FA@aEa>coZ9k_KfkSc+{UG0l%zh zuL4Xnj&6yJ4;&Jl4%)R2V@rH&AiZRBb|gvNS?=?itwVl(nZ=#gd7C{$l&@kOJ1z;E zy{Fy(ssCiBF~sk^x1j!Fe*e?<#`eom>CSv@Z>+)SkRt81A;w(R>_eWe0s5PY2~gwG z?|Ml;xt>08vY-7VApN~y%=`jlEu}E9KWr-|@5@K;V>HIRL zTF~LrlI}zRwF6t+oSArd4k-xKc!m9hTv-1d9&Z&2rFXs&}?HPz9bMYFaS@J~V<|Z&1^Nawf4+46t z74GYUU%q4%BG0^yFyl05nbw#@1B3VL9Q;JWt}Sw*o;Kvr>{?i7@lr=y;c3G}Mop*{ z`9xSRhSc3yc*GBhynr=yATPH(Bwf*0 zoC6>fq?G&uBZc_bzgwz*8nb|SXu}T;2T|6Ey?wCjOQM=I7Mi=msJ*ABgKGyJVL0A4 zP%6v5pCdn(T(?>f)zF4*2tf{a0cU#272$5-+QiE=J& z**yZVGtD$(J0`3Z%c$3NG@6$UMB>#7R#CfduaxWUxgE}l8k5FKf`yW~o1idK(oXI( z@Xk*FV-(|F5idv;O$X^@J_!DH>#?|fw7a&MiV6aKdq!c0wO1PutS9HGUe~Wd)^ckv zD;n;|?zyG>N_>DeJ`XOwa0!rFb@>FM!-JP$GtkA~g*)Z4;zp89R_oY*ZEl;?f+{hB zaOCY%f?Zfyn+6zEg+QQ7yE^33(FdMwNPxg;D}mau7YNK#%;wIb!Fa-tpbm*f$6Kj^ z+7S0i+uIspUllRHJMh^z1Edb`bM7CTQ|~M6zdo||{<6mYSpdKeZ>#K&jy=@Rw^oPw za8qg|ZAj2xySKk>NYTgt_A2`$y$+U3@E^UcvNkP(F$pGaZw#dOn30dN9J=wvf-w4E zQ-DM&2ZWJRVBjg*c=^xI=wpPCK`7G)cM;sKe_Hqd?iqbPA!O-L{i)FXUgv7|-hT+w zDKvwLu)w0OXaG@>X`5Q5DsTB2^ZI;i*$uOs`78D+W=GwFd$ZYI zveiy)a~L3`Lw>l#FX!eRz+brL#b>BSCK7>yM%IMh>~5Ybs6B2F*t&(zH(J2xT_x0w zt&4Z-QfP8*C`zy{1mYCNa$ZZk*bIp!d5rm_WdQ1B$U%c#Kl%J1?`OKW8~k{WC7;4F znr6H-z+u1~w$Gs{EvJ^m>P!@C?|uOEP_=mad@zx)?!1DZOH)2@@mNSP*)@K6koOq* z&{vL{VHb}KbM={-&c5Skw}uRiGri64u8f`Q!A({N;-oxe=9)!ZTLPH$sz8Z+L!ft3 z=i3$?aP|d;)N2TxiY+19SjD*!!nimeEz6)xX(2f9m%9 zq0#fFT9*?S8P@nE!!jL+K)W?^iBlcy0XRk#Q3=w?zjOy7!0RAkzc`WFfi$^v#!)q;ZMJ*QO!tg7RCQw5Ew zLbaMv_#D_yJc~FeW?01rnOau!>Fy&V_lb zO${U#bGB4&w~uqX+9XditqwY!eXx!nMhg$&yayHuRkF>`_y0|71 zeiLvHlyiVTSszal@=$;l_LU_d=wR?wer~{#ujqFNT$l(fo(0NiZ)vsm!5I@1&+V-j&yo)mQxT%ip?p}&cW~W2Q}T3S zcssb%CpP6flHIArR=1Q);hZd)q61?fy1+?ydI!3DYLFNbx)@??bKc<)M`>RN5B0F1 zr+C590W%V>q|!LdBOf)g?~9x&UX-Py)ErRM4E!FAjjGf!B515uyhbYOLZnGn5ciF!ZF@DZlBoD zFNZzj3!i|= z%L3k=f7V%?zM~fZHfj)|AeR~%)%!;=K#tYraoIJ`Cv0$6??DqsHzD-+u)A16a87{| z0}4jl-QeQ=tmHX$+AwTIg>1bqH)%zf2(H{E#egm*eH$z2TeAI_^isaQVpI%>>>Ov0 z)Ucxz>yWd6`3r*iNI6q{P0gu2YeWhP0On~&cUL3Vh#! zH=Eq;qS@lnS9IO>Q{=po2VcKP3%1?tq06Zio3VrKnronwrl_^TRE9@hPRfZzUdipC zRY}(dHioG$0`@x$hS=#w1>f+YFMRGbo8 zd`UcfGv=cnnDGDf5|>x_6It}X^AeX=h=307zx@*blbxcE_BNTOKuKVPRHrOjPFD|a znw;W30kUb!Obo%7l!_rYDCSQqF6>N*#P%Yo>Q)kW6sz?dW^J>61$&4-d_|S z?=1X*r8_ut?1R(msMsA>DXpCwRW=`c`s|$s-#%?#fIG+Wo>gu%azw>S=fjH~JiBDL zAJ3PVPJR9``Wgi>Fw@!`*Dzhl7?UVrY&uXe#T)nJ@MZJnu{g}k~ZJ)(2yCskVHr2P5~PAE*ybt^?k8NV&T~;zaxomlNnI$x&P5C z|9u?UcfpTYA*EHAAiKPlgt*?)b?`LJ6YEy%ySBK$iG0+5i%A^9s#^4kVjy*WPrHh(}VPMvF8PzFeF zYd|jZ`WB|ISewtsePy!8i{J;Y8l5VA^B6`gB;0K&c3|2IQUOcVWF4@wA)dCUZA-4S zJ&I}PZJ7or5?#^5qlWSWPKLBSP4>%O(JL*j1^|YwKGg@?4 zSgc_ZniwD19EBST)9f-w?&9nA3{kw*H_vq(hT?j42D`+*o4vXKdQSpIU})%Dd}r2b zIY$6*EDJ2vjS9u&>>6Nc!eLuK^H*tyaGMJoK_I79&!_UrkvES_?nm*Fn~!ju&^bDS zEn}*}>P#wzuUSV(;8k#6ZED<9?7`(*SD|-J&&#rmJYVIo5zy&!IUgE}60Zk*@RD)m zY5$yO_R-zq80Oni=0E9hEt}n+&N0kw>2hU1_-P`V4);o;VxD##N=U1X9vpM(2xj2> zwa9g2X@<^!z0r~XsSei?SBCskhijRleRjB{9~~~jgN>p@fh^(Nl(5|>v9gNxrc z@&417xX6nT=%cmEOH6VK`quHsZ%YD_jQhw;laewG3ZMz|fD~9*a`y{n3{%Jq_ z78IdiK%+Z?ro`15!Of;HXq2XPoJ1Q`2KHo@q|R=&O^?UHWqq#O+$KNg@2DJKtRu-> zfd{&iL;+t%%wb?oWz>RdR3+*gGR_;=6`F3pR~)*p^0&^+&-zO&4r8cOszVKvNz=Vt zO4X7QqIRG)`I9W>5AB~{Zq!k0KzdM8IY;eBElTgNZA!JTC!Sx{`;&n1RB>G0+3I5E z0#whWaD=oPJ39K*3m`ESV8lm5)rA$$igzlfTvApKb{NlTOAFRs%b`^rIgexz*px!t zHG~}N6jtStHH`v6JOKo@J|qg;cqg*5^~C?j!67Je*3^50;!kf|j#}Ce{TFzE*DW4` zQ_SD`gERlvD3RbR^=_%QByJ1@kTpOP+MU>syfd1L9r{FHp*;-nfv>JD#EvAUW0Q`B zTDofDBl}*ID%^PD5EIiJ+u?MTf^II{daetC#>I##0xGitO;@D+O&f@{E z0$nyL-XukIBgV)k>S%k~C{+M~rSD`I$f$*?6i_E>Uc6N7P0aysRcZo-$NR_1X8fm@ zxV%E>vi#4y#N`zt|5Gn}t5g{mo199!+L$xLBH3><-zTcnqXq z79j+62)r;zU-x)ftO;2zkOXya^9V0*%8tlmW~o zB_MhNG7Zi)=7^pAz_|x(BJS$T5mjWLjh`K9rW-ki+p>Lt8N6XEVtL`Asy6j&GCYZXA7*I(d&rb`{Hin7B-&Cl-pb{)N z-!Hp>Xj9zsj!~%wqG|6ml4d*sZQx&GqU;=GE56UO%*}ix#}{v`aYDbda1-ahvK4N?RxY@4!4ew5J)~7nzTyeDudE-!$Zo= zHi4{ma$__+b|5X~Q4=`cau>BDqF`vp@;+)H^j@7Z6CATWBMtdwjQA~NnFrnLh@s~o z(0yN-fCCI;1$rNdhTh7BLO^$!0ch`rq>1o;Eunr}H!#l58Y9#WQjJADEYv0pgnUTv z1bch9mYdE{w(RpzCMo0c2IjlfIESmbmDX+2p1a1p4hiIcm;mK?0TN*w>o{SIU^>!r zJ9Kz!#gCeVlxDVQ>4&Qcd~bKl)yc4bbh{S{nviTWCf!3L4#2pp&U+Y7EBg6~Stxnf zWFZ%&3^{dcK5#hSKOTD?K`Ywx{s32eYf%87^j}O@2Q0og5u1CR1~RnSfHum3{1JROL9Dc~Eh^baf&w~-rC7bN6Mj$kD8TT}Ei@St z?isKJ-ER8Ew9kkq)`P^|nGhdu!)m;+tBQ-$?ZoyrF3^U0$^l{@G^y*s8@i%5H`au9 zfnjy>_UNZ_A;!Ew@2{Y3!Dl3hbe%b!Y$Ni>^>}$aJpLpwuQm*>M+jEp)yXOo3S?W! zZlKT{%+*fJ;m)2YWgqq`MgmGG+AR>j4g>bK<{}Q(#no*HC_2n15|C zd_=7MPKVrFS9Q07D4BC?&_S0_HgP#zC*AZq2WU6#<+e}j=UVihp1r+2bX+*V!nB(z zHHzANS zCI>Y;pmGD(^Fn58+Mnv$Ln`srab0FSolA0i61}Ff#|4Dg~tRm9tdqu!D|$3u0SUGk&X>F zFyPNW4+T?c*bpUd*|Y$4eIE$#+G&Yf{tfEx&8bi!ZA$)}WlrSh3$X|)L z3A8z3@%}gb_n)ec7rKJj?~X*Y=axX-@*Yk!NGfI^g($*`J<>;4KRGg}Xd!ddO7{7S zo~+ZU?~7HoUB8}>UE#Th!fQ=a(Q|H} zm(56Swc%(h&!D{alyGZEOT*w0S%h2sNnNMlNP@X$dR&HxMG^u99Kukr(tO=G(Y5kB zzA}fW<#6(=lc>!)c{Oqf2_|q@?b3~ZRsqrws$058{oV0$0g1b62v?aL0%Q%Sl$$JM zICl^`<_a>*EGki3huE%+-|XvSzcO?a@_{79H)%^&>J|oCmleKo)bUh8D{j2D*ptNR zt%WF!5RK#&u)iBm*iB<+`7T2~v)%?Z@@MgkaicT;vwnIJY5X?Tu7fi3k%xy)tU)+r zR?n-jk|Mdiw%~X9k7dtXe_f9~XjTkjbahawtIbHG{mU%rRclh>(Jt;lZ_8&Cc2=-p zL@xkeN)@82h55Q}q}A38L|AZ#i0<4=vAH}4%wYlb?vjypSU1dTvzh2BNz{`#0cw-o zjqYZi(U^F(G(^X3MGHq(Lx%Z$!Ehk|8;qycF_8DTe`c!K)+#phRU!iNptR$4uio3Z zJc|lMV(uPJKIfSuT&P{N9}T>{@#he^LN)=lk8anaUTHu+*E8`daD!(Fx7oOqP9oW} z)xu#qW40MQJv@bz`Ln+fubTnvkQ<-l6h6I5t>Jv6DJDDVD684*E4WCx2TTX|;I0yX zC4_eAyL&J0H>=B8b^X1D4tS8uYh{07GV~w27wRp3G+i41EB$}$8B$Z5Pf*z3FXew) z#Kk)Zq3QO^ZemgD3n%s@uumUk^PH;I8as9Z;3sI{f04kCprrdUc)VAay!#ED6N9Kx z#$Z7j12A_00rPuchz9lTE82qi`9-UVU;@Sq?!=Ed9rO~Or2;yoCGIeS!rA;--9I`W zf#a1hnk?FSS0?d*f&~gYBw@Lq(pkPg6Gyb5sszh9%rri>A?5qCTdH@6Gs)fyY1Kgl z7i&Q)H7s&jNpPR;wuRN67^H8x0H1TVKY8Gxh-RNJialj#2;8A)an^cnw0SUr*e1(} zfs0?BMxk-;ZuMA6Ok{{R4U;x~udf|0dC^37*q6=hMblY8lI?;52NCeYudyxk`d#&~ zd)A$@!imGCt!=z#=9hv8r}IityW!$qcgFcl-0xJ~ZTp-QTX%baxP^cdJ7`Zd3uy+{yKf>`WCh`@|Tx@L1-S<3~$8( zz;-`hJ~&+$%YZ9_^_8Q*Ov6xALeW=Bz^PS6gXR#W5ct4`(m5*1XkvN5&ZJ+IXi~u1 z?I@rk!{0kfFQ|BATMAHMZ~uRP+`K&g{c%1OjdYDr0!IZDd!^vg<0jou!huRNDqB7- zQJ{Mfo8^J-SUHAZ$>FY{mbW}J^$?i@C@UTZkM0v0vB@mhJFS=NEoSfd4}-+ zx0eQ=hsVMHT@akWp#Pq^517@;HK@$Uh8KU%lNIP&@ zOpRFtc7f=gWl;)$Y~l0vLO|v7$NMXiLOKVcpMQQ+1$E1k{+GJ|)pW%8ww}q3G=5wB zN);M((S}5qkHbRPIhafS@_8^~O~&WC z>SPD!VEELOf~I*+*yj!KQ&$8sbbrIFhKveH@ZPTz2b&KLUG5%YL(3in;ndG>Ij=}& z8dGf*YVS{I4&8p=#=dr}5h#J5Ghx`de(V?HsC~WUPM?9J;~-xC?EzO+`@W&r;2?kv z#rlZdSmf%GS)bq+L4%at{L8KdGHd}dg_owO%4MMmR%ik4h%~d$t_M2L2-wyfI&fQ4 zW(VgvZ<}*iBrN^C-toXYsX)Um-pa*4L0Fg2y)NfAI~BM98djl ziog?+C0%g4=%dqRcd+JLr8Vx$huVmjd&rsfZY{N2i1WrS1LQEp+$4KAv*I}fuD58; z6!c^_Fv@2ext=q<6Ct`!nUW|X zZ>M#L9CjIA&#u6z_^pig8g_ZDJdz+na@yU!Qw6DVrB|+>m#5xY6{eExQG7BKhYJ(l zi5KhY21o_R8^bz?g-@gc+UYo2n)-rNh9{Iuxh)!D^EJfV%F#&%61x!OhW;T_nZQWasRQB zeG?96b@)}d{;5u7mpYaDQK!n3v5)Z)at7Ue{poc~XB#&@NKxC-jp+-eFu9#1Vh!mLcak<2aqH{L|dzk=O1ruY8)lxW3mo~?0@35 zW2Ml5JfLSdYoc3akeB#W_IKp0bJgDBML!j8VBEz`Ml5`p2w#G6ofN?Q`pQhAvY9I*F?*^i$Cjo{DXxWx@8=s-g(@b)Fww&Mz{Atz$^p+_;Q% z*~-@b)KwI<7Y_F$bLx*d?)y_*8Z*I3bhME>pnPP|hSQT=F?1F14Xd-!Swfc6R&~4} z5+r1d4b}o&a_3Re<*Vw8M%X-I19|t;y@g8rutWU33<>>qWjYniycjDOGV$d;Pdr&R z1W;DSV7d1e%@YrhAe?ePAN<$H3RnGTf_&orCVtcJg0l}074LWPe|i&VSwXFzGu(-5 z8L@#6_E-7VlGnrujK>Hz)U7MHVqnSxQZJMxzvD%J%*2qZ32|GsxH0eRYqJqR1_!SD z^|8dX`-ymltC01{3&gHE(qll)!!j5)XFKfX#a*n3uenu-l-*%gL7x<1-_R2GX1dDv{KA^voV@25` z25n324KL#bFHw)5{t)Hlj(3C(hRQ zwn|;^q1h-GkToi_egtJ7;=RNJ7r;hbh(k(j&dCJ;KQZHZ%=+G=(Yaqaf%1o$7{&a{ z3jgoKZ2#{>vGcopDgO9BR)vr7U-ti@{?FI?`sKR#?LYps`oazgT>|dQieUhV&Mvk? z#;4l(AXMrL2rIu`g~gxwwg@m*U?LHZ)_VzcWLX027Z8F1=j#Pn;(I{It^heMz|#4- z3NNE2Pix1$)=S*7DwpWul13Eh#=fg?4bXppFSFtx|AU~RWXfR;f7eHhV`#cdJtne` zbMq-*%EukQM37!3UhPeYXh9Zk)>~Hq)^%togLG6P-sAT`smsEcZBgyQxD6V8`(Mf> z)|mmv!oAz(m~31jAdAmK4+=F11cW&-5GCbn#L)2W{d~qj3w3H9#`+BNJr4RD?Hl74 z$T1(=z}GVb$I07M{E&An8;Pn41jf)fGRxjCFPMxX$5ipbSm6oKBHU#QodJA5GKlo#%Rc^Clr1+nDE+aDAbkv zQ8^Ijb7ZRR?dFqaopGdGcK(%~l?$70FX`-DwlLWi?yrq>J1Xu8y&LJ=1FsC(bm;AN z2C2ish7T=buB+Aws%Y} zYtP*xc#|{GXB3jto>0P6RM#@Dy}$=TZv<_wplPo719yjXrE5qJ^9%~d9l$7M`N9&< z2IVf-*apzc+2$q#*}VL8cX*iuJ`f?`x4=twN7)A7&gmHkAVDUG4k*8@43$HNvgMHG z4iBDeGEP)|PSM#Dgdb3=2nve|IY_`;Kx?4HVA5?}up=+m)ue34LFy~v#B7o<#NqIv zny=>-NQYG2j5{!#t?)yBD{YZb4u^d|u!(!UAYxt)8R*g{d&}{d89e6{0QIT$GJFL~ z+dRVcPFI!LAa~(v#pV8mmE^A5ydc&de$Pd-16}1wpSJ^mmDTHtg|uvV!xR^ncskAX zTWeqpK1!PKwNjAqENu`(>8pP|!*F z3FLD5iXMT(b@C!U7|Ghl`|~||BoJw^xYFV0*CKBe7_bHk;0}W-aaj>y6(RcohVg;m zX2AyD+#Z4MJ$`;$Am1#%Zub2Y90-Rj-T+T97Efg$oO%iV0RFiLEB+O{!X+#>9jp+X z%Yn)5H&iSzK~fT(x}Fc6hs+B6iJ)W7llCShBRb30!D0 zdTa(G$<3_A2d>;O4R3GV+O2YF-V=TO+Mdf4EHen#(s5r8d_}JIx@|~nBG;J$y-{u^ zUYZAm0avr+oMG6ex0{zp&<0}ZP>}a3dBbP4gptfzex!TpK@7-xF3*Y5?p`2u8Nu?i zJ9gbl5d=vu*01>#q1Q`$9CmQlOsIWxy#)}Kt#8;ionJW2xYt?++3r=&sFnxiyl{TN zF-=M%P}!t1lhKhw25P?MUgy`T*+$}c+i(vJZSYMtS5`r@5+tHwmwbhzxCnr4GklgT zBZV-Z*lN_EZ)_(q7_TryP!E)$#xdT3_3bg#&>XO%WcTn|ojI(hB(#suyzpYy~PH*#SZ7I-MvF-wAm|5*eT$bR4w5t;8T#b-lcR;=7 z<-z#uOyV^oYU+zRl8{5HW!|gVSzF?vvijA(m23M^UzId=5orX-6D+>zWjvi=L0B`V z$=|xO$f%D8HV1n*+4>Z|XQ#bAYEwb`^&y4Jq%Z+{|AT$iVgB`&$;H41P@PGY+ zUml;??x&U;j8QP?hQYQu>#RAy`dn6 z@#>o@3Mh6K3zX)!WCm-4-5@CJZFc`LGYLK)`2BGvu(%=4I#U;Dj`Krvg~04S{^J+e zv~2%JLZo9)U5Q>lsM_I5Ucm7!S=~G*=0@pPs>W}6aJ%zs>-bRa#U{Tz)!Z{zHJ6;q z^;(A{5SE8FAq3FYx0FcN=nn0wc4wIb0BKmaofzK^EsDN>0aC{w;zKW zKF%^(t}nBah4qB9{m?-E$Sr+v*10s1bGUD%vu!*6Gsv2ii?7P#Ax-2CW-6qoDA@T( ziu>BG0d8_P8v3Ob+LnAAEMhaiK-FQpk4XyamB8&G%StnYenpameoS6izlnx5VCf%q z0-UA3p-NpHiZFmGF>J!C;eKw~4CO$7GJ_zi# zau8y;gNfoK+^0()+=X^Dgmu92CaRYJ5BH^hyjPcgxBC8ndigiJ2RmoRT=NBw`DGzk zKEJ$s5Sy8d6KHRi?)qCPAgY}O4f0=}#oNc=nfznZ9C`1WLktzfm>d6a@Xxi&<=O6ThQt)J=d6`;4nozw~afw@veA0&%>B^S3N_=dQA>~AENw}#@idD z-u0f>^I~+>rS|a*^0K!Hu;*V!MZlk12%B?)rVfy!7AgnyboBQZG991Sb98+U9fUD& zYY3YH!fCNtoonk5_Nb@Rp;`sT|Wpd@3C=Pd& zgXjrvataJZMR>YqUVOJIpK$mWOR*3wTv9k=>gR^{3Y(2+-~!Mt3c!v2tG+h^)_I z0-*{)NSt?6DkW~~H6W?f?@pBmN3bLtFFY0nKY7wqoJQn`hpu}D>*){&One55$97Yj z%^X~S7587+#^{ia-*u>ENwheaM&L)I#91O{l%rPALphaP{>4YISPed5;;zR;G3YY%M^ zw28vG8BPU=_MHvZm~7BMw^F=jhs*7;&W^8e-9eu4x#FL~6HWj&VKi9Sy8+Ulwvj&J z;fgfYyk$xos=W7wm+)elT|$z&Wy#zTx`%E}Gi}vB<9|_7Fi#ek&gh^G?*UmqAp-|L8X6HUmUD91Nc# zwey)u3zV_z(U2$%j+g&y+t~cSyNxYd77XzI|GkZA6Uri6eUpYyjnvrY?%3B9wx#XymckM7x`Q#B5UUSc_s-$X^xaYeE+A^04$kv@ z2T)fZcf$TS5M4Cftcr^c$jf@3z10J(x81tq1>b;7JB2UkP4nb-I*+cyq}iVAU4};8 ziwm*UadjTqP8OxL9=ATJV!;RyGN?^XBqGUowuX>!{UY-59ZY0vbZ?eYy8(d(Nj%eB z3$<&32dl>z51o5${WMJ(e6tzLso6^CN|-^n2%v`&rm85p@mEi$q6cSu-ss$3HSG}I znc%wLXW_lpcBmuhp*`XvtwKbXco%E@VUwyi>aK$gD@M@xMjCXso#BhIdn0U-Zrwml4KdEo}L**Tm8SZy-Bj_*ca~C z*C?`S2k`<>LD5uQAqmw&@j5~hs%wEjEk`&!2X{RHPryyTnRp~#aEg0wk@sf4_kS6Y znK#Ij2smQzwb%N--}j4+EdGHt@vqKf5<`Nf=FK6&|Ki*RZCo&Qcn~j8LmTLs&26y& z5`O^|pDw=WSBDtKCE6z_JVc=-4qqk_I4#dc^>gqD23rx%WcFHRKFFXyZDzzjIg=r8 zH0YnsWQ9V1>e$Zz4wF+ zVWYf`y`?}5TL7P}Q)oeV7(VIQ>XO-LCW@p85Fy%+pr|8=#~s&#qzb1^272i>wfBIK z>~F}uFIn6P_t<@Ji&y972hE%^{XEy*!tvv4Ziq*YIcB!NFy<+=Zk!OW3CJh9!c>3O zOsaMdMLn62ay=nIvRGGJAA^V*zmBb&+hOwr&5rfT(HJZXuSyYfr_l{mdmx+g{I0 z`hnc0v%g(;ivbnWQH^`myIaQ&no9vYqG^-Y;T&z5X$0@t%F~y$T35S=-DZb)-NSV# z9ebeN(2u7xgf}Ir4V<9HRn#2FPreXBbBkq9Hoyn9elZJ&&7iNh=ll8k;D_PRFupVc z++fAb-SPys;mp5_I!{dG0ccm(JYrpn+mKZ!?wD`|SqN>f!l`lTw>fXxT3vDSnRMmp zK_4gJf-YCOOyDqx3}XE5E>Tc&0J$o#^HqRsX;BfN*V^RRv|(y+u29>pv$~vj9t1VU zr?*bmuNQ14zK#Q+lK!&dGA^3xLwo!e`kU4IPpvbieulX;Aku@TJO~CU>6d;H&^_tH zM8C}ppB{>zdP|7GJL^bL0fT8L4(|-UJKoObEBg5I&OvgG$KDxl@L>MuxA8X@ zdNkW@BqM``krHg^>B<6!je1k z;VTI)nw)5cxhV3fq&%0S5 zwl#l(4vNj$VAS$QXB%J_9u5-?9>|Cp6Bc#a`IhR%u27vaG)9H_n92;)6K&qcfZ5S;u>Z_w`( zR-CUl==0n!N#->phfebFxJH24ca_MXo zc5$uIRxuw}ts#&3@d^__Rf0?yt-)(?hxGn-2{CU)wQ^Sw%sI_g;aAL|++0| z;j7^iLVy7niNM;IO%)A9N|dFNML?{1$Hi$_Rq=s4hR3YaU9~`E0kJj;Gkvl6!K48!erM+ujFWs&+@9JH1S;n5jB}r_ z@`nbLX@g!XftkV&<4usXlTY3tGm+DmR3@ky-Si^(x-)Hb(J`^S;iAoUQLg0vN?f=| z;!`fR9-ts$b2qrg$F)Fs(xKq9_$i9(1_a+XX(A{oeccm45x>yKMQRJ!1I|*C!|xVA z0~*=mcbI)ZNtX8RE!Ot+&&yd25)J zJlgl$AzAJOKX3s|7PRg*4fYhe5`9kQuxqT`2v=gNha(!y9%?=GaHo($fm^)FgUw0O zJ8Nv_trL+gltHj;qP7|V3PdvE$>&J`97~WRzepy= z%KBncquA%6=?N1C(Dznhssv8Z>oiwCyYoH-dIg^N%1DBg&Kf8tIb4~lf}{64 zh>k^>5Pve>!o>x2hNQR@jtRllcLJ)zUl?6Kh{fEnycVgdci3RpxrXW)w3jFsPA|7z zc+GDH0C{>&pnP@g}o`)$1UwHHlw1f zJtC%k{(K+M>NwKTz(dG4P*_(Uak`J02C&pe9c?;hl4f*5kNQrAfTI@S(w4he3gchE zB;d>Z5j{8Sk4h4 z)}3Uf#tomNLkg6v+R%kx`&IgKo{Y5dj+a2uWmn$noY{5PD9x0nDM;$9O$O@F+Gics& z0KWtb!m-(BVpn>~kKcd{Y&3v$_1Q6am7VW$Wb|2T!UBpzCx8V1`%8}utL)o@?~hHt zy87=fj{NcJ|H2TAEEF(38HVns$K_5{i7n*GjQ3v18}H86TEz#Aj)H*_qW^+uCX9=7 zMlo80n*mZX4lHIx4lHNebE75mn-wU_DOTT>-?SpB|e=k zHsltE+#RvxQLTji!qd>~0LEyoLLb6mOeWSpAS7tufyBaRBelu{$R!%K*QFL8ul!i; zusus2_LXGlJqA=JL66OU91F|+e;fEV`1}&?9&mOKib0gU@tEx4R^xXBJtb&D6v#F>bENCzI7P3?DP@K}V zga7}U7@4k37fqlrHu3N6OrAW`uGl1ZjctlvpA-I?L^`LpR*Pqr4w?aOyMKj&iqC0~@uWA*Fwj z7GfQM0@rRPvfNWUtJ}tT>ZI+I(<4f`K!G?y%ZUpX0!->VsAez6y_gT$N?`49 zYQ&k$5CS^BhtBiGg@#*2le8#KOVTbo@zFNBuOD=1-#x7)YMg?d98Kvdw2$^>NrEq( zAxD-#m9oVa58(QuNUE*!eZ3Mo5dW_Bi}|*IZG1qRrV4v|bTR)z63|jj3a_&4WN%|9 zZCmg8BUHTew7V@8?Y;vw>&c)N7UE&7B=!JuzcwMc+C)60hAwax+j83-UAX;v5qhAR zNj4RIZXwG$=Y|&O(FrH5#&Y#&i@O`0LY?wfxr?}mwF}|K8XG1leo&0U_0FRlh?+t; zzv}|TM_GJ7`F}!!|0OW-PwOlcU=5JbHkmd$DngR|2*bylE-Y0-!6I8ipK=XVUn7+Vn6w!5ba|KR=4@1{;{S4ff zeD}qG7eRRWQ^*GcYMC6?<(EPxdP75ec?^02QJ`@6_YRfP@SgUvcXyf0P%RS(Kyg4* z3?RB>e}C- zqkye8R)t2Z$IjlN>gqAEX^>yKlp_UTpPgx29T3qcx`%2rdzWf+$W9Qi`h{3VotX33 zf$|>s5!{Q#ahakXKN>yNuI{5)lWCRcyFR#F$RRPfxYWtMC#-$%)%YdZHM3xL7d*8qivx5bZ~{ZVq)f^Q zPc=dEM{dV;VH7XS<<)kD^#Wln?XKUV>`dkEJeAF{-Vb|lYM(l^JnaV%)9x}I?AT|b zl8@tsIIgHoe5Om%KbW<(0tJPwlO{SVb3Xc3)t7caj_DZ6TXC(uyjC3kPw?9F4#eR%U^C>N5QpSUVs#)hu=BR6< zg7DM=YaeptFzow`R_zo%`M&W?;n2G9>)n+%Azy%-IGZ@s;S$n5Gq63r$cmsx`X)sJ z^*QT58Ue;gcZJ@8T^rh!ki+^d02Ul)WXMyX93dwX+|C9!Cd+Yb^2Fbj&a10)JvE)bIhDuBZ=L$cWEE^_a2|Cqoqx1*hsauj`;SwZMN zl?cSfM@03m0L>^{8kG{ACeeJe1m_1n(rgo54~w(+%;qz$Nw_%!P-B}YlW_^;rcM`_ zKY^ZRd&cqr+Bc{DqDOeO+7Q=L-juY=pu8nq#gUK23F22wPv4-_X6Gm3UMM*3a44_{ z#=9n6iZVy^JHDrM@@i8Js$e3JEs(o38kNCnAu;j!TEDiB6v7ZI!O2$G?c}hf#zN!j z5l)26sl0Gtw%OS%RCAf@o69+G<>-!r=U`e;#vMtNQ>+$%_9?g!_TUCs0YCvLSpp+Y z?k2-?vLO_k{Y!qcEKwVXm3b>Dir_CHo2z*I%Y6Eq;OF-+6nenZz#q@+|9aoR)4lz9 z`1k{)&YSN~ME4(msQ$wK=A`#a57dAD!9Nx{+_Po3`~*W&U_t$PVR#lp=JzftvNXWU z3WK>fT#A4&6`$frm_l;%>|oB$&KePmiU=+yn{Wpd~n~r1lKnSFqR* zpoJ`95K;zU(1y6j4gtL>WP3@#PTH^T2krr4p2P&&AFLDWXXd%1XrVrs0Hfs&3LJZl zcW4X4?7=$iyau}lOjrU8a)Zw(0q{@?1>+N>B$iXe@8LMxwoo-aPN54auI4?g*69;h z1#;guQnXzNc}cGe+0H???N8qmaES*nK8@+wv!9K@cMSCiy5JWjQH9d1_krT4z%jsl zA44-NXHUePz8@%Cw}-@ed(s3kcN+Q(|M{rr0w@SgzTBK$2lhQRy-RzLPuJ|=9@)Wz zzn`BicZAOnB2{?^`JLY}VDs}3{?X!OUd7%MF@u9)?5*tyk3HEK^8CF_&fy@hjv-(8 z0YCvO%ql9O-BKdY_iloL?BqHFP&dDGmcfU=gAqv^yLJM+dd)2N z=L_$Q3c+rJ)R+Y?UmBr;JVc(fetve~oBR5i+)ak!-=z!6aqU2$%S)laoq4B!9o?$3 zf8Hh_DIWp)NWpC9ehVsKRsL|B7%l;<%W^es@8Bbzo)>bU)db=4Uy5+>7nxv*Ln5%L zef#ja8I0Iq?|a(+0KQfMLJ6V)-d>fW=#ItI?13FPgEAlQPYUm7+WI~GvPuxtf-ewW zCcI5C@LDk3K@>PDfEoFo#-VvX?chFxzn`D24fj_#XuGosedu2_G=QYTa^!0&vLl~A z@PRnXs`X)cr$uczqL4&GL)hT99U(G2 zZWQpO`8>*Q99@jkdgp@Anin7#Le{oMwE>&eQq#Kg;cy_M;c?p^`ZQdmjN>uxoO*7bAuJcNsN?+-SXxVx#1m`(tWzkuus1tK|# z9H64VQiy+%lRwquP|rbP>gAWx)i($Pwcag?>ZocJ;N3;HN}#i|y6I=D93~J|&wX;g zDc0pi_c)>w>t6uoF3XGupYcdJ>u=YsbiIARg9Nm?I321 z;HdF5qVOAnQqAqdgM~cy2VK7?m0EP?(w#t4BtQ;LAOI86>x3|K>}&Y07wp!-5=3o}~`07WnXQQ92v z5XLQemWJUp)E)tt)yE`ht6(8A25{sXbs?=gR6(LnvA|4}%IM8ME380gA|x_BIEf9~ zTfR8NqDfyeU8yf91^nW&(^ja}LSB;p(9!Fo)$_+VCgN`^0}6gF7$8LMn-S;NAm2aj zqma1^dt`q77=8UsmJoIL+8lu1fM(5Xq)>o5dKy%c$wq*!LWEC^KdheiV+Eg&0(eIS zCRmWSYLVxU(~QwI~Y>FGp3j@JbU9sK*J0G>Ht-TCV)L@FJJ@o&Q4Sh!P=3%ZJy-06OO2oI0k-74{T@XGb>-k3WK zS@mFT?W(b3AF=5AjJC;kyQ#`G)$t`opbadzXWWCuM@Tsg23hv?QG4oe8|Hbmn9>1Ro7_x79c8CK=#M#0&{=t1@uAPsIOEWp zy+z@Jd5fV%M9Oz0yZA{q!0?_u7|=y*9t-}wMGa%@E=TU-tP(z93z<4KSAW%(s^!>e zek3FpGYu`jWgB_9oK>-lWi?zO^=7)QlO>4F7kj&xq|{vz>V;wzNU@iW8cM)q_r~)# zNR6-;JJI8CW5D67x=@PHdCb$%+t@eSwNfn$5K?L(MM(0JqoK`Xb=4r0(!P^`KW>E> zg&4aV;HyIa4tjAT1s-@>RQ+yRBxl-3z4S3um{7tr9g-|JA+pZXg(Q-Wa*|ybRD(w< zI%ni0pK@!_uF^$yW~YoGvC@E6*v1|po5gvkx5(9dy7#hVFAg6qH~Js1aT;Y+k0af- z!nnzg*)ef1@c66Y{uGHR7rzB*Ej7C$Wy4^?pJ_|1ElKk@i&e zkjmH9d4}cujt;A%5Mp6W>%m5Qq+5t*kWTI((loQn5?2 z&EPkYuY|yo8|pUZ7J;OrHb!vPt3tb;g+`R`Cu^UNpzb1aS#<3Lt7YmZmv2W_^f2fV~A8gnB zsb=JeXU(|#?7fJVyr1>-p+)3RSp^()0Raq1-k)>Oj}q{(a%kg0aS+V-<&X?V(SLdp zeWgNvP;emrP%pv+c^&DYEfToUXMrdFIL^aG9)bC4qr4w)p|uBSaFJ!NcOU;ze`VWH z7$Hvq7Qo5z=am!&l&JvJfXAM|a(GOK$H2c0kHHL?RIFrD-x@iP47q>3nvW*VvxkHH zt5%7{0xsMhxb>0B93pYFAB|=qW`Pl8zZL#dSVoiYjX%BG0F%!DY zL$jAzwOrtp!SH54*-bx_^L1yTXC$er!a8Qbc@btXDc*R%ZsF-r?&OwTWcV;1N4`oD zCc)%B(~K@0>e4s%S2vV^Am z?anp@ro=F&VJvjXt#(<)G5fwh4+TfbF0pX*pqH7gBm-UBhY%x`=Yks^uA~lR=DRV(C!1qN;Ei7(9kV+UWW zF$U1#ZrU?(ravTNl~Mx+S?r*V5q9-Sms#vKX?teZOt9z0oqK84VrmeD2a?IAo1HiT z%-&v>cl;&rJyGQZrr4YaJfEf2g}Xe~<9UUsO>th(<&bUR3$f>mL)R_ndrcd0IeE`^ zh=lntc9;P9_EPu$6yE$r^YJvzKS6CjQEiCbmbaFZ>l5dV*(s3yY1R+4kI^Fhba;Fi zJU)IF`PC2qLNf}j6BvO>*Av)z7Q08112A*gW6MgHwxl{f9L7LLgbQsHRc&Is1Uf;v znUmg#uB$0{w4#cw!b0ek0s^wc%}JdwA1a%3H)D4{IF8%oalBbecWM`u1BBwFLS{)d zdw>ZS1S3bgRyE^g=8i>ovlz`f$kdoKnrkluz!P z3=Z32uS-ks2Cc!)Le6w`5`%2Z-L#f1_p9*~pLVTXVY7A1O3lb1lcAKA<%K@rYdiyq z(8KK*P@ePhg`^1Ev8DQ6toeL9*oa}Rm>Xsf%WC$W94)w`s;IauLiXU@Ijmx=B?fv4Xs3+5j|kcol!2>-go=6s9pxCZ z&V|`*AHJ~Y*XuFOVocn$YhGy*VoM&^I5eQDFgqc?^|6GLxQCZ8MIRlXdAXwP(JAcnak+HC^At^e};>(?fi5N1%O$g6)D znr8hTI&@WZ@F51c9)D?G7_{n2?@3g2fE`IA?w!x#c^5)e)DECrx#^!xeHZog*=9O~^VQpmh-7!#2y22&T>%)$G%ND}@Wb9J7P;Mveya0r;-IOW zvgj@-b(*>?FBQ>reYp}~6bZ!J2 z_&`n_Q9MaE1Y~_S%&f>NL$ovqAnXRd4(Iiz&^27x*tDE^LtcP9{xmbbs<&b;3h2TND=)TO3#=}yIVLeOQZol$l zJKpC2>@TLhZkoCkfO<2$?xfX*Pw^EEoxc!}0{RXydHh(fZub7ZwZOw%I8u~{CF3~Z zawAF#4en${Bvg$n9kdZB;vBA0VYj;-&XbSh$$h~UK?1+Rasx@ocPRbb-5oe{(t2qO zG#!op8I!Hx65jO)gl~t1F!U=ozEmA?faj0a5aOqVqs0mo6Rh}_-Zz4Ahtg<7ZotW5 z@Zh=&hQ)nDLN`qnS21(;wb&fP#Vstgk*5W$y>?H@766^RYd@T!lL!%4E4vg z%6ST!bM&Kc&YG4&lE0im1OD=hunv0X3@k^V8KloFVMvi9G}8u-@(f9kubDISWQwOX zu6&XzkJeg$j|L8(m}Fqvg7g(yM{hK#Z;v6b2cNlizq#T+z2MX3@p)4Cz(cs3L9kUrs*TE(_@Yp4S zB$}h|-)&611yCWX{l#VVQb~*Mju8+~fkWSy+Jf;}QZD3#?v!(sRa>x&fAcLHB5#^BstACgrv;PeD4$>UC2s?7S2FRifUuW`fc%KU(i+ z728z=97!8&c@*Us+s!>-$BFvzVQUL#a6tY&Wcc#DZJy-%=TtnQjB=OrqkOwym?OLN z5Yot`Z*T2rZ$DVwKUc-CVGgh!-wNX8512>)BHnwm$M*ZRiIhn%kOQl2H)lutb;8Zt ze2^X1ka1r0{gOF%D1-q)vwS_o(9~`ls75qRCJ_F%h=~dZgx}`6$z5#kYlbzpG#)A* zgpvX+d#bJ{8QWA?QHxehVujZe$-Y!?!Zl&)>tRPZI}S4}Q9-mNzY@r7S~@&*qETQ; zDri-q*nNHwcw$6g%PZx?K#Nb?3NO`;*Z9tA7MH{M>RrG;=YaEgfAJPTZl$H|RfFB<;f|rhZ;Er0 zIIa46=71?d_6`5oU5F)MBYK4;Lq0@$uACWE zH^LbM;YL^y;}b^qC4>p$q}Nm^P#__B4{|U5S>PM;A%|#DEQ#2SkZ)`rtFjEm1K&h- zHM~Ibtbf(ItDqc4snd4cW|X2dKXr?H+l5qb@^-9aOl{!ErCi7tfJv`cp}2IYz_}Vt zPp32J4cf~+Gj(=1)))6`u<5KOLG06jfu@gVk3JWnR~^?70xtHIHHE#3OwM`Cc)&a} zMM`nu(A?aevEq(iu0w!=eUaUDY~EBg>G7RHat64`t`ejBa~!2FpQkIjwKdz-QpAn5CocvUybJ%oV`;yLESk!mvZ* z=!EtDqCPoSq<%E=nbBW+uqaT9YUuB(sn%p-Io{ZwGYb zrHjz_hvc!ZtV0c8Qg>P|*F%#?u>Iza#^-G>iu8`=Iwd!2K|lq6pCC&nnb`#&V+H)7`wsr3p7832a8{{cv z4X_?lR(UK}%Q)o2rF*zG@Ec`Rw)gHK#C>j-6Fn?w|F+0ve=$m;x1=>YIj^tn&Q+%C zU>MO2*Tc$1BKTxItT2NGD4y002hrKm{NOKHF-ajGw9>%#tPSAXWV>4fwS&o}A~-Ha z%1bZg9c^%e9wd!C>T+~IARn$7@q^5hmug&(tBpzem#uit9R0UzEgv^8IO<==J_C9@ zL@oc?-T})n|1V{ge_Vf;Pkib%_$WhlF1TMys(Qqr9NT9x+;_=Q_z6Wga8LGf^(AoQ z6+!1X3izGB2Gm65dHvy~E3c;qe%Ih6{8pk4mhvrF69=^F=g)%H?e)V?4I2b&ipj}y zRsjTRg1W2(H}d+q$U|p*0BF!Nr{Q%jhso$@pg~No)ahmOx}jAWZa~RR1@| zk(Y2YoZrPGI6NWfM!-PwY3>92^pgzAWbJiR@iU*p%exOA*93p{iW)}RXA z+b`H8O-bhph|fAnMVIur zn=l#?&2-9+OINDy!->>Ot8^BZc(E+mJRa{@6pAa(gG#De9_a10H$a;>p7JDek~2rH zB15DAfqW+qOeJ5DsC1zX5HF5JLD@43o^KVEAk=zPuhOQj%duCs$8D>~EVrbZH+*8m=TyA2p2 zDw#r8iyO9wBOSU(SrrWJ8ikjg?3}Ui2A*U8j)B_6>%e!5id#xoJP-V`K?p~IKo{7! z=NW`_(|vC9X-Vajal?>Jv}1Jact{{rpdi)b^+7>{xIlM(!elF9$O#t{u{Gf1 z1XCKoUouKZ3>%Pfi5+q`miX>AUhkV6lH^40(Sb#ui=IYiXhEDKwd59igB-lB3uu%d z+9Jb4w!afIzFRMvBt7)J!H&P{9*k))jq&Hw|B8ryRowjV*go(337qFd^)DKTJR%1J zH;a9>S0RZ^q_byXoqYBeboDY-o?5ZiuGmZY+N(BO&&i=!Op-1wa_y*tiV48I>6bK19eEi{liCK%1hgWz@Z%|Hz^LRd22UDkKyCi6=BgxWxlApvh*8bPA{;e7>s z$*cdgs(pjGDHe}?Tnza9RryQ}AwB{+5g?L2cL;EmeyG7g^bG=-*TVf)!2>fJ_5~|> zD6nnv1isn6zUBI3f&EeME(9{e;Lpo*vGEbRg((JbV`<6JlHBLeFb<*(|$9$S>9`wyd!(#(Qp8 zb!eR?<(%$?y1J^HHfXPlZ8yU~tIlL`y_U6LfCkER-Q5>mMj*T80Nh5w0B@7?t{?v6 z!0hklWk@w9VB=!y03zFXZF3lhjm#Vq13v?O>KSeM_SRw8rZ54B0>C+RCsho`xkzv~ zmx>;={r&{n=-E~g9xrx|=wq_dJ>N|{#wUC@LU5mWUy=|aaa%4=jkWc`772nK^NCvy z?foIFy~Ks1`z%5x3BGRb9y|ro_bW@bbyZql8v@Nj_7>s&253%FR4rIFRb78F2)y7G&#muA8@~o0Frkk{wqErK^U= zL<1s^1;V4c+@1V63%6ocg13U_mMrA%cxMvS0`x&ti)nL_J!8g$TP8;=nX0SMQ)Im? zXk-EL<-zIzFo?w_z~v0wkhR&bV$wUDP0VUEY`?q!+Gd0ZWBgzQJsW~YD)$E3H^Kb| zgOBqGHO>7#>rVjZ<3Ou+L*pxOuqPXwyw z*N3UF0i5-n1>?IV6oKSi@Mj2+v-nHUMD*(0zQ=I(?xQO~?!C2=)lxkuW{_w6vg=lz8B$g2crcbmSDCo zbn+C-2#NK~X5PsMPIMc3WUi*GA2GUB9?ob$9iu%i#}1esdV0HPtC>`0uW$+lw z{*m8?o5yt3S%cBt6&ZK=!QTl|O*JR@UNEM9yq`!ypY1cZ!y;n8Jvlg&pYO2!HsrL7 z9{vh7Z4=FffKRufZ1aYg-`jRO(8#X$Lut~aJ$de`h4DzPT1tmPOH#FU9E}MQ7@!x{ zp8A`)-M9~Qi-QqldjkrI@17z>Zg)m#@zj>`!U~B2#6zvc;dF~2$*v%7{4Sj8I)pjE zZ655wCyh8`{HqcfBwvY;UA9}3!DcvZ$p6@>|F@;!&&}6A?HqLf+&S`3NUsiG$CXJo zB!1iW5(Aqhvt@$$=i>0|iT_)1_}_Qp$G)EUpVbo_hw=Z&iT`=ve{p{P78UV!;(vU` zi(2diJfF9X;f3>2prmDCArt54fgkx#o%o-HBlr~|)b8;=e&T-~_>s@{%D+AFKQm(} zlBXUWZz_;^1_lNgS6m?~oXkiRf+s2WzB#TK&OVmCc7<~!=wA0Sqn6U%aKeMxthWv` zY|iD*AqPrt0b+K*FxdpayUi;hB4@04ks1^wZ;O?A=3IuIWZIiO2hFdCpd6*cc%~nh z&3?^ffw(hQnIXV4O5@T!feKsjT|`eXtA+G7B~Zn%YlOoVTj;_673&t?Haf=kst`0;9VsUtGhFL*o}h z7gSe1bOEIHosam@Uen;~ZeY;S>JcqM-yv$?`1aYrTgBGfN%bFAqWd3D zst6oaJ%xH#_oj;G0G~W~!!>@KK=075eN_eE*tWPYpC<@^->GIq841x1itFL7fgbto z!-saPndY(y!+!?!B;3!xh##x-uf;j?(Ubh5)3y%lZ%^_Af&Il(d$NDuCEM@wI2>%v z&I*#epS@m#_?1KWYkB&$I=!PTOx0ORRmW_7chAc;FmY%lN7fas6;Z5LqPii<1W73d zW20QS9pv0_>vXdvTpa(Dgc29P0@f0U;<|A3L$?QiEw?}m}@JaPPrM`#+9 z0lLjm6RS`_kcRZ%sNsgmwE!~4*)HuuW5SL&fyiN5?6wKGH$;KD^esHEMNK)&Qu<{`_=vV95JF?fj<@i9t)F0qvAQZxo z)9!w?j^!RC<>BK{tgmoeoR&?os2)tt#*u~|=L(QAO6wYf7w>urnCCG-bHjit9Y0`t zfnFc@$_?f_JlPeusI_0Pu%v>yNr1s7d%RLMlPG6pz8}Nm`n1qy{2@pZQ@2aQsSNN< zvk|3+8^Gq?iv2c7FQ?JEBgZB5thun~fn+l(dV{v6*8(l6r_cp;7p8S|i-^-atu4U7 zEqo6LvCXZ6&gZ;}#z@CEV?23Gdkpf$5t(=&YTLd=1Kr(=f>9c}b^(}$s@7%>@l%O+ z4KF=B8bfvG6Lo4e~#P zFnw--Z{}s}ujBO$T7}OR>TjlJ_`lr^zwV5G?74#E47SFp``j8KZ*Bpx>Y51dEa1vF z#VH5W%YkxTYT<{(2V^1Z4v6wFFV@rx5ekKh3pvFA4~pglbJu|YS6qT!PWRyo4-Xu zCoqYFmQt>~hab|^^Ya7Lz!#s&a}fDI@cF%E#L<-Yr?TRoe16YgK>MsKzAG#KJ3l`t zCw{$W{`mPtIRwcj;d^f%{0WKOC%O*OSv4a`vv%rshX9GT0EG4k%#pa4#Qic6D&B7P zVA(z_D$ox>L{H|{8%GJC&rLXTWyRDjP|f^0vJ3<{`?N@jb)xY6jDRYbYOz~aw0l~|3IvG%J1OnGcfViE!Jswz*;U?vKnGx3&p@m+ln(X!+(3w-Dxi1Ks- zU9&Ba`ox|r>e4u9;?9(>aN*<_C+Ru)^idm@dsyme7UIQcQusy-)9rlWS$q==`HASK z-GU58L*(iEmWM2I$vEYo0mAQl#xn&b@Lo`CIHdvx@PPR<@Oo-MA=h9M|9<**P~75z zUE69~j3y!Fc!a~wI1p!k{o|O<0{pQw#smYq9ih7d5{0fA+kM8%j$3qhqf02DqKmPh(-j-j!DWm`O zFYdqnAOGL~_J58+{onrg|M&kH;2;0@c!PibU-jc(t+;&7a`pVQtJVI z0aZD7jiDLy!L|S~+u+khVhpYUq12yOeY@yKOl$&auutR>Si-?=_@?Vk?$2HWa4+5; zgrM&B2j+#z0b1?d=Jezs(E!)*d2aGO74&NM#J(-@AWFKw&REJBg}29!6%?*d(9-(- z?4TSOArBCroN)h!Q=UEzE>e25QY7k7rc!NK+9l}^V^dt%Hhk0 z|HK@fLB=3|fHl|%P+2-iUC$iE9lS1ze7)+wIx~RhD}<2xvtcpK#mY;9x+1Hb;)Hy@ zLiA*TQyqL0o9WRUbBJ%r_Y9;oaJ%5bjpJ>mjwyXX>-%21DS=M|$BkJ!OC8s-)0#iT zoiiazp*_u~&3PNDJQ%$vF9M6APeQ6SK6TzUmC$3ob@g3y$R!0mF1VIif+1nQhKVz* zMGU-F3(yVHf{O|V$| zPH*5_P$XT`hu3u7?sBgTUOYq-a+&AYRIjeR4T)%>2lx=WDI9*>$70JHF1O$-Ztquh zcM(_ZrUISCad*Z~dq=pVlr;7WKqr%o1(2e0jnuI#lABgtkVjLm&m{kp(aG7NSwWdF zLwNg(Gyh@%ea*=L`t#3SZRE#*`1#n@#gay^DqT+0b_ULbV(%Bsn)oS7>|0k`9+%s6 za*@uTcD4?L8HyDtkT4R}j>%ZwL9ZZu87RE_VJ5s%rtU_7wbBx?#@>*jxxs^wqDLRK1#NjWK?+4-pbTIH|YVp zE?UFMo5*z1B_CfenzWly4x$v#x85b>OC2C8$T&=2XHwRxZ!6_KW9~tUgjHKv>*5yl zR6OiAfqhV`12lI1i`raKFXwUjHpcr}xEOR0-?fukoOMvL_%3O??Lm=)>D2Mo&cB`J z!N?;BWH+|I7Y>_a5R89C5b~|Y@Xs=+qqzReD*^@EKj~%vX&>Mo&j$APbM(oQQs(AA zp*^2XClKv^?`6;|hK&{K#TjKmPdhm_W~3)zmie!QZ=!tu8){fc4tB1JIZX1KQyje6 zk_9Vp8qrh%=F$X~ZTPn|fb6*NUHluS_&K(JP3_-sM9@oC9_nj(PVVaZg^Pz?GdyNJ z1q)yV=Nd>T`rc}dfLQD<a7jbIOs9(DBLun!Zx=vY4=&zI_<=aqkl#5* z`PL>_@!<7q0lFqEY4ZIMy|TQ1=lw3#OSW5O80&pXQBthT`_T|?uo)RTi#h1hwCN5E~z3!MB+bS1*@9B#c&K~qpK1pb7@wLP%aVqeO@N&?n6!Z_EM1W?y$*=P#ts}B%6U+nCR z_8gl6`+My@d^f1tnKls6{o=yu#HNQPkh~Pk;!DNm8JEQ)bL%P>kgD&e)Q0I(pI$1x z&4t5>OVvHSf^={bN@c<5?-mvfaw{UVwYtLFR{6^FWjqV2^K`nj%j?DUcSi_|fOtr4 z_7h-Xa5sNXFT4fSYyqJ@gvH=`nc0oI{=|cX!PyW9zUw!aHO(J85v0zO6wrwwXjXc4 zriHO>9>;sGxVW_j?)2&|NGm+n4h`EuM$hTC=~inrW2{V+(j6sc$k@;NIamT`4iySH<8=HYcJI(Ih=k(FbW0GYG96e7?TA)aCV2oz%`w7LAmga;?~^!G_vISAYxJExh?6w@%5$+X2?E^QbM_tXA9W zF(jTA81U^u6p9Z~C_bP~esSVh&cJehd0ej+e+~EOGcu#<+%vg@s*J$pAPBT&+ib0WjS!JC1FI2+{w3%k@Q;LW!0JQsQs$Al zf2)>0b~qbezq}cFpGLr6rF9I*gRrg+ z`GxmMpYu(Om>{^BJ=;HrhRq>`Y3}$VBu`!Nv+$^5fHh;+!VP?_RwHcHUuM=Wr}8!e zQb6T|J+tfWYw6IV>!}-n_Hj57ls9E|Zi^@-H3Z73#XZT~;cgOf;2pKpiuO>4!rx-LZ!+PV+_0>ve+q<^^PJ z|Ez2wU(2=d6@5Jol(R_=T=pR8zf(1^XT)U*)|TDaM#a8_Gj5y!v~0k4(8I6nnFS^J z+YlD|i;dRU$9v)BwDqdXsZjSrXAYPCc5Dd;GKavr3Z+&^1;lH6V2|mhk*?A# zQh}$oI#$@aamY{$7S1(L4xqWBT$p#OJ9~(Z&tRJG&j$!!@K>QPX7Uv7ji2>;v9&I@ zRcvk>LA%}D)*t+bs!vxF@JffrI=5wddQ@{@lFcDFIpk43H$aIn&Zhme6yDj+6^Gi2 ze?JC#7mV?OD-~UBPN%Iz{Gsaynn*h9v*g=;@=rAaL%&7M)AxA8-@7YG>6iMz0xqES zcFKY6g8|Q+1Y|-n1+psa_*vAozW)%Uf|3D`d!W5@P3#4G#E;G8`ximkC%kX4Uw;0@ zeF+h*AHlKEGP_#Jr~T6U5+?igvHZ_x^!0>*fAhaTqhH;b8vs>;74v&a*LQm+W#Tzc z#%_*RaNk4uX$|i8MG5>@==dkwOu1AHkE*=%h`g|l3%m#pd=u)jO-&$s91jeG+xq>O zBNvlRC(v-7AST05S0R5CO4`#)(M;)+)sL`?;nSN`hh$sdt9-GuS3z&I8DU?&-z5iu zdXo5ZSr5lh&waOeHQWA-VQ3Q%RliTVF3T6sjCJ^qF)n=%XkeRPPEf=qC*k}UZM)f| zbKVb1bDJ7D9BdP^I#G`1(#&^n&gD7V?yKW=51{Y?bkn?S(awS_ogrYbNIhDb16^@P z+vfW|@RVV*R&fU@vZHb;lq7>q0@tKEX(u#T+>?vcvgw@=!Otu$-mq308WPle*l7#{ zwE73CvR~bq2{2MONj(38b9XYo8HcNpUTL49H`2tNJFlNvmx*-hc zE}`pd>|&C=%y$TeY^X7jT(|z^eh9H)&@fvu*!=@d8NNX8xG-R2$54xYTr!`5G}HUpJmO)i2#keNfffu@fnZ3vx_0vDWRjawjMhU}fdpAy15Y^tJY&kD8;tmVltJOKScJzFmT zV0;lBI|Pih0SuN}t4W?Ec4;zAoi|T*<*g4ZN_^*SQLFJz_HQ zx80uo-tC27taRdcsarv^N%=0%hz)#)$A@G8?A$4CtODK_fQ7uL8Q|e8fj|2lj|~=z z@+~>=9r)UUfYUobKr&=g!SL|Q_+t*G@P1q6n<{@%6v3_zP_ZQ?@8b7Fz!odGZ69JI)NQ+0IU$o{9Xu;!ZmJSLwdEm17{oL&il+Gq3&^k+bc)?IK`0%K{Q=Vw zp%KPux;2t;#b$7wM=R}ZtacfW5UPY!8qTh;q0&*~6y;`iVKTUL(i-;q?_5 za-|4w26P(N{5oF$#?Xd;h!0*pZxRgrS^W?{y!+w0%~9EV#IBPs*oM8Ayd-vkOHY8r z>FelSpcH|pH~c$C1>$L;b664-K?F1Wmluc-K4F4$2@g7o1P4|Fo!q^D?$6}-{%@Gj z1$6a*8BV4Iue^^>Hw3Q}p-vX>1K`Cig4(^G;Pw8y{r4x{y?^oJh2aI^xPjn`_X)rY z+Hh^Y|G?Yu0Fk`Uz=u~LxE&$CpP1FwM7=N+sj*PoXk+;iqluwG`EIep&s zD18=kA_0*U!6zm|xD)MY-gpuY2 z;?^_6;@4)w7_cW{%15WaWWLS1K7%~@_lRM>sgnZ! z_m|f6!?#Z8?@`2{H~7=tkXGI*gY+9Rfg-lQkH3W6@}J<1CUC`mbmwkpI|Ydw1aG4l zu$IW_Jp+Tbee~IJR4jJ)x1T3pWp2>o{7PGg8=bv?F&5_Z79iU{<1jxSgvTIcSXkfk z**~4lk0%3+%KydL{3cD}trdgL4=k?w&uJ2!b~z4XSrJ8@H=UIhT1n)G8asA-3`r#X zoS7zX$|%~v21zpP$#;omgroNZFPj1sq}DuxkqFyo=aG>XeeVQ9;qNl&(pPI5Vm^K^SU zW8aQ`1W}{txt6k%(=WyAbT;FsEF2*07gE*E?l@FIy_X&$0;H_R-HY@L3506(EJXBJ zt6BmGKeVHC;6<3Fg2AM5#q&NW$tF|CkWO#eyv5`y$~FR_AJBG|cMC*H3EO*Q8B@w6 z;LuZm@@_CS#?H7vMk%9FQV3*$)Pi<5+A|^*r7U&6h>yv5Y^BSk?Kc+E7}wOk8NCJ> zz^X6XjCsD1wQeY&j2`Xm*NGV=V^OYC@x};Uc&F8VfUWpIKhvE-5~a>&#s@^Q2Zwb7OHr z=C0i>>z~M}mbV2qn1mwcFWUF4{8Za01H|5J zl2eL~Kw=r7`KvdMCXB(zP123>1$MBFYj|Rk3FIbL(gL*QuqX9BYwaEjVkTP~=^2zd z+#kkX;*d_;T+hT(<+l+w9o%lFj0>doKJ0Z-373cfkbMD4fD^!*8?##Jw5nn#ZV7fZ z(@aWqIYAKRlDV)E(XxTq_^nA$4vO|De(+zmU~4^ey}kx}Cely@K+o-|pm! z6ZcS(!5xVPP3V^2$w?omEI>h-?wrHi>yFvM1YI$qyOsUXIn~Mb*hRM!cWm{|HAQjS zU(Pp{kVjjZZXV$#-oC7&?G_VPWD%TB_eI;s=kf&v(_;fVKD`tn!Q<>yl|y8Jm%53M z(|xz!tUz~I>n(|ZU2KO0&_uq++iQ%qTDz7qvc z8m`pYPR00$E_SCq0LLPr)L#9ZtW@0$Mg4k?uuNsH;hGAAcOsB~56mGbhK4Li<)eQ4 z+PL^shyH2lV~6+BhkX+*39ftK)4Yd?lKs2h)NBAP5vG@44E*;H5o z4t%4a%33X?;2fXfZ|529d>6>bmo(#s`{G??zJRdh`nm*E zdY-87K+SpWVjpxydWo1#a@5XPjaa6G8vs7!E%|yq-+XDZ5e;A=GwG+6;Dou>q7qnH zVRG;UF~a4@;{E}BrWHD{cgxx=lDIr4-HxMR9ZASdi`grn!R|y}gQomOUHgF0#-ef; z{t57V30bnRAHuWz>K^4ZHGC_L%>FK*W{hqii`@t86q!cqp?*Az%RC#reh>ikG7hc? zV6qDs_%D-?X>Onln6H%b|h@TEPhN` z1f+RvL52H$E{eIuR~WaM=dI0vb_hb(`WZ%ef%x(@hQBj*!P3r{AnbEvx#elwX|C+} zv)aUaX%B5WU^Wom6&PA?<=sEP#L3J1I{u!>E_tub(d;|Z_wT`pdzP9_Vh6Rfqy=P- zf0s+8zi<}YPD`bA5Qiar0SDgR;9z3`eZJDM#B98qoW?F8>D_#N5g3^mKz$^@0LRSo z{DZU>dQCsLDuA4GD?q6?ZG7{skAc_{bYBM*z7Hr2{=AzWAYc4-AWeP_lVI~jUu9x2 z!KhKi`dlYRgvEzvvVqBoR+Q&w%PT8%+?c)qs#r8@kqvo`lF!qRgFH+Pa;;y_>6lvF z>vc$`hE**sRlW2+Ut<8iT#(`=YMY32>2MC+6G(I7{H#Y{=DVZ=M5~RL@>-lC6a&1m z6bUDT-9p{ZoGF=;`4Bd1VY?HNn}0q#=YijAbFq2p=2#~7ZU1~-q4y_I7w2@$HDrH=?o2XUO0QceCsxskUa!N$n4 z_Hj0gdwXVUcB)1i8~LV_?U|pBEP14{qp7I2aDkiHrN2WI!SFn2iEpRrr4hhZsnqbz z>Rwyac1|lWl4M?zIElgr)y$S5wJu_iFZFS#1M=KKCgCrH!bBGohpuiLM4-`DuH*5k{h^{lbz;_w&_ovbEKnuwiP#=L? zsnjHZ^bdyKRe2v#Din@a?%G1G`h15LomuZ4o+%-8H^FPq;1$r`ZO!&MbUUgEy~Qbb z^Vo=M898tz8=c_k_ja5bx(Dv-5&nr^?V;HWg{%5CP}!@?QyDmp>I5l=kilc{Y?O ztDyvaj1Pnl!5haNVZc+Om=)N+x;_5r zR`{$&3V^sV?|s$}4r~F65pa6spAPJI2Wj)W)BWF`?YqVFujZ8Bc~d}99{;+?y(i|N zy5ZC}5iiq0aic@tI9o-Rbd(6g+%f8f(bXxxoq(NSQ(8(ui@?$zsKIOJ1Tbpr{UAM4 zhV&r4Zoz@diJh$R(Gbr}1)bf>HWk$02cdpxhO*SRWtZ2JwUg&Cyhw%OT?KCI(n!_= z26zUhcCosC4cB2pPjdog7vxUXkW8$Q2`=w#?>)ZNVyEzhk z;H&+FfNru_Hx$Fqi_=Rl{-_BC%=x%DxC5USp#M#P?J`tMNBDB2kd<}mnH%93W|;fb zQr1Q)>#(s5rJ~3>r>dR%#?NsJv7LuYqK&kBVfSYsqP#utaj|sieZ4QzTj&%>5#PWQ z6t+TDQDt`)S3ti(R8k)-rQq3E7jq7>p^*jR=`#KEGWmVJfRY73XpDltqW>{paOF1N zda>wkhyUTi{L}TvQ12P#^i7c}!d7^z&k*(cx;%dUaNo=|_%2bu^g2G=2{7*YCDML+m)yDCBEalh?sP*;8_ zn-iMc{yGi)2C@C3bNQ*6@)N7qlIe>dZ}dV_v|!wu)HUVmXC-z0&ZCK6c;}x7|HH8# z(X+h4FdG(H+KEB7e)X7ixU7ONmz7+l;O+Y9G9tf&6=`v&W05@EmHseqS7gSKc?Zqs zhr+Bf;=S(GQOD@HmCw^YILvb$i-aea*Y^BLO!cGCb}4|%Jpnh}MFdjVzdi3VJ+FxquTxuFX-KsCNL@hTxK zn{I8qQ+fV&G;!|)Nv&Fia!~zIuN{oYYACdh)dhXAd~faNfu>_qER&jY{%yTy{)ZbU z@E%A_@rR7Or1aJ-fO75+H-X<)Xn(ph(8K%A(0)^|=!RIS8j$Y9Ga7`ggF)xMAO2=E z|4_5+f4oC%Ao>Bq<(TFhhAma%A9LcsK1M;JTMc1#Z#{Jh_zGC`fdFe_7HAVM3jNtK zf>ru$gnB0DOqPI8egJa>L%(rMbkl2E;5<=abGJngvzVdT`mkt0O=v{-j zad-U~0KVOFKRq^wKd?XECg&R~EZ{4vKJQtL#qVzY!x?ta`Nl`j>63RJ-~059!wm&~ zI4dN|nAKA-6QJRpVXzw2Y1Ar+VuytrVW zqDTvv13m0O-U{uP_ht3}x5Xbcb#E8MTc{0!A@MZd6SB;0jDyKba587E#P6@5FXu4| z<%bK?^)t5B)X;`R&}eT+Cwl>~O_}EB{p4;g+Z|Z!+r^Z$fT8w){vQGpTOEpl063CY zva-#H8+|*?r6nUdog=3g0t&)rRO8q`57d@SPH5dL+k?BwmN# z5*DhQ&NGGY)CfFgv%04q(Y&?59!JZHx}{?w(9uV-qRe6(que^3@LL5KQ27NPN?UC3 zYq4w0bsubbN*i-wwe*r=U$3+0^QE{QGDayOC<}A7Q-8gE&uRWZ|NOGZZ$4v|KN}{@ zr|to?ET0kcKM`<6WHjWfy^o)UwVofhN5kBPepuA8{JKtmm0Z28#Kb#5htNsnel8(? zNWnvBL~MIw$Mpku*gaaFm9-~$(7fve)m~-CS)WG7QCC$lDJsHRW>oj#bXq>yG9TnP#de{QUUmukr znHUX=pZ9-Tr@6B6z4F_H5t6?EbPn8t->$a*fj;8?R<;%2bl)-%tv;ln!Y#EZ>2E%# zw`Fh!PZ*d)KALL`L~Pv+aDH#xitWEn3g3f5u-=nzJb|76n6%SC(oP825wNMU9~SXn zQg}Xpw)yhIFG6q-yu5&6@MXvQY1jSbv7CfehM4(Jl_8Liz*fuQnd>YTtZL!-V<`_5 zToaz~n{53HYS;{tPx^pM~$gEq&itzPSur5+my*W2ZZjoIPgE zG6=)Hp-kWmn~aw)Mk3P7S(0E_9g9jonp-wW3O}`h1_-?C*;n_)E}HhTq-aULQ>4@B zzCXLr;3Bc{)msT4Db$q}H@m8ZHa8w^+edRa7IkT5F$oz@YtUDYzJCFLP&k?HHCgW5 zc|XcPOi$LLswC~vUJ+kjsm#D0sN~*)!=~eP`@mbtb;MSAJq25w0_2~K6IY0C-)59_ z!mJiR)xq%<>iRLc_7wPD`L-{%I+$~l(=C=q2+i`iyxd%=M-uuHC^WVPd)8ohEj3~ndp!w9dP;mS!wfJ z!HnQ~#pLqtOWkF|w0>`2+ySEuP~jT+7GErn3mvVw9$zmzoiAmB^k;7_ug{kV{~j?3 zr0w-~xVNrEHWMG7p~(`GIY5gyei&Mk7;Z0U!0_q)p0yrq;xR=$847n$U*V+Rt3ZgO z!aP#pkb53m0@^=l&%hw$$>R^uTHbooJN?5&ypyeGJkN<7y zv#7s5k{>9D(*eiqccL4tfr23X(-Qb~W&C65d3;wjef3p1eRWs3)#(Jq3cDAp%Z0Cj z8Sdxp?nh%V`lT_rF&KN{L2v)HSY!4E1dDz0#6XBKh9B11aBz!c`OfFvmU z5KP3F_IdY9&MY=H`qj}{h(N?kA0 z?Qwwh{|@nOXN^B8r4UP(3EU13J=(@d+ok>UjM?XVd9oqH=c>gyaLl&Y13Wypb<2#y zhT?10b4x-*?C0$5>9Yj&8^@tIE@Dy@xM7hF&T5lypyaTJ{lIebT^IbUWIv!D9$ZXM z_q_T>GxUC=97#II);!Ewc96D6{5tX4!DnA)2jf-Sag+(;5L;V8CvI2faaTW}sM8il zM3Aq>9QOr#6&TTdNNt5#cNNkjSk|wPx4zVmbb>dpH1O9e<`NJDokQT=@5|F4)gO@i z1F(G{Zhi%keMuLBsAv|{5m(}!D9CcW9Z@j!#ILXrK^2bh1qZ=!!A*3jp*L^IV}F&l!+8tC#?@Y>al4VY z+3^4&QtsTO;nLa_5&-V=u17#i;2EQ!heglVwdd09`lv84F@Xb@Jrn*TK)cRX?+!54 zDSI`-R04BOq%Cs5_x6sXBd$Cl#(wRd!A?eByO&T{S8RK%UB=u2#7>jj8?9ZiI}>Y$ z5tPNWTql7T(RBy+|J#NV5^)CG0cTdTKpl|vl|kMobD!!m1vCXu93P5R_guYjT<+GR zc(MFrH$U=ZqUS~9;SQHyajn557<|nj)-1_~eYsv@5hKcx*j*vSm=AXm&Pz#od6>J$ zACz&#I5b@rdLhsbzDM>1SyTVTW?kjAT@yz={M9S}q6GFY;)I?K$KC1jr)B-?^8WY# z{%OJI*!L6&S-&p$g1w#3=V@F`Fl+s8p|^k8lp8Ps(sPpd@KwF{xmWv5uLK&SW2BJ0 zQvm<#N3>1;#+U;`vkfXpo8iUj0m*0Y$39oVl7kI93KSamr2=9Vloeka$goaB_n8LH zu628_*KfBBG?1BZk0~r9iM$B$^N#b5$%23#8``t_r%#6lHRC(SW&#Rj;Q}K5!P!4) z0%2DV5=WBr?jpoSkl??DJI?ztsOsSkA{vl`vr%&aRe(08<_WC3--GSHR!Co#-CuL< zA**VX`pF^_>j^90b$$v+A$XTT-S67C9ypM^}Tg&Afz=(3KMz_ z8=w=KTum9V4UCiTO3fTmT~`9H$L;%3+mJY(lebqpVa7C@6|B4#Sf^=HlgB~bwZS^E zvYH%==NX|>KE|Icz3ZcxlW}2i-2I6vPL2nYlV|P$-duZ~SV2+L1rdupMD|B!z@Xc3 zq>nqKig%F2W$X}xcrM zi1m)gnfGxXu_WQLIJe1Kb*UOyhywT9_^e-SL9DhCE>C#9W=}f2v6n?T@qlWJ1e}D0 zGb%ZAjKEBIQVTMp3$KLeT|KmcWV3+t0^ue*u{YDJRQDoA4$ao#ovTye6)1y~#S@PQ zG9QV|zNJ@F!bCV%O> z{N`2#^1ZQBjUxg0BFJwef`M204G{1P8A4>*&nHOWMLtvX1kU{?H4!)sVs?JE-(>2~ z_M7U_LLcyNOUn2GUjt7Lq?rO3Y;{gZQ*LZ9d#YZ<|s= zP6T&+yN19VbOB!z`~p0#62#%d#`NKD0x#g(z65@!5C0Rmk=_^x;N?R?2?3xrh|m4a zY6_-O=pvCJ-e}eC5Zu|*X)lYilM>G+g_f5MwjTQIbuFh&t1Dac>KSE$P+SBgnJZ z80USVbQ3DNW+v|By&%&Rvk(ScJh!m`v(X?j$A?>;UaY`OyC>Qg+zVnBpZ0W1*Bpy1 z)6_DIIcc7@u^_}qTb{Ps#>-_9Q6ms+OwLyJ<9wfT-9#xASOL|+# z3dWW&s-@AJZXP^@wvuDK5zC``kgw`lb;v+Hn{aKg7j(Je_9DXW-av3c7VS6cm1CAd z0uQaF?Rcy(BWpdJyeBi}u1f_Km65zPl>TM(JT_C`AqEZw^l zvCF!&9U+}(3QtcFO?VZ@A2YKsj*6X&Aj8hj{o!svpcNm5wpHu(A-kaieh{mR<|@sp zp{zW(DUX1i6CXrN5dH}kXvi6i)=uj)vWM^~BjkA&uf|aEnxQc^y=Pto@bgYhjEs=T zxn*~WIT$f^-Zv3?Us;f`UZ2Hq3e!%M*1N+PdsOe@)JI7Z(c8c6QH57jx6%I-G}RAv%byAn_VV6&;@@_j zIw4aB2Tu8ZM$#1`8~00H#eW-myn#)`@z6QPBdIDNqhfboGQ{Nu_hOKVTJ`ey(CoW}JZy9z{x@}ZOI>bi@nsg~|3l2eZA!faT zr`{WC78NbfQJ#D)iiETQGUIg#6NpabALf-Aw4srL0nIDp?j@eY<3KDB>qvB@gL9hK z6*N;XzdHC)osuU#gJ#x=mn+wRygYleeXU{8Qx|zcr~$?RA;1pyNVN0hQ-()Z((hT$ z-=pf0IdC`D5jp6NQXP9Ay{l9yT7P{3h1_P_xV}>xjiOl>&=1i1P73jw7R>arYPc$H zrnl4WO82R~1y0=L9qQUId zhXMrN+mjc%6_8Efa_k_3`4nGLvTlKaCk#-8rGoa#LUuE4IxWA?uvCb z4N#{r6iA(Ys*%5yU%N>IbuPInBXh8XX3Ju{-8*ubzz&m?bUJQO1g*CjjfEPm!e9rF z4eTy%c_lp{`_ZG%5x}P*?7>T%GZPgo)DzH@Ajsy(qfk&lk`On)YxVb>Jn^8K_8gK% z%kfd+#5=aruR%@nW^u!Gval%77qGm-d?DE<^LF#gMg2|!p-tOObn88@gb2>uo#mSd zwWpZN<)i)Fl`xR`$-bcd)J7R;Lqi>cyGZU`*C+NXS@ahPwGFVY>mdFoyMGSQC-mCzKpW#z;=PREZ)^{7db1}NO1hp(`&&FK~A{{*XhQ_vZCZA z3-mVII`lps`-!(Hn6)b)?e%O6K=DT0K7MA!$R@sroxHhvE?GT#Oj#=eOjmNox!#8D z#hAx~Gm9OByU(t89sLQLy32EuS_q*_%E^hBhxwWtQ5_*l(-~s@wR1ku*$RK)U=vTo}XrMiY~JeY~rb^0WIi&gHKc;=sV z8gWR2sWw^X(EuMm9 zI~h5b(bpTfN3N~M_D5sCJx{if3~qcu^jcv{M!V(tawV+h(Hb~s)v#CXTmH8-wEQf4QnW@%oeK}D9?O9bm z#bw6ljvpv!%N#D+{;_eo>tp50USC~Ob=2hMLPxy5yJOKk0AVs7fE^--%yEA^4iuK+ zTJ-{sn+M;Cuk*U!OY*1`*mY6Y|JB5QQB74vT@Zb$^8V*95as>3Q}U-egtuTANLt^9 zfpB-!;958py?6G0z0}@=U|7a}&3|KW7E41Q>o+3Q$pX&ryX^p+UjS~{iF<&?bOl{- zh|hd*#tQV@7v%Qt1pWgJm%Gj$SUaChlJ^=2Dti3efdB(G-$^{g8#iSrq7G@5>Pvqq zd2&#Ue&#;4w!kG3N$5M%KR(&J0Q#syB#Wp&*EvWjX4D1_%HGXrNad*D@00&=29O-g ziW9`Dzt^^pn2#?Cj!&&ENcf;tQ|tjp2^OJu1QG)$`kHM0D{Iw->Q*33{KhKb7 zUajgn2K0*bL;`Bc8y263u)@BZ`0#lY4_*X(h5~WUkYoI&EL1Q60AR_ZDp$}0ec9c8 zJFZm>;hlQ<_B64uQ7uWR-3}^%Gp}^8aDXxWe9Mi+fDZ%S=8sR7*egbY>ZMhv;N!D} zy9o4$QaDB|f$y$BfHd4(0OtKZ0~Z3NKdtRR?)-=d{LlMAa2up1LKz^`X(XJYIr)5M z$DWFCDT1n@gQJ&THFyE)5lOeZHovZ^>z|yL|1hfyzAtF@j^bmyLQovBxsPnNbZ&ce z+5XZYWo(Jhn?$S-nY`tX(_M2YE;Wtm2p>TBIwl}MNxicopm$wOuc}Hy~w9Tm&r|NaI6vJ~?QWMc}+*une2^`$22=TS(j0 zA*BzPuUMiY8(3OF9FgwFsDcg7@e#!KYGTXal7+mztYH|gh}ffAaY(S}u12DMmhRU9 zEIYCMU|2qAubr)E9d&;c8&wss;ousSzDJF~Y`c8_?9Mm*VQy_G9Qr%IPVp$AoLcME z4)e?qn!w4VXv!O(8wGr%UGws~B||I$y~I>+9!O@qJ(7Qtmm-VP7}9d$>%DfE-OuWf3*N8E0ULo!SB3Waw6xZHtHJx%kfZ+3GTqtR7Tg9USn z-2-r!;IHR~4lythteJ#9F5P~0E=OYB?q|HxxJ27^(e&Kf@=)HYG#p)V4|!8*zF7fx zc_)+oQH05LzG&(yVevR=5Js1_`RazJymzV!!b@}nh{&jiz^Xihp-Cn11v=Fzg%#G+57U-`iQ0=|4e%Q5K(AN>`w;meR z%o6e4uJsm1IXw4`-1Z3`JruB_vIE=)s*fi4mmTpxcCJLi>{emFnV$-Fq0Z6Czqb*; z2otbxjfWVW!so)pv!jVyFgALTH^%gMLxmFob;hb_hs-|R`$cO5ZZCUtu`3gPb9l;{ z=NgH!1!IJ9Z3UcSF&8_x?GX=BbyX1O83&J?pYt7(u!yK!I+@kQ!zgtA103cySg-PB z8x_92F`SlrUWYvhHtQ$EjeDf>!rR?^;V$*n)S*j7;{{dhFRd1<(w)PRe98$tGwXHS zAvb#~plDTkJlhDTjdFtab&?-|8u*lf8dr7Z-tZLmir0Z$+=%P83u3Teop2sP>5_d* z)9m%R-0Mz-03GtYH86>E1hUQ2{l*m|lXi|<%L-}wA>80@oV{+`qoE2;@0BybrQcfaWa&mpI)WV#%u~l~w)S z)_5{UNP)@)YGI{O804VOSPGb7#D%KGGtnsbtE`Xx0z>{l+Pp{s!cnVP(^bT?r=3cX zc>l7Vc`?A|_Kf$dTC*^)9yRcE>ZPH{Ks1l3QotiRyjrE)*Km!86qq=Ub zG-q)NuvOazV`;TJX@M8bu#d$lpeRrLWMm!1T`mbX5ZY2a#>$Z}Sl{oeg6_9CVP{6N zxpD!cL@S_JWbV+Fx62Cv9k(tR^yJpv-I7Z7XSs@5TmG@KG@-*qTHkW;!0=J4yKQ}oP3`&*m1X~Hf9d}R zmE{k%5{v&TbOX@_NAzQx=@5ec$jXbEl9?}_XO81#KS z_vX)ifj{=z4k!fY zS}1~$1DFHU9dNvEB7a(dc&yVZ1x3A}Pa4O?yiKz-cEbU;D6P4Q*@O)_c6U z=iU`i4nbfmAsTkmU6s$!(>e_S46-i^)6VE97&bEATfczKT}ukb%&4T{NSnu8oNn!E z?3+ZV&gyRS5XGIVY3OT7!SgJDiZ3|7Di*qi2t}(9J=o^3n@q3GxsbYwN}v^Iy63i< zoIKh3NAD?cXTAW{Y^aeNBq5Sfyib#4qyk>5YC>!*9)*2V=t=iR;(*rH0B9n57G!Mt&Q?ENotVcV zpm{G@{r$S*P$4`3h5^3C*d^BYv^buZK58TP+@s2dN5;VRPI4gc>iWP#uJ3{uoZsyC zyA$oxx4D6>pNNLDa{whRZeUmKIKL9KgD9LZ@__%Nh6N@lUJ^%}>w>z#n&@XRJ~Sty zL=MtEOb?MC75yVy%v2@WqCW;$WWV@u=IyrPCjQd#Hh`wxu7z$CvMAhF$zq}(qx-#nHI9`1|79be8HPtgE!Zf z!NqhlKe)3Ai&nnl6m$3TJp<;_q8SK+`UtlBOB2fr5*`j_sL~GH^xR8>gG+mVE9;i- zo8$$f&|)pL@1*sFeZFZm5a;(#*&oW!;ujO6f@i=FlLfZbt{eCE{V8;qM-(M=K%?~Bj^!>mBG(ga*`)E1Z7G=MK%7PvE zB97{d@fGqjqXG1}CNPR&`}tX(eR(p{k_!eRCxRKeO7C4Stew~w)h~$3zHDAWHV3wj z<1hQwjH1AJ`UrL*W6o9 zHBNIwc6X$Q$P*|v3}lHHX&EDYknUK>uxmm71QT$8Wq&SFfkl^uO(6opJA&R)12gdiWw z7qr#va56sncJG}e#NJV)=vUBkgs$Kl7xKA8ttk)V6Xv}JLh|}&A^3AhVfj-A^3UNo z7?{Vv`S6qXABH`a0IkRG-v7jfq2iBfuoBc@0Ac=6s_44F%pnOK+0({Hp@DBGGxN14 zIky&^I>f`Opb}e3#b{>k8|j(l{T=AqI0FcN&?Gg#QR9}kLgj;M1Z~3x@HYVRfA=Me zZvaf#Re#HQhEBv=iq^b?9z!?=MpqE;0snA6@Rc|J1X%tsl*#zwCa}vbiygj9A}48w zgel#VDbdUcRJstHdp%kU*4)H;jh`F5f!)xP+Mx%^U0wp&>-Ls}v=dxwHF;mm!Webj z?a>_@f=8e<2weh$9FB4e?xv7AwYe);nCv1?{Yr1PPidQ_w`YtW<@xMBSmG{$8LJ_o zgJ;z9O2>fh&7jDGoL&`3o}3KC@pMTBIzJK3>$=1D9EpRHU>w3ttfZIinds~j7}BcJ z5cONi70?K#R*0Q&^TTOAC6DGR1$OX^Ac(s2qBlRA6Q3=rz zXU-VtVU}`y>?5#g5-eWh7KZLsApW3;d=1^_IgO3!bzR7w)`+?@Ef!cm-s{K&-&_^Y z!H4h5ZF@zi;w^tfF-jmaCamG=y2=x!VJ!uc32om_oG}yb#=YaDS zq5=RQ+4vRS!)geL+F&~ex5VgzZT7u6|NJGzlHPe@-+$?k>-GjhDSu2g`*2+RdELJJ zcHRC8&;Pb?|8d_rdFQab$3`VYK_;6UcgsBvgJ>my1Ua|Y*ZUOQL1xf3 zez{GRKmF2IknykU_~uUw`MI3cGeIhD95Bd0dhFfI82r*4Vo{RJaZ_%rS)EF;I9KVGO0C)s6UV-fOjDry?5@{TBjt9_+sBJ# zJnP7ev&OCL$nAH5JNT`gn5{sbf< zw{`8Fa~12H_B9Ft^^j7KLaC86kXl4R5aIN{ntdC4-`E~RL`FvDo5fn|`&VnLWxj@K zU^V8PWAy%X3iR1ZcVllOy>_2{H_T5FU)7fLAkFO#GU?Cx#%gW`8>}S%ko5G;9TABJ za0e&k+%d~H4VY*04g<#FY8^UtC|zttK2zYhKo5#U)XkBJ6!bN1sO$xSB8|L0f_(7B zO(d+Qn2Ovr%&bRGeI9Nnl~v8BXHh&j#__GRm6Hnqfa>Cy07Hb=Hm}uF<9$ow=bp{8 zWSa>ZanR(dxk%#o!y`Xt&b*3NCrHq} zkSDc_gBpS^H09|B7>N|v1>9u7|FL@edKZdw3SCu`IK)`2*vXaLyzYKi4rIbP-Hbi1 z)T?FW@H9kKf2x&Qh9HC*G*+Vv&M~9_r}IdrDYwhPa742(vxjEqR=7CN#_IuatoQc1 z>9<|gHBUjNtt{qGpbYX&rOWjtGzI(`cdm|2?TBdm-4((W)50qD*)BZX=6m190c7zq zj9?xpeY=&JwbWHMxGOdchr8ZRzlUS7rJw~;3q>40&g=fdTqO?a^v3lJ6g=V!Z6($l zqIRP_wt1Gf=SyOJxzZ1>5ncIePZD{! zR?*<0TTE`Ie^as;wl&aQdmVVBIGNni(i`ng>wC!z@4j@8iY*EPwE|V5N&ZjDy9$pXlo6b0U z*xl?Hm(i;fwf9P>$920ob#a7C5NQkU&kY*U83(!VkF~{slyY@vP(jCr0~*$-o&)&x zR-RE8UDwh&HCX8-yUCH&^i=8g*A}#%;8%jEl;Pqr2$vnUkYVF>4FUATqi6&th8wlL zfvscM+JNcl@WN-CemD;oZFY30+N20P?hS z(Z=uA`tJFp@hTnmeA{`W4!SPL9}UozYTSt@wXRkyP3zwTIA1vOKwhRqDL36FJnmeo zPp5W+H81K&gRk<*J7leZkMrN`VZ7~qfAJ~*$i6EdTh=_xXV$>RZcAu4KbWrDlq^C2 z+}J&bubg1hK(W{b?s10{C54{X0PuBDr;TG#y|6!2hVZ1hC zClPQTaFi>beYmj?lM5(@-NOUM=H>+6VBl@cU_*L>#;Psd!;w6oIV1^aaafgiod}hU zkH3hJX;J428iHh+x1`&!?Ov>$KX zrEI>3ntrWr|3!Vv#0{VZXE3wlKi9W6uEX!D%70tm4q;%epzGNIFS7YXeFG)yyO#7z zeS5p@|9XA<@k;)a`qnFsuD{MhL|c!DliWpaR zc6weZTSVk?HJ$eO=sYH|NR`L@Vp6P%I(>B}EJ($vi`&*13I+ghp2bLQbb5xE_F%fE zj)=^GpvWP*@J4q98Ud0hXI-vQx+zyoOXwYdugT-x0Mc`*%dJw$hSheq%3MtVJNSY2 zgvq>TTbe1_uiZ8)##_Ly3Kl!2B!$4v;iVAA^ON+0c-zpXyfdyP6&pus%AUF|btEqRslIU#;6Xz+=y+vHQ?tSN3QlVow8k2IaQ_$e zZTXbH*EgjO9!1EsU@a#4YkZv@zR}D{63OOnV2@`Dkrd)FzBt*T7nA{UB{wo$nlwSL zx~7elQ+OkYkA%@8`jtKq`>hF!m1Mi~UBsKC0ZsO2{-HY#hIy8C|j0@O#B zOD-uVKDk2teHg9$mCdRGe#J|4oYTut#d)TrQVl^Yx1Jhq^|0+;6%9IQ<1954ND|~} zljhuf-{STwiMb0CcHS1jLg|^q$dBJ2V@b?jwQ?%zj&*MF;O%ccz+XRt$a*!g|e27$2Oc5Uys z{q`z;-nA{8HfS^&_!j~V>>vMd6~D>Kc!PjIR0aZKi_ff#7pG;dhoL5D?6(joMFEZu zhDX#D{4*PQ%iILLT`71DNc%oUQ-^dQmi<~Cs~S!kUf&=bq;cnoH=_4ot63o&I2mP z{rwA1Ck4=6amuu{2Z4@yX-}k8K}jv6?e&E=mPl$Jw=qdE3`kIhp zp_}Jn?_LvR2P}on)W0gtXAWkvPq6u^-BptVml5PSuGjbhGoVP5$9ld`^Mp&FNEfMV zK%r*DUY^6TI&;HixK^}<+_z%+V%z2*7LNzkU|BTmJoLa2H;+ozcY(PS*tRc0fePre ztw_dFao&JAY3G^I);!w4SS~6J-#oU4g4jz!s*KvL9PWU?S|1^%Z8Rag=yC$*W;XX* zfAVbkIrJ}`-DhiQ?>71xyP1$@jOS%2UD@@uS=;o0QwTGRoLs#W?{b0He_XM9MiCy| zO!?a@6YOPO0Q{`^5T@`B!LqYd%XINlx-6rVh$kA+cR*&be&vyOq7f_xnfo;Rp%8~p zx9SUSi{1fYsdfdwRUn{AI+&?Q^}8p@#kdn3MhUMkTFxGnAwoL|g4iCz8bcw2@rIzr zOg6Y&9kEiz)yssx+=`Yu<>w{jvvqe~gt>^`T6W>`o2xMS>vLJs6F!;$> zCjcw}u#aG@<7W@Y&C`WqXmxHO0pW@0xOGQdJ1Lt)UUM4G8xct*k??SlZ@P z7>btbD+zq`tOrxh0+-LdZKp?IV^7C^Y|1TF-=OVe^z=p`FHWg?gmKT6`yuR zv^w?-vq2xYX_RH2dDL;jyn8l>x86!QmI}Iz<~9d^IzR7XUKu>X@Wg3LMEa>h8M6b+ zmh?ikt9uO~qnXwARMx`EY?H>okq5BJkC-o*x(eH8)+*bx(;ErR)F^&9NQ{kWv@zbJ z>p5nUt@t9)S6(O&k8T)3RQ73e-9xsV8t%?`RnNSXrB^e;!OH{e1es^ml9I(651nvx zbY&GmsgY0ul0O{PySEoZBLqvVe`8)TsFA7b?t+%_WNw)Is-hw;R8?Q2EtExE@?N1Grg+ezU#n(tr{(V}sq^X##q3V#vD6ObShL&ZM7&Hv$hh zSnwa~OADiJ==qcEZe2Vo>?Y-i^192X8{{{07d+pgbH{a6gK=wHU3qL$H+@@A7xdPL zoj(l+b9>aZCsg*98B?sC0i$w?Haj&UT8Y7toP2eWD>%(|evM?^4XM=gne%FEj^vyB zHZ9V^3q$_uh>&Z=S`{?oGB88K&^D2bPL@zps&BKn*W4JHU#1LN9qLBYT+xjpz8n0B zZ&?E(Vb^0+t-MMq92^DsYpSL|-DB(9&KghVUyOBMj~O4!@V`W!|4kp|uZ4$IDiFX>EnY&m!g`K?O&G!- zV5E;f=u1}ahOin0e9%^a^xQsi0b(8<2|`L~H*t!BuLBT?&67plduR||s|DutRcHzR zV>{}gvjK<^uu6v(fT)G&NwY+>_JOK=T;8Q`ft?V%3?3mF`&H}^2bvAoT;(6n9e8G= z(LezEg{|0t&kk}aL88S5UZ8F(2blMWZZQlA5}XzahZsF+XxcC9k$l)8OfISo@>IRtcKZvz&BL2_YD!}!dkCA^L#q0o} zVFFk8hq(F$>cBOY{zE;1AW0Mw zt?&JwAh0d*=pRHUyB^xz1@(G5rDU9=JG^3fq{gZs^3q}lQqt&Z(XU(zJ3!LeRk6Wy z$F`^HrbwGL$7s3}9ODf`A74c5`EBZ#SvR+2IFbKtmVV9wXx1N0MBwCgRX>$<7{SJjIw!VSGduryBvekw!K%)#uTgAXB7 z55HN9Jsx-Z#odFJCD>nt;z?qHj#5-w6Bm^5xdWZMx3yc-B0ey-@pz(v<{Zu)DsOYZ zwm*H`gkQs+kB?O$_7D}E4Uz!j(`yqY6hwSgs=E*9JK<=a5}H=j(Dsi#g3scE0EtTc ztUf=)I+#lGSZN%#xojVSv5p7xc~C_I4~gykYaQ3mfgay`1Zs5aYz@5hbTHa%`Rq%>=+MPIf5VC0T6;jz*%2WFahX6@INNCf0l#h;&OmDiL4>0bK zGfmkp74zk5sB{<1RoHf$BKL%lYyBHWyDJ@3(#0D`q@6KvMCtH&AhXtngK;~KQqCriEn#4s*tc>72R{s`J49S z-HiEsuy?y&d71I;`78kg--J(RC=R(vVLmjaZ=4Ff^W3r@58K!JvH29}Qc%K$_t_8Ux9hXlh2JLZBeTdzB^V0P^>+h4Y-MI35LGz=VOKCHS^}_sxNSUrXvf}ksf)tEs+BKV z-UUSdUL-$$>+5?s*257%`UNFC2mAbda4r-ub7$Q?jmZ8RPmv=&$c`YSg1z!WIyVC- z)r+WA2jix+hZsNrx-3e!-+SI2#aU)WjGErv^@#ksMw(xOnzMZK}Y$t2Yw%r zV(A=Gu}R(_g?r-8VGTnQk$zFtNg}{Xca4+(WP=(y_8I}LSiEzVPc zzvv?&=_i=3IP~Rw==KnfB9t_^Dyf^i5;D);9@gjN6_53VXv50W@0q#riWTnj;0RyG z*PBBEJ_a%;L-XEj+q0c0h2W>%k-kHmIulfG4Q$lLcDz;Ho=G2-jn!m~kQ_&406`pN(iG35ve=vcAJiT0Ft(Gd#p2vYEZTrzK!RUHZUXCP^*;5MqHcp zP)^J) zwpnoz>Feyc1EUL<<`AEl18Q(#Fv55mS&mg7dc%)Z3%*jkiJsUHl_9bE*gxCuHANaL zYFphWNcZyEN(5JddfI_j?d=H%>pWIK82Cc`wn>ya_gbZM9_eY~Pl^y5XN=b~YKU)a z95+5DDN_(x*j<2pxOJ!>lHua`XM_L{0ncit@hYxRsb1)gBw6wm zoFY!>No*PO&f+1pY8hfHd4O~1l;`Djb&rr+q6hwoo-4H>IX)O=3P+kf3MrnDSiRZ6 z8HohRTyi_>`g{jp4{5km4dJ3`I$(TGDfGsD!f`5BUlxFF<(xaa4RtataozbvL2wAf zH&kVE-1BIu4ozF#R{F{~aa*y==LBb|@pw;lL!0{c@FH5(tEpY=4#eF#!rCVtV^4Yr z(4Wm7arH#@8u4s^eEuRGUYLrq@WXW13{#JygK@ruI#W`6uu}sL{ze6!VoC8D5ZcOs zr+e^<-?t}WM~jxJ5srwom!qUR5{!Xj30}De#NfT0tXkC=>Pt^GaMB8dJ~Dl1AW(Nl zi4!V2mgTqiL`)iws2JV>V2V=~3?3ssVA8MHGe}lr2A`(#X0y@l;YRAwELfBpAgzgo zQB#=rVVpcP?Eoc(J@S<>?E3g3tVo8(aWNXCBoPtt>Jw<9XqzG8yrWCQSimo{k^)ny;`|MH?bZO&x`-_FmO!7u;vx9z|VTEsjTd>+cg10K|n z|MioJ<}GdM_S2SN!T-Ib<1J_&1U!4b1*m(FbAV9>_}Bok@qi@^aGOQmF`OI`Ql0QO z)(m_GcS|U@MTFc>cD^^A^^%JT2>S#gnt(myzW`+*j2ll{eQ$vpOw}TgiD9!8= zw+9#=^W)t0b{j zM-|_q4!a?yGqqkHboX_UYcSe8eId(df4aTAs$1vJ%S8r~#0B7uC;8;GKBp=0RqWUF z5vHm6>x&mx2R@J@z~=}6BA?7$ctgyq4hCrmHc-^@wB#TGId``MU_98RSVo(+&(q2n zwT9~=n{JTgD#E89yj8!!#IQ?~uzJg_Paug9c8QM#stv$6@PUp{DVATt?l2EJWx&vd zI~O|KLB4&tDtG|6J-MZDyAP`)o0uHFfO^k4cV~A1|2Cn;^o8te0;m^ZWra=HA&93kAE=Kdu~%3MSOnpPt&+XNLUpsmX7zQN8@b_t)tB{tK3;#KJFvmjqrzfF0}0 zOY;qW+{2Y!mP;L$rx=42b$M~$t_-NhZ%+l5dU!y1O~C#2alf~p|Kd$qUbBC^D_<}D z*H^wg@bZh_Ui^xc-M3!^@20u@<~J_$+i!-a_Kn{RK9 z25!_(BD3!e7Tzil=jlW0q{6G9@=KzX6rVu=BcMQG_m$CeSaEkP#d32xPM+DyFK`}$ zt1q*N*F}grf=`Z->klOUdOeaE;V%`c$XXw7=37pRzIBH$rQ2_-``zYkjErCNL6G+4$))}(ELKIgRCea8 zp1Sf3sG3x(s8Xqq4_mcD@kzJ_C6H(!CBxYX8xIY$2iMRC87cQG+Nu*!QS;9$4>5w~Qrk+YF#tw2fGa&o+6@>rKqdUu3r0#IJH z4)yK6&0DiPzI#A#5qkrB9Ij_vG zclu?#(69Gqe1C*}EsGt@!-nH{%4U%{9orjCbOX8O&6~4wEvLAtc@M{MYtvKJMzBPT z29E;kR<+C1+^Vei*-3r6{tkq*+mW>og=-b-71|(E)^YpuBxySx<9u$m%^*L)Hck|u zXNXk`=SBkb^Psk+lkvD#l0>wzd$k5e%gUVBNxs#uBC8#l@+cy~U-7BcBH75fGNB)-Ji};3cu|mI2P&== zM3Aqfdb)#r9n8*0?{$D9JawFRhpzXh&X1tby`rId zkm<@p&clRyqkP~zKU?)uUUJ}MhqOVK-Bm^fJ;dL%7~U-G7Jh({sR;9?w)PVb0Zk3; zY2Jbg6X89&0fw$HdHh2{ke664?$t`59U!f{#ZD7;$w3*5+-9phKI7B+3VBGNV2{VA z%VGT?F)>H$kF2!GcIsi=!JB#!at3nTQ2hZ}1LtH0xH4t%*L;dKm|j`e4tbc#+6gNs z&;)CvCj3nc#Hz*6jf3H9e7j@ixMM*V-6VUqex%?=E;BJ`W{9D@JuS>hm0j+-=38{cVB9s5Pl26TB zr+fGGU>Nv_2?nHJgWh3xX&EFc+U=TqDzB3r&3_p(!dk%o>{wgkfj(goe>vR#8|`i( zT?#c2N|p}+^p1Yl?#_NH(ylju$Ie2H-XoqU?LAyNXf6!LzM~a1U_XBI2E$qQjXU^e zs18@GejsJP4j#d_^%lPKb@2FYkoX4R2ej<8bfVuu{J>ZMLKvK9iG$Tl8wcpOLe>%b+8V zoFeo|=YzOA1DslvirhCLpxw;m+Vifi!`&z<^)eGIHRS6ydS(=Ur zC7uxhsY$YJcu<$f5KE#-5Tbu zqhILpsbEBhOsIP-=iFH5-3H6iQ!}%#mH)EC?5gE4RZ`aL#I9RwM_uG^W%5nM@QbPk zc&Ohf7Jir+TJ1r4T&sl9{O2A{$F{Jus)`roexw#1;IkMzd)i8&79bbs(A#GhAi4U9<N5>`gBS>R&y*1kKPI;>0F$}cGJC1>j^V&yD;BL59 ziF*4Mv&0>^$f$g{*5`FstmZTQkQq{_i()Huu6sB+FZBStZ<=1q&3*E3hdK4JXMdbc zzV%LsgU1<4611PGOVsorZ02<)Je%kNDyg%h4ng7+>5o5 zyT6E+?DRamp>!4`_|TN+s9&n)(kJ9u@-H>>uRGghDVR0-y--zrR)mw*8G$ubaB%!1suILOA3Io3Xb8?kJsimr0YLqOoB`~p6%euCC^2vB=>VcI zL8@n4~a4@a(zdZ8==n#`i1>9-)n2@s`xsxRIE3X70pY1n)L-TaA< zfI!ZYcktAg+Z~vfcLjneVRzMC2u~ak=2ZV_Jjfbik3wa-1rU}2fc4diK5rp&l?>9c z=-pj6$2FSVQ4~QPiZoPqJ!Yqu2y4-0CW2fK=rU{|Wvp)rEr`sJHOD0O&0E7iF>qJi zJ>3KAyfIi(zIwP}5}$!HVj-)B(p#|FOEJZGZ5YL?@b0!XGn}g~y2FUFXM6toAf)_a z0;sPA(Z&waXk}Wa17}7xhD@na1?EEyDmVBhiCKId3+u8=`E`7y7v#a zs>y1t809I)O6Q3ML#KM*;ZzkmurRT!c`_awmuZo{v3BBhveuR3t@o`(<2DM=_K9#W{5IF> zEr)fParM2Z!PZJgU)>Bdyc^%-aOm=x=b*;Qk4?nS$= zPb-jDCzT2WyPJ5+)MUFyA8dDnqx+k_?AIbTk^dj|Q`Gsl!Y6s~MdgG~ONF@x2OzUG zi&bIYPVFdewkwhSMp&hzaFYW`I+(M#9q;UIsrF$nP{dV~KFM>KZxhm32?4<>*5fGP%(Cs+&h;3h9-=m75@Dq!OB!s36 zgtg0F3A3&Wmb70z;LCs>%llJ&IGPkf;scn>ls67JHy_H)^IOV8vRfY19AMssYbyxi zyh=-A#sfYI6=YX{_4)lB{CES^<&6PFu0%w>m|Gw@hgAr4Zohu};f;V6k@Q%Cd_brJ zHSK*02e0PNa`oPH4ao2KgWm6Fx!+^bWCv9P^X@Aa1%a3a9&7;Mx#wtWLzgNt(qO8= zd6Nrx`J`Xi7M!7>btxq)<4y8)we~lI6DT@nJS}bSRZrc;CaJ5-$+}W}ejF|u$h+1n ziBBCQN*PONjZEm|E^POc^MZ}n)q~-Ff8;P5c7Q^3xTxW4y~iG}$dmPqHZ-u1C4LyR zoN|-bjYRs?t??;DejaPH0oPe}Q0<+S+Am(}n|{zN^|rdZK2}p)gl7_UyFc#% z^xdCz5?sjH{cyX2&SL z>H6_dOx7J++lH4SH5$EcS#??Cr@98q7fD{I=kPiUbu5RTT)PVN+HlQNK`oEQZK`!g zbt@liHXl%D7kA2$p{KPUW@rS#78q`2zAi?OJs_}Lk zP&K~YHs;}vh7g3kB)0CFBe0&|+V|qz|1YlWZ9`zf$l?o4$&pwv*nLYNTG`O+Uql{} z53ds({2+|3U;Ykj*9BTrkWlRv=c{o8g-AWX84XT~9&kpt11!Pc4u=b4AD-HOa_j;& z0m#gT`!hPASK*{VbRo)*ttYOH;baxHQ~<=6)M)WIC#S37rjB52RkaieTJFyF3dUac zt+nYsQ4qpJFNd-gjX0OL*F5pgIOS$M@ERd9nmX>Y6xItAk5U>B(D;xXB=&f(@AT!w zKMjVt;ngiVj=}p@zk8+EIwk!t${w14r{)yZ(nY>VB7a%rXkQJfys8-svQF zIQ|IfrtS!KuO$Q~<=|f)TXq8v27Tp;Zq5}e<+%=ErN`Qq(fgT<1$Jv;laPUl&M_}2ZF5Pzmf?bpC>=IRo!EEZK`YD{0AAZ(X6^b_a2BJXq zy@nZjvE8&2?SbB8dKgWM-5P`0Qjok5wgm)vA0ZjXK-QCX4x2%Ix-Njb@y*oLD?`Cx zbiKiJXI+(t18dvBR$cqa^o$DY?8+34ww>d%D^j{lb ze{?9lts8$^BcwN*67xARP$0y>s&P%EHot}xBd&{%3OxXkKFq1#vkzLb(0A zWeL^?sD1A~rq7I#rRDUk%#EG>PGVgD*V0mtwL7QKN>>urjRjvc=0D&V1D^ zbSv5r)P$m~rmS@Sz#wx5f?EQFsfj8?c%i@4A#phU zuz_gt{yGgXo)BrIf+Tx>;@wp<2*VMpyc@ZK4B&NjR9~Y9jA6Fd)$MiK9etv~KRc0? z4j#ZCBvF!fLLj_WX;#H`4U?aAF2-8Ffaotae>Vn~-Za1n3|FV}eW0F{3Un5bQf#_O0B=Q?j& z1xNOwLAX8BG!cF%sMQNo^}% zHHb;fO<62rvYRdk?cS^*0u2f3EF+*1?$)EQ1^@uLN-2#-+H6a+Zz$U=v~%BdpdQ#6R=bP&-PEePc# zU#`^ixNQ?YVr2ek2c1vHxGMCIenXKM0}WgtamjTc-w?7jHm|crC3{8OQ816<_l~JW z5A5Q_Rtu2)Ty)RiQLoRj?m{-YhF+DvhJR$hm=)TRd~hbw8rD!4f%P$Uwhi6p=)fb_f%XTo-%qd?VSnnx>w`? z`wV~nX8@AHFY_V?GLhS`EU4MS-6z8zAsLy{ZtF=>I-QBV4N6Xl zpaw;qe>(;Kx+VOk`+}{5bhJN|2fuVQ|80{Xgv*rd@;N0lcQ3T>Asu`V0d5hN$(z%Z z`@d`!bJEwIk*v$K;L!wLc)RGukm3=hRuT*n(oKh z=Y92jmuoHY5YRn^Ng3cL-g!LAI{?6ewSPVlKpy)Cion8^*ABF7%i6!72poZU=Qu9S zP6wn|aEz@(L4;iaOm{%_4?SS0{(E9MiNV$GTnU<@*X0)jph5R0sSbZ^jUIru8#RZy_ht4S|Ok+0sMZI0*q)j0= zk;=WpYj$^cCum5JWM1*N!50Gic?YiHcl5CAts`jb;_~)Gcoc&+Vx6A)08Us%k@qiV z4VLE{Aj4)hd6(vXv=4{p{k0FSnum+Eayn_}beKX=$1DE%_x(7TK4BP6z=q?D>_jwu z@WZCMjV?A#IeAIq5k)yI+JFtnQhZEDojjA{vp-)po6_(m^0;!FV7&S>L@GWntRBE% z3*Cb=eJY!K0PnL$JtzbGcDoA%oP{(u90*7iw=bq%QV-SbqJR~n$B`m9WkSuh@JPm~ z5Y0!t>30HpznVZfK{j4l-*em$NIAWSbdvdgapbb5mAu265#;qb6f?phZYY0*shy|X zHuwIvt0*5@zn~ls(WzJV8~t>ZJ+QfNp@+QU$Qr+^Hy7)6!2riN38J5}70P5=4IAWa zIMFg{s+2{EEd8*(<5Tkb+Pd76Zr!a9jgrjSsYXhU31)tGR!z|e(;hz3Mo@RXGM~gh z_T!f5haO}D|9bNnXWvdv|GwbrZ-r3?(G1V|pM{ZwS<0t^-ErL)3_dr5` z7WbPuVv!FRhzqA9U@rh779aq!1rq_W)A^6V&Py*pqyjKzvLNmY#!mhc0rnN{;4Z4t z20C;D63#ycU4MP>AOF$sbXlhn;AW7!bHNd#`T#u4-*1H5NDyZI^=WA1H98@z_6ikZvoNSse@n$W>rIrTL?C zf`_rvd8k*Li>}`C5XO|#!Fc8rT^`5yNL?2+Y5S!Pv{dH+R=n~y#8VC zGP6w+CGb;sVvSV?)CJG>GuTVup>Q`;*eYnkIWve;WkXrHV~BjihPC6E;yLwaPuULD z(O<#l0wDXUO=JAN#F*YXozIoGnyME_SG!_=djNwv1VclQOMHN?V?QrhEJ0HJ*2`lW z=&abEn})IalLL}ka5xWwZLR9ffF(4$JM7r@cp`Ma@F7LFxG=NkUGI;5m#~mbhDzkI zvwDO)h9VUhr3^}mC-i5$(tEgOvufL?3jD_{K*8oF8L*=tZ3HQ5JGxM6=dP`or@i-!|%F>Hs=tLUE0>W0(PQD?TQ!5rFiih^$f=Qo1Pi*FyyrhCN+$v*j-D2J#h%=Y|@E1h~Jy!&vF)q2nq&HxF> zXM8s=z8UVJdGmf!`iSp#;WPecKso|l#lu^=kw|IlS9>v~p_WK+FX%Ts5<#9AtwD(N zZh%%s6ZUYxgZ#~Xk+(a;kkwyW>B~e7{tgL1FyPAA1z^(o0>XHVwIzfYAODguOg~`aK8x&8Pzk__s>?{Q-bt z09(!pvcWIl+{D9=2g=WzuX8>gCX~F+pM8)^ElD}}qJly|1_je=n72bYRzH5QD7jRd z)03S!=qxZ>O)&z~&*$D&5kb2ESuKlgG=-2cn0yy7M8P2}*3F^gU%d-Z+1A;4&GNt> zThTXw4@^`bEOmQTWa|dzh_?`%WYJ^6z<<#)M1BZH3UCc9Q-U8x4>o54H3(D_m;4lj zMFf%zP*H&80KBF@y+%L3M2Pm&iwt7){YeSIMi)~i#KONHuE8iJ*d~0|S9q5q%aLNC;;$N+$z~fmOVbu)-aI-}t*>NXj^mZSUV42Pa z9m^eQ^uhD#s_IiZtZLS{>H_+r$F^~K&f5oDGA&F4bemvgIH9CccHEQ-ZQx%a1?MPZ z?$dT6JTUcQ_pEx%&1Rv`-PcMdCFMfDdTjp+IyQQBty8W_+r9-<%Ax{RqP=#^E_dzG zok{XT!J&>mYp=;FP~HLFa>-C7EjvaM91C<;b7F8ia%v5q z(-DsoXG5~?aPwe`FKy(NS4a~ZASpSnO}jo*aAt+1Km7`)VcBXPFnAfsXHD-^PdehY z05L+z-f$l`449mDO3>-UE5jmEj}&-4uk}}uO@H9Kq9S2z?L35sLmfVxr~gN9-von$4S*qI@Yc#uti6R z0jl=ptElhC(!2D-Ia@)OPt7)b!nxhmylg>hfZy*NDz)2ZouA8Itq2`-lp?ZkpxNQk zFL?3m9XX#)i5^js6VF|H*E_e|HU`IgBn4=qgFs(R;*v%2cw6Vv zCE)9+*UIU(b7C<{%d@JRcr;k!!vx0@YRFg4hM>0YhXvyL?JZSZ1U^P1*D|_ z5hbfXlfeJBRsA<(B>%Qyl}^h^9v?pSuAtib)rQsiZ#JwCoqsDA>i_E2&iCI06&9$=O3?bvF00JfBVOF`oFq5Sb8q`a&>>( zKYrgn@?`0RF}FVFMo01k3Tqg9@X~g3KyE~^--opdU2fkzrKV#``JJ=n!)CR8R16-D zM!QbMqrCyEWWY(3s6yoFr6O3-xN#gk!0hOm9UvW0-XRo=Y0d5C@*Tv#)?v9hdsAO2 zH5qF&#K=g3{Thf6_OZ%?H7%QuaTWmPx0`^uX*Ol6S`$~tIFm1sv4ODZysed{n0IRj zf)v$Va2<%*=EH2eF~Q%pGKZ_7Zne{q#!UROE2)<-Nby7l8~B=L?Hw;cN9z$xIn;^-v2gTyF}=6T$} zf%dkh+xUST(D5odmQrOAs{){!9R^i~PQBXnzEr#>wL7#F6cWHth*xy~lnd+RGl1bD z^3Axu9}W-^NQI~FIBaC(2_-c+zl>&F6)Uw}Q$7`~6|Cq1t&|4)1d<9gImtL{+xq*1 zU;@iA3dmD08sk%i*xdb-Qf02uae>kh&^GL~XB|W8wcH$PXwiFs4fbZpuiS6wln;jJ zcrf!6cKT4S6$cyn^LEX&u8x(iTLpknexf3c>Ja0GNIQi|{Npi&u1sDH_hD|zmxe!B zcCARv=&W(Pu7GfS;n6!;)>}E+;soYC)N%PVpWM}~0L z9N*T&cqu>x>*m@CUhaGYkZcJ`>T9sJAi2!n=pXk31XaVW3XLAnmC z^DEmO>{Qsq_lq-!sEUveoZIulIPKe_ zjjX$PSI5kWT}#OVHxuutZAi>kd_nfqB|&v%vX86yn()Vfu<%)Z!5Sfzq&cbvm07n} zqEx*S$XOg|~W08-fxoO&kvVy5D= ziD8(MQB`1D>NYWYfmB4!1Dfjn!Y@CI?oZt3}QWnAk#CSN#d*JcEZ`C6$)UGr!hTP@x@EW$)3$+#n=l}2S%ynMJ zlPf-OW~L4&nOycr6h%^mBa!01?-Vocq&DuWLqC~gzlfj0aOvLO?(IfT+lCV-p8x@Z zJ_-`+UsdP)PJ+C}(jf_P@zK(F_=-3;ZM0cls>^SGnhNI=t`X&6cW*b6+wuc=O3?6l zF?T1;+_^TIhRcN`mEAsgrbzrOZ^3qjT>&wvkTv1FR-z%IGT)R~*O>)&8M2HEee_a4 z3m!L9VH#h+!f{Wi(ffwW5f02U*<%fo1pupMeBPL}DGWM&WTA|Ee= z#V8fVGERLBk1zH$a^XX)>oWDyR1vIeMZq0?EG3C-Pzbw zrN2l`STOaui23&Lgy%j9_O!bma2;I2Fv{5=lzxE*GW)s&hrot|gk}LOK_wZ=Rc-`?oB9=K)kB=MsN?vl^zf5{mrv zZk{>-K@Z0Hw@uwdO#K!H%%qT$b_>9l&1(IZM_|}}Gl2&b-S>pYA13hMq3E<+2&SB- zDGS>jK@Vp5b6y;eNxh>-<7 z@rrnFAD#Ki)R+xXZri+^$%&IkOr68r@RXB&%tzymP$ALXjJI?>c$;Vp3vnMo$`vUud4)G!>Eu91} z)8gnF@|W^afgCFPN#7!kURU*qCc>gZqK5O{AIiq)OHJ1&cH9RSP6y&}!ilYmFs;)< zqLJceAT?U<#C2l318~eCr>>+(6J(xg6}El&^Lr^oWV5&$O`e_GW2{y0lOZ>59;RkQXo84j?_dxuFmOg6S!^b z+~sn$%O{L`S+6LhfD5O98oPungGaMR{S|d$bvyAw7sO=qx|~;ZK^23+ql+h7Os?ca zjooO-I&DkgvF}yvU0SxWcdE^h$_EAQ&T$G5w}rKzJX}nI4m3|YojK!lb43B-s)86F zRQ-b9!A>%1^;jiytx@(TMWNA%H=z5{NeC9Sx}9?h3xyt0cO)9e)~ND#NQb+`kp^b0T)N5Z{WKI<@xF;3jI!0H0G~DA zF4&+y$N8z@?CHRYFy#|^A&n^q#+w#(ahY@XT04(SF`O1q;<}KLs)x~R;1O;5Q~_J> zdYAWAl0JdbhVm0>vmJg(uBWq&fE9isOPuHmNv_JIODCfD#K%Kn&-Ok1!|Y zBqRgoh_A=!I1pvbK6!31pI}`r=Y9KZZ^|u2uJ4DsPr6nT>2(Gg;~8LP<|@j|ZaiK^ zn^8o%GjFvxgPJX(b|Kr3GU^fVi3){O6h~VP2pyQ*`_;c9;O8YKs-x}`@mvpXFPv@B zC2;IIyrQ)CVfk{rk3-O_EqQ6%4Lbzz9ivR)^tfYUP0Wo%wOdWB{p$)Y|5Y)?-RS!7 zroqhJ-sG}ALZ9X_(!-Na?(QasORMT(0Io+;hBIBgVBtB5*xZ)XP z_6yvJ?VHbs)yB4F(8ED~wwKKE4zFYdTIMyAUYCSGL#t_x7MIn1v!_bT;3CJLSMgws zoqQk3M{OgFv!qEP@3OpO%43l-do+oXnLkJk zIg=TfY@#xn$pvXyZyEx}T;FRizq=m#woYUJPwMm!+i|Fnzfq?@JlQW9T)(K(U!VKG zuG8Ob%KvbkmV<}^uZFAZ-uX$S=^Z3I?>0VLG{he;(cp<77PADTm(I6PStDxdyezFC zz+U1*FxM=l9qG-d3&0c!Mv0l>Wn+htGnmZ_gP6zZ_&s2heFF&artFjQh+k5VW zE=q9O;h?#zMq`#Q(;;mtNWM$G{$4wKCD}<^21zD*?X2B&Q+jIH-q&lv3E*q`9AJTK zl$8jXztXAXAS|GFAl)S8>UP$aC3w5RzLIX>&Y5Hy8>aGT1c$5CqEEEH8vGXD-xbIe zA%f!a=Cspk*5?oj>zhqT=*pGa!|k(1TQ;h=Um@FO)IexF49aBJ#OM;`+Tmu>deeczAcF%!af?h@KY69H(?Mg)N^~l79 z|vKT_}kz5r=}jMQlYDrHX@{pgA(Nu#`&dYm=>`E@&QR*9(u*j)%j%bw5kjr@00Y z5OM>~Gol94wtWALcjT!b=gEQ4F)4=Z6n=tG z+CRc~`9+-u_S@ZbT=t;?%=vYlPIpg5w_Sg_+vX^9Q##c?*IJ^sZp}kgR>LUdH&xMi zJjBP!?cv4`m>Sz$DKPHB0;&b6LEjfS6X5%JgXt^m@!ELDNvt|A=!qdg%y6p<{Ne4| zib~{0wE|n@yME7zw5;xUWE3wMEWE77*;cO8gm=Dy09s&IiWU-l~qmn+BQOlj`W z3VKc*w=uzI-UE<>Wd9lX&FEwgb>?Ryxb@`)5-ZP0s9Q3MbIv6yii#(a;9x^xXJ}1d zrUQmWHn;Bvi8(9LBVmX+K_jXD(2CJ%UGD3SwC}72e%XY8Bqv0+WAr%O+4I{2qdEbQ zDoxHF^z(7bPeRS8<>>Qheb)D!+TZlTzgcZ%JT!81fWymo=(&EpE`A01aN>pl%aMJ= zqNUO7ju>cQRGhC5{G#qrmh$!%9gl)iD`dC&fKyJk$L<=nkp#C9?-(SksX_OQVmhk^ z@d#1Zp`+ww+_CoV{&)nUBM9N7zCss*j1=^0Ope!3*Mqke(NnpccT~+2Pi4A}B=yWR zna^@c(wFvnHLe+w>6>^4R}DW9jGW(Tf9PP^aeITn0~*Ie;zniN9-R9@96%LVkR!Ed z=+Rl-n0&SE5D|_r(%rI6i&h~_vlqrN`Q1A0{F9SCGvGk{g@4v@^!$p5{nA|jnq~Gy z_5Q=3zcmfN&Yx*``|~vX*M{d$XAM56?|N7ZqGaUl()`%NBI45=enETy1*QcKS9*=W z7zMkokA)W2avt=pU-?}E=!(9+xL3JvU+aF&p7|`tK=2+0;xFJ0sw!|G)B@K~=z-&E z1@;+FRUnf8Vg~xTDF*gnnP?we8MuQ#?w|``Bi!THaXPSdKF@s_r+@f5fBW)&ygJ}g zcmoU%{#Tdx1N!ay;hO!AFYkLE5A^)7L;g*sEJLNCG2bd_l4P>T0Bn*2%|X)q)3D#P zGpj%>dL?>K0;Dr$>X@sHP=jG4hGh?F<5ki3~iR9_mQ-wa>- zhR0*0AWS*xN1lmFx#c;dLoO@tPJ2>ce{0h9SpkD@%DZDg*YK(1TVH*J7$5TSCgJ(+ z67#cLFefK7V-fmEB=4_d@B-F;L?vj6MThqr=JQDdfp!8`SmAZgg(z=xHvXCaLtcb#BYZ9(ipUTG{=Ys z5&Y?i>a;@V)e1qaXO?>26w7LA(h#asOhAN)Z&w+8YMjQnHk|4Dzt7`A|BC(f@Q+E* i(Es87gYmELfB*aS-~RbO|NJk1{<}Z@=}$bg9RCFp{RA!m diff --git a/tests/kitchen/tests/wordpress/states/wp-config.php.j2 b/tests/kitchen/tests/wordpress/states/wp-config.php.j2 deleted file mode 100644 index 928dbddc335..00000000000 --- a/tests/kitchen/tests/wordpress/states/wp-config.php.j2 +++ /dev/null @@ -1,82 +0,0 @@ - Date: Tue, 27 Feb 2024 10:24:22 +0000 Subject: [PATCH 44/54] Update pre-commit hook versions --- .pre-commit-config.yaml | 27 +- doc/_ext/saltdomain.py | 12 +- doc/ref/executors/index.rst | 3 +- doc/ref/modules/index.rst | 1 + doc/topics/development/tests/index.rst | 3 +- doc/topics/proxyminion/index.rst | 2 - doc/topics/releases/2016.11.0.rst | 15 +- noxfile.py | 3 +- salt/__init__.py | 6 - salt/_compat.py | 1 + salt/_logging/__init__.py | 1 + salt/auth/django.py | 3 +- salt/auth/file.py | 1 - salt/auth/keystone.py | 1 - salt/auth/ldap.py | 13 +- salt/auth/mysql.py | 1 - salt/auth/rest.py | 1 - salt/auth/yubico.py | 1 - salt/beacons/adb.py | 1 + salt/beacons/aix_account.py | 1 + salt/beacons/bonjour_announce.py | 1 + salt/beacons/btmp.py | 2 +- salt/beacons/cert_info.py | 1 + salt/beacons/diskusage.py | 3 +- salt/beacons/glxinfo.py | 1 + salt/beacons/haproxy.py | 1 + salt/beacons/inotify.py | 4 +- salt/beacons/journald.py | 1 + salt/beacons/load.py | 1 + salt/beacons/log_beacon.py | 1 + salt/beacons/memusage.py | 1 + salt/beacons/napalm_beacon.py | 2 +- salt/beacons/network_info.py | 1 + salt/beacons/pkg.py | 1 + salt/beacons/proxy_example.py | 1 + salt/beacons/ps.py | 1 + salt/beacons/salt_monitor.py | 11 +- salt/beacons/salt_proxy.py | 5 +- salt/beacons/sensehat.py | 5 +- salt/beacons/service.py | 1 + salt/beacons/sh.py | 3 +- salt/beacons/smartos_imgadm.py | 1 + salt/beacons/smartos_vmadm.py | 1 + salt/beacons/status.py | 7 +- salt/beacons/swapusage.py | 1 + salt/beacons/telegram_bot_msg.py | 1 + salt/beacons/twilio_txt_msg.py | 1 + salt/beacons/wtmp.py | 2 +- salt/cache/__init__.py | 17 +- salt/cache/etcd_cache.py | 38 +-- salt/cache/localfs.py | 24 +- salt/cache/redis_cache.py | 3 +- salt/channel/client.py | 1 + salt/cli/api.py | 1 - salt/cli/batch.py | 2 +- salt/cli/caller.py | 18 +- salt/cli/cp.py | 22 +- salt/cli/daemons.py | 1 - salt/cli/spm.py | 1 - salt/client/__init__.py | 1 - salt/client/mixins.py | 8 +- salt/client/netapi.py | 2 +- salt/client/ssh/__init__.py | 12 +- salt/client/ssh/ssh_py_shim.py | 4 +- salt/client/ssh/wrapper/__init__.py | 1 - salt/client/ssh/wrapper/cmdmod.py | 1 + salt/client/ssh/wrapper/grains.py | 1 - salt/client/ssh/wrapper/mine.py | 1 - salt/cloud/__init__.py | 1 + salt/cloud/cli.py | 21 +- salt/cloud/clouds/aliyun.py | 20 +- salt/cloud/clouds/cloudstack.py | 13 +- salt/cloud/clouds/ec2.py | 70 +++-- salt/cloud/clouds/gce.py | 28 +- salt/cloud/clouds/gogrid.py | 6 +- salt/cloud/clouds/hetzner.py | 43 +-- salt/cloud/clouds/joyent.py | 29 +- salt/cloud/clouds/libvirt.py | 32 +-- salt/cloud/clouds/lxc.py | 22 +- salt/cloud/clouds/oneandone.py | 22 +- salt/cloud/clouds/opennebula.py | 47 ++-- salt/cloud/clouds/openstack.py | 6 +- salt/cloud/clouds/packet.py | 14 +- salt/cloud/clouds/parallels.py | 24 +- salt/cloud/clouds/profitbricks.py | 24 +- salt/cloud/clouds/qingcloud.py | 22 +- salt/cloud/clouds/saltify.py | 10 +- salt/cloud/clouds/scaleway.py | 12 +- salt/cloud/clouds/softlayer.py | 10 +- salt/cloud/clouds/softlayer_hw.py | 10 +- salt/cloud/clouds/tencentcloud.py | 30 +- salt/cloud/clouds/vagrant.py | 12 +- salt/cloud/clouds/virtualbox.py | 6 +- salt/cloud/clouds/vmware.py | 162 ++++++----- salt/cloud/clouds/xen.py | 20 +- salt/cloud/libcloudfuncs.py | 20 +- salt/config/__init__.py | 1 + salt/config/schemas/common.py | 3 +- salt/config/schemas/esxcluster.py | 1 - salt/config/schemas/esxdatacenter.py | 1 - salt/config/schemas/esxi.py | 1 - salt/config/schemas/esxvm.py | 1 - salt/config/schemas/minion.py | 1 - salt/config/schemas/ssh.py | 1 - salt/daemons/__init__.py | 2 +- salt/daemons/masterapi.py | 4 +- salt/defaults/__init__.py | 4 +- salt/engines/__init__.py | 7 +- salt/engines/docker_events.py | 1 + salt/engines/ircbot.py | 18 +- salt/engines/libvirt_events.py | 10 +- salt/engines/napalm_syslog.py | 2 +- salt/engines/script.py | 2 +- salt/engines/slack.py | 7 +- salt/engines/slack_bolt_engine.py | 7 +- salt/exceptions.py | 2 +- salt/executors/sudo.py | 2 +- salt/features.py | 1 + salt/fileclient.py | 1 + salt/fileserver/__init__.py | 1 - salt/fileserver/gitfs.py | 1 - salt/fileserver/hgfs.py | 2 +- salt/fileserver/minionfs.py | 4 +- salt/fileserver/roots.py | 5 +- salt/fileserver/s3fs.py | 1 - salt/fileserver/svnfs.py | 3 +- salt/grains/cimc.py | 1 - salt/grains/core.py | 28 +- salt/grains/disks.py | 6 +- salt/grains/esxi.py | 1 - salt/grains/junos.py | 1 - salt/grains/lvm.py | 10 +- salt/grains/minion_process.py | 1 - salt/grains/napalm.py | 1 - salt/grains/package.py | 1 + salt/grains/panos.py | 1 - salt/grains/pending_reboot.py | 1 + salt/loader/context.py | 1 + salt/loader/dunder.py | 1 + salt/loader/lazy.py | 2 +- salt/log_handlers/fluent_mod.py | 8 +- salt/log_handlers/logstash_mod.py | 5 +- salt/log_handlers/sentry_mod.py | 2 +- salt/master.py | 25 +- salt/matchers/compound_match.py | 2 +- salt/matchers/confirm_top.py | 1 + salt/matchers/ipcidr_match.py | 2 +- salt/matchers/list_match.py | 2 +- salt/metaproxy/deltaproxy.py | 16 +- salt/minion.py | 1 + salt/modules/aix_group.py | 12 +- salt/modules/aix_shadow.py | 6 +- salt/modules/aixpkg.py | 30 +- salt/modules/aliases.py | 10 +- salt/modules/alternatives.py | 2 +- salt/modules/ansiblegate.py | 51 ++-- salt/modules/apache.py | 43 ++- salt/modules/apf.py | 8 +- salt/modules/apkpkg.py | 2 +- salt/modules/aptly.py | 34 +-- salt/modules/archive.py | 52 ++-- salt/modules/arista_pyeapi.py | 4 +- salt/modules/augeas_cfg.py | 16 +- salt/modules/aws_sqs.py | 6 +- salt/modules/bamboohr.py | 8 +- salt/modules/baredoc.py | 4 +- salt/modules/bcache.py | 50 ++-- salt/modules/beacons.py | 87 +++--- salt/modules/bigip.py | 72 ++--- salt/modules/bluez_bluetooth.py | 19 +- salt/modules/boto3_elasticache.py | 72 +++-- salt/modules/boto3_elasticsearch.py | 1 + salt/modules/boto3_route53.py | 26 +- salt/modules/boto3_sns.py | 1 + salt/modules/boto_apigateway.py | 21 +- salt/modules/boto_asg.py | 17 +- salt/modules/boto_cfn.py | 11 +- salt/modules/boto_cloudfront.py | 3 +- salt/modules/boto_cloudtrail.py | 3 +- salt/modules/boto_cloudwatch.py | 1 + salt/modules/boto_cloudwatch_event.py | 9 +- salt/modules/boto_cognitoidentity.py | 10 +- salt/modules/boto_datapipeline.py | 3 +- salt/modules/boto_dynamodb.py | 1 + salt/modules/boto_ec2.py | 28 +- salt/modules/boto_efs.py | 1 - salt/modules/boto_elasticache.py | 37 +-- salt/modules/boto_elasticsearch_domain.py | 5 +- salt/modules/boto_elb.py | 5 +- salt/modules/boto_elbv2.py | 1 + salt/modules/boto_iam.py | 3 +- salt/modules/boto_iot.py | 5 +- salt/modules/boto_kinesis.py | 3 +- salt/modules/boto_kms.py | 1 + salt/modules/boto_lambda.py | 9 +- salt/modules/boto_rds.py | 45 ++- salt/modules/boto_route53.py | 9 +- salt/modules/boto_s3.py | 1 + salt/modules/boto_s3_bucket.py | 3 +- salt/modules/boto_secgroup.py | 7 +- salt/modules/boto_sns.py | 5 +- salt/modules/boto_sqs.py | 1 + salt/modules/boto_ssm.py | 1 + salt/modules/boto_vpc.py | 118 ++++---- salt/modules/bsd_shadow.py | 7 +- salt/modules/btrfs.py | 100 +++---- salt/modules/cabal.py | 6 +- salt/modules/capirca_acl.py | 14 +- salt/modules/cassandra_cql.py | 36 +-- salt/modules/chef.py | 11 +- salt/modules/chronos.py | 6 +- salt/modules/chroot.py | 4 +- salt/modules/cimc.py | 23 +- salt/modules/ciscoconfparse_mod.py | 2 +- salt/modules/cloud.py | 1 - salt/modules/cmdmod.py | 123 ++++----- salt/modules/composer.py | 4 +- salt/modules/config.py | 4 +- salt/modules/consul.py | 100 ++++--- salt/modules/container_resource.py | 1 + salt/modules/cpan.py | 4 +- salt/modules/cron.py | 8 +- salt/modules/cryptdev.py | 10 +- salt/modules/csf.py | 46 +-- salt/modules/cyg.py | 16 +- salt/modules/daemontools.py | 16 +- salt/modules/datadog_api.py | 2 +- salt/modules/ddns.py | 18 +- salt/modules/deb_postgres.py | 7 +- salt/modules/debconfmod.py | 6 +- salt/modules/debian_ip.py | 46 ++- salt/modules/debian_service.py | 6 +- salt/modules/debuild_pkgbuild.py | 61 ++-- salt/modules/defaults.py | 1 - salt/modules/devinfo.py | 4 +- salt/modules/devmap.py | 4 +- salt/modules/dig.py | 16 +- salt/modules/djangomod.py | 19 +- salt/modules/dnsmasq.py | 11 +- salt/modules/dnsutil.py | 14 +- salt/modules/dockercompose.py | 1 - salt/modules/dockermod.py | 6 +- salt/modules/dpkg_lowpkg.py | 14 +- salt/modules/drac.py | 23 +- salt/modules/dracr.py | 55 ++-- salt/modules/ebuildpkg.py | 32 +-- salt/modules/elasticsearch.py | 1 - salt/modules/eselect.py | 3 +- salt/modules/esxi.py | 1 - salt/modules/esxvm.py | 1 - salt/modules/ethtool.py | 6 +- salt/modules/event.py | 1 - salt/modules/extfs.py | 1 - salt/modules/file.py | 16 +- salt/modules/firewalld.py | 67 +++-- salt/modules/freebsd_sysctl.py | 17 +- salt/modules/freebsd_update.py | 3 +- salt/modules/freebsdjail.py | 9 +- salt/modules/freebsdkmod.py | 6 +- salt/modules/freebsdpkg.py | 6 +- salt/modules/freebsdports.py | 20 +- salt/modules/freebsdservice.py | 42 ++- salt/modules/freezer.py | 4 +- salt/modules/genesis.py | 86 +++--- salt/modules/gentoo_service.py | 1 - salt/modules/gentoolkitmod.py | 8 +- salt/modules/github.py | 9 +- salt/modules/glanceng.py | 1 - salt/modules/glassfish.py | 16 +- salt/modules/glusterfs.py | 64 ++--- salt/modules/gnomedesktop.py | 7 +- salt/modules/gpg.py | 38 +-- salt/modules/grains.py | 11 +- salt/modules/grub_legacy.py | 6 +- salt/modules/haproxyconn.py | 6 +- salt/modules/hashutil.py | 1 - salt/modules/heat.py | 46 +-- salt/modules/helm.py | 3 +- salt/modules/hg.py | 23 +- salt/modules/highstate_doc.py | 26 +- salt/modules/hosts.py | 3 +- salt/modules/http.py | 1 - salt/modules/icinga2.py | 21 +- salt/modules/ifttt.py | 3 +- salt/modules/ilo.py | 8 +- salt/modules/incron.py | 14 +- salt/modules/influxdb08mod.py | 1 - salt/modules/influxdbmod.py | 11 +- salt/modules/infoblox.py | 10 +- salt/modules/inspectlib/collector.py | 8 +- salt/modules/inspectlib/fsdb.py | 4 +- salt/modules/inspectlib/kiwiproc.py | 6 +- salt/modules/inspectlib/query.py | 14 +- salt/modules/inspector.py | 2 +- salt/modules/iosconfig.py | 2 +- salt/modules/ipmi.py | 9 +- salt/modules/ipset.py | 1 - salt/modules/iptables.py | 58 ++-- salt/modules/iwtools.py | 8 +- salt/modules/jboss7.py | 39 ++- salt/modules/jboss7_cli.py | 5 +- salt/modules/jenkinsmod.py | 43 +-- salt/modules/junos.py | 132 ++++----- salt/modules/kapacitor.py | 24 +- salt/modules/kerberos.py | 19 +- salt/modules/kernelpkg_linux_apt.py | 18 +- salt/modules/kernelpkg_linux_yum.py | 6 +- salt/modules/keyboard.py | 13 +- salt/modules/keystone.py | 58 ++-- salt/modules/keystoneng.py | 3 +- salt/modules/keystore.py | 5 +- salt/modules/kmod.py | 10 +- salt/modules/launchctl_service.py | 7 +- salt/modules/layman.py | 6 +- salt/modules/ldap3.py | 7 +- salt/modules/ldapmod.py | 9 +- salt/modules/libcloud_compute.py | 3 +- salt/modules/libcloud_dns.py | 1 + salt/modules/libcloud_loadbalancer.py | 1 + salt/modules/libcloud_storage.py | 1 + salt/modules/linux_acl.py | 12 +- salt/modules/linux_ip.py | 6 +- salt/modules/linux_lvm.py | 58 ++-- salt/modules/linux_service.py | 2 +- salt/modules/linux_shadow.py | 2 +- salt/modules/linux_sysctl.py | 16 +- salt/modules/localemod.py | 26 +- salt/modules/locate.py | 8 +- salt/modules/logadm.py | 12 +- salt/modules/logrotate.py | 10 +- salt/modules/lvs.py | 18 +- salt/modules/lxc.py | 7 +- salt/modules/lxd.py | 91 +++--- salt/modules/mac_desktop.py | 4 +- salt/modules/mac_group.py | 13 +- salt/modules/mac_pkgutil.py | 8 +- salt/modules/mac_portspkg.py | 4 +- salt/modules/mac_shadow.py | 1 + salt/modules/mac_softwareupdate.py | 4 +- salt/modules/mac_sysctl.py | 14 +- salt/modules/mac_timezone.py | 12 +- salt/modules/mac_user.py | 42 +-- salt/modules/mac_xattr.py | 28 +- salt/modules/macdefaults.py | 6 +- salt/modules/makeconf.py | 14 +- salt/modules/mandrill.py | 1 - salt/modules/marathon.py | 15 +- salt/modules/mattermost.py | 1 - salt/modules/mdadm_raid.py | 13 +- salt/modules/mdata.py | 1 - salt/modules/memcached.py | 10 +- salt/modules/mine.py | 5 +- salt/modules/minion.py | 4 +- salt/modules/modjk.py | 33 ++- salt/modules/mongodb.py | 8 +- salt/modules/monit.py | 10 +- salt/modules/mount.py | 1 - salt/modules/mssql.py | 83 +++--- salt/modules/munin.py | 4 +- salt/modules/mysql.py | 1 - salt/modules/nacl.py | 1 - salt/modules/nagios.py | 5 +- salt/modules/nagios_rpc.py | 3 +- salt/modules/namecheap_domains.py | 8 +- salt/modules/namecheap_domains_dns.py | 1 - salt/modules/napalm_bgp.py | 3 - salt/modules/napalm_formula.py | 2 +- salt/modules/napalm_network.py | 75 ++--- salt/modules/napalm_ntp.py | 7 - salt/modules/napalm_probes.py | 4 - salt/modules/napalm_route.py | 2 - salt/modules/napalm_snmp.py | 4 - salt/modules/napalm_users.py | 4 - salt/modules/netaddress.py | 1 - salt/modules/netbox.py | 4 +- salt/modules/netmiko_mod.py | 4 +- salt/modules/netscaler.py | 2 +- salt/modules/neutronng.py | 1 - salt/modules/nexus.py | 12 +- salt/modules/nfs3.py | 4 +- salt/modules/nftables.py | 80 +++--- salt/modules/nginx.py | 10 +- salt/modules/nilrt_ip.py | 98 +++---- salt/modules/nix.py | 1 - salt/modules/npm.py | 14 +- salt/modules/nspawn.py | 1 - salt/modules/nxos_api.py | 6 +- salt/modules/nxos_upgrade.py | 12 +- salt/modules/omapi.py | 5 +- salt/modules/openbsd_sysctl.py | 10 +- salt/modules/openbsdpkg.py | 12 +- salt/modules/openbsdrcctl_service.py | 36 ++- salt/modules/openbsdservice.py | 13 +- salt/modules/opkg.py | 24 +- salt/modules/osquery.py | 16 +- salt/modules/pacmanpkg.py | 2 +- salt/modules/pagerduty_util.py | 10 +- salt/modules/pam.py | 2 +- salt/modules/panos.py | 55 ++-- salt/modules/parallels.py | 12 +- salt/modules/parted_partition.py | 38 ++- salt/modules/pcs.py | 9 +- salt/modules/pecl.py | 6 +- salt/modules/peeringdb.py | 4 +- salt/modules/pf.py | 23 +- salt/modules/pip.py | 10 +- salt/modules/pkg_resource.py | 5 +- salt/modules/pkgng.py | 34 ++- salt/modules/pkgutil.py | 4 +- salt/modules/portage_config.py | 6 +- salt/modules/postfix.py | 54 ++-- salt/modules/postgres.py | 2 +- salt/modules/poudriere.py | 50 ++-- salt/modules/powerpath.py | 4 +- salt/modules/proxy.py | 13 +- salt/modules/ps.py | 1 - salt/modules/publish.py | 6 +- salt/modules/puppet.py | 25 +- salt/modules/purefb.py | 2 +- salt/modules/pushbullet.py | 1 - salt/modules/pushover_notify.py | 1 - salt/modules/pw_group.py | 14 +- salt/modules/pw_user.py | 18 +- salt/modules/pyenv.py | 26 +- salt/modules/qemu_img.py | 2 +- salt/modules/qemu_nbd.py | 13 +- salt/modules/quota.py | 8 +- salt/modules/rabbitmq.py | 24 +- salt/modules/rallydev.py | 3 +- salt/modules/random_org.py | 31 ++- salt/modules/rbenv.py | 9 +- salt/modules/rdp.py | 4 +- salt/modules/reg.py | 5 +- salt/modules/restartcheck.py | 21 +- salt/modules/restconf.py | 3 +- salt/modules/ret.py | 8 +- salt/modules/rh_ip.py | 33 +-- salt/modules/riak.py | 6 +- salt/modules/rpm_lowpkg.py | 12 +- salt/modules/rpmbuild_pkgbuild.py | 27 +- salt/modules/rsync.py | 18 +- salt/modules/rvm.py | 6 +- salt/modules/s6.py | 14 +- salt/modules/salt_proxy.py | 22 +- salt/modules/salt_version.py | 1 - salt/modules/saltcheck.py | 13 +- salt/modules/saltcloudmod.py | 2 +- salt/modules/saltutil.py | 10 +- salt/modules/schedule.py | 35 +-- salt/modules/scp_mod.py | 4 +- salt/modules/scsi.py | 8 +- salt/modules/sdb.py | 1 - salt/modules/seed.py | 9 +- salt/modules/sensehat.py | 1 - salt/modules/sensors.py | 2 +- salt/modules/serverdensity_device.py | 21 +- salt/modules/servicenow.py | 2 +- salt/modules/slack_notify.py | 3 +- salt/modules/slsutil.py | 1 - salt/modules/smartos_imgadm.py | 4 +- salt/modules/smartos_nictagadm.py | 24 +- salt/modules/smartos_virt.py | 10 +- salt/modules/smartos_vmadm.py | 10 +- salt/modules/smbios.py | 6 +- salt/modules/smf_service.py | 25 +- salt/modules/smtp.py | 3 +- salt/modules/snapper.py | 31 +-- salt/modules/solaris_group.py | 6 +- salt/modules/solaris_shadow.py | 12 +- salt/modules/solaris_user.py | 15 +- salt/modules/solarisipspkg.py | 8 +- salt/modules/solarispkg.py | 22 +- salt/modules/solr.py | 33 ++- salt/modules/solrcloud.py | 14 +- salt/modules/splunk_search.py | 4 +- salt/modules/ssh.py | 32 +-- salt/modules/state.py | 2 +- salt/modules/status.py | 22 +- salt/modules/statuspage.py | 1 - salt/modules/supervisord.py | 15 +- salt/modules/suse_ip.py | 30 +- salt/modules/sysbench.py | 10 +- salt/modules/sysfs.py | 2 +- salt/modules/syslog_ng.py | 25 +- salt/modules/system_profiler.py | 1 - salt/modules/telegram.py | 2 +- salt/modules/telemetry.py | 19 +- salt/modules/testinframod.py | 2 +- salt/modules/textfsm_mod.py | 48 ++-- salt/modules/timezone.py | 1 - salt/modules/tls.py | 176 ++++++------ salt/modules/tomcat.py | 18 +- salt/modules/travisci.py | 1 + salt/modules/udev.py | 2 +- salt/modules/upstart_service.py | 18 +- salt/modules/uptime.py | 17 +- salt/modules/uwsgi.py | 2 +- salt/modules/vault.py | 1 + salt/modules/vbox_guest.py | 18 +- salt/modules/vboxmanage.py | 77 +++--- salt/modules/victorops.py | 5 +- salt/modules/virt.py | 239 ++++++++-------- salt/modules/virtualenv_mod.py | 17 +- salt/modules/vmctl.py | 11 +- salt/modules/vsphere.py | 51 ++-- salt/modules/webutil.py | 5 +- salt/modules/win_appx.py | 1 + salt/modules/win_autoruns.py | 1 - salt/modules/win_certutil.py | 14 +- salt/modules/win_dacl.py | 31 +-- salt/modules/win_disk.py | 12 +- salt/modules/win_dns_client.py | 2 +- salt/modules/win_dsc.py | 54 ++-- salt/modules/win_event.py | 5 +- salt/modules/win_firewall.py | 24 +- salt/modules/win_iis.py | 197 +++++++------ salt/modules/win_ip.py | 34 +-- salt/modules/win_lgpo.py | 73 ++--- salt/modules/win_lgpo_reg.py | 1 + salt/modules/win_license.py | 3 +- salt/modules/win_network.py | 4 +- salt/modules/win_pkg.py | 1 - salt/modules/win_pki.py | 40 +-- salt/modules/win_powercfg.py | 4 +- salt/modules/win_psget.py | 22 +- salt/modules/win_servermanager.py | 1 - salt/modules/win_service.py | 43 ++- salt/modules/win_shortcut.py | 19 +- salt/modules/win_smtp_server.py | 8 +- salt/modules/win_snmp.py | 6 +- salt/modules/win_status.py | 1 + salt/modules/win_task.py | 52 ++-- salt/modules/win_timezone.py | 7 +- salt/modules/win_useradd.py | 18 +- salt/modules/win_wua.py | 5 +- salt/modules/win_wusa.py | 1 - salt/modules/winrepo.py | 11 +- salt/modules/wordpress.py | 14 +- salt/modules/x509_v2.py | 9 +- salt/modules/xapi_virt.py | 16 +- salt/modules/xbpspkg.py | 6 +- salt/modules/xfs.py | 36 +-- salt/modules/xmpp.py | 1 - salt/modules/yumpkg.py | 1 + salt/modules/zcbuildout.py | 7 +- salt/modules/zenoss.py | 2 +- salt/modules/zypperpkg.py | 17 +- salt/netapi/__init__.py | 3 +- salt/netapi/rest_cherrypy/app.py | 14 +- salt/netapi/rest_wsgi.py | 2 +- salt/output/__init__.py | 3 +- salt/output/highstate.py | 13 +- salt/output/key.py | 2 +- salt/output/overstatestage.py | 1 - salt/output/pony.py | 1 - salt/output/profile.py | 4 +- salt/output/progress.py | 1 - salt/output/raw.py | 1 - salt/output/table_out.py | 10 +- salt/output/txt.py | 6 +- salt/output/virt_query.py | 8 +- salt/pillar/cmd_yamlex.py | 1 - salt/pillar/cobbler.py | 3 +- salt/pillar/consul_pillar.py | 1 - salt/pillar/django_orm.py | 6 +- salt/pillar/ec2_pillar.py | 5 +- salt/pillar/extra_minion_data_in_pillar.py | 1 + salt/pillar/gpg.py | 1 - salt/pillar/hiera.py | 5 +- salt/pillar/http_json.py | 3 +- salt/pillar/http_yaml.py | 3 +- salt/pillar/libvirt.py | 11 +- salt/pillar/makostack.py | 9 +- salt/pillar/nacl.py | 1 - salt/pillar/neutron.py | 1 - salt/pillar/pepa.py | 2 +- salt/pillar/puppet.py | 4 +- salt/pillar/reclass_adapter.py | 3 +- salt/pillar/s3.py | 4 +- salt/pillar/saltclass.py | 1 - salt/pillar/stack.py | 13 +- salt/pillar/varstack_pillar.py | 1 - salt/pillar/vault.py | 1 - salt/platform/win.py | 18 +- salt/proxy/chronos.py | 2 +- salt/proxy/cisconso.py | 1 - salt/proxy/dummy.py | 4 +- salt/proxy/esxcluster.py | 1 + salt/proxy/esxdatacenter.py | 1 - salt/proxy/esxi.py | 1 - salt/proxy/esxvm.py | 1 - salt/proxy/marathon.py | 2 +- salt/proxy/napalm.py | 2 +- salt/proxy/philips_hue.py | 8 +- salt/proxy/rest_sample.py | 2 - salt/proxy/restconf.py | 1 - salt/queues/pgjsonb_queue.py | 25 +- salt/queues/sqlite_queue.py | 28 +- salt/renderers/cheetah.py | 1 - salt/renderers/dson.py | 1 - salt/renderers/genshi.py | 1 - salt/renderers/gpg.py | 1 - salt/renderers/hjson.py | 1 - salt/renderers/jinja.py | 7 +- salt/renderers/json.py | 1 - salt/renderers/json5.py | 1 - salt/renderers/mako.py | 1 - salt/renderers/nacl.py | 1 - salt/renderers/pass.py | 1 - salt/renderers/py.py | 4 +- salt/renderers/pydsl.py | 1 + salt/renderers/pyobjects.py | 9 +- salt/renderers/stateconf.py | 9 +- salt/renderers/yaml.py | 1 - salt/returners/__init__.py | 8 +- salt/returners/appoptics_return.py | 1 - salt/returners/carbon_return.py | 4 +- salt/returners/couchdb_return.py | 3 +- salt/returners/elasticsearch_return.py | 11 +- salt/returners/influxdb_return.py | 8 +- salt/returners/librato_return.py | 1 - salt/returners/local_cache.py | 4 +- salt/returners/mattermost_returner.py | 4 +- salt/returners/memcache_return.py | 12 +- salt/returners/multi_returner.py | 19 +- salt/returners/mysql.py | 2 +- salt/returners/odbc.py | 4 +- salt/returners/pgjsonb.py | 6 +- salt/returners/postgres.py | 4 +- salt/returners/postgres_local_cache.py | 1 - salt/returners/rawfile_json.py | 1 - salt/returners/sentry_return.py | 6 +- salt/returners/slack_webhook_return.py | 12 +- salt/returners/smtp_return.py | 5 +- salt/returners/zabbix_return.py | 1 - salt/roster/__init__.py | 8 +- salt/roster/cache.py | 16 +- salt/roster/cloud.py | 1 - salt/roster/clustershell.py | 1 - salt/roster/dir.py | 7 +- salt/roster/sshconfig.py | 4 +- salt/roster/sshknownhosts.py | 5 +- salt/runners/asam.py | 20 +- salt/runners/auth.py | 1 - salt/runners/bgp.py | 4 +- salt/runners/cache.py | 2 +- salt/runners/ddns.py | 30 +- salt/runners/digicertapi.py | 33 +-- salt/runners/drac.py | 3 +- salt/runners/f5.py | 26 +- salt/runners/jobs.py | 30 +- salt/runners/launchd.py | 2 +- salt/runners/lxc.py | 11 +- salt/runners/manage.py | 11 +- salt/runners/match.py | 1 + salt/runners/mattermost.py | 5 +- salt/runners/nacl.py | 1 - salt/runners/net.py | 26 +- salt/runners/network.py | 5 +- salt/runners/pkg.py | 3 +- salt/runners/queue.py | 27 +- salt/runners/salt.py | 6 +- salt/runners/spacewalk.py | 18 +- salt/runners/ssh.py | 1 - salt/runners/test.py | 4 +- salt/runners/thin.py | 1 - salt/runners/venafiapi.py | 8 +- salt/runners/virt.py | 59 ++-- salt/runners/vistara.py | 8 +- salt/runners/winrepo.py | 2 +- salt/scripts.py | 4 +- salt/sdb/cache.py | 1 - salt/sdb/couchdb.py | 1 - salt/sdb/etcd_db.py | 1 - salt/sdb/rest.py | 1 - salt/sdb/sqlite3.py | 8 +- salt/sdb/tism.py | 1 - salt/sdb/vault.py | 1 - salt/sdb/yaml.py | 1 - salt/serializers/__init__.py | 1 - salt/serializers/configparser.py | 2 +- salt/serializers/json.py | 1 - salt/serializers/msgpack.py | 1 - salt/serializers/plist.py | 1 + salt/serializers/yaml.py | 1 - salt/serializers/yamlex.py | 3 +- salt/spm/__init__.py | 92 +++--- salt/spm/pkgdb/sqlite3.py | 3 +- salt/spm/pkgfiles/local.py | 25 +- salt/state.py | 16 +- salt/states/alias.py | 16 +- salt/states/alternatives.py | 44 +-- salt/states/apache.py | 1 - salt/states/aptpkg.py | 9 +- salt/states/archive.py | 46 +-- salt/states/artifactory.py | 1 - salt/states/at.py | 8 +- salt/states/aws_sqs.py | 8 +- salt/states/beacon.py | 26 +- salt/states/bigip.py | 49 ++-- salt/states/blockdev.py | 24 +- salt/states/boto3_elasticache.py | 76 ++--- salt/states/boto3_elasticsearch.py | 25 +- salt/states/boto3_route53.py | 101 +++---- salt/states/boto3_sns.py | 29 +- salt/states/boto_apigateway.py | 141 +++++----- salt/states/boto_asg.py | 5 +- salt/states/boto_cfn.py | 18 +- salt/states/boto_cloudfront.py | 9 +- salt/states/boto_cloudtrail.py | 21 +- salt/states/boto_cloudwatch_alarm.py | 21 +- salt/states/boto_cloudwatch_event.py | 13 +- salt/states/boto_cognitoidentity.py | 55 ++-- salt/states/boto_datapipeline.py | 13 +- salt/states/boto_dynamodb.py | 44 ++- salt/states/boto_ec2.py | 112 ++++---- salt/states/boto_elasticache.py | 39 ++- salt/states/boto_elasticsearch_domain.py | 29 +- salt/states/boto_elb.py | 133 +++++---- salt/states/boto_elbv2.py | 43 ++- salt/states/boto_iam.py | 174 ++++++------ salt/states/boto_iam_role.py | 56 ++-- salt/states/boto_iot.py | 46 ++- salt/states/boto_kinesis.py | 24 +- salt/states/boto_kms.py | 8 +- salt/states/boto_lambda.py | 45 ++- salt/states/boto_rds.py | 61 ++-- salt/states/boto_route53.py | 43 ++- salt/states/boto_s3.py | 13 +- salt/states/boto_s3_bucket.py | 31 +-- salt/states/boto_secgroup.py | 50 ++-- salt/states/boto_sns.py | 14 +- salt/states/boto_sqs.py | 12 +- salt/states/boto_vpc.py | 84 +++--- salt/states/bower.py | 29 +- salt/states/btrfs.py | 38 ++- salt/states/cabal.py | 15 +- salt/states/chocolatey.py | 24 +- salt/states/chronos_job.py | 14 +- salt/states/cimc.py | 7 +- salt/states/cloud.py | 61 ++-- salt/states/cmd.py | 39 ++- salt/states/composer.py | 34 +-- salt/states/consul.py | 5 +- salt/states/cron.py | 60 ++-- salt/states/cryptdev.py | 14 +- salt/states/csf.py | 8 +- salt/states/cyg.py | 4 +- salt/states/ddns.py | 6 +- salt/states/debconfmod.py | 4 +- salt/states/dellchassis.py | 9 +- salt/states/disk.py | 20 +- salt/states/docker_container.py | 18 +- salt/states/docker_image.py | 8 +- salt/states/docker_network.py | 18 +- salt/states/drac.py | 16 +- salt/states/dvs.py | 31 +-- salt/states/elasticsearch.py | 159 ++++++----- salt/states/elasticsearch_index.py | 19 +- salt/states/elasticsearch_index_template.py | 21 +- salt/states/environ.py | 1 - salt/states/eselect.py | 5 +- salt/states/esxcluster.py | 23 +- salt/states/esxdatacenter.py | 1 - salt/states/esxi.py | 10 +- salt/states/esxvm.py | 1 - salt/states/etcd_mod.py | 3 +- salt/states/ethtool.py | 57 ++-- salt/states/event.py | 1 - salt/states/file.py | 69 +++-- salt/states/firewalld.py | 2 - salt/states/gem.py | 6 +- salt/states/git.py | 196 ++++++------- salt/states/github.py | 128 +++++---- salt/states/glance_image.py | 5 +- salt/states/glassfish.py | 24 +- salt/states/glusterfs.py | 67 +++-- salt/states/gnomedesktop.py | 12 +- salt/states/grafana.py | 22 +- salt/states/grafana4_dashboard.py | 15 +- salt/states/grafana4_datasource.py | 16 +- salt/states/grafana4_org.py | 18 +- salt/states/grafana4_user.py | 18 +- salt/states/grafana_dashboard.py | 19 +- salt/states/grafana_datasource.py | 10 +- salt/states/grains.py | 74 +++-- salt/states/group.py | 7 +- salt/states/heat.py | 16 +- salt/states/helm.py | 8 +- salt/states/hg.py | 23 +- salt/states/highstate_doc.py | 3 +- salt/states/host.py | 37 ++- salt/states/http.py | 23 +- salt/states/icinga2.py | 55 ++-- salt/states/idem.py | 6 +- salt/states/ifttt.py | 4 +- salt/states/incron.py | 20 +- salt/states/influxdb08_database.py | 12 +- salt/states/influxdb08_user.py | 16 +- salt/states/influxdb_continuous_query.py | 20 +- salt/states/influxdb_database.py | 14 +- salt/states/influxdb_retention_policy.py | 26 +- salt/states/influxdb_user.py | 28 +- salt/states/infoblox_a.py | 14 +- salt/states/infoblox_cname.py | 14 +- salt/states/infoblox_host_record.py | 16 +- salt/states/infoblox_range.py | 4 +- salt/states/ini_manage.py | 37 ++- salt/states/ipmi.py | 6 +- salt/states/ipset.py | 22 +- salt/states/iptables.py | 67 ++--- salt/states/jboss7.py | 15 +- salt/states/jenkins.py | 11 +- salt/states/kapacitor.py | 3 +- salt/states/kernelpkg.py | 6 +- salt/states/keyboard.py | 12 +- salt/states/keystone.py | 122 ++++---- salt/states/keystone_domain.py | 7 +- salt/states/keystone_endpoint.py | 1 - salt/states/keystone_group.py | 1 - salt/states/keystone_project.py | 1 - salt/states/keystone_role.py | 1 - salt/states/keystone_role_grant.py | 1 - salt/states/keystone_service.py | 1 - salt/states/keystone_user.py | 1 - salt/states/keystore.py | 5 +- salt/states/kmod.py | 16 +- salt/states/layman.py | 18 +- salt/states/libcloud_dns.py | 2 +- salt/states/libcloud_loadbalancer.py | 1 - salt/states/libcloud_storage.py | 1 - salt/states/linux_acl.py | 1 - salt/states/locale.py | 19 +- salt/states/logrotate.py | 7 +- salt/states/loop.py | 19 +- salt/states/lvm.py | 28 +- salt/states/lvs_server.py | 64 ++--- salt/states/lvs_service.py | 28 +- salt/states/lxc.py | 55 ++-- salt/states/lxd.py | 13 +- salt/states/lxd_container.py | 73 +++-- salt/states/lxd_image.py | 21 +- salt/states/lxd_profile.py | 23 +- salt/states/mac_assistive.py | 4 +- salt/states/mac_keychain.py | 14 +- salt/states/macdefaults.py | 12 +- salt/states/macpackage.py | 14 +- salt/states/makeconf.py | 6 +- salt/states/marathon_app.py | 20 +- salt/states/mdadm_raid.py | 49 ++-- salt/states/memcached.py | 21 +- salt/states/modjk.py | 6 +- salt/states/modjk_worker.py | 18 +- salt/states/module.py | 21 +- salt/states/mongodb_database.py | 4 +- salt/states/mongodb_user.py | 18 +- salt/states/monit.py | 16 +- salt/states/mount.py | 32 +-- salt/states/mssql_database.py | 24 +- salt/states/mssql_login.py | 26 +- salt/states/mssql_role.py | 22 +- salt/states/mssql_user.py | 26 +- salt/states/msteams.py | 7 +- salt/states/mysql_database.py | 22 +- salt/states/mysql_grants.py | 36 +-- salt/states/mysql_query.py | 17 +- salt/states/mysql_user.py | 28 +- salt/states/netconfig.py | 16 +- salt/states/netntp.py | 28 +- salt/states/netsnmp.py | 16 +- salt/states/netusers.py | 11 +- salt/states/network.py | 64 ++--- salt/states/neutron_network.py | 3 +- salt/states/neutron_secgroup.py | 1 - salt/states/neutron_secgroup_rule.py | 3 +- salt/states/neutron_subnet.py | 1 - salt/states/nexus.py | 1 - salt/states/nfs_export.py | 12 +- salt/states/nftables.py | 102 +++---- salt/states/npm.py | 25 +- salt/states/nxos.py | 4 +- salt/states/nxos_upgrade.py | 4 +- salt/states/openstack_config.py | 3 +- salt/states/openvswitch_port.py | 80 +++--- salt/states/opsgenie.py | 16 +- salt/states/pagerduty.py | 4 +- salt/states/pagerduty_escalation_policy.py | 6 +- salt/states/pagerduty_schedule.py | 2 +- salt/states/pagerduty_service.py | 2 +- salt/states/panos.py | 60 ++-- salt/states/pbm.py | 15 +- salt/states/pecl.py | 18 +- salt/states/pip_state.py | 5 +- salt/states/pkg.py | 67 ++--- salt/states/pkgbuild.py | 2 +- salt/states/pkgrepo.py | 19 +- salt/states/ports.py | 36 +-- salt/states/postgres_cluster.py | 6 +- salt/states/postgres_database.py | 22 +- salt/states/postgres_extension.py | 16 +- salt/states/postgres_group.py | 20 +- salt/states/postgres_initdb.py | 8 +- salt/states/postgres_language.py | 16 +- salt/states/postgres_privileges.py | 8 +- salt/states/postgres_schema.py | 12 +- salt/states/postgres_tablespace.py | 35 ++- salt/states/postgres_user.py | 22 +- salt/states/powerpath.py | 8 +- salt/states/probes.py | 10 - salt/states/process.py | 2 +- salt/states/proxy.py | 6 +- salt/states/pyenv.py | 8 +- salt/states/pyrax_queues.py | 12 +- salt/states/quota.py | 10 +- salt/states/rabbitmq_cluster.py | 6 +- salt/states/rabbitmq_plugin.py | 21 +- salt/states/rabbitmq_policy.py | 12 +- salt/states/rabbitmq_upstream.py | 21 +- salt/states/rabbitmq_user.py | 37 ++- salt/states/rabbitmq_vhost.py | 9 +- salt/states/rbac_solaris.py | 4 +- salt/states/rbenv.py | 12 +- salt/states/redismod.py | 12 +- salt/states/restconf.py | 1 - salt/states/rsync.py | 2 +- salt/states/rvm.py | 6 +- salt/states/salt_proxy.py | 2 +- salt/states/saltmod.py | 8 +- salt/states/serverdensity_device.py | 13 +- salt/states/service.py | 151 +++++----- salt/states/slack.py | 5 +- salt/states/smartos.py | 20 +- salt/states/smtp.py | 4 +- salt/states/snapper.py | 5 +- salt/states/solrcloud.py | 15 +- salt/states/splunk.py | 22 +- salt/states/splunk_search.py | 14 +- salt/states/sqlite3.py | 1 - salt/states/ssh_auth.py | 15 +- salt/states/ssh_known_hosts.py | 14 +- salt/states/status.py | 8 +- salt/states/statuspage.py | 18 +- salt/states/supervisord.py | 56 ++-- salt/states/svn.py | 14 +- salt/states/sysctl.py | 8 +- salt/states/sysfs.py | 12 +- salt/states/sysrc.py | 15 +- salt/states/telemetry_alert.py | 18 +- salt/states/test.py | 6 +- salt/states/testinframod.py | 2 +- salt/states/timezone.py | 22 +- salt/states/tls.py | 5 +- salt/states/tomcat.py | 8 +- salt/states/trafficserver.py | 6 +- salt/states/uptime.py | 4 +- salt/states/user.py | 38 +-- salt/states/vagrant.py | 10 +- salt/states/vbox_guest.py | 6 +- salt/states/victorops.py | 2 +- salt/states/virt.py | 77 +++--- salt/states/virtualenv_mod.py | 23 +- salt/states/webutil.py | 7 +- salt/states/win_appx.py | 1 + salt/states/win_certutil.py | 28 +- salt/states/win_dns_client.py | 22 +- salt/states/win_firewall.py | 12 +- salt/states/win_iis.py | 73 +++-- salt/states/win_lgpo.py | 5 +- salt/states/win_lgpo_reg.py | 5 +- salt/states/win_network.py | 46 +-- salt/states/win_path.py | 20 +- salt/states/win_pki.py | 21 +- salt/states/win_powercfg.py | 13 +- salt/states/win_shortcut.py | 13 +- salt/states/win_smtp_server.py | 15 +- salt/states/win_snmp.py | 6 +- salt/states/win_system.py | 60 ++-- salt/states/win_task.py | 6 +- salt/states/win_wusa.py | 17 +- salt/states/winrepo.py | 4 +- salt/states/wordpress.py | 28 +- salt/states/x509_v2.py | 31 ++- salt/states/xml.py | 8 +- salt/states/xmpp.py | 8 +- salt/states/zabbix_action.py | 8 +- salt/states/zabbix_hostgroup.py | 1 + salt/states/zabbix_template.py | 8 +- salt/states/zabbix_user.py | 6 +- salt/states/zabbix_valuemap.py | 8 +- salt/states/zenoss.py | 23 +- salt/states/zk_concurrency.py | 7 +- salt/states/zone.py | 144 +++++----- salt/states/zookeeper.py | 37 ++- salt/syspaths.py | 1 - salt/template.py | 5 +- salt/thorium/__init__.py | 7 +- salt/thorium/calc.py | 3 +- salt/thorium/check.py | 26 +- salt/thorium/file.py | 1 - salt/thorium/reg.py | 1 - salt/thorium/timer.py | 1 - salt/tokens/localfs.py | 3 +- salt/tops/cobbler.py | 3 +- salt/tops/ext_nodes.py | 1 + salt/tops/reclass_adapter.py | 8 +- salt/tops/saltclass.py | 1 - salt/tops/varstack_top.py | 1 - salt/transport/__init__.py | 1 + salt/transport/client.py | 1 + salt/transport/frame.py | 1 - salt/transport/ipc.py | 1 - salt/transport/server.py | 1 + salt/transport/tcp.py | 1 + salt/transport/zeromq.py | 2 +- salt/utils/aggregation.py | 2 - salt/utils/ansible.py | 6 +- salt/utils/args.py | 15 +- salt/utils/asynchronous.py | 1 - salt/utils/atomicfile.py | 3 +- salt/utils/aws.py | 1 + salt/utils/boto3mod.py | 11 +- salt/utils/botomod.py | 9 +- salt/utils/cloud.py | 7 +- salt/utils/color.py | 3 +- salt/utils/configcomparer.py | 10 +- salt/utils/configparser.py | 6 +- salt/utils/crypt.py | 1 + salt/utils/data.py | 3 +- salt/utils/dateutils.py | 7 +- salt/utils/debug.py | 8 +- salt/utils/decorators/__init__.py | 23 +- .../utils/decorators/extension_deprecation.py | 1 + salt/utils/decorators/path.py | 4 +- salt/utils/decorators/state.py | 5 +- salt/utils/dns.py | 54 ++-- salt/utils/doc.py | 1 + salt/utils/dockermod/__init__.py | 1 - salt/utils/dockermod/translate/container.py | 26 +- salt/utils/dockermod/translate/helpers.py | 22 +- salt/utils/extend.py | 13 +- salt/utils/files.py | 31 +-- salt/utils/find.py | 29 +- salt/utils/fsutils.py | 3 +- salt/utils/functools.py | 1 + salt/utils/gitfs.py | 12 +- salt/utils/github.py | 3 +- salt/utils/gzip_util.py | 1 - salt/utils/hashutils.py | 4 +- salt/utils/http.py | 16 +- salt/utils/idem.py | 1 + salt/utils/immutabletypes.py | 6 +- salt/utils/itertools.py | 1 - salt/utils/jid.py | 4 +- salt/utils/job.py | 1 - salt/utils/json.py | 1 - salt/utils/kickstart.py | 2 +- salt/utils/lazy.py | 3 +- salt/utils/locales.py | 1 + salt/utils/mac_utils.py | 6 +- salt/utils/master.py | 15 +- salt/utils/mattermost.py | 2 +- salt/utils/memcached.py | 3 +- salt/utils/mine.py | 1 - salt/utils/minion.py | 3 +- salt/utils/minions.py | 1 - salt/utils/mount.py | 1 - salt/utils/msgpack.py | 1 + salt/utils/namecheap.py | 1 - salt/utils/napalm.py | 3 +- salt/utils/nb_popen.py | 8 +- salt/utils/network.py | 4 +- salt/utils/nxos.py | 16 +- salt/utils/openstack/neutron.py | 2 - salt/utils/openstack/nova.py | 37 ++- salt/utils/oset.py | 12 +- salt/utils/pagerduty.py | 2 +- salt/utils/parsers.py | 1 + salt/utils/path.py | 1 - salt/utils/pbm.py | 21 +- salt/utils/pkg/rpm.py | 5 +- salt/utils/pkg/win.py | 19 +- salt/utils/platform.py | 1 + salt/utils/powershell.py | 6 +- salt/utils/process.py | 13 +- salt/utils/profile.py | 9 +- salt/utils/proxy.py | 1 - salt/utils/psutil_compat.py | 1 - salt/utils/pushover.py | 4 +- salt/utils/pycrypto.py | 5 +- salt/utils/pydsl.py | 12 +- salt/utils/pyobjects.py | 6 +- salt/utils/reactor.py | 1 + salt/utils/roster_matcher.py | 2 +- salt/utils/s3.py | 22 +- salt/utils/saltclass.py | 8 +- salt/utils/schedule.py | 39 ++- salt/utils/schema.py | 18 +- salt/utils/slack.py | 2 +- salt/utils/smb.py | 9 +- salt/utils/smtp.py | 8 +- salt/utils/ssdp.py | 8 +- salt/utils/ssh.py | 2 +- salt/utils/state.py | 1 - salt/utils/stringio.py | 1 - salt/utils/stringutils.py | 15 +- salt/utils/templates.py | 1 + salt/utils/textformat.py | 3 +- salt/utils/thin.py | 18 +- salt/utils/timed_subprocess.py | 2 +- salt/utils/url.py | 11 +- salt/utils/user.py | 1 - salt/utils/validate/net.py | 2 +- salt/utils/vault/cache.py | 8 +- salt/utils/vault/helpers.py | 2 +- salt/utils/versions.py | 1 + salt/utils/virt.py | 2 +- salt/utils/virtualbox.py | 4 +- salt/utils/vmware.py | 148 +++++----- salt/utils/vsan.py | 23 +- salt/utils/vt.py | 16 +- salt/utils/vt_helper.py | 2 +- salt/utils/win_chcp.py | 8 +- salt/utils/win_dotnet.py | 4 +- salt/utils/win_functions.py | 6 +- salt/utils/win_lgpo_auditpol.py | 18 +- salt/utils/win_lgpo_netsh.py | 56 ++-- salt/utils/win_lgpo_reg.py | 1 + salt/utils/win_network.py | 1 + salt/utils/win_osinfo.py | 1 + salt/utils/win_pdh.py | 2 +- salt/utils/win_service.py | 8 +- salt/utils/win_system.py | 1 + salt/utils/win_update.py | 15 +- salt/utils/x509.py | 86 +++--- salt/utils/xmlutil.py | 8 +- salt/utils/yaml.py | 1 + salt/utils/yamldumper.py | 1 + salt/utils/yamlencoding.py | 1 - salt/utils/yamlloader.py | 7 +- salt/utils/yamlloader_old.py | 7 +- salt/utils/zfs.py | 1 - salt/version.py | 2 +- salt/wheel/config.py | 2 +- salt/wheel/file_roots.py | 1 - salt/wheel/key.py | 1 - salt/wheel/minions.py | 1 - salt/wheel/pillar_roots.py | 4 +- scripts/suse/yum/plugins/yumnotify.py | 4 +- tests/buildpackage.py | 28 +- tests/committer_parser.py | 10 +- tests/conftest.py | 4 +- tests/eventlisten.py | 3 +- .../cloud/clouds/test_digitalocean.py | 1 + .../cloud/clouds/test_dimensiondata.py | 9 +- tests/integration/cloud/clouds/test_ec2.py | 7 +- tests/integration/cloud/clouds/test_gce.py | 7 +- tests/integration/cloud/clouds/test_gogrid.py | 2 +- .../cloud/clouds/test_oneandone.py | 5 +- .../cloud/clouds/test_openstack.py | 2 +- .../cloud/clouds/test_profitbricks.py | 17 +- .../cloud/clouds/test_tencentcloud.py | 12 +- .../cloud/clouds/test_virtualbox.py | 10 +- tests/integration/cloud/clouds/test_vmware.py | 10 +- .../integration/cloud/clouds/test_vultrpy.py | 8 +- .../cloud/helpers/cloud_test_base.py | 5 +- tests/integration/cloud/helpers/virtualbox.py | 10 +- tests/integration/cloud/test_cloud.py | 3 +- tests/integration/conftest.py | 1 + .../pillar/ext_pillar_opts.py | 1 - .../file/base/_modules/runtests_decorators.py | 4 +- .../file/base/_modules/runtests_helpers.py | 1 - .../file/base/buildout/var/tb/2/bootstrap.py | 1 + .../files/returners/noop_returner.py | 1 - tests/integration/grains/test_core.py | 1 + tests/integration/grains/test_custom.py | 1 - tests/integration/loader/test_ext_grains.py | 1 - tests/integration/minion/test_timeout.py | 7 +- tests/integration/modules/test_boto_iam.py | 1 + tests/integration/modules/test_boto_sns.py | 3 +- tests/integration/modules/test_cmdmod.py | 12 +- tests/integration/modules/test_git.py | 32 +-- tests/integration/modules/test_groupadd.py | 2 +- .../integration/modules/test_linux_shadow.py | 2 +- tests/integration/modules/test_lxc.py | 4 +- tests/integration/modules/test_macdefaults.py | 1 + tests/integration/modules/test_mine.py | 16 +- tests/integration/modules/test_mysql.py | 14 +- tests/integration/modules/test_test.py | 5 +- tests/integration/modules/test_timezone.py | 1 + tests/integration/pillar/test_git_pillar.py | 6 +- .../runners/test_runner_returns.py | 2 +- tests/integration/shell/test_master_tops.py | 1 - tests/integration/shell/test_spm.py | 10 +- tests/integration/spm/test_install.py | 1 + tests/integration/states/test_boto_sns.py | 17 +- tests/integration/states/test_compiler.py | 1 - tests/integration/states/test_git.py | 34 ++- .../integration/states/test_handle_iorder.py | 1 - tests/integration/states/test_host.py | 2 +- tests/integration/states/test_lxd_image.py | 1 + tests/integration/states/test_lxd_profile.py | 1 + tests/integration/states/test_reg.py | 28 +- .../states/test_ssh_known_hosts.py | 10 +- tests/integration/states/test_x509.py | 20 +- tests/integration/utils/test_idem.py | 1 + tests/integration/utils/test_smb.py | 1 + tests/integration/utils/test_win_runas.py | 26 +- tests/minionswarm.py | 10 +- tests/modparser.py | 2 +- tests/packdump.py | 1 + tests/pytests/conftest.py | 2 + tests/pytests/functional/cache/helpers.py | 2 +- tests/pytests/functional/cli/test_batch.py | 1 + .../pytests/functional/cli/test_salt_cloud.py | 1 + .../functional/formulas/test_docker.py | 1 + .../pytests/functional/formulas/test_nginx.py | 1 + .../functional/formulas/test_sudoers.py | 1 + tests/pytests/functional/formulas/test_vim.py | 1 + .../loader/test_loaded_base_name.py | 2 +- .../log_handlers/test_logstash_mod.py | 4 +- .../functional/modules/cmd/test_powershell.py | 4 +- .../functional/modules/cmd/test_runas.py | 4 +- .../functional/modules/file/test_replace.py | 5 +- .../functional/modules/file/test_rmdir.py | 14 +- .../functional/modules/file/test_symlink.py | 2 +- .../modules/state/test_jinja_filters.py | 1 + .../functional/modules/test_archive.py | 9 +- .../functional/modules/test_dockermod.py | 1 + .../functional/modules/test_etcd_mod.py | 27 +- .../functional/modules/test_mac_pkgutil.py | 1 + .../pytests/functional/modules/test_mysql.py | 1 + .../functional/modules/test_network.py | 5 +- tests/pytests/functional/modules/test_opkg.py | 2 +- .../pytests/functional/modules/test_system.py | 4 +- .../functional/modules/test_win_dsc.py | 4 +- .../functional/modules/test_win_shortcut.py | 9 +- .../modules/win_file/test_check_perms.py | 1 + .../modules/win_file/test_remove.py | 1 + .../functional/modules/win_file/test_stat.py | 1 + .../win_lgpo/test_audit_settings_module.py | 2 +- .../netapi/rest_cherrypy/test_auth.py | 2 +- .../test_external_auth_syntax.py | 20 +- .../netapi/rest_tornado/test_auth_handler.py | 6 +- .../rest_tornado/test_auth_handler_pam.py | 6 +- .../rest_tornado/test_base_api_handler.py | 4 +- .../rest_tornado/test_external_auth_syntax.py | 20 +- tests/pytests/functional/pillar/test_gpg.py | 6 +- tests/pytests/functional/sdb/test_etcd_db.py | 9 +- .../functional/states/cmd/test_runas.py | 4 +- .../functional/states/file/test_append.py | 2 +- .../states/file/test_blockreplace.py | 4 +- .../functional/states/file/test_cached.py | 8 +- .../functional/states/file/test_comment.py | 1 + .../functional/states/file/test_managed.py | 1 - .../functional/states/file/test_patch.py | 4 +- .../functional/states/file/test_pruned.py | 16 +- .../functional/states/file/test_recurse.py | 8 +- .../functional/states/file/test_rename.py | 1 + .../functional/states/file/test_replace.py | 18 +- .../functional/states/file/test_symlink.py | 2 +- .../functional/states/rabbitmq/conftest.py | 6 +- .../states/test_chocolatey_1_2_1.py | 1 + .../states/test_chocolatey_latest.py | 1 + .../functional/states/test_docker_network.py | 17 +- .../functional/states/test_etcd_mod.py | 40 ++- tests/pytests/functional/states/test_mysql.py | 1 + tests/pytests/functional/states/test_svn.py | 3 +- .../functional/states/test_win_certutil.py | 1 + .../pytests/functional/states/test_x509_v2.py | 6 +- .../functional/states/test_zookeeper.py | 4 +- .../win_lgpo/test_audit_settings_state.py | 2 +- .../functional/transport/ipc/test_client.py | 2 +- .../transport/server/test_request_server.py | 6 +- .../transport/tcp/test_pub_server.py | 1 - .../functools/test_namespaced_function.py | 2 +- .../functional/utils/test_etcd_util.py | 261 ++++++++---------- tests/pytests/functional/utils/test_jinja.py | 4 +- .../pytests/functional/utils/test_process.py | 1 + .../utils/win_dacl/test_get_name.py | 1 + .../functional/utils/win_dacl/test_get_sid.py | 1 + .../utils/win_dacl/test_get_sid_string.py | 1 + .../test_multiple_processes_logging.py | 2 +- tests/pytests/integration/cli/test_batch.py | 6 +- tests/pytests/integration/cli/test_salt.py | 1 + tests/pytests/integration/cli/test_salt_cp.py | 1 - .../integration/cli/test_salt_deltaproxy.py | 23 +- .../integration/cluster/test_basic_cluster.py | 1 + .../pytests/integration/grains/test_grains.py | 1 + .../integration/master/test_payload.py | 1 + .../integration/minion/test_return_retries.py | 4 +- .../integration/modules/grains/test_module.py | 1 - .../modules/saltutil/test_modules.py | 1 - .../modules/saltutil/test_pillar.py | 1 - .../modules/saltutil/test_wheel.py | 1 - .../modules/state/test_state_test.py | 4 +- .../integration/modules/test_beacons.py | 1 + .../pytests/integration/modules/test_event.py | 1 + .../pytests/integration/modules/test_file.py | 3 +- .../pytests/integration/modules/test_idem.py | 1 + .../modules/test_rpmbuild_pkgbuild.py | 8 +- .../pytests/integration/modules/test_state.py | 8 +- .../integration/modules/test_useradd.py | 1 + .../pytests/integration/modules/test_virt.py | 1 + .../netapi/rest_cherrypy/test_arg_kwarg.py | 4 +- .../netapi/rest_cherrypy/test_auth.py | 2 +- .../rest_tornado/test_jobs_api_handler.py | 2 +- .../pillar/cache/test_pillar_cache.py | 1 + .../integration/pillar/test_pillar_include.py | 13 +- tests/pytests/integration/proxy/conftest.py | 16 +- .../integration/proxy/test_deltaproxy.py | 1 + tests/pytests/integration/proxy/test_shell.py | 1 + .../pytests/integration/proxy/test_simple.py | 1 + .../runners/state/orchestrate/test_events.py | 1 + .../pytests/integration/runners/test_match.py | 1 + tests/pytests/integration/sdb/test_vault.py | 1 + .../ssh/state/test_with_import_dir.py | 1 + .../integration/ssh/test_jinja_mods.py | 2 +- tests/pytests/integration/ssh/test_log.py | 1 + .../integration/ssh/test_py_versions.py | 1 + .../pytests/integration/ssh/test_ssh_setup.py | 1 + .../pytests/integration/states/test_beacon.py | 1 + tests/pytests/integration/states/test_file.py | 9 +- tests/pytests/integration/states/test_idem.py | 3 +- .../integration/states/test_include.py | 1 + .../integration/utils/test_templates.py | 5 +- .../integration/wheel/test_pillar_roots.py | 4 +- tests/pytests/pkg/conftest.py | 12 +- .../pytests/pkg/download/test_pkg_download.py | 1 + tests/pytests/scenarios/blackout/conftest.py | 2 +- .../blackout/test_minion_blackout.py | 1 - .../pytests/scenarios/cluster/test_cluster.py | 13 +- tests/pytests/scenarios/compat/conftest.py | 3 +- .../scenarios/compat/test_with_versions.py | 1 + .../failover/multimaster/conftest.py | 10 +- .../multimaster/test_failover_master.py | 18 +- .../pytests/scenarios/multimaster/conftest.py | 10 +- .../scenarios/multimaster/test_multimaster.py | 4 +- .../pytests/scenarios/performance/conftest.py | 1 + tests/pytests/scenarios/setup/test_install.py | 1 + tests/pytests/scenarios/setup/test_man.py | 2 +- tests/pytests/unit/auth/test_ldap.py | 1 + tests/pytests/unit/beacons/test_adb.py | 1 + .../unit/beacons/test_avahi_announce.py | 1 + .../unit/beacons/test_bonjour_announce.py | 1 + tests/pytests/unit/beacons/test_btmp.py | 2 +- tests/pytests/unit/beacons/test_diskusage.py | 1 + tests/pytests/unit/beacons/test_glxinfo.py | 1 + tests/pytests/unit/beacons/test_haproxy.py | 1 + tests/pytests/unit/beacons/test_load.py | 1 + tests/pytests/unit/beacons/test_log_beacon.py | 1 + tests/pytests/unit/beacons/test_memusage.py | 1 + .../pytests/unit/beacons/test_network_info.py | 1 + tests/pytests/unit/beacons/test_ps.py | 1 + tests/pytests/unit/beacons/test_swapusage.py | 1 + tests/pytests/unit/beacons/test_wtmp.py | 2 +- tests/pytests/unit/cache/test_localfs.py | 1 + tests/pytests/unit/cache/test_memcache.py | 1 + tests/pytests/unit/cache/test_mysql_cache.py | 1 - .../unit/client/ssh/wrapper/test_config.py | 1 - .../unit/client/ssh/wrapper/test_cp.py | 1 + .../unit/cloud/clouds/test_digitalocean.py | 1 - .../pytests/unit/cloud/clouds/test_hetzner.py | 12 +- .../pytests/unit/cloud/clouds/test_proxmox.py | 10 +- .../pytests/unit/cloud/clouds/test_saltify.py | 1 + .../pytests/unit/cloud/clouds/test_vultrpy.py | 12 +- tests/pytests/unit/config/schemas/test_ssh.py | 14 +- .../unit/config/test__validate_opts.py | 1 + tests/pytests/unit/crypt/test_crypt.py | 1 + tests/pytests/unit/engines/test_engines.py | 2 +- .../unit/engines/test_libvirt_events.py | 1 + tests/pytests/unit/engines/test_slack.py | 1 + .../unit/engines/test_slack_bolt_engine.py | 23 +- tests/pytests/unit/engines/test_sqs_events.py | 1 + .../unit/fileclient/test_fileclient.py | 1 + .../fileserver/gitfs/test_gitfs_config.py | 2 +- tests/pytests/unit/grains/test_core.py | 18 +- tests/pytests/unit/grains/test_esxi.py | 1 - tests/pytests/unit/loader/test_context.py | 1 + tests/pytests/unit/loader/test_lazy.py | 1 + tests/pytests/unit/loader/test_loader.py | 1 + .../unit/log_handlers/test_sentry_mod.py | 1 + .../unit/modules/dockermod/test_module.py | 30 +- .../unit/modules/file/test_file_chattr.py | 2 +- .../unit/modules/file/test_file_check.py | 4 +- .../unit/modules/file/test_file_grep.py | 4 +- .../unit/modules/file/test_file_line.py | 10 +- .../unit/modules/file/test_file_module.py | 7 +- tests/pytests/unit/modules/napalm/test_bgp.py | 1 - tests/pytests/unit/modules/napalm/test_mod.py | 1 + .../unit/modules/napalm/test_network.py | 1 - .../pytests/unit/modules/napalm/test_route.py | 2 +- .../pytests/unit/modules/napalm/test_snmp.py | 1 - .../pytests/unit/modules/napalm/test_users.py | 1 - tests/pytests/unit/modules/test_acme.py | 1 - tests/pytests/unit/modules/test_aixpkg.py | 36 ++- tests/pytests/unit/modules/test_at.py | 1 - tests/pytests/unit/modules/test_augeas_cfg.py | 1 + tests/pytests/unit/modules/test_bigip.py | 1 + .../unit/modules/test_bluez_bluetooth.py | 1 - .../unit/modules/test_boto_dynamodb.py | 1 - tests/pytests/unit/modules/test_bower.py | 1 - tests/pytests/unit/modules/test_bridge.py | 1 - .../unit/modules/test_cassandra_cql.py | 3 +- tests/pytests/unit/modules/test_chocolatey.py | 1 + tests/pytests/unit/modules/test_chroot.py | 6 +- tests/pytests/unit/modules/test_composer.py | 1 - tests/pytests/unit/modules/test_config.py | 1 - tests/pytests/unit/modules/test_consul.py | 17 +- tests/pytests/unit/modules/test_cp.py | 1 - .../pytests/unit/modules/test_daemontools.py | 1 - tests/pytests/unit/modules/test_data.py | 1 + tests/pytests/unit/modules/test_deb_apache.py | 1 - tests/pytests/unit/modules/test_devinfo.py | 11 +- tests/pytests/unit/modules/test_devmap.py | 1 - tests/pytests/unit/modules/test_dig.py | 1 - tests/pytests/unit/modules/test_disk.py | 5 +- tests/pytests/unit/modules/test_djangomod.py | 1 + .../pytests/unit/modules/test_dpkg_lowpkg.py | 1 - tests/pytests/unit/modules/test_drac.py | 1 - tests/pytests/unit/modules/test_drbd.py | 1 - tests/pytests/unit/modules/test_etcd_mod.py | 1 - tests/pytests/unit/modules/test_extfs.py | 1 - tests/pytests/unit/modules/test_genesis.py | 1 + .../unit/modules/test_gentoo_service.py | 1 - tests/pytests/unit/modules/test_git.py | 9 +- tests/pytests/unit/modules/test_glassfish.py | 1 + tests/pytests/unit/modules/test_glusterfs.py | 1 - .../pytests/unit/modules/test_grub_legacy.py | 1 - tests/pytests/unit/modules/test_hadoop.py | 1 - .../pytests/unit/modules/test_haproxyconn.py | 1 - tests/pytests/unit/modules/test_hashutil.py | 1 - tests/pytests/unit/modules/test_helm.py | 1 - tests/pytests/unit/modules/test_hg.py | 17 +- tests/pytests/unit/modules/test_http.py | 1 - tests/pytests/unit/modules/test_ilo.py | 1 - tests/pytests/unit/modules/test_incron.py | 1 - tests/pytests/unit/modules/test_ini_manage.py | 11 +- tests/pytests/unit/modules/test_introspect.py | 9 +- tests/pytests/unit/modules/test_ipset.py | 1 + tests/pytests/unit/modules/test_iptables.py | 4 +- tests/pytests/unit/modules/test_junos.py | 1 + tests/pytests/unit/modules/test_key.py | 1 - tests/pytests/unit/modules/test_keyboard.py | 1 - tests/pytests/unit/modules/test_kmod.py | 4 +- tests/pytests/unit/modules/test_kubeadm.py | 1 - .../unit/modules/test_launchctl_service.py | 1 - tests/pytests/unit/modules/test_ldapmod.py | 1 - tests/pytests/unit/modules/test_linux_lvm.py | 3 +- .../pytests/unit/modules/test_linux_shadow.py | 1 + tests/pytests/unit/modules/test_locate.py | 1 - tests/pytests/unit/modules/test_logadm.py | 1 - tests/pytests/unit/modules/test_logrotate.py | 1 - tests/pytests/unit/modules/test_lvs.py | 1 - .../unit/modules/test_mac_assistive.py | 2 +- .../pytests/unit/modules/test_mac_brew_pkg.py | 1 + .../pytests/unit/modules/test_mac_service.py | 1 - tests/pytests/unit/modules/test_mac_shadow.py | 1 + tests/pytests/unit/modules/test_mandrill.py | 1 - tests/pytests/unit/modules/test_match.py | 3 +- tests/pytests/unit/modules/test_mdadm_raid.py | 1 + tests/pytests/unit/modules/test_mine.py | 3 +- tests/pytests/unit/modules/test_mongodb.py | 56 +++- tests/pytests/unit/modules/test_monit.py | 1 - tests/pytests/unit/modules/test_mysql.py | 3 +- tests/pytests/unit/modules/test_nacl.py | 1 + tests/pytests/unit/modules/test_nfs3.py | 1 - tests/pytests/unit/modules/test_nftables.py | 1 + tests/pytests/unit/modules/test_npm.py | 1 - tests/pytests/unit/modules/test_openbsdpkg.py | 1 - .../unit/modules/test_openbsdrcctl_service.py | 24 +- tests/pytests/unit/modules/test_oracle.py | 1 - tests/pytests/unit/modules/test_osquery.py | 1 - tests/pytests/unit/modules/test_pacmanpkg.py | 5 +- tests/pytests/unit/modules/test_pagerduty.py | 1 - tests/pytests/unit/modules/test_pam.py | 1 + tests/pytests/unit/modules/test_parallels.py | 5 +- tests/pytests/unit/modules/test_pecl.py | 1 - tests/pytests/unit/modules/test_pkgutil.py | 1 - .../unit/modules/test_portage_config.py | 3 +- tests/pytests/unit/modules/test_postfix.py | 1 - tests/pytests/unit/modules/test_poudriere.py | 6 +- tests/pytests/unit/modules/test_ps.py | 8 +- tests/pytests/unit/modules/test_publish.py | 1 - tests/pytests/unit/modules/test_pw_user.py | 1 - tests/pytests/unit/modules/test_qemu_img.py | 1 - tests/pytests/unit/modules/test_rabbitmq.py | 1 - tests/pytests/unit/modules/test_rbenv.py | 1 - tests/pytests/unit/modules/test_rdp.py | 1 - tests/pytests/unit/modules/test_reg.py | 6 +- .../pytests/unit/modules/test_restartcheck.py | 24 +- tests/pytests/unit/modules/test_ret.py | 1 - tests/pytests/unit/modules/test_rh_service.py | 1 - tests/pytests/unit/modules/test_rvm.py | 1 - tests/pytests/unit/modules/test_s6.py | 1 - .../pytests/unit/modules/test_saltcloudmod.py | 1 - tests/pytests/unit/modules/test_schedule.py | 118 ++++++-- tests/pytests/unit/modules/test_sdb.py | 1 + .../unit/modules/test_serverdensity_device.py | 1 - tests/pytests/unit/modules/test_servicenow.py | 1 - .../unit/modules/test_slackware_service.py | 1 + .../unit/modules/test_smartos_imgadm.py | 1 - tests/pytests/unit/modules/test_smtp.py | 1 - tests/pytests/unit/modules/test_status.py | 3 +- tests/pytests/unit/modules/test_suse_ip.py | 12 +- tests/pytests/unit/modules/test_swift.py | 1 - tests/pytests/unit/modules/test_syslog_ng.py | 1 - tests/pytests/unit/modules/test_system.py | 1 + tests/pytests/unit/modules/test_telegram.py | 1 - tests/pytests/unit/modules/test_tls.py | 16 +- tests/pytests/unit/modules/test_tomcat.py | 1 - .../unit/modules/test_transactional_update.py | 8 +- tests/pytests/unit/modules/test_tuned.py | 1 - tests/pytests/unit/modules/test_udev.py | 1 - tests/pytests/unit/modules/test_uptime.py | 1 - tests/pytests/unit/modules/test_uwsgi.py | 1 - tests/pytests/unit/modules/test_vagrant.py | 1 - tests/pytests/unit/modules/test_vmctl.py | 1 - tests/pytests/unit/modules/test_webutil.py | 1 - .../pytests/unit/modules/test_win_autoruns.py | 1 - .../unit/modules/test_win_dns_client.py | 1 - tests/pytests/unit/modules/test_win_iis.py | 3 +- .../pytests/unit/modules/test_win_licence.py | 1 - tests/pytests/unit/modules/test_win_path.py | 1 - tests/pytests/unit/modules/test_win_pkg.py | 1 + tests/pytests/unit/modules/test_win_pki.py | 1 - .../pytests/unit/modules/test_win_powercfg.py | 1 - tests/pytests/unit/modules/test_win_psget.py | 1 - tests/pytests/unit/modules/test_win_shadow.py | 1 - tests/pytests/unit/modules/test_win_snmp.py | 1 - tests/pytests/unit/modules/test_win_system.py | 1 + tests/pytests/unit/modules/test_win_task.py | 1 + .../pytests/unit/modules/test_win_timezone.py | 1 + tests/pytests/unit/modules/test_win_wua.py | 1 + tests/pytests/unit/modules/test_xapi_virt.py | 1 - tests/pytests/unit/modules/test_xfs.py | 1 - tests/pytests/unit/modules/test_xml.py | 1 - tests/pytests/unit/modules/test_yumpkg.py | 6 +- tests/pytests/unit/modules/test_zenoss.py | 1 - tests/pytests/unit/modules/test_zfs.py | 6 +- tests/pytests/unit/modules/test_znc.py | 1 - tests/pytests/unit/modules/test_zpool.py | 6 +- tests/pytests/unit/modules/test_zypperpkg.py | 1 - tests/pytests/unit/modules/virt/conftest.py | 8 +- .../pytests/unit/modules/virt/test_domain.py | 23 +- .../modules/win_lgpo/test_admx_policies.py | 1 + .../modules/win_lgpo/test_defined_policies.py | 1 + .../unit/modules/win_lgpo/test_mechanisms.py | 1 + .../win_lgpo/test_point_print_enabled.py | 1 + .../modules/win_lgpo/test_point_print_nc.py | 1 + .../unit/modules/win_lgpo/test_policy_info.py | 1 + .../win_lgpo/test_policy_info_functions.py | 1 + .../modules/win_lgpo/test_policy_resources.py | 1 + .../unit/modules/win_lgpo/test_reg_pol.py | 1 + .../modules/win_lgpo/test_secedit_policy.py | 2 +- tests/pytests/unit/output/test_json_out.py | 1 + tests/pytests/unit/output/test_nested.py | 1 + tests/pytests/unit/output/test_yaml_out.py | 1 + tests/pytests/unit/pillar/test_csvpillar.py | 1 - .../unit/pillar/test_http_json_pillar.py | 8 +- .../unit/pillar/test_http_yaml_pillar.py | 4 +- tests/pytests/unit/pillar/test_mysql.py | 12 +- tests/pytests/unit/pillar/test_s3.py | 6 +- tests/pytests/unit/pillar/test_saltclass.py | 2 +- .../unit/proxy/nxos/test_nxos_nxapi.py | 18 -- .../pytests/unit/proxy/nxos/test_nxos_ssh.py | 14 - .../pytests/unit/proxy/test_esxdatacenter.py | 1 + tests/pytests/unit/proxy/test_napalm.py | 1 + tests/pytests/unit/renderers/test_aws_kms.py | 1 + .../returners/test_elasticsearch_return.py | 1 + tests/pytests/unit/returners/test_pgjsonb.py | 1 - .../returners/test_slack_webhook_return.py | 13 +- .../unit/returners/test_smtp_return.py | 1 + .../unit/returners/test_syslog_return.py | 3 +- .../unit/returners/test_telegram_return.py | 1 + tests/pytests/unit/roster/test_dir.py | 5 +- tests/pytests/unit/roster/test_terraform.py | 1 + tests/pytests/unit/runners/test_bgp.py | 1 + tests/pytests/unit/runners/test_fileserver.py | 3 +- tests/pytests/unit/runners/test_git_pillar.py | 1 - tests/pytests/unit/runners/test_jobs.py | 1 + tests/pytests/unit/runners/test_network.py | 1 + tests/pytests/unit/runners/test_reactor.py | 1 - tests/pytests/unit/runners/test_saltutil.py | 4 +- tests/pytests/unit/runners/test_spacewalk.py | 1 + tests/pytests/unit/runners/test_winrepo.py | 1 - .../vault/test_token_auth_deprecated.py | 1 - tests/pytests/unit/sdb/test_yaml.py | 1 - .../unit/serializers/test_serializers.py | 2 +- tests/pytests/unit/state/test_state_basic.py | 1 + tests/pytests/unit/states/apache/test_conf.py | 12 +- .../pytests/unit/states/apache/test_module.py | 12 +- tests/pytests/unit/states/apache/test_site.py | 12 +- .../unit/states/file/test__clean_dir.py | 1 + tests/pytests/unit/states/file/test_absent.py | 16 +- .../pytests/unit/states/file/test_comment.py | 12 +- tests/pytests/unit/states/file/test_copy.py | 10 +- .../unit/states/file/test_directory.py | 14 +- .../unit/states/file/test_filestate.py | 36 +-- .../pytests/unit/states/file/test_hardlink.py | 34 +-- .../pytests/unit/states/file/test_managed.py | 14 +- .../pytests/unit/states/file/test_prepend.py | 6 +- .../states/file/test_private_functions.py | 6 +- tests/pytests/unit/states/file/test_pruned.py | 6 +- .../states/file/test_retention_schedule.py | 14 +- .../pytests/unit/states/file/test_selinux.py | 2 +- .../pytests/unit/states/file/test_symlink.py | 28 +- tests/pytests/unit/states/file/test_tidied.py | 30 +- .../unit/states/mysql/test_database.py | 15 +- tests/pytests/unit/states/mysql/test_query.py | 2 +- .../unit/states/postgresql/test_cluster.py | 20 +- .../unit/states/postgresql/test_database.py | 8 +- .../unit/states/postgresql/test_initdb.py | 8 +- .../unit/states/postgresql/test_language.py | 16 +- .../unit/states/rabbitmq/test_vhost.py | 2 +- tests/pytests/unit/states/test_alias.py | 16 +- .../pytests/unit/states/test_alternatives.py | 26 +- tests/pytests/unit/states/test_aptpkg.py | 3 +- tests/pytests/unit/states/test_archive.py | 5 +- tests/pytests/unit/states/test_at.py | 4 +- tests/pytests/unit/states/test_aws_sqs.py | 9 +- tests/pytests/unit/states/test_blockdev.py | 10 +- .../unit/states/test_boto_cloudfront.py | 7 +- .../unit/states/test_boto_cloudwatch_alarm.py | 2 +- .../pytests/unit/states/test_boto_dynamodb.py | 8 +- tests/pytests/unit/states/test_boto_ec2.py | 10 +- .../unit/states/test_boto_elasticache.py | 12 +- tests/pytests/unit/states/test_boto_elb.py | 6 +- .../pytests/unit/states/test_boto_iam_role.py | 2 +- .../pytests/unit/states/test_boto_kinesis.py | 12 +- tests/pytests/unit/states/test_boto_lc.py | 1 + .../pytests/unit/states/test_boto_route53.py | 11 +- tests/pytests/unit/states/test_boto_sns.py | 13 +- tests/pytests/unit/states/test_boto_sqs.py | 7 +- tests/pytests/unit/states/test_bower.py | 1 + tests/pytests/unit/states/test_chocolatey.py | 1 + tests/pytests/unit/states/test_cloud.py | 46 +-- tests/pytests/unit/states/test_consul.py | 1 - tests/pytests/unit/states/test_ddns.py | 6 +- tests/pytests/unit/states/test_debconfmod.py | 1 + tests/pytests/unit/states/test_drac.py | 9 +- .../pytests/unit/states/test_elasticsearch.py | 1 + tests/pytests/unit/states/test_eselect.py | 3 +- tests/pytests/unit/states/test_etcd_mod.py | 1 - tests/pytests/unit/states/test_ethtool.py | 6 +- tests/pytests/unit/states/test_firewalld.py | 1 + tests/pytests/unit/states/test_gem.py | 1 - tests/pytests/unit/states/test_git.py | 1 - .../pytests/unit/states/test_gnomedesktop.py | 1 - tests/pytests/unit/states/test_grafana.py | 2 +- tests/pytests/unit/states/test_grains.py | 1 + tests/pytests/unit/states/test_group.py | 10 +- tests/pytests/unit/states/test_helm.py | 1 - tests/pytests/unit/states/test_host.py | 57 ++-- tests/pytests/unit/states/test_incron.py | 18 +- .../unit/states/test_influxdb08_database.py | 16 +- .../unit/states/test_influxdb08_user.py | 16 +- tests/pytests/unit/states/test_ini_manage.py | 1 - tests/pytests/unit/states/test_iptables.py | 1 - tests/pytests/unit/states/test_kapacitor.py | 1 - tests/pytests/unit/states/test_kernelpkg.py | 1 - tests/pytests/unit/states/test_keyboard.py | 12 +- tests/pytests/unit/states/test_keystone.py | 52 ++-- tests/pytests/unit/states/test_kmod.py | 13 +- tests/pytests/unit/states/test_layman.py | 9 +- tests/pytests/unit/states/test_ldap.py | 65 +++-- .../pytests/unit/states/test_libcloud_dns.py | 1 - tests/pytests/unit/states/test_linux_acl.py | 12 +- tests/pytests/unit/states/test_lvm.py | 44 +-- tests/pytests/unit/states/test_lxc.py | 18 +- tests/pytests/unit/states/test_makeconf.py | 4 +- .../unit/states/test_mongodb_database.py | 6 +- .../pytests/unit/states/test_mongodb_user.py | 10 +- tests/pytests/unit/states/test_mount.py | 6 +- tests/pytests/unit/states/test_npm.py | 12 +- tests/pytests/unit/states/test_pagerduty.py | 4 +- tests/pytests/unit/states/test_pdbedit.py | 2 +- tests/pytests/unit/states/test_pecl.py | 4 +- tests/pytests/unit/states/test_pip.py | 1 + tests/pytests/unit/states/test_ports.py | 3 +- tests/pytests/unit/states/test_powerpath.py | 4 +- .../pytests/unit/states/test_pyrax_queues.py | 2 +- tests/pytests/unit/states/test_rbenv.py | 18 +- tests/pytests/unit/states/test_slack.py | 4 +- tests/pytests/unit/states/test_smartos.py | 7 +- .../pytests/unit/states/test_splunk_search.py | 8 +- tests/pytests/unit/states/test_ssh_auth.py | 2 +- .../unit/states/test_ssh_known_hosts.py | 2 +- tests/pytests/unit/states/test_supervisord.py | 2 +- tests/pytests/unit/states/test_sysctl.py | 14 +- tests/pytests/unit/states/test_sysfs.py | 13 +- .../unit/states/test_virtualenv_mod.py | 1 - tests/pytests/unit/states/test_webutil.py | 1 - tests/pytests/unit/states/test_win_lgpo.py | 1 + tests/pytests/unit/states/test_win_path.py | 28 +- tests/pytests/unit/states/test_win_wua.py | 21 +- tests/pytests/unit/states/test_win_wusa.py | 32 +-- tests/pytests/unit/states/test_xml.py | 8 +- tests/pytests/unit/states/test_xmpp.py | 1 - tests/pytests/unit/states/virt/test_domain.py | 22 +- .../pytests/unit/states/zabbix/test_action.py | 30 +- .../unit/states/zabbix/test_template.py | 22 +- .../unit/states/zabbix/test_valuemap.py | 30 +- tests/pytests/unit/test_acl.py | 1 - tests/pytests/unit/test_config.py | 1 + tests/pytests/unit/test_fileclient.py | 1 + tests/pytests/unit/test_log.py | 9 +- tests/pytests/unit/test_pillar.py | 1 - tests/pytests/unit/test_request_channel.py | 1 + tests/pytests/unit/test_syspaths.py | 1 + tests/pytests/unit/test_version.py | 1 + tests/pytests/unit/tokens/test_localfs.py | 2 +- tests/pytests/unit/transport/test_base.py | 1 + tests/pytests/unit/utils/jinja/conftest.py | 1 + tests/pytests/unit/utils/jinja/test_jinja.py | 1 + .../pytests/unit/utils/scheduler/conftest.py | 1 - .../unit/utils/templates/test_jinja.py | 1 + .../utils/templates/test_wrap_tmpl_func.py | 1 + tests/pytests/unit/utils/test_aws.py | 1 + tests/pytests/unit/utils/test_cache.py | 6 +- tests/pytests/unit/utils/test_cloud.py | 1 - tests/pytests/unit/utils/test_compat.py | 1 + tests/pytests/unit/utils/test_crypt.py | 1 + tests/pytests/unit/utils/test_data.py | 1 + tests/pytests/unit/utils/test_files.py | 3 +- tests/pytests/unit/utils/test_nacl.py | 1 + tests/pytests/unit/utils/test_pycrypto.py | 8 +- tests/pytests/unit/utils/test_rsax931.py | 1 + tests/pytests/unit/utils/test_versions.py | 8 +- tests/pytests/unit/utils/test_win_reg.py | 12 +- tests/pytests/unit/utils/test_x509.py | 8 +- tests/pytests/unit/utils/vault/conftest.py | 11 +- .../pytests/unit/utils/vault/test_factory.py | 10 +- .../unit/utils/verify/test_clean_path_link.py | 1 + .../pytests/unit/utils/verify/test_verify.py | 16 +- .../unit/utils/win_lgpo/test_auditpol.py | 2 +- tests/support/case.py | 22 +- tests/support/cli_scripts.py | 1 - tests/support/helpers.py | 1 + tests/support/kernelpkg.py | 1 + tests/support/mixins.py | 28 +- tests/support/mock.py | 1 + tests/support/napalm.py | 1 - tests/support/netapi.py | 6 +- tests/support/pytest/etcd.py | 2 +- tests/support/pytest/helpers.py | 1 + tests/support/pytest/loader.py | 9 +- tests/support/runtests.py | 16 +- tests/support/sminion.py | 2 +- tests/support/unit.py | 3 +- tests/support/win_installer.py | 6 +- tests/support/xmlunit.py | 1 + tests/support/zfs.py | 1 - tests/unit/ext/test_ipaddress.py | 10 +- tests/unit/modules/nxos/nxos_n36k.py | 1 - tests/unit/modules/nxos/nxos_n3k.py | 1 - tests/unit/modules/nxos/nxos_n5k.py | 1 - tests/unit/modules/nxos/nxos_n7k.py | 1 - tests/unit/modules/nxos/nxos_n93k.py | 1 - tests/unit/modules/nxos/nxos_n93klxc.py | 1 - tests/unit/modules/nxos/nxos_n95k.py | 1 - tests/unit/modules/nxos/nxos_platform.py | 4 - .../unit/modules/test_boto3_elasticsearch.py | 1 + tests/unit/modules/test_boto3_route53.py | 1 + tests/unit/modules/test_boto_route53.py | 2 +- tests/unit/modules/test_boto_secgroup.py | 2 +- tests/unit/modules/test_boto_vpc.py | 14 +- tests/unit/modules/test_bsd_shadow.py | 1 + tests/unit/modules/test_cron.py | 10 +- tests/unit/modules/test_freezer.py | 1 - tests/unit/modules/test_influxdb08mod.py | 1 - tests/unit/modules/test_k8s.py | 56 ++-- .../unit/modules/test_kernelpkg_linux_apt.py | 6 +- .../unit/modules/test_kernelpkg_linux_yum.py | 3 +- tests/unit/modules/test_kubernetesmod.py | 1 + tests/unit/modules/test_libcloud_compute.py | 1 + tests/unit/modules/test_libcloud_dns.py | 1 + .../modules/test_libcloud_loadbalancer.py | 1 + tests/unit/modules/test_libcloud_storage.py | 1 + tests/unit/modules/test_linux_acl.py | 2 +- tests/unit/modules/test_localemod.py | 5 +- tests/unit/modules/test_memcached.py | 1 - tests/unit/modules/test_napalm_probes.py | 3 +- tests/unit/modules/test_napalm_yang_mod.py | 1 - tests/unit/modules/test_netbox.py | 1 + tests/unit/modules/test_netscaler.py | 1 - tests/unit/modules/test_neutron.py | 1 - tests/unit/modules/test_nova.py | 1 - tests/unit/modules/test_nxos.py | 60 ---- tests/unit/modules/test_nxos_upgrade.py | 23 -- tests/unit/modules/test_openstack_config.py | 1 - tests/unit/modules/test_opkg.py | 6 +- tests/unit/modules/test_parted_partition.py | 1 - tests/unit/modules/test_rh_ip.py | 16 +- tests/unit/modules/test_snapper.py | 1 + tests/unit/modules/test_sqlite3.py | 1 - tests/unit/modules/test_ssh.py | 16 +- tests/unit/modules/test_supervisord.py | 1 - tests/unit/modules/test_sysmod.py | 7 +- tests/unit/modules/test_twilio_notify.py | 1 + tests/unit/modules/test_useradd.py | 1 + tests/unit/modules/test_virt.py | 40 +-- tests/unit/modules/test_virtualenv_mod.py | 2 +- tests/unit/modules/test_vsphere.py | 7 +- tests/unit/modules/test_win_system.py | 1 + tests/unit/modules/test_zypperpkg.py | 1 - tests/unit/states/test_boto_vpc.py | 16 +- tests/unit/states/test_group.py | 1 - tests/unit/states/test_ipset.py | 14 +- tests/unit/states/test_module.py | 1 - tests/unit/states/test_syslog_ng.py | 1 - tests/unit/test_config.py | 67 ++--- tests/unit/test_mock.py | 6 +- tests/unit/test_zypp_plugins.py | 3 +- tests/unit/transport/test_ipc.py | 1 + tests/unit/transport/test_tcp.py | 8 +- tests/unit/utils/test_color.py | 1 - tests/unit/utils/test_context.py | 1 - tests/unit/utils/test_decorators.py | 1 - tests/unit/utils/test_dns.py | 8 +- tests/unit/utils/test_doc.py | 1 - tests/unit/utils/test_dockermod.py | 16 +- tests/unit/utils/test_environment.py | 1 + tests/unit/utils/test_extend.py | 1 + tests/unit/utils/test_filebuffer.py | 1 - tests/unit/utils/test_immutabletypes.py | 1 - tests/unit/utils/test_jid.py | 5 +- tests/unit/utils/test_job.py | 1 - tests/unit/utils/test_json.py | 2 +- tests/unit/utils/test_mac_utils.py | 1 + tests/unit/utils/test_msgpack.py | 1 + tests/unit/utils/test_pbm.py | 2 +- tests/unit/utils/test_proxy.py | 1 - tests/unit/utils/test_roster_matcher.py | 1 + tests/unit/utils/test_schema.py | 90 +++--- tests/unit/utils/test_sdb.py | 1 - tests/unit/utils/test_ssdp.py | 25 +- tests/unit/utils/test_state.py | 13 +- tests/unit/utils/test_systemd.py | 8 +- tests/unit/utils/test_thin.py | 24 +- tests/unit/utils/test_vmware.py | 30 +- tests/unit/utils/test_vsan.py | 1 + tests/unit/utils/test_vt.py | 6 +- tests/unit/utils/test_win_chcp.py | 1 + tests/unit/utils/test_win_service.py | 4 +- tests/unit/utils/test_win_system.py | 4 +- tests/unit/utils/test_xmlutil.py | 1 + tests/unit/utils/test_yamlencoding.py | 1 - tests/unit/utils/test_zeromq.py | 1 + tests/unit/utils/test_zfs.py | 1 - tools/changelog.py | 1 + tools/ci.py | 1 + tools/docs.py | 1 + tools/pkg/__init__.py | 3 +- tools/pkg/build.py | 5 +- tools/pkg/repo/__init__.py | 1 + tools/pkg/repo/create.py | 1 + tools/pkg/repo/publish.py | 1 + tools/precommit/__init__.py | 1 + tools/precommit/changelog.py | 1 + tools/precommit/docs.py | 1 + tools/precommit/docstrings.py | 1 + tools/precommit/filemap.py | 1 + tools/precommit/workflows.py | 1 + tools/release.py | 1 + tools/testsuite/__init__.py | 1 + tools/testsuite/download.py | 1 + tools/vm.py | 1 + 1867 files changed, 10506 insertions(+), 11419 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4f05fb991c6..4eb7e3af7d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ exclude: ^(doc/_static/.*|doc/_themes/.*)$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-merge-conflict # Check for files that contain merge conflict strings. - id: trailing-whitespace # Trims trailing whitespace. @@ -1397,7 +1397,7 @@ repos: # ----- Code Formatting -------------------------------------------------------------------------------------------> - repo: https://github.com/asottile/pyupgrade - rev: v2.37.2 + rev: v3.15.1 hooks: - id: pyupgrade name: Upgrade code for Py3.8+ @@ -1437,7 +1437,7 @@ repos: args: [--silent, -E, fix_asserts, -E, fix_docstrings, -E, fix_tornado_imports] - repo: https://github.com/timothycrosley/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort additional_dependencies: ['toml'] @@ -1450,31 +1450,32 @@ repos: )$ - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 24.2.0 hooks: - id: black # This tells pre-commit not to pass files to black. # This should be kept in sync with pyproject.toml exclude: > (?x)^( + salt/client/ssh/ssh_py_shim\.py| templates/.*| salt/ext/.*| )$ - repo: https://github.com/asottile/blacken-docs - rev: v1.12.1 + rev: 1.16.0 hooks: - id: blacken-docs args: [--skip-errors] files: ^doc/.*\.rst additional_dependencies: - - black==22.6.0 + - black==24.2.0 # <---- Code Formatting -------------------------------------------------------------------------------------------- # ----- Security --------------------------------------------------------------------------------------------------> - repo: https://github.com/PyCQA/bandit - rev: "1.7.4" + rev: "1.7.7" hooks: - id: bandit alias: bandit-salt @@ -1488,7 +1489,7 @@ repos: )$ additional_dependencies: ['importlib_metadata<5'] - repo: https://github.com/PyCQA/bandit - rev: "1.7.4" + rev: "1.7.7" hooks: - id: bandit alias: bandit-tests @@ -1501,7 +1502,7 @@ repos: # ----- Pre-Commit ------------------------------------------------------------------------------------------------> - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.3.0 + rev: v1.8.0 hooks: - id: mypy alias: mypy-tools @@ -1518,15 +1519,15 @@ repos: - types-attrs - types-pyyaml - types-requests - - python-tools-scripts>=0.18.6 + - python-tools-scripts==0.18.6 - repo: https://github.com/saltstack/mirrors-nox - rev: v2021.6.12 + rev: v2022.11.21 hooks: - id: nox alias: lint-salt name: Lint Salt - files: ^((setup|noxfile)|(salt|tasks|tools)/.*)\.py$ + files: ^((setup|noxfile)|(salt|tools)/.*)\.py$ exclude: > (?x)^( templates/.*| @@ -1541,7 +1542,7 @@ repos: - pip>=20.2.4,<21.2 - repo: https://github.com/saltstack/mirrors-nox - rev: v2021.6.12 + rev: v2022.11.21 hooks: - id: nox alias: lint-tests diff --git a/doc/_ext/saltdomain.py b/doc/_ext/saltdomain.py index 9810ae4c31a..03ad25cb93c 100644 --- a/doc/_ext/saltdomain.py +++ b/doc/_ext/saltdomain.py @@ -53,7 +53,7 @@ class LiterateCoding(Directive): comment; False designates code. """ comment_char = "#" # TODO: move this into a directive option - comment = re.compile(r"^\s*{}[ \n]".format(comment_char)) + comment = re.compile(rf"^\s*{comment_char}[ \n]") section_test = lambda val: bool(comment.match(val)) sections = [] @@ -136,7 +136,7 @@ class LiterateFormula(LiterateCoding): formulas_dirs = config.formulas_dirs fpath = sls_path.replace(".", "/") - name_options = ("{}.sls".format(fpath), os.path.join(fpath, "init.sls")) + name_options = (f"{fpath}.sls", os.path.join(fpath, "init.sls")) paths = [ os.path.join(fdir, fname) @@ -151,7 +151,7 @@ class LiterateFormula(LiterateCoding): except OSError: pass - raise OSError("Could not find sls file '{}'".format(sls_path)) + raise OSError(f"Could not find sls file '{sls_path}'") class CurrentFormula(Directive): @@ -196,7 +196,7 @@ class Formula(Directive): targetnode = nodes.target("", "", ids=["module-" + formname], ismod=True) self.state.document.note_explicit_target(targetnode) - indextext = "{}-formula)".format(formname) + indextext = f"{formname}-formula)" inode = addnodes.index( entries=[("single", indextext, "module-" + formname, "")] ) @@ -221,9 +221,9 @@ class State(Directive): formula = env.temp_data.get("salt:formula") - indextext = "{1} ({0}-formula)".format(formula, statename) + indextext = f"{statename} ({formula}-formula)" inode = addnodes.index( - entries=[("single", indextext, "module-{}".format(statename), "")] + entries=[("single", indextext, f"module-{statename}", "")] ) return [targetnode, inode] diff --git a/doc/ref/executors/index.rst b/doc/ref/executors/index.rst index 97379fdba3a..44df3a12918 100644 --- a/doc/ref/executors/index.rst +++ b/doc/ref/executors/index.rst @@ -59,8 +59,7 @@ the ``execute`` function with the following signature: .. code-block:: python - def execute(opts, data, func, args, kwargs): - ... + def execute(opts, data, func, args, kwargs): ... Where the args are: diff --git a/doc/ref/modules/index.rst b/doc/ref/modules/index.rst index ca9171383c5..3231368c036 100644 --- a/doc/ref/modules/index.rst +++ b/doc/ref/modules/index.rst @@ -329,6 +329,7 @@ the case when the dependency is unavailable. """ Cheese execution (or returner/beacon/etc.) module """ + try: import enzymes diff --git a/doc/topics/development/tests/index.rst b/doc/topics/development/tests/index.rst index 55e8bb18f2a..a789bab089d 100644 --- a/doc/topics/development/tests/index.rst +++ b/doc/topics/development/tests/index.rst @@ -364,8 +364,7 @@ the actual testing, such as functions containing assertions, must start with .. code-block:: python - def test_user_present(self): - ... + def test_user_present(self): ... When functions in test files are not prepended with ``test_``, the function acts as a normal, helper function and is not run as a test by the test suite. diff --git a/doc/topics/proxyminion/index.rst b/doc/topics/proxyminion/index.rst index cb4aec151a2..2d18e3607cf 100644 --- a/doc/topics/proxyminion/index.rst +++ b/doc/topics/proxyminion/index.rst @@ -581,7 +581,6 @@ and status; "package" installation, and a ping. def uptodate(name): - """ Call the REST endpoint to see if the packages on the "server" are up to date. """ @@ -592,7 +591,6 @@ and status; "package" installation, and a ping. def package_remove(name): - """ Remove a "package" on the REST server """ diff --git a/doc/topics/releases/2016.11.0.rst b/doc/topics/releases/2016.11.0.rst index 2aad664eca9..227eaa9ce93 100644 --- a/doc/topics/releases/2016.11.0.rst +++ b/doc/topics/releases/2016.11.0.rst @@ -551,15 +551,13 @@ General Deprecations .. code-block:: python - def fcn(msg="", env="base", refresh=True, saltenv="base", **kwargs): - ... + def fcn(msg="", env="base", refresh=True, saltenv="base", **kwargs): ... has been changed to .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base", **kwargs): - ... + def fcn(msg="", refresh=True, saltenv="base", **kwargs): ... - If ``env`` (or ``__env__``) is supplied as a keyword argument to a function that also accepts arbitrary keyword arguments, then a new warning informs the @@ -568,8 +566,7 @@ General Deprecations .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base", **kwargs): - ... + def fcn(msg="", refresh=True, saltenv="base", **kwargs): ... .. code-block:: python @@ -582,8 +579,7 @@ General Deprecations .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base"): - ... + def fcn(msg="", refresh=True, saltenv="base"): ... .. code-block:: python @@ -597,8 +593,7 @@ General Deprecations .. code-block:: python - def fcn(msg="", refresh=True, saltenv="base"): - ... + def fcn(msg="", refresh=True, saltenv="base"): ... .. code-block:: python diff --git a/noxfile.py b/noxfile.py index 474dcd5bb75..4fa2b1a792d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,6 +4,7 @@ noxfile Nox configuration script """ + # pylint: disable=resource-leakage,3rd-party-module-not-gated import contextlib @@ -1787,7 +1788,7 @@ class Recompress: d_targz = tempd.joinpath(targz.name) with tarfile.open(d_tar, "w|") as wfile: with tarfile.open(targz, "r:gz") as rfile: - rfile.extractall(d_src) + rfile.extractall(d_src) # nosec extracted_dir = next(pathlib.Path(d_src).iterdir()) for name in sorted(extracted_dir.rglob("*")): wfile.add( diff --git a/salt/__init__.py b/salt/__init__.py index a2b9365ab46..3d36a148f7f 100644 --- a/salt/__init__.py +++ b/salt/__init__.py @@ -12,12 +12,6 @@ import warnings if sys.platform.startswith("win"): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) -if sys.version_info < (3,): # pragma: no cover - sys.stderr.write( - "\n\nAfter the Sodium release, 3001, Salt no longer supports Python 2. Exiting.\n\n" - ) - sys.stderr.flush() - class NaclImporter: """ diff --git a/salt/_compat.py b/salt/_compat.py index 7d20691f594..2cead97d0b2 100644 --- a/salt/_compat.py +++ b/salt/_compat.py @@ -1,6 +1,7 @@ """ Salt compatibility code """ + # pylint: disable=unused-import import sys diff --git a/salt/_logging/__init__.py b/salt/_logging/__init__.py index 43bcbac3aca..ea97b6ce9a8 100644 --- a/salt/_logging/__init__.py +++ b/salt/_logging/__init__.py @@ -9,6 +9,7 @@ The ``salt._logging`` package should be imported as soon as possible since salt tweaks the python's logging system. """ + from salt._logging.impl import ( DFLT_LOG_DATEFMT, DFLT_LOG_DATEFMT_LOGFILE, diff --git a/salt/auth/django.py b/salt/auth/django.py index a5a52063eb7..d11fa438f30 100644 --- a/salt/auth/django.py +++ b/salt/auth/django.py @@ -46,7 +46,6 @@ indicated above, though the model DOES NOT have to be named 'SaltExternalAuthModel'. """ - import logging import os import sys @@ -112,7 +111,7 @@ def __django_auth_setup(): django_module_name, globals(), locals(), "SaltExternalAuthModel" ) # pylint: enable=possibly-unused-variable - DJANGO_AUTH_CLASS_str = "django_auth_module.{}".format(django_model_name) + DJANGO_AUTH_CLASS_str = f"django_auth_module.{django_model_name}" DJANGO_AUTH_CLASS = eval(DJANGO_AUTH_CLASS_str) # pylint: disable=W0123 diff --git a/salt/auth/file.py b/salt/auth/file.py index 807c9c93bba..61f73480978 100644 --- a/salt/auth/file.py +++ b/salt/auth/file.py @@ -94,7 +94,6 @@ When using ``htdigest`` the ``^realm`` must be set: """ - import logging import os diff --git a/salt/auth/keystone.py b/salt/auth/keystone.py index 5ed9f7c499f..def2e8170e5 100644 --- a/salt/auth/keystone.py +++ b/salt/auth/keystone.py @@ -4,7 +4,6 @@ Provide authentication using OpenStack Keystone :depends: - keystoneclient Python module """ - try: from keystoneclient.exceptions import AuthorizationFailure, Unauthorized from keystoneclient.v2_0 import client diff --git a/salt/auth/ldap.py b/salt/auth/ldap.py index 629bd93a3e0..a3c952ce678 100644 --- a/salt/auth/ldap.py +++ b/salt/auth/ldap.py @@ -3,6 +3,7 @@ Provide authentication using simple LDAP binds :depends: - ldap Python module """ + import itertools import logging @@ -53,15 +54,15 @@ def _config(key, mandatory=True, opts=None): """ try: if opts: - value = opts["auth.ldap.{}".format(key)] + value = opts[f"auth.ldap.{key}"] else: - value = __opts__["auth.ldap.{}".format(key)] + value = __opts__[f"auth.ldap.{key}"] except KeyError: try: - value = __defopts__["auth.ldap.{}".format(key)] + value = __defopts__[f"auth.ldap.{key}"] except KeyError: if mandatory: - msg = "missing auth.ldap.{} in master config".format(key) + msg = f"missing auth.ldap.{key} in master config" raise SaltInvocationError(msg) return False return value @@ -119,13 +120,13 @@ class _LDAPConnection: schema = "ldaps" if tls else "ldap" if self.uri == "": - self.uri = "{}://{}:{}".format(schema, self.server, self.port) + self.uri = f"{schema}://{self.server}:{self.port}" try: if no_verify: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) - self.ldap = ldap.initialize("{}".format(self.uri)) + self.ldap = ldap.initialize(f"{self.uri}") self.ldap.protocol_version = 3 # ldap.VERSION3 self.ldap.set_option(ldap.OPT_REFERRALS, 0) # Needed for AD diff --git a/salt/auth/mysql.py b/salt/auth/mysql.py index d08accb6cf4..215e7a42d2b 100644 --- a/salt/auth/mysql.py +++ b/salt/auth/mysql.py @@ -47,7 +47,6 @@ Enable MySQL authentication. :depends: - MySQL-python Python module """ - import logging log = logging.getLogger(__name__) diff --git a/salt/auth/rest.py b/salt/auth/rest.py index 42fc73da59a..d48b24797aa 100644 --- a/salt/auth/rest.py +++ b/salt/auth/rest.py @@ -22,7 +22,6 @@ structure of a user as above. """ - import logging import salt.utils.http diff --git a/salt/auth/yubico.py b/salt/auth/yubico.py index f0b37eb6c0d..7682d444194 100644 --- a/salt/auth/yubico.py +++ b/salt/auth/yubico.py @@ -36,7 +36,6 @@ the API key will be updated on all the YubiCloud servers. """ - import logging log = logging.getLogger(__name__) diff --git a/salt/beacons/adb.py b/salt/beacons/adb.py index cea98eafdae..e5ebba1771c 100644 --- a/salt/beacons/adb.py +++ b/salt/beacons/adb.py @@ -3,6 +3,7 @@ Beacon to emit adb device state changes for Android devices .. versionadded:: 2016.3.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/aix_account.py b/salt/beacons/aix_account.py index 8a9e0469bd0..07aad263846 100644 --- a/salt/beacons/aix_account.py +++ b/salt/beacons/aix_account.py @@ -5,6 +5,7 @@ Beacon to fire event when we notice a AIX user is locked due to many failed logi :depends: none """ + import logging log = logging.getLogger(__name__) diff --git a/salt/beacons/bonjour_announce.py b/salt/beacons/bonjour_announce.py index edbd135e751..c129128f849 100644 --- a/salt/beacons/bonjour_announce.py +++ b/salt/beacons/bonjour_announce.py @@ -1,6 +1,7 @@ """ Beacon to announce via Bonjour (zeroconf) """ + import atexit import logging import select diff --git a/salt/beacons/btmp.py b/salt/beacons/btmp.py index f980a3ff4e1..a5d10f997fc 100644 --- a/salt/beacons/btmp.py +++ b/salt/beacons/btmp.py @@ -130,7 +130,7 @@ except ImportError: def __virtual__(): if os.path.isfile(BTMP): return __virtualname__ - err_msg = "{} does not exist.".format(BTMP) + err_msg = f"{BTMP} does not exist." log.error("Unable to load %s beacon: %s", __virtualname__, err_msg) return False, err_msg diff --git a/salt/beacons/cert_info.py b/salt/beacons/cert_info.py index b9b59902063..298d56317bd 100644 --- a/salt/beacons/cert_info.py +++ b/salt/beacons/cert_info.py @@ -7,6 +7,7 @@ Beacon to monitor certificate expiration dates from files on the filesystem. :maturity: new :depends: OpenSSL """ + import logging from datetime import datetime diff --git a/salt/beacons/diskusage.py b/salt/beacons/diskusage.py index 5be33ff975e..da904cfa520 100644 --- a/salt/beacons/diskusage.py +++ b/salt/beacons/diskusage.py @@ -5,6 +5,7 @@ Beacon to monitor disk usage. :depends: python-psutil """ + import logging import re @@ -94,7 +95,7 @@ def beacon(config): # if our mount doesn't end with a $, insert one. mount_re = mount if not mount.endswith("$"): - mount_re = "{}$".format(mount) + mount_re = f"{mount}$" if salt.utils.platform.is_windows(): # mount_re comes in formatted with a $ at the end diff --git a/salt/beacons/glxinfo.py b/salt/beacons/glxinfo.py index 20c4d4b9b01..a4aa4013804 100644 --- a/salt/beacons/glxinfo.py +++ b/salt/beacons/glxinfo.py @@ -3,6 +3,7 @@ Beacon to emit when a display is available to a linux machine .. versionadded:: 2016.3.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/haproxy.py b/salt/beacons/haproxy.py index e19ec34abd2..a3aa13de597 100644 --- a/salt/beacons/haproxy.py +++ b/salt/beacons/haproxy.py @@ -4,6 +4,7 @@ Fire an event when over a specified threshold. .. versionadded:: 2016.11.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/inotify.py b/salt/beacons/inotify.py index 283b84fdc73..3b11322319b 100644 --- a/salt/beacons/inotify.py +++ b/salt/beacons/inotify.py @@ -68,7 +68,7 @@ def _get_notifier(config): Check the context for the notifier and construct it if not present """ beacon_name = config.get("_beacon_name", "inotify") - notifier = "{}.notifier".format(beacon_name) + notifier = f"{beacon_name}.notifier" if notifier not in __context__: __context__["inotify.queue"] = collections.deque() wm = pyinotify.WatchManager() @@ -353,7 +353,7 @@ def beacon(config): def close(config): config = salt.utils.beacons.list_to_dict(config) beacon_name = config.get("_beacon_name", "inotify") - notifier = "{}.notifier".format(beacon_name) + notifier = f"{beacon_name}.notifier" if notifier in __context__: __context__[notifier].stop() del __context__[notifier] diff --git a/salt/beacons/journald.py b/salt/beacons/journald.py index f2c46c02e7d..19618a59938 100644 --- a/salt/beacons/journald.py +++ b/salt/beacons/journald.py @@ -1,6 +1,7 @@ """ A simple beacon to watch journald for specific entries """ + import logging import salt.utils.beacons diff --git a/salt/beacons/load.py b/salt/beacons/load.py index 56bc5b0cfa0..90b76201f8e 100644 --- a/salt/beacons/load.py +++ b/salt/beacons/load.py @@ -1,6 +1,7 @@ """ Beacon to emit system load averages """ + import logging import os diff --git a/salt/beacons/log_beacon.py b/salt/beacons/log_beacon.py index 6e5621f53a7..52227cd09cb 100644 --- a/salt/beacons/log_beacon.py +++ b/salt/beacons/log_beacon.py @@ -4,6 +4,7 @@ Beacon to fire events at specific log messages. .. versionadded:: 2017.7.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/memusage.py b/salt/beacons/memusage.py index a80423a398e..029fb8efbeb 100644 --- a/salt/beacons/memusage.py +++ b/salt/beacons/memusage.py @@ -5,6 +5,7 @@ Beacon to monitor memory usage. :depends: python-psutil """ + import logging import re diff --git a/salt/beacons/napalm_beacon.py b/salt/beacons/napalm_beacon.py index 122d56edb75..e1c97415bf8 100644 --- a/salt/beacons/napalm_beacon.py +++ b/salt/beacons/napalm_beacon.py @@ -298,7 +298,7 @@ def validate(config): " dictionary".format(fun), ) if fun not in __salt__: - return False, "Execution function {} is not availabe!".format(fun) + return False, f"Execution function {fun} is not availabe!" return True, "Valid configuration for the napal beacon!" diff --git a/salt/beacons/network_info.py b/salt/beacons/network_info.py index de85c39d94e..4d5743d20fb 100644 --- a/salt/beacons/network_info.py +++ b/salt/beacons/network_info.py @@ -3,6 +3,7 @@ Beacon to monitor statistics from ethernet adapters .. versionadded:: 2015.5.0 """ + import logging import salt.utils.beacons diff --git a/salt/beacons/pkg.py b/salt/beacons/pkg.py index 2613f41a61f..2a7c5e19eec 100644 --- a/salt/beacons/pkg.py +++ b/salt/beacons/pkg.py @@ -3,6 +3,7 @@ Watch for pkgs that have upgrades, then fire an event. .. versionadded:: 2016.3.0 """ + import logging __virtualname__ = "pkg" diff --git a/salt/beacons/proxy_example.py b/salt/beacons/proxy_example.py index 1c804d05284..960e23fa709 100644 --- a/salt/beacons/proxy_example.py +++ b/salt/beacons/proxy_example.py @@ -7,6 +7,7 @@ Example beacon to use with salt-proxy proxy_example: endpoint: beacon """ + import logging import salt.utils.beacons diff --git a/salt/beacons/ps.py b/salt/beacons/ps.py index 2b56cafd87b..a5d9aa3d91c 100644 --- a/salt/beacons/ps.py +++ b/salt/beacons/ps.py @@ -1,6 +1,7 @@ """ Send events covering process status """ + import logging import salt.utils.beacons diff --git a/salt/beacons/salt_monitor.py b/salt/beacons/salt_monitor.py index 1776d0ce896..d8d580edbb3 100644 --- a/salt/beacons/salt_monitor.py +++ b/salt/beacons/salt_monitor.py @@ -24,6 +24,7 @@ See example config below. - test.ping - interval: 3600 # seconds """ + import salt.utils.beacons @@ -44,7 +45,7 @@ def validate(config): # a simple str is taking as the single function with no args / kwargs fun = config["salt_fun"] if fun not in __salt__: - return False, "{} not in __salt__".format(fun) + return False, f"{fun} not in __salt__" else: for entry in config["salt_fun"]: if isinstance(entry, dict): @@ -55,7 +56,7 @@ def validate(config): if not isinstance(args_kwargs_dict[key], list): return ( False, - "args key for fun {} must be list".format(fun), + f"args key for fun {fun} must be list", ) elif key == "kwargs": if not isinstance(args_kwargs_dict[key], list): @@ -69,19 +70,19 @@ def validate(config): if not isinstance(key_value, dict): return ( False, - "{} is not a key / value pair".format(key_value), + f"{key_value} is not a key / value pair", ) else: return ( False, - "key {} not allowed under fun {}".format(key, fun), + f"key {key} not allowed under fun {fun}", ) else: # entry must be function itself fun = entry if fun not in __salt__: - return False, "{} not in __salt__".format(fun) + return False, f"{fun} not in __salt__" return True, "valid config" diff --git a/salt/beacons/salt_proxy.py b/salt/beacons/salt_proxy.py index dea7ce42057..2ec7c47d2a5 100644 --- a/salt/beacons/salt_proxy.py +++ b/salt/beacons/salt_proxy.py @@ -4,6 +4,7 @@ .. versionadded:: 2015.8.3 """ + import logging import salt.utils.beacons @@ -22,9 +23,9 @@ def _run_proxy_processes(proxies): result = {} if not __salt__["salt_proxy.is_running"](proxy)["result"]: __salt__["salt_proxy.configure_proxy"](proxy, start=True) - result[proxy] = "Proxy {} was started".format(proxy) + result[proxy] = f"Proxy {proxy} was started" else: - msg = "Proxy {} is already running".format(proxy) + msg = f"Proxy {proxy} is already running" result[proxy] = msg log.debug(msg) ret.append(result) diff --git a/salt/beacons/sensehat.py b/salt/beacons/sensehat.py index 8f1d1393350..a6b4c912a18 100644 --- a/salt/beacons/sensehat.py +++ b/salt/beacons/sensehat.py @@ -8,6 +8,7 @@ Monitor temperature, humidity and pressure using the SenseHat of a Raspberry Pi :maturity: new :depends: sense_hat Python module """ + import logging import re @@ -72,7 +73,7 @@ def beacon(config): config = salt.utils.beacons.list_to_dict(config) for sensor in config.get("sensors", {}): - sensor_function = "sensehat.get_{}".format(sensor) + sensor_function = f"sensehat.get_{sensor}" if sensor_function not in __salt__: log.error("No sensor for meassuring %s. Skipping.", sensor) continue @@ -94,6 +95,6 @@ def beacon(config): current_value = __salt__[sensor_function]() if not sensor_min <= current_value <= sensor_max: - ret.append({"tag": "sensehat/{}".format(sensor), sensor: current_value}) + ret.append({"tag": f"sensehat/{sensor}", sensor: current_value}) return ret diff --git a/salt/beacons/service.py b/salt/beacons/service.py index b27f75273af..6f7519e8f95 100644 --- a/salt/beacons/service.py +++ b/salt/beacons/service.py @@ -1,6 +1,7 @@ """ Send events covering service status """ + import logging import os import time diff --git a/salt/beacons/sh.py b/salt/beacons/sh.py index 29c2a2a206a..57ef43bca9c 100644 --- a/salt/beacons/sh.py +++ b/salt/beacons/sh.py @@ -1,6 +1,7 @@ """ Watch the shell commands being executed actively. This beacon requires strace. """ + import logging import time @@ -72,7 +73,7 @@ def beacon(config): __context__[pkey] = {} for pid in track_pids: if pid not in __context__[pkey]: - cmd = ["strace", "-f", "-e", "execve", "-p", "{}".format(pid)] + cmd = ["strace", "-f", "-e", "execve", "-p", f"{pid}"] __context__[pkey][pid] = {} __context__[pkey][pid]["vt"] = salt.utils.vt.Terminal( cmd, diff --git a/salt/beacons/smartos_imgadm.py b/salt/beacons/smartos_imgadm.py index dcf47c7d086..665168c0e3f 100644 --- a/salt/beacons/smartos_imgadm.py +++ b/salt/beacons/smartos_imgadm.py @@ -17,6 +17,7 @@ Beacon that fires events on image import/delete. - interval: 60 - startup_import_event: True """ + import logging import salt.utils.beacons diff --git a/salt/beacons/smartos_vmadm.py b/salt/beacons/smartos_vmadm.py index 2501de96da8..7cdb8806a18 100644 --- a/salt/beacons/smartos_vmadm.py +++ b/salt/beacons/smartos_vmadm.py @@ -17,6 +17,7 @@ Beacon that fires events on vm state changes - interval: 60 - startup_create_event: True """ + import logging import salt.utils.beacons diff --git a/salt/beacons/status.py b/salt/beacons/status.py index aa5aa13b478..8c1210e7dbc 100644 --- a/salt/beacons/status.py +++ b/salt/beacons/status.py @@ -87,6 +87,7 @@ markers for specific list items: to check the minion log for errors after configuring this beacon. """ + import datetime import logging @@ -142,7 +143,7 @@ def beacon(config): for func in entry: ret[func] = {} try: - data = __salt__["status.{}".format(func)]() + data = __salt__[f"status.{func}"]() except salt.exceptions.CommandExecutionError as exc: log.debug( "Status beacon attempted to process function %s " @@ -165,8 +166,6 @@ def beacon(config): except TypeError: ret[func][item] = data[int(item)] except KeyError as exc: - ret[ - func - ] = "Status beacon is incorrectly configured: {}".format(exc) + ret[func] = f"Status beacon is incorrectly configured: {exc}" return [{"tag": ctime, "data": ret}] diff --git a/salt/beacons/swapusage.py b/salt/beacons/swapusage.py index 0cbdec07ea4..1bb9a572a3d 100644 --- a/salt/beacons/swapusage.py +++ b/salt/beacons/swapusage.py @@ -5,6 +5,7 @@ Beacon to monitor swap usage. :depends: python-psutil """ + import logging import re diff --git a/salt/beacons/telegram_bot_msg.py b/salt/beacons/telegram_bot_msg.py index e11c869947f..76e0e2a6c34 100644 --- a/salt/beacons/telegram_bot_msg.py +++ b/salt/beacons/telegram_bot_msg.py @@ -4,6 +4,7 @@ Beacon to emit Telegram messages Requires the python-telegram-bot library """ + import logging import salt.utils.beacons diff --git a/salt/beacons/twilio_txt_msg.py b/salt/beacons/twilio_txt_msg.py index 6aed64531dd..1f2bc64f398 100644 --- a/salt/beacons/twilio_txt_msg.py +++ b/salt/beacons/twilio_txt_msg.py @@ -1,6 +1,7 @@ """ Beacon to emit Twilio text messages """ + import logging import salt.utils.beacons diff --git a/salt/beacons/wtmp.py b/salt/beacons/wtmp.py index c8ac6cfc379..a9f1b09281a 100644 --- a/salt/beacons/wtmp.py +++ b/salt/beacons/wtmp.py @@ -159,7 +159,7 @@ except ImportError: def __virtual__(): if os.path.isfile(WTMP): return __virtualname__ - err_msg = "{} does not exist.".format(WTMP) + err_msg = f"{WTMP} does not exist." log.error("Unable to load %s beacon: %s", __virtualname__, err_msg) return False, err_msg diff --git a/salt/cache/__init__.py b/salt/cache/__init__.py index 2b13a364235..fb2ecdc62f1 100644 --- a/salt/cache/__init__.py +++ b/salt/cache/__init__.py @@ -4,7 +4,6 @@ Loader mechanism for caching data, with data expiration, etc. .. versionadded:: 2016.11.0 """ - import logging import time @@ -70,7 +69,7 @@ class Cache: def __lazy_init(self): self._modules = salt.loader.cache(self.opts) - fun = "{}.init_kwargs".format(self.driver) + fun = f"{self.driver}.init_kwargs" if fun in self.modules: self._kwargs = self.modules[fun](self._kwargs) else: @@ -141,7 +140,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.store".format(self.driver) + fun = f"{self.driver}.store" return self.modules[fun](bank, key, data, **self._kwargs) def fetch(self, bank, key): @@ -165,7 +164,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.fetch".format(self.driver) + fun = f"{self.driver}.fetch" return self.modules[fun](bank, key, **self._kwargs) def updated(self, bank, key): @@ -189,7 +188,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.updated".format(self.driver) + fun = f"{self.driver}.updated" return self.modules[fun](bank, key, **self._kwargs) def flush(self, bank, key=None): @@ -210,7 +209,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.flush".format(self.driver) + fun = f"{self.driver}.flush" return self.modules[fun](bank, key=key, **self._kwargs) def list(self, bank): @@ -229,7 +228,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.list".format(self.driver) + fun = f"{self.driver}.list" return self.modules[fun](bank, **self._kwargs) def contains(self, bank, key=None): @@ -254,7 +253,7 @@ class Cache: Raises an exception if cache driver detected an error accessing data in the cache backend (auth, permissions, etc). """ - fun = "{}.contains".format(self.driver) + fun = f"{self.driver}.contains" return self.modules[fun](bank, key, **self._kwargs) @@ -289,7 +288,7 @@ class MemCache(Cache): break def _get_storage_id(self): - fun = "{}.storage_id".format(self.driver) + fun = f"{self.driver}.storage_id" if fun in self.modules: return self.modules[fun](self.kwargs) else: diff --git a/salt/cache/etcd_cache.py b/salt/cache/etcd_cache.py index c1a111bd4f9..36c23f8131c 100644 --- a/salt/cache/etcd_cache.py +++ b/salt/cache/etcd_cache.py @@ -141,16 +141,14 @@ def store(bank, key, data): Store a key value. """ _init_client() - etcd_key = "{}/{}/{}".format(path_prefix, bank, key) - etcd_tstamp_key = "{}/{}/{}".format(path_prefix, bank, key + _tstamp_suffix) + etcd_key = f"{path_prefix}/{bank}/{key}" + etcd_tstamp_key = f"{path_prefix}/{bank}/{key + _tstamp_suffix}" try: value = salt.payload.dumps(data) client.write(etcd_key, base64.b64encode(value)) client.write(etcd_tstamp_key, int(time.time())) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error writing the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error writing the key, {etcd_key}: {exc}") def fetch(bank, key): @@ -158,16 +156,14 @@ def fetch(bank, key): Fetch a key value. """ _init_client() - etcd_key = "{}/{}/{}".format(path_prefix, bank, key) + etcd_key = f"{path_prefix}/{bank}/{key}" try: value = client.read(etcd_key).value return salt.payload.loads(base64.b64decode(value)) except etcd.EtcdKeyNotFound: return {} except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error reading the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error reading the key, {etcd_key}: {exc}") def flush(bank, key=None): @@ -176,11 +172,11 @@ def flush(bank, key=None): """ _init_client() if key is None: - etcd_key = "{}/{}".format(path_prefix, bank) + etcd_key = f"{path_prefix}/{bank}" tstamp_key = None else: - etcd_key = "{}/{}/{}".format(path_prefix, bank, key) - tstamp_key = "{}/{}/{}".format(path_prefix, bank, key + _tstamp_suffix) + etcd_key = f"{path_prefix}/{bank}/{key}" + tstamp_key = f"{path_prefix}/{bank}/{key + _tstamp_suffix}" try: client.read(etcd_key) except etcd.EtcdKeyNotFound: @@ -190,9 +186,7 @@ def flush(bank, key=None): client.delete(tstamp_key) client.delete(etcd_key, recursive=True) except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error removing the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error removing the key, {etcd_key}: {exc}") def _walk(r): @@ -218,14 +212,14 @@ def ls(bank): bank. """ _init_client() - path = "{}/{}".format(path_prefix, bank) + path = f"{path_prefix}/{bank}" try: return _walk(client.read(path)) except etcd.EtcdKeyNotFound: return [] except Exception as exc: # pylint: disable=broad-except raise SaltCacheError( - 'There was an error getting the key "{}": {}'.format(bank, exc) + f'There was an error getting the key "{bank}": {exc}' ) from exc @@ -242,9 +236,7 @@ def contains(bank, key): except etcd.EtcdKeyNotFound: return False except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error getting the key, {}: {}".format(etcd_key, exc) - ) + raise SaltCacheError(f"There was an error getting the key, {etcd_key}: {exc}") def updated(bank, key): @@ -252,13 +244,11 @@ def updated(bank, key): Return Unix Epoch based timestamp of when the bank/key was updated. """ _init_client() - tstamp_key = "{}/{}/{}".format(path_prefix, bank, key + _tstamp_suffix) + tstamp_key = f"{path_prefix}/{bank}/{key + _tstamp_suffix}" try: value = client.read(tstamp_key).value return int(value) except etcd.EtcdKeyNotFound: return None except Exception as exc: # pylint: disable=broad-except - raise SaltCacheError( - "There was an error reading the key, {}: {}".format(tstamp_key, exc) - ) + raise SaltCacheError(f"There was an error reading the key, {tstamp_key}: {exc}") diff --git a/salt/cache/localfs.py b/salt/cache/localfs.py index df2f3ac4727..4ac5ecec062 100644 --- a/salt/cache/localfs.py +++ b/salt/cache/localfs.py @@ -51,10 +51,10 @@ def store(bank, key, data, cachedir): except OSError as exc: if exc.errno != errno.EEXIST: raise SaltCacheError( - "The cache directory, {}, could not be created: {}".format(base, exc) + f"The cache directory, {base}, could not be created: {exc}" ) - outfile = os.path.join(base, "{}.p".format(key)) + outfile = os.path.join(base, f"{key}.p") tmpfh, tmpfname = tempfile.mkstemp(dir=base) os.close(tmpfh) try: @@ -64,7 +64,7 @@ def store(bank, key, data, cachedir): salt.utils.atomicfile.atomic_rename(tmpfname, outfile) except OSError as exc: raise SaltCacheError( - "There was an error writing the cache file, {}: {}".format(base, exc) + f"There was an error writing the cache file, {base}: {exc}" ) @@ -73,7 +73,7 @@ def fetch(bank, key, cachedir): Fetch information from a file. """ inkey = False - key_file = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + key_file = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") if not os.path.isfile(key_file): # The bank includes the full filename, and the key is inside the file key_file = os.path.join(cachedir, os.path.normpath(bank) + ".p") @@ -90,7 +90,7 @@ def fetch(bank, key, cachedir): return salt.payload.load(fh_) except OSError as exc: raise SaltCacheError( - 'There was an error reading the cache file "{}": {}'.format(key_file, exc) + f'There was an error reading the cache file "{key_file}": {exc}' ) @@ -98,7 +98,7 @@ def updated(bank, key, cachedir): """ Return the epoch of the mtime for this cache file """ - key_file = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + key_file = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") if not os.path.isfile(key_file): log.warning('Cache file "%s" does not exist', key_file) return None @@ -106,7 +106,7 @@ def updated(bank, key, cachedir): return int(os.path.getmtime(key_file)) except OSError as exc: raise SaltCacheError( - 'There was an error reading the mtime for "{}": {}'.format(key_file, exc) + f'There was an error reading the mtime for "{key_file}": {exc}' ) @@ -124,12 +124,12 @@ def flush(bank, key=None, cachedir=None): return False shutil.rmtree(target) else: - target = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + target = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") if not os.path.isfile(target): return False os.remove(target) except OSError as exc: - raise SaltCacheError('There was an error removing "{}": {}'.format(target, exc)) + raise SaltCacheError(f'There was an error removing "{target}": {exc}') return True @@ -143,9 +143,7 @@ def list_(bank, cachedir): try: items = os.listdir(base) except OSError as exc: - raise SaltCacheError( - 'There was an error accessing directory "{}": {}'.format(base, exc) - ) + raise SaltCacheError(f'There was an error accessing directory "{base}": {exc}') ret = [] for item in items: if item.endswith(".p"): @@ -163,5 +161,5 @@ def contains(bank, key, cachedir): base = os.path.join(cachedir, os.path.normpath(bank)) return os.path.isdir(base) else: - keyfile = os.path.join(cachedir, os.path.normpath(bank), "{}.p".format(key)) + keyfile = os.path.join(cachedir, os.path.normpath(bank), f"{key}.p") return os.path.isfile(keyfile) diff --git a/salt/cache/redis_cache.py b/salt/cache/redis_cache.py index 6579303fef8..5584d118ba7 100644 --- a/salt/cache/redis_cache.py +++ b/salt/cache/redis_cache.py @@ -151,7 +151,6 @@ Cluster Configuration Example: cache.redis.separator: '@' """ - import itertools import logging import time @@ -352,7 +351,7 @@ def _get_banks_to_remove(redis_server, bank, path=""): A simple tree traversal algorithm that builds the list of banks to remove, starting from an arbitrary node in the tree. """ - current_path = bank if not path else "{path}/{bank}".format(path=path, bank=bank) + current_path = bank if not path else f"{path}/{bank}" bank_paths_to_remove = [current_path] # as you got here, you'll be removed diff --git a/salt/channel/client.py b/salt/channel/client.py index ea42cefaef0..f49ec473f85 100644 --- a/salt/channel/client.py +++ b/salt/channel/client.py @@ -3,6 +3,7 @@ Encapsulate the different transports available to Salt. This includes client side transport, for the ReqServer and the Publisher """ + import logging import os import time diff --git a/salt/cli/api.py b/salt/cli/api.py index a54595578c4..3e46676e1ef 100644 --- a/salt/cli/api.py +++ b/salt/cli/api.py @@ -6,7 +6,6 @@ """ - import logging import salt.client.netapi diff --git a/salt/cli/batch.py b/salt/cli/batch.py index 8e1547c61d4..85250c02efd 100644 --- a/salt/cli/batch.py +++ b/salt/cli/batch.py @@ -188,7 +188,7 @@ class Batch: if next_: if not self.quiet: salt.utils.stringutils.print_cli( - "\nExecuting run on {}\n".format(sorted(next_)) + f"\nExecuting run on {sorted(next_)}\n" ) # create a new iterator for this batch of minions return_value = self.opts.get("return", self.opts.get("ret", "")) diff --git a/salt/cli/caller.py b/salt/cli/caller.py index fd12b4e0ae3..ffc39356ba9 100644 --- a/salt/cli/caller.py +++ b/salt/cli/caller.py @@ -75,7 +75,7 @@ class BaseCaller: docs[name] = func.__doc__ for name in sorted(docs): if name.startswith(self.opts.get("fun", "")): - salt.utils.stringutils.print_cli("{}:\n{}\n".format(name, docs[name])) + salt.utils.stringutils.print_cli(f"{name}:\n{docs[name]}\n") def print_grains(self): """ @@ -130,7 +130,7 @@ class BaseCaller: salt.minion.get_proc_dir(self.opts["cachedir"]), ret["jid"] ) if fun not in self.minion.functions: - docs = self.minion.functions["sys.doc"]("{}*".format(fun)) + docs = self.minion.functions["sys.doc"](f"{fun}*") if docs: docs[fun] = self.minion.functions.missing_fun_string(fun) ret["out"] = "nested" @@ -194,20 +194,16 @@ class BaseCaller: executors = [executors] try: for name in executors: - fname = "{}.execute".format(name) + fname = f"{name}.execute" if fname not in self.minion.executors: - raise SaltInvocationError( - "Executor '{}' is not available".format(name) - ) + raise SaltInvocationError(f"Executor '{name}' is not available") ret["return"] = self.minion.executors[fname]( self.opts, data, func, args, kwargs ) if ret["return"] is not None: break except TypeError as exc: - sys.stderr.write( - "\nPassed invalid arguments: {}.\n\nUsage:\n".format(exc) - ) + sys.stderr.write(f"\nPassed invalid arguments: {exc}.\n\nUsage:\n") salt.utils.stringutils.print_cli(func.__doc__) active_level = LOG_LEVELS.get( self.opts["log_level"].lower(), logging.ERROR @@ -235,7 +231,7 @@ class BaseCaller: retcode = salt.defaults.exitcodes.EX_GENERIC ret["retcode"] = retcode - except (CommandExecutionError) as exc: + except CommandExecutionError as exc: msg = "Error running '{0}': {1}\n" active_level = LOG_LEVELS.get(self.opts["log_level"].lower(), logging.ERROR) if active_level <= logging.DEBUG: @@ -272,7 +268,7 @@ class BaseCaller: continue try: ret["success"] = True - self.minion.returners["{}.returner".format(returner)](ret) + self.minion.returners[f"{returner}.returner"](ret) except Exception: # pylint: disable=broad-except pass diff --git a/salt/cli/cp.py b/salt/cli/cp.py index 457be4b044e..39ba429134d 100644 --- a/salt/cli/cp.py +++ b/salt/cli/cp.py @@ -68,7 +68,7 @@ class SaltCP: except OSError as exc: if exc.errno == errno.ENOENT: # Path does not exist - sys.stderr.write("{} does not exist\n".format(path)) + sys.stderr.write(f"{path} does not exist\n") sys.exit(42) elif exc.errno in (errno.EINVAL, errno.ENOTDIR): # Path is a file (EINVAL on Windows, ENOTDIR otherwise) @@ -97,7 +97,7 @@ class SaltCP: Take a path and return the contents of the file as a string """ if not os.path.isfile(fn_): - err = "The referenced file, {} is not available.".format(fn_) + err = f"The referenced file, {fn_} is not available." sys.stderr.write(err + "\n") sys.exit(42) with salt.utils.files.fopen(fn_, "r") as fp_: @@ -211,12 +211,10 @@ class SaltCP: log.debug( "Copying %s to %starget '%s' as %s%s", fn_, - "{} ".format(selected_target_option) - if selected_target_option - else "", + f"{selected_target_option} " if selected_target_option else "", tgt, remote_path, - " (chunk #{})".format(index) if append else "", + f" (chunk #{index})" if append else "", ) args = [ tgt, @@ -261,11 +259,13 @@ class SaltCP: log.debug( "Creating empty dir %s on %starget '%s'", dirname, - "{} ".format( - selected_target_option - ) # pylint: disable=str-format-in-logging - if selected_target_option - else "", + ( + "{} ".format( + selected_target_option + ) # pylint: disable=str-format-in-logging + if selected_target_option + else "" + ), tgt, ) args = [tgt, "cp.recv_chunked", [remote_path, None], timeout] diff --git a/salt/cli/daemons.py b/salt/cli/daemons.py index 22d89e0541d..efd89219551 100644 --- a/salt/cli/daemons.py +++ b/salt/cli/daemons.py @@ -2,7 +2,6 @@ Make me some salt! """ - import logging import os import warnings diff --git a/salt/cli/spm.py b/salt/cli/spm.py index 9098e0d78e6..a4c97da5570 100644 --- a/salt/cli/spm.py +++ b/salt/cli/spm.py @@ -7,7 +7,6 @@ .. versionadded:: 2015.8.0 """ - import salt.spm import salt.utils.parsers as parsers from salt.utils.verify import verify_env diff --git a/salt/client/__init__.py b/salt/client/__init__.py index 9a1af36c872..3be1150b111 100644 --- a/salt/client/__init__.py +++ b/salt/client/__init__.py @@ -8,7 +8,6 @@ The data structure needs to be: 'key': ''} """ - import logging # The components here are simple, and they need to be and stay simple, we diff --git a/salt/client/mixins.py b/salt/client/mixins.py index 9bfa7c651d4..e8e22728a28 100644 --- a/salt/client/mixins.py +++ b/salt/client/mixins.py @@ -382,10 +382,10 @@ class SyncClientMixin(ClientStateMixin): try: data["return"] = func(*args, **kwargs) except TypeError as exc: - data[ - "return" - ] = "\nPassed invalid arguments: {}\n\nUsage:\n{}".format( - exc, func.__doc__ + data["return"] = ( + "\nPassed invalid arguments: {}\n\nUsage:\n{}".format( + exc, func.__doc__ + ) ) try: data["success"] = self.context.get("retcode", 0) == 0 diff --git a/salt/client/netapi.py b/salt/client/netapi.py index 6d0dc73b854..27029af85a3 100644 --- a/salt/client/netapi.py +++ b/salt/client/netapi.py @@ -48,7 +48,7 @@ class NetapiClient: for fun in self.netapi: if fun.endswith(".start"): - name = "RunNetapi({})".format(self.netapi[fun].__module__) + name = f"RunNetapi({self.netapi[fun].__module__})" log.info("Starting %s", name) self.process_manager.add_process( RunNetapi, args=(self.opts, fun), name=name diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py index 4eec0eadcf6..ae51bdb4d8c 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -783,9 +783,9 @@ class SSH(MultiprocessingStateMixin): data["return"] = data.get("stdout") else: data["return"] = data.get("stderr", data.get("stdout")) - data[ - "jid" - ] = jid # make the jid in the payload the same as the jid in the tag + data["jid"] = ( + jid # make the jid in the payload the same as the jid in the tag + ) self.event.fire_event( data, salt.utils.event.tagify([jid, "ret", host], "job") ) @@ -923,9 +923,9 @@ class SSH(MultiprocessingStateMixin): data["return"] = data.get("stdout") else: data["return"] = data.get("stderr", data.get("stdout")) - data[ - "jid" - ] = jid # make the jid in the payload the same as the jid in the tag + data["jid"] = ( + jid # make the jid in the payload the same as the jid in the tag + ) self.event.fire_event( data, salt.utils.event.tagify([jid, "ret", host], "job") ) diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py index 9b8f9e0f658..24e4c0cc9cb 100644 --- a/salt/client/ssh/ssh_py_shim.py +++ b/salt/client/ssh/ssh_py_shim.py @@ -170,7 +170,7 @@ def unpack_thin(thin_path): """ tfile = tarfile.TarFile.gzopen(thin_path) old_umask = os.umask(0o077) # pylint: disable=blacklisted-function - tfile.extractall(path=OPTIONS.saltdir) + tfile.extractall(path=OPTIONS.saltdir) # nosec tfile.close() os.umask(old_umask) # pylint: disable=blacklisted-function try: @@ -197,7 +197,7 @@ def unpack_ext(ext_path): ) tfile = tarfile.TarFile.gzopen(ext_path) old_umask = os.umask(0o077) # pylint: disable=blacklisted-function - tfile.extractall(path=modcache) + tfile.extractall(path=modcache) # nosec tfile.close() os.umask(old_umask) # pylint: disable=blacklisted-function os.unlink(ext_path) diff --git a/salt/client/ssh/wrapper/__init__.py b/salt/client/ssh/wrapper/__init__.py index bb60f58cd1a..4d29c168491 100644 --- a/salt/client/ssh/wrapper/__init__.py +++ b/salt/client/ssh/wrapper/__init__.py @@ -5,7 +5,6 @@ to be easily rewritten to execute in a way that makes them do the same tasks as ZeroMQ salt, but via ssh. """ - import copy import logging diff --git a/salt/client/ssh/wrapper/cmdmod.py b/salt/client/ssh/wrapper/cmdmod.py index 788c86b3144..e74079bfcbc 100644 --- a/salt/client/ssh/wrapper/cmdmod.py +++ b/salt/client/ssh/wrapper/cmdmod.py @@ -8,6 +8,7 @@ SSH wrapper module for the ``cmdmod`` execution module. value of the minion setting. This is the same for the ``state`` and `cp`` wrappers. """ + import logging import os.path import shlex diff --git a/salt/client/ssh/wrapper/grains.py b/salt/client/ssh/wrapper/grains.py index ff3789ff84c..2483726ae21 100644 --- a/salt/client/ssh/wrapper/grains.py +++ b/salt/client/ssh/wrapper/grains.py @@ -2,7 +2,6 @@ Return/control aspects of the grains data """ - import math import salt.utils.data diff --git a/salt/client/ssh/wrapper/mine.py b/salt/client/ssh/wrapper/mine.py index 32a0e01e90b..80e114ac738 100644 --- a/salt/client/ssh/wrapper/mine.py +++ b/salt/client/ssh/wrapper/mine.py @@ -8,7 +8,6 @@ Wrapper function for mine operations for salt-ssh accessing the regular mine as well. """ - import copy import logging diff --git a/salt/cloud/__init__.py b/salt/cloud/__init__.py index 5402bd848e9..61daa8db521 100644 --- a/salt/cloud/__init__.py +++ b/salt/cloud/__init__.py @@ -2,6 +2,7 @@ The top level interface used to translate configuration data back to the correct cloud modules """ + import copy import glob import logging diff --git a/salt/cloud/cli.py b/salt/cloud/cli.py index f458e975c63..4a441a0798c 100644 --- a/salt/cloud/cli.py +++ b/salt/cloud/cli.py @@ -1,6 +1,7 @@ """ Primary interfaces for the salt-cloud system """ + # Need to get data from 4 sources! # CLI options # salt cloud config - CONFIG_DIR + '/cloud' @@ -174,11 +175,11 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): msg = "The following virtual machines are set to be destroyed:\n" names = set() for alias, drivers in matching.items(): - msg += " {}:\n".format(alias) + msg += f" {alias}:\n" for driver, vms in drivers.items(): - msg += " {}:\n".format(driver) + msg += f" {driver}:\n" for name in vms: - msg += " {}\n".format(name) + msg += f" {name}\n" names.add(name) try: if self.print_confirm(msg): @@ -212,7 +213,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): key, value = name.split("=", 1) kwargs[key] = value else: - msg += " {}\n".format(name) + msg += f" {name}\n" machines.append(name) names = machines @@ -255,7 +256,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): elif self.options.set_password: username = self.credential_username - provider_name = "salt.cloud.provider.{}".format(self.credential_provider) + provider_name = f"salt.cloud.provider.{self.credential_provider}" # TODO: check if provider is configured # set the password salt.utils.cloud.store_password_in_keyring(provider_name, username) @@ -275,7 +276,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): # display profile errors msg += "Found the following errors:\n" for profile_name, error in dmap["errors"].items(): - msg += " {}: {}\n".format(profile_name, error) + msg += f" {profile_name}: {error}\n" sys.stderr.write(msg) sys.stderr.flush() @@ -283,17 +284,17 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): if "existing" in dmap: msg += "The following virtual machines already exist:\n" for name in dmap["existing"]: - msg += " {}\n".format(name) + msg += f" {name}\n" if dmap["create"]: msg += "The following virtual machines are set to be created:\n" for name in dmap["create"]: - msg += " {}\n".format(name) + msg += f" {name}\n" if "destroy" in dmap: msg += "The following virtual machines are set to be destroyed:\n" for name in dmap["destroy"]: - msg += " {}\n".format(name) + msg += f" {name}\n" if not dmap["create"] and not dmap.get("destroy", None): if not dmap.get("existing", None): @@ -382,7 +383,7 @@ class SaltCloud(salt.utils.parsers.SaltCloudParser): # This is a salt cloud system exit if exc.exit_code > 0: # the exit code is bigger than 0, it's an error - msg = "Error: {}".format(msg) + msg = f"Error: {msg}" self.exit(exc.exit_code, msg.format(exc).rstrip() + "\n") # It's not a system exit but it's an error we can # handle diff --git a/salt/cloud/clouds/aliyun.py b/salt/cloud/clouds/aliyun.py index 9b1b318885b..9879e4df223 100644 --- a/salt/cloud/clouds/aliyun.py +++ b/salt/cloud/clouds/aliyun.py @@ -412,9 +412,7 @@ def get_image(vm_): if vm_image and str(vm_image) in images: return images[vm_image]["ImageId"] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_securitygroup(vm_): @@ -432,7 +430,7 @@ def get_securitygroup(vm_): if securitygroup and str(securitygroup) in sgs: return sgs[securitygroup]["SecurityGroupId"] raise SaltCloudNotFound( - "The specified security group, '{}', could not be found.".format(securitygroup) + f"The specified security group, '{securitygroup}', could not be found." ) @@ -451,9 +449,7 @@ def get_size(vm_): if vm_size and str(vm_size) in sizes: return sizes[vm_size]["InstanceTypeId"] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def __get_location(vm_): @@ -471,7 +467,7 @@ def __get_location(vm_): if vm_location and str(vm_location) in locations: return locations[vm_location]["RegionId"] raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -575,7 +571,7 @@ def create_node(kwargs): "HostName", "Password", "SystemDisk.Category", - "VSwitchId" + "VSwitchId", # 'DataDisk.n.Size', 'DataDisk.n.Category', 'DataDisk.n.SnapshotId' ] @@ -920,7 +916,7 @@ def _get_node(name): ) # Just a little delay between attempts... time.sleep(0.5) - raise SaltCloudNotFound("The specified instance {} not found".format(name)) + raise SaltCloudNotFound(f"The specified instance {name} not found") def show_image(kwargs, call=None): @@ -982,7 +978,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1001,7 +997,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/cloudstack.py b/salt/cloud/clouds/cloudstack.py index ef50aaf3bf0..ff526aa82e0 100644 --- a/salt/cloud/clouds/cloudstack.py +++ b/salt/cloud/clouds/cloudstack.py @@ -20,6 +20,7 @@ Use of this module requires the ``apikey``, ``secretkey``, ``host`` and driver: cloudstack """ + # pylint: disable=function-redefined import logging @@ -473,7 +474,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", sock_dir=__opts__["sock_dir"], args={"name": name}, ) @@ -498,7 +499,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "detaching volume", - "salt/cloud/{}/detaching".format(volume.name), + f"salt/cloud/{volume.name}/detaching", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -509,7 +510,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "detached volume", - "salt/cloud/{}/detached".format(volume.name), + f"salt/cloud/{volume.name}/detached", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -518,7 +519,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying volume", - "salt/cloud/{}/destroying".format(volume.name), + f"salt/cloud/{volume.name}/destroying", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -529,7 +530,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed volume", - "salt/cloud/{}/destroyed".format(volume.name), + f"salt/cloud/{volume.name}/destroyed", sock_dir=__opts__["sock_dir"], args={"name": volume.name}, ) @@ -544,7 +545,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", sock_dir=__opts__["sock_dir"], args={"name": name}, ) diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 3c8ea286bce..11f6dd6a926 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -296,11 +296,9 @@ def query( location = get_location() if not requesturl: - endpoint = provider.get( - "endpoint", "ec2.{}.{}".format(location, service_url) - ) + endpoint = provider.get("endpoint", f"ec2.{location}.{service_url}") - requesturl = "https://{}/".format(endpoint) + requesturl = f"https://{endpoint}/" endpoint = urllib.parse.urlparse(requesturl).netloc endpoint_path = urllib.parse.urlparse(requesturl).path else: @@ -1479,7 +1477,7 @@ def _create_eni_if_necessary(interface, vm_): eni_desc = result[1] if not eni_desc or not eni_desc.get("networkInterfaceId"): - raise SaltCloudException("Failed to create interface: {}".format(result)) + raise SaltCloudException(f"Failed to create interface: {result}") eni_id = eni_desc.get("networkInterfaceId") log.debug("Created network interface %s inst %s", eni_id, interface["DeviceIndex"]) @@ -1750,11 +1748,11 @@ def _param_from_config(key, data): if isinstance(data, dict): for k, v in data.items(): - param.update(_param_from_config("{}.{}".format(key, k), v)) + param.update(_param_from_config(f"{key}.{k}", v)) elif isinstance(data, list) or isinstance(data, tuple): for idx, conf_item in enumerate(data): - prefix = "{}.{}".format(key, idx) + prefix = f"{key}.{idx}" param.update(_param_from_config(prefix, conf_item)) else: @@ -1869,7 +1867,7 @@ def request_instance(vm_=None, call=None): params[spot_prefix + "SecurityGroup.1"] = ex_securitygroup else: for counter, sg_ in enumerate(ex_securitygroup): - params[spot_prefix + "SecurityGroup.{}".format(counter)] = sg_ + params[spot_prefix + f"SecurityGroup.{counter}"] = sg_ ex_iam_profile = iam_profile(vm_) if ex_iam_profile: @@ -1904,7 +1902,7 @@ def request_instance(vm_=None, call=None): params[spot_prefix + "SecurityGroupId.1"] = ex_securitygroupid else: for counter, sg_ in enumerate(ex_securitygroupid): - params[spot_prefix + "SecurityGroupId.{}".format(counter)] = sg_ + params[spot_prefix + f"SecurityGroupId.{counter}"] = sg_ placementgroup_ = get_placementgroup(vm_) if placementgroup_ is not None: @@ -2043,9 +2041,9 @@ def request_instance(vm_=None, call=None): else: dev_index = len(dev_list) # Add the device name in since it wasn't already there - params[ - "{}BlockDeviceMapping.{}.DeviceName".format(spot_prefix, dev_index) - ] = rd_name + params[f"{spot_prefix}BlockDeviceMapping.{dev_index}.DeviceName"] = ( + rd_name + ) # Set the termination value termination_key = "{}BlockDeviceMapping.{}.Ebs.DeleteOnTermination".format( @@ -2508,7 +2506,7 @@ def wait_for_instance( for line in comps[0].splitlines(): if not line: continue - keys += "\n{} {}".format(ip_address, line) + keys += f"\n{ip_address} {line}" with salt.utils.files.fopen(known_hosts_file, "a") as fp_: fp_.write(salt.utils.stringutils.to_str(keys)) @@ -2562,7 +2560,7 @@ def _validate_key_path_and_mode(key_filename): if not os.path.exists(key_filename): raise SaltCloudSystemExit( - "The EC2 key file '{}' does not exist.\n".format(key_filename) + f"The EC2 key file '{key_filename}' does not exist.\n" ) key_mode = stat.S_IMODE(os.stat(key_filename).st_mode) @@ -2751,7 +2749,7 @@ def create(vm_=None, call=None): __utils__["cloud.fire_event"]( "event", "setting tags", - "salt/cloud/spot_request_{}/tagging".format(sir_id), + f"salt/cloud/spot_request_{sir_id}/tagging", args={"tags": spot_request_tags}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2923,7 +2921,7 @@ def create(vm_=None, call=None): __utils__["cloud.fire_event"]( "event", "setting tags", - "salt/cloud/block_volume_{}/tagging".format(str(volid)), + f"salt/cloud/block_volume_{str(volid)}/tagging", args={"tags": tags}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3053,7 +3051,7 @@ def stop(name, call=None): __utils__["cloud.fire_event"]( "event", "stopping instance", - "salt/cloud/{}/stopping".format(name), + f"salt/cloud/{name}/stopping", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3087,7 +3085,7 @@ def start(name, call=None): __utils__["cloud.fire_event"]( "event", "starting instance", - "salt/cloud/{}/starting".format(name), + f"salt/cloud/{name}/starting", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3162,8 +3160,8 @@ def set_tags( tags = kwargs for idx, (tag_k, tag_v) in enumerate(tags.items()): - params["Tag.{}.Key".format(idx)] = tag_k - params["Tag.{}.Value".format(idx)] = tag_v + params[f"Tag.{idx}.Key"] = tag_k + params[f"Tag.{idx}.Value"] = tag_v attempts = 0 while attempts < aws.AWS_MAX_RETRIES: @@ -3209,7 +3207,7 @@ def set_tags( return settags - raise SaltCloudSystemExit("Failed to set tags on {}!".format(name)) + raise SaltCloudSystemExit(f"Failed to set tags on {name}!") def get_tags( @@ -3291,7 +3289,7 @@ def del_tags( params = {"Action": "DeleteTags", "ResourceId.1": instance_id} for idx, tag in enumerate(kwargs["tags"].split(",")): - params["Tag.{}.Key".format(idx)] = tag + params[f"Tag.{idx}.Key"] = tag aws.query( params, @@ -3355,7 +3353,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3376,7 +3374,7 @@ def destroy(name, call=None): "rename_on_destroy", get_configured_provider(), __opts__, search_global=False ) if rename_on_destroy is not False: - newname = "{}-DEL{}".format(name, uuid.uuid4().hex) + newname = f"{name}-DEL{uuid.uuid4().hex}" rename(name, kwargs={"newname": newname}, call="action") log.info( "Machine will be identified as %s until it has been cleaned up.", newname @@ -3409,7 +3407,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name, "instance_id": instance_id}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -4055,8 +4053,8 @@ def _toggle_delvol( if volume_id is not None and volume_id != item["ebs"]["volumeId"]: continue - params["BlockDeviceMapping.{}.DeviceName".format(idx)] = device_name - params["BlockDeviceMapping.{}.Ebs.DeleteOnTermination".format(idx)] = value + params[f"BlockDeviceMapping.{idx}.DeviceName"] = device_name + params[f"BlockDeviceMapping.{idx}.Ebs.DeleteOnTermination"] = value aws.query( params, @@ -4476,7 +4474,7 @@ def describe_volumes(kwargs=None, call=None): if "volume_id" in kwargs: volume_id = kwargs["volume_id"].split(",") for volume_index, volume_id in enumerate(volume_id): - params["VolumeId.{}".format(volume_index)] = volume_id + params[f"VolumeId.{volume_index}"] = volume_id log.debug(params) @@ -4795,17 +4793,17 @@ def describe_snapshots(kwargs=None, call=None): if "snapshot_id" in kwargs: snapshot_ids = kwargs["snapshot_id"].split(",") for snapshot_index, snapshot_id in enumerate(snapshot_ids): - params["SnapshotId.{}".format(snapshot_index)] = snapshot_id + params[f"SnapshotId.{snapshot_index}"] = snapshot_id if "owner" in kwargs: owners = kwargs["owner"].split(",") for owner_index, owner in enumerate(owners): - params["Owner.{}".format(owner_index)] = owner + params[f"Owner.{owner_index}"] = owner if "restorable_by" in kwargs: restorable_bys = kwargs["restorable_by"].split(",") for restorable_by_index, restorable_by in enumerate(restorable_bys): - params["RestorableBy.{}".format(restorable_by_index)] = restorable_by + params[f"RestorableBy.{restorable_by_index}"] = restorable_by log.debug(params) @@ -5012,11 +5010,11 @@ def _parse_pricing(url, name): "storageGiB", "USD", ): - price_js = price_js.replace(keyword, '"{}"'.format(keyword)) + price_js = price_js.replace(keyword, f'"{keyword}"') for keyword in ("region", "price", "size"): - price_js = price_js.replace(keyword, '"{}"'.format(keyword)) - price_js = price_js.replace('"{}"s'.format(keyword), '"{}s"'.format(keyword)) + price_js = price_js.replace(keyword, f'"{keyword}"') + price_js = price_js.replace(f'"{keyword}"s', f'"{keyword}s"') price_js = price_js.replace('""', '"') @@ -5030,7 +5028,7 @@ def _parse_pricing(url, name): sizes[size["size"]] = size regions[region["region"]] = sizes - outfile = os.path.join(__opts__["cachedir"], "ec2-pricing-{}.p".format(name)) + outfile = os.path.join(__opts__["cachedir"], f"ec2-pricing-{name}.p") with salt.utils.files.fopen(outfile, "w") as fho: salt.utils.msgpack.dump(regions, fho) @@ -5092,7 +5090,7 @@ def show_pricing(kwargs=None, call=None): else: name = "linux" - pricefile = os.path.join(__opts__["cachedir"], "ec2-pricing-{}.p".format(name)) + pricefile = os.path.join(__opts__["cachedir"], f"ec2-pricing-{name}.p") if not os.path.isfile(pricefile): update_pricing({"type": name}, "function") diff --git a/salt/cloud/clouds/gce.py b/salt/cloud/clouds/gce.py index 4c14f4e74d8..f5b16897fa0 100644 --- a/salt/cloud/clouds/gce.py +++ b/salt/cloud/clouds/gce.py @@ -43,6 +43,7 @@ Example Provider Configuration :maintainer: Russell Tolle :depends: libcloud >= 1.0.0 """ + # pylint: disable=function-redefined import logging @@ -185,7 +186,7 @@ def get_conn(): "service_account_private_key", provider, __opts__ ) gce = driver(email, private_key, project=project) - gce.connection.user_agent_append("{}/{}".format(_UA_PRODUCT, _UA_VERSION)) + gce.connection.user_agent_append(f"{_UA_PRODUCT}/{_UA_VERSION}") return gce @@ -543,7 +544,7 @@ def _parse_allow(allow): pairs = p.split(":") if pairs[0].lower() not in ["tcp", "udp", "icmp"]: raise SaltCloudSystemExit( - "Unsupported protocol {}. Must be tcp, udp, or icmp.".format(pairs[0]) + f"Unsupported protocol {pairs[0]}. Must be tcp, udp, or icmp." ) if len(pairs) == 1 or pairs[0].lower() == "icmp": seen_protos[pairs[0]] = [] @@ -1698,7 +1699,6 @@ def delete_disk(kwargs=None, call=None): def create_disk(kwargs=None, call=None): - """ Create a new persistent disk. Must specify `disk_name` and `location`, and optionally can specify 'disk_type' as pd-standard or pd-ssd, which @@ -2014,7 +2014,7 @@ def reboot(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "reboot instance", - "salt/cloud/{}/rebooting".format(vm_name), + f"salt/cloud/{vm_name}/rebooting", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2025,7 +2025,7 @@ def reboot(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "reboot instance", - "salt/cloud/{}/rebooted".format(vm_name), + f"salt/cloud/{vm_name}/rebooted", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2056,7 +2056,7 @@ def start(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "start instance", - "salt/cloud/{}/starting".format(vm_name), + f"salt/cloud/{vm_name}/starting", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2067,7 +2067,7 @@ def start(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "start instance", - "salt/cloud/{}/started".format(vm_name), + f"salt/cloud/{vm_name}/started", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2096,7 +2096,7 @@ def stop(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "stop instance", - "salt/cloud/{}/stopping".format(vm_name), + f"salt/cloud/{vm_name}/stopping", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2107,7 +2107,7 @@ def stop(vm_name, call=None): __utils__["cloud.fire_event"]( "event", "stop instance", - "salt/cloud/{}/stopped".format(vm_name), + f"salt/cloud/{vm_name}/stopped", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2145,12 +2145,12 @@ def destroy(vm_name, call=None): exc, exc_info_on_loglevel=logging.DEBUG, ) - raise SaltCloudSystemExit("Could not find instance {}.".format(vm_name)) + raise SaltCloudSystemExit(f"Could not find instance {vm_name}.") __utils__["cloud.fire_event"]( "event", "delete instance", - "salt/cloud/{}/deleting".format(vm_name), + f"salt/cloud/{vm_name}/deleting", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2186,11 +2186,11 @@ def destroy(vm_name, call=None): exc, exc_info_on_loglevel=logging.DEBUG, ) - raise SaltCloudSystemExit("Could not destroy instance {}.".format(vm_name)) + raise SaltCloudSystemExit(f"Could not destroy instance {vm_name}.") __utils__["cloud.fire_event"]( "event", "delete instance", - "salt/cloud/{}/deleted".format(vm_name), + f"salt/cloud/{vm_name}/deleted", args={"name": vm_name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2279,7 +2279,7 @@ def create_attach_volumes(name, kwargs, call=None): letter = ord("a") - 1 for idx, volume in enumerate(volumes): - volume_name = "{}-sd{}".format(name, chr(letter + 2 + idx)) + volume_name = f"{name}-sd{chr(letter + 2 + idx)}" volume_dict = { "disk_name": volume_name, diff --git a/salt/cloud/clouds/gogrid.py b/salt/cloud/clouds/gogrid.py index a2457b48ca4..1a28f837459 100644 --- a/salt/cloud/clouds/gogrid.py +++ b/salt/cloud/clouds/gogrid.py @@ -417,7 +417,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -428,7 +428,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -536,7 +536,7 @@ def _query( path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("GoGrid URL: %s", path) diff --git a/salt/cloud/clouds/hetzner.py b/salt/cloud/clouds/hetzner.py index e666769ee6a..f8f34ad6d85 100644 --- a/salt/cloud/clouds/hetzner.py +++ b/salt/cloud/clouds/hetzner.py @@ -16,6 +16,7 @@ Use of this module requires the ``key`` parameter to be set. driver: hetzner """ + # pylint: disable=invalid-name,function-redefined @@ -469,22 +470,22 @@ def start(name, call=None, wait=True): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." server.power_on() if wait and not wait_until(name, "running"): - return "Instance {} doesn't start.".format(name) + return f"Instance {name} doesn't start." __utils__["cloud.fire_event"]( "event", "started instance", - "salt/cloud/{}/started".format(name), + f"salt/cloud/{name}/started", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) - return {"Started": "{} was started.".format(name)} + return {"Started": f"{name} was started."} def stop(name, call=None, wait=True): @@ -503,22 +504,22 @@ def stop(name, call=None, wait=True): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." server.power_off() if wait and not wait_until(name, "off"): - return "Instance {} doesn't stop.".format(name) + return f"Instance {name} doesn't stop." __utils__["cloud.fire_event"]( "event", "stopped instance", - "salt/cloud/{}/stopped".format(name), + f"salt/cloud/{name}/stopped", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) - return {"Stopped": "{} was stopped.".format(name)} + return {"Stopped": f"{name} was stopped."} def reboot(name, call=None, wait=True): @@ -539,14 +540,14 @@ def reboot(name, call=None, wait=True): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." server.reboot() if wait and not wait_until(name, "running"): - return "Instance {} doesn't start.".format(name) + return f"Instance {name} doesn't start." - return {"Rebooted": "{} was rebooted.".format(name)} + return {"Rebooted": f"{name} was rebooted."} def destroy(name, call=None): @@ -567,12 +568,12 @@ def destroy(name, call=None): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -582,14 +583,14 @@ def destroy(name, call=None): if node["state"] == "running": stop(name, call="action", wait=False) if not wait_until(name, "off"): - return {"Error": "Unable to destroy {}, command timed out".format(name)} + return {"Error": f"Unable to destroy {name}, command timed out"} server.delete() __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -602,7 +603,7 @@ def destroy(name, call=None): __opts__, ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def resize(name, kwargs, call=None): @@ -623,7 +624,7 @@ def resize(name, kwargs, call=None): client = _connect_client() server = client.servers.get_by_name(name) if server is None: - return "Instance {} doesn't exist.".format(name) + return f"Instance {name} doesn't exist." # Check the configuration size = kwargs.get("size", None) @@ -637,7 +638,7 @@ def resize(name, kwargs, call=None): __utils__["cloud.fire_event"]( "event", "resizing instance", - "salt/cloud/{}/resizing".format(name), + f"salt/cloud/{name}/resizing", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -647,17 +648,17 @@ def resize(name, kwargs, call=None): if node["state"] == "running": stop(name, call="action", wait=False) if not wait_until(name, "off"): - return {"Error": "Unable to resize {}, command timed out".format(name)} + return {"Error": f"Unable to resize {name}, command timed out"} server.change_type(server_type, kwargs.get("upgrade_disk", False)) __utils__["cloud.fire_event"]( "event", "resizing instance", - "salt/cloud/{}/resized".format(name), + f"salt/cloud/{name}/resized", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) - return {"Resized": "{} was resized.".format(name)} + return {"Resized": f"{name} was resized."} diff --git a/salt/cloud/clouds/joyent.py b/salt/cloud/clouds/joyent.py index 58b853b3f00..6326d202b58 100644 --- a/salt/cloud/clouds/joyent.py +++ b/salt/cloud/clouds/joyent.py @@ -161,9 +161,7 @@ def get_image(vm_): images[vm_image]["name"] = images[vm_image]["id"] return images[vm_image] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_size(vm_): @@ -178,9 +176,7 @@ def get_size(vm_): if vm_size and str(vm_size) in sizes: return sizes[vm_size] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def query_instance(vm_=None, call=None): @@ -375,11 +371,11 @@ def create_node(**kwargs): if metadata is not None: for key, value in metadata.items(): - create_data["metadata.{}".format(key)] = value + create_data[f"metadata.{key}"] = value if tag is not None: for key, value in tag.items(): - create_data["tag.{}".format(key)] = value + create_data[f"tag.{key}"] = value if firewall_enabled is not None: create_data["firewall_enabled"] = firewall_enabled @@ -419,7 +415,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -435,7 +431,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -532,7 +528,6 @@ def take_action( method="GET", location=DEFAULT_LOCATION, ): - """ take action call used by start,stop, reboot :param name: name given to the machine @@ -921,11 +916,11 @@ def avail_images(call=None): get_configured_provider(), __opts__, search_global=False, - default="{}{}/{}/images".format(DEFAULT_LOCATION, JOYENT_API_HOST_SUFFIX, user), + default=f"{DEFAULT_LOCATION}{JOYENT_API_HOST_SUFFIX}/{user}/images", ) if not img_url.startswith("http://") and not img_url.startswith("https://"): - img_url = "{}://{}".format(_get_proto(), img_url) + img_url = f"{_get_proto()}://{img_url}" rcode, data = query(command="my/images", method="GET") log.debug(data) @@ -1078,7 +1073,7 @@ def get_location_path( :param location: joyent data center location :return: url """ - return "{}://{}{}".format(_get_proto(), location, api_host_suffix) + return f"{_get_proto()}://{location}{api_host_suffix}" def query(action=None, command=None, args=None, method="GET", location=None, data=None): @@ -1152,7 +1147,7 @@ def query(action=None, command=None, args=None, method="GET", location=None, dat path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("User: '%s' on PATH: %s", user, path) @@ -1175,9 +1170,9 @@ def query(action=None, command=None, args=None, method="GET", location=None, dat signed = base64.b64encode(signed) user_arr = user.split("/") if len(user_arr) == 1: - keyid = "/{}/keys/{}".format(user_arr[0], ssh_keyname) + keyid = f"/{user_arr[0]}/keys/{ssh_keyname}" elif len(user_arr) == 2: - keyid = "/{}/users/{}/keys/{}".format(user_arr[0], user_arr[1], ssh_keyname) + keyid = f"/{user_arr[0]}/users/{user_arr[1]}/keys/{ssh_keyname}" else: log.error("Malformed user string") diff --git a/salt/cloud/clouds/libvirt.py b/salt/cloud/clouds/libvirt.py index 76f6f6daa26..366e1871e1f 100644 --- a/salt/cloud/clouds/libvirt.py +++ b/salt/cloud/clouds/libvirt.py @@ -258,7 +258,7 @@ def get_domain_ips(domain, ip_source): log.info("Exception polling address %s", error) return ips - for (name, val) in addresses.items(): + for name, val in addresses.items(): if val["addrs"]: for addr in val["addrs"]: tp = to_ip_addr_type(addr["type"]) @@ -332,7 +332,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -345,7 +345,7 @@ def create(vm_): ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) vm_["key_filename"] = key_filename # wait_for_instance requires private_key @@ -374,7 +374,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) @@ -392,7 +392,7 @@ def create(vm_): description_elem = ElementTree.Element("description") domain_xml.insert(0, description_elem) description = domain_xml.find("./description") - description.text = "Cloned from {}".format(base) + description.text = f"Cloned from {base}" domain_xml.remove(domain_xml.find("./uuid")) for iface_xml in domain_xml.findall("./devices/interface"): @@ -426,9 +426,7 @@ def create(vm_): # see if there is a path element that needs rewriting if source_element and "path" in source_element.attrib: path = source_element.attrib["path"] - new_path = path.replace( - "/domain-{}/".format(base), "/domain-{}/".format(name) - ) + new_path = path.replace(f"/domain-{base}/", f"/domain-{name}/") log.debug("Rewriting agent socket path to %s", new_path) source_element.attrib["path"] = new_path @@ -471,7 +469,7 @@ def create(vm_): disk.find("./source").attrib["file"] = new_volume.path() else: raise SaltCloudExecutionFailure( - "Disk type '{}' not supported".format(disk_type) + f"Disk type '{disk_type}' not supported" ) clone_xml = salt.utils.stringutils.to_str(ElementTree.tostring(domain_xml)) @@ -515,7 +513,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -617,15 +615,15 @@ def destroy(name, call=None): pass if not found: - return "{} doesn't exist and can't be deleted".format(name) + return f"{name} doesn't exist and can't be deleted" if len(found) > 1: - return "{} doesn't identify a unique machine leaving things".format(name) + return f"{name} doesn't identify a unique machine leaving things" __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -636,7 +634,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -718,15 +716,15 @@ def find_pool_and_volume(conn, path): for v in sp.listAllVolumes(): if v.path() == path: return sp, v - raise SaltCloudNotFound("Could not find volume for path {}".format(path)) + raise SaltCloudNotFound(f"Could not find volume for path {path}") def generate_new_name(orig_name): if "." not in orig_name: - return "{}-{}".format(orig_name, uuid.uuid1()) + return f"{orig_name}-{uuid.uuid1()}" name, ext = orig_name.rsplit(".", 1) - return "{}-{}.{}".format(name, uuid.uuid1(), ext) + return f"{name}-{uuid.uuid1()}.{ext}" def get_domain_volumes(conn, domain): diff --git a/salt/cloud/clouds/lxc.py b/salt/cloud/clouds/lxc.py index da293dca66a..ced89e587bb 100644 --- a/salt/cloud/clouds/lxc.py +++ b/salt/cloud/clouds/lxc.py @@ -179,7 +179,7 @@ def _salt(fun, *args, **kw): ping_retries += 1 log.error("%s unreachable, retrying", target) if not ping: - raise SaltCloudSystemExit("Target {} unreachable".format(target)) + raise SaltCloudSystemExit(f"Target {target} unreachable") jid = conn.cmd_async(tgt=target, fun=fun, arg=args, kwarg=kw, **rkwargs) cret = conn.cmd( tgt=target, fun="saltutil.find_job", arg=[jid], timeout=10, **kwargs @@ -224,9 +224,7 @@ def _salt(fun, *args, **kw): time.sleep(0.5) try: if "is not available." in ret: - raise SaltCloudSystemExit( - "module/function {} is not available".format(fun) - ) + raise SaltCloudSystemExit(f"module/function {fun} is not available") except SaltCloudSystemExit: # pylint: disable=try-except-raise raise except TypeError: @@ -367,12 +365,12 @@ def destroy(vm_, call=None): ) if not get_configured_provider(): return - ret = {"comment": "{} was not found".format(vm_), "result": False} + ret = {"comment": f"{vm_} was not found", "result": False} if _salt("lxc.info", vm_, path=path): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(vm_), + f"salt/cloud/{vm_}/destroying", args={"name": vm_, "instance_id": vm_}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -380,11 +378,11 @@ def destroy(vm_, call=None): cret = _salt("lxc.destroy", vm_, stop=True, path=path) ret["result"] = cret["result"] if ret["result"]: - ret["comment"] = "{} was destroyed".format(vm_) + ret["comment"] = f"{vm_} was destroyed" __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(vm_), + f"salt/cloud/{vm_}/destroyed", args={"name": vm_, "instance_id": vm_}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -506,14 +504,14 @@ def get_configured_provider(vm_=None): matched = False # --list-images level if img_provider: - tgt = "provider: {}".format(img_provider) + tgt = f"provider: {img_provider}" if dalias == img_provider: data = get_provider(img_provider) matched = True # providers are set in configuration if not data and "profile" not in __opts__ and arg_providers: for name in arg_providers: - tgt = "provider: {}".format(name) + tgt = f"provider: {name}" if dalias == name: data = get_provider(name) if data: @@ -523,13 +521,13 @@ def get_configured_provider(vm_=None): elif "profile" in __opts__: curprof = __opts__["profile"] profs = __opts__["profiles"] - tgt = "profile: {}".format(curprof) + tgt = f"profile: {curprof}" if ( curprof in profs and profs[curprof]["provider"] == _get_active_provider_name() ): prov, cdriver = profs[curprof]["provider"].split(":") - tgt += " provider: {}".format(prov) + tgt += f" provider: {prov}" data = get_provider(prov) matched = True # fallback if we have only __active_provider_name__ diff --git a/salt/cloud/clouds/oneandone.py b/salt/cloud/clouds/oneandone.py index 7ddb50d3aba..6028e4f53e0 100644 --- a/salt/cloud/clouds/oneandone.py +++ b/salt/cloud/clouds/oneandone.py @@ -193,9 +193,7 @@ def get_size(vm_): if size: return size - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def get_image(vm_): @@ -211,9 +209,7 @@ def get_image(vm_): if vm_image and vm_image in (images[key]["id"], images[key]["name"]): return images[key] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def avail_locations(conn=None, call=None): @@ -735,7 +731,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -749,7 +745,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -846,7 +842,7 @@ def get_key_filename(vm_): key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_private_key '{}' does not exist".format(key_filename) + f"The defined ssh_private_key '{key_filename}' does not exist" ) return key_filename @@ -897,11 +893,9 @@ def _wait_for_completion(conn, wait_timeout, server_id): if server_state == "powered_on": return elif server_state == "failed": - raise Exception("Server creation failed for {}".format(server_id)) + raise Exception(f"Server creation failed for {server_id}") elif server_state in ("active", "enabled", "deploying", "configuring"): continue else: - raise Exception("Unknown server state {}".format(server_state)) - raise Exception( - "Timed out waiting for server create completion for {}".format(server_id) - ) + raise Exception(f"Unknown server state {server_state}") + raise Exception(f"Timed out waiting for server create completion for {server_id}") diff --git a/salt/cloud/clouds/opennebula.py b/salt/cloud/clouds/opennebula.py index 02602ca1e17..f3274a26b5a 100644 --- a/salt/cloud/clouds/opennebula.py +++ b/salt/cloud/clouds/opennebula.py @@ -76,7 +76,7 @@ from salt.exceptions import ( ) try: - import xmlrpc.client + import xmlrpc.client # nosec from lxml import etree @@ -85,7 +85,6 @@ except ImportError: HAS_XML_LIBS = False -# Get Logging Started log = logging.getLogger(__name__) __virtualname__ = "opennebula" @@ -558,7 +557,7 @@ def get_cluster_id(kwargs=None, call=None): try: ret = list_clusters()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The cluster '{}' could not be found".format(name)) + raise SaltCloudSystemExit(f"The cluster '{name}' could not be found") return ret @@ -590,7 +589,7 @@ def get_datastore_id(kwargs=None, call=None): try: ret = list_datastores()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The datastore '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The datastore '{name}' could not be found.") return ret @@ -622,7 +621,7 @@ def get_host_id(kwargs=None, call=None): try: ret = avail_locations()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The host '{}' could not be found".format(name)) + raise SaltCloudSystemExit(f"The host '{name}' could not be found") return ret @@ -641,9 +640,7 @@ def get_image(vm_): for image in images: if vm_image in (images[image]["name"], images[image]["id"]): return images[image]["id"] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_image_id(kwargs=None, call=None): @@ -673,7 +670,7 @@ def get_image_id(kwargs=None, call=None): try: ret = avail_images()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The image '{}' could not be found".format(name)) + raise SaltCloudSystemExit(f"The image '{name}' could not be found") return ret @@ -697,7 +694,7 @@ def get_location(vm_): if vm_location in (locations[location]["name"], locations[location]["id"]): return locations[location]["id"] raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -728,9 +725,7 @@ def get_secgroup_id(kwargs=None, call=None): try: ret = list_security_groups()[name]["id"] except KeyError: - raise SaltCloudSystemExit( - "The security group '{}' could not be found.".format(name) - ) + raise SaltCloudSystemExit(f"The security group '{name}' could not be found.") return ret @@ -761,7 +756,7 @@ def get_template_image(kwargs=None, call=None): ret = list_templates()[name]["template"]["disk"]["image"] except KeyError: raise SaltCloudSystemExit( - "The image for template '{}' could not be found.".format(name) + f"The image for template '{name}' could not be found." ) return ret @@ -794,7 +789,7 @@ def get_template_id(kwargs=None, call=None): try: ret = list_templates()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The template '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The template '{name}' could not be found.") return ret @@ -816,7 +811,7 @@ def get_template(vm_): return list_templates()[vm_template]["id"] except KeyError: raise SaltCloudNotFound( - "The specified template, '{}', could not be found.".format(vm_template) + f"The specified template, '{vm_template}', could not be found." ) @@ -847,7 +842,7 @@ def get_vm_id(kwargs=None, call=None): try: ret = list_nodes()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The VM '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The VM '{name}' could not be found.") return ret @@ -879,7 +874,7 @@ def get_vn_id(kwargs=None, call=None): try: ret = list_vns()[name]["id"] except KeyError: - raise SaltCloudSystemExit("The VN '{}' could not be found.".format(name)) + raise SaltCloudSystemExit(f"The VN '{name}' could not be found.") return ret @@ -895,9 +890,7 @@ def _get_device_template(disk, disk_info, template=None): def _require_disk_opts(*args): for arg in args: if arg not in disk_info: - raise SaltCloudSystemExit( - "The disk {} requires a {} argument".format(disk, arg) - ) + raise SaltCloudSystemExit(f"The disk {disk} requires a {arg} argument") _require_disk_opts("disk_type", "size") @@ -919,12 +912,12 @@ def _get_device_template(disk, disk_info, template=None): if disk_type == "volatile": _require_disk_opts("type") v_type = disk_info["type"] - temp = "DISK=[TYPE={}, SIZE={}]".format(v_type, size) + temp = f"DISK=[TYPE={v_type}, SIZE={size}]" if v_type == "fs": _require_disk_opts("format") format = disk_info["format"] - temp = "DISK=[TYPE={}, SIZE={}, FORMAT={}]".format(v_type, size, format) + temp = f"DISK=[TYPE={v_type}, SIZE={size}, FORMAT={format}]" return temp # TODO add persistant disk_type @@ -1101,7 +1094,7 @@ def create(vm_): ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) if fqdn: @@ -1178,7 +1171,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], ) @@ -1192,7 +1185,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], ) @@ -4474,7 +4467,7 @@ def _get_xml(xml_str): except etree.XMLSyntaxError as err: # opennebula returned invalid XML, which could be an error message, so # log it - raise SaltCloudSystemExit("opennebula returned: {}".format(xml_str)) + raise SaltCloudSystemExit(f"opennebula returned: {xml_str}") return xml_data diff --git a/salt/cloud/clouds/openstack.py b/salt/cloud/clouds/openstack.py index 0a8b8d7e1b2..8dfbf1c341c 100644 --- a/salt/cloud/clouds/openstack.py +++ b/salt/cloud/clouds/openstack.py @@ -737,7 +737,7 @@ def create(vm_): ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_key_file '{}' does not exist".format(key_filename) + f"The defined ssh_key_file '{key_filename}' does not exist" ) vm_["key_filename"] = key_filename @@ -846,7 +846,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -863,7 +863,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/packet.py b/salt/cloud/clouds/packet.py index 1c6217bf4f7..0e1b65bed0c 100644 --- a/salt/cloud/clouds/packet.py +++ b/salt/cloud/clouds/packet.py @@ -242,9 +242,7 @@ def _wait_for_status(status_type, object_id, status=None, timeout=500, quiet=Tru manager = packet.Manager(auth_token=vm_["token"]) for i in range(0, iterations): - get_object = getattr( - manager, "get_{status_type}".format(status_type=status_type) - ) + get_object = getattr(manager, f"get_{status_type}") obj = get_object(object_id) if obj.state == status: @@ -340,7 +338,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -413,7 +411,7 @@ def create(vm_): volume = manager.create_volume( vm_["project_id"], - "{}_storage".format(name), + f"{name}_storage", vm_.get("storage_tier"), vm_.get("storage_size"), vm_.get("location"), @@ -441,7 +439,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -580,7 +578,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -606,7 +604,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/parallels.py b/salt/cloud/clouds/parallels.py index 4b65ddd9c8a..a5e6ca0fff7 100644 --- a/salt/cloud/clouds/parallels.py +++ b/salt/cloud/clouds/parallels.py @@ -310,11 +310,11 @@ def create(vm_): name = vm_["name"] if not wait_until(name, "CREATED"): - return {"Error": "Unable to start {}, command timed out".format(name)} + return {"Error": f"Unable to start {name}, command timed out"} start(vm_["name"], call="action") if not wait_until(name, "STARTED"): - return {"Error": "Unable to start {}, command timed out".format(name)} + return {"Error": f"Unable to start {name}, command timed out"} def __query_node_data(vm_name): data = show_instance(vm_name, call="action") @@ -391,7 +391,7 @@ def query(action=None, command=None, args=None, method="GET", data=None): path += action if command: - path += "/{}".format(command) + path += f"/{command}" if not type(args, dict): args = {} @@ -404,7 +404,7 @@ def query(action=None, command=None, args=None, method="GET", data=None): if args: params = urllib.parse.urlencode(args) - req = urllib.request.Request(url="{}?{}".format(path, params), **kwargs) + req = urllib.request.Request(url=f"{path}?{params}", **kwargs) else: req = urllib.request.Request(url=path, **kwargs) @@ -526,7 +526,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -536,7 +536,7 @@ def destroy(name, call=None): if node["state"] == "STARTED": stop(name, call="action") if not wait_until(name, "STOPPED"): - return {"Error": "Unable to destroy {}, command timed out".format(name)} + return {"Error": f"Unable to destroy {name}, command timed out"} data = query(action="ve", command=name, method="DELETE") @@ -546,7 +546,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -557,7 +557,7 @@ def destroy(name, call=None): name, _get_active_provider_name().split(":")[0], __opts__ ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def start(name, call=None): @@ -575,12 +575,12 @@ def start(name, call=None): "The show_instance action must be called with -a or --action." ) - data = query(action="ve", command="{}/start".format(name), method="PUT") + data = query(action="ve", command=f"{name}/start", method="PUT") if "error" in data: return data["error"] - return {"Started": "{} was started.".format(name)} + return {"Started": f"{name} was started."} def stop(name, call=None): @@ -598,9 +598,9 @@ def stop(name, call=None): "The show_instance action must be called with -a or --action." ) - data = query(action="ve", command="{}/stop".format(name), method="PUT") + data = query(action="ve", command=f"{name}/stop", method="PUT") if "error" in data: return data["error"] - return {"Stopped": "{} was stopped.".format(name)} + return {"Stopped": f"{name} was stopped."} diff --git a/salt/cloud/clouds/profitbricks.py b/salt/cloud/clouds/profitbricks.py index 72f1b362551..a8a9351a717 100644 --- a/salt/cloud/clouds/profitbricks.py +++ b/salt/cloud/clouds/profitbricks.py @@ -328,9 +328,7 @@ def get_size(vm_): combinations = (str(sizes[size]["id"]), str(size)) if vm_size and str(vm_size) in combinations: return sizes[size] - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def get_datacenter_id(): @@ -415,7 +413,7 @@ def get_datacenter(conn): return item raise SaltCloudNotFound( - "The specified datacenter '{}' could not be found.".format(datacenter_id) + f"The specified datacenter '{datacenter_id}' could not be found." ) @@ -488,9 +486,7 @@ def get_image(vm_): if vm_image and vm_image in (images[key]["id"], images[key]["name"]): return images[key] - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def list_datacenters(conn=None, call=None): @@ -725,7 +721,7 @@ def get_public_keys(vm_): key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_public_key '{}' does not exist".format(key_filename) + f"The defined ssh_public_key '{key_filename}' does not exist" ) ssh_keys = [] with salt.utils.files.fopen(key_filename) as rfh: @@ -746,7 +742,7 @@ def get_key_filename(vm_): key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined ssh_private_key '{}' does not exist".format(key_filename) + f"The defined ssh_private_key '{key_filename}' does not exist" ) return key_filename @@ -941,7 +937,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -972,7 +968,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1142,9 +1138,7 @@ def _get_data_volumes(vm_): # Verify the required 'disk_size' property is present in the cloud # profile config if "disk_size" not in volumes[key].keys(): - raise SaltCloudConfigError( - "The volume '{}' is missing 'disk_size'".format(key) - ) + raise SaltCloudConfigError(f"The volume '{key}' is missing 'disk_size'") # Use 'HDD' if no 'disk_type' property is present in cloud profile if "disk_type" not in volumes[key].keys(): volumes[key]["disk_type"] = "HDD" @@ -1187,7 +1181,7 @@ def _get_firewall_rules(firewall_rules): # profile config if "protocol" not in firewall_rules[key].keys(): raise SaltCloudConfigError( - "The firewall rule '{}' is missing 'protocol'".format(key) + f"The firewall rule '{key}' is missing 'protocol'" ) ret.append( FirewallRule( diff --git a/salt/cloud/clouds/qingcloud.py b/salt/cloud/clouds/qingcloud.py index b684f6bc9d8..5cfa8a19930 100644 --- a/salt/cloud/clouds/qingcloud.py +++ b/salt/cloud/clouds/qingcloud.py @@ -108,7 +108,7 @@ def _compute_signature(parameters, access_key_secret, method, path): """ parameters["signature_method"] = "HmacSHA256" - string_to_sign = "{}\n{}\n".format(method.upper(), path) + string_to_sign = f"{method.upper()}\n{path}\n" keys = sorted(parameters.keys()) pairs = [] @@ -166,9 +166,9 @@ def query(params=None): for sk, sv in value[i - 1].items(): if isinstance(sv, dict) or isinstance(sv, list): sv = salt.utils.json.dumps(sv, separators=(",", ":")) - real_parameters["{}.{}.{}".format(key, i, sk)] = sv + real_parameters[f"{key}.{i}.{sk}"] = sv else: - real_parameters["{}.{}".format(key, i)] = value[i - 1] + real_parameters[f"{key}.{i}"] = value[i - 1] else: real_parameters[key] = value @@ -252,7 +252,7 @@ def _get_location(vm_=None): return vm_location raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -320,9 +320,7 @@ def _get_image(vm_): if vm_image in images: return vm_image - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def show_image(kwargs, call=None): @@ -442,9 +440,7 @@ def _get_size(vm_): if vm_size in sizes.keys(): return vm_size - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def _show_normalized_node(full_node): @@ -626,7 +622,7 @@ def show_instance(instance_id, call=None, kwargs=None): if items["total_count"] == 0: raise SaltCloudNotFound( - "The specified instance, '{}', could not be found.".format(instance_id) + f"The specified instance, '{instance_id}', could not be found." ) full_node = items["instance_set"][0] @@ -878,7 +874,7 @@ def destroy(instance_id, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -894,7 +890,7 @@ def destroy(instance_id, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/saltify.py b/salt/cloud/clouds/saltify.py index 89082ddbef5..d3430935fc0 100644 --- a/salt/cloud/clouds/saltify.py +++ b/salt/cloud/clouds/saltify.py @@ -289,7 +289,7 @@ def create(vm_): if ssh_host: log.info("trying to ping %s", ssh_host) count = "n" if salt.utils.platform.is_windows() else "c" - cmd = "ping -{} 1 {}".format(count, ssh_host) + cmd = f"ping -{count} 1 {ssh_host}" good_ping = local.cmd(wol_host, "cmd.retcode", [cmd]) == 0 if good_ping: log.info("successful ping.") @@ -358,7 +358,7 @@ def _verify(vm_): log.debug("Testing SMB protocol for %s", vm_["name"]) if __utils__["smb.get_conn"](**kwargs) is False: return False - except (smbSessionError) as exc: + except smbSessionError as exc: log.error("Exception: %s", exc) return False @@ -464,7 +464,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], @@ -510,13 +510,13 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} def reboot(name, call=None): diff --git a/salt/cloud/clouds/scaleway.py b/salt/cloud/clouds/scaleway.py index 9b412181c01..d261e50360f 100644 --- a/salt/cloud/clouds/scaleway.py +++ b/salt/cloud/clouds/scaleway.py @@ -160,7 +160,7 @@ def get_image(server_): if server_image in (images[image]["name"], images[image]["id"]): return images[image]["id"] raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(server_image) + f"The specified image, '{server_image}', could not be found." ) @@ -225,7 +225,7 @@ def create(server_): if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( - "The defined key_filename '{}' does not exist".format(key_filename) + f"The defined key_filename '{key_filename}' does not exist" ) ssh_password = config.get_cloud_config_value("ssh_password", server_, __opts__) @@ -346,10 +346,10 @@ def query( ) ) - path = "{}/{}/".format(base_path, method) + path = f"{base_path}/{method}/" if server_id: - path += "{}/".format(server_id) + path += f"{server_id}/" if command: path += command @@ -439,7 +439,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -457,7 +457,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/softlayer.py b/salt/cloud/clouds/softlayer.py index 5c6892227ef..c0f282f84ed 100644 --- a/salt/cloud/clouds/softlayer.py +++ b/salt/cloud/clouds/softlayer.py @@ -269,7 +269,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -395,7 +395,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) @@ -513,7 +513,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -620,7 +620,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -633,7 +633,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/softlayer_hw.py b/salt/cloud/clouds/softlayer_hw.py index 2cfd2fbf38c..f8a92f8a8a8 100644 --- a/salt/cloud/clouds/softlayer_hw.py +++ b/salt/cloud/clouds/softlayer_hw.py @@ -241,7 +241,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), @@ -311,7 +311,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) @@ -406,7 +406,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), @@ -514,7 +514,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -535,7 +535,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/tencentcloud.py b/salt/cloud/clouds/tencentcloud.py index b2903b9380a..374f4a3247b 100644 --- a/salt/cloud/clouds/tencentcloud.py +++ b/salt/cloud/clouds/tencentcloud.py @@ -123,7 +123,7 @@ def get_provider_client(name=None): elif name == "vpc_client": client = vpc_client.VpcClient(crd, region, cpf) else: - raise SaltCloudSystemExit("Client name {} is not supported".format(name)) + raise SaltCloudSystemExit(f"Client name {name} is not supported") return client @@ -206,11 +206,11 @@ def avail_sizes(call=None): ret[typeConfig.InstanceType] = { "Zone": typeConfig.Zone, "InstanceFamily": typeConfig.InstanceFamily, - "Memory": "{}GB".format(typeConfig.Memory), - "CPU": "{}-Core".format(typeConfig.CPU), + "Memory": f"{typeConfig.Memory}GB", + "CPU": f"{typeConfig.CPU}-Core", } if typeConfig.GPU: - ret[typeConfig.InstanceType]["GPU"] = "{}-Core".format(typeConfig.GPU) + ret[typeConfig.InstanceType]["GPU"] = f"{typeConfig.GPU}-Core" return ret @@ -714,7 +714,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -730,7 +730,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -782,9 +782,7 @@ def show_image(kwargs, call=None): resp = client.DescribeImages(req) if not resp.ImageSet: - raise SaltCloudNotFound( - "The specified image '{}' could not be found.".format(image) - ) + raise SaltCloudNotFound(f"The specified image '{image}' could not be found.") ret = {} for image in resp.ImageSet: @@ -794,7 +792,7 @@ def show_image(kwargs, call=None): "ImageSource": image.ImageSource, "Platform": image.Platform, "Architecture": image.Architecture, - "ImageSize": "{}GB".format(image.ImageSize), + "ImageSize": f"{image.ImageSize}GB", "ImageState": image.ImageState, } @@ -893,7 +891,7 @@ def _get_node(name): ) time.sleep(0.5) - raise SaltCloudNotFound("Failed to get instance info {}".format(name)) + raise SaltCloudNotFound(f"Failed to get instance info {name}") def _get_nodes(): @@ -940,7 +938,7 @@ def _get_images(image_type): "ImageSource": image.ImageSource, "Platform": image.Platform, "Architecture": image.Architecture, - "ImageSize": "{}GB".format(image.ImageSize), + "ImageSize": f"{image.ImageSize}GB", } return ret @@ -958,9 +956,7 @@ def __get_image(vm_): if vm_image in images: return vm_image - raise SaltCloudNotFound( - "The specified image '{}' could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image '{vm_image}' could not be found.") def __get_size(vm_): @@ -975,9 +971,7 @@ def __get_size(vm_): if vm_size in sizes: return vm_size - raise SaltCloudNotFound( - "The specified size '{}' could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size '{vm_size}' could not be found.") def __get_securitygroups(vm_): diff --git a/salt/cloud/clouds/vagrant.py b/salt/cloud/clouds/vagrant.py index 836ea44badd..ac9119b70d9 100644 --- a/salt/cloud/clouds/vagrant.py +++ b/salt/cloud/clouds/vagrant.py @@ -256,7 +256,7 @@ def create(vm_): vm_.setdefault("ssh_port", ret["ssh_port"]) except (KeyError, TypeError): raise SaltInvocationError( - "Insufficient SSH addressing information for {}".format(name) + f"Insufficient SSH addressing information for {name}" ) log.info( @@ -300,7 +300,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], @@ -317,7 +317,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=opts["sock_dir"], transport=opts["transport"], @@ -328,11 +328,11 @@ def destroy(name, call=None): name, _get_active_provider_name().split(":")[0], opts ) - return {"Destroyed": "{} was destroyed.".format(name)} + return {"Destroyed": f"{name} was destroyed."} else: - return {"Error": "Error destroying {}".format(name)} + return {"Error": f"Error destroying {name}"} else: - return {"Error": "No response from {}. Cannot destroy.".format(name)} + return {"Error": f"No response from {name}. Cannot destroy."} # noinspection PyTypeChecker diff --git a/salt/cloud/clouds/virtualbox.py b/salt/cloud/clouds/virtualbox.py index 58b8ecd0242..0f7c169cef6 100644 --- a/salt/cloud/clouds/virtualbox.py +++ b/salt/cloud/clouds/virtualbox.py @@ -368,12 +368,12 @@ def destroy(name, call=None): """ log.info("Attempting to delete instance %s", name) if not vb_machine_exists(name): - return "{} doesn't exist and can't be deleted".format(name) + return f"{name} doesn't exist and can't be deleted" __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -384,7 +384,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index 68fa1c821ab..2a9c0563b87 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -306,7 +306,7 @@ def _add_new_hard_disk_helper( disk_spec.device.key = random_key disk_spec.device.deviceInfo = vim.Description() disk_spec.device.deviceInfo.label = disk_label - disk_spec.device.deviceInfo.summary = "{} GB".format(size_gb) + disk_spec.device.deviceInfo.summary = f"{size_gb} GB" disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() disk_spec.device.backing.thinProvisioned = thin_provision @@ -662,7 +662,7 @@ def _set_cd_or_dvd_backing_type(drive, device_type, mode, iso_path): if datastore_ref: drive.backing.datastore = datastore_ref - drive.deviceInfo.summary = "ISO {}".format(iso_path) + drive.deviceInfo.summary = f"ISO {iso_path}" elif device_type == "client_device": if mode == "passthrough": @@ -917,7 +917,7 @@ def _manage_devices(devices, vm=None, container_ref=None, new_vm_name=None): else None ) if bus_sharing and bus_sharing in ["virtual", "physical", "no"]: - bus_sharing = "{}Sharing".format(bus_sharing) + bus_sharing = f"{bus_sharing}Sharing" if bus_sharing != device.sharedBus: # Only edit the SCSI controller if bus_sharing is different scsi_spec = _edit_existing_scsi_controller( @@ -1327,7 +1327,7 @@ def _format_instance_info_select(vm, selection): if "size" in selection: cpu = defaultto(vm, "config.hardware.numCPU") ram = "{} MB".format(defaultto(vm, "config.hardware.memoryMB")) - vm_select_info["size"] = "cpu: {}\nram: {}".format(cpu, ram) + vm_select_info["size"] = f"cpu: {cpu}\nram: {ram}" vm_select_info["size_dict"] = { "cpu": cpu, "memory": ram, @@ -1454,15 +1454,21 @@ def _format_instance_info_select(vm, selection): if "storage" in selection: storage_full_info = { - "committed": int(vm["summary.storage.committed"]) - if "summary.storage.committed" in vm - else "N/A", - "uncommitted": int(vm["summary.storage.uncommitted"]) - if "summary.storage.uncommitted" in vm - else "N/A", - "unshared": int(vm["summary.storage.unshared"]) - if "summary.storage.unshared" in vm - else "N/A", + "committed": ( + int(vm["summary.storage.committed"]) + if "summary.storage.committed" in vm + else "N/A" + ), + "uncommitted": ( + int(vm["summary.storage.uncommitted"]) + if "summary.storage.uncommitted" in vm + else "N/A" + ), + "unshared": ( + int(vm["summary.storage.unshared"]) + if "summary.storage.unshared" in vm + else "N/A" + ), } vm_select_info["storage"] = storage_full_info @@ -1553,15 +1559,21 @@ def _format_instance_info(vm): ] = device.backing.fileName storage_full_info = { - "committed": int(vm["summary.storage.committed"]) - if "summary.storage.committed" in vm - else "N/A", - "uncommitted": int(vm["summary.storage.uncommitted"]) - if "summary.storage.uncommitted" in vm - else "N/A", - "unshared": int(vm["summary.storage.unshared"]) - if "summary.storage.unshared" in vm - else "N/A", + "committed": ( + int(vm["summary.storage.committed"]) + if "summary.storage.committed" in vm + else "N/A" + ), + "uncommitted": ( + int(vm["summary.storage.uncommitted"]) + if "summary.storage.uncommitted" in vm + else "N/A" + ), + "unshared": ( + int(vm["summary.storage.unshared"]) + if "summary.storage.unshared" in vm + else "N/A" + ), } file_full_info = {} @@ -1593,14 +1605,18 @@ def _format_instance_info(vm): ) vm_full_info = { "id": str(vm["name"]), - "image": "{} (Detected)".format(vm["config.guestFullName"]) - if "config.guestFullName" in vm - else "N/A", - "size": "cpu: {}\nram: {}".format(cpu, ram), + "image": ( + "{} (Detected)".format(vm["config.guestFullName"]) + if "config.guestFullName" in vm + else "N/A" + ), + "size": f"cpu: {cpu}\nram: {ram}", "size_dict": {"cpu": cpu, "memory": ram}, - "state": str(vm["summary.runtime.powerState"]) - if "summary.runtime.powerState" in vm - else "N/A", + "state": ( + str(vm["summary.runtime.powerState"]) + if "summary.runtime.powerState" in vm + else "N/A" + ), "private_ips": ip_addresses, "public_ips": [], "devices": device_full_info, @@ -1610,12 +1626,14 @@ def _format_instance_info(vm): "hostname": str(vm["object"].guest.hostName), "mac_addresses": device_mac_addresses, "networks": network_full_info, - "path": str(vm["config.files.vmPathName"]) - if "config.files.vmPathName" in vm - else "N/A", - "tools_status": str(vm["guest.toolsStatus"]) - if "guest.toolsStatus" in vm - else "N/A", + "path": ( + str(vm["config.files.vmPathName"]) + if "config.files.vmPathName" in vm + else "N/A" + ), + "tools_status": ( + str(vm["guest.toolsStatus"]) if "guest.toolsStatus" in vm else "N/A" + ), } return vm_full_info @@ -1624,7 +1642,7 @@ def _format_instance_info(vm): def _get_snapshots(snapshot_list, current_snapshot=None, parent_snapshot_path=""): snapshots = {} for snapshot in snapshot_list: - snapshot_path = "{}/{}".format(parent_snapshot_path, snapshot.name) + snapshot_path = f"{parent_snapshot_path}/{snapshot.name}" snapshots[snapshot_path] = { "name": snapshot.name, "description": snapshot.description, @@ -1759,7 +1777,7 @@ def test_vcenter_connection(kwargs=None, call=None): # Get the service instance object _get_si() except Exception as exc: # pylint: disable=broad-except - return "failed to connect: {}".format(exc) + return f"failed to connect: {exc}" return "connection successful" @@ -2004,14 +2022,18 @@ def list_nodes(kwargs=None, call=None): ) vm_info = { "id": vm["name"], - "image": "{} (Detected)".format(vm["config.guestFullName"]) - if "config.guestFullName" in vm - else "N/A", - "size": "cpu: {}\nram: {}".format(cpu, ram), + "image": ( + "{} (Detected)".format(vm["config.guestFullName"]) + if "config.guestFullName" in vm + else "N/A" + ), + "size": f"cpu: {cpu}\nram: {ram}", "size_dict": {"cpu": cpu, "memory": ram}, - "state": str(vm["summary.runtime.powerState"]) - if "summary.runtime.powerState" in vm - else "N/A", + "state": ( + str(vm["summary.runtime.powerState"]) + if "summary.runtime.powerState" in vm + else "N/A" + ), "private_ips": [vm["guest.ipAddress"]] if "guest.ipAddress" in vm else [], "public_ips": [], } @@ -2242,15 +2264,21 @@ def avail_images(call=None): if "config.template" in vm and vm["config.template"]: templates[vm["name"]] = { "name": vm["name"], - "guest_fullname": vm["config.guestFullName"] - if "config.guestFullName" in vm - else "N/A", - "cpus": vm["config.hardware.numCPU"] - if "config.hardware.numCPU" in vm - else "N/A", - "ram": vm["config.hardware.memoryMB"] - if "config.hardware.memoryMB" in vm - else "N/A", + "guest_fullname": ( + vm["config.guestFullName"] + if "config.guestFullName" in vm + else "N/A" + ), + "cpus": ( + vm["config.hardware.numCPU"] + if "config.hardware.numCPU" in vm + else "N/A" + ), + "ram": ( + vm["config.hardware.memoryMB"] + if "config.hardware.memoryMB" in vm + else "N/A" + ), } return templates @@ -2656,7 +2684,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -2702,7 +2730,7 @@ def destroy(name, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -3107,7 +3135,7 @@ def create(vm_): ) if not datastore_ref: raise SaltCloudSystemExit( - "Specified datastore: '{}' does not exist".format(datastore) + f"Specified datastore: '{datastore}' does not exist" ) if host: @@ -3123,7 +3151,7 @@ def create(vm_): # If the hardware version is specified and if it is different from the current # hardware version, then schedule a hardware version upgrade if hardware_version and object_ref is not None: - hardware_version = "vmx-{:02}".format(hardware_version) + hardware_version = f"vmx-{hardware_version:02}" if hardware_version != object_ref.config.version: log.debug( "Scheduling hardware version upgrade from %s to %s", @@ -3153,7 +3181,7 @@ def create(vm_): elif memory_unit.lower() == "gb": memory_mb = int(float(memory_num) * 1024.0) else: - err_msg = "Invalid memory type specified: '{}'".format(memory_unit) + err_msg = f"Invalid memory type specified: '{memory_unit}'" log.error(err_msg) return {"Error": err_msg} except (TypeError, ValueError): @@ -3601,7 +3629,7 @@ def rescan_hba(kwargs=None, call=None): if hba: log.info("Rescanning HBA %s on host %s", hba, host_name) host_ref.configManager.storageSystem.RescanHba(hba) - ret = "rescanned HBA {}".format(hba) + ret = f"rescanned HBA {hba}" else: log.info("Rescanning all HBAs on host %s", host_name) host_ref.configManager.storageSystem.RescanAllHba() @@ -3879,7 +3907,7 @@ def list_hbas(kwargs=None, call=None): if hba_type and hba_type not in ["parallel", "block", "iscsi", "fibre"]: raise SaltCloudSystemExit( - "Specified hba type {} currently not supported.".format(hba_type) + f"Specified hba type {hba_type} currently not supported." ) host_list = salt.utils.vmware.get_mors_with_properties( @@ -4252,10 +4280,10 @@ def revert_to_snapshot(name, kwargs=None, call=None): task = vm_ref.RevertToCurrentSnapshot(suppressPowerOn=suppress_power_on) else: log.debug("Reverting VM %s to snapshot %s", name, snapshot_name) - msg = "reverted to snapshot {}".format(snapshot_name) + msg = f"reverted to snapshot {snapshot_name}" snapshot_ref = _get_snapshot_ref_by_name(vm_ref, snapshot_name) if snapshot_ref is None: - return "specified snapshot '{}' does not exist".format(snapshot_name) + return f"specified snapshot '{snapshot_name}' does not exist" task = snapshot_ref.snapshot.Revert(suppressPowerOn=suppress_power_on) salt.utils.vmware.wait_for_task(task, name, "revert to snapshot", 5, "info") @@ -4393,7 +4421,7 @@ def convert_to_template(name, kwargs=None, call=None): vm_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.VirtualMachine, name) if vm_ref.config.template: - raise SaltCloudSystemExit("{} already a template".format(name)) + raise SaltCloudSystemExit(f"{name} already a template") try: vm_ref.MarkAsTemplate() @@ -4407,7 +4435,7 @@ def convert_to_template(name, kwargs=None, call=None): ) return "failed to convert to teamplate" - return "{} converted to template".format(name) + return f"{name} converted to template" def add_host(kwargs=None, call=None): @@ -4529,7 +4557,7 @@ def add_host(kwargs=None, call=None): ("echo", "-n"), stdout=subprocess.PIPE, stderr=subprocess.PIPE ) p2 = subprocess.Popen( - ("openssl", "s_client", "-connect", "{}:443".format(host_name)), + ("openssl", "s_client", "-connect", f"{host_name}:443"), stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -4559,12 +4587,12 @@ def add_host(kwargs=None, call=None): try: if cluster_name: task = cluster_ref.AddHost(spec=spec, asConnected=True) - ret = "added host system to cluster {}".format(cluster_name) + ret = f"added host system to cluster {cluster_name}" if datacenter_name: task = datacenter_ref.hostFolder.AddStandaloneHost( spec=spec, addConnected=True ) - ret = "added host system to datacenter {}".format(datacenter_name) + ret = f"added host system to datacenter {datacenter_name}" salt.utils.vmware.wait_for_task(task, host_name, "add host system", 5, "info") except Exception as exc: # pylint: disable=broad-except if isinstance(exc, vim.fault.SSLVerifyFault): diff --git a/salt/cloud/clouds/xen.py b/salt/cloud/clouds/xen.py index 878f74f2a7a..810ff460227 100644 --- a/salt/cloud/clouds/xen.py +++ b/salt/cloud/clouds/xen.py @@ -124,7 +124,7 @@ def _get_session(): Get a connection to the XenServer host """ api_version = "1.0" - originator = "salt_cloud_{}_driver".format(__virtualname__) + originator = f"salt_cloud_{__virtualname__}_driver" url = config.get_cloud_config_value( "url", get_configured_provider(), __opts__, search_global=False ) @@ -550,7 +550,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "starting create", - "salt/cloud/{}/creating".format(name), + f"salt/cloud/{name}/creating", args={"name": name, "profile": vm_["profile"], "provider": vm_["driver"]}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -580,7 +580,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "requesting instance", - "salt/cloud/{}/requesting".format(name), + f"salt/cloud/{name}/requesting", sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) @@ -623,7 +623,7 @@ def create(vm_): __utils__["cloud.fire_event"]( "event", "created instance", - "salt/cloud/{}/created".format(name), + f"salt/cloud/{name}/created", args={"name": name, "profile": vm_["profile"], "provider": vm_["driver"]}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -923,7 +923,7 @@ def reboot(name, call=None, session=None): _run_async_task(task, session) return show_instance(name) else: - return "{} is not running to be rebooted".format(name) + return f"{name} is not running to be rebooted" def _get_vm(name=None, session=None): @@ -984,7 +984,7 @@ def destroy(name=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1009,7 +1009,7 @@ def destroy(name=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -1134,7 +1134,7 @@ def vif_list(name, call=None, kwargs=None): x = 0 for vif in vifs: vif_record = session.xenapi.VIF.get_record(vif) - data["vif-{}".format(x)] = vif_record + data[f"vif-{x}"] = vif_record x += 1 ret[name] = data return ret @@ -1168,7 +1168,7 @@ def vbd_list(name=None, call=None): x = 0 for vbd in vbds: vbd_record = session.xenapi.VBD.get_record(vbd) - data["vbd-{}".format(x)] = vbd_record + data[f"vbd-{x}"] = vbd_record x += 1 ret = data return ret @@ -1219,7 +1219,7 @@ def destroy_vm_vdis(name=None, session=None, call=None): vdi_record = session.xenapi.VDI.get_record(vbd_record["VDI"]) if "iso" not in vdi_record["name_label"]: session.xenapi.VDI.destroy(vbd_record["VDI"]) - ret["vdi-{}".format(x)] = vdi_record["name_label"] + ret[f"vdi-{x}"] = vdi_record["name_label"] x += 1 return ret diff --git a/salt/cloud/libcloudfuncs.py b/salt/cloud/libcloudfuncs.py index cee5ea724f9..2165e3ee442 100644 --- a/salt/cloud/libcloudfuncs.py +++ b/salt/cloud/libcloudfuncs.py @@ -61,7 +61,7 @@ def check_libcloud_version(reqver=LIBCLOUD_MINIMAL_VERSION, why=None): ) ) if why: - errormsg += " for {}".format(why) + errormsg += f" for {why}" errormsg += ". Please upgrade." raise ImportError(errormsg) @@ -186,7 +186,7 @@ def get_location(conn, vm_): return img raise SaltCloudNotFound( - "The specified location, '{}', could not be found.".format(vm_location) + f"The specified location, '{vm_location}', could not be found." ) @@ -204,9 +204,7 @@ def get_image(conn, vm_): if vm_image and vm_image in (img_id, img_name): return img - raise SaltCloudNotFound( - "The specified image, '{}', could not be found.".format(vm_image) - ) + raise SaltCloudNotFound(f"The specified image, '{vm_image}', could not be found.") def get_size(conn, vm_): @@ -224,9 +222,7 @@ def get_size(conn, vm_): str(size.name), ): return size - raise SaltCloudNotFound( - "The specified size, '{}', could not be found.".format(vm_size) - ) + raise SaltCloudNotFound(f"The specified size, '{vm_size}', could not be found.") def script(vm_): @@ -257,7 +253,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroying instance", - "salt/cloud/{}/destroying".format(name), + f"salt/cloud/{name}/destroying", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -296,7 +292,7 @@ def destroy(name, conn=None, call=None): __utils__["cloud.fire_event"]( "event", "destroyed instance", - "salt/cloud/{}/destroyed".format(name), + f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], @@ -338,8 +334,8 @@ def reboot(name, conn=None): # Fire reboot action __utils__["cloud.fire_event"]( "event", - "{} has been rebooted".format(name), - "salt/cloud/{}/rebooting".format(name), + f"{name} has been rebooted", + f"salt/cloud/{name}/rebooting", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], diff --git a/salt/config/__init__.py b/salt/config/__init__.py index f39494babda..edc4cc6b5b2 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -1,6 +1,7 @@ """ All salt configuration loading and defaults should be in this module """ + import codecs import glob import logging diff --git a/salt/config/schemas/common.py b/salt/config/schemas/common.py index f8d164abfed..5c32ecf789a 100644 --- a/salt/config/schemas/common.py +++ b/salt/config/schemas/common.py @@ -8,7 +8,6 @@ Common salt configuration schemas """ - from salt.utils.schema import ArrayItem, OneOfItem, Schema, StringItem @@ -26,7 +25,7 @@ class DefaultIncludeConfig(StringItem): description = __doc__ def __init__(self, default=None, pattern=None, **kwargs): - default = "{}/*.conf".format(self.__confd_directory__) + default = f"{self.__confd_directory__}/*.conf" pattern = r"(?:.*)/\*\.conf" super().__init__(default=default, pattern=pattern, **kwargs) diff --git a/salt/config/schemas/esxcluster.py b/salt/config/schemas/esxcluster.py index 2522a4bf4e1..cc3f30da6e5 100644 --- a/salt/config/schemas/esxcluster.py +++ b/salt/config/schemas/esxcluster.py @@ -8,7 +8,6 @@ ESX Cluster configuration schemas """ - from salt.utils.schema import ( AnyOfItem, ArrayItem, diff --git a/salt/config/schemas/esxdatacenter.py b/salt/config/schemas/esxdatacenter.py index 2bb4ec0b29f..edf8b404cd4 100644 --- a/salt/config/schemas/esxdatacenter.py +++ b/salt/config/schemas/esxdatacenter.py @@ -8,7 +8,6 @@ ESX Datacenter configuration schemas """ - from salt.utils.schema import ArrayItem, IntegerItem, Schema, StringItem diff --git a/salt/config/schemas/esxi.py b/salt/config/schemas/esxi.py index 1bb03b44c34..822f382b098 100644 --- a/salt/config/schemas/esxi.py +++ b/salt/config/schemas/esxi.py @@ -8,7 +8,6 @@ ESXi host configuration schemas """ - from salt.utils.schema import ( ArrayItem, BooleanItem, diff --git a/salt/config/schemas/esxvm.py b/salt/config/schemas/esxvm.py index 5842cb0be5c..2dfdbb26ac5 100644 --- a/salt/config/schemas/esxvm.py +++ b/salt/config/schemas/esxvm.py @@ -7,7 +7,6 @@ ESX Virtual Machine configuration schemas """ - from salt.utils.schema import ( AnyOfItem, ArrayItem, diff --git a/salt/config/schemas/minion.py b/salt/config/schemas/minion.py index 9aee9fe4c0f..22fe2fdeb7f 100644 --- a/salt/config/schemas/minion.py +++ b/salt/config/schemas/minion.py @@ -7,7 +7,6 @@ Minion configuration schema """ - from salt.config.schemas.common import IncludeConfig, MinionDefaultInclude from salt.utils.schema import IPv4Item, Schema diff --git a/salt/config/schemas/ssh.py b/salt/config/schemas/ssh.py index 2db9acda5de..2123768935c 100644 --- a/salt/config/schemas/ssh.py +++ b/salt/config/schemas/ssh.py @@ -8,7 +8,6 @@ Salt SSH related configuration schemas """ - from salt.config.schemas.minion import MinionConfiguration from salt.utils.schema import ( AnyOfItem, diff --git a/salt/daemons/__init__.py b/salt/daemons/__init__.py index f044f827b44..cb3b7c99c31 100644 --- a/salt/daemons/__init__.py +++ b/salt/daemons/__init__.py @@ -140,7 +140,7 @@ def extract_masters(opts, masters="master", port=None, raise_if_empty=True): entries = opts.get(masters, []) if not entries: - emsg = "Invalid or missing opts['{}'].".format(masters) + emsg = f"Invalid or missing opts['{masters}']." log.error(emsg) if raise_if_empty: raise ValueError(emsg) diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index 07ce6122ba4..df09f0b2380 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -132,7 +132,7 @@ def clean_pub_auth(opts): if not os.path.exists(auth_cache): return else: - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk(auth_cache): + for dirpath, dirnames, filenames in salt.utils.path.os_walk(auth_cache): for auth_file in filenames: auth_file_path = os.path.join(dirpath, auth_file) if not os.path.isfile(auth_file_path): @@ -738,7 +738,7 @@ class RemoteFuncs: if not os.path.isdir(cdir): try: os.makedirs(cdir) - except os.error: + except OSError: pass if os.path.isfile(cpath) and load["loc"] != 0: mode = "ab" diff --git a/salt/defaults/__init__.py b/salt/defaults/__init__.py index 35bdf162a02..5ebdb694a58 100644 --- a/salt/defaults/__init__.py +++ b/salt/defaults/__init__.py @@ -45,8 +45,8 @@ class _Constant: def __repr__(self): if self.value: - return "".format(self.name, self.value) - return "".format(self.name) + return f"" + return f"" # Default delimiter for multi-level traversal in targeting diff --git a/salt/engines/__init__.py b/salt/engines/__init__.py index edd4a178225..11baafb2b86 100644 --- a/salt/engines/__init__.py +++ b/salt/engines/__init__.py @@ -2,6 +2,7 @@ Initialize the engines system. This plugin system allows for complex services to be encapsulated within the salt plugin environment """ + import logging import salt @@ -47,13 +48,13 @@ def start_engines(opts, proc_mgr, proxy=None): engine_name = engine del engine_opts["engine_module"] else: - fun = "{}.start".format(engine) + fun = f"{engine}.start" if fun in engines: start_func = engines[fun] if engine_name: - name = "Engine({}, name={})".format(start_func.__module__, engine_name) + name = f"Engine({start_func.__module__}, name={engine_name})" else: - name = "Engine({})".format(start_func.__module__) + name = f"Engine({start_func.__module__})" log.info("Starting %s", name) proc_mgr.add_process( Engine, diff --git a/salt/engines/docker_events.py b/salt/engines/docker_events.py index 024b75597cf..3bcabedc8ba 100644 --- a/salt/engines/docker_events.py +++ b/salt/engines/docker_events.py @@ -2,6 +2,7 @@ Send events from Docker events :Depends: Docker API >= 1.22 """ + import logging import traceback diff --git a/salt/engines/ircbot.py b/salt/engines/ircbot.py index 3e134c4e8b9..fc1241bc85b 100644 --- a/salt/engines/ircbot.py +++ b/salt/engines/ircbot.py @@ -173,16 +173,16 @@ class IRCClient: event.source, nick, user, host, event.code, channel, command, line ) if (self._allow_nick(nick) or self._allow_host(host)) and hasattr( - self, "_command_{}".format(command) + self, f"_command_{command}" ): - getattr(self, "_command_{}".format(command))(privevent) + getattr(self, f"_command_{command}")(privevent) def _command_echo(self, event): - message = "PRIVMSG {} :{}".format(event.channel, event.line) + message = f"PRIVMSG {event.channel} :{event.line}" self.send_message(message) def _command_ping(self, event): - message = "PRIVMSG {} :{}: pong".format(event.channel, event.nick) + message = f"PRIVMSG {event.channel} :{event.nick}: pong" self.send_message(message) def _command_event(self, event): @@ -210,7 +210,7 @@ class IRCClient: payload = {"data": []} fire("salt/engines/ircbot/" + tag, payload) - message = "PRIVMSG {} :{}: TaDa!".format(event.channel, event.nick) + message = f"PRIVMSG {event.channel} :{event.nick}: TaDa!" self.send_message(message) def _message(self, raw): @@ -219,7 +219,7 @@ class IRCClient: if event.code == "PING": tornado.ioloop.IOLoop.current().spawn_callback( - self.send_message, "PONG {}".format(event.line) + self.send_message, f"PONG {event.line}" ) elif event.code == "PRIVMSG": tornado.ioloop.IOLoop.current().spawn_callback(self._privmsg, event) @@ -228,13 +228,13 @@ class IRCClient: def join_channel(self, channel): if not channel.startswith("#"): channel = "#" + channel - self.send_message("JOIN {}".format(channel)) + self.send_message(f"JOIN {channel}") def on_connect(self): logging.info("on_connect") if self.sasl is True: self.send_message("CAP REQ :sasl") - self.send_message("NICK {}".format(self.nick)) + self.send_message(f"NICK {self.nick}") self.send_message("USER saltstack 0 * :saltstack") if self.password: if self.sasl is True: @@ -242,7 +242,7 @@ class IRCClient: "{0}\x00{0}\x00{1}".format(self.username, self.password).encode() ) self.send_message("AUTHENTICATE PLAIN") - self.send_message("AUTHENTICATE {}".format(authstring)) + self.send_message(f"AUTHENTICATE {authstring}") self.send_message("CAP END") else: self.send_message( diff --git a/salt/engines/libvirt_events.py b/salt/engines/libvirt_events.py index 3b77515f408..f09a298dc47 100644 --- a/salt/engines/libvirt_events.py +++ b/salt/engines/libvirt_events.py @@ -189,7 +189,7 @@ def _get_domain_event_detail(event, detail): if event_name == "unknown": return event_name, "unknown" - prefix = "VIR_DOMAIN_EVENT_{}_".format(event_name.upper()) + prefix = f"VIR_DOMAIN_EVENT_{event_name.upper()}_" detail_name = _get_libvirt_enum_string(prefix, detail) return event_name, detail_name @@ -333,9 +333,7 @@ def _domain_event_graphics_cb( transform address structure into event data piece """ return { - "family": _get_libvirt_enum_string( - "{}_ADDRESS_".format(prefix), addr["family"] - ), + "family": _get_libvirt_enum_string(f"{prefix}_ADDRESS_", addr["family"]), "node": addr["node"], "service": addr["service"], } @@ -680,14 +678,14 @@ def _register_callback(cnx, tag_prefix, obj, event, real_id): """ libvirt_name = real_id if real_id is None: - libvirt_name = "VIR_{}_EVENT_ID_{}".format(obj, event).upper() + libvirt_name = f"VIR_{obj}_EVENT_ID_{event}".upper() if not hasattr(libvirt, libvirt_name): log.warning('Skipping "%s/%s" events: libvirt too old', obj, event) return None libvirt_id = getattr(libvirt, libvirt_name) - callback_name = "_{}_event_{}_cb".format(obj, event) + callback_name = f"_{obj}_event_{event}_cb" callback = globals().get(callback_name, None) if callback is None: log.error("Missing function %s in engine", callback_name) diff --git a/salt/engines/napalm_syslog.py b/salt/engines/napalm_syslog.py index 3956a2836fd..e64f3c6b54b 100644 --- a/salt/engines/napalm_syslog.py +++ b/salt/engines/napalm_syslog.py @@ -209,7 +209,7 @@ def _zmq(address, port, **kwargs): socket = context.socket(zmq.SUB) if salt.utils.network.is_ipv6(address): socket.ipv6 = True - socket.connect("tcp://{addr}:{port}".format(addr=address, port=port)) + socket.connect(f"tcp://{address}:{port}") socket.setsockopt(zmq.SUBSCRIBE, b"") return socket.recv diff --git a/salt/engines/script.py b/salt/engines/script.py index 67277b14d5f..7b0e750d449 100644 --- a/salt/engines/script.py +++ b/salt/engines/script.py @@ -59,7 +59,7 @@ def _get_serializer(output): return getattr(serializers, output) except AttributeError: raise CommandExecutionError( - "Unknown serializer `{}` found for output option".format(output) + f"Unknown serializer `{output}` found for output option" ) diff --git a/salt/engines/slack.py b/salt/engines/slack.py index 65009619a17..cf8bef74d13 100644 --- a/salt/engines/slack.py +++ b/salt/engines/slack.py @@ -800,9 +800,9 @@ class SlackClient: channel = self.sc.server.channels.find(msg["channel"]) jid = self.run_command_async(msg) log.debug("Submitted a job and got jid: %s", jid) - outstanding[ - jid - ] = msg # record so we can return messages to the caller + outstanding[jid] = ( + msg # record so we can return messages to the caller + ) channel.send_message( "@{}'s job is submitted as salt jid {}".format( msg["user_name"], jid @@ -855,7 +855,6 @@ class SlackClient: del outstanding[jid] def run_command_async(self, msg): - """ :type message_generator: generator of dict :param message_generator: Generates messages from slack that should be run diff --git a/salt/engines/slack_bolt_engine.py b/salt/engines/slack_bolt_engine.py index 75eb0909e48..954ef79f556 100644 --- a/salt/engines/slack_bolt_engine.py +++ b/salt/engines/slack_bolt_engine.py @@ -913,9 +913,9 @@ class SlackClient: if control and (len(msg) > 1) and msg.get("cmdline"): jid = self.run_command_async(msg) log.debug("Submitted a job and got jid: %s", jid) - outstanding[ - jid - ] = msg # record so we can return messages to the caller + outstanding[jid] = ( + msg # record so we can return messages to the caller + ) text_msg = "@{}'s job is submitted as salt jid {}".format( msg["user_name"], jid ) @@ -969,7 +969,6 @@ class SlackClient: del outstanding[jid] def run_command_async(self, msg): - """ :type msg: dict :param msg: The message dictionary that contains the command and all information. diff --git a/salt/exceptions.py b/salt/exceptions.py index e351584bc03..57a6175de2d 100644 --- a/salt/exceptions.py +++ b/salt/exceptions.py @@ -284,7 +284,7 @@ class SaltRenderError(SaltException): self.buffer = buf self.context = "" if trace: - exc_str += "\n{}\n".format(trace) + exc_str += f"\n{trace}\n" if self.line_num and self.buffer: # Avoid circular import import salt.utils.templates diff --git a/salt/executors/sudo.py b/salt/executors/sudo.py index 4d5a2fd71aa..799e77f5486 100644 --- a/salt/executors/sudo.py +++ b/salt/executors/sudo.py @@ -64,7 +64,7 @@ def execute(opts, data, func, args, kwargs): for arg in args: cmd.append(shlex.quote(str(arg))) for key in kwargs: - cmd.append(shlex.quote("{}={}".format(key, kwargs[key]))) + cmd.append(shlex.quote(f"{key}={kwargs[key]}")) cmd_ret = __salt__["cmd.run_all"](cmd, use_vt=True, python_shell=False) diff --git a/salt/features.py b/salt/features.py index 4335c46ca5a..51761c24fcb 100644 --- a/salt/features.py +++ b/salt/features.py @@ -1,6 +1,7 @@ """ Feature flags """ + import logging log = logging.getLogger(__name__) diff --git a/salt/fileclient.py b/salt/fileclient.py index 317d0c6607f..fb27cedecab 100644 --- a/salt/fileclient.py +++ b/salt/fileclient.py @@ -1,6 +1,7 @@ """ Classes that manage file clients """ + import contextlib import errno import ftplib # nosec diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py index 89f1fd70460..fe4b3b8e496 100644 --- a/salt/fileserver/__init__.py +++ b/salt/fileserver/__init__.py @@ -2,7 +2,6 @@ File server pluggable modules and generic backend functions """ - import errno import fnmatch import logging diff --git a/salt/fileserver/gitfs.py b/salt/fileserver/gitfs.py index 968e2c9ebfe..3f947d2384c 100644 --- a/salt/fileserver/gitfs.py +++ b/salt/fileserver/gitfs.py @@ -47,7 +47,6 @@ Walkthrough `. .. _GitPython: https://github.com/gitpython-developers/GitPython """ - import logging import salt.utils.gitfs diff --git a/salt/fileserver/hgfs.py b/salt/fileserver/hgfs.py index 947380b106a..48d17557886 100644 --- a/salt/fileserver/hgfs.py +++ b/salt/fileserver/hgfs.py @@ -858,7 +858,7 @@ def _file_lists(load, form): if not os.path.isdir(list_cachedir): try: os.makedirs(list_cachedir) - except os.error: + except OSError: log.critical("Unable to make cachedir %s", list_cachedir) return [] list_cache = os.path.join(list_cachedir, "{}.p".format(load["saltenv"])) diff --git a/salt/fileserver/minionfs.py b/salt/fileserver/minionfs.py index 02b1b59eeab..0cc77994fc2 100644 --- a/salt/fileserver/minionfs.py +++ b/salt/fileserver/minionfs.py @@ -150,7 +150,7 @@ def update(): salt.fileserver.reap_fileserver_cache_dir( os.path.join(__opts__["cachedir"], "minionfs/hash"), find_file ) - except os.error: + except OSError: # Hash file won't exist if no files have yet been served up pass @@ -204,7 +204,7 @@ def file_hash(load, fnd): ret["hsum"] = hsum return ret # Can't use Python select() because we need Windows support - except os.error: + except OSError: log.debug("Fileserver encountered lock when reading cache file. Retrying.") file_hash(load, fnd) return ret diff --git a/salt/fileserver/roots.py b/salt/fileserver/roots.py index e2ea92029c3..91536d737ce 100644 --- a/salt/fileserver/roots.py +++ b/salt/fileserver/roots.py @@ -289,10 +289,7 @@ def file_hash(load, fnd): # check if mtime changed ret["hsum"] = hsum return ret - except ( - os.error, - OSError, - ): # Can't use Python select() because we need Windows support + except OSError: # Can't use Python select() because we need Windows support log.debug("Fileserver encountered lock when reading cache file. Retrying.") # Delete the file since its incomplete (either corrupted or incomplete) try: diff --git a/salt/fileserver/s3fs.py b/salt/fileserver/s3fs.py index d013ea3b193..520c3d53635 100644 --- a/salt/fileserver/s3fs.py +++ b/salt/fileserver/s3fs.py @@ -87,7 +87,6 @@ structure:: s3.s3_sync_on_update: False """ - import datetime import logging import os diff --git a/salt/fileserver/svnfs.py b/salt/fileserver/svnfs.py index 82f1541fe8d..8e13ec99353 100644 --- a/salt/fileserver/svnfs.py +++ b/salt/fileserver/svnfs.py @@ -30,7 +30,6 @@ This backend assumes a standard svn layout with directories for ``branches``, :conf_master:`documentation ` for more information. """ - import copy import errno import fnmatch @@ -721,7 +720,7 @@ def _file_lists(load, form): if not os.path.isdir(list_cachedir): try: os.makedirs(list_cachedir) - except os.error: + except OSError: log.critical("Unable to make cachedir %s", list_cachedir) return [] list_cache = os.path.join(list_cachedir, "{}.p".format(load["saltenv"])) diff --git a/salt/grains/cimc.py b/salt/grains/cimc.py index 72b89d931bb..30032159294 100644 --- a/salt/grains/cimc.py +++ b/salt/grains/cimc.py @@ -3,7 +3,6 @@ Generate baseline proxy minion grains for cimc hosts. """ - import logging import salt.proxy.cimc diff --git a/salt/grains/core.py b/salt/grains/core.py index 1a701f2f53d..728a5b1494a 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -2380,10 +2380,10 @@ def _legacy_linux_distribution_data(grains, os_release, lsb_has_error): "Please report this, as it is likely a bug." ) else: - grains[ - "osrelease" - ] = "{majorversion}.{minorversion}-{buildnumber}".format( - **synoinfo + grains["osrelease"] = ( + "{majorversion}.{minorversion}-{buildnumber}".format( + **synoinfo + ) ) log.trace( @@ -2871,14 +2871,16 @@ def fqdns(): opt = {"fqdns": []} if __opts__.get( "enable_fqdns_grains", - False - if salt.utils.platform.is_windows() - or salt.utils.platform.is_proxy() - or salt.utils.platform.is_sunos() - or salt.utils.platform.is_aix() - or salt.utils.platform.is_junos() - or salt.utils.platform.is_darwin() - else True, + ( + False + if salt.utils.platform.is_windows() + or salt.utils.platform.is_proxy() + or salt.utils.platform.is_sunos() + or salt.utils.platform.is_aix() + or salt.utils.platform.is_junos() + or salt.utils.platform.is_darwin() + else True + ), ): opt = __salt__["network.fqdns"]() return opt @@ -3309,7 +3311,7 @@ def _hw_data(osdata): # of information. With that said, consolidate the output from various # commands and attempt various lookups. data = "" - for (cmd, args) in ( + for cmd, args in ( ("/usr/sbin/prtdiag", "-v"), ("/usr/sbin/prtconf", "-vp"), ("/usr/sbin/virtinfo", "-a"), diff --git a/salt/grains/disks.py b/salt/grains/disks.py index 1dfbeb737bb..f61ad6d6b34 100644 --- a/salt/grains/disks.py +++ b/salt/grains/disks.py @@ -91,14 +91,14 @@ def _freebsd_geom(): geom = salt.utils.path.which("geom") ret = {"disks": {}, "ssds": []} - devices = __salt__["cmd.run"]("{} disk list".format(geom)) + devices = __salt__["cmd.run"](f"{geom} disk list") devices = devices.split("\n\n") def parse_geom_attribs(device): tmp = {} for line in device.split("\n"): for attrib in _geom_attribs: - search = re.search(r"{}:\s(.*)".format(attrib), line) + search = re.search(rf"{attrib}:\s(.*)", line) if search: value = _datavalue( _geomconsts._datatypes.get(attrib), search.group(1) @@ -174,7 +174,7 @@ def _windows_disks(): info = line.split() if len(info) != 2 or not info[0].isdigit() or not info[1].isdigit(): continue - device = r"\\.\PhysicalDrive{}".format(info[0]) + device = rf"\\.\PhysicalDrive{info[0]}" mediatype = info[1] if mediatype == "3": log.trace("Device %s reports itself as an HDD", device) diff --git a/salt/grains/esxi.py b/salt/grains/esxi.py index 57041db8283..e9b40e73c22 100644 --- a/salt/grains/esxi.py +++ b/salt/grains/esxi.py @@ -13,7 +13,6 @@ Generate baseline proxy minion grains for ESXi hosts. """ - import logging import salt.utils.proxy diff --git a/salt/grains/junos.py b/salt/grains/junos.py index a24e39dade4..0dfd3344ff2 100644 --- a/salt/grains/junos.py +++ b/salt/grains/junos.py @@ -5,7 +5,6 @@ via salt-proxy-minion. Thus, some grains make sense to get them from the minion (PYTHONPATH), but others don't (ip_interfaces) """ - import logging import salt.utils.platform diff --git a/salt/grains/lvm.py b/salt/grains/lvm.py index 586b187ddb9..bb08de96e8b 100644 --- a/salt/grains/lvm.py +++ b/salt/grains/lvm.py @@ -33,14 +33,12 @@ def _linux_lvm(): ret = {} cmd = salt.utils.path.which("lvm") if cmd: - vgs = __salt__["cmd.run_all"]("{} vgs -o vg_name --noheadings".format(cmd)) + vgs = __salt__["cmd.run_all"](f"{cmd} vgs -o vg_name --noheadings") for vg in vgs["stdout"].splitlines(): vg = vg.strip() ret[vg] = [] - lvs = __salt__["cmd.run_all"]( - "{} lvs -o lv_name --noheadings {}".format(cmd, vg) - ) + lvs = __salt__["cmd.run_all"](f"{cmd} lvs -o lv_name --noheadings {vg}") for lv in lvs["stdout"].splitlines(): ret[vg].append(lv.strip()) @@ -52,11 +50,11 @@ def _linux_lvm(): def _aix_lvm(): ret = {} cmd = salt.utils.path.which("lsvg") - vgs = __salt__["cmd.run"]("{}".format(cmd)) + vgs = __salt__["cmd.run"](f"{cmd}") for vg in vgs.splitlines(): ret[vg] = [] - lvs = __salt__["cmd.run"]("{} -l {}".format(cmd, vg)) + lvs = __salt__["cmd.run"](f"{cmd} -l {vg}") for lvline in lvs.splitlines()[2:]: lv = lvline.split(" ", 1)[0] ret[vg].append(lv) diff --git a/salt/grains/minion_process.py b/salt/grains/minion_process.py index 54c0b61eb07..9a8dd420f0a 100644 --- a/salt/grains/minion_process.py +++ b/salt/grains/minion_process.py @@ -2,7 +2,6 @@ Set grains describing the minion process. """ - import os import salt.utils.platform diff --git a/salt/grains/napalm.py b/salt/grains/napalm.py index d36eb0273ab..5fca987e132 100644 --- a/salt/grains/napalm.py +++ b/salt/grains/napalm.py @@ -15,7 +15,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging import salt.utils.dns diff --git a/salt/grains/package.py b/salt/grains/package.py index c60a9fbb8d8..6d1963aea95 100644 --- a/salt/grains/package.py +++ b/salt/grains/package.py @@ -3,6 +3,7 @@ Grains for detecting what type of package Salt is using .. versionadded:: 3007.0 """ + import logging import salt.utils.package diff --git a/salt/grains/panos.py b/salt/grains/panos.py index 60d0e52b71e..f5ba8d731de 100644 --- a/salt/grains/panos.py +++ b/salt/grains/panos.py @@ -3,7 +3,6 @@ Generate baseline proxy minion grains for panos hosts. """ - import logging import salt.proxy.panos diff --git a/salt/grains/pending_reboot.py b/salt/grains/pending_reboot.py index dddba83fb6f..c83aecaf7ed 100644 --- a/salt/grains/pending_reboot.py +++ b/salt/grains/pending_reboot.py @@ -3,6 +3,7 @@ Grain that indicates the system is pending a reboot See functions in salt.utils.win_system to see what conditions would indicate a reboot is pending """ + import logging import salt.utils.platform diff --git a/salt/loader/context.py b/salt/loader/context.py index 560b05a8d2b..88a6472a8f3 100644 --- a/salt/loader/context.py +++ b/salt/loader/context.py @@ -1,6 +1,7 @@ """ Manage the context a module loaded by Salt's loader """ + import collections.abc import contextlib import copy diff --git a/salt/loader/dunder.py b/salt/loader/dunder.py index f0235d19a29..d3027098b5a 100644 --- a/salt/loader/dunder.py +++ b/salt/loader/dunder.py @@ -1,6 +1,7 @@ """ Salt dunders. """ + import salt.loader.context loader_context = salt.loader.context.LoaderContext() diff --git a/salt/loader/lazy.py b/salt/loader/lazy.py index 97fd3085573..3e6ad9ffa7c 100644 --- a/salt/loader/lazy.py +++ b/salt/loader/lazy.py @@ -315,7 +315,7 @@ class LazyLoader(salt.utils.lazy.LazyDict): # A list to determine precedence of extensions # Prefer packages (directories) over modules (single files)! self.suffix_order = [""] - for (suffix, mode, kind) in SUFFIXES: + for suffix, mode, kind in SUFFIXES: self.suffix_map[suffix] = (suffix, mode, kind) self.suffix_order.append(suffix) diff --git a/salt/log_handlers/fluent_mod.py b/salt/log_handlers/fluent_mod.py index 1086a926158..a23544ff871 100644 --- a/salt/log_handlers/fluent_mod.py +++ b/salt/log_handlers/fluent_mod.py @@ -181,7 +181,7 @@ class MessageFormatter(logging.Formatter): self.tags = tags self.msg_path = msg_path if msg_path else payload_type self.msg_type = msg_type if msg_type else payload_type - format_func = "format_{}_v{}".format(payload_type, version).replace(".", "_") + format_func = f"format_{payload_type}_v{version}".replace(".", "_") self.format = getattr(self, format_func) super().__init__(fmt=None, datefmt=None) @@ -236,7 +236,7 @@ class MessageFormatter(logging.Formatter): val = value else: val = repr(value) - message_dict.update({"{}".format(key): val}) + message_dict.update({f"{key}": val}) return message_dict def format_gelf_v1_1(self, record): @@ -286,7 +286,7 @@ class MessageFormatter(logging.Formatter): else: val = repr(value) # GELF spec require "non-standard" fields to be prefixed with '_' (underscore). - message_dict.update({"_{}".format(key): val}) + message_dict.update({f"_{key}": val}) return message_dict @@ -308,7 +308,7 @@ class MessageFormatter(logging.Formatter): "processName": record.processName, }, "@message": record.getMessage(), - "@source": "{}://{}/{}".format(self.msg_type, host, self.msg_path), + "@source": f"{self.msg_type}://{host}/{self.msg_path}", "@source_host": host, "@source_path": self.msg_path, "@tags": self.tags, diff --git a/salt/log_handlers/logstash_mod.py b/salt/log_handlers/logstash_mod.py index 1d69cfc8945..b3e30f83a99 100644 --- a/salt/log_handlers/logstash_mod.py +++ b/salt/log_handlers/logstash_mod.py @@ -154,7 +154,6 @@ """ - import datetime import logging import logging.handlers @@ -266,7 +265,7 @@ class LogstashFormatter(logging.Formatter): self.msg_path = msg_path self.msg_type = msg_type self.version = version - self.format = getattr(self, "format_v{}".format(version)) + self.format = getattr(self, f"format_v{version}") super().__init__(fmt=None, datefmt=None) def formatTime(self, record, datefmt=None): @@ -287,7 +286,7 @@ class LogstashFormatter(logging.Formatter): "processName": record.processName, }, "@message": record.getMessage(), - "@source": "{}://{}/{}".format(self.msg_type, host, self.msg_path), + "@source": f"{self.msg_type}://{host}/{self.msg_path}", "@source_host": host, "@source_path": self.msg_path, "@tags": ["salt"], diff --git a/salt/log_handlers/sentry_mod.py b/salt/log_handlers/sentry_mod.py index c3a6209b1f1..a12366f9fcb 100644 --- a/salt/log_handlers/sentry_mod.py +++ b/salt/log_handlers/sentry_mod.py @@ -140,7 +140,7 @@ def setup_handlers(): transport_registry = TransportRegistry(default_transports) url = urlparse(dsn) if not transport_registry.supported_scheme(url.scheme): - raise ValueError("Unsupported Sentry DSN scheme: {}".format(url.scheme)) + raise ValueError(f"Unsupported Sentry DSN scheme: {url.scheme}") except ValueError as exc: log.info("Raven failed to parse the configuration provided DSN: %s", exc) diff --git a/salt/master.py b/salt/master.py index 6bf7ca68fe0..516bdd5bf84 100644 --- a/salt/master.py +++ b/salt/master.py @@ -2,6 +2,7 @@ This module contains all of the routines needed to set up a master server, this involves preparing the three listeners and the workers needed by the master. """ + import asyncio import collections import copy @@ -181,16 +182,16 @@ class SMaster: if use_lock: with cls.secrets["cluster_aes"]["secret"].get_lock(): - cls.secrets["cluster_aes"][ - "secret" - ].value = salt.utils.stringutils.to_bytes( - cls.secrets["cluster_aes"]["reload"](remove=owner) + cls.secrets["cluster_aes"]["secret"].value = ( + salt.utils.stringutils.to_bytes( + cls.secrets["cluster_aes"]["reload"](remove=owner) + ) ) else: - cls.secrets["cluster_aes"][ - "secret" - ].value = salt.utils.stringutils.to_bytes( - cls.secrets["cluster_aes"]["reload"](remove=owner) + cls.secrets["cluster_aes"]["secret"].value = ( + salt.utils.stringutils.to_bytes( + cls.secrets["cluster_aes"]["reload"](remove=owner) + ) ) if event: @@ -363,7 +364,7 @@ class Maintenance(salt.utils.process.SignalHandlingProcess): log.error("Found dropfile with incorrect permissions, ignoring...") if to_rotate: os.remove(dfn) - except os.error: + except OSError: pass # There is no need to check key against publish_session if we're @@ -373,7 +374,7 @@ class Maintenance(salt.utils.process.SignalHandlingProcess): keyfile = os.path.join(self.opts["cluster_pki_dir"], ".aes") try: stats = os.stat(keyfile) - except os.error as exc: + except OSError as exc: log.error("Unexpected condition while reading keyfile %s", exc) return if now - stats.st_mtime >= self.opts["publish_session"]: @@ -1042,7 +1043,7 @@ class ReqServer(salt.utils.process.SignalHandlingProcess): # Cannot delete read-only files on Windows. os.chmod(dfn, stat.S_IRUSR | stat.S_IWUSR) os.remove(dfn) - except os.error: + except OSError: pass # Wait for kill should be less then parent's ProcessManager. @@ -1735,7 +1736,7 @@ class AESFuncs(TransportMethods): if not os.path.isdir(cdir): try: os.makedirs(cdir) - except os.error: + except OSError: pass if os.path.isfile(cpath) and load["loc"] != 0: mode = "ab" diff --git a/salt/matchers/compound_match.py b/salt/matchers/compound_match.py index 2bce58f117a..04da7281e3e 100644 --- a/salt/matchers/compound_match.py +++ b/salt/matchers/compound_match.py @@ -111,7 +111,7 @@ def match(tgt, opts=None, minion_id=None): results.append( str( - __context__["matchers"]["{}_match.match".format(engine)]( + __context__["matchers"][f"{engine}_match.match"]( *engine_args, **engine_kwargs ) ) diff --git a/salt/matchers/confirm_top.py b/salt/matchers/confirm_top.py index 7435f4ae94d..09a11ff428d 100644 --- a/salt/matchers/confirm_top.py +++ b/salt/matchers/confirm_top.py @@ -3,6 +3,7 @@ The matcher subsystem needs a function called "confirm_top", which takes the data passed to a top file environment and determines if that data matches this minion. """ + import logging import salt.loader diff --git a/salt/matchers/ipcidr_match.py b/salt/matchers/ipcidr_match.py index 175dade0024..8cfbf4d3332 100644 --- a/salt/matchers/ipcidr_match.py +++ b/salt/matchers/ipcidr_match.py @@ -27,7 +27,7 @@ def match(tgt, opts=None, minion_id=None): except: # pylint: disable=bare-except log.error("Invalid IP/CIDR target: %s", tgt) return [] - proto = "ipv{}".format(tgt.version) + proto = f"ipv{tgt.version}" grains = opts["grains"] diff --git a/salt/matchers/list_match.py b/salt/matchers/list_match.py index 5b790666ee3..91520cbb13d 100644 --- a/salt/matchers/list_match.py +++ b/salt/matchers/list_match.py @@ -19,7 +19,7 @@ def match(tgt, opts=None, minion_id=None): try: if ( - ",{},".format(minion_id) in tgt + f",{minion_id}," in tgt or tgt.startswith(minion_id + ",") or tgt.endswith("," + minion_id) ): diff --git a/salt/metaproxy/deltaproxy.py b/salt/metaproxy/deltaproxy.py index fdf80491ed2..50bdaa0b3c3 100644 --- a/salt/metaproxy/deltaproxy.py +++ b/salt/metaproxy/deltaproxy.py @@ -371,10 +371,10 @@ def post_master_init(self, master): self.deltaproxy_objs[minion_id] = sub_proxy_data["proxy_minion"] if self.deltaproxy_opts[minion_id] and self.deltaproxy_objs[minion_id]: - self.deltaproxy_objs[ - minion_id - ].req_channel = salt.channel.client.AsyncReqChannel.factory( - sub_proxy_data["proxy_opts"], io_loop=self.io_loop + self.deltaproxy_objs[minion_id].req_channel = ( + salt.channel.client.AsyncReqChannel.factory( + sub_proxy_data["proxy_opts"], io_loop=self.io_loop + ) ) else: log.debug("Initiating non-parallel startup for proxies") @@ -398,10 +398,10 @@ def post_master_init(self, master): self.deltaproxy_objs[minion_id] = sub_proxy_data["proxy_minion"] if self.deltaproxy_opts[minion_id] and self.deltaproxy_objs[minion_id]: - self.deltaproxy_objs[ - minion_id - ].req_channel = salt.channel.client.AsyncReqChannel.factory( - sub_proxy_data["proxy_opts"], io_loop=self.io_loop + self.deltaproxy_objs[minion_id].req_channel = ( + salt.channel.client.AsyncReqChannel.factory( + sub_proxy_data["proxy_opts"], io_loop=self.io_loop + ) ) if _failed: diff --git a/salt/minion.py b/salt/minion.py index 729053ed402..4246bdfdee8 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1,6 +1,7 @@ """ Routines to set up a minion """ + import asyncio import binascii import contextlib diff --git a/salt/modules/aix_group.py b/salt/modules/aix_group.py index ddbb452fcbf..b1e5f092e79 100644 --- a/salt/modules/aix_group.py +++ b/salt/modules/aix_group.py @@ -48,7 +48,7 @@ def add(name, gid=None, system=False, root=None, **kwargs): cmd += "-a " if gid: - cmd += "id={} ".format(gid) + cmd += f"id={gid} " cmd += name @@ -67,7 +67,7 @@ def delete(name): salt '*' group.delete foo """ - ret = __salt__["cmd.run_all"]("rmgroup {}".format(name), python_shell=False) + ret = __salt__["cmd.run_all"](f"rmgroup {name}", python_shell=False) return not ret["retcode"] @@ -129,7 +129,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) if gid == pre_gid: return True - cmd = "chgroup id={} {}".format(gid, name) + cmd = f"chgroup id={gid} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_gid = __salt__["file.group_to_gid"](name) if post_gid != pre_gid: @@ -150,7 +150,7 @@ def adduser(name, username, root=None): Verifies if a valid username 'bar' as a member of an existing group 'foo', if not then adds it. """ - cmd = "chgrpmem -m + {} {}".format(username, name) + cmd = f"chgrpmem -m + {username} {name}" retcode = __salt__["cmd.retcode"](cmd, python_shell=False) @@ -173,7 +173,7 @@ def deluser(name, username, root=None): grp_info = __salt__["group.info"](name) try: if username in grp_info["members"]: - cmd = "chgrpmem -m - {} {}".format(username, name) + cmd = f"chgrpmem -m - {username} {name}" ret = __salt__["cmd.run"](cmd, python_shell=False) return not ret["retcode"] else: @@ -195,7 +195,7 @@ def members(name, members_list, root=None): Replaces a membership list for a local group 'foo'. foo:x:1234:user1,user2,user3,... """ - cmd = "chgrpmem -m = {} {}".format(members_list, name) + cmd = f"chgrpmem -m = {members_list} {name}" retcode = __salt__["cmd.retcode"](cmd, python_shell=False) return not retcode diff --git a/salt/modules/aix_shadow.py b/salt/modules/aix_shadow.py index aa7471cb026..e58f93180fe 100644 --- a/salt/modules/aix_shadow.py +++ b/salt/modules/aix_shadow.py @@ -6,7 +6,6 @@ Manage account locks on AIX systems :depends: none """ - # Import python librarie import logging @@ -30,7 +29,6 @@ def __virtual__(): def login_failures(user): - """ Query for all accounts which have 3 or more login failures. @@ -41,7 +39,7 @@ def login_failures(user): salt shadow.login_failures ALL """ - cmd = "lsuser -a unsuccessful_login_count {}".format(user) + cmd = f"lsuser -a unsuccessful_login_count {user}" cmd += " | grep -E 'unsuccessful_login_count=([3-9]|[0-9][0-9]+)'" out = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=True) @@ -65,7 +63,7 @@ def locked(user): salt shadow.locked ALL """ - cmd = "lsuser -a account_locked {}".format(user) + cmd = f"lsuser -a account_locked {user}" cmd += ' | grep "account_locked=true"' out = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=True) diff --git a/salt/modules/aixpkg.py b/salt/modules/aixpkg.py index 25c0b2dbdfc..a77cff26788 100644 --- a/salt/modules/aixpkg.py +++ b/salt/modules/aixpkg.py @@ -184,7 +184,7 @@ def version(*names, **kwargs): for name in names: # AIX packaging includes info on filesets and rpms version_found = "" - cmd = "lslpp -Lq {}".format(name) + cmd = f"lslpp -Lq {name}" aix_info = __salt__["cmd.run_all"](cmd, python_shell=False) if 0 == aix_info["retcode"]: aix_info_list = aix_info["stdout"].split("\n") @@ -344,7 +344,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if refresh: cmdflags += "--refresh " - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -360,7 +360,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa else: cmdflags += "--assumeyes " - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -378,7 +378,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if refresh: cmdflags += "--refresh " - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -392,7 +392,7 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if test: cmdflags += "--test" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"](cmd, python_shell=False) if "retcode" in out and not (0 == out["retcode"] or 100 == out["retcode"]): @@ -510,7 +510,7 @@ def remove(name=None, pkgs=None, **kwargs): libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -519,7 +519,7 @@ def remove(name=None, pkgs=None, **kwargs): ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -528,7 +528,7 @@ def remove(name=None, pkgs=None, **kwargs): ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"]( cmd, python_shell=False, @@ -538,7 +538,7 @@ def remove(name=None, pkgs=None, **kwargs): else: cmdexe = "/usr/bin/rpm" cmdflags = "-e" - cmd = "{} {} {}".format(cmdexe, cmdflags, target) + cmd = f"{cmdexe} {cmdflags} {target}" out = __salt__["cmd.run_all"](cmd, python_shell=False) else: cmd = ["/usr/sbin/installp", "-u", named] @@ -594,19 +594,19 @@ def latest_version(*names, **kwargs): libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) @@ -683,19 +683,19 @@ def upgrade_available(name, **kwargs): libpathenv = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} if pathlib.Path("/opt/freeware/bin/dnf").is_file(): cmdexe = "/opt/freeware/bin/dnf" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/opt/freeware/bin/yum").is_file(): cmdexe = "/opt/freeware/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) elif pathlib.Path("/usr/bin/yum").is_file(): cmdexe = "/usr/bin/yum" - cmd = "{} check-update {}".format(cmdexe, name) + cmd = f"{cmdexe} check-update {name}" available_info = __salt__["cmd.run_all"]( cmd, python_shell=False, env=libpathenv, ignore_retcode=True ) diff --git a/salt/modules/aliases.py b/salt/modules/aliases.py index f04b457ac80..b006593767f 100644 --- a/salt/modules/aliases.py +++ b/salt/modules/aliases.py @@ -74,15 +74,15 @@ def __write_aliases_file(lines): os.chmod(out.name, 0o644) os.chown(out.name, 0, 0) - for (line_alias, line_target, line_comment) in lines: + for line_alias, line_target, line_comment in lines: if isinstance(line_target, list): line_target = ", ".join(line_target) if not line_comment: line_comment = "" if line_alias and line_target: - write_line = "{}: {}{}\n".format(line_alias, line_target, line_comment) + write_line = f"{line_alias}: {line_target}{line_comment}\n" else: - write_line = "{}\n".format(line_comment) + write_line = f"{line_comment}\n" write_line = write_line.encode(__salt_system_encoding__) out.write(write_line) @@ -173,7 +173,7 @@ def set_target(alias, target): lines = __parse_aliases() out = [] ovr = False - for (line_alias, line_target, line_comment) in lines: + for line_alias, line_target, line_comment in lines: if line_alias == alias: if not ovr: out.append((alias, target, line_comment)) @@ -202,7 +202,7 @@ def rm_alias(alias): lines = __parse_aliases() out = [] - for (line_alias, line_target, line_comment) in lines: + for line_alias, line_target, line_comment in lines: if line_alias != alias: out.append((line_alias, line_target, line_comment)) diff --git a/salt/modules/alternatives.py b/salt/modules/alternatives.py index 64df8d78367..a71814b6ef1 100644 --- a/salt/modules/alternatives.py +++ b/salt/modules/alternatives.py @@ -241,5 +241,5 @@ def _read_link(name): Throws an OSError if the link does not exist """ - alt_link_path = "/etc/alternatives/{}".format(name) + alt_link_path = f"/etc/alternatives/{name}" return salt.utils.path.readlink(alt_link_path) diff --git a/salt/modules/ansiblegate.py b/salt/modules/ansiblegate.py index 2f60a7444fb..ec87aa9969c 100644 --- a/salt/modules/ansiblegate.py +++ b/salt/modules/ansiblegate.py @@ -101,17 +101,16 @@ def __virtual__(): proc = subprocess.run( [ansible_doc_bin, "--list", "--json", "--type=module"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, check=False, shell=False, - universal_newlines=True, + text=True, env=env, ) if proc.returncode != 0: return ( False, - "Failed to get the listing of ansible modules:\n{}".format(proc.stderr), + f"Failed to get the listing of ansible modules:\n{proc.stderr}", ) module_funcs = dir(sys.modules[__name__]) @@ -170,11 +169,10 @@ def help(module=None, *args): proc = subprocess.run( [ansible_doc_bin, "--json", "--type=module", module], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, check=True, shell=False, - universal_newlines=True, + text=True, env=env, ) data = salt.utils.json.loads(proc.stdout) @@ -240,7 +238,7 @@ def call(module, *args, **kwargs): _kwargs = {k: v for (k, v) in kwargs.items() if not k.startswith("__pub")} for key, value in _kwargs.items(): - module_args.append("{}={}".format(key, salt.utils.json.dumps(value))) + module_args.append(f"{key}={salt.utils.json.dumps(value)}") with NamedTemporaryFile(mode="w") as inventory: @@ -263,10 +261,9 @@ def call(module, *args, **kwargs): "-i", inventory.name, ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, timeout=__opts__.get("ansible_timeout", DEFAULT_TIMEOUT), - universal_newlines=True, + text=True, check=True, shell=False, env=env, @@ -367,15 +364,15 @@ def playbooks( if diff: command.append("--diff") if isinstance(extra_vars, dict): - command.append("--extra-vars='{}'".format(json.dumps(extra_vars))) + command.append(f"--extra-vars='{json.dumps(extra_vars)}'") elif isinstance(extra_vars, str) and extra_vars.startswith("@"): - command.append("--extra-vars={}".format(extra_vars)) + command.append(f"--extra-vars={extra_vars}") if flush_cache: command.append("--flush-cache") if inventory: - command.append("--inventory={}".format(inventory)) + command.append(f"--inventory={inventory}") if limit: - command.append("--limit={}".format(limit)) + command.append(f"--limit={limit}") if list_hosts: command.append("--list-hosts") if list_tags: @@ -383,25 +380,25 @@ def playbooks( if list_tasks: command.append("--list-tasks") if module_path: - command.append("--module-path={}".format(module_path)) + command.append(f"--module-path={module_path}") if skip_tags: - command.append("--skip-tags={}".format(skip_tags)) + command.append(f"--skip-tags={skip_tags}") if start_at_task: - command.append("--start-at-task={}".format(start_at_task)) + command.append(f"--start-at-task={start_at_task}") if syntax_check: command.append("--syntax-check") if tags: - command.append("--tags={}".format(tags)) + command.append(f"--tags={tags}") if playbook_kwargs: for key, value in playbook_kwargs.items(): key = key.replace("_", "-") if value is True: - command.append("--{}".format(key)) + command.append(f"--{key}") elif isinstance(value, str): - command.append("--{}={}".format(key, value)) + command.append(f"--{key}={value}") elif isinstance(value, dict): - command.append("--{}={}".format(key, json.dumps(value))) - command.append("--forks={}".format(forks)) + command.append(f"--{key}={json.dumps(value)}") + command.append(f"--forks={forks}") cmd_kwargs = { "env": { "ANSIBLE_STDOUT_CALLBACK": "json", @@ -540,12 +537,10 @@ def discover_playbooks( if path: if not os.path.isabs(path): raise CommandExecutionError( - "The given path is not an absolute path: {}".format(path) + f"The given path is not an absolute path: {path}" ) if not os.path.isdir(path): - raise CommandExecutionError( - "The given path is not a directory: {}".format(path) - ) + raise CommandExecutionError(f"The given path is not a directory: {path}") return { path: _explore_path(path, playbook_extension, hosts_filename, syntax_check) } @@ -599,7 +594,7 @@ def _explore_path(path, playbook_extension, hosts_filename, syntax_check): ) except Exception as exc: raise CommandExecutionError( - "There was an exception while discovering playbooks: {}".format(exc) + f"There was an exception while discovering playbooks: {exc}" ) # Run syntax check validation diff --git a/salt/modules/apache.py b/salt/modules/apache.py index 4b867706d10..3d9fc41c618 100644 --- a/salt/modules/apache.py +++ b/salt/modules/apache.py @@ -8,7 +8,6 @@ Support for Apache Debian-based system is detected. """ - import io import logging import re @@ -61,7 +60,7 @@ def version(): salt '*' apache.version """ - cmd = "{} -v".format(_detect_os()) + cmd = f"{_detect_os()} -v" out = __salt__["cmd.run"](cmd).splitlines() ret = out[0].split(": ") return ret[1] @@ -77,7 +76,7 @@ def fullversion(): salt '*' apache.fullversion """ - cmd = "{} -V".format(_detect_os()) + cmd = f"{_detect_os()} -V" ret = {} ret["compiled_with"] = [] out = __salt__["cmd.run"](cmd).splitlines() @@ -106,7 +105,7 @@ def modules(): salt '*' apache.modules """ - cmd = "{} -M".format(_detect_os()) + cmd = f"{_detect_os()} -M" ret = {} ret["static"] = [] ret["shared"] = [] @@ -132,7 +131,7 @@ def servermods(): salt '*' apache.servermods """ - cmd = "{} -l".format(_detect_os()) + cmd = f"{_detect_os()} -l" ret = [] out = __salt__["cmd.run"](cmd).splitlines() for line in out: @@ -154,7 +153,7 @@ def directives(): salt '*' apache.directives """ - cmd = "{} -L".format(_detect_os()) + cmd = f"{_detect_os()} -L" ret = {} out = __salt__["cmd.run"](cmd) out = out.replace("\n\t", "\t") @@ -181,7 +180,7 @@ def vhosts(): salt -t 10 '*' apache.vhosts """ - cmd = "{} -S".format(_detect_os()) + cmd = f"{_detect_os()} -S" ret = {} namevhost = "" out = __salt__["cmd.run"](cmd) @@ -222,9 +221,9 @@ def signal(signal=None): return # Make sure you use the right arguments if signal in valid_signals: - arguments = " -k {}".format(signal) + arguments = f" -k {signal}" else: - arguments = " {}".format(signal) + arguments = f" {signal}" cmd = _detect_os() + arguments out = __salt__["cmd.run_all"](cmd) @@ -238,7 +237,7 @@ def signal(signal=None): ret = out["stdout"].strip() # No output for something like: apachectl graceful else: - ret = 'Command: "{}" completed successfully!'.format(cmd) + ret = f'Command: "{cmd}" completed successfully!' return ret @@ -327,14 +326,12 @@ def server_status(profile="default"): # Get configuration from pillar url = __salt__["config.get"]( - "apache.server-status:{}:url".format(profile), "http://localhost/server-status" - ) - user = __salt__["config.get"]("apache.server-status:{}:user".format(profile), "") - passwd = __salt__["config.get"]("apache.server-status:{}:pass".format(profile), "") - realm = __salt__["config.get"]("apache.server-status:{}:realm".format(profile), "") - timeout = __salt__["config.get"]( - "apache.server-status:{}:timeout".format(profile), 5 + f"apache.server-status:{profile}:url", "http://localhost/server-status" ) + user = __salt__["config.get"](f"apache.server-status:{profile}:user", "") + passwd = __salt__["config.get"](f"apache.server-status:{profile}:pass", "") + realm = __salt__["config.get"](f"apache.server-status:{profile}:realm", "") + timeout = __salt__["config.get"](f"apache.server-status:{profile}:timeout", 5) # create authentication handler if configuration exists if user and passwd: @@ -380,9 +377,9 @@ def _parse_config(conf, slot=None): ret = io.StringIO() if isinstance(conf, str): if slot: - print("{} {}".format(slot, conf), file=ret, end="") + print(f"{slot} {conf}", file=ret, end="") else: - print("{}".format(conf), file=ret, end="") + print(f"{conf}", file=ret, end="") elif isinstance(conf, list): is_section = False for item in conf: @@ -390,12 +387,12 @@ def _parse_config(conf, slot=None): is_section = True slot_this = str(item["this"]) if is_section: - print("<{} {}>".format(slot, slot_this), file=ret) + print(f"<{slot} {slot_this}>", file=ret) for item in conf: for key, val in item.items(): if key != "this": print(_parse_config(val, str(key)), file=ret) - print("".format(slot), file=ret) + print(f"", file=ret) else: for value in conf: print(_parse_config(value, str(slot)), file=ret) @@ -410,12 +407,12 @@ def _parse_config(conf, slot=None): for key, value in conf.items(): if key != "this": if isinstance(value, str): - print("{} {}".format(key, value), file=ret) + print(f"{key} {value}", file=ret) elif isinstance(value, list): print(_parse_config(value, key), file=ret) elif isinstance(value, dict): print(_parse_config(value, key), file=ret) - print("".format(slot), file=ret) + print(f"", file=ret) ret.seek(0) return ret.read() diff --git a/salt/modules/apf.py b/salt/modules/apf.py index 406f2c9d417..c7de7e47895 100644 --- a/salt/modules/apf.py +++ b/salt/modules/apf.py @@ -45,7 +45,7 @@ def __apf_cmd(cmd): msg = out["stdout"] else: msg = out["stderr"] - raise CommandExecutionError("apf failed: {}".format(msg)) + raise CommandExecutionError(f"apf failed: {msg}") return out["stdout"] @@ -140,7 +140,7 @@ def allow(ip, port=None): salt '*' apf.allow 127.0.0.1 """ if port is None: - return __apf_cmd("-a {}".format(ip)) + return __apf_cmd(f"-a {ip}") def deny(ip): @@ -153,7 +153,7 @@ def deny(ip): salt '*' apf.deny 1.2.3.4 """ - return __apf_cmd("-d {}".format(ip)) + return __apf_cmd(f"-d {ip}") def remove(ip): @@ -166,4 +166,4 @@ def remove(ip): salt '*' apf.remove 1.2.3.4 """ - return __apf_cmd("-u {}".format(ip)) + return __apf_cmd(f"-u {ip}") diff --git a/salt/modules/apkpkg.py b/salt/modules/apkpkg.py index 365c9e4c941..e1240d28d15 100644 --- a/salt/modules/apkpkg.py +++ b/salt/modules/apkpkg.py @@ -597,6 +597,6 @@ def owner(*paths, **kwargs): else: ret[path] = output.split("by ")[1].strip() else: - ret[path] = "Error running {}".format(cmd) + ret[path] = f"Error running {cmd}" return ret diff --git a/salt/modules/aptly.py b/salt/modules/aptly.py index a3409abfc3b..6a0a653b3ff 100644 --- a/salt/modules/aptly.py +++ b/salt/modules/aptly.py @@ -77,10 +77,10 @@ def _format_repo_args( for setting in settings: if settings[setting] is not None: - ret.append("-{}={}".format(setting, settings[setting])) + ret.append(f"-{setting}={settings[setting]}") if cached_uploaders_path: - ret.append("-uploaders-file={}".format(cached_uploaders_path)) + ret.append(f"-uploaders-file={cached_uploaders_path}") return ret @@ -97,7 +97,7 @@ def _validate_config(config_path): log.debug("Checking configuration file: %s", config_path) if not os.path.isfile(config_path): - message = "Unable to get configuration file: {}".format(config_path) + message = f"Unable to get configuration file: {config_path}" log.error(message) raise SaltInvocationError(message) @@ -119,7 +119,7 @@ def get_config(config_path=_DEFAULT_CONFIG_PATH): """ _validate_config(config_path) - cmd = ["config", "show", "-config={}".format(config_path)] + cmd = ["config", "show", f"-config={config_path}"] cmd_ret = _cmd_run(cmd) @@ -145,7 +145,7 @@ def list_repos(config_path=_DEFAULT_CONFIG_PATH, with_packages=False): _validate_config(config_path) ret = dict() - cmd = ["repo", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["repo", "list", f"-config={config_path}", "-raw=true"] cmd_ret = _cmd_run(cmd) repos = [line.strip() for line in cmd_ret.splitlines()] @@ -183,8 +183,8 @@ def get_repo(name, config_path=_DEFAULT_CONFIG_PATH, with_packages=False): cmd = [ "repo", "show", - "-config={}".format(config_path), - "-with-packages={}".format(with_packages), + f"-config={config_path}", + f"-with-packages={with_packages}", name, ] @@ -250,7 +250,7 @@ def new_repo( log.debug("Repository already exists: %s", name) return True - cmd = ["repo", "create", "-config={}".format(config_path)] + cmd = ["repo", "create", f"-config={config_path}"] repo_params = _format_repo_args( comment=comment, component=component, @@ -336,7 +336,7 @@ def set_repo( log.debug("Settings already have the desired values for repository: %s", name) return True - cmd = ["repo", "edit", "-config={}".format(config_path)] + cmd = ["repo", "edit", f"-config={config_path}"] repo_params = _format_repo_args( comment=comment, @@ -395,8 +395,8 @@ def delete_repo(name, config_path=_DEFAULT_CONFIG_PATH, force=False): cmd = [ "repo", "drop", - "-config={}".format(config_path), - "-force={}".format(force), + f"-config={config_path}", + f"-force={force}", name, ] @@ -427,7 +427,7 @@ def list_mirrors(config_path=_DEFAULT_CONFIG_PATH): """ _validate_config(config_path) - cmd = ["mirror", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["mirror", "list", f"-config={config_path}", "-raw=true"] cmd_ret = _cmd_run(cmd) ret = [line.strip() for line in cmd_ret.splitlines()] @@ -453,7 +453,7 @@ def list_published(config_path=_DEFAULT_CONFIG_PATH): """ _validate_config(config_path) - cmd = ["publish", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["publish", "list", f"-config={config_path}", "-raw=true"] cmd_ret = _cmd_run(cmd) ret = [line.strip() for line in cmd_ret.splitlines()] @@ -480,7 +480,7 @@ def list_snapshots(config_path=_DEFAULT_CONFIG_PATH, sort_by_time=False): """ _validate_config(config_path) - cmd = ["snapshot", "list", "-config={}".format(config_path), "-raw=true"] + cmd = ["snapshot", "list", f"-config={config_path}", "-raw=true"] if sort_by_time: cmd.append("-sort=time") @@ -518,8 +518,8 @@ def cleanup_db(config_path=_DEFAULT_CONFIG_PATH, dry_run=False): cmd = [ "db", "cleanup", - "-config={}".format(config_path), - "-dry-run={}".format(dry_run), + f"-config={config_path}", + f"-dry-run={dry_run}", "-verbose=true", ] @@ -533,7 +533,7 @@ def cleanup_db(config_path=_DEFAULT_CONFIG_PATH, dry_run=False): if current_block: match = re.search(list_pattern, line) if match: - package_type = "deleted_{}".format(current_block) + package_type = f"deleted_{current_block}" ret[package_type].append(match.group("package")) else: current_block = None diff --git a/salt/modules/archive.py b/salt/modules/archive.py index 3f91cd9cefe..f96d03bc404 100644 --- a/salt/modules/archive.py +++ b/salt/modules/archive.py @@ -207,7 +207,7 @@ def list_( stderr = cached.communicate()[1] if cached.returncode != 0: raise CommandExecutionError( - "Failed to decompress {}".format(name), + f"Failed to decompress {name}", info={"error": stderr}, ) else: @@ -290,7 +290,7 @@ def list_( files.remove(dirname) return list(dirs), files, links except zipfile.BadZipfile: - raise CommandExecutionError("{} is not a ZIP file".format(name)) + raise CommandExecutionError(f"{name} is not a ZIP file") def _list_rar(name, cached): """ @@ -335,7 +335,7 @@ def list_( name, saltenv, source_hash=source_hash, use_etag=use_etag ) if not cached: - raise CommandExecutionError("Failed to cache {}".format(name)) + raise CommandExecutionError(f"Failed to cache {name}") try: if strip_components: @@ -362,7 +362,7 @@ def list_( "'archive_format' argument." ) raise CommandExecutionError( - "Unsupported archive format '{}'".format(archive_format) + f"Unsupported archive format '{archive_format}'" ) if not archive_format: @@ -380,13 +380,13 @@ def list_( dirs, files, links = func(name, cached, *args) except OSError as exc: raise CommandExecutionError( - "Failed to list contents of {}: {}".format(name, exc.__str__()) + f"Failed to list contents of {name}: {exc.__str__()}" ) except CommandExecutionError as exc: raise except Exception as exc: # pylint: disable=broad-except raise CommandExecutionError( - "Uncaught exception '{}' when listing contents of {}".format(exc, name) + f"Uncaught exception '{exc}' when listing contents of {name}" ) if clean: @@ -551,10 +551,10 @@ def tar(options, tarfile, sources=None, dest=None, cwd=None, template=None, runa if options: cmd.extend(options.split()) - cmd.extend(["{}".format(tarfile)]) + cmd.extend([f"{tarfile}"]) cmd.extend(_expand_sources(sources)) if dest: - cmd.extend(["-C", "{}".format(dest)]) + cmd.extend(["-C", f"{dest}"]) return __salt__["cmd.run"]( cmd, cwd=cwd, template=template, runas=runas, python_shell=False @@ -593,7 +593,7 @@ def gzip(sourcefile, template=None, runas=None, options=None): cmd = ["gzip"] if options: cmd.append(options) - cmd.append("{}".format(sourcefile)) + cmd.append(f"{sourcefile}") return __salt__["cmd.run"]( cmd, template=template, runas=runas, python_shell=False @@ -632,7 +632,7 @@ def gunzip(gzipfile, template=None, runas=None, options=None): cmd = ["gunzip"] if options: cmd.append(options) - cmd.append("{}".format(gzipfile)) + cmd.append(f"{gzipfile}") return __salt__["cmd.run"]( cmd, template=template, runas=runas, python_shell=False @@ -698,7 +698,7 @@ def cmd_zip(zip_file, sources, template=None, cwd=None, runas=None): salt '*' archive.cmd_zip /tmp/zipfile.zip '/tmp/sourcefile*' """ cmd = ["zip", "-r"] - cmd.append("{}".format(zip_file)) + cmd.append(f"{zip_file}") cmd.extend(_expand_sources(sources)) return __salt__["cmd.run"]( cmd, cwd=cwd, template=template, runas=runas, python_shell=False @@ -773,7 +773,7 @@ def zip_(zip_file, sources, template=None, cwd=None, runas=None, zip64=False): egid = os.getegid() uinfo = __salt__["user.info"](runas) if not uinfo: - raise SaltInvocationError("User '{}' does not exist".format(runas)) + raise SaltInvocationError(f"User '{runas}' does not exist") zip_file, sources = _render_filenames(zip_file, sources, None, template) sources = _expand_sources(sources) @@ -848,7 +848,7 @@ def zip_(zip_file, sources, template=None, cwd=None, runas=None, zip64=False): ) else: raise CommandExecutionError( - "Exception encountered creating zipfile: {}".format(exc) + f"Exception encountered creating zipfile: {exc}" ) return archived_files @@ -942,7 +942,7 @@ def cmd_unzip( cmd.extend(["-P", password]) if options: cmd.extend(shlex.split(options)) - cmd.extend(["{}".format(zip_file), "-d", "{}".format(dest)]) + cmd.extend([f"{zip_file}", "-d", f"{dest}"]) if excludes is not None: cmd.append("-x") @@ -1060,7 +1060,7 @@ def unzip( egid = os.getegid() uinfo = __salt__["user.info"](runas) if not uinfo: - raise SaltInvocationError("User '{}' does not exist".format(runas)) + raise SaltInvocationError(f"User '{runas}' does not exist") zip_file, dest = _render_filenames(zip_file, dest, None, template) @@ -1121,9 +1121,7 @@ def unzip( os.setegid(egid) # Wait to raise the exception until euid/egid are restored to avoid # permission errors in writing to minion log. - raise CommandExecutionError( - "Exception encountered unpacking zipfile: {}".format(exc) - ) + raise CommandExecutionError(f"Exception encountered unpacking zipfile: {exc}") finally: # Restore the euid/egid if runas: @@ -1190,7 +1188,7 @@ def is_encrypted(name, clean=False, saltenv="base", source_hash=None, use_etag=F name, saltenv, source_hash=source_hash, use_etag=use_etag ) if not cached: - raise CommandExecutionError("Failed to cache {}".format(name)) + raise CommandExecutionError(f"Failed to cache {name}") archive_info = {"archive location": cached} try: @@ -1199,9 +1197,7 @@ def is_encrypted(name, clean=False, saltenv="base", source_hash=None, use_etag=F except RuntimeError: ret = True except zipfile.BadZipfile: - raise CommandExecutionError( - "{} is not a ZIP file".format(name), info=archive_info - ) + raise CommandExecutionError(f"{name} is not a ZIP file", info=archive_info) except Exception as exc: # pylint: disable=broad-except raise CommandExecutionError(exc.__str__(), info=archive_info) else: @@ -1261,7 +1257,7 @@ def rar(rarfile, sources, template=None, cwd=None, runas=None): # Globbing for sources (2017.7.0 and later) salt '*' archive.rar /tmp/rarfile.rar '/tmp/sourcefile*' """ - cmd = ["rar", "a", "-idp", "{}".format(rarfile)] + cmd = ["rar", "a", "-idp", f"{rarfile}"] cmd.extend(_expand_sources(sources)) return __salt__["cmd.run"]( cmd, cwd=cwd, template=template, runas=runas, python_shell=False @@ -1307,12 +1303,12 @@ def unrar(rarfile, dest, excludes=None, template=None, runas=None, trim_output=F salt.utils.path.which_bin(("unrar", "rar")), "x", "-idp", - "{}".format(rarfile), + f"{rarfile}", ] if excludes is not None: for exclude in excludes: - cmd.extend(["-x", "{}".format(exclude)]) - cmd.append("{}".format(dest)) + cmd.extend(["-x", f"{exclude}"]) + cmd.append(f"{dest}") files = __salt__["cmd.run"]( cmd, template=template, runas=runas, python_shell=False ).splitlines() @@ -1332,7 +1328,7 @@ def _render_filenames(filenames, zip_file, saltenv, template): # render the path as a template using path_template_engine as the engine if template not in salt.utils.templates.TEMPLATE_REGISTRY: raise CommandExecutionError( - "Attempted to render file paths with unavailable engine {}".format(template) + f"Attempted to render file paths with unavailable engine {template}" ) kwargs = {} @@ -1381,6 +1377,6 @@ def _trim_files(files, trim_output): and len(files) > count ): files = files[:count] - files.append("List trimmed after {} files.".format(count)) + files.append(f"List trimmed after {count} files.") return files diff --git a/salt/modules/arista_pyeapi.py b/salt/modules/arista_pyeapi.py index 1dbd27fd872..9e9abb1a973 100644 --- a/salt/modules/arista_pyeapi.py +++ b/salt/modules/arista_pyeapi.py @@ -398,7 +398,7 @@ def config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Configures the node with the specified commands. @@ -509,7 +509,7 @@ def config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") log.debug("Fetched from %s", config_file) log.debug(file_str) elif commands: diff --git a/salt/modules/augeas_cfg.py b/salt/modules/augeas_cfg.py index 70f05b3a465..adc4fa22b21 100644 --- a/salt/modules/augeas_cfg.py +++ b/salt/modules/augeas_cfg.py @@ -190,7 +190,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): cmd, arg = command.split(" ", 1) if cmd not in METHOD_MAP: - ret["error"] = "Command {} is not supported (yet)".format(cmd) + ret["error"] = f"Command {cmd} is not supported (yet)" return ret method = METHOD_MAP[cmd] @@ -199,7 +199,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): parts = salt.utils.args.shlex_split(arg) if len(parts) not in nargs: - err = "{} takes {} args: {}".format(method, nargs, parts) + err = f"{method} takes {nargs} args: {parts}" raise ValueError(err) if method == "set": path = make_path(parts[0]) @@ -217,9 +217,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): elif method == "insert": label, where, path = parts if where not in ("before", "after"): - raise ValueError( - 'Expected "before" or "after", not {}'.format(where) - ) + raise ValueError(f'Expected "before" or "after", not {where}') path = make_path(path) args = {"path": path, "label": label, "before": where == "before"} elif method == "remove": @@ -230,9 +228,9 @@ def execute(context=None, lens=None, commands=(), load_path=None): # if command.split fails arg will not be set if "arg" not in locals(): arg = command - ret[ - "error" - ] = "Invalid formatted command, see debug log for details: {}".format(arg) + ret["error"] = ( + f"Invalid formatted command, see debug log for details: {arg}" + ) return ret args = salt.utils.data.decode(args, to_str=True) @@ -374,7 +372,7 @@ def setvalue(*args): try: aug.set(target_path, str(value)) except ValueError as err: - ret["error"] = "Multiple values: {}".format(err) + ret["error"] = f"Multiple values: {err}" try: aug.save() diff --git a/salt/modules/aws_sqs.py b/salt/modules/aws_sqs.py index e85417faf1a..428f4062dad 100644 --- a/salt/modules/aws_sqs.py +++ b/salt/modules/aws_sqs.py @@ -23,7 +23,7 @@ def _region(region): """ Return the region argument. """ - return " --region {r}".format(r=region) + return f" --region {region}" def _run_aws(cmd, region, opts, user, **kwargs): @@ -49,7 +49,7 @@ def _run_aws(cmd, region, opts, user, **kwargs): if num: kwargs["max-number-of-messages"] = num - _formatted_args = ['--{} "{}"'.format(k, v) for k, v in kwargs.items()] + _formatted_args = [f'--{k} "{v}"' for k, v in kwargs.items()] cmd = "aws sqs {cmd} {args} {region} {out}".format( cmd=cmd, args=" ".join(_formatted_args), region=_region(region), out=_OUTPUT @@ -245,7 +245,7 @@ def delete_queue(name, region, opts=None, user=None): rtn = _run_aws("delete-queue", region=region, opts=opts, user=user, **delete) success = True err = "" - out = "{} deleted".format(name) + out = f"{name} deleted" else: out = "" diff --git a/salt/modules/bamboohr.py b/salt/modules/bamboohr.py index 5cdd05bee8e..e1582ff9a3f 100644 --- a/salt/modules/bamboohr.py +++ b/salt/modules/bamboohr.py @@ -175,8 +175,8 @@ def update_employee(emp_id, key=None, value=None, items=None): xml_items = "" for pair in items: - xml_items += '{}'.format(pair, items[pair]) - xml_items = "{}".format(xml_items) + xml_items += f'{items[pair]}' + xml_items = f"{xml_items}" status, result = _query( action="employees", @@ -259,13 +259,13 @@ def _query(action=None, command=None, args=None, method="GET", data=None): The password can be any random text, so we chose Salty text. """ subdomain = __opts__.get("bamboohr", {}).get("subdomain", None) - path = "https://api.bamboohr.com/api/gateway.php/{}/v1/".format(subdomain) + path = f"https://api.bamboohr.com/api/gateway.php/{subdomain}/v1/" if action: path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("BambooHR URL: %s", path) diff --git a/salt/modules/baredoc.py b/salt/modules/baredoc.py index aa867102bd4..7513b546919 100644 --- a/salt/modules/baredoc.py +++ b/salt/modules/baredoc.py @@ -122,9 +122,9 @@ def _parse_module_docs(module_path, mod_name=None): function_name = v if mod_name and "." in mod_name: if function_name == mod_name.split(".")[1]: - ret["{}.{}".format(module_name, function_name)] = doc_string + ret[f"{module_name}.{function_name}"] = doc_string else: - ret["{}.{}".format(module_name, function_name)] = doc_string + ret[f"{module_name}.{function_name}"] = doc_string return salt.utils.doc.strip_rst(ret) diff --git a/salt/modules/bcache.py b/salt/modules/bcache.py index 7e69b45ad57..acd4fdbcd56 100644 --- a/salt/modules/bcache.py +++ b/salt/modules/bcache.py @@ -117,14 +117,14 @@ def attach_(dev=None): "attach", cache, "error", - "Error attaching {} to bcache {}".format(dev, cache), + f"Error attaching {dev} to bcache {cache}", ): return False return _wait( lambda: uuid(dev) == cache, "error", - "{} received attach to bcache {}, but did not comply".format(dev, cache), + f"{dev} received attach to bcache {cache}, but did not comply", ) @@ -153,12 +153,12 @@ def detach(dev=None): return res if res else None log.debug("Detaching %s", dev) - if not _bcsys(dev, "detach", "goaway", "error", "Error detaching {}".format(dev)): + if not _bcsys(dev, "detach", "goaway", "error", f"Error detaching {dev}"): return False return _wait( lambda: uuid(dev) is False, "error", - "{} received detach, but did not comply".format(dev), + f"{dev} received detach, but did not comply", 300, ) @@ -203,12 +203,12 @@ def stop(dev=None): """ if dev is not None: log.warning("Stopping %s, device will only reappear after reregistering!", dev) - if not _bcsys(dev, "stop", "goaway", "error", "Error stopping {}".format(dev)): + if not _bcsys(dev, "stop", "goaway", "error", f"Error stopping {dev}"): return False return _wait( lambda: _sysfs_attr(_bcpath(dev)) is False, "error", - "Device {} did not stop".format(dev), + f"Device {dev} did not stop", 300, ) else: @@ -271,19 +271,19 @@ def back_make(dev, cache_mode="writeback", force=False, attach=True, bucket_size if force: cmd += " --wipe-bcache" - if not _run_all(cmd, "error", "Error creating backing device {}: %s".format(dev)): + if not _run_all(cmd, "error", f"Error creating backing device {dev}: %s"): return False elif not _sysfs_attr( "fs/bcache/register", _devpath(dev), "error", - "Error registering backing device {}".format(dev), + f"Error registering backing device {dev}", ): return False elif not _wait( lambda: _sysfs_attr(_bcpath(dev)) is not False, "error", - "Backing device {} did not register".format(dev), + f"Backing device {dev} did not register", ): return False elif attach: @@ -370,25 +370,23 @@ def cache_make( ) # if wipe was incomplete & part layout remains the same, # this is one condition set where udev would make it accidentally popup again - if not _run_all( - cmd, "error", "Error creating bcache partitions on {}: %s".format(dev) - ): + if not _run_all(cmd, "error", f"Error creating bcache partitions on {dev}: %s"): return False - dev = "{}2".format(dev) + dev = f"{dev}2" # ---------------- Finally, create a cache ---------------- - cmd = "make-bcache --cache /dev/{} --block {} --wipe-bcache".format(dev, block_size) + cmd = f"make-bcache --cache /dev/{dev} --block {block_size} --wipe-bcache" # Actually bucket_size should always have a value, but for testing 0 is possible as well if bucket_size: - cmd += " --bucket {}".format(bucket_size) + cmd += f" --bucket {bucket_size}" - if not _run_all(cmd, "error", "Error creating cache {}: %s".format(dev)): + if not _run_all(cmd, "error", f"Error creating cache {dev}: %s"): return False elif not _wait( lambda: uuid() is not False, "error", - "Cache {} seemingly created OK, but FS did not activate".format(dev), + f"Cache {dev} seemingly created OK, but FS did not activate", ): return False @@ -430,7 +428,7 @@ def config_(dev=None, **kwargs): [spath, key], val, "warn", - "Failed to update {} with {}".format(os.path.join(spath, key), val), + f"Failed to update {os.path.join(spath, key)} with {val}", ) return endres > 0 else: @@ -470,7 +468,7 @@ def status(stats=False, config=False, internals=False, superblock=False, alldevs continue for spath, sdirs, _ in salt.utils.path.os_walk( - "/sys/block/{}".format(block), followlinks=False + f"/sys/block/{block}", followlinks=False ): if "bcache" in sdirs: bdevs.append(os.path.basename(spath)) @@ -514,7 +512,7 @@ def device(dev, stats=False, config=False, internals=False, superblock=False): result = {} if not _sysfs_attr( - _bcpath(dev), None, "error", "{} is not a bcache fo any kind".format(dev) + _bcpath(dev), None, "error", f"{dev} is not a bcache fo any kind" ): return False elif _bcsys(dev, "set"): @@ -632,9 +630,9 @@ def super_(dev): ret = {} res = _run_all( - "bcache-super-show {}".format(dev), + f"bcache-super-show {dev}", "error", - "Error reading superblock on {}: %s".format(dev), + f"Error reading superblock on {dev}: %s", ) if not res: return False @@ -992,18 +990,18 @@ def _wipe(dev): else: wiper = "blkdiscard" - wipe_failmsg = "Error wiping {}: %s".format(dev) + wipe_failmsg = f"Error wiping {dev}: %s" if wiper == "dd": blocks = 4 - cmd = "dd if=/dev/zero of=/dev/{} bs=1M count={}".format(dev, blocks) + cmd = f"dd if=/dev/zero of=/dev/{dev} bs=1M count={blocks}" endres += _run_all(cmd, "warn", wipe_failmsg) # Some stuff (GPT) writes stuff at the end of a dev as well - cmd += " seek={}".format((size / 1024**2) - blocks) + cmd += f" seek={(size / 1024**2) - blocks}" endres += _run_all(cmd, "warn", wipe_failmsg) elif wiper == "blkdiscard": - cmd = "blkdiscard /dev/{}".format(dev) + cmd = f"blkdiscard /dev/{dev}" endres += _run_all(cmd, "warn", wipe_failmsg) # TODO: fix annoying bug failing blkdiscard by trying to discard 1 sector past blkdev endres = 1 diff --git a/salt/modules/beacons.py b/salt/modules/beacons.py index 3aef0abbec2..e482abcf235 100644 --- a/salt/modules/beacons.py +++ b/salt/modules/beacons.py @@ -5,7 +5,6 @@ Module for managing the Salt beacons on a minion """ - import difflib import logging import os @@ -139,10 +138,10 @@ def add(name, beacon_data, **kwargs): salt '*' beacons.add ps "[{'processes': {'salt-master': 'stopped', 'apache2': 'stopped'}}]" """ - ret = {"comment": "Failed to add beacon {}.".format(name), "result": False} + ret = {"comment": f"Failed to add beacon {name}.", "result": False} if name in list_(return_yaml=False, **kwargs): - ret["comment"] = "Beacon {} is already configured.".format(name) + ret["comment"] = f"Beacon {name} is already configured." ret["result"] = True return ret @@ -155,12 +154,12 @@ def add(name, beacon_data, **kwargs): beacon_name = name if beacon_name not in list_available(return_yaml=False, **kwargs): - ret["comment"] = 'Beacon "{}" is not available.'.format(beacon_name) + ret["comment"] = f'Beacon "{beacon_name}" is not available.' return ret if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"] = "Beacon: {} would be added.".format(name) + ret["comment"] = f"Beacon: {name} would be added." else: try: # Attempt to load the beacon module so we have access to the validate function @@ -185,10 +184,10 @@ def add(name, beacon_data, **kwargs): if not valid: ret["result"] = False - ret[ - "comment" - ] = "Beacon {} configuration invalid, not adding.\n{}".format( - name, vcomment + ret["comment"] = ( + "Beacon {} configuration invalid, not adding.\n{}".format( + name, vcomment + ) ) return ret except KeyError: @@ -216,7 +215,7 @@ def add(name, beacon_data, **kwargs): [item in beacons[name] for item in beacon_data] ): ret["result"] = True - ret["comment"] = "Added beacon: {}.".format(name) + ret["comment"] = f"Added beacon: {name}." elif event_ret: ret["result"] = False ret["comment"] = event_ret["comment"] @@ -255,12 +254,12 @@ def modify(name, beacon_data, **kwargs): current_beacons = list_(return_yaml=False, **kwargs) if name not in current_beacons: - ret["comment"] = "Beacon {} is not configured.".format(name) + ret["comment"] = f"Beacon {name} is not configured." return ret if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"] = "Beacon: {} would be modified.".format(name) + ret["comment"] = f"Beacon: {name} would be modified." else: try: # Attempt to load the beacon module so we have access to the validate function @@ -285,10 +284,10 @@ def modify(name, beacon_data, **kwargs): if not valid: ret["result"] = False - ret[ - "comment" - ] = "Beacon {} configuration invalid, not modifying.\n{}".format( - name, vcomment + ret["comment"] = ( + "Beacon {} configuration invalid, not modifying.\n{}".format( + name, vcomment + ) ) return ret @@ -300,10 +299,10 @@ def modify(name, beacon_data, **kwargs): if not valid: ret["result"] = False - ret[ - "comment" - ] = "Beacon {} configuration invalid, not modifying.\n{}".format( - name, vcomment + ret["comment"] = ( + "Beacon {} configuration invalid, not modifying.\n{}".format( + name, vcomment + ) ) return ret @@ -311,19 +310,17 @@ def modify(name, beacon_data, **kwargs): _new = beacon_data if _new == _current: - ret["comment"] = "Job {} in correct state".format(name) + ret["comment"] = f"Job {name} in correct state" return ret _current_lines = [] for _item in _current: _current_lines.extend( - ["{}:{}\n".format(key, value) for (key, value) in _item.items()] + [f"{key}:{value}\n" for (key, value) in _item.items()] ) _new_lines = [] for _item in _new: - _new_lines.extend( - ["{}:{}\n".format(key, value) for (key, value) in _item.items()] - ) + _new_lines.extend([f"{key}:{value}\n" for (key, value) in _item.items()]) _diff = difflib.unified_diff(_current_lines, _new_lines) ret["changes"] = {} @@ -346,7 +343,7 @@ def modify(name, beacon_data, **kwargs): beacons = event_ret["beacons"] if name in beacons and beacons[name] == beacon_data: ret["result"] = True - ret["comment"] = "Modified beacon: {}.".format(name) + ret["comment"] = f"Modified beacon: {name}." elif event_ret: ret["result"] = False ret["comment"] = event_ret["comment"] @@ -383,11 +380,11 @@ def delete(name, **kwargs): """ - ret = {"comment": "Failed to delete beacon {}.".format(name), "result": False} + ret = {"comment": f"Failed to delete beacon {name}.", "result": False} if "test" in kwargs and kwargs["test"]: ret["result"] = True - ret["comment"] = "Beacon: {} would be deleted.".format(name) + ret["comment"] = f"Beacon: {name} would be deleted." else: try: with salt.utils.event.get_event( @@ -405,7 +402,7 @@ def delete(name, **kwargs): beacons = event_ret["beacons"] if name not in beacons: ret["result"] = True - ret["comment"] = "Deleted beacon: {}.".format(name) + ret["comment"] = f"Deleted beacon: {name}." return ret elif event_ret: ret["result"] = False @@ -457,11 +454,9 @@ def save(**kwargs): try: with salt.utils.files.fopen(sfn, "w+") as fp_: fp_.write(yaml_out) - ret["comment"] = "Beacons saved to {}.".format(sfn) + ret["comment"] = f"Beacons saved to {sfn}." except OSError: - ret[ - "comment" - ] = "Unable to write to beacons file at {}. Check permissions.".format(sfn) + ret["comment"] = f"Unable to write to beacons file at {sfn}. Check permissions." ret["result"] = False return ret @@ -604,11 +599,11 @@ def enable_beacon(name, **kwargs): return ret if "test" in kwargs and kwargs["test"]: - ret["comment"] = "Beacon {} would be enabled.".format(name) + ret["comment"] = f"Beacon {name} would be enabled." else: _beacons = list_(return_yaml=False, **kwargs) if name not in _beacons: - ret["comment"] = "Beacon {} is not currently configured.".format(name) + ret["comment"] = f"Beacon {name} is not currently configured." ret["result"] = False return ret @@ -633,12 +628,12 @@ def enable_beacon(name, **kwargs): and beacon_config_dict["enabled"] ): ret["result"] = True - ret["comment"] = "Enabled beacon {} on minion.".format(name) + ret["comment"] = f"Enabled beacon {name} on minion." else: ret["result"] = False - ret[ - "comment" - ] = "Failed to enable beacon {} on minion.".format(name) + ret["comment"] = ( + f"Failed to enable beacon {name} on minion." + ) elif event_ret: ret["result"] = False ret["comment"] = event_ret["comment"] @@ -654,9 +649,9 @@ def enable_beacon(name, **kwargs): except KeyError: # Effectively a no-op, since we can't really return without an event system ret["result"] = False - ret[ - "comment" - ] = "Event module not available. Beacon enable_beacon job failed." + ret["comment"] = ( + "Event module not available. Beacon enable_beacon job failed." + ) return ret @@ -686,7 +681,7 @@ def disable_beacon(name, **kwargs): else: _beacons = list_(return_yaml=False, **kwargs) if name not in _beacons: - ret["comment"] = "Beacon {} is not currently configured.".format(name) + ret["comment"] = f"Beacon {name} is not currently configured." ret["result"] = False return ret @@ -732,9 +727,9 @@ def disable_beacon(name, **kwargs): except KeyError: # Effectively a no-op, since we can't really return without an event system ret["result"] = False - ret[ - "comment" - ] = "Event module not available. Beacon disable_beacon job failed." + ret["comment"] = ( + "Event module not available. Beacon disable_beacon job failed." + ) return ret diff --git a/salt/modules/bigip.py b/salt/modules/bigip.py index 219afea9726..6624b85c6f8 100644 --- a/salt/modules/bigip.py +++ b/salt/modules/bigip.py @@ -48,9 +48,7 @@ def _build_session(username, password, trans_label=None): if trans_label: # pull the trans id from the grain - trans_id = __salt__["grains.get"]( - "bigip_f5_trans:{label}".format(label=trans_label) - ) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{trans_label}") if trans_id: bigip.headers.update({"X-F5-REST-Coordination-Id": trans_id}) @@ -311,7 +309,7 @@ def list_transaction(hostname, username, password, label): bigip_session = _build_session(username, password) # pull the trans id from the grain - trans_id = __salt__["grains.get"]("bigip_f5_trans:{label}".format(label=label)) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}") if trans_id: @@ -319,7 +317,7 @@ def list_transaction(hostname, username, password, label): try: response = bigip_session.get( BIG_IP_URL_BASE.format(host=hostname) - + "/transaction/{trans_id}/commands".format(trans_id=trans_id) + + f"/transaction/{trans_id}/commands" ) return _load_response(response) except requests.exceptions.ConnectionError as e: @@ -356,7 +354,7 @@ def commit_transaction(hostname, username, password, label): bigip_session = _build_session(username, password) # pull the trans id from the grain - trans_id = __salt__["grains.get"]("bigip_f5_trans:{label}".format(label=label)) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}") if trans_id: @@ -366,8 +364,7 @@ def commit_transaction(hostname, username, password, label): # patch to REST to get trans id try: response = bigip_session.patch( - BIG_IP_URL_BASE.format(host=hostname) - + "/transaction/{trans_id}".format(trans_id=trans_id), + BIG_IP_URL_BASE.format(host=hostname) + f"/transaction/{trans_id}", data=salt.utils.json.dumps(payload), ) return _load_response(response) @@ -405,15 +402,14 @@ def delete_transaction(hostname, username, password, label): bigip_session = _build_session(username, password) # pull the trans id from the grain - trans_id = __salt__["grains.get"]("bigip_f5_trans:{label}".format(label=label)) + trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}") if trans_id: # patch to REST to get trans id try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) - + "/transaction/{trans_id}".format(trans_id=trans_id) + BIG_IP_URL_BASE.format(host=hostname) + f"/transaction/{trans_id}" ) return _load_response(response) except requests.exceptions.ConnectionError as e: @@ -457,8 +453,7 @@ def list_node(hostname, username, password, name=None, trans_label=None): try: if name: response = bigip_session.get( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/node/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}" ) else: response = bigip_session.get( @@ -593,8 +588,7 @@ def modify_node( # put to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/node/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -632,7 +626,7 @@ def delete_node(hostname, username, password, name, trans_label=None): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) + "/ltm/node/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -672,7 +666,7 @@ def list_pool(hostname, username, password, name=None): if name: response = bigip_session.get( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/?expandSubcollections=true".format(name=name) + + f"/ltm/pool/{name}/?expandSubcollections=true" ) else: response = bigip_session.get( @@ -991,8 +985,7 @@ def modify_pool( # post to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1027,7 +1020,7 @@ def delete_pool(hostname, username, password, name): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) + "/ltm/pool/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -1098,8 +1091,7 @@ def replace_pool_members(hostname, username, password, name, members): # put to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1155,8 +1147,7 @@ def add_pool_member(hostname, username, password, name, member): # post to REST try: response = bigip_session.post( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/members".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}/members", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1254,7 +1245,7 @@ def modify_pool_member( try: response = bigip_session.put( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/members/{member}".format(name=name, member=member), + + f"/ltm/pool/{name}/members/{member}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1291,8 +1282,7 @@ def delete_pool_member(hostname, username, password, name, member): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/pool/{name}/members/{member}".format(name=name, member=member) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}/members/{member}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -1332,7 +1322,7 @@ def list_virtual(hostname, username, password, name=None): if name: response = bigip_session.get( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/virtual/{name}/?expandSubcollections=true".format(name=name) + + f"/ltm/virtual/{name}/?expandSubcollections=true" ) else: response = bigip_session.get( @@ -1925,8 +1915,7 @@ def modify_virtual( # put to REST try: response = bigip_session.put( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/virtual/{name}".format(name=name), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/virtual/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -1961,8 +1950,7 @@ def delete_virtual(hostname, username, password, name): # delete to REST try: response = bigip_session.delete( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/virtual/{name}".format(name=name) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/virtual/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2017,8 +2005,7 @@ def list_monitor( ) else: response = bigip_session.get( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}".format(type=monitor_type) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/monitor/{monitor_type}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2069,8 +2056,7 @@ def create_monitor(hostname, username, password, monitor_type, name, **kwargs): # post to REST try: response = bigip_session.post( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}".format(type=monitor_type), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/monitor/{monitor_type}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2123,7 +2109,7 @@ def modify_monitor(hostname, username, password, monitor_type, name, **kwargs): try: response = bigip_session.put( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}/{name}".format(type=monitor_type, name=name), + + f"/ltm/monitor/{monitor_type}/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2162,7 +2148,7 @@ def delete_monitor(hostname, username, password, monitor_type, name): try: response = bigip_session.delete( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/monitor/{type}/{name}".format(type=monitor_type, name=name) + + f"/ltm/monitor/{monitor_type}/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2217,8 +2203,7 @@ def list_profile( ) else: response = bigip_session.get( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}".format(type=profile_type) + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/profile/{profile_type}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) @@ -2302,8 +2287,7 @@ def create_profile(hostname, username, password, profile_type, name, **kwargs): # post to REST try: response = bigip_session.post( - BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}".format(type=profile_type), + BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/profile/{profile_type}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2396,7 +2380,7 @@ def modify_profile(hostname, username, password, profile_type, name, **kwargs): try: response = bigip_session.put( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}/{name}".format(type=profile_type, name=name), + + f"/ltm/profile/{profile_type}/{name}", data=salt.utils.json.dumps(payload), ) except requests.exceptions.ConnectionError as e: @@ -2435,7 +2419,7 @@ def delete_profile(hostname, username, password, profile_type, name): try: response = bigip_session.delete( BIG_IP_URL_BASE.format(host=hostname) - + "/ltm/profile/{type}/{name}".format(type=profile_type, name=name) + + f"/ltm/profile/{profile_type}/{name}" ) except requests.exceptions.ConnectionError as e: return _load_connection_error(hostname, e) diff --git a/salt/modules/bluez_bluetooth.py b/salt/modules/bluez_bluetooth.py index ba2ec098e5d..1813e7014ef 100644 --- a/salt/modules/bluez_bluetooth.py +++ b/salt/modules/bluez_bluetooth.py @@ -8,6 +8,7 @@ The following packages are required packages for this module: bluez-utils >= 5.7 pybluez >= 0.18 """ + import shlex import salt.utils.validate.net @@ -80,7 +81,7 @@ def address_(): dev = comps[0] ret[dev] = { "device": dev, - "path": "/sys/class/bluetooth/{}".format(dev), + "path": f"/sys/class/bluetooth/{dev}", } if "BD Address" in line: comps = line.split() @@ -112,7 +113,7 @@ def power(dev, mode): else: state = "down" mode = "off" - cmd = "hciconfig {} {}".format(dev, state) + cmd = f"hciconfig {dev} {state}" __salt__["cmd.run"](cmd).splitlines() info = address_() if info[dev]["power"] == mode: @@ -133,9 +134,9 @@ def discoverable(dev): if dev not in address_(): raise CommandExecutionError("Invalid dev passed to bluetooth.discoverable") - cmd = "hciconfig {} iscan".format(dev) + cmd = f"hciconfig {dev} iscan" __salt__["cmd.run"](cmd).splitlines() - cmd = "hciconfig {}".format(dev) + cmd = f"hciconfig {dev}" out = __salt__["cmd.run"](cmd) if "UP RUNNING ISCAN" in out: return True @@ -155,9 +156,9 @@ def noscan(dev): if dev not in address_(): raise CommandExecutionError("Invalid dev passed to bluetooth.noscan") - cmd = "hciconfig {} noscan".format(dev) + cmd = f"hciconfig {dev} noscan" __salt__["cmd.run"](cmd).splitlines() - cmd = "hciconfig {}".format(dev) + cmd = f"hciconfig {dev}" out = __salt__["cmd.run"](cmd) if "SCAN" in out: return False @@ -194,7 +195,7 @@ def block(bdaddr): if not salt.utils.validate.net.mac(bdaddr): raise CommandExecutionError("Invalid BD address passed to bluetooth.block") - cmd = "hciconfig {} block".format(bdaddr) + cmd = f"hciconfig {bdaddr} block" __salt__["cmd.run"](cmd).splitlines() @@ -211,7 +212,7 @@ def unblock(bdaddr): if not salt.utils.validate.net.mac(bdaddr): raise CommandExecutionError("Invalid BD address passed to bluetooth.unblock") - cmd = "hciconfig {} unblock".format(bdaddr) + cmd = f"hciconfig {bdaddr} unblock" __salt__["cmd.run"](cmd).splitlines() @@ -267,7 +268,7 @@ def unpair(address): if not salt.utils.validate.net.mac(address): raise CommandExecutionError("Invalid BD address passed to bluetooth.unpair") - cmd = "bluez-test-device remove {}".format(address) + cmd = f"bluez-test-device remove {address}" out = __salt__["cmd.run"](cmd).splitlines() return out diff --git a/salt/modules/boto3_elasticache.py b/salt/modules/boto3_elasticache.py index 1e52ea25a2c..ec644d92ccb 100644 --- a/salt/modules/boto3_elasticache.py +++ b/salt/modules/boto3_elasticache.py @@ -107,7 +107,7 @@ def _describe_resource( key=None, keyid=None, profile=None, - **args + **args, ): if conn is None: conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) @@ -115,9 +115,7 @@ def _describe_resource( func = "describe_" + res_type + "s" f = getattr(conn, func) except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") # Undocumented, but you can't pass 'Marker' if searching for a specific resource... args.update({name_param: name} if name else {"Marker": ""}) args = {k: v for k, v in args.items() if not k.startswith("_")} @@ -140,7 +138,7 @@ def _delete_resource( key=None, keyid=None, profile=None, - **args + **args, ): """ Delete a generic Elasticache resource. @@ -171,9 +169,7 @@ def _delete_resource( func = "describe_" + res_type + "s" s = globals()[func] except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") try: f(**args) @@ -211,7 +207,7 @@ def _create_resource( key=None, keyid=None, profile=None, - **args + **args, ): try: wait = int(wait) @@ -239,9 +235,7 @@ def _create_resource( func = "describe_" + res_type + "s" s = globals()[func] except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") try: f(**args) if not wait: @@ -270,7 +264,7 @@ def _create_resource( ) return False except botocore.exceptions.ClientError as e: - msg = "Failed to create {} {}: {}".format(desc, name, e) + msg = f"Failed to create {desc} {name}: {e}" log.error(msg) return False @@ -287,7 +281,7 @@ def _modify_resource( key=None, keyid=None, profile=None, - **args + **args, ): try: wait = int(wait) @@ -315,9 +309,7 @@ def _modify_resource( func = "describe_" + res_type + "s" s = globals()[func] except (AttributeError, KeyError) as e: - raise SaltInvocationError( - "No function '{}()' found: {}".format(func, e.message) - ) + raise SaltInvocationError(f"No function '{func}()' found: {e.message}") try: f(**args) if not wait: @@ -346,7 +338,7 @@ def _modify_resource( ) return False except botocore.exceptions.ClientError as e: - msg = "Failed to modify {} {}: {}".format(desc, name, e) + msg = f"Failed to modify {desc} {name}: {e}" log.error(msg) return False @@ -374,7 +366,7 @@ def describe_cache_clusters( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -405,7 +397,7 @@ def create_cache_cluster( key=None, keyid=None, profile=None, - **args + **args, ): """ Create a cache cluster. @@ -442,7 +434,7 @@ def create_cache_cluster( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -454,7 +446,7 @@ def modify_cache_cluster( key=None, keyid=None, profile=None, - **args + **args, ): """ Update a cache cluster in place. @@ -496,7 +488,7 @@ def modify_cache_cluster( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -523,7 +515,7 @@ def delete_cache_cluster( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -578,7 +570,7 @@ def create_replication_group( key=None, keyid=None, profile=None, - **args + **args, ): """ Create a replication group. @@ -615,7 +607,7 @@ def create_replication_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -627,7 +619,7 @@ def modify_replication_group( key=None, keyid=None, profile=None, - **args + **args, ): """ Modify a replication group. @@ -661,7 +653,7 @@ def modify_replication_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -688,7 +680,7 @@ def delete_replication_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -783,13 +775,13 @@ def create_cache_subnet_group( ).get("subnets") if not sn: raise SaltInvocationError( - "Could not resolve Subnet Name {} to an ID.".format(subnet) + f"Could not resolve Subnet Name {subnet} to an ID." ) if len(sn) == 1: args["SubnetIds"] += [sn[0]["id"]] elif len(sn) > 1: raise CommandExecutionError( - "Subnet Name {} returned more than one ID.".format(subnet) + f"Subnet Name {subnet} returned more than one ID." ) args = {k: v for k, v in args.items() if not k.startswith("_")} return _create_resource( @@ -801,7 +793,7 @@ def create_cache_subnet_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -836,14 +828,14 @@ def modify_cache_subnet_group( args["SubnetIds"] += [sn[0]["id"]] elif len(sn) > 1: raise CommandExecutionError( - "Subnet Name {} returned more than one ID.".format(subnet) + f"Subnet Name {subnet} returned more than one ID." ) elif subnet.startswith("subnet-"): # Moderately safe assumption... :) Will be caught later if incorrect. args["SubnetIds"] += [subnet] else: raise SaltInvocationError( - "Could not resolve Subnet Name {} to an ID.".format(subnet) + f"Could not resolve Subnet Name {subnet} to an ID." ) args = {k: v for k, v in args.items() if not k.startswith("_")} return _modify_resource( @@ -855,7 +847,7 @@ def modify_cache_subnet_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -880,7 +872,7 @@ def delete_cache_subnet_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -948,7 +940,7 @@ def create_cache_security_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -973,7 +965,7 @@ def delete_cache_security_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -1264,7 +1256,7 @@ def create_cache_parameter_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) @@ -1289,5 +1281,5 @@ def delete_cache_parameter_group( key=key, keyid=keyid, profile=profile, - **args + **args, ) diff --git a/salt/modules/boto3_elasticsearch.py b/salt/modules/boto3_elasticsearch.py index 7462ea74d5d..60238776980 100644 --- a/salt/modules/boto3_elasticsearch.py +++ b/salt/modules/boto3_elasticsearch.py @@ -46,6 +46,7 @@ Connection module for Amazon Elasticsearch Service :codeauthor: Herbert Buurman :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto3_route53.py b/salt/modules/boto3_route53.py index 32c971356c2..5a0f730e018 100644 --- a/salt/modules/boto3_route53.py +++ b/salt/modules/boto3_route53.py @@ -913,10 +913,12 @@ def _aws_encode_changebatch(o): ) rr_idx += 1 if "AliasTarget" in o["Changes"][change_idx]["ResourceRecordSet"]: - o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"][ - "DNSName" - ] = _aws_encode( - o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"]["DNSName"] + o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"]["DNSName"] = ( + _aws_encode( + o["Changes"][change_idx]["ResourceRecordSet"]["AliasTarget"][ + "DNSName" + ] + ) ) change_idx += 1 return o @@ -1026,13 +1028,17 @@ def get_resource_records( if done: return ret args = {"HostedZoneId": HostedZoneId} - args.update( - {"StartRecordName": _aws_encode(next_rr_name)} - ) if next_rr_name else None + ( + args.update({"StartRecordName": _aws_encode(next_rr_name)}) + if next_rr_name + else None + ) # Grrr, can't specify type unless name is set... We'll do this via filtering later instead - args.update( - {"StartRecordType": next_rr_type} - ) if next_rr_name and next_rr_type else None + ( + args.update({"StartRecordType": next_rr_type}) + if next_rr_name and next_rr_type + else None + ) args.update({"StartRecordIdentifier": next_rr_id}) if next_rr_id else None try: r = conn.list_resource_record_sets(**args) diff --git a/salt/modules/boto3_sns.py b/salt/modules/boto3_sns.py index 65ab6283f51..197cd795e24 100644 --- a/salt/modules/boto3_sns.py +++ b/salt/modules/boto3_sns.py @@ -38,6 +38,7 @@ Connection module for Amazon SNS :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_apigateway.py b/salt/modules/boto_apigateway.py index dad8858edb5..ccaeb163ac5 100644 --- a/salt/modules/boto_apigateway.py +++ b/salt/modules/boto_apigateway.py @@ -74,6 +74,7 @@ Connection module for Amazon APIGateway message: error message """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -131,7 +132,7 @@ def _convert_datetime_str(response): if response: return dict( [ - (k, "{}".format(v)) if isinstance(v, datetime.date) else (k, v) + (k, f"{v}") if isinstance(v, datetime.date) else (k, v) for k, v in response.items() ] ) @@ -378,9 +379,9 @@ def create_api_resources( conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) for path_part in path_parts: if current_path == "/": - current_path = "{}{}".format(current_path, path_part) + current_path = f"{current_path}{path_part}" else: - current_path = "{}/{}".format(current_path, path_part) + current_path = f"{current_path}/{path_part}" r = describe_api_resource( restApiId, current_path, @@ -431,7 +432,7 @@ def delete_api_resources( conn.delete_resource(restApiId=restApiId, resourceId=resource["id"]) return {"deleted": True} else: - return {"deleted": False, "error": "no resource found by {}".format(path)} + return {"deleted": False, "error": f"no resource found by {path}"} except ClientError as e: return {"created": False, "error": __utils__["boto3.get_error"](e)} @@ -895,12 +896,12 @@ def overwrite_api_stage_variables( for old_var in old_vars: if old_var not in variables: patch_ops.append( - dict(op="remove", path="/variables/{}".format(old_var), value="") + dict(op="remove", path=f"/variables/{old_var}", value="") ) for var, val in variables.items(): if var not in old_vars or old_vars[var] != val: patch_ops.append( - dict(op="replace", path="/variables/{}".format(var), value=val) + dict(op="replace", path=f"/variables/{var}", value=val) ) if patch_ops: @@ -1622,7 +1623,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region=region, key=key, keyid=keyid, profile=profile ) - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def create_api_integration( @@ -1799,7 +1800,7 @@ def _validate_throttle(throttle): if throttle is not None: if not isinstance(throttle, dict): raise TypeError( - "throttle must be a dictionary, provided value: {}".format(throttle) + f"throttle must be a dictionary, provided value: {throttle}" ) @@ -1809,9 +1810,7 @@ def _validate_quota(quota): """ if quota is not None: if not isinstance(quota, dict): - raise TypeError( - "quota must be a dictionary, provided value: {}".format(quota) - ) + raise TypeError(f"quota must be a dictionary, provided value: {quota}") periods = ["DAY", "WEEK", "MONTH"] if "period" not in quota or quota["period"] not in periods: raise ValueError( diff --git a/salt/modules/boto_asg.py b/salt/modules/boto_asg.py index c52c7946791..9d915c34ddb 100644 --- a/salt/modules/boto_asg.py +++ b/salt/modules/boto_asg.py @@ -41,6 +41,7 @@ Connection module for Amazon Autoscale Groups :depends: boto :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -119,7 +120,7 @@ def exists(name, region=None, key=None, keyid=None, profile=None): if _conn: return True else: - msg = "The autoscale group does not exist in region {}".format(region) + msg = f"The autoscale group does not exist in region {region}" log.debug(msg) return False except boto.exception.BotoServerError as e: @@ -429,12 +430,12 @@ def update( key = tag.get("key") except KeyError: log.error("Tag missing key.") - return False, "Tag {} missing key".format(tag) + return False, f"Tag {tag} missing key" try: value = tag.get("value") except KeyError: log.error("Tag missing value.") - return False, "Tag {} missing value".format(tag) + return False, f"Tag {tag} missing value" propagate_at_launch = tag.get("propagate_at_launch", False) _tag = { "key": key, @@ -508,7 +509,7 @@ def update( retries -= 1 continue log.error(e) - msg = "Failed to update ASG {}".format(name) + msg = f"Failed to update ASG {name}" log.error(msg) return False, str(e) @@ -569,7 +570,7 @@ def delete(name, force=False, region=None, key=None, keyid=None, profile=None): while True: try: conn.delete_auto_scaling_group(name, force) - msg = "Deleted autoscale group {}.".format(name) + msg = f"Deleted autoscale group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: @@ -579,7 +580,7 @@ def delete(name, force=False, region=None, key=None, keyid=None, profile=None): retries -= 1 continue log.error(e) - msg = "Failed to delete autoscale group {}".format(name) + msg = f"Failed to delete autoscale group {name}" log.error(msg) return False @@ -821,7 +822,7 @@ def create_launch_configuration( retries -= 1 continue log.error(e) - msg = "Failed to create LC {}".format(name) + msg = f"Failed to create LC {name}" log.error(msg) return False @@ -850,7 +851,7 @@ def delete_launch_configuration(name, region=None, key=None, keyid=None, profile retries -= 1 continue log.error(e) - msg = "Failed to delete LC {}".format(name) + msg = f"Failed to delete LC {name}" log.error(msg) return False diff --git a/salt/modules/boto_cfn.py b/salt/modules/boto_cfn.py index 4c6b700482a..647bb185e42 100644 --- a/salt/modules/boto_cfn.py +++ b/salt/modules/boto_cfn.py @@ -28,6 +28,7 @@ Connection module for Amazon Cloud Formation :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -184,7 +185,7 @@ def create( stack_policy_url, ) except BotoServerError as e: - msg = "Failed to create stack {}.\n{}".format(name, e) + msg = f"Failed to create stack {name}.\n{e}" log.error(msg) log.debug(e) return False @@ -244,7 +245,7 @@ def update_stack( log.debug("Updated result is : %s.", update) return update except BotoServerError as e: - msg = "Failed to update stack {}.".format(name) + msg = f"Failed to update stack {name}." log.debug(e) log.error(msg) return str(e) @@ -265,7 +266,7 @@ def delete(name, region=None, key=None, keyid=None, profile=None): try: return conn.delete_stack(name) except BotoServerError as e: - msg = "Failed to create stack {}.".format(name) + msg = f"Failed to create stack {name}." log.error(msg) log.debug(e) return str(e) @@ -289,7 +290,7 @@ def get_template(name, region=None, key=None, keyid=None, profile=None): return template except BotoServerError as e: log.debug(e) - msg = "Template {} does not exist".format(name) + msg = f"Template {name} does not exist" log.error(msg) return str(e) @@ -320,6 +321,6 @@ def validate_template( return conn.validate_template(template_body, template_url) except BotoServerError as e: log.debug(e) - msg = "Error while trying to validate template {}.".format(template_body) + msg = f"Error while trying to validate template {template_body}." log.error(msg) return str(e) diff --git a/salt/modules/boto_cloudfront.py b/salt/modules/boto_cloudfront.py index 7e4db092d06..33ac1b76652 100644 --- a/salt/modules/boto_cloudfront.py +++ b/salt/modules/boto_cloudfront.py @@ -46,6 +46,7 @@ Connection module for Amazon CloudFront key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -255,7 +256,7 @@ def export_distributions(region=None, key=None, keyid=None, profile=None): {"config": config}, {"tags": tags}, ] - results["Manage CloudFront distribution {}".format(name)] = { + results[f"Manage CloudFront distribution {name}"] = { "boto_cloudfront.present": distribution_sls_data, } except botocore.exceptions.ClientError as exc: diff --git a/salt/modules/boto_cloudtrail.py b/salt/modules/boto_cloudtrail.py index 25c165bd424..0a789a86150 100644 --- a/salt/modules/boto_cloudtrail.py +++ b/salt/modules/boto_cloudtrail.py @@ -45,6 +45,7 @@ The dependencies listed above can be installed via package or pip. region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -424,7 +425,7 @@ def _get_trail_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:cloudtrail:{}:{}:trail/{}".format(region, account_id, name) + return f"arn:aws:cloudtrail:{region}:{account_id}:trail/{name}" def add_tags(Name, region=None, key=None, keyid=None, profile=None, **kwargs): diff --git a/salt/modules/boto_cloudwatch.py b/salt/modules/boto_cloudwatch.py index f7967d23876..c3a36561f71 100644 --- a/salt/modules/boto_cloudwatch.py +++ b/salt/modules/boto_cloudwatch.py @@ -40,6 +40,7 @@ Connection module for Amazon CloudWatch :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_cloudwatch_event.py b/salt/modules/boto_cloudwatch_event.py index 1e8def652d1..7729cf715b8 100644 --- a/salt/modules/boto_cloudwatch_event.py +++ b/salt/modules/boto_cloudwatch_event.py @@ -40,6 +40,7 @@ Connection module for Amazon CloudWatch Events :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -214,7 +215,7 @@ def describe(Name, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} @@ -270,7 +271,7 @@ def list_targets(Rule, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} @@ -299,7 +300,7 @@ def put_targets(Rule, Targets, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} @@ -328,5 +329,5 @@ def remove_targets(Rule, Ids, region=None, key=None, keyid=None, profile=None): except ClientError as e: err = __utils__["boto3.get_error"](e) if e.response.get("Error", {}).get("Code") == "RuleNotFoundException": - return {"error": "Rule {} not found".format(Rule)} + return {"error": f"Rule {Rule} not found"} return {"error": __utils__["boto3.get_error"](e)} diff --git a/salt/modules/boto_cognitoidentity.py b/salt/modules/boto_cognitoidentity.py index 5d8e7d8aa8f..37943d28c1f 100644 --- a/salt/modules/boto_cognitoidentity.py +++ b/salt/modules/boto_cognitoidentity.py @@ -72,6 +72,7 @@ Connection module for Amazon CognitoIdentity :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -147,7 +148,6 @@ def describe_identity_pools( keyid=None, profile=None, ): - """ Given an identity pool name, (optionally if an identity pool id is given, the given name will be ignored) @@ -365,7 +365,7 @@ def set_identity_pool_roles( if role_arn is None: return { "set": False, - "error": "invalid AuthenticatedRole {}".format(AuthenticatedRole), + "error": f"invalid AuthenticatedRole {AuthenticatedRole}", } AuthenticatedRole = role_arn @@ -447,9 +447,9 @@ def update_identity_pool( if AllowUnauthenticatedIdentities != request_params.get( "AllowUnauthenticatedIdentities" ): - request_params[ - "AllowUnauthenticatedIdentities" - ] = AllowUnauthenticatedIdentities + request_params["AllowUnauthenticatedIdentities"] = ( + AllowUnauthenticatedIdentities + ) current_val = request_params.pop("SupportedLoginProviders", None) if SupportedLoginProviders is not None and SupportedLoginProviders != current_val: diff --git a/salt/modules/boto_datapipeline.py b/salt/modules/boto_datapipeline.py index 52d5872d360..b2cc6ca773f 100644 --- a/salt/modules/boto_datapipeline.py +++ b/salt/modules/boto_datapipeline.py @@ -6,7 +6,6 @@ Connection module for Amazon Data Pipeline :depends: boto3 """ - import logging import salt.utils.versions @@ -182,7 +181,7 @@ def pipeline_id_from_name(name, region=None, key=None, keyid=None, profile=None) if pipeline["name"] == name: r["result"] = pipeline["id"] return r - r["error"] = "No pipeline found with name={}".format(name) + r["error"] = f"No pipeline found with name={name}" return r diff --git a/salt/modules/boto_dynamodb.py b/salt/modules/boto_dynamodb.py index 29e2757f63b..10201cb48e0 100644 --- a/salt/modules/boto_dynamodb.py +++ b/salt/modules/boto_dynamodb.py @@ -40,6 +40,7 @@ Connection module for Amazon DynamoDB :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_ec2.py b/salt/modules/boto_ec2.py index be4edce11dc..f5f8a7fd3e6 100644 --- a/salt/modules/boto_ec2.py +++ b/salt/modules/boto_ec2.py @@ -39,6 +39,7 @@ as a passed in dict, or as a string to pull from pillars or minion config: :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -658,7 +659,6 @@ def find_instances( in_states=None, filters=None, ): - """ Given instance properties, find and return matching instance ids @@ -685,7 +685,7 @@ def find_instances( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value if filters: filter_parameters["filters"].update(filters) @@ -785,7 +785,6 @@ def find_images( profile=None, return_objs=False, ): - """ Given image properties, find and return matching AMI ids @@ -811,7 +810,7 @@ def find_images( filter_parameters["filters"]["name"] = ami_name if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value images = conn.get_all_images(**filter_parameters) log.debug( "The filters criteria %s matched the following images:%s", @@ -885,7 +884,6 @@ def get_id( in_states=None, filters=None, ): - """ Given instance properties, return the instance id if it exists. @@ -1518,9 +1516,7 @@ def get_attribute( " command." ) if attribute not in attribute_list: - raise SaltInvocationError( - "Attribute must be one of: {}.".format(attribute_list) - ) + raise SaltInvocationError(f"Attribute must be one of: {attribute_list}.") try: if instance_name: instances = find_instances( @@ -1611,9 +1607,7 @@ def set_attribute( " command." ) if attribute not in attribute_list: - raise SaltInvocationError( - "Attribute must be one of: {}.".format(attribute_list) - ) + raise SaltInvocationError(f"Attribute must be one of: {attribute_list}.") try: if instance_name: instances = find_instances( @@ -1824,7 +1818,7 @@ def create_network_interface( ) vpc_id = vpc_id.get("vpc_id") if not vpc_id: - msg = "subnet_id {} does not map to a valid vpc id.".format(subnet_id) + msg = f"subnet_id {subnet_id} does not map to a valid vpc id." r["error"] = {"message": msg} return r _groups = __salt__["boto_secgroup.convert_to_group_ids"]( @@ -2233,7 +2227,7 @@ def set_volumes_tags( profile=profile, ) if not instance_id: - msg = "Couldn't resolve instance Name {} to an ID.".format(v) + msg = f"Couldn't resolve instance Name {v} to an ID." raise CommandExecutionError(msg) new_filters["attachment.instance_id"] = instance_id else: @@ -2295,10 +2289,10 @@ def set_volumes_tags( profile=profile, ): ret["success"] = False - ret[ - "comment" - ] = "Failed to remove tags on vol.id {}: {}".format( - vol.id, remove + ret["comment"] = ( + "Failed to remove tags on vol.id {}: {}".format( + vol.id, remove + ) ) return ret if changes["old"] or changes["new"]: diff --git a/salt/modules/boto_efs.py b/salt/modules/boto_efs.py index 70f226bf67c..800aa7977f6 100644 --- a/salt/modules/boto_efs.py +++ b/salt/modules/boto_efs.py @@ -47,7 +47,6 @@ Connection module for Amazon EFS :depends: boto3 """ - import logging import salt.utils.versions diff --git a/salt/modules/boto_elasticache.py b/salt/modules/boto_elasticache.py index 43f183b0f39..fdcec9d4962 100644 --- a/salt/modules/boto_elasticache.py +++ b/salt/modules/boto_elasticache.py @@ -40,6 +40,7 @@ Connection module for Amazon Elasticache :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -156,7 +157,7 @@ def create_replication_group( if config["status"] == "available": return True except boto.exception.BotoServerError as e: - msg = "Failed to create replication group {}.".format(name) + msg = f"Failed to create replication group {name}." log.error(msg) log.debug(e) return {} @@ -178,12 +179,12 @@ def delete_replication_group(name, region=None, key=None, keyid=None, profile=No return False try: conn.delete_replication_group(name) - msg = "Deleted ElastiCache replication group {}.".format(name) + msg = f"Deleted ElastiCache replication group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: log.debug(e) - msg = "Failed to delete ElastiCache replication group {}".format(name) + msg = f"Failed to delete ElastiCache replication group {name}" log.error(msg) return False @@ -207,7 +208,7 @@ def describe_replication_group( try: cc = conn.describe_replication_groups(name) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -277,7 +278,7 @@ def get_config(name, region=None, key=None, keyid=None, profile=None): try: cc = conn.describe_cache_clusters(name, show_cache_node_info=True) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -356,7 +357,7 @@ def get_node_host(name, region=None, key=None, keyid=None, profile=None): try: cc = conn.describe_cache_clusters(name, show_cache_node_info=True) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -383,7 +384,7 @@ def get_group_host(name, region=None, key=None, keyid=None, profile=None): try: cc = conn.describe_replication_groups(name) except boto.exception.BotoServerError as e: - msg = "Failed to get config for cache cluster {}.".format(name) + msg = f"Failed to get config for cache cluster {name}." log.error(msg) log.debug(e) return {} @@ -464,7 +465,7 @@ def subnet_group_exists( try: ec = conn.describe_cache_subnet_groups(cache_subnet_group_name=name) if not ec: - msg = "ElastiCache subnet group does not exist in region {}".format(region) + msg = f"ElastiCache subnet group does not exist in region {region}" log.debug(msg) return False return True @@ -515,14 +516,14 @@ def create_subnet_group( try: ec = conn.create_cache_subnet_group(name, description, subnet_ids) if not ec: - msg = "Failed to create ElastiCache subnet group {}".format(name) + msg = f"Failed to create ElastiCache subnet group {name}" log.error(msg) return False log.info("Created ElastiCache subnet group %s", name) return True except boto.exception.BotoServerError as e: log.debug(e) - msg = "Failed to create ElastiCache subnet group {}".format(name) + msg = f"Failed to create ElastiCache subnet group {name}" log.error(msg) return False @@ -544,12 +545,12 @@ def get_cache_subnet_group(name, region=None, key=None, keyid=None, profile=None csg = csg["DescribeCacheSubnetGroupsResponse"] csg = csg["DescribeCacheSubnetGroupsResult"]["CacheSubnetGroups"][0] except boto.exception.BotoServerError as e: - msg = "Failed to get cache subnet group {}.".format(name) + msg = f"Failed to get cache subnet group {name}." log.error(msg) log.debug(e) return False except (IndexError, TypeError, KeyError): - msg = "Failed to get cache subnet group {} (2).".format(name) + msg = f"Failed to get cache subnet group {name} (2)." log.error(msg) return False ret = {} @@ -589,12 +590,12 @@ def delete_subnet_group(name, region=None, key=None, keyid=None, profile=None): return False try: conn.delete_cache_subnet_group(name) - msg = "Deleted ElastiCache subnet group {}.".format(name) + msg = f"Deleted ElastiCache subnet group {name}." log.info(msg) return True except boto.exception.BotoServerError as e: log.debug(e) - msg = "Failed to delete ElastiCache subnet group {}".format(name) + msg = f"Failed to delete ElastiCache subnet group {name}" log.error(msg) return False @@ -665,7 +666,7 @@ def create( return True log.info("Created cache cluster %s.", name) except boto.exception.BotoServerError as e: - msg = "Failed to create cache cluster {}.".format(name) + msg = f"Failed to create cache cluster {name}." log.error(msg) log.debug(e) return False @@ -698,7 +699,7 @@ def delete(name, wait=False, region=None, key=None, keyid=None, profile=None): log.info("Deleted cache cluster %s.", name) return True except boto.exception.BotoServerError as e: - msg = "Failed to delete cache cluster {}.".format(name) + msg = f"Failed to delete cache cluster {name}." log.error(msg) log.debug(e) return False @@ -723,7 +724,7 @@ def create_cache_security_group( log.info("Created cache security group %s.", name) return True else: - msg = "Failed to create cache security group {}.".format(name) + msg = f"Failed to create cache security group {name}." log.error(msg) return False @@ -745,7 +746,7 @@ def delete_cache_security_group(name, region=None, key=None, keyid=None, profile log.info("Deleted cache security group %s.", name) return True else: - msg = "Failed to delete cache security group {}.".format(name) + msg = f"Failed to delete cache security group {name}." log.error(msg) return False diff --git a/salt/modules/boto_elasticsearch_domain.py b/salt/modules/boto_elasticsearch_domain.py index 050ef2f011b..ff11574685c 100644 --- a/salt/modules/boto_elasticsearch_domain.py +++ b/salt/modules/boto_elasticsearch_domain.py @@ -70,6 +70,7 @@ Connection module for Amazon Elasticsearch Service :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -273,7 +274,7 @@ def create( except ValueError as e: return { "updated": False, - "error": "Error parsing {}: {}".format(k, e.message), + "error": f"Error parsing {k}: {e.message}", } kwargs[k] = val if "AccessPolicies" in kwargs: @@ -364,7 +365,7 @@ def update( except ValueError as e: return { "updated": False, - "error": "Error parsing {}: {}".format(k, e.message), + "error": f"Error parsing {k}: {e.message}", } call_args[k] = val if "AccessPolicies" in call_args: diff --git a/salt/modules/boto_elb.py b/salt/modules/boto_elb.py index 310b91134bf..5c5d3c016b4 100644 --- a/salt/modules/boto_elb.py +++ b/salt/modules/boto_elb.py @@ -40,6 +40,7 @@ Connection module for Amazon ELB :depends: boto >= 2.33.0 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -1101,9 +1102,9 @@ def _build_tag_param_list(params, tags): i = 1 for key in keys: value = tags[key] - params["Tags.member.{}.Key".format(i)] = key + params[f"Tags.member.{i}.Key"] = key if value is not None: - params["Tags.member.{}.Value".format(i)] = value + params[f"Tags.member.{i}.Value"] = value i += 1 diff --git a/salt/modules/boto_elbv2.py b/salt/modules/boto_elbv2.py index d91927caa67..7754ef1ef86 100644 --- a/salt/modules/boto_elbv2.py +++ b/salt/modules/boto_elbv2.py @@ -36,6 +36,7 @@ Connection module for Amazon ALB :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_iam.py b/salt/modules/boto_iam.py index 521b1ff7140..54322e12eb5 100644 --- a/salt/modules/boto_iam.py +++ b/salt/modules/boto_iam.py @@ -33,6 +33,7 @@ Connection module for Amazon IAM :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -1733,7 +1734,7 @@ def _get_policy_arn(name, region=None, key=None, keyid=None, profile=None): return name account_id = get_account_id(region=region, key=key, keyid=keyid, profile=profile) - return "arn:aws:iam::{}:policy/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:policy/{name}" def policy_exists(policy_name, region=None, key=None, keyid=None, profile=None): diff --git a/salt/modules/boto_iot.py b/salt/modules/boto_iot.py index 1243a1700f9..7df25b47acf 100644 --- a/salt/modules/boto_iot.py +++ b/salt/modules/boto_iot.py @@ -45,6 +45,7 @@ The dependencies listed above can be installed via package or pip. region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -148,7 +149,7 @@ def describe_thing_type(thingTypeName, region=None, key=None, keyid=None, profil for dtype in ("creationDate", "deprecationDate"): dval = thingTypeMetadata.get(dtype) if dval and isinstance(dval, datetime.date): - thingTypeMetadata[dtype] = "{}".format(dval) + thingTypeMetadata[dtype] = f"{dval}" return {"thing_type": res} else: return {"thing_type": None} @@ -915,7 +916,7 @@ def list_topic_rules( conn.list_topic_rules, marker_flag="nextToken", marker_arg="nextToken", - **kwargs + **kwargs, ): rules.extend(ret["rules"]) if not bool(rules): diff --git a/salt/modules/boto_kinesis.py b/salt/modules/boto_kinesis.py index 846defa5d6a..d2d999a733c 100644 --- a/salt/modules/boto_kinesis.py +++ b/salt/modules/boto_kinesis.py @@ -41,6 +41,7 @@ Connection module for Amazon Kinesis :depends: boto3 """ + # keep lint from choking on _get_conn # pylint: disable=E0602 @@ -491,7 +492,7 @@ def reshard( # merge next_shard_id = _get_next_open_shard(stream_details, shard_id) if not next_shard_id: - r["error"] = "failed to find next shard after {}".format(shard_id) + r["error"] = f"failed to find next shard after {shard_id}" return r if force: log.debug( diff --git a/salt/modules/boto_kms.py b/salt/modules/boto_kms.py index ac106655d5b..70a172d51c7 100644 --- a/salt/modules/boto_kms.py +++ b/salt/modules/boto_kms.py @@ -32,6 +32,7 @@ Connection module for Amazon KMS :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_lambda.py b/salt/modules/boto_lambda.py index 5dcd82a3634..87ef561c3c5 100644 --- a/salt/modules/boto_lambda.py +++ b/salt/modules/boto_lambda.py @@ -74,6 +74,7 @@ as a passed in dict, or as a string to pull from pillars or minion config: message: error message """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -176,7 +177,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def _filedata(infile): @@ -272,7 +273,7 @@ def create_function( dlZipFile = __salt__["cp.cache_file"](path=ZipFile) if dlZipFile is False: ret["result"] = False - ret["comment"] = "Failed to cache ZipFile `{}`.".format(ZipFile) + ret["comment"] = f"Failed to cache ZipFile `{ZipFile}`." return ret ZipFile = dlZipFile code = { @@ -313,7 +314,7 @@ def create_function( Timeout=Timeout, MemorySize=MemorySize, Publish=Publish, - **kwargs + **kwargs, ) except ClientError as e: if ( @@ -645,7 +646,7 @@ def add_permission( StatementId=StatementId, Action=Action, Principal=str(Principal), - **kwargs + **kwargs, ) return {"updated": True} except ClientError as e: diff --git a/salt/modules/boto_rds.py b/salt/modules/boto_rds.py index 129c80bc6fe..9c65ee737ea 100644 --- a/salt/modules/boto_rds.py +++ b/salt/modules/boto_rds.py @@ -40,6 +40,7 @@ Connection module for Amazon RDS :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 # pylint whinging perfectly valid code @@ -294,9 +295,7 @@ def create( if wait_status: wait_stati = ["available", "modifying", "backing-up"] if wait_status not in wait_stati: - raise SaltInvocationError( - "wait_status can be one of: {}".format(wait_stati) - ) + raise SaltInvocationError(f"wait_status can be one of: {wait_stati}") if vpc_security_groups: v_tmp = __salt__["boto_secgroup.convert_to_group_ids"]( groups=vpc_security_groups, @@ -336,7 +335,7 @@ def create( if not wait_status: return { "created": True, - "message": "RDS instance {} created.".format(name), + "message": f"RDS instance {name} created.", } while True: @@ -408,14 +407,14 @@ def create_read_replica( if not res.get("exists"): return { "exists": bool(res), - "message": "RDS instance source {} does not exists.".format(source_name), + "message": f"RDS instance source {source_name} does not exists.", } res = __salt__["boto_rds.exists"](name, tags, region, key, keyid, profile) if res.get("exists"): return { "exists": bool(res), - "message": "RDS replica instance {} already exists.".format(name), + "message": f"RDS replica instance {name} already exists.", } try: @@ -444,7 +443,7 @@ def create_read_replica( Tags=taglist, DBSubnetGroupName=db_subnet_group_name, StorageType=storage_type, - **kwargs + **kwargs, ) return {"exists": bool(rds_replica)} @@ -535,12 +534,12 @@ def create_parameter_group( if not rds: return { "created": False, - "message": "Failed to create RDS parameter group {}".format(name), + "message": f"Failed to create RDS parameter group {name}", } return { "exists": bool(rds), - "message": "Created RDS parameter group {}".format(name), + "message": f"Created RDS parameter group {name}", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -617,7 +616,7 @@ def update_parameter_group( if not res.get("exists"): return { "exists": bool(res), - "message": "RDS parameter group {} does not exist.".format(name), + "message": f"RDS parameter group {name} does not exist.", } param_list = [] @@ -662,7 +661,7 @@ def describe(name, tags=None, region=None, key=None, keyid=None, profile=None): if not res.get("exists"): return { "exists": bool(res), - "message": "RDS instance {} does not exist.".format(name), + "message": f"RDS instance {name} does not exist.", } try: @@ -867,7 +866,7 @@ def delete( if not wait_for_deletion: return { "deleted": bool(res), - "message": "Deleted RDS instance {}.".format(name), + "message": f"Deleted RDS instance {name}.", } start_time = time.time() @@ -883,7 +882,7 @@ def delete( if not res.get("exists"): return { "deleted": bool(res), - "message": "Deleted RDS instance {} completely.".format(name), + "message": f"Deleted RDS instance {name} completely.", } if time.time() - start_time > timeout: @@ -922,12 +921,12 @@ def delete_option_group(name, region=None, key=None, keyid=None, profile=None): if not res: return { "deleted": bool(res), - "message": "Failed to delete RDS option group {}.".format(name), + "message": f"Failed to delete RDS option group {name}.", } return { "deleted": bool(res), - "message": "Deleted RDS option group {}.".format(name), + "message": f"Deleted RDS option group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -952,7 +951,7 @@ def delete_parameter_group(name, region=None, key=None, keyid=None, profile=None r = conn.delete_db_parameter_group(DBParameterGroupName=name) return { "deleted": bool(r), - "message": "Deleted RDS parameter group {}.".format(name), + "message": f"Deleted RDS parameter group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -977,7 +976,7 @@ def delete_subnet_group(name, region=None, key=None, keyid=None, profile=None): r = conn.delete_db_subnet_group(DBSubnetGroupName=name) return { "deleted": bool(r), - "message": "Deleted RDS subnet group {}.".format(name), + "message": f"Deleted RDS subnet group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -1024,12 +1023,12 @@ def describe_parameter_group( if not info: return { "results": bool(info), - "message": "Failed to get RDS description for group {}.".format(name), + "message": f"Failed to get RDS description for group {name}.", } return { "results": bool(info), - "message": "Got RDS descrition for group {}.".format(name), + "message": f"Got RDS descrition for group {name}.", } except ClientError as e: return {"error": __utils__["boto3.get_error"](e)} @@ -1058,7 +1057,7 @@ def describe_parameters( if not res.get("exists"): return { "result": False, - "message": "Parameter group {} does not exist".format(name), + "message": f"Parameter group {name} does not exist", } try: @@ -1166,7 +1165,7 @@ def modify_db_instance( if not res.get("exists"): return { "modified": False, - "message": "RDS db instance {} does not exist.".format(name), + "message": f"RDS db instance {name} does not exist.", } try: @@ -1189,12 +1188,12 @@ def modify_db_instance( if not info: return { "modified": bool(info), - "message": "Failed to modify RDS db instance {}.".format(name), + "message": f"Failed to modify RDS db instance {name}.", } return { "modified": bool(info), - "message": "Modified RDS db instance {}.".format(name), + "message": f"Modified RDS db instance {name}.", "results": dict(info), } except ClientError as e: diff --git a/salt/modules/boto_route53.py b/salt/modules/boto_route53.py index 500e6f2cb78..bee6cff4d3a 100644 --- a/salt/modules/boto_route53.py +++ b/salt/modules/boto_route53.py @@ -41,6 +41,7 @@ Connection module for Amazon Route53 :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -589,7 +590,7 @@ def get_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return None _type = record_type.upper() @@ -698,7 +699,7 @@ def add_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return False _type = record_type.upper() @@ -797,7 +798,7 @@ def update_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return False _type = record_type.upper() @@ -886,7 +887,7 @@ def delete_record( else: _zone = conn.get_zone(zone) if not _zone: - msg = "Failed to retrieve zone {}".format(zone) + msg = f"Failed to retrieve zone {zone}" log.error(msg) return False _type = record_type.upper() diff --git a/salt/modules/boto_s3.py b/salt/modules/boto_s3.py index bef68657e9b..54939033667 100644 --- a/salt/modules/boto_s3.py +++ b/salt/modules/boto_s3.py @@ -46,6 +46,7 @@ Connection module for Amazon S3 using boto3 :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_s3_bucket.py b/salt/modules/boto_s3_bucket.py index 9fc2417cbfc..d461c320a76 100644 --- a/salt/modules/boto_s3_bucket.py +++ b/salt/modules/boto_s3_bucket.py @@ -45,6 +45,7 @@ The dependencies listed above can be installed via package or pip. region: us-east-1 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 # disable complaints about perfectly valid non-assignment code @@ -773,7 +774,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def put_replication( diff --git a/salt/modules/boto_secgroup.py b/salt/modules/boto_secgroup.py index 97941147933..9ecdb782900 100644 --- a/salt/modules/boto_secgroup.py +++ b/salt/modules/boto_secgroup.py @@ -40,6 +40,7 @@ Connection module for Amazon Security Groups :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -509,7 +510,7 @@ def create( log.info("Created security group %s.", name) return True else: - msg = "Failed to create security group {}.".format(name) + msg = f"Failed to create security group {name}." log.error(msg) return False @@ -552,7 +553,7 @@ def delete( log.info("Deleted security group %s with id %s.", group.name, group.id) return True else: - msg = "Failed to delete security group {}.".format(name) + msg = f"Failed to delete security group {name}." log.error(msg) return False else: @@ -776,7 +777,7 @@ def _find_vpcs( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) log.debug( diff --git a/salt/modules/boto_sns.py b/salt/modules/boto_sns.py index 7df58b95e5a..2814f56ea41 100644 --- a/salt/modules/boto_sns.py +++ b/salt/modules/boto_sns.py @@ -38,6 +38,7 @@ Connection module for Amazon SNS :depends: boto """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -235,7 +236,7 @@ def get_arn(name, region=None, key=None, keyid=None, profile=None): account_id = __salt__["boto_iam.get_account_id"]( region=region, key=key, keyid=keyid, profile=profile ) - return "arn:aws:sns:{}:{}:{}".format(_get_region(region, profile), account_id, name) + return f"arn:aws:sns:{_get_region(region, profile)}:{account_id}:{name}" def _get_region(region=None, profile=None): @@ -252,7 +253,7 @@ def _get_region(region=None, profile=None): def _subscriptions_cache_key(name): - return "{}_{}_subscriptions".format(_cache_get_key(), name) + return f"{_cache_get_key()}_{name}_subscriptions" def _invalidate_cache(): diff --git a/salt/modules/boto_sqs.py b/salt/modules/boto_sqs.py index c2a572ab248..cb9033d4ce4 100644 --- a/salt/modules/boto_sqs.py +++ b/salt/modules/boto_sqs.py @@ -40,6 +40,7 @@ Connection module for Amazon SQS :depends: boto3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/boto_ssm.py b/salt/modules/boto_ssm.py index f2908a46edc..475279a9153 100644 --- a/salt/modules/boto_ssm.py +++ b/salt/modules/boto_ssm.py @@ -12,6 +12,7 @@ Connection module for Amazon SSM :depends: boto3 """ + import logging import salt.utils.json as json diff --git a/salt/modules/boto_vpc.py b/salt/modules/boto_vpc.py index ee7a757e2b2..289a7a2fb78 100644 --- a/salt/modules/boto_vpc.py +++ b/salt/modules/boto_vpc.py @@ -120,6 +120,7 @@ Deleting VPC peering connection via this module salt myminion boto_vpc.delete_vpc_peering_connection conn_id=pcx-8a8939e3 """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -242,7 +243,7 @@ def _create_resource( key=None, keyid=None, profile=None, - **kwargs + **kwargs, ): """ Create a VPC resource. Returns the resource id if created, or False @@ -265,9 +266,7 @@ def _create_resource( ): return { "created": False, - "error": { - "message": "A {} named {} already exists.".format(resource, name) - }, + "error": {"message": f"A {resource} named {name} already exists."}, } r = create_resource(**kwargs) @@ -293,9 +292,9 @@ def _create_resource( return {"created": True, "id": r.id} else: if name: - e = "{} {} was not created.".format(resource, name) + e = f"{resource} {name} was not created." else: - e = "{} was not created.".format(resource) + e = f"{resource} was not created." log.warning(e) return {"created": False, "error": {"message": e}} except BotoServerError as e: @@ -310,7 +309,7 @@ def _delete_resource( key=None, keyid=None, profile=None, - **kwargs + **kwargs, ): """ Delete a VPC resource. Returns True if successful, otherwise False. @@ -337,9 +336,7 @@ def _delete_resource( if not resource_id: return { "deleted": False, - "error": { - "message": "{} {} does not exist.".format(resource, name) - }, + "error": {"message": f"{resource} {name} does not exist."}, } if delete_resource(resource_id, **kwargs): @@ -356,9 +353,9 @@ def _delete_resource( return {"deleted": True} else: if name: - e = "{} {} was not deleted.".format(resource, name) + e = f"{resource} {name} was not deleted." else: - e = "{} was not deleted.".format(resource) + e = f"{resource} was not deleted." return {"deleted": False, "error": {"message": e}} except BotoServerError as e: return {"deleted": False, "error": __utils__["boto.get_error"](e)} @@ -383,7 +380,7 @@ def _get_resource( conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) - f = "get_all_{}".format(resource) + f = f"get_all_{resource}" if not f.endswith("s"): f = f + "s" get_resources = getattr(conn, f) @@ -392,7 +389,7 @@ def _get_resource( if name: filter_parameters["filters"] = {"tag:Name": name} if resource_id: - filter_parameters["{}_ids".format(resource)] = resource_id + filter_parameters[f"{resource}_ids"] = resource_id try: r = get_resources(**filter_parameters) @@ -416,7 +413,7 @@ def _get_resource( return r[0] else: raise CommandExecutionError( - 'Found more than one {} named "{}"'.format(resource, name) + f'Found more than one {resource} named "{name}"' ) else: return None @@ -446,7 +443,7 @@ def _find_resources( conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) - f = "get_all_{}".format(resource) + f = f"get_all_{resource}" if not f.endswith("s"): f = f + "s" get_resources = getattr(conn, f) @@ -455,10 +452,10 @@ def _find_resources( if name: filter_parameters["filters"] = {"tag:Name": name} if resource_id: - filter_parameters["{}_ids".format(resource)] = resource_id + filter_parameters[f"{resource}_ids"] = resource_id if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value try: r = get_resources(**filter_parameters) @@ -579,7 +576,6 @@ def _find_vpcs( keyid=None, profile=None, ): - """ Given VPC properties, find and return matching VPC ids. """ @@ -601,7 +597,7 @@ def _find_vpcs( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) log.debug( @@ -868,7 +864,7 @@ def delete( if not vpc_id: return { "deleted": False, - "error": {"message": "VPC {} not found".format(vpc_name)}, + "error": {"message": f"VPC {vpc_name} not found"}, } if conn.delete_vpc(vpc_id): @@ -1013,7 +1009,7 @@ def describe_vpcs( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) @@ -1055,7 +1051,7 @@ def _find_subnets(subnet_name=None, vpc_id=None, cidr=None, tags=None, conn=None if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value subnets = conn.get_all_subnets(**filter_parameters) log.debug( @@ -1108,9 +1104,7 @@ def create_subnet( if not vpc_id: return { "created": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } except BotoServerError as e: return {"created": False, "error": __utils__["boto.get_error"](e)} @@ -1222,7 +1216,7 @@ def subnet_exists( filter_parameters["filters"]["cidr"] = cidr if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value if zones: filter_parameters["filters"]["availability_zone"] = zones @@ -1419,9 +1413,9 @@ def describe_subnets( subnet["id"], subnet["vpc_id"], conn=conn ) if explicit_route_table_assoc: - subnet[ - "explicit_route_table_association_id" - ] = explicit_route_table_assoc + subnet["explicit_route_table_association_id"] = ( + explicit_route_table_assoc + ) subnets_list.append(subnet) return {"subnets": subnets_list} @@ -1462,9 +1456,7 @@ def create_internet_gateway( if not vpc_id: return { "created": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } r = _create_resource( @@ -1622,7 +1614,7 @@ def _find_nat_gateways( conn3.describe_nat_gateways, marker_flag="NextToken", marker_arg="NextToken", - **filter_parameters + **filter_parameters, ): for gw in ret.get("NatGateways", []): if gw.get("State") in states: @@ -1769,9 +1761,7 @@ def create_nat_gateway( if not subnet_id: return { "created": False, - "error": { - "message": "Subnet {} does not exist.".format(subnet_name) - }, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } else: if not _get_resource( @@ -1784,7 +1774,7 @@ def create_nat_gateway( ): return { "created": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_id)}, + "error": {"message": f"Subnet {subnet_id} does not exist."}, } conn3 = _get_conn3(region=region, key=key, keyid=keyid, profile=profile) @@ -2035,9 +2025,7 @@ def create_dhcp_options( if not vpc_id: return { "created": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } r = _create_resource( @@ -2177,9 +2165,7 @@ def associate_dhcp_options_to_vpc( if not vpc_id: return { "associated": False, - "error": { - "message": "VPC {} does not exist.".format(vpc_name or vpc_id) - }, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) @@ -2284,7 +2270,7 @@ def create_network_acl( if not vpc_id: return { "created": False, - "error": {"message": "VPC {} does not exist.".format(_id)}, + "error": {"message": f"VPC {_id} does not exist."}, } if all((subnet_id, subnet_name)): @@ -2298,7 +2284,7 @@ def create_network_acl( if not subnet_id: return { "created": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_name)}, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } elif subnet_id: if not _get_resource( @@ -2311,7 +2297,7 @@ def create_network_acl( ): return { "created": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_id)}, + "error": {"message": f"Subnet {subnet_id} does not exist."}, } r = _create_resource( @@ -2468,9 +2454,7 @@ def associate_network_acl_to_subnet( if not network_acl_id: return { "associated": False, - "error": { - "message": "Network ACL {} does not exist.".format(network_acl_name) - }, + "error": {"message": f"Network ACL {network_acl_name} does not exist."}, } if subnet_name: subnet_id = _get_resource_id( @@ -2479,7 +2463,7 @@ def associate_network_acl_to_subnet( if not subnet_id: return { "associated": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_name)}, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } try: conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) @@ -2547,9 +2531,7 @@ def disassociate_network_acl( if not subnet_id: return { "disassociated": False, - "error": { - "message": "Subnet {} does not exist.".format(subnet_name) - }, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } if vpc_name or vpc_id: @@ -2592,7 +2574,7 @@ def _create_network_acl_entry( for v in ("rule_number", "protocol", "rule_action", "cidr_block"): if locals()[v] is None: - raise SaltInvocationError("{} is required.".format(v)) + raise SaltInvocationError(f"{v} is required.") if network_acl_name: network_acl_id = _get_resource_id( @@ -2742,7 +2724,7 @@ def delete_network_acl_entry( for v in ("rule_number", "egress"): if locals()[v] is None: - raise SaltInvocationError("{} is required.".format(v)) + raise SaltInvocationError(f"{v} is required.") if network_acl_name: network_acl_id = _get_resource_id( @@ -2805,7 +2787,7 @@ def create_route_table( if not vpc_id: return { "created": False, - "error": {"message": "VPC {} does not exist.".format(vpc_name or vpc_id)}, + "error": {"message": f"VPC {vpc_name or vpc_id} does not exist."}, } return _create_resource( @@ -2941,7 +2923,7 @@ def route_exists( if tags: for tag_name, tag_value in tags.items(): - filter_parameters["filters"]["tag:{}".format(tag_name)] = tag_value + filter_parameters["filters"][f"tag:{tag_name}"] = tag_value route_tables = conn.get_all_route_tables(**filter_parameters) @@ -3013,7 +2995,7 @@ def associate_route_table( if not subnet_id: return { "associated": False, - "error": {"message": "Subnet {} does not exist.".format(subnet_name)}, + "error": {"message": f"Subnet {subnet_name} does not exist."}, } if all((route_table_id, route_table_name)): @@ -3032,9 +3014,7 @@ def associate_route_table( if not route_table_id: return { "associated": False, - "error": { - "message": "Route table {} does not exist.".format(route_table_name) - }, + "error": {"message": f"Route table {route_table_name} does not exist."}, } try: @@ -3484,7 +3464,7 @@ def describe_route_tables( if tags: for tag_name, tag_value in tags.items(): filter_parameters["Filters"].append( - {"Name": "tag:{}".format(tag_name), "Values": [tag_value]} + {"Name": f"tag:{tag_name}", "Values": [tag_value]} ) route_tables = conn3.describe_route_tables(**filter_parameters).get( @@ -3598,7 +3578,7 @@ def _maybe_name_route_table(conn, vpcid, vpc_name): log.warning("no default route table found") return - name = "{}-default-table".format(vpc_name) + name = f"{vpc_name}-default-table" _maybe_set_name_tag(name, default_table) log.debug("Default route table name was set to: %s on vpc %s", name, vpcid) @@ -3755,9 +3735,7 @@ def request_vpc_peering_connection( vpc_name=peer_vpc_name, region=region, key=key, keyid=keyid, profile=profile ) if not peer_vpc_id: - return { - "error": "Could not resolve VPC name {} to an ID".format(peer_vpc_name) - } + return {"error": f"Could not resolve VPC name {peer_vpc_name} to an ID"} peering_params = { "VpcId": requester_vpc_id, @@ -3778,7 +3756,7 @@ def request_vpc_peering_connection( vpc_peering = conn.create_vpc_peering_connection(**peering_params) peering = vpc_peering.get("VpcPeeringConnection", {}) peering_conn_id = peering.get("VpcPeeringConnectionId", "ERROR") - msg = "VPC peering {} requested.".format(peering_conn_id) + msg = f"VPC peering {peering_conn_id} requested." log.debug(msg) if name: @@ -3787,7 +3765,7 @@ def request_vpc_peering_connection( Resources=[peering_conn_id], Tags=[{"Key": "Name", "Value": name}] ) log.debug("Applied name tag to vpc peering connection") - msg += " With name {}.".format(name) + msg += f" With name {name}." return {"msg": msg} except botocore.exceptions.ClientError as err: @@ -3989,7 +3967,7 @@ def delete_vpc_peering_connection( conn_id = _vpc_peering_conn_id_for_name(conn_name, conn) if not conn_id: raise SaltInvocationError( - "Couldn't resolve VPC peering connection {} to an ID".format(conn_name) + f"Couldn't resolve VPC peering connection {conn_name} to an ID" ) try: log.debug("Trying to delete vpc peering connection") diff --git a/salt/modules/bsd_shadow.py b/salt/modules/bsd_shadow.py index c9717d8c036..3af23b710f3 100644 --- a/salt/modules/bsd_shadow.py +++ b/salt/modules/bsd_shadow.py @@ -8,7 +8,6 @@ Manage the password database on BSD systems `. """ - import salt.utils.files import salt.utils.stringutils from salt.exceptions import CommandExecutionError, SaltInvocationError @@ -111,7 +110,7 @@ def info(name): if not isinstance(name, str): name = str(name) if ":" in name: - raise SaltInvocationError("Invalid username '{}'".format(name)) + raise SaltInvocationError(f"Invalid username '{name}'") if __salt__["cmd.has_exec"]("pw"): change, expire = __salt__["cmd.run_stdout"]( @@ -122,7 +121,7 @@ def info(name): with salt.utils.files.fopen("/etc/master.passwd", "r") as fp_: for line in fp_: line = salt.utils.stringutils.to_unicode(line) - if line.startswith("{}:".format(name)): + if line.startswith(f"{name}:"): key = line.split(":") change, expire = key[5:7] ret["passwd"] = str(key[1]) @@ -211,7 +210,7 @@ def del_password(name): salt '*' shadow.del_password username """ - cmd = "pw user mod {} -w none".format(name) + cmd = f"pw user mod {name} -w none" __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="quiet") uinfo = info(name) return not uinfo["passwd"] diff --git a/salt/modules/btrfs.py b/salt/modules/btrfs.py index 4b02eb21afa..30f857de5d7 100644 --- a/salt/modules/btrfs.py +++ b/salt/modules/btrfs.py @@ -85,7 +85,7 @@ def info(device): salt '*' btrfs.info /dev/sda1 """ - out = __salt__["cmd.run_all"]("btrfs filesystem show {}".format(device)) + out = __salt__["cmd.run_all"](f"btrfs filesystem show {device}") salt.utils.fsutils._verify_run(out) return _parse_btrfs_info(out["stdout"]) @@ -111,9 +111,7 @@ def _defragment_mountpoint(mountpoint): """ Defragment only one BTRFS mountpoint. """ - out = __salt__["cmd.run_all"]( - "btrfs filesystem defragment -f {}".format(mountpoint) - ) + out = __salt__["cmd.run_all"](f"btrfs filesystem defragment -f {mountpoint}") return { "mount_point": mountpoint, "passed": not out["stderr"], @@ -140,7 +138,7 @@ def defragment(path): is_device = salt.utils.fsutils._is_device(path) mounts = salt.utils.fsutils._get_mounts("btrfs") if is_device and not mounts.get(path): - raise CommandExecutionError('Device "{}" is not mounted'.format(path)) + raise CommandExecutionError(f'Device "{path}" is not mounted') result = [] if is_device: @@ -159,9 +157,9 @@ def defragment(path): and not d_res["passed"] and "range ioctl not supported" in d_res["log"] ): - d_res[ - "log" - ] = "Range ioctl defragmentation is not supported in this kernel." + d_res["log"] = ( + "Range ioctl defragmentation is not supported in this kernel." + ) if not is_mountpoint: d_res["mount_point"] = False @@ -212,7 +210,7 @@ def _usage_overall(raw): subk = keyset[1].split("(") data[key] = subk[0].strip() subk = subk[1].replace(")", "").split(": ") - data["{}_{}".format(key, subk[0])] = subk[1] + data[f"{key}_{subk[0]}"] = subk[1] else: data[key] = keyset[1] @@ -263,7 +261,7 @@ def usage(path): salt '*' btrfs.usage /your/mountpoint """ - out = __salt__["cmd.run_all"]("btrfs filesystem usage {}".format(path)) + out = __salt__["cmd.run_all"](f"btrfs filesystem usage {path}") salt.utils.fsutils._verify_run(out) ret = {} @@ -317,9 +315,7 @@ def mkfs(*devices, **kwargs): mounts = salt.utils.fsutils._get_mounts("btrfs") for device in devices: if mounts.get(device): - raise CommandExecutionError( - 'Device "{}" should not be mounted'.format(device) - ) + raise CommandExecutionError(f'Device "{device}" should not be mounted') cmd = ["mkfs.btrfs"] @@ -332,9 +328,9 @@ def mkfs(*devices, **kwargs): cmd.append("-m single") else: if dto: - cmd.append("-d {}".format(dto)) + cmd.append(f"-d {dto}") if mto: - cmd.append("-m {}".format(mto)) + cmd.append(f"-m {mto}") for key, option in [ ("-l", "leafsize"), @@ -348,7 +344,7 @@ def mkfs(*devices, **kwargs): if option == "label" and option in kwargs: kwargs["label"] = "'{}'".format(kwargs["label"]) if kwargs.get(option): - cmd.append("{} {}".format(key, kwargs.get(option))) + cmd.append(f"{key} {kwargs.get(option)}") if kwargs.get("uuid"): cmd.append( @@ -393,12 +389,10 @@ def resize(mountpoint, size): if size == "max": if not salt.utils.fsutils._is_device(mountpoint): raise CommandExecutionError( - 'Mountpoint "{}" should be a valid device'.format(mountpoint) + f'Mountpoint "{mountpoint}" should be a valid device' ) if not salt.utils.fsutils._get_mounts("btrfs").get(mountpoint): - raise CommandExecutionError( - 'Device "{}" should be mounted'.format(mountpoint) - ) + raise CommandExecutionError(f'Device "{mountpoint}" should be mounted') elif ( len(size) < 3 or size[0] not in "-+" @@ -411,9 +405,7 @@ def resize(mountpoint, size): ) ) - out = __salt__["cmd.run_all"]( - "btrfs filesystem resize {} {}".format(size, mountpoint) - ) + out = __salt__["cmd.run_all"](f"btrfs filesystem resize {size} {mountpoint}") salt.utils.fsutils._verify_run(out) ret = {"log": out["stdout"]} @@ -441,7 +433,7 @@ def _fsck_ext(device): } return msgs.get( - __salt__["cmd.run_all"]("fsck -f -n {}".format(device))["retcode"], + __salt__["cmd.run_all"](f"fsck -f -n {device}")["retcode"], "Unknown error", ) @@ -472,7 +464,7 @@ def convert(device, permanent=False, keeplf=False): salt.utils.fsutils._verify_run(out) devices = salt.utils.fsutils._blkid_output(out["stdout"]) if not devices.get(device): - raise CommandExecutionError('The device "{}" was is not found.'.format(device)) + raise CommandExecutionError(f'The device "{device}" was is not found.') if not devices[device]["type"] in ["ext2", "ext3", "ext4"]: raise CommandExecutionError( @@ -503,7 +495,7 @@ documentation regarding this topic. """ ) - salt.utils.fsutils._verify_run(__salt__["cmd.run_all"]("umount {}".format(device))) + salt.utils.fsutils._verify_run(__salt__["cmd.run_all"](f"umount {device}")) ret = { "before": { @@ -513,11 +505,9 @@ documentation regarding this topic. } } + salt.utils.fsutils._verify_run(__salt__["cmd.run_all"](f"btrfs-convert {device}")) salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("btrfs-convert {}".format(device)) - ) - salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("mount {} {}".format(device, mountpoint)) + __salt__["cmd.run_all"](f"mount {device} {mountpoint}") ) # Refresh devices @@ -532,38 +522,34 @@ documentation regarding this topic. } # Post-migration procedures - image_path = "{}/ext2_saved".format(mountpoint) + image_path = f"{mountpoint}/ext2_saved" orig_fstype = ret["before"]["type"] if not os.path.exists(image_path): raise CommandExecutionError( - 'BTRFS migration went wrong: the image "{}" not found!'.format(image_path) + f'BTRFS migration went wrong: the image "{image_path}" not found!' ) if not permanent: - ret["after"]["{}_image".format(orig_fstype)] = image_path + ret["after"][f"{orig_fstype}_image"] = image_path image_info_proc = subprocess.run( - ["file", "{}/image".format(image_path)], check=True, stdout=subprocess.PIPE + ["file", f"{image_path}/image"], check=True, stdout=subprocess.PIPE ) - ret["after"][ - "{}_image_info".format(orig_fstype) - ] = image_info_proc.stdout.strip() + ret["after"][f"{orig_fstype}_image_info"] = image_info_proc.stdout.strip() else: - ret["after"]["{}_image".format(orig_fstype)] = "removed" - ret["after"]["{}_image_info".format(orig_fstype)] = "N/A" + ret["after"][f"{orig_fstype}_image"] = "removed" + ret["after"][f"{orig_fstype}_image_info"] = "N/A" salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("btrfs subvolume delete {}".format(image_path)) + __salt__["cmd.run_all"](f"btrfs subvolume delete {image_path}") ) - out = __salt__["cmd.run_all"]("btrfs filesystem balance {}".format(mountpoint)) + out = __salt__["cmd.run_all"](f"btrfs filesystem balance {mountpoint}") salt.utils.fsutils._verify_run(out) ret["after"]["balance_log"] = out["stdout"] - lost_found = "{}/lost+found".format(mountpoint) + lost_found = f"{mountpoint}/lost+found" if os.path.exists(lost_found) and not keeplf: - salt.utils.fsutils._verify_run( - __salt__["cmd.run_all"]("rm -rf {}".format(lost_found)) - ) + salt.utils.fsutils._verify_run(__salt__["cmd.run_all"](f"rm -rf {lost_found}")) return ret @@ -576,7 +562,7 @@ def _restripe(mountpoint, direction, *devices, **kwargs): if salt.utils.fsutils._is_device(mountpoint): raise CommandExecutionError( - 'Mountpount expected, while device "{}" specified'.format(mountpoint) + f'Mountpount expected, while device "{mountpoint}" specified' ) mounted = False @@ -588,7 +574,7 @@ def _restripe(mountpoint, direction, *devices, **kwargs): if not mounted: raise CommandExecutionError( - 'No BTRFS device mounted on "{}" mountpoint'.format(mountpoint) + f'No BTRFS device mounted on "{mountpoint}" mountpoint' ) if not devices: @@ -597,9 +583,9 @@ def _restripe(mountpoint, direction, *devices, **kwargs): available_devices = __salt__["btrfs.devices"]() for device in devices: if device not in available_devices.keys(): - raise CommandExecutionError('Device "{}" is not recognized'.format(device)) + raise CommandExecutionError(f'Device "{device}" is not recognized') - cmd = ["btrfs device {}".format(direction)] + cmd = [f"btrfs device {direction}"] for device in devices: cmd.append(device) @@ -627,9 +613,7 @@ def _restripe(mountpoint, direction, *devices, **kwargs): ) ) else: - out = __salt__["cmd.run_all"]( - "btrfs filesystem balance {}".format(mountpoint) - ) + out = __salt__["cmd.run_all"](f"btrfs filesystem balance {mountpoint}") salt.utils.fsutils._verify_run(out) if out["stdout"]: fs_log.append(out["stdout"]) @@ -715,15 +699,13 @@ def properties(obj, type=None, set=None): "d", "device", ]: - raise CommandExecutionError( - 'Unknown property type: "{}" specified'.format(type) - ) + raise CommandExecutionError(f'Unknown property type: "{type}" specified') cmd = ["btrfs"] cmd.append("property") cmd.append(set and "set" or "list") if type: - cmd.append("-t{}".format(type)) + cmd.append(f"-t{type}") cmd.append(obj) if set: @@ -744,9 +726,9 @@ def properties(obj, type=None, set=None): ret = {} for prop, descr in _parse_proplist(out["stdout"]).items(): ret[prop] = {"description": descr} - value = __salt__["cmd.run_all"]( - "btrfs property get {} {}".format(obj, prop) - )["stdout"] + value = __salt__["cmd.run_all"](f"btrfs property get {obj} {prop}")[ + "stdout" + ] ret[prop]["value"] = value and value.split("=")[-1] or "N/A" return ret diff --git a/salt/modules/cabal.py b/salt/modules/cabal.py index 8b4426c1400..fb2ccb61c8c 100644 --- a/salt/modules/cabal.py +++ b/salt/modules/cabal.py @@ -85,7 +85,7 @@ def install(pkg=None, pkgs=None, user=None, install_global=False, env=None): cmd.append("--global") if pkg: - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') elif pkgs: cmd.append('"{}"'.format('" "'.join(pkgs))) @@ -125,7 +125,7 @@ def list_(pkg=None, user=None, installed=False, env=None): cmd.append("--installed") if pkg: - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') result = __salt__["cmd.run_all"](" ".join(cmd), runas=user, env=env) @@ -160,7 +160,7 @@ def uninstall(pkg, user=None, env=None): """ cmd = ["ghc-pkg unregister"] - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') result = __salt__["cmd.run_all"](" ".join(cmd), runas=user, env=env) diff --git a/salt/modules/capirca_acl.py b/salt/modules/capirca_acl.py index 82189e48ade..2678556a433 100644 --- a/salt/modules/capirca_acl.py +++ b/salt/modules/capirca_acl.py @@ -481,7 +481,7 @@ def _get_term_object( pillarenv=None, saltenv=None, merge_pillar=True, - **term_fields + **term_fields, ): """ Return an instance of the ``_Term`` class given the term options. @@ -558,7 +558,7 @@ def _get_policy_object( pillarenv=pillarenv, saltenv=saltenv, merge_pillar=merge_pillar, - **term_fields + **term_fields, ) filter_terms.append(term) policy_filters.append((header, filter_terms)) @@ -597,17 +597,15 @@ def _revision_tag( if "$Id:$" in line: if not revision_id: # if no explicit revision ID required continue # jump to next line, ignore this one - line = line.replace("$Id:$", "$Id: {rev_id} $".format(rev_id=revision_id)) + line = line.replace("$Id:$", f"$Id: {revision_id} $") if "$Revision:$" in line: if not revision_no: # if no explicit revision number required continue # jump to next line, ignore this one - line = line.replace( - "$Revision:$", "$Revision: {rev_no} $".format(rev_no=revision_no) - ) + line = line.replace("$Revision:$", f"$Revision: {revision_no} $") if "$Date:$" in line: if not revision_date: continue # jump - line = line.replace("$Date:$", "$Date: {ts} $".format(ts=timestamp)) + line = line.replace("$Date:$", f"$Date: {timestamp} $") new_text.append(line) return "\n".join(new_text) @@ -632,7 +630,7 @@ def get_term_config( revision_date_format="%Y/%m/%d", source_service=None, destination_service=None, - **term_fields + **term_fields, ): """ Return the configuration of a single policy term. diff --git a/salt/modules/cassandra_cql.py b/salt/modules/cassandra_cql.py index 4e5ddcee71b..38e42f42bd9 100644 --- a/salt/modules/cassandra_cql.py +++ b/salt/modules/cassandra_cql.py @@ -220,7 +220,7 @@ def _load_properties(property_name, config_option, set_default=False, default=No config_option, ) raise CommandExecutionError( - "ERROR: Cassandra {} cannot be empty.".format(config_option) + f"ERROR: Cassandra {config_option} cannot be empty." ) return loaded_property return property_name @@ -510,7 +510,7 @@ def cql_query( results = session.execute(query) except BaseException as e: log.error("Failed to execute query: %s\n reason: %s", query, e) - msg = "ERROR: Cassandra query failed: {} reason: {}".format(query, e) + msg = f"ERROR: Cassandra query failed: {query} reason: {e}" raise CommandExecutionError(msg) if results: @@ -543,7 +543,7 @@ def cql_query_with_prepare( load_balancing_policy=None, load_balancing_policy_args=None, ssl_options=None, - **kwargs + **kwargs, ): """ Run a query on a Cassandra cluster and return a dictionary. @@ -642,7 +642,7 @@ def cql_query_with_prepare( results = session.execute(bound_statement.bind(statement_arguments)) except BaseException as e: log.error("Failed to execute query: %s\n reason: %s", query, e) - msg = "ERROR: Cassandra query failed: {} reason: {}".format(query, e) + msg = f"ERROR: Cassandra query failed: {query} reason: {e}" raise CommandExecutionError(msg) if not asynchronous and results: @@ -919,13 +919,13 @@ def list_column_families( salt 'minion1' cassandra_cql.list_column_families keyspace=system """ - where_clause = "where keyspace_name = '{}'".format(keyspace) if keyspace else "" + where_clause = f"where keyspace_name = '{keyspace}'" if keyspace else "" query = { "2": "select columnfamily_name from system.schema_columnfamilies {};".format( where_clause ), - "3": "select column_name from system_schema.columns {};".format(where_clause), + "3": f"select column_name from system_schema.columns {where_clause};", } ret = {} @@ -1190,7 +1190,7 @@ def drop_keyspace( ssl_options=ssl_options, ) if existing_keyspace: - query = """drop keyspace {};""".format(keyspace) + query = f"""drop keyspace {keyspace};""" try: cql_query( query, @@ -1419,16 +1419,12 @@ def list_permissions( salt 'minion1' cassandra_cql.list_permissions username=joe resource=test_table resource_type=table \ permission=select contact_points=minion1 """ - keyspace_cql = ( - "{} {}".format(resource_type, resource) if resource else "all keyspaces" - ) - permission_cql = ( - "{} permission".format(permission) if permission else "all permissions" - ) - query = "list {} on {}".format(permission_cql, keyspace_cql) + keyspace_cql = f"{resource_type} {resource}" if resource else "all keyspaces" + permission_cql = f"{permission} permission" if permission else "all permissions" + query = f"list {permission_cql} on {keyspace_cql}" if username: - query = "{} of {}".format(query, username) + query = f"{query} of {username}" log.debug("Attempting to list permissions with query '%s'", query) @@ -1511,13 +1507,9 @@ def grant_permission( salt 'minion1' cassandra_cql.grant_permission username=joe resource=test_table resource_type=table \ permission=select contact_points=minion1 """ - permission_cql = ( - "grant {}".format(permission) if permission else "grant all permissions" - ) - resource_cql = ( - "on {} {}".format(resource_type, resource) if resource else "on all keyspaces" - ) - query = "{} {} to {}".format(permission_cql, resource_cql, username) + permission_cql = f"grant {permission}" if permission else "grant all permissions" + resource_cql = f"on {resource_type} {resource}" if resource else "on all keyspaces" + query = f"{permission_cql} {resource_cql} to {username}" log.debug("Attempting to grant permissions with query '%s'", query) try: diff --git a/salt/modules/chef.py b/salt/modules/chef.py index 698db0db560..4568e0c9458 100644 --- a/salt/modules/chef.py +++ b/salt/modules/chef.py @@ -2,7 +2,6 @@ Execute chef in server or solo mode """ - import logging import os import tempfile @@ -37,7 +36,7 @@ def _default_logfile(exe_name): logfile = logfile_tmp.name logfile_tmp.close() else: - logfile = salt.utils.path.join("/var/log", "{}.log".format(exe_name)) + logfile = salt.utils.path.join("/var/log", f"{exe_name}.log") return logfile @@ -117,7 +116,7 @@ def client(whyrun=False, localmode=False, logfile=None, **kwargs): "chef-client", "--no-color", "--once", - '--logfile "{}"'.format(logfile), + f'--logfile "{logfile}"', "--format doc", ] @@ -185,7 +184,7 @@ def solo(whyrun=False, logfile=None, **kwargs): args = [ "chef-solo", "--no-color", - '--logfile "{}"'.format(logfile), + f'--logfile "{logfile}"', "--format doc", ] @@ -200,9 +199,9 @@ def _exec_cmd(*args, **kwargs): # Compile the command arguments cmd_args = " ".join(args) cmd_kwargs = "".join( - [" --{} {}".format(k, v) for k, v in kwargs.items() if not k.startswith("__")] + [f" --{k} {v}" for k, v in kwargs.items() if not k.startswith("__")] ) - cmd_exec = "{}{}".format(cmd_args, cmd_kwargs) + cmd_exec = f"{cmd_args}{cmd_kwargs}" log.debug("Chef command: %s", cmd_exec) return __salt__["cmd.run_all"](cmd_exec, python_shell=False) diff --git a/salt/modules/chronos.py b/salt/modules/chronos.py index a76590cb4af..3bc35e06bf9 100644 --- a/salt/modules/chronos.py +++ b/salt/modules/chronos.py @@ -37,7 +37,7 @@ def _jobs(): Return the currently configured jobs. """ response = salt.utils.http.query( - "{}/scheduler/jobs".format(_base_url()), + f"{_base_url()}/scheduler/jobs", decode_type="json", decode=True, ) @@ -106,7 +106,7 @@ def update_job(name, config): data = salt.utils.json.dumps(config) try: response = salt.utils.http.query( - "{}/scheduler/iso8601".format(_base_url()), + f"{_base_url()}/scheduler/iso8601", method="POST", data=data, header_dict={"Content-Type": "application/json"}, @@ -129,7 +129,7 @@ def rm_job(name): salt chronos-minion-id chronos.rm_job my-job """ response = salt.utils.http.query( - "{}/scheduler/job/{}".format(_base_url(), name), + f"{_base_url()}/scheduler/job/{name}", method="DELETE", ) return True diff --git a/salt/modules/chroot.py b/salt/modules/chroot.py index 78c974cc196..5be402f1beb 100644 --- a/salt/modules/chroot.py +++ b/salt/modules/chroot.py @@ -171,7 +171,7 @@ def call(root, function, *args, **kwargs): safe_kwargs = salt.utils.args.clean_kwargs(**kwargs) salt_argv = ( [ - "python{}".format(sys.version_info[0]), + f"python{sys.version_info[0]}", os.path.join(chroot_path, "salt-call"), "--metadata", "--local", @@ -187,7 +187,7 @@ def call(root, function, *args, **kwargs): function, ] + list(args) - + ["{}={}".format(k, v) for (k, v) in safe_kwargs.items()] + + [f"{k}={v}" for (k, v) in safe_kwargs.items()] ) ret = __salt__["cmd.run_chroot"](root, [str(x) for x in salt_argv]) diff --git a/salt/modules/cimc.py b/salt/modules/cimc.py index e555538a901..90eb2b34c6c 100644 --- a/salt/modules/cimc.py +++ b/salt/modules/cimc.py @@ -24,7 +24,6 @@ rest API. """ - import logging import salt.proxy.cimc @@ -116,7 +115,7 @@ def create_user(uid=None, username=None, password=None, priv=None): "The privilege level must be specified." ) - dn = "sys/user-ext/user-{}".format(uid) + dn = f"sys/user-ext/user-{uid}" inconfig = """""".format( @@ -607,7 +606,7 @@ def mount_share( else: mount_options = "" - dn = "sys/svc-ext/vmedia-svc/vmmap-{}".format(name) + dn = f"sys/svc-ext/vmedia-svc/vmmap-{name}" inconfig = """""".format( @@ -713,7 +712,7 @@ def set_logging_levels(remote=None, local=None): if remote: if remote in logging_options: - query += ' remoteSeverity="{}"'.format(remote) + query += f' remoteSeverity="{remote}"' else: raise salt.exceptions.CommandExecutionError( "Remote Severity option is not valid." @@ -721,14 +720,14 @@ def set_logging_levels(remote=None, local=None): if local: if local in logging_options: - query += ' localSeverity="{}"'.format(local) + query += f' localSeverity="{local}"' else: raise salt.exceptions.CommandExecutionError( "Local Severity option is not valid." ) dn = "sys/svc-ext/syslog" - inconfig = """""".format(query) + inconfig = f"""""" ret = __proxy__["cimc.set_config_modify"](dn, inconfig, False) @@ -818,7 +817,7 @@ def set_power_configuration(policy=None, delayType=None, delayValue=None): if delayType == "fixed": query += ' delayType="fixed"' if delayValue: - query += ' delay="{}"'.format(delayValue) + query += f' delay="{delayValue}"' elif delayType == "random": query += ' delayType="random"' else: @@ -924,18 +923,18 @@ def set_user(uid=None, username=None, password=None, priv=None, status=None): raise salt.exceptions.CommandExecutionError("The user ID must be specified.") if status: - conf += ' accountStatus="{}"'.format(status) + conf += f' accountStatus="{status}"' if username: - conf += ' name="{}"'.format(username) + conf += f' name="{username}"' if priv: - conf += ' priv="{}"'.format(priv) + conf += f' priv="{priv}"' if password: - conf += ' pwd="{}"'.format(password) + conf += f' pwd="{password}"' - dn = "sys/user-ext/user-{}".format(uid) + dn = f"sys/user-ext/user-{uid}" inconfig = """""".format(uid, conf) diff --git a/salt/modules/ciscoconfparse_mod.py b/salt/modules/ciscoconfparse_mod.py index 56924691245..2be0a5f482e 100644 --- a/salt/modules/ciscoconfparse_mod.py +++ b/salt/modules/ciscoconfparse_mod.py @@ -58,7 +58,7 @@ def _get_ccp(config=None, config_path=None, saltenv="base"): if config_path: config = __salt__["cp.get_file_str"](config_path, saltenv=saltenv) if config is False: - raise SaltException("{} is not available".format(config_path)) + raise SaltException(f"{config_path} is not available") if isinstance(config, str): config = config.splitlines() ccp = ciscoconfparse.CiscoConfParse(config) diff --git a/salt/modules/cloud.py b/salt/modules/cloud.py index b4f52ae3b73..dd1ededf158 100644 --- a/salt/modules/cloud.py +++ b/salt/modules/cloud.py @@ -2,7 +2,6 @@ Salt-specific interface for calling Salt Cloud directly """ - import copy import logging import os diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py index 4822971d552..d603a69ba77 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py @@ -145,7 +145,7 @@ def _render_cmd(cmd, cwd, template, saltenv=None, pillarenv=None, pillar_overrid # render the path as a template using path_template_engine as the engine if template not in salt.utils.templates.TEMPLATE_REGISTRY: raise CommandExecutionError( - "Attempted to render file paths with unavailable engine {}".format(template) + f"Attempted to render file paths with unavailable engine {template}" ) kwargs = {} @@ -265,7 +265,7 @@ def _prep_powershell_cmd(shell, cmd, stack, encoded_cmd): # the shell in quotes in case there are # spaces in the paths. if salt.utils.platform.is_windows(): - shell = '"{}"'.format(shell) + shell = f'"{shell}"' # extract_stack() returns a list of tuples. # The last item in the list [-1] is the current method. @@ -277,9 +277,9 @@ def _prep_powershell_cmd(shell, cmd, stack, encoded_cmd): ) ) elif encoded_cmd: - cmd = "{} -NonInteractive -NoProfile -EncodedCommand {}".format(shell, cmd) + cmd = f"{shell} -NonInteractive -NoProfile -EncodedCommand {cmd}" else: - cmd = '{} -NonInteractive -NoProfile -Command "{}"'.format(shell, cmd) + cmd = f'{shell} -NonInteractive -NoProfile -Command "{cmd}"' return cmd @@ -318,7 +318,7 @@ def _run( success_stdout=None, success_stderr=None, windows_codepage=65001, - **kwargs + **kwargs, ): """ Do the DRY thing and only call subprocess.Popen() once @@ -368,7 +368,7 @@ def _run( change_windows_codepage = False if not salt.utils.platform.is_windows(): if not os.path.isfile(shell) or not os.access(shell, os.X_OK): - msg = "The shell {} is not available".format(shell) + msg = f"The shell {shell} is not available" raise CommandExecutionError(msg) elif use_vt: # Memozation so not much overhead raise CommandExecutionError("VT not available on windows") @@ -406,9 +406,7 @@ def _run( # checked if blacklisted if "__pub_jid" in kwargs: if not _check_avail(cmd): - raise CommandExecutionError( - 'The shell command "{}" is not permitted'.format(cmd) - ) + raise CommandExecutionError(f'The shell command "{cmd}" is not permitted') env = _parse_env(env) @@ -428,12 +426,14 @@ def _run( "'" if not isinstance(cmd, list) else "", _log_cmd(cmd), "'" if not isinstance(cmd, list) else "", - "as user '{}' ".format(runas) if runas else "", - "in group '{}' ".format(group) if group else "", + f"as user '{runas}' " if runas else "", + f"in group '{group}' " if group else "", cwd, - ". Executing command in the background, no output will be logged." - if bg - else "", + ( + ". Executing command in the background, no output will be logged." + if bg + else "" + ), ) log.info(log_callback(msg)) @@ -455,7 +455,7 @@ def _run( cmd = " ".join(map(_cmd_quote, cmd)) # Ensure directory is correct before running command - cmd = "cd -- {dir} && {{ {cmd}\n }}".format(dir=_cmd_quote(cwd), cmd=cmd) + cmd = f"cd -- {_cmd_quote(cwd)} && {{ {cmd}\n }}" # Ensure environment is correct for a newly logged-in user by running # the command under bash as a login shell @@ -472,7 +472,7 @@ def _run( # Ensure the login is simulated correctly (note: su runs sh, not bash, # which causes the environment to be initialised incorrectly, which is # fixed by the previous line of code) - cmd = "su -l {} -c {}".format(_cmd_quote(runas), _cmd_quote(cmd)) + cmd = f"su -l {_cmd_quote(runas)} -c {_cmd_quote(cmd)}" # Set runas to None, because if you try to run `su -l` after changing # user, su will prompt for the password of the user and cause salt to @@ -484,7 +484,7 @@ def _run( try: pwd.getpwnam(runas) except KeyError: - raise CommandExecutionError("User '{}' is not available".format(runas)) + raise CommandExecutionError(f"User '{runas}' is not available") if group: if salt.utils.platform.is_windows(): @@ -496,7 +496,7 @@ def _run( try: grp.getgrnam(group) except KeyError: - raise CommandExecutionError("Group '{}' is not available".format(runas)) + raise CommandExecutionError(f"Group '{runas}' is not available") else: use_sudo = True @@ -542,7 +542,7 @@ def _run( if not salt.utils.pkg.check_bundled(): if __grains__["os"] in ["FreeBSD"]: - env_cmd.extend(["{} -c {}".format(shell, sys.executable)]) + env_cmd.extend([f"{shell} -c {sys.executable}"]) else: env_cmd.extend([sys.executable]) else: @@ -556,11 +556,11 @@ def _run( ] ) else: - env_cmd.extend(["{} python {}".format(sys.executable, fp.name)]) + env_cmd.extend([f"{sys.executable} python {fp.name}"]) fp.write(py_code) shutil.chown(fp.name, runas) - msg = "env command: {}".format(env_cmd) + msg = f"env command: {env_cmd}" log.debug(log_callback(msg)) env_bytes, env_encoded_err = subprocess.Popen( env_cmd, @@ -607,7 +607,7 @@ def _run( # Fix some corner cases where shelling out to get the user's # environment returns the wrong home directory. - runas_home = os.path.expanduser("~{}".format(runas)) + runas_home = os.path.expanduser(f"~{runas}") if env_runas.get("HOME") != runas_home: env_runas["HOME"] = runas_home @@ -685,7 +685,7 @@ def _run( try: _umask = int(_umask, 8) except ValueError: - raise CommandExecutionError("Invalid umask: '{}'".format(umask)) + raise CommandExecutionError(f"Invalid umask: '{umask}'") else: _umask = None @@ -707,7 +707,7 @@ def _run( if not os.path.isabs(cwd) or not os.path.isdir(cwd): raise CommandExecutionError( - "Specified cwd '{}' either not absolute or does not exist".format(cwd) + f"Specified cwd '{cwd}' either not absolute or does not exist" ) if ( @@ -828,9 +828,9 @@ def _run( else: formatted_timeout = "" if timeout: - formatted_timeout = " (timeout: {}s)".format(timeout) + formatted_timeout = f" (timeout: {timeout}s)" if output_loglevel is not None: - msg = "Running {} in VT{}".format(cmd, formatted_timeout) + msg = f"Running {cmd} in VT{formatted_timeout}" log.debug(log_callback(msg)) stdout, stderr = "", "" now = time.time() @@ -875,7 +875,7 @@ def _run( ret["retcode"] = None break except KeyboardInterrupt: - ret["stderr"] = "SALT: User break\n{}".format(stderr) + ret["stderr"] = f"SALT: User break\n{stderr}" ret["retcode"] = 1 break except salt.utils.vt.TerminalException as exc: @@ -999,7 +999,6 @@ def _run_all_quiet( success_stderr=None, ignore_retcode=None, ): - """ Helper for running commands quietly for minion startup. Returns a dict of return data. @@ -1064,7 +1063,7 @@ def run( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): r""" Execute the passed command and return the output as a string @@ -1331,7 +1330,7 @@ def run( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) log_callback = _check_cb(log_callback) @@ -1380,7 +1379,7 @@ def shell( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed command and return the output as a string. @@ -1608,7 +1607,7 @@ def shell( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) @@ -1639,7 +1638,7 @@ def run_stdout( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute a command, and only return the standard out @@ -1840,7 +1839,7 @@ def run_stdout( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return ret["stdout"] if not hide_output else "" @@ -1873,7 +1872,7 @@ def run_stderr( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute a command and only return the standard error @@ -2074,7 +2073,7 @@ def run_stderr( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return ret["stderr"] if not hide_output else "" @@ -2109,7 +2108,7 @@ def run_all( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed command and return a dict of return data @@ -2354,7 +2353,7 @@ def run_all( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) if hide_output: @@ -2386,7 +2385,7 @@ def retcode( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute a shell command and return the command's return code. @@ -2576,7 +2575,7 @@ def retcode( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return ret["retcode"] @@ -2604,7 +2603,7 @@ def _retcode_quiet( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Helper for running commands quietly for minion startup. Returns same as @@ -2634,7 +2633,7 @@ def _retcode_quiet( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) @@ -2663,7 +2662,7 @@ def script( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script from a remote location and execute the script locally. @@ -2936,7 +2935,7 @@ def script( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) _cleanup_tempfile(path) # If a temp working directory was created (Windows), let's remove that @@ -2971,7 +2970,7 @@ def script_retcode( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script from a remote location and execute the script locally. @@ -3150,7 +3149,7 @@ def script_retcode( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, )["retcode"] @@ -3280,7 +3279,7 @@ def tty(device, echo=""): salt '*' cmd.tty pts3 'This is a test' """ if device.startswith("tty"): - teletype = "/dev/{}".format(device) + teletype = f"/dev/{device}" elif device.startswith("pts"): teletype = "/dev/{}".format(device.replace("pts", "pts/")) else: @@ -3288,9 +3287,9 @@ def tty(device, echo=""): try: with salt.utils.files.fopen(teletype, "wb") as tty_device: tty_device.write(salt.utils.stringutils.to_bytes(echo)) - return {"Success": "Message was successfully echoed to {}".format(teletype)} + return {"Success": f"Message was successfully echoed to {teletype}"} except OSError: - return {"Error": "Echoing to {} returned error".format(teletype)} + return {"Error": f"Echoing to {teletype} returned error"} def run_chroot( @@ -3321,7 +3320,7 @@ def run_chroot( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2014.7.0 @@ -3497,7 +3496,7 @@ def run_chroot( else: userspec = "" - cmd = "chroot {} {} {} -c {}".format(userspec, root, sh_, _cmd_quote(cmd)) + cmd = f"chroot {userspec} {root} {sh_} -c {_cmd_quote(cmd)}" run_func = __context__.pop("cmd.run_chroot.func", run_all) @@ -3710,7 +3709,7 @@ def shell_info(shell, list_modules=False): for reg_ver in pw_keys: install_data = salt.utils.win_reg.read_value( hive="HKEY_LOCAL_MACHINE", - key="Software\\Microsoft\\PowerShell\\{}".format(reg_ver), + key=f"Software\\Microsoft\\PowerShell\\{reg_ver}", vname="Install", ) if ( @@ -3861,7 +3860,7 @@ def powershell( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed PowerShell command and return the output as a dictionary. @@ -4064,7 +4063,7 @@ def powershell( if salt.utils.versions.version_cmp(psversion, "2.0") == 1: cmd += " | ConvertTo-JSON" if depth is not None: - cmd += " -Depth {}".format(depth) + cmd += f" -Depth {depth}" # Put the whole command inside a try / catch block # Some errors in PowerShell are not "Terminating Errors" and will not be @@ -4077,7 +4076,7 @@ def powershell( # Convert the cmd to UTF-16LE without a BOM and base64 encode. # Just base64 encoding UTF-8 or including a BOM is not valid. log.debug("Encoding PowerShell command '%s'", cmd) - cmd = "$ProgressPreference='SilentlyContinue'; {}".format(cmd) + cmd = f"$ProgressPreference='SilentlyContinue'; {cmd}" cmd_utf16 = cmd.encode("utf-16-le") cmd = base64.standard_b64encode(cmd_utf16) cmd = salt.utils.stringutils.to_str(cmd) @@ -4111,7 +4110,7 @@ def powershell( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) # Sometimes Powershell returns an empty string, which isn't valid JSON @@ -4150,7 +4149,7 @@ def powershell_all( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Execute the passed PowerShell command and return a dictionary with a result @@ -4423,13 +4422,13 @@ def powershell_all( # Append PowerShell Object formatting cmd += " | ConvertTo-JSON" if depth is not None: - cmd += " -Depth {}".format(depth) + cmd += f" -Depth {depth}" if encode_cmd: # Convert the cmd to UTF-16LE without a BOM and base64 encode. # Just base64 encoding UTF-8 or including a BOM is not valid. log.debug("Encoding PowerShell command '%s'", cmd) - cmd = "$ProgressPreference='SilentlyContinue'; {}".format(cmd) + cmd = f"$ProgressPreference='SilentlyContinue'; {cmd}" cmd_utf16 = cmd.encode("utf-16-le") cmd = base64.standard_b64encode(cmd_utf16) cmd = salt.utils.stringutils.to_str(cmd) @@ -4463,7 +4462,7 @@ def powershell_all( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) stdoutput = response["stdout"] @@ -4519,7 +4518,7 @@ def run_bg( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): r""" .. versionadded:: 2016.3.0 @@ -4737,7 +4736,7 @@ def run_bg( success_retcodes=success_retcodes, success_stdout=success_stdout, success_stderr=success_stderr, - **kwargs + **kwargs, ) return {"pid": res["pid"]} diff --git a/salt/modules/composer.py b/salt/modules/composer.py index 7feb5d0f2ca..8e31c52a688 100644 --- a/salt/modules/composer.py +++ b/salt/modules/composer.py @@ -48,7 +48,7 @@ def did_composer_install(dir): salt '*' composer.did_composer_install /var/www/application """ - lockFile = "{}/vendor".format(dir) + lockFile = f"{dir}/vendor" if os.path.exists(lockFile): return True return False @@ -147,7 +147,7 @@ def _run_composer( # Don't need a dir for the 'selfupdate' action; all other actions do need a dir if directory is None and action != "selfupdate": raise SaltInvocationError( - "The 'directory' argument is required for composer.{}".format(action) + f"The 'directory' argument is required for composer.{action}" ) # Base Settings diff --git a/salt/modules/config.py b/salt/modules/config.py index 972a2e84c7c..044d7172c7c 100644 --- a/salt/modules/config.py +++ b/salt/modules/config.py @@ -522,10 +522,10 @@ def dot_vals(value): """ ret = {} for key, val in __pillar__.get("master", {}).items(): - if key.startswith("{}.".format(value)): + if key.startswith(f"{value}."): ret[key] = val for key, val in __opts__.items(): - if key.startswith("{}.".format(value)): + if key.startswith(f"{value}."): ret[key] = val return ret diff --git a/salt/modules/consul.py b/salt/modules/consul.py index 205cfb202bd..d1eca824b64 100644 --- a/salt/modules/consul.py +++ b/salt/modules/consul.py @@ -68,7 +68,7 @@ def _query( token = _get_token() headers = {"X-Consul-Token": token, "Content-Type": "application/json"} - base_url = urllib.parse.urljoin(consul_url, "{}/".format(api_version)) + base_url = urllib.parse.urljoin(consul_url, f"{api_version}/") url = urllib.parse.urljoin(base_url, function, False) if method == "GET": @@ -149,7 +149,7 @@ def list_(consul_url=None, token=None, key=None, **kwargs): query_params["recurse"] = "True" function = "kv/" else: - function = "kv/{}".format(key) + function = f"kv/{key}" query_params["keys"] = "True" query_params["separator"] = "/" @@ -203,7 +203,7 @@ def get(consul_url=None, key=None, token=None, recurse=False, decode=False, raw= raise SaltInvocationError('Required argument "key" is missing.') query_params = {} - function = "kv/{}".format(key) + function = f"kv/{key}" if recurse: query_params["recurse"] = "True" if raw: @@ -286,19 +286,17 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): if "cas" in kwargs: if _current["res"]: if kwargs["cas"] == 0: - ret["message"] = "Key {} exists, index must be non-zero.".format(key) + ret["message"] = f"Key {key} exists, index must be non-zero." ret["res"] = False return ret if kwargs["cas"] != _current["data"]["ModifyIndex"]: - ret["message"] = "Key {} exists, but indexes do not match.".format(key) + ret["message"] = f"Key {key} exists, but indexes do not match." ret["res"] = False return ret query_params["cas"] = kwargs["cas"] else: - ret[ - "message" - ] = "Key {} does not exists, CAS argument can not be used.".format(key) + ret["message"] = f"Key {key} does not exists, CAS argument can not be used." ret["res"] = False return ret @@ -316,7 +314,7 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): if _current["data"]["Session"] == kwargs["release"]: query_params["release"] = kwargs["release"] else: - ret["message"] = "{} locked by another session.".format(key) + ret["message"] = f"{key} locked by another session." ret["res"] = False return ret @@ -327,7 +325,7 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): log.error("Key {0} does not exist. Skipping release.") data = value - function = "kv/{}".format(key) + function = f"kv/{key}" method = "PUT" res = _query( consul_url=consul_url, @@ -340,10 +338,10 @@ def put(consul_url=None, token=None, key=None, value=None, **kwargs): if res["res"]: ret["res"] = True - ret["data"] = "Added key {} with value {}.".format(key, value) + ret["data"] = f"Added key {key} with value {value}." else: ret["res"] = False - ret["data"] = "Unable to add key {} with value {}.".format(key, value) + ret["data"] = f"Unable to add key {key} with value {value}." if "error" in res: ret["error"] = res["error"] return ret @@ -396,7 +394,7 @@ def delete(consul_url=None, token=None, key=None, **kwargs): ret["res"] = False return ret - function = "kv/{}".format(key) + function = f"kv/{key}" res = _query( consul_url=consul_url, token=token, @@ -407,10 +405,10 @@ def delete(consul_url=None, token=None, key=None, **kwargs): if res["res"]: ret["res"] = True - ret["message"] = "Deleted key {}.".format(key) + ret["message"] = f"Deleted key {key}." else: ret["res"] = False - ret["message"] = "Unable to delete key {}.".format(key) + ret["message"] = f"Unable to delete key {key}." if "error" in res: ret["error"] = res["error"] return ret @@ -635,7 +633,7 @@ def agent_join(consul_url=None, token=None, address=None, **kwargs): if "wan" in kwargs: query_params["wan"] = kwargs["wan"] - function = "agent/join/{}".format(address) + function = f"agent/join/{address}" res = _query( consul_url=consul_url, function=function, @@ -680,7 +678,7 @@ def agent_leave(consul_url=None, token=None, node=None): if not node: raise SaltInvocationError('Required argument "node" is missing.') - function = "agent/force-leave/{}".format(node) + function = f"agent/force-leave/{node}" res = _query( consul_url=consul_url, function=function, @@ -690,10 +688,10 @@ def agent_leave(consul_url=None, token=None, node=None): ) if res["res"]: ret["res"] = True - ret["message"] = "Node {} put in leave state.".format(node) + ret["message"] = f"Node {node} put in leave state." else: ret["res"] = False - ret["message"] = "Unable to change state for {}.".format(node) + ret["message"] = f"Unable to change state for {node}." return ret @@ -810,11 +808,11 @@ def agent_check_deregister(consul_url=None, token=None, checkid=None): if not checkid: raise SaltInvocationError('Required argument "checkid" is missing.') - function = "agent/check/deregister/{}".format(checkid) + function = f"agent/check/deregister/{checkid}" res = _query(consul_url=consul_url, function=function, token=token, method="GET") if res["res"]: ret["res"] = True - ret["message"] = "Check {} removed from agent.".format(checkid) + ret["message"] = f"Check {checkid} removed from agent." else: ret["res"] = False ret["message"] = "Unable to remove check from agent." @@ -855,7 +853,7 @@ def agent_check_pass(consul_url=None, token=None, checkid=None, **kwargs): if "note" in kwargs: query_params["note"] = kwargs["note"] - function = "agent/check/pass/{}".format(checkid) + function = f"agent/check/pass/{checkid}" res = _query( consul_url=consul_url, function=function, @@ -865,10 +863,10 @@ def agent_check_pass(consul_url=None, token=None, checkid=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Check {} marked as passing.".format(checkid) + ret["message"] = f"Check {checkid} marked as passing." else: ret["res"] = False - ret["message"] = "Unable to update check {}.".format(checkid) + ret["message"] = f"Unable to update check {checkid}." return ret @@ -906,7 +904,7 @@ def agent_check_warn(consul_url=None, token=None, checkid=None, **kwargs): if "note" in kwargs: query_params["note"] = kwargs["note"] - function = "agent/check/warn/{}".format(checkid) + function = f"agent/check/warn/{checkid}" res = _query( consul_url=consul_url, function=function, @@ -916,10 +914,10 @@ def agent_check_warn(consul_url=None, token=None, checkid=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Check {} marked as warning.".format(checkid) + ret["message"] = f"Check {checkid} marked as warning." else: ret["res"] = False - ret["message"] = "Unable to update check {}.".format(checkid) + ret["message"] = f"Unable to update check {checkid}." return ret @@ -957,7 +955,7 @@ def agent_check_fail(consul_url=None, token=None, checkid=None, **kwargs): if "note" in kwargs: query_params["note"] = kwargs["note"] - function = "agent/check/fail/{}".format(checkid) + function = f"agent/check/fail/{checkid}" res = _query( consul_url=consul_url, function=function, @@ -967,10 +965,10 @@ def agent_check_fail(consul_url=None, token=None, checkid=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Check {} marked as critical.".format(checkid) + ret["message"] = f"Check {checkid} marked as critical." else: ret["res"] = False - ret["message"] = "Unable to update check {}.".format(checkid) + ret["message"] = f"Unable to update check {checkid}." return ret @@ -1114,16 +1112,16 @@ def agent_service_deregister(consul_url=None, token=None, serviceid=None): if not serviceid: raise SaltInvocationError('Required argument "serviceid" is missing.') - function = "agent/service/deregister/{}".format(serviceid) + function = f"agent/service/deregister/{serviceid}" res = _query( consul_url=consul_url, function=function, token=token, method="PUT", data=data ) if res["res"]: ret["res"] = True - ret["message"] = "Service {} removed from agent.".format(serviceid) + ret["message"] = f"Service {serviceid} removed from agent." else: ret["res"] = False - ret["message"] = "Unable to remove service {}.".format(serviceid) + ret["message"] = f"Unable to remove service {serviceid}." return ret @@ -1168,14 +1166,14 @@ def agent_service_maintenance(consul_url=None, token=None, serviceid=None, **kwa if "reason" in kwargs: query_params["reason"] = kwargs["reason"] - function = "agent/service/maintenance/{}".format(serviceid) + function = f"agent/service/maintenance/{serviceid}" res = _query( consul_url=consul_url, token=token, function=function, query_params=query_params ) if res["res"]: ret["res"] = True - ret["message"] = "Service {} set in maintenance mode.".format(serviceid) + ret["message"] = f"Service {serviceid} set in maintenance mode." else: ret["res"] = False ret["message"] = "Unable to set service {} to maintenance mode.".format( @@ -1255,7 +1253,7 @@ def session_create(consul_url=None, token=None, **kwargs): ret["message"] = ("TTL must be ", "between 0 and 3600.") ret["res"] = False return ret - data["TTL"] = "{}s".format(_ttl) + data["TTL"] = f"{_ttl}s" function = "session/create" res = _query( @@ -1351,7 +1349,7 @@ def session_destroy(consul_url=None, token=None, session=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "session/destroy/{}".format(session) + function = f"session/destroy/{session}" res = _query( consul_url=consul_url, function=function, @@ -1361,10 +1359,10 @@ def session_destroy(consul_url=None, token=None, session=None, **kwargs): ) if res["res"]: ret["res"] = True - ret["message"] = "Destroyed Session {}.".format(session) + ret["message"] = f"Destroyed Session {session}." else: ret["res"] = False - ret["message"] = "Unable to destroy session {}.".format(session) + ret["message"] = f"Unable to destroy session {session}." return ret @@ -1402,7 +1400,7 @@ def session_info(consul_url=None, token=None, session=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "session/info/{}".format(session) + function = f"session/info/{session}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1543,9 +1541,9 @@ def catalog_register(consul_url=None, token=None, **kwargs): "warning", "critical", ): - ret[ - "message" - ] = "Check status must be unknown, passing, warning, or critical." + ret["message"] = ( + "Check status must be unknown, passing, warning, or critical." + ) ret["res"] = False return ret data["Check"]["Status"] = kwargs["check_status"] @@ -1770,7 +1768,7 @@ def catalog_service(consul_url=None, token=None, service=None, **kwargs): if "tag" in kwargs: query_params["tag"] = kwargs["tag"] - function = "catalog/service/{}".format(service) + function = f"catalog/service/{service}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1810,7 +1808,7 @@ def catalog_node(consul_url=None, token=None, node=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "catalog/node/{}".format(node) + function = f"catalog/node/{node}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1850,7 +1848,7 @@ def health_node(consul_url=None, token=None, node=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "health/node/{}".format(node) + function = f"health/node/{node}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1890,7 +1888,7 @@ def health_checks(consul_url=None, token=None, service=None, **kwargs): if "dc" in kwargs: query_params["dc"] = kwargs["dc"] - function = "health/checks/{}".format(service) + function = f"health/checks/{service}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1941,7 +1939,7 @@ def health_service(consul_url=None, token=None, service=None, **kwargs): if "passing" in kwargs: query_params["passing"] = kwargs["passing"] - function = "health/service/{}".format(service) + function = f"health/service/{service}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -1991,7 +1989,7 @@ def health_state(consul_url=None, token=None, state=None, **kwargs): ret["res"] = False return ret - function = "health/state/{}".format(state) + function = f"health/state/{state}" ret = _query( consul_url=consul_url, function=function, token=token, query_params=query_params ) @@ -2378,7 +2376,7 @@ def event_fire(consul_url=None, token=None, name=None, **kwargs): if "tag" in kwargs: query_params = kwargs["tag"] - function = "event/fire/{}".format(name) + function = f"event/fire/{name}" res = _query( consul_url=consul_url, token=token, @@ -2389,7 +2387,7 @@ def event_fire(consul_url=None, token=None, name=None, **kwargs): if res["res"]: ret["res"] = True - ret["message"] = "Event {} fired.".format(name) + ret["message"] = f"Event {name} fired." ret["data"] = res["data"] else: ret["res"] = False diff --git a/salt/modules/container_resource.py b/salt/modules/container_resource.py index 0a44ce3e518..5474d43a54c 100644 --- a/salt/modules/container_resource.py +++ b/salt/modules/container_resource.py @@ -8,6 +8,7 @@ These functions are not designed to be called directly, but instead from the :mod:`docker ` execution modules. They provide for common logic to be re-used for common actions. """ + import copy import functools import logging diff --git a/salt/modules/cpan.py b/salt/modules/cpan.py index b92f081d308..27b96d416eb 100644 --- a/salt/modules/cpan.py +++ b/salt/modules/cpan.py @@ -43,7 +43,7 @@ def install(module): old_info = show(module) - cmd = "cpan -i {}".format(module) + cmd = f"cpan -i {module}" out = __salt__["cmd.run"](cmd) if "don't know what it is" in out: @@ -153,7 +153,7 @@ def show(module): ret["name"] = module # This section parses out details from CPAN, if possible - cmd = "cpan -D {}".format(module) + cmd = f"cpan -D {module}" out = __salt__["cmd.run"](cmd).splitlines() mode = "skip" info = [] diff --git a/salt/modules/cron.py b/salt/modules/cron.py index dc0a229062c..660ca9c768d 100644 --- a/salt/modules/cron.py +++ b/salt/modules/cron.py @@ -113,7 +113,7 @@ def _render_tab(lst): """ ret = [] for pre in lst["pre"]: - ret.append("{}\n".format(pre)) + ret.append(f"{pre}\n") if ret: if ret[-1] != TAG: ret.append(TAG) @@ -170,10 +170,10 @@ def _get_cron_cmdstr(path, user=None): Returns a format string, to be used to build a crontab command. """ if user: - cmd = "crontab -u {}".format(user) + cmd = f"crontab -u {user}" else: cmd = "crontab" - return "{} {}".format(cmd, path) + return f"{cmd} {path}" def _check_instance_uid_match(user): @@ -343,7 +343,7 @@ def raw_cron(user): ).splitlines(True) # If Salt is running from root user it could modify any user's crontab elif _check_instance_uid_match("root"): - cmd = "crontab -u {} -l".format(user) + cmd = f"crontab -u {user} -l" # Preserve line endings lines = salt.utils.data.decode( __salt__["cmd.run_stdout"]( diff --git a/salt/modules/cryptdev.py b/salt/modules/cryptdev.py index 40c28d17f10..015272135a5 100644 --- a/salt/modules/cryptdev.py +++ b/salt/modules/cryptdev.py @@ -49,7 +49,7 @@ class _crypttab_entry: @classmethod def dict_from_line(cls, line, keys=crypttab_keys): if len(keys) != 4: - raise ValueError("Invalid key array: {}".format(keys)) + raise ValueError(f"Invalid key array: {keys}") if line.startswith("#"): raise cls.ParseError("Comment!") @@ -266,12 +266,12 @@ def set_crypttab( filterFn = lambda key: key not in _crypttab_entry.crypttab_keys invalid_keys = filter(filterFn, match_on) - msg = 'Unrecognized keys in match_on: "{}"'.format(invalid_keys) + msg = f'Unrecognized keys in match_on: "{invalid_keys}"' raise CommandExecutionError(msg) # parse file, use ret to cache status if not os.path.isfile(config): - raise CommandExecutionError('Bad config file "{}"'.format(config)) + raise CommandExecutionError(f'Bad config file "{config}"') try: with salt.utils.files.fopen(config, "r") as ifile: @@ -335,7 +335,7 @@ def open(name, device, keyfile): ) code = __salt__["cmd.retcode"]( - "cryptsetup open --key-file {} {} {}".format(keyfile, device, name) + f"cryptsetup open --key-file {keyfile} {device} {name}" ) return code == 0 @@ -350,5 +350,5 @@ def close(name): salt '*' cryptdev.close foo """ - code = __salt__["cmd.retcode"]("cryptsetup close {}".format(name)) + code = __salt__["cmd.retcode"](f"cryptsetup close {name}") return code == 0 diff --git a/salt/modules/csf.py b/salt/modules/csf.py index 1ab12cab941..b3d669547ce 100644 --- a/salt/modules/csf.py +++ b/salt/modules/csf.py @@ -37,7 +37,7 @@ def _temp_exists(method, ip): def _exists_with_port(method, rule): - path = "/etc/csf/csf.{}".format(method) + path = f"/etc/csf/csf.{method}" return __salt__["file.contains"](path, rule) @@ -71,7 +71,7 @@ def exists( ip, port, proto, direction, port_origin, ip_origin, comment ) return _exists_with_port(method, rule) - exists = __salt__["cmd.run_all"]("egrep ^'{} +' /etc/csf/csf.{}".format(ip, method)) + exists = __salt__["cmd.run_all"](f"egrep ^'{ip} +' /etc/csf/csf.{method}") return not bool(exists["retcode"]) @@ -87,7 +87,7 @@ def __csf_cmd(cmd): ret = out["stdout"] else: ret = out["stderr"] - raise CommandExecutionError("csf failed: {}".format(ret)) + raise CommandExecutionError(f"csf failed: {ret}") else: ret = out["stdout"] return ret @@ -123,9 +123,9 @@ def _build_args(method, ip, comment): Returns the cmd args for csf basic allow/deny commands. """ opt = _get_opt(method) - args = "{} {}".format(opt, ip) + args = f"{opt} {ip}" if comment: - args += " {}".format(comment) + args += f" {comment}" return args @@ -178,7 +178,7 @@ def _build_port_rule(ip, port, proto, direction, port_origin, ip_origin, comment } rule = "{proto}|{direction}|{port_origin}={port}|{ip_origin}={ip}".format(**kwargs) if comment: - rule += " #{}".format(comment) + rule += f" #{comment}" return rule @@ -207,8 +207,8 @@ def _remove_access_rule_with_port( rule = rule.replace("|", "[|]") rule = rule.replace(".", "[.]") result = __salt__["file.replace"]( - "/etc/csf/csf.{}".format(method), - pattern="^{}(( +)?\\#.*)?$\n".format(rule), # pylint: disable=W1401 + f"/etc/csf/csf.{method}", + pattern=f"^{rule}(( +)?\\#.*)?$\n", # pylint: disable=W1401 repl="", ) @@ -233,7 +233,7 @@ def split_option(option): def get_option(option): - pattern = r'^{}(\ +)?\=(\ +)?".*"$'.format(option) # pylint: disable=W1401 + pattern = rf'^{option}(\ +)?\=(\ +)?".*"$' # pylint: disable=W1401 grep = __salt__["file.grep"]("/etc/csf/csf.conf", pattern, "-E") if "stdout" in grep and grep["stdout"]: line = grep["stdout"] @@ -247,8 +247,8 @@ def set_option(option, value): return {"error": "No such option exists in csf.conf"} result = __salt__["file.replace"]( "/etc/csf/csf.conf", - pattern=r'^{}(\ +)?\=(\ +)?".*"'.format(option), # pylint: disable=W1401 - repl='{} = "{}"'.format(option, value), + pattern=rf'^{option}(\ +)?\=(\ +)?".*"', # pylint: disable=W1401 + repl=f'{option} = "{value}"', ) return result @@ -279,9 +279,9 @@ def skip_nics(nics, ipv6=False): result = __salt__["file.replace"]( "/etc/csf/csf.conf", # pylint: disable=anomalous-backslash-in-string - pattern=r'^ETH{}_DEVICE_SKIP(\ +)?\=(\ +)?".*"'.format(ipv6), + pattern=rf'^ETH{ipv6}_DEVICE_SKIP(\ +)?\=(\ +)?".*"', # pylint: enable=anomalous-backslash-in-string - repl='ETH{}_DEVICE_SKIP = "{}"'.format(ipv6, nics_csv), + repl=f'ETH{ipv6}_DEVICE_SKIP = "{nics_csv}"', ) return result @@ -326,7 +326,7 @@ def _access_rule_with_port( ip_origin=ip_origin, comment=comment, ) - path = "/etc/csf/csf.{}".format(method) + path = f"/etc/csf/csf.{method}" results[direction] = __salt__["file.append"](path, rule) return results @@ -358,13 +358,13 @@ def _build_tmp_access_args(method, ip, ttl, port, direction, comment): Builds the cmd args for temporary access/deny opts. """ opt = _get_opt(method) - args = "{} {} {}".format(opt, ip, ttl) + args = f"{opt} {ip} {ttl}" if port: - args += " -p {}".format(port) + args += f" -p {port}" if direction: - args += " -d {}".format(direction) + args += f" -d {direction}" if comment: - args += " #{}".format(comment) + args += f" #{comment}" return args @@ -515,7 +515,7 @@ def deny( def remove_temp_rule(ip): opt = _get_opt("temprm") - args = "{} {}".format(opt, ip) + args = f"{opt} {ip}" return __csf_cmd(args) @@ -608,9 +608,9 @@ def allow_ports(ports, proto="tcp", direction="in"): result = __salt__["file.replace"]( "/etc/csf/csf.conf", # pylint: disable=anomalous-backslash-in-string - pattern=r'^{}_{}(\ +)?\=(\ +)?".*"$'.format(proto, direction), + pattern=rf'^{proto}_{direction}(\ +)?\=(\ +)?".*"$', # pylint: enable=anomalous-backslash-in-string - repl='{}_{} = "{}"'.format(proto, direction, ports_csv), + repl=f'{proto}_{direction} = "{ports_csv}"', ) results.append(result) @@ -635,7 +635,7 @@ def get_ports(proto="tcp", direction="in"): _validate_direction_and_proto(direction, proto) directions = build_directions(direction) for direction in directions: - option = "{}_{}".format(proto, direction) + option = f"{proto}_{direction}" results[direction] = _csf_to_list(option) return results @@ -701,7 +701,7 @@ def _toggle_testing(val): result = __salt__["file.replace"]( "/etc/csf/csf.conf", pattern=r'^TESTING(\ +)?\=(\ +)?".*"', # pylint: disable=W1401 - repl='TESTING = "{}"'.format(val), + repl=f'TESTING = "{val}"', ) return result diff --git a/salt/modules/cyg.py b/salt/modules/cyg.py index 9f7a61af59a..b76cbeb8010 100644 --- a/salt/modules/cyg.py +++ b/salt/modules/cyg.py @@ -45,7 +45,7 @@ def _get_cyg_dir(cyg_arch="x86_64"): elif cyg_arch == "x86": return "cygwin" - raise SaltInvocationError("Invalid architecture {arch}".format(arch=cyg_arch)) + raise SaltInvocationError(f"Invalid architecture {cyg_arch}") def _check_cygwin_installed(cyg_arch="x86_64"): @@ -129,9 +129,9 @@ def _run_silent_cygwin(cyg_arch="x86_64", args=None, mirrors=None): installation up and running. """ cyg_cache_dir = os.sep.join(["c:", "cygcache"]) - cyg_setup = "setup-{}.exe".format(cyg_arch) + cyg_setup = f"setup-{cyg_arch}.exe" cyg_setup_path = os.sep.join([cyg_cache_dir, cyg_setup]) - cyg_setup_source = "http://cygwin.com/{}".format(cyg_setup) + cyg_setup_source = f"http://cygwin.com/{cyg_setup}" # cyg_setup_source_hash = 'http://cygwin.com/{0}.sig'.format(cyg_setup) # until a hash gets published that we can verify the newest setup against @@ -147,15 +147,15 @@ def _run_silent_cygwin(cyg_arch="x86_64", args=None, mirrors=None): setup_command = cyg_setup_path options = [] - options.append("--local-package-dir {}".format(cyg_cache_dir)) + options.append(f"--local-package-dir {cyg_cache_dir}") if mirrors is None: mirrors = [{DEFAULT_MIRROR: DEFAULT_MIRROR_KEY}] for mirror in mirrors: for mirror_url, key in mirror.items(): - options.append("--site {}".format(mirror_url)) + options.append(f"--site {mirror_url}") if key: - options.append("--pubkey {}".format(key)) + options.append(f"--pubkey {key}") options.append("--no-desktop") options.append("--quiet-mode") options.append("--disable-buggy-antivirus") @@ -211,7 +211,7 @@ def install(packages=None, cyg_arch="x86_64", mirrors=None): args = [] # If we want to install packages if packages is not None: - args.append("--packages {pkgs}".format(pkgs=packages)) + args.append(f"--packages {packages}") # but we don't have cygwin installed yet if not _check_cygwin_installed(cyg_arch): # install just the base system @@ -240,7 +240,7 @@ def uninstall(packages, cyg_arch="x86_64", mirrors=None): """ args = [] if packages is not None: - args.append("--remove-packages {pkgs}".format(pkgs=packages)) + args.append(f"--remove-packages {packages}") LOG.debug("args: %s", args) if not _check_cygwin_installed(cyg_arch): LOG.debug("We're convinced cygwin isn't installed") diff --git a/salt/modules/daemontools.py b/salt/modules/daemontools.py index 84a9dc2eabf..7892cb561b8 100644 --- a/salt/modules/daemontools.py +++ b/salt/modules/daemontools.py @@ -44,7 +44,7 @@ def __virtual__(): BINS = frozenset(("svc", "supervise", "svok")) if all(salt.utils.path.which(b) for b in BINS) and SERVICE_DIR: return __virtualname__ - return (False, "Missing dependency: {}".format(BINS)) + return (False, f"Missing dependency: {BINS}") def _service_path(name): @@ -53,7 +53,7 @@ def _service_path(name): """ if not SERVICE_DIR: raise CommandExecutionError("Could not find service directory.") - return "{}/{}".format(SERVICE_DIR, name) + return f"{SERVICE_DIR}/{name}" # -- states.service compatible args @@ -67,8 +67,8 @@ def start(name): salt '*' daemontools.start """ - __salt__["file.remove"]("{}/down".format(_service_path(name))) - cmd = "svc -u {}".format(_service_path(name)) + __salt__["file.remove"](f"{_service_path(name)}/down") + cmd = f"svc -u {_service_path(name)}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -83,8 +83,8 @@ def stop(name): salt '*' daemontools.stop """ - __salt__["file.touch"]("{}/down".format(_service_path(name))) - cmd = "svc -d {}".format(_service_path(name)) + __salt__["file.touch"](f"{_service_path(name)}/down") + cmd = f"svc -d {_service_path(name)}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -98,7 +98,7 @@ def term(name): salt '*' daemontools.term """ - cmd = "svc -t {}".format(_service_path(name)) + cmd = f"svc -t {_service_path(name)}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -158,7 +158,7 @@ def status(name, sig=None): salt '*' daemontools.status """ - cmd = "svstat {}".format(_service_path(name)) + cmd = f"svstat {_service_path(name)}" out = __salt__["cmd.run_stdout"](cmd, python_shell=False) try: pid = re.search(r"\(pid (\d+)\)", out).group(1) diff --git a/salt/modules/datadog_api.py b/salt/modules/datadog_api.py index 57ce01953f6..74ba7de0e29 100644 --- a/salt/modules/datadog_api.py +++ b/salt/modules/datadog_api.py @@ -165,7 +165,7 @@ def cancel_downtime(api_key=None, app_key=None, scope=None, id=None): ret["comment"] = "Successfully cancelled downtime" else: ret["response"] = response.text - ret["comment"] = "Status Code: {}".format(response.status_code) + ret["comment"] = f"Status Code: {response.status_code}" return ret else: raise SaltInvocationError("One of id or scope must be specified") diff --git a/salt/modules/ddns.py b/salt/modules/ddns.py index 60bccff0719..54132ae21e0 100644 --- a/salt/modules/ddns.py +++ b/salt/modules/ddns.py @@ -62,7 +62,7 @@ def _config(name, key=None, **kwargs): if name in kwargs: value = kwargs[name] else: - value = __salt__["config.option"]("ddns.{}".format(key)) + value = __salt__["config.option"](f"ddns.{key}") if not value: value = None return value @@ -85,7 +85,7 @@ def add_host( replace=True, timeout=5, port=53, - **kwargs + **kwargs, ): """ Add, replace, or update the A and PTR (reverse) records for a host. @@ -100,7 +100,7 @@ def add_host( if res is False: return False - fqdn = "{}.{}.".format(name, zone) + fqdn = f"{name}.{zone}." parts = ip.split(".")[::-1] popped = [] @@ -130,7 +130,7 @@ def delete_host(zone, name, nameserver="127.0.0.1", timeout=5, port=53, **kwargs salt ns1 ddns.delete_host example.com host1 """ - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, "A") answer = dns.query.udp(request, nameserver, timeout, port) try: @@ -161,7 +161,7 @@ def delete_host(zone, name, nameserver="127.0.0.1", timeout=5, port=53, **kwargs nameserver=nameserver, timeout=timeout, port=port, - **kwargs + **kwargs, ) if ptr: res = True @@ -178,7 +178,7 @@ def update( timeout=5, replace=False, port=53, - **kwargs + **kwargs, ): """ Add, replace, or update a DNS record. @@ -197,7 +197,7 @@ def update( if name[-1:] == ".": fqdn = name else: - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) @@ -240,7 +240,7 @@ def delete( nameserver="127.0.0.1", timeout=5, port=53, - **kwargs + **kwargs, ): """ Delete a DNS record. @@ -256,7 +256,7 @@ def delete( if name[-1:] == ".": fqdn = name else: - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, (rdtype or "ANY")) answer = dns.query.udp(request, nameserver, timeout, port) diff --git a/salt/modules/deb_postgres.py b/salt/modules/deb_postgres.py index d92859562d4..ecd339e08f2 100644 --- a/salt/modules/deb_postgres.py +++ b/salt/modules/deb_postgres.py @@ -2,6 +2,7 @@ Module to provide Postgres compatibility to salt for debian family specific tools. """ + import logging import shlex @@ -74,7 +75,7 @@ def cluster_create( cmd += ["--data-checksums"] if wal_segsize: cmd += ["--wal-segsize", wal_segsize] - cmdstr = " ".join([shlex.quote(c) for c in cmd]) + cmdstr = shlex.join(cmd) ret = __salt__["cmd.run_all"](cmdstr, python_shell=False) if ret.get("retcode", 0) != 0: log.error("Error creating a Postgresql cluster %s/%s", version, name) @@ -95,7 +96,7 @@ def cluster_list(verbose=False): salt '*' postgres.cluster_list verbose=True """ cmd = [salt.utils.path.which("pg_lsclusters"), "--no-header"] - ret = __salt__["cmd.run_all"](" ".join([shlex.quote(c) for c in cmd])) + ret = __salt__["cmd.run_all"](shlex.join(cmd)) if ret.get("retcode", 0) != 0: log.error("Error listing clusters") cluster_dict = _parse_pg_lscluster(ret["stdout"]) @@ -139,7 +140,7 @@ def cluster_remove(version, name="main", stop=False): if stop: cmd += ["--stop"] cmd += [str(version), name] - cmdstr = " ".join([shlex.quote(c) for c in cmd]) + cmdstr = shlex.join(cmd) ret = __salt__["cmd.run_all"](cmdstr, python_shell=False) # FIXME - return Boolean ? if ret.get("retcode", 0) != 0: diff --git a/salt/modules/debconfmod.py b/salt/modules/debconfmod.py index b4cd3a1934b..7f7644fb84b 100644 --- a/salt/modules/debconfmod.py +++ b/salt/modules/debconfmod.py @@ -106,7 +106,7 @@ def _set_file(path): """ Execute the set selections command for debconf """ - cmd = "debconf-set-selections {}".format(path) + cmd = f"debconf-set-selections {path}" __salt__["cmd.run_stdout"](cmd, python_shell=False) @@ -127,7 +127,7 @@ def set_(package, question, type, value, *extra): fd_, fname = salt.utils.files.mkstemp(prefix="salt-", close_fd=False) - line = "{} {} {} {}".format(package, question, type, value) + line = f"{package} {question} {type} {value}" os.write(fd_, salt.utils.stringutils.to_bytes(line)) os.close(fd_) @@ -169,7 +169,7 @@ def set_template(path, template, context, defaults, saltenv="base", **kwargs): saltenv=saltenv, context=context, defaults=defaults, - **kwargs + **kwargs, ) return set_file(path, saltenv, **kwargs) diff --git a/salt/modules/debian_ip.py b/salt/modules/debian_ip.py index 4a7062c48fc..9953b5c51ef 100644 --- a/salt/modules/debian_ip.py +++ b/salt/modules/debian_ip.py @@ -5,6 +5,7 @@ References: * http://www.debian.org/doc/manuals/debian-reference/ch05.en.html """ + import functools import io import logging @@ -365,9 +366,9 @@ def __within2(value, within=None, errmsg=None, dtype=None): "__name__", hasattr(dtype, "__class__") and getattr(dtype.__class__, "name", dtype), ) - errmsg = "{} within '{}'".format(typename, within) + errmsg = f"{typename} within '{within}'" else: - errmsg = "within '{}'".format(within) + errmsg = f"within '{within}'" return (valid, _value, errmsg) @@ -386,7 +387,7 @@ def __space_delimited_list(value): return ( False, value, - "{} is not a valid space-delimited value.\n".format(value), + f"{value} is not a valid space-delimited value.\n", ) @@ -548,8 +549,7 @@ def _parse_interfaces(interface_files=None): # Add this later. if os.path.exists(_DEB_NETWORK_DIR): interface_files += [ - "{}/{}".format(_DEB_NETWORK_DIR, dir) - for dir in os.listdir(_DEB_NETWORK_DIR) + f"{_DEB_NETWORK_DIR}/{dir}" for dir in os.listdir(_DEB_NETWORK_DIR) ] if os.path.isfile(_DEB_NETWORK_FILE): @@ -689,7 +689,7 @@ def _filter_malformed_interfaces(*, adapters): if iface_name == "source": continue if "data" not in adapters[iface_name]: - msg = "Interface file malformed for interface: {}.".format(iface_name) + msg = f"Interface file malformed for interface: {iface_name}." log.error(msg) adapters.pop(iface_name) continue @@ -908,7 +908,6 @@ def _parse_settings_bond_0(opts, iface, bond_def): def _parse_settings_bond_1(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond1. If an option has a value that is not expected, this @@ -995,7 +994,6 @@ def _parse_settings_bond_2(opts, iface, bond_def): def _parse_settings_bond_3(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond3. If an option has a value that is not expected, this @@ -1082,7 +1080,6 @@ def _parse_settings_bond_4(opts, iface, bond_def): def _parse_settings_bond_5(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond5. If an option has a value that is not expected, this @@ -1121,7 +1118,6 @@ def _parse_settings_bond_5(opts, iface, bond_def): def _parse_settings_bond_6(opts, iface, bond_def): - """ Filters given options and outputs valid settings for bond6. If an option has a value that is not expected, this @@ -1201,7 +1197,7 @@ def _parse_bridge_opts(opts, iface): try: port, cost_or_prio = opts[opt].split() int(cost_or_prio) - config.update({opt: "{} {}".format(port, cost_or_prio)}) + config.update({opt: f"{port} {cost_or_prio}"}) except ValueError: _raise_error_iface(iface, opt, ["interface integer"]) @@ -1295,9 +1291,9 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): tmp_ethtool = _parse_ethtool_pppoe_opts(opts, iface) if tmp_ethtool: for item in tmp_ethtool: - adapters[iface]["data"][addrfam][ - _DEB_CONFIG_PPPOE_OPTS[item] - ] = tmp_ethtool[item] + adapters[iface]["data"][addrfam][_DEB_CONFIG_PPPOE_OPTS[item]] = ( + tmp_ethtool[item] + ) iface_data[addrfam]["addrfam"] = addrfam opts.pop("mode", None) @@ -1350,7 +1346,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): iface_data["inet6"][opt] = opts[opt] # Remove incomplete/disabled inet blocks - for (addrfam, opt) in [("inet", "enable_ipv4"), ("inet6", "enable_ipv6")]: + for addrfam, opt in [("inet", "enable_ipv4"), ("inet6", "enable_ipv6")]: if opts.get(opt, None) is False: iface_data.pop(addrfam) elif iface_data[addrfam].get("addrfam", "") != addrfam: @@ -1633,15 +1629,15 @@ def build_bond(iface, **settings): if "test" in settings and settings["test"]: return _read_temp(data) - _write_file(iface, data, _DEB_NETWORK_CONF_FILES, "{}.conf".format(iface)) - path = os.path.join(_DEB_NETWORK_CONF_FILES, "{}.conf".format(iface)) + _write_file(iface, data, _DEB_NETWORK_CONF_FILES, f"{iface}.conf") + path = os.path.join(_DEB_NETWORK_CONF_FILES, f"{iface}.conf") if deb_major == "5": for line_type in ("alias", "options"): cmd = [ "sed", "-i", "-e", - r"/^{}\s{}.*/d".format(line_type, iface), + rf"/^{line_type}\s{iface}.*/d", "/etc/modprobe.conf", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -1785,7 +1781,7 @@ def get_bond(iface): salt '*' ip.get_bond bond0 """ - path = os.path.join(_DEB_NETWORK_CONF_FILES, "{}.conf".format(iface)) + path = os.path.join(_DEB_NETWORK_CONF_FILES, f"{iface}.conf") return _read_file(path) @@ -1891,10 +1887,10 @@ def get_routes(iface): salt '*' ip.get_routes eth0 """ - filename = os.path.join(_DEB_NETWORK_UP_DIR, "route-{}".format(iface)) + filename = os.path.join(_DEB_NETWORK_UP_DIR, f"route-{iface}") results = _read_file(filename) - filename = os.path.join(_DEB_NETWORK_DOWN_DIR, "route-{}".format(iface)) + filename = os.path.join(_DEB_NETWORK_DOWN_DIR, f"route-{iface}") results += _read_file(filename) return results @@ -2035,20 +2031,20 @@ def build_network_settings(**settings): for item in _read_file(_DEB_RESOLV_FILE): if domain_prog.match(item): - item = "domain {}".format(domainname) + item = f"domain {domainname}" elif search_prog.match(item): - item = "search {}".format(searchdomain) + item = f"search {searchdomain}" new_contents.append(item) # A domain line didn't exist so we'll add one in # with the new domainname if "domain" not in resolve: - new_contents.insert(0, "domain {}".format(domainname)) + new_contents.insert(0, f"domain {domainname}") # A search line didn't exist so we'll add one in # with the new search domain if "search" not in resolve: - new_contents.insert("domain" in resolve, "search {}".format(searchdomain)) + new_contents.insert("domain" in resolve, f"search {searchdomain}") new_resolv = "\n".join(new_contents) diff --git a/salt/modules/debian_service.py b/salt/modules/debian_service.py index 04c6cd5d37b..e11d9d18e7e 100644 --- a/salt/modules/debian_service.py +++ b/salt/modules/debian_service.py @@ -74,9 +74,9 @@ def get_enabled(): salt '*' service.get_enabled """ - prefix = "/etc/rc[S{}].d/S".format(_get_runlevel()) + prefix = f"/etc/rc[S{_get_runlevel()}].d/S" ret = set() - for line in [x.rsplit(os.sep, 1)[-1] for x in glob.glob("{}*".format(prefix))]: + for line in [x.rsplit(os.sep, 1)[-1] for x in glob.glob(f"{prefix}*")]: ret.add(re.split(r"\d+", line)[-1]) return sorted(ret) @@ -277,7 +277,7 @@ def disable(name, **kwargs): salt '*' service.disable """ - cmd = "update-rc.d {} disable".format(name) + cmd = f"update-rc.d {name} disable" return not __salt__["cmd.retcode"](cmd) diff --git a/salt/modules/debuild_pkgbuild.py b/salt/modules/debuild_pkgbuild.py index b63f0b3f183..cc5217b7b72 100644 --- a/salt/modules/debuild_pkgbuild.py +++ b/salt/modules/debuild_pkgbuild.py @@ -9,7 +9,6 @@ environments. This also provides a function to generate debian repositories This module implements the pkgbuild interface """ - import errno import logging import os @@ -91,9 +90,7 @@ def _check_repo_gpg_phrase_utils(): if __salt__["file.file_exists"](util_name): return True else: - raise CommandExecutionError( - "utility '{}' needs to be installed".format(util_name) - ) + raise CommandExecutionError(f"utility '{util_name}' needs to be installed") def _get_build_env(env): @@ -106,8 +103,8 @@ def _get_build_env(env): if not isinstance(env, dict): raise SaltInvocationError("'env' must be a Python dictionary") for key, value in env.items(): - env_override += "{}={}\n".format(key, value) - env_override += "export {}\n".format(key) + env_override += f"{key}={value}\n" + env_override += f"export {key}\n" return env_override @@ -140,7 +137,7 @@ def _get_repo_options_env(env): raise SaltInvocationError("'env' must be a Python dictionary") for key, value in env.items(): if key == "OPTIONS": - env_options += "{}\n".format(value) + env_options += f"{value}\n" return env_options @@ -195,7 +192,7 @@ def _get_repo_dists_env(env): if env is None: for key, value in dflts_dict.items(): if dflts_dict[key][0] == "M": - env_dists += "{}: {}\n".format(dflts_dict[key][1], dflts_dict[key][2]) + env_dists += f"{dflts_dict[key][1]}: {dflts_dict[key][2]}\n" if key == "CODENAME": codename = dflts_dict[key][2] return (codename, env_dists) @@ -211,15 +208,15 @@ def _get_repo_dists_env(env): if key == "CODENAME": codename = value if dflts_dict[key][0] != "I": - env_dists += "{}: {}\n".format(dflts_dict[key][1], value) + env_dists += f"{dflts_dict[key][1]}: {value}\n" else: - env_dists += "{}: {}\n".format(key, value) + env_dists += f"{key}: {value}\n" # ensure mandatories are included env_keys = list(env.keys()) for key in env_keys: if key in dflts_keys and dflts_dict[key][0] == "M" and key not in env_man_seen: - env_dists += "{}: {}\n".format(dflts_dict[key][1], dflts_dict[key][2]) + env_dists += f"{dflts_dict[key][1]}: {dflts_dict[key][2]}\n" if key == "CODENAME": codename = value @@ -257,7 +254,7 @@ def _create_pbuilders(env, runas="root"): Ensure the user has correct permissions to any files and directories which are to be utilized. """ - home = os.path.expanduser("~{}".format(runas)) + home = os.path.expanduser(f"~{runas}") pbuilderrc = os.path.join(home, ".pbuilderrc") if not os.path.isfile(pbuilderrc): raise SaltInvocationError("pbuilderrc environment is incorrectly setup") @@ -426,25 +423,25 @@ def make_src_pkg(dest_dir, spec, sources, env=None, saltenv="base", runas="root" debname_orig = debname + ".orig.tar.gz" abspath_debname = os.path.join(tree_base, debname) - cmd = "tar -xvzf {}".format(salttarball) + cmd = f"tar -xvzf {salttarball}" retrc = __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user) - cmd = "mv {} {}".format(salttar_name, debname) + cmd = f"mv {salttar_name} {debname}" retrc |= __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user) - cmd = "tar -cvzf {} {}".format(os.path.join(tree_base, debname_orig), debname) + cmd = f"tar -cvzf {os.path.join(tree_base, debname_orig)} {debname}" retrc |= __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user) - cmd = "rm -f {}".format(salttarball) + cmd = f"rm -f {salttarball}" retrc |= __salt__["cmd.retcode"](cmd, cwd=tree_base, runas=root_user, env=env) - cmd = "cp {} {}".format(spec_pathfile, abspath_debname) + cmd = f"cp {spec_pathfile} {abspath_debname}" retrc |= __salt__["cmd.retcode"](cmd, cwd=abspath_debname, runas=root_user) - cmd = "tar -xvJf {}".format(spec_pathfile) + cmd = f"tar -xvJf {spec_pathfile}" retrc |= __salt__["cmd.retcode"](cmd, cwd=abspath_debname, runas=root_user, env=env) - cmd = "rm -f {}".format(os.path.basename(spec_pathfile)) + cmd = f"rm -f {os.path.basename(spec_pathfile)}" retrc |= __salt__["cmd.retcode"](cmd, cwd=abspath_debname, runas=root_user) cmd = "debuild -S -uc -us -sa" retrc |= __salt__["cmd.retcode"]( cmd, cwd=abspath_debname, runas=root_user, python_shell=True, env=env ) - cmd = "rm -fR {}".format(abspath_debname) + cmd = f"rm -fR {abspath_debname}" retrc |= __salt__["cmd.retcode"](cmd, runas=root_user) if retrc != 0: raise SaltInvocationError( @@ -512,13 +509,13 @@ def build( # ensure pbuilder setup from runas if other than root if runas != root_user: - user_home = os.path.expanduser("~{}".format(runas)) + user_home = os.path.expanduser(f"~{runas}") root_home = os.path.expanduser("~root") - cmd = "cp {}/.pbuilderrc {}/".format(user_home, root_home) + cmd = f"cp {user_home}/.pbuilderrc {root_home}/" retrc = __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) - cmd = "cp -R {}/.pbuilder-hooks {}/".format(user_home, root_home) + cmd = f"cp -R {user_home}/.pbuilder-hooks {root_home}/" retrc = __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) @@ -540,7 +537,7 @@ def build( results_dir = "/var/cache/pbuilder/result" # ensure clean - cmd = "rm -fR {}".format(results_dir) + cmd = f"rm -fR {results_dir}" retrc |= __salt__["cmd.retcode"](cmd, runas=root_user, python_shell=True, env=env) # dscs should only contain salt orig and debian tarballs and dsc file @@ -559,7 +556,7 @@ def build( retrc |= __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) - cmd = '/usr/sbin/pbuilder build --debbuildopts "-sa" {}'.format(dsc) + cmd = f'/usr/sbin/pbuilder build --debbuildopts "-sa" {dsc}' retrc |= __salt__["cmd.retcode"]( cmd, runas=root_user, python_shell=True, env=env ) @@ -712,15 +709,15 @@ def make_repo( phrase = "" # preset passphase and interaction with gpg-agent - gpg_info_file = "{}/gpg-agent-info-salt".format(gnupghome) - gpg_tty_info_file = "{}/gpg-tty-info-salt".format(gnupghome) + gpg_info_file = f"{gnupghome}/gpg-agent-info-salt" + gpg_tty_info_file = f"{gnupghome}/gpg-tty-info-salt" # if using older than gnupg 2.1, then env file exists older_gnupg = __salt__["file.file_exists"](gpg_info_file) if keyid is not None: with salt.utils.files.fopen(repoconfdist, "a") as fow: - fow.write(salt.utils.stringutils.to_str("SignWith: {}\n".format(keyid))) + fow.write(salt.utils.stringutils.to_str(f"SignWith: {keyid}\n")) # import_keys pkg_pub_key_file = "{}/{}".format( @@ -828,7 +825,7 @@ def make_repo( # sign_it_here if older_gnupg: if local_keyid is not None: - cmd = "debsign --re-sign -k {} {}".format(keyid, abs_file) + cmd = f"debsign --re-sign -k {keyid} {abs_file}" retrc |= __salt__["cmd.retcode"]( cmd, runas=runas, cwd=repodir, use_vt=True, env=env ) @@ -846,7 +843,7 @@ def make_repo( if local_keyid is not None: number_retries = timeout / interval times_looped = 0 - error_msg = "Failed to debsign file {}".format(abs_file) + error_msg = f"Failed to debsign file {abs_file}" if ( __grains__["os"] in ["Ubuntu"] and __grains__["osmajorrelease"] < 18 @@ -854,7 +851,7 @@ def make_repo( __grains__["os"] in ["Debian"] and __grains__["osmajorrelease"] <= 8 ): - cmd = "debsign --re-sign -k {} {}".format(keyid, abs_file) + cmd = f"debsign --re-sign -k {keyid} {abs_file}" try: proc = salt.utils.vt.Terminal( cmd, @@ -903,7 +900,7 @@ def make_repo( number_retries = timeout / interval times_looped = 0 - error_msg = "Failed to reprepro includedsc file {}".format(abs_file) + error_msg = f"Failed to reprepro includedsc file {abs_file}" cmd = ( "reprepro --ignore=wrongdistribution --component=main -Vb ." " includedsc {} {}".format(codename, abs_file) diff --git a/salt/modules/defaults.py b/salt/modules/defaults.py index c807337dc2c..48ce0b11819 100644 --- a/salt/modules/defaults.py +++ b/salt/modules/defaults.py @@ -3,7 +3,6 @@ Module to work with salt formula defaults files """ - import copy import logging import os diff --git a/salt/modules/devinfo.py b/salt/modules/devinfo.py index d6c530aa2e2..ea9d3f5da67 100644 --- a/salt/modules/devinfo.py +++ b/salt/modules/devinfo.py @@ -293,7 +293,7 @@ def hwinfo(items=None, short=True, listmd=False, devices=None): cmd = ["hwinfo"] for item in items: - cmd.append("--{}".format(item)) + cmd.append(f"--{item}") if short: cmd.append("--short") @@ -302,7 +302,7 @@ def hwinfo(items=None, short=True, listmd=False, devices=None): cmd.append("--listmd") for device in devices: - cmd.append("--only {}".format(device)) + cmd.append(f"--only {device}") out = __salt__["cmd.run_stdout"](cmd) result["hwinfo"] = _hwinfo_parse(out, short) diff --git a/salt/modules/devmap.py b/salt/modules/devmap.py index 247d0293c2e..9f14ee6c9c8 100644 --- a/salt/modules/devmap.py +++ b/salt/modules/devmap.py @@ -30,7 +30,7 @@ def multipath_flush(device): salt '*' devmap.multipath_flush mpath1 """ if not os.path.exists(device): - return "{} does not exist".format(device) + return f"{device} does not exist" - cmd = "multipath -f {}".format(device) + cmd = f"multipath -f {device}" return __salt__["cmd.run"](cmd).splitlines() diff --git a/salt/modules/dig.py b/salt/modules/dig.py index ea0463075d4..1cd7ad37e33 100644 --- a/salt/modules/dig.py +++ b/salt/modules/dig.py @@ -84,7 +84,7 @@ def A(host, nameserver=None): dig = ["dig", "+short", str(host), "A"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -116,7 +116,7 @@ def PTR(host, nameserver=None): dig = ["dig", "+short", "-x", str(host)] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -145,7 +145,7 @@ def AAAA(host, nameserver=None): dig = ["dig", "+short", str(host), "AAAA"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -175,7 +175,7 @@ def CNAME(host, nameserver=None): dig = ["dig", "+short", str(host), "CNAME"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -204,7 +204,7 @@ def NS(domain, resolve=True, nameserver=None): dig = ["dig", "+short", str(domain), "NS"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -243,7 +243,7 @@ def SPF(domain, record="SPF", nameserver=None): cmd = ["dig", "+short", str(domain), record] if nameserver is not None: - cmd.append("@{}".format(nameserver)) + cmd.append(f"@{nameserver}") result = __salt__["cmd.run_all"](cmd, python_shell=False) # In this case, 0 is not the same as False @@ -300,7 +300,7 @@ def MX(domain, resolve=False, nameserver=None): dig = ["dig", "+short", str(domain), "MX"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) # In this case, 0 is not the same as False @@ -334,7 +334,7 @@ def TXT(host, nameserver=None): dig = ["dig", "+short", str(host), "TXT"] if nameserver is not None: - dig.append("@{}".format(nameserver)) + dig.append(f"@{nameserver}") cmd = __salt__["cmd.run_all"](dig, python_shell=False) diff --git a/salt/modules/djangomod.py b/salt/modules/djangomod.py index 17942130e80..b66479f9a32 100644 --- a/salt/modules/djangomod.py +++ b/salt/modules/djangomod.py @@ -2,7 +2,6 @@ Manage Django sites """ - import os import salt.exceptions @@ -44,7 +43,7 @@ def command( env=None, runas=None, *args, - **kwargs + **kwargs, ): """ Run arbitrary django management command @@ -56,17 +55,17 @@ def command( salt '*' django.command """ dja = _get_django_admin(bin_env) - cmd = "{} {} --settings={}".format(dja, command, settings_module) + cmd = f"{dja} {command} --settings={settings_module}" if pythonpath: - cmd = "{} --pythonpath={}".format(cmd, pythonpath) + cmd = f"{cmd} --pythonpath={pythonpath}" for arg in args: - cmd = "{} --{}".format(cmd, arg) + cmd = f"{cmd} --{arg}" for key, value in kwargs.items(): if not key.startswith("__"): - cmd = "{} --{}={}".format(cmd, key, value) + cmd = f"{cmd} --{key}={value}" return __salt__["cmd.run"](cmd, env=env, runas=runas, python_shell=False) @@ -193,9 +192,9 @@ def migrate( args.append("noinput") if app_label and migration_name: - cmd = "migrate {} {}".format(app_label, migration_name) + cmd = f"migrate {app_label} {migration_name}" elif app_label: - cmd = "migrate {}".format(app_label) + cmd = f"migrate {app_label}" else: cmd = "migrate" @@ -240,7 +239,7 @@ def createsuperuser( env, runas, *args, - **kwargs + **kwargs, ) @@ -316,5 +315,5 @@ def collectstatic( env, runas, *args, - **kwargs + **kwargs, ) diff --git a/salt/modules/dnsmasq.py b/salt/modules/dnsmasq.py index e3f1d8bfa80..5aec67f959f 100644 --- a/salt/modules/dnsmasq.py +++ b/salt/modules/dnsmasq.py @@ -2,7 +2,6 @@ Module for managing dnsmasq """ - import logging import os @@ -114,13 +113,13 @@ def set_config(config_file="/etc/dnsmasq.conf", follow=True, **kwargs): for config in includes: __salt__["file.sed"]( path=config, - before="^{}=.*".format(key), - after="{}={}".format(key, kwargs[key]), + before=f"^{key}=.*", + after=f"{key}={kwargs[key]}", ) else: - __salt__["file.append"](config_file, "{}={}".format(key, kwargs[key])) + __salt__["file.append"](config_file, f"{key}={kwargs[key]}") else: - __salt__["file.append"](config_file, "{}={}".format(key, kwargs[key])) + __salt__["file.append"](config_file, f"{key}={kwargs[key]}") return ret_kwargs @@ -161,7 +160,7 @@ def _parse_dnamasq(filename): fileopts = {} if not os.path.isfile(filename): - raise CommandExecutionError("Error: No such file '{}'".format(filename)) + raise CommandExecutionError(f"Error: No such file '{filename}'") with salt.utils.files.fopen(filename, "r") as fp_: for line in fp_: diff --git a/salt/modules/dnsutil.py b/salt/modules/dnsutil.py index bc25f3d3386..5b677d777ee 100644 --- a/salt/modules/dnsutil.py +++ b/salt/modules/dnsutil.py @@ -74,13 +74,13 @@ def hosts_append(hostsfile="/etc/hosts", ip_addr=None, entries=None): host_list.remove(host) if not host_list: - return "No additional hosts were added to {}".format(hostsfile) + return f"No additional hosts were added to {hostsfile}" append_line = "\n{} {}".format(ip_addr, " ".join(host_list)) with salt.utils.files.fopen(hostsfile, "a") as fp_: fp_.write(salt.utils.stringutils.to_str(append_line)) - return "The following line was added to {}:{}".format(hostsfile, append_line) + return f"The following line was added to {hostsfile}:{append_line}" def hosts_remove(hostsfile="/etc/hosts", entries=None): @@ -103,7 +103,7 @@ def hosts_remove(hostsfile="/etc/hosts", entries=None): with salt.utils.files.fopen(hostsfile, "w") as out_file: for line in hosts.splitlines(): if not line or line.strip().startswith("#"): - out_file.write(salt.utils.stringutils.to_str("{}\n".format(line))) + out_file.write(salt.utils.stringutils.to_str(f"{line}\n")) continue comps = line.split() for host in host_list: @@ -149,7 +149,7 @@ def parse_zone(zonefile=None, zone=None): mode = "multi" multi = "" if mode == "multi": - multi += " {}".format(line) + multi += f" {line}" if ")" in line: mode = "single" line = multi.replace("(", "").replace(")", "") @@ -267,7 +267,7 @@ def A(host, nameserver=None): ] return addresses except socket.gaierror: - return "Unable to resolve {}".format(host) + return f"Unable to resolve {host}" return "This function requires dig, which is not currently available" @@ -299,7 +299,7 @@ def AAAA(host, nameserver=None): ] return addresses except socket.gaierror: - return "Unable to resolve {}".format(host) + return f"Unable to resolve {host}" return "This function requires dig, which is not currently available" @@ -394,7 +394,7 @@ def serial(zone="", update=False): grains = {} key = "dnsserial" if zone: - key += "_{}".format(zone) + key += f"_{zone}" stored = __salt__["grains.get"](key=key) present = time.strftime("%Y%m%d01") if not update: diff --git a/salt/modules/dockercompose.py b/salt/modules/dockercompose.py index 656af8d0d04..5ddc27d3480 100644 --- a/salt/modules/dockercompose.py +++ b/salt/modules/dockercompose.py @@ -103,7 +103,6 @@ Detailed Function Documentation ------------------------------- """ - import inspect import logging import os diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py index 1bdf22c6d6c..4bcf86ec4be 100644 --- a/salt/modules/dockermod.py +++ b/salt/modules/dockermod.py @@ -4495,9 +4495,9 @@ def load(path, repository=None, tag=None): result = tag_(top_level_images[0], repository=repository, tag=tag) ret["Image"] = tagged_image except IndexError: - ret[ - "Warning" - ] = "No top-level image layers were loaded, no image was tagged" + ret["Warning"] = ( + "No top-level image layers were loaded, no image was tagged" + ) except Exception as exc: # pylint: disable=broad-except ret["Warning"] = "Failed to tag {} as {}: {}".format( top_level_images[0], tagged_image, exc diff --git a/salt/modules/dpkg_lowpkg.py b/salt/modules/dpkg_lowpkg.py index eefd852c511..3a405862163 100644 --- a/salt/modules/dpkg_lowpkg.py +++ b/salt/modules/dpkg_lowpkg.py @@ -62,14 +62,14 @@ def bin_pkg_info(path, saltenv="base"): newpath = __salt__["cp.cache_file"](path, saltenv) if not newpath: raise CommandExecutionError( - "Unable to retrieve {} from saltenv '{}'".format(path, saltenv) + f"Unable to retrieve {path} from saltenv '{saltenv}'" ) path = newpath else: if not os.path.exists(path): - raise CommandExecutionError("{} does not exist on minion".format(path)) + raise CommandExecutionError(f"{path} does not exist on minion") elif not os.path.isabs(path): - raise SaltInvocationError("{} does not exist on minion".format(path)) + raise SaltInvocationError(f"{path} does not exist on minion") cmd = ["dpkg", "-I", path] result = __salt__["cmd.run_all"](cmd, output_loglevel="trace") @@ -99,7 +99,7 @@ def bin_pkg_info(path, saltenv="base"): osarch = __grains__.get("osarch", "") arch = ret["arch"] if arch != "all" and osarch == "amd64" and osarch != arch: - ret["name"] += ":{}".format(arch) + ret["name"] += f":{arch}" return ret @@ -120,7 +120,7 @@ def unpurge(*packages): ret = {} __salt__["cmd.run"]( ["dpkg", "--set-selections"], - stdin=r"\n".join(["{} install".format(x) for x in packages]), + stdin=r"\n".join([f"{x} install" for x in packages]), python_shell=False, output_loglevel="trace", ) @@ -317,7 +317,7 @@ def _get_pkg_license(pkg): :return: """ licenses = set() - cpr = "/usr/share/doc/{}/copyright".format(pkg) + cpr = f"/usr/share/doc/{pkg}/copyright" if os.path.exists(cpr): with salt.utils.files.fopen(cpr, errors="ignore") as fp_: for line in salt.utils.stringutils.to_unicode(fp_.read()).split(os.linesep): @@ -335,7 +335,7 @@ def _get_pkg_install_time(pkg): """ iso_time = None if pkg is not None: - location = "/var/lib/dpkg/info/{}.list".format(pkg) + location = f"/var/lib/dpkg/info/{pkg}.list" if os.path.exists(location): iso_time = ( datetime.datetime.utcfromtimestamp( diff --git a/salt/modules/drac.py b/salt/modules/drac.py index 86ff8eedd5a..cb25d91f6a0 100644 --- a/salt/modules/drac.py +++ b/salt/modules/drac.py @@ -2,7 +2,6 @@ Manage Dell DRAC """ - import logging import salt.utils.path @@ -43,7 +42,7 @@ def __execute_cmd(command): """ Execute rac commands """ - cmd = __salt__["cmd.run_all"]("racadm {}".format(command)) + cmd = __salt__["cmd.run_all"](f"racadm {command}") if cmd["retcode"] != 0: log.warning("racadm return an exit code '%s'.", cmd["retcode"]) @@ -106,7 +105,7 @@ def nameservers(*ns): for i in range(1, len(ns) + 1): if not __execute_cmd( - "config -g cfgLanNetworking -o cfgDNSServer{} {}".format(i, ns[i - 1]) + f"config -g cfgLanNetworking -o cfgDNSServer{i} {ns[i - 1]}" ): return False @@ -128,7 +127,7 @@ def syslog(server, enable=True): """ if enable and __execute_cmd("config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 1"): return __execute_cmd( - "config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {}".format(server) + f"config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {server}" ) return __execute_cmd("config -g cfgRemoteHosts -o cfgRhostsSyslogEnable 0") @@ -166,9 +165,7 @@ def list_users(): _username = "" for idx in range(1, 17): - cmd = __salt__["cmd.run_all"]( - "racadm getconfig -g cfgUserAdmin -i {}".format(idx) - ) + cmd = __salt__["cmd.run_all"](f"racadm getconfig -g cfgUserAdmin -i {idx}") if cmd["retcode"] != 0: log.warning("racadm return an exit code '%s'.", cmd["retcode"]) @@ -209,7 +206,7 @@ def delete_user(username, uid=None): if uid: return __execute_cmd( - 'config -g cfgUserAdmin -o cfgUserAdminUserName -i {} ""'.format(uid) + f'config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} ""' ) else: @@ -285,7 +282,7 @@ def create_user(username, password, permissions, users=None): # Create user accountvfirst if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} {}".format(uid, username) + f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} {username}" ): delete_user(username, uid) return False @@ -303,9 +300,7 @@ def create_user(username, password, permissions, users=None): return False # Enable users admin - if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminEnable -i {} 1".format(uid) - ): + if not __execute_cmd(f"config -g cfgUserAdmin -o cfgUserAdminEnable -i {uid} 1"): delete_user(username, uid) return False @@ -379,7 +374,7 @@ def set_snmp(community): salt dell drac.set_snmp public """ return __execute_cmd( - "config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {}".format(community) + f"config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {community}" ) @@ -394,7 +389,7 @@ def set_network(ip, netmask, gateway): salt dell drac.set_network [DRAC IP] [NETMASK] [GATEWAY] salt dell drac.set_network 192.168.0.2 255.255.255.0 192.168.0.1 """ - return __execute_cmd("setniccfg -s {} {} {}".format(ip, netmask, gateway)) + return __execute_cmd(f"setniccfg -s {ip} {netmask} {gateway}") def server_reboot(): diff --git a/salt/modules/dracr.py b/salt/modules/dracr.py index c790f5423b2..31a939a9267 100644 --- a/salt/modules/dracr.py +++ b/salt/modules/dracr.py @@ -4,7 +4,6 @@ Manage Dell DRAC. .. versionadded:: 2015.8.2 """ - import logging import os import re @@ -69,12 +68,12 @@ def __execute_cmd( if module.startswith("ALL_"): modswitch = "-a " + module[module.index("_") + 1 : len(module)].lower() else: - modswitch = "-m {}".format(module) + modswitch = f"-m {module}" else: modswitch = "" if not host: # This is a local call - cmd = __salt__["cmd.run_all"]("racadm {} {}".format(command, modswitch)) + cmd = __salt__["cmd.run_all"](f"racadm {command} {modswitch}") else: cmd = __salt__["cmd.run_all"]( "racadm -r {} -u {} -p {} {} {}".format( @@ -100,12 +99,12 @@ def __execute_ret( if module == "ALL": modswitch = "-a " else: - modswitch = "-m {}".format(module) + modswitch = f"-m {module}" else: modswitch = "" if not host: # This is a local call - cmd = __salt__["cmd.run_all"]("racadm {} {}".format(command, modswitch)) + cmd = __salt__["cmd.run_all"](f"racadm {command} {modswitch}") else: cmd = __salt__["cmd.run_all"]( "racadm -r {} -u {} -p {} {} {}".format( @@ -153,7 +152,7 @@ def get_dns_dracname(host=None, admin_username=None, admin_password=None): def set_dns_dracname(name, host=None, admin_username=None, admin_password=None): ret = __execute_ret( - "set iDRAC.NIC.DNSRacName {}".format(name), + f"set iDRAC.NIC.DNSRacName {name}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -256,7 +255,7 @@ def network_info(host=None, admin_username=None, admin_password=None, module=Non if module not in inv.get("switch") and module not in inv.get("server"): cmd = {} cmd["retcode"] = -1 - cmd["stdout"] = "No module {} found.".format(module) + cmd["stdout"] = f"No module {module} found." return cmd cmd = __execute_ret( @@ -293,7 +292,7 @@ def nameservers(ns, host=None, admin_username=None, admin_password=None, module= for i in range(1, len(ns) + 1): if not __execute_cmd( - "config -g cfgLanNetworking -o cfgDNSServer{} {}".format(i, ns[i - 1]), + f"config -g cfgLanNetworking -o cfgDNSServer{i} {ns[i - 1]}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -332,7 +331,7 @@ def syslog( module=None, ): return __execute_cmd( - "config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {}".format(server), + f"config -g cfgRemoteHosts -o cfgRhostsSyslogServer1 {server}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -386,7 +385,7 @@ def list_users(host=None, admin_username=None, admin_password=None, module=None) for idx in range(1, 17): cmd = __execute_ret( - "getconfig -g cfgUserAdmin -i {}".format(idx), + f"getconfig -g cfgUserAdmin -i {idx}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -434,7 +433,7 @@ def delete_user( if uid: return __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} ".format(uid), + f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} ", host=host, admin_username=admin_username, admin_password=admin_password, @@ -522,7 +521,7 @@ def deploy_password( on that then setting the password is much quicker. """ return __execute_cmd( - "deploy -u {} -p {}".format(username, password), + f"deploy -u {username} -p {password}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -545,7 +544,7 @@ def deploy_snmp(snmp, host=None, admin_username=None, admin_password=None, modul """ return __execute_cmd( - "deploy -v SNMPv2 {} ro".format(snmp), + f"deploy -v SNMPv2 {snmp} ro", host=host, admin_username=admin_username, admin_password=admin_password, @@ -599,7 +598,7 @@ def create_user( # Create user account first if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminUserName -i {} {}".format(uid, username), + f"config -g cfgUserAdmin -o cfgUserAdminUserName -i {uid} {username}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -620,9 +619,7 @@ def create_user( return False # Enable users admin - if not __execute_cmd( - "config -g cfgUserAdmin -o cfgUserAdminEnable -i {} 1".format(uid) - ): + if not __execute_cmd(f"config -g cfgUserAdmin -o cfgUserAdminEnable -i {uid} 1"): delete_user(username, uid) return False @@ -703,7 +700,7 @@ def set_snmp(community, host=None, admin_username=None, admin_password=None): salt dell dracr.set_snmp public """ return __execute_cmd( - "config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {}".format(community), + f"config -g cfgOobSnmp -o cfgOobSnmpAgentCommunity {community}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -767,7 +764,7 @@ def server_power( """ return __execute_cmd( - "serveraction {}".format(status), + f"serveraction {status}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1089,7 +1086,7 @@ def set_slotname(slot, name, host=None, admin_username=None, admin_password=None """ return __execute_cmd( - "config -g cfgServerInfo -o cfgServerName -i {} {}".format(slot, name), + f"config -g cfgServerInfo -o cfgServerName -i {slot} {name}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1121,7 +1118,7 @@ def set_chassis_name(name, host=None, admin_username=None, admin_password=None): """ return __execute_cmd( - "setsysinfo -c chassisname {}".format(name), + f"setsysinfo -c chassisname {name}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1265,7 +1262,7 @@ def set_chassis_location(location, host=None, admin_username=None, admin_passwor """ return __execute_cmd( - "setsysinfo -c chassislocation {}".format(location), + f"setsysinfo -c chassislocation {location}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1368,7 +1365,7 @@ def set_general( cfg_sec, cfg_var, val, host=None, admin_username=None, admin_password=None ): return __execute_cmd( - "config -g {} -o {} {}".format(cfg_sec, cfg_var, val), + f"config -g {cfg_sec} -o {cfg_var} {val}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1377,7 +1374,7 @@ def set_general( def get_general(cfg_sec, cfg_var, host=None, admin_username=None, admin_password=None): ret = __execute_ret( - "getconfig -g {} -o {}".format(cfg_sec, cfg_var), + f"getconfig -g {cfg_sec} -o {cfg_var}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1458,7 +1455,7 @@ def _update_firmware(cmd, host=None, admin_username=None, admin_password=None): def bare_rac_cmd(cmd, host=None, admin_username=None, admin_password=None): ret = __execute_ret( - "{}".format(cmd), + f"{cmd}", host=host, admin_username=admin_username, admin_password=admin_password, @@ -1488,13 +1485,13 @@ def update_firmware(filename, host=None, admin_username=None, admin_password=Non """ if os.path.exists(filename): return _update_firmware( - "update -f {}".format(filename), + f"update -f {filename}", host=None, admin_username=None, admin_password=None, ) else: - raise CommandExecutionError("Unable to find firmware file {}".format(filename)) + raise CommandExecutionError(f"Unable to find firmware file {filename}") def update_firmware_nfs_or_cifs( @@ -1533,13 +1530,13 @@ def update_firmware_nfs_or_cifs( """ if os.path.exists(filename): return _update_firmware( - "update -f {} -l {}".format(filename, share), + f"update -f {filename} -l {share}", host=None, admin_username=None, admin_password=None, ) else: - raise CommandExecutionError("Unable to find firmware file {}".format(filename)) + raise CommandExecutionError(f"Unable to find firmware file {filename}") # def get_idrac_nic() diff --git a/salt/modules/ebuildpkg.py b/salt/modules/ebuildpkg.py index 0e8fd851066..905f0339250 100644 --- a/salt/modules/ebuildpkg.py +++ b/salt/modules/ebuildpkg.py @@ -303,7 +303,7 @@ def _get_upgradable(backtrack=3): "--ask", "n", "--backtrack", - "{}".format(backtrack), + f"{backtrack}", "--pretend", "--update", "--newuse", @@ -547,7 +547,7 @@ def install( fromrepo=None, uses=None, binhost=None, - **kwargs + **kwargs, ): """ .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0 @@ -680,9 +680,9 @@ def install( if not version_num: version_num = "" if slot is not None: - version_num += ":{}".format(slot) + version_num += f":{slot}" if fromrepo is not None: - version_num += "::{}".format(fromrepo) + version_num += f"::{fromrepo}" if uses is not None: version_num += "[{}]".format(",".join(uses)) pkg_params = {name: version_num} @@ -724,11 +724,11 @@ def install( # If no prefix characters were supplied and verstr contains a version, use '=' if len(verstr) > 0 and verstr[0] != ":" and verstr[0] != "[": prefix = prefix or "=" - target = "{}{}-{}".format(prefix, param, verstr) + target = f"{prefix}{param}-{verstr}" else: - target = "{}{}".format(param, verstr) + target = f"{param}{verstr}" else: - target = "{}".format(param) + target = f"{param}" if "[" in target: old = __salt__["portage_config.get_flags_from_package_conf"]( @@ -842,10 +842,10 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None, **kwargs) full_atom = pkg if slot is not None: - full_atom = "{}:{}".format(full_atom, slot) + full_atom = f"{full_atom}:{slot}" if fromrepo is not None: - full_atom = "{}::{}".format(full_atom, fromrepo) + full_atom = f"{full_atom}::{fromrepo}" if binhost == "try": bin_opts = ["-g"] @@ -950,7 +950,7 @@ def upgrade(refresh=True, binhost=None, backtrack=3, **kwargs): "n", "--quiet", "--backtrack", - "{}".format(backtrack), + f"{backtrack}", "--update", "--newuse", "--deep", @@ -1034,9 +1034,9 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs): ): fullatom = name if slot is not None: - targets = ["{}:{}".format(fullatom, slot)] + targets = [f"{fullatom}:{slot}"] if fromrepo is not None: - targets = ["{}::{}".format(fullatom, fromrepo)] + targets = [f"{fullatom}::{fromrepo}"] targets = [fullatom] else: targets = [x for x in pkg_params if x in old] @@ -1165,9 +1165,9 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None): ): fullatom = name if slot is not None: - targets = ["{}:{}".format(fullatom, slot)] + targets = [f"{fullatom}:{slot}"] if fromrepo is not None: - targets = ["{}::{}".format(fullatom, fromrepo)] + targets = [f"{fullatom}::{fromrepo}"] targets = [fullatom] else: targets = [x for x in pkg_params if x in old] @@ -1245,9 +1245,9 @@ def check_extra_requirements(pkgname, pkgver): # If no prefix characters were supplied and verstr contains a version, use '=' if verstr[0] != ":" and verstr[0] != "[": prefix = prefix or "=" - atom = "{}{}-{}".format(prefix, pkgname, verstr) + atom = f"{prefix}{pkgname}-{verstr}" else: - atom = "{}{}".format(pkgname, verstr) + atom = f"{pkgname}{verstr}" else: return True diff --git a/salt/modules/elasticsearch.py b/salt/modules/elasticsearch.py index 4db9b370abc..e8a468103fe 100644 --- a/salt/modules/elasticsearch.py +++ b/salt/modules/elasticsearch.py @@ -48,7 +48,6 @@ Module to provide Elasticsearch compatibility to Salt Some functionality might be limited by elasticsearch-py and Elasticsearch server versions. """ - import logging from salt.exceptions import CommandExecutionError, SaltInvocationError diff --git a/salt/modules/eselect.py b/salt/modules/eselect.py index 9a0c1cf6756..33a1e96709b 100644 --- a/salt/modules/eselect.py +++ b/salt/modules/eselect.py @@ -2,7 +2,6 @@ Support for eselect, Gentoo's configuration and management tool. """ - import logging import salt.utils.path @@ -195,7 +194,7 @@ def set_target(module, target, module_parameter=None, action_parameter=None): salt '*' eselect.set_target kernel linux-3.17.5-gentoo """ if action_parameter: - action_parameter = "{} {}".format(action_parameter, target) + action_parameter = f"{action_parameter} {target}" else: action_parameter = target diff --git a/salt/modules/esxi.py b/salt/modules/esxi.py index e9686ea9411..dbbf1adda27 100644 --- a/salt/modules/esxi.py +++ b/salt/modules/esxi.py @@ -34,7 +34,6 @@ type manor. """ - import logging from functools import wraps diff --git a/salt/modules/esxvm.py b/salt/modules/esxvm.py index 397f6d24478..d8065ae9bf2 100644 --- a/salt/modules/esxvm.py +++ b/salt/modules/esxvm.py @@ -13,7 +13,6 @@ Module used to access the esx proxy connection methods """ - import logging from functools import wraps diff --git a/salt/modules/ethtool.py b/salt/modules/ethtool.py index 16f9c4a7b53..0fb0a16b98a 100644 --- a/salt/modules/ethtool.py +++ b/salt/modules/ethtool.py @@ -312,8 +312,8 @@ def _ethtool_command(devname, *args, **kwargs): if not ethtool: raise CommandExecutionError("Command 'ethtool' cannot be found") switches = " ".join(arg for arg in args) - params = " ".join("{} {}".format(key, val) for key, val in kwargs.items()) - cmd = "{} {} {} {}".format(ethtool, switches, devname, params).strip() + params = " ".join(f"{key} {val}" for key, val in kwargs.items()) + cmd = f"{ethtool} {switches} {devname} {params}".strip() ret = __salt__["cmd.run"](cmd, ignore_retcode=True).splitlines() if ret and ret[0].startswith("Cannot"): raise CommandExecutionError(ret[0]) @@ -336,7 +336,7 @@ def _validate_params(valid_params, kwargs): validated[key] = val if not validated: raise CommandExecutionError( - "None of the valid parameters were provided: {}".format(valid_params) + f"None of the valid parameters were provided: {valid_params}" ) return validated diff --git a/salt/modules/event.py b/salt/modules/event.py index bf6d4bde0d7..7bb64a8119a 100644 --- a/salt/modules/event.py +++ b/salt/modules/event.py @@ -3,7 +3,6 @@ Use the :ref:`Salt Event System ` to fire events from the master to the minion and vice-versa. """ - import logging import os import sys diff --git a/salt/modules/extfs.py b/salt/modules/extfs.py index 2737cbe2b72..fc5585295c1 100644 --- a/salt/modules/extfs.py +++ b/salt/modules/extfs.py @@ -2,7 +2,6 @@ Module for managing ext2/3/4 file systems """ - import logging import salt.utils.platform diff --git a/salt/modules/file.py b/salt/modules/file.py index 3a9f0669cbe..e826c435d45 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -887,9 +887,11 @@ def get_source_sum( if source_hash_sig: _check_sig( hash_fn, - signature=source_hash_sig - if isinstance(source_hash_sig, str) - else None, + signature=( + source_hash_sig + if isinstance(source_hash_sig, str) + else None + ), signed_by_any=signed_by_any, signed_by_all=signed_by_all, keyring=keyring, @@ -5060,9 +5062,11 @@ def extract_hash( if basename_searches: log.debug( "file.extract_hash: %s %s hash for file matching%s: %s", - "If no source_hash_name match found, will extract" - if source_hash_name - else "Extracting", + ( + "If no source_hash_name match found, will extract" + if source_hash_name + else "Extracting" + ), "any supported" if not hash_type else hash_type, "" if len(basename_searches) == 1 else " either of the following", ", ".join(basename_searches), diff --git a/salt/modules/firewalld.py b/salt/modules/firewalld.py index 135713d8516..878969d6d8b 100644 --- a/salt/modules/firewalld.py +++ b/salt/modules/firewalld.py @@ -4,7 +4,6 @@ Support for firewalld. .. versionadded:: 2015.2.0 """ - import logging import re @@ -40,7 +39,7 @@ def __firewall_cmd(cmd): msg = out["stdout"] else: msg = out["stderr"] - raise CommandExecutionError("firewall-cmd failed: {}".format(msg)) + raise CommandExecutionError(f"firewall-cmd failed: {msg}") return out["stdout"] @@ -49,7 +48,7 @@ def __mgmt(name, _type, action): Perform zone management """ # It's permanent because the 4 concerned functions need the permanent option, it's wrong without - cmd = "--{}-{}={} --permanent".format(action, _type, name) + cmd = f"--{action}-{_type}={name} --permanent" return __firewall_cmd(cmd) @@ -259,7 +258,7 @@ def set_default_zone(zone): salt '*' firewalld.set_default_zone damian """ - return __firewall_cmd("--set-default-zone={}".format(zone)) + return __firewall_cmd(f"--set-default-zone={zone}") def new_service(name, restart=True): @@ -333,7 +332,7 @@ def list_all(zone=None, permanent=True): salt '*' firewalld.list_all my_zone """ if zone: - cmd = "--zone={} --list-all".format(zone) + cmd = f"--zone={zone} --list-all" else: cmd = "--list-all" @@ -361,7 +360,7 @@ def list_services(zone=None, permanent=True): salt '*' firewalld.list_services my_zone """ if zone: - cmd = "--zone={} --list-services".format(zone) + cmd = f"--zone={zone} --list-services" else: cmd = "--list-services" @@ -388,9 +387,9 @@ def add_service(service, zone=None, permanent=True): salt '*' firewalld.add_service ssh my_zone """ if zone: - cmd = "--zone={} --add-service={}".format(zone, service) + cmd = f"--zone={zone} --add-service={service}" else: - cmd = "--add-service={}".format(service) + cmd = f"--add-service={service}" if permanent: cmd += " --permanent" @@ -416,9 +415,9 @@ def remove_service(service, zone=None, permanent=True): salt '*' firewalld.remove_service ssh dmz """ if zone: - cmd = "--zone={} --remove-service={}".format(zone, service) + cmd = f"--zone={zone} --remove-service={service}" else: - cmd = "--remove-service={}".format(service) + cmd = f"--remove-service={service}" if permanent: cmd += " --permanent" @@ -441,7 +440,7 @@ def add_service_port(service, port): if service not in get_services(permanent=True): raise CommandExecutionError("The service does not exist.") - cmd = "--permanent --service={} --add-port={}".format(service, port) + cmd = f"--permanent --service={service} --add-port={port}" return __firewall_cmd(cmd) @@ -460,7 +459,7 @@ def remove_service_port(service, port): if service not in get_services(permanent=True): raise CommandExecutionError("The service does not exist.") - cmd = "--permanent --service={} --remove-port={}".format(service, port) + cmd = f"--permanent --service={service} --remove-port={port}" return __firewall_cmd(cmd) @@ -476,7 +475,7 @@ def get_service_ports(service): salt '*' firewalld.get_service_ports zone """ - cmd = "--permanent --service={} --get-ports".format(service) + cmd = f"--permanent --service={service} --get-ports" return __firewall_cmd(cmd).split() @@ -492,7 +491,7 @@ def add_service_protocol(service, protocol): salt '*' firewalld.add_service_protocol zone ssh """ - cmd = "--permanent --service={} --add-protocol={}".format(service, protocol) + cmd = f"--permanent --service={service} --add-protocol={protocol}" return __firewall_cmd(cmd) @@ -508,7 +507,7 @@ def remove_service_protocol(service, protocol): salt '*' firewalld.remove_service_protocol zone ssh """ - cmd = "--permanent --service={} --remove-protocol={}".format(service, protocol) + cmd = f"--permanent --service={service} --remove-protocol={protocol}" return __firewall_cmd(cmd) @@ -524,7 +523,7 @@ def get_service_protocols(service): salt '*' firewalld.get_service_protocols zone """ - cmd = "--permanent --service={} --get-protocols".format(service) + cmd = f"--permanent --service={service} --get-protocols" return __firewall_cmd(cmd).split() @@ -567,7 +566,7 @@ def add_masquerade(zone=None, permanent=True): salt '*' firewalld.add_masquerade dmz """ if zone: - cmd = "--zone={} --add-masquerade".format(zone) + cmd = f"--zone={zone} --add-masquerade" else: cmd = "--add-masquerade" @@ -597,7 +596,7 @@ def remove_masquerade(zone=None, permanent=True): salt '*' firewalld.remove_masquerade dmz """ if zone: - cmd = "--zone={} --remove-masquerade".format(zone) + cmd = f"--zone={zone} --remove-masquerade" else: cmd = "--remove-masquerade" @@ -626,7 +625,7 @@ def add_port(zone, port, permanent=True, force_masquerade=False): if force_masquerade and not get_masquerade(zone): add_masquerade(zone) - cmd = "--zone={} --add-port={}".format(zone, port) + cmd = f"--zone={zone} --add-port={port}" if permanent: cmd += " --permanent" @@ -646,7 +645,7 @@ def remove_port(zone, port, permanent=True): salt '*' firewalld.remove_port internal 443/tcp """ - cmd = "--zone={} --remove-port={}".format(zone, port) + cmd = f"--zone={zone} --remove-port={port}" if permanent: cmd += " --permanent" @@ -666,7 +665,7 @@ def list_ports(zone, permanent=True): salt '*' firewalld.list_ports """ - cmd = "--zone={} --list-ports".format(zone) + cmd = f"--zone={zone} --list-ports" if permanent: cmd += " --permanent" @@ -741,7 +740,7 @@ def list_port_fwd(zone, permanent=True): """ ret = [] - cmd = "--zone={} --list-forward-ports".format(zone) + cmd = f"--zone={zone} --list-forward-ports" if permanent: cmd += " --permanent" @@ -781,7 +780,7 @@ def block_icmp(zone, icmp, permanent=True): log.info("ICMP block already exists") return "success" - cmd = "--zone={} --add-icmp-block={}".format(zone, icmp) + cmd = f"--zone={zone} --add-icmp-block={icmp}" if permanent: cmd += " --permanent" @@ -809,7 +808,7 @@ def allow_icmp(zone, icmp, permanent=True): log.info("ICMP Type is already permitted") return "success" - cmd = "--zone={} --remove-icmp-block={}".format(zone, icmp) + cmd = f"--zone={zone} --remove-icmp-block={icmp}" if permanent: cmd += " --permanent" @@ -829,7 +828,7 @@ def list_icmp_block(zone, permanent=True): salt '*' firewlld.list_icmp_block zone """ - cmd = "--zone={} --list-icmp-blocks".format(zone) + cmd = f"--zone={zone} --list-icmp-blocks" if permanent: cmd += " --permanent" @@ -864,7 +863,7 @@ def get_interfaces(zone, permanent=True): salt '*' firewalld.get_interfaces zone """ - cmd = "--zone={} --list-interfaces".format(zone) + cmd = f"--zone={zone} --list-interfaces" if permanent: cmd += " --permanent" @@ -887,7 +886,7 @@ def add_interface(zone, interface, permanent=True): if interface in get_interfaces(zone, permanent): log.info("Interface is already bound to zone.") - cmd = "--zone={} --add-interface={}".format(zone, interface) + cmd = f"--zone={zone} --add-interface={interface}" if permanent: cmd += " --permanent" @@ -910,7 +909,7 @@ def remove_interface(zone, interface, permanent=True): if interface not in get_interfaces(zone, permanent): log.info("Interface is not bound to zone.") - cmd = "--zone={} --remove-interface={}".format(zone, interface) + cmd = f"--zone={zone} --remove-interface={interface}" if permanent: cmd += " --permanent" @@ -930,7 +929,7 @@ def get_sources(zone, permanent=True): salt '*' firewalld.get_sources zone """ - cmd = "--zone={} --list-sources".format(zone) + cmd = f"--zone={zone} --list-sources" if permanent: cmd += " --permanent" @@ -953,7 +952,7 @@ def add_source(zone, source, permanent=True): if source in get_sources(zone, permanent): log.info("Source is already bound to zone.") - cmd = "--zone={} --add-source={}".format(zone, source) + cmd = f"--zone={zone} --add-source={source}" if permanent: cmd += " --permanent" @@ -976,7 +975,7 @@ def remove_source(zone, source, permanent=True): if source not in get_sources(zone, permanent): log.info("Source is not bound to zone.") - cmd = "--zone={} --remove-source={}".format(zone, source) + cmd = f"--zone={zone} --remove-source={source}" if permanent: cmd += " --permanent" @@ -996,7 +995,7 @@ def get_rich_rules(zone, permanent=True): salt '*' firewalld.get_rich_rules zone """ - cmd = "--zone={} --list-rich-rules".format(zone) + cmd = f"--zone={zone} --list-rich-rules" if permanent: cmd += " --permanent" @@ -1016,7 +1015,7 @@ def add_rich_rule(zone, rule, permanent=True): salt '*' firewalld.add_rich_rule zone 'rule' """ - cmd = "--zone={} --add-rich-rule='{}'".format(zone, rule) + cmd = f"--zone={zone} --add-rich-rule='{rule}'" if permanent: cmd += " --permanent" @@ -1036,7 +1035,7 @@ def remove_rich_rule(zone, rule, permanent=True): salt '*' firewalld.remove_rich_rule zone 'rule' """ - cmd = "--zone={} --remove-rich-rule='{}'".format(zone, rule) + cmd = f"--zone={zone} --remove-rich-rule='{rule}'" if permanent: cmd += " --permanent" diff --git a/salt/modules/freebsd_sysctl.py b/salt/modules/freebsd_sysctl.py index 3d6dd930ec5..ad2a6ba3eaf 100644 --- a/salt/modules/freebsd_sysctl.py +++ b/salt/modules/freebsd_sysctl.py @@ -2,7 +2,6 @@ Module for viewing and modifying sysctl parameters """ - import logging import os @@ -31,9 +30,9 @@ def __virtual__(): def _formatfor(name, value, config, tail=""): if config == "/boot/loader.conf": - return '{}="{}"{}'.format(name, value, tail) + return f'{name}="{value}"{tail}' else: - return "{}={}{}".format(name, value, tail) + return f"{name}={value}{tail}" def show(config_file=False): @@ -88,13 +87,13 @@ def show(config_file=False): out = __salt__["cmd.run"](cmd, output_loglevel="trace") value = None for line in out.splitlines(): - if any([line.startswith("{}.".format(root)) for root in roots]): + if any([line.startswith(f"{root}.") for root in roots]): if value is not None: ret[key] = "\n".join(value) (key, firstvalue) = line.split("=", 1) value = [firstvalue] elif value is not None: - value.append("{}".format(line)) + value.append(f"{line}") if value is not None: ret[key] = "\n".join(value) return ret @@ -110,7 +109,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd, python_shell=False) return out @@ -126,7 +125,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.icmp.icmplim 50 """ ret = {} - cmd = 'sysctl {}="{}"'.format(name, value) + cmd = f'sysctl {name}="{value}"' data = __salt__["cmd.run_all"](cmd, python_shell=False) if data["retcode"] != 0: @@ -154,7 +153,7 @@ def persist(name, value, config="/etc/sysctl.conf"): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line).rstrip("\n") - if not line.startswith("{}=".format(name)): + if not line.startswith(f"{name}="): nlines.append(line) continue else: @@ -177,7 +176,7 @@ def persist(name, value, config="/etc/sysctl.conf"): nlines.append(new_line) edited = True if not edited: - nlines.append("{}\n".format(_formatfor(name, value, config))) + nlines.append(f"{_formatfor(name, value, config)}\n") with salt.utils.files.fopen(config, "w+") as ofile: nlines = [salt.utils.stringutils.to_str(_l) + "\n" for _l in nlines] ofile.writelines(nlines) diff --git a/salt/modules/freebsd_update.py b/salt/modules/freebsd_update.py index 26a6acd932f..71904d7230c 100644 --- a/salt/modules/freebsd_update.py +++ b/salt/modules/freebsd_update.py @@ -8,7 +8,6 @@ Support for freebsd-update utility on FreeBSD. :platform: FreeBSD """ - import logging import salt.utils.path @@ -195,7 +194,7 @@ def update(**kwargs): return ret if "stdout" in err_: stdout[mode] = err_["stdout"] - return "\n".join(["{}: {}".format(k, v) for (k, v) in stdout.items()]) + return "\n".join([f"{k}: {v}" for (k, v) in stdout.items()]) def ids(**kwargs): diff --git a/salt/modules/freebsdjail.py b/salt/modules/freebsdjail.py index fc3c3ce04f3..46c10f0be15 100644 --- a/salt/modules/freebsdjail.py +++ b/salt/modules/freebsdjail.py @@ -2,7 +2,6 @@ The jail module for FreeBSD """ - import os import re import subprocess @@ -38,7 +37,7 @@ def start(jail=""): salt '*' jail.start [] """ - cmd = "service jail onestart {}".format(jail) + cmd = f"service jail onestart {jail}" return not __salt__["cmd.retcode"](cmd) @@ -52,7 +51,7 @@ def stop(jail=""): salt '*' jail.stop [] """ - cmd = "service jail onestop {}".format(jail) + cmd = f"service jail onestop {jail}" return not __salt__["cmd.retcode"](cmd) @@ -66,7 +65,7 @@ def restart(jail=""): salt '*' jail.restart [] """ - cmd = "service jail onerestart {}".format(jail) + cmd = f"service jail onerestart {jail}" return not __salt__["cmd.retcode"](cmd) @@ -145,7 +144,7 @@ def show_config(jail): line = salt.utils.stringutils.to_unicode(line) if not line.strip(): continue - if not line.startswith("jail_{}_".format(jail)): + if not line.startswith(f"jail_{jail}_"): continue key, value = line.split("=") ret[key.split("_", 2)[2]] = value.split('"')[1] diff --git a/salt/modules/freebsdkmod.py b/salt/modules/freebsdkmod.py index 27793f758c6..db13306ceb5 100644 --- a/salt/modules/freebsdkmod.py +++ b/salt/modules/freebsdkmod.py @@ -201,7 +201,7 @@ def load(mod, persist=False): salt '*' kmod.load bhyve """ pre_mods = lsmod() - response = __salt__["cmd.run_all"]("kldload {}".format(mod), python_shell=False) + response = __salt__["cmd.run_all"](f"kldload {mod}", python_shell=False) if response["retcode"] == 0: post_mods = lsmod() mods = _new_mods(pre_mods, post_mods) @@ -217,7 +217,7 @@ def load(mod, persist=False): # It's compiled into the kernel return [None] else: - return "Module {} not found".format(mod) + return f"Module {mod} not found" def is_loaded(mod): @@ -254,7 +254,7 @@ def remove(mod, persist=False, comment=True): salt '*' kmod.remove vmm """ pre_mods = lsmod() - res = __salt__["cmd.run_all"]("kldunload {}".format(mod), python_shell=False) + res = __salt__["cmd.run_all"](f"kldunload {mod}", python_shell=False) if res["retcode"] == 0: post_mods = lsmod() mods = _rm_mods(pre_mods, post_mods) diff --git a/salt/modules/freebsdpkg.py b/salt/modules/freebsdpkg.py index 36de306b687..77ba7444cfa 100644 --- a/salt/modules/freebsdpkg.py +++ b/salt/modules/freebsdpkg.py @@ -175,20 +175,20 @@ def _match(names): cver = pkgs.get(name) if cver is not None: if len(cver) == 1: - matches.append("{}-{}".format(name, cver[0])) + matches.append(f"{name}-{cver[0]}") else: ambiguous.append(name) errors.append( "Ambiguous package '{}'. Full name/version required. " "Possible matches: {}".format( - name, ", ".join(["{}-{}".format(name, x) for x in cver]) + name, ", ".join([f"{name}-{x}" for x in cver]) ) ) # Find packages that did not match anything not_matched = set(names) - set(matches) - set(full_matches) - set(ambiguous) for name in not_matched: - errors.append("Package '{}' not found".format(name)) + errors.append(f"Package '{name}' not found") return matches + full_matches, errors diff --git a/salt/modules/freebsdports.py b/salt/modules/freebsdports.py index 3ab53e24f80..254212f0e16 100644 --- a/salt/modules/freebsdports.py +++ b/salt/modules/freebsdports.py @@ -59,13 +59,11 @@ def _check_portname(name): ports tree. """ if not isinstance(name, str) or "/" not in name: - raise SaltInvocationError( - "Invalid port name '{}' (category required)".format(name) - ) + raise SaltInvocationError(f"Invalid port name '{name}' (category required)") path = os.path.join("/usr/ports", name) if not os.path.isdir(path): - raise SaltInvocationError("Path '{}' does not exist".format(path)) + raise SaltInvocationError(f"Path '{path}' does not exist") return path @@ -109,7 +107,7 @@ def _write_options(name, configuration): try: os.makedirs(dirname) except OSError as exc: - raise CommandExecutionError("Unable to make {}: {}".format(dirname, exc)) + raise CommandExecutionError(f"Unable to make {dirname}: {exc}") with salt.utils.files.fopen(os.path.join(dirname, "options"), "w") as fp_: sorted_options = list(conf_ptr) @@ -270,7 +268,7 @@ def showconfig(name, default=False, dict_return=False): error = result if error: - msg = "Error running 'make showconfig' for {}: {}".format(name, error) + msg = f"Error running 'make showconfig' for {name}: {error}" log.error(msg) raise SaltInvocationError(msg) @@ -327,9 +325,7 @@ def config(name, reset=False, **kwargs): configuration = showconfig(name, dict_return=True) if not configuration: - raise CommandExecutionError( - "Unable to get port configuration for '{}'".format(name) - ) + raise CommandExecutionError(f"Unable to get port configuration for '{name}'") # Get top-level key for later reference pkg = next(iter(configuration)) @@ -345,7 +341,7 @@ def config(name, reset=False, **kwargs): ) ) - bad_vals = ["{}={}".format(x, y) for x, y in opts.items() if y not in ("on", "off")] + bad_vals = [f"{x}={y}" for x, y in opts.items() if y not in ("on", "off")] if bad_vals: raise SaltInvocationError( "The following key/value pairs are invalid: {}".format(", ".join(bad_vals)) @@ -396,8 +392,8 @@ def update(extract=False): except AttributeError: new_port_count = 0 - ret.append("Applied {} new patches".format(patch_count)) - ret.append("Fetched {} new ports or files".format(new_port_count)) + ret.append(f"Applied {patch_count} new patches") + ret.append(f"Fetched {new_port_count} new ports or files") if extract: result = __salt__["cmd.run_all"](_portsnap() + ["extract"], python_shell=False) diff --git a/salt/modules/freebsdservice.py b/salt/modules/freebsdservice.py index f053db695fe..a5fdc2cbad6 100644 --- a/salt/modules/freebsdservice.py +++ b/salt/modules/freebsdservice.py @@ -56,7 +56,7 @@ def _cmd(jail=None): jexec = salt.utils.path.which("jexec") if not jexec: raise CommandNotFoundError("'jexec' command not found") - service = "{} {} {}".format(jexec, jail, service) + service = f"{jexec} {jail} {service}" return service @@ -72,7 +72,7 @@ def _get_jail_path(jail): jls = salt.utils.path.which("jls") if not jls: raise CommandNotFoundError("'jls' command not found") - jails = __salt__["cmd.run_stdout"]("{} -n jid name path".format(jls)) + jails = __salt__["cmd.run_stdout"](f"{jls} -n jid name path") for j in jails.splitlines(): jid, jname, path = (x.split("=")[1].strip() for x in j.split()) if jid == jail or jname == jail: @@ -89,10 +89,10 @@ def _get_rcscript(name, jail=None): Support for jail (representing jid or jail name) keyword argument in kwargs """ - cmd = "{} -r".format(_cmd(jail)) + cmd = f"{_cmd(jail)} -r" prf = _get_jail_path(jail) if jail else "" for line in __salt__["cmd.run_stdout"](cmd, python_shell=False).splitlines(): - if line.endswith("{}{}".format(os.path.sep, name)): + if line.endswith(f"{os.path.sep}{name}"): return os.path.join(prf, line.lstrip(os.path.sep)) return None @@ -109,7 +109,7 @@ def _get_rcvar(name, jail=None): log.error("Service %s not found", name) return False - cmd = "{} {} rcvar".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} rcvar" for line in __salt__["cmd.run_stdout"](cmd, python_shell=False).splitlines(): if '_enable="' not in line: @@ -137,14 +137,14 @@ def get_enabled(jail=None): ret = [] service = _cmd(jail) prf = _get_jail_path(jail) if jail else "" - for svc in __salt__["cmd.run"]("{} -e".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} -e").splitlines(): ret.append(os.path.basename(svc)) # This is workaround for bin/173454 bug for svc in get_all(jail): if svc in ret: continue - if not os.path.exists("{}/etc/rc.conf.d/{}".format(prf, svc)): + if not os.path.exists(f"{prf}/etc/rc.conf.d/{svc}"): continue if enabled(svc, jail=jail): ret.append(svc) @@ -199,13 +199,11 @@ def _switch(name, on, **kwargs): # pylint: disable=C0103 # pylint: disable=C01 config = kwargs.get( "config", - __salt__["config.option"]( - "service.config", default="{}/etc/rc.conf".format(chroot) - ), + __salt__["config.option"]("service.config", default=f"{chroot}/etc/rc.conf"), ) if not config: - rcdir = "{}/etc/rc.conf.d".format(chroot) + rcdir = f"{chroot}/etc/rc.conf.d" if not os.path.exists(rcdir) or not os.path.isdir(rcdir): log.error("%s not exists", rcdir) return False @@ -223,17 +221,17 @@ def _switch(name, on, **kwargs): # pylint: disable=C0103 # pylint: disable=C01 with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - if not line.startswith("{}=".format(rcvar)): + if not line.startswith(f"{rcvar}="): nlines.append(line) continue rest = line[len(line.split()[0]) :] # keep comments etc - nlines.append('{}="{}"{}'.format(rcvar, val, rest)) + nlines.append(f'{rcvar}="{val}"{rest}') edited = True if not edited: # Ensure that the file ends in a \n if len(nlines) > 1 and nlines[-1][-1] != "\n": - nlines[-1] = "{}\n".format(nlines[-1]) - nlines.append('{}="{}"\n'.format(rcvar, val)) + nlines[-1] = f"{nlines[-1]}\n" + nlines.append(f'{rcvar}="{val}"\n') with salt.utils.files.fopen(config, "w") as ofile: nlines = [salt.utils.stringutils.to_str(_l) for _l in nlines] @@ -318,7 +316,7 @@ def enabled(name, **kwargs): log.error("Service %s not found", name) return False - cmd = "{} {} rcvar".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} rcvar" for line in __salt__["cmd.run_stdout"](cmd, python_shell=False).splitlines(): if '_enable="' not in line: @@ -395,7 +393,7 @@ def get_all(jail=None): """ ret = [] service = _cmd(jail) - for srv in __salt__["cmd.run"]("{} -l".format(service)).splitlines(): + for srv in __salt__["cmd.run"](f"{service} -l").splitlines(): if not srv.isupper(): ret.append(srv) return sorted(ret) @@ -415,7 +413,7 @@ def start(name, jail=None): salt '*' service.start """ - cmd = "{} {} onestart".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onestart" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -433,7 +431,7 @@ def stop(name, jail=None): salt '*' service.stop """ - cmd = "{} {} onestop".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onestop" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -451,7 +449,7 @@ def restart(name, jail=None): salt '*' service.restart """ - cmd = "{} {} onerestart".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onerestart" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -469,7 +467,7 @@ def reload_(name, jail=None): salt '*' service.reload """ - cmd = "{} {} onereload".format(_cmd(jail), name) + cmd = f"{_cmd(jail)} {name} onereload" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -508,7 +506,7 @@ def status(name, sig=None, jail=None): services = [name] results = {} for service in services: - cmd = "{} {} onestatus".format(_cmd(jail), service) + cmd = f"{_cmd(jail)} {service} onestatus" results[service] = not __salt__["cmd.retcode"]( cmd, python_shell=False, ignore_retcode=True ) diff --git a/salt/modules/freezer.py b/salt/modules/freezer.py index 296a26bf5bb..329cff98c3e 100644 --- a/salt/modules/freezer.py +++ b/salt/modules/freezer.py @@ -49,8 +49,8 @@ def _paths(name=None): name = "freezer" if not name else name states_path = _states_path() return ( - os.path.join(states_path, "{}-pkgs.yml".format(name)), - os.path.join(states_path, "{}-reps.yml".format(name)), + os.path.join(states_path, f"{name}-pkgs.yml"), + os.path.join(states_path, f"{name}-reps.yml"), ) diff --git a/salt/modules/genesis.py b/salt/modules/genesis.py index 5c2be12388a..4b9dca2351a 100644 --- a/salt/modules/genesis.py +++ b/salt/modules/genesis.py @@ -153,18 +153,18 @@ def bootstrap( if not img_size: raise SaltInvocationError("An img_size must be specified for a sparse file") if not mount_dir: - mount_dir = "/opt/salt-genesis.{}".format(uuid.uuid4()) + mount_dir = f"/opt/salt-genesis.{uuid.uuid4()}" __salt__["file.mkdir"](mount_dir, "root", "root", "755") __salt__["cmd.run"](("fallocate", "-l", img_size, root), python_shell=False) _mkpart(root, fs_format, fs_opts, mount_dir) loop1 = __salt__["cmd.run"]("losetup -f") log.debug("First loop device is %s", loop1) - __salt__["cmd.run"]("losetup {} {}".format(loop1, root)) + __salt__["cmd.run"](f"losetup {loop1} {root}") loop2 = __salt__["cmd.run"]("losetup -f") log.debug("Second loop device is %s", loop2) start = str(2048 * 2048) - __salt__["cmd.run"]("losetup -o {} {} {}".format(start, loop2, loop1)) + __salt__["cmd.run"](f"losetup -o {start} {loop2} {loop1}") __salt__["mount.mount"](mount_dir, loop2) _populate_cache(platform, pkg_cache, mount_dir) @@ -206,13 +206,13 @@ def bootstrap( if img_format != "dir": blkinfo = __salt__["disk.blkid"](loop2) __salt__["file.replace"]( - "{}/boot/grub/grub.cfg".format(mount_dir), + f"{mount_dir}/boot/grub/grub.cfg", "ad4103fa-d940-47ca-8506-301d8071d467", # This seems to be the default blkinfo[loop2]["UUID"], ) __salt__["mount.umount"](root) - __salt__["cmd.run"]("losetup -d {}".format(loop2)) - __salt__["cmd.run"]("losetup -d {}".format(loop1)) + __salt__["cmd.run"](f"losetup -d {loop2}") + __salt__["cmd.run"](f"losetup -d {loop1}") __salt__["file.rmdir"](mount_dir) @@ -225,7 +225,7 @@ def _mkpart(root, fs_format, fs_opts, mount_dir): __salt__["partition.mklabel"](root, "msdos") loop1 = __salt__["cmd.run"]("losetup -f") log.debug("First loop device is %s", loop1) - __salt__["cmd.run"]("losetup {} {}".format(loop1, root)) + __salt__["cmd.run"](f"losetup {loop1} {root}") part_info = __salt__["partition.list"](loop1) start = str(2048 * 2048) + "B" end = part_info["info"]["size"] @@ -235,7 +235,7 @@ def _mkpart(root, fs_format, fs_opts, mount_dir): loop2 = __salt__["cmd.run"]("losetup -f") log.debug("Second loop device is %s", loop2) start = start.rstrip("B") - __salt__["cmd.run"]("losetup -o {} {} {}".format(start, loop2, loop1)) + __salt__["cmd.run"](f"losetup -o {start} {loop2} {loop1}") _mkfs(loop2, fs_format, fs_opts) __salt__["mount.mount"](mount_dir, loop2) __salt__["cmd.run"]( @@ -245,14 +245,14 @@ def _mkpart(root, fs_format, fs_opts, mount_dir): "--debug", "--no-floppy", "--modules=part_msdos linux", - "--boot-directory={}/boot".format(mount_dir), + f"--boot-directory={mount_dir}/boot", loop1, ), python_shell=False, ) __salt__["mount.umount"](mount_dir) - __salt__["cmd.run"]("losetup -d {}".format(loop2)) - __salt__["cmd.run"]("losetup -d {}".format(loop1)) + __salt__["cmd.run"](f"losetup -d {loop2}") + __salt__["cmd.run"](f"losetup -d {loop1}") return part_info @@ -284,7 +284,7 @@ def _populate_cache(platform, pkg_cache, mount_dir): return if platform == "pacman": - cache_dir = "{}/var/cache/pacman/pkg".format(mount_dir) + cache_dir = f"{mount_dir}/var/cache/pacman/pkg" __salt__["file.mkdir"](cache_dir, "root", "root", "755") __salt__["file.copy"](pkg_cache, cache_dir, recurse=True, remove_existing=True) @@ -361,14 +361,14 @@ def _bootstrap_yum( yum_args = [ "yum", "install", - "--installroot={}".format(shlex.quote(root)), + f"--installroot={shlex.quote(root)}", "-y", ] + pkgs __salt__["cmd.run"](yum_args, python_shell=False) if "epel-release" not in exclude_pkgs: __salt__["cmd.run"]( - ("rpm", "--root={}".format(shlex.quote(root)), "-Uvh", epel_url), + ("rpm", f"--root={shlex.quote(root)}", "-Uvh", epel_url), python_shell=False, ) @@ -462,9 +462,7 @@ def _bootstrap_deb( ), env=env, ) - __salt__["cmd.run"]( - "chroot {root} dpkg --configure -a".format(root=shlex.quote(root)), env=env - ) + __salt__["cmd.run"](f"chroot {shlex.quote(root)} dpkg --configure -a", env=env) def _bootstrap_pacman( @@ -519,25 +517,23 @@ def _bootstrap_pacman( pkgs.remove(pkg) if img_format != "dir": - __salt__["mount.mount"]("{}/proc".format(root), "/proc", fstype="", opts="bind") - __salt__["mount.mount"]("{}/dev".format(root), "/dev", fstype="", opts="bind") + __salt__["mount.mount"](f"{root}/proc", "/proc", fstype="", opts="bind") + __salt__["mount.mount"](f"{root}/dev", "/dev", fstype="", opts="bind") - __salt__["file.mkdir"]( - "{}/var/lib/pacman/local".format(root), "root", "root", "755" - ) + __salt__["file.mkdir"](f"{root}/var/lib/pacman/local", "root", "root", "755") pac_files = [rf for rf in os.listdir("/etc") if rf.startswith("pacman.")] for pac_file in pac_files: - __salt__["cmd.run"]("cp -r /etc/{} {}/etc".format(pac_file, shlex.quote(root))) + __salt__["cmd.run"](f"cp -r /etc/{pac_file} {shlex.quote(root)}/etc") __salt__["file.copy"]( - "/var/lib/pacman/sync", "{}/var/lib/pacman/sync".format(root), recurse=True + "/var/lib/pacman/sync", f"{root}/var/lib/pacman/sync", recurse=True ) pacman_args = ["pacman", "--noconfirm", "-r", shlex.quote(root), "-S"] + pkgs __salt__["cmd.run"](pacman_args, python_shell=False) if img_format != "dir": - __salt__["mount.umount"]("{}/proc".format(root)) - __salt__["mount.umount"]("{}/dev".format(root)) + __salt__["mount.umount"](f"{root}/proc") + __salt__["mount.umount"](f"{root}/dev") def _make_nodes(root): @@ -547,24 +543,24 @@ def _make_nodes(root): https://wiki.archlinux.org/index.php/Linux_Containers """ dirs = ( - ("{}/etc".format(root), "root", "root", "755"), - ("{}/dev".format(root), "root", "root", "755"), - ("{}/proc".format(root), "root", "root", "755"), - ("{}/dev/pts".format(root), "root", "root", "755"), - ("{}/dev/shm".format(root), "root", "root", "1755"), + (f"{root}/etc", "root", "root", "755"), + (f"{root}/dev", "root", "root", "755"), + (f"{root}/proc", "root", "root", "755"), + (f"{root}/dev/pts", "root", "root", "755"), + (f"{root}/dev/shm", "root", "root", "1755"), ) nodes = ( - ("{}/dev/null".format(root), "c", 1, 3, "root", "root", "666"), - ("{}/dev/zero".format(root), "c", 1, 5, "root", "root", "666"), - ("{}/dev/random".format(root), "c", 1, 8, "root", "root", "666"), - ("{}/dev/urandom".format(root), "c", 1, 9, "root", "root", "666"), - ("{}/dev/tty".format(root), "c", 5, 0, "root", "root", "666"), - ("{}/dev/tty0".format(root), "c", 4, 0, "root", "root", "666"), - ("{}/dev/console".format(root), "c", 5, 1, "root", "root", "600"), - ("{}/dev/full".format(root), "c", 1, 7, "root", "root", "666"), - ("{}/dev/initctl".format(root), "p", 0, 0, "root", "root", "600"), - ("{}/dev/ptmx".format(root), "c", 5, 2, "root", "root", "666"), + (f"{root}/dev/null", "c", 1, 3, "root", "root", "666"), + (f"{root}/dev/zero", "c", 1, 5, "root", "root", "666"), + (f"{root}/dev/random", "c", 1, 8, "root", "root", "666"), + (f"{root}/dev/urandom", "c", 1, 9, "root", "root", "666"), + (f"{root}/dev/tty", "c", 5, 0, "root", "root", "666"), + (f"{root}/dev/tty0", "c", 4, 0, "root", "root", "666"), + (f"{root}/dev/console", "c", 5, 1, "root", "root", "600"), + (f"{root}/dev/full", "c", 1, 7, "root", "root", "666"), + (f"{root}/dev/initctl", "p", 0, 0, "root", "root", "600"), + (f"{root}/dev/ptmx", "c", 5, 2, "root", "root", "666"), ) for path in dirs: @@ -636,9 +632,9 @@ def _tar(name, root, path=None, compress="bzip2"): compression, ext = _compress(compress) - tarfile = "{}/{}.tar.{}".format(path, name, ext) + tarfile = f"{path}/{name}.tar.{ext}" out = __salt__["archive.tar"]( - options="{}pcf".format(compression), + options=f"{compression}pcf", tarfile=tarfile, sources=".", dest=root, @@ -663,9 +659,9 @@ def _untar(name, dest=None, path=None, compress="bz2"): compression, ext = _compress(compress) - tarfile = "{}/{}.tar.{}".format(path, name, ext) + tarfile = f"{path}/{name}.tar.{ext}" out = __salt__["archive.tar"]( - options="{}xf".format(compression), + options=f"{compression}xf", tarfile=tarfile, dest=dest, ) diff --git a/salt/modules/gentoo_service.py b/salt/modules/gentoo_service.py index 5a35ba0fcbd..ede473e6779 100644 --- a/salt/modules/gentoo_service.py +++ b/salt/modules/gentoo_service.py @@ -9,7 +9,6 @@ to the correct service manager `. """ - import fnmatch import logging import re diff --git a/salt/modules/gentoolkitmod.py b/salt/modules/gentoolkitmod.py index 19e7b45f6fa..da8f803a786 100644 --- a/salt/modules/gentoolkitmod.py +++ b/salt/modules/gentoolkitmod.py @@ -50,7 +50,7 @@ def revdep_rebuild(lib=None): """ cmd = "revdep-rebuild -i --quiet --no-progress" if lib is not None: - cmd += " --library={}".format(lib) + cmd += f" --library={lib}" return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 @@ -62,7 +62,7 @@ def _pretty_size(size): while units and size >= 1000: size = size / 1024.0 units.pop() - return "{}{}".format(round(size, 1), units[-1]) + return f"{round(size, 1)}{units[-1]}" def _parse_exclude(exclude_file): @@ -137,7 +137,7 @@ def eclean_dist( try: exclude = _parse_exclude(exclude_file) except excludemod.ParseExcludeFileException as e: - ret = {e: "Invalid exclusion file: {}".format(exclude_file)} + ret = {e: f"Invalid exclusion file: {exclude_file}"} return ret if time_limit != 0: @@ -221,7 +221,7 @@ def eclean_pkg( try: exclude = _parse_exclude(exclude_file) except excludemod.ParseExcludeFileException as e: - ret = {e: "Invalid exclusion file: {}".format(exclude_file)} + ret = {e: f"Invalid exclusion file: {exclude_file}"} return ret if time_limit != 0: diff --git a/salt/modules/github.py b/salt/modules/github.py index bc45f9cae96..54b5b1d167a 100644 --- a/salt/modules/github.py +++ b/salt/modules/github.py @@ -29,7 +29,6 @@ For example: allow_repo_privacy_changes: False """ - import logging import salt.utils.http @@ -119,7 +118,7 @@ def _get_members(organization, params=None): def _get_repos(profile, params=None, ignore_cache=False): # Use cache when no params are given org_name = _get_config_value(profile, "org_name") - key = "github.{}:repos".format(org_name) + key = f"github.{org_name}:repos" if key not in __context__ or ignore_cache or params is not None: org_name = _get_config_value(profile, "org_name") @@ -143,7 +142,7 @@ def _get_repos(profile, params=None, ignore_cache=False): next_result.append(repo) # Cache a copy of each repo for single lookups - repo_key = "github.{}:{}:repo_info".format(org_name, repo.name.lower()) + repo_key = f"github.{org_name}:{repo.name.lower()}:repo_info" __context__[repo_key] = _repo_to_dict(repo) __context__[key] = next_result @@ -171,7 +170,7 @@ def list_users(profile="github", ignore_cache=False): salt myminion github.list_users profile='my-github-profile' """ org_name = _get_config_value(profile, "org_name") - key = "github.{}:users".format(org_name) + key = f"github.{org_name}:users" if key not in __context__ or ignore_cache: client = _get_client(profile) organization = client.get_organization(org_name) @@ -1834,7 +1833,7 @@ def _query( url += action if command: - url += "/{}".format(command) + url += f"/{command}" log.debug("GitHub URL: %s", url) diff --git a/salt/modules/glanceng.py b/salt/modules/glanceng.py index 7f1b824b0f6..85a76dc650a 100644 --- a/salt/modules/glanceng.py +++ b/salt/modules/glanceng.py @@ -25,7 +25,6 @@ Example configuration identity_api_version: 3 """ - HAS_SHADE = False try: import shade diff --git a/salt/modules/glassfish.py b/salt/modules/glassfish.py index 637264e7331..a41f21e419b 100644 --- a/salt/modules/glassfish.py +++ b/salt/modules/glassfish.py @@ -70,9 +70,9 @@ def _get_url(ssl, url, port, path): Returns the URL of the endpoint """ if ssl: - return "https://{}:{}/management/domain/{}".format(url, port, path) + return f"https://{url}:{port}/management/domain/{path}" else: - return "http://{}:{}/management/domain/{}".format(url, port, path) + return f"http://{url}:{port}/management/domain/{path}" def _get_server(server): @@ -180,7 +180,7 @@ def _get_element_properties(name, element_type, server=None): Get an element's properties """ properties = {} - data = _api_get("{}/{}/property".format(element_type, name), server) + data = _api_get(f"{element_type}/{name}/property", server) # Get properties into a dict if any(data["extraProperties"]["properties"]): @@ -196,7 +196,7 @@ def _get_element(name, element_type, server=None, with_properties=True): """ element = {} name = urllib.parse.quote(name, safe="") - data = _api_get("{}/{}".format(element_type, name), server) + data = _api_get(f"{element_type}/{name}", server) # Format data, get properties if asked, and return the whole thing if any(data["extraProperties"]["entity"]): @@ -239,7 +239,7 @@ def _update_element(name, element_type, data, server=None): properties = [] for key, value in data["properties"].items(): properties.append({"name": key, "value": value}) - _api_post("{}/{}/property".format(element_type, name), properties, server) + _api_post(f"{element_type}/{name}/property", properties, server) del data["properties"] # If the element only contained properties @@ -252,10 +252,10 @@ def _update_element(name, element_type, data, server=None): update_data.update(data) else: __context__["retcode"] = salt.defaults.exitcodes.SALT_BUILD_FAIL - raise CommandExecutionError("Cannot update {}".format(name)) + raise CommandExecutionError(f"Cannot update {name}") # Finally, update the element - _api_post("{}/{}".format(element_type, name), _clean_data(update_data), server) + _api_post(f"{element_type}/{name}", _clean_data(update_data), server) return urllib.parse.unquote(name) @@ -691,4 +691,4 @@ def delete_system_properties(name, server=None): """ Delete a system property """ - _api_delete("system-properties/{}".format(name), None, server) + _api_delete(f"system-properties/{name}", None, server) diff --git a/salt/modules/glusterfs.py b/salt/modules/glusterfs.py index 5de5110df35..b1ba1e2cb8e 100644 --- a/salt/modules/glusterfs.py +++ b/salt/modules/glusterfs.py @@ -73,12 +73,10 @@ def _gluster_xml(cmd): 6, ): result = __salt__["cmd.run"]( - 'script -q -c "gluster --xml --mode=script"', stdin="{}\n\004".format(cmd) + 'script -q -c "gluster --xml --mode=script"', stdin=f"{cmd}\n\004" ) else: - result = __salt__["cmd.run"]( - "gluster --xml --mode=script", stdin="{}\n".format(cmd) - ) + result = __salt__["cmd.run"]("gluster --xml --mode=script", stdin=f"{cmd}\n") try: root = ET.fromstring(_gluster_output_cleanup(result)) @@ -206,9 +204,9 @@ def peer(name): """ if salt.utils.cloud.check_name(name, "a-zA-Z0-9._-"): - raise SaltInvocationError('Invalid characters in peer name "{}"'.format(name)) + raise SaltInvocationError(f'Invalid characters in peer name "{name}"') - cmd = "peer probe {}".format(name) + cmd = f"peer probe {name}" return _gluster(cmd) @@ -288,13 +286,9 @@ def create_volume( try: peer_name, path = brick.split(":") if not path.startswith("/"): - raise SaltInvocationError( - "Brick paths must start with / in {}".format(brick) - ) + raise SaltInvocationError(f"Brick paths must start with / in {brick}") except ValueError: - raise SaltInvocationError( - "Brick syntax is : got {}".format(brick) - ) + raise SaltInvocationError(f"Brick syntax is : got {brick}") # Validate arbiter config if arbiter and replica != 3: @@ -303,17 +297,17 @@ def create_volume( ) # Format creation call - cmd = "volume create {} ".format(name) + cmd = f"volume create {name} " if stripe: - cmd += "stripe {} ".format(stripe) + cmd += f"stripe {stripe} " if replica: - cmd += "replica {} ".format(replica) + cmd += f"replica {replica} " if arbiter: cmd += "arbiter 1 " if device_vg: cmd += "device vg " if transport != "tcp": - cmd += "transport {} ".format(transport) + cmd += f"transport {transport} " cmd += " ".join(bricks) if force: cmd += " force" @@ -358,7 +352,7 @@ def status(name): salt '*' glusterfs.status myvolume """ # Get volume status - root = _gluster_xml("volume status {}".format(name)) + root = _gluster_xml(f"volume status {name}") if not _gluster_ok(root): # Most probably non-existing volume, the error output is logged # This return value is easy to test and intuitive @@ -384,7 +378,7 @@ def status(name): hostname = node.find("hostname").text if hostname not in ("NFS Server", "Self-heal Daemon"): path = node.find("path").text - ret["bricks"]["{}:{}".format(hostname, path)] = etree_legacy_wrap(node) + ret["bricks"][f"{hostname}:{path}"] = etree_legacy_wrap(node) elif hostname == "NFS Server": peerid = node.find("peerid").text true_hostname = hostref[peerid] @@ -427,7 +421,7 @@ def info(name=None): bricks = {} for i, brick in enumerate(_iter(volume, "brick"), start=1): - brickkey = "brick{}".format(i) + brickkey = f"brick{i}" bricks[brickkey] = {"path": brick.text} for child in brick: if not child.tag == "name": @@ -461,9 +455,9 @@ def start_volume(name, force=False): salt '*' glusterfs.start mycluster """ - cmd = "volume start {}".format(name) + cmd = f"volume start {name}" if force: - cmd = "{} force".format(cmd) + cmd = f"{cmd} force" volinfo = info(name) if name not in volinfo: @@ -503,7 +497,7 @@ def stop_volume(name, force=False): log.warning("Attempt to stop already stopped volume %s", name) return True - cmd = "volume stop {}".format(name) + cmd = f"volume stop {name}" if force: cmd += " force" @@ -543,7 +537,7 @@ def delete_volume(target, stop=True): if not stop_volume(target, force=True): return False - cmd = "volume delete {}".format(target) + cmd = f"volume delete {target}" return _gluster(cmd) @@ -571,7 +565,7 @@ def add_volume_bricks(name, bricks): new_bricks = [] - cmd = "volume add-brick {}".format(name) + cmd = f"volume add-brick {name}" if isinstance(bricks, str): bricks = [bricks] @@ -588,7 +582,7 @@ def add_volume_bricks(name, bricks): if new_bricks: for brick in new_bricks: - cmd += " {}".format(brick) + cmd += f" {brick}" return _gluster(cmd) return True @@ -607,7 +601,7 @@ def enable_quota_volume(name): salt '*' glusterfs.enable_quota_volume """ - cmd = "volume quota {} enable".format(name) + cmd = f"volume quota {name} enable" if not _gluster(cmd): return False return True @@ -627,7 +621,7 @@ def disable_quota_volume(name): salt '*' glusterfs.disable_quota_volume """ - cmd = "volume quota {} disable".format(name) + cmd = f"volume quota {name} disable" if not _gluster(cmd): return False return True @@ -655,11 +649,11 @@ def set_quota_volume(name, path, size, enable_quota=False): salt '*' glusterfs.set_quota_volume enable_quota=True """ - cmd = "volume quota {}".format(name) + cmd = f"volume quota {name}" if path: - cmd += " limit-usage {}".format(path) + cmd += f" limit-usage {path}" if size: - cmd += " {}".format(size) + cmd += f" {size}" if enable_quota: if not enable_quota_volume(name): @@ -685,9 +679,9 @@ def unset_quota_volume(name, path): salt '*' glusterfs.unset_quota_volume """ - cmd = "volume quota {}".format(name) + cmd = f"volume quota {name}" if path: - cmd += " remove {}".format(path) + cmd += f" remove {path}" if not _gluster(cmd): return False @@ -707,7 +701,7 @@ def list_quota_volume(name): salt '*' glusterfs.list_quota_volume """ - cmd = "volume quota {}".format(name) + cmd = f"volume quota {name}" cmd += " list" root = _gluster_xml(cmd) @@ -738,7 +732,7 @@ def get_op_version(name): salt '*' glusterfs.get_op_version """ - cmd = "volume get {} cluster.op-version".format(name) + cmd = f"volume get {name} cluster.op-version" root = _gluster_xml(cmd) if not _gluster_ok(root): @@ -816,7 +810,7 @@ def set_op_version(version): salt '*' glusterfs.set_op_version """ - cmd = "volume set all cluster.op-version {}".format(version) + cmd = f"volume set all cluster.op-version {version}" root = _gluster_xml(cmd) if not _gluster_ok(root): diff --git a/salt/modules/gnomedesktop.py b/salt/modules/gnomedesktop.py index abefaeb8586..15553f5fe75 100644 --- a/salt/modules/gnomedesktop.py +++ b/salt/modules/gnomedesktop.py @@ -2,7 +2,6 @@ GNOME implementations """ - import logging import re @@ -78,7 +77,7 @@ class _GSettings: cmd = self.gsetting_command + ["get", str(self.SCHEMA), str(self.KEY)] environ = {} - environ["XDG_RUNTIME_DIR"] = "/run/user/{}".format(uid) + environ["XDG_RUNTIME_DIR"] = f"/run/user/{uid}" result = __salt__["cmd.run_all"]( cmd, runas=user, env=environ, python_shell=False ) @@ -103,12 +102,12 @@ class _GSettings: log.info("User does not exist") result = {} result["retcode"] = 1 - result["stdout"] = "User {} does not exist".format(user) + result["stdout"] = f"User {user} does not exist" return result cmd = self.gsetting_command + ["set", self.SCHEMA, self.KEY, value] environ = {} - environ["XDG_RUNTIME_DIR"] = "/run/user/{}".format(uid) + environ["XDG_RUNTIME_DIR"] = f"/run/user/{uid}" result = __salt__["cmd.run_all"]( cmd, runas=user, env=environ, python_shell=False ) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index 538228214f8..cdfd6a149f4 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -652,9 +652,9 @@ def delete_key( if skey: if not delete_secret: ret["res"] = False - ret[ - "message" - ] = "Secret key exists, delete first or pass delete_secret=True." + ret["message"] = ( + "Secret key exists, delete first or pass delete_secret=True." + ) return ret else: out = __delete_key(fingerprint, True, use_passphrase) @@ -663,9 +663,9 @@ def delete_key( ret["message"] = f"Secret key for {fingerprint} deleted\n" else: ret["res"] = False - ret[ - "message" - ] = f"Failed to delete secret key for {fingerprint}: {out}" + ret["message"] = ( + f"Failed to delete secret key for {fingerprint}: {out}" + ) return ret # Delete the public key @@ -1401,9 +1401,11 @@ def verify( "username": sig.get("username"), "key_id": sig["keyid"], "fingerprint": sig["pubkey_fingerprint"], - "trust_level": VERIFY_TRUST_LEVELS[str(sig["trust_level"])] - if "trust_level" in sig - else None, + "trust_level": ( + VERIFY_TRUST_LEVELS[str(sig["trust_level"])] + if "trust_level" in sig + else None + ), "status": sig["status"], } for sig in verified.sig_info.values() @@ -1431,9 +1433,9 @@ def verify( if not any_signed: ret["res"] = False - ret[ - "message" - ] = "None of the public keys listed in signed_by_any provided a valid signature" + ret["message"] = ( + "None of the public keys listed in signed_by_any provided a valid signature" + ) return ret any_check = True @@ -1451,9 +1453,9 @@ def verify( except (KeyError, IndexError): pass ret["res"] = False - ret[ - "message" - ] = f"Public key {signer} has not provided a valid signature, but was listed in signed_by_all" + ret["message"] = ( + f"Public key {signer} has not provided a valid signature, but was listed in signed_by_all" + ) return ret all_check = True @@ -1463,9 +1465,9 @@ def verify( return ret ret["res"] = False - ret[ - "message" - ] = "Something went wrong while checking for specific signers. This is most likely a bug" + ret["message"] = ( + "Something went wrong while checking for specific signers. This is most likely a bug" + ) return ret diff --git a/salt/modules/grains.py b/salt/modules/grains.py index 9c474a94a64..f60fb1bb053 100644 --- a/salt/modules/grains.py +++ b/salt/modules/grains.py @@ -9,7 +9,6 @@ file on the minions. By default, this file is located at: ``/etc/salt/grains`` This does **NOT** override any grains set in the minion config file. """ - import collections import logging import math @@ -255,7 +254,7 @@ def setvals(grains, destructive=False, refresh_pillar=True): try: grains = salt.utils.yaml.safe_load(fp_) except salt.utils.yaml.YAMLError as exc: - return "Unable to read existing grains file: {}".format(exc) + return f"Unable to read existing grains file: {exc}" if not isinstance(grains, dict): grains = {} for key, val in new_grains.items(): @@ -351,9 +350,9 @@ def append(key, val, convert=False, delimiter=DEFAULT_TARGET_DELIM): if not isinstance(grains, list): grains = [] if grains is None else [grains] if not isinstance(grains, list): - return "The key {} is not a valid list".format(key) + return f"The key {key} is not a valid list" if val in grains: - return "The val {} was already in the list {}".format(val, key) + return f"The val {val} was already in the list {key}" if isinstance(val, list): for item in val: grains.append(item) @@ -398,9 +397,9 @@ def remove(key, val, delimiter=DEFAULT_TARGET_DELIM): """ grains = get(key, [], delimiter) if not isinstance(grains, list): - return "The key {} is not a valid list".format(key) + return f"The key {key} is not a valid list" if val not in grains: - return "The val {} was not in the list {}".format(val, key) + return f"The val {val} was not in the list {key}" grains.remove(val) while delimiter in key: diff --git a/salt/modules/grub_legacy.py b/salt/modules/grub_legacy.py index 7bb46f8be9a..08851e7954a 100644 --- a/salt/modules/grub_legacy.py +++ b/salt/modules/grub_legacy.py @@ -75,14 +75,14 @@ def conf(): if line.startswith("\n"): in_stanza = False if "title" in stanza: - stanza += "order {}".format(pos) + stanza += f"order {pos}" pos += 1 stanzas.append(stanza) stanza = "" continue if line.strip().startswith("title"): if in_stanza: - stanza += "order {}".format(pos) + stanza += f"order {pos}" pos += 1 stanzas.append(stanza) stanza = "" @@ -97,7 +97,7 @@ def conf(): if not line.endswith("\n"): line += "\n" stanza += line - stanza += "order {}".format(pos) + stanza += f"order {pos}" pos += 1 stanzas.append(stanza) except OSError as exc: diff --git a/salt/modules/haproxyconn.py b/salt/modules/haproxyconn.py index f9e156572bc..712eb018d06 100644 --- a/salt/modules/haproxyconn.py +++ b/salt/modules/haproxyconn.py @@ -4,7 +4,6 @@ Support for haproxy .. versionadded:: 2014.7.0 """ - import logging import os import stat @@ -48,9 +47,9 @@ def _get_conn(socket=DEFAULT_SOCKET_URL): """ Get connection to haproxy socket. """ - assert os.path.exists(socket), "{} does not exist.".format(socket) + assert os.path.exists(socket), f"{socket} does not exist." issock = os.stat(socket).st_mode - assert stat.S_ISSOCK(issock), "{} is not a socket.".format(socket) + assert stat.S_ISSOCK(issock), f"{socket} is not a socket." ha_conn = haproxy.conn.HaPConn(socket) return ha_conn @@ -315,6 +314,7 @@ def set_state(name, backend, state, socket=DEFAULT_SOCKET_URL): salt '*' haproxy.set_state my_proxy_server my_backend ready """ + # Pulling this in from the latest 0.5 release which is not yet in PyPi. # https://github.com/neurogeek/haproxyctl class setServerState(haproxy.cmds.Cmd): diff --git a/salt/modules/hashutil.py b/salt/modules/hashutil.py index 9e834794e4e..3517f2512ac 100644 --- a/salt/modules/hashutil.py +++ b/salt/modules/hashutil.py @@ -2,7 +2,6 @@ A collection of hashing and encoding functions """ - import base64 import hashlib import hmac diff --git a/salt/modules/heat.py b/salt/modules/heat.py index 40540fe7cf0..b26277c1488 100644 --- a/salt/modules/heat.py +++ b/salt/modules/heat.py @@ -212,7 +212,7 @@ def _parse_environment(env_str): for param in env: if param not in SECTIONS: - raise ValueError('environment has wrong section "{}"'.format(param)) + raise ValueError(f'environment has wrong section "{param}"') return env @@ -240,7 +240,7 @@ def _poll_for_events( Polling stack events """ if action: - stop_status = ("{}_FAILED".format(action), "{}_COMPLETE".format(action)) + stop_status = (f"{action}_FAILED", f"{action}_COMPLETE") stop_check = lambda a: a in stop_status else: stop_check = lambda a: a.endswith("_COMPLETE") or a.endswith("_FAILED") @@ -281,7 +281,7 @@ def _poll_for_events( time.sleep(poll_period) timeout_sec -= poll_period if timeout_sec <= 0: - stack_status = "{}_FAILED".format(action) + stack_status = f"{action}_FAILED" msg = "Timeout expired" return stack_status, msg @@ -354,7 +354,7 @@ def show_stack(name=None, profile=None): } ret["result"] = True except heatclient.exc.HTTPNotFound: - return {"result": False, "comment": "No stack {}".format(name)} + return {"result": False, "comment": f"No stack {name}"} return ret @@ -391,7 +391,7 @@ def delete_stack(name=None, poll=0, timeout=60, profile=None): h_client.stacks.delete(name) except heatclient.exc.HTTPNotFound: ret["result"] = False - ret["comment"] = "No stack {}".format(name) + ret["comment"] = f"No stack {name}" except heatclient.exc.HTTPForbidden as forbidden: log.exception(forbidden) ret["result"] = False @@ -405,19 +405,19 @@ def delete_stack(name=None, poll=0, timeout=60, profile=None): h_client, name, action="DELETE", poll_period=poll, timeout=timeout ) except heatclient.exc.CommandError: - ret["comment"] = "Deleted stack {}.".format(name) + ret["comment"] = f"Deleted stack {name}." return ret except Exception as ex: # pylint: disable=W0703 log.exception("Delete failed %s", ex) ret["result"] = False - ret["comment"] = "{}".format(ex) + ret["comment"] = f"{ex}" return ret if stack_status == "DELETE_FAILED": ret["result"] = False - ret["comment"] = "Deleted stack FAILED'{}'{}.".format(name, msg) + ret["comment"] = f"Deleted stack FAILED'{name}'{msg}." else: - ret["comment"] = "Deleted stack {}.".format(name) + ret["comment"] = f"Deleted stack {name}." return ret @@ -523,7 +523,7 @@ def create_stack( template = _parse_template(tpl) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open template: {} {}".format( @@ -542,7 +542,7 @@ def create_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Template not valid %s", ex) ret["result"] = False - ret["comment"] = "Template not valid {}".format(ex) + ret["comment"] = f"Template not valid {ex}" return ret env = {} if environment: @@ -590,7 +590,7 @@ def create_stack( env = _parse_environment(env_str) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open environment: {}, {}".format( @@ -614,7 +614,7 @@ def create_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Create failed %s", ex) ret["result"] = False - ret["comment"] = "{}".format(ex) + ret["comment"] = f"{ex}" return ret if poll > 0: stack_status, msg = _poll_for_events( @@ -622,9 +622,9 @@ def create_stack( ) if stack_status == "CREATE_FAILED": ret["result"] = False - ret["comment"] = "Created stack FAILED'{}'{}.".format(name, msg) + ret["comment"] = f"Created stack FAILED'{name}'{msg}." if ret["result"] is True: - ret["comment"] = "Created stack '{}'.".format(name) + ret["comment"] = f"Created stack '{name}'." return ret @@ -734,7 +734,7 @@ def update_stack( template = _parse_template(tpl) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open template: {} {}".format( @@ -753,7 +753,7 @@ def update_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Template not valid %s", ex) ret["result"] = False - ret["comment"] = "Template not valid {}".format(ex) + ret["comment"] = f"Template not valid {ex}" return ret env = {} if environment: @@ -801,7 +801,7 @@ def update_stack( env = _parse_environment(env_str) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open environment: {}, {}".format( @@ -823,7 +823,7 @@ def update_stack( except Exception as ex: # pylint: disable=W0703 log.exception("Update failed %s", ex) ret["result"] = False - ret["comment"] = "Update failed {}".format(ex) + ret["comment"] = f"Update failed {ex}" return ret if poll > 0: @@ -832,9 +832,9 @@ def update_stack( ) if stack_status == "UPDATE_FAILED": ret["result"] = False - ret["comment"] = "Updated stack FAILED'{}'{}.".format(name, msg) + ret["comment"] = f"Updated stack FAILED'{name}'{msg}." if ret["result"] is True: - ret["comment"] = ("Updated stack '{}'.".format(name),) + ret["comment"] = (f"Updated stack '{name}'.",) return ret @@ -861,9 +861,9 @@ def template_stack(name=None, profile=None): try: get_template = h_client.stacks.template(name) except heatclient.exc.HTTPNotFound: - return {"result": False, "comment": "No stack with {}".format(name)} + return {"result": False, "comment": f"No stack with {name}"} except heatclient.exc.BadRequest: - return {"result": False, "comment": "Bad request fot stack {}".format(name)} + return {"result": False, "comment": f"Bad request fot stack {name}"} if "heat_template_version" in get_template: template = salt.utils.yaml.safe_dump(get_template) else: diff --git a/salt/modules/helm.py b/salt/modules/helm.py index 19790726716..960c90e87bf 100644 --- a/salt/modules/helm.py +++ b/salt/modules/helm.py @@ -32,7 +32,6 @@ Detailed Function Documentation ------------------------------- """ - import copy import logging import re @@ -1044,7 +1043,7 @@ def repo_manage( ) already_present = False - for (index, repo_present) in enumerate(repos_present): + for index, repo_present in enumerate(repos_present): if repo.get("name") == repo_present.get("name") and repo.get( "url" ) == repo_present.get("url"): diff --git a/salt/modules/hg.py b/salt/modules/hg.py index 2835a531494..9e1d9de6be1 100644 --- a/salt/modules/hg.py +++ b/salt/modules/hg.py @@ -2,7 +2,6 @@ Support for the Mercurial SCM """ - import logging import salt.utils.data @@ -23,7 +22,7 @@ def __virtual__(): def _ssh_flag(identity_path): - return ["--ssh", "ssh -i {}".format(identity_path)] + return ["--ssh", f"ssh -i {identity_path}"] def revision(cwd, rev="tip", short=False, user=None): @@ -48,7 +47,7 @@ def revision(cwd, rev="tip", short=False, user=None): salt '*' hg.revision /path/to/repo mybranch """ - cmd = ["hg", "id", "-i", "--debug" if not short else "", "-r", "{}".format(rev)] + cmd = ["hg", "id", "-i", "--debug" if not short else "", "-r", f"{rev}"] result = __salt__["cmd.run_all"](cmd, cwd=cwd, runas=user, python_shell=False) @@ -81,7 +80,7 @@ def describe(cwd, rev="tip", user=None): "hg", "log", "-r", - "{}".format(rev), + f"{rev}", "--template", "'{{latesttag}}-{{latesttagdistance}}-{{node|short}}'", ] @@ -125,16 +124,16 @@ def archive(cwd, output, rev="tip", fmt=None, prefix=None, user=None): cmd = [ "hg", "archive", - "{}".format(output), + f"{output}", "--rev", - "{}".format(rev), + f"{rev}", ] if fmt: cmd.append("--type") - cmd.append("{}".format(fmt)) + cmd.append(f"{fmt}") if prefix: cmd.append("--prefix") - cmd.append('"{}"'.format(prefix)) + cmd.append(f'"{prefix}"') return __salt__["cmd.run"](cmd, cwd=cwd, runas=user, python_shell=False) @@ -205,7 +204,7 @@ def update(cwd, rev, force=False, user=None): salt devserver1 hg.update /path/to/repo somebranch """ - cmd = ["hg", "update", "{}".format(rev)] + cmd = ["hg", "update", f"{rev}"] if force: cmd.append("-C") @@ -245,10 +244,10 @@ def clone(cwd, repository, opts=None, user=None, identity=None): salt '*' hg.clone /path/to/repo https://bitbucket.org/birkenfeld/sphinx """ - cmd = ["hg", "clone", "{}".format(repository), "{}".format(cwd)] + cmd = ["hg", "clone", f"{repository}", f"{cwd}"] if opts: for opt in opts.split(): - cmd.append("{}".format(opt)) + cmd.append(f"{opt}") if identity: cmd.extend(_ssh_flag(identity)) @@ -285,7 +284,7 @@ def status(cwd, opts=None, user=None): cmd = ["hg", "status"] if opts: for opt in opts.split(): - cmd.append("{}".format(opt)) + cmd.append(f"{opt}") out = __salt__["cmd.run_stdout"](cmd, cwd=cwd, runas=user, python_shell=False) types = { "M": "modified", diff --git a/salt/modules/highstate_doc.py b/salt/modules/highstate_doc.py index 9f0b89bffbf..a91f77b2afb 100644 --- a/salt/modules/highstate_doc.py +++ b/salt/modules/highstate_doc.py @@ -388,7 +388,7 @@ def _get_config(**kwargs): "note": None, } if "__salt__" in globals(): - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" config.update(__salt__["config.get"](config_key, {})) # pylint: disable=C0201 for k in set(config.keys()) & set(kwargs.keys()): @@ -437,7 +437,7 @@ def read_file(name): def render( jinja_template_text=None, jinja_template_function="highstate_doc.markdown_default_jinja_template", - **kwargs + **kwargs, ): """ Render highstate to a text format (default Markdown) @@ -573,13 +573,13 @@ def _format_markdown_system_file(filename, config): file_stats, whitelist=["user", "group", "mode", "uid", "gid", "size"] ) if y: - ret += "file stat {1}\n```\n{0}```\n".format(y, filename) + ret += f"file stat {filename}\n```\n{y}```\n" file_size = file_stats.get("size") if file_size <= config.get("max_render_file_size"): is_binary = True try: # TODO: this is linux only should find somthing portable - file_type = __salt__["cmd.shell"]("\\file -i '{}'".format(filename)) + file_type = __salt__["cmd.shell"](f"\\file -i '{filename}'") if "charset=binary" not in file_type: is_binary = False except Exception as ex: # pylint: disable=broad-except @@ -591,11 +591,11 @@ def _format_markdown_system_file(filename, config): with salt.utils.files.fopen(filename, "r") as f: file_data = salt.utils.stringutils.to_unicode(f.read()) file_data = _md_fix(file_data) - ret += "file data {1}\n```\n{0}\n```\n".format(file_data, filename) + ret += f"file data {filename}\n```\n{file_data}\n```\n" else: ret += "```\n{}\n```\n".format( "SKIPPED LARGE FILE!\nSet {}:max_render_file_size > {} to render.".format( - "{}.config".format(__virtualname__), file_size + f"{__virtualname__}.config", file_size ) ) return ret @@ -614,11 +614,11 @@ def _format_markdown_requisite(state, stateid, makelink=True): """ format requisite as a link users can click """ - fmt_id = "{}: {}".format(state, stateid) + fmt_id = f"{state}: {stateid}" if makelink: - return " * [{}](#{})\n".format(fmt_id, _format_markdown_link(fmt_id)) + return f" * [{fmt_id}](#{_format_markdown_link(fmt_id)})\n" else: - return " * `{}`\n".format(fmt_id) + return f" * `{fmt_id}`\n" def processor_markdown(lowstate_item, config, **kwargs): @@ -669,19 +669,19 @@ def processor_markdown(lowstate_item, config, **kwargs): if "source" in s: text = __salt__["cp.get_file_str"](s["source"]) if text: - details += "\n{}\n".format(text) + details += f"\n{text}\n" else: details += "\n{}\n".format("ERROR: opening {}".format(s["source"])) if state_function == "pkg.installed": pkgs = s.get("pkgs", s.get("name")) - details += "\n```\ninstall: {}\n```\n".format(pkgs) + details += f"\n```\ninstall: {pkgs}\n```\n" if state_function == "file.recurse": details += """recurse copy of files\n""" y = _state_data_to_yaml_string(s) if y: - details += "```\n{}\n```\n".format(y) + details += f"```\n{y}\n```\n" if "!doc_recurse" in id_full: findfiles = __salt__["file.find"](path=s.get("name"), type="f") if len(findfiles) < 10 or "!doc_recurse_force" in id_full: @@ -715,7 +715,7 @@ def processor_markdown(lowstate_item, config, **kwargs): if not details: y = _state_data_to_yaml_string(s) if y: - details += "```\n{}```\n".format(y) + details += f"```\n{y}```\n" r = { "vars": lowstate_item, diff --git a/salt/modules/hosts.py b/salt/modules/hosts.py index a8c4d412c2a..267fe056ad5 100644 --- a/salt/modules/hosts.py +++ b/salt/modules/hosts.py @@ -2,7 +2,6 @@ Manage the information in the hosts file """ - import errno import logging import os @@ -59,7 +58,7 @@ def _list_hosts(): if not line: continue if line.startswith("#"): - ret.setdefault("comment-{}".format(count), []).append(line) + ret.setdefault(f"comment-{count}", []).append(line) count += 1 continue comment = None diff --git a/salt/modules/http.py b/salt/modules/http.py index 44464eaa11b..6252b21dc16 100644 --- a/salt/modules/http.py +++ b/salt/modules/http.py @@ -5,7 +5,6 @@ like, but also useful for basic http testing. .. versionadded:: 2015.5.0 """ - import time import salt.utils.http diff --git a/salt/modules/icinga2.py b/salt/modules/icinga2.py index ef222ced217..391fb4abea7 100644 --- a/salt/modules/icinga2.py +++ b/salt/modules/icinga2.py @@ -6,7 +6,6 @@ Module to provide icinga2 compatibility to salt. :depends: - icinga2 server """ - import logging import salt.utils.path @@ -71,9 +70,9 @@ def generate_cert(domain): "--cn", domain, "--key", - "{}{}.key".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.key", "--cert", - "{}{}.crt".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.crt", ], python_shell=False, ) @@ -100,11 +99,11 @@ def save_cert(domain, master): "pki", "save-cert", "--key", - "{}{}.key".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.key", "--cert", - "{}{}.cert".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.cert", "--trustedcert", - "{}trusted-master.crt".format(get_certs_path()), + f"{get_certs_path()}trusted-master.crt", "--host", master, ], @@ -140,13 +139,13 @@ def request_cert(domain, master, ticket, port): "--ticket", ticket, "--key", - "{}{}.key".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.key", "--cert", - "{}{}.crt".format(get_certs_path(), domain), + f"{get_certs_path()}{domain}.crt", "--trustedcert", - "{}trusted-master.crt".format(get_certs_path()), + f"{get_certs_path()}trusted-master.crt", "--ca", - "{}ca.crt".format(get_certs_path()), + f"{get_certs_path()}ca.crt", ], python_shell=False, ) @@ -182,7 +181,7 @@ def node_setup(domain, master, ticket): "--master_host", master, "--trustedcert", - "{}trusted-master.crt".format(get_certs_path()), + f"{get_certs_path()}trusted-master.crt", ], python_shell=False, ) diff --git a/salt/modules/ifttt.py b/salt/modules/ifttt.py index 3c49b25a111..9126ab06b33 100644 --- a/salt/modules/ifttt.py +++ b/salt/modules/ifttt.py @@ -11,7 +11,6 @@ Requires an ``api_key`` in ``/etc/salt/minion``: secret_key: '280d4699-a817-4719-ba6f-ca56e573e44f' """ - import logging import time @@ -39,7 +38,7 @@ def _query(event=None, method="GET", args=None, header_dict=None, data=None): secret_key = __salt__["config.get"]("ifttt.secret_key") or __salt__["config.get"]( "ifttt:secret_key" ) - path = "https://maker.ifttt.com/trigger/{}/with/key/{}".format(event, secret_key) + path = f"https://maker.ifttt.com/trigger/{event}/with/key/{secret_key}" if header_dict is None: header_dict = {"Content-type": "application/json"} diff --git a/salt/modules/ilo.py b/salt/modules/ilo.py index c01e9da213c..c8d104fe797 100644 --- a/salt/modules/ilo.py +++ b/salt/modules/ilo.py @@ -47,7 +47,7 @@ def __execute_cmd(name, xml): tmpfilename = fh.name fh.write(xml) - cmd = __salt__["cmd.run_all"]("hponcfg -f {}".format(tmpfilename)) + cmd = __salt__["cmd.run_all"](f"hponcfg -f {tmpfilename}") # Clean up the temp file __salt__["file.remove"](tmpfilename) @@ -394,11 +394,7 @@ def create_user(name, password, *privileges): name, password, "\n".join( - [ - '<{} value="Y" />'.format(i.upper()) - for i in privileges - if i.upper() in _priv - ] + [f'<{i.upper()} value="Y" />' for i in privileges if i.upper() in _priv] ), ) diff --git a/salt/modules/incron.py b/salt/modules/incron.py index ad13c6de6e5..ad99b27aa3e 100644 --- a/salt/modules/incron.py +++ b/salt/modules/incron.py @@ -56,7 +56,7 @@ def _render_tab(lst): """ ret = [] for pre in lst["pre"]: - ret.append("{}\n".format(pre)) + ret.append(f"{pre}\n") for cron in lst["crons"]: ret.append( "{} {} {}\n".format( @@ -72,7 +72,7 @@ def _get_incron_cmdstr(path): """ Returns a format string, to be used to build an incrontab command. """ - return "incrontab {}".format(path) + return f"incrontab {path}" def write_incron_file(user, path): @@ -121,7 +121,7 @@ def _write_incron_lines(user, lines): with salt.utils.files.fopen(path, "wb") as fp_: fp_.writelines(salt.utils.data.encode(lines)) if user != "root": - __salt__["cmd.run"]("chown {} {}".format(user, path), python_shell=False) + __salt__["cmd.run"](f"chown {user} {path}", python_shell=False) ret = __salt__["cmd.run_all"]( _get_incron_cmdstr(path), runas=user, python_shell=False ) @@ -135,7 +135,7 @@ def _write_file(folder, filename, data): """ path = os.path.join(folder, filename) if not os.path.exists(folder): - msg = "{} cannot be written. {} does not exist".format(filename, folder) + msg = f"{filename} cannot be written. {folder} does not exist" log.error(msg) raise AttributeError(str(msg)) with salt.utils.files.fopen(path, "w") as fp_: @@ -180,7 +180,7 @@ def raw_incron(user): salt '*' incron.raw_incron root """ - cmd = "incrontab -l {}".format(user) + cmd = f"incrontab -l {user}" return __salt__["cmd.run_stdout"](cmd, rstrip=False, runas=user, python_shell=False) @@ -236,7 +236,7 @@ def set_job(user, path, mask, cmd): # Check for valid mask types for item in mask.split(","): if item not in _MASK_TYPES: - return "Invalid mask type: {}".format(item) + return f"Invalid mask type: {item}" updated = False arg_mask = mask.split(",") @@ -296,7 +296,7 @@ def rm_job(user, path, mask, cmd): # Check for valid mask types for item in mask.split(","): if item not in _MASK_TYPES: - return "Invalid mask type: {}".format(item) + return f"Invalid mask type: {item}" lst = list_tab(user) ret = "absent" diff --git a/salt/modules/influxdb08mod.py b/salt/modules/influxdb08mod.py index 8a46c7d4ef6..b48d08e0792 100644 --- a/salt/modules/influxdb08mod.py +++ b/salt/modules/influxdb08mod.py @@ -21,7 +21,6 @@ version 0.5-0.8) overwrite options passed into pillar. """ - import logging try: diff --git a/salt/modules/influxdbmod.py b/salt/modules/influxdbmod.py index 303ab044706..c8c1689d5d4 100644 --- a/salt/modules/influxdbmod.py +++ b/salt/modules/influxdbmod.py @@ -66,7 +66,7 @@ def _client( influxdb_password=None, influxdb_host=None, influxdb_port=None, - **client_args + **client_args, ): if not influxdb_user: influxdb_user = __salt__["config.option"]("influxdb.user", "root") @@ -84,7 +84,7 @@ def _client( port=influxdb_port, username=influxdb_user, password=influxdb_password, - **client_args + **client_args, ) @@ -635,7 +635,8 @@ def create_continuous_query( .. code-block:: bash - salt '*' influxdb.create_continuous_query mydb cq_month 'SELECT mean(*) INTO mydb.a_month.:MEASUREMENT FROM mydb.a_week./.*/ GROUP BY time(5m), *'""" + salt '*' influxdb.create_continuous_query mydb cq_month 'SELECT mean(*) INTO mydb.a_month.:MEASUREMENT FROM mydb.a_week./.*/ GROUP BY time(5m), *' + """ client = _client(**client_args) full_query = "CREATE CONTINUOUS QUERY {name} ON {database}" if resample_time: @@ -673,7 +674,7 @@ def drop_continuous_query(database, name, **client_args): """ client = _client(**client_args) - query = "DROP CONTINUOUS QUERY {} ON {}".format(name, database) + query = f"DROP CONTINUOUS QUERY {name} ON {database}" client.query(query) return True @@ -683,7 +684,7 @@ def _pull_query_results(resultset): Parses a ResultSet returned from InfluxDB into a dictionary of results, grouped by series names and optional JSON-encoded grouping tags. """ - _results = collections.defaultdict(lambda: {}) + _results = collections.defaultdict(dict) for _header, _values in resultset.items(): _header, _group_tags = _header if _group_tags: diff --git a/salt/modules/infoblox.py b/salt/modules/infoblox.py index a779b6322f9..14402e437d6 100644 --- a/salt/modules/infoblox.py +++ b/salt/modules/infoblox.py @@ -61,7 +61,7 @@ def _get_config(**api_opts): "api_key": "", } if "__salt__" in globals(): - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" config.update(__salt__["config.get"](config_key, {})) # pylint: disable=C0201 for k in set(config.keys()) & set(api_opts.keys()): @@ -143,7 +143,7 @@ def update_object(objref, data, **api_opts): salt-call infoblox.update_object objref=[ref_of_object] data={} """ if "__opts__" in globals() and __opts__["test"]: - return {"Test": "Would attempt to update object: {}".format(objref)} + return {"Test": f"Would attempt to update object: {objref}"} infoblox = _get_infoblox(**api_opts) return infoblox.update_object(objref, data) @@ -159,7 +159,7 @@ def delete_object(objref, **api_opts): salt-call infoblox.delete_object objref=[ref_of_object] """ if "__opts__" in globals() and __opts__["test"]: - return {"Test": "Would attempt to delete object: {}".format(objref)} + return {"Test": f"Would attempt to delete object: {objref}"} infoblox = _get_infoblox(**api_opts) return infoblox.delete_object(objref) @@ -175,7 +175,7 @@ def create_object(object_type, data, **api_opts): salt-call infoblox.update_object object_type=record:host data={} """ if "__opts__" in globals() and __opts__["test"]: - return {"Test": "Would attempt to create object: {}".format(object_type)} + return {"Test": f"Would attempt to create object: {object_type}"} infoblox = _get_infoblox(**api_opts) return infoblox.create_object(object_type, data) @@ -186,7 +186,7 @@ def get_object( return_fields=None, max_results=None, ensure_none_or_one_result=False, - **api_opts + **api_opts, ): """ Get raw infoblox object. This is a low level api call. diff --git a/salt/modules/inspectlib/collector.py b/salt/modules/inspectlib/collector.py index 735f74d67de..d92646c9fc3 100644 --- a/salt/modules/inspectlib/collector.py +++ b/salt/modules/inspectlib/collector.py @@ -406,7 +406,7 @@ class Inspector(EnvLoader): all_links = list() for entry_path in [pth for pth in (allowed or os.listdir("/")) if pth]: if entry_path[0] != "/": - entry_path = "/{}".format(entry_path) + entry_path = f"/{entry_path}" if entry_path in ignored or os.path.islink(entry_path): continue e_files, e_dirs, e_links = self._get_all_files(entry_path, *ignored) @@ -490,7 +490,7 @@ class Inspector(EnvLoader): Take a snapshot of the system. """ if mode not in self.MODE: - raise InspectorSnapshotException("Unknown mode: '{}'".format(mode)) + raise InspectorSnapshotException(f"Unknown mode: '{mode}'") if is_alive(self.pidfile): raise CommandExecutionError("Inspection already in progress.") @@ -500,7 +500,7 @@ class Inspector(EnvLoader): subprocess.run( [ "nice", - "-{}".format(priority), + f"-{priority}", "python", __file__, os.path.dirname(self.pidfile), @@ -596,7 +596,7 @@ if __name__ == "__main__": with salt.utils.files.fopen( os.path.join(pidfile, EnvLoader.PID_FILE), "w" ) as fp_: - fp_.write("{}\n".format(pid)) + fp_.write(f"{pid}\n") sys.exit(0) except OSError as ex: sys.exit(1) diff --git a/salt/modules/inspectlib/fsdb.py b/salt/modules/inspectlib/fsdb.py index b834b8f6783..daa9a74ded4 100644 --- a/salt/modules/inspectlib/fsdb.py +++ b/salt/modules/inspectlib/fsdb.py @@ -187,7 +187,7 @@ class CsvDB: with gzip.open(os.path.join(self.db_path, obj._TABLE), "wt") as table_file: csv.writer(table_file).writerow( [ - "{col}:{type}".format(col=elm[0], type=get_type(elm[1])) + f"{elm[0]}:{get_type(elm[1])}" for elm in tuple(obj.__dict__.items()) ] ) @@ -270,7 +270,7 @@ class CsvDB: def _validate_object(self, obj): descr = self._tables.get(obj._TABLE) if descr is None: - raise Exception("Table {} not found.".format(obj._TABLE)) + raise Exception(f"Table {obj._TABLE} not found.") return obj._serialize(self._tables[obj._TABLE]) def __criteria(self, obj, matches=None, mt=None, lt=None, eq=None): diff --git a/salt/modules/inspectlib/kiwiproc.py b/salt/modules/inspectlib/kiwiproc.py index 321dfa8ff68..d3947ff5b00 100644 --- a/salt/modules/inspectlib/kiwiproc.py +++ b/salt/modules/inspectlib/kiwiproc.py @@ -247,11 +247,11 @@ class KiwiExporter: descr = etree.SubElement(node, "description") author = etree.SubElement(descr, "author") - author.text = "salt.modules.node on {}".format(hostname) + author.text = f"salt.modules.node on {hostname}" contact = etree.SubElement(descr, "contact") - contact.text = "root@{}".format(hostname) + contact.text = f"root@{hostname}" specs = etree.SubElement(descr, "specification") - specs.text = "Rebuild of {}, based on Salt inspection.".format(hostname) + specs.text = f"Rebuild of {hostname}, based on Salt inspection." return descr diff --git a/salt/modules/inspectlib/query.py b/salt/modules/inspectlib/query.py index 54494d6a104..cfc372486a0 100644 --- a/salt/modules/inspectlib/query.py +++ b/salt/modules/inspectlib/query.py @@ -35,7 +35,7 @@ class SysInfo: def __init__(self, systype): if systype.lower() == "solaris": - raise SIException("Platform {} not (yet) supported.".format(systype)) + raise SIException(f"Platform {systype} not (yet) supported.") def _grain(self, grain): """ @@ -47,7 +47,7 @@ class SysInfo: """ Get a size of a disk. """ - out = __salt__["cmd.run_all"]("df {}".format(device)) + out = __salt__["cmd.run_all"](f"df {device}") if out["retcode"]: msg = "Disk size info error: {}".format(out["stderr"]) log.error(msg) @@ -464,13 +464,13 @@ class Query(EnvLoader): fmt = fmt.lower() if fmt == "b": - return "{} Bytes".format(size) + return f"{size} Bytes" elif fmt == "kb": - return "{} Kb".format(round((float(size) / 0x400), 2)) + return f"{round((float(size) / 0x400), 2)} Kb" elif fmt == "mb": - return "{} Mb".format(round((float(size) / 0x400 / 0x400), 2)) + return f"{round((float(size) / 0x400 / 0x400), 2)} Mb" elif fmt == "gb": - return "{} Gb".format(round((float(size) / 0x400 / 0x400 / 0x400), 2)) + return f"{round((float(size) / 0x400 / 0x400 / 0x400), 2)} Gb" filter = kwargs.get("filter") offset = kwargs.get("offset", 0) @@ -478,7 +478,7 @@ class Query(EnvLoader): timeformat = kwargs.get("time", "tz") if timeformat not in ["ticks", "tz"]: raise InspectorQueryException( - 'Unknown "{}" value for parameter "time"'.format(timeformat) + f'Unknown "{timeformat}" value for parameter "time"' ) tfmt = ( lambda param: timeformat == "tz" diff --git a/salt/modules/inspector.py b/salt/modules/inspector.py index 02162cb564c..2d549e353a6 100644 --- a/salt/modules/inspector.py +++ b/salt/modules/inspector.py @@ -51,7 +51,7 @@ def _(module): import importlib - mod = importlib.import_module("salt.modules.inspectlib.{}".format(module)) + mod = importlib.import_module(f"salt.modules.inspectlib.{module}") mod.__grains__ = __grains__ mod.__pillar__ = __pillar__ mod.__salt__ = __salt__ diff --git a/salt/modules/iosconfig.py b/salt/modules/iosconfig.py index be0b58a5bd6..75d40756aee 100644 --- a/salt/modules/iosconfig.py +++ b/salt/modules/iosconfig.py @@ -166,7 +166,7 @@ def tree(config=None, path=None, with_tags=False, saltenv="base"): if path: config = __salt__["cp.get_file_str"](path, saltenv=saltenv) if config is False: - raise SaltException("{} is not available".format(path)) + raise SaltException(f"{path} is not available") config_lines = config.splitlines() return _parse_text_config(config_lines, with_tags=with_tags) diff --git a/salt/modules/ipmi.py b/salt/modules/ipmi.py index a30a8fb5a14..133b1161c6a 100644 --- a/salt/modules/ipmi.py +++ b/salt/modules/ipmi.py @@ -30,7 +30,6 @@ systems hardware through IPMI drivers. It uses a python module `pyghmi`. uid=1 """ - IMPORT_ERR = None try: from pyghmi.ipmi import command # nosec @@ -58,7 +57,7 @@ def _get_config(**kwargs): "api_login_timeout": 2, } if "__salt__" in globals(): - config_key = "{}.config".format(__virtualname__) + config_key = f"{__virtualname__}.config" config.update(__salt__["config.get"](config_key, {})) for k in set(config) & set(kwargs): config[k] = kwargs[k] @@ -198,7 +197,7 @@ def set_channel_access( access_mode="always", privilege_update_mode="non_volatile", privilege_level="administrator", - **kwargs + **kwargs, ): """ Set channel access @@ -388,7 +387,7 @@ def set_user_access( link_auth=True, ipmi_msg=True, privilege_level="administrator", - **kwargs + **kwargs, ): """ Set user access @@ -897,7 +896,7 @@ def create_user( link_auth=True, ipmi_msg=True, privilege_level="administrator", - **kwargs + **kwargs, ): """ create/ensure a user is created with provided settings. diff --git a/salt/modules/ipset.py b/salt/modules/ipset.py index c250d90e0d8..daa32dd3fb1 100644 --- a/salt/modules/ipset.py +++ b/salt/modules/ipset.py @@ -2,7 +2,6 @@ Support for ipset """ - import logging import salt.utils.path diff --git a/salt/modules/iptables.py b/salt/modules/iptables.py index 0b1177f1f54..c159dde87f3 100644 --- a/salt/modules/iptables.py +++ b/salt/modules/iptables.py @@ -73,7 +73,7 @@ def _has_option(option, family="ipv4"): _has_option('--wait') _has_option('--check', family='ipv6') """ - cmd = "{} --help".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)} --help" if option in __salt__["cmd.run_stdout"](cmd, output_loglevel="quiet"): return True return False @@ -192,7 +192,7 @@ def version(family="ipv4"): IPv6: salt '*' iptables.version family=ipv6 """ - cmd = "{} --version".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)} --version" out = __salt__["cmd.run_stdout"](cmd).split() return out[1] @@ -204,7 +204,7 @@ def build_rule( position="", full=None, family="ipv4", - **kwargs + **kwargs, ): """ Build a well-formatted iptables rule based on kwargs. A `table` and `chain` @@ -316,7 +316,7 @@ def build_rule( if not isinstance(match_value, list): match_value = match_value.split(",") for match in match_value: - rule.append("-m {}".format(match)) + rule.append(f"-m {match}") if "name_" in kwargs and match.strip() in ("pknock", "quota2", "recent"): rule.append("--name {}".format(kwargs["name_"])) del kwargs["name_"] @@ -335,7 +335,7 @@ def build_rule( if match_set.startswith("!") or match_set.startswith("not"): negative_match_set = "! " match_set = re.sub(bang_not_pat, "", match_set) - rule.append("-m set {}--match-set {}".format(negative_match_set, match_set)) + rule.append(f"-m set {negative_match_set}--match-set {match_set}") del kwargs["match-set"] if "connstate" in kwargs: @@ -382,7 +382,7 @@ def build_rule( else: dports = mp_value - rule.append("--{} {}".format(multiport_arg, dports)) + rule.append(f"--{multiport_arg} {dports}") del kwargs[multiport_arg] if "comment" in kwargs: @@ -526,11 +526,11 @@ def build_rule( if after_jump_argument in kwargs: value = kwargs[after_jump_argument] if value in (None, ""): # options without arguments - after_jump.append("--{}".format(after_jump_argument)) + after_jump.append(f"--{after_jump_argument}") elif any(ws_char in str(value) for ws_char in string.whitespace): - after_jump.append('--{} "{}"'.format(after_jump_argument, value)) + after_jump.append(f'--{after_jump_argument} "{value}"') else: - after_jump.append("--{} {}".format(after_jump_argument, value)) + after_jump.append(f"--{after_jump_argument} {value}") del kwargs[after_jump_argument] for key in kwargs: @@ -539,8 +539,8 @@ def build_rule( # the value in the kwargs, thus we need to fetch it after that has run value = kwargs[key] flag = "-" if len(key) == 1 else "--" - value = "" if value in (None, "") else " {}".format(value) - rule.append("{}{}{}{}".format(negation, flag, key, value)) + value = "" if value in (None, "") else f" {value}" + rule.append(f"{negation}{flag}{key}{value}") rule += after_jump @@ -704,7 +704,7 @@ def save(filename=None, family="ipv4"): parent_dir = os.path.dirname(filename) if not os.path.isdir(parent_dir): os.makedirs(parent_dir) - cmd = "{}-save".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)}-save" ipt = __salt__["cmd.run_stdout"](cmd) # regex out the output if configured with filters @@ -743,26 +743,24 @@ def check(table="filter", chain=None, rule=None, family="ipv4"): ipt_cmd = _iptables_cmd(family) if _has_option("--check", family): - cmd = "{} -t {} -C {} {}".format(ipt_cmd, table, chain, rule) + cmd = f"{ipt_cmd} -t {table} -C {chain} {rule}" __salt__["cmd.run_stderr"](cmd, output_loglevel="quiet") return not __context__["retcode"] else: _chain_name = hex(uuid.getnode()) # Create temporary table - __salt__["cmd.run"]("{} -t {} -N {}".format(ipt_cmd, table, _chain_name)) - __salt__["cmd.run"]( - "{} -t {} -A {} {}".format(ipt_cmd, table, _chain_name, rule) - ) + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -N {_chain_name}") + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -A {_chain_name} {rule}") - out = __salt__["cmd.run_stdout"]("{}-save".format(ipt_cmd)) + out = __salt__["cmd.run_stdout"](f"{ipt_cmd}-save") # Clean up temporary table - __salt__["cmd.run"]("{} -t {} -F {}".format(ipt_cmd, table, _chain_name)) - __salt__["cmd.run"]("{} -t {} -X {}".format(ipt_cmd, table, _chain_name)) + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -F {_chain_name}") + __salt__["cmd.run"](f"{ipt_cmd} -t {table} -X {_chain_name}") for i in out.splitlines(): - if i.startswith("-A {}".format(_chain_name)): + if i.startswith(f"-A {_chain_name}"): if i.replace(_chain_name, chain) in out.splitlines(): return True @@ -792,8 +790,8 @@ def check_chain(table="filter", chain=None, family="ipv4"): if not chain: return "Error: Chain needs to be specified" - cmd = "{}-save -t {}".format(_iptables_cmd(family), table) - out = __salt__["cmd.run_stdout"](cmd).find(":{} ".format(chain)) + cmd = f"{_iptables_cmd(family)}-save -t {table}" + out = __salt__["cmd.run_stdout"](cmd).find(f":{chain} ") if out != -1: out = True @@ -823,7 +821,7 @@ def new_chain(table="filter", chain=None, family="ipv4"): return "Error: Chain needs to be specified" wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -N {}".format(_iptables_cmd(family), wait, table, chain) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -N {chain}" out = __salt__["cmd.run_stderr"](cmd) if not out: @@ -851,7 +849,7 @@ def delete_chain(table="filter", chain=None, family="ipv4"): return "Error: Chain needs to be specified" wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -X {}".format(_iptables_cmd(family), wait, table, chain) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -X {chain}" out = __salt__["cmd.run_stderr"](cmd) if not out: @@ -889,7 +887,7 @@ def append(table="filter", chain=None, rule=None, family="ipv4"): returnCheck = check(table, chain, rule, family) if isinstance(returnCheck, bool) and returnCheck: return False - cmd = "{} {} -t {} -A {} {}".format(_iptables_cmd(family), wait, table, chain, rule) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -A {chain} {rule}" out = __salt__["cmd.run_stderr"](cmd) return not out @@ -977,7 +975,7 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): rule = position wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -D {} {}".format(_iptables_cmd(family), wait, table, chain, rule) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -D {chain} {rule}" out = __salt__["cmd.run_stderr"](cmd) return out @@ -998,7 +996,7 @@ def flush(table="filter", chain="", family="ipv4"): """ wait = "--wait" if _has_option("--wait", family) else "" - cmd = "{} {} -t {} -F {}".format(_iptables_cmd(family), wait, table, chain) + cmd = f"{_iptables_cmd(family)} {wait} -t {table} -F {chain}" out = __salt__["cmd.run_stderr"](cmd) return out @@ -1016,7 +1014,7 @@ def _parse_conf(conf_file=None, in_mem=False, family="ipv4"): with salt.utils.files.fopen(conf_file, "r") as ifile: rules = ifile.read() elif in_mem: - cmd = "{}-save".format(_iptables_cmd(family)) + cmd = f"{_iptables_cmd(family)}-save" rules = __salt__["cmd.run_stdout"](cmd) else: raise SaltException("A file was not found to parse") @@ -1057,7 +1055,7 @@ def _parse_conf(conf_file=None, in_mem=False, family="ipv4"): and args[index + 1] != "!" and not args[index + 1].startswith("-") ): - args[index] += " {}".format(args.pop(index + 1)) + args[index] += f" {args.pop(index + 1)}" index += 1 if args[-1].startswith("-"): args.append("") diff --git a/salt/modules/iwtools.py b/salt/modules/iwtools.py index aec30a8390c..198375d9850 100644 --- a/salt/modules/iwtools.py +++ b/salt/modules/iwtools.py @@ -36,10 +36,10 @@ def scan(iface, style=None): if not _valid_iface(iface): raise SaltInvocationError("The interface specified is not valid") - out = __salt__["cmd.run"]("iwlist {} scan".format(iface)) + out = __salt__["cmd.run"](f"iwlist {iface} scan") if "Network is down" in out: - __salt__["cmd.run"]("ip link set {} up".format(iface)) - out = __salt__["cmd.run"]("iwlist {} scan".format(iface)) + __salt__["cmd.run"](f"ip link set {iface} up") + out = __salt__["cmd.run"](f"iwlist {iface} scan") ret = {} tmp = {} for line in out.splitlines(): @@ -101,7 +101,7 @@ def set_mode(iface, mode): ) ) __salt__["ip.down"](iface) - out = __salt__["cmd.run"]("iwconfig {} mode {}".format(iface, mode)) + out = __salt__["cmd.run"](f"iwconfig {iface} mode {mode}") __salt__["ip.up"](iface) return mode diff --git a/salt/modules/jboss7.py b/salt/modules/jboss7.py index f43a66fb1f4..1651da7ea8f 100644 --- a/salt/modules/jboss7.py +++ b/salt/modules/jboss7.py @@ -21,7 +21,6 @@ Example: """ - import logging import re @@ -91,7 +90,7 @@ def stop_server(jboss_config, host=None): if host is None: operation = ":shutdown" else: - operation = '/host="{host}"/:shutdown'.format(host=host) + operation = f'/host="{host}"/:shutdown' shutdown_result = __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False ) @@ -130,7 +129,7 @@ def reload_(jboss_config, host=None): if host is None: operation = ":reload" else: - operation = '/host="{host}"/:reload'.format(host=host) + operation = f'/host="{host}"/:reload' reload_result = __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False ) @@ -195,7 +194,7 @@ def create_datasource(jboss_config, name, datasource_properties, profile=None): ), ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False @@ -214,7 +213,7 @@ def __get_properties_assignment_string(datasource_properties, ds_resource_descri def __get_single_assignment_string(key, val, ds_attributes): - return "{}={}".format(key, __format_value(key, val, ds_attributes)) + return f"{key}={__format_value(key, val, ds_attributes)}" def __format_value(key, value, ds_attributes): @@ -228,18 +227,14 @@ def __format_value(key, value, ds_attributes): else: return "false" else: - raise Exception( - "Don't know how to convert {} to BOOLEAN type".format(value) - ) + raise Exception(f"Don't know how to convert {value} to BOOLEAN type") elif type_ == "INT": return str(value) elif type_ == "STRING": - return '"{}"'.format(value) + return f'"{value}"' else: - raise Exception( - "Don't know how to format value {} of type {}".format(value, type_) - ) + raise Exception(f"Don't know how to format value {value} of type {type_}") def update_datasource(jboss_config, name, new_properties, profile=None): @@ -316,7 +311,7 @@ def __get_datasource_resource_description(jboss_config, name, profile=None): ) ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation operation_result = __salt__["jboss7_cli.run_operation"](jboss_config, operation) if operation_result["outcome"]: return operation_result["result"] @@ -382,7 +377,7 @@ def create_simple_binding(jboss_config, binding_name, value, profile=None): ) ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -419,7 +414,7 @@ def update_simple_binding(jboss_config, binding_name, value, profile=None): ) ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -453,7 +448,7 @@ def __read_simple_binding(jboss_config, binding_name, profile=None): binding_name=binding_name ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -475,7 +470,7 @@ def __update_datasource_property( value=__format_value(name, value, ds_attributes), ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False @@ -488,7 +483,7 @@ def __read_datasource(jboss_config, name, profile=None): name=name ) if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation operation_result = __salt__["jboss7_cli.run_operation"](jboss_config, operation) @@ -525,9 +520,9 @@ def remove_datasource(jboss_config, name, profile=None): profile, ) - operation = "/subsystem=datasources/data-source={name}:remove".format(name=name) + operation = f"/subsystem=datasources/data-source={name}:remove" if profile is not None: - operation = '/profile="{profile}"'.format(profile=profile) + operation + operation = f'/profile="{profile}"' + operation return __salt__["jboss7_cli.run_operation"]( jboss_config, operation, fail_on_error=False @@ -553,7 +548,7 @@ def deploy(jboss_config, source_file): "======================== MODULE FUNCTION: jboss7.deploy, source_file=%s", source_file, ) - command = "deploy {source_file} --force ".format(source_file=source_file) + command = f"deploy {source_file} --force " return __salt__["jboss7_cli.run_command"]( jboss_config, command, fail_on_error=False ) @@ -601,5 +596,5 @@ def undeploy(jboss_config, deployment): "======================== MODULE FUNCTION: jboss7.undeploy, deployment=%s", deployment, ) - command = "undeploy {deployment} ".format(deployment=deployment) + command = f"undeploy {deployment} " return __salt__["jboss7_cli.run_command"](jboss_config, command) diff --git a/salt/modules/jboss7_cli.py b/salt/modules/jboss7_cli.py index 683b61662e8..bd0d7111e8e 100644 --- a/salt/modules/jboss7_cli.py +++ b/salt/modules/jboss7_cli.py @@ -35,7 +35,6 @@ Example: """ - import logging import pprint import re @@ -159,7 +158,7 @@ def _call_cli(jboss_config, command, retries=1): command_segments.append('--user="{}"'.format(jboss_config["cli_user"])) if "cli_password" in jboss_config.keys(): command_segments.append('--password="{}"'.format(jboss_config["cli_password"])) - command_segments.append('--command="{}"'.format(__escape_command(command))) + command_segments.append(f'--command="{__escape_command(command)}"') cli_script = " ".join(command_segments) cli_command_result = __salt__["cmd.run_all"](cli_script) @@ -337,7 +336,7 @@ def __process_tokens_internal(tokens, start_at=0): log.debug(" TYPE: EXPRESSION") is_expression = True else: - raise CommandExecutionError("Unknown token! Token: {}".format(token)) + raise CommandExecutionError(f"Unknown token! Token: {token}") token_no = token_no + 1 diff --git a/salt/modules/jenkinsmod.py b/salt/modules/jenkinsmod.py index d87c13c3049..3d504d9f5c8 100644 --- a/salt/modules/jenkinsmod.py +++ b/salt/modules/jenkinsmod.py @@ -22,7 +22,6 @@ Module for controlling Jenkins api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15 """ - import logging import salt.utils.files @@ -109,7 +108,7 @@ def _retrieve_config_xml(config_xml, saltenv): ret = __salt__["cp.cache_file"](config_xml, saltenv) if not ret: - raise CommandExecutionError("Failed to retrieve {}".format(config_xml)) + raise CommandExecutionError(f"Failed to retrieve {config_xml}") return ret @@ -220,7 +219,7 @@ def get_job_info(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") job_info = server.get_job_info(name) if job_info: @@ -249,14 +248,12 @@ def build_job(name=None, parameters=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist.".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist.") try: server.build_job(name, parameters) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error building job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error building job '{name}': {err}") return True @@ -282,7 +279,7 @@ def create_job(name=None, config_xml=None, saltenv="base"): raise SaltInvocationError("Required parameter 'name' is missing") if job_exists(name): - raise CommandExecutionError("Job '{}' already exists".format(name)) + raise CommandExecutionError(f"Job '{name}' already exists") if not config_xml: config_xml = jenkins.EMPTY_CONFIG_XML @@ -296,9 +293,7 @@ def create_job(name=None, config_xml=None, saltenv="base"): try: server.create_job(name, config_xml) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error creating job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error creating job '{name}': {err}") return config_xml @@ -335,9 +330,7 @@ def update_job(name=None, config_xml=None, saltenv="base"): try: server.reconfig_job(name, config_xml) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error updating job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error updating job '{name}': {err}") return config_xml @@ -361,14 +354,12 @@ def delete_job(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") try: server.delete_job(name) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error deleting job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error deleting job '{name}': {err}") return True @@ -392,14 +383,12 @@ def enable_job(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") try: server.enable_job(name) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error enabling job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error enabling job '{name}': {err}") return True @@ -424,14 +413,12 @@ def disable_job(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") try: server.disable_job(name) except jenkins.JenkinsException as err: - raise CommandExecutionError( - "Encountered error disabling job '{}': {}".format(name, err) - ) + raise CommandExecutionError(f"Encountered error disabling job '{name}': {err}") return True @@ -456,7 +443,7 @@ def job_status(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") return server.get_job_info("empty")["buildable"] @@ -482,7 +469,7 @@ def get_job_config(name=None): server = _connect() if not job_exists(name): - raise CommandExecutionError("Job '{}' does not exist".format(name)) + raise CommandExecutionError(f"Job '{name}' does not exist") job_info = server.get_job_config(name) return job_info diff --git a/salt/modules/junos.py b/salt/modules/junos.py index 01bcbbaa167..385aee4fac4 100644 --- a/salt/modules/junos.py +++ b/salt/modules/junos.py @@ -479,10 +479,10 @@ def set_hostname(hostname=None, **kwargs): ret["out"] = True except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Successfully loaded host-name but commit failed with "{}"'.format( - exception + ret["message"] = ( + 'Successfully loaded host-name but commit failed with "{}"'.format( + exception + ) ) _restart_connection() return ret @@ -493,10 +493,10 @@ def set_hostname(hostname=None, **kwargs): conn.cu.rollback() except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Successfully loaded host-name but rollback before exit failed "{}"'.format( - exception + ret["message"] = ( + 'Successfully loaded host-name but rollback before exit failed "{}"'.format( + exception + ) ) _restart_connection() @@ -579,10 +579,10 @@ def commit(**kwargs): ret["out"] = False except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Commit check succeeded but actual commit failed with "{}"'.format( - exception + ret["message"] = ( + 'Commit check succeeded but actual commit failed with "{}"'.format( + exception + ) ) _restart_connection() else: @@ -592,10 +592,10 @@ def commit(**kwargs): conn.cu.rollback() except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Pre-commit check failed, and exception during rollback "{}"'.format( - exception + ret["message"] = ( + 'Pre-commit check failed, and exception during rollback "{}"'.format( + exception + ) ) _restart_connection() @@ -708,10 +708,10 @@ def rollback(**kwargs): ret["out"] = True except Exception as exception: # pylint: disable=broad-except ret["out"] = False - ret[ - "message" - ] = 'Rollback successful but commit failed with error "{}"'.format( - exception + ret["message"] = ( + 'Rollback successful but commit failed with error "{}"'.format( + exception + ) ) _restart_connection() return ret @@ -1078,9 +1078,9 @@ def install_config(path=None, **kwargs): ret["out"] = True if path is None: - ret[ - "message" - ] = "Please provide the salt path where the configuration is present" + ret["message"] = ( + "Please provide the salt path where the configuration is present" + ) ret["out"] = False return ret @@ -1139,9 +1139,9 @@ def install_config(path=None, **kwargs): db_mode = op.pop("mode", "exclusive") if write_diff and db_mode in ["dynamic", "ephemeral"]: - ret[ - "message" - ] = "Write diff is not supported with dynamic/ephemeral configuration mode" + ret["message"] = ( + "Write diff is not supported with dynamic/ephemeral configuration mode" + ) ret["out"] = False return ret @@ -1153,9 +1153,9 @@ def install_config(path=None, **kwargs): try: cu.load(**op) except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = f'Could not load configuration due to : "{exception}"' + ret["message"] = ( + f'Could not load configuration due to : "{exception}"' + ) ret["format"] = op["format"] ret["out"] = False _restart_connection() @@ -1185,10 +1185,10 @@ def install_config(path=None, **kwargs): try: check = cu.commit_check() except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = 'Commit check threw the following exception: "{}"'.format( - exception + ret["message"] = ( + 'Commit check threw the following exception: "{}"'.format( + exception + ) ) ret["out"] = False _restart_connection() @@ -1199,10 +1199,10 @@ def install_config(path=None, **kwargs): cu.commit(**commit_params) ret["message"] = "Successfully loaded and committed!" except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = 'Commit check successful but commit failed with "{}"'.format( - exception + ret["message"] = ( + 'Commit check successful but commit failed with "{}"'.format( + exception + ) ) ret["out"] = False _restart_connection() @@ -1248,9 +1248,9 @@ def install_config(path=None, **kwargs): with salt.utils.files.fopen(write_diff, "w") as fp: fp.write(salt.utils.stringutils.to_str(config_diff)) except Exception as exception: # pylint: disable=broad-except - ret[ - "message" - ] = f"Could not write into diffs_file due to: '{exception}'" + ret["message"] = ( + f"Could not write into diffs_file due to: '{exception}'" + ) ret["out"] = False except ValueError as ex: @@ -1396,9 +1396,9 @@ def install_os(path=None, **kwargs): no_copy_ = op.get("no_copy", False) if path is None: - ret[ - "message" - ] = "Please provide the salt path where the junos image is present." + ret["message"] = ( + "Please provide the salt path where the junos image is present." + ) ret["out"] = False return ret @@ -1467,10 +1467,10 @@ def install_os(path=None, **kwargs): conn.sw.reboot(**reboot_kwargs) except Exception as exception: # pylint: disable=broad-except __proxy__["junos.reboot_clear"]() - ret[ - "message" - ] = 'Installation successful but reboot failed due to : "{}"'.format( - exception + ret["message"] = ( + 'Installation successful but reboot failed due to : "{}"'.format( + exception + ) ) ret["out"] = False _restart_connection() @@ -1666,9 +1666,9 @@ def load(path=None, **kwargs): ret["out"] = True if path is None: - ret[ - "message" - ] = "Please provide the salt path where the configuration is present" + ret["message"] = ( + "Please provide the salt path where the configuration is present" + ) ret["out"] = False return ret @@ -1862,10 +1862,10 @@ def get_table( ) globals().update(FactoryLoader().load(ret["table"])) except OSError as err: - ret[ - "message" - ] = "Uncaught exception during YAML Load - please report: {}".format( - str(err) + ret["message"] = ( + "Uncaught exception during YAML Load - please report: {}".format( + str(err) + ) ) ret["out"] = False return ret @@ -1873,18 +1873,18 @@ def get_table( data = globals()[table](conn) data.get(**get_kvargs) except KeyError as err: - ret[ - "message" - ] = "Uncaught exception during get API call - please report: {}".format( - str(err) + ret["message"] = ( + "Uncaught exception during get API call - please report: {}".format( + str(err) + ) ) ret["out"] = False return ret except ConnectClosedError: - ret[ - "message" - ] = "Got ConnectClosedError exception. Connection lost with {}".format( - conn + ret["message"] = ( + "Got ConnectClosedError exception. Connection lost with {}".format( + conn + ) ) ret["out"] = False _restart_connection() @@ -1914,10 +1914,10 @@ def get_table( ret["table"][table]["args"] = args ret["table"][table]["command"] = data.GET_CMD except ConnectClosedError: - ret[ - "message" - ] = "Got ConnectClosedError exception. Connection lost with {}".format( - str(conn) + ret["message"] = ( + "Got ConnectClosedError exception. Connection lost with {}".format( + str(conn) + ) ) ret["out"] = False _restart_connection() diff --git a/salt/modules/kapacitor.py b/salt/modules/kapacitor.py index f3a47267a71..3cd8ff2ce9a 100644 --- a/salt/modules/kapacitor.py +++ b/salt/modules/kapacitor.py @@ -61,7 +61,7 @@ def _get_url(): host = __salt__["config.option"]("kapacitor.host", "localhost") port = __salt__["config.option"]("kapacitor.port", 9092) - return "{}://{}:{}".format(protocol, host, port) + return f"{protocol}://{host}:{port}" def get_task(name): @@ -80,9 +80,9 @@ def get_task(name): url = _get_url() if version() < "0.13": - task_url = "{}/task?name={}".format(url, name) + task_url = f"{url}/task?name={name}" else: - task_url = "{}/kapacitor/v1/tasks/{}?skip-format=true".format(url, name) + task_url = f"{url}/kapacitor/v1/tasks/{name}?skip-format=true" response = salt.utils.http.query(task_url, status=True) @@ -173,28 +173,28 @@ def define_task( return False if version() < "0.13": - cmd = "kapacitor define -name {}".format(name) + cmd = f"kapacitor define -name {name}" else: - cmd = "kapacitor define {}".format(name) + cmd = f"kapacitor define {name}" if tick_script.startswith("salt://"): tick_script = __salt__["cp.cache_file"](tick_script, __env__) - cmd += " -tick {}".format(tick_script) + cmd += f" -tick {tick_script}" if task_type: - cmd += " -type {}".format(task_type) + cmd += f" -type {task_type}" if not dbrps: dbrps = [] if database and retention_policy: - dbrp = "{}.{}".format(database, retention_policy) + dbrp = f"{database}.{retention_policy}" dbrps.append(dbrp) if dbrps: for dbrp in dbrps: - cmd += " -dbrp {}".format(dbrp) + cmd += f" -dbrp {dbrp}" return _run_cmd(cmd) @@ -212,7 +212,7 @@ def delete_task(name): salt '*' kapacitor.delete_task cpu """ - return _run_cmd("kapacitor delete tasks {}".format(name)) + return _run_cmd(f"kapacitor delete tasks {name}") def enable_task(name): @@ -228,7 +228,7 @@ def enable_task(name): salt '*' kapacitor.enable_task cpu """ - return _run_cmd("kapacitor enable {}".format(name)) + return _run_cmd(f"kapacitor enable {name}") def disable_task(name): @@ -244,4 +244,4 @@ def disable_task(name): salt '*' kapacitor.disable_task cpu """ - return _run_cmd("kapacitor disable {}".format(name)) + return _run_cmd(f"kapacitor disable {name}") diff --git a/salt/modules/kerberos.py b/salt/modules/kerberos.py index ea898a22634..e452b53b4b3 100644 --- a/salt/modules/kerberos.py +++ b/salt/modules/kerberos.py @@ -19,7 +19,6 @@ authenticate as. auth_principal: kadmin/admin """ - import logging import salt.utils.path @@ -45,7 +44,7 @@ def __execute_kadmin(cmd): if __salt__["file.file_exists"](auth_keytab) and auth_principal: return __salt__["cmd.run_all"]( - 'kadmin -k -t {} -p {} -q "{}"'.format(auth_keytab, auth_principal, cmd) + f'kadmin -k -t {auth_keytab} -p {auth_principal} -q "{cmd}"' ) else: log.error("Unable to find kerberos keytab/principal") @@ -95,7 +94,7 @@ def get_principal(name): """ ret = {} - cmd = __execute_kadmin("get_principal {}".format(name)) + cmd = __execute_kadmin(f"get_principal {name}") if cmd["retcode"] != 0 or cmd["stderr"]: ret["comment"] = cmd["stderr"].splitlines()[-1] @@ -151,7 +150,7 @@ def get_policy(name): """ ret = {} - cmd = __execute_kadmin("get_policy {}".format(name)) + cmd = __execute_kadmin(f"get_policy {name}") if cmd["retcode"] != 0 or cmd["stderr"]: ret["comment"] = cmd["stderr"].splitlines()[-1] @@ -210,9 +209,9 @@ def create_principal(name, enctypes=None): krb_cmd = "addprinc -randkey" if enctypes: - krb_cmd += " -e {}".format(enctypes) + krb_cmd += f" -e {enctypes}" - krb_cmd += " {}".format(name) + krb_cmd += f" {name}" cmd = __execute_kadmin(krb_cmd) @@ -238,7 +237,7 @@ def delete_principal(name): """ ret = {} - cmd = __execute_kadmin("delprinc -force {}".format(name)) + cmd = __execute_kadmin(f"delprinc -force {name}") if cmd["retcode"] != 0 or cmd["stderr"]: ret["comment"] = cmd["stderr"].splitlines()[-1] @@ -261,12 +260,12 @@ def create_keytab(name, keytab, enctypes=None): """ ret = {} - krb_cmd = "ktadd -k {}".format(keytab) + krb_cmd = f"ktadd -k {keytab}" if enctypes: - krb_cmd += " -e {}".format(enctypes) + krb_cmd += f" -e {enctypes}" - krb_cmd += " {}".format(name) + krb_cmd += f" {name}" cmd = __execute_kadmin(krb_cmd) diff --git a/salt/modules/kernelpkg_linux_apt.py b/salt/modules/kernelpkg_linux_apt.py index fc8684d03fa..33cef3eaaa5 100644 --- a/salt/modules/kernelpkg_linux_apt.py +++ b/salt/modules/kernelpkg_linux_apt.py @@ -53,7 +53,7 @@ def list_installed(): salt '*' kernelpkg.list_installed """ - pkg_re = re.compile(r"^{}-[\d.-]+-{}$".format(_package_prefix(), _kernel_type())) + pkg_re = re.compile(rf"^{_package_prefix()}-[\d.-]+-{_kernel_type()}$") pkgs = __salt__["pkg.list_pkgs"](versions_as_list=True) if pkgs is None: pkgs = [] @@ -79,14 +79,12 @@ def latest_available(): salt '*' kernelpkg.latest_available """ - result = __salt__["pkg.latest_version"]( - "{}-{}".format(_package_prefix(), _kernel_type()) - ) + result = __salt__["pkg.latest_version"](f"{_package_prefix()}-{_kernel_type()}") if result == "": return latest_installed() version = re.match(r"^(\d+\.\d+\.\d+)\.(\d+)", result) - return "{}-{}-{}".format(version.group(1), version.group(2), _kernel_type()) + return f"{version.group(1)}-{version.group(2)}-{_kernel_type()}" def latest_installed(): @@ -152,9 +150,7 @@ def upgrade(reboot=False, at_time=None): chance to return, resulting in errors. A minimal delay (1 minute) is useful to ensure the result is delivered to the master. """ - result = __salt__["pkg.install"]( - name="{}-{}".format(_package_prefix(), latest_available()) - ) + result = __salt__["pkg.install"](name=f"{_package_prefix()}-{latest_available()}") _needs_reboot = needs_reboot() ret = { @@ -202,14 +198,12 @@ def remove(release): salt '*' kernelpkg.remove 4.4.0-70-generic """ if release not in list_installed(): - raise CommandExecutionError( - "Kernel release '{}' is not installed".format(release) - ) + raise CommandExecutionError(f"Kernel release '{release}' is not installed") if release == active(): raise CommandExecutionError("Active kernel cannot be removed") - target = "{}-{}".format(_package_prefix(), release) + target = f"{_package_prefix()}-{release}" log.info("Removing kernel package %s", target) __salt__["pkg.purge"](target) diff --git a/salt/modules/kernelpkg_linux_yum.py b/salt/modules/kernelpkg_linux_yum.py index a144a98811d..c37f8729174 100644 --- a/salt/modules/kernelpkg_linux_yum.py +++ b/salt/modules/kernelpkg_linux_yum.py @@ -199,14 +199,12 @@ def remove(release): salt '*' kernelpkg.remove 3.10.0-327.el7 """ if release not in list_installed(): - raise CommandExecutionError( - "Kernel release '{}' is not installed".format(release) - ) + raise CommandExecutionError(f"Kernel release '{release}' is not installed") if release == active(): raise CommandExecutionError("Active kernel cannot be removed") - target = "{}-{}".format(_package_name(), release) + target = f"{_package_name()}-{release}" log.info("Removing kernel package %s", target) old = __salt__["pkg.list_pkgs"]() diff --git a/salt/modules/keyboard.py b/salt/modules/keyboard.py index 85d3e3aca93..7c15246ea95 100644 --- a/salt/modules/keyboard.py +++ b/salt/modules/keyboard.py @@ -3,7 +3,6 @@ Module for managing keyboards on supported POSIX-like systems using systemd, or such as Redhat, Debian and Gentoo. """ - import logging import salt.utils.path @@ -64,19 +63,17 @@ def set_sys(layout): salt '*' keyboard.set_sys dvorak """ if salt.utils.path.which("localectl"): - __salt__["cmd.run"]("localectl set-keymap {}".format(layout)) + __salt__["cmd.run"](f"localectl set-keymap {layout}") elif "RedHat" in __grains__["os_family"]: __salt__["file.sed"]( - "/etc/sysconfig/keyboard", "^LAYOUT=.*", "LAYOUT={}".format(layout) + "/etc/sysconfig/keyboard", "^LAYOUT=.*", f"LAYOUT={layout}" ) elif "Debian" in __grains__["os_family"]: __salt__["file.sed"]( - "/etc/default/keyboard", "^XKBLAYOUT=.*", "XKBLAYOUT={}".format(layout) + "/etc/default/keyboard", "^XKBLAYOUT=.*", f"XKBLAYOUT={layout}" ) elif "Gentoo" in __grains__["os_family"]: - __salt__["file.sed"]( - "/etc/conf.d/keymaps", "^keymap=.*", "keymap={}".format(layout) - ) + __salt__["file.sed"]("/etc/conf.d/keymaps", "^keymap=.*", f"keymap={layout}") return layout @@ -105,6 +102,6 @@ def set_x(layout): salt '*' keyboard.set_x dvorak """ - cmd = "setxkbmap {}".format(layout) + cmd = f"setxkbmap {layout}" __salt__["cmd.run"](cmd) return layout diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index b39a8b0ae5b..898180b0c33 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -201,7 +201,7 @@ def ec2_credentials_create( tenant_id=None, tenant=None, profile=None, - **connection_args + **connection_args, ): """ Create EC2-compatible credentials for user per tenant @@ -262,7 +262,7 @@ def ec2_credentials_delete( if not user_id: return {"Error": "Could not resolve User ID"} kstone.ec2.delete(user_id, access_key) - return 'ec2 key "{}" deleted under user id "{}"'.format(access_key, user_id) + return f'ec2 key "{access_key}" deleted under user id "{user_id}"' def ec2_credentials_get( @@ -355,11 +355,13 @@ def endpoint_get(service, region=None, profile=None, interface=None, **connectio e = [ _f for _f in [ - e - if e["service_id"] == service_id - and (e["region"] == region if region else True) - and (e["interface"] == interface if interface else True) - else None + ( + e + if e["service_id"] == service_id + and (e["region"] == region if region else True) + and (e["interface"] == interface if interface else True) + else None + ) for e in endpoints.values() ] if _f @@ -408,7 +410,7 @@ def endpoint_create( profile=None, url=None, interface=None, - **connection_args + **connection_args, ): """ Create an endpoint for an Openstack service @@ -481,7 +483,7 @@ def role_create(name, profile=None, **connection_args): kstone = auth(profile, **connection_args) if "Error" not in role_get(name=name, profile=profile, **connection_args): - return {"Error": 'Role "{}" already exists'.format(name)} + return {"Error": f'Role "{name}" already exists'} kstone.roles.create(name) return role_get(name=name, profile=profile, **connection_args) @@ -511,9 +513,9 @@ def role_delete(role_id=None, name=None, profile=None, **connection_args): role = kstone.roles.get(role_id) kstone.roles.delete(role) - ret = "Role ID {} deleted".format(role_id) + ret = f"Role ID {role_id} deleted" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -601,7 +603,7 @@ def service_delete(service_id=None, name=None, profile=None, **connection_args): "id" ] kstone.services.delete(service_id) - return 'Keystone service ID "{}" deleted'.format(service_id) + return f'Keystone service ID "{service_id}" deleted' def service_get(service_id=None, name=None, profile=None, **connection_args): @@ -734,10 +736,10 @@ def tenant_delete(tenant_id=None, name=None, profile=None, **connection_args): if not tenant_id: return {"Error": "Unable to resolve tenant id"} getattr(kstone, _TENANTS, None).delete(tenant_id) - ret = "Tenant ID {} deleted".format(tenant_id) + ret = f"Tenant ID {tenant_id} deleted" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -896,7 +898,7 @@ def tenant_update( description=None, enabled=None, profile=None, - **connection_args + **connection_args, ): """ Update a tenant's information (keystone tenant-update) @@ -945,7 +947,7 @@ def project_update( description=None, enabled=None, profile=None, - **connection_args + **connection_args, ): """ Update a tenant's information (keystone project-update) @@ -988,7 +990,7 @@ def project_update( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) else: return False @@ -1063,7 +1065,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args): try: user = kstone.users.get(user_id) except keystoneclient.exceptions.NotFound: - msg = "Could not find user '{}'".format(user_id) + msg = f"Could not find user '{user_id}'" log.error(msg) return {"Error": msg} @@ -1089,7 +1091,7 @@ def user_create( profile=None, project_id=None, description=None, - **connection_args + **connection_args, ): """ Create a user (keystone user-create) @@ -1146,10 +1148,10 @@ def user_delete(user_id=None, name=None, profile=None, **connection_args): if not user_id: return {"Error": "Unable to resolve user id"} kstone.users.delete(user_id) - ret = "User ID {} deleted".format(user_id) + ret = f"User ID {user_id} deleted" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -1162,7 +1164,7 @@ def user_update( profile=None, project=None, description=None, - **connection_args + **connection_args, ): """ Update a user's information (keystone user-update) @@ -1228,7 +1230,7 @@ def user_update( if tenant_id: kstone.users.update_tenant(user_id, tenant_id) - ret = "Info updated for user ID {}".format(user_id) + ret = f"Info updated for user ID {user_id}" return ret @@ -1306,9 +1308,9 @@ def user_password_update( kstone.users.update(user=user_id, password=password) else: kstone.users.update_password(user=user_id, password=password) - ret = "Password updated for user ID {}".format(user_id) + ret = f"Password updated for user ID {user_id}" if name: - ret += " ({})".format(name) + ret += f" ({name})" return ret @@ -1322,7 +1324,7 @@ def user_role_add( profile=None, project_id=None, project_name=None, - **connection_args + **connection_args, ): """ Add role for user in tenant (keystone user-role-add) @@ -1393,7 +1395,7 @@ def user_role_remove( profile=None, project_id=None, project_name=None, - **connection_args + **connection_args, ): """ Remove role for user in tenant (keystone user-role-remove) @@ -1460,7 +1462,7 @@ def user_role_list( profile=None, project_id=None, project_name=None, - **connection_args + **connection_args, ): """ Return a list of available user_roles (keystone user-roles-list) diff --git a/salt/modules/keystoneng.py b/salt/modules/keystoneng.py index 77c5e7f8b01..9a4ea9a8b19 100644 --- a/salt/modules/keystoneng.py +++ b/salt/modules/keystoneng.py @@ -25,7 +25,6 @@ Example configuration identity_api_version: 3 """ - HAS_SHADE = False try: import shade @@ -69,7 +68,7 @@ def get_entity(ent_type, **kwargs): Attempt to query Keystone for more information about an entity """ try: - func = "keystoneng.{}_get".format(ent_type) + func = f"keystoneng.{ent_type}_get" ent = __salt__[func](**kwargs) except OpenStackCloudException as e: # NOTE(SamYaple): If this error was something other than Forbidden we diff --git a/salt/modules/keystore.py b/salt/modules/keystore.py index 449c78b9589..4dc0fdfc65e 100644 --- a/salt/modules/keystore.py +++ b/salt/modules/keystore.py @@ -2,7 +2,6 @@ Module to interact with keystores """ - import logging import os from datetime import datetime @@ -162,9 +161,7 @@ def add(name, keystore, passphrase, certificate, private_key=None): try: cert_string = __salt__["x509.get_pem_entry"](certificate) except SaltInvocationError: - raise SaltInvocationError( - "Invalid certificate file or string: {}".format(certificate) - ) + raise SaltInvocationError(f"Invalid certificate file or string: {certificate}") if private_key: # Accept PEM input format, but convert to DES for loading into new keystore diff --git a/salt/modules/kmod.py b/salt/modules/kmod.py index 108bc6cad82..997c25fc868 100644 --- a/salt/modules/kmod.py +++ b/salt/modules/kmod.py @@ -83,9 +83,7 @@ def _set_persistent_module(mod): return set() escape_mod = re.escape(mod) # If module is commented only uncomment it - if __salt__["file.search"]( - conf, "^#[\t ]*{}[\t ]*$".format(escape_mod), multiline=True - ): + if __salt__["file.search"](conf, f"^#[\t ]*{escape_mod}[\t ]*$", multiline=True): __salt__["file.uncomment"](conf, escape_mod) else: __salt__["file.append"](conf, mod) @@ -103,9 +101,9 @@ def _remove_persistent_module(mod, comment): return set() escape_mod = re.escape(mod) if comment: - __salt__["file.comment"](conf, "^[\t ]*{}[\t ]?".format(escape_mod)) + __salt__["file.comment"](conf, f"^[\t ]*{escape_mod}[\t ]?") else: - __salt__["file.sed"](conf, "^[\t ]*{}[\t ]?".format(escape_mod), "") + __salt__["file.sed"](conf, f"^[\t ]*{escape_mod}[\t ]?", "") return {mod_name} @@ -115,7 +113,7 @@ def _which(cmd): """ _cmd = salt.utils.path.which(cmd) if not _cmd: - raise CommandExecutionError("Command '{}' cannot be found".format(cmd)) + raise CommandExecutionError(f"Command '{cmd}' cannot be found") return _cmd diff --git a/salt/modules/launchctl_service.py b/salt/modules/launchctl_service.py index b30ce1320f4..65bc04aeb99 100644 --- a/salt/modules/launchctl_service.py +++ b/salt/modules/launchctl_service.py @@ -10,7 +10,6 @@ Module for the management of MacOS systems that use launchd/launchctl :depends: - plistlib Python module """ - import fnmatch import logging import os @@ -102,7 +101,7 @@ def _available_services(): except Exception: # pylint: disable=broad-except # If plistlib is unable to read the file we'll need to use # the system provided plutil program to do the conversion - cmd = '/usr/bin/plutil -convert xml1 -o - -- "{}"'.format(true_path) + cmd = f'/usr/bin/plutil -convert xml1 -o - -- "{true_path}"' plist_xml = __salt__["cmd.run_all"](cmd, python_shell=False)[ "stdout" ] @@ -174,9 +173,9 @@ def get_all(): def _get_launchctl_data(job_label, runas=None): if BEFORE_YOSEMITE: - cmd = "launchctl list -x {}".format(job_label) + cmd = f"launchctl list -x {job_label}" else: - cmd = "launchctl list {}".format(job_label) + cmd = f"launchctl list {job_label}" launchctl_data = __salt__["cmd.run_all"](cmd, python_shell=False, runas=runas) diff --git a/salt/modules/layman.py b/salt/modules/layman.py index 0b8474076b5..6b61c649208 100644 --- a/salt/modules/layman.py +++ b/salt/modules/layman.py @@ -48,7 +48,7 @@ def add(overlay): """ ret = list() old_overlays = list_local() - cmd = "layman --quietness=0 --add {}".format(overlay) + cmd = f"layman --quietness=0 --add {overlay}" add_attempt = __salt__["cmd.run_all"](cmd, python_shell=False, stdin="y") if add_attempt["retcode"] != 0: raise salt.exceptions.CommandExecutionError(add_attempt["stdout"]) @@ -82,7 +82,7 @@ def delete(overlay): """ ret = list() old_overlays = list_local() - cmd = "layman --quietness=0 --delete {}".format(overlay) + cmd = f"layman --quietness=0 --delete {overlay}" delete_attempt = __salt__["cmd.run_all"](cmd, python_shell=False) if delete_attempt["retcode"] != 0: raise salt.exceptions.CommandExecutionError(delete_attempt["stdout"]) @@ -114,7 +114,7 @@ def sync(overlay="ALL"): salt '*' layman.sync """ - cmd = "layman --quietness=0 --sync {}".format(overlay) + cmd = f"layman --quietness=0 --sync {overlay}" return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 diff --git a/salt/modules/ldap3.py b/salt/modules/ldap3.py index a065b306b6d..d7e0834d341 100644 --- a/salt/modules/ldap3.py +++ b/salt/modules/ldap3.py @@ -10,7 +10,6 @@ This is an alternative to the ``ldap`` interface provided by the :depends: - ``ldap`` Python module """ - import logging import salt.utils.data @@ -52,7 +51,7 @@ class LDAPError(Exception): def _convert_exception(e): """Convert an ldap backend exception to an LDAPError and raise it.""" - raise LDAPError("exception in ldap backend: {!r}".format(e), e) from e + raise LDAPError(f"exception in ldap backend: {e!r}", e) from e def _bind(l, bind=None): @@ -90,7 +89,7 @@ def _format_unicode_password(pwd): :returns: A unicode string """ - return '"{}"'.format(pwd).encode("utf-16-le") + return f'"{pwd}"'.encode("utf-16-le") class _connect_ctx: @@ -266,7 +265,7 @@ def connect(connect_spec=None): if backend_name not in available_backends: raise ValueError( "unsupported backend or required Python module" - + " unavailable: {}".format(backend_name) + + f" unavailable: {backend_name}" ) url = connect_spec.get("url", "ldapi:///") try: diff --git a/salt/modules/ldapmod.py b/salt/modules/ldapmod.py index 8b1e22d994e..f611e1e287a 100644 --- a/salt/modules/ldapmod.py +++ b/salt/modules/ldapmod.py @@ -39,7 +39,6 @@ Salt interface to LDAP commands badness may ensue - you have been warned. """ - import logging import time @@ -83,7 +82,7 @@ def _config(name, key=None, **kwargs): if name in kwargs: value = kwargs[name] else: - value = __salt__["config.option"]("ldap.{}".format(key)) + value = __salt__["config.option"](f"ldap.{key}") return salt.utils.data.decode(value, to_str=True) @@ -112,7 +111,7 @@ def search( dn=None, # pylint: disable=C0103 scope=None, attrs=None, - **kwargs + **kwargs, ): """ Run an arbitrary LDAP query and return the results. @@ -191,13 +190,13 @@ class _LDAPConnection: self.bindpw = bindpw if self.uri == "": - self.uri = "ldap://{}:{}".format(self.server, self.port) + self.uri = f"ldap://{self.server}:{self.port}" try: if no_verify: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) - self.ldap = ldap.initialize("{}".format(self.uri)) + self.ldap = ldap.initialize(f"{self.uri}") self.ldap.protocol_version = 3 # ldap.VERSION3 self.ldap.set_option(ldap.OPT_REFERRALS, 0) # Needed for AD diff --git a/salt/modules/libcloud_compute.py b/salt/modules/libcloud_compute.py index 73171caa553..038ebd3c58c 100644 --- a/salt/modules/libcloud_compute.py +++ b/salt/modules/libcloud_compute.py @@ -26,6 +26,7 @@ Clouds include Amazon EC2, Azure, Google GCE, VMware, OpenStack Nova :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 @@ -786,7 +787,7 @@ def _get_by_id(collection, id): if not matches: raise ValueError("Could not find a matching item") elif len(matches) > 1: - raise ValueError("The id matched {} items, not 1".format(len(matches))) + raise ValueError(f"The id matched {len(matches)} items, not 1") return matches[0] diff --git a/salt/modules/libcloud_dns.py b/salt/modules/libcloud_dns.py index 182b7fb7820..33779286112 100644 --- a/salt/modules/libcloud_dns.py +++ b/salt/modules/libcloud_dns.py @@ -24,6 +24,7 @@ Connection module for Apache Libcloud DNS management :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/libcloud_loadbalancer.py b/salt/modules/libcloud_loadbalancer.py index 08d768ef626..3fa4fd49467 100644 --- a/salt/modules/libcloud_loadbalancer.py +++ b/salt/modules/libcloud_loadbalancer.py @@ -26,6 +26,7 @@ Clouds include Amazon ELB, ALB, Google, Aliyun, CloudStack, Softlayer :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/libcloud_storage.py b/salt/modules/libcloud_storage.py index 7e055ab30e5..51fc04b5512 100644 --- a/salt/modules/libcloud_storage.py +++ b/salt/modules/libcloud_storage.py @@ -26,6 +26,7 @@ Clouds include Amazon S3, Google Storage, Aliyun, Azure Blobs, Ceph, OpenStack s :depends: apache-libcloud """ + # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 diff --git a/salt/modules/linux_acl.py b/salt/modules/linux_acl.py index e1fcf4a9c8f..ae121e9c1b7 100644 --- a/salt/modules/linux_acl.py +++ b/salt/modules/linux_acl.py @@ -69,7 +69,7 @@ def getfacl(*args, **kwargs): if recursive: cmd += " -R" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() dentry = "" for line in out: @@ -186,7 +186,7 @@ def wipefacls(*args, **kwargs): if recursive: cmd += " -R" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' __salt__["cmd.run"](cmd, python_shell=False) return True @@ -233,10 +233,10 @@ def modfacl(acl_type, acl_name="", perms="", *args, **kwargs): cmd += " -m" - cmd = "{} {}:{}:{}".format(cmd, _acl_prefix(acl_type), acl_name, perms) + cmd = f"{cmd} {_acl_prefix(acl_type)}:{acl_name}:{perms}" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' __salt__["cmd.run"](cmd, python_shell=False, raise_err=raise_err) return True @@ -265,9 +265,9 @@ def delfacl(acl_type, acl_name="", *args, **kwargs): cmd += " -x" - cmd = "{} {}:{}".format(cmd, _acl_prefix(acl_type), acl_name) + cmd = f"{cmd} {_acl_prefix(acl_type)}:{acl_name}" for dentry in args: - cmd += ' "{}"'.format(dentry) + cmd += f' "{dentry}"' __salt__["cmd.run"](cmd, python_shell=False) return True diff --git a/salt/modules/linux_ip.py b/salt/modules/linux_ip.py index 01cc0e285d5..a7f6e960da9 100644 --- a/salt/modules/linux_ip.py +++ b/salt/modules/linux_ip.py @@ -45,7 +45,7 @@ def down(iface, iface_type=None): """ # Slave devices are controlled by the master. if iface_type not in ["slave"]: - return __salt__["cmd.run"]("ip link set {} down".format(iface)) + return __salt__["cmd.run"](f"ip link set {iface} down") return None @@ -92,7 +92,7 @@ def _ip_ifaces(): at_ = comps[0] if len(comps) % 2 != 0: last = comps.pop() - comps[-1] += " {}".format(last) + comps[-1] += f" {last}" ifi = iter(comps) ret[if_][at_] = dict(list(zip(ifi, ifi))) else: @@ -114,7 +114,7 @@ def up(iface, iface_type=None): """ # Slave devices are controlled by the master. if iface_type not in ["slave"]: - return __salt__["cmd.run"]("ip link set {} up".format(iface)) + return __salt__["cmd.run"](f"ip link set {iface} up") return None diff --git a/salt/modules/linux_lvm.py b/salt/modules/linux_lvm.py index 03803497aa6..d53caa0e073 100644 --- a/salt/modules/linux_lvm.py +++ b/salt/modules/linux_lvm.py @@ -245,11 +245,11 @@ def pvcreate(devices, override=True, force=True, **kwargs): for device in devices: if not os.path.exists(device): - return "{} does not exist".format(device) + return f"{device} does not exist" if not pvdisplay(device, quiet=True): cmd.append(device) elif not override: - return 'Device "{}" is already an LVM physical volume.'.format(device) + return f'Device "{device}" is already an LVM physical volume.' if not cmd[2:]: # All specified devices are already LVM volumes @@ -270,9 +270,9 @@ def pvcreate(devices, override=True, force=True, **kwargs): no_parameter = "norestorefile" for var in kwargs: if kwargs[var] and var in valid: - cmd.extend(["--{}".format(var), kwargs[var]]) + cmd.extend([f"--{var}", kwargs[var]]) elif kwargs[var] and var in no_parameter: - cmd.append("--{}".format(var)) + cmd.append(f"--{var}") out = __salt__["cmd.run_all"](cmd, python_shell=False) if out.get("retcode"): @@ -281,7 +281,7 @@ def pvcreate(devices, override=True, force=True, **kwargs): # Verify pvcreate was successful for device in devices: if not pvdisplay(device): - return 'Device "{}" was not affected.'.format(device) + return f'Device "{device}" was not affected.' return True @@ -313,7 +313,7 @@ def pvremove(devices, override=True, force=True): if pvdisplay(device): cmd.append(device) elif not override: - return "{} is not a physical volume".format(device) + return f"{device} is not a physical volume" if not cmd[2:]: # Nothing to do @@ -326,7 +326,7 @@ def pvremove(devices, override=True, force=True): # Verify pvremove was successful for device in devices: if pvdisplay(device, quiet=True): - return 'Device "{}" was not affected.'.format(device) + return f'Device "{device}" was not affected.' return True @@ -371,14 +371,14 @@ def vgcreate(vgname, devices, force=False, **kwargs): ) for var in kwargs: if kwargs[var] and var in valid: - cmd.append("--{}".format(var)) + cmd.append(f"--{var}") cmd.append(kwargs[var]) cmd_ret = __salt__["cmd.run_all"](cmd, python_shell=False) if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Volume group "{}" successfully created'.format(vgname) + out = f'Volume group "{vgname}" successfully created' vgdata = vgdisplay(vgname) vgdata["Output from vgcreate"] = out @@ -415,7 +415,7 @@ def vgextend(vgname, devices, force=False): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Volume group "{}" successfully extended'.format(vgname) + out = f'Volume group "{vgname}" successfully extended' vgdata = {"Output from vgextend": out} return vgdata @@ -431,7 +431,7 @@ def lvcreate( thinvolume=False, thinpool=False, force=False, - **kwargs + **kwargs, ): """ Create a new logical volume, with option for which physical volume to be used @@ -494,9 +494,9 @@ def lvcreate( if kwargs: for k, v in kwargs.items(): if k in no_parameter: - extra_arguments.append("--{}".format(k)) + extra_arguments.append(f"--{k}") elif k in valid: - extra_arguments.extend(["--{}".format(k), "{}".format(v)]) + extra_arguments.extend([f"--{k}", f"{v}"]) cmd = [salt.utils.path.which("lvcreate")] @@ -508,18 +508,18 @@ def lvcreate( cmd.extend(["-n", lvname]) if snapshot: - cmd.extend(["-s", "{}/{}".format(vgname, snapshot)]) + cmd.extend(["-s", f"{vgname}/{snapshot}"]) else: cmd.append(vgname) if size and thinvolume: - cmd.extend(["-V", "{}".format(size)]) + cmd.extend(["-V", f"{size}"]) elif extents and thinvolume: return "Error: Thin volume size cannot be specified as extents" elif size: - cmd.extend(["-L", "{}".format(size)]) + cmd.extend(["-L", f"{size}"]) elif extents: - cmd.extend(["-l", "{}".format(extents)]) + cmd.extend(["-l", f"{extents}"]) else: return "Error: Either size or extents must be specified" @@ -537,9 +537,9 @@ def lvcreate( if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" created.'.format(lvname) + out = f'Logical volume "{lvname}" created.' - lvdev = "/dev/{}/{}".format(vgname, lvname) + lvdev = f"/dev/{vgname}/{lvname}" lvdata = lvdisplay(lvdev) lvdata["Output from lvcreate"] = out return lvdata @@ -567,7 +567,7 @@ def vgremove(vgname, force=True): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Volume group "{}" successfully removed'.format(vgname) + out = f'Volume group "{vgname}" successfully removed' return out @@ -581,7 +581,7 @@ def lvremove(lvname, vgname, force=True): salt '*' lvm.lvremove lvname vgname force=True """ - cmd = ["lvremove", "{}/{}".format(vgname, lvname)] + cmd = ["lvremove", f"{vgname}/{lvname}"] if force: cmd.append("--yes") @@ -592,7 +592,7 @@ def lvremove(lvname, vgname, force=True): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" successfully removed'.format(lvname) + out = f'Logical volume "{lvname}" successfully removed' return out @@ -625,9 +625,9 @@ def lvresize(size=None, lvpath=None, extents=None, force=False, resizefs=False): cmd.append("--resizefs") if size: - cmd.extend(["-L", "{}".format(size)]) + cmd.extend(["-L", f"{size}"]) elif extents: - cmd.extend(["-l", "{}".format(extents)]) + cmd.extend(["-l", f"{extents}"]) else: log.error("Error: Either size or extents must be specified") return {} @@ -638,7 +638,7 @@ def lvresize(size=None, lvpath=None, extents=None, force=False, resizefs=False): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" successfully resized.'.format(lvpath) + out = f'Logical volume "{lvpath}" successfully resized.' return {"Output from lvresize": out} @@ -671,9 +671,9 @@ def lvextend(size=None, lvpath=None, extents=None, force=False, resizefs=False): cmd.append("--resizefs") if size: - cmd.extend(["-L", "{}".format(size)]) + cmd.extend(["-L", f"{size}"]) elif extents: - cmd.extend(["-l", "{}".format(extents)]) + cmd.extend(["-l", f"{extents}"]) else: log.error("Error: Either size or extents must be specified") return {} @@ -684,7 +684,7 @@ def lvextend(size=None, lvpath=None, extents=None, force=False, resizefs=False): if cmd_ret.get("retcode"): out = cmd_ret.get("stderr").strip() else: - out = 'Logical volume "{}" successfully extended.'.format(lvpath) + out = f'Logical volume "{lvpath}" successfully extended.' return {"Output from lvextend": out} @@ -716,7 +716,7 @@ def pvresize(devices, override=True, force=True): if pvdisplay(device): cmd.append(device) elif not override: - return "{} is not a physical volume".format(device) + return f"{device} is not a physical volume" if not cmd[2:]: # Nothing to do diff --git a/salt/modules/linux_service.py b/salt/modules/linux_service.py index d26fc5a9799..4289fc6003f 100644 --- a/salt/modules/linux_service.py +++ b/salt/modules/linux_service.py @@ -43,7 +43,7 @@ def __virtual__(): return (False, "Non Linux OSes are not supported") init_grain = __grains__.get("init") if init_grain not in (None, "sysvinit", "unknown"): - return (False, "Minion is running {}".format(init_grain)) + return (False, f"Minion is running {init_grain}") elif __utils__["systemd.booted"](__context__): # Should have been caught by init grain check, but check just in case return (False, "Minion is running systemd") diff --git a/salt/modules/linux_shadow.py b/salt/modules/linux_shadow.py index aa149ac4c8e..09fe73fdb54 100644 --- a/salt/modules/linux_shadow.py +++ b/salt/modules/linux_shadow.py @@ -368,7 +368,7 @@ def set_password(name, password, use_usermod=False, root=None): # ALT Linux uses tcb to store password hashes. More information found # in manpage (http://docs.altlinux.org/manpages/tcb.5.html) if __grains__["os"] == "ALT": - s_file = "/etc/tcb/{}/shadow".format(name) + s_file = f"/etc/tcb/{name}/shadow" else: s_file = "/etc/shadow" if root: diff --git a/salt/modules/linux_sysctl.py b/salt/modules/linux_sysctl.py index fe63cb6c596..3cb77e36017 100644 --- a/salt/modules/linux_sysctl.py +++ b/salt/modules/linux_sysctl.py @@ -41,7 +41,7 @@ def _which(cmd): """ _cmd = salt.utils.path.which(cmd) if not _cmd: - raise CommandExecutionError("Command '{}' cannot be found".format(cmd)) + raise CommandExecutionError(f"Command '{cmd}' cannot be found") return _cmd @@ -137,13 +137,13 @@ def assign(name, value): tran_tab = name.translate("".maketrans("./", "/.")) - sysctl_file = "/proc/sys/{}".format(tran_tab) + sysctl_file = f"/proc/sys/{tran_tab}" if not os.path.exists(sysctl_file): - raise CommandExecutionError("sysctl {} does not exist".format(name)) + raise CommandExecutionError(f"sysctl {name} does not exist") ret = {} _sysctl = "{}".format(_which("sysctl")) - cmd = [_sysctl, "-w", "{}={}".format(name, value)] + cmd = [_sysctl, "-w", f"{name}={value}"] data = __salt__["cmd.run_all"](cmd, python_shell=False) out = data["stdout"] err = data["stderr"] @@ -151,14 +151,14 @@ def assign(name, value): # Example: # # sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216" # net.ipv4.tcp_rmem = 4096 87380 16777216 - regex = re.compile(r"^{}\s+=\s+{}$".format(re.escape(name), re.escape(value))) + regex = re.compile(rf"^{re.escape(name)}\s+=\s+{re.escape(value)}$") if not regex.match(out) or "Invalid argument" in str(err): if data["retcode"] != 0 and err: error = err else: error = out - raise CommandExecutionError("sysctl -w failed: {}".format(error)) + raise CommandExecutionError(f"sysctl -w failed: {error}") new_name, new_value = out.split(" = ", 1) ret[new_name] = new_value return ret @@ -238,13 +238,13 @@ def persist(name, value, config=None): else: return "Already set" - nlines.append("{} = {}\n".format(name, value)) + nlines.append(f"{name} = {value}\n") edited = True continue else: nlines.append(line) if not edited: - nlines.append("{} = {}\n".format(name, value)) + nlines.append(f"{name} = {value}\n") try: with salt.utils.files.fopen(config, "wb") as _fh: _fh.writelines(salt.utils.data.encode(nlines)) diff --git a/salt/modules/localemod.py b/salt/modules/localemod.py index 8744535d1a1..e8cd9063ca3 100644 --- a/salt/modules/localemod.py +++ b/salt/modules/localemod.py @@ -109,11 +109,9 @@ def _localectl_set(locale=""): else _localectl_status().get("system_locale", {}) ) locale_params["LANG"] = str(locale) - args = " ".join( - ['{}="{}"'.format(k, v) for k, v in locale_params.items() if v is not None] - ) + args = " ".join([f'{k}="{v}"' for k, v in locale_params.items() if v is not None]) return not __salt__["cmd.retcode"]( - "localectl set-locale {}".format(args), python_shell=False + f"localectl set-locale {args}", python_shell=False ) @@ -204,7 +202,7 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/sysconfig/language", "^RC_LANG=.*", - 'RC_LANG="{}"'.format(locale), + f'RC_LANG="{locale}"', append_if_not_found=True, ) elif "RedHat" in __grains__["os_family"]: @@ -213,7 +211,7 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/sysconfig/i18n", "^LANG=.*", - 'LANG="{}"'.format(locale), + f'LANG="{locale}"', append_if_not_found=True, ) elif "Debian" in __grains__["os_family"]: @@ -227,11 +225,11 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/default/locale", "^LANG=.*", - 'LANG="{}"'.format(locale), + f'LANG="{locale}"', append_if_not_found=True, ) elif "Gentoo" in __grains__["os_family"]: - cmd = "eselect --brief locale set {}".format(locale) + cmd = f"eselect --brief locale set {locale}" return __salt__["cmd.retcode"](cmd, python_shell=False) == 0 elif "Solaris" in __grains__["os_family"]: if locale not in __salt__["locale.list_avail"](): @@ -239,7 +237,7 @@ def set_locale(locale): __salt__["file.replace"]( "/etc/default/init", "^LANG=.*", - 'LANG="{}"'.format(locale), + f'LANG="{locale}"', append_if_not_found=True, ) else: @@ -319,9 +317,7 @@ def gen_locale(locale, **kwargs): if on_debian or on_gentoo: # file-based search search = "/usr/share/i18n/SUPPORTED" - valid = __salt__["file.search"]( - search, "^{}$".format(locale), flags=re.MULTILINE - ) + valid = __salt__["file.search"](search, f"^{locale}$", flags=re.MULTILINE) else: # directory-based search if on_suse: search = "/usr/share/locale" @@ -332,7 +328,7 @@ def gen_locale(locale, **kwargs): valid = locale_search_str in os.listdir(search) except OSError as ex: log.error(ex) - raise CommandExecutionError('Locale "{}" is not available.'.format(locale)) + raise CommandExecutionError(f'Locale "{locale}" is not available.') if not valid: log.error('The provided locale "%s" is not found in %s', locale, search) @@ -341,8 +337,8 @@ def gen_locale(locale, **kwargs): if os.path.exists("/etc/locale.gen"): __salt__["file.replace"]( "/etc/locale.gen", - r"^\s*#\s*{}\s*$".format(locale), - "{}\n".format(locale), + rf"^\s*#\s*{locale}\s*$", + f"{locale}\n", append_if_not_found=True, ) elif on_ubuntu: diff --git a/salt/modules/locate.py b/salt/modules/locate.py index fd4f2e3878c..aa8e1a2473c 100644 --- a/salt/modules/locate.py +++ b/salt/modules/locate.py @@ -111,13 +111,13 @@ def locate(pattern, database="", limit=0, **kwargs): if bool(kwargs[option]) is True and option in toggles: options += toggles[option] if options: - options = "-{}".format(options) + options = f"-{options}" if database: - options += " -d {}".format(database) + options += f" -d {database}" if limit > 0: - options += " -l {}".format(limit) + options += f" -l {limit}" if "regex" in kwargs and bool(kwargs["regex"]) is True: options += " --regex" - cmd = "locate {} {}".format(options, pattern) + cmd = f"locate {options} {pattern}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() return out diff --git a/salt/modules/logadm.py b/salt/modules/logadm.py index 677e12f705b..9f50803ba40 100644 --- a/salt/modules/logadm.py +++ b/salt/modules/logadm.py @@ -119,7 +119,7 @@ def _parse_options(entry, options, include_unset=True): if "additional_options" not in log_cfg: log_cfg["additional_options"] = [] if " " in options[index]: - log_cfg["dditional_options"] = "'{}'".format(options[index]) + log_cfg["dditional_options"] = f"'{options[index]}'" else: log_cfg["additional_options"].append(options[index]) @@ -172,7 +172,7 @@ def show_conf(conf_file=default_conf, name=None): if name and name in cfg: return {name: cfg[name]} elif name: - return {name: "not found in {}".format(conf_file)} + return {name: f"not found in {conf_file}"} else: return cfg @@ -212,7 +212,7 @@ def list_conf(conf_file=default_conf, log_file=None, include_unset=False): if log_file and log_file in cfg_parsed: return {log_file: cfg_parsed[log_file]} elif log_file: - return {log_file: "not found in {}".format(conf_file)} + return {log_file: f"not found in {conf_file}"} else: return cfg_parsed @@ -286,7 +286,7 @@ def rotate(name, pattern=None, conf_file=default_conf, **kwargs): ## build command log.debug("logadm.rotate - kwargs: %s", kwargs) - command = "logadm -f {}".format(conf_file) + command = f"logadm -f {conf_file}" for arg, val in kwargs.items(): if arg in option_toggles.values() and val: command = "{} {}".format( @@ -294,7 +294,7 @@ def rotate(name, pattern=None, conf_file=default_conf, **kwargs): _arg2opt(arg), ) elif arg in option_flags.values(): - command = "{} {} {}".format(command, _arg2opt(arg), shlex.quote(str(val))) + command = f"{command} {_arg2opt(arg)} {shlex.quote(str(val))}" elif arg != "log_file": log.warning("Unknown argument %s, don't know how to map this!", arg) if "log_file" in kwargs: @@ -329,7 +329,7 @@ def remove(name, conf_file=default_conf): salt '*' logadm.remove myapplog """ - command = "logadm -f {} -r {}".format(conf_file, name) + command = f"logadm -f {conf_file} -r {name}" result = __salt__["cmd.run_all"](command, python_shell=False) if result["retcode"] != 0: return dict( diff --git a/salt/modules/logrotate.py b/salt/modules/logrotate.py index 314fc607cfc..2e29876da81 100644 --- a/salt/modules/logrotate.py +++ b/salt/modules/logrotate.py @@ -211,7 +211,7 @@ def set_(key, value, setting=None, conf_file=_DEFAULT_CONF): "flags": 8, "backup": False, "path": conf_file, - "pattern": "^{}.*".format(key), + "pattern": f"^{key}.*", "show_changes": False, } @@ -232,7 +232,7 @@ def set_(key, value, setting=None, conf_file=_DEFAULT_CONF): if value is True: new_line = key elif value: - new_line = "{} {}".format(key, value) + new_line = f"{key} {value}" kwargs.update({"prepend_if_not_found": True}) else: @@ -259,7 +259,7 @@ def set_(key, value, setting=None, conf_file=_DEFAULT_CONF): kwargs.update( { - "pattern": "^{0}.*?{{.*?}}".format(key), + "pattern": f"^{key}.*?{{.*?}}", "flags": 24, "append_if_not_found": True, } @@ -279,5 +279,5 @@ def _dict_to_stanza(key, stanza): for skey in stanza: if stanza[skey] is True: stanza[skey] = "" - ret += " {} {}\n".format(skey, stanza[skey]) - return "{0} {{\n{1}}}".format(key, ret) + ret += f" {skey} {stanza[skey]}\n" + return f"{key} {{\n{ret}}}" diff --git a/salt/modules/lvs.py b/salt/modules/lvs.py index a5f2aec02ae..212a5c6f0fc 100644 --- a/salt/modules/lvs.py +++ b/salt/modules/lvs.py @@ -192,7 +192,7 @@ def add_server( server_address=None, packet_forward_method="dr", weight=1, - **kwargs + **kwargs, ): """ @@ -228,7 +228,7 @@ def add_server( server_address=server_address, packet_forward_method=packet_forward_method, weight=weight, - **kwargs + **kwargs, ), ) out = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -247,7 +247,7 @@ def edit_server( server_address=None, packet_forward_method=None, weight=None, - **kwargs + **kwargs, ): """ @@ -283,7 +283,7 @@ def edit_server( server_address=server_address, packet_forward_method=packet_forward_method, weight=weight, - **kwargs + **kwargs, ), ) out = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -347,7 +347,7 @@ def clear(): salt '*' lvs.clear """ - cmd = "{} -C".format(__detect_os()) + cmd = f"{__detect_os()} -C" out = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -371,7 +371,7 @@ def get_rules(): salt '*' lvs.get_rules """ - cmd = "{} -S -n".format(__detect_os()) + cmd = f"{__detect_os()} -S -n" ret = __salt__["cmd.run"](cmd, python_shell=False) return ret @@ -395,7 +395,7 @@ def list_(protocol=None, service_address=None): _build_cmd(protocol=protocol, service_address=service_address), ) else: - cmd = "{} -L -n".format(__detect_os()) + cmd = f"{__detect_os()} -L -n" out = __salt__["cmd.run_all"](cmd, python_shell=False) # A non-zero return code means fail @@ -425,7 +425,7 @@ def zero(protocol=None, service_address=None): _build_cmd(protocol=protocol, service_address=service_address), ) else: - cmd = "{} -Z".format(__detect_os()) + cmd = f"{__detect_os()} -Z" out = __salt__["cmd.run_all"](cmd, python_shell=False) # A non-zero return code means fail @@ -482,7 +482,7 @@ def check_server(protocol=None, service_address=None, server_address=None, **kwa protocol=protocol, service_address=service_address, server_address=server_address, - **kwargs + **kwargs, ) ) # Exact match diff --git a/salt/modules/lxc.py b/salt/modules/lxc.py index ba03d1f4180..a74077eacae 100644 --- a/salt/modules/lxc.py +++ b/salt/modules/lxc.py @@ -1666,9 +1666,9 @@ def init( ret["result"] = False else: if not result: - ret[ - "comment" - ] = "Bootstrap failed, see minion log for more information" + ret["comment"] = ( + "Bootstrap failed, see minion log for more information" + ) ret["result"] = False else: changes.append({"bootstrap": "Container successfully bootstrapped"}) @@ -3274,7 +3274,6 @@ def systemd_running_state(name, path=None): def test_sd_started_state(name, path=None): - """ Test if a systemd container is fully started diff --git a/salt/modules/lxd.py b/salt/modules/lxd.py index da87ca08f5a..dd0a9e49216 100644 --- a/salt/modules/lxd.py +++ b/salt/modules/lxd.py @@ -31,7 +31,6 @@ several functions to help manage it and its containers. :platform: Linux """ - import logging import os from datetime import datetime @@ -181,31 +180,31 @@ def init( salt '*' lxd.init """ - cmd = 'lxd init --auto --storage-backend="{}"'.format(storage_backend) + cmd = f'lxd init --auto --storage-backend="{storage_backend}"' if trust_password is not None: - cmd = cmd + ' --trust-password="{}"'.format(trust_password) + cmd = cmd + f' --trust-password="{trust_password}"' if network_address is not None: - cmd = cmd + ' --network-address="{}"'.format(network_address) + cmd = cmd + f' --network-address="{network_address}"' if network_port is not None: - cmd = cmd + ' --network-port="{}"'.format(network_port) + cmd = cmd + f' --network-port="{network_port}"' if storage_create_device is not None: - cmd = cmd + ' --storage-create-device="{}"'.format(storage_create_device) + cmd = cmd + f' --storage-create-device="{storage_create_device}"' if storage_create_loop is not None: - cmd = cmd + ' --storage-create-loop="{}"'.format(storage_create_loop) + cmd = cmd + f' --storage-create-loop="{storage_create_loop}"' if storage_pool is not None: - cmd = cmd + ' --storage-pool="{}"'.format(storage_pool) + cmd = cmd + f' --storage-pool="{storage_pool}"' try: output = __salt__["cmd.run"](cmd) except ValueError as e: raise CommandExecutionError( - "Failed to call: '{}', error was: {}".format(cmd, str(e)), + f"Failed to call: '{cmd}', error was: {str(e)}", ) if "error:" in output: @@ -249,7 +248,7 @@ def config_set(key, value): output[output.index("error:") + 7 :], ) - return ('Config value "{}" successfully set.'.format(key),) + return (f'Config value "{key}" successfully set.',) @salt.utils.decorators.path.which("lxd") @@ -268,7 +267,7 @@ def config_get(key): salt '*' lxd.config_get core.https_address """ - cmd = 'lxc config get "{}"'.format(key) + cmd = f'lxc config get "{key}"' output = __salt__["cmd.run"](cmd) if "error:" in output: @@ -375,7 +374,7 @@ def pylxd_client_get(remote_addr=None, cert=None, key=None, verify_cert=True): verify=verify_cert, ) except pylxd.exceptions.ClientConnectionFailed: - raise CommandExecutionError("Failed to connect to '{}'".format(remote_addr)) + raise CommandExecutionError(f"Failed to connect to '{remote_addr}'") except TypeError as e: # Happens when the verification failed. @@ -747,7 +746,7 @@ def container_get( try: containers = [client.containers.get(name)] except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Container '{}' not found".format(name)) + raise SaltInvocationError(f"Container '{name}' not found") if _raw: return containers[0] @@ -834,9 +833,7 @@ def container_rename( container = container_get(name, remote_addr, cert, key, verify_cert, _raw=True) if container.status_code == CONTAINER_STATUS_RUNNING: - raise SaltInvocationError( - "Can't rename the running container '{}'.".format(name) - ) + raise SaltInvocationError(f"Can't rename the running container '{name}'.") container.rename(newname, wait=True) return _pylxd_model_to_dict(container) @@ -879,7 +876,7 @@ def container_state(name=None, remote_addr=None, cert=None, key=None, verify_cer try: containers = [client.containers.get(name)] except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Container '{}' not found".format(name)) + raise SaltInvocationError(f"Container '{name}' not found") states = [] for container in containers: @@ -1387,7 +1384,7 @@ def container_device_add( cert=None, key=None, verify_cert=True, - **kwargs + **kwargs, ): """ Add a container device @@ -1567,7 +1564,7 @@ def container_file_put( # and integer, handle it as if it where a octal representation. mode = str(mode) if not mode.startswith("0"): - mode = "0{}".format(mode) + mode = f"0{mode}" container = container_get(name, remote_addr, cert, key, verify_cert, _raw=True) @@ -1577,7 +1574,7 @@ def container_file_put( if src.find("://") >= 0: cached_file = __salt__["cp.cache_file"](src, saltenv=saltenv) if not cached_file: - raise SaltInvocationError("File '{}' not found".format(src)) + raise SaltInvocationError(f"File '{src}' not found") if not os.path.isabs(cached_file): raise SaltInvocationError("File path must be absolute.") src = cached_file @@ -1588,7 +1585,7 @@ def container_file_put( src = os.path.sep if not os.path.exists(src): - raise CommandExecutionError("No such file or directory '{}'".format(src)) + raise CommandExecutionError(f"No such file or directory '{src}'") if os.path.isdir(src) and not recursive: raise SaltInvocationError( @@ -1771,7 +1768,7 @@ def container_file_get( if mode is not None: mode = str(mode) if not mode.startswith("0"): - mode = "0{}".format(mode) + mode = f"0{mode}" container = container_get(name, remote_addr, cert, key, verify_cert, _raw=True) @@ -1792,9 +1789,7 @@ def container_file_get( else: dst_path = os.path.dirname(dst) if not os.path.isdir(dst_path): - raise CommandExecutionError( - "No such file or directory '{}'".format(dst_path) - ) + raise CommandExecutionError(f"No such file or directory '{dst_path}'") # Seems to be duplicate of line 1794, produces /path/file_name/file_name # dst = os.path.join(dst, os.path.basename(src)) @@ -2075,7 +2070,7 @@ def profile_get( try: profile = client.profiles.get(name) except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Profile '{}' not found".format(name)) + raise SaltInvocationError(f"Profile '{name}' not found") if _raw: return profile @@ -2331,7 +2326,7 @@ def profile_device_set( cert=None, key=None, verify_cert=True, - **kwargs + **kwargs, ): """Set a profile device. @@ -2532,9 +2527,7 @@ def image_get( try: image = client.images.get(fingerprint) except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError( - "Image with fingerprint '{}' not found".format(fingerprint) - ) + raise SaltInvocationError(f"Image with fingerprint '{fingerprint}' not found") if _raw: return image @@ -2590,7 +2583,7 @@ def image_get_by_alias( try: image = client.images.get_by_alias(alias) except pylxd.exceptions.LXDAPIException: - raise SaltInvocationError("Image with alias '{}' not found".format(alias)) + raise SaltInvocationError(f"Image with alias '{alias}' not found") if _raw: return image @@ -3442,17 +3435,17 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): if newconfig[k] != obj.config[k]: if not test: - config_changes[ - k - ] = 'Changed config key "{}" to "{}", its value was "{}"'.format( - k, newconfig[k], obj.config[k] + config_changes[k] = ( + 'Changed config key "{}" to "{}", its value was "{}"'.format( + k, newconfig[k], obj.config[k] + ) ) obj.config[k] = newconfig[k] else: - config_changes[ - k - ] = 'Would change config key "{}" to "{}", its current value is "{}"'.format( - k, newconfig[k], obj.config[k] + config_changes[k] = ( + 'Would change config key "{}" to "{}", its current value is "{}"'.format( + k, newconfig[k], obj.config[k] + ) ) # New keys @@ -3462,7 +3455,7 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): continue if not test: - config_changes[k] = 'Added config key "{}" = "{}"'.format(k, newconfig[k]) + config_changes[k] = f'Added config key "{k}" = "{newconfig[k]}"' obj.config[k] = newconfig[k] else: config_changes[k] = 'Would add config key "{}" = "{}"'.format( @@ -3489,10 +3482,10 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): continue if not test: - devices_changes[k] = 'Removed device "{}"'.format(k) + devices_changes[k] = f'Removed device "{k}"' del obj.devices[k] else: - devices_changes[k] = 'Would remove device "{}"'.format(k) + devices_changes[k] = f'Would remove device "{k}"' # Changed devices for k, v in obj.devices.items(): @@ -3506,10 +3499,10 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): if newdevices[k] != v: if not test: - devices_changes[k] = 'Changed device "{}"'.format(k) + devices_changes[k] = f'Changed device "{k}"' obj.devices[k] = newdevices[k] else: - devices_changes[k] = 'Would change device "{}"'.format(k) + devices_changes[k] = f'Would change device "{k}"' # New devices for k in ndk.difference(dk): @@ -3518,10 +3511,10 @@ def sync_config_devices(obj, newconfig, newdevices, test=False): continue if not test: - devices_changes[k] = 'Added device "{}"'.format(k) + devices_changes[k] = f'Added device "{k}"' obj.devices[k] = newdevices[k] else: - devices_changes[k] = 'Would add device "{}"'.format(k) + devices_changes[k] = f'Would add device "{k}"' if devices_changes: changes["devices"] = devices_changes @@ -3567,7 +3560,7 @@ def _set_property_dict_item(obj, prop, key, value): def _get_property_dict_item(obj, prop, key): attr = getattr(obj, prop) if key not in attr: - raise SaltInvocationError("'{}' doesn't exists".format(key)) + raise SaltInvocationError(f"'{key}' doesn't exists") return attr[key] @@ -3575,7 +3568,7 @@ def _get_property_dict_item(obj, prop, key): def _delete_property_dict_item(obj, prop, key): attr = getattr(obj, prop) if key not in attr: - raise SaltInvocationError("'{}' doesn't exists".format(key)) + raise SaltInvocationError(f"'{key}' doesn't exists") del attr[key] pylxd_save_object(obj) @@ -3599,7 +3592,7 @@ def _verify_image(image, remote_addr=None, cert=None, key=None, verify_cert=True except SaltInvocationError: image = image_get(name, remote_addr, cert, key, verify_cert, _raw=True) elif not hasattr(image, "fingerprint"): - raise SaltInvocationError("Invalid image '{}'".format(image)) + raise SaltInvocationError(f"Invalid image '{image}'") return image diff --git a/salt/modules/mac_desktop.py b/salt/modules/mac_desktop.py index eb58cf2888e..0c457080d28 100644 --- a/salt/modules/mac_desktop.py +++ b/salt/modules/mac_desktop.py @@ -48,7 +48,7 @@ def set_output_volume(volume): salt '*' desktop.set_output_volume """ - cmd = 'osascript -e "set volume output volume {}"'.format(volume) + cmd = f'osascript -e "set volume output volume {volume}"' call = __salt__["cmd.run_all"](cmd, output_loglevel="debug", python_shell=False) _check_cmd(call) @@ -125,6 +125,6 @@ def _check_cmd(call): if std_out: comment += std_out - raise CommandExecutionError("Error running command: {}".format(comment)) + raise CommandExecutionError(f"Error running command: {comment}") return call diff --git a/salt/modules/mac_group.py b/salt/modules/mac_group.py index 4c13f598802..0f4337cb2c3 100644 --- a/salt/modules/mac_group.py +++ b/salt/modules/mac_group.py @@ -1,6 +1,7 @@ """ Manage groups on Mac OS 10.7+ """ + import logging import salt.utils.functools @@ -57,7 +58,7 @@ def add(name, gid=None, **kwargs): ### NOTE: **kwargs isn't used here but needs to be included in this ### function for compatibility with the group.present state if info(name): - raise CommandExecutionError("Group '{}' already exists".format(name)) + raise CommandExecutionError(f"Group '{name}' already exists") if salt.utils.stringutils.contains_whitespace(name): raise SaltInvocationError("Group name cannot contain whitespace") if name.startswith("_"): @@ -71,7 +72,7 @@ def add(name, gid=None, **kwargs): # check if gid is already in use gid_list = _list_gids() if str(gid) in gid_list: - raise CommandExecutionError("gid '{}' already exists".format(gid)) + raise CommandExecutionError(f"gid '{gid}' already exists") cmd = ["dseditgroup", "-o", "create"] if gid: @@ -129,7 +130,7 @@ def adduser(group, name): Verifies if a valid username 'bar' as a member of an existing group 'foo', if not then adds it. """ - cmd = "dscl . -merge /Groups/{} GroupMembership {}".format(group, name) + cmd = f"dscl . -merge /Groups/{group} GroupMembership {name}" return __salt__["cmd.retcode"](cmd) == 0 @@ -148,7 +149,7 @@ def deluser(group, name): Removes a member user 'bar' from a group 'foo'. If group is not present then returns True. """ - cmd = "dscl . -delete /Groups/{} GroupMembership {}".format(group, name) + cmd = f"dscl . -delete /Groups/{group} GroupMembership {name}" return __salt__["cmd.retcode"](cmd) == 0 @@ -169,7 +170,7 @@ def members(name, members_list): retcode = 1 grp_info = __salt__["group.info"](name) if grp_info and name in grp_info["name"]: - cmd = "/usr/bin/dscl . -delete /Groups/{} GroupMembership".format(name) + cmd = f"/usr/bin/dscl . -delete /Groups/{name} GroupMembership" retcode = __salt__["cmd.retcode"](cmd) == 0 for user in members_list.split(","): cmd = "/usr/bin/dscl . -merge /Groups/{} GroupMembership {}".format( @@ -254,7 +255,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) pre_info = info(name) if not pre_info: - raise CommandExecutionError("Group '{}' does not exist".format(name)) + raise CommandExecutionError(f"Group '{name}' does not exist") if gid == pre_info["gid"]: return True cmd = ["dseditgroup", "-o", "edit", "-i", gid, name] diff --git a/salt/modules/mac_pkgutil.py b/salt/modules/mac_pkgutil.py index 538db2fcf61..63c4bd46b43 100644 --- a/salt/modules/mac_pkgutil.py +++ b/salt/modules/mac_pkgutil.py @@ -68,10 +68,10 @@ def _install_from_path(path): Internal function to install a package from the given path """ if not os.path.exists(path): - msg = "File not found: {}".format(path) + msg = f"File not found: {path}" raise SaltInvocationError(msg) - cmd = 'installer -pkg "{}" -target /'.format(path) + cmd = f'installer -pkg "{path}" -target /' return salt.utils.mac_utils.execute_return_success(cmd) @@ -97,7 +97,7 @@ def install(source, package_id): uri = urllib.parse.urlparse(source) if not uri.scheme == "": - msg = "Unsupported scheme for source uri: {}".format(uri.scheme) + msg = f"Unsupported scheme for source uri: {uri.scheme}" raise SaltInvocationError(msg) _install_from_path(source) @@ -125,6 +125,6 @@ def forget(package_id): salt '*' pkgutil.forget com.apple.pkg.gcc4.2Leo """ - cmd = "pkgutil --forget {}".format(package_id) + cmd = f"pkgutil --forget {package_id}" salt.utils.mac_utils.execute_return_success(cmd) return not is_installed(package_id) diff --git a/salt/modules/mac_portspkg.py b/salt/modules/mac_portspkg.py index 70cb23039fb..2113af467d3 100644 --- a/salt/modules/mac_portspkg.py +++ b/salt/modules/mac_portspkg.py @@ -62,7 +62,7 @@ def __virtual__(): def _list(query=""): - cmd = "port list {}".format(query) + cmd = f"port list {query}" out = salt.utils.mac_utils.execute_return_result(cmd) ret = {} @@ -178,7 +178,7 @@ def latest_version(*names, **kwargs): ): ret[key] = val else: - ret[key] = "{} (installed)".format(version(key)) + ret[key] = f"{version(key)} (installed)" return ret diff --git a/salt/modules/mac_shadow.py b/salt/modules/mac_shadow.py index 1297971fca2..c484d5db967 100644 --- a/salt/modules/mac_shadow.py +++ b/salt/modules/mac_shadow.py @@ -6,6 +6,7 @@ Manage macOS local directory passwords and policies Note that it is usually better to apply password policies through the creation of a configuration profile. """ + # Authentication concepts reference: # https://developer.apple.com/library/mac/documentation/Networking/Conceptual/Open_Directory/openDirectoryConcepts/openDirectoryConcepts.html#//apple_ref/doc/uid/TP40000917-CH3-CIFCAIBB diff --git a/salt/modules/mac_softwareupdate.py b/salt/modules/mac_softwareupdate.py index 0b5df536210..22d69f7199e 100644 --- a/salt/modules/mac_softwareupdate.py +++ b/salt/modules/mac_softwareupdate.py @@ -311,7 +311,7 @@ def update(name): salt '*' softwareupdate.update """ if not update_available(name): - raise SaltInvocationError("Update not available: {}".format(name)) + raise SaltInvocationError(f"Update not available: {name}") cmd = ["softwareupdate", "--install", name] salt.utils.mac_utils.execute_return_success(cmd) @@ -390,7 +390,7 @@ def download(name): salt '*' softwareupdate.download """ if not update_available(name): - raise SaltInvocationError("Update not available: {}".format(name)) + raise SaltInvocationError(f"Update not available: {name}") if name in list_downloads(): return True diff --git a/salt/modules/mac_sysctl.py b/salt/modules/mac_sysctl.py index 9fe3cc60f03..16f67e09a3b 100644 --- a/salt/modules/mac_sysctl.py +++ b/salt/modules/mac_sysctl.py @@ -66,14 +66,14 @@ def show(config_file=False): # # Yes. That's two `kern.clockrate`. # - if any([line.startswith("{}.".format(root)) for root in roots]): + if any([line.startswith(f"{root}.") for root in roots]): comps = line.split(": " if ": " in line else " = ", 1) if len(comps) == 2: ret[comps[0]] = comps[1] else: ret[comps[0]] = "" elif comps[0]: - ret[comps[0]] += "{}\n".format(line) + ret[comps[0]] += f"{line}\n" else: continue return ret @@ -92,7 +92,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd, python_shell=False) return out @@ -114,7 +114,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.icmp.icmplim 50 """ ret = {} - cmd = 'sysctl -w {}="{}"'.format(name, value) + cmd = f'sysctl -w {name}="{value}"' data = __salt__["cmd.run_all"](cmd, python_shell=False) if data["retcode"] != 0: @@ -165,7 +165,7 @@ def persist(name, value, config="/etc/sysctl.conf", apply_change=False): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - if not line.startswith("{}=".format(name)): + if not line.startswith(f"{name}="): nlines.append(line) continue else: @@ -179,10 +179,10 @@ def persist(name, value, config="/etc/sysctl.conf", apply_change=False): rest = rest[len(rest_v) :] if rest_v == value: return "Already set" - nlines.append("{}={}\n".format(name, value)) + nlines.append(f"{name}={value}\n") edited = True if not edited: - nlines.append("{}={}\n".format(name, value)) + nlines.append(f"{name}={value}\n") nlines = [salt.utils.stringutils.to_str(_l) for _l in nlines] with salt.utils.files.fopen(config, "w+") as ofile: ofile.writelines(nlines) diff --git a/salt/modules/mac_timezone.py b/salt/modules/mac_timezone.py index 5703ab08784..26549c44882 100644 --- a/salt/modules/mac_timezone.py +++ b/salt/modules/mac_timezone.py @@ -53,7 +53,7 @@ def _get_date_time_format(dt_string): return dt_format except ValueError: continue - msg = "Invalid Date/Time Format: {}".format(dt_string) + msg = f"Invalid Date/Time Format: {dt_string}" raise SaltInvocationError(msg) @@ -237,11 +237,9 @@ def set_zone(time_zone): salt '*' timezone.set_zone America/Denver """ if time_zone not in list_zones(): - raise SaltInvocationError("Invalid Timezone: {}".format(time_zone)) + raise SaltInvocationError(f"Invalid Timezone: {time_zone}") - salt.utils.mac_utils.execute_return_success( - "systemsetup -settimezone {}".format(time_zone) - ) + salt.utils.mac_utils.execute_return_success(f"systemsetup -settimezone {time_zone}") return time_zone in get_zone() @@ -303,7 +301,7 @@ def set_using_network_time(enable): """ state = salt.utils.mac_utils.validate_enabled(enable) - cmd = "systemsetup -setusingnetworktime {}".format(state) + cmd = f"systemsetup -setusingnetworktime {state}" salt.utils.mac_utils.execute_return_success(cmd) return state == salt.utils.mac_utils.validate_enabled(get_using_network_time()) @@ -349,7 +347,7 @@ def set_time_server(time_server="time.apple.com"): salt '*' timezone.set_time_server time.acme.com """ - cmd = "systemsetup -setnetworktimeserver {}".format(time_server) + cmd = f"systemsetup -setnetworktimeserver {time_server}" salt.utils.mac_utils.execute_return_success(cmd) return time_server in get_time_server() diff --git a/salt/modules/mac_user.py b/salt/modules/mac_user.py index 7e4f1b25965..d5fd6e98665 100644 --- a/salt/modules/mac_user.py +++ b/salt/modules/mac_user.py @@ -79,7 +79,7 @@ def add( shell=None, fullname=None, createhome=True, - **kwargs + **kwargs, ): """ Add a user to the minion @@ -91,7 +91,7 @@ def add( salt '*' user.add name """ if info(name): - raise CommandExecutionError("User '{}' already exists".format(name)) + raise CommandExecutionError(f"User '{name}' already exists") if salt.utils.stringutils.contains_whitespace(name): raise SaltInvocationError("Username cannot contain whitespace") @@ -101,7 +101,7 @@ def add( if gid is None: gid = 20 # gid 20 == 'staff', the default group if home is None: - home = "/Users/{}".format(name) + home = f"/Users/{name}" if shell is None: shell = "/bin/bash" if fullname is None: @@ -112,7 +112,7 @@ def add( if not isinstance(gid, int): raise SaltInvocationError("gid must be an integer") - name_path = "/Users/{}".format(name) + name_path = f"/Users/{name}" _dscl([name_path, "UniqueID", uid]) _dscl([name_path, "PrimaryGroupID", gid]) _dscl([name_path, "UserShell", shell]) @@ -155,7 +155,7 @@ def delete(name, remove=False, force=False): # group membership is managed separately from users and an entry for the # user will persist even after the user is removed. chgroups(name, ()) - ret = _dscl(["/Users/{}".format(name)], ctype="delete")["retcode"] == 0 + ret = _dscl([f"/Users/{name}"], ctype="delete")["retcode"] == 0 if ret and remove: # remove home directory from filesystem __salt__["file.remove"](user_info["home"]) @@ -196,10 +196,10 @@ def chuid(name, uid): raise SaltInvocationError("uid must be an integer") pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if uid == pre_info["uid"]: return True - _dscl(["/Users/{}".format(name), "UniqueID", pre_info["uid"], uid], ctype="change") + _dscl([f"/Users/{name}", "UniqueID", pre_info["uid"], uid], ctype="change") # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) @@ -220,11 +220,11 @@ def chgid(name, gid): raise SaltInvocationError("gid must be an integer") pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if gid == pre_info["gid"]: return True _dscl( - ["/Users/{}".format(name), "PrimaryGroupID", pre_info["gid"], gid], + [f"/Users/{name}", "PrimaryGroupID", pre_info["gid"], gid], ctype="change", ) # dscl buffers changes, sleep 1 second before checking if new value @@ -245,11 +245,11 @@ def chshell(name, shell): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if shell == pre_info["shell"]: return True _dscl( - ["/Users/{}".format(name), "UserShell", pre_info["shell"], shell], + [f"/Users/{name}", "UserShell", pre_info["shell"], shell], ctype="change", ) # dscl buffers changes, sleep 1 second before checking if new value @@ -277,11 +277,11 @@ def chhome(name, home, **kwargs): pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if home == pre_info["home"]: return True _dscl( - ["/Users/{}".format(name), "NFSHomeDirectory", pre_info["home"], home], + [f"/Users/{name}", "NFSHomeDirectory", pre_info["home"], home], ctype="change", ) # dscl buffers changes, sleep 1 second before checking if new value @@ -303,12 +303,12 @@ def chfullname(name, fullname): fullname = salt.utils.data.decode(fullname) pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") pre_info["fullname"] = salt.utils.data.decode(pre_info["fullname"]) if fullname == pre_info["fullname"]: return True _dscl( - ["/Users/{}".format(name), "RealName", fullname], + [f"/Users/{name}", "RealName", fullname], # use a 'create' command, because a 'change' command would fail if # current fullname is an empty string. The 'create' will just overwrite # this field. @@ -346,7 +346,7 @@ def chgroups(name, groups, append=False): ### function for compatibility with the user.present state uinfo = info(name) if not uinfo: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if isinstance(groups, str): groups = groups.split(",") @@ -364,11 +364,11 @@ def chgroups(name, groups, append=False): return True # Add groups from which user is missing for group in desired - ugrps: - _dscl(["/Groups/{}".format(group), "GroupMembership", name], ctype="append") + _dscl([f"/Groups/{group}", "GroupMembership", name], ctype="append") if not append: # Remove from extra groups for group in ugrps - desired: - _dscl(["/Groups/{}".format(group), "GroupMembership", name], ctype="delete") + _dscl([f"/Groups/{group}", "GroupMembership", name], ctype="delete") time.sleep(1) return set(list_groups(name)) == desired @@ -472,11 +472,11 @@ def rename(name, new_name): """ current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) - _dscl(["/Users/{}".format(name), "RecordName", name, new_name], ctype="change") + raise CommandExecutionError(f"User '{new_name}' already exists") + _dscl([f"/Users/{name}", "RecordName", name, new_name], ctype="change") # dscl buffers changes, sleep 1 second before checking if new value # matches desired value time.sleep(1) diff --git a/salt/modules/mac_xattr.py b/salt/modules/mac_xattr.py index e2bbf1c503a..b7b742965a6 100644 --- a/salt/modules/mac_xattr.py +++ b/salt/modules/mac_xattr.py @@ -60,8 +60,8 @@ def list_(path, **kwargs): ret = salt.utils.mac_utils.execute_return_result(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"File not found: {path}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") if not ret: return {} @@ -115,10 +115,10 @@ def read(path, attribute, **kwargs): return exc.object.decode(errors="replace") except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) + raise CommandExecutionError(f"File not found: {path}") if "No such xattr" in exc.strerror: - raise CommandExecutionError("Attribute not found: {}".format(attribute)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"Attribute not found: {attribute}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return ret @@ -161,8 +161,8 @@ def write(path, attribute, value, **kwargs): salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"File not found: {path}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return read(path, attribute, **{"hex": hex_}) == value @@ -188,15 +188,15 @@ def delete(path, attribute): salt '*' xattr.delete /path/to/file "com.test.attr" """ - cmd = 'xattr -d "{}" "{}"'.format(attribute, path) + cmd = f'xattr -d "{attribute}" "{path}"' try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) + raise CommandExecutionError(f"File not found: {path}") if "No such xattr" in exc.strerror: - raise CommandExecutionError("Attribute not found: {}".format(attribute)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"Attribute not found: {attribute}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return attribute not in list_(path) @@ -217,12 +217,12 @@ def clear(path): salt '*' xattr.delete /path/to/file "com.test.attr" """ - cmd = 'xattr -c "{}"'.format(path) + cmd = f'xattr -c "{path}"' try: salt.utils.mac_utils.execute_return_success(cmd) except CommandExecutionError as exc: if "No such file" in exc.strerror: - raise CommandExecutionError("File not found: {}".format(path)) - raise CommandExecutionError("Unknown Error: {}".format(exc.strerror)) + raise CommandExecutionError(f"File not found: {path}") + raise CommandExecutionError(f"Unknown Error: {exc.strerror}") return list_(path) == {} diff --git a/salt/modules/macdefaults.py b/salt/modules/macdefaults.py index c805536fdd7..77f0e580afc 100644 --- a/salt/modules/macdefaults.py +++ b/salt/modules/macdefaults.py @@ -56,7 +56,7 @@ def write(domain, key, value, type="string", user=None): elif value is False: value = "FALSE" - cmd = 'defaults write "{}" "{}" -{} "{}"'.format(domain, key, type, value) + cmd = f'defaults write "{domain}" "{key}" -{type} "{value}"' return __salt__["cmd.run_all"](cmd, runas=user) @@ -82,7 +82,7 @@ def read(domain, key, user=None): The user to read the defaults as """ - cmd = 'defaults read "{}" "{}"'.format(domain, key) + cmd = f'defaults read "{domain}" "{key}"' return __salt__["cmd.run"](cmd, runas=user) @@ -108,5 +108,5 @@ def delete(domain, key, user=None): The user to delete the defaults with """ - cmd = 'defaults delete "{}" "{}"'.format(domain, key) + cmd = f'defaults delete "{domain}" "{key}"' return __salt__["cmd.run_all"](cmd, runas=user, output_loglevel="debug") diff --git a/salt/modules/makeconf.py b/salt/modules/makeconf.py index 446a72cfd31..b95d3b7bf23 100644 --- a/salt/modules/makeconf.py +++ b/salt/modules/makeconf.py @@ -42,7 +42,7 @@ def _add_var(var, value): """ makeconf = _get_makeconf() layman = "source /var/lib/layman/make.conf" - fullvar = '{}="{}"'.format(var, value) + fullvar = f'{var}="{value}"' if __salt__["file.contains"](makeconf, layman): # TODO perhaps make this a function in the file module? cmd = [ @@ -77,9 +77,7 @@ def set_var(var, value): # If var already in file, replace its value if old_value is not None: - __salt__["file.sed"]( - makeconf, "^{}=.*".format(var), '{}="{}"'.format(var, value) - ) + __salt__["file.sed"](makeconf, f"^{var}=.*", f'{var}="{value}"') else: _add_var(var, value) @@ -108,7 +106,7 @@ def remove_var(var): # If var is in file if old_value is not None: - __salt__["file.sed"](makeconf, "^{}=.*".format(var), "") + __salt__["file.sed"](makeconf, f"^{var}=.*", "") new_value = get_var(var) return {var: {"old": old_value, "new": new_value}} @@ -135,10 +133,8 @@ def append_var(var, value): # If var already in file, add to its value if old_value is not None: - appended_value = "{} {}".format(old_value, value) - __salt__["file.sed"]( - makeconf, "^{}=.*".format(var), '{}="{}"'.format(var, appended_value) - ) + appended_value = f"{old_value} {value}" + __salt__["file.sed"](makeconf, f"^{var}=.*", f'{var}="{appended_value}"') else: _add_var(var, value) diff --git a/salt/modules/mandrill.py b/salt/modules/mandrill.py index d9c7d333ecd..5896662d664 100644 --- a/salt/modules/mandrill.py +++ b/salt/modules/mandrill.py @@ -17,7 +17,6 @@ In the minion configuration file, the following block is required: .. versionadded:: 2018.3.0 """ - import logging import salt.utils.json diff --git a/salt/modules/marathon.py b/salt/modules/marathon.py index c749f28015e..6c2c73b429a 100644 --- a/salt/modules/marathon.py +++ b/salt/modules/marathon.py @@ -6,7 +6,6 @@ Currently this only works when run through a proxy minion. .. versionadded:: 2015.8.2 """ - import logging import salt.utils.http @@ -44,7 +43,7 @@ def _app_id(app_id): Make sure the app_id is in the correct format. """ if app_id[0] != "/": - app_id = "/{}".format(app_id) + app_id = f"/{app_id}" return app_id @@ -59,7 +58,7 @@ def apps(): salt marathon-minion-id marathon.apps """ response = salt.utils.http.query( - "{}/v2/apps".format(_base_url()), + f"{_base_url()}/v2/apps", decode_type="json", decode=True, ) @@ -90,7 +89,7 @@ def app(id): salt marathon-minion-id marathon.app my-app """ response = salt.utils.http.query( - "{}/v2/apps/{}".format(_base_url(), id), + f"{_base_url()}/v2/apps/{id}", decode_type="json", decode=True, ) @@ -116,7 +115,7 @@ def update_app(id, config): data = salt.utils.json.dumps(config) try: response = salt.utils.http.query( - "{}/v2/apps/{}?force=true".format(_base_url(), id), + f"{_base_url()}/v2/apps/{id}?force=true", method="PUT", decode_type="json", decode=True, @@ -144,7 +143,7 @@ def rm_app(id): salt marathon-minion-id marathon.rm_app my-app """ response = salt.utils.http.query( - "{}/v2/apps/{}".format(_base_url(), id), + f"{_base_url()}/v2/apps/{id}", method="DELETE", decode_type="json", decode=True, @@ -163,7 +162,7 @@ def info(): salt marathon-minion-id marathon.info """ response = salt.utils.http.query( - "{}/v2/info".format(_base_url()), + f"{_base_url()}/v2/info", decode_type="json", decode=True, ) @@ -202,7 +201,7 @@ def restart_app(id, restart=False, force=True): return ret try: response = salt.utils.http.query( - "{}/v2/apps/{}/restart?force={}".format(_base_url(), _app_id(id), force), + f"{_base_url()}/v2/apps/{_app_id(id)}/restart?force={force}", method="POST", decode_type="json", decode=True, diff --git a/salt/modules/mattermost.py b/salt/modules/mattermost.py index adb3cb7b676..5f821766a55 100644 --- a/salt/modules/mattermost.py +++ b/salt/modules/mattermost.py @@ -14,7 +14,6 @@ Module for sending messages to Mattermost api_url: https://example.com """ - import logging import salt.utils.json diff --git a/salt/modules/mdadm_raid.py b/salt/modules/mdadm_raid.py index e76f400a214..85e5d1e6247 100644 --- a/salt/modules/mdadm_raid.py +++ b/salt/modules/mdadm_raid.py @@ -1,6 +1,7 @@ """ Salt module to manage RAID arrays with mdadm """ + import logging import os import re @@ -142,7 +143,7 @@ def destroy(device): cfg_file = "/etc/mdadm.conf" try: - __salt__["file.replace"](cfg_file, "ARRAY {} .*".format(device), "") + __salt__["file.replace"](cfg_file, f"ARRAY {device} .*", "") except SaltInvocationError: pass @@ -229,7 +230,7 @@ def create(name, level, devices, metadata="default", test_mode=False, **kwargs): for key in kwargs: if not key.startswith("__"): - opts.append("--{}".format(key)) + opts.append(f"--{key}") if kwargs[key] is not True: opts.append(str(kwargs[key])) if key == "spare-devices": @@ -274,7 +275,7 @@ def save_config(): buggy_ubuntu_tags = ["name", "metadata"] for i, elem in enumerate(scan): for bad_tag in buggy_ubuntu_tags: - pattern = r"\s{}=\S+".format(re.escape(bad_tag)) + pattern = rf"\s{re.escape(bad_tag)}=\S+" pattern = re.compile(pattern, flags=re.I) scan[i] = re.sub(pattern, "", scan[i]) @@ -334,7 +335,7 @@ def assemble(name, devices, test_mode=False, **kwargs): opts = [] for key in kwargs: if not key.startswith("__"): - opts.append("--{}".format(key)) + opts.append(f"--{key}") if kwargs[key] is not True: opts.append(kwargs[key]) @@ -367,7 +368,7 @@ def examine(device, quiet=False): salt '*' raid.examine '/dev/sda1' """ res = __salt__["cmd.run_stdout"]( - "mdadm -Y -E {}".format(device), python_shell=False, ignore_retcode=quiet + f"mdadm -Y -E {device}", python_shell=False, ignore_retcode=quiet ) ret = {} @@ -389,7 +390,7 @@ def add(name, device): """ - cmd = "mdadm --manage {} --add {}".format(name, device) + cmd = f"mdadm --manage {name} --add {device}" if __salt__["cmd.retcode"](cmd) == 0: return True return False diff --git a/salt/modules/mdata.py b/salt/modules/mdata.py index 87f2582ce00..94415b7c39b 100644 --- a/salt/modules/mdata.py +++ b/salt/modules/mdata.py @@ -8,7 +8,6 @@ Module for managaging metadata in SmartOS Zones :platform: smartos """ - import logging import salt.utils.decorators as decorators diff --git a/salt/modules/memcached.py b/salt/modules/memcached.py index d8c2cf6d01b..4c6cc558e18 100644 --- a/salt/modules/memcached.py +++ b/salt/modules/memcached.py @@ -51,7 +51,7 @@ def _connect(host=DEFAULT_HOST, port=DEFAULT_PORT): values assigned to missing values. """ if str(port).isdigit(): - return memcache.Client(["{}:{}".format(host, port)], debug=0) + return memcache.Client([f"{host}:{port}"], debug=0) raise SaltInvocationError("port must be an integer") @@ -214,10 +214,10 @@ def increment(key, delta=1, host=DEFAULT_HOST, port=DEFAULT_PORT): cur = get(key) if cur is None: - raise CommandExecutionError("Key '{}' does not exist".format(key)) + raise CommandExecutionError(f"Key '{key}' does not exist") elif not isinstance(cur, int): raise CommandExecutionError( - "Value for key '{}' must be an integer to be incremented".format(key) + f"Value for key '{key}' must be an integer to be incremented" ) try: @@ -245,10 +245,10 @@ def decrement(key, delta=1, host=DEFAULT_HOST, port=DEFAULT_PORT): cur = get(key) if cur is None: - raise CommandExecutionError("Key '{}' does not exist".format(key)) + raise CommandExecutionError(f"Key '{key}' does not exist") elif not isinstance(cur, int): raise CommandExecutionError( - "Value for key '{}' must be an integer to be decremented".format(key) + f"Value for key '{key}' must be an integer to be decremented" ) try: diff --git a/salt/modules/mine.py b/salt/modules/mine.py index f8d55464019..758ec9e4e1d 100644 --- a/salt/modules/mine.py +++ b/salt/modules/mine.py @@ -309,7 +309,7 @@ def get(tgt, fun, tgt_type="glob", exclude_minion=False): # Load from local minion's cache if __opts__["file_client"] == "local": ret = {} - is_target = { + _targets = { "glob": __salt__["match.glob"], "pcre": __salt__["match.pcre"], "list": __salt__["match.list"], @@ -319,7 +319,8 @@ def get(tgt, fun, tgt_type="glob", exclude_minion=False): "compound": __salt__["match.compound"], "pillar": __salt__["match.pillar"], "pillar_pcre": __salt__["match.pillar_pcre"], - }[tgt_type](tgt) + } + is_target = _targets[tgt_type](tgt) if not is_target: return ret diff --git a/salt/modules/minion.py b/salt/modules/minion.py index e93b2783c80..bed8f437f75 100644 --- a/salt/modules/minion.py +++ b/salt/modules/minion.py @@ -212,12 +212,12 @@ def restart(): restart_cmd = __salt__["config.get"]("minion_restart_command") if restart_cmd: comment.append("Using configuration minion_restart_command:") - comment.extend([" {}".format(arg) for arg in restart_cmd]) + comment.extend([f" {arg}" for arg in restart_cmd]) else: if "-d" in sys.argv: restart_cmd = sys.argv comment.append("Restart using process argv:") - comment.extend([" {}".format(arg) for arg in restart_cmd]) + comment.extend([f" {arg}" for arg in restart_cmd]) else: should_restart = False comment.append( diff --git a/salt/modules/modjk.py b/salt/modules/modjk.py index 41f6253fd43..fb968a7a986 100644 --- a/salt/modules/modjk.py +++ b/salt/modules/modjk.py @@ -29,6 +29,7 @@ this module. realm: authentication realm2 for digest passwords timeout: 600 """ + import urllib.parse import urllib.request @@ -59,25 +60,25 @@ def _do_http(opts, profile="default"): ret = {} - url = __salt__["config.get"]("modjk:{}:url".format(profile), "") - user = __salt__["config.get"]("modjk:{}:user".format(profile), "") - passwd = __salt__["config.get"]("modjk:{}:pass".format(profile), "") - realm = __salt__["config.get"]("modjk:{}:realm".format(profile), "") - timeout = __salt__["config.get"]("modjk:{}:timeout".format(profile), "") + url = __salt__["config.get"](f"modjk:{profile}:url", "") + user = __salt__["config.get"](f"modjk:{profile}:user", "") + passwd = __salt__["config.get"](f"modjk:{profile}:pass", "") + realm = __salt__["config.get"](f"modjk:{profile}:realm", "") + timeout = __salt__["config.get"](f"modjk:{profile}:timeout", "") if not url: - raise Exception("missing url in profile {}".format(profile)) + raise Exception(f"missing url in profile {profile}") if user and passwd: auth = _auth(url=url, realm=realm, user=user, passwd=passwd) urllib.request.install_opener(auth) - url += "?{}".format(urllib.parse.urlencode(opts)) + url += f"?{urllib.parse.urlencode(opts)}" for line in urllib.request.urlopen(url, timeout=timeout).read().splitlines(): splt = line.split("=", 1) if splt[0] in ret: - ret[splt[0]] += ",{}".format(splt[1]) + ret[splt[0]] += f",{splt[1]}" else: ret[splt[0]] = splt[1] @@ -171,7 +172,7 @@ def list_configured_members(lbn, profile="default"): config = dump_config(profile) try: - ret = config["worker.{}.balance_workers".format(lbn)] + ret = config[f"worker.{lbn}.balance_workers"] except KeyError: return [] @@ -197,9 +198,7 @@ def workers(profile="default"): for lb in lbn: try: - worker_list.extend( - config["worker.{}.balance_workers".format(lb)].split(",") - ) + worker_list.extend(config[f"worker.{lb}.balance_workers"].split(",")) except KeyError: pass @@ -207,8 +206,8 @@ def workers(profile="default"): for worker in worker_list: ret[worker] = { - "activation": config["worker.{}.activation".format(worker)], - "state": config["worker.{}.state".format(worker)], + "activation": config[f"worker.{worker}.activation"], + "state": config[f"worker.{worker}.state"], } return ret @@ -229,7 +228,7 @@ def recover_all(lbn, profile="default"): ret = {} config = get_running(profile) try: - workers_ = config["worker.{}.balance_workers".format(lbn)].split(",") + workers_ = config[f"worker.{lbn}.balance_workers"].split(",") except KeyError: return ret @@ -417,8 +416,8 @@ def worker_status(worker, profile="default"): config = get_running(profile) try: return { - "activation": config["worker.{}.activation".format(worker)], - "state": config["worker.{}.state".format(worker)], + "activation": config[f"worker.{worker}.activation"], + "state": config[f"worker.{worker}.state"], } except KeyError: return False diff --git a/salt/modules/mongodb.py b/salt/modules/mongodb.py index 72b0ff00747..699dcfd48e9 100644 --- a/salt/modules/mongodb.py +++ b/salt/modules/mongodb.py @@ -236,7 +236,7 @@ def version( """ conn = _connect(user, password, host, port, authdb=authdb) if not conn: - err_msg = "Failed to connect to MongoDB database {}:{}".format(host, port) + err_msg = f"Failed to connect to MongoDB database {host}:{port}" log.error(err_msg) return (False, err_msg) @@ -283,7 +283,7 @@ def user_find( """ conn = _connect(user, password, host, port, authdb=authdb) if not conn: - err_msg = "Failed to connect to MongoDB database {}:{}".format(host, port) + err_msg = f"Failed to connect to MongoDB database {host}:{port}" log.error(err_msg) return (False, err_msg) @@ -993,7 +993,7 @@ def update_one( col = getattr(mdb, collection) ids = col.update_one(_id_field, {"$set": _update_doc}) nb_mod = ids.modified_count - return "{} objects updated".format(nb_mod) + return f"{nb_mod} objects updated" except pymongo.errors.PyMongoError as err: log.error("Updating object %s failed with error %s", objects, err) return err @@ -1139,7 +1139,7 @@ def remove( for count in range(0, w): res = col.delete_one(query) deleted_count += res.deleted_count - return "{} objects removed".format(deleted_count) + return f"{deleted_count} objects removed" except pymongo.errors.PyMongoError as err: log.error("Removing objects failed with error: %s", _get_error_message(err)) return _get_error_message(err) diff --git a/salt/modules/monit.py b/salt/modules/monit.py index 65d9da8286c..3f685f6f5d9 100644 --- a/salt/modules/monit.py +++ b/salt/modules/monit.py @@ -34,7 +34,7 @@ def start(name): salt '*' monit.start """ - cmd = "monit start {}".format(name) + cmd = f"monit start {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -49,7 +49,7 @@ def stop(name): salt '*' monit.stop """ - cmd = "monit stop {}".format(name) + cmd = f"monit stop {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -64,7 +64,7 @@ def restart(name): salt '*' monit.restart """ - cmd = "monit restart {}".format(name) + cmd = f"monit restart {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -79,7 +79,7 @@ def unmonitor(name): salt '*' monit.unmonitor """ - cmd = "monit unmonitor {}".format(name) + cmd = f"monit unmonitor {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -94,7 +94,7 @@ def monitor(name): salt '*' monit.monitor """ - cmd = "monit monitor {}".format(name) + cmd = f"monit monitor {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) diff --git a/salt/modules/mount.py b/salt/modules/mount.py index fd43821db49..413efb98bf0 100644 --- a/salt/modules/mount.py +++ b/salt/modules/mount.py @@ -2,7 +2,6 @@ Salt module to manage Unix mounts and the fstab file """ - import logging import os import re diff --git a/salt/modules/mssql.py b/salt/modules/mssql.py index 3b64899929c..23ca6577542 100644 --- a/salt/modules/mssql.py +++ b/salt/modules/mssql.py @@ -20,7 +20,6 @@ Module to provide MS SQL Server compatibility to salt. configs or pillars. """ - import salt.utils.json try: @@ -140,7 +139,7 @@ def db_exists(database_name, **kwargs): "SELECT database_id FROM sys.databases WHERE NAME='{}'".format( database_name ), - **kwargs + **kwargs, ) ) == 1 @@ -161,7 +160,7 @@ def db_create(database, containment="NONE", new_database_options=None, **kwargs) """ if containment not in ["NONE", "PARTIAL"]: return "CONTAINMENT can be one of NONE and PARTIAL" - sql = "CREATE DATABASE [{}] CONTAINMENT = {} ".format(database, containment) + sql = f"CREATE DATABASE [{database}] CONTAINMENT = {containment} " if new_database_options: sql += " WITH " + ", ".join(new_database_options) conn = None @@ -172,7 +171,7 @@ def db_create(database, containment="NONE", new_database_options=None, **kwargs) # cur.execute(sql) conn.cursor().execute(sql) except Exception as e: # pylint: disable=broad-except - return "Could not create the database: {}".format(e) + return f"Could not create the database: {e}" finally: if conn: conn.autocommit(False) @@ -206,18 +205,17 @@ def db_remove(database_name, **kwargs): database_name ) ) - cur.execute("DROP DATABASE {}".format(database_name)) + cur.execute(f"DROP DATABASE {database_name}") conn.autocommit(False) conn.close() return True else: return False except Exception as e: # pylint: disable=broad-except - return "Could not find the database: {}".format(e) + return f"Could not find the database: {e}" def role_list(**kwargs): - """ Lists database roles. @@ -231,7 +229,6 @@ def role_list(**kwargs): def role_exists(role, **kwargs): - """ Checks if a role exists. @@ -242,10 +239,7 @@ def role_exists(role, **kwargs): salt minion mssql.role_exists db_owner """ # We should get one, and only one row - return ( - len(tsql_query(query='sp_helprole "{}"'.format(role), as_dict=True, **kwargs)) - == 1 - ) + return len(tsql_query(query=f'sp_helprole "{role}"', as_dict=True, **kwargs)) == 1 def role_create(role, owner=None, grants=None, **kwargs): @@ -264,9 +258,9 @@ def role_create(role, owner=None, grants=None, **kwargs): if not grants: grants = [] - sql = "CREATE ROLE {}".format(role) + sql = f"CREATE ROLE {role}" if owner: - sql += " AUTHORIZATION {}".format(owner) + sql += f" AUTHORIZATION {owner}" conn = None try: conn = _get_connection(**kwargs) @@ -275,9 +269,9 @@ def role_create(role, owner=None, grants=None, **kwargs): # cur.execute(sql) conn.cursor().execute(sql) for grant in grants: - conn.cursor().execute("GRANT {} TO [{}]".format(grant, role)) + conn.cursor().execute(f"GRANT {grant} TO [{role}]") except Exception as e: # pylint: disable=broad-except - return "Could not create the role: {}".format(e) + return f"Could not create the role: {e}" finally: if conn: conn.autocommit(False) @@ -299,12 +293,12 @@ def role_remove(role, **kwargs): conn = _get_connection(**kwargs) conn.autocommit(True) cur = conn.cursor() - cur.execute("DROP ROLE {}".format(role)) + cur.execute(f"DROP ROLE {role}") conn.autocommit(True) conn.close() return True except Exception as e: # pylint: disable=broad-except - return "Could not remove the role: {}".format(e) + return f"Could not remove the role: {e}" def login_exists(login, domain="", **kwargs): @@ -319,7 +313,7 @@ def login_exists(login, domain="", **kwargs): salt minion mssql.login_exists 'LOGIN' """ if domain: - login = "{}\\{}".format(domain, login) + login = f"{domain}\\{login}" try: # We should get one, and only one row return ( @@ -328,14 +322,14 @@ def login_exists(login, domain="", **kwargs): query="SELECT name FROM sys.syslogins WHERE name='{}'".format( login ), - **kwargs + **kwargs, ) ) == 1 ) except Exception as e: # pylint: disable=broad-except - return "Could not find the login: {}".format(e) + return f"Could not find the login: {e}" def login_create( @@ -344,7 +338,7 @@ def login_create( new_login_domain="", new_login_roles=None, new_login_options=None, - **kwargs + **kwargs, ): """ Creates a new login. Does not update password of existing logins. For @@ -371,19 +365,19 @@ def login_create( if login_exists(login, new_login_domain, **kwargs): return False if new_login_domain: - login = "{}\\{}".format(new_login_domain, login) + login = f"{new_login_domain}\\{login}" if not new_login_roles: new_login_roles = [] if not new_login_options: new_login_options = [] - sql = "CREATE LOGIN [{}] ".format(login) + sql = f"CREATE LOGIN [{login}] " if new_login_domain: sql += " FROM WINDOWS " elif isinstance(new_login_password, int): - new_login_options.insert(0, "PASSWORD=0x{:x} HASHED".format(new_login_password)) + new_login_options.insert(0, f"PASSWORD=0x{new_login_password:x} HASHED") else: # Plain test password - new_login_options.insert(0, "PASSWORD=N'{}'".format(new_login_password)) + new_login_options.insert(0, f"PASSWORD=N'{new_login_password}'") if new_login_options: sql += " WITH " + ", ".join(new_login_options) conn = None @@ -394,11 +388,9 @@ def login_create( # cur.execute(sql) conn.cursor().execute(sql) for role in new_login_roles: - conn.cursor().execute( - "ALTER SERVER ROLE [{}] ADD MEMBER [{}]".format(role, login) - ) + conn.cursor().execute(f"ALTER SERVER ROLE [{role}] ADD MEMBER [{login}]") except Exception as e: # pylint: disable=broad-except - return "Could not create the login: {}".format(e) + return f"Could not create the login: {e}" finally: if conn: conn.autocommit(False) @@ -420,12 +412,12 @@ def login_remove(login, **kwargs): conn = _get_connection(**kwargs) conn.autocommit(True) cur = conn.cursor() - cur.execute("DROP LOGIN [{}]".format(login)) + cur.execute(f"DROP LOGIN [{login}]") conn.autocommit(False) conn.close() return True except Exception as e: # pylint: disable=broad-except - return "Could not remove the login: {}".format(e) + return f"Could not remove the login: {e}" def user_exists(username, domain="", database=None, **kwargs): @@ -440,15 +432,14 @@ def user_exists(username, domain="", database=None, **kwargs): salt minion mssql.user_exists 'USERNAME' [database='DBNAME'] """ if domain: - username = "{}\\{}".format(domain, username) + username = f"{domain}\\{username}" if database: kwargs["database"] = database # We should get one, and only one row return ( len( tsql_query( - query="SELECT name FROM sysusers WHERE name='{}'".format(username), - **kwargs + query=f"SELECT name FROM sysusers WHERE name='{username}'", **kwargs ) ) == 1 @@ -470,7 +461,7 @@ def user_list(**kwargs): for row in tsql_query( "SELECT name FROM sysusers where issqluser=1 or isntuser=1", as_dict=False, - **kwargs + **kwargs, ) ] @@ -492,10 +483,10 @@ def user_create( if domain and not login: return "domain cannot be set without login" if user_exists(username, domain, **kwargs): - return "User {} already exists".format(username) + return f"User {username} already exists" if domain: - username = "{}\\{}".format(domain, username) - login = "{}\\{}".format(domain, login) if login else login + username = f"{domain}\\{username}" + login = f"{domain}\\{login}" if login else login if database: kwargs["database"] = database if not roles: @@ -503,12 +494,12 @@ def user_create( if not options: options = [] - sql = "CREATE USER [{}] ".format(username) + sql = f"CREATE USER [{username}] " if login: # If the login does not exist, user creation will throw # if not login_exists(name, **kwargs): # return False - sql += " FOR LOGIN [{}]".format(login) + sql += f" FOR LOGIN [{login}]" else: # Plain test password sql += " WITHOUT LOGIN" if options: @@ -521,11 +512,9 @@ def user_create( # cur.execute(sql) conn.cursor().execute(sql) for role in roles: - conn.cursor().execute( - "ALTER ROLE [{}] ADD MEMBER [{}]".format(role, username) - ) + conn.cursor().execute(f"ALTER ROLE [{role}] ADD MEMBER [{username}]") except Exception as e: # pylint: disable=broad-except - return "Could not create the user: {}".format(e) + return f"Could not create the user: {e}" finally: if conn: conn.autocommit(False) @@ -550,9 +539,9 @@ def user_remove(username, **kwargs): conn = _get_connection(**kwargs) conn.autocommit(True) cur = conn.cursor() - cur.execute("DROP USER {}".format(username)) + cur.execute(f"DROP USER {username}") conn.autocommit(False) conn.close() return True except Exception as e: # pylint: disable=broad-except - return "Could not remove the user: {}".format(e) + return f"Could not remove the user: {e}" diff --git a/salt/modules/munin.py b/salt/modules/munin.py index ced668011f0..764135fc485 100644 --- a/salt/modules/munin.py +++ b/salt/modules/munin.py @@ -49,9 +49,7 @@ def run(plugins): if plugin not in all_plugins: continue data[plugin] = {} - muninout = __salt__["cmd.run"]( - "munin-run {}".format(plugin), python_shell=False - ) + muninout = __salt__["cmd.run"](f"munin-run {plugin}", python_shell=False) for line in muninout.split("\n"): if "value" in line: # This skips multigraph lines, etc key, val = line.split(" ") diff --git a/salt/modules/mysql.py b/salt/modules/mysql.py index d566f7b4e45..5a0820c0400 100644 --- a/salt/modules/mysql.py +++ b/salt/modules/mysql.py @@ -28,7 +28,6 @@ Module to provide MySQL compatibility to salt. Additionally, it is now possible to setup a user with no password. """ - import copy import hashlib import logging diff --git a/salt/modules/nacl.py b/salt/modules/nacl.py index ef0e1774548..ca1e54193e5 100644 --- a/salt/modules/nacl.py +++ b/salt/modules/nacl.py @@ -149,7 +149,6 @@ Optional small program to encrypt data without needing salt modules. """ - import salt.utils.nacl __virtualname__ = "nacl" diff --git a/salt/modules/nagios.py b/salt/modules/nagios.py index 29c02e4bf03..87f3ae639f7 100644 --- a/salt/modules/nagios.py +++ b/salt/modules/nagios.py @@ -2,7 +2,6 @@ Run nagios plugins/checks from salt and get the return as data. """ - import logging import os import stat @@ -33,9 +32,7 @@ def _execute_cmd(plugin, args="", run_type="cmd.retcode"): all_plugins = list_plugins() if plugin in all_plugins: - data = __salt__[run_type]( - "{}{} {}".format(PLUGINDIR, plugin, args), python_shell=False - ) + data = __salt__[run_type](f"{PLUGINDIR}{plugin} {args}", python_shell=False) return data diff --git a/salt/modules/nagios_rpc.py b/salt/modules/nagios_rpc.py index 0f7969dbf38..9aee76a10c3 100644 --- a/salt/modules/nagios_rpc.py +++ b/salt/modules/nagios_rpc.py @@ -5,7 +5,6 @@ Check Host & Service status from Nagios via JSON RPC. """ - import http.client import logging @@ -98,7 +97,7 @@ def _status_query(query, hostname, enumerate=None, service=None): elif result.get("status", None) == http.client.NOT_FOUND: ret["error"] = "URL {} was not found.".format(config["url"]) else: - ret["error"] = "Results: {}".format(result.text) + ret["error"] = f"Results: {result.text}" return ret diff --git a/salt/modules/namecheap_domains.py b/salt/modules/namecheap_domains.py index 97ec8e215a0..e12c102b913 100644 --- a/salt/modules/namecheap_domains.py +++ b/salt/modules/namecheap_domains.py @@ -364,7 +364,7 @@ def create(domain_name, years, **kwargs): for requiredkey in require_opts: if requiredkey not in opts: log.error("Missing required parameter '%s'", requiredkey) - raise Exception("Missing required parameter '{}'".format(requiredkey)) + raise Exception(f"Missing required parameter '{requiredkey}'") response_xml = salt.utils.namecheap.post_request(opts) @@ -402,9 +402,9 @@ def check(*domains_to_check): domains_checked = {} for result in response_xml.getElementsByTagName("DomainCheckResult"): available = result.getAttribute("Available") - domains_checked[ - result.getAttribute("Domain").lower() - ] = salt.utils.namecheap.string_to_value(available) + domains_checked[result.getAttribute("Domain").lower()] = ( + salt.utils.namecheap.string_to_value(available) + ) return domains_checked diff --git a/salt/modules/namecheap_domains_dns.py b/salt/modules/namecheap_domains_dns.py index ef6789ec778..24805acba6d 100644 --- a/salt/modules/namecheap_domains_dns.py +++ b/salt/modules/namecheap_domains_dns.py @@ -26,7 +26,6 @@ file, or in the Pillar data. #namecheap.url: https://api.sandbox.namecheap.xml.response """ - CAN_USE_NAMECHEAP = True diff --git a/salt/modules/napalm_bgp.py b/salt/modules/napalm_bgp.py index 84a19b27a2c..b7721397bd9 100644 --- a/salt/modules/napalm_bgp.py +++ b/salt/modules/napalm_bgp.py @@ -17,7 +17,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -59,7 +58,6 @@ def __virtual__(): @proxy_napalm_wrap def config(group=None, neighbor=None, **kwargs): - """ Provides the BGP configuration on the device. @@ -169,7 +167,6 @@ def config(group=None, neighbor=None, **kwargs): @proxy_napalm_wrap def neighbors(neighbor=None, **kwargs): - """ Provides details regarding the BGP sessions configured on the network device. diff --git a/salt/modules/napalm_formula.py b/salt/modules/napalm_formula.py index 1b641d71973..c69d376cd60 100644 --- a/salt/modules/napalm_formula.py +++ b/salt/modules/napalm_formula.py @@ -292,7 +292,7 @@ def render_field(dictionary, field, prepend=None, append=None, quotes=False, **o else: append = "" if quotes: - value = '"{value}"'.format(value=value) + value = f'"{value}"' return "{prepend} {value}{append}".format( prepend=prepend, value=value, append=append ) diff --git a/salt/modules/napalm_network.py b/salt/modules/napalm_network.py index 124d70b4876..9fc5185553f 100644 --- a/salt/modules/napalm_network.py +++ b/salt/modules/napalm_network.py @@ -64,7 +64,6 @@ def __virtual__(): def _filter_list(input_list, search_key, search_value): - """ Filters a list of dictionary by a set of key-value pair. @@ -84,7 +83,6 @@ def _filter_list(input_list, search_key, search_value): def _filter_dict(input_dict, search_key, search_value): - """ Filters a dictionary of dictionaries by a key-value pair. @@ -172,7 +170,7 @@ def _config_logic( revert_in=None, revert_at=None, commit_jid=None, - **kwargs + **kwargs, ): """ Builds the config logic for `load_config` and `load_template` functions. @@ -193,7 +191,7 @@ def _config_logic( current_jid = kwargs.get("__pub_jid") if not current_jid: - current_jid = "{:%Y%m%d%H%M%S%f}".format(datetime.datetime.now()) + current_jid = f"{datetime.datetime.now():%Y%m%d%H%M%S%f}" loaded_result["already_configured"] = False @@ -248,7 +246,7 @@ def _config_logic( time_in=commit_in, time_at=commit_in ) # schedule job - scheduled_job_name = "__napalm_commit_{}".format(current_jid) + scheduled_job_name = f"__napalm_commit_{current_jid}" temp_file = salt.utils.files.mkstemp() with salt.utils.files.fopen(temp_file, "w") as fp_: fp_.write(loaded_config) @@ -310,9 +308,9 @@ def _config_logic( _comm = __salt__["napalm.junos_commit"](confirm=minutes) if not _comm["out"]: # If unable to commit confirm, should try to bail out - loaded_result[ - "comment" - ] = "Unable to commit confirm: {}".format(_comm["message"]) + loaded_result["comment"] = ( + "Unable to commit confirm: {}".format(_comm["message"]) + ) loaded_result["result"] = False # But before exiting, we must gracefully discard the config discarded = _safe_dicard_config(loaded_result, napalm_device) @@ -331,7 +329,7 @@ def _config_logic( # already done by the _safe_commit_config function), and # return with the command and other details. return loaded_result - scheduled_job_name = "__napalm_commit_{}".format(current_jid) + scheduled_job_name = f"__napalm_commit_{current_jid}" scheduled = __salt__["schedule.add"]( scheduled_job_name, function="net.load_config", @@ -694,7 +692,7 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument raw_cli_outputs = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "cli", - **{"commands": list(commands)} + **{"commands": list(commands)}, ) # thus we can display the output as is # in case of errors, they'll be caught in the proxy @@ -828,7 +826,7 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument processed_command_output = command_output processed_cli_outputs[ "comment" - ] += "\nUnable to process the output from {}.".format(command) + ] += f"\nUnable to process the output from {command}." processed_cli_outputs["out"][command] = processed_command_output processed_cli_outputs["comment"] = processed_cli_outputs["comment"].strip() return processed_cli_outputs @@ -838,7 +836,6 @@ def cli(*commands, **kwargs): # pylint: disable=unused-argument def traceroute( destination, source=None, ttl=None, timeout=None, vrf=None, **kwargs ): # pylint: disable=unused-argument - """ Calls the method traceroute from the NAPALM driver object and returns a dictionary with the result of the traceroute command executed on the device. @@ -877,7 +874,7 @@ def traceroute( "ttl": ttl, "timeout": timeout, "vrf": vrf, - } + }, ) @@ -890,9 +887,8 @@ def ping( size=None, count=None, vrf=None, - **kwargs + **kwargs, ): # pylint: disable=unused-argument - """ Executes a ping on the network device and returns a dictionary as a result. @@ -939,7 +935,7 @@ def ping( "size": size, "count": count, "vrf": vrf, - } + }, ) @@ -947,7 +943,6 @@ def ping( def arp( interface="", ipaddr="", macaddr="", **kwargs ): # pylint: disable=unused-argument - """ NAPALM returns a list of dictionaries with details of the ARP entries. @@ -1008,7 +1003,6 @@ def arp( @salt.utils.napalm.proxy_napalm_wrap def ipaddrs(**kwargs): # pylint: disable=unused-argument - """ Returns IP addresses configured on the device. @@ -1065,7 +1059,6 @@ def ipaddrs(**kwargs): # pylint: disable=unused-argument @salt.utils.napalm.proxy_napalm_wrap def interfaces(**kwargs): # pylint: disable=unused-argument - """ Returns details of the interfaces on the device. @@ -1109,7 +1102,6 @@ def interfaces(**kwargs): # pylint: disable=unused-argument @salt.utils.napalm.proxy_napalm_wrap def lldp(interface="", **kwargs): # pylint: disable=unused-argument - """ Returns a detailed view of the LLDP neighbors. @@ -1151,7 +1143,7 @@ def lldp(interface="", **kwargs): # pylint: disable=unused-argument proxy_output = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "get_lldp_neighbors_detail", - **{} + **{}, ) if not proxy_output.get("result"): @@ -1169,7 +1161,6 @@ def lldp(interface="", **kwargs): # pylint: disable=unused-argument @salt.utils.napalm.proxy_napalm_wrap def mac(address="", interface="", vlan=0, **kwargs): # pylint: disable=unused-argument - """ Returns the MAC Address Table on the device. @@ -1214,7 +1205,7 @@ def mac(address="", interface="", vlan=0, **kwargs): # pylint: disable=unused-a proxy_output = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "get_mac_address_table", - **{} + **{}, ) if not proxy_output.get("result"): @@ -1283,7 +1274,7 @@ def config(source=None, **kwargs): # pylint: disable=unused-argument return salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable "get_config", - **{"retrieve": source} + **{"retrieve": source}, ) @@ -1350,7 +1341,7 @@ def load_config( commit_jid=None, inherit_napalm_device=None, saltenv="base", - **kwargs + **kwargs, ): # pylint: disable=unused-argument """ Applies configuration changes on the device. It can be loaded from a file or from inline string. @@ -1563,10 +1554,10 @@ def load_config( # When using salt:// or https://, if the resource is not available, # it will either raise an exception, or return False. ret = {"result": False, "out": None} - ret[ - "comment" - ] = "Unable to read from {}. Please specify a valid file or text.".format( - filename + ret["comment"] = ( + "Unable to read from {}. Please specify a valid file or text.".format( + filename + ) ) log.error(ret["comment"]) return ret @@ -1591,7 +1582,7 @@ def load_config( revert_in=revert_in, revert_at=revert_at, commit_jid=commit_jid, - **kwargs + **kwargs, ) @@ -1615,7 +1606,7 @@ def load_template( revert_in=None, revert_at=None, inherit_napalm_device=None, # pylint: disable=unused-argument - **template_vars + **template_vars, ): """ Renders a configuration template (default: Jinja) and loads the result on the device. @@ -2077,7 +2068,7 @@ def load_template( _loaded = salt.utils.napalm.call( napalm_device, # pylint: disable=undefined-variable fun, - **{"config": _rendered} + **{"config": _rendered}, ) return _config_logic( napalm_device, # pylint: disable=undefined-variable @@ -2091,13 +2082,12 @@ def load_template( commit_in=commit_in, revert_in=revert_in, revert_at=revert_at, - **template_vars + **template_vars, ) @salt.utils.napalm.proxy_napalm_wrap def commit(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-argument - """ Commits the configuration changes made on the network device. @@ -2117,7 +2107,6 @@ def commit(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-argu def discard_config( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Discards the changes applied. @@ -2137,7 +2126,6 @@ def discard_config( def compare_config( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Returns the difference between the running config and the candidate config. @@ -2155,7 +2143,6 @@ def compare_config( @salt.utils.napalm.proxy_napalm_wrap def rollback(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-argument - """ Rollbacks the configuration. @@ -2175,7 +2162,6 @@ def rollback(inherit_napalm_device=None, **kwargs): # pylint: disable=unused-ar def config_changed( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Will prompt if the configuration has been changed. @@ -2210,7 +2196,6 @@ def config_changed( def config_control( inherit_napalm_device=None, **kwargs ): # pylint: disable=unused-argument - """ Will check if the configuration was changed. If differences found, will try to commit. @@ -2270,13 +2255,13 @@ def cancel_commit(jid): salt '*' net.cancel_commit 20180726083540640360 """ - job_name = "__napalm_commit_{}".format(jid) + job_name = f"__napalm_commit_{jid}" removed = __salt__["schedule.delete"](job_name) if removed["result"]: saved = __salt__["schedule.save"]() - removed["comment"] = "Commit #{jid} cancelled.".format(jid=jid) + removed["comment"] = f"Commit #{jid} cancelled." else: - removed["comment"] = "Unable to find commit #{jid}.".format(jid=jid) + removed["comment"] = f"Unable to find commit #{jid}." return removed @@ -2305,7 +2290,7 @@ def confirm_commit(jid): else: confirmed = cancel_commit(jid) if confirmed["result"]: - confirmed["comment"] = "Commit #{jid} confirmed.".format(jid=jid) + confirmed["comment"] = f"Commit #{jid} confirmed." return confirmed @@ -2343,7 +2328,7 @@ def save_config(source=None, path=None): return { "result": True, "out": path, - "comment": "{source} config saved to {path}".format(source=source, path=path), + "comment": f"{source} config saved to {path}", } @@ -2679,7 +2664,7 @@ def patch( return { "out": None, "result": False, - "comment": 'The file "{}" does not exist.'.format(patchfile), + "comment": f'The file "{patchfile}" does not exist.', } replace_pattern = __salt__["file.patch"](path, patchfile_cache, options=options) with salt.utils.files.fopen(path, "r") as fh_: diff --git a/salt/modules/napalm_ntp.py b/salt/modules/napalm_ntp.py index 125c36dfb47..d737c149e23 100644 --- a/salt/modules/napalm_ntp.py +++ b/salt/modules/napalm_ntp.py @@ -20,7 +20,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -62,7 +61,6 @@ def __virtual__(): @proxy_napalm_wrap def peers(**kwargs): # pylint: disable=unused-argument - """ Returns a list the NTP peers configured on the network device. @@ -103,7 +101,6 @@ def peers(**kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def servers(**kwargs): # pylint: disable=unused-argument - """ Returns a list of the configured NTP servers on the device. @@ -141,7 +138,6 @@ def servers(**kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def stats(peer=None, **kwargs): # pylint: disable=unused-argument - """ Returns a dictionary containing synchronization details of the NTP peers. @@ -208,7 +204,6 @@ def stats(peer=None, **kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def set_peers(*peers, **options): - """ Configures a list of NTP peers on the device. @@ -285,7 +280,6 @@ def set_servers(*servers, **options): @proxy_napalm_wrap def delete_peers(*peers, **options): - """ Removes NTP peers configured on the device. @@ -325,7 +319,6 @@ def delete_peers(*peers, **options): @proxy_napalm_wrap def delete_servers(*servers, **options): - """ Removes NTP servers configured on the device. diff --git a/salt/modules/napalm_probes.py b/salt/modules/napalm_probes.py index 7f798391a75..132b984d6b1 100644 --- a/salt/modules/napalm_probes.py +++ b/salt/modules/napalm_probes.py @@ -60,7 +60,6 @@ def __virtual__(): @proxy_napalm_wrap def config(**kwargs): # pylint: disable=unused-argument - """ Returns the configuration of the RPM probes. @@ -103,7 +102,6 @@ def config(**kwargs): # pylint: disable=unused-argument @proxy_napalm_wrap def results(**kwargs): # pylint: disable=unused-argument - """ Provides the results of the measurements of the RPM/SLA probes. @@ -270,7 +268,6 @@ def set_probes( def delete_probes( probes, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Removes RPM/SLA probes from the network device. Calls the configuration template 'delete_probes' from the NAPALM library, @@ -327,7 +324,6 @@ def delete_probes( def schedule_probes( probes, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Will schedule the probes. On Cisco devices, it is not enough to define the probes, it is also necessary to schedule them. diff --git a/salt/modules/napalm_route.py b/salt/modules/napalm_route.py index 41d8d74987e..1f88345c4fd 100644 --- a/salt/modules/napalm_route.py +++ b/salt/modules/napalm_route.py @@ -16,7 +16,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -58,7 +57,6 @@ def __virtual__(): @proxy_napalm_wrap def show(destination, protocol=None, **kwargs): # pylint: disable=unused-argument - """ Displays all details for a certain route learned via a specific protocol. If the protocol is not specified, will return all possible routes. diff --git a/salt/modules/napalm_snmp.py b/salt/modules/napalm_snmp.py index dbcbb4ad700..2e72c03fa69 100644 --- a/salt/modules/napalm_snmp.py +++ b/salt/modules/napalm_snmp.py @@ -20,7 +20,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -62,7 +61,6 @@ def __virtual__(): @proxy_napalm_wrap def config(**kwargs): # pylint: disable=unused-argument - """ Returns the SNMP configuration @@ -90,7 +88,6 @@ def remove_config( commit=True, **kwargs ): # pylint: disable=unused-argument - """ Removes a configuration element from the SNMP configuration. @@ -157,7 +154,6 @@ def update_config( commit=True, **kwargs ): # pylint: disable=unused-argument - """ Updates the SNMP configuration. diff --git a/salt/modules/napalm_users.py b/salt/modules/napalm_users.py index 170e441ba98..40603097102 100644 --- a/salt/modules/napalm_users.py +++ b/salt/modules/napalm_users.py @@ -19,7 +19,6 @@ Dependencies .. versionadded:: 2016.11.0 """ - import logging # import NAPALM utils @@ -61,7 +60,6 @@ def __virtual__(): @proxy_napalm_wrap def config(**kwargs): # pylint: disable=unused-argument - """ Returns the configuration of the users on the device @@ -100,7 +98,6 @@ def config(**kwargs): # pylint: disable=unused-argument def set_users( users, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Configures users on network devices. @@ -149,7 +146,6 @@ def set_users( def delete_users( users, test=False, commit=True, **kwargs ): # pylint: disable=unused-argument - """ Removes users from the configuration of network devices. diff --git a/salt/modules/netaddress.py b/salt/modules/netaddress.py index 7c528c92a9e..86b7b1aae97 100644 --- a/salt/modules/netaddress.py +++ b/salt/modules/netaddress.py @@ -6,7 +6,6 @@ Module for getting information about network addresses. :depends: netaddr """ - __virtualname__ = "netaddress" try: diff --git a/salt/modules/netbox.py b/salt/modules/netbox.py index 656087d0cb0..13b1ff63a71 100644 --- a/salt/modules/netbox.py +++ b/salt/modules/netbox.py @@ -190,7 +190,7 @@ def get_(app, endpoint, id=None, **kwargs): endpoint, id=id, auth_required=True if app in AUTH_ENDPOINTS else False, - **kwargs + **kwargs, ) ) @@ -1014,7 +1014,7 @@ def create_circuit_provider(name, asn=None): else: log.error("Duplicate provider with different ASN: %s: %s", name, asn) raise CommandExecutionError( - "Duplicate provider with different ASN: {}: {}".format(name, asn) + f"Duplicate provider with different ASN: {name}: {asn}" ) else: payload = {"name": name, "slug": slugify(name)} diff --git a/salt/modules/netmiko_mod.py b/salt/modules/netmiko_mod.py index 1769471f82b..d3cd44e10cd 100644 --- a/salt/modules/netmiko_mod.py +++ b/salt/modules/netmiko_mod.py @@ -486,7 +486,7 @@ def send_config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Send configuration commands down the SSH channel. @@ -564,7 +564,7 @@ def send_config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") elif config_commands: if isinstance(config_commands, ((str,), str)): config_commands = [config_commands] diff --git a/salt/modules/netscaler.py b/salt/modules/netscaler.py index e4d684c4088..94949f3527c 100644 --- a/salt/modules/netscaler.py +++ b/salt/modules/netscaler.py @@ -118,7 +118,7 @@ def _connect(**kwargs): name = name[len(prefix) :] except IndexError: return - val = __salt__["config.option"]("netscaler.{}".format(name), None) + val = __salt__["config.option"](f"netscaler.{name}", None) if val is not None: connargs[key] = val elif default is not None: diff --git a/salt/modules/neutronng.py b/salt/modules/neutronng.py index daf91f49ff7..3aa2817985c 100644 --- a/salt/modules/neutronng.py +++ b/salt/modules/neutronng.py @@ -25,7 +25,6 @@ Example configuration identity_api_version: 3 """ - HAS_SHADE = False try: import shade diff --git a/salt/modules/nexus.py b/salt/modules/nexus.py index 06a44f38a22..e8e212ce8f5 100644 --- a/salt/modules/nexus.py +++ b/salt/modules/nexus.py @@ -94,7 +94,7 @@ def get_latest_snapshot( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) artifact_metadata = _get_artifact_metadata( nexus_url=nexus_url, @@ -175,7 +175,7 @@ def get_snapshot( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) snapshot_url, file_name = _get_snapshot_url( nexus_url=nexus_url, @@ -241,7 +241,7 @@ def get_snapshot_version_string( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) return _get_snapshot_url( nexus_url=nexus_url, @@ -306,7 +306,7 @@ def get_latest_release( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) artifact_metadata = _get_artifact_metadata( nexus_url=nexus_url, @@ -379,7 +379,7 @@ def get_release( headers = {} if username and password: headers["Authorization"] = "Basic {}".format( - base64.encodestring("{}:{}".format(username, password)).replace("\n", "") + base64.encodestring(f"{username}:{password}").replace("\n", "") ) release_url, file_name = _get_release_url( repository, group_id, artifact_id, packaging, version, nexus_url, classifier @@ -688,7 +688,7 @@ def __save_artifact(artifact_url, target_file, headers): local_file.write(salt.utils.stringutils.to_bytes(f.read())) result["status"] = True result["comment"] = __append_comment( - "Artifact downloaded from URL: {}".format(artifact_url), + f"Artifact downloaded from URL: {artifact_url}", result["comment"], ) result["changes"]["downloaded_file"] = target_file diff --git a/salt/modules/nfs3.py b/salt/modules/nfs3.py index 048c8b18456..d692c5fb01e 100644 --- a/salt/modules/nfs3.py +++ b/salt/modules/nfs3.py @@ -125,8 +125,8 @@ def _write_exports(exports, edict): for perms in edict[export]: hosts = perms["hosts"] options = ",".join(perms["options"]) - line += " {}({})".format(hosts, options) - efh.write("{}\n".format(line)) + line += f" {hosts}({options})" + efh.write(f"{line}\n") def reload_exports(): diff --git a/salt/modules/nftables.py b/salt/modules/nftables.py index 8cfa92e3751..11ac05915bd 100644 --- a/salt/modules/nftables.py +++ b/salt/modules/nftables.py @@ -572,10 +572,10 @@ def check(table="filter", chain=None, rule=None, family="ipv4"): out = __salt__["cmd.run"](cmd, python_shell=False).find(search_rule) if out == -1: - ret[ - "comment" - ] = "Rule {} in chain {} in table {} in family {} does not exist".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} in chain {} in table {} in family {} does not exist".format( + rule, chain, table, family + ) ) else: ret["comment"] = "Rule {} in chain {} in table {} in family {} exists".format( @@ -795,10 +795,10 @@ def new_chain( ) ret["result"] = True else: - ret[ - "comment" - ] = "Chain {} in table {} in family {} could not be created".format( - chain, table, family + ret["comment"] = ( + "Chain {} in table {} in family {} could not be created".format( + chain, table, family + ) ) return ret @@ -846,10 +846,10 @@ def delete_chain(table="filter", chain=None, family="ipv4"): ) ret["result"] = True else: - ret[ - "comment" - ] = "Chain {} in table {} in family {} could not be deleted".format( - chain, table, family + ret["comment"] = ( + "Chain {} in table {} in family {} could not be deleted".format( + chain, table, family + ) ) return ret @@ -900,10 +900,10 @@ def append(table="filter", chain=None, rule=None, family="ipv4"): res = check(table, chain, rule, family=family) if res["result"]: - ret[ - "comment" - ] = "Rule {} chain {} in table {} in family {} already exists".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} chain {} in table {} in family {} already exists".format( + rule, chain, table, family + ) ) return ret @@ -919,10 +919,10 @@ def append(table="filter", chain=None, rule=None, family="ipv4"): rule, chain, table, family ) else: - ret[ - "comment" - ] = 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( - rule, chain, table, family + ret["comment"] = ( + 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( + rule, chain, table, family + ) ) return ret @@ -980,10 +980,10 @@ def insert(table="filter", chain=None, position=None, rule=None, family="ipv4"): res = check(table, chain, rule, family=family) if res["result"]: - ret[ - "comment" - ] = "Rule {} chain {} in table {} in family {} already exists".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} chain {} in table {} in family {} already exists".format( + rule, chain, table, family + ) ) return ret @@ -1004,10 +1004,10 @@ def insert(table="filter", chain=None, position=None, rule=None, family="ipv4"): rule, chain, table, family ) else: - ret[ - "comment" - ] = 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( - rule, chain, table, family + ret["comment"] = ( + 'Failed to add rule "{}" chain {} in table {} in family {}.'.format( + rule, chain, table, family + ) ) return ret @@ -1057,10 +1057,10 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): res = check(table, chain, rule, family=family) if not res["result"]: - ret[ - "comment" - ] = "Rule {} chain {} in table {} in family {} does not exist".format( - rule, chain, table, family + ret["comment"] = ( + "Rule {} chain {} in table {} in family {} does not exist".format( + rule, chain, table, family + ) ) return ret @@ -1077,16 +1077,16 @@ def delete(table, chain=None, position=None, rule=None, family="ipv4"): if not out: ret["result"] = True - ret[ - "comment" - ] = 'Deleted rule "{}" in chain {} in table {} in family {}.'.format( - rule, chain, table, family + ret["comment"] = ( + 'Deleted rule "{}" in chain {} in table {} in family {}.'.format( + rule, chain, table, family + ) ) else: - ret[ - "comment" - ] = 'Failed to delete rule "{}" in chain {} table {} in family {}'.format( - rule, chain, table, family + ret["comment"] = ( + 'Failed to delete rule "{}" in chain {} table {} in family {}'.format( + rule, chain, table, family + ) ) return ret diff --git a/salt/modules/nginx.py b/salt/modules/nginx.py index b684df5f6ff..21332816a5d 100644 --- a/salt/modules/nginx.py +++ b/salt/modules/nginx.py @@ -39,7 +39,7 @@ def version(): salt '*' nginx.version """ - cmd = "{} -v".format(__detect_os()) + cmd = f"{__detect_os()} -v" out = __salt__["cmd.run"](cmd).splitlines() ret = out[0].rsplit("/", maxsplit=1) return ret[-1] @@ -56,7 +56,7 @@ def build_info(): salt '*' nginx.build_info """ ret = {"info": []} - out = __salt__["cmd.run"]("{} -V".format(__detect_os())) + out = __salt__["cmd.run"](f"{__detect_os()} -V") for i in out.splitlines(): if i.startswith("configure argument"): @@ -80,7 +80,7 @@ def configtest(): """ ret = {} - cmd = "{} -t".format(__detect_os()) + cmd = f"{__detect_os()} -t" out = __salt__["cmd.run_all"](cmd) if out["retcode"] != 0: @@ -116,7 +116,7 @@ def signal(signal=None): if signal == "start": arguments = "" else: - arguments = " -s {}".format(signal) + arguments = f" -s {signal}" cmd = __detect_os() + arguments out = __salt__["cmd.run_all"](cmd) @@ -130,7 +130,7 @@ def signal(signal=None): ret = out["stdout"].strip() # No output for something like: nginxctl graceful else: - ret = 'Command: "{}" completed successfully!'.format(cmd) + ret = f'Command: "{cmd}" completed successfully!' return ret diff --git a/salt/modules/nilrt_ip.py b/salt/modules/nilrt_ip.py index 84612d7a17d..27243f2c70f 100644 --- a/salt/modules/nilrt_ip.py +++ b/salt/modules/nilrt_ip.py @@ -86,9 +86,7 @@ def _get_state(): except KeyError: return "offline" except dbus.DBusException as exc: - raise salt.exceptions.CommandExecutionError( - "Connman daemon error: {}".format(exc) - ) + raise salt.exceptions.CommandExecutionError(f"Connman daemon error: {exc}") def _get_technologies(): @@ -143,7 +141,7 @@ def _space_delimited_list(value): if valid: return True, "space-delimited string" - return False, "{} is not a valid list.\n".format(value) + return False, f"{value} is not a valid list.\n" def _validate_ipv4(value): @@ -152,13 +150,13 @@ def _validate_ipv4(value): """ if len(value) == 3: if not salt.utils.validate.net.ipv4_addr(value[0].strip()): - return False, "Invalid ip address: {} for ipv4 option".format(value[0]) + return False, f"Invalid ip address: {value[0]} for ipv4 option" if not salt.utils.validate.net.netmask(value[1].strip()): - return False, "Invalid netmask: {} for ipv4 option".format(value[1]) + return False, f"Invalid netmask: {value[1]} for ipv4 option" if not salt.utils.validate.net.ipv4_addr(value[2].strip()): - return False, "Invalid gateway: {} for ipv4 option".format(value[2]) + return False, f"Invalid gateway: {value[2]} for ipv4 option" else: - return False, "Invalid value: {} for ipv4 option".format(value) + return False, f"Invalid value: {value} for ipv4 option" return True, "" @@ -322,10 +320,8 @@ def _get_possible_adapter_modes(interface, blacklist): protocols = _load_config("lvrt", ["AdditionalNetworkProtocols"])[ "AdditionalNetworkProtocols" ].lower() - sys_interface_path = os.readlink("/sys/class/net/{}".format(interface)) - with salt.utils.files.fopen( - "/sys/class/net/{}/uevent".format(interface) - ) as uevent_file: + sys_interface_path = os.readlink(f"/sys/class/net/{interface}") + with salt.utils.files.fopen(f"/sys/class/net/{interface}/uevent") as uevent_file: uevent_lines = uevent_file.readlines() uevent_devtype = "" for line in uevent_lines: @@ -554,7 +550,7 @@ def _change_state_legacy(interface, new_state): if initial_mode == "ethercat": __salt__["system.set_reboot_required_witnessed"]() else: - out = __salt__["cmd.run_all"]("ip link set {} {}".format(interface, new_state)) + out = __salt__["cmd.run_all"](f"ip link set {interface} {new_state}") if out["retcode"] != 0: msg = "Couldn't {} interface {}. Error: {}".format( "enable" if new_state == "up" else "disable", interface, out["stderr"] @@ -582,22 +578,22 @@ def _change_dhcp_config(interface, enable_dhcp=True, filename=INTERFACES_CONFIG) interface = pyiface.Interface(name=interface) hwaddr = interface.hwaddr[:-1] hwaddr_section_number = "".join(hwaddr.split(":")) - if parser.has_section("service_{}".format(hwaddr_section_number)): - parser.remove_section("service_{}".format(hwaddr_section_number)) - parser.add_section("service_{}".format(hwaddr_section_number)) - parser.set("service_{}".format(hwaddr_section_number), "MAC", hwaddr) + if parser.has_section(f"service_{hwaddr_section_number}"): + parser.remove_section(f"service_{hwaddr_section_number}") + parser.add_section(f"service_{hwaddr_section_number}") + parser.set(f"service_{hwaddr_section_number}", "MAC", hwaddr) parser.set( - "service_{}".format(hwaddr_section_number), + f"service_{hwaddr_section_number}", "Name", - "ethernet_cable_{}".format(hwaddr_section_number), + f"ethernet_cable_{hwaddr_section_number}", ) - parser.set("service_{}".format(hwaddr_section_number), "Type", "ethernet") + parser.set(f"service_{hwaddr_section_number}", "Type", "ethernet") if enable_dhcp: - parser.set("service_{}".format(hwaddr_section_number), "IPv4.Method", "dhcp") - parser.set("service_{}".format(hwaddr_section_number), "AutoConnect", "true") - parser.set("service_{}".format(hwaddr_section_number), "Nameservers", "''") + parser.set(f"service_{hwaddr_section_number}", "IPv4.Method", "dhcp") + parser.set(f"service_{hwaddr_section_number}", "AutoConnect", "true") + parser.set(f"service_{hwaddr_section_number}", "Nameservers", "''") else: - parser.set("service_{}".format(hwaddr_section_number), "IPv4", "off") + parser.set(f"service_{hwaddr_section_number}", "IPv4", "off") with salt.utils.files.fopen(filename, "w") as config_file: parser.write(config_file) return True @@ -622,9 +618,7 @@ def _change_state(interface, new_state): if new_state == "up" else _change_dhcp_config(interface, False) ) - raise salt.exceptions.CommandExecutionError( - "Invalid interface name: {}".format(interface) - ) + raise salt.exceptions.CommandExecutionError(f"Invalid interface name: {interface}") def up(interface, iface_type=None): # pylint: disable=invalid-name,unused-argument @@ -708,9 +702,9 @@ def _save_config(section, token, value): Helper function to persist a configuration in the ini file """ cmd = NIRTCFG_PATH - cmd += " --set section={},token='{}',value='{}'".format(section, token, value) + cmd += f" --set section={section},token='{token}',value='{value}'" if __salt__["cmd.run_all"](cmd)["retcode"] != 0: - exc_msg = "Error: could not set {} to {} for {}\n".format(token, value, section) + exc_msg = f"Error: could not set {token} to {value} for {section}\n" raise salt.exceptions.CommandExecutionError(exc_msg) @@ -775,9 +769,7 @@ def set_dhcp_linklocal_all(interface): return True if interface in [x.name for x in pyiface.getIfaces()]: return _change_dhcp_config(interface) - raise salt.exceptions.CommandExecutionError( - "Invalid interface name: {}".format(interface) - ) + raise salt.exceptions.CommandExecutionError(f"Invalid interface name: {interface}") def set_dhcp_only_all(interface): @@ -863,24 +855,24 @@ def _configure_static_interface(interface, **settings): pass hwaddr = interface.hwaddr[:-1] hwaddr_section_number = "".join(hwaddr.split(":")) - if parser.has_section("service_{}".format(hwaddr_section_number)): - parser.remove_section("service_{}".format(hwaddr_section_number)) - parser.add_section("service_{}".format(hwaddr_section_number)) + if parser.has_section(f"service_{hwaddr_section_number}"): + parser.remove_section(f"service_{hwaddr_section_number}") + parser.add_section(f"service_{hwaddr_section_number}") ip_address = settings.get("ip", "0.0.0.0") netmask = settings.get("netmask", "0.0.0.0") gateway = settings.get("gateway", "0.0.0.0") dns_servers = settings.get("dns", "''") - name = settings.get("name", "ethernet_cable_{}".format(hwaddr_section_number)) + name = settings.get("name", f"ethernet_cable_{hwaddr_section_number}") parser.set( - "service_{}".format(hwaddr_section_number), + f"service_{hwaddr_section_number}", "IPv4", - "{}/{}/{}".format(ip_address, netmask, gateway), + f"{ip_address}/{netmask}/{gateway}", ) - parser.set("service_{}".format(hwaddr_section_number), "Nameservers", dns_servers) - parser.set("service_{}".format(hwaddr_section_number), "Name", name) - parser.set("service_{}".format(hwaddr_section_number), "MAC", hwaddr) - parser.set("service_{}".format(hwaddr_section_number), "Type", "ethernet") - parser.set("service_{}".format(hwaddr_section_number), "IPv4.method", "manual") + parser.set(f"service_{hwaddr_section_number}", "Nameservers", dns_servers) + parser.set(f"service_{hwaddr_section_number}", "Name", name) + parser.set(f"service_{hwaddr_section_number}", "MAC", hwaddr) + parser.set(f"service_{hwaddr_section_number}", "Type", "ethernet") + parser.set(f"service_{hwaddr_section_number}", "IPv4.method", "manual") with salt.utils.files.fopen(INTERFACES_CONFIG, "w") as config_file: parser.write(config_file) return True @@ -941,23 +933,23 @@ def set_static_all(interface, address, netmask, gateway, nameservers=None): "dns": ",".join(nameservers) if nameservers else "", "netmask": netmask, "gateway": gateway, - } + }, ) raise salt.exceptions.CommandExecutionError( - "Invalid interface name: {}".format(interface) + f"Invalid interface name: {interface}" ) service = pyconnman.ConnService(os.path.join(SERVICE_PATH, service)) ipv4 = service.get_property("IPv4.Configuration") ipv4["Method"] = dbus.String("manual", variant_level=1) - ipv4["Address"] = dbus.String("{}".format(address), variant_level=1) - ipv4["Netmask"] = dbus.String("{}".format(netmask), variant_level=1) - ipv4["Gateway"] = dbus.String("{}".format(gateway), variant_level=1) + ipv4["Address"] = dbus.String(f"{address}", variant_level=1) + ipv4["Netmask"] = dbus.String(f"{netmask}", variant_level=1) + ipv4["Gateway"] = dbus.String(f"{gateway}", variant_level=1) try: service.set_property("IPv4.Configuration", ipv4) if nameservers: service.set_property( "Nameservers.Configuration", - [dbus.String("{}".format(d)) for d in nameservers], + [dbus.String(f"{d}") for d in nameservers], ) except Exception as exc: # pylint: disable=broad-except exc_msg = "Couldn't set manual settings for service: {}\nError: {}\n".format( @@ -998,7 +990,7 @@ def build_interface(iface, iface_type, enabled, **settings): raise salt.exceptions.CommandExecutionError("Not supported in this version.") if iface_type != "eth": raise salt.exceptions.CommandExecutionError( - "Interface type not supported: {}:".format(iface_type) + f"Interface type not supported: {iface_type}:" ) if ( @@ -1049,7 +1041,7 @@ def build_network_settings(**settings): old_hostname = __salt__["network.get_hostname"] if new_hostname != old_hostname: __salt__["network.mod_hostname"](new_hostname) - changes.append("hostname={}".format(new_hostname)) + changes.append(f"hostname={new_hostname}") return changes @@ -1068,9 +1060,9 @@ def get_network_settings(): raise salt.exceptions.CommandExecutionError("Not supported in this version.") settings = [] networking = "no" if _get_state() == "offline" else "yes" - settings.append("networking={}".format(networking)) + settings.append(f"networking={networking}") hostname = __salt__["network.get_hostname"] - settings.append("hostname={}".format(hostname)) + settings.append(f"hostname={hostname}") return settings diff --git a/salt/modules/nix.py b/salt/modules/nix.py index d5331cb7a97..b0e95afc2d1 100644 --- a/salt/modules/nix.py +++ b/salt/modules/nix.py @@ -18,7 +18,6 @@ For more information on nix, see the `nix documentation`_. .. _`nix-daemon`: https://nixos.org/nix/manual/#ssec-multi-user """ - import itertools import logging import os diff --git a/salt/modules/npm.py b/salt/modules/npm.py index edbb7b4ae1d..f7a40043de4 100644 --- a/salt/modules/npm.py +++ b/salt/modules/npm.py @@ -47,9 +47,7 @@ def _check_valid_version(): npm_path = salt.utils.path.which("npm") # pylint: disable=no-member - res = salt.modules.cmdmod.run( - "{npm} --version".format(npm=npm_path), output_loglevel="quiet" - ) + res = salt.modules.cmdmod.run(f"{npm_path} --version", output_loglevel="quiet") npm_version = Version(res) valid_version = Version("1.2") # pylint: enable=no-member @@ -151,7 +149,7 @@ def install( cwd = dir if registry: - cmd.append('--registry="{}"'.format(registry)) + cmd.append(f'--registry="{registry}"') if dry_run: cmd.append("--dry-run") @@ -222,7 +220,7 @@ def uninstall(pkg, dir=None, runas=None, env=None): if uid: env.update({"SUDO_UID": uid, "SUDO_USER": ""}) - cmd = ["npm", "uninstall", '"{}"'.format(pkg)] + cmd = ["npm", "uninstall", f'"{pkg}"'] if not dir: cmd.append("--global") @@ -291,14 +289,14 @@ def list_(pkg=None, dir=None, runas=None, env=None, depth=None): if depth is not None: if not isinstance(depth, (int, float)): raise salt.exceptions.SaltInvocationError( - "Error: depth {} must be a number".format(depth) + f"Error: depth {depth} must be a number" ) - cmd.append("--depth={}".format(int(depth))) + cmd.append(f"--depth={int(depth)}") if pkg: # Protect against injection pkg = shlex.quote(pkg) - cmd.append('"{}"'.format(pkg)) + cmd.append(f'"{pkg}"') cmd = " ".join(cmd) result = __salt__["cmd.run_all"]( diff --git a/salt/modules/nspawn.py b/salt/modules/nspawn.py index 3c8e8c0f76f..a99a8f9fc8b 100644 --- a/salt/modules/nspawn.py +++ b/salt/modules/nspawn.py @@ -20,7 +20,6 @@ Minions running systemd >= 219 will place new containers in package. """ - import errno import functools import logging diff --git a/salt/modules/nxos_api.py b/salt/modules/nxos_api.py index 2513d9b0ff9..b787043f354 100644 --- a/salt/modules/nxos_api.py +++ b/salt/modules/nxos_api.py @@ -181,7 +181,7 @@ def _cli_command(commands, method="cli", **kwargs): ) raise SaltException(msg) else: - msg = 'Invalid command: "{cmd}".'.format(cmd=cmd) + msg = f'Invalid command: "{cmd}".' raise SaltException(msg) txt_responses.append(rpc_reponse["result"]) return txt_responses @@ -313,7 +313,7 @@ def config( context=None, defaults=None, saltenv="base", - **kwargs + **kwargs, ): """ Configures the Nexus switch with the specified commands. @@ -401,7 +401,7 @@ def config( if config_file: file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv) if file_str is False: - raise CommandExecutionError("Source file {} not found".format(config_file)) + raise CommandExecutionError(f"Source file {config_file} not found") elif commands: if isinstance(commands, str): commands = [commands] diff --git a/salt/modules/nxos_upgrade.py b/salt/modules/nxos_upgrade.py index 69ce8d2b5c4..25f662db8ee 100644 --- a/salt/modules/nxos_upgrade.py +++ b/salt/modules/nxos_upgrade.py @@ -114,7 +114,7 @@ def check_upgrade_impact(system_image, kickstart_image=None, issu=True, **kwargs if ki is not None: cmd = cmd + " kickstart {0}:{1} system {0}:{2}".format(dev, ki, si) else: - cmd = cmd + " nxos {}:{}".format(dev, si) + cmd = cmd + f" nxos {dev}:{si}" if issu and ki is None: cmd = cmd + " non-disruptive" @@ -254,14 +254,14 @@ def _upgrade(system_image, kickstart_image, issu, **kwargs): if ki is None: logmsg = "Upgrading device using combined system/kickstart image." - logmsg += "\nSystem Image: {}".format(si) - cmd = cmd + " nxos {}:{}".format(dev, si) + logmsg += f"\nSystem Image: {si}" + cmd = cmd + f" nxos {dev}:{si}" if issu: cmd = cmd + " non-disruptive" else: logmsg = "Upgrading device using separate system/kickstart images." - logmsg += "\nSystem Image: {}".format(si) - logmsg += "\nKickstart Image: {}".format(ki) + logmsg += f"\nSystem Image: {si}" + logmsg += f"\nKickstart Image: {ki}" if not issu: log.info("Attempting upgrade using force option") cmd = cmd + " force" @@ -367,7 +367,7 @@ def _parse_upgrade_data(data): g3 = mo.group(3) g4 = mo.group(4) g5 = mo.group(5) - mk = "module {}:image {}".format(g1, g2) # module key + mk = f"module {g1}:image {g2}" # module key upgrade_result[bk][mk] = {} upgrade_result[bk][mk]["running_version"] = g3 upgrade_result[bk][mk]["new_version"] = g4 diff --git a/salt/modules/omapi.py b/salt/modules/omapi.py index c63d94d3dae..e5d01260012 100644 --- a/salt/modules/omapi.py +++ b/salt/modules/omapi.py @@ -11,7 +11,6 @@ config or pillar: :depends: pypureomapi Python module """ - import logging import struct @@ -87,9 +86,9 @@ def add_host(mac, name=None, ip=None, ddns=False, group=None, supersede_host=Fal if group: msg.obj.append((b"group", salt.utils.stringutils.to_bytes(group))) if supersede_host: - statements += 'option host-name "{}"; '.format(name) + statements += f'option host-name "{name}"; ' if ddns and name: - statements += 'ddns-hostname "{}"; '.format(name) + statements += f'ddns-hostname "{name}"; ' if statements: msg.obj.append((b"statements", salt.utils.stringutils.to_bytes(statements))) response = o.query_server(msg) diff --git a/salt/modules/openbsd_sysctl.py b/salt/modules/openbsd_sysctl.py index 35a49297404..348d164efd0 100644 --- a/salt/modules/openbsd_sysctl.py +++ b/salt/modules/openbsd_sysctl.py @@ -61,7 +61,7 @@ def get(name): salt '*' sysctl.get hw.physmem """ - cmd = "sysctl -n {}".format(name) + cmd = f"sysctl -n {name}" out = __salt__["cmd.run"](cmd) return out @@ -77,7 +77,7 @@ def assign(name, value): salt '*' sysctl.assign net.inet.ip.forwarding 1 """ ret = {} - cmd = 'sysctl {}="{}"'.format(name, value) + cmd = f'sysctl {name}="{value}"' data = __salt__["cmd.run_all"](cmd) # Certain values cannot be set from this console, at the current @@ -119,7 +119,7 @@ def persist(name, value, config="/etc/sysctl.conf"): with salt.utils.files.fopen(config, "r") as ifile: for line in ifile: line = salt.utils.stringutils.to_unicode(line) - if not line.startswith("{}=".format(name)): + if not line.startswith(f"{name}="): nlines.append(line) continue else: @@ -133,11 +133,11 @@ def persist(name, value, config="/etc/sysctl.conf"): rest = rest[len(rest_v) :] if rest_v == value: return "Already set" - new_line = "{}={}{}".format(key, value, rest) + new_line = f"{key}={value}{rest}" nlines.append(new_line) edited = True if not edited: - nlines.append("{}={}\n".format(name, value)) + nlines.append(f"{name}={value}\n") with salt.utils.files.fopen(config, "wb") as ofile: ofile.writelines(salt.utils.data.encode(nlines)) diff --git a/salt/modules/openbsdpkg.py b/salt/modules/openbsdpkg.py index 3cbdc0cadf1..57d28ed96b5 100644 --- a/salt/modules/openbsdpkg.py +++ b/salt/modules/openbsdpkg.py @@ -95,7 +95,7 @@ def list_pkgs(versions_as_list=False, **kwargs): pkgname, pkgver, flavor = __PKG_RE.match(line).groups() except AttributeError: continue - pkgname += "--{}".format(flavor) if flavor else "" + pkgname += f"--{flavor}" if flavor else "" __salt__["pkg_resource.add_pkg"](ret, pkgname, pkgver) __salt__["pkg_resource.sort_pkglist"](ret) @@ -129,7 +129,7 @@ def latest_version(*names, **kwargs): ret[name] = "" # Query the repository for the package name - cmd = "pkg_info -Q {}".format(name) + cmd = f"pkg_info -Q {name}" out = __salt__["cmd.run_stdout"]( cmd, python_shell=False, output_loglevel="trace" ) @@ -153,8 +153,8 @@ def latest_version(*names, **kwargs): # First check if we need to look for flavors before # looking at unflavored packages. - if "{}--{}".format(pkgname, flavor) == name: - pkgname += "--{}".format(flavor) + if f"{pkgname}--{flavor}" == name: + pkgname += f"--{flavor}" elif pkgname == name: pass else: @@ -233,8 +233,8 @@ def install(name=None, pkgs=None, sources=None, **kwargs): if pkg_type == "repository": stem, branch = (pkg.split("%") + [""])[:2] base, flavor = (stem.split("--") + [""])[:2] - pkg = "{}--{}%{}".format(base, flavor, branch) - cmd = "pkg_add -x -I {}".format(pkg) + pkg = f"{base}--{flavor}%{branch}" + cmd = f"pkg_add -x -I {pkg}" out = __salt__["cmd.run_all"](cmd, python_shell=False, output_loglevel="trace") if out["retcode"] != 0 and out["stderr"]: errors.append(out["stderr"]) diff --git a/salt/modules/openbsdrcctl_service.py b/salt/modules/openbsdrcctl_service.py index 4baa0a4c56a..8a80cf57acd 100644 --- a/salt/modules/openbsdrcctl_service.py +++ b/salt/modules/openbsdrcctl_service.py @@ -56,7 +56,7 @@ def available(name): salt '*' service.available sshd """ - cmd = "{} get {}".format(_cmd(), name) + cmd = f"{_cmd()} get {name}" if __salt__["cmd.retcode"](cmd, ignore_retcode=True) == 2: return False return True @@ -88,7 +88,7 @@ def get_all(): """ ret = [] service = _cmd() - for svc in __salt__["cmd.run"]("{} ls all".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} ls all").splitlines(): ret.append(svc) return sorted(ret) @@ -105,7 +105,7 @@ def get_disabled(): """ ret = [] service = _cmd() - for svc in __salt__["cmd.run"]("{} ls off".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} ls off").splitlines(): ret.append(svc) return sorted(ret) @@ -122,7 +122,7 @@ def get_enabled(): """ ret = [] service = _cmd() - for svc in __salt__["cmd.run"]("{} ls on".format(service)).splitlines(): + for svc in __salt__["cmd.run"](f"{service} ls on").splitlines(): ret.append(svc) return sorted(ret) @@ -137,7 +137,7 @@ def start(name): salt '*' service.start """ - cmd = "{} -f start {}".format(_cmd(), name) + cmd = f"{_cmd()} -f start {name}" return not __salt__["cmd.retcode"](cmd) @@ -151,7 +151,7 @@ def stop(name): salt '*' service.stop """ - cmd = "{} stop {}".format(_cmd(), name) + cmd = f"{_cmd()} stop {name}" return not __salt__["cmd.retcode"](cmd) @@ -165,7 +165,7 @@ def restart(name): salt '*' service.restart """ - cmd = "{} -f restart {}".format(_cmd(), name) + cmd = f"{_cmd()} -f restart {name}" return not __salt__["cmd.retcode"](cmd) @@ -179,7 +179,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "{} reload {}".format(_cmd(), name) + cmd = f"{_cmd()} reload {name}" return not __salt__["cmd.retcode"](cmd) @@ -197,7 +197,7 @@ def status(name, sig=None): if sig: return bool(__salt__["status.pid"](sig)) - cmd = "{} check {}".format(_cmd(), name) + cmd = f"{_cmd()} check {name}" return not __salt__["cmd.retcode"](cmd, ignore_retcode=True) @@ -217,14 +217,14 @@ def enable(name, **kwargs): salt '*' service.enable salt '*' service.enable flags= """ - stat_cmd = "{} set {} status on".format(_cmd(), name) + stat_cmd = f"{_cmd()} set {name} status on" stat_retcode = __salt__["cmd.retcode"](stat_cmd) flag_retcode = None # only (re)set flags for services that have an rc.d(8) script - if os.path.exists("/etc/rc.d/{}".format(name)): + if os.path.exists(f"/etc/rc.d/{name}"): flags = _get_flags(**kwargs) - flag_cmd = "{} set {} flags {}".format(_cmd(), name, flags) + flag_cmd = f"{_cmd()} set {name} flags {flags}" flag_retcode = __salt__["cmd.retcode"](flag_cmd) return not any([stat_retcode, flag_retcode]) @@ -240,7 +240,7 @@ def disable(name, **kwargs): salt '*' service.disable """ - cmd = "{} set {} status off".format(_cmd(), name) + cmd = f"{_cmd()} set {name} status off" return not __salt__["cmd.retcode"](cmd) @@ -254,7 +254,7 @@ def disabled(name): salt '*' service.disabled """ - cmd = "{} get {} status".format(_cmd(), name) + cmd = f"{_cmd()} get {name} status" return not __salt__["cmd.retcode"](cmd, ignore_retcode=True) == 0 @@ -273,18 +273,16 @@ def enabled(name, **kwargs): salt '*' service.enabled salt '*' service.enabled flags= """ - cmd = "{} get {} status".format(_cmd(), name) + cmd = f"{_cmd()} get {name} status" if not __salt__["cmd.retcode"](cmd, ignore_retcode=True): # also consider a service disabled if the current flags are different # than the configured ones so we have a chance to update them flags = _get_flags(**kwargs) - cur_flags = __salt__["cmd.run_stdout"]("{} get {} flags".format(_cmd(), name)) + cur_flags = __salt__["cmd.run_stdout"](f"{_cmd()} get {name} flags") if format(flags) == format(cur_flags): return True if not flags: - def_flags = __salt__["cmd.run_stdout"]( - "{} getdef {} flags".format(_cmd(), name) - ) + def_flags = __salt__["cmd.run_stdout"](f"{_cmd()} getdef {name} flags") if format(cur_flags) == format(def_flags): return True diff --git a/salt/modules/openbsdservice.py b/salt/modules/openbsdservice.py index b68d217b448..70fe9981f54 100644 --- a/salt/modules/openbsdservice.py +++ b/salt/modules/openbsdservice.py @@ -8,7 +8,6 @@ The service module for OpenBSD `. """ - import fnmatch import logging import os @@ -56,7 +55,7 @@ def start(name): salt '*' service.start """ - cmd = "/etc/rc.d/{} -f start".format(name) + cmd = f"/etc/rc.d/{name} -f start" return not __salt__["cmd.retcode"](cmd) @@ -70,7 +69,7 @@ def stop(name): salt '*' service.stop """ - cmd = "/etc/rc.d/{} -f stop".format(name) + cmd = f"/etc/rc.d/{name} -f stop" return not __salt__["cmd.retcode"](cmd) @@ -84,7 +83,7 @@ def restart(name): salt '*' service.restart """ - cmd = "/etc/rc.d/{} -f restart".format(name) + cmd = f"/etc/rc.d/{name} -f restart" return not __salt__["cmd.retcode"](cmd) @@ -121,7 +120,7 @@ def status(name, sig=None): services = [name] results = {} for service in services: - cmd = "/etc/rc.d/{} -f check".format(service) + cmd = f"/etc/rc.d/{service} -f check" results[service] = not __salt__["cmd.retcode"](cmd, ignore_retcode=True) if contains_globbing: return results @@ -140,7 +139,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "/etc/rc.d/{} -f reload".format(name) + cmd = f"/etc/rc.d/{name} -f reload" return not __salt__["cmd.retcode"](cmd) @@ -220,7 +219,7 @@ def available(name): salt '*' service.available sshd """ - path = "/etc/rc.d/{}".format(name) + path = f"/etc/rc.d/{name}" return os.path.isfile(path) and os.access(path, os.X_OK) diff --git a/salt/modules/opkg.py b/salt/modules/opkg.py index 98882c85e96..7176c865347 100644 --- a/salt/modules/opkg.py +++ b/salt/modules/opkg.py @@ -107,7 +107,7 @@ def _update_nilrt_restart_state(): if os.path.exists(nisysapi_conf_d_path): with salt.utils.files.fopen( - "{}/sysapi.conf.d.count".format(NILRT_RESTARTCHECK_STATE_PATH), "w" + f"{NILRT_RESTARTCHECK_STATE_PATH}/sysapi.conf.d.count", "w" ) as fcount: fcount.write(str(len(os.listdir(nisysapi_conf_d_path)))) @@ -135,7 +135,7 @@ def _fingerprint_file(*, filename, fingerprint_dir): ) ) __salt__["cmd.shell"]( - "md5sum {} > {}/{}.md5sum".format(filename, fingerprint_dir, filename.name) + f"md5sum {filename} > {fingerprint_dir}/{filename.name}.md5sum" ) @@ -532,7 +532,7 @@ def install( else: to_install.append(pkgname) else: - pkgstr = "{}={}".format(pkgname, version_num) + pkgstr = f"{pkgname}={version_num}" cver = old.get(pkgname, "") if ( reinstall @@ -839,15 +839,15 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613 state = _get_state(target) if not state: - ret[target]["comment"] = "Package {} not currently held.".format(target) + ret[target]["comment"] = f"Package {target} not currently held." elif state != "hold": if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret[target]["comment"] = "Package {} is set to be held.".format(target) + ret[target]["comment"] = f"Package {target} is set to be held." else: result = _set_state(target, "hold") ret[target].update(changes=result[target], result=True) - ret[target]["comment"] = "Package {} is now being held.".format(target) + ret[target]["comment"] = f"Package {target} is now being held." else: ret[target].update(result=True) ret[target]["comment"] = "Package {} is already set to be held.".format( @@ -902,11 +902,11 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 state = _get_state(target) if not state: - ret[target]["comment"] = "Package {} does not have a state.".format(target) + ret[target]["comment"] = f"Package {target} does not have a state." elif state == "hold": if "test" in __opts__ and __opts__["test"]: ret[target].update(result=None) - ret["comment"] = "Package {} is set not to be held.".format(target) + ret["comment"] = f"Package {target} is set not to be held." else: result = _set_state(target, "ok") ret[target].update(changes=result[target], result=True) @@ -960,7 +960,7 @@ def _set_state(pkg, state): ret = {} valid_states = ("hold", "noprune", "user", "ok", "installed", "unpacked") if state not in valid_states: - raise SaltInvocationError("Invalid state: {}".format(state)) + raise SaltInvocationError(f"Invalid state: {state}") oldstate = _get_state(pkg) cmd = ["opkg", "flag"] cmd.append(state) @@ -1466,7 +1466,7 @@ def del_repo(repo, **kwargs): # pylint: disable=unused-argument refresh_db() return ret - return "Repo {} doesn't exist in the opkg repo lists".format(repo) + return f"Repo {repo} doesn't exist in the opkg repo lists" def mod_repo(repo, **kwargs): @@ -1514,9 +1514,9 @@ def mod_repo(repo, **kwargs): repostr += "src/gz" if source["compressed"] else "src" repo_alias = kwargs["alias"] if "alias" in kwargs else repo if " " in repo_alias: - repostr += ' "{}"'.format(repo_alias) + repostr += f' "{repo_alias}"' else: - repostr += " {}".format(repo_alias) + repostr += f" {repo_alias}" repostr += " {}".format(kwargs["uri"] if "uri" in kwargs else source["uri"]) trusted = kwargs.get("trusted") repostr = ( diff --git a/salt/modules/osquery.py b/salt/modules/osquery.py index 93c3774dc18..0bb7b6c994f 100644 --- a/salt/modules/osquery.py +++ b/salt/modules/osquery.py @@ -36,7 +36,7 @@ def _table_attrs(table): """ Helper function to find valid table attributes """ - cmd = ["osqueryi"] + ["--json"] + ["pragma table_info({})".format(table)] + cmd = ["osqueryi"] + ["--json"] + [f"pragma table_info({table})"] res = __salt__["cmd.run_all"](cmd) if res["retcode"] == 0: attrs = [] @@ -81,14 +81,14 @@ def _osquery_cmd(table, attrs=None, where=None, format="json"): for a in attrs: if a not in valid_attrs: ret["result"] = False - ret[ - "comment" - ] = "{} is not a valid attribute for table {}".format(a, table) + ret["comment"] = ( + f"{a} is not a valid attribute for table {table}" + ) return ret _attrs = ",".join(attrs) else: ret["result"] = False - ret["comment"] = "Invalid table {}.".format(table) + ret["comment"] = f"Invalid table {table}." return ret else: ret["comment"] = "attrs must be specified as a list." @@ -97,12 +97,12 @@ def _osquery_cmd(table, attrs=None, where=None, format="json"): else: _attrs = "*" - sql = "select {} from {}".format(_attrs, table) + sql = f"select {_attrs} from {table}" if where: - sql = "{} where {}".format(sql, where) + sql = f"{sql} where {where}" - sql = "{};".format(sql) + sql = f"{sql};" res = _osquery(sql) if res["result"]: diff --git a/salt/modules/pacmanpkg.py b/salt/modules/pacmanpkg.py index 298b3e7313a..857f6d07dfc 100644 --- a/salt/modules/pacmanpkg.py +++ b/salt/modules/pacmanpkg.py @@ -8,6 +8,7 @@ A module to wrap pacman calls, since Arch is the best *'pkg.install' is not available*), see :ref:`here `. """ + import copy import fnmatch import logging @@ -363,7 +364,6 @@ def group_info(name): def group_diff(name): - """ .. versionadded:: 2016.11.0 diff --git a/salt/modules/pagerduty_util.py b/salt/modules/pagerduty_util.py index 642e2ce2a5a..76e508b5e10 100644 --- a/salt/modules/pagerduty_util.py +++ b/salt/modules/pagerduty_util.py @@ -345,7 +345,7 @@ def create_or_update_resource( resource_id = _get_resource_id(resource) return _query( method="PUT", - action="{}/{}".format(resource_name, resource_id), + action=f"{resource_name}/{resource_id}", data=data_to_update, profile=profile, subdomain=subdomain, @@ -383,7 +383,7 @@ def delete_resource( resource_id = _get_resource_id(resource) return _query( method="DELETE", - action="{}/{}".format(resource_name, resource_id), + action=f"{resource_name}/{resource_id}", profile=profile, subdomain=subdomain, api_key=api_key, @@ -399,7 +399,7 @@ def resource_present( profile="pagerduty", subdomain=None, api_key=None, - **kwargs + **kwargs, ): """ Generic resource.present state method. Pagerduty state modules should be a thin wrapper over this method, @@ -442,7 +442,7 @@ def resource_absent( profile="pagerduty", subdomain=None, api_key=None, - **kwargs + **kwargs, ): """ Generic resource.absent state method. Pagerduty state modules should be a thin wrapper over this method, @@ -467,7 +467,7 @@ def resource_absent( ) if result is None: ret["result"] = True - ret["comment"] = "{} deleted".format(v) + ret["comment"] = f"{v} deleted" return ret elif result is True: continue diff --git a/salt/modules/pam.py b/salt/modules/pam.py index 58254917e35..50b09262856 100644 --- a/salt/modules/pam.py +++ b/salt/modules/pam.py @@ -54,7 +54,7 @@ def _parse(contents=None, file_name=None): position += 1 break else: - control_flag += " {}".format(part) + control_flag += f" {part}" else: control_flag = comps[1] position += 1 diff --git a/salt/modules/panos.py b/salt/modules/panos.py index 64be78723de..73dd05bd92f 100644 --- a/salt/modules/panos.py +++ b/salt/modules/panos.py @@ -27,7 +27,6 @@ through the XML API or through a brokered connection to Panorama. """ - import logging import time @@ -229,7 +228,7 @@ def delete_license(key_name=None): else: query = { "type": "op", - "cmd": "{}".format(key_name), + "cmd": f"{key_name}", } return __proxy__["panos.call"](query) @@ -775,7 +774,7 @@ def get_interface_counters(name="all"): """ query = { "type": "op", - "cmd": "{}".format(name), + "cmd": f"{name}", } return __proxy__["panos.call"](query) @@ -798,7 +797,7 @@ def get_interfaces(name="all"): """ query = { "type": "op", - "cmd": "{}".format(name), + "cmd": f"{name}", } return __proxy__["panos.call"](query) @@ -821,7 +820,7 @@ def get_job(jid=None): if not jid: raise CommandExecutionError("ID option must not be none.") - query = {"type": "op", "cmd": "{}".format(jid)} + query = {"type": "op", "cmd": f"{jid}"} return __proxy__["panos.call"](query) @@ -1170,7 +1169,7 @@ def get_predefined_application(application=None): query = { "type": "config", "action": "get", - "xpath": "/config/predefined/application/entry[@name='{}']".format(application), + "xpath": f"/config/predefined/application/entry[@name='{application}']", } return __proxy__["panos.call"](query) @@ -1800,7 +1799,7 @@ def save_device_config(filename=None): query = { "type": "op", - "cmd": "{}".format(filename), + "cmd": f"{filename}", } return __proxy__["panos.call"](query) @@ -1894,7 +1893,7 @@ def set_hostname(hostname=None, deploy=False): "xpath": ( "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system" ), - "element": "{}".format(hostname), + "element": f"{hostname}", } ret.update(__proxy__["panos.call"](query)) @@ -1938,7 +1937,7 @@ def set_management_icmp(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -1982,7 +1981,7 @@ def set_management_http(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2026,7 +2025,7 @@ def set_management_https(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2070,7 +2069,7 @@ def set_management_ocsp(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2114,7 +2113,7 @@ def set_management_snmp(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2158,7 +2157,7 @@ def set_management_ssh(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2202,7 +2201,7 @@ def set_management_telnet(enabled=True, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/service", - "element": "{}".format(value), + "element": f"{value}", } ret.update(__proxy__["panos.call"](query)) @@ -2447,7 +2446,7 @@ def set_permitted_ip(address=None, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/permitted-ip", - "element": "".format(address), + "element": f"", } ret.update(__proxy__["panos.call"](query)) @@ -2485,7 +2484,7 @@ def set_timezone(tz=None, deploy=False): "type": "config", "action": "set", "xpath": "/config/devices/entry[@name='localhost.localdomain']/deviceconfig/system/timezone", - "element": "{}".format(tz), + "element": f"{tz}", } ret.update(__proxy__["panos.call"](query)) @@ -2535,10 +2534,10 @@ def test_fib_route(ip=None, vr="vr1"): xpath = "" if ip: - xpath += "{}".format(ip) + xpath += f"{ip}" if vr: - xpath += "{}".format(vr) + xpath += f"{vr}" xpath += "" @@ -2594,35 +2593,35 @@ def test_security_policy( xpath = "" if sourcezone: - xpath += "{}".format(sourcezone) + xpath += f"{sourcezone}" if destinationzone: - xpath += "{}".format(destinationzone) + xpath += f"{destinationzone}" if source: - xpath += "{}".format(source) + xpath += f"{source}" if destination: - xpath += "{}".format(destination) + xpath += f"{destination}" if protocol: - xpath += "{}".format(protocol) + xpath += f"{protocol}" if port: - xpath += "{}".format(port) + xpath += f"{port}" if application: - xpath += "{}".format(application) + xpath += f"{application}" if category: - xpath += "{}".format(category) + xpath += f"{category}" if allrules: xpath += "yes" xpath += "" - query = {"type": "op", "vsys": "vsys{}".format(vsys), "cmd": xpath} + query = {"type": "op", "vsys": f"vsys{vsys}", "cmd": xpath} return __proxy__["panos.call"](query) diff --git a/salt/modules/parallels.py b/salt/modules/parallels.py index 27f187bacae..2f8ddf80556 100644 --- a/salt/modules/parallels.py +++ b/salt/modules/parallels.py @@ -277,7 +277,7 @@ def exists(name, runas=None): """ vm_info = list_vms(name, info=True, runas=runas).splitlines() for info_line in vm_info: - if "Name: {}".format(name) in info_line: + if f"Name: {name}" in info_line: return True return False @@ -453,7 +453,7 @@ def snapshot_id_to_name(name, snap_id, strict=False, runas=None): name = salt.utils.data.decode(name) if not re.match(GUID_REGEX, snap_id): raise SaltInvocationError( - 'Snapshot ID "{}" is not a GUID'.format(salt.utils.data.decode(snap_id)) + f'Snapshot ID "{salt.utils.data.decode(snap_id)}" is not a GUID' ) # Get the snapshot information of the snapshot having the requested ID @@ -461,9 +461,7 @@ def snapshot_id_to_name(name, snap_id, strict=False, runas=None): # Parallels desktop returned no information for snap_id if not info: - raise SaltInvocationError( - 'No snapshots for VM "{}" have ID "{}"'.format(name, snap_id) - ) + raise SaltInvocationError(f'No snapshots for VM "{name}" have ID "{snap_id}"') # Try to interpret the information try: @@ -540,7 +538,7 @@ def snapshot_name_to_id(name, snap_name, strict=False, runas=None): # non-singular names if not named_ids: raise SaltInvocationError( - 'No snapshots for VM "{}" have name "{}"'.format(name, snap_name) + f'No snapshots for VM "{name}" have name "{snap_name}"' ) elif len(named_ids) == 1: return named_ids[0] @@ -634,7 +632,7 @@ def list_snapshots(name, snap_name=None, tree=False, names=False, runas=None): ret = "{:<38} {}\n".format("Snapshot ID", "Snapshot Name") for snap_id in snap_ids: snap_name = snapshot_id_to_name(name, snap_id, runas=runas) - ret += "{{{0}}} {1}\n".format(snap_id, salt.utils.data.decode(snap_name)) + ret += f"{{{snap_id}}} {salt.utils.data.decode(snap_name)}\n" return ret # Return information directly from parallels desktop diff --git a/salt/modules/parted_partition.py b/salt/modules/parted_partition.py index 02c5ab5a49d..1c9a135b7b8 100644 --- a/salt/modules/parted_partition.py +++ b/salt/modules/parted_partition.py @@ -140,9 +140,7 @@ def _validate_partition_boundary(boundary): unit = match.group(2) if not unit or unit in VALID_UNITS: return - raise CommandExecutionError( - 'Invalid partition boundary passed: "{}"'.format(boundary) - ) + raise CommandExecutionError(f'Invalid partition boundary passed: "{boundary}"') def probe(*devices): @@ -186,9 +184,9 @@ def list_(device, unit=None): if unit: if unit not in VALID_UNITS: raise CommandExecutionError("Invalid unit passed to partition.part_list") - cmd = "parted -m -s {} unit {} print".format(device, unit) + cmd = f"parted -m -s {device} unit {unit} print" else: - cmd = "parted -m -s {} print".format(device) + cmd = f"parted -m -s {device} print" out = __salt__["cmd.run_stdout"](cmd).splitlines() ret = {"info": {}, "partitions": {}} @@ -268,7 +266,7 @@ def align_check(device, part_type, partition): except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid partition passed to partition.align_check") - cmd = "parted -m {} align-check {} {}".format(device, part_type, partition) + cmd = f"parted -m {device} align-check {part_type} {partition}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -290,7 +288,7 @@ def check(device, minor): except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.check") - cmd = "parted -m -s {} check {}".format(device, minor) + cmd = f"parted -m -s {device} check {minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -315,7 +313,7 @@ def cp(device, from_minor, to_minor): # pylint: disable=C0103 except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.cp") - cmd = "parted -m -s {} cp {} {}".format(device, from_minor, to_minor) + cmd = f"parted -m -s {device} cp {from_minor} {to_minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -344,7 +342,7 @@ def get_id(device, minor): except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.get_id") - cmd = "sfdisk --print-id {} {}".format(device, minor) + cmd = f"sfdisk --print-id {device} {minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -376,7 +374,7 @@ def set_id(device, minor, system_id): if system_id not in system_types(): raise CommandExecutionError("Invalid system_id passed to partition.set_id") - cmd = "sfdisk --change-id {} {} {}".format(device, minor, system_id) + cmd = f"sfdisk --change-id {device} {minor} {system_id}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -451,11 +449,11 @@ def mkfs(device, fs_type): if fs_type == "linux-swap": mkfs_cmd = "mkswap" else: - mkfs_cmd = "mkfs.{}".format(fs_type) + mkfs_cmd = f"mkfs.{fs_type}" if not salt.utils.path.which(mkfs_cmd): - return "Error: {} is unavailable.".format(mkfs_cmd) - cmd = "{} {}".format(mkfs_cmd, device) + return f"Error: {mkfs_cmd} is unavailable." + cmd = f"{mkfs_cmd} {device}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -582,7 +580,7 @@ def name(device, partition, name): if letter not in valid: raise CommandExecutionError("Invalid characters passed to partition.name") - cmd = '''parted -m -s {} name {} "'{}'"'''.format(device, partition, name) + cmd = f'''parted -m -s {device} name {partition} "'{name}'"''' out = __salt__["cmd.run"](cmd).splitlines() return out @@ -603,7 +601,7 @@ def rescue(device, start, end): _validate_partition_boundary(start) _validate_partition_boundary(end) - cmd = "parted -m -s {} rescue {} {}".format(device, start, end) + cmd = f"parted -m -s {device} rescue {start} {end}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -633,9 +631,7 @@ def resize(device, minor, start, end): _validate_partition_boundary(start) _validate_partition_boundary(end) - out = __salt__["cmd.run"]( - "parted -m -s -- {} resize {} {} {}".format(device, minor, start, end) - ) + out = __salt__["cmd.run"](f"parted -m -s -- {device} resize {minor} {start} {end}") return out.splitlines() @@ -656,7 +652,7 @@ def rm(device, minor): # pylint: disable=C0103 except Exception: # pylint: disable=broad-except raise CommandExecutionError("Invalid minor number passed to partition.rm") - cmd = "parted -m -s {} rm {}".format(device, minor) + cmd = f"parted -m -s {device} rm {minor}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -709,7 +705,7 @@ def set_(device, minor, flag, state): if state not in {"on", "off"}: raise CommandExecutionError("Invalid state passed to partition.set") - cmd = "parted -m -s {} set {} {} {}".format(device, minor, flag, state) + cmd = f"parted -m -s {device} set {minor} {flag} {state}" out = __salt__["cmd.run"](cmd).splitlines() return out @@ -737,7 +733,7 @@ def toggle(device, partition, flag): if flag not in VALID_PARTITION_FLAGS: raise CommandExecutionError("Invalid flag passed to partition.toggle") - cmd = "parted -m -s {} toggle {} {}".format(device, partition, flag) + cmd = f"parted -m -s {device} toggle {partition} {flag}" out = __salt__["cmd.run"](cmd).splitlines() return out diff --git a/salt/modules/pcs.py b/salt/modules/pcs.py index 4e3c74158a3..78415307dda 100644 --- a/salt/modules/pcs.py +++ b/salt/modules/pcs.py @@ -10,7 +10,6 @@ Pacemaker/Cororsync conifguration system (PCS) .. versionadded:: 2016.3.0 """ - import logging import salt.utils.path @@ -160,7 +159,7 @@ def item_create( if isinstance(extra_args, (list, tuple)): # constraint command needs item_id in format 'id=", "").split(";") - out = __salt__["cmd.run"]( - "networksetup -getproxybypassdomains {}".format(network_service) - ) + out = __salt__["cmd.run"](f"networksetup -getproxybypassdomains {network_service}") return out.split("\n") diff --git a/salt/modules/ps.py b/salt/modules/ps.py index d79d8c932c1..b2eccab73d2 100644 --- a/salt/modules/ps.py +++ b/salt/modules/ps.py @@ -6,7 +6,6 @@ See http://code.google.com/p/psutil. - python-utmp package (optional) """ - import datetime import re import time diff --git a/salt/modules/publish.py b/salt/modules/publish.py index cc424cc3835..c3aa8757b2f 100644 --- a/salt/modules/publish.py +++ b/salt/modules/publish.py @@ -94,7 +94,7 @@ def _publish( matching_master_uris = [ master for master in __opts__["master_uri_list"] - if "//{}:".format(via_master) in master + if f"//{via_master}:" in master ] if not matching_master_uris: @@ -144,7 +144,7 @@ def _publish( try: peer_data = channel.send(load) except SaltReqTimeoutError: - return "'{}' publish timed out".format(fun) + return f"'{fun}' publish timed out" if not peer_data: return {} # CLI args are passed as strings, re-cast to keep time.sleep happy @@ -348,4 +348,4 @@ def runner(fun, arg=None, timeout=5): try: return channel.send(load) except SaltReqTimeoutError: - return "'{}' runner publish timed out".format(fun) + return f"'{fun}' runner publish timed out" diff --git a/salt/modules/puppet.py b/salt/modules/puppet.py index b97eaa3ff60..82df2986f2c 100644 --- a/salt/modules/puppet.py +++ b/salt/modules/puppet.py @@ -2,7 +2,6 @@ Execute puppet routines """ - import datetime import logging import os @@ -85,15 +84,15 @@ class _Puppet: ) args = " ".join(self.subcmd_args) - args += "".join([" --{}".format(k) for k in self.args]) # single spaces - args += "".join([" --{} {}".format(k, v) for k, v in self.kwargs.items()]) + args += "".join([f" --{k}" for k in self.args]) # single spaces + args += "".join([f" --{k} {v}" for k, v in self.kwargs.items()]) # Ensure that the puppet call will return 0 in case of exit code 2 if salt.utils.platform.is_windows(): return "cmd /V:ON /c {} {} ^& if !ERRORLEVEL! EQU 2 (EXIT 0) ELSE (EXIT /B)".format( cmd, args ) - return "({} {}) || test $? -eq 2".format(cmd, args) + return f"({cmd} {args}) || test $? -eq 2" def arguments(self, args=None): """ @@ -194,7 +193,7 @@ def enable(): try: os.remove(puppet.disabled_lockfile) except OSError as exc: - msg = "Failed to enable: {}".format(exc) + msg = f"Failed to enable: {exc}" log.error(msg) raise CommandExecutionError(msg) else: @@ -230,7 +229,7 @@ def disable(message=None): try: # Puppet chokes when no valid json is found msg = ( - '{{"disabled_message":"{0}"}}'.format(message) + f'{{"disabled_message":"{message}"}}' if message is not None else "{}" ) @@ -238,7 +237,7 @@ def disable(message=None): lockfile.close() return True except OSError as exc: - msg = "Failed to disable: {}".format(exc) + msg = f"Failed to disable: {exc}" log.error(msg) raise CommandExecutionError(msg) @@ -320,11 +319,9 @@ def summary(): result["resources"] = report["resources"] except salt.utils.yaml.YAMLError as exc: - raise CommandExecutionError( - "YAML error parsing puppet run summary: {}".format(exc) - ) + raise CommandExecutionError(f"YAML error parsing puppet run summary: {exc}") except OSError as exc: - raise CommandExecutionError("Unable to read puppet run summary: {}".format(exc)) + raise CommandExecutionError(f"Unable to read puppet run summary: {exc}") return result @@ -358,7 +355,7 @@ def facts(puppet=False): """ ret = {} opt_puppet = "--puppet" if puppet else "" - cmd_ret = __salt__["cmd.run_all"]("facter {}".format(opt_puppet)) + cmd_ret = __salt__["cmd.run_all"](f"facter {opt_puppet}") if cmd_ret["retcode"] != 0: raise CommandExecutionError(cmd_ret["stderr"]) @@ -389,9 +386,7 @@ def fact(name, puppet=False): salt '*' puppet.fact kernel """ opt_puppet = "--puppet" if puppet else "" - ret = __salt__["cmd.run_all"]( - "facter {} {}".format(opt_puppet, name), python_shell=False - ) + ret = __salt__["cmd.run_all"](f"facter {opt_puppet} {name}", python_shell=False) if ret["retcode"] != 0: raise CommandExecutionError(ret["stderr"]) diff --git a/salt/modules/purefb.py b/salt/modules/purefb.py index 787c77446b8..cf9cdb4e2e0 100644 --- a/salt/modules/purefb.py +++ b/salt/modules/purefb.py @@ -150,7 +150,7 @@ def _get_snapshot(name, suffix, blade): or None """ try: - filt = "source='{}' and suffix='{}'".format(name, suffix) + filt = f"source='{name}' and suffix='{suffix}'" res = blade.file_system_snapshots.list_file_system_snapshots(filter=filt) return res.items[0] except rest.ApiException: diff --git a/salt/modules/pushbullet.py b/salt/modules/pushbullet.py index b716e667d04..ff58bbda489 100644 --- a/salt/modules/pushbullet.py +++ b/salt/modules/pushbullet.py @@ -21,7 +21,6 @@ For example: """ - import logging try: diff --git a/salt/modules/pushover_notify.py b/salt/modules/pushover_notify.py index a3448b80dcc..ad06f4870cd 100644 --- a/salt/modules/pushover_notify.py +++ b/salt/modules/pushover_notify.py @@ -15,7 +15,6 @@ Module for sending messages to Pushover (https://www.pushover.net) token: abAHuZyCLtdH8P4zhmFZmgUHUsv1ei8 """ - import logging import urllib.parse diff --git a/salt/modules/pw_group.py b/salt/modules/pw_group.py index 99128d196bd..7c6d1fd5292 100644 --- a/salt/modules/pw_group.py +++ b/salt/modules/pw_group.py @@ -64,8 +64,8 @@ def add(name, gid=None, **kwargs): cmd = "pw groupadd " if gid: - cmd += "-g {} ".format(gid) - cmd = "{} -n {}".format(cmd, name) + cmd += f"-g {gid} " + cmd = f"{cmd} -n {name}" ret = __salt__["cmd.run_all"](cmd, python_shell=False) return not ret["retcode"] @@ -81,7 +81,7 @@ def delete(name): salt '*' group.delete foo """ - ret = __salt__["cmd.run_all"]("pw groupdel {}".format(name), python_shell=False) + ret = __salt__["cmd.run_all"](f"pw groupdel {name}", python_shell=False) return not ret["retcode"] @@ -142,7 +142,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) if gid == pre_gid: return True - cmd = "pw groupmod {} -g {}".format(name, gid) + cmd = f"pw groupmod {name} -g {gid}" __salt__["cmd.run"](cmd, python_shell=False) post_gid = __salt__["file.group_to_gid"](name) if post_gid != pre_gid: @@ -165,7 +165,7 @@ def adduser(name, username): """ # Note: pw exits with code 65 if group is unknown retcode = __salt__["cmd.retcode"]( - "pw groupmod {} -m {}".format(name, username), python_shell=False + f"pw groupmod {name} -m {username}", python_shell=False ) return not retcode @@ -191,7 +191,7 @@ def deluser(name, username): # Note: pw exits with code 65 if group is unknown retcode = __salt__["cmd.retcode"]( - "pw groupmod {} -d {}".format(name, username), python_shell=False + f"pw groupmod {name} -d {username}", python_shell=False ) return not retcode @@ -214,7 +214,7 @@ def members(name, members_list): """ retcode = __salt__["cmd.retcode"]( - "pw groupmod {} -M {}".format(name, members_list), python_shell=False + f"pw groupmod {name} -M {members_list}", python_shell=False ) return not retcode diff --git a/salt/modules/pw_user.py b/salt/modules/pw_user.py index 6506452db56..cebb46c993b 100644 --- a/salt/modules/pw_user.py +++ b/salt/modules/pw_user.py @@ -75,7 +75,7 @@ def _get_gecos(name): try: gecos_field = pwd.getpwnam(name).pw_gecos.split(",", 3) except KeyError: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if not gecos_field: return {} else: @@ -136,7 +136,7 @@ def add( homephone="", createhome=True, loginclass=None, - **kwargs + **kwargs, ): """ Add a user to the minion @@ -238,7 +238,7 @@ def chuid(name, uid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if uid == pre_info["uid"]: return True cmd = ["pw", "usermod", "-u", uid, "-n", name] @@ -258,7 +258,7 @@ def chgid(name, gid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if gid == pre_info["gid"]: return True cmd = ["pw", "usermod", "-g", gid, "-n", name] @@ -278,7 +278,7 @@ def chshell(name, shell): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if shell == pre_info["shell"]: return True cmd = ["pw", "usermod", "-s", shell, "-n", name] @@ -309,7 +309,7 @@ def chhome(name, home, persist=False): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if home == pre_info["home"]: return True cmd = ["pw", "usermod", name, "-d", home] @@ -419,7 +419,7 @@ def chloginclass(name, loginclass, root=None): if loginclass == get_loginclass(name): return True - cmd = ["pw", "usermod", "-L", "{}".format(loginclass), "-n", "{}".format(name)] + cmd = ["pw", "usermod", "-L", f"{loginclass}", "-n", f"{name}"] __salt__["cmd.run"](cmd, python_shell=False) @@ -518,10 +518,10 @@ def rename(name, new_name): """ current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") cmd = ["pw", "usermod", "-l", new_name, "-n", name] __salt__["cmd.run"](cmd) post_info = info(new_name) diff --git a/salt/modules/pyenv.py b/salt/modules/pyenv.py index df39db80333..30d569b5700 100644 --- a/salt/modules/pyenv.py +++ b/salt/modules/pyenv.py @@ -32,14 +32,12 @@ def _pyenv_exec(command, args="", env=None, runas=None, ret=None): path = _pyenv_path(runas) if env: - env = " {}".format(env) + env = f" {env}" env = env or "" - binary = "env PYENV_ROOT={}{} {}".format(path, env, binary) + binary = f"env PYENV_ROOT={path}{env} {binary}" - result = __salt__["cmd.run_all"]( - "{} {} {}".format(binary, command, args), runas=runas - ) + result = __salt__["cmd.run_all"](f"{binary} {command} {args}", runas=runas) if isinstance(ret, dict): ret.update(result) @@ -53,7 +51,7 @@ def _pyenv_exec(command, args="", env=None, runas=None, ret=None): def _pyenv_bin(runas=None): path = _pyenv_path(runas) - return "{}/bin/pyenv".format(path) + return f"{path}/bin/pyenv" def _pyenv_path(runas=None): @@ -61,7 +59,7 @@ def _pyenv_path(runas=None): if runas in (None, "root"): path = __salt__["config.option"]("pyenv.root") or "/usr/local/pyenv" else: - path = __salt__["config.option"]("pyenv.root") or "~{}/.pyenv".format(runas) + path = __salt__["config.option"]("pyenv.root") or f"~{runas}/.pyenv" return os.path.expanduser(path) @@ -71,7 +69,7 @@ def _install_pyenv(path, runas=None): return True return 0 == __salt__["cmd.retcode"]( - "git clone https://github.com/yyuu/pyenv.git {}".format(path), runas=runas + f"git clone https://github.com/yyuu/pyenv.git {path}", runas=runas ) @@ -80,17 +78,17 @@ def _update_pyenv(path, runas=None): return False return 0 == __salt__["cmd.retcode"]( - "cd {} && git pull".format(shlex.quote(path)), runas=runas + f"cd {shlex.quote(path)} && git pull", runas=runas ) def _update_python_build(path, runas=None): - path = "{}/plugins/python-build".format(path) + path = f"{path}/plugins/python-build" if not os.path.isdir(path): return False return 0 == __salt__["cmd.retcode"]( - "cd {} && git pull".format(shlex.quote(path)), runas=runas + f"cd {shlex.quote(path)} && git pull", runas=runas ) @@ -193,7 +191,7 @@ def uninstall_python(python, runas=None): """ python = re.sub(r"^python-", "", python) - args = "--force {}".format(python) + args = f"--force {python}" _pyenv_exec("uninstall", args, runas=runas) return True @@ -287,7 +285,7 @@ def do(cmdline=None, runas=None): for cmd in cmd_split: quoted_line = quoted_line + " " + shlex.quote(cmd) result = __salt__["cmd.run_all"]( - "env PATH={}/shims:$PATH {}".format(shlex.quote(path), quoted_line), + f"env PATH={shlex.quote(path)}/shims:$PATH {quoted_line}", runas=runas, python_shell=True, ) @@ -311,7 +309,7 @@ def do_with_python(python, cmdline, runas=None): salt '*' pyenv.do_with_python 2.0.0-p0 'gem list bundler' deploy """ if python: - cmd = "PYENV_VERSION={} {}".format(python, cmdline) + cmd = f"PYENV_VERSION={python} {cmdline}" else: cmd = cmdline diff --git a/salt/modules/qemu_img.py b/salt/modules/qemu_img.py index 1424929e45a..4f4b0dde628 100644 --- a/salt/modules/qemu_img.py +++ b/salt/modules/qemu_img.py @@ -42,7 +42,7 @@ def make_image(location, size, fmt): if not os.path.isdir(os.path.dirname(location)): return "" if not __salt__["cmd.retcode"]( - "qemu-img create -f {} {} {}M".format(fmt, location, size), + f"qemu-img create -f {fmt} {location} {size}M", python_shell=False, ): return location diff --git a/salt/modules/qemu_nbd.py b/salt/modules/qemu_nbd.py index 9a76d68cad5..375cbdeb3ab 100644 --- a/salt/modules/qemu_nbd.py +++ b/salt/modules/qemu_nbd.py @@ -5,7 +5,6 @@ The qemu system comes with powerful tools, such as qemu-img and qemu-nbd which are used here to build up kvm images. """ - import glob import logging import os @@ -52,14 +51,14 @@ def connect(image): fdisk = "fdisk -l" __salt__["cmd.run"]("modprobe nbd max_part=63") for nbd in glob.glob("/dev/nbd?"): - if __salt__["cmd.retcode"]("{} {}".format(fdisk, nbd)): + if __salt__["cmd.retcode"](f"{fdisk} {nbd}"): while True: # Sometimes nbd does not "take hold", loop until we can verify __salt__["cmd.run"]( - "qemu-nbd -c {} {}".format(nbd, image), + f"qemu-nbd -c {nbd} {image}", python_shell=False, ) - if not __salt__["cmd.retcode"]("{} {}".format(fdisk, nbd)): + if not __salt__["cmd.retcode"](f"{fdisk} {nbd}"): break return nbd log.warning("Could not connect image: %s", image) @@ -78,13 +77,13 @@ def mount(nbd, root=None): salt '*' qemu_nbd.mount /dev/nbd0 """ __salt__["cmd.run"]( - "partprobe {}".format(nbd), + f"partprobe {nbd}", python_shell=False, ) ret = {} if root is None: root = os.path.join(tempfile.gettempdir(), "nbd", os.path.basename(nbd)) - for part in glob.glob("{}p*".format(nbd)): + for part in glob.glob(f"{nbd}p*"): m_pt = os.path.join(root, os.path.basename(part)) time.sleep(1) mnt = __salt__["mount.mount"](m_pt, part, True) @@ -133,5 +132,5 @@ def clear(mnt): if ret: return ret for nbd in nbds: - __salt__["cmd.run"]("qemu-nbd -d {}".format(nbd), python_shell=False) + __salt__["cmd.run"](f"qemu-nbd -d {nbd}", python_shell=False) return ret diff --git a/salt/modules/quota.py b/salt/modules/quota.py index 931ae63d0ab..ec9f20ca3fd 100644 --- a/salt/modules/quota.py +++ b/salt/modules/quota.py @@ -48,7 +48,7 @@ def _parse_quota(mount, opts): """ Parse the output from repquota. Requires that -u -g are passed in """ - cmd = "repquota -vp {} {}".format(opts, mount) + cmd = f"repquota -vp {opts} {mount}" out = __salt__["cmd.run"](cmd, python_shell=False).splitlines() mode = "header" @@ -200,7 +200,7 @@ def on(device): salt '*' quota.on """ - cmd = "quotaon {}".format(device) + cmd = f"quotaon {device}" __salt__["cmd.run"](cmd, python_shell=False) return True @@ -215,7 +215,7 @@ def off(device): salt '*' quota.off """ - cmd = "quotaoff {}".format(device) + cmd = f"quotaoff {device}" __salt__["cmd.run"](cmd, python_shell=False) return True @@ -231,7 +231,7 @@ def get_mode(device): salt '*' quota.get_mode """ ret = {} - cmd = "quotaon -p {}".format(device) + cmd = f"quotaon -p {device}" out = __salt__["cmd.run"](cmd, python_shell=False) for line in out.splitlines(): comps = line.strip().split() diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index e0a9304bd54..5ad42678489 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -44,11 +44,9 @@ def __virtual__(): ) (dir_path, value_type) = winreg.QueryValueEx(key, "Install_Dir") if value_type != winreg.REG_SZ: - raise TypeError( - "Invalid RabbitMQ Server directory type: {}".format(value_type) - ) + raise TypeError(f"Invalid RabbitMQ Server directory type: {value_type}") if not os.path.isdir(dir_path): - raise OSError("RabbitMQ directory not found: {}".format(dir_path)) + raise OSError(f"RabbitMQ directory not found: {dir_path}") subdir_match = "" for name in os.listdir(dir_path): if name.startswith("rabbitmq_server-"): @@ -58,7 +56,7 @@ def __virtual__(): subdir_match = subdir_path if not subdir_match: raise OSError( - '"rabbitmq_server-*" subdirectory not found in: {}'.format(dir_path) + f'"rabbitmq_server-*" subdirectory not found in: {dir_path}' ) RABBITMQCTL = os.path.join(subdir_match, "sbin", "rabbitmqctl.bat") RABBITMQ_PLUGINS = os.path.join( @@ -86,7 +84,7 @@ def _check_response(response): ) else: if "Error" in response: - raise CommandExecutionError("RabbitMQ command failed: {}".format(response)) + raise CommandExecutionError(f"RabbitMQ command failed: {response}") def _format_response(response, msg): @@ -99,7 +97,7 @@ def _format_response(response, msg): response = response["stdout"] else: if "Error" in response: - raise CommandExecutionError("RabbitMQ command failed: {}".format(response)) + raise CommandExecutionError(f"RabbitMQ command failed: {response}") return {msg: response} @@ -237,8 +235,8 @@ def list_users(runas=None): ) # func to get tags from string such as "[admin, monitoring]" - func = ( - lambda string: [x.strip() for x in string[1:-1].split(",")] + func = lambda string: ( + [x.strip() for x in string[1:-1].split(",")] if "," in string else [x for x in string[1:-1].split(" ")] ) @@ -378,7 +376,7 @@ def add_user(name, password=None, runas=None): # command,\r\noperable program or batch file. # Work around this by using a shell and a quoted command. python_shell = True - cmd = '"{}" add_user "{}" "{}"'.format(RABBITMQCTL, name, password) + cmd = f'"{RABBITMQCTL}" add_user "{name}" "{password}"' else: python_shell = False cmd = [RABBITMQCTL, "add_user", name, password] @@ -448,7 +446,7 @@ def change_password(name, password, runas=None): # command,\r\noperable program or batch file. # Work around this by using a shell and a quoted command. python_shell = True - cmd = '"{}" change_password "{}" "{}"'.format(RABBITMQCTL, name, password) + cmd = f'"{RABBITMQCTL}" change_password "{name}" "{password}"' else: python_shell = False cmd = [RABBITMQCTL, "change_password", name, password] @@ -539,7 +537,7 @@ def check_password(name, password, runas=None): # command,\r\noperable program or batch file. # Work around this by using a shell and a quoted command. python_shell = True - cmd = '"{}" authenticate_user "{}" "{}"'.format(RABBITMQCTL, name, password) + cmd = f'"{RABBITMQCTL}" authenticate_user "{name}" "{password}"' else: python_shell = False cmd = [RABBITMQCTL, "authenticate_user", name, password] @@ -786,7 +784,7 @@ def join_cluster(host, user="rabbit", ram_node=None, runas=None): cmd = [RABBITMQCTL, "join_cluster"] if ram_node: cmd.append("--ram") - cmd.append("{}@{}".format(user, host)) + cmd.append(f"{user}@{host}") if runas is None and not salt.utils.platform.is_windows(): runas = salt.utils.user.get_user() diff --git a/salt/modules/rallydev.py b/salt/modules/rallydev.py index 6461fb133f5..dc92ae93185 100644 --- a/salt/modules/rallydev.py +++ b/salt/modules/rallydev.py @@ -12,7 +12,6 @@ Requires a ``username`` and a ``password`` in ``/etc/salt/minion``: password: 123pass """ - import logging import salt.utils.http @@ -81,7 +80,7 @@ def _query( path += action if command: - path += "/{}".format(command) + path += f"/{command}" log.debug("RallyDev URL: %s", path) diff --git a/salt/modules/random_org.py b/salt/modules/random_org.py index 494c323eba5..91db8756a41 100644 --- a/salt/modules/random_org.py +++ b/salt/modules/random_org.py @@ -15,6 +15,7 @@ Module for retrieving random information from Random.org api_key: 7be1402d-5719-5bd3-a306-3def9f135da5 api_version: 1 """ + import http.client import logging import urllib.request @@ -205,7 +206,7 @@ def generateIntegers(api_key=None, api_version=None, **kwargs): for item in ["number", "minimum", "maximum"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Rquired argument, {} is missing.".format(item) + ret["message"] = f"Rquired argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 10000: @@ -218,9 +219,9 @@ def generateIntegers(api_key=None, api_version=None, **kwargs): or not -1000000000 <= kwargs["minimum"] <= 1000000000 ): ret["res"] = False - ret[ - "message" - ] = "Minimum argument must be between -1,000,000,000 and 1,000,000,000" + ret["message"] = ( + "Minimum argument must be between -1,000,000,000 and 1,000,000,000" + ) return ret if ( @@ -228,9 +229,9 @@ def generateIntegers(api_key=None, api_version=None, **kwargs): or not -1000000000 <= kwargs["maximum"] <= 1000000000 ): ret["res"] = False - ret[ - "message" - ] = "Maximum argument must be between -1,000,000,000 and 1,000,000,000" + ret["message"] = ( + "Maximum argument must be between -1,000,000,000 and 1,000,000,000" + ) return ret if "base" in kwargs: @@ -331,7 +332,7 @@ def generateStrings(api_key=None, api_version=None, **kwargs): for item in ["number", "length", "characters"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 10000: @@ -421,7 +422,7 @@ def generateUUIDs(api_key=None, api_version=None, **kwargs): for item in ["number"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if isinstance(api_version, int): @@ -502,7 +503,7 @@ def generateDecimalFractions(api_key=None, api_version=None, **kwargs): for item in ["number", "decimalPlaces"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not isinstance(kwargs["number"], int) or not 1 <= kwargs["number"] <= 10000: @@ -596,7 +597,7 @@ def generateGaussians(api_key=None, api_version=None, **kwargs): for item in ["number", "mean", "standardDeviation", "significantDigits"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 10000: @@ -614,9 +615,9 @@ def generateGaussians(api_key=None, api_version=None, **kwargs): or not -1000000 <= kwargs["standardDeviation"] <= 1000000 ): ret["res"] = False - ret[ - "message" - ] = "The distribution's standard deviation must be between -1000000 and 1000000" + ret["message"] = ( + "The distribution's standard deviation must be between -1000000 and 1000000" + ) return ret if ( @@ -696,7 +697,7 @@ def generateBlobs(api_key=None, api_version=None, **kwargs): for item in ["number", "size"]: if item not in kwargs: ret["res"] = False - ret["message"] = "Required argument, {} is missing.".format(item) + ret["message"] = f"Required argument, {item} is missing." return ret if not _numeric(kwargs["number"]) or not 1 <= kwargs["number"] <= 100: diff --git a/salt/modules/rbenv.py b/salt/modules/rbenv.py index e0bc1e82503..1f3ee003818 100644 --- a/salt/modules/rbenv.py +++ b/salt/modules/rbenv.py @@ -9,7 +9,6 @@ http://misheska.com/blog/2013/06/15/using-rbenv-to-manage-multiple-versions-of-r .. versionadded:: 0.16.0 """ - import logging import os import re @@ -76,7 +75,7 @@ def _parse_env(env): def _rbenv_bin(runas=None): path = _rbenv_path(runas) - return "{}/bin/rbenv".format(path) + return f"{path}/bin/rbenv" def _rbenv_path(runas=None): @@ -84,7 +83,7 @@ def _rbenv_path(runas=None): if runas in (None, "root"): path = __salt__["config.option"]("rbenv.root") or "/usr/local/rbenv" else: - path = __salt__["config.option"]("rbenv.root") or "~{}/.rbenv".format(runas) + path = __salt__["config.option"]("rbenv.root") or f"~{runas}/.rbenv" return os.path.expanduser(path) @@ -120,7 +119,7 @@ def _install_rbenv(path, runas=None): def _install_ruby_build(path, runas=None): - path = "{}/plugins/ruby-build".format(path) + path = f"{path}/plugins/ruby-build" if os.path.isdir(path): return True @@ -141,7 +140,7 @@ def _update_rbenv(path, runas=None): def _update_ruby_build(path, runas=None): - path = "{}/plugins/ruby-build".format(path) + path = f"{path}/plugins/ruby-build" if not os.path.isdir(path): return False diff --git a/salt/modules/rdp.py b/salt/modules/rdp.py index e0c4a5d21a5..81dc1c77c6a 100644 --- a/salt/modules/rdp.py +++ b/salt/modules/rdp.py @@ -50,9 +50,7 @@ def _psrdp(cmd): "-Namespace root\\CIMV2\\TerminalServices -Computer . " "-Authentication 6 -ErrorAction Stop" ) - return __salt__["cmd.run"]( - "{} ; {}".format(rdp, cmd), shell="powershell", python_shell=True - ) + return __salt__["cmd.run"](f"{rdp} ; {cmd}", shell="powershell", python_shell=True) def enable(): diff --git a/salt/modules/reg.py b/salt/modules/reg.py index 229998e27a9..5afaad95716 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -64,6 +64,7 @@ Value: :depends: - salt.utils.win_reg """ + # When production windows installer is using Python 3, Python 2 code can be removed import logging @@ -558,13 +559,13 @@ def import_file(source, use_32bit_registry=False): """ cache_path = __salt__["cp.cache_file"](source) if not cache_path: - error_msg = "File/URL '{}' probably invalid.".format(source) + error_msg = f"File/URL '{source}' probably invalid." raise ValueError(error_msg) if use_32bit_registry: word_sz_txt = "32" else: word_sz_txt = "64" - cmd = 'reg import "{}" /reg:{}'.format(cache_path, word_sz_txt) + cmd = f'reg import "{cache_path}" /reg:{word_sz_txt}' cmd_ret_dict = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = cmd_ret_dict["retcode"] if retcode != 0: diff --git a/salt/modules/restartcheck.py b/salt/modules/restartcheck.py index 287b9bd3b38..9f355df48cd 100644 --- a/salt/modules/restartcheck.py +++ b/salt/modules/restartcheck.py @@ -9,6 +9,7 @@ https://packages.debian.org/debian-goodies) and psdel by Sam Morris. :codeauthor: Jiri Kotlin """ + import os import re import subprocess @@ -329,7 +330,7 @@ def _kernel_versions_nilrt(): Get kernel version from a binary image or None if detection fails """ kvregex = r"[0-9]+\.[0-9]+\.[0-9]+-rt\S+" - kernel_strings = __salt__["cmd.run"]("strings {}".format(kbin)) + kernel_strings = __salt__["cmd.run"](f"strings {kbin}") re_result = re.search(kvregex, kernel_strings) return None if re_result is None else re_result.group(0) @@ -346,7 +347,7 @@ def _kernel_versions_nilrt(): itb_path, compressed_kernel ) ) - __salt__["cmd.run"]("gunzip -f {}".format(compressed_kernel)) + __salt__["cmd.run"](f"gunzip -f {compressed_kernel}") kver = _get_kver_from_bin(uncompressed_kernel) else: # the kernel bzImage is copied to rootfs without package management or @@ -387,8 +388,8 @@ def _file_changed_nilrt(full_filepath): """ rs_state_dir = "/var/lib/salt/restartcheck_state" base_filename = os.path.basename(full_filepath) - timestamp_file = os.path.join(rs_state_dir, "{}.timestamp".format(base_filename)) - md5sum_file = os.path.join(rs_state_dir, "{}.md5sum".format(base_filename)) + timestamp_file = os.path.join(rs_state_dir, f"{base_filename}.timestamp") + md5sum_file = os.path.join(rs_state_dir, f"{base_filename}.md5sum") if not os.path.exists(timestamp_file) or not os.path.exists(md5sum_file): return True @@ -401,9 +402,7 @@ def _file_changed_nilrt(full_filepath): return True return bool( - __salt__["cmd.retcode"]( - "md5sum -cs {}".format(md5sum_file), output_loglevel="quiet" - ) + __salt__["cmd.retcode"](f"md5sum -cs {md5sum_file}", output_loglevel="quiet") ) @@ -418,7 +417,7 @@ def _kernel_modules_changed_nilrt(kernelversion): - True if modules.dep was modified/touched, False otherwise. """ if kernelversion is not None: - return _file_changed_nilrt("/lib/modules/{}/modules.dep".format(kernelversion)) + return _file_changed_nilrt(f"/lib/modules/{kernelversion}/modules.dep") return False @@ -446,7 +445,7 @@ def _sysapi_changed_nilrt(): ) if os.path.exists(nisysapi_conf_d_path): - rs_count_file = "{}/sysapi.conf.d.count".format(restartcheck_state_dir) + rs_count_file = f"{restartcheck_state_dir}/sysapi.conf.d.count" if not os.path.exists(rs_count_file): return True @@ -457,7 +456,7 @@ def _sysapi_changed_nilrt(): return True for fexpert in os.listdir(nisysapi_conf_d_path): - if _file_changed_nilrt("{}/{}".format(nisysapi_conf_d_path, fexpert)): + if _file_changed_nilrt(f"{nisysapi_conf_d_path}/{fexpert}"): return True return False @@ -578,7 +577,7 @@ def restartcheck(ignorelist=None, blacklist=None, excludepid=None, **kwargs): if path in blacklist or pid in excludepid: continue try: - readlink = os.readlink("/proc/{}/exe".format(pid)) + readlink = os.readlink(f"/proc/{pid}/exe") except OSError: excludepid.append(pid) continue diff --git a/salt/modules/restconf.py b/salt/modules/restconf.py index 3007adc225d..b99187c87f3 100644 --- a/salt/modules/restconf.py +++ b/salt/modules/restconf.py @@ -7,7 +7,6 @@ Execution module for RESTCONF Proxy minions """ - import logging __proxyenabled__ = ["restconf"] @@ -18,7 +17,7 @@ log = logging.getLogger(__file__) def __virtual__(): if __opts__.get("proxy", {}).get("proxytype") != __virtualname__: - return False, "Proxytype does not match: {}".format(__virtualname__) + return False, f"Proxytype does not match: {__virtualname__}" return True diff --git a/salt/modules/ret.py b/salt/modules/ret.py index 9210eb4d7ed..1885b92a8b5 100644 --- a/salt/modules/ret.py +++ b/salt/modules/ret.py @@ -16,7 +16,7 @@ def get_jid(returner, jid): salt '*' ret.get_jid redis 20421104181954700505 """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_jid".format(returner)](jid) + return returners[f"{returner}.get_jid"](jid) def get_fun(returner, fun): @@ -30,7 +30,7 @@ def get_fun(returner, fun): salt '*' ret.get_fun mysql network.interfaces """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_fun".format(returner)](fun) + return returners[f"{returner}.get_fun"](fun) def get_jids(returner): @@ -44,7 +44,7 @@ def get_jids(returner): salt '*' ret.get_jids mysql """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_jids".format(returner)]() + return returners[f"{returner}.get_jids"]() def get_minions(returner): @@ -58,4 +58,4 @@ def get_minions(returner): salt '*' ret.get_minions mysql """ returners = salt.loader.returners(__opts__, __salt__) - return returners["{}.get_minions".format(returner)]() + return returners[f"{returner}.get_minions"]() diff --git a/salt/modules/rh_ip.py b/salt/modules/rh_ip.py index e476bbd3f6e..f1d823b1a82 100644 --- a/salt/modules/rh_ip.py +++ b/salt/modules/rh_ip.py @@ -202,7 +202,7 @@ def _parse_ethtool_opts(opts, iface): _raise_error_iface(iface, "advertise", valid) if "channels" in opts: - channels_cmd = "-L {}".format(iface.strip()) + channels_cmd = f"-L {iface.strip()}" channels_params = [] for option in ("rx", "tx", "other", "combined"): if option in opts["channels"]: @@ -372,7 +372,6 @@ def _parse_settings_bond_0(opts, iface): def _parse_settings_bond_1(opts, iface): - """ Filters given options and outputs valid settings for bond1. If an option has a value that is not expected, this @@ -418,7 +417,6 @@ def _parse_settings_bond_2(opts, iface): def _parse_settings_bond_3(opts, iface): - """ Filters given options and outputs valid settings for bond3. If an option has a value that is not expected, this @@ -491,7 +489,6 @@ def _parse_settings_bond_4(opts, iface): def _parse_settings_bond_5(opts, iface): - """ Filters given options and outputs valid settings for bond5. If an option has a value that is not expected, this @@ -511,7 +508,6 @@ def _parse_settings_bond_5(opts, iface): def _parse_settings_bond_6(opts, iface): - """ Filters given options and outputs valid settings for bond6. If an option has a value that is not expected, this @@ -531,7 +527,6 @@ def _parse_settings_bond_6(opts, iface): def _parse_settings_vlan(opts, iface): - """ Filters given options and outputs valid settings for a vlan """ @@ -589,9 +584,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): if iface_type not in ("bridge",): ethtool = _parse_ethtool_opts(opts, iface) if ethtool: - result["ethtool"] = " ".join( - ["{} {}".format(x, y) for x, y in ethtool.items()] - ) + result["ethtool"] = " ".join([f"{x} {y}" for x, y in ethtool.items()]) if iface_type == "slave": result["proto"] = "none" @@ -614,9 +607,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): raise AttributeError(msg) bonding = _parse_settings_bond(opts, iface) if bonding: - result["bonding"] = " ".join( - ["{}={}".format(x, y) for x, y in bonding.items()] - ) + result["bonding"] = " ".join([f"{x}={y}" for x, y in bonding.items()]) result["devtype"] = "Bond" if iface_type == "vlan": @@ -1081,7 +1072,7 @@ def build_interface(iface, iface_type, enabled, **settings): ): opts = _parse_settings_eth(settings, iface_type, enabled, iface) try: - template = JINJA.get_template("rh{}_eth.jinja".format(rh_major)) + template = JINJA.get_template(f"rh{rh_major}_eth.jinja") except jinja2.exceptions.TemplateNotFound: log.error("Could not load template rh%s_eth.jinja", rh_major) return "" @@ -1091,7 +1082,7 @@ def build_interface(iface, iface_type, enabled, **settings): return _read_temp(ifcfg) _write_file_iface(iface, ifcfg, _RH_NETWORK_SCRIPT_DIR, "ifcfg-{0}") - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1144,8 +1135,8 @@ def build_routes(iface, **settings): _write_file_iface(iface, routecfg, _RH_NETWORK_SCRIPT_DIR, "route-{0}") _write_file_iface(iface, routecfg6, _RH_NETWORK_SCRIPT_DIR, "route6-{0}") - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route-{}".format(iface)) - path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route6-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route-{iface}") + path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route6-{iface}") routes = _read_file(path) routes.extend(_read_file(path6)) @@ -1164,7 +1155,7 @@ def down(iface, iface_type): """ # Slave devices are controlled by the master. if iface_type.lower() not in ("slave", "teamport"): - return __salt__["cmd.run"]("ifdown {}".format(iface)) + return __salt__["cmd.run"](f"ifdown {iface}") return None @@ -1178,7 +1169,7 @@ def get_interface(iface): salt '*' ip.get_interface eth0 """ - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1194,7 +1185,7 @@ def up(iface, iface_type): # pylint: disable=C0103 """ # Slave devices are controlled by the master. if iface_type.lower() not in ("slave", "teamport"): - return __salt__["cmd.run"]("ifup {}".format(iface)) + return __salt__["cmd.run"](f"ifup {iface}") return None @@ -1208,8 +1199,8 @@ def get_routes(iface): salt '*' ip.get_routes eth0 """ - path = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route-{}".format(iface)) - path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, "route6-{}".format(iface)) + path = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route-{iface}") + path6 = os.path.join(_RH_NETWORK_SCRIPT_DIR, f"route6-{iface}") routes = _read_file(path) routes.extend(_read_file(path6)) return routes diff --git a/salt/modules/riak.py b/salt/modules/riak.py index 197d8689971..f8d893a8451 100644 --- a/salt/modules/riak.py +++ b/salt/modules/riak.py @@ -21,7 +21,7 @@ def __execute_cmd(name, cmd): """ Execute Riak commands """ - return __salt__["cmd.run_all"]("{} {}".format(salt.utils.path.which(name), cmd)) + return __salt__["cmd.run_all"](f"{salt.utils.path.which(name)} {cmd}") def start(): @@ -89,7 +89,7 @@ def cluster_join(username, hostname): """ ret = {"comment": "", "success": False} - cmd = __execute_cmd("riak-admin", "cluster join {}@{}".format(username, hostname)) + cmd = __execute_cmd("riak-admin", f"cluster join {username}@{hostname}") if cmd["retcode"] != 0: ret["comment"] = cmd["stdout"] @@ -117,7 +117,7 @@ def cluster_leave(username, hostname): """ ret = {"comment": "", "success": False} - cmd = __execute_cmd("riak-admin", "cluster leave {}@{}".format(username, hostname)) + cmd = __execute_cmd("riak-admin", f"cluster leave {username}@{hostname}") if cmd["retcode"] != 0: ret["comment"] = cmd["stdout"] diff --git a/salt/modules/rpm_lowpkg.py b/salt/modules/rpm_lowpkg.py index 4cd137c258f..59bf0fa9fb4 100644 --- a/salt/modules/rpm_lowpkg.py +++ b/salt/modules/rpm_lowpkg.py @@ -110,14 +110,14 @@ def bin_pkg_info(path, saltenv="base"): newpath = __salt__["cp.cache_file"](path, saltenv) if not newpath: raise CommandExecutionError( - "Unable to retrieve {} from saltenv '{}'".format(path, saltenv) + f"Unable to retrieve {path} from saltenv '{saltenv}'" ) path = newpath else: if not os.path.exists(path): - raise CommandExecutionError("{} does not exist on minion".format(path)) + raise CommandExecutionError(f"{path} does not exist on minion") elif not os.path.isabs(path): - raise SaltInvocationError("{} does not exist on minion".format(path)) + raise SaltInvocationError(f"{path} does not exist on minion") # REPOID is not a valid tag for the rpm command. Remove it and replace it # with 'none' @@ -495,7 +495,7 @@ def diff(package_path, path): ) res = __salt__["cmd.shell"](cmd.format(package_path, path), output_loglevel="trace") if res and res.startswith("Binary file"): - return "File '{}' is binary and its content has been modified.".format(path) + return f"File '{path}' is binary and its content has been modified." return res @@ -762,7 +762,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False): # rpmdev-vercmp always uses epochs, even when zero def _ensure_epoch(ver): def _prepend(ver): - return "0:{}".format(ver) + return f"0:{ver}" try: if ":" not in ver: @@ -818,7 +818,7 @@ def version_cmp(ver1, ver2, ignore_epoch=False): ) if cmp_result not in (-1, 0, 1): raise CommandExecutionError( - "Comparison result '{}' is invalid".format(cmp_result) + f"Comparison result '{cmp_result}' is invalid" ) return cmp_result diff --git a/salt/modules/rpmbuild_pkgbuild.py b/salt/modules/rpmbuild_pkgbuild.py index 1532817222f..135afab975c 100644 --- a/salt/modules/rpmbuild_pkgbuild.py +++ b/salt/modules/rpmbuild_pkgbuild.py @@ -9,7 +9,6 @@ environments. This also provides a function to generate yum repositories This module implements the pkgbuild interface """ - import errno import functools import logging @@ -83,7 +82,7 @@ def _create_rpmmacros(runas="root"): rpmmacros = os.path.join(home, ".rpmmacros") with salt.utils.files.fopen(rpmmacros, "w") as afile: - afile.write(salt.utils.stringutils.to_str("%_topdir {}\n".format(rpmbuilddir))) + afile.write(salt.utils.stringutils.to_str(f"%_topdir {rpmbuilddir}\n")) afile.write("%signature gpg\n") afile.write("%_source_filedigest_algorithm 8\n") afile.write("%_binary_filedigest_algorithm 8\n") @@ -133,9 +132,9 @@ def _get_distset(tgt): # consistent naming on Centos and Redhat, and allow for Amazon naming tgtattrs = tgt.split("-") if tgtattrs[0] == "amzn2": - distset = '--define "dist .{}"'.format(tgtattrs[0]) + distset = f'--define "dist .{tgtattrs[0]}"' elif tgtattrs[1] in ["6", "7", "8"]: - distset = '--define "dist .el{}"'.format(tgtattrs[1]) + distset = f'--define "dist .el{tgtattrs[1]}"' else: distset = "" @@ -162,7 +161,7 @@ def _get_deps(deps, tree_base, saltenv="base"): else: shutil.copy(deprpm, dest) - deps_list += " {}".format(dest) + deps_list += f" {dest}" return deps_list @@ -175,9 +174,7 @@ def _check_repo_gpg_phrase_utils(): if __salt__["file.file_exists"](util_name): return True else: - raise CommandExecutionError( - "utility '{}' needs to be installed".format(util_name) - ) + raise CommandExecutionError(f"utility '{util_name}' needs to be installed") def _get_gpg_key_resources(keyid, env, use_passphrase, gnupghome, runas): @@ -326,7 +323,7 @@ def _get_gpg_key_resources(keyid, env, use_passphrase, gnupghome, runas): ) # need to update rpm with public key - cmd = "rpm --import {}".format(pkg_pub_key_file) + cmd = f"rpm --import {pkg_pub_key_file}" retrc = __salt__["cmd.retcode"](cmd, runas=runas, use_vt=True) if retrc != 0: raise SaltInvocationError( @@ -349,9 +346,9 @@ def _sign_file(runas, define_gpg_name, phrase, abs_file, timeout): interval = 0.5 number_retries = timeout / interval times_looped = 0 - error_msg = "Failed to sign file {}".format(abs_file) + error_msg = f"Failed to sign file {abs_file}" - cmd = "rpm {} --addsign {}".format(define_gpg_name, abs_file) + cmd = f"rpm {define_gpg_name} --addsign {abs_file}" preexec_fn = functools.partial(salt.utils.user.chugid_and_umask, runas, None) try: stdout, stderr = None, None @@ -396,7 +393,7 @@ def _sign_files_with_gpg_agent(runas, local_keyid, abs_file, repodir, env, timeo """ Sign file with provided key utilizing gpg-agent """ - cmd = "rpmsign --verbose --key-id={} --addsign {}".format(local_keyid, abs_file) + cmd = f"rpmsign --verbose --key-id={local_keyid} --addsign {abs_file}" retrc = __salt__["cmd.retcode"](cmd, runas=runas, cwd=repodir, use_vt=True, env=env) if retrc != 0: raise SaltInvocationError( @@ -548,7 +545,7 @@ def build( try: __salt__["file.chown"](path=dbase, user=runas, group="mock") __salt__["file.chown"](path=results_dir, user=runas, group="mock") - cmd = "mock --root={} --resultdir={} --init".format(tgt, results_dir) + cmd = f"mock --root={tgt} --resultdir={results_dir} --init" retrc |= __salt__["cmd.retcode"](cmd, runas=runas) if deps_list and not deps_list.isspace(): cmd = "mock --root={} --resultdir={} --install {} {}".format( @@ -565,7 +562,7 @@ def build( "rpm", "-qp", "--queryformat", - "{0}/%{{name}}/%{{version}}-%{{release}}".format(log_dir), + f"{log_dir}/%{{name}}/%{{version}}-%{{release}}", srpm, ] log_dest = __salt__["cmd.run_stdout"](cmdlist, python_shell=False) @@ -753,6 +750,6 @@ def make_repo( else: _sign_file(runas, define_gpg_name, phrase, abs_file, timeout) - cmd = "createrepo --update {}".format(repodir) + cmd = f"createrepo --update {repodir}" retrc = __salt__["cmd.run_all"](cmd, runas=runas) return retrc diff --git a/salt/modules/rsync.py b/salt/modules/rsync.py index ffecb3dfb89..311a51cf8a7 100644 --- a/salt/modules/rsync.py +++ b/salt/modules/rsync.py @@ -47,7 +47,7 @@ def _check(delete, force, update, passwordfile, exclude, excludefrom, dryrun, rs if update: options.append("--update") if rsh: - options.append("--rsh={}".format(rsh)) + options.append(f"--rsh={rsh}") if passwordfile: options.extend(["--password-file", passwordfile]) if excludefrom: @@ -182,16 +182,16 @@ def rsync( # get the contents not the tmpdir # itself. if not src.endswith("/"): - src = "{}/".format(src) + src = f"{src}/" else: - raise CommandExecutionError("{} does not exist".format(src)) + raise CommandExecutionError(f"{src} does not exist") else: tmp_src = salt.utils.files.mkstemp() file_src = __salt__["cp.get_file"](_src, tmp_src, saltenv) if file_src: src = tmp_src else: - raise CommandExecutionError("{} does not exist".format(src)) + raise CommandExecutionError(f"{src} does not exist") option = _check( delete, force, update, passwordfile, exclude, excludefrom, dryrun, rsh @@ -261,16 +261,14 @@ def config(conf_path="/etc/rsyncd.conf"): ret += salt.utils.stringutils.to_unicode(line) except OSError as exc: if exc.errno == errno.ENOENT: - raise CommandExecutionError("{} does not exist".format(conf_path)) + raise CommandExecutionError(f"{conf_path} does not exist") elif exc.errno == errno.EACCES: - raise CommandExecutionError( - "Unable to read {}, access denied".format(conf_path) - ) + raise CommandExecutionError(f"Unable to read {conf_path}, access denied") elif exc.errno == errno.EISDIR: raise CommandExecutionError( - "Unable to read {}, path is a directory".format(conf_path) + f"Unable to read {conf_path}, path is a directory" ) else: - raise CommandExecutionError("Error {}: {}".format(exc.errno, exc.strerror)) + raise CommandExecutionError(f"Error {exc.errno}: {exc.strerror}") else: return ret diff --git a/salt/modules/rvm.py b/salt/modules/rvm.py index 28669a26511..92d9b92983d 100644 --- a/salt/modules/rvm.py +++ b/salt/modules/rvm.py @@ -21,8 +21,8 @@ __opts__ = { def _get_rvm_location(runas=None): if runas: - runas_home = os.path.expanduser("~{}".format(runas)) - rvmpath = "{}/.rvm/bin/rvm".format(runas_home) + runas_home = os.path.expanduser(f"~{runas}") + rvmpath = f"{runas_home}/.rvm/bin/rvm" if os.path.exists(rvmpath): return [rvmpath] return ["/usr/local/rvm/bin/rvm"] @@ -87,7 +87,7 @@ def install(runas=None): ret = __salt__["cmd.run_all"]( # the RVM installer automatically does a multi-user install when it is # invoked with root privileges - "curl -Ls {installer} | bash -s stable".format(installer=installer), + f"curl -Ls {installer} | bash -s stable", runas=runas, python_shell=True, ) diff --git a/salt/modules/s6.py b/salt/modules/s6.py index 23edface5a5..3f1c4656520 100644 --- a/salt/modules/s6.py +++ b/salt/modules/s6.py @@ -40,7 +40,7 @@ def _service_path(name): """ if not SERVICE_DIR: raise CommandExecutionError("Could not find service directory.") - return "{}/{}".format(SERVICE_DIR, name) + return f"{SERVICE_DIR}/{name}" def start(name): @@ -53,7 +53,7 @@ def start(name): salt '*' s6.start """ - cmd = "s6-svc -u {}".format(_service_path(name)) + cmd = f"s6-svc -u {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -67,7 +67,7 @@ def stop(name): salt '*' s6.stop """ - cmd = "s6-svc -d {}".format(_service_path(name)) + cmd = f"s6-svc -d {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -81,7 +81,7 @@ def term(name): salt '*' s6.term """ - cmd = "s6-svc -t {}".format(_service_path(name)) + cmd = f"s6-svc -t {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -95,7 +95,7 @@ def reload_(name): salt '*' s6.reload """ - cmd = "s6-svc -h {}".format(_service_path(name)) + cmd = f"s6-svc -h {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -109,7 +109,7 @@ def restart(name): salt '*' s6.restart """ - cmd = "s6-svc -t {}".format(_service_path(name)) + cmd = f"s6-svc -t {_service_path(name)}" return not __salt__["cmd.retcode"](cmd) @@ -136,7 +136,7 @@ def status(name, sig=None): salt '*' s6.status """ - cmd = "s6-svstat {}".format(_service_path(name)) + cmd = f"s6-svstat {_service_path(name)}" out = __salt__["cmd.run_stdout"](cmd) try: pid = re.search(r"up \(pid (\d+)\)", out).group(1) diff --git a/salt/modules/salt_proxy.py b/salt/modules/salt_proxy.py index 315abf4314d..70572ba1f33 100644 --- a/salt/modules/salt_proxy.py +++ b/salt/modules/salt_proxy.py @@ -33,7 +33,7 @@ def _write_proxy_conf(proxyfile): proxy_conf.write( salt.utils.stringutils.to_str("master: {}".format(__grains__["master"])) ) - msg = "Wrote proxy file {}".format(proxyfile) + msg = f"Wrote proxy file {proxyfile}" log.debug(msg) return msg @@ -50,18 +50,18 @@ def _proxy_conf_file(proxyfile, test): try: if not test: changes_new.append(_write_proxy_conf(proxyfile)) - msg = "Salt Proxy: Wrote proxy conf {}".format(proxyfile) + msg = f"Salt Proxy: Wrote proxy conf {proxyfile}" else: - msg = "Salt Proxy: Update required to proxy conf {}".format(proxyfile) + msg = f"Salt Proxy: Update required to proxy conf {proxyfile}" except OSError as err: success = False - msg = "Salt Proxy: Error writing proxy file {}".format(err) + msg = f"Salt Proxy: Error writing proxy file {err}" log.error(msg) changes_new.append(msg) changes_new.append(msg) log.debug(msg) else: - msg = "Salt Proxy: {} already exists, skipping".format(proxyfile) + msg = f"Salt Proxy: {proxyfile} already exists, skipping" changes_old.append(msg) log.debug(msg) return success, changes_new, changes_old @@ -90,18 +90,14 @@ def _proxy_process(proxyname, test): if not _is_proxy_running(proxyname): if not test: __salt__["cmd.run_all"]( - "salt-proxy --proxyid={} -l info -d".format(shlex.quote(proxyname)), + f"salt-proxy --proxyid={shlex.quote(proxyname)} -l info -d", timeout=5, ) - changes_new.append( - "Salt Proxy: Started proxy process for {}".format(proxyname) - ) + changes_new.append(f"Salt Proxy: Started proxy process for {proxyname}") else: - changes_new.append( - "Salt Proxy: process {} will be started".format(proxyname) - ) + changes_new.append(f"Salt Proxy: process {proxyname} will be started") else: - changes_old.append("Salt Proxy: already running for {}".format(proxyname)) + changes_old.append(f"Salt Proxy: already running for {proxyname}") return True, changes_new, changes_old diff --git a/salt/modules/salt_version.py b/salt/modules/salt_version.py index 99dae5f61a5..56dde8f708c 100644 --- a/salt/modules/salt_version.py +++ b/salt/modules/salt_version.py @@ -30,7 +30,6 @@ A simple example might be something like the following: """ - import logging import salt.utils.versions diff --git a/salt/modules/saltcheck.py b/salt/modules/saltcheck.py index 4b4ebee9cd1..816860f16c8 100644 --- a/salt/modules/saltcheck.py +++ b/salt/modules/saltcheck.py @@ -297,7 +297,6 @@ Supported assertions ``saltcheck.run_highstate_tests`` are needed. """ - import copy import logging import multiprocessing @@ -927,12 +926,12 @@ class SaltCheck: else: assertion_section_repr_title = "" assertion_section_repr_value = "" - value[ - f"module.function [args]{assertion_section_repr_title}" - ] = "{} {}{}".format( - mod_and_func, - dumps(args), - assertion_section_repr_value, + value[f"module.function [args]{assertion_section_repr_title}"] = ( + "{} {}{}".format( + mod_and_func, + dumps(args), + assertion_section_repr_value, + ) ) value["saltcheck assertion"] = "{}{} {}".format( ("" if expected_return is None else f"{expected_return} "), diff --git a/salt/modules/saltcloudmod.py b/salt/modules/saltcloudmod.py index acaed51519b..29a549490e0 100644 --- a/salt/modules/saltcloudmod.py +++ b/salt/modules/saltcloudmod.py @@ -40,7 +40,7 @@ def create(name, profile): salt saltcloud.create webserver rackspace_centos_512 """ - cmd = "salt-cloud --out json -p {} {}".format(profile, name) + cmd = f"salt-cloud --out json -p {profile} {name}" out = __salt__["cmd.run_stdout"](cmd, python_shell=False) try: ret = salt.utils.json.loads(out) diff --git a/salt/modules/saltutil.py b/salt/modules/saltutil.py index 6505a9b2d0b..0095871116b 100644 --- a/salt/modules/saltutil.py +++ b/salt/modules/saltutil.py @@ -1646,7 +1646,7 @@ def regen_keys(): path = os.path.join(__opts__["pki_dir"], fn_) try: os.remove(path) - except os.error: + except OSError: pass # TODO: move this into a channel function? Or auth? # create a channel again, this will force the key regen @@ -1752,9 +1752,11 @@ def _exec( old_ret, fcn_ret = fcn_ret, {} for key, value in old_ret.items(): fcn_ret[key] = { - "out": value.get("out", "highstate") - if isinstance(value, dict) - else "highstate", + "out": ( + value.get("out", "highstate") + if isinstance(value, dict) + else "highstate" + ), "ret": value, } diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index 50ec9846ba6..42458fb1c25 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -7,7 +7,6 @@ Requires that python-dateutil is installed on the minion. """ - import copy as pycopy import datetime import logging @@ -423,10 +422,10 @@ def delete(name, **kwargs): ) ret["changes"][name] = "removed" else: - ret[ - "comment" - ] = "Failed to delete job {} from schedule.".format( - name + ret["comment"] = ( + "Failed to delete job {} from schedule.".format( + name + ) ) return ret except KeyError: @@ -967,9 +966,9 @@ def disable_job(name, **kwargs): ret["changes"][name] = "disabled" else: ret["result"] = False - ret[ - "comment" - ] = f"Failed to disable job {name} in schedule." + ret["comment"] = ( + f"Failed to disable job {name} in schedule." + ) return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -1391,9 +1390,9 @@ def postpone_job(name, current_time, new_time, **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = f"Failed to postpone job {name} in schedule." + ret["comment"] = ( + f"Failed to postpone job {name} in schedule." + ) return ret except KeyError: # Effectively a no-op, since we can't really return without an event system @@ -1520,9 +1519,9 @@ def show_next_fire_time(name, **kwargs): except KeyError: # Effectively a no-op, since we can't really return without an event system ret = {} - ret[ - "comment" - ] = "Event module not available. Schedule show next fire time failed." + ret["comment"] = ( + "Event module not available. Schedule show next fire time failed." + ) ret["result"] = True return ret @@ -1547,9 +1546,11 @@ def job_status(name, time_fmt="%Y-%m-%dT%H:%M:%S"): def convert_datetime_objects_in_dict_to_string(data_dict, time_fmt): return { - key: value.strftime(time_fmt) - if isinstance(value, datetime.datetime) - else value + key: ( + value.strftime(time_fmt) + if isinstance(value, datetime.datetime) + else value + ) for key, value in data_dict.items() } diff --git a/salt/modules/scp_mod.py b/salt/modules/scp_mod.py index 4121bdbf4a7..d7525b28c73 100644 --- a/salt/modules/scp_mod.py +++ b/salt/modules/scp_mod.py @@ -9,8 +9,6 @@ Module to copy files via `SCP `_ import logging -# Import salt modules - try: import paramiko import scp @@ -55,7 +53,7 @@ def _prepare_connection(**kwargs): paramiko_kwargs, scp_kwargs = _select_kwargs(**kwargs) ssh = paramiko.SSHClient() if paramiko_kwargs.pop("auto_add_policy", False): - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # nosec ssh.connect(**paramiko_kwargs) scp_client = scp.SCPClient(ssh.get_transport(), **scp_kwargs) return scp_client diff --git a/salt/modules/scsi.py b/salt/modules/scsi.py index e405865806a..83a3e8b169d 100644 --- a/salt/modules/scsi.py +++ b/salt/modules/scsi.py @@ -47,7 +47,7 @@ def ls_(get_size=True): __context__["retcode"] = rc error = res.get("stderr", "").split("\n")[0] if error == "lsscsi: invalid option -- 's'": - return "{} - try get_size=False".format(error) + return f"{error} - try get_size=False" return res.get("stderr", "").split("\n")[0] data = res.get("stdout", "") @@ -93,8 +93,8 @@ def rescan_all(host): salt '*' scsi.rescan_all 0 """ - if os.path.isdir("/sys/class/scsi_host/host{}".format(host)): - cmd = 'echo "- - -" > /sys/class/scsi_host/host{}/scan'.format(host) + if os.path.isdir(f"/sys/class/scsi_host/host{host}"): + cmd = f'echo "- - -" > /sys/class/scsi_host/host{host}/scan' else: - return "Host {} does not exist".format(host) + return f"Host {host} does not exist" return __salt__["cmd.run"](cmd).splitlines() diff --git a/salt/modules/sdb.py b/salt/modules/sdb.py index 6dc4457b1f8..1182d6dc934 100644 --- a/salt/modules/sdb.py +++ b/salt/modules/sdb.py @@ -3,7 +3,6 @@ Module for Manipulating Data via the Salt DB API ================================================ """ - import salt.utils.sdb __func_alias__ = { diff --git a/salt/modules/seed.py b/salt/modules/seed.py index 7b985249cac..657c7bccd64 100644 --- a/salt/modules/seed.py +++ b/salt/modules/seed.py @@ -2,7 +2,6 @@ Virtual machine image management tools """ - import logging import os import shutil @@ -42,7 +41,7 @@ def prep_bootstrap(mpt): """ # Verify that the boostrap script is downloaded bs_ = __salt__["config.gather_bootstrap_script"]() - fpd_ = os.path.join(mpt, "tmp", "{}".format(uuid.uuid4())) + fpd_ = os.path.join(mpt, "tmp", f"{uuid.uuid4()}") if not os.path.exists(fpd_): os.makedirs(fpd_) os.chmod(fpd_, 0o700) @@ -136,7 +135,7 @@ def apply_( """ stats = __salt__["file.stats"](path, follow_symlinks=True) if not stats: - return "{} does not exist".format(path) + return f"{path} does not exist" ftype = stats["type"] path = stats["target"] log.debug("Mounting %s at %s", ftype, path) @@ -149,7 +148,7 @@ def apply_( mpt = _mount(path, ftype, mount_point) if not mpt: - return "{} could not be mounted".format(path) + return f"{path} could not be mounted" tmp = os.path.join(mpt, "tmp") log.debug("Attempting to create directory %s", tmp) @@ -300,6 +299,6 @@ def _check_install(root): sh_ = "/bin/bash" cmd = "if ! type salt-minion; then exit 1; fi" - cmd = "chroot '{}' {} -c '{}'".format(root, sh_, cmd) + cmd = f"chroot '{root}' {sh_} -c '{cmd}'" return not __salt__["cmd.retcode"](cmd, output_loglevel="quiet", python_shell=True) diff --git a/salt/modules/sensehat.py b/salt/modules/sensehat.py index 71c5630703c..c3f3e2f0a6d 100644 --- a/salt/modules/sensehat.py +++ b/salt/modules/sensehat.py @@ -19,7 +19,6 @@ Example: """ - import logging try: diff --git a/salt/modules/sensors.py b/salt/modules/sensors.py index b96c3a32a4c..53b1970bf8f 100644 --- a/salt/modules/sensors.py +++ b/salt/modules/sensors.py @@ -42,7 +42,7 @@ def sense(chip, fahrenheit=False): if fahrenheit is True: extra_args = "-f" sensors = __salt__["cmd.run"]( - "/usr/bin/sensors {} {}".format(chip, extra_args), python_shell=False + f"/usr/bin/sensors {chip} {extra_args}", python_shell=False ).splitlines() ret = {} for sensor in sensors: diff --git a/salt/modules/serverdensity_device.py b/salt/modules/serverdensity_device.py index 27a4c0b0a32..7b653d9bcb8 100644 --- a/salt/modules/serverdensity_device.py +++ b/salt/modules/serverdensity_device.py @@ -5,7 +5,6 @@ Wrapper around Server Density API .. versionadded:: 2014.7.0 """ - import logging import os import tempfile @@ -49,14 +48,14 @@ def get_sd_auth(val, sd_auth_pillar_name="serverdensity"): if not sd_pillar: log.error("Could not load %s pillar", sd_auth_pillar_name) raise CommandExecutionError( - "{} pillar is required for authentication".format(sd_auth_pillar_name) + f"{sd_auth_pillar_name} pillar is required for authentication" ) try: return sd_pillar[val] except KeyError: log.error("Could not find value %s in pillar", val) - raise CommandExecutionError("{} value was not found in pillar".format(val)) + raise CommandExecutionError(f"{val} value was not found in pillar") def _clean_salt_variables(params, variable_prefix="__"): @@ -98,7 +97,7 @@ def create(name, **params): except ValueError: log.error("Could not parse API Response content: %s", api_response.content) raise CommandExecutionError( - "Failed to create, API Response: {}".format(api_response) + f"Failed to create, API Response: {api_response}" ) else: return None @@ -129,7 +128,7 @@ def delete(device_id): except ValueError: log.error("Could not parse API Response content: %s", api_response.content) raise CommandExecutionError( - "Failed to create, API Response: {}".format(api_response) + f"Failed to create, API Response: {api_response}" ) else: return None @@ -166,7 +165,7 @@ def ls(**params): params[key] = str(val) api_response = requests.get( - "https://api.serverdensity.io/inventory/{}".format(endpoint), + f"https://api.serverdensity.io/inventory/{endpoint}", params={ "token": get_sd_auth("api_token"), "filter": salt.utils.json.dumps(params), @@ -183,7 +182,7 @@ def ls(**params): api_response.content, ) raise CommandExecutionError( - "Failed to create, Server Density API Response: {}".format(api_response) + f"Failed to create, Server Density API Response: {api_response}" ) else: return None @@ -221,7 +220,7 @@ def update(device_id, **params): api_response.content, ) raise CommandExecutionError( - "Failed to create, API Response: {}".format(api_response) + f"Failed to create, API Response: {api_response}" ) else: return None @@ -255,10 +254,8 @@ def install_agent(agent_key, agent_version=1): account = get_sd_auth(account_field) - __salt__["cmd.run"]( - cmd="curl -L {} -o {}".format(url, install_filename), cwd=work_dir - ) - __salt__["cmd.run"](cmd="chmod +x {}".format(install_filename), cwd=work_dir) + __salt__["cmd.run"](cmd=f"curl -L {url} -o {install_filename}", cwd=work_dir) + __salt__["cmd.run"](cmd=f"chmod +x {install_filename}", cwd=work_dir) return __salt__["cmd.run"]( cmd="{filename} -a {account} -k {agent_key}".format( diff --git a/salt/modules/servicenow.py b/salt/modules/servicenow.py index 5ac48ee72c6..04cff9cb6b6 100644 --- a/salt/modules/servicenow.py +++ b/salt/modules/servicenow.py @@ -137,7 +137,7 @@ def non_structured_query(table, query=None, **kwargs): # try and assemble a query by keyword query_parts = [] for key, value in kwargs.items(): - query_parts.append("{}={}".format(key, value)) + query_parts.append(f"{key}={value}") query = "^".join(query_parts) query = str(query) response = client.get(query) diff --git a/salt/modules/slack_notify.py b/salt/modules/slack_notify.py index d0d32fabe18..b82367176e8 100644 --- a/salt/modules/slack_notify.py +++ b/salt/modules/slack_notify.py @@ -15,7 +15,6 @@ Module for sending messages to Slack api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15 """ - import logging import urllib.parse @@ -205,7 +204,7 @@ def post_message( channel, channel, ) - channel = "#{}".format(channel) + channel = f"#{channel}" if not from_name: log.error("from_name is a required option.") diff --git a/salt/modules/slsutil.py b/salt/modules/slsutil.py index 51abe5b390d..cf8afa76c37 100644 --- a/salt/modules/slsutil.py +++ b/salt/modules/slsutil.py @@ -2,7 +2,6 @@ Utility functions for use with or in SLS files """ - import os import posixpath import textwrap diff --git a/salt/modules/smartos_imgadm.py b/salt/modules/smartos_imgadm.py index f390bdcb7d0..10ced9fe024 100644 --- a/salt/modules/smartos_imgadm.py +++ b/salt/modules/smartos_imgadm.py @@ -42,8 +42,8 @@ def _exit_status(retcode, stderr=None): 1: "An error occurred." if not stderr else stderr, 2: "Usage error.", 3: "Image not installed.", - }[retcode] - return ret + } + return ret[retcode] def _parse_image_meta(image=None, detail=False): diff --git a/salt/modules/smartos_nictagadm.py b/salt/modules/smartos_nictagadm.py index 439db5ab498..fb67c9602b3 100644 --- a/salt/modules/smartos_nictagadm.py +++ b/salt/modules/smartos_nictagadm.py @@ -170,9 +170,11 @@ def add(name, mac, mtu=1500): return True else: return { - "Error": "failed to create nictag." - if "stderr" not in res and res["stderr"] == "" - else res["stderr"] + "Error": ( + "failed to create nictag." + if "stderr" not in res and res["stderr"] == "" + else res["stderr"] + ) } @@ -226,9 +228,11 @@ def update(name, mac=None, mtu=None): return True else: return { - "Error": "failed to update nictag." - if "stderr" not in res and res["stderr"] == "" - else res["stderr"] + "Error": ( + "failed to update nictag." + if "stderr" not in res and res["stderr"] == "" + else res["stderr"] + ) } @@ -259,7 +263,9 @@ def delete(name, force=False): return True else: return { - "Error": "failed to delete nictag." - if "stderr" not in res and res["stderr"] == "" - else res["stderr"] + "Error": ( + "failed to delete nictag." + if "stderr" not in res and res["stderr"] == "" + else res["stderr"] + ) } diff --git a/salt/modules/smartos_virt.py b/salt/modules/smartos_virt.py index 2f29fcefd5f..54aa8841822 100644 --- a/salt/modules/smartos_virt.py +++ b/salt/modules/smartos_virt.py @@ -22,7 +22,7 @@ def __virtual__(): return __virtualname__ return ( False, - "{} module can only be loaded on SmartOS compute nodes".format(__virtualname__), + f"{__virtualname__} module can only be loaded on SmartOS compute nodes", ) @@ -185,9 +185,7 @@ def vm_virt_type(domain): salt '*' virt.vm_virt_type """ - ret = __salt__["vmadm.lookup"]( - search="uuid={uuid}".format(uuid=domain), order="type" - ) + ret = __salt__["vmadm.lookup"](search=f"uuid={domain}", order="type") if not ret: raise CommandExecutionError("We can't determine the type of this VM") @@ -232,9 +230,7 @@ def get_macs(domain): salt '*' virt.get_macs """ macs = [] - ret = __salt__["vmadm.lookup"]( - search="uuid={uuid}".format(uuid=domain), order="nics" - ) + ret = __salt__["vmadm.lookup"](search=f"uuid={domain}", order="nics") if not ret: raise CommandExecutionError("We can't find the MAC address of this VM") else: diff --git a/salt/modules/smartos_vmadm.py b/salt/modules/smartos_vmadm.py index 83d64e361dd..e757a660e5c 100644 --- a/salt/modules/smartos_vmadm.py +++ b/salt/modules/smartos_vmadm.py @@ -43,10 +43,12 @@ def _exit_status(retcode): """ Translate exit status of vmadm """ - ret = {0: "Successful completion.", 1: "An error occurred.", 2: "Usage error."}[ - retcode - ] - return ret + ret = { + 0: "Successful completion.", + 1: "An error occurred.", + 2: "Usage error.", + } + return ret[retcode] def _create_update_from_file(mode="create", uuid=None, path=None): diff --git a/salt/modules/smbios.py b/salt/modules/smbios.py index b27a2aeb2d3..9e6f7192ac0 100644 --- a/salt/modules/smbios.py +++ b/salt/modules/smbios.py @@ -75,7 +75,7 @@ def get(string, clean=True): salt '*' smbios.get system-uuid clean=False """ - val = _dmidecoder("-s {}".format(string)).strip() + val = _dmidecoder(f"-s {string}").strip() # Cleanup possible comments in strings. val = "\n".join([v for v in val.split("\n") if not v.startswith("#")]) @@ -158,7 +158,7 @@ def records(rec_type=None, fields=None, clean=True): if rec_type is None: smbios = _dmi_parse(_dmidecoder(), clean, fields) else: - smbios = _dmi_parse(_dmidecoder("-t {}".format(rec_type)), clean, fields) + smbios = _dmi_parse(_dmidecoder(f"-t {rec_type}"), clean, fields) return smbios @@ -334,6 +334,6 @@ def _dmidecoder(args=None): if not args: out = salt.modules.cmdmod._run_quiet(dmidecoder) else: - out = salt.modules.cmdmod._run_quiet("{} {}".format(dmidecoder, args)) + out = salt.modules.cmdmod._run_quiet(f"{dmidecoder} {args}") return out diff --git a/salt/modules/smf_service.py b/salt/modules/smf_service.py index 5c3d948b9d9..4314c84c88f 100644 --- a/salt/modules/smf_service.py +++ b/salt/modules/smf_service.py @@ -9,7 +9,6 @@ that use SMF also. (e.g. SmartOS) `. """ - import fnmatch import re @@ -112,7 +111,7 @@ def available(name): salt '*' service.available net-snmp """ - cmd = "/usr/bin/svcs -H -o FMRI {}".format(name) + cmd = f"/usr/bin/svcs -H -o FMRI {name}" name = __salt__["cmd.run"](cmd, python_shell=False) return name in get_all() @@ -129,7 +128,7 @@ def missing(name): salt '*' service.missing net-snmp """ - cmd = "/usr/bin/svcs -H -o FMRI {}".format(name) + cmd = f"/usr/bin/svcs -H -o FMRI {name}" name = __salt__["cmd.run"](cmd, python_shell=False) return name not in get_all() @@ -165,7 +164,7 @@ def start(name): salt '*' service.start """ - cmd = "/usr/sbin/svcadm enable -s -t {}".format(name) + cmd = f"/usr/sbin/svcadm enable -s -t {name}" retcode = __salt__["cmd.retcode"](cmd, python_shell=False) if not retcode: return True @@ -173,7 +172,7 @@ def start(name): # Return code 3 means there was a problem with the service # A common case is being in the 'maintenance' state # Attempt a clear and try one more time - clear_cmd = "/usr/sbin/svcadm clear {}".format(name) + clear_cmd = f"/usr/sbin/svcadm clear {name}" __salt__["cmd.retcode"](clear_cmd, python_shell=False) return not __salt__["cmd.retcode"](cmd, python_shell=False) return False @@ -189,7 +188,7 @@ def stop(name): salt '*' service.stop """ - cmd = "/usr/sbin/svcadm disable -s -t {}".format(name) + cmd = f"/usr/sbin/svcadm disable -s -t {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -203,7 +202,7 @@ def restart(name): salt '*' service.restart """ - cmd = "/usr/sbin/svcadm restart {}".format(name) + cmd = f"/usr/sbin/svcadm restart {name}" if not __salt__["cmd.retcode"](cmd, python_shell=False): # calling restart doesn't clear maintenance # or tell us that the service is in the 'online' state @@ -221,7 +220,7 @@ def reload_(name): salt '*' service.reload """ - cmd = "/usr/sbin/svcadm refresh {}".format(name) + cmd = f"/usr/sbin/svcadm refresh {name}" if not __salt__["cmd.retcode"](cmd, python_shell=False): # calling reload doesn't clear maintenance # or tell us that the service is in the 'online' state @@ -259,7 +258,7 @@ def status(name, sig=None): services = [name] results = {} for service in services: - cmd = "/usr/bin/svcs -H -o STATE {}".format(service) + cmd = f"/usr/bin/svcs -H -o STATE {service}" line = __salt__["cmd.run"](cmd, python_shell=False) results[service] = line == "online" if contains_globbing: @@ -277,7 +276,7 @@ def enable(name, **kwargs): salt '*' service.enable """ - cmd = "/usr/sbin/svcadm enable {}".format(name) + cmd = f"/usr/sbin/svcadm enable {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -291,7 +290,7 @@ def disable(name, **kwargs): salt '*' service.disable """ - cmd = "/usr/sbin/svcadm disable {}".format(name) + cmd = f"/usr/sbin/svcadm disable {name}" return not __salt__["cmd.retcode"](cmd, python_shell=False) @@ -308,9 +307,9 @@ def enabled(name, **kwargs): # The property that reveals whether a service is enabled # can only be queried using the full FMRI # We extract the FMRI and then do the query - fmri_cmd = "/usr/bin/svcs -H -o FMRI {}".format(name) + fmri_cmd = f"/usr/bin/svcs -H -o FMRI {name}" fmri = __salt__["cmd.run"](fmri_cmd, python_shell=False) - cmd = "/usr/sbin/svccfg -s {} listprop general/enabled".format(fmri) + cmd = f"/usr/sbin/svccfg -s {fmri} listprop general/enabled" comps = __salt__["cmd.run"](cmd, python_shell=False).split() if comps[2] == "true": return True diff --git a/salt/modules/smtp.py b/salt/modules/smtp.py index 8eaa6bb0a73..fc9d55f0cbb 100644 --- a/salt/modules/smtp.py +++ b/salt/modules/smtp.py @@ -40,7 +40,6 @@ Module for Sending Messages via SMTP """ - import logging import os import socket @@ -157,7 +156,7 @@ def send_msg( name = os.path.basename(f) with salt.utils.files.fopen(f, "rb") as fin: att = email.mime.application.MIMEApplication(fin.read(), Name=name) - att["Content-Disposition"] = 'attachment; filename="{}"'.format(name) + att["Content-Disposition"] = f'attachment; filename="{name}"' msg.attach(att) try: diff --git a/salt/modules/snapper.py b/salt/modules/snapper.py index 4968dbc329d..f97d3d5f598 100644 --- a/salt/modules/snapper.py +++ b/salt/modules/snapper.py @@ -11,6 +11,7 @@ Module to manage filesystem snapshots with snapper :maturity: new :platform: Linux """ + import difflib import logging import os @@ -333,7 +334,7 @@ def create_config( def raise_arg_error(argname): raise CommandExecutionError( - 'You must provide a "{}" for the new configuration'.format(argname) + f'You must provide a "{argname}" for the new configuration' ) if not name: @@ -365,7 +366,7 @@ def create_snapshot( description=None, cleanup_algorithm="number", userdata=None, - **kwargs + **kwargs, ): """ Creates an snapshot @@ -407,7 +408,7 @@ def create_snapshot( jid = kwargs.get("__pub_jid") if description is None and jid is not None: - description = "salt job {}".format(jid) + description = f"salt job {jid}" if jid is not None: userdata["salt_jid"] = jid @@ -432,9 +433,7 @@ def create_snapshot( config, pre_number, description, cleanup_algorithm, userdata ) else: - raise CommandExecutionError( - "Invalid snapshot type '{}'".format(snapshot_type) - ) + raise CommandExecutionError(f"Invalid snapshot type '{snapshot_type}'") except dbus.DBusException as exc: raise CommandExecutionError( "Error encountered while listing changed files: {}".format( @@ -524,9 +523,9 @@ def modify_snapshot( try: # Updating only the explicitly provided attributes by the user updated_opts = { - "description": description - if description is not None - else snapshot["description"], + "description": ( + description if description is not None else snapshot["description"] + ), "cleanup": cleanup if cleanup is not None else snapshot["cleanup"], "userdata": userdata if userdata is not None else snapshot["userdata"], } @@ -559,7 +558,7 @@ def _is_text_file(filename): ["file", "-bi", filename], check=False, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ).stdout return type_of_file.startswith("text") @@ -605,7 +604,7 @@ def run(function, *args, **kwargs): salt '*' snapper.run file.append args='["/etc/motd", "some text"]' """ config = kwargs.pop("config", "root") - description = kwargs.pop("description", "snapper.run[{}]".format(function)) + description = kwargs.pop("description", f"snapper.run[{function}]") cleanup_algorithm = kwargs.pop("cleanup_algorithm", "number") userdata = kwargs.pop("userdata", {}) @@ -618,11 +617,11 @@ def run(function, *args, **kwargs): description=description, cleanup_algorithm=cleanup_algorithm, userdata=userdata, - **kwargs + **kwargs, ) if function not in __salt__: - raise CommandExecutionError('function "{}" does not exist'.format(function)) + raise CommandExecutionError(f'function "{function}" does not exist') try: ret = __salt__[function](*args, **func_kwargs) @@ -636,7 +635,7 @@ def run(function, *args, **kwargs): description=description, cleanup_algorithm=cleanup_algorithm, userdata=userdata, - **kwargs + **kwargs, ) return ret @@ -754,7 +753,7 @@ def undo(config="root", files=None, num_pre=None, num_post=None): return ret except ValueError as exc: raise CommandExecutionError( - "Error while processing Snapper response: {}".format(cmdret) + f"Error while processing Snapper response: {cmdret}" ) @@ -772,7 +771,7 @@ def _get_jid_snapshots(jid, config="root"): post_snapshot = [x for x in jid_snapshots if x["type"] == "post"] if not pre_snapshot or not post_snapshot: - raise CommandExecutionError("Jid '{}' snapshots not found".format(jid)) + raise CommandExecutionError(f"Jid '{jid}' snapshots not found") return (pre_snapshot[0]["id"], post_snapshot[0]["id"]) diff --git a/salt/modules/solaris_group.py b/salt/modules/solaris_group.py index 31663be1846..7e9fc1d074f 100644 --- a/salt/modules/solaris_group.py +++ b/salt/modules/solaris_group.py @@ -54,7 +54,7 @@ def add(name, gid=None, **kwargs): cmd = "groupadd " if gid: - cmd += "-g {} ".format(gid) + cmd += f"-g {gid} " cmd += name ret = __salt__["cmd.run_all"](cmd, python_shell=False) @@ -72,7 +72,7 @@ def delete(name): salt '*' group.delete foo """ - ret = __salt__["cmd.run_all"]("groupdel {}".format(name), python_shell=False) + ret = __salt__["cmd.run_all"](f"groupdel {name}", python_shell=False) return not ret["retcode"] @@ -134,7 +134,7 @@ def chgid(name, gid): pre_gid = __salt__["file.group_to_gid"](name) if gid == pre_gid: return True - cmd = "groupmod -g {} {}".format(gid, name) + cmd = f"groupmod -g {gid} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_gid = __salt__["file.group_to_gid"](name) if post_gid != pre_gid: diff --git a/salt/modules/solaris_shadow.py b/salt/modules/solaris_shadow.py index 65d20f2e9e1..fcf7e934cfd 100644 --- a/salt/modules/solaris_shadow.py +++ b/salt/modules/solaris_shadow.py @@ -144,7 +144,7 @@ def info(name): # 5. Maximum age # 6. Warning period - output = __salt__["cmd.run_all"]("passwd -s {}".format(name), python_shell=False) + output = __salt__["cmd.run_all"](f"passwd -s {name}", python_shell=False) if output["retcode"] != 0: return ret @@ -183,7 +183,7 @@ def set_maxdays(name, maxdays): pre_info = info(name) if maxdays == pre_info["max"]: return True - cmd = "passwd -x {} {}".format(maxdays, name) + cmd = f"passwd -x {maxdays} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["max"] != pre_info["max"]: @@ -203,7 +203,7 @@ def set_mindays(name, mindays): pre_info = info(name) if mindays == pre_info["min"]: return True - cmd = "passwd -n {} {}".format(mindays, name) + cmd = f"passwd -n {mindays} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["min"] != pre_info["min"]: @@ -265,7 +265,7 @@ def del_password(name): salt '*' shadow.del_password username """ - cmd = "passwd -d {}".format(name) + cmd = f"passwd -d {name}" __salt__["cmd.run"](cmd, python_shell=False, output_loglevel="quiet") uinfo = info(name) return not uinfo["passwd"] @@ -296,7 +296,7 @@ def set_password(name, password): continue comps[1] = password line = ":".join(comps) - lines.append("{}\n".format(line)) + lines.append(f"{line}\n") with salt.utils.files.fopen(s_file, "w+") as ofile: lines = [salt.utils.stringutils.to_str(_l) for _l in lines] ofile.writelines(lines) @@ -318,7 +318,7 @@ def set_warndays(name, warndays): pre_info = info(name) if warndays == pre_info["warn"]: return True - cmd = "passwd -w {} {}".format(warndays, name) + cmd = f"passwd -w {warndays} {name}" __salt__["cmd.run"](cmd, python_shell=False) post_info = info(name) if post_info["warn"] != pre_info["warn"]: diff --git a/salt/modules/solaris_user.py b/salt/modules/solaris_user.py index e8d7d0b2bc4..be705b2f0a6 100644 --- a/salt/modules/solaris_user.py +++ b/salt/modules/solaris_user.py @@ -10,7 +10,6 @@ Manage users with the useradd command """ - import copy import logging @@ -109,7 +108,7 @@ def add( workphone="", homephone="", createhome=True, - **kwargs + **kwargs, ): """ Add a user to the minion @@ -219,7 +218,7 @@ def chuid(name, uid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if uid == pre_info["uid"]: return True cmd = ["usermod", "-u", uid, name] @@ -239,7 +238,7 @@ def chgid(name, gid): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if gid == pre_info["gid"]: return True cmd = ["usermod", "-g", gid, name] @@ -259,7 +258,7 @@ def chshell(name, shell): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if shell == pre_info["shell"]: return True cmd = ["usermod", "-s", shell, name] @@ -290,7 +289,7 @@ def chhome(name, home, persist=False): """ pre_info = info(name) if not pre_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") if home == pre_info["home"]: return True cmd = ["usermod", "-d", home] @@ -458,10 +457,10 @@ def rename(name, new_name): """ current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") cmd = ["usermod", "-l", new_name, name] __salt__["cmd.run"](cmd, python_shell=False) return info(new_name).get("name") == new_name diff --git a/salt/modules/solarisipspkg.py b/salt/modules/solarisipspkg.py index 6e6e4f6610f..1d720db0656 100644 --- a/salt/modules/solarisipspkg.py +++ b/salt/modules/solarisipspkg.py @@ -539,19 +539,19 @@ def install(name=None, refresh=False, pkgs=None, version=None, test=False, **kwa if getattr(pkg, "items", False): if list(pkg.items())[0][1]: # version specified pkg2inst.append( - "{}@{}".format(list(pkg.items())[0][0], list(pkg.items())[0][1]) + f"{list(pkg.items())[0][0]}@{list(pkg.items())[0][1]}" ) else: pkg2inst.append(list(pkg.items())[0][0]) else: - pkg2inst.append("{}".format(pkg)) + pkg2inst.append(f"{pkg}") log.debug("Installing these packages instead of %s: %s", name, pkg2inst) else: # install single package if version: - pkg2inst = "{}@{}".format(name, version) + pkg2inst = f"{name}@{version}" else: - pkg2inst = "{}".format(name) + pkg2inst = f"{name}" cmd = ["pkg", "install", "-v", "--accept"] if test: diff --git a/salt/modules/solarispkg.py b/salt/modules/solarispkg.py index fd0ab8d1add..370981b0e7e 100644 --- a/salt/modules/solarispkg.py +++ b/salt/modules/solarispkg.py @@ -65,17 +65,17 @@ def _write_adminfile(kwargs): fp_.write(salt.utils.stringutils.to_str(line)) with salt.utils.files.fopen(adminfile, "w") as fp_: - _write_line(fp_, "email={}\n".format(email)) - _write_line(fp_, "instance={}\n".format(instance)) - _write_line(fp_, "partial={}\n".format(partial)) - _write_line(fp_, "runlevel={}\n".format(runlevel)) - _write_line(fp_, "idepend={}\n".format(idepend)) - _write_line(fp_, "rdepend={}\n".format(rdepend)) - _write_line(fp_, "space={}\n".format(space)) - _write_line(fp_, "setuid={}\n".format(setuid)) - _write_line(fp_, "conflict={}\n".format(conflict)) - _write_line(fp_, "action={}\n".format(action)) - _write_line(fp_, "basedir={}\n".format(basedir)) + _write_line(fp_, f"email={email}\n") + _write_line(fp_, f"instance={instance}\n") + _write_line(fp_, f"partial={partial}\n") + _write_line(fp_, f"runlevel={runlevel}\n") + _write_line(fp_, f"idepend={idepend}\n") + _write_line(fp_, f"rdepend={rdepend}\n") + _write_line(fp_, f"space={space}\n") + _write_line(fp_, f"setuid={setuid}\n") + _write_line(fp_, f"conflict={conflict}\n") + _write_line(fp_, f"action={action}\n") + _write_line(fp_, f"basedir={basedir}\n") return adminfile diff --git a/salt/modules/solr.py b/salt/modules/solr.py index 373aee65b20..9654bd36f6c 100644 --- a/salt/modules/solr.py +++ b/salt/modules/solr.py @@ -58,7 +58,6 @@ verbose : True Get verbose output """ - import os import urllib.request @@ -206,7 +205,7 @@ def _format_url(handler, host=None, core_name=None, extra=None): baseurl = __salt__["config.option"]("solr.baseurl") if _get_none_or_value(core_name) is None: if extra is None or len(extra) == 0: - return "http://{}:{}{}/{}?wt=json".format(host, port, baseurl, handler) + return f"http://{host}:{port}{baseurl}/{handler}?wt=json" else: return "http://{}:{}{}/{}?wt=json&{}".format( host, port, baseurl, handler, "&".join(extra) @@ -261,7 +260,7 @@ def _http_request(url, request_timeout=None): data = salt.utils.json.load(urllib.request.urlopen(url, **kwargs)) return _get_return_dict(True, data, []) except Exception as err: # pylint: disable=broad-except - return _get_return_dict(False, {}, ["{} : {}".format(url, err)]) + return _get_return_dict(False, {}, [f"{url} : {err}"]) def _replication_request(command, host=None, core_name=None, params=None): @@ -287,7 +286,7 @@ def _replication_request(command, host=None, core_name=None, params=None): {'success':boolean, 'data':dict, 'errors':list, 'warnings':list} """ params = [] if params is None else params - extra = ["command={}".format(command)] + params + extra = [f"command={command}"] + params url = _format_url("replication", host=host, core_name=core_name, extra=extra) return _http_request(url) @@ -312,7 +311,7 @@ def _get_admin_info(command, host=None, core_name=None): {'success':boolean, 'data':dict, 'errors':list, 'warnings':list} """ - url = _format_url("admin/{}".format(command), host, core_name=core_name) + url = _format_url(f"admin/{command}", host, core_name=core_name) resp = _http_request(url) return resp @@ -391,10 +390,10 @@ def _pre_index_check(handler, host=None, core_name=None): warn = ["An indexing process is already running."] return _get_return_dict(True, warnings=warn) if status != "idle": - errors = ['Unknown status: "{}"'.format(status)] + errors = [f'Unknown status: "{status}"'] return _get_return_dict(False, data=resp["data"], errors=errors) else: - errors = ["Status check failed. Response details: {}".format(resp)] + errors = [f"Status check failed. Response details: {resp}"] return _get_return_dict(False, data=resp["data"], errors=errors) return resp @@ -422,7 +421,7 @@ def _find_value(ret_dict, key, path=None): if path is None: path = key else: - path = "{}:{}".format(path, key) + path = f"{path}:{key}" ret = [] for ikey, val in ret_dict.items(): @@ -740,7 +739,7 @@ def match_index_versions(host=None, core_name=None): if "ERROR" in slave: error = slave["ERROR"] success = False - err = "{}: {} - {}".format(core, error, master_url) + err = f"{core}: {error} - {master_url}" resp["errors"].append(err) # if there was an error return the entire response so the # alterer can get what it wants @@ -865,8 +864,8 @@ def backup(host=None, core_name=None, append_core_to_path=False): params = [] if path is not None: path = path + name if append_core_to_path else path - params.append("&location={}".format(path + name)) - params.append("&numberToKeep={}".format(num_backups)) + params.append(f"&location={path + name}") + params.append(f"&numberToKeep={num_backups}") resp = _replication_request( "backup", host=host, core_name=name, params=params ) @@ -882,8 +881,8 @@ def backup(host=None, core_name=None, append_core_to_path=False): if append_core_to_path: path += core_name if path is not None: - params = ["location={}".format(path)] - params.append("&numberToKeep={}".format(num_backups)) + params = [f"location={path}"] + params.append(f"&numberToKeep={num_backups}") resp = _replication_request( "backup", host=host, core_name=core_name, params=params ) @@ -1059,7 +1058,7 @@ def reload_core(host=None, core_name=None): ret, success, data, resp["errors"], resp["warnings"] ) return ret - extra = ["action=RELOAD", "core={}".format(core_name)] + extra = ["action=RELOAD", f"core={core_name}"] url = _format_url("admin/cores", host=host, core_name=None, extra=extra) return _http_request(url) @@ -1100,7 +1099,7 @@ def core_status(host=None, core_name=None): ret, success, data, resp["errors"], resp["warnings"] ) return ret - extra = ["action=STATUS", "core={}".format(core_name)] + extra = ["action=STATUS", f"core={core_name}"] url = _format_url("admin/cores", host=host, core_name=None, extra=extra) return _http_request(url) @@ -1242,7 +1241,7 @@ def full_import(handler, host=None, core_name=None, options=None, extra=None): return _get_return_dict(False, errors=errors) params = ["command=full-import"] for key, val in options.items(): - params.append("&{}={}".format(key, val)) + params.append(f"&{key}={val}") url = _format_url(handler, host=host, core_name=core_name, extra=params + extra) return _http_request(url) @@ -1295,7 +1294,7 @@ def delta_import(handler, host=None, core_name=None, options=None, extra=None): return _get_return_dict(False, errors=errors) params = ["command=delta-import"] for key, val in options.items(): - params.append("{}={}".format(key, val)) + params.append(f"{key}={val}") url = _format_url(handler, host=host, core_name=core_name, extra=params + extra) return _http_request(url) diff --git a/salt/modules/solrcloud.py b/salt/modules/solrcloud.py index fda16a1ef55..7b594e3292f 100644 --- a/salt/modules/solrcloud.py +++ b/salt/modules/solrcloud.py @@ -314,7 +314,7 @@ def alias_set_collections(alias_name, collections=None, **kwargs): "admin/collections?action=CREATEALIAS&name={alias}&wt=json&collections={collections}".format( alias=alias_name, collections=", ".join(collections) ), - **kwargs + **kwargs, ) @@ -337,7 +337,7 @@ def collection_reload(collection, **kwargs): "admin/collections?action=RELOAD&name={collection}&wt=json".format( collection=collection ), - **kwargs + **kwargs, ) @@ -398,7 +398,7 @@ def collection_backup(collection_name, location, backup_name=None, **kwargs): raise ValueError("Collection doesn't exists") if backup_name is not None: - backup_name = "&name={}".format(backup_name) + backup_name = f"&name={backup_name}" else: backup_name = "" @@ -406,7 +406,7 @@ def collection_backup(collection_name, location, backup_name=None, **kwargs): "{collection}/replication?command=BACKUP&location={location}{backup_name}&wt=json".format( collection=collection_name, backup_name=backup_name, location=location ), - **kwargs + **kwargs, ) @@ -436,7 +436,7 @@ def collection_backup_all(location, backup_name=None, **kwargs): "{collection}/replication?command=BACKUP&location={location}{backup_name}&wt=json".format( collection=collection_name, backup_name=backup_name, location=location ), - **kwargs + **kwargs, ) @@ -481,7 +481,7 @@ def collection_create(collection_name, options=None, **kwargs): "admin/collections?action=CREATE&wt=json&name=" + collection_name + options_string, - **kwargs + **kwargs, ) @@ -566,5 +566,5 @@ def collection_set_options(collection_name, options, **kwargs): "admin/collections?action=MODIFYCOLLECTION&wt=json&collection=" + collection_name + options_string, - **kwargs + **kwargs, ) diff --git a/salt/modules/splunk_search.py b/salt/modules/splunk_search.py index 560874cd23e..d6de25eba63 100644 --- a/salt/modules/splunk_search.py +++ b/salt/modules/splunk_search.py @@ -130,7 +130,7 @@ def update(name, profile="splunk", **kwargs): if old_value != new_value: update_set[key] = new_value update_needed = True - diffs.append("{}: '{}' => '{}'".format(key, old_value, new_value)) + diffs.append(f"{key}: '{old_value}' => '{new_value}'") if update_needed: search.update(**update_set).refresh() return update_set, diffs @@ -286,7 +286,7 @@ def list_all( d = [{"name": name}] # add the rest of the splunk settings, ignoring any defaults description = "" - for (k, v) in sorted(search.content.items()): + for k, v in sorted(search.content.items()): if k in readonly_keys: continue if k.startswith("display."): diff --git a/salt/modules/ssh.py b/salt/modules/ssh.py index 44e7c67da16..0701e963867 100644 --- a/salt/modules/ssh.py +++ b/salt/modules/ssh.py @@ -83,7 +83,7 @@ def _refine_enc(enc): elif enc in also_allowed: return enc else: - raise CommandExecutionError("Incorrect encryption key type '{}'.".format(enc)) + raise CommandExecutionError(f"Incorrect encryption key type '{enc}'.") def _format_auth_line(key, enc, comment, options): @@ -93,7 +93,7 @@ def _format_auth_line(key, enc, comment, options): line = "" if options: line += "{} ".format(",".join(options)) - line += "{} {} {}\n".format(enc, key, comment) + line += f"{enc} {key} {comment}\n" return line @@ -134,7 +134,7 @@ def _get_config_file(user, config): """ uinfo = __salt__["user.info"](user) if not uinfo: - raise CommandExecutionError("User '{}' does not exist".format(user)) + raise CommandExecutionError(f"User '{user}' does not exist") home = uinfo["home"] config = _expand_authorized_keys_path(config, user, home) if not os.path.isabs(config): @@ -183,9 +183,7 @@ def _replace_auth_key( # Write out any changes _fh.writelines(salt.utils.data.encode(lines)) except OSError as exc: - raise CommandExecutionError( - "Problem reading or writing to key file: {}".format(exc) - ) + raise CommandExecutionError(f"Problem reading or writing to key file: {exc}") def _validate_keys(key_file, fingerprint_hash_type): @@ -241,7 +239,7 @@ def _validate_keys(key_file, fingerprint_hash_type): "fingerprint": fingerprint, } except OSError: - raise CommandExecutionError("Problem reading ssh key file {}".format(key_file)) + raise CommandExecutionError(f"Problem reading ssh key file {key_file}") return ret @@ -277,7 +275,7 @@ def _fingerprint(public_key, fingerprint_hash_type): hash_func = getattr(hashlib, hash_type) except AttributeError: raise CommandExecutionError( - "The fingerprint_hash_type {} is not supported.".format(hash_type) + f"The fingerprint_hash_type {hash_type} is not supported." ) try: @@ -305,7 +303,7 @@ def _get_known_hosts_file(config=None, user=None): if not uinfo: return { "status": "error", - "error": "User {} does not exist".format(user), + "error": f"User {user} does not exist", } full = os.path.join(uinfo["home"], config) else: @@ -433,7 +431,7 @@ def check_key_file( return {} s_keys = _validate_keys(keyfile, fingerprint_hash_type) if not s_keys: - err = "No keys detected in {}. Is file properly formatted?".format(source) + err = f"No keys detected in {source}. Is file properly formatted?" log.error(err) __context__["ssh_auth.error"] = err return {} @@ -526,7 +524,7 @@ def rm_auth_key_from_file( s_keys = _validate_keys(lfile, fingerprint_hash_type) if not s_keys: - err = "No keys detected in {}. Is file properly formatted?".format(source) + err = f"No keys detected in {source}. Is file properly formatted?" log.error(err) __context__["ssh_auth.error"] = err return "fail" @@ -568,7 +566,7 @@ def rm_auth_key(user, key, config=".ssh/authorized_keys", fingerprint_hash_type= # Return something sensible if the file doesn't exist if not os.path.isfile(full): - return "Authorized keys file {} not present".format(full) + return f"Authorized keys file {full} not present" lines = [] try: @@ -644,7 +642,7 @@ def set_auth_key_from_file( s_keys = _validate_keys(lfile, fingerprint_hash_type) if not s_keys: - err = "No keys detected in {}. Is file properly formatted?".format(source) + err = f"No keys detected in {source}. Is file properly formatted?" log.error(err) __context__["ssh_auth.error"] = err return "fail" @@ -1009,7 +1007,7 @@ def rm_known_host(user=None, hostname=None, config=None, port=None): if not os.path.isfile(full): return { "status": "error", - "error": "Known hosts file {} does not exist".format(full), + "error": f"Known hosts file {full} does not exist", } ssh_hostname = _hostname_and_port_to_ssh_hostname(hostname, port) @@ -1252,7 +1250,7 @@ def set_known_host( ofile.writelines(salt.utils.data.encode(lines)) except OSError as exception: raise CommandExecutionError( - "Couldn't append to known hosts file: '{}'".format(exception) + f"Couldn't append to known hosts file: '{exception}'" ) if not salt.utils.platform.is_windows(): @@ -1378,7 +1376,7 @@ def hash_known_hosts(user=None, config=None): if not os.path.isfile(full): return { "status": "error", - "error": "Known hosts file {} does not exist".format(full), + "error": f"Known hosts file {full} does not exist", } origmode = os.stat(full).st_mode cmd = ["ssh-keygen", "-H", "-f", full] @@ -1396,7 +1394,7 @@ def _hostname_and_port_to_ssh_hostname(hostname, port=DEFAULT_SSH_PORT): if not port or port == DEFAULT_SSH_PORT: return hostname else: - return "[{}]:{}".format(hostname, port) + return f"[{hostname}]:{port}" def key_is_encrypted(key): diff --git a/salt/modules/state.py b/salt/modules/state.py index 6f23b6f2db3..6440d347ffe 100644 --- a/salt/modules/state.py +++ b/salt/modules/state.py @@ -2345,7 +2345,7 @@ def pkg(pkg_path, pkg_sum, hash_type, test=None, **kwargs): return {} elif f"..{os.sep}" in salt.utils.stringutils.to_unicode(member.path): return {} - s_pkg.extractall(root) + s_pkg.extractall(root) # nosec s_pkg.close() lowstate_json = os.path.join(root, "lowstate.json") with salt.utils.files.fopen(lowstate_json, "r") as fp_: diff --git a/salt/modules/status.py b/salt/modules/status.py index 4b0a3b0d400..ba4567cd48a 100644 --- a/salt/modules/status.py +++ b/salt/modules/status.py @@ -221,9 +221,7 @@ def uptime(): if salt.utils.platform.is_linux(): ut_path = "/proc/uptime" if not os.path.exists(ut_path): - raise CommandExecutionError( - "File {ut_path} was not found.".format(ut_path=ut_path) - ) + raise CommandExecutionError(f"File {ut_path} was not found.") with salt.utils.files.fopen(ut_path) as rfh: seconds = int(float(rfh.read().split()[0])) elif salt.utils.platform.is_sunos(): @@ -267,7 +265,7 @@ def uptime(): "since_iso": boot_time.isoformat(), "since_t": int(curr_seconds - seconds), "days": up_time.days, - "time": "{}:{}".format(up_time.seconds // 3600, up_time.seconds % 3600 // 60), + "time": f"{up_time.seconds // 3600}:{up_time.seconds % 3600 // 60}", } if salt.utils.path.which("who"): @@ -569,7 +567,7 @@ def meminfo(): procn = len(ret["svmon"]) ret["svmon"].append({}) comps = line.split() - pg_space = "{} {}".format(comps[0], comps[1]) + pg_space = f"{comps[0]} {comps[1]}" ret["svmon"][procn][pg_space] = {} for idx, field in enumerate(fields): if len(comps) > idx + 2: @@ -760,7 +758,7 @@ def cpuinfo(): ret["psrinfo"][procn]["family"] = _number(line[4]) ret["psrinfo"][procn]["model"] = _number(line[6]) ret["psrinfo"][procn]["step"] = _number(line[8]) - ret["psrinfo"][procn]["clock"] = "{} {}".format(line[10], line[11][:-1]) + ret["psrinfo"][procn]["clock"] = f"{line[10]} {line[11][:-1]}" return ret def aix_cpuinfo(): @@ -1383,10 +1381,10 @@ def netdev(): ): # fetch device info netstat_ipv4 = __salt__["cmd.run"]( - "netstat -i -I {dev} -n -f inet".format(dev=dev) + f"netstat -i -I {dev} -n -f inet" ).splitlines() netstat_ipv6 = __salt__["cmd.run"]( - "netstat -i -I {dev} -n -f inet6".format(dev=dev) + f"netstat -i -I {dev} -n -f inet6" ).splitlines() # prepare data @@ -1401,14 +1399,14 @@ def netdev(): if val == "Name": continue if val in ["Address", "Net/Dest"]: - ret[dev]["IPv4 {field}".format(field=val)] = val + ret[dev][f"IPv4 {val}"] = val else: ret[dev][val] = _number(val) for val in netstat_ipv6[0][:-1]: if val == "Name": continue if val in ["Address", "Net/Dest"]: - ret[dev]["IPv6 {field}".format(field=val)] = val + ret[dev][f"IPv6 {val}"] = val else: ret[dev][val] = _number(val) @@ -1434,10 +1432,10 @@ def netdev(): # en0 1500 link#3 e2.eb.32.42.84.c 10029731 0 446499 0 0 netstat_ipv4 = __salt__["cmd.run"]( - "netstat -i -n -I {dev} -f inet".format(dev=dev) + f"netstat -i -n -I {dev} -f inet" ).splitlines() netstat_ipv6 = __salt__["cmd.run"]( - "netstat -i -n -I {dev} -f inet6".format(dev=dev) + f"netstat -i -n -I {dev} -f inet6" ).splitlines() # add data diff --git a/salt/modules/statuspage.py b/salt/modules/statuspage.py index 0a38e84102b..09b8cd0b2d6 100644 --- a/salt/modules/statuspage.py +++ b/salt/modules/statuspage.py @@ -18,7 +18,6 @@ In the minion configuration file, the following block is required: .. versionadded:: 2017.7.0 """ - import logging # import third party diff --git a/salt/modules/supervisord.py b/salt/modules/supervisord.py index eee4a9f42cf..1e97e3b7632 100644 --- a/salt/modules/supervisord.py +++ b/salt/modules/supervisord.py @@ -3,7 +3,6 @@ Provide the service module for system supervisord or supervisord in a virtualenv """ - import configparser import os @@ -27,7 +26,7 @@ def _get_supervisorctl_bin(bin_env): if not bin_env: which_result = __salt__["cmd.which_bin"]([cmd]) if which_result is None: - raise CommandNotFoundError("Could not find a `{}` binary".format(cmd)) + raise CommandNotFoundError(f"Could not find a `{cmd}` binary") return which_result # try to get binary from env @@ -35,7 +34,7 @@ def _get_supervisorctl_bin(bin_env): cmd_bin = os.path.join(bin_env, "bin", cmd) if os.path.isfile(cmd_bin): return cmd_bin - raise CommandNotFoundError("Could not find a `{}` binary".format(cmd)) + raise CommandNotFoundError(f"Could not find a `{cmd}` binary") return bin_env @@ -58,7 +57,7 @@ def _get_return(ret): if ret["retcode"] != 0: # This is a non 0 exit code if "ERROR" not in retmsg: - retmsg = "ERROR: {}".format(retmsg) + retmsg = f"ERROR: {retmsg}" return retmsg @@ -372,7 +371,7 @@ def _read_config(conf_file=None): try: config.read(conf_file) except OSError as exc: - raise CommandExecutionError("Unable to read from {}: {}".format(conf_file, exc)) + raise CommandExecutionError(f"Unable to read from {conf_file}: {exc}") return config @@ -394,9 +393,9 @@ def options(name, conf_file=None): salt '*' supervisord.options foo """ config = _read_config(conf_file) - section_name = "program:{}".format(name) + section_name = f"program:{name}" if section_name not in config.sections(): - raise CommandExecutionError("Process '{}' not found".format(name)) + raise CommandExecutionError(f"Process '{name}' not found") ret = {} for key, val in config.items(section_name): val = salt.utils.stringutils.to_num(val.split(";")[0].strip()) @@ -438,7 +437,7 @@ def status_bool(name, expected_state=None, user=None, conf_file=None, bin_env=No salt '*' supervisord.status_bool nginx expected_state='RUNNING' """ - cmd = "status {}".format(name) + cmd = f"status {name}" for line in custom(cmd, user, conf_file, bin_env).splitlines(): if len(line.split()) > 2: process, state, reason = line.split(None, 2) diff --git a/salt/modules/suse_ip.py b/salt/modules/suse_ip.py index 9422c0d91b2..fdff55e37a4 100644 --- a/salt/modules/suse_ip.py +++ b/salt/modules/suse_ip.py @@ -197,7 +197,7 @@ def _parse_ethtool_opts(opts, iface): _raise_error_iface(iface, "advertise", valid) if "channels" in opts: - channels_cmd = "-L {}".format(iface.strip()) + channels_cmd = f"-L {iface.strip()}" channels_params = [] for option in ("rx", "tx", "other", "combined"): if option in opts["channels"]: @@ -557,9 +557,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): if iface_type not in ("bridge",): ethtool = _parse_ethtool_opts(opts, iface) if ethtool: - result["ethtool"] = " ".join( - ["{} {}".format(x, y) for x, y in ethtool.items()] - ) + result["ethtool"] = " ".join([f"{x} {y}" for x, y in ethtool.items()]) if iface_type == "slave": result["proto"] = "none" @@ -571,9 +569,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): raise AttributeError(msg) bonding = _parse_settings_bond(opts, iface) if bonding: - result["bonding"] = " ".join( - ["{}={}".format(x, y) for x, y in bonding.items()] - ) + result["bonding"] = " ".join([f"{x}={y}" for x, y in bonding.items()]) result["devtype"] = "Bond" if "slaves" in opts: if isinstance(opts["slaves"], list): @@ -667,14 +663,14 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): ) or salt.utils.validate.net.ipv6_addr(opt): result["ipaddrs"].append(opt) else: - msg = "{} is invalid ipv4 or ipv6 CIDR".format(opt) + msg = f"{opt} is invalid ipv4 or ipv6 CIDR" log.error(msg) raise AttributeError(msg) if "ipv6addr" in opts: if salt.utils.validate.net.ipv6_addr(opts["ipv6addr"]): result["ipaddrs"].append(opts["ipv6addr"]) else: - msg = "{} is invalid ipv6 CIDR".format(opt) + msg = f"{opt} is invalid ipv6 CIDR" log.error(msg) raise AttributeError(msg) if "ipv6addrs" in opts: @@ -682,7 +678,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface): if salt.utils.validate.net.ipv6_addr(opt): result["ipaddrs"].append(opt) else: - msg = "{} is invalid ipv6 CIDR".format(opt) + msg = f"{opt} is invalid ipv6 CIDR" log.error(msg) raise AttributeError(msg) @@ -878,7 +874,7 @@ def _write_file_iface(iface, data, folder, pattern): """ filename = os.path.join(folder, pattern.format(iface)) if not os.path.exists(folder): - msg = "{} cannot be written. {} does not exist".format(filename, folder) + msg = f"{filename} cannot be written. {folder} does not exist" log.error(msg) raise AttributeError(msg) with salt.utils.files.fopen(filename, "w") as fp_: @@ -987,7 +983,7 @@ def build_interface(iface, iface_type, enabled, **settings): return _get_non_blank_lines(ifcfg) _write_file_iface(iface, ifcfg, _SUSE_NETWORK_SCRIPT_DIR, "ifcfg-{}") - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1036,7 +1032,7 @@ def build_routes(iface, **settings): if iface == "routes": path = _SUSE_NETWORK_ROUTES_FILE else: - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifroute-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifroute-{iface}") _write_file_network(routecfg, path) @@ -1068,7 +1064,7 @@ def down(iface, iface_type=None): """ # Slave devices are controlled by the master. if not iface_type or iface_type.lower() != "slave": - return __salt__["cmd.run"]("ifdown {}".format(iface)) + return __salt__["cmd.run"](f"ifdown {iface}") return None @@ -1089,7 +1085,7 @@ def get_interface(iface): salt '*' ip.get_interface eth0 """ - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifcfg-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifcfg-{iface}") return _read_file(path) @@ -1118,7 +1114,7 @@ def up(iface, iface_type=None): """ # Slave devices are controlled by the master. if not iface_type or iface_type.lower() != "slave": - return __salt__["cmd.run"]("ifup {}".format(iface)) + return __salt__["cmd.run"](f"ifup {iface}") return None @@ -1142,7 +1138,7 @@ def get_routes(iface): if iface == "routes": path = _SUSE_NETWORK_ROUTES_FILE else: - path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, "ifroute-{}".format(iface)) + path = os.path.join(_SUSE_NETWORK_SCRIPT_DIR, f"ifroute-{iface}") return _read_file(path) diff --git a/salt/modules/sysbench.py b/salt/modules/sysbench.py index 9e56ddbbe71..1f44e77fb2a 100644 --- a/salt/modules/sysbench.py +++ b/salt/modules/sysbench.py @@ -79,7 +79,7 @@ def cpu(): # Test beings! for primes in max_primes: - key = "Prime numbers limit: {}".format(primes) + key = f"Prime numbers limit: {primes}" run_command = test_command.format(primes) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -110,7 +110,7 @@ def threads(): # Test begins! for yields, locks in zip(thread_yields, thread_locks): - key = "Yields: {} Locks: {}".format(yields, locks) + key = f"Yields: {yields} Locks: {locks}" run_command = test_command.format(yields, locks) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -149,7 +149,7 @@ def mutex(): # Test begins! for num, locks, loops in zip(mutex_num, mutex_locks, mutex_loops): - key = "Mutex: {} Locks: {} Loops: {}".format(num, locks, loops) + key = f"Mutex: {num} Locks: {locks} Loops: {loops}" run_command = test_command.format(num, locks, loops) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -187,7 +187,7 @@ def memory(): # Test begins! for oper in memory_oper: for scope in memory_scope: - key = "Operation: {} Scope: {}".format(oper, scope) + key = f"Operation: {oper} Scope: {scope}" run_command = test_command.format(oper, scope) result = __salt__["cmd.run"](run_command) ret_val[key] = _parser(result) @@ -228,7 +228,7 @@ def fileio(): # Test begins! for mode in test_modes: - key = "Mode: {}".format(mode) + key = f"Mode: {mode}" # Prepare phase run_command = (test_command + "prepare").format(mode) diff --git a/salt/modules/sysfs.py b/salt/modules/sysfs.py index 0192c038612..f86136c2060 100644 --- a/salt/modules/sysfs.py +++ b/salt/modules/sysfs.py @@ -62,7 +62,7 @@ def write(key, value): key = target(key) log.trace("Writing %s to %s", value, key) with salt.utils.files.fopen(key, "w") as twriter: - twriter.write(salt.utils.stringutils.to_str("{}\n".format(value))) + twriter.write(salt.utils.stringutils.to_str(f"{value}\n")) return True except Exception: # pylint: disable=broad-except return False diff --git a/salt/modules/syslog_ng.py b/salt/modules/syslog_ng.py index 9e8e8829df7..d215d8057b0 100644 --- a/salt/modules/syslog_ng.py +++ b/salt/modules/syslog_ng.py @@ -24,7 +24,6 @@ configuration file. """ - import logging import os import os.path @@ -80,7 +79,7 @@ def _indent(value): """ Returns the indented parameter. """ - return "{}{}".format(_INDENT, value) + return f"{_INDENT}{value}" def _indentln(string): @@ -162,9 +161,9 @@ class Statement(Buildable): def build_header(self): if self.has_name: - return _indentln("{0} {1} {{".format(self.type, self.id)) + return _indentln(f"{self.type} {self.id} {{") else: - return _indentln("{0} {{".format(self.type)) + return _indentln(f"{self.type} {{") def build_tail(self): return _indentln("};") @@ -232,7 +231,7 @@ class Option(Buildable): self.iterable = self.params def build(self): - header = _indentln("{}(".format(self.type)) + header = _indentln(f"{self.type}(") tail = _indentln(");") body = self.build_body() @@ -305,7 +304,7 @@ class TypedParameter(Parameter): self.iterable = self.values def build(self): - header = _indentln("{}(".format(self.type)) + header = _indentln(f"{self.type}(") tail = _indent(")") body = self.build_body() @@ -373,7 +372,7 @@ class TypedParameterValue(ParameterValue): self.iterable = self.arguments def build(self): - header = _indentln("{}(".format(self.type)) + header = _indentln(f"{self.type}(") tail = _indent(")") body = self.build_body() @@ -823,7 +822,7 @@ def config_test(syslog_ng_sbin_dir=None, cfgfile=None): """ params = ["--syntax-only"] if cfgfile: - params.append("--cfgfile={}".format(cfgfile)) + params.append(f"--cfgfile={cfgfile}") try: ret = _run_command_in_extended_path(syslog_ng_sbin_dir, "syslog-ng", params) @@ -937,7 +936,7 @@ def _add_cli_param(params, key, value): Adds key and value as a command line parameter to params. """ if value is not None: - params.append("--{}={}".format(key, value)) + params.append(f"--{key}={value}") def _add_boolean_cli_param(params, key, value): @@ -945,7 +944,7 @@ def _add_boolean_cli_param(params, key, value): Adds key as a command line parameter to params. """ if value is True: - params.append("--{}".format(key)) + params.append(f"--{key}") def stop(name=None): @@ -1041,7 +1040,7 @@ def start( command = [syslog_ng_binary] + params if __opts__.get("test", False): - comment = "Syslog_ng state module will start {}".format(command) + comment = f"Syslog_ng state module will start {command}" return _format_state_result(name, result=None, comment=comment) result = __salt__["cmd.run_all"](command, python_shell=False) @@ -1049,7 +1048,7 @@ def start( command = ["syslog-ng"] + params if __opts__.get("test", False): - comment = "Syslog_ng state module will start {}".format(command) + comment = f"Syslog_ng state module will start {command}" return _format_state_result(name, result=None, comment=comment) result = __salt__["cmd.run_all"](command, python_shell=False) @@ -1157,7 +1156,7 @@ def write_version(name): salt '*' syslog_ng.write_version name="3.6" """ - line = "@version: {}".format(name) + line = f"@version: {name}" try: if os.path.exists(__SYSLOG_NG_CONFIG_FILE): log.debug( diff --git a/salt/modules/system_profiler.py b/salt/modules/system_profiler.py index 5cbb4998a8c..aa3af692a37 100644 --- a/salt/modules/system_profiler.py +++ b/salt/modules/system_profiler.py @@ -8,7 +8,6 @@ information about package receipts and installed applications. """ - import plistlib import subprocess diff --git a/salt/modules/telegram.py b/salt/modules/telegram.py index 79230b5e049..13fceb4cfff 100644 --- a/salt/modules/telegram.py +++ b/salt/modules/telegram.py @@ -104,7 +104,7 @@ def _post_message(message, chat_id, token): :param token: The Telegram API token. :return: Boolean if message was sent successfully. """ - url = "https://api.telegram.org/bot{}/sendMessage".format(token) + url = f"https://api.telegram.org/bot{token}/sendMessage" parameters = dict() if chat_id: diff --git a/salt/modules/telemetry.py b/salt/modules/telemetry.py index 20dcf08c185..450ff383b28 100644 --- a/salt/modules/telemetry.py +++ b/salt/modules/telemetry.py @@ -72,7 +72,7 @@ def _auth(api_key=None, profile="telemetry"): def _update_cache(deployment_id, metric_name, alert): - key = "telemetry.{}.alerts".format(deployment_id) + key = f"telemetry.{deployment_id}.alerts" if key in __context__: alerts = __context__[key] @@ -133,7 +133,7 @@ def get_alert_config( auth = _auth(profile=profile) alert = False - key = "telemetry.{}.alerts".format(deployment_id) + key = f"telemetry.{deployment_id}.alerts" if key not in __context__: try: @@ -209,9 +209,7 @@ def get_notification_channel_id(notify_channel, profile="telemetry"): notification_channel_id = response.json().get("_id") __context__["telemetry.channels"][notify_channel] = notification_channel_id else: - raise Exception( - "Failed to created notification channel {}".format(notify_channel) - ) + raise Exception(f"Failed to created notification channel {notify_channel}") return notification_channel_id @@ -233,8 +231,7 @@ def get_alarms(deployment_id, profile="telemetry"): try: response = requests.get( - _get_telemetry_base(profile) - + "/alerts?deployment={}".format(deployment_id), + _get_telemetry_base(profile) + f"/alerts?deployment={deployment_id}", headers=auth, ) except requests.exceptions.RequestException as e: @@ -247,7 +244,7 @@ def get_alarms(deployment_id, profile="telemetry"): if alarms: return alarms - return "No alarms defined for deployment: {}".format(deployment_id) + return f"No alarms defined for deployment: {deployment_id}" else: # Non 200 response, sent back the error response' return { @@ -275,7 +272,7 @@ def create_alarm(deployment_id, metric_name, data, api_key=None, profile="teleme auth = _auth(api_key, profile) request_uri = _get_telemetry_base(profile) + "/alerts" - key = "telemetry.{}.alerts".format(deployment_id) + key = f"telemetry.{deployment_id}.alerts" # set the notification channels if not already set post_body = { @@ -421,12 +418,12 @@ def delete_alarms( if not alert_ids: return ( False, - "failed to find alert associated with deployment: {}".format(deployment_id), + f"failed to find alert associated with deployment: {deployment_id}", ) failed_to_delete = [] for id in alert_ids: - delete_url = _get_telemetry_base(profile) + "/alerts/{}".format(id) + delete_url = _get_telemetry_base(profile) + f"/alerts/{id}" try: response = requests.delete(delete_url, headers=auth) diff --git a/salt/modules/testinframod.py b/salt/modules/testinframod.py index eb7254a09d6..bac95da5c65 100644 --- a/salt/modules/testinframod.py +++ b/salt/modules/testinframod.py @@ -150,7 +150,7 @@ def _apply_assertion(expected, result): raise return comparison(expected["expected"], result) else: - raise TypeError("Expected bool or dict but received {}".format(type(expected))) + raise TypeError(f"Expected bool or dict but received {type(expected)}") # This does not currently generate documentation from the underlying modules diff --git a/salt/modules/textfsm_mod.py b/salt/modules/textfsm_mod.py index 0e0d390b87d..e11dd5afbb7 100644 --- a/salt/modules/textfsm_mod.py +++ b/salt/modules/textfsm_mod.py @@ -195,20 +195,20 @@ def extract(template_path, raw_text=None, raw_text_file=None, saltenv="base"): fsm_handler = textfsm.TextFSM(tpl_file_handle) except textfsm.TextFSMTemplateError as tfte: log.error("Unable to parse the TextFSM template", exc_info=True) - ret[ - "comment" - ] = "Unable to parse the TextFSM template from {}: {}. Please check the logs.".format( - template_path, tfte + ret["comment"] = ( + "Unable to parse the TextFSM template from {}: {}. Please check the logs.".format( + template_path, tfte + ) ) return ret if not raw_text and raw_text_file: log.debug("Trying to read the raw input from %s", raw_text_file) raw_text = __salt__["cp.get_file_str"](raw_text_file, saltenv=saltenv) if raw_text is False: - ret[ - "comment" - ] = "Unable to read from {}. Please specify a valid input file or text.".format( - raw_text_file + ret["comment"] = ( + "Unable to read from {}. Please specify a valid input file or text.".format( + raw_text_file + ) ) log.error(ret["comment"]) return ret @@ -393,17 +393,17 @@ def index( ) platform = __grains__.get(platform_grain_name) if not platform: - ret[ - "comment" - ] = "Unable to identify the platform name using the {} grain.".format( - platform_grain_name + ret["comment"] = ( + "Unable to identify the platform name using the {} grain.".format( + platform_grain_name + ) ) return ret log.info("Using platform: %s", platform) else: - ret[ - "comment" - ] = "No platform specified, no platform grain identifier configured." + ret["comment"] = ( + "No platform specified, no platform grain identifier configured." + ) log.error(ret["comment"]) return ret if not textfsm_path: @@ -431,10 +431,10 @@ def index( ) log.debug("Cache fun return:\n%s", textfsm_cachedir_ret) if not textfsm_cachedir_ret: - ret[ - "comment" - ] = "Unable to fetch from {}. Is the TextFSM path correctly specified?".format( - textfsm_path + ret["comment"] = ( + "Unable to fetch from {}. Is the TextFSM path correctly specified?".format( + textfsm_path + ) ) log.error(ret["comment"]) return ret @@ -457,10 +457,10 @@ def index( log.debug("Processing the output from %s", output_file) output = __salt__["cp.get_file_str"](output_file, saltenv=saltenv) if output is False: - ret[ - "comment" - ] = "Unable to read from {}. Please specify a valid file or text.".format( - output_file + ret["comment"] = ( + "Unable to read from {}. Please specify a valid file or text.".format( + output_file + ) ) log.error(ret["comment"]) return ret @@ -476,5 +476,5 @@ def index( ret["result"] = True except clitable.CliTableError as cterr: log.error("Unable to proces the CliTable", exc_info=True) - ret["comment"] = "Unable to process the output: {}".format(cterr) + ret["comment"] = f"Unable to process the output: {cterr}" return ret diff --git a/salt/modules/timezone.py b/salt/modules/timezone.py index 9835e0551f6..115ec06eeef 100644 --- a/salt/modules/timezone.py +++ b/salt/modules/timezone.py @@ -2,7 +2,6 @@ Module for managing timezone on POSIX-like systems. """ - import errno import filecmp import logging diff --git a/salt/modules/tls.py b/salt/modules/tls.py index b74b765cfbb..2cc3c09119a 100644 --- a/salt/modules/tls.py +++ b/salt/modules/tls.py @@ -169,7 +169,7 @@ def _microtime(): """ val1, val2 = math.modf(time.time()) val2 = int(val2) - return "{:f}{}".format(val1, val2) + return f"{val1:f}{val2}" def _context_or_config(key): @@ -249,7 +249,7 @@ def _new_serial(ca_name): # record the hash somewhere cachedir = __opts__["cachedir"] log.debug("cachedir: %s", cachedir) - serial_file = "{}/{}.serial".format(cachedir, ca_name) + serial_file = f"{cachedir}/{ca_name}.serial" if not os.path.exists(cachedir): os.makedirs(cachedir) if not os.path.exists(serial_file): @@ -271,9 +271,9 @@ def _get_basic_info(ca_name, cert, ca_dir=None): Get basic info to write out to the index.txt """ if ca_dir is None: - ca_dir = "{}/{}".format(_cert_base_path(), ca_name) + ca_dir = f"{_cert_base_path()}/{ca_name}" - index_file = "{}/index.txt".format(ca_dir) + index_file = f"{ca_dir}/index.txt" cert = _read_cert(cert) expire_date = _four_digit_year_to_two_digit(_get_expiration_date(cert)) @@ -283,9 +283,7 @@ def _get_basic_info(ca_name, cert, ca_dir=None): subject = "/" # then we can add the rest of the subject - subject += "/".join( - ["{}={}".format(x, y) for x, y in cert.get_subject().get_components()] - ) + subject += "/".join([f"{x}={y}" for x, y in cert.get_subject().get_components()]) subject += "\n" return (index_file, expire_date, serial_number, subject) @@ -302,7 +300,7 @@ def _write_cert_to_database(ca_name, cert, cacert_path=None, status="V"): certificate to be recorded """ set_ca_path(cacert_path) - ca_dir = "{}/{}".format(cert_base_path(), ca_name) + ca_dir = f"{cert_base_path()}/{ca_name}" index_file, expire_date, serial_number, subject = _get_basic_info( ca_name, cert, ca_dir ) @@ -338,9 +336,9 @@ def maybe_fix_ssl_version(ca_name, cacert_path=None, ca_filename=None): """ set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) - certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) - ca_keyp = "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + ca_filename = f"{ca_name}_ca_cert" + certp = f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" + ca_keyp = f"{cert_base_path()}/{ca_name}/{ca_filename}.key" with salt.utils.files.fopen(certp) as fic: cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, fic.read()) if cert.get_version() == 3: @@ -398,8 +396,8 @@ def ca_exists(ca_name, cacert_path=None, ca_filename=None): """ set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) - certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + ca_filename = f"{ca_name}_ca_cert" + certp = f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" if os.path.exists(certp): maybe_fix_ssl_version(ca_name, cacert_path=cacert_path, ca_filename=ca_filename) return True @@ -431,7 +429,7 @@ def get_ca(ca_name, as_text=False, cacert_path=None): set_ca_path(cacert_path) certp = "{0}/{1}/{1}_ca_cert.crt".format(cert_base_path(), ca_name) if not os.path.exists(certp): - raise ValueError("Certificate does not exist for {}".format(ca_name)) + raise ValueError(f"Certificate does not exist for {ca_name}") else: if as_text: with salt.utils.files.fopen(certp) as fic: @@ -468,9 +466,9 @@ def get_ca_signed_cert( if not cert_filename: cert_filename = CN - certp = "{}/{}/certs/{}.crt".format(cert_base_path(), ca_name, cert_filename) + certp = f"{cert_base_path()}/{ca_name}/certs/{cert_filename}.crt" if not os.path.exists(certp): - raise ValueError("Certificate does not exists for {}".format(CN)) + raise ValueError(f"Certificate does not exists for {CN}") else: if as_text: with salt.utils.files.fopen(certp) as fic: @@ -512,9 +510,9 @@ def get_ca_signed_key( if not key_filename: key_filename = CN - keyp = "{}/{}/certs/{}.key".format(cert_base_path(), ca_name, key_filename) + keyp = f"{cert_base_path()}/{ca_name}/certs/{key_filename}.key" if not os.path.exists(keyp): - raise ValueError("Certificate does not exists for {}".format(CN)) + raise ValueError(f"Certificate does not exists for {CN}") else: if as_text: with salt.utils.files.fopen(keyp) as fic: @@ -559,10 +557,10 @@ def validate(cert, ca_name, crl_file): cert_obj = _read_cert(cert) if cert_obj is None: raise CommandExecutionError( - "Failed to read cert from {}, see log for details".format(cert) + f"Failed to read cert from {cert}, see log for details" ) - ca_dir = "{}/{}".format(cert_base_path(), ca_name) - ca_cert = _read_cert("{}/{}_ca_cert.crt".format(ca_dir, ca_name)) + ca_dir = f"{cert_base_path()}/{ca_name}" + ca_cert = _read_cert(f"{ca_dir}/{ca_name}_ca_cert.crt") store.add_cert(ca_cert) # These flags tell OpenSSL to check the leaf as well as the # entire cert chain. @@ -594,7 +592,7 @@ def _get_expiration_date(cert): if cert_obj is None: raise CommandExecutionError( - "Failed to read cert from {}, see log for details".format(cert) + f"Failed to read cert from {cert}, see log for details" ) return datetime.strptime( @@ -734,18 +732,18 @@ def create_ca( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" - certp = "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) - ca_keyp = "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + certp = f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" + ca_keyp = f"{cert_base_path()}/{ca_name}/{ca_filename}.key" if not replace and not fixmode and ca_exists(ca_name, ca_filename=ca_filename): - return 'Certificate for CA named "{}" already exists'.format(ca_name) + return f'Certificate for CA named "{ca_name}" already exists' if fixmode and not os.path.exists(certp): - raise ValueError("{} does not exists, can't fix".format(certp)) + raise ValueError(f"{certp} does not exists, can't fix") - if not os.path.exists("{}/{}".format(cert_base_path(), ca_name)): - os.makedirs("{}/{}".format(cert_base_path(), ca_name)) + if not os.path.exists(f"{cert_base_path()}/{ca_name}"): + os.makedirs(f"{cert_base_path()}/{ca_name}") # try to reuse existing ssl key key = None @@ -932,9 +930,7 @@ def get_extensions(cert_type): # possible user-defined profile or a typo if cert_type not in ext: try: - ext[cert_type] = __salt__["pillar.get"]( - "tls.extensions:{}".format(cert_type) - ) + ext[cert_type] = __salt__["pillar.get"](f"tls.extensions:{cert_type}") except NameError as e: log.debug( "pillar, tls:extensions:%s not available or " @@ -1071,7 +1067,7 @@ def create_csr( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if not ca_exists(ca_name, ca_filename=ca_filename): return 'Certificate for CA named "{}" does not exist, please create it first.'.format( @@ -1079,20 +1075,20 @@ def create_csr( ) if not csr_path: - csr_path = "{}/{}/certs/".format(cert_base_path(), ca_name) + csr_path = f"{cert_base_path()}/{ca_name}/certs/" if not os.path.exists(csr_path): os.makedirs(csr_path) - CN_ext = "_{}".format(cert_type) if type_ext else "" + CN_ext = f"_{cert_type}" if type_ext else "" if not csr_filename: - csr_filename = "{}{}".format(CN, CN_ext) + csr_filename = f"{CN}{CN_ext}" - csr_f = "{}/{}.csr".format(csr_path, csr_filename) + csr_f = f"{csr_path}/{csr_filename}.csr" if not replace and os.path.exists(csr_f): - return 'Certificate Request "{}" already exists'.format(csr_f) + return f'Certificate Request "{csr_f}" already exists' key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) @@ -1153,7 +1149,7 @@ def create_csr( req.sign(key, salt.utils.stringutils.to_str(digest)) # Write private key and request - priv_keyp = "{}/{}.key".format(csr_path, csr_filename) + priv_keyp = f"{csr_path}/{csr_filename}.key" fp = os.open(priv_keyp, os.O_CREAT | os.O_RDWR, 0o600) with salt.utils.files.fopen(fp, "wb+") as priv_key: priv_key.write( @@ -1171,8 +1167,8 @@ def create_csr( ) ) - ret = 'Created Private Key: "{}{}.key" '.format(csr_path, csr_filename) - ret += 'Created CSR for "{}": "{}{}.csr"'.format(CN, csr_path, csr_filename) + ret = f'Created Private Key: "{csr_path}{csr_filename}.key" ' + ret += f'Created CSR for "{CN}": "{csr_path}{csr_filename}.csr"' return ret @@ -1255,16 +1251,16 @@ def create_self_signed_cert( """ set_ca_path(cacert_path) - if not os.path.exists("{}/{}/certs/".format(cert_base_path(), tls_dir)): - os.makedirs("{}/{}/certs/".format(cert_base_path(), tls_dir)) + if not os.path.exists(f"{cert_base_path()}/{tls_dir}/certs/"): + os.makedirs(f"{cert_base_path()}/{tls_dir}/certs/") if not cert_filename: cert_filename = CN if not replace and os.path.exists( - "{}/{}/certs/{}.crt".format(cert_base_path(), tls_dir, cert_filename) + f"{cert_base_path()}/{tls_dir}/certs/{cert_filename}.crt" ): - return 'Certificate "{}" already exists'.format(cert_filename) + return f'Certificate "{cert_filename}" already exists' key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, bits) @@ -1303,7 +1299,7 @@ def create_self_signed_cert( ) ) - crt_path = "{}/{}/certs/{}.crt".format(cert_base_path(), tls_dir, cert_filename) + crt_path = f"{cert_base_path()}/{tls_dir}/certs/{cert_filename}.crt" with salt.utils.files.fopen(crt_path, "wb+") as crt: crt.write( salt.utils.stringutils.to_bytes( @@ -1431,10 +1427,10 @@ def create_ca_signed_cert( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if not cert_path: - cert_path = "{}/{}/certs".format(cert_base_path(), ca_name) + cert_path = f"{cert_base_path()}/{ca_name}/certs" if type_ext: if not cert_type: @@ -1443,14 +1439,14 @@ def create_ca_signed_cert( ) return ret elif cert_type: - CN_ext = "_{}".format(cert_type) + CN_ext = f"_{cert_type}" else: CN_ext = "" - csr_filename = "{}{}".format(CN, CN_ext) + csr_filename = f"{CN}{CN_ext}" if not cert_filename: - cert_filename = "{}{}".format(CN, CN_ext) + cert_filename = f"{CN}{CN_ext}" if not replace and os.path.exists( os.path.join( @@ -1461,29 +1457,29 @@ def create_ca_signed_cert( ) ) ): - return 'Certificate "{}" already exists'.format(cert_filename) + return f'Certificate "{cert_filename}" already exists' try: maybe_fix_ssl_version(ca_name, cacert_path=cacert_path, ca_filename=ca_filename) with salt.utils.files.fopen( - "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" ) as fhr: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) with salt.utils.files.fopen( - "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.key" ) as fhr: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: ret["retcode"] = 1 - ret["comment"] = 'There is no CA named "{}"'.format(ca_name) + ret["comment"] = f'There is no CA named "{ca_name}"' return ret try: - csr_path = "{}/{}.csr".format(cert_path, csr_filename) + csr_path = f"{cert_path}/{csr_filename}.csr" with salt.utils.files.fopen(csr_path) as fhr: req = OpenSSL.crypto.load_certificate_request( OpenSSL.crypto.FILETYPE_PEM, fhr.read() @@ -1539,7 +1535,7 @@ def create_ca_signed_cert( cert.sign(ca_key, salt.utils.stringutils.to_str(digest)) - cert_full_path = "{}/{}.crt".format(cert_path, cert_filename) + cert_full_path = f"{cert_path}/{cert_filename}.crt" with salt.utils.files.fopen(cert_full_path, "wb+") as crt: crt.write( @@ -1590,10 +1586,8 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): salt '*' tls.create_pkcs12 test localhost """ set_ca_path(cacert_path) - if not replace and os.path.exists( - "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN) - ): - return 'Certificate "{}" already exists'.format(CN) + if not replace and os.path.exists(f"{cert_base_path()}/{ca_name}/certs/{CN}.p12"): + return f'Certificate "{CN}" already exists' try: with salt.utils.files.fopen( @@ -1603,23 +1597,23 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: - return 'There is no CA named "{}"'.format(ca_name) + return f'There is no CA named "{ca_name}"' try: with salt.utils.files.fopen( - "{}/{}/certs/{}.crt".format(cert_base_path(), ca_name, CN) + f"{cert_base_path()}/{ca_name}/certs/{CN}.crt" ) as fhr: cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) with salt.utils.files.fopen( - "{}/{}/certs/{}.key".format(cert_base_path(), ca_name, CN) + f"{cert_base_path()}/{ca_name}/certs/{CN}.key" ) as fhr: key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fhr.read() ) except OSError: - return 'There is no certificate that matches the CN "{}"'.format(CN) + return f'There is no certificate that matches the CN "{CN}"' pkcs12 = OpenSSL.crypto.PKCS12() @@ -1628,7 +1622,7 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): pkcs12.set_privatekey(key) with salt.utils.files.fopen( - "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN), "wb" + f"{cert_base_path()}/{ca_name}/certs/{CN}.p12", "wb" ) as ofile: ofile.write( pkcs12.export(passphrase=salt.utils.stringutils.to_bytes(passphrase)) @@ -1780,29 +1774,29 @@ def create_empty_crl( set_ca_path(cacert_path) if not ca_filename: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if not crl_file: - crl_file = "{}/{}/crl.pem".format(_cert_base_path(), ca_name) + crl_file = f"{_cert_base_path()}/{ca_name}/crl.pem" - if os.path.exists("{}".format(crl_file)): - return 'CRL "{}" already exists'.format(crl_file) + if os.path.exists(f"{crl_file}"): + return f'CRL "{crl_file}" already exists' try: with salt.utils.files.fopen( - "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" ) as fp_: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) with salt.utils.files.fopen( - "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.key" ) as fp_: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) except OSError: - return 'There is no CA named "{}"'.format(ca_name) + return f'There is no CA named "{ca_name}"' crl = OpenSSL.crypto.CRL() crl_text = crl.export( @@ -1814,7 +1808,7 @@ def create_empty_crl( with salt.utils.files.fopen(crl_file, "w") as f: f.write(salt.utils.stringutils.to_str(crl_text)) - return 'Created an empty CRL: "{}"'.format(crl_file) + return f'Created an empty CRL: "{crl_file}"' def revoke_cert( @@ -1870,43 +1864,43 @@ def revoke_cert( """ set_ca_path(cacert_path) - ca_dir = "{}/{}".format(cert_base_path(), ca_name) + ca_dir = f"{cert_base_path()}/{ca_name}" if ca_filename is None: - ca_filename = "{}_ca_cert".format(ca_name) + ca_filename = f"{ca_name}_ca_cert" if cert_path is None: - cert_path = "{}/{}/certs".format(_cert_base_path(), ca_name) + cert_path = f"{_cert_base_path()}/{ca_name}/certs" if cert_filename is None: - cert_filename = "{}".format(CN) + cert_filename = f"{CN}" try: with salt.utils.files.fopen( - "{}/{}/{}.crt".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.crt" ) as fp_: ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) with salt.utils.files.fopen( - "{}/{}/{}.key".format(cert_base_path(), ca_name, ca_filename) + f"{cert_base_path()}/{ca_name}/{ca_filename}.key" ) as fp_: ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, fp_.read() ) except OSError: - return 'There is no CA named "{}"'.format(ca_name) + return f'There is no CA named "{ca_name}"' - client_cert = _read_cert("{}/{}.crt".format(cert_path, cert_filename)) + client_cert = _read_cert(f"{cert_path}/{cert_filename}.crt") if client_cert is None: - return 'There is no client certificate named "{}"'.format(CN) + return f'There is no client certificate named "{CN}"' index_file, expire_date, serial_number, subject = _get_basic_info( ca_name, client_cert, ca_dir ) - index_serial_subject = "{}\tunknown\t{}".format(serial_number, subject) - index_v_data = "V\t{}\t\t{}".format(expire_date, index_serial_subject) + index_serial_subject = f"{serial_number}\tunknown\t{subject}" + index_v_data = f"V\t{expire_date}\t\t{index_serial_subject}" index_r_data_pattern = re.compile( r"R\t" + expire_date + r"\t\d{12}Z\t" + re.escape(index_serial_subject) ) @@ -1929,10 +1923,10 @@ def revoke_cert( ) except ValueError: ret["retcode"] = 1 - ret[ - "comment" - ] = "Revocation date '{}' does not matchformat '{}'".format( - revoke_date, two_digit_year_fmt + ret["comment"] = ( + "Revocation date '{}' does not matchformat '{}'".format( + revoke_date, two_digit_year_fmt + ) ) return ret elif index_serial_subject in line: @@ -1963,11 +1957,11 @@ def revoke_cert( ) if crl_file is None: - crl_file = "{}/{}/crl.pem".format(_cert_base_path(), ca_name) + crl_file = f"{_cert_base_path()}/{ca_name}/crl.pem" if os.path.isdir(crl_file): ret["retcode"] = 1 - ret["comment"] = 'crl_file "{}" is an existing directory'.format(crl_file) + ret["comment"] = f'crl_file "{crl_file}" is an existing directory' return ret with salt.utils.files.fopen(crl_file, "w") as fp_: diff --git a/salt/modules/tomcat.py b/salt/modules/tomcat.py index 46451508c50..1a15fa83627 100644 --- a/salt/modules/tomcat.py +++ b/salt/modules/tomcat.py @@ -214,11 +214,11 @@ def _wget(cmd, opts=None, url="http://localhost:8080/manager", timeout=180): if url[-1] != "/": url += "/" url6 = url - url += "text/{}".format(cmd) - url6 += "{}".format(cmd) + url += f"text/{cmd}" + url6 += f"{cmd}" if opts: - url += "?{}".format(urllib.parse.urlencode(opts)) - url6 += "?{}".format(urllib.parse.urlencode(opts)) + url += f"?{urllib.parse.urlencode(opts)}" + url6 += f"?{urllib.parse.urlencode(opts)}" # Make the HTTP request urllib.request.install_opener(auth) @@ -257,7 +257,7 @@ def _simple_cmd(cmd, app, url="http://localhost:8080/manager", timeout=180): opts = {"path": app, "version": ls(url)[app]["version"]} return "\n".join(_wget(cmd, opts, url, timeout=timeout)["msg"]) except Exception: # pylint: disable=broad-except - return "FAIL - No context exists for path {}".format(app) + return f"FAIL - No context exists for path {app}" # Functions @@ -565,10 +565,10 @@ def deploy_war( salt '*' tomcat.deploy_war /tmp/application.war /api yes http://localhost:8080/manager """ # Decide the location to copy the war for the deployment - tfile = "salt.{}".format(os.path.basename(war)) + tfile = f"salt.{os.path.basename(war)}" if temp_war_location is not None: if not os.path.isdir(temp_war_location): - return 'Error - "{}" is not a directory'.format(temp_war_location) + return f'Error - "{temp_war_location}" is not a directory' tfile = os.path.join(temp_war_location, tfile) else: tfile = os.path.join(tempfile.gettempdir(), tfile) @@ -589,7 +589,7 @@ def deploy_war( # Prepare options opts = { - "war": "file:{}".format(tfile), + "war": f"file:{tfile}", "path": context, } @@ -710,7 +710,7 @@ def signal(signal=None): if signal not in valid_signals: return - cmd = "{}/bin/catalina.sh {}".format(__catalina_home(), valid_signals[signal]) + cmd = f"{__catalina_home()}/bin/catalina.sh {valid_signals[signal]}" __salt__["cmd.run"](cmd) diff --git a/salt/modules/travisci.py b/salt/modules/travisci.py index 70672403b5b..100890e103a 100644 --- a/salt/modules/travisci.py +++ b/salt/modules/travisci.py @@ -3,6 +3,7 @@ Commands for working with travisci. :depends: pyOpenSSL >= 16.0.0 """ + import base64 import urllib.parse diff --git a/salt/modules/udev.py b/salt/modules/udev.py index 9a734edf4b7..0e4a7473eda 100644 --- a/salt/modules/udev.py +++ b/salt/modules/udev.py @@ -97,7 +97,7 @@ def info(dev): else: qtype = "name" - cmd = "udevadm info --export --query=all --{}={}".format(qtype, dev) + cmd = f"udevadm info --export --query=all --{qtype}={dev}" udev_result = __salt__["cmd.run_all"](cmd, output_loglevel="quiet") if udev_result["retcode"] != 0: diff --git a/salt/modules/upstart_service.py b/salt/modules/upstart_service.py index ee47f6d002a..c59da325e3d 100644 --- a/salt/modules/upstart_service.py +++ b/salt/modules/upstart_service.py @@ -159,7 +159,7 @@ def _runlevel(): ret = _default_runlevel() utmp = _find_utmp() if utmp: - out = __salt__["cmd.run"](["runlevel", "{}".format(utmp)], python_shell=False) + out = __salt__["cmd.run"](["runlevel", f"{utmp}"], python_shell=False) try: ret = out.split()[1] except IndexError: @@ -180,7 +180,7 @@ def _service_is_upstart(name): Jobs are defined in files placed in /etc/init, the name of the job is the filename under this directory without the .conf extension. """ - return os.access("/etc/init/{}.conf".format(name), os.R_OK) + return os.access(f"/etc/init/{name}.conf", os.R_OK) def _upstart_is_disabled(name): @@ -190,7 +190,7 @@ def _upstart_is_disabled(name): NOTE: An Upstart service can also be disabled by placing "manual" in /etc/init/[name].conf. """ - files = ["/etc/init/{}.conf".format(name), "/etc/init/{}.override".format(name)] + files = [f"/etc/init/{name}.conf", f"/etc/init/{name}.override"] for file_name in filter(os.path.isfile, files): with salt.utils.files.fopen(file_name) as fp_: if re.search( @@ -217,7 +217,7 @@ def _service_is_sysv(name): to Upstart's /lib/init/upstart-job, and anything that isn't an executable, like README or skeleton. """ - script = "/etc/init.d/{}".format(name) + script = f"/etc/init.d/{name}" return not _service_is_upstart(name) and os.access(script, os.X_OK) @@ -227,7 +227,7 @@ def _sysv_is_disabled(name): start-up link (starts with "S") to its script in /etc/init.d in the current runlevel. """ - return not bool(glob.glob("/etc/rc{}.d/S*{}".format(_runlevel(), name))) + return not bool(glob.glob(f"/etc/rc{_runlevel()}.d/S*{name}")) def _sysv_is_enabled(name): @@ -508,7 +508,7 @@ def _upstart_disable(name): """ if _upstart_is_disabled(name): return _upstart_is_disabled(name) - override = "/etc/init/{}.override".format(name) + override = f"/etc/init/{name}.override" with salt.utils.files.fopen(override, "a") as ofile: ofile.write(salt.utils.stringutils.to_str("manual\n")) return _upstart_is_disabled(name) @@ -520,8 +520,8 @@ def _upstart_enable(name): """ if _upstart_is_enabled(name): return _upstart_is_enabled(name) - override = "/etc/init/{}.override".format(name) - files = ["/etc/init/{}.conf".format(name), override] + override = f"/etc/init/{name}.override" + files = [f"/etc/init/{name}.conf", override] for file_name in filter(os.path.isfile, files): with salt.utils.files.fopen(file_name, "r+") as fp_: new_text = re.sub( @@ -552,7 +552,7 @@ def enable(name, **kwargs): if _service_is_upstart(name): return _upstart_enable(name) executable = _get_service_exec() - cmd = "{} -f {} defaults".format(executable, name) + cmd = f"{executable} -f {name} defaults" return not __salt__["cmd.retcode"](cmd, python_shell=False) diff --git a/salt/modules/uptime.py b/salt/modules/uptime.py index 8e40717fa8a..e3549cc305e 100644 --- a/salt/modules/uptime.py +++ b/salt/modules/uptime.py @@ -3,7 +3,6 @@ Wrapper around uptime API ========================= """ - import logging from salt.exceptions import CommandExecutionError @@ -43,15 +42,15 @@ def create(name, **params): """ if check_exists(name): - msg = "Trying to create check that already exists : {}".format(name) + msg = f"Trying to create check that already exists : {name}" log.error(msg) raise CommandExecutionError(msg) application_url = _get_application_url() log.debug("[uptime] trying PUT request") params.update(url=name) - req = requests.put("{}/api/checks".format(application_url), data=params) + req = requests.put(f"{application_url}/api/checks", data=params) if not req.ok: - raise CommandExecutionError("request to uptime failed : {}".format(req.reason)) + raise CommandExecutionError(f"request to uptime failed : {req.reason}") log.debug("[uptime] PUT request successful") return req.json()["_id"] @@ -67,16 +66,16 @@ def delete(name): salt '*' uptime.delete http://example.org """ if not check_exists(name): - msg = "Trying to delete check that doesn't exists : {}".format(name) + msg = f"Trying to delete check that doesn't exists : {name}" log.error(msg) raise CommandExecutionError(msg) application_url = _get_application_url() log.debug("[uptime] trying DELETE request") - jcontent = requests.get("{}/api/checks".format(application_url)).json() + jcontent = requests.get(f"{application_url}/api/checks").json() url_id = [x["_id"] for x in jcontent if x["url"] == name][0] - req = requests.delete("{}/api/checks/{}".format(application_url, url_id)) + req = requests.delete(f"{application_url}/api/checks/{url_id}") if not req.ok: - raise CommandExecutionError("request to uptime failed : {}".format(req.reason)) + raise CommandExecutionError(f"request to uptime failed : {req.reason}") log.debug("[uptime] DELETE request successful") return True @@ -106,7 +105,7 @@ def checks_list(): """ application_url = _get_application_url() log.debug("[uptime] get checks") - jcontent = requests.get("{}/api/checks".format(application_url)).json() + jcontent = requests.get(f"{application_url}/api/checks").json() return [x["url"] for x in jcontent] diff --git a/salt/modules/uwsgi.py b/salt/modules/uwsgi.py index 2ede5c17da7..71ced4a4088 100644 --- a/salt/modules/uwsgi.py +++ b/salt/modules/uwsgi.py @@ -40,6 +40,6 @@ def stats(socket): salt '*' uwsgi.stats 127.0.0.1:5050 """ - cmd = ["uwsgi", "--connect-and-read", "{}".format(socket)] + cmd = ["uwsgi", "--connect-and-read", f"{socket}"] out = __salt__["cmd.run"](cmd, python_shell=False) return salt.utils.json.loads(out) diff --git a/salt/modules/vault.py b/salt/modules/vault.py index 3f888a3bc9d..0add87959cb 100644 --- a/salt/modules/vault.py +++ b/salt/modules/vault.py @@ -706,6 +706,7 @@ Minion configuration (optional): .. _vault-setup: """ + import logging import salt.utils.vault as vault diff --git a/salt/modules/vbox_guest.py b/salt/modules/vbox_guest.py index 56c576ed211..e646e4f2b86 100644 --- a/salt/modules/vbox_guest.py +++ b/salt/modules/vbox_guest.py @@ -90,19 +90,17 @@ def _return_mount_error(f): def _additions_install_program_path(mount_point): - return os.path.join( - mount_point, - { - "Linux": "VBoxLinuxAdditions.run", - "Solaris": "VBoxSolarisAdditions.pkg", - "Windows": "VBoxWindowsAdditions.exe", - }[__grains__.get("kernel", "")], - ) + mount_points = { + "Linux": "VBoxLinuxAdditions.run", + "Solaris": "VBoxSolarisAdditions.pkg", + "Windows": "VBoxWindowsAdditions.exe", + } + return os.path.join(mount_point, mount_points[__grains__.get("kernel", "")]) def _additions_install_opensuse(**kwargs): kernel_type = re.sub(r"^(\d|\.|-)*", "", __grains__.get("kernelrelease", "")) - kernel_devel = "kernel-{}-devel".format(kernel_type) + kernel_devel = f"kernel-{kernel_type}-devel" return __states__["pkg.installed"](None, pkgs=["make", "gcc", kernel_devel]) @@ -279,7 +277,7 @@ def additions_version(): except OSError: return False if d and len(os.listdir(d)) > 0: - return re.sub(r"^{}-".format(_additions_dir_prefix), "", os.path.basename(d)) + return re.sub(rf"^{_additions_dir_prefix}-", "", os.path.basename(d)) return False diff --git a/salt/modules/vboxmanage.py b/salt/modules/vboxmanage.py index 635734466a2..290de89dfe3 100644 --- a/salt/modules/vboxmanage.py +++ b/salt/modules/vboxmanage.py @@ -15,7 +15,6 @@ The default for this setting is ``False``. :depends: virtualbox """ - import logging import os.path import re @@ -86,7 +85,7 @@ def list_nodes_min(): salt '*' vboxmanage.list_nodes_min """ ret = {} - cmd = "{} list vms".format(vboxcmd()) + cmd = f"{vboxcmd()} list vms" for line in salt.modules.cmdmod.run(cmd).splitlines(): if not line.strip(): continue @@ -148,7 +147,7 @@ def start(name): salt '*' vboxmanage.start my_vm """ ret = {} - cmd = "{} startvm {}".format(vboxcmd(), name) + cmd = f"{vboxcmd()} startvm {name}" ret = salt.modules.cmdmod.run(cmd).splitlines() return ret @@ -163,7 +162,7 @@ def stop(name): salt '*' vboxmanage.stop my_vm """ - cmd = "{} controlvm {} poweroff".format(vboxcmd(), name) + cmd = f"{vboxcmd()} controlvm {name} poweroff" ret = salt.modules.cmdmod.run(cmd).splitlines() return ret @@ -180,10 +179,10 @@ def register(filename): """ if not os.path.isfile(filename): raise CommandExecutionError( - "The specified filename ({}) does not exist.".format(filename) + f"The specified filename ({filename}) does not exist." ) - cmd = "{} registervm {}".format(vboxcmd(), filename) + cmd = f"{vboxcmd()} registervm {filename}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -202,11 +201,9 @@ def unregister(name, delete=False): """ nodes = list_nodes_min() if name not in nodes: - raise CommandExecutionError( - "The specified VM ({}) is not registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is not registered.") - cmd = "{} unregistervm {}".format(vboxcmd(), name) + cmd = f"{vboxcmd()} unregistervm {name}" if delete is True: cmd += " --delete" ret = salt.modules.cmdmod.run_all(cmd) @@ -235,7 +232,7 @@ def create( register=True, basefolder=None, new_uuid=None, - **kwargs + **kwargs, ): """ Create a new VM @@ -248,16 +245,14 @@ def create( """ nodes = list_nodes_min() if name in nodes: - raise CommandExecutionError( - "The specified VM ({}) is already registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is already registered.") params = "" if name: if NAME_RE.search(name): raise CommandExecutionError("New VM name contains invalid characters") - params += " --name {}".format(name) + params += f" --name {name}" if groups: if isinstance(groups, str): @@ -271,9 +266,7 @@ def create( ostypes = list_ostypes() if ostype not in ostypes: - raise CommandExecutionError( - "The specified OS type ({}) is not available.".format(name) - ) + raise CommandExecutionError(f"The specified OS type ({name}) is not available.") else: params += " --ostype " + ostype @@ -282,17 +275,15 @@ def create( if basefolder: if not os.path.exists(basefolder): - raise CommandExecutionError( - "basefolder {} was not found".format(basefolder) - ) - params += " --basefolder {}".format(basefolder) + raise CommandExecutionError(f"basefolder {basefolder} was not found") + params += f" --basefolder {basefolder}" if new_uuid: if NAME_RE.search(new_uuid): raise CommandExecutionError("New UUID contains invalid characters") - params += " --uuid {}".format(new_uuid) + params += f" --uuid {new_uuid}" - cmd = "{} create {}".format(vboxcmd(), params) + cmd = f"{vboxcmd()} create {params}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -311,7 +302,7 @@ def clonevm( new_uuid=None, register=False, groups=None, - **kwargs + **kwargs, ): """ Clone a new VM from an existing VM @@ -332,15 +323,11 @@ def clonevm( nodes_uuids = list_items("vms", True, "UUID").keys() if name: if name not in nodes_names: - raise CommandExecutionError( - "The specified VM ({}) is not registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is not registered.") params += " " + name elif uuid: if uuid not in nodes_uuids: - raise CommandExecutionError( - "The specified VM ({}) is not registered.".format(name) - ) + raise CommandExecutionError(f"The specified VM ({name}) is not registered.") params += " " + uuid if snapshot_name and snapshot_uuid: @@ -351,11 +338,11 @@ def clonevm( if snapshot_name: if NAME_RE.search(snapshot_name): raise CommandExecutionError("Snapshot name contains invalid characters") - params += " --snapshot {}".format(snapshot_name) + params += f" --snapshot {snapshot_name}" elif snapshot_uuid: if UUID_RE.search(snapshot_uuid): raise CommandExecutionError("Snapshot name contains invalid characters") - params += " --snapshot {}".format(snapshot_uuid) + params += f" --snapshot {snapshot_uuid}" valid_modes = ("machine", "machineandchildren", "all") if mode and mode not in valid_modes: @@ -376,7 +363,7 @@ def clonevm( if new_name: if NAME_RE.search(new_name): raise CommandExecutionError("New name contains invalid characters") - params += " --name {}".format(new_name) + params += f" --name {new_name}" if groups: if isinstance(groups, str): @@ -390,20 +377,18 @@ def clonevm( if basefolder: if not os.path.exists(basefolder): - raise CommandExecutionError( - "basefolder {} was not found".format(basefolder) - ) - params += " --basefolder {}".format(basefolder) + raise CommandExecutionError(f"basefolder {basefolder} was not found") + params += f" --basefolder {basefolder}" if new_uuid: if NAME_RE.search(new_uuid): raise CommandExecutionError("New UUID contains invalid characters") - params += " --uuid {}".format(new_uuid) + params += f" --uuid {new_uuid}" if register is True: params += " --register" - cmd = "{} clonevm {}".format(vboxcmd(), name) + cmd = f"{vboxcmd()} clonevm {name}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -419,7 +404,7 @@ def clonemedium( mformat=None, variant=None, existing=False, - **kwargs + **kwargs, ): """ Clone a new VM from an existing VM @@ -455,11 +440,11 @@ def clonemedium( items = list_items(item) if uuid_in not in items: - raise CommandExecutionError("UUID {} was not found".format(uuid_in)) + raise CommandExecutionError(f"UUID {uuid_in} was not found") params += " " + uuid_in elif file_in: if not os.path.exists(file_in): - raise CommandExecutionError("File {} was not found".format(file_in)) + raise CommandExecutionError(f"File {file_in} was not found") params += " " + file_in if (uuid_out and file_out) or (not uuid_out and not file_out): @@ -477,7 +462,7 @@ def clonemedium( os.unlink(file_out) params += " " + file_out except OSError: - raise CommandExecutionError("{} is not a valid filename".format(file_out)) + raise CommandExecutionError(f"{file_out} is not a valid filename") if mformat: valid_mformat = ("VDI", "VMDK", "VHD", "RAW") @@ -504,7 +489,7 @@ def clonemedium( if existing: params += " --existing" - cmd = "{} clonemedium {}".format(vboxcmd(), params) + cmd = f"{vboxcmd()} clonemedium {params}" ret = salt.modules.cmdmod.run_all(cmd) if ret["retcode"] == 0: return True @@ -587,7 +572,7 @@ def list_items(item, details=False, group_by="UUID"): ret = {} tmp_id = None tmp_dict = {} - cmd = "{} list{} {}".format(vboxcmd(), flag, item) + cmd = f"{vboxcmd()} list{flag} {item}" for line in salt.modules.cmdmod.run(cmd).splitlines(): if not line.strip(): continue diff --git a/salt/modules/victorops.py b/salt/modules/victorops.py index c5288355579..058e0f3ed4a 100644 --- a/salt/modules/victorops.py +++ b/salt/modules/victorops.py @@ -11,7 +11,6 @@ Requires an ``api_key`` in ``/etc/salt/minion``: api_key: '280d4699-a817-4719-ba6f-ca56e573e44f' """ - import datetime import logging import time @@ -49,10 +48,10 @@ def _query( path = "https://alert.victorops.com/integrations/generic/20131114/" if action: - path += "{}/".format(action) + path += f"{action}/" if api_key: - path += "{}/".format(api_key) + path += f"{api_key}/" if routing_key: path += routing_key diff --git a/salt/modules/virt.py b/salt/modules/virt.py index 1e671621c25..d7d7cfe65a6 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -116,6 +116,7 @@ ZB 10**21 YB 10**24 ====== ======= """ + # Special Thanks to Michael Dehann, many of the concepts, and a few structures # of his in the virt func module have been used @@ -298,9 +299,7 @@ def _get_domain(conn, *vms, **kwargs): if vms: for name in vms: if name not in all_vms: - raise CommandExecutionError( - 'The VM "{name}" is not present'.format(name=name) - ) + raise CommandExecutionError(f'The VM "{name}" is not present') else: lookup_vms.append(name) else: @@ -324,9 +323,9 @@ def _parse_qemu_img_info(info): "file format": disk_infos["format"], "disk size": disk_infos["actual-size"], "virtual size": disk_infos["virtual-size"], - "cluster size": disk_infos["cluster-size"] - if "cluster-size" in disk_infos - else None, + "cluster size": ( + disk_infos["cluster-size"] if "cluster-size" in disk_infos else None + ), } if "full-backing-filename" in disk_infos.keys(): @@ -515,7 +514,7 @@ def _get_disks(conn, dom): disk_type = elem.get("type") def _get_disk_volume_data(pool_name, volume_name): - qemu_target = "{}/{}".format(pool_name, volume_name) + qemu_target = f"{pool_name}/{volume_name}" pool = conn.storagePoolLookupByName(pool_name) extra_properties = {} try: @@ -553,9 +552,9 @@ def _get_disks(conn, dom): "file": backing_path.text } if backing_format is not None: - extra_properties["backing file"][ - "file format" - ] = backing_format.get("type") + extra_properties["backing file"]["file format"] = ( + backing_format.get("type") + ) except libvirt.libvirtError: # The volume won't be found if the pool is not started, just output less infos log.info( @@ -614,7 +613,7 @@ def _get_disks(conn, dom): qemu_target = source.get("protocol") source_name = source.get("name") if source_name: - qemu_target = "{}:{}".format(qemu_target, source_name) + qemu_target = f"{qemu_target}:{source_name}" # Reverse the magic for the rbd and gluster pools if source.get("protocol") in ["rbd", "gluster"]: @@ -622,7 +621,7 @@ def _get_disks(conn, dom): pool_i_xml = ElementTree.fromstring(pool_i.XMLDesc()) name_node = pool_i_xml.find("source/name") if name_node is not None and source_name.startswith( - "{}/".format(name_node.text) + f"{name_node.text}/" ): qemu_target = "{}{}".format( pool_i.name(), source_name[len(name_node.text) :] @@ -638,7 +637,7 @@ def _get_disks(conn, dom): qemu_target = urllib.parse.urlunparse( ( source.get("protocol"), - "{}:{}".format(hostname, port) if port else hostname, + f"{hostname}:{port}" if port else hostname, source_name, "", saxutils.unescape(source.get("query", "")), @@ -743,9 +742,7 @@ def _migrate(dom, dst_uri, **kwargs): try: bandwidth_value = int(max_bandwidth) except ValueError: - raise SaltInvocationError( - "Invalid max_bandwidth value: {}".format(max_bandwidth) - ) + raise SaltInvocationError(f"Invalid max_bandwidth value: {max_bandwidth}") dom.migrateSetMaxSpeed(bandwidth_value) max_downtime = kwargs.get("max_downtime") @@ -753,9 +750,7 @@ def _migrate(dom, dst_uri, **kwargs): try: downtime_value = int(max_downtime) except ValueError: - raise SaltInvocationError( - "Invalid max_downtime value: {}".format(max_downtime) - ) + raise SaltInvocationError(f"Invalid max_downtime value: {max_downtime}") dom.migrateSetMaxDowntime(downtime_value) if kwargs.get("offline") is True: @@ -776,13 +771,13 @@ def _migrate(dom, dst_uri, **kwargs): "comp_xbzrle_cache": libvirt.VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, } - for (comp_option, param_key) in comp_options.items(): + for comp_option, param_key in comp_options.items(): comp_option_value = kwargs.get(comp_option) if comp_option_value: try: params[param_key] = int(comp_option_value) except ValueError: - raise SaltInvocationError("Invalid {} value".format(comp_option)) + raise SaltInvocationError(f"Invalid {comp_option} value") parallel_connections = kwargs.get("parallel_connections") if parallel_connections: @@ -888,7 +883,7 @@ def _disk_from_pool(conn, pool, pool_xml, volume_name): # Gluster and RBD need pool/volume name name_node = pool_xml.find("./source/name") if name_node is not None: - disk_context["volume"] = "{}/{}".format(name_node.text, volume_name) + disk_context["volume"] = f"{name_node.text}/{volume_name}" # Copy the authentication if any for RBD auth_node = pool_xml.find("./source/auth") if auth_node is not None: @@ -947,7 +942,7 @@ def _gen_xml( consoles=None, stop_on_reboot=False, host_devices=None, - **kwargs + **kwargs, ): """ Generate the XML string to define a libvirt VM @@ -1300,9 +1295,11 @@ def _gen_pool_xml( ): source = { "devices": source_devices or [], - "dir": source_dir - if source_format != "cifs" or not source_dir - else source_dir.lstrip("/"), + "dir": ( + source_dir + if source_format != "cifs" or not source_dir + else source_dir.lstrip("/") + ), "adapter": source_adapter, "hosts": [ {"name": host[0], "port": host[1] if len(host) > 1 else None} @@ -1391,7 +1388,7 @@ def _zfs_image_create( ) ) - destination_fs = os.path.join(pool, "{}.{}".format(vm_name, disk_name)) + destination_fs = os.path.join(pool, f"{vm_name}.{disk_name}") log.debug("Image destination will be %s", destination_fs) existing_disk = __salt__["zfs.list"](name=pool) @@ -1423,9 +1420,7 @@ def _zfs_image_create( sparse=sparse_volume, ) - blockdevice_path = os.path.join( - "/dev/zvol", pool, "{}.{}".format(vm_name, disk_name) - ) + blockdevice_path = os.path.join("/dev/zvol", pool, f"{vm_name}.{disk_name}") log.debug("Image path will be %s", blockdevice_path) return blockdevice_path @@ -1458,7 +1453,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): qcow2 = False if salt.utils.path.which("qemu-img"): - res = __salt__["cmd.run"]('qemu-img info "{}"'.format(sfn)) + res = __salt__["cmd.run"](f'qemu-img info "{sfn}"') imageinfo = salt.utils.yaml.safe_load(res) qcow2 = imageinfo["file format"] == "qcow2" try: @@ -1477,9 +1472,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): if disk_size and qcow2: log.debug("Resize qcow2 image to %sM", disk_size) - __salt__["cmd.run"]( - 'qemu-img resize "{}" {}M'.format(img_dest, disk_size) - ) + __salt__["cmd.run"](f'qemu-img resize "{img_dest}" {disk_size}M') log.debug("Apply umask and remove exec bit") mode = (0o0777 ^ mask) & 0o0666 @@ -1487,7 +1480,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): except OSError as err: raise CommandExecutionError( - "Problem while copying image. {} - {}".format(disk_image, err) + f"Problem while copying image. {disk_image} - {err}" ) else: @@ -1514,7 +1507,7 @@ def _qemu_image_create(disk, create_overlay=False, saltenv="base"): except OSError as err: raise CommandExecutionError( - "Problem while creating volume {} - {}".format(img_dest, err) + f"Problem while creating volume {img_dest} - {err}" ) return img_dest @@ -1730,7 +1723,7 @@ def _fill_disk_filename(conn, vm_name, disk, hypervisor, pool_caps): index = min( idx for idx in range(1, max(indexes) + 2) if idx not in indexes ) - disk["filename"] = "{}{}".format(os.path.basename(device), index) + disk["filename"] = f"{os.path.basename(device)}{index}" # Is the user wanting to reuse an existing volume? if disk.get("source_file"): @@ -2006,7 +1999,7 @@ def init( consoles=None, stop_on_reboot=False, host_devices=None, - **kwargs + **kwargs, ): """ Initialize a new vm @@ -2912,7 +2905,7 @@ def init( consoles, stop_on_reboot, host_devices, - **kwargs + **kwargs, ) log.debug("New virtual machine definition: %s", vm_xml) conn.defineXML(vm_xml) @@ -2982,12 +2975,16 @@ def _nics_equal(nic1, nic2): } return { "type": source_type, - "source": source_getters[source_type](source_node) - if source_node is not None - else None, - "model": nic.find("model").attrib["type"] - if nic.find("model") is not None - else None, + "source": ( + source_getters[source_type](source_node) + if source_node is not None + else None + ), + "model": ( + nic.find("model").attrib["type"] + if nic.find("model") is not None + else None + ), } def _get_mac(nic): @@ -3112,7 +3109,7 @@ def _get_disk_target(targets, disks_count, prefix): :param prefix: the prefix of the target name, i.e. "hd" """ for i in range(disks_count): - ret = "{}{}".format(prefix, string.ascii_lowercase[i]) + ret = f"{prefix}{string.ascii_lowercase[i]}" if ret not in targets: return ret return None @@ -3235,12 +3232,16 @@ def _serial_or_concole_equal(old, new): """ return { "type": item.attrib["type"], - "port": item.find("source").get("service") - if item.find("source") is not None - else None, - "protocol": item.find("protocol").get("type") - if item.find("protocol") is not None - else None, + "port": ( + item.find("source").get("service") + if item.find("source") is not None + else None + ), + "protocol": ( + item.find("protocol").get("type") + if item.find("protocol") is not None + else None + ), } return _filter_serial_or_concole(old) == _filter_serial_or_concole(new) @@ -3294,8 +3295,8 @@ def _compute_device_changes(old_xml, new_xml, to_skip): changes[dev_type] = {} if not to_skip[dev_type]: old = devices_node.findall(dev_type) - new = new_xml.findall("devices/{}".format(dev_type)) - changes[dev_type] = globals()["_diff_{}_lists".format(dev_type)](old, new) + new = new_xml.findall(f"devices/{dev_type}") + changes[dev_type] = globals()[f"_diff_{dev_type}_lists"](old, new) return changes @@ -3499,7 +3500,7 @@ def update( stop_on_reboot=False, host_devices=None, autostart=False, - **kwargs + **kwargs, ): """ Update the definition of an existing domain. @@ -3761,7 +3762,7 @@ def update( consoles=consoles, stop_on_reboot=stop_on_reboot, host_devices=host_devices, - **kwargs + **kwargs, ) ) set_autostart(name, "on" if autostart else "off") @@ -3796,7 +3797,7 @@ def update( # _handle_unit treats bytes as invalid unit for the purpose of consistency unit = unit if unit != "bytes" else "b" value = node.get("memory") or node.get("size") or node.text - return _handle_unit("{}{}".format(value, unit)) if value else None + return _handle_unit(f"{value}{unit}") if value else None def _set_vcpu(node, value): node.text = str(value) @@ -4063,32 +4064,32 @@ def update( for timer in timer_names: params_mapping += [ xmlutil.attribute( - "clock:timers:{}:track".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:track", + f"clock/timer[@name='{timer}']", "track", ["name"], ), xmlutil.attribute( - "clock:timers:{}:tickpolicy".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:tickpolicy", + f"clock/timer[@name='{timer}']", "tickpolicy", ["name"], ), xmlutil.int_attribute( - "clock:timers:{}:frequency".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:frequency", + f"clock/timer[@name='{timer}']", "frequency", ["name"], ), xmlutil.attribute( - "clock:timers:{}:mode".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:mode", + f"clock/timer[@name='{timer}']", "mode", ["name"], ), _yesno_attribute( - "clock:timers:{}:present".format(timer), - "clock/timer[@name='{}']".format(timer), + f"clock:timers:{timer}:present", + f"clock/timer[@name='{timer}']", "present", ["name"], ), @@ -4096,8 +4097,8 @@ def update( for attr in ["slew", "threshold", "limit"]: params_mapping.append( xmlutil.int_attribute( - "clock:timers:{}:{}".format(timer, attr), - "clock/timer[@name='{}']/catchup".format(timer), + f"clock:timers:{timer}:{attr}", + f"clock/timer[@name='{timer}']/catchup", attr, ) ) @@ -5490,7 +5491,7 @@ def migrate(vm_, target, **kwargs): if not urllib.parse.urlparse(target).scheme: proto = "qemu" - dst_uri = "{}://{}/system".format(proto, target) + dst_uri = f"{proto}://{target}/system" else: dst_uri = target @@ -5779,7 +5780,7 @@ def get_hypervisor(): result = [ hyper for hyper in hypervisors - if getattr(sys.modules[__name__], "_is_{}_hyper".format(hyper))() + if getattr(sys.modules[__name__], f"_is_{hyper}_hyper")() ] return result[0] if result else None @@ -5862,7 +5863,7 @@ def vm_cputime(vm_=None, **kwargs): cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus return { "cputime": int(raw[4]), - "cputime_percent": int("{:.0f}".format(cputime_percent)), + "cputime_percent": int(f"{cputime_percent:.0f}"), } info = {} @@ -6134,7 +6135,7 @@ def snapshot(domain, name=None, suffix=None, **kwargs): ) if suffix: - name = "{name}-{suffix}".format(name=name, suffix=suffix) + name = f"{name}-{suffix}" doc = ElementTree.Element("domainsnapshot") n_name = ElementTree.SubElement(doc, "name") @@ -6258,7 +6259,7 @@ def revert_snapshot(name, vm_snapshot=None, cleanup=False, **kwargs): conn.close() raise CommandExecutionError( snapshot - and 'Snapshot "{}" not found'.format(vm_snapshot) + and f'Snapshot "{vm_snapshot}" not found' or "No more previous snapshots available" ) elif snap.isCurrent(): @@ -6363,7 +6364,7 @@ def _parse_caps_cell(cell): if mem_node is not None: unit = mem_node.get("unit", "KiB") memory = mem_node.text - result["memory"] = "{} {}".format(memory, unit) + result["memory"] = f"{memory} {unit}" pages = [ { @@ -6425,7 +6426,7 @@ def _parse_caps_bank(bank): minimum = control.get("min") if minimum: - result_control["min"] = "{} {}".format(minimum, unit) + result_control["min"] = f"{minimum} {unit}" controls.append(result_control) if controls: result["controls"] = controls @@ -6445,15 +6446,19 @@ def _parse_caps_host(host): elif child.tag == "cpu": cpu = { - "arch": child.find("arch").text - if child.find("arch") is not None - else None, - "model": child.find("model").text - if child.find("model") is not None - else None, - "vendor": child.find("vendor").text - if child.find("vendor") is not None - else None, + "arch": ( + child.find("arch").text if child.find("arch") is not None else None + ), + "model": ( + child.find("model").text + if child.find("model") is not None + else None + ), + "vendor": ( + child.find("vendor").text + if child.find("vendor") is not None + else None + ), "features": [ feature.get("name") for feature in child.findall("feature") ], @@ -6499,12 +6504,14 @@ def _parse_caps_host(host): result["security"] = [ { - "model": secmodel.find("model").text - if secmodel.find("model") is not None - else None, - "doi": secmodel.find("doi").text - if secmodel.find("doi") is not None - else None, + "model": ( + secmodel.find("model").text + if secmodel.find("model") is not None + else None + ), + "doi": ( + secmodel.find("doi").text if secmodel.find("doi") is not None else None + ), "baselabels": [ {"type": label.get("type"), "label": label.text} for label in secmodel.findall("baselabel") @@ -6652,9 +6659,9 @@ def _parse_domain_caps(caps): result = { "emulator": caps.find("path").text if caps.find("path") is not None else None, "domain": caps.find("domain").text if caps.find("domain") is not None else None, - "machine": caps.find("machine").text - if caps.find("machine") is not None - else None, + "machine": ( + caps.find("machine").text if caps.find("machine") is not None else None + ), "arch": caps.find("arch").text if caps.find("arch") is not None else None, } @@ -6848,11 +6855,9 @@ def cpu_baseline(full=False, migratable=False, out="libvirt", **kwargs): ] if not cpu_specs: - raise ValueError("Model {} not found in CPU map".format(cpu_model)) + raise ValueError(f"Model {cpu_model} not found in CPU map") elif len(cpu_specs) > 1: - raise ValueError( - "Multiple models {} found in CPU map".format(cpu_model) - ) + raise ValueError(f"Multiple models {cpu_model} found in CPU map") cpu_specs = cpu_specs[0] @@ -6892,7 +6897,7 @@ def network_define( addresses=None, physical_function=None, dns=None, - **kwargs + **kwargs, ): """ Create libvirt network. @@ -7191,7 +7196,7 @@ def network_update( physical_function=None, dns=None, test=False, - **kwargs + **kwargs, ): """ Update a virtual network if needed. @@ -7658,14 +7663,12 @@ def _parse_pools_caps(doc): } for option_kind in ["pool", "vol"]: options = {} - default_format_node = pool.find( - "{}Options/defaultFormat".format(option_kind) - ) + default_format_node = pool.find(f"{option_kind}Options/defaultFormat") if default_format_node is not None: options["default_format"] = default_format_node.get("type") options_enums = { enum.get("name"): [value.text for value in enum.findall("value")] - for enum in pool.findall("{}Options/enum".format(option_kind)) + for enum in pool.findall(f"{option_kind}Options/enum") } if options_enums: options.update(options_enums) @@ -7888,7 +7891,7 @@ def pool_define( source_format=None, transient=False, start=True, # pylint: disable=redefined-outer-name - **kwargs + **kwargs, ): """ Create libvirt pool. @@ -8076,9 +8079,9 @@ def _pool_set_secret( # Create secret if needed if not secret: - description = "Passphrase for {} pool created by Salt".format(pool_name) + description = f"Passphrase for {pool_name} pool created by Salt" if not usage: - usage = "pool_{}".format(pool_name) + usage = f"pool_{pool_name}" secret_xml = _gen_secret_xml(secret_type, usage, description) if not test: secret = conn.secretDefineXML(secret_xml) @@ -8114,7 +8117,7 @@ def pool_update( source_name=None, source_format=None, test=False, - **kwargs + **kwargs, ): """ Update a libvirt storage pool if needed. @@ -8487,7 +8490,7 @@ def pool_undefine(name, **kwargs): } secret_type = auth_types[auth_node.get("type")] secret_usage = auth_node.find("secret").get("usage") - if secret_type and "pool_{}".format(name) == secret_usage: + if secret_type and f"pool_{name}" == secret_usage: secret = conn.secretLookupByUsage(secret_type, secret_usage) secret.undefine() @@ -8719,9 +8722,11 @@ def volume_infos(pool=None, volume=None, **kwargs): if backing_store_path is not None: backing_store = { "path": backing_store_path.text, - "format": backing_store_format.get("type") - if backing_store_format is not None - else None, + "format": ( + backing_store_format.get("type") + if backing_store_format is not None + else None + ), } format_node = vol_xml.find("./target/format") @@ -8809,7 +8814,7 @@ def volume_define( permissions=None, backing_store=None, nocow=False, - **kwargs + **kwargs, ): """ Create libvirt volume. @@ -8910,7 +8915,7 @@ def _volume_upload(conn, pool, volume, file, offset=0, length=0, sparse=False): inData = False eof = os.lseek(fd, 0, os.SEEK_END) if eof < cur: - raise RuntimeError("Current position in file after EOF: {}".format(cur)) + raise RuntimeError(f"Current position in file after EOF: {cur}") sectionLen = eof - cur else: if data > cur: @@ -8963,16 +8968,14 @@ def _volume_upload(conn, pool, volume, file, offset=0, length=0, sparse=False): if stream: stream.abort() if ret: - raise CommandExecutionError( - "Failed to close file: {}".format(err.strerror) - ) + raise CommandExecutionError(f"Failed to close file: {err.strerror}") if stream: try: stream.finish() except libvirt.libvirtError as err: if ret: raise CommandExecutionError( - "Failed to finish stream: {}".format(err.get_error_message()) + f"Failed to finish stream: {err.get_error_message()}" ) return ret diff --git a/salt/modules/virtualenv_mod.py b/salt/modules/virtualenv_mod.py index 81c270196d2..36fd6c9d93d 100644 --- a/salt/modules/virtualenv_mod.py +++ b/salt/modules/virtualenv_mod.py @@ -4,7 +4,6 @@ Create virtualenv environments. .. versionadded:: 0.17.0 """ - import glob import logging import os @@ -21,7 +20,7 @@ from salt.exceptions import CommandExecutionError, SaltInvocationError KNOWN_BINARY_NAMES = frozenset( [ "virtualenv-{}.{}".format(*sys.version_info[:2]), - "virtualenv{}".format(sys.version_info[0]), + f"virtualenv{sys.version_info[0]}", "virtualenv", ] ) @@ -88,7 +87,7 @@ def create( user=None, use_vt=False, saltenv="base", - **kwargs + **kwargs, ): """ Create a virtualenv @@ -212,15 +211,13 @@ def create( if python is not None and python.strip() != "": if not salt.utils.path.which(python): - raise CommandExecutionError( - "Cannot find requested python ({}).".format(python) - ) - cmd.append("--python={}".format(python)) + raise CommandExecutionError(f"Cannot find requested python ({python}).") + cmd.append(f"--python={python}") if extra_search_dir is not None: if isinstance(extra_search_dir, str) and extra_search_dir.strip() != "": extra_search_dir = [e.strip() for e in extra_search_dir.split(",")] for entry in extra_search_dir: - cmd.append("--extra-search-dir={}".format(entry)) + cmd.append(f"--extra-search-dir={entry}") if never_download is True: if (1, 10) <= virtualenv_version_info < (14, 0, 0): log.info( @@ -231,7 +228,7 @@ def create( else: cmd.append("--never-download") if prompt is not None and prompt.strip() != "": - cmd.append("--prompt='{}'".format(prompt)) + cmd.append(f"--prompt='{prompt}'") else: # venv module from the Python >= 3.3 standard library @@ -500,7 +497,7 @@ def _install_script(source, cwd, python, user, saltenv="base", use_vt=False): def _verify_safe_py_code(*args): for arg in args: if not salt.utils.verify.safe_py_code(arg): - raise SaltInvocationError("Unsafe python code detected in '{}'".format(arg)) + raise SaltInvocationError(f"Unsafe python code detected in '{arg}'") def _verify_virtualenv(venv_path): diff --git a/salt/modules/vmctl.py b/salt/modules/vmctl.py index 6b3d7b8880c..01334383f92 100644 --- a/salt/modules/vmctl.py +++ b/salt/modules/vmctl.py @@ -11,7 +11,6 @@ Manage vms running on the OpenBSD VMM hypervisor using vmctl(8). target machine. """ - import logging import re @@ -60,7 +59,7 @@ def create_disk(name, size): salt '*' vmctl.create_disk /path/to/disk.img size=10G """ ret = False - cmd = "vmctl create {} -s {}".format(name, size) + cmd = f"vmctl create {name} -s {size}" result = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False) @@ -89,7 +88,7 @@ def load(path): salt '*' vmctl.load path=/etc/vm.switches.conf """ ret = False - cmd = "vmctl load {}".format(path) + cmd = f"vmctl load {path}" result = __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False) if result["retcode"] == 0: ret = True @@ -227,7 +226,7 @@ def start( name = _id_to_name(id) if nics > 0: - cmd.append("-i {}".format(nics)) + cmd.append(f"-i {nics}") # Paths cannot be appended as otherwise the inserted whitespace is treated by # vmctl as being part of the path. @@ -235,10 +234,10 @@ def start( cmd.extend(["-b", bootpath]) if memory: - cmd.append("-m {}".format(memory)) + cmd.append(f"-m {memory}") if switch: - cmd.append("-n {}".format(switch)) + cmd.append(f"-n {switch}") if local_iface: cmd.append("-L") diff --git a/salt/modules/vsphere.py b/salt/modules/vsphere.py index d05d22168ce..ff62e1ca3c6 100644 --- a/salt/modules/vsphere.py +++ b/salt/modules/vsphere.py @@ -181,7 +181,6 @@ connection credentials are used instead of vCenter credentials, the ``host_names 6500 """ - import datetime import logging import sys @@ -9640,7 +9639,7 @@ def _create_scsi_devices(scsi_devices): log.trace("Creating SCSI devices %s", devs) # unitNumber for disk attachment, 0:0 1st 0 is the controller busNumber, # 2nd is the unitNumber - for (key, scsi_controller) in zip(keys, scsi_devices): + for key, scsi_controller in zip(keys, scsi_devices): # create the SCSI controller scsi_spec = _apply_scsi_controller( scsi_controller["adapter"], @@ -9688,9 +9687,9 @@ def _create_network_adapters(network_interfaces, parent=None): interface["switch_type"], network_adapter_label=interface["adapter"], operation="add", - connectable=interface["connectable"] - if "connectable" in interface - else None, + connectable=( + interface["connectable"] if "connectable" in interface else None + ), mac=interface["mac"], parent=parent, ) @@ -9758,15 +9757,17 @@ def _create_cd_drives(cd_drives, controllers=None, parent_ref=None): key, drive["device_type"], "add", - client_device=drive["client_device"] - if "client_device" in drive - else None, - datastore_iso_file=drive["datastore_iso_file"] - if "datastore_iso_file" in drive - else None, - connectable=drive["connectable"] - if "connectable" in drive - else None, + client_device=( + drive["client_device"] if "client_device" in drive else None + ), + datastore_iso_file=( + drive["datastore_iso_file"] + if "datastore_iso_file" in drive + else None + ), + connectable=( + drive["connectable"] if "connectable" in drive else None + ), controller_key=controller_key, parent_ref=parent_ref, ) @@ -10056,9 +10057,9 @@ def get_vm_config(name, datacenter=None, objects=True, service_instance=None): if isinstance(device, vim.vm.device.VirtualEthernetCard): interface = {} interface["adapter"] = device.deviceInfo.label - interface[ - "adapter_type" - ] = salt.utils.vmware.get_network_adapter_object_type(device) + interface["adapter_type"] = ( + salt.utils.vmware.get_network_adapter_object_type(device) + ) interface["connectable"] = { "allow_guest_control": device.connectable.allowGuestControl, "connected": device.connectable.connected, @@ -10396,12 +10397,16 @@ def _update_cd_drives(drives_old_new, controllers=None, parent=None): current_drive["key"], new_drive["device_type"], "edit", - client_device=new_drive["client_device"] - if "client_device" in new_drive - else None, - datastore_iso_file=new_drive["datastore_iso_file"] - if "datastore_iso_file" in new_drive - else None, + client_device=( + new_drive["client_device"] + if "client_device" in new_drive + else None + ), + datastore_iso_file=( + new_drive["datastore_iso_file"] + if "datastore_iso_file" in new_drive + else None + ), connectable=new_drive["connectable"], controller_key=controller_key, parent_ref=parent, diff --git a/salt/modules/webutil.py b/salt/modules/webutil.py index 42da8f330d4..bb5109d1c2a 100644 --- a/salt/modules/webutil.py +++ b/salt/modules/webutil.py @@ -7,7 +7,6 @@ The functions here will load inside the webutil module. This allows other functions that don't use htpasswd to use the webutil module name. """ - import logging import os @@ -66,7 +65,7 @@ def useradd(pwfile, user, password, opts="", runas=None): if not os.path.exists(pwfile): opts += "c" - cmd = ["htpasswd", "-b{}".format(opts), pwfile, user, password] + cmd = ["htpasswd", f"-b{opts}", pwfile, user, password] return __salt__["cmd.run_all"](cmd, runas=runas, python_shell=False) @@ -140,7 +139,7 @@ def verify(pwfile, user, password, opts="", runas=None): if not os.path.exists(pwfile): return False - cmd = ["htpasswd", "-bv{}".format(opts), pwfile, user, password] + cmd = ["htpasswd", f"-bv{opts}", pwfile, user, password] ret = __salt__["cmd.run_all"](cmd, runas=runas, python_shell=False) log.debug("Result of verifying htpasswd for user %s: %s", user, ret) diff --git a/salt/modules/win_appx.py b/salt/modules/win_appx.py index 0858f9c8c72..e6057f8fa3b 100644 --- a/salt/modules/win_appx.py +++ b/salt/modules/win_appx.py @@ -42,6 +42,7 @@ Not all packages can be found this way, but it seems like most of them can. Use the ``appx.install`` function to provision the new app. """ + import fnmatch import logging diff --git a/salt/modules/win_autoruns.py b/salt/modules/win_autoruns.py index 14497199e25..940474138c1 100644 --- a/salt/modules/win_autoruns.py +++ b/salt/modules/win_autoruns.py @@ -3,7 +3,6 @@ Module for listing programs that automatically run on startup (very alpha...not tested on anything but my Win 7x64) """ - import os import salt.utils.platform diff --git a/salt/modules/win_certutil.py b/salt/modules/win_certutil.py index efed109e2c0..9a0fd737ff7 100644 --- a/salt/modules/win_certutil.py +++ b/salt/modules/win_certutil.py @@ -48,10 +48,10 @@ def get_cert_serial(cert_file, saltenv="base"): # Since we're allowing a path, let's make sure it exists if not os.path.exists(cert_file): - msg = "cert_file not found: {}".format(cert_file) + msg = f"cert_file not found: {cert_file}" raise CommandExecutionError(msg) - cmd = 'certutil.exe -silent -verify "{}"'.format(cert_file) + cmd = f'certutil.exe -silent -verify "{cert_file}"' out = __salt__["cmd.run"](cmd) # match serial number by paragraph to work with multiple languages matches = re.search(r":\s*(\w*)\r\n\r\n", out) @@ -77,7 +77,7 @@ def get_stored_cert_serials(store): salt '*' certutil.get_stored_cert_serials """ - cmd = 'certutil.exe -store "{}"'.format(store) + cmd = f'certutil.exe -store "{store}"' out = __salt__["cmd.run"](cmd) # match serial numbers by header position to work with multiple languages matches = re.findall(r"={16}\r\n.*:\s*(\w*)\r\n", out) @@ -112,10 +112,10 @@ def add_store(source, store, retcode=False, saltenv="base"): # Since we're allowing a path, let's make sure it exists if not os.path.exists(source): - msg = "cert_file not found: {}".format(source) + msg = f"cert_file not found: {source}" raise CommandExecutionError(msg) - cmd = 'certutil.exe -addstore {} "{}"'.format(store, source) + cmd = f'certutil.exe -addstore {store} "{source}"' if retcode: return __salt__["cmd.retcode"](cmd) else: @@ -150,11 +150,11 @@ def del_store(source, store, retcode=False, saltenv="base"): # Since we're allowing a path, let's make sure it exists if not os.path.exists(source): - msg = "cert_file not found: {}".format(source) + msg = f"cert_file not found: {source}" raise CommandExecutionError(msg) serial = get_cert_serial(source) - cmd = 'certutil.exe -delstore {} "{}"'.format(store, serial) + cmd = f'certutil.exe -delstore {store} "{serial}"' if retcode: return __salt__["cmd.retcode"](cmd) else: diff --git a/salt/modules/win_dacl.py b/salt/modules/win_dacl.py index a084a75684f..b8b5aca3dc3 100644 --- a/salt/modules/win_dacl.py +++ b/salt/modules/win_dacl.py @@ -4,7 +4,6 @@ Manage DACLs on Windows :depends: - winreg Python module """ - import logging import os import re @@ -503,17 +502,17 @@ def add_ace(path, objectType, user, permission, acetype, propagation): ) ret["result"] = True except Exception as e: # pylint: disable=broad-except - ret[ - "comment" - ] = "An error occurred attempting to add the ace. The error was {}".format( - e + ret["comment"] = ( + "An error occurred attempting to add the ace. The error was {}".format( + e + ) ) ret["result"] = False return ret if acesAdded: ret["changes"]["Added ACEs"] = acesAdded else: - ret["comment"] = "Unable to obtain the DACL of {}".format(path) + ret["comment"] = f"Unable to obtain the DACL of {path}" else: ret["comment"] = "An empty value was specified for a required item." ret["result"] = False @@ -604,7 +603,7 @@ def rm_ace(path, objectType, user, permission=None, acetype=None, propagation=No ret["result"] = True except Exception as e: # pylint: disable=broad-except ret["result"] = False - ret["comment"] = "Error removing ACE. The error was {}.".format(e) + ret["comment"] = f"Error removing ACE. The error was {e}." return ret else: ret["comment"] = "The specified ACE was not found on the path." @@ -620,9 +619,9 @@ def _ace_to_text(ace, objectType): try: userSid = win32security.LookupAccountSid("", ace[2]) if userSid[1]: - userSid = "{1}\\{0}".format(userSid[0], userSid[1]) + userSid = f"{userSid[1]}\\{userSid[0]}" else: - userSid = "{}".format(userSid[0]) + userSid = f"{userSid[0]}" except Exception: # pylint: disable=broad-except userSid = win32security.ConvertSidToStringSid(ace[2]) tPerm = ace[1] @@ -644,7 +643,7 @@ def _ace_to_text(ace, objectType): if dc.validPropagations[objectType][x]["BITS"] == tProps: tProps = dc.validPropagations[objectType][x]["TEXT"] break - return "{} {} {} on {} {}".format(userSid, tAceType, tPerm, tProps, tInherited) + return f"{userSid} {tAceType} {tPerm} on {tProps} {tInherited}" def _set_dacl_inheritance(path, objectType, inheritance=True, copy=True, clear=False): @@ -730,9 +729,9 @@ def _set_dacl_inheritance(path, objectType, inheritance=True, copy=True, clear=F ret["result"] = True except Exception as e: # pylint: disable=broad-except ret["result"] = False - ret[ - "comment" - ] = "Error attempting to set the inheritance. The error was {}.".format(e) + ret["comment"] = ( + f"Error attempting to set the inheritance. The error was {e}." + ) return ret @@ -818,9 +817,9 @@ def check_inheritance(path, objectType, user=None): dacls = sd.GetSecurityDescriptorDacl() except Exception as e: # pylint: disable=broad-except ret["result"] = False - ret[ - "comment" - ] = "Error obtaining the Security Descriptor or DACL of the path: {}.".format(e) + ret["comment"] = ( + f"Error obtaining the Security Descriptor or DACL of the path: {e}." + ) return ret for counter in range(0, dacls.GetAceCount()): diff --git a/salt/modules/win_disk.py b/salt/modules/win_disk.py index 155efa5fe3f..92fa81ed59d 100644 --- a/salt/modules/win_disk.py +++ b/salt/modules/win_disk.py @@ -53,19 +53,19 @@ def usage(): available_bytes, total_bytes, total_free_bytes, - ) = win32api.GetDiskFreeSpaceEx("{}:\\".format(drive)) + ) = win32api.GetDiskFreeSpaceEx(f"{drive}:\\") used = total_bytes - total_free_bytes capacity = used / float(total_bytes) * 100 - ret["{}:\\".format(drive)] = { - "filesystem": "{}:\\".format(drive), + ret[f"{drive}:\\"] = { + "filesystem": f"{drive}:\\", "1K-blocks": total_bytes / 1024, "used": used / 1024, "available": total_free_bytes / 1024, - "capacity": "{:.0f}%".format(capacity), + "capacity": f"{capacity:.0f}%", } except Exception: # pylint: disable=broad-except - ret["{}:\\".format(drive)] = { - "filesystem": "{}:\\".format(drive), + ret[f"{drive}:\\"] = { + "filesystem": f"{drive}:\\", "1K-blocks": None, "used": None, "available": None, diff --git a/salt/modules/win_dns_client.py b/salt/modules/win_dns_client.py index 89ba38fffb1..d72e344bbf8 100644 --- a/salt/modules/win_dns_client.py +++ b/salt/modules/win_dns_client.py @@ -118,7 +118,7 @@ def add_dns(ip, interface="Local Area Connection", index=1): "dns", interface, ip, - "index={}".format(index), + f"index={index}", "validate=no", ] diff --git a/salt/modules/win_dsc.py b/salt/modules/win_dsc.py index 9c99efae61b..997a72fd787 100644 --- a/salt/modules/win_dsc.py +++ b/salt/modules/win_dsc.py @@ -60,7 +60,7 @@ def _pshell(cmd, cwd=None, json_depth=2, ignore_retcode=False): CommandExecutionError. """ if "convertto-json" not in cmd.lower(): - cmd = "{} | ConvertTo-Json -Depth {}".format(cmd, json_depth) + cmd = f"{cmd} | ConvertTo-Json -Depth {json_depth}" log.debug("DSC: %s", cmd) results = __salt__["cmd.run_all"]( cmd, @@ -75,9 +75,7 @@ def _pshell(cmd, cwd=None, json_depth=2, ignore_retcode=False): if "retcode" not in results or results["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError( - "Issue executing PowerShell {}".format(cmd), info=results - ) + raise CommandExecutionError(f"Issue executing PowerShell {cmd}", info=results) # Sometimes Powershell returns an empty string, which isn't valid JSON if results["stdout"] == "": @@ -267,7 +265,7 @@ def compile_config( path=source, dest=path, saltenv=salt_env, makedirs=True ) if not cached_files: - error = "Failed to cache {}".format(source) + error = f"Failed to cache {source}" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -277,13 +275,13 @@ def compile_config( path=config_data_source, dest=config_data, saltenv=salt_env, makedirs=True ) if not cached_files: - error = "Failed to cache {}".format(config_data_source) + error = f"Failed to cache {config_data_source}" log.error("DSC: %s", error) raise CommandExecutionError(error) # Make sure the path exists if not os.path.exists(path): - error = "{} not found".format(path) + error = f"{path} not found" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -341,8 +339,8 @@ def compile_config( log.info("DSC: Compile Config: %s", ret) return ret - error = "Failed to compile config: {}".format(path) - error += "\nReturned: {}".format(ret) + error = f"Failed to compile config: {path}" + error += f"\nReturned: {ret}" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -394,7 +392,7 @@ def apply_config(path, source=None, salt_env="base"): source_name = os.path.basename(os.path.normpath(source)) if path_name.lower() != source_name.lower(): # Append the Source name to the Path - path = "{}\\{}".format(path, source_name) + path = f"{path}\\{source_name}" log.debug("DSC: %s appended to the path.", source_name) # Destination path minus the basename @@ -402,7 +400,7 @@ def apply_config(path, source=None, salt_env="base"): log.info("DSC: Caching %s", source) cached_files = __salt__["cp.get_dir"](source, dest_path, salt_env) if not cached_files: - error = "Failed to copy {}".format(source) + error = f"Failed to copy {source}" log.error("DSC: %s", error) raise CommandExecutionError(error) else: @@ -410,13 +408,13 @@ def apply_config(path, source=None, salt_env="base"): # Make sure the path exists if not os.path.exists(config): - error = "{} not found".format(config) + error = f"{config} not found" log.error("DSC: %s", error) raise CommandExecutionError(error) # Run the DSC Configuration # Putting quotes around the parameter protects against command injection - cmd = 'Start-DscConfiguration -Path "{}" -Wait -Force'.format(config) + cmd = f'Start-DscConfiguration -Path "{config}" -Wait -Force' _pshell(cmd) cmd = "$status = Get-DscConfigurationStatus; $status.Status" @@ -541,7 +539,7 @@ def remove_config(reset=False): if os.path.exists(path): log.info("DSC: Removing %s", path) if not __salt__["file.remove"](path): - error = "Failed to remove {}".format(path) + error = f"Failed to remove {path}" log.error("DSC: %s", error) raise CommandExecutionError(error) @@ -550,13 +548,13 @@ def remove_config(reset=False): ) # Remove History - _remove_fs_obj("{}\\DSCStatusHistory.mof".format(dsc_config_dir)) + _remove_fs_obj(f"{dsc_config_dir}\\DSCStatusHistory.mof") # Remove Engine Cache - _remove_fs_obj("{}\\DSCEngineCache.mof".format(dsc_config_dir)) + _remove_fs_obj(f"{dsc_config_dir}\\DSCEngineCache.mof") # Remove Status Directory - _remove_fs_obj("{}\\ConfigurationStatus".format(dsc_config_dir)) + _remove_fs_obj(f"{dsc_config_dir}\\ConfigurationStatus") return True @@ -756,7 +754,7 @@ def set_lcm_config( "or ApplyAndAutoCorrect. Passed {}".format(config_mode) ) raise SaltInvocationError(error) - cmd += ' ConfigurationMode = "{}";'.format(config_mode) + cmd += f' ConfigurationMode = "{config_mode}";' if config_mode_freq: if not isinstance(config_mode_freq, int): error = "config_mode_freq must be an integer. Passed {}".format( @@ -771,11 +769,11 @@ def set_lcm_config( raise SaltInvocationError( "refresh_mode must be one of Disabled, Push, or Pull" ) - cmd += ' RefreshMode = "{}";'.format(refresh_mode) + cmd += f' RefreshMode = "{refresh_mode}";' if refresh_freq: if not isinstance(refresh_freq, int): raise SaltInvocationError("refresh_freq must be an integer") - cmd += " RefreshFrequencyMins = {};".format(refresh_freq) + cmd += f" RefreshFrequencyMins = {refresh_freq};" if reboot_if_needed is not None: if not isinstance(reboot_if_needed, bool): raise SaltInvocationError("reboot_if_needed must be a boolean value") @@ -783,22 +781,22 @@ def set_lcm_config( reboot_if_needed = "$true" else: reboot_if_needed = "$false" - cmd += " RebootNodeIfNeeded = {};".format(reboot_if_needed) + cmd += f" RebootNodeIfNeeded = {reboot_if_needed};" if action_after_reboot: if action_after_reboot not in ("ContinueConfiguration", "StopConfiguration"): raise SaltInvocationError( "action_after_reboot must be one of " "ContinueConfiguration or StopConfiguration" ) - cmd += ' ActionAfterReboot = "{}"'.format(action_after_reboot) + cmd += f' ActionAfterReboot = "{action_after_reboot}"' if certificate_id is not None: if certificate_id == "": certificate_id = None - cmd += ' CertificateID = "{}";'.format(certificate_id) + cmd += f' CertificateID = "{certificate_id}";' if configuration_id is not None: if configuration_id == "": configuration_id = None - cmd += ' ConfigurationID = "{}";'.format(configuration_id) + cmd += f' ConfigurationID = "{configuration_id}";' if allow_module_overwrite is not None: if not isinstance(allow_module_overwrite, bool): raise SaltInvocationError("allow_module_overwrite must be a boolean value") @@ -806,7 +804,7 @@ def set_lcm_config( allow_module_overwrite = "$true" else: allow_module_overwrite = "$false" - cmd += " AllowModuleOverwrite = {};".format(allow_module_overwrite) + cmd += f" AllowModuleOverwrite = {allow_module_overwrite};" if debug_mode is not False: if debug_mode is None: debug_mode = "None" @@ -815,7 +813,7 @@ def set_lcm_config( "debug_mode must be one of None, ForceModuleImport, " "ResourceScriptBreakAll, or All" ) - cmd += ' DebugMode = "{}";'.format(debug_mode) + cmd += f' DebugMode = "{debug_mode}";' if status_retention_days: if not isinstance(status_retention_days, int): raise SaltInvocationError("status_retention_days must be an integer") @@ -823,7 +821,7 @@ def set_lcm_config( status_retention_days ) cmd += " }}};" - cmd += r'SaltConfig -OutputPath "{}\SaltConfig"'.format(temp_dir) + cmd += rf'SaltConfig -OutputPath "{temp_dir}\SaltConfig"' # Execute Config to create the .mof _pshell(cmd) @@ -831,7 +829,7 @@ def set_lcm_config( # Apply the config cmd = r'Set-DscLocalConfigurationManager -Path "{}\SaltConfig"' r"".format(temp_dir) ret = __salt__["cmd.run_all"](cmd, shell="powershell", python_shell=True) - __salt__["file.remove"](r"{}\SaltConfig".format(temp_dir)) + __salt__["file.remove"](rf"{temp_dir}\SaltConfig") if not ret["retcode"]: log.info("DSC: LCM config applied successfully") return True diff --git a/salt/modules/win_event.py b/salt/modules/win_event.py index f813abb329a..71fc1ac4928 100644 --- a/salt/modules/win_event.py +++ b/salt/modules/win_event.py @@ -2,6 +2,7 @@ A module for working with the Windows Event log system. .. versionadded:: 3006.0 """ + # https://docs.microsoft.com/en-us/windows/win32/eventlog/event-logging import collections @@ -174,7 +175,7 @@ def _get_handle(log_name): return win32evtlog.OpenEventLog(None, log_name) except pywintypes.error as exc: raise FileNotFoundError( - "Failed to open log: {}\nError: {}".format(log_name, exc.strerror) + f"Failed to open log: {log_name}\nError: {exc.strerror}" ) @@ -679,7 +680,7 @@ def add( if event_type is None: event_type = event_types["Error"] elif event_type not in event_types: - msg = "Incorrect event type: {}".format(event_type) + msg = f"Incorrect event type: {event_type}" raise CommandExecutionError(msg) else: event_type = event_types[event_type] diff --git a/salt/modules/win_firewall.py b/salt/modules/win_firewall.py index 75dbd3f964e..6d8dd025895 100644 --- a/salt/modules/win_firewall.py +++ b/salt/modules/win_firewall.py @@ -151,7 +151,7 @@ def get_rule(name="all"): salt '*' firewall.get_rule 'MyAppPort' """ - cmd = ["netsh", "advfirewall", "firewall", "show", "rule", "name={}".format(name)] + cmd = ["netsh", "advfirewall", "firewall", "show", "rule", f"name={name}"] ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=True) if ret["retcode"] != 0: raise CommandExecutionError(ret["stdout"]) @@ -228,15 +228,15 @@ def add_rule(name, localport, protocol="tcp", action="allow", dir="in", remoteip "firewall", "add", "rule", - "name={}".format(name), - "protocol={}".format(protocol), - "dir={}".format(dir), - "action={}".format(action), - "remoteip={}".format(remoteip), + f"name={name}", + f"protocol={protocol}", + f"dir={dir}", + f"action={action}", + f"remoteip={remoteip}", ] if protocol is None or ("icmpv4" not in protocol and "icmpv6" not in protocol): - cmd.append("localport={}".format(localport)) + cmd.append(f"localport={localport}") ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=True) if ret["retcode"] != 0: @@ -292,19 +292,19 @@ def delete_rule(name=None, localport=None, protocol=None, dir=None, remoteip=Non """ cmd = ["netsh", "advfirewall", "firewall", "delete", "rule"] if name: - cmd.append("name={}".format(name)) + cmd.append(f"name={name}") if protocol: - cmd.append("protocol={}".format(protocol)) + cmd.append(f"protocol={protocol}") if dir: - cmd.append("dir={}".format(dir)) + cmd.append(f"dir={dir}") if remoteip: - cmd.append("remoteip={}".format(remoteip)) + cmd.append(f"remoteip={remoteip}") if protocol is None or ("icmpv4" not in protocol and "icmpv6" not in protocol): if localport: if not protocol: cmd.append("protocol=tcp") - cmd.append("localport={}".format(localport)) + cmd.append(f"localport={localport}") ret = __salt__["cmd.run_all"](cmd, python_shell=False, ignore_retcode=True) if ret["retcode"] != 0: diff --git a/salt/modules/win_iis.py b/salt/modules/win_iis.py index 42ec335bf32..04d2f35d0ba 100644 --- a/salt/modules/win_iis.py +++ b/salt/modules/win_iis.py @@ -8,6 +8,7 @@ Microsoft IIS site management via WebAdministration powershell module .. versionadded:: 2016.3.0 """ + import decimal import logging import os @@ -83,7 +84,7 @@ def _list_certs(certificate_store="My"): ps_cmd = [ "Get-ChildItem", "-Path", - r"'Cert:\LocalMachine\{}'".format(certificate_store), + rf"'Cert:\LocalMachine\{certificate_store}'", "|", "Select-Object DnsNameList, SerialNumber, Subject, Thumbprint, Version", ] @@ -145,9 +146,9 @@ def _srvmgr(cmd, return_json=False): cmd = " ".join(cmd) if return_json: - cmd = "ConvertTo-Json -Compress -Depth 4 -InputObject @({})".format(cmd) + cmd = f"ConvertTo-Json -Compress -Depth 4 -InputObject @({cmd})" - cmd = "Import-Module WebAdministration; {}".format(cmd) + cmd = f"Import-Module WebAdministration; {cmd}" ret = __salt__["cmd.run_all"](cmd, shell="powershell", python_shell=True) @@ -305,7 +306,7 @@ def create_site( salt '*' win_iis.create_site name='My Test Site' sourcepath='c:\\stage' apppool='TestPool' """ protocol = str(protocol).lower() - site_path = r"IIS:\Sites\{}".format(name) + site_path = rf"IIS:\Sites\{name}" binding_info = _get_binding_info(hostheader, ipaddress, port) current_sites = list_sites() @@ -322,9 +323,9 @@ def create_site( ps_cmd = [ "New-Item", "-Path", - r"'{}'".format(site_path), + rf"'{site_path}'", "-PhysicalPath", - r"'{}'".format(sourcepath), + rf"'{sourcepath}'", "-Bindings", "@{{ protocol='{0}'; bindingInformation='{1}' }};".format( protocol, binding_info @@ -342,11 +343,11 @@ def create_site( [ "Set-ItemProperty", "-Path", - "'{}'".format(site_path), + f"'{site_path}'", "-Name", "ApplicationPool", "-Value", - "'{}'".format(apppool), + f"'{apppool}'", ] ) @@ -385,7 +386,7 @@ def modify_site(name, sourcepath=None, apppool=None): salt '*' win_iis.modify_site name='My Test Site' sourcepath='c:\\new_path' apppool='NewTestPool' """ - site_path = r"IIS:\Sites\{}".format(name) + site_path = rf"IIS:\Sites\{name}" current_sites = list_sites() if name not in current_sites: @@ -399,11 +400,11 @@ def modify_site(name, sourcepath=None, apppool=None): [ "Set-ItemProperty", "-Path", - r"'{}'".format(site_path), + rf"'{site_path}'", "-Name", "PhysicalPath", "-Value", - r"'{}'".format(sourcepath), + rf"'{sourcepath}'", ] ) @@ -423,11 +424,11 @@ def modify_site(name, sourcepath=None, apppool=None): [ "Set-ItemProperty", "-Path", - r"'{}'".format(site_path), + rf"'{site_path}'", "-Name", "ApplicationPool", "-Value", - r"'{}'".format(apppool), + rf"'{apppool}'", ] ) @@ -468,7 +469,7 @@ def remove_site(name): log.debug("Site already absent: %s", name) return True - ps_cmd = ["Remove-WebSite", "-Name", r"'{}'".format(name)] + ps_cmd = ["Remove-WebSite", "-Name", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -498,7 +499,7 @@ def stop_site(name): salt '*' win_iis.stop_site name='My Test Site' """ - ps_cmd = ["Stop-WebSite", r"'{}'".format(name)] + ps_cmd = ["Stop-WebSite", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -523,7 +524,7 @@ def start_site(name): salt '*' win_iis.start_site name='My Test Site' """ - ps_cmd = ["Start-WebSite", r"'{}'".format(name)] + ps_cmd = ["Start-WebSite", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -641,31 +642,31 @@ def create_binding( ps_cmd = [ "New-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-HostHeader", - "'{}'".format(hostheader), + f"'{hostheader}'", "-IpAddress", - "'{}'".format(ipaddress), + f"'{ipaddress}'", "-Port", - "'{}'".format(port), + f"'{port}'", "-Protocol", - "'{}'".format(protocol), + f"'{protocol}'", "-SslFlags", - "{}".format(sslflags), + f"{sslflags}", ] else: ps_cmd = [ "New-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-HostHeader", - "'{}'".format(hostheader), + f"'{hostheader}'", "-IpAddress", - "'{}'".format(ipaddress), + f"'{ipaddress}'", "-Port", - "'{}'".format(port), + f"'{port}'", "-Protocol", - "'{}'".format(protocol), + f"'{protocol}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -749,13 +750,13 @@ def modify_binding( ps_cmd = [ "Set-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-BindingInformation", - "'{}'".format(binding), + f"'{binding}'", "-PropertyName", "BindingInformation", "-Value", - "'{}'".format(new_binding), + f"'{new_binding}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -773,13 +774,13 @@ def modify_binding( ps_cmd = [ "Set-WebBinding", "-Name", - "'{}'".format(site), + f"'{site}'", "-BindingInformation", - "'{}'".format(new_binding), + f"'{new_binding}'", "-PropertyName", "sslflags", "-Value", - "'{}'".format(sslflags), + f"'{sslflags}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -822,11 +823,11 @@ def remove_binding(site, hostheader="", ipaddress="*", port=80): ps_cmd = [ "Remove-WebBinding", "-HostHeader", - "'{}'".format(hostheader), + f"'{hostheader}'", "-IpAddress", - "'{}'".format(ipaddress), + f"'{ipaddress}'", "-Port", - "'{}'".format(port), + f"'{port}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -961,19 +962,19 @@ def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslf ps_cmd = [ "New-Item", "-Path", - "'{}'".format(iis7path), + f"'{iis7path}'", "-Thumbprint", - "'{}'".format(name), + f"'{name}'", ] else: ps_cmd = [ "New-Item", "-Path", - "'{}'".format(binding_path), + f"'{binding_path}'", "-Thumbprint", - "'{}'".format(name), + f"'{name}'", "-SSLFlags", - "{}".format(sslflags), + f"{sslflags}", ] cmd_ret = _srvmgr(ps_cmd) @@ -1037,10 +1038,10 @@ def remove_cert_binding(name, site, hostheader="", ipaddress="*", port=443): r"'IIS:\Sites'", "|", "Where-Object", - r" {{ $_.Name -Eq '{0}' }};".format(site), + rf" {{ $_.Name -Eq '{site}' }};", "$Binding = $Site.Bindings.Collection", r"| Where-Object { $_.bindingInformation", - r"-Eq '{0}' }};".format(binding_info), + rf"-Eq '{binding_info}' }};", "$Binding.RemoveSslCertificate()", ] @@ -1167,13 +1168,13 @@ def create_apppool(name): salt '*' win_iis.create_apppool name='MyTestPool' """ current_apppools = list_apppools() - apppool_path = r"IIS:\AppPools\{}".format(name) + apppool_path = rf"IIS:\AppPools\{name}" if name in current_apppools: log.debug("Application pool '%s' already present.", name) return True - ps_cmd = ["New-Item", "-Path", r"'{}'".format(apppool_path)] + ps_cmd = ["New-Item", "-Path", rf"'{apppool_path}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1204,13 +1205,13 @@ def remove_apppool(name): salt '*' win_iis.remove_apppool name='MyTestPool' """ current_apppools = list_apppools() - apppool_path = r"IIS:\AppPools\{}".format(name) + apppool_path = rf"IIS:\AppPools\{name}" if name not in current_apppools: log.debug("Application pool already absent: %s", name) return True - ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(apppool_path), "-Recurse"] + ps_cmd = ["Remove-Item", "-Path", rf"'{apppool_path}'", "-Recurse"] cmd_ret = _srvmgr(ps_cmd) @@ -1242,7 +1243,7 @@ def stop_apppool(name): salt '*' win_iis.stop_apppool name='MyTestPool' """ - ps_cmd = ["Stop-WebAppPool", r"'{}'".format(name)] + ps_cmd = ["Stop-WebAppPool", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1267,7 +1268,7 @@ def start_apppool(name): salt '*' win_iis.start_apppool name='MyTestPool' """ - ps_cmd = ["Start-WebAppPool", r"'{}'".format(name)] + ps_cmd = ["Start-WebAppPool", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1292,7 +1293,7 @@ def restart_apppool(name): salt '*' win_iis.restart_apppool name='MyTestPool' """ - ps_cmd = ["Restart-WebAppPool", r"'{}'".format(name)] + ps_cmd = ["Restart-WebAppPool", rf"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1324,7 +1325,7 @@ def get_container_setting(name, container, settings): ret = dict() ps_cmd = list() ps_cmd_validate = list() - container_path = r"IIS:\{}\{}".format(container, name) + container_path = rf"IIS:\{container}\{name}" if not settings: log.warning("No settings provided") @@ -1338,9 +1339,9 @@ def get_container_setting(name, container, settings): [ "Get-ItemProperty", "-Path", - "'{}'".format(container_path), + f"'{container_path}'", "-Name", - "'{}'".format(setting), + f"'{setting}'", "-ErrorAction", "Stop", "|", @@ -1351,13 +1352,13 @@ def get_container_setting(name, container, settings): # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. - ps_cmd.append("$Property = Get-ItemProperty -Path '{}'".format(container_path)) - ps_cmd.append("-Name '{}' -ErrorAction Stop;".format(setting)) + ps_cmd.append(f"$Property = Get-ItemProperty -Path '{container_path}'") + ps_cmd.append(f"-Name '{setting}' -ErrorAction Stop;") ps_cmd.append(r"if (([String]::IsNullOrEmpty($Property) -eq $False) -and") ps_cmd.append(r"($Property.GetType()).Name -eq 'ConfigurationAttribute') {") ps_cmd.append(r"$Property = $Property | Select-Object") ps_cmd.append(r"-ExpandProperty Value };") - ps_cmd.append("$Settings['{}'] = [String] $Property;".format(setting)) + ps_cmd.append(f"$Settings['{setting}'] = [String] $Property;") ps_cmd.append(r"$Property = $Null;") # Validate the setting names that were passed in. @@ -1425,7 +1426,7 @@ def set_container_setting(name, container, settings): "ApplicationPoolIdentity": "4", } ps_cmd = list() - container_path = r"IIS:\{}\{}".format(container, name) + container_path = rf"IIS:\{container}\{name}" if not settings: log.warning("No settings provided") @@ -1449,7 +1450,7 @@ def set_container_setting(name, container, settings): complex(settings[setting]) value = settings[setting] except ValueError: - value = "'{}'".format(settings[setting]) + value = f"'{settings[setting]}'" # Map to numeric to support server 2008 if ( @@ -1462,18 +1463,18 @@ def set_container_setting(name, container, settings): [ "Set-ItemProperty", "-Path", - "'{}'".format(container_path), + f"'{container_path}'", "-Name", - "'{}'".format(setting), + f"'{setting}'", "-Value", - "{};".format(value), + f"{value};", ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: - msg = "Unable to set settings for {}: {}".format(container, name) + msg = f"Unable to set settings for {container}: {name}" raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values @@ -1520,7 +1521,7 @@ def list_apps(site): """ ret = dict() ps_cmd = list() - ps_cmd.append("Get-WebApplication -Site '{}'".format(site)) + ps_cmd.append(f"Get-WebApplication -Site '{site}'") ps_cmd.append( r"| Select-Object applicationPool, path, PhysicalPath, preloadEnabled," ) @@ -1604,15 +1605,15 @@ def create_app(name, site, sourcepath, apppool=None): ps_cmd = [ "New-WebApplication", "-Name", - "'{}'".format(name), + f"'{name}'", "-Site", - "'{}'".format(site), + f"'{site}'", "-PhysicalPath", - "'{}'".format(sourcepath), + f"'{sourcepath}'", ] if apppool: - ps_cmd.extend(["-ApplicationPool", "'{}'".format(apppool)]) + ps_cmd.extend(["-ApplicationPool", f"'{apppool}'"]) cmd_ret = _srvmgr(ps_cmd) @@ -1658,9 +1659,9 @@ def remove_app(name, site): ps_cmd = [ "Remove-WebApplication", "-Name", - "'{}'".format(name), + f"'{name}'", "-Site", - "'{}'".format(site), + f"'{site}'", ] cmd_ret = _srvmgr(ps_cmd) @@ -1704,9 +1705,9 @@ def list_vdirs(site, app=_DEFAULT_APP): ps_cmd = [ "Get-WebVirtualDirectory", "-Site", - r"'{}'".format(site), + rf"'{site}'", "-Application", - r"'{}'".format(app), + rf"'{app}'", "|", "Select-Object PhysicalPath, @{ Name = 'name';", r"Expression = { $_.path.Trim('/') } }", @@ -1768,15 +1769,15 @@ def create_vdir(name, site, sourcepath, app=_DEFAULT_APP): ps_cmd = [ "New-WebVirtualDirectory", "-Name", - r"'{}'".format(name), + rf"'{name}'", "-Site", - r"'{}'".format(site), + rf"'{site}'", "-PhysicalPath", - r"'{}'".format(sourcepath), + rf"'{sourcepath}'", ] if app != _DEFAULT_APP: - ps_cmd.extend(["-Application", r"'{}'".format(app)]) + ps_cmd.extend(["-Application", rf"'{app}'"]) cmd_ret = _srvmgr(ps_cmd) @@ -1818,8 +1819,8 @@ def remove_vdir(name, site, app=_DEFAULT_APP): app_path = os.path.join(*app.rstrip("/").split("/")) if app_path: - app_path = "{}\\".format(app_path) - vdir_path = r"IIS:\Sites\{}\{}{}".format(site, app_path, name) + app_path = f"{app_path}\\" + vdir_path = rf"IIS:\Sites\{site}\{app_path}{name}" if name not in current_vdirs: log.debug("Virtual directory already absent: %s", name) @@ -1828,7 +1829,7 @@ def remove_vdir(name, site, app=_DEFAULT_APP): # We use Remove-Item here instead of Remove-WebVirtualDirectory, since the # latter has a bug that causes it to always prompt for user input. - ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(vdir_path), "-Recurse"] + ps_cmd = ["Remove-Item", "-Path", rf"'{vdir_path}'", "-Recurse"] cmd_ret = _srvmgr(ps_cmd) @@ -1918,9 +1919,9 @@ def create_backup(name): salt '*' win_iis.create_backup good_config_20170209 """ if name in list_backups(): - raise CommandExecutionError("Backup already present: {}".format(name)) + raise CommandExecutionError(f"Backup already present: {name}") - ps_cmd = ["Backup-WebConfiguration", "-Name", "'{}'".format(name)] + ps_cmd = ["Backup-WebConfiguration", "-Name", f"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1955,7 +1956,7 @@ def remove_backup(name): log.debug("Backup already removed: %s", name) return True - ps_cmd = ["Remove-WebConfigurationBackup", "-Name", "'{}'".format(name)] + ps_cmd = ["Remove-WebConfigurationBackup", "-Name", f"'{name}'"] cmd_ret = _srvmgr(ps_cmd) @@ -1987,7 +1988,7 @@ def list_worker_processes(apppool): salt '*' win_iis.list_worker_processes 'My App Pool' """ - ps_cmd = ["Get-ChildItem", r"'IIS:\AppPools\{}\WorkerProcesses'".format(apppool)] + ps_cmd = ["Get-ChildItem", rf"'IIS:\AppPools\{apppool}\WorkerProcesses'"] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) @@ -2050,20 +2051,16 @@ def get_webapp_settings(name, site, settings): site, name ) ) - pscmd.append( - r' -Name "{}" -ErrorAction Stop | select Value;'.format(setting) - ) + pscmd.append(rf' -Name "{setting}" -ErrorAction Stop | select Value;') pscmd.append( r" $Property = $Property | Select-Object -ExpandProperty Value;" ) - pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) + pscmd.append(rf" $Settings['{setting}'] = [String] $Property;") pscmd.append(r" $Property = $Null;") if setting == "physicalPath" or setting == "applicationPool": - pscmd.append( - r" $Property = (get-webapplication {}).{};".format(name, setting) - ) - pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) + pscmd.append(rf" $Property = (get-webapplication {name}).{setting};") + pscmd.append(rf" $Settings['{setting}'] = [String] $Property;") pscmd.append(r" $Property = $Null;") else: @@ -2171,7 +2168,7 @@ def set_webapp_settings(name, site, settings): complex(settings[setting]) value = settings[setting] except ValueError: - value = "'{}'".format(settings[setting]) + value = f"'{settings[setting]}'" # Append relevant update command per setting key if setting == "userName" or setting == "password": @@ -2181,7 +2178,7 @@ def set_webapp_settings(name, site, settings): site, name ) ) - pscmd.append(' -Name "{}" -Value {};'.format(setting, value)) + pscmd.append(f' -Name "{setting}" -Value {value};') if setting == "physicalPath" or setting == "applicationPool": pscmd.append( @@ -2199,7 +2196,7 @@ def set_webapp_settings(name, site, settings): # Verify commands completed successfully if cmd_ret["retcode"] != 0: - msg = "Unable to set settings for web application {}".format(name) + msg = f"Unable to set settings for web application {name}" raise SaltInvocationError(msg) # verify changes @@ -2252,7 +2249,7 @@ def get_webconfiguration_settings(name, settings): [ "Get-WebConfigurationProperty", "-PSPath", - "'{}'".format(name), + f"'{name}'", "-Filter", "'{}'".format(setting["filter"]), "-Name", @@ -2267,9 +2264,7 @@ def get_webconfiguration_settings(name, settings): # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. - ps_cmd.append( - "$Property = Get-WebConfigurationProperty -PSPath '{}'".format(name) - ) + ps_cmd.append(f"$Property = Get-WebConfigurationProperty -PSPath '{name}'") ps_cmd.append( "-Name '{}' -Filter '{}' -ErrorAction Stop;".format( setting["name"], setting["filter"] @@ -2367,7 +2362,7 @@ def set_webconfiguration_settings(name, settings): for value_item in setting["value"]: configelement_construct = [] for key, value in value_item.items(): - configelement_construct.append("{}='{}'".format(key, value)) + configelement_construct.append(f"{key}='{value}'") configelement_list.append( "@{" + ";".join(configelement_construct) + "}" ) @@ -2377,20 +2372,20 @@ def set_webconfiguration_settings(name, settings): [ "Set-WebConfigurationProperty", "-PSPath", - "'{}'".format(name), + f"'{name}'", "-Filter", "'{}'".format(setting["filter"]), "-Name", "'{}'".format(setting["name"]), "-Value", - "{};".format(value), + f"{value};", ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: - msg = "Unable to set settings for {}".format(name) + msg = f"Unable to set settings for {name}" raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values diff --git a/salt/modules/win_ip.py b/salt/modules/win_ip.py index f1c11cfacbc..524a8d887c2 100644 --- a/salt/modules/win_ip.py +++ b/salt/modules/win_ip.py @@ -132,14 +132,14 @@ def is_enabled(iface): salt -G 'os_family:Windows' ip.is_enabled 'Local Area Connection #2' """ - cmd = ["netsh", "interface", "show", "interface", "name={}".format(iface)] + cmd = ["netsh", "interface", "show", "interface", f"name={iface}"] iface_found = False for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines(): if "Connect state:" in line: iface_found = True return line.split()[-1] == "Connected" if not iface_found: - raise CommandExecutionError("Interface '{}' not found".format(iface)) + raise CommandExecutionError(f"Interface '{iface}' not found") return False @@ -173,7 +173,7 @@ def enable(iface): "interface", "set", "interface", - "name={}".format(iface), + f"name={iface}", "admin=ENABLED", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -197,7 +197,7 @@ def disable(iface): "interface", "set", "interface", - "name={}".format(iface), + f"name={iface}", "admin=DISABLED", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -215,7 +215,7 @@ def get_subnet_length(mask): salt -G 'os_family:Windows' ip.get_subnet_length 255.255.255.0 """ if not salt.utils.validate.net.netmask(mask): - raise SaltInvocationError("'{}' is not a valid netmask".format(mask)) + raise SaltInvocationError(f"'{mask}' is not a valid netmask") return salt.utils.network.get_net_size(mask) @@ -258,17 +258,17 @@ def set_static_ip(iface, addr, gateway=None, append=False): return {} if not salt.utils.validate.net.ipv4_addr(addr): - raise SaltInvocationError("Invalid address '{}'".format(addr)) + raise SaltInvocationError(f"Invalid address '{addr}'") if gateway and not salt.utils.validate.net.ipv4_addr(addr): - raise SaltInvocationError("Invalid default gateway '{}'".format(gateway)) + raise SaltInvocationError(f"Invalid default gateway '{gateway}'") if "/" not in addr: addr += "/32" if append and _find_addr(iface, addr): raise CommandExecutionError( - "Address '{}' already exists on interface '{}'".format(addr, iface) + f"Address '{addr}' already exists on interface '{iface}'" ) cmd = ["netsh", "interface", "ip"] @@ -276,12 +276,12 @@ def set_static_ip(iface, addr, gateway=None, append=False): cmd.append("add") else: cmd.append("set") - cmd.extend(["address", "name={}".format(iface)]) + cmd.extend(["address", f"name={iface}"]) if not append: cmd.append("source=static") - cmd.append("address={}".format(addr)) + cmd.append(f"address={addr}") if gateway: - cmd.append("gateway={}".format(gateway)) + cmd.append(f"gateway={gateway}") result = __salt__["cmd.run_all"](cmd, python_shell=False) if result["retcode"] != 0: @@ -348,7 +348,7 @@ def set_static_dns(iface, *addrs): "ip", "set", "dns", - "name={}".format(iface), + f"name={iface}", "source=static", "address=none", ] @@ -363,9 +363,9 @@ def set_static_dns(iface, *addrs): "ip", "set", "dns", - "name={}".format(iface), + f"name={iface}", "source=static", - "address={}".format(addr), + f"address={addr}", "register=primary", ] __salt__["cmd.run"](cmd, python_shell=False) @@ -377,9 +377,9 @@ def set_static_dns(iface, *addrs): "ip", "add", "dns", - "name={}".format(iface), - "address={}".format(addr), - "index={}".format(addr_index), + f"name={iface}", + f"address={addr}", + f"index={addr_index}", ] __salt__["cmd.run"](cmd, python_shell=False) addr_index = addr_index + 1 diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index 441b549fa50..71a875c5638 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -41,6 +41,7 @@ Current known limitations - struct - salt.utils.win_reg """ + import csv import ctypes import glob @@ -6932,9 +6933,9 @@ def _checkAllAdmxPolicies( TRUE_VALUE_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = True + configured_elements[this_element_name] = ( + True + ) log.trace( "element %s is configured true", child_item.attrib["id"], @@ -6951,9 +6952,9 @@ def _checkAllAdmxPolicies( FALSE_VALUE_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = False + configured_elements[this_element_name] = ( + False + ) policy_disabled_elements = ( policy_disabled_elements + 1 ) @@ -6975,9 +6976,9 @@ def _checkAllAdmxPolicies( TRUE_LIST_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = True + configured_elements[this_element_name] = ( + True + ) log.trace( "element %s is configured true", child_item.attrib["id"], @@ -6994,9 +6995,9 @@ def _checkAllAdmxPolicies( FALSE_LIST_XPATH, policy_file_data, ): - configured_elements[ - this_element_name - ] = False + configured_elements[this_element_name] = ( + False + ) policy_disabled_elements = ( policy_disabled_elements + 1 ) @@ -7096,9 +7097,9 @@ def _checkAllAdmxPolicies( ), policy_file_data, ) - configured_elements[ - this_element_name - ] = configured_value + configured_elements[this_element_name] = ( + configured_value + ) log.trace( "element %s is enabled, value == %s", child_item.attrib["id"], @@ -7218,9 +7219,9 @@ def _checkAllAdmxPolicies( policy_file_data, return_value_name=return_value_name, ) - configured_elements[ - this_element_name - ] = configured_value + configured_elements[this_element_name] = ( + configured_value + ) log.trace( "element %s is enabled values: %s", child_item.attrib["id"], @@ -9396,23 +9397,23 @@ def _get_policy_adm_setting( log.trace( "all valueList items exist in file" ) - configured_elements[ - this_element_name - ] = _getAdmlDisplayName( + configured_elements[this_element_name] = ( + _getAdmlDisplayName( + adml_xml_data=adml_policy_resources, + display_name=enum_item.attrib[ + "displayName" + ], + ) + ) + break + else: + configured_elements[this_element_name] = ( + _getAdmlDisplayName( adml_xml_data=adml_policy_resources, display_name=enum_item.attrib[ "displayName" ], ) - break - else: - configured_elements[ - this_element_name - ] = _getAdmlDisplayName( - adml_xml_data=adml_policy_resources, - display_name=enum_item.attrib[ - "displayName" - ], ) break elif etree.QName(child_item).localname == "list": @@ -9547,12 +9548,12 @@ def _get_policy_adm_setting( this_policy_namespace in policy_vals and this_policy_name in policy_vals[this_policy_namespace] ): - hierarchy.setdefault(this_policy_namespace, {})[ - this_policy_name - ] = _build_parent_list( - policy_definition=admx_policy, - return_full_policy_names=return_full_policy_names, - adml_language=adml_language, + hierarchy.setdefault(this_policy_namespace, {})[this_policy_name] = ( + _build_parent_list( + policy_definition=admx_policy, + return_full_policy_names=return_full_policy_names, + adml_language=adml_language, + ) ) if policy_vals and return_full_policy_names and not hierarchical_return: diff --git a/salt/modules/win_lgpo_reg.py b/salt/modules/win_lgpo_reg.py index 4c88a73c4f4..da0fe393730 100644 --- a/salt/modules/win_lgpo_reg.py +++ b/salt/modules/win_lgpo_reg.py @@ -54,6 +54,7 @@ The same values can also be used to create states for setting these policies. you will have to find the values needed to set them with this module using a different method. """ + import logging import salt.utils.platform diff --git a/salt/modules/win_license.py b/salt/modules/win_license.py index 669521368ef..11851398579 100644 --- a/salt/modules/win_license.py +++ b/salt/modules/win_license.py @@ -6,7 +6,6 @@ This module allows you to manage windows licensing via slmgr.vbs salt '*' license.install XXXXX-XXXXX-XXXXX-XXXXX-XXXXX """ - import logging import re @@ -53,7 +52,7 @@ def install(product_key): salt '*' license.install XXXXX-XXXXX-XXXXX-XXXXX-XXXXX """ - cmd = r"cscript C:\Windows\System32\slmgr.vbs /ipk {}".format(product_key) + cmd = rf"cscript C:\Windows\System32\slmgr.vbs /ipk {product_key}" return __salt__["cmd.run"](cmd) diff --git a/salt/modules/win_network.py b/salt/modules/win_network.py index ad57ca33bc3..d3d9de5681d 100644 --- a/salt/modules/win_network.py +++ b/salt/modules/win_network.py @@ -259,7 +259,7 @@ def get_route(ip): salt '*' network.get_route 10.10.10.10 """ - cmd = "Find-NetRoute -RemoteIPAddress {}".format(ip) + cmd = f"Find-NetRoute -RemoteIPAddress {ip}" out = __salt__["cmd.run"](cmd, shell="powershell", python_shell=True) regexp = re.compile( r"^IPAddress\s+:\s(?P[\d\.:]+)?.*" @@ -492,7 +492,7 @@ def connect(host, port=None, **kwargs): ): address = host else: - address = "{}".format(salt.utils.network.sanitize_host(host)) + address = f"{salt.utils.network.sanitize_host(host)}" # just in case we encounter error on getaddrinfo _address = ("unknown",) diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index c2ea64d823a..3b9224c4815 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -36,7 +36,6 @@ old. """ - import collections import datetime import errno diff --git a/salt/modules/win_pki.py b/salt/modules/win_pki.py index defb92e9d8b..d7129bcf2a1 100644 --- a/salt/modules/win_pki.py +++ b/salt/modules/win_pki.py @@ -90,10 +90,10 @@ def _validate_cert_path(name): """ Ensure that the certificate path, as determind from user input, is valid. """ - cmd = r"Test-Path -Path '{}'".format(name) + cmd = rf"Test-Path -Path '{name}'" if not ast.literal_eval(_cmd_run(cmd=cmd)): - raise SaltInvocationError(r"Invalid path specified: {}".format(name)) + raise SaltInvocationError(rf"Invalid path specified: {name}") def _validate_cert_format(name): @@ -155,11 +155,11 @@ def get_certs(context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE): ret = dict() cmd = list() blacklist_keys = ["DnsNameList"] - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" _validate_cert_path(name=store_path) - cmd.append(r"Get-ChildItem -Path '{}' | Select-Object".format(store_path)) + cmd.append(rf"Get-ChildItem -Path '{store_path}' | Select-Object") cmd.append(" DnsNameList, SerialNumber, Subject, Thumbprint, Version") items = _cmd_run(cmd="".join(cmd), as_json=True) @@ -216,15 +216,15 @@ def get_cert_file(name, cert_format=_DEFAULT_FORMAT, password=""): cmd.append( " System.Security.Cryptography.X509Certificates.X509Certificate2;" ) - cmd.append(r" $CertObject.Import('{}'".format(name)) - cmd.append(",'{}'".format(password)) + cmd.append(rf" $CertObject.Import('{name}'") + cmd.append(f",'{password}'") cmd.append(",'DefaultKeySet') ; $CertObject") cmd.append( " | Select-Object DnsNameList, SerialNumber, Subject, " "Thumbprint, Version" ) else: - cmd.append(r"Get-PfxCertificate -FilePath '{}'".format(name)) + cmd.append(rf"Get-PfxCertificate -FilePath '{name}'") cmd.append( " | Select-Object DnsNameList, SerialNumber, Subject, " "Thumbprint, Version" @@ -232,7 +232,7 @@ def get_cert_file(name, cert_format=_DEFAULT_FORMAT, password=""): else: cmd.append("$CertObject = New-Object") cmd.append(" System.Security.Cryptography.X509Certificates.X509Certificate2;") - cmd.append(r" $CertObject.Import('{}'); $CertObject".format(name)) + cmd.append(rf" $CertObject.Import('{name}'); $CertObject") cmd.append( " | Select-Object DnsNameList, SerialNumber, Subject, Thumbprint, Version" ) @@ -288,7 +288,7 @@ def import_cert( """ cmd = list() thumbprint = None - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" cert_format = cert_format.lower() _validate_cert_format(name=cert_format) @@ -331,14 +331,14 @@ def import_cert( cmd.append( r"Import-PfxCertificate " r"-FilePath '{}'".format(cached_source_path) ) - cmd.append(r" -CertStoreLocation '{}'".format(store_path)) + cmd.append(rf" -CertStoreLocation '{store_path}'") cmd.append(r" -Password $Password") if exportable: cmd.append(" -Exportable") else: cmd.append(r"Import-Certificate " r"-FilePath '{}'".format(cached_source_path)) - cmd.append(r" -CertStoreLocation '{}'".format(store_path)) + cmd.append(rf" -CertStoreLocation '{store_path}'") _cmd_run(cmd="".join(cmd)) @@ -387,7 +387,7 @@ def export_cert( """ cmd = list() thumbprint = thumbprint.upper() - cert_path = r"Cert:\{}\{}\{}".format(context, store, thumbprint) + cert_path = rf"Cert:\{context}\{store}\{thumbprint}" cert_format = cert_format.lower() _validate_cert_path(name=cert_path) @@ -415,7 +415,7 @@ def export_cert( r"Export-Certificate " r"-Cert '{}' -FilePath '{}'".format(cert_path, name) ) - cmd.append(r" | Out-Null; Test-Path -Path '{}'".format(name)) + cmd.append(rf" | Out-Null; Test-Path -Path '{name}'") ret = ast.literal_eval(_cmd_run(cmd="".join(cmd))) @@ -458,17 +458,17 @@ def test_cert( """ cmd = list() thumbprint = thumbprint.upper() - cert_path = r"Cert:\{}\{}\{}".format(context, store, thumbprint) - cmd.append(r"Test-Certificate -Cert '{}'".format(cert_path)) + cert_path = rf"Cert:\{context}\{store}\{thumbprint}" + cmd.append(rf"Test-Certificate -Cert '{cert_path}'") _validate_cert_path(name=cert_path) if untrusted_root: cmd.append(" -AllowUntrustedRoot") if dns_name: - cmd.append(" -DnsName '{}'".format(dns_name)) + cmd.append(f" -DnsName '{dns_name}'") if eku: - cmd.append(" -EKU '{}'".format(eku)) + cmd.append(f" -EKU '{eku}'") cmd.append(" -ErrorAction SilentlyContinue") @@ -493,9 +493,9 @@ def remove_cert(thumbprint, context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE): salt '*' win_pki.remove_cert thumbprint='AAA000' """ thumbprint = thumbprint.upper() - store_path = r"Cert:\{}\{}".format(context, store) - cert_path = r"{}\{}".format(store_path, thumbprint) - cmd = r"Remove-Item -Path '{}'".format(cert_path) + store_path = rf"Cert:\{context}\{store}" + cert_path = rf"{store_path}\{thumbprint}" + cmd = rf"Remove-Item -Path '{cert_path}'" current_certs = get_certs(context=context, store=store) diff --git a/salt/modules/win_powercfg.py b/salt/modules/win_powercfg.py index 5a76e98b58b..16428b48ea7 100644 --- a/salt/modules/win_powercfg.py +++ b/salt/modules/win_powercfg.py @@ -47,9 +47,9 @@ def _get_powercfg_minute_values(scheme, guid, subguid, safe_name): scheme = _get_current_scheme() if __grains__["osrelease"] == "7": - cmd = "powercfg /q {} {}".format(scheme, guid) + cmd = f"powercfg /q {scheme} {guid}" else: - cmd = "powercfg /q {} {} {}".format(scheme, guid, subguid) + cmd = f"powercfg /q {scheme} {guid} {subguid}" out = __salt__["cmd.run"](cmd, python_shell=False) split = out.split("\r\n\r\n") diff --git a/salt/modules/win_psget.py b/salt/modules/win_psget.py index 66302b4f91e..af978969a98 100644 --- a/salt/modules/win_psget.py +++ b/salt/modules/win_psget.py @@ -82,7 +82,7 @@ def _pshell(cmd, cwd=None, depth=2): in Xml format and load that into python """ - cmd = '{} | ConvertTo-Xml -Depth {} -As "stream"'.format(cmd, depth) + cmd = f'{cmd} | ConvertTo-Xml -Depth {depth} -As "stream"' log.debug("DSC: %s", cmd) results = __salt__["cmd.run_all"]( @@ -94,9 +94,7 @@ def _pshell(cmd, cwd=None, depth=2): if "retcode" not in results or results["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError( - "Issue executing powershell {}".format(cmd), info=results - ) + raise CommandExecutionError(f"Issue executing powershell {cmd}", info=results) try: ret = _ps_xml_to_dict( @@ -224,8 +222,8 @@ def install( flags.append(("Repository", repository)) params = "" for flag, value in flags: - params += "-{} {} ".format(flag, value) - cmd = "Install-Module {} -Force".format(params) + params += f"-{flag} {value} " + cmd = f"Install-Module {params} -Force" _pshell(cmd) return name in list_modules() @@ -259,8 +257,8 @@ def update(name, maximum_version=None, required_version=None): params = "" for flag, value in flags: - params += "-{} {} ".format(flag, value) - cmd = "Update-Module {} -Force".format(params) + params += f"-{flag} {value} " + cmd = f"Update-Module {params} -Force" _pshell(cmd) return name in list_modules() @@ -279,7 +277,7 @@ def remove(name): salt 'win01' psget.remove PowerPlan """ # Putting quotes around the parameter protects against command injection - cmd = 'Uninstall-Module "{}"'.format(name) + cmd = f'Uninstall-Module "{name}"' no_ret = _pshell(cmd) return name not in list_modules() @@ -313,8 +311,8 @@ def register_repository(name, location, installation_policy=None): params = "" for flag, value in flags: - params += "-{} {} ".format(flag, value) - cmd = "Register-PSRepository {}".format(params) + params += f"-{flag} {value} " + cmd = f"Register-PSRepository {params}" no_ret = _pshell(cmd) return name not in list_modules() @@ -333,6 +331,6 @@ def get_repository(name): salt 'win01' psget.get_repository MyRepo """ # Putting quotes around the parameter protects against command injection - cmd = 'Get-PSRepository "{}"'.format(name) + cmd = f'Get-PSRepository "{name}"' no_ret = _pshell(cmd) return name not in list_modules() diff --git a/salt/modules/win_servermanager.py b/salt/modules/win_servermanager.py index ab714b30e37..15d6c5d64f5 100644 --- a/salt/modules/win_servermanager.py +++ b/salt/modules/win_servermanager.py @@ -7,7 +7,6 @@ available and installed roles/features. Can install and remove roles/features. :depends: PowerShell module ``ServerManager`` """ - import logging import shlex diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index f788f7559d9..38356e87c69 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -5,6 +5,7 @@ Windows Service module. Rewritten to use PyWin32 """ + import fnmatch import logging import re @@ -112,7 +113,7 @@ def _cmd_quote(cmd): cmd = cmd.strip('"').strip("'") # Ensure the path to the binary is wrapped in double quotes to account for # spaces in the path - cmd = '"{}"'.format(cmd) + cmd = f'"{cmd}"' return cmd @@ -339,9 +340,7 @@ def start(name, timeout=90): win32serviceutil.StartService(name) except pywintypes.error as exc: if exc.winerror != 1056: - raise CommandExecutionError( - "Failed To Start {}: {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed To Start {name}: {exc.strerror}") log.debug('Service "%s" is running', name) srv_status = _status_wait( @@ -380,9 +379,7 @@ def stop(name, timeout=90): win32serviceutil.StopService(name) except pywintypes.error as exc: if exc.winerror != 1062: - raise CommandExecutionError( - "Failed To Stop {}: {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed To Stop {name}: {exc.strerror}") log.debug('Service "%s" is not running', name) srv_status = _status_wait( @@ -668,7 +665,7 @@ def modify( win32service.SERVICE_CHANGE_CONFIG | win32service.SERVICE_QUERY_CONFIG, ) except pywintypes.error as exc: - raise CommandExecutionError("Failed To Open {}: {}".format(name, exc.strerror)) + raise CommandExecutionError(f"Failed To Open {name}: {exc.strerror}") config_info = win32service.QueryServiceConfig(handle_svc) @@ -679,7 +676,7 @@ def modify( # shlex.quote the path to the binary bin_path = _cmd_quote(bin_path) if exe_args is not None: - bin_path = "{} {}".format(bin_path, exe_args) + bin_path = f"{bin_path} {exe_args}" changes["BinaryPath"] = bin_path if service_type is not None: @@ -688,7 +685,7 @@ def modify( if run_interactive: service_type = service_type | win32service.SERVICE_INTERACTIVE_PROCESS else: - raise CommandExecutionError("Invalid Service Type: {}".format(service_type)) + raise CommandExecutionError(f"Invalid Service Type: {service_type}") else: if run_interactive is True: service_type = config_info[0] | win32service.SERVICE_INTERACTIVE_PROCESS @@ -709,7 +706,7 @@ def modify( if start_type.lower() in SERVICE_START_TYPE: start_type = SERVICE_START_TYPE[start_type.lower()] else: - raise CommandExecutionError("Invalid Start Type: {}".format(start_type)) + raise CommandExecutionError(f"Invalid Start Type: {start_type}") changes["StartType"] = SERVICE_START_TYPE[start_type] else: start_type = win32service.SERVICE_NO_CHANGE @@ -718,9 +715,7 @@ def modify( if error_control.lower() in SERVICE_ERROR_CONTROL: error_control = SERVICE_ERROR_CONTROL[error_control.lower()] else: - raise CommandExecutionError( - "Invalid Error Control: {}".format(error_control) - ) + raise CommandExecutionError(f"Invalid Error Control: {error_control}") changes["ErrorControl"] = SERVICE_ERROR_CONTROL[error_control] else: error_control = win32service.SERVICE_NO_CHANGE @@ -897,7 +892,7 @@ def create( account_name=".\\LocalSystem", account_password=None, run_interactive=False, - **kwargs + **kwargs, ): """ Create the named service. @@ -1003,29 +998,29 @@ def create( # Test if the service already exists if name in get_all(): - raise CommandExecutionError("Service Already Exists: {}".format(name)) + raise CommandExecutionError(f"Service Already Exists: {name}") # shlex.quote the path to the binary bin_path = _cmd_quote(bin_path) if exe_args is not None: - bin_path = "{} {}".format(bin_path, exe_args) + bin_path = f"{bin_path} {exe_args}" if service_type.lower() in SERVICE_TYPE: service_type = SERVICE_TYPE[service_type.lower()] if run_interactive: service_type = service_type | win32service.SERVICE_INTERACTIVE_PROCESS else: - raise CommandExecutionError("Invalid Service Type: {}".format(service_type)) + raise CommandExecutionError(f"Invalid Service Type: {service_type}") if start_type.lower() in SERVICE_START_TYPE: start_type = SERVICE_START_TYPE[start_type.lower()] else: - raise CommandExecutionError("Invalid Start Type: {}".format(start_type)) + raise CommandExecutionError(f"Invalid Start Type: {start_type}") if error_control.lower() in SERVICE_ERROR_CONTROL: error_control = SERVICE_ERROR_CONTROL[error_control.lower()] else: - raise CommandExecutionError("Invalid Error Control: {}".format(error_control)) + raise CommandExecutionError(f"Invalid Error Control: {error_control}") if start_delayed: if start_type != 2: @@ -1120,18 +1115,14 @@ def delete(name, timeout=90): except pywintypes.error as exc: win32service.CloseServiceHandle(handle_scm) if exc.winerror != 1060: - raise CommandExecutionError( - "Failed to open {}. {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed to open {name}. {exc.strerror}") log.debug('Service "%s" is not present', name) return True try: win32service.DeleteService(handle_svc) except pywintypes.error as exc: - raise CommandExecutionError( - "Failed to delete {}. {}".format(name, exc.strerror) - ) + raise CommandExecutionError(f"Failed to delete {name}. {exc.strerror}") finally: log.debug("Cleaning up") win32service.CloseServiceHandle(handle_scm) diff --git a/salt/modules/win_shortcut.py b/salt/modules/win_shortcut.py index c11cc1c64d1..90d1ae52f63 100644 --- a/salt/modules/win_shortcut.py +++ b/salt/modules/win_shortcut.py @@ -6,6 +6,7 @@ url shortcuts. .. versionadded:: 3005 """ + # https://docs.microsoft.com/en-us/troubleshoot/windows-client/admin-development/create-desktop-shortcut-with-wsh # https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/windows-scripting/f5y78918(v=vs.84) import logging @@ -74,11 +75,11 @@ def get(path): salt * shortcut.get path="C:\path\to\shortcut.lnk" """ if not os.path.exists(path): - raise CommandExecutionError("Shortcut not found: {}".format(path)) + raise CommandExecutionError(f"Shortcut not found: {path}") if not path.endswith((".lnk", ".url")): _, ext = os.path.splitext(path) - raise CommandExecutionError("Invalid file extension: {}".format(ext)) + raise CommandExecutionError(f"Invalid file extension: {ext}") # This will load the existing shortcut with salt.utils.winapi.Com(): @@ -101,7 +102,7 @@ def get(path): if target: target = salt.utils.path.expand(target) else: - msg = "Not a valid shortcut: {}".format(path) + msg = f"Not a valid shortcut: {path}" log.debug(msg) raise CommandExecutionError(msg) if shortcut.Arguments: @@ -299,11 +300,11 @@ def modify( salt * shortcut.modify "C:\path\to\shortcut.lnk" "C:\Windows\notepad.exe" """ if not os.path.exists(path): - raise CommandExecutionError("Shortcut not found: {}".format(path)) + raise CommandExecutionError(f"Shortcut not found: {path}") if not path.endswith((".lnk", ".url")): _, ext = os.path.splitext(path) - raise CommandExecutionError("Invalid file extension: {}".format(ext)) + raise CommandExecutionError(f"Invalid file extension: {ext}") return _set_info( path=path, @@ -435,14 +436,14 @@ def create( """ if not path.endswith((".lnk", ".url")): _, ext = os.path.splitext(path) - raise CommandExecutionError("Invalid file extension: {}".format(ext)) + raise CommandExecutionError(f"Invalid file extension: {ext}") if os.path.exists(path): if backup: log.debug("Backing up: %s", path) file, ext = os.path.splitext(path) ext = ext.strip(".") - backup_path = "{}-{}.{}".format(file, time.time_ns(), ext) + backup_path = f"{file}-{time.time_ns()}.{ext}" os.rename(path, backup_path) elif force: log.debug("Removing: %s", path) @@ -471,11 +472,11 @@ def create( __salt__["file.makedirs"](path=path, owner=user) except CommandExecutionError as exc: raise CommandExecutionError( - "Error creating parent directory: {}".format(exc.message) + f"Error creating parent directory: {exc.message}" ) else: raise CommandExecutionError( - "Parent directory not present: {}".format(os.path.dirname(path)) + f"Parent directory not present: {os.path.dirname(path)}" ) return _set_info( diff --git a/salt/modules/win_smtp_server.py b/salt/modules/win_smtp_server.py index ab0e602fe79..44531a569b9 100644 --- a/salt/modules/win_smtp_server.py +++ b/salt/modules/win_smtp_server.py @@ -109,7 +109,7 @@ def _normalize_server_settings(**settings): _LOG.debug("Fixing value: %s", settings[setting]) value_from_key = next(iter(settings[setting].keys())) - ret[setting] = "{{{0}}}".format(value_from_key) + ret[setting] = f"{{{value_from_key}}}" else: ret[setting] = settings[setting] return ret @@ -391,7 +391,7 @@ def get_connection_ip_list(as_wmi_format=False, server=_DEFAULT_SERVER): for unnormalized_address in addresses: ip_address, subnet = re.split(reg_separator, unnormalized_address) if as_wmi_format: - ret.append("{}, {}".format(ip_address, subnet)) + ret.append(f"{ip_address}, {subnet}") else: ret[ip_address] = subnet @@ -431,9 +431,7 @@ def set_connection_ip_list( # Convert addresses to the 'ip_address, subnet' format used by # IIsIPSecuritySetting. for address in addresses: - formatted_addresses.append( - "{}, {}".format(address.strip(), addresses[address].strip()) - ) + formatted_addresses.append(f"{address.strip()}, {addresses[address].strip()}") current_addresses = get_connection_ip_list(as_wmi_format=True, server=server) diff --git a/salt/modules/win_snmp.py b/salt/modules/win_snmp.py index 0fc7775ea6c..a2cff764477 100644 --- a/salt/modules/win_snmp.py +++ b/salt/modules/win_snmp.py @@ -11,11 +11,11 @@ from salt.exceptions import CommandExecutionError, SaltInvocationError _HKEY = "HKLM" _SNMP_KEY = r"SYSTEM\CurrentControlSet\Services\SNMP\Parameters" -_AGENT_KEY = r"{}\RFC1156Agent".format(_SNMP_KEY) -_COMMUNITIES_KEY = r"{}\ValidCommunities".format(_SNMP_KEY) +_AGENT_KEY = rf"{_SNMP_KEY}\RFC1156Agent" +_COMMUNITIES_KEY = rf"{_SNMP_KEY}\ValidCommunities" _SNMP_GPO_KEY = r"SOFTWARE\Policies\SNMP\Parameters" -_COMMUNITIES_GPO_KEY = r"{}\ValidCommunities".format(_SNMP_GPO_KEY) +_COMMUNITIES_GPO_KEY = rf"{_SNMP_GPO_KEY}\ValidCommunities" _PERMISSION_TYPES = { "None": 1, diff --git a/salt/modules/win_status.py b/salt/modules/win_status.py index fad2323a43b..ee789c4363b 100644 --- a/salt/modules/win_status.py +++ b/salt/modules/win_status.py @@ -7,6 +7,7 @@ or for problem solving if your minion is having problems. :depends: - wmi """ + import ctypes import datetime import logging diff --git a/salt/modules/win_task.py b/salt/modules/win_task.py index 8c9f2718dbd..2151b663ba3 100644 --- a/salt/modules/win_task.py +++ b/salt/modules/win_task.py @@ -227,7 +227,7 @@ def _get_date_value(date): :rtype: str """ try: - return "{}".format(date) + return f"{date}" except ValueError: return "Never" @@ -323,11 +323,11 @@ def _save_task_definition( try: failure_code = fc[exc[5]] except KeyError: - failure_code = "Unknown Failure: {}".format(error) + failure_code = f"Unknown Failure: {error}" log.debug("Failed to modify task: %s", failure_code) - return "Failed to modify task: {}".format(failure_code) + return f"Failed to modify task: {failure_code}" def list_tasks(location="\\"): @@ -363,7 +363,7 @@ def list_tasks(location="\\"): try: task_folder = task_service.GetFolder(location) except pywintypes.com_error: - msg = "Unable to load location: {}".format(location) + msg = f"Unable to load location: {location}" log.error(msg) raise CommandExecutionError(msg) @@ -551,7 +551,7 @@ def create_task( # Check for existing task if name in list_tasks(location) and not force: # Connect to an existing task definition - return "{} already exists".format(name) + return f"{name} already exists" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -566,7 +566,7 @@ def create_task( task_definition=task_definition, user_name=user_name, password=password, - **kwargs + **kwargs, ) # Add Action @@ -642,7 +642,7 @@ def create_task_from_xml( # Check for existing task if name in list_tasks(location): # Connect to an existing task definition - return "{} already exists".format(name) + return f"{name} already exists" if not xml_text and not xml_path: raise ArgumentValueError("Must specify either xml_text or xml_path") @@ -731,7 +731,7 @@ def create_task_from_xml( try: failure_code = fc[error_code] except KeyError: - failure_code = "Unknown Failure: {}".format(error_code) + failure_code = f"Unknown Failure: {error_code}" finally: log.debug("Failed to create task: %s", failure_code) raise CommandExecutionError(failure_code) @@ -767,7 +767,7 @@ def create_folder(name, location="\\"): # Check for existing folder if name in list_folders(location): # Connect to an existing task definition - return "{} already exists".format(name) + return f"{name} already exists" # Create the task service object with salt.utils.winapi.Com(): @@ -812,7 +812,7 @@ def edit_task( force_stop=None, delete_after=None, multiple_instances=None, - **kwargs + **kwargs, ): r""" Edit the parameters of a task. Triggers and Actions cannot be edited yet. @@ -1016,7 +1016,7 @@ def edit_task( else: # Not found and create_new not set, return not found - return "{} not found".format(name) + return f"{name} not found" # General Information if save_definition: @@ -1183,7 +1183,7 @@ def delete_task(name, location="\\"): """ # Check for existing task if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1224,7 +1224,7 @@ def delete_folder(name, location="\\"): """ # Check for existing folder if name not in list_folders(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1266,7 +1266,7 @@ def run(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1309,7 +1309,7 @@ def run_wait(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1370,7 +1370,7 @@ def stop(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1419,7 +1419,7 @@ def status(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1458,7 +1458,7 @@ def info(name, location="\\"): """ # Check for existing folder if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # connect to the task scheduler with salt.utils.winapi.Com(): @@ -1582,9 +1582,9 @@ def info(name, location="\\"): trigger["repeat_interval"] = _reverse_lookup( duration, triggerObj.Repetition.Interval ) - trigger[ - "repeat_stop_at_duration_end" - ] = triggerObj.Repetition.StopAtDurationEnd + trigger["repeat_stop_at_duration_end"] = ( + triggerObj.Repetition.StopAtDurationEnd + ) triggers.append(trigger) properties["settings"] = settings @@ -1714,7 +1714,7 @@ def add_action(name=None, location="\\", action_type="Execute", **kwargs): else: # Not found and create_new not set, return not found - return "{} not found".format(name) + return f"{name} not found" # Action Settings task_action = task_definition.Actions.Create(action_types[action_type]) @@ -1808,7 +1808,7 @@ def _clear_actions(name, location="\\"): # TODO: action. # Check for existing task if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # Create the task service object with salt.utils.winapi.Com(): @@ -1848,7 +1848,7 @@ def add_trigger( repeat_stop_at_duration_end=False, execution_time_limit=None, delay=None, - **kwargs + **kwargs, ): r""" Add a trigger to a Windows Scheduled task @@ -2303,7 +2303,7 @@ def add_trigger( else: # Not found and create_new not set, return not found - return "{} not found".format(name) + return f"{name} not found" # Create a New Trigger trigger = task_definition.Triggers.Create(trigger_types[trigger_type]) @@ -2481,7 +2481,7 @@ def clear_triggers(name, location="\\"): """ # Check for existing task if name not in list_tasks(location): - return "{} not found in {}".format(name, location) + return f"{name} not found in {location}" # Create the task service object with salt.utils.winapi.Com(): diff --git a/salt/modules/win_timezone.py b/salt/modules/win_timezone.py index d8c3c82bb23..fde63eb7ff8 100644 --- a/salt/modules/win_timezone.py +++ b/salt/modules/win_timezone.py @@ -1,6 +1,7 @@ """ Module for managing timezone on Windows systems. """ + import logging from datetime import datetime @@ -293,14 +294,14 @@ def set_zone(timezone): else: # Raise error because it's neither key nor value - raise CommandExecutionError("Invalid timezone passed: {}".format(timezone)) + raise CommandExecutionError(f"Invalid timezone passed: {timezone}") # Set the value cmd = ["tzutil", "/s", win_zone] res = __salt__["cmd.run_all"](cmd, python_shell=False) if res["retcode"]: raise CommandExecutionError( - "tzutil encountered an error setting timezone: {}".format(timezone), + f"tzutil encountered an error setting timezone: {timezone}", info=res, ) return zone_compare(timezone) @@ -335,7 +336,7 @@ def zone_compare(timezone): else: # Raise error because it's neither key nor value - raise CommandExecutionError("Invalid timezone passed: {}".format(timezone)) + raise CommandExecutionError(f"Invalid timezone passed: {timezone}") return get_zone() == mapper.get_unix(check_zone, "Unknown") diff --git a/salt/modules/win_useradd.py b/salt/modules/win_useradd.py index e557ffd8113..a9e9b2629b6 100644 --- a/salt/modules/win_useradd.py +++ b/salt/modules/win_useradd.py @@ -250,7 +250,7 @@ def update( try: dt_obj = salt.utils.dateutils.date_cast(expiration_date) except (ValueError, RuntimeError): - return "Invalid Date/Time Format: {}".format(expiration_date) + return f"Invalid Date/Time Format: {expiration_date}" user_info["acct_expires"] = time.mktime(dt_obj.timetuple()) if expired is not None: if expired: @@ -467,7 +467,7 @@ def addgroup(name, group): if group in user["groups"]: return True - cmd = 'net localgroup "{}" {} /add'.format(group, name) + cmd = f'net localgroup "{group}" {name} /add' ret = __salt__["cmd.run_all"](cmd, python_shell=True) return ret["retcode"] == 0 @@ -502,7 +502,7 @@ def removegroup(name, group): if group not in user["groups"]: return True - cmd = 'net localgroup "{}" {} /delete'.format(group, name) + cmd = f'net localgroup "{group}" {name} /delete' ret = __salt__["cmd.run_all"](cmd, python_shell=True) return ret["retcode"] == 0 @@ -633,14 +633,14 @@ def chgroups(name, groups, append=True): for group in ugrps: group = shlex.quote(group).lstrip("'").rstrip("'") if group not in groups: - cmd = 'net localgroup "{}" {} /delete'.format(group, name) + cmd = f'net localgroup "{group}" {name} /delete' __salt__["cmd.run_all"](cmd, python_shell=True) for group in groups: if group in ugrps: continue group = shlex.quote(group).lstrip("'").rstrip("'") - cmd = 'net localgroup "{}" {} /add'.format(group, name) + cmd = f'net localgroup "{group}" {name} /add' out = __salt__["cmd.run_all"](cmd, python_shell=True) if out["retcode"] != 0: log.error(out["stdout"]) @@ -774,7 +774,7 @@ def _get_userprofile_from_registry(user, sid): """ profile_dir = __utils__["reg.read_value"]( "HKEY_LOCAL_MACHINE", - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{}".format(sid), + f"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{sid}", "ProfileImagePath", )["vdata"] log.debug('user %s with sid=%s profile is located at "%s"', user, sid, profile_dir) @@ -901,12 +901,12 @@ def rename(name, new_name): # Load information for the current name current_info = info(name) if not current_info: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") # Look for an existing user with the new name new_info = info(new_name) if new_info: - raise CommandExecutionError("User '{}' already exists".format(new_name)) + raise CommandExecutionError(f"User '{new_name}' already exists") # Rename the user account # Connect to WMI @@ -917,7 +917,7 @@ def rename(name, new_name): try: user = c.Win32_UserAccount(Name=name)[0] except IndexError: - raise CommandExecutionError("User '{}' does not exist".format(name)) + raise CommandExecutionError(f"User '{name}' does not exist") # Rename the user result = user.Rename(new_name)[0] diff --git a/salt/modules/win_wua.py b/salt/modules/win_wua.py index 1393fc6efaf..c7799d5f6be 100644 --- a/salt/modules/win_wua.py +++ b/salt/modules/win_wua.py @@ -54,6 +54,7 @@ Group Policy using the ``lgpo`` module. :depends: salt.utils.win_update """ + import logging import salt.utils.platform @@ -994,7 +995,7 @@ def set_wu_settings( ) = error.args # pylint: enable=unpacking-non-sequence,unbalanced-tuple-unpacking # Consider checking for -2147024891 (0x80070005) Access Denied - ret["Comment"] = "Failed with failure code: {}".format(exc[5]) + ret["Comment"] = f"Failed with failure code: {exc[5]}" ret["Success"] = False else: # msupdate is false, so remove it from the services @@ -1018,7 +1019,7 @@ def set_wu_settings( # -2147024891 (0x80070005) Access Denied # -2145091564 (0x80248014) Service Not Found (shouldn't get # this with the check for _get_msupdate_status above - ret["Comment"] = "Failed with failure code: {}".format(exc[5]) + ret["Comment"] = f"Failed with failure code: {exc[5]}" ret["Success"] = False else: ret["msupdate"] = msupdate diff --git a/salt/modules/win_wusa.py b/salt/modules/win_wusa.py index 1a25fed3fa6..0cb1ef1b21d 100644 --- a/salt/modules/win_wusa.py +++ b/salt/modules/win_wusa.py @@ -8,7 +8,6 @@ Microsoft Update files management via wusa.exe .. versionadded:: 2018.3.4 """ - import logging import os diff --git a/salt/modules/winrepo.py b/salt/modules/winrepo.py index 12d4a0b4c5f..d7d39253eb1 100644 --- a/salt/modules/winrepo.py +++ b/salt/modules/winrepo.py @@ -6,6 +6,7 @@ Module to manage Windows software repo on a Standalone Minion For documentation on Salt's Windows Repo feature, see :ref:`here `. """ + import logging import os @@ -164,15 +165,15 @@ def show_sls(name, saltenv="base"): repo.extend(definition) # Check for the sls file by name - sls_file = "{}.sls".format(os.sep.join(repo)) + sls_file = f"{os.sep.join(repo)}.sls" if not os.path.exists(sls_file): # Maybe it's a directory with an init.sls - sls_file = "{}\\init.sls".format(os.sep.join(repo)) + sls_file = f"{os.sep.join(repo)}\\init.sls" if not os.path.exists(sls_file): # It's neither, return - return "Software definition {} not found".format(name) + return f"Software definition {name} not found" # Load the renderer renderers = salt.loader.render(__opts__, __salt__) @@ -192,7 +193,7 @@ def show_sls(name, saltenv="base"): except SaltRenderError as exc: log.debug("Failed to compile %s.", sls_file) log.debug("Error: %s.", exc) - config["Message"] = "Failed to compile {}".format(sls_file) - config["Error"] = "{}".format(exc) + config["Message"] = f"Failed to compile {sls_file}" + config["Error"] = f"{exc}" return config diff --git a/salt/modules/wordpress.py b/salt/modules/wordpress.py index 792d4f25536..7ce4c6b3cca 100644 --- a/salt/modules/wordpress.py +++ b/salt/modules/wordpress.py @@ -41,7 +41,7 @@ def list_plugins(path, user): salt '*' wordpress.list_plugins /var/www/html apache """ ret = [] - resp = __salt__["cmd.shell"]("wp --path={} plugin list".format(path), runas=user) + resp = __salt__["cmd.shell"](f"wp --path={path} plugin list", runas=user) for line in resp.split("\n")[1:]: ret.append(line.split("\t")) return [plugin.__dict__ for plugin in map(_get_plugins, ret)] @@ -68,7 +68,7 @@ def show_plugin(name, path, user): """ ret = {"name": name} resp = __salt__["cmd.shell"]( - "wp --path={} plugin status {}".format(path, name), runas=user + f"wp --path={path} plugin status {name}", runas=user ).split("\n") for line in resp: if "Status" in line: @@ -101,9 +101,7 @@ def activate(name, path, user): if check["status"] == "active": # already active return None - resp = __salt__["cmd.shell"]( - "wp --path={} plugin activate {}".format(path, name), runas=user - ) + resp = __salt__["cmd.shell"](f"wp --path={path} plugin activate {name}", runas=user) if "Success" in resp: return True elif show_plugin(name, path, user)["status"] == "active": @@ -135,7 +133,7 @@ def deactivate(name, path, user): # already inactive return None resp = __salt__["cmd.shell"]( - "wp --path={} plugin deactivate {}".format(path, name), runas=user + f"wp --path={path} plugin deactivate {name}", runas=user ) if "Success" in resp: return True @@ -160,9 +158,7 @@ def is_installed(path, user=None): salt '*' wordpress.is_installed /var/www/html apache """ - retcode = __salt__["cmd.retcode"]( - "wp --path={} core is-installed".format(path), runas=user - ) + retcode = __salt__["cmd.retcode"](f"wp --path={path} core is-installed", runas=user) if retcode == 0: return True return False diff --git a/salt/modules/x509_v2.py b/salt/modules/x509_v2.py index a8069518c82..1e20c088d59 100644 --- a/salt/modules/x509_v2.py +++ b/salt/modules/x509_v2.py @@ -165,6 +165,7 @@ Note that when a ``ca_server`` is involved, both peers must use the updated modu .. _x509-setup: """ + import base64 import copy import datetime @@ -766,9 +767,11 @@ def encode_certificate( else: cipher = serialization.BestAvailableEncryption(pkcs12_passphrase) crt_bytes = serialization.pkcs12.serialize_key_and_certificates( - name=salt.utils.stringutils.to_bytes(pkcs12_friendlyname) - if pkcs12_friendlyname - else None, + name=( + salt.utils.stringutils.to_bytes(pkcs12_friendlyname) + if pkcs12_friendlyname + else None + ), key=private_key, cert=cert, cas=append_certs, diff --git a/salt/modules/xapi_virt.py b/salt/modules/xapi_virt.py index 489a5b2ed4a..89772a302cd 100644 --- a/salt/modules/xapi_virt.py +++ b/salt/modules/xapi_virt.py @@ -50,7 +50,7 @@ def _check_xenapi(): if os.path.isfile(debian_xen_version): # __salt__ is not available in __virtual__ xenversion = salt.modules.cmdmod._run_quiet(debian_xen_version) - xapipath = "/usr/lib/xen-{}/lib/python".format(xenversion) + xapipath = f"/usr/lib/xen-{xenversion}/lib/python" if os.path.isdir(xapipath): sys.path.append(xapipath) @@ -156,7 +156,7 @@ def _get_metrics_record(xapi, rectype, record): Internal, returns metrics record for a rectype """ metrics_id = record["metrics"] - return getattr(xapi, "{}_metrics".format(rectype)).get_record(metrics_id) + return getattr(xapi, f"{rectype}_metrics").get_record(metrics_id) def _get_val(record, keys): @@ -507,10 +507,10 @@ def vcpu_pin(vm_, vcpu, cpus): if cpus == "all": cpumap = cpu_make_map("0-63") else: - cpumap = cpu_make_map("{}".format(cpus)) + cpumap = cpu_make_map(f"{cpus}") try: - xapi.VM.add_to_VCPUs_params_live(vm_uuid, "cpumap{}".format(vcpu), cpumap) + xapi.VM.add_to_VCPUs_params_live(vm_uuid, f"cpumap{vcpu}", cpumap) return True # VM.add_to_VCPUs_params_live() implementation in xend 4.1+ has # a bug which makes the client call fail. @@ -518,7 +518,7 @@ def vcpu_pin(vm_, vcpu, cpus): # for that particular one, fallback to xm / xl instead. except Exception: # pylint: disable=broad-except return __salt__["cmd.run"]( - "{} vcpu-pin {} {} {}".format(_get_xtool(), vm_, vcpu, cpus), + f"{_get_xtool()} vcpu-pin {vm_} {vcpu} {cpus}", python_shell=False, ) @@ -641,9 +641,7 @@ def start(config_): # This function does NOT use the XenAPI. Instead, it use good old xm / xl. # On Xen Source, creating a virtual machine using XenAPI is really painful. # XCP / XS make it really easy using xapi.Async.VM.start instead. Anyone? - return __salt__["cmd.run"]( - "{} create {}".format(_get_xtool(), config_), python_shell=False - ) + return __salt__["cmd.run"](f"{_get_xtool()} create {config_}", python_shell=False) def reboot(vm_): @@ -816,7 +814,7 @@ def vm_cputime(vm_=None): cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus return { "cputime": int(cputime), - "cputime_percent": int("{:.0f}".format(cputime_percent)), + "cputime_percent": int(f"{cputime_percent:.0f}"), } info = {} diff --git a/salt/modules/xbpspkg.py b/salt/modules/xbpspkg.py index afcf54fb2f2..65376c7dea1 100644 --- a/salt/modules/xbpspkg.py +++ b/salt/modules/xbpspkg.py @@ -401,7 +401,7 @@ def install(name=None, refresh=False, fromrepo=None, pkgs=None, sources=None, ** if refresh: cmd.append("-S") # update repo db if fromrepo: - cmd.append("--repository={}".format(fromrepo)) + cmd.append(f"--repository={fromrepo}") cmd.append("-y") # assume yes when asked cmd.extend(pkg_params) @@ -578,9 +578,7 @@ def add_repo(repo, conffile="/usr/share/xbps.d/15-saltstack.conf"): if not _locate_repo_files(repo): try: with salt.utils.files.fopen(conffile, "a+") as conf_file: - conf_file.write( - salt.utils.stringutils.to_str("repository={}\n".format(repo)) - ) + conf_file.write(salt.utils.stringutils.to_str(f"repository={repo}\n")) except OSError: return False diff --git a/salt/modules/xfs.py b/salt/modules/xfs.py index 04b104f9967..16c6e85a572 100644 --- a/salt/modules/xfs.py +++ b/salt/modules/xfs.py @@ -111,7 +111,7 @@ def info(device): salt '*' xfs.info /dev/sda1 """ - out = __salt__["cmd.run_all"]("xfs_info {}".format(device)) + out = __salt__["cmd.run_all"](f"xfs_info {device}") if out.get("stderr"): raise CommandExecutionError(out["stderr"].replace("xfs_info:", "").strip()) return _parse_xfs_info(out["stdout"]) @@ -186,16 +186,16 @@ def dump(device, destination, level=0, label=None, noerase=None): label and label or time.strftime( - 'XFS dump for "{}" of %Y.%m.%d, %H:%M'.format(device), time.localtime() + f'XFS dump for "{device}" of %Y.%m.%d, %H:%M', time.localtime() ).replace("'", '"') ) cmd = ["xfsdump"] cmd.append("-F") # Force if not noerase: cmd.append("-E") # pre-erase - cmd.append("-L '{}'".format(label)) # Label - cmd.append("-l {}".format(level)) # Dump level - cmd.append("-f {}".format(destination)) # Media destination + cmd.append(f"-L '{label}'") # Label + cmd.append(f"-l {level}") # Dump level + cmd.append(f"-f {destination}") # Media destination cmd.append(device) # Device cmd = " ".join(cmd) @@ -211,10 +211,10 @@ def _xr_to_keyset(line): """ tkns = [elm for elm in line.strip().split(":", 1) if elm] if len(tkns) == 1: - return "'{}': ".format(tkns[0]) + return f"'{tkns[0]}': " else: key, val = tkns - return "'{}': '{}',".format(key.strip(), val.strip()) + return f"'{key.strip()}': '{val.strip()}'," def _xfs_inventory_output(out): @@ -305,14 +305,14 @@ def prune_dump(sessionid): salt '*' xfs.prune_dump b74a3586-e52e-4a4a-8775-c3334fa8ea2c """ - out = __salt__["cmd.run_all"]("xfsinvutil -s {} -F".format(sessionid)) + out = __salt__["cmd.run_all"](f"xfsinvutil -s {sessionid} -F") _verify_run(out) data = _xfs_prune_output(out["stdout"], sessionid) if data: return data - raise CommandExecutionError('Session UUID "{}" was not found.'.format(sessionid)) + raise CommandExecutionError(f'Session UUID "{sessionid}" was not found.') def _blkid_output(out): @@ -387,9 +387,9 @@ def estimate(path): salt '*' xfs.estimate /path/to/dir/* """ if not os.path.exists(path): - raise CommandExecutionError('Path "{}" was not found.'.format(path)) + raise CommandExecutionError(f'Path "{path}" was not found.') - out = __salt__["cmd.run_all"]("xfs_estimate -v {}".format(path)) + out = __salt__["cmd.run_all"](f"xfs_estimate -v {path}") _verify_run(out) return _xfs_estimate_output(out["stdout"]) @@ -447,7 +447,7 @@ def mkfs( cmd = ["mkfs.xfs"] if label: cmd.append("-L") - cmd.append("'{}'".format(label)) + cmd.append(f"'{label}'") if ssize: cmd.append("-s") @@ -468,7 +468,7 @@ def mkfs( cmd.append(opts) except Exception: # pylint: disable=broad-except raise CommandExecutionError( - 'Wrong parameters "{}" for option "{}"'.format(opts, switch) + f'Wrong parameters "{opts}" for option "{switch}"' ) if not noforce: @@ -496,13 +496,13 @@ def modify(device, label=None, lazy_counting=None, uuid=None): """ if not label and lazy_counting is None and uuid is None: raise CommandExecutionError( - 'Nothing specified for modification for "{}" device'.format(device) + f'Nothing specified for modification for "{device}" device' ) cmd = ["xfs_admin"] if label: cmd.append("-L") - cmd.append("'{}'".format(label)) + cmd.append(f"'{label}'") if lazy_counting is False: cmd.append("-c") @@ -522,7 +522,7 @@ def modify(device, label=None, lazy_counting=None, uuid=None): cmd = " ".join(cmd) _verify_run(__salt__["cmd.run_all"](cmd), cmd=cmd) - out = __salt__["cmd.run_all"]("blkid -o export {}".format(device)) + out = __salt__["cmd.run_all"](f"blkid -o export {device}") _verify_run(out) return _blkid_output(out["stdout"]) @@ -563,9 +563,9 @@ def defragment(device): raise CommandExecutionError("Root is not a device.") if not _get_mounts().get(device): - raise CommandExecutionError('Device "{}" is not mounted'.format(device)) + raise CommandExecutionError(f'Device "{device}" is not mounted') - out = __salt__["cmd.run_all"]("xfs_fsr {}".format(device)) + out = __salt__["cmd.run_all"](f"xfs_fsr {device}") _verify_run(out) return {"log": out["stdout"]} diff --git a/salt/modules/xmpp.py b/salt/modules/xmpp.py index 5e058ff1324..944ef5c92af 100644 --- a/salt/modules/xmpp.py +++ b/salt/modules/xmpp.py @@ -34,7 +34,6 @@ Module for Sending Messages via XMPP (a.k.a. Jabber) """ - import logging HAS_LIBS = False diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 9f3d9d27e6d..0ca3e9dc809 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -18,6 +18,7 @@ Support for YUM/DNF .. versionadded:: 3007.0 Support for ``dnf5``` on Fedora 39 """ + import configparser import contextlib import datetime diff --git a/salt/modules/zcbuildout.py b/salt/modules/zcbuildout.py index c36f254cd84..c5c32dac2ef 100644 --- a/salt/modules/zcbuildout.py +++ b/salt/modules/zcbuildout.py @@ -22,7 +22,6 @@ You have those following methods: * buildout """ - import copy import logging import os @@ -190,9 +189,9 @@ def _encode_status(status): logs = status["logs_by_level"].get(logger, [])[:] if logs: for i, log in enumerate(logs): - status["logs_by_level"][logger][ - i - ] = salt.utils.stringutils.to_unicode(log) + status["logs_by_level"][logger][i] = ( + salt.utils.stringutils.to_unicode(log) + ) return status diff --git a/salt/modules/zenoss.py b/salt/modules/zenoss.py index 5f2408c486b..50855f2bebb 100644 --- a/salt/modules/zenoss.py +++ b/salt/modules/zenoss.py @@ -203,7 +203,7 @@ def set_prod_state(prod_state, device=None): device_object = find_device(device) if not device_object: - return "Unable to find a device in Zenoss for {}".format(device) + return f"Unable to find a device in Zenoss for {device}" log.info("Setting prodState to %d on %s device", prod_state, device) data = dict( diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py index d5e9203dc26..0b15ca46ff1 100644 --- a/salt/modules/zypperpkg.py +++ b/salt/modules/zypperpkg.py @@ -11,7 +11,6 @@ Package support for openSUSE via the zypper package manager """ - import configparser import datetime import errno @@ -2353,10 +2352,10 @@ def unhold(name=None, pkgs=None, root=None, **kwargs): lock_ver = lock_ver.lstrip("= ") if version and lock_ver != version: ret[target]["result"] = False - ret[target][ - "comment" - ] = "Unable to unhold package {} as it is held with the other version.".format( - target + ret[target]["comment"] = ( + "Unable to unhold package {} as it is held with the other version.".format( + target + ) ) else: removed.append(target if not lock_ver else f"{target}={lock_ver}") @@ -2943,10 +2942,10 @@ def download(*packages, **kwargs): if pkg_ret: failed = [pkg for pkg in packages if pkg not in pkg_ret] if failed: - pkg_ret[ - "_error" - ] = "The following package(s) failed to download: {}".format( - ", ".join(failed) + pkg_ret["_error"] = ( + "The following package(s) failed to download: {}".format( + ", ".join(failed) + ) ) return pkg_ret diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py index a89c1a19af0..583a6f158d5 100644 --- a/salt/netapi/__init__.py +++ b/salt/netapi/__init__.py @@ -2,7 +2,6 @@ Make api awesomeness """ - import copy import inspect import logging @@ -54,7 +53,7 @@ def sum_permissions(token, eauth): eauth_groups = {i.rstrip("%") for i in eauth.keys() if i.endswith("%")} for group in user_groups & eauth_groups: - perms.extend(eauth["{}%".format(group)]) + perms.extend(eauth[f"{group}%"]) return perms diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index d9dd7e9bcea..56a4859d431 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -898,9 +898,11 @@ def hypermedia_handler(*args, **kwargs): ret = { "status": cherrypy.response.status, - "return": f"{traceback.format_exc()}" - if cherrypy.config["debug"] - else "An unexpected error occurred", + "return": ( + f"{traceback.format_exc()}" + if cherrypy.config["debug"] + else "An unexpected error occurred" + ), } # Raises 406 if requested content-type is not supported @@ -1740,9 +1742,9 @@ class Keys(LowDataAdapter): tarball.close() headers = cherrypy.response.headers - headers[ - "Content-Disposition" - ] = 'attachment; filename="saltkeys-{}.tar"'.format(lowstate[0]["id_"]) + headers["Content-Disposition"] = ( + 'attachment; filename="saltkeys-{}.tar"'.format(lowstate[0]["id_"]) + ) headers["Content-Type"] = "application/x-tar" headers["Content-Length"] = len(fileobj.getvalue()) headers["Cache-Control"] = "no-cache" diff --git a/salt/netapi/rest_wsgi.py b/salt/netapi/rest_wsgi.py index 4afd3d55ec3..50dfabe23c1 100644 --- a/salt/netapi/rest_wsgi.py +++ b/salt/netapi/rest_wsgi.py @@ -161,7 +161,7 @@ class HTTPError(Exception): def __init__(self, code, message): self.code = code - Exception.__init__(self, "{}: {}".format(code, message)) + Exception.__init__(self, f"{code}: {message}") def mkdir_p(path): diff --git a/salt/output/__init__.py b/salt/output/__init__.py index 32d0560772d..c90932fa8ea 100644 --- a/salt/output/__init__.py +++ b/salt/output/__init__.py @@ -3,7 +3,6 @@ Used to manage the outputter system. This package is the modular system used for managing outputters. """ - import errno import io import logging @@ -54,7 +53,7 @@ def get_progress(opts, out, progress): Get the progress bar from the given outputter """ return salt.loader.raw_mod(opts, out, "rawmodule", mod="output")[ - "{}.progress_iter".format(out) + f"{out}.progress_iter" ](progress) diff --git a/salt/output/highstate.py b/salt/output/highstate.py index 6c852554fc4..dc00885753f 100644 --- a/salt/output/highstate.py +++ b/salt/output/highstate.py @@ -123,7 +123,6 @@ Example output with no special settings in configuration files: Total: 0 """ - import collections import logging import pprint @@ -572,10 +571,10 @@ def _format_host(host, data, indent_level=1): if "data" in ret: if isinstance(ret["data"], list): for item in ret["data"]: - comment = "{} {}".format(comment, item) + comment = f"{comment} {item}" elif isinstance(ret["data"], dict): for key, value in ret["data"].items(): - comment = "{}\n\t\t{}: {}".format(comment, key, value) + comment = f"{comment}\n\t\t{key}: {value}" else: comment = "{} {}".format(comment, ret["data"]) for detail in ["start_time", "duration"]: @@ -635,13 +634,13 @@ def _format_host(host, data, indent_level=1): changestats.append( colorfmt.format( colors["LIGHT_YELLOW"], - "unchanged={}".format(rcounts.get(None, 0)), + f"unchanged={rcounts.get(None, 0)}", colors, ) ) if nchanges > 0: changestats.append( - colorfmt.format(colors["GREEN"], "changed={}".format(nchanges), colors) + colorfmt.format(colors["GREEN"], f"changed={nchanges}", colors) ) if changestats: changestats = " ({})".format(", ".join(changestats)) @@ -733,7 +732,7 @@ def _format_host(host, data, indent_level=1): sum_duration /= 1000 duration_unit = "s" total_duration = "Total run time: {} {}".format( - "{:.3f}".format(sum_duration).rjust(line_max_len - 5), duration_unit + f"{sum_duration:.3f}".rjust(line_max_len - 5), duration_unit ) hstrs.append(colorfmt.format(colors["CYAN"], total_duration, colors)) @@ -763,7 +762,7 @@ def _format_changes(changes, orchestration=False): return True, _nested_changes(changes) if not isinstance(changes, dict): - return True, "Invalid Changes data: {}".format(changes) + return True, f"Invalid Changes data: {changes}" ret = changes.get("ret") if ret is not None and changes.get("out") == "highstate": diff --git a/salt/output/key.py b/salt/output/key.py index 13ee6f0f5fe..f89f95c7f96 100644 --- a/salt/output/key.py +++ b/salt/output/key.py @@ -84,7 +84,7 @@ def output(data, **kwargs): # pylint: disable=unused-argument ret = "" for status in sorted(data): - ret += "{}\n".format(trans[status]) + ret += f"{trans[status]}\n" for key in sorted(data[status]): key = salt.utils.data.decode(key) skey = salt.output.strip_esc_sequence(key) if strip_colors else key diff --git a/salt/output/overstatestage.py b/salt/output/overstatestage.py index 3f80e0871f6..a8facfcb308 100644 --- a/salt/output/overstatestage.py +++ b/salt/output/overstatestage.py @@ -6,7 +6,6 @@ This outputter is used to display :ref:`Orchestrate Runner ` stages, and should not be called directly. """ - import salt.utils.color # [{'group2': {'match': ['fedora17-2', 'fedora17-3'], diff --git a/salt/output/pony.py b/salt/output/pony.py index 908b8b29392..e8cc866cff2 100644 --- a/salt/output/pony.py +++ b/salt/output/pony.py @@ -46,7 +46,6 @@ CLI Example: salt '*' foo.bar --out=pony """ - import subprocess import salt.utils.data diff --git a/salt/output/profile.py b/salt/output/profile.py index d182da565ff..8f54c7017f4 100644 --- a/salt/output/profile.py +++ b/salt/output/profile.py @@ -56,11 +56,11 @@ def _find_durations(data, name_max=60): if len(name) > name_max: name = name[0 : name_max - 3] + "..." - l = len("{:0.4f}".format(dur)) + l = len(f"{dur:0.4f}") if l > ml: ml = l - ret.append([dur, name, "{}.{}".format(mod, fun)]) + ret.append([dur, name, f"{mod}.{fun}"]) for row in ret: row[0] = "{0:{w}.4f}".format(row[0], w=ml) diff --git a/salt/output/progress.py b/salt/output/progress.py index 1d00a379cc4..302ce1f1467 100644 --- a/salt/output/progress.py +++ b/salt/output/progress.py @@ -2,7 +2,6 @@ Display return data as a progress bar """ - try: import progressbar diff --git a/salt/output/raw.py b/salt/output/raw.py index d2e68041180..a3005948e42 100644 --- a/salt/output/raw.py +++ b/salt/output/raw.py @@ -24,7 +24,6 @@ Example output: {'myminion': {'foo': {'list': ['Hello', 'World'], 'bar': 'baz', 'dictionary': {'abc': 123, 'def': 456}}}} """ - import salt.utils.stringutils diff --git a/salt/output/table_out.py b/salt/output/table_out.py index 730e0cb2df8..6b17c901b64 100644 --- a/salt/output/table_out.py +++ b/salt/output/table_out.py @@ -42,7 +42,6 @@ CLI Example: salt '*' foo.bar --out=table """ - import operator from functools import reduce # pylint: disable=redefined-builtin @@ -117,9 +116,9 @@ class TableDisplay: ) def wrap_onspace(self, text): - """ - When the text inside the column is longer then the width, will split by space and continue on the next line.""" + When the text inside the column is longer then the width, will split by space and continue on the next line. + """ def _truncate(line, word): return "{line}{part}{word}".format( @@ -136,7 +135,6 @@ class TableDisplay: return reduce(_truncate, text.split(" ")) def prepare_rows(self, rows, indent, has_header): - """Prepare rows content to be displayed.""" out = [] @@ -198,7 +196,6 @@ class TableDisplay: return out def display_rows(self, rows, labels, indent): - """Prepares row content and displays.""" out = [] @@ -245,7 +242,6 @@ class TableDisplay: return self.prepare_rows(labels_and_rows, indent + 4, has_header) def display(self, ret, indent, out, rows_key=None, labels_key=None): - """Display table(s).""" rows = [] @@ -350,7 +346,7 @@ def output(ret, **kwargs): ) for argk in argks: - argv = kwargs.get(argk) or __opts__.get("out.table.{key}".format(key=argk)) + argv = kwargs.get(argk) or __opts__.get(f"out.table.{argk}") if argv is not None: class_kvargs[argk] = argv diff --git a/salt/output/txt.py b/salt/output/txt.py index 71d694a2333..f5e652cdd14 100644 --- a/salt/output/txt.py +++ b/salt/output/txt.py @@ -26,14 +26,14 @@ def output(data, **kwargs): # pylint: disable=unused-argument # Don't blow up on non-strings try: for line in value.splitlines(): - ret += "{}: {}\n".format(key, line) + ret += f"{key}: {line}\n" except AttributeError: - ret += "{}: {}\n".format(key, value) + ret += f"{key}: {value}\n" else: try: ret += data + "\n" except TypeError: # For non-dictionary, non-string data, just use print - ret += "{}\n".format(pprint.pformat(data)) + ret += f"{pprint.pformat(data)}\n" return ret diff --git a/salt/output/virt_query.py b/salt/output/virt_query.py index d20e6357e60..935b9d213d7 100644 --- a/salt/output/virt_query.py +++ b/salt/output/virt_query.py @@ -13,9 +13,9 @@ def output(data, **kwargs): # pylint: disable=unused-argument """ out = "" for id_ in data["data"]: - out += "{}\n".format(id_) + out += f"{id_}\n" for vm_ in data["data"][id_]["vm_info"]: - out += " {}\n".format(vm_) + out += f" {vm_}\n" vm_data = data[id_]["vm_info"][vm_] if "cpu" in vm_data: out += " CPU: {}\n".format(vm_data["cpu"]) @@ -30,13 +30,13 @@ def output(data, **kwargs): # pylint: disable=unused-argument ) if "disks" in vm_data: for disk, d_data in vm_data["disks"].items(): - out += " Disk - {}:\n".format(disk) + out += f" Disk - {disk}:\n" out += " Size: {}\n".format(d_data["disk size"]) out += " File: {}\n".format(d_data["file"]) out += " File Format: {}\n".format(d_data["file format"]) if "nics" in vm_data: for mac in vm_data["nics"]: - out += " Nic - {}:\n".format(mac) + out += f" Nic - {mac}:\n" out += " Source: {}\n".format( vm_data["nics"][mac]["source"][ next(iter(vm_data["nics"][mac]["source"].keys())) diff --git a/salt/pillar/cmd_yamlex.py b/salt/pillar/cmd_yamlex.py index c014370f1d0..bf6d40a65fa 100644 --- a/salt/pillar/cmd_yamlex.py +++ b/salt/pillar/cmd_yamlex.py @@ -4,7 +4,6 @@ Execute a command and read the output as YAMLEX. The YAMLEX data is then directly overlaid onto the minion's Pillar data """ - import logging from salt.serializers.yamlex import deserialize diff --git a/salt/pillar/cobbler.py b/salt/pillar/cobbler.py index 5103d91f419..74e87d0a91f 100644 --- a/salt/pillar/cobbler.py +++ b/salt/pillar/cobbler.py @@ -25,7 +25,7 @@ Module Documentation """ import logging -import xmlrpc.client +import xmlrpc.client # nosec __opts__ = { "cobbler.url": "http://localhost/cobbler_api", @@ -34,7 +34,6 @@ __opts__ = { } -# Set up logging log = logging.getLogger(__name__) diff --git a/salt/pillar/consul_pillar.py b/salt/pillar/consul_pillar.py index 2b28b297353..3e4ff329329 100644 --- a/salt/pillar/consul_pillar.py +++ b/salt/pillar/consul_pillar.py @@ -315,7 +315,6 @@ def pillar_format(ret, keys, value, expand_keys): def get_conn(opts, profile): - """ Return a client object for accessing consul """ diff --git a/salt/pillar/django_orm.py b/salt/pillar/django_orm.py index 29a5eaaa413..641e6098514 100644 --- a/salt/pillar/django_orm.py +++ b/salt/pillar/django_orm.py @@ -125,7 +125,7 @@ def ext_pillar( env=None, env_file=None, *args, # pylint: disable=W0613 - **kwargs + **kwargs, ): # pylint: disable=W0613 """ Connect to a Django database through the ORM and retrieve model fields @@ -179,7 +179,7 @@ def ext_pillar( (key, _, value) = salt.utils.stringutils.to_str(line).partition("=") base_env[key] = value - command = ["bash", "-c", "source {} && env".format(env_file)] + command = ["bash", "-c", f"source {env_file} && env"] proc = subprocess.Popen(command, stdout=subprocess.PIPE) for line in proc.stdout: @@ -229,7 +229,7 @@ def ext_pillar( # (since we're using it as the key in a dictionary) if name_field not in model: raise salt.exceptions.SaltException( - "Name '{}' not found in returned fields.".format(name_field) + f"Name '{name_field}' not found in returned fields." ) if model[name_field] in pillar_for_model: diff --git a/salt/pillar/ec2_pillar.py b/salt/pillar/ec2_pillar.py index e197940908b..7aa6cb008dd 100644 --- a/salt/pillar/ec2_pillar.py +++ b/salt/pillar/ec2_pillar.py @@ -53,7 +53,6 @@ returns a list of key/value pairs for all of the EC2 tags assigned to the instance. """ - import logging import re @@ -185,9 +184,9 @@ def ext_pillar( find_id = minion_id elif tag_match_key: if tag_match_value == "uqdn": - find_filter = {"tag:{}".format(tag_match_key): minion_id.split(".", 1)[0]} + find_filter = {f"tag:{tag_match_key}": minion_id.split(".", 1)[0]} else: - find_filter = {"tag:{}".format(tag_match_key): minion_id} + find_filter = {f"tag:{tag_match_key}": minion_id} if grain_instance_id: # we have an untrusted grain_instance_id, use it to narrow the search # even more. Combination will be unique even if uqdn is set. diff --git a/salt/pillar/extra_minion_data_in_pillar.py b/salt/pillar/extra_minion_data_in_pillar.py index 170cdb6fa08..457c79462b0 100644 --- a/salt/pillar/extra_minion_data_in_pillar.py +++ b/salt/pillar/extra_minion_data_in_pillar.py @@ -27,6 +27,7 @@ Complete example in etc/salt/master include: """ + import logging # Set up logging diff --git a/salt/pillar/gpg.py b/salt/pillar/gpg.py index 28497a51f2c..8652a18b2a5 100644 --- a/salt/pillar/gpg.py +++ b/salt/pillar/gpg.py @@ -15,7 +15,6 @@ Set ``gpg_keydir`` in your config to adjust the homedir the renderer uses. """ - import salt.loader diff --git a/salt/pillar/hiera.py b/salt/pillar/hiera.py index 19e9c78c034..c799d4f195f 100644 --- a/salt/pillar/hiera.py +++ b/salt/pillar/hiera.py @@ -2,7 +2,6 @@ Use hiera data as a Pillar source """ - import logging import salt.utils.path @@ -25,10 +24,10 @@ def ext_pillar( """ Execute hiera and return the data """ - cmd = "hiera -c {}".format(conf) + cmd = f"hiera -c {conf}" for key, val in __grains__.items(): if isinstance(val, str): - cmd += " {}='{}'".format(key, val) + cmd += f" {key}='{val}'" try: data = salt.utils.yaml.safe_load(__salt__["cmd.run"](cmd)) except Exception: # pylint: disable=broad-except diff --git a/salt/pillar/http_json.py b/salt/pillar/http_json.py index f79f8655020..b07a2573772 100644 --- a/salt/pillar/http_json.py +++ b/salt/pillar/http_json.py @@ -48,7 +48,6 @@ Module Documentation ==================== """ - import logging import re import urllib.parse @@ -102,7 +101,7 @@ def ext_pillar( return {} grain_value = urllib.parse.quote(str(grain_value)) - url = re.sub("<{}>".format(grain_name), grain_value, url) + url = re.sub(f"<{grain_name}>", grain_value, url) log.debug("Getting url: %s", url) data = __salt__["http.query"]( diff --git a/salt/pillar/http_yaml.py b/salt/pillar/http_yaml.py index 434d5b8a892..58df6248ae0 100644 --- a/salt/pillar/http_yaml.py +++ b/salt/pillar/http_yaml.py @@ -43,6 +43,7 @@ in <> brackets) in the url in order to populate pillar data based on the grain v Module Documentation ==================== """ + import logging import re import urllib.parse @@ -94,7 +95,7 @@ def ext_pillar( return {} grain_value = urllib.parse.quote(str(grain_value)) - url = re.sub("<{}>".format(grain_name), grain_value, url) + url = re.sub(f"<{grain_name}>", grain_value, url) log.debug("Getting url: %s", url) data = __salt__["http.query"]( diff --git a/salt/pillar/libvirt.py b/salt/pillar/libvirt.py index 072293df251..cbcba870e4c 100644 --- a/salt/pillar/libvirt.py +++ b/salt/pillar/libvirt.py @@ -4,6 +4,7 @@ generated using the libvirt key runner :depends: certtool """ + import os import subprocess @@ -41,9 +42,7 @@ def ext_pillar(minion_id, pillar, command): continue fn_ = os.path.join(key_dir, key) with salt.utils.files.fopen(fn_, "r") as fp_: - ret["libvirt.{}".format(key)] = salt.utils.stringutils.to_unicode( - fp_.read() - ) + ret[f"libvirt.{key}"] = salt.utils.stringutils.to_unicode(fp_.read()) with salt.utils.files.fopen(cacert, "r") as fp_: ret["libvirt.cacert.pem"] = salt.utils.stringutils.to_unicode(fp_.read()) return ret @@ -74,7 +73,7 @@ def gen_hyper_keys( proc = subprocess.run( ["certtool", "--generate-privkey"], stdout=subprocess.PIPE, - universal_newlines=True, + text=True, check=True, ) with salt.utils.files.fopen(cakey, "w") as wfh: @@ -115,7 +114,7 @@ def gen_hyper_keys( proc = subprocess.run( ["certtool", "--generate-privkey"], stdout=subprocess.PIPE, - universal_newlines=True, + text=True, check=True, ) with salt.utils.files.fopen(priv, "w") as wfh: @@ -152,7 +151,7 @@ def gen_hyper_keys( proc = subprocess.run( ["certtool", "--generate-privkey"], stdout=subprocess.PIPE, - universal_newlines=True, + text=True, check=True, ) with salt.utils.files.fopen(cpriv, "w") as wfh: diff --git a/salt/pillar/makostack.py b/salt/pillar/makostack.py index b689bd5f4cd..f96092f8945 100644 --- a/salt/pillar/makostack.py +++ b/salt/pillar/makostack.py @@ -372,7 +372,6 @@ You can also select a custom merging strategy using a ``__`` object in a list: +----------------+-------------------------+-------------------------+ """ - import functools import logging import os @@ -499,9 +498,7 @@ def _cleanup(obj): def _merge_dict(stack, obj): strategy = obj.pop("__", "merge-last") if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return _cleanup(obj) else: @@ -538,9 +535,7 @@ def _merge_list(stack, obj): strategy = obj[0]["__"] del obj[0] if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return obj elif strategy == "remove": diff --git a/salt/pillar/nacl.py b/salt/pillar/nacl.py index 67f8c6fd25a..5e0a03512d7 100644 --- a/salt/pillar/nacl.py +++ b/salt/pillar/nacl.py @@ -18,7 +18,6 @@ Set ``nacl.config`` in your config. """ - import salt __virtualname__ = "nacl" diff --git a/salt/pillar/neutron.py b/salt/pillar/neutron.py index 738305b916b..2999f9a6b7c 100644 --- a/salt/pillar/neutron.py +++ b/salt/pillar/neutron.py @@ -42,7 +42,6 @@ name after the Keystone profile name: - neutron: my_openstack_config neutron_networks """ - import logging try: diff --git a/salt/pillar/pepa.py b/salt/pillar/pepa.py index a35ebb47a09..3be4a4bea62 100644 --- a/salt/pillar/pepa.py +++ b/salt/pillar/pepa.py @@ -615,7 +615,7 @@ if __name__ == "__main__": if not request.ok: raise RuntimeError( - "Failed to authenticate to SaltStack REST API: {}".format(request.text) + f"Failed to authenticate to SaltStack REST API: {request.text}" ) response = request.json() diff --git a/salt/pillar/puppet.py b/salt/pillar/puppet.py index b907ad1f321..792c3ec7738 100644 --- a/salt/pillar/puppet.py +++ b/salt/pillar/puppet.py @@ -19,9 +19,7 @@ def ext_pillar(minion_id, pillar, command): # pylint: disable=W0613 Execute an unmodified puppet_node_classifier and read the output as YAML """ try: - data = salt.utils.yaml.safe_load( - __salt__["cmd.run"]("{} {}".format(command, minion_id)) - ) + data = salt.utils.yaml.safe_load(__salt__["cmd.run"](f"{command} {minion_id}")) return data["parameters"] except Exception: # pylint: disable=broad-except log.critical("YAML data from %s failed to parse", command) diff --git a/salt/pillar/reclass_adapter.py b/salt/pillar/reclass_adapter.py index 2f7e158ce75..ded9d664934 100644 --- a/salt/pillar/reclass_adapter.py +++ b/salt/pillar/reclass_adapter.py @@ -45,7 +45,6 @@ either let the master know via the ``PYTHONPATH`` environment variable, or by setting the configuration option, like in the example above. """ - # This file cannot be called reclass.py, because then the module import would # not work. Thanks to the __virtual__ function, however, the plugin still # responds to the name 'reclass'. @@ -127,4 +126,4 @@ def ext_pillar(minion_id, pillar, **kwargs): raise except ReclassException as e: - raise SaltInvocationError("ext_pillar.reclass: {}".format(e)) + raise SaltInvocationError(f"ext_pillar.reclass: {e}") diff --git a/salt/pillar/s3.py b/salt/pillar/s3.py index 6e97dfd33bd..deb1c9b2a26 100644 --- a/salt/pillar/s3.py +++ b/salt/pillar/s3.py @@ -87,7 +87,6 @@ for each environment rather than specifying multiple_env. This is due to issue #22471 (https://github.com/saltstack/salt/issues/22471) """ - import logging import os import pickle @@ -144,7 +143,6 @@ def ext_pillar( path_style=False, https_enable=True, ): - """ Execute a command and read the output as YAML """ @@ -278,7 +276,7 @@ def _get_buckets_cache_filename(bucket, prefix): if not os.path.exists(cache_dir): os.makedirs(cache_dir) - return os.path.join(cache_dir, "{}-{}-files.cache".format(bucket, prefix)) + return os.path.join(cache_dir, f"{bucket}-{prefix}-files.cache") def _refresh_buckets_cache_file(creds, cache_file, multiple_env, environment, prefix): diff --git a/salt/pillar/saltclass.py b/salt/pillar/saltclass.py index 3354b1ae7ba..badf776eb0d 100644 --- a/salt/pillar/saltclass.py +++ b/salt/pillar/saltclass.py @@ -11,7 +11,6 @@ SaltClass Pillar Module For additional configuration instructions, see the :mod:`saltclass ` module """ - import logging import salt.utils.saltclass as sc diff --git a/salt/pillar/stack.py b/salt/pillar/stack.py index f5e2a07ea44..f8936ad4b4a 100644 --- a/salt/pillar/stack.py +++ b/salt/pillar/stack.py @@ -373,6 +373,7 @@ You can also select a custom merging strategy using a ``__`` object in a list: | - root | - mat | | +----------------+-------------------------+-------------------------+ """ + import functools import glob import logging @@ -475,9 +476,7 @@ def _process_stack_cfg(cfg, stack, minion_id, pillar): try: yaml = jenv.get_template(unix_path).render(stack=stack, ymlpath=path) except Exception as e: - raise Exception( - 'Stack pillar template render error in {}:\n"{}"'.format(path, e) - ) + raise Exception(f'Stack pillar template render error in {path}:\n"{e}"') try: obj = salt.utils.yaml.safe_load(yaml) except Exception as e: @@ -505,9 +504,7 @@ def _cleanup(obj): def _merge_dict(stack, obj): strategy = obj.pop("__", "merge-last") if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return _cleanup(obj) else: @@ -544,9 +541,7 @@ def _merge_list(stack, obj): strategy = obj[0]["__"] del obj[0] if strategy not in strategies: - raise Exception( - 'Unknown strategy "{}", should be one of {}'.format(strategy, strategies) - ) + raise Exception(f'Unknown strategy "{strategy}", should be one of {strategies}') if strategy == "overwrite": return obj elif strategy == "remove": diff --git a/salt/pillar/varstack_pillar.py b/salt/pillar/varstack_pillar.py index 7f1d707b538..eebb12fda19 100644 --- a/salt/pillar/varstack_pillar.py +++ b/salt/pillar/varstack_pillar.py @@ -18,7 +18,6 @@ data to return as pillar information. From there you can take a look at the varstack on how this file is evaluated. """ - try: import varstack except ImportError: diff --git a/salt/pillar/vault.py b/salt/pillar/vault.py index 1ae0c9c86e0..36ea8bb7b2b 100644 --- a/salt/pillar/vault.py +++ b/salt/pillar/vault.py @@ -151,7 +151,6 @@ You can override the merging behavior per defined ext_pillar: merge_lists: false """ - import logging import salt.utils.dictupdate diff --git a/salt/platform/win.py b/salt/platform/win.py index 694238e4fc0..0483e016d9e 100644 --- a/salt/platform/win.py +++ b/salt/platform/win.py @@ -154,7 +154,7 @@ class NTSTATUS(wintypes.LONG): def __repr__(self): name = self.__class__.__name__ status = wintypes.ULONG.from_buffer(self) - return "{}({})".format(name, status.value) + return f"{name}({status.value})" PNTSTATUS = ctypes.POINTER(NTSTATUS) @@ -163,7 +163,7 @@ PNTSTATUS = ctypes.POINTER(NTSTATUS) class BOOL(wintypes.BOOL): def __repr__(self): name = self.__class__.__name__ - return "{}({})".format(name, bool(self)) + return f"{name}({bool(self)})" class HANDLE(wintypes.HANDLE): @@ -187,7 +187,7 @@ class HANDLE(wintypes.HANDLE): __del__ = Close def __repr__(self): - return "{}({})".format(self.__class__.__name__, int(self)) + return f"{self.__class__.__name__}({int(self)})" class LARGE_INTEGER(wintypes.LARGE_INTEGER): @@ -202,7 +202,7 @@ class LARGE_INTEGER(wintypes.LARGE_INTEGER): def __repr__(self): name = self.__class__.__name__ - return "{}({})".format(name, self.value) + return f"{name}({self.value})" def as_time(self): time100ns = self.value - self._unix_epoch @@ -258,7 +258,7 @@ class LUID(ctypes.Structure): def __repr__(self): name = self.__class__.__name__ - return "{}({})".format(name, int(self)) + return f"{name}({int(self)})" LPLUID = ctypes.POINTER(LUID) @@ -309,7 +309,7 @@ class TOKEN_SOURCE(ctypes.Structure): LPTOKEN_SOURCE = ctypes.POINTER(TOKEN_SOURCE) py_source_context = TOKEN_SOURCE(b"PYTHON ") py_origin_name = __name__.encode() -py_logon_process_name = "{}-{}".format(py_origin_name, os.getpid()) +py_logon_process_name = f"{py_origin_name}-{os.getpid()}" SIZE_T = ctypes.c_size_t @@ -340,7 +340,7 @@ class ContiguousUnicode(ctypes.Structure): def _get_unicode_string(self, name): wchar_size = ctypes.sizeof(WCHAR) - s = getattr(self, "_{}".format(name)) + s = getattr(self, f"_{name}") length = s.Length // wchar_size buf = s.Buffer if buf: @@ -372,7 +372,7 @@ class ContiguousUnicode(ctypes.Structure): addr = ctypes.addressof(self) + ctypes.sizeof(cls) for n, v in zip(self._string_names_, values): ptr = ctypes.cast(addr, PWCHAR) - ustr = getattr(self, "_{}".format(n)) + ustr = getattr(self, f"_{n}") length = ustr.Length = len(v) * wchar_size full_length = length + wchar_size if (n == name and value is None) or ( @@ -404,7 +404,7 @@ class ContiguousUnicode(ctypes.Structure): ctypes.memmove(ctypes.byref(x), address, ctypes.sizeof(x)) delta = ctypes.addressof(x) - address for n in cls._string_names_: - ustr = getattr(x, "_{}".format(n)) + ustr = getattr(x, f"_{n}") addr = ctypes.c_void_p.from_buffer(ustr.Buffer) if addr: addr.value += delta diff --git a/salt/proxy/chronos.py b/salt/proxy/chronos.py index 69b06d63e44..a138f39e78b 100644 --- a/salt/proxy/chronos.py +++ b/salt/proxy/chronos.py @@ -55,7 +55,7 @@ def ping(): """ try: response = salt.utils.http.query( - "{}/scheduler/jobs".format(CONFIG[CONFIG_BASE_URL]), + f"{CONFIG[CONFIG_BASE_URL]}/scheduler/jobs", decode_type="json", decode=True, ) diff --git a/salt/proxy/cisconso.py b/salt/proxy/cisconso.py index aa97f37b1b5..8d9bd56c629 100644 --- a/salt/proxy/cisconso.py +++ b/salt/proxy/cisconso.py @@ -171,7 +171,6 @@ responding: salt test.ping """ - import logging from salt.exceptions import SaltSystemExit diff --git a/salt/proxy/dummy.py b/salt/proxy/dummy.py index d470c1082a7..d1238c9c4eb 100644 --- a/salt/proxy/dummy.py +++ b/salt/proxy/dummy.py @@ -30,7 +30,7 @@ def __virtual__(): def _save_state(opts, details): _id = __context__["dummy_proxy"]["id"] - cachefile = os.path.join(opts["cachedir"], "dummy-proxy-{}.cache".format(_id)) + cachefile = os.path.join(opts["cachedir"], f"dummy-proxy-{_id}.cache") with salt.utils.files.fopen(cachefile, "wb") as pck: pck.write(salt.utils.msgpack.packb(details, use_bin_type=True)) log.warning("Dummy Proxy Saved State(%s):\n%s", cachefile, pprint.pformat(details)) @@ -38,7 +38,7 @@ def _save_state(opts, details): def _load_state(opts): _id = __context__["dummy_proxy"]["id"] - cachefile = os.path.join(opts["cachedir"], "dummy-proxy-{}.cache".format(_id)) + cachefile = os.path.join(opts["cachedir"], f"dummy-proxy-{_id}.cache") try: with salt.utils.files.fopen(cachefile, "rb") as pck: state = salt.utils.msgpack.unpackb(pck.read(), raw=False) diff --git a/salt/proxy/esxcluster.py b/salt/proxy/esxcluster.py index 4448178398a..cbb15e587ff 100644 --- a/salt/proxy/esxcluster.py +++ b/salt/proxy/esxcluster.py @@ -149,6 +149,7 @@ Associated states are documented in Look there to find an example structure for Pillar as well as an example ``.sls`` file for configuring an ESX cluster from scratch. """ + import logging import os diff --git a/salt/proxy/esxdatacenter.py b/salt/proxy/esxdatacenter.py index 98b0be0e1d1..ff100786656 100644 --- a/salt/proxy/esxdatacenter.py +++ b/salt/proxy/esxdatacenter.py @@ -144,7 +144,6 @@ Look there to find an example structure for Pillar as well as an example ``.sls`` file for configuring an ESX datacenter from scratch. """ - import logging import os diff --git a/salt/proxy/esxi.py b/salt/proxy/esxi.py index af58e48185c..a7f6b1e90e4 100644 --- a/salt/proxy/esxi.py +++ b/salt/proxy/esxi.py @@ -277,7 +277,6 @@ for standing up an ESXi host from scratch. """ - import logging import os diff --git a/salt/proxy/esxvm.py b/salt/proxy/esxvm.py index ac46bdf304c..247aa078b47 100644 --- a/salt/proxy/esxvm.py +++ b/salt/proxy/esxvm.py @@ -144,7 +144,6 @@ Look there to find an example structure for Pillar as well as an example ``.sls`` file for configuring an ESX virtual machine from scratch. """ - import logging import os diff --git a/salt/proxy/marathon.py b/salt/proxy/marathon.py index 5347276bbdb..3be5b366333 100644 --- a/salt/proxy/marathon.py +++ b/salt/proxy/marathon.py @@ -55,7 +55,7 @@ def ping(): """ try: response = salt.utils.http.query( - "{}/ping".format(CONFIG[CONFIG_BASE_URL]), + f"{CONFIG[CONFIG_BASE_URL]}/ping", decode_type="plain", decode=True, ) diff --git a/salt/proxy/napalm.py b/salt/proxy/napalm.py index 4b9729635cb..13f2663cf0a 100644 --- a/salt/proxy/napalm.py +++ b/salt/proxy/napalm.py @@ -299,7 +299,7 @@ def shutdown(opts): __context__["napalm_device"]["network_device"].get( "HOSTNAME", "[unknown hostname]" ), - ":{}".format(port) if port else "", + f":{port}" if port else "", error, ) diff --git a/salt/proxy/philips_hue.py b/salt/proxy/philips_hue.py index 9b846baf096..da3ab572430 100644 --- a/salt/proxy/philips_hue.py +++ b/salt/proxy/philips_hue.py @@ -117,9 +117,9 @@ def _query(lamp_id, state, action="", method="GET"): # Because salt.utils.query is that dreadful... :( err = None - url = "{}/lights{}".format( - CONFIG["uri"], lamp_id and "/{}".format(lamp_id) or "" - ) + (action and "/{}".format(action) or "") + url = "{}/lights{}".format(CONFIG["uri"], lamp_id and f"/{lamp_id}" or "") + ( + action and f"/{action}" or "" + ) conn = http.client.HTTPConnection(CONFIG["host"]) if method == "PUT": conn.request(method, url, salt.utils.json.dumps(state)) @@ -130,7 +130,7 @@ def _query(lamp_id, state, action="", method="GET"): if resp.status == http.client.OK: res = salt.utils.json.loads(resp.read()) else: - err = "HTTP error: {}, {}".format(resp.status, resp.reason) + err = f"HTTP error: {resp.status}, {resp.reason}" conn.close() if err: raise CommandExecutionError(err) diff --git a/salt/proxy/rest_sample.py b/salt/proxy/rest_sample.py index 596e91494e3..4e66bbfd67e 100644 --- a/salt/proxy/rest_sample.py +++ b/salt/proxy/rest_sample.py @@ -192,7 +192,6 @@ def fix_outage(): def uptodate(name): - """ Call the REST endpoint to see if the packages on the "server" are up to date. """ @@ -205,7 +204,6 @@ def uptodate(name): def package_remove(name): - """ Remove a "package" on the REST server """ diff --git a/salt/proxy/restconf.py b/salt/proxy/restconf.py index d375894b368..31f214aa7cb 100644 --- a/salt/proxy/restconf.py +++ b/salt/proxy/restconf.py @@ -72,7 +72,6 @@ Proxy Pillar Example verify: false """ - import copy import json import logging diff --git a/salt/queues/pgjsonb_queue.py b/salt/queues/pgjsonb_queue.py index decade54234..f198c580b2b 100644 --- a/salt/queues/pgjsonb_queue.py +++ b/salt/queues/pgjsonb_queue.py @@ -38,7 +38,6 @@ Use the following Pg database schema: salt-run queue.process_queue test all backend=pgjsonb """ - import logging import sys from contextlib import contextmanager @@ -81,15 +80,11 @@ def _conn(commit=False): conn_kwargs = {} for key, value in defaults.items(): - conn_kwargs[key] = __opts__.get( - "queue.{}.{}".format(__virtualname__, key), value - ) + conn_kwargs[key] = __opts__.get(f"queue.{__virtualname__}.{key}", value) try: conn = psycopg2.connect(**conn_kwargs) except psycopg2.OperationalError as exc: - raise SaltMasterError( - "pgjsonb returner could not connect to database: {exc}".format(exc=exc) - ) + raise SaltMasterError(f"pgjsonb returner could not connect to database: {exc}") cursor = conn.cursor() @@ -118,7 +113,7 @@ def _list_tables(cur): def _create_table(cur, queue): - cmd = "CREATE TABLE {}(id SERIAL PRIMARY KEY, data jsonb NOT NULL)".format(queue) + cmd = f"CREATE TABLE {queue}(id SERIAL PRIMARY KEY, data jsonb NOT NULL)" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True @@ -129,7 +124,7 @@ def _list_items(queue): Private function to list contents of a queue """ with _conn() as cur: - cmd = "SELECT data FROM {}".format(queue) + cmd = f"SELECT data FROM {queue}" log.debug("SQL Query: %s", cmd) cur.execute(cmd) contents = cur.fetchall() @@ -192,7 +187,7 @@ def insert(queue, items): with _conn(commit=True) as cur: if isinstance(items, dict): items = salt.utils.json.dumps(items) - cmd = "INSERT INTO {}(data) VALUES('{}')".format(queue, items) + cmd = f"INSERT INTO {queue}(data) VALUES('{items}')" log.debug("SQL Query: %s", cmd) try: cur.execute(cmd) @@ -202,7 +197,7 @@ def insert(queue, items): ) if isinstance(items, list): items = [(salt.utils.json.dumps(el),) for el in items] - cmd = "INSERT INTO {}(data) VALUES (%s)".format(queue) + cmd = f"INSERT INTO {queue}(data) VALUES (%s)" log.debug("SQL Query: %s", cmd) try: cur.executemany(cmd, items) @@ -228,7 +223,7 @@ def delete(queue, items): return True if isinstance(items, list): items = [(salt.utils.json.dumps(el),) for el in items] - cmd = "DELETE FROM {} WHERE data = %s".format(queue) + cmd = f"DELETE FROM {queue} WHERE data = %s" log.debug("SQL Query: %s", cmd) cur.executemany(cmd, items) return True @@ -238,7 +233,7 @@ def pop(queue, quantity=1, is_runner=False): """ Pop one or more or all items from the queue return them. """ - cmd = "SELECT id, data FROM {}".format(queue) + cmd = f"SELECT id, data FROM {queue}" if quantity != "all": try: quantity = int(quantity) @@ -247,7 +242,7 @@ def pop(queue, quantity=1, is_runner=False): exc ) raise SaltInvocationError(error_txt) - cmd = "".join([cmd, " LIMIT {};".format(quantity)]) + cmd = "".join([cmd, f" LIMIT {quantity};"]) log.debug("SQL Query: %s", cmd) items = [] with _conn(commit=True) as cur: @@ -257,7 +252,7 @@ def pop(queue, quantity=1, is_runner=False): ids = [str(item[0]) for item in result] items = [item[1] for item in result] idlist = "','".join(ids) - del_cmd = "DELETE FROM {} WHERE id IN ('{}');".format(queue, idlist) + del_cmd = f"DELETE FROM {queue} WHERE id IN ('{idlist}');" log.debug("SQL Query: %s", del_cmd) diff --git a/salt/queues/sqlite_queue.py b/salt/queues/sqlite_queue.py index 713bfa09ccd..b81d13ce5ed 100644 --- a/salt/queues/sqlite_queue.py +++ b/salt/queues/sqlite_queue.py @@ -38,7 +38,7 @@ def _conn(queue): Return an sqlite connection """ queue_dir = __opts__["sqlite_queue_dir"] - db = os.path.join(queue_dir, "{}.db".format(queue)) + db = os.path.join(queue_dir, f"{queue}.db") log.debug("Connecting to: %s", db) con = sqlite3.connect(db) @@ -61,7 +61,7 @@ def _list_tables(con): def _create_table(con, queue): with con: cur = con.cursor() - cmd = "CREATE TABLE {}(id INTEGER PRIMARY KEY, name TEXT UNIQUE)".format(queue) + cmd = f"CREATE TABLE {queue}(id INTEGER PRIMARY KEY, name TEXT UNIQUE)" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True @@ -74,7 +74,7 @@ def _list_items(queue): con = _conn(queue) with con: cur = con.cursor() - cmd = "SELECT name FROM {}".format(queue) + cmd = f"SELECT name FROM {queue}" log.debug("SQL Query: %s", cmd) cur.execute(cmd) contents = cur.fetchall() @@ -138,15 +138,15 @@ def insert(queue, items): cur = con.cursor() if isinstance(items, str): items = _quote_escape(items) - cmd = "INSERT INTO {}(name) VALUES('{}')".format(queue, items) + cmd = f"INSERT INTO {queue}(name) VALUES('{items}')" log.debug("SQL Query: %s", cmd) try: cur.execute(cmd) except sqlite3.IntegrityError as esc: - return "Item already exists in this queue. sqlite error: {}".format(esc) + return f"Item already exists in this queue. sqlite error: {esc}" if isinstance(items, list): items = [_quote_escape(el) for el in items] - cmd = "INSERT INTO {}(name) VALUES(?)".format(queue) + cmd = f"INSERT INTO {queue}(name) VALUES(?)" log.debug("SQL Query: %s", cmd) newitems = [] for item in items: @@ -162,12 +162,12 @@ def insert(queue, items): if isinstance(items, dict): items = salt.utils.json.dumps(items).replace('"', "'") items = _quote_escape(items) - cmd = "INSERT INTO {}(name) VALUES('{}')".format(queue, items) + cmd = f"INSERT INTO {queue}(name) VALUES('{items}')" log.debug("SQL Query: %s", cmd) try: cur.execute(cmd) except sqlite3.IntegrityError as esc: - return "Item already exists in this queue. sqlite error: {}".format(esc) + return f"Item already exists in this queue. sqlite error: {esc}" return True @@ -180,13 +180,13 @@ def delete(queue, items): cur = con.cursor() if isinstance(items, str): items = _quote_escape(items) - cmd = "DELETE FROM {} WHERE name = '{}'".format(queue, items) + cmd = f"DELETE FROM {queue} WHERE name = '{items}'" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True if isinstance(items, list): items = [_quote_escape(el) for el in items] - cmd = "DELETE FROM {} WHERE name = ?".format(queue) + cmd = f"DELETE FROM {queue} WHERE name = ?" log.debug("SQL Query: %s", cmd) newitems = [] for item in items: @@ -196,7 +196,7 @@ def delete(queue, items): if isinstance(items, dict): items = salt.utils.json.dumps(items).replace('"', "'") items = _quote_escape(items) - cmd = "DELETE FROM {} WHERE name = '{}'".format(queue, items) + cmd = f"DELETE FROM {queue} WHERE name = '{items}'" log.debug("SQL Query: %s", cmd) cur.execute(cmd) return True @@ -207,7 +207,7 @@ def pop(queue, quantity=1, is_runner=False): """ Pop one or more or all items from the queue return them. """ - cmd = "SELECT name FROM {}".format(queue) + cmd = f"SELECT name FROM {queue}" if quantity != "all": try: quantity = int(quantity) @@ -216,7 +216,7 @@ def pop(queue, quantity=1, is_runner=False): exc ) raise SaltInvocationError(error_txt) - cmd = "".join([cmd, " LIMIT {}".format(quantity)]) + cmd = "".join([cmd, f" LIMIT {quantity}"]) log.debug("SQL Query: %s", cmd) con = _conn(queue) items = [] @@ -227,7 +227,7 @@ def pop(queue, quantity=1, is_runner=False): items = [item[0] for item in result] itemlist = '","'.join(items) _quote_escape(itemlist) - del_cmd = 'DELETE FROM {} WHERE name IN ("{}")'.format(queue, itemlist) + del_cmd = f'DELETE FROM {queue} WHERE name IN ("{itemlist}")' log.debug("SQL Query: %s", del_cmd) diff --git a/salt/renderers/cheetah.py b/salt/renderers/cheetah.py index d7351fa6af9..5cb8499e390 100644 --- a/salt/renderers/cheetah.py +++ b/salt/renderers/cheetah.py @@ -2,7 +2,6 @@ Cheetah Renderer for Salt """ - try: from Cheetah.Template import Template diff --git a/salt/renderers/dson.py b/salt/renderers/dson.py index 0a9597aa5f6..45d4f1ab252 100644 --- a/salt/renderers/dson.py +++ b/salt/renderers/dson.py @@ -11,7 +11,6 @@ This renderer requires `Dogeon`__ (installable via pip) .. __: https://github.com/soasme/dogeon """ - import logging try: diff --git a/salt/renderers/genshi.py b/salt/renderers/genshi.py index 206cce5a3fe..62716fc2522 100644 --- a/salt/renderers/genshi.py +++ b/salt/renderers/genshi.py @@ -2,7 +2,6 @@ Genshi Renderer for Salt """ - try: from genshi.template import MarkupTemplate, NewTextTemplate, OldTextTemplate diff --git a/salt/renderers/gpg.py b/salt/renderers/gpg.py index 583d75efd69..8edde999cd9 100644 --- a/salt/renderers/gpg.py +++ b/salt/renderers/gpg.py @@ -335,7 +335,6 @@ In the Chlorine release, the default behavior will be reversed and an error message will be added to ``_errors`` by default. """ - import logging import os import re diff --git a/salt/renderers/hjson.py b/salt/renderers/hjson.py index f76f993dee6..84a7531af94 100644 --- a/salt/renderers/hjson.py +++ b/salt/renderers/hjson.py @@ -6,7 +6,6 @@ See the hjson_ documentation for more information .. _hjson: http://laktak.github.io/hjson/ """ - try: import hjson diff --git a/salt/renderers/jinja.py b/salt/renderers/jinja.py index 3ad9855805f..f238bd281de 100644 --- a/salt/renderers/jinja.py +++ b/salt/renderers/jinja.py @@ -4,7 +4,6 @@ Jinja loading utils to enable a more powerful backend for jinja templates .. include:: ../../../_incl/jinja_security.rst """ - import logging from io import StringIO @@ -47,7 +46,7 @@ def render( argline="", context=None, tmplpath=None, - **kws + **kws, ): """ Render the template_file, passing the functions and grains into the @@ -57,7 +56,7 @@ def render( """ from_str = argline == "-s" if not from_str and argline: - raise SaltRenderError("Unknown renderer option: {opt}".format(opt=argline)) + raise SaltRenderError(f"Unknown renderer option: {argline}") tmp_data = salt.utils.templates.JINJA( template_file, @@ -72,7 +71,7 @@ def render( tmplpath=tmplpath, proxy=__proxy__, from_str=from_str, - **kws + **kws, ) if not tmp_data.get("result", False): raise SaltRenderError( diff --git a/salt/renderers/json.py b/salt/renderers/json.py index 36125685334..79d29fa6b37 100644 --- a/salt/renderers/json.py +++ b/salt/renderers/json.py @@ -2,7 +2,6 @@ JSON Renderer for Salt """ - import salt.utils.json json = salt.utils.json.import_json() diff --git a/salt/renderers/json5.py b/salt/renderers/json5.py index 9d4b345113f..ed8e96e5aa1 100644 --- a/salt/renderers/json5.py +++ b/salt/renderers/json5.py @@ -11,7 +11,6 @@ This renderer requires the `json5 python bindings`__, installable via pip. .. __: https://pypi.python.org/pypi/json5 """ - import logging try: diff --git a/salt/renderers/mako.py b/salt/renderers/mako.py index 01d413140ba..9032542f865 100644 --- a/salt/renderers/mako.py +++ b/salt/renderers/mako.py @@ -10,7 +10,6 @@ To install Mako, do the following: salt-pip install mako """ - import io import salt.utils.templates diff --git a/salt/renderers/nacl.py b/salt/renderers/nacl.py index 9cd2ba0f46b..6fa0351d45c 100644 --- a/salt/renderers/nacl.py +++ b/salt/renderers/nacl.py @@ -50,7 +50,6 @@ data like so: a-secret: "NACL[MRN3cc+fmdxyQbz6WMF+jq1hKdU5X5BBI7OjK+atvHo1ll+w1gZ7XyWtZVfq9gK9rQaMfkDxmidJKwE0Mw==]" """ - import logging import re diff --git a/salt/renderers/pass.py b/salt/renderers/pass.py index ae75bba443b..825810ce68f 100644 --- a/salt/renderers/pass.py +++ b/salt/renderers/pass.py @@ -75,7 +75,6 @@ Salt master configuration options pass_dir: """ - import logging import os from os.path import expanduser diff --git a/salt/renderers/py.py b/salt/renderers/py.py index 3ce58ac405c..46ce1c03902 100644 --- a/salt/renderers/py.py +++ b/salt/renderers/py.py @@ -140,7 +140,7 @@ def render(template, saltenv="base", sls="", tmplpath=None, **kws): """ template = tmplpath if not os.path.isfile(template): - raise SaltRenderError("Template {} is not a file!".format(template)) + raise SaltRenderError(f"Template {template} is not a file!") tmp_data = salt.utils.templates.py( template, @@ -157,7 +157,7 @@ def render(template, saltenv="base", sls="", tmplpath=None, **kws): saltenv=saltenv, __sls__=sls, sls=sls, - **kws + **kws, ) if not tmp_data.get("result", False): raise SaltRenderError( diff --git a/salt/renderers/pydsl.py b/salt/renderers/pydsl.py index 5cd74941bf2..996bbb13848 100644 --- a/salt/renderers/pydsl.py +++ b/salt/renderers/pydsl.py @@ -333,6 +333,7 @@ For example: my_mod = sys.modules['salt.loaded.ext.module.my_mod'] """ + import types import salt.utils.pydsl as pydsl diff --git a/salt/renderers/pyobjects.py b/salt/renderers/pyobjects.py index ad56246396b..a719b34ef5f 100644 --- a/salt/renderers/pyobjects.py +++ b/salt/renderers/pyobjects.py @@ -313,6 +313,7 @@ file ``samba/map.sls``, you could do the following. Service.running("samba", name=Samba.service) """ + # TODO: Interface for working with reactor files @@ -346,7 +347,7 @@ class PyobjectsModule: self.__dict__ = attrs def __repr__(self): - return "".format(self.name) + return f"" def load_states(): @@ -463,9 +464,7 @@ def render(template, saltenv="base", sls="", salt_data=True, **kwargs): with get_file_client(__opts__) as client: state_file = client.cache_file(import_file, saltenv) if not state_file: - raise ImportError( - "Could not find the file '{}'".format(import_file) - ) + raise ImportError(f"Could not find the file '{import_file}'") with salt.utils.files.fopen(state_file) as state_fh: state_contents, state_globals = process_template(state_fh) @@ -490,7 +489,7 @@ def render(template, saltenv="base", sls="", salt_data=True, **kwargs): if name not in state_globals: raise ImportError( - "'{}' was not found in '{}'".format(name, import_file) + f"'{name}' was not found in '{import_file}'" ) template_globals[alias] = state_globals[name] diff --git a/salt/renderers/stateconf.py b/salt/renderers/stateconf.py index 3b0348633af..50b2ebb20c0 100644 --- a/salt/renderers/stateconf.py +++ b/salt/renderers/stateconf.py @@ -5,6 +5,7 @@ A flexible renderer that takes a templating engine and a data format :maturity: new :platform: all """ + # See http://docs.saltstack.org/en/latest/ref/renderers/all/salt.renderers.stateconf.html # for a guide to using this module. # @@ -50,7 +51,7 @@ __opts__ = { # name of the state id for the generated start state. "stateconf_goal_state": ".goal", # name of the state id for the generated goal state. - "stateconf_state_func": "stateconf.set" + "stateconf_state_func": "stateconf.set", # names the state and the state function to be recognized as a special # state from which to gather sls file context variables. It should be # specified in the 'state.func' notation, and both the state module and @@ -115,7 +116,7 @@ def render(input, saltenv="base", sls="", argline="", **kws): sls, context=ctx, argline=rt_argline.strip(), - **kws + **kws, ) high = render_data(tmplout, saltenv, sls, argline=rd_argline.strip()) return process_high_data(high, extract) @@ -201,7 +202,7 @@ def render(input, saltenv="base", sls="", argline="", **kws): name, rt_argline = (args[1] + " ").split(" ", 1) render_template = renderers[name] # e.g., the mako renderer except KeyError as err: - raise SaltRenderError("Renderer: {} is not available!".format(err)) + raise SaltRenderError(f"Renderer: {err} is not available!") except IndexError: raise INVALID_USAGE_ERROR @@ -427,7 +428,7 @@ EXTENDED_REQUIRE_IN = {} # explicit require_in/watch_in/listen_in/onchanges_in/onfail_in can only contain states after it def add_implicit_requires(data): def T(sid, state): # pylint: disable=C0103 - return "{}:{}".format(sid, state_name(state)) + return f"{sid}:{state_name(state)}" states_before = set() states_after = set() diff --git a/salt/renderers/yaml.py b/salt/renderers/yaml.py index eb76a431372..cfc908bce19 100644 --- a/salt/renderers/yaml.py +++ b/salt/renderers/yaml.py @@ -4,7 +4,6 @@ YAML Renderer for Salt For YAML usage information see :ref:`Understanding YAML `. """ - import logging import warnings diff --git a/salt/returners/__init__.py b/salt/returners/__init__.py index 5ad44a7ff65..2f184fa598a 100644 --- a/salt/returners/__init__.py +++ b/salt/returners/__init__.py @@ -120,9 +120,9 @@ def _fetch_option(cfg, ret_config, virtualname, attr_name): if isinstance(cfg, dict): c_cfg = cfg else: - c_cfg = cfg("{}".format(virtualname), {}) + c_cfg = cfg(f"{virtualname}", {}) - default_cfg_key = "{}.{}".format(virtualname, attr_name) + default_cfg_key = f"{virtualname}.{attr_name}" if not ret_config: # Using the default configuration key if isinstance(cfg, dict): @@ -134,7 +134,7 @@ def _fetch_option(cfg, ret_config, virtualname, attr_name): return c_cfg.get(attr_name, cfg(default_cfg_key)) # Using ret_config to override the default configuration key - ret_cfg = cfg("{}.{}".format(ret_config, virtualname), {}) + ret_cfg = cfg(f"{ret_config}.{virtualname}", {}) override_default_cfg_key = "{}.{}.{}".format( ret_config, @@ -209,6 +209,6 @@ def _fetch_profile_opts( return {} return { - pattr: creds.get("{}.{}".format(virtualname, profile_attrs[pattr])) + pattr: creds.get(f"{virtualname}.{profile_attrs[pattr]}") for pattr in profile_attrs } diff --git a/salt/returners/appoptics_return.py b/salt/returners/appoptics_return.py index c49d5e22e28..036112e11fa 100644 --- a/salt/returners/appoptics_return.py +++ b/salt/returners/appoptics_return.py @@ -69,7 +69,6 @@ the name of the state that was invoked, e.g. ``role_salt_master.netapi``. """ - import logging import salt.returners diff --git a/salt/returners/carbon_return.py b/salt/returners/carbon_return.py index 5dd6cd82dbd..91d5ceeb24a 100644 --- a/salt/returners/carbon_return.py +++ b/salt/returners/carbon_return.py @@ -198,10 +198,10 @@ def _walk(path, value, metrics, timestamp, skip): ) if isinstance(value, Mapping): for key, val in value.items(): - _walk("{}.{}".format(path, key), val, metrics, timestamp, skip) + _walk(f"{path}.{key}", val, metrics, timestamp, skip) elif isinstance(value, list): for item in value: - _walk("{}.{}".format(path, item), item, metrics, timestamp, skip) + _walk(f"{path}.{item}", item, metrics, timestamp, skip) else: try: diff --git a/salt/returners/couchdb_return.py b/salt/returners/couchdb_return.py index 1a67a61d275..0e39745c883 100644 --- a/salt/returners/couchdb_return.py +++ b/salt/returners/couchdb_return.py @@ -51,7 +51,6 @@ otherwise multi-minion targeting can lead to losing output: * other minions fail with ``{'error': 'HTTP Error 409: Conflict'}`` """ - import logging import time from urllib.error import HTTPError @@ -123,7 +122,7 @@ def _request(method, url, content_type=None, _data=None): try: handler = opener.open(request) except HTTPError as exc: - return {"error": "{}".format(exc)} + return {"error": f"{exc}"} return salt.utils.json.loads(handler.read()) diff --git a/salt/returners/elasticsearch_return.py b/salt/returners/elasticsearch_return.py index e4c790b64b5..8d329e313e3 100644 --- a/salt/returners/elasticsearch_return.py +++ b/salt/returners/elasticsearch_return.py @@ -93,7 +93,6 @@ Minion configuration: - saltutil.find_job """ - import datetime import logging import uuid @@ -183,8 +182,8 @@ def _ensure_index(index): "number_of_replicas": options["number_of_replicas"], } } - __salt__["elasticsearch.index_create"]("{}-v1".format(index), index_definition) - __salt__["elasticsearch.alias_create"]("{}-v1".format(index), index) + __salt__["elasticsearch.index_create"](f"{index}-v1", index_definition) + __salt__["elasticsearch.alias_create"](f"{index}-v1", index) def _convert_keys(data): @@ -236,9 +235,9 @@ def returner(ret): # Build the index name if options["states_single_index"] and job_fun in STATE_FUNCTIONS: - index = "salt-{}".format(STATE_FUNCTIONS[job_fun]) + index = f"salt-{STATE_FUNCTIONS[job_fun]}" else: - index = "salt-{}".format(job_fun_escaped) + index = f"salt-{job_fun_escaped}" if options["index_date"]: index = "{}-{}".format(index, datetime.date.today().strftime("%Y.%m.%d")) @@ -260,7 +259,7 @@ def returner(ret): # index to be '-ordered' so as not to clash with the unsorted # index data format if options["states_order_output"] and isinstance(ret["return"], dict): - index = "{}-ordered".format(index) + index = f"{index}-ordered" max_chars = len(str(len(ret["return"]))) for uid, data in ret["return"].items(): diff --git a/salt/returners/influxdb_return.py b/salt/returners/influxdb_return.py index 645218242aa..99aa32716c3 100644 --- a/salt/returners/influxdb_return.py +++ b/salt/returners/influxdb_return.py @@ -108,9 +108,7 @@ def _get_version(host, port, user, password): version = None # check the InfluxDB version via the HTTP API try: - result = requests.get( - "http://{}:{}/ping".format(host, port), auth=(user, password) - ) + result = requests.get(f"http://{host}:{port}/ping", auth=(user, password)) if influxDBVersionHeader in result.headers: version = result.headers[influxDBVersionHeader] except Exception as ex: # pylint: disable=broad-except @@ -224,7 +222,7 @@ def get_load(jid): Return the load data that marks a specified jid """ serv = _get_serv(ret=None) - sql = "select load from jids where jid = '{}'".format(jid) + sql = f"select load from jids where jid = '{jid}'" log.debug(">> Now in get_load %s", jid) data = serv.query(sql) @@ -240,7 +238,7 @@ def get_jid(jid): """ serv = _get_serv(ret=None) - sql = "select id, full_ret from returns where jid = '{}'".format(jid) + sql = f"select id, full_ret from returns where jid = '{jid}'" data = serv.query(sql) ret = {} diff --git a/salt/returners/librato_return.py b/salt/returners/librato_return.py index cceaffb6490..890393808e1 100644 --- a/salt/returners/librato_return.py +++ b/salt/returners/librato_return.py @@ -29,7 +29,6 @@ by adding more tags to the submission. """ - import logging import salt.returners diff --git a/salt/returners/local_cache.py b/salt/returners/local_cache.py index 1530d94ddfc..927502358a6 100644 --- a/salt/returners/local_cache.py +++ b/salt/returners/local_cache.py @@ -89,7 +89,7 @@ def prep_jid(nocache=False, passed_jid=None, recurse_count=0): So do what you have to do to make sure that stays the case """ if recurse_count >= 5: - err = "prep_jid could not store a jid after {} tries.".format(recurse_count) + err = f"prep_jid could not store a jid after {recurse_count} tries." log.error(err) raise salt.exceptions.SaltCacheError(err) if passed_jid is None: # this can be a None or an empty string. @@ -237,7 +237,7 @@ def save_minions(jid, minions, syndic_id=None): log.debug( "Adding minions for job %s%s: %s", jid, - " from syndic master '{}'".format(syndic_id) if syndic_id else "", + f" from syndic master '{syndic_id}'" if syndic_id else "", minions, ) diff --git a/salt/returners/mattermost_returner.py b/salt/returners/mattermost_returner.py index fae03a0259b..d41841aa4a1 100644 --- a/salt/returners/mattermost_returner.py +++ b/salt/returners/mattermost_returner.py @@ -128,7 +128,7 @@ def event_return(events): log.debug("Event data: %s", event["data"]) message = "tag: {}\r\n".format(event["tag"]) for key, value in event["data"].items(): - message += "{}: {}\r\n".format(key, value) + message += f"{key}: {value}\r\n" result = post_message(channel, message, username, api_url, hook) if not result: is_ok = False @@ -157,7 +157,7 @@ def post_message(channel, message, username, api_url, hook): result = salt.utils.mattermost.query( api_url=api_url, hook=hook, - data="payload={}".format(salt.utils.json.dumps(parameters)), + data=f"payload={salt.utils.json.dumps(parameters)}", ) log.debug("result %s", result) diff --git a/salt/returners/memcache_return.py b/salt/returners/memcache_return.py index a5d80802757..455f0a4adc9 100644 --- a/salt/returners/memcache_return.py +++ b/salt/returners/memcache_return.py @@ -121,9 +121,9 @@ def _get_list(serv, key): def _append_list(serv, key, value): if value in _get_list(serv, key): return - r = serv.append(key, "{},".format(value)) + r = serv.append(key, f"{value},") if not r: - serv.add(key, "{},".format(value)) + serv.add(key, f"{value},") def prep_jid(nocache=False, passed_jid=None): # pylint: disable=unused-argument @@ -142,8 +142,8 @@ def returner(ret): jid = ret["jid"] fun = ret["fun"] rets = salt.utils.json.dumps(ret) - serv.set("{}:{}".format(jid, minion), rets) # cache for get_jid - serv.set("{}:{}".format(fun, minion), rets) # cache for get_fun + serv.set(f"{jid}:{minion}", rets) # cache for get_jid + serv.set(f"{fun}:{minion}", rets) # cache for get_fun # The following operations are neither efficient nor atomic. # If there is a way to make them so, this should be updated. @@ -183,7 +183,7 @@ def get_jid(jid): """ serv = _get_serv(ret=None) minions = _get_list(serv, "minions") - returns = serv.get_multi(minions, key_prefix="{}:".format(jid)) + returns = serv.get_multi(minions, key_prefix=f"{jid}:") # returns = {minion: return, minion: return, ...} ret = {} for minion, data in returns.items(): @@ -197,7 +197,7 @@ def get_fun(fun): """ serv = _get_serv(ret=None) minions = _get_list(serv, "minions") - returns = serv.get_multi(minions, key_prefix="{}:".format(fun)) + returns = serv.get_multi(minions, key_prefix=f"{fun}:") # returns = {minion: return, minion: return, ...} ret = {} for minion, data in returns.items(): diff --git a/salt/returners/multi_returner.py b/salt/returners/multi_returner.py index 550a6c1e43e..0017f6e7a2f 100644 --- a/salt/returners/multi_returner.py +++ b/salt/returners/multi_returner.py @@ -3,7 +3,6 @@ Read/Write multiple returners """ - import logging import salt.minion @@ -42,11 +41,9 @@ def prep_jid(nocache=False, passed_jid=None): jid = passed_jid for returner_ in __opts__[CONFIG_KEY]: if jid is None: - jid = _mminion().returners["{}.prep_jid".format(returner_)](nocache=nocache) + jid = _mminion().returners[f"{returner_}.prep_jid"](nocache=nocache) else: - r_jid = _mminion().returners["{}.prep_jid".format(returner_)]( - nocache=nocache - ) + r_jid = _mminion().returners[f"{returner_}.prep_jid"](nocache=nocache) if r_jid != jid: log.debug("Uhh.... crud the jids do not match") return jid @@ -57,7 +54,7 @@ def returner(load): Write return to all returners in multi_returner """ for returner_ in __opts__[CONFIG_KEY]: - _mminion().returners["{}.returner".format(returner_)](load) + _mminion().returners[f"{returner_}.returner"](load) def save_load(jid, clear_load, minions=None): @@ -65,7 +62,7 @@ def save_load(jid, clear_load, minions=None): Write load to all returners in multi_returner """ for returner_ in __opts__[CONFIG_KEY]: - _mminion().returners["{}.save_load".format(returner_)](jid, clear_load) + _mminion().returners[f"{returner_}.save_load"](jid, clear_load) def save_minions(jid, minions, syndic_id=None): # pylint: disable=unused-argument @@ -80,7 +77,7 @@ def get_load(jid): """ ret = {} for returner_ in __opts__[CONFIG_KEY]: - ret.update(_mminion().returners["{}.get_load".format(returner_)](jid)) + ret.update(_mminion().returners[f"{returner_}.get_load"](jid)) return ret @@ -91,7 +88,7 @@ def get_jid(jid): """ ret = {} for returner_ in __opts__[CONFIG_KEY]: - ret.update(_mminion().returners["{}.get_jid".format(returner_)](jid)) + ret.update(_mminion().returners[f"{returner_}.get_jid"](jid)) return ret @@ -102,7 +99,7 @@ def get_jids(): """ ret = {} for returner_ in __opts__[CONFIG_KEY]: - ret.update(_mminion().returners["{}.get_jids".format(returner_)]()) + ret.update(_mminion().returners[f"{returner_}.get_jids"]()) return ret @@ -112,6 +109,6 @@ def clean_old_jobs(): Clean out the old jobs from all returners (if you have it) """ for returner_ in __opts__[CONFIG_KEY]: - fstr = "{}.clean_old_jobs".format(returner_) + fstr = f"{returner_}.clean_old_jobs" if fstr in _mminion().returners: _mminion().returners[fstr]() diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py index 67b44004acf..87f5e37fa46 100644 --- a/salt/returners/mysql.py +++ b/salt/returners/mysql.py @@ -274,7 +274,7 @@ def _get_serv(ret=None, commit=False): pass except OperationalError as exc: raise salt.exceptions.SaltMasterError( - "MySQL returner could not connect to database: {exc}".format(exc=exc) + f"MySQL returner could not connect to database: {exc}" ) cursor = conn.cursor() diff --git a/salt/returners/odbc.py b/salt/returners/odbc.py index f7393876739..da98baf18c4 100644 --- a/salt/returners/odbc.py +++ b/salt/returners/odbc.py @@ -153,7 +153,7 @@ def _get_options(ret=None): attrs = {"dsn": "dsn", "user": "user", "passwd": "passwd"} _options = salt.returners.get_returner_options( - "returner.{}".format(__virtualname__), + f"returner.{__virtualname__}", ret, attrs, __salt__=__salt__, @@ -171,7 +171,7 @@ def _get_conn(ret=None): user = _options.get("user") passwd = _options.get("passwd") - return pyodbc.connect("DSN={};UID={};PWD={}".format(dsn, user, passwd)) + return pyodbc.connect(f"DSN={dsn};UID={user};PWD={passwd}") def _close_conn(conn): diff --git a/salt/returners/pgjsonb.py b/salt/returners/pgjsonb.py index d47e9cce8d6..5cfd1150172 100644 --- a/salt/returners/pgjsonb.py +++ b/salt/returners/pgjsonb.py @@ -225,7 +225,7 @@ def _get_options(ret=None): } _options = salt.returners.get_returner_options( - "returner.{}".format(__virtualname__), + f"returner.{__virtualname__}", ret, attrs, __salt__=__salt__, @@ -258,11 +258,11 @@ def _get_serv(ret=None, commit=False): dbname=_options.get("db"), user=_options.get("user"), password=_options.get("pass"), - **ssl_options + **ssl_options, ) except psycopg2.OperationalError as exc: raise salt.exceptions.SaltMasterError( - "pgjsonb returner could not connect to database: {exc}".format(exc=exc) + f"pgjsonb returner could not connect to database: {exc}" ) if conn.server_version is not None and conn.server_version >= 90500: diff --git a/salt/returners/postgres.py b/salt/returners/postgres.py index a30ac590056..de7d436c83c 100644 --- a/salt/returners/postgres.py +++ b/salt/returners/postgres.py @@ -174,7 +174,7 @@ def _get_options(ret=None): } _options = salt.returners.get_returner_options( - "returner.{}".format(__virtualname__), + f"returner.{__virtualname__}", ret, attrs, __salt__=__salt__, @@ -204,7 +204,7 @@ def _get_serv(ret=None, commit=False): except psycopg2.OperationalError as exc: raise salt.exceptions.SaltMasterError( - "postgres returner could not connect to database: {exc}".format(exc=exc) + f"postgres returner could not connect to database: {exc}" ) cursor = conn.cursor() diff --git a/salt/returners/postgres_local_cache.py b/salt/returners/postgres_local_cache.py index 58d2a19766e..4a8c6d4262e 100644 --- a/salt/returners/postgres_local_cache.py +++ b/salt/returners/postgres_local_cache.py @@ -106,7 +106,6 @@ and then: Required python modules: psycopg2 """ - import logging import re import sys diff --git a/salt/returners/rawfile_json.py b/salt/returners/rawfile_json.py index e06347180d5..a4687611813 100644 --- a/salt/returners/rawfile_json.py +++ b/salt/returners/rawfile_json.py @@ -16,7 +16,6 @@ noise, so you may wish to configure batch processing and/or configure the to restrict the events that are written. """ - import logging import salt.returners diff --git a/salt/returners/sentry_return.py b/salt/returners/sentry_return.py index 0b660392ef0..6f477dc1c99 100644 --- a/salt/returners/sentry_return.py +++ b/salt/returners/sentry_return.py @@ -111,11 +111,7 @@ def _get_message(ret): kwargs = ret["fun_args"][-1] if isinstance(kwargs, dict): kwarg_string = " ".join( - sorted( - "{}={}".format(k, v) - for k, v in kwargs.items() - if not k.startswith("_") - ) + sorted(f"{k}={v}" for k, v in kwargs.items() if not k.startswith("_")) ) return "salt func: {fun} {argstr} {kwargstr}".format( fun=ret["fun"], argstr=arg_string, kwargstr=kwarg_string diff --git a/salt/returners/slack_webhook_return.py b/salt/returners/slack_webhook_return.py index 43357f53d23..5df1a1d641c 100644 --- a/salt/returners/slack_webhook_return.py +++ b/salt/returners/slack_webhook_return.py @@ -170,10 +170,10 @@ def _generate_payload(author_icon, title, report, **kwargs): text += "JID: {}\n".format(report.get("jid")) if TOTAL_KEY in report: - text += "Total: {}\n".format(report[TOTAL_KEY]) + text += f"Total: {report[TOTAL_KEY]}\n" if DURATION_KEY in report: - text += "Duration: {:.2f} secs".format(float(report[DURATION_KEY])) + text += f"Duration: {float(report[DURATION_KEY]):.2f} secs" attachments = [ { @@ -201,7 +201,7 @@ def _generate_payload(author_icon, title, report, **kwargs): # Changed changed = { "color": "warning", - "title": "Changed: {}".format(report[CHANGED_KEY].get(COUNTER_KEY, 0)), + "title": f"Changed: {report[CHANGED_KEY].get(COUNTER_KEY, 0)}", } if len(report[CHANGED_KEY].get(TASKS_KEY, [])) > 0: @@ -212,7 +212,7 @@ def _generate_payload(author_icon, title, report, **kwargs): # Failed failed = { "color": "danger", - "title": "Failed: {}".format(report[FAILED_KEY].get(COUNTER_KEY, None)), + "title": f"Failed: {report[FAILED_KEY].get(COUNTER_KEY, None)}", } if len(report[FAILED_KEY].get(TASKS_KEY, [])) > 0: @@ -319,9 +319,7 @@ def _generate_report(ret, show_tasks): del ret_return[CHANGED_KEY][TASKS_KEY] del ret_return[FAILED_KEY][TASKS_KEY] elif isinstance(ret_return, dict): - ret_return = { - "return": "\n{}".format(salt.utils.yaml.safe_dump(ret_return, indent=2)) - } + ret_return = {"return": f"\n{salt.utils.yaml.safe_dump(ret_return, indent=2)}"} else: ret_return = {"return": ret_return} diff --git a/salt/returners/smtp_return.py b/salt/returners/smtp_return.py index 7e3787d46e8..6c6394861d9 100644 --- a/salt/returners/smtp_return.py +++ b/salt/returners/smtp_return.py @@ -104,7 +104,6 @@ Also you need to create additional file ``/srv/salt/templates/email.j2`` with em This configuration enables Salt Master to send an email when accepting or rejecting minions keys. """ - import io import logging import os @@ -186,7 +185,7 @@ def returner(ret): for field in fields: if field in ret: - subject += " {}".format(ret[field]) + subject += f" {ret[field]}" subject = compile_template( ":string:", rend, renderer, blacklist, whitelist, input_data=subject, **ret ) @@ -214,7 +213,7 @@ def returner(ret): if gpgowner: if HAS_GNUPG: gpg = gnupg.GPG( - gnupghome=os.path.expanduser("~{}/.gnupg".format(gpgowner)), + gnupghome=os.path.expanduser(f"~{gpgowner}/.gnupg"), options=["--trust-model always"], ) encrypted_data = gpg.encrypt(content, to_addrs) diff --git a/salt/returners/zabbix_return.py b/salt/returners/zabbix_return.py index a762c67badf..ac49150f0cd 100644 --- a/salt/returners/zabbix_return.py +++ b/salt/returners/zabbix_return.py @@ -16,7 +16,6 @@ To use the Zabbix returner, append '--return zabbix' to the salt command. ex: salt '*' test.ping --return zabbix """ - import os # Define the module's virtual name diff --git a/salt/roster/__init__.py b/salt/roster/__init__.py index fc7339d785b..a6b8bb2475d 100644 --- a/salt/roster/__init__.py +++ b/salt/roster/__init__.py @@ -45,10 +45,10 @@ def get_roster_file(options): template = os.path.join(salt.syspaths.CONFIG_DIR, "roster") if not os.path.isfile(template): - raise OSError('Roster file "{}" not found'.format(template)) + raise OSError(f'Roster file "{template}" not found') if not os.access(template, os.R_OK): - raise OSError('Access denied to roster "{}"'.format(template)) + raise OSError(f'Access denied to roster "{template}"') return template @@ -80,7 +80,7 @@ class Roster: back = set() if self.backends: for backend in self.backends: - fun = "{}.targets".format(backend) + fun = f"{backend}.targets" if fun in self.rosters: back.add(backend) return back @@ -93,7 +93,7 @@ class Roster: """ targets = {} for back in self._gen_back(): - f_str = "{}.targets".format(back) + f_str = f"{back}.targets" if f_str not in self.rosters: continue try: diff --git a/salt/roster/cache.py b/salt/roster/cache.py index a6a117d2d8e..57f096dde6b 100644 --- a/salt/roster/cache.py +++ b/salt/roster/cache.py @@ -177,7 +177,7 @@ def _load_minion(minion_id, cache): 6: sorted(ipaddress.IPv6Address(addr) for addr in grains.get("ipv6", [])), } - mine = cache.fetch("minions/{}".format(minion_id), "mine") + mine = cache.fetch(f"minions/{minion_id}", "mine") return grains, pillar, addrs, mine @@ -205,9 +205,9 @@ def _minion_lookup(minion_id, key, minion): elif isinstance(key, dict): # Lookup the key in the dict for data_id, lookup in key.items(): - ref = {"pillar": pillar, "grain": grains, "mine": mine}[data_id] + ref = {"pillar": pillar, "grain": grains, "mine": mine} - for k in _data_lookup(ref, lookup): + for k in _data_lookup(ref[data_id], lookup): if k: return k @@ -229,9 +229,9 @@ def _minion_lookup(minion_id, key, minion): else: # Take the addresses from the grains and filter them filters = { - "global": lambda addr: addr.is_global - if addr.version == 6 - else not addr.is_private, + "global": lambda addr: ( + addr.is_global if addr.version == 6 else not addr.is_private + ), "public": lambda addr: not addr.is_private, "private": lambda addr: addr.is_private and not addr.is_loopback @@ -250,6 +250,4 @@ def _minion_lookup(minion_id, key, minion): if filters[key](addr): return str(addr) except KeyError: - raise KeyError( - "Invalid filter {} specified in roster_order".format(key) - ) + raise KeyError(f"Invalid filter {key} specified in roster_order") diff --git a/salt/roster/cloud.py b/salt/roster/cloud.py index 7b9305fbd0c..096329f569d 100644 --- a/salt/roster/cloud.py +++ b/salt/roster/cloud.py @@ -17,7 +17,6 @@ usually located at /etc/salt/cloud. For example, add the following: sudo: True """ - import copy import os diff --git a/salt/roster/clustershell.py b/salt/roster/clustershell.py index 1d07bf4adc4..ea3250117ef 100644 --- a/salt/roster/clustershell.py +++ b/salt/roster/clustershell.py @@ -11,7 +11,6 @@ When you want to use host globs for target matching, use ``--roster clustershell """ - import copy import socket diff --git a/salt/roster/dir.py b/salt/roster/dir.py index b194f192fd0..8ac42a3350b 100644 --- a/salt/roster/dir.py +++ b/salt/roster/dir.py @@ -46,7 +46,6 @@ This makes it possible to avoid having to specify the hostnames when you always their minion id plus some domain. """ - import logging import os @@ -72,7 +71,7 @@ def targets(tgt, tgt_type="glob", **kwargs): for minion_id in matched_raw: target_file = salt.utils.verify.clean_path(roster_dir, minion_id) if not os.path.exists(target_file): - raise CommandExecutionError("{} does not exist".format(target_file)) + raise CommandExecutionError(f"{target_file} does not exist") rendered[minion_id] = _render(target_file, **kwargs) pruned_rendered = {id_: data for id_, data in rendered.items() if data} log.debug( @@ -100,9 +99,9 @@ def _render(roster_file, **kwargs): __opts__["renderer_blacklist"], __opts__["renderer_whitelist"], mask_value="*passw*", - **kwargs + **kwargs, ) - result.setdefault("host", "{}.{}".format(os.path.basename(roster_file), domain)) + result.setdefault("host", f"{os.path.basename(roster_file)}.{domain}") return result except: # pylint: disable=W0702 log.warning('Unable to render roster file "%s".', roster_file, exc_info=True) diff --git a/salt/roster/sshconfig.py b/salt/roster/sshconfig.py index a499fff5860..c4b3bdcb7ae 100644 --- a/salt/roster/sshconfig.py +++ b/salt/roster/sshconfig.py @@ -33,7 +33,7 @@ def _get_ssh_config_file(opts): if not os.path.isfile(ssh_config_file): raise OSError("Cannot find SSH config file") if not os.access(ssh_config_file, os.R_OK): - raise OSError("Cannot access SSH config file: {}".format(ssh_config_file)) + raise OSError(f"Cannot access SSH config file: {ssh_config_file}") return ssh_config_file @@ -117,7 +117,7 @@ class RosterMatcher: Execute the correct tgt_type routine and return """ try: - return getattr(self, "ret_{}_minions".format(self.tgt_type))() + return getattr(self, f"ret_{self.tgt_type}_minions")() except AttributeError: return {} diff --git a/salt/roster/sshknownhosts.py b/salt/roster/sshknownhosts.py index 33ecea925a1..6f895e2e7fa 100644 --- a/salt/roster/sshknownhosts.py +++ b/salt/roster/sshknownhosts.py @@ -36,7 +36,6 @@ Or with a Saltfile """ - import logging import os @@ -98,9 +97,7 @@ def targets(tgt, tgt_type="glob"): raise OSError("Cannot find SSH known_hosts file") if not os.access(ssh_known_hosts_file, os.R_OK): log.error("Cannot access SSH known_hosts file: %s", ssh_known_hosts_file) - raise OSError( - "Cannot access SSH known_hosts file: {}".format(ssh_known_hosts_file) - ) + raise OSError(f"Cannot access SSH known_hosts file: {ssh_known_hosts_file}") with salt.utils.files.fopen(ssh_known_hosts_file, "r") as hostfile: raw = _parse_ssh_known_hosts([line.rstrip() for line in hostfile]) diff --git a/salt/runners/asam.py b/salt/runners/asam.py index 81e547b784b..ca80dcfdf78 100644 --- a/salt/runners/asam.py +++ b/salt/runners/asam.py @@ -226,7 +226,7 @@ def remove_platform(name, server_url): try: html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"]) except Exception as exc: # pylint: disable=broad-except - err_msg = "Failed to look up existing platforms on {}".format(server_url) + err_msg = f"Failed to look up existing platforms on {server_url}" log.error("%s:\n%s", err_msg, exc) return {name: err_msg} @@ -244,18 +244,18 @@ def remove_platform(name, server_url): url, data, auth, verify=config["verify_ssl"] ) except Exception as exc: # pylint: disable=broad-except - err_msg = "Failed to delete platform from {}".format(server_url) + err_msg = f"Failed to delete platform from {server_url}" log.error("%s:\n%s", err_msg, exc) return {name: err_msg} parser = _parse_html_content(html_content) platformset_name = _get_platformset_name(parser.data, name) if platformset_name: - return {name: "Failed to delete platform from {}".format(server_url)} + return {name: f"Failed to delete platform from {server_url}"} else: - return {name: "Successfully deleted platform from {}".format(server_url)} + return {name: f"Successfully deleted platform from {server_url}"} else: - return {name: "Specified platform name does not exist on {}".format(server_url)} + return {name: f"Specified platform name does not exist on {server_url}"} def list_platforms(server_url): @@ -351,11 +351,11 @@ def add_platform(name, platform_set, server_url): platforms = list_platforms(server_url) if name in platforms[server_url]: - return {name: "Specified platform already exists on {}".format(server_url)} + return {name: f"Specified platform already exists on {server_url}"} platform_sets = list_platform_sets(server_url) if platform_set not in platform_sets[server_url]: - return {name: "Specified platform set does not exist on {}".format(server_url)} + return {name: f"Specified platform set does not exist on {server_url}"} url = config["platform_edit_url"] @@ -373,12 +373,12 @@ def add_platform(name, platform_set, server_url): try: html_content = _make_post_request(url, data, auth, verify=config["verify_ssl"]) except Exception as exc: # pylint: disable=broad-except - err_msg = "Failed to add platform on {}".format(server_url) + err_msg = f"Failed to add platform on {server_url}" log.error("%s:\n%s", err_msg, exc) return {name: err_msg} platforms = list_platforms(server_url) if name in platforms[server_url]: - return {name: "Successfully added platform on {}".format(server_url)} + return {name: f"Successfully added platform on {server_url}"} else: - return {name: "Failed to add platform on {}".format(server_url)} + return {name: f"Failed to add platform on {server_url}"} diff --git a/salt/runners/auth.py b/salt/runners/auth.py index 7485ef55a44..91f20c52e38 100644 --- a/salt/runners/auth.py +++ b/salt/runners/auth.py @@ -5,7 +5,6 @@ Authentication runner for creating, deleting, and managing eauth tokens. """ - import os import salt.auth diff --git a/salt/runners/bgp.py b/salt/runners/bgp.py index 4603de029af..bee6d4698ea 100644 --- a/salt/runners/bgp.py +++ b/salt/runners/bgp.py @@ -331,9 +331,7 @@ def neighbors(*asns, **kwargs): ) ) if ipnet: - title_parts.append( - "Selecting neighbors within the IP network: {ipnet}".format(ipnet=ipnet) - ) + title_parts.append(f"Selecting neighbors within the IP network: {ipnet}") if kwargs: title_parts.append( "Searching for BGP neighbors having the attributes: {attrmap}".format( diff --git a/salt/runners/cache.py b/salt/runners/cache.py index 88a5c6be0db..89309af690f 100644 --- a/salt/runners/cache.py +++ b/salt/runners/cache.py @@ -327,7 +327,7 @@ def clear_git_lock(role, remote=None, **kwargs): ) git_objects.append(obj) else: - raise SaltInvocationError("Invalid role '{}'".format(role)) + raise SaltInvocationError(f"Invalid role '{role}'") ret = {} for obj in git_objects: diff --git a/salt/runners/ddns.py b/salt/runners/ddns.py index 9e4d5c64971..831f5211627 100644 --- a/salt/runners/ddns.py +++ b/salt/runners/ddns.py @@ -75,7 +75,7 @@ def create( """ if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) @@ -99,9 +99,9 @@ def create( answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: - return {fqdn: "Failed to create record of type '{}'".format(rdtype)} + return {fqdn: f"Failed to create record of type '{rdtype}'"} - return {fqdn: "Created record of type '{}': {} -> {}".format(rdtype, fqdn, data)} + return {fqdn: f"Created record of type '{rdtype}': {fqdn} -> {data}"} def update( @@ -135,7 +135,7 @@ def update( """ if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, rdtype) answer = dns.query.udp(request, nameserver, timeout, port) if not answer.answer: @@ -166,9 +166,9 @@ def update( answer = dns.query.udp(dns_update, nameserver, timeout, port) if answer.rcode() > 0: - return {fqdn: "Failed to update record of type '{}'".format(rdtype)} + return {fqdn: f"Failed to update record of type '{rdtype}'"} - return {fqdn: "Updated record of type '{}'".format(rdtype)} + return {fqdn: f"Updated record of type '{rdtype}'"} def delete( @@ -194,7 +194,7 @@ def delete( """ if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, (rdtype or "ANY")) answer = dns.query.udp(request, nameserver, timeout, port) @@ -248,7 +248,7 @@ def add_host( res = [] if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" ret = create( zone, @@ -277,13 +277,13 @@ def add_host( zone = "{}.{}".format(".".join(parts), "in-addr.arpa.") name = ".".join(popped) - rev_fqdn = "{}.{}".format(name, zone) + rev_fqdn = f"{name}.{zone}" ret = create( zone, name, ttl, "PTR", - "{}.".format(fqdn), + f"{fqdn}.", keyname, keyfile, nameserver, @@ -317,7 +317,7 @@ def delete_host( res = [] if zone in name: name = name.replace(zone, "").rstrip(".") - fqdn = "{}.{}".format(name, zone) + fqdn = f"{name}.{zone}" request = dns.message.make_query(fqdn, "A") answer = dns.query.udp(request, nameserver, timeout, port) @@ -336,7 +336,7 @@ def delete_host( port=port, keyalgorithm=keyalgorithm, ) - res.append("{} of type 'A'".format(ret[fqdn])) + res.append(f"{ret[fqdn]} of type 'A'") for ip in ips: parts = ip.split(".")[::-1] @@ -350,7 +350,7 @@ def delete_host( popped.append(p) zone = "{}.{}".format(".".join(parts), "in-addr.arpa.") name = ".".join(popped) - rev_fqdn = "{}.{}".format(name, zone) + rev_fqdn = f"{name}.{zone}" ret = delete( zone, name, @@ -359,13 +359,13 @@ def delete_host( nameserver, timeout, "PTR", - "{}.".format(fqdn), + f"{fqdn}.", port, keyalgorithm, ) if "Deleted" in ret[rev_fqdn]: - res.append("{} of type 'PTR'".format(ret[rev_fqdn])) + res.append(f"{ret[rev_fqdn]} of type 'PTR'") return {fqdn: res} res.append(ret[rev_fqdn]) diff --git a/salt/runners/digicertapi.py b/salt/runners/digicertapi.py index 76db62ed61f..a7450d7b8ad 100644 --- a/salt/runners/digicertapi.py +++ b/salt/runners/digicertapi.py @@ -34,6 +34,7 @@ This API currently only supports RSA key types. Support for other key types wil if interest warrants. """ + import logging import os import re @@ -112,7 +113,7 @@ def _paginate(url, topkey, *args, **kwargs): aggregate_ret = ret["dict"][topkey] url = args[0] for p in range(2, numpages): - param_url = url + "?offset={}".format(lim * (p - 1)) + param_url = url + f"?offset={lim * (p - 1)}" next_ret = salt.utils.http.query(param_url, kwargs) aggregate_ret[topkey].extend(next_ret["dict"][topkey]) @@ -131,9 +132,9 @@ def list_domains(container_id=None): salt-run digicert.list_domains """ if container_id: - url = "{}/domain?{}".format(_base_url(), container_id) + url = f"{_base_url()}/domain?{container_id}" else: - url = "{}/domain".format(_base_url()) + url = f"{_base_url()}/domain" orgs = _paginate( url, @@ -160,9 +161,9 @@ def list_requests(status=None): salt-run digicert.list_requests pending """ if status: - url = "{}/request?status={}".format(_base_url(), status) + url = f"{_base_url()}/request?status={status}" else: - url = "{}/request".format(_base_url()) + url = f"{_base_url()}/request" reqs = _paginate( url, @@ -188,7 +189,7 @@ def list_orders(status=None): salt-run digicert.list_orders """ - url = "{}/order/certificate".format(_base_url()) + url = f"{_base_url()}/order/certificate" reqs = _paginate( url, @@ -238,7 +239,7 @@ def get_certificate( if order_id: order_cert = salt.utils.http.query( - "{}/order/certificate/{}".format(_base_url(), order_id), + f"{_base_url()}/order/certificate/{order_id}", method="GET", raise_error=False, decode=True, @@ -372,7 +373,7 @@ def list_organizations(container_id=None, include_validation=True): """ orgs = _paginate( - "{}/organization".format(_base_url()), + f"{_base_url()}/organization", "organizations", method="GET", decode=True, @@ -495,7 +496,7 @@ def order_certificate( encoded_body = salt.utils.json.dumps(body) qdata = salt.utils.http.query( - "{}/order/certificate/ssl".format(_base_url()), + f"{_base_url()}/order/certificate/ssl", method="POST", data=encoded_body, decode=True, @@ -571,7 +572,7 @@ def get_org_details(organization_id): """ qdata = salt.utils.http.query( - "{}/organization/{}".format(_base_url(), organization_id), + f"{_base_url()}/organization/{organization_id}", method="GET", decode=True, decode_type="json", @@ -623,8 +624,8 @@ def gen_csr( if "private_key" not in data: data["private_key"] = gen_key(minion_id, dns_name, password, key_len=key_len) - tmppriv = "{}/priv".format(tmpdir) - tmpcsr = "{}/csr".format(tmpdir) + tmppriv = f"{tmpdir}/priv" + tmpcsr = f"{tmpdir}/csr" with salt.utils.files.fopen(tmppriv, "w") as if_: if_.write(salt.utils.stringutils.to_str(data["private_key"])) @@ -636,9 +637,9 @@ def gen_csr( ) if ou_name: - subject = subject + "/OU={}".format(ou_name) + subject = subject + f"/OU={ou_name}" - subject = subject + "/CN={}".format(dns_name) + subject = subject + f"/CN={dns_name}" cmd = "openssl req -new -{} -key {} -out {} -subj '{}'".format( shatype, tmppriv, tmpcsr, subject @@ -689,7 +690,7 @@ def show_organization(domain): salt-run digicert.show_company example.com """ data = salt.utils.http.query( - "{}/companies/domain/{}".format(_base_url(), domain), + f"{_base_url()}/companies/domain/{domain}", status=True, decode=True, decode_type="json", @@ -712,7 +713,7 @@ def show_csrs(): salt-run digicert.show_csrs """ data = salt.utils.http.query( - "{}/certificaterequests".format(_base_url()), + f"{_base_url()}/certificaterequests", status=True, decode=True, decode_type="json", diff --git a/salt/runners/drac.py b/salt/runners/drac.py index f5e9d39ed7d..0a377c6d808 100644 --- a/salt/runners/drac.py +++ b/salt/runners/drac.py @@ -12,7 +12,6 @@ configuration file. """ - import logging try: @@ -58,7 +57,7 @@ def __connect(hostname, timeout=20, username=None, password=None): password = drac_cred.get("password", None) client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # nosec try: client.connect(hostname, username=username, password=password, timeout=timeout) diff --git a/salt/runners/f5.py b/salt/runners/f5.py index bac50c00cd9..13f33f31a1d 100644 --- a/salt/runners/f5.py +++ b/salt/runners/f5.py @@ -53,7 +53,7 @@ class F5Mgmt: wsdls=["LocalLB.VirtualServer", "LocalLB.Pool"], ) except Exception: # pylint: disable=broad-except - raise Exception("Unable to connect to {}".format(self.lb)) + raise Exception(f"Unable to connect to {self.lb}") return True @@ -123,9 +123,7 @@ class F5Mgmt: profiles=[vs_profile_seq], ) except Exception as e: # pylint: disable=broad-except - raise Exception( - "Unable to create `{}` virtual server\n\n{}".format(name, e) - ) + raise Exception(f"Unable to create `{name}` virtual server\n\n{e}") return True def create_pool(self, name, method="ROUND_ROBIN"): @@ -144,7 +142,7 @@ class F5Mgmt: pool_names=[name], lb_methods=[supported_method], members=[[]] ) except Exception as e: # pylint: disable=broad-except - raise Exception("Unable to create `{}` pool\n\n{}".format(name, e)) + raise Exception(f"Unable to create `{name}` pool\n\n{e}") else: raise Exception("Unsupported method") return True @@ -154,7 +152,7 @@ class F5Mgmt: Add a node to a pool """ if not self.check_pool(pool_name): - raise CommandExecutionError("{} pool does not exists".format(pool_name)) + raise CommandExecutionError(f"{pool_name} pool does not exists") members_seq = self.bigIP.LocalLB.Pool.typefactory.create( "Common.IPPortDefinitionSequence" @@ -173,9 +171,7 @@ class F5Mgmt: pool_names=[pool_name], members=[members_seq] ) except Exception as e: # pylint: disable=broad-except - raise Exception( - "Unable to add `{}` to `{}`\n\n{}".format(name, pool_name, e) - ) + raise Exception(f"Unable to add `{name}` to `{pool_name}`\n\n{e}") return True def check_pool(self, name): @@ -229,7 +225,7 @@ def create_vs(lb, name, ip, port, protocol, profile, pool_name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) F5.create_vs(name, ip, port, protocol, profile, pool_name) @@ -250,7 +246,7 @@ def create_pool(lb, name, method="ROUND_ROBIN"): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) F5.create_pool(name, method) return True @@ -269,7 +265,7 @@ def add_pool_member(lb, name, port, pool_name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) F5.add_pool_member(name, port, pool_name) return True @@ -288,7 +284,7 @@ def check_pool(lb, name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) return F5.check_pool(name) @@ -306,7 +302,7 @@ def check_virtualserver(lb, name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) return F5.check_virtualserver(name) @@ -324,6 +320,6 @@ def check_member_pool(lb, member, pool_name): if __opts__["load_balancers"].get(lb, None): (username, password) = list(__opts__["load_balancers"][lb].values()) else: - raise Exception("Unable to find `{}` load balancer".format(lb)) + raise Exception(f"Unable to find `{lb}` load balancer") F5 = F5Mgmt(lb, username, password) return F5.check_member_pool(member, pool_name) diff --git a/salt/runners/jobs.py b/salt/runners/jobs.py index 1d958b87a9b..f1ff0f8b492 100644 --- a/salt/runners/jobs.py +++ b/salt/runners/jobs.py @@ -70,7 +70,7 @@ def active(display_progress=False): for minion, data in active_.items(): if display_progress: __jid_event__.fire_event( - {"message": "Received reply from minion {}".format(minion)}, "progress" + {"message": f"Received reply from minion {minion}"}, "progress" ) if not isinstance(data, list): continue @@ -88,7 +88,7 @@ def active(display_progress=False): returner = _get_returner( (__opts__["ext_job_cache"], __opts__["master_job_cache"]) ) - data = mminion.returners["{}.get_jid".format(returner)](jid) + data = mminion.returners[f"{returner}.get_jid"](jid) if data: for minion in data: if minion not in ret[jid]["Returned"]: @@ -199,12 +199,12 @@ def list_job(jid, ext_source=None, display_progress=False): ) if display_progress: __jid_event__.fire_event( - {"message": "Querying returner: {}".format(returner)}, "progress" + {"message": f"Querying returner: {returner}"}, "progress" ) - job = mminion.returners["{}.get_load".format(returner)](jid) + job = mminion.returners[f"{returner}.get_load"](jid) ret.update(_format_jid_instance(jid, job)) - ret["Result"] = mminion.returners["{}.get_jid".format(returner)](jid) + ret["Result"] = mminion.returners[f"{returner}.get_jid"](jid) fstr = "{}.get_endtime".format(__opts__["master_job_cache"]) if __opts__.get("job_cache_store_endtime") and fstr in mminion.returners: @@ -306,11 +306,11 @@ def list_jobs( ) if display_progress: __jid_event__.fire_event( - {"message": "Querying returner {} for jobs.".format(returner)}, "progress" + {"message": f"Querying returner {returner} for jobs."}, "progress" ) mminion = salt.minion.MasterMinion(__opts__) - ret = mminion.returners["{}.get_jids".format(returner)]() + ret = mminion.returners[f"{returner}.get_jids"]() mret = {} for item in ret: @@ -401,15 +401,13 @@ def list_jobs_filter( ) if display_progress: __jid_event__.fire_event( - {"message": "Querying returner {} for jobs.".format(returner)}, "progress" + {"message": f"Querying returner {returner} for jobs."}, "progress" ) mminion = salt.minion.MasterMinion(__opts__) - fun = "{}.get_jids_filter".format(returner) + fun = f"{returner}.get_jids_filter" if fun not in mminion.returners: - raise NotImplementedError( - "'{}' returner function not implemented yet.".format(fun) - ) + raise NotImplementedError(f"'{fun}' returner function not implemented yet.") ret = mminion.returners[fun](count, filter_find_job) if outputter: @@ -436,7 +434,7 @@ def print_job(jid, ext_source=None): mminion = salt.minion.MasterMinion(__opts__) try: - job = mminion.returners["{}.get_load".format(returner)](jid) + job = mminion.returners[f"{returner}.get_load"](jid) ret[jid] = _format_jid_instance(jid, job) except TypeError: ret[jid]["Result"] = ( @@ -444,7 +442,7 @@ def print_job(jid, ext_source=None): "retrieved. Check master log for details.".format(returner) ) return ret - ret[jid]["Result"] = mminion.returners["{}.get_jid".format(returner)](jid) + ret[jid]["Result"] = mminion.returners[f"{returner}.get_jid"](jid) fstr = "{}.get_endtime".format(__opts__["master_job_cache"]) if __opts__.get("job_cache_store_endtime") and fstr in mminion.returners: @@ -598,7 +596,5 @@ def _walk_through(job_dir, display_progress=False): job = salt.payload.load(rfh) jid = job["jid"] if display_progress: - __jid_event__.fire_event( - {"message": "Found JID {}".format(jid)}, "progress" - ) + __jid_event__.fire_event({"message": f"Found JID {jid}"}, "progress") yield jid, job, t_path, final diff --git a/salt/runners/launchd.py b/salt/runners/launchd.py index ce9be4e3a9c..cbbd22ae6ec 100644 --- a/salt/runners/launchd.py +++ b/salt/runners/launchd.py @@ -48,7 +48,7 @@ def write_launchd_plist(program): supported_programs = ["salt-master", "salt-minion"] if program not in supported_programs: - sys.stderr.write("Supported programs: '{}'\n".format(supported_programs)) + sys.stderr.write(f"Supported programs: '{supported_programs}'\n") sys.exit(-1) return plist_sample_text.format( diff --git a/salt/runners/lxc.py b/salt/runners/lxc.py index 0ded584f427..c12826f4162 100644 --- a/salt/runners/lxc.py +++ b/salt/runners/lxc.py @@ -4,7 +4,6 @@ Control Linux Containers via Salt :depends: lxc execution module """ - import copy import logging import os @@ -41,7 +40,7 @@ def _do(name, fun, path=None): with salt.client.get_local_client(__opts__["conf_file"]) as client: cmd_ret = client.cmd_iter( - host, "lxc.{}".format(fun), [name], kwarg={"path": path}, timeout=60 + host, f"lxc.{fun}", [name], kwarg={"path": path}, timeout=60 ) data = next(cmd_ret) data = data.get(host, {}).get("ret", None) @@ -72,7 +71,7 @@ def _do_names(names, fun, path=None): cmds.append( client.cmd_iter( host, - "lxc.{}".format(fun), + f"lxc.{fun}", [name], kwarg={"path": path}, timeout=60, @@ -248,7 +247,7 @@ def init(names, host=None, saltcloud_mode=False, quiet=False, **kwargs): except (TypeError, KeyError): pass if not alive: - ret["comment"] = "Host {} is not reachable".format(host) + ret["comment"] = f"Host {host} is not reachable" ret["result"] = False return ret @@ -264,7 +263,7 @@ def init(names, host=None, saltcloud_mode=False, quiet=False, **kwargs): host, ) if host not in data: - ret["comment"] = "Host '{}' was not found".format(host) + ret["comment"] = f"Host '{host}' was not found" ret["result"] = False return ret @@ -391,7 +390,7 @@ def init(names, host=None, saltcloud_mode=False, quiet=False, **kwargs): time.sleep(1) if ping: return "OK" - raise Exception("Unresponsive {}".format(mid_)) + raise Exception(f"Unresponsive {mid_}") ping = salt.utils.cloud.wait_for_fun(testping, timeout=21, mid=mid) if ping != "OK": diff --git a/salt/runners/manage.py b/salt/runners/manage.py index b15573ed168..43f76e1d529 100644 --- a/salt/runners/manage.py +++ b/salt/runners/manage.py @@ -3,7 +3,6 @@ General management functions for salt, tools like seeing what hosts are up and what hosts are down """ - import logging import operator import os @@ -134,7 +133,7 @@ def key_regen(): path = os.path.join(root, fn_) try: os.remove(path) - except os.error: + except OSError: pass msg = ( "The minion and master keys have been deleted. Restart the Salt\n" @@ -540,10 +539,10 @@ def safe_accept(target, tgt_type="glob"): elif minion not in pending: failures[minion] = f"Minion key {minion} not found by salt-key" elif pending[minion] != finger: - failures[ - minion - ] = "Minion key {} does not match the key in salt-key: {}".format( - finger, pending[minion] + failures[minion] = ( + "Minion key {} does not match the key in salt-key: {}".format( + finger, pending[minion] + ) ) else: subprocess.call(["salt-key", "-qya", minion]) diff --git a/salt/runners/match.py b/salt/runners/match.py index 0133d3a2343..1dea4186560 100644 --- a/salt/runners/match.py +++ b/salt/runners/match.py @@ -3,6 +3,7 @@ Run matchers from the master context. .. versionadded:: 3007.0 """ + import logging import salt.utils.minions diff --git a/salt/runners/mattermost.py b/salt/runners/mattermost.py index 40309f62160..828ff857939 100644 --- a/salt/runners/mattermost.py +++ b/salt/runners/mattermost.py @@ -14,7 +14,6 @@ Module for sending messages to Mattermost api_url: https://example.com """ - import logging import salt.utils.json @@ -130,7 +129,7 @@ def post_message(message, channel=None, username=None, api_url=None, hook=None): log.debug("Parameters: %s", parameters) data = salt.utils.json.dumps(parameters) result = salt.utils.mattermost.query( - api_url=api_url, hook=hook, data="payload={}".format(data) + api_url=api_url, hook=hook, data=f"payload={data}" ) if result: @@ -168,7 +167,7 @@ def post_event(event, channel=None, username=None, api_url=None, hook=None): log.debug("Event data: %s", event["data"]) message = "tag: {}\r\n".format(event["tag"]) for key, value in event["data"].items(): - message += "{}: {}\r\n".format(key, value) + message += f"{key}: {value}\r\n" result = post_message( message, channel=channel, username=username, api_url=api_url, hook=hook ) diff --git a/salt/runners/nacl.py b/salt/runners/nacl.py index 3c097604bad..62b89444723 100644 --- a/salt/runners/nacl.py +++ b/salt/runners/nacl.py @@ -111,7 +111,6 @@ Larger files like certificates can be encrypted with: """ - import salt.utils.nacl __virtualname__ = "nacl" diff --git a/salt/runners/net.py b/salt/runners/net.py index a7865219b62..f330c0ba924 100644 --- a/salt/runners/net.py +++ b/salt/runners/net.py @@ -347,13 +347,13 @@ def interfaces( if not title: title = "Details" if interface: - title += " for interface {}".format(interface) + title += f" for interface {interface}" else: title += " for all interfaces" if device: - title += " on device {}".format(device) + title += f" on device {device}" if ipnet: - title += " that include network {net}".format(net=str(ipnet)) + title += f" that include network {str(ipnet)}" if best: title += " - only best match returned" @@ -511,13 +511,13 @@ def findarp( title = "ARP Entries" if device: - title += " on device {device}".format(device=device) + title += f" on device {device}" if interface: - title += " on interface {interf}".format(interf=interface) + title += f" on interface {interface}" if ip: - title += " for IP {ip}".format(ip=ip) + title += f" for IP {ip}" if mac: - title += " for MAC {mac}".format(mac=mac) + title += f" for MAC {mac}" if device: all_arp = {device: all_arp.get(device)} @@ -615,11 +615,11 @@ def findmac(device=None, mac=None, interface=None, vlan=None, display=_DEFAULT_D title = "MAC Address(es)" if device: - title += " on device {device}".format(device=device) + title += f" on device {device}" if interface: - title += " on interface {interf}".format(interf=interface) + title += f" on interface {interface}" if vlan: - title += " on VLAN {vlan}".format(vlan=vlan) + title += f" on VLAN {vlan}" if device: all_mac = {device: all_mac.get(device)} @@ -752,13 +752,13 @@ def lldp( if not title: title = "LLDP Neighbors" if interface: - title += " for interface {}".format(interface) + title += f" for interface {interface}" else: title += " for all interfaces" if device: - title += " on device {}".format(device) + title += f" on device {device}" if chassis: - title += " having Chassis ID {}".format(chassis) + title += f" having Chassis ID {chassis}" if device: all_lldp = {device: all_lldp.get(device)} diff --git a/salt/runners/network.py b/salt/runners/network.py index 1a56da20f17..2bf46e80a98 100644 --- a/salt/runners/network.py +++ b/salt/runners/network.py @@ -2,7 +2,6 @@ Network tools to run from the Master """ - import logging import socket @@ -32,11 +31,11 @@ def wollist(maclist, bcast="255.255.255.255", destport=9): for mac in ifile: mac = salt.utils.stringutils.to_unicode(mac).strip() wol(mac, bcast, destport) - print("Waking up {}".format(mac)) + print(f"Waking up {mac}") ret.append(mac) except Exception as err: # pylint: disable=broad-except __jid_event__.fire_event( - {"error": "Failed to open the MAC file. Error: {}".format(err)}, "progress" + {"error": f"Failed to open the MAC file. Error: {err}"}, "progress" ) return [] return ret diff --git a/salt/runners/pkg.py b/salt/runners/pkg.py index 6a4a06e6109..7d36caf2998 100644 --- a/salt/runners/pkg.py +++ b/salt/runners/pkg.py @@ -4,7 +4,6 @@ Package helper functions using ``salt.modules.pkg`` .. versionadded:: 2015.8.0 """ - import salt.minion import salt.output @@ -33,7 +32,7 @@ def list_upgrades(jid, style="group", outputter="nested", ext_source=None): (__opts__["ext_job_cache"], ext_source, __opts__["master_job_cache"]) ) - data = mminion.returners["{}.get_jid".format(returner)](jid) + data = mminion.returners[f"{returner}.get_jid"](jid) pkgs = {} if style == "group": diff --git a/salt/runners/queue.py b/salt/runners/queue.py index 286ebebcbff..d91418355c3 100644 --- a/salt/runners/queue.py +++ b/salt/runners/queue.py @@ -61,7 +61,6 @@ run them. And it will do this every minute, unless there are any jobs that are still running from the last time the process_runner task was executed. """ - import salt.loader from salt.exceptions import SaltInvocationError from salt.utils.event import get_event, tagify @@ -81,9 +80,9 @@ def insert(queue, items, backend="sqlite"): salt-run queue.insert myqueue "['item1', 'item2', 'item3']" backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.insert".format(backend) + cmd = f"{backend}.insert" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](items=items, queue=queue) return ret @@ -101,9 +100,9 @@ def delete(queue, items, backend="sqlite"): salt-run queue.delete myqueue "['item1', 'item2', 'item3']" """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.delete".format(backend) + cmd = f"{backend}.delete" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](items=items, queue=queue) return ret @@ -120,9 +119,9 @@ def list_queues(backend="sqlite"): salt-run queue.list_queues backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.list_queues".format(backend) + cmd = f"{backend}.list_queues" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd]() return ret @@ -139,9 +138,9 @@ def list_length(queue, backend="sqlite"): salt-run queue.list_length myqueue backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.list_length".format(backend) + cmd = f"{backend}.list_length" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](queue=queue) return ret @@ -158,9 +157,9 @@ def list_items(queue, backend="sqlite"): salt-run queue.list_items myqueue backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.list_items".format(backend) + cmd = f"{backend}.list_items" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](queue=queue) return ret @@ -180,9 +179,9 @@ def pop(queue, quantity=1, backend="sqlite", is_runner=False): salt-run queue.pop myqueue all backend=sqlite """ queue_funcs = salt.loader.queues(__opts__) - cmd = "{}.pop".format(backend) + cmd = f"{backend}.pop" if cmd not in queue_funcs: - raise SaltInvocationError('Function "{}" is not available'.format(cmd)) + raise SaltInvocationError(f'Function "{cmd}" is not available') ret = queue_funcs[cmd](quantity=quantity, queue=queue, is_runner=is_runner) return ret @@ -212,7 +211,7 @@ def process_queue(queue, quantity=1, backend="sqlite", is_runner=False): queue=queue, quantity=quantity, backend=backend, is_runner=is_runner ) except SaltInvocationError as exc: - error_txt = "{}".format(exc) + error_txt = f"{exc}" __jid_event__.fire_event({"errors": error_txt}, "progress") return False diff --git a/salt/runners/salt.py b/salt/runners/salt.py index 50fac6ab4a7..3ac499ae579 100644 --- a/salt/runners/salt.py +++ b/salt/runners/salt.py @@ -102,7 +102,7 @@ def cmd(fun, *args, **kwargs): return ( functions[fun](*args, **kwargs) if fun in functions - else "'{}' is not available.".format(fun) + else f"'{fun}' is not available." ) @@ -115,7 +115,7 @@ def execute( ret="", jid="", kwarg=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2017.7.0 @@ -159,7 +159,7 @@ def execute( ret=ret, jid=jid, kwarg=kwarg, - **kwargs + **kwargs, ) except SaltClientError as client_error: log.error("Error while executing %s on %s (%s)", fun, tgt, tgt_type) diff --git a/salt/runners/spacewalk.py b/salt/runners/spacewalk.py index 638e338b496..4936859b16b 100644 --- a/salt/runners/spacewalk.py +++ b/salt/runners/spacewalk.py @@ -31,7 +31,7 @@ master configuration at ``/etc/salt/master`` or ``/etc/salt/master.d/spacewalk.c import atexit import logging -import xmlrpc.client +import xmlrpc.client # nosec log = logging.getLogger(__name__) @@ -71,7 +71,7 @@ def _get_spacewalk_configuration(spacewalk_url=""): return False ret = { - "api_url": "{}://{}/rpc/api".format(protocol, spacewalk_server), + "api_url": f"{protocol}://{spacewalk_server}/rpc/api", "username": username, "password": password, } @@ -120,7 +120,7 @@ def _get_session(server): config = _get_spacewalk_configuration(server) if not config: - raise Exception("No config for '{}' found on master".format(server)) + raise Exception(f"No config for '{server}' found on master") session = _get_client_and_key( config["api_url"], config["username"], config["password"] @@ -163,7 +163,7 @@ def api(server, command, *args, **kwargs): else: arguments = args - call = "{} {}".format(command, arguments) + call = f"{command} {arguments}" try: client, key = _get_session(server) except Exception as exc: # pylint: disable=broad-except @@ -185,7 +185,7 @@ def api(server, command, *args, **kwargs): try: output = endpoint(key, *arguments) except Exception as e: # pylint: disable=broad-except - output = "API call failed: {}".format(e) + output = f"API call failed: {e}" return {call: output} @@ -360,10 +360,8 @@ def unregister(name, server_url): for system in systems_list: out = client.system.deleteSystem(key, system["id"]) if out == 1: - return {name: "Successfully unregistered from {}".format(server_url)} + return {name: f"Successfully unregistered from {server_url}"} else: - return {name: "Failed to unregister from {}".format(server_url)} + return {name: f"Failed to unregister from {server_url}"} else: - return { - name: "System does not exist in spacewalk server ({})".format(server_url) - } + return {name: f"System does not exist in spacewalk server ({server_url})"} diff --git a/salt/runners/ssh.py b/salt/runners/ssh.py index 90ac4cfc02d..6a6086d21c1 100644 --- a/salt/runners/ssh.py +++ b/salt/runners/ssh.py @@ -4,7 +4,6 @@ A Runner module interface on top of the salt-ssh Python API. This allows for programmatic use from salt-api, the Reactor, Orchestrate, etc. """ - import salt.client.ssh.client diff --git a/salt/runners/test.py b/salt/runners/test.py index 98df7fd4e11..b20e27c847c 100644 --- a/salt/runners/test.py +++ b/salt/runners/test.py @@ -116,9 +116,7 @@ def stream(): """ ret = True for i in range(1, 100): - __jid_event__.fire_event( - {"message": "Runner is {}% done".format(i)}, "progress" - ) + __jid_event__.fire_event({"message": f"Runner is {i}% done"}, "progress") time.sleep(0.1) return ret diff --git a/salt/runners/thin.py b/salt/runners/thin.py index 83698cf6eb2..346c9ce68b0 100644 --- a/salt/runners/thin.py +++ b/salt/runners/thin.py @@ -6,7 +6,6 @@ in a standalone way. This runner has tools which generate the standalone salt system for easy consumption. """ - import salt.utils.thin diff --git a/salt/runners/venafiapi.py b/salt/runners/venafiapi.py index 23118ee8f7a..e5794f906dd 100644 --- a/salt/runners/venafiapi.py +++ b/salt/runners/venafiapi.py @@ -138,9 +138,7 @@ def request( csr = csr_file.read() request = CertificateRequest(csr=csr, common_name=dns_name) except Exception as e: - raise Exception( - "Unable to open file {file}: {excp}".format(file=csr_path, excp=e) - ) + raise Exception(f"Unable to open file {csr_path}: {e}") conn.request_cert(request, zone) # TODO: add timeout parameter here @@ -160,9 +158,7 @@ def request( with salt.utils.files.fopen(pkey_path) as pkey_file: private_key = pkey_file.read() except Exception as e: - raise Exception( - "Unable to open file {file}: {excp}".format(file=pkey_path, excp=e) - ) + raise Exception(f"Unable to open file {pkey_path}: {e}") else: private_key = None diff --git a/salt/runners/virt.py b/salt/runners/virt.py index 71e665b4c50..669ded40137 100644 --- a/salt/runners/virt.py +++ b/salt/runners/virt.py @@ -2,7 +2,6 @@ Control virtual machines via Salt """ - import logging import os.path @@ -247,7 +246,7 @@ def init( if "vm_info" in data[node]: if name in data[node]["vm_info"]: __jid_event__.fire_event( - {"message": "Virtual machine {} is already deployed".format(name)}, + {"message": f"Virtual machine {name} is already deployed"}, "progress", ) return "fail" @@ -256,9 +255,7 @@ def init( host = _determine_host(data) if host not in data or not host: - __jid_event__.fire_event( - {"message": "Host {} was not found".format(host)}, "progress" - ) + __jid_event__.fire_event({"message": f"Host {host} was not found"}, "progress") return "fail" pub_key = None @@ -273,7 +270,7 @@ def init( with salt.client.get_local_client(__opts__["conf_file"]) as client: __jid_event__.fire_event( - {"message": "Creating VM {} on host {}".format(name, host)}, "progress" + {"message": f"Creating VM {name} on host {host}"}, "progress" ) try: cmd_ret = client.cmd_iter( @@ -305,7 +302,7 @@ def init( ret = next(cmd_ret) if not ret: __jid_event__.fire_event( - {"message": "VM {} was not initialized.".format(name)}, "progress" + {"message": f"VM {name} was not initialized."}, "progress" ) return "fail" for minion_id in ret: @@ -318,7 +315,7 @@ def init( return "fail" __jid_event__.fire_event( - {"message": "VM {} initialized on host {}".format(name, host)}, "progress" + {"message": f"VM {name} initialized on host {host}"}, "progress" ) return "good" @@ -340,7 +337,7 @@ def reset(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"message": "Failed to find VM {} to reset".format(name)}, "progress" + {"message": f"Failed to find VM {name} to reset"}, "progress" ) return "fail" host = next(iter(data.keys())) @@ -348,9 +345,7 @@ def reset(name): cmd_ret = client.cmd_iter(host, "virt.reset", [name], timeout=600) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event( - {"message": "Reset VM {}".format(name)}, "progress" - ) + __jid_event__.fire_event({"message": f"Reset VM {name}"}, "progress") except SaltClientError as client_error: print(client_error) return ret @@ -365,20 +360,20 @@ def start(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"message": "Failed to find VM {} to start".format(name)}, "progress" + {"message": f"Failed to find VM {name} to start"}, "progress" ) return "fail" host = next(iter(data.keys())) if data[host][name]["state"] == "running": - print("VM {} is already running".format(name)) + print(f"VM {name} is already running") return "bad state" try: cmd_ret = client.cmd_iter(host, "virt.start", [name], timeout=600) except SaltClientError as client_error: - return "Virtual machine {} not started: {}".format(name, client_error) + return f"Virtual machine {name} not started: {client_error}" for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event({"message": "Started VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Started VM {name}"}, "progress") return "good" @@ -390,11 +385,11 @@ def force_off(name): with salt.client.get_local_client(__opts__["conf_file"]) as client: data = vm_info(name, quiet=True) if not data: - print("Failed to find VM {} to destroy".format(name)) + print(f"Failed to find VM {name} to destroy") return "fail" host = next(iter(data.keys())) if data[host][name]["state"] == "shutdown": - print("VM {} is already shutdown".format(name)) + print(f"VM {name} is already shutdown") return "bad state" try: cmd_ret = client.cmd_iter(host, "virt.stop", [name], timeout=600) @@ -404,9 +399,7 @@ def force_off(name): ) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event( - {"message": "Powered off VM {}".format(name)}, "progress" - ) + __jid_event__.fire_event({"message": f"Powered off VM {name}"}, "progress") return "good" @@ -419,7 +412,7 @@ def purge(name, delete_key=True): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"error": "Failed to find VM {} to purge".format(name)}, "progress" + {"error": f"Failed to find VM {name} to purge"}, "progress" ) return "fail" host = next(iter(data.keys())) @@ -437,7 +430,7 @@ def purge(name, delete_key=True): log.debug("Deleting key %s", name) with salt.key.Key(__opts__) as skey: skey.delete_key(name) - __jid_event__.fire_event({"message": "Purged VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Purged VM {name}"}, "progress") return "good" @@ -451,13 +444,13 @@ def pause(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"error": "Failed to find VM {} to pause".format(name)}, "progress" + {"error": f"Failed to find VM {name} to pause"}, "progress" ) return "fail" host = next(iter(data.keys())) if data[host][name]["state"] == "paused": __jid_event__.fire_event( - {"error": "VM {} is already paused".format(name)}, "progress" + {"error": f"VM {name} is already paused"}, "progress" ) return "bad state" try: @@ -468,7 +461,7 @@ def pause(name): ) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event({"message": "Paused VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Paused VM {name}"}, "progress") return "good" @@ -481,14 +474,12 @@ def resume(name): data = vm_info(name, quiet=True) if not data: __jid_event__.fire_event( - {"error": "Failed to find VM {} to pause".format(name)}, "progress" + {"error": f"Failed to find VM {name} to pause"}, "progress" ) return "not found" host = next(iter(data.keys())) if data[host][name]["state"] != "paused": - __jid_event__.fire_event( - {"error": "VM {} is not paused".format(name)}, "progress" - ) + __jid_event__.fire_event({"error": f"VM {name} is not paused"}, "progress") return "bad state" try: cmd_ret = client.cmd_iter(host, "virt.resume", [name], timeout=600) @@ -498,7 +489,7 @@ def resume(name): ) for comp in cmd_ret: ret.update(comp) - __jid_event__.fire_event({"message": "Resumed VM {}".format(name)}, "progress") + __jid_event__.fire_event({"message": f"Resumed VM {name}"}, "progress") return "good" @@ -514,14 +505,14 @@ def migrate(name, target=""): origin_host = next(iter(origin_data)) except StopIteration: __jid_event__.fire_event( - {"error": "Named VM {} was not found to migrate".format(name)}, + {"error": f"Named VM {name} was not found to migrate"}, "progress", ) return "" disks = origin_data[origin_host][name]["disks"] if not origin_data: __jid_event__.fire_event( - {"error": "Named VM {} was not found to migrate".format(name)}, + {"error": f"Named VM {name} was not found to migrate"}, "progress", ) return "" @@ -529,7 +520,7 @@ def migrate(name, target=""): target = _determine_host(data, origin_host) if target not in data: __jid_event__.fire_event( - {"error": "Target host {} not found".format(origin_data)}, "progress" + {"error": f"Target host {origin_data} not found"}, "progress" ) return "" try: diff --git a/salt/runners/vistara.py b/salt/runners/vistara.py index ea2d708e354..bd594764919 100644 --- a/salt/runners/vistara.py +++ b/salt/runners/vistara.py @@ -94,7 +94,7 @@ def delete_device(name, safety_on=True): if not access_token: return "Vistara access token not available" - query_string = "dnsName:{}".format(name) + query_string = f"dnsName:{name}" devices = _search_devices(query_string, config["client_id"], access_token) @@ -123,7 +123,7 @@ def delete_device(name, safety_on=True): def _search_devices(query_string, client_id, access_token): - authstring = "Bearer {}".format(access_token) + authstring = f"Bearer {access_token}" headers = { "Authorization": authstring, @@ -134,7 +134,7 @@ def _search_devices(query_string, client_id, access_token): params = {"queryString": query_string} method = "GET" - url = "https://api.vistara.io/api/v2/tenants/{}/devices/search".format(client_id) + url = f"https://api.vistara.io/api/v2/tenants/{client_id}/devices/search" resp = salt.utils.http.query( url=url, method=method, header_dict=headers, params=params, opts=__opts__ @@ -152,7 +152,7 @@ def _search_devices(query_string, client_id, access_token): def _delete_resource(device_id, client_id, access_token): - authstring = "Bearer {}".format(access_token) + authstring = f"Bearer {access_token}" headers = { "Authorization": authstring, diff --git a/salt/runners/winrepo.py b/salt/runners/winrepo.py index 9e31040884c..856115d6642 100644 --- a/salt/runners/winrepo.py +++ b/salt/runners/winrepo.py @@ -241,7 +241,7 @@ def update_git_repos(opts=None, clean=False, masterless=False): winrepo.clear_old_remotes() winrepo.checkout() except Exception as exc: # pylint: disable=broad-except - msg = "Failed to update winrepo_remotes: {}".format(exc) + msg = f"Failed to update winrepo_remotes: {exc}" log.error(msg, exc_info_on_loglevel=logging.DEBUG) return msg ret.update(winrepo.winrepo_dirs) diff --git a/salt/scripts.py b/salt/scripts.py index cc960f07854..f322490f659 100644 --- a/salt/scripts.py +++ b/salt/scripts.py @@ -1,6 +1,7 @@ """ This module contains the function calls to execute command line scripts """ + import contextlib import functools import logging @@ -18,9 +19,6 @@ from salt.exceptions import SaltClientError, SaltReqTimeoutError, SaltSystemExit log = logging.getLogger(__name__) -if sys.version_info < (3,): - raise SystemExit(salt.defaults.exitcodes.EX_GENERIC) - def _handle_signals(client, signum, sigframe): try: diff --git a/salt/sdb/cache.py b/salt/sdb/cache.py index 837fcba8ff1..96503b3bbc3 100644 --- a/salt/sdb/cache.py +++ b/salt/sdb/cache.py @@ -44,7 +44,6 @@ it must be specified in the URI: master_ip: sdb://mastercloudcache/public_ips?bank=cloud/active/ec2/my-ec2-conf/saltmaster """ - import salt.cache __func_alias__ = {"set_": "set"} diff --git a/salt/sdb/couchdb.py b/salt/sdb/couchdb.py index 978385f9788..5e7012798a1 100644 --- a/salt/sdb/couchdb.py +++ b/salt/sdb/couchdb.py @@ -35,7 +35,6 @@ Additional contributions to build true map-reduce functionality into this module would be welcome. """ - # Import Python libraries import logging from uuid import uuid4 diff --git a/salt/sdb/etcd_db.py b/salt/sdb/etcd_db.py index bf31fc74eb3..aa2858307c7 100644 --- a/salt/sdb/etcd_db.py +++ b/salt/sdb/etcd_db.py @@ -39,7 +39,6 @@ defaults to true, meaning you will use v2 unless you specify otherwise. """ - import logging try: diff --git a/salt/sdb/rest.py b/salt/sdb/rest.py index f436fc5802b..dfcb980331b 100644 --- a/salt/sdb/rest.py +++ b/salt/sdb/rest.py @@ -64,7 +64,6 @@ For instance: user: myuser """ - import logging import salt.loader diff --git a/salt/sdb/sqlite3.py b/salt/sdb/sqlite3.py index 28419060789..3aba762fe78 100644 --- a/salt/sdb/sqlite3.py +++ b/salt/sdb/sqlite3.py @@ -106,8 +106,8 @@ def _connect(profile): for sql in stmts: cur.execute(sql) elif profile.get("create_table", True): - cur.execute("CREATE TABLE {} (key text, value blob)".format(table)) - cur.execute("CREATE UNIQUE INDEX {} ON {} (key)".format(idx, table)) + cur.execute(f"CREATE TABLE {table} (key text, value blob)") + cur.execute(f"CREATE UNIQUE INDEX {idx} ON {table} (key)") except sqlite3.OperationalError: pass @@ -124,7 +124,7 @@ def set_(key, value, profile=None): value = memoryview(salt.utils.msgpack.packb(value)) q = profile.get( "set_query", - "INSERT OR REPLACE INTO {} VALUES (:key, :value)".format(table), + f"INSERT OR REPLACE INTO {table} VALUES (:key, :value)", ) conn.execute(q, {"key": key, "value": value}) conn.commit() @@ -138,7 +138,7 @@ def get(key, profile=None): if not profile: return None _, cur, table = _connect(profile) - q = profile.get("get_query", "SELECT value FROM {} WHERE key=:key".format(table)) + q = profile.get("get_query", f"SELECT value FROM {table} WHERE key=:key") res = cur.execute(q, {"key": key}) res = res.fetchone() if not res: diff --git a/salt/sdb/tism.py b/salt/sdb/tism.py index 08b05b08b4a..50c72b85317 100644 --- a/salt/sdb/tism.py +++ b/salt/sdb/tism.py @@ -27,7 +27,6 @@ configuration. token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6MSwiZXhwIjoxNTg1MTExNDYwLCJqdGkiOiI3NnA5cWNiMWdtdmw4Iiwia2V5cyI6WyJBTEwiXX0.RtAhG6Uorf5xnSf4Ya_GwJnoHkCsql4r1_hiOeDSLzo """ - import logging import salt.utils.http as http diff --git a/salt/sdb/vault.py b/salt/sdb/vault.py index 907714942ff..ba2fbb002f8 100644 --- a/salt/sdb/vault.py +++ b/salt/sdb/vault.py @@ -52,7 +52,6 @@ patch .. versionadded:: 3007.0 """ - import logging import salt.exceptions diff --git a/salt/sdb/yaml.py b/salt/sdb/yaml.py index 1411e6c2899..e899382eff5 100644 --- a/salt/sdb/yaml.py +++ b/salt/sdb/yaml.py @@ -41,7 +41,6 @@ embedded GPG-encrypted data using the :py:mod:`GPG renderer `. """ - import logging import salt.exceptions diff --git a/salt/serializers/__init__.py b/salt/serializers/__init__.py index 2d0b5dc10db..afa7ff49cb3 100644 --- a/salt/serializers/__init__.py +++ b/salt/serializers/__init__.py @@ -14,7 +14,6 @@ """ - from salt.exceptions import SaltException, SaltRenderError diff --git a/salt/serializers/configparser.py b/salt/serializers/configparser.py index cb9c820758c..96fdbcde282 100644 --- a/salt/serializers/configparser.py +++ b/salt/serializers/configparser.py @@ -54,7 +54,7 @@ def serialize(obj, **options): try: if not isinstance(obj, dict): raise TypeError( - "configparser can only serialize dictionaries, not {}".format(type(obj)) + f"configparser can only serialize dictionaries, not {type(obj)}" ) fp = options.pop("fp", None) cp = configparser.ConfigParser(**options) diff --git a/salt/serializers/json.py b/salt/serializers/json.py index 8ee1085452c..cea79944b42 100644 --- a/salt/serializers/json.py +++ b/salt/serializers/json.py @@ -7,7 +7,6 @@ It's just a wrapper around json (or simplejson if available). """ - import salt.utils.json from salt.serializers import DeserializationError, SerializationError diff --git a/salt/serializers/msgpack.py b/salt/serializers/msgpack.py index 93a3fddeb3a..ac9eebb1e49 100644 --- a/salt/serializers/msgpack.py +++ b/salt/serializers/msgpack.py @@ -5,7 +5,6 @@ Implements MsgPack serializer. """ - import copy import logging diff --git a/salt/serializers/plist.py b/salt/serializers/plist.py index a833b4e7897..d205d68ea1d 100644 --- a/salt/serializers/plist.py +++ b/salt/serializers/plist.py @@ -7,6 +7,7 @@ Wrapper around plistlib. """ + import logging import plistlib diff --git a/salt/serializers/yaml.py b/salt/serializers/yaml.py index e8a5e85e4b5..bc6391618df 100644 --- a/salt/serializers/yaml.py +++ b/salt/serializers/yaml.py @@ -8,7 +8,6 @@ It also use C bindings if they are available. """ - import datetime import logging diff --git a/salt/serializers/yamlex.py b/salt/serializers/yamlex.py index d67ff7a60b2..c1f68f1c07a 100644 --- a/salt/serializers/yamlex.py +++ b/salt/serializers/yamlex.py @@ -98,6 +98,7 @@ Document is defacto an aggregate mapping. """ + # pylint: disable=invalid-name,no-member,missing-docstring,no-self-use # pylint: disable=too-few-public-methods,too-many-public-methods @@ -208,7 +209,7 @@ class Loader(BaseLoader): # pylint: disable=W0232 raise ConstructorError( None, None, - "expected a mapping node, but found {}".format(node.id), + f"expected a mapping node, but found {node.id}", node.start_mark, ) diff --git a/salt/spm/__init__.py b/salt/spm/__init__.py index fa8f366702c..34649f6d087 100644 --- a/salt/spm/__init__.py +++ b/salt/spm/__init__.py @@ -136,7 +136,7 @@ class SPMClient: elif command == "close": self._close() else: - raise SPMInvocationError("Invalid command '{}'".format(command)) + raise SPMInvocationError(f"Invalid command '{command}'") except SPMException as exc: self.ui.error(str(exc)) @@ -144,7 +144,7 @@ class SPMClient: try: return getattr(getattr(self.pkgdb, self.db_prov), func)(*args, **kwargs) except AttributeError: - return self.pkgdb["{}.{}".format(self.db_prov, func)](*args, **kwargs) + return self.pkgdb[f"{self.db_prov}.{func}"](*args, **kwargs) def _pkgfiles_fun(self, func, *args, **kwargs): try: @@ -152,7 +152,7 @@ class SPMClient: *args, **kwargs ) except AttributeError: - return self.pkgfiles["{}.{}".format(self.files_prov, func)](*args, **kwargs) + return self.pkgfiles[f"{self.files_prov}.{func}"](*args, **kwargs) def _list(self, args): """ @@ -167,7 +167,7 @@ class SPMClient: elif command == "repos": self._repo_list(args) else: - raise SPMInvocationError("Invalid list command '{}'".format(command)) + raise SPMInvocationError(f"Invalid list command '{command}'") def _local(self, args): """ @@ -182,7 +182,7 @@ class SPMClient: elif command == "info": self._local_info(args) else: - raise SPMInvocationError("Invalid local command '{}'".format(command)) + raise SPMInvocationError(f"Invalid local command '{command}'") def _repo(self, args): """ @@ -201,7 +201,7 @@ class SPMClient: elif command == "create": self._create_repo(args) else: - raise SPMInvocationError("Invalid repo command '{}'".format(command)) + raise SPMInvocationError(f"Invalid repo command '{command}'") def _repo_packages(self, args, search=False): """ @@ -216,7 +216,7 @@ class SPMClient: release = repo_metadata[repo]["packages"][pkg]["info"]["release"] packages.append((pkg, version, release, repo)) for pkg in sorted(packages): - self.ui.status("{}\t{}-{}\t{}".format(pkg[0], pkg[1], pkg[2], pkg[3])) + self.ui.status(f"{pkg[0]}\t{pkg[1]}-{pkg[2]}\t{pkg[3]}") return packages def _repo_list(self, args): @@ -255,7 +255,7 @@ class SPMClient: pkg_name = comps[-1] formula_tar = tarfile.open(pkg, "r:bz2") - formula_ref = formula_tar.extractfile("{}/FORMULA".format(pkg_name)) + formula_ref = formula_tar.extractfile(f"{pkg_name}/FORMULA") formula_def = salt.utils.yaml.safe_load(formula_ref) file_map[pkg_name] = pkg @@ -267,7 +267,7 @@ class SPMClient: recommended.extend(re_) formula_tar.close() else: - raise SPMInvocationError("Package file {} not found".format(pkg)) + raise SPMInvocationError(f"Package file {pkg} not found") else: to_, op_, re_ = self._check_all_deps(pkg_name=pkg) to_install.extend(to_) @@ -385,7 +385,7 @@ class SPMClient: Starting with one package, check all packages for dependencies """ if pkg_file and not os.path.exists(pkg_file): - raise SPMInvocationError("Package file {} not found".format(pkg_file)) + raise SPMInvocationError(f"Package file {pkg_file} not found") self.repo_metadata = self._get_repo_metadata() if not formula_def: @@ -396,7 +396,7 @@ class SPMClient: formula_def = self.repo_metadata[repo]["packages"][pkg_name]["info"] if not formula_def: - raise SPMInvocationError("Unable to read formula for {}".format(pkg_name)) + raise SPMInvocationError(f"Unable to read formula for {pkg_name}") # Check to see if the package is already installed pkg_info = self._pkgdb_fun("info", pkg_name, self.db_conn) @@ -439,7 +439,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", formula_def["name"]) msg = dep_pkg if isinstance(pkg_info, dict): - msg = "{} [Installed]".format(dep_pkg) + msg = f"{dep_pkg} [Installed]" optional_install.append(msg) if recommended: @@ -448,7 +448,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", formula_def["name"]) msg = dep_pkg if isinstance(pkg_info, dict): - msg = "{} [Installed]".format(dep_pkg) + msg = f"{dep_pkg} [Installed]" recommended_install.append(msg) if needs: @@ -457,7 +457,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", formula_def["name"]) msg = dep_pkg if isinstance(pkg_info, dict): - msg = "{} [Installed]".format(dep_pkg) + msg = f"{dep_pkg} [Installed]" return pkgs_to_install, optional_install, recommended_install @@ -465,16 +465,14 @@ class SPMClient: """ Install one individual package """ - self.ui.status("... installing {}".format(pkg_name)) + self.ui.status(f"... installing {pkg_name}") formula_tar = tarfile.open(pkg_file, "r:bz2") - formula_ref = formula_tar.extractfile("{}/FORMULA".format(pkg_name)) + formula_ref = formula_tar.extractfile(f"{pkg_name}/FORMULA") formula_def = salt.utils.yaml.safe_load(formula_ref) for field in ("version", "release", "summary", "description"): if field not in formula_def: - raise SPMPackageError( - "Invalid package: the {} was not found".format(field) - ) + raise SPMPackageError(f"Invalid package: the {field} was not found") pkg_files = formula_tar.getmembers() @@ -542,7 +540,7 @@ class SPMClient: digest = "" else: self._verbose( - "Installing file {} to {}".format(member.name, out_path), + f"Installing file {member.name} to {out_path}", log.trace, ) file_hash = hashlib.sha1() @@ -580,7 +578,7 @@ class SPMClient: Return a list of packages which need to be installed, to resolve all dependencies """ - pkg_info = self.pkgdb["{}.info".format(self.db_prov)](formula_def["name"]) + pkg_info = self.pkgdb[f"{self.db_prov}.info"](formula_def["name"]) if not isinstance(pkg_info, dict): pkg_info = {} @@ -592,7 +590,7 @@ class SPMClient: dep = dep.strip() if not dep: continue - if self.pkgdb["{}.info".format(self.db_prov)](dep): + if self.pkgdb[f"{self.db_prov}.info"](dep): continue if dep in self.avail_pkgs: @@ -635,7 +633,7 @@ class SPMClient: if os.path.exists(self.opts["spm_repos_config"]): repo_files.append(self.opts["spm_repos_config"]) - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk( + for dirpath, dirnames, filenames in salt.utils.path.os_walk( "{}.d".format(self.opts["spm_repos_config"]) ): for repo_file in filenames: @@ -753,17 +751,17 @@ class SPMClient: old_files = [] repo_metadata = {} - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk(repo_path): + for dirpath, dirnames, filenames in salt.utils.path.os_walk(repo_path): for spm_file in filenames: if not spm_file.endswith(".spm"): continue - spm_path = "{}/{}".format(repo_path, spm_file) + spm_path = f"{repo_path}/{spm_file}" if not tarfile.is_tarfile(spm_path): continue comps = spm_file.split("-") spm_name = "-".join(comps[:-2]) spm_fh = tarfile.open(spm_path, "r:bz2") - formula_handle = spm_fh.extractfile("{}/FORMULA".format(spm_name)) + formula_handle = spm_fh.extractfile(f"{spm_name}/FORMULA") formula_conf = salt.utils.yaml.safe_load(formula_handle.read()) use_formula = True @@ -815,7 +813,7 @@ class SPMClient: } repo_metadata[spm_name]["filename"] = spm_file - metadata_filename = "{}/SPM-METADATA".format(repo_path) + metadata_filename = f"{repo_path}/SPM-METADATA" with salt.utils.files.fopen(metadata_filename, "w") as mfh: salt.utils.yaml.safe_dump( repo_metadata, @@ -868,7 +866,7 @@ class SPMClient: self.ui.confirm(msg) for package in packages: - self.ui.status("... removing {}".format(package)) + self.ui.status(f"... removing {package}") if not self._pkgdb_fun("db_exists", self.opts["spm_db"]): raise SPMDatabaseError( @@ -880,7 +878,7 @@ class SPMClient: # Look at local repo index pkg_info = self._pkgdb_fun("info", package, self.db_conn) if pkg_info is None: - raise SPMInvocationError("Package {} not installed".format(package)) + raise SPMInvocationError(f"Package {package} not installed") # Find files that have not changed and remove them files = self._pkgdb_fun("list_files", package, self.db_conn) @@ -894,22 +892,22 @@ class SPMClient: "hash_file", filerow[0], file_hash, self.files_conn ) if filerow[1] == digest: - self._verbose("Removing file {}".format(filerow[0]), log.trace) + self._verbose(f"Removing file {filerow[0]}", log.trace) self._pkgfiles_fun("remove_file", filerow[0], self.files_conn) else: - self._verbose("Not removing file {}".format(filerow[0]), log.trace) + self._verbose(f"Not removing file {filerow[0]}", log.trace) self._pkgdb_fun("unregister_file", filerow[0], package, self.db_conn) # Clean up directories for dir_ in sorted(dirs, reverse=True): self._pkgdb_fun("unregister_file", dir_, package, self.db_conn) try: - self._verbose("Removing directory {}".format(dir_), log.trace) + self._verbose(f"Removing directory {dir_}", log.trace) os.rmdir(dir_) except OSError: # Leave directories in place that still have files in them self._verbose( - "Cannot remove directory {}, probably not empty".format(dir_), + f"Cannot remove directory {dir_}, probably not empty", log.trace, ) @@ -933,14 +931,14 @@ class SPMClient: pkg_file = args[1] if not os.path.exists(pkg_file): - raise SPMInvocationError("Package file {} not found".format(pkg_file)) + raise SPMInvocationError(f"Package file {pkg_file} not found") comps = pkg_file.split("-") comps = "-".join(comps[:-2]).split("/") name = comps[-1] formula_tar = tarfile.open(pkg_file, "r:bz2") - formula_ref = formula_tar.extractfile("{}/FORMULA".format(name)) + formula_ref = formula_tar.extractfile(f"{name}/FORMULA") formula_def = salt.utils.yaml.safe_load(formula_ref) self.ui.status(self._get_info(formula_def)) @@ -957,7 +955,7 @@ class SPMClient: pkg_info = self._pkgdb_fun("info", package, self.db_conn) if pkg_info is None: - raise SPMPackageError("package {} not installed".format(package)) + raise SPMPackageError(f"package {package} not installed") self.ui.status(self._get_info(pkg_info)) def _get_info(self, formula_def): @@ -1007,7 +1005,7 @@ class SPMClient: pkg_file = args[1] if not os.path.exists(pkg_file): - raise SPMPackageError("Package file {} not found".format(pkg_file)) + raise SPMPackageError(f"Package file {pkg_file} not found") formula_tar = tarfile.open(pkg_file, "r:bz2") pkg_files = formula_tar.getmembers() @@ -1037,7 +1035,7 @@ class SPMClient: files = self._pkgdb_fun("list_files", package, self.db_conn) if files is None: - raise SPMPackageError("package {} not installed".format(package)) + raise SPMPackageError(f"package {package} not installed") else: for file_ in files: if self.opts["verbose"]: @@ -1057,17 +1055,15 @@ class SPMClient: comps = self.abspath.split("/") self.relpath = comps[-1] - formula_path = "{}/FORMULA".format(self.abspath) + formula_path = f"{self.abspath}/FORMULA" if not os.path.exists(formula_path): - raise SPMPackageError("Formula file {} not found".format(formula_path)) + raise SPMPackageError(f"Formula file {formula_path} not found") with salt.utils.files.fopen(formula_path) as fp_: formula_conf = salt.utils.yaml.safe_load(fp_) for field in ("name", "version", "release", "summary", "description"): if field not in formula_conf: - raise SPMPackageError( - "Invalid package: a {} must be defined".format(field) - ) + raise SPMPackageError(f"Invalid package: a {field} must be defined") out_path = "{}/{}-{}-{}.spm".format( self.opts["spm_build_dir"], @@ -1094,8 +1090,8 @@ class SPMClient: formula_tar.addfile(formula_dir) for file_ in formula_conf["files"]: for ftype in FILE_TYPES: - if file_.startswith("{}|".format(ftype)): - file_ = file_.lstrip("{}|".format(ftype)) + if file_.startswith(f"{ftype}|"): + file_ = file_.lstrip(f"{ftype}|") formula_tar.add( os.path.join(os.getcwd(), file_), os.path.join(formula_conf["name"], file_), @@ -1118,7 +1114,7 @@ class SPMClient: ) formula_tar.close() - self.ui.status("Built package {}".format(out_path)) + self.ui.status(f"Built package {out_path}") def _exclude(self, member): """ @@ -1130,7 +1126,7 @@ class SPMClient: for item in self.opts["spm_build_exclude"]: if member.name.startswith("{}/{}".format(self.formula_conf["name"], item)): return None - elif member.name.startswith("{}/{}".format(self.abspath, item)): + elif member.name.startswith(f"{self.abspath}/{item}"): return None return member @@ -1152,7 +1148,7 @@ class SPMClient: blacklist, whitelist, input_data=data, - **template_vars + **template_vars, ) diff --git a/salt/spm/pkgdb/sqlite3.py b/salt/spm/pkgdb/sqlite3.py index 48a23e0109a..c6c0fb1384f 100644 --- a/salt/spm/pkgdb/sqlite3.py +++ b/salt/spm/pkgdb/sqlite3.py @@ -4,7 +4,6 @@ This module allows SPM to use sqlite3 as the backend for SPM's package database. .. versionadded:: 2015.8.0 """ - import datetime import logging import os @@ -194,7 +193,7 @@ def register_file(name, member, path, digest="", conn=None): "INSERT INTO files VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ( name, - "{}/{}".format(path, member.path), + f"{path}/{member.path}", member.size, member.mode, digest, diff --git a/salt/spm/pkgfiles/local.py b/salt/spm/pkgfiles/local.py index b75a1457448..2b826a5d393 100644 --- a/salt/spm/pkgfiles/local.py +++ b/salt/spm/pkgfiles/local.py @@ -4,7 +4,6 @@ This module allows SPM to use the local filesystem to install files for SPM. .. versionadded:: 2015.8.0 """ - import logging import os import os.path @@ -57,11 +56,11 @@ def check_existing(package, pkg_files, formula_def, conn=None): continue tld = formula_def.get("top_level_dir", package) - new_name = member.name.replace("{}/".format(package), "") + new_name = member.name.replace(f"{package}/", "") if not new_name.startswith(tld): continue - if member.name.startswith("{}/_".format(package)): + if member.name.startswith(f"{package}/_"): if node_type in ("master", "minion"): # Module files are distributed via extmods directory out_file = os.path.join( @@ -73,9 +72,9 @@ def check_existing(package, pkg_files, formula_def, conn=None): else: # Module files are distributed via _modules, _states, etc out_file = os.path.join(conn["formula_path"], new_name) - elif member.name == "{}/pillar.example".format(package): + elif member.name == f"{package}/pillar.example": # Pillars are automatically put in the pillar_path - new_name = "{}.sls.orig".format(package) + new_name = f"{package}.sls.orig" out_file = os.path.join(conn["pillar_path"], new_name) elif package.endswith("-conf"): # Configuration files go into /etc/salt/ @@ -109,7 +108,7 @@ def install_file(package, formula_tar, member, formula_def, conn=None): out_path = conn["formula_path"] tld = formula_def.get("top_level_dir", package) - new_name = member.name.replace("{}/".format(package), "", 1) + new_name = member.name.replace(f"{package}/", "", 1) if ( not new_name.startswith(tld) and not new_name.startswith("_") @@ -122,7 +121,7 @@ def install_file(package, formula_tar, member, formula_def, conn=None): for line in formula_def.get("files", []): tag = "" for ftype in FILE_TYPES: - if line.startswith("{}|".format(ftype)): + if line.startswith(f"{ftype}|"): tag = line.split("|", 1)[0] line = line.split("|", 1)[1] if tag and new_name == line: @@ -131,10 +130,10 @@ def install_file(package, formula_tar, member, formula_def, conn=None): elif tag in ("s", "m"): pass - if member.name.startswith("{}{}_".format(package, os.sep)): + if member.name.startswith(f"{package}{os.sep}_"): if node_type in ("master", "minion"): # Module files are distributed via extmods directory - member.name = new_name.replace("{}{}_".format(package, os.sep), "") + member.name = new_name.replace(f"{package}{os.sep}_", "") out_path = os.path.join( salt.syspaths.CACHE_DIR, node_type, @@ -142,14 +141,14 @@ def install_file(package, formula_tar, member, formula_def, conn=None): ) else: # Module files are distributed via _modules, _states, etc - member.name = new_name.replace("{}{}".format(package, os.sep), "") - elif member.name == "{}/pillar.example".format(package): + member.name = new_name.replace(f"{package}{os.sep}", "") + elif member.name == f"{package}/pillar.example": # Pillars are automatically put in the pillar_path - member.name = "{}.sls.orig".format(package) + member.name = f"{package}.sls.orig" out_path = conn["pillar_path"] elif package.endswith("-conf"): # Configuration files go into /etc/salt/ - member.name = member.name.replace("{}/".format(package), "") + member.name = member.name.replace(f"{package}/", "") out_path = salt.syspaths.CONFIG_DIR elif package.endswith("-reactor"): # Reactor files go into /srv/reactor/ diff --git a/salt/state.py b/salt/state.py index ed37dfb1034..92e6cbca385 100644 --- a/salt/state.py +++ b/salt/state.py @@ -4518,9 +4518,11 @@ class BaseHighState: " on the salt master in saltenv(s): {} ".format( env_key, inc_sls, - ", ".join(matches) - if env_key == xenv_key - else env_key, + ( + ", ".join(matches) + if env_key == xenv_key + else env_key + ), ) ) elif len(resolved_envs) > 1: @@ -4720,10 +4722,10 @@ class BaseHighState: # match SLS foobar in environment this_sls = f"SLS {sls_match} in saltenv" if this_sls in error: - errors[ - i - ] = "No matching sls found for '{}' in env '{}'".format( - sls_match, saltenv + errors[i] = ( + "No matching sls found for '{}' in env '{}'".format( + sls_match, saltenv + ) ) all_errors.extend(errors) diff --git a/salt/states/alias.py b/salt/states/alias.py index 6c2eb8959e1..48b153b5f6e 100644 --- a/salt/states/alias.py +++ b/salt/states/alias.py @@ -43,20 +43,20 @@ def present(name, target): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if __salt__["aliases.has_target"](name, target): ret["result"] = True - ret["comment"] = "Alias {} already present".format(name) + ret["comment"] = f"Alias {name} already present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Alias {} -> {} is set to be added".format(name, target) + ret["comment"] = f"Alias {name} -> {target} is set to be added" return ret if __salt__["aliases.set_target"](name, target): ret["changes"] = {"alias": name} ret["result"] = True - ret["comment"] = "Set email alias {} -> {}".format(name, target) + ret["comment"] = f"Set email alias {name} -> {target}" return ret else: ret["result"] = False - ret["comment"] = "Failed to set alias {} -> {}".format(name, target) + ret["comment"] = f"Failed to set alias {name} -> {target}" return ret @@ -70,18 +70,18 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["aliases.get_target"](name): ret["result"] = True - ret["comment"] = "Alias {} already absent".format(name) + ret["comment"] = f"Alias {name} already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Alias {} is set to be removed".format(name) + ret["comment"] = f"Alias {name} is set to be removed" return ret if __salt__["aliases.rm_alias"](name): ret["changes"] = {"alias": name} ret["result"] = True - ret["comment"] = "Removed alias {}".format(name) + ret["comment"] = f"Removed alias {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to remove alias {}".format(name) + ret["comment"] = f"Failed to remove alias {name}" return ret diff --git a/salt/states/alternatives.py b/salt/states/alternatives.py index f69b5f70351..2f89516acbc 100644 --- a/salt/states/alternatives.py +++ b/salt/states/alternatives.py @@ -76,10 +76,10 @@ def install(name, link, path, priority): ) else: if __opts__["test"]: - ret[ - "comment" - ] = "Alternative will be set for {} to {} with priority {}".format( - name, path, priority + ret["comment"] = ( + "Alternative will be set for {} to {} with priority {}".format( + name, path, priority + ) ) ret["result"] = None return ret @@ -87,10 +87,10 @@ def install(name, link, path, priority): out = __salt__["alternatives.install"](name, link, path, priority) if __salt__["alternatives.check_exists"](name, path): if __salt__["alternatives.check_installed"](name, path): - ret[ - "comment" - ] = "Alternative for {} set to path {} with priority {}".format( - name, path, priority + ret["comment"] = ( + "Alternative for {} set to path {} with priority {}".format( + name, path, priority + ) ) else: ret["comment"] = ( @@ -105,7 +105,7 @@ def install(name, link, path, priority): } else: ret["result"] = False - ret["comment"] = "Alternative for {} not installed: {}".format(name, out) + ret["comment"] = f"Alternative for {name} not installed: {out}" return ret @@ -128,22 +128,22 @@ def remove(name, path): isinstalled = __salt__["alternatives.check_exists"](name, path) if isinstalled: if __opts__["test"]: - ret["comment"] = "Alternative for {} will be removed".format(name) + ret["comment"] = f"Alternative for {name} will be removed" ret["result"] = None return ret __salt__["alternatives.remove"](name, path) current = __salt__["alternatives.show_current"](name) if current: ret["result"] = True - ret[ - "comment" - ] = "Alternative for {} removed. Falling back to path {}".format( - name, current + ret["comment"] = ( + "Alternative for {} removed. Falling back to path {}".format( + name, current + ) ) ret["changes"] = {"path": current} return ret - ret["comment"] = "Alternative for {} removed".format(name) + ret["comment"] = f"Alternative for {name} removed" ret["changes"] = {} return ret @@ -156,7 +156,7 @@ def remove(name, path): return ret ret["result"] = False - ret["comment"] = "Alternative for {} doesn't exist".format(name) + ret["comment"] = f"Alternative for {name} doesn't exist" return ret @@ -178,11 +178,11 @@ def auto(name): display = __salt__["alternatives.display"](name) line = display.splitlines()[0] if line.endswith(" auto mode"): - ret["comment"] = "{} already in auto mode".format(name) + ret["comment"] = f"{name} already in auto mode" return ret if __opts__["test"]: - ret["comment"] = "{} will be put in auto mode".format(name) + ret["comment"] = f"{name} will be put in auto mode" ret["result"] = None return ret ret["changes"]["result"] = __salt__["alternatives.auto"](name) @@ -214,7 +214,7 @@ def set_(name, path): current = __salt__["alternatives.show_current"](name) if current == path: - ret["comment"] = "Alternative for {} already set to {}".format(name, path) + ret["comment"] = f"Alternative for {name} already set to {path}" return ret display = __salt__["alternatives.display"](name) @@ -234,15 +234,15 @@ def set_(name, path): __salt__["alternatives.set"](name, path) current = __salt__["alternatives.show_current"](name) if current == path: - ret["comment"] = "Alternative for {} set to path {}".format(name, current) + ret["comment"] = f"Alternative for {name} set to path {current}" ret["changes"] = {"path": current} else: - ret["comment"] = "Alternative for {} not updated".format(name) + ret["comment"] = f"Alternative for {name} not updated" return ret else: ret["result"] = False - ret["comment"] = "Alternative {} for {} doesn't exist".format(path, name) + ret["comment"] = f"Alternative {path} for {name} doesn't exist" return ret diff --git a/salt/states/apache.py b/salt/states/apache.py index 9bd7779e9fc..598b429fca0 100644 --- a/salt/states/apache.py +++ b/salt/states/apache.py @@ -84,7 +84,6 @@ it still needs keyword ``this`` with empty string (or "\b" if nicer output is re do: another thing """ - import os import salt.utils.files diff --git a/salt/states/aptpkg.py b/salt/states/aptpkg.py index 62b83f37b26..0b196e3503e 100644 --- a/salt/states/aptpkg.py +++ b/salt/states/aptpkg.py @@ -3,7 +3,6 @@ Package management operations specific to APT- and DEB-based systems ==================================================================== """ - import logging import salt.utils.data @@ -36,18 +35,18 @@ def held(name): pattern=name, ) if not state: - ret.update(comment="Package {} does not have a state".format(name)) + ret.update(comment=f"Package {name} does not have a state") elif not salt.utils.data.is_true(state.get("hold", False)): if not __opts__["test"]: result = __salt__["pkg.set_selections"](selection={"hold": [name]}) ret.update( changes=result[name], result=True, - comment="Package {} is now being held".format(name), + comment=f"Package {name} is now being held", ) else: - ret.update(result=None, comment="Package {} is set to be held".format(name)) + ret.update(result=None, comment=f"Package {name} is set to be held") else: - ret.update(result=True, comment="Package {} is already held".format(name)) + ret.update(result=True, comment=f"Package {name} is already held") return ret diff --git a/salt/states/archive.py b/salt/states/archive.py index 25ca6549dbf..03dd9bdb441 100644 --- a/salt/states/archive.py +++ b/salt/states/archive.py @@ -826,9 +826,9 @@ def extracted( kwargs = salt.utils.args.clean_kwargs(**kwargs) if skip_files_list_verify and skip_verify: - ret[ - "comment" - ] = 'Only one of "skip_files_list_verify" and "skip_verify" can be set to True' + ret["comment"] = ( + 'Only one of "skip_files_list_verify" and "skip_verify" can be set to True' + ) return ret if "keep_source" in kwargs and "keep" in kwargs: @@ -890,9 +890,9 @@ def extracted( # from making this state blow up with a traceback. not_rel = True if not_rel: - ret[ - "comment" - ] = f"Value for 'enforce_ownership_on' must be within {name}" + ret["comment"] = ( + f"Value for 'enforce_ownership_on' must be within {name}" + ) return ret if if_missing is not None and os.path.exists(if_missing): @@ -902,9 +902,9 @@ def extracted( if user or group: if salt.utils.platform.is_windows(): - ret[ - "comment" - ] = "User/group ownership cannot be enforced on Windows minions" + ret["comment"] = ( + "User/group ownership cannot be enforced on Windows minions" + ) return ret if user: @@ -939,9 +939,9 @@ def extracted( try: __salt__["gpg.verify"] except KeyError: - ret[ - "comment" - ] = "Cannot verify signatures because the gpg module was not loaded" + ret["comment"] = ( + "Cannot verify signatures because the gpg module was not loaded" + ) return ret try: @@ -1061,9 +1061,9 @@ def extracted( ) else: if password: - ret[ - "comment" - ] = "The 'password' argument is only supported for zip archives" + ret["comment"] = ( + "The 'password' argument is only supported for zip archives" + ) return ret if archive_format == "rar": @@ -1091,9 +1091,9 @@ def extracted( # string-ified integer. trim_output = int(trim_output) except TypeError: - ret[ - "comment" - ] = "Invalid value for trim_output, must be True/False or an integer" + ret["comment"] = ( + "Invalid value for trim_output, must be True/False or an integer" + ) return ret if source_hash: @@ -1173,10 +1173,10 @@ def extracted( # salt/states/file.py from being processed through the loader. If # that is the case, we have much more important problems as _all_ # file states would be unavailable. - ret[ - "comment" - ] = "Unable to cache {}, file.cached state not available".format( - salt.utils.url.redact_http_basic_auth(source_match) + ret["comment"] = ( + "Unable to cache {}, file.cached state not available".format( + salt.utils.url.redact_http_basic_auth(source_match) + ) ) return ret @@ -1565,7 +1565,7 @@ def extracted( if options is None: try: with closing(tarfile.open(cached, "r")) as tar: - tar.extractall(salt.utils.stringutils.to_str(name)) + tar.extractall(salt.utils.stringutils.to_str(name)) # nosec files = tar.getnames() if trim_output: files = files[:trim_output] diff --git a/salt/states/artifactory.py b/salt/states/artifactory.py index 2395fe7d6c4..23fa8d8dd59 100644 --- a/salt/states/artifactory.py +++ b/salt/states/artifactory.py @@ -3,7 +3,6 @@ This state downloads artifacts from artifactory. """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/at.py b/salt/states/at.py index 59a44555bf4..5d211f7f7d3 100644 --- a/salt/states/at.py +++ b/salt/states/at.py @@ -209,10 +209,10 @@ def absent(name, jobid=None, **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "more than one job was return for job with id {jobid}".format( - jobid=jobid + ret["comment"] = ( + "more than one job was return for job with id {jobid}".format( + jobid=jobid + ) ) return ret diff --git a/salt/states/aws_sqs.py b/salt/states/aws_sqs.py index 42b8a5eb996..68370410ef2 100644 --- a/salt/states/aws_sqs.py +++ b/salt/states/aws_sqs.py @@ -48,7 +48,7 @@ def exists(name, region, user=None, opts=False): if not does_exist: if __opts__["test"]: ret["result"] = None - ret["comment"] = "AWS SQS queue {} is set to be created".format(name) + ret["comment"] = f"AWS SQS queue {name} is set to be created" return ret created = __salt__["aws_sqs.create_queue"](name, region, opts, user) if created["retcode"] == 0: @@ -58,7 +58,7 @@ def exists(name, region, user=None, opts=False): ret["comment"] = created["stderr"] else: - ret["comment"] = "{} exists in {}".format(name, region) + ret["comment"] = f"{name} exists in {region}" return ret @@ -86,7 +86,7 @@ def absent(name, region, user=None, opts=False): if does_exist: if __opts__["test"]: ret["result"] = None - ret["comment"] = "AWS SQS queue {} is set to be removed".format(name) + ret["comment"] = f"AWS SQS queue {name} is set to be removed" return ret removed = __salt__["aws_sqs.delete_queue"](name, region, opts, user) if removed["retcode"] == 0: @@ -95,6 +95,6 @@ def absent(name, region, user=None, opts=False): ret["result"] = False ret["comment"] = removed["stderr"] else: - ret["comment"] = "{} does not exist in {}".format(name, region) + ret["comment"] = f"{name} does not exist in {region}" return ret diff --git a/salt/states/beacon.py b/salt/states/beacon.py index 088c8d308ec..b83717ae2bd 100644 --- a/salt/states/beacon.py +++ b/salt/states/beacon.py @@ -104,7 +104,7 @@ def present(name, save=False, **kwargs): if name in current_beacons: if beacon_data == current_beacons[name]: - ret["comment"].append("Job {} in correct state".format(name)) + ret["comment"].append(f"Job {name} in correct state") else: if __opts__.get("test"): kwargs["test"] = True @@ -119,7 +119,7 @@ def present(name, save=False, **kwargs): return ret else: if "changes" in result: - ret["comment"].append("Modifying {} in beacons".format(name)) + ret["comment"].append(f"Modifying {name} in beacons") ret["changes"] = result["changes"] else: ret["comment"].append(result["comment"]) @@ -136,14 +136,14 @@ def present(name, save=False, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Adding {} to beacons".format(name)) + ret["comment"].append(f"Adding {name} to beacons") if save: if __opts__.get("test"): - ret["comment"].append("Beacon {} would be saved".format(name)) + ret["comment"].append(f"Beacon {name} would be saved") else: __salt__["beacons.save"]() - ret["comment"].append("Beacon {} saved".format(name)) + ret["comment"].append(f"Beacon {name} saved") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -184,16 +184,16 @@ def absent(name, save=False, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Removed {} from beacons".format(name)) + ret["comment"].append(f"Removed {name} from beacons") else: - ret["comment"].append("{} not configured in beacons".format(name)) + ret["comment"].append(f"{name} not configured in beacons") if save: if __opts__.get("test"): - ret["comment"].append("Beacon {} would be saved".format(name)) + ret["comment"].append(f"Beacon {name} would be saved") else: __salt__["beacons.save"]() - ret["comment"].append("Beacon {} saved".format(name)) + ret["comment"].append(f"Beacon {name} saved") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -231,9 +231,9 @@ def enabled(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Enabled {} from beacons".format(name)) + ret["comment"].append(f"Enabled {name} from beacons") else: - ret["comment"].append("{} not a configured beacon".format(name)) + ret["comment"].append(f"{name} not a configured beacon") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -271,9 +271,9 @@ def disabled(name, **kwargs): ret["comment"] = result["comment"] return ret else: - ret["comment"].append("Disabled beacon {}.".format(name)) + ret["comment"].append(f"Disabled beacon {name}.") else: - ret["comment"].append("Job {} is not configured.".format(name)) + ret["comment"].append(f"Job {name} is not configured.") ret["comment"] = "\n".join(ret["comment"]) return ret diff --git a/salt/states/bigip.py b/salt/states/bigip.py index 58b525435c6..9f494ac20c5 100644 --- a/salt/states/bigip.py +++ b/salt/states/bigip.py @@ -4,7 +4,6 @@ A state module designed to enforce load-balancing configurations for F5 Big-IP e :platform: f5_bigip_11.6 """ - import salt.utils.json @@ -331,9 +330,9 @@ def manage_node( # we think we are managing if existing["content"]["address"] != address: ret["result"] = False - ret[ - "comment" - ] = "A node with this name exists but the address does not match." + ret["comment"] = ( + "A node with this name exists but the address does not match." + ) modified = __salt__["bigip.modify_node"]( hostname=hostname, @@ -1443,10 +1442,10 @@ def add_pool_member(hostname, username, password, name, member): if exists: ret["result"] = True - ret[ - "comment" - ] = "Member: {name} already exists within this pool. No changes made.".format( - name=member["name"] + ret["comment"] = ( + "Member: {name} already exists within this pool. No changes made.".format( + name=member["name"] + ) ) ret["changes"]["old"] = {} ret["changes"]["new"] = {} @@ -1457,10 +1456,10 @@ def add_pool_member(hostname, username, password, name, member): if new_member["code"] == 200: ret["result"] = True - ret[ - "comment" - ] = "Member: {name} has been successfully added to the pool.".format( - name=member["name"] + ret["comment"] = ( + "Member: {name} has been successfully added to the pool.".format( + name=member["name"] + ) ) ret["changes"]["old"] = {} @@ -1629,17 +1628,15 @@ def modify_pool_member( # check for changes old = {"content": existing_member} new = {"content": modified_member} - ret = _check_for_changes( - "Pool Member: {member}".format(member=member), ret, old, new - ) + ret = _check_for_changes(f"Pool Member: {member}", ret, old, new) else: ret = _load_result(modified, ret) else: - ret[ - "comment" - ] = "Member: {name} does not exists within this pool. No changes made.".format( - name=member["name"] + ret["comment"] = ( + "Member: {name} does not exists within this pool. No changes made.".format( + name=member["name"] + ) ) # pool does not exists @@ -1706,10 +1703,10 @@ def delete_pool_member(hostname, username, password, name, member): # did we get rid of it? if deleted["code"] == 200: ret["result"] = True - ret[ - "comment" - ] = "Pool Member: {member} was successfully deleted.".format( - member=member + ret["comment"] = ( + "Pool Member: {member} was successfully deleted.".format( + member=member + ) ) ret["changes"]["old"] = existing_member ret["changes"]["new"] = {} @@ -2353,9 +2350,9 @@ def manage_virtual( ret["result"] = True ret["changes"]["old"] = {} ret["changes"]["new"] = virtual["content"] - ret[ - "comment" - ] = "Virtual was successfully created and enforced to the desired state." + ret["comment"] = ( + "Virtual was successfully created and enforced to the desired state." + ) else: ret = _load_result(virtual, ret) diff --git a/salt/states/blockdev.py b/salt/states/blockdev.py index c8218e68b3d..0f85f3485e5 100644 --- a/salt/states/blockdev.py +++ b/salt/states/blockdev.py @@ -82,7 +82,7 @@ def tuned(name, **kwargs): name ) elif __opts__["test"]: - ret["comment"] = "Changes to {} will be applied ".format(name) + ret["comment"] = f"Changes to {name} will be applied " ret["result"] = None return ret else: @@ -102,15 +102,15 @@ def tuned(name, **kwargs): if key == "read-write": old = not old new = not new - changeset[key] = "Changed from {} to {}".format(old, new) + changeset[key] = f"Changed from {old} to {new}" if changes: if changeset: - ret["comment"] = "Block device {} successfully modified ".format(name) + ret["comment"] = f"Block device {name} successfully modified " ret["changes"] = changeset else: - ret["comment"] = "Block device {} already in correct state".format(name) + ret["comment"] = f"Block device {name} already in correct state" else: - ret["comment"] = "Failed to modify block device {}".format(name) + ret["comment"] = f"Failed to modify block device {name}" ret["result"] = False return ret @@ -136,13 +136,13 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): """ ret = { "changes": {}, - "comment": "{} already formatted with {}".format(name, fs_type), + "comment": f"{name} already formatted with {fs_type}", "name": name, "result": False, } if not os.path.exists(name): - ret["comment"] = "{} does not exist".format(name) + ret["comment"] = f"{name} does not exist" return ret current_fs = _checkblk(name) @@ -150,12 +150,12 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): if current_fs == fs_type: ret["result"] = True return ret - elif not salt.utils.path.which("mkfs.{}".format(fs_type)): - ret["comment"] = "Invalid fs_type: {}".format(fs_type) + elif not salt.utils.path.which(f"mkfs.{fs_type}"): + ret["comment"] = f"Invalid fs_type: {fs_type}" ret["result"] = False return ret elif __opts__["test"]: - ret["comment"] = "Changes to {} will be applied ".format(name) + ret["comment"] = f"Changes to {name} will be applied " ret["result"] = None return ret @@ -171,7 +171,7 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): current_fs = _checkblk(name) if current_fs == fs_type: - ret["comment"] = "{} has been formatted with {}".format(name, fs_type) + ret["comment"] = f"{name} has been formatted with {fs_type}" ret["changes"] = {"new": fs_type, "old": current_fs} ret["result"] = True return ret @@ -182,7 +182,7 @@ def formatted(name, fs_type="ext4", force=False, **kwargs): else: break - ret["comment"] = "Failed to format {}".format(name) + ret["comment"] = f"Failed to format {name}" ret["result"] = False return ret diff --git a/salt/states/boto3_elasticache.py b/salt/states/boto3_elasticache.py index 0cf1a867851..d2d5774a4b5 100644 --- a/salt/states/boto3_elasticache.py +++ b/salt/states/boto3_elasticache.py @@ -173,7 +173,7 @@ def cache_cluster_present( key=None, keyid=None, profile=None, - **args + **args, ): """ Ensure a given cache cluster exists. @@ -444,7 +444,7 @@ def cache_cluster_present( else: create_args[k] = v if __opts__["test"]: - ret["comment"] = "Cache cluster {} would be created.".format(name) + ret["comment"] = f"Cache cluster {name} would be created." ret["result"] = None return ret created = __salt__["boto3_elasticache.create_cache_cluster"]( @@ -455,18 +455,18 @@ def cache_cluster_present( key=key, keyid=keyid, profile=profile, - **create_args + **create_args, ) if created: new = __salt__["boto3_elasticache.describe_cache_clusters"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Cache cluster {} was created.".format(name) + ret["comment"] = f"Cache cluster {name} was created." ret["changes"]["old"] = None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to create {} cache cluster.".format(name) + ret["comment"] = f"Failed to create {name} cache cluster." if check_update: # Refresh this in case we're updating from 'only_on_modify' above... @@ -476,7 +476,7 @@ def cache_cluster_present( need_update = _diff_cache_cluster(updated["CacheClusters"][0], args) if need_update: if __opts__["test"]: - ret["comment"] = "Cache cluster {} would be modified.".format(name) + ret["comment"] = f"Cache cluster {name} would be modified." ret["result"] = None return ret modified = __salt__["boto3_elasticache.modify_cache_cluster"]( @@ -487,7 +487,7 @@ def cache_cluster_present( key=key, keyid=keyid, profile=profile, - **need_update + **need_update, ) if modified: new = __salt__["boto3_elasticache.describe_cache_clusters"]( @@ -496,14 +496,14 @@ def cache_cluster_present( if ret["comment"]: # 'create' just ran... ret["comment"] += " ... and then immediately modified." else: - ret["comment"] = "Cache cluster {} was modified.".format(name) + ret["comment"] = f"Cache cluster {name} was modified." ret["changes"]["old"] = current ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to modify cache cluster {}.".format(name) + ret["comment"] = f"Failed to modify cache cluster {name}." else: - ret["comment"] = "Cache cluster {} is in the desired state.".format(name) + ret["comment"] = f"Cache cluster {name} is in the desired state." return ret @@ -552,7 +552,7 @@ def cache_cluster_absent( ) if exists: if __opts__["test"]: - ret["comment"] = "Cache cluster {} would be removed.".format(name) + ret["comment"] = f"Cache cluster {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto3_elasticache.delete_cache_cluster"]( @@ -562,16 +562,16 @@ def cache_cluster_absent( key=key, keyid=keyid, profile=profile, - **args + **args, ) if deleted: ret["changes"]["old"] = name ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} cache cluster.".format(name) + ret["comment"] = f"Failed to delete {name} cache cluster." else: - ret["comment"] = "Cache cluster {} already absent.".format(name) + ret["comment"] = f"Cache cluster {name} already absent." return ret @@ -637,7 +637,7 @@ def replication_group_present( key=None, keyid=None, profile=None, - **args + **args, ): """ Ensure a replication group exists and is in the given state. @@ -896,7 +896,7 @@ def replication_group_present( else: create_args[k] = v if __opts__["test"]: - ret["comment"] = "Replication group {} would be created.".format(name) + ret["comment"] = f"Replication group {name} would be created." ret["result"] = None return ret created = __salt__["boto3_elasticache.create_replication_group"]( @@ -907,18 +907,18 @@ def replication_group_present( key=key, keyid=keyid, profile=profile, - **create_args + **create_args, ) if created: new = __salt__["boto3_elasticache.describe_replication_groups"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Replication group {} was created.".format(name) + ret["comment"] = f"Replication group {name} was created." ret["changes"]["old"] = None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to create {} replication group.".format(name) + ret["comment"] = f"Failed to create {name} replication group." if check_update: # Refresh this in case we're updating from 'only_on_modify' above... @@ -928,7 +928,7 @@ def replication_group_present( need_update = _diff_replication_group(updated, args) if need_update: if __opts__["test"]: - ret["comment"] = "Replication group {} would be modified.".format(name) + ret["comment"] = f"Replication group {name} would be modified." ret["result"] = None return ret modified = __salt__["boto3_elasticache.modify_replication_group"]( @@ -939,7 +939,7 @@ def replication_group_present( key=key, keyid=keyid, profile=profile, - **need_update + **need_update, ) if modified: new = __salt__["boto3_elasticache.describe_replication_groups"]( @@ -948,12 +948,12 @@ def replication_group_present( if ret["comment"]: # 'create' just ran... ret["comment"] += " ... and then immediately modified." else: - ret["comment"] = "Replication group {} was modified.".format(name) + ret["comment"] = f"Replication group {name} was modified." ret["changes"]["old"] = current[0] if current else None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to modify replication group {}.".format(name) + ret["comment"] = f"Failed to modify replication group {name}." else: ret["comment"] = "Replication group {} is in the desired state.".format( name @@ -1010,7 +1010,7 @@ def replication_group_absent( ) if exists: if __opts__["test"]: - ret["comment"] = "Replication group {} would be removed.".format(name) + ret["comment"] = f"Replication group {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto3_elasticache.delete_replication_group"]( @@ -1020,16 +1020,16 @@ def replication_group_absent( key=key, keyid=keyid, profile=profile, - **args + **args, ) if deleted: ret["changes"]["old"] = name ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} replication group.".format(name) + ret["comment"] = f"Failed to delete {name} replication group." else: - ret["comment"] = "Replication group {} already absent.".format(name) + ret["comment"] = f"Replication group {name} already absent." return ret @@ -1113,7 +1113,7 @@ def cache_subnet_group_present( else: check_update = False if __opts__["test"]: - ret["comment"] = "Cache subnet group {} would be created.".format(name) + ret["comment"] = f"Cache subnet group {name} would be created." ret["result"] = None return ret created = __salt__["boto3_elasticache.create_cache_subnet_group"]( @@ -1123,24 +1123,24 @@ def cache_subnet_group_present( key=key, keyid=keyid, profile=profile, - **args + **args, ) if created: new = __salt__["boto3_elasticache.describe_cache_subnet_groups"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Cache subnet group {} was created.".format(name) + ret["comment"] = f"Cache subnet group {name} was created." ret["changes"]["old"] = None ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to create {} cache subnet group.".format(name) + ret["comment"] = f"Failed to create {name} cache subnet group." if check_update: need_update = _diff_cache_subnet_group(current, args) if need_update: if __opts__["test"]: - ret["comment"] = "Cache subnet group {} would be modified.".format(name) + ret["comment"] = f"Cache subnet group {name} would be modified." ret["result"] = None return ret modified = __salt__["boto3_elasticache.modify_cache_subnet_group"]( @@ -1150,18 +1150,18 @@ def cache_subnet_group_present( key=key, keyid=keyid, profile=profile, - **need_update + **need_update, ) if modified: new = __salt__["boto3_elasticache.describe_cache_subnet_groups"]( name, region=region, key=key, keyid=keyid, profile=profile ) - ret["comment"] = "Cache subnet group {} was modified.".format(name) + ret["comment"] = f"Cache subnet group {name} was modified." ret["changes"]["old"] = current["CacheSubetGroups"][0] ret["changes"]["new"] = new[0] else: ret["result"] = False - ret["comment"] = "Failed to modify cache subnet group {}.".format(name) + ret["comment"] = f"Failed to modify cache subnet group {name}." else: ret["comment"] = "Cache subnet group {} is in the desired state.".format( name @@ -1202,7 +1202,7 @@ def cache_subnet_group_absent( ) if exists: if __opts__["test"]: - ret["comment"] = "Cache subnet group {} would be removed.".format(name) + ret["comment"] = f"Cache subnet group {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto3_elasticache.delete_cache_subnet_group"]( @@ -1213,7 +1213,7 @@ def cache_subnet_group_absent( ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} cache_subnet group.".format(name) + ret["comment"] = f"Failed to delete {name} cache_subnet group." else: - ret["comment"] = "Cache subnet group {} already absent.".format(name) + ret["comment"] = f"Cache subnet group {name} already absent." return ret diff --git a/salt/states/boto3_elasticsearch.py b/salt/states/boto3_elasticsearch.py index ff0dae55457..9a908f33ae7 100644 --- a/salt/states/boto3_elasticsearch.py +++ b/salt/states/boto3_elasticsearch.py @@ -43,7 +43,6 @@ Manage Elasticsearch Service :depends: boto3 """ - import logging import salt.utils.json @@ -73,7 +72,7 @@ def __virtual__(): if req not in __salt__: return ( False, - "A required function was not found in __salt__: {}".format(req), + f"A required function was not found in __salt__: {req}", ) return __virtualname__ @@ -378,7 +377,7 @@ def present( else: ret["result"] = True ret["comment"].append( - 'Elasticsearch Domain "{}" has been {}d.'.format(name, action) + f'Elasticsearch Domain "{name}" has been {action}d.' ) ret["changes"] = config_diff elif action == "upgrade": @@ -455,7 +454,7 @@ def absent(name, blocking=True, region=None, keyid=None, key=None, profile=None) if __opts__["test"]: ret["result"] = None ret["comment"].append( - 'Elasticsearch domain "{}" would have been removed.'.format(name) + f'Elasticsearch domain "{name}" would have been removed.' ) ret["changes"] = {"old": name, "new": None} else: @@ -477,14 +476,12 @@ def absent(name, blocking=True, region=None, keyid=None, key=None, profile=None) else: ret["result"] = True ret["comment"].append( - 'Elasticsearch domain "{}" has been deleted.'.format(name) + f'Elasticsearch domain "{name}" has been deleted.' ) ret["changes"] = {"old": name, "new": None} else: ret["result"] = True - ret["comment"].append( - 'Elasticsearch domain "{}" is already absent.'.format(name) - ) + ret["comment"].append(f'Elasticsearch domain "{name}" is already absent.') ret = _check_return_value(ret) return ret @@ -529,9 +526,7 @@ def upgraded( if not res["result"]: ret["result"] = False if "ResourceNotFoundException" in res["error"]: - ret["comment"].append( - 'The Elasticsearch domain "{}" does not exist.'.format(name) - ) + ret["comment"].append(f'The Elasticsearch domain "{name}" does not exist.') else: ret["comment"].append(res["error"]) else: @@ -727,9 +722,7 @@ def latest(name, minor_only=True, region=None, keyid=None, key=None, profile=Non pass if not current_version: ret["result"] = True - ret["comment"].append( - 'The Elasticsearch domain "{}" can not be upgraded.'.format(name) - ) + ret["comment"].append(f'The Elasticsearch domain "{name}" can not be upgraded.') elif not latest_version: ret["result"] = True ret["comment"].append( @@ -819,7 +812,7 @@ def tagged( current_tags = res["response"] or {} else: ret["result"] = False - ret["comment"].append('Elasticsearch domain "{}" does not exist.'.format(name)) + ret["comment"].append(f'Elasticsearch domain "{name}" does not exist.') if isinstance(ret["result"], bool): return ret @@ -827,7 +820,7 @@ def tagged( if not diff_tags: ret["result"] = True ret["comment"].append( - 'Elasticsearch domain "{}" already has the specified tags.'.format(name) + f'Elasticsearch domain "{name}" already has the specified tags.' ) else: if replace: diff --git a/salt/states/boto3_route53.py b/salt/states/boto3_route53.py index 3edbc57a870..8494ecb4b12 100644 --- a/salt/states/boto3_route53.py +++ b/salt/states/boto3_route53.py @@ -59,6 +59,7 @@ passed in as a dict, or as a string to pull from pillars or minion config: - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ + # keep lint from choking # pylint: disable=W0106 # pylint: disable=E1320 @@ -241,7 +242,7 @@ def hosted_zone_present( update_comment = True if not (create or add_vpcs or del_vpcs or update_comment): - ret["comment"] = "Hostd Zone {} already in desired state".format(Name) + ret["comment"] = f"Hostd Zone {Name} already in desired state" return ret if create: @@ -282,10 +283,10 @@ def hosted_zone_present( if update_comment: if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 {} hosted zone {} comment would be updated.".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Route 53 {} hosted zone {} comment would be updated.".format( + "private" if PrivateZone else "public", Name + ) ) ret["result"] = None return ret @@ -310,10 +311,10 @@ def hosted_zone_present( ret["changes"].get("new", {}), r ) else: - ret[ - "comment" - ] = "Update of Route 53 {} hosted zone {} comment failed".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Update of Route 53 {} hosted zone {} comment failed".format( + "private" if PrivateZone else "public", Name + ) ) log.error(ret["comment"]) ret["result"] = False @@ -321,10 +322,10 @@ def hosted_zone_present( if add_vpcs or del_vpcs: if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 {} hosted zone {} associated VPCs would be updated.".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Route 53 {} hosted zone {} associated VPCs would be updated.".format( + "private" if PrivateZone else "public", Name + ) ) ret["result"] = None return ret @@ -366,10 +367,10 @@ def hosted_zone_present( log.info(msg) ret["comment"] = " ".join([ret["comment"], msg]) else: - ret[ - "comment" - ] = "Update of Route 53 {} hosted zone {} associated VPCs failed".format( - "private" if PrivateZone else "public", Name + ret["comment"] = ( + "Update of Route 53 {} hosted zone {} associated VPCs failed".format( + "private" if PrivateZone else "public", Name + ) ) log.error(ret["comment"]) ret["result"] = False @@ -697,19 +698,19 @@ def rr_present( profile=profile, ) if len(r) < 1: - ret[ - "comment" - ] = "No EC2 instance with tag {} == {} found".format( - tag_name, tag_value + ret["comment"] = ( + "No EC2 instance with tag {} == {} found".format( + tag_name, tag_value + ) ) log.error(ret["comment"]) ret["result"] = False return ret if len(r) > 1: - ret[ - "comment" - ] = "Multiple EC2 instances with tag {} == {} found".format( - tag_name, tag_value + ret["comment"] = ( + "Multiple EC2 instances with tag {} == {} found".format( + tag_name, tag_value + ) ) log.error(ret["comment"]) ret["result"] = False @@ -745,7 +746,7 @@ def rr_present( # this appears to be incredibly difficult with the jinja templating engine # so inject the quotations here to make a viable ChangeBatch if Type == "TXT": - rr = '"{}"'.format(rr) + rr = f'"{rr}"' fixed_rrs += [rr] ResourceRecords = [{"Value": rr} for rr in sorted(fixed_rrs)] @@ -782,10 +783,10 @@ def rr_present( if not recordsets: create = True if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} would be added.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} would be added.".format( + Name, Type + ) ) ret["result"] = None return ret @@ -818,10 +819,10 @@ def rr_present( return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} would be updated.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} would be updated.".format( + Name, Type + ) ) ret["result"] = None return ret @@ -859,10 +860,10 @@ def rr_present( ret["changes"]["old"] = rrset ret["changes"]["new"] = ResourceRecordSet else: - ret[ - "comment" - ] = "Failed to {} Route 53 resource record {} with type {}.".format( - "create" if create else "update", Name, Type + ret["comment"] = ( + "Failed to {} Route 53 resource record {} with type {}.".format( + "create" if create else "update", Name, Type + ) ) log.error(ret["comment"]) ret["result"] = False @@ -967,10 +968,10 @@ def rr_absent( recordsets = [r for r in recordsets if r.get("SetIdentifier") == SetIdentifier] log.debug("Resulted in recordsets %s.", recordsets) if not recordsets: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} already absent.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} already absent.".format( + Name, Type + ) ) return ret elif len(recordsets) > 1: @@ -980,10 +981,10 @@ def rr_absent( return ret ResourceRecordSet = recordsets[0] if __opts__["test"]: - ret[ - "comment" - ] = "Route 53 resource record {} with type {} would be deleted.".format( - Name, Type + ret["comment"] = ( + "Route 53 resource record {} with type {} would be deleted.".format( + Name, Type + ) ) ret["result"] = None return ret @@ -1007,10 +1008,10 @@ def rr_absent( ret["changes"]["old"] = ResourceRecordSet ret["changes"]["new"] = None else: - ret[ - "comment" - ] = "Failed to delete Route 53 resource record {} with type {}.".format( - Name, Type + ret["comment"] = ( + "Failed to delete Route 53 resource record {} with type {}.".format( + Name, Type + ) ) log.error(ret["comment"]) ret["result"] = False diff --git a/salt/states/boto3_sns.py b/salt/states/boto3_sns.py index 30509176e70..feeca5602c1 100644 --- a/salt/states/boto3_sns.py +++ b/salt/states/boto3_sns.py @@ -135,11 +135,11 @@ def topic_present( something_changed = False current = __salt__["boto3_sns.describe_topic"](name, region, key, keyid, profile) if current: - ret["comment"] = "AWS SNS topic {} present.".format(name) + ret["comment"] = f"AWS SNS topic {name} present." TopicArn = current["TopicArn"] else: if __opts__["test"]: - ret["comment"] = "AWS SNS topic {} would be created.".format(name) + ret["comment"] = f"AWS SNS topic {name} would be created." ret["result"] = None return ret else: @@ -152,7 +152,7 @@ def topic_present( ) something_changed = True else: - ret["comment"] = "Failed to create AWS SNS topic {}".format(name) + ret["comment"] = f"Failed to create AWS SNS topic {name}" log.error(ret["comment"]) ret["result"] = False return ret @@ -246,7 +246,7 @@ def topic_present( TopicArn, prot, endp, region=region, key=key, keyid=keyid, profile=profile ) if subbed: - msg = " Subscription {}:{} set on topic {}.".format(prot, endp, TopicArn) + msg = f" Subscription {prot}:{endp} set on topic {TopicArn}." ret["comment"] += msg something_changed = True else: @@ -318,11 +318,11 @@ def topic_absent( something_changed = False current = __salt__["boto3_sns.describe_topic"](name, region, key, keyid, profile) if not current: - ret["comment"] = "AWS SNS topic {} absent.".format(name) + ret["comment"] = f"AWS SNS topic {name} absent." else: TopicArn = current["TopicArn"] if __opts__["test"]: - ret["comment"] = "AWS SNS topic {} would be removed.".format(TopicArn) + ret["comment"] = f"AWS SNS topic {TopicArn} would be removed." if unsubscribe: ret["comment"] += " {} subscription(s) would be removed.".format( len(current["Subscriptions"]) @@ -350,27 +350,24 @@ def topic_absent( log.debug("Deleted subscription %s for SNS topic %s", sub, TopicArn) something_changed = True else: - ret[ - "comment" - ] = "Failed to delete subscription {} for SNS topic {}".format( - sub, TopicArn + ret["comment"] = ( + "Failed to delete subscription {} for SNS topic {}".format( + sub, TopicArn + ) ) ret["result"] = False return ret if not __salt__["boto3_sns.delete_topic"]( TopicArn, region=region, key=key, keyid=keyid, profile=profile ): - ret["comment"] = "Failed to delete SNS topic {}".format(TopicArn) + ret["comment"] = f"Failed to delete SNS topic {TopicArn}" log.error(ret["comment"]) ret["result"] = False else: - ret["comment"] = "AWS SNS topic {} deleted.".format(TopicArn) + ret["comment"] = f"AWS SNS topic {TopicArn} deleted." if unsubscribe: ret["comment"] += " ".join( - [ - "Subscription {} deleted".format(s) - for s in current["Subscriptions"] - ] + [f"Subscription {s} deleted" for s in current["Subscriptions"]] ) something_changed = True diff --git a/salt/states/boto_apigateway.py b/salt/states/boto_apigateway.py index f70edf470f1..554f574c8a3 100644 --- a/salt/states/boto_apigateway.py +++ b/salt/states/boto_apigateway.py @@ -50,7 +50,6 @@ config: """ - import hashlib import logging import os @@ -350,7 +349,7 @@ def present( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -435,7 +434,7 @@ def absent( swagger = _Swagger(api_name, stage_name, "", None, None, None, common_args) if not swagger.restApiId: - ret["comment"] = "[Rest API: {}] does not exist.".format(api_name) + ret["comment"] = f"[Rest API: {api_name}] does not exist." return ret if __opts__["test"]: @@ -446,7 +445,7 @@ def absent( "deleted.".format(stage_name, api_name) ) else: - ret["comment"] = "[stage: {}] will be deleted.".format(stage_name) + ret["comment"] = f"[stage: {stage_name}] will be deleted." ret["result"] = None return ret @@ -460,7 +459,7 @@ def absent( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -725,11 +724,11 @@ class _Swagger: _name = self._paramdict.get("name") if _name: if self.location == "header": - return "method.request.header.{}".format(_name) + return f"method.request.header.{_name}" elif self.location == "query": - return "method.request.querystring.{}".format(_name) + return f"method.request.querystring.{_name}" elif self.location == "path": - return "method.request.path.{}".format(_name) + return f"method.request.path.{_name}" return None raise ValueError( "Parameter must have a name: {}".format( @@ -754,9 +753,7 @@ class _Swagger: self.name ) ) - raise ValueError( - "Body parameter must have a schema: {}".format(self.name) - ) + raise ValueError(f"Body parameter must have a schema: {self.name}") return None class SwaggerMethodResponse: @@ -819,7 +816,7 @@ class _Swagger: self._cfg = salt.utils.yaml.safe_load(sf) self._swagger_version = "" else: - raise OSError("Invalid swagger file path, {}".format(swagger_file_path)) + raise OSError(f"Invalid swagger file path, {swagger_file_path}") self._validate_swagger_file() @@ -877,7 +874,7 @@ class _Swagger: if model.get("type") != "object": raise ValueError( - "model schema {} must be type object".format(modelname) + f"model schema {modelname} must be type object" ) if "properties" not in model: raise ValueError( @@ -928,12 +925,12 @@ class _Swagger: field not in _Swagger.SWAGGER_OBJ_V2_FIELDS and not _Swagger.VENDOR_EXT_PATTERN.match(field) ): - raise ValueError("Invalid Swagger Object Field: {}".format(field)) + raise ValueError(f"Invalid Swagger Object Field: {field}") # check for Required Swagger fields by Saltstack boto apigateway state for field in _Swagger.SWAGGER_OBJ_V2_FIELDS_REQUIRED: if field not in self._cfg: - raise ValueError("Missing Swagger Object Field: {}".format(field)) + raise ValueError(f"Missing Swagger Object Field: {field}") # check for Swagger Version self._swagger_version = self._cfg.get("swagger") @@ -1027,7 +1024,7 @@ class _Swagger: for path in paths: if not path.startswith("/"): raise ValueError( - "Path object {} should start with /. Please fix it".format(path) + f"Path object {path} should start with /. Please fix it" ) return paths.items() @@ -1100,7 +1097,7 @@ class _Swagger: stages = __salt__["boto_apigateway.describe_api_stages"]( restApiId=self.restApiId, deploymentId=deploymentId, - **self._common_aws_args + **self._common_aws_args, ).get("stages") if stages: no_more_deployments = False @@ -1116,7 +1113,7 @@ class _Swagger: stage = __salt__["boto_apigateway.describe_api_stage"]( restApiId=self.restApiId, stageName=self._stage_name, - **self._common_aws_args + **self._common_aws_args, ).get("stage") if stage: deploymentId = stage.get("deploymentId") @@ -1156,7 +1153,7 @@ class _Swagger: restApiId=self.restApiId, stageName=self._stage_name, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not res.get("overwrite"): @@ -1174,7 +1171,7 @@ class _Swagger: stage = __salt__["boto_apigateway.describe_api_stage"]( restApiId=self.restApiId, stageName=self._stage_name, - **self._common_aws_args + **self._common_aws_args, ).get("stage") if not stage: stage = __salt__["boto_apigateway.create_api_stage"]( @@ -1183,7 +1180,7 @@ class _Swagger: deploymentId=self._deploymentId, description=stage_desc_json, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not stage.get("stage"): return {"set": False, "error": stage.get("error")} @@ -1193,7 +1190,7 @@ class _Swagger: restApiId=self.restApiId, stageName=self._stage_name, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not overwrite.get("stage"): return {"set": False, "error": overwrite.get("error")} @@ -1202,7 +1199,7 @@ class _Swagger: restApiId=self.restApiId, stageName=self._stage_name, deploymentId=self._deploymentId, - **self._common_aws_args + **self._common_aws_args, ) def _resolve_api_id(self): @@ -1213,7 +1210,7 @@ class _Swagger: apis = __salt__["boto_apigateway.describe_apis"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ).get("restapi") if apis: if len(apis) == 1: @@ -1236,7 +1233,7 @@ class _Swagger: result = __salt__["boto_apigateway.delete_api_stage"]( restApiId=self.restApiId, stageName=self._stage_name, - **self._common_aws_args + **self._common_aws_args, ) if not result.get("deleted"): ret["abort"] = True @@ -1250,15 +1247,15 @@ class _Swagger: result = __salt__["boto_apigateway.delete_api_deployment"]( restApiId=self.restApiId, deploymentId=deploymentId, - **self._common_aws_args + **self._common_aws_args, ) if not result.get("deleted"): ret["abort"] = True ret["result"] = False - ret[ - "comment" - ] = "delete_stage delete_api_deployment, {}".format( - result.get("error") + ret["comment"] = ( + "delete_stage delete_api_deployment, {}".format( + result.get("error") + ) ) else: ret["comment"] = "stage {} has been deleted.\n".format( @@ -1266,7 +1263,7 @@ class _Swagger: ) else: # no matching stage_name/deployment found - ret["comment"] = "stage {} does not exist".format(self._stage_name) + ret["comment"] = f"stage {self._stage_name} does not exist" return ret @@ -1327,7 +1324,7 @@ class _Swagger: stageDescription=stage_desc_json, description=self.deployment_label_json, variables=stage_variables, - **self._common_aws_args + **self._common_aws_args, ) if not res.get("created"): ret["abort"] = True @@ -1354,7 +1351,7 @@ class _Swagger: delres = __salt__["boto_apigateway.delete_api_resources"]( restApiId=self.restApiId, path=resource.get("path"), - **self._common_aws_args + **self._common_aws_args, ) if not delres.get("deleted"): return delres @@ -1367,7 +1364,7 @@ class _Swagger: delres = __salt__["boto_apigateway.delete_api_model"]( restApiId=self.restApiId, modelName=model.get("name"), - **self._common_aws_args + **self._common_aws_args, ) if not delres.get("deleted"): return delres @@ -1381,7 +1378,7 @@ class _Swagger: if self.restApiId: res = self._cleanup_api() if not res.get("deleted"): - ret["comment"] = "Failed to cleanup restAreId {}".format(self.restApiId) + ret["comment"] = f"Failed to cleanup restAreId {self.restApiId}" ret["abort"] = True ret["result"] = False return ret @@ -1390,7 +1387,7 @@ class _Swagger: response = __salt__["boto_apigateway.create_api"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ) if not response.get("created"): @@ -1417,7 +1414,7 @@ class _Swagger: exists_response = __salt__["boto_apigateway.api_exists"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ) if exists_response.get("exists"): if __opts__["test"]: @@ -1431,7 +1428,7 @@ class _Swagger: delete_api_response = __salt__["boto_apigateway.delete_api"]( name=self.rest_api_name, description=_Swagger.AWS_API_DESCRIPTION, - **self._common_aws_args + **self._common_aws_args, ) if not delete_api_response.get("deleted"): ret["result"] = False @@ -1553,7 +1550,7 @@ class _Swagger: _schema.update( { "$schema": _Swagger.JSON_SCHEMA_DRAFT_4, - "title": "{} Schema".format(model), + "title": f"{model} Schema", } ) @@ -1570,7 +1567,7 @@ class _Swagger: restApiId=self.restApiId, modelName=model, schema=_dict_to_json_pretty(_schema), - **self._common_aws_args + **self._common_aws_args, ) if not update_model_schema_response.get("updated"): ret["result"] = False @@ -1594,19 +1591,19 @@ class _Swagger: modelDescription=model, schema=_dict_to_json_pretty(_schema), contentType="application/json", - **self._common_aws_args + **self._common_aws_args, ) if not create_model_response.get("created"): ret["result"] = False ret["abort"] = True if "error" in create_model_response: - ret[ - "comment" - ] = "Failed to create model {}, schema {}, error: {}".format( - model, - _dict_to_json_pretty(schema), - create_model_response["error"]["message"], + ret["comment"] = ( + "Failed to create model {}, schema {}, error: {}".format( + model, + _dict_to_json_pretty(schema), + create_model_response["error"]["message"], + ) ) return ret @@ -1745,7 +1742,7 @@ class _Swagger: method_response_params = {} method_integration_response_params = {} for header in method_response.headers: - response_header = "method.response.header.{}".format(header) + response_header = f"method.response.header.{header}" method_response_params[response_header] = False header_data = method_response.headers.get(header) method_integration_response_params[response_header] = ( @@ -1822,7 +1819,7 @@ class _Swagger: apiKeyRequired=api_key_required, requestParameters=method.get("params"), requestModels=method.get("models"), - **self._common_aws_args + **self._common_aws_args, ) if not m.get("created"): ret = _log_error_and_abort(ret, m) @@ -1848,7 +1845,7 @@ class _Swagger: uri=lambda_uri, credentials=lambda_integration_role, requestTemplates=method.get("request_templates"), - **self._common_aws_args + **self._common_aws_args, ) if not integration.get("created"): ret = _log_error_and_abort(ret, integration) @@ -1871,7 +1868,7 @@ class _Swagger: statusCode=httpStatus, responseParameters=method_response.get("params"), responseModels=method_response.get("models"), - **self._common_aws_args + **self._common_aws_args, ) if not mr.get("created"): ret = _log_error_and_abort(ret, mr) @@ -1886,7 +1883,7 @@ class _Swagger: selectionPattern=method_response.get("pattern"), responseParameters=method_response.get("integration_params"), responseTemplates=method_response.get("response_templates"), - **self._common_aws_args + **self._common_aws_args, ) if not mir.get("created"): ret = _log_error_and_abort(ret, mir) @@ -1896,7 +1893,7 @@ class _Swagger: ) else: raise ValueError( - "No responses specified for {} {}".format(resource_path, method_name) + f"No responses specified for {resource_path} {method_name}" ) return ret @@ -2043,7 +2040,7 @@ def usage_plan_present( description=description, throttle=throttle, quota=quota, - **common_args + **common_args, ) if "error" in result: ret["result"] = False @@ -2053,7 +2050,7 @@ def usage_plan_present( return ret ret["changes"]["old"] = {"plan": None} - ret["comment"] = "A new usage plan {} has been created".format(plan_name) + ret["comment"] = f"A new usage plan {plan_name} has been created" else: # need an existing plan modified to match given value @@ -2098,7 +2095,7 @@ def usage_plan_present( return ret ret["changes"]["old"] = {"plan": plan} - ret["comment"] = "usage plan {} has been updated".format(plan_name) + ret["comment"] = f"usage plan {plan_name} has been updated" newstate = __salt__["boto_apigateway.describe_usage_plans"]( name=plan_name, **common_args @@ -2112,7 +2109,7 @@ def usage_plan_present( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -2153,7 +2150,7 @@ def usage_plan_absent(name, plan_name, region=None, key=None, keyid=None, profil return ret if not existing["plans"]: - ret["comment"] = "Usage plan {} does not exist already".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} does not exist already" return ret if __opts__["test"]: @@ -2173,13 +2170,13 @@ def usage_plan_absent(name, plan_name, region=None, key=None, keyid=None, profil ) return ret - ret["comment"] = "Usage plan {} has been deleted".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} has been deleted" ret["changes"]["old"] = {"plan": existing["plans"][0]} ret["changes"]["new"] = {"plan": None} except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -2235,7 +2232,7 @@ def usage_plan_association_present( return ret if not existing["plans"]: - ret["comment"] = "Usage plan {} does not exist".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} does not exist" ret["result"] = False return ret @@ -2264,10 +2261,10 @@ def usage_plan_association_present( plan_id, stages_to_add, **common_args ) if "error" in result: - ret[ - "comment" - ] = "Failed to associate a usage plan {} to the apis {}, {}".format( - plan_name, stages_to_add, result["error"] + ret["comment"] = ( + "Failed to associate a usage plan {} to the apis {}, {}".format( + plan_name, stages_to_add, result["error"] + ) ) ret["result"] = False return ret @@ -2278,7 +2275,7 @@ def usage_plan_association_present( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret @@ -2336,7 +2333,7 @@ def usage_plan_association_absent( return ret if not existing["plans"]: - ret["comment"] = "Usage plan {} does not exist".format(plan_name) + ret["comment"] = f"Usage plan {plan_name} does not exist" ret["result"] = False return ret @@ -2371,10 +2368,10 @@ def usage_plan_association_absent( plan_id, stages_to_remove, **common_args ) if "error" in result: - ret[ - "comment" - ] = "Failed to disassociate a usage plan {} from the apis {}, {}".format( - plan_name, stages_to_remove, result["error"] + ret["comment"] = ( + "Failed to disassociate a usage plan {} from the apis {}, {}".format( + plan_name, stages_to_remove, result["error"] + ) ) ret["result"] = False return ret @@ -2385,6 +2382,6 @@ def usage_plan_association_absent( except (ValueError, OSError) as e: ret["result"] = False - ret["comment"] = "{}".format(e.args) + ret["comment"] = f"{e.args}" return ret diff --git a/salt/states/boto_asg.py b/salt/states/boto_asg.py index 58a5baed2ca..64d44574773 100644 --- a/salt/states/boto_asg.py +++ b/salt/states/boto_asg.py @@ -191,7 +191,6 @@ Overriding the alarm values on the resource: threshold: 50.0 """ - import copy import hashlib import logging @@ -450,7 +449,7 @@ def present( ret["result"] = False return ret if "id" not in r: - ret["comment"] = "Subnet {} does not exist.".format(i) + ret["comment"] = f"Subnet {i} does not exist." ret["result"] = False return ret vpc_zone_identifier.append(r["id"]) @@ -830,7 +829,7 @@ def _alarms_present( if "scaling_policy" not in action: scaling_policy_actions_only = False if ":self:" in action: - action = action.replace(":self:", ":{}:".format(name)) + action = action.replace(":self:", f":{name}:") new_actions.append(action) info["attributes"][action_type] = new_actions # skip alarms that only have actions for scaling policy, if min_size == max_size for this ASG diff --git a/salt/states/boto_cfn.py b/salt/states/boto_cfn.py index 971514a3b6b..bd748eb410f 100644 --- a/salt/states/boto_cfn.py +++ b/salt/states/boto_cfn.py @@ -56,7 +56,7 @@ def __virtual__(): else: return ( False, - "Cannot load {} state: boto_cfn module unavailable".format(__virtualname__), + f"Cannot load {__virtualname__} state: boto_cfn module unavailable", ) @@ -177,7 +177,7 @@ def present( log.debug("Templates are not the same. Compare value is %s", compare) # At this point we should be able to run update safely since we already validated the template if __opts__["test"]: - ret["comment"] = "Stack {} is set to be updated.".format(name) + ret["comment"] = f"Stack {name} is set to be updated." ret["result"] = None return ret updated = __salt__["boto_cfn.update_stack"]( @@ -213,11 +213,11 @@ def present( ) ret["changes"]["new"] = updated return ret - ret["comment"] = "Stack {} exists.".format(name) + ret["comment"] = f"Stack {name} exists." ret["changes"] = {} return ret if __opts__["test"]: - ret["comment"] = "Stack {} is set to be created.".format(name) + ret["comment"] = f"Stack {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_cfn.create"]( @@ -239,7 +239,7 @@ def present( profile, ) if created: - ret["comment"] = "Stack {} was created.".format(name) + ret["comment"] = f"Stack {name} was created." ret["changes"]["new"] = created return ret ret["result"] = False @@ -263,11 +263,11 @@ def absent(name, region=None, key=None, keyid=None, profile=None): """ ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_cfn.exists"](name, region, key, keyid, profile): - ret["comment"] = "Stack {} does not exist.".format(name) + ret["comment"] = f"Stack {name} does not exist." ret["changes"] = {} return ret if __opts__["test"]: - ret["comment"] = "Stack {} is set to be deleted.".format(name) + ret["comment"] = f"Stack {name} is set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_cfn.delete"](name, region, key, keyid, profile) @@ -280,7 +280,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret["changes"] = {} return ret if deleted: - ret["comment"] = "Stack {} was deleted.".format(name) + ret["comment"] = f"Stack {name} was deleted." ret["changes"]["deleted"] = name return ret @@ -293,7 +293,7 @@ def _get_template(template, name): return __salt__["cp.get_file_str"](template) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(template) + ret["comment"] = f"File {template} not found." ret["result"] = False return ret return template diff --git a/salt/states/boto_cloudfront.py b/salt/states/boto_cloudfront.py index db83cc10b80..0bdd44d13bb 100644 --- a/salt/states/boto_cloudfront.py +++ b/salt/states/boto_cloudfront.py @@ -43,7 +43,6 @@ either passed in as a dict, or a string to pull from pillars or minion config: :depends: boto3 """ - import difflib import logging @@ -132,7 +131,7 @@ def present( if old is None: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Distribution {} set for creation.".format(name) + ret["comment"] = f"Distribution {name} set for creation." ret["changes"] = {"old": None, "new": name} return ret @@ -154,7 +153,7 @@ def present( return ret ret["result"] = True - ret["comment"] = "Created distribution {}.".format(name) + ret["comment"] = f"Created distribution {name}." ret["changes"] = {"old": None, "new": name} return ret else: @@ -199,7 +198,7 @@ def present( if __opts__["test"]: ret["result"] = None ret["comment"] = "\n".join( - ["Distribution {} set for new config:".format(name), changes_diff] + [f"Distribution {name} set for new config:", changes_diff] ) ret["changes"] = {"diff": changes_diff} return ret @@ -222,6 +221,6 @@ def present( return ret ret["result"] = True - ret["comment"] = "Updated distribution {}.".format(name) + ret["comment"] = f"Updated distribution {name}." ret["changes"] = {"diff": changes_diff} return ret diff --git a/salt/states/boto_cloudtrail.py b/salt/states/boto_cloudtrail.py index 5699ef2033d..d4cf62f5be3 100644 --- a/salt/states/boto_cloudtrail.py +++ b/salt/states/boto_cloudtrail.py @@ -51,7 +51,6 @@ config: """ - import logging import os import os.path @@ -165,7 +164,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "CloudTrail {} is set to be created.".format(Name) + ret["comment"] = f"CloudTrail {Name} is set to be created." ret["result"] = None return ret r = __salt__["boto_cloudtrail.create"]( @@ -193,7 +192,7 @@ def present( ) ret["changes"]["old"] = {"trail": None} ret["changes"]["new"] = _describe - ret["comment"] = "CloudTrail {} created.".format(Name) + ret["comment"] = f"CloudTrail {Name} created." if LoggingEnabled: r = __salt__["boto_cloudtrail.start_logging"]( @@ -224,9 +223,7 @@ def present( ret["changes"]["new"]["trail"]["Tags"] = Tags return ret - ret["comment"] = os.linesep.join( - [ret["comment"], "CloudTrail {} is present.".format(Name)] - ) + ret["comment"] = os.linesep.join([ret["comment"], f"CloudTrail {Name} is present."]) ret["changes"] = {} # trail exists, ensure config matches _describe = __salt__["boto_cloudtrail.describe"]( @@ -278,7 +275,7 @@ def present( if need_update: if __opts__["test"]: - msg = "CloudTrail {} set to be modified.".format(Name) + msg = f"CloudTrail {Name} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -345,7 +342,7 @@ def present( key=key, keyid=keyid, profile=profile, - **adds + **adds, ) if bool(removes): r = __salt__["boto_cloudtrail.remove_tags"]( @@ -354,7 +351,7 @@ def present( key=key, keyid=keyid, profile=profile, - **removes + **removes, ) return ret @@ -395,11 +392,11 @@ def absent(name, Name, region=None, key=None, keyid=None, profile=None): return ret if r and not r["exists"]: - ret["comment"] = "CloudTrail {} does not exist.".format(Name) + ret["comment"] = f"CloudTrail {Name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "CloudTrail {} is set to be removed.".format(Name) + ret["comment"] = f"CloudTrail {Name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_cloudtrail.delete"]( @@ -411,5 +408,5 @@ def absent(name, Name, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"trail": Name} ret["changes"]["new"] = {"trail": None} - ret["comment"] = "CloudTrail {} deleted.".format(Name) + ret["comment"] = f"CloudTrail {Name} deleted." return ret diff --git a/salt/states/boto_cloudwatch_alarm.py b/salt/states/boto_cloudwatch_alarm.py index a3737765dff..5a931ef2ae2 100644 --- a/salt/states/boto_cloudwatch_alarm.py +++ b/salt/states/boto_cloudwatch_alarm.py @@ -52,7 +52,6 @@ as a passed in dict, or as a string to pull from pillars or minion config: - arn:aws:sns:us-east-1:1111111:myalerting-action """ - import salt.utils.data @@ -106,7 +105,7 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): if alarm_details: for k, v in attributes.items(): if k not in alarm_details: - difference.append("{}={} (new)".format(k, v)) + difference.append(f"{k}={v} (new)") continue v = salt.utils.data.decode(v) v2 = salt.utils.data.decode(alarm_details[k]) @@ -120,7 +119,7 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): continue if isinstance(v, list) and sorted(v) == sorted(v2): continue - difference.append("{}='{}' was: '{}'".format(k, v, v2)) + difference.append(f"{k}='{v}' was: '{v2}'") else: difference.append("new alarm") create_or_update_alarm_args = { @@ -134,10 +133,10 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): if alarm_details: # alarm is present. update, or do nothing # check to see if attributes matches is_present. If so, do nothing. if len(difference) == 0: - ret["comment"] = "alarm {} present and matching".format(name) + ret["comment"] = f"alarm {name} present and matching" return ret if __opts__["test"]: - msg = "alarm {} is to be created/updated.".format(name) + msg = f"alarm {name} is to be created/updated." ret["comment"] = msg ret["result"] = None return ret @@ -148,10 +147,10 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): ret["changes"]["diff"] = difference else: ret["result"] = False - ret["comment"] = "Failed to create {} alarm".format(name) + ret["comment"] = f"Failed to create {name} alarm" else: # alarm is absent. create it. if __opts__["test"]: - msg = "alarm {} is to be created/updated.".format(name) + msg = f"alarm {name} is to be created/updated." ret["comment"] = msg ret["result"] = None return ret @@ -162,7 +161,7 @@ def present(name, attributes, region=None, key=None, keyid=None, profile=None): ret["changes"]["new"] = attributes else: ret["result"] = False - ret["comment"] = "Failed to create {} alarm".format(name) + ret["comment"] = f"Failed to create {name} alarm" return ret @@ -194,7 +193,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None): if is_present: if __opts__["test"]: - ret["comment"] = "alarm {} is set to be removed.".format(name) + ret["comment"] = f"alarm {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_cloudwatch.delete_alarm"]( @@ -205,8 +204,8 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} alarm.".format(name) + ret["comment"] = f"Failed to delete {name} alarm." else: - ret["comment"] = "{} does not exist in {}.".format(name, region) + ret["comment"] = f"{name} does not exist in {region}." return ret diff --git a/salt/states/boto_cloudwatch_event.py b/salt/states/boto_cloudwatch_event.py index 4a421549bfc..1e718b374cc 100644 --- a/salt/states/boto_cloudwatch_event.py +++ b/salt/states/boto_cloudwatch_event.py @@ -51,7 +51,6 @@ config: """ - import logging import os @@ -183,7 +182,7 @@ def present( return ret ret["changes"]["old"] = {"rule": None} ret["changes"]["new"] = _describe - ret["comment"] = "CloudTrail {} created.".format(Name) + ret["comment"] = f"CloudTrail {Name} created." if bool(Targets): r = __salt__["boto_cloudwatch_event.put_targets"]( @@ -205,7 +204,7 @@ def present( return ret ret["comment"] = os.linesep.join( - [ret["comment"], "CloudWatch event rule {} is present.".format(Name)] + [ret["comment"], f"CloudWatch event rule {Name} is present."] ) ret["changes"] = {} # trail exists, ensure config matches @@ -250,7 +249,7 @@ def present( if need_update: if __opts__["test"]: - msg = "CloudWatch event rule {} set to be modified.".format(Name) + msg = f"CloudWatch event rule {Name} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -361,11 +360,11 @@ def absent(name, Name=None, region=None, key=None, keyid=None, profile=None): return ret if r and not r["exists"]: - ret["comment"] = "CloudWatch event rule {} does not exist.".format(Name) + ret["comment"] = f"CloudWatch event rule {Name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "CloudWatch event rule {} is set to be removed.".format(Name) + ret["comment"] = f"CloudWatch event rule {Name} is set to be removed." ret["result"] = None return ret @@ -406,5 +405,5 @@ def absent(name, Name=None, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"rule": Name} ret["changes"]["new"] = {"rule": None} - ret["comment"] = "CloudWatch event rule {} deleted.".format(Name) + ret["comment"] = f"CloudWatch event rule {Name} deleted." return ret diff --git a/salt/states/boto_cognitoidentity.py b/salt/states/boto_cognitoidentity.py index cb6905a2781..a6115f9f49a 100644 --- a/salt/states/boto_cognitoidentity.py +++ b/salt/states/boto_cognitoidentity.py @@ -45,7 +45,6 @@ config: """ - import logging log = logging.getLogger(__name__) @@ -109,7 +108,7 @@ def _role_present( IdentityPoolId=IdentityPoolId, AuthenticatedRole=AuthenticatedRole, UnauthenticatedRole=UnauthenticatedRole, - **conn_params + **conn_params, ) if not r.get("set"): ret["result"] = False @@ -234,10 +233,10 @@ def pool_present( IdentityPoolName ) else: - ret[ - "comment" - ] = "An existing identity pool named {} with id {} will be updated.".format( - IdentityPoolName, IdentityPoolId + ret["comment"] = ( + "An existing identity pool named {} with id {} will be updated.".format( + IdentityPoolName, IdentityPoolId + ) ) ret["result"] = None return ret @@ -261,10 +260,10 @@ def pool_present( if r.get("created"): updated_identity_pool = r.get("identity_pool") IdentityPoolId = updated_identity_pool.get("IdentityPoolId") - ret[ - "comment" - ] = "A new identity pool with name {}, id {} is created.".format( - IdentityPoolName, IdentityPoolId + ret["comment"] = ( + "A new identity pool with name {}, id {} is created.".format( + IdentityPoolName, IdentityPoolId + ) ) else: ret["result"] = False @@ -280,26 +279,26 @@ def pool_present( if r.get("updated"): updated_identity_pool = r.get("identity_pool") - ret[ - "comment" - ] = "Existing identity pool with name {}, id {} is updated.".format( - IdentityPoolName, IdentityPoolId + ret["comment"] = ( + "Existing identity pool with name {}, id {} is updated.".format( + IdentityPoolName, IdentityPoolId + ) ) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to update an existing identity pool {} {}: {}".format( - IdentityPoolName, - IdentityPoolId, - r["error"].get("message", r["error"]), + ret["comment"] = ( + "Failed to update an existing identity pool {} {}: {}".format( + IdentityPoolName, + IdentityPoolId, + r["error"].get("message", r["error"]), + ) ) return ret if existing_identity_pool != updated_identity_pool: ret["changes"]["old"] = dict() ret["changes"]["new"] = dict() - change_key = "Identity Pool Name {}".format(IdentityPoolName) + change_key = f"Identity Pool Name {IdentityPoolName}" ret["changes"]["old"][change_key] = existing_identity_pool ret["changes"]["new"][change_key] = updated_identity_pool else: @@ -388,10 +387,10 @@ def pool_absent( return ret if __opts__["test"]: - ret[ - "comment" - ] = "The following matched identity pools will be deleted.\n{}".format( - identity_pools + ret["comment"] = ( + "The following matched identity pools will be deleted.\n{}".format( + identity_pools + ) ) ret["result"] = None return ret @@ -413,12 +412,10 @@ def pool_absent( if not ret["changes"]: ret["changes"]["old"] = dict() ret["changes"]["new"] = dict() - change_key = "Identity Pool Id {}".format(IdentityPoolId) + change_key = f"Identity Pool Id {IdentityPoolId}" ret["changes"]["old"][change_key] = IdentityPoolName ret["changes"]["new"][change_key] = None - ret["comment"] = "{}\n{}".format( - ret["comment"], "{} deleted".format(change_key) - ) + ret["comment"] = "{}\n{}".format(ret["comment"], f"{change_key} deleted") else: ret["result"] = False failure_comment = ( diff --git a/salt/states/boto_datapipeline.py b/salt/states/boto_datapipeline.py index e42e328791e..0ed8ab42257 100644 --- a/salt/states/boto_datapipeline.py +++ b/salt/states/boto_datapipeline.py @@ -48,7 +48,6 @@ config: myDDBTableName: my-dynamo-table """ - import copy import datetime import difflib @@ -133,11 +132,11 @@ def present( profile=profile, ) if present: - ret["comment"] = "AWS data pipeline {} present".format(name) + ret["comment"] = f"AWS data pipeline {name} present" return ret if __opts__["test"]: - ret["comment"] = "Data pipeline {} is set to be created or updated".format(name) + ret["comment"] = f"Data pipeline {name} is set to be created or updated" ret["result"] = None return ret @@ -260,10 +259,10 @@ def present( if not old_pipeline_definition: ret["changes"]["new"] = "Pipeline created." - ret["comment"] = "Data pipeline {} created".format(name) + ret["comment"] = f"Data pipeline {name} created" else: ret["changes"]["diff"] = _diff(old_pipeline_definition, new_pipeline_definition) - ret["comment"] = "Data pipeline {} updated".format(name) + ret["comment"] = f"Data pipeline {name} updated" return ret @@ -596,7 +595,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None): if "error" not in result_pipeline_id: pipeline_id = result_pipeline_id["result"] if __opts__["test"]: - ret["comment"] = "Data pipeline {} set to be deleted.".format(name) + ret["comment"] = f"Data pipeline {name} set to be deleted." ret["result"] = None return ret else: @@ -610,6 +609,6 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret["changes"]["old"] = {"pipeline_id": pipeline_id} ret["changes"]["new"] = None else: - ret["comment"] = "AWS data pipeline {} absent.".format(name) + ret["comment"] = f"AWS data pipeline {name} absent." return ret diff --git a/salt/states/boto_dynamodb.py b/salt/states/boto_dynamodb.py index 8e563ba0574..505f0f11a63 100644 --- a/salt/states/boto_dynamodb.py +++ b/salt/states/boto_dynamodb.py @@ -284,7 +284,7 @@ def present( if not table_exists: if __opts__["test"]: ret["result"] = None - ret["comment"] = "DynamoDB table {} would be created.".format(name) + ret["comment"] = f"DynamoDB table {name} would be created." return ret else: is_created = __salt__["boto_dynamodb.create_table"]( @@ -304,11 +304,11 @@ def present( ) if not is_created: ret["result"] = False - ret["comment"] = "Failed to create table {}".format(name) + ret["comment"] = f"Failed to create table {name}" _add_changes(ret, changes_old, changes_new) return ret - comments.append("DynamoDB table {} was successfully created".format(name)) + comments.append(f"DynamoDB table {name} was successfully created") changes_new["table"] = name changes_new["read_capacity_units"] = read_capacity_units changes_new["write_capacity_units"] = write_capacity_units @@ -319,7 +319,7 @@ def present( changes_new["local_indexes"] = local_indexes changes_new["global_indexes"] = global_indexes else: - comments.append("DynamoDB table {} exists".format(name)) + comments.append(f"DynamoDB table {name} exists") # Ensure DynamoDB table provisioned throughput matches description = __salt__["boto_dynamodb.describe"](name, region, key, keyid, profile) @@ -335,7 +335,7 @@ def present( if not throughput_matches: if __opts__["test"]: ret["result"] = None - comments.append("DynamoDB table {} is set to be updated.".format(name)) + comments.append(f"DynamoDB table {name} is set to be updated.") else: is_updated = __salt__["boto_dynamodb.update"]( name, @@ -350,17 +350,17 @@ def present( ) if not is_updated: ret["result"] = False - ret["comment"] = "Failed to update table {}".format(name) + ret["comment"] = f"Failed to update table {name}" _add_changes(ret, changes_old, changes_new) return ret - comments.append("DynamoDB table {} was successfully updated".format(name)) + comments.append(f"DynamoDB table {name} was successfully updated") changes_old["read_capacity_units"] = (current_read_capacity_units,) changes_old["write_capacity_units"] = (current_write_capacity_units,) changes_new["read_capacity_units"] = (read_capacity_units,) changes_new["write_capacity_units"] = (write_capacity_units,) else: - comments.append("DynamoDB table {} throughput matches".format(name)) + comments.append(f"DynamoDB table {name} throughput matches") provisioned_indexes = description.get("Table", {}).get("GlobalSecondaryIndexes", []) @@ -478,7 +478,7 @@ def _global_indexes_present( index_name = next(iter(entry.values())) if not index_name: ret["result"] = False - ret["comment"] = "Index name not found for table {}".format(name) + ret["comment"] = f"Index name not found for table {name}" return ret gsi_config[index_name] = index @@ -591,11 +591,11 @@ def _add_global_secondary_index( ) if success: - comments.append("Created GSI {}".format(index_name)) + comments.append(f"Created GSI {index_name}") changes_new["global_indexes"][index_name] = gsi_config[index_name] else: ret["result"] = False - ret["comment"] = "Failed to create GSI {}".format(index_name) + ret["comment"] = f"Failed to create GSI {index_name}" def _update_global_secondary_indexes( @@ -641,9 +641,7 @@ def _update_global_secondary_indexes( ) if success: - comments.append( - "Updated GSIs with new throughputs {}".format(index_updates) - ) + comments.append(f"Updated GSIs with new throughputs {index_updates}") for index_name in index_updates: changes_old["global_indexes"][index_name] = provisioned_throughputs[ index_name @@ -651,7 +649,7 @@ def _update_global_secondary_indexes( changes_new["global_indexes"][index_name] = index_updates[index_name] else: ret["result"] = False - ret["comment"] = "Failed to update GSI throughputs {}".format(index_updates) + ret["comment"] = f"Failed to update GSI throughputs {index_updates}" def _determine_gsi_updates(existing_index_names, provisioned_gsi_config, gsi_config): @@ -779,7 +777,7 @@ def _ensure_backup_datapipeline_present( ): kwargs = { - "name": "{}-{}-backup".format(name, schedule_name), + "name": f"{name}-{schedule_name}-backup", "pipeline_objects": { "DefaultSchedule": { "name": schedule_name, @@ -794,7 +792,7 @@ def _ensure_backup_datapipeline_present( }, "parameter_values": { "myDDBTableName": name, - "myOutputS3Loc": "{}/{}/".format(s3_base_location, name), + "myOutputS3Loc": f"{s3_base_location}/{name}/", }, } return __states__["boto_datapipeline.present"](**kwargs) @@ -860,20 +858,20 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ret = {"name": name, "result": True, "comment": "", "changes": {}} exists = __salt__["boto_dynamodb.exists"](name, region, key, keyid, profile) if not exists: - ret["comment"] = "DynamoDB table {} does not exist".format(name) + ret["comment"] = f"DynamoDB table {name} does not exist" return ret if __opts__["test"]: - ret["comment"] = "DynamoDB table {} is set to be deleted".format(name) + ret["comment"] = f"DynamoDB table {name} is set to be deleted" ret["result"] = None return ret is_deleted = __salt__["boto_dynamodb.delete"](name, region, key, keyid, profile) if is_deleted: - ret["comment"] = "Deleted DynamoDB table {}".format(name) - ret["changes"].setdefault("old", "Table {} exists".format(name)) - ret["changes"].setdefault("new", "Table {} deleted".format(name)) + ret["comment"] = f"Deleted DynamoDB table {name}" + ret["changes"].setdefault("old", f"Table {name} exists") + ret["changes"].setdefault("new", f"Table {name} deleted") else: - ret["comment"] = "Failed to delete DynamoDB table {}".format(name) + ret["comment"] = f"Failed to delete DynamoDB table {name}" ret["result"] = False return ret diff --git a/salt/states/boto_ec2.py b/salt/states/boto_ec2.py index 773016b48a7..6e7b1d3ea06 100644 --- a/salt/states/boto_ec2.py +++ b/salt/states/boto_ec2.py @@ -50,7 +50,6 @@ The below code deletes a key pair: - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ - import logging from time import sleep, time @@ -90,12 +89,12 @@ def key_present( upload_public = __salt__["cp.get_file_str"](upload_public) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(upload_public) + ret["comment"] = f"File {upload_public} not found." ret["result"] = False return ret if not exists: if __opts__["test"]: - ret["comment"] = "The key {} is set to be created.".format(name) + ret["comment"] = f"The key {name} is set to be created." ret["result"] = None return ret if save_private and not upload_public: @@ -104,29 +103,29 @@ def key_present( ) if created: ret["result"] = True - ret["comment"] = "The key {} is created.".format(name) + ret["comment"] = f"The key {name} is created." ret["changes"]["new"] = created else: ret["result"] = False - ret["comment"] = "Could not create key {} ".format(name) + ret["comment"] = f"Could not create key {name} " elif not save_private and upload_public: imported = __salt__["boto_ec2.import_key"]( name, upload_public, region, key, keyid, profile ) if imported: ret["result"] = True - ret["comment"] = "The key {} is created.".format(name) + ret["comment"] = f"The key {name} is created." ret["changes"]["old"] = None ret["changes"]["new"] = imported else: ret["result"] = False - ret["comment"] = "Could not create key {} ".format(name) + ret["comment"] = f"Could not create key {name} " else: ret["result"] = False ret["comment"] = "You can either upload or download a private key " else: ret["result"] = True - ret["comment"] = "The key name {} already exists".format(name) + ret["comment"] = f"The key name {name} already exists" return ret @@ -138,21 +137,21 @@ def key_absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_ec2.get_key"](name, region, key, keyid, profile) if exists: if __opts__["test"]: - ret["comment"] = "The key {} is set to be deleted.".format(name) + ret["comment"] = f"The key {name} is set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_ec2.delete_key"](name, region, key, keyid, profile) log.debug("exists is %s", deleted) if deleted: ret["result"] = True - ret["comment"] = "The key {} is deleted.".format(name) + ret["comment"] = f"The key {name} is deleted." ret["changes"]["old"] = name else: ret["result"] = False - ret["comment"] = "Could not delete key {} ".format(name) + ret["comment"] = f"Could not delete key {name} " else: ret["result"] = True - ret["comment"] = "The key name {} does not exist".format(name) + ret["comment"] = f"The key name {name} does not exist" return ret @@ -284,7 +283,7 @@ def eni_present( ) return ret r["result"] = result_create["result"] - ret["comment"] = "Created ENI {}".format(name) + ret["comment"] = f"Created ENI {name}" ret["changes"]["id"] = r["result"]["id"] else: _ret = _eni_attribute( @@ -422,7 +421,7 @@ def _eni_attribute(metadata, attr, value, region, key, keyid, profile): if metadata[attr] == value: return ret if __opts__["test"]: - ret["comment"] = "ENI set to have {} updated.".format(attr) + ret["comment"] = f"ENI set to have {attr} updated." ret["result"] = None return ret result_update = __salt__["boto_ec2.modify_network_interface_attribute"]( @@ -439,7 +438,7 @@ def _eni_attribute(metadata, attr, value, region, key, keyid, profile): ret["result"] = False ret["comment"] = msg.format(attr, result_update["error"]["message"]) else: - ret["comment"] = "Updated ENI {}.".format(attr) + ret["comment"] = f"Updated ENI {attr}." ret["changes"][attr] = {"old": metadata[attr], "new": value} return ret @@ -561,7 +560,7 @@ def eni_absent( result_delete["error"]["message"] ) return ret - ret["comment"] = "Deleted ENI {}".format(name) + ret["comment"] = f"Deleted ENI {name}" ret["changes"]["id"] = None if release_eip and "allocationId" in r["result"]: _ret = __salt__["boto_ec2.release_eip_address"]( @@ -590,7 +589,7 @@ def snapshot_created( instance_name, wait_until_available=True, wait_timeout_seconds=300, - **kwargs + **kwargs, ): """ Create a snapshot from the given instance @@ -602,11 +601,11 @@ def snapshot_created( if not __salt__["boto_ec2.create_image"]( ami_name=ami_name, instance_name=instance_name, **kwargs ): - ret["comment"] = "Failed to create new AMI {ami_name}".format(ami_name=ami_name) + ret["comment"] = f"Failed to create new AMI {ami_name}" ret["result"] = False return ret - ret["comment"] = "Created new AMI {ami_name}".format(ami_name=ami_name) + ret["comment"] = f"Created new AMI {ami_name}" ret["changes"]["new"] = {ami_name: ami_name} if not wait_until_available: return ret @@ -624,10 +623,10 @@ def snapshot_created( state=images[0].state ) else: - ret[ - "comment" - ] = "AMI with name {ami_name} not found after timeout.".format( - ami_name=ami_name + ret["comment"] = ( + "AMI with name {ami_name} not found after timeout.".format( + ami_name=ami_name + ) ) ret["result"] = False return ret @@ -888,7 +887,7 @@ def instance_present( if _create: if __opts__["test"]: - ret["comment"] = "The instance {} is set to be created.".format(name) + ret["comment"] = f"The instance {name} is set to be created." ret["result"] = None return ret if image_name: @@ -1007,15 +1006,15 @@ def instance_present( if r[0].get("instance_id"): if r[0]["instance_id"] != instance_id: ret["result"] = False - ret[ - "comment" - ] = "EIP {} is already associated with instance {}.".format( - public_ip if public_ip else allocation_id, r[0]["instance_id"] + ret["comment"] = ( + "EIP {} is already associated with instance {}.".format( + public_ip if public_ip else allocation_id, r[0]["instance_id"] + ) ) return ret else: if __opts__["test"]: - ret["comment"] = "Instance {} to be updated.".format(name) + ret["comment"] = f"Instance {name} to be updated." ret["result"] = None return ret r = __salt__["boto_ec2.associate_eip_address"]( @@ -1070,10 +1069,10 @@ def instance_present( ) except SaltInvocationError as e: ret["result"] = False - ret[ - "comment" - ] = "Failed to set attribute {} to {} on instance {}.".format( - k, v, instance_name + ret["comment"] = ( + "Failed to set attribute {} to {} on instance {}.".format( + k, v, instance_name + ) ) return ret ret["changes"] = ( @@ -1248,7 +1247,7 @@ def instance_absent( ) if not instances: ret["result"] = True - ret["comment"] = "Instance {} is already gone.".format(instance_id) + ret["comment"] = f"Instance {instance_id} is already gone." return ret instance = instances[0] @@ -1269,7 +1268,7 @@ def instance_absent( return ret if __opts__["test"]: - ret["comment"] = "The instance {} is set to be deleted.".format(name) + ret["comment"] = f"The instance {name} is set to be deleted." ret["result"] = None return ret @@ -1283,7 +1282,7 @@ def instance_absent( ) if not r: ret["result"] = False - ret["comment"] = "Failed to terminate instance {}.".format(instance_id) + ret["comment"] = f"Failed to terminate instance {instance_id}." return ret ret["changes"]["old"] = {"instance_id": instance_id} @@ -1309,9 +1308,7 @@ def instance_absent( else: # I /believe/ this situation is impossible but let's hedge our bets... ret["result"] = False - ret[ - "comment" - ] = "Can't determine AllocationId for address {}.".format(ip) + ret["comment"] = f"Can't determine AllocationId for address {ip}." return ret else: public_ip = instance.ip_address @@ -1330,7 +1327,7 @@ def instance_absent( ret["changes"]["old"]["public_ip"] = public_ip or r[0]["public_ip"] else: ret["result"] = False - ret["comment"] = "Failed to release EIP {}.".format(ip) + ret["comment"] = f"Failed to release EIP {ip}." return ret return ret @@ -1450,14 +1447,14 @@ def volume_absent( log.info("Matched Volume ID %s", vol) if __opts__["test"]: - ret["comment"] = "The volume {} is set to be deleted.".format(vol) + ret["comment"] = f"The volume {vol} is set to be deleted." ret["result"] = None return ret if __salt__["boto_ec2.delete_volume"](volume_id=vol, force=True, **args): - ret["comment"] = "Volume {} deleted.".format(vol) + ret["comment"] = f"Volume {vol} deleted." ret["changes"] = {"old": {"volume_id": vol}, "new": {"volume_id": None}} else: - ret["comment"] = "Error deleting volume {}.".format(vol) + ret["comment"] = f"Error deleting volume {vol}." ret["result"] = False return ret @@ -1665,9 +1662,7 @@ def volume_present( name=instance_name, in_states=running_states, **args ) if not instance_id: - raise SaltInvocationError( - "Instance with Name {} not found.".format(instance_name) - ) + raise SaltInvocationError(f"Instance with Name {instance_name} not found.") instances = __salt__["boto_ec2.find_instances"]( instance_id=instance_id, return_objs=True, **args @@ -1700,13 +1695,13 @@ def volume_present( encrypted=encrypted, kms_key_id=kms_key_id, wait_for_creation=True, - **args + **args, ) if "result" in _rt: volume_id = _rt["result"] else: raise SaltInvocationError( - "Error creating volume with name {}.".format(volume_name) + f"Error creating volume with name {volume_name}." ) _rt = __salt__["boto_ec2.set_volumes_tags"]( tag_maps=[ @@ -1715,7 +1710,7 @@ def volume_present( "tags": {"Name": volume_name}, } ], - **args + **args, ) if _rt["success"] is False: raise SaltInvocationError( @@ -1731,7 +1726,7 @@ def volume_present( volume_ids=[volume_id], return_objs=True, **args ) if len(vols) < 1: - raise SaltInvocationError("Volume {} do not exist".format(volume_id)) + raise SaltInvocationError(f"Volume {volume_id} do not exist") vol = vols[0] if vol.zone != instance.placement: raise SaltInvocationError( @@ -1748,14 +1743,14 @@ def volume_present( return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "The volume {} is set to be detached from {}({} and attached on {}({}).".format( - attach_data.instance_id, - attach_data.devic, - volume_id, - instance_id, - device, + ret["comment"] = ( + "The volume {} is set to be detached from {}({} and attached on {}({}).".format( + attach_data.instance_id, + attach_data.devic, + volume_id, + instance_id, + device, + ) ) ret["result"] = None return ret @@ -1956,7 +1951,6 @@ def private_ips_absent( keyid=None, profile=None, ): - """ Ensure an ENI does not have secondary private ip addresses associated with it diff --git a/salt/states/boto_elasticache.py b/salt/states/boto_elasticache.py index f46b2f7a1b4..b5520bfc7da 100644 --- a/salt/states/boto_elasticache.py +++ b/salt/states/boto_elasticache.py @@ -75,7 +75,6 @@ passed in as a dict, or as a string to pull from pillars or minion config: key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ - import logging log = logging.getLogger(__name__) @@ -227,7 +226,7 @@ def present( return ret elif not config: if __opts__["test"]: - msg = "Cache cluster {} is set to be created.".format(name) + msg = f"Cache cluster {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -261,11 +260,11 @@ def present( ret["changes"]["new"] = config else: ret["result"] = False - ret["comment"] = "Failed to create {} cache cluster.".format(name) + ret["comment"] = f"Failed to create {name} cache cluster." return ret # TODO: support modification of existing elasticache clusters else: - ret["comment"] = "Cache cluster {} is present.".format(name) + ret["comment"] = f"Cache cluster {name} is present." return ret @@ -320,7 +319,7 @@ def subnet_group_present( ) if not exists: if __opts__["test"]: - ret["comment"] = "Subnet group {} is set to be created.".format(name) + ret["comment"] = f"Subnet group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_elasticache.create_subnet_group"]( @@ -336,11 +335,11 @@ def subnet_group_present( ) if not created: ret["result"] = False - ret["comment"] = "Failed to create {} subnet group.".format(name) + ret["comment"] = f"Failed to create {name} subnet group." return ret ret["changes"]["old"] = None ret["changes"]["new"] = name - ret["comment"] = "Subnet group {} created.".format(name) + ret["comment"] = f"Subnet group {name} created." return ret ret["comment"] = "Subnet group present." return ret @@ -380,7 +379,7 @@ def absent(name, wait=True, region=None, key=None, keyid=None, profile=None): if is_present: if __opts__["test"]: - ret["comment"] = "Cache cluster {} is set to be removed.".format(name) + ret["comment"] = f"Cache cluster {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_elasticache.delete"]( @@ -391,9 +390,9 @@ def absent(name, wait=True, region=None, key=None, keyid=None, profile=None): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} cache cluster.".format(name) + ret["comment"] = f"Failed to delete {name} cache cluster." else: - ret["comment"] = "{} does not exist in {}.".format(name, region) + ret["comment"] = f"{name} does not exist in {region}." return ret @@ -445,7 +444,7 @@ def creategroup( ) if not is_present: if __opts__["test"]: - ret["comment"] = "Replication {} is set to be created.".format(name) + ret["comment"] = f"Replication {name} is set to be created." ret["result"] = None created = __salt__["boto_elasticache.create_replication_group"]( name, @@ -466,9 +465,9 @@ def creategroup( ret["result"] = True else: ret["result"] = False - ret["comment"] = "Failed to create {} replication group.".format(name) + ret["comment"] = f"Failed to create {name} replication group." else: - ret["comment"] = "{} replication group exists .".format(name) + ret["comment"] = f"{name} replication group exists ." ret["result"] = True return ret @@ -483,7 +482,7 @@ def subnet_group_absent( ) if not exists: ret["result"] = True - ret["comment"] = "{} ElastiCache subnet group does not exist.".format(name) + ret["comment"] = f"{name} ElastiCache subnet group does not exist." return ret if __opts__["test"]: @@ -497,11 +496,11 @@ def subnet_group_absent( ) if not deleted: ret["result"] = False - ret["comment"] = "Failed to delete {} ElastiCache subnet group.".format(name) + ret["comment"] = f"Failed to delete {name} ElastiCache subnet group." return ret ret["changes"]["old"] = name ret["changes"]["new"] = None - ret["comment"] = "ElastiCache subnet group {} deleted.".format(name) + ret["comment"] = f"ElastiCache subnet group {name} deleted." return ret @@ -515,14 +514,12 @@ def replication_group_absent( ) if not exists: ret["result"] = True - ret["comment"] = "{} ElastiCache replication group does not exist.".format(name) + ret["comment"] = f"{name} ElastiCache replication group does not exist." log.info(ret["comment"]) return ret if __opts__["test"]: - ret[ - "comment" - ] = "ElastiCache replication group {} is set to be removed.".format(name) + ret["comment"] = f"ElastiCache replication group {name} is set to be removed." ret["result"] = True return ret deleted = __salt__["boto_elasticache.delete_replication_group"]( @@ -537,6 +534,6 @@ def replication_group_absent( return ret ret["changes"]["old"] = name ret["changes"]["new"] = None - ret["comment"] = "ElastiCache replication group {} deleted.".format(name) + ret["comment"] = f"ElastiCache replication group {name} deleted." log.info(ret["comment"]) return ret diff --git a/salt/states/boto_elasticsearch_domain.py b/salt/states/boto_elasticsearch_domain.py index 4c47222b560..e682c463257 100644 --- a/salt/states/boto_elasticsearch_domain.py +++ b/salt/states/boto_elasticsearch_domain.py @@ -77,7 +77,6 @@ config: """ - import logging import os @@ -222,7 +221,7 @@ def present( AccessPolicies = salt.utils.json.loads(AccessPolicies) except ValueError as e: ret["result"] = False - ret["comment"] = "Failed to create domain: {}.".format(e.message) + ret["comment"] = f"Failed to create domain: {e.message}." return ret r = __salt__["boto_elasticsearch_domain.exists"]( DomainName=DomainName, region=region, key=key, keyid=keyid, profile=profile @@ -235,7 +234,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Domain {} is set to be created.".format(DomainName) + ret["comment"] = f"Domain {DomainName} is set to be created." ret["result"] = None return ret r = __salt__["boto_elasticsearch_domain.create"]( @@ -262,11 +261,11 @@ def present( ) ret["changes"]["old"] = {"domain": None} ret["changes"]["new"] = _describe - ret["comment"] = "Domain {} created.".format(DomainName) + ret["comment"] = f"Domain {DomainName} created." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Domain {} is present.".format(DomainName)] + [ret["comment"], f"Domain {DomainName} is present."] ) ret["changes"] = {} # domain exists, ensure config matches @@ -275,11 +274,11 @@ def present( )["domain"] if _status.get("ElasticsearchVersion") != str(ElasticsearchVersion): ret["result"] = False - ret[ - "comment" - ] = "Failed to update domain: version cannot be modified from {} to {}.".format( - _status.get("ElasticsearchVersion"), - str(ElasticsearchVersion), + ret["comment"] = ( + "Failed to update domain: version cannot be modified from {} to {}.".format( + _status.get("ElasticsearchVersion"), + str(ElasticsearchVersion), + ) ) return ret _describe = __salt__["boto_elasticsearch_domain.describe"]( @@ -311,7 +310,7 @@ def present( ret["changes"].setdefault("old", {})[k] = _describe[k] if need_update: if __opts__["test"]: - msg = "Domain {} set to be modified.".format(DomainName) + msg = f"Domain {DomainName} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -324,7 +323,7 @@ def present( key=key, keyid=keyid, profile=profile, - **comm_args + **comm_args, ) if not r.get("updated"): ret["result"] = False @@ -369,11 +368,11 @@ def absent(name, DomainName, region=None, key=None, keyid=None, profile=None): return ret if r and not r["exists"]: - ret["comment"] = "Domain {} does not exist.".format(DomainName) + ret["comment"] = f"Domain {DomainName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Domain {} is set to be removed.".format(DomainName) + ret["comment"] = f"Domain {DomainName} is set to be removed." ret["result"] = None return ret @@ -386,5 +385,5 @@ def absent(name, DomainName, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"domain": DomainName} ret["changes"]["new"] = {"domain": None} - ret["comment"] = "Domain {} deleted.".format(DomainName) + ret["comment"] = f"Domain {DomainName} deleted." return ret diff --git a/salt/states/boto_elb.py b/salt/states/boto_elb.py index 0fd59a31088..7499f9c1008 100644 --- a/salt/states/boto_elb.py +++ b/salt/states/boto_elb.py @@ -234,7 +234,6 @@ Tags can also be set: OtherTag: 'My Other Value' """ - import hashlib import logging import re @@ -549,7 +548,7 @@ def present( if __salt__["boto_elb.set_instances"]( name, instance_ids, True, region, key, keyid, profile ): - ret["comment"] += " ELB {} instances would be updated.".format(name) + ret["comment"] += f" ELB {name} instances would be updated." ret["result"] = None else: success = __salt__["boto_elb.set_instances"]( @@ -592,7 +591,7 @@ def register_instances( ret = {"name": name, "result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not lb: - msg = "Could not find lb {}".format(name) + msg = f"Could not find lb {name}" log.error(msg) ret.update({"comment": msg, "result": False}) return ret @@ -611,7 +610,7 @@ def register_instances( return ret if __opts__["test"]: - ret["comment"] = "ELB {} is set to register : {}.".format(name, new) + ret["comment"] = f"ELB {name} is set to register : {new}." ret["result"] = None return ret @@ -619,7 +618,7 @@ def register_instances( name, instances, region, key, keyid, profile ) if state: - msg = "Load Balancer {} has been changed".format(name) + msg = f"Load Balancer {name} has been changed" log.info(msg) new = set().union(nodes, instances) ret.update( @@ -629,7 +628,7 @@ def register_instances( } ) else: - msg = "Load balancer {} failed to add instances".format(name) + msg = f"Load balancer {name} failed to add instances" log.error(msg) ret.update({"comment": msg, "result": False}) return ret @@ -706,7 +705,7 @@ def _elb_present( ret["result"] = False return ret if "id" not in r: - ret["comment"] = "Subnet {} does not exist.".format(i) + ret["comment"] = f"Subnet {i} does not exist." ret["result"] = False return ret subnets.append(r["id"]) @@ -718,7 +717,7 @@ def _elb_present( ) vpc_id = vpc_id.get("vpc_id") if not vpc_id: - ret["comment"] = "Subnets {} do not map to a valid vpc id.".format(subnets) + ret["comment"] = f"Subnets {subnets} do not map to a valid vpc id." ret["result"] = False return ret _security_groups = __salt__["boto_secgroup.convert_to_group_ids"]( @@ -730,17 +729,17 @@ def _elb_present( profile=profile, ) if not _security_groups: - ret[ - "comment" - ] = "Security groups {} do not map to valid security group ids.".format( - security_groups + ret["comment"] = ( + "Security groups {} do not map to valid security group ids.".format( + security_groups + ) ) ret["result"] = False return ret exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if not exists: if __opts__["test"]: - ret["comment"] = "ELB {} is set to be created.".format(name) + ret["comment"] = f"ELB {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_elb.create"]( @@ -758,12 +757,12 @@ def _elb_present( if created: ret["changes"]["old"] = {"elb": None} ret["changes"]["new"] = {"elb": name} - ret["comment"] = "ELB {} created.".format(name) + ret["comment"] = f"ELB {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} ELB.".format(name) + ret["comment"] = f"Failed to create {name} ELB." else: - ret["comment"] = "ELB {} present.".format(name) + ret["comment"] = f"ELB {name} present." _ret = _security_groups_present( name, _security_groups, region, key, keyid, profile ) @@ -805,7 +804,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: - ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} ELB configuration could not be retrieved." ret["result"] = False return ret if not listeners: @@ -833,7 +832,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): if __opts__["test"]: msg = [] if to_create or to_delete: - msg.append("ELB {} set to have listeners modified:".format(name)) + msg.append(f"ELB {name} set to have listeners modified:") for listener in to_create: msg.append( "Listener {} added.".format( @@ -848,7 +847,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): ) ret["result"] = None else: - msg.append("Listeners already set on ELB {}.".format(name)) + msg.append(f"Listeners already set on ELB {name}.") ret["comment"] = " ".join(msg) return ret @@ -858,9 +857,9 @@ def _listeners_present(name, listeners, region, key, keyid, profile): name, ports, region, key, keyid, profile ) if deleted: - ret["comment"] = "Deleted listeners on {} ELB.".format(name) + ret["comment"] = f"Deleted listeners on {name} ELB." else: - ret["comment"] = "Failed to delete listeners on {} ELB.".format(name) + ret["comment"] = f"Failed to delete listeners on {name} ELB." ret["result"] = False if to_create: @@ -881,7 +880,7 @@ def _listeners_present(name, listeners, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["listeners"]["new"] = lb["listeners"] else: - ret["comment"] = "Listeners already set on ELB {}.".format(name) + ret["comment"] = f"Listeners already set on ELB {name}." return ret @@ -890,7 +889,7 @@ def _security_groups_present(name, security_groups, region, key, keyid, profile) ret = {"result": True, "comment": "", "changes": {}} lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: - ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} ELB configuration could not be retrieved." ret["result"] = False return ret if not security_groups: @@ -900,21 +899,21 @@ def _security_groups_present(name, security_groups, region, key, keyid, profile) change_needed = True if change_needed: if __opts__["test"]: - ret["comment"] = "ELB {} set to have security groups modified.".format(name) + ret["comment"] = f"ELB {name} set to have security groups modified." ret["result"] = None return ret changed = __salt__["boto_elb.apply_security_groups"]( name, security_groups, region, key, keyid, profile ) if changed: - ret["comment"] = "Modified security_groups on {} ELB.".format(name) + ret["comment"] = f"Modified security_groups on {name} ELB." else: - ret["comment"] = "Failed to modify security_groups on {} ELB.".format(name) + ret["comment"] = f"Failed to modify security_groups on {name} ELB." ret["result"] = False ret["changes"]["old"] = {"security_groups": lb["security_groups"]} ret["changes"]["new"] = {"security_groups": security_groups} else: - ret["comment"] = "security_groups already set on ELB {}.".format(name) + ret["comment"] = f"security_groups already set on ELB {name}." return ret @@ -923,7 +922,7 @@ def _attributes_present(name, attributes, region, key, keyid, profile): _attributes = __salt__["boto_elb.get_attributes"](name, region, key, keyid, profile) if not _attributes: ret["result"] = False - ret["comment"] = "Failed to retrieve attributes for ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve attributes for ELB {name}." return ret attrs_to_set = [] if "cross_zone_load_balancing" in attributes: @@ -955,7 +954,7 @@ def _attributes_present(name, attributes, region, key, keyid, profile): ) if attrs_to_set: if __opts__["test"]: - ret["comment"] = "ELB {} set to have attributes set.".format(name) + ret["comment"] = f"ELB {name} set to have attributes set." ret["result"] = None return ret was_set = __salt__["boto_elb.set_attributes"]( @@ -964,12 +963,12 @@ def _attributes_present(name, attributes, region, key, keyid, profile): if was_set: ret["changes"]["old"] = {"attributes": _attributes} ret["changes"]["new"] = {"attributes": attributes} - ret["comment"] = "Set attributes on ELB {}.".format(name) + ret["comment"] = f"Set attributes on ELB {name}." else: ret["result"] = False - ret["comment"] = "Failed to set attributes on ELB {}.".format(name) + ret["comment"] = f"Failed to set attributes on ELB {name}." else: - ret["comment"] = "Attributes already set on ELB {}.".format(name) + ret["comment"] = f"Attributes already set on ELB {name}." return ret @@ -982,7 +981,7 @@ def _health_check_present(name, health_check, region, key, keyid, profile): ) if not _health_check: ret["result"] = False - ret["comment"] = "Failed to retrieve health_check for ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve health_check for ELB {name}." return ret need_to_set = False for attr, val in health_check.items(): @@ -990,7 +989,7 @@ def _health_check_present(name, health_check, region, key, keyid, profile): need_to_set = True if need_to_set: if __opts__["test"]: - ret["comment"] = "ELB {} set to have health check set.".format(name) + ret["comment"] = f"ELB {name} set to have health check set." ret["result"] = None return ret was_set = __salt__["boto_elb.set_health_check"]( @@ -1002,12 +1001,12 @@ def _health_check_present(name, health_check, region, key, keyid, profile): name, region, key, keyid, profile ) ret["changes"]["new"] = {"health_check": _health_check} - ret["comment"] = "Set health check on ELB {}.".format(name) + ret["comment"] = f"Set health check on ELB {name}." else: ret["result"] = False - ret["comment"] = "Failed to set health check on ELB {}.".format(name) + ret["comment"] = f"Failed to set health check on ELB {name}." else: - ret["comment"] = "Health check already set on ELB {}.".format(name) + ret["comment"] = f"Health check already set on ELB {name}." return ret @@ -1016,7 +1015,7 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["result"] = False - ret["comment"] = "Failed to retrieve ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve ELB {name}." return ret to_enable = [] to_disable = [] @@ -1029,7 +1028,7 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): to_disable.append(zone) if to_enable or to_disable: if __opts__["test"]: - ret["comment"] = "ELB {} to have availability zones set.".format(name) + ret["comment"] = f"ELB {name} to have availability zones set." ret["result"] = None return ret if to_enable: @@ -1037,11 +1036,9 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): name, to_enable, region, key, keyid, profile ) if enabled: - ret["comment"] = "Enabled availability zones on {} ELB.".format(name) + ret["comment"] = f"Enabled availability zones on {name} ELB." else: - ret[ - "comment" - ] = "Failed to enable availability zones on {} ELB.".format(name) + ret["comment"] = f"Failed to enable availability zones on {name} ELB." ret["result"] = False if to_disable: disabled = __salt__["boto_elb.disable_availability_zones"]( @@ -1058,7 +1055,7 @@ def _zones_present(name, availability_zones, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["new"] = {"availability_zones": lb["availability_zones"]} else: - ret["comment"] = "Availability zones already set on ELB {}.".format(name) + ret["comment"] = f"Availability zones already set on ELB {name}." return ret @@ -1069,7 +1066,7 @@ def _subnets_present(name, subnets, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: ret["result"] = False - ret["comment"] = "Failed to retrieve ELB {}.".format(name) + ret["comment"] = f"Failed to retrieve ELB {name}." return ret to_enable = [] to_disable = [] @@ -1082,7 +1079,7 @@ def _subnets_present(name, subnets, region, key, keyid, profile): to_disable.append(subnet) if to_enable or to_disable: if __opts__["test"]: - ret["comment"] = "ELB {} to have subnets set.".format(name) + ret["comment"] = f"ELB {name} to have subnets set." ret["result"] = None return ret if to_enable: @@ -1090,9 +1087,9 @@ def _subnets_present(name, subnets, region, key, keyid, profile): name, to_enable, region, key, keyid, profile ) if attached: - ret["comment"] = "Attached subnets on {} ELB.".format(name) + ret["comment"] = f"Attached subnets on {name} ELB." else: - ret["comment"] = "Failed to attach subnets on {} ELB.".format(name) + ret["comment"] = f"Failed to attach subnets on {name} ELB." ret["result"] = False if to_disable: detached = __salt__["boto_elb.detach_subnets"]( @@ -1100,13 +1097,13 @@ def _subnets_present(name, subnets, region, key, keyid, profile): ) if detached: ret["comment"] = " ".join( - [ret["comment"], "Detached subnets on {} ELB.".format(name)] + [ret["comment"], f"Detached subnets on {name} ELB."] ) else: ret["comment"] = " ".join( [ ret["comment"], - "Failed to detach subnets on {} ELB.".format(name), + f"Failed to detach subnets on {name} ELB.", ] ) ret["result"] = False @@ -1114,7 +1111,7 @@ def _subnets_present(name, subnets, region, key, keyid, profile): lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) ret["changes"]["new"] = {"subnets": lb["subnets"]} else: - ret["comment"] = "Subnets already set on ELB {}.".format(name) + ret["comment"] = f"Subnets already set on ELB {name}." return ret @@ -1210,7 +1207,7 @@ def _policies_present( lb = __salt__["boto_elb.get_elb_config"](name, region, key, keyid, profile) if not lb: - ret["comment"] = "{} ELB configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} ELB configuration could not be retrieved." ret["result"] = False return ret @@ -1296,18 +1293,18 @@ def _policies_present( if __opts__["test"]: msg = [] if to_create or to_delete: - msg.append("ELB {} set to have policies modified:".format(name)) + msg.append(f"ELB {name} set to have policies modified:") for policy in to_create: - msg.append("Policy {} added.".format(policy)) + msg.append(f"Policy {policy} added.") for policy in to_delete: - msg.append("Policy {} deleted.".format(policy)) + msg.append(f"Policy {policy} deleted.") ret["result"] = None else: - msg.append("Policies already set on ELB {}.".format(name)) + msg.append(f"Policies already set on ELB {name}.") for listener in listeners_to_update: - msg.append("Listener {} policies updated.".format(listener)) + msg.append(f"Listener {listener} policies updated.") for backend in backends_to_update: - msg.append("Backend {} policies updated.".format(backend)) + msg.append(f"Backend {backend} policies updated.") ret["comment"] = " ".join(msg) return ret @@ -1325,7 +1322,7 @@ def _policies_present( ) if created: ret["changes"].setdefault(policy_name, {})["new"] = policy_name - comment = "Policy {} was created on ELB {}".format(policy_name, name) + comment = f"Policy {policy_name} was created on ELB {name}" ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: @@ -1343,7 +1340,7 @@ def _policies_present( profile=profile, ) if policy_set: - policy_key = "listener_{}_policy".format(port) + policy_key = f"listener_{port}_policy" ret["changes"][policy_key] = { "old": list(actual_policies_by_listener.get(port, [])), "new": list(expected_policies_by_listener.get(port, [])), @@ -1368,7 +1365,7 @@ def _policies_present( profile=profile, ) if policy_set: - policy_key = "backend_{}_policy".format(port) + policy_key = f"backend_{port}_policy" ret["changes"][policy_key] = { "old": list(actual_policies_by_backend.get(port, [])), "new": list(expected_policies_by_backend.get(port, [])), @@ -1394,7 +1391,7 @@ def _policies_present( ) if deleted: ret["changes"].setdefault(policy_name, {})["old"] = policy_name - comment = "Policy {} was deleted from ELB {}".format(policy_name, name) + comment = f"Policy {policy_name} was deleted from ELB {name}" ret["comment"] = " ".join([ret["comment"], comment]) ret["result"] = True else: @@ -1413,7 +1410,7 @@ def _policy_cname(policy_dict): ).hexdigest() if policy_type.endswith("Type"): policy_type = policy_type[:-4] - return "{}-{}-{}".format(policy_type, policy_name, policy_hash) + return f"{policy_type}-{policy_name}-{policy_hash}" def absent(name, region=None, key=None, keyid=None, profile=None): @@ -1428,19 +1425,19 @@ def absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_elb.exists"](name, region, key, keyid, profile) if exists: if __opts__["test"]: - ret["comment"] = "ELB {} is set to be removed.".format(name) + ret["comment"] = f"ELB {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_elb.delete"](name, region, key, keyid, profile) if deleted: ret["changes"]["old"] = {"elb": name} ret["changes"]["new"] = {"elb": None} - ret["comment"] = "ELB {} deleted.".format(name) + ret["comment"] = f"ELB {name} deleted." else: ret["result"] = False - ret["comment"] = "Failed to delete {} ELB.".format(name) + ret["comment"] = f"Failed to delete {name} ELB." else: - ret["comment"] = "{} ELB does not exist.".format(name) + ret["comment"] = f"{name} ELB does not exist." return ret @@ -1478,7 +1475,7 @@ def _tags_present(name, tags, region, key, keyid, profile): ) if not _ret: ret["result"] = False - msg = "Error attempting to delete tag {}.".format(tags_to_remove) + msg = f"Error attempting to delete tag {tags_to_remove}." ret["comment"] = " ".join([ret["comment"], msg]) return ret if "old" not in ret["changes"]: diff --git a/salt/states/boto_elbv2.py b/salt/states/boto_elbv2.py index b3c2fe2a2e0..480d5b3b04a 100644 --- a/salt/states/boto_elbv2.py +++ b/salt/states/boto_elbv2.py @@ -64,9 +64,8 @@ def create_target_group( health_check_timeout_seconds=5, healthy_threshold_count=5, unhealthy_threshold_count=2, - **kwargs + **kwargs, ): - """ .. versionadded:: 2017.11.0 @@ -122,11 +121,11 @@ def create_target_group( if __salt__["boto_elbv2.target_group_exists"](name, region, key, keyid, profile): ret["result"] = True - ret["comment"] = "Target Group {} already exists".format(name) + ret["comment"] = f"Target Group {name} already exists" return ret if __opts__["test"]: - ret["comment"] = "Target Group {} will be created".format(name) + ret["comment"] = f"Target Group {name} will be created" return ret state = __salt__["boto_elbv2.create_target_group"]( @@ -145,16 +144,16 @@ def create_target_group( health_check_timeout_seconds=health_check_timeout_seconds, healthy_threshold_count=healthy_threshold_count, unhealthy_threshold_count=unhealthy_threshold_count, - **kwargs + **kwargs, ) if state: ret["changes"]["target_group"] = name ret["result"] = True - ret["comment"] = "Target Group {} created".format(name) + ret["comment"] = f"Target Group {name} created" else: ret["result"] = False - ret["comment"] = "Target Group {} creation failed".format(name) + ret["comment"] = f"Target Group {name} creation failed" return ret @@ -185,11 +184,11 @@ def delete_target_group(name, region=None, key=None, keyid=None, profile=None): name, region, key, keyid, profile ): ret["result"] = True - ret["comment"] = "Target Group {} does not exists".format(name) + ret["comment"] = f"Target Group {name} does not exists" return ret if __opts__["test"]: - ret["comment"] = "Target Group {} will be deleted".format(name) + ret["comment"] = f"Target Group {name} will be deleted" return ret state = __salt__["boto_elbv2.delete_target_group"]( @@ -199,10 +198,10 @@ def delete_target_group(name, region=None, key=None, keyid=None, profile=None): if state: ret["result"] = True ret["changes"]["target_group"] = name - ret["comment"] = "Target Group {} deleted".format(name) + ret["comment"] = f"Target Group {name} deleted" else: ret["result"] = False - ret["comment"] = "Target Group {} deletion failed".format(name) + ret["comment"] = f"Target Group {name} deletion failed" return ret @@ -277,18 +276,18 @@ def targets_registered( if changes: ret["changes"]["old"] = health if __opts__["test"]: - ret["comment"] = "Target Group {} would be changed".format(name) + ret["comment"] = f"Target Group {name} would be changed" ret["result"] = None ret["changes"]["new"] = newhealth_mock else: - ret["comment"] = "Target Group {} has been changed".format(name) + ret["comment"] = f"Target Group {name} has been changed" newhealth = __salt__["boto_elbv2.describe_target_health"]( name, region=region, key=key, keyid=keyid, profile=profile ) ret["changes"]["new"] = newhealth return ret else: - ret["comment"] = "Could not find target group {}".format(name) + ret["comment"] = f"Could not find target group {name}" return ret @@ -327,9 +326,9 @@ def targets_deregistered( targets = [targets] for target in targets: if target not in health or health.get(target) == "draining": - ret["comment"] = ret[ - "comment" - ] + "Target/s {} already deregistered\n".format(target) + ret["comment"] = ( + ret["comment"] + f"Target/s {target} already deregistered\n" + ) ret["result"] = True else: if __opts__["test"]: @@ -348,25 +347,23 @@ def targets_deregistered( changes = True ret["result"] = True else: - ret[ - "comment" - ] = "Target Group {} failed to remove targets".format(name) + ret["comment"] = f"Target Group {name} failed to remove targets" failure = True if failure: ret["result"] = False if changes: ret["changes"]["old"] = health if __opts__["test"]: - ret["comment"] = "Target Group {} would be changed".format(name) + ret["comment"] = f"Target Group {name} would be changed" ret["result"] = None ret["changes"]["new"] = newhealth_mock else: - ret["comment"] = "Target Group {} has been changed".format(name) + ret["comment"] = f"Target Group {name} has been changed" newhealth = __salt__["boto_elbv2.describe_target_health"]( name, region=region, key=key, keyid=keyid, profile=profile ) ret["changes"]["new"] = newhealth return ret else: - ret["comment"] = "Could not find target group {}".format(name) + ret["comment"] = f"Could not find target group {name}" return ret diff --git a/salt/states/boto_iam.py b/salt/states/boto_iam.py index 93400521fce..d89573cf5ae 100644 --- a/salt/states/boto_iam.py +++ b/salt/states/boto_iam.py @@ -155,7 +155,7 @@ def __virtual__(): else: return ( False, - "Cannot load {} state: boto_iam module unavailable".format(__virtualname__), + f"Cannot load {__virtualname__} state: boto_iam module unavailable", ) @@ -207,7 +207,7 @@ def user_absent( ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_user"](name, region, key, keyid, profile): ret["result"] = True - ret["comment"] = "IAM User {} does not exist.".format(name) + ret["comment"] = f"IAM User {name} does not exist." return ret # delete the user's access keys if delete_keys: @@ -297,7 +297,7 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "Virtual MFA device {} is deleted.".format(serial), + f"Virtual MFA device {serial} is deleted.", ] ) # delete the user's login profile @@ -306,7 +306,7 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} login profile is set to be deleted.".format(name), + f"IAM user {name} login profile is set to be deleted.", ] ) ret["result"] = None @@ -318,14 +318,14 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} login profile is deleted.".format(name), + f"IAM user {name} login profile is deleted.", ] ) if __opts__["test"]: ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} managed policies are set to be detached.".format(name), + f"IAM user {name} managed policies are set to be detached.", ] ) ret["result"] = None @@ -340,7 +340,7 @@ def user_absent( ret["comment"] = " ".join( [ ret["comment"], - "IAM user {} inline policies are set to be deleted.".format(name), + f"IAM user {name} inline policies are set to be deleted.", ] ) ret["result"] = None @@ -354,19 +354,17 @@ def user_absent( # finally, actually delete the user if __opts__["test"]: ret["comment"] = " ".join( - [ret["comment"], "IAM user {} is set to be deleted.".format(name)] + [ret["comment"], f"IAM user {name} is set to be deleted."] ) ret["result"] = None return ret deleted = __salt__["boto_iam.delete_user"](name, region, key, keyid, profile) if deleted is True: - ret["comment"] = " ".join( - [ret["comment"], "IAM user {} is deleted.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"IAM user {name} is deleted."]) ret["result"] = True ret["changes"]["deleted"] = name return ret - ret["comment"] = "IAM user {} could not be deleted.\n {}".format(name, deleted) + ret["comment"] = f"IAM user {name} could not be deleted.\n {deleted}" ret["result"] = False return ret @@ -418,14 +416,14 @@ def keys_present( ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_user"](name, region, key, keyid, profile): ret["result"] = False - ret["comment"] = "IAM User {} does not exist.".format(name) + ret["comment"] = f"IAM User {name} does not exist." return ret if not isinstance(number, int): ret["comment"] = "The number of keys must be an integer." ret["result"] = False return ret if not os.path.isdir(save_dir): - ret["comment"] = "The directory {} does not exist.".format(save_dir) + ret["comment"] = f"The directory {save_dir} does not exist." ret["result"] = False return ret keys = __salt__["boto_iam.get_all_access_keys"]( @@ -434,7 +432,7 @@ def keys_present( if isinstance(keys, str): log.debug("keys are : false %s", keys) error, message = _get_error(keys) - ret["comment"] = "Could not get keys.\n{}\n{}".format(error, message) + ret["comment"] = f"Could not get keys.\n{error}\n{message}" ret["result"] = False return ret keys = keys["list_access_keys_response"]["list_access_keys_result"][ @@ -442,11 +440,11 @@ def keys_present( ] log.debug("Keys are : %s.", keys) if len(keys) >= number: - ret["comment"] = "The number of keys exist for user {}".format(name) + ret["comment"] = f"The number of keys exist for user {name}" ret["result"] = True return ret if __opts__["test"]: - ret["comment"] = "Access key is set to be created for {}.".format(name) + ret["comment"] = f"Access key is set to be created for {name}." ret["result"] = None return ret new_keys = {} @@ -456,7 +454,7 @@ def keys_present( ) if isinstance(created, str): error, message = _get_error(created) - ret["comment"] = "Could not create keys.\n{}\n{}".format(error, message) + ret["comment"] = f"Could not create keys.\n{error}\n{message}" ret["result"] = False return ret log.debug("Created is : %s", created) @@ -470,7 +468,7 @@ def keys_present( "secret_access_key" ] try: - with salt.utils.files.fopen("{}/{}".format(save_dir, name), "a") as _wrf: + with salt.utils.files.fopen(f"{save_dir}/{name}", "a") as _wrf: for key_num, key in new_keys.items(): key_id = key["key_id"] secret_key = key["secret_key"] @@ -479,17 +477,17 @@ def keys_present( save_format.format( key_id, secret_key, - "key_id-{}".format(key_num), - "key-{}".format(key_num), + f"key_id-{key_num}", + f"key-{key_num}", ) ) ) - ret["comment"] = "Keys have been written to file {}/{}.".format(save_dir, name) + ret["comment"] = f"Keys have been written to file {save_dir}/{name}." ret["result"] = True ret["changes"] = new_keys return ret except OSError: - ret["comment"] = "Could not write to file {}/{}.".format(save_dir, name) + ret["comment"] = f"Could not write to file {save_dir}/{name}." ret["result"] = False return ret @@ -525,7 +523,7 @@ def keys_absent( ret = {"name": access_keys, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_user"](user_name, region, key, keyid, profile): ret["result"] = False - ret["comment"] = "IAM User {} does not exist.".format(user_name) + ret["comment"] = f"IAM User {user_name} does not exist." return ret for k in access_keys: ret = _delete_key(ret, k, user_name, region, key, keyid, profile) @@ -542,7 +540,7 @@ def _delete_key( if isinstance(keys, str): log.debug("Keys %s are a string. Something went wrong.", keys) ret["comment"] = " ".join( - [ret["comment"], "Key {} could not be deleted.".format(access_key_id)] + [ret["comment"], f"Key {access_key_id} could not be deleted."] ) return ret keys = keys["list_access_keys_response"]["list_access_keys_result"][ @@ -564,15 +562,15 @@ def _delete_key( ) if deleted: ret["comment"] = " ".join( - [ret["comment"], "Key {} has been deleted.".format(access_key_id)] + [ret["comment"], f"Key {access_key_id} has been deleted."] ) ret["changes"][access_key_id] = "deleted" return ret ret["comment"] = " ".join( - [ret["comment"], "Key {} could not be deleted.".format(access_key_id)] + [ret["comment"], f"Key {access_key_id} could not be deleted."] ) return ret - ret["comment"] = " ".join([ret["comment"], "Key {} does not exist.".format(k)]) + ret["comment"] = " ".join([ret["comment"], f"Key {k} does not exist."]) return ret @@ -649,7 +647,7 @@ def user_present( exists = __salt__["boto_iam.get_user"](name, region, key, keyid, profile) if not exists: if __opts__["test"]: - ret["comment"] = "IAM user {} is set to be created.".format(name) + ret["comment"] = f"IAM user {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_user"]( @@ -658,7 +656,7 @@ def user_present( if created: ret["changes"]["user"] = created ret["comment"] = " ".join( - [ret["comment"], "User {} has been created.".format(name)] + [ret["comment"], f"User {name} has been created."] ) if password: ret = _case_password(ret, name, password, region, key, keyid, profile) @@ -666,7 +664,7 @@ def user_present( ret["changes"] = dictupdate.update(ret["changes"], _ret["changes"]) ret["comment"] = " ".join([ret["comment"], _ret["comment"]]) else: - ret["comment"] = " ".join([ret["comment"], "User {} is present.".format(name)]) + ret["comment"] = " ".join([ret["comment"], f"User {name} is present."]) if password: ret = _case_password(ret, name, password, region, key, keyid, profile) _ret = _user_policies_present(name, _policies, region, key, keyid, profile) @@ -845,7 +843,7 @@ def _user_policies_detached(name, region=None, key=None, keyid=None, profile=Non ) oldpolicies = [x.get("policy_arn") for x in _list] if not _list: - ret["comment"] = "No attached policies in user {}.".format(name) + ret["comment"] = f"No attached policies in user {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be detached from user {}.".format( @@ -865,7 +863,7 @@ def _user_policies_detached(name, region=None, key=None, keyid=None, profile=Non newpolicies = [x.get("policy_arn") for x in _list] ret["changes"]["new"] = {"managed_policies": newpolicies} ret["result"] = False - ret["comment"] = "Failed to detach {} from user {}".format(policy_arn, name) + ret["comment"] = f"Failed to detach {policy_arn} from user {name}" return ret _list = __salt__["boto_iam.list_attached_user_policies"]( name, region=region, key=key, keyid=keyid, profile=profile @@ -884,7 +882,7 @@ def _user_policies_deleted(name, region=None, key=None, keyid=None, profile=None user_name=name, region=region, key=key, keyid=keyid, profile=profile ) if not oldpolicies: - ret["comment"] = "No inline policies in user {}.".format(name) + ret["comment"] = f"No inline policies in user {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be deleted from user {}.".format( @@ -921,7 +919,7 @@ def _case_password( ret, name, password, region=None, key=None, keyid=None, profile=None ): if __opts__["test"]: - ret["comment"] = "Login policy for {} is set to be changed.".format(name) + ret["comment"] = f"Login policy for {name} is set to be changed." ret["result"] = None return ret login = __salt__["boto_iam.create_login_profile"]( @@ -931,11 +929,11 @@ def _case_password( if login: if "Conflict" in login: ret["comment"] = " ".join( - [ret["comment"], "Login profile for user {} exists.".format(name)] + [ret["comment"], f"Login profile for user {name} exists."] ) else: ret["comment"] = " ".join( - [ret["comment"], "Password has been added to User {}.".format(name)] + [ret["comment"], f"Password has been added to User {name}."] ) ret["changes"]["password"] = "REDACTED" else: @@ -976,13 +974,13 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): ret = {"name": name, "result": True, "comment": "", "changes": {}} if not __salt__["boto_iam.get_group"](name, region, key, keyid, profile): ret["result"] = True - ret["comment"] = "IAM Group {} does not exist.".format(name) + ret["comment"] = f"IAM Group {name} does not exist." return ret if __opts__["test"]: ret["comment"] = " ".join( [ ret["comment"], - "IAM group {} managed policies are set to be detached.".format(name), + f"IAM group {name} managed policies are set to be detached.", ] ) ret["result"] = None @@ -997,7 +995,7 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): ret["comment"] = " ".join( [ ret["comment"], - "IAM group {} inline policies are set to be deleted.".format(name), + f"IAM group {name} inline policies are set to be deleted.", ] ) ret["result"] = None @@ -1009,7 +1007,7 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): if ret["result"] is False: return ret ret["comment"] = " ".join( - [ret["comment"], "IAM group {} users are set to be removed.".format(name)] + [ret["comment"], f"IAM group {name} users are set to be removed."] ) existing_users = __salt__["boto_iam.get_group_members"]( group_name=name, region=region, key=key, keyid=keyid, profile=profile @@ -1023,19 +1021,17 @@ def group_absent(name, region=None, key=None, keyid=None, profile=None): # finally, actually delete the group if __opts__["test"]: ret["comment"] = " ".join( - [ret["comment"], "IAM group {} is set to be deleted.".format(name)] + [ret["comment"], f"IAM group {name} is set to be deleted."] ) ret["result"] = None return ret deleted = __salt__["boto_iam.delete_group"](name, region, key, keyid, profile) if deleted is True: - ret["comment"] = " ".join( - [ret["comment"], "IAM group {} is deleted.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"IAM group {name} is deleted."]) ret["result"] = True ret["changes"]["deleted"] = name return ret - ret["comment"] = "IAM group {} could not be deleted.\n {}".format(name, deleted) + ret["comment"] = f"IAM group {name} could not be deleted.\n {deleted}" ret["result"] = False return ret @@ -1119,7 +1115,7 @@ def group_present( ) if not exists: if __opts__["test"]: - ret["comment"] = "IAM group {} is set to be created.".format(name) + ret["comment"] = f"IAM group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_group"]( @@ -1131,15 +1127,13 @@ def group_present( profile=profile, ) if not created: - ret["comment"] = "Failed to create IAM group {}.".format(name) + ret["comment"] = f"Failed to create IAM group {name}." ret["result"] = False return ret ret["changes"]["group"] = created - ret["comment"] = " ".join( - [ret["comment"], "Group {} has been created.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"Group {name} has been created."]) else: - ret["comment"] = " ".join([ret["comment"], "Group {} is present.".format(name)]) + ret["comment"] = " ".join([ret["comment"], f"Group {name} is present."]) # Group exists, ensure group policies and users are set. _ret = _group_policies_present( name, _policies, region, key, keyid, profile, delete_policies @@ -1178,7 +1172,7 @@ def _case_group(ret, users, group_name, existing_users, region, key, keyid, prof ret["comment"] = " ".join( [ ret["comment"], - "User {} is already a member of group {}.".format(user, group_name), + f"User {user} is already a member of group {group_name}.", ] ) continue @@ -1196,7 +1190,7 @@ def _case_group(ret, users, group_name, existing_users, region, key, keyid, prof ret["comment"] = " ".join( [ ret["comment"], - "User {} has been added to group {}.".format(user, group_name), + f"User {user} has been added to group {group_name}.", ] ) ret["changes"][user] = group_name @@ -1229,7 +1223,7 @@ def _case_group(ret, users, group_name, existing_users, region, key, keyid, prof ), ] ) - ret["changes"][user] = "Removed from group {}.".format(group_name) + ret["changes"][user] = f"Removed from group {group_name}." return ret @@ -1410,7 +1404,7 @@ def _group_policies_detached(name, region=None, key=None, keyid=None, profile=No ) oldpolicies = [x.get("policy_arn") for x in _list] if not _list: - ret["comment"] = "No attached policies in group {}.".format(name) + ret["comment"] = f"No attached policies in group {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be detached from group {}.".format( @@ -1451,7 +1445,7 @@ def _group_policies_deleted(name, region=None, key=None, keyid=None, profile=Non group_name=name, region=region, key=key, keyid=keyid, profile=profile ) if not oldpolicies: - ret["comment"] = "No inline policies in group {}.".format(name) + ret["comment"] = f"No inline policies in group {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be deleted from group {}.".format( @@ -1568,7 +1562,7 @@ def account_policy( ret["comment"] = " ".join( [ ret["comment"], - "Policy value {} has been set to {}.".format(value, info[key]), + f"Policy value {value} has been set to {info[key]}.", ] ) ret["changes"][key] = str(value).lower() @@ -1627,18 +1621,18 @@ def server_cert_absent(name, region=None, key=None, keyid=None, profile=None): name, region, key, keyid, profile ) if not exists: - ret["comment"] = "Certificate {} does not exist.".format(name) + ret["comment"] = f"Certificate {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Server certificate {} is set to be deleted.".format(name) + ret["comment"] = f"Server certificate {name} is set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_server_cert"](name, region, key, keyid, profile) if not deleted: ret["result"] = False - ret["comment"] = "Certificate {} failed to be deleted.".format(name) + ret["comment"] = f"Certificate {name} failed to be deleted." return ret - ret["comment"] = "Certificate {} was deleted.".format(name) + ret["comment"] = f"Certificate {name} was deleted." ret["changes"] = deleted return ret @@ -1693,14 +1687,14 @@ def server_cert_present( ) log.debug("Variables are : %s.", locals()) if exists: - ret["comment"] = "Certificate {} exists.".format(name) + ret["comment"] = f"Certificate {name} exists." return ret if "salt://" in public_key: try: public_key = __salt__["cp.get_file_str"](public_key) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(public_key) + ret["comment"] = f"File {public_key} not found." ret["result"] = False return ret if "salt://" in private_key: @@ -1708,7 +1702,7 @@ def server_cert_present( private_key = __salt__["cp.get_file_str"](private_key) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(private_key) + ret["comment"] = f"File {private_key} not found." ret["result"] = False return ret if cert_chain is not None and "salt://" in cert_chain: @@ -1716,22 +1710,22 @@ def server_cert_present( cert_chain = __salt__["cp.get_file_str"](cert_chain) except OSError as e: log.debug(e) - ret["comment"] = "File {} not found.".format(cert_chain) + ret["comment"] = f"File {cert_chain} not found." ret["result"] = False return ret if __opts__["test"]: - ret["comment"] = "Server certificate {} is set to be created.".format(name) + ret["comment"] = f"Server certificate {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.upload_server_cert"]( name, public_key, private_key, cert_chain, path, region, key, keyid, profile ) if created is not False: - ret["comment"] = "Certificate {} was created.".format(name) + ret["comment"] = f"Certificate {name} was created." ret["changes"] = created return ret ret["result"] = False - ret["comment"] = "Certificate {} failed to be created.".format(name) + ret["comment"] = f"Certificate {name} failed to be created." return ret @@ -1780,7 +1774,7 @@ def policy_present( policy = __salt__["boto_iam.get_policy"](name, region, key, keyid, profile) if not policy: if __opts__["test"]: - ret["comment"] = "IAM policy {} is set to be created.".format(name) + ret["comment"] = f"IAM policy {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_policy"]( @@ -1789,7 +1783,7 @@ def policy_present( if created: ret["changes"]["policy"] = created ret["comment"] = " ".join( - [ret["comment"], "Policy {} has been created.".format(name)] + [ret["comment"], f"Policy {name} has been created."] ) else: ret["result"] = False @@ -1798,9 +1792,7 @@ def policy_present( return ret else: policy = policy.get("policy", {}) - ret["comment"] = " ".join( - [ret["comment"], "Policy {} is present.".format(name)] - ) + ret["comment"] = " ".join([ret["comment"], f"Policy {name} is present."]) _describe = __salt__["boto_iam.get_policy_version"]( name, policy.get("default_version_id"), region, key, keyid, profile ).get("policy_version", {}) @@ -1816,7 +1808,7 @@ def policy_present( if bool(r): if __opts__["test"]: - ret["comment"] = "Policy {} set to be modified.".format(name) + ret["comment"] = f"Policy {name} set to be modified." ret["result"] = None return ret @@ -1883,11 +1875,11 @@ def policy_absent(name, region=None, key=None, keyid=None, profile=None): name, region=region, key=key, keyid=keyid, profile=profile ) if not r: - ret["comment"] = "Policy {} does not exist.".format(name) + ret["comment"] = f"Policy {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Policy {} is set to be removed.".format(name) + ret["comment"] = f"Policy {name} is set to be removed." ret["result"] = None return ret # delete non-default versions @@ -1908,18 +1900,18 @@ def policy_absent(name, region=None, key=None, keyid=None, profile=None): ) if not r: ret["result"] = False - ret["comment"] = "Failed to delete policy {}.".format(name) + ret["comment"] = f"Failed to delete policy {name}." return ret r = __salt__["boto_iam.delete_policy"]( name, region=region, key=key, keyid=keyid, profile=profile ) if not r: ret["result"] = False - ret["comment"] = "Failed to delete policy {}.".format(name) + ret["comment"] = f"Failed to delete policy {name}." return ret ret["changes"]["old"] = {"policy": name} ret["changes"]["new"] = {"policy": None} - ret["comment"] = "Policy {} deleted.".format(name) + ret["comment"] = f"Policy {name} deleted." return ret @@ -1957,19 +1949,19 @@ def saml_provider_present( ET.fromstring(saml_metadata_document) except OSError as e: log.debug(e) - ret[ - "comment" - ] = "SAML document file {} not found or could not be loaded".format(name) + ret["comment"] = ( + f"SAML document file {name} not found or could not be loaded" + ) ret["result"] = False return ret for provider in __salt__["boto_iam.list_saml_providers"]( region=region, key=key, keyid=keyid, profile=profile ): if provider == name: - ret["comment"] = "SAML provider {} is present.".format(name) + ret["comment"] = f"SAML provider {name} is present." return ret if __opts__["test"]: - ret["comment"] = "SAML provider {} is set to be create.".format(name) + ret["comment"] = f"SAML provider {name} is set to be create." ret["result"] = None return ret created = __salt__["boto_iam.create_saml_provider"]( @@ -1981,11 +1973,11 @@ def saml_provider_present( profile=profile, ) if created: - ret["comment"] = "SAML provider {} was created.".format(name) + ret["comment"] = f"SAML provider {name} was created." ret["changes"]["new"] = name return ret ret["result"] = False - ret["comment"] = "SAML provider {} failed to be created.".format(name) + ret["comment"] = f"SAML provider {name} failed to be created." return ret @@ -2019,21 +2011,21 @@ def saml_provider_absent(name, region=None, key=None, keyid=None, profile=None): region=region, key=key, keyid=keyid, profile=profile ) if len(provider) == 0: - ret["comment"] = "SAML provider {} is absent.".format(name) + ret["comment"] = f"SAML provider {name} is absent." return ret if __opts__["test"]: - ret["comment"] = "SAML provider {} is set to be removed.".format(name) + ret["comment"] = f"SAML provider {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_saml_provider"]( name, region=region, key=key, keyid=keyid, profile=profile ) if deleted is not False: - ret["comment"] = "SAML provider {} was deleted.".format(name) + ret["comment"] = f"SAML provider {name} was deleted." ret["changes"]["old"] = name return ret ret["result"] = False - ret["comment"] = "SAML provider {} failed to be deleted.".format(name) + ret["comment"] = f"SAML provider {name} failed to be deleted." return ret diff --git a/salt/states/boto_iam_role.py b/salt/states/boto_iam_role.py index 67c41f760a0..9ddcdfdee39 100644 --- a/salt/states/boto_iam_role.py +++ b/salt/states/boto_iam_role.py @@ -255,7 +255,7 @@ def _role_present( role = __salt__["boto_iam.describe_role"](name, region, key, keyid, profile) if not role: if __opts__["test"]: - ret["comment"] = "IAM role {} is set to be created.".format(name) + ret["comment"] = f"IAM role {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_role"]( @@ -264,12 +264,12 @@ def _role_present( if created: ret["changes"]["old"] = {"role": None} ret["changes"]["new"] = {"role": name} - ret["comment"] = "IAM role {} created.".format(name) + ret["comment"] = f"IAM role {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} IAM role.".format(name) + ret["comment"] = f"Failed to create {name} IAM role." else: - ret["comment"] = "{} role present.".format(name) + ret["comment"] = f"{name} role present." if not policy_document: _policy_document = __salt__["boto_iam.build_policy"]( region, key, keyid, profile @@ -309,7 +309,7 @@ def _instance_profile_present(name, region=None, key=None, keyid=None, profile=N ) if not exists: if __opts__["test"]: - ret["comment"] = "Instance profile {} is set to be created.".format(name) + ret["comment"] = f"Instance profile {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_iam.create_instance_profile"]( @@ -318,10 +318,10 @@ def _instance_profile_present(name, region=None, key=None, keyid=None, profile=N if created: ret["changes"]["old"] = {"instance_profile": None} ret["changes"]["new"] = {"instance_profile": name} - ret["comment"] = "Instance profile {} created.".format(name) + ret["comment"] = f"Instance profile {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} instance profile.".format(name) + ret["comment"] = f"Failed to create {name} instance profile." return ret @@ -332,7 +332,7 @@ def _instance_profile_associated(name, region=None, key=None, keyid=None, profil ) if not is_associated: if __opts__["test"]: - ret["comment"] = "Instance profile {} is set to be associated.".format(name) + ret["comment"] = f"Instance profile {name} is set to be associated." ret["result"] = None return ret associated = __salt__["boto_iam.associate_profile_to_role"]( @@ -341,12 +341,12 @@ def _instance_profile_associated(name, region=None, key=None, keyid=None, profil if associated: ret["changes"]["old"] = {"profile_associated": None} ret["changes"]["new"] = {"profile_associated": True} - ret["comment"] = "Instance profile {} associated.".format(name) + ret["comment"] = f"Instance profile {name} associated." else: ret["result"] = False - ret[ - "comment" - ] = "Failed to associate {0} instance profile with {0} role.".format(name) + ret["comment"] = ( + "Failed to associate {0} instance profile with {0} role.".format(name) + ) return ret @@ -591,19 +591,19 @@ def _role_absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_iam.role_exists"](name, region, key, keyid, profile) if exists: if __opts__["test"]: - ret["comment"] = "IAM role {} is set to be removed.".format(name) + ret["comment"] = f"IAM role {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_role"](name, region, key, keyid, profile) if deleted: ret["changes"]["old"] = {"role": name} ret["changes"]["new"] = {"role": None} - ret["comment"] = "IAM role {} removed.".format(name) + ret["comment"] = f"IAM role {name} removed." else: ret["result"] = False - ret["comment"] = "Failed to delete {} iam role.".format(name) + ret["comment"] = f"Failed to delete {name} iam role." else: - ret["comment"] = "{} role does not exist.".format(name) + ret["comment"] = f"{name} role does not exist." return ret @@ -615,7 +615,7 @@ def _instance_profile_absent(name, region=None, key=None, keyid=None, profile=No ) if exists: if __opts__["test"]: - ret["comment"] = "Instance profile {} is set to be removed.".format(name) + ret["comment"] = f"Instance profile {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_iam.delete_instance_profile"]( @@ -624,12 +624,12 @@ def _instance_profile_absent(name, region=None, key=None, keyid=None, profile=No if deleted: ret["changes"]["old"] = {"instance_profile": name} ret["changes"]["new"] = {"instance_profile": None} - ret["comment"] = "Instance profile {} removed.".format(name) + ret["comment"] = f"Instance profile {name} removed." else: ret["result"] = False - ret["comment"] = "Failed to delete {} instance profile.".format(name) + ret["comment"] = f"Failed to delete {name} instance profile." else: - ret["comment"] = "{} instance profile does not exist.".format(name) + ret["comment"] = f"{name} instance profile does not exist." return ret @@ -637,7 +637,7 @@ def _policies_absent(name, region=None, key=None, keyid=None, profile=None): ret = {"result": True, "comment": "", "changes": {}} _list = __salt__["boto_iam.list_role_policies"](name, region, key, keyid, profile) if not _list: - ret["comment"] = "No policies in role {}.".format(name) + ret["comment"] = f"No policies in role {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be removed from role {}.".format( @@ -673,7 +673,7 @@ def _policies_detached(name, region=None, key=None, keyid=None, profile=None): ) oldpolicies = [x.get("policy_arn") for x in _list] if not _list: - ret["comment"] = "No attached policies in role {}.".format(name) + ret["comment"] = f"No attached policies in role {name}." return ret if __opts__["test"]: ret["comment"] = "{} policies to be detached from role {}.".format( @@ -693,7 +693,7 @@ def _policies_detached(name, region=None, key=None, keyid=None, profile=None): newpolicies = [x.get("policy_arn") for x in _list] ret["changes"]["new"] = {"managed_policies": newpolicies} ret["result"] = False - ret["comment"] = "Failed to detach {} from role {}".format(policy_arn, name) + ret["comment"] = f"Failed to detach {policy_arn} from role {name}" return ret _list = __salt__["boto_iam.list_attached_role_policies"]( name, region=region, key=key, keyid=keyid, profile=profile @@ -726,12 +726,12 @@ def _instance_profile_disassociated( if associated: ret["changes"]["old"] = {"profile_associated": True} ret["changes"]["new"] = {"profile_associated": False} - ret["comment"] = "Instance profile {} disassociated.".format(name) + ret["comment"] = f"Instance profile {name} disassociated." else: ret["result"] = False - ret[ - "comment" - ] = "Failed to disassociate {0} instance profile from {0} role.".format( - name + ret["comment"] = ( + "Failed to disassociate {0} instance profile from {0} role.".format( + name + ) ) return ret diff --git a/salt/states/boto_iot.py b/salt/states/boto_iot.py index e14d1541949..bea8f9481f5 100644 --- a/salt/states/boto_iot.py +++ b/salt/states/boto_iot.py @@ -157,7 +157,7 @@ def thing_type_present( return ret if __opts__["test"]: - ret["comment"] = "Thing type {} is set to be created.".format(thingTypeName) + ret["comment"] = f"Thing type {thingTypeName} is set to be created." ret["result"] = None return ret @@ -187,7 +187,7 @@ def thing_type_present( ) ret["changes"]["old"] = {"thing_type": None} ret["changes"]["new"] = _describe - ret["comment"] = "Thing Type {} created.".format(thingTypeName) + ret["comment"] = f"Thing Type {thingTypeName} created." return ret @@ -237,7 +237,7 @@ def thing_type_absent( return ret if _describe and not _describe["thing_type"]: - ret["comment"] = "Thing Type {} does not exist.".format(thingTypeName) + ret["comment"] = f"Thing Type {thingTypeName} does not exist." return ret _existing_thing_type = _describe["thing_type"] @@ -319,7 +319,7 @@ def thing_type_absent( return ret ret["changes"]["old"] = _describe ret["changes"]["new"] = {"thing_type": None} - ret["comment"] = "Thing Type {} deleted.".format(thingTypeName) + ret["comment"] = f"Thing Type {thingTypeName} deleted." return ret @@ -366,7 +366,7 @@ def policy_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Policy {} is set to be created.".format(policyName) + ret["comment"] = f"Policy {policyName} is set to be created." ret["result"] = None return ret r = __salt__["boto_iot.create_policy"]( @@ -388,11 +388,11 @@ def policy_present( ) ret["changes"]["old"] = {"policy": None} ret["changes"]["new"] = _describe - ret["comment"] = "Policy {} created.".format(policyName) + ret["comment"] = f"Policy {policyName} created." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Policy {} is present.".format(policyName)] + [ret["comment"], f"Policy {policyName} is present."] ) ret["changes"] = {} # policy exists, ensure config matches @@ -411,7 +411,7 @@ def policy_present( r = salt.utils.data.compare_dicts(describeDict, policyDocument) if bool(r): if __opts__["test"]: - msg = "Policy {} set to be modified.".format(policyName) + msg = f"Policy {policyName} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -487,11 +487,11 @@ def policy_absent(name, policyName, region=None, key=None, keyid=None, profile=N return ret if r and not r["exists"]: - ret["comment"] = "Policy {} does not exist.".format(policyName) + ret["comment"] = f"Policy {policyName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Policy {} is set to be removed.".format(policyName) + ret["comment"] = f"Policy {policyName} is set to be removed." ret["result"] = None return ret # delete non-default versions @@ -532,7 +532,7 @@ def policy_absent(name, policyName, region=None, key=None, keyid=None, profile=N return ret ret["changes"]["old"] = {"policy": policyName} ret["changes"]["new"] = {"policy": None} - ret["comment"] = "Policy {} deleted.".format(policyName) + ret["comment"] = f"Policy {policyName} deleted." return ret @@ -603,11 +603,11 @@ def policy_attached( return ret ret["changes"]["old"] = {"attached": False} ret["changes"]["new"] = {"attached": True} - ret["comment"] = "Policy {} attached to {}.".format(policyName, principal) + ret["comment"] = f"Policy {policyName} attached to {principal}." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Policy {} is attached.".format(policyName)] + [ret["comment"], f"Policy {policyName} is attached."] ) ret["changes"] = {} @@ -682,11 +682,11 @@ def policy_detached( return ret ret["changes"]["old"] = {"attached": True} ret["changes"]["new"] = {"attached": False} - ret["comment"] = "Policy {} detached from {}.".format(policyName, principal) + ret["comment"] = f"Policy {policyName} detached from {principal}." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Policy {} is detached.".format(policyName)] + [ret["comment"], f"Policy {policyName} is detached."] ) ret["changes"] = {} @@ -752,7 +752,7 @@ def topic_rule_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Rule {} is set to be created.".format(ruleName) + ret["comment"] = f"Rule {ruleName} is set to be created." ret["result"] = None return ret r = __salt__["boto_iot.create_topic_rule"]( @@ -775,12 +775,10 @@ def topic_rule_present( ) ret["changes"]["old"] = {"rule": None} ret["changes"]["new"] = _describe - ret["comment"] = "Rule {} created.".format(ruleName) + ret["comment"] = f"Rule {ruleName} created." return ret - ret["comment"] = os.linesep.join( - [ret["comment"], "Rule {} is present.".format(ruleName)] - ) + ret["comment"] = os.linesep.join([ret["comment"], f"Rule {ruleName} is present."]) ret["changes"] = {} # policy exists, ensure config matches _describe = __salt__["boto_iot.describe_topic_rule"]( @@ -805,7 +803,7 @@ def topic_rule_present( ret["changes"].setdefault("old", {})[var] = _describe[var] if need_update: if __opts__["test"]: - msg = "Rule {} set to be modified.".format(ruleName) + msg = f"Rule {ruleName} set to be modified." ret["changes"] = {} ret["comment"] = msg ret["result"] = None @@ -864,11 +862,11 @@ def topic_rule_absent(name, ruleName, region=None, key=None, keyid=None, profile return ret if r and not r["exists"]: - ret["comment"] = "Rule {} does not exist.".format(ruleName) + ret["comment"] = f"Rule {ruleName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Rule {} is set to be removed.".format(ruleName) + ret["comment"] = f"Rule {ruleName} is set to be removed." ret["result"] = None return ret r = __salt__["boto_iot.delete_topic_rule"]( @@ -880,5 +878,5 @@ def topic_rule_absent(name, ruleName, region=None, key=None, keyid=None, profile return ret ret["changes"]["old"] = {"rule": ruleName} ret["changes"]["new"] = {"rule": None} - ret["comment"] = "Rule {} deleted.".format(ruleName) + ret["comment"] = f"Rule {ruleName} deleted." return ret diff --git a/salt/states/boto_kinesis.py b/salt/states/boto_kinesis.py index 5809ef711e5..938449515c2 100644 --- a/salt/states/boto_kinesis.py +++ b/salt/states/boto_kinesis.py @@ -140,7 +140,7 @@ def present( if exists["result"] is False: if __opts__["test"]: ret["result"] = None - comments.append("Kinesis stream {} would be created".format(name)) + comments.append(f"Kinesis stream {name} would be created") _add_changes(ret, changes_old, changes_new, comments) return ret else: @@ -155,11 +155,11 @@ def present( _add_changes(ret, changes_old, changes_new, comments) return ret - comments.append("Kinesis stream {} successfully created".format(name)) + comments.append(f"Kinesis stream {name} successfully created") changes_new["name"] = name changes_new["num_shards"] = num_shards else: - comments.append("Kinesis stream {} already exists".format(name)) + comments.append(f"Kinesis stream {name} already exists") stream_response = __salt__["boto_kinesis.get_stream_when_active"]( name, region, key, keyid, profile @@ -238,9 +238,7 @@ def present( " at {}".format(name, old_retention_hours) ) else: - comments.append( - "Kinesis stream {}: did not configure retention hours".format(name) - ) + comments.append(f"Kinesis stream {name}: did not configure retention hours") # Configure enhanced monitoring if enhanced_monitoring is not None: @@ -345,9 +343,7 @@ def present( enhanced_monitoring if len(enhanced_monitoring) > 0 else "None" ) else: - comments.append( - "Kinesis stream {}: did not configure enhanced monitoring".format(name) - ) + comments.append(f"Kinesis stream {name}: did not configure enhanced monitoring") # Reshard stream if necessary min_hash_key, max_hash_key, full_stream_details = __salt__[ @@ -439,11 +435,11 @@ def absent(name, region=None, key=None, keyid=None, profile=None): exists = __salt__["boto_kinesis.exists"](name, region, key, keyid, profile) if exists["result"] is False: - ret["comment"] = "Kinesis stream {} does not exist".format(name) + ret["comment"] = f"Kinesis stream {name} does not exist" return ret if __opts__["test"]: - ret["comment"] = "Kinesis stream {} would be deleted".format(name) + ret["comment"] = f"Kinesis stream {name} would be deleted" ret["result"] = None return ret @@ -456,9 +452,9 @@ def absent(name, region=None, key=None, keyid=None, profile=None): ) ret["result"] = False else: - ret["comment"] = "Deleted stream {}".format(name) - ret["changes"].setdefault("old", "Stream {} exists".format(name)) - ret["changes"].setdefault("new", "Stream {} deleted".format(name)) + ret["comment"] = f"Deleted stream {name}" + ret["changes"].setdefault("old", f"Stream {name} exists") + ret["changes"].setdefault("new", f"Stream {name} deleted") return ret diff --git a/salt/states/boto_kms.py b/salt/states/boto_kms.py index aadc02093e8..3c542541304 100644 --- a/salt/states/boto_kms.py +++ b/salt/states/boto_kms.py @@ -174,7 +174,7 @@ def _key_present( profile, ): ret = {"result": True, "comment": "", "changes": {}} - alias = "alias/{}".format(name) + alias = f"alias/{name}" r = __salt__["boto_kms.key_exists"](alias, region, key, keyid, profile) if "error" in r: ret["result"] = False @@ -212,7 +212,7 @@ def _key_present( return ret ret["changes"]["old"] = {"key": None} ret["changes"]["new"] = {"key": name} - ret["comment"] = "Key {} created.".format(name) + ret["comment"] = f"Key {name} created." else: rd = __salt__["boto_kms.describe_key"](alias, region, key, keyid, profile) if "error" in rd: @@ -271,7 +271,7 @@ def _key_enabled(key_metadata, enabled, region, key, keyid, profile): re["error"]["message"] ) else: - ret["comment"] = "{} key.".format(event) + ret["comment"] = f"{event} key." return ret @@ -339,7 +339,7 @@ def _key_rotation(key_metadata, key_rotation, region, key, keyid, profile): "old": {"key_rotation": not key_rotation}, "new": {"key_rotation": key_rotation}, } - ret["comment"] = "Set key rotation policy to {}.".format(key_rotation) + ret["comment"] = f"Set key rotation policy to {key_rotation}." return ret diff --git a/salt/states/boto_lambda.py b/salt/states/boto_lambda.py index cd8bca05f52..0ce5a513c06 100644 --- a/salt/states/boto_lambda.py +++ b/salt/states/boto_lambda.py @@ -59,7 +59,6 @@ config: """ - import hashlib import logging import os @@ -249,7 +248,7 @@ def function_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Function {} is set to be created.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} is set to be created." ret["result"] = None return ret r = __salt__["boto_lambda.create_function"]( @@ -289,7 +288,7 @@ def function_present( key=key, keyid=keyid, profile=profile, - **permission + **permission, ) if not r.get("updated"): ret["result"] = False @@ -305,11 +304,11 @@ def function_present( )["permissions"] ret["changes"]["old"] = {"function": None} ret["changes"]["new"] = _describe - ret["comment"] = "Function {} created.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} created." return ret ret["comment"] = os.linesep.join( - [ret["comment"], "Function {} is present.".format(FunctionName)] + [ret["comment"], f"Function {FunctionName} is present."] ) ret["changes"] = {} # function exists, ensure config matches @@ -373,7 +372,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): account_id = __salt__["boto_iam.get_account_id"]( region=region, key=key, keyid=keyid, profile=profile ) - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def _resolve_vpcconfig(conf, region=None, key=None, keyid=None, profile=None): @@ -461,7 +460,7 @@ def _function_config_present( [ret["comment"], "Function config to be modified"] ) if __opts__["test"]: - ret["comment"] = "Function {} set to be modified.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} set to be modified." ret["result"] = None return ret _r = __salt__["boto_lambda.update_function_config"]( @@ -502,7 +501,7 @@ def _function_code_present( dlZipFile = __salt__["cp.cache_file"](path=ZipFile) if dlZipFile is False: ret["result"] = False - ret["comment"] = "Failed to cache ZipFile `{}`.".format(ZipFile) + ret["comment"] = f"Failed to cache ZipFile `{ZipFile}`." return ret ZipFile = dlZipFile size = os.path.getsize(ZipFile) @@ -522,7 +521,7 @@ def _function_code_present( update = True if update: if __opts__["test"]: - ret["comment"] = "Function {} set to be modified.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} set to be modified." ret["result"] = None return ret ret["changes"]["old"] = { @@ -580,7 +579,7 @@ def _function_permissions_present( [ret["comment"], "Function permissions to be modified"] ) if __opts__["test"]: - ret["comment"] = "Function {} set to be modified.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} set to be modified." ret["result"] = None return ret for sid, diff in diffs.items(): @@ -609,7 +608,7 @@ def _function_permissions_present( key=key, keyid=keyid, profile=profile, - **diff["new"] + **diff["new"], ) ret["changes"].setdefault("new", {}).setdefault("Permissions", {})[ sid @@ -665,11 +664,11 @@ def function_absent( return ret if r and not r["exists"]: - ret["comment"] = "Function {} does not exist.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Function {} is set to be removed.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} is set to be removed." ret["result"] = None return ret r = __salt__["boto_lambda.delete_function"]( @@ -681,7 +680,7 @@ def function_absent( return ret ret["changes"]["old"] = {"function": FunctionName} ret["changes"]["new"] = {"function": None} - ret["comment"] = "Function {} deleted.".format(FunctionName) + ret["comment"] = f"Function {FunctionName} deleted." return ret @@ -746,7 +745,7 @@ def alias_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Alias {} is set to be created.".format(Name) + ret["comment"] = f"Alias {Name} is set to be created." ret["result"] = None return ret r = __salt__["boto_lambda.create_alias"]( @@ -768,12 +767,10 @@ def alias_present( ) ret["changes"]["old"] = {"alias": None} ret["changes"]["new"] = _describe - ret["comment"] = "Alias {} created.".format(Name) + ret["comment"] = f"Alias {Name} created." return ret - ret["comment"] = os.linesep.join( - [ret["comment"], "Alias {} is present.".format(Name)] - ) + ret["comment"] = os.linesep.join([ret["comment"], f"Alias {Name} is present."]) ret["changes"] = {} _describe = __salt__["boto_lambda.describe_alias"]( FunctionName, Name, region=region, key=key, keyid=keyid, profile=profile @@ -792,7 +789,7 @@ def alias_present( [ret["comment"], "Alias config to be modified"] ) if __opts__["test"]: - ret["comment"] = "Alias {} set to be modified.".format(Name) + ret["comment"] = f"Alias {Name} set to be modified." ret["result"] = None return ret _r = __salt__["boto_lambda.update_alias"]( @@ -854,11 +851,11 @@ def alias_absent( return ret if r and not r["exists"]: - ret["comment"] = "Alias {} does not exist.".format(Name) + ret["comment"] = f"Alias {Name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Alias {} is set to be removed.".format(Name) + ret["comment"] = f"Alias {Name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_lambda.delete_alias"]( @@ -870,7 +867,7 @@ def alias_absent( return ret ret["changes"]["old"] = {"alias": Name} ret["changes"]["new"] = {"alias": None} - ret["comment"] = "Alias {} deleted.".format(Name) + ret["comment"] = f"Alias {Name} deleted." return ret @@ -885,7 +882,7 @@ def _get_function_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:lambda:{}:{}:function:{}".format(region, account_id, name) + return f"arn:aws:lambda:{region}:{account_id}:function:{name}" def event_source_mapping_present( diff --git a/salt/states/boto_rds.py b/salt/states/boto_rds.py index b5894c1fbd3..5d33a01925f 100644 --- a/salt/states/boto_rds.py +++ b/salt/states/boto_rds.py @@ -68,7 +68,6 @@ config: """ - import logging import os @@ -306,7 +305,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "RDS instance {} would be created.".format(name) + ret["comment"] = f"RDS instance {name} would be created." ret["result"] = None return ret @@ -374,9 +373,9 @@ def present( profile=profile, ) } - ret["comment"] = "RDS instance {} created.".format(name) + ret["comment"] = f"RDS instance {name} created." else: - ret["comment"] = "RDS instance {} exists.".format(name) + ret["comment"] = f"RDS instance {name} exists." return ret @@ -413,7 +412,7 @@ def replica_present( ) if not replica_exists.get("exists"): if __opts__["test"]: - ret["comment"] = "RDS read replica {} is set to be created ".format(name) + ret["comment"] = f"RDS read replica {name} is set to be created " ret["result"] = None return ret created = __salt__["boto_rds.create_read_replica"]( @@ -433,7 +432,7 @@ def replica_present( profile, ) if created: - ret["comment"] = "RDS replica {} created.".format(name) + ret["comment"] = f"RDS replica {name} created." ret["changes"]["old"] = {"instance": None} ret["changes"]["new"] = { "instance": __salt__["boto_rds.describe_db_instances"]( @@ -447,7 +446,7 @@ def replica_present( } else: ret["result"] = False - ret["comment"] = "Failed to create RDS replica {}.".format(name) + ret["comment"] = f"Failed to create RDS replica {name}." else: jmespath = "DBInstances[0].DBParameterGroups[0].DBParameterGroupName" pmg_name = __salt__["boto_rds.describe_db_instances"]( @@ -470,13 +469,13 @@ def replica_present( ) if not modified: ret["result"] = False - ret[ - "comment" - ] = "Failed to update parameter group of {} RDS instance.".format(name) + ret["comment"] = ( + f"Failed to update parameter group of {name} RDS instance." + ) ret["changes"]["old"] = pmg_name ret["changes"]["new"] = db_parameter_group_name ret["result"] = True - ret["comment"] = "RDS replica {} exists.".format(name) + ret["comment"] = f"RDS replica {name} exists." return ret @@ -547,7 +546,7 @@ def subnet_group_present( ret["result"] = False return ret if r["id"] is None: - ret["comment"] = "Subnet {} does not exist.".format(i) + ret["comment"] = f"Subnet {i} does not exist." ret["result"] = False return ret subnet_ids.append(r["id"]) @@ -557,7 +556,7 @@ def subnet_group_present( ) if not exists.get("exists"): if __opts__["test"]: - ret["comment"] = "Subnet group {} is set to be created.".format(name) + ret["comment"] = f"Subnet group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_rds.create_subnet_group"]( @@ -573,14 +572,14 @@ def subnet_group_present( if not created: ret["result"] = False - ret["comment"] = "Failed to create {} subnet group.".format(name) + ret["comment"] = f"Failed to create {name} subnet group." return ret ret["changes"]["old"] = None ret["changes"]["new"] = name - ret["comment"] = "Subnet {} created.".format(name) + ret["comment"] = f"Subnet {name} created." return ret else: - ret["comment"] = "Subnet {} present.".format(name) + ret["comment"] = f"Subnet {name} present." return ret @@ -642,11 +641,11 @@ def absent( ) if not current: ret["result"] = True - ret["comment"] = "{} RDS already absent.".format(name) + ret["comment"] = f"{name} RDS already absent." return ret if __opts__["test"]: - ret["comment"] = "RDS {} would be removed.".format(name) + ret["comment"] = f"RDS {name} would be removed." ret["result"] = None return ret deleted = __salt__["boto_rds.delete"]( @@ -663,11 +662,11 @@ def absent( ) if not deleted: ret["result"] = False - ret["comment"] = "Failed to delete {} RDS.".format(name) + ret["comment"] = f"Failed to delete {name} RDS." return ret ret["changes"]["old"] = {"instance": current[0]} ret["changes"]["new"] = {"instance": None} - ret["comment"] = "RDS {} deleted.".format(name) + ret["comment"] = f"RDS {name} deleted." return ret @@ -681,11 +680,11 @@ def subnet_group_absent( ) if not exists: ret["result"] = True - ret["comment"] = "{} RDS subnet group does not exist.".format(name) + ret["comment"] = f"{name} RDS subnet group does not exist." return ret if __opts__["test"]: - ret["comment"] = "RDS subnet group {} is set to be removed.".format(name) + ret["comment"] = f"RDS subnet group {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_rds.delete_subnet_group"]( @@ -693,11 +692,11 @@ def subnet_group_absent( ) if not deleted: ret["result"] = False - ret["comment"] = "Failed to delete {} RDS subnet group.".format(name) + ret["comment"] = f"Failed to delete {name} RDS subnet group." return ret ret["changes"]["old"] = name ret["changes"]["new"] = None - ret["comment"] = "RDS subnet group {} deleted.".format(name) + ret["comment"] = f"RDS subnet group {name} deleted." return ret @@ -762,7 +761,7 @@ def parameter_present( ) if not res.get("exists"): if __opts__["test"]: - ret["comment"] = "Parameter group {} is set to be created.".format(name) + ret["comment"] = f"Parameter group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_rds.create_parameter_group"]( @@ -777,12 +776,12 @@ def parameter_present( ) if not created: ret["result"] = False - ret["comment"] = "Failed to create {} parameter group.".format(name) + ret["comment"] = f"Failed to create {name} parameter group." return ret ret["changes"]["New Parameter Group"] = name - ret["comment"] = "Parameter group {} created.".format(name) + ret["comment"] = f"Parameter group {name} created." else: - ret["comment"] = "Parameter group {} present.".format(name) + ret["comment"] = f"Parameter group {name} present." if parameters is not None: params = {} changed = {} @@ -799,7 +798,7 @@ def parameter_present( if not options.get("result"): ret["result"] = False ret["comment"] = os.linesep.join( - [ret["comment"], "Faled to get parameters for group {}.".format(name)] + [ret["comment"], f"Faled to get parameters for group {name}."] ) return ret for parameter in options["parameters"].values(): @@ -853,14 +852,14 @@ def parameter_present( ret["comment"] = os.linesep.join( [ ret["comment"], - "Parameters {} for group {} are changed.".format(changed, name), + f"Parameters {changed} for group {name} are changed.", ] ) else: ret["comment"] = os.linesep.join( [ ret["comment"], - "Parameters {} for group {} are present.".format(params, name), + f"Parameters {params} for group {name} are present.", ] ) return ret diff --git a/salt/states/boto_route53.py b/salt/states/boto_route53.py index 0143c4e276f..39ed57aca52 100644 --- a/salt/states/boto_route53.py +++ b/salt/states/boto_route53.py @@ -70,7 +70,6 @@ passed in as a dict, or as a string to pull from pillars or minion config: key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs """ - import logging import uuid @@ -186,10 +185,10 @@ def present( log.info("Found private IP %s for instance %s", private_ip, name_tag) else: if public_ip is None: - ret[ - "comment" - ] = "Error: No Public IP assigned to instance with Name {}".format( - name_tag + ret["comment"] = ( + "Error: No Public IP assigned to instance with Name {}".format( + name_tag + ) ) ret["result"] = False return ret @@ -211,13 +210,13 @@ def present( identifier, ) except SaltInvocationError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" ret["result"] = False return ret if isinstance(record, dict) and not record: if __opts__["test"]: - ret["comment"] = "Route53 record {} set to be added.".format(name) + ret["comment"] = f"Route53 record {name} set to be added." ret["result"] = None return ret added = __salt__["boto_route53.add_record"]( @@ -244,10 +243,10 @@ def present( "ttl": ttl, "identifier": identifier, } - ret["comment"] = "Added {} Route53 record.".format(name) + ret["comment"] = f"Added {name} Route53 record." else: ret["result"] = False - ret["comment"] = "Failed to add {} Route53 record.".format(name) + ret["comment"] = f"Failed to add {name} Route53 record." return ret elif record: need_to_update = False @@ -268,7 +267,7 @@ def present( need_to_update = True if need_to_update: if __opts__["test"]: - ret["comment"] = "Route53 record {} set to be updated.".format(name) + ret["comment"] = f"Route53 record {name} set to be updated." ret["result"] = None return ret updated = __salt__["boto_route53.update_record"]( @@ -295,12 +294,12 @@ def present( "ttl": ttl, "identifier": identifier, } - ret["comment"] = "Updated {} Route53 record.".format(name) + ret["comment"] = f"Updated {name} Route53 record." else: ret["result"] = False - ret["comment"] = "Failed to update {} Route53 record.".format(name) + ret["comment"] = f"Failed to update {name} Route53 record." else: - ret["comment"] = "{} exists.".format(name) + ret["comment"] = f"{name} exists." return ret @@ -376,7 +375,7 @@ def absent( ) if record: if __opts__["test"]: - ret["comment"] = "Route53 record {} set to be deleted.".format(name) + ret["comment"] = f"Route53 record {name} set to be deleted." ret["result"] = None return ret deleted = __salt__["boto_route53.delete_record"]( @@ -396,12 +395,12 @@ def absent( if deleted: ret["changes"]["old"] = record ret["changes"]["new"] = None - ret["comment"] = "Deleted {} Route53 record.".format(name) + ret["comment"] = f"Deleted {name} Route53 record." else: ret["result"] = False - ret["comment"] = "Failed to delete {} Route53 record.".format(name) + ret["comment"] = f"Failed to delete {name} Route53 record." else: - ret["comment"] = "{} does not exist.".format(name) + ret["comment"] = f"{name} does not exist." return ret @@ -575,13 +574,13 @@ def hosted_zone_present( profile=profile, ) if res: - msg = "Hosted Zone {} successfully created".format(domain_name) + msg = f"Hosted Zone {domain_name} successfully created" log.info(msg) ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = res else: - ret["comment"] = "Creating Hosted Zone {} failed".format(domain_name) + ret["comment"] = f"Creating Hosted Zone {domain_name} failed" ret["result"] = False return ret @@ -609,11 +608,11 @@ def hosted_zone_absent( domain_name=domain_name, region=region, key=key, keyid=keyid, profile=profile ) if not deets: - ret["comment"] = "Hosted Zone {} already absent".format(domain_name) + ret["comment"] = f"Hosted Zone {domain_name} already absent" log.info(ret["comment"]) return ret if __opts__["test"]: - ret["comment"] = "Route53 Hosted Zone {} set to be deleted.".format(domain_name) + ret["comment"] = f"Route53 Hosted Zone {domain_name} set to be deleted." ret["result"] = None return ret # Not entirely comfortable with this - no safety checks around pub/priv, VPCs @@ -622,7 +621,7 @@ def hosted_zone_absent( if __salt__["boto_route53.delete_zone"]( zone=domain_name, region=region, key=key, keyid=keyid, profile=profile ): - ret["comment"] = "Route53 Hosted Zone {} deleted".format(domain_name) + ret["comment"] = f"Route53 Hosted Zone {domain_name} deleted" log.info(ret["comment"]) ret["changes"]["old"] = deets ret["changes"]["new"] = None diff --git a/salt/states/boto_s3.py b/salt/states/boto_s3.py index d466374cc27..e80f25c8539 100644 --- a/salt/states/boto_s3.py +++ b/salt/states/boto_s3.py @@ -48,7 +48,6 @@ config: :depends: boto3 """ - import copy import difflib import logging @@ -177,7 +176,7 @@ def object_present( combined_extra_args_keys = frozenset(combined_extra_args.keys()) extra_keys = combined_extra_args_keys - supported_args if extra_keys: - msg = "extra_args keys {} are not supported".format(extra_keys) + msg = f"extra_args keys {extra_keys} are not supported" return {"error": msg} # Get the hash of the local file @@ -253,7 +252,7 @@ def object_present( } if s3_metadata == desired_metadata: ret["result"] = True - ret["comment"] = "S3 object {} is present.".format(name) + ret["comment"] = f"S3 object {name} is present." return ret action = "update" else: @@ -277,8 +276,8 @@ def object_present( if __opts__["test"]: ret["result"] = None - ret["comment"] = "S3 object {} set to be {}d.".format(name, action) - ret["comment"] += "\nChanges:\n{}".format(changes_diff) + ret["comment"] = f"S3 object {name} set to be {action}d." + ret["comment"] += f"\nChanges:\n{changes_diff}" ret["changes"] = {"diff": changes_diff} return ret @@ -301,7 +300,7 @@ def object_present( return ret ret["result"] = True - ret["comment"] = "S3 object {} {}d.".format(name, action) - ret["comment"] += "\nChanges:\n{}".format(changes_diff) + ret["comment"] = f"S3 object {name} {action}d." + ret["comment"] += f"\nChanges:\n{changes_diff}" ret["changes"] = {"diff": changes_diff} return ret diff --git a/salt/states/boto_s3_bucket.py b/salt/states/boto_s3_bucket.py index 66dc68db08d..9baee1f5350 100644 --- a/salt/states/boto_s3_bucket.py +++ b/salt/states/boto_s3_bucket.py @@ -137,7 +137,6 @@ config: """ - import copy import logging @@ -299,7 +298,7 @@ def _get_role_arn(name, region=None, key=None, keyid=None, profile=None): region = profile["region"] if region is None: region = "us-east-1" - return "arn:aws:iam::{}:role/{}".format(account_id, name) + return f"arn:aws:iam::{account_id}:role/{name}" def _compare_json(current, desired, region, key, keyid, profile): @@ -440,7 +439,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "S3 bucket {} is set to be created.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} is set to be created." ret["result"] = None return ret r = __salt__["boto_s3_bucket.create"]( @@ -481,13 +480,13 @@ def present( ("put_website", Website, Website), ): if testval is not None: - r = __salt__["boto_s3_bucket.{}".format(setter)]( + r = __salt__[f"boto_s3_bucket.{setter}"]( Bucket=Bucket, region=region, key=key, keyid=keyid, profile=profile, - **funcargs + **funcargs, ) if not r.get("updated"): ret["result"] = False @@ -501,14 +500,12 @@ def present( ) ret["changes"]["old"] = {"bucket": None} ret["changes"]["new"] = _describe - ret["comment"] = "S3 bucket {} created.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} created." return ret # bucket exists, ensure config matches - ret["comment"] = " ".join( - [ret["comment"], "S3 bucket {} is present.".format(Bucket)] - ) + ret["comment"] = " ".join([ret["comment"], f"S3 bucket {Bucket} is present."]) ret["changes"] = {} _describe = __salt__["boto_s3_bucket.describe"]( Bucket=Bucket, region=region, key=key, keyid=keyid, profile=profile @@ -647,7 +644,7 @@ def present( if not __opts__["test"]: if deleter and desired is None: # Setting can be deleted, so use that to unset it - r = __salt__["boto_s3_bucket.{}".format(deleter)]( + r = __salt__[f"boto_s3_bucket.{deleter}"]( Bucket=Bucket, region=region, key=key, @@ -662,13 +659,13 @@ def present( ret["changes"] = {} return ret else: - r = __salt__["boto_s3_bucket.{}".format(setter)]( + r = __salt__[f"boto_s3_bucket.{setter}"]( Bucket=Bucket, region=region, key=key, keyid=keyid, profile=profile, - **(desired or {}) + **(desired or {}), ) if not r.get("updated"): ret["result"] = False @@ -678,7 +675,7 @@ def present( ret["changes"] = {} return ret if update and __opts__["test"]: - msg = "S3 bucket {} set to be modified.".format(Bucket) + msg = f"S3 bucket {Bucket} set to be modified." ret["comment"] = msg ret["result"] = None return ret @@ -693,7 +690,7 @@ def present( ) log.warning(msg) ret["result"] = False - ret["comment"] = "Failed to update bucket: {}.".format(msg) + ret["comment"] = f"Failed to update bucket: {msg}." return ret return ret @@ -737,11 +734,11 @@ def absent(name, Bucket, Force=False, region=None, key=None, keyid=None, profile return ret if r and not r["exists"]: - ret["comment"] = "S3 bucket {} does not exist.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} does not exist." return ret if __opts__["test"]: - ret["comment"] = "S3 bucket {} is set to be removed.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} is set to be removed." ret["result"] = None return ret r = __salt__["boto_s3_bucket.delete"]( @@ -753,5 +750,5 @@ def absent(name, Bucket, Force=False, region=None, key=None, keyid=None, profile return ret ret["changes"]["old"] = {"bucket": Bucket} ret["changes"]["new"] = {"bucket": None} - ret["comment"] = "S3 bucket {} deleted.".format(Bucket) + ret["comment"] = f"S3 bucket {Bucket} deleted." return ret diff --git a/salt/states/boto_secgroup.py b/salt/states/boto_secgroup.py index b4037ad11a2..23ef79e32f9 100644 --- a/salt/states/boto_secgroup.py +++ b/salt/states/boto_secgroup.py @@ -283,7 +283,7 @@ def _security_group_present( ) if not exists: if __opts__["test"]: - ret["comment"] = "Security group {} is set to be created.".format(name) + ret["comment"] = f"Security group {name} is set to be created." ret["result"] = None return ret created = __salt__["boto_secgroup.create"]( @@ -309,12 +309,12 @@ def _security_group_present( vpc_name=vpc_name, ) ret["changes"]["new"] = {"secgroup": sg} - ret["comment"] = "Security group {} created.".format(name) + ret["comment"] = f"Security group {name} created." else: ret["result"] = False - ret["comment"] = "Failed to create {} security group.".format(name) + ret["comment"] = f"Failed to create {name} security group." else: - ret["comment"] = "Security group {} present.".format(name) + ret["comment"] = f"Security group {name} present." return ret @@ -422,7 +422,7 @@ def _get_rule_changes(rules, _rules): -1, ] if ip_protocol not in supported_protocols and ( - not "{}".format(ip_protocol).isdigit() or int(ip_protocol) > 255 + not f"{ip_protocol}".isdigit() or int(ip_protocol) > 255 ): raise SaltInvocationError( "Invalid ip_protocol {} specified in security group rule.".format( @@ -509,9 +509,7 @@ def _rules_present( vpc_name=vpc_name, ) if not sg: - ret[ - "comment" - ] = "{} security group configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} security group configuration could not be retrieved." ret["result"] = False return ret rules = _split_rules(rules) @@ -568,12 +566,12 @@ def _rules_present( key=key, keyid=keyid, profile=profile, - **rule + **rule, ) if not _deleted: deleted = False if deleted: - ret["comment"] = "Removed rules on {} security group.".format(name) + ret["comment"] = f"Removed rules on {name} security group." else: ret["comment"] = "Failed to remove rules on {} security group.".format( name @@ -590,7 +588,7 @@ def _rules_present( key=key, keyid=keyid, profile=profile, - **rule + **rule, ) if not _created: created = False @@ -598,14 +596,14 @@ def _rules_present( ret["comment"] = " ".join( [ ret["comment"], - "Created rules on {} security group.".format(name), + f"Created rules on {name} security group.", ] ) else: ret["comment"] = " ".join( [ ret["comment"], - "Failed to create rules on {} security group.".format(name), + f"Failed to create rules on {name} security group.", ] ) ret["result"] = False @@ -654,9 +652,7 @@ def _rules_egress_present( vpc_name=vpc_name, ) if not sg: - ret[ - "comment" - ] = "{} security group configuration could not be retrieved.".format(name) + ret["comment"] = f"{name} security group configuration could not be retrieved." ret["result"] = False return ret rules_egress = _split_rules(rules_egress) @@ -714,7 +710,7 @@ def _rules_egress_present( keyid=keyid, profile=profile, egress=True, - **rule + **rule, ) if not _deleted: deleted = False @@ -722,7 +718,7 @@ def _rules_egress_present( ret["comment"] = " ".join( [ ret["comment"], - "Removed egress rule on {} security group.".format(name), + f"Removed egress rule on {name} security group.", ] ) else: @@ -747,7 +743,7 @@ def _rules_egress_present( keyid=keyid, profile=profile, egress=True, - **rule + **rule, ) if not _created: created = False @@ -755,7 +751,7 @@ def _rules_egress_present( ret["comment"] = " ".join( [ ret["comment"], - "Created egress rules on {} security group.".format(name), + f"Created egress rules on {name} security group.", ] ) else: @@ -831,7 +827,7 @@ def absent( if sg: if __opts__["test"]: - ret["comment"] = "Security group {} is set to be removed.".format(name) + ret["comment"] = f"Security group {name} is set to be removed." ret["result"] = None return ret deleted = __salt__["boto_secgroup.delete"]( @@ -847,12 +843,12 @@ def absent( if deleted: ret["changes"]["old"] = {"secgroup": sg} ret["changes"]["new"] = {"secgroup": None} - ret["comment"] = "Security group {} deleted.".format(name) + ret["comment"] = f"Security group {name} deleted." else: ret["result"] = False - ret["comment"] = "Failed to delete {} security group.".format(name) + ret["comment"] = f"Failed to delete {name} security group." else: - ret["comment"] = "{} security group does not exist.".format(name) + ret["comment"] = f"{name} security group does not exist." return ret @@ -882,9 +878,9 @@ def _tags_present( vpc_name=vpc_name, ) if not sg: - ret[ - "comment" - ] = "{} security group configuration could not be retrieved.".format(name) + ret["comment"] = ( + f"{name} security group configuration could not be retrieved." + ) ret["result"] = False return ret tags_to_add = tags diff --git a/salt/states/boto_sns.py b/salt/states/boto_sns.py index d4e4c05133b..387a29868c9 100644 --- a/salt/states/boto_sns.py +++ b/salt/states/boto_sns.py @@ -106,10 +106,10 @@ def present(name, subscriptions=None, region=None, key=None, keyid=None, profile ) if is_present: ret["result"] = True - ret["comment"] = "AWS SNS topic {} present.".format(name) + ret["comment"] = f"AWS SNS topic {name} present." else: if __opts__["test"]: - msg = "AWS SNS topic {} is set to be created.".format(name) + msg = f"AWS SNS topic {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -118,13 +118,13 @@ def present(name, subscriptions=None, region=None, key=None, keyid=None, profile name, region=region, key=key, keyid=keyid, profile=profile ) if created: - msg = "AWS SNS topic {} created.".format(name) + msg = f"AWS SNS topic {name} created." ret["comment"] = msg ret["changes"]["old"] = None ret["changes"]["new"] = {"topic": name, "subscriptions": []} ret["result"] = True else: - ret["comment"] = "Failed to create {} AWS SNS topic".format(name) + ret["comment"] = f"Failed to create {name} AWS SNS topic" ret["result"] = False return ret @@ -264,7 +264,7 @@ def absent(name, region=None, key=None, keyid=None, profile=None, unsubscribe=Fa name, region=region, key=key, keyid=keyid, profile=profile ) if deleted: - ret["comment"] = "AWS SNS topic {} deleted.".format(name) + ret["comment"] = f"AWS SNS topic {name} deleted." ret["changes"]["new"] = None if unsubscribe is False: ret["changes"]["old"] = {"topic": name} @@ -276,8 +276,8 @@ def absent(name, region=None, key=None, keyid=None, profile=None, unsubscribe=Fa } else: ret["result"] = False - ret["comment"] = "Failed to delete {} AWS SNS topic.".format(name) + ret["comment"] = f"Failed to delete {name} AWS SNS topic." else: - ret["comment"] = "AWS SNS topic {} does not exist.".format(name) + ret["comment"] = f"AWS SNS topic {name} does not exist." return ret diff --git a/salt/states/boto_sqs.py b/salt/states/boto_sqs.py index 0c3784070c9..6f0e4b3a61a 100644 --- a/salt/states/boto_sqs.py +++ b/salt/states/boto_sqs.py @@ -124,12 +124,12 @@ def present( return ret if r["result"]: - ret["comment"].append("SQS queue {} present.".format(name)) + ret["comment"].append(f"SQS queue {name} present.") else: if __opts__["test"]: ret["result"] = None ret["comment"].append( - "SQS queue {} is set to be created.".format(name), + f"SQS queue {name} is set to be created.", ) ret["changes"] = {"old": None, "new": name} return ret @@ -149,7 +149,7 @@ def present( ) return ret - ret["comment"].append("SQS queue {} created.".format(name)) + ret["comment"].append(f"SQS queue {name} created.") ret["changes"]["old"] = None ret["changes"]["new"] = name # Return immediately, as the create call also set all attributes @@ -238,7 +238,7 @@ def present( return ret ret["comment"].append( - "Updated SQS queue attribute(s) {}.".format(attr_names), + f"Updated SQS queue attribute(s) {attr_names}.", ) ret["changes"]["attributes"] = {"diff": attributes_diff} return ret @@ -293,7 +293,7 @@ def absent( if __opts__["test"]: ret["result"] = None - ret["comment"] = "SQS queue {} is set to be removed.".format(name) + ret["comment"] = f"SQS queue {name} is set to be removed." ret["changes"] = {"old": name, "new": None} return ret @@ -309,7 +309,7 @@ def absent( ret["comment"] = str(r["error"]) return ret - ret["comment"] = "SQS queue {} was deleted.".format(name) + ret["comment"] = f"SQS queue {name} was deleted." ret["changes"]["old"] = name ret["changes"]["new"] = None return ret diff --git a/salt/states/boto_vpc.py b/salt/states/boto_vpc.py index d822adbbeb7..d65d3ca7255 100644 --- a/salt/states/boto_vpc.py +++ b/salt/states/boto_vpc.py @@ -141,7 +141,6 @@ Delete also accepts a VPC peering connection id. """ - import logging import salt.utils.dictupdate as dictupdate @@ -228,7 +227,7 @@ def present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "VPC {} is set to be created.".format(name) + ret["comment"] = f"VPC {name} is set to be created." ret["result"] = None return ret r = __salt__["boto_vpc.create"]( @@ -252,7 +251,7 @@ def present( ) ret["changes"]["old"] = {"vpc": None} ret["changes"]["new"] = _describe - ret["comment"] = "VPC {} created.".format(name) + ret["comment"] = f"VPC {name} created." return ret ret["comment"] = "VPC present." return ret @@ -294,11 +293,11 @@ def absent(name, tags=None, region=None, key=None, keyid=None, profile=None): _id = r.get("id") if not _id: - ret["comment"] = "{} VPC does not exist.".format(name) + ret["comment"] = f"{name} VPC does not exist." return ret if __opts__["test"]: - ret["comment"] = "VPC {} is set to be removed.".format(name) + ret["comment"] = f"VPC {name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_vpc.delete"]( @@ -310,7 +309,7 @@ def absent(name, tags=None, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"vpc": _id} ret["changes"]["new"] = {"vpc": None} - ret["comment"] = "VPC {} deleted.".format(name) + ret["comment"] = f"VPC {name} deleted." return ret @@ -429,7 +428,7 @@ def dhcp_options_present( return ret else: if __opts__["test"]: - ret["comment"] = "DHCP options {} are set to be created.".format(name) + ret["comment"] = f"DHCP options {name} are set to be created." ret["result"] = None return ret @@ -457,7 +456,7 @@ def dhcp_options_present( ret["changes"]["old"] = {"dhcp_options": None} ret["changes"]["new"] = {"dhcp_options": _new} - ret["comment"] = "DHCP options {} created.".format(name) + ret["comment"] = f"DHCP options {name} created." return ret @@ -509,11 +508,11 @@ def dhcp_options_absent( _id = r.get("id") if not _id: - ret["comment"] = "DHCP options {} do not exist.".format(name) + ret["comment"] = f"DHCP options {name} do not exist." return ret if __opts__["test"]: - ret["comment"] = "DHCP options {} are set to be deleted.".format(name) + ret["comment"] = f"DHCP options {name} are set to be deleted." ret["result"] = None return ret @@ -529,7 +528,7 @@ def dhcp_options_absent( ret["changes"]["old"] = {"dhcp_options": _id} ret["changes"]["new"] = {"dhcp_options": None} - ret["comment"] = "DHCP options {} deleted.".format(name) + ret["comment"] = f"DHCP options {name} deleted." return ret @@ -548,7 +547,6 @@ def subnet_present( route_table_name=None, auto_assign_public_ipv4=False, ): - """ Ensure a subnet exists. @@ -669,7 +667,7 @@ def subnet_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Subnet {} is set to be created.".format(name) + ret["comment"] = f"Subnet {name} is set to be created." ret["result"] = None return ret r = __salt__["boto_vpc.create_subnet"]( @@ -694,7 +692,7 @@ def subnet_present( ) ret["changes"]["old"] = {"subnet": None} ret["changes"]["new"] = _describe - ret["comment"] = "Subnet {} created.".format(name) + ret["comment"] = f"Subnet {name} created." else: ret["comment"] = "Subnet present." @@ -705,7 +703,7 @@ def subnet_present( ) if not _verify_subnet_association(route_table_desc, _describe["subnet"]["id"]): if __opts__["test"]: - msg = "Subnet is set to be associated with route table {}".format(rtid) + msg = f"Subnet is set to be associated with route table {rtid}" ret["comment"] = " ".join([ret["comment"], msg]) ret["result"] = None return ret @@ -743,7 +741,7 @@ def subnet_present( ret["result"] = False return ret else: - msg = "Subnet successfully associated with route table {}.".format(rtid) + msg = f"Subnet successfully associated with route table {rtid}." ret["comment"] = " ".join([ret["comment"], msg]) if "new" not in ret["changes"]: ret["changes"]["new"] = __salt__["boto_vpc.describe_subnet"]( @@ -761,7 +759,7 @@ def subnet_present( ret["comment"] = " ".join( [ ret["comment"], - "Subnet is already associated with route table {}".format(rtid), + f"Subnet is already associated with route table {rtid}", ] ) return ret @@ -823,7 +821,7 @@ def subnet_absent( _id = r.get("id") if not _id: - ret["comment"] = "{} subnet does not exist.".format(name) + ret["comment"] = f"{name} subnet does not exist." return ret if __opts__["test"]: @@ -841,7 +839,7 @@ def subnet_absent( ret["changes"]["old"] = {"subnet": _id} ret["changes"]["new"] = {"subnet": None} - ret["comment"] = "Subnet {} deleted.".format(name) + ret["comment"] = f"Subnet {name} deleted." return ret @@ -904,7 +902,7 @@ def internet_gateway_present( if not r.get("exists"): if __opts__["test"]: - ret["comment"] = "Internet gateway {} is set to be created.".format(name) + ret["comment"] = f"Internet gateway {name} is set to be created." ret["result"] = None return ret r = __salt__["boto_vpc.create_internet_gateway"]( @@ -926,9 +924,9 @@ def internet_gateway_present( ret["changes"]["old"] = {"internet_gateway": None} ret["changes"]["new"] = {"internet_gateway": r["id"]} - ret["comment"] = "Internet gateway {} created.".format(name) + ret["comment"] = f"Internet gateway {name} created." return ret - ret["comment"] = "Internet gateway {} present.".format(name) + ret["comment"] = f"Internet gateway {name} present." return ret @@ -977,11 +975,11 @@ def internet_gateway_absent( igw_id = r["id"] if not igw_id: - ret["comment"] = "Internet gateway {} does not exist.".format(name) + ret["comment"] = f"Internet gateway {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Internet gateway {} is set to be removed.".format(name) + ret["comment"] = f"Internet gateway {name} is set to be removed." ret["result"] = None return ret r = __salt__["boto_vpc.delete_internet_gateway"]( @@ -1000,7 +998,7 @@ def internet_gateway_absent( return ret ret["changes"]["old"] = {"internet_gateway": igw_id} ret["changes"]["new"] = {"internet_gateway": None} - ret["comment"] = "Internet gateway {} deleted.".format(name) + ret["comment"] = f"Internet gateway {name} deleted." return ret @@ -1162,7 +1160,7 @@ def _route_table_present( if not _id: if __opts__["test"]: - msg = "Route table {} is set to be created.".format(name) + msg = f"Route table {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -1186,9 +1184,9 @@ def _route_table_present( ret["changes"]["old"] = {"route_table": None} ret["changes"]["new"] = {"route_table": r["id"]} - ret["comment"] = "Route table {} created.".format(name) + ret["comment"] = f"Route table {name} created." return ret - ret["comment"] = "Route table {} ({}) present.".format(name, _id) + ret["comment"] = f"Route table {name} ({_id}) present." return ret @@ -1247,7 +1245,7 @@ def _routes_present( ret["result"] = False return ret if r["id"] is None: - msg = "Internet gateway {} does not exist.".format(i) + msg = f"Internet gateway {i} does not exist." ret["comment"] = msg ret["result"] = False return ret @@ -1271,7 +1269,7 @@ def _routes_present( ret["result"] = False return ret if r["id"] is None: - msg = "VPC peering connection {} does not exist.".format(i) + msg = f"VPC peering connection {i} does not exist." ret["comment"] = msg ret["result"] = False return ret @@ -1325,7 +1323,7 @@ def _routes_present( to_delete.append(route) if to_create or to_delete: if __opts__["test"]: - msg = "Route table {} set to have routes modified.".format(route_table_name) + msg = f"Route table {route_table_name} set to have routes modified." ret["comment"] = msg ret["result"] = None return ret @@ -1359,7 +1357,7 @@ def _routes_present( key=key, keyid=keyid, profile=profile, - **r + **r, ) if not res["created"]: msg = "Failed to create route {} in route table {}: {}.".format( @@ -1414,7 +1412,7 @@ def _subnets_present( ret["result"] = False return ret if r["id"] is None: - msg = "Subnet {} does not exist.".format(i) + msg = f"Subnet {i} does not exist." ret["comment"] = msg ret["result"] = False return ret @@ -1538,11 +1536,11 @@ def route_table_absent(name, region=None, key=None, keyid=None, profile=None): rtbl_id = r["id"] if not rtbl_id: - ret["comment"] = "Route table {} does not exist.".format(name) + ret["comment"] = f"Route table {name} does not exist." return ret if __opts__["test"]: - ret["comment"] = "Route table {} is set to be removed.".format(name) + ret["comment"] = f"Route table {name} is set to be removed." ret["result"] = None return ret @@ -1557,7 +1555,7 @@ def route_table_absent(name, region=None, key=None, keyid=None, profile=None): return ret ret["changes"]["old"] = {"route_table": rtbl_id} ret["changes"]["new"] = {"route_table": None} - ret["comment"] = "Route table {} deleted.".format(name) + ret["comment"] = f"Route table {name} deleted." return ret @@ -1652,7 +1650,7 @@ def nat_gateway_present( inst = r[0] _id = inst.get("NatGatewayId") - ret["comment"] = "Nat gateway {} present.".format(_id) + ret["comment"] = f"Nat gateway {_id} present." return ret @@ -1742,9 +1740,7 @@ def nat_gateway_absent( r["error"]["message"] ) return ret - ret["comment"] = ", ".join( - (ret["comment"], "Nat gateway {} deleted.".format(rtbl_id)) - ) + ret["comment"] = ", ".join((ret["comment"], f"Nat gateway {rtbl_id} deleted.")) ret["changes"]["old"] = {"nat_gateway": rtbl_id} ret["changes"]["new"] = {"nat_gateway": None} return ret @@ -2053,10 +2049,10 @@ def vpc_peering_connection_present( keyid=keyid, profile=profile, ): - ret[ - "comment" - ] = "VPC peering {} already requested - pending acceptance by {}".format( - conn_name, peer_owner_id or peer_vpc_name or peer_vpc_id + ret["comment"] = ( + "VPC peering {} already requested - pending acceptance by {}".format( + conn_name, peer_owner_id or peer_vpc_name or peer_vpc_id + ) ) log.info(ret["comment"]) return ret diff --git a/salt/states/bower.py b/salt/states/bower.py index 0c1928ca47c..e7966345273 100644 --- a/salt/states/bower.py +++ b/salt/states/bower.py @@ -29,7 +29,6 @@ Example: - npm: bower """ - from salt.exceptions import CommandExecutionError, CommandNotFoundError @@ -88,7 +87,7 @@ def installed(name, dir, pkgs=None, user=None, env=None): installed_pkgs = __salt__["bower.list"](dir=dir, runas=user, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" return ret else: installed_pkgs = {p: info for p, info in installed_pkgs.items()} @@ -106,7 +105,7 @@ def installed(name, dir, pkgs=None, user=None, env=None): if pkg_name in installed_pkgs: installed_pkg = installed_pkgs[pkg_name] installed_pkg_ver = installed_pkg.get("pkgMeta").get("version") - installed_name_ver = "{}#{}".format(pkg_name, installed_pkg_ver) + installed_name_ver = f"{pkg_name}#{installed_pkg_ver}" # If given an explicit version check the installed version matches. if pkg_ver: @@ -200,30 +199,30 @@ def removed(name, dir, user=None): installed_pkgs = __salt__["bower.list"](dir=dir, runas=user) except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error removing '{}': {}".format(name, err) + ret["comment"] = f"Error removing '{name}': {err}" return ret if name not in installed_pkgs: ret["result"] = True - ret["comment"] = "Package '{}' is not installed".format(name) + ret["comment"] = f"Package '{name}' is not installed" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package '{}' is set to be removed".format(name) + ret["comment"] = f"Package '{name}' is set to be removed" return ret try: if __salt__["bower.uninstall"](pkg=name, dir=dir, runas=user): ret["result"] = True ret["changes"] = {name: "Removed"} - ret["comment"] = "Package '{}' was successfully removed".format(name) + ret["comment"] = f"Package '{name}' was successfully removed" else: ret["result"] = False - ret["comment"] = "Error removing '{}'".format(name) + ret["comment"] = f"Error removing '{name}'" except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error removing '{}': {}".format(name, err) + ret["comment"] = f"Error removing '{name}': {err}" return ret @@ -242,14 +241,14 @@ def bootstrap(name, user=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Directory '{}' is set to be bootstrapped".format(name) + ret["comment"] = f"Directory '{name}' is set to be bootstrapped" return ret try: call = __salt__["bower.install"](pkg=None, dir=name, runas=user) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error bootstrapping '{}': {}".format(name, err) + ret["comment"] = f"Error bootstrapping '{name}': {err}" return ret if not call: @@ -280,21 +279,21 @@ def pruned(name, user=None, env=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Directory '{}' is set to be pruned".format(name) + ret["comment"] = f"Directory '{name}' is set to be pruned" return ret try: call = __salt__["bower.prune"](dir=name, runas=user, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error pruning '{}': {}".format(name, err) + ret["comment"] = f"Error pruning '{name}': {err}" return ret ret["result"] = True if call: - ret["comment"] = "Directory '{}' was successfully pruned".format(name) + ret["comment"] = f"Directory '{name}' was successfully pruned" ret["changes"] = {"old": [], "new": call} else: - ret["comment"] = "No packages were pruned from directory '{}'".format(name) + ret["comment"] = f"No packages were pruned from directory '{name}'" return ret diff --git a/salt/states/btrfs.py b/salt/states/btrfs.py index 68ab8f869c9..2c17192754e 100644 --- a/salt/states/btrfs.py +++ b/salt/states/btrfs.py @@ -97,7 +97,7 @@ def __mount_device(action): if device: dest = _mount(device, use_default) if not dest: - msg = "Device {} cannot be mounted".format(device) + msg = f"Device {device} cannot be mounted" ret["comment"].append(msg) kwargs["__dest"] = dest ret = action(*args, **kwargs) @@ -157,7 +157,7 @@ def subvolume_created( exists = __salt__["btrfs.subvolume_exists"](path) if exists: - ret["comment"].append("Subvolume {} already present".format(name)) + ret["comment"].append(f"Subvolume {name} already present") # Resolve first the test case. The check is not complete, but at # least we will report if a subvolume needs to be created. Can @@ -166,7 +166,7 @@ def subvolume_created( if __opts__["test"]: ret["result"] = None if not exists: - ret["changes"][name] = "Subvolume {} will be created".format(name) + ret["changes"][name] = f"Subvolume {name} will be created" return ret if not exists: @@ -174,16 +174,16 @@ def subvolume_created( _path = os.path.dirname(path) res = __states__["file.directory"](_path, makedirs=True) if not res["result"]: - ret["comment"].append("Error creating {} directory".format(_path)) + ret["comment"].append(f"Error creating {_path} directory") return ret try: __salt__["btrfs.subvolume_create"](name, dest=__dest, qgroupids=qgroupids) except CommandExecutionError: - ret["comment"].append("Error creating subvolume {}".format(name)) + ret["comment"].append(f"Error creating subvolume {name}") return ret - ret["changes"][name] = "Created subvolume {}".format(name) + ret["changes"][name] = f"Created subvolume {name}" # If the volume was already present, we can opt-out the check for # default subvolume. @@ -227,12 +227,12 @@ def subvolume_deleted(name, device, commit=False, __dest=None): exists = __salt__["btrfs.subvolume_exists"](path) if not exists: - ret["comment"].append("Subvolume {} already missing".format(name)) + ret["comment"].append(f"Subvolume {name} already missing") if __opts__["test"]: ret["result"] = None if exists: - ret["changes"][name] = "Subvolume {} will be removed".format(name) + ret["changes"][name] = f"Subvolume {name} will be removed" return ret # If commit is set, we wait until all is over @@ -242,10 +242,10 @@ def subvolume_deleted(name, device, commit=False, __dest=None): try: __salt__["btrfs.subvolume_delete"](path, commit=commit) except CommandExecutionError: - ret["comment"].append("Error removing subvolume {}".format(name)) + ret["comment"].append(f"Error removing subvolume {name}") return ret - ret["changes"][name] = "Removed subvolume {}".format(name) + ret["changes"][name] = f"Removed subvolume {name}" ret["result"] = True return ret @@ -320,7 +320,7 @@ def properties(name, device, use_default=False, __dest=None, **properties): path = name if not os.path.exists(path): - ret["comment"].append("Object {} not found".format(name)) + ret["comment"].append(f"Object {name} not found") return ret # Convert the booleans to lowercase @@ -332,14 +332,14 @@ def properties(name, device, use_default=False, __dest=None, **properties): try: current_properties = __salt__["btrfs.properties"](path) except CommandExecutionError as e: - ret["comment"].append("Error reading properties from {}".format(name)) - ret["comment"].append("Current error {}".format(e)) + ret["comment"].append(f"Error reading properties from {name}") + ret["comment"].append(f"Current error {e}") return ret try: properties_to_set = _diff_properties(properties, current_properties) except KeyError: - ret["comment"].append("Some property not found in {}".format(name)) + ret["comment"].append(f"Some property not found in {name}") return ret if __opts__["test"]: @@ -347,14 +347,12 @@ def properties(name, device, use_default=False, __dest=None, **properties): if properties_to_set: ret["changes"] = properties_to_set else: - msg = "No properties will be changed in {}".format(name) + msg = f"No properties will be changed in {name}" ret["comment"].append(msg) return ret if properties_to_set: - _properties = ",".join( - "{}={}".format(k, v) for k, v in properties_to_set.items() - ) + _properties = ",".join(f"{k}={v}" for k, v in properties_to_set.items()) __salt__["btrfs.properties"](path, set=_properties) current_properties = __salt__["btrfs.properties"](path) @@ -366,10 +364,10 @@ def properties(name, device, use_default=False, __dest=None, **properties): ret["comment"].append(msg) return ret - ret["comment"].append("Properties changed in {}".format(name)) + ret["comment"].append(f"Properties changed in {name}") ret["changes"] = properties_to_set else: - ret["comment"].append("Properties not changed in {}".format(name)) + ret["comment"].append(f"Properties not changed in {name}") ret["result"] = True return ret diff --git a/salt/states/cabal.py b/salt/states/cabal.py index 8c415e32c4f..5190d850a9a 100644 --- a/salt/states/cabal.py +++ b/salt/states/cabal.py @@ -22,7 +22,6 @@ pkg.installed state for the package which provides cabal """ - import salt.utils.path from salt.exceptions import CommandExecutionError, CommandNotFoundError @@ -84,7 +83,7 @@ def installed(name, pkgs=None, user=None, install_global=False, env=None): call = __salt__["cabal.update"](user=user, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Could not run cabal update {}".format(err) + ret["comment"] = f"Could not run cabal update {err}" return ret if pkgs is not None: @@ -96,7 +95,7 @@ def installed(name, pkgs=None, user=None, install_global=False, env=None): installed_pkgs = __salt__["cabal.list"](user=user, installed=True, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" return ret pkgs_satisfied = [] @@ -181,24 +180,24 @@ def removed(name, user=None, env=None): installed_pkgs = __salt__["cabal.list"](user=user, installed=True, env=env) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" if name not in installed_pkgs: ret["result"] = True - ret["comment"] = "Package '{}' is not installed".format(name) + ret["comment"] = f"Package '{name}' is not installed" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package '{}' is set to be removed".format(name) + ret["comment"] = f"Package '{name}' is set to be removed" return ret if __salt__["cabal.uninstall"](pkg=name, user=user, env=env): ret["result"] = True ret["changes"][name] = "Removed" - ret["comment"] = "Package '{}' was successfully removed".format(name) + ret["comment"] = f"Package '{name}' was successfully removed" else: ret["result"] = False - ret["comment"] = "Error removing package '{}'".format(name) + ret["comment"] = f"Error removing package '{name}'" return ret diff --git a/salt/states/chocolatey.py b/salt/states/chocolatey.py index 87dad46a751..5e49113607e 100644 --- a/salt/states/chocolatey.py +++ b/salt/states/chocolatey.py @@ -141,13 +141,13 @@ def installed( ret["comment"] = f"{name} {version} is already installed" else: if allow_multiple: - ret[ - "comment" - ] = f"{name} {version} will be installed side by side with {name} {installed_version} if supported" + ret["comment"] = ( + f"{name} {version} will be installed side by side with {name} {installed_version} if supported" + ) else: - ret[ - "comment" - ] = f"{name} {version} will be installed over {name} {installed_version}" + ret["comment"] = ( + f"{name} {version} will be installed over {name} {installed_version}" + ) force = True else: version = installed_version @@ -374,14 +374,14 @@ def upgraded( if salt.utils.versions.compare( ver1=installed_version, oper="<", ver2=version ): - ret[ - "comment" - ] = f"{name} {installed_version} will be upgraded to version {version}" + ret["comment"] = ( + f"{name} {installed_version} will be upgraded to version {version}" + ) # If installed version is newer than new version else: - ret[ - "comment" - ] = f"{name} {installed_version} (newer) is already installed" + ret["comment"] = ( + f"{name} {installed_version} (newer) is already installed" + ) return ret # Catch all for a condition where version is not passed and there is no # available version diff --git a/salt/states/chronos_job.py b/salt/states/chronos_job.py index 7bea17b8335..dc016eb3718 100644 --- a/salt/states/chronos_job.py +++ b/salt/states/chronos_job.py @@ -97,7 +97,7 @@ def config(name, config): # if test report there will be an update if __opts__["test"]: ret["result"] = None - ret["comment"] = "Chronos job {} is set to be updated".format(name) + ret["comment"] = f"Chronos job {name} is set to be updated" return ret update_result = __salt__["chronos.update_job"](name, update_config) @@ -110,10 +110,10 @@ def config(name, config): return ret else: ret["result"] = True - ret["comment"] = "Updated job config for {}".format(name) + ret["comment"] = f"Updated job config for {name}" return ret ret["result"] = True - ret["comment"] = "Chronos job {} configured correctly".format(name) + ret["comment"] = f"Chronos job {name} configured correctly" return ret @@ -127,18 +127,18 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["chronos.has_job"](name): ret["result"] = True - ret["comment"] = "Job {} already absent".format(name) + ret["comment"] = f"Job {name} already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Job {} is set to be removed".format(name) + ret["comment"] = f"Job {name} is set to be removed" return ret if __salt__["chronos.rm_job"](name): ret["changes"] = {"job": name} ret["result"] = True - ret["comment"] = "Removed job {}".format(name) + ret["comment"] = f"Removed job {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to remove job {}".format(name) + ret["comment"] = f"Failed to remove job {name}" return ret diff --git a/salt/states/cimc.py b/salt/states/cimc.py index 09832c99ed4..ac6996211bc 100644 --- a/salt/states/cimc.py +++ b/salt/states/cimc.py @@ -17,7 +17,6 @@ relies on the CIMC proxy module to interface with the device. """ - import logging log = logging.getLogger(__name__) @@ -477,9 +476,9 @@ def user(name, id="", user="", priv="", password="", status="active"): if not conf: ret["result"] = False - ret[ - "comment" - ] = "Unable to find requested user id on device. Please verify id is valid." + ret["comment"] = ( + "Unable to find requested user id on device. Please verify id is valid." + ) return ret updates = __salt__["cimc.set_user"](str(id), user, password, priv, status) diff --git a/salt/states/cloud.py b/salt/states/cloud.py index adb55dcab0f..8b7afc71c0d 100644 --- a/salt/states/cloud.py +++ b/salt/states/cloud.py @@ -13,7 +13,6 @@ Use this minion to spin up a cloud instance: my-ec2-config """ - import pprint import salt.utils.cloud as suc @@ -103,21 +102,21 @@ def present(name, cloud_provider, onlyif=None, unless=None, opts=None, **kwargs) # need to ensure ALL providers don't have the instance if __salt__["cloud.has_instance"](name=name, provider=None): ret["result"] = True - ret["comment"] = "Already present instance {}".format(name) + ret["comment"] = f"Already present instance {name}" return ret if __opts__["test"]: - ret["comment"] = "Instance {} needs to be created".format(name) + ret["comment"] = f"Instance {name} needs to be created" return ret info = __salt__["cloud.create"](cloud_provider, name, opts=opts, **kwargs) if info and "Error" not in info: ret["changes"] = info ret["result"] = True - ret[ - "comment" - ] = "Created instance {} using provider {} and the following options: {}".format( - name, cloud_provider, pprint.pformat(kwargs) + ret["comment"] = ( + "Created instance {} using provider {} and the following options: {}".format( + name, cloud_provider, pprint.pformat(kwargs) + ) ) elif info and "Error" in info: ret["result"] = False @@ -173,18 +172,18 @@ def absent(name, onlyif=None, unless=None): if not __salt__["cloud.has_instance"](name=name, provider=None): ret["result"] = True - ret["comment"] = "Already absent instance {}".format(name) + ret["comment"] = f"Already absent instance {name}" return ret if __opts__["test"]: - ret["comment"] = "Instance {} needs to be destroyed".format(name) + ret["comment"] = f"Instance {name} needs to be destroyed" return ret info = __salt__["cloud.destroy"](name) if info and "Error" not in info: ret["changes"] = info ret["result"] = True - ret["comment"] = "Destroyed instance {}".format(name) + ret["comment"] = f"Destroyed instance {name}" elif "Error" in info: ret["result"] = False ret["comment"] = "Failed to destroy instance {}: {}".format( @@ -193,7 +192,7 @@ def absent(name, onlyif=None, unless=None): ) else: ret["result"] = False - ret["comment"] = "Failed to destroy instance {}".format(name) + ret["comment"] = f"Failed to destroy instance {name}" return ret @@ -244,11 +243,11 @@ def profile(name, profile, onlyif=None, unless=None, opts=None, **kwargs): instance = _get_instance([name]) if instance and not any("Not Actioned" in key for key in instance): ret["result"] = True - ret["comment"] = "Already present instance {}".format(name) + ret["comment"] = f"Already present instance {name}" return ret if __opts__["test"]: - ret["comment"] = "Instance {} needs to be created".format(name) + ret["comment"] = f"Instance {name} needs to be created" return ret info = __salt__["cloud.profile"](profile, name, vm_overrides=kwargs, opts=opts) @@ -281,7 +280,7 @@ def profile(name, profile, onlyif=None, unless=None, opts=None, **kwargs): ret["comment"] = "Failed to create instance {} using profile {}: {}".format( name, profile, - "{}\n{}\n".format(main_error, name_error).strip(), + f"{main_error}\n{name_error}\n".strip(), ) else: ret["result"] = False @@ -303,22 +302,22 @@ def volume_present(name, provider=None, **kwargs): volumes = __salt__["cloud.volume_list"](provider=provider) if name in volumes: - ret["comment"] = "Volume exists: {}".format(name) + ret["comment"] = f"Volume exists: {name}" ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be created.".format(name) + ret["comment"] = f"Volume {name} will be created." ret["result"] = None return ret response = __salt__["cloud.volume_create"](names=name, provider=provider, **kwargs) if response: ret["result"] = True - ret["comment"] = "Volume {} was created".format(name) + ret["comment"] = f"Volume {name} was created" ret["changes"] = {"old": None, "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to create.".format(name) + ret["comment"] = f"Volume {name} failed to create." return ret @@ -337,18 +336,18 @@ def volume_absent(name, provider=None, **kwargs): ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be deleted.".format(name) + ret["comment"] = f"Volume {name} will be deleted." ret["result"] = None return ret response = __salt__["cloud.volume_delete"](names=name, provider=provider, **kwargs) if response: ret["result"] = True - ret["comment"] = "Volume {} was deleted".format(name) + ret["comment"] = f"Volume {name} was deleted" ret["changes"] = {"old": volumes[name], "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to delete.".format(name) + ret["comment"] = f"Volume {name} failed to delete." return ret @@ -375,15 +374,15 @@ def volume_attached(name, server_name, provider=None, **kwargs): ret["result"] = True return ret elif name not in volumes: - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" ret["result"] = False return ret elif not instance: - ret["comment"] = "Server {} does not exist".format(server_name) + ret["comment"] = f"Server {server_name} does not exist" ret["result"] = False return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be will be attached.".format(name) + ret["comment"] = f"Volume {name} will be will be attached." ret["result"] = None return ret @@ -392,11 +391,11 @@ def volume_attached(name, server_name, provider=None, **kwargs): ) if response: ret["result"] = True - ret["comment"] = "Volume {} was created".format(name) + ret["comment"] = f"Volume {name} was created" ret["changes"] = {"old": volumes[name], "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to attach.".format(name) + ret["comment"] = f"Volume {name} failed to attach." return ret @@ -429,15 +428,15 @@ def volume_detached(name, server_name=None, provider=None, **kwargs): ret["result"] = True return ret elif name not in volumes: - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" ret["result"] = True return ret elif not instance and server_name is not None: - ret["comment"] = "Server {} does not exist".format(server_name) + ret["comment"] = f"Server {server_name} does not exist" ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be will be detached.".format(name) + ret["comment"] = f"Volume {name} will be will be detached." ret["result"] = None return ret @@ -446,9 +445,9 @@ def volume_detached(name, server_name=None, provider=None, **kwargs): ) if response: ret["result"] = True - ret["comment"] = "Volume {} was created".format(name) + ret["comment"] = f"Volume {name} was created" ret["changes"] = {"old": volumes[name], "new": response} else: ret["result"] = False - ret["comment"] = "Volume {} failed to detach.".format(name) + ret["comment"] = f"Volume {name} failed to detach." return ret diff --git a/salt/states/cmd.py b/salt/states/cmd.py index 5a859c8092c..df0aec96ef8 100644 --- a/salt/states/cmd.py +++ b/salt/states/cmd.py @@ -231,7 +231,6 @@ To use it, one may pass it like this. Example: """ - import copy import logging import os @@ -317,7 +316,7 @@ def _is_true(val): return True elif str(val).lower() in ("false", "no", "0"): return False - raise ValueError("Failed parsing boolean value: {}".format(val)) + raise ValueError(f"Failed parsing boolean value: {val}") def wait( @@ -334,7 +333,7 @@ def wait( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Run the given command only if the watch statement calls it. @@ -485,7 +484,7 @@ def wait_script( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script from a remote source and execute it only if a watch @@ -630,7 +629,7 @@ def run( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Run a command if certain circumstances are met. Use ``cmd.wait`` if you @@ -848,12 +847,12 @@ def run( if __opts__["test"] and not test_name: ret["result"] = None - ret["comment"] = 'Command "{}" would have been executed'.format(name) + ret["comment"] = f'Command "{name}" would have been executed' ret["changes"] = {"cmd": name} return _reinterpreted_state(ret) if stateful else ret if cwd and not os.path.isdir(cwd): - ret["comment"] = 'Desired working directory "{}" is not available'.format(cwd) + ret["comment"] = f'Desired working directory "{cwd}" is not available' return ret # Wow, we passed the test, run this sucker! @@ -868,7 +867,7 @@ def run( ret["changes"] = cmd_all ret["result"] = not bool(cmd_all["retcode"]) - ret["comment"] = 'Command "{}" run'.format(name) + ret["comment"] = f'Command "{name}" run' # Ignore timeout errors if asked (for nohups) and treat cmd as a success if ignore_timeout: @@ -905,7 +904,7 @@ def script( success_retcodes=None, success_stdout=None, success_stderr=None, - **kwargs + **kwargs, ): """ Download a script and execute it with specified arguments. @@ -1100,14 +1099,14 @@ def script( return ret if context and not isinstance(context, dict): - ret[ - "comment" - ] = "Invalidly-formatted 'context' parameter. Must be formed as a dict." + ret["comment"] = ( + "Invalidly-formatted 'context' parameter. Must be formed as a dict." + ) return ret if defaults and not isinstance(defaults, dict): - ret[ - "comment" - ] = "Invalidly-formatted 'defaults' parameter. Must be formed as a dict." + ret["comment"] = ( + "Invalidly-formatted 'defaults' parameter. Must be formed as a dict." + ) return ret if runas and salt.utils.platform.is_windows() and not password: @@ -1155,11 +1154,11 @@ def script( if __opts__["test"] and not test_name: ret["result"] = None - ret["comment"] = "Command '{}' would have been executed".format(name) + ret["comment"] = f"Command '{name}' would have been executed" return _reinterpreted_state(ret) if stateful else ret if cwd and not os.path.isdir(cwd): - ret["comment"] = 'Desired working directory "{}" is not available'.format(cwd) + ret["comment"] = f'Desired working directory "{cwd}" is not available' return ret # Wow, we passed the test, run this sucker! @@ -1179,7 +1178,7 @@ def script( source, __env__ ) else: - ret["comment"] = "Command '{}' run".format(name) + ret["comment"] = f"Command '{name}' run" if stateful: ret = _reinterpreted_state(ret) if __opts__["test"] and cmd_all["retcode"] == 0 and ret["changes"]: @@ -1195,7 +1194,7 @@ def call( output_loglevel="debug", hide_output=False, use_vt=False, - **kwargs + **kwargs, ): """ Invoke a pre-defined Python function with arguments specified in the state @@ -1258,7 +1257,7 @@ def wait_call( use_vt=False, output_loglevel="debug", hide_output=False, - **kwargs + **kwargs, ): # Ignoring our arguments is intentional. return {"name": name, "changes": {}, "result": True, "comment": ""} diff --git a/salt/states/composer.py b/salt/states/composer.py index c21ae515098..9578507066b 100644 --- a/salt/states/composer.py +++ b/salt/states/composer.py @@ -137,10 +137,10 @@ def installed( else: install_status = "not " - ret["comment"] = 'The state of "{}" will be changed.'.format(name) + ret["comment"] = f'The state of "{name}" will be changed.' ret["changes"] = { - "old": "composer install has {}been run in {}".format(install_status, name), - "new": "composer install will be run in {}".format(name), + "old": f"composer install has {install_status}been run in {name}", + "new": f"composer install will be run in {name}", } ret["result"] = None return ret @@ -161,9 +161,9 @@ def installed( composer_home=composer_home, env=env, ) - except (SaltException) as err: + except SaltException as err: ret["result"] = False - ret["comment"] = "Error executing composer in '{}': {}".format(name, err) + ret["comment"] = f"Error executing composer in '{name}': {err}" return ret # If composer retcode != 0 then an exception was thrown and we dealt with it. @@ -172,9 +172,9 @@ def installed( ret["result"] = True if quiet is True: - ret[ - "comment" - ] = "Composer install completed successfully, output silenced by quiet flag" + ret["comment"] = ( + "Composer install completed successfully, output silenced by quiet flag" + ) else: ret["comment"] = "Composer install completed successfully" ret["changes"] = {"stderr": call["stderr"], "stdout": call["stdout"]} @@ -250,17 +250,17 @@ def update( # Check if composer.lock exists, if so we already ran `composer install` is_installed = __salt__["composer.did_composer_install"](name) if is_installed: - old_status = "composer install has not yet been run in {}".format(name) + old_status = f"composer install has not yet been run in {name}" else: - old_status = "composer install has been run in {}".format(name) + old_status = f"composer install has been run in {name}" # The state of the system does need to be changed. Check if we're running # in ``test=true`` mode. if __opts__["test"] is True: - ret["comment"] = 'The state of "{}" will be changed.'.format(name) + ret["comment"] = f'The state of "{name}" will be changed.' ret["changes"] = { "old": old_status, - "new": "composer install/update will be run in {}".format(name), + "new": f"composer install/update will be run in {name}", } ret["result"] = None return ret @@ -281,9 +281,9 @@ def update( composer_home=composer_home, env=env, ) - except (SaltException) as err: + except SaltException as err: ret["result"] = False - ret["comment"] = "Error executing composer in '{}': {}".format(name, err) + ret["comment"] = f"Error executing composer in '{name}': {err}" return ret # If composer retcode != 0 then an exception was thrown and we dealt with it. @@ -292,9 +292,9 @@ def update( ret["result"] = True if quiet is True: - ret[ - "comment" - ] = "Composer update completed successfully, output silenced by quiet flag" + ret["comment"] = ( + "Composer update completed successfully, output silenced by quiet flag" + ) else: ret["comment"] = "Composer update completed successfully" ret["changes"] = {"stderr": call["stderr"], "stdout": call["stdout"]} diff --git a/salt/states/consul.py b/salt/states/consul.py index b35b72649ed..f76bac8f7c9 100644 --- a/salt/states/consul.py +++ b/salt/states/consul.py @@ -20,6 +20,7 @@ The consul module is used to create and manage Consul ACLs consul.acl_absent: - id: 38AC8470-4A83-4140-8DFD-F924CD32917F """ + import logging log = logging.getLogger(__name__) @@ -103,7 +104,7 @@ def acl_present( "name": name, "changes": {}, "result": True, - "comment": 'ACL "{}" exists and is up to date'.format(name), + "comment": f'ACL "{name}" exists and is up to date', } exists = _acl_exists(name, id, token, consul_url) @@ -180,7 +181,7 @@ def acl_absent(name, id=None, token=None, consul_url="http://localhost:8500"): "name": id, "changes": {}, "result": True, - "comment": 'ACL "{}" does not exist'.format(id), + "comment": f'ACL "{id}" does not exist', } exists = _acl_exists(name, id, token, consul_url) diff --git a/salt/states/cron.py b/salt/states/cron.py index c8576727190..c06980fccfe 100644 --- a/salt/states/cron.py +++ b/salt/states/cron.py @@ -346,12 +346,12 @@ def present( ) ret["result"] = None if status == "absent": - ret["comment"] = "Cron {} is set to be added".format(name) + ret["comment"] = f"Cron {name} is set to be added" elif status == "present": ret["result"] = True - ret["comment"] = "Cron {} already present".format(name) + ret["comment"] = f"Cron {name} already present" elif status == "update": - ret["comment"] = "Cron {} is set to be updated".format(name) + ret["comment"] = f"Cron {name} is set to be updated" return ret if special is None: @@ -377,16 +377,16 @@ def present( identifier=identifier, ) if data == "present": - ret["comment"] = "Cron {} already present".format(name) + ret["comment"] = f"Cron {name} already present" return ret if data == "new": - ret["comment"] = "Cron {} added to {}'s crontab".format(name, user) + ret["comment"] = f"Cron {name} added to {user}'s crontab" ret["changes"] = {user: name} return ret if data == "updated": - ret["comment"] = "Cron {} updated".format(name) + ret["comment"] = f"Cron {name} updated" ret["changes"] = {user: name} return ret ret["comment"] = "Cron {} for user {} failed to commit with error \n{}".format( @@ -432,9 +432,9 @@ def absent(name, user="root", identifier=False, special=None, **kwargs): ret["result"] = None if status == "absent": ret["result"] = True - ret["comment"] = "Cron {} is absent".format(name) + ret["comment"] = f"Cron {name} is absent" elif status == "present" or status == "update": - ret["comment"] = "Cron {} is set to be removed".format(name) + ret["comment"] = f"Cron {name} is set to be removed" return ret if special is None: @@ -445,10 +445,10 @@ def absent(name, user="root", identifier=False, special=None, **kwargs): ) if data == "absent": - ret["comment"] = "Cron {} already absent".format(name) + ret["comment"] = f"Cron {name} already absent" return ret if data == "removed": - ret["comment"] = "Cron {} removed from {}'s crontab".format(name, user) + ret["comment"] = f"Cron {name} removed from {user}'s crontab" ret["changes"] = {user: name} return ret ret["comment"] = "Cron {} for user {} failed to commit with error {}".format( @@ -468,7 +468,7 @@ def file( replace=True, defaults=None, backup="", - **kwargs + **kwargs, ): """ Provides file.managed-like functionality (templating, etc.) for a pre-made @@ -559,7 +559,7 @@ def file( except Exception: # pylint: disable=broad-except ret = { "changes": {}, - "comment": "Could not identify group for user {}".format(user), + "comment": f"Could not identify group for user {user}", "name": name, "result": False, } @@ -569,7 +569,7 @@ def file( with salt.utils.files.fopen(cron_path, "w+") as fp_: raw_cron = __salt__["cron.raw_cron"](user) if not raw_cron.endswith("\n"): - raw_cron = "{}\n".format(raw_cron) + raw_cron = f"{raw_cron}\n" fp_.write(salt.utils.stringutils.to_str(raw_cron)) ret = {"changes": {}, "comment": "", "name": name, "result": True} @@ -579,7 +579,7 @@ def file( source = name if not replace and os.stat(cron_path).st_size > 0: - ret["comment"] = "User {} already has a crontab. No changes made".format(user) + ret["comment"] = f"User {user} already has a crontab. No changes made" os.unlink(cron_path) return ret @@ -597,7 +597,7 @@ def file( context=context, defaults=defaults, saltenv=__env__, - **kwargs + **kwargs, ) ret["result"], ret["comment"] = fcm os.unlink(cron_path) @@ -622,12 +622,12 @@ def file( context=context, defaults=defaults, skip_verify=False, # skip_verify - **kwargs + **kwargs, ) except Exception as exc: # pylint: disable=broad-except ret["result"] = False ret["changes"] = {} - ret["comment"] = "Unable to manage file: {}".format(exc) + ret["comment"] = f"Unable to manage file: {exc}" return ret if comment: @@ -653,7 +653,7 @@ def file( except Exception as exc: # pylint: disable=broad-except ret["result"] = False ret["changes"] = {} - ret["comment"] = "Unable to manage file: {}".format(exc) + ret["comment"] = f"Unable to manage file: {exc}" return ret cron_ret = None @@ -661,7 +661,7 @@ def file( cron_ret = __salt__["cron.write_cron_file_verbose"](user, cron_path) # Check cmd return code and show success or failure if cron_ret["retcode"] == 0: - ret["comment"] = "Crontab for user {} was updated".format(user) + ret["comment"] = f"Crontab for user {user} was updated" ret["result"] = True ret["changes"] = ret["changes"] else: @@ -671,7 +671,7 @@ def file( ret["result"] = False ret["changes"] = {} elif ret["result"]: - ret["comment"] = "Crontab for user {} is in the correct state".format(user) + ret["comment"] = f"Crontab for user {user} is in the correct state" ret["changes"] = {} os.unlink(cron_path) @@ -698,26 +698,26 @@ def env_present(name, value=None, user="root"): status = _check_cron_env(user, name, value=value) ret["result"] = None if status == "absent": - ret["comment"] = "Cron env {} is set to be added".format(name) + ret["comment"] = f"Cron env {name} is set to be added" elif status == "present": ret["result"] = True - ret["comment"] = "Cron env {} already present".format(name) + ret["comment"] = f"Cron env {name} already present" elif status == "update": - ret["comment"] = "Cron env {} is set to be updated".format(name) + ret["comment"] = f"Cron env {name} is set to be updated" return ret data = __salt__["cron.set_env"](user, name, value=value) if data == "present": - ret["comment"] = "Cron env {} already present".format(name) + ret["comment"] = f"Cron env {name} already present" return ret if data == "new": - ret["comment"] = "Cron env {} added to {}'s crontab".format(name, user) + ret["comment"] = f"Cron env {name} added to {user}'s crontab" ret["changes"] = {user: name} return ret if data == "updated": - ret["comment"] = "Cron env {} updated".format(name) + ret["comment"] = f"Cron env {name} updated" ret["changes"] = {user: name} return ret ret["comment"] = "Cron env {} for user {} failed to commit with error \n{}".format( @@ -748,17 +748,17 @@ def env_absent(name, user="root"): ret["result"] = None if status == "absent": ret["result"] = True - ret["comment"] = "Cron env {} is absent".format(name) + ret["comment"] = f"Cron env {name} is absent" elif status == "present" or status == "update": - ret["comment"] = "Cron env {} is set to be removed".format(name) + ret["comment"] = f"Cron env {name} is set to be removed" return ret data = __salt__["cron.rm_env"](user, name) if data == "absent": - ret["comment"] = "Cron env {} already absent".format(name) + ret["comment"] = f"Cron env {name} already absent" return ret if data == "removed": - ret["comment"] = "Cron env {} removed from {}'s crontab".format(name, user) + ret["comment"] = f"Cron env {name} removed from {user}'s crontab" ret["changes"] = {user: name} return ret ret["comment"] = "Cron env {} for user {} failed to commit with error {}".format( diff --git a/salt/states/cryptdev.py b/salt/states/cryptdev.py index d30ed73168d..d80aeed735e 100644 --- a/salt/states/cryptdev.py +++ b/salt/states/cryptdev.py @@ -85,9 +85,9 @@ def mapped( # If neither option is set, we've been asked to do nothing. if not immediate and not persist: ret["result"] = False - ret[ - "comment" - ] = "Either persist or immediate must be set, otherwise this state does nothing" + ret["comment"] = ( + "Either persist or immediate must be set, otherwise this state does nothing" + ) return ret if immediate and (keyfile is None or keyfile == "none" or keyfile == "-"): @@ -128,7 +128,7 @@ def mapped( ) if crypttab_result: if crypttab_result == "new": - ret["changes"]["crypttab"] = "Entry added in {}".format(config) + ret["changes"]["crypttab"] = f"Entry added in {config}" if crypttab_result == "change": ret["changes"]["crypttab"] = "Existing entry in {} changed".format( @@ -136,7 +136,7 @@ def mapped( ) else: - ret["changes"]["crypttab"] = "Unable to set entry in {}".format(config) + ret["changes"]["crypttab"] = f"Unable to set entry in {config}" ret["result"] = False return ret @@ -183,10 +183,10 @@ def unmapped(name, config="/etc/crypttab", persist=True, immediate=False): crypttab_result = __salt__["cryptdev.rm_crypttab"](name, config=config) if crypttab_result: if crypttab_result == "change": - ret["changes"]["crypttab"] = "Entry removed from {}".format(config) + ret["changes"]["crypttab"] = f"Entry removed from {config}" else: - ret["changes"]["crypttab"] = "Unable to remove entry in {}".format(config) + ret["changes"]["crypttab"] = f"Unable to remove entry in {config}" ret["result"] = False return ret diff --git a/salt/states/csf.py b/salt/states/csf.py index 4a66377031c..57118c75d02 100644 --- a/salt/states/csf.py +++ b/salt/states/csf.py @@ -107,8 +107,8 @@ def rule_present( return ret else: if ttl: - method = "temp{}".format(method) - func = __salt__["csf.{}".format(method)] + method = f"temp{method}" + func = __salt__[f"csf.{method}"] rule = func( ip, port=port, @@ -387,7 +387,7 @@ def option_present(name, value, reload=False): if current_option: l = __salt__["csf.split_option"](current_option) option_value = l[1] - if '"{}"'.format(value) == option_value: + if f'"{value}"' == option_value: return ret else: result = __salt__["csf.set_option"](option, value) @@ -395,7 +395,7 @@ def option_present(name, value, reload=False): ret["changes"]["Option"] = "Changed" else: result = __salt__["file.append"]( - "/etc/csf/csf.conf", args='{} = "{}"'.format(option, value) + "/etc/csf/csf.conf", args=f'{option} = "{value}"' ) ret["comment"] = "Option not present. Appended to csf.conf" ret["changes"]["Option"] = "Changed." diff --git a/salt/states/cyg.py b/salt/states/cyg.py index 957b194c724..e4ea5925979 100644 --- a/salt/states/cyg.py +++ b/salt/states/cyg.py @@ -72,7 +72,7 @@ def installed(name, cyg_arch="x86_64", mirrors=None): return ret if __opts__["test"]: - ret["comment"] = "The package {} would have been installed".format(name) + ret["comment"] = f"The package {name} would have been installed" return ret if __salt__["cyg.install"](name, cyg_arch=cyg_arch, mirrors=mirrors): @@ -131,7 +131,7 @@ def removed(name, cyg_arch="x86_64", mirrors=None): return ret if __opts__["test"]: - ret["comment"] = "The package {} would have been removed".format(name) + ret["comment"] = f"The package {name} would have been removed" return ret if __salt__["cyg.uninstall"](name, cyg_arch): ret["result"] = True diff --git a/salt/states/ddns.py b/salt/states/ddns.py index 8fd2e9c0508..0260fc10916 100644 --- a/salt/states/ddns.py +++ b/salt/states/ddns.py @@ -64,7 +64,7 @@ def present(name, zone, ttl, data, rdtype="A", **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = '{} record "{}" will be updated'.format(rdtype, name) + ret["comment"] = f'{rdtype} record "{name}" will be updated' return ret status = __salt__["ddns.update"](zone, name, ttl, rdtype, data, **kwargs) @@ -76,7 +76,7 @@ def present(name, zone, ttl, data, rdtype="A", **kwargs): ) elif status: ret["result"] = True - ret["comment"] = 'Updated {} record for "{}"'.format(rdtype, name) + ret["comment"] = f'Updated {rdtype} record for "{name}"' ret["changes"] = { "name": name, "zone": zone, @@ -122,7 +122,7 @@ def absent(name, zone, data=None, rdtype=None, **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = '{} record "{}" will be deleted'.format(rdtype, name) + ret["comment"] = f'{rdtype} record "{name}" will be deleted' return ret status = __salt__["ddns.delete"](zone, name, rdtype, data, **kwargs) diff --git a/salt/states/debconfmod.py b/salt/states/debconfmod.py index cb93d0d721c..4d399408341 100644 --- a/salt/states/debconfmod.py +++ b/salt/states/debconfmod.py @@ -184,7 +184,7 @@ def set(name, data, **kwargs): current = __salt__["debconf.show"](name) - for (key, args) in data.items(): + for key, args in data.items(): # For debconf data, valid booleans are 'true' and 'false'; # But str()'ing the args['value'] will result in 'True' and 'False' # which will be ignored and overridden by a dpkg-reconfigure. @@ -198,7 +198,7 @@ def set(name, data, **kwargs): if current is not None and [key, args["type"], str(args["value"])] in current: if ret["comment"] == "": ret["comment"] = "Unchanged answers: " - ret["comment"] += "{} ".format(key) + ret["comment"] += f"{key} " else: if __opts__["test"]: ret["result"] = None diff --git a/salt/states/dellchassis.py b/salt/states/dellchassis.py index 2ac905c8ad2..23487b6dfad 100644 --- a/salt/states/dellchassis.py +++ b/salt/states/dellchassis.py @@ -153,7 +153,6 @@ pillar stated above: """ - import logging import os @@ -701,9 +700,9 @@ def switch( if any([password_ret, snmp_ret, net_ret, dhcp_ret]) is False: ret["result"] = False - ret["comment"] = "There was an error setting the switch {}.".format(name) + ret["comment"] = f"There was an error setting the switch {name}." - ret["comment"] = "Dell chassis switch {} was updated.".format(name) + ret["comment"] = f"Dell chassis switch {name} was updated." return ret @@ -756,7 +755,7 @@ def firmware_update(hosts=None, directory=""): ret["changes"].update( { "host": { - "comment": "Firmware update submitted for {}".format(host), + "comment": f"Firmware update submitted for {host}", "success": True, } } @@ -766,7 +765,7 @@ def firmware_update(hosts=None, directory=""): ret["changes"].update( { "host": { - "comment": "FAILED to update firmware for {}".format(host), + "comment": f"FAILED to update firmware for {host}", "success": False, "reason": str(err), } diff --git a/salt/states/disk.py b/salt/states/disk.py index c257870c1be..47d7177b59b 100644 --- a/salt/states/disk.py +++ b/salt/states/disk.py @@ -62,7 +62,7 @@ def _validate_int(name, value, limits=(), strip="%"): value = value.strip(" " + strip) value = int(value) except (TypeError, ValueError): - comment += "{} must be an integer ".format(name) + comment += f"{name} must be an integer " # Must be in range else: if len(limits) == 2: @@ -136,10 +136,10 @@ def _check_min_max(absolute, free, available, used, maximum, minimum, ret): return ret else: if used < minimum: - ret[ - "comment" - ] = "Disk used space is below minimum of {0} {2} at {1} {2}".format( - minimum, used, unit + ret["comment"] = ( + "Disk used space is below minimum of {0} {2} at {1} {2}".format( + minimum, used, unit + ) ) return ret if maximum is not None: @@ -153,10 +153,10 @@ def _check_min_max(absolute, free, available, used, maximum, minimum, ret): return ret else: if used > maximum: - ret[ - "comment" - ] = "Disk used space is above maximum of {0} {2} at {1} {2}".format( - maximum, used, unit + ret["comment"] = ( + "Disk used space is above maximum of {0} {2} at {1} {2}".format( + maximum, used, unit + ) ) return ret ret["comment"] = "Disk used space in acceptable range" @@ -219,7 +219,7 @@ def status(name, maximum=None, minimum=None, absolute=False, free=False): # Validate name if name not in data: - ret["comment"] += "Disk mount {} not present. ".format(name) + ret["comment"] += f"Disk mount {name} not present. " return _status_path(name, ret, minimum, maximum, absolute, free) else: return _status_mount(name, ret, minimum, maximum, absolute, free, data) diff --git a/salt/states/docker_container.py b/salt/states/docker_container.py index 543f35b6902..8008e8a5952 100644 --- a/salt/states/docker_container.py +++ b/salt/states/docker_container.py @@ -1883,9 +1883,9 @@ def running( if not _replace(name, temp_container_name): ret["result"] = False return _format_comments(ret, comments) - ret["changes"].setdefault("container_id", {})[ - "added" - ] = temp_container["Id"] + ret["changes"].setdefault("container_id", {})["added"] = ( + temp_container["Id"] + ) else: # No changes between existing container and temp container. # First check if a requisite is asking to send a signal to the @@ -2231,9 +2231,9 @@ def run( if remove is not None: if not ignore_collisions: ret["result"] = False - ret[ - "comment" - ] = "'rm' is an alias for 'auto_remove', they cannot both be used" + ret["comment"] = ( + "'rm' is an alias for 'auto_remove', they cannot both be used" + ) return ret else: remove = bool(val) @@ -2271,9 +2271,9 @@ def run( pass else: ret["result"] = False if failhard and retcode != 0 else True - ret[ - "comment" - ] = f"Container ran and exited with a return code of {retcode}" + ret["comment"] = ( + f"Container ran and exited with a return code of {retcode}" + ) if remove: id_ = ret.get("changes", {}).get("Id") diff --git a/salt/states/docker_image.py b/salt/states/docker_image.py index 030c9b6924e..25a069cb399 100644 --- a/salt/states/docker_image.py +++ b/salt/states/docker_image.py @@ -316,10 +316,10 @@ def present( repository=name, tag=tag, base=base, mods=sls, **sls_build_kwargs ) except Exception as exc: # pylint: disable=broad-except - ret[ - "comment" - ] = "Encountered error using SLS {} for building {}: {}".format( - sls, full_image, exc + ret["comment"] = ( + "Encountered error using SLS {} for building {}: {}".format( + sls, full_image, exc + ) ) return ret if image_info is None or image_update["Id"] != image_info["Id"][:12]: diff --git a/salt/states/docker_network.py b/salt/states/docker_network.py index 31b19537b43..2710c69133b 100644 --- a/salt/states/docker_network.py +++ b/salt/states/docker_network.py @@ -625,9 +625,9 @@ def present( # Set the comment now to say that it already exists, if we need to # recreate the network with new config we'll update the comment later. - ret[ - "comment" - ] = f"Network '{name}' already exists, and is configured as specified" + ret["comment"] = ( + f"Network '{name}' already exists, and is configured as specified" + ) log.trace("Details of docker network '%s': %s", name, network) temp_net_name = "".join( @@ -696,8 +696,8 @@ def present( existing_pool_count = len(network["IPAM"]["Config"]) desired_pool_count = len(temp_net_info["IPAM"]["Config"]) - is_default_pool = ( - lambda x: True if sorted(x) == ["Gateway", "Subnet"] else False + is_default_pool = lambda x: ( + True if sorted(x) == ["Gateway", "Subnet"] else False ) if ( @@ -875,9 +875,11 @@ def present( errors.append(exc.__str__()) else: ret["changes"].setdefault( - "reconnected" - if cid in disconnected_containers - else "connected", + ( + "reconnected" + if cid in disconnected_containers + else "connected" + ), [], ).append(connect_info["Name"]) else: diff --git a/salt/states/drac.py b/salt/states/drac.py index 29a3a6fa7a6..c3a7b4258de 100644 --- a/salt/states/drac.py +++ b/salt/states/drac.py @@ -68,18 +68,18 @@ def present(name, password, permission): if __opts__["test"]: if name in users: - ret["comment"] = "`{}` already exists".format(name) + ret["comment"] = f"`{name}` already exists" else: - ret["comment"] = "`{}` will be created".format(name) + ret["comment"] = f"`{name}` will be created" ret["changes"] = {name: "will be created"} return ret if name in users: - ret["comment"] = "`{}` already exists".format(name) + ret["comment"] = f"`{name}` already exists" else: if __salt__["drac.create_user"](name, password, permission, users): - ret["comment"] = "`{}` user created".format(name) + ret["comment"] = f"`{name}` user created" ret["changes"] = {name: "new user created"} else: ret["comment"] = "Unable to create user" @@ -101,22 +101,22 @@ def absent(name): if __opts__["test"]: if name in users: - ret["comment"] = "`{}` is set to be deleted".format(name) + ret["comment"] = f"`{name}` is set to be deleted" ret["changes"] = {name: "will be deleted"} else: - ret["comment"] = "`{}` does not exist".format(name) + ret["comment"] = f"`{name}` does not exist" return ret if name in users: if __salt__["drac.delete_user"](name, users[name]["index"]): - ret["comment"] = "`{}` deleted".format(name) + ret["comment"] = f"`{name}` deleted" ret["changes"] = {name: "deleted"} else: ret["comment"] = "Unable to delete user" ret["result"] = False else: - ret["comment"] = "`{}` does not exist".format(name) + ret["comment"] = f"`{name}` does not exist" return ret diff --git a/salt/states/dvs.py b/salt/states/dvs.py index 7b4cdf4ba00..6333395c490 100644 --- a/salt/states/dvs.py +++ b/salt/states/dvs.py @@ -200,7 +200,6 @@ The 5.5.0.2014.1.1 is a known stable version that this original ESXi State Module was developed against. """ - import logging import sys @@ -258,7 +257,7 @@ def _get_datacenter_name(): details = __salt__["esxdatacenter.get_details"]() if not details: raise salt.exceptions.CommandExecutionError( - "details for proxy type '{}' not loaded".format(proxy_type) + f"details for proxy type '{proxy_type}' not loaded" ) return details["datacenter"] @@ -363,12 +362,12 @@ def dvs_configured(name, dvs): ) updated_infra_res_pools.append(dict(dvs[infra_prop][idx])) if updated_infra_res_pools: - props_to_original_values[ - "infrastructure_traffic_resource_pools" - ] = original_infra_res_pools - props_to_updated_values[ - "infrastructure_traffic_resource_pools" - ] = updated_infra_res_pools + props_to_original_values["infrastructure_traffic_resource_pools"] = ( + original_infra_res_pools + ) + props_to_updated_values["infrastructure_traffic_resource_pools"] = ( + updated_infra_res_pools + ) if props_to_updated_values: if __opts__["test"]: changes_string = "" @@ -476,7 +475,7 @@ def _get_val2_dict_from_diff_dict(diff_dict): ret_dict = {} for p in diff_dict.keys(): if not isinstance(diff_dict[p], dict): - raise ValueError("Unexpected diff difct '{}'".format(diff_dict)) + raise ValueError(f"Unexpected diff difct '{diff_dict}'") if "val2" in diff_dict[p].keys(): ret_dict.update({p: diff_dict[p]["val2"]}) else: @@ -491,7 +490,7 @@ def _get_val1_dict_from_diff_dict(diff_dict): ret_dict = {} for p in diff_dict.keys(): if not isinstance(diff_dict[p], dict): - raise ValueError("Unexpected diff difct '{}'".format(diff_dict)) + raise ValueError(f"Unexpected diff difct '{diff_dict}'") if "val1" in diff_dict[p].keys(): ret_dict.update({p: diff_dict[p]["val1"]}) else: @@ -508,7 +507,7 @@ def _get_changes_from_diff_dict(diff_dict): changes_strings = [] for p in diff_dict.keys(): if not isinstance(diff_dict[p], dict): - raise ValueError("Unexpected diff difct '{}'".format(diff_dict)) + raise ValueError(f"Unexpected diff difct '{diff_dict}'") if sorted(diff_dict[p].keys()) == ["val1", "val2"]: # Some string formatting from_str = diff_dict[p]["val1"] @@ -521,12 +520,12 @@ def _get_changes_from_diff_dict(diff_dict): to_str = "'{}'".format(diff_dict[p]["val2"]) elif isinstance(diff_dict[p]["val2"], list): to_str = "'{}'".format(", ".join(diff_dict[p]["val2"])) - changes_strings.append("{} from {} to {}".format(p, from_str, to_str)) + changes_strings.append(f"{p} from {from_str} to {to_str}") else: sub_changes = _get_changes_from_diff_dict(diff_dict[p]) if sub_changes: - changes_strings.append("{}:".format(p)) - changes_strings.extend(["\t{}".format(c) for c in sub_changes]) + changes_strings.append(f"{p}:") + changes_strings.extend([f"\t{c}" for c in sub_changes]) return changes_strings @@ -609,7 +608,7 @@ def portgroups_configured(name, dvs, portgroups): pg_name, dvs, datacenter, - "\n".join(["\t{}".format(c) for c in changes_strings]), + "\n".join([f"\t{c}" for c in changes_strings]), ) ) else: @@ -735,7 +734,7 @@ def uplink_portgroup_configured(name, dvs, uplink_portgroup): name, dvs, datacenter, - "\n".join(["\t{}".format(c) for c in changes_strings]), + "\n".join([f"\t{c}" for c in changes_strings]), ) ) else: diff --git a/salt/states/elasticsearch.py b/salt/states/elasticsearch.py index bf58af5913d..962ac1d8ddf 100644 --- a/salt/states/elasticsearch.py +++ b/salt/states/elasticsearch.py @@ -4,7 +4,6 @@ State module to manage Elasticsearch. .. versionadded:: 2017.7.0 """ - import logging import salt.utils.json @@ -26,20 +25,20 @@ def index_absent(name): index = __salt__["elasticsearch.index_get"](index=name) if index and name in index: if __opts__["test"]: - ret["comment"] = "Index {} will be removed".format(name) + ret["comment"] = f"Index {name} will be removed" ret["changes"]["old"] = index[name] ret["result"] = None else: ret["result"] = __salt__["elasticsearch.index_delete"](index=name) if ret["result"]: - ret["comment"] = "Successfully removed index {}".format(name) + ret["comment"] = f"Successfully removed index {name}" ret["changes"]["old"] = index[name] else: - ret[ - "comment" - ] = "Failed to remove index {} for unknown reasons".format(name) + ret["comment"] = ( + f"Failed to remove index {name} for unknown reasons" + ) else: - ret["comment"] = "Index {} is already absent".format(name) + ret["comment"] = f"Index {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -89,15 +88,15 @@ def index_present(name, definition=None): index=name, body=definition ) if output: - ret["comment"] = "Successfully created index {}".format(name) + ret["comment"] = f"Successfully created index {name}" ret["changes"] = { "new": __salt__["elasticsearch.index_get"](index=name)[name] } else: ret["result"] = False - ret["comment"] = "Cannot create index {}, {}".format(name, output) + ret["comment"] = f"Cannot create index {name}, {output}" else: - ret["comment"] = "Index {} is already present".format(name) + ret["comment"] = f"Index {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -136,17 +135,17 @@ def alias_absent(name, index): aliases=name, indices=index ) if ret["result"]: - ret[ - "comment" - ] = "Successfully removed alias {} for index {}".format(name, index) + ret["comment"] = ( + f"Successfully removed alias {name} for index {index}" + ) ret["changes"]["old"] = ( alias.get(index, {}).get("aliases", {}).get(name, {}) ) else: - ret[ - "comment" - ] = "Failed to remove alias {} for index {} for unknown reasons".format( - name, index + ret["comment"] = ( + "Failed to remove alias {} for index {} for unknown reasons".format( + name, index + ) ) else: ret["comment"] = "Alias {} for index {} is already absent".format( @@ -198,10 +197,10 @@ def alias_present(name, index, definition=None): if ret["changes"] or not definition: if __opts__["test"]: if not old: - ret[ - "comment" - ] = "Alias {} for index {} does not exist and will be created".format( - name, index + ret["comment"] = ( + "Alias {} for index {} does not exist and will be created".format( + name, index + ) ) else: ret["comment"] = ( @@ -216,16 +215,16 @@ def alias_present(name, index, definition=None): ) if output: if not old: - ret[ - "comment" - ] = "Successfully created alias {} for index {}".format( - name, index + ret["comment"] = ( + "Successfully created alias {} for index {}".format( + name, index + ) ) else: - ret[ - "comment" - ] = "Successfully replaced alias {} for index {}".format( - name, index + ret["comment"] = ( + "Successfully replaced alias {} for index {}".format( + name, index + ) ) else: ret["result"] = False @@ -257,7 +256,7 @@ def index_template_absent(name): index_template = __salt__["elasticsearch.index_template_get"](name=name) if index_template and name in index_template: if __opts__["test"]: - ret["comment"] = "Index template {} will be removed".format(name) + ret["comment"] = f"Index template {name} will be removed" ret["changes"]["old"] = index_template[name] ret["result"] = None else: @@ -270,13 +269,13 @@ def index_template_absent(name): ) ret["changes"]["old"] = index_template[name] else: - ret[ - "comment" - ] = "Failed to remove index template {} for unknown reasons".format( - name + ret["comment"] = ( + "Failed to remove index template {} for unknown reasons".format( + name + ) ) else: - ret["comment"] = "Index template {} is already absent".format(name) + ret["comment"] = f"Index template {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -316,9 +315,9 @@ def index_template_present(name, definition, check_definition=False): ) if not index_template_exists: if __opts__["test"]: - ret[ - "comment" - ] = "Index template {} does not exist and will be created".format(name) + ret["comment"] = ( + f"Index template {name} does not exist and will be created" + ) ret["changes"] = {"new": definition} ret["result"] = None else: @@ -357,10 +356,10 @@ def index_template_present(name, definition, check_definition=False): ) if len(diff) != 0: if __opts__["test"]: - ret[ - "comment" - ] = "Index template {} exist but need to be updated".format( - name + ret["comment"] = ( + "Index template {} exist but need to be updated".format( + name + ) ) ret["changes"] = diff ret["result"] = None @@ -369,25 +368,25 @@ def index_template_present(name, definition, check_definition=False): name=name, body=definition ) if output: - ret[ - "comment" - ] = "Successfully updated index template {}".format(name) + ret["comment"] = ( + f"Successfully updated index template {name}" + ) ret["changes"] = diff else: ret["result"] = False - ret[ - "comment" - ] = "Cannot update index template {}, {}".format( - name, output + ret["comment"] = ( + "Cannot update index template {}, {}".format( + name, output + ) ) else: - ret[ - "comment" - ] = "Index template {} is already present and up to date".format( - name + ret["comment"] = ( + "Index template {} is already present and up to date".format( + name + ) ) else: - ret["comment"] = "Index template {} is already present".format(name) + ret["comment"] = f"Index template {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -409,20 +408,20 @@ def pipeline_absent(name): pipeline = __salt__["elasticsearch.pipeline_get"](id=name) if pipeline and name in pipeline: if __opts__["test"]: - ret["comment"] = "Pipeline {} will be removed".format(name) + ret["comment"] = f"Pipeline {name} will be removed" ret["changes"]["old"] = pipeline[name] ret["result"] = None else: ret["result"] = __salt__["elasticsearch.pipeline_delete"](id=name) if ret["result"]: - ret["comment"] = "Successfully removed pipeline {}".format(name) + ret["comment"] = f"Successfully removed pipeline {name}" ret["changes"]["old"] = pipeline[name] else: - ret[ - "comment" - ] = "Failed to remove pipeline {} for unknown reasons".format(name) + ret["comment"] = ( + f"Failed to remove pipeline {name} for unknown reasons" + ) else: - ret["comment"] = "Pipeline {} is already absent".format(name) + ret["comment"] = f"Pipeline {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -465,9 +464,9 @@ def pipeline_present(name, definition): if ret["changes"] or not definition: if __opts__["test"]: if not pipeline: - ret[ - "comment" - ] = "Pipeline {} does not exist and will be created".format(name) + ret["comment"] = ( + f"Pipeline {name} does not exist and will be created" + ) else: ret["comment"] = ( "Pipeline {} exists with wrong configuration and will be" @@ -481,7 +480,7 @@ def pipeline_present(name, definition): ) if output: if not pipeline: - ret["comment"] = "Successfully created pipeline {}".format(name) + ret["comment"] = f"Successfully created pipeline {name}" else: ret["comment"] = "Successfully replaced pipeline {}".format( name @@ -492,7 +491,7 @@ def pipeline_present(name, definition): name, output ) else: - ret["comment"] = "Pipeline {} is already present".format(name) + ret["comment"] = f"Pipeline {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -514,7 +513,7 @@ def search_template_absent(name): template = __salt__["elasticsearch.search_template_get"](id=name) if template: if __opts__["test"]: - ret["comment"] = "Search template {} will be removed".format(name) + ret["comment"] = f"Search template {name} will be removed" ret["changes"]["old"] = salt.utils.json.loads(template["template"]) ret["result"] = None else: @@ -527,13 +526,13 @@ def search_template_absent(name): ) ret["changes"]["old"] = salt.utils.json.loads(template["template"]) else: - ret[ - "comment" - ] = "Failed to remove search template {} for unknown reasons".format( - name + ret["comment"] = ( + "Failed to remove search template {} for unknown reasons".format( + name + ) ) else: - ret["comment"] = "Search template {} is already absent".format(name) + ret["comment"] = f"Search template {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -575,10 +574,10 @@ def search_template_present(name, definition): if ret["changes"] or not definition: if __opts__["test"]: if not template: - ret[ - "comment" - ] = "Search template {} does not exist and will be created".format( - name + ret["comment"] = ( + "Search template {} does not exist and will be created".format( + name + ) ) else: ret["comment"] = ( @@ -593,20 +592,16 @@ def search_template_present(name, definition): ) if output: if not template: - ret[ - "comment" - ] = "Successfully created search template {}".format(name) + ret["comment"] = f"Successfully created search template {name}" else: - ret[ - "comment" - ] = "Successfully replaced search template {}".format(name) + ret["comment"] = f"Successfully replaced search template {name}" else: ret["result"] = False ret["comment"] = "Cannot create search template {}, {}".format( name, output ) else: - ret["comment"] = "Search template {} is already present".format(name) + ret["comment"] = f"Search template {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) diff --git a/salt/states/elasticsearch_index.py b/salt/states/elasticsearch_index.py index 9acd98a629c..dcf0d442579 100644 --- a/salt/states/elasticsearch_index.py +++ b/salt/states/elasticsearch_index.py @@ -6,7 +6,6 @@ State module to manage Elasticsearch indices Use elasticsearch state instead """ - import logging log = logging.getLogger(__name__) @@ -26,20 +25,20 @@ def absent(name): index = __salt__["elasticsearch.index_get"](index=name) if index and name in index: if __opts__["test"]: - ret["comment"] = "Index {} will be removed".format(name) + ret["comment"] = f"Index {name} will be removed" ret["changes"]["old"] = index[name] ret["result"] = None else: ret["result"] = __salt__["elasticsearch.index_delete"](index=name) if ret["result"]: - ret["comment"] = "Successfully removed index {}".format(name) + ret["comment"] = f"Successfully removed index {name}" ret["changes"]["old"] = index[name] else: - ret[ - "comment" - ] = "Failed to remove index {} for unknown reasons".format(name) + ret["comment"] = ( + f"Failed to remove index {name} for unknown reasons" + ) else: - ret["comment"] = "Index {} is already absent".format(name) + ret["comment"] = f"Index {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -94,15 +93,15 @@ def present(name, definition=None): index=name, body=definition ) if output: - ret["comment"] = "Successfully created index {}".format(name) + ret["comment"] = f"Successfully created index {name}" ret["changes"] = { "new": __salt__["elasticsearch.index_get"](index=name)[name] } else: ret["result"] = False - ret["comment"] = "Cannot create index {}, {}".format(name, output) + ret["comment"] = f"Cannot create index {name}, {output}" else: - ret["comment"] = "Index {} is already present".format(name) + ret["comment"] = f"Index {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) diff --git a/salt/states/elasticsearch_index_template.py b/salt/states/elasticsearch_index_template.py index 841fa381b43..c4574bd9dc7 100644 --- a/salt/states/elasticsearch_index_template.py +++ b/salt/states/elasticsearch_index_template.py @@ -6,7 +6,6 @@ State module to manage Elasticsearch index templates Use elasticsearch state instead """ - import logging log = logging.getLogger(__name__) @@ -26,7 +25,7 @@ def absent(name): index_template = __salt__["elasticsearch.index_template_get"](name=name) if index_template and name in index_template: if __opts__["test"]: - ret["comment"] = "Index template {} will be removed".format(name) + ret["comment"] = f"Index template {name} will be removed" ret["changes"]["old"] = index_template[name] ret["result"] = None else: @@ -39,13 +38,13 @@ def absent(name): ) ret["changes"]["old"] = index_template[name] else: - ret[ - "comment" - ] = "Failed to remove index template {} for unknown reasons".format( - name + ret["comment"] = ( + "Failed to remove index template {} for unknown reasons".format( + name + ) ) else: - ret["comment"] = "Index template {} is already absent".format(name) + ret["comment"] = f"Index template {name} is already absent" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) @@ -88,9 +87,9 @@ def present(name, definition): ) if not index_template_exists: if __opts__["test"]: - ret[ - "comment" - ] = "Index template {} does not exist and will be created".format(name) + ret["comment"] = ( + f"Index template {name} does not exist and will be created" + ) ret["changes"] = {"new": definition} ret["result"] = None else: @@ -112,7 +111,7 @@ def present(name, definition): name, output ) else: - ret["comment"] = "Index template {} is already present".format(name) + ret["comment"] = f"Index template {name} is already present" except Exception as err: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(err) diff --git a/salt/states/environ.py b/salt/states/environ.py index fb495d1af44..ad574b10344 100644 --- a/salt/states/environ.py +++ b/salt/states/environ.py @@ -3,7 +3,6 @@ Support for getting and setting the environment variables of the current salt process. """ - import os import salt.utils.platform diff --git a/salt/states/eselect.py b/salt/states/eselect.py index 18d4f644771..2b5196cea17 100644 --- a/salt/states/eselect.py +++ b/salt/states/eselect.py @@ -6,7 +6,6 @@ A state module to manage Gentoo configuration via eselect """ - # Define a function alias in order not to shadow built-in's __func_alias__ = {"set_": "set"} @@ -60,7 +59,7 @@ def set_(name, target, module_parameter=None, action_parameter=None): ) ret["result"] = False elif __opts__["test"]: - ret["comment"] = "Target '{}' will be set on '{}' module.".format(target, name) + ret["comment"] = f"Target '{target}' will be set on '{name}' module." ret["result"] = None else: result = __salt__["eselect.set_target"]( @@ -71,7 +70,7 @@ def set_(name, target, module_parameter=None, action_parameter=None): ) if result: ret["changes"][name] = {"old": old_target, "new": target} - ret["comment"] = "Target '{}' set on '{}' module.".format(target, name) + ret["comment"] = f"Target '{target}' set on '{name}' module." else: ret["comment"] = "Target '{}' failed to be set on '{}' module.".format( target, name diff --git a/salt/states/esxcluster.py b/salt/states/esxcluster.py index f2d7fbc9c36..700f12830d9 100644 --- a/salt/states/esxcluster.py +++ b/salt/states/esxcluster.py @@ -48,7 +48,6 @@ The 5.5.0.2014.1.1 is a known stable version that this original ESXi State Module was developed against. """ - import logging import sys from functools import wraps @@ -402,11 +401,11 @@ def vsan_datastore_configured(name, datastore_name): ret.update( { - "result": True - if (not changes_required) - else None - if __opts__["test"] - else True, + "result": ( + True + if (not changes_required) + else None if __opts__["test"] else True + ), "comment": "\n".join(comments), "changes": changes, } @@ -600,13 +599,11 @@ def licenses_configured(name, licenses=None): ret.update( { - "result": True - if (not needs_changes) - else None - if __opts__["test"] - else False - if has_errors - else True, + "result": ( + True + if (not needs_changes) + else None if __opts__["test"] else False if has_errors else True + ), "comment": "\n".join(comments), "changes": changes if not __opts__["test"] else {}, } diff --git a/salt/states/esxdatacenter.py b/salt/states/esxdatacenter.py index 10cd01d5507..0ee6f685ff7 100644 --- a/salt/states/esxdatacenter.py +++ b/salt/states/esxdatacenter.py @@ -58,7 +58,6 @@ State configuration: esxdatacenter.datacenter_configured """ - import logging from functools import wraps diff --git a/salt/states/esxi.py b/salt/states/esxi.py index 6a910c5f114..a0e4fd0edbb 100644 --- a/salt/states/esxi.py +++ b/salt/states/esxi.py @@ -1397,11 +1397,11 @@ def diskgroups_configured(name, diskgroups, erase_disks=False): result = ( True if not (changes or errors) - else None # no changes/errors - if __opts__["test"] - else False # running in test mode - if errors - else True + else ( + None # no changes/errors + if __opts__["test"] + else False if errors else True # running in test mode + ) ) # found errors; defaults to True ret.update( {"result": result, "comment": "\n".join(comments), "changes": diskgroup_changes} diff --git a/salt/states/esxvm.py b/salt/states/esxvm.py index 8fa551c2b19..0a1efed9a56 100644 --- a/salt/states/esxvm.py +++ b/salt/states/esxvm.py @@ -192,7 +192,6 @@ execution functions against ESXi hosts via a Salt Proxy Minion, and a larger sta example. """ - import logging import sys from functools import wraps diff --git a/salt/states/etcd_mod.py b/salt/states/etcd_mod.py index ec8cc96c355..b86e89680c7 100644 --- a/salt/states/etcd_mod.py +++ b/salt/states/etcd_mod.py @@ -154,7 +154,6 @@ Available Functions - file: /some/file.txt """ - # Define the module's virtual name __virtualname__ = "etcd" @@ -187,7 +186,7 @@ def __virtual__(): def _etcd_action(*, action, key, profile, value=None, **kwargs): try: - ret = __salt__["etcd.{}".format(action)]( + ret = __salt__[f"etcd.{action}"]( key=key, profile=profile, value=value, **kwargs ) except Exception: # pylint: disable=broad-except diff --git a/salt/states/ethtool.py b/salt/states/ethtool.py index 3d9fff691ec..25367cd8e48 100644 --- a/salt/states/ethtool.py +++ b/salt/states/ethtool.py @@ -29,7 +29,6 @@ Configuration of network device """ - import logging from salt.exceptions import CommandExecutionError @@ -87,7 +86,7 @@ def coalesce(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} coalescing settings are up to date.".format(name), + "comment": f"Network device {name} coalescing settings are up to date.", } apply_coalescing = False if "test" not in kwargs: @@ -110,7 +109,7 @@ def coalesce(name, **kwargs): for key, value in kwargs.items(): if key in old and value != old[key]: new.update({key: value}) - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") # Dry run if kwargs["test"]: @@ -118,17 +117,17 @@ def coalesce(name, **kwargs): return ret if new: ret["result"] = None - ret[ - "comment" - ] = "Device {} coalescing settings are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Device {} coalescing settings are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret # Prepare return output if new: apply_coalescing = True - ret["comment"] = "Device {} coalescing settings updated.".format(name) + ret["comment"] = f"Device {name} coalescing settings updated." ret["changes"]["ethtool_coalesce"] = "\n".join(diff) except AttributeError as error: @@ -172,7 +171,7 @@ def ring(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} ring parameters are up to date.".format(name), + "comment": f"Network device {name} ring parameters are up to date.", } apply_ring = False if "test" not in kwargs: @@ -183,7 +182,7 @@ def ring(name, **kwargs): old = __salt__["ethtool.show_ring"](name) if not isinstance(old, dict): ret["result"] = False - ret["comment"] = "Device {} ring parameters are not supported".format(name) + ret["comment"] = f"Device {name} ring parameters are not supported" return ret new = {} @@ -193,11 +192,11 @@ def ring(name, **kwargs): for key, value in kwargs.items(): if key in old: if value == "max": - value = old["{}_max".format(key)] + value = old[f"{key}_max"] if value != old[key]: new.update({key: value}) - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") # Dry run if kwargs["test"]: @@ -205,17 +204,17 @@ def ring(name, **kwargs): return ret if new: ret["result"] = None - ret[ - "comment" - ] = "Device {} ring parameters are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Device {} ring parameters are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret # Prepare return output if new: apply_ring = True - ret["comment"] = "Device {} ring parameters updated.".format(name) + ret["comment"] = f"Device {name} ring parameters updated." ret["changes"]["ethtool_ring"] = "\n".join(diff) except AttributeError as error: @@ -254,7 +253,7 @@ def offload(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} offload settings are up to date.".format(name), + "comment": f"Network device {name} offload settings are up to date.", } apply_offload = False if "test" not in kwargs: @@ -265,7 +264,7 @@ def offload(name, **kwargs): old = __salt__["ethtool.show_offload"](name) if not isinstance(old, dict): ret["result"] = False - ret["comment"] = "Device {} offload settings are not supported".format(name) + ret["comment"] = f"Device {name} offload settings are not supported" return ret new = {} @@ -276,7 +275,7 @@ def offload(name, **kwargs): value = value and "on" or "off" if key in old and value != old[key]: new.update({key: value}) - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") # Dry run if kwargs["test"]: @@ -284,17 +283,17 @@ def offload(name, **kwargs): return ret if new: ret["result"] = None - ret[ - "comment" - ] = "Device {} offload settings are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Device {} offload settings are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret # Prepare return output if new: apply_offload = True - ret["comment"] = "Device {} offload settings updated.".format(name) + ret["comment"] = f"Device {name} offload settings updated." ret["changes"]["ethtool_offload"] = "\n".join(diff) except AttributeError as error: @@ -337,7 +336,7 @@ def pause(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Network device {} pause parameters are up to date.".format(name), + "comment": f"Network device {name} pause parameters are up to date.", } apply_pause = False @@ -346,7 +345,7 @@ def pause(name, **kwargs): old = __salt__["ethtool.show_pause"](name) except CommandExecutionError: ret["result"] = False - ret["comment"] = "Device {} pause parameters are not supported".format(name) + ret["comment"] = f"Device {name} pause parameters are not supported" return ret # map ethtool command input to output text @@ -369,7 +368,7 @@ def pause(name, **kwargs): value = "on" elif value is False: value = "off" - diff.append("{}: {}".format(key, value)) + diff.append(f"{key}: {value}") if not new: return ret @@ -386,7 +385,7 @@ def pause(name, **kwargs): try: __salt__["ethtool.set_pause"](name, **new) # Prepare return output - ret["comment"] = "Device {} pause parameters updated.".format(name) + ret["comment"] = f"Device {name} pause parameters updated." ret["changes"]["ethtool_pause"] = "\n".join(diff) except CommandExecutionError as exc: ret["result"] = False diff --git a/salt/states/event.py b/salt/states/event.py index 2026b2e2032..759bd16dd83 100644 --- a/salt/states/event.py +++ b/salt/states/event.py @@ -2,7 +2,6 @@ Send events through Salt's event system during state runs """ - import salt.utils.functools diff --git a/salt/states/file.py b/salt/states/file.py index 8daf99c5f08..1eecd5bd673 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -277,7 +277,6 @@ For example: """ - import copy import difflib import itertools @@ -1137,7 +1136,7 @@ def _get_template_texts( txtl = [] - for (source, source_hash) in source_list: + for source, source_hash in source_list: tmpctx = defaults if defaults else {} if context: @@ -1898,9 +1897,7 @@ def symlink( fs_entry_type = ( "File" if os.path.isfile(name) - else "Directory" - if os.path.isdir(name) - else "File system entry" + else "Directory" if os.path.isdir(name) else "File system entry" ) return _error( ret, @@ -3261,9 +3258,9 @@ def managed( else: ret["comment"] = f"File {name} not updated" elif not ret["changes"] and ret["result"]: - ret[ - "comment" - ] = f"File {name} exists with proper permissions. No changes made." + ret["comment"] = ( + f"File {name} exists with proper permissions. No changes made." + ) return ret accum_data, _ = _load_accumulators() @@ -4183,9 +4180,9 @@ def directory( # As above with user, we need to make sure group exists. if isinstance(gid, str): ret["result"] = False - ret[ - "comment" - ] = f"Failed to enforce group ownership for group {group}" + ret["comment"] = ( + f"Failed to enforce group ownership for group {group}" + ) else: ret["result"] = False ret["comment"] = ( @@ -6199,9 +6196,9 @@ def blockreplace( ) except Exception as exc: # pylint: disable=broad-except log.exception("Encountered error managing block") - ret[ - "comment" - ] = f"Encountered error managing block: {exc}. See the log for details." + ret["comment"] = ( + f"Encountered error managing block: {exc}. See the log for details." + ) return ret if changes: @@ -7700,9 +7697,9 @@ def copy_( ) ret["result"] = None else: - ret[ - "comment" - ] = f'The target file "{name}" exists and will not be overwritten' + ret["comment"] = ( + f'The target file "{name}" exists and will not be overwritten' + ) ret["result"] = True return ret @@ -7802,9 +7799,9 @@ def rename(name, source, force=False, makedirs=False, **kwargs): if os.path.lexists(source) and os.path.lexists(name): if not force: - ret[ - "comment" - ] = f'The target file "{name}" exists and will not be overwritten' + ret["comment"] = ( + f'The target file "{name}" exists and will not be overwritten' + ) return ret elif not __opts__["test"]: # Remove the destination to prevent problems later @@ -8561,10 +8558,10 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): elif ntype == "b": # Check for file existence if __salt__["file.file_exists"](name): - ret[ - "comment" - ] = "File {} exists and is not a block device. Refusing to continue".format( - name + ret["comment"] = ( + "File {} exists and is not a block device. Refusing to continue".format( + name + ) ) # Check if it is a block device @@ -8596,10 +8593,10 @@ def mknod(name, ntype, major=0, minor=0, user=None, group=None, mode="0600"): elif ntype == "p": # Check for file existence if __salt__["file.file_exists"](name): - ret[ - "comment" - ] = "File {} exists and is not a fifo pipe. Refusing to continue".format( - name + ret["comment"] = ( + "File {} exists and is not a fifo pipe. Refusing to continue".format( + name + ) ) # Check if it is a fifo @@ -9260,10 +9257,10 @@ def cached( ) if local_hash == source_sum["hsum"]: ret["result"] = True - ret[ - "comment" - ] = "File {} is present on the minion and has hash {}".format( - full_path, local_hash + ret["comment"] = ( + "File {} is present on the minion and has hash {}".format( + full_path, local_hash + ) ) else: ret["comment"] = ( @@ -9321,10 +9318,10 @@ def cached( return ret if not local_copy: - ret[ - "comment" - ] = "Failed to cache {}, check minion log for more information".format( - salt.utils.url.redact_http_basic_auth(name) + ret["comment"] = ( + "Failed to cache {}, check minion log for more information".format( + salt.utils.url.redact_http_basic_auth(name) + ) ) return ret diff --git a/salt/states/firewalld.py b/salt/states/firewalld.py index 7aab15e1382..d3e69560a25 100644 --- a/salt/states/firewalld.py +++ b/salt/states/firewalld.py @@ -102,7 +102,6 @@ with an example output of: rule service name="snmp" accept """ - import logging import salt.utils.path @@ -204,7 +203,6 @@ def present( rich_rules=None, prune_rich_rules=False, ): - """ Ensure a zone has specific attributes. diff --git a/salt/states/gem.py b/salt/states/gem.py index e5a1ab26b8b..66477e60cff 100644 --- a/salt/states/gem.py +++ b/salt/states/gem.py @@ -118,7 +118,7 @@ def installed( return ret if __opts__["test"]: - ret["comment"] = "The gem {} would have been installed".format(name) + ret["comment"] = f"The gem {name} would have been installed" return ret if __salt__["gem.install"]( name, @@ -169,7 +169,7 @@ def removed(name, ruby=None, user=None, gem_bin=None): return ret if __opts__["test"]: - ret["comment"] = "The gem {} would have been removed".format(name) + ret["comment"] = f"The gem {name} would have been removed" return ret if __salt__["gem.uninstall"](name, ruby, gem_bin=gem_bin, runas=user): ret["result"] = True @@ -203,7 +203,7 @@ def sources_add(name, ruby=None, user=None): ret["comment"] = "Gem source is already added." return ret if __opts__["test"]: - ret["comment"] = "The gem source {} would have been added.".format(name) + ret["comment"] = f"The gem source {name} would have been added." return ret if __salt__["gem.sources_add"](source_uri=name, ruby=ruby, runas=user): ret["result"] = True diff --git a/salt/states/git.py b/salt/states/git.py index 0f3f977442e..d4d91f0383f 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -144,7 +144,7 @@ def _strip_exc(exc): def _uptodate(ret, target, comments=None, local_changes=False): - ret["comment"] = "Repository {} is up-to-date".format(target) + ret["comment"] = f"Repository {target} is up-to-date" if local_changes: ret["comment"] += ( ", but with uncommitted changes. Set 'force_reset' to True to " @@ -177,7 +177,7 @@ def _fail(ret, msg, comments=None): def _already_cloned(ret, target, branch=None, comments=None): ret["result"] = True ret["comment"] = "Repository already exists at {}{}".format( - target, " and is checked out to branch '{}'".format(branch) if branch else "" + target, f" and is checked out to branch '{branch}'" if branch else "" ) if comments: ret["comment"] += "\n\nChanges {}made: {}".format( @@ -234,15 +234,17 @@ def _not_fast_forward( ret, "Repository would be updated {}{}, but {}. Set 'force_reset' to " "True{} to force this update{}.{}".format( - "from {} to {}".format(pre, post) - if local_changes and pre != post - else "to {}".format(post), - " (after checking out local branch '{}')".format(branch) - if _need_branch_change(branch, local_branch) - else "", - "this is not a fast-forward merge" - if not local_changes - else "there are uncommitted changes", + f"from {pre} to {post}" if local_changes and pre != post else f"to {post}", + ( + f" (after checking out local branch '{branch}')" + if _need_branch_change(branch, local_branch) + else "" + ), + ( + "this is not a fast-forward merge" + if not local_changes + else "there are uncommitted changes" + ), " (or 'remote-changes')" if local_changes else "", " and discard these changes" if local_changes else "", branch_msg, @@ -276,7 +278,7 @@ def latest( refspec_branch="*", refspec_tag="*", output_encoding=None, - **kwargs + **kwargs, ): """ Make sure the repository is cloned to the given directory and is @@ -619,9 +621,7 @@ def latest( return _fail(ret, "'target' argument is required") if not rev: - return _fail( - ret, "'{}' is not a valid value for the 'rev' argument".format(rev) - ) + return _fail(ret, f"'{rev}' is not a valid value for the 'rev' argument") if force_reset not in (True, False, "remote-changes"): return _fail( @@ -635,7 +635,7 @@ def latest( if not isinstance(target, str): target = str(target) if not os.path.isabs(target): - return _fail(ret, "target '{}' is not an absolute path".format(target)) + return _fail(ret, f"target '{target}' is not an absolute path") if branch is not None and not isinstance(branch, str): branch = str(branch) if user is not None and not isinstance(user, str): @@ -656,13 +656,9 @@ def latest( ident_path = __salt__["cp.cache_file"](ident_path, __env__) except OSError as exc: log.exception("Failed to cache %s", ident_path) - return _fail( - ret, "identity '{}' does not exist.".format(ident_path) - ) + return _fail(ret, f"identity '{ident_path}' does not exist.") if not os.path.isabs(ident_path): - return _fail( - ret, "identity '{}' is not an absolute path".format(ident_path) - ) + return _fail(ret, f"identity '{ident_path}' is not an absolute path") if https_user is not None and not isinstance(https_user, str): https_user = str(https_user) if https_pass is not None and not isinstance(https_pass, str): @@ -681,7 +677,7 @@ def latest( if os.path.isfile(target): return _fail( ret, - "Target '{}' exists and is a regular file, cannot proceed".format(target), + f"Target '{target}' exists and is a regular file, cannot proceed", ) try: @@ -731,7 +727,7 @@ def latest( output_encoding=output_encoding, ) except CommandExecutionError as exc: - return _fail(ret, "Failed to check remote refs: {}".format(_strip_exc(exc))) + return _fail(ret, f"Failed to check remote refs: {_strip_exc(exc)}") if "HEAD" in all_remote_refs: head_rev = all_remote_refs["HEAD"] @@ -825,7 +821,7 @@ def latest( # remote repo. return _fail( ret, - "No revision matching '{}' exists in the remote repository".format(rev), + f"No revision matching '{rev}' exists in the remote repository", ) git_ver = Version(__salt__["git.version"](versioninfo=False)) @@ -1200,9 +1196,7 @@ def latest( output_encoding=output_encoding, ) if fetch_url is None: - comments.append( - "Remote '{}' set to {}".format(remote, redacted_fetch_url) - ) + comments.append(f"Remote '{remote}' set to {redacted_fetch_url}") ret["changes"]["new"] = name + " => " + remote else: comments.append( @@ -1217,7 +1211,7 @@ def latest( if __opts__["test"]: actions = [] if not has_remote_rev: - actions.append("Remote '{}' would be fetched".format(remote)) + actions.append(f"Remote '{remote}' would be fetched") if (not revs_match) and ( update_head or (branch is not None and branch != local_branch) ): @@ -1258,9 +1252,11 @@ def latest( else: actions.append( "Repository would be {} from {} to {}".format( - "hard-reset" - if force_reset and has_remote_rev - else "updated", + ( + "hard-reset" + if force_reset and has_remote_rev + else "updated" + ), _short_sha(local_rev), _short_sha(remote_rev), ) @@ -1418,7 +1414,7 @@ def latest( else: if fetch_changes: comments.append( - "{} was fetched, resulting in updated refs".format(name) + f"{name} was fetched, resulting in updated refs" ) try: @@ -1518,7 +1514,7 @@ def latest( "as a starting point".format(branch, remote_loc) ) else: - comments.append("'{}' was checked out".format(checkout_rev)) + comments.append(f"'{checkout_rev}' was checked out") if fast_forward is False: __salt__["git.reset"]( @@ -1527,14 +1523,12 @@ def latest( user=user, password=password, output_encoding=output_encoding, - **lfs_opts + **lfs_opts, ) ret["changes"]["forced update"] = True if local_changes: comments.append("Uncommitted changes were discarded") - comments.append( - "Repository was hard-reset to {}".format(remote_loc) - ) + comments.append(f"Repository was hard-reset to {remote_loc}") elif ( fast_forward is True and local_changes and force_reset is not False ): @@ -1595,10 +1589,10 @@ def latest( user=user, password=password, output_encoding=output_encoding, - **lfs_opts + **lfs_opts, ) comments.append( - "Repository was fast-forwarded to {}".format(remote_loc) + f"Repository was fast-forwarded to {remote_loc}" ) else: return _fail( @@ -1615,11 +1609,9 @@ def latest( user=user, password=password, output_encoding=output_encoding, - **lfs_opts - ) - comments.append( - "Repository was reset to {} (fast-forward)".format(rev) + **lfs_opts, ) + comments.append(f"Repository was reset to {rev} (fast-forward)") # TODO: Figure out how to add submodule update info to # test=True return data, and changes dict. @@ -1639,7 +1631,7 @@ def latest( return _failed_submodule_update(ret, exc, comments) elif bare: if __opts__["test"]: - msg = "Bare repository at {} would be fetched".format(target) + msg = f"Bare repository at {target} would be fetched" if ret["changes"]: return _neutral_test(ret, msg) else: @@ -1724,9 +1716,7 @@ def latest( if exc.errno != errno.ENOENT: removal_errors[target_path] = exc if removal_errors: - err_strings = [ - " {}\n {}".format(k, v) for k, v in removal_errors.items() - ] + err_strings = [f" {k}\n {v}" for k, v in removal_errors.items()] return _fail( ret, "Unable to remove\n{}".format("\n".join(err_strings)), @@ -1747,9 +1737,7 @@ def latest( log.debug("Target %s is not found, 'git clone' is required", target) if __opts__["test"]: ret["changes"]["new"] = name + " => " + target - return _neutral_test( - ret, "Repository {} would be cloned to {}".format(name, target) - ) + return _neutral_test(ret, f"Repository {name} would be cloned to {target}") try: clone_opts = ["--mirror"] if mirror else ["--bare"] if bare else [] if remote != "origin": @@ -1774,7 +1762,7 @@ def latest( output_encoding=output_encoding, ) except CommandExecutionError as exc: - msg = "Clone failed: {}".format(_strip_exc(exc)) + msg = f"Clone failed: {_strip_exc(exc)}" return _fail(ret, msg, comments) ret["changes"]["new"] = name + " => " + target @@ -1813,7 +1801,7 @@ def latest( ): return _fail( ret, - "Revision '{}' does not exist in clone".format(rev), + f"Revision '{rev}' does not exist in clone", comments, ) @@ -1872,7 +1860,7 @@ def latest( password=password, output_encoding=output_encoding, ) - comments.append("Repository was reset to {}".format(remote_loc)) + comments.append(f"Repository was reset to {remote_loc}") try: upstream = __salt__["git.rev_parse"]( @@ -2110,7 +2098,7 @@ def present( else: salt.utils.files.rm_rf(name) except OSError as exc: - return _fail(ret, "Unable to remove {}: {}".format(name, exc)) + return _fail(ret, f"Unable to remove {name}: {exc}") else: ret["changes"]["forced init"] = True elif os.listdir(name): @@ -2142,9 +2130,9 @@ def present( actions = ["Initialized {}repository in {}".format("bare " if bare else "", name)] if template: - actions.append("Template directory set to {}".format(template)) + actions.append(f"Template directory set to {template}") if separate_git_dir: - actions.append("Gitdir set to {}".format(separate_git_dir)) + actions.append(f"Gitdir set to {separate_git_dir}") message = ". ".join(actions) if len(actions) > 1: message += "." @@ -2170,7 +2158,7 @@ def detached( https_user=None, https_pass=None, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2016.3.0 @@ -2261,14 +2249,10 @@ def detached( return _fail(ret, salt.utils.args.invalid_kwargs(kwargs, raise_exc=False)) if not rev: - return _fail( - ret, "'{}' is not a valid value for the 'rev' argument".format(rev) - ) + return _fail(ret, f"'{rev}' is not a valid value for the 'rev' argument") if not target: - return _fail( - ret, "'{}' is not a valid value for the 'target' argument".format(rev) - ) + return _fail(ret, f"'{rev}' is not a valid value for the 'target' argument") # Ensure that certain arguments are strings to ensure that comparisons work if not isinstance(rev, str): @@ -2277,7 +2261,7 @@ def detached( if not isinstance(target, str): target = str(target) if not os.path.isabs(target): - return _fail(ret, "Target '{}' is not an absolute path".format(target)) + return _fail(ret, f"Target '{target}' is not an absolute path") if user is not None and not isinstance(user, str): user = str(user) if remote is not None and not isinstance(remote, str): @@ -2294,13 +2278,9 @@ def detached( ident_path = __salt__["cp.cache_file"](ident_path) except OSError as exc: log.error("Failed to cache %s: %s", ident_path, exc) - return _fail( - ret, "Identity '{}' does not exist.".format(ident_path) - ) + return _fail(ret, f"Identity '{ident_path}' does not exist.") if not os.path.isabs(ident_path): - return _fail( - ret, "Identity '{}' is not an absolute path".format(ident_path) - ) + return _fail(ret, f"Identity '{ident_path}' is not an absolute path") if https_user is not None and not isinstance(https_user, str): https_user = str(https_user) if https_pass is not None and not isinstance(https_pass, str): @@ -2309,7 +2289,7 @@ def detached( if os.path.isfile(target): return _fail( ret, - "Target '{}' exists and is a regular file, cannot proceed".format(target), + f"Target '{target}' exists and is a regular file, cannot proceed", ) try: @@ -2377,9 +2357,7 @@ def detached( current_fetch_url = remotes[remote]["fetch"] if __opts__["test"]: - return _neutral_test( - ret, "Remote {} would be set to {}".format(remote, name) - ) + return _neutral_test(ret, f"Remote {remote} would be set to {name}") __salt__["git.remote_set"]( target, @@ -2427,9 +2405,7 @@ def detached( if exc.errno != errno.ENOENT: removal_errors[target_path] = exc if removal_errors: - err_strings = [ - " {}\n {}".format(k, v) for k, v in removal_errors.items() - ] + err_strings = [f" {k}\n {v}" for k, v in removal_errors.items()] return _fail( ret, "Unable to remove\n{}".format("\n".join(err_strings)), @@ -2449,9 +2425,7 @@ def detached( log.debug("Target %s is not found, 'git clone' is required", target) if __opts__["test"]: - return _neutral_test( - ret, "Repository {} would be cloned to {}".format(name, target) - ) + return _neutral_test(ret, f"Repository {name} would be cloned to {target}") try: clone_opts = ["--no-checkout"] if remote != "origin": @@ -2469,7 +2443,7 @@ def detached( saltenv=__env__, output_encoding=output_encoding, ) - comments.append("{} cloned to {}".format(name, target)) + comments.append(f"{name} cloned to {target}") except Exception as exc: # pylint: disable=broad-except log.error("Unexpected exception in git.detached state", exc_info=True) @@ -2481,7 +2455,7 @@ def detached( # Repository exists and is ready for fetch/checkout refspecs = [ - "refs/heads/*:refs/remotes/{}/*".format(remote), + f"refs/heads/*:refs/remotes/{remote}/*", "+refs/tags/*:refs/tags/*", ] if hash_exists_locally or fetch_remote is False: @@ -2489,9 +2463,7 @@ def detached( else: # Fetch refs from remote if __opts__["test"]: - return _neutral_test( - ret, "Repository remote {} would be fetched".format(remote) - ) + return _neutral_test(ret, f"Repository remote {remote} would be fetched") try: fetch_changes = __salt__["git.fetch"]( target, @@ -2511,7 +2483,7 @@ def detached( else: if fetch_changes: comments.append( - "Remote {} was fetched, resulting in updated refs".format(remote) + f"Remote {remote} was fetched, resulting in updated refs" ) # get refs and checkout @@ -2522,7 +2494,7 @@ def detached( ): checkout_commit_id = rev else: - return _fail(ret, "Revision '{}' does not exist".format(rev)) + return _fail(ret, f"Revision '{rev}' does not exist") else: try: all_remote_refs = __salt__["git.remote_refs"]( @@ -2543,17 +2515,15 @@ def detached( elif "refs/tags/" + rev in all_remote_refs: checkout_commit_id = all_remote_refs["refs/tags/" + rev] else: - return _fail(ret, "Revision '{}' does not exist".format(rev)) + return _fail(ret, f"Revision '{rev}' does not exist") except CommandExecutionError as exc: - return _fail( - ret, "Failed to list refs for {}: {}".format(remote, _strip_exc(exc)) - ) + return _fail(ret, f"Failed to list refs for {remote}: {_strip_exc(exc)}") if hard_reset: if __opts__["test"]: return _neutral_test( - ret, "Hard reset to HEAD would be performed on {}".format(target) + ret, f"Hard reset to HEAD would be performed on {target}" ) __salt__["git.reset"]( target, @@ -2585,9 +2555,7 @@ def detached( password=password, output_encoding=output_encoding, ) - comments.append( - "Commit ID {} was checked out at {}".format(checkout_commit_id, target) - ) + comments.append(f"Commit ID {checkout_commit_id} was checked out at {target}") try: new_rev = __salt__["git.revision"]( @@ -2734,7 +2702,7 @@ def cloned( comment = "{} would be cloned to {}{}".format( name, target, - " with branch '{}'".format(branch) if branch is not None else "", + f" with branch '{branch}'" if branch is not None else "", ) return _neutral_test(ret, comment) clone_opts = ["--branch", branch] if branch is not None else None @@ -2751,14 +2719,14 @@ def cloned( output_encoding=output_encoding, ) except CommandExecutionError as exc: - msg = "Clone failed: {}".format(_strip_exc(exc)) + msg = f"Clone failed: {_strip_exc(exc)}" return _fail(ret, msg, comments) comments.append( "{} cloned to {}{}".format( name, target, - " with branch '{}'".format(branch) if branch is not None else "", + f" with branch '{branch}'" if branch is not None else "", ) ) _clone_changes(ret) @@ -2777,9 +2745,7 @@ def cloned( else: if __opts__["test"]: _branch_changes(ret, current_branch, branch) - return _neutral_test( - ret, "Branch would be changed to '{}'".format(branch) - ) + return _neutral_test(ret, f"Branch would be changed to '{branch}'") try: __salt__["git.rev_parse"]( target, @@ -2809,10 +2775,10 @@ def cloned( output_encoding=output_encoding, ) except CommandExecutionError as exc: - msg = "Failed to change branch to '{}': {}".format(branch, exc) + msg = f"Failed to change branch to '{branch}': {exc}" return _fail(ret, msg, comments) else: - comments.append("Branch changed to '{}'".format(branch)) + comments.append(f"Branch changed to '{branch}'") _branch_changes(ret, current_branch, branch) ret["comment"] = _format_comments(comments) ret["result"] = True @@ -2826,7 +2792,7 @@ def config_unset( user=None, password=None, output_encoding=None, - **kwargs + **kwargs, ): r""" .. versionadded:: 2015.8.0 @@ -2951,7 +2917,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) if not pre_matches: @@ -2984,7 +2950,7 @@ def config_unset( if __opts__["test"]: ret["changes"] = pre_matches return _neutral_test( - ret, "{} key(s) would have value(s) unset".format(len(pre_matches)) + ret, f"{len(pre_matches)} key(s) would have value(s) unset" ) if value_regex is None: @@ -3000,7 +2966,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) failed = [] @@ -3016,10 +2982,10 @@ def config_unset( user=user, password=password, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) except CommandExecutionError as exc: - msg = "Failed to unset '{}'".format(key_name) + msg = f"Failed to unset '{key_name}'" if value_regex is not None: msg += " using value_regex '{1}'" msg += ": " + _strip_exc(exc) @@ -3041,7 +3007,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) for key_name in pre: @@ -3062,7 +3028,7 @@ def config_unset( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) if post_matches: @@ -3081,7 +3047,7 @@ def config_set( user=None, password=None, output_encoding=None, - **kwargs + **kwargs, ): """ .. versionadded:: 2014.7.0 @@ -3219,7 +3185,7 @@ def config_set( password=password, ignore_retcode=True, output_encoding=output_encoding, - **{"all": True, "global": global_} + **{"all": True, "global": global_}, ) if desired == pre: @@ -3248,7 +3214,7 @@ def config_set( user=user, password=password, output_encoding=output_encoding, - **{"global": global_} + **{"global": global_}, ) except CommandExecutionError as exc: return _fail( diff --git a/salt/states/github.py b/salt/states/github.py index f93e6e8799d..e632cf679a5 100644 --- a/salt/states/github.py +++ b/salt/states/github.py @@ -55,15 +55,15 @@ def present(name, profile="github", **kwargs): # If the user has a valid github handle and is not in the org already if not target: ret["result"] = False - ret["comment"] = "Couldnt find user {}".format(name) + ret["comment"] = f"Couldnt find user {name}" elif isinstance(target, bool) and target: - ret["comment"] = "User {} is already in the org ".format(name) + ret["comment"] = f"User {name} is already in the org " ret["result"] = True elif ( not target.get("in_org", False) and target.get("membership_state") != "pending" ): if __opts__["test"]: - ret["comment"] = "User {} will be added to the org".format(name) + ret["comment"] = f"User {name} will be added to the org" return ret # add the user @@ -71,15 +71,13 @@ def present(name, profile="github", **kwargs): if result: ret["changes"].setdefault("old", None) - ret["changes"].setdefault( - "new", "User {} exists in the org now".format(name) - ) + ret["changes"].setdefault("new", f"User {name} exists in the org now") ret["result"] = True else: ret["result"] = False - ret["comment"] = "Failed to add user {} to the org".format(name) + ret["comment"] = f"Failed to add user {name} to the org" else: - ret["comment"] = "User {} has already been invited.".format(name) + ret["comment"] = f"User {name} has already been invited." ret["result"] = True return ret @@ -110,7 +108,7 @@ def absent(name, profile="github", **kwargs): "name": name, "changes": {}, "result": None, - "comment": "User {} is absent.".format(name), + "comment": f"User {name} is absent.", } target = __salt__["github.get_user"](name, profile=profile, **kwargs) @@ -118,25 +116,25 @@ def absent(name, profile="github", **kwargs): if target: if isinstance(target, bool) or target.get("in_org", False): if __opts__["test"]: - ret["comment"] = "User {} will be deleted".format(name) + ret["comment"] = f"User {name} will be deleted" ret["result"] = None return ret result = __salt__["github.remove_user"](name, profile=profile, **kwargs) if result: - ret["comment"] = "Deleted user {}".format(name) - ret["changes"].setdefault("old", "User {} exists".format(name)) - ret["changes"].setdefault("new", "User {} deleted".format(name)) + ret["comment"] = f"Deleted user {name}" + ret["changes"].setdefault("old", f"User {name} exists") + ret["changes"].setdefault("new", f"User {name} deleted") ret["result"] = True else: - ret["comment"] = "Failed to delete {}".format(name) + ret["comment"] = f"Failed to delete {name}" ret["result"] = False else: - ret["comment"] = "User {} has already been deleted!".format(name) + ret["comment"] = f"User {name} has already been deleted!" ret["result"] = True else: - ret["comment"] = "User {} does not exist".format(name) + ret["comment"] = f"User {name} does not exist" ret["result"] = True return ret @@ -153,7 +151,7 @@ def team_present( enforce_mfa=False, no_mfa_grace_seconds=0, profile="github", - **kwargs + **kwargs, ): """ Ensure a team is present @@ -229,7 +227,7 @@ def team_present( if len(parameters) > 0: if __opts__["test"]: test_comments.append( - "Team properties are set to be edited: {}".format(parameters) + f"Team properties are set to be edited: {parameters}" ) ret["result"] = None else: @@ -238,7 +236,7 @@ def team_present( ) if result: ret["changes"]["team"] = { - "old": "Team properties were {}".format(target), + "old": f"Team properties were {target}", "new": "Team properties (that changed) are {}".format( parameters ), @@ -272,8 +270,8 @@ def team_present( ) if result: ret["changes"][repo_name] = { - "old": "Repo {} is not in team {}".format(repo_name, name), - "new": "Repo {} is in team {}".format(repo_name, name), + "old": f"Repo {repo_name} is not in team {name}", + "new": f"Repo {repo_name} is in team {name}", } else: ret["result"] = False @@ -297,21 +295,21 @@ def team_present( ) if result: ret["changes"][repo_name] = { - "old": "Repo {} is in team {}".format(repo_name, name), - "new": "Repo {} is not in team {}".format(repo_name, name), + "old": f"Repo {repo_name} is in team {name}", + "new": f"Repo {repo_name} is not in team {name}", } else: ret["result"] = False - ret[ - "comment" - ] = "Failed to remove repo {} from team {}.".format( - repo_name, name + ret["comment"] = ( + "Failed to remove repo {} from team {}.".format( + repo_name, name + ) ) return ret else: # Team does not exist - it will be created. if __opts__["test"]: - ret["comment"] = "Team {} is set to be created.".format(name) + ret["comment"] = f"Team {name} is set to be created." ret["result"] = None return ret @@ -322,15 +320,15 @@ def team_present( permission=permission, privacy=privacy, profile=profile, - **kwargs + **kwargs, ) if result: ret["changes"]["team"] = {} ret["changes"]["team"]["old"] = None - ret["changes"]["team"]["new"] = "Team {} has been created".format(name) + ret["changes"]["team"]["new"] = f"Team {name} has been created" else: ret["result"] = False - ret["comment"] = "Failed to create team {}.".format(name) + ret["comment"] = f"Failed to create team {name}." return ret manage_members = members is not None @@ -363,9 +361,7 @@ def team_present( else: # Add to team member_change = True if __opts__["test"]: - test_comments.append( - "User {} set to be added to the team.".format(member) - ) + test_comments.append(f"User {member} set to be added to the team.") ret["result"] = None else: result = __salt__["github.add_team_member"]( @@ -375,7 +371,7 @@ def team_present( ret["changes"][member] = {} ret["changes"][member][ "old" - ] = "User {} is not in team {}".format(member, name) + ] = f"User {member} is not in team {name}" ret["changes"][member]["new"] = "User {} is in team {}".format( member, name ) @@ -407,7 +403,7 @@ def team_present( ) else: test_comments.append( - "User {} set to be removed from the team.".format(member) + f"User {member} set to be removed from the team." ) ret["result"] = None else: @@ -417,7 +413,7 @@ def team_present( if result: extra_changes = " due to MFA violation" if mfa_violation else "" ret["changes"][member] = { - "old": "User {} is in team {}".format(member, name), + "old": f"User {member} is in team {name}", "new": "User {} is not in team {}{}".format( member, name, extra_changes ), @@ -473,24 +469,24 @@ def team_absent(name, profile="github", **kwargs): target = __salt__["github.get_team"](name, profile=profile, **kwargs) if not target: - ret["comment"] = "Team {} does not exist".format(name) + ret["comment"] = f"Team {name} does not exist" ret["result"] = True return ret else: if __opts__["test"]: - ret["comment"] = "Team {} will be deleted".format(name) + ret["comment"] = f"Team {name} will be deleted" ret["result"] = None return ret result = __salt__["github.remove_team"](name, profile=profile, **kwargs) if result: - ret["comment"] = "Deleted team {}".format(name) - ret["changes"].setdefault("old", "Team {} exists".format(name)) - ret["changes"].setdefault("new", "Team {} deleted".format(name)) + ret["comment"] = f"Deleted team {name}" + ret["changes"].setdefault("old", f"Team {name} exists") + ret["changes"].setdefault("new", f"Team {name} deleted") ret["result"] = True else: - ret["comment"] = "Failed to delete {}".format(name) + ret["comment"] = f"Failed to delete {name}" ret["result"] = False return ret @@ -508,7 +504,7 @@ def repo_present( license_template=None, teams=None, profile="github", - **kwargs + **kwargs, ): """ Ensure a repository is present @@ -605,8 +601,8 @@ def repo_present( if len(parameters) > 0: repo_change = { - "old": "Repo properties were {}".format(old_parameters), - "new": "Repo properties (that changed) are {}".format(parameters), + "old": f"Repo properties were {old_parameters}", + "new": f"Repo properties (that changed) are {parameters}", } if __opts__["test"]: ret["changes"]["repo"] = repo_change @@ -623,7 +619,7 @@ def repo_present( return ret else: # Repo does not exist - it will be created. - repo_change = {"old": None, "new": "Repo {} has been created".format(name)} + repo_change = {"old": None, "new": f"Repo {name} has been created"} if __opts__["test"]: ret["changes"]["repo"] = repo_change ret["result"] = None @@ -634,7 +630,7 @@ def repo_present( if not result: ret["result"] = False - ret["comment"] = "Failed to create repo {}.".format(name) + ret["comment"] = f"Failed to create repo {name}." return ret # Turns out that trying to fetch teams for a new repo can 404 immediately @@ -652,7 +648,7 @@ def repo_present( if current_teams is None: ret["result"] = False - ret["comment"] = "Failed to verify repo {} after creation.".format(name) + ret["comment"] = f"Failed to verify repo {name} after creation." return ret ret["changes"]["repo"] = repo_change @@ -669,8 +665,8 @@ def repo_present( for team_name in current_team_names: if team_name not in teams: team_change = { - "old": "Repo {} is in team {}".format(name, team_name), - "new": "Repo {} is not in team {}".format(name, team_name), + "old": f"Repo {name} is in team {team_name}", + "new": f"Repo {name} is not in team {team_name}", } if __opts__["test"]: @@ -684,10 +680,10 @@ def repo_present( ret["changes"][team_name] = team_change else: ret["result"] = False - ret[ - "comment" - ] = "Failed to remove repo {} from team {}.".format( - name, team_name + ret["comment"] = ( + "Failed to remove repo {} from team {}.".format( + name, team_name + ) ) return ret @@ -695,8 +691,8 @@ def repo_present( for team_name, permission in teams.items(): if team_name not in current_team_names: # Need to add repo to team team_change = { - "old": "Repo {} is not in team {}".format(name, team_name), - "new": "Repo {} is in team {}".format(name, team_name), + "old": f"Repo {name} is not in team {team_name}", + "new": f"Repo {name} is in team {team_name}", } if __opts__["test"]: ret["changes"][team_name] = team_change @@ -709,10 +705,10 @@ def repo_present( ret["changes"][team_name] = team_change else: ret["result"] = False - ret[ - "comment" - ] = "Failed to remove repo {} from team {}.".format( - name, team_name + ret["comment"] = ( + "Failed to remove repo {} from team {}.".format( + name, team_name + ) ) return ret else: @@ -783,21 +779,21 @@ def repo_absent(name, profile="github", **kwargs): target = None if not target: - ret["comment"] = "Repo {} does not exist".format(name) + ret["comment"] = f"Repo {name} does not exist" ret["result"] = True return ret else: if __opts__["test"]: - ret["comment"] = "Repo {} will be deleted".format(name) + ret["comment"] = f"Repo {name} will be deleted" ret["result"] = None return ret result = __salt__["github.remove_repo"](name, profile=profile, **kwargs) if result: - ret["comment"] = "Deleted repo {}".format(name) - ret["changes"].setdefault("old", "Repo {} exists".format(name)) - ret["changes"].setdefault("new", "Repo {} deleted".format(name)) + ret["comment"] = f"Deleted repo {name}" + ret["changes"].setdefault("old", f"Repo {name} exists") + ret["changes"].setdefault("new", f"Repo {name} deleted") ret["result"] = True else: ret["comment"] = ( diff --git a/salt/states/glance_image.py b/salt/states/glance_image.py index fe8f7857ce7..b65ec5f353c 100644 --- a/salt/states/glance_image.py +++ b/salt/states/glance_image.py @@ -22,7 +22,6 @@ Example States - name: cirros """ - __virtualname__ = "glance_image" @@ -61,7 +60,7 @@ def present(name, auth=None, **kwargs): if __opts__["test"]: ret["result"] = None ret["changes"] = kwargs - ret["comment"] = "Image {} will be created.".format(name) + ret["comment"] = f"Image {name} will be created." return ret kwargs["name"] = name @@ -91,7 +90,7 @@ def absent(name, auth=None): if __opts__["test"]: ret["result"] = None ret["changes"] = {"name": name} - ret["comment"] = "Image {} will be deleted.".format(name) + ret["comment"] = f"Image {name} will be deleted." return ret __salt__["glanceng.image_delete"](name=image) diff --git a/salt/states/glassfish.py b/salt/states/glassfish.py index 913b7da2fb5..30778d17729 100644 --- a/salt/states/glassfish.py +++ b/salt/states/glassfish.py @@ -82,7 +82,7 @@ def _do_element_present(name, elem_type, data, server=None): """ ret = {"changes": {}, "update": False, "create": False, "error": None} try: - elements = __salt__["glassfish.enum_{}".format(elem_type)]() + elements = __salt__[f"glassfish.enum_{elem_type}"]() except requests.ConnectionError as error: if __opts__["test"]: ret["changes"] = {"Name": name, "Params": data} @@ -97,23 +97,19 @@ def _do_element_present(name, elem_type, data, server=None): ret["create"] = True if not __opts__["test"]: try: - __salt__["glassfish.create_{}".format(elem_type)]( - name, server=server, **data - ) + __salt__[f"glassfish.create_{elem_type}"](name, server=server, **data) except CommandExecutionError as error: ret["error"] = error return ret elif elements and any(data): - current_data = __salt__["glassfish.get_{}".format(elem_type)]( - name, server=server - ) + current_data = __salt__[f"glassfish.get_{elem_type}"](name, server=server) data_diff = _is_updated(current_data, data) if data_diff: ret["update"] = True ret["changes"] = data_diff if not __opts__["test"]: try: - __salt__["glassfish.update_{}".format(elem_type)]( + __salt__[f"glassfish.update_{elem_type}"]( name, server=server, **data ) except CommandExecutionError as error: @@ -127,7 +123,7 @@ def _do_element_absent(name, elem_type, data, server=None): """ ret = {"delete": False, "error": None} try: - elements = __salt__["glassfish.enum_{}".format(elem_type)]() + elements = __salt__[f"glassfish.enum_{elem_type}"]() except requests.ConnectionError as error: if __opts__["test"]: ret["create"] = True @@ -140,9 +136,7 @@ def _do_element_absent(name, elem_type, data, server=None): ret["delete"] = True if not __opts__["test"]: try: - __salt__["glassfish.delete_{}".format(elem_type)]( - name, server=server, **data - ) + __salt__[f"glassfish.delete_{elem_type}"](name, server=server, **data) except CommandExecutionError as error: ret["error"] = error return ret @@ -208,7 +202,7 @@ def connection_factory_present( # Manage parameters pool_data = {} res_data = {} - pool_name = "{}-Connection-Pool".format(name) + pool_name = f"{name}-Connection-Pool" if restype == "topic_connection_factory": pool_data["connectionDefinitionName"] = "javax.jms.TopicConnectionFactory" elif restype == "queue_connection_factory": @@ -285,7 +279,7 @@ def connection_factory_absent(name, both=True, server=None): Delete both the pool and the resource, defaults to ``true`` """ ret = {"name": name, "result": None, "comment": None, "changes": {}} - pool_name = "{}-Connection-Pool".format(name) + pool_name = f"{name}-Connection-Pool" pool_ret = _do_element_absent( pool_name, "connector_c_pool", {"cascade": both}, server ) @@ -466,7 +460,7 @@ def jdbc_datasource_present( ret = {"name": name, "result": None, "comment": None, "changes": {}} # Manage parameters - res_name = "jdbc/{}".format(name) + res_name = f"jdbc/{name}" pool_data = {} pool_data_properties = {} res_data = {} diff --git a/salt/states/glusterfs.py b/salt/states/glusterfs.py index bfe4fb63380..331053d2550 100644 --- a/salt/states/glusterfs.py +++ b/salt/states/glusterfs.py @@ -2,7 +2,6 @@ Manage GlusterFS pool. """ - import logging import salt.utils.cloud as suc @@ -84,11 +83,11 @@ def peered(name): if peers and any(name in v["hostnames"] for v in peers.values()): ret["result"] = True - ret["comment"] = "Host {} already peered".format(name) + ret["comment"] = f"Host {name} already peered" return ret if __opts__["test"]: - ret["comment"] = "Peer {} will be added.".format(name) + ret["comment"] = f"Peer {name} will be added." ret["result"] = None return ret @@ -102,13 +101,13 @@ def peered(name): newpeers = __salt__["glusterfs.peer_status"]() if newpeers and any(name in v["hostnames"] for v in newpeers.values()): ret["result"] = True - ret["comment"] = "Host {} successfully peered".format(name) + ret["comment"] = f"Host {name} successfully peered" ret["changes"] = {"new": newpeers, "old": peers} else: - ret[ - "comment" - ] = "Host {} was successfully peered but did not appear in the list of peers".format( - name + ret["comment"] = ( + "Host {} was successfully peered but did not appear in the list of peers".format( + name + ) ) return ret @@ -182,7 +181,7 @@ def volume_present( volumes = __salt__["glusterfs.list_volumes"]() if name not in volumes: if __opts__["test"]: - comment = "Volume {} will be created".format(name) + comment = f"Volume {name} will be created" if start: comment += " and started" ret["comment"] = comment @@ -194,16 +193,16 @@ def volume_present( ) if not vol_created: - ret["comment"] = "Creation of volume {} failed".format(name) + ret["comment"] = f"Creation of volume {name} failed" return ret old_volumes = volumes volumes = __salt__["glusterfs.list_volumes"]() if name in volumes: ret["changes"] = {"new": volumes, "old": old_volumes} - ret["comment"] = "Volume {} is created".format(name) + ret["comment"] = f"Volume {name} is created" else: - ret["comment"] = "Volume {} already exists".format(name) + ret["comment"] = f"Volume {name} already exists" if start: if __opts__["test"]: @@ -252,26 +251,26 @@ def started(name): volinfo = __salt__["glusterfs.info"]() if name not in volinfo: ret["result"] = False - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" return ret if int(volinfo[name]["status"]) == 1: - ret["comment"] = "Volume {} is already started".format(name) + ret["comment"] = f"Volume {name} is already started" ret["result"] = True return ret elif __opts__["test"]: - ret["comment"] = "Volume {} will be started".format(name) + ret["comment"] = f"Volume {name} will be started" ret["result"] = None return ret vol_started = __salt__["glusterfs.start_volume"](name) if vol_started: ret["result"] = True - ret["comment"] = "Volume {} is started".format(name) + ret["comment"] = f"Volume {name} is started" ret["change"] = {"new": "started", "old": "stopped"} else: ret["result"] = False - ret["comment"] = "Failed to start volume {}".format(name) + ret["comment"] = f"Failed to start volume {name}" return ret @@ -305,23 +304,23 @@ def add_volume_bricks(name, bricks): volinfo = __salt__["glusterfs.info"]() if name not in volinfo: - ret["comment"] = "Volume {} does not exist".format(name) + ret["comment"] = f"Volume {name} does not exist" return ret if int(volinfo[name]["status"]) != 1: - ret["comment"] = "Volume {} is not started".format(name) + ret["comment"] = f"Volume {name} is not started" return ret current_bricks = [brick["path"] for brick in volinfo[name]["bricks"].values()] if not set(bricks) - set(current_bricks): ret["result"] = True - ret["comment"] = "Bricks already added in volume {}".format(name) + ret["comment"] = f"Bricks already added in volume {name}" return ret bricks_added = __salt__["glusterfs.add_volume_bricks"](name, bricks) if bricks_added: ret["result"] = True - ret["comment"] = "Bricks successfully added to volume {}".format(name) + ret["comment"] = f"Bricks successfully added to volume {name}" new_bricks = [ brick["path"] for brick in __salt__["glusterfs.info"]()[name]["bricks"].values() @@ -329,7 +328,7 @@ def add_volume_bricks(name, bricks): ret["changes"] = {"new": new_bricks, "old": current_bricks} return ret - ret["comment"] = "Adding bricks to volume {} failed".format(name) + ret["comment"] = f"Adding bricks to volume {name} failed" return ret @@ -368,10 +367,10 @@ def op_version(name, version): ret["result"] = True return ret elif __opts__["test"]: - ret[ - "comment" - ] = "An attempt would be made to set the cluster.op-version for {} to {}.".format( - name, version + ret["comment"] = ( + "An attempt would be made to set the cluster.op-version for {} to {}.".format( + name, version + ) ) ret["result"] = None return ret @@ -421,18 +420,18 @@ def max_op_version(name): return ret if current == max_version: - ret[ - "comment" - ] = "The cluster.op-version is already set to the cluster.max-op-version of {}".format( - current + ret["comment"] = ( + "The cluster.op-version is already set to the cluster.max-op-version of {}".format( + current + ) ) ret["result"] = True return ret elif __opts__["test"]: - ret[ - "comment" - ] = "An attempt would be made to set the cluster.op-version to {}.".format( - max_version + ret["comment"] = ( + "An attempt would be made to set the cluster.op-version to {}.".format( + max_version + ) ) ret["result"] = None return ret diff --git a/salt/states/gnomedesktop.py b/salt/states/gnomedesktop.py index 24c9df87796..6fb3c222a1b 100644 --- a/salt/states/gnomedesktop.py +++ b/salt/states/gnomedesktop.py @@ -68,12 +68,12 @@ def _do(name, gnome_kwargs, preferences): gnome_kwargs.update({"key": key, "value": value}) if _check_current_value(gnome_kwargs, value): - messages.append("{} is already set to {}".format(key, value)) + messages.append(f"{key} is already set to {value}") else: result = __salt__["gnome.set"](**gnome_kwargs) if result["retcode"] == 0: - messages.append("Setting {} to {}".format(key, value)) - ret["changes"][key] = "{}:{}".format(key, value) + messages.append(f"Setting {key} to {value}") + ret["changes"][key] = f"{key}:{value}" ret["result"] = True else: messages.append(result["stdout"]) @@ -108,7 +108,7 @@ def wm_preferences( visual_bell=None, visual_bell_type=None, workspace_names=None, - **kwargs + **kwargs, ): """ wm_preferences: sets values in the org.gnome.desktop.wm.preferences schema @@ -160,7 +160,7 @@ def desktop_lockdown( disable_save_to_disk=None, disable_user_switching=None, user_administration_disabled=None, - **kwargs + **kwargs, ): """ desktop_lockdown: sets values in the org.gnome.desktop.lockdown schema @@ -227,7 +227,7 @@ def desktop_interface( toolbar_icons_size=None, toolbar_style=None, toolkit_accessibility=None, - **kwargs + **kwargs, ): """ desktop_interface: sets values in the org.gnome.desktop.interface schema diff --git a/salt/states/grafana.py b/salt/states/grafana.py index e061b916fb2..b25a1d93d3c 100644 --- a/salt/states/grafana.py +++ b/salt/states/grafana.py @@ -189,7 +189,7 @@ def _parse_profile(profile): if isinstance(profile, str): _profile = __salt__["config.option"](profile) if not _profile: - msg = "Pillar key for profile {} not found.".format(profile) + msg = f"Pillar key for profile {profile} not found." raise SaltInvocationError(msg) else: _profile = profile @@ -292,7 +292,7 @@ def dashboard_present( " dashboard template was provided." ) if __opts__["test"]: - ret["comment"] = "Dashboard {} is set to be created.".format(name) + ret["comment"] = f"Dashboard {name} is set to be created." ret["result"] = None return ret _dashboard = dashboard @@ -330,12 +330,12 @@ def dashboard_present( update_rows.append(title) if not update_rows: ret["result"] = True - ret["comment"] = "Dashboard {} is up to date".format(name) + ret["comment"] = f"Dashboard {name} is up to date" return ret if __opts__["test"]: - msg = "Dashboard {} is set to be updated.".format(name) + msg = f"Dashboard {name} is set to be updated." if update_rows: - msg = "{} The following rows set to be updated: {}".format(msg, update_rows) + msg = f"{msg} The following rows set to be updated: {update_rows}" ret["comment"] = msg return ret body = { @@ -350,13 +350,13 @@ def dashboard_present( if updated: ret["result"] = True ret["changes"]["changed"] = name - msg = "Updated dashboard {}.".format(name) + msg = f"Updated dashboard {name}." if update_rows: - msg = "{} The following rows were updated: {}".format(msg, update_rows) + msg = f"{msg} The following rows were updated: {update_rows}" ret["comment"] = msg else: ret["result"] = False - msg = "Failed to update dashboard {}.".format(name) + msg = f"Failed to update dashboard {name}." ret["comment"] = msg return ret @@ -385,7 +385,7 @@ def dashboard_absent(name, hosts=None, profile="grafana"): if exists: if __opts__["test"]: - ret["comment"] = "Dashboard {} is set to be removed.".format(name) + ret["comment"] = f"Dashboard {name} is set to be removed." return ret deleted = __salt__["elasticsearch.delete"]( index=index, doc_type="dashboard", id=name, hosts=hosts @@ -396,9 +396,9 @@ def dashboard_absent(name, hosts=None, profile="grafana"): ret["changes"]["new"] = None else: ret["result"] = False - ret["comment"] = "Failed to delete {} dashboard.".format(name) + ret["comment"] = f"Failed to delete {name} dashboard." else: ret["result"] = True - ret["comment"] = "Dashboard {} does not exist.".format(name) + ret["comment"] = f"Dashboard {name} does not exist." return ret diff --git a/salt/states/grafana4_dashboard.py b/salt/states/grafana4_dashboard.py index 8f85ebad9cc..43d88734852 100644 --- a/salt/states/grafana4_dashboard.py +++ b/salt/states/grafana4_dashboard.py @@ -52,7 +52,6 @@ allowing users to manage their own custom rows. type: graph """ - import copy import salt.utils.json @@ -139,15 +138,15 @@ def present( if not old_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be created.".format(name) + ret["comment"] = f"Dashboard {name} is set to be created." return ret response = __salt__["grafana4.create_update_dashboard"]( dashboard=new_dashboard, overwrite=True, profile=profile ) if response.get("status") == "success": - ret["comment"] = "Dashboard {} created.".format(name) - ret["changes"]["new"] = "Dashboard {} created.".format(name) + ret["comment"] = f"Dashboard {name} created." + ret["changes"]["new"] = f"Dashboard {name} created." else: ret["result"] = False ret["comment"] = "Failed to create dashboard {}, response={}".format( @@ -192,7 +191,7 @@ def present( dashboard_diff = DictDiffer( _cleaned(updated_dashboard), _cleaned(old_dashboard) ) - ret["comment"] = "Dashboard {} updated.".format(name) + ret["comment"] = f"Dashboard {name} updated." ret["changes"] = _dashboard_diff( _cleaned(new_dashboard), _cleaned(old_dashboard) ) @@ -230,12 +229,12 @@ def absent(name, orgname=None, profile="grafana"): if existing_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be deleted.".format(name) + ret["comment"] = f"Dashboard {name} is set to be deleted." return ret __salt__["grafana4.delete_dashboard"](name, profile=profile) - ret["comment"] = "Dashboard {} deleted.".format(name) - ret["changes"]["new"] = "Dashboard {} deleted.".format(name) + ret["comment"] = f"Dashboard {name} deleted." + ret["changes"]["new"] = f"Dashboard {name} deleted." return ret ret["comment"] = "Dashboard absent" diff --git a/salt/states/grafana4_datasource.py b/salt/states/grafana4_datasource.py index b0ebe8d02d3..b3b2503071c 100644 --- a/salt/states/grafana4_datasource.py +++ b/salt/states/grafana4_datasource.py @@ -152,12 +152,12 @@ def present( if not datasource: if __opts__["test"]: - ret["comment"] = "Datasource {} will be created".format(name) + ret["comment"] = f"Datasource {name} will be created" return ret __salt__["grafana4.create_datasource"](profile=profile, **data) datasource = __salt__["grafana4.get_datasource"](name, profile=profile) ret["result"] = True - ret["comment"] = "New data source {} added".format(name) + ret["comment"] = f"New data source {name} added" ret["changes"] = data return ret @@ -168,16 +168,16 @@ def present( datasource[key] = None if data == datasource: - ret["comment"] = "Data source {} already up-to-date".format(name) + ret["comment"] = f"Data source {name} already up-to-date" return ret if __opts__["test"]: - ret["comment"] = "Datasource {} will be updated".format(name) + ret["comment"] = f"Datasource {name} will be updated" return ret __salt__["grafana4.update_datasource"](datasource["id"], profile=profile, **data) ret["result"] = True ret["changes"] = deep_diff(datasource, data, ignore=["id", "orgId", "readOnly"]) - ret["comment"] = "Data source {} updated".format(name) + ret["comment"] = f"Data source {name} updated" return ret @@ -203,17 +203,17 @@ def absent(name, orgname=None, profile="grafana"): if not datasource: ret["result"] = True - ret["comment"] = "Data source {} already absent".format(name) + ret["comment"] = f"Data source {name} already absent" return ret if __opts__["test"]: - ret["comment"] = "Datasource {} will be deleted".format(name) + ret["comment"] = f"Datasource {name} will be deleted" return ret __salt__["grafana4.delete_datasource"](datasource["id"], profile=profile) ret["result"] = True ret["changes"][name] = "Absent" - ret["comment"] = "Data source {} was deleted".format(name) + ret["comment"] = f"Data source {name} was deleted" return ret diff --git a/salt/states/grafana4_org.py b/salt/states/grafana4_org.py index 8d4aa5e1da9..c0167637e8e 100644 --- a/salt/states/grafana4_org.py +++ b/salt/states/grafana4_org.py @@ -130,12 +130,12 @@ def present( if create: if __opts__["test"]: - ret["comment"] = "Org {} will be created".format(name) + ret["comment"] = f"Org {name} will be created" return ret __salt__["grafana4.create_org"](profile=profile, name=name) org = __salt__["grafana4.get_org"](name, profile) ret["changes"] = org - ret["comment"] = "New org {} added".format(name) + ret["comment"] = f"New org {name} added" data = _get_json_data( address1=address1, @@ -148,7 +148,7 @@ def present( ) if data != org["address"]: if __opts__["test"]: - ret["comment"] = "Org {} address will be updated".format(name) + ret["comment"] = f"Org {name} address will be updated" return ret __salt__["grafana4.update_org_address"](name, profile=profile, **data) if create: @@ -165,7 +165,7 @@ def present( ) if data != prefs: if __opts__["test"]: - ret["comment"] = "Org {} prefs will be updated".format(name) + ret["comment"] = f"Org {name} prefs will be updated" return ret __salt__["grafana4.update_org_prefs"](name, profile=profile, **data) if create: @@ -227,10 +227,10 @@ def present( ret["result"] = True if not create: if ret["changes"]: - ret["comment"] = "Org {} updated".format(name) + ret["comment"] = f"Org {name} updated" else: ret["changes"] = {} - ret["comment"] = "Org {} already up-to-date".format(name) + ret["comment"] = f"Org {name} already up-to-date" return ret @@ -254,17 +254,17 @@ def absent(name, profile="grafana"): if not org: ret["result"] = True - ret["comment"] = "Org {} already absent".format(name) + ret["comment"] = f"Org {name} already absent" return ret if __opts__["test"]: - ret["comment"] = "Org {} will be deleted".format(name) + ret["comment"] = f"Org {name} will be deleted" return ret __salt__["grafana4.delete_org"](org["id"], profile=profile) ret["result"] = True ret["changes"][name] = "Absent" - ret["comment"] = "Org {} was deleted".format(name) + ret["comment"] = f"Org {name} was deleted" return ret diff --git a/salt/states/grafana4_user.py b/salt/states/grafana4_user.py index 813c4e5aae4..30c4c1e83f3 100644 --- a/salt/states/grafana4_user.py +++ b/salt/states/grafana4_user.py @@ -85,7 +85,7 @@ def present( if create: if __opts__["test"]: - ret["comment"] = "User {} will be created".format(name) + ret["comment"] = f"User {name} will be created" return ret __salt__["grafana4.create_user"]( login=name, password=password, email=email, name=fullname, profile=profile @@ -101,7 +101,7 @@ def present( login=None, email=None, name=None, theme=None, defaults=user_data ): if __opts__["test"]: - ret["comment"] = "User {} will be updated".format(name) + ret["comment"] = f"User {name} will be updated" return ret __salt__["grafana4.update_user"](user["id"], profile=profile, **data) dictupdate.update( @@ -111,7 +111,7 @@ def present( if user["isAdmin"] != is_admin: if __opts__["test"]: - ret["comment"] = "User {} isAdmin status will be updated".format(name) + ret["comment"] = f"User {name} isAdmin status will be updated" return ret __salt__["grafana4.update_user_permissions"]( user["id"], isGrafanaAdmin=is_admin, profile=profile @@ -124,13 +124,13 @@ def present( ret["result"] = True if create: ret["changes"] = ret["changes"]["new"] - ret["comment"] = "New user {} added".format(name) + ret["comment"] = f"New user {name} added" else: if ret["changes"]: - ret["comment"] = "User {} updated".format(name) + ret["comment"] = f"User {name} updated" else: ret["changes"] = {} - ret["comment"] = "User {} already up-to-date".format(name) + ret["comment"] = f"User {name} already up-to-date" return ret @@ -154,7 +154,7 @@ def absent(name, profile="grafana"): if user: if __opts__["test"]: - ret["comment"] = "User {} will be deleted".format(name) + ret["comment"] = f"User {name} will be deleted" return ret orgs = __salt__["grafana4.get_user_orgs"](user["id"], profile=profile) __salt__["grafana4.delete_user"](user["id"], profile=profile) @@ -171,12 +171,12 @@ def absent(name, profile="grafana"): ) else: ret["result"] = True - ret["comment"] = "User {} already absent".format(name) + ret["comment"] = f"User {name} already absent" return ret ret["result"] = True ret["changes"][name] = "Absent" - ret["comment"] = "User {} was deleted".format(name) + ret["comment"] = f"User {name} was deleted" return ret diff --git a/salt/states/grafana_dashboard.py b/salt/states/grafana_dashboard.py index a23d0f084e3..0e4538f8852 100644 --- a/salt/states/grafana_dashboard.py +++ b/salt/states/grafana_dashboard.py @@ -37,7 +37,6 @@ they exist in dashboards. The module will not manage rows that are not defined, allowing users to manage their own custom rows. """ - import copy import requests @@ -122,18 +121,18 @@ def present( _ensure_annotations(new_dashboard) # Create dashboard if it does not exist - url = "db/{}".format(name) + url = f"db/{name}" old_dashboard = _get(url, profile) if not old_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be created.".format(name) + ret["comment"] = f"Dashboard {name} is set to be created." return ret response = _update(new_dashboard, profile) if response.get("status") == "success": - ret["comment"] = "Dashboard {} created.".format(name) - ret["changes"]["new"] = "Dashboard {} created.".format(name) + ret["comment"] = f"Dashboard {name} created." + ret["changes"]["new"] = f"Dashboard {name} created." else: ret["result"] = False ret["comment"] = "Failed to create dashboard {}, response={}".format( @@ -174,7 +173,7 @@ def present( dashboard_diff = DictDiffer( _cleaned(updated_dashboard), _cleaned(old_dashboard) ) - ret["comment"] = "Dashboard {} updated.".format(name) + ret["comment"] = f"Dashboard {name} updated." ret["changes"] = _dashboard_diff( _cleaned(new_dashboard), _cleaned(old_dashboard) ) @@ -204,17 +203,17 @@ def absent(name, profile="grafana"): if isinstance(profile, str): profile = __salt__["config.option"](profile) - url = "db/{}".format(name) + url = f"db/{name}" existing_dashboard = _get(url, profile) if existing_dashboard: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Dashboard {} is set to be deleted.".format(name) + ret["comment"] = f"Dashboard {name} is set to be deleted." return ret _delete(url, profile) - ret["comment"] = "Dashboard {} deleted.".format(name) - ret["changes"]["new"] = "Dashboard {} deleted.".format(name) + ret["comment"] = f"Dashboard {name} deleted." + ret["changes"]["new"] = f"Dashboard {name} deleted." return ret ret["comment"] = "Dashboard absent" diff --git a/salt/states/grafana_datasource.py b/salt/states/grafana_datasource.py index e513802c890..9daf0efa79f 100644 --- a/salt/states/grafana_datasource.py +++ b/salt/states/grafana_datasource.py @@ -110,10 +110,10 @@ def present( ret["result"] = True ret["changes"] = _diff(datasource, data) if ret["changes"]["new"] or ret["changes"]["old"]: - ret["comment"] = "Data source {} updated".format(name) + ret["comment"] = f"Data source {name} updated" else: ret["changes"] = {} - ret["comment"] = "Data source {} already up-to-date".format(name) + ret["comment"] = f"Data source {name} already up-to-date" else: requests.post( "{}/api/datasources".format(profile["grafana_url"]), @@ -122,7 +122,7 @@ def present( timeout=profile.get("grafana_timeout", 3), ) ret["result"] = True - ret["comment"] = "New data source {} added".format(name) + ret["comment"] = f"New data source {name} added" ret["changes"] = data return ret @@ -143,7 +143,7 @@ def absent(name, profile="grafana"): if not datasource: ret["result"] = True - ret["comment"] = "Data source {} already absent".format(name) + ret["comment"] = f"Data source {name} already absent" return ret requests.delete( @@ -153,7 +153,7 @@ def absent(name, profile="grafana"): ) ret["result"] = True - ret["comment"] = "Data source {} was deleted".format(name) + ret["comment"] = f"Data source {name} was deleted" return ret diff --git a/salt/states/grains.py b/salt/states/grains.py index 9e6399dd57f..d69a8779467 100644 --- a/salt/states/grains.py +++ b/salt/states/grains.py @@ -125,15 +125,15 @@ def present(name, value, delimiter=DEFAULT_TARGET_DELIM, force=False): if __opts__["test"]: ret["result"] = None if existing is _non_existent: - ret["comment"] = "Grain {} is set to be added".format(name) + ret["comment"] = f"Grain {name} is set to be added" ret["changes"] = {"new": name} else: - ret["comment"] = "Grain {} is set to be changed".format(name) + ret["comment"] = f"Grain {name} is set to be changed" ret["changes"] = {"changed": {name: value}} return ret ret = __salt__["grains.set"](name, value, force=force) if ret["result"] is True and ret["changes"] != {}: - ret["comment"] = "Set grain {} to {}".format(name, value) + ret["comment"] = f"Set grain {name} to {value}" ret["name"] = name return ret @@ -182,13 +182,13 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): # check whether grain is a list if not isinstance(grain, list): ret["result"] = False - ret["comment"] = "Grain {} is not a valid list".format(name) + ret["comment"] = f"Grain {name} is not a valid list" return ret if isinstance(value, list): if make_hashable(value).issubset( make_hashable(__salt__["grains.get"](name)) ): - ret["comment"] = "Value {1} is already in grain {0}".format(name, value) + ret["comment"] = f"Value {value} is already in grain {name}" return ret elif name in __context__.get("pending_grains", {}): # elements common to both @@ -199,10 +199,10 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): value = list( set(value).difference(__context__["pending_grains"][name]) ) - ret[ - "comment" - ] = 'Removed value {} from update due to context found in "{}".\n'.format( - value, name + ret["comment"] = ( + 'Removed value {} from update due to context found in "{}".\n'.format( + value, name + ) ) if "pending_grains" not in __context__: __context__["pending_grains"] = {} @@ -211,7 +211,7 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): __context__["pending_grains"][name].update(value) else: if value in grain: - ret["comment"] = "Value {1} is already in grain {0}".format(name, value) + ret["comment"] = f"Value {value} is already in grain {name}" return ret if __opts__["test"]: ret["result"] = None @@ -223,21 +223,21 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Grain {} is set to be added".format(name) + ret["comment"] = f"Grain {name} is set to be added" ret["changes"] = {"new": grain} return ret new_grains = __salt__["grains.append"](name, value) if isinstance(value, list): if not set(value).issubset(set(__salt__["grains.get"](name))): ret["result"] = False - ret["comment"] = "Failed append value {1} to grain {0}".format(name, value) + ret["comment"] = f"Failed append value {value} to grain {name}" return ret else: if value not in __salt__["grains.get"](name, delimiter=DEFAULT_TARGET_DELIM): ret["result"] = False - ret["comment"] = "Failed append value {1} to grain {0}".format(name, value) + ret["comment"] = f"Failed append value {value} to grain {name}" return ret - ret["comment"] = "Append value {1} to grain {0}".format(name, value) + ret["comment"] = f"Append value {value} to grain {name}" ret["changes"] = {"new": new_grains} return ret @@ -288,22 +288,16 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): value = [value] for val in value: if val not in grain: - comments.append( - "Value {1} is absent from grain {0}".format(name, val) - ) + comments.append(f"Value {val} is absent from grain {name}") elif __opts__["test"]: ret["result"] = None - comments.append( - "Value {1} in grain {0} is set to be deleted".format(name, val) - ) + comments.append(f"Value {val} in grain {name} is set to be deleted") if "deleted" not in ret["changes"].keys(): ret["changes"] = {"deleted": []} ret["changes"]["deleted"].append(val) elif val in grain: __salt__["grains.remove"](name, val) - comments.append( - "Value {1} was deleted from grain {0}".format(name, val) - ) + comments.append(f"Value {val} was deleted from grain {name}") if "deleted" not in ret["changes"].keys(): ret["changes"] = {"deleted": []} ret["changes"]["deleted"].append(val) @@ -311,9 +305,9 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): return ret else: ret["result"] = False - ret["comment"] = "Grain {} is not a valid list".format(name) + ret["comment"] = f"Grain {name} is not a valid list" else: - ret["comment"] = "Grain {} does not exist".format(name) + ret["comment"] = f"Grain {name} does not exist" return ret @@ -362,38 +356,36 @@ def absent(name, destructive=False, delimiter=DEFAULT_TARGET_DELIM, force=False) if __opts__["test"]: ret["result"] = None if destructive is True: - ret["comment"] = "Grain {} is set to be deleted".format(name) + ret["comment"] = f"Grain {name} is set to be deleted" ret["changes"] = {"deleted": name} return ret ret = __salt__["grains.set"](name, None, destructive=destructive, force=force) if ret["result"]: if destructive is True: - ret["comment"] = "Grain {} was deleted".format(name) + ret["comment"] = f"Grain {name} was deleted" ret["changes"] = {"deleted": name} ret["name"] = name elif grain is not _non_existent: if __opts__["test"]: ret["result"] = None if destructive is True: - ret["comment"] = "Grain {} is set to be deleted".format(name) + ret["comment"] = f"Grain {name} is set to be deleted" ret["changes"] = {"deleted": name} else: - ret[ - "comment" - ] = "Value for grain {} is set to be deleted (None)".format(name) + ret["comment"] = f"Value for grain {name} is set to be deleted (None)" ret["changes"] = {"grain": name, "value": None} return ret ret = __salt__["grains.set"](name, None, destructive=destructive, force=force) if ret["result"]: if destructive is True: - ret["comment"] = "Grain {} was deleted".format(name) + ret["comment"] = f"Grain {name} was deleted" ret["changes"] = {"deleted": name} else: - ret["comment"] = "Value for grain {} was set to None".format(name) + ret["comment"] = f"Value for grain {name} was set to None" ret["changes"] = {"grain": name, "value": None} ret["name"] = name else: - ret["comment"] = "Grain {} does not exist".format(name) + ret["comment"] = f"Grain {name} does not exist" return ret @@ -436,9 +428,9 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): if grain or name in __grains__: if isinstance(grain, list): if value in grain: - ret[ - "comment" - ] = "Value {1} is already in the list for grain {0}".format(name, value) + ret["comment"] = ( + f"Value {value} is already in the list for grain {name}" + ) return ret if __opts__["test"]: ret["result"] = None @@ -448,7 +440,7 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): ret["changes"] = {"added": value} return ret __salt__["grains.append"](name, value) - ret["comment"] = "Value {1} was added to grain {0}".format(name, value) + ret["comment"] = f"Value {value} was added to grain {name}" ret["changes"] = {"added": value} else: if convert is True: @@ -464,12 +456,12 @@ def append(name, value, convert=False, delimiter=DEFAULT_TARGET_DELIM): grain = [] if grain is None else [grain] grain.append(value) __salt__["grains.setval"](name, grain) - ret["comment"] = "Value {1} was added to grain {0}".format(name, value) + ret["comment"] = f"Value {value} was added to grain {name}" ret["changes"] = {"added": value} else: ret["result"] = False - ret["comment"] = "Grain {} is not a valid list".format(name) + ret["comment"] = f"Grain {name} is not a valid list" else: ret["result"] = False - ret["comment"] = "Grain {} does not exist".format(name) + ret["comment"] = f"Grain {name} does not exist" return ret diff --git a/salt/states/group.py b/salt/states/group.py index 1fe30589c06..3a2bcf1c3be 100644 --- a/salt/states/group.py +++ b/salt/states/group.py @@ -33,7 +33,6 @@ In Windows, if no domain is specified in the user or group name (i.e. - user2 """ - import sys import salt.utils.platform @@ -204,9 +203,9 @@ def present( # -- if trying to add and delete the same user(s) at the same time. if not set(addusers).isdisjoint(set(delusers)): ret["result"] = None - ret[ - "comment" - ] = "Error. Same user(s) can not be added and deleted simultaneously" + ret["comment"] = ( + "Error. Same user(s) can not be added and deleted simultaneously" + ) return ret changes = _changes(name, gid, addusers, delusers, members, local=local) diff --git a/salt/states/heat.py b/salt/states/heat.py index c4a63133ee4..2e86486c972 100644 --- a/salt/states/heat.py +++ b/salt/states/heat.py @@ -108,7 +108,7 @@ def deployed( timeout=60, update=False, profile=None, - **connection_args + **connection_args, ): """ Deploy stack with the specified properties @@ -168,7 +168,7 @@ def deployed( existing_stack = __salt__["heat.show_stack"](name, profile=profile) if existing_stack["result"] and not update: - ret["comment"] = "Stack {} is deployed".format(name) + ret["comment"] = f"Stack {name} is deployed" return ret if existing_stack["result"] and update: if template: @@ -223,7 +223,7 @@ def deployed( salt.utils.files.safe_rm(template_tmp_file) except ValueError as ex: ret["result"] = False - ret["comment"] = "Error parsing template {}".format(ex) + ret["comment"] = f"Error parsing template {ex}" else: ret["result"] = False ret["comment"] = "Can not open template: {} {}".format( @@ -245,13 +245,13 @@ def deployed( checksum_stack = __salt__["hashutil.digest"](template_stack["template"]) except salt.exceptions.CommandExecutionError as cmdexc: ret["result"] = False - ret["comment"] = "{}".format(cmdexc) + ret["comment"] = f"{cmdexc}" if ret["result"] is True: if checksum_template == checksum_stack: if __opts__["test"]: ret["result"] = True - ret["comment"] = "Stack {} is deployed".format(name) + ret["comment"] = f"Stack {name} is deployed" return ret else: ret["result"] = False @@ -263,7 +263,7 @@ def deployed( if __opts__["test"]: stack = { "result": None, - "comment": "Stack {} is set to be updated".format(name), + "comment": f"Stack {name} is set to be updated", } else: stack = __salt__["heat.update_stack"]( @@ -282,7 +282,7 @@ def deployed( if __opts__["test"]: stack = { "result": None, - "comment": "Stack {} is set to be created".format(name), + "comment": f"Stack {name} is set to be created", } else: stack = __salt__["heat.create_stack"]( @@ -337,7 +337,7 @@ def absent(name, poll=5, timeout=60, profile=None): return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Stack {} is set to be removed".format(name) + ret["comment"] = f"Stack {name} is set to be removed" return ret stack = __salt__["heat.delete_stack"]( diff --git a/salt/states/helm.py b/salt/states/helm.py index f80a766a956..95d1e393655 100644 --- a/salt/states/helm.py +++ b/salt/states/helm.py @@ -99,7 +99,7 @@ def repo_managed( except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Failed to add some repositories: {}.".format(err) + ret["comment"] = f"Failed to add some repositories: {err}." return ret @@ -154,7 +154,7 @@ def repo_updated(name, namespace=None, flags=None, kvflags=None): except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Failed to update some repositories: {}.".format(err) + ret["comment"] = f"Failed to update some repositories: {err}." return ret @@ -226,7 +226,7 @@ def release_present( "name": name, "changes": {}, "result": True, - "comment": "Helm release {} is present".format(name), + "comment": f"Helm release {name} is present", } if "helm.status" not in __salt__: @@ -332,7 +332,7 @@ def release_absent(name, namespace=None, flags=None, kvflags=None): "name": name, "changes": {}, "result": True, - "comment": "Helm release {} is absent.".format(name), + "comment": f"Helm release {name} is absent.", } if "helm.uninstall" not in __salt__: diff --git a/salt/states/hg.py b/salt/states/hg.py index c75e58435fb..f4045514e38 100644 --- a/salt/states/hg.py +++ b/salt/states/hg.py @@ -13,7 +13,6 @@ in ~/.ssh/known_hosts, and the remote host has this host's public key. - target: /tmp/example_repo """ - import logging import os import shutil @@ -33,7 +32,7 @@ def __virtual__(): """ if __salt__["cmd.has_exec"](HG_BINARY): return True - return (False, "Command {} not found".format(HG_BINARY)) + return (False, f"Command {HG_BINARY} not found") def latest( @@ -89,7 +88,7 @@ def latest( if not target: return _fail(ret, '"target option is required') - is_repository = os.path.isdir(target) and os.path.isdir("{}/.hg".format(target)) + is_repository = os.path.isdir(target) and os.path.isdir(f"{target}/.hg") if is_repository: ret = _update_repo( @@ -104,7 +103,7 @@ def latest( log.debug('target %s is not found, "hg clone" is required', target) if __opts__["test"]: return _neutral_test( - ret, "Repository {} is about to be cloned to {}".format(name, target) + ret, f"Repository {name} is about to be cloned to {target}" ) _clone_repo(ret, target, name, user, identity, rev, opts) return ret @@ -118,7 +117,7 @@ def _update_repo(ret, name, target, clean, user, identity, rev, opts, update_hea current_rev = __salt__["hg.revision"](target, user=user, rev=".") if not current_rev: - return _fail(ret, "Seems that {} is not a valid hg repo".format(target)) + return _fail(ret, f"Seems that {target} is not a valid hg repo") if __opts__["test"]: return _neutral_test( @@ -145,9 +144,9 @@ def _update_repo(ret, name, target, clean, user, identity, rev, opts, update_hea " updating." ) else: - ret[ - "comment" - ] = "No changes found and update_head=False so will skip updating." + ret["comment"] = ( + "No changes found and update_head=False so will skip updating." + ) return ret if rev: @@ -168,12 +167,12 @@ def _update_repo(ret, name, target, clean, user, identity, rev, opts, update_hea new_rev = __salt__["hg.revision"](cwd=target, user=user, rev=".") if current_rev != new_rev: - revision_text = "{} => {}".format(current_rev, new_rev) + revision_text = f"{current_rev} => {new_rev}" log.info("Repository %s updated: %s", target, revision_text) - ret["comment"] = "Repository {} updated.".format(target) + ret["comment"] = f"Repository {target} updated." ret["changes"]["revision"] = revision_text elif "error:" in pull_out: - return _fail(ret, "An error was thrown by hg:\n{}".format(pull_out)) + return _fail(ret, f"An error was thrown by hg:\n{pull_out}") return ret @@ -217,7 +216,7 @@ def _clone_repo(ret, target, name, user, identity, rev, opts): return ret new_rev = __salt__["hg.revision"](cwd=target, user=user) - message = "Repository {} cloned to {}".format(name, target) + message = f"Repository {name} cloned to {target}" log.info(message) ret["comment"] = message diff --git a/salt/states/highstate_doc.py b/salt/states/highstate_doc.py index ea7c27e0125..8af62692521 100644 --- a/salt/states/highstate_doc.py +++ b/salt/states/highstate_doc.py @@ -2,7 +2,6 @@ To be used with processors in module `highstate_doc`. """ - __virtualname__ = "highstate_doc" @@ -36,7 +35,7 @@ def note(name, source=None, contents=None, **kwargs): """ comment = "" if source: - comment += "include file: {}\n".format(source) + comment += f"include file: {source}\n" if contents and len(contents) < 200: comment += contents return {"name": name, "result": True, "comment": comment, "changes": {}} diff --git a/salt/states/host.py b/salt/states/host.py index c70f04d9ed7..078e4b9f0dc 100644 --- a/salt/states/host.py +++ b/salt/states/host.py @@ -70,7 +70,6 @@ You can also include comments: """ - import logging import salt.utils.validate.net @@ -145,7 +144,7 @@ def present(name, ip, comment="", clean=False): # pylint: disable=C0103 update_comment.add((addr, comment)) else: # No changes needed for this IP address and hostname - comments.append("Host {} ({}) already present".format(name, addr)) + comments.append(f"Host {name} ({addr}) already present") else: # IP address listed in hosts file, but hostname is not present. # We will need to add it. @@ -155,32 +154,30 @@ def present(name, ip, comment="", clean=False): # pylint: disable=C0103 update_comment.add((addr, comment)) else: ret["result"] = False - comments.append("Invalid IP Address for {} ({})".format(name, addr)) + comments.append(f"Invalid IP Address for {name} ({addr})") for addr, name in to_add: if __opts__["test"]: ret["result"] = None - comments.append("Host {} ({}) would be added".format(name, addr)) + comments.append(f"Host {name} ({addr}) would be added") else: if __salt__["hosts.add_host"](addr, name): - comments.append("Added host {} ({})".format(name, addr)) + comments.append(f"Added host {name} ({addr})") else: ret["result"] = False - comments.append("Failed to add host {} ({})".format(name, addr)) + comments.append(f"Failed to add host {name} ({addr})") continue ret["changes"].setdefault("added", {}).setdefault(addr, []).append(name) for addr, comment in update_comment: if __opts__["test"]: - comments.append("Comment for {} ({}) would be added".format(addr, comment)) + comments.append(f"Comment for {addr} ({comment}) would be added") else: if __salt__["hosts.set_comment"](addr, comment): - comments.append("Set comment for host {} ({})".format(addr, comment)) + comments.append(f"Set comment for host {addr} ({comment})") else: ret["result"] = False - comments.append( - "Failed to add comment for host {} ({})".format(addr, comment) - ) + comments.append(f"Failed to add comment for host {addr} ({comment})") continue ret["changes"].setdefault("comment_added", {}).setdefault(addr, []).append( comment @@ -189,13 +186,13 @@ def present(name, ip, comment="", clean=False): # pylint: disable=C0103 for addr, name in to_remove: if __opts__["test"]: ret["result"] = None - comments.append("Host {} ({}) would be removed".format(name, addr)) + comments.append(f"Host {name} ({addr}) would be removed") else: if __salt__["hosts.rm_host"](addr, name): - comments.append("Removed host {} ({})".format(name, addr)) + comments.append(f"Removed host {name} ({addr})") else: ret["result"] = False - comments.append("Failed to remove host {} ({})".format(name, addr)) + comments.append(f"Failed to remove host {name} ({addr})") continue ret["changes"].setdefault("removed", {}).setdefault(addr, []).append(name) @@ -222,15 +219,15 @@ def absent(name, ip): # pylint: disable=C0103 for _ip in ip: if not __salt__["hosts.has_pair"](_ip, name): ret["result"] = True - comments.append("Host {} ({}) already absent".format(name, _ip)) + comments.append(f"Host {name} ({_ip}) already absent") else: if __opts__["test"]: - comments.append("Host {} ({}) needs to be removed".format(name, _ip)) + comments.append(f"Host {name} ({_ip}) needs to be removed") else: if __salt__["hosts.rm_host"](_ip, name): ret["changes"] = {"host": name} ret["result"] = True - comments.append("Removed host {} ({})".format(name, _ip)) + comments.append(f"Removed host {name} ({_ip})") else: ret["result"] = False comments.append("Failed to remove host") @@ -264,12 +261,12 @@ def only(name, hostnames): new = " ".join(x.strip() for x in hostnames) if old == new: - ret["comment"] = 'IP address {} already set to "{}"'.format(name, new) + ret["comment"] = f'IP address {name} already set to "{new}"' ret["result"] = True return ret if __opts__["test"]: - ret["comment"] = 'Would change {} from "{}" to "{}"'.format(name, old, new) + ret["comment"] = f'Would change {name} from "{old}" to "{new}"' return ret ret["result"] = __salt__["hosts.set_host"](name, new) @@ -279,6 +276,6 @@ def only(name, hostnames): ) return ret - ret["comment"] = 'successfully changed {} from "{}" to "{}"'.format(name, old, new) + ret["comment"] = f'successfully changed {name} from "{old}" to "{new}"' ret["changes"] = {name: {"old": old, "new": new}} return ret diff --git a/salt/states/http.py b/salt/states/http.py index 271f06fece1..3cb5485e0c3 100644 --- a/salt/states/http.py +++ b/salt/states/http.py @@ -6,7 +6,6 @@ Perform an HTTP query and statefully return the result .. versionadded:: 2015.5.0 """ - import logging import re import sys @@ -26,7 +25,7 @@ def query( status=None, status_type="string", wait_for=None, - **kwargs + **kwargs, ): """ Perform an HTTP query and statefully return the result @@ -130,48 +129,48 @@ def query( if match_type == "string": if str(match) in data.get("text", ""): ret["result"] = True - ret["comment"] += ' Match text "{}" was found.'.format(match) + ret["comment"] += f' Match text "{match}" was found.' else: ret["result"] = False - ret["comment"] += ' Match text "{}" was not found.'.format(match) + ret["comment"] += f' Match text "{match}" was not found.' elif match_type == "pcre": if re.search(str(match), str(data.get("text", ""))): ret["result"] = True - ret["comment"] += ' Match pattern "{}" was found.'.format(match) + ret["comment"] += f' Match pattern "{match}" was found.' else: ret["result"] = False - ret["comment"] += ' Match pattern "{}" was not found.'.format(match) + ret["comment"] += f' Match pattern "{match}" was not found.' if status is not None: # Deals with case of status_type as a list of strings representing statuses if status_type == "list": for stat in status: if str(data.get("status", "")) == str(stat): - ret["comment"] += " Status {} was found.".format(stat) + ret["comment"] += f" Status {stat} was found." if ret["result"] is None: ret["result"] = True if ret["result"] is not True: - ret["comment"] += " Statuses {} were not found.".format(status) + ret["comment"] += f" Statuses {status} were not found." ret["result"] = False # Deals with the case of status_type representing a regex elif status_type == "pcre": if re.search(str(status), str(data.get("status", ""))): - ret["comment"] += ' Status pattern "{}" was found.'.format(status) + ret["comment"] += f' Status pattern "{status}" was found.' if ret["result"] is None: ret["result"] = True else: - ret["comment"] += ' Status pattern "{}" was not found.'.format(status) + ret["comment"] += f' Status pattern "{status}" was not found.' ret["result"] = False # Deals with the case of status_type as a single string representing a status elif status_type == "string": if str(data.get("status", "")) == str(status): - ret["comment"] += " Status {} was found.".format(status) + ret["comment"] += f" Status {status} was found." if ret["result"] is None: ret["result"] = True else: - ret["comment"] += " Status {} was not found.".format(status) + ret["comment"] += f" Status {status} was not found." ret["result"] = False # cleanup spaces in comment diff --git a/salt/states/icinga2.py b/salt/states/icinga2.py index c67e58b3451..a764cc4f7f6 100644 --- a/salt/states/icinga2.py +++ b/salt/states/icinga2.py @@ -18,7 +18,6 @@ Its output may be stored in a file or in a grain. - output: "/tmp/query_id.txt" """ - import os.path import salt.utils.files @@ -69,10 +68,10 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): return ret elif __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Ticket generation would be executed, storing result in grain: {}".format( - grain + ret["comment"] = ( + "Ticket generation would be executed, storing result in grain: {}".format( + grain + ) ) return ret elif grain: @@ -98,14 +97,14 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): return ret elif output: if not overwrite and os.path.isfile(output): - ret["comment"] = "No execution needed. File {} already set".format(output) + ret["comment"] = f"No execution needed. File {output} already set" return ret elif __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Ticket generation would be executed, storing result in file: {}".format( - output + ret["comment"] = ( + "Ticket generation would be executed, storing result in file: {}".format( + output + ) ) return ret elif __opts__["test"]: @@ -122,7 +121,7 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): if output == "grain": if grain and not key: __salt__["grains.setval"](grain, ticket) - ret["changes"]["ticket"] = "Executed. Output into grain: {}".format(grain) + ret["changes"]["ticket"] = f"Executed. Output into grain: {grain}" elif grain: if grain in __salt__["grains.ls"](): grain_value = __salt__["grains.get"](grain) @@ -134,7 +133,7 @@ def generate_ticket(name, output=None, grain=None, key=None, overwrite=True): grain, key ) elif output: - ret["changes"]["ticket"] = "Executed. Output into {}".format(output) + ret["changes"]["ticket"] = f"Executed. Output into {output}" with salt.utils.files.fopen(output, "w") as output_file: output_file.write(salt.utils.stringutils.to_str(ticket)) else: @@ -151,15 +150,15 @@ def generate_cert(name): The domain name for which this certificate and key will be generated """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}{}.crt".format(get_certs_path(), name) - key = "{}{}.key".format(get_certs_path(), name) + cert = f"{get_certs_path()}{name}.crt" + key = f"{get_certs_path()}{name}.key" # Checking if execution is needed. if os.path.isfile(cert) and os.path.isfile(key): - ret[ - "comment" - ] = "No execution needed. Cert: {} and key: {} already generated.".format( - cert, key + ret["comment"] = ( + "No execution needed. Cert: {} and key: {} already generated.".format( + cert, key + ) ) return ret if __opts__["test"]: @@ -171,8 +170,8 @@ def generate_cert(name): cert_save = __salt__["icinga2.generate_cert"](name) if not cert_save["retcode"]: ret["comment"] = "Certificate and key generated" - ret["changes"]["cert"] = "Executed. Certificate saved: {}".format(cert) - ret["changes"]["key"] = "Executed. Key saved: {}".format(key) + ret["changes"]["cert"] = f"Executed. Certificate saved: {cert}" + ret["changes"]["key"] = f"Executed. Key saved: {key}" return ret @@ -187,11 +186,11 @@ def save_cert(name, master): Icinga2 master node for which this certificate will be saved """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}trusted-master.crt".format(get_certs_path()) + cert = f"{get_certs_path()}trusted-master.crt" # Checking if execution is needed. if os.path.isfile(cert): - ret["comment"] = "No execution needed. Cert: {} already saved.".format(cert) + ret["comment"] = f"No execution needed. Cert: {cert} already saved." return ret if __opts__["test"]: ret["result"] = None @@ -202,7 +201,7 @@ def save_cert(name, master): cert_save = __salt__["icinga2.save_cert"](name, master) if not cert_save["retcode"]: ret["comment"] = "Certificate for icinga2 master saved" - ret["changes"]["cert"] = "Executed. Certificate saved: {}".format(cert) + ret["changes"]["cert"] = f"Executed. Certificate saved: {cert}" return ret @@ -223,11 +222,11 @@ def request_cert(name, master, ticket, port="5665"): Icinga2 port, defaults to 5665 """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}ca.crt".format(get_certs_path()) + cert = f"{get_certs_path()}ca.crt" # Checking if execution is needed. if os.path.isfile(cert): - ret["comment"] = "No execution needed. Cert: {} already exists.".format(cert) + ret["comment"] = f"No execution needed. Cert: {cert} already exists." return ret if __opts__["test"]: ret["result"] = None @@ -238,7 +237,7 @@ def request_cert(name, master, ticket, port="5665"): cert_request = __salt__["icinga2.request_cert"](name, master, ticket, port) if not cert_request["retcode"]: ret["comment"] = "Certificate request from icinga2 master executed" - ret["changes"]["cert"] = "Executed. Certificate requested: {}".format(cert) + ret["changes"]["cert"] = f"Executed. Certificate requested: {cert}" return ret ret["comment"] = "FAILED. Certificate requested failed with output: {}".format( @@ -262,8 +261,8 @@ def node_setup(name, master, ticket): Authentication ticket generated on icinga2 master """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} - cert = "{}{}.crt.orig".format(get_certs_path(), name) - key = "{}{}.key.orig".format(get_certs_path(), name) + cert = f"{get_certs_path()}{name}.crt.orig" + key = f"{get_certs_path()}{name}.key.orig" # Checking if execution is needed. if os.path.isfile(cert) and os.path.isfile(cert): diff --git a/salt/states/idem.py b/salt/states/idem.py index a7caba30ecd..b324f885671 100644 --- a/salt/states/idem.py +++ b/salt/states/idem.py @@ -30,13 +30,13 @@ def _get_refs(sources, tree): sls_sources = [] SLSs = [] if tree: - sls_sources.append("file://{}".format(tree)) + sls_sources.append(f"file://{tree}") for sls in sources: path = pathlib.Path(sls) if path.is_file(): ref = str(path.stem if path.suffix == ".sls" else path.name) SLSs.append(ref) - implied = "file://{}".format(path.parent) + implied = f"file://{path.parent}" if implied not in sls_sources: sls_sources.append(implied) else: @@ -152,7 +152,7 @@ def state( return { "name": name, "result": success, - "comment": "Ran {} idem states".format(len(running)) if success else errors, + "comment": f"Ran {len(running)} idem states" if success else errors, "changes": {}, "sub_state_run": running, } diff --git a/salt/states/ifttt.py b/salt/states/ifttt.py index f7378576783..4ab7f68df02 100644 --- a/salt/states/ifttt.py +++ b/salt/states/ifttt.py @@ -80,8 +80,8 @@ def trigger_event(name, event, value1=None, value2=None, value3=None): if ret and ret["result"]: ret["result"] = True - ret["comment"] = "Triggered Event: {}".format(name) + ret["comment"] = f"Triggered Event: {name}" else: - ret["comment"] = "Failed to trigger event: {}".format(name) + ret["comment"] = f"Failed to trigger event: {name}" return ret diff --git a/salt/states/incron.py b/salt/states/incron.py index 6baad30808f..d290ca7b681 100644 --- a/salt/states/incron.py +++ b/salt/states/incron.py @@ -119,26 +119,26 @@ def present(name, path, mask, cmd, user="root"): status = _check_cron(user, path, mask, cmd) ret["result"] = None if status == "absent": - ret["comment"] = "Incron {} is set to be added".format(name) + ret["comment"] = f"Incron {name} is set to be added" elif status == "present": ret["result"] = True - ret["comment"] = "Incron {} already present".format(name) + ret["comment"] = f"Incron {name} already present" elif status == "update": - ret["comment"] = "Incron {} is set to be updated".format(name) + ret["comment"] = f"Incron {name} is set to be updated" return ret data = __salt__["incron.set_job"](user=user, path=path, mask=mask, cmd=cmd) if data == "present": - ret["comment"] = "Incron {} already present".format(name) + ret["comment"] = f"Incron {name} already present" return ret if data == "new": - ret["comment"] = "Incron {} added to {}'s incrontab".format(name, user) + ret["comment"] = f"Incron {name} added to {user}'s incrontab" ret["changes"] = {user: name} return ret if data == "updated": - ret["comment"] = "Incron {} updated".format(name) + ret["comment"] = f"Incron {name} updated" ret["changes"] = {user: name} return ret ret["comment"] = "Incron {} for user {} failed to commit with error \n{}".format( @@ -180,17 +180,17 @@ def absent(name, path, mask, cmd, user="root"): ret["result"] = None if status == "absent": ret["result"] = True - ret["comment"] = "Incron {} is absent".format(name) + ret["comment"] = f"Incron {name} is absent" elif status == "present" or status == "update": - ret["comment"] = "Incron {} is set to be removed".format(name) + ret["comment"] = f"Incron {name} is set to be removed" return ret data = __salt__["incron.rm_job"](user=user, path=path, mask=mask, cmd=cmd) if data == "absent": - ret["comment"] = "Incron {} already absent".format(name) + ret["comment"] = f"Incron {name} already absent" return ret if data == "removed": - ret["comment"] = "Incron {} removed from {}'s crontab".format(name, user) + ret["comment"] = f"Incron {name} removed from {user}'s crontab" ret["changes"] = {user: name} return ret ret["comment"] = "Incron {} for user {} failed to commit with error {}".format( diff --git a/salt/states/influxdb08_database.py b/salt/states/influxdb08_database.py index fac790a0824..e2bfe5989d0 100644 --- a/salt/states/influxdb08_database.py +++ b/salt/states/influxdb08_database.py @@ -49,16 +49,16 @@ def present(name, user=None, password=None, host=None, port=None): ) return ret if __salt__["influxdb08.db_create"](name, user, password, host, port): - ret["comment"] = "Database {} has been created".format(name) + ret["comment"] = f"Database {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret # fallback - ret["comment"] = "Database {} is already present, so cannot be created".format(name) + ret["comment"] = f"Database {name} is already present, so cannot be created" return ret @@ -93,14 +93,14 @@ def absent(name, user=None, password=None, host=None, port=None): ) return ret if __salt__["influxdb08.db_remove"](name, user, password, host, port): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove database {}".format(name) + ret["comment"] = f"Failed to remove database {name}" ret["result"] = False return ret # fallback - ret["comment"] = "Database {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Database {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/influxdb08_user.py b/salt/states/influxdb08_user.py index 19865232692..e482287e6dc 100644 --- a/salt/states/influxdb08_user.py +++ b/salt/states/influxdb08_user.py @@ -53,7 +53,7 @@ def present( database, user, password, host, port ): ret["result"] = False - ret["comment"] = "Database {} does not exist".format(database) + ret["comment"] = f"Database {database} does not exist" return ret # check if user exists @@ -70,16 +70,16 @@ def present( if __salt__["influxdb08.user_create"]( name, passwd, database, user, password, host, port ): - ret["comment"] = "User {} has been created".format(name) + ret["comment"] = f"User {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create user {}".format(name) + ret["comment"] = f"Failed to create user {name}" ret["result"] = False return ret # fallback - ret["comment"] = "User {} is already present".format(name) + ret["comment"] = f"User {name} is already present" return ret @@ -112,19 +112,19 @@ def absent(name, database=None, user=None, password=None, host=None, port=None): if __salt__["influxdb08.user_exists"](name, database, user, password, host, port): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is present and needs to be removed".format(name) + ret["comment"] = f"User {name} is present and needs to be removed" return ret if __salt__["influxdb08.user_remove"]( name, database, user, password, host, port ): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove user {}".format(name) + ret["comment"] = f"Failed to remove user {name}" ret["result"] = False return ret # fallback - ret["comment"] = "User {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"User {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/influxdb_continuous_query.py b/salt/states/influxdb_continuous_query.py index 8c402dc1b09..c21dde4e5e0 100644 --- a/salt/states/influxdb_continuous_query.py +++ b/salt/states/influxdb_continuous_query.py @@ -42,7 +42,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "continuous query {} is already present".format(name), + "comment": f"continuous query {name} is already present", } if not __salt__["influxdb.continuous_query_exists"]( @@ -50,16 +50,16 @@ def present( ): if __opts__["test"]: ret["result"] = None - ret["comment"] = " {} is absent and will be created".format(name) + ret["comment"] = f" {name} is absent and will be created" return ret if __salt__["influxdb.create_continuous_query"]( database, name, query, resample_time, coverage_period, **client_args ): - ret["comment"] = "continuous query {} has been created".format(name) + ret["comment"] = f"continuous query {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create continuous query {}".format(name) + ret["comment"] = f"Failed to create continuous query {name}" ret["result"] = False return ret @@ -80,22 +80,22 @@ def absent(name, database, **client_args): "name": name, "changes": {}, "result": True, - "comment": "continuous query {} is not present".format(name), + "comment": f"continuous query {name} is not present", } if __salt__["influxdb.continuous_query_exists"](database, name, **client_args): if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "continuous query {} is present and needs to be removed".format(name) + ret["comment"] = ( + f"continuous query {name} is present and needs to be removed" + ) return ret if __salt__["influxdb.drop_continuous_query"](database, name, **client_args): - ret["comment"] = "continuous query {} has been removed".format(name) + ret["comment"] = f"continuous query {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove continuous query {}".format(name) + ret["comment"] = f"Failed to remove continuous query {name}" ret["result"] = False return ret diff --git a/salt/states/influxdb_database.py b/salt/states/influxdb_database.py index cfa2a1c9d47..1a99df01801 100644 --- a/salt/states/influxdb_database.py +++ b/salt/states/influxdb_database.py @@ -26,20 +26,20 @@ def present(name, **client_args): "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(name), + "comment": f"Database {name} is already present", } if not __salt__["influxdb.db_exists"](name, **client_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is absent and will be created".format(name) + ret["comment"] = f"Database {name} is absent and will be created" return ret if __salt__["influxdb.create_db"](name, **client_args): - ret["comment"] = "Database {} has been created".format(name) + ret["comment"] = f"Database {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret @@ -57,7 +57,7 @@ def absent(name, **client_args): "name": name, "changes": {}, "result": True, - "comment": "Database {} is not present".format(name), + "comment": f"Database {name} is not present", } if __salt__["influxdb.db_exists"](name, **client_args): @@ -68,11 +68,11 @@ def absent(name, **client_args): ) return ret if __salt__["influxdb.drop_db"](name, **client_args): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove database {}".format(name) + ret["comment"] = f"Failed to remove database {name}" ret["result"] = False return ret diff --git a/salt/states/influxdb_retention_policy.py b/salt/states/influxdb_retention_policy.py index e729269a605..f63ffd24c21 100644 --- a/salt/states/influxdb_retention_policy.py +++ b/salt/states/influxdb_retention_policy.py @@ -59,7 +59,7 @@ def present(name, database, duration="7d", replication=1, default=False, **clien "name": name, "changes": {}, "result": True, - "comment": "retention policy {} is already present".format(name), + "comment": f"retention policy {name} is already present", } if not __salt__["influxdb.retention_policy_exists"]( @@ -67,16 +67,16 @@ def present(name, database, duration="7d", replication=1, default=False, **clien ): if __opts__["test"]: ret["result"] = None - ret["comment"] = " {} is absent and will be created".format(name) + ret["comment"] = f" {name} is absent and will be created" return ret if __salt__["influxdb.create_retention_policy"]( database, name, duration, replication, default, **client_args ): - ret["comment"] = "retention policy {} has been created".format(name) + ret["comment"] = f"retention policy {name} has been created" ret["changes"][name] = "Present" return ret else: - ret["comment"] = "Failed to create retention policy {}".format(name) + ret["comment"] = f"Failed to create retention policy {name}" ret["result"] = False return ret @@ -106,16 +106,16 @@ def present(name, database, duration="7d", replication=1, default=False, **clien if update_policy: if __opts__["test"]: ret["result"] = None - ret["comment"] = " {} is present and set to be changed".format(name) + ret["comment"] = f" {name} is present and set to be changed" return ret else: if __salt__["influxdb.alter_retention_policy"]( database, name, duration, replication, default, **client_args ): - ret["comment"] = "retention policy {} has been changed".format(name) + ret["comment"] = f"retention policy {name} has been changed" return ret else: - ret["comment"] = "Failed to update retention policy {}".format(name) + ret["comment"] = f"Failed to update retention policy {name}" ret["result"] = False return ret @@ -136,22 +136,22 @@ def absent(name, database, **client_args): "name": name, "changes": {}, "result": True, - "comment": "retention policy {} is not present".format(name), + "comment": f"retention policy {name} is not present", } if __salt__["influxdb.retention_policy_exists"](database, name, **client_args): if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "retention policy {} is present and needs to be removed".format(name) + ret["comment"] = ( + f"retention policy {name} is present and needs to be removed" + ) return ret if __salt__["influxdb.drop_retention_policy"](database, name, **client_args): - ret["comment"] = "retention policy {} has been removed".format(name) + ret["comment"] = f"retention policy {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove retention policy {}".format(name) + ret["comment"] = f"Failed to remove retention policy {name}" ret["result"] = False return ret diff --git a/salt/states/influxdb_user.py b/salt/states/influxdb_user.py index 52f153ccc53..ea48c6854d4 100644 --- a/salt/states/influxdb_user.py +++ b/salt/states/influxdb_user.py @@ -55,20 +55,20 @@ def present(name, passwd, admin=False, grants=None, **client_args): "name": name, "changes": {}, "result": True, - "comment": "User {} is present and up to date".format(name), + "comment": f"User {name} is present and up to date", } if not __salt__["influxdb.user_exists"](name, **client_args): create = True if __opts__["test"]: - ret["comment"] = "User {} will be created".format(name) + ret["comment"] = f"User {name} will be created" ret["result"] = None return ret else: if not __salt__["influxdb.create_user"]( name, passwd, admin=admin, **client_args ): - ret["comment"] = "Failed to create user {}".format(name) + ret["comment"] = f"Failed to create user {name}" ret["result"] = False return ret else: @@ -104,7 +104,7 @@ def present(name, passwd, admin=False, grants=None, **client_args): del db_privileges[database] if database not in db_privileges: ret["changes"][ - "Grant on database {} to user {}".format(database, name) + f"Grant on database {database} to user {name}" ] = privilege if not __opts__["test"]: __salt__["influxdb.grant_privilege"]( @@ -113,19 +113,19 @@ def present(name, passwd, admin=False, grants=None, **client_args): if ret["changes"]: if create: - ret["comment"] = "Created user {}".format(name) + ret["comment"] = f"Created user {name}" ret["changes"][name] = "User created" else: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "User {} will be updated with the following changes:".format(name) + ret["comment"] = ( + f"User {name} will be updated with the following changes:" + ) for k, v in ret["changes"].items(): - ret["comment"] += "\n{} => {}".format(k, v) + ret["comment"] += f"\n{k} => {v}" ret["changes"] = {} else: - ret["comment"] = "Updated user {}".format(name) + ret["comment"] = f"Updated user {name}" return ret @@ -141,21 +141,21 @@ def absent(name, **client_args): "name": name, "changes": {}, "result": True, - "comment": "User {} is not present".format(name), + "comment": f"User {name} is not present", } if __salt__["influxdb.user_exists"](name, **client_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} will be removed".format(name) + ret["comment"] = f"User {name} will be removed" return ret else: if __salt__["influxdb.remove_user"](name, **client_args): - ret["comment"] = "Removed user {}".format(name) + ret["comment"] = f"Removed user {name}" ret["changes"][name] = "removed" return ret else: - ret["comment"] = "Failed to remove user {}".format(name) + ret["comment"] = f"Failed to remove user {name}" ret["result"] = False return ret return ret diff --git a/salt/states/infoblox_a.py b/salt/states/infoblox_a.py index 35f3d716aa5..c2b43599c64 100644 --- a/salt/states/infoblox_a.py +++ b/salt/states/infoblox_a.py @@ -48,10 +48,10 @@ def present(name=None, ipv4addr=None, data=None, ensure_data=True, **api_opts): if obj: # warn user that the data was updated and does not match ret["result"] = False - ret[ - "comment" - ] = "** please update the name: {} to equal the updated data name {}".format( - name, data["name"] + ret["comment"] = ( + "** please update the name: {} to equal the updated data name {}".format( + name, data["name"] + ) ) return ret @@ -59,9 +59,9 @@ def present(name=None, ipv4addr=None, data=None, ensure_data=True, **api_opts): obj = obj[0] if not ensure_data: ret["result"] = True - ret[ - "comment" - ] = "infoblox record already created (supplied fields not ensured to match)" + ret["comment"] = ( + "infoblox record already created (supplied fields not ensured to match)" + ) return ret diff = __salt__["infoblox.diff_objects"](data, obj) diff --git a/salt/states/infoblox_cname.py b/salt/states/infoblox_cname.py index 99c42a6d9f8..f02470261d9 100644 --- a/salt/states/infoblox_cname.py +++ b/salt/states/infoblox_cname.py @@ -57,19 +57,19 @@ def present(name=None, data=None, ensure_data=True, **api_opts): if obj: # warn user that the data was updated and does not match ret["result"] = False - ret[ - "comment" - ] = "** please update the name: {} to equal the updated data name {}".format( - name, data["name"] + ret["comment"] = ( + "** please update the name: {} to equal the updated data name {}".format( + name, data["name"] + ) ) return ret if obj: if not ensure_data: ret["result"] = True - ret[ - "comment" - ] = "infoblox record already created (supplied fields not ensured to match)" + ret["comment"] = ( + "infoblox record already created (supplied fields not ensured to match)" + ) return ret diff = __salt__["infoblox.diff_objects"](data, obj) diff --git a/salt/states/infoblox_host_record.py b/salt/states/infoblox_host_record.py index e5c5ecb9529..3b1cace0ed3 100644 --- a/salt/states/infoblox_host_record.py +++ b/salt/states/infoblox_host_record.py @@ -53,19 +53,19 @@ def present(name=None, data=None, ensure_data=True, **api_opts): if obj: # warn user that the host name was updated and does not match ret["result"] = False - ret[ - "comment" - ] = "please update the name: {} to equal the updated data name {}".format( - name, data["name"] + ret["comment"] = ( + "please update the name: {} to equal the updated data name {}".format( + name, data["name"] + ) ) return ret if obj: if not ensure_data: ret["result"] = True - ret[ - "comment" - ] = "infoblox record already created (supplied fields not ensured to match)" + ret["comment"] = ( + "infoblox record already created (supplied fields not ensured to match)" + ) return ret obj = __salt__["infoblox.get_host_advanced"](name=name, **api_opts) @@ -131,7 +131,7 @@ def present(name=None, data=None, ensure_data=True, **api_opts): if __opts__["test"]: ret["result"] = None - ret["comment"] = "would attempt to create infoblox record {}".format(name) + ret["comment"] = f"would attempt to create infoblox record {name}" return ret new_obj_ref = __salt__["infoblox.create_host"](data=data, **api_opts) diff --git a/salt/states/infoblox_range.py b/salt/states/infoblox_range.py index 6eb0d193ebd..20783323420 100644 --- a/salt/states/infoblox_range.py +++ b/salt/states/infoblox_range.py @@ -132,7 +132,7 @@ def present(name=None, start_addr=None, end_addr=None, data=None, **api_opts): if __opts__["test"]: ret["result"] = None - ret["comment"] = "would attempt to create record {}".format(name) + ret["comment"] = f"would attempt to create record {name}" return ret new_obj_ref = __salt__["infoblox.create_ipv4_range"](data, **api_opts) @@ -199,7 +199,7 @@ def absent(name=None, start_addr=None, end_addr=None, data=None, **api_opts): if __salt__["infoblox.delete_object"](objref=obj["_ref"]): ret["result"] = True ret["changes"] = { - "old": "Found {} - {}".format(start_addr, end_addr), + "old": f"Found {start_addr} - {end_addr}", "new": "Removed", } return ret diff --git a/salt/states/ini_manage.py b/salt/states/ini_manage.py index 9d3989769c7..9851d792734 100644 --- a/salt/states/ini_manage.py +++ b/salt/states/ini_manage.py @@ -9,7 +9,6 @@ Manage ini files """ - from salt.utils.odict import OrderedDict __virtualname__ = "ini" @@ -71,12 +70,12 @@ def options_present(name, sections=None, separator="=", strict=False): for option in options: if option in original_top_level_opts: if str(original_top_level_opts[option]) == str(options[option]): - ret["comment"] += "Unchanged key {}.\n".format(option) + ret["comment"] += f"Unchanged key {option}.\n" else: - ret["comment"] += "Changed key {}.\n".format(option) + ret["comment"] += f"Changed key {option}.\n" ret["result"] = None else: - ret["comment"] += "Changed key {}.\n".format(option) + ret["comment"] += f"Changed key {option}.\n" ret["result"] = None else: options_updated = __salt__["ini.set_option"](name, options, separator) @@ -84,7 +83,7 @@ def options_present(name, sections=None, separator="=", strict=False): if strict: for opt_to_remove in set(original_top_level_opts).difference(options): if __opts__["test"]: - ret["comment"] += "Removed key {}.\n".format(opt_to_remove) + ret["comment"] += f"Removed key {opt_to_remove}.\n" ret["result"] = None else: __salt__["ini.remove_option"]( @@ -151,7 +150,7 @@ def options_present(name, sections=None, separator="=", strict=False): if not __opts__["test"]: changes = __salt__["ini.set_option"](name, sections, separator) except (OSError, KeyError) as err: - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" ret["result"] = False return ret if "error" in changes: @@ -199,7 +198,7 @@ def options_absent(name, sections=None, separator="="): try: cur_section = __salt__["ini.get_section"](name, section, separator) except OSError as err: - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" ret["result"] = False return ret except AttributeError: @@ -212,14 +211,14 @@ def options_absent(name, sections=None, separator="="): key, section_name ) continue - ret["comment"] += "Deleted key {}{}.\n".format(key, section_name) + ret["comment"] += f"Deleted key {key}{section_name}.\n" ret["result"] = None else: option = section if not __salt__["ini.get_option"](name, None, option, separator): - ret["comment"] += "Key {} does not exist.\n".format(option) + ret["comment"] += f"Key {option} does not exist.\n" continue - ret["comment"] += "Deleted key {}.\n".format(option) + ret["comment"] += f"Deleted key {option}.\n" ret["result"] = None if ret["comment"] == "": @@ -233,7 +232,7 @@ def options_absent(name, sections=None, separator="="): name, section, key, separator ) except OSError as err: - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" ret["result"] = False return ret if not current_value: @@ -278,14 +277,14 @@ def sections_present(name, sections=None, separator="="): cur_ini = __salt__["ini.get_ini"](name, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret for section in sections or {}: if section in cur_ini: - ret["comment"] += "Section unchanged {}.\n".format(section) + ret["comment"] += f"Section unchanged {section}.\n" continue else: - ret["comment"] += "Created new section {}.\n".format(section) + ret["comment"] += f"Created new section {section}.\n" ret["result"] = None if ret["comment"] == "": ret["comment"] = "No changes detected." @@ -297,7 +296,7 @@ def sections_present(name, sections=None, separator="="): changes = __salt__["ini.set_option"](name, section_to_update, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret if "error" in changes: ret["result"] = False @@ -335,13 +334,13 @@ def sections_absent(name, sections=None, separator="="): cur_ini = __salt__["ini.get_ini"](name, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret for section in sections or []: if section not in cur_ini: - ret["comment"] += "Section {} does not exist.\n".format(section) + ret["comment"] += f"Section {section} does not exist.\n" continue - ret["comment"] += "Deleted section {}.\n".format(section) + ret["comment"] += f"Deleted section {section}.\n" ret["result"] = None if ret["comment"] == "": ret["comment"] = "No changes detected." @@ -351,7 +350,7 @@ def sections_absent(name, sections=None, separator="="): cur_section = __salt__["ini.remove_section"](name, section, separator) except OSError as err: ret["result"] = False - ret["comment"] = "{}".format(err) + ret["comment"] = f"{err}" return ret if not cur_section: continue diff --git a/salt/states/ipmi.py b/salt/states/ipmi.py index 3f408590b49..51448b66329 100644 --- a/salt/states/ipmi.py +++ b/salt/states/ipmi.py @@ -131,7 +131,7 @@ def power(name="power_on", wait=300, **kwargs): return ret if __opts__["test"]: - ret["comment"] = "would power: {} system".format(name) + ret["comment"] = f"would power: {name} system" ret["result"] = None ret["changes"] = {"old": org, "new": name} return ret @@ -152,7 +152,7 @@ def user_present( link_auth=True, ipmi_msg=True, privilege_level="administrator", - **kwargs + **kwargs, ): """ Ensure IPMI user and user privileges. @@ -259,7 +259,7 @@ def user_present( link_auth, ipmi_msg, privilege_level, - **kwargs + **kwargs, ) current_user = __salt__["ipmi.get_user"](uid=uid, channel=channel, **kwargs) ret["comment"] = "(re)created user" diff --git a/salt/states/ipset.py b/salt/states/ipset.py index f59e01f80c9..8132e0b5f19 100644 --- a/salt/states/ipset.py +++ b/salt/states/ipset.py @@ -87,17 +87,17 @@ def set_present(name, set_type, family="ipv4", **kwargs): set_check = __salt__["ipset.check_set"](name) if set_check is True: ret["result"] = True - ret["comment"] = "ipset set {} already exists for {}".format(name, family) + ret["comment"] = f"ipset set {name} already exists for {family}" return ret if __opts__["test"]: - ret["comment"] = "ipset set {} would be added for {}".format(name, family) + ret["comment"] = f"ipset set {name} would be added for {family}" return ret command = __salt__["ipset.new_set"](name, set_type, family, **kwargs) if command is True: ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "ipset set {} created successfully for {}".format(name, family) + ret["comment"] = f"ipset set {name} created successfully for {family}" return ret else: ret["result"] = False @@ -122,10 +122,10 @@ def set_absent(name, family="ipv4", **kwargs): set_check = __salt__["ipset.check_set"](name, family) if not set_check: ret["result"] = True - ret["comment"] = "ipset set {} for {} is already absent".format(name, family) + ret["comment"] = f"ipset set {name} for {family} is already absent" return ret if __opts__["test"]: - ret["comment"] = "ipset set {} for {} would be removed".format(name, family) + ret["comment"] = f"ipset set {name} for {family} would be removed" return ret flush_set = __salt__["ipset.flush"](name, family) if flush_set: @@ -212,10 +212,10 @@ def present(name, entry=None, family="ipv4", **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = "Failed to add to entry {1} to set {0} for family {2}.\n{3}".format( - kwargs["set_name"], _entry, family, command + ret["comment"] = ( + "Failed to add to entry {1} to set {0} for family {2}.\n{3}".format( + kwargs["set_name"], _entry, family, command + ) ) return ret @@ -310,7 +310,7 @@ def flush(name, family="ipv4", **kwargs): set_check = __salt__["ipset.check_set"](name) if set_check is False: ret["result"] = False - ret["comment"] = "ipset set {} does not exist for {}".format(name, family) + ret["comment"] = f"ipset set {name} does not exist for {family}" return ret if __opts__["test"]: @@ -321,7 +321,7 @@ def flush(name, family="ipv4", **kwargs): if __salt__["ipset.flush"](name, family): ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Flushed ipset entries from set {} for {}".format(name, family) + ret["comment"] = f"Flushed ipset entries from set {name} for {family}" return ret else: ret["result"] = False diff --git a/salt/states/iptables.py b/salt/states/iptables.py index 79edd60b8ff..57c8b287cb0 100644 --- a/salt/states/iptables.py +++ b/salt/states/iptables.py @@ -245,6 +245,7 @@ Example rules for IPSec policy: output of iptables-save. This may have unintended consequences on legacy releases of ``iptables``. """ + import copy from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS @@ -324,10 +325,10 @@ def chain_absent(name, table="filter", family="ipv4"): chain_check = __salt__["iptables.check_chain"](table, name, family) if not chain_check: ret["result"] = True - ret[ - "comment" - ] = "iptables {} chain is already absent in {} table for {}".format( - name, table, family + ret["comment"] = ( + "iptables {} chain is already absent in {} table for {}".format( + name, table, family + ) ) return ret if __opts__["test"]: @@ -341,10 +342,10 @@ def chain_absent(name, table="filter", family="ipv4"): if command is True: ret["changes"] = {"locale": name} ret["result"] = True - ret[ - "comment" - ] = "iptables {} chain in {} table delete success for {}".format( - name, table, family + ret["comment"] = ( + "iptables {} chain in {} table delete success for {}".format( + name, table, family + ) ) else: ret["result"] = False @@ -497,10 +498,10 @@ def append(name, table="filter", family="ipv4", **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set iptables rule for {}.\nAttempted rule was {} for {}".format( - name, command.strip(), family + ret["comment"] = ( + "Failed to set iptables rule for {}.\nAttempted rule was {} for {}".format( + name, command.strip(), family + ) ) return ret @@ -633,10 +634,10 @@ def insert(name, table="filter", family="ipv4", **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set iptables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to set iptables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -736,7 +737,7 @@ def delete(name, table="filter", family="ipv4", **kwargs): if not result: ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Delete iptables rule for {} {}".format(name, command.strip()) + ret["comment"] = f"Delete iptables rule for {name} {command.strip()}" if "save" in kwargs and kwargs["save"]: if kwargs["save"] is not True: filename = kwargs["save"] @@ -749,10 +750,10 @@ def delete(name, table="filter", family="ipv4", **kwargs): return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to delete iptables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to delete iptables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -788,10 +789,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): == kwargs["policy"] ): ret["result"] = True - ret[ - "comment" - ] = "iptables default policy for chain {} on table {} for {} already set to {}".format( - kwargs["chain"], table, family, kwargs["policy"] + ret["comment"] = ( + "iptables default policy for chain {} on table {} for {} already set to {}".format( + kwargs["chain"], table, family, kwargs["policy"] + ) ) return ret if __opts__["test"]: @@ -814,10 +815,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): else: filename = None __salt__["iptables.save"](filename=filename, family=family) - ret[ - "comment" - ] = "Set and saved default policy for {} to {} family {}".format( - kwargs["chain"], kwargs["policy"], family + ret["comment"] = ( + "Set and saved default policy for {} to {} family {}".format( + kwargs["chain"], kwargs["policy"], family + ) ) return ret else: @@ -852,10 +853,10 @@ def flush(name, table="filter", family="ipv4", **kwargs): if "chain" not in kwargs: kwargs["chain"] = "" if __opts__["test"]: - ret[ - "comment" - ] = "iptables rules in {} table {} chain {} family needs to be flushed".format( - name, table, family + ret["comment"] = ( + "iptables rules in {} table {} chain {} family needs to be flushed".format( + name, table, family + ) ) return ret if not __salt__["iptables.flush"](table, kwargs["chain"], family): diff --git a/salt/states/jboss7.py b/salt/states/jboss7.py index 8d3438d9940..9f1dfdb4c30 100644 --- a/salt/states/jboss7.py +++ b/salt/states/jboss7.py @@ -35,7 +35,6 @@ For the sake of brevity, examples for each state assume that jboss_config is con """ - import logging import re import time @@ -579,7 +578,7 @@ def __get_artifact(salt_source): except Exception as e: # pylint: disable=broad-except log.debug(traceback.format_exc()) - comment = "Unable to manage file: {}".format(e) + comment = f"Unable to manage file: {e}" else: resolved_source = salt_source["target_file"] @@ -649,10 +648,10 @@ def reloaded(name, jboss_config, timeout=60, interval=5): ret["changes"]["reloaded"] = "configuration" else: ret["result"] = False - ret[ - "comment" - ] = "Could not reload the configuration. Timeout ({} s) exceeded. ".format( - timeout + ret["comment"] = ( + "Could not reload the configuration. Timeout ({} s) exceeded. ".format( + timeout + ) ) if not status["success"]: ret["comment"] = __append_comment( @@ -675,9 +674,7 @@ def __check_dict_contains(dct, dict_name, keys, comment="", result=True): for key in keys: if key not in dct.keys(): result = False - comment = __append_comment( - "Missing {} in {}".format(key, dict_name), comment - ) + comment = __append_comment(f"Missing {key} in {dict_name}", comment) return result, comment diff --git a/salt/states/jenkins.py b/salt/states/jenkins.py index 3b04caf3b0c..b55b05a3716 100644 --- a/salt/states/jenkins.py +++ b/salt/states/jenkins.py @@ -6,7 +6,6 @@ Management of Jenkins """ - import difflib import io import logging @@ -56,7 +55,7 @@ def present(name, config=None, **kwargs): "name": name, "result": True, "changes": {}, - "comment": ["Job {} is up to date.".format(name)], + "comment": [f"Job {name} is up to date."], } if __salt__["jenkins.job_exists"](name): @@ -79,7 +78,7 @@ def present(name, config=None, **kwargs): return _fail(ret, exc.strerror) else: ret["changes"] = "".join(diff) - ret["comment"].append("Job '{}' updated.".format(name)) + ret["comment"].append(f"Job '{name}' updated.") else: cached_source_path = __salt__["cp.cache_file"](config, __env__) @@ -94,7 +93,7 @@ def present(name, config=None, **kwargs): buf = io.StringIO(new_config_xml) diff = difflib.unified_diff("", buf.readlines(), lineterm="") ret["changes"][name] = "".join(diff) - ret["comment"].append("Job '{}' added.".format(name)) + ret["comment"].append(f"Job '{name}' added.") ret["comment"] = "\n".join(ret["comment"]) return ret @@ -115,7 +114,7 @@ def absent(name, **kwargs): except CommandExecutionError as exc: return _fail(ret, exc.strerror) else: - ret["comment"] = "Job '{}' deleted.".format(name) + ret["comment"] = f"Job '{name}' deleted." else: - ret["comment"] = "Job '{}' already absent.".format(name) + ret["comment"] = f"Job '{name}' already absent." return ret diff --git a/salt/states/kapacitor.py b/salt/states/kapacitor.py index 23f99ff2e8a..94dc7477c49 100644 --- a/salt/states/kapacitor.py +++ b/salt/states/kapacitor.py @@ -15,6 +15,7 @@ Kapacitor state module. .. versionadded:: 2016.11.0 """ + import difflib import salt.utils.files @@ -74,7 +75,7 @@ def task_present( if not dbrps: dbrps = [] if database and retention_policy: - dbrp = "{}.{}".format(database, retention_policy) + dbrp = f"{database}.{retention_policy}" dbrps.append(dbrp) task_dbrps = [ {"db": dbrp[0], "rp": dbrp[1]} for dbrp in (dbrp.split(".") for dbrp in dbrps) diff --git a/salt/states/kernelpkg.py b/salt/states/kernelpkg.py index 0f535e74038..85476c071da 100644 --- a/salt/states/kernelpkg.py +++ b/salt/states/kernelpkg.py @@ -99,9 +99,9 @@ def latest_installed(name, **kwargs): # pylint: disable=unused-argument result = __salt__["kernelpkg.upgrade"]() ret["result"] = True ret["changes"] = result["upgrades"] - ret[ - "comment" - ] = "The latest kernel package has been installed, but not activated." + ret["comment"] = ( + "The latest kernel package has been installed, but not activated." + ) return ret diff --git a/salt/states/keyboard.py b/salt/states/keyboard.py index 0670a431c08..d8c0ede0d61 100644 --- a/salt/states/keyboard.py +++ b/salt/states/keyboard.py @@ -37,15 +37,15 @@ def system(name): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["keyboard.get_sys"]() == name: ret["result"] = True - ret["comment"] = "System layout {} already set".format(name) + ret["comment"] = f"System layout {name} already set" return ret if __opts__["test"]: - ret["comment"] = "System layout {} needs to be set".format(name) + ret["comment"] = f"System layout {name} needs to be set" return ret if __salt__["keyboard.set_sys"](name): ret["changes"] = {"layout": name} ret["result"] = True - ret["comment"] = "Set system keyboard layout {}".format(name) + ret["comment"] = f"Set system keyboard layout {name}" return ret else: ret["result"] = False @@ -63,15 +63,15 @@ def xorg(name): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["keyboard.get_x"]() == name: ret["result"] = True - ret["comment"] = "XOrg layout {} already set".format(name) + ret["comment"] = f"XOrg layout {name} already set" return ret if __opts__["test"]: - ret["comment"] = "XOrg layout {} needs to be set".format(name) + ret["comment"] = f"XOrg layout {name} needs to be set" return ret if __salt__["keyboard.set_x"](name): ret["changes"] = {"layout": name} ret["result"] = True - ret["comment"] = "Set XOrg keyboard layout {}".format(name) + ret["comment"] = f"Set XOrg keyboard layout {name}" return ret else: ret["result"] = False diff --git a/salt/states/keystone.py b/salt/states/keystone.py index eeab1ce27c4..f3ea1f5ceaa 100644 --- a/salt/states/keystone.py +++ b/salt/states/keystone.py @@ -112,7 +112,7 @@ def user_present( profile=None, password_reset=True, project=None, - **connection_args + **connection_args, ): """ Ensure that the keystone user is present with the specified properties. @@ -162,7 +162,7 @@ def user_present( "name": name, "changes": {}, "result": True, - "comment": 'User "{}" will be updated'.format(name), + "comment": f'User "{name}" will be updated', } _api_version(profile=profile, **connection_args) @@ -177,7 +177,7 @@ def user_present( ) if "Error" in tenantdata: ret["result"] = False - ret["comment"] = 'Tenant / project "{}" does not exist'.format(tenant) + ret["comment"] = f'Tenant / project "{tenant}" does not exist' return ret tenant_id = tenantdata[tenant]["id"] else: @@ -213,52 +213,52 @@ def user_present( change_email or change_enabled or change_tenant or change_password ): ret["result"] = None - ret["comment"] = 'User "{}" will be updated'.format(name) + ret["comment"] = f'User "{name}" will be updated' if change_email is True: ret["changes"]["Email"] = "Will be updated" if change_enabled is True: ret["changes"]["Enabled"] = "Will be True" if change_tenant is True: - ret["changes"]["Tenant"] = 'Will be added to "{}" tenant'.format(tenant) + ret["changes"]["Tenant"] = f'Will be added to "{tenant}" tenant' if change_password is True: ret["changes"]["Password"] = "Will be updated" return ret - ret["comment"] = 'User "{}" is already present'.format(name) + ret["comment"] = f'User "{name}" is already present' if change_email: __salt__["keystone.user_update"]( name=name, email=email, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) + ret["comment"] = f'User "{name}" has been updated' ret["changes"]["Email"] = "Updated" if change_enabled: __salt__["keystone.user_update"]( name=name, enabled=enabled, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) - ret["changes"]["Enabled"] = "Now {}".format(enabled) + ret["comment"] = f'User "{name}" has been updated' + ret["changes"]["Enabled"] = f"Now {enabled}" if change_tenant: __salt__["keystone.user_update"]( name=name, tenant=tenant, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) - ret["changes"]["Tenant"] = 'Added to "{}" tenant'.format(tenant) + ret["comment"] = f'User "{name}" has been updated' + ret["changes"]["Tenant"] = f'Added to "{tenant}" tenant' if change_password: __salt__["keystone.user_password_update"]( name=name, password=password, profile=profile, **connection_args ) - ret["comment"] = 'User "{}" has been updated'.format(name) + ret["comment"] = f'User "{name}" has been updated' ret["changes"]["Password"] = "Updated" if roles: for tenant in roles: args = dict( {"user_name": name, "tenant_name": tenant, "profile": profile}, - **connection_args + **connection_args, ) tenant_roles = __salt__["keystone.user_role_list"](**args) for role in roles[tenant]: @@ -276,7 +276,7 @@ def user_present( "tenant": tenant, "profile": profile, }, - **connection_args + **connection_args, ) newrole = __salt__["keystone.user_role_add"](**addargs) if "roles" in ret["changes"]: @@ -298,7 +298,7 @@ def user_present( "tenant": tenant, "profile": profile, }, - **connection_args + **connection_args, ) oldrole = __salt__["keystone.user_role_remove"](**addargs) if "roles" in ret["changes"]: @@ -309,7 +309,7 @@ def user_present( # Create that user! if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Keystone user "{}" will be added'.format(name) + ret["comment"] = f'Keystone user "{name}" will be added' ret["changes"]["User"] = "Will be created" return ret __salt__["keystone.user_create"]( @@ -319,7 +319,7 @@ def user_present( tenant_id=tenant_id, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) if roles: for tenant in roles: @@ -329,9 +329,9 @@ def user_present( role=role, tenant=tenant, profile=profile, - **connection_args + **connection_args, ) - ret["comment"] = "Keystone user {} has been added".format(name) + ret["comment"] = f"Keystone user {name} has been added" ret["changes"]["User"] = "Created" return ret @@ -348,7 +348,7 @@ def user_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'User "{}" is already absent'.format(name), + "comment": f'User "{name}" is already absent', } # Check if user is present @@ -356,11 +356,11 @@ def user_absent(name, profile=None, **connection_args): if "Error" not in user: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'User "{}" will be deleted'.format(name) + ret["comment"] = f'User "{name}" will be deleted' return ret # Delete that user! __salt__["keystone.user_delete"](name=name, profile=profile, **connection_args) - ret["comment"] = 'User "{}" has been deleted'.format(name) + ret["comment"] = f'User "{name}" has been deleted' ret["changes"]["User"] = "Deleted" return ret @@ -385,7 +385,7 @@ def tenant_present( "name": name, "changes": {}, "result": True, - "comment": 'Tenant / project "{}" already exists'.format(name), + "comment": f'Tenant / project "{name}" already exists', } _api_version(profile=profile, **connection_args) @@ -399,7 +399,7 @@ def tenant_present( if tenant[name].get("description", None) != description: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be updated'.format(name) + ret["comment"] = f'Tenant / project "{name}" will be updated' ret["changes"]["Description"] = "Will be updated" return ret __salt__["keystone.tenant_update"]( @@ -407,29 +407,29 @@ def tenant_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) - ret["comment"] = 'Tenant / project "{}" has been updated'.format(name) + ret["comment"] = f'Tenant / project "{name}" has been updated' ret["changes"]["Description"] = "Updated" if tenant[name].get("enabled", None) != enabled: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be updated'.format(name) - ret["changes"]["Enabled"] = "Will be {}".format(enabled) + ret["comment"] = f'Tenant / project "{name}" will be updated' + ret["changes"]["Enabled"] = f"Will be {enabled}" return ret __salt__["keystone.tenant_update"]( name=name, description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) - ret["comment"] = 'Tenant / project "{}" has been updated'.format(name) - ret["changes"]["Enabled"] = "Now {}".format(enabled) + ret["comment"] = f'Tenant / project "{name}" has been updated' + ret["changes"]["Enabled"] = f"Now {enabled}" else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be added'.format(name) + ret["comment"] = f'Tenant / project "{name}" will be added' ret["changes"]["Tenant"] = "Will be created" return ret # Create tenant @@ -440,7 +440,7 @@ def tenant_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) else: created = __salt__["keystone.tenant_create"]( @@ -448,11 +448,11 @@ def tenant_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) ret["changes"]["Tenant"] = "Created" if created is True else "Failed" ret["result"] = created - ret["comment"] = 'Tenant / project "{}" has been added'.format(name) + ret["comment"] = f'Tenant / project "{name}" has been added' return ret @@ -467,7 +467,7 @@ def tenant_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Tenant / project "{}" is already absent'.format(name), + "comment": f'Tenant / project "{name}" is already absent', } # Check if tenant is present @@ -477,13 +477,13 @@ def tenant_absent(name, profile=None, **connection_args): if "Error" not in tenant: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Tenant / project "{}" will be deleted'.format(name) + ret["comment"] = f'Tenant / project "{name}" will be deleted' return ret # Delete tenant __salt__["keystone.tenant_delete"]( name=name, profile=profile, **connection_args ) - ret["comment"] = 'Tenant / project "{}" has been deleted'.format(name) + ret["comment"] = f'Tenant / project "{name}" has been deleted' ret["changes"]["Tenant/Project"] = "Deleted" return ret @@ -522,7 +522,7 @@ def project_present( description=description, enabled=enabled, profile=profile, - **connection_args + **connection_args, ) @@ -558,7 +558,7 @@ def role_present(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Role "{}" already exists'.format(name), + "comment": f'Role "{name}" already exists', } # Check if role is already present @@ -569,11 +569,11 @@ def role_present(name, profile=None, **connection_args): else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Role "{}" will be added'.format(name) + ret["comment"] = f'Role "{name}" will be added' return ret # Create role __salt__["keystone.role_create"](name, profile=profile, **connection_args) - ret["comment"] = 'Role "{}" has been added'.format(name) + ret["comment"] = f'Role "{name}" has been added' ret["changes"]["Role"] = "Created" return ret @@ -589,7 +589,7 @@ def role_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Role "{}" is already absent'.format(name), + "comment": f'Role "{name}" is already absent', } # Check if role is present @@ -597,11 +597,11 @@ def role_absent(name, profile=None, **connection_args): if "Error" not in role: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Role "{}" will be deleted'.format(name) + ret["comment"] = f'Role "{name}" will be deleted' return ret # Delete role __salt__["keystone.role_delete"](name=name, profile=profile, **connection_args) - ret["comment"] = 'Role "{}" has been deleted'.format(name) + ret["comment"] = f'Role "{name}" has been deleted' ret["changes"]["Role"] = "Deleted" return ret @@ -626,7 +626,7 @@ def service_present( "name": name, "changes": {}, "result": True, - "comment": 'Service "{}" already exists'.format(name), + "comment": f'Service "{name}" already exists', } # Check if service is already present @@ -639,13 +639,13 @@ def service_present( else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Service "{}" will be added'.format(name) + ret["comment"] = f'Service "{name}" will be added' return ret # Create service __salt__["keystone.service_create"]( name, service_type, description, profile=profile, **connection_args ) - ret["comment"] = 'Service "{}" has been added'.format(name) + ret["comment"] = f'Service "{name}" has been added' ret["changes"]["Service"] = "Created" return ret @@ -662,7 +662,7 @@ def service_absent(name, profile=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": 'Service "{}" is already absent'.format(name), + "comment": f'Service "{name}" is already absent', } # Check if service is present @@ -672,13 +672,13 @@ def service_absent(name, profile=None, **connection_args): if "Error" not in role: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Service "{}" will be deleted'.format(name) + ret["comment"] = f'Service "{name}" will be deleted' return ret # Delete service __salt__["keystone.service_delete"]( name=name, profile=profile, **connection_args ) - ret["comment"] = 'Service "{}" has been deleted'.format(name) + ret["comment"] = f'Service "{name}" has been deleted' ret["changes"]["Service"] = "Deleted" return ret @@ -693,7 +693,7 @@ def endpoint_present( profile=None, url=None, interface=None, - **connection_args + **connection_args, ): """ Ensure the specified endpoints exists for service @@ -740,7 +740,7 @@ def endpoint_present( url=url, interface=interface, profile=profile, - **connection_args + **connection_args, ) else: ret["changes"] = __salt__["keystone.endpoint_create"]( @@ -750,7 +750,7 @@ def endpoint_present( adminurl=adminurl, internalurl=internalurl, profile=profile, - **connection_args + **connection_args, ) if endpoint and "Error" not in endpoint and endpoint.get("region") == region: @@ -844,20 +844,20 @@ def endpoint_present( name, region, profile=profile, interface=interface, **connection_args ) _create_endpoint() - ret["comment"] += 'Endpoint for service "{}" has been updated'.format(name) + ret["comment"] += f'Endpoint for service "{name}" has been updated' else: # Add new endpoint if __opts__.get("test"): ret["result"] = None ret["changes"]["Endpoint"] = "Will be created" - ret["comment"] = 'Endpoint for service "{}" will be added'.format(name) + ret["comment"] = f'Endpoint for service "{name}" will be added' return ret _create_endpoint() - ret["comment"] = 'Endpoint for service "{}" has been added'.format(name) + ret["comment"] = f'Endpoint for service "{name}" has been added' if ret["comment"] == "": # => no changes - ret["comment"] = 'Endpoint for service "{}" already exists'.format(name) + ret["comment"] = f'Endpoint for service "{name}" already exists' return ret @@ -881,7 +881,7 @@ def endpoint_absent(name, region=None, profile=None, interface=None, **connectio "result": True, "comment": 'Endpoint for service "{}"{} is already absent'.format( name, - ', interface "{}",'.format(interface) if interface is not None else "", + f', interface "{interface}",' if interface is not None else "", ), } @@ -894,7 +894,7 @@ def endpoint_absent(name, region=None, profile=None, interface=None, **connectio else: if __opts__.get("test"): ret["result"] = None - ret["comment"] = 'Endpoint for service "{}" will be deleted'.format(name) + ret["comment"] = f'Endpoint for service "{name}" will be deleted' return ret # Delete service __salt__["keystone.endpoint_delete"]( @@ -902,7 +902,7 @@ def endpoint_absent(name, region=None, profile=None, interface=None, **connectio ) ret["comment"] = 'Endpoint for service "{}"{} has been deleted'.format( name, - ', interface "{}",'.format(interface) if interface is not None else "", + f', interface "{interface}",' if interface is not None else "", ) ret["changes"]["endpoint"] = "Deleted" return ret diff --git a/salt/states/keystone_domain.py b/salt/states/keystone_domain.py index b8df63b9871..b722238ae73 100644 --- a/salt/states/keystone_domain.py +++ b/salt/states/keystone_domain.py @@ -26,7 +26,6 @@ Example States - name: domain1 """ - __virtualname__ = "keystone_domain" @@ -65,7 +64,7 @@ def present(name, auth=None, **kwargs): if __opts__["test"]: ret["result"] = None ret["changes"] = kwargs - ret["comment"] = "Domain {} will be created.".format(name) + ret["comment"] = f"Domain {name} will be created." return ret kwargs["name"] = name @@ -79,7 +78,7 @@ def present(name, auth=None, **kwargs): if __opts__["test"]: ret["result"] = None ret["changes"] = changes - ret["comment"] = "Domain {} will be updated.".format(name) + ret["comment"] = f"Domain {name} will be updated." return ret kwargs["domain_id"] = domain.id @@ -107,7 +106,7 @@ def absent(name, auth=None): if __opts__["test"] is True: ret["result"] = None ret["changes"] = {"name": name} - ret["comment"] = "Domain {} will be deleted.".format(name) + ret["comment"] = f"Domain {name} will be deleted." return ret __salt__["keystoneng.domain_delete"](name=domain) diff --git a/salt/states/keystone_endpoint.py b/salt/states/keystone_endpoint.py index 279c3be23f6..56b30d20d0a 100644 --- a/salt/states/keystone_endpoint.py +++ b/salt/states/keystone_endpoint.py @@ -36,7 +36,6 @@ Example States - service_name: glance """ - __virtualname__ = "keystone_endpoint" diff --git a/salt/states/keystone_group.py b/salt/states/keystone_group.py index ac6077a3f9a..678b5ebce83 100644 --- a/salt/states/keystone_group.py +++ b/salt/states/keystone_group.py @@ -26,7 +26,6 @@ Example States - description: 'my group' """ - __virtualname__ = "keystone_group" diff --git a/salt/states/keystone_project.py b/salt/states/keystone_project.py index b6db7cc2033..49d0b80f61f 100644 --- a/salt/states/keystone_project.py +++ b/salt/states/keystone_project.py @@ -27,7 +27,6 @@ Example States - description: 'my project' """ - __virtualname__ = "keystone_project" diff --git a/salt/states/keystone_role.py b/salt/states/keystone_role.py index 1cb938a4a51..3ca384bdbf4 100644 --- a/salt/states/keystone_role.py +++ b/salt/states/keystone_role.py @@ -25,7 +25,6 @@ Example States - description: 'my group' """ - __virtualname__ = "keystone_role" diff --git a/salt/states/keystone_role_grant.py b/salt/states/keystone_role_grant.py index edc17a1148c..d908cf93af5 100644 --- a/salt/states/keystone_role_grant.py +++ b/salt/states/keystone_role_grant.py @@ -26,7 +26,6 @@ Example States - description: 'my group' """ - __virtualname__ = "keystone_role_grant" diff --git a/salt/states/keystone_service.py b/salt/states/keystone_service.py index 988eae706e6..4a62e711465 100644 --- a/salt/states/keystone_service.py +++ b/salt/states/keystone_service.py @@ -28,7 +28,6 @@ Example States - description: 'OpenStack Image' """ - __virtualname__ = "keystone_service" diff --git a/salt/states/keystone_user.py b/salt/states/keystone_user.py index 8f9ec9f8c8d..527d71916ad 100644 --- a/salt/states/keystone_user.py +++ b/salt/states/keystone_user.py @@ -29,7 +29,6 @@ Example States - description: 'my user' """ - __virtualname__ = "keystone_user" diff --git a/salt/states/keystore.py b/salt/states/keystore.py index 5990c9d1e0c..9e6abb72769 100644 --- a/salt/states/keystore.py +++ b/salt/states/keystore.py @@ -2,7 +2,6 @@ State management of a java keystore """ - import logging import os @@ -147,12 +146,12 @@ def managed(name, passphrase, entries, force_remove=False): log.debug("Will remove: %s", remove_list) for alias_name in remove_list: if __opts__["test"]: - ret["comment"] += "Alias {} would have been removed".format(alias_name) + ret["comment"] += f"Alias {alias_name} would have been removed" ret["result"] = None else: __salt__["keystore.remove"](alias_name, name, passphrase) ret["changes"][alias_name] = "Removed" - ret["comment"] += "Alias {} removed.\n".format(alias_name) + ret["comment"] += f"Alias {alias_name} removed.\n" if not ret["changes"] and not ret["comment"]: ret["comment"] = "No changes made.\n" diff --git a/salt/states/kmod.py b/salt/states/kmod.py index 0bb257412f3..92b8cb8e7b7 100644 --- a/salt/states/kmod.py +++ b/salt/states/kmod.py @@ -84,7 +84,7 @@ def present(name, persist=False, mods=None): # Intersection of loaded and proposed modules already_loaded = list(set(loaded_mods) & set(mods)) if len(already_loaded) == 1: - comment = "Kernel module {} is already present".format(already_loaded[0]) + comment = f"Kernel module {already_loaded[0]} is already present" _append_comment(ret, comment) elif len(already_loaded) > 1: comment = "Kernel modules {} are already present".format( @@ -103,7 +103,7 @@ def present(name, persist=False, mods=None): if ret["comment"]: ret["comment"] += "\n" if len(not_loaded) == 1: - comment = "Kernel module {} is set to be loaded".format(not_loaded[0]) + comment = f"Kernel module {not_loaded[0]} is set to be loaded" else: comment = "Kernel modules {} are set to be loaded".format( ", ".join(not_loaded) @@ -115,7 +115,7 @@ def present(name, persist=False, mods=None): unavailable = list(set(not_loaded) - set(__salt__["kmod.available"]())) if unavailable: if len(unavailable) == 1: - comment = "Kernel module {} is unavailable".format(unavailable[0]) + comment = f"Kernel module {unavailable[0]} is unavailable" else: comment = "Kernel modules {} are unavailable".format(", ".join(unavailable)) _append_comment(ret, comment) @@ -161,7 +161,7 @@ def present(name, persist=False, mods=None): if loaded["failed"]: for mod, msg in loaded["failed"]: - _append_comment(ret, "Failed to load kernel module {}: {}".format(mod, msg)) + _append_comment(ret, f"Failed to load kernel module {mod}: {msg}") return ret @@ -205,7 +205,7 @@ def absent(name, persist=False, comment=True, mods=None): ret["result"] = None if len(to_unload) == 1: _append_comment( - ret, "Kernel module {} is set to be removed".format(to_unload[0]) + ret, f"Kernel module {to_unload[0]} is set to be removed" ) elif len(to_unload) > 1: _append_comment( @@ -252,15 +252,13 @@ def absent(name, persist=False, comment=True, mods=None): if unloaded["failed"]: for mod, msg in unloaded["failed"]: - _append_comment( - ret, "Failed to remove kernel module {}: {}".format(mod, msg) - ) + _append_comment(ret, f"Failed to remove kernel module {mod}: {msg}") return ret else: if len(mods) == 1: - ret["comment"] = "Kernel module {} is already removed".format(mods[0]) + ret["comment"] = f"Kernel module {mods[0]} is already removed" else: ret["comment"] = "Kernel modules {} are already removed".format( ", ".join(mods) diff --git a/salt/states/layman.py b/salt/states/layman.py index 00d65c458be..6a7a552f12a 100644 --- a/salt/states/layman.py +++ b/salt/states/layman.py @@ -31,15 +31,15 @@ def present(name): # Overlay already present if name in __salt__["layman.list_local"](): - ret["comment"] = "Overlay {} already present".format(name) + ret["comment"] = f"Overlay {name} already present" elif __opts__["test"]: - ret["comment"] = "Overlay {} is set to be added".format(name) + ret["comment"] = f"Overlay {name} is set to be added" ret["result"] = None return ret else: # Does the overlay exist? if name not in __salt__["layman.list_all"](): - ret["comment"] = "Overlay {} not found".format(name) + ret["comment"] = f"Overlay {name} not found" ret["result"] = False else: # Attempt to add the overlay @@ -47,12 +47,12 @@ def present(name): # The overlay failed to add if len(changes) < 1: - ret["comment"] = "Overlay {} failed to add".format(name) + ret["comment"] = f"Overlay {name} failed to add" ret["result"] = False # Success else: ret["changes"]["added"] = changes - ret["comment"] = "Overlay {} added.".format(name) + ret["comment"] = f"Overlay {name} added." return ret @@ -68,9 +68,9 @@ def absent(name): # Overlay is already absent if name not in __salt__["layman.list_local"](): - ret["comment"] = "Overlay {} already absent".format(name) + ret["comment"] = f"Overlay {name} already absent" elif __opts__["test"]: - ret["comment"] = "Overlay {} is set to be deleted".format(name) + ret["comment"] = f"Overlay {name} is set to be deleted" ret["result"] = None return ret else: @@ -79,11 +79,11 @@ def absent(name): # The overlay failed to delete if len(changes) < 1: - ret["comment"] = "Overlay {} failed to delete".format(name) + ret["comment"] = f"Overlay {name} failed to delete" ret["result"] = False # Success else: ret["changes"]["deleted"] = changes - ret["comment"] = "Overlay {} deleted.".format(name) + ret["comment"] = f"Overlay {name} deleted." return ret diff --git a/salt/states/libcloud_dns.py b/salt/states/libcloud_dns.py index a78a5d17dde..d9d6c41ff08 100644 --- a/salt/states/libcloud_dns.py +++ b/salt/states/libcloud_dns.py @@ -185,6 +185,6 @@ def record_absent(name, zone, type, data, profile): matching_zone["id"], record["id"], profile ) ) - return state_result(all(result), "Removed {} records".format(len(result)), name) + return state_result(all(result), f"Removed {len(result)} records", name) else: return state_result(True, "Records already absent", name) diff --git a/salt/states/libcloud_loadbalancer.py b/salt/states/libcloud_loadbalancer.py index c49ea093c1f..b10bb0b854c 100644 --- a/salt/states/libcloud_loadbalancer.py +++ b/salt/states/libcloud_loadbalancer.py @@ -45,7 +45,6 @@ Using States to deploy a load balancer with extended arguments to specify region :depends: apache-libcloud """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/libcloud_storage.py b/salt/states/libcloud_storage.py index a2a70f44389..641155f4cea 100644 --- a/salt/states/libcloud_storage.py +++ b/salt/states/libcloud_storage.py @@ -63,7 +63,6 @@ This example will download the file from the remote cloud and keep it locally :depends: apache-libcloud """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/linux_acl.py b/salt/states/linux_acl.py index 016af32a3e6..61429b592cf 100644 --- a/salt/states/linux_acl.py +++ b/salt/states/linux_acl.py @@ -81,7 +81,6 @@ Ensure a Linux ACL list does not exist """ - import logging import os diff --git a/salt/states/locale.py b/salt/states/locale.py index 23a8c8684f7..2fd35a4a29f 100644 --- a/salt/states/locale.py +++ b/salt/states/locale.py @@ -17,7 +17,6 @@ Manage the available locales and the system default: - locale: us_locale """ - from salt.exceptions import CommandExecutionError @@ -41,23 +40,23 @@ def system(name): try: if __salt__["locale.get_locale"]() == name: ret["result"] = True - ret["comment"] = "System locale {} already set".format(name) + ret["comment"] = f"System locale {name} already set" return ret if __opts__["test"]: - ret["comment"] = "System locale {} needs to be set".format(name) + ret["comment"] = f"System locale {name} needs to be set" return ret if __salt__["locale.set_locale"](name): ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Set system locale {}".format(name) + ret["comment"] = f"Set system locale {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to set system locale to {}".format(name) + ret["comment"] = f"Failed to set system locale to {name}" return ret except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Failed to set system locale: {}".format(err) + ret["comment"] = f"Failed to set system locale: {err}" return ret @@ -74,17 +73,17 @@ def present(name): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["locale.avail"](name): ret["result"] = True - ret["comment"] = "Locale {} is already present".format(name) + ret["comment"] = f"Locale {name} is already present" return ret if __opts__["test"]: - ret["comment"] = "Locale {} needs to be generated".format(name) + ret["comment"] = f"Locale {name} needs to be generated" return ret if __salt__["locale.gen_locale"](name): ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Generated locale {}".format(name) + ret["comment"] = f"Generated locale {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to generate locale {}".format(name) + ret["comment"] = f"Failed to generate locale {name}" return ret diff --git a/salt/states/logrotate.py b/salt/states/logrotate.py index fcac9f20ff3..d65d2ce28ac 100644 --- a/salt/states/logrotate.py +++ b/salt/states/logrotate.py @@ -5,7 +5,6 @@ Module for managing logrotate. """ - _DEFAULT_CONF = "/etc/logrotate.conf" # Define the module's virtual name @@ -85,10 +84,10 @@ def set_(name, key, value, setting=None, conf_file=_DEFAULT_CONF): value = _convert_if_int(value) if current_value == value: - ret["comment"] = "Command '{}' already has value: {}".format(key, value) + ret["comment"] = f"Command '{key}' already has value: {value}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Command '{}' will be set to value: {}".format(key, value) + ret["comment"] = f"Command '{key}' will be set to value: {value}" ret["changes"] = {"old": current_value, "new": value} else: ret["changes"] = {"old": current_value, "new": value} @@ -96,7 +95,7 @@ def set_(name, key, value, setting=None, conf_file=_DEFAULT_CONF): key=key, value=value, conf_file=conf_file ) if ret["result"]: - ret["comment"] = "Set command '{}' value: {}".format(key, value) + ret["comment"] = f"Set command '{key}' value: {value}" else: ret["comment"] = "Unable to set command '{}' value: {}".format( key, value diff --git a/salt/states/loop.py b/salt/states/loop.py index 6b787393858..a2434daeff2 100644 --- a/salt/states/loop.py +++ b/salt/states/loop.py @@ -57,7 +57,6 @@ The function :py:func:`data.subdict_match ` check instances: "{{ instance }}" """ - import logging import operator import sys @@ -96,7 +95,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60 m_kwargs = {} if name not in __salt__: - ret["comment"] = "Cannot find module {}".format(name) + ret["comment"] = f"Cannot find module {name}" elif condition is None: ret["comment"] = "An exit condition must be specified" elif not isinstance(period, (int, float)): @@ -104,7 +103,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60 elif not isinstance(timeout, (int, float)): ret["comment"] = "Timeout must be specified as a float in seconds" elif __opts__["test"]: - ret["comment"] = "The execution module {} will be run".format(name) + ret["comment"] = f"The execution module {name} will be run" ret["result"] = None else: if m_args is None: @@ -117,7 +116,7 @@ def until(name, m_args=None, m_kwargs=None, condition=None, period=1, timeout=60 m_ret = __salt__[name](*m_args, **m_kwargs) if eval(condition): # pylint: disable=W0123 ret["result"] = True - ret["comment"] = "Condition {} was met".format(condition) + ret["comment"] = f"Condition {condition} was met" break time.sleep(period) else: @@ -162,7 +161,7 @@ def until_no_eval( """ ret = {"name": name, "comment": "", "changes": {}, "result": False} if name not in __salt__: - ret["comment"] = 'Module.function "{}" is unavailable.'.format(name) + ret["comment"] = f'Module.function "{name}" is unavailable.' elif not isinstance(period, (int, float)): ret["comment"] = "Period must be specified as a float in seconds" elif not isinstance(timeout, (int, float)): @@ -172,7 +171,7 @@ def until_no_eval( elif compare_operator in __utils__: comparator = __utils__[compare_operator] elif not hasattr(operator, compare_operator): - ret["comment"] = 'Invalid operator "{}" supplied.'.format(compare_operator) + ret["comment"] = f'Invalid operator "{compare_operator}" supplied.' else: comparator = getattr(operator, compare_operator) if __opts__["test"]: @@ -222,10 +221,10 @@ def until_no_eval( break time.sleep(period) else: - ret[ - "comment" - ] = "Call did not produce the expected result after {} attempts".format( - current_attempt + ret["comment"] = ( + "Call did not produce the expected result after {} attempts".format( + current_attempt + ) ) log.debug( "%s:until_no_eval:\n\t\tResults of all attempts: %s", diff --git a/salt/states/lvm.py b/salt/states/lvm.py index 82c9fa6015b..5b4bdad8696 100644 --- a/salt/states/lvm.py +++ b/salt/states/lvm.py @@ -342,18 +342,18 @@ def lv_present( else: # ignore percentage "extents" if the logical volume already exists if "%" in str(extents): - ret[ - "comment" - ] = "Logical Volume {} already present, {} won't be resized.".format( - name, extents + ret["comment"] = ( + "Logical Volume {} already present, {} won't be resized.".format( + name, extents + ) ) extents = old_extents size_mb = old_size_mb if force is False and (size_mb < old_size_mb or extents < old_extents): - ret[ - "comment" - ] = "To reduce a Logical Volume option 'force' must be True." + ret["comment"] = ( + "To reduce a Logical Volume option 'force' must be True." + ) ret["result"] = False return ret @@ -378,9 +378,9 @@ def lv_present( ) if not changes: - ret[ - "comment" - ] = "Failed to resize Logical Volume. Unknown Error." + ret["comment"] = ( + "Failed to resize Logical Volume. Unknown Error." + ) ret["result"] = False lv_info = __salt__["lvm.lvdisplay"](lvpath, quiet=True)[lvpath] @@ -389,10 +389,10 @@ def lv_present( ret["comment"] = f"Resized Logical Volume {name}" ret["changes"]["resized"] = changes else: - ret[ - "comment" - ] = "Failed to resize Logical Volume {}.\nError: {}".format( - name, changes["Output from lvresize"] + ret["comment"] = ( + "Failed to resize Logical Volume {}.\nError: {}".format( + name, changes["Output from lvresize"] + ) ) ret["result"] = False return ret diff --git a/salt/states/lvs_server.py b/salt/states/lvs_server.py index 1c0eb81fb69..4d86848b9de 100644 --- a/salt/states/lvs_server.py +++ b/salt/states/lvs_server.py @@ -91,27 +91,27 @@ def present( weight=weight, ) if server_edit is True: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) has been updated".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) has been updated".format( + name, service_address, protocol + ) ) ret["changes"][name] = "Update" return ret else: ret["result"] = False - ret[ - "comment" - ] = "LVS Server {} in service {}({}) update failed({})".format( - name, service_address, protocol, server_edit + ret["comment"] = ( + "LVS Server {} in service {}({}) update failed({})".format( + name, service_address, protocol, server_edit + ) ) return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) is not present and needs to be created".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) is not present and needs to be created".format( + name, service_address, protocol + ) ) ret["result"] = None return ret @@ -124,18 +124,18 @@ def present( weight=weight, ) if server_add is True: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) has been created".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) has been created".format( + name, service_address, protocol + ) ) ret["changes"][name] = "Present" return ret else: - ret[ - "comment" - ] = "LVS Service {} in service {}({}) create failed({})".format( - name, service_address, protocol, server_add + ret["comment"] = ( + "LVS Service {} in service {}({}) create failed({})".format( + name, service_address, protocol, server_add + ) ) ret["result"] = False return ret @@ -168,10 +168,10 @@ def absent(name, protocol=None, service_address=None, server_address=None): if server_check is True: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "LVS Server {} in service {}({}) is present and needs to be removed".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) is present and needs to be removed".format( + name, service_address, protocol + ) ) return ret server_delete = __salt__["lvs.delete_server"]( @@ -186,18 +186,18 @@ def absent(name, protocol=None, service_address=None, server_address=None): ret["changes"][name] = "Absent" return ret else: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) removed failed({})".format( - name, service_address, protocol, server_delete + ret["comment"] = ( + "LVS Server {} in service {}({}) removed failed({})".format( + name, service_address, protocol, server_delete + ) ) ret["result"] = False return ret else: - ret[ - "comment" - ] = "LVS Server {} in service {}({}) is not present, so it cannot be removed".format( - name, service_address, protocol + ret["comment"] = ( + "LVS Server {} in service {}({}) is not present, so it cannot be removed".format( + name, service_address, protocol + ) ) return ret diff --git a/salt/states/lvs_service.py b/salt/states/lvs_service.py index 4e12c321773..5a1981d4426 100644 --- a/salt/states/lvs_service.py +++ b/salt/states/lvs_service.py @@ -53,15 +53,15 @@ def present( protocol=protocol, service_address=service_address, scheduler=scheduler ) if service_rule_check is True: - ret["comment"] = "LVS Service {} is present".format(name) + ret["comment"] = f"LVS Service {name} is present" return ret else: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "LVS Service {} is present but some options should update".format( - name + ret["comment"] = ( + "LVS Service {} is present but some options should update".format( + name + ) ) return ret else: @@ -71,18 +71,18 @@ def present( scheduler=scheduler, ) if service_edit is True: - ret["comment"] = "LVS Service {} has been updated".format(name) + ret["comment"] = f"LVS Service {name} has been updated" ret["changes"][name] = "Update" return ret else: ret["result"] = False - ret["comment"] = "LVS Service {} update failed".format(name) + ret["comment"] = f"LVS Service {name} update failed" return ret else: if __opts__["test"]: - ret[ - "comment" - ] = "LVS Service {} is not present and needs to be created".format(name) + ret["comment"] = ( + f"LVS Service {name} is not present and needs to be created" + ) ret["result"] = None return ret else: @@ -90,7 +90,7 @@ def present( protocol=protocol, service_address=service_address, scheduler=scheduler ) if service_add is True: - ret["comment"] = "LVS Service {} has been created".format(name) + ret["comment"] = f"LVS Service {name} has been created" ret["changes"][name] = "Present" return ret else: @@ -131,7 +131,7 @@ def absent(name, protocol=None, service_address=None): protocol=protocol, service_address=service_address ) if service_delete is True: - ret["comment"] = "LVS Service {} has been removed".format(name) + ret["comment"] = f"LVS Service {name} has been removed" ret["changes"][name] = "Absent" return ret else: @@ -141,8 +141,6 @@ def absent(name, protocol=None, service_address=None): ret["result"] = False return ret else: - ret[ - "comment" - ] = "LVS Service {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"LVS Service {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/lxc.py b/salt/states/lxc.py index 51dae0b92c6..05b7081d122 100644 --- a/salt/states/lxc.py +++ b/salt/states/lxc.py @@ -3,7 +3,6 @@ Manage Linux Containers ======================= """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" @@ -151,7 +150,7 @@ def present( ret = { "name": name, "result": True, - "comment": "Container '{}' already exists".format(name), + "comment": f"Container '{name}' already exists", "changes": {}, } @@ -179,17 +178,17 @@ def present( # Sanity check(s) if clone_from and not __salt__["lxc.exists"](clone_from, path=path): ret["result"] = False - ret["comment"] = "Clone source '{}' does not exist".format(clone_from) + ret["comment"] = f"Clone source '{clone_from}' does not exist" if not ret["result"]: return ret - action = "cloned from {}".format(clone_from) if clone_from else "created" + action = f"cloned from {clone_from}" if clone_from else "created" state = {"old": __salt__["lxc.state"](name, path=path)} if __opts__["test"]: if state["old"] is None: ret["comment"] = "Container '{}' will be {}".format( - name, "cloned from {}".format(clone_from) if clone_from else "created" + name, f"cloned from {clone_from}" if clone_from else "created" ) ret["result"] = None return ret @@ -210,7 +209,7 @@ def present( return ret else: if state["old"] in ("frozen", "running"): - ret["comment"] = "Container '{}' would be stopped".format(name) + ret["comment"] = f"Container '{name}' would be stopped" ret["result"] = None return ret else: @@ -257,7 +256,7 @@ def present( clone_from, name ) else: - ret["comment"] = "Created container '{}'".format(name) + ret["comment"] = f"Created container '{name}'" state["new"] = result["state"]["new"] if ret["result"] is True: @@ -279,7 +278,7 @@ def present( ret["comment"] += error except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret["comment"] += "{}: {}".format(error, exc) + ret["comment"] += f"{error}: {exc}" else: if state["old"] is None: ret["comment"] += ", and the container was started" @@ -302,12 +301,12 @@ def present( ret["comment"] += error except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret["comment"] += "{}: {}".format(error, exc) + ret["comment"] += f"{error}: {exc}" else: if state["old"] is None: ret["comment"] += ", and the container was stopped" else: - ret["comment"] = "Container '{}' was stopped".format(name) + ret["comment"] = f"Container '{name}' was stopped" if "new" not in state: # Make sure we know the final state of the container before we return @@ -346,7 +345,7 @@ def absent(name, stop=False, path=None): "name": name, "changes": {}, "result": True, - "comment": "Container '{}' does not exist".format(name), + "comment": f"Container '{name}' does not exist", } if not __salt__["lxc.exists"](name, path=path): @@ -354,17 +353,17 @@ def absent(name, stop=False, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be destroyed".format(name) + ret["comment"] = f"Container '{name}' would be destroyed" return ret try: result = __salt__["lxc.destroy"](name, stop=stop, path=path) except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret["comment"] = "Failed to destroy container: {}".format(exc) + ret["comment"] = f"Failed to destroy container: {exc}" else: ret["changes"]["state"] = result["state"] - ret["comment"] = "Container '{}' was destroyed".format(name) + ret["comment"] = f"Container '{name}' was destroyed" return ret @@ -408,14 +407,14 @@ def running(name, restart=False, path=None): ret = { "name": name, "result": True, - "comment": "Container '{}' is already running".format(name), + "comment": f"Container '{name}' is already running", "changes": {}, } state = {"old": __salt__["lxc.state"](name, path=path)} if state["old"] is None: ret["result"] = False - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" return ret elif state["old"] == "running" and not restart: return ret @@ -436,7 +435,7 @@ def running(name, restart=False, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be {}".format(name, action[1]) + ret["comment"] = f"Container '{name}' would be {action[1]}" return ret try: @@ -455,7 +454,7 @@ def running(name, restart=False, path=None): state["new"] = result["state"]["new"] if state["new"] != "running": ret["result"] = False - ret["comment"] = "Unable to {} container '{}'".format(action[0], name) + ret["comment"] = f"Unable to {action[0]} container '{name}'" else: ret["comment"] = "Container '{}' was successfully {}".format( name, action[1] @@ -508,17 +507,17 @@ def frozen(name, start=True, path=None): ret = { "name": name, "result": True, - "comment": "Container '{}' is already frozen".format(name), + "comment": f"Container '{name}' is already frozen", "changes": {}, } state = {"old": __salt__["lxc.state"](name, path=path)} if state["old"] is None: ret["result"] = False - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" elif state["old"] == "stopped" and not start: ret["result"] = False - ret["comment"] = "Container '{}' is stopped".format(name) + ret["comment"] = f"Container '{name}' is stopped" if ret["result"] is False or state["old"] == "frozen": return ret @@ -530,7 +529,7 @@ def frozen(name, start=True, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be {}".format(name, action[1]) + ret["comment"] = f"Container '{name}' would be {action[1]}" return ret try: @@ -543,7 +542,7 @@ def frozen(name, start=True, path=None): state["new"] = result["state"]["new"] if state["new"] != "frozen": ret["result"] = False - ret["comment"] = "Unable to {} container '{}'".format(action[0], name) + ret["comment"] = f"Unable to {action[0]} container '{name}'" else: ret["comment"] = "Container '{}' was successfully {}".format( name, action[1] @@ -595,14 +594,14 @@ def stopped(name, kill=False, path=None): ret = { "name": name, "result": True, - "comment": "Container '{}' is already stopped".format(name), + "comment": f"Container '{name}' is already stopped", "changes": {}, } state = {"old": __salt__["lxc.state"](name, path=path)} if state["old"] is None: ret["result"] = False - ret["comment"] = "Container '{}' does not exist".format(name) + ret["comment"] = f"Container '{name}' does not exist" return ret elif state["old"] == "stopped": return ret @@ -614,7 +613,7 @@ def stopped(name, kill=False, path=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Container '{}' would be {}".format(name, action[1]) + ret["comment"] = f"Container '{name}' would be {action[1]}" return ret try: @@ -627,7 +626,7 @@ def stopped(name, kill=False, path=None): state["new"] = result["state"]["new"] if state["new"] != "stopped": ret["result"] = False - ret["comment"] = "Unable to {} container '{}'".format(action[0], name) + ret["comment"] = f"Unable to {action[0]} container '{name}'" else: ret["comment"] = "Container '{}' was successfully {}".format( name, action[1] @@ -708,7 +707,7 @@ def edited_conf(name, lxc_conf=None, lxc_conf_unset=None): if __opts__["test"]: return { "name": name, - "comment": "{} lxc.conf will be edited".format(name), + "comment": f"{name} lxc.conf will be edited", "result": True, "changes": {}, } diff --git a/salt/states/lxd.py b/salt/states/lxd.py index e5ddbf382af..35b87ea8371 100644 --- a/salt/states/lxd.py +++ b/salt/states/lxd.py @@ -27,7 +27,6 @@ Manage LXD profiles. :platform: Linux """ - import os.path from salt.exceptions import CommandExecutionError, SaltInvocationError @@ -173,7 +172,7 @@ def config_managed(name, value, force_password=False): ) elif str(value) == current_value: - return _success(ret, '"{}" is already set to "{}"'.format(name, value)) + return _success(ret, f'"{name}" is already set to "{value}"') if __opts__["test"]: if name == _password_config_key: @@ -181,7 +180,7 @@ def config_managed(name, value, force_password=False): ret["changes"] = {"password": msg} return _unchanged(ret, msg) else: - msg = 'Would set the "{}" to "{}"'.format(name, value) + msg = f'Would set the "{name}" to "{value}"' ret["changes"] = {name: msg} return _unchanged(ret, msg) @@ -191,9 +190,7 @@ def config_managed(name, value, force_password=False): if name == _password_config_key: ret["changes"] = {name: "Changed the password"} else: - ret["changes"] = { - name: 'Changed from "{}" to {}"'.format(current_value, value) - } + ret["changes"] = {name: f'Changed from "{current_value}" to {value}"'} except CommandExecutionError as e: return _error(ret, str(e)) @@ -266,9 +263,9 @@ def authenticate(name, remote_addr, password, cert, key, verify_cert=True): return _error(ret, str(e)) if result is not True: - return _error(ret, "Failed to authenticate with peer: {}".format(remote_addr)) + return _error(ret, f"Failed to authenticate with peer: {remote_addr}") - msg = "Successfully authenticated with peer: {}".format(remote_addr) + msg = f"Successfully authenticated with peer: {remote_addr}" ret["changes"] = msg return _success(ret, msg) diff --git a/salt/states/lxd_container.py b/salt/states/lxd_container.py index 014c0265522..a1f894c6ac5 100644 --- a/salt/states/lxd_container.py +++ b/salt/states/lxd_container.py @@ -27,7 +27,6 @@ Manage LXD containers. :platform: Linux """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" @@ -219,7 +218,7 @@ def present( if container is None: if __opts__["test"]: # Test is on, just return that we would create the container - msg = 'Would create the container "{}"'.format(name) + msg = f'Would create the container "{name}"' ret["changes"] = {"created": msg} if running is True: msg = msg + " and start it." @@ -249,7 +248,7 @@ def present( except CommandExecutionError as e: return _error(ret, str(e)) - msg = 'Created the container "{}"'.format(name) + msg = f'Created the container "{name}"' ret["changes"] = {"created": msg} if running is True: @@ -261,7 +260,7 @@ def present( return _error(ret, str(e)) msg = msg + " and started it." - ret["changes"] = {"started": 'Started the container "{}"'.format(name)} + ret["changes"] = {"started": f'Started the container "{name}"'} return _success(ret, msg) @@ -275,18 +274,18 @@ def present( # Removed profiles for k in old_profiles.difference(new_profiles): if not __opts__["test"]: - profile_changes.append('Removed profile "{}"'.format(k)) + profile_changes.append(f'Removed profile "{k}"') old_profiles.discard(k) else: - profile_changes.append('Would remove profile "{}"'.format(k)) + profile_changes.append(f'Would remove profile "{k}"') # Added profiles for k in new_profiles.difference(old_profiles): if not __opts__["test"]: - profile_changes.append('Added profile "{}"'.format(k)) + profile_changes.append(f'Added profile "{k}"') old_profiles.add(k) else: - profile_changes.append('Would add profile "{}"'.format(k)) + profile_changes.append(f'Would add profile "{k}"') if profile_changes: container_changed = True @@ -316,7 +315,7 @@ def present( changes["running"] = "Would start the container" return _unchanged( ret, - 'Container "{}" would get changed and started.'.format(name), + f'Container "{name}" would get changed and started.', ) else: container.start(wait=True) @@ -327,7 +326,7 @@ def present( changes["stopped"] = "Would stopped the container" return _unchanged( ret, - 'Container "{}" would get changed and stopped.'.format(name), + f'Container "{name}" would get changed and stopped.', ) else: container.stop(wait=True) @@ -342,17 +341,17 @@ def present( if __opts__["test"]: changes["restarted"] = "Would restart the container" - return _unchanged(ret, 'Would restart the container "{}"'.format(name)) + return _unchanged(ret, f'Would restart the container "{name}"') else: container.restart(wait=True) - changes["restarted"] = 'Container "{}" has been restarted'.format(name) - return _success(ret, 'Container "{}" has been restarted'.format(name)) + changes["restarted"] = f'Container "{name}" has been restarted' + return _success(ret, f'Container "{name}" has been restarted') if not container_changed: return _success(ret, "No changes") if __opts__["test"]: - return _unchanged(ret, 'Container "{}" would get changed.'.format(name)) + return _unchanged(ret, f'Container "{name}" would get changed.') return _success(ret, "{} changes".format(len(ret["changes"].keys()))) @@ -411,10 +410,10 @@ def absent(name, stop=False, remote_addr=None, cert=None, key=None, verify_cert= return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _success(ret, 'Container "{}" not found.'.format(name)) + return _success(ret, f'Container "{name}" not found.') if __opts__["test"]: - ret["changes"] = {"removed": 'Container "{}" would get deleted.'.format(name)} + ret["changes"] = {"removed": f'Container "{name}" would get deleted.'} return _unchanged(ret, ret["changes"]["removed"]) if stop and container.status_code == CONTAINER_STATUS_RUNNING: @@ -422,7 +421,7 @@ def absent(name, stop=False, remote_addr=None, cert=None, key=None, verify_cert= container.delete(wait=True) - ret["changes"]["deleted"] = 'Container "{}" has been deleted.'.format(name) + ret["changes"]["deleted"] = f'Container "{name}" has been deleted.' return _success(ret, ret["changes"]["deleted"]) @@ -481,13 +480,13 @@ def running( return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Container "{}" not found'.format(name)) + return _error(ret, f'Container "{name}" not found') is_running = container.status_code == CONTAINER_STATUS_RUNNING if is_running: if not restart: - return _success(ret, 'The container "{}" is already running'.format(name)) + return _success(ret, f'The container "{name}" is already running') else: if __opts__["test"]: ret["changes"]["restarted"] = 'Would restart the container "{}"'.format( @@ -502,11 +501,11 @@ def running( return _success(ret, ret["changes"]["restarted"]) if __opts__["test"]: - ret["changes"]["started"] = 'Would start the container "{}"'.format(name) + ret["changes"]["started"] = f'Would start the container "{name}"' return _unchanged(ret, ret["changes"]["started"]) container.start(wait=True) - ret["changes"]["started"] = 'Started the container "{}"'.format(name) + ret["changes"]["started"] = f'Started the container "{name}"' return _success(ret, ret["changes"]["started"]) @@ -563,10 +562,10 @@ def frozen(name, start=True, remote_addr=None, cert=None, key=None, verify_cert= return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Container "{}" not found'.format(name)) + return _error(ret, f'Container "{name}" not found') if container.status_code == CONTAINER_STATUS_FROZEN: - return _success(ret, 'Container "{}" is alredy frozen'.format(name)) + return _success(ret, f'Container "{name}" is alredy frozen') is_running = container.status_code == CONTAINER_STATUS_RUNNING @@ -582,18 +581,18 @@ def frozen(name, start=True, remote_addr=None, cert=None, key=None, verify_cert= if __opts__["test"]: ret["changes"][ "started" - ] = 'Would start the container "{}" and freeze it after'.format(name) + ] = f'Would start the container "{name}" and freeze it after' return _unchanged(ret, ret["changes"]["started"]) else: container.start(wait=True) - ret["changes"]["started"] = 'Start the container "{}"'.format(name) + ret["changes"]["started"] = f'Start the container "{name}"' if __opts__["test"]: - ret["changes"]["frozen"] = 'Would freeze the container "{}"'.format(name) + ret["changes"]["frozen"] = f'Would freeze the container "{name}"' return _unchanged(ret, ret["changes"]["frozen"]) container.freeze(wait=True) - ret["changes"]["frozen"] = 'Froze the container "{}"'.format(name) + ret["changes"]["frozen"] = f'Froze the container "{name}"' return _success(ret, ret["changes"]["frozen"]) @@ -651,17 +650,17 @@ def stopped(name, kill=False, remote_addr=None, cert=None, key=None, verify_cert return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Container "{}" not found'.format(name)) + return _error(ret, f'Container "{name}" not found') if container.status_code == CONTAINER_STATUS_STOPPED: - return _success(ret, 'Container "{}" is already stopped'.format(name)) + return _success(ret, f'Container "{name}" is already stopped') if __opts__["test"]: - ret["changes"]["stopped"] = 'Would stop the container "{}"'.format(name) + ret["changes"]["stopped"] = f'Would stop the container "{name}"' return _unchanged(ret, ret["changes"]["stopped"]) container.stop(force=kill, wait=True) - ret["changes"]["stopped"] = 'Stopped the container "{}"'.format(name) + ret["changes"]["stopped"] = f'Stopped the container "{name}"' return _success(ret, ret["changes"]["stopped"]) @@ -764,7 +763,7 @@ def migrated( pass if dest_container is not None: - return _success(ret, 'Container "{}" exists on the destination'.format(name)) + return _success(ret, f'Container "{name}" exists on the destination') if src_verify_cert is None: src_verify_cert = verify_cert @@ -777,13 +776,13 @@ def migrated( return _error(ret, str(e)) except SaltInvocationError as e: # Container not found - return _error(ret, 'Source Container "{}" not found'.format(name)) + return _error(ret, f'Source Container "{name}" not found') if __opts__["test"]: - ret["changes"][ - "migrated" - ] = 'Would migrate the container "{}" from "{}" to "{}"'.format( - name, src_remote_addr, remote_addr + ret["changes"]["migrated"] = ( + 'Would migrate the container "{}" from "{}" to "{}"'.format( + name, src_remote_addr, remote_addr + ) ) return _unchanged(ret, ret["changes"]["migrated"]) diff --git a/salt/states/lxd_image.py b/salt/states/lxd_image.py index c6d554ee284..923726e7b26 100644 --- a/salt/states/lxd_image.py +++ b/salt/states/lxd_image.py @@ -28,7 +28,6 @@ Manage LXD images. :platform: Linux """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" @@ -181,7 +180,7 @@ def present( if image is None: if __opts__["test"]: # Test is on, just return that we would create the image - msg = 'Would create the image "{}"'.format(name) + msg = f'Would create the image "{name}"' ret["changes"] = {"created": msg} return _unchanged(ret, msg) @@ -259,17 +258,17 @@ def present( for k in old_aliases.difference(new_aliases): if not __opts__["test"]: __salt__["lxd.image_alias_delete"](image, k) - alias_changes.append('Removed alias "{}"'.format(k)) + alias_changes.append(f'Removed alias "{k}"') else: - alias_changes.append('Would remove alias "{}"'.format(k)) + alias_changes.append(f'Would remove alias "{k}"') # New aliases for k in new_aliases.difference(old_aliases): if not __opts__["test"]: __salt__["lxd.image_alias_add"](image, k, "") - alias_changes.append('Added alias "{}"'.format(k)) + alias_changes.append(f'Added alias "{k}"') else: - alias_changes.append('Would add alias "{}"'.format(k)) + alias_changes.append(f'Would add alias "{k}"') if alias_changes: ret["changes"]["aliases"] = alias_changes @@ -277,11 +276,11 @@ def present( # Set public if public is not None and image.public != public: if not __opts__["test"]: - ret["changes"]["public"] = "Setting the image public to {!s}".format(public) + ret["changes"]["public"] = f"Setting the image public to {public!s}" image.public = public __salt__["lxd.pylxd_save_object"](image) else: - ret["changes"]["public"] = "Would set public to {!s}".format(public) + ret["changes"]["public"] = f"Would set public to {public!s}" if __opts__["test"] and ret["changes"]: return _unchanged(ret, "Would do {} changes".format(len(ret["changes"].keys()))) @@ -342,15 +341,15 @@ def absent(name, remote_addr=None, cert=None, key=None, verify_cert=True): except CommandExecutionError as e: return _error(ret, str(e)) except SaltInvocationError as e: - return _success(ret, 'Image "{}" not found.'.format(name)) + return _success(ret, f'Image "{name}" not found.') if __opts__["test"]: - ret["changes"] = {"removed": 'Image "{}" would get deleted.'.format(name)} + ret["changes"] = {"removed": f'Image "{name}" would get deleted.'} return _success(ret, ret["changes"]["removed"]) __salt__["lxd.image_delete"](image) - ret["changes"] = {"removed": 'Image "{}" has been deleted.'.format(name)} + ret["changes"] = {"removed": f'Image "{name}" has been deleted.'} return _success(ret, ret["changes"]["removed"]) diff --git a/salt/states/lxd_profile.py b/salt/states/lxd_profile.py index a4a0176ad39..a699252b4d7 100644 --- a/salt/states/lxd_profile.py +++ b/salt/states/lxd_profile.py @@ -27,7 +27,6 @@ Manage LXD profiles. :platform: Linux """ - from salt.exceptions import CommandExecutionError, SaltInvocationError __docformat__ = "restructuredtext en" @@ -133,7 +132,7 @@ def present( if profile is None: if __opts__["test"]: # Test is on, just return that we would create the profile - msg = 'Would create the profile "{}"'.format(name) + msg = f'Would create the profile "{name}"' ret["changes"] = {"created": msg} return _unchanged(ret, msg) @@ -146,7 +145,7 @@ def present( except CommandExecutionError as e: return _error(ret, str(e)) - msg = 'Profile "{}" has been created'.format(name) + msg = f'Profile "{name}" has been created' ret["changes"] = {"created": msg} return _success(ret, msg) @@ -156,10 +155,10 @@ def present( # Description change # if str(profile.description) != str(description): - ret["changes"][ - "description" - ] = 'Description changed, from "{}" to "{}".'.format( - profile.description, description + ret["changes"]["description"] = ( + 'Description changed, from "{}" to "{}".'.format( + profile.description, description + ) ) profile.description = description @@ -173,7 +172,7 @@ def present( return _success(ret, "No changes") if __opts__["test"]: - return _unchanged(ret, 'Profile "{}" would get changed.'.format(name)) + return _unchanged(ret, f'Profile "{name}" would get changed.') try: __salt__["lxd.pylxd_save_object"](profile) @@ -234,9 +233,9 @@ def absent(name, remote_addr=None, cert=None, key=None, verify_cert=True): return _error(ret, str(e)) except SaltInvocationError as e: # Profile not found - return _success(ret, 'Profile "{}" not found.'.format(name)) + return _success(ret, f'Profile "{name}" not found.') - ret["changes"] = {"removed": 'Profile "{}" would get deleted.'.format(name)} + ret["changes"] = {"removed": f'Profile "{name}" would get deleted.'} return _success(ret, ret["changes"]["removed"]) try: @@ -245,9 +244,9 @@ def absent(name, remote_addr=None, cert=None, key=None, verify_cert=True): return _error(ret, str(e)) except SaltInvocationError as e: # Profile not found - return _success(ret, 'Profile "{}" not found.'.format(name)) + return _success(ret, f'Profile "{name}" not found.') - ret["changes"] = {"removed": 'Profile "{}" has been deleted.'.format(name)} + ret["changes"] = {"removed": f'Profile "{name}" has been deleted.'} return _success(ret, ret["changes"]["removed"]) diff --git a/salt/states/mac_assistive.py b/salt/states/mac_assistive.py index 8aee4ccffec..ad0de154452 100644 --- a/salt/states/mac_assistive.py +++ b/salt/states/mac_assistive.py @@ -53,12 +53,12 @@ def installed(name, enabled=True): if enabled != is_enabled: __salt__["assistive.enable"](name, enabled) - ret["comment"] = "Updated enable to {}".format(enabled) + ret["comment"] = f"Updated enable to {enabled}" else: ret["comment"] = "Already in the correct state" else: __salt__["assistive.install"](name, enabled) - ret["comment"] = "Installed {} into the assistive access panel".format(name) + ret["comment"] = f"Installed {name} into the assistive access panel" return ret diff --git a/salt/states/mac_keychain.py b/salt/states/mac_keychain.py index 7126a95b01c..fd1af09623b 100644 --- a/salt/states/mac_keychain.py +++ b/salt/states/mac_keychain.py @@ -95,9 +95,9 @@ def installed(name, password, keychain="/Library/Keychains/System.keychain", **k ret["changes"]["installed"] = friendly_name else: ret["result"] = False - ret["comment"] += "Failed to install {}".format(friendly_name) + ret["comment"] += f"Failed to install {friendly_name}" else: - ret["comment"] += "{} already installed.".format(friendly_name) + ret["comment"] += f"{friendly_name} already installed." return ret @@ -150,9 +150,9 @@ def uninstalled( ret["changes"]["uninstalled"] = friendly_name else: ret["result"] = False - ret["comment"] += "Failed to uninstall {}".format(friendly_name) + ret["comment"] += f"Failed to uninstall {friendly_name}" else: - ret["comment"] += "{} already uninstalled.".format(friendly_name) + ret["comment"] += f"{friendly_name} already uninstalled." return ret @@ -175,18 +175,18 @@ def default_keychain(name, domain="user", user=None): if not os.path.exists(name): ret["result"] = False - ret["comment"] += "Keychain not found at {}".format(name) + ret["comment"] += f"Keychain not found at {name}" else: out = __salt__["keychain.get_default_keychain"](user, domain) if name in out: - ret["comment"] += "{} was already the default keychain.".format(name) + ret["comment"] += f"{name} was already the default keychain." else: out = __salt__["keychain.set_default_keychain"](name, domain, user) if len(out) == 0: ret["changes"]["default"] = name else: ret["result"] = False - ret["comment"] = "Failed to install keychain. {}".format(out) + ret["comment"] = f"Failed to install keychain. {out}" return ret diff --git a/salt/states/macdefaults.py b/salt/states/macdefaults.py index 67383eaffcd..05e83c2a4d6 100644 --- a/salt/states/macdefaults.py +++ b/salt/states/macdefaults.py @@ -58,20 +58,20 @@ def write(name, domain, value, vtype="string", user=None): (value in [True, "TRUE", "YES"] and current_value == "1") or (value in [False, "FALSE", "NO"] and current_value == "0") ): - ret["comment"] += "{} {} is already set to {}".format(domain, name, value) + ret["comment"] += f"{domain} {name} is already set to {value}" elif vtype in ["int", "integer"] and safe_cast(current_value, int) == safe_cast( value, int ): - ret["comment"] += "{} {} is already set to {}".format(domain, name, value) + ret["comment"] += f"{domain} {name} is already set to {value}" elif current_value == value: - ret["comment"] += "{} {} is already set to {}".format(domain, name, value) + ret["comment"] += f"{domain} {name} is already set to {value}" else: out = __salt__["macdefaults.write"](domain, name, value, vtype, user) if out["retcode"] != 0: ret["result"] = False ret["comment"] = "Failed to write default. {}".format(out["stdout"]) else: - ret["changes"]["written"] = "{} {} is set to {}".format(domain, name, value) + ret["changes"]["written"] = f"{domain} {name} is set to {value}" return ret @@ -96,8 +96,8 @@ def absent(name, domain, user=None): out = __salt__["macdefaults.delete"](domain, name, user) if out["retcode"] != 0: - ret["comment"] += "{} {} is already absent".format(domain, name) + ret["comment"] += f"{domain} {name} is already absent" else: - ret["changes"]["absent"] = "{} {} is now absent".format(domain, name) + ret["changes"]["absent"] = f"{domain} {name} is now absent" return ret diff --git a/salt/states/macpackage.py b/salt/states/macpackage.py index 17a03fb1140..2d64d3b6955 100644 --- a/salt/states/macpackage.py +++ b/salt/states/macpackage.py @@ -114,7 +114,7 @@ def installed( version_out = "" if re.match(expected_version, version_out) is not None: - ret["comment"] += "Version already matches {}".format(expected_version) + ret["comment"] += f"Version already matches {expected_version}" return ret else: ret["comment"] += "Version {} doesn't match {}. ".format( @@ -130,7 +130,7 @@ def installed( out, mount_point = __salt__["macpackage.mount"](name) if "attach failed" in out: ret["result"] = False - ret["comment"] += "Unable to mount {}".format(name) + ret["comment"] += f"Unable to mount {name}" return ret if app: @@ -150,7 +150,7 @@ def installed( if ".app" not in out: ret["result"] = False - ret["comment"] += "Unable to find .app in {}".format(mount_point) + ret["comment"] += f"Unable to find .app in {mount_point}" return ret else: pkg_ids = out.split("\n") @@ -191,7 +191,7 @@ def installed( def failed_pkg(f_pkg): ret["result"] = False - ret["comment"] += "{} failed to install: {}".format(name, out) + ret["comment"] += f"{name} failed to install: {out}" if "failed" in ret["changes"]: ret["changes"]["failed"].append(f_pkg) @@ -209,7 +209,7 @@ def installed( if len(out) != 0: failed_pkg(app) else: - ret["comment"] += "{} installed".format(app) + ret["comment"] += f"{app} installed" if "installed" in ret["changes"]: ret["changes"]["installed"].append(app) else: @@ -224,9 +224,9 @@ def installed( if out["retcode"] != 0: ret["result"] = False - ret["comment"] += ". {} failed to install: {}".format(name, out) + ret["comment"] += f". {name} failed to install: {out}" else: - ret["comment"] += "{} installed".format(name) + ret["comment"] += f"{name} installed" ret["changes"]["installed"] = installing finally: diff --git a/salt/states/makeconf.py b/salt/states/makeconf.py index 632a11b2c43..9e5a19261c1 100644 --- a/salt/states/makeconf.py +++ b/salt/states/makeconf.py @@ -131,11 +131,11 @@ def present(name, value=None, contains=None, excludes=None): ret["comment"] = msg.format(name) else: if __opts__["test"]: - msg = "Variable {} is set to".format(name) + msg = f"Variable {name} is set to" if len(to_append) > 0: - msg += ' append "{}"'.format(list(to_append)) + msg += f' append "{list(to_append)}"' if len(to_trim) > 0: - msg += ' trim "{}"'.format(list(to_trim)) + msg += f' trim "{list(to_trim)}"' msg += " in make.conf" ret["comment"] = msg ret["result"] = None diff --git a/salt/states/marathon_app.py b/salt/states/marathon_app.py index 3d44503db61..95339b1d148 100644 --- a/salt/states/marathon_app.py +++ b/salt/states/marathon_app.py @@ -66,7 +66,7 @@ def config(name, config): # if test, report there will be an update if __opts__["test"]: ret["result"] = None - ret["comment"] = "Marathon app {} is set to be updated".format(name) + ret["comment"] = f"Marathon app {name} is set to be updated" return ret update_result = __salt__["marathon.update_app"](name, update_config) @@ -79,10 +79,10 @@ def config(name, config): return ret else: ret["result"] = True - ret["comment"] = "Updated app config for {}".format(name) + ret["comment"] = f"Updated app config for {name}" return ret ret["result"] = True - ret["comment"] = "Marathon app {} configured correctly".format(name) + ret["comment"] = f"Marathon app {name} configured correctly" return ret @@ -96,20 +96,20 @@ def absent(name): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["marathon.has_app"](name): ret["result"] = True - ret["comment"] = "App {} already absent".format(name) + ret["comment"] = f"App {name} already absent" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "App {} is set to be removed".format(name) + ret["comment"] = f"App {name} is set to be removed" return ret if __salt__["marathon.rm_app"](name): ret["changes"] = {"app": name} ret["result"] = True - ret["comment"] = "Removed app {}".format(name) + ret["comment"] = f"Removed app {name}" return ret else: ret["result"] = False - ret["comment"] = "Failed to remove app {}".format(name) + ret["comment"] = f"Failed to remove app {name}" return ret @@ -125,12 +125,12 @@ def running(name, restart=False, force=True): ret = {"name": name, "changes": {}, "result": False, "comment": ""} if not __salt__["marathon.has_app"](name): ret["result"] = False - ret["comment"] = "App {} cannot be restarted because it is absent".format(name) + ret["comment"] = f"App {name} cannot be restarted because it is absent" return ret if __opts__["test"]: ret["result"] = None qualifier = "is" if restart else "is not" - ret["comment"] = "App {} {} set to be restarted".format(name, qualifier) + ret["comment"] = f"App {name} {qualifier} set to be restarted" return ret restart_result = __salt__["marathon.restart_app"](name, restart, force) if "exception" in restart_result: @@ -143,5 +143,5 @@ def running(name, restart=False, force=True): ret["changes"] = restart_result ret["result"] = True qualifier = "Restarted" if restart else "Did not restart" - ret["comment"] = "{} app {}".format(qualifier, name) + ret["comment"] = f"{qualifier} app {name}" return ret diff --git a/salt/states/mdadm_raid.py b/salt/states/mdadm_raid.py index 7f32f3bd991..76396d858dd 100644 --- a/salt/states/mdadm_raid.py +++ b/salt/states/mdadm_raid.py @@ -19,7 +19,6 @@ A state module for creating or destroying software RAID devices. - run: True """ - import logging import salt.utils.path @@ -100,20 +99,20 @@ def present(name, level, devices, **kwargs): new_devices.append(dev) if len(uuid_dict) > 1: - ret[ - "comment" - ] = "Devices are a mix of RAID constituents with multiple MD_UUIDs: {}.".format( - sorted(uuid_dict) + ret["comment"] = ( + "Devices are a mix of RAID constituents with multiple MD_UUIDs: {}.".format( + sorted(uuid_dict) + ) ) ret["result"] = False return ret elif len(uuid_dict) == 1: uuid = next(iter(uuid_dict)) if present and present["uuid"] != uuid: - ret[ - "comment" - ] = "Devices MD_UUIDs: {} differs from present RAID uuid {}.".format( - uuid, present["uuid"] + ret["comment"] = ( + "Devices MD_UUIDs: {} differs from present RAID uuid {}.".format( + uuid, present["uuid"] + ) ) ret["result"] = False return ret @@ -131,7 +130,7 @@ def present(name, level, devices, **kwargs): verb = "assembled" else: if len(new_devices) == 0: - ret["comment"] = "All devices are missing: {}.".format(missing) + ret["comment"] = f"All devices are missing: {missing}." ret["result"] = False return ret do_assemble = False @@ -150,22 +149,22 @@ def present(name, level, devices, **kwargs): level, new_devices + ["missing"] * len(missing), test_mode=True, - **kwargs + **kwargs, ) if present: - ret["comment"] = "Raid {} already present.".format(name) + ret["comment"] = f"Raid {name} already present." if do_assemble or do_create: - ret["comment"] = "Raid will be {} with: {}".format(verb, res) + ret["comment"] = f"Raid will be {verb} with: {res}" ret["result"] = None if (do_assemble or present) and len(new_devices) > 0: - ret["comment"] += " New devices will be added: {}".format(new_devices) + ret["comment"] += f" New devices will be added: {new_devices}" ret["result"] = None if len(missing) > 0: - ret["comment"] += " Missing devices: {}".format(missing) + ret["comment"] += f" Missing devices: {missing}" return ret @@ -181,29 +180,29 @@ def present(name, level, devices, **kwargs): raids = __salt__["raid.list"]() changes = raids.get(name) if changes: - ret["comment"] = "Raid {} {}.".format(name, verb) + ret["comment"] = f"Raid {name} {verb}." ret["changes"] = changes # Saving config __salt__["raid.save_config"]() else: - ret["comment"] = "Raid {} failed to be {}.".format(name, verb) + ret["comment"] = f"Raid {name} failed to be {verb}." ret["result"] = False else: - ret["comment"] = "Raid {} already present.".format(name) + ret["comment"] = f"Raid {name} already present." if (do_assemble or present) and len(new_devices) > 0 and ret["result"]: for d in new_devices: res = __salt__["raid.add"](name, d) if not res: - ret["comment"] += " Unable to add {} to {}.\n".format(d, name) + ret["comment"] += f" Unable to add {d} to {name}.\n" ret["result"] = False else: - ret["comment"] += " Added new device {} to {}.\n".format(d, name) + ret["comment"] += f" Added new device {d} to {name}.\n" if ret["result"]: ret["changes"]["added"] = new_devices if len(missing) > 0: - ret["comment"] += " Missing devices: {}".format(missing) + ret["comment"] += f" Missing devices: {missing}" return ret @@ -225,10 +224,10 @@ def absent(name): # Raid does not exist if name not in __salt__["raid.list"](): - ret["comment"] = "Raid {} already absent".format(name) + ret["comment"] = f"Raid {name} already absent" return ret elif __opts__["test"]: - ret["comment"] = "Raid {} is set to be destroyed".format(name) + ret["comment"] = f"Raid {name} is set to be destroyed" ret["result"] = None return ret else: @@ -236,7 +235,7 @@ def absent(name): ret["result"] = __salt__["raid.destroy"](name) if ret["result"]: - ret["comment"] = "Raid {} has been destroyed".format(name) + ret["comment"] = f"Raid {name} has been destroyed" else: - ret["comment"] = "Raid {} failed to be destroyed".format(name) + ret["comment"] = f"Raid {name} failed to be destroyed" return ret diff --git a/salt/states/memcached.py b/salt/states/memcached.py index 9f4a6d367dd..3499961671b 100644 --- a/salt/states/memcached.py +++ b/salt/states/memcached.py @@ -5,7 +5,6 @@ States for Management of Memcached Keys .. versionadded:: 2014.1.0 """ - from salt.exceptions import CommandExecutionError, SaltInvocationError from salt.modules.memcached import ( DEFAULT_HOST, @@ -21,7 +20,7 @@ def __virtual__(): """ Only load if memcache module is available """ - if "{}.status".format(__virtualname__) in __salt__: + if f"{__virtualname__}.status" in __salt__: return __virtualname__ return (False, "memcached module could not be loaded") @@ -66,15 +65,15 @@ def managed( if cur == value: ret["result"] = True - ret["comment"] = "Key '{}' does not need to be updated".format(name) + ret["comment"] = f"Key '{name}' does not need to be updated" return ret if __opts__["test"]: ret["result"] = None if cur is None: - ret["comment"] = "Key '{}' would be added".format(name) + ret["comment"] = f"Key '{name}' would be added" else: - ret["comment"] = "Value of key '{}' would be changed".format(name) + ret["comment"] = f"Value of key '{name}' would be changed" return ret try: @@ -85,13 +84,13 @@ def managed( ret["comment"] = str(exc) else: if ret["result"]: - ret["comment"] = "Successfully set key '{}'".format(name) + ret["comment"] = f"Successfully set key '{name}'" if cur is not None: ret["changes"] = {"old": cur, "new": value} else: ret["changes"] = {"key added": name, "value": value} else: - ret["comment"] = "Failed to set key '{}'".format(name) + ret["comment"] = f"Failed to set key '{name}'" return ret @@ -139,12 +138,12 @@ def absent(name, value=None, host=DEFAULT_HOST, port=DEFAULT_PORT, time=DEFAULT_ return ret if cur is None: ret["result"] = True - ret["comment"] = "Key '{}' does not exist".format(name) + ret["comment"] = f"Key '{name}' does not exist" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Key '{}' would be deleted".format(name) + ret["comment"] = f"Key '{name}' would be deleted" return ret try: @@ -153,8 +152,8 @@ def absent(name, value=None, host=DEFAULT_HOST, port=DEFAULT_PORT, time=DEFAULT_ ret["comment"] = str(exc) else: if ret["result"]: - ret["comment"] = "Successfully deleted key '{}'".format(name) + ret["comment"] = f"Successfully deleted key '{name}'" ret["changes"] = {"key deleted": name, "value": cur} else: - ret["comment"] = "Failed to delete key '{}'".format(name) + ret["comment"] = f"Failed to delete key '{name}'" return ret diff --git a/salt/states/modjk.py b/salt/states/modjk.py index 0932715b129..f41a84010ab 100644 --- a/salt/states/modjk.py +++ b/salt/states/modjk.py @@ -26,7 +26,7 @@ def _bulk_state(saltfunc, lbn, workers, profile): if not isinstance(workers, list): ret["result"] = False - ret["comment"] = "workers should be a list not a {}".format(type(workers)) + ret["comment"] = f"workers should be a list not a {type(workers)}" return ret if __opts__["test"]: @@ -38,7 +38,7 @@ def _bulk_state(saltfunc, lbn, workers, profile): cmdret = __salt__[saltfunc](workers, lbn, profile=profile) except KeyError: ret["result"] = False - ret["comment"] = "unsupported function {}".format(saltfunc) + ret["comment"] = f"unsupported function {saltfunc}" return ret errors = [] @@ -49,7 +49,7 @@ def _bulk_state(saltfunc, lbn, workers, profile): ret["changes"] = {"status": cmdret} if errors: ret["result"] = False - ret["comment"] = "{} failed on some workers".format(saltfunc) + ret["comment"] = f"{saltfunc} failed on some workers" return ret diff --git a/salt/states/modjk_worker.py b/salt/states/modjk_worker.py index bcf745c03eb..5cefeac1d63 100644 --- a/salt/states/modjk_worker.py +++ b/salt/states/modjk_worker.py @@ -44,7 +44,7 @@ def _send_command(cmd, worker, lbn, target, profile="default", tgt_type="glob"): } # Send the command to target - func = "modjk.{}".format(cmd) + func = f"modjk.{cmd}" args = [worker, lbn, profile] response = __salt__["publish.publish"](target, func, args, tgt_type) @@ -58,7 +58,7 @@ def _send_command(cmd, worker, lbn, target, profile="default", tgt_type="glob"): # parse response if not response: - ret["msg"] = "no servers answered the published command {}".format(cmd) + ret["msg"] = f"no servers answered the published command {cmd}" return ret elif len(errors) > 0: ret["msg"] = "the following minions return False" @@ -127,16 +127,16 @@ def _talk2modjk(name, lbn, target, action, profile="default", tgt_type="glob"): return ret if status["errors"]: ret["result"] = False - ret[ - "comment" - ] = "the following balancers could not find the worker {}: {}".format( - name, status["errors"] + ret["comment"] = ( + "the following balancers could not find the worker {}: {}".format( + name, status["errors"] + ) ) return ret if not status["wrong_state"]: - ret[ - "comment" - ] = "the worker is in the desired activation state on all the balancers" + ret["comment"] = ( + "the worker is in the desired activation state on all the balancers" + ) return ret else: ret["comment"] = "the action {} will be sent to the balancers {}".format( diff --git a/salt/states/module.py b/salt/states/module.py index 5ad87b053d2..262e38b96d6 100644 --- a/salt/states/module.py +++ b/salt/states/module.py @@ -300,6 +300,7 @@ Windows system: .. _file_roots: https://docs.saltproject.io/en/latest/ref/configuration/master.html#file-roots """ + import logging import salt.loader @@ -459,19 +460,21 @@ def _run(**kwargs): ) ) if func_ret is False: - failures.append("'{}': {}".format(func, func_ret)) + failures.append(f"'{func}': {func_ret}") else: success.append( "{}: {}".format( func, - func_ret.get("comment", "Success") - if isinstance(func_ret, dict) - else func_ret, + ( + func_ret.get("comment", "Success") + if isinstance(func_ret, dict) + else func_ret + ), ) ) ret["changes"][func] = func_ret except (SaltInvocationError, TypeError) as ex: - failures.append("'{}' failed: {}".format(func, ex)) + failures.append(f"'{func}' failed: {ex}") ret["comment"] = ", ".join(failures + success) ret["result"] = not bool(failures) @@ -527,12 +530,12 @@ def _legacy_run(name, **kwargs): """ ret = {"name": name, "changes": {}, "comment": "", "result": None} if name not in __salt__: - ret["comment"] = "Module function {} is not available".format(name) + ret["comment"] = f"Module function {name} is not available" ret["result"] = False return ret if __opts__["test"]: - ret["comment"] = "Module function {} is set to execute".format(name) + ret["comment"] = f"Module function {name} is set to execute" return ret aspec = salt.utils.args.get_function_argspec(__salt__[name]) @@ -590,7 +593,7 @@ def _legacy_run(name, **kwargs): if missing: comment = "The following arguments are missing:" for arg in missing: - comment += " {}".format(arg) + comment += f" {arg}" ret["comment"] = comment ret["result"] = False return ret @@ -654,7 +657,7 @@ def _legacy_run(name, **kwargs): returners = salt.loader.returners(__opts__, __salt__) if kwargs["returner"] in returners: returners[kwargs["returner"]](ret_ret) - ret["comment"] = "Module function {} executed".format(name) + ret["comment"] = f"Module function {name} executed" ret["result"] = _get_result(mret, ret["changes"]) return ret diff --git a/salt/states/mongodb_database.py b/salt/states/mongodb_database.py index 4df6c4297ed..5445b3b880d 100644 --- a/salt/states/mongodb_database.py +++ b/salt/states/mongodb_database.py @@ -53,9 +53,9 @@ def absent(name, user=None, password=None, host=None, port=None, authdb=None): if __salt__["mongodb.db_remove"]( name, user, password, host, port, authdb=authdb ): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret - ret["comment"] = "Database {} is not present".format(name) + ret["comment"] = f"Database {name} is not present" return ret diff --git a/salt/states/mongodb_user.py b/salt/states/mongodb_user.py index a83cd9b5686..6494b0018a9 100644 --- a/salt/states/mongodb_user.py +++ b/salt/states/mongodb_user.py @@ -81,7 +81,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {} is already present".format(name), + "comment": f"User {name} is already present", } # setup default empty roles if not provided to preserve previous API interface @@ -93,7 +93,7 @@ def present( port = int(port) except TypeError: ret["result"] = False - ret["comment"] = "Port ({}) is not an integer.".format(port) + ret["comment"] = f"Port ({port}) is not an integer." return ret # check if user exists @@ -106,7 +106,7 @@ def present( # users= (False, 'not authorized on admin to execute command { usersInfo: "root" }') if not users[0]: ret["result"] = False - ret["comment"] = "Mongo Err: {}".format(users[1]) + ret["comment"] = f"Mongo Err: {users[1]}" return ret # check each user occurrence @@ -152,7 +152,7 @@ def present( if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is not present and needs to be created".format(name) + ret["comment"] = f"User {name} is not present and needs to be created" return ret # The user is not present, make it! if __salt__["mongodb.user_create"]( @@ -166,10 +166,10 @@ def present( authdb=authdb, roles=roles, ): - ret["comment"] = "User {} has been created".format(name) + ret["comment"] = f"User {name} has been created" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" ret["result"] = False return ret @@ -212,12 +212,12 @@ def absent( if user_exists is True: if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is present and needs to be removed".format(name) + ret["comment"] = f"User {name} is present and needs to be removed" return ret if __salt__["mongodb.user_remove"]( name, user, password, host, port, database=database, authdb=authdb ): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret @@ -229,5 +229,5 @@ def absent( return ret # fallback - ret["comment"] = "User {} is not present".format(name) + ret["comment"] = f"User {name} is not present" return ret diff --git a/salt/states/monit.py b/salt/states/monit.py index b6de50d307f..4e1cd7dd514 100644 --- a/salt/states/monit.py +++ b/salt/states/monit.py @@ -40,20 +40,20 @@ def monitor(name): try: for key, value in result.items(): if "Running" in value[name]: - ret["comment"] = "{} is being being monitored.".format(name) + ret["comment"] = f"{name} is being being monitored." ret["result"] = True else: if __opts__["test"]: - ret["comment"] = "Service {} is set to be monitored.".format(name) + ret["comment"] = f"Service {name} is set to be monitored." ret["result"] = None return ret __salt__["monit.monitor"](name) - ret["comment"] = "{} started to be monitored.".format(name) + ret["comment"] = f"{name} started to be monitored." ret["changes"][name] = "Running" ret["result"] = True break except KeyError: - ret["comment"] = "{} not found in configuration.".format(name) + ret["comment"] = f"{name} not found in configuration." ret["result"] = False return ret @@ -70,20 +70,20 @@ def unmonitor(name): try: for key, value in result.items(): if "Not monitored" in value[name]: - ret["comment"] = "{} is not being monitored.".format(name) + ret["comment"] = f"{name} is not being monitored." ret["result"] = True else: if __opts__["test"]: - ret["comment"] = "Service {} is set to be unmonitored.".format(name) + ret["comment"] = f"Service {name} is set to be unmonitored." ret["result"] = None return ret __salt__["monit.unmonitor"](name) - ret["comment"] = "{} stopped being monitored.".format(name) + ret["comment"] = f"{name} stopped being monitored." ret["changes"][name] = "Not monitored" ret["result"] = True break except KeyError: - ret["comment"] = "{} not found in configuration.".format(name) + ret["comment"] = f"{name} not found in configuration." ret["result"] = False return ret diff --git a/salt/states/mount.py b/salt/states/mount.py index 8f608bf265b..560ccc39ae6 100644 --- a/salt/states/mount.py +++ b/salt/states/mount.py @@ -477,10 +477,10 @@ def mounted( if trigger_remount: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Remount would be forced because options ({}) changed".format( - ",".join(sorted(trigger_remount)) + ret["comment"] = ( + "Remount would be forced because options ({}) changed".format( + ",".join(sorted(trigger_remount)) + ) ) return ret else: @@ -603,10 +603,10 @@ def mounted( ret["result"] = mount_result else: ret["result"] = False - ret[ - "comment" - ] = "Unable to unmount {}: {}.".format( - real_name, unmount_result + ret["comment"] = ( + "Unable to unmount {}: {}.".format( + real_name, unmount_result + ) ) return ret else: @@ -708,10 +708,10 @@ def mounted( if mkmnt: ret["comment"] = f"{name} would be created, but not mounted" else: - ret[ - "comment" - ] = "{} does not exist and would neither be created nor mounted".format( - name + ret["comment"] = ( + "{} does not exist and would neither be created nor mounted".format( + name + ) ) elif mkmnt: __salt__["file.mkdir"](name, user=user) @@ -899,10 +899,10 @@ def swap(name, persist=True, config="/etc/fstab"): ]: ret["result"] = None if name in on_: - ret[ - "comment" - ] = "Swap {} is set to be added to the fstab and to be activated".format( - name + ret["comment"] = ( + "Swap {} is set to be added to the fstab and to be activated".format( + name + ) ) return ret diff --git a/salt/states/mssql_database.py b/salt/states/mssql_database.py index e5c4c3cc67f..f3f44f0bd64 100644 --- a/salt/states/mssql_database.py +++ b/salt/states/mssql_database.py @@ -25,7 +25,7 @@ def __virtual__(): def _normalize_options(options): if type(options) in [dict, collections.OrderedDict]: - return ["{}={}".format(k, v) for k, v in options.items()] + return [f"{k}={v}" for k, v in options.items()] if type(options) is list and (not options or type(options[0]) is str): return options # Invalid options @@ -51,22 +51,22 @@ def present(name, containment="NONE", options=None, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if __salt__["mssql.db_exists"](name, **kwargs): - ret[ - "comment" - ] = "Database {} is already present (Not going to try to set its options)".format( - name + ret["comment"] = ( + "Database {} is already present (Not going to try to set its options)".format( + name + ) ) return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is set to be added".format(name) + ret["comment"] = f"Database {name} is set to be added" return ret db_created = __salt__["mssql.db_create"]( name, containment=containment, new_database_options=_normalize_options(options), - **kwargs + **kwargs, ) if ( db_created is not True @@ -76,7 +76,7 @@ def present(name, containment="NONE", options=None, **kwargs): name, db_created ) return ret - ret["comment"] += "Database {} has been added".format(name) + ret["comment"] += f"Database {name} has been added" ret["changes"][name] = "Present" return ret @@ -91,17 +91,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.db_exists"](name): - ret["comment"] = "Database {} is not present".format(name) + ret["comment"] = f"Database {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Database {} is set to be removed".format(name) + ret["comment"] = f"Database {name} is set to be removed" return ret if __salt__["mssql.db_remove"](name, **kwargs): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "Database {} failed to be removed".format(name) + ret["comment"] = f"Database {name} failed to be removed" return ret diff --git a/salt/states/mssql_login.py b/salt/states/mssql_login.py index 89ace89bcaf..56316db60f4 100644 --- a/salt/states/mssql_login.py +++ b/salt/states/mssql_login.py @@ -26,7 +26,7 @@ def __virtual__(): def _normalize_options(options): if type(options) in [dict, collections.OrderedDict]: - return ["{}={}".format(k, v) for k, v in options.items()] + return [f"{k}={v}" for k, v in options.items()] if type(options) is list and (not options or type(options[0]) is str): return options # Invalid options @@ -67,15 +67,15 @@ def present( ret["comment"] = "One and only one of password and domain should be specifies" return ret if __salt__["mssql.login_exists"](name, domain=domain, **kwargs): - ret[ - "comment" - ] = "Login {} is already present (Not going to try to set its password)".format( - name + ret["comment"] = ( + "Login {} is already present (Not going to try to set its password)".format( + name + ) ) return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Login {} is set to be added".format(name) + ret["comment"] = f"Login {name} is set to be added" return ret login_created = __salt__["mssql.login_create"]( @@ -84,14 +84,14 @@ def present( new_login_domain=domain, new_login_roles=server_roles, new_login_options=_normalize_options(options), - **kwargs + **kwargs, ) # Non-empty strings are also evaluated to True, so we cannot use if not login_created: if login_created is not True: ret["result"] = False - ret["comment"] = "Login {} failed to be added: {}".format(name, login_created) + ret["comment"] = f"Login {name} failed to be added: {login_created}" return ret - ret["comment"] = "Login {} has been added. ".format(name) + ret["comment"] = f"Login {name} has been added. " ret["changes"][name] = "Present" return ret @@ -106,17 +106,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.login_exists"](name): - ret["comment"] = "Login {} is not present".format(name) + ret["comment"] = f"Login {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Login {} is set to be removed".format(name) + ret["comment"] = f"Login {name} is set to be removed" return ret if __salt__["mssql.login_remove"](name, **kwargs): - ret["comment"] = "Login {} has been removed".format(name) + ret["comment"] = f"Login {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "Login {} failed to be removed".format(name) + ret["comment"] = f"Login {name} failed to be removed" return ret diff --git a/salt/states/mssql_role.py b/salt/states/mssql_role.py index 2fbdfe172a7..2bd540233f0 100644 --- a/salt/states/mssql_role.py +++ b/salt/states/mssql_role.py @@ -35,15 +35,15 @@ def present(name, owner=None, grants=None, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if __salt__["mssql.role_exists"](name, **kwargs): - ret[ - "comment" - ] = "Role {} is already present (Not going to try to set its grants)".format( - name + ret["comment"] = ( + "Role {} is already present (Not going to try to set its grants)".format( + name + ) ) return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Role {} is set to be added".format(name) + ret["comment"] = f"Role {name} is set to be added" return ret role_created = __salt__["mssql.role_create"]( @@ -53,9 +53,9 @@ def present(name, owner=None, grants=None, **kwargs): role_created is not True ): # Non-empty strings are also evaluated to True, so we cannot use if not role_created: ret["result"] = False - ret["comment"] += "Role {} failed to be created: {}".format(name, role_created) + ret["comment"] += f"Role {name} failed to be created: {role_created}" return ret - ret["comment"] += "Role {} has been added".format(name) + ret["comment"] += f"Role {name} has been added" ret["changes"][name] = "Present" return ret @@ -70,17 +70,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.role_exists"](name): - ret["comment"] = "Role {} is not present".format(name) + ret["comment"] = f"Role {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Role {} is set to be removed".format(name) + ret["comment"] = f"Role {name} is set to be removed" return ret if __salt__["mssql.role_remove"](name, **kwargs): - ret["comment"] = "Role {} has been removed".format(name) + ret["comment"] = f"Role {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "Role {} failed to be removed".format(name) + ret["comment"] = f"Role {name} failed to be removed" return ret diff --git a/salt/states/mssql_user.py b/salt/states/mssql_user.py index d07c0d56cca..60f8987d518 100644 --- a/salt/states/mssql_user.py +++ b/salt/states/mssql_user.py @@ -26,7 +26,7 @@ def __virtual__(): def _normalize_options(options): if type(options) in [dict, collections.OrderedDict]: - return ["{}={}".format(k, v) for k, v in options.items()] + return [f"{k}={v}" for k, v in options.items()] if type(options) is list and (not options or type(options[0]) is str): return options # Invalid options @@ -66,15 +66,15 @@ def present( ret["comment"] = "domain cannot be set without login" return ret if __salt__["mssql.user_exists"](name, domain=domain, database=database, **kwargs): - ret[ - "comment" - ] = "User {} is already present (Not going to try to set its roles or options)".format( - name + ret["comment"] = ( + "User {} is already present (Not going to try to set its roles or options)".format( + name + ) ) return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is set to be added".format(name) + ret["comment"] = f"User {name} is set to be added" return ret user_created = __salt__["mssql.user_create"]( @@ -84,15 +84,15 @@ def present( database=database, roles=roles, options=_normalize_options(options), - **kwargs + **kwargs, ) if ( user_created is not True ): # Non-empty strings are also evaluated to True, so we cannot use if not user_created: ret["result"] = False - ret["comment"] += "User {} failed to be added: {}".format(name, user_created) + ret["comment"] += f"User {name} failed to be added: {user_created}" return ret - ret["comment"] += "User {} has been added".format(name) + ret["comment"] += f"User {name} has been added" ret["changes"][name] = "Present" return ret @@ -107,17 +107,17 @@ def absent(name, **kwargs): ret = {"name": name, "changes": {}, "result": True, "comment": ""} if not __salt__["mssql.user_exists"](name): - ret["comment"] = "User {} is not present".format(name) + ret["comment"] = f"User {name} is not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is set to be removed".format(name) + ret["comment"] = f"User {name} is set to be removed" return ret if __salt__["mssql.user_remove"](name, **kwargs): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret # else: ret["result"] = False - ret["comment"] = "User {} failed to be removed".format(name) + ret["comment"] = f"User {name} failed to be removed" return ret diff --git a/salt/states/msteams.py b/salt/states/msteams.py index d84387c7d68..a4438825797 100644 --- a/salt/states/msteams.py +++ b/salt/states/msteams.py @@ -21,7 +21,6 @@ The hook_url can be specified in the master or minion configuration like below: hook_url: https://outlook.office.com/webhook/837 """ - from salt.exceptions import SaltInvocationError @@ -70,7 +69,7 @@ def post_card(name, message, hook_url=None, title=None, theme_color=None): return ret if not message: - ret["comment"] = "Teams message is missing: {}".format(message) + ret["comment"] = f"Teams message is missing: {message}" return ret try: @@ -81,11 +80,11 @@ def post_card(name, message, hook_url=None, title=None, theme_color=None): theme_color=theme_color, ) except SaltInvocationError as sie: - ret["comment"] = "Failed to send message ({}): {}".format(sie, name) + ret["comment"] = f"Failed to send message ({sie}): {name}" else: if isinstance(result, bool) and result: ret["result"] = True - ret["comment"] = "Sent message: {}".format(name) + ret["comment"] = f"Sent message: {name}" else: ret["comment"] = "Failed to send message ({}): {}".format( result["message"], name diff --git a/salt/states/mysql_database.py b/salt/states/mysql_database.py index c7561cf14db..0c0ce030ff4 100644 --- a/salt/states/mysql_database.py +++ b/salt/states/mysql_database.py @@ -52,7 +52,7 @@ def present(name, character_set=None, collate=None, **connection_args): "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(name), + "comment": f"Database {name} is already present", } # check if database exists existing = __salt__["mysql.db_get"](name, **connection_args) @@ -91,20 +91,20 @@ def present(name, character_set=None, collate=None, **connection_args): ) if __opts__.get("test", False): ret["result"] = None - ret["comment"] += "\n{}".format(comment) + ret["comment"] += f"\n{comment}" return ret else: - ret["comment"] += "\n{}".format(comment) + ret["comment"] += f"\n{comment}" if alter_charset or alter_collate: if __opts__.get("test", False): - ret["comment"] += "\nDatabase {} is going to be updated".format(name) + ret["comment"] += f"\nDatabase {name} is going to be updated" else: __salt__["mysql.alter_db"]( name, character_set=character_set, collate=collate, - **connection_args + **connection_args, ) current = __salt__["mysql.db_get"](name, **connection_args) @@ -145,13 +145,13 @@ def present(name, character_set=None, collate=None, **connection_args): if __salt__["mysql.db_create"]( name, character_set=character_set, collate=collate, **connection_args ): - ret["comment"] = "The database {} has been created".format(name) + ret["comment"] = f"The database {name} has been created" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to create database {}".format(name) + ret["comment"] = f"Failed to create database {name}" err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" ret["result"] = False return ret @@ -175,13 +175,13 @@ def absent(name, **connection_args): ) return ret if __salt__["mysql.db_remove"](name, **connection_args): - ret["comment"] = "Database {} has been removed".format(name) + ret["comment"] = f"Database {name} has been removed" ret["changes"][name] = "Absent" return ret else: err = _get_mysql_error() if err is not None: - ret["comment"] = "Unable to remove database {} ({})".format(name, err) + ret["comment"] = f"Unable to remove database {name} ({err})" ret["result"] = False return ret else: @@ -192,5 +192,5 @@ def absent(name, **connection_args): return ret # fallback - ret["comment"] = "Database {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Database {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/mysql_grants.py b/salt/states/mysql_grants.py index acc9856a1f4..74e1c8346b5 100644 --- a/salt/states/mysql_grants.py +++ b/salt/states/mysql_grants.py @@ -77,7 +77,7 @@ def present( escape=True, revoke_first=False, ssl_option=False, - **connection_args + **connection_args, ): """ Ensure that the grant is present with the specified properties @@ -182,14 +182,14 @@ def present( host=host, grant_option=grant_option, escape=escape, - **connection_args + **connection_args, ) # The grant is not present, make it! if __opts__["test"]: # there is probably better things to make in test mode ret["result"] = None - ret["comment"] = "MySQL grant {} is set to be created".format(name) + ret["comment"] = f"MySQL grant {name} is set to be created" return ret if __salt__["mysql.grant_add"]( grant, database, user, host, grant_option, escape, ssl_option, **connection_args @@ -202,7 +202,7 @@ def present( ret["comment"] = ret["comment"].format(grant, database, user, host) err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" ret["result"] = False return ret @@ -215,7 +215,7 @@ def absent( host="localhost", grant_option=False, escape=True, - **connection_args + **connection_args, ): """ Ensure that the grant is absent @@ -244,7 +244,7 @@ def absent( if __opts__["test"]: ret["result"] = None - ret["comment"] = "MySQL grant {} is set to be revoked".format(name) + ret["comment"] = f"MySQL grant {name} is set to be revoked" return ret if __salt__["mysql.grant_revoke"]( grant, database, user, host, grant_option, **connection_args @@ -257,28 +257,28 @@ def absent( else: err = _get_mysql_error() if err is not None: - ret[ - "comment" - ] = "Unable to revoke grant {} on {} for {}@{} ({})".format( - grant, database, user, host, err + ret["comment"] = ( + "Unable to revoke grant {} on {} for {}@{} ({})".format( + grant, database, user, host, err + ) ) ret["result"] = False return ret else: err = _get_mysql_error() if err is not None: - ret[ - "comment" - ] = "Unable to determine if grant {} on {} for {}@{} exists ({})".format( - grant, database, user, host, err + ret["comment"] = ( + "Unable to determine if grant {} on {} for {}@{} exists ({})".format( + grant, database, user, host, err + ) ) ret["result"] = False return ret # fallback - ret[ - "comment" - ] = "Grant {} on {} to {}@{} is not present, so it cannot be revoked".format( - grant, database, user, host + ret["comment"] = ( + "Grant {} on {} to {}@{} is not present, so it cannot be revoked".format( + grant, database, user, host + ) ) return ret diff --git a/salt/states/mysql_query.py b/salt/states/mysql_query.py index be4ee5169a6..d0bc6bedfc9 100644 --- a/salt/states/mysql_query.py +++ b/salt/states/mysql_query.py @@ -19,7 +19,6 @@ Its output may be stored in a file or in a grain. - output: "/tmp/query_id.txt" """ - import os.path import sys @@ -57,7 +56,7 @@ def run_file( saltenv=None, check_db_exists=True, client_flags=None, - **connection_args + **connection_args, ): """ Execute an arbitrary query on the specified database @@ -104,7 +103,7 @@ def run_file( "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(database), + "comment": f"Database {database} is already present", } if client_flags is None: @@ -125,7 +124,7 @@ def run_file( query_file = __salt__["cp.cache_file"](query_file, saltenv=saltenv or __env__) if not os.path.exists(query_file): - ret["comment"] = "File {} does not exist".format(query_file) + ret["comment"] = f"File {query_file} does not exist" ret["result"] = False return ret @@ -138,7 +137,7 @@ def run_file( return ret ret["result"] = None - ret["comment"] = "Database {} is not present".format(database) + ret["comment"] = f"Database {database} is not present" return ret # Check if execution needed @@ -253,7 +252,7 @@ def run( overwrite=True, check_db_exists=True, client_flags=None, - **connection_args + **connection_args, ): """ Execute an arbitrary query on the specified database @@ -295,7 +294,7 @@ def run( "name": name, "changes": {}, "result": True, - "comment": "Database {} is already present".format(database), + "comment": f"Database {database} is already present", } if client_flags is None: @@ -316,7 +315,7 @@ def run( return ret ret["result"] = None - ret["comment"] = "Database {} is not present".format(name) + ret["comment"] = f"Database {name} is not present" return ret # Check if execution needed @@ -414,7 +413,7 @@ def run( else: for col, val in query_result.items(): output_file.write( - salt.utils.stringutils.to_str("{}:{}\n".format(col, val)) + salt.utils.stringutils.to_str(f"{col}:{val}\n") ) else: ret["changes"]["query"] = "Executed" diff --git a/salt/states/mysql_user.py b/salt/states/mysql_user.py index 61f2caa936a..1c54de4ec5c 100644 --- a/salt/states/mysql_user.py +++ b/salt/states/mysql_user.py @@ -73,7 +73,7 @@ def present( unix_socket=False, password_column=None, auth_plugin="mysql_native_password", - **connection_args + **connection_args, ): """ Ensure that the named user is present with the specified properties. A @@ -117,7 +117,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {}@{} is already present".format(name, host), + "comment": f"User {name}@{host} is already present", } passwordless = not any((password, password_hash)) @@ -138,7 +138,7 @@ def present( passwordless=True, unix_socket=unix_socket, password_column=password_column, - **connection_args + **connection_args, ): if allow_passwordless: ret["comment"] += " with passwordless login" @@ -157,7 +157,7 @@ def present( password_hash, unix_socket=unix_socket, password_column=password_column, - **connection_args + **connection_args, ): if auth_plugin == "mysql_native_password": ret["comment"] += " with the desired password" @@ -180,7 +180,7 @@ def present( # The user is present, change the password if __opts__["test"]: - ret["comment"] = "Password for user {}@{} is set to be ".format(name, host) + ret["comment"] = f"Password for user {name}@{host} is set to be " ret["result"] = None if passwordless: ret["comment"] += "cleared" @@ -198,7 +198,7 @@ def present( password_hash, allow_passwordless, unix_socket, - **connection_args + **connection_args, ): ret["comment"] = "Password for user {}@{} has been {}".format( name, host, "cleared" if passwordless else "changed" @@ -210,7 +210,7 @@ def present( ) err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" if passwordless and not salt.utils.data.is_true(allow_passwordless): ret["comment"] += ( ". Note: allow_passwordless must be True " @@ -227,7 +227,7 @@ def present( # The user is not present, make it! if __opts__["test"]: - ret["comment"] = "User {}@{} is set to be added".format(name, host) + ret["comment"] = f"User {name}@{host} is set to be added" ret["result"] = None if allow_passwordless: ret["comment"] += " with passwordless login" @@ -247,19 +247,19 @@ def present( unix_socket=unix_socket, password_column=password_column, auth_plugin=auth_plugin, - **connection_args + **connection_args, ): - ret["comment"] = "The user {}@{} has been added".format(name, host) + ret["comment"] = f"The user {name}@{host} has been added" if allow_passwordless: ret["comment"] += " with passwordless login" if unix_socket: ret["comment"] += " using unix_socket" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to create user {}@{}".format(name, host) + ret["comment"] = f"Failed to create user {name}@{host}" err = _get_mysql_error() if err is not None: - ret["comment"] += " ({})".format(err) + ret["comment"] += f" ({err})" ret["result"] = False return ret @@ -278,10 +278,10 @@ def absent(name, host="localhost", **connection_args): if __salt__["mysql.user_exists"](name, host, **connection_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {}@{} is set to be removed".format(name, host) + ret["comment"] = f"User {name}@{host} is set to be removed" return ret if __salt__["mysql.user_remove"](name, host, **connection_args): - ret["comment"] = "User {}@{} has been removed".format(name, host) + ret["comment"] = f"User {name}@{host} has been removed" ret["changes"][name] = "Absent" return ret else: diff --git a/salt/states/netconfig.py b/salt/states/netconfig.py index 2b050e8abee..17870ab4afd 100644 --- a/salt/states/netconfig.py +++ b/salt/states/netconfig.py @@ -67,7 +67,7 @@ def _update_config( commit=True, debug=False, replace=False, - **template_vars + **template_vars, ): """ Call the necessary functions in order to execute the state. @@ -92,7 +92,7 @@ def _update_config( commit=commit, debug=debug, replace=replace, - **template_vars + **template_vars, ) @@ -275,7 +275,7 @@ def saved( win_deny_perms=None, win_inheritance=True, win_perms_reset=False, - **kwargs + **kwargs, ): """ .. versionadded:: 2019.2.0 @@ -452,7 +452,7 @@ def saved( win_deny_perms=win_deny_perms, win_inheritance=win_inheritance, win_perms_reset=win_perms_reset, - **kwargs + **kwargs, ) @@ -475,7 +475,7 @@ def managed( commit_at=None, revert_in=None, revert_at=None, - **template_vars + **template_vars, ): """ Manages the configuration on network devices. @@ -851,7 +851,7 @@ def managed( revert_at=revert_at, debug=debug, replace=replace, - **template_vars + **template_vars, ) return salt.utils.napalm.loaded_ret(ret, config_update_ret, test, debug) @@ -877,7 +877,7 @@ def commit_cancelled(name): """ cancelled = {"name": name, "result": None, "changes": {}, "comment": ""} if __opts__["test"]: - cancelled["comment"] = "It would cancel commit #{}".format(name) + cancelled["comment"] = f"It would cancel commit #{name}" return cancelled ret = __salt__["net.cancel_commit"](name) cancelled.update(ret) @@ -904,7 +904,7 @@ def commit_confirmed(name): """ confirmed = {"name": name, "result": None, "changes": {}, "comment": ""} if __opts__["test"]: - confirmed["comment"] = "It would confirm commit #{}".format(name) + confirmed["comment"] = f"It would confirm commit #{name}" return confirmed ret = __salt__["net.confirm_commit"](name) confirmed.update(ret) diff --git a/salt/states/netntp.py b/salt/states/netntp.py index 27a8b09713f..561b5bbda12 100644 --- a/salt/states/netntp.py +++ b/salt/states/netntp.py @@ -80,21 +80,18 @@ def _default_ret(name): def _retrieve_ntp_peers(): - """Retrieves configured NTP peers""" return __salt__["ntp.peers"]() def _retrieve_ntp_servers(): - """Retrieves configured NTP servers""" return __salt__["ntp.servers"]() def _check(peers): - """Checks whether the input is a valid list of peers and transforms domain names into IP Addresses""" if not isinstance(peers, list): @@ -141,28 +138,24 @@ def _clean(lst): def _set_ntp_peers(peers): - """Calls ntp.set_peers.""" return __salt__["ntp.set_peers"](*peers, commit=False) def _set_ntp_servers(servers): - """Calls ntp.set_servers.""" return __salt__["ntp.set_servers"](*servers, commit=False) def _delete_ntp_peers(peers): - """Calls ntp.delete_peers.""" return __salt__["ntp.delete_peers"](*peers, commit=False) def _delete_ntp_servers(servers): - """Calls ntp.delete_servers.""" return __salt__["ntp.delete_servers"](*servers, commit=False) @@ -185,7 +178,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): if name not in _options: return _ret - _retrieve_fun = "_retrieve_ntp_{what}".format(what=name) + _retrieve_fun = f"_retrieve_ntp_{name}" ntp_list_output = _exec_fun( _retrieve_fun ) # contains only IP Addresses as dictionary keys @@ -202,7 +195,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): if configured_ntp_list == desired_ntp_list: _ret.update( { - "comment": "NTP {what} already configured as needed.".format(what=name), + "comment": f"NTP {name} already configured as needed.", "result": True, } ) @@ -238,7 +231,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): comment = "" if list_to_set: - _set_fun = "_set_ntp_{what}".format(what=name) + _set_fun = f"_set_ntp_{name}" _set = _exec_fun(_set_fun, list_to_set) if _set.get("result"): expected_config_change = True @@ -249,7 +242,7 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): ) if list_to_delete: - _delete_fun = "_delete_ntp_{what}".format(what=name) + _delete_fun = f"_delete_ntp_{name}" _removed = _exec_fun(_delete_fun, list_to_delete) if _removed.get("result"): expected_config_change = True @@ -276,7 +269,6 @@ def _check_diff_and_configure(fun_name, peers_servers, name="peers"): def managed(name, peers=None, servers=None): - """ Manages the configuration of NTP peers and servers on the device, as specified in the state SLS file. NTP entities not specified in these lists will be removed whilst entities not configured on the device will be set. @@ -334,15 +326,15 @@ def managed(name, peers=None, servers=None): return ret # just exit if isinstance(peers, list) and not _check(peers): # check and clean peers - ret[ - "comment" - ] = "NTP peers must be a list of valid IP Addresses or Domain Names" + ret["comment"] = ( + "NTP peers must be a list of valid IP Addresses or Domain Names" + ) return ret if isinstance(servers, list) and not _check(servers): # check and clean servers - ret[ - "comment" - ] = "NTP servers must be a list of valid IP Addresses or Domain Names" + ret["comment"] = ( + "NTP servers must be a list of valid IP Addresses or Domain Names" + ) return ret # ----- Retrieve existing NTP peers and determine peers to be added/removed ---------------------------------------> diff --git a/salt/states/netsnmp.py b/salt/states/netsnmp.py index 54dbf7887d3..be2c4ccec5d 100644 --- a/salt/states/netsnmp.py +++ b/salt/states/netsnmp.py @@ -60,7 +60,6 @@ def __virtual__(): def _ordered_dict_to_dict(config): - """ Forced the datatype to dict, in case OrderedDict is used. """ @@ -69,7 +68,6 @@ def _ordered_dict_to_dict(config): def _expand_config(config, defaults): - """ Completed the values of the expected config for the edge cases with the default values. """ @@ -79,7 +77,6 @@ def _expand_config(config, defaults): def _valid_dict(dic): - """ Valid dictionary? """ @@ -88,7 +85,6 @@ def _valid_dict(dic): def _valid_str(value): - """ Valid str? """ @@ -97,7 +93,6 @@ def _valid_str(value): def _community_defaults(): - """ Returns the default values of a community. """ @@ -106,7 +101,6 @@ def _community_defaults(): def _clear_community_details(community_details): - """ Clears community details. """ @@ -126,7 +120,6 @@ def _clear_community_details(community_details): def _str_elem(config, key): - """ Re-adds the value of a specific key in the dict, only in case of valid str value. """ @@ -137,7 +130,6 @@ def _str_elem(config, key): def _check_config(config): - """ Checks the desired config and clears interesting details. """ @@ -187,7 +179,6 @@ def _check_config(config): def _retrieve_device_config(): - """ Retrieves the SNMP config from the device. """ @@ -196,7 +187,6 @@ def _retrieve_device_config(): def _create_diff_action(diff, diff_key, key, value): - """ DRY to build diff parts (added, removed, updated). """ @@ -207,7 +197,6 @@ def _create_diff_action(diff, diff_key, key, value): def _create_diff(diff, fun, key, prev, curr): - """ Builds the diff dictionary. """ @@ -221,7 +210,6 @@ def _create_diff(diff, fun, key, prev, curr): def _compute_diff(existing, expected): - """ Computes the differences between the existing and the expected SNMP config. """ @@ -240,7 +228,6 @@ def _compute_diff(existing, expected): def _configure(changes): - """ Calls the configuration template to apply the configuration changes on the device. """ @@ -259,7 +246,7 @@ def _configure(changes): _chassis_id = _updated_changes.get("chassis_id", "") if key == "removed": fun = "remove_config" - _ret = __salt__["snmp.{fun}".format(fun=fun)]( + _ret = __salt__[f"snmp.{fun}"]( location=_location, contact=_contact, community=_community, @@ -279,7 +266,6 @@ def _configure(changes): def managed(name, config=None, defaults=None): - """ Configures the SNMP on the device as specified in the SLS file. diff --git a/salt/states/netusers.py b/salt/states/netusers.py index 9120ce358aa..350fe5b471c 100644 --- a/salt/states/netusers.py +++ b/salt/states/netusers.py @@ -54,21 +54,18 @@ def __virtual__(): def _retrieve_users(): - """Retrieves configured users""" return __salt__["users.config"]() def _ordered_dict_to_dict(probes): - """.""" return salt.utils.json.loads(salt.utils.json.dumps(probes)) def _expand_users(device_users, common_users): - """Creates a longer list of accepted users on the device.""" expected_users = copy.deepcopy(common_users) @@ -78,7 +75,6 @@ def _expand_users(device_users, common_users): def _check_users(users): - """Checks if the input dictionary of users is valid.""" messg = "" @@ -87,7 +83,7 @@ def _check_users(users): for user, user_details in users.items(): if not user_details: valid = False - messg += "Please provide details for username {user}.\n".format(user=user) + messg += f"Please provide details for username {user}.\n" continue if not ( isinstance(user_details.get("level"), int) @@ -103,7 +99,6 @@ def _check_users(users): def _compute_diff(configured, expected): - """Computes the differences between the actual config and the expected config""" diff = {"add": {}, "update": {}, "remove": {}} @@ -135,21 +130,18 @@ def _compute_diff(configured, expected): def _set_users(users): - """Calls users.set_users.""" return __salt__["users.set_users"](users, commit=False) def _update_users(users): - """Calls users.set_users.""" return __salt__["users.set_users"](users, commit=False) def _delete_users(users): - """Calls users.delete_users.""" return __salt__["users.delete_users"](users, commit=False) @@ -161,7 +153,6 @@ def _delete_users(users): def managed(name, users=None, defaults=None): - """ Manages the configuration of the users on the device, as specified in the state SLS file. Users not defined in that file will be removed whilst users not configured on the device, will be added. diff --git a/salt/states/network.py b/salt/states/network.py index b942a7e58d4..383b1b69243 100644 --- a/salt/states/network.py +++ b/salt/states/network.py @@ -482,7 +482,7 @@ def managed(name, enabled=True, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Interface {} is up to date.".format(name), + "comment": f"Interface {name} is up to date.", } if "test" not in kwargs: kwargs["test"] = __opts__.get("test", False) @@ -513,7 +513,7 @@ def managed(name, enabled=True, **kwargs): pass if not old and new: ret["result"] = None - ret["comment"] = "Interface {} is set to be added.".format(name) + ret["comment"] = f"Interface {name} is set to be added." elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None @@ -522,12 +522,12 @@ def managed(name, enabled=True, **kwargs): ) else: if not old and new: - ret["comment"] = "Interface {} added.".format(name) + ret["comment"] = f"Interface {name} added." ret["changes"]["interface"] = "Added network interface." apply_ranged_setting = True elif old != new: diff = difflib.unified_diff(old, new, lineterm="") - ret["comment"] = "Interface {} updated.".format(name) + ret["comment"] = f"Interface {name} updated." ret["changes"]["interface"] = "\n".join(diff) apply_ranged_setting = True except AttributeError as error: @@ -554,19 +554,19 @@ def managed(name, enabled=True, **kwargs): elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None - ret[ - "comment" - ] = "Bond interface {} is set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Bond interface {} is set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) else: if not old and new: - ret["comment"] = "Bond interface {} added.".format(name) - ret["changes"]["bond"] = "Added bond {}.".format(name) + ret["comment"] = f"Bond interface {name} added." + ret["changes"]["bond"] = f"Added bond {name}." apply_ranged_setting = True elif old != new: diff = difflib.unified_diff(old, new, lineterm="") - ret["comment"] = "Bond interface {} updated.".format(name) + ret["comment"] = f"Bond interface {name} updated." ret["changes"]["bond"] = "\n".join(diff) apply_ranged_setting = True except AttributeError as error: @@ -628,15 +628,15 @@ def managed(name, enabled=True, **kwargs): __salt__["ip.up"](name, iface_type) ret["changes"][ "status" - ] = "Interface {} restart to validate".format(name) + ] = f"Interface {name} restart to validate" else: __salt__["ip.up"](name, iface_type) - ret["changes"]["status"] = "Interface {} is up".format(name) + ret["changes"]["status"] = f"Interface {name} is up" else: if "noifupdown" not in kwargs: if interface_status: __salt__["ip.down"](name, iface_type) - ret["changes"]["status"] = "Interface {} down".format(name) + ret["changes"]["status"] = f"Interface {name} down" except Exception as error: # pylint: disable=broad-except ret["result"] = False ret["comment"] = str(error) @@ -648,7 +648,7 @@ def managed(name, enabled=True, **kwargs): if "slaves" in kwargs and kwargs["slaves"]: # Check that there are new slaves for this master present_slaves = __salt__["cmd.run"]( - ["cat", "/sys/class/net/{}/bonding/slaves".format(name)] + ["cat", f"/sys/class/net/{name}/bonding/slaves"] ).split() if isinstance(kwargs["slaves"], list): desired_slaves = kwargs["slaves"] @@ -670,10 +670,10 @@ def managed(name, enabled=True, **kwargs): __salt__["cmd.run"](cmd, python_shell=False) else: log.error("Command 'ifenslave' not found") - ret["changes"][ - "enslave" - ] = "Added slaves '{}' to master '{}'".format( - " ".join(missing_slaves), name + ret["changes"]["enslave"] = ( + "Added slaves '{}' to master '{}'".format( + " ".join(missing_slaves), name + ) ) else: log.info( @@ -706,7 +706,7 @@ def routes(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "Interface {} routes are up to date.".format(name), + "comment": f"Interface {name} routes are up to date.", } apply_routes = False if "test" not in kwargs: @@ -721,25 +721,25 @@ def routes(name, **kwargs): return ret if not old and new: ret["result"] = None - ret["comment"] = "Interface {} routes are set to be added.".format(name) + ret["comment"] = f"Interface {name} routes are set to be added." return ret elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None - ret[ - "comment" - ] = "Interface {} routes are set to be updated:\n{}".format( - name, "\n".join(diff) + ret["comment"] = ( + "Interface {} routes are set to be updated:\n{}".format( + name, "\n".join(diff) + ) ) return ret if not old and new: apply_routes = True - ret["comment"] = "Interface {} routes added.".format(name) - ret["changes"]["network_routes"] = "Added interface {} routes.".format(name) + ret["comment"] = f"Interface {name} routes added." + ret["changes"]["network_routes"] = f"Added interface {name} routes." elif old != new: diff = difflib.unified_diff(old, new, lineterm="") apply_routes = True - ret["comment"] = "Interface {} routes updated.".format(name) + ret["comment"] = f"Interface {name} routes updated." ret["changes"]["network_routes"] = "\n".join(diff) except AttributeError as error: ret["result"] = False @@ -791,10 +791,10 @@ def system(name, **kwargs): elif old != new: diff = difflib.unified_diff(old, new, lineterm="") ret["result"] = None - ret[ - "comment" - ] = "Global network settings are set to be updated:\n{}".format( - "\n".join(diff) + ret["comment"] = ( + "Global network settings are set to be updated:\n{}".format( + "\n".join(diff) + ) ) return ret if not old and new: diff --git a/salt/states/neutron_network.py b/salt/states/neutron_network.py index 30e6cfb050f..2dc5bc0a3a0 100644 --- a/salt/states/neutron_network.py +++ b/salt/states/neutron_network.py @@ -28,7 +28,6 @@ Example States - project: project1 """ - __virtualname__ = "neutron_network" @@ -99,7 +98,7 @@ def present(name, auth=None, **kwargs): del kwargs["project"] else: ret["result"] = False - ret["comment"] = "Project:{} not found.".format(projectname) + ret["comment"] = f"Project:{projectname} not found." return ret network = __salt__["neutronng.network_create"](**kwargs) diff --git a/salt/states/neutron_secgroup.py b/salt/states/neutron_secgroup.py index 045f413c945..144178bbc2d 100644 --- a/salt/states/neutron_secgroup.py +++ b/salt/states/neutron_secgroup.py @@ -34,7 +34,6 @@ Example States - project_name: Project1 """ - __virtualname__ = "neutron_secgroup" diff --git a/salt/states/neutron_secgroup_rule.py b/salt/states/neutron_secgroup_rule.py index db4721fc79e..219455a8447 100644 --- a/salt/states/neutron_secgroup_rule.py +++ b/salt/states/neutron_secgroup_rule.py @@ -28,7 +28,6 @@ Example States - project_id: 1dcac318a83b4610b7a7f7ba01465548 """ - __virtualname__ = "neutron_secgroup_rule" @@ -96,7 +95,7 @@ def present(name, auth=None, **kwargs): if secgroup is None: ret["result"] = False ret["changes"] = ({},) - ret["comment"] = "Security Group does not exist {}".format(name) + ret["comment"] = f"Security Group does not exist {name}" return ret # we have to search through all secgroup rules for a possible match diff --git a/salt/states/neutron_subnet.py b/salt/states/neutron_subnet.py index 30c69992b58..60e241e69ef 100644 --- a/salt/states/neutron_subnet.py +++ b/salt/states/neutron_subnet.py @@ -46,7 +46,6 @@ Example States - ip_version: 6 """ - __virtualname__ = "neutron_subnet" diff --git a/salt/states/nexus.py b/salt/states/nexus.py index a823b0a47d0..10d71db4cd8 100644 --- a/salt/states/nexus.py +++ b/salt/states/nexus.py @@ -4,7 +4,6 @@ This state downloads artifacts from Nexus 3.x. .. versionadded:: 2018.3.0 """ - import logging log = logging.getLogger(__name__) diff --git a/salt/states/nfs_export.py b/salt/states/nfs_export.py index ad572739d7f..27d6b853d54 100644 --- a/salt/states/nfs_export.py +++ b/salt/states/nfs_export.py @@ -140,14 +140,14 @@ def present(name, clients=None, hosts=None, options=None, exports="/etc/exports" if path in old: if old[path] == clients: ret["result"] = True - ret["comment"] = "Export {} already configured".format(path) + ret["comment"] = f"Export {path} already configured" return ret ret["changes"]["new"] = clients ret["changes"]["old"] = old[path] if __opts__["test"]: ret["result"] = None - ret["comment"] = "Export {} would be changed".format(path) + ret["comment"] = f"Export {path} would be changed" return ret __salt__["nfs3.del_export"](exports, path) @@ -157,7 +157,7 @@ def present(name, clients=None, hosts=None, options=None, exports="/etc/exports" ret["changes"]["new"] = clients if __opts__["test"]: ret["result"] = None - ret["comment"] = "Export {} would be added".format(path) + ret["comment"] = f"Export {path} would be added" return ret add_export = __salt__["nfs3.add_export"] @@ -186,7 +186,7 @@ def absent(name, exports="/etc/exports"): old = __salt__["nfs3.list_exports"](exports) if path in old: if __opts__["test"]: - ret["comment"] = "Export {} would be removed".format(path) + ret["comment"] = f"Export {path} would be removed" ret["changes"][path] = old[path] ret["result"] = None return ret @@ -196,12 +196,12 @@ def absent(name, exports="/etc/exports"): if not try_reload["result"]: ret["comment"] = try_reload["stderr"] else: - ret["comment"] = "Export {} removed".format(path) + ret["comment"] = f"Export {path} removed" ret["result"] = try_reload["result"] ret["changes"][path] = old[path] else: - ret["comment"] = "Export {} already absent".format(path) + ret["comment"] = f"Export {path} already absent" ret["result"] = True return ret diff --git a/salt/states/nftables.py b/salt/states/nftables.py index 71c6e997eed..fa9a33fb929 100644 --- a/salt/states/nftables.py +++ b/salt/states/nftables.py @@ -157,10 +157,10 @@ def chain_present( return ret if __opts__["test"]: - ret[ - "comment" - ] = "nftables chain {} would be created in table {} for family {}".format( - name, table, family + ret["comment"] = ( + "nftables chain {} would be created in table {} for family {}".format( + name, table, family + ) ) return ret @@ -198,10 +198,10 @@ def chain_absent(name, table="filter", family="ipv4"): chain_check = __salt__["nftables.check_chain"](table, name, family) if not chain_check: ret["result"] = True - ret[ - "comment" - ] = "nftables {} chain is already absent in {} table for {}".format( - name, table, family + ret["comment"] = ( + "nftables {} chain is already absent in {} table for {}".format( + name, table, family + ) ) return ret @@ -211,10 +211,10 @@ def chain_absent(name, table="filter", family="ipv4"): if command is True: ret["changes"] = {"locale": name} ret["result"] = True - ret[ - "comment" - ] = "nftables {} chain in {} table delete success for {}".format( - name, table, family + ret["comment"] = ( + "nftables {} chain in {} table delete success for {}".format( + name, table, family + ) ) else: ret["result"] = False @@ -286,18 +286,18 @@ def append(name, family="ipv4", **kwargs): if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) - ret[ - "comment" - ] = "Set and Saved nftables rule for {} to: {} for {}".format( - name, command.strip(), family + ret["comment"] = ( + "Set and Saved nftables rule for {} to: {} for {}".format( + name, command.strip(), family + ) ) return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set nftables rule for {}.\nAttempted rule was {} for {}.\n{}".format( - name, command.strip(), family, res["comment"] + ret["comment"] = ( + "Failed to set nftables rule for {}.\nAttempted rule was {} for {}.\n{}".format( + name, command.strip(), family, res["comment"] + ) ) return ret @@ -361,18 +361,18 @@ def insert(name, family="ipv4", **kwargs): if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) - ret[ - "comment" - ] = "Set and Saved nftables rule for {} to: {} for {}".format( - name, command.strip(), family + ret["comment"] = ( + "Set and Saved nftables rule for {} to: {} for {}".format( + name, command.strip(), family + ) ) return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to set nftables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to set nftables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -438,22 +438,22 @@ def delete(name, family="ipv4", **kwargs): if res["result"]: ret["changes"] = {"locale": name} ret["result"] = True - ret["comment"] = "Delete nftables rule for {} {}".format(name, command.strip()) + ret["comment"] = f"Delete nftables rule for {name} {command.strip()}" if "save" in kwargs: if kwargs["save"]: __salt__["nftables.save"](filename=None, family=family) - ret[ - "comment" - ] = "Deleted and Saved nftables rule for {} for {}{}".format( - name, command.strip(), family + ret["comment"] = ( + "Deleted and Saved nftables rule for {} for {}{}".format( + name, command.strip(), family + ) ) return ret else: ret["result"] = False - ret[ - "comment" - ] = "Failed to delete nftables rule for {}.\nAttempted rule was {}".format( - name, command.strip() + ret["comment"] = ( + "Failed to delete nftables rule for {}.\nAttempted rule was {}".format( + name, command.strip() + ) ) return ret @@ -492,10 +492,10 @@ def flush(name, family="ipv4", ignore_absence=False, **kwargs): check_table = __salt__["nftables.check_table"](kwargs["table"], family=family) if not ignore_absence and not check_table["result"]: ret["result"] = False - ret[ - "comment" - ] = "Failed to flush table {} in family {}, table does not exist.".format( - kwargs["table"], family + ret["comment"] = ( + "Failed to flush table {} in family {}, table does not exist.".format( + kwargs["table"], family + ) ) return ret @@ -562,10 +562,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): if (policy or "").lower() == kwargs["policy"].lower(): ret["result"] = True - ret[ - "comment" - ] = "nftables default policy for chain {} on table {} for {} already set to {}".format( - kwargs["chain"], table, family, kwargs["policy"] + ret["comment"] = ( + "nftables default policy for chain {} on table {} for {} already set to {}".format( + kwargs["chain"], table, family, kwargs["policy"] + ) ) return ret @@ -590,10 +590,10 @@ def set_policy(name, table="filter", family="ipv4", **kwargs): __salt__["nftables.save"]( filename=kwargs.get("save_filename"), family=family ) - ret[ - "comment" - ] = "Set and saved default policy for {} to {} family {}".format( - kwargs["chain"], kwargs["policy"], family + ret["comment"] = ( + "Set and saved default policy for {} to {} family {}".format( + kwargs["chain"], kwargs["policy"], family + ) ) else: ret["result"] = False @@ -642,7 +642,7 @@ def table_present(name, family="ipv4", **kwargs): ) else: ret["result"] = False - ret["comment"] = "Failed to create table {} for family {}".format(name, family) + ret["comment"] = f"Failed to create table {name} for family {family}" return ret @@ -687,6 +687,6 @@ def table_absent(name, family="ipv4", **kwargs): ) else: ret["result"] = False - ret["comment"] = "Failed to delete table {} from family {}".format(name, family) + ret["comment"] = f"Failed to delete table {name} from family {family}" return ret diff --git a/salt/states/npm.py b/salt/states/npm.py index 535a516a1d4..1e8b942f90c 100644 --- a/salt/states/npm.py +++ b/salt/states/npm.py @@ -18,7 +18,6 @@ for the package which provides npm (simply ``npm`` in most cases). Example: - pkg: npm """ - import re from salt.exceptions import CommandExecutionError, CommandNotFoundError @@ -95,7 +94,7 @@ def installed( installed_pkgs = __salt__["npm.list"](dir=dir, runas=user, env=env, depth=0) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error looking up '{}': {}".format(name, err) + ret["comment"] = f"Error looking up '{name}': {err}" return ret else: installed_pkgs = {p: info for p, info in installed_pkgs.items()} @@ -239,26 +238,26 @@ def removed(name, dir=None, user=None): installed_pkgs = __salt__["npm.list"](dir=dir, depth=0) except (CommandExecutionError, CommandNotFoundError) as err: ret["result"] = False - ret["comment"] = "Error uninstalling '{}': {}".format(name, err) + ret["comment"] = f"Error uninstalling '{name}': {err}" return ret if name not in installed_pkgs: ret["result"] = True - ret["comment"] = "Package '{}' is not installed".format(name) + ret["comment"] = f"Package '{name}' is not installed" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Package '{}' is set to be removed".format(name) + ret["comment"] = f"Package '{name}' is set to be removed" return ret if __salt__["npm.uninstall"](pkg=name, dir=dir, runas=user): ret["result"] = True ret["changes"][name] = "Removed" - ret["comment"] = "Package '{}' was successfully removed".format(name) + ret["comment"] = f"Package '{name}' was successfully removed" else: ret["result"] = False - ret["comment"] = "Error removing package '{}'".format(name) + ret["comment"] = f"Error removing package '{name}'" return ret @@ -284,20 +283,20 @@ def bootstrap(name, user=None, silent=True): if call: ret["result"] = None ret["changes"] = {"old": [], "new": call} - ret["comment"] = "{} is set to be bootstrapped".format(name) + ret["comment"] = f"{name} is set to be bootstrapped" else: ret["result"] = True - ret["comment"] = "{} is already bootstrapped".format(name) + ret["comment"] = f"{name} is already bootstrapped" except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error Bootstrapping '{}': {}".format(name, err) + ret["comment"] = f"Error Bootstrapping '{name}': {err}" return ret try: call = __salt__["npm.install"](dir=name, runas=user, pkg=None, silent=silent) except (CommandNotFoundError, CommandExecutionError) as err: ret["result"] = False - ret["comment"] = "Error Bootstrapping '{}': {}".format(name, err) + ret["comment"] = f"Error Bootstrapping '{name}': {err}" return ret if not call: @@ -351,11 +350,11 @@ def cache_cleaned(name=None, user=None, force=False): all_cached_pkgs = __salt__["npm.cache_list"](path=None, runas=user) # The first package is always the cache path cache_root_path = all_cached_pkgs[0] - specific_pkg = "{}/{}/".format(cache_root_path, name) + specific_pkg = f"{cache_root_path}/{name}/" if specific_pkg not in cached_pkgs: ret["result"] = True - ret["comment"] = "Package {} is not in the cache".format(name) + ret["comment"] = f"Package {name} is not in the cache" return ret if __opts__["test"]: diff --git a/salt/states/nxos.py b/salt/states/nxos.py index 6888413e859..6d413d45548 100644 --- a/salt/states/nxos.py +++ b/salt/states/nxos.py @@ -352,7 +352,7 @@ def replace(name, repl, full_match=False): ret = {"name": name, "result": False, "changes": {}, "comment": ""} if full_match is False: - search = "^.*{}.*$".format(name) + search = f"^.*{name}.*$" else: search = name @@ -376,7 +376,7 @@ def replace(name, repl, full_match=False): if matches: ret["result"] = False - ret["comment"] = 'Failed to replace all instances of "{}"'.format(name) + ret["comment"] = f'Failed to replace all instances of "{name}"' else: ret["result"] = True ret["comment"] = 'Successfully replaced all instances of "{}" with "{}"'.format( diff --git a/salt/states/nxos_upgrade.py b/salt/states/nxos_upgrade.py index daa22f6fcfc..f4960b777be 100644 --- a/salt/states/nxos_upgrade.py +++ b/salt/states/nxos_upgrade.py @@ -90,7 +90,7 @@ def image_running(name, system_image, kickstart_image=None, issu=True, **kwargs) system_image=system_image, kickstart_image=kickstart_image, issu=issu, - **kwargs + **kwargs, ) if upgrade["upgrade_in_progress"]: @@ -99,7 +99,7 @@ def image_running(name, system_image, kickstart_image=None, issu=True, **kwargs) ret["comment"] = "NX-OS Device Now Being Upgraded - See Change Details Below" elif upgrade["succeeded"]: ret["result"] = upgrade["succeeded"] - ret["comment"] = "NX-OS Device Running Image: {}".format(_version_info()) + ret["comment"] = f"NX-OS Device Running Image: {_version_info()}" else: ret["comment"] = "Upgrade Failed: {}.".format(upgrade["error_data"]) diff --git a/salt/states/openstack_config.py b/salt/states/openstack_config.py index e9154d57a4f..bad221a802a 100644 --- a/salt/states/openstack_config.py +++ b/salt/states/openstack_config.py @@ -8,7 +8,6 @@ Manage OpenStack configuration file settings. """ - from salt.exceptions import CommandExecutionError @@ -113,7 +112,7 @@ def absent(name, filename, section, parameter=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Value '{}' is set to be deleted.".format(old_value) + ret["comment"] = f"Value '{old_value}' is set to be deleted." return ret __salt__["openstack_config.delete"]( diff --git a/salt/states/openvswitch_port.py b/salt/states/openvswitch_port.py index 3ca769b1e37..a4591c6da12 100644 --- a/salt/states/openvswitch_port.py +++ b/salt/states/openvswitch_port.py @@ -47,24 +47,24 @@ def present( comments = {} - comments["comment_bridge_notexists"] = "Bridge {} does not exist.".format(bridge) - comments["comment_port_exists"] = "Port {} already exists.".format(name) + comments["comment_bridge_notexists"] = f"Bridge {bridge} does not exist." + comments["comment_port_exists"] = f"Port {name} already exists." comments["comment_port_created"] = "Port {} created on bridge {}.".format( name, bridge ) - comments[ - "comment_port_notcreated" - ] = "Unable to create port {} on bridge {}.".format(name, bridge) + comments["comment_port_notcreated"] = ( + f"Unable to create port {name} on bridge {bridge}." + ) comments["changes_port_created"] = { name: { - "old": "No port named {} present.".format(name), - "new": "Created port {1} on bridge {0}.".format(bridge, name), + "old": f"No port named {name} present.", + "new": f"Created port {name} on bridge {bridge}.", } } - comments[ - "comment_port_internal" - ] = "Port {} already exists, but interface type has been changed to internal.".format( - name + comments["comment_port_internal"] = ( + "Port {} already exists, but interface type has been changed to internal.".format( + name + ) ) comments["changes_port_internal"] = {"internal": {"old": False, "new": True}} comments["comment_port_internal_not_changed"] = ( @@ -76,23 +76,23 @@ def present( comments["comment_invalid_ip"] = "Remote is not valid ip address." if tunnel_type == "vlan": comments["comment_vlan_invalid_id"] = "VLANs id must be between 0 and 4095." - comments[ - "comment_vlan_invalid_name" - ] = "Could not find network interface {}.".format(name) - comments[ - "comment_vlan_port_exists" - ] = "Port {} with access to VLAN {} already exists on bridge {}.".format( - name, id, bridge + comments["comment_vlan_invalid_name"] = ( + f"Could not find network interface {name}." ) - comments[ - "comment_vlan_created" - ] = "Created port {} with access to VLAN {} on bridge {}.".format( - name, id, bridge + comments["comment_vlan_port_exists"] = ( + "Port {} with access to VLAN {} already exists on bridge {}.".format( + name, id, bridge + ) ) - comments[ - "comment_vlan_notcreated" - ] = "Unable to create port {} with access to VLAN {} on bridge {}.".format( - name, id, bridge + comments["comment_vlan_created"] = ( + "Created port {} with access to VLAN {} on bridge {}.".format( + name, id, bridge + ) + ) + comments["comment_vlan_notcreated"] = ( + "Unable to create port {} with access to VLAN {} on bridge {}.".format( + name, id, bridge + ) ) comments["changes_vlan_created"] = { name: { @@ -108,9 +108,9 @@ def present( } elif tunnel_type == "gre": - comments[ - "comment_gre_invalid_id" - ] = "Id of GRE tunnel must be an unsigned 32-bit integer." + comments["comment_gre_invalid_id"] = ( + "Id of GRE tunnel must be an unsigned 32-bit integer." + ) comments["comment_gre_interface_exists"] = ( "GRE tunnel interface {} with rempte ip {} and key {} " "already exists on bridge {}.".format(name, remote, id, bridge) @@ -139,9 +139,9 @@ def present( comments["comment_dstport"] = ( " (dst_port" + str(dst_port) + ")" if 0 < dst_port <= 65535 else "" ) - comments[ - "comment_vxlan_invalid_id" - ] = "Id of VXLAN tunnel must be an unsigned 64-bit integer." + comments["comment_vxlan_invalid_id"] = ( + "Id of VXLAN tunnel must be an unsigned 64-bit integer." + ) comments["comment_vxlan_interface_exists"] = ( "VXLAN tunnel interface {} with rempte ip {} and key {} " "already exists on bridge {}{}.".format( @@ -234,11 +234,7 @@ def present( 'dst_port="' + str(dst_port) + '", ' if 0 < dst_port <= 65535 else "" ) interface_attroptions = ( - '{{{0}key="'.format(opt_port) - + str(id) - + '", remote_ip="' - + str(remote) - + '"}' + f'{{{opt_port}key="' + str(id) + '", remote_ip="' + str(remote) + '"}' ) try: if ( @@ -388,16 +384,16 @@ def absent(name, bridge=None): # Comment and change messages comments = {} - comments["comment_bridge_notexists"] = "Bridge {} does not exist.".format(bridge) + comments["comment_bridge_notexists"] = f"Bridge {bridge} does not exist." comments["comment_port_notexists"] = "Port {} does not exist on bridge {}.".format( name, bridge ) - comments["comment_port_deleted"] = "Port {} deleted.".format(name) - comments["comment_port_notdeleted"] = "Unable to delete port {}.".format(name) + comments["comment_port_deleted"] = f"Port {name} deleted." + comments["comment_port_notdeleted"] = f"Unable to delete port {name}." comments["changes_port_deleted"] = { name: { - "old": "Port named {} may exist.".format(name), - "new": "Deleted port {}.".format(name), + "old": f"Port named {name} may exist.", + "new": f"Deleted port {name}.", } } diff --git a/salt/states/opsgenie.py b/salt/states/opsgenie.py index 8e80bf2ef90..f7cafcccfd9 100644 --- a/salt/states/opsgenie.py +++ b/salt/states/opsgenie.py @@ -75,10 +75,10 @@ def create_alert(name=None, api_key=None, reason=None, action_type="Create"): raise salt.exceptions.SaltInvocationError("API Key or Reason cannot be None.") if __opts__["test"] is True: - ret[ - "comment" - ] = 'Test: {} alert request will be processed using the API Key="{}".'.format( - action_type, api_key + ret["comment"] = ( + 'Test: {} alert request will be processed using the API Key="{}".'.format( + action_type, api_key + ) ) # Return ``None`` when running with ``test=true``. @@ -96,10 +96,10 @@ def create_alert(name=None, api_key=None, reason=None, action_type="Create"): response_text, response_status_code, ) - ret[ - "comment" - ] = 'Test: {} alert request will be processed using the API Key="{}".'.format( - action_type, api_key + ret["comment"] = ( + 'Test: {} alert request will be processed using the API Key="{}".'.format( + action_type, api_key + ) ) ret["result"] = True else: diff --git a/salt/states/pagerduty.py b/salt/states/pagerduty.py index bfdd82f28ac..2be04eff915 100644 --- a/salt/states/pagerduty.py +++ b/salt/states/pagerduty.py @@ -57,7 +57,7 @@ def create_event(name, details, service_key, profile): """ ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __opts__["test"]: - ret["comment"] = "Need to create event: {}".format(name) + ret["comment"] = f"Need to create event: {name}" return ret __salt__["pagerduty.create_event"]( description=name, @@ -66,5 +66,5 @@ def create_event(name, details, service_key, profile): profile=profile, ) ret["result"] = True - ret["comment"] = "Created event: {}".format(name) + ret["comment"] = f"Created event: {name}" return ret diff --git a/salt/states/pagerduty_escalation_policy.py b/salt/states/pagerduty_escalation_policy.py index 44e663e4ea3..3b3594587d4 100644 --- a/salt/states/pagerduty_escalation_policy.py +++ b/salt/states/pagerduty_escalation_policy.py @@ -96,7 +96,7 @@ def present(profile="pagerduty", subdomain=None, api_key=None, **kwargs): if schedule: target_id = schedule["schedule"]["id"] if target_id is None: - raise Exception("unidentified target: {}".format(target)) + raise Exception(f"unidentified target: {target}") target["id"] = target_id r = __salt__["pagerduty_util.resource_present"]( @@ -106,7 +106,7 @@ def present(profile="pagerduty", subdomain=None, api_key=None, **kwargs): profile, subdomain, api_key, - **kwargs + **kwargs, ) return r @@ -143,7 +143,7 @@ def _diff(state_data, resource_object): else: resource_value = resource_object[k] if v != resource_value: - objects_differ = "{} {} {}".format(k, v, resource_value) + objects_differ = f"{k} {v} {resource_value}" break if objects_differ: diff --git a/salt/states/pagerduty_schedule.py b/salt/states/pagerduty_schedule.py index 75f705f6086..5947dbc4b0a 100644 --- a/salt/states/pagerduty_schedule.py +++ b/salt/states/pagerduty_schedule.py @@ -65,7 +65,7 @@ def present(profile="pagerduty", subdomain=None, api_key=None, **kwargs): api_key=api_key, ) if u is None: - raise Exception("unknown user: {}".format(user)) + raise Exception(f"unknown user: {user}") user["user"]["id"] = u["id"] r = __salt__["pagerduty_util.resource_present"]( "schedules", ["name", "id"], _diff, profile, subdomain, api_key, **kwargs diff --git a/salt/states/pagerduty_service.py b/salt/states/pagerduty_service.py index f615aff7a7b..f17c7ef6087 100644 --- a/salt/states/pagerduty_service.py +++ b/salt/states/pagerduty_service.py @@ -110,7 +110,7 @@ def _diff(state_data, resource_object): else: resource_value = resource_object[k] if v != resource_value: - objects_differ = "{} {} {}".format(k, v, resource_value) + objects_differ = f"{k} {v} {resource_value}" break if objects_differ: diff --git a/salt/states/panos.py b/salt/states/panos.py index fb915bbdb78..5ea57dbf0dd 100644 --- a/salt/states/panos.py +++ b/salt/states/panos.py @@ -108,10 +108,10 @@ def _build_members(members, anycheck=False): return "any" response = "" for m in members: - response += "{}".format(m) + response += f"{m}" return response else: - return "{}".format(members) + return f"{members}" def _default_ret(name): @@ -354,19 +354,19 @@ def address_exists( # Verify the arguments if ipnetmask: - element = "{}".format(ipnetmask) + element = f"{ipnetmask}" elif iprange: - element = "{}".format(iprange) + element = f"{iprange}" elif fqdn: - element = "{}".format(fqdn) + element = f"{fqdn}" else: ret.update({"comment": "A valid address type must be specified."}) return ret if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(addressname, element) + full_element = f"{element}" new_address = xml.to_dict(ET.fromstring(full_element), True) @@ -467,15 +467,15 @@ def address_group_exists( # Verify the arguments if members: - element = "{}".format(_build_members(members, True)) + element = f"{_build_members(members, True)}" else: ret.update({"comment": "The group members must be provided."}) return ret if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(groupname, element) + full_element = f"{element}" new_group = xml.to_dict(ET.fromstring(full_element), True) @@ -1117,19 +1117,19 @@ def security_rule_exists( # Build the rule element element = "" if sourcezone: - element += "{}".format(_build_members(sourcezone, True)) + element += f"{_build_members(sourcezone, True)}" else: ret.update({"comment": "The sourcezone field must be provided."}) return ret if destinationzone: - element += "{}".format(_build_members(destinationzone, True)) + element += f"{_build_members(destinationzone, True)}" else: ret.update({"comment": "The destinationzone field must be provided."}) return ret if source: - element += "{}".format(_build_members(source, True)) + element += f"{_build_members(source, True)}" else: ret.update({"comment": "The source field must be provided."}) return @@ -1151,13 +1151,13 @@ def security_rule_exists( return ret if service: - element += "{}".format(_build_members(service, True)) + element += f"{_build_members(service, True)}" else: ret.update({"comment": "The service field must be provided."}) return ret if action: - element += "{}".format(action) + element += f"{action}" else: ret.update({"comment": "The action field must be provided."}) return ret @@ -1169,10 +1169,10 @@ def security_rule_exists( element += "no" if description: - element += "{}".format(description) + element += f"{description}" if logsetting: - element += "{}".format(logsetting) + element += f"{logsetting}" if logstart is not None: if logstart: @@ -1201,7 +1201,7 @@ def security_rule_exists( # Build the profile settings profile_string = None if profilegroup: - profile_string = "{}".format(profilegroup) + profile_string = f"{profilegroup}" else: member_string = "" if datafilter: @@ -1212,16 +1212,16 @@ def security_rule_exists( ) if fileblock: member_string += ( - "{}".format(fileblock) + f"{fileblock}" ) if spyware: - member_string += "{}".format(spyware) + member_string += f"{spyware}" if urlfilter: member_string += ( - "{}".format(urlfilter) + f"{urlfilter}" ) if virus: - member_string += "{}".format(virus) + member_string += f"{virus}" if vulnerability: member_string += ( "{}".format( @@ -1235,12 +1235,12 @@ def security_rule_exists( ) ) if member_string != "": - profile_string = "{}".format(member_string) + profile_string = f"{member_string}" if profile_string: - element += "{}".format(profile_string) + element += f"{profile_string}" - full_element = "{}".format(rulename, element) + full_element = f"{element}" new_rule = xml.to_dict(ET.fromstring(full_element), True) @@ -1380,9 +1380,9 @@ def service_exists( element = "<{0}>{1}".format(protocol, port) if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(servicename, element) + full_element = f"{element}" new_service = xml.to_dict(ET.fromstring(full_element), True) @@ -1483,15 +1483,15 @@ def service_group_exists( # Verify the arguments if members: - element = "{}".format(_build_members(members, True)) + element = f"{_build_members(members, True)}" else: ret.update({"comment": "The group members must be provided."}) return ret if description: - element += "{}".format(description) + element += f"{description}" - full_element = "{}".format(groupname, element) + full_element = f"{element}" new_group = xml.to_dict(ET.fromstring(full_element), True) diff --git a/salt/states/pbm.py b/salt/states/pbm.py index ae21462ea47..8b2c3eb2a4b 100644 --- a/salt/states/pbm.py +++ b/salt/states/pbm.py @@ -90,7 +90,6 @@ PyVmomi can be installed via pip: information. """ - import copy import logging import sys @@ -153,7 +152,7 @@ def default_vsan_policy_configured(name, policy): # All allowed proxies have a shim execution module with the same # name which implementes a get_details function # All allowed proxies have a vcenter detail - vcenter = __salt__["{}.get_details".format(proxy_type)]()["vcenter"] + vcenter = __salt__[f"{proxy_type}.get_details"]()["vcenter"] log.info("Running %s on vCenter '%s'", name, vcenter) log.trace("policy = %s", policy) changes_required = False @@ -215,7 +214,7 @@ def default_vsan_policy_configured(name, policy): if subprofile_differ.diffs: str_changes.extend( [ - " {}".format(change) + f" {change}" for change in subprofile_differ.changes_str.split("\n") ] ) @@ -223,7 +222,7 @@ def default_vsan_policy_configured(name, policy): str_changes.append(" capabilities:") str_changes.extend( [ - " {}".format(change) + f" {change}" for change in capabilities_differ.changes_str2.split( "\n" ) @@ -241,7 +240,7 @@ def default_vsan_policy_configured(name, policy): service_instance=si, ) comments.append( - "Updated the default VSAN policy in vCenter '{}'".format(vcenter) + f"Updated the default VSAN policy in vCenter '{vcenter}'" ) log.info(comments[-1]) @@ -320,7 +319,7 @@ def storage_policies_configured(name, policies): # All allowed proxies have a shim execution module with the same # name which implementes a get_details function # All allowed proxies have a vcenter detail - vcenter = __salt__["{}.get_details".format(proxy_type)]()["vcenter"] + vcenter = __salt__[f"{proxy_type}.get_details"]()["vcenter"] log.info("Running state '%s' on vCenter '%s'", name, vcenter) si = __salt__["vsphere.get_service_instance_via_proxy"]() current_policies = __salt__["vsphere.list_storage_policies"]( @@ -402,7 +401,7 @@ def storage_policies_configured(name, policies): if subprofile_differ.diffs: str_changes.extend( [ - " {}".format(change) + f" {change}" for change in subprofile_differ.changes_str.split( "\n" ) @@ -412,7 +411,7 @@ def storage_policies_configured(name, policies): str_changes.append(" capabilities:") str_changes.extend( [ - " {}".format(change) + f" {change}" for change in capabilities_differ.changes_str2.split( "\n" ) diff --git a/salt/states/pecl.py b/salt/states/pecl.py index a69a2ca1cb1..e690b5a01e9 100644 --- a/salt/states/pecl.py +++ b/salt/states/pecl.py @@ -73,25 +73,25 @@ def installed( version is None or version in installed_pecls[package] ) and preferred_state in installed_pecls[package]: ret["result"] = True - ret["comment"] = "Pecl extension {} is already installed.".format(name) + ret["comment"] = f"Pecl extension {name} is already installed." return ret if version is not None: # Modify the name to include the version and proceed. - name = "{}-{}".format(name, version) + name = f"{name}-{version}" if __opts__["test"]: - ret["comment"] = "Pecl extension {} would have been installed".format(name) + ret["comment"] = f"Pecl extension {name} would have been installed" return ret if __salt__["pecl.install"]( name, defaults=defaults, force=force, preferred_state=preferred_state ): ret["result"] = True ret["changes"][name] = "Installed" - ret["comment"] = "Pecl extension {} was successfully installed".format(name) + ret["comment"] = f"Pecl extension {name} was successfully installed" else: ret["result"] = False - ret["comment"] = "Could not install pecl extension {}.".format(name) + ret["comment"] = f"Could not install pecl extension {name}." return ret @@ -106,17 +106,17 @@ def removed(name): ret = {"name": name, "result": None, "comment": "", "changes": {}} if name not in __salt__["pecl.list"](): ret["result"] = True - ret["comment"] = "Pecl extension {} is not installed.".format(name) + ret["comment"] = f"Pecl extension {name} is not installed." return ret if __opts__["test"]: - ret["comment"] = "Pecl extension {} would have been removed".format(name) + ret["comment"] = f"Pecl extension {name} would have been removed" return ret if __salt__["pecl.uninstall"](name): ret["result"] = True ret["changes"][name] = "Removed" - ret["comment"] = "Pecl extension {} was successfully removed.".format(name) + ret["comment"] = f"Pecl extension {name} was successfully removed." else: ret["result"] = False - ret["comment"] = "Could not remove pecl extension {}.".format(name) + ret["comment"] = f"Could not remove pecl extension {name}." return ret diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index bb23f715e83..a262e16261e 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -18,7 +18,6 @@ requisite to a pkg.installed state for the package which provides pip - pkg: python-pip """ - import logging import re import sys @@ -754,8 +753,8 @@ def installed( # prepro = lambda pkg: pkg if type(pkg) == str else \ # ' '.join((pkg.items()[0][0], pkg.items()[0][1].replace(',', ';'))) # pkgs = ','.join([prepro(pkg) for pkg in pkgs]) - prepro = ( - lambda pkg: pkg + prepro = lambda pkg: ( + pkg if isinstance(pkg, str) else " ".join((pkg.items()[0][0], pkg.items()[0][1])) ) diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 13a9edd0fb4..1e7336749cd 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -67,6 +67,7 @@ state module Make sure the package name has the correct case for package managers which are case-sensitive (such as :mod:`pkgng `). """ + import fnmatch import logging import os @@ -1953,10 +1954,10 @@ def installed( ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = "An error was encountered while installing package(s): {}".format( - exc + ret["comment"] = ( + "An error was encountered while installing package(s): {}".format( + exc + ) ) if warnings: ret.setdefault("warnings", []).extend(warnings) @@ -2368,9 +2369,9 @@ def downloaded( ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = f"An error was encountered while downloading package(s): {exc}" + ret["comment"] = ( + f"An error was encountered while downloading package(s): {exc}" + ) return ret new_pkgs = __salt__["pkg.list_downloaded"](**kwargs) @@ -2425,9 +2426,9 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): if "pkg.list_patches" not in __salt__: ret["result"] = False - ret[ - "comment" - ] = "The pkg.patch_installed state is not available on this platform" + ret["comment"] = ( + "The pkg.patch_installed state is not available on this platform" + ) return ret if isinstance(advisory_ids, list) and len(advisory_ids) == 0: @@ -2448,9 +2449,9 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): if __opts__["test"]: summary = ", ".join(targets) - ret[ - "comment" - ] = f"The following advisory patches would be downloaded: {summary}" + ret["comment"] = ( + f"The following advisory patches would be downloaded: {summary}" + ) return ret try: @@ -2467,18 +2468,18 @@ def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs): ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = f"An error was encountered while downloading package(s): {exc}" + ret["comment"] = ( + f"An error was encountered while downloading package(s): {exc}" + ) return ret if not ret["changes"] and not ret["comment"]: status = "downloaded" if downloadonly else "installed" ret["result"] = True - ret[ - "comment" - ] = "Advisory patch is not needed or related packages are already {}".format( - status + ret["comment"] = ( + "Advisory patch is not needed or related packages are already {}".format( + status + ) ) return ret @@ -3164,9 +3165,9 @@ def removed(name, version=None, pkgs=None, normalize=True, ignore_epoch=None, ** ret["comment"] = exc.strerror_without_changes else: ret["changes"] = {} - ret[ - "comment" - ] = f"An error was encountered while removing package(s): {exc}" + ret["comment"] = ( + f"An error was encountered while removing package(s): {exc}" + ) return ret @@ -3491,19 +3492,19 @@ def group_installed(name, skip=None, include=None, **kwargs): if "unexpected keyword argument" in str(err): ret["comment"] = "Repo options are not supported on this platform" else: - ret[ - "comment" - ] = f"An error was encountered while installing/updating group '{name}': {err}." + ret["comment"] = ( + f"An error was encountered while installing/updating group '{name}': {err}." + ) return ret mandatory = diff["mandatory"]["installed"] + diff["mandatory"]["not installed"] invalid_skip = [x for x in mandatory if x in skip] if invalid_skip: - ret[ - "comment" - ] = "The following mandatory packages cannot be skipped: {}".format( - ", ".join(invalid_skip) + ret["comment"] = ( + "The following mandatory packages cannot be skipped: {}".format( + ", ".join(invalid_skip) + ) ) return ret @@ -3525,9 +3526,9 @@ def group_installed(name, skip=None, include=None, **kwargs): if __opts__["test"]: ret["result"] = None if partially_installed: - ret[ - "comment" - ] = f"Group '{name}' is partially installed and will be updated" + ret["comment"] = ( + f"Group '{name}' is partially installed and will be updated" + ) else: ret["comment"] = f"Group '{name}' will be installed" return ret diff --git a/salt/states/pkgbuild.py b/salt/states/pkgbuild.py index 68725fc362b..7888e97bb59 100644 --- a/salt/states/pkgbuild.py +++ b/salt/states/pkgbuild.py @@ -330,7 +330,7 @@ def repo( if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Package repo metadata at {} will be refreshed".format(name) + ret["comment"] = f"Package repo metadata at {name} will be refreshed" return ret # Need the check for None here, if env is not provided then it falls back diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py index 25959da679c..35b8d3896b8 100644 --- a/salt/states/pkgrepo.py +++ b/salt/states/pkgrepo.py @@ -117,7 +117,6 @@ Using ``aptkey: False`` with ``keyserver`` and ``keyid``: - aptkey: False """ - import sys import salt.utils.data @@ -365,15 +364,15 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): if "key_url" in kwargs and ("keyid" in kwargs or "keyserver" in kwargs): ret["result"] = False - ret[ - "comment" - ] = 'You may not use both "keyid"/"keyserver" and "key_url" argument.' + ret["comment"] = ( + 'You may not use both "keyid"/"keyserver" and "key_url" argument.' + ) if "key_text" in kwargs and ("keyid" in kwargs or "keyserver" in kwargs): ret["result"] = False - ret[ - "comment" - ] = 'You may not use both "keyid"/"keyserver" and "key_text" argument.' + ret["comment"] = ( + 'You may not use both "keyid"/"keyserver" and "key_text" argument.' + ) if "key_text" in kwargs and ("key_url" in kwargs): ret["result"] = False ret["comment"] = 'You may not use both "key_url" and "key_text" argument.' @@ -409,9 +408,9 @@ def managed(name, ppa=None, copr=None, aptkey=True, **kwargs): ) else: ret["result"] = False - ret[ - "comment" - ] = "Cannot have 'key_url' using http with 'allow_insecure_key' set to True" + ret["comment"] = ( + "Cannot have 'key_url' using http with 'allow_insecure_key' set to True" + ) return ret repo = name diff --git a/salt/states/ports.py b/salt/states/ports.py index b4e53c4a6a7..072bb7bf4f4 100644 --- a/salt/states/ports.py +++ b/salt/states/ports.py @@ -49,7 +49,7 @@ def _get_option_list(options): Returns the key/value pairs in the passed dict in a commaspace-delimited list in the format "key=value". """ - return ", ".join(["{}={}".format(x, y) for x, y in options.items()]) + return ", ".join([f"{x}={y}" for x, y in options.items()]) def _build_option_string(options): @@ -57,7 +57,7 @@ def _build_option_string(options): Common function to get a string to append to the end of the state comment """ if options: - return "with the following build options: {}".format(_get_option_list(options)) + return f"with the following build options: {_get_option_list(options)}" else: return "with the default build options" @@ -89,7 +89,7 @@ def installed(name, options=None): "name": name, "changes": {}, "result": True, - "comment": "{} is already installed".format(name), + "comment": f"{name} is already installed", } try: current_options = __salt__["ports.showconfig"]( @@ -128,44 +128,44 @@ def installed(name, options=None): if not default_options: if options: ret["result"] = False - ret[ - "comment" - ] = "{} does not have any build options, yet options were specified".format( - name + ret["comment"] = ( + "{} does not have any build options, yet options were specified".format( + name + ) ) return ret else: if __opts__["test"]: ret["result"] = None - ret["comment"] = "{} will be installed".format(name) + ret["comment"] = f"{name} will be installed" return ret else: bad_opts = [x for x in options if x not in default_options] if bad_opts: ret["result"] = False - ret[ - "comment" - ] = "The following options are not available for {}: {}".format( - name, ", ".join(bad_opts) + ret["comment"] = ( + "The following options are not available for {}: {}".format( + name, ", ".join(bad_opts) + ) ) return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "{} will be installed ".format(name) + ret["comment"] = f"{name} will be installed " ret["comment"] += _build_option_string(options) return ret if options: if not __salt__["ports.config"](name, reset=True, **options): ret["result"] = False - ret["comment"] = "Unable to set options for {}".format(name) + ret["comment"] = f"Unable to set options for {name}" return ret else: __salt__["ports.rmconfig"](name) if _options_file_exists(name): ret["result"] = False - ret["comment"] = "Unable to clear options for {}".format(name) + ret["comment"] = f"Unable to clear options for {name}" return ret ret["changes"] = __salt__["ports.install"](name) @@ -178,11 +178,11 @@ def installed(name, options=None): if err or name not in ports_post: ret["result"] = False if ret["result"]: - ret["comment"] = "Successfully installed {}".format(name) + ret["comment"] = f"Successfully installed {name}" if default_options: ret["comment"] += " " + _build_option_string(options) else: - ret["comment"] = "Failed to install {}".format(name) + ret["comment"] = f"Failed to install {name}" if err: - ret["comment"] += ". Error message:\n{}".format(err) + ret["comment"] += f". Error message:\n{err}" return ret diff --git a/salt/states/postgres_cluster.py b/salt/states/postgres_cluster.py index de98d5ab92f..bbcf42eb5ce 100644 --- a/salt/states/postgres_cluster.py +++ b/salt/states/postgres_cluster.py @@ -70,13 +70,13 @@ def present( .. versionadded:: 2016.3.0 """ - msg = "Cluster {}/{} is already present".format(version, name) + msg = f"Cluster {version}/{name} is already present" ret = {"name": name, "changes": {}, "result": True, "comment": msg} if __salt__["postgres.cluster_exists"](version, name): # check cluster config is correct infos = __salt__["postgres.cluster_list"](verbose=True) - info = infos["{}/{}".format(version, name)] + info = infos[f"{version}/{name}"] # TODO: check locale en encoding configs also if any( ( @@ -111,7 +111,7 @@ def present( if cluster: msg = "The cluster {0}/{1} has been created" ret["comment"] = msg.format(version, name) - ret["changes"]["{}/{}".format(version, name)] = "Present" + ret["changes"][f"{version}/{name}"] = "Present" else: msg = "Failed to create cluster {0}/{1}" ret["comment"] = msg.format(version, name) diff --git a/salt/states/postgres_database.py b/salt/states/postgres_database.py index eaeec035273..dfe2cfcd998 100644 --- a/salt/states/postgres_database.py +++ b/salt/states/postgres_database.py @@ -124,17 +124,19 @@ def present( return ret elif name in dbs and any( ( - db_params.get("Encoding").lower() != encoding.lower() - if encoding - else False, + ( + db_params.get("Encoding").lower() != encoding.lower() + if encoding + else False + ), db_params.get("Collate") != lc_collate if lc_collate else False, db_params.get("Ctype") != lc_ctype if lc_ctype else False, ) ): - ret[ - "comment" - ] = "Database {} has wrong parameters which couldn't be changed on fly.".format( - name + ret["comment"] = ( + "Database {} has wrong parameters which couldn't be changed on fly.".format( + name + ) ) ret["result"] = False return ret @@ -145,9 +147,9 @@ def present( if name not in dbs: ret["comment"] = f"Database {name} is set to be created" else: - ret[ - "comment" - ] = f"Database {name} exists, but parameters need to be changed" + ret["comment"] = ( + f"Database {name} exists, but parameters need to be changed" + ) return ret if name not in dbs and __salt__["postgres.db_create"]( name, diff --git a/salt/states/postgres_extension.py b/salt/states/postgres_extension.py index 963b9caa5ff..91726fbd58e 100644 --- a/salt/states/postgres_extension.py +++ b/salt/states/postgres_extension.py @@ -93,7 +93,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Extension {} is already present".format(name), + "comment": f"Extension {name} is already present", } db_args = { "maintenance_db": maintenance_db, @@ -135,17 +135,17 @@ def present( schema=schema, ext_version=ext_version, from_version=from_version, - **db_args + **db_args, ) if cret: if mode.endswith("e"): suffix = "d" else: suffix = "ed" - ret["comment"] = "The extension {} has been {}{}".format(name, mode, suffix) - ret["changes"][name] = "{}{}".format(mode.capitalize(), suffix) + ret["comment"] = f"The extension {name} has been {mode}{suffix}" + ret["changes"][name] = f"{mode.capitalize()}{suffix}" elif cret is not None: - ret["comment"] = "Failed to {1} extension {0}".format(name, mode) + ret["comment"] = f"Failed to {mode} extension {name}" ret["result"] = False return ret @@ -210,17 +210,17 @@ def absent( if exists: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Extension {} is set to be removed".format(name) + ret["comment"] = f"Extension {name} is set to be removed" return ret if __salt__["postgres.drop_extension"]( name, if_exists=if_exists, restrict=restrict, cascade=cascade, **db_args ): - ret["comment"] = "Extension {} has been removed".format(name) + ret["comment"] = f"Extension {name} has been removed" ret["changes"][name] = "Absent" return ret else: ret["result"] = False - ret["comment"] = "Extension {} failed to be removed".format(name) + ret["comment"] = f"Extension {name} failed to be removed" return ret else: ret["comment"] = "Extension {} is not present, so it cannot be removed".format( diff --git a/salt/states/postgres_group.py b/salt/states/postgres_group.py index 01209ddfd43..2668f01bc90 100644 --- a/salt/states/postgres_group.py +++ b/salt/states/postgres_group.py @@ -138,7 +138,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Group {} is already present".format(name), + "comment": f"Group {name} is already present", } # default to encrypted passwords @@ -210,9 +210,9 @@ def present( if update: ret["changes"][name] = update ret["result"] = None - ret["comment"] = "Group {} is set to be {}d".format(name, mode) + ret["comment"] = f"Group {name} is set to be {mode}d" return ret - cret = __salt__["postgres.group_{}".format(mode)]( + cret = __salt__[f"postgres.group_{mode}"]( groupname=name, createdb=createdb, createroles=createroles, @@ -223,19 +223,19 @@ def present( replication=replication, rolepassword=password, groups=groups, - **db_args + **db_args, ) else: cret = None if cret: - ret["comment"] = "The group {} has been {}d".format(name, mode) + ret["comment"] = f"The group {name} has been {mode}d" if update: ret["changes"][name] = update else: ret["changes"][name] = "Present" elif cret is not None: - ret["comment"] = "Failed to {} group {}".format(mode, name) + ret["comment"] = f"Failed to {mode} group {name}" ret["result"] = False else: ret["result"] = True @@ -289,17 +289,17 @@ def absent( if __salt__["postgres.user_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Group {} is set to be removed".format(name) + ret["comment"] = f"Group {name} is set to be removed" return ret if __salt__["postgres.group_remove"](name, **db_args): - ret["comment"] = "Group {} has been removed".format(name) + ret["comment"] = f"Group {name} has been removed" ret["changes"][name] = "Absent" return ret else: ret["result"] = False - ret["comment"] = "Group {} failed to be removed".format(name) + ret["comment"] = f"Group {name} failed to be removed" return ret else: - ret["comment"] = "Group {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"Group {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/postgres_initdb.py b/salt/states/postgres_initdb.py index bde59f925eb..bb1a85474e4 100644 --- a/salt/states/postgres_initdb.py +++ b/salt/states/postgres_initdb.py @@ -83,13 +83,13 @@ def present( runas The system user the operation should be performed on behalf of """ - _cmt = "Postgres data directory {} is already present".format(name) + _cmt = f"Postgres data directory {name} is already present" ret = {"name": name, "changes": {}, "result": True, "comment": _cmt} if not __salt__["postgres.datadir_exists"](name=name): if __opts__["test"]: ret["result"] = None - _cmt = "Postgres data directory {} is set to be initialized".format(name) + _cmt = f"Postgres data directory {name} is set to be initialized" ret["comment"] = _cmt return ret @@ -105,11 +105,11 @@ def present( ) if __salt__["postgres.datadir_init"](name, **kwargs): - _cmt = "Postgres data directory {} has been initialized".format(name) + _cmt = f"Postgres data directory {name} has been initialized" ret["comment"] = _cmt ret["changes"][name] = "Present" else: - _cmt = "Postgres data directory {} initialization failed".format(name) + _cmt = f"Postgres data directory {name} initialization failed" ret["result"] = False ret["comment"] = _cmt diff --git a/salt/states/postgres_language.py b/salt/states/postgres_language.py index 3a06476c975..d8c5665ddf4 100644 --- a/salt/states/postgres_language.py +++ b/salt/states/postgres_language.py @@ -72,7 +72,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Language {} is already installed".format(name), + "comment": f"Language {name} is already installed", } dbargs = { @@ -88,14 +88,14 @@ def present( if name not in languages: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Language {} is set to be installed".format(name) + ret["comment"] = f"Language {name} is set to be installed" return ret if __salt__["postgres.language_create"](name, maintenance_db, **dbargs): - ret["comment"] = "Language {} has been installed".format(name) + ret["comment"] = f"Language {name} has been installed" ret["changes"][name] = "Present" else: - ret["comment"] = "Failed to install language {}".format(name) + ret["comment"] = f"Failed to install language {name}" ret["result"] = False return ret @@ -148,15 +148,15 @@ def absent( if __salt__["postgres.language_exists"](name, maintenance_db, **dbargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Language {} is set to be removed".format(name) + ret["comment"] = f"Language {name} is set to be removed" return ret if __salt__["postgres.language_remove"](name, **dbargs): - ret["comment"] = "Language {} has been removed".format(name) + ret["comment"] = f"Language {name} has been removed" ret["changes"][name] = "Absent" return ret else: - ret["comment"] = "Failed to remove language {}".format(name) + ret["comment"] = f"Failed to remove language {name}" ret["result"] = False - ret["comment"] = "Language {} is not present so it cannot be removed".format(name) + ret["comment"] = f"Language {name} is not present so it cannot be removed" return ret diff --git a/salt/states/postgres_privileges.py b/salt/states/postgres_privileges.py index 9241c2de6e4..9829e583441 100644 --- a/salt/states/postgres_privileges.py +++ b/salt/states/postgres_privileges.py @@ -311,10 +311,10 @@ def absent( if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "The privilege(s): {} are set to be revoked from {}".format( - _privs, name + ret["comment"] = ( + "The privilege(s): {} are set to be revoked from {}".format( + _privs, name + ) ) return ret diff --git a/salt/states/postgres_schema.py b/salt/states/postgres_schema.py index 0f58db1afe8..0052f4da1d7 100644 --- a/salt/states/postgres_schema.py +++ b/salt/states/postgres_schema.py @@ -66,7 +66,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Schema {} is already present in database {}".format(name, dbname), + "comment": f"Schema {name} is already present in database {dbname}", } db_args = { @@ -163,13 +163,13 @@ def absent( return ret else: ret["result"] = False - ret["comment"] = "Schema {} failed to be removed".format(name) + ret["comment"] = f"Schema {name} failed to be removed" return ret else: - ret[ - "comment" - ] = "Schema {} is not present in database {}, so it cannot be removed".format( - name, dbname + ret["comment"] = ( + "Schema {} is not present in database {}, so it cannot be removed".format( + name, dbname + ) ) return ret diff --git a/salt/states/postgres_tablespace.py b/salt/states/postgres_tablespace.py index fcb28d68774..84da41f99ec 100644 --- a/salt/states/postgres_tablespace.py +++ b/salt/states/postgres_tablespace.py @@ -15,7 +15,6 @@ A module used to create and manage PostgreSQL tablespaces. """ - import salt.utils.dictupdate as dictupdate @@ -94,7 +93,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "Tablespace {} is already present".format(name), + "comment": f"Tablespace {name} is already present", } dbargs = { "maintenance_db": maintenance_db, @@ -109,22 +108,22 @@ def present( # not there, create it if __opts__["test"]: ret["result"] = None - ret["comment"] = "Tablespace {} is set to be created".format(name) + ret["comment"] = f"Tablespace {name} is set to be created" return ret if __salt__["postgres.tablespace_create"]( name, directory, options, owner, **dbargs ): - ret["comment"] = "The tablespace {} has been created".format(name) + ret["comment"] = f"The tablespace {name} has been created" ret["changes"][name] = "Present" return ret # already exists, make sure it's got the right config if tblspaces[name]["Location"] != directory and not __opts__["test"]: - ret[ - "comment" - ] = """Tablespace {} is not at the right location. This is + ret["comment"] = ( + """Tablespace {} is not at the right location. This is unfixable without dropping and recreating the tablespace.""".format( - name + name + ) ) ret["result"] = False return ret @@ -132,12 +131,12 @@ def present( if owner and not tblspaces[name]["Owner"] == owner: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Tablespace {} owner to be altered".format(name) + ret["comment"] = f"Tablespace {name} owner to be altered" if ( __salt__["postgres.tablespace_alter"](name, new_owner=owner) and not __opts__["test"] ): - ret["comment"] = "Tablespace {} owner changed".format(name) + ret["comment"] = f"Tablespace {name} owner changed" ret["changes"][name] = {"owner": owner} ret["result"] = True @@ -149,18 +148,18 @@ def present( # TODO remove options that exist if possible for k, v in options.items(): # if 'seq_page_cost=1.1' not in '{seq_page_cost=1.1,...}' - if "{}={}".format(k, v) not in tblspaces[name]["Opts"]: + if f"{k}={v}" not in tblspaces[name]["Opts"]: if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = """Tablespace {} options to be + ret["comment"] = ( + """Tablespace {} options to be altered""".format( - name + name + ) ) break # we know it's going to be altered, no reason to cont if __salt__["postgres.tablespace_alter"](name, set_option={k: v}): - ret["comment"] = "Tablespace {} opts changed".format(name) + ret["comment"] = f"Tablespace {name} opts changed" dictupdate.update(ret["changes"], {name: {"options": {k: v}}}) ret["result"] = True @@ -214,10 +213,10 @@ def absent( if __salt__["postgres.tablespace_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Tablespace {} is set to be removed".format(name) + ret["comment"] = f"Tablespace {name} is set to be removed" return ret if __salt__["postgres.tablespace_remove"](name, **db_args): - ret["comment"] = "Tablespace {} has been removed".format(name) + ret["comment"] = f"Tablespace {name} has been removed" ret["changes"][name] = "Absent" return ret diff --git a/salt/states/postgres_user.py b/salt/states/postgres_user.py index f76e5e38403..fa5f5f9ecbf 100644 --- a/salt/states/postgres_user.py +++ b/salt/states/postgres_user.py @@ -149,7 +149,7 @@ def present( "name": name, "changes": {}, "result": True, - "comment": "User {} is already present".format(name), + "comment": f"User {name} is already present", } db_args = { @@ -214,7 +214,7 @@ def present( "SELECT '{}'::timestamp(0) as dt;".format( valid_until.replace("'", "''") ), - **db_args + **db_args, )[0]["dt"] try: valid_until_dt = datetime.datetime.strptime( @@ -238,9 +238,9 @@ def present( if update: ret["changes"][name] = update ret["result"] = None - ret["comment"] = "User {} is set to be {}d".format(name, mode) + ret["comment"] = f"User {name} is set to be {mode}d" return ret - cret = __salt__["postgres.user_{}".format(mode)]( + cret = __salt__[f"postgres.user_{mode}"]( username=name, createdb=createdb, createroles=createroles, @@ -252,19 +252,19 @@ def present( rolepassword=password, valid_until=valid_until, groups=groups, - **db_args + **db_args, ) else: cret = None if cret: - ret["comment"] = "The user {} has been {}d".format(name, mode) + ret["comment"] = f"The user {name} has been {mode}d" if update: ret["changes"][name] = update else: ret["changes"][name] = "Present" elif cret is not None: - ret["comment"] = "Failed to {} user {}".format(mode, name) + ret["comment"] = f"Failed to {mode} user {name}" ret["result"] = False else: ret["result"] = True @@ -318,17 +318,17 @@ def absent( if __salt__["postgres.user_exists"](name, **db_args): if __opts__["test"]: ret["result"] = None - ret["comment"] = "User {} is set to be removed".format(name) + ret["comment"] = f"User {name} is set to be removed" return ret if __salt__["postgres.user_remove"](name, **db_args): - ret["comment"] = "User {} has been removed".format(name) + ret["comment"] = f"User {name} has been removed" ret["changes"][name] = "Absent" return ret else: ret["result"] = False - ret["comment"] = "User {} failed to be removed".format(name) + ret["comment"] = f"User {name} failed to be removed" return ret else: - ret["comment"] = "User {} is not present, so it cannot be removed".format(name) + ret["comment"] = f"User {name} is not present, so it cannot be removed" return ret diff --git a/salt/states/powerpath.py b/salt/states/powerpath.py index 829a6359e5c..0ee13997d0a 100644 --- a/salt/states/powerpath.py +++ b/salt/states/powerpath.py @@ -31,12 +31,12 @@ def license_present(name): if name in licenses: ret["result"] = True - ret["comment"] = "License key {} already present".format(name) + ret["comment"] = f"License key {name} already present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "License key {} is set to be added".format(name) + ret["comment"] = f"License key {name} is set to be added" return ret data = __salt__["powerpath.add_license"](name) @@ -70,12 +70,12 @@ def license_absent(name): if name not in licenses: ret["result"] = True - ret["comment"] = "License key {} not present".format(name) + ret["comment"] = f"License key {name} not present" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "License key {} is set to be removed".format(name) + ret["comment"] = f"License key {name} is set to be removed" return ret data = __salt__["powerpath.remove_license"](name) diff --git a/salt/states/probes.py b/salt/states/probes.py index 2b5c566caf0..23f34e85328 100644 --- a/salt/states/probes.py +++ b/salt/states/probes.py @@ -54,7 +54,6 @@ def __virtual__(): def _default_ret(name): - """ Returns a default structure of the dictionary to be returned as output of the state functions. """ @@ -63,7 +62,6 @@ def _default_ret(name): def _retrieve_rpm_probes(): - """ Will retrieve the probes from the network device using salt module "probes" throught NAPALM proxy. """ @@ -72,7 +70,6 @@ def _retrieve_rpm_probes(): def _expand_probes(probes, defaults): - """ Updates the probes dictionary with different levels of default values. """ @@ -104,7 +101,6 @@ def _expand_probes(probes, defaults): def _clean_probes(probes): - """ Will remove empty and useless values from the probes dictionary. """ @@ -127,7 +123,6 @@ def _clean_probes(probes): def _compare_probes(configured_probes, expected_probes): - """ Compares configured probes on the device with the expected configuration and returns the differences. """ @@ -190,14 +185,12 @@ def _compare_probes(configured_probes, expected_probes): def _ordered_dict_to_dict(probes): - """Mandatory to be dict type in order to be used in the NAPALM Jinja template.""" return salt.utils.json.loads(salt.utils.json.dumps(probes)) def _set_rpm_probes(probes): - """ Calls the Salt module "probes" to configure the probes on the device. """ @@ -209,7 +202,6 @@ def _set_rpm_probes(probes): def _schedule_probes(probes): - """ Calls the Salt module "probes" to schedule the configured probes on the device. """ @@ -221,7 +213,6 @@ def _schedule_probes(probes): def _delete_rpm_probes(probes): - """ Calls the Salt module "probes" to delete probes from the device. """ @@ -240,7 +231,6 @@ def _delete_rpm_probes(probes): def managed(name, probes, defaults=None): - """ Ensure the networks device is configured as specified in the state SLS file. Probes not specified will be removed, while probes not confiured as expected will trigger config updates. diff --git a/salt/states/process.py b/salt/states/process.py index d4b40f81f01..b75a7f7cd7f 100644 --- a/salt/states/process.py +++ b/salt/states/process.py @@ -37,7 +37,7 @@ def absent(name, user=None, signal=None): running = __salt__["ps.pgrep"](name, user=user) ret["result"] = None if running: - ret["comment"] = "{} processes will be killed".format(len(running)) + ret["comment"] = f"{len(running)} processes will be killed" else: ret["comment"] = "No matching processes running" return ret diff --git a/salt/states/proxy.py b/salt/states/proxy.py index e951e97e133..231cba04195 100644 --- a/salt/states/proxy.py +++ b/salt/states/proxy.py @@ -78,13 +78,13 @@ def managed( ret["changes"] = {"new": []} for service in services: - current_settings = __salt__["proxy.get_{}_proxy".format(service)]() + current_settings = __salt__[f"proxy.get_{service}_proxy"]() if current_settings.get("server") == name and current_settings.get( "port" ) == str(port): - ret["comment"] += "{} proxy settings already set.\n".format(service) - elif __salt__["proxy.set_{}_proxy".format(service)]( + ret["comment"] += f"{service} proxy settings already set.\n" + elif __salt__[f"proxy.set_{service}_proxy"]( name, port, user, password, network_service ): ret["comment"] += "{} proxy settings updated correctly\n".format( diff --git a/salt/states/pyenv.py b/salt/states/pyenv.py index f68dd947970..0d2a30020ab 100644 --- a/salt/states/pyenv.py +++ b/salt/states/pyenv.py @@ -122,7 +122,7 @@ def installed(name, default=False, user=None): name = re.sub(r"^python-", "", name) if __opts__["test"]: - ret["comment"] = "python {} is set to be installed".format(name) + ret["comment"] = f"python {name} is set to be installed" return ret ret = _check_pyenv(ret, user) @@ -156,7 +156,7 @@ def _check_and_uninstall_python(ret, python, user=None): return ret else: ret["result"] = True - ret["comment"] = "python {} is already absent".format(python) + ret["comment"] = f"python {python} is already absent" return ret @@ -182,13 +182,13 @@ def absent(name, user=None): name = re.sub(r"^python-", "", name) if __opts__["test"]: - ret["comment"] = "python {} is set to be uninstalled".format(name) + ret["comment"] = f"python {name} is set to be uninstalled" return ret ret = _check_pyenv(ret, user) if ret["result"] is False: ret["result"] = True - ret["comment"] = "pyenv not installed, {} not either".format(name) + ret["comment"] = f"pyenv not installed, {name} not either" return ret else: return _check_and_uninstall_python(ret, name, user=user) diff --git a/salt/states/pyrax_queues.py b/salt/states/pyrax_queues.py index f1c951a510c..7aba6a2750b 100644 --- a/salt/states/pyrax_queues.py +++ b/salt/states/pyrax_queues.py @@ -53,7 +53,7 @@ def present(name, provider): if not is_present: if __opts__["test"]: - msg = "Rackspace queue {} is set to be created.".format(name) + msg = f"Rackspace queue {name} is set to be created." ret["comment"] = msg ret["result"] = None return ret @@ -68,10 +68,10 @@ def present(name, provider): ret["changes"]["new"] = {"queue": queue} else: ret["result"] = False - ret["comment"] = "Failed to create {} Rackspace queue.".format(name) + ret["comment"] = f"Failed to create {name} Rackspace queue." return ret else: - ret["comment"] = "{} present.".format(name) + ret["comment"] = f"{name} present." return ret @@ -98,7 +98,7 @@ def absent(name, provider): if is_present: if __opts__["test"]: - ret["comment"] = "Rackspace queue {} is set to be removed.".format(name) + ret["comment"] = f"Rackspace queue {name} is set to be removed." ret["result"] = None return ret queue = __salt__["cloud.action"]("queues_show", provider=provider, name=name) @@ -110,8 +110,8 @@ def absent(name, provider): ret["changes"]["new"] = {} else: ret["result"] = False - ret["comment"] = "Failed to delete {} Rackspace queue.".format(name) + ret["comment"] = f"Failed to delete {name} Rackspace queue." else: - ret["comment"] = "{} does not exist.".format(name) + ret["comment"] = f"{name} does not exist." return ret diff --git a/salt/states/quota.py b/salt/states/quota.py index 07fe25a87ee..6c032e42ddb 100644 --- a/salt/states/quota.py +++ b/salt/states/quota.py @@ -41,17 +41,17 @@ def mode(name, mode, quotatype): fun = "on" if __salt__["quota.get_mode"](name)[name][quotatype] == fun: ret["result"] = True - ret["comment"] = "Quota for {} already set to {}".format(name, fun) + ret["comment"] = f"Quota for {name} already set to {fun}" return ret if __opts__["test"]: - ret["comment"] = "Quota for {} needs to be set to {}".format(name, fun) + ret["comment"] = f"Quota for {name} needs to be set to {fun}" return ret - if __salt__["quota.{}".format(fun)](name): + if __salt__[f"quota.{fun}"](name): ret["changes"] = {"quota": name} ret["result"] = True - ret["comment"] = "Set quota for {} to {}".format(name, fun) + ret["comment"] = f"Set quota for {name} to {fun}" return ret else: ret["result"] = False - ret["comment"] = "Failed to set quota for {} to {}".format(name, fun) + ret["comment"] = f"Failed to set quota for {name} to {fun}" return ret diff --git a/salt/states/rabbitmq_cluster.py b/salt/states/rabbitmq_cluster.py index 8a845006dba..6af09e26099 100644 --- a/salt/states/rabbitmq_cluster.py +++ b/salt/states/rabbitmq_cluster.py @@ -48,7 +48,7 @@ def joined(name, host, user="rabbit", ram_node=None, runas="root"): ret = {"name": name, "result": True, "comment": "", "changes": {}} status = __salt__["rabbitmq.cluster_status"]() - if "{}@{}".format(user, host) in status: + if f"{user}@{host}" in status: ret["comment"] = "Already in cluster" return ret @@ -62,11 +62,11 @@ def joined(name, host, user="rabbit", ram_node=None, runas="root"): ret["comment"] = result["Join"] # If we've reached this far before returning, we have changes. - ret["changes"] = {"old": "", "new": "{}@{}".format(user, host)} + ret["changes"] = {"old": "", "new": f"{user}@{host}"} if __opts__["test"]: ret["result"] = None - ret["comment"] = "Node is set to join cluster {}@{}".format(user, host) + ret["comment"] = f"Node is set to join cluster {user}@{host}" return ret diff --git a/salt/states/rabbitmq_plugin.py b/salt/states/rabbitmq_plugin.py index d59e74fa035..76342b87b54 100644 --- a/salt/states/rabbitmq_plugin.py +++ b/salt/states/rabbitmq_plugin.py @@ -12,7 +12,6 @@ Example: rabbitmq_plugin.enabled: [] """ - import logging from salt.exceptions import CommandExecutionError @@ -45,11 +44,11 @@ def enabled(name, runas=None): plugin_enabled = __salt__["rabbitmq.plugin_is_enabled"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if plugin_enabled: - ret["comment"] = "Plugin '{}' is already enabled.".format(name) + ret["comment"] = f"Plugin '{name}' is already enabled." return ret if not __opts__["test"]: @@ -57,16 +56,16 @@ def enabled(name, runas=None): __salt__["rabbitmq.enable_plugin"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"old": "", "new": name}) if __opts__["test"] and ret["changes"]: ret["result"] = None - ret["comment"] = "Plugin '{}' is set to be enabled.".format(name) + ret["comment"] = f"Plugin '{name}' is set to be enabled." return ret - ret["comment"] = "Plugin '{}' was enabled.".format(name) + ret["comment"] = f"Plugin '{name}' was enabled." return ret @@ -86,11 +85,11 @@ def disabled(name, runas=None): plugin_enabled = __salt__["rabbitmq.plugin_is_enabled"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if not plugin_enabled: - ret["comment"] = "Plugin '{}' is already disabled.".format(name) + ret["comment"] = f"Plugin '{name}' is already disabled." return ret if not __opts__["test"]: @@ -98,14 +97,14 @@ def disabled(name, runas=None): __salt__["rabbitmq.disable_plugin"](name, runas=runas) except CommandExecutionError as err: ret["result"] = False - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"old": name, "new": ""}) if __opts__["test"] and ret["changes"]: ret["result"] = None - ret["comment"] = "Plugin '{}' is set to be disabled.".format(name) + ret["comment"] = f"Plugin '{name}' is set to be disabled." return ret - ret["comment"] = "Plugin '{}' was disabled.".format(name) + ret["comment"] = f"Plugin '{name}' was disabled." return ret diff --git a/salt/states/rabbitmq_policy.py b/salt/states/rabbitmq_policy.py index 120b6ec6f57..2e17f2fbc8e 100644 --- a/salt/states/rabbitmq_policy.py +++ b/salt/states/rabbitmq_policy.py @@ -79,13 +79,13 @@ def present( updates.append("Priority") if policy and not updates: - ret["comment"] = "Policy {} {} is already present".format(vhost, name) + ret["comment"] = f"Policy {vhost} {name} is already present" return ret if not policy: ret["changes"].update({"old": {}, "new": name}) if __opts__["test"]: - ret["comment"] = "Policy {} {} is set to be created".format(vhost, name) + ret["comment"] = f"Policy {vhost} {name} is set to be created" else: log.debug("Policy doesn't exist - Creating") result = __salt__["rabbitmq.set_policy"]( @@ -100,7 +100,7 @@ def present( elif updates: ret["changes"].update({"old": policy, "new": updates}) if __opts__["test"]: - ret["comment"] = "Policy {} {} is set to be updated".format(vhost, name) + ret["comment"] = f"Policy {vhost} {name} is set to be updated" else: log.debug("Policy exists but needs updating") result = __salt__["rabbitmq.set_policy"]( @@ -117,7 +117,7 @@ def present( ret["result"] = False ret["comment"] = result["Error"] elif ret["changes"] == {}: - ret["comment"] = "'{}' is already in the desired state.".format(name) + ret["comment"] = f"'{name}' is already in the desired state." elif __opts__["test"]: ret["result"] = None elif "Set" in result: @@ -142,7 +142,7 @@ def absent(name, vhost="/", runas=None): policy_exists = __salt__["rabbitmq.policy_exists"](vhost, name, runas=runas) if not policy_exists: - ret["comment"] = "Policy '{} {}' is not present.".format(vhost, name) + ret["comment"] = f"Policy '{vhost} {name}' is not present." return ret if not __opts__["test"]: @@ -159,6 +159,6 @@ def absent(name, vhost="/", runas=None): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Policy '{} {}' will be removed.".format(vhost, name) + ret["comment"] = f"Policy '{vhost} {name}' will be removed." return ret diff --git a/salt/states/rabbitmq_upstream.py b/salt/states/rabbitmq_upstream.py index da0e74ee746..21f39cc6ac2 100644 --- a/salt/states/rabbitmq_upstream.py +++ b/salt/states/rabbitmq_upstream.py @@ -17,7 +17,6 @@ Example: .. versionadded:: 3000 """ - import json import logging @@ -122,7 +121,7 @@ def present( try: current_upstreams = __salt__["rabbitmq.list_upstreams"](runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_config = salt.utils.data.filter_falsey( { @@ -147,7 +146,7 @@ def present( action = "update" else: ret["result"] = True - ret["comment"] = 'Upstream "{}" already present as specified.'.format(name) + ret["comment"] = f'Upstream "{name}" already present as specified.' else: action = "create" diff_config = {"old": None, "new": new_config} @@ -155,7 +154,7 @@ def present( if action: if __opts__["test"]: ret["result"] = None - ret["comment"] = 'Upstream "{}" would have been {}d.'.format(name, action) + ret["comment"] = f'Upstream "{name}" would have been {action}d.' else: try: res = __salt__["rabbitmq.set_upstream"]( @@ -174,10 +173,10 @@ def present( runas=runas, ) ret["result"] = res - ret["comment"] = 'Upstream "{}" {}d.'.format(name, action) + ret["comment"] = f'Upstream "{name}" {action}d.' ret["changes"] = diff_config except CommandExecutionError as exp: - ret["comment"] = "Error trying to {} upstream: {}".format(action, exp) + ret["comment"] = f"Error trying to {action} upstream: {exp}" return ret @@ -195,23 +194,23 @@ def absent(name, runas=None): try: upstream_exists = __salt__["rabbitmq.upstream_exists"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if upstream_exists: if __opts__["test"]: ret["result"] = None - ret["comment"] = 'Upstream "{}" would have been deleted.'.format(name) + ret["comment"] = f'Upstream "{name}" would have been deleted.' else: try: res = __salt__["rabbitmq.delete_upstream"](name, runas=runas) if res: ret["result"] = True - ret["comment"] = 'Upstream "{}" has been deleted.'.format(name) + ret["comment"] = f'Upstream "{name}" has been deleted.' ret["changes"] = {"old": name, "new": None} except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" else: ret["result"] = True - ret["comment"] = 'The upstream "{}" is already absent.'.format(name) + ret["comment"] = f'The upstream "{name}" is already absent.' return ret diff --git a/salt/states/rabbitmq_user.py b/salt/states/rabbitmq_user.py index 8cf9d5f7e75..ce29c5da1c9 100644 --- a/salt/states/rabbitmq_user.py +++ b/salt/states/rabbitmq_user.py @@ -21,7 +21,6 @@ Example: - runas: rabbitmq """ - import logging import salt.utils.path @@ -106,7 +105,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): try: user = __salt__["rabbitmq.user_exists"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret passwd_reqs_update = False @@ -116,7 +115,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): passwd_reqs_update = True log.debug("RabbitMQ user %s password update required", name) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if user and not any((force, perms, tags, passwd_reqs_update)): @@ -124,7 +123,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): "RabbitMQ user '%s' exists, password is up to date and force is not set.", name, ) - ret["comment"] = "User '{}' is already present.".format(name) + ret["comment"] = f"User '{name}' is already present." ret["result"] = True return ret @@ -132,14 +131,14 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): ret["changes"].update({"user": {"old": "", "new": name}}) if __opts__["test"]: ret["result"] = None - ret["comment"] = "User '{}' is set to be created.".format(name) + ret["comment"] = f"User '{name}' is set to be created." return ret log.debug("RabbitMQ user '%s' doesn't exist - Creating.", name) try: __salt__["rabbitmq.add_user"](name, password, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret else: log.debug("RabbitMQ user '%s' exists", name) @@ -151,7 +150,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): name, password, runas=runas ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"password": {"old": "", "new": "Set password."}}) else: @@ -160,7 +159,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): try: __salt__["rabbitmq.clear_password"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update( {"password": {"old": "Removed password.", "new": ""}} @@ -177,13 +176,13 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): try: __salt__["rabbitmq.set_user_tags"](name, tags, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"tags": {"old": current_tags, "new": tags}}) try: existing_perms = __salt__["rabbitmq.list_user_permissions"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if _check_perms_changes(name, perms, runas=runas, existing=existing_perms): @@ -195,7 +194,7 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): vhost, name, perm[0], perm[1], perm[2], runas=runas ) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret new_perms = { vhost: {"configure": perm[0], "write": perm[1], "read": perm[2]} @@ -212,15 +211,15 @@ def present(name, password=None, force=False, tags=None, perms=(), runas=None): ret["result"] = True if ret["changes"] == {}: - ret["comment"] = "'{}' is already in the desired state.".format(name) + ret["comment"] = f"'{name}' is already in the desired state." return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Configuration for '{}' will change.".format(name) + ret["comment"] = f"Configuration for '{name}' will change." return ret - ret["comment"] = "'{}' was configured.".format(name) + ret["comment"] = f"'{name}' was configured." return ret @@ -238,7 +237,7 @@ def absent(name, runas=None): try: user_exists = __salt__["rabbitmq.user_exists"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret if user_exists: @@ -246,19 +245,19 @@ def absent(name, runas=None): try: __salt__["rabbitmq.delete_user"](name, runas=runas) except CommandExecutionError as err: - ret["comment"] = "Error: {}".format(err) + ret["comment"] = f"Error: {err}" return ret ret["changes"].update({"name": {"old": name, "new": ""}}) else: ret["result"] = True - ret["comment"] = "The user '{}' is not present.".format(name) + ret["comment"] = f"The user '{name}' is not present." return ret if __opts__["test"] and ret["changes"]: ret["result"] = None - ret["comment"] = "The user '{}' will be removed.".format(name) + ret["comment"] = f"The user '{name}' will be removed." return ret ret["result"] = True - ret["comment"] = "The user '{}' was removed.".format(name) + ret["comment"] = f"The user '{name}' was removed." return ret diff --git a/salt/states/rabbitmq_vhost.py b/salt/states/rabbitmq_vhost.py index 4231e9519f4..5fb68e6d764 100644 --- a/salt/states/rabbitmq_vhost.py +++ b/salt/states/rabbitmq_vhost.py @@ -14,7 +14,6 @@ Example: - read: .* """ - import logging import salt.utils.path @@ -70,7 +69,7 @@ def present(name): vhost_exists = __salt__["rabbitmq.vhost_exists"](name) if vhost_exists: - ret["comment"] = "Virtual Host '{}' already exists.".format(name) + ret["comment"] = f"Virtual Host '{name}' already exists." return ret if not __opts__["test"]: @@ -87,7 +86,7 @@ def present(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Virtual Host '{}' will be created.".format(name) + ret["comment"] = f"Virtual Host '{name}' will be created." return ret @@ -108,7 +107,7 @@ def absent(name): vhost_exists = __salt__["rabbitmq.vhost_exists"](name) if not vhost_exists: - ret["comment"] = "Virtual Host '{}' is not present.".format(name) + ret["comment"] = f"Virtual Host '{name}' is not present." return ret if not __opts__["test"]: @@ -125,6 +124,6 @@ def absent(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Virtual Host '{}' will be removed.".format(name) + ret["comment"] = f"Virtual Host '{name}' will be removed." return ret diff --git a/salt/states/rbac_solaris.py b/salt/states/rbac_solaris.py index 551e5b9df83..74476640b33 100644 --- a/salt/states/rbac_solaris.py +++ b/salt/states/rbac_solaris.py @@ -41,7 +41,7 @@ def __virtual__(): else: return ( False, - "{} state module can only be loaded on Solaris".format(__virtualname__), + f"{__virtualname__} state module can only be loaded on Solaris", ) @@ -70,7 +70,7 @@ def managed(name, roles=None, profiles=None, authorizations=None): ## check properties if name not in __salt__["user.list_users"](): ret["result"] = False - ret["comment"] = "User {} does not exist!".format(name) + ret["comment"] = f"User {name} does not exist!" return ret if roles and not isinstance(roles, (list)): ret["result"] = False diff --git a/salt/states/rbenv.py b/salt/states/rbenv.py index c9c721f7104..34bce97ca80 100644 --- a/salt/states/rbenv.py +++ b/salt/states/rbenv.py @@ -130,9 +130,9 @@ def installed(name, default=False, user=None): if __opts__["test"]: ret = _ruby_installed(ret, name, user=user) if not ret["result"]: - ret["comment"] = "Ruby {} is set to be installed".format(name) + ret["comment"] = f"Ruby {name} is set to be installed" else: - ret["comment"] = "Ruby {} is already installed".format(name) + ret["comment"] = f"Ruby {name} is already installed" return ret rbenv_installed_ret = _check_and_install_rbenv(rbenv_installed_ret, user) @@ -164,7 +164,7 @@ def _check_and_uninstall_ruby(ret, ruby, user=None): return ret else: ret["result"] = True - ret["comment"] = "Ruby {} is already absent".format(ruby) + ret["comment"] = f"Ruby {ruby} is already absent" return ret @@ -192,17 +192,17 @@ def absent(name, user=None): ret = _check_rbenv(ret, user) if ret["result"] is False: ret["result"] = True - ret["comment"] = "Rbenv not installed, {} not either".format(name) + ret["comment"] = f"Rbenv not installed, {name} not either" return ret else: if __opts__["test"]: ret = _ruby_installed(ret, name, user=user) if ret["result"]: ret["result"] = None - ret["comment"] = "Ruby {} is set to be uninstalled".format(name) + ret["comment"] = f"Ruby {name} is set to be uninstalled" else: ret["result"] = True - ret["comment"] = "Ruby {} is already uninstalled".format(name) + ret["comment"] = f"Ruby {name} is already uninstalled" return ret return _check_and_uninstall_ruby(ret, name, user=user) diff --git a/salt/states/redismod.py b/salt/states/redismod.py index 4ff14c61881..47a4ac776c1 100644 --- a/salt/states/redismod.py +++ b/salt/states/redismod.py @@ -74,10 +74,10 @@ def string(name, value, expire=None, expireat=None, **connection_args): if expireat: __salt__["redis.expireat"](name, expireat, **connection_args) - ret["changes"]["expireat"] = "Key expires at {}".format(expireat) + ret["changes"]["expireat"] = f"Key expires at {expireat}" elif expire: __salt__["redis.expire"](name, expire, **connection_args) - ret["changes"]["expire"] = "TTL set to {} seconds".format(expire) + ret["changes"]["expire"] = f"TTL set to {expire} seconds" return ret @@ -126,7 +126,7 @@ def slaveof( sentinel_host=None, sentinel_port=None, sentinel_password=None, - **connection_args + **connection_args, ): """ Set this redis instance as a slave. @@ -156,13 +156,13 @@ def slaveof( ) if sentinel_master["master_host"] in __salt__["network.ip_addrs"](): ret["result"] = True - ret["comment"] = "Minion is the master: {}".format(name) + ret["comment"] = f"Minion is the master: {name}" return ret first_master = __salt__["redis.get_master_ip"](**connection_args) if first_master == sentinel_master: ret["result"] = True - ret["comment"] = "Minion already slave of master: {}".format(name) + ret["comment"] = f"Minion already slave of master: {name}" return ret if __opts__["test"] is True: @@ -184,6 +184,6 @@ def slaveof( "old": first_master, "new": current_master, } - ret["comment"] = "Minion successfully connected to master: {}".format(name) + ret["comment"] = f"Minion successfully connected to master: {name}" return ret diff --git a/salt/states/restconf.py b/salt/states/restconf.py index 4ac74e27bd4..44fcbc5896c 100644 --- a/salt/states/restconf.py +++ b/salt/states/restconf.py @@ -11,7 +11,6 @@ This state module was designed to manage RESTCONF states. This module relies on the RESTCONF proxy module to interface with the devices. """ - import difflib import json import logging diff --git a/salt/states/rsync.py b/salt/states/rsync.py index 79be3def583..4e01eb2e8dd 100644 --- a/salt/states/rsync.py +++ b/salt/states/rsync.py @@ -143,7 +143,7 @@ def synchronized( if not os.path.exists(name) and not force and not prepare: ret["result"] = False - ret["comment"] = "Destination directory {dest} was not found.".format(dest=name) + ret["comment"] = f"Destination directory {name} was not found." else: if not os.path.exists(name) and prepare: os.makedirs(name) diff --git a/salt/states/rvm.py b/salt/states/rvm.py index 5b7c4fa8e22..f593447093b 100644 --- a/salt/states/rvm.py +++ b/salt/states/rvm.py @@ -150,7 +150,7 @@ def _check_ruby(ret, ruby, user=None): for impl, version, default in __salt__["rvm.list"](runas=user): if impl != "ruby": - version = "{impl}-{version}".format(impl=impl, version=version) + version = f"{impl}-{version}" if not match_micro_version: version = micro_version_regex.sub("", version) if not match_version: @@ -188,7 +188,7 @@ def installed(name, default=False, user=None, opts=None, env=None): ret = {"name": name, "result": None, "comment": "", "changes": {}} if __opts__["test"]: - ret["comment"] = "Ruby {} is set to be installed".format(name) + ret["comment"] = f"Ruby {name} is set to be installed" return ret ret = _check_rvm(ret, user) @@ -241,7 +241,7 @@ def gemset_present(name, ruby="default", user=None): else: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Set to install gemset {}".format(name) + ret["comment"] = f"Set to install gemset {name}" return ret if __salt__["rvm.gemset_create"](ruby, name, runas=user): ret["result"] = True diff --git a/salt/states/salt_proxy.py b/salt/states/salt_proxy.py index 8a6ef6e2675..005ae65d24d 100644 --- a/salt/states/salt_proxy.py +++ b/salt/states/salt_proxy.py @@ -52,5 +52,5 @@ def configure_proxy(name, proxyname="p8000", start=True): """ ret = __salt__["salt_proxy.configure_proxy"](proxyname, start=start) - ret.update({"name": name, "comment": "{} config messages".format(name)}) + ret.update({"name": name, "comment": f"{name} config messages"}) return ret diff --git a/salt/states/saltmod.py b/salt/states/saltmod.py index f788c70a1e6..c6a194ef1db 100644 --- a/salt/states/saltmod.py +++ b/salt/states/saltmod.py @@ -349,9 +349,11 @@ def state( cmd_ret = { __opts__["id"]: { "ret": tmp_ret, - "out": tmp_ret.get("out", "highstate") - if isinstance(tmp_ret, dict) - else "highstate", + "out": ( + tmp_ret.get("out", "highstate") + if isinstance(tmp_ret, dict) + else "highstate" + ), } } diff --git a/salt/states/serverdensity_device.py b/salt/states/serverdensity_device.py index bce8db5bc92..02eced4b42f 100644 --- a/salt/states/serverdensity_device.py +++ b/salt/states/serverdensity_device.py @@ -46,7 +46,6 @@ Example: serverdensity_device.monitored """ - import logging import salt.utils.json @@ -206,9 +205,9 @@ def monitored( ret["changes"] = {} if __opts__["test"]: ret["result"] = None - ret[ - "comment" - ] = "Agent is not installed and device is not in the Server Density DB" + ret["comment"] = ( + "Agent is not installed and device is not in the Server Density DB" + ) return ret if __opts__["test"]: @@ -224,8 +223,8 @@ def monitored( ) ret["result"] = True - ret[ - "comment" - ] = "Successfully installed agent and created device in Server Density db." + ret["comment"] = ( + "Successfully installed agent and created device in Server Density db." + ) ret["changes"] = {"created_device": device, "installed_agent": installed_agent} return ret diff --git a/salt/states/service.py b/salt/states/service.py index 0bb04c34cc1..ab14ed0abf1 100644 --- a/salt/states/service.py +++ b/salt/states/service.py @@ -155,10 +155,10 @@ def _enable(name, started, result=True, **kwargs): # Check to see if this minion supports enable if "service.enable" not in __salt__ or "service.enabled" not in __salt__: if started is True: - ret[ - "comment" - ] = "Enable is not available on this minion, service {} started".format( - name + ret["comment"] = ( + "Enable is not available on this minion, service {} started".format( + name + ) ) elif started is None: ret["comment"] = ( @@ -166,10 +166,10 @@ def _enable(name, started, result=True, **kwargs): " service {} is in the desired state".format(name) ) else: - ret[ - "comment" - ] = "Enable is not available on this minion, service {} is dead".format( - name + ret["comment"] = ( + "Enable is not available on this minion, service {} is dead".format( + name + ) ) return ret @@ -184,19 +184,19 @@ def _enable(name, started, result=True, **kwargs): elif started is None: # always be sure in this case to reset the changes dict ret["changes"] = {} - ret[ - "comment" - ] = "Service {} is already enabled, and is in the desired state".format( - name + ret["comment"] = ( + "Service {} is already enabled, and is in the desired state".format( + name + ) ) else: - ret["comment"] = "Service {} is already enabled, and is dead".format(name) + ret["comment"] = f"Service {name} is already enabled, and is dead" return ret # Service needs to be enabled if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} set to be enabled".format(name) + ret["comment"] = f"Service {name} set to be enabled" return ret try: @@ -214,13 +214,13 @@ def _enable(name, started, result=True, **kwargs): name ) elif started is None: - ret[ - "comment" - ] = "Service {} has been enabled, and is in the desired state".format( - name + ret["comment"] = ( + "Service {} has been enabled, and is in the desired state".format( + name + ) ) else: - ret["comment"] = "Service {} has been enabled, and is dead".format(name) + ret["comment"] = f"Service {name} has been enabled, and is dead" return ret except CommandExecutionError as exc: enable_error = exc.strerror @@ -240,14 +240,14 @@ def _enable(name, started, result=True, **kwargs): " but the service was already running".format(name) ) else: - ret[ - "comment" - ] = "Failed when setting service {} to start at boot, and the service is dead".format( - name + ret["comment"] = ( + "Failed when setting service {} to start at boot, and the service is dead".format( + name + ) ) if enable_error: - ret["comment"] += ". Additional information follows:\n\n{}".format(enable_error) + ret["comment"] += f". Additional information follows:\n\n{enable_error}" return ret @@ -274,10 +274,10 @@ def _disable(name, started, result=True, **kwargs): # is enable/disable available? if "service.disable" not in __salt__ or "service.disabled" not in __salt__: if started is True: - ret[ - "comment" - ] = "Disable is not available on this minion, service {} started".format( - name + ret["comment"] = ( + "Disable is not available on this minion, service {} started".format( + name + ) ) elif started is None: ret["comment"] = ( @@ -285,10 +285,10 @@ def _disable(name, started, result=True, **kwargs): " service {} is in the desired state".format(name) ) else: - ret[ - "comment" - ] = "Disable is not available on this minion, service {} is dead".format( - name + ret["comment"] = ( + "Disable is not available on this minion, service {} is dead".format( + name + ) ) return ret @@ -310,19 +310,19 @@ def _disable(name, started, result=True, **kwargs): elif started is None: # always be sure in this case to reset the changes dict ret["changes"] = {} - ret[ - "comment" - ] = "Service {} is already disabled, and is in the desired state".format( - name + ret["comment"] = ( + "Service {} is already disabled, and is in the desired state".format( + name + ) ) else: - ret["comment"] = "Service {} is already disabled, and is dead".format(name) + ret["comment"] = f"Service {name} is already disabled, and is dead" return ret # Service needs to be disabled if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} set to be disabled".format(name) + ret["comment"] = f"Service {name} set to be disabled" return ret if __salt__["service.disable"](name, **kwargs): @@ -335,22 +335,22 @@ def _disable(name, started, result=True, **kwargs): if before_toggle_disable_status != after_toggle_disable_status: ret["changes"][name] = True if started is True: - ret["comment"] = "Service {} has been disabled, and is running".format(name) + ret["comment"] = f"Service {name} has been disabled, and is running" elif started is None: - ret[ - "comment" - ] = "Service {} has been disabled, and is in the desired state".format(name) + ret["comment"] = ( + f"Service {name} has been disabled, and is in the desired state" + ) else: - ret["comment"] = "Service {} has been disabled, and is dead".format(name) + ret["comment"] = f"Service {name} has been disabled, and is dead" return ret # Service failed to be disabled ret["result"] = False if started is True: - ret[ - "comment" - ] = "Failed when setting service {} to not start at boot, and is running".format( - name + ret["comment"] = ( + "Failed when setting service {} to not start at boot, and is running".format( + name + ) ) elif started is None: ret["comment"] = ( @@ -380,7 +380,7 @@ def _available(name, ret): avail = name in __salt__["service.get_all"]() if not avail: ret["result"] = False - ret["comment"] = "The named service {} is not available".format(name) + ret["comment"] = f"The named service {name} is not available" return avail @@ -505,7 +505,7 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): [ _f for _f in [ - "The service {} is already running".format(name), + f"The service {name} is already running", unmask_ret["comment"], ] if _f @@ -524,7 +524,7 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): [ _f for _f in [ - "Service {} is set to start".format(name), + f"Service {name} is set to start", unmask_ret["comment"], ] if _f @@ -566,7 +566,7 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): if not func_ret: ret["result"] = False - ret["comment"] = "Service {} failed to start".format(name) + ret["comment"] = f"Service {name} failed to start" if enable is True: ret.update(_enable(name, False, result=False, **kwargs)) elif enable is False: @@ -589,9 +589,9 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs): ret["changes"][name] = after_toggle_status if after_toggle_status: - ret["comment"] = "Started service {}".format(name) + ret["comment"] = f"Started service {name}" else: - ret["comment"] = "Service {} failed to start".format(name) + ret["comment"] = f"Service {name} failed to start" ret["result"] = False if enable is True: @@ -708,7 +708,7 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): # See if the service is already dead if not before_toggle_status: - ret["comment"] = "The service {} is already dead".format(name) + ret["comment"] = f"The service {name} is already dead" if enable is True and not before_toggle_enable_status: ret.update(_enable(name, None, **kwargs)) elif enable is False and before_toggle_enable_status: @@ -718,7 +718,7 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): # Run the tests if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} is set to be killed".format(name) + ret["comment"] = f"Service {name} is set to be killed" return ret # Conditionally add systemd-specific args to call to service.start @@ -732,7 +732,7 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): func_ret = __salt__["service.stop"](name, **stop_kwargs) if not func_ret: ret["result"] = False - ret["comment"] = "Service {} failed to die".format(name) + ret["comment"] = f"Service {name} failed to die" if enable is True: ret.update(_enable(name, True, result=False, **kwargs)) elif enable is False: @@ -757,9 +757,9 @@ def dead(name, enable=None, sig=None, init_delay=None, **kwargs): # be sure to stop, in case we mis detected in the check if after_toggle_status: ret["result"] = False - ret["comment"] = "Service {} failed to die".format(name) + ret["comment"] = f"Service {name} failed to die" else: - ret["comment"] = "Service {} was killed".format(name) + ret["comment"] = f"Service {name} was killed" if enable is True: ret.update( @@ -791,9 +791,10 @@ def enabled(name, **kwargs): __context__["service.state"] = "enabled" ret.update(_enable(name, None, **kwargs)) - if __opts__.get("test") and ret.get( - "comment" - ) == "The named service {} is not available".format(name): + if ( + __opts__.get("test") + and ret.get("comment") == f"The named service {name} is not available" + ): ret["result"] = None ret["comment"] = ( "Service {} not present; if created in this state run, " @@ -885,16 +886,16 @@ def masked(name, runtime=False): if __opts__["test"]: ret["result"] = None ret["changes"] = expected_changes - ret["comment"] = "Service {} would be {}".format(name, mask_type) + ret["comment"] = f"Service {name} would be {mask_type}" return ret __salt__["service.mask"](name, runtime) if __salt__["service.masked"](name, runtime): ret["changes"] = expected_changes - ret["comment"] = "Service {} was {}".format(name, mask_type) + ret["comment"] = f"Service {name} was {mask_type}" else: - ret["comment"] = "Failed to mask service {}".format(name) + ret["comment"] = f"Failed to mask service {name}" return ret except CommandExecutionError as exc: @@ -943,22 +944,22 @@ def unmasked(name, runtime=False): try: if not __salt__["service.masked"](name, runtime): - ret["comment"] = "Service {} was already {}".format(name, action) + ret["comment"] = f"Service {name} was already {action}" return ret if __opts__["test"]: ret["result"] = None ret["changes"] = expected_changes - ret["comment"] = "Service {} would be {}".format(name, action) + ret["comment"] = f"Service {name} would be {action}" return ret __salt__["service.unmask"](name, runtime) if not __salt__["service.masked"](name, runtime): ret["changes"] = expected_changes - ret["comment"] = "Service {} was {}".format(name, action) + ret["comment"] = f"Service {name} was {action}" else: - ret["comment"] = "Failed to unmask service {}".format(name) + ret["comment"] = f"Failed to unmask service {name}" return ret except CommandExecutionError as exc: @@ -975,7 +976,7 @@ def mod_watch( full_restart=False, init_delay=None, force=False, - **kwargs + **kwargs, ): """ The service watcher, called to invoke the watch command. @@ -1027,7 +1028,7 @@ def mod_watch( func = __salt__["service.stop"] else: ret["result"] = True - ret["comment"] = "Service is already {}".format(past_participle) + ret["comment"] = f"Service is already {past_participle}" return ret elif sfun == "running": if __salt__["service.status"](name, sig, **status_kwargs): @@ -1050,13 +1051,13 @@ def mod_watch( if not past_participle: past_participle = verb + "ed" else: - ret["comment"] = "Unable to trigger watch for service.{}".format(sfun) + ret["comment"] = f"Unable to trigger watch for service.{sfun}" ret["result"] = False return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service is set to be {}".format(past_participle) + ret["comment"] = f"Service is set to be {past_participle}" return ret if verb == "start" and "service.stop" in __salt__: @@ -1080,9 +1081,7 @@ def mod_watch( ret["changes"] = {name: result} ret["result"] = result ret["comment"] = ( - "Service {}".format(past_participle) - if result - else "Failed to {} the service".format(verb) + f"Service {past_participle}" if result else f"Failed to {verb} the service" ) return ret @@ -1112,7 +1111,7 @@ def mod_beacon(name, **kwargs): data["emitatstartup"] = _beacon_data.get("emitatstartup", False) data["uncleanshutdown"] = _beacon_data.get("emitatstartup", None) - beacon_name = "beacon_{}_{}".format(beacon_module, name) + beacon_name = f"beacon_{beacon_module}_{name}" beacon_kwargs = { "name": beacon_name, diff --git a/salt/states/slack.py b/salt/states/slack.py index a0c1b3a2dfc..df271f2be1c 100644 --- a/salt/states/slack.py +++ b/salt/states/slack.py @@ -24,7 +24,6 @@ The api key can be specified in the master or minion configuration like below: """ - from salt.exceptions import SaltInvocationError @@ -162,11 +161,11 @@ def post_message(name, **kwargs): ) except SaltInvocationError as sie: - ret["comment"] = "Failed to send message ({}): {}".format(sie, name) + ret["comment"] = f"Failed to send message ({sie}): {name}" else: if isinstance(result, bool) and result: ret["result"] = True - ret["comment"] = "Sent message: {}".format(name) + ret["comment"] = f"Sent message: {name}" else: ret["comment"] = "Failed to send message ({}): {}".format( result["message"], name diff --git a/salt/states/smartos.py b/salt/states/smartos.py index afc536c2235..1309ad00c72 100644 --- a/salt/states/smartos.py +++ b/salt/states/smartos.py @@ -381,10 +381,10 @@ def config_present(name, value): ret["result"] = _write_config(config) if not ret["result"]: - ret[ - "comment" - ] = 'Could not add property {} with value "{}" to config'.format( - name, value + ret["comment"] = ( + 'Could not add property {} with value "{}" to config'.format( + name, value + ) ) return ret @@ -1021,9 +1021,9 @@ def vm_present(name, vmconfig, config=None): if f"update_{instance}" not in vmconfig["changed"]: vmconfig["changed"][f"update_{instance}"] = [] - update_cfg[ - vmconfig_type["instance"][instance] - ] = state_cfg[vmconfig_type["instance"][instance]] + update_cfg[vmconfig_type["instance"][instance]] = ( + state_cfg[vmconfig_type["instance"][instance]] + ) vmconfig["changed"][f"update_{instance}"].append( update_cfg ) @@ -1151,9 +1151,9 @@ def vm_present(name, vmconfig, config=None): ) if vmconfig["state"]["hostname"] not in ret["changes"]: ret["changes"][vmconfig["state"]["hostname"]] = {} - ret["changes"][vmconfig["state"]["hostname"]][ - "image_uuid" - ] = vmconfig["reprovision_uuid"] + ret["changes"][vmconfig["state"]["hostname"]]["image_uuid"] = ( + vmconfig["reprovision_uuid"] + ) else: log.warning( "smartos.vm_present::%s::reprovision - " diff --git a/salt/states/smtp.py b/salt/states/smtp.py index 2c8068363e7..1dd9fd9c799 100644 --- a/salt/states/smtp.py +++ b/salt/states/smtp.py @@ -86,8 +86,8 @@ def send_msg( recipient, name, atts ) else: - ret["comment"] = "Sent message to {}: {}".format(recipient, name) + ret["comment"] = f"Sent message to {recipient}: {name}" else: ret["result"] = False - ret["comment"] = "Unable to send message to {}: {}".format(recipient, name) + ret["comment"] = f"Unable to send message to {recipient}: {name}" return ret diff --git a/salt/states/snapper.py b/salt/states/snapper.py index 964c88c5001..2c61ab9722c 100644 --- a/salt/states/snapper.py +++ b/salt/states/snapper.py @@ -106,7 +106,6 @@ and include this change. :platform: Linux """ - import os @@ -178,9 +177,7 @@ def baseline_snapshot( if tag: snapshot = _get_baseline_from_tag(config, tag) if not snapshot: - ret.update( - {"result": False, "comment": 'Baseline tag "{}" not found'.format(tag)} - ) + ret.update({"result": False, "comment": f'Baseline tag "{tag}" not found'}) return ret number = snapshot["id"] diff --git a/salt/states/solrcloud.py b/salt/states/solrcloud.py index 6e9aaab545e..4858ecf84f5 100644 --- a/salt/states/solrcloud.py +++ b/salt/states/solrcloud.py @@ -5,7 +5,6 @@ States for solrcloud alias and collection configuration """ - import salt.utils.json @@ -39,11 +38,11 @@ def alias(name, collections, **kwargs): return ret if __opts__["test"]: - ret["comment"] = 'The alias "{}" will be updated.'.format(name) + ret["comment"] = f'The alias "{name}" will be updated.' ret["result"] = None else: __salt__["solrcloud.alias_set_collections"](name, collections, **kwargs) - ret["comment"] = 'The alias "{}" has been updated.'.format(name) + ret["comment"] = f'The alias "{name}" has been updated.' ret["result"] = True ret["changes"] = { @@ -53,11 +52,11 @@ def alias(name, collections, **kwargs): else: if __opts__["test"]: - ret["comment"] = 'The alias "{}" will be created.'.format(name) + ret["comment"] = f'The alias "{name}" will be created.' ret["result"] = None else: __salt__["solrcloud.alias_set_collections"](name, collections, **kwargs) - ret["comment"] = 'The alias "{}" has been created.'.format(name) + ret["comment"] = f'The alias "{name}" has been created.' ret["result"] = True ret["changes"] = { @@ -121,7 +120,7 @@ def collection(name, options=None, **kwargs): else: if __opts__["test"]: - ret["comment"] = 'Collection options "{}" will be changed.'.format(name) + ret["comment"] = f'Collection options "{name}" will be changed.' ret["result"] = None else: __salt__["solrcloud.collection_set_options"](name, diff, **kwargs) @@ -146,11 +145,11 @@ def collection(name, options=None, **kwargs): options, sort_keys=True, indent=4, separators=(",", ": ") ) if __opts__["test"]: - ret["comment"] = 'The collection "{}" will be created.'.format(name) + ret["comment"] = f'The collection "{name}" will be created.' ret["result"] = None else: __salt__["solrcloud.collection_create"](name, options, **kwargs) - ret["comment"] = 'The collection "{}" has been created.'.format(name) + ret["comment"] = f'The collection "{name}" has been created.' ret["result"] = True ret["changes"] = { diff --git a/salt/states/splunk.py b/salt/states/splunk.py index 272a516ff4a..54c175f5490 100644 --- a/salt/states/splunk.py +++ b/salt/states/splunk.py @@ -50,22 +50,22 @@ def present(email, profile="splunk", **kwargs): if not target: if __opts__["test"]: - ret["comment"] = "User {} will be created".format(name) + ret["comment"] = f"User {name} will be created" return ret # create the user result = __salt__["splunk.create_user"](email, profile=profile, **kwargs) if result: ret["changes"].setdefault("old", None) - ret["changes"].setdefault("new", "User {} exists".format(name)) + ret["changes"].setdefault("new", f"User {name} exists") ret["result"] = True else: ret["result"] = False - ret["comment"] = "Failed to create {}".format(name) + ret["comment"] = f"Failed to create {name}" return ret else: - ret["comment"] = "User {} set to be updated.".format(name) + ret["comment"] = f"User {name} set to be updated." if __opts__["test"]: ret["result"] = None return ret @@ -130,31 +130,31 @@ def absent(email, profile="splunk", **kwargs): "name": user_identity, "changes": {}, "result": None, - "comment": "User {} is absent.".format(user_identity), + "comment": f"User {user_identity} is absent.", } target = __salt__["splunk.get_user"](email, profile=profile) if not target: - ret["comment"] = "User {} does not exist".format(user_identity) + ret["comment"] = f"User {user_identity} does not exist" ret["result"] = True return ret if __opts__["test"]: - ret["comment"] = "User {} is all set to be deleted".format(user_identity) + ret["comment"] = f"User {user_identity} is all set to be deleted" ret["result"] = None return ret result = __salt__["splunk.delete_user"](email, profile=profile) if result: - ret["comment"] = "Deleted user {}".format(user_identity) - ret["changes"].setdefault("old", "User {} exists".format(user_identity)) - ret["changes"].setdefault("new", "User {} deleted".format(user_identity)) + ret["comment"] = f"Deleted user {user_identity}" + ret["changes"].setdefault("old", f"User {user_identity} exists") + ret["changes"].setdefault("new", f"User {user_identity} deleted") ret["result"] = True else: - ret["comment"] = "Failed to delete {}".format(user_identity) + ret["comment"] = f"Failed to delete {user_identity}" ret["result"] = False return ret diff --git a/salt/states/splunk_search.py b/salt/states/splunk_search.py index a12ca481e29..8c00b217e45 100644 --- a/salt/states/splunk_search.py +++ b/salt/states/splunk_search.py @@ -44,7 +44,7 @@ def present(name, profile="splunk", **kwargs): target = __salt__["splunk_search.get"](name, profile=profile) if target: if __opts__["test"]: - ret["comment"] = "Would update {}".format(name) + ret["comment"] = f"Would update {name}" return ret # found a search... updating result = __salt__["splunk_search.update"](name, profile=profile, **kwargs) @@ -64,7 +64,7 @@ def present(name, profile="splunk", **kwargs): ret["changes"]["new"] = newvalues else: if __opts__["test"]: - ret["comment"] = "Would create {}".format(name) + ret["comment"] = f"Would create {name}" return ret # creating a new search result = __salt__["splunk_search.create"](name, profile=profile, **kwargs) @@ -74,7 +74,7 @@ def present(name, profile="splunk", **kwargs): ret["changes"]["new"] = kwargs else: ret["result"] = False - ret["comment"] = "Failed to create {}".format(name) + ret["comment"] = f"Failed to create {name}" return ret @@ -96,7 +96,7 @@ def absent(name, profile="splunk"): "name": name, "changes": {}, "result": True, - "comment": "{} is absent.".format(name), + "comment": f"{name} is absent.", } target = __salt__["splunk_search.get"](name, profile=profile) @@ -104,14 +104,14 @@ def absent(name, profile="splunk"): if __opts__["test"]: ret = {} ret["name"] = name - ret["comment"] = "Would delete {}".format(name) + ret["comment"] = f"Would delete {name}" ret["result"] = None return ret result = __salt__["splunk_search.delete"](name, profile=profile) if result: - ret["comment"] = "{} was deleted".format(name) + ret["comment"] = f"{name} was deleted" else: - ret["comment"] = "Failed to delete {}".format(name) + ret["comment"] = f"Failed to delete {name}" ret["result"] = False return ret diff --git a/salt/states/sqlite3.py b/salt/states/sqlite3.py index d0eb0615dd2..3cddab97d97 100644 --- a/salt/states/sqlite3.py +++ b/salt/states/sqlite3.py @@ -92,7 +92,6 @@ can be approximated with sqlite3's module functions and module.run: - sqlite3: zone-insert-12 """ - try: import sqlite3 diff --git a/salt/states/ssh_auth.py b/salt/states/ssh_auth.py index 1806a34709a..19bc0ae2934 100644 --- a/salt/states/ssh_auth.py +++ b/salt/states/ssh_auth.py @@ -59,7 +59,6 @@ to use a YAML 'explicit key', as demonstrated in the second example below. - AAAAB3NzaC1kcQ9fJFF435bYTEyY== newcomment """ - import re import sys @@ -356,10 +355,10 @@ def present( ) return ret elif data == "no change": - ret[ - "comment" - ] = "The authorized host key {} is already present for user {}".format( - name, user + ret["comment"] = ( + "The authorized host key {} is already present for user {}".format( + name, user + ) ) elif data == "new": ret["changes"][name] = "New" @@ -386,9 +385,9 @@ def present( ) elif data == "invalid" or data == "Invalid public key": ret["result"] = False - ret[ - "comment" - ] = "Invalid public ssh key, most likely has spaces or invalid syntax" + ret["comment"] = ( + "Invalid public ssh key, most likely has spaces or invalid syntax" + ) return ret diff --git a/salt/states/ssh_known_hosts.py b/salt/states/ssh_known_hosts.py index 262c9cadb32..9502e827bff 100644 --- a/salt/states/ssh_known_hosts.py +++ b/salt/states/ssh_known_hosts.py @@ -148,18 +148,18 @@ def present( ) except CommandNotFoundError as err: ret["result"] = False - ret["comment"] = "ssh.check_known_host error: {}".format(err) + ret["comment"] = f"ssh.check_known_host error: {err}" return ret if result == "exists": - comment = "Host {} is already in {}".format(name, config) + comment = f"Host {name} is already in {config}" ret["result"] = True return dict(ret, comment=comment) elif result == "add": - comment = "Key for {} is set to be added to {}".format(name, config) + comment = f"Key for {name} is set to be added to {config}" return dict(ret, comment=comment) else: # 'update' - comment = "Key for {} is set to be updated in {}".format(name, config) + comment = f"Key for {name} is set to be updated in {config}" return dict(ret, comment=comment) result = __salt__["ssh.set_known_host"]( @@ -175,7 +175,7 @@ def present( fingerprint_hash_type=fingerprint_hash_type, ) if result["status"] == "exists": - return dict(ret, comment="{} already exists in {}".format(name, config)) + return dict(ret, comment=f"{name} already exists in {config}") elif result["status"] == "error": return dict(ret, result=False, comment=result["error"]) else: # 'updated' @@ -184,7 +184,7 @@ def present( return dict( ret, changes={"old": result["old"], "new": result["new"]}, - comment="{}'s key saved to {} (key: {})".format(name, config, new_key), + comment=f"{name}'s key saved to {config} (key: {new_key})", ) else: fingerprint = result["new"][0]["fingerprint"] @@ -235,7 +235,7 @@ def absent(name, user=None, config=None): return dict(ret, comment="Host is already absent") if __opts__["test"]: - comment = "Key for {} is set to be removed from {}".format(name, config) + comment = f"Key for {name} is set to be removed from {config}" ret["result"] = None return dict(ret, comment=comment) diff --git a/salt/states/status.py b/salt/states/status.py index 98cdffb3f08..5f84d07e16b 100644 --- a/salt/states/status.py +++ b/salt/states/status.py @@ -28,7 +28,7 @@ def loadavg(name, maximum=None, minimum=None): data = __salt__["status.loadavg"]() if name not in data: ret["result"] = False - ret["comment"] += "Requested load average {} not available ".format(name) + ret["comment"] += f"Requested load average {name} not available " return ret if minimum and maximum and minimum >= maximum: ret["comment"] += "Min must be less than max" @@ -44,7 +44,7 @@ def loadavg(name, maximum=None, minimum=None): return ret if maximum: if cap > float(maximum): - ret["comment"] = "Load avg above maximum of {} at {}".format(maximum, cap) + ret["comment"] = f"Load avg above maximum of {maximum} at {cap}" return ret ret["comment"] = "Load avg in acceptable range" ret["result"] = True @@ -69,9 +69,9 @@ def process(name): data = __salt__["status.pid"](name) if not data: ret["result"] = False - ret["comment"] += 'Process signature "{}" not found '.format(name) + ret["comment"] += f'Process signature "{name}" not found ' return ret ret["data"] = data - ret["comment"] += 'Process signature "{}" was found '.format(name) + ret["comment"] += f'Process signature "{name}" was found ' ret["result"] = True return ret diff --git a/salt/states/statuspage.py b/salt/states/statuspage.py index e8961aceca8..7d478ae82c9 100644 --- a/salt/states/statuspage.py +++ b/salt/states/statuspage.py @@ -207,7 +207,7 @@ def create( page_id=None, api_key=None, api_version=None, - **kwargs + **kwargs, ): """ Insert a new entry under a specific endpoint. @@ -259,14 +259,14 @@ def create( page_id=page_id, api_key=api_key, api_version=api_version, - **kwargs + **kwargs, ) if not sp_create.get("result"): ret["comment"] = "Unable to create {endpoint}: {msg}".format( endpoint=endpoint_sg, msg=sp_create.get("comment") ) else: - ret["comment"] = "{endpoint} created!".format(endpoint=endpoint_sg) + ret["comment"] = f"{endpoint_sg} created!" ret["result"] = True ret["changes"] = sp_create.get("out") @@ -279,7 +279,7 @@ def update( page_id=None, api_key=None, api_version=None, - **kwargs + **kwargs, ): """ Update attribute(s) of a specific endpoint. @@ -337,14 +337,14 @@ def update( page_id=page_id, api_key=api_key, api_version=api_version, - **kwargs + **kwargs, ) if not sp_update.get("result"): ret["comment"] = "Unable to update {endpoint} #{id}: {msg}".format( endpoint=endpoint_sg, id=id, msg=sp_update.get("comment") ) else: - ret["comment"] = "{endpoint} #{id} updated!".format(endpoint=endpoint_sg, id=id) + ret["comment"] = f"{endpoint_sg} #{id} updated!" ret["result"] = True ret["changes"] = sp_update.get("out") @@ -411,7 +411,7 @@ def delete( endpoint=endpoint_sg, id=id, msg=sp_delete.get("comment") ) else: - ret["comment"] = "{endpoint} #{id} deleted!".format(endpoint=endpoint_sg, id=id) + ret["comment"] = f"{endpoint_sg} #{id} deleted!" ret["result"] = True @@ -544,7 +544,7 @@ def managed( page_id=page_id, api_key=api_key, api_version=api_version, - **new_endpoint + **new_endpoint, ) if not adding.get("result"): ret.update({"comment": adding.get("comment")}) @@ -563,7 +563,7 @@ def managed( page_id=page_id, api_key=api_key, api_version=api_version, - **update_endpoint + **update_endpoint, ) if not updating.get("result"): ret.update({"comment": updating.get("comment")}) diff --git a/salt/states/supervisord.py b/salt/states/supervisord.py index d0a5614c939..4b0c7bbf23c 100644 --- a/salt/states/supervisord.py +++ b/salt/states/supervisord.py @@ -82,9 +82,9 @@ def running( if "supervisord.status" not in __salt__: ret["result"] = False - ret[ - "comment" - ] = "Supervisord module not activated. Do you need to install supervisord?" + ret["comment"] = ( + "Supervisord module not activated. Do you need to install supervisord?" + ) return ret all_processes = __salt__["supervisord.status"]( @@ -115,34 +115,34 @@ def running( if name.endswith(":"): # Process group if len(to_start) == len(matches): - ret[ - "comment" - ] = "All services in group '{}' will be started".format(name) + ret["comment"] = ( + f"All services in group '{name}' will be started" + ) else: - ret[ - "comment" - ] = "The following services will be started: {}".format( - " ".join(to_start) + ret["comment"] = ( + "The following services will be started: {}".format( + " ".join(to_start) + ) ) else: # Single program - ret["comment"] = "Service {} will be started".format(name) + ret["comment"] = f"Service {name} will be started" else: if name.endswith(":"): # Process group - ret[ - "comment" - ] = "All services in group '{}' are already running".format(name) + ret["comment"] = ( + f"All services in group '{name}' are already running" + ) else: - ret["comment"] = "Service {} is already running".format(name) + ret["comment"] = f"Service {name} is already running" else: ret["result"] = None # Process/group needs to be added if name.endswith(":"): - _type = "Group '{}'".format(name) + _type = f"Group '{name}'" else: - _type = "Service {}".format(name) - ret["comment"] = "{} will be added and started".format(_type) + _type = f"Service {name}" + ret["comment"] = f"{_type} will be added and started" return ret changes = [] @@ -162,11 +162,11 @@ def running( ret.update(_check_error(result, comment)) log.debug(comment) - if "{}: updated".format(name) in result: + if f"{name}: updated" in result: just_updated = True elif to_add: # Not sure if this condition is precise enough. - comment = "Adding service: {}".format(name) + comment = f"Adding service: {name}" __salt__["supervisord.reread"](user=user, conf_file=conf_file, bin_env=bin_env) # Causes supervisorctl to throw `ERROR: process group already active` # if process group exists. At this moment, I'm not sure how to handle @@ -205,7 +205,7 @@ def running( if is_stopped is False: if restart and not just_updated: comment = "Restarting{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) log.debug(comment) result = __salt__["supervisord.restart"]( @@ -215,20 +215,20 @@ def running( changes.append(comment) elif just_updated: comment = "Not starting updated{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) result = comment ret.update({"comment": comment}) else: comment = "Not starting already running{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) result = comment ret.update({"comment": comment}) elif not just_updated: comment = "Starting{}: {}".format( - process_type is not None and " {}".format(process_type) or "", name + process_type is not None and f" {process_type}" or "", name ) changes.append(comment) log.debug(comment) @@ -268,9 +268,9 @@ def dead(name, user=None, conf_file=None, bin_env=None, **kwargs): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Service {} is set to be stopped".format(name) + ret["comment"] = f"Service {name} is set to be stopped" else: - comment = "Stopping service: {}".format(name) + comment = f"Stopping service: {name}" log.debug(comment) all_processes = __salt__["supervisord.status"]( @@ -303,11 +303,11 @@ def dead(name, user=None, conf_file=None, bin_env=None, **kwargs): is_stopped = False else: # process name doesn't exist - ret["comment"] = "Service {} doesn't exist".format(name) + ret["comment"] = f"Service {name} doesn't exist" return ret if is_stopped is True: - ret["comment"] = "Service {} is not running".format(name) + ret["comment"] = f"Service {name} is not running" else: result = { name: __salt__["supervisord.stop"]( diff --git a/salt/states/svn.py b/salt/states/svn.py index c041d4f27a6..aac0dca9fa9 100644 --- a/salt/states/svn.py +++ b/salt/states/svn.py @@ -101,7 +101,7 @@ def latest( opts = tuple() if os.path.exists(target) and not os.path.isdir(target): - return _fail(ret, 'The path "{}" exists and is not a directory.'.format(target)) + return _fail(ret, f'The path "{target}" exists and is not a directory.') if __opts__["test"]: if rev: @@ -123,11 +123,11 @@ def latest( ) svn_cmd = "svn.diff" except exceptions.CommandExecutionError: - return _fail(ret, "{} exists but is not a svn working copy.".format(target)) + return _fail(ret, f"{target} exists but is not a svn working copy.") current_rev = current_info[0]["Revision"] - opts += ("-r", "{}:{}".format(current_rev, new_rev)) + opts += ("-r", f"{current_rev}:{new_rev}") if trust: opts += ("--trust-server-cert",) @@ -173,7 +173,7 @@ def latest( fmt="dict", )[0]["Revision"] if current_rev != new_rev: - ret["changes"]["revision"] = "{} => {}".format(current_rev, new_rev) + ret["changes"]["revision"] = f"{current_rev} => {new_rev}" else: out = __salt__[svn_cmd](cwd, name, basename, user, username, password, *opts) @@ -260,11 +260,11 @@ def export( opts = () if not overwrite and os.path.exists(target) and not os.path.isdir(target): - return _fail(ret, 'The path "{}" exists and is not a directory.'.format(target)) + return _fail(ret, f'The path "{target}" exists and is not a directory.') if __opts__["test"]: if not os.path.exists(target): return _neutral_test( - ret, "{} doesn't exist and is set to be checked out.".format(target) + ret, f"{target} doesn't exist and is set to be checked out." ) svn_cmd = "svn.list" rev = "HEAD" @@ -288,7 +288,7 @@ def export( out = __salt__[svn_cmd](cwd, name, basename, user, username, password, rev, *opts) ret["changes"]["new"] = name - ret["changes"]["comment"] = "{} was Exported to {}".format(name, target) + ret["changes"]["comment"] = f"{name} was Exported to {target}" ret["comment"] = out return ret diff --git a/salt/states/sysctl.py b/salt/states/sysctl.py index 4498e672758..a417512bd1f 100644 --- a/salt/states/sysctl.py +++ b/salt/states/sysctl.py @@ -98,20 +98,20 @@ def present(name, value, config=None): return ret # otherwise, we don't have it set anywhere and need to set it ret["result"] = None - ret["comment"] = "Sysctl option {} would be changed to {}".format(name, value) + ret["comment"] = f"Sysctl option {name} would be changed to {value}" return ret try: update = __salt__["sysctl.persist"](name, value, config) except CommandExecutionError as exc: ret["result"] = False - ret["comment"] = "Failed to set {} to {}: {}".format(name, value, exc) + ret["comment"] = f"Failed to set {name} to {value}: {exc}" return ret if update == "Updated": ret["changes"] = {name: value} - ret["comment"] = "Updated sysctl value {} = {}".format(name, value) + ret["comment"] = f"Updated sysctl value {name} = {value}" elif update == "Already set": - ret["comment"] = "Sysctl value {} = {} is already set".format(name, value) + ret["comment"] = f"Sysctl value {name} = {value} is already set" return ret diff --git a/salt/states/sysfs.py b/salt/states/sysfs.py index afcaf609fbe..e63c6499bc9 100644 --- a/salt/states/sysfs.py +++ b/salt/states/sysfs.py @@ -41,33 +41,33 @@ def present(name, value, config=None): current = __salt__["sysfs.read"](name) if current is False: ret["result"] = False - ret["comment"] = "SysFS attribute {} doesn't exist.".format(name) + ret["comment"] = f"SysFS attribute {name} doesn't exist." else: # if the return is a dict, the "name" is an object not an attribute if isinstance(current, dict): ret["result"] = False - ret["comment"] = "{} is not a SysFS attribute.".format(name) + ret["comment"] = f"{name} is not a SysFS attribute." else: # some attribute files lists all available options and the selected one between [] if isinstance(current, str): current = re.sub(r"(.*\[|\].*)", "", current) if value == current: ret["result"] = True - ret["comment"] = "SysFS attribute {} is already set.".format(name) + ret["comment"] = f"SysFS attribute {name} is already set." else: ret["result"] = None if ret["result"] is None: if __opts__["test"]: - ret["comment"] = "SysFS attribute {} set to be changed.".format(name) + ret["comment"] = f"SysFS attribute {name} set to be changed." else: update = __salt__["sysfs.write"](name, value) if not update: ret["result"] = False - ret["comment"] = "Failed to set {} to {}".format(name, value) + ret["comment"] = f"Failed to set {name} to {value}" else: ret["result"] = True ret["changes"] = {name: value} - ret["comment"] = "Updated SysFS attribute {} to {}".format(name, value) + ret["comment"] = f"Updated SysFS attribute {name} to {value}" return ret diff --git a/salt/states/sysrc.py b/salt/states/sysrc.py index 991e33bbff9..4c7b0d2a57f 100644 --- a/salt/states/sysrc.py +++ b/salt/states/sysrc.py @@ -3,7 +3,6 @@ State to work with sysrc """ - # define the module's virtual name __virtualname__ = "sysrc" @@ -48,11 +47,11 @@ def managed(name, value, **kwargs): for rcname, rcdict in current_state.items(): if rcdict[name] == value: ret["result"] = True - ret["comment"] = "{} is already set to the desired value.".format(name) + ret["comment"] = f"{name} is already set to the desired value." return ret if __opts__["test"] is True: - ret["comment"] = 'The value of "{}" will be changed!'.format(name) + ret["comment"] = f'The value of "{name}" will be changed!' ret["changes"] = { "old": current_state, "new": name + " = " + value + " will be set.", @@ -65,7 +64,7 @@ def managed(name, value, **kwargs): new_state = __salt__["sysrc.set"](name=name, value=value, **kwargs) - ret["comment"] = 'The value of "{}" was changed!'.format(name) + ret["comment"] = f'The value of "{name}" was changed!' ret["changes"] = {"old": current_state, "new": new_state} @@ -92,14 +91,14 @@ def absent(name, **kwargs): current_state = __salt__["sysrc.get"](name=name, **kwargs) if current_state is None: ret["result"] = True - ret["comment"] = '"{}" is already absent.'.format(name) + ret["comment"] = f'"{name}" is already absent.' return ret if __opts__["test"] is True: - ret["comment"] = '"{}" will be removed!'.format(name) + ret["comment"] = f'"{name}" will be removed!' ret["changes"] = { "old": current_state, - "new": '"{}" will be removed.'.format(name), + "new": f'"{name}" will be removed.', } # When test=true return none @@ -109,7 +108,7 @@ def absent(name, **kwargs): new_state = __salt__["sysrc.remove"](name=name, **kwargs) - ret["comment"] = '"{}" was removed!'.format(name) + ret["comment"] = f'"{name}" was removed!' ret["changes"] = {"old": current_state, "new": new_state} diff --git a/salt/states/telemetry_alert.py b/salt/states/telemetry_alert.py index ccbe8fb9791..18ec2bc40ed 100644 --- a/salt/states/telemetry_alert.py +++ b/salt/states/telemetry_alert.py @@ -96,7 +96,7 @@ def present( # del saved_alert_config["_id"] for k, v in post_body.items(): if k not in saved_alert_config: - difference.append("{}={} (new)".format(k, v)) + difference.append(f"{k}={v} (new)") continue v2 = saved_alert_config[k] @@ -108,7 +108,7 @@ def present( continue if isinstance(v, int) and v == int(v2): continue - difference.append("{}='{}' was: '{}'".format(k, v, v2)) + difference.append(f"{k}='{v}' was: '{v2}'") else: difference.append("new alert config") @@ -122,10 +122,10 @@ def present( if saved_alert_config: # alert config is present. update, or do nothing # check to see if attributes matches is_present. If so, do nothing. if len(difference) == 0: - ret["comment"] = "alert config {} present and matching".format(metric_name) + ret["comment"] = f"alert config {metric_name} present and matching" return ret if __opts__["test"]: - msg = "alert config {} is to be updated.".format(metric_name) + msg = f"alert config {metric_name} is to be updated." ret["comment"] = msg ret["result"] = "\n".join(difference) return ret @@ -142,7 +142,7 @@ def present( ) else: # alert config is absent. create it. if __opts__["test"]: - msg = "alert config {} is to be created.".format(metric_name) + msg = f"alert config {metric_name} is to be created." ret["comment"] = msg ret["result"] = None return ret @@ -190,10 +190,10 @@ def absent(name, deployment_id, metric_name, api_key=None, profile="telemetry"): if is_present: alert_id = is_present.get("_id") if __opts__["test"]: - ret[ - "comment" - ] = "alert {} is set to be removed from deployment: {}.".format( - metric_name, deployment_id + ret["comment"] = ( + "alert {} is set to be removed from deployment: {}.".format( + metric_name, deployment_id + ) ) ret["result"] = None return ret diff --git a/salt/states/test.py b/salt/states/test.py index 464f3ee33aa..bdded67a16e 100644 --- a/salt/states/test.py +++ b/salt/states/test.py @@ -478,17 +478,17 @@ def check_pillar( fine[key] = key_type for key, key_type in failed.items(): - comment = 'Pillar key "{}" '.format(key) + comment = f'Pillar key "{key}" ' if key_type is None: comment += "is missing.\n" else: - comment += "is not {}.\n".format(key_type) + comment += f"is not {key_type}.\n" ret["comment"] += comment if verbose and fine: comment = "Those keys passed the check:\n" for key, key_type in fine.items(): - comment += "- {} ({})\n".format(key, key_type) + comment += f"- {key} ({key_type})\n" ret["comment"] += comment return ret diff --git a/salt/states/testinframod.py b/salt/states/testinframod.py index 493fc8ef2eb..d0107ae79d9 100644 --- a/salt/states/testinframod.py +++ b/salt/states/testinframod.py @@ -40,7 +40,7 @@ def _generate_functions(): modules_ = [module_ for module_ in modules.modules] for module_name in modules_: - func_name = "testinfra.{}".format(module_name) + func_name = f"testinfra.{module_name}" __all__.append(module_name) log.debug( "Generating state for module %s as function %s", module_name, func_name diff --git a/salt/states/timezone.py b/salt/states/timezone.py index 514e4c0dda6..208d18e5f0b 100644 --- a/salt/states/timezone.py +++ b/salt/states/timezone.py @@ -58,10 +58,10 @@ def system(name, utc=True): compzone = __salt__["timezone.zone_compare"](name) except (SaltInvocationError, CommandExecutionError) as exc: ret["result"] = False - ret[ - "comment" - ] = "Unable to compare desired timezone '{}' to system timezone: {}".format( - name, exc + ret["comment"] = ( + "Unable to compare desired timezone '{}' to system timezone: {}".format( + name, exc + ) ) return ret @@ -73,7 +73,7 @@ def system(name, utc=True): # Check the time zone if compzone is True: ret["result"] = True - messages.append("Timezone {} already set".format(name)) + messages.append(f"Timezone {name} already set") else: do_zone = True @@ -82,7 +82,7 @@ def system(name, utc=True): ret["result"] = None do_utc = True elif utc and utc == myutc: - messages.append("UTC already set to {}".format(name)) + messages.append(f"UTC already set to {name}") if ret["result"] is True: ret["comment"] = ", ".join(messages) @@ -91,9 +91,9 @@ def system(name, utc=True): if __opts__["test"]: messages = [] if compzone is False: - messages.append("Timezone {} needs to be set".format(name)) + messages.append(f"Timezone {name} needs to be set") if utc and myutc != utc: - messages.append("UTC needs to be set to {}".format(utc)) + messages.append(f"UTC needs to be set to {utc}") ret["comment"] = ", ".join(messages) return ret @@ -102,7 +102,7 @@ def system(name, utc=True): if do_zone: if __salt__["timezone.set_zone"](name): ret["changes"]["timezone"] = name - messages.append("Set timezone {}".format(name)) + messages.append(f"Set timezone {name}") ret["result"] = True else: messages.append("Failed to set timezone") @@ -114,10 +114,10 @@ def system(name, utc=True): clock = "UTC" if __salt__["timezone.set_hwclock"](clock): ret["changes"]["utc"] = utc - messages.append("Set UTC to {}".format(utc)) + messages.append(f"Set UTC to {utc}") ret["result"] = True else: - messages.append("Failed to set UTC to {}".format(utc)) + messages.append(f"Failed to set UTC to {utc}") ret["result"] = False ret["comment"] = ", ".join(messages) diff --git a/salt/states/tls.py b/salt/states/tls.py index 8e0f1249424..9c0fc451711 100644 --- a/salt/states/tls.py +++ b/salt/states/tls.py @@ -4,7 +4,6 @@ Enforce state for SSL/TLS """ - import datetime import logging import time @@ -31,7 +30,7 @@ def valid_certificate(name, weeks=0, days=0, hours=0, minutes=0, seconds=0): try: cert_info = __salt__["tls.cert_info"](name) except OSError as exc: - ret["comment"] = "{}".format(exc) + ret["comment"] = f"{exc}" ret["result"] = False log.error(ret["comment"]) return ret @@ -63,5 +62,5 @@ def valid_certificate(name, weeks=0, days=0, hours=0, minutes=0, seconds=0): return ret ret["result"] = True - ret["comment"] = "Certificate is valid for {}".format(delta_remaining) + ret["comment"] = f"Certificate is valid for {delta_remaining}" return ret diff --git a/salt/states/tomcat.py b/salt/states/tomcat.py index d4511911fd4..5b74573c143 100644 --- a/salt/states/tomcat.py +++ b/salt/states/tomcat.py @@ -142,7 +142,7 @@ def war_deployed( status = True # Gathered/specified new WAR version string - specified_ver = "version {}".format(version) if version else "no version" + specified_ver = f"version {version}" if version else "no version" # Determine what to do try: @@ -172,13 +172,13 @@ def war_deployed( name, specified_ver ) if webapps[name]["mode"] != "running": - ret["changes"]["start"] = "starting {}".format(name) + ret["changes"]["start"] = f"starting {name}" status = False else: return ret except Exception: # pylint: disable=broad-except deploy = True - ret["changes"]["deploy"] = "deployed {} with {}".format(name, specified_ver) + ret["changes"]["deploy"] = f"deployed {name} with {specified_ver}" # Test if __opts__["test"]: @@ -216,7 +216,7 @@ def war_deployed( if deploy_res.startswith("OK"): ret["result"] = True ret["comment"] = str(__salt__["tomcat.ls"](url, timeout)[name]) - ret["changes"]["deploy"] = "deployed {} with {}".format(name, specified_ver) + ret["changes"]["deploy"] = f"deployed {name} with {specified_ver}" else: ret["result"] = False ret["comment"] = deploy_res diff --git a/salt/states/trafficserver.py b/salt/states/trafficserver.py index c491f176bac..55edcd35836 100644 --- a/salt/states/trafficserver.py +++ b/salt/states/trafficserver.py @@ -209,7 +209,7 @@ def config(name, value): __salt__["trafficserver.set_config"](name, value) ret["result"] = True - ret["comment"] = "Configured {} to {}".format(name, value) + ret["comment"] = f"Configured {name} to {value}" return ret @@ -345,11 +345,11 @@ def offline(name, path): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __opts__["test"]: - ret["comment"] = "Setting {} to offline".format(path) + ret["comment"] = f"Setting {path} to offline" return ret __salt__["trafficserver.offline"](path) ret["result"] = True - ret["comment"] = "Set {} as offline".format(path) + ret["comment"] = f"Set {path} as offline" return ret diff --git a/salt/states/uptime.py b/salt/states/uptime.py index 590d1017066..5c284eeb2f1 100644 --- a/salt/states/uptime.py +++ b/salt/states/uptime.py @@ -53,7 +53,7 @@ def monitored(name, **params): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __salt__["uptime.check_exists"](name=name): ret["result"] = True - ret["comment"] = "URL {} is already monitored".format(name) + ret["comment"] = f"URL {name} is already monitored" ret["changes"] = {} return ret if not __opts__["test"]: @@ -65,7 +65,7 @@ def monitored(name, **params): ret["changes"] = {"url_monitored": url_monitored} else: ret["result"] = False - ret["comment"] = "Failed to add {} to uptime".format(name) + ret["comment"] = f"Failed to add {name} to uptime" ret["changes"] = {} else: msg = "URL {0} is going to be added to uptime" diff --git a/salt/states/user.py b/salt/states/user.py index 756ec17d19a..f0452fa2f60 100644 --- a/salt/states/user.py +++ b/salt/states/user.py @@ -932,10 +932,10 @@ def present( __salt__["shadow.set_password"](name, password) spost = __salt__["shadow.info"](name) if spost["passwd"] != password: - ret[ - "comment" - ] = "User {} created but failed to set password to {}".format( - name, "XXX-REDACTED-XXX" + ret["comment"] = ( + "User {} created but failed to set password to {}".format( + name, "XXX-REDACTED-XXX" + ) ) ret["result"] = False ret["changes"]["password"] = "XXX-REDACTED-XXX" @@ -943,9 +943,9 @@ def present( __salt__["shadow.del_password"](name) spost = __salt__["shadow.info"](name) if spost["passwd"] != "": - ret[ - "comment" - ] = f"User {name} created but failed to empty password" + ret["comment"] = ( + f"User {name} created but failed to empty password" + ) ret["result"] = False ret["changes"]["password"] = "" if date is not None: @@ -996,10 +996,10 @@ def present( __salt__["shadow.set_warndays"](name, warndays) spost = __salt__["shadow.info"](name) if spost["warn"] != warndays: - ret[ - "comment" - ] = "User {} created but failed to set warn days to {}".format( - name, warndays + ret["comment"] = ( + "User {} created but failed to set warn days to {}".format( + name, warndays + ) ) ret["result"] = False ret["changes"]["warndays"] = warndays @@ -1017,10 +1017,10 @@ def present( elif salt.utils.platform.is_windows(): if password and not empty_password: if not __salt__["user.setpassword"](name, password): - ret[ - "comment" - ] = "User {} created but failed to set password to {}".format( - name, "XXX-REDACTED-XXX" + ret["comment"] = ( + "User {} created but failed to set password to {}".format( + name, "XXX-REDACTED-XXX" + ) ) ret["result"] = False ret["changes"]["passwd"] = "XXX-REDACTED-XXX" @@ -1039,10 +1039,10 @@ def present( ret["changes"]["expiration_date"] = spost["expire"] elif salt.utils.platform.is_darwin() and password and not empty_password: if not __salt__["shadow.set_password"](name, password): - ret[ - "comment" - ] = "User {} created but failed to set password to {}".format( - name, "XXX-REDACTED-XXX" + ret["comment"] = ( + "User {} created but failed to set password to {}".format( + name, "XXX-REDACTED-XXX" + ) ) ret["result"] = False ret["changes"]["passwd"] = "XXX-REDACTED-XXX" diff --git a/salt/states/vagrant.py b/salt/states/vagrant.py index 4210715f92e..93650d54de0 100644 --- a/salt/states/vagrant.py +++ b/salt/states/vagrant.py @@ -103,7 +103,7 @@ def _vagrant_call(node, function, section, comment, status_when_done=None, **kwa except (IndexError, SaltInvocationError, CommandExecutionError): pass try: - response = __salt__["vagrant.{}".format(function)](node, **kwargs) + response = __salt__[f"vagrant.{function}"](node, **kwargs) if isinstance(response, dict): response = response["name"] changed_nodes.append({"node": node, function: response}) @@ -170,7 +170,7 @@ def running(name, **kwargs): "name": name, "changes": {}, "result": True, - "comment": "{} is already running".format(name), + "comment": f"{name} is already running", } try: @@ -178,14 +178,14 @@ def running(name, **kwargs): if info[0]["state"] != "running": __salt__["vagrant.start"](name) ret["changes"][name] = "Machine started" - ret["comment"] = "Node {} started".format(name) + ret["comment"] = f"Node {name} started" except (SaltInvocationError, CommandExecutionError): # there was no viable existing machine to start ret, kwargs = _find_init_change(name, ret, **kwargs) kwargs["start"] = True __salt__["vagrant.init"](name, **kwargs) ret["changes"][name] = "Node defined and started" - ret["comment"] = "Node {} defined and started".format(name) + ret["comment"] = f"Node {name} defined and started" return ret @@ -272,7 +272,7 @@ def initialized(name, **kwargs): kwargs["start"] = False __salt__["vagrant.init"](name, **kwargs) ret["changes"][name] = "Node initialized" - ret["comment"] = "Node {} defined but not started.".format(name) + ret["comment"] = f"Node {name} defined but not started." return ret diff --git a/salt/states/vbox_guest.py b/salt/states/vbox_guest.py index 45a78381d59..78907dd14f7 100644 --- a/salt/states/vbox_guest.py +++ b/salt/states/vbox_guest.py @@ -126,9 +126,9 @@ def grant_access_to_shared_folders_to(name, users=None): name=name, users=users ) - ret[ - "comment" - ] = "List of users who have access to auto-mounted shared folders was changed" + ret["comment"] = ( + "List of users who have access to auto-mounted shared folders was changed" + ) ret["changes"] = { "old": current_state, "new": new_state, diff --git a/salt/states/victorops.py b/salt/states/victorops.py index 54cf5353a2c..f89265fe2cb 100644 --- a/salt/states/victorops.py +++ b/salt/states/victorops.py @@ -93,7 +93,7 @@ def create_event(name, message_type, routing_key="everyone", **kwargs): ret = {"name": name, "changes": {}, "result": None, "comment": ""} if __opts__["test"]: - ret["comment"] = "Need to create event: {}".format(name) + ret["comment"] = f"Need to create event: {name}" return ret res = __salt__["victorops.create_event"]( diff --git a/salt/states/virt.py b/salt/states/virt.py index 3b958e32d60..33f35b0d8c8 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -11,7 +11,6 @@ for the generation and signing of certificates for systems running libvirt: virt.keys """ - import fnmatch import logging import os @@ -95,7 +94,7 @@ def keys(name, basepath="/etc/pki", **kwargs): # overriding anything existing pillar_kwargs = {} for key, value in kwargs.items(): - pillar_kwargs["ext_pillar_virt.{}".format(key)] = value + pillar_kwargs[f"ext_pillar_virt.{key}"] = value pillar = __salt__["pillar.ext"]({"libvirt": "_"}, pillar_kwargs) paths = { @@ -107,7 +106,7 @@ def keys(name, basepath="/etc/pki", **kwargs): } for key in paths: - p_key = "libvirt.{}.pem".format(key) + p_key = f"libvirt.{key}.pem" if p_key not in pillar: continue if not os.path.exists(os.path.dirname(paths[key])): @@ -128,9 +127,7 @@ def keys(name, basepath="/etc/pki", **kwargs): else: for key in ret["changes"]: with salt.utils.files.fopen(paths[key], "w+") as fp_: - fp_.write( - salt.utils.stringutils.to_str(pillar["libvirt.{}.pem".format(key)]) - ) + fp_.write(salt.utils.stringutils.to_str(pillar[f"libvirt.{key}.pem"])) ret["comment"] = "Updated libvirt certs and keys" @@ -146,7 +143,7 @@ def _virt_call( connection=None, username=None, password=None, - **kwargs + **kwargs, ): """ Helper to call the virt functions. Wildcards supported. @@ -174,12 +171,12 @@ def _virt_call( if action_needed: response = True if not __opts__["test"]: - response = __salt__["virt.{}".format(function)]( + response = __salt__[f"virt.{function}"]( targeted_domain, connection=connection, username=username, password=password, - **kwargs + **kwargs, ) if isinstance(response, dict): response = response["name"] @@ -677,14 +674,12 @@ def defined( ret["changes"][name] = status if not status.get("definition"): ret["changes"] = {} - ret["comment"] = "Domain {} unchanged".format(name) + ret["comment"] = f"Domain {name} unchanged" ret["result"] = True elif status.get("errors"): - ret[ - "comment" - ] = "Domain {} updated with live update(s) failures".format(name) + ret["comment"] = f"Domain {name} updated with live update(s) failures" else: - ret["comment"] = "Domain {} updated".format(name) + ret["comment"] = f"Domain {name} updated" else: if not __opts__["test"]: __salt__["virt.init"]( @@ -718,7 +713,7 @@ def defined( host_devices=host_devices, ) ret["changes"][name] = {"definition": True} - ret["comment"] = "Domain {} defined".format(name) + ret["comment"] = f"Domain {name} defined" except libvirt.libvirtError as err: # Something bad happened when defining / updating the VM, report it ret["comment"] = str(err) @@ -1050,7 +1045,7 @@ def running( username=username, password=password, ) - comment = "Domain {} started".format(name) + comment = f"Domain {name} started" if not ret["comment"].endswith("unchanged"): comment = "{} and started".format(ret["comment"]) ret["comment"] = comment @@ -1058,7 +1053,7 @@ def running( ret["changes"][name] = {} ret["changes"][name]["started"] = True elif not changed: - ret["comment"] = "Domain {} exists and is running".format(name) + ret["comment"] = f"Domain {name} exists and is running" except libvirt.libvirtError as err: # Something bad happened when starting / updating the VM, report it @@ -1207,7 +1202,7 @@ def reverted( try: domains = fnmatch.filter(__salt__["virt.list_domains"](), name) if not domains: - ret["comment"] = 'No domains found for criteria "{}"'.format(name) + ret["comment"] = f'No domains found for criteria "{name}"' else: ignored_domains = list() if len(domains) > 1: @@ -1516,10 +1511,10 @@ def network_defined( password=password, ) action = ", autostart flag changed" if needs_autostart else "" - ret["changes"][name] = "Network updated{}".format(action) - ret["comment"] = "Network {} updated{}".format(name, action) + ret["changes"][name] = f"Network updated{action}" + ret["comment"] = f"Network {name} updated{action}" else: - ret["comment"] = "Network {} unchanged".format(name) + ret["comment"] = f"Network {name} unchanged" ret["result"] = True else: needs_autostart = autostart @@ -1547,10 +1542,10 @@ def network_defined( ) if needs_autostart: ret["changes"][name] = "Network defined, marked for autostart" - ret["comment"] = "Network {} defined, marked for autostart".format(name) + ret["comment"] = f"Network {name} defined, marked for autostart" else: ret["changes"][name] = "Network defined" - ret["comment"] = "Network {} defined".format(name) + ret["comment"] = f"Network {name} defined" if needs_autostart: if not __opts__["test"]: @@ -1975,15 +1970,13 @@ def pool_defined( action = ", built" action = ( - "{}, autostart flag changed".format(action) - if needs_autostart - else action + f"{action}, autostart flag changed" if needs_autostart else action ) - ret["changes"][name] = "Pool updated{}".format(action) - ret["comment"] = "Pool {} updated{}".format(name, action) + ret["changes"][name] = f"Pool updated{action}" + ret["comment"] = f"Pool {name} updated{action}" else: - ret["comment"] = "Pool {} unchanged".format(name) + ret["comment"] = f"Pool {name} unchanged" ret["result"] = True else: needs_autostart = autostart @@ -2026,10 +2019,10 @@ def pool_defined( ) if needs_autostart: ret["changes"][name] = "Pool defined, marked for autostart" - ret["comment"] = "Pool {} defined, marked for autostart".format(name) + ret["comment"] = f"Pool {name} defined, marked for autostart" else: ret["changes"][name] = "Pool defined" - ret["comment"] = "Pool {} defined".format(name) + ret["comment"] = f"Pool {name} defined" if needs_autostart: if not __opts__["test"]: @@ -2147,7 +2140,7 @@ def pool_running( username=username, password=password, ) - action = "built, {}".format(action) + action = f"built, {action}" else: action = "already running" result = True @@ -2161,16 +2154,16 @@ def pool_running( password=password, ) - comment = "Pool {}".format(name) + comment = f"Pool {name}" change = "Pool" if name in ret["changes"]: comment = "{},".format(ret["comment"]) change = "{},".format(ret["changes"][name]) if action != "already running": - ret["changes"][name] = "{} {}".format(change, action) + ret["changes"][name] = f"{change} {action}" - ret["comment"] = "{} {}".format(comment, action) + ret["comment"] = f"{comment} {action}" ret["result"] = result except libvirt.libvirtError as err: @@ -2302,9 +2295,9 @@ def pool_deleted(name, purge=False, connection=None, username=None, password=Non info[name]["type"], ", ".join(unsupported) ) else: - ret["comment"] = "Storage pool could not be found: {}".format(name) + ret["comment"] = f"Storage pool could not be found: {name}" except libvirt.libvirtError as err: - ret["comment"] = "Failed deleting pool: {}".format(err.get_error_message()) + ret["comment"] = f"Failed deleting pool: {err.get_error_message()}" ret["result"] = False return ret @@ -2390,7 +2383,7 @@ def volume_defined( connection=connection, username=username, password=password ) if pool not in pools: - raise SaltInvocationError("Storage pool {} not existing".format(pool)) + raise SaltInvocationError(f"Storage pool {pool} not existing") vol_infos = ( __salt__["virt.volume_infos"]( @@ -2422,9 +2415,9 @@ def volume_defined( # otherwise assume the volume has already been defined # if the sizes don't match, issue a warning comment: too dangerous to do this for now if int(vol_infos.get("capacity")) != int(size) * 1024 * 1024: - ret[ - "comment" - ] = "The capacity of the volume is different, but no resize performed" + ret["comment"] = ( + "The capacity of the volume is different, but no resize performed" + ) return ret ret["result"] = None if __opts__["test"] else True @@ -2450,7 +2443,7 @@ def volume_defined( ret["comment"] = "Volume {} {}defined in pool {}".format( name, test_comment, pool ) - ret["changes"] = {"{}/{}".format(pool, name): {"old": "", "new": "defined"}} + ret["changes"] = {f"{pool}/{name}": {"old": "", "new": "defined"}} except libvirt.libvirtError as err: ret["comment"] = err.get_error_message() ret["result"] = False diff --git a/salt/states/virtualenv_mod.py b/salt/states/virtualenv_mod.py index d395dd2cc1a..957f44265bc 100644 --- a/salt/states/virtualenv_mod.py +++ b/salt/states/virtualenv_mod.py @@ -4,7 +4,6 @@ Setup of Python virtualenv sandboxes. .. versionadded:: 0.17.0 """ - import logging import os @@ -58,7 +57,7 @@ def managed( pip_cache_dir=None, process_dependency_links=False, no_binary=None, - **kwargs + **kwargs, ): """ Create a virtualenv and optionally manage it with pip @@ -172,21 +171,19 @@ def managed( # If it already exists, grab the version for posterity if venv_exists and clear: ret["changes"]["cleared_packages"] = __salt__["pip.freeze"](bin_env=name) - ret["changes"]["old"] = __salt__["cmd.run_stderr"]( - "{} -V".format(venv_py) - ).strip("\n") + ret["changes"]["old"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n") # Create (or clear) the virtualenv if __opts__["test"]: if venv_exists and clear: ret["result"] = None - ret["comment"] = "Virtualenv {} is set to be cleared".format(name) + ret["comment"] = f"Virtualenv {name} is set to be cleared" return ret if venv_exists and not clear: - ret["comment"] = "Virtualenv {} is already created".format(name) + ret["comment"] = f"Virtualenv {name} is already created" return ret ret["result"] = None - ret["comment"] = "Virtualenv {} is set to be created".format(name) + ret["comment"] = f"Virtualenv {name} is set to be created" return ret if not venv_exists or (venv_exists and clear): @@ -203,11 +200,11 @@ def managed( prompt=prompt, user=user, use_vt=use_vt, - **kwargs + **kwargs, ) except CommandNotFoundError as err: ret["result"] = False - ret["comment"] = "Failed to create virtualenv: {}".format(err) + ret["comment"] = f"Failed to create virtualenv: {err}" return ret if venv_ret["retcode"] != 0: @@ -216,9 +213,7 @@ def managed( return ret ret["result"] = True - ret["changes"]["new"] = __salt__["cmd.run_stderr"]( - "{} -V".format(venv_py) - ).strip("\n") + ret["changes"]["new"] = __salt__["cmd.run_stderr"](f"{venv_py} -V").strip("\n") if clear: ret["comment"] = "Cleared existing virtualenv" @@ -329,7 +324,7 @@ def managed( env_vars=env_vars, no_cache_dir=pip_no_cache_dir, cache_dir=pip_cache_dir, - **kwargs + **kwargs, ) ret["result"] &= pip_ret["retcode"] == 0 if pip_ret["retcode"] > 0: diff --git a/salt/states/webutil.py b/salt/states/webutil.py index 573e494cef6..d83190f8ac9 100644 --- a/salt/states/webutil.py +++ b/salt/states/webutil.py @@ -14,7 +14,6 @@ Support for htpasswd module. Requires the apache2-utils package for Debian-based """ - import salt.utils.path __virtualname__ = "webutil" @@ -67,9 +66,7 @@ def user_exists( ret = {"name": name, "changes": {}, "comment": "", "result": None} if __salt__["file.file_exists"](htpasswd_file): - exists = ( - __salt__["file.grep"](htpasswd_file, "^{}:".format(name))["retcode"] == 0 - ) + exists = __salt__["file.grep"](htpasswd_file, f"^{name}:")["retcode"] == 0 else: exists = False @@ -127,7 +124,7 @@ def user_absent(name, htpasswd_file=None, runas=None): """ ret = {"name": name, "changes": {}, "comment": "", "result": None} - exists = __salt__["file.grep"](htpasswd_file, "^{}:".format(name))["retcode"] == 0 + exists = __salt__["file.grep"](htpasswd_file, f"^{name}:")["retcode"] == 0 if not exists: if __opts__["test"]: diff --git a/salt/states/win_appx.py b/salt/states/win_appx.py index e3e1e9a3fb6..432c1556d75 100644 --- a/salt/states/win_appx.py +++ b/salt/states/win_appx.py @@ -4,6 +4,7 @@ deprovision the app from the online Windows image. .. versionadded:: 3007.0 """ + import fnmatch import logging diff --git a/salt/states/win_certutil.py b/salt/states/win_certutil.py index 392139d8a49..fa3c78e4af3 100644 --- a/salt/states/win_certutil.py +++ b/salt/states/win_certutil.py @@ -61,38 +61,38 @@ def add_store(name, store, saltenv="base"): cert_file = __salt__["cp.cache_file"](name, saltenv) if cert_file is False: - ret["comment"] = "Certificate file not found: {}".format(name) + ret["comment"] = f"Certificate file not found: {name}" ret["result"] = False return ret cert_serial = __salt__["certutil.get_cert_serial"](name) if cert_serial is None: - ret["comment"] = "Invalid certificate file: {}".format(name) + ret["comment"] = f"Invalid certificate file: {name}" ret["result"] = False return ret old_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial in old_serials: - ret["comment"] = "Certificate already present: {}".format(name) + ret["comment"] = f"Certificate already present: {name}" return ret if __opts__["test"]: - ret["comment"] = "Certificate will be added: {}".format(name) + ret["comment"] = f"Certificate will be added: {name}" ret["result"] = None return ret retcode = __salt__["certutil.add_store"](name, store, retcode=True) if retcode != 0: - ret["comment"] = "Error adding certificate: {}".format(name) + ret["comment"] = f"Error adding certificate: {name}" ret["result"] = False return ret new_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial in new_serials: ret["changes"]["added"] = name - ret["comment"] = "Added certificate: {}".format(name) + ret["comment"] = f"Added certificate: {name}" else: - ret["comment"] = "Failed to add certificate: {}".format(name) + ret["comment"] = f"Failed to add certificate: {name}" ret["result"] = False return ret @@ -131,38 +131,38 @@ def del_store(name, store, saltenv="base"): cert_file = __salt__["cp.cache_file"](name, saltenv) if cert_file is False: - ret["comment"] = "Certificate file not found: {}".format(name) + ret["comment"] = f"Certificate file not found: {name}" ret["result"] = False return ret cert_serial = __salt__["certutil.get_cert_serial"](name) if cert_serial is None: - ret["comment"] = "Invalid certificate file: {}".format(name) + ret["comment"] = f"Invalid certificate file: {name}" ret["result"] = False return ret old_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial not in old_serials: - ret["comment"] = "Certificate already absent: {}".format(name) + ret["comment"] = f"Certificate already absent: {name}" return ret if __opts__["test"]: - ret["comment"] = "Certificate will be removed: {}".format(name) + ret["comment"] = f"Certificate will be removed: {name}" ret["result"] = None return ret retcode = __salt__["certutil.del_store"](name, store, retcode=True) if retcode != 0: - ret["comment"] = "Error removing certificate: {}".format(name) + ret["comment"] = f"Error removing certificate: {name}" ret["result"] = False return ret new_serials = __salt__["certutil.get_stored_cert_serials"](store=store) if cert_serial not in new_serials: ret["changes"]["removed"] = name - ret["comment"] = "Removed certificate: {}".format(name) + ret["comment"] = f"Removed certificate: {name}" else: - ret["comment"] = "Failed to remove certificate: {}".format(name) + ret["comment"] = f"Failed to remove certificate: {name}" ret["result"] = False return ret diff --git a/salt/states/win_dns_client.py b/salt/states/win_dns_client.py index 9afa0faf368..dcd56a4eada 100644 --- a/salt/states/win_dns_client.py +++ b/salt/states/win_dns_client.py @@ -53,7 +53,7 @@ def dns_exists(name, servers=None, interface="Local Area Connection", replace=Fa # Do nothing is already configured configured_list = __salt__["win_dns_client.get_dns_servers"](interface) if configured_list == servers: - ret["comment"] = "{} are already configured".format(servers) + ret["comment"] = f"{servers} are already configured" ret["changes"] = {} ret["result"] = True return ret @@ -89,9 +89,9 @@ def dns_exists(name, servers=None, interface="Local Area Connection", replace=Fa ret["changes"]["Servers Removed"].append(server) else: if not __salt__["win_dns_client.rm_dns"](server, interface): - ret[ - "comment" - ] = "Failed to remove {} from DNS server list".format(server) + ret["comment"] = ( + f"Failed to remove {server} from DNS server list" + ) ret["result"] = False return ret else: @@ -109,7 +109,7 @@ def dns_dhcp(name, interface="Local Area Connection"): # Check the config config = __salt__["win_dns_client.get_dns_config"](interface) if config == "dhcp": - ret["comment"] = "{} already configured with DNS from DHCP".format(interface) + ret["comment"] = f"{interface} already configured with DNS from DHCP" return ret else: ret["changes"] = {"dns": "configured from DHCP"} @@ -208,7 +208,7 @@ def primary_suffix(name, suffix=None, updates=False): return ret # Changes to update policy needed else: - ret["comment"] = "{} suffix updates".format(updates_operation) + ret["comment"] = f"{updates_operation} suffix updates" ret["changes"] = { "old": {"updates": reg_data["updates"]["old"]}, "new": {"updates": reg_data["updates"]["new"]}, @@ -217,10 +217,10 @@ def primary_suffix(name, suffix=None, updates=False): else: # Changes to updates policy needed if reg_data["updates"]["new"] != reg_data["updates"]["old"]: - ret[ - "comment" - ] = "Updated primary DNS suffix ({}) and {} suffix updates".format( - suffix, updates_operation + ret["comment"] = ( + "Updated primary DNS suffix ({}) and {} suffix updates".format( + suffix, updates_operation + ) ) ret["changes"] = { "old": { @@ -234,7 +234,7 @@ def primary_suffix(name, suffix=None, updates=False): } # No changes to updates policy needed else: - ret["comment"] = "Updated primary DNS suffix ({})".format(suffix) + ret["comment"] = f"Updated primary DNS suffix ({suffix})" ret["changes"] = { "old": {"suffix": reg_data["suffix"]["old"]}, "new": {"suffix": reg_data["suffix"]["new"]}, diff --git a/salt/states/win_firewall.py b/salt/states/win_firewall.py index 959021ede74..151519f8ee0 100644 --- a/salt/states/win_firewall.py +++ b/salt/states/win_firewall.py @@ -52,12 +52,12 @@ def disabled(name="allprofiles"): # Make sure the profile name is valid if name not in profile_map: - raise SaltInvocationError("Invalid profile name: {}".format(name)) + raise SaltInvocationError(f"Invalid profile name: {name}") current_config = __salt__["firewall.get_config"]() if name != "allprofiles" and profile_map[name] not in current_config: ret["result"] = False - ret["comment"] = "Profile {} does not exist in firewall.get_config".format(name) + ret["comment"] = f"Profile {name} does not exist in firewall.get_config" return ret for key in current_config: @@ -83,7 +83,7 @@ def disabled(name="allprofiles"): if name == "allprofiles": msg = "All the firewall profiles are disabled" else: - msg = "Firewall profile {} is disabled".format(name) + msg = f"Firewall profile {name} is disabled" ret["comment"] = msg return ret @@ -211,12 +211,12 @@ def enabled(name="allprofiles"): # Make sure the profile name is valid if name not in profile_map: - raise SaltInvocationError("Invalid profile name: {}".format(name)) + raise SaltInvocationError(f"Invalid profile name: {name}") current_config = __salt__["firewall.get_config"]() if name != "allprofiles" and profile_map[name] not in current_config: ret["result"] = False - ret["comment"] = "Profile {} does not exist in firewall.get_config".format(name) + ret["comment"] = f"Profile {name} does not exist in firewall.get_config" return ret for key in current_config: @@ -242,7 +242,7 @@ def enabled(name="allprofiles"): if name == "allprofiles": msg = "All the firewall profiles are enabled" else: - msg = "Firewall profile {} is enabled".format(name) + msg = f"Firewall profile {name} is enabled" ret["comment"] = msg return ret diff --git a/salt/states/win_iis.py b/salt/states/win_iis.py index 773f7e7b3ad..da9a01a2b35 100644 --- a/salt/states/win_iis.py +++ b/salt/states/win_iis.py @@ -8,7 +8,6 @@ from Microsoft IIS. """ - # Define the module's virtual name __virtualname__ = "win_iis" @@ -85,13 +84,13 @@ def deployed( current_sites = __salt__["win_iis.list_sites"]() if name in current_sites: - ret["comment"] = "Site already present: {}".format(name) + ret["comment"] = f"Site already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Site will be created: {}".format(name) + ret["comment"] = f"Site will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created site: {}".format(name) + ret["comment"] = f"Created site: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_site"]( name, sourcepath, apppool, hostheader, ipaddress, port, protocol @@ -119,13 +118,13 @@ def remove_site(name): current_sites = __salt__["win_iis.list_sites"]() if name not in current_sites: - ret["comment"] = "Site has already been removed: {}".format(name) + ret["comment"] = f"Site has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Site will be removed: {}".format(name) + ret["comment"] = f"Site will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed site: {}".format(name) + ret["comment"] = f"Removed site: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_site"](name) return ret @@ -177,13 +176,13 @@ def create_binding( current_bindings = __salt__["win_iis.list_bindings"](site) if binding_info in current_bindings: - ret["comment"] = "Binding already present: {}".format(binding_info) + ret["comment"] = f"Binding already present: {binding_info}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Binding will be created: {}".format(binding_info) + ret["comment"] = f"Binding will be created: {binding_info}" ret["changes"] = {"old": None, "new": binding_info} else: - ret["comment"] = "Created binding: {}".format(binding_info) + ret["comment"] = f"Created binding: {binding_info}" ret["changes"] = {"old": None, "new": binding_info} ret["result"] = __salt__["win_iis.create_binding"]( site, hostheader, ipaddress, port, protocol, sslflags @@ -225,13 +224,13 @@ def remove_binding(name, site, hostheader="", ipaddress="*", port=80): current_bindings = __salt__["win_iis.list_bindings"](site) if binding_info not in current_bindings: - ret["comment"] = "Binding has already been removed: {}".format(binding_info) + ret["comment"] = f"Binding has already been removed: {binding_info}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Binding will be removed: {}".format(binding_info) + ret["comment"] = f"Binding will be removed: {binding_info}" ret["changes"] = {"old": binding_info, "new": None} else: - ret["comment"] = "Removed binding: {}".format(binding_info) + ret["comment"] = f"Removed binding: {binding_info}" ret["changes"] = {"old": binding_info, "new": None} ret["result"] = __salt__["win_iis.remove_binding"]( site, hostheader, ipaddress, port @@ -287,7 +286,7 @@ def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslf current_name = current_cert_bindings[binding_info]["certificatehash"] if name == current_name: - ret["comment"] = "Certificate binding already present: {}".format(name) + ret["comment"] = f"Certificate binding already present: {name}" ret["result"] = True return ret ret["comment"] = ( @@ -296,10 +295,10 @@ def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslf ) ret["result"] = False elif __opts__["test"]: - ret["comment"] = "Certificate binding will be created: {}".format(name) + ret["comment"] = f"Certificate binding will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created certificate binding: {}".format(name) + ret["comment"] = f"Created certificate binding: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_cert_binding"]( name, site, hostheader, ipaddress, port, sslflags @@ -351,16 +350,16 @@ def remove_cert_binding(name, site, hostheader="", ipaddress="*", port=443): current_cert_bindings = __salt__["win_iis.list_cert_bindings"](site) if binding_info not in current_cert_bindings: - ret["comment"] = "Certificate binding has already been removed: {}".format(name) + ret["comment"] = f"Certificate binding has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Certificate binding will be removed: {}".format(name) + ret["comment"] = f"Certificate binding will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: current_name = current_cert_bindings[binding_info]["certificatehash"] if name == current_name: - ret["comment"] = "Removed certificate binding: {}".format(name) + ret["comment"] = f"Removed certificate binding: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_cert_binding"]( name, site, hostheader, ipaddress, port @@ -394,13 +393,13 @@ def create_apppool(name): current_apppools = __salt__["win_iis.list_apppools"]() if name in current_apppools: - ret["comment"] = "Application pool already present: {}".format(name) + ret["comment"] = f"Application pool already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application pool will be created: {}".format(name) + ret["comment"] = f"Application pool will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created application pool: {}".format(name) + ret["comment"] = f"Created application pool: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_apppool"](name) return ret @@ -427,13 +426,13 @@ def remove_apppool(name): current_apppools = __salt__["win_iis.list_apppools"]() if name not in current_apppools: - ret["comment"] = "Application pool has already been removed: {}".format(name) + ret["comment"] = f"Application pool has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application pool will be removed: {}".format(name) + ret["comment"] = f"Application pool will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed application pool: {}".format(name) + ret["comment"] = f"Removed application pool: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_apppool"](name) return ret @@ -606,13 +605,13 @@ def create_app(name, site, sourcepath, apppool=None): current_apps = __salt__["win_iis.list_apps"](site) if name in current_apps: - ret["comment"] = "Application already present: {}".format(name) + ret["comment"] = f"Application already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application will be created: {}".format(name) + ret["comment"] = f"Application will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created application: {}".format(name) + ret["comment"] = f"Created application: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_app"](name, site, sourcepath, apppool) return ret @@ -639,13 +638,13 @@ def remove_app(name, site): current_apps = __salt__["win_iis.list_apps"](site) if name not in current_apps: - ret["comment"] = "Application has already been removed: {}".format(name) + ret["comment"] = f"Application has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Application will be removed: {}".format(name) + ret["comment"] = f"Application will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed application: {}".format(name) + ret["comment"] = f"Removed application: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_app"](name, site) return ret @@ -692,13 +691,13 @@ def create_vdir(name, site, sourcepath, app="/"): current_vdirs = __salt__["win_iis.list_vdirs"](site, app) if name in current_vdirs: - ret["comment"] = "Virtual directory already present: {}".format(name) + ret["comment"] = f"Virtual directory already present: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Virtual directory will be created: {}".format(name) + ret["comment"] = f"Virtual directory will be created: {name}" ret["changes"] = {"old": None, "new": name} else: - ret["comment"] = "Created virtual directory: {}".format(name) + ret["comment"] = f"Created virtual directory: {name}" ret["changes"] = {"old": None, "new": name} ret["result"] = __salt__["win_iis.create_vdir"](name, site, sourcepath, app) @@ -737,13 +736,13 @@ def remove_vdir(name, site, app="/"): current_vdirs = __salt__["win_iis.list_vdirs"](site, app) if name not in current_vdirs: - ret["comment"] = "Virtual directory has already been removed: {}".format(name) + ret["comment"] = f"Virtual directory has already been removed: {name}" ret["result"] = True elif __opts__["test"]: - ret["comment"] = "Virtual directory will be removed: {}".format(name) + ret["comment"] = f"Virtual directory will be removed: {name}" ret["changes"] = {"old": name, "new": None} else: - ret["comment"] = "Removed virtual directory: {}".format(name) + ret["comment"] = f"Removed virtual directory: {name}" ret["changes"] = {"old": name, "new": None} ret["result"] = __salt__["win_iis.remove_vdir"](name, site, app) diff --git a/salt/states/win_lgpo.py b/salt/states/win_lgpo.py index 07b5d98cb08..669a3d44dae 100644 --- a/salt/states/win_lgpo.py +++ b/salt/states/win_lgpo.py @@ -206,6 +206,7 @@ Multiple policy configuration Windows Components\\Windows Update\\Configure Automatic Updates: """ + import logging import salt.utils.data @@ -428,7 +429,7 @@ def set_( ) deprecation_comments.append(msg) else: - msg = "Invalid element name: {}".format(e_name) + msg = f"Invalid element name: {e_name}" ret["comment"] = "\n".join( [ret["comment"], msg] ).strip() @@ -525,7 +526,7 @@ def set_( ) policy_changes.append(p_name) else: - msg = '"{}" is already set'.format(p_name) + msg = f'"{p_name}" is already set' log.debug(msg) else: policy_changes.append(p_name) diff --git a/salt/states/win_lgpo_reg.py b/salt/states/win_lgpo_reg.py index 8377817a198..1a01ea17c0f 100644 --- a/salt/states/win_lgpo_reg.py +++ b/salt/states/win_lgpo_reg.py @@ -53,6 +53,7 @@ configure that policy. you will have to find the values needed to set them with this module using a different method. """ + import salt.utils.data import salt.utils.platform @@ -251,7 +252,7 @@ def value_disabled(name, key, policy_class="Machine"): old = _get_current(key=key, name=name, policy_class=policy_class) - pol_correct = old["pol"].get("data", "") == "**del.{}".format(name) + pol_correct = old["pol"].get("data", "") == f"**del.{name}" reg_correct = old["reg"] == {} if pol_correct and reg_correct: @@ -273,7 +274,7 @@ def value_disabled(name, key, policy_class="Machine"): new = _get_current(key=key, name=name, policy_class=policy_class) - pol_correct = new["pol"].get("data", "") == "**del.{}".format(name) + pol_correct = new["pol"].get("data", "") == f"**del.{name}" reg_correct = new["reg"] == {} if pol_correct and reg_correct: diff --git a/salt/states/win_network.py b/salt/states/win_network.py index 72bf74fca13..c35ee8ed6ad 100644 --- a/salt/states/win_network.py +++ b/salt/states/win_network.py @@ -137,7 +137,7 @@ def _validate(dns_proto, dns_servers, ip_proto, ip_addrs, gateway): # Validate default gateway if gateway is not None: if not salt.utils.validate.net.ipv4_addr(gateway): - errors.append("Gateway IP {} is invalid".format(gateway)) + errors.append(f"Gateway IP {gateway} is invalid") return errors @@ -198,7 +198,7 @@ def managed( ip_addrs=None, gateway=None, enabled=True, - **kwargs + **kwargs, ): """ Ensure that the named interface is configured properly. @@ -262,7 +262,7 @@ def managed( "name": name, "changes": {}, "result": True, - "comment": "Interface '{}' is up to date".format(name), + "comment": f"Interface '{name}' is up to date", } dns_proto = str(dns_proto).lower() @@ -296,11 +296,11 @@ def managed( if currently_enabled: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Interface '{}' will be disabled".format(name) + ret["comment"] = f"Interface '{name}' will be disabled" else: ret["result"] = __salt__["ip.disable"](name) if not ret["result"]: - ret["comment"] = "Failed to disable interface '{}'".format(name) + ret["comment"] = f"Failed to disable interface '{name}'" else: ret["comment"] += " (already disabled)" return ret @@ -308,31 +308,31 @@ def managed( if not currently_enabled: if __opts__["test"]: ret["result"] = None - ret["comment"] = "Interface '{}' will be enabled".format(name) + ret["comment"] = f"Interface '{name}' will be enabled" else: if not __salt__["ip.enable"](name): ret["result"] = False - ret[ - "comment" - ] = "Failed to enable interface '{}' to make changes".format(name) + ret["comment"] = ( + f"Failed to enable interface '{name}' to make changes" + ) return ret errors = _validate(dns_proto, dns_servers, ip_proto, ip_addrs, gateway) if errors: ret["result"] = False - ret[ - "comment" - ] = "The following SLS configuration errors were detected:\n- {}".format( - "\n- ".join(errors) + ret["comment"] = ( + "The following SLS configuration errors were detected:\n- {}".format( + "\n- ".join(errors) + ) ) return ret old = __salt__["ip.get_interface"](name) if not old: ret["result"] = False - ret[ - "comment" - ] = "Unable to get current configuration for interface '{}'".format(name) + ret["comment"] = ( + f"Unable to get current configuration for interface '{name}'" + ) return ret changes = _changes(old, dns_proto, dns_servers, ip_proto, ip_addrs, gateway) @@ -382,10 +382,10 @@ def managed( ) ret["result"] = None - ret[ - "comment" - ] = "The following changes will be made to interface '{}':\n- {}".format( - name, "\n- ".join(comments) + ret["comment"] = ( + "The following changes will be made to interface '{}':\n- {}".format( + name, "\n- ".join(comments) + ) ) return ret @@ -431,7 +431,7 @@ def managed( "for interface '{}'".format(name) ) else: - ret[ - "comment" - ] = "Successfully updated configuration for interface '{}'".format(name) + ret["comment"] = ( + f"Successfully updated configuration for interface '{name}'" + ) return ret diff --git a/salt/states/win_path.py b/salt/states/win_path.py index 5463cacfdcd..8b3d76ff391 100644 --- a/salt/states/win_path.py +++ b/salt/states/win_path.py @@ -35,21 +35,21 @@ def absent(name): ret = {"name": name, "result": True, "changes": {}, "comment": ""} if not __salt__["win_path.exists"](name): - ret["comment"] = "{} is not in the PATH".format(name) + ret["comment"] = f"{name} is not in the PATH" return ret if __opts__["test"]: - ret["comment"] = "{} would be removed from the PATH".format(name) + ret["comment"] = f"{name} would be removed from the PATH" ret["result"] = None return ret __salt__["win_path.remove"](name) if __salt__["win_path.exists"](name): - ret["comment"] = "Failed to remove {} from the PATH".format(name) + ret["comment"] = f"Failed to remove {name} from the PATH" ret["result"] = False else: - ret["comment"] = "Removed {} from the PATH".format(name) + ret["comment"] = f"Removed {name} from the PATH" ret["changes"]["removed"] = name return ret @@ -143,13 +143,11 @@ def exists(name, index=None): if index is None: # We're not enforcing the index, and the directory is in the PATH. # There's nothing to do here. - comments.append("{} already exists in the PATH.".format(name)) + comments.append(f"{name} already exists in the PATH.") return _format_comments(ret, comments) else: if index == old_index: - comments.append( - "{} already exists in the PATH at index {}.".format(name, index) - ) + comments.append(f"{name} already exists in the PATH at index {index}.") return _format_comments(ret, comments) else: if __opts__["test"]: @@ -168,7 +166,7 @@ def exists(name, index=None): ret["result"] = None comments.append( "{} would be added to the PATH{}.".format( - name, " at index {}".format(index) if index is not None else "" + name, f" at index {index}" if index is not None else "" ) ) ret["changes"] = _changes(old_index, index) @@ -177,7 +175,7 @@ def exists(name, index=None): try: ret["result"] = __salt__["win_path.add"](name, index=index, rehash=False) except Exception as exc: # pylint: disable=broad-except - comments.append("Encountered error: {}.".format(exc)) + comments.append(f"Encountered error: {exc}.") ret["result"] = False if ret["result"]: @@ -203,7 +201,7 @@ def exists(name, index=None): "{} {} to the PATH{}.".format( "Added" if ret["result"] else "Failed to add", name, - " at index {}".format(index) if index is not None else "", + f" at index {index}" if index is not None else "", ) ) diff --git a/salt/states/win_pki.py b/salt/states/win_pki.py index 168939374e1..0e0724209f1 100644 --- a/salt/states/win_pki.py +++ b/salt/states/win_pki.py @@ -6,7 +6,6 @@ Microsoft certificate management via the Pki PowerShell module. .. versionadded:: 2016.11.0 """ - _DEFAULT_CONTEXT = "LocalMachine" _DEFAULT_FORMAT = "cer" _DEFAULT_STORE = "My" @@ -65,7 +64,7 @@ def import_cert( """ ret = {"name": name, "changes": dict(), "comment": "", "result": None} - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" cached_source_path = __salt__["cp.cache_file"](name, saltenv) current_certs = __salt__["win_pki.get_certs"](context=context, store=store) @@ -104,10 +103,10 @@ def import_cert( cert_props["thumbprint"], store_path ) else: - ret[ - "comment" - ] = "Certificate '{}' unable to be imported into store: {}".format( - cert_props["thumbprint"], store_path + ret["comment"] = ( + "Certificate '{}' unable to be imported into store: {}".format( + cert_props["thumbprint"], store_path + ) ) return ret @@ -140,7 +139,7 @@ def remove_cert(name, thumbprint, context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE """ ret = {"name": name, "changes": dict(), "comment": "", "result": None} - store_path = r"Cert:\{}\{}".format(context, store) + store_path = rf"Cert:\{context}\{store}" current_certs = __salt__["win_pki.get_certs"](context=context, store=store) if thumbprint not in current_certs: @@ -163,9 +162,9 @@ def remove_cert(name, thumbprint, context=_DEFAULT_CONTEXT, store=_DEFAULT_STORE thumbprint, store_path ) else: - ret[ - "comment" - ] = "Certificate '{}' unable to be removed from store: {}".format( - thumbprint, store_path + ret["comment"] = ( + "Certificate '{}' unable to be removed from store: {}".format( + thumbprint, store_path + ) ) return ret diff --git a/salt/states/win_powercfg.py b/salt/states/win_powercfg.py index b7f4e82a139..46aba50985f 100644 --- a/salt/states/win_powercfg.py +++ b/salt/states/win_powercfg.py @@ -14,7 +14,6 @@ powercfg. - power: dc """ - import logging import salt.utils.data @@ -89,7 +88,7 @@ def set_timeout(name, value, power="ac", scheme=None): name = name.lower() if name not in ["monitor", "disk", "standby", "hibernate"]: ret["result"] = False - ret["comment"] = '"{}" is not a valid setting'.format(name) + ret["comment"] = f'"{name}" is not a valid setting' log.debug(ret["comment"]) return ret @@ -97,12 +96,12 @@ def set_timeout(name, value, power="ac", scheme=None): power = power.lower() if power not in ["ac", "dc"]: ret["result"] = False - ret["comment"] = '"{}" is not a power type'.format(power) + ret["comment"] = f'"{power}" is not a power type' log.debug(ret["comment"]) return ret # Get current settings - old = __salt__["powercfg.get_{}_timeout".format(name)](scheme=scheme) + old = __salt__[f"powercfg.get_{name}_timeout"](scheme=scheme) # Check current settings if old[power] == value: @@ -121,12 +120,10 @@ def set_timeout(name, value, power="ac", scheme=None): return ret # Set the timeout value - __salt__["powercfg.set_{}_timeout".format(name)]( - timeout=value, power=power, scheme=scheme - ) + __salt__[f"powercfg.set_{name}_timeout"](timeout=value, power=power, scheme=scheme) # Get the setting after the change - new = __salt__["powercfg.get_{}_timeout".format(name)](scheme=scheme) + new = __salt__[f"powercfg.get_{name}_timeout"](scheme=scheme) changes = salt.utils.data.compare_dicts(old, new) diff --git a/salt/states/win_shortcut.py b/salt/states/win_shortcut.py index 8443a187a3c..a1fa46a2f9e 100644 --- a/salt/states/win_shortcut.py +++ b/salt/states/win_shortcut.py @@ -6,6 +6,7 @@ shortcuts. .. versionadded:: 3005 """ + import salt.utils.data import salt.utils.path import salt.utils.platform @@ -187,10 +188,10 @@ def present( if __opts__["test"]: if changes: - ret["comment"] = "Shortcut will be modified: {}".format(name) + ret["comment"] = f"Shortcut will be modified: {name}" ret["changes"] = changes else: - ret["comment"] = "Shortcut will be created: {}".format(name) + ret["comment"] = f"Shortcut will be created: {name}" ret["result"] = None return ret @@ -212,7 +213,7 @@ def present( user=user, ) except CommandExecutionError as exc: - ret["comment"] = ["Failed to create the shortcut: {}".format(name)] + ret["comment"] = [f"Failed to create the shortcut: {name}"] ret["comment"].append(exc.message) ret["result"] = False return ret @@ -220,7 +221,7 @@ def present( try: new = __salt__["shortcut.get"](name) except CommandExecutionError as exc: - ret["comment"] = ["Failed to create the shortcut: {}".format(name)] + ret["comment"] = [f"Failed to create the shortcut: {name}"] ret["comment"].append(exc.message) ret["result"] = False return ret @@ -233,9 +234,9 @@ def present( return ret if changes: - ret["comment"] = "Shortcut modified: {}".format(name) + ret["comment"] = f"Shortcut modified: {name}" ret["changes"] = changes else: - ret["comment"] = "Shortcut created: {}".format(name) + ret["comment"] = f"Shortcut created: {name}" return ret diff --git a/salt/states/win_smtp_server.py b/salt/states/win_smtp_server.py index e3eadc82745..91df2a6586a 100644 --- a/salt/states/win_smtp_server.py +++ b/salt/states/win_smtp_server.py @@ -3,7 +3,6 @@ Module for managing IIS SMTP server configuration on Windows servers. """ - import salt.utils.args _DEFAULT_SERVER = "SmtpSvc/1" @@ -39,7 +38,7 @@ def _normalize_server_settings(**settings): if isinstance(settings[setting], dict): value_from_key = next(iter(settings[setting].keys())) - ret[setting] = "{{{0}}}".format(value_from_key) + ret[setting] = f"{{{value_from_key}}}" else: ret[setting] = settings[setting] return ret @@ -144,17 +143,17 @@ def active_log_format(name, log_format, server=_DEFAULT_SERVER): current_log_format = __salt__["win_smtp_server.get_log_format"](server) if log_format == current_log_format: - ret[ - "comment" - ] = "LogPluginClsid already contains the id of the provided log format." + ret["comment"] = ( + "LogPluginClsid already contains the id of the provided log format." + ) ret["result"] = True elif __opts__["test"]: ret["comment"] = "LogPluginClsid will be changed." ret["changes"] = {"old": current_log_format, "new": log_format} else: - ret[ - "comment" - ] = "Set LogPluginClsid to contain the id of the provided log format." + ret["comment"] = ( + "Set LogPluginClsid to contain the id of the provided log format." + ) ret["changes"] = {"old": current_log_format, "new": log_format} ret["result"] = __salt__["win_smtp_server.set_log_format"](log_format, server) return ret diff --git a/salt/states/win_snmp.py b/salt/states/win_snmp.py index 0b5dfac12d8..9d70ebc1b8e 100644 --- a/salt/states/win_snmp.py +++ b/salt/states/win_snmp.py @@ -104,13 +104,13 @@ def auth_traps_enabled(name, status=True): current_status = __salt__["win_snmp.get_auth_traps_enabled"]() if status == current_status: - ret["comment"] = "{} already contains the provided value.".format(vname) + ret["comment"] = f"{vname} already contains the provided value." ret["result"] = True elif __opts__["test"]: - ret["comment"] = "{} will be changed.".format(vname) + ret["comment"] = f"{vname} will be changed." ret["changes"] = {"old": current_status, "new": status} else: - ret["comment"] = "Set {} to contain the provided value.".format(vname) + ret["comment"] = f"Set {vname} to contain the provided value." ret["changes"] = {"old": current_status, "new": status} ret["result"] = __salt__["win_snmp.set_auth_traps_enabled"](status=status) diff --git a/salt/states/win_system.py b/salt/states/win_system.py index 34f47f15e0d..0aa5438b0ec 100644 --- a/salt/states/win_system.py +++ b/salt/states/win_system.py @@ -52,7 +52,7 @@ def computer_desc(name): "name": name, "changes": {}, "result": True, - "comment": "Computer description already set to '{}'".format(name), + "comment": f"Computer description already set to '{name}'", } before_desc = __salt__["system.get_computer_desc"]() @@ -62,7 +62,7 @@ def computer_desc(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Computer description will be changed to '{}'".format(name) + ret["comment"] = f"Computer description will be changed to '{name}'" return ret result = __salt__["system.set_computer_desc"](name) @@ -73,7 +73,7 @@ def computer_desc(name): ret["changes"] = {"old": before_desc, "new": name} else: ret["result"] = False - ret["comment"] = "Unable to set computer description to '{}'".format(name) + ret["comment"] = f"Unable to set computer description to '{name}'" return ret @@ -96,7 +96,7 @@ def computer_name(name): "name": name, "changes": {}, "result": True, - "comment": "Computer name already set to '{}'".format(name), + "comment": f"Computer name already set to '{name}'", } before_name = __salt__["system.get_computer_name"]() @@ -113,7 +113,7 @@ def computer_name(name): if __opts__["test"]: ret["result"] = None - ret["comment"] = "Computer name will be changed to '{}'".format(name) + ret["comment"] = f"Computer name will be changed to '{name}'" return ret result = __salt__["system.set_computer_name"](name) @@ -123,13 +123,13 @@ def computer_name(name): if (after_pending is not None and after_pending == name) or ( after_pending is None and after_name == name ): - ret["comment"] = "Computer name successfully set to '{}'".format(name) + ret["comment"] = f"Computer name successfully set to '{name}'" if after_pending is not None: ret["comment"] += " (reboot required for change to take effect)" ret["changes"] = {"old": before_name, "new": name} else: ret["result"] = False - ret["comment"] = "Unable to set computer name to '{}'".format(name) + ret["comment"] = f"Unable to set computer name to '{name}'" return ret @@ -147,7 +147,7 @@ def hostname(name): current_hostname = __salt__["system.get_hostname"]() if current_hostname.upper() == name.upper(): - ret["comment"] = "Hostname is already set to '{}'".format(name) + ret["comment"] = f"Hostname is already set to '{name}'" return ret out = __salt__["system.set_hostname"](name) @@ -191,22 +191,20 @@ def workgroup(name): current_workgroup = ( out["Domain"] if "Domain" in out - else out["Workgroup"] - if "Workgroup" in out - else "" + else out["Workgroup"] if "Workgroup" in out else "" ) # Notify the user if the requested workgroup is the same if current_workgroup.upper() == name.upper(): ret["result"] = True - ret["comment"] = "Workgroup is already set to '{}'".format(name.upper()) + ret["comment"] = f"Workgroup is already set to '{name.upper()}'" return ret # If being run in test-mode, inform the user what is supposed to happen if __opts__["test"]: ret["result"] = None ret["changes"] = {} - ret["comment"] = "Computer will be joined to workgroup '{}'".format(name) + ret["comment"] = f"Computer will be joined to workgroup '{name}'" return ret # Set our new workgroup, and then immediately ask the machine what it @@ -216,9 +214,7 @@ def workgroup(name): new_workgroup = ( out["Domain"] if "Domain" in out - else out["Workgroup"] - if "Workgroup" in out - else "" + else out["Workgroup"] if "Workgroup" in out else "" ) # Return our results based on the changes @@ -299,7 +295,7 @@ def join_domain( "name": name, "changes": {}, "result": True, - "comment": "Computer already added to '{}'".format(name), + "comment": f"Computer already added to '{name}'", } current_domain_dic = __salt__["system.get_domain_workgroup"]() @@ -311,12 +307,12 @@ def join_domain( current_domain = None if name.lower() == current_domain.lower(): - ret["comment"] = "Computer already added to '{}'".format(name) + ret["comment"] = f"Computer already added to '{name}'" return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Computer will be added to '{}'".format(name) + ret["comment"] = f"Computer will be added to '{name}'" return ret result = __salt__["system.join_domain"]( @@ -328,14 +324,14 @@ def join_domain( restart=restart, ) if result is not False: - ret["comment"] = "Computer added to '{}'".format(name) + ret["comment"] = f"Computer added to '{name}'" if restart: ret["comment"] += "\nSystem will restart" else: ret["comment"] += "\nSystem needs to be restarted" ret["changes"] = {"old": current_domain, "new": name} else: - ret["comment"] = "Computer failed to join '{}'".format(name) + ret["comment"] = f"Computer failed to join '{name}'" ret["result"] = False return ret @@ -461,20 +457,20 @@ def shutdown( if only_on_pending_reboot and not __salt__["system.get_pending_reboot"](): if __opts__["test"]: - ret[ - "comment" - ] = "System {} will be skipped because no reboot is pending".format(action) + ret["comment"] = ( + f"System {action} will be skipped because no reboot is pending" + ) else: - ret[ - "comment" - ] = "System {} has been skipped because no reboot was pending".format( - action + ret["comment"] = ( + "System {} has been skipped because no reboot was pending".format( + action + ) ) return ret if __opts__["test"]: ret["result"] = None - ret["comment"] = "Will attempt to schedule a {}".format(action) + ret["comment"] = f"Will attempt to schedule a {action}" return ret ret["result"] = __salt__["system.shutdown"]( @@ -489,9 +485,9 @@ def shutdown( if ret["result"]: ret["changes"] = { "old": "No reboot or shutdown was scheduled", - "new": "A {} has been scheduled".format(action), + "new": f"A {action} has been scheduled", } - ret["comment"] = "Request to {} was successful".format(action) + ret["comment"] = f"Request to {action} was successful" else: - ret["comment"] = "Request to {} failed".format(action) + ret["comment"] = f"Request to {action} failed" return ret diff --git a/salt/states/win_task.py b/salt/states/win_task.py index 6a83392ebee..990724c5da6 100644 --- a/salt/states/win_task.py +++ b/salt/states/win_task.py @@ -406,9 +406,9 @@ def present( if __opts__["test"]: # if force is False and task is found then no changes will take place if not force and before["task_found"]: - ret[ - "comment" - ] = '"force=True" will allow the new task to replace the old one' + ret["comment"] = ( + '"force=True" will allow the new task to replace the old one' + ) ret["result"] = None log.warning("force=False") return ret diff --git a/salt/states/win_wusa.py b/salt/states/win_wusa.py index 4371bfc1341..70cf1f00436 100644 --- a/salt/states/win_wusa.py +++ b/salt/states/win_wusa.py @@ -7,7 +7,6 @@ without WSUS or Windows Update .. versionadded:: 2018.3.4 """ - import logging import salt.utils.platform @@ -62,13 +61,13 @@ def installed(name, source): # Is the KB already installed if __salt__["wusa.is_installed"](name): ret["result"] = True - ret["comment"] = "{} already installed".format(name) + ret["comment"] = f"{name} already installed" return ret # Check for test=True if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "{} would be installed".format(name) + ret["comment"] = f"{name} would be installed" ret["result"] = None return ret @@ -92,11 +91,11 @@ def installed(name, source): # Verify successful install if __salt__["wusa.is_installed"](name): - ret["comment"] = "{} was installed. {}".format(name, additional_comment) + ret["comment"] = f"{name} was installed. {additional_comment}" ret["changes"] = {"old": False, "new": True} ret["result"] = True else: - ret["comment"] = "{} failed to install. {}".format(name, additional_comment) + ret["comment"] = f"{name} failed to install. {additional_comment}" return ret @@ -122,13 +121,13 @@ def uninstalled(name): # Is the KB already uninstalled if not __salt__["wusa.is_installed"](name): ret["result"] = True - ret["comment"] = "{} already uninstalled".format(name) + ret["comment"] = f"{name} already uninstalled" return ret # Check for test=True if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "{} would be uninstalled".format(name) + ret["comment"] = f"{name} would be uninstalled" ret["result"] = None return ret @@ -137,10 +136,10 @@ def uninstalled(name): # Verify successful uninstall if not __salt__["wusa.is_installed"](name): - ret["comment"] = "{} was uninstalled".format(name) + ret["comment"] = f"{name} was uninstalled" ret["changes"] = {"old": True, "new": False} ret["result"] = True else: - ret["comment"] = "{} failed to uninstall".format(name) + ret["comment"] = f"{name} failed to uninstall" return ret diff --git a/salt/states/winrepo.py b/salt/states/winrepo.py index 23858551592..241c66c1ca6 100644 --- a/salt/states/winrepo.py +++ b/salt/states/winrepo.py @@ -60,11 +60,11 @@ def genrepo(name, force=False, allow_empty=False): if not force: if not os.path.exists(winrepo_dir): ret["result"] = False - ret["comment"] = "{} is missing".format(winrepo_dir) + ret["comment"] = f"{winrepo_dir} is missing" return ret elif not os.path.exists(winrepo_cachefile): execute = True - ret["comment"] = "{} is missing".format(winrepo_cachefile) + ret["comment"] = f"{winrepo_cachefile} is missing" else: winrepo_cachefile_mtime = os.stat(winrepo_cachefile)[stat.ST_MTIME] for root, dirs, files in salt.utils.path.os_walk(winrepo_dir): diff --git a/salt/states/wordpress.py b/salt/states/wordpress.py index e672e30be4a..5e208458ef7 100644 --- a/salt/states/wordpress.py +++ b/salt/states/wordpress.py @@ -53,11 +53,11 @@ def installed(name, user, admin_user, admin_password, admin_email, title, url): if check: ret["result"] = True - ret["comment"] = "Wordpress is already installed: {}".format(name) + ret["comment"] = f"Wordpress is already installed: {name}" return ret elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Wordpress will be installed: {}".format(name) + ret["comment"] = f"Wordpress will be installed: {name}" return ret resp = __salt__["wordpress.install"]( @@ -65,10 +65,10 @@ def installed(name, user, admin_user, admin_password, admin_email, title, url): ) if resp: ret["result"] = True - ret["comment"] = "Wordpress Installed: {}".format(name) + ret["comment"] = f"Wordpress Installed: {name}" ret["changes"] = {"new": resp} else: - ret["comment"] = "Failed to install wordpress: {}".format(name) + ret["comment"] = f"Failed to install wordpress: {name}" return ret @@ -99,30 +99,30 @@ def activated(name, path, user): if check["status"] == "active": ret["result"] = True - ret["comment"] = "Plugin already activated: {}".format(name) + ret["comment"] = f"Plugin already activated: {name}" return ret elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Plugin will be activated: {}".format(name) + ret["comment"] = f"Plugin will be activated: {name}" return ret resp = __salt__["wordpress.activate"](name, path, user) if resp is True: ret["result"] = True - ret["comment"] = "Plugin activated: {}".format(name) + ret["comment"] = f"Plugin activated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } elif resp is None: ret["result"] = True - ret["comment"] = "Plugin already activated: {}".format(name) + ret["comment"] = f"Plugin already activated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } else: - ret["comment"] = "Plugin failed to activate: {}".format(name) + ret["comment"] = f"Plugin failed to activate: {name}" return ret @@ -153,29 +153,29 @@ def deactivated(name, path, user): if check["status"] == "inactive": ret["result"] = True - ret["comment"] = "Plugin already deactivated: {}".format(name) + ret["comment"] = f"Plugin already deactivated: {name}" return ret elif __opts__["test"]: ret["result"] = None - ret["comment"] = "Plugin will be deactivated: {}".format(name) + ret["comment"] = f"Plugin will be deactivated: {name}" return ret resp = __salt__["wordpress.deactivate"](name, path, user) if resp is True: ret["result"] = True - ret["comment"] = "Plugin deactivated: {}".format(name) + ret["comment"] = f"Plugin deactivated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } elif resp is None: ret["result"] = True - ret["comment"] = "Plugin already deactivated: {}".format(name) + ret["comment"] = f"Plugin already deactivated: {name}" ret["changes"] = { "old": check, "new": __salt__["wordpress.show_plugin"](name, path, user), } else: - ret["comment"] = "Plugin failed to deactivate: {}".format(name) + ret["comment"] = f"Plugin failed to deactivate: {name}" return ret diff --git a/salt/states/x509_v2.py b/salt/states/x509_v2.py index 4987d272922..773006b6694 100644 --- a/salt/states/x509_v2.py +++ b/salt/states/x509_v2.py @@ -180,6 +180,7 @@ according to the www policy. - require: - x509: /etc/pki/www.key """ + import base64 import copy import datetime @@ -433,9 +434,9 @@ def certificate_managed( file_managed_test = _file_managed(name, test=True, replace=False, **file_args) if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -839,9 +840,9 @@ def crl_managed( if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -1078,9 +1079,9 @@ def csr_managed( if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -1362,9 +1363,9 @@ def private_key_managed( if file_managed_test["result"] is False: ret["result"] = False - ret[ - "comment" - ] = "Problem while testing file.managed changes, see its output" + ret["comment"] = ( + "Problem while testing file.managed changes, see its output" + ) _add_sub_state_run(ret, file_managed_test) return ret @@ -1584,9 +1585,9 @@ def _file_managed(name, test=None, **kwargs): def _check_file_ret(fret, ret, current): if fret["result"] is False: ret["result"] = False - ret[ - "comment" - ] = f"Could not {'create' if not current else 'update'} file, see file.managed output" + ret["comment"] = ( + f"Could not {'create' if not current else 'update'} file, see file.managed output" + ) ret["changes"] = {} return False return True diff --git a/salt/states/xml.py b/salt/states/xml.py index 67cf30a825b..48bcb4eb5db 100644 --- a/salt/states/xml.py +++ b/salt/states/xml.py @@ -51,20 +51,20 @@ def value_present(name, xpath, value, **kwargs): current_value = __salt__["xml.get_value"](name, xpath) if not current_value: ret["result"] = False - ret["comment"] = "xpath query {} not found in {}".format(xpath, name) + ret["comment"] = f"xpath query {xpath} not found in {name}" return ret if current_value != value: if kwargs["test"]: ret["result"] = None - ret["comment"] = "{} will be updated".format(name) + ret["comment"] = f"{name} will be updated" ret["changes"] = {name: {"old": current_value, "new": value}} else: results = __salt__["xml.set_value"](name, xpath, value) ret["result"] = results - ret["comment"] = "{} updated".format(name) + ret["comment"] = f"{name} updated" ret["changes"] = {name: {"old": current_value, "new": value}} else: - ret["comment"] = "{} is already present".format(value) + ret["comment"] = f"{value} is already present" return ret diff --git a/salt/states/xmpp.py b/salt/states/xmpp.py index 2186c37bbca..84b4a6a3017 100644 --- a/salt/states/xmpp.py +++ b/salt/states/xmpp.py @@ -54,7 +54,7 @@ def send_msg(name, recipient, profile): profile=profile, ) ret["result"] = True - ret["comment"] = "Sent message to {}: {}".format(recipient, name) + ret["comment"] = f"Sent message to {recipient}: {name}" return ret @@ -84,10 +84,10 @@ def send_msg_multi(name, profile, recipients=None, rooms=None): comment = "" if recipients: - comment += " users {}".format(recipients) + comment += f" users {recipients}" if rooms: - comment += " rooms {}".format(rooms) - comment += ", message: {}".format(name) + comment += f" rooms {rooms}" + comment += f", message: {name}" if __opts__["test"]: ret["comment"] = "Need to send" + comment diff --git a/salt/states/zabbix_action.py b/salt/states/zabbix_action.py index 9b92aa528e0..33215891904 100644 --- a/salt/states/zabbix_action.py +++ b/salt/states/zabbix_action.py @@ -170,10 +170,10 @@ def present(name, params, **kwargs): else: ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( + name + ) ) else: diff --git a/salt/states/zabbix_hostgroup.py b/salt/states/zabbix_hostgroup.py index 772a32e9528..3b573abac55 100644 --- a/salt/states/zabbix_hostgroup.py +++ b/salt/states/zabbix_hostgroup.py @@ -5,6 +5,7 @@ Management of Zabbix host groups. """ + __deprecated__ = ( 3009, "zabbix", diff --git a/salt/states/zabbix_template.py b/salt/states/zabbix_template.py index e489c185301..cefd692fa77 100644 --- a/salt/states/zabbix_template.py +++ b/salt/states/zabbix_template.py @@ -873,10 +873,10 @@ def present(name, params, static_host_list=True, **kwargs): if not CHANGE_STACK: ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Template "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Template "{}" already exists and corresponds to a definition.'.format( + name + ) ) else: tmpl_action = next( diff --git a/salt/states/zabbix_user.py b/salt/states/zabbix_user.py index 1c43e0f8f06..fa8ba6c4b3f 100644 --- a/salt/states/zabbix_user.py +++ b/salt/states/zabbix_user.py @@ -90,9 +90,9 @@ def admin_password_present(name, password=None, **kwargs): unique_passwords.reverse() if not unique_passwords: - ret[ - "comment" - ] = "Could not find any Zabbix Admin password setting! See documentation." + ret["comment"] = ( + "Could not find any Zabbix Admin password setting! See documentation." + ) return ret else: desired_password = unique_passwords[0] diff --git a/salt/states/zabbix_valuemap.py b/salt/states/zabbix_valuemap.py index 7bf57263c14..641f929fa17 100644 --- a/salt/states/zabbix_valuemap.py +++ b/salt/states/zabbix_valuemap.py @@ -138,10 +138,10 @@ def present(name, params, **kwargs): else: ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( + name + ) ) else: diff --git a/salt/states/zenoss.py b/salt/states/zenoss.py index 0a05c67af23..ed06e9a249d 100644 --- a/salt/states/zenoss.py +++ b/salt/states/zenoss.py @@ -17,7 +17,6 @@ Allows for setting a state of minions in Zenoss using the Zenoss API. Currently - prod_state: 1000 """ - import logging log = logging.getLogger(__name__) @@ -55,30 +54,30 @@ def monitored(name, device_class=None, collector="localhost", prod_state=None): if device: ret["result"] = True ret["changes"] = None - ret["comment"] = "{} is already monitored".format(name) + ret["comment"] = f"{name} is already monitored" # if prod_state is set, ensure it matches with the current state if prod_state is not None and device["productionState"] != prod_state: if __opts__["test"]: - ret[ - "comment" - ] = "{} is already monitored but prodState will be updated".format(name) + ret["comment"] = ( + f"{name} is already monitored but prodState will be updated" + ) ret["result"] = None else: __salt__["zenoss.set_prod_state"](prod_state, name) - ret[ - "comment" - ] = "{} is already monitored but prodState was updated".format(name) + ret["comment"] = ( + f"{name} is already monitored but prodState was updated" + ) ret["changes"] = { "old": "prodState == {}".format(device["productionState"]), - "new": "prodState == {}".format(prod_state), + "new": f"prodState == {prod_state}", } return ret # Device not yet in Zenoss if __opts__["test"]: - ret["comment"] = 'The state of "{}" will be changed.'.format(name) + ret["comment"] = f'The state of "{name}" will be changed.' ret["changes"] = {"old": "monitored == False", "new": "monitored == True"} ret["result"] = None return ret @@ -87,9 +86,9 @@ def monitored(name, device_class=None, collector="localhost", prod_state=None): if __salt__["zenoss.add_device"](name, device_class, collector, prod_state): ret["result"] = True ret["changes"] = {"old": "monitored == False", "new": "monitored == True"} - ret["comment"] = "{} has been added to Zenoss".format(name) + ret["comment"] = f"{name} has been added to Zenoss" else: ret["result"] = False ret["changes"] = None - ret["comment"] = "Unable to add {} to Zenoss".format(name) + ret["comment"] = f"Unable to add {name} to Zenoss" return ret diff --git a/salt/states/zk_concurrency.py b/salt/states/zk_concurrency.py index f76ffdd64d4..d376e51c955 100644 --- a/salt/states/zk_concurrency.py +++ b/salt/states/zk_concurrency.py @@ -45,7 +45,6 @@ This example would allow the file state to change, but would limit the concurrency of the trafficserver service restart to 4. """ - # TODO: use depends decorator to make these per function deps, instead of all or nothing REQUIRED_FUNCS = ( "zk_concurrency.lock", @@ -103,7 +102,7 @@ def lock( max_concurrency=max_concurrency, timeout=timeout, ephemeral_lease=ephemeral_lease, - **conn_kwargs + **conn_kwargs, ) if locked: ret["result"] = True @@ -152,13 +151,13 @@ def unlock( identifier=identifier, max_concurrency=max_concurrency, ephemeral_lease=ephemeral_lease, - **conn_kwargs + **conn_kwargs, ) if unlocked: ret["result"] = True else: - ret["comment"] = "Unable to find lease for path {}".format(name) + ret["comment"] = f"Unable to find lease for path {name}" return ret diff --git a/salt/states/zone.py b/salt/states/zone.py index bb6de7dfc13..0c908ed34c4 100644 --- a/salt/states/zone.py +++ b/salt/states/zone.py @@ -193,10 +193,10 @@ def property_present(name, property, value): else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -250,10 +250,10 @@ def property_absent(name, property): else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -373,31 +373,31 @@ def resource_present( ) if ret["comment"] == "": if resource_selector_property: - ret[ - "comment" - ] = "The {} resource {} was updated.".format( - resource_type, - resource_selector_value, + ret["comment"] = ( + "The {} resource {} was updated.".format( + resource_type, + resource_selector_value, + ) ) else: - ret[ - "comment" - ] = "The {} resource was updated.".format( - resource_type, + ret["comment"] = ( + "The {} resource was updated.".format( + resource_type, + ) ) elif ret["comment"] == "": if resource_selector_property: - ret[ - "comment" - ] = "The {} resource {} was not updated.".format( - resource_type, - resource_selector_value, + ret["comment"] = ( + "The {} resource {} was not updated.".format( + resource_type, + resource_selector_value, + ) ) else: - ret[ - "comment" - ] = "The {} resource was not updated.".format( - resource_type, + ret["comment"] = ( + "The {} resource was not updated.".format( + resource_type, + ) ) if ret["result"] is None: ## add @@ -418,9 +418,9 @@ def resource_present( ret["changes"][resource_type][resource_selector_value] = {} for key in kwargs if ret["result"] else []: if resource_selector_property: - ret["changes"][resource_type][resource_selector_value][ - key - ] = _parse_value(kwargs[key]) + ret["changes"][resource_type][resource_selector_value][key] = ( + _parse_value(kwargs[key]) + ) else: ret["changes"][resource_type][key] = _parse_value(kwargs[key]) if ret["comment"] == "": @@ -436,10 +436,10 @@ def resource_present( else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -541,10 +541,10 @@ def resource_absent( else: ## zone does not exist ret["result"] = False - ret[ - "comment" - ] = "The zone {} is not in the configured, installed, or booted state.".format( - name + ret["comment"] = ( + "The zone {} is not in the configured, installed, or booted state.".format( + name + ) ) return ret @@ -682,11 +682,11 @@ def export(name, path, replace=False): if __salt__["file.file_exists"](path) and not replace: ret["result"] = False ret["changes"] = {} - ret[ - "comment" - ] = "File {} exists, zone configuration for {} not exported.".format( - path, - name, + ret["comment"] = ( + "File {} exists, zone configuration for {} not exported.".format( + path, + name, + ) ) else: ## export and update file @@ -700,29 +700,29 @@ def export(name, path, replace=False): if __salt__["file.file_exists"](cfg_tmp): __salt__["file.remove"](cfg_tmp) ret["result"] = False - ret[ - "comment" - ] = "Unable to export zone configuration for {} to {}!".format( - name, - path, + ret["comment"] = ( + "Unable to export zone configuration for {} to {}!".format( + name, + path, + ) ) else: ret["result"] = True - ret[ - "comment" - ] = "Zone configuration for {} was exported to {}.".format( - name, - path, + ret["comment"] = ( + "Zone configuration for {} was exported to {}.".format( + name, + path, + ) ) ret["changes"][name] = "exported" else: cfg_diff = __salt__["file.get_diff"](path, cfg_tmp) if not cfg_diff: ret["result"] = True - ret[ - "comment" - ] = "Zone configuration for {} was already exported to {}.".format( - name, path + ret["comment"] = ( + "Zone configuration for {} was already exported to {}.".format( + name, path + ) ) if __salt__["file.file_exists"](cfg_tmp): __salt__["file.remove"](cfg_tmp) @@ -743,11 +743,11 @@ def export(name, path, replace=False): ) else: ret["result"] = True - ret[ - "comment" - ] = "Zone configuration for {} was re-exported to {}.".format( - name, - path, + ret["comment"] = ( + "Zone configuration for {} was re-exported to {}.".format( + name, + path, + ) ) ret["changes"][name] = "exported" else: @@ -1016,25 +1016,25 @@ def present(name, brand, zonepath, properties=None, resources=None): name, resource_cfg["resource_type"], resource_selector_property=resource_selector_property, - resource_selector_value=resource_cfg[ - resource_selector_property - ] - if resource_selector_property - else None, + resource_selector_value=( + resource_cfg[resource_selector_property] + if resource_selector_property + else None + ), ) else: - resource_cfg[ - "resource_selector_property" - ] = resource_selector_property + resource_cfg["resource_selector_property"] = ( + resource_selector_property + ) if resource_selector_property in resource_cfg: resource_cfg["resource_selector_value"] = resource_cfg[ resource_selector_property ] else: resource_cfg["resource_selector_value"] = None - resource_cfg[ - "name" - ] = name # we do this last because name can also be a attrib value + resource_cfg["name"] = ( + name # we do this last because name can also be a attrib value + ) res = resource_present(**resource_cfg) if res: ret["result"] = ret["result"] if res["result"] else False diff --git a/salt/states/zookeeper.py b/salt/states/zookeeper.py index 5fb20f1d813..e6674e9911b 100644 --- a/salt/states/zookeeper.py +++ b/salt/states/zookeeper.py @@ -27,7 +27,6 @@ The following options can be included in the acl dictionary: :type all: bool """ - __virtualname__ = "zookeeper" @@ -134,7 +133,7 @@ def present( ret = { "name": name, "result": False, - "comment": "Failed to setup znode {}".format(name), + "comment": f"Failed to setup znode {name}", "changes": {}, } connkwargs = { @@ -154,15 +153,15 @@ def present( cur_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) if cur_value == value and _check_acls(cur_acls, chk_acls): ret["result"] = True - ret[ - "comment" - ] = "Znode {} is already set to the correct value with the correct acls".format( - name + ret["comment"] = ( + "Znode {} is already set to the correct value with the correct acls".format( + name + ) ) return ret elif __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Znode {} is will be updated".format(name) + ret["comment"] = f"Znode {name} is will be updated" ret["changes"]["old"] = {} ret["changes"]["new"] = {} if value != cur_value: @@ -190,12 +189,12 @@ def present( ret["changes"] = changes if value_result and acl_result: ret["result"] = True - ret["comment"] = "Znode {} successfully updated".format(name) + ret["comment"] = f"Znode {name} successfully updated" return ret if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "{} is will be created".format(name) + ret["comment"] = f"{name} is will be created" ret["changes"]["old"] = {} ret["changes"]["new"] = {} ret["changes"]["new"]["acls"] = chk_acls @@ -220,7 +219,7 @@ def present( ret["changes"] = changes if value_result and acl_result: ret["result"] = True - ret["comment"] = "Znode {} successfully created".format(name) + ret["comment"] = f"Znode {name} successfully created" return ret @@ -278,7 +277,7 @@ def absent( ret = { "name": name, "result": False, - "comment": "Failed to delete znode {}".format(name), + "comment": f"Failed to delete znode {name}", "changes": {}, } connkwargs = { @@ -292,7 +291,7 @@ def absent( if __salt__["zookeeper.exists"](name, **connkwargs) is False: ret["result"] = True - ret["comment"] = "Znode {} does not exist".format(name) + ret["comment"] = f"Znode {name} does not exist" return ret changes = {} @@ -303,7 +302,7 @@ def absent( if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Znode {} will be removed".format(name) + ret["comment"] = f"Znode {name} will be removed" ret["changes"]["old"] = changes return ret @@ -311,7 +310,7 @@ def absent( if __salt__["zookeeper.exists"](name, **connkwargs) is False: ret["result"] = True - ret["comment"] = "Znode {} has been removed".format(name) + ret["comment"] = f"Znode {name} has been removed" ret["changes"]["old"] = changes return ret @@ -375,7 +374,7 @@ def acls( ret = { "name": name, "result": False, - "comment": "Failed to set acls on znode {}".format(name), + "comment": f"Failed to set acls on znode {name}", "changes": {}, } connkwargs = { @@ -397,12 +396,12 @@ def acls( cur_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) if _check_acls(cur_acls, chk_acls): ret["result"] = True - ret["comment"] = "Znode {} acls already set".format(name) + ret["comment"] = f"Znode {name} acls already set" return ret if __opts__["test"] is True: ret["result"] = None - ret["comment"] = "Znode {} acls will be updated".format(name) + ret["comment"] = f"Znode {name} acls will be updated" ret["changes"]["old"] = cur_acls ret["changes"]["new"] = chk_acls return ret @@ -413,7 +412,7 @@ def acls( ret["changes"] = {"old": cur_acls, "new": new_acls} if _check_acls(new_acls, chk_acls): ret["result"] = True - ret["comment"] = "Znode {} acls updated".format(name) + ret["comment"] = f"Znode {name} acls updated" return ret - ret["comment"] = "Znode {} acls failed to update".format(name) + ret["comment"] = f"Znode {name} acls failed to update" return ret diff --git a/salt/syspaths.py b/salt/syspaths.py index ce9bbc44ef6..23445622614 100644 --- a/salt/syspaths.py +++ b/salt/syspaths.py @@ -13,7 +13,6 @@ paths that are set in the master/minion config files. """ - import logging import os import os.path diff --git a/salt/template.py b/salt/template.py index 7de759dc4fb..7cdd8ed2055 100644 --- a/salt/template.py +++ b/salt/template.py @@ -1,6 +1,7 @@ """ Manage basic template commands """ + import codecs import io import logging @@ -33,7 +34,7 @@ def compile_template( sls="", input_data="", context=None, - **kwargs + **kwargs, ): """ Take the path to a template and return the high data structure @@ -208,7 +209,7 @@ for comb in ( ): fmt, tmpl = comb.split("_") - OLD_STYLE_RENDERERS[comb] = "{}|{}".format(tmpl, fmt) + OLD_STYLE_RENDERERS[comb] = f"{tmpl}|{fmt}" def check_render_pipe_str(pipestr, renderers, blacklist, whitelist): diff --git a/salt/thorium/__init__.py b/salt/thorium/__init__.py index 0b2bfb37f0d..6dffc972a07 100644 --- a/salt/thorium/__init__.py +++ b/salt/thorium/__init__.py @@ -1,6 +1,7 @@ """ The thorium system allows for advanced event tracking and reactions """ + # Needed: # Use a top file to load sls files locally # use the existing state system to compile a low state @@ -49,7 +50,7 @@ class ThorState(salt.state.HighState): regdata = {} if self.reg_ret is not None: try: - regdata = self.returners["{}.load_reg".format(self.reg_ret)]() + regdata = self.returners[f"{self.reg_ret}.load_reg"]() except Exception as exc: # pylint: disable=broad-except log.error(exc) @@ -67,7 +68,7 @@ class ThorState(salt.state.HighState): if not minions: return cache for minion in minions: - total = self.cache.fetch("minions/{}".format(minion), "data") + total = self.cache.fetch(f"minions/{minion}", "data") if "pillar" in total: if self.pillar_keys: @@ -175,5 +176,5 @@ class ThorState(salt.state.HighState): cache = self.gather_cache() chunks = self.get_chunks() if self.reg_ret is not None: - self.returners["{}.save_reg".format(self.reg_ret)](chunks) + self.returners[f"{self.reg_ret}.save_reg"](chunks) r_start = time.time() diff --git a/salt/thorium/calc.py b/salt/thorium/calc.py index 9eba4317779..d5487966a54 100644 --- a/salt/thorium/calc.py +++ b/salt/thorium/calc.py @@ -7,7 +7,6 @@ values are stored and computed, such as averages etc. :depends: statistics PyPi module """ - try: import statistics @@ -49,7 +48,7 @@ def calc(name, num, oper, minimum=0, maximum=0, ref=None): """ ret = {"name": name, "changes": {}, "comment": "", "result": True} if name not in __reg__: - ret["comment"] = "{} not found in register".format(name) + ret["comment"] = f"{name} not found in register" ret["result"] = False def opadd(vals): diff --git a/salt/thorium/check.py b/salt/thorium/check.py index ee41cfb9034..48149f3c426 100644 --- a/salt/thorium/check.py +++ b/salt/thorium/check.py @@ -35,7 +35,7 @@ def gt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] > value: ret["result"] = True @@ -65,7 +65,7 @@ def gte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] >= value: ret["result"] = True @@ -95,7 +95,7 @@ def lt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] < value: ret["result"] = True @@ -125,7 +125,7 @@ def lte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] <= value: ret["result"] = True @@ -155,7 +155,7 @@ def eq(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] == value: ret["result"] = True @@ -185,7 +185,7 @@ def ne(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] != value: ret["result"] = True @@ -224,7 +224,7 @@ def contains( ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret try: count_compare = ( @@ -305,7 +305,7 @@ def len_gt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) > value: ret["result"] = True @@ -335,7 +335,7 @@ def len_gte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) >= value: ret["result"] = True @@ -365,7 +365,7 @@ def len_lt(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) < value: ret["result"] = True @@ -395,7 +395,7 @@ def len_lte(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) <= value: ret["result"] = True @@ -425,7 +425,7 @@ def len_eq(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if __reg__[name]["val"] == value: ret["result"] = True @@ -455,7 +455,7 @@ def len_ne(name, value): ret = {"name": name, "result": False, "comment": "", "changes": {}} if name not in __reg__: ret["result"] = False - ret["comment"] = "Value {} not in register".format(name) + ret["comment"] = f"Value {name} not in register" return ret if len(__reg__[name]["val"]) != value: ret["result"] = True diff --git a/salt/thorium/file.py b/salt/thorium/file.py index 1e7dcc8f09e..ad6911e9003 100644 --- a/salt/thorium/file.py +++ b/salt/thorium/file.py @@ -37,7 +37,6 @@ Be warned that if you do this, then the file will be saved, but not in a format that can be re-imported into Python. """ - import os import salt.utils.data diff --git a/salt/thorium/reg.py b/salt/thorium/reg.py index 20cbebb253f..57842202cdf 100644 --- a/salt/thorium/reg.py +++ b/salt/thorium/reg.py @@ -3,7 +3,6 @@ Used to manage the thorium register. The thorium register is where compound values are stored and computed, such as averages etc. """ - import salt.utils.stringutils __func_alias__ = { diff --git a/salt/thorium/timer.py b/salt/thorium/timer.py index a1eefa3aa6f..bc67ec502a0 100644 --- a/salt/thorium/timer.py +++ b/salt/thorium/timer.py @@ -3,7 +3,6 @@ Allow for flow based timers. These timers allow for a sleep to exist across multiple runs of the flow """ - import time diff --git a/salt/tokens/localfs.py b/salt/tokens/localfs.py index afebb1a9ea7..93cfffa934f 100644 --- a/salt/tokens/localfs.py +++ b/salt/tokens/localfs.py @@ -2,7 +2,6 @@ Stores eauth tokens in the filesystem of the master. Location is configured by the master config option 'token_dir' """ - import hashlib import logging import os @@ -93,7 +92,7 @@ def list_tokens(opts): :returns: List of dicts (tokens) """ ret = [] - for (dirpath, dirnames, filenames) in salt.utils.path.os_walk(opts["token_dir"]): + for dirpath, dirnames, filenames in salt.utils.path.os_walk(opts["token_dir"]): for token in filenames: ret.append(token) return ret diff --git a/salt/tops/cobbler.py b/salt/tops/cobbler.py index 7a5d66662ab..5e5aed16a4b 100644 --- a/salt/tops/cobbler.py +++ b/salt/tops/cobbler.py @@ -20,9 +20,8 @@ Module Documentation """ import logging -import xmlrpc.client +import xmlrpc.client # nosec -# Set up logging log = logging.getLogger(__name__) diff --git a/salt/tops/ext_nodes.py b/salt/tops/ext_nodes.py index 4aa7ee1566c..a32c9f8eae8 100644 --- a/salt/tops/ext_nodes.py +++ b/salt/tops/ext_nodes.py @@ -44,6 +44,7 @@ The above essentially is the same as a top.sls containing the following: - basepackages - database """ + import logging import shlex import subprocess diff --git a/salt/tops/reclass_adapter.py b/salt/tops/reclass_adapter.py index 65fe33b0a5f..9b04bb55b58 100644 --- a/salt/tops/reclass_adapter.py +++ b/salt/tops/reclass_adapter.py @@ -120,7 +120,7 @@ def top(**kwargs): except ImportError as e: if "reclass" in str(e): raise SaltInvocationError( - "master_tops.reclass: cannot find reclass module in {}".format(sys.path) + f"master_tops.reclass: cannot find reclass module in {sys.path}" ) else: raise @@ -128,9 +128,7 @@ def top(**kwargs): except TypeError as e: if "unexpected keyword argument" in str(e): arg = str(e).split()[-1] - raise SaltInvocationError( - "master_tops.reclass: unexpected option: {}".format(arg) - ) + raise SaltInvocationError(f"master_tops.reclass: unexpected option: {arg}") else: raise @@ -143,4 +141,4 @@ def top(**kwargs): raise except ReclassException as e: - raise SaltInvocationError("master_tops.reclass: {}".format(str(e))) + raise SaltInvocationError(f"master_tops.reclass: {str(e)}") diff --git a/salt/tops/saltclass.py b/salt/tops/saltclass.py index 94dbae8b156..f9057842f47 100644 --- a/salt/tops/saltclass.py +++ b/salt/tops/saltclass.py @@ -207,7 +207,6 @@ Not using ``^`` as the first entry will simply merge the lists escaped one will not be correctly rendered - '\${xx}' will stay as is instead of being rendered as '${xx}' """ - import logging import salt.utils.saltclass as sc diff --git a/salt/tops/varstack_top.py b/salt/tops/varstack_top.py index 7f0f833cb65..479701d60ac 100644 --- a/salt/tops/varstack_top.py +++ b/salt/tops/varstack_top.py @@ -42,7 +42,6 @@ managed by salt as if given from a top.sls file. """ - try: import varstack except ImportError: diff --git a/salt/transport/__init__.py b/salt/transport/__init__.py index 83d327cdbc4..8795cb9d52a 100644 --- a/salt/transport/__init__.py +++ b/salt/transport/__init__.py @@ -1,6 +1,7 @@ """ Encapsulate the different transports available to Salt. """ + import logging import warnings diff --git a/salt/transport/client.py b/salt/transport/client.py index 6b079c9756b..899532380f6 100644 --- a/salt/transport/client.py +++ b/salt/transport/client.py @@ -7,6 +7,7 @@ This includes client side transport, for the ReqServer and the Publisher NOTE: This module has been deprecated and will be removed in Argon. Please use salt.channel.server instead. """ + import logging from salt.utils.versions import warn_until diff --git a/salt/transport/frame.py b/salt/transport/frame.py index c545a6ee7cf..aa6961f5ad9 100644 --- a/salt/transport/frame.py +++ b/salt/transport/frame.py @@ -2,7 +2,6 @@ Helper functions for transport components to handle message framing """ - import salt.utils.msgpack diff --git a/salt/transport/ipc.py b/salt/transport/ipc.py index 5265467112a..5421c60d1e5 100644 --- a/salt/transport/ipc.py +++ b/salt/transport/ipc.py @@ -2,7 +2,6 @@ IPC transport classes """ - import errno import logging import socket diff --git a/salt/transport/server.py b/salt/transport/server.py index 5b162b90e5b..1883ca1d1f6 100644 --- a/salt/transport/server.py +++ b/salt/transport/server.py @@ -7,6 +7,7 @@ This includes server side transport, for the ReqServer and the Publisher NOTE: This module has been deprecated and will be removed in Argon. Please use salt.channel.server instead. """ + import logging from salt.utils.versions import warn_until diff --git a/salt/transport/tcp.py b/salt/transport/tcp.py index 0dca8d6e4cf..42ab887aec9 100644 --- a/salt/transport/tcp.py +++ b/salt/transport/tcp.py @@ -4,6 +4,7 @@ TCP transport classes Wire protocol: "len(payload) msgpack({'head': SOMEHEADER, 'body': SOMEBODY})" """ + import asyncio import asyncio.exceptions import errno diff --git a/salt/transport/zeromq.py b/salt/transport/zeromq.py index c7e07408ae5..43f335a2338 100644 --- a/salt/transport/zeromq.py +++ b/salt/transport/zeromq.py @@ -1,6 +1,7 @@ """ Zeromq transport classes """ + import asyncio import asyncio.exceptions import errno @@ -365,7 +366,6 @@ class PublishClient(salt.transport.base.PublishClient): # self.on_recv_task = asyncio.create_task(self.on_recv_handler(callback)) def on_recv(self, callback): - """ Register a callback for received messages (that we didn't initiate) diff --git a/salt/utils/aggregation.py b/salt/utils/aggregation.py index e668f2c3782..eadbd2cfeb5 100644 --- a/salt/utils/aggregation.py +++ b/salt/utils/aggregation.py @@ -102,7 +102,6 @@ """ - import copy import logging @@ -132,7 +131,6 @@ class Sequence(list, Aggregate): def Scalar(obj): - """ Shortcut for Sequence creation diff --git a/salt/utils/ansible.py b/salt/utils/ansible.py index b91c931dff6..d75740e30f2 100644 --- a/salt/utils/ansible.py +++ b/salt/utils/ansible.py @@ -24,7 +24,7 @@ def targets(inventory="/etc/ansible/hosts", yaml=False, export=False): Default: /etc/salt/roster """ if not os.path.isfile(inventory): - raise CommandExecutionError("Inventory file not found: {}".format(inventory)) + raise CommandExecutionError(f"Inventory file not found: {inventory}") if not os.path.isabs(inventory): raise CommandExecutionError("Path to inventory file must be an absolute path") @@ -44,6 +44,4 @@ def targets(inventory="/etc/ansible/hosts", yaml=False, export=False): try: return salt.utils.json.loads(salt.utils.stringutils.to_str(inv)) except ValueError: - raise CommandExecutionError( - "Error processing the inventory: {}".format(inv) - ) + raise CommandExecutionError(f"Error processing the inventory: {inv}") diff --git a/salt/utils/args.py b/salt/utils/args.py index 536aea38166..e34c208d6dd 100644 --- a/salt/utils/args.py +++ b/salt/utils/args.py @@ -49,7 +49,7 @@ def invalid_kwargs(invalid_kwargs, raise_exc=True): """ if invalid_kwargs: if isinstance(invalid_kwargs, dict): - new_invalid = ["{}={}".format(x, y) for x, y in invalid_kwargs.items()] + new_invalid = [f"{x}={y}" for x, y in invalid_kwargs.items()] invalid_kwargs = new_invalid msg = "The following keyword arguments are not valid: {}".format( ", ".join(invalid_kwargs) @@ -236,7 +236,7 @@ def get_function_argspec(func, is_class_method=None): the argspec unless ``is_class_method`` is True. """ if not callable(func): - raise TypeError("{} is not a callable".format(func)) + raise TypeError(f"{func} is not a callable") while hasattr(func, "__wrapped__"): func = func.__wrapped__ @@ -244,7 +244,7 @@ def get_function_argspec(func, is_class_method=None): try: sig = inspect.signature(func) except TypeError: - raise TypeError("Cannot inspect argument list for '{}'".format(func)) + raise TypeError(f"Cannot inspect argument list for '{func}'") # Build a namedtuple which looks like the result of a Python 2 argspec _ArgSpec = namedtuple("ArgSpec", "args varargs keywords defaults") @@ -466,18 +466,18 @@ def format_call( # In case this is being called for a state module "full", # Not a state module, build the name - "{}.{}".format(fun.__module__, fun.__name__), + f"{fun.__module__}.{fun.__name__}", ), ) else: msg = "{} and '{}' are invalid keyword arguments for '{}'".format( - ", ".join(["'{}'".format(e) for e in extra][:-1]), + ", ".join([f"'{e}'" for e in extra][:-1]), list(extra.keys())[-1], ret.get( # In case this is being called for a state module "full", # Not a state module, build the name - "{}.{}".format(fun.__module__, fun.__name__), + f"{fun.__module__}.{fun.__name__}", ), ) @@ -529,7 +529,8 @@ def parse_function(s): key = None word = [] elif token in "]})": - if not brackets or token != {"[": "]", "{": "}", "(": ")"}[brackets.pop()]: + _tokens = {"[": "]", "{": "}", "(": ")"} + if not brackets or token != _tokens[brackets.pop()]: break word.append(token) elif token == "=" and not brackets: diff --git a/salt/utils/asynchronous.py b/salt/utils/asynchronous.py index f983a4ec64f..316fc5c478d 100644 --- a/salt/utils/asynchronous.py +++ b/salt/utils/asynchronous.py @@ -2,7 +2,6 @@ Helpers/utils for working with tornado asynchronous stuff """ - import asyncio import contextlib import logging diff --git a/salt/utils/atomicfile.py b/salt/utils/atomicfile.py index 574797b77e3..d36733c83fb 100644 --- a/salt/utils/atomicfile.py +++ b/salt/utils/atomicfile.py @@ -2,6 +2,7 @@ A module written originally by Armin Ronacher to manage file transfers in an atomic way """ + import errno import os import random @@ -90,7 +91,7 @@ if os.name == "nt": # pragma: no cover except OSError as err: if err.errno != errno.EEXIST: raise - old = "{}-{:08x}".format(dst, random.randint(0, sys.maxint)) + old = f"{dst}-{random.randint(0, sys.maxint):08x}" os.rename(dst, old) os.rename(src, dst) try: diff --git a/salt/utils/aws.py b/salt/utils/aws.py index 36a99d92bcf..4c581a06c92 100644 --- a/salt/utils/aws.py +++ b/salt/utils/aws.py @@ -7,6 +7,7 @@ This is a base library used by a number of AWS services. :depends: requests """ + import binascii import copy import hashlib diff --git a/salt/utils/boto3mod.py b/salt/utils/boto3mod.py index 3692ae5549e..4e84c2ee70c 100644 --- a/salt/utils/boto3mod.py +++ b/salt/utils/boto3mod.py @@ -24,7 +24,6 @@ Example Usage: .. versionadded:: 2015.8.0 """ - import hashlib import logging import sys @@ -104,7 +103,7 @@ def _get_profile(service, region, key, keyid, profile): if not keyid and _option(service + ".keyid"): keyid = _option(service + ".keyid") - label = "boto_{}:".format(service) + label = f"boto_{service}:" if keyid: hash_string = region + keyid + key hash_string = salt.utils.stringutils.to_bytes(hash_string) @@ -138,9 +137,9 @@ def cache_id( cxkey, _, _, _ = _get_profile(service, region, key, keyid, profile) if sub_resource: - cxkey = "{}:{}:{}:id".format(cxkey, sub_resource, name) + cxkey = f"{cxkey}:{sub_resource}:{name}:id" else: - cxkey = "{}:{}:id".format(cxkey, name) + cxkey = f"{cxkey}:{name}:id" if invalidate: if cxkey in __context__: @@ -197,10 +196,10 @@ def get_connection( aws_access_key_id=keyid, aws_secret_access_key=key, region_name=region ) if session is None: - raise SaltInvocationError('Region "{}" is not valid.'.format(region)) + raise SaltInvocationError(f'Region "{region}" is not valid.') conn = session.client(module) if conn is None: - raise SaltInvocationError('Region "{}" is not valid.'.format(region)) + raise SaltInvocationError(f'Region "{region}" is not valid.') except botocore.exceptions.NoCredentialsError: raise SaltInvocationError( "No authentication credentials found when " diff --git a/salt/utils/botomod.py b/salt/utils/botomod.py index 8d9d5cad535..ac9b510d689 100644 --- a/salt/utils/botomod.py +++ b/salt/utils/botomod.py @@ -24,7 +24,6 @@ Example Usage: .. versionadded:: 2015.8.0 """ - import hashlib import logging import sys @@ -91,7 +90,7 @@ def _get_profile(service, region, key, keyid, profile): if not keyid and __salt__["config.option"](service + ".keyid"): keyid = __salt__["config.option"](service + ".keyid") - label = "boto_{}:".format(service) + label = f"boto_{service}:" if keyid: hash_string = region + keyid + key hash_string = salt.utils.stringutils.to_bytes(hash_string) @@ -125,9 +124,9 @@ def cache_id( cxkey, _, _, _ = _get_profile(service, region, key, keyid, profile) if sub_resource: - cxkey = "{}:{}:{}:id".format(cxkey, sub_resource, name) + cxkey = f"{cxkey}:{sub_resource}:{name}:id" else: - cxkey = "{}:{}:id".format(cxkey, name) + cxkey = f"{cxkey}:{name}:id" if invalidate: if cxkey in __context__: @@ -187,7 +186,7 @@ def get_connection( region, aws_access_key_id=keyid, aws_secret_access_key=key ) if conn is None: - raise SaltInvocationError('Region "{}" is not valid.'.format(region)) + raise SaltInvocationError(f'Region "{region}" is not valid.') except boto.exception.NoAuthHandlerFound: raise SaltInvocationError( "No authentication credentials found when " diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py index 3e026a0bb57..0f3e27c2a24 100644 --- a/salt/utils/cloud.py +++ b/salt/utils/cloud.py @@ -2,7 +2,6 @@ Utility functions for salt.cloud """ - import codecs import copy import errno @@ -565,9 +564,9 @@ def bootstrap(vm_, opts=None): ) if saltify_driver: - deploy_kwargs[ - "wait_for_passwd_maxtries" - ] = 0 # No need to wait/retry with Saltify + deploy_kwargs["wait_for_passwd_maxtries"] = ( + 0 # No need to wait/retry with Saltify + ) win_installer = salt.config.get_cloud_config_value("win_installer", vm_, opts) if win_installer: diff --git a/salt/utils/color.py b/salt/utils/color.py index d765288f496..8ef55ccad20 100644 --- a/salt/utils/color.py +++ b/salt/utils/color.py @@ -2,7 +2,6 @@ Functions used for CLI color themes. """ - import logging import os @@ -28,7 +27,7 @@ def get_color_theme(theme): colors = salt.utils.data.decode(salt.utils.yaml.safe_load(fp_)) ret = {} for color in colors: - ret[color] = "\033[{}m".format(colors[color]) + ret[color] = f"\033[{colors[color]}m" if not isinstance(colors, dict): log.warning("The theme file %s is not a dict", theme) return {} diff --git a/salt/utils/configcomparer.py b/salt/utils/configcomparer.py index ef67e65e5f1..1ab770a5a96 100644 --- a/salt/utils/configcomparer.py +++ b/salt/utils/configcomparer.py @@ -32,7 +32,7 @@ def compare_and_update_config(config, update_config, changes, namespace=""): for key, value in config.items(): _namespace = key if namespace: - _namespace = "{}.{}".format(namespace, _namespace) + _namespace = f"{namespace}.{_namespace}" update_config[key] = compare_and_update_config( value, update_config.get(key, None), @@ -61,9 +61,9 @@ def compare_and_update_config(config, update_config, changes, namespace=""): # iterate through config list, ensuring that each index in the # update_config list is the same for idx, item in enumerate(config): - _namespace = "[{}]".format(idx) + _namespace = f"[{idx}]" if namespace: - _namespace = "{}{}".format(namespace, _namespace) + _namespace = f"{namespace}{_namespace}" _update = None if len(update_config) > idx: _update = update_config[idx] @@ -86,9 +86,9 @@ def compare_and_update_config(config, update_config, changes, namespace=""): for idx, old_item in enumerate(update_config): if idx < len(config): continue - _namespace = "[{}]".format(idx) + _namespace = f"[{idx}]" if namespace: - _namespace = "{}{}".format(namespace, _namespace) + _namespace = f"{namespace}{_namespace}" changes[_namespace] = { "new": None, "old": old_item, diff --git a/salt/utils/configparser.py b/salt/utils/configparser.py index 6a3b1e689ea..f4d72c68343 100644 --- a/salt/utils/configparser.py +++ b/salt/utils/configparser.py @@ -267,12 +267,12 @@ class GitConfigParser(RawConfigParser): ) if self._defaults: fp_.write(convert("[%s]\n" % self.DEFAULTSECT)) - for (key, value) in self._defaults.items(): + for key, value in self._defaults.items(): value = salt.utils.stringutils.to_unicode(value).replace("\n", "\n\t") - fp_.write(convert("{} = {}\n".format(key, value))) + fp_.write(convert(f"{key} = {value}\n")) for section in self._sections: fp_.write(convert("[%s]\n" % section)) - for (key, value) in self._sections[section].items(): + for key, value in self._sections[section].items(): if (value is not None) or (self._optcre == self.OPTCRE): if not isinstance(value, list): value = [value] diff --git a/salt/utils/crypt.py b/salt/utils/crypt.py index e34576c175a..044eebe7a77 100644 --- a/salt/utils/crypt.py +++ b/salt/utils/crypt.py @@ -1,6 +1,7 @@ """ Functions dealing with encryption """ + import hashlib import logging import os diff --git a/salt/utils/data.py b/salt/utils/data.py index 5f9d7484868..5b7cc8fbea6 100644 --- a/salt/utils/data.py +++ b/salt/utils/data.py @@ -3,7 +3,6 @@ Functions for manipulating, inspecting, or otherwise working with data types and data structures. """ - import copy import datetime import fnmatch @@ -1380,7 +1379,7 @@ def recursive_diff( append_old = list(old.keys())[min_length:] append_new = list(new.keys())[min_length:] # Compare ordered - for (key_old, key_new) in zip(old, new): + for key_old, key_new in zip(old, new): if key_old == key_new: if key_old in ignore_keys: del ret_old[key_old] diff --git a/salt/utils/dateutils.py b/salt/utils/dateutils.py index b55d9a40027..2b680672eb6 100644 --- a/salt/utils/dateutils.py +++ b/salt/utils/dateutils.py @@ -2,7 +2,6 @@ Convenience functions for dealing with datetime classes """ - import datetime import salt.utils.stringutils @@ -47,11 +46,9 @@ def date_cast(date): return datetime.datetime.fromtimestamp(date) except Exception: # pylint: disable=broad-except if HAS_TIMELIB: - raise ValueError("Unable to parse {}".format(date)) + raise ValueError(f"Unable to parse {date}") - raise RuntimeError( - "Unable to parse {}. Consider installing timelib".format(date) - ) + raise RuntimeError(f"Unable to parse {date}. Consider installing timelib") @jinja_filter("date_format") diff --git a/salt/utils/debug.py b/salt/utils/debug.py index e1fda0a8aec..e74bad3dda2 100644 --- a/salt/utils/debug.py +++ b/salt/utils/debug.py @@ -34,7 +34,7 @@ def _handle_sigusr1(sig, stack): output = sys.stderr _makepretty(output, stack) else: - filename = "salt-debug-{}.log".format(int(time.time())) + filename = f"salt-debug-{int(time.time())}.log" destfile = os.path.join(tempfile.gettempdir(), filename) with salt.utils.files.fopen(destfile, "w") as output: _makepretty(output, stack) @@ -50,11 +50,11 @@ def _handle_sigusr2(sig, stack): return if yappi.is_running(): yappi.stop() - filename = "callgrind.salt-{}-{}".format(int(time.time()), os.getpid()) + filename = f"callgrind.salt-{int(time.time())}-{os.getpid()}" destfile = os.path.join(tempfile.gettempdir(), filename) yappi.get_func_stats().save(destfile, type="CALLGRIND") if sys.stderr.isatty(): - sys.stderr.write("Saved profiling data to: {}\n".format(destfile)) + sys.stderr.write(f"Saved profiling data to: {destfile}\n") yappi.clear_stats() else: if sys.stderr.isatty(): @@ -135,5 +135,5 @@ def caller_name(skip=2, include_lineno=False): del parentframe fullname = ".".join(name) if include_lineno and lineno: - fullname += ":{}".format(lineno) + fullname += f":{lineno}" return fullname diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py index 1f62d5f3d65..4ddf359d23c 100644 --- a/salt/utils/decorators/__init__.py +++ b/salt/utils/decorators/__init__.py @@ -2,7 +2,6 @@ Helpful decorators for module writing """ - import errno import inspect import logging @@ -117,7 +116,7 @@ class Depends: @staticmethod def run_command(dependency, mod_name, func_name): - full_name = "{}.{}".format(mod_name, func_name) + full_name = f"{mod_name}.{func_name}" log.trace("Running '%s' for '%s'", dependency, full_name) if IS_WINDOWS: args = salt.utils.args.shlex_split(dependency, posix=False) @@ -217,9 +216,11 @@ class Depends: mod_name, func_name, dependency, - " version {}".format(params["version"]) - if "version" in params - else "", + ( + " version {}".format(params["version"]) + if "version" in params + else "" + ), ) # if not, unload the function if frame: @@ -228,7 +229,7 @@ class Depends: except (AttributeError, KeyError): pass - mod_key = "{}.{}".format(mod_name, func_name) + mod_key = f"{mod_name}.{func_name}" # if we don't have this module loaded, skip it! if mod_key not in functions: @@ -263,7 +264,7 @@ def timing(function): mod_name = function.__module__[16:] else: mod_name = function.__module__ - fstr = "Function %s.%s took %.{}f seconds to execute".format(sys.float_info.dig) + fstr = f"Function %s.%s took %.{sys.float_info.dig}f seconds to execute" log.profile(fstr, mod_name, function.__name__, end_time - start_time) return ret @@ -290,9 +291,7 @@ def memoize(func): else: str_args.append(arg) - args_ = ",".join( - list(str_args) + ["{}={}".format(k, kwargs[k]) for k in sorted(kwargs)] - ) + args_ = ",".join(list(str_args) + [f"{k}={kwargs[k]}" for k in sorted(kwargs)]) if args_ not in cache: cache[args_] = func(*args, **kwargs) return cache[args_] @@ -623,9 +622,7 @@ class _WithDeprecated(_DeprecationDecorator): "Function '{}' is mentioned both in deprecated " "and superseded sections. Please remove any of that.".format(full_name) ) - old_function = self._globals.get( - self._with_name or "_{}".format(function.__name__) - ) + old_function = self._globals.get(self._with_name or f"_{function.__name__}") if self._policy == self.OPT_IN: self._function = function if use_superseded else old_function else: diff --git a/salt/utils/decorators/extension_deprecation.py b/salt/utils/decorators/extension_deprecation.py index a540eb0825f..bced8ea180e 100644 --- a/salt/utils/decorators/extension_deprecation.py +++ b/salt/utils/decorators/extension_deprecation.py @@ -1,6 +1,7 @@ """ Decorators for deprecation of modules to Salt extensions """ + import logging from functools import wraps diff --git a/salt/utils/decorators/path.py b/salt/utils/decorators/path.py index 254593553a3..af08960b3e5 100644 --- a/salt/utils/decorators/path.py +++ b/salt/utils/decorators/path.py @@ -18,7 +18,7 @@ def which(exe): def wrapped(*args, **kwargs): if salt.utils.path.which(exe) is None: raise CommandNotFoundError( - "The '{}' binary was not found in $PATH.".format(exe) + f"The '{exe}' binary was not found in $PATH." ) return function(*args, **kwargs) @@ -38,7 +38,7 @@ def which_bin(exes): if salt.utils.path.which_bin(exes) is None: raise CommandNotFoundError( "None of provided binaries({}) were found in $PATH.".format( - ["'{}'".format(exe) for exe in exes] + [f"'{exe}'" for exe in exes] ) ) return function(*args, **kwargs) diff --git a/salt/utils/decorators/state.py b/salt/utils/decorators/state.py index bcca040b996..0d0fbf4254f 100644 --- a/salt/utils/decorators/state.py +++ b/salt/utils/decorators/state.py @@ -4,7 +4,6 @@ Decorators for salt.state :codeauthor: :email:`Bo Maryniuk (bo@suse.de)` """ - import logging import salt.utils.stringutils @@ -18,7 +17,7 @@ class OutputUnifier: self.policies = [] for pls in policies: if not hasattr(self, pls): - raise SaltException("Unknown policy: {}".format(pls)) + raise SaltException(f"Unknown policy: {pls}") else: self.policies.append(getattr(self, pls)) @@ -36,7 +35,7 @@ class OutputUnifier: "result": False, "name": "later", "changes": {}, - "comment": "An exception occurred in this state: {}".format(exc), + "comment": f"An exception occurred in this state: {exc}", } return data diff --git a/salt/utils/dns.py b/salt/utils/dns.py index dc0d680c773..2a7cd420cf7 100644 --- a/salt/utils/dns.py +++ b/salt/utils/dns.py @@ -123,7 +123,7 @@ def _to_port(port): assert 1 <= port <= 65535 return port except (ValueError, AssertionError): - raise ValueError("Invalid port {}".format(port)) + raise ValueError(f"Invalid port {port}") def _tree(domain, tld=False): @@ -276,24 +276,24 @@ def _lookup_dig(name, rdtype, timeout=None, servers=None, secure=None): :param servers: [] of servers to use :return: [] of records or False if error """ - cmd = "dig {} -t {} ".format(DIG_OPTIONS, rdtype) + cmd = f"dig {DIG_OPTIONS} -t {rdtype} " if servers: - cmd += "".join(["@{} ".format(srv) for srv in servers]) + cmd += "".join([f"@{srv} " for srv in servers]) if timeout is not None: if servers: timeout = int(float(timeout) / len(servers)) else: timeout = int(timeout) - cmd += "+time={} ".format(timeout) + cmd += f"+time={timeout} " if secure: cmd += "+dnssec +adflag " cmd = __salt__["cmd.run_all"]( - "{} {}".format(cmd, name), python_shell=False, output_loglevel="quiet" + f"{cmd} {name}", python_shell=False, output_loglevel="quiet" ) if "ignoring invalid type" in cmd["stderr"]: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") elif cmd["retcode"] != 0: log.warning( "dig returned (%s): %s", @@ -333,9 +333,9 @@ def _lookup_drill(name, rdtype, timeout=None, servers=None, secure=None): cmd = "drill " if secure: cmd += "-D -o ad " - cmd += "{} {} ".format(rdtype, name) + cmd += f"{rdtype} {name} " if servers: - cmd += "".join(["@{} ".format(srv) for srv in servers]) + cmd += "".join([f"@{srv} " for srv in servers]) cmd = __salt__["cmd.run_all"]( cmd, timeout=timeout, python_shell=False, output_loglevel="quiet" ) @@ -364,7 +364,7 @@ def _lookup_drill(name, rdtype, timeout=None, servers=None, secure=None): validated = True continue elif l_type != rdtype: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") res.append(_data_clean(l_rec)) @@ -385,10 +385,12 @@ def _lookup_gai(name, rdtype, timeout=None): :param timeout: ignored :return: [] of addresses or False if error """ - try: - sock_t = {"A": socket.AF_INET, "AAAA": socket.AF_INET6}[rdtype] - except KeyError: - raise ValueError("Invalid DNS type {} for gai lookup".format(rdtype)) + if rdtype == "A": + sock_t = socket.AF_INET + elif rdtype == "AAAA": + sock_t = socket.AF_INET6 + else: + raise ValueError(f"Invalid DNS type {rdtype} for gai lookup") if timeout: log.info("Ignoring timeout on gai resolver; fix resolv.conf to do that") @@ -412,18 +414,18 @@ def _lookup_host(name, rdtype, timeout=None, server=None): :param timeout: server response wait :return: [] of records or False if error """ - cmd = "host -t {} ".format(rdtype) + cmd = f"host -t {rdtype} " if timeout: - cmd += "-W {} ".format(int(timeout)) + cmd += f"-W {int(timeout)} " cmd += name if server is not None: - cmd += " {}".format(server) + cmd += f" {server}" cmd = __salt__["cmd.run_all"](cmd, python_shell=False, output_loglevel="quiet") if "invalid type" in cmd["stderr"]: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") elif cmd["retcode"] != 0: log.warning("host returned (%s): %s", cmd["retcode"], cmd["stderr"]) return False @@ -470,7 +472,7 @@ def _lookup_dnspython(name, rdtype, timeout=None, servers=None, secure=None): ] return res except dns.rdatatype.UnknownRdatatype: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") except ( dns.resolver.NXDOMAIN, dns.resolver.YXDOMAIN, @@ -489,12 +491,12 @@ def _lookup_nslookup(name, rdtype, timeout=None, server=None): :param server: server to query :return: [] of records or False if error """ - cmd = "nslookup -query={} {}".format(rdtype, name) + cmd = f"nslookup -query={rdtype} {name}" if timeout is not None: - cmd += " -timeout={}".format(int(timeout)) + cmd += f" -timeout={int(timeout)}" if server is not None: - cmd += " {}".format(server) + cmd += f" {server}" cmd = __salt__["cmd.run_all"](cmd, python_shell=False, output_loglevel="quiet") @@ -511,7 +513,7 @@ def _lookup_nslookup(name, rdtype, timeout=None, server=None): try: line = next(lookup_res) if "unknown query type" in line: - raise ValueError("Invalid DNS type {}".format(rdtype)) + raise ValueError(f"Invalid DNS type {rdtype}") while True: if name in line: @@ -895,7 +897,7 @@ def spf_rec(rdata): # It's a modifier mod, val = mech_spec.split("=", 1) if mod in mods: - raise KeyError("Modifier {} can only appear once".format(mod)) + raise KeyError(f"Modifier {mod} can only appear once") mods.add(mod) continue @@ -959,7 +961,7 @@ def srv_name(svc, proto="tcp", domain=None): if domain: domain = "." + domain - return "_{}._{}{}".format(svc, proto, domain) + return f"_{svc}._{proto}{domain}" def srv_rec(rdatas): @@ -1133,7 +1135,7 @@ def services(services_file="/etc/services"): if not curr_desc: pp_res["desc"] = comment elif comment != curr_desc: - pp_res["desc"] = "{}, {}".format(curr_desc, comment) + pp_res["desc"] = f"{curr_desc}, {comment}" res[name] = svc_res for svc, data in res.items(): @@ -1210,7 +1212,7 @@ def parse_resolv(src="/etc/resolv.conf"): ip_addr ) ip_net = ipaddress.ip_network( - "{}{}".format(ip_addr, mask), strict=False + f"{ip_addr}{mask}", strict=False ) if ip_net.version == 6: # TODO diff --git a/salt/utils/doc.py b/salt/utils/doc.py index 9f80bc3337b..4fcbe1549d6 100644 --- a/salt/utils/doc.py +++ b/salt/utils/doc.py @@ -1,6 +1,7 @@ """ Functions for analyzing/parsing docstrings """ + import logging import re diff --git a/salt/utils/dockermod/__init__.py b/salt/utils/dockermod/__init__.py index f703ee7b1e6..73f1be23a15 100644 --- a/salt/utils/dockermod/__init__.py +++ b/salt/utils/dockermod/__init__.py @@ -5,7 +5,6 @@ This module contains logic to accommodate docker/salt CLI usage, as well as input as formatted by states. """ - import copy import logging diff --git a/salt/utils/dockermod/translate/container.py b/salt/utils/dockermod/translate/container.py index b155308bf74..a59fd9c7e82 100644 --- a/salt/utils/dockermod/translate/container.py +++ b/salt/utils/dockermod/translate/container.py @@ -137,7 +137,7 @@ def binds(val, **kwargs): # pylint: disable=unused-argument val = helpers.split(val) except AttributeError: raise SaltInvocationError( - "'{}' is not a dictionary or list of bind definitions".format(val) + f"'{val}' is not a dictionary or list of bind definitions" ) return val @@ -453,9 +453,11 @@ def port_bindings(val, **kwargs): bind_vals = [ ( _format_port(val, proto), - (host_ip,) - if hport_list[idx] is None - else (host_ip, hport_list[idx]), + ( + (host_ip,) + if hport_list[idx] is None + else (host_ip, hport_list[idx]) + ), ) for idx, val in enumerate(cport_list) ] @@ -509,9 +511,7 @@ def ports(val, **kwargs): # pylint: disable=unused-argument if isinstance(val, int): val = [val] else: - raise SaltInvocationError( - "'{}' is not a valid port definition".format(val) - ) + raise SaltInvocationError(f"'{val}' is not a valid port definition") new_ports = set() for item in val: if isinstance(item, int): @@ -520,9 +520,7 @@ def ports(val, **kwargs): # pylint: disable=unused-argument try: item, _, proto = item.partition("/") except AttributeError: - raise SaltInvocationError( - "'{}' is not a valid port definition".format(item) - ) + raise SaltInvocationError(f"'{item}' is not a valid port definition") try: range_start, range_end = helpers.get_port_range(item) except ValueError as exc: @@ -633,7 +631,7 @@ def ulimits(val, **kwargs): # pylint: disable=unused-argument } except (TypeError, ValueError): raise SaltInvocationError( - "Limit '{}' contains non-numeric value(s)".format(item) + f"Limit '{item}' contains non-numeric value(s)" ) return val @@ -655,7 +653,7 @@ def user(val, **kwargs): # pylint: disable=unused-argument if not isinstance(val, (int, str)): raise SaltInvocationError("Value must be a username or uid") elif isinstance(val, int) and val < 0: - raise SaltInvocationError("'{}' is an invalid uid".format(val)) + raise SaltInvocationError(f"'{val}' is an invalid uid") return val @@ -674,7 +672,7 @@ def volumes(val, **kwargs): # pylint: disable=unused-argument val = helpers.translate_stringlist(val) for item in val: if not os.path.isabs(item): - raise SaltInvocationError("'{}' is not an absolute path".format(item)) + raise SaltInvocationError(f"'{item}' is not an absolute path") return val @@ -691,5 +689,5 @@ def working_dir(val, **kwargs): # pylint: disable=unused-argument except AttributeError: is_abs = False if not is_abs: - raise SaltInvocationError("'{}' is not an absolute path".format(val)) + raise SaltInvocationError(f"'{val}' is not an absolute path") return val diff --git a/salt/utils/dockermod/translate/helpers.py b/salt/utils/dockermod/translate/helpers.py index f172d080cdc..deb0e50ec5f 100644 --- a/salt/utils/dockermod/translate/helpers.py +++ b/salt/utils/dockermod/translate/helpers.py @@ -78,7 +78,7 @@ def get_port_range(port_def): "port range ({})".format(range_start, range_end) ) else: - msg = "'{}' is non-numeric or an invalid port range".format(port_def) + msg = f"'{port_def}' is non-numeric or an invalid port range" raise ValueError(msg) else: return range_start, range_end @@ -110,9 +110,11 @@ def map_vals(val, *names, **extra_opts): "'{}' contains {} value(s) (expected {})".format( item, num_elements, - expected_num_elements - if fill is NOTSET - else "up to {}".format(expected_num_elements), + ( + expected_num_elements + if fill is NOTSET + else f"up to {expected_num_elements}" + ), ) ) val[idx] = dict(zip(names, elements)) @@ -122,7 +124,7 @@ def map_vals(val, *names, **extra_opts): def validate_ip(val): try: if not salt.utils.network.is_ip(val): - raise SaltInvocationError("'{}' is not a valid IP address".format(val)) + raise SaltInvocationError(f"'{val}' is not a valid IP address") except RuntimeError: pass @@ -130,7 +132,7 @@ def validate_ip(val): def validate_subnet(val): try: if not salt.utils.network.is_subnet(val): - raise SaltInvocationError("'{}' is not a valid subnet".format(val)) + raise SaltInvocationError(f"'{val}' is not a valid subnet") except RuntimeError: pass @@ -144,7 +146,7 @@ def translate_int(val): try: val = int(val) except (TypeError, ValueError): - raise SaltInvocationError("'{}' is not an integer".format(val)) + raise SaltInvocationError(f"'{val}' is not an integer") return val @@ -157,7 +159,7 @@ def translate_dict(val): Not really translating, just raising an exception if it's not a dict """ if not isinstance(val, dict): - raise SaltInvocationError("'{}' is not a dictionary".format(val)) + raise SaltInvocationError(f"'{val}' is not a dictionary") return val @@ -255,9 +257,7 @@ def translate_key_val(val, delimiter="="): try: lvalue, rvalue = split(item, delimiter, 1) except (AttributeError, TypeError, ValueError): - raise SaltInvocationError( - "'{}' is not a key{}value pair".format(item, delimiter) - ) + raise SaltInvocationError(f"'{item}' is not a key{delimiter}value pair") new_val[lvalue] = rvalue return new_val diff --git a/salt/utils/extend.py b/salt/utils/extend.py index 72903af23fc..2317feb2bf8 100644 --- a/salt/utils/extend.py +++ b/salt/utils/extend.py @@ -12,7 +12,6 @@ This tool is accessed using `salt-extend` :codeauthor: Anthony Shaw """ - import logging import os import shutil @@ -175,19 +174,15 @@ def _prompt_choice(var_name, options): :returns: The selected user """ choice_map = OrderedDict( - ("{}".format(i), value) - for i, value in enumerate(options, 1) - if value[0] != "test" + (f"{i}", value) for i, value in enumerate(options, 1) if value[0] != "test" ) choices = choice_map.keys() default = "1" - choice_lines = [ - "{} - {} - {}".format(c[0], c[1][0], c[1][1]) for c in choice_map.items() - ] + choice_lines = [f"{c[0]} - {c[1][0]} - {c[1][1]}" for c in choice_map.items()] prompt = "\n".join( ( - "Select {}:".format(var_name), + f"Select {var_name}:", "\n".join(choice_lines), "Choose from {}".format(", ".join(choices)), ) @@ -273,7 +268,7 @@ def run( if description is None: description = _prompt_user_variable("Short description of the module", "") - template_dir = "templates/{}".format(extension_type) + template_dir = f"templates/{extension_type}" module_name = name param_dict = { diff --git a/salt/utils/files.py b/salt/utils/files.py index 3c57cce7132..8f6cf980d66 100644 --- a/salt/utils/files.py +++ b/salt/utils/files.py @@ -2,7 +2,6 @@ Functions for working with files """ - import codecs import contextlib import errno @@ -131,9 +130,9 @@ def copyfile(source, dest, backup_mode="", cachedir=""): specified cache the file. """ if not os.path.isfile(source): - raise OSError("[Errno 2] No such file or directory: {}".format(source)) + raise OSError(f"[Errno 2] No such file or directory: {source}") if not os.path.isdir(os.path.dirname(dest)): - raise OSError("[Errno 2] No such file or directory: {}".format(dest)) + raise OSError(f"[Errno 2] No such file or directory: {dest}") bname = os.path.basename(dest) dname = os.path.dirname(os.path.abspath(dest)) tgt = mkstemp(prefix=bname, dir=dname) @@ -199,9 +198,7 @@ def rename(src, dst): os.remove(dst) except OSError as exc: if exc.errno != errno.ENOENT: - raise MinionError( - "Error: Unable to remove {}: {}".format(dst, exc.strerror) - ) + raise MinionError(f"Error: Unable to remove {dst}: {exc.strerror}") os.rename(src, dst) @@ -222,9 +219,9 @@ def process_read_exception(exc, path, ignore=None): return if exc.errno == errno.ENOENT: - raise CommandExecutionError("{} does not exist".format(path)) + raise CommandExecutionError(f"{path} does not exist") elif exc.errno == errno.EACCES: - raise CommandExecutionError("Permission denied reading from {}".format(path)) + raise CommandExecutionError(f"Permission denied reading from {path}") else: raise CommandExecutionError( "Error {} encountered reading from {}: {}".format( @@ -254,7 +251,7 @@ def wait_lock(path, lock_fn=None, timeout=5, sleep=0.1, time_start=None): try: if os.path.exists(lock_fn) and not os.path.isfile(lock_fn): - _raise_error("lock_fn {} exists and is not a file".format(lock_fn)) + _raise_error(f"lock_fn {lock_fn} exists and is not a file") open_flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY while time.time() - time_start < timeout: @@ -294,9 +291,7 @@ def wait_lock(path, lock_fn=None, timeout=5, sleep=0.1, time_start=None): raise except Exception as exc: # pylint: disable=broad-except - _raise_error( - "Error encountered obtaining file lock {}: {}".format(lock_fn, exc) - ) + _raise_error(f"Error encountered obtaining file lock {lock_fn}: {exc}") finally: if obtained_lock: @@ -347,7 +342,7 @@ def fopen(*args, **kwargs): # and True are treated by Python 3's open() as file descriptors 0 # and 1, respectively. if args[0] in (0, 1, 2): - raise TypeError("{} is not a permitted file descriptor".format(args[0])) + raise TypeError(f"{args[0]} is not a permitted file descriptor") except IndexError: pass binary = None @@ -488,7 +483,7 @@ def safe_walk(top, topdown=True, onerror=None, followlinks=True, _seen=None): # Note that listdir and error are globals in this module due # to earlier import-*. names = os.listdir(top) - except os.error as err: + except OSError as err: if onerror is not None: onerror(err) return @@ -694,7 +689,7 @@ def is_binary(path): return salt.utils.stringutils.is_binary(data) except UnicodeDecodeError: return True - except os.error: + except OSError: return False @@ -787,8 +782,8 @@ def backup_minion(path, bkroot): stamp = time.strftime("%a_%b_%d_%H-%M-%S_%Y") else: stamp = time.strftime("%a_%b_%d_%H:%M:%S_%Y") - stamp = "{}{}_{}".format(stamp[:-4], msecs, stamp[-4:]) - bkpath = os.path.join(bkroot, src_dir, "{}_{}".format(bname, stamp)) + stamp = f"{stamp[:-4]}{msecs}_{stamp[-4:]}" + bkpath = os.path.join(bkroot, src_dir, f"{bname}_{stamp}") if not os.path.isdir(os.path.dirname(bkpath)): os.makedirs(os.path.dirname(bkpath)) shutil.copyfile(path, bkpath) @@ -883,7 +878,7 @@ def get_encoding(path): try: with fopen(path, "rb") as fp_: data = fp_.read(2048) - except os.error: + except OSError: raise CommandExecutionError("Failed to open file") # Check for Unicode BOM diff --git a/salt/utils/find.py b/salt/utils/find.py index d722066caa2..b8ae01b1e4a 100644 --- a/salt/utils/find.py +++ b/salt/utils/find.py @@ -82,7 +82,6 @@ the following: user: user name """ - import logging import os import re @@ -163,7 +162,7 @@ def _parse_interval(value): """ match = _INTERVAL_REGEX.match(str(value)) if match is None: - raise ValueError("invalid time interval: '{}'".format(value)) + raise ValueError(f"invalid time interval: '{value}'") result = 0 resolution = None @@ -212,7 +211,7 @@ def _parse_size(value): try: num = int(float(scalar) * multiplier) except ValueError: - raise ValueError('invalid size: "{}"'.format(value)) + raise ValueError(f'invalid size: "{value}"') if style == "-": min_size = 0 @@ -280,7 +279,7 @@ class RegexOption(Option): try: self.regex = re.compile(value) except re.error: - raise ValueError('invalid regular expression: "{}"'.format(value)) + raise ValueError(f'invalid regular expression: "{value}"') def match(self, dirname, filename, fstat): return self.regex.match(filename) @@ -297,7 +296,7 @@ class IregexOption(Option): try: self.regex = re.compile(value, re.IGNORECASE) except re.error: - raise ValueError('invalid regular expression: "{}"'.format(value)) + raise ValueError(f'invalid regular expression: "{value}"') def match(self, dirname, filename, fstat): return self.regex.match(filename) @@ -326,7 +325,7 @@ class TypeOption(Option): try: self.ftypes.add(_FILE_TYPES[ftype]) except KeyError: - raise ValueError('invalid file type "{}"'.format(ftype)) + raise ValueError(f'invalid file type "{ftype}"') def requires(self): return _REQUIRES_STAT @@ -352,7 +351,7 @@ class OwnerOption(Option): try: self.uids.add(pwd.getpwnam(value).pw_uid) except KeyError: - raise ValueError('no such user "{}"'.format(name)) + raise ValueError(f'no such user "{name}"') def requires(self): return _REQUIRES_STAT @@ -378,7 +377,7 @@ class GroupOption(Option): try: self.gids.add(grp.getgrnam(name).gr_gid) except KeyError: - raise ValueError('no such group "{}"'.format(name)) + raise ValueError(f'no such group "{name}"') def requires(self): return _REQUIRES_STAT @@ -450,7 +449,7 @@ class GrepOption(Option): try: self.regex = re.compile(value) except re.error: - raise ValueError('invalid regular expression: "{}"'.format(value)) + raise ValueError(f'invalid regular expression: "{value}"') def requires(self): return _REQUIRES_CONTENTS | _REQUIRES_STAT @@ -590,11 +589,11 @@ class ExecOption(Option): command, salt.utils.stringutils.to_str(err), ) - return "{}:\n{}\n".format(command, salt.utils.stringutils.to_str(out)) + return f"{command}:\n{salt.utils.stringutils.to_str(out)}\n" except Exception as e: # pylint: disable=broad-except log.error('Exception while executing command "%s":\n\n%s', command, e) - return "{}: Failed".format(fullpath) + return f"{fullpath}: Failed" class Finder: @@ -622,11 +621,11 @@ class Finder: # this is a passthrough object, continue continue if not value: - raise ValueError('missing value for "{}" option'.format(key)) + raise ValueError(f'missing value for "{key}" option') try: obj = globals()[key.title() + "Option"](key, value) except KeyError: - raise ValueError('invalid option "{}"'.format(key)) + raise ValueError(f'invalid option "{key}"') if hasattr(obj, "match"): requires = obj.requires() if requires & _REQUIRES_CONTENTS: @@ -722,7 +721,7 @@ def find(path, options): def _main(): if len(sys.argv) < 2: - sys.stderr.write("usage: {} path [options]\n".format(sys.argv[0])) + sys.stderr.write(f"usage: {sys.argv[0]} path [options]\n") sys.exit(salt.defaults.exitcodes.EX_USAGE) path = sys.argv[1] @@ -734,7 +733,7 @@ def _main(): try: finder = Finder(criteria) except ValueError as ex: - sys.stderr.write("error: {}\n".format(ex)) + sys.stderr.write(f"error: {ex}\n") sys.exit(salt.defaults.exitcodes.EX_GENERIC) for result in finder.find(path): diff --git a/salt/utils/fsutils.py b/salt/utils/fsutils.py index 7b0eb084f64..6c93534085c 100644 --- a/salt/utils/fsutils.py +++ b/salt/utils/fsutils.py @@ -1,6 +1,7 @@ """ Run-time utilities """ + # # Copyright (C) 2014 SUSE LLC @@ -112,7 +113,7 @@ def _is_device(path): """ Return True if path is a physical device. """ - out = __salt__["cmd.run_all"]("file -i {}".format(path)) + out = __salt__["cmd.run_all"](f"file -i {path}") _verify_run(out) # Always [device, mime, charset]. See (file --help) diff --git a/salt/utils/functools.py b/salt/utils/functools.py index 5398434adf8..74e9012124c 100644 --- a/salt/utils/functools.py +++ b/salt/utils/functools.py @@ -1,6 +1,7 @@ """ Utility functions to modify other functions """ + import logging import types diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index a7ab90d62ab..056e4782636 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -575,8 +575,8 @@ class GitProvider: """ def _getconf(self, tgt_env="base"): - strip_sep = ( - lambda x: x.rstrip(os.sep) if name in ("root", "mountpoint") else x + strip_sep = lambda x: ( + x.rstrip(os.sep) if name in ("root", "mountpoint") else x ) if self.role != "gitfs": return strip_sep(getattr(self, "_" + name)) @@ -3004,9 +3004,9 @@ class GitFS(GitBase): remotes if remotes is not None else [], per_remote_overrides=per_remote_overrides, per_remote_only=per_remote_only, - git_providers=git_providers - if git_providers is not None - else GIT_PROVIDERS, + git_providers=( + git_providers if git_providers is not None else GIT_PROVIDERS + ), cache_root=cache_root, init_remotes=init_remotes, ) @@ -3241,7 +3241,7 @@ class GitFS(GitBase): if not os.path.isdir(self.file_list_cachedir): try: os.makedirs(self.file_list_cachedir) - except os.error: + except OSError: log.error("Unable to make cachedir %s", self.file_list_cachedir) return [] list_cache = salt.utils.path.join( diff --git a/salt/utils/github.py b/salt/utils/github.py index 1d6824f2ae9..4ee55c39a73 100644 --- a/salt/utils/github.py +++ b/salt/utils/github.py @@ -2,7 +2,6 @@ Connection library for GitHub """ - import logging import salt.utils.http @@ -44,7 +43,7 @@ def get_user_pubkeys(users): key_ids = user[tmp_user] user = tmp_user - url = "https://api.github.com/users/{}/keys".format(user) + url = f"https://api.github.com/users/{user}/keys" result = salt.utils.http.query( url, "GET", diff --git a/salt/utils/gzip_util.py b/salt/utils/gzip_util.py index 5946d2269ab..49592e7280e 100644 --- a/salt/utils/gzip_util.py +++ b/salt/utils/gzip_util.py @@ -4,7 +4,6 @@ Helper module for handling gzip consistently between 2.7+ and 2.6- """ - import gzip import io diff --git a/salt/utils/hashutils.py b/salt/utils/hashutils.py index 02d234af068..4969465acbe 100644 --- a/salt/utils/hashutils.py +++ b/salt/utils/hashutils.py @@ -160,7 +160,7 @@ def get_hash(path, form="sha256", chunk_size=65536): """ hash_type = hasattr(hashlib, form) and getattr(hashlib, form) or None if hash_type is None: - raise ValueError("Invalid hash type: {}".format(form)) + raise ValueError(f"Invalid hash type: {form}") with salt.utils.files.fopen(path, "rb") as ifile: hash_obj = hash_type() @@ -182,7 +182,7 @@ class DigestCollector: """ self.__digest = hasattr(hashlib, form) and getattr(hashlib, form)() or None if self.__digest is None: - raise ValueError("Invalid hash type: {}".format(form)) + raise ValueError(f"Invalid hash type: {form}") self.__buff = buff def add(self, path): diff --git a/salt/utils/http.py b/salt/utils/http.py index 9f31082fffb..7405566b12b 100644 --- a/salt/utils/http.py +++ b/salt/utils/http.py @@ -487,10 +487,10 @@ def query( try: match_hostname(sockwrap.getpeercert(), hostname) except CertificateError as exc: - ret[ - "error" - ] = "The certificate was invalid. Error returned was: {}".format( - pprint.pformat(exc) + ret["error"] = ( + "The certificate was invalid. Error returned was: {}".format( + pprint.pformat(exc) + ) ) return ret @@ -727,10 +727,10 @@ def query( valid_decodes = ("json", "xml", "yaml", "plain") if decode_type not in valid_decodes: - ret[ - "error" - ] = "Invalid decode_type specified. Valid decode types are: {}".format( - pprint.pformat(valid_decodes) + ret["error"] = ( + "Invalid decode_type specified. Valid decode types are: {}".format( + pprint.pformat(valid_decodes) + ) ) log.error(ret["error"]) return ret diff --git a/salt/utils/idem.py b/salt/utils/idem.py index 5c14cf7c47a..d488ed22f7e 100644 --- a/salt/utils/idem.py +++ b/salt/utils/idem.py @@ -6,6 +6,7 @@ This util provides access to an idem-ready hub .. versionadded:: 3002 """ + import logging try: diff --git a/salt/utils/immutabletypes.py b/salt/utils/immutabletypes.py index 183dc3606ef..fde42753801 100644 --- a/salt/utils/immutabletypes.py +++ b/salt/utils/immutabletypes.py @@ -30,7 +30,7 @@ class ImmutableDict(Mapping): return freeze(self.__obj[key]) def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, repr(self.__obj)) + return f"<{self.__class__.__name__} {repr(self.__obj)}>" def __deepcopy__(self, memo): return copy.deepcopy(self.__obj) @@ -66,7 +66,7 @@ class ImmutableList(Sequence): return freeze(self.__obj[key]) def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, repr(self.__obj)) + return f"<{self.__class__.__name__} {repr(self.__obj)}>" def __deepcopy__(self, memo): return copy.deepcopy(self.__obj) @@ -96,7 +96,7 @@ class ImmutableSet(Set): return key in self.__obj def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, repr(self.__obj)) + return f"<{self.__class__.__name__} {repr(self.__obj)}>" def __deepcopy__(self, memo): return copy.deepcopy(self.__obj) diff --git a/salt/utils/itertools.py b/salt/utils/itertools.py index a1f55cb026a..3e0635e15c7 100644 --- a/salt/utils/itertools.py +++ b/salt/utils/itertools.py @@ -2,7 +2,6 @@ Helpful generators and other tools """ - import fnmatch import re diff --git a/salt/utils/jid.py b/salt/utils/jid.py index c3dbf8a078a..69d926469b9 100644 --- a/salt/utils/jid.py +++ b/salt/utils/jid.py @@ -27,11 +27,11 @@ def gen_jid(opts): jid_dt = _utc_now() if not opts.get("unique_jid", False): - return "{:%Y%m%d%H%M%S%f}".format(jid_dt) + return f"{jid_dt:%Y%m%d%H%M%S%f}" if LAST_JID_DATETIME and LAST_JID_DATETIME >= jid_dt: jid_dt = LAST_JID_DATETIME + datetime.timedelta(microseconds=1) LAST_JID_DATETIME = jid_dt - return "{:%Y%m%d%H%M%S%f}_{}".format(jid_dt, os.getpid()) + return f"{jid_dt:%Y%m%d%H%M%S%f}_{os.getpid()}" def is_jid(jid): diff --git a/salt/utils/job.py b/salt/utils/job.py index 1172fa7c32d..5b52449666f 100644 --- a/salt/utils/job.py +++ b/salt/utils/job.py @@ -2,7 +2,6 @@ Functions for interacting with the job cache """ - import logging import salt.minion diff --git a/salt/utils/json.py b/salt/utils/json.py index 33cdbf401df..5e14872309f 100644 --- a/salt/utils/json.py +++ b/salt/utils/json.py @@ -2,7 +2,6 @@ Functions to work with JSON """ - import json import logging diff --git a/salt/utils/kickstart.py b/salt/utils/kickstart.py index 6674999a4e9..6869d2b5ba9 100644 --- a/salt/utils/kickstart.py +++ b/salt/utils/kickstart.py @@ -64,7 +64,7 @@ def parse_auth(rule): "disablewins", ) for arg in noargs: - parser.add_argument("--{}".format(arg), dest=arg, action="store_true") + parser.add_argument(f"--{arg}", dest=arg, action="store_true") parser.add_argument("--enablenis", dest="enablenis", action="store") parser.add_argument("--hesiodrhs", dest="hesiodrhs", action="store") diff --git a/salt/utils/lazy.py b/salt/utils/lazy.py index cdc963aa801..87b356eac9a 100644 --- a/salt/utils/lazy.py +++ b/salt/utils/lazy.py @@ -2,7 +2,6 @@ Lazily-evaluated data structures, primarily used by Salt's loader """ - import logging from collections.abc import MutableMapping @@ -78,7 +77,7 @@ class LazyDict(MutableMapping): Override this to return a more meaningfull error message if possible """ - return "'{}' is not available.".format(function_name) + return f"'{function_name}' is not available." def __setitem__(self, key, val): self._dict[key] = val diff --git a/salt/utils/locales.py b/salt/utils/locales.py index 43c0f1c68d7..cd42a8c9e8a 100644 --- a/salt/utils/locales.py +++ b/salt/utils/locales.py @@ -1,6 +1,7 @@ """ the locale utils used by salt """ + import sys from salt.utils.decorators import memoize as real_memoize diff --git a/salt/utils/mac_utils.py b/salt/utils/mac_utils.py index dbfc9f05f82..1614d2189b3 100644 --- a/salt/utils/mac_utils.py +++ b/salt/utils/mac_utils.py @@ -154,7 +154,7 @@ def execute_return_success(cmd): log.debug("Execute return success %s: %r", cmd, ret) if ret["retcode"] != 0 or "not supported" in ret["stdout"].lower(): - msg = "Command Failed: {}\n".format(cmd) + msg = f"Command Failed: {cmd}\n" msg += "Return Code: {}\n".format(ret["retcode"]) msg += "Output: {}\n".format(ret["stdout"]) msg += "Error: {}\n".format(ret["stderr"]) @@ -178,7 +178,7 @@ def execute_return_result(cmd): ret = _run_all(cmd) if ret["retcode"] != 0 or "not supported" in ret["stdout"].lower(): - msg = "Command Failed: {}\n".format(cmd) + msg = f"Command Failed: {cmd}\n" msg += "Return Code: {}\n".format(ret["retcode"]) msg += "Output: {}\n".format(ret["stdout"]) msg += "Error: {}\n".format(ret["stderr"]) @@ -313,7 +313,7 @@ def launchctl(sub_cmd, *args, **kwargs): # Raise an error or return successful result if ret["retcode"] or error: - out = "Failed to {} service:\n".format(sub_cmd) + out = f"Failed to {sub_cmd} service:\n" out += "stdout: {}\n".format(ret["stdout"]) out += "stderr: {}\n".format(ret["stderr"]) out += "retcode: {}".format(ret["retcode"]) diff --git a/salt/utils/master.py b/salt/utils/master.py index 031b151caef..6aa661c0607 100644 --- a/salt/utils/master.py +++ b/salt/utils/master.py @@ -5,6 +5,7 @@ Utilities that can only be used on a salt master. """ + import logging import os import signal @@ -108,7 +109,7 @@ def _check_cmdline(data): return False if not os.path.isdir("/proc"): return True - path = os.path.join("/proc/{}/cmdline".format(pid)) + path = os.path.join(f"/proc/{pid}/cmdline") if not os.path.isfile(path): return False try: @@ -160,7 +161,7 @@ class MasterPillarUtil: if opts is None: log.error("%s: Missing master opts init arg.", self.__class__.__name__) raise SaltException( - "{}: Missing master opts init arg.".format(self.__class__.__name__) + f"{self.__class__.__name__}: Missing master opts init arg." ) else: self.opts = opts @@ -201,7 +202,7 @@ class MasterPillarUtil: for minion_id in minion_ids: if not salt.utils.verify.valid_id(self.opts, minion_id): continue - mdata = self.cache.fetch("minions/{}".format(minion_id), "mine") + mdata = self.cache.fetch(f"minions/{minion_id}", "mine") if isinstance(mdata, dict): mine_data[minion_id] = mdata return mine_data @@ -219,7 +220,7 @@ class MasterPillarUtil: for minion_id in minion_ids: if not salt.utils.verify.valid_id(self.opts, minion_id): continue - mdata = self.cache.fetch("minions/{}".format(minion_id), "data") + mdata = self.cache.fetch(f"minions/{minion_id}", "data") if not isinstance(mdata, dict): log.warning( "cache.fetch should always return a dict. ReturnedType: %s," @@ -488,7 +489,7 @@ class MasterPillarUtil: if clear_mine: clear_what.append("mine") if clear_mine_func is not None: - clear_what.append("mine_func: '{}'".format(clear_mine_func)) + clear_what.append(f"mine_func: '{clear_mine_func}'") if not clear_what: log.debug("No cached data types specified for clearing.") return False @@ -514,7 +515,7 @@ class MasterPillarUtil: if minion_id not in c_minions: # Cache bank for this minion does not exist. Nothing to do. continue - bank = "minions/{}".format(minion_id) + bank = f"minions/{minion_id}" minion_pillar = pillars.pop(minion_id, False) minion_grains = grains.pop(minion_id, False) if ( @@ -822,7 +823,7 @@ def get_master_key(key_user, opts, skip_perm_errors=False): # The username may contain '\' if it is in Windows # 'DOMAIN\username' format. Fix this for the keyfile path. key_user = key_user.replace("\\", "_") - keyfile = os.path.join(opts["cachedir"], ".{}_key".format(key_user)) + keyfile = os.path.join(opts["cachedir"], f".{key_user}_key") # Make sure all key parent directories are accessible salt.utils.verify.check_path_traversal(opts["cachedir"], key_user, skip_perm_errors) diff --git a/salt/utils/mattermost.py b/salt/utils/mattermost.py index b8b49c32e75..17c2d6b8ffe 100644 --- a/salt/utils/mattermost.py +++ b/salt/utils/mattermost.py @@ -39,7 +39,7 @@ def query(hook=None, api_url=None, data=None): result = salt.utils.http.query(url, method, data=data, decode=True, status=True) if result.get("status", None) == http.client.OK: - ret["message"] = "Message posted {} correctly".format(data) + ret["message"] = f"Message posted {data} correctly" return ret elif result.get("status", None) == http.client.NO_CONTENT: return True diff --git a/salt/utils/memcached.py b/salt/utils/memcached.py index 3bb1fa94000..881f923979a 100644 --- a/salt/utils/memcached.py +++ b/salt/utils/memcached.py @@ -34,7 +34,6 @@ specified, rather than top-level configurations. This being the case, it is better to always use a named configuration profile, as shown above. """ - import logging from salt.exceptions import CommandExecutionError, SaltInvocationError @@ -92,7 +91,7 @@ def get_conn(opts, profile=None, host=None, port=None): raise SaltInvocationError("port must be an integer") if HAS_LIBS: - return memcache.Client(["{}:{}".format(host, port)]) + return memcache.Client([f"{host}:{port}"]) else: raise CommandExecutionError( "(unable to import memcache, module most likely not installed)" diff --git a/salt/utils/mine.py b/salt/utils/mine.py index 4f6416e554f..04795b0f8a3 100644 --- a/salt/utils/mine.py +++ b/salt/utils/mine.py @@ -2,7 +2,6 @@ This module contains routines used for the salt mine """ - import logging import salt.utils.data diff --git a/salt/utils/minion.py b/salt/utils/minion.py index 28e63af1df3..39bae1a2302 100644 --- a/salt/utils/minion.py +++ b/salt/utils/minion.py @@ -2,7 +2,6 @@ Utility functions for minions """ - import logging import os import threading @@ -132,7 +131,7 @@ def _check_cmdline(data): return False if not os.path.isdir("/proc"): return True - path = os.path.join("/proc/{}/cmdline".format(pid)) + path = os.path.join(f"/proc/{pid}/cmdline") if not os.path.isfile(path): return False try: diff --git a/salt/utils/minions.py b/salt/utils/minions.py index f3d791f4d31..65d6fd5b8d9 100644 --- a/salt/utils/minions.py +++ b/salt/utils/minions.py @@ -3,7 +3,6 @@ This module contains routines used to verify the matcher against the minions expected to return """ - import fnmatch import logging import os diff --git a/salt/utils/mount.py b/salt/utils/mount.py index 019cac5562b..c09791e668e 100644 --- a/salt/utils/mount.py +++ b/salt/utils/mount.py @@ -2,7 +2,6 @@ Common functions for managing mounts """ - import logging import os diff --git a/salt/utils/msgpack.py b/salt/utils/msgpack.py index 9c1baedbf12..034ce5dd366 100644 --- a/salt/utils/msgpack.py +++ b/salt/utils/msgpack.py @@ -1,6 +1,7 @@ """ Functions to work with MessagePack """ + import logging log = logging.getLogger(__name__) diff --git a/salt/utils/namecheap.py b/salt/utils/namecheap.py index 343ecfb62b6..c09a04b6ac6 100644 --- a/salt/utils/namecheap.py +++ b/salt/utils/namecheap.py @@ -15,7 +15,6 @@ """ - import logging import xml.dom.minidom diff --git a/salt/utils/napalm.py b/salt/utils/napalm.py index 082be2167c9..6d3ef580eed 100644 --- a/salt/utils/napalm.py +++ b/salt/utils/napalm.py @@ -14,7 +14,6 @@ Utils for the NAPALM modules and proxy. .. versionadded:: 2017.7.0 """ - import copy import importlib import logging @@ -95,7 +94,7 @@ def virtual(opts, virtualname, filename): False, '"{vname}"" {filename} cannot be loaded: ' "NAPALM is not installed: ``pip install napalm``".format( - vname=virtualname, filename="({filename})".format(filename=filename) + vname=virtualname, filename=f"({filename})" ), ) diff --git a/salt/utils/nb_popen.py b/salt/utils/nb_popen.py index 12cdc39e1b0..e878c730396 100644 --- a/salt/utils/nb_popen.py +++ b/salt/utils/nb_popen.py @@ -147,8 +147,8 @@ class NonBlockingPopen(subprocess.Popen): return self._close(which) raise - getattr(self, "{}_buff".format(which)).write(read) - getattr(self, "_{}_logger".format(which)).debug(read.rstrip()) + getattr(self, f"{which}_buff").write(read) + getattr(self, f"_{which}_logger").debug(read.rstrip()) if self.stream_stds: getattr(sys, which).write(read) @@ -195,8 +195,8 @@ class NonBlockingPopen(subprocess.Popen): if self.universal_newlines: buff = self._translate_newlines(buff) - getattr(self, "{}_buff".format(which)).write(buff) - getattr(self, "_{}_logger".format(which)).debug(buff.rstrip()) + getattr(self, f"{which}_buff").write(buff) + getattr(self, f"_{which}_logger").debug(buff.rstrip()) if self.stream_stds: getattr(sys, which).write(buff) diff --git a/salt/utils/network.py b/salt/utils/network.py index fae91e01ecb..ed274a34eea 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -2180,9 +2180,7 @@ def dns_check(addr, port, safe=False, ipv6=None): family = ( socket.AF_INET6 if ipv6 - else socket.AF_INET - if ipv6 is False - else socket.AF_UNSPEC + else socket.AF_INET if ipv6 is False else socket.AF_UNSPEC ) socket_error = False try: diff --git a/salt/utils/nxos.py b/salt/utils/nxos.py index 2572a762670..5615e9216b6 100644 --- a/salt/utils/nxos.py +++ b/salt/utils/nxos.py @@ -83,7 +83,7 @@ class NxapiClient: if self.nxargs["connect_over_uds"]: if not os.path.exists(self.NXAPI_UDS): raise NxosClientError( - "No host specified and no UDS found at {}\n".format(self.NXAPI_UDS) + f"No host specified and no UDS found at {self.NXAPI_UDS}\n" ) # Create UHTTPConnection object for NX-API communication over UDS. @@ -190,7 +190,7 @@ class NxapiClient: header_dict=req["headers"], decode=True, decode_type="json", - **self.nxargs + **self.nxargs, ) return self.parse_response(response, command_list) @@ -202,9 +202,9 @@ class NxapiClient: # Check for 500 level NX-API Server Errors if isinstance(response, Iterable) and "status" in response: if int(response["status"]) >= 500: - raise NxosError("{}".format(response)) + raise NxosError(f"{response}") else: - raise NxosError("NX-API Request Not Supported: {}".format(response)) + raise NxosError(f"NX-API Request Not Supported: {response}") if isinstance(response, Iterable): body = response["dict"] @@ -218,7 +218,7 @@ class NxapiClient: # Don't just return body['ins_api']['outputs']['output'] directly. output = body.get("ins_api") if output is None: - raise NxosClientError("Unexpected JSON output\n{}".format(body)) + raise NxosClientError(f"Unexpected JSON output\n{body}") if output.get("outputs"): output = output["outputs"] if output.get("output"): @@ -257,9 +257,9 @@ class NxapiClient: } ) elif code == "413": - raise NxosRequestNotSupported("Error 413: {}".format(msg)) + raise NxosRequestNotSupported(f"Error 413: {msg}") elif code != "200": - raise NxosError("Unknown Error: {}, Code: {}".format(msg, code)) + raise NxosError(f"Unknown Error: {msg}, Code: {code}") else: previous_commands.append(cmd) result.append(cmd_result["body"]) @@ -321,7 +321,7 @@ def ping(**kwargs): def _parser(block): - return re.compile("^{block}\n(?:^[ \n].*$\n?)+".format(block=block), re.MULTILINE) + return re.compile(f"^{block}\n(?:^[ \n].*$\n?)+", re.MULTILINE) def _parse_software(data): diff --git a/salt/utils/openstack/neutron.py b/salt/utils/openstack/neutron.py index 8cf675e453c..c6707b18bfe 100644 --- a/salt/utils/openstack/neutron.py +++ b/salt/utils/openstack/neutron.py @@ -2,7 +2,6 @@ Neutron class """ - import logging import salt.utils.versions @@ -89,7 +88,6 @@ class SaltNeutron(NeutronShell): use_keystoneauth=False, **kwargs ): - """ Set up neutron credentials """ diff --git a/salt/utils/openstack/nova.py b/salt/utils/openstack/nova.py index 4c3855edb31..9b8a15264b8 100644 --- a/salt/utils/openstack/nova.py +++ b/salt/utils/openstack/nova.py @@ -2,7 +2,6 @@ Nova class """ - import inspect import logging import time @@ -205,7 +204,7 @@ def get_entry(dict_, key, value, raise_error=True): if entry[key] == value: return entry if raise_error is True: - raise SaltCloudSystemExit("Unable to find {} in {}.".format(key, dict_)) + raise SaltCloudSystemExit(f"Unable to find {key} in {dict_}.") return {} @@ -214,7 +213,7 @@ def get_entry_multi(dict_, pairs, raise_error=True): if all([entry[key] == value for key, value in pairs]): return entry if raise_error is True: - raise SaltCloudSystemExit("Unable to find {} in {}.".format(pairs, dict_)) + raise SaltCloudSystemExit(f"Unable to find {pairs} in {dict_}.") return {} @@ -282,7 +281,7 @@ class SaltNova: password=None, os_auth_plugin=None, use_keystoneauth=False, - **kwargs + **kwargs, ): """ Set up nova credentials @@ -295,7 +294,7 @@ class SaltNova: region_name=region_name, password=password, os_auth_plugin=os_auth_plugin, - **kwargs + **kwargs, ) else: self._old_init( @@ -305,7 +304,7 @@ class SaltNova: region_name=region_name, password=password, os_auth_plugin=os_auth_plugin, - **kwargs + **kwargs, ) def _new_init( @@ -318,7 +317,7 @@ class SaltNova: os_auth_plugin, auth=None, verify=True, - **kwargs + **kwargs, ): if auth is None: auth = {} @@ -387,7 +386,7 @@ class SaltNova: region_name, password, os_auth_plugin, - **kwargs + **kwargs, ): self.kwargs = kwargs.copy() if not self.extensions: @@ -675,7 +674,7 @@ class SaltNova: try: volume = self.volume_show(name) except KeyError as exc: - raise SaltCloudSystemExit("Unable to find {} volume: {}".format(name, exc)) + raise SaltCloudSystemExit(f"Unable to find {name} volume: {exc}") if volume["status"] == "deleted": return volume response = nt_ks.volumes.delete(volume["id"]) @@ -688,7 +687,7 @@ class SaltNova: try: volume = self.volume_show(name) except KeyError as exc: - raise SaltCloudSystemExit("Unable to find {} volume: {}".format(name, exc)) + raise SaltCloudSystemExit(f"Unable to find {name} volume: {exc}") if not volume["attachments"]: return True response = self.compute_conn.volumes.delete_server_volume( @@ -720,7 +719,7 @@ class SaltNova: try: volume = self.volume_show(name) except KeyError as exc: - raise SaltCloudSystemExit("Unable to find {} volume: {}".format(name, exc)) + raise SaltCloudSystemExit(f"Unable to find {name} volume: {exc}") server = self.server_by_name(server_name) response = self.compute_conn.volumes.create_server_volume( server.id, volume["id"], device=device @@ -824,7 +823,7 @@ class SaltNova: """ nt_ks = self.compute_conn nt_ks.flavors.delete(flavor_id) - return "Flavor deleted: {}".format(flavor_id) + return f"Flavor deleted: {flavor_id}" def keypair_list(self): """ @@ -860,7 +859,7 @@ class SaltNova: """ nt_ks = self.compute_conn nt_ks.keypairs.delete(name) - return "Keypair deleted: {}".format(name) + return f"Keypair deleted: {name}" def image_show(self, image_id): """ @@ -949,7 +948,7 @@ class SaltNova: if not image_id: return {"Error": "A valid image name or id was not specified"} nt_ks.images.delete_meta(image_id, pairs) - return {image_id: "Deleted: {}".format(pairs)} + return {image_id: f"Deleted: {pairs}"} def server_list(self): """ @@ -1033,9 +1032,9 @@ class SaltNova: "OS-EXT-SRV-ATTR:host" ] if hasattr(item.__dict__, "OS-EXT-SRV-ATTR:hypervisor_hostname"): - ret[item.name]["OS-EXT-SRV-ATTR"][ - "hypervisor_hostname" - ] = item.__dict__["OS-EXT-SRV-ATTR:hypervisor_hostname"] + ret[item.name]["OS-EXT-SRV-ATTR"]["hypervisor_hostname"] = ( + item.__dict__["OS-EXT-SRV-ATTR:hypervisor_hostname"] + ) if hasattr(item.__dict__, "OS-EXT-SRV-ATTR:instance_name"): ret[item.name]["OS-EXT-SRV-ATTR"]["instance_name"] = item.__dict__[ "OS-EXT-SRV-ATTR:instance_name" @@ -1089,8 +1088,8 @@ class SaltNova: for item in nt_ks.security_groups.list(): if item.name == name: nt_ks.security_groups.delete(item.id) - return {name: "Deleted security group: {}".format(name)} - return "Security group not found: {}".format(name) + return {name: f"Deleted security group: {name}"} + return f"Security group not found: {name}" def secgroup_list(self): """ diff --git a/salt/utils/oset.py b/salt/utils/oset.py index d0bd6536e82..fb1db32b4e9 100644 --- a/salt/utils/oset.py +++ b/salt/utils/oset.py @@ -85,9 +85,7 @@ class OrderedSet(MutableSet): elif is_iterable(index): return OrderedSet([self.items[i] for i in index]) else: - raise TypeError( - "Don't know how to index an OrderedSet by {}".format(repr(index)) - ) + raise TypeError(f"Don't know how to index an OrderedSet by {repr(index)}") def copy(self): return OrderedSet(self) @@ -137,9 +135,7 @@ class OrderedSet(MutableSet): for item in sequence: item_index = self.add(item) except TypeError: - raise ValueError( - "Argument needs to be an iterable, got {}".format(type(sequence)) - ) + raise ValueError(f"Argument needs to be an iterable, got {type(sequence)}") return item_index def index(self, key): @@ -198,8 +194,8 @@ class OrderedSet(MutableSet): def __repr__(self): if not self: - return "{}()".format(self.__class__.__name__) - return "{}({})".format(self.__class__.__name__, repr(list(self))) + return f"{self.__class__.__name__}()" + return f"{self.__class__.__name__}({repr(list(self))})" def __eq__(self, other): if isinstance(other, OrderedSet): diff --git a/salt/utils/pagerduty.py b/salt/utils/pagerduty.py index 44c039a9f6b..62c663196e5 100644 --- a/salt/utils/pagerduty.py +++ b/salt/utils/pagerduty.py @@ -44,7 +44,7 @@ def query( """ Query the PagerDuty API """ - user_agent = "SaltStack {}".format(__version__) + user_agent = f"SaltStack {__version__}" if opts is None: opts = {} diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py index 013c5e8ff74..df044de4241 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py @@ -7,6 +7,7 @@ This is where all the black magic happens on all of salt's CLI tools. """ + # pylint: disable=missing-docstring,protected-access,too-many-ancestors,too-few-public-methods # pylint: disable=attribute-defined-outside-init,no-self-use diff --git a/salt/utils/path.py b/salt/utils/path.py index cf3e4cf50bf..e940321446a 100644 --- a/salt/utils/path.py +++ b/salt/utils/path.py @@ -3,7 +3,6 @@ Platform independent versions of some os/os.path functions. Gets around PY2's lack of support for reading NTFS links. """ - import logging import os import posixpath diff --git a/salt/utils/pbm.py b/salt/utils/pbm.py index c8eceaeedb3..420d69912ab 100644 --- a/salt/utils/pbm.py +++ b/salt/utils/pbm.py @@ -37,7 +37,6 @@ version currently listed in PyPi, run the following: pip install pyVmomi==5.5.0.2014.1.1 """ - import logging import salt.utils.vmware @@ -89,7 +88,7 @@ def get_profile_manager(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -116,7 +115,7 @@ def get_placement_solver(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -142,7 +141,7 @@ def get_capability_definitions(profile_manager): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -171,7 +170,7 @@ def get_policies_by_id(profile_manager, policy_ids): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -204,7 +203,7 @@ def get_storage_policies(profile_manager, policy_names=None, get_all_policies=Fa except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -241,7 +240,7 @@ def create_storage_policy(profile_manager, policy_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -269,7 +268,7 @@ def update_storage_policy(profile_manager, policy, policy_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -297,7 +296,7 @@ def get_default_storage_policy_of_datastore(profile_manager, datastore): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -308,7 +307,7 @@ def get_default_storage_policy_of_datastore(profile_manager, datastore): policy_refs = get_policies_by_id(profile_manager, [policy_id]) if not policy_refs: raise VMwareObjectRetrievalError( - "Storage policy with id '{}' was not found".format(policy_id) + f"Storage policy with id '{policy_id}' was not found" ) return policy_refs[0] @@ -337,7 +336,7 @@ def assign_default_storage_policy_to_datastore(profile_manager, policy, datastor except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py index f9975f8dff1..7574a068e83 100644 --- a/salt/utils/pkg/rpm.py +++ b/salt/utils/pkg/rpm.py @@ -1,6 +1,7 @@ """ Common functions for working with RPM packages """ + import collections import datetime import logging @@ -105,7 +106,7 @@ def resolve_name(name, arch, osarch=None): osarch = get_osarch() if not check_32(arch, osarch) and arch not in (osarch, "noarch"): - name += ".{}".format(arch) + name += f".{arch}" return name @@ -123,7 +124,7 @@ def parse_pkginfo(line, osarch=None): name = resolve_name(name, arch, osarch) if release: - version += "-{}".format(release) + version += f"-{release}" if epoch not in ("(none)", "0"): version = ":".join((epoch, version)) diff --git a/salt/utils/pkg/win.py b/salt/utils/pkg/win.py index c34fa2c26b3..fa013196420 100644 --- a/salt/utils/pkg/win.py +++ b/salt/utils/pkg/win.py @@ -10,6 +10,7 @@ Collect information about software installed on Windows OS Known Issue: install_date may not match Control Panel\Programs\Programs and Features """ + import collections import datetime import locale @@ -143,7 +144,7 @@ class RegSoftwareInfo: ) ) self.__reg_upgradecode_path = ( - "{}\\Software\\Microsoft\\Installer\\UpgradeCodes".format(sid) + f"{sid}\\Software\\Microsoft\\Installer\\UpgradeCodes" ) self.__reg_patches_path = ( "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" @@ -160,7 +161,7 @@ class RegSoftwareInfo: ) if self.__squid: self.__reg_products_path = ( - "Software\\Classes\\Installer\\Products\\{}".format(self.__squid) + f"Software\\Classes\\Installer\\Products\\{self.__squid}" ) self.__reg_upgradecode_path = ( "Software\\Classes\\Installer\\UpgradeCodes" @@ -603,7 +604,7 @@ class RegSoftwareInfo: Returns: str: \\ """ - return "{}\\{}".format(self.__reg_hive, self.__reg_uninstall_path) + return f"{self.__reg_hive}\\{self.__reg_uninstall_path}" @property def registry_path(self): @@ -929,7 +930,7 @@ class WinSoftware: name, domain, _account_type = win32security.LookupAccountSid( None, sid_bin ) # pylint: disable=no-member - user_name = "{}\\{}".format(domain, name) + user_name = f"{domain}\\{name}" except pywintypes.error as exc: # pylint: disable=no-member # if user does not exist... # winerror.ERROR_NONE_MAPPED = No mapping between account names and @@ -961,7 +962,7 @@ class WinSoftware: winerror.ERROR_INVALID_DOMAINNAME, winerror.ERROR_NONE_MAPPED, ): - return "{}@{}".format(name.lower(), domain.lower()) + return f"{name.lower()}@{domain.lower()}" else: raise return user_principal @@ -1441,9 +1442,7 @@ def __main(): system|system+user: System installed and System and User installs. """ if len(sys.argv) < 3: - sys.stderr.write( - "usage: {} \n".format(sys.argv[0]) - ) + sys.stderr.write(f"usage: {sys.argv[0]} \n") sys.exit(64) user_pkgs = False version_only = False @@ -1463,10 +1462,10 @@ def __main(): print( salt.utils.json.dumps(pkg_list.data, sort_keys=True, indent=4) ) # pylint: disable=superfluous-parens - print("Total: {}".format(len(pkg_list))) # pylint: disable=superfluous-parens + print(f"Total: {len(pkg_list)}") # pylint: disable=superfluous-parens print( - "Time Taken: {}".format(timeit.timeit(run, number=1)) + f"Time Taken: {timeit.timeit(run, number=1)}" ) # pylint: disable=superfluous-parens diff --git a/salt/utils/platform.py b/salt/utils/platform.py index 35bb7ff3f81..c6ca7fe8cae 100644 --- a/salt/utils/platform.py +++ b/salt/utils/platform.py @@ -1,6 +1,7 @@ """ Functions for identifying which platform a machine is """ + import contextlib import multiprocessing import os diff --git a/salt/utils/powershell.py b/salt/utils/powershell.py index bcca243239a..2ac67bfa665 100644 --- a/salt/utils/powershell.py +++ b/salt/utils/powershell.py @@ -73,13 +73,13 @@ def get_modules(): system_dir = "{}\\System32".format(os.environ.get("WINDIR", "C:\\Windows")) program_files = os.environ.get("ProgramFiles", "C:\\Program Files") default_paths = [ - "{}/.local/share/powershell/Modules".format(home_dir), + f"{home_dir}/.local/share/powershell/Modules", # Once version is available, these can be enabled # '/opt/microsoft/powershell/{0}/Modules'.format(ps_version), # '/usr/local/microsoft/powershell/{0}/Modules'.format(ps_version), "/usr/local/share/powershell/Modules", - "{}\\WindowsPowerShell\\v1.0\\Modules\\".format(system_dir), - "{}\\WindowsPowerShell\\Modules".format(program_files), + f"{system_dir}\\WindowsPowerShell\\v1.0\\Modules\\", + f"{program_files}\\WindowsPowerShell\\Modules", ] default_paths = ";".join(default_paths) diff --git a/salt/utils/process.py b/salt/utils/process.py index e1ee5ff83df..52dd19f8479 100644 --- a/salt/utils/process.py +++ b/salt/utils/process.py @@ -1,6 +1,7 @@ """ Functions for daemonizing and otherwise modifying running processes """ + import contextlib import copy import errno @@ -55,7 +56,7 @@ def appendproctitle(name): current = setproctitle.getproctitle() if current.strip().endswith("MainProcess"): current, _ = current.rsplit("MainProcess", 1) - setproctitle.setproctitle("{} {}".format(current.rstrip(), name)) + setproctitle.setproctitle(f"{current.rstrip()} {name}") def daemonize(redirect_out=True): @@ -173,7 +174,7 @@ def notify_systemd(): if notify_socket: # Handle abstract namespace socket if notify_socket.startswith("@"): - notify_socket = "\0{}".format(notify_socket[1:]) + notify_socket = f"\0{notify_socket[1:]}" try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) sock.connect(notify_socket) @@ -351,7 +352,7 @@ def set_pidfile(pidfile, user): pidfile, user ) log.debug("%s Traceback follows:", msg, exc_info=True) - sys.stderr.write("{}\n".format(msg)) + sys.stderr.write(f"{msg}\n") sys.exit(err.errno) log.debug("Chowned pidfile: %s to user: %s", pidfile, user) @@ -921,9 +922,9 @@ class Process(multiprocessing.Process): self.__init__(*args, **kwargs) # Override self.__logging_config__ with what's in state self.__logging_config__ = logging_config - for (function, args, kwargs) in state["after_fork_methods"]: + for function, args, kwargs in state["after_fork_methods"]: self.register_after_fork_method(function, *args, **kwargs) - for (function, args, kwargs) in state["finalize_methods"]: + for function, args, kwargs in state["finalize_methods"]: self.register_finalize_method(function, *args, **kwargs) def __getstate__(self): @@ -1062,7 +1063,7 @@ class SignalHandlingProcess(Process): def _handle_signals(self, signum, sigframe): signal.signal(signal.SIGTERM, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN) - msg = "{} received a ".format(self.__class__.__name__) + msg = f"{self.__class__.__name__} received a " if signum == signal.SIGINT: msg += "SIGINT" elif signum == signal.SIGTERM: diff --git a/salt/utils/profile.py b/salt/utils/profile.py index 30f4276ef0c..e301cd196ef 100644 --- a/salt/utils/profile.py +++ b/salt/utils/profile.py @@ -2,7 +2,6 @@ Decorator and functions to profile Salt using cProfile """ - import datetime import logging import os @@ -35,7 +34,7 @@ def profile_func(filename=None): try: profiler = cProfile.Profile() retval = profiler.runcall(fun, *args, **kwargs) - profiler.dump_stats(filename or "{}_func.profile".format(fun.__name__)) + profiler.dump_stats(filename or f"{fun.__name__}_func.profile") except OSError: logging.exception("Could not open profile file %s", filename) @@ -66,9 +65,9 @@ def output_profile(pr, stats_path="/tmp/stats", stop=False, id_=None): date = datetime.datetime.now().isoformat() if id_ is None: id_ = salt.utils.hashutils.random_hash(size=32) - ficp = os.path.join(stats_path, "{}.{}.pstats".format(id_, date)) - fico = os.path.join(stats_path, "{}.{}.dot".format(id_, date)) - ficn = os.path.join(stats_path, "{}.{}.stats".format(id_, date)) + ficp = os.path.join(stats_path, f"{id_}.{date}.pstats") + fico = os.path.join(stats_path, f"{id_}.{date}.dot") + ficn = os.path.join(stats_path, f"{id_}.{date}.stats") if not os.path.exists(ficp): pr.dump_stats(ficp) with salt.utils.files.fopen(ficn, "w") as fic: diff --git a/salt/utils/proxy.py b/salt/utils/proxy.py index 6677134f478..b9db9251582 100644 --- a/salt/utils/proxy.py +++ b/salt/utils/proxy.py @@ -2,7 +2,6 @@ Utils for proxy. """ - import logging import salt.utils.platform diff --git a/salt/utils/psutil_compat.py b/salt/utils/psutil_compat.py index e6684e5ca46..bd6656945cd 100644 --- a/salt/utils/psutil_compat.py +++ b/salt/utils/psutil_compat.py @@ -9,7 +9,6 @@ Should be removed once support for psutil <2.0 is dropped. (eg RHEL 6) Built off of http://grodola.blogspot.com/2014/01/psutil-20-porting.html """ - # No exception handling, as we want ImportError if psutil doesn't exist import psutil # pylint: disable=3rd-party-module-not-gated diff --git a/salt/utils/pushover.py b/salt/utils/pushover.py index bf733a9d064..2917ef4fc28 100644 --- a/salt/utils/pushover.py +++ b/salt/utils/pushover.py @@ -106,10 +106,10 @@ def validate_sound(sound, token): if _message.get("dict", {}).get("status", "") == 1: sounds = _message.get("dict", {}).get("sounds", "") if sound in sounds: - ret["message"] = "Valid sound {}.".format(sound) + ret["message"] = f"Valid sound {sound}." ret["res"] = True else: - ret["message"] = "Warning: {} not a valid sound.".format(sound) + ret["message"] = f"Warning: {sound} not a valid sound." ret["res"] = False else: ret["message"] = "".join(_message.get("dict", {}).get("errors")) diff --git a/salt/utils/pycrypto.py b/salt/utils/pycrypto.py index a0f3874035e..e50ac323eb7 100644 --- a/salt/utils/pycrypto.py +++ b/salt/utils/pycrypto.py @@ -1,6 +1,7 @@ """ Use pycrypto to generate random passwords on the fly. """ + import logging import random import re @@ -87,7 +88,7 @@ def secure_password( continue pw += re.sub( salt.utils.stringutils.to_str( - r"[^{}]".format(re.escape(chars)), encoding=encoding + rf"[^{re.escape(chars)}]", encoding=encoding ), "", char, @@ -140,7 +141,7 @@ def _gen_hash_crypt(crypt_salt=None, password=None, algorithm=None): else: if algorithm != "crypt": # all non-crypt algorithms are specified as part of the salt - crypt_salt = "${}${}".format(methods[algorithm].ident, crypt_salt) + crypt_salt = f"${methods[algorithm].ident}${crypt_salt}" try: ret = crypt.crypt(password, crypt_salt) diff --git a/salt/utils/pydsl.py b/salt/utils/pydsl.py index 385a24d6a05..4a6f71a4fdb 100644 --- a/salt/utils/pydsl.py +++ b/salt/utils/pydsl.py @@ -153,7 +153,7 @@ class Sls: highstate = self.included_highstate slsmods = [] # a list of pydsl sls modules rendered. for sls in sls_names: - r_env = "{}:{}".format(saltenv, sls) + r_env = f"{saltenv}:{sls}" if r_env not in self.rendered_sls: self.rendered_sls.add( sls @@ -166,7 +166,7 @@ class Sls: raise PyDslError("\n".join(errors)) HIGHSTATE.clean_duplicate_extends(highstate) - state_id = "_slsmod_{}".format(sls) + state_id = f"_slsmod_{sls}" if state_id not in highstate: slsmods.append(None) else: @@ -194,7 +194,7 @@ class Sls: def state(self, id=None): if not id: - id = ".{}".format(_uuid()) + id = f".{_uuid()}" # adds a leading dot to make use of stateconf's namespace feature. try: return self.get_all_decls()[id] @@ -408,7 +408,7 @@ class StateFunction: def _repr(self, context=None): if not self.name and context != "extend": raise PyDslError( - "No state function specified for module: {}".format(self.mod._name) + f"No state function specified for module: {self.mod._name}" ) if not self.name and context == "extend": return self.args @@ -440,9 +440,7 @@ class StateFunction: if isinstance(mod, StateModule): ref = mod._state_id elif not (mod and ref): - raise PyDslError( - "Invalid a requisite reference declaration! {}: {}".format(mod, ref) - ) + raise PyDslError(f"Invalid a requisite reference declaration! {mod}: {ref}") self.args.append({req_type: [{str(mod): str(ref)}]}) ns = locals() diff --git a/salt/utils/pyobjects.py b/salt/utils/pyobjects.py index eec61b79148..54bbc4ac6e4 100644 --- a/salt/utils/pyobjects.py +++ b/salt/utils/pyobjects.py @@ -250,10 +250,10 @@ class State: @property def full_func(self): - return "{!s}.{!s}".format(self.module, self.func) + return f"{self.module!s}.{self.func!s}" def __str__(self): - return "{!s} = {!s}:{!s}".format(self.id_, self.full_func, self.attrs) + return f"{self.id_!s} = {self.full_func!s}:{self.attrs!s}" def __call__(self): return {self.full_func: self.attrs} @@ -283,7 +283,7 @@ class SaltObject: class __wrapper__: def __getattr__(wself, func): # pylint: disable=E0213 try: - return self._salt["{}.{}".format(mod, func)] + return self._salt[f"{mod}.{func}"] except KeyError: raise AttributeError diff --git a/salt/utils/reactor.py b/salt/utils/reactor.py index 19420a51cf0..2cbcd3a1ab5 100644 --- a/salt/utils/reactor.py +++ b/salt/utils/reactor.py @@ -1,6 +1,7 @@ """ Functions which implement running reactor jobs """ + import fnmatch import glob import logging diff --git a/salt/utils/roster_matcher.py b/salt/utils/roster_matcher.py index db5dfda3e03..c424c63bb0e 100644 --- a/salt/utils/roster_matcher.py +++ b/salt/utils/roster_matcher.py @@ -55,7 +55,7 @@ class RosterMatcher: Execute the correct tgt_type routine and return """ try: - return getattr(self, "ret_{}_minions".format(self.tgt_type))() + return getattr(self, f"ret_{self.tgt_type}_minions")() except AttributeError: return {} diff --git a/salt/utils/s3.py b/salt/utils/s3.py index ba46c5ee7cc..51586cb18e3 100644 --- a/salt/utils/s3.py +++ b/salt/utils/s3.py @@ -111,10 +111,10 @@ def query( if not bucket or path_style: endpoint = service_url else: - endpoint = "{}.{}".format(bucket, service_url) + endpoint = f"{bucket}.{service_url}" if path_style and bucket: - path = "{}/{}".format(bucket, path) + path = f"{bucket}/{path}" # Try grabbing the credentials from the EC2 instance IAM metadata if available if not key: @@ -150,7 +150,7 @@ def query( endpoint, params, data=data, - uri="/{}".format(path), + uri=f"/{path}", prov_dict={"id": keyid, "key": key}, role_arn=role_arn, location=location, @@ -222,7 +222,7 @@ def query( log.debug( "Failed to parse s3 err response. %s: %s", type(err).__name__, err ) - err_code = "http-{}".format(result.status_code) + err_code = f"http-{result.status_code}" err_msg = err_text log.debug("S3 Response Status Code: %s", result.status_code) @@ -236,7 +236,7 @@ def query( ) ) raise CommandExecutionError( - "Failed to create bucket {}. {}: {}".format(bucket, err_code, err_msg) + f"Failed to create bucket {bucket}. {err_code}: {err_msg}" ) if local_file: @@ -254,7 +254,7 @@ def query( ) ) raise CommandExecutionError( - "Failed to delete bucket {}. {}: {}".format(bucket, err_code, err_msg) + f"Failed to delete bucket {bucket}. {err_code}: {err_msg}" ) if path: @@ -266,20 +266,16 @@ def query( # This can be used to save a binary object to disk if local_file and method == "GET": if result.status_code < 200 or result.status_code >= 300: - raise CommandExecutionError( - "Failed to get file. {}: {}".format(err_code, err_msg) - ) + raise CommandExecutionError(f"Failed to get file. {err_code}: {err_msg}") log.debug("Saving to local file: %s", local_file) with salt.utils.files.fopen(local_file, "wb") as out: for chunk in result.iter_content(chunk_size=chunk_size): out.write(chunk) - return "Saved to local file: {}".format(local_file) + return f"Saved to local file: {local_file}" if result.status_code < 200 or result.status_code >= 300: - raise CommandExecutionError( - "Failed s3 operation. {}: {}".format(err_code, err_msg) - ) + raise CommandExecutionError(f"Failed s3 operation. {err_code}: {err_msg}") # This can be used to return a binary object wholesale if return_bin: diff --git a/salt/utils/saltclass.py b/salt/utils/saltclass.py index bbd33068b06..7d6fec7c578 100644 --- a/salt/utils/saltclass.py +++ b/salt/utils/saltclass.py @@ -67,7 +67,7 @@ def get_class_paths(_class, saltclass_path): :return: 3-tuple of possible file counterparts :rtype: tuple(str) """ - straight = os.path.join(saltclass_path, "classes", "{}.yml".format(_class)) + straight = os.path.join(saltclass_path, "classes", f"{_class}.yml") sub_straight = os.path.join( saltclass_path, "classes", "{}.yml".format(_class.replace(".", os.sep)) ) @@ -138,7 +138,7 @@ def dict_merge(a, b, path=None): # Recursive search and replace in a dict def dict_search_and_replace(d, old, new, expanded): - for (k, v) in d.items(): + for k, v in d.items(): if isinstance(v, dict): dict_search_and_replace(d[k], old, new, expanded) @@ -206,7 +206,7 @@ def expand_variables(a, b, expanded, path=None): b = a.copy() path = [] - for (k, v) in a.items(): + for k, v in a.items(): if isinstance(v, dict): expand_variables(v, b, expanded, path + [str(k)]) else: @@ -365,7 +365,7 @@ def expanded_dict_from_minion(minion_id, salt_data): os.path.join(saltclass_path, "nodes"), followlinks=True ): for minion_file in files: - if minion_file == "{}.yml".format(minion_id): + if minion_file == f"{minion_id}.yml": _file = os.path.join(root, minion_file) # Load the minion_id definition if existing, else an empty dict diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 6565dda59e6..5eca89fb6ee 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -834,7 +834,7 @@ class Schedule: # this function accepts **kwargs, pack in the publish data for key, val in ret.items(): if key != "kwargs": - kwargs["__pub_{}".format(key)] = copy.deepcopy(val) + kwargs[f"__pub_{key}"] = copy.deepcopy(val) # Only include these when running runner modules if self.opts["__role"] == "master": @@ -899,7 +899,7 @@ class Schedule: rets.extend(returner) # simple de-duplication with order retained for returner in OrderedDict.fromkeys(rets): - ret_str = "{}.returner".format(returner) + ret_str = f"{returner}.returner" if ret_str in self.returners: self.returners[ret_str](ret) else: @@ -1108,10 +1108,10 @@ class Schedule: and i in self.opts["grains"]["whens"] ): if not isinstance(self.opts["grains"]["whens"], dict): - data[ - "_error" - ] = 'Grain "whens" must be a dict. Ignoring job {}.'.format( - data["name"] + data["_error"] = ( + 'Grain "whens" must be a dict. Ignoring job {}.'.format( + data["name"] + ) ) log.error(data["_error"]) return @@ -1123,10 +1123,10 @@ class Schedule: try: when_ = dateutil_parser.parse(when_) except ValueError: - data[ - "_error" - ] = "Invalid date string {}. Ignoring job {}.".format( - i, data["name"] + data["_error"] = ( + "Invalid date string {}. Ignoring job {}.".format( + i, data["name"] + ) ) log.error(data["_error"]) return @@ -1382,10 +1382,10 @@ class Schedule: try: start = dateutil_parser.parse(start) except ValueError: - data[ - "_error" - ] = "Invalid date string for start. Ignoring job {}.".format( - data["name"] + data["_error"] = ( + "Invalid date string for start. Ignoring job {}.".format( + data["name"] + ) ) log.error(data["_error"]) return @@ -1394,10 +1394,10 @@ class Schedule: try: end = dateutil_parser.parse(end) except ValueError: - data[ - "_error" - ] = "Invalid date string for end. Ignoring job {}.".format( - data["name"] + data["_error"] = ( + "Invalid date string for end. Ignoring job {}.".format( + data["name"] + ) ) log.error(data["_error"]) return @@ -1753,7 +1753,7 @@ class Schedule: miss_msg = "" if seconds < 0: - miss_msg = " (runtime missed by {} seconds)".format(abs(seconds)) + miss_msg = f" (runtime missed by {abs(seconds)} seconds)" try: if run: @@ -1883,7 +1883,6 @@ class Schedule: def clean_proc_dir(opts): - """ Loop through jid files in the minion proc directory (default /var/cache/salt/minion/proc) and remove any that refer to processes that no longer exist diff --git a/salt/utils/schema.py b/salt/utils/schema.py index 8bc73c9d068..2ac9a45f266 100644 --- a/salt/utils/schema.py +++ b/salt/utils/schema.py @@ -512,7 +512,7 @@ class Schema(metaclass=SchemaMeta): serialized = OrderedDict() if id_ is not None: # This is meant as a configuration section, sub json schema - serialized["id"] = "{}/{}.json#".format(BASE_SCHEMA_URL, id_) + serialized["id"] = f"{BASE_SCHEMA_URL}/{id_}.json#" else: # Main configuration block, json schema serialized["$schema"] = "http://json-schema.org/draft-04/schema#" @@ -687,7 +687,7 @@ class SchemaItem(metaclass=BaseSchemaItemMeta): Return the argname value looking up on all possible attributes """ # Let's see if there's a private function to get the value - argvalue = getattr(self, "__get_{}__".format(argname), None) + argvalue = getattr(self, f"__get_{argname}__", None) if argvalue is not None and callable(argvalue): argvalue = argvalue() # pylint: disable=not-callable if argvalue is None: @@ -695,7 +695,7 @@ class SchemaItem(metaclass=BaseSchemaItemMeta): argvalue = getattr(self, argname, None) if argvalue is None: # Let's see if it's defined as a private class variable - argvalue = getattr(self, "__{}__".format(argname), None) + argvalue = getattr(self, f"__{argname}__", None) if argvalue is None: # Let's look for it in the extra dictionary argvalue = self.extra.get(argname, None) @@ -737,7 +737,7 @@ class BaseSchemaItem(SchemaItem): default=None, enum=None, enumNames=None, - **kwargs + **kwargs, ): """ :param required: @@ -876,7 +876,7 @@ class StringItem(BaseSchemaItem): pattern=None, min_length=None, max_length=None, - **kwargs + **kwargs, ): """ :param required: @@ -1006,7 +1006,7 @@ class NumberItem(BaseSchemaItem): exclusive_minimum=None, maximum=None, exclusive_maximum=None, - **kwargs + **kwargs, ): """ :param required: @@ -1071,7 +1071,7 @@ class ArrayItem(BaseSchemaItem): max_items=None, unique_items=None, additional_items=None, - **kwargs + **kwargs, ): """ :param required: @@ -1169,7 +1169,7 @@ class DictItem(BaseSchemaItem): additional_properties=None, min_properties=None, max_properties=None, - **kwargs + **kwargs, ): """ :param required: @@ -1481,7 +1481,7 @@ class ComplexSchemaItem(BaseSchemaItem): The serialization of the complex item is a pointer to the item definition """ - return {"$ref": "#/definitions/{}".format(self.definition_name)} + return {"$ref": f"#/definitions/{self.definition_name}"} def get_definition(self): """Returns the definition of the complex item""" diff --git a/salt/utils/slack.py b/salt/utils/slack.py index 74b98af46d3..b4f1b5e3b7c 100644 --- a/salt/utils/slack.py +++ b/salt/utils/slack.py @@ -85,7 +85,7 @@ def query( # send the token in an HTTP POST body. # Apps created before February 24, 2021 will continue functioning no # matter which way you pass your token. - header_dict["Authorization"] = "Bearer {}".format(api_key) + header_dict["Authorization"] = f"Bearer {api_key}" result = salt.utils.http.query( url, method, diff --git a/salt/utils/smb.py b/salt/utils/smb.py index d3468078a48..de32b52b2fa 100644 --- a/salt/utils/smb.py +++ b/salt/utils/smb.py @@ -4,7 +4,6 @@ Utility functions for SMB connections :depends: impacket """ - import logging import socket import uuid @@ -73,7 +72,7 @@ class SMBProto: def tree_connect(self, share): if share.endswith("$"): - share = r"\\{}\{}".format(self.server, share) + share = rf"\\{self.server}\{share}" tree = TreeConnect(self.session, share) tree.connect() return tree @@ -87,9 +86,9 @@ class SMBProto: file = cls.normalize_filename(file) # ensure file is created, get maximal access, and set everybody read access max_req = SMB2CreateContextRequest() - max_req[ - "buffer_name" - ] = CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST + max_req["buffer_name"] = ( + CreateContextName.SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST + ) max_req["buffer_data"] = SMB2CreateQueryMaximalAccessRequest() # create security buffer that sets the ACL for everyone to have read access diff --git a/salt/utils/smtp.py b/salt/utils/smtp.py index bab7a3aa4eb..a138a03110b 100644 --- a/salt/utils/smtp.py +++ b/salt/utils/smtp.py @@ -83,10 +83,10 @@ def send(kwargs, opts): config["smtp.content"] = str(encrypted_data) else: log.error("SMTP: Encryption failed, only an error message will be sent") - config[ - "smtp.content" - ] = "Encryption failed, the return data was not sent.\r\n\r\n{}\r\n{}".format( - encrypted_data.status, encrypted_data.stderr + config["smtp.content"] = ( + "Encryption failed, the return data was not sent.\r\n\r\n{}\r\n{}".format( + encrypted_data.status, encrypted_data.stderr + ) ) message = "From: {}\r\nTo: {}\r\nDate: {}\r\nSubject: {}\r\n\r\n{}".format( diff --git a/salt/utils/ssdp.py b/salt/utils/ssdp.py index 497accb522e..40a0d82d067 100644 --- a/salt/utils/ssdp.py +++ b/salt/utils/ssdp.py @@ -282,7 +282,7 @@ class SSDPDiscoveryServer(SSDPBase): family=family, type=socket.SOCK_DGRAM, proto=proto, - flags=flags + flags=flags, ) ) if not infos: @@ -303,7 +303,7 @@ class SSDPDiscoveryServer(SSDPBase): if not addr_pairs_info: raise ValueError("can not get address information") exceptions = [] - for ((family, proto), (local_address, remote_address)) in addr_pairs_info: + for (family, proto), (local_address, remote_address) in addr_pairs_info: sock = r_addr = None try: sock = socket.socket(family=family, type=socket.SOCK_DGRAM, proto=proto) @@ -404,9 +404,7 @@ class SSDPDiscoveryClient(SSDPBase): Query the broadcast for defined services. :return: """ - query = salt.utils.stringutils.to_bytes( - "{}{}".format(self.signature, time.time()) - ) + query = salt.utils.stringutils.to_bytes(f"{self.signature}{time.time()}") self._socket.sendto(query, ("", self.port)) return query diff --git a/salt/utils/ssh.py b/salt/utils/ssh.py index 6c59a5cab02..8e436904434 100644 --- a/salt/utils/ssh.py +++ b/salt/utils/ssh.py @@ -20,6 +20,6 @@ def key_is_encrypted(key): del key_data if not is_private_key: - raise CommandExecutionError("{} is not a private key".format(key)) + raise CommandExecutionError(f"{key} is not a private key") return is_encrypted diff --git a/salt/utils/state.py b/salt/utils/state.py index de3913e0286..41c2e191cc9 100644 --- a/salt/utils/state.py +++ b/salt/utils/state.py @@ -4,7 +4,6 @@ Utility functions for state functions .. versionadded:: 2018.3.0 """ - import copy import salt.state diff --git a/salt/utils/stringio.py b/salt/utils/stringio.py index 1dae9346484..0d3cadf2936 100644 --- a/salt/utils/stringio.py +++ b/salt/utils/stringio.py @@ -2,7 +2,6 @@ Functions for StringIO objects """ - import io readable_types = (io.StringIO,) diff --git a/salt/utils/stringutils.py b/salt/utils/stringutils.py index 30ca46fee5c..d43798df3df 100644 --- a/salt/utils/stringutils.py +++ b/salt/utils/stringutils.py @@ -2,7 +2,6 @@ Functions for manipulating or otherwise processing strings """ - import base64 import difflib import errno @@ -50,7 +49,7 @@ def to_bytes(s, encoding=None, errors="strict"): # raised, otherwise we would have already returned (or raised some # other exception). raise exc # pylint: disable=raising-bad-type - raise TypeError("expected str, bytes, or bytearray not {}".format(type(s))) + raise TypeError(f"expected str, bytes, or bytearray not {type(s)}") def to_str(s, encoding=None, errors="strict", normalize=False): @@ -88,7 +87,7 @@ def to_str(s, encoding=None, errors="strict", normalize=False): # raised, otherwise we would have already returned (or raised some # other exception). raise exc # pylint: disable=raising-bad-type - raise TypeError("expected str, bytes, or bytearray not {}".format(type(s))) + raise TypeError(f"expected str, bytes, or bytearray not {type(s)}") def to_unicode(s, encoding=None, errors="strict", normalize=False): @@ -112,7 +111,7 @@ def to_unicode(s, encoding=None, errors="strict", normalize=False): return _normalize(s) elif isinstance(s, (bytes, bytearray)): return _normalize(to_str(s, encoding, errors)) - raise TypeError("expected str, bytes, or bytearray not {}".format(type(s))) + raise TypeError(f"expected str, bytes, or bytearray not {type(s)}") @jinja_filter("str_to_num") @@ -301,7 +300,7 @@ def build_whitespace_split_regex(text): for line in text.splitlines(): parts = [re.escape(s) for s in __build_parts(line)] regex += r"(?:[\s]+)?{}(?:[\s]+)?".format(r"(?:[\s]+)?".join(parts)) - return r"(?m)^{}$".format(regex) + return rf"(?m)^{regex}$" def expr_match(line, expr): @@ -323,7 +322,7 @@ def expr_match(line, expr): if fnmatch.fnmatch(line, expr): return True try: - if re.match(r"\A{}\Z".format(expr), line): + if re.match(rf"\A{expr}\Z", line): return True except re.error: pass @@ -460,7 +459,7 @@ def print_cli(msg, retries=10, step=0.01): except UnicodeEncodeError: print(msg.encode("utf-8")) except OSError as exc: - err = "{}".format(exc) + err = f"{exc}" if exc.errno != errno.EPIPE: if ( "temporarily unavailable" in err or exc.errno in (errno.EAGAIN,) @@ -523,7 +522,7 @@ def get_diff(a, b, *args, **kwargs): salt.utils.data.decode_list(a, encoding=encoding), salt.utils.data.decode_list(b, encoding=encoding), *args, - **kwargs + **kwargs, ) ) diff --git a/salt/utils/templates.py b/salt/utils/templates.py index 317ccb43460..7623d49577b 100644 --- a/salt/utils/templates.py +++ b/salt/utils/templates.py @@ -1,6 +1,7 @@ """ Template render systems """ + import codecs import importlib.machinery import importlib.util diff --git a/salt/utils/textformat.py b/salt/utils/textformat.py index 304456a0e50..c02c1f175a4 100644 --- a/salt/utils/textformat.py +++ b/salt/utils/textformat.py @@ -3,7 +3,6 @@ ANSI escape code utilities, see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf """ - graph_prefix = "\x1b[" graph_suffix = "m" codes = { @@ -170,7 +169,7 @@ class TextFormat: 'The answer is: {0}'.format(green_blink_text(42)) """ end = TextFormat("reset") if reset else "" - return "{}{}{}".format(self.sequence, text, end) + return f"{self.sequence}{text}{end}" def __str__(self): return self.sequence diff --git a/salt/utils/thin.py b/salt/utils/thin.py index e6f75041db5..a760fcc02f5 100644 --- a/salt/utils/thin.py +++ b/salt/utils/thin.py @@ -148,7 +148,7 @@ def find_site_modules(name): except RuntimeError: log.debug("No site package directories found") for site_path in site_paths: - path = os.path.join(site_path, "{}.py".format(name)) + path = os.path.join(site_path, f"{name}.py") lib = import_module(name, path) if lib: libs.append(lib) @@ -549,9 +549,7 @@ def _pack_alternative(extended_cfg, digest_collector, tfp): top = os.path.normpath(top) base, top_dirname = os.path.basename(top), os.path.dirname(top) os.chdir(top_dirname) - site_pkg_dir = ( - _is_shareable(base) and "pyall" or "py{}".format(py_ver_major) - ) + site_pkg_dir = _is_shareable(base) and "pyall" or f"py{py_ver_major}" log.debug( 'Packing alternative "%s" to "%s/%s" destination', base, @@ -701,11 +699,11 @@ def gen_thin( # This is likely a compressed python .egg tempdir = tempfile.mkdtemp() egg = zipfile.ZipFile(top_dirname) - egg.extractall(tempdir) + egg.extractall(tempdir) # nosec top = os.path.join(tempdir, base) os.chdir(tempdir) - site_pkg_dir = _is_shareable(base) and "pyall" or "py{}".format(py_ver) + site_pkg_dir = _is_shareable(base) and "pyall" or f"py{py_ver}" log.debug('Packing "%s" to "%s" destination', base, site_pkg_dir) if not os.path.isdir(top): @@ -773,7 +771,7 @@ def thin_sum(cachedir, form="sha1"): code_checksum_path = os.path.join(cachedir, "thin", "code-checksum") if os.path.isfile(code_checksum_path): with salt.utils.files.fopen(code_checksum_path, "r") as fh: - code_checksum = "'{}'".format(fh.read().strip()) + code_checksum = f"'{fh.read().strip()}'" else: code_checksum = "'0'" @@ -973,12 +971,12 @@ def gen_min( # This is likely a compressed python .egg tempdir = tempfile.mkdtemp() egg = zipfile.ZipFile(top_dirname) - egg.extractall(tempdir) + egg.extractall(tempdir) # nosec top = os.path.join(tempdir, base) os.chdir(tempdir) if not os.path.isdir(top): # top is a single file module - tfp.add(base, arcname=os.path.join("py{}".format(py_ver), base)) + tfp.add(base, arcname=os.path.join(f"py{py_ver}", base)) continue for root, dirs, files in salt.utils.path.os_walk(base, followlinks=True): for name in files: @@ -991,7 +989,7 @@ def gen_min( continue tfp.add( os.path.join(root, name), - arcname=os.path.join("py{}".format(py_ver), root, name), + arcname=os.path.join(f"py{py_ver}", root, name), ) if tempdir is not None: shutil.rmtree(tempdir) diff --git a/salt/utils/timed_subprocess.py b/salt/utils/timed_subprocess.py index a3ffe3d38e4..627d3f712ed 100644 --- a/salt/utils/timed_subprocess.py +++ b/salt/utils/timed_subprocess.py @@ -44,7 +44,7 @@ class TimedProc: if self.timeout and not isinstance(self.timeout, (int, float)): raise salt.exceptions.TimedProcTimeoutError( - "Error: timeout {} must be a number".format(self.timeout) + f"Error: timeout {self.timeout} must be a number" ) if kwargs.get("shell", False): args = salt.utils.data.decode(args, to_str=True) diff --git a/salt/utils/url.py b/salt/utils/url.py index a30610394c1..478d8e911c2 100644 --- a/salt/utils/url.py +++ b/salt/utils/url.py @@ -2,7 +2,6 @@ URL utils """ - import re import sys from urllib.parse import urlparse, urlunparse @@ -46,7 +45,7 @@ def create(path, saltenv=None): path = salt.utils.path.sanitize_win_path(path) path = salt.utils.data.decode(path) - query = "saltenv={}".format(saltenv) if saltenv else "" + query = f"saltenv={saltenv}" if saltenv else "" url = salt.utils.data.decode(urlunparse(("file", "", path, "", query, ""))) return "salt://{}".format(url[len("file:///") :]) @@ -80,13 +79,13 @@ def escape(url): if url.startswith("|"): return url else: - return "|{}".format(url) + return f"|{url}" elif scheme == "salt": path, saltenv = parse(url) if path.startswith("|"): return create(path, saltenv) else: - return create("|{}".format(path), saltenv) + return create(f"|{path}", saltenv) else: return url @@ -158,11 +157,11 @@ def add_http_basic_auth(url, user=None, password=None, https_only=False): if https_only and urltuple.scheme != "https": raise ValueError("Basic Auth only supported for HTTPS") if password is None: - netloc = "{}@{}".format(user, urltuple.netloc) + netloc = f"{user}@{urltuple.netloc}" urltuple = urltuple._replace(netloc=netloc) return urlunparse(urltuple) else: - netloc = "{}:{}@{}".format(user, password, urltuple.netloc) + netloc = f"{user}:{password}@{urltuple.netloc}" urltuple = urltuple._replace(netloc=netloc) return urlunparse(urltuple) diff --git a/salt/utils/user.py b/salt/utils/user.py index be2abdced2b..d48d2641c0f 100644 --- a/salt/utils/user.py +++ b/salt/utils/user.py @@ -3,7 +3,6 @@ Functions for querying and modifying a user account and the groups to which it belongs. """ - import ctypes import getpass import logging diff --git a/salt/utils/validate/net.py b/salt/utils/validate/net.py index a58fb2b2d70..c098281b654 100644 --- a/salt/utils/validate/net.py +++ b/salt/utils/validate/net.py @@ -37,7 +37,7 @@ def __ip_addr(addr, address_family=socket.AF_INET): try: if "/" not in addr: - addr = "{addr}/{mask_max}".format(addr=addr, mask_max=mask_max) + addr = f"{addr}/{mask_max}" except TypeError: return False diff --git a/salt/utils/vault/cache.py b/salt/utils/vault/cache.py index 3c93a0dda28..7e14681699e 100644 --- a/salt/utils/vault/cache.py +++ b/salt/utils/vault/cache.py @@ -317,9 +317,11 @@ class VaultLeaseCache(LeaseCacheMixin, CommonCache): self.expire_events( tag=f"vault/lease/{ckey}/expire", data={ - "valid_for_less": valid_for - if valid_for is not None - else data.get("min_ttl") or 0, + "valid_for_less": ( + valid_for + if valid_for is not None + else data.get("min_ttl") or 0 + ), }, ) ret = None diff --git a/salt/utils/vault/helpers.py b/salt/utils/vault/helpers.py index 6798a892f3b..7fb4ef1c2b8 100644 --- a/salt/utils/vault/helpers.py +++ b/salt/utils/vault/helpers.py @@ -111,7 +111,7 @@ def expand_pattern_lists(pattern, **mappings): # very expensive, since patterns will typically involve a handful of lists at # most. - for (_, field_name, _, _) in f.parse(pattern): + for _, field_name, _, _ in f.parse(pattern): if field_name is None: continue (value, _) = f.get_field(field_name, None, mappings) diff --git a/salt/utils/versions.py b/salt/utils/versions.py index 7c65e74deab..04dac7d4280 100644 --- a/salt/utils/versions.py +++ b/salt/utils/versions.py @@ -6,6 +6,7 @@ which works under python 3 because on python 3 you can no longer compare strings against integers. """ + import datetime import inspect import logging diff --git a/salt/utils/virt.py b/salt/utils/virt.py index fcd3d4fd4ea..42fe6a8cde1 100644 --- a/salt/utils/virt.py +++ b/salt/utils/virt.py @@ -28,7 +28,7 @@ def download_remote(url, dir): try: rand = hashlib.md5(os.urandom(32)).hexdigest() remote_filename = urllib.parse.urlparse(url).path.split("/")[-1] - full_directory = os.path.join(dir, "{}-{}".format(rand, remote_filename)) + full_directory = os.path.join(dir, f"{rand}-{remote_filename}") with salt.utils.files.fopen( full_directory, "wb" ) as file, urllib.request.urlopen(url) as response: diff --git a/salt/utils/virtualbox.py b/salt/utils/virtualbox.py index d551cc1d386..e8a89dd5dd9 100644 --- a/salt/utils/virtualbox.py +++ b/salt/utils/virtualbox.py @@ -382,7 +382,7 @@ def vb_get_network_addresses(machine_name=None, machine=None, wait_for_pattern=N for i in range(total_slots): try: address = machine.getGuestPropertyValue( - "/VirtualBox/GuestInfo/Net/{}/V4/IP".format(i) + f"/VirtualBox/GuestInfo/Net/{i}/V4/IP" ) if address: ip_addresses.append(address) @@ -607,7 +607,7 @@ def vb_xpcom_to_attribute_dict( """ # Check the interface if interface_name: - m = re.search(r"XPCOM.+implementing {}".format(interface_name), str(xpcom)) + m = re.search(rf"XPCOM.+implementing {interface_name}", str(xpcom)) if not m: # TODO maybe raise error here? log.warning( diff --git a/salt/utils/vmware.py b/salt/utils/vmware.py index 92a3be8e3cf..f6c230c398f 100644 --- a/salt/utils/vmware.py +++ b/salt/utils/vmware.py @@ -159,7 +159,7 @@ def esxcli( protocol = "https" if credstore: - esx_cmd += " --credstore '{}'".format(credstore) + esx_cmd += f" --credstore '{credstore}'" if not esxi_host: # Then we are connecting directly to an ESXi server, @@ -259,7 +259,7 @@ def _get_service_instance( raise salt.exceptions.CommandExecutionError(err_msg) else: raise salt.exceptions.CommandExecutionError( - "Unsupported mechanism: '{}'".format(mechanism) + f"Unsupported mechanism: '{mechanism}'" ) log.trace( @@ -343,7 +343,7 @@ def _get_service_instance( log.exception(exc) err_msg = exc.msg if hasattr(exc, "msg") else str(exc) raise salt.exceptions.VMwareConnectionError( - "Could not connect to host '{}': {}".format(host, err_msg) + f"Could not connect to host '{host}': {err_msg}" ) else: err_msg = exc.msg if hasattr(exc, "msg") else default_msg @@ -494,7 +494,7 @@ def get_service_instance( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -574,7 +574,7 @@ def disconnect(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -597,7 +597,7 @@ def is_connection_to_a_vcenter(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -629,7 +629,7 @@ def get_service_info(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -727,7 +727,7 @@ def get_gssapi_token(principal, host, domain): if not HAS_GSSAPI: raise ImportError("The gssapi library is not imported.") - service = "{}/{}@{}".format(principal, host, domain) + service = f"{principal}/{host}@{domain}" log.debug("Retrieving gsspi token for service %s", service) service_name = gssapi.Name(service, gssapi.C_NT_USER_NAME) ctx = gssapi.InitContext(service_name) @@ -858,7 +858,7 @@ def get_root_folder(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -923,7 +923,7 @@ def get_content( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -968,7 +968,7 @@ def get_content( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -984,7 +984,7 @@ def get_content( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1139,7 +1139,7 @@ def get_properties_of_managed_object(mo_ref, properties): ) if not items: raise salt.exceptions.VMwareApiError( - "Properties of managed object '{}' weren't retrieved".format(mo_name) + f"Properties of managed object '{mo_name}' weren't retrieved" ) return items[0] @@ -1263,7 +1263,7 @@ def get_network_folder(dc_ref): ) if not entries: raise salt.exceptions.VMwareObjectRetrievalError( - "Network folder in datacenter '{}' wasn't retrieved".format(dc_name) + f"Network folder in datacenter '{dc_name}' wasn't retrieved" ) return entries[0]["object"] @@ -1296,7 +1296,7 @@ def create_dvs(dc_ref, dvs_name, dvs_create_spec=None): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1325,7 +1325,7 @@ def update_dvs(dvs_ref, dvs_config_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1357,7 +1357,7 @@ def set_dvs_network_resource_management_enabled(dvs_ref, enabled): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1452,7 +1452,7 @@ def get_uplink_dvportgroup(dvs_ref): ] if not items: raise salt.exceptions.VMwareObjectRetrievalError( - "Uplink portgroup of DVS '{}' wasn't found".format(dvs_name) + f"Uplink portgroup of DVS '{dvs_name}' wasn't found" ) return items[0] @@ -1476,7 +1476,7 @@ def create_dvportgroup(dvs_ref, spec): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1504,7 +1504,7 @@ def update_dvportgroup(portgroup_ref, spec): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1529,7 +1529,7 @@ def remove_dvportgroup(portgroup_ref): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1630,7 +1630,7 @@ def get_license_manager(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1657,7 +1657,7 @@ def get_license_assignment_manager(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1692,7 +1692,7 @@ def get_licenses(service_instance, license_manager=None): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1730,7 +1730,7 @@ def add_license(service_instance, key, description, license_manager=None): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1783,7 +1783,7 @@ def get_assigned_licenses( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1800,7 +1800,7 @@ def get_assigned_licenses( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1874,7 +1874,7 @@ def assign_license( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: raise salt.exceptions.VMwareApiError(exc.msg) @@ -1894,7 +1894,7 @@ def assign_license( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -1952,7 +1952,7 @@ def get_datacenter(service_instance, datacenter_name): items = get_datacenters(service_instance, datacenter_names=[datacenter_name]) if not items: raise salt.exceptions.VMwareObjectRetrievalError( - "Datacenter '{}' was not found".format(datacenter_name) + f"Datacenter '{datacenter_name}' was not found" ) return items[0] @@ -1976,7 +1976,7 @@ def create_datacenter(service_instance, datacenter_name): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2023,7 +2023,7 @@ def get_cluster(dc_ref, cluster): ] if not items: raise salt.exceptions.VMwareObjectRetrievalError( - "Cluster '{}' was not found in datacenter '{}'".format(cluster, dc_name) + f"Cluster '{cluster}' was not found in datacenter '{dc_name}'" ) return items[0] @@ -2049,7 +2049,7 @@ def create_cluster(dc_ref, cluster_name, cluster_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2077,7 +2077,7 @@ def update_cluster(cluster_ref, cluster_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2150,13 +2150,13 @@ def get_datastore_files( for datobj in datastore_objects: try: task = datobj.browser.SearchDatastore_Task( - datastorePath="[{}] {}".format(datobj.name, directory), + datastorePath=f"[{datobj.name}] {directory}", searchSpec=browser_spec, ) except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2313,7 +2313,7 @@ def get_datastores( ) else: raise salt.exceptions.ArgumentValueError( - "Unsupported reference type '{}'".format(reference.__class__.__name__) + f"Unsupported reference type '{reference.__class__.__name__}'" ) items = get_mors_with_properties( @@ -2346,7 +2346,7 @@ def rename_datastore(datastore_ref, new_datastore_name): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2376,7 +2376,7 @@ def get_storage_system(service_instance, host_ref, hostname=None): ) if not objs: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' storage system was not retrieved".format(hostname) + f"Host's '{hostname}' storage system was not retrieved" ) log.trace("[%s] Retrieved storage system", hostname) return objs[0]["object"] @@ -2394,7 +2394,7 @@ def _get_partition_info(storage_system, device_path): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2443,7 +2443,7 @@ def _get_new_computed_partition_spec(storage_system, device_path, partition_info except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2531,7 +2531,7 @@ def create_vmfs_datastore( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2569,7 +2569,7 @@ def get_host_datastore_system(host_ref, hostname=None): ) if not objs: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' datastore system was not retrieved".format(hostname) + f"Host's '{hostname}' datastore system was not retrieved" ) log.trace("[%s] Retrieved datastore system", hostname) return objs[0]["object"] @@ -2591,7 +2591,7 @@ def remove_datastore(service_instance, datastore_ref): ds_hosts = ds_props.get("host") if not ds_hosts: raise salt.exceptions.VMwareApiError( - "Datastore '{}' can't be removed. No attached hosts found".format(ds_name) + f"Datastore '{ds_name}' can't be removed. No attached hosts found" ) hostname = get_managed_object_name(ds_hosts[0].key) host_ds_system = get_host_datastore_system(ds_hosts[0].key, hostname=hostname) @@ -2600,7 +2600,7 @@ def remove_datastore(service_instance, datastore_ref): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2715,7 +2715,7 @@ def _get_scsi_address_to_lun_key_map( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2725,16 +2725,16 @@ def _get_scsi_address_to_lun_key_map( raise salt.exceptions.VMwareRuntimeError(exc.msg) if not device_info: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' storage device info was not retrieved".format(hostname) + f"Host's '{hostname}' storage device info was not retrieved" ) multipath_info = device_info.multipathInfo if not multipath_info: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' multipath info was not retrieved".format(hostname) + f"Host's '{hostname}' multipath info was not retrieved" ) if multipath_info.lun is None: raise salt.exceptions.VMwareObjectRetrievalError( - "No luns were retrieved from host '{}'".format(hostname) + f"No luns were retrieved from host '{hostname}'" ) lun_key_by_scsi_addr = {} for l in multipath_info.lun: @@ -2768,14 +2768,14 @@ def get_all_luns(host_ref, storage_system=None, hostname=None): storage_system = get_storage_system(si, host_ref, hostname) if not storage_system: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' storage system was not retrieved".format(hostname) + f"Host's '{hostname}' storage system was not retrieved" ) try: device_info = storage_system.storageDeviceInfo except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -2785,7 +2785,7 @@ def get_all_luns(host_ref, storage_system=None, hostname=None): raise salt.exceptions.VMwareRuntimeError(exc.msg) if not device_info: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' storage device info was not retrieved".format(hostname) + f"Host's '{hostname}' storage device info was not retrieved" ) scsi_luns = device_info.scsiLun @@ -2926,7 +2926,7 @@ def get_disk_partition_info(host_ref, disk_id, storage_system=None): ) if not props.get("storageDeviceInfo.scsiLun"): raise salt.exceptions.VMwareObjectRetrievalError( - "No devices were retrieved in host '{}'".format(hostname) + f"No devices were retrieved in host '{hostname}'" ) log.trace( "[%s] Retrieved %s devices: %s", @@ -2941,7 +2941,7 @@ def get_disk_partition_info(host_ref, disk_id, storage_system=None): ] if not disks: raise salt.exceptions.VMwareObjectRetrievalError( - "Disk '{}' was not found in host '{}'".format(disk_id, hostname) + f"Disk '{disk_id}' was not found in host '{hostname}'" ) log.trace("[%s] device_path = %s", hostname, disks[0].devicePath) partition_info = _get_partition_info(storage_system, disks[0].devicePath) @@ -2995,7 +2995,7 @@ def erase_disk_partitions( ) if not results: raise salt.exceptions.VMwareObjectRetrievalError( - "Host's '{}' devices were not retrieved".format(hostname) + f"Host's '{hostname}' devices were not retrieved" ) log.trace( "[%s] Retrieved %s devices: %s", @@ -3012,7 +3012,7 @@ def erase_disk_partitions( ] if not disks: raise salt.exceptions.VMwareObjectRetrievalError( - "Disk '{}' was not found in host '{}'".format(disk_id, hostname) + f"Disk '{disk_id}' was not found in host '{hostname}'" ) log.trace("[%s] device_path = %s", hostname, disks[0].devicePath) # Erase the partitions by setting an empty partition spec @@ -3023,7 +3023,7 @@ def erase_disk_partitions( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3069,7 +3069,7 @@ def get_diskgroups(host_ref, cache_disk_ids=None, get_all_disk_groups=False): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3079,12 +3079,12 @@ def get_diskgroups(host_ref, cache_disk_ids=None, get_all_disk_groups=False): raise salt.exceptions.VMwareRuntimeError(exc.msg) if not vsan_host_config: raise salt.exceptions.VMwareObjectRetrievalError( - "No host config found on host '{}'".format(hostname) + f"No host config found on host '{hostname}'" ) vsan_storage_info = vsan_host_config.storageInfo if not vsan_storage_info: raise salt.exceptions.VMwareObjectRetrievalError( - "No vsan storage info found on host '{}'".format(hostname) + f"No vsan storage info found on host '{hostname}'" ) vsan_disk_mappings = vsan_storage_info.diskMapping if not vsan_disk_mappings: @@ -3199,7 +3199,7 @@ def configure_host_cache( ) if not props.get("configManager.cacheConfigurationManager"): raise salt.exceptions.VMwareObjectRetrievalError( - "Host '{}' has no host cache".format(hostname) + f"Host '{hostname}' has no host cache" ) host_cache_manager = props["configManager.cacheConfigurationManager"] log.trace( @@ -3218,7 +3218,7 @@ def configure_host_cache( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3396,7 +3396,7 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level="de except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.FileNotFound as exc: log.exception(exc) @@ -3423,7 +3423,7 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level="de except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.FileNotFound as exc: log.exception(exc) @@ -3451,7 +3451,7 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level="de except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.FileNotFound as exc: log.exception(exc) @@ -3466,7 +3466,7 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level="de log.exception(exc) exc_message = exc.msg if exc.faultMessage: - exc_message = "{} ({})".format(exc_message, exc.faultMessage[0].message) + exc_message = f"{exc_message} ({exc.faultMessage[0].message})" raise salt.exceptions.VMwareApiError(exc_message) @@ -3745,7 +3745,7 @@ def power_cycle_vm(virtual_machine, action="on"): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3760,7 +3760,7 @@ def power_cycle_vm(virtual_machine, action="on"): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3777,7 +3777,7 @@ def power_cycle_vm(virtual_machine, action="on"): " ".join( [ "An error occurred during power", - "operation, a file was not found: {}".format(exc), + f"operation, a file was not found: {exc}", ] ) ) @@ -3818,7 +3818,7 @@ def create_vm( except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3866,7 +3866,7 @@ def register_vm(datacenter, name, vmx_path, resourcepool_object, host_object=Non except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3901,7 +3901,7 @@ def update_vm(vm_ref, vm_config_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3927,7 +3927,7 @@ def delete_vm(vm_ref): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -3952,7 +3952,7 @@ def unregister_vm(vm_ref): except vim.fault.NoPermission as exc: log.exception(exc) raise salt.exceptions.VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: raise salt.exceptions.VMwareApiError(exc.msg) diff --git a/salt/utils/vsan.py b/salt/utils/vsan.py index 7f893150fa6..a10c101d4d9 100644 --- a/salt/utils/vsan.py +++ b/salt/utils/vsan.py @@ -41,7 +41,6 @@ The 5.5.0.2014.1.1 is a known stable version that this original VMware utils fil was developed against. """ - import logging import ssl import sys @@ -99,7 +98,7 @@ def vsan_supported(service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -187,7 +186,7 @@ def get_host_vsan_system(service_instance, host_ref, hostname=None): ) if not objs: raise VMwareObjectRetrievalError( - "Host's '{}' VSAN system was not retrieved".format(hostname) + f"Host's '{hostname}' VSAN system was not retrieved" ) log.trace("[%s] Retrieved VSAN system", hostname) return objs[0]["object"] @@ -238,14 +237,14 @@ def create_diskgroup( except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) raise VMwareApiError(exc.msg) except vmodl.fault.MethodNotFound as exc: log.exception(exc) - raise VMwareRuntimeError("Method '{}' not found".format(exc.method)) + raise VMwareRuntimeError(f"Method '{exc.method}' not found") except vmodl.RuntimeFault as exc: log.exception(exc) raise VMwareRuntimeError(exc.msg) @@ -305,14 +304,14 @@ def add_capacity_to_diskgroup( except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) raise VMwareApiError(exc.msg) except vmodl.fault.MethodNotFound as exc: log.exception(exc) - raise VMwareRuntimeError("Method '{}' not found".format(exc.method)) + raise VMwareRuntimeError(f"Method '{exc.method}' not found") except vmodl.RuntimeFault as exc: raise VMwareRuntimeError(exc.msg) _wait_for_tasks([task], service_instance) @@ -389,7 +388,7 @@ def remove_capacity_from_diskgroup( except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -457,7 +456,7 @@ def remove_diskgroup( except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -490,7 +489,7 @@ def get_cluster_vsan_info(cluster_ref): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -519,7 +518,7 @@ def reconfigure_cluster_vsan(cluster_ref, cluster_vsan_spec): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) @@ -540,7 +539,7 @@ def _wait_for_tasks(tasks, service_instance): except vim.fault.NoPermission as exc: log.exception(exc) raise VMwareApiError( - "Not enough permissions. Required privilege: {}".format(exc.privilegeId) + f"Not enough permissions. Required privilege: {exc.privilegeId}" ) except vim.fault.VimFault as exc: log.exception(exc) diff --git a/salt/utils/vt.py b/salt/utils/vt.py index 42635b3be29..4e81046820e 100644 --- a/salt/utils/vt.py +++ b/salt/utils/vt.py @@ -215,7 +215,7 @@ class Terminal: log.warning( "Failed to spawn the VT: %s", err, exc_info_on_loglevel=logging.DEBUG ) - raise TerminalException("Failed to spawn the VT. Error: {}".format(err)) + raise TerminalException(f"Failed to spawn the VT. Error: {err}") log.debug( "Child Forked! PID: %s STDOUT_FD: %s STDERR_FD: %s", @@ -246,7 +246,7 @@ class Terminal: self.stdin_logger_level = LOG_LEVELS.get(log_stdin_level, log_stdin_level) if log_stdin is True: self.stdin_logger = logging.getLogger( - "{}.{}.PID-{}.STDIN".format(__name__, self.__class__.__name__, self.pid) + f"{__name__}.{self.__class__.__name__}.PID-{self.pid}.STDIN" ) elif log_stdin is not None: if not isinstance(log_stdin, logging.Logger): @@ -294,7 +294,7 @@ class Terminal: """ Send the provided data to the terminal appending a line feed. """ - return self.send("{}{}".format(data, linesep)) + return self.send(f"{data}{linesep}") def recv(self, maxsize=None): """ @@ -373,7 +373,7 @@ class Terminal: elif sig == signal.CTRL_BREAK_EVENT: os.kill(self.pid, signal.CTRL_BREAK_EVENT) else: - raise ValueError("Unsupported signal: {}".format(sig)) + raise ValueError(f"Unsupported signal: {sig}") # pylint: enable=E1101 def terminate(self, force=False): @@ -442,9 +442,7 @@ class Terminal: tty_fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) if tty_fd >= 0: os.close(tty_fd) - raise TerminalException( - "Could not open child pty, {}".format(child_name) - ) + raise TerminalException(f"Could not open child pty, {child_name}") # which exception, shouldn't we catch explicitly .. ? except Exception: # pylint: disable=broad-except # Good! We are disconnected from a controlling tty. @@ -452,9 +450,7 @@ class Terminal: tty_fd = os.open(child_name, os.O_RDWR) setwinsize(tty_fd, rows, cols) if tty_fd < 0: - raise TerminalException( - "Could not open child pty, {}".format(child_name) - ) + raise TerminalException(f"Could not open child pty, {child_name}") else: os.close(tty_fd) if os.name != "posix": diff --git a/salt/utils/vt_helper.py b/salt/utils/vt_helper.py index b18feba3793..aeafbd4f332 100644 --- a/salt/utils/vt_helper.py +++ b/salt/utils/vt_helper.py @@ -61,7 +61,7 @@ class SSHConnection: Example: '-o PubkeyAuthentication=no' """ self.conn = Terminal( - "ssh {} -l {} {}".format(ssh_args, username, host), + f"ssh {ssh_args} -l {username} {host}", shell=True, log_stdout=True, log_stdout_level="trace", diff --git a/salt/utils/win_chcp.py b/salt/utils/win_chcp.py index 2f4d2891267..62cfb1608af 100644 --- a/salt/utils/win_chcp.py +++ b/salt/utils/win_chcp.py @@ -53,7 +53,7 @@ def chcp(page_id, raise_error=False): try: page_id = int(page_id) except ValueError: - error = "The `page_id` needs to be an integer, not {}".format(type(page_id)) + error = f"The `page_id` needs to be an integer, not {type(page_id)}" if raise_error: raise CodePageError(error) log.error(error) @@ -98,7 +98,7 @@ def get_codepage_id(raise_error=False): return win32console.GetConsoleCP() except pywintypes.error as exc: _, _, msg = exc.args - error = "Failed to get the windows code page: {}".format(msg) + error = f"Failed to get the windows code page: {msg}" if raise_error: raise CodePageError(error) else: @@ -129,7 +129,7 @@ def set_codepage_id(page_id, raise_error=False): try: page_id = int(page_id) except ValueError: - error = "The `page_id` needs to be an integer, not {}".format(type(page_id)) + error = f"The `page_id` needs to be an integer, not {type(page_id)}" if raise_error: raise CodePageError(error) log.error(error) @@ -139,7 +139,7 @@ def set_codepage_id(page_id, raise_error=False): return get_codepage_id(raise_error=raise_error) except pywintypes.error as exc: _, _, msg = exc.args - error = "Failed to set the windows code page: {}".format(msg) + error = f"Failed to set the windows code page: {msg}" if raise_error: raise CodePageError(error) else: diff --git a/salt/utils/win_dotnet.py b/salt/utils/win_dotnet.py index 65325da75c3..c798a6329ad 100644 --- a/salt/utils/win_dotnet.py +++ b/salt/utils/win_dotnet.py @@ -98,12 +98,12 @@ def versions(): else: continue - service_pack = " SP{}".format(sp) if sp != "N/A" else "" + service_pack = f" SP{sp}" if sp != "N/A" else "" return_dict["versions"].append(version) return_dict["details"][ver_key] = { "version": version, "service_pack": sp, - "full": "{}{}".format(version, service_pack), + "full": f"{version}{service_pack}", } return return_dict diff --git a/salt/utils/win_functions.py b/salt/utils/win_functions.py index 97e3e0878a2..c3906b1e210 100644 --- a/salt/utils/win_functions.py +++ b/salt/utils/win_functions.py @@ -135,7 +135,7 @@ def get_sid_from_name(name): try: sid = win32security.LookupAccountName(None, name)[0] except pywintypes.error as exc: - raise CommandExecutionError("User {} not found: {}".format(name, exc)) + raise CommandExecutionError(f"User {name} not found: {exc}") return win32security.ConvertSidToStringSid(sid) @@ -166,7 +166,7 @@ def get_current_user(with_domain=True): elif not with_domain: user_name = win32api.GetUserName() except pywintypes.error as exc: - raise CommandExecutionError("Failed to get current user: {}".format(exc)) + raise CommandExecutionError(f"Failed to get current user: {exc}") if not user_name: return False @@ -253,7 +253,7 @@ def escape_for_cmd_exe(arg): meta_re = re.compile( "(" + "|".join(re.escape(char) for char in list(meta_chars)) + ")" ) - meta_map = {char: "^{}".format(char) for char in meta_chars} + meta_map = {char: f"^{char}" for char in meta_chars} def escape_meta_chars(m): char = m.group(1) diff --git a/salt/utils/win_lgpo_auditpol.py b/salt/utils/win_lgpo_auditpol.py index e155ce0000f..47f0d8e8912 100644 --- a/salt/utils/win_lgpo_auditpol.py +++ b/salt/utils/win_lgpo_auditpol.py @@ -116,11 +116,11 @@ def _auditpol_cmd(cmd): Raises: CommandExecutionError: If the command encounters an error """ - ret = salt.modules.cmdmod.run_all(cmd="auditpol {}".format(cmd), python_shell=True) + ret = salt.modules.cmdmod.run_all(cmd=f"auditpol {cmd}", python_shell=True) if ret["retcode"] == 0: return ret["stdout"].splitlines() - msg = "Error executing auditpol command: {}\n".format(cmd) + msg = f"Error executing auditpol command: {cmd}\n" msg += "\n".join(ret["stdout"]) raise CommandExecutionError(msg) @@ -173,9 +173,9 @@ def get_settings(category="All"): if category.lower() in ["all", "*"]: category = "*" elif category.lower() not in [x.lower() for x in categories]: - raise KeyError('Invalid category: "{}"'.format(category)) + raise KeyError(f'Invalid category: "{category}"') - cmd = '/get /category:"{}"'.format(category) + cmd = f'/get /category:"{category}"' results = _auditpol_cmd(cmd) ret = {} @@ -213,7 +213,7 @@ def get_setting(name): for setting in current_settings: if name.lower() == setting.lower(): return current_settings[setting] - raise KeyError("Invalid name: {}".format(name)) + raise KeyError(f"Invalid name: {name}") def _get_valid_names(): @@ -264,13 +264,13 @@ def set_setting(name, value): """ # Input validation if name.lower() not in _get_valid_names(): - raise KeyError("Invalid name: {}".format(name)) + raise KeyError(f"Invalid name: {name}") for setting in settings: if value.lower() == setting.lower(): - cmd = '/set /subcategory:"{}" {}'.format(name, settings[setting]) + cmd = f'/set /subcategory:"{name}" {settings[setting]}' break else: - raise KeyError("Invalid setting value: {}".format(value)) + raise KeyError(f"Invalid setting value: {value}") _auditpol_cmd(cmd) @@ -298,7 +298,7 @@ def get_auditpol_dump(): with tempfile.NamedTemporaryFile(suffix=".csv") as tmp_file: csv_file = tmp_file.name - cmd = "/backup /file:{}".format(csv_file) + cmd = f"/backup /file:{csv_file}" _auditpol_cmd(cmd) with salt.utils.files.fopen(csv_file) as fp: diff --git a/salt/utils/win_lgpo_netsh.py b/salt/utils/win_lgpo_netsh.py index 7037b9f75dc..30ea51fc10d 100644 --- a/salt/utils/win_lgpo_netsh.py +++ b/salt/utils/win_lgpo_netsh.py @@ -117,14 +117,14 @@ def _netsh_file(content): fp.write(content) try: log.debug("%s:\n%s", fp.name, content) - return salt.modules.cmdmod.run("netsh -f {}".format(fp.name), python_shell=True) + return salt.modules.cmdmod.run(f"netsh -f {fp.name}", python_shell=True) finally: os.remove(fp.name) def _netsh_command(command, store): if store.lower() not in ("local", "lgpo"): - raise ValueError("Incorrect store: {}".format(store)) + raise ValueError(f"Incorrect store: {store}") # set the store for local or lgpo if store.lower() == "local": netsh_script = dedent( @@ -190,12 +190,12 @@ def get_settings(profile, section, store="local"): """ # validate input if profile.lower() not in ("domain", "public", "private"): - raise ValueError("Incorrect profile: {}".format(profile)) + raise ValueError(f"Incorrect profile: {profile}") if section.lower() not in ("state", "firewallpolicy", "settings", "logging"): - raise ValueError("Incorrect section: {}".format(section)) + raise ValueError(f"Incorrect section: {section}") if store.lower() not in ("local", "lgpo"): - raise ValueError("Incorrect store: {}".format(store)) - command = "show {}profile {}".format(profile, section) + raise ValueError(f"Incorrect store: {store}") + command = f"show {profile}profile {section}" # run it results = _netsh_command(command=command, store=store) # sample output: @@ -209,7 +209,7 @@ def get_settings(profile, section, store="local"): # if it's less than 3 lines it failed if len(results) < 3: - raise CommandExecutionError("Invalid results: {}".format(results)) + raise CommandExecutionError(f"Invalid results: {results}") ret = {} # Skip the first 2 lines. Add everything else to a dictionary for line in results[3:]: @@ -339,20 +339,20 @@ def set_firewall_settings(profile, inbound=None, outbound=None, store="local"): """ # Input validation if profile.lower() not in ("domain", "public", "private"): - raise ValueError("Incorrect profile: {}".format(profile)) + raise ValueError(f"Incorrect profile: {profile}") if inbound and inbound.lower() not in ( "blockinbound", "blockinboundalways", "allowinbound", "notconfigured", ): - raise ValueError("Incorrect inbound value: {}".format(inbound)) + raise ValueError(f"Incorrect inbound value: {inbound}") if outbound and outbound.lower() not in ( "allowoutbound", "blockoutbound", "notconfigured", ): - raise ValueError("Incorrect outbound value: {}".format(outbound)) + raise ValueError(f"Incorrect outbound value: {outbound}") if not inbound and not outbound: raise ValueError("Must set inbound or outbound") @@ -366,12 +366,12 @@ def set_firewall_settings(profile, inbound=None, outbound=None, store="local"): if not outbound: outbound = ret["Outbound"] - command = "set {}profile firewallpolicy {},{}".format(profile, inbound, outbound) + command = f"set {profile}profile firewallpolicy {inbound},{outbound}" results = _netsh_command(command=command, store=store) if results: - raise CommandExecutionError("An error occurred: {}".format(results)) + raise CommandExecutionError(f"An error occurred: {results}") return True @@ -441,17 +441,17 @@ def set_logging_settings(profile, setting, value, store="local"): """ # Input validation if profile.lower() not in ("domain", "public", "private"): - raise ValueError("Incorrect profile: {}".format(profile)) + raise ValueError(f"Incorrect profile: {profile}") if setting.lower() not in ( "allowedconnections", "droppedconnections", "filename", "maxfilesize", ): - raise ValueError("Incorrect setting: {}".format(setting)) + raise ValueError(f"Incorrect setting: {setting}") if setting.lower() in ("allowedconnections", "droppedconnections"): if value.lower() not in ("enable", "disable", "notconfigured"): - raise ValueError("Incorrect value: {}".format(value)) + raise ValueError(f"Incorrect value: {value}") # TODO: Consider adding something like the following to validate filename # https://stackoverflow.com/questions/9532499/check-whether-a-path-is-valid-in-python-without-creating-a-file-at-the-paths-ta if setting.lower() == "maxfilesize": @@ -460,16 +460,16 @@ def set_logging_settings(profile, setting, value, store="local"): try: int(value) except ValueError: - raise ValueError("Incorrect value: {}".format(value)) + raise ValueError(f"Incorrect value: {value}") if not 1 <= int(value) <= 32767: - raise ValueError("Incorrect value: {}".format(value)) + raise ValueError(f"Incorrect value: {value}") # Run the command - command = "set {}profile logging {} {}".format(profile, setting, value) + command = f"set {profile}profile logging {setting} {value}" results = _netsh_command(command=command, store=store) # A successful run should return an empty list if results: - raise CommandExecutionError("An error occurred: {}".format(results)) + raise CommandExecutionError(f"An error occurred: {results}") return True @@ -521,7 +521,7 @@ def set_settings(profile, setting, value, store="local"): """ # Input validation if profile.lower() not in ("domain", "public", "private"): - raise ValueError("Incorrect profile: {}".format(profile)) + raise ValueError(f"Incorrect profile: {profile}") if setting.lower() not in ( "localfirewallrules", "localconsecrules", @@ -529,17 +529,17 @@ def set_settings(profile, setting, value, store="local"): "remotemanagement", "unicastresponsetomulticast", ): - raise ValueError("Incorrect setting: {}".format(setting)) + raise ValueError(f"Incorrect setting: {setting}") if value.lower() not in ("enable", "disable", "notconfigured"): - raise ValueError("Incorrect value: {}".format(value)) + raise ValueError(f"Incorrect value: {value}") # Run the command - command = "set {}profile settings {} {}".format(profile, setting, value) + command = f"set {profile}profile settings {setting} {value}" results = _netsh_command(command=command, store=store) # A successful run should return an empty list if results: - raise CommandExecutionError("An error occurred: {}".format(results)) + raise CommandExecutionError(f"An error occurred: {results}") return True @@ -582,16 +582,16 @@ def set_state(profile, state, store="local"): """ # Input validation if profile.lower() not in ("domain", "public", "private"): - raise ValueError("Incorrect profile: {}".format(profile)) + raise ValueError(f"Incorrect profile: {profile}") if state.lower() not in ("on", "off", "notconfigured"): - raise ValueError("Incorrect state: {}".format(state)) + raise ValueError(f"Incorrect state: {state}") # Run the command - command = "set {}profile state {}".format(profile, state) + command = f"set {profile}profile state {state}" results = _netsh_command(command=command, store=store) # A successful run should return an empty list if results: - raise CommandExecutionError("An error occurred: {}".format(results)) + raise CommandExecutionError(f"An error occurred: {results}") return True diff --git a/salt/utils/win_lgpo_reg.py b/salt/utils/win_lgpo_reg.py index 8e3af61b858..4f2761d8a90 100644 --- a/salt/utils/win_lgpo_reg.py +++ b/salt/utils/win_lgpo_reg.py @@ -2,6 +2,7 @@ A Salt Util for working with the Registry.pol file. The Registry.pol file is the source of truth for registry settings that are configured via LGPO. """ + import logging import os import re diff --git a/salt/utils/win_network.py b/salt/utils/win_network.py index eeae8fc091b..1fae2ffe2f2 100644 --- a/salt/utils/win_network.py +++ b/salt/utils/win_network.py @@ -18,6 +18,7 @@ depending on the version of Windows this is run on. Once support for Windows :depends: - pythonnet - wmi """ + # https://docs.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface.getallnetworkinterfaces?view=netframework-4.7.2 import logging diff --git a/salt/utils/win_osinfo.py b/salt/utils/win_osinfo.py index 56f1e12d50f..99a3b0ad9fd 100644 --- a/salt/utils/win_osinfo.py +++ b/salt/utils/win_osinfo.py @@ -1,6 +1,7 @@ """ Get Version information from Windows """ + # http://stackoverflow.com/questions/32300004/python-ctypes-getting-0-with-getversionex-function import ctypes diff --git a/salt/utils/win_pdh.py b/salt/utils/win_pdh.py index fcd395184a4..4d3dde820c2 100644 --- a/salt/utils/win_pdh.py +++ b/salt/utils/win_pdh.py @@ -167,7 +167,7 @@ class Counter: ) if win32pdh.ValidatePath(path) == 0: return Counter(path, obj, instance, instance_index, counter) - raise CommandExecutionError("Invalid counter specified: {}".format(path)) + raise CommandExecutionError(f"Invalid counter specified: {path}") build_counter = staticmethod(build_counter) diff --git a/salt/utils/win_service.py b/salt/utils/win_service.py index c05652c65c5..2713d40aeec 100644 --- a/salt/utils/win_service.py +++ b/salt/utils/win_service.py @@ -114,9 +114,7 @@ def info(name): None, None, win32service.SC_MANAGER_CONNECT ) except pywintypes.error as exc: - raise CommandExecutionError( - "Failed to connect to the SCM: {}".format(exc.strerror) - ) + raise CommandExecutionError(f"Failed to connect to the SCM: {exc.strerror}") try: handle_svc = win32service.OpenService( @@ -128,7 +126,7 @@ def info(name): | win32service.SERVICE_QUERY_STATUS, ) except pywintypes.error as exc: - raise CommandExecutionError("Failed To Open {}: {}".format(name, exc.strerror)) + raise CommandExecutionError(f"Failed To Open {name}: {exc.strerror}") try: config_info = win32service.QueryServiceConfig(handle_svc) @@ -150,7 +148,7 @@ def info(name): ret = dict() try: - sid = win32security.LookupAccountName("", "NT Service\\{}".format(name))[0] + sid = win32security.LookupAccountName("", f"NT Service\\{name}")[0] ret["sid"] = win32security.ConvertSidToStringSid(sid) except pywintypes.error: ret["sid"] = "Failed to get SID" diff --git a/salt/utils/win_system.py b/salt/utils/win_system.py index e9f38c9171e..125024674ce 100644 --- a/salt/utils/win_system.py +++ b/salt/utils/win_system.py @@ -5,6 +5,7 @@ Functions shared with salt.modules.win_system and salt.grains.pending_reboot .. versionadded:: 3001 """ + # NOTE: DO NOT USE RAW STRINGS IN THIS MODULE! UNICODE_LITERALS DOES NOT PLAY # NICELY WITH RAW STRINGS CONTAINING \u or \U. diff --git a/salt/utils/win_update.py b/salt/utils/win_update.py index 778acd141fa..dd54f213963 100644 --- a/salt/utils/win_update.py +++ b/salt/utils/win_update.py @@ -1,6 +1,7 @@ """ Classes for working with Windows Update Agent """ + import logging import subprocess @@ -398,14 +399,14 @@ class WindowsUpdateAgent: results = searcher.Search(search_string) if results.Updates.Count == 0: log.debug("No Updates found for:\n\t\t%s", search_string) - return "No Updates found: {}".format(search_string) + return f"No Updates found: {search_string}" except pywintypes.com_error as error: # Something happened, raise an error hr, msg, exc, arg = error.args # pylint: disable=W0633 try: failure_code = self.fail_codes[exc[5]] except KeyError: - failure_code = "Unknown Failure: {}".format(error) + failure_code = f"Unknown Failure: {error}" log.error("Search Failed: %s\n\t\t%s", failure_code, search_string) raise CommandExecutionError(failure_code) @@ -719,7 +720,7 @@ class WindowsUpdateAgent: try: failure_code = self.fail_codes[exc[5]] except KeyError: - failure_code = "Unknown Failure: {}".format(error) + failure_code = f"Unknown Failure: {error}" log.error("Download Failed: %s", failure_code) raise CommandExecutionError(failure_code) @@ -828,7 +829,7 @@ class WindowsUpdateAgent: try: failure_code = self.fail_codes[exc[5]] except KeyError: - failure_code = "Unknown Failure: {}".format(error) + failure_code = f"Unknown Failure: {error}" log.error("Install Failed: %s", failure_code) raise CommandExecutionError(failure_code) @@ -962,7 +963,7 @@ class WindowsUpdateAgent: try: failure_code = self.fail_codes[exc[5]] except KeyError: - failure_code = "Unknown Failure: {}".format(error) + failure_code = f"Unknown Failure: {error}" # If "Uninstall Not Allowed" error, try using DISM if exc[5] == -2145124312: @@ -992,7 +993,7 @@ class WindowsUpdateAgent: "dism", "/Online", "/Remove-Package", - "/PackageName:{}".format(pkg), + f"/PackageName:{pkg}", "/Quiet", "/NoRestart", ] @@ -1004,7 +1005,7 @@ class WindowsUpdateAgent: log.debug("Command: %s", " ".join(cmd)) log.debug("Error: %s", exc) raise CommandExecutionError( - "Uninstall using DISM failed: {}".format(exc) + f"Uninstall using DISM failed: {exc}" ) # DISM Uninstall Completed Successfully diff --git a/salt/utils/x509.py b/salt/utils/x509.py index c0b3fb47cc3..d09e8b9762a 100644 --- a/salt/utils/x509.py +++ b/salt/utils/x509.py @@ -1190,21 +1190,21 @@ def _create_authority_key_identifier(val, ca_crt, ca_pub, **kwargs): cx509.SubjectKeyIdentifier ).value.digest except cx509.ExtensionNotFound: - args[ - "key_identifier" - ] = cx509.AuthorityKeyIdentifier.from_issuer_public_key( - ca_crt.public_key() - ).key_identifier + args["key_identifier"] = ( + cx509.AuthorityKeyIdentifier.from_issuer_public_key( + ca_crt.public_key() + ).key_identifier + ) except Exception: # pylint: disable=broad-except pass if not args["key_identifier"] and ca_pub: # this should happen for self-signed certificates try: - args[ - "key_identifier" - ] = cx509.AuthorityKeyIdentifier.from_issuer_public_key( - ca_pub - ).key_identifier + args["key_identifier"] = ( + cx509.AuthorityKeyIdentifier.from_issuer_public_key( + ca_pub + ).key_identifier + ) except Exception: # pylint: disable=broad-except pass @@ -1484,12 +1484,14 @@ def _create_policy_constraints(val, **kwargs): if isinstance(val, str): val, critical = _deserialize_openssl_confstring(val) args = { - "require_explicit_policy": int(val["requireExplicitPolicy"]) - if "requireExplicitPolicy" in val - else None, - "inhibit_policy_mapping": int(val["inhibitPolicyMapping"]) - if "inhibitPolicyMapping" in val - else None, + "require_explicit_policy": ( + int(val["requireExplicitPolicy"]) + if "requireExplicitPolicy" in val + else None + ), + "inhibit_policy_mapping": ( + int(val["inhibitPolicyMapping"]) if "inhibitPolicyMapping" in val else None + ), } try: # not sure why pylint complains about this line having kwargs from keyUsage @@ -1544,12 +1546,12 @@ def _create_name_constraints(val, **kwargs): ], } args = { - "permitted_subtrees": _parse_general_names(val["permitted"]) - if "permitted" in val - else None, - "excluded_subtrees": _parse_general_names(val["excluded"]) - if "excluded" in val - else None, + "permitted_subtrees": ( + _parse_general_names(val["permitted"]) if "permitted" in val else None + ), + "excluded_subtrees": ( + _parse_general_names(val["excluded"]) if "excluded" in val else None + ), } if not any(args.values()): raise SaltInvocationError("nameConstraints needs at least one definition") @@ -1954,13 +1956,15 @@ def _render_subject_key_identifier(ext): def _render_authority_key_identifier(ext): return { - "keyid": pretty_hex(ext.value.key_identifier) - if ext.value.key_identifier - else None, + "keyid": ( + pretty_hex(ext.value.key_identifier) if ext.value.key_identifier else None + ), "issuer": [render_gn(x) for x in ext.value.authority_cert_issuer or []] or None, - "issuer_sn": dec2hex(ext.value.authority_cert_serial_number) - if ext.value.authority_cert_serial_number - else None, + "issuer_sn": ( + dec2hex(ext.value.authority_cert_serial_number) + if ext.value.authority_cert_serial_number + else None + ), } @@ -1994,11 +1998,11 @@ def _render_authority_info_access(ext): for description in ext.value._descriptions: rendered.append( { - description.access_method._name - if description.access_method._name != "Unknown OID" - else description.access_method.dotted_string: render_gn( - description.access_location.value - ) + ( + description.access_method._name + if description.access_method._name != "Unknown OID" + else description.access_method.dotted_string + ): render_gn(description.access_location.value) } ) except AttributeError: @@ -2015,9 +2019,11 @@ def _render_distribution_points(ext): "crlissuer": [render_gn(x) for x in dpoint.crl_issuer or []], "fullname": [render_gn(x) for x in dpoint.full_name or []], "reasons": list(sorted(x.value for x in dpoint.reasons or [])), - "relativename": dpoint.relative_name.rfc4514_string() - if dpoint.relative_name - else None, + "relativename": ( + dpoint.relative_name.rfc4514_string() + if dpoint.relative_name + else None + ), } ) except AttributeError: @@ -2031,9 +2037,11 @@ def _render_issuing_distribution_point(ext): "onysomereasons": list( sorted(x.value for x in ext.value.only_some_reasons or []) ), - "relativename": ext.value.relative_name.rfc4514_string() - if ext.value.relative_name - else None, + "relativename": ( + ext.value.relative_name.rfc4514_string() + if ext.value.relative_name + else None + ), "onlyuser": ext.value.only_contains_user_certs, "onlyCA": ext.value.only_contains_ca_certs, "onlyAA": ext.value.only_contains_attribute_certs, diff --git a/salt/utils/xmlutil.py b/salt/utils/xmlutil.py index 46e2946f914..2c68afd67a6 100644 --- a/salt/utils/xmlutil.py +++ b/salt/utils/xmlutil.py @@ -115,7 +115,7 @@ def get_xml_node(node, xpath): xpath: simple XPath to look for. """ if not xpath.startswith("./"): - xpath = "./{}".format(xpath) + xpath = f"./{xpath}" res = node.find(xpath) if res is None: parent_xpath = xpath[: xpath.rfind("/")] @@ -304,7 +304,7 @@ def change_xml(doc, data, mapping): xpath = param["xpath"] # Prepend the xpath with ./ to handle the root more easily if not xpath.startswith("./"): - xpath = "./{}".format(xpath) + xpath = f"./{xpath}" placeholders = [ s[1:-1] @@ -331,9 +331,7 @@ def change_xml(doc, data, mapping): if new_value is not None: # We need to increment ids from arrays since xpath starts at 1 converters = { - p: (lambda n: n + 1) - if "[${}]".format(p) in xpath - else (lambda n: n) + p: (lambda n: n + 1) if f"[${p}]" in xpath else (lambda n: n) for p in placeholders } ctx = { diff --git a/salt/utils/yaml.py b/salt/utils/yaml.py index f590d493261..8e9e202b15f 100644 --- a/salt/utils/yaml.py +++ b/salt/utils/yaml.py @@ -1,6 +1,7 @@ """ Convenience module that provides our custom loader and dumper in a single module """ + # pylint: disable=wildcard-import,unused-wildcard-import,unused-import from yaml import YAMLError, parser, scanner diff --git a/salt/utils/yamldumper.py b/salt/utils/yamldumper.py index e5e937cac7d..8c6e40394a3 100644 --- a/salt/utils/yamldumper.py +++ b/salt/utils/yamldumper.py @@ -3,6 +3,7 @@ ~~~~~~~~~~~~~~~~~~~~~ """ + # pylint: disable=W0232 # class has no __init__ method diff --git a/salt/utils/yamlencoding.py b/salt/utils/yamlencoding.py index 7e26b9afcb5..b9c2d20d6c8 100644 --- a/salt/utils/yamlencoding.py +++ b/salt/utils/yamlencoding.py @@ -2,7 +2,6 @@ Functions for adding yaml encoding to the jinja context """ - import io import sys diff --git a/salt/utils/yamlloader.py b/salt/utils/yamlloader.py index 25b4b3bb936..89ac51b8367 100644 --- a/salt/utils/yamlloader.py +++ b/salt/utils/yamlloader.py @@ -2,7 +2,6 @@ Custom YAML loading in Salt """ - import yaml # pylint: disable=blacklisted-import from yaml.constructor import ConstructorError from yaml.nodes import MappingNode, SequenceNode @@ -56,7 +55,7 @@ class SaltYamlSafeLoader(BaseLoader): raise ConstructorError( None, None, - "expected a mapping node, but found {}".format(node.id), + f"expected a mapping node, but found {node.id}", node.start_mark, ) @@ -72,7 +71,7 @@ class SaltYamlSafeLoader(BaseLoader): raise ConstructorError( context, node.start_mark, - "found unacceptable key {}".format(key_node.value), + f"found unacceptable key {key_node.value}", key_node.start_mark, ) value = self.construct_object(value_node, deep=deep) @@ -80,7 +79,7 @@ class SaltYamlSafeLoader(BaseLoader): raise ConstructorError( context, node.start_mark, - "found conflicting ID '{}'".format(key), + f"found conflicting ID '{key}'", key_node.start_mark, ) mapping[key] = value diff --git a/salt/utils/yamlloader_old.py b/salt/utils/yamlloader_old.py index d24717a79b2..ea483c197b2 100644 --- a/salt/utils/yamlloader_old.py +++ b/salt/utils/yamlloader_old.py @@ -2,7 +2,6 @@ Custom YAML loading in Salt """ - import re import yaml # pylint: disable=blacklisted-import @@ -61,7 +60,7 @@ class SaltYamlSafeLoader(yaml.SafeLoader): raise ConstructorError( None, None, - "expected a mapping node, but found {}".format(node.id), + f"expected a mapping node, but found {node.id}", node.start_mark, ) @@ -77,7 +76,7 @@ class SaltYamlSafeLoader(yaml.SafeLoader): raise ConstructorError( context, node.start_mark, - "found unacceptable key {}".format(key_node.value), + f"found unacceptable key {key_node.value}", key_node.start_mark, ) value = self.construct_object(value_node, deep=deep) @@ -85,7 +84,7 @@ class SaltYamlSafeLoader(yaml.SafeLoader): raise ConstructorError( context, node.start_mark, - "found conflicting ID '{}'".format(key), + f"found conflicting ID '{key}'", key_node.start_mark, ) mapping[key] = value diff --git a/salt/utils/zfs.py b/salt/utils/zfs.py index 6612302a072..52d5ede4ea0 100644 --- a/salt/utils/zfs.py +++ b/salt/utils/zfs.py @@ -12,7 +12,6 @@ These functions are for dealing with type conversion and basic execution """ - import logging import math import os diff --git a/salt/version.py b/salt/version.py index ee8a70e2bd3..82f1b6f3519 100644 --- a/salt/version.py +++ b/salt/version.py @@ -1,6 +1,7 @@ """ Set up the version of Salt """ + import argparse import operator import os @@ -686,7 +687,6 @@ def salt_information(): def package_information(): - """ Report package type """ diff --git a/salt/wheel/config.py b/salt/wheel/config.py index a5dfee0b602..10a62efda6e 100644 --- a/salt/wheel/config.py +++ b/salt/wheel/config.py @@ -86,6 +86,6 @@ def update_config(file_name, yaml_contents): with salt.utils.files.fopen(file_path, "w") as fp_: fp_.write(yaml_out) - return "Wrote {}".format(file_name) + return f"Wrote {file_name}" except (OSError, salt.utils.yaml.YAMLError, ValueError) as err: return str(err) diff --git a/salt/wheel/file_roots.py b/salt/wheel/file_roots.py index d29a82cbbba..bcc259eea0e 100644 --- a/salt/wheel/file_roots.py +++ b/salt/wheel/file_roots.py @@ -2,7 +2,6 @@ Read in files from the file_root and save files to the file root """ - import os import salt.utils.files diff --git a/salt/wheel/key.py b/salt/wheel/key.py index 66bee797220..76156b7e29e 100644 --- a/salt/wheel/key.py +++ b/salt/wheel/key.py @@ -26,7 +26,6 @@ The wheel key functions can also be called via a ``salt`` command at the CLI using the :mod:`saltutil execution module `. """ - import hashlib import logging import os diff --git a/salt/wheel/minions.py b/salt/wheel/minions.py index 75d06a94f02..65ac422f268 100644 --- a/salt/wheel/minions.py +++ b/salt/wheel/minions.py @@ -2,7 +2,6 @@ Wheel system wrapper for connected minions """ - import salt.config import salt.utils.minions from salt.utils.cache import CacheCli diff --git a/salt/wheel/pillar_roots.py b/salt/wheel/pillar_roots.py index 53078f9f9dd..fff560bf933 100644 --- a/salt/wheel/pillar_roots.py +++ b/salt/wheel/pillar_roots.py @@ -93,7 +93,7 @@ def write(data, path, saltenv="base", index=0): index of the file can be specified to write to a lower priority file root """ if saltenv not in __opts__["pillar_roots"]: - return "Named environment {} is not present".format(saltenv) + return f"Named environment {saltenv} is not present" if len(__opts__["pillar_roots"][saltenv]) <= index: return "Specified index {} in environment {} is not present".format( index, saltenv @@ -112,4 +112,4 @@ def write(data, path, saltenv="base", index=0): os.makedirs(dest_dir) with salt.utils.files.fopen(dest, "w+") as fp_: fp_.write(salt.utils.stringutils.to_str(data)) - return "Wrote data to file {}".format(dest) + return f"Wrote data to file {dest}" diff --git a/scripts/suse/yum/plugins/yumnotify.py b/scripts/suse/yum/plugins/yumnotify.py index 4e137191a00..18dfa5bb8ce 100644 --- a/scripts/suse/yum/plugins/yumnotify.py +++ b/scripts/suse/yum/plugins/yumnotify.py @@ -52,6 +52,4 @@ def posttrans_hook(conduit): # Integrate Yum with Salt if "SALT_RUNNING" not in os.environ: with open(CK_PATH, "w") as ck_fh: - ck_fh.write( - "{chksum} {mtime}\n".format(chksum=_get_checksum(), mtime=_get_mtime()) - ) + ck_fh.write(f"{_get_checksum()} {_get_mtime()}\n") diff --git a/tests/buildpackage.py b/tests/buildpackage.py index 108cd729a0b..fcd3c734752 100644 --- a/tests/buildpackage.py +++ b/tests/buildpackage.py @@ -133,7 +133,7 @@ def _init(): if not opts.platform: problems.append("Platform ('os' grain) required") if not os.path.isdir(opts.source_dir): - problems.append("Source directory {} not found".format(opts.source_dir)) + problems.append(f"Source directory {opts.source_dir} not found") try: shutil.rmtree(opts.build_dir) except OSError as exc: @@ -245,11 +245,11 @@ def build_centos(opts): "contents: '{}'".format(redhat_release) ) except OSError as exc: - _abort("{}".format(exc)) + _abort(f"{exc}") log.info("major_release: %s", major_release) - define_opts = ["--define", "_topdir {}".format(os.path.join(opts.build_dir))] + define_opts = ["--define", f"_topdir {os.path.join(opts.build_dir)}"] build_reqs = ["rpm-build"] if major_release == 5: python_bin = "python26" @@ -262,7 +262,7 @@ def build_centos(opts): elif major_release == 7: build_reqs.extend(["python-devel", "systemd-units"]) else: - _abort("Unsupported major release: {}".format(major_release)) + _abort(f"Unsupported major release: {major_release}") # Install build deps _run_command(["yum", "-y", "install"] + build_reqs) @@ -280,7 +280,7 @@ def build_centos(opts): try: base, offset, oid = tarball_re.match(os.path.basename(sdist)).groups() except AttributeError: - _abort("Unable to extract version info from sdist filename '{}'".format(sdist)) + _abort(f"Unable to extract version info from sdist filename '{sdist}'") if offset is None: salt_pkgver = salt_srcver = base @@ -299,7 +299,7 @@ def build_centos(opts): except OSError: pass if not os.path.isdir(path): - _abort("Unable to make directory: {}".format(path)) + _abort(f"Unable to make directory: {path}") # Get sources into place build_sources_path = os.path.join(opts.build_dir, "SOURCES") @@ -327,9 +327,9 @@ def build_centos(opts): with open(spec_path, "w") as fp_: for line in spec_lines: if line.startswith("%global srcver "): - line = "%global srcver {}".format(salt_srcver) + line = f"%global srcver {salt_srcver}" elif line.startswith("Version: "): - line = "Version: {}".format(salt_pkgver) + line = f"Version: {salt_pkgver}" fp_.write(line + "\n") # Do the thing @@ -346,15 +346,11 @@ def build_centos(opts): opts.build_dir, "RPMS", "noarch", - "salt-*{}*.noarch.rpm".format(salt_pkgver), + f"salt-*{salt_pkgver}*.noarch.rpm", ) ) packages.extend( - glob.glob( - os.path.join( - opts.build_dir, "SRPMS", "salt-{}*.src.rpm".format(salt_pkgver) - ) - ) + glob.glob(os.path.join(opts.build_dir, "SRPMS", f"salt-{salt_pkgver}*.src.rpm")) ) return packages @@ -393,9 +389,9 @@ if __name__ == "__main__": elif opts.platform.lower() == "centos": artifacts = build_centos(opts) else: - _abort("Unsupported platform '{}'".format(opts.platform)) + _abort(f"Unsupported platform '{opts.platform}'") - msg = "Build complete. Artifacts will be stored in {}".format(opts.artifact_dir) + msg = f"Build complete. Artifacts will be stored in {opts.artifact_dir}" log.info(msg) print(msg) # pylint: disable=C0325 for artifact in artifacts: diff --git a/tests/committer_parser.py b/tests/committer_parser.py index 8056b7fd406..914bc7c3dba 100644 --- a/tests/committer_parser.py +++ b/tests/committer_parser.py @@ -78,7 +78,7 @@ def parse_gitlog(filename=None): if len(line) < 2 and new_commit: new_commit = False - key = "{}-{}".format(d.year, str(d.month).zfill(2)) + key = f"{d.year}-{str(d.month).zfill(2)}" if key not in results: results[key] = [] @@ -108,15 +108,15 @@ def counts_by_contributor(commits_by_contributor, results): output = "" dates = sorted(results.keys()) for d in dates: - output += "\t{}".format(d) + output += f"\t{d}" output += "\n" for email in sorted(commits_by_contributor.keys()): - output += "'{}".format(email) + output += f"'{email}" for d in dates: if d in commits_by_contributor[email]: - output += "\t{}".format(commits_by_contributor[email][d]) + output += f"\t{commits_by_contributor[email][d]}" else: output += "\t" output += "\n" @@ -127,7 +127,7 @@ def count_results(results, commits): result_str = "" print("Date\tContributors\tCommits") for k in sorted(results.keys()): - result_str += "{}\t{}\t{}".format(k, len(results[k]), commits[k]) + result_str += f"{k}\t{len(results[k])}\t{commits[k]}" result_str += "\n" return result_str diff --git a/tests/conftest.py b/tests/conftest.py index b25db4172e8..fbcf2901e27 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -519,7 +519,9 @@ def pytest_collection_modifyitems(config, items): log.debug("Finish called on %s", self) try: return func(request) - except BaseException as exc: # pylint: disable=broad-except + except ( + BaseException # pylint: disable=broad-except + ) as exc: pytest.fail( "Failed to run finish() on {}: {}".format( fixturedef, exc diff --git a/tests/eventlisten.py b/tests/eventlisten.py index 8ff5ada8232..8016f93bb8b 100644 --- a/tests/eventlisten.py +++ b/tests/eventlisten.py @@ -5,7 +5,6 @@ what the sock_dir is. This script is a generic tool to test event output """ - import optparse import os import pprint @@ -135,7 +134,7 @@ def listen(opts): ) continue else: - print("Event fired at {}".format(time.asctime())) + print(f"Event fired at {time.asctime()}") print("*" * 25) print("Tag: {}".format(ret["tag"])) print("Data:") diff --git a/tests/integration/cloud/clouds/test_digitalocean.py b/tests/integration/cloud/clouds/test_digitalocean.py index c0f98e39233..8f10ad0c305 100644 --- a/tests/integration/cloud/clouds/test_digitalocean.py +++ b/tests/integration/cloud/clouds/test_digitalocean.py @@ -1,6 +1,7 @@ """ Integration tests for DigitalOcean APIv2 """ + import base64 import hashlib diff --git a/tests/integration/cloud/clouds/test_dimensiondata.py b/tests/integration/cloud/clouds/test_dimensiondata.py index 56ac83042c3..5aba20bed74 100644 --- a/tests/integration/cloud/clouds/test_dimensiondata.py +++ b/tests/integration/cloud/clouds/test_dimensiondata.py @@ -2,7 +2,6 @@ Integration tests for the Dimension Data cloud provider """ - from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest @@ -18,14 +17,14 @@ class DimensionDataTest(CloudTest): """ Tests the return of running the --list-images command for the dimensiondata cloud provider """ - image_list = self.run_cloud("--list-images {}".format(self.PROVIDER)) + image_list = self.run_cloud(f"--list-images {self.PROVIDER}") self.assertIn("Ubuntu 14.04 2 CPU", [i.strip() for i in image_list]) def test_list_locations(self): """ Tests the return of running the --list-locations command for the dimensiondata cloud provider """ - _list_locations = self.run_cloud("--list-locations {}".format(self.PROVIDER)) + _list_locations = self.run_cloud(f"--list-locations {self.PROVIDER}") self.assertIn( "Australia - Melbourne MCP2", [i.strip() for i in _list_locations] ) @@ -34,7 +33,7 @@ class DimensionDataTest(CloudTest): """ Tests the return of running the --list-sizes command for the dimensiondata cloud provider """ - _list_sizes = self.run_cloud("--list-sizes {}".format(self.PROVIDER)) + _list_sizes = self.run_cloud(f"--list-sizes {self.PROVIDER}") self.assertIn("default", [i.strip() for i in _list_sizes]) def test_instance(self): @@ -43,7 +42,7 @@ class DimensionDataTest(CloudTest): """ # check if instance with salt installed returned ret_val = self.run_cloud( - "-p dimensiondata-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p dimensiondata-test {self.instance_name}", timeout=TIMEOUT ) self.assertInstanceExists(ret_val) diff --git a/tests/integration/cloud/clouds/test_ec2.py b/tests/integration/cloud/clouds/test_ec2.py index c3c3da8484e..3713a365ab3 100644 --- a/tests/integration/cloud/clouds/test_ec2.py +++ b/tests/integration/cloud/clouds/test_ec2.py @@ -1,6 +1,7 @@ """ :codeauthor: Nicole Thomas """ + import os import pytest @@ -61,7 +62,7 @@ class EC2Test(CloudTest): if not group_or_subnet: self.skipTest( - "securitygroup or subnetid missing for {} config".format(self.PROVIDER) + f"securitygroup or subnetid missing for {self.PROVIDER} config" ) super().setUp() @@ -117,7 +118,7 @@ class EC2Test(CloudTest): """ # create the instance ret_val = self.run_cloud( - "-p ec2-test {} --no-deploy".format(self.instance_name), timeout=TIMEOUT + f"-p ec2-test {self.instance_name} --no-deploy", timeout=TIMEOUT ) # check if instance returned self.assertInstanceExists(ret_val) @@ -132,7 +133,7 @@ class EC2Test(CloudTest): ) self.assertFalse( self._instance_exists(), - "Instance wasn't renamed: |\n{}".format(rename_result), + f"Instance wasn't renamed: |\n{rename_result}", ) self.assertInstanceExists(instance_name=changed_name) diff --git a/tests/integration/cloud/clouds/test_gce.py b/tests/integration/cloud/clouds/test_gce.py index affa0134fc5..e8bd45d4efa 100644 --- a/tests/integration/cloud/clouds/test_gce.py +++ b/tests/integration/cloud/clouds/test_gce.py @@ -3,7 +3,6 @@ :codeauthor: Tomas Sirny """ - from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest @@ -25,9 +24,7 @@ class GCETest(CloudTest): """ # create the instance - ret_str = self.run_cloud( - "-p gce-test {}".format(self.instance_name), timeout=TIMEOUT - ) + ret_str = self.run_cloud(f"-p gce-test {self.instance_name}", timeout=TIMEOUT) # check if instance returned with salt installed self.assertInstanceExists(ret_str) @@ -40,7 +37,7 @@ class GCETest(CloudTest): # create the instance ret_str = self.run_cloud( - "-p gce-test-extra {}".format(self.instance_name), timeout=TIMEOUT + f"-p gce-test-extra {self.instance_name}", timeout=TIMEOUT ) # check if instance returned with salt installed diff --git a/tests/integration/cloud/clouds/test_gogrid.py b/tests/integration/cloud/clouds/test_gogrid.py index 4943839f46b..f45d3891d90 100644 --- a/tests/integration/cloud/clouds/test_gogrid.py +++ b/tests/integration/cloud/clouds/test_gogrid.py @@ -22,7 +22,7 @@ class GoGridTest(CloudTest): """ # check if instance with salt installed returned ret_str = self.run_cloud( - "-p gogrid-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p gogrid-test {self.instance_name}", timeout=TIMEOUT ) self.assertInstanceExists(ret_str) diff --git a/tests/integration/cloud/clouds/test_oneandone.py b/tests/integration/cloud/clouds/test_oneandone.py index 632f2b871d3..d0f5e30ee9f 100644 --- a/tests/integration/cloud/clouds/test_oneandone.py +++ b/tests/integration/cloud/clouds/test_oneandone.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Amel Ajdinovic ` """ + import pytest from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest @@ -26,7 +27,7 @@ class OneAndOneTest(CloudTest): """ Tests the return of running the --list-images command for 1and1 """ - image_list = self.run_cloud("--list-images {}".format(self.PROVIDER_NAME)) + image_list = self.run_cloud(f"--list-images {self.PROVIDER_NAME}") self.assertIn("coreOSimage", [i.strip() for i in image_list]) def test_instance(self): @@ -35,7 +36,7 @@ class OneAndOneTest(CloudTest): """ # check if instance with salt installed returned ret_str = self.run_cloud( - "-p oneandone-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p oneandone-test {self.instance_name}", timeout=TIMEOUT ) self.assertInstanceExists(ret_str) diff --git a/tests/integration/cloud/clouds/test_openstack.py b/tests/integration/cloud/clouds/test_openstack.py index bc76184f16d..c0f7a4df720 100644 --- a/tests/integration/cloud/clouds/test_openstack.py +++ b/tests/integration/cloud/clouds/test_openstack.py @@ -219,7 +219,7 @@ class RackspaceTest(CloudTest): """ # check if instance with salt installed returned ret_val = self.run_cloud( - "-p rackspace-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p rackspace-test {self.instance_name}", timeout=TIMEOUT ) self.assertInstanceExists(ret_val) diff --git a/tests/integration/cloud/clouds/test_profitbricks.py b/tests/integration/cloud/clouds/test_profitbricks.py index 0428b40c260..f8f4e1c744f 100644 --- a/tests/integration/cloud/clouds/test_profitbricks.py +++ b/tests/integration/cloud/clouds/test_profitbricks.py @@ -1,6 +1,7 @@ """ :codeauthor: Ethan Devenport """ + import pytest from tests.integration.cloud.helpers.cloud_test_base import TIMEOUT, CloudTest @@ -45,7 +46,7 @@ class ProfitBricksTest(CloudTest): """ Tests the return of running the --list-images command for ProfitBricks """ - list_images = self.run_cloud("--list-images {}".format(self.PROVIDER)) + list_images = self.run_cloud(f"--list-images {self.PROVIDER}") self.assertIn( "Ubuntu-16.04-LTS-server-2017-10-01", [i.strip() for i in list_images] ) @@ -55,7 +56,7 @@ class ProfitBricksTest(CloudTest): Tests the return of running the -f list_images command for ProfitBricks """ - cmd = "-f list_images {}".format(self.PROVIDER) + cmd = f"-f list_images {self.PROVIDER}" list_images = self.run_cloud(cmd) self.assertIn("- ubuntu:latest", [i.strip() for i in list_images]) @@ -63,7 +64,7 @@ class ProfitBricksTest(CloudTest): """ Tests the return of running the --list_sizes command for ProfitBricks """ - list_sizes = self.run_cloud("--list-sizes {}".format(self.PROVIDER)) + list_sizes = self.run_cloud(f"--list-sizes {self.PROVIDER}") self.assertIn("Micro Instance:", [i.strip() for i in list_sizes]) def test_list_datacenters(self): @@ -71,7 +72,7 @@ class ProfitBricksTest(CloudTest): Tests the return of running the -f list_datacenters command for ProfitBricks """ - cmd = "-f list_datacenters {}".format(self.PROVIDER) + cmd = f"-f list_datacenters {self.PROVIDER}" list_datacenters = self.run_cloud(cmd) self.assertIn( self.provider_config["datacenter_id"], [i.strip() for i in list_datacenters] @@ -81,7 +82,7 @@ class ProfitBricksTest(CloudTest): """ Tests the return of running the -f list_nodes command for ProfitBricks """ - list_nodes = self.run_cloud("-f list_nodes {}".format(self.PROVIDER)) + list_nodes = self.run_cloud(f"-f list_nodes {self.PROVIDER}") self.assertIn("state:", [i.strip() for i in list_nodes]) self.assertIn("name:", [i.strip() for i in list_nodes]) @@ -91,7 +92,7 @@ class ProfitBricksTest(CloudTest): Tests the return of running the -f list_nodes_full command for ProfitBricks """ - cmd = "-f list_nodes_full {}".format(self.PROVIDER) + cmd = f"-f list_nodes_full {self.PROVIDER}" list_nodes = self.run_cloud(cmd) self.assertIn("state:", [i.strip() for i in list_nodes]) @@ -102,7 +103,7 @@ class ProfitBricksTest(CloudTest): Tests the return of running the --list-locations command for ProfitBricks """ - cmd = "--list-locations {}".format(self.PROVIDER) + cmd = f"--list-locations {self.PROVIDER}" list_locations = self.run_cloud(cmd) self.assertIn("de/fkb", [i.strip() for i in list_locations]) @@ -119,7 +120,7 @@ class ProfitBricksTest(CloudTest): """ # check if instance with salt installed returned ret_str = self.run_cloud( - "-p profitbricks-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p profitbricks-test {self.instance_name}", timeout=TIMEOUT ) self.assertInstanceExists(ret_str) diff --git a/tests/integration/cloud/clouds/test_tencentcloud.py b/tests/integration/cloud/clouds/test_tencentcloud.py index ce995c44ff1..85bac333b57 100644 --- a/tests/integration/cloud/clouds/test_tencentcloud.py +++ b/tests/integration/cloud/clouds/test_tencentcloud.py @@ -68,12 +68,12 @@ class TencentCloudTest(ShellCase): [ i.strip() for i in self.run_cloud( - "-p tencentcloud-test {}".format(INSTANCE_NAME), timeout=500 + f"-p tencentcloud-test {INSTANCE_NAME}", timeout=500 ) ], ) except AssertionError: - self.run_cloud("-d {} --assume-yes".format(INSTANCE_NAME), timeout=500) + self.run_cloud(f"-d {INSTANCE_NAME} --assume-yes", timeout=500) raise # delete the instance @@ -81,9 +81,7 @@ class TencentCloudTest(ShellCase): INSTANCE_NAME + ":", [ i.strip() - for i in self.run_cloud( - "-d {} --assume-yes".format(INSTANCE_NAME), timeout=500 - ) + for i in self.run_cloud(f"-d {INSTANCE_NAME} --assume-yes", timeout=500) ], ) @@ -92,8 +90,8 @@ class TencentCloudTest(ShellCase): Clean up after tests """ query = self.run_cloud("--query") - ret_str = " {}:".format(INSTANCE_NAME) + ret_str = f" {INSTANCE_NAME}:" # if test instance is still present, delete it if ret_str in query: - self.run_cloud("-d {} --assume-yes".format(INSTANCE_NAME), timeout=500) + self.run_cloud(f"-d {INSTANCE_NAME} --assume-yes", timeout=500) diff --git a/tests/integration/cloud/clouds/test_virtualbox.py b/tests/integration/cloud/clouds/test_virtualbox.py index ad69aa249c2..8b3d8b26dfb 100644 --- a/tests/integration/cloud/clouds/test_virtualbox.py +++ b/tests/integration/cloud/clouds/test_virtualbox.py @@ -63,9 +63,7 @@ class VirtualboxProviderTest(VirtualboxCloudTestCase): @return: @rtype: dict """ - output = self.run_cloud( - "-d {} --assume-yes --log-level=debug".format(machine_name) - ) + output = self.run_cloud(f"-d {machine_name} --assume-yes --log-level=debug") return output.get(CONFIG_NAME, {}).get(PROVIDER_NAME, {}) def setUp(self): @@ -130,7 +128,7 @@ class VirtualboxProviderTest(VirtualboxCloudTestCase): Simply create a machine and make sure it was created """ machines = self.run_cloud( - "-p {} {} --log-level=debug".format(PROFILE_NAME, INSTANCE_NAME) + f"-p {PROFILE_NAME} {INSTANCE_NAME} --log-level=debug" ) self.assertIn(INSTANCE_NAME, machines.keys()) @@ -231,7 +229,7 @@ class VirtualboxProviderHeavyTests(VirtualboxCloudTestCase): try: socket.inet_pton(socket.AF_INET6, ip_str) except Exception: # pylint: disable=broad-except - self.fail("{} is not a valid IP address".format(ip_str)) + self.fail(f"{ip_str} is not a valid IP address") def setUp(self): """ @@ -295,7 +293,7 @@ class VirtualboxProviderHeavyTests(VirtualboxCloudTestCase): def test_deploy(self): machines = self.run_cloud( - "-p {} {} --log-level=debug".format(DEPLOY_PROFILE_NAME, INSTANCE_NAME) + f"-p {DEPLOY_PROFILE_NAME} {INSTANCE_NAME} --log-level=debug" ) self.assertIn(INSTANCE_NAME, machines.keys()) machine = machines[INSTANCE_NAME] diff --git a/tests/integration/cloud/clouds/test_vmware.py b/tests/integration/cloud/clouds/test_vmware.py index 1e82566fc21..b997951c330 100644 --- a/tests/integration/cloud/clouds/test_vmware.py +++ b/tests/integration/cloud/clouds/test_vmware.py @@ -39,7 +39,7 @@ class VMWareTest(CloudTest): ] ret_val = self.run_cloud( - "-p vmware-test {}".format(self.instance_name), timeout=TIMEOUT + f"-p vmware-test {self.instance_name}", timeout=TIMEOUT ) disk_datastore_str = " [{}] {}/Hard disk 2-flat.vmdk".format( disk_datastore, self.instance_name @@ -50,7 +50,7 @@ class VMWareTest(CloudTest): self.assertIn( disk_datastore_str, ret_val, - msg="Hard Disk 2 did not use the Datastore {} ".format(disk_datastore), + msg=f"Hard Disk 2 did not use the Datastore {disk_datastore} ", ) self.assertDestroyInstance() @@ -61,7 +61,7 @@ class VMWareTest(CloudTest): """ # create the instance ret_val = self.run_cloud( - "-p vmware-test {} --no-deploy".format(self.instance_name), timeout=TIMEOUT + f"-p vmware-test {self.instance_name} --no-deploy", timeout=TIMEOUT ) # check if instance returned with salt installed @@ -90,7 +90,7 @@ class VMWareTest(CloudTest): ) # create the instance ret_val = self.run_cloud( - "-p {} {}".format(profile_name, self.instance_name), timeout=TIMEOUT + f"-p {profile_name} {self.instance_name}", timeout=TIMEOUT ) # check if instance returned with salt installed self.assertInstanceExists(ret_val) @@ -109,7 +109,7 @@ class VMWareTest(CloudTest): handler = TstSuiteLoggingHandler(format=log_format, level=logging.INFO) with handler: ret_val = self.run_cloud( - "-p {} {}".format(profile_name, self.instance_name), timeout=TIMEOUT + f"-p {profile_name} {self.instance_name}", timeout=TIMEOUT ) # This sometimes times out before it get's an IP, so we check the logs if ret_val == []: diff --git a/tests/integration/cloud/clouds/test_vultrpy.py b/tests/integration/cloud/clouds/test_vultrpy.py index a25b4502dae..fb81d427bd7 100644 --- a/tests/integration/cloud/clouds/test_vultrpy.py +++ b/tests/integration/cloud/clouds/test_vultrpy.py @@ -17,7 +17,7 @@ class VultrTest(CloudTest): """ Tests the return of running the --list-images command for Vultr """ - image_list = self.run_cloud("--list-images {}".format(self.PROVIDER)) + image_list = self.run_cloud(f"--list-images {self.PROVIDER}") self.assertIn("Debian 10 x64 (buster)", [i.strip() for i in image_list]) @@ -25,14 +25,14 @@ class VultrTest(CloudTest): """ Tests the return of running the --list-locations command for Vultr """ - location_list = self.run_cloud("--list-locations {}".format(self.PROVIDER)) + location_list = self.run_cloud(f"--list-locations {self.PROVIDER}") self.assertIn("New Jersey", [i.strip() for i in location_list]) def test_list_sizes(self): """ Tests the return of running the --list-sizes command for Vultr """ - size_list = self.run_cloud("--list-sizes {}".format(self.PROVIDER)) + size_list = self.run_cloud(f"--list-sizes {self.PROVIDER}") self.assertIn( "2048 MB RAM,55 GB SSD,2.00 TB BW", [i.strip() for i in size_list] ) @@ -84,7 +84,7 @@ class VultrTest(CloudTest): """ # check if instance with salt installed returned ret_val = self.run_cloud( - "-p vultr-test {}".format(self.instance_name), timeout=TIMEOUT + 300 + f"-p vultr-test {self.instance_name}", timeout=TIMEOUT + 300 ) self.assertInstanceExists(ret_val) diff --git a/tests/integration/cloud/helpers/cloud_test_base.py b/tests/integration/cloud/helpers/cloud_test_base.py index 48e44a6f0fa..2848db25ed0 100644 --- a/tests/integration/cloud/helpers/cloud_test_base.py +++ b/tests/integration/cloud/helpers/cloud_test_base.py @@ -2,7 +2,6 @@ Tests for the Openstack Cloud Provider """ - import logging import os import shutil @@ -116,7 +115,7 @@ class CloudTest(ShellCase): instance_name = self.instance_name log.debug('Deleting instance "%s"', instance_name) delete_str = self.run_cloud( - "-d {} --assume-yes --out=yaml".format(instance_name), timeout=timeout + f"-d {instance_name} --assume-yes --out=yaml", timeout=timeout ) if delete_str: delete = safe_load("\n".join(delete_str)) @@ -160,7 +159,7 @@ class CloudTest(ShellCase): subclass = self.__class__.__name__.strip("Test") # Use the first three letters of the subclass, fill with '-' if too short self._instance_name = random_string( - "cloud-test-{:-<3}-".format(subclass[:3]), uppercase=False + f"cloud-test-{subclass[:3]:-<3}-", uppercase=False ).lower() return self._instance_name diff --git a/tests/integration/cloud/helpers/virtualbox.py b/tests/integration/cloud/helpers/virtualbox.py index 202ad639b75..8efcea0f84c 100644 --- a/tests/integration/cloud/helpers/virtualbox.py +++ b/tests/integration/cloud/helpers/virtualbox.py @@ -59,7 +59,7 @@ class VirtualboxCloudTestCase(ShellCase): @return: @rtype: dict """ - arg_str = "--out=json {}".format(arg_str) + arg_str = f"--out=json {arg_str}" log.debug("running salt-cloud with %s", arg_str) output = self.run_script( "salt-cloud", arg_str, catch_stderr, timeout=timeout, config_dir=config_dir @@ -97,9 +97,7 @@ class VirtualboxCloudTestCase(ShellCase): args = [] # Args converted in the form of key1='value1' ... keyN='valueN' if kw_function_args: - args = [ - "{}='{}'".format(key, value) for key, value in kw_function_args.items() - ] + args = [f"{key}='{value}'" for key, value in kw_function_args.items()] output = self.run_cloud( "-f {} {} {}".format(function, CONFIG_NAME, " ".join(args)), **kwargs @@ -118,7 +116,5 @@ class VirtualboxCloudTestCase(ShellCase): @rtype: dict """ - output = self.run_cloud( - "-a {} {} --assume-yes".format(action, instance_name), **kwargs - ) + output = self.run_cloud(f"-a {action} {instance_name} --assume-yes", **kwargs) return output.get(CONFIG_NAME, {}).get(PROVIDER_NAME, {}) diff --git a/tests/integration/cloud/test_cloud.py b/tests/integration/cloud/test_cloud.py index 29bd820da7b..960ed317539 100644 --- a/tests/integration/cloud/test_cloud.py +++ b/tests/integration/cloud/test_cloud.py @@ -1,6 +1,7 @@ """ Integration tests for functions located in the salt.cloud.__init__.py file. """ + import pytest import salt.cloud @@ -23,7 +24,7 @@ class CloudClientTestCase(CloudTest): # Use a --list-images salt-cloud call to see if the DigitalOcean provider is # configured correctly before running any tests. - images = self.run_cloud("--list-images {}".format(self.PROVIDER)) + images = self.run_cloud(f"--list-images {self.PROVIDER}") if self.image_name not in [i.strip() for i in images]: self.skipTest( diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 1e1baf6134a..13ded49f4a6 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -4,6 +4,7 @@ Integration tests PyTest configuration/fixtures """ + import logging import pathlib diff --git a/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py b/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py index 19d4d4e9420..37d8e0d2450 100644 --- a/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py +++ b/tests/integration/files/extension_modules/pillar/ext_pillar_opts.py @@ -6,7 +6,6 @@ Returns a hash of the name of the pillar module as defined in _virtual__ with the value __opts__ """ - import logging # Set up logging diff --git a/tests/integration/files/file/base/_modules/runtests_decorators.py b/tests/integration/files/file/base/_modules/runtests_decorators.py index a005b32a1bc..0365a0b655e 100644 --- a/tests/integration/files/file/base/_modules/runtests_decorators.py +++ b/tests/integration/files/file/base/_modules/runtests_decorators.py @@ -15,9 +15,9 @@ EXIT_CODE_CMD = STATE_BASE_DIR / "exit_code.cmd" def _exit_code(code): if os.name == "nt": - cmd = "cmd /c {} {}".format(EXIT_CODE_CMD, code) + cmd = f"cmd /c {EXIT_CODE_CMD} {code}" else: - cmd = "/usr/bin/env sh {} {}".format(EXIT_CODE_SH, code) + cmd = f"/usr/bin/env sh {EXIT_CODE_SH} {code}" return cmd diff --git a/tests/integration/files/file/base/_modules/runtests_helpers.py b/tests/integration/files/file/base/_modules/runtests_helpers.py index 3ee0e2da5f3..a38dd1835cf 100644 --- a/tests/integration/files/file/base/_modules/runtests_helpers.py +++ b/tests/integration/files/file/base/_modules/runtests_helpers.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~ """ - import logging import os import sys diff --git a/tests/integration/files/file/base/buildout/var/tb/2/bootstrap.py b/tests/integration/files/file/base/buildout/var/tb/2/bootstrap.py index 257cc5642cb..b8ba90e4d14 100644 --- a/tests/integration/files/file/base/buildout/var/tb/2/bootstrap.py +++ b/tests/integration/files/file/base/buildout/var/tb/2/bootstrap.py @@ -1 +1,2 @@ +# pylint: skip-file foo diff --git a/tests/integration/files/returners/noop_returner.py b/tests/integration/files/returners/noop_returner.py index 0201e5076b9..c6a34f975c2 100644 --- a/tests/integration/files/returners/noop_returner.py +++ b/tests/integration/files/returners/noop_returner.py @@ -5,7 +5,6 @@ noop_returner A returner that does nothing which is used to test the salt-master `event_return` functionality """ - import logging import salt.utils.jid diff --git a/tests/integration/grains/test_core.py b/tests/integration/grains/test_core.py index e45836e4ad2..59b84456938 100644 --- a/tests/integration/grains/test_core.py +++ b/tests/integration/grains/test_core.py @@ -1,6 +1,7 @@ """ Test the core grains """ + import pytest import salt.loader diff --git a/tests/integration/grains/test_custom.py b/tests/integration/grains/test_custom.py index 17a09a4797e..d99e88d1902 100644 --- a/tests/integration/grains/test_custom.py +++ b/tests/integration/grains/test_custom.py @@ -2,7 +2,6 @@ Test the core grains """ - import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/loader/test_ext_grains.py b/tests/integration/loader/test_ext_grains.py index af98e544f65..242519aa3f4 100644 --- a/tests/integration/loader/test_ext_grains.py +++ b/tests/integration/loader/test_ext_grains.py @@ -5,7 +5,6 @@ Test Salt's loader regarding external grains """ - import os import time diff --git a/tests/integration/minion/test_timeout.py b/tests/integration/minion/test_timeout.py index 8ceb66c4a5d..ccb3bf76a92 100644 --- a/tests/integration/minion/test_timeout.py +++ b/tests/integration/minion/test_timeout.py @@ -2,7 +2,6 @@ Tests for various minion timeouts """ - import os import sys @@ -31,16 +30,16 @@ class MinionTimeoutTestCase(ShellCase): else: popen_kwargs = None ret = self.run_salt( - "minion test.sleep {}".format(sleep_length), + f"minion test.sleep {sleep_length}", timeout=90, catch_stderr=True, popen_kwargs=popen_kwargs, ) self.assertTrue( isinstance(ret[0], list), - "Return is not a list. Minion may have returned error: {}".format(ret), + f"Return is not a list. Minion may have returned error: {ret}", ) - self.assertEqual(len(ret[0]), 2, "Standard out wrong length {}".format(ret)) + self.assertEqual(len(ret[0]), 2, f"Standard out wrong length {ret}") self.assertTrue( "True" in ret[0][1], "Minion did not return True after {} seconds. ret={}".format( diff --git a/tests/integration/modules/test_boto_iam.py b/tests/integration/modules/test_boto_iam.py index 01f15d76edd..667395083b6 100644 --- a/tests/integration/modules/test_boto_iam.py +++ b/tests/integration/modules/test_boto_iam.py @@ -1,6 +1,7 @@ """ Validate the boto_iam module """ + import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/modules/test_boto_sns.py b/tests/integration/modules/test_boto_sns.py index fd4313a3344..52125593715 100644 --- a/tests/integration/modules/test_boto_sns.py +++ b/tests/integration/modules/test_boto_sns.py @@ -1,6 +1,7 @@ """ Validate the boto_sns module """ + import re import pytest @@ -99,7 +100,7 @@ class BotoSNSTest(ModuleCase): ) def _get_arn(self, name): - return "arn:aws:sns:us-east-1:{}:{}".format(self.account_id, name) + return f"arn:aws:sns:us-east-1:{self.account_id}:{name}" @property def account_id(self): diff --git a/tests/integration/modules/test_cmdmod.py b/tests/integration/modules/test_cmdmod.py index 800111174f0..c13d31b527b 100644 --- a/tests/integration/modules/test_cmdmod.py +++ b/tests/integration/modules/test_cmdmod.py @@ -56,7 +56,7 @@ class CMDModuleTest(ModuleCase): self.assertTrue(self.run_function("cmd.run", ["echo $SHELL"])) self.assertEqual( self.run_function( - "cmd.run", ["echo $SHELL", "shell={}".format(shell)], python_shell=True + "cmd.run", ["echo $SHELL", f"shell={shell}"], python_shell=True ).rstrip(), shell, ) @@ -108,7 +108,7 @@ class CMDModuleTest(ModuleCase): self.assertEqual( self.run_function( "cmd.run_stderr", - ['echo "cheese" 1>&2', "shell={}".format(shell)], + ['echo "cheese" 1>&2', f"shell={shell}"], python_shell=True, ).rstrip(), "cheese" if not salt.utils.platform.is_windows() else '"cheese"', @@ -126,7 +126,7 @@ class CMDModuleTest(ModuleCase): ret = self.run_function( "cmd.run_all", - ['echo "cheese" 1>&2', "shell={}".format(shell)], + ['echo "cheese" 1>&2', f"shell={shell}"], python_shell=True, ) self.assertTrue("pid" in ret) @@ -194,7 +194,7 @@ class CMDModuleTest(ModuleCase): expected_stderr = "No such file or directory" ret = self.run_function( "cmd.run_all", - ["{} {}".format(func, random_file)], + [f"{func} {random_file}"], success_stderr=[expected_stderr], python_shell=True, ) @@ -394,7 +394,7 @@ class CMDModuleTest(ModuleCase): result = self.run_function( "cmd.run_all", [cmd], runas=RUNTIME_VARS.RUNNING_TESTS_USER ) - errmsg = "The command returned: {}".format(result) + errmsg = f"The command returned: {result}" self.assertEqual(result["retcode"], 0, errmsg) self.assertEqual(result["stdout"], expected_result, errmsg) @@ -505,7 +505,7 @@ class CMDModuleTest(ModuleCase): out = self.run_function( "cmd.run", ["env"], runas=self.runas_usr ).splitlines() - self.assertIn("USER={}".format(self.runas_usr), out) + self.assertIn(f"USER={self.runas_usr}", out) @pytest.mark.skip_if_binaries_missing("sleep", reason="sleep cmd not installed") def test_timeout(self): diff --git a/tests/integration/modules/test_git.py b/tests/integration/modules/test_git.py index f0d26a59a92..8bc2eee57f3 100644 --- a/tests/integration/modules/test_git.py +++ b/tests/integration/modules/test_git.py @@ -38,7 +38,7 @@ def _git_version(): stdout=subprocess.PIPE, check=False, shell=False, - universal_newlines=True, + text=True, ) # On macOS, the git version is displayed in a different format # git version 2.21.1 (Apple Git-122.3) @@ -81,9 +81,7 @@ class GitModuleTest(ModuleCase): dir_path.mkdir(parents=True, exist_ok=True) for filename in self.files: with salt.utils.files.fopen(str(dir_path / filename), "wb") as fp_: - fp_.write( - "This is a test file named {}.".format(filename).encode("utf-8") - ) + fp_.write(f"This is a test file named {filename}.".encode()) # Navigate to the root of the repo to init, stage, and commit with pytest.helpers.change_cwd(self.repo): # Initialize a new git repository @@ -152,13 +150,9 @@ class GitModuleTest(ModuleCase): files_relpath = [os.path.join(newdir, x) for x in self.files] for path in files: with salt.utils.files.fopen(path, "wb") as fp_: - fp_.write( - "This is a test file with relative path {}.\n".format(path).encode( - "utf-8" - ) - ) + fp_.write(f"This is a test file with relative path {path}.\n".encode()) ret = self.run_function("git.add", [self.repo, newdir]) - res = "\n".join(sorted("add '{}'".format(x) for x in files_relpath)) + res = "\n".join(sorted(f"add '{x}'" for x in files_relpath)) if salt.utils.platform.is_windows(): res = res.replace("\\", "/") self.assertEqual(ret, res) @@ -173,11 +167,11 @@ class GitModuleTest(ModuleCase): with salt.utils.files.fopen(file_path, "w") as fp_: fp_.write( salt.utils.stringutils.to_str( - "This is a test file named {}.\n".format(filename) + f"This is a test file named {filename}.\n" ) ) ret = self.run_function("git.add", [self.repo, filename]) - self.assertEqual(ret, "add '{}'".format(filename)) + self.assertEqual(ret, f"add '{filename}'") @pytest.mark.slow_test def test_archive(self): @@ -411,7 +405,7 @@ class GitModuleTest(ModuleCase): "git.config_set", ["foo.single"], value=cfg_global["foo.single"][0], - **{"global": True} + **{"global": True}, ), cfg_global["foo.single"], ) @@ -431,7 +425,7 @@ class GitModuleTest(ModuleCase): "git.config_set", ["foo.multi"], multivar=cfg_global["foo.multi"], - **{"global": True} + **{"global": True}, ), cfg_global["foo.multi"], ) @@ -482,7 +476,7 @@ class GitModuleTest(ModuleCase): "git.config_get_regexp", ["foo.(single|multi)"], cwd=self.repo, - **{"global": True} + **{"global": True}, ), cfg_global, ) @@ -503,7 +497,7 @@ class GitModuleTest(ModuleCase): ["foo.multi"], value_regex="a", cwd=self.repo, - **{"global": True} + **{"global": True}, ), {"foo.multi": [x for x in cfg_global["foo.multi"] if "a" in x]}, ) @@ -586,7 +580,7 @@ class GitModuleTest(ModuleCase): else: self.assertEqual( self.run_function("git.init", [new_repo]).lower(), - "Initialized empty Git repository in {}/.git/".format(new_repo).lower(), + f"Initialized empty Git repository in {new_repo}/.git/".lower(), ) shutil.rmtree(new_repo) @@ -840,7 +834,7 @@ class GitModuleTest(ModuleCase): with salt.utils.files.fopen(os.path.join(self.repo, filename), "w") as fp_: fp_.write( salt.utils.stringutils.to_str( - "This is a new file named {}.".format(filename) + f"This is a new file named {filename}." ) ) # Stage the new file so it shows up as a 'new' file @@ -853,7 +847,7 @@ class GitModuleTest(ModuleCase): with salt.utils.files.fopen(os.path.join(self.repo, filename), "w") as fp_: fp_.write( salt.utils.stringutils.to_str( - "This is a new file named {}.".format(filename) + f"This is a new file named {filename}." ) ) self.assertEqual(self.run_function("git.status", [self.repo]), changes) diff --git a/tests/integration/modules/test_groupadd.py b/tests/integration/modules/test_groupadd.py index 58c1c88e204..60ae68e5d20 100644 --- a/tests/integration/modules/test_groupadd.py +++ b/tests/integration/modules/test_groupadd.py @@ -217,7 +217,7 @@ class GroupModuleTest(ModuleCase): self.run_function("group.add", [self._group], gid=self._gid) self.run_function("user.add", [self._user]) self.run_function("user.add", [self._user1]) - m = "{},{}".format(self._user, self._user1) + m = f"{self._user},{self._user1}" ret = self.run_function("group.members", [self._group, m]) self.assertTrue(ret) group_info = self.run_function("group.info", [self._group]) diff --git a/tests/integration/modules/test_linux_shadow.py b/tests/integration/modules/test_linux_shadow.py index aaea75d8e45..c922cb2f618 100644 --- a/tests/integration/modules/test_linux_shadow.py +++ b/tests/integration/modules/test_linux_shadow.py @@ -27,7 +27,7 @@ class ShadowModuleTest(ModuleCase): """ self._password = self.run_function("shadow.gen_password", ["Password1234"]) if "ERROR" in self._password: - self.fail("Failed to generate password: {}".format(self._password)) + self.fail(f"Failed to generate password: {self._password}") super().setUp() self._no_user = random_string("tu-", uppercase=False) self._test_user = random_string("tu-", uppercase=False) diff --git a/tests/integration/modules/test_lxc.py b/tests/integration/modules/test_lxc.py index b2f9b7945da..08f8cd3c14a 100644 --- a/tests/integration/modules/test_lxc.py +++ b/tests/integration/modules/test_lxc.py @@ -90,11 +90,11 @@ class LXCModuleTest(ModuleCase): start=False, ) - f = "/var/lib/lxc/{}/config".format(self.prefix) + f = f"/var/lib/lxc/{self.prefix}/config" conf = self.run_function("lxc.read_conf", [f]) # Due to a segfault in lxc-destroy caused by invalid configs, # truncate the config. - self.run_function("cmd.run", ["truncate -s 0 {}".format(f)]) + self.run_function("cmd.run", [f"truncate -s 0 {f}"]) self.assertEqual(conf.get("lxc.network.type"), "macvlan") diff --git a/tests/integration/modules/test_macdefaults.py b/tests/integration/modules/test_macdefaults.py index da7a6ef854d..bdd74901628 100644 --- a/tests/integration/modules/test_macdefaults.py +++ b/tests/integration/modules/test_macdefaults.py @@ -1,6 +1,7 @@ """ Validate the mac-defaults module """ + import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/modules/test_mine.py b/tests/integration/modules/test_mine.py index c5e4bef5cc4..88a1d8b3a2c 100644 --- a/tests/integration/modules/test_mine.py +++ b/tests/integration/modules/test_mine.py @@ -46,13 +46,13 @@ class MineTest(ModuleCase, ShellCase): # sub_minion should be able to view test.arg data sub_min_ret = self.run_call( - "mine.get {} test.arg".format(self.tgt), + f"mine.get {self.tgt} test.arg", config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR, ) assert " - isn't" in sub_min_ret # minion should not be able to view test.arg data - min_ret = self.run_call("mine.get {} test.arg".format(self.tgt)) + min_ret = self.run_call(f"mine.get {self.tgt} test.arg") assert " - isn't" not in min_ret @pytest.mark.slow_test @@ -68,9 +68,9 @@ class MineTest(ModuleCase, ShellCase): allow_tgt="sub_minion", minion_tgt=minion, ) - min_ret = self.run_call("mine.get {} {}".format(self.tgt, mine_name)) + min_ret = self.run_call(f"mine.get {self.tgt} {mine_name}") sub_ret = self.run_call( - "mine.get {} {}".format(self.tgt, mine_name), + f"mine.get {self.tgt} {mine_name}", config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR, ) @@ -94,9 +94,9 @@ class MineTest(ModuleCase, ShellCase): allow_tgt_type="compound", minion_tgt=minion, ) - min_ret = self.run_call("mine.get {} {}".format(self.tgt, mine_name)) + min_ret = self.run_call(f"mine.get {self.tgt} {mine_name}") sub_ret = self.run_call( - "mine.get {} {}".format(self.tgt, mine_name), + f"mine.get {self.tgt} {mine_name}", config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR, ) @@ -119,9 +119,9 @@ class MineTest(ModuleCase, ShellCase): allow_tgt="doesnotexist", minion_tgt=minion, ) - min_ret = self.run_call("mine.get {} {}".format(self.tgt, mine_name)) + min_ret = self.run_call(f"mine.get {self.tgt} {mine_name}") sub_ret = self.run_call( - "mine.get {} {}".format(self.tgt, mine_name), + f"mine.get {self.tgt} {mine_name}", config_dir=RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR, ) diff --git a/tests/integration/modules/test_mysql.py b/tests/integration/modules/test_mysql.py index 826a91df78c..fe769b129a6 100644 --- a/tests/integration/modules/test_mysql.py +++ b/tests/integration/modules/test_mysql.py @@ -72,14 +72,14 @@ class MysqlModuleDbTest(ModuleCase, SaltReturnAssertsMixin): """ ret = self.run_function("mysql.db_create", name=db_name, **kwargs) self.assertEqual( - True, ret, "Problem while creating db for db name: '{}'".format(db_name) + True, ret, f"Problem while creating db for db name: '{db_name}'" ) # test db exists ret = self.run_function("mysql.db_exists", name=db_name, **kwargs) self.assertEqual( True, ret, - "Problem while testing db exists for db name: '{}'".format(db_name), + f"Problem while testing db exists for db name: '{db_name}'", ) # List db names to ensure db is created with the right utf8 string ret = self.run_function("mysql.db_list", **kwargs) @@ -115,7 +115,7 @@ class MysqlModuleDbTest(ModuleCase, SaltReturnAssertsMixin): # Now remove database ret = self.run_function("mysql.db_remove", name=db_name, **kwargs) self.assertEqual( - True, ret, "Problem while removing db for db name: '{}'".format(db_name) + True, ret, f"Problem while removing db for db name: '{db_name}'" ) @pytest.mark.destructive_test @@ -694,7 +694,7 @@ class MysqlModuleUserTest(ModuleCase, SaltReturnAssertsMixin): password=None, new_password=None, new_password_hash=None, - **kwargs + **kwargs, ): """ Perform some tests around creation of the given user @@ -760,7 +760,7 @@ class MysqlModuleUserTest(ModuleCase, SaltReturnAssertsMixin): ) if not isinstance(ret, dict): raise AssertionError( - "Unexpected result while retrieving user_info for '{}'".format(user) + f"Unexpected result while retrieving user_info for '{user}'" ) self.assertEqual(ret["Host"], host) self.assertEqual(ret["Password"], check_hash) @@ -1489,7 +1489,7 @@ class MysqlModuleUserGrantTest(ModuleCase, SaltReturnAssertsMixin): user=user, grant_option=grant_option, escape=escape, - **kwargs + **kwargs, ) self.assertEqual( True, @@ -1505,7 +1505,7 @@ class MysqlModuleUserGrantTest(ModuleCase, SaltReturnAssertsMixin): user=user, grant_option=grant_option, escape=escape, - **kwargs + **kwargs, ) self.assertEqual( True, diff --git a/tests/integration/modules/test_test.py b/tests/integration/modules/test_test.py index f9849e3a48c..06f9d23341c 100644 --- a/tests/integration/modules/test_test.py +++ b/tests/integration/modules/test_test.py @@ -82,7 +82,10 @@ class TestModuleTest(ModuleCase, AdaptedConfigurationTestCaseMixin): test.collatz """ self.assertEqual( - self.run_function("test.collatz", ["40"],)[ + self.run_function( + "test.collatz", + ["40"], + )[ 0 ][-1], 2, diff --git a/tests/integration/modules/test_timezone.py b/tests/integration/modules/test_timezone.py index 8d7180cbd13..3af9bf628ec 100644 --- a/tests/integration/modules/test_timezone.py +++ b/tests/integration/modules/test_timezone.py @@ -3,6 +3,7 @@ Integration tests for timezone module Linux and Solaris are supported """ + import pytest from tests.support.case import ModuleCase diff --git a/tests/integration/pillar/test_git_pillar.py b/tests/integration/pillar/test_git_pillar.py index 68c14daaa15..89835a069f8 100644 --- a/tests/integration/pillar/test_git_pillar.py +++ b/tests/integration/pillar/test_git_pillar.py @@ -686,7 +686,7 @@ class GitPythonMixin: @pytest.mark.skipif( - not HAS_GITPYTHON, reason="GitPython >= {} required".format(GITPYTHON_MINVER) + not HAS_GITPYTHON, reason=f"GitPython >= {GITPYTHON_MINVER} required" ) @pytest.mark.usefixtures("ssh_pillar_tests_prep") @pytest.mark.destructive_test @@ -704,7 +704,7 @@ class TestGitPythonSSH(GitPillarSSHTestBase, GitPythonMixin): @pytest.mark.skipif( - not HAS_GITPYTHON, reason="GitPython >= {} required".format(GITPYTHON_MINVER) + not HAS_GITPYTHON, reason=f"GitPython >= {GITPYTHON_MINVER} required" ) @pytest.mark.usefixtures("webserver_pillar_tests_prep") class TestGitPythonHTTP(GitPillarHTTPTestBase, GitPythonMixin): @@ -714,7 +714,7 @@ class TestGitPythonHTTP(GitPillarHTTPTestBase, GitPythonMixin): @pytest.mark.skipif( - not HAS_GITPYTHON, reason="GitPython >= {} required".format(GITPYTHON_MINVER) + not HAS_GITPYTHON, reason=f"GitPython >= {GITPYTHON_MINVER} required" ) @pytest.mark.usefixtures("webserver_pillar_tests_prep_authenticated") class TestGitPythonAuthenticatedHTTP(TestGitPythonHTTP, GitPythonMixin): diff --git a/tests/integration/runners/test_runner_returns.py b/tests/integration/runners/test_runner_returns.py index 849c7aa1e4d..a2ecaf5a51b 100644 --- a/tests/integration/runners/test_runner_returns.py +++ b/tests/integration/runners/test_runner_returns.py @@ -129,7 +129,7 @@ class RunnerReturnsTest(ShellCase): else: user = RUNTIME_VARS.RUNNING_TESTS_USER if salt.utils.platform.is_windows(): - user = "sudo_{}\\{}".format(socket.gethostname(), user) + user = f"sudo_{socket.gethostname()}\\{user}" self.assertEqual( deserialized, { diff --git a/tests/integration/shell/test_master_tops.py b/tests/integration/shell/test_master_tops.py index 27625a4ff60..ac419de96b6 100644 --- a/tests/integration/shell/test_master_tops.py +++ b/tests/integration/shell/test_master_tops.py @@ -3,7 +3,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import pytest from tests.support.case import ShellCase diff --git a/tests/integration/shell/test_spm.py b/tests/integration/shell/test_spm.py index 991e335e29c..156497cdec4 100644 --- a/tests/integration/shell/test_spm.py +++ b/tests/integration/shell/test_spm.py @@ -41,9 +41,9 @@ class SPMTest(ShellCase, SPMCase): spm_file = os.path.join(config["spm_build_dir"], "apache-201506-2.spm") - build = self.run_spm("build {} -c {}".format(self.formula_dir, self._tmp_spm)) + build = self.run_spm(f"build {self.formula_dir} -c {self._tmp_spm}") - install = self.run_spm("install {} -c {} -y".format(spm_file, self._tmp_spm)) + install = self.run_spm(f"install {spm_file} -c {self._tmp_spm} -y") self.assertTrue( os.path.exists(os.path.join(config["formula_path"], "apache", "apache.sls")) @@ -59,15 +59,15 @@ class SPMTest(ShellCase, SPMCase): spm_file = os.path.join(config["spm_build_dir"], "apache-201506-2.spm") - build = self.run_spm("build {} -c {}".format(self.formula_dir, self._tmp_spm)) + build = self.run_spm(f"build {self.formula_dir} -c {self._tmp_spm}") - install = self.run_spm("install {} -c {} -y".format(spm_file, self._tmp_spm)) + install = self.run_spm(f"install {spm_file} -c {self._tmp_spm} -y") self.assertTrue( os.path.exists(os.path.join(config["formula_path"], "apache", "apache.sls")) ) # check if it forces the install after its already been installed it - install = self.run_spm("install {} -c {} -y -f".format(spm_file, self._tmp_spm)) + install = self.run_spm(f"install {spm_file} -c {self._tmp_spm} -y -f") self.assertEqual(["... installing apache"], install) diff --git a/tests/integration/spm/test_install.py b/tests/integration/spm/test_install.py index c73f6639230..bd4d3617694 100644 --- a/tests/integration/spm/test_install.py +++ b/tests/integration/spm/test_install.py @@ -1,6 +1,7 @@ """ Tests for the spm install utility """ + import os import pytest diff --git a/tests/integration/states/test_boto_sns.py b/tests/integration/states/test_boto_sns.py index c40adbdba5f..f3a255047f9 100644 --- a/tests/integration/states/test_boto_sns.py +++ b/tests/integration/states/test_boto_sns.py @@ -1,6 +1,7 @@ """ Tests for the boto_sns state """ + import re import pytest @@ -44,9 +45,7 @@ class BotoSNSTest(ModuleCase, SaltReturnAssertsMixin): ret = self.run_state("boto_sns.present", name=self.topic_name) self.assertSaltTrueReturn(ret) self.assertInSaltReturn(self.topic_name, ret, "name") - self.assertInSaltComment( - "AWS SNS topic {} created.".format(self.topic_name), ret - ) + self.assertInSaltComment(f"AWS SNS topic {self.topic_name} created.", ret) self.assertSaltStateChangesEqual( ret, {"old": None, "new": {"topic": self.topic_name, "subscriptions": []}} ) @@ -130,9 +129,7 @@ class BotoSNSTest(ModuleCase, SaltReturnAssertsMixin): self.assertSaltTrueReturn(ret) self.assertInSaltReturn(self.topic_name, ret, "name") - self.assertInSaltComment( - "AWS SNS topic {} present.".format(self.topic_name), ret - ) + self.assertInSaltComment(f"AWS SNS topic {self.topic_name} present.", ret) self.assertInSaltComment( "AWS SNS subscription https:https://www.example.com/sns/endpoint already" " set on topic {}.".format(self.topic_name), @@ -234,7 +231,7 @@ class BotoSNSTest(ModuleCase, SaltReturnAssertsMixin): self.assertSaltNoneReturn(ret) self.assertInSaltReturn(self.topic_name, ret, "name") self.assertInSaltComment( - "AWS SNS topic {} is set to be created.".format(self.topic_name), ret + f"AWS SNS topic {self.topic_name} is set to be created.", ret ) self.assertSaltStateChangesEqual(ret, {}) ret = self.run_function("boto_sns.exists", name=self.topic_name) @@ -270,7 +267,7 @@ class BotoSNSTest(ModuleCase, SaltReturnAssertsMixin): self.assertSaltTrueReturn(ret) self.assertInSaltReturn(self.topic_name, ret, "name") self.assertInSaltComment( - "AWS SNS topic {} does not exist.".format(self.topic_name), ret + f"AWS SNS topic {self.topic_name} does not exist.", ret ) self.assertSaltStateChangesEqual(ret, {}) @@ -280,7 +277,7 @@ class BotoSNSTest(ModuleCase, SaltReturnAssertsMixin): self.assertSaltTrueReturn(ret) self.assertInSaltReturn(self.topic_name, ret, "name") self.assertInSaltComment( - "AWS SNS topic {} does not exist.".format(self.topic_name), ret + f"AWS SNS topic {self.topic_name} does not exist.", ret ) self.assertSaltStateChangesEqual( ret, {"new": None, "old": {"topic": self.topic_name}} @@ -292,7 +289,7 @@ class BotoSNSTest(ModuleCase, SaltReturnAssertsMixin): self.assertSaltNoneReturn(ret) self.assertInSaltReturn(self.topic_name, ret, "name") self.assertInSaltComment( - "AWS SNS topic {} is set to be removed.".format(self.topic_name), ret + f"AWS SNS topic {self.topic_name} is set to be removed.", ret ) self.assertSaltStateChangesEqual(ret, {}) ret = self.run_function("boto_sns.exists", name=self.topic_name) diff --git a/tests/integration/states/test_compiler.py b/tests/integration/states/test_compiler.py index ea64759e26d..257655fae91 100644 --- a/tests/integration/states/test_compiler.py +++ b/tests/integration/states/test_compiler.py @@ -2,7 +2,6 @@ tests for host state """ - from tests.support.case import ModuleCase diff --git a/tests/integration/states/test_git.py b/tests/integration/states/test_git.py index dba4340dabd..19cb08f12d2 100644 --- a/tests/integration/states/test_git.py +++ b/tests/integration/states/test_git.py @@ -237,7 +237,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): name=TEST_REPO, rev="develop", target=target, - unless="test -e {}".format(target), + unless=f"test -e {target}", submodules=True, ) self.assertSaltTrueReturn(ret) @@ -495,7 +495,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): assert ret["result"] # Now remove the tag - self.run_function("git.push", [admin_dir, "origin", ":{}".format(tag1)]) + self.run_function("git.push", [admin_dir, "origin", f":{tag1}"]) # Add and push another tag self.run_function("git.tag", [admin_dir, tag2]) self.run_function("git.push", [admin_dir, "origin", tag2]) @@ -541,29 +541,29 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ret = self.run_state("git.cloned", name=TEST_REPO, target=target, test=True) ret = ret[next(iter(ret))] assert ret["result"] is None - assert ret["changes"] == {"new": "{} => {}".format(TEST_REPO, target)} - assert ret["comment"] == "{} would be cloned to {}".format(TEST_REPO, target) + assert ret["changes"] == {"new": f"{TEST_REPO} => {target}"} + assert ret["comment"] == f"{TEST_REPO} would be cloned to {target}" # Now actually run the state ret = self.run_state("git.cloned", name=TEST_REPO, target=target) ret = ret[next(iter(ret))] assert ret["result"] is True - assert ret["changes"] == {"new": "{} => {}".format(TEST_REPO, target)} - assert ret["comment"] == "{} cloned to {}".format(TEST_REPO, target) + assert ret["changes"] == {"new": f"{TEST_REPO} => {target}"} + assert ret["comment"] == f"{TEST_REPO} cloned to {target}" # Run the state again to test idempotence ret = self.run_state("git.cloned", name=TEST_REPO, target=target) ret = ret[next(iter(ret))] assert ret["result"] is True assert not ret["changes"] - assert ret["comment"] == "Repository already exists at {}".format(target) + assert ret["comment"] == f"Repository already exists at {target}" # Run the state again to test idempotence (test mode) ret = self.run_state("git.cloned", name=TEST_REPO, target=target, test=True) ret = ret[next(iter(ret))] assert not ret["changes"] assert ret["result"] is True - assert ret["comment"] == "Repository already exists at {}".format(target) + assert ret["comment"] == f"Repository already exists at {target}" @with_tempdir(create=False) @pytest.mark.slow_test @@ -581,7 +581,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ) ret = ret[next(iter(ret))] assert ret["result"] is None - assert ret["changes"] == {"new": "{} => {}".format(TEST_REPO, target)} + assert ret["changes"] == {"new": f"{TEST_REPO} => {target}"} assert ret["comment"] == "{} would be cloned to {} with branch '{}'".format( TEST_REPO, target, old_branch ) @@ -592,7 +592,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ) ret = ret[next(iter(ret))] assert ret["result"] is True - assert ret["changes"] == {"new": "{} => {}".format(TEST_REPO, target)} + assert ret["changes"] == {"new": f"{TEST_REPO} => {target}"} assert ret["comment"] == "{} cloned to {} with branch '{}'".format( TEST_REPO, target, old_branch ) @@ -630,7 +630,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ret = ret[next(iter(ret))] assert ret["result"] is None assert ret["changes"] == {"branch": {"old": old_branch, "new": new_branch}} - assert ret["comment"] == "Branch would be changed to '{}'".format(new_branch) + assert ret["comment"] == f"Branch would be changed to '{new_branch}'" # Now really change the branch ret = self.run_state( @@ -639,7 +639,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ret = ret[next(iter(ret))] assert ret["result"] is True assert ret["changes"] == {"branch": {"old": old_branch, "new": new_branch}} - assert ret["comment"] == "Branch changed to '{}'".format(new_branch) + assert ret["comment"] == f"Branch changed to '{new_branch}'" # Change back to original branch. This tests that we don't attempt to # checkout a new branch (i.e. git checkout -b) for a branch that exists @@ -650,7 +650,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ret = ret[next(iter(ret))] assert ret["result"] is True assert ret["changes"] == {"branch": {"old": new_branch, "new": old_branch}} - assert ret["comment"] == "Branch changed to '{}'".format(old_branch) + assert ret["comment"] == f"Branch changed to '{old_branch}'" # Test switching to a nonexistent branch. This should fail. ret = self.run_state( @@ -659,9 +659,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): ret = ret[next(iter(ret))] assert ret["result"] is False assert not ret["changes"] - assert ret["comment"].startswith( - "Failed to change branch to '{}':".format(bad_branch) - ) + assert ret["comment"].startswith(f"Failed to change branch to '{bad_branch}':") @with_tempdir(create=False) @ensure_min_git(min_version="1.7.10") @@ -739,7 +737,7 @@ class GitTest(ModuleCase, SaltReturnAssertsMixin): name="user.name", value="foo bar", repo=name, - **{"global": False} + **{"global": False}, ) self.assertSaltTrueReturn(ret) @@ -966,7 +964,7 @@ class LocalRepoGitTest(ModuleCase, SaltReturnAssertsMixin): ) self.assertEqual( ret[next(iter(ret))]["changes"], - {"new": "{} => {}".format(self.repo, self.target)}, + {"new": f"{self.repo} => {self.target}"}, ) # Run git.latest state again. This should fail again, with a different diff --git a/tests/integration/states/test_handle_iorder.py b/tests/integration/states/test_handle_iorder.py index 39a5e88fe32..7bdd4a0d0df 100644 --- a/tests/integration/states/test_handle_iorder.py +++ b/tests/integration/states/test_handle_iorder.py @@ -2,7 +2,6 @@ tests for host state """ - from tests.support.case import ModuleCase diff --git a/tests/integration/states/test_host.py b/tests/integration/states/test_host.py index f80ed37416f..e351f52fc35 100644 --- a/tests/integration/states/test_host.py +++ b/tests/integration/states/test_host.py @@ -50,4 +50,4 @@ class HostTest(ModuleCase, SaltReturnAssertsMixin): self.assertSaltTrueReturn(ret) with salt.utils.files.fopen(self.hosts_file) as fp_: output = salt.utils.stringutils.to_unicode(fp_.read()) - self.assertIn("{}\t\t{}".format(ip, name), output) + self.assertIn(f"{ip}\t\t{name}", output) diff --git a/tests/integration/states/test_lxd_image.py b/tests/integration/states/test_lxd_image.py index 374aac57762..b0ab485bdf3 100644 --- a/tests/integration/states/test_lxd_image.py +++ b/tests/integration/states/test_lxd_image.py @@ -1,6 +1,7 @@ """ Integration tests for the lxd states """ + import pytest import salt.modules.lxd diff --git a/tests/integration/states/test_lxd_profile.py b/tests/integration/states/test_lxd_profile.py index cfcc24d968d..e6df9db2ef8 100644 --- a/tests/integration/states/test_lxd_profile.py +++ b/tests/integration/states/test_lxd_profile.py @@ -1,6 +1,7 @@ """ Integration tests for the lxd states """ + import pytest import salt.modules.lxd diff --git a/tests/integration/states/test_reg.py b/tests/integration/states/test_reg.py index 94f17d8dad4..2fca4c52b18 100644 --- a/tests/integration/states/test_reg.py +++ b/tests/integration/states/test_reg.py @@ -43,7 +43,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # Does the state return the correct data ret = self.run_state( "reg.present", - name="HKLM\\{}".format(FAKE_KEY), + name=f"HKLM\\{FAKE_KEY}", vname="test_reg_sz", vdata="fake string data", ) @@ -52,7 +52,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): "Added": { "Entry": "test_reg_sz", "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": "fake string data", @@ -83,7 +83,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # Does the state return the correct data ret = self.run_state( "reg.present", - name="HKLM\\{}".format(FAKE_KEY), + name=f"HKLM\\{FAKE_KEY}", vname="test_reg_sz", vdata=UNICODE_VALUE, ) @@ -92,7 +92,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): "Added": { "Entry": "test_reg_sz", "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": UNICODE_VALUE, @@ -122,14 +122,14 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # default type is 'REG_SZ' # Does the state return the correct data ret = self.run_state( - "reg.present", name="HKLM\\{}".format(FAKE_KEY), vdata=UNICODE_VALUE + "reg.present", name=f"HKLM\\{FAKE_KEY}", vdata=UNICODE_VALUE ) expected = { "reg": { "Added": { "Entry": "(Default)", "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": UNICODE_VALUE, @@ -161,7 +161,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # Does the state return the correct data ret = self.run_state( "reg.present", - name="HKLM\\{}".format(FAKE_KEY), + name=f"HKLM\\{FAKE_KEY}", vname=UNICODE_VALUE_NAME, vdata="fake string data", ) @@ -170,7 +170,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): "Added": { "Entry": UNICODE_VALUE_NAME, "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": "fake string data", @@ -203,7 +203,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # Does the state return the correct data ret = self.run_state( "reg.present", - name="HKLM\\{}".format(FAKE_KEY), + name=f"HKLM\\{FAKE_KEY}", vname="test_reg_binary", vtype="REG_BINARY", vdata=test_data, @@ -213,7 +213,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): "Added": { "Entry": "test_reg_binary", "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": test_data, @@ -244,7 +244,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # Does the state return the correct data ret = self.run_state( "reg.present", - name="HKLM\\{}".format(FAKE_KEY), + name=f"HKLM\\{FAKE_KEY}", vname="test_reg_multi_sz", vtype="REG_MULTI_SZ", vdata=["item1", "item2"], @@ -254,7 +254,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): "Added": { "Entry": "test_reg_multi_sz", "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": ["item1", "item2"], @@ -285,7 +285,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): # Does the state return the correct data ret = self.run_state( "reg.present", - name="HKLM\\{}".format(FAKE_KEY), + name=f"HKLM\\{FAKE_KEY}", vname="test_reg_sz", vdata="fake string data", use_32bit_registry=True, @@ -296,7 +296,7 @@ class RegTest(ModuleCase, SaltReturnAssertsMixin): "Added": { "Entry": "test_reg_sz", "Inheritance": True, - "Key": "HKLM\\{}".format(FAKE_KEY), + "Key": f"HKLM\\{FAKE_KEY}", "Owner": None, "Perms": {"Deny": None, "Grant": None}, "Value": "fake string data", diff --git a/tests/integration/states/test_ssh_known_hosts.py b/tests/integration/states/test_ssh_known_hosts.py index d5e7b8b25bb..3486d0cfd1b 100644 --- a/tests/integration/states/test_ssh_known_hosts.py +++ b/tests/integration/states/test_ssh_known_hosts.py @@ -86,16 +86,14 @@ class SSHKnownHostsStateTest(ModuleCase, SaltReturnAssertsMixin): try: self.assertNotIn(ret, ("", None)) except AssertionError: - raise AssertionError("Salt return '{}' is in ('', None).".format(ret)) + raise AssertionError(f"Salt return '{ret}' is in ('', None).") ret = self.run_function( "ssh.get_known_host_entries", ["root", GITHUB_IP], config=self.known_hosts )[0] try: self.assertNotIn(ret, ("", None, {})) except AssertionError: - raise AssertionError( - "Salt return '{}' is in ('', None,".format(ret) + " {})" - ) + raise AssertionError(f"Salt return '{ret}' is in ('', None," + " {})") @pytest.mark.slow_test def test_present_fail(self): @@ -117,9 +115,7 @@ class SSHKnownHostsStateTest(ModuleCase, SaltReturnAssertsMixin): known_hosts = os.path.join(RUNTIME_VARS.FILES, "ssh", "known_hosts") shutil.copyfile(known_hosts, self.known_hosts) if not os.path.isfile(self.known_hosts): - self.skipTest( - "Unable to copy {} to {}".format(known_hosts, self.known_hosts) - ) + self.skipTest(f"Unable to copy {known_hosts} to {self.known_hosts}") kwargs = {"name": "github.com", "user": "root", "config": self.known_hosts} # test first diff --git a/tests/integration/states/test_x509.py b/tests/integration/states/test_x509.py index 6337df80ccd..228afce78f8 100644 --- a/tests/integration/states/test_x509.py +++ b/tests/integration/states/test_x509.py @@ -214,7 +214,7 @@ class x509Test(ModuleCase, SaltReturnAssertsMixin): assert "Revoked Certificates" in ret[key]["changes"]["New"] self.assertEqual( ret[key]["changes"]["Old"], - "{}/pki/ca.crl does not exist.".format(RUNTIME_VARS.TMP), + f"{RUNTIME_VARS.TMP}/pki/ca.crl does not exist.", ) @pytest.mark.slow_test @@ -261,7 +261,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== assert "Revoked Certificates" in ret[key]["changes"]["New"] self.assertEqual( ret[key]["changes"]["Old"], - "{}/pki/ca.crl is not a valid CRL.".format(RUNTIME_VARS.TMP), + f"{RUNTIME_VARS.TMP}/pki/ca.crl is not a valid CRL.", ) def test_cert_issue_not_before_not_after(self): @@ -321,7 +321,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== @with_tempfile(suffix=".crt", create=False) @with_tempfile(suffix=".key", create=False) def test_issue_41858(self, keyfile, crtfile): - ret_key = "x509_|-test_crt_|-{}_|-certificate_managed".format(crtfile) + ret_key = f"x509_|-test_crt_|-{crtfile}_|-certificate_managed" signing_policy = "no_such_policy" ret = self.run_function( "state.apply", @@ -351,7 +351,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== @with_tempfile(suffix=".crt", create=False) @with_tempfile(suffix=".key", create=False) def test_compound_match_minion_have_correct_grain_value(self, keyfile, crtfile): - ret_key = "x509_|-test_crt_|-{}_|-certificate_managed".format(crtfile) + ret_key = f"x509_|-test_crt_|-{crtfile}_|-certificate_managed" signing_policy = "compound_match" ret = self.run_function( "state.apply", @@ -385,7 +385,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== minion_tgt="sub_minion", ) - ret_key = "x509_|-test_crt_|-{}_|-certificate_managed".format(crtfile) + ret_key = f"x509_|-test_crt_|-{crtfile}_|-certificate_managed" signing_policy = "compound_match" self.run_function( "state.apply", @@ -418,7 +418,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== ["x509.self_signed"], pillar={"keyfile": keyfile, "crtfile": crtfile}, ) - key = "x509_|-self_signed_cert_|-{}_|-certificate_managed".format(crtfile) + key = f"x509_|-self_signed_cert_|-{crtfile}_|-certificate_managed" self.assertIn("New", first_run[key]["changes"]["Certificate"]) self.assertEqual( "Certificate is valid and up to date", @@ -461,7 +461,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== "days_remaining": 10, }, ) - key = "x509_|-self_signed_cert_|-{}_|-certificate_managed".format(crtfile) + key = f"x509_|-self_signed_cert_|-{crtfile}_|-certificate_managed" self.assertEqual( "Certificate is valid and up to date", first_run[key]["changes"]["Status"]["New"], @@ -522,7 +522,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== "subjectAltName": "DNS:alt.service.local", }, ) - key = "x509_|-self_signed_cert_|-{}_|-certificate_managed".format(crtfile) + key = f"x509_|-self_signed_cert_|-{crtfile}_|-certificate_managed" self.assertEqual( "Certificate is valid and up to date", first_run[key]["changes"]["Status"]["New"], @@ -612,7 +612,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== ["x509.self_signed_different_properties"], pillar={"keyfile": keyfile, "crtfile": crtfile, "fileMode": "0755"}, ) - key = "x509_|-self_signed_cert_|-{}_|-certificate_managed".format(crtfile) + key = f"x509_|-self_signed_cert_|-{crtfile}_|-certificate_managed" self.assertEqual( "Certificate is valid and up to date", first_run[key]["changes"]["Status"]["New"], @@ -657,7 +657,7 @@ c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== pillar={"keyfile": keyfile, "crtfile": bad_crtfile}, ) - key = "x509_|-self_signed_cert_|-{}_|-certificate_managed".format(bad_crtfile) + key = f"x509_|-self_signed_cert_|-{bad_crtfile}_|-certificate_managed" self.assertFalse(ret[key]["result"], "State should have failed.") self.assertEqual({}, ret[key]["changes"]) self.assertFalse( diff --git a/tests/integration/utils/test_idem.py b/tests/integration/utils/test_idem.py index c2b57b1ec14..eb2fcd83254 100644 --- a/tests/integration/utils/test_idem.py +++ b/tests/integration/utils/test_idem.py @@ -1,6 +1,7 @@ """ Test utility methods that the idem module and state share """ + from contextlib import contextmanager import pytest diff --git a/tests/integration/utils/test_smb.py b/tests/integration/utils/test_smb.py index 5f7db744242..8ef792d6340 100644 --- a/tests/integration/utils/test_smb.py +++ b/tests/integration/utils/test_smb.py @@ -1,6 +1,7 @@ """ Test utility methods that communicate with SMB shares. """ + import getpass import logging import os diff --git a/tests/integration/utils/test_win_runas.py b/tests/integration/utils/test_win_runas.py index 41d4169d945..bd498c2f622 100644 --- a/tests/integration/utils/test_win_runas.py +++ b/tests/integration/utils/test_win_runas.py @@ -92,7 +92,7 @@ class _ServiceManager(win32serviceutil.ServiceFramework): logger.exception(msg) exc_info = sys.exc_info() tb = traceback.format_tb(exc_info[2]) - servicemanager.LogErrorMsg("{} {} {}".format(msg, exc_info[1], tb)) + servicemanager.LogErrorMsg(f"{msg} {exc_info[1]} {tb}") @property def timeout_ms(self): @@ -118,7 +118,7 @@ class _ServiceManager(win32serviceutil.ServiceFramework): servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ""), ) - self.log_info("Starting Service {}".format(self._svc_name_)) + self.log_info(f"Starting Service {self._svc_name_}") monitor_thread = threading.Thread(target=self.target_thread) monitor_thread.start() while self.active: @@ -362,7 +362,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -390,7 +390,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -423,7 +423,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -455,7 +455,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -477,7 +477,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -499,7 +499,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -521,7 +521,7 @@ class RunAsTest(ModuleCase): "cmd.exe", "/C", "winrs", - "/r:{}".format(self.hostname), + f"/r:{self.hostname}", "python", RUNAS_PATH, ] @@ -552,7 +552,7 @@ class RunAsTest(ModuleCase): "-ComputerName", self.hostname, "-ScriptBlock", - "{{ python.exe {} }}".format(RUNAS_PATH), + f"{{ python.exe {RUNAS_PATH} }}", ] ) self.assertEqual(ret, 1) @@ -580,7 +580,7 @@ class RunAsTest(ModuleCase): "-ComputerName", self.hostname, "-ScriptBlock", - "{{ python.exe {} }}".format(RUNAS_PATH), + f"{{ python.exe {RUNAS_PATH} }}", ] ) self.assertEqual(ret, 1) @@ -611,7 +611,7 @@ class RunAsTest(ModuleCase): ) with salt.utils.files.fopen(RUNAS_PATH, "w") as fp: fp.write(runaspy) - cmd = "python.exe {}; exit $LASTEXITCODE".format(RUNAS_PATH) + cmd = f"python.exe {RUNAS_PATH}; exit $LASTEXITCODE" ret = subprocess.call(psrp_wrap.format(self.hostname, cmd), shell=True) # nosec self.assertEqual(ret, 0) @@ -639,7 +639,7 @@ class RunAsTest(ModuleCase): ) with salt.utils.files.fopen(RUNAS_PATH, "w") as fp: fp.write(runaspy) - cmd = "python.exe {}; exit $LASTEXITCODE".format(RUNAS_PATH) + cmd = f"python.exe {RUNAS_PATH}; exit $LASTEXITCODE" ret = subprocess.call(psrp_wrap.format(self.hostname, cmd), shell=True) # nosec self.assertEqual(ret, 0) diff --git a/tests/minionswarm.py b/tests/minionswarm.py index cb3cb0aa38d..2ace3c7a7d5 100644 --- a/tests/minionswarm.py +++ b/tests/minionswarm.py @@ -207,7 +207,7 @@ class Swarm: if not os.path.exists(path): os.makedirs(path) - print("Creating shared pki keys for the swarm on: {}".format(path)) + print(f"Creating shared pki keys for the swarm on: {path}") subprocess.call( "salt-key -c {0} --gen-keys minion --gen-keys-dir {0} " "--log-file {1} --user {2}".format( @@ -260,7 +260,7 @@ class Swarm: Clean up the config files """ for path in self.confs: - pidfile = "{}.pid".format(path) + pidfile = f"{path}.pid" try: try: with salt.utils.files.fopen(pidfile) as fp_: @@ -287,7 +287,7 @@ class MinionSwarm(Swarm): """ self.prep_configs() for path in self.confs: - cmd = "salt-minion -c {} --pid-file {}".format(path, "{}.pid".format(path)) + cmd = "salt-minion -c {} --pid-file {}".format(path, f"{path}.pid") if self.opts["foreground"]: cmd += " -l debug &" else: @@ -392,9 +392,7 @@ class MasterSwarm(Swarm): """ Do the master start """ - cmd = "salt-master -c {} --pid-file {}".format( - self.conf, "{}.pid".format(self.conf) - ) + cmd = "salt-master -c {} --pid-file {}".format(self.conf, f"{self.conf}.pid") if self.opts["foreground"]: cmd += " -l debug &" else: diff --git a/tests/modparser.py b/tests/modparser.py index 978b3ad7836..7e7882b1b9c 100644 --- a/tests/modparser.py +++ b/tests/modparser.py @@ -46,7 +46,7 @@ def mod_data(opts, full): try: finder.load_file(full) except ImportError as exc: - print("ImportError - {} (Reason: {})".format(full, exc), file=sys.stderr) + print(f"ImportError - {full} (Reason: {exc})", file=sys.stderr) return ret for name, mod in finder.modules.items(): basemod = name.split(".")[0] diff --git a/tests/packdump.py b/tests/packdump.py index d25b5454e73..e9b7b70096a 100644 --- a/tests/packdump.py +++ b/tests/packdump.py @@ -1,6 +1,7 @@ """ Simple script to dump the contents of msgpack files to the terminal """ + # pylint: disable=resource-leakage import os diff --git a/tests/pytests/conftest.py b/tests/pytests/conftest.py index ba3defb6cc8..a1cdac8c2be 100644 --- a/tests/pytests/conftest.py +++ b/tests/pytests/conftest.py @@ -2,6 +2,7 @@ tests.pytests.conftest ~~~~~~~~~~~~~~~~~~~~~~ """ + import asyncio import functools import inspect @@ -648,6 +649,7 @@ def io_loop(): # <---- Async Test Fixtures ------------------------------------------------------------------------------------------ + # ----- Helpers -----------------------------------------------------------------------------------------------------> @pytest.helpers.proxy.register def delta_proxy_minion_ids(): diff --git a/tests/pytests/functional/cache/helpers.py b/tests/pytests/functional/cache/helpers.py index cd90f0fefc7..49ddf32e406 100644 --- a/tests/pytests/functional/cache/helpers.py +++ b/tests/pytests/functional/cache/helpers.py @@ -138,7 +138,7 @@ def run_common_cache_tests(subtests, cache): ): with patch.dict( cache.modules._dict, - {"{}.updated".format(cache.driver): MagicMock(side_effect=SaltCacheError)}, + {f"{cache.driver}.updated": MagicMock(side_effect=SaltCacheError)}, ), pytest.raises(SaltCacheError): cache.updated(bank="kaboom", key="oops") diff --git a/tests/pytests/functional/cli/test_batch.py b/tests/pytests/functional/cli/test_batch.py index c82a0ef0a51..599ac70bccf 100644 --- a/tests/pytests/functional/cli/test_batch.py +++ b/tests/pytests/functional/cli/test_batch.py @@ -2,6 +2,7 @@ tests.pytests.functional.cli.test_batch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import salt.cli.batch import salt.config import salt.utils.jid diff --git a/tests/pytests/functional/cli/test_salt_cloud.py b/tests/pytests/functional/cli/test_salt_cloud.py index 0b661490bfe..4bd33bdc6c9 100644 --- a/tests/pytests/functional/cli/test_salt_cloud.py +++ b/tests/pytests/functional/cli/test_salt_cloud.py @@ -2,6 +2,7 @@ tests.pytests.integration.cli.test_salt_cloud ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import pytest pytest.importorskip("libcloud", reason="salt-cloud requires >= libcloud 0.11.4") diff --git a/tests/pytests/functional/formulas/test_docker.py b/tests/pytests/functional/formulas/test_docker.py index f48f03f5faa..d6b95c9df9d 100644 --- a/tests/pytests/functional/formulas/test_docker.py +++ b/tests/pytests/functional/formulas/test_docker.py @@ -1,6 +1,7 @@ """ Tests using docker formula """ + import pytest diff --git a/tests/pytests/functional/formulas/test_nginx.py b/tests/pytests/functional/formulas/test_nginx.py index f1d86091185..0cd8324893c 100644 --- a/tests/pytests/functional/formulas/test_nginx.py +++ b/tests/pytests/functional/formulas/test_nginx.py @@ -1,6 +1,7 @@ """ Tests using nginx formula """ + import pytest pytestmark = [ diff --git a/tests/pytests/functional/formulas/test_sudoers.py b/tests/pytests/functional/formulas/test_sudoers.py index 015d3a13472..caeace8d853 100644 --- a/tests/pytests/functional/formulas/test_sudoers.py +++ b/tests/pytests/functional/formulas/test_sudoers.py @@ -1,6 +1,7 @@ """ Tests using sudoers formula """ + import pytest diff --git a/tests/pytests/functional/formulas/test_vim.py b/tests/pytests/functional/formulas/test_vim.py index 2f0448e76d6..83d2354dff0 100644 --- a/tests/pytests/functional/formulas/test_vim.py +++ b/tests/pytests/functional/formulas/test_vim.py @@ -1,6 +1,7 @@ """ Tests using vim formula """ + import pytest diff --git a/tests/pytests/functional/loader/test_loaded_base_name.py b/tests/pytests/functional/loader/test_loaded_base_name.py index 56c2892c8d6..ff68ff72350 100644 --- a/tests/pytests/functional/loader/test_loaded_base_name.py +++ b/tests/pytests/functional/loader/test_loaded_base_name.py @@ -10,7 +10,7 @@ from salt.loader.lazy import LazyLoader @pytest.fixture(scope="module") def loaded_base_name(): - return random_string("{}.".format(__name__), digits=False, uppercase=False) + return random_string(f"{__name__}.", digits=False, uppercase=False) @pytest.fixture(scope="module") diff --git a/tests/pytests/functional/log_handlers/test_logstash_mod.py b/tests/pytests/functional/log_handlers/test_logstash_mod.py index dfc45a75824..426ad3a51dd 100644 --- a/tests/pytests/functional/log_handlers/test_logstash_mod.py +++ b/tests/pytests/functional/log_handlers/test_logstash_mod.py @@ -36,10 +36,10 @@ def zmq_server(): context = zmq.Context() server = context.socket(zmq.SUB) port = ports.get_unused_localhost_port() - handler = ZMQLogstashHander("tcp://127.0.0.1:{}".format(port)) + handler = ZMQLogstashHander(f"tcp://127.0.0.1:{port}") try: server.setsockopt(zmq.SUBSCRIBE, b"") - server.bind("tcp://127.0.0.1:{}".format(port)) + server.bind(f"tcp://127.0.0.1:{port}") logger.setLevel(logging.DEBUG) logger.addHandler(handler) diff --git a/tests/pytests/functional/modules/cmd/test_powershell.py b/tests/pytests/functional/modules/cmd/test_powershell.py index 62b17665640..f072a967e81 100644 --- a/tests/pytests/functional/modules/cmd/test_powershell.py +++ b/tests/pytests/functional/modules/cmd/test_powershell.py @@ -87,7 +87,7 @@ def test_cmd_run_all_powershell_string(): def test_cmd_run_encoded_cmd(shell): cmd = "Write-Output 'encoded command'" - cmd = "$ProgressPreference='SilentlyContinue'; {}".format(cmd) + cmd = f"$ProgressPreference='SilentlyContinue'; {cmd}" cmd_utf16 = cmd.encode("utf-16-le") encoded_cmd = base64.standard_b64encode(cmd_utf16) encoded_cmd = salt.utils.stringutils.to_str(encoded_cmd) @@ -97,7 +97,7 @@ def test_cmd_run_encoded_cmd(shell): def test_cmd_run_all_encoded_cmd(shell): cmd = "Write-Output 'encoded command'" - cmd = "$ProgressPreference='SilentlyContinue'; {}".format(cmd) + cmd = f"$ProgressPreference='SilentlyContinue'; {cmd}" cmd_utf16 = cmd.encode("utf-16-le") encoded_cmd = base64.standard_b64encode(cmd_utf16) encoded_cmd = salt.utils.stringutils.to_str(encoded_cmd) diff --git a/tests/pytests/functional/modules/cmd/test_runas.py b/tests/pytests/functional/modules/cmd/test_runas.py index 0d4cc020124..f226900de69 100644 --- a/tests/pytests/functional/modules/cmd/test_runas.py +++ b/tests/pytests/functional/modules/cmd/test_runas.py @@ -22,5 +22,5 @@ def configure_loader_modules(): @pytest.mark.skip_if_not_root def test_run_as(account): ret = cmdmod.run("id", runas=account.username) - assert "gid={}".format(account.info.gid) in ret - assert "uid={}".format(account.info.uid) in ret + assert f"gid={account.info.gid}" in ret + assert f"uid={account.info.uid}" in ret diff --git a/tests/pytests/functional/modules/file/test_replace.py b/tests/pytests/functional/modules/file/test_replace.py index 3be41d0661d..416ddfb1945 100644 --- a/tests/pytests/functional/modules/file/test_replace.py +++ b/tests/pytests/functional/modules/file/test_replace.py @@ -1,6 +1,7 @@ """ Tests for file.rename function """ + import os import shutil @@ -46,7 +47,7 @@ def multiline_file(tmp_path_factory, multiline_string): def test_no_backup(file, multiline_file): # Backup file should NOT be created - bak_file = "{}.bak".format(multiline_file) + bak_file = f"{multiline_file}.bak" assert "Salticus" not in multiline_file.read_text() file.replace(str(multiline_file), "Etiam", "Salticus", backup=False) assert "Salticus" in multiline_file.read_text() @@ -55,7 +56,7 @@ def test_no_backup(file, multiline_file): def test_backup(file, multiline_file): # Should create a backup file. This is basically the default - bak_file = "{}.bak".format(multiline_file) + bak_file = f"{multiline_file}.bak" file.replace(str(multiline_file), "Etiam", "Salticus") assert "Salticus" in multiline_file.read_text() assert os.path.exists(bak_file) diff --git a/tests/pytests/functional/modules/file/test_rmdir.py b/tests/pytests/functional/modules/file/test_rmdir.py index 0dd6bc0476b..cca9d273496 100644 --- a/tests/pytests/functional/modules/file/test_rmdir.py +++ b/tests/pytests/functional/modules/file/test_rmdir.py @@ -33,12 +33,7 @@ def nested_empty_dirs(tmp_path): for root in range(1, num_root + 1): for mid in range(1, num_mid + 1): for last in range(1, num_last + 1): - nest = ( - tmp_path - / "root{}".format(root) - / "mid{}".format(mid) - / "last{}".format(last) - ) + nest = tmp_path / f"root{root}" / f"mid{mid}" / f"last{last}" nest.mkdir(parents=True, exist_ok=True) if last % 2: now = time.time() @@ -55,12 +50,7 @@ def nested_dirs_with_files(tmp_path): for root in range(1, num_root + 1): for mid in range(1, num_mid + 1): for last in range(1, num_last + 1): - nest = ( - tmp_path - / "root{}".format(root) - / "mid{}".format(mid) - / "last{}".format(last) - ) + nest = tmp_path / f"root{root}" / f"mid{mid}" / f"last{last}" nest.mkdir(parents=True, exist_ok=True) if last % 2: last_file = nest / "stuff.txt" diff --git a/tests/pytests/functional/modules/file/test_symlink.py b/tests/pytests/functional/modules/file/test_symlink.py index 24e110dc41f..6d40d6e9160 100644 --- a/tests/pytests/functional/modules/file/test_symlink.py +++ b/tests/pytests/functional/modules/file/test_symlink.py @@ -116,7 +116,7 @@ def test_symlink_target_relative_path(file, source): Test symlink when the target file is a relative path Should throw a SaltInvocationError """ - target = "..{}symlink.lnk".format(os.path.sep) + target = f"..{os.path.sep}symlink.lnk" with pytest.raises(SaltInvocationError) as exc: file.symlink(str(source), str(target)) assert "Link path must be absolute" in exc.value.message diff --git a/tests/pytests/functional/modules/state/test_jinja_filters.py b/tests/pytests/functional/modules/state/test_jinja_filters.py index 0fd44dba74c..7a72ba7f530 100644 --- a/tests/pytests/functional/modules/state/test_jinja_filters.py +++ b/tests/pytests/functional/modules/state/test_jinja_filters.py @@ -1,6 +1,7 @@ """ Testing Jinja filters availablilty via state system """ + import logging import os diff --git a/tests/pytests/functional/modules/test_archive.py b/tests/pytests/functional/modules/test_archive.py index 60f06aef71f..1ec0a4e092f 100644 --- a/tests/pytests/functional/modules/test_archive.py +++ b/tests/pytests/functional/modules/test_archive.py @@ -1,6 +1,7 @@ """ Tests for the archive state """ + import os import pathlib import shutil @@ -45,7 +46,7 @@ class Archive: @src.default def _src(self): - return self.path / "{}_src_dir".format(self.fmt) + return self.path / f"{self.fmt}_src_dir" @src_file.default def _src_file(self): @@ -53,11 +54,11 @@ class Archive: @archive.default def _archive(self): - return self.path / "archive.{}".format(self.fmt) + return self.path / f"archive.{self.fmt}" @dst.default def _dst(self): - return self.path / "{}_dst_dir".format(self.fmt) + return self.path / f"{self.fmt}_dst_dir" @filename.default def _filename(self): @@ -150,7 +151,7 @@ def archive(modules): def unicode_filename_ids(value): - return "unicode_filename={}".format(value) + return f"unicode_filename={value}" @pytest.fixture(params=[True, False], ids=unicode_filename_ids) diff --git a/tests/pytests/functional/modules/test_dockermod.py b/tests/pytests/functional/modules/test_dockermod.py index 3c7bb25e461..7d66379de0c 100644 --- a/tests/pytests/functional/modules/test_dockermod.py +++ b/tests/pytests/functional/modules/test_dockermod.py @@ -1,6 +1,7 @@ """ Integration tests for the docker_container states """ + import logging import pytest diff --git a/tests/pytests/functional/modules/test_etcd_mod.py b/tests/pytests/functional/modules/test_etcd_mod.py index e1e1b552df2..6ec3017e94d 100644 --- a/tests/pytests/functional/modules/test_etcd_mod.py +++ b/tests/pytests/functional/modules/test_etcd_mod.py @@ -65,10 +65,9 @@ def test_basic_operations(subtests, profile_name, prefix): assert etcd_mod.get_(prefix, recurse=True, profile=profile_name) is None with subtests.test("We should be able to set and retrieve simple values"): - etcd_mod.set_("{}/1".format(prefix), "one", profile=profile_name) + etcd_mod.set_(f"{prefix}/1", "one", profile=profile_name) assert ( - etcd_mod.get_("{}/1".format(prefix), recurse=False, profile=profile_name) - == "one" + etcd_mod.get_(f"{prefix}/1", recurse=False, profile=profile_name) == "one" ) with subtests.test("We should be able to update and retrieve those values"): @@ -85,8 +84,8 @@ def test_basic_operations(subtests, profile_name, prefix): with subtests.test("We should be list all top level values at a directory"): expected = { prefix: { - "{}/1".format(prefix): "not one", - "{}/2/".format(prefix): {}, + f"{prefix}/1": "not one", + f"{prefix}/2/": {}, }, } assert etcd_mod.ls_(path=prefix, profile=profile_name) == expected @@ -98,7 +97,7 @@ def test_basic_operations(subtests, profile_name, prefix): "4": "two-four", }, } - etcd_mod.rm_("{}/1".format(prefix), profile=profile_name) + etcd_mod.rm_(f"{prefix}/1", profile=profile_name) assert etcd_mod.tree(path=prefix, profile=profile_name) == updated with subtests.test("updates should be able to be caught by waiting in read"): @@ -106,16 +105,16 @@ def test_basic_operations(subtests, profile_name, prefix): def wait_func(return_list): return_list.append( - etcd_mod.watch("{}/1".format(prefix), timeout=30, profile=profile_name) + etcd_mod.watch(f"{prefix}/1", timeout=30, profile=profile_name) ) wait_thread = threading.Thread(target=wait_func, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_mod.set_("{}/1".format(prefix), "one", profile=profile_name) + etcd_mod.set_(f"{prefix}/1", "one", profile=profile_name) wait_thread.join() modified = return_list.pop() - assert modified["key"] == "{}/1".format(prefix) + assert modified["key"] == f"{prefix}/1" assert modified["value"] == "one" @@ -126,22 +125,22 @@ def test_with_missing_profile(subtests, prefix, etcd_version, etcd_port): if etcd_version in (EtcdVersion.v2, EtcdVersion.v3_v2_mode) and etcd_port != 2379: # Only need to run this once with subtests.test("Test no profile and bad connection in get_"): - assert etcd_mod.get_("{}/1".format(prefix)) is None + assert etcd_mod.get_(f"{prefix}/1") is None with subtests.test("Test no profile and bad connection in set_"): - assert etcd_mod.set_("{}/1".format(prefix), "lol") is None + assert etcd_mod.set_(f"{prefix}/1", "lol") is None with subtests.test("Test no profile and bad connection in update"): - assert etcd_mod.update({"{}/1".format(prefix): "SIUUU"}) is None + assert etcd_mod.update({f"{prefix}/1": "SIUUU"}) is None with subtests.test("Test no profile and bad connection in watch"): - assert etcd_mod.watch("{}/1".format(prefix)) is None + assert etcd_mod.watch(f"{prefix}/1") is None with subtests.test("Test no profile and bad connection in ls_"): assert etcd_mod.ls_() is None with subtests.test("Test no profile and bad connection in rm"): - assert etcd_mod.rm_("{}/1".format(prefix)) is None + assert etcd_mod.rm_(f"{prefix}/1") is None with subtests.test("Test no profile and bad connection in tree"): assert etcd_mod.tree() is None diff --git a/tests/pytests/functional/modules/test_mac_pkgutil.py b/tests/pytests/functional/modules/test_mac_pkgutil.py index 397bb895871..6b9233c2ecd 100644 --- a/tests/pytests/functional/modules/test_mac_pkgutil.py +++ b/tests/pytests/functional/modules/test_mac_pkgutil.py @@ -1,6 +1,7 @@ """ integration tests for mac_pkgutil """ + import shutil import pytest diff --git a/tests/pytests/functional/modules/test_mysql.py b/tests/pytests/functional/modules/test_mysql.py index d920bbdbc03..c82bba30193 100644 --- a/tests/pytests/functional/modules/test_mysql.py +++ b/tests/pytests/functional/modules/test_mysql.py @@ -1,6 +1,7 @@ """ Test Salt MySQL module across various MySQL variants """ + import logging import time diff --git a/tests/pytests/functional/modules/test_network.py b/tests/pytests/functional/modules/test_network.py index 702373c15ae..ab6aef879e5 100644 --- a/tests/pytests/functional/modules/test_network.py +++ b/tests/pytests/functional/modules/test_network.py @@ -1,6 +1,7 @@ """ Validate network module """ + import pytest pytestmark = [ @@ -76,6 +77,4 @@ def test_network_nslookup(network, url): if out in val: exp_out.remove(out) if exp_out: - pytest.fail( - "Failed to find the {} key(s) on the returned data: {}".format(exp_out, ret) - ) + pytest.fail(f"Failed to find the {exp_out} key(s) on the returned data: {ret}") diff --git a/tests/pytests/functional/modules/test_opkg.py b/tests/pytests/functional/modules/test_opkg.py index 091db51ef03..243011d5e73 100644 --- a/tests/pytests/functional/modules/test_opkg.py +++ b/tests/pytests/functional/modules/test_opkg.py @@ -63,7 +63,7 @@ def test_conf_d_path_exists_with_files(tmp_path): conf_d_path = tmp_path / "conf.d.path" conf_d_path.mkdir(parents=True, exist_ok=True) file_one = conf_d_path / "file_one" - expected_md5sum = "d41d8cd98f00b204e9800998ecf8427e {}\n".format(file_one) + expected_md5sum = f"d41d8cd98f00b204e9800998ecf8427e {file_one}\n" expected_timestamp = "10000\n" file_one.touch() os.utime(str(file_one), (int(expected_timestamp), int(expected_timestamp))) diff --git a/tests/pytests/functional/modules/test_system.py b/tests/pytests/functional/modules/test_system.py index 2dabaaebfad..e5ae735fdd3 100644 --- a/tests/pytests/functional/modules/test_system.py +++ b/tests/pytests/functional/modules/test_system.py @@ -178,7 +178,7 @@ def test_get_system_date_time(setup_teardown_vars, system, fmt_str): t1 = datetime.datetime.now() res = system.get_system_date_time() t2 = datetime.datetime.strptime(res, fmt_str) - msg = "Difference in times is too large. Now: {} Fake: {}".format(t1, t2) + msg = f"Difference in times is too large. Now: {t1} Fake: {t2}" assert _same_times(t1, t2, seconds_diff=3), msg @@ -189,7 +189,7 @@ def test_get_system_date_time_utc(setup_teardown_vars, system, fmt_str): t1 = datetime.datetime.utcnow() res = system.get_system_date_time("+0000") t2 = datetime.datetime.strptime(res, fmt_str) - msg = "Difference in times is too large. Now: {} Fake: {}".format(t1, t2) + msg = f"Difference in times is too large. Now: {t1} Fake: {t2}" assert _same_times(t1, t2, seconds_diff=3), msg diff --git a/tests/pytests/functional/modules/test_win_dsc.py b/tests/pytests/functional/modules/test_win_dsc.py index 76255968631..c496d1857c9 100644 --- a/tests/pytests/functional/modules/test_win_dsc.py +++ b/tests/pytests/functional/modules/test_win_dsc.py @@ -167,7 +167,7 @@ def test_compile_config_missing(dsc): path = "C:\\Path\\not\\exists.ps1" with pytest.raises(salt.exceptions.CommandExecutionError) as exc: dsc.compile_config(path=path) - assert exc.value.message == "{} not found".format(path) + assert exc.value.message == f"{path} not found" @pytest.mark.destructive_test @@ -204,7 +204,7 @@ def test_apply_config_missing(dsc): path = "C:\\Path\\not\\exists" with pytest.raises(salt.exceptions.CommandExecutionError) as exc: dsc.apply_config(path=path) - assert exc.value.message == "{} not found".format(path) + assert exc.value.message == f"{path} not found" @pytest.mark.destructive_test diff --git a/tests/pytests/functional/modules/test_win_shortcut.py b/tests/pytests/functional/modules/test_win_shortcut.py index 292f439536b..604a7efa6b2 100644 --- a/tests/pytests/functional/modules/test_win_shortcut.py +++ b/tests/pytests/functional/modules/test_win_shortcut.py @@ -1,6 +1,7 @@ """ Tests for win_shortcut execution module """ + import os import shutil import subprocess @@ -127,7 +128,7 @@ def tmp_share(): remove_cmd = [ "powershell", "-command", - '"Remove-SmbShare -Name {} -Force" | Out-Null'.format(share_name), + f'"Remove-SmbShare -Name {share_name} -Force" | Out-Null', ] subprocess.run(create_cmd, check=True) @@ -342,7 +343,7 @@ def test_create_lnk_smb_issue_61170(shortcut, tmp_dir, tmp_share): hot_key="Alt+Ctrl+C", icon_index=0, icon_location=r"C:\Windows\notepad.exe", - target=r"\\localhost\{}".format(tmp_share), + target=rf"\\localhost\{tmp_share}", window_style="Normal", working_dir=r"C:\Windows", ) @@ -354,7 +355,7 @@ def test_create_lnk_smb_issue_61170(shortcut, tmp_dir, tmp_share): "icon_index": 0, "icon_location": r"C:\Windows\notepad.exe", "path": test_link, - "target": r"\\localhost\{}".format(tmp_share), + "target": rf"\\localhost\{tmp_share}", "window_style": "Normal", "working_dir": r"C:\Windows", } @@ -449,7 +450,7 @@ def test_create_backup(shortcut, tmp_lnk): } result = shortcut.get(path=str(tmp_lnk)) assert result == expected - assert len(list(tmp_lnk.parent.glob("{}-*.lnk".format(tmp_lnk.stem)))) == 1 + assert len(list(tmp_lnk.parent.glob(f"{tmp_lnk.stem}-*.lnk"))) == 1 def test_create_make_dirs(shortcut, tmp_dir): diff --git a/tests/pytests/functional/modules/win_file/test_check_perms.py b/tests/pytests/functional/modules/win_file/test_check_perms.py index 7b829b35eed..f2196185904 100644 --- a/tests/pytests/functional/modules/win_file/test_check_perms.py +++ b/tests/pytests/functional/modules/win_file/test_check_perms.py @@ -1,6 +1,7 @@ """ Tests for win_file execution module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/functional/modules/win_file/test_remove.py b/tests/pytests/functional/modules/win_file/test_remove.py index 6cc26686f5a..d9e92411ca2 100644 --- a/tests/pytests/functional/modules/win_file/test_remove.py +++ b/tests/pytests/functional/modules/win_file/test_remove.py @@ -1,6 +1,7 @@ """ Tests for win_file execution module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/functional/modules/win_file/test_stat.py b/tests/pytests/functional/modules/win_file/test_stat.py index 0ff78e85fb7..a09d7d43aa9 100644 --- a/tests/pytests/functional/modules/win_file/test_stat.py +++ b/tests/pytests/functional/modules/win_file/test_stat.py @@ -1,6 +1,7 @@ """ Tests for win_file execution module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/functional/modules/win_lgpo/test_audit_settings_module.py b/tests/pytests/functional/modules/win_lgpo/test_audit_settings_module.py index 2830c7a7d27..978fe1e4c44 100644 --- a/tests/pytests/functional/modules/win_lgpo/test_audit_settings_module.py +++ b/tests/pytests/functional/modules/win_lgpo/test_audit_settings_module.py @@ -42,7 +42,7 @@ def clean_adv_audit(): # - C:\Windows\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit win_dir = os.environ.get("WINDIR") audit_csv_files = [ - r"{}\security\audit\audit.csv".format(win_dir), + rf"{win_dir}\security\audit\audit.csv", r"{}\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit\audit.csv".format( win_dir ), diff --git a/tests/pytests/functional/netapi/rest_cherrypy/test_auth.py b/tests/pytests/functional/netapi/rest_cherrypy/test_auth.py index bd348430bf2..0e4ae4e6841 100644 --- a/tests/pytests/functional/netapi/rest_cherrypy/test_auth.py +++ b/tests/pytests/functional/netapi/rest_cherrypy/test_auth.py @@ -56,7 +56,7 @@ async def test_good_login(http_client, auth_creds, content_type_map, client_conf cookies = response.headers["Set-Cookie"] response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"]["auto"][auth_creds["username"]] assert set(perms) == set(perms_config) diff --git a/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py b/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py index 7344adb383d..073d0b390e2 100644 --- a/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py +++ b/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py @@ -14,7 +14,7 @@ pytestmark = [ ACCOUNT_USERNAME = "saltdev-syntax" -ACCOUNT_GROUP_NAME = "{}-group".format(ACCOUNT_USERNAME) +ACCOUNT_GROUP_NAME = f"{ACCOUNT_USERNAME}-group" @attr.s(frozen=True, slots=True) @@ -32,7 +32,7 @@ class ExternalAuthConfig: return { "*": ["grains.*"], ACCOUNT_USERNAME: ["@wheel"], - "{}%".format(ACCOUNT_GROUP_NAME): ["@runner"], + f"{ACCOUNT_GROUP_NAME}%": ["@runner"], } @pam.default @@ -72,14 +72,14 @@ def external_auth_ids(value): # By Group ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["grains.*"], expected_perms=["grains.*"], fixture_id="by-group-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@wheel", "grains.*"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-auto", @@ -147,14 +147,14 @@ def external_auth_ids(value): # By group, by wheel ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@wheel"], expected_perms=["@wheel"], fixture_id="by-group-by-@wheel-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@wheel"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-by-@wheel-auto", @@ -162,14 +162,14 @@ def external_auth_ids(value): # By group, by runner ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@runner"], expected_perms=["@runner"], fixture_id="by-group-by-@runner-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@runner"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-by-@runner-auto", @@ -177,14 +177,14 @@ def external_auth_ids(value): # By group, by jobs ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@jobs"], expected_perms=["@jobs"], fixture_id="by-group-by-@jobs-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@jobs"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-by-@jobs-auto", diff --git a/tests/pytests/functional/netapi/rest_tornado/test_auth_handler.py b/tests/pytests/functional/netapi/rest_tornado/test_auth_handler.py index d3f42af9621..5c276ce6400 100644 --- a/tests/pytests/functional/netapi/rest_tornado/test_auth_handler.py +++ b/tests/pytests/functional/netapi/rest_tornado/test_auth_handler.py @@ -47,7 +47,7 @@ async def test_login( assert response.code == 200 response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"]["auto"][auth_creds["username"]] assert set(perms) == set(perms_config) @@ -67,7 +67,7 @@ async def test_login( assert response.code == 200 response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"]["auto"][auth_creds["username"]] assert set(perms) == set(perms_config) @@ -87,7 +87,7 @@ async def test_login( assert response.code == 200 response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"]["auto"][auth_creds["username"]] assert set(perms) == set(perms_config) diff --git a/tests/pytests/functional/netapi/rest_tornado/test_auth_handler_pam.py b/tests/pytests/functional/netapi/rest_tornado/test_auth_handler_pam.py index b2c514e9586..e16320ea898 100644 --- a/tests/pytests/functional/netapi/rest_tornado/test_auth_handler_pam.py +++ b/tests/pytests/functional/netapi/rest_tornado/test_auth_handler_pam.py @@ -55,7 +55,7 @@ async def test_login( assert response.code == 200 response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"][eauth][username] assert set(perms) == set(perms_config) @@ -75,7 +75,7 @@ async def test_login( assert response.code == 200 response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"][eauth][username] assert set(perms) == set(perms_config) @@ -95,7 +95,7 @@ async def test_login( assert response.code == 200 response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"][eauth][username] assert set(perms) == set(perms_config) diff --git a/tests/pytests/functional/netapi/rest_tornado/test_base_api_handler.py b/tests/pytests/functional/netapi/rest_tornado/test_base_api_handler.py index a8c4b762f6e..6794b081f47 100644 --- a/tests/pytests/functional/netapi/rest_tornado/test_base_api_handler.py +++ b/tests/pytests/functional/netapi/rest_tornado/test_base_api_handler.py @@ -95,7 +95,7 @@ async def test_token(http_client): # send a token as a cookie response = await http_client.fetch( - "/", headers={"Cookie": "{}=foo".format(saltnado.AUTH_COOKIE_NAME)} + "/", headers={"Cookie": f"{saltnado.AUTH_COOKIE_NAME}=foo"} ) token = salt.utils.json.loads(response.body)["token"] assert token == "foo" @@ -105,7 +105,7 @@ async def test_token(http_client): "/", headers={ saltnado.AUTH_TOKEN_HEADER: "foo", - "Cookie": "{}=bar".format(saltnado.AUTH_COOKIE_NAME), + "Cookie": f"{saltnado.AUTH_COOKIE_NAME}=bar", }, ) token = salt.utils.json.loads(response.body)["token"] diff --git a/tests/pytests/functional/netapi/rest_tornado/test_external_auth_syntax.py b/tests/pytests/functional/netapi/rest_tornado/test_external_auth_syntax.py index 4bdd3279ed1..fb0455152c4 100644 --- a/tests/pytests/functional/netapi/rest_tornado/test_external_auth_syntax.py +++ b/tests/pytests/functional/netapi/rest_tornado/test_external_auth_syntax.py @@ -15,7 +15,7 @@ pytestmark = [ ACCOUNT_USERNAME = "saltdev-syntax" -ACCOUNT_GROUP_NAME = "{}-group".format(ACCOUNT_USERNAME) +ACCOUNT_GROUP_NAME = f"{ACCOUNT_USERNAME}-group" @attr.s(frozen=True, slots=True) @@ -33,7 +33,7 @@ class ExternalAuthConfig: return { "*": ["grains.*"], ACCOUNT_USERNAME: ["@wheel"], - "{}%".format(ACCOUNT_GROUP_NAME): ["@runner"], + f"{ACCOUNT_GROUP_NAME}%": ["@runner"], } @pam.default @@ -73,14 +73,14 @@ def external_auth_ids(value): # By Group ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["grains.*"], expected_perms=["grains.*"], fixture_id="by-group-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@wheel", "grains.*"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-auto", @@ -148,14 +148,14 @@ def external_auth_ids(value): # By group, by wheel ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@wheel"], expected_perms=["@wheel"], fixture_id="by-group-by-@wheel-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@wheel"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-by-@wheel-auto", @@ -163,14 +163,14 @@ def external_auth_ids(value): # By group, by runner ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@runner"], expected_perms=["@runner"], fixture_id="by-group-by-@runner-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@runner"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-by-@runner-auto", @@ -178,14 +178,14 @@ def external_auth_ids(value): # By group, by jobs ExternalAuthConfig( eauth="pam", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@jobs"], expected_perms=["@jobs"], fixture_id="by-group-by-@jobs-pam", ), ExternalAuthConfig( eauth="auto", - pam_key="{}%".format(ACCOUNT_GROUP_NAME), + pam_key=f"{ACCOUNT_GROUP_NAME}%", pam_config=["@jobs"], expected_perms=["@wheel", "grains.*"], fixture_id="by-group-by-@jobs-auto", diff --git a/tests/pytests/functional/pillar/test_gpg.py b/tests/pytests/functional/pillar/test_gpg.py index 2c7166795bb..6e633127caa 100644 --- a/tests/pytests/functional/pillar/test_gpg.py +++ b/tests/pytests/functional/pillar/test_gpg.py @@ -264,7 +264,7 @@ def gpg_homedir(salt_master, test_key): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True, - universal_newlines=True, + text=True, ) ret = ProcessResult( returncode=proc.returncode, @@ -280,7 +280,7 @@ def gpg_homedir(salt_master, test_key): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True, - universal_newlines=True, + text=True, input=test_key, ) ret = ProcessResult( @@ -303,7 +303,7 @@ def gpg_homedir(salt_master, test_key): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True, - universal_newlines=True, + text=True, input="KILLAGENT", ) ret = ProcessResult( diff --git a/tests/pytests/functional/sdb/test_etcd_db.py b/tests/pytests/functional/sdb/test_etcd_db.py index eb3ebba6448..b10588320a7 100644 --- a/tests/pytests/functional/sdb/test_etcd_db.py +++ b/tests/pytests/functional/sdb/test_etcd_db.py @@ -43,10 +43,7 @@ def test_basic_operations(etcd_profile, prefix, profile_name): Ensure we can do the basic CRUD operations available in sdb.etcd_db """ assert ( - etcd_db.set_("{}/1".format(prefix), "one", profile=etcd_profile[profile_name]) - == "one" - ) - etcd_db.delete("{}/1".format(prefix), profile=etcd_profile[profile_name]) - assert ( - etcd_db.get("{}/1".format(prefix), profile=etcd_profile[profile_name]) is None + etcd_db.set_(f"{prefix}/1", "one", profile=etcd_profile[profile_name]) == "one" ) + etcd_db.delete(f"{prefix}/1", profile=etcd_profile[profile_name]) + assert etcd_db.get(f"{prefix}/1", profile=etcd_profile[profile_name]) is None diff --git a/tests/pytests/functional/states/cmd/test_runas.py b/tests/pytests/functional/states/cmd/test_runas.py index 75ce883a05c..5ab0169ffa1 100644 --- a/tests/pytests/functional/states/cmd/test_runas.py +++ b/tests/pytests/functional/states/cmd/test_runas.py @@ -13,5 +13,5 @@ def account(): def test_runas_id(cmd, account): ret = cmd.run("id", runas=account.username) assert ret.result is True - assert "uid={}".format(account.info.uid) in ret.changes["stdout"] - assert "gid={}".format(account.info.gid) in ret.changes["stdout"] + assert f"uid={account.info.uid}" in ret.changes["stdout"] + assert f"gid={account.info.gid}" in ret.changes["stdout"] diff --git a/tests/pytests/functional/states/file/test_append.py b/tests/pytests/functional/states/file/test_append.py index 874d5d20714..6eeab13e287 100644 --- a/tests/pytests/functional/states/file/test_append.py +++ b/tests/pytests/functional/states/file/test_append.py @@ -94,7 +94,7 @@ def test_issue_2379_file_append(modules, tmp_path): ) # create the sls template template_lines = [ - "{}:".format(tmp_file), + f"{tmp_file}:", " file.append:", " - text: PermitRootLogin yes", ] diff --git a/tests/pytests/functional/states/file/test_blockreplace.py b/tests/pytests/functional/states/file/test_blockreplace.py index 2e93a7a7324..6920fa27ac9 100644 --- a/tests/pytests/functional/states/file/test_blockreplace.py +++ b/tests/pytests/functional/states/file/test_blockreplace.py @@ -118,7 +118,7 @@ class BlockreplaceParts: def strip_ending_linebreak_ids(value): - return "strip_ending_linebreak={}".format(value) + return f"strip_ending_linebreak={value}" @pytest.mark.parametrize( @@ -478,7 +478,7 @@ def test_append_no_append_newline(file, tmp_path, strip_ending_linebreak): def line_breaks_ids(value): - return "line_breaks={}".format(value) + return f"line_breaks={value}" @pytest.mark.parametrize("line_breaks", ("windows", "posix"), ids=line_breaks_ids) diff --git a/tests/pytests/functional/states/file/test_cached.py b/tests/pytests/functional/states/file/test_cached.py index 1b052382071..130dd213d5a 100644 --- a/tests/pytests/functional/states/file/test_cached.py +++ b/tests/pytests/functional/states/file/test_cached.py @@ -22,7 +22,7 @@ def test_cached_test_true(): source_hash = secrets.token_hex(nbytes=32) expected = { "changes": {}, - "comment": "File will be cached: {}".format(name), + "comment": f"File will be cached: {name}", "name": name, "result": None, } @@ -41,7 +41,7 @@ def test_cached_present_test_true(): source_hash = secrets.token_hex(nbytes=32) expected = { "changes": {}, - "comment": "File already cached: {}".format(name), + "comment": f"File already cached: {name}", "name": name, "result": None, } @@ -62,7 +62,7 @@ def test_cached_present_different_hash_test_true(): existing_hash = secrets.token_hex(nbytes=32) expected = { "changes": {}, - "comment": "Hashes don't match.\nFile will be cached: {}".format(name), + "comment": f"Hashes don't match.\nFile will be cached: {name}", "name": name, "result": None, } @@ -82,7 +82,7 @@ def test_cached_present_no_source_hash_test_true(): existing_hash = secrets.token_hex(nbytes=32) expected = { "changes": {}, - "comment": "No hash found. File will be cached: {}".format(name), + "comment": f"No hash found. File will be cached: {name}", "name": name, "result": None, } diff --git a/tests/pytests/functional/states/file/test_comment.py b/tests/pytests/functional/states/file/test_comment.py index b7a7c8a7c95..cd825d75d83 100644 --- a/tests/pytests/functional/states/file/test_comment.py +++ b/tests/pytests/functional/states/file/test_comment.py @@ -1,6 +1,7 @@ """ Tests for file.comment state function """ + import re import pytest diff --git a/tests/pytests/functional/states/file/test_managed.py b/tests/pytests/functional/states/file/test_managed.py index 013935d3a70..76b139c7988 100644 --- a/tests/pytests/functional/states/file/test_managed.py +++ b/tests/pytests/functional/states/file/test_managed.py @@ -778,7 +778,6 @@ def test_issue_8947_utf8_sls(modules, tmp_path, state_tree, subtests): @pytest.mark.skip_if_not_root @pytest.mark.skip_on_windows(reason="Windows does not support setuid. Skipping.") def test_owner_after_setuid(file, modules, tmp_path, state_file_account): - """ Test to check file user/group after setting setuid or setgid. Because Python os.chown() does reset the setuid/setgid to 0. diff --git a/tests/pytests/functional/states/file/test_patch.py b/tests/pytests/functional/states/file/test_patch.py index 6dc0e0349ab..3c28eabea60 100644 --- a/tests/pytests/functional/states/file/test_patch.py +++ b/tests/pytests/functional/states/file/test_patch.py @@ -291,7 +291,7 @@ def test_patch_single_file_failure(file, tmp_path, files, patches): assert_fpath = f".*{reject_file.name}" else: assert_fpath = reject_file - assert re.search("saving rejects to (file )?{}".format(assert_fpath), ret.comment) + assert re.search(f"saving rejects to (file )?{assert_fpath}", ret.comment) @pytest.mark.skip_on_freebsd( @@ -324,7 +324,7 @@ def test_patch_directory_failure(file, tmp_path, files, patches): assert_fpath = f".*{reject_file.name}" else: assert_fpath = reject_file - assert re.search("saving rejects to (file )?{}".format(assert_fpath), ret.comment) + assert re.search(f"saving rejects to (file )?{assert_fpath}", ret.comment) def test_patch_single_file_remote_source(file, files, patches, subtests): diff --git a/tests/pytests/functional/states/file/test_pruned.py b/tests/pytests/functional/states/file/test_pruned.py index 80d4f94b6c2..544f92f210a 100644 --- a/tests/pytests/functional/states/file/test_pruned.py +++ b/tests/pytests/functional/states/file/test_pruned.py @@ -26,12 +26,7 @@ def nested_empty_dirs(tmp_path): for root in range(1, num_root + 1): for mid in range(1, num_mid + 1): for last in range(1, num_last + 1): - nest = ( - tmp_path - / "root{}".format(root) - / "mid{}".format(mid) - / "last{}".format(last) - ) + nest = tmp_path / f"root{root}" / f"mid{mid}" / f"last{last}" nest.mkdir(parents=True, exist_ok=True) yield str(tmp_path) @@ -44,12 +39,7 @@ def nested_dirs_with_files(tmp_path): for root in range(1, num_root + 1): for mid in range(1, num_mid + 1): for last in range(1, num_last + 1): - nest = ( - tmp_path - / "root{}".format(root) - / "mid{}".format(mid) - / "last{}".format(last) - ) + nest = tmp_path / f"root{root}" / f"mid{mid}" / f"last{last}" nest.mkdir(parents=True, exist_ok=True) if last % 2: last_file = nest / "stuff.txt" @@ -62,7 +52,7 @@ def test_pruned_failure(file, single_dir_with_file): assert ret.result is False assert not ret.changes["deleted"] assert len(ret.changes["errors"]) == 1 - assert ret.comment == "Failed to remove directory {}".format(single_dir_with_file) + assert ret.comment == f"Failed to remove directory {single_dir_with_file}" def test_pruned_success_recurse_and_deleted(file, nested_empty_dirs): diff --git a/tests/pytests/functional/states/file/test_recurse.py b/tests/pytests/functional/states/file/test_recurse.py index 5b58127fc7a..c735d5128da 100644 --- a/tests/pytests/functional/states/file/test_recurse.py +++ b/tests/pytests/functional/states/file/test_recurse.py @@ -180,9 +180,7 @@ def test_recurse_issue_34945(file, tmp_path, state_tree): name = tmp_path / issue_dir - ret = file.recurse( - name=str(name), source="salt://{}".format(issue_dir), dir_mode=dir_mode - ) + ret = file.recurse(name=str(name), source=f"salt://{issue_dir}", dir_mode=dir_mode) assert ret.result is True assert name.is_dir() assert src_dir.stat().st_mode != name.stat().st_mode @@ -222,7 +220,7 @@ def test_issue_2726_mode_kwarg(modules, tmp_path, state_tree): # Let's test for the wrong usage approach bad_mode_kwarg_testfile = dir1 / "bad_mode_kwarg" / "testfile" bad_template = [ - "{}:".format(bad_mode_kwarg_testfile), + f"{bad_mode_kwarg_testfile}:", " file.recurse:", " - source: salt://testfile", " - mode: 644", @@ -242,7 +240,7 @@ def test_issue_2726_mode_kwarg(modules, tmp_path, state_tree): # Now, the correct usage approach good_mode_kwargs_testfile = dir2 / "good_mode_kwargs" / "testappend" good_template = [ - "{}:".format(good_mode_kwargs_testfile), + f"{good_mode_kwargs_testfile}:", " file.recurse:", " - source: salt://testappend", " - dir_mode: 744", diff --git a/tests/pytests/functional/states/file/test_rename.py b/tests/pytests/functional/states/file/test_rename.py index db293d16277..1aa4fc77b68 100644 --- a/tests/pytests/functional/states/file/test_rename.py +++ b/tests/pytests/functional/states/file/test_rename.py @@ -1,6 +1,7 @@ """ Tests for file.rename state function """ + # nox -e pytest-zeromq-3.8(coverage=False) -- -vvv --run-slow --run-destructive tests\pytests\functional\states\file\test_rename.py import pytest diff --git a/tests/pytests/functional/states/file/test_replace.py b/tests/pytests/functional/states/file/test_replace.py index 22dab816804..48442bfb3e6 100644 --- a/tests/pytests/functional/states/file/test_replace.py +++ b/tests/pytests/functional/states/file/test_replace.py @@ -86,9 +86,9 @@ def test_replace_issue_18612_prepend(file, tmp_path): ) # ensure, the resulting file contains the expected lines - assert path_test.read_text() == "en_US.UTF-8\n{}".format(contents) + assert path_test.read_text() == f"en_US.UTF-8\n{contents}" - backup_file = path_test.with_name("{}.bak".format(path_test.name)) + backup_file = path_test.with_name(f"{path_test.name}.bak") assert backup_file.is_file() assert backup_file.read_text() == contents @@ -127,9 +127,9 @@ def test_replace_issue_18612_append(file, tmp_path): ) # ensure, the resulting file contains the expected lines - assert path_test.read_text() == "{}\nen_US.UTF-8\n".format(contents) + assert path_test.read_text() == f"{contents}\nen_US.UTF-8\n" - backup_file = path_test.with_name("{}.bak".format(path_test.name)) + backup_file = path_test.with_name(f"{path_test.name}.bak") assert backup_file.is_file() assert backup_file.read_text() == contents @@ -171,9 +171,9 @@ def test_replace_issue_18612_append_not_found_content(file, tmp_path): ) # ensure, the resulting file contains the expected lines - assert path_test.read_text() == "{}\n{}\n".format(contents, not_found_content) + assert path_test.read_text() == f"{contents}\n{not_found_content}\n" - backup_file = path_test.with_name("{}.bak".format(path_test.name)) + backup_file = path_test.with_name(f"{path_test.name}.bak") assert backup_file.is_file() assert backup_file.read_text() == contents @@ -215,7 +215,7 @@ def test_replace_issue_18612_change_mid_line_with_comment(file, tmp_path): # ensure, the resulting file contains the expected lines assert path_test.read_text() == contents.replace("#foo=bar", "foo=salt") - backup_file = path_test.with_name("{}.bak".format(path_test.name)) + backup_file = path_test.with_name(f"{path_test.name}.bak") assert backup_file.is_file() assert backup_file.read_text() == contents @@ -273,7 +273,7 @@ def test_replace_issue_18841_no_changes(file, tmp_path): assert path_test.read_text() == contents # ensure no backup file was created - backup_file = path_test.with_name("{}.bak".format(path_test.name)) + backup_file = path_test.with_name(f"{path_test.name}.bak") assert backup_file.is_file() is False # ensure the file's mtime didn't change @@ -328,7 +328,7 @@ def test_replace_issue_18841_omit_backup(file, tmp_path): assert path_test.read_text() == contents # ensure no backup file was created - backup_file = path_test.with_name("{}.bak".format(path_test.name)) + backup_file = path_test.with_name(f"{path_test.name}.bak") assert backup_file.is_file() is False # ensure the file's mtime didn't change diff --git a/tests/pytests/functional/states/file/test_symlink.py b/tests/pytests/functional/states/file/test_symlink.py index cabd1d43e83..1ad85efac2c 100644 --- a/tests/pytests/functional/states/file/test_symlink.py +++ b/tests/pytests/functional/states/file/test_symlink.py @@ -20,7 +20,7 @@ def test_symlink(file, tmp_path): "name": str(symlink), "changes": {"new": str(symlink)}, "result": True, - "comment": "Created new symlink {} -> {}".format(symlink, target), + "comment": f"Created new symlink {symlink} -> {target}", } assert ret.filtered == expected assert symlink.exists() diff --git a/tests/pytests/functional/states/rabbitmq/conftest.py b/tests/pytests/functional/states/rabbitmq/conftest.py index d8ccc1761b8..cc667939f5f 100644 --- a/tests/pytests/functional/states/rabbitmq/conftest.py +++ b/tests/pytests/functional/states/rabbitmq/conftest.py @@ -16,10 +16,10 @@ class RabbitMQImage: @container_id.default def _default_container_id(self): - return random_string("{}-{}-".format(self.name, self.tag)) + return random_string(f"{self.name}-{self.tag}-") def __str__(self): - return "{}:{}".format(self.name, self.tag) + return f"{self.name}:{self.tag}" @attr.s(kw_only=True, slots=True) @@ -42,7 +42,7 @@ def get_test_versions(): def get_test_version_id(value): - return "container={}".format(value) + return f"container={value}" @pytest.fixture(scope="package", params=get_test_versions(), ids=get_test_version_id) diff --git a/tests/pytests/functional/states/test_chocolatey_1_2_1.py b/tests/pytests/functional/states/test_chocolatey_1_2_1.py index 9dcc186636a..0e9972df17e 100644 --- a/tests/pytests/functional/states/test_chocolatey_1_2_1.py +++ b/tests/pytests/functional/states/test_chocolatey_1_2_1.py @@ -1,6 +1,7 @@ """ Functional tests for chocolatey state """ + import os import pathlib diff --git a/tests/pytests/functional/states/test_chocolatey_latest.py b/tests/pytests/functional/states/test_chocolatey_latest.py index 9d329d5fc59..41ba0df5b38 100644 --- a/tests/pytests/functional/states/test_chocolatey_latest.py +++ b/tests/pytests/functional/states/test_chocolatey_latest.py @@ -1,6 +1,7 @@ """ Functional tests for chocolatey state """ + import os import pathlib diff --git a/tests/pytests/functional/states/test_docker_network.py b/tests/pytests/functional/states/test_docker_network.py index 16a78b13a4a..3890bd7ef06 100644 --- a/tests/pytests/functional/states/test_docker_network.py +++ b/tests/pytests/functional/states/test_docker_network.py @@ -33,7 +33,7 @@ class Network: self._rand_indexes = random.sample( range(2, self.net.num_addresses - 1), self.net.num_addresses - 3 ) - self.ip_arg = "ipv{}_address".format(self.net.version) + self.ip_arg = f"ipv{self.net.version}_address" except KeyError: # No explicit subnet passed self.net = self.ip_arg = None @@ -47,12 +47,13 @@ class Network: ) def arg_map(self, arg_name): - return { + ret = { "ipv4_address": "IPv4Address", "ipv6_address": "IPv6Address", "links": "Links", "aliases": "Aliases", - }[arg_name] + } + return ret[arg_name] @property def subnet(self): @@ -165,7 +166,7 @@ def test_absent(docker_network, existing_network): assert ret.changes assert ret.changes == {"removed": True} assert ret.comment - assert ret.comment == "Removed network '{}'".format(existing_network.name) + assert ret.comment == f"Removed network '{existing_network.name}'" def test_absent_with_disconnected_container( @@ -185,7 +186,7 @@ def test_absent_when_not_present(network, docker_network): ret = docker_network.absent(name=net.name) assert ret.result is True assert not ret.changes - assert ret.comment == "Network '{}' already absent".format(net.name) + assert ret.comment == f"Network '{net.name}' already absent" def test_present(docker, network, docker_network): @@ -194,7 +195,7 @@ def test_present(docker, network, docker_network): assert ret.result is True assert ret.changes assert ret.changes == {"created": True} - assert ret.comment == "Network '{}' created".format(net.name) + assert ret.comment == f"Network '{net.name}' created" # Now check to see that the network actually exists. If it doesn't, # this next function call will raise an exception. @@ -207,7 +208,7 @@ def test_present_with_containers(network, docker, docker_network, container): assert ret.result is True assert ret.changes assert ret.changes == {"created": True, "connected": [container.name]} - assert ret.comment == "Network '{}' created".format(net.name) + assert ret.comment == f"Network '{net.name}' created" # Now check to see that the network actually exists. If it doesn't, # this next function call will raise an exception. @@ -224,7 +225,7 @@ def test_present_with_reconnect(network, docker, docker_network, container, reco assert ret.result is True assert ret.changes assert ret.changes == {"created": True} - assert ret.comment == "Network '{}' created".format(net.name) + assert ret.comment == f"Network '{net.name}' created" # Connect the container docker.connect_container_to_network(container.name, net.name) diff --git a/tests/pytests/functional/states/test_etcd_mod.py b/tests/pytests/functional/states/test_etcd_mod.py index 5a862b4c7bc..abe76fd6030 100644 --- a/tests/pytests/functional/states/test_etcd_mod.py +++ b/tests/pytests/functional/states/test_etcd_mod.py @@ -69,59 +69,53 @@ def test_basic_operations(subtests, profile_name, prefix, etcd_version): """ with subtests.test("Removing a non-existent key should not explode"): expected = { - "name": "{}/2/3".format(prefix), + "name": f"{prefix}/2/3", "comment": "Key does not exist", "result": True, "changes": {}, } - assert etcd_state.rm("{}/2/3".format(prefix), profile=profile_name) == expected + assert etcd_state.rm(f"{prefix}/2/3", profile=profile_name) == expected with subtests.test("We should be able to set a value"): expected = { - "name": "{}/1".format(prefix), + "name": f"{prefix}/1", "comment": "New key created", "result": True, - "changes": {"{}/1".format(prefix): "one"}, + "changes": {f"{prefix}/1": "one"}, } - assert ( - etcd_state.set_("{}/1".format(prefix), "one", profile=profile_name) - == expected - ) + assert etcd_state.set_(f"{prefix}/1", "one", profile=profile_name) == expected with subtests.test( "We should be able to create an empty directory and set values in it" ): if etcd_version in (EtcdVersion.v2, EtcdVersion.v3_v2_mode): expected = { - "name": "{}/2".format(prefix), + "name": f"{prefix}/2", "comment": "New directory created", "result": True, - "changes": {"{}/2".format(prefix): "Created"}, + "changes": {f"{prefix}/2": "Created"}, } - assert ( - etcd_state.directory("{}/2".format(prefix), profile=profile_name) - == expected - ) + assert etcd_state.directory(f"{prefix}/2", profile=profile_name) == expected expected = { - "name": "{}/2/3".format(prefix), + "name": f"{prefix}/2/3", "comment": "New key created", "result": True, - "changes": {"{}/2/3".format(prefix): "two-three"}, + "changes": {f"{prefix}/2/3": "two-three"}, } assert ( - etcd_state.set_("{}/2/3".format(prefix), "two-three", profile=profile_name) + etcd_state.set_(f"{prefix}/2/3", "two-three", profile=profile_name) == expected ) with subtests.test("We should be able to remove an existing key"): expected = { - "name": "{}/2/3".format(prefix), + "name": f"{prefix}/2/3", "comment": "Key removed", "result": True, - "changes": {"{}/2/3".format(prefix): "Deleted"}, + "changes": {f"{prefix}/2/3": "Deleted"}, } - assert etcd_state.rm("{}/2/3".format(prefix), profile=profile_name) == expected + assert etcd_state.rm(f"{prefix}/2/3", profile=profile_name) == expected def test_with_missing_profile(subtests, prefix, etcd_version, etcd_port): @@ -131,16 +125,16 @@ def test_with_missing_profile(subtests, prefix, etcd_version, etcd_port): if etcd_version in (EtcdVersion.v2, EtcdVersion.v3_v2_mode) and etcd_port != 2379: # Only need to run this once with subtests.test("Test no profile and bad connection in set_"): - ret = etcd_state.set_("{}/1".format(prefix), "one") + ret = etcd_state.set_(f"{prefix}/1", "one") assert not ret["result"] assert ret["comment"] == etcd_state.NO_PROFILE_MSG with subtests.test("Test no profile and bad connection in directory"): - ret = etcd_state.directory("{}/2".format(prefix)) + ret = etcd_state.directory(f"{prefix}/2") assert not ret["result"] assert ret["comment"] == etcd_state.NO_PROFILE_MSG with subtests.test("Test no profile and bad connection in rm"): - ret = etcd_state.rm("{}/2/3".format(prefix)) + ret = etcd_state.rm(f"{prefix}/2/3") assert not ret["result"] assert ret["comment"] == etcd_state.NO_PROFILE_MSG diff --git a/tests/pytests/functional/states/test_mysql.py b/tests/pytests/functional/states/test_mysql.py index 355f2cc1eba..1f14d8d8ed2 100644 --- a/tests/pytests/functional/states/test_mysql.py +++ b/tests/pytests/functional/states/test_mysql.py @@ -1,6 +1,7 @@ """ Test Salt MySQL state module across various MySQL variants """ + import logging import time diff --git a/tests/pytests/functional/states/test_svn.py b/tests/pytests/functional/states/test_svn.py index 5ad09ad37e2..a1f85eee92d 100644 --- a/tests/pytests/functional/states/test_svn.py +++ b/tests/pytests/functional/states/test_svn.py @@ -1,6 +1,7 @@ """ Tests for the SVN state """ + import logging import pytest @@ -133,7 +134,7 @@ def no_test_latest_existing_repo(svn, svn_mod, repo_url, repo_revision, repo_tar assert ret.result is True assert ret.changes assert "revision" in ret.changes - assert ret.changes["revision"] == "{} => {}".format(current_rev, repo_revision) + assert ret.changes["revision"] == f"{current_rev} => {repo_revision}" assert repo_target.joinpath(".svn").is_dir() diff --git a/tests/pytests/functional/states/test_win_certutil.py b/tests/pytests/functional/states/test_win_certutil.py index 92d238b3f4a..6b3d58b19c6 100644 --- a/tests/pytests/functional/states/test_win_certutil.py +++ b/tests/pytests/functional/states/test_win_certutil.py @@ -1,6 +1,7 @@ """ Tests for win_certutil state module """ + import pytest import salt.utils.files diff --git a/tests/pytests/functional/states/test_x509_v2.py b/tests/pytests/functional/states/test_x509_v2.py index 3cd09d7d840..01c877fceda 100644 --- a/tests/pytests/functional/states/test_x509_v2.py +++ b/tests/pytests/functional/states/test_x509_v2.py @@ -572,9 +572,9 @@ def existing_cert(x509, cert_args, ca_key, rsa_privkey, request): ca_key, encoding=cert_args.get("encoding", "pem"), passphrase=cert_args.get("pkcs12_passphrase"), - subject=subject - if "signing_policy" not in cert_args - else "CN=from_signing_policy", + subject=( + subject if "signing_policy" not in cert_args else "CN=from_signing_policy" + ), ) yield cert_args["name"] diff --git a/tests/pytests/functional/states/test_zookeeper.py b/tests/pytests/functional/states/test_zookeeper.py index e735fdd1cf0..77a50cc0b72 100644 --- a/tests/pytests/functional/states/test_zookeeper.py +++ b/tests/pytests/functional/states/test_zookeeper.py @@ -23,7 +23,7 @@ pytestmark = [ def minion_config_overrides(zookeeper_port): zookeeper_grains = { "prod": { - "hosts": "localhost:{}".format(zookeeper_port), + "hosts": f"localhost:{zookeeper_port}", "default_acl": [ { "username": "daniel", @@ -38,7 +38,7 @@ def minion_config_overrides(zookeeper_port): "username": "daniel", "password": "test", }, - "hosts": "localhost:{}".format(zookeeper_port), + "hosts": f"localhost:{zookeeper_port}", "default_acl": [ { "username": "daniel", diff --git a/tests/pytests/functional/states/win_lgpo/test_audit_settings_state.py b/tests/pytests/functional/states/win_lgpo/test_audit_settings_state.py index 6f45461618d..f7590e48938 100644 --- a/tests/pytests/functional/states/win_lgpo/test_audit_settings_state.py +++ b/tests/pytests/functional/states/win_lgpo/test_audit_settings_state.py @@ -77,7 +77,7 @@ def clean_adv_audit(): # - C:\Windows\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit win_dir = os.environ.get("WINDIR") audit_csv_files = [ - r"{}\security\audit\audit.csv".format(win_dir), + rf"{win_dir}\security\audit\audit.csv", r"{}\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit\audit.csv".format( win_dir ), diff --git a/tests/pytests/functional/transport/ipc/test_client.py b/tests/pytests/functional/transport/ipc/test_client.py index 20bc43aa064..51efbe2b5e2 100644 --- a/tests/pytests/functional/transport/ipc/test_client.py +++ b/tests/pytests/functional/transport/ipc/test_client.py @@ -110,7 +110,7 @@ async def test_basic_send(channel): async def test_send_many(channel): msgs = [] for i in range(0, 1000): - msgs.append("test_many_send_{}".format(i)) + msgs.append(f"test_many_send_{i}") for msg in msgs: await channel.send(msg) diff --git a/tests/pytests/functional/transport/server/test_request_server.py b/tests/pytests/functional/transport/server/test_request_server.py index 773de615e4d..fe271f1b403 100644 --- a/tests/pytests/functional/transport/server/test_request_server.py +++ b/tests/pytests/functional/transport/server/test_request_server.py @@ -10,9 +10,9 @@ async def test_request_server( minion_opts["transport"] = master_opts["transport"] = transport # Needed by tcp transport's RequestClient - minion_opts[ - "master_uri" - ] = f"tcp://{master_opts['interface']}:{master_opts['ret_port']}" + minion_opts["master_uri"] = ( + f"tcp://{master_opts['interface']}:{master_opts['ret_port']}" + ) req_server = salt.transport.request_server(master_opts) req_server.pre_fork(process_manager) diff --git a/tests/pytests/functional/transport/tcp/test_pub_server.py b/tests/pytests/functional/transport/tcp/test_pub_server.py index e4ec44fb856..5b9ef4b6196 100644 --- a/tests/pytests/functional/transport/tcp/test_pub_server.py +++ b/tests/pytests/functional/transport/tcp/test_pub_server.py @@ -1,5 +1,4 @@ import os -import threading import time import tornado.gen diff --git a/tests/pytests/functional/utils/functools/test_namespaced_function.py b/tests/pytests/functional/utils/functools/test_namespaced_function.py index 88b92637804..283a722a87c 100644 --- a/tests/pytests/functional/utils/functools/test_namespaced_function.py +++ b/tests/pytests/functional/utils/functools/test_namespaced_function.py @@ -11,7 +11,7 @@ log = logging.getLogger(__name__) def preserve_context_ids(value): - return "preserve_context={}".format(value) + return f"preserve_context={value}" @pytest.fixture(params=[True, False], ids=preserve_context_ids) diff --git a/tests/pytests/functional/utils/test_etcd_util.py b/tests/pytests/functional/utils/test_etcd_util.py index 9c8f9764f72..e665d0b2856 100644 --- a/tests/pytests/functional/utils/test_etcd_util.py +++ b/tests/pytests/functional/utils/test_etcd_util.py @@ -66,23 +66,23 @@ def test_simple_operations(etcd_client, prefix): """ Verify basic functionality in order to justify use of the cleanup fixture. """ - assert not etcd_client.get("{}/mtg/ambush".format(prefix)) - assert etcd_client.set("{}/mtg/ambush".format(prefix), "viper") == "viper" - assert etcd_client.get("{}/mtg/ambush".format(prefix)) == "viper" - assert etcd_client.set("{}/mtg/counter".format(prefix), "spell") == "spell" - assert etcd_client.tree("{}/mtg".format(prefix)) == { + assert not etcd_client.get(f"{prefix}/mtg/ambush") + assert etcd_client.set(f"{prefix}/mtg/ambush", "viper") == "viper" + assert etcd_client.get(f"{prefix}/mtg/ambush") == "viper" + assert etcd_client.set(f"{prefix}/mtg/counter", "spell") == "spell" + assert etcd_client.tree(f"{prefix}/mtg") == { "ambush": "viper", "counter": "spell", } - assert etcd_client.ls("{}/mtg".format(prefix)) == { - "{}/mtg".format(prefix): { - "{}/mtg/ambush".format(prefix): "viper", - "{}/mtg/counter".format(prefix): "spell", + assert etcd_client.ls(f"{prefix}/mtg") == { + f"{prefix}/mtg": { + f"{prefix}/mtg/ambush": "viper", + f"{prefix}/mtg/counter": "spell", }, } - assert etcd_client.delete("{}/mtg/ambush".format(prefix)) - assert etcd_client.delete("{}/mtg".format(prefix), recurse=True) - assert not etcd_client.get("{}/mtg".format(prefix), recurse=True) + assert etcd_client.delete(f"{prefix}/mtg/ambush") + assert etcd_client.delete(f"{prefix}/mtg", recurse=True) + assert not etcd_client.get(f"{prefix}/mtg", recurse=True) def test_simple_operations_with_raw_keys_and_values( @@ -94,23 +94,23 @@ def test_simple_operations_with_raw_keys_and_values( modified_opts[profile_name]["etcd.raw_keys"] = True modified_opts[profile_name]["etcd.raw_values"] = True etcd_client = get_conn(modified_opts, profile=profile_name) - assert not etcd_client.get("{}/mtg/ambush".format(prefix)) - assert etcd_client.set("{}/mtg/ambush".format(prefix), "viper") == b"viper" - assert etcd_client.get("{}/mtg/ambush".format(prefix)) == b"viper" - assert etcd_client.set("{}/mtg/counter".format(prefix), "spell") == b"spell" - assert etcd_client.tree("{}/mtg".format(prefix)) == { + assert not etcd_client.get(f"{prefix}/mtg/ambush") + assert etcd_client.set(f"{prefix}/mtg/ambush", "viper") == b"viper" + assert etcd_client.get(f"{prefix}/mtg/ambush") == b"viper" + assert etcd_client.set(f"{prefix}/mtg/counter", "spell") == b"spell" + assert etcd_client.tree(f"{prefix}/mtg") == { b"ambush": b"viper", b"counter": b"spell", } - assert etcd_client.ls("{}/mtg".format(prefix)) == { - "{}/mtg".format(prefix).encode("UTF-8"): { - "{}/mtg/ambush".format(prefix).encode("UTF-8"): b"viper", - "{}/mtg/counter".format(prefix).encode("UTF-8"): b"spell", + assert etcd_client.ls(f"{prefix}/mtg") == { + f"{prefix}/mtg".encode(): { + f"{prefix}/mtg/ambush".encode(): b"viper", + f"{prefix}/mtg/counter".encode(): b"spell", }, } - assert etcd_client.delete("{}/mtg/ambush".format(prefix)) - assert etcd_client.delete("{}/mtg".format(prefix), recurse=True) - assert not etcd_client.get("{}/mtg".format(prefix), recurse=True) + assert etcd_client.delete(f"{prefix}/mtg/ambush") + assert etcd_client.delete(f"{prefix}/mtg", recurse=True) + assert not etcd_client.get(f"{prefix}/mtg", recurse=True) def test_get(subtests, etcd_client, prefix): @@ -120,14 +120,14 @@ def test_get(subtests, etcd_client, prefix): # Test general get case with key=value with subtests.test("inserted keys should be able to be retrieved"): - etcd_client.set("{}/get-test/key".format(prefix), "value") - assert etcd_client.get("{}/get-test/key".format(prefix)) == "value" + etcd_client.set(f"{prefix}/get-test/key", "value") + assert etcd_client.get(f"{prefix}/get-test/key") == "value" # Test with recurse=True. with subtests.test("keys should be able to be retrieved recursively"): - etcd_client.set("{}/get-test/key2/subkey".format(prefix), "subvalue") - etcd_client.set("{}/get-test/key2/subkey2/1".format(prefix), "subvalue1") - etcd_client.set("{}/get-test/key2/subkey2/2".format(prefix), "subvalue2") + etcd_client.set(f"{prefix}/get-test/key2/subkey", "subvalue") + etcd_client.set(f"{prefix}/get-test/key2/subkey2/1", "subvalue1") + etcd_client.set(f"{prefix}/get-test/key2/subkey2/2", "subvalue2") expected = { "subkey": "subvalue", @@ -137,24 +137,22 @@ def test_get(subtests, etcd_client, prefix): }, } - assert ( - etcd_client.get("{}/get-test/key2".format(prefix), recurse=True) == expected - ) + assert etcd_client.get(f"{prefix}/get-test/key2", recurse=True) == expected def test_read(subtests, etcd_client, prefix, etcd_version): """ Test that we are able to read and wait. """ - etcd_client.set("{}/read/1".format(prefix), "one") - etcd_client.set("{}/read/2".format(prefix), "two") - etcd_client.set("{}/read/3/4".format(prefix), "three/four") + etcd_client.set(f"{prefix}/read/1", "one") + etcd_client.set(f"{prefix}/read/2", "two") + etcd_client.set(f"{prefix}/read/3/4", "three/four") # Simple read test with subtests.test( "reading a newly inserted and existent key should return that key" ): - result = etcd_client.read("{}/read/1".format(prefix)) + result = etcd_client.read(f"{prefix}/read/1") assert result if etcd_version in (EtcdVersion.v2, EtcdVersion.v3_v2_mode): assert result.value == "one" @@ -171,10 +169,10 @@ def test_read(subtests, etcd_client, prefix, etcd_version): "2": "two", "3": {"4": "three/four"}, }, - path="{}/read".format(prefix), + path=f"{prefix}/read", ) - result = etcd_client.read("{}/read".format(prefix), recurse=True) + result = etcd_client.read(f"{prefix}/read", recurse=True) assert result if etcd_version in (EtcdVersion.v2, EtcdVersion.v3_v2_mode): assert result.children @@ -187,7 +185,7 @@ def test_read(subtests, etcd_client, prefix, etcd_version): result_dict[child.key] = child.value else: for child in result: - if child.key != "{}/read".format(prefix): + if child.key != f"{prefix}/read": result_dict[child.key] = child.value assert result_dict == expected @@ -197,16 +195,16 @@ def test_read(subtests, etcd_client, prefix, etcd_version): def wait_func(return_list): return_list.append( - etcd_client.read("{}/read/1".format(prefix), wait=True, timeout=30) + etcd_client.read(f"{prefix}/read/1", wait=True, timeout=30) ) wait_thread = threading.Thread(target=wait_func, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/read/1".format(prefix), "not one") + etcd_client.set(f"{prefix}/read/1", "not one") wait_thread.join() modified = return_list.pop() - assert modified.key == "{}/read/1".format(prefix) + assert modified.key == f"{prefix}/read/1" assert modified.value == "not one" # Wait for an update using recursive @@ -215,18 +213,16 @@ def test_read(subtests, etcd_client, prefix, etcd_version): def wait_func_2(return_list): return_list.append( - etcd_client.read( - "{}/read".format(prefix), wait=True, timeout=30, recurse=True - ) + etcd_client.read(f"{prefix}/read", wait=True, timeout=30, recurse=True) ) wait_thread = threading.Thread(target=wait_func_2, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/read/1".format(prefix), "one again!") + etcd_client.set(f"{prefix}/read/1", "one again!") wait_thread.join() modified = return_list.pop() - assert modified.key == "{}/read/1".format(prefix) + assert modified.key == f"{prefix}/read/1" assert modified.value == "one again!" # Wait for an update after last modification @@ -242,7 +238,7 @@ def test_read(subtests, etcd_client, prefix, etcd_version): def wait_func_3(return_list): return_list.append( etcd_client.read( - "{}/read/1".format(prefix), + f"{prefix}/read/1", wait=True, timeout=30, start_revision=last_modified + 1, @@ -252,10 +248,10 @@ def test_read(subtests, etcd_client, prefix, etcd_version): wait_thread = threading.Thread(target=wait_func_3, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/read/1".format(prefix), "one") + etcd_client.set(f"{prefix}/read/1", "one") wait_thread.join() modified = return_list.pop() - assert modified.key == "{}/read/1".format(prefix) + assert modified.key == f"{prefix}/read/1" assert modified.value == "one" # Wait for an update after last modification, recursively @@ -269,7 +265,7 @@ def test_read(subtests, etcd_client, prefix, etcd_version): def wait_func_4(return_list): return_list.append( etcd_client.read( - "{}/read".format(prefix), + f"{prefix}/read", wait=True, timeout=30, recurse=True, @@ -280,10 +276,10 @@ def test_read(subtests, etcd_client, prefix, etcd_version): wait_thread = threading.Thread(target=wait_func_4, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/read/1".format(prefix), "one") + etcd_client.set(f"{prefix}/read/1", "one") wait_thread.join() modified = return_list.pop() - assert modified.key == "{}/read/1".format(prefix) + assert modified.key == f"{prefix}/read/1" assert modified.value == "one" @@ -291,19 +287,19 @@ def test_update(subtests, etcd_client, prefix): """ Ensure that we can update fields """ - etcd_client.set("{}/read/1".format(prefix), "one") - etcd_client.set("{}/read/2".format(prefix), "two") - etcd_client.set("{}/read/3/4".format(prefix), "three/four") + etcd_client.set(f"{prefix}/read/1", "one") + etcd_client.set(f"{prefix}/read/2", "two") + etcd_client.set(f"{prefix}/read/3/4", "three/four") # Update existent fields with subtests.test("update should work on already existent field"): updated = { - "{}/read/1".format(prefix): "not one", - "{}/read/2".format(prefix): "not two", + f"{prefix}/read/1": "not one", + f"{prefix}/read/2": "not two", } assert etcd_client.update(updated) == updated - assert etcd_client.get("{}/read/1".format(prefix)) == "not one" - assert etcd_client.get("{}/read/2".format(prefix)) == "not two" + assert etcd_client.get(f"{prefix}/read/1") == "not one" + assert etcd_client.get(f"{prefix}/read/2") == "not two" # Update non-existent fields with subtests.test("update should work on non-existent fields"): @@ -319,10 +315,10 @@ def test_update(subtests, etcd_client, prefix): } assert etcd_client.update(updated) == etcd_client._flatten(updated) - assert etcd_client.get("{}/read-2".format(prefix)) == "read-2" - assert etcd_client.get("{}/read-3".format(prefix)) == "read-3" + assert etcd_client.get(f"{prefix}/read-2") == "read-2" + assert etcd_client.get(f"{prefix}/read-3") == "read-3" assert ( - etcd_client.get("{}/read-4".format(prefix), recurse=True) + etcd_client.get(f"{prefix}/read-4", recurse=True) == updated[prefix]["read-4"] ) @@ -332,15 +328,12 @@ def test_update(subtests, etcd_client, prefix): "2": "path updated two", } expected_return = { - "{}/read/1".format(prefix): "path updated one", - "{}/read/2".format(prefix): "path updated two", + f"{prefix}/read/1": "path updated one", + f"{prefix}/read/2": "path updated two", } - assert ( - etcd_client.update(updated, path="{}/read".format(prefix)) - == expected_return - ) - assert etcd_client.get("{}/read/1".format(prefix)) == "path updated one" - assert etcd_client.get("{}/read/2".format(prefix)) == "path updated two" + assert etcd_client.update(updated, path=f"{prefix}/read") == expected_return + assert etcd_client.get(f"{prefix}/read/1") == "path updated one" + assert etcd_client.get(f"{prefix}/read/2") == "path updated two" def test_write_file(subtests, etcd_client, prefix): @@ -350,28 +343,23 @@ def test_write_file(subtests, etcd_client, prefix): with subtests.test( "we should be able to write a single value for a non-existent key" ): - assert ( - etcd_client.write_file("{}/write/key_1".format(prefix), "value_1") - == "value_1" - ) - assert etcd_client.get("{}/write/key_1".format(prefix)) == "value_1" + assert etcd_client.write_file(f"{prefix}/write/key_1", "value_1") == "value_1" + assert etcd_client.get(f"{prefix}/write/key_1") == "value_1" with subtests.test("we should be able to write a single value for an existent key"): assert ( - etcd_client.write_file("{}/write/key_1".format(prefix), "new_value_1") + etcd_client.write_file(f"{prefix}/write/key_1", "new_value_1") == "new_value_1" ) - assert etcd_client.get("{}/write/key_1".format(prefix)) == "new_value_1" + assert etcd_client.get(f"{prefix}/write/key_1") == "new_value_1" with subtests.test("we should be able to write a single value with a ttl"): assert ( - etcd_client.write_file( - "{}/write/ttl_key".format(prefix), "new_value_2", ttl=5 - ) + etcd_client.write_file(f"{prefix}/write/ttl_key", "new_value_2", ttl=5) == "new_value_2" ) time.sleep(10) - assert etcd_client.get("{}/write/ttl_key".format(prefix)) is None + assert etcd_client.get(f"{prefix}/write/ttl_key") is None def test_write_directory(subtests, etcd_client, prefix, etcd_version): @@ -382,19 +370,19 @@ def test_write_directory(subtests, etcd_client, prefix, etcd_version): pytest.skip("write_directory is not defined for etcd v3") with subtests.test("we should be able to create a non-existent directory"): - assert etcd_client.write_directory("{}/write_dir/dir1".format(prefix), None) - assert etcd_client.get("{}/write_dir/dir1".format(prefix)) is None + assert etcd_client.write_directory(f"{prefix}/write_dir/dir1", None) + assert etcd_client.get(f"{prefix}/write_dir/dir1") is None with subtests.test("writing an already existent directory should return True"): - assert etcd_client.write_directory("{}/write_dir/dir1".format(prefix), None) - assert etcd_client.get("{}/write_dir/dir1".format(prefix)) is None + assert etcd_client.write_directory(f"{prefix}/write_dir/dir1", None) + assert etcd_client.get(f"{prefix}/write_dir/dir1") is None with subtests.test("we should be able to write to a new directory"): assert ( - etcd_client.write_file("{}/write_dir/dir1/key1".format(prefix), "value1") + etcd_client.write_file(f"{prefix}/write_dir/dir1/key1", "value1") == "value1" ) - assert etcd_client.get("{}/write_dir/dir1/key1".format(prefix)) == "value1" + assert etcd_client.get(f"{prefix}/write_dir/dir1/key1") == "value1" def test_ls(subtests, etcd_client, prefix): @@ -402,25 +390,25 @@ def test_ls(subtests, etcd_client, prefix): Test listing top level contents """ with subtests.test("ls on a non-existent directory should return an empty dict"): - assert not etcd_client.ls("{}/ls".format(prefix)) + assert not etcd_client.ls(f"{prefix}/ls") with subtests.test( "ls should list the top level keys and values at the given path" ): - etcd_client.set("{}/ls/1".format(prefix), "one") - etcd_client.set("{}/ls/2".format(prefix), "two") - etcd_client.set("{}/ls/3/4".format(prefix), "three/four") + etcd_client.set(f"{prefix}/ls/1", "one") + etcd_client.set(f"{prefix}/ls/2", "two") + etcd_client.set(f"{prefix}/ls/3/4", "three/four") # If it's a dir, it's suffixed with a slash expected = { - "{}/ls".format(prefix): { - "{}/ls/1".format(prefix): "one", - "{}/ls/2".format(prefix): "two", - "{}/ls/3/".format(prefix): {}, + f"{prefix}/ls": { + f"{prefix}/ls/1": "one", + f"{prefix}/ls/2": "two", + f"{prefix}/ls/3/": {}, }, } - assert etcd_client.ls("{}/ls".format(prefix)) == expected + assert etcd_client.ls(f"{prefix}/ls") == expected @pytest.mark.parametrize("func", ("rm", "delete")) @@ -431,18 +419,18 @@ def test_rm_and_delete(subtests, etcd_client, prefix, func, etcd_version): func = getattr(etcd_client, func) with subtests.test("removing a non-existent key should do nothing"): - assert func("{}/rm/key1".format(prefix)) is None + assert func(f"{prefix}/rm/key1") is None with subtests.test("we should be able to remove an existing key"): - etcd_client.set("{}/rm/key1".format(prefix), "value1") - assert func("{}/rm/key1".format(prefix)) - assert etcd_client.get("{}/rm/key1".format(prefix)) is None + etcd_client.set(f"{prefix}/rm/key1", "value1") + assert func(f"{prefix}/rm/key1") + assert etcd_client.get(f"{prefix}/rm/key1") is None with subtests.test("we should be able to remove an empty directory"): if etcd_version == EtcdVersion.v2: - etcd_client.write_directory("{}/rm/dir1".format(prefix), None) - assert func("{}/rm/dir1".format(prefix), recurse=True) - assert etcd_client.get("{}/rm/dir1".format(prefix), recurse=True) is None + etcd_client.write_directory(f"{prefix}/rm/dir1", None) + assert func(f"{prefix}/rm/dir1", recurse=True) + assert etcd_client.get(f"{prefix}/rm/dir1", recurse=True) is None with subtests.test("we should be able to remove a directory with keys"): updated = { @@ -454,11 +442,11 @@ def test_rm_and_delete(subtests, etcd_client, prefix, func, etcd_version): }, } } - etcd_client.update(updated, path="{}/rm".format(prefix)) + etcd_client.update(updated, path=f"{prefix}/rm") - assert func("{}/rm/dir1".format(prefix), recurse=True) - assert etcd_client.get("{}/rm/dir1".format(prefix), recurse=True) is None - assert etcd_client.get("{}/rm/dir1/rm-1".format(prefix), recurse=True) is None + assert func(f"{prefix}/rm/dir1", recurse=True) + assert etcd_client.get(f"{prefix}/rm/dir1", recurse=True) is None + assert etcd_client.get(f"{prefix}/rm/dir1/rm-1", recurse=True) is None with subtests.test("removing a directory without recursion should do nothing"): updated = { @@ -470,14 +458,11 @@ def test_rm_and_delete(subtests, etcd_client, prefix, func, etcd_version): }, } } - etcd_client.update(updated, path="{}/rm".format(prefix)) + etcd_client.update(updated, path=f"{prefix}/rm") - assert func("{}/rm/dir1".format(prefix)) is None - assert ( - etcd_client.get("{}/rm/dir1".format(prefix), recurse=True) - == updated["dir1"] - ) - assert etcd_client.get("{}/rm/dir1/rm-1".format(prefix)) == "value-1" + assert func(f"{prefix}/rm/dir1") is None + assert etcd_client.get(f"{prefix}/rm/dir1", recurse=True) == updated["dir1"] + assert etcd_client.get(f"{prefix}/rm/dir1/rm-1") == "value-1" def test_tree(subtests, etcd_client, prefix, etcd_version): @@ -488,16 +473,16 @@ def test_tree(subtests, etcd_client, prefix, etcd_version): assert etcd_client.tree(prefix) is None with subtests.test("the tree of an file should be {key: value}"): - etcd_client.set("{}/1".format(prefix), "one") - assert etcd_client.tree("{}/1".format(prefix)) == {"1": "one"} + etcd_client.set(f"{prefix}/1", "one") + assert etcd_client.tree(f"{prefix}/1") == {"1": "one"} with subtests.test("the tree of an empty directory should be empty"): if etcd_version == EtcdVersion.v2: - etcd_client.write_directory("{}/2".format(prefix), None) - assert etcd_client.tree("{}/2".format(prefix)) == {} + etcd_client.write_directory(f"{prefix}/2", None) + assert etcd_client.tree(f"{prefix}/2") == {} with subtests.test("we should be able to recieve the tree of a directory"): - etcd_client.set("{}/3/4".format(prefix), "three/four") + etcd_client.set(f"{prefix}/3/4", "three/four") expected = { "1": "one", "2": {}, @@ -508,11 +493,11 @@ def test_tree(subtests, etcd_client, prefix, etcd_version): assert etcd_client.tree(prefix) == expected with subtests.test("we should be able to recieve the tree of an outer directory"): - etcd_client.set("{}/5/6/7".format(prefix), "five/six/seven") + etcd_client.set(f"{prefix}/5/6/7", "five/six/seven") expected = { "6": {"7": "five/six/seven"}, } - assert etcd_client.tree("{}/5".format(prefix)) == expected + assert etcd_client.tree(f"{prefix}/5") == expected def test_watch(subtests, etcd_client, prefix): @@ -523,32 +508,30 @@ def test_watch(subtests, etcd_client, prefix): "4": "three/four", }, } - etcd_client.update(updated, path="{}/watch".format(prefix)) + etcd_client.update(updated, path=f"{prefix}/watch") with subtests.test("watching an invalid key should timeout and return None"): - assert etcd_client.watch("{}/invalid".format(prefix), timeout=3) is None + assert etcd_client.watch(f"{prefix}/invalid", timeout=3) is None with subtests.test( "watching an valid key with no changes should timeout and return None" ): - assert etcd_client.watch("{}/watch/1".format(prefix), timeout=3) is None + assert etcd_client.watch(f"{prefix}/watch/1", timeout=3) is None # Wait for an update with subtests.test("updates should be able to be caught by waiting in read"): return_list = [] def wait_func(return_list): - return_list.append( - etcd_client.watch("{}/watch/1".format(prefix), timeout=30) - ) + return_list.append(etcd_client.watch(f"{prefix}/watch/1", timeout=30)) wait_thread = threading.Thread(target=wait_func, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/watch/1".format(prefix), "not one") + etcd_client.set(f"{prefix}/watch/1", "not one") wait_thread.join() modified = return_list.pop() - assert modified["key"] == "{}/watch/1".format(prefix) + assert modified["key"] == f"{prefix}/watch/1" assert modified["value"] == "not one" # Wait for an update using recursive @@ -557,16 +540,16 @@ def test_watch(subtests, etcd_client, prefix): def wait_func_2(return_list): return_list.append( - etcd_client.watch("{}/watch".format(prefix), timeout=30, recurse=True) + etcd_client.watch(f"{prefix}/watch", timeout=30, recurse=True) ) wait_thread = threading.Thread(target=wait_func_2, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/watch/1".format(prefix), "one again!") + etcd_client.set(f"{prefix}/watch/1", "one again!") wait_thread.join() modified = return_list.pop() - assert modified["key"] == "{}/watch/1".format(prefix) + assert modified["key"] == f"{prefix}/watch/1" assert modified["value"] == "one again!" # Wait for an update after last modification @@ -579,7 +562,7 @@ def test_watch(subtests, etcd_client, prefix): def wait_func_3(return_list): return_list.append( etcd_client.watch( - "{}/watch/1".format(prefix), + f"{prefix}/watch/1", timeout=30, start_revision=last_modified + 1, ) @@ -588,10 +571,10 @@ def test_watch(subtests, etcd_client, prefix): wait_thread = threading.Thread(target=wait_func_3, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/watch/1".format(prefix), "one") + etcd_client.set(f"{prefix}/watch/1", "one") wait_thread.join() modified = return_list.pop() - assert modified["key"] == "{}/watch/1".format(prefix) + assert modified["key"] == f"{prefix}/watch/1" assert modified["value"] == "one" # Wait for an update after last modification, recursively @@ -602,7 +585,7 @@ def test_watch(subtests, etcd_client, prefix): def wait_func_4(return_list): return_list.append( etcd_client.watch( - "{}/watch".format(prefix), + f"{prefix}/watch", timeout=30, recurse=True, start_revision=last_modified + 1, @@ -612,8 +595,8 @@ def test_watch(subtests, etcd_client, prefix): wait_thread = threading.Thread(target=wait_func_4, args=(return_list,)) wait_thread.start() time.sleep(1) - etcd_client.set("{}/watch/1".format(prefix), "one") + etcd_client.set(f"{prefix}/watch/1", "one") wait_thread.join() modified = return_list.pop() - assert modified["key"] == "{}/watch/1".format(prefix) + assert modified["key"] == f"{prefix}/watch/1" assert modified["value"] == "one" diff --git a/tests/pytests/functional/utils/test_jinja.py b/tests/pytests/functional/utils/test_jinja.py index 98070c9909b..9623e198b5d 100644 --- a/tests/pytests/functional/utils/test_jinja.py +++ b/tests/pytests/functional/utils/test_jinja.py @@ -17,8 +17,8 @@ def test_utils_jinja_cache_removed_file_from_root(temp_salt_minion, tmp_path): cache_root = tmp_path / "cache" cache_root.mkdir(parents=True, exist_ok=True) filename = "jinja_cache" - sls_file = file_root / "{}.sls".format(filename) - jinja_file = file_root / "{}.jinja".format(filename) + sls_file = file_root / f"{filename}.sls" + jinja_file = file_root / f"{filename}.jinja" sls_file.write_text("{% include '" + filename + ".jinja' %}") jinja_file.write_text("{% set this = 'that' %}") diff --git a/tests/pytests/functional/utils/test_process.py b/tests/pytests/functional/utils/test_process.py index 6c420b95f48..bbb83638761 100644 --- a/tests/pytests/functional/utils/test_process.py +++ b/tests/pytests/functional/utils/test_process.py @@ -4,6 +4,7 @@ tests.pytests.functional.utils.test_process Test salt's process utility module """ + import pytest import salt.utils.process diff --git a/tests/pytests/functional/utils/win_dacl/test_get_name.py b/tests/pytests/functional/utils/win_dacl/test_get_name.py index 8ea5d7614e4..f35c1336ec4 100644 --- a/tests/pytests/functional/utils/win_dacl/test_get_name.py +++ b/tests/pytests/functional/utils/win_dacl/test_get_name.py @@ -4,6 +4,7 @@ tests.pytests.unit.utils.win_dacl.test_get_name Test the get_name function in the win_dacl utility module """ + import pytest import salt.exceptions diff --git a/tests/pytests/functional/utils/win_dacl/test_get_sid.py b/tests/pytests/functional/utils/win_dacl/test_get_sid.py index e2e09f6dea6..4560713dad5 100644 --- a/tests/pytests/functional/utils/win_dacl/test_get_sid.py +++ b/tests/pytests/functional/utils/win_dacl/test_get_sid.py @@ -4,6 +4,7 @@ tests.pytests.unit.utils.win_dacl.test_get_sid Test the get_sid function in the win_dacl utility module """ + import pytest import salt.utils.win_dacl diff --git a/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py b/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py index adde42501ae..bea9240f75e 100644 --- a/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py +++ b/tests/pytests/functional/utils/win_dacl/test_get_sid_string.py @@ -4,6 +4,7 @@ tests.pytests.unit.utils.win_dacl.test_get_sid_string Test the get_sid_string function in the win_dacl utility module """ + import pytest import salt.utils.win_dacl diff --git a/tests/pytests/integration/_logging/test_multiple_processes_logging.py b/tests/pytests/integration/_logging/test_multiple_processes_logging.py index 57a9beca3f9..b9457bad656 100644 --- a/tests/pytests/integration/_logging/test_multiple_processes_logging.py +++ b/tests/pytests/integration/_logging/test_multiple_processes_logging.py @@ -48,7 +48,7 @@ def logging_master(salt_factories): def matches(logging_master): return [ # Each of these is a separate process started by the master - "*|PID:{}|*".format(logging_master.process_pid), + f"*|PID:{logging_master.process_pid}|*", "*|MWorker-*|*", "*|Maintenance|*", "*|ReqServer|*", diff --git a/tests/pytests/integration/cli/test_batch.py b/tests/pytests/integration/cli/test_batch.py index 70d66d99598..32ae60346f4 100644 --- a/tests/pytests/integration/cli/test_batch.py +++ b/tests/pytests/integration/cli/test_batch.py @@ -24,7 +24,7 @@ def test_batch_run(salt_cli, run_timeout, salt_sub_minion): """ Tests executing a simple batch command to help catch regressions """ - ret = "Executing run on [{}]".format(repr(salt_sub_minion.id)) + ret = f"Executing run on [{repr(salt_sub_minion.id)}]" cmd = salt_cli.run( "test.echo", "batch testing", @@ -59,8 +59,8 @@ def test_batch_run_grains_targeting( Tests executing a batch command using a percentage divisor as well as grains targeting. """ - sub_min_ret = "Executing run on [{}]".format(repr(salt_sub_minion.id)) - min_ret = "Executing run on [{}]".format(repr(salt_minion.id)) + sub_min_ret = f"Executing run on [{repr(salt_sub_minion.id)}]" + min_ret = f"Executing run on [{repr(salt_minion.id)}]" cmd = salt_cli.run( "-C", "-b 25%", diff --git a/tests/pytests/integration/cli/test_salt.py b/tests/pytests/integration/cli/test_salt.py index 231e8b7dc4b..24b79a11b35 100644 --- a/tests/pytests/integration/cli/test_salt.py +++ b/tests/pytests/integration/cli/test_salt.py @@ -1,6 +1,7 @@ """ :codeauthor: Thayne Harbaugh (tharbaug@adobe.com) """ + import logging import os import shutil diff --git a/tests/pytests/integration/cli/test_salt_cp.py b/tests/pytests/integration/cli/test_salt_cp.py index 9c303e7c9b4..ce01de43437 100644 --- a/tests/pytests/integration/cli/test_salt_cp.py +++ b/tests/pytests/integration/cli/test_salt_cp.py @@ -3,7 +3,6 @@ tests.integration.shell.cp ~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import os import pathlib diff --git a/tests/pytests/integration/cli/test_salt_deltaproxy.py b/tests/pytests/integration/cli/test_salt_deltaproxy.py index 3457a972aec..1d8eea0e997 100644 --- a/tests/pytests/integration/cli/test_salt_deltaproxy.py +++ b/tests/pytests/integration/cli/test_salt_deltaproxy.py @@ -1,6 +1,7 @@ """ :codeauthor: Gareth J. Greenaway (ggreenaway@vmware.com) """ + import logging import random @@ -177,7 +178,9 @@ def test_exit_status_correct_usage( f"{proxy_two}.sls", dummy_proxy_two_pillar_file, ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile: + with ( + top_tempfile + ), controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, @@ -404,7 +407,11 @@ def test_invalid_connection( broken_proxy_two_tempfile = salt_master.pillar_tree.base.temp_file( f"{broken_proxy_two}.sls", broken_proxy_two_pillar_file ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, broken_proxy_one_tempfile, broken_proxy_two_tempfile: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), dummy_proxy_one_tempfile, broken_proxy_one_tempfile, broken_proxy_two_tempfile: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, @@ -533,7 +540,11 @@ def ping(): custom_proxy_module = salt_master.state_tree.base.temp_file( "_proxy/custom_dummy.py", module_contents ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, @@ -666,7 +677,11 @@ def ping(): custom_proxy_module = salt_master.state_tree.base.temp_file( "_proxy/custom_dummy.py", module_contents ) - with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, custom_proxy_module: factory = salt_master.salt_proxy_minion_daemon( proxy_minion_id, defaults=config_defaults, diff --git a/tests/pytests/integration/cluster/test_basic_cluster.py b/tests/pytests/integration/cluster/test_basic_cluster.py index 663a4a465db..1879d1c8425 100644 --- a/tests/pytests/integration/cluster/test_basic_cluster.py +++ b/tests/pytests/integration/cluster/test_basic_cluster.py @@ -1,6 +1,7 @@ """ Cluster integration tests. """ + import salt.utils.event diff --git a/tests/pytests/integration/grains/test_grains.py b/tests/pytests/integration/grains/test_grains.py index f83db6a97b8..6d374021caa 100644 --- a/tests/pytests/integration/grains/test_grains.py +++ b/tests/pytests/integration/grains/test_grains.py @@ -1,6 +1,7 @@ """ Grains include tests """ + import os diff --git a/tests/pytests/integration/master/test_payload.py b/tests/pytests/integration/master/test_payload.py index 692005b5692..9d663ac34ee 100644 --- a/tests/pytests/integration/master/test_payload.py +++ b/tests/pytests/integration/master/test_payload.py @@ -1,6 +1,7 @@ """ Tests for payload """ + import pytest diff --git a/tests/pytests/integration/minion/test_return_retries.py b/tests/pytests/integration/minion/test_return_retries.py index 058cfdc32be..be7885e7b44 100644 --- a/tests/pytests/integration/minion/test_return_retries.py +++ b/tests/pytests/integration/minion/test_return_retries.py @@ -108,7 +108,9 @@ def test_pillar_timeout(salt_master_factory, tmp_path): ) cli = master.salt_cli() sls_tempfile = master.state_tree.base.temp_file(f"{sls_name}.sls", sls_contents) - with master.started(), minion1.started(), minion2.started(), minion3.started(), minion4.started(), sls_tempfile: + with master.started(), minion1.started(), minion2.started(), minion3.started(), minion4.started(), ( + sls_tempfile + ): cmd = 'import time; time.sleep(6); print(\'{"foo": "bang"}\');\n' with salt.utils.files.fopen(tmp_path / "script.py", "w") as fp: fp.write(cmd) diff --git a/tests/pytests/integration/modules/grains/test_module.py b/tests/pytests/integration/modules/grains/test_module.py index cbbb149d2ad..bb977af9183 100644 --- a/tests/pytests/integration/modules/grains/test_module.py +++ b/tests/pytests/integration/modules/grains/test_module.py @@ -2,7 +2,6 @@ Test the grains module """ - import logging import time diff --git a/tests/pytests/integration/modules/saltutil/test_modules.py b/tests/pytests/integration/modules/saltutil/test_modules.py index 9d10189bb30..d35cb735f2e 100644 --- a/tests/pytests/integration/modules/saltutil/test_modules.py +++ b/tests/pytests/integration/modules/saltutil/test_modules.py @@ -2,7 +2,6 @@ Integration tests for the saltutil module. """ - import pytest pytestmark = [ diff --git a/tests/pytests/integration/modules/saltutil/test_pillar.py b/tests/pytests/integration/modules/saltutil/test_pillar.py index 7eb51605604..c1e451772c3 100644 --- a/tests/pytests/integration/modules/saltutil/test_pillar.py +++ b/tests/pytests/integration/modules/saltutil/test_pillar.py @@ -2,7 +2,6 @@ Integration tests for the saltutil module. """ - import logging import time diff --git a/tests/pytests/integration/modules/saltutil/test_wheel.py b/tests/pytests/integration/modules/saltutil/test_wheel.py index 51164c62399..3ddb95c2dc3 100644 --- a/tests/pytests/integration/modules/saltutil/test_wheel.py +++ b/tests/pytests/integration/modules/saltutil/test_wheel.py @@ -2,7 +2,6 @@ Integration tests for the saltutil module. """ - import pathlib import shutil diff --git a/tests/pytests/integration/modules/state/test_state_test.py b/tests/pytests/integration/modules/state/test_state_test.py index 40049e9a6b6..776350af1d9 100644 --- a/tests/pytests/integration/modules/state/test_state_test.py +++ b/tests/pytests/integration/modules/state/test_state_test.py @@ -173,7 +173,7 @@ def test_state_sls_id_test_true_post_run(salt_call_cli, testfile_path): assert ret.returncode == 0 assert testfile_path.exists() for val in ret.data.values(): - assert val["comment"] == "File {} updated".format(testfile_path) + assert val["comment"] == f"File {testfile_path} updated" assert val["changes"]["diff"] == "New file" ret = salt_call_cli.run("state.sls", "sls-id-test", test=True) @@ -195,7 +195,7 @@ def test_state_sls_id_test_false_pillar_true(salt_call_cli, testfile_path): ret = salt_call_cli.run("state.sls", "sls-id-test", test=False) assert ret.returncode == 0 for val in ret.data.values(): - assert val["comment"] == "File {} updated".format(testfile_path) + assert val["comment"] == f"File {testfile_path} updated" assert val["changes"]["diff"] == "New file" diff --git a/tests/pytests/integration/modules/test_beacons.py b/tests/pytests/integration/modules/test_beacons.py index 1a1ae274854..7908f4db609 100644 --- a/tests/pytests/integration/modules/test_beacons.py +++ b/tests/pytests/integration/modules/test_beacons.py @@ -1,6 +1,7 @@ """ :codeauthor: Justin Anderson """ + import pathlib import shutil diff --git a/tests/pytests/integration/modules/test_event.py b/tests/pytests/integration/modules/test_event.py index 172b2ab445b..b6ea0a2d1cb 100644 --- a/tests/pytests/integration/modules/test_event.py +++ b/tests/pytests/integration/modules/test_event.py @@ -2,6 +2,7 @@ tests.pytests.integration.modules.test_event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import time import pytest diff --git a/tests/pytests/integration/modules/test_file.py b/tests/pytests/integration/modules/test_file.py index 1489269a93f..f68031b67e7 100644 --- a/tests/pytests/integration/modules/test_file.py +++ b/tests/pytests/integration/modules/test_file.py @@ -1,6 +1,7 @@ """ Tests for the file state """ + import os import pytest @@ -110,7 +111,7 @@ def test_manage_file_verify_ssl( ) if not verify_ssl: assert ret.data["changes"] == {"diff": "New file", "mode": "0000"} - assert ret.data["comment"] == "File {} updated".format(test_file) + assert ret.data["comment"] == f"File {test_file} updated" else: assert "SSL: CERTIFICATE_VERIFY_FAILED" in ret.stderr diff --git a/tests/pytests/integration/modules/test_idem.py b/tests/pytests/integration/modules/test_idem.py index 90e319cab0d..9ddc3eb4412 100644 --- a/tests/pytests/integration/modules/test_idem.py +++ b/tests/pytests/integration/modules/test_idem.py @@ -1,6 +1,7 @@ """ Integration tests for the idem execution module """ + from contextlib import contextmanager import pytest diff --git a/tests/pytests/integration/modules/test_rpmbuild_pkgbuild.py b/tests/pytests/integration/modules/test_rpmbuild_pkgbuild.py index e4bc54b56e5..c9eaa3284b2 100644 --- a/tests/pytests/integration/modules/test_rpmbuild_pkgbuild.py +++ b/tests/pytests/integration/modules/test_rpmbuild_pkgbuild.py @@ -270,7 +270,7 @@ def gpg_agent(request, gpghome): shell=True, stdout=subprocess.PIPE, check=True, - universal_newlines=True, + text=True, ) if tuple(int(p) for p in gpg_version_proc.stdout.split(".")) >= (2, 1): kill_option_supported = True @@ -286,7 +286,7 @@ def gpg_agent(request, gpghome): ["pidof", "gpg-agent"], check=True, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ) except subprocess.CalledProcessError as exc: # Not running @@ -314,7 +314,7 @@ def gpg_agent(request, gpghome): ) ) subprocess.run( # nosec - "{}; {}".format(gpg_agent_cmd, echo_gpg_tty_cmd), shell=True, check=True + f"{gpg_agent_cmd}; {echo_gpg_tty_cmd}", shell=True, check=True ) yield finally: @@ -327,7 +327,7 @@ def gpg_agent(request, gpghome): ["pidof", "gpg-agent"], check=True, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ) except subprocess.CalledProcessError as exc: # Not running diff --git a/tests/pytests/integration/modules/test_state.py b/tests/pytests/integration/modules/test_state.py index c9804afb6a9..847a71df62c 100644 --- a/tests/pytests/integration/modules/test_state.py +++ b/tests/pytests/integration/modules/test_state.py @@ -24,7 +24,7 @@ def test_logging_and_state_output_order(salt_master, salt_minion, salt_cli, tmp_ target_path ) sls_tempfile = salt_master.state_tree.base.temp_file( - "{}.sls".format(sls_name), sls_contents + f"{sls_name}.sls", sls_contents ) with sls_tempfile: # Get the command line to use @@ -40,7 +40,7 @@ def test_logging_and_state_output_order(salt_master, salt_minion, salt_cli, tmp_ stderr=subprocess.STDOUT, check=False, shell=False, - universal_newlines=True, + text=True, ) assert ret.stdout assert not ret.stderr @@ -53,7 +53,7 @@ def test_logging_and_state_output_order(salt_master, salt_minion, salt_cli, tmp_ # This output order should not match and should trigger a _pytest.outcomes.Failed exception matcher.fnmatch_lines( [ - '"{}":*'.format(salt_minion.id), + f'"{salt_minion.id}":*', '"file_*', "*Reading configuration from*", ] @@ -66,7 +66,7 @@ def test_logging_and_state_output_order(salt_master, salt_minion, salt_cli, tmp_ # Confirm we have logging going on... "*Reading configuration from*", # And that after logging, we have the state output - '"{}":*'.format(salt_minion.id), + f'"{salt_minion.id}":*', '"file_*', ] ) diff --git a/tests/pytests/integration/modules/test_useradd.py b/tests/pytests/integration/modules/test_useradd.py index 6b180d89df6..25c2d7090da 100644 --- a/tests/pytests/integration/modules/test_useradd.py +++ b/tests/pytests/integration/modules/test_useradd.py @@ -1,6 +1,7 @@ """ Integration tests for modules/useradd.py and modules/win_useradd.py """ + import pytest from saltfactories.utils import random_string diff --git a/tests/pytests/integration/modules/test_virt.py b/tests/pytests/integration/modules/test_virt.py index 8f1c71e2238..2ce6eed7357 100644 --- a/tests/pytests/integration/modules/test_virt.py +++ b/tests/pytests/integration/modules/test_virt.py @@ -1,6 +1,7 @@ """ Validate the virt module """ + import logging from numbers import Number from xml.etree import ElementTree diff --git a/tests/pytests/integration/netapi/rest_cherrypy/test_arg_kwarg.py b/tests/pytests/integration/netapi/rest_cherrypy/test_arg_kwarg.py index 65e12a082d6..9db103d7a19 100644 --- a/tests/pytests/integration/netapi/rest_cherrypy/test_arg_kwarg.py +++ b/tests/pytests/integration/netapi/rest_cherrypy/test_arg_kwarg.py @@ -48,7 +48,7 @@ async def test_accepts_arg_kwarg_keys( arg = _low.pop("arg") body = urllib.parse.urlencode(_low) for _arg in arg: - body += "&arg={}".format(_arg) + body += f"&arg={_arg}" response = await http_client.fetch( "/", method="POST", @@ -70,7 +70,7 @@ async def test_accepts_arg_kwarg_keys( _low = low2.copy() arg = _low.pop("arg") body = urllib.parse.urlencode(_low) - body += "&arg={}".format(arg) + body += f"&arg={arg}" response = await http_client.fetch( "/", method="POST", diff --git a/tests/pytests/integration/netapi/rest_cherrypy/test_auth.py b/tests/pytests/integration/netapi/rest_cherrypy/test_auth.py index ce11207d2c1..0c46316eafe 100644 --- a/tests/pytests/integration/netapi/rest_cherrypy/test_auth.py +++ b/tests/pytests/integration/netapi/rest_cherrypy/test_auth.py @@ -54,7 +54,7 @@ async def test_good_login(http_client, auth_creds, content_type_map, client_conf cookies = response.headers["Set-Cookie"] response_obj = salt.utils.json.loads(response.body)["return"][0] token = response_obj["token"] - assert "session_id={}".format(token) in cookies + assert f"session_id={token}" in cookies perms = response_obj["perms"] perms_config = client_config["external_auth"]["auto"][auth_creds["username"]] assert set(perms) == set(perms_config) diff --git a/tests/pytests/integration/netapi/rest_tornado/test_jobs_api_handler.py b/tests/pytests/integration/netapi/rest_tornado/test_jobs_api_handler.py index 80cc53453f2..b47875b7410 100644 --- a/tests/pytests/integration/netapi/rest_tornado/test_jobs_api_handler.py +++ b/tests/pytests/integration/netapi/rest_tornado/test_jobs_api_handler.py @@ -37,7 +37,7 @@ async def test_get(http_client, subtests): # test with a specific JID passed in jid = next(iter(response_obj.keys())) response = await http_client.fetch( - "/jobs/{}".format(jid), + f"/jobs/{jid}", method="GET", follow_redirects=False, ) diff --git a/tests/pytests/integration/pillar/cache/test_pillar_cache.py b/tests/pytests/integration/pillar/cache/test_pillar_cache.py index d54bbfa082f..86f0d49d39b 100644 --- a/tests/pytests/integration/pillar/cache/test_pillar_cache.py +++ b/tests/pytests/integration/pillar/cache/test_pillar_cache.py @@ -1,6 +1,7 @@ """ Pillar cache tests """ + import pytest diff --git a/tests/pytests/integration/pillar/test_pillar_include.py b/tests/pytests/integration/pillar/test_pillar_include.py index 63a76599660..dfabd4cb99f 100644 --- a/tests/pytests/integration/pillar/test_pillar_include.py +++ b/tests/pytests/integration/pillar/test_pillar_include.py @@ -1,6 +1,7 @@ """ Pillar include tests """ + import pytest @@ -83,8 +84,16 @@ def pillar_include_tree(base_env_pillar_tree_root_dir, salt_minion, salt_call_cl "glob-include-b.sls", glob_include_b_pillar_file, base_env_pillar_tree_root_dir ) try: - with top_tempfile, include_tempfile, include_a_tempfile, include_b_tempfile, include_c_tempfile, include_d_tempfile: - with glob_include_tempfile, glob_include_a_tempfile, glob_include_b_tempfile: + with ( + top_tempfile + ), ( + include_tempfile + ), ( + include_a_tempfile + ), include_b_tempfile, include_c_tempfile, include_d_tempfile: + with ( + glob_include_tempfile + ), glob_include_a_tempfile, glob_include_b_tempfile: ret = salt_call_cli.run("saltutil.refresh_pillar", wait=True) assert ret.returncode == 0 assert ret.data is True diff --git a/tests/pytests/integration/proxy/conftest.py b/tests/pytests/integration/proxy/conftest.py index d924f4eba8a..6c2abb2688b 100644 --- a/tests/pytests/integration/proxy/conftest.py +++ b/tests/pytests/integration/proxy/conftest.py @@ -78,18 +78,24 @@ def deltaproxy_pillar_tree(request, 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_pillar_file + f"{proxy_one}.sls", dummy_proxy_pillar_file ) dummy_proxy_two_tempfile = salt_master.pillar_tree.base.temp_file( - "{}.sls".format(proxy_two), dummy_proxy_pillar_file + f"{proxy_two}.sls", dummy_proxy_pillar_file ) dummy_proxy_three_tempfile = salt_master.pillar_tree.base.temp_file( - "{}.sls".format(proxy_three), dummy_proxy_pillar_file + f"{proxy_three}.sls", dummy_proxy_pillar_file ) dummy_proxy_four_tempfile = salt_master.pillar_tree.base.temp_file( - "{}.sls".format(proxy_four), dummy_proxy_pillar_file + f"{proxy_four}.sls", 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: + with ( + top_tempfile + ), ( + controlproxy_tempfile + ), ( + dummy_proxy_one_tempfile + ), dummy_proxy_two_tempfile, dummy_proxy_three_tempfile, dummy_proxy_four_tempfile: yield diff --git a/tests/pytests/integration/proxy/test_deltaproxy.py b/tests/pytests/integration/proxy/test_deltaproxy.py index 48f23b18d68..c95c43f17bf 100644 --- a/tests/pytests/integration/proxy/test_deltaproxy.py +++ b/tests/pytests/integration/proxy/test_deltaproxy.py @@ -1,6 +1,7 @@ """ Simple Smoke Tests for Connected Proxy Minion """ + import logging import pytest diff --git a/tests/pytests/integration/proxy/test_shell.py b/tests/pytests/integration/proxy/test_shell.py index 44a0e137f75..fec736d7063 100644 --- a/tests/pytests/integration/proxy/test_shell.py +++ b/tests/pytests/integration/proxy/test_shell.py @@ -1,6 +1,7 @@ """ Simple Smoke Tests for Connected Proxy Minion """ + import logging import random diff --git a/tests/pytests/integration/proxy/test_simple.py b/tests/pytests/integration/proxy/test_simple.py index f3d26834ef9..048138e43e5 100644 --- a/tests/pytests/integration/proxy/test_simple.py +++ b/tests/pytests/integration/proxy/test_simple.py @@ -1,6 +1,7 @@ """ Simple Smoke Tests for Connected Proxy Minion """ + import logging import pytest diff --git a/tests/pytests/integration/runners/state/orchestrate/test_events.py b/tests/pytests/integration/runners/state/orchestrate/test_events.py index 4f0ecccb406..072317d4423 100644 --- a/tests/pytests/integration/runners/state/orchestrate/test_events.py +++ b/tests/pytests/integration/runners/state/orchestrate/test_events.py @@ -1,6 +1,7 @@ """ Tests for orchestration events """ + import concurrent.futures import functools import json diff --git a/tests/pytests/integration/runners/test_match.py b/tests/pytests/integration/runners/test_match.py index 3f7ebb2f09b..7a76ff59efe 100644 --- a/tests/pytests/integration/runners/test_match.py +++ b/tests/pytests/integration/runners/test_match.py @@ -1,6 +1,7 @@ """ Integration tests for the match runner """ + import logging import pytest diff --git a/tests/pytests/integration/sdb/test_vault.py b/tests/pytests/integration/sdb/test_vault.py index 047de78b01e..f5a4cf57870 100644 --- a/tests/pytests/integration/sdb/test_vault.py +++ b/tests/pytests/integration/sdb/test_vault.py @@ -1,6 +1,7 @@ """ Integration tests for the vault modules """ + import logging import pytest diff --git a/tests/pytests/integration/ssh/state/test_with_import_dir.py b/tests/pytests/integration/ssh/state/test_with_import_dir.py index 4048545bfc2..cc15dac1f2f 100644 --- a/tests/pytests/integration/ssh/state/test_with_import_dir.py +++ b/tests/pytests/integration/ssh/state/test_with_import_dir.py @@ -3,6 +3,7 @@ Verify salt-ssh can use imported map files in states when the map files are in another directory outside of sls files importing them. """ + import pytest pytestmark = [ diff --git a/tests/pytests/integration/ssh/test_jinja_mods.py b/tests/pytests/integration/ssh/test_jinja_mods.py index d730af16d02..aa745c7cdcd 100644 --- a/tests/pytests/integration/ssh/test_jinja_mods.py +++ b/tests/pytests/integration/ssh/test_jinja_mods.py @@ -21,7 +21,7 @@ def test_echo(salt_ssh_cli, base_env_state_tree_root_dir): echo=echo ) state_tempfile = pytest.helpers.temp_file( - "{}.sls".format(name), state_file, base_env_state_tree_root_dir + f"{name}.sls", state_file, base_env_state_tree_root_dir ) with state_tempfile: diff --git a/tests/pytests/integration/ssh/test_log.py b/tests/pytests/integration/ssh/test_log.py index e87c4a8581f..cc851407521 100644 --- a/tests/pytests/integration/ssh/test_log.py +++ b/tests/pytests/integration/ssh/test_log.py @@ -1,6 +1,7 @@ """ Integration tests for salt-ssh logging """ + import logging import time diff --git a/tests/pytests/integration/ssh/test_py_versions.py b/tests/pytests/integration/ssh/test_py_versions.py index 52ab819e808..cacd2ba97cb 100644 --- a/tests/pytests/integration/ssh/test_py_versions.py +++ b/tests/pytests/integration/ssh/test_py_versions.py @@ -1,6 +1,7 @@ """ Integration tests for salt-ssh py_versions """ + import logging import socket import time diff --git a/tests/pytests/integration/ssh/test_ssh_setup.py b/tests/pytests/integration/ssh/test_ssh_setup.py index 00e7e6394ff..2b68f5c4a48 100644 --- a/tests/pytests/integration/ssh/test_ssh_setup.py +++ b/tests/pytests/integration/ssh/test_ssh_setup.py @@ -1,6 +1,7 @@ """ Integration tests for salt-ssh py_versions """ + import logging import os import signal diff --git a/tests/pytests/integration/states/test_beacon.py b/tests/pytests/integration/states/test_beacon.py index 5d6737e6a18..5aefa6ecf2b 100644 --- a/tests/pytests/integration/states/test_beacon.py +++ b/tests/pytests/integration/states/test_beacon.py @@ -1,6 +1,7 @@ """ Integration tests for the beacon states """ + import logging import pytest diff --git a/tests/pytests/integration/states/test_file.py b/tests/pytests/integration/states/test_file.py index 4b286a854f4..1233b0b2998 100644 --- a/tests/pytests/integration/states/test_file.py +++ b/tests/pytests/integration/states/test_file.py @@ -1,6 +1,7 @@ """ Tests for the file state """ + import logging import os import pathlib @@ -656,7 +657,9 @@ def test_patch_single_file_failure( math_tempfile = pytest.helpers.temp_file(math_file, content[1], tmp_path) reject_tempfile = pytest.helpers.temp_file("reject.txt", "", tmp_path) - with sls_tempfile, sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: + with ( + sls_tempfile + ), sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: # Empty the file to ensure that the patch doesn't apply cleanly with salt.utils.files.fopen(numbers_file, "w"): pass @@ -729,7 +732,9 @@ def test_patch_directory_failure( math_tempfile = pytest.helpers.temp_file(math_file, content[1], tmp_path) reject_tempfile = pytest.helpers.temp_file("reject.txt", "", tmp_path) - with sls_tempfile, sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: + with ( + sls_tempfile + ), sls_reject_tempfile, numbers_tempfile, math_tempfile, reject_tempfile: # Empty the file to ensure that the patch doesn't apply cleanly with salt.utils.files.fopen(math_file, "w"): pass diff --git a/tests/pytests/integration/states/test_idem.py b/tests/pytests/integration/states/test_idem.py index feab60d4951..86d253036e7 100644 --- a/tests/pytests/integration/states/test_idem.py +++ b/tests/pytests/integration/states/test_idem.py @@ -1,6 +1,7 @@ """ Tests for the idem state """ + import tempfile from contextlib import contextmanager @@ -62,5 +63,5 @@ def test_bad_state(salt_call_cli): parent = ret.data["idem_|-idem_bad_test_|-idem_bad_test_|-state"] assert parent["result"] is False - assert "SLS ref {} did not resolve to a file".format(bad_sls) == parent["comment"] + assert f"SLS ref {bad_sls} did not resolve to a file" == parent["comment"] assert not parent["sub_state_run"] diff --git a/tests/pytests/integration/states/test_include.py b/tests/pytests/integration/states/test_include.py index 62ee7efeaf8..829ccddd130 100644 --- a/tests/pytests/integration/states/test_include.py +++ b/tests/pytests/integration/states/test_include.py @@ -1,6 +1,7 @@ """ Integration tests for the jinja includes in states """ + import logging import pytest diff --git a/tests/pytests/integration/utils/test_templates.py b/tests/pytests/integration/utils/test_templates.py index 241bd8f58d8..595dcebe0ac 100644 --- a/tests/pytests/integration/utils/test_templates.py +++ b/tests/pytests/integration/utils/test_templates.py @@ -1,6 +1,7 @@ """ Tests for the templates utils """ + import os import pytest @@ -25,7 +26,7 @@ def test_issue_60083( {{ pillar|json }} """ sls_tempfile = pytest.helpers.temp_file( - "{}.sls".format(sls_name), sls_contents, base_env_state_tree_root_dir + f"{sls_name}.sls", sls_contents, base_env_state_tree_root_dir ) with sls_tempfile: # , issue_50221_ext_pillar_tempfile: ret = salt_call_cli.run( @@ -60,7 +61,7 @@ def test_issue_62372( {{ my_list | random_shuffle(seed="static") }} """ sls_tempfile = pytest.helpers.temp_file( - "{}.sls".format(sls_name), sls_contents, base_env_state_tree_root_dir + f"{sls_name}.sls", sls_contents, base_env_state_tree_root_dir ) with sls_tempfile: ret = salt_call_cli.run( diff --git a/tests/pytests/integration/wheel/test_pillar_roots.py b/tests/pytests/integration/wheel/test_pillar_roots.py index df6bb578550..c107f1646b3 100644 --- a/tests/pytests/integration/wheel/test_pillar_roots.py +++ b/tests/pytests/integration/wheel/test_pillar_roots.py @@ -37,7 +37,7 @@ def test_write_subdir(client, salt_master): def test_cvr_2021_25282(client, pillar_file_path): ret = client.cmd( "pillar_roots.write", - kwarg={"data": "foo", "path": "../{}".format(pillar_file_path.name)}, + kwarg={"data": "foo", "path": f"../{pillar_file_path.name}"}, ) assert not pillar_file_path.parent.parent.joinpath(pillar_file_path.name).is_file() assert ret.find("Invalid path") != -1 @@ -46,7 +46,7 @@ def test_cvr_2021_25282(client, pillar_file_path): def test_cvr_2021_25282_subdir(client, pillar_file_path): ret = client.cmd( "pillar_roots.write", - kwarg={"data": "foo", "path": "../../{}".format(pillar_file_path.name)}, + kwarg={"data": "foo", "path": f"../../{pillar_file_path.name}"}, ) assert not pillar_file_path.parent.parent.parent.joinpath( pillar_file_path.name diff --git a/tests/pytests/pkg/conftest.py b/tests/pytests/pkg/conftest.py index 048ad7a238d..20d71f14228 100644 --- a/tests/pytests/pkg/conftest.py +++ b/tests/pytests/pkg/conftest.py @@ -373,12 +373,12 @@ def salt_minion(salt_factories, salt_master, install_salt): "open_mode": True, } if platform.is_windows(): - config_overrides[ - "winrepo_dir" - ] = rf"{salt_factories.root_dir}\srv\salt\win\repo" - config_overrides[ - "winrepo_dir_ng" - ] = rf"{salt_factories.root_dir}\srv\salt\win\repo_ng" + config_overrides["winrepo_dir"] = ( + rf"{salt_factories.root_dir}\srv\salt\win\repo" + ) + config_overrides["winrepo_dir_ng"] = ( + rf"{salt_factories.root_dir}\srv\salt\win\repo_ng" + ) config_overrides["winrepo_source_dir"] = r"salt://win/repo_ng" if install_salt.classic and platform.is_windows(): diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index a71d4b038e9..d25db84383f 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -1,6 +1,7 @@ """ Test Salt Pkg Downloads """ + import contextlib import logging import os diff --git a/tests/pytests/scenarios/blackout/conftest.py b/tests/pytests/scenarios/blackout/conftest.py index 09cee10db66..dd025aa0d74 100644 --- a/tests/pytests/scenarios/blackout/conftest.py +++ b/tests/pytests/scenarios/blackout/conftest.py @@ -76,7 +76,7 @@ class BlackoutPillar: ) else: pytest.fail( - "Minion did not refresh pillar after {} seconds".format(timeout) + f"Minion did not refresh pillar after {timeout} seconds" ) time.sleep(sleep) diff --git a/tests/pytests/scenarios/blackout/test_minion_blackout.py b/tests/pytests/scenarios/blackout/test_minion_blackout.py index 581ad2b135b..ed5fca72c48 100644 --- a/tests/pytests/scenarios/blackout/test_minion_blackout.py +++ b/tests/pytests/scenarios/blackout/test_minion_blackout.py @@ -2,7 +2,6 @@ Tests for minion blackout """ - import logging import pytest diff --git a/tests/pytests/scenarios/cluster/test_cluster.py b/tests/pytests/scenarios/cluster/test_cluster.py index 35899a2a1e9..5f81f30b09a 100644 --- a/tests/pytests/scenarios/cluster/test_cluster.py +++ b/tests/pytests/scenarios/cluster/test_cluster.py @@ -1,6 +1,7 @@ """ Cluster scinarios. """ + import os import pathlib import time @@ -27,9 +28,9 @@ def test_cluster_key_rotation( cluster_master_3, ): config = cluster_minion_1.config.copy() - config[ - "master_uri" - ] = f"tcp://{master.config['interface']}:{master.config['ret_port']}" + config["master_uri"] = ( + f"tcp://{master.config['interface']}:{master.config['ret_port']}" + ) auth = salt.crypt.SAuth(config) auth.authenticate() assert "aes" in auth._creds @@ -64,9 +65,9 @@ def test_cluster_key_rotation( cluster_master_3, ): config = cluster_minion_1.config.copy() - config[ - "master_uri" - ] = f"tcp://{master.config['interface']}:{master.config['ret_port']}" + config["master_uri"] = ( + f"tcp://{master.config['interface']}:{master.config['ret_port']}" + ) auth = salt.crypt.SAuth(config) auth.authenticate() assert "aes" in auth._creds diff --git a/tests/pytests/scenarios/compat/conftest.py b/tests/pytests/scenarios/compat/conftest.py index 29d58354abc..e42c4c9259a 100644 --- a/tests/pytests/scenarios/compat/conftest.py +++ b/tests/pytests/scenarios/compat/conftest.py @@ -4,6 +4,7 @@ Salt Compatibility PyTest Fixtures """ + import logging import os import shutil @@ -61,7 +62,7 @@ def host_docker_network_ip_address(docker_client): ipam_pools=[{"subnet": network_subnet, "gateway": network_gateway}], ) assert isinstance(ret, dict), ret - assert ret["result"], "Failed to create docker network: {}".format(ret) + assert ret["result"], f"Failed to create docker network: {ret}" yield network_gateway finally: sminion.states.docker_network.absent(network_name) diff --git a/tests/pytests/scenarios/compat/test_with_versions.py b/tests/pytests/scenarios/compat/test_with_versions.py index ecb3a73de1a..cc61a01f509 100644 --- a/tests/pytests/scenarios/compat/test_with_versions.py +++ b/tests/pytests/scenarios/compat/test_with_versions.py @@ -4,6 +4,7 @@ Test current salt master with older salt minions """ + import logging import pathlib diff --git a/tests/pytests/scenarios/failover/multimaster/conftest.py b/tests/pytests/scenarios/failover/multimaster/conftest.py index 3a2c941a200..970c1e59137 100644 --- a/tests/pytests/scenarios/failover/multimaster/conftest.py +++ b/tests/pytests/scenarios/failover/multimaster/conftest.py @@ -91,8 +91,8 @@ def salt_mm_failover_minion_1(salt_mm_failover_master_1, salt_mm_failover_master mm_master_2_addr = salt_mm_failover_master_2.config["interface"] config_overrides = { "master": [ - "{}:{}".format(mm_master_1_addr, mm_master_1_port), - "{}:{}".format(mm_master_2_addr, mm_master_2_port), + f"{mm_master_1_addr}:{mm_master_1_port}", + f"{mm_master_2_addr}:{mm_master_2_port}", ], "publish_port": salt_mm_failover_master_1.config["publish_port"], "master_type": "failover", @@ -129,8 +129,8 @@ def salt_mm_failover_minion_2(salt_mm_failover_master_1, salt_mm_failover_master # We put the second master first in the list so it has the right startup checks every time. config_overrides = { "master": [ - "{}:{}".format(mm_master_2_addr, mm_master_2_port), - "{}:{}".format(mm_master_1_addr, mm_master_1_port), + f"{mm_master_2_addr}:{mm_master_2_port}", + f"{mm_master_1_addr}:{mm_master_1_port}", ], "publish_port": salt_mm_failover_master_1.config["publish_port"], "master_type": "failover", @@ -174,7 +174,7 @@ def run_salt_cmds(): for minion in list(minions_to_check): try: ret = cli.run( - "--timeout={}".format(timeout), + f"--timeout={timeout}", "test.ping", minion_tgt=minion, ) diff --git a/tests/pytests/scenarios/failover/multimaster/test_failover_master.py b/tests/pytests/scenarios/failover/multimaster/test_failover_master.py index 6efecfb8334..f661e9ab9a4 100644 --- a/tests/pytests/scenarios/failover/multimaster/test_failover_master.py +++ b/tests/pytests/scenarios/failover/multimaster/test_failover_master.py @@ -28,8 +28,8 @@ def test_pki(salt_mm_failover_master_1, salt_mm_failover_master_2, caplog): mm_master_2_addr = salt_mm_failover_master_2.config["interface"] config_overrides = { "master": [ - "{}:{}".format(mm_master_1_addr, mm_master_1_port), - "{}:{}".format(mm_master_2_addr, mm_master_2_port), + f"{mm_master_1_addr}:{mm_master_1_port}", + f"{mm_master_2_addr}:{mm_master_2_port}", ], "publish_port": salt_mm_failover_master_1.config["publish_port"], "master_type": "failover", @@ -94,7 +94,7 @@ def test_failover_to_second_master( event_patterns = [ ( salt_mm_failover_master_2.id, - "salt/minion/{}/start".format(salt_mm_failover_minion_1.id), + f"salt/minion/{salt_mm_failover_minion_1.id}/start", ) ] @@ -184,19 +184,19 @@ def test_minions_alive_with_no_master( event_patterns = [ ( salt_mm_failover_master_1.id, - "salt/minion/{}/start".format(salt_mm_failover_minion_1.id), + f"salt/minion/{salt_mm_failover_minion_1.id}/start", ), ( salt_mm_failover_master_1.id, - "salt/minion/{}/start".format(salt_mm_failover_minion_2.id), + f"salt/minion/{salt_mm_failover_minion_2.id}/start", ), ( salt_mm_failover_master_2.id, - "salt/minion/{}/start".format(salt_mm_failover_minion_1.id), + f"salt/minion/{salt_mm_failover_minion_1.id}/start", ), ( salt_mm_failover_master_2.id, - "salt/minion/{}/start".format(salt_mm_failover_minion_2.id), + f"salt/minion/{salt_mm_failover_minion_2.id}/start", ), ] events = event_listener.wait_for_events( @@ -208,7 +208,7 @@ def test_minions_alive_with_no_master( assert len(events.matches) >= 2 expected_tags = { - "salt/minion/{}/start".format(salt_mm_failover_minion_1.id), - "salt/minion/{}/start".format(salt_mm_failover_minion_2.id), + f"salt/minion/{salt_mm_failover_minion_1.id}/start", + f"salt/minion/{salt_mm_failover_minion_2.id}/start", } assert {event.tag for event in events} == expected_tags diff --git a/tests/pytests/scenarios/multimaster/conftest.py b/tests/pytests/scenarios/multimaster/conftest.py index ff230a2b46e..1bfc830cb00 100644 --- a/tests/pytests/scenarios/multimaster/conftest.py +++ b/tests/pytests/scenarios/multimaster/conftest.py @@ -91,8 +91,8 @@ def salt_mm_minion_1(salt_mm_master_1, salt_mm_master_2): mm_master_2_addr = salt_mm_master_2.config["interface"] config_overrides = { "master": [ - "{}:{}".format(mm_master_1_addr, mm_master_1_port), - "{}:{}".format(mm_master_2_addr, mm_master_2_port), + f"{mm_master_1_addr}:{mm_master_1_port}", + f"{mm_master_2_addr}:{mm_master_2_port}", ], "test.foo": "baz", } @@ -118,8 +118,8 @@ def salt_mm_minion_2(salt_mm_master_1, salt_mm_master_2): mm_master_2_addr = salt_mm_master_2.config["interface"] config_overrides = { "master": [ - "{}:{}".format(mm_master_1_addr, mm_master_1_port), - "{}:{}".format(mm_master_2_addr, mm_master_2_port), + f"{mm_master_1_addr}:{mm_master_1_port}", + f"{mm_master_2_addr}:{mm_master_2_port}", ], "test.foo": "baz", } @@ -157,7 +157,7 @@ def run_salt_cmds(): for cli in list(clis_to_check[minion]): try: ret = cli.run( - "--timeout={}".format(timeout), + f"--timeout={timeout}", "test.ping", minion_tgt=minion, _timeout=2 * timeout, diff --git a/tests/pytests/scenarios/multimaster/test_multimaster.py b/tests/pytests/scenarios/multimaster/test_multimaster.py index 8f8c8cf9055..a40e7a39622 100644 --- a/tests/pytests/scenarios/multimaster/test_multimaster.py +++ b/tests/pytests/scenarios/multimaster/test_multimaster.py @@ -110,7 +110,7 @@ def test_minion_reconnection_attempts( assert salt_mm_minion_2.is_running() start_events = event_listener.wait_for_events( - [(salt_mm_master_1.id, "salt/minion/{}/start".format(salt_mm_minion_1.id))], + [(salt_mm_master_1.id, f"salt/minion/{salt_mm_minion_1.id}/start")], timeout=60, after_time=start_time, ) @@ -123,7 +123,7 @@ def test_minion_reconnection_attempts( start_time = time.time() start_events = event_listener.wait_for_events( - [(salt_mm_master_2.id, "salt/minion/{}/start".format(salt_mm_minion_1.id))], + [(salt_mm_master_2.id, f"salt/minion/{salt_mm_minion_1.id}/start")], timeout=60, after_time=start_time, ) diff --git a/tests/pytests/scenarios/performance/conftest.py b/tests/pytests/scenarios/performance/conftest.py index 2485cf51fd3..89c92bb599e 100644 --- a/tests/pytests/scenarios/performance/conftest.py +++ b/tests/pytests/scenarios/performance/conftest.py @@ -1,6 +1,7 @@ """ Salt performance tests """ + import logging import shutil diff --git a/tests/pytests/scenarios/setup/test_install.py b/tests/pytests/scenarios/setup/test_install.py index 9c506b56cab..5953a9640c5 100644 --- a/tests/pytests/scenarios/setup/test_install.py +++ b/tests/pytests/scenarios/setup/test_install.py @@ -1,6 +1,7 @@ """ Tests for building and installing salt """ + import json import logging import os diff --git a/tests/pytests/scenarios/setup/test_man.py b/tests/pytests/scenarios/setup/test_man.py index 28f0d6285a3..92b91e8e6d0 100644 --- a/tests/pytests/scenarios/setup/test_man.py +++ b/tests/pytests/scenarios/setup/test_man.py @@ -59,7 +59,7 @@ def test_man_pages(virtualenv, src_dir): venv.venv_python, "setup.py", "install", - "--root={}".format(rootdir), + f"--root={rootdir}", cwd=src_dir, ) diff --git a/tests/pytests/unit/auth/test_ldap.py b/tests/pytests/unit/auth/test_ldap.py index fe973701af3..6a43bb350d0 100644 --- a/tests/pytests/unit/auth/test_ldap.py +++ b/tests/pytests/unit/auth/test_ldap.py @@ -1,6 +1,7 @@ """ Unit tests for salt.auth.ldap """ + import pytest import salt.auth.ldap diff --git a/tests/pytests/unit/beacons/test_adb.py b/tests/pytests/unit/beacons/test_adb.py index 0d9ee99ee6a..945e782093b 100644 --- a/tests/pytests/unit/beacons/test_adb.py +++ b/tests/pytests/unit/beacons/test_adb.py @@ -4,6 +4,7 @@ ADB beacon test cases """ + import pytest import salt.beacons.adb as adb diff --git a/tests/pytests/unit/beacons/test_avahi_announce.py b/tests/pytests/unit/beacons/test_avahi_announce.py index 2eb95a35a2f..bd7359dcd58 100644 --- a/tests/pytests/unit/beacons/test_avahi_announce.py +++ b/tests/pytests/unit/beacons/test_avahi_announce.py @@ -4,6 +4,7 @@ Avahi announce beacon test cases """ + import pytest import salt.beacons.avahi_announce as avahi_announce diff --git a/tests/pytests/unit/beacons/test_bonjour_announce.py b/tests/pytests/unit/beacons/test_bonjour_announce.py index c5551edebfd..25df0ffbd13 100644 --- a/tests/pytests/unit/beacons/test_bonjour_announce.py +++ b/tests/pytests/unit/beacons/test_bonjour_announce.py @@ -4,6 +4,7 @@ Bonjour announce beacon test cases """ + import pytest import salt.beacons.bonjour_announce as bonjour_announce diff --git a/tests/pytests/unit/beacons/test_btmp.py b/tests/pytests/unit/beacons/test_btmp.py index 6ea03fbfdbd..1ae0d2cf23e 100644 --- a/tests/pytests/unit/beacons/test_btmp.py +++ b/tests/pytests/unit/beacons/test_btmp.py @@ -232,7 +232,7 @@ def test_match_group(): with patch("time.time", MagicMock(return_value=1506121200)): with patch("struct.unpack", MagicMock(return_value=pack)): with patch( - "{}.info".format(groupadd), + f"{groupadd}.info", new=MagicMock(return_value=mock_group_info), ): config = [ diff --git a/tests/pytests/unit/beacons/test_diskusage.py b/tests/pytests/unit/beacons/test_diskusage.py index e37863cd733..94fff2fa918 100644 --- a/tests/pytests/unit/beacons/test_diskusage.py +++ b/tests/pytests/unit/beacons/test_diskusage.py @@ -4,6 +4,7 @@ Disk usage beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_glxinfo.py b/tests/pytests/unit/beacons/test_glxinfo.py index b556c2cafa9..4888c6301d2 100644 --- a/tests/pytests/unit/beacons/test_glxinfo.py +++ b/tests/pytests/unit/beacons/test_glxinfo.py @@ -4,6 +4,7 @@ glxinfo beacon test cases """ + import pytest import salt.beacons.glxinfo as glxinfo diff --git a/tests/pytests/unit/beacons/test_haproxy.py b/tests/pytests/unit/beacons/test_haproxy.py index 33197cb1414..dc0c961d547 100644 --- a/tests/pytests/unit/beacons/test_haproxy.py +++ b/tests/pytests/unit/beacons/test_haproxy.py @@ -4,6 +4,7 @@ HAProxy beacon test cases """ + import pytest import salt.beacons.haproxy as haproxy diff --git a/tests/pytests/unit/beacons/test_load.py b/tests/pytests/unit/beacons/test_load.py index a0a28428e4b..0f57465cfe3 100644 --- a/tests/pytests/unit/beacons/test_load.py +++ b/tests/pytests/unit/beacons/test_load.py @@ -4,6 +4,7 @@ Load beacon test cases """ + import pytest import salt.beacons.load as load diff --git a/tests/pytests/unit/beacons/test_log_beacon.py b/tests/pytests/unit/beacons/test_log_beacon.py index f0dc61865cb..18184936d9d 100644 --- a/tests/pytests/unit/beacons/test_log_beacon.py +++ b/tests/pytests/unit/beacons/test_log_beacon.py @@ -4,6 +4,7 @@ log beacon test cases """ + import pytest import salt.beacons.log_beacon as log_beacon diff --git a/tests/pytests/unit/beacons/test_memusage.py b/tests/pytests/unit/beacons/test_memusage.py index bab3d5321e2..6f172c9c1d8 100644 --- a/tests/pytests/unit/beacons/test_memusage.py +++ b/tests/pytests/unit/beacons/test_memusage.py @@ -4,6 +4,7 @@ Memory usage beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_network_info.py b/tests/pytests/unit/beacons/test_network_info.py index 2f356f41ac0..5ea31605484 100644 --- a/tests/pytests/unit/beacons/test_network_info.py +++ b/tests/pytests/unit/beacons/test_network_info.py @@ -4,6 +4,7 @@ Network info beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_ps.py b/tests/pytests/unit/beacons/test_ps.py index 2d1df7ff15d..da6baa2bc0b 100644 --- a/tests/pytests/unit/beacons/test_ps.py +++ b/tests/pytests/unit/beacons/test_ps.py @@ -4,6 +4,7 @@ ps usage beacon test cases """ + import pytest import salt.beacons.ps as ps diff --git a/tests/pytests/unit/beacons/test_swapusage.py b/tests/pytests/unit/beacons/test_swapusage.py index 5ffed290bf8..39070ce49bf 100644 --- a/tests/pytests/unit/beacons/test_swapusage.py +++ b/tests/pytests/unit/beacons/test_swapusage.py @@ -4,6 +4,7 @@ Swap usage beacon test cases """ + from collections import namedtuple import pytest diff --git a/tests/pytests/unit/beacons/test_wtmp.py b/tests/pytests/unit/beacons/test_wtmp.py index 3788ef05cb5..cd0c9d1df6f 100644 --- a/tests/pytests/unit/beacons/test_wtmp.py +++ b/tests/pytests/unit/beacons/test_wtmp.py @@ -236,7 +236,7 @@ def test_match_group(): with patch("time.time", MagicMock(return_value=1506121200)): with patch("struct.unpack", MagicMock(return_value=pack)): with patch( - "{}.info".format(groupadd), + f"{groupadd}.info", new=MagicMock(return_value=mock_group_info), ): config = [ diff --git a/tests/pytests/unit/cache/test_localfs.py b/tests/pytests/unit/cache/test_localfs.py index cda71066368..e5f7c6cc30b 100644 --- a/tests/pytests/unit/cache/test_localfs.py +++ b/tests/pytests/unit/cache/test_localfs.py @@ -1,6 +1,7 @@ """ Validate the functions in the localfs cache """ + import errno import shutil diff --git a/tests/pytests/unit/cache/test_memcache.py b/tests/pytests/unit/cache/test_memcache.py index d8a074c5c35..7a1d9374335 100644 --- a/tests/pytests/unit/cache/test_memcache.py +++ b/tests/pytests/unit/cache/test_memcache.py @@ -1,6 +1,7 @@ """ Validate Cache class methods """ + import pytest import salt.cache diff --git a/tests/pytests/unit/cache/test_mysql_cache.py b/tests/pytests/unit/cache/test_mysql_cache.py index 9d1bcf72c75..930a191e3fa 100644 --- a/tests/pytests/unit/cache/test_mysql_cache.py +++ b/tests/pytests/unit/cache/test_mysql_cache.py @@ -2,7 +2,6 @@ unit tests for the mysql_cache cache """ - import logging import pytest diff --git a/tests/pytests/unit/client/ssh/wrapper/test_config.py b/tests/pytests/unit/client/ssh/wrapper/test_config.py index 64e89c762ad..a708b925fdf 100644 --- a/tests/pytests/unit/client/ssh/wrapper/test_config.py +++ b/tests/pytests/unit/client/ssh/wrapper/test_config.py @@ -3,7 +3,6 @@ This tests the SSH wrapper module. """ - import fnmatch import pytest diff --git a/tests/pytests/unit/client/ssh/wrapper/test_cp.py b/tests/pytests/unit/client/ssh/wrapper/test_cp.py index 58f8334721c..77f8ebb0878 100644 --- a/tests/pytests/unit/client/ssh/wrapper/test_cp.py +++ b/tests/pytests/unit/client/ssh/wrapper/test_cp.py @@ -6,6 +6,7 @@ tests.pytests.unit.fileclient.test_fileclient_cache. + additional ones below """ + import errno import logging import os diff --git a/tests/pytests/unit/cloud/clouds/test_digitalocean.py b/tests/pytests/unit/cloud/clouds/test_digitalocean.py index 68990adf8ac..0b3316675b0 100644 --- a/tests/pytests/unit/cloud/clouds/test_digitalocean.py +++ b/tests/pytests/unit/cloud/clouds/test_digitalocean.py @@ -5,7 +5,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import pytest diff --git a/tests/pytests/unit/cloud/clouds/test_hetzner.py b/tests/pytests/unit/cloud/clouds/test_hetzner.py index cfe5bb4e85e..c423d83dbca 100644 --- a/tests/pytests/unit/cloud/clouds/test_hetzner.py +++ b/tests/pytests/unit/cloud/clouds/test_hetzner.py @@ -490,9 +490,9 @@ def test_destroy(): connect.return_value.servers.get_by_name.return_value = None hetzner.destroy("myvm", "action") - server = ( - connect.return_value.servers.get_by_name.return_value - ) = MagicMock() + server = connect.return_value.servers.get_by_name.return_value = ( + MagicMock() + ) # Stop the server before shutdown but failed hetzner.destroy("myvm", "action") @@ -531,9 +531,9 @@ def test_resize(): hetzner.resize("myvm", kwargs, "action") - server = ( - connect.return_value.servers.get_by_name.return_value - ) = MagicMock() + server = connect.return_value.servers.get_by_name.return_value = ( + MagicMock() + ) # Invalid server size with pytest.raises(SaltCloudException): diff --git a/tests/pytests/unit/cloud/clouds/test_proxmox.py b/tests/pytests/unit/cloud/clouds/test_proxmox.py index 1d1823a8035..8aba387c372 100644 --- a/tests/pytests/unit/cloud/clouds/test_proxmox.py +++ b/tests/pytests/unit/cloud/clouds/test_proxmox.py @@ -156,14 +156,14 @@ def test__reconfigure_clone_params(): "onboot": "0", "sshkeys": "ssh-rsa ABCDEF user@host\n", } - query_calls = [call("get", "nodes/myhost/qemu/{}/config".format(vmid))] + query_calls = [call("get", f"nodes/myhost/qemu/{vmid}/config")] for key, value in properties.items(): if key == "sshkeys": value = urllib.parse.quote(value, safe="") query_calls.append( call( "post", - "nodes/myhost/qemu/{}/config".format(vmid), + f"nodes/myhost/qemu/{vmid}/config", {key: value}, ) ) @@ -346,7 +346,7 @@ def test_find_agent_ips(): # CASE 1: Test ipv4 and ignore_cidr result = proxmox._find_agent_ip(vm_, ANY) mock_query.assert_any_call( - "get", "nodes/myhost/qemu/{}/agent/network-get-interfaces".format(ANY) + "get", f"nodes/myhost/qemu/{ANY}/agent/network-get-interfaces" ) assert result == "2.3.4.5" @@ -356,7 +356,7 @@ def test_find_agent_ips(): vm_["protocol"] = "ipv6" result = proxmox._find_agent_ip(vm_, ANY) mock_query.assert_any_call( - "get", "nodes/myhost/qemu/{}/agent/network-get-interfaces".format(ANY) + "get", f"nodes/myhost/qemu/{ANY}/agent/network-get-interfaces" ) assert result == "2001::1:2" @@ -515,6 +515,6 @@ def test_creation_failure_logging(caplog): break if missing: raise AssertionError( - "Did not find error messages: {}".format(sorted(list(missing))) + f"Did not find error messages: {sorted(list(missing))}" ) return diff --git a/tests/pytests/unit/cloud/clouds/test_saltify.py b/tests/pytests/unit/cloud/clouds/test_saltify.py index 8dd0359185a..851c05d0f80 100644 --- a/tests/pytests/unit/cloud/clouds/test_saltify.py +++ b/tests/pytests/unit/cloud/clouds/test_saltify.py @@ -1,6 +1,7 @@ """ :codeauthor: Alexander Schwartz """ + import pytest import salt.client diff --git a/tests/pytests/unit/cloud/clouds/test_vultrpy.py b/tests/pytests/unit/cloud/clouds/test_vultrpy.py index a388ba7f2a5..2945588280d 100644 --- a/tests/pytests/unit/cloud/clouds/test_vultrpy.py +++ b/tests/pytests/unit/cloud/clouds/test_vultrpy.py @@ -96,7 +96,9 @@ def test_create_firewall_ssh(): patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with ( + patch_scripts + ), patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: vultr.create(kwargs) query_ret = mock_query.call_args.kwargs["data"] assert "SSHKEYID=key1%2Ckey2%2Ckey3" in query_ret @@ -143,7 +145,9 @@ def test_create_firewall_doesnotexist(caplog): patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with ( + patch_scripts + ), patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: with caplog.at_level(logging.INFO): ret = vultr.create(kwargs) assert ( @@ -193,7 +197,9 @@ def test_create_ssh_key_ids_doesnotexist(caplog): patch_show = patch("salt.cloud.clouds.vultrpy.show_instance", MagicMock()) - with patch_scripts, patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: + with ( + patch_scripts + ), patch_firewall, patch_keys, patch_vultrid, patch_query, patch_show: with caplog.at_level(logging.INFO): ret = vultr.create(kwargs) assert ( diff --git a/tests/pytests/unit/config/schemas/test_ssh.py b/tests/pytests/unit/config/schemas/test_ssh.py index 93692edabd4..5616c341a15 100644 --- a/tests/pytests/unit/config/schemas/test_ssh.py +++ b/tests/pytests/unit/config/schemas/test_ssh.py @@ -146,7 +146,7 @@ def test_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -155,7 +155,7 @@ def test_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -164,7 +164,7 @@ def test_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -173,7 +173,7 @@ def test_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -188,7 +188,7 @@ def test_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -202,7 +202,7 @@ def test_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") with pytest.raises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -259,7 +259,7 @@ def test_roster_config_validate(): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - pytest.fail("ValidationError raised: {}".format(exc)) + pytest.fail(f"ValidationError raised: {exc}") with pytest.raises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( diff --git a/tests/pytests/unit/config/test__validate_opts.py b/tests/pytests/unit/config/test__validate_opts.py index 741631e6f81..f07a60c3c1f 100644 --- a/tests/pytests/unit/config/test__validate_opts.py +++ b/tests/pytests/unit/config/test__validate_opts.py @@ -1,6 +1,7 @@ """ Test config option type enforcement """ + import pytest import salt.config diff --git a/tests/pytests/unit/crypt/test_crypt.py b/tests/pytests/unit/crypt/test_crypt.py index 098c42d0dd9..6062dd0c44d 100644 --- a/tests/pytests/unit/crypt/test_crypt.py +++ b/tests/pytests/unit/crypt/test_crypt.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_crypt Unit tests for salt's crypt module """ + import uuid import pytest diff --git a/tests/pytests/unit/engines/test_engines.py b/tests/pytests/unit/engines/test_engines.py index aaf8280a74d..f83ced785b0 100644 --- a/tests/pytests/unit/engines/test_engines.py +++ b/tests/pytests/unit/engines/test_engines.py @@ -8,7 +8,7 @@ from tests.support.mock import MagicMock, patch def kwargs(): opts = {"__role": "minion"} name = "foobar" - fun = "{}.start".format(name) + fun = f"{name}.start" config = funcs = runners = proxy = {} return dict( opts=opts, diff --git a/tests/pytests/unit/engines/test_libvirt_events.py b/tests/pytests/unit/engines/test_libvirt_events.py index 382ec311732..a83a1948fac 100644 --- a/tests/pytests/unit/engines/test_libvirt_events.py +++ b/tests/pytests/unit/engines/test_libvirt_events.py @@ -1,6 +1,7 @@ """ unit tests for the libvirt_events engine """ + import pytest import salt.engines.libvirt_events as libvirt_events diff --git a/tests/pytests/unit/engines/test_slack.py b/tests/pytests/unit/engines/test_slack.py index c375e903b7b..b3269a6f2a5 100644 --- a/tests/pytests/unit/engines/test_slack.py +++ b/tests/pytests/unit/engines/test_slack.py @@ -1,6 +1,7 @@ """ unit tests for the slack engine """ + import pytest import salt.engines.slack as slack diff --git a/tests/pytests/unit/engines/test_slack_bolt_engine.py b/tests/pytests/unit/engines/test_slack_bolt_engine.py index e537a859550..1d2e30a045b 100644 --- a/tests/pytests/unit/engines/test_slack_bolt_engine.py +++ b/tests/pytests/unit/engines/test_slack_bolt_engine.py @@ -1,6 +1,7 @@ """ unit tests for the slack engine """ + import pytest import salt.engines.slack_bolt_engine as slack_bolt_engine @@ -327,7 +328,13 @@ def test_run_commands_from_slack_async(slack_client): # # test with control as True and fire_all as False # - with patch_slack_client_run_until, patch_slack_client_run_command_async, patch_slack_client_get_jobs_from_runner, patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: + with ( + patch_slack_client_run_until + ), ( + patch_slack_client_run_command_async + ), ( + patch_slack_client_get_jobs_from_runner + ), patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: slack_client.run_commands_from_slack_async( message_generator=message_generator, fire_all=False, @@ -389,7 +396,15 @@ def test_run_commands_from_slack_async(slack_client): }, ) ] - with patch_slack_client_run_until, patch_slack_client_run_command_async, patch_slack_client_get_jobs_from_runner, patch_event_send, patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: + with ( + patch_slack_client_run_until + ), ( + patch_slack_client_run_command_async + ), ( + patch_slack_client_get_jobs_from_runner + ), ( + patch_event_send + ), patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage: slack_client.run_commands_from_slack_async( message_generator=message_generator, fire_all=True, @@ -509,6 +524,8 @@ def test_run_command_async(slack_client): }, ) ] - with patch_runner_client, patch_runner_client_asynchronous as runner_client_asynchronous: + with ( + patch_runner_client + ), patch_runner_client_asynchronous as runner_client_asynchronous: ret = slack_client.run_command_async(msg) runner_client_asynchronous.assert_has_calls(expected_calls) diff --git a/tests/pytests/unit/engines/test_sqs_events.py b/tests/pytests/unit/engines/test_sqs_events.py index 894d1d6f652..28fb75f8f89 100644 --- a/tests/pytests/unit/engines/test_sqs_events.py +++ b/tests/pytests/unit/engines/test_sqs_events.py @@ -1,6 +1,7 @@ """ unit tests for the sqs_events engine """ + import pytest import salt.engines.sqs_events as sqs_events diff --git a/tests/pytests/unit/fileclient/test_fileclient.py b/tests/pytests/unit/fileclient/test_fileclient.py index 395695b69ad..94512e50633 100644 --- a/tests/pytests/unit/fileclient/test_fileclient.py +++ b/tests/pytests/unit/fileclient/test_fileclient.py @@ -1,6 +1,7 @@ """ Tests for the salt fileclient """ + import errno import logging import os diff --git a/tests/pytests/unit/fileserver/gitfs/test_gitfs_config.py b/tests/pytests/unit/fileserver/gitfs/test_gitfs_config.py index 209e659c6dd..9b5d10590dc 100644 --- a/tests/pytests/unit/fileserver/gitfs/test_gitfs_config.py +++ b/tests/pytests/unit/fileserver/gitfs/test_gitfs_config.py @@ -27,7 +27,7 @@ except (ImportError, AttributeError): pytestmark = [ pytest.mark.skipif( - not HAS_GITPYTHON, reason="GitPython >= {} required".format(GITPYTHON_MINVER) + not HAS_GITPYTHON, reason=f"GitPython >= {GITPYTHON_MINVER} required" ) ] diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py index 0b686fcb05d..68a2c2f347a 100644 --- a/tests/pytests/unit/grains/test_core.py +++ b/tests/pytests/unit/grains/test_core.py @@ -1780,9 +1780,9 @@ def test_lxc_virtual(): os.path, "isfile", MagicMock( - side_effect=lambda x: True - if x in ("/proc/1/cgroup", "/proc/1/environ") - else False + side_effect=lambda x: ( + True if x in ("/proc/1/cgroup", "/proc/1/environ") else False + ) ), ), patch("salt.utils.files.fopen", mock_open(read_data=file_contents)), patch.dict( core.__salt__, {"cmd.run_all": MagicMock()} @@ -1828,9 +1828,11 @@ def test_container_inside_virtual_machine(): os.path, "isfile", MagicMock( - side_effect=lambda x: True - if x in ("/proc/cpuinfo", "/proc/1/cgroup", "/proc/1/environ") - else False + side_effect=lambda x: ( + True + if x in ("/proc/cpuinfo", "/proc/1/cgroup", "/proc/1/environ") + else False + ) ), ), patch("salt.utils.files.fopen", mock_open(read_data=file_contents)), patch.dict( core.__salt__, {"cmd.run_all": MagicMock()} @@ -3601,8 +3603,8 @@ def test_linux_devicetree_data(test_input, expected): raise FileNotFoundError() m = MagicMock() - m.__enter__.return_value.read = ( - lambda: test_input.get(filename) # pylint: disable=W0640 + m.__enter__.return_value.read = lambda: ( + test_input.get(filename) # pylint: disable=W0640 if filename in test_input # pylint: disable=W0640 else _raise_fnfe() ) diff --git a/tests/pytests/unit/grains/test_esxi.py b/tests/pytests/unit/grains/test_esxi.py index 29be04bc56e..e158b2b3843 100644 --- a/tests/pytests/unit/grains/test_esxi.py +++ b/tests/pytests/unit/grains/test_esxi.py @@ -4,7 +4,6 @@ :codeauthor: :email:`Gareth J. Greenaway ` """ - import logging import pytest diff --git a/tests/pytests/unit/loader/test_context.py b/tests/pytests/unit/loader/test_context.py index 9815f443f25..64b36411f4b 100644 --- a/tests/pytests/unit/loader/test_context.py +++ b/tests/pytests/unit/loader/test_context.py @@ -1,6 +1,7 @@ """ Tests for salt.loader.context """ + import copy import salt.loader.context diff --git a/tests/pytests/unit/loader/test_lazy.py b/tests/pytests/unit/loader/test_lazy.py index 571f458b360..8e461b454b4 100644 --- a/tests/pytests/unit/loader/test_lazy.py +++ b/tests/pytests/unit/loader/test_lazy.py @@ -1,6 +1,7 @@ """ Tests for salt.loader.lazy """ + import sys import pytest diff --git a/tests/pytests/unit/loader/test_loader.py b/tests/pytests/unit/loader/test_loader.py index 3c26b435c8c..e7359c6a74a 100644 --- a/tests/pytests/unit/loader/test_loader.py +++ b/tests/pytests/unit/loader/test_loader.py @@ -4,6 +4,7 @@ tests.pytests.unit.loader.test_loader Unit tests for salt's loader """ + import os import shutil import textwrap diff --git a/tests/pytests/unit/log_handlers/test_sentry_mod.py b/tests/pytests/unit/log_handlers/test_sentry_mod.py index 4c2d174b710..e011719ca84 100644 --- a/tests/pytests/unit/log_handlers/test_sentry_mod.py +++ b/tests/pytests/unit/log_handlers/test_sentry_mod.py @@ -1,6 +1,7 @@ """ Tests for salt.log_handlers.sentry_mod """ + import pytest import salt.log_handlers.sentry_mod diff --git a/tests/pytests/unit/modules/dockermod/test_module.py b/tests/pytests/unit/modules/dockermod/test_module.py index abfd101540d..e311032f229 100644 --- a/tests/pytests/unit/modules/dockermod/test_module.py +++ b/tests/pytests/unit/modules/dockermod/test_module.py @@ -319,24 +319,26 @@ def test_update_mine(): """ def config_get_disabled(val, default): - return { + ret = { "base_url": docker_mod.NOTSET, "version": docker_mod.NOTSET, "docker.url": docker_mod.NOTSET, "docker.version": docker_mod.NOTSET, "docker.machine": docker_mod.NOTSET, "docker.update_mine": False, - }[val] + } + return ret[val] def config_get_enabled(val, default): - return { + ret = { "base_url": docker_mod.NOTSET, "version": docker_mod.NOTSET, "docker.url": docker_mod.NOTSET, "docker.version": docker_mod.NOTSET, "docker.machine": docker_mod.NOTSET, "docker.update_mine": True, - }[val] + } + return ret[val] mine_mock = Mock() dunder_salt = { @@ -937,19 +939,21 @@ def test_compare_container_image_id_resolution(): """ def _inspect_container_effect(id_): - return { + ret = { "container1": { "Config": {"Image": "realimage:latest"}, "HostConfig": {}, }, "container2": {"Config": {"Image": "image_id"}, "HostConfig": {}}, - }[id_] + } + return ret[id_] def _inspect_image_effect(id_): - return { + ret = { "realimage:latest": {"Id": "image_id"}, "image_id": {"Id": "image_id"}, - }[id_] + } + return ret[id_] inspect_container_mock = MagicMock(side_effect=_inspect_container_effect) inspect_image_mock = MagicMock(side_effect=_inspect_image_effect) @@ -967,7 +971,7 @@ def test_compare_container_ulimits_order(): """ def _inspect_container_effect(id_): - return { + ret = { "container1": { "Config": {}, "HostConfig": { @@ -986,7 +990,8 @@ def test_compare_container_ulimits_order(): ] }, }, - }[id_] + } + return ret[id_] inspect_container_mock = MagicMock(side_effect=_inspect_container_effect) @@ -1004,7 +1009,7 @@ def test_compare_container_env_order(): """ def _inspect_container_effect(id_): - return { + ret = { "container1": { "Config": {}, "HostConfig": {"Env": ["FOO=bar", "HELLO=world"]}, @@ -1013,7 +1018,8 @@ def test_compare_container_env_order(): "Config": {}, "HostConfig": {"Env": ["HELLO=world", "FOO=bar"]}, }, - }[id_] + } + return ret[id_] inspect_container_mock = MagicMock(side_effect=_inspect_container_effect) diff --git a/tests/pytests/unit/modules/file/test_file_chattr.py b/tests/pytests/unit/modules/file/test_file_chattr.py index b97dcf946f4..edee87b8093 100644 --- a/tests/pytests/unit/modules/file/test_file_chattr.py +++ b/tests/pytests/unit/modules/file/test_file_chattr.py @@ -221,7 +221,7 @@ def test_check_perms_should_report_attrs_new_and_old_if_they_changed(): ) ).strip() else: - assert False, "not sure how to handle {}".format(cmd) + assert False, f"not sure how to handle {cmd}" patch_run = patch.dict( filemod.__salt__, diff --git a/tests/pytests/unit/modules/file/test_file_check.py b/tests/pytests/unit/modules/file/test_file_check.py index ce86acd7fcc..76d8a0cecae 100644 --- a/tests/pytests/unit/modules/file/test_file_check.py +++ b/tests/pytests/unit/modules/file/test_file_check.py @@ -88,7 +88,7 @@ def test_check_managed_follow_symlinks(a_link, tfile): a_link, tfile, None, None, user, None, lperms, None, None, None, None, None ) assert ret is True - assert comments == "The file {} is in the correct state".format(a_link) + assert comments == f"The file {a_link} is in the correct state" ret, comments = filemod.check_managed( a_link, tfile, None, None, user, None, "0644", None, None, None, None, None @@ -113,7 +113,7 @@ def test_check_managed_follow_symlinks(a_link, tfile): follow_symlinks=True, ) assert ret is True - assert comments == "The file {} is in the correct state".format(a_link) + assert comments == f"The file {a_link} is in the correct state" @pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows") diff --git a/tests/pytests/unit/modules/file/test_file_grep.py b/tests/pytests/unit/modules/file/test_file_grep.py index b3f57e0505f..8f362c0896b 100644 --- a/tests/pytests/unit/modules/file/test_file_grep.py +++ b/tests/pytests/unit/modules/file/test_file_grep.py @@ -117,7 +117,7 @@ def test_grep_query_too_many_opts(multiline_file): def test_grep_query_exists_wildcard(multiline_file): - _file = "{}*".format(multiline_file) + _file = f"{multiline_file}*" result = filemod.grep(_file, "Lorem ipsum") assert result, None @@ -127,7 +127,7 @@ def test_grep_query_exists_wildcard(multiline_file): def test_grep_file_not_exists_wildcard(multiline_file): - _file = "{}-junk*".format(multiline_file) + _file = f"{multiline_file}-junk*" result = filemod.grep(_file, "Lorem ipsum") assert result, None diff --git a/tests/pytests/unit/modules/file/test_file_line.py b/tests/pytests/unit/modules/file/test_file_line.py index 80030e1417d..17f08cdf371 100644 --- a/tests/pytests/unit/modules/file/test_file_line.py +++ b/tests/pytests/unit/modules/file/test_file_line.py @@ -965,7 +965,7 @@ def test_delete_line_in_empty_file(anyattr, mode): ) warning_call = _log.warning.call_args_list[0][0] warning_log_msg = warning_call[0] % warning_call[1:] - assert "Cannot find text to {}".format(mode) in warning_log_msg + assert f"Cannot find text to {mode}" in warning_log_msg @pytest.mark.parametrize("mode", ["delete", "replace"]) @@ -1149,7 +1149,7 @@ def test_line_insert_multi_line_content_after_unicode(tempfile_name, get_body): See issue #48113 :return: """ - file_content = "This is a line{}This is another line".format(os.linesep) + file_content = f"This is a line{os.linesep}This is another line" file_modified = salt.utils.stringutils.to_str( "This is a line{}" "This is another line{}" @@ -1588,7 +1588,7 @@ def test_line_insert_ensure_beforeafter_twolines(tempfile_name, get_body): isfile_mock = MagicMock( side_effect=lambda x: True if x == tempfile_name else DEFAULT ) - for (_after, _before) in [(after, before), ("NAME_.*", "SKEL_.*")]: + for _after, _before in [(after, before), ("NAME_.*", "SKEL_.*")]: with patch("os.path.isfile", isfile_mock), patch( "os.stat", MagicMock(return_value=DummyStat()) ), patch("salt.utils.files.fopen", mock_open(read_data=file_content)), patch( @@ -1640,7 +1640,7 @@ def test_line_insert_ensure_beforeafter_twolines_exists(tempfile_name): isfile_mock = MagicMock( side_effect=lambda x: True if x == tempfile_name else DEFAULT ) - for (_after, _before) in [(after, before), ("NAME_.*", "SKEL_.*")]: + for _after, _before in [(after, before), ("NAME_.*", "SKEL_.*")]: with patch("os.path.isfile", isfile_mock), patch( "os.stat", MagicMock(return_value=DummyStat()) ), patch("salt.utils.files.fopen", mock_open(read_data=file_content)), patch( @@ -1677,7 +1677,7 @@ def test_line_insert_ensure_beforeafter_rangelines(): file_content.split(os.linesep)[0], file_content.split(os.linesep)[-1], ) - for (_after, _before) in [(after, before), ("NAME_.*", "SKEL_.*")]: + for _after, _before in [(after, before), ("NAME_.*", "SKEL_.*")]: with patch("os.path.realpath", MagicMock(wraps=lambda x: x)), patch( "os.path.isfile", MagicMock(return_value=True) ), patch("os.stat", MagicMock()), patch( diff --git a/tests/pytests/unit/modules/file/test_file_module.py b/tests/pytests/unit/modules/file/test_file_module.py index 34fe4fa210d..38de2811aba 100644 --- a/tests/pytests/unit/modules/file/test_file_module.py +++ b/tests/pytests/unit/modules/file/test_file_module.py @@ -183,7 +183,7 @@ def test_sed_limit_escaped(sed_content, subdir): path = tfile.name before = "/var/lib/foo" after = "" - limit = "^{}".format(before) + limit = f"^{before}" filemod.sed(path, before, after, limit=limit) @@ -506,12 +506,13 @@ def test_get_diff(): mockself.path = path def readlines(mockself): # pylint: disable=unused-argument - return { + ret = { "text1": text1.encode("utf8"), "text2": text2.encode("utf8"), "binary1": binary1, "binary2": binary2, - }[mockself.path].splitlines(True) + } + return ret[mockself.path].splitlines(True) def __enter__(mockself): return mockself diff --git a/tests/pytests/unit/modules/napalm/test_bgp.py b/tests/pytests/unit/modules/napalm/test_bgp.py index e9dcb21ecf5..48a7105342d 100644 --- a/tests/pytests/unit/modules/napalm/test_bgp.py +++ b/tests/pytests/unit/modules/napalm/test_bgp.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import pytest import salt.modules.napalm_bgp as napalm_bgp diff --git a/tests/pytests/unit/modules/napalm/test_mod.py b/tests/pytests/unit/modules/napalm/test_mod.py index 306a9840a46..5b693c2de2a 100644 --- a/tests/pytests/unit/modules/napalm/test_mod.py +++ b/tests/pytests/unit/modules/napalm/test_mod.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`David Murphy ` """ + import logging import pytest diff --git a/tests/pytests/unit/modules/napalm/test_network.py b/tests/pytests/unit/modules/napalm/test_network.py index 4dfaf8af447..2ce2d6e621b 100644 --- a/tests/pytests/unit/modules/napalm/test_network.py +++ b/tests/pytests/unit/modules/napalm/test_network.py @@ -2,7 +2,6 @@ :codeauthor: Anthony Shaw """ - import pytest import salt.modules.napalm_network as napalm_network diff --git a/tests/pytests/unit/modules/napalm/test_route.py b/tests/pytests/unit/modules/napalm/test_route.py index 06ccf0ec618..b72130c14de 100644 --- a/tests/pytests/unit/modules/napalm/test_route.py +++ b/tests/pytests/unit/modules/napalm/test_route.py @@ -10,7 +10,7 @@ from tests.support.mock import MagicMock, patch def mock_net_load(template, *args, **kwargs): - raise ValueError("incorrect template {}".format(template)) + raise ValueError(f"incorrect template {template}") @pytest.fixture diff --git a/tests/pytests/unit/modules/napalm/test_snmp.py b/tests/pytests/unit/modules/napalm/test_snmp.py index 67d25850f3a..5166372ca68 100644 --- a/tests/pytests/unit/modules/napalm/test_snmp.py +++ b/tests/pytests/unit/modules/napalm/test_snmp.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import pytest import salt.modules.napalm_network as napalm_network diff --git a/tests/pytests/unit/modules/napalm/test_users.py b/tests/pytests/unit/modules/napalm/test_users.py index b76010e76f1..f55a649aa7b 100644 --- a/tests/pytests/unit/modules/napalm/test_users.py +++ b/tests/pytests/unit/modules/napalm/test_users.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import pytest import salt.modules.napalm_network as napalm_network diff --git a/tests/pytests/unit/modules/test_acme.py b/tests/pytests/unit/modules/test_acme.py index 2d7aa6d2883..aa56dc59813 100644 --- a/tests/pytests/unit/modules/test_acme.py +++ b/tests/pytests/unit/modules/test_acme.py @@ -2,7 +2,6 @@ :codeauthor: Herbert Buurman """ - import datetime import os import textwrap diff --git a/tests/pytests/unit/modules/test_aixpkg.py b/tests/pytests/unit/modules/test_aixpkg.py index 7e9b21afb7f..bb56173bd34 100644 --- a/tests/pytests/unit/modules/test_aixpkg.py +++ b/tests/pytests/unit/modules/test_aixpkg.py @@ -1283,7 +1283,7 @@ fake_info Not found on the installation media """ fileset_pkg_name = "/cecc/repos/aix72/TL3/BASE/installp/ppc/info_fake" - fileset_pkg_base_name = os.path.basename("{}".format(fileset_pkg_name)) + fileset_pkg_base_name = os.path.basename(f"{fileset_pkg_name}") dnf_installp_call = MagicMock( side_effect=[ {"retcode": 1, "stdout": "", "stderr": info_fake_dnf_error}, @@ -1347,8 +1347,8 @@ def test_remove_dnf(): ) list_pkgs_mock = MagicMock( side_effect=[ - {"{}".format(pkg_name): "{}".format(pkg_name_version)}, - {"{}".format(pkg_name): ""}, + {f"{pkg_name}": f"{pkg_name_version}"}, + {f"{pkg_name}": ""}, ] ) @@ -1357,21 +1357,19 @@ def test_remove_dnf(): aixpkg.__salt__, {"cmd.run_all": dnf_call, "config.get": MagicMock(return_value=False)}, ), patch.object(aixpkg, "list_pkgs", list_pkgs_mock): - result = aixpkg.remove("{}".format(pkg_name)) + result = aixpkg.remove(f"{pkg_name}") dnf_call.assert_any_call( - ["/usr/bin/lslpp", "-Lc", "{}".format(pkg_name)], + ["/usr/bin/lslpp", "-Lc", f"{pkg_name}"], python_shell=False, ) libpath_env = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} dnf_call.assert_any_call( - "/opt/freeware/bin/dnf -y remove {}".format(pkg_name), + f"/opt/freeware/bin/dnf -y remove {pkg_name}", env=libpath_env, ignore_retcode=True, python_shell=False, ) - expected = { - "{}".format(pkg_name): {"old": "{}".format(pkg_name_version), "new": ""} - } + expected = {f"{pkg_name}": {"old": f"{pkg_name_version}", "new": ""}} assert result == expected @@ -1468,8 +1466,8 @@ bos.adt.insttools 7.2.2.0 ROOT APPLY SUCCESS ) list_pkgs_mock = MagicMock( side_effect=[ - {"{}".format(fileset_base_name): "{}".format(fileset_pkg_name_version)}, - {"{}".format(fileset_base_name): ""}, + {f"{fileset_base_name}": f"{fileset_pkg_name_version}"}, + {f"{fileset_base_name}": ""}, ] ) @@ -1478,20 +1476,20 @@ bos.adt.insttools 7.2.2.0 ROOT APPLY SUCCESS aixpkg.__salt__, {"cmd.run_all": dnf_call, "config.get": MagicMock(return_value=False)}, ), patch.object(aixpkg, "list_pkgs", list_pkgs_mock): - result = aixpkg.remove("{}".format(fileset_pkg_name)) + result = aixpkg.remove(f"{fileset_pkg_name}") dnf_call.assert_any_call( - ["/usr/bin/lslpp", "-Lc", "{}".format(fileset_pkg_name)], + ["/usr/bin/lslpp", "-Lc", f"{fileset_pkg_name}"], python_shell=False, ) libpath_env = {"LIBPATH": "/opt/freeware/lib:/usr/lib"} test_name = os.path.basename(fileset_pkg_name) dnf_call.assert_any_call( - ["/usr/sbin/installp", "-u", "{}".format(fileset_base_name)], + ["/usr/sbin/installp", "-u", f"{fileset_base_name}"], python_shell=False, ) expected = { - "{}".format(fileset_base_name): { - "old": "{}".format(fileset_pkg_name_version), + f"{fileset_base_name}": { + "old": f"{fileset_pkg_name_version}", "new": "", } } @@ -1530,15 +1528,13 @@ lslpp: Fileset info_fake not installed. ), patch.object(aixpkg, "list_pkgs", list_pkgs_mock): expected = { "changes": {}, - "errors": [ - "/usr/bin/lslpp: Fileset {} not installed.".format(fileset_pkg_name) - ], + "errors": [f"/usr/bin/lslpp: Fileset {fileset_pkg_name} not installed."], } with pytest.raises(CommandExecutionError) as exc_info: result = aixpkg.remove(fileset_pkg_name) assert exc_info.value.info == expected, exc_info.value.info assert lslpp_call.call_count == 1 lslpp_call.assert_any_call( - ["/usr/bin/lslpp", "-Lc", "{}".format(fileset_pkg_name)], + ["/usr/bin/lslpp", "-Lc", f"{fileset_pkg_name}"], python_shell=False, ) diff --git a/tests/pytests/unit/modules/test_at.py b/tests/pytests/unit/modules/test_at.py index 0a44d83beea..da5be7f4b0e 100644 --- a/tests/pytests/unit/modules/test_at.py +++ b/tests/pytests/unit/modules/test_at.py @@ -4,7 +4,6 @@ TestCase for the salt.modules.at module """ - import pytest import salt.modules.at as at diff --git a/tests/pytests/unit/modules/test_augeas_cfg.py b/tests/pytests/unit/modules/test_augeas_cfg.py index 0720b6b25b9..dd197555665 100644 --- a/tests/pytests/unit/modules/test_augeas_cfg.py +++ b/tests/pytests/unit/modules/test_augeas_cfg.py @@ -3,6 +3,7 @@ Test cases for salt.modules.augeas_cfg """ + import pytest import salt.modules.augeas_cfg as augeas_cfg diff --git a/tests/pytests/unit/modules/test_bigip.py b/tests/pytests/unit/modules/test_bigip.py index 3e24ad9df4a..2fc8cb44c50 100644 --- a/tests/pytests/unit/modules/test_bigip.py +++ b/tests/pytests/unit/modules/test_bigip.py @@ -4,6 +4,7 @@ tests.unit.modules.test_bigip Unit tests for the bigip module """ + import logging import pytest diff --git a/tests/pytests/unit/modules/test_bluez_bluetooth.py b/tests/pytests/unit/modules/test_bluez_bluetooth.py index e7b832e613f..d3bab5ba043 100644 --- a/tests/pytests/unit/modules/test_bluez_bluetooth.py +++ b/tests/pytests/unit/modules/test_bluez_bluetooth.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.modules.bluez_bluetooth as bluez diff --git a/tests/pytests/unit/modules/test_boto_dynamodb.py b/tests/pytests/unit/modules/test_boto_dynamodb.py index f5b983e13f0..0a2fe186a1c 100644 --- a/tests/pytests/unit/modules/test_boto_dynamodb.py +++ b/tests/pytests/unit/modules/test_boto_dynamodb.py @@ -2,7 +2,6 @@ Test cases for salt.modules.boto_dynamodb """ - import pytest import salt.modules.boto_dynamodb as boto_dynamodb diff --git a/tests/pytests/unit/modules/test_bower.py b/tests/pytests/unit/modules/test_bower.py index df33182ab1a..537fb08fbaa 100644 --- a/tests/pytests/unit/modules/test_bower.py +++ b/tests/pytests/unit/modules/test_bower.py @@ -2,7 +2,6 @@ :codeauthor: Alexander Pyatkin """ - import pytest import salt.modules.bower as bower diff --git a/tests/pytests/unit/modules/test_bridge.py b/tests/pytests/unit/modules/test_bridge.py index f68ffbce2d7..7595e4263ee 100644 --- a/tests/pytests/unit/modules/test_bridge.py +++ b/tests/pytests/unit/modules/test_bridge.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.bridge as bridge diff --git a/tests/pytests/unit/modules/test_cassandra_cql.py b/tests/pytests/unit/modules/test_cassandra_cql.py index 6b39d2f0cc4..c07b78ce158 100644 --- a/tests/pytests/unit/modules/test_cassandra_cql.py +++ b/tests/pytests/unit/modules/test_cassandra_cql.py @@ -2,7 +2,6 @@ Test case for the cassandra_cql module """ - import logging import ssl @@ -86,7 +85,7 @@ def test_version(caplog): with pytest.raises(CommandExecutionError) as err: with patch.object(cassandra_cql, "cql_query", mock_cql_query): version = cassandra_cql.version() - assert "{}".format(err.value) == "" + assert f"{err.value}" == "" assert "Could not get Cassandra version." in caplog.text for record in caplog.records: assert record.levelname == "CRITICAL" diff --git a/tests/pytests/unit/modules/test_chocolatey.py b/tests/pytests/unit/modules/test_chocolatey.py index ac2c7341045..8dd630793f1 100644 --- a/tests/pytests/unit/modules/test_chocolatey.py +++ b/tests/pytests/unit/modules/test_chocolatey.py @@ -1,6 +1,7 @@ """ Test for the chocolatey module """ + import os import pytest diff --git a/tests/pytests/unit/modules/test_chroot.py b/tests/pytests/unit/modules/test_chroot.py index d44bfed9303..b1e9beb674e 100644 --- a/tests/pytests/unit/modules/test_chroot.py +++ b/tests/pytests/unit/modules/test_chroot.py @@ -159,7 +159,7 @@ def test_call_fails_salt_thin(): salt_mock["cmd.run_chroot"].assert_called_with( "/chroot", [ - "python{}".format(sys.version_info[0]), + f"python{sys.version_info[0]}", "/tmp01/salt-call", "--metadata", "--local", @@ -207,7 +207,7 @@ def test_call_success(): salt_mock["cmd.run_chroot"].assert_called_with( "/chroot", [ - "python{}".format(sys.version_info[0]), + f"python{sys.version_info[0]}", "/tmp01/salt-call", "--metadata", "--local", @@ -257,7 +257,7 @@ def test_call_success_parameters(): salt_mock["cmd.run_chroot"].assert_called_with( "/chroot", [ - "python{}".format(sys.version_info[0]), + f"python{sys.version_info[0]}", "/tmp01/salt-call", "--metadata", "--local", diff --git a/tests/pytests/unit/modules/test_composer.py b/tests/pytests/unit/modules/test_composer.py index 74d828aee6a..c0f5f552f2a 100644 --- a/tests/pytests/unit/modules/test_composer.py +++ b/tests/pytests/unit/modules/test_composer.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.composer as composer diff --git a/tests/pytests/unit/modules/test_config.py b/tests/pytests/unit/modules/test_config.py index c522dc7897c..122d41b9291 100644 --- a/tests/pytests/unit/modules/test_config.py +++ b/tests/pytests/unit/modules/test_config.py @@ -2,7 +2,6 @@ Test cases for salt.modules.config """ - import fnmatch import pytest diff --git a/tests/pytests/unit/modules/test_consul.py b/tests/pytests/unit/modules/test_consul.py index 52f1c8ece2e..311c48d05a4 100644 --- a/tests/pytests/unit/modules/test_consul.py +++ b/tests/pytests/unit/modules/test_consul.py @@ -2,7 +2,6 @@ Test case for the consul execution module """ - import logging import pytest @@ -1148,11 +1147,11 @@ def test_catalog_register(): token=token, node=node, address=address, - **nodemeta_kwargs + **nodemeta_kwargs, ) expected = { "data": {"Address": address, "Node": node, "NodeMeta": nodemeta}, - "message": "Catalog registration for {} successful.".format(node), + "message": f"Catalog registration for {node} successful.", "res": True, } @@ -1198,7 +1197,7 @@ def test_catalog_deregister(): checkid=checkid, ) expected = { - "message": "Catalog item {} removed.".format(node), + "message": f"Catalog item {node} removed.", "res": True, } @@ -1604,7 +1603,7 @@ def test_acl_create(): with patch.object(salt.utils.http, "query", return_value=mock_http_result): with patch.dict(consul.__salt__, {"config.get": mock_url}): result = consul.acl_create(consul_url=consul_url, token=token, name=name) - expected = {"message": "ACL {} created.".format(name), "res": True} + expected = {"message": f"ACL {name} created.", "res": True} assert expected == result @@ -1653,7 +1652,7 @@ def test_acl_update(): result = consul.acl_update( consul_url=consul_url, token=token, name=name, id=aclid ) - expected = {"message": "ACL {} created.".format(name), "res": True} + expected = {"message": f"ACL {name} created.", "res": True} assert expected == result @@ -1693,7 +1692,7 @@ def test_acl_delete(): result = consul.acl_delete( consul_url=consul_url, token=token, name=name, id=aclid ) - expected = {"message": "ACL {} deleted.".format(aclid), "res": True} + expected = {"message": f"ACL {aclid} deleted.", "res": True} assert expected == result @@ -1775,7 +1774,7 @@ def test_acl_clone(): ) expected = { "ID": aclid, - "message": "ACL {} cloned.".format(name), + "message": f"ACL {name} cloned.", "res": True, } assert expected == result @@ -1845,7 +1844,7 @@ def test_event_fire(): result = consul.event_fire(consul_url=consul_url, token=token, name=name) expected = { "data": "test", - "message": "Event {} fired.".format(name), + "message": f"Event {name} fired.", "res": True, } assert expected == result diff --git a/tests/pytests/unit/modules/test_cp.py b/tests/pytests/unit/modules/test_cp.py index 8fa0fd0d44b..8618a6bf74f 100644 --- a/tests/pytests/unit/modules/test_cp.py +++ b/tests/pytests/unit/modules/test_cp.py @@ -2,7 +2,6 @@ :codeauthor: jmoney """ - import pytest import salt.channel.client diff --git a/tests/pytests/unit/modules/test_daemontools.py b/tests/pytests/unit/modules/test_daemontools.py index 3a5e51fcba4..a5cbed24568 100644 --- a/tests/pytests/unit/modules/test_daemontools.py +++ b/tests/pytests/unit/modules/test_daemontools.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_data.py b/tests/pytests/unit/modules/test_data.py index c4d3f918c79..11b8568082d 100644 --- a/tests/pytests/unit/modules/test_data.py +++ b/tests/pytests/unit/modules/test_data.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.data as data diff --git a/tests/pytests/unit/modules/test_deb_apache.py b/tests/pytests/unit/modules/test_deb_apache.py index 1608321f107..d78f17c5d60 100644 --- a/tests/pytests/unit/modules/test_deb_apache.py +++ b/tests/pytests/unit/modules/test_deb_apache.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.deb_apache as deb_apache diff --git a/tests/pytests/unit/modules/test_devinfo.py b/tests/pytests/unit/modules/test_devinfo.py index d3895e53246..ccca1486e86 100644 --- a/tests/pytests/unit/modules/test_devinfo.py +++ b/tests/pytests/unit/modules/test_devinfo.py @@ -42,10 +42,13 @@ def test_devices(): "E": {"ID_BUS": "ata"}, } - with patch.dict( - devinfo.__salt__, - {"udev.info": lambda d: {"sda": hd, "sdb": usb, "sr0": cdrom}[d]}, - ), patch.dict(devinfo.__grains__, {"disks": ["sda", "sdb", "sr0"]}): + def udev_info(key): + devices = {"sda": hd, "sdb": usb, "sr0": cdrom} + return devices[key] + + with patch.dict(devinfo.__salt__, {"udev.info": udev_info}), patch.dict( + devinfo.__grains__, {"disks": ["sda", "sdb", "sr0"]} + ): assert devinfo.filter_({"e.id_bus": "ata"}, {}) == ["sda", "sr0"] assert devinfo.filter_({"e.id_bus": "usb"}, {}) == ["sdb"] assert devinfo.filter_({"e.id_bus": "ata"}, {"s": ["cdrom"]}) == ["sda"] diff --git a/tests/pytests/unit/modules/test_devmap.py b/tests/pytests/unit/modules/test_devmap.py index f7fc9f09ea1..405eccac1b4 100644 --- a/tests/pytests/unit/modules/test_devmap.py +++ b/tests/pytests/unit/modules/test_devmap.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import os.path import pytest diff --git a/tests/pytests/unit/modules/test_dig.py b/tests/pytests/unit/modules/test_dig.py index dcc0acc8295..0d39a20e73c 100644 --- a/tests/pytests/unit/modules/test_dig.py +++ b/tests/pytests/unit/modules/test_dig.py @@ -2,7 +2,6 @@ Test cases for salt.modules.dig """ - import pytest import salt.modules.dig as dig diff --git a/tests/pytests/unit/modules/test_disk.py b/tests/pytests/unit/modules/test_disk.py index 58d8cbc305c..ca35852e06e 100644 --- a/tests/pytests/unit/modules/test_disk.py +++ b/tests/pytests/unit/modules/test_disk.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.disk as disk @@ -274,7 +275,7 @@ def test_fstype(): """ device = "/dev/sdX1" fs_type = "ext4" - mock = MagicMock(return_value="FSTYPE\n{}".format(fs_type)) + mock = MagicMock(return_value=f"FSTYPE\n{fs_type}") with patch.dict(disk.__grains__, {"kernel": "Linux"}), patch.dict( disk.__salt__, {"cmd.run": mock} ), patch("salt.utils.path.which", MagicMock(return_value=True)): @@ -291,7 +292,7 @@ def test_resize2fs(): "salt.utils.path.which", MagicMock(return_value=True) ): disk.resize2fs(device) - mock.assert_called_once_with("resize2fs {}".format(device), python_shell=False) + mock.assert_called_once_with(f"resize2fs {device}", python_shell=False) @pytest.mark.skip_on_windows(reason="Skip on Windows") diff --git a/tests/pytests/unit/modules/test_djangomod.py b/tests/pytests/unit/modules/test_djangomod.py index f3a22dd8052..f3fb1ed884e 100644 --- a/tests/pytests/unit/modules/test_djangomod.py +++ b/tests/pytests/unit/modules/test_djangomod.py @@ -3,6 +3,7 @@ Test cases for salt.modules.djangomod """ + import pytest import salt.modules.djangomod as djangomod diff --git a/tests/pytests/unit/modules/test_dpkg_lowpkg.py b/tests/pytests/unit/modules/test_dpkg_lowpkg.py index 41bd615ff29..625015b7590 100644 --- a/tests/pytests/unit/modules/test_dpkg_lowpkg.py +++ b/tests/pytests/unit/modules/test_dpkg_lowpkg.py @@ -4,7 +4,6 @@ Test cases for salt.modules.dpkg """ - import logging import os diff --git a/tests/pytests/unit/modules/test_drac.py b/tests/pytests/unit/modules/test_drac.py index 2a8da5a23f6..9d684797e0c 100644 --- a/tests/pytests/unit/modules/test_drac.py +++ b/tests/pytests/unit/modules/test_drac.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.drac as drac diff --git a/tests/pytests/unit/modules/test_drbd.py b/tests/pytests/unit/modules/test_drbd.py index ce9625c2d0c..c4686093a5a 100644 --- a/tests/pytests/unit/modules/test_drbd.py +++ b/tests/pytests/unit/modules/test_drbd.py @@ -4,7 +4,6 @@ Test cases for salt.modules.drbd """ - import pytest import salt.modules.drbd as drbd diff --git a/tests/pytests/unit/modules/test_etcd_mod.py b/tests/pytests/unit/modules/test_etcd_mod.py index 1c43772524d..d4b26a8486f 100644 --- a/tests/pytests/unit/modules/test_etcd_mod.py +++ b/tests/pytests/unit/modules/test_etcd_mod.py @@ -9,7 +9,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.etcd_mod as etcd_mod diff --git a/tests/pytests/unit/modules/test_extfs.py b/tests/pytests/unit/modules/test_extfs.py index 4099f21b2ff..ce36373ef0b 100644 --- a/tests/pytests/unit/modules/test_extfs.py +++ b/tests/pytests/unit/modules/test_extfs.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.extfs as extfs diff --git a/tests/pytests/unit/modules/test_genesis.py b/tests/pytests/unit/modules/test_genesis.py index 7a3b1632843..2bb81bf67f5 100644 --- a/tests/pytests/unit/modules/test_genesis.py +++ b/tests/pytests/unit/modules/test_genesis.py @@ -1,6 +1,7 @@ """ :codeauthor: Rupesh Tare """ + import pytest import salt.modules.genesis as genesis diff --git a/tests/pytests/unit/modules/test_gentoo_service.py b/tests/pytests/unit/modules/test_gentoo_service.py index 1d7e8eca7f9..31df975cb53 100644 --- a/tests/pytests/unit/modules/test_gentoo_service.py +++ b/tests/pytests/unit/modules/test_gentoo_service.py @@ -2,7 +2,6 @@ Test cases for salt.modules.gentoo_service """ - import pytest import salt.modules.gentoo_service as gentoo_service diff --git a/tests/pytests/unit/modules/test_git.py b/tests/pytests/unit/modules/test_git.py index 9d7c9ae9fc7..4da79b7bd55 100644 --- a/tests/pytests/unit/modules/test_git.py +++ b/tests/pytests/unit/modules/test_git.py @@ -2,7 +2,6 @@ :codeauthor: Erik Johnson """ - import copy import logging import os @@ -88,9 +87,11 @@ def test_list_worktrees(worktree_info, worktree_root): return "worktree {}\nHEAD {}\n{}\n".format( path, worktree_info[path]["HEAD"], - "branch {}".format(worktree_info[path]["branch"]) - if worktree_info[path]["branch"] != "detached" - else "detached", + ( + "branch {}".format(worktree_info[path]["branch"]) + if worktree_info[path]["branch"] != "detached" + else "detached" + ), ) # Build dict for _cmd_run_side_effect below. Start with the output from diff --git a/tests/pytests/unit/modules/test_glassfish.py b/tests/pytests/unit/modules/test_glassfish.py index 159d00cbb16..0362d23fc8d 100644 --- a/tests/pytests/unit/modules/test_glassfish.py +++ b/tests/pytests/unit/modules/test_glassfish.py @@ -4,6 +4,7 @@ tests.unit.modules.test_glassfish Unit tests for the glassfish module """ + import logging import pytest diff --git a/tests/pytests/unit/modules/test_glusterfs.py b/tests/pytests/unit/modules/test_glusterfs.py index be0d5b04462..8fab4a942a0 100644 --- a/tests/pytests/unit/modules/test_glusterfs.py +++ b/tests/pytests/unit/modules/test_glusterfs.py @@ -5,7 +5,6 @@ Test cases for salt.modules.glusterfs """ - import pytest import salt.modules.glusterfs as glusterfs diff --git a/tests/pytests/unit/modules/test_grub_legacy.py b/tests/pytests/unit/modules/test_grub_legacy.py index 47ec919939c..4d0feae6f4b 100644 --- a/tests/pytests/unit/modules/test_grub_legacy.py +++ b/tests/pytests/unit/modules/test_grub_legacy.py @@ -4,7 +4,6 @@ Test cases for salt.modules.grub_legacy """ - import errno import pytest diff --git a/tests/pytests/unit/modules/test_hadoop.py b/tests/pytests/unit/modules/test_hadoop.py index 37416403274..fad51b9b6e6 100644 --- a/tests/pytests/unit/modules/test_hadoop.py +++ b/tests/pytests/unit/modules/test_hadoop.py @@ -4,7 +4,6 @@ Test cases for salt.modules.hadoop """ - import pytest import salt.modules.hadoop as hadoop diff --git a/tests/pytests/unit/modules/test_haproxyconn.py b/tests/pytests/unit/modules/test_haproxyconn.py index 7834818fbea..51d39fc7d3b 100644 --- a/tests/pytests/unit/modules/test_haproxyconn.py +++ b/tests/pytests/unit/modules/test_haproxyconn.py @@ -4,7 +4,6 @@ Test cases for salt.modules.haproxyconn """ - import pytest import salt.modules.haproxyconn as haproxyconn diff --git a/tests/pytests/unit/modules/test_hashutil.py b/tests/pytests/unit/modules/test_hashutil.py index 57a237bad66..cf1527e624e 100644 --- a/tests/pytests/unit/modules/test_hashutil.py +++ b/tests/pytests/unit/modules/test_hashutil.py @@ -2,7 +2,6 @@ Test cases for salt.modules.hashutil """ - import pytest import salt.modules.hashutil as hashutil diff --git a/tests/pytests/unit/modules/test_helm.py b/tests/pytests/unit/modules/test_helm.py index 8286f4af27a..776ed45734e 100644 --- a/tests/pytests/unit/modules/test_helm.py +++ b/tests/pytests/unit/modules/test_helm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.helm """ - import pytest import salt.modules.helm as helm diff --git a/tests/pytests/unit/modules/test_hg.py b/tests/pytests/unit/modules/test_hg.py index 314b48b2c8e..c942066fe9a 100644 --- a/tests/pytests/unit/modules/test_hg.py +++ b/tests/pytests/unit/modules/test_hg.py @@ -4,7 +4,6 @@ Test cases for salt.modules.hg """ - import pytest import salt.modules.hg as hg @@ -97,17 +96,17 @@ def test_status_multiple(): """ Test for Status to a given repository (cwd is list) """ + + def side_effect(*_, **kwargs): + if kwargs["cwd"] == "dir 0": + return "A file 0\n" + if kwargs["cwd"] == "dir 1": + return "M file 1" + with patch.dict( hg.__salt__, { - "cmd.run_stdout": MagicMock( - side_effect=( - lambda *args, **kwargs: { - "dir 0": "A file 0\n", - "dir 1": "M file 1", - }[kwargs["cwd"]] - ) - ) + "cmd.run_stdout": MagicMock(side_effect=side_effect), }, ): assert hg.status(["dir 0", "dir 1"]) == { diff --git a/tests/pytests/unit/modules/test_http.py b/tests/pytests/unit/modules/test_http.py index 7e2c33dc4c6..16aa8a72a99 100644 --- a/tests/pytests/unit/modules/test_http.py +++ b/tests/pytests/unit/modules/test_http.py @@ -4,7 +4,6 @@ Test cases for salt.modules.http """ - import pytest import salt.modules.http as http diff --git a/tests/pytests/unit/modules/test_ilo.py b/tests/pytests/unit/modules/test_ilo.py index 0df13c8be7d..3328856e577 100644 --- a/tests/pytests/unit/modules/test_ilo.py +++ b/tests/pytests/unit/modules/test_ilo.py @@ -4,7 +4,6 @@ Test cases for salt.modules.ilo """ - import tempfile import pytest diff --git a/tests/pytests/unit/modules/test_incron.py b/tests/pytests/unit/modules/test_incron.py index 9f241d570f1..cae619a6968 100644 --- a/tests/pytests/unit/modules/test_incron.py +++ b/tests/pytests/unit/modules/test_incron.py @@ -4,7 +4,6 @@ Test cases for salt.modules.incron """ - import pytest import salt.modules.incron as incron diff --git a/tests/pytests/unit/modules/test_ini_manage.py b/tests/pytests/unit/modules/test_ini_manage.py index 27f8d46eac6..499bae71e06 100644 --- a/tests/pytests/unit/modules/test_ini_manage.py +++ b/tests/pytests/unit/modules/test_ini_manage.py @@ -437,9 +437,7 @@ def test_unicode_set_option(encoding, linesep, ini_file, unicode_content): assert ini.get_option(str(ini_file), "Ascii", "ay", encoding=encoding) == "Aymar" # Check new section and option added - assert ( - ini.get_option(str(ini_file), "Юникод", "dv", encoding=encoding) == "ދިވެހިބަސް" - ) + assert ini.get_option(str(ini_file), "Юникод", "dv", encoding=encoding) == "ދިވެހިބަސް" @pytest.mark.parametrize("linesep", ["\r", "\n", "\r\n"]) @@ -478,9 +476,12 @@ def test_unicode_remove_option(encoding, linesep, ini_file, unicode_content): ini_file.write_bytes(content) assert ( - ini.remove_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) == "zh_TW" + ini.remove_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) + == "zh_TW" + ) + assert ( + ini.get_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) is None ) - assert ini.get_option(str(ini_file), "Юникод", "繁體中文", encoding=encoding) is None @pytest.mark.parametrize("linesep", ["\r", "\n", "\r\n"]) diff --git a/tests/pytests/unit/modules/test_introspect.py b/tests/pytests/unit/modules/test_introspect.py index caf9db42eee..287829af22c 100644 --- a/tests/pytests/unit/modules/test_introspect.py +++ b/tests/pytests/unit/modules/test_introspect.py @@ -4,7 +4,6 @@ Test cases for salt.modules.introspect """ - import pytest import salt.modules.introspect as introspect @@ -33,8 +32,8 @@ def test_running_service_owners(): ) ret = { "Error": { - "Unsupported File Module": "{}".format(err2), - "Unsupported Package Manager": "{}".format(err1), + "Unsupported File Module": f"{err2}", + "Unsupported Package Manager": f"{err1}", } } assert introspect.running_service_owners() == ret @@ -65,8 +64,8 @@ def test_enabled_service_owners(): ) ret = { "Error": { - "Unsupported Service Manager": "{}".format(err2), - "Unsupported Package Manager": "{}".format(err1), + "Unsupported Service Manager": f"{err2}", + "Unsupported Package Manager": f"{err1}", } } assert introspect.enabled_service_owners() == ret diff --git a/tests/pytests/unit/modules/test_ipset.py b/tests/pytests/unit/modules/test_ipset.py index e0f486300f3..83d07f1d4ef 100644 --- a/tests/pytests/unit/modules/test_ipset.py +++ b/tests/pytests/unit/modules/test_ipset.py @@ -1,6 +1,7 @@ """ :codeauthor: Rupesh Tare """ + import pytest import salt.modules.ipset as ipset diff --git a/tests/pytests/unit/modules/test_iptables.py b/tests/pytests/unit/modules/test_iptables.py index 63943462429..27fc171c86c 100644 --- a/tests/pytests/unit/modules/test_iptables.py +++ b/tests/pytests/unit/modules/test_iptables.py @@ -433,9 +433,7 @@ def test_check(): mock_rule = "m state --state RELATED,ESTABLISHED -j ACCEPT" mock_chain = "INPUT" mock_uuid = 31337 - mock_cmd_rule = MagicMock( - return_value="-A {}\n-A {}".format(mock_chain, hex(mock_uuid)) - ) + mock_cmd_rule = MagicMock(return_value=f"-A {mock_chain}\n-A {hex(mock_uuid)}") mock_cmd_nooutput = MagicMock(return_value="") mock_has = MagicMock(return_value=True) mock_not = MagicMock(return_value=False) diff --git a/tests/pytests/unit/modules/test_junos.py b/tests/pytests/unit/modules/test_junos.py index c29e70a4295..cfc792f5dd3 100644 --- a/tests/pytests/unit/modules/test_junos.py +++ b/tests/pytests/unit/modules/test_junos.py @@ -1,6 +1,7 @@ """ :codeauthor: Rajvi Dhimar """ + import os import pytest diff --git a/tests/pytests/unit/modules/test_key.py b/tests/pytests/unit/modules/test_key.py index bfc9442a103..726d7db44ca 100644 --- a/tests/pytests/unit/modules/test_key.py +++ b/tests/pytests/unit/modules/test_key.py @@ -4,7 +4,6 @@ Test cases for salt.modules.key """ - import os.path import pytest diff --git a/tests/pytests/unit/modules/test_keyboard.py b/tests/pytests/unit/modules/test_keyboard.py index d88f52bd6d6..ceb0d7effe0 100644 --- a/tests/pytests/unit/modules/test_keyboard.py +++ b/tests/pytests/unit/modules/test_keyboard.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.keyboard as keyboard diff --git a/tests/pytests/unit/modules/test_kmod.py b/tests/pytests/unit/modules/test_kmod.py index c75c17caf59..313c6dd7121 100644 --- a/tests/pytests/unit/modules/test_kmod.py +++ b/tests/pytests/unit/modules/test_kmod.py @@ -93,9 +93,7 @@ def test_load(): assert [mod] == kmod.load(mod, True) with patch.dict(kmod.__salt__, {"cmd.run_all": mock_run_all_1}): - assert "Error loading module {}: {}".format(mod, err_msg) == kmod.load( - mod - ) + assert f"Error loading module {mod}: {err_msg}" == kmod.load(mod) def test_is_loaded(): diff --git a/tests/pytests/unit/modules/test_kubeadm.py b/tests/pytests/unit/modules/test_kubeadm.py index 252a89da2f9..a4c1d2fc449 100644 --- a/tests/pytests/unit/modules/test_kubeadm.py +++ b/tests/pytests/unit/modules/test_kubeadm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.kubeadm """ - import pytest import salt.modules.kubeadm as kubeadm diff --git a/tests/pytests/unit/modules/test_launchctl_service.py b/tests/pytests/unit/modules/test_launchctl_service.py index bda0137189b..afb0920476a 100644 --- a/tests/pytests/unit/modules/test_launchctl_service.py +++ b/tests/pytests/unit/modules/test_launchctl_service.py @@ -4,7 +4,6 @@ Test cases for salt.modules.launchctl """ - import pytest import salt.modules.launchctl_service as launchctl diff --git a/tests/pytests/unit/modules/test_ldapmod.py b/tests/pytests/unit/modules/test_ldapmod.py index 751625eb992..9b8207ed5bf 100644 --- a/tests/pytests/unit/modules/test_ldapmod.py +++ b/tests/pytests/unit/modules/test_ldapmod.py @@ -4,7 +4,6 @@ Test cases for salt.modules.ldapmod """ - import time import pytest diff --git a/tests/pytests/unit/modules/test_linux_lvm.py b/tests/pytests/unit/modules/test_linux_lvm.py index 848a57040a1..2b45072876a 100644 --- a/tests/pytests/unit/modules/test_linux_lvm.py +++ b/tests/pytests/unit/modules/test_linux_lvm.py @@ -4,7 +4,6 @@ TestCase for the salt.modules.linux_lvm module """ - import os.path import pytest @@ -371,7 +370,7 @@ def test_lvcreate_extra_arguments_no_parameter(): assert linux_lvm.lvcreate(None, None, None, 1, **extra_args) == { "Output from lvcreate": 'Logical volume "None" created.' } - expected_args = ["--{}".format(arg) for arg in extra_args] + expected_args = [f"--{arg}" for arg in extra_args] processed_extra_args = mock.call_args.args[0][-(len(extra_args) + 1) : -1] assert all([arg in expected_args for arg in processed_extra_args]) diff --git a/tests/pytests/unit/modules/test_linux_shadow.py b/tests/pytests/unit/modules/test_linux_shadow.py index 5d977fc5212..0c742672750 100644 --- a/tests/pytests/unit/modules/test_linux_shadow.py +++ b/tests/pytests/unit/modules/test_linux_shadow.py @@ -1,6 +1,7 @@ """ :codeauthor: Erik Johnson """ + import types import pytest diff --git a/tests/pytests/unit/modules/test_locate.py b/tests/pytests/unit/modules/test_locate.py index f74853a10bc..f4e5b2fb822 100644 --- a/tests/pytests/unit/modules/test_locate.py +++ b/tests/pytests/unit/modules/test_locate.py @@ -4,7 +4,6 @@ Test cases for salt.modules.locate """ - import pytest import salt.modules.locate as locate diff --git a/tests/pytests/unit/modules/test_logadm.py b/tests/pytests/unit/modules/test_logadm.py index 7926252d025..fd5e61ba30f 100644 --- a/tests/pytests/unit/modules/test_logadm.py +++ b/tests/pytests/unit/modules/test_logadm.py @@ -4,7 +4,6 @@ Test cases for salt.modules.logadm """ - import pytest import salt.modules.logadm as logadm diff --git a/tests/pytests/unit/modules/test_logrotate.py b/tests/pytests/unit/modules/test_logrotate.py index 86caa5e58ad..03872c4cf06 100644 --- a/tests/pytests/unit/modules/test_logrotate.py +++ b/tests/pytests/unit/modules/test_logrotate.py @@ -4,7 +4,6 @@ Test cases for salt.modules.logrotate """ - import pytest import salt.modules.logrotate as logrotate diff --git a/tests/pytests/unit/modules/test_lvs.py b/tests/pytests/unit/modules/test_lvs.py index 58ba24a4160..513046787f0 100644 --- a/tests/pytests/unit/modules/test_lvs.py +++ b/tests/pytests/unit/modules/test_lvs.py @@ -4,7 +4,6 @@ Test cases for salt.modules.lvs """ - import pytest import salt.modules.lvs as lvs diff --git a/tests/pytests/unit/modules/test_mac_assistive.py b/tests/pytests/unit/modules/test_mac_assistive.py index 40841f516f2..b670991681c 100644 --- a/tests/pytests/unit/modules/test_mac_assistive.py +++ b/tests/pytests/unit/modules/test_mac_assistive.py @@ -49,7 +49,7 @@ def tcc_db_path(tmp_path, macos_version): # .schema # # Copy/Paste the output of that to this test. - pytest.fail("Don't know how to handle {}".format(macos_version)) + pytest.fail(f"Don't know how to handle {macos_version}") conn = sqlite3.connect(str(db)) with conn: for stmt in schema.splitlines(): diff --git a/tests/pytests/unit/modules/test_mac_brew_pkg.py b/tests/pytests/unit/modules/test_mac_brew_pkg.py index e824ba175df..6cd46f1ebb5 100644 --- a/tests/pytests/unit/modules/test_mac_brew_pkg.py +++ b/tests/pytests/unit/modules/test_mac_brew_pkg.py @@ -1,6 +1,7 @@ """ :codeauthor: Nicole Thomas """ + import os import textwrap diff --git a/tests/pytests/unit/modules/test_mac_service.py b/tests/pytests/unit/modules/test_mac_service.py index c657ea893c5..91578d946cf 100644 --- a/tests/pytests/unit/modules/test_mac_service.py +++ b/tests/pytests/unit/modules/test_mac_service.py @@ -2,7 +2,6 @@ :codeauthor: Megan Wilhite """ - import pytest import salt.modules.mac_service as mac_service diff --git a/tests/pytests/unit/modules/test_mac_shadow.py b/tests/pytests/unit/modules/test_mac_shadow.py index fa294b6651d..94d3c36b046 100644 --- a/tests/pytests/unit/modules/test_mac_shadow.py +++ b/tests/pytests/unit/modules/test_mac_shadow.py @@ -1,6 +1,7 @@ """ Unit Tests for the mac_desktop execution module. """ + from datetime import datetime import pytest diff --git a/tests/pytests/unit/modules/test_mandrill.py b/tests/pytests/unit/modules/test_mandrill.py index c1930d470e3..4f1c62e4673 100644 --- a/tests/pytests/unit/modules/test_mandrill.py +++ b/tests/pytests/unit/modules/test_mandrill.py @@ -2,7 +2,6 @@ Tests for the Mandrill execution module. """ - import pytest import salt.modules.mandrill as mandrill diff --git a/tests/pytests/unit/modules/test_match.py b/tests/pytests/unit/modules/test_match.py index 3a942dec752..6f159c0e8a5 100644 --- a/tests/pytests/unit/modules/test_match.py +++ b/tests/pytests/unit/modules/test_match.py @@ -2,7 +2,6 @@ :codeauthor: Oleg Lipovchenko """ - import pytest import salt.loader @@ -145,7 +144,7 @@ def test_watch_for_opts_mismatch_compound_match(minion_id): and use it instead of `__opts__`. If sometime in the future we update the matchers and use `__opts__` directly this breaks proxy matching. """ - assert compound_match.match("L@{}".format(minion_id)) + assert compound_match.match(f"L@{minion_id}") assert compound_match.match("L@rest03", {"id": "rest03"}) assert not compound_match.match("L@rest03") diff --git a/tests/pytests/unit/modules/test_mdadm_raid.py b/tests/pytests/unit/modules/test_mdadm_raid.py index f496339b738..ebbf9cecc25 100644 --- a/tests/pytests/unit/modules/test_mdadm_raid.py +++ b/tests/pytests/unit/modules/test_mdadm_raid.py @@ -5,6 +5,7 @@ tests.unit.modules.mdadm_test ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import re import pytest diff --git a/tests/pytests/unit/modules/test_mine.py b/tests/pytests/unit/modules/test_mine.py index 9fdfecbd0c1..2f06c1c27d8 100644 --- a/tests/pytests/unit/modules/test_mine.py +++ b/tests/pytests/unit/modules/test_mine.py @@ -3,7 +3,6 @@ :codeauthor: Herbert Buurman """ - import pytest import salt.modules.mine as mine @@ -24,7 +23,7 @@ class FakeCache: return self.data.get((bank, key), {}) def debug(self): - print("{}:FakeCache dump:\n{}".format(__name__, self.data)) + print(f"{__name__}:FakeCache dump:\n{self.data}") @pytest.fixture diff --git a/tests/pytests/unit/modules/test_mongodb.py b/tests/pytests/unit/modules/test_mongodb.py index b8b011dfdac..37bf432af25 100644 --- a/tests/pytests/unit/modules/test_mongodb.py +++ b/tests/pytests/unit/modules/test_mongodb.py @@ -112,7 +112,9 @@ def test_version(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_command, patch_pymongo_database, patch_salt_dict: + with ( + patch_mongo_client + ), patch_pymongo_command, patch_pymongo_database, patch_salt_dict: ret = mongodb.version() assert ret == "6.0.2" @@ -139,7 +141,9 @@ def test_db_list(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_list_db_names, patch_mongo_client, patch_pymongo_database, patch_salt_dict: + with ( + patch_list_db_names + ), patch_mongo_client, patch_pymongo_database, patch_salt_dict: ret = mongodb.db_list() assert ret == ["admin", "config", "local"] @@ -167,7 +171,9 @@ def test_db_exists(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_list_db_names, patch_mongo_client, patch_pymongo_database, patch_salt_dict: + with ( + patch_list_db_names + ), patch_mongo_client, patch_pymongo_database, patch_salt_dict: ret = mongodb.db_exists("admin") assert ret @@ -215,7 +221,9 @@ def test_user_list(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_pymongo_command, patch_salt_dict: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_pymongo_command, patch_salt_dict: ret = mongodb.user_list() expected = [ { @@ -318,7 +326,9 @@ def test_user_create(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_create("test_user", "test_password") assert ret @@ -344,7 +354,9 @@ def test_user_create_exception(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_create("test_user", "test_password") assert not ret @@ -370,7 +382,9 @@ def test_user_remove(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_remove("test_user") assert ret @@ -396,7 +410,9 @@ def test_user_remove_exception(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_remove("test_user") assert not ret @@ -446,7 +462,9 @@ def test_user_roles_exists(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_roles_exists("test_user", '["read"]', "admin") assert ret @@ -471,7 +489,9 @@ def test_user_grant_roles(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_grant_roles( "test_user", '[{"role": "readWrite", "db": "admin" }]', "admin" ) @@ -498,7 +518,9 @@ def test_user_revoke_roles(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.user_revoke_roles( "test_user", '[{"role": "readWrite", "db": "admin" }]', "admin" ) @@ -525,7 +547,9 @@ def test_collection_create(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_command: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_command: ret = mongodb.collection_create("test_collection") assert ret @@ -552,7 +576,9 @@ def test_collections_list(): mongodb.__salt__, {"config.option": config_option_mock} ) - with patch_mongo_client, patch_pymongo_database, patch_salt_dict, patch_pymongo_list_collection_names: + with ( + patch_mongo_client + ), patch_pymongo_database, patch_salt_dict, patch_pymongo_list_collection_names: ret = mongodb.collections_list() assert ret == ["system.users", "mycollection", "system.version"] @@ -579,7 +605,9 @@ def test_insert(): patch_pymongo_database = patch("pymongo.database.Database", pymongo_database_mock) patch_pymongo_collection = patch.object(mongodb, "getattr", pymongo_collection_mock) - with patch_mongo_client, patch_salt_dict, patch_pymongo_database, patch_pymongo_collection: + with ( + patch_mongo_client + ), patch_salt_dict, patch_pymongo_database, patch_pymongo_collection: patch_pymongo_collection_insert = patch.object( MockPyMongoCollection, "insert_many", diff --git a/tests/pytests/unit/modules/test_monit.py b/tests/pytests/unit/modules/test_monit.py index 092782bc1dd..7e16f1eca69 100644 --- a/tests/pytests/unit/modules/test_monit.py +++ b/tests/pytests/unit/modules/test_monit.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import pytest import salt.modules.monit as monit diff --git a/tests/pytests/unit/modules/test_mysql.py b/tests/pytests/unit/modules/test_mysql.py index 001655c8fd1..7e2bb5928b3 100644 --- a/tests/pytests/unit/modules/test_mysql.py +++ b/tests/pytests/unit/modules/test_mysql.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import pytest @@ -861,7 +860,7 @@ def _test_call(function, expected_sql, *args, **kwargs): .execute("{}".format(expected_sql["sql"]), expected_sql["sql_args"]) ) else: - calls = call().cursor().execute("{}".format(expected_sql)) + calls = call().cursor().execute(f"{expected_sql}") connect_mock.assert_has_calls((calls,), True) diff --git a/tests/pytests/unit/modules/test_nacl.py b/tests/pytests/unit/modules/test_nacl.py index 915e2c5e3dd..2906ebc5419 100644 --- a/tests/pytests/unit/modules/test_nacl.py +++ b/tests/pytests/unit/modules/test_nacl.py @@ -1,6 +1,7 @@ """ Unit tests for the salt.modules.nacl module """ + import pytest import salt.utils.stringutils diff --git a/tests/pytests/unit/modules/test_nfs3.py b/tests/pytests/unit/modules/test_nfs3.py index 030e7f6d6f2..ecb16dff4a5 100644 --- a/tests/pytests/unit/modules/test_nfs3.py +++ b/tests/pytests/unit/modules/test_nfs3.py @@ -4,7 +4,6 @@ Test cases for salt.modules.nfs3 """ - import pytest import salt.modules.nfs3 as nfs3 diff --git a/tests/pytests/unit/modules/test_nftables.py b/tests/pytests/unit/modules/test_nftables.py index 423a38c0101..855e7712e7f 100644 --- a/tests/pytests/unit/modules/test_nftables.py +++ b/tests/pytests/unit/modules/test_nftables.py @@ -3,6 +3,7 @@ Test cases for salt.modules.nftables """ + import json import pytest diff --git a/tests/pytests/unit/modules/test_npm.py b/tests/pytests/unit/modules/test_npm.py index 61117ffcc12..53243964953 100644 --- a/tests/pytests/unit/modules/test_npm.py +++ b/tests/pytests/unit/modules/test_npm.py @@ -4,7 +4,6 @@ Test cases for salt.modules.npm """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_openbsdpkg.py b/tests/pytests/unit/modules/test_openbsdpkg.py index 33261be9464..aca6068cc48 100644 --- a/tests/pytests/unit/modules/test_openbsdpkg.py +++ b/tests/pytests/unit/modules/test_openbsdpkg.py @@ -2,7 +2,6 @@ :codeauthor: Eric Radman """ - import pytest import salt.modules.openbsdpkg as openbsdpkg diff --git a/tests/pytests/unit/modules/test_openbsdrcctl_service.py b/tests/pytests/unit/modules/test_openbsdrcctl_service.py index b0f97fa1404..1aa53507562 100644 --- a/tests/pytests/unit/modules/test_openbsdrcctl_service.py +++ b/tests/pytests/unit/modules/test_openbsdrcctl_service.py @@ -28,32 +28,28 @@ def configure_loader_modules(retcode_mock): def test_available(retcode_mock, rcctl): retcode_mock.return_value = 0 assert openbsdrcctl.available("test") is True - retcode_mock.assert_called_with("{} get test".format(rcctl), ignore_retcode=True) + retcode_mock.assert_called_with(f"{rcctl} get test", ignore_retcode=True) retcode_mock.return_value = 2 assert openbsdrcctl.available("test") is False - retcode_mock.assert_called_with("{} get test".format(rcctl), ignore_retcode=True) + retcode_mock.assert_called_with(f"{rcctl} get test", ignore_retcode=True) def test_status(retcode_mock, rcctl): retcode_mock.return_value = 0 assert openbsdrcctl.status("test") is True - retcode_mock.assert_called_with("{} check test".format(rcctl), ignore_retcode=True) + retcode_mock.assert_called_with(f"{rcctl} check test", ignore_retcode=True) retcode_mock.return_value = 2 assert openbsdrcctl.status("test") is False - retcode_mock.assert_called_with("{} check test".format(rcctl), ignore_retcode=True) + retcode_mock.assert_called_with(f"{rcctl} check test", ignore_retcode=True) def test_disabled(retcode_mock, rcctl): retcode_mock.return_value = 0 assert openbsdrcctl.disabled("test") is False - retcode_mock.assert_called_with( - "{} get test status".format(rcctl), ignore_retcode=True - ) + retcode_mock.assert_called_with(f"{rcctl} get test status", ignore_retcode=True) retcode_mock.return_value = 2 assert openbsdrcctl.disabled("test") is True - retcode_mock.assert_called_with( - "{} get test status".format(rcctl), ignore_retcode=True - ) + retcode_mock.assert_called_with(f"{rcctl} get test status", ignore_retcode=True) def test_enabled(retcode_mock, rcctl): @@ -66,12 +62,8 @@ def test_enabled(retcode_mock, rcctl): } with patch.dict(openbsdrcctl.__salt__, salt_mock): assert openbsdrcctl.enabled("test", flags=flags_return) is True - retcode_mock.assert_called_with( - "{} get test status".format(rcctl), ignore_retcode=True - ) + retcode_mock.assert_called_with(f"{rcctl} get test status", ignore_retcode=True) retcode_mock.return_value = 2 stdout_mock.reset_mock() assert openbsdrcctl.enabled("test") is False - retcode_mock.assert_called_with( - "{} get test status".format(rcctl), ignore_retcode=True - ) + retcode_mock.assert_called_with(f"{rcctl} get test status", ignore_retcode=True) diff --git a/tests/pytests/unit/modules/test_oracle.py b/tests/pytests/unit/modules/test_oracle.py index 2e578e6b5db..4aa8318d9b7 100644 --- a/tests/pytests/unit/modules/test_oracle.py +++ b/tests/pytests/unit/modules/test_oracle.py @@ -4,7 +4,6 @@ Test cases for salt.modules.oracle """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_osquery.py b/tests/pytests/unit/modules/test_osquery.py index 98ce22b25e3..20647a6dfc4 100644 --- a/tests/pytests/unit/modules/test_osquery.py +++ b/tests/pytests/unit/modules/test_osquery.py @@ -4,7 +4,6 @@ Test cases for salt.modules.osquery """ - import pytest import salt.modules.osquery as osquery diff --git a/tests/pytests/unit/modules/test_pacmanpkg.py b/tests/pytests/unit/modules/test_pacmanpkg.py index 09a6f6aef16..796624dbeb7 100644 --- a/tests/pytests/unit/modules/test_pacmanpkg.py +++ b/tests/pytests/unit/modules/test_pacmanpkg.py @@ -2,7 +2,6 @@ :codeauthor: Eric Vz """ - import pytest import salt.modules.pacmanpkg as pacman @@ -110,7 +109,7 @@ def test_group_list(): elif cmd == ["pacman", "-Qg"]: return "group-a pkg1\ngroup-b pkg4" else: - return "Untested command ({}, {})!".format(cmd, kwargs) + return f"Untested command ({cmd}, {kwargs})!" cmdmock = MagicMock(side_effect=cmdlist) @@ -137,7 +136,7 @@ def test_group_info(): if cmd == ["pacman", "-Sgg", "testgroup"]: return "testgroup pkg1\ntestgroup pkg2" else: - return "Untested command ({}, {})!".format(cmd, kwargs) + return f"Untested command ({cmd}, {kwargs})!" cmdmock = MagicMock(side_effect=cmdlist) diff --git a/tests/pytests/unit/modules/test_pagerduty.py b/tests/pytests/unit/modules/test_pagerduty.py index 0d4cda95868..f43df961f53 100644 --- a/tests/pytests/unit/modules/test_pagerduty.py +++ b/tests/pytests/unit/modules/test_pagerduty.py @@ -4,7 +4,6 @@ Test cases for salt.modules.pagerduty """ - import pytest import salt.modules.pagerduty as pagerduty diff --git a/tests/pytests/unit/modules/test_pam.py b/tests/pytests/unit/modules/test_pam.py index 0fd8078a560..6f1e7faf661 100644 --- a/tests/pytests/unit/modules/test_pam.py +++ b/tests/pytests/unit/modules/test_pam.py @@ -3,6 +3,7 @@ Test cases for salt.modules.pam """ + import pytest import salt.modules.pam as pam diff --git a/tests/pytests/unit/modules/test_parallels.py b/tests/pytests/unit/modules/test_parallels.py index 2d48ccb6146..22c0b1c87df 100644 --- a/tests/pytests/unit/modules/test_parallels.py +++ b/tests/pytests/unit/modules/test_parallels.py @@ -2,7 +2,6 @@ Test parallels desktop execution module functions """ - import textwrap import pytest @@ -234,12 +233,12 @@ def test_exists(): runas = "macdev" # Validate exists - mock_list = MagicMock(return_value="Name: {}\nState: running".format(name)) + mock_list = MagicMock(return_value=f"Name: {name}\nState: running") with patch.object(parallels, "list_vms", mock_list): assert parallels.exists(name, runas=runas) # Validate not exists - mock_list = MagicMock(return_value="Name: {}\nState: running".format(name)) + mock_list = MagicMock(return_value=f"Name: {name}\nState: running") with patch.object(parallels, "list_vms", mock_list): assert not parallels.exists("winvm", runas=runas) diff --git a/tests/pytests/unit/modules/test_pecl.py b/tests/pytests/unit/modules/test_pecl.py index 65b1235ce18..8113fb4ce64 100644 --- a/tests/pytests/unit/modules/test_pecl.py +++ b/tests/pytests/unit/modules/test_pecl.py @@ -4,7 +4,6 @@ Test cases for salt.modules.pecl """ - import pytest import salt.modules.pecl as pecl diff --git a/tests/pytests/unit/modules/test_pkgutil.py b/tests/pytests/unit/modules/test_pkgutil.py index 627c807d917..5df0044fc30 100644 --- a/tests/pytests/unit/modules/test_pkgutil.py +++ b/tests/pytests/unit/modules/test_pkgutil.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.pkgutil as pkgutil diff --git a/tests/pytests/unit/modules/test_portage_config.py b/tests/pytests/unit/modules/test_portage_config.py index 34b388a8a43..71da51390e2 100644 --- a/tests/pytests/unit/modules/test_portage_config.py +++ b/tests/pytests/unit/modules/test_portage_config.py @@ -4,6 +4,7 @@ pytest.unit.modules.portage_flags ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ + import pytest import salt.modules.portage_config as portage_config @@ -26,7 +27,7 @@ def test_get_config_file_wildcards(): ("cat/pkg::repo", "/etc/portage/package.mask/cat/pkg"), ] - for (atom, expected) in pairs: + for atom, expected in pairs: assert portage_config._get_config_file("mask", atom) == expected diff --git a/tests/pytests/unit/modules/test_postfix.py b/tests/pytests/unit/modules/test_postfix.py index e834b654473..72ed5a8d4b7 100644 --- a/tests/pytests/unit/modules/test_postfix.py +++ b/tests/pytests/unit/modules/test_postfix.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.postfix as postfix diff --git a/tests/pytests/unit/modules/test_poudriere.py b/tests/pytests/unit/modules/test_poudriere.py index 4f069f47715..899d553a6bb 100644 --- a/tests/pytests/unit/modules/test_poudriere.py +++ b/tests/pytests/unit/modules/test_poudriere.py @@ -34,9 +34,9 @@ def test_make_pkgng_aware(): """ temp_dir = os.path.join("tmp", "salt") conf_file = os.path.join("tmp", "salt", "salt-make.conf") - ret1 = "Could not create or find required directory {}".format(temp_dir) - ret2 = "Looks like file {} could not be created".format(conf_file) - ret3 = {"changes": "Created {}".format(conf_file)} + ret1 = f"Could not create or find required directory {temp_dir}" + ret2 = f"Looks like file {conf_file} could not be created" + ret3 = {"changes": f"Created {conf_file}"} mock = MagicMock(return_value=temp_dir) mock_true = MagicMock(return_value=True) with patch.dict( diff --git a/tests/pytests/unit/modules/test_ps.py b/tests/pytests/unit/modules/test_ps.py index 99540b243d2..ba87bdccd4a 100644 --- a/tests/pytests/unit/modules/test_ps.py +++ b/tests/pytests/unit/modules/test_ps.py @@ -85,7 +85,9 @@ def sample_process(): patch_create_time = patch( "psutil._psplatform.Process.create_time", return_value=393829200 ) - with patch_stat_file, patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: + with ( + patch_stat_file + ), patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: proc = psutil.Process(pid=42) proc.info = proc.as_dict(("name", "status")) yield proc @@ -1184,7 +1186,9 @@ def test_proc_info(): patch_create_time = patch( "psutil._psplatform.Process.create_time", return_value=393829200 ) - with patch_stat_file, patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: + with ( + patch_stat_file + ), patch_status, patch_create_time, patch_exe, patch_oneshot, patch_kinfo: if salt.utils.platform.is_windows(): with patch("psutil._pswindows.cext") as mock__psutil_windows: with patch("psutil._pswindows.Process.ppid", return_value=99): diff --git a/tests/pytests/unit/modules/test_publish.py b/tests/pytests/unit/modules/test_publish.py index 38731761a91..5da0902dfa7 100644 --- a/tests/pytests/unit/modules/test_publish.py +++ b/tests/pytests/unit/modules/test_publish.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.publish as publish diff --git a/tests/pytests/unit/modules/test_pw_user.py b/tests/pytests/unit/modules/test_pw_user.py index c527bcbd2df..9b1c86f1039 100644 --- a/tests/pytests/unit/modules/test_pw_user.py +++ b/tests/pytests/unit/modules/test_pw_user.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import logging import pytest diff --git a/tests/pytests/unit/modules/test_qemu_img.py b/tests/pytests/unit/modules/test_qemu_img.py index b616f6f172b..ed175d33a36 100644 --- a/tests/pytests/unit/modules/test_qemu_img.py +++ b/tests/pytests/unit/modules/test_qemu_img.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_rabbitmq.py b/tests/pytests/unit/modules/test_rabbitmq.py index b9004962b4f..13860cd33f5 100644 --- a/tests/pytests/unit/modules/test_rabbitmq.py +++ b/tests/pytests/unit/modules/test_rabbitmq.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import logging import pytest diff --git a/tests/pytests/unit/modules/test_rbenv.py b/tests/pytests/unit/modules/test_rbenv.py index ed0a535ec37..5d36acc2094 100644 --- a/tests/pytests/unit/modules/test_rbenv.py +++ b/tests/pytests/unit/modules/test_rbenv.py @@ -4,7 +4,6 @@ Test cases for salt.modules.rbenv """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_rdp.py b/tests/pytests/unit/modules/test_rdp.py index 682bd752f1b..8815b201737 100644 --- a/tests/pytests/unit/modules/test_rdp.py +++ b/tests/pytests/unit/modules/test_rdp.py @@ -4,7 +4,6 @@ Test cases for salt.modules.rdp """ - import pytest import salt.modules.rdp as rdp diff --git a/tests/pytests/unit/modules/test_reg.py b/tests/pytests/unit/modules/test_reg.py index 480af192086..e28f6db832a 100644 --- a/tests/pytests/unit/modules/test_reg.py +++ b/tests/pytests/unit/modules/test_reg.py @@ -193,7 +193,7 @@ def test_list_keys_non_existing(): """ Test the list_keys function using a non existing registry key """ - expected = (False, "Cannot find key: HKLM\\{}".format(FAKE_KEY)) + expected = (False, f"Cannot find key: HKLM\\{FAKE_KEY}") result = reg.list_keys(hive="HKLM", key=FAKE_KEY) assert result == expected @@ -235,7 +235,7 @@ def test_list_values_non_existing(): """ Test the list_values function using a non existing registry key """ - expected = (False, "Cannot find key: HKLM\\{}".format(FAKE_KEY)) + expected = (False, f"Cannot find key: HKLM\\{FAKE_KEY}") result = reg.list_values(hive="HKLM", key=FAKE_KEY) assert result == expected @@ -312,7 +312,7 @@ def test_read_value_non_existing_key(): Test the read_value function using a non existing registry key """ expected = { - "comment": "Cannot find key: HKLM\\{}".format(FAKE_KEY), + "comment": f"Cannot find key: HKLM\\{FAKE_KEY}", "vdata": None, "vtype": None, "vname": "fake_name", diff --git a/tests/pytests/unit/modules/test_restartcheck.py b/tests/pytests/unit/modules/test_restartcheck.py index 14efa9a7add..2a4c385bd24 100644 --- a/tests/pytests/unit/modules/test_restartcheck.py +++ b/tests/pytests/unit/modules/test_restartcheck.py @@ -217,7 +217,11 @@ def test_when_nilinuxrt_and_not_kernel_modules_changed_or_sysapi_files_changed_a return_value=[], ) - with patch_grains, patch_kernel_versions, patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: + with ( + patch_grains + ), ( + patch_kernel_versions + ), patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: actual_result = restartcheck.restartcheck() assert actual_result == expected_result @@ -262,7 +266,11 @@ def test_when_nilinuxrt_and_not_kernel_modules_changed_or_sysapi_files_changed_a return_value=[], ) - with patch_grains, patch_kernel_versions, patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: + with ( + patch_grains + ), ( + patch_kernel_versions + ), patch_salt, patch_sysapi_changed, patch_kernel_mod_changed, patch_del_files: actual_result = restartcheck.restartcheck() assert actual_result == expected_result @@ -570,14 +578,10 @@ def test_valid_command(): patch_deleted = patch( "salt.modules.restartcheck._deleted_files", - MagicMock( - return_value=[(";touch {};".format(create_file), 123, "/root/ (deleted)")] - ), + MagicMock(return_value=[(f";touch {create_file};", 123, "/root/ (deleted)")]), ) - patch_readlink = patch( - "os.readlink", return_value="/root/;touch {};".format(create_file) - ) + patch_readlink = patch("os.readlink", return_value=f"/root/;touch {create_file};") check_error = True if salt.utils.path.which("repoquery"): @@ -635,7 +639,9 @@ def test_valid_command_b(): patch_popen = patch("subprocess.Popen", popen_mock) patch_grains = patch.dict(restartcheck.__grains__, {"os_family": "RedHat"}) - with patch_kernel, patch_salt, patch_deleted, patch_readlink, patch_grains, patch_popen: + with ( + patch_kernel + ), patch_salt, patch_deleted, patch_readlink, patch_grains, patch_popen: ret = restartcheck.restartcheck() assert "Found 1 processes using old versions of upgraded files" in ret popen_mock.assert_called_with( diff --git a/tests/pytests/unit/modules/test_ret.py b/tests/pytests/unit/modules/test_ret.py index 85c4e539859..25d85beecfa 100644 --- a/tests/pytests/unit/modules/test_ret.py +++ b/tests/pytests/unit/modules/test_ret.py @@ -4,7 +4,6 @@ Test cases for salt.modules.ret """ - import pytest import salt.loader diff --git a/tests/pytests/unit/modules/test_rh_service.py b/tests/pytests/unit/modules/test_rh_service.py index bee9e1e0860..e6373b92e6e 100644 --- a/tests/pytests/unit/modules/test_rh_service.py +++ b/tests/pytests/unit/modules/test_rh_service.py @@ -4,7 +4,6 @@ Test cases for salt.modules.rh_service """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_rvm.py b/tests/pytests/unit/modules/test_rvm.py index 0125d7a42ff..dab57c2a2ff 100644 --- a/tests/pytests/unit/modules/test_rvm.py +++ b/tests/pytests/unit/modules/test_rvm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.rvm """ - import pytest import salt.modules.rvm as rvm diff --git a/tests/pytests/unit/modules/test_s6.py b/tests/pytests/unit/modules/test_s6.py index 7809051f03f..a66fd62018b 100644 --- a/tests/pytests/unit/modules/test_s6.py +++ b/tests/pytests/unit/modules/test_s6.py @@ -4,7 +4,6 @@ Test cases for salt.modules.s6 """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_saltcloudmod.py b/tests/pytests/unit/modules/test_saltcloudmod.py index 54f56552329..53f2f61f77b 100644 --- a/tests/pytests/unit/modules/test_saltcloudmod.py +++ b/tests/pytests/unit/modules/test_saltcloudmod.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.modules.saltcloudmod as saltcloudmod diff --git a/tests/pytests/unit/modules/test_schedule.py b/tests/pytests/unit/modules/test_schedule.py index 419c4df9c8b..1dbdc529d5a 100644 --- a/tests/pytests/unit/modules/test_schedule.py +++ b/tests/pytests/unit/modules/test_schedule.py @@ -59,7 +59,13 @@ def test_purge(job1): schedule, "list_", MagicMock(return_value=_schedule_data) ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_list: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_list: assert schedule.purge() == { "comment": ["Deleted job: job1 from schedule."], "changes": {"job1": "removed"}, @@ -113,7 +119,11 @@ def test_delete(job1): SaltEvent, "connect_pub", return_value=True ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: assert schedule.delete("job1") == { "comment": "Job job1 does not exist.", "changes": {}, @@ -268,7 +278,9 @@ def test_add(): SaltEvent, "get_event", return_value={"complete": True, "schedule": {}} ) - with patch_makedirs, patch_schedule_opts, patch_schedule_connect_pub, patch_schedule_event_fire: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_connect_pub, patch_schedule_event_fire: _ret_value = {"complete": True, "schedule": {"job1": {"salt": "salt"}}} patch_schedule_get_event = patch.object( @@ -355,7 +367,11 @@ def test_run_job(job1): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: assert schedule.run_job("job1") == { "comment": "Scheduling Job job1 on minion.", "result": True, @@ -384,7 +400,11 @@ def test_enable_job(): SaltEvent, "connect_pub", return_value=True ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: assert schedule.enable_job("job1") == { "comment": "Job job1 does not exist.", "changes": {}, @@ -414,7 +434,11 @@ def test_disable_job(): SaltEvent, "connect_pub", return_value=True ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: assert schedule.disable_job("job1") == { "comment": "Job job1 does not exist.", "changes": {}, @@ -503,7 +527,11 @@ def test_move(job1): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( schedule.__salt__, {"publish.publish": mock} @@ -545,7 +573,11 @@ def test_move(job1): mock = MagicMock(side_effect=[{}, {"job1": {}}]) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_connect_pub, patch_schedule_get_event: with patch.dict(schedule.__pillar__, {"schedule": {"job1": job1}}): mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( @@ -608,7 +640,11 @@ def test_copy(job1): SaltEvent, "connect_pub", return_value=True ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub: mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( schedule.__salt__, {"publish.publish": mock} @@ -648,7 +684,11 @@ def test_copy(job1): "result": False, } - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub: mock = MagicMock(return_value={}) patch_schedule_publish = patch.dict( schedule.__salt__, {"publish.publish": mock} @@ -762,7 +802,9 @@ def test_modify(job1): SaltEvent, "connect_pub", return_value=True ) - with patch_makedirs, patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub: + with ( + patch_makedirs + ), patch_schedule_opts, patch_schedule_event_fire, patch_schedule_connect_pub: _ret_value = {"complete": True, "schedule": {"job1": current_job1}} patch_schedule_get_event = patch.object( @@ -925,7 +967,11 @@ def test_is_enabled(): return_value={"complete": True, "schedule": {"job1": job1}}, ) - with patch_makedirs, patch_schedule_opts, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_salt: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_salt: ret = schedule.is_enabled("job1") assert ret == job1 @@ -966,7 +1012,11 @@ def test_job_status(): SaltEvent, "connect_pub", return_value=True ) - with patch_makedirs, patch_schedule_opts, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_salt: + with ( + patch_makedirs + ), ( + patch_schedule_opts + ), patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_salt: ret = schedule.job_status("job1") assert ret == { "_last_run": "2021-11-01T12:36:57", @@ -1022,7 +1072,13 @@ def test_list(job1): "os.path.exists", MagicMock(return_value=True) ) - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), ( + patch_schedule_get_event + ), patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: @@ -1050,7 +1106,15 @@ def test_list(job1): seconds: 10 """ - with patch_schedule_opts, patch_makedirs, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_os_path_exists: + with ( + patch_schedule_opts + ), ( + patch_makedirs + ), ( + patch_schedule_event_fire + ), ( + patch_schedule_get_event + ), patch_schedule_connect_pub, patch_schedule_os_path_exists: with patch("salt.utils.files.fopen", mock_open(read_data="")) as fopen_mock: ret = schedule.list_() assert ret == expected @@ -1082,7 +1146,13 @@ def test_list(job1): seconds: 10 """ - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), ( + patch_schedule_get_event + ), patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: @@ -1141,7 +1211,13 @@ def test_list_global_enabled(job1): "os.path.exists", MagicMock(return_value=True) ) - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), ( + patch_schedule_get_event + ), patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: @@ -1201,7 +1277,13 @@ def test_list_global_disabled(job1): "os.path.exists", MagicMock(return_value=True) ) - with patch_schedule_opts, patch_schedule_event_fire, patch_schedule_get_event, patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: + with ( + patch_schedule_opts + ), ( + patch_schedule_event_fire + ), ( + patch_schedule_get_event + ), patch_schedule_connect_pub, patch_schedule_os_path_exists, patch_makedirs: with patch( "salt.utils.files.fopen", mock_open(read_data=saved_schedule) ) as fopen_mock: diff --git a/tests/pytests/unit/modules/test_sdb.py b/tests/pytests/unit/modules/test_sdb.py index 01d1e1a6273..aa046d7cffe 100644 --- a/tests/pytests/unit/modules/test_sdb.py +++ b/tests/pytests/unit/modules/test_sdb.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.sdb as sdb diff --git a/tests/pytests/unit/modules/test_serverdensity_device.py b/tests/pytests/unit/modules/test_serverdensity_device.py index 6d79aefa813..5a65012c11e 100644 --- a/tests/pytests/unit/modules/test_serverdensity_device.py +++ b/tests/pytests/unit/modules/test_serverdensity_device.py @@ -4,7 +4,6 @@ TestCase for salt.modules.serverdensity_device """ - import pytest import salt.modules.serverdensity_device as serverdensity_device diff --git a/tests/pytests/unit/modules/test_servicenow.py b/tests/pytests/unit/modules/test_servicenow.py index 1971b63f653..d5e9a96ae13 100644 --- a/tests/pytests/unit/modules/test_servicenow.py +++ b/tests/pytests/unit/modules/test_servicenow.py @@ -4,7 +4,6 @@ TestCase for salt.modules.servicenow """ - import pytest import salt.modules.servicenow as servicenow diff --git a/tests/pytests/unit/modules/test_slackware_service.py b/tests/pytests/unit/modules/test_slackware_service.py index c2cd52e1a5d..93e685a0677 100644 --- a/tests/pytests/unit/modules/test_slackware_service.py +++ b/tests/pytests/unit/modules/test_slackware_service.py @@ -1,6 +1,7 @@ """ :codeauthor: Piter Punk """ + import os import pytest diff --git a/tests/pytests/unit/modules/test_smartos_imgadm.py b/tests/pytests/unit/modules/test_smartos_imgadm.py index 3f9500aaa81..111e28529dc 100644 --- a/tests/pytests/unit/modules/test_smartos_imgadm.py +++ b/tests/pytests/unit/modules/test_smartos_imgadm.py @@ -4,7 +4,6 @@ TestCase for salt.modules.smartos_imgadm module """ - import pytest import salt.modules.smartos_imgadm as imgadm diff --git a/tests/pytests/unit/modules/test_smtp.py b/tests/pytests/unit/modules/test_smtp.py index 983bb209cf2..840b6c08fbb 100644 --- a/tests/pytests/unit/modules/test_smtp.py +++ b/tests/pytests/unit/modules/test_smtp.py @@ -4,7 +4,6 @@ TestCase for salt.modules.smtp """ - import pytest import salt.modules.smtp as smtp diff --git a/tests/pytests/unit/modules/test_status.py b/tests/pytests/unit/modules/test_status.py index e0bb270df66..55632e13c0b 100644 --- a/tests/pytests/unit/modules/test_status.py +++ b/tests/pytests/unit/modules/test_status.py @@ -2,7 +2,6 @@ Test cases for salt.modules.status """ - import os import pytest @@ -150,7 +149,7 @@ def test_uptime_linux(): ), patch( "os.path.exists", MagicMock(return_value=True) ): - proc_uptime = salt.utils.stringutils.to_str("{} {}".format(m.ut, m.idle)) + proc_uptime = salt.utils.stringutils.to_str(f"{m.ut} {m.idle}") with patch("salt.utils.files.fopen", mock_open(read_data=proc_uptime)): ret = status.uptime() diff --git a/tests/pytests/unit/modules/test_suse_ip.py b/tests/pytests/unit/modules/test_suse_ip.py index b6812a0043f..c46764f7066 100644 --- a/tests/pytests/unit/modules/test_suse_ip.py +++ b/tests/pytests/unit/modules/test_suse_ip.py @@ -400,7 +400,7 @@ def _test_mode_0_or_2(mode_num=0): expected = [ "downdelay=200", "miimon=100", - "mode={}".format(mode_num), + f"mode={mode_num}", "use_carrier=0", ] assert bonding_opts == expected, bonding_opts @@ -414,7 +414,7 @@ def _test_mode_0_or_2(mode_num=0): "arp_ip_target=1.2.3.4,5.6.7.8", "downdelay=200", "miimon=100", - "mode={}".format(mode_num), + f"mode={mode_num}", "use_carrier=0", ] assert bonding_opts == expected, bonding_opts @@ -426,7 +426,7 @@ def _test_mode_0_or_2(mode_num=0): expected = [ "arp_interval=300", "arp_ip_target=1.2.3.4,5.6.7.8", - "mode={}".format(mode_num), + f"mode={mode_num}", ] assert bonding_opts == expected, bonding_opts @@ -580,14 +580,12 @@ def test_build_interface_bond_mode_4(): raise else: expected = [ - "ad_select={}".format(ad_select), + f"ad_select={ad_select}", "downdelay=200", "lacp_rate={}".format( "1" if lacp_rate == "fast" - else "0" - if lacp_rate == "slow" - else lacp_rate + else "0" if lacp_rate == "slow" else lacp_rate ), "miimon=100", "mode=4", diff --git a/tests/pytests/unit/modules/test_swift.py b/tests/pytests/unit/modules/test_swift.py index f8c0f313387..3fb5c504df8 100644 --- a/tests/pytests/unit/modules/test_swift.py +++ b/tests/pytests/unit/modules/test_swift.py @@ -4,7 +4,6 @@ Test cases for salt.modules.swift """ - import pytest import salt.modules.swift as swift diff --git a/tests/pytests/unit/modules/test_syslog_ng.py b/tests/pytests/unit/modules/test_syslog_ng.py index d481de33f96..88d403f4c61 100644 --- a/tests/pytests/unit/modules/test_syslog_ng.py +++ b/tests/pytests/unit/modules/test_syslog_ng.py @@ -2,7 +2,6 @@ Test cases for salt.modules.syslog_ng """ - import os from textwrap import dedent diff --git a/tests/pytests/unit/modules/test_system.py b/tests/pytests/unit/modules/test_system.py index d2a8a4ba9a9..c825db51cbc 100644 --- a/tests/pytests/unit/modules/test_system.py +++ b/tests/pytests/unit/modules/test_system.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.system as system diff --git a/tests/pytests/unit/modules/test_telegram.py b/tests/pytests/unit/modules/test_telegram.py index 568c01002b2..02679df4d1a 100644 --- a/tests/pytests/unit/modules/test_telegram.py +++ b/tests/pytests/unit/modules/test_telegram.py @@ -4,7 +4,6 @@ Test cases for salt.modules.telegram. """ - import pytest import salt.modules.telegram as telegram diff --git a/tests/pytests/unit/modules/test_tls.py b/tests/pytests/unit/modules/test_tls.py index 6ed24dbaf00..8f85c681982 100644 --- a/tests/pytests/unit/modules/test_tls.py +++ b/tests/pytests/unit/modules/test_tls.py @@ -97,8 +97,8 @@ bymYbi0l2pWqQLA2sPoRHNw= @pytest.mark.skip_on_windows(reason="Skipping on Windows per Shane's suggestion") def test_create_ca_permissions_on_cert_and_key(tmp_path, tls_test_data): ca_name = "test_ca" - certp = tmp_path / ca_name / "{}_ca_cert.crt".format(ca_name) - certk = tmp_path / ca_name / "{}_ca_cert.key".format(ca_name) + certp = tmp_path / ca_name / f"{ca_name}_ca_cert.crt" + certk = tmp_path / ca_name / f"{ca_name}_ca_cert.key" mock_opt = MagicMock(return_value=str(tmp_path)) mock_ret = MagicMock(return_value=0) @@ -392,16 +392,12 @@ def test_cert_info(tls_test_data): == str(err) ): log.exception(err) - pytest.skip( - "Encountered an upstream error with PyOpenSSL: {}".format(err) - ) + pytest.skip(f"Encountered an upstream error with PyOpenSSL: {err}") if "'_cffi_backend.CDataGCP' object has no attribute 'object'" == str( err ): log.exception(err) - pytest.skip( - "Encountered an upstream error with PyOpenSSL: {}".format(err) - ) + pytest.skip(f"Encountered an upstream error with PyOpenSSL: {err}") # python-openssl version 0.14, when installed with the "junos-eznc" pip # package, causes an error on this test. Newer versions of PyOpenSSL do not have # this issue. If 0.14 is installed and we hit this error, skip the test. @@ -555,7 +551,7 @@ def test_create_self_signed_cert(tmp_path, tls_test_data): certk = "{}/{}/certs/{}.key".format( ca_path, tls_dir, tls_test_data["create_ca"]["CN"] ) - ret = 'Created Private Key: "{}" Created Certificate: "{}"'.format(certk, certp) + ret = f'Created Private Key: "{certk}" Created Certificate: "{certp}"' mock_opt = MagicMock(return_value=ca_path) with patch.dict(tls.__salt__, {"config.option": mock_opt}), patch.dict( tls.__opts__, {"hash_type": "sha256", "cachedir": ca_path} @@ -580,7 +576,7 @@ def test_recreate_self_signed_cert(tmp_path, tls_test_data): certk = "{}/{}/certs/{}.key".format( ca_path, tls_dir, tls_test_data["create_ca"]["CN"] ) - ret = 'Created Private Key: "{}" Created Certificate: "{}"'.format(certk, certp) + ret = f'Created Private Key: "{certk}" Created Certificate: "{certp}"' mock_opt = MagicMock(return_value=ca_path) with patch.dict(tls.__salt__, {"config.option": mock_opt}), patch.dict( tls.__opts__, {"hash_type": "sha256", "cachedir": ca_path} diff --git a/tests/pytests/unit/modules/test_tomcat.py b/tests/pytests/unit/modules/test_tomcat.py index 869c3f96c85..6658fca0dad 100644 --- a/tests/pytests/unit/modules/test_tomcat.py +++ b/tests/pytests/unit/modules/test_tomcat.py @@ -2,7 +2,6 @@ Tests cases for salt.modules.tomcat """ - import io import urllib.request diff --git a/tests/pytests/unit/modules/test_transactional_update.py b/tests/pytests/unit/modules/test_transactional_update.py index 5d9294c49bd..eb6dfae2868 100644 --- a/tests/pytests/unit/modules/test_transactional_update.py +++ b/tests/pytests/unit/modules/test_transactional_update.py @@ -178,9 +178,11 @@ def test_commands_with_global_params(): "--non-interactive", "--drop-if-no-change", "--no-selfupdate", - cmd.replace("_", ".") - if cmd.startswith("grub") - else cmd.replace("_", "-"), + ( + cmd.replace("_", ".") + if cmd.startswith("grub") + else cmd.replace("_", "-") + ), ] ) diff --git a/tests/pytests/unit/modules/test_tuned.py b/tests/pytests/unit/modules/test_tuned.py index 19692ec9d83..557112a0fe3 100644 --- a/tests/pytests/unit/modules/test_tuned.py +++ b/tests/pytests/unit/modules/test_tuned.py @@ -2,7 +2,6 @@ Test for the salt.modules.tuned """ - import pytest from salt.modules import tuned diff --git a/tests/pytests/unit/modules/test_udev.py b/tests/pytests/unit/modules/test_udev.py index d5dbee9d20f..19e055908ee 100644 --- a/tests/pytests/unit/modules/test_udev.py +++ b/tests/pytests/unit/modules/test_udev.py @@ -4,7 +4,6 @@ Test cases for salt.modules.udev """ - import pytest import salt.modules.udev as udev diff --git a/tests/pytests/unit/modules/test_uptime.py b/tests/pytests/unit/modules/test_uptime.py index 2e129a7c9bb..9857a9959f4 100644 --- a/tests/pytests/unit/modules/test_uptime.py +++ b/tests/pytests/unit/modules/test_uptime.py @@ -2,7 +2,6 @@ Test cases for salt.modules.uptime """ - import pytest import salt.modules.uptime as uptime diff --git a/tests/pytests/unit/modules/test_uwsgi.py b/tests/pytests/unit/modules/test_uwsgi.py index 65d3f75a86a..23e35a2a105 100644 --- a/tests/pytests/unit/modules/test_uwsgi.py +++ b/tests/pytests/unit/modules/test_uwsgi.py @@ -2,7 +2,6 @@ Test cases for salt.modules.uswgi """ - import pytest import salt.modules.uwsgi as uwsgi diff --git a/tests/pytests/unit/modules/test_vagrant.py b/tests/pytests/unit/modules/test_vagrant.py index a6bc3c32cd0..d34c98c1a5e 100644 --- a/tests/pytests/unit/modules/test_vagrant.py +++ b/tests/pytests/unit/modules/test_vagrant.py @@ -2,7 +2,6 @@ TestCase for the salt.modules.vagrant module. """ - import pytest import salt.exceptions diff --git a/tests/pytests/unit/modules/test_vmctl.py b/tests/pytests/unit/modules/test_vmctl.py index e0935924a43..b264d99f1c7 100644 --- a/tests/pytests/unit/modules/test_vmctl.py +++ b/tests/pytests/unit/modules/test_vmctl.py @@ -2,7 +2,6 @@ Test for salt.modules.vmctl """ - import pytest import salt.modules.vmctl as vmctl diff --git a/tests/pytests/unit/modules/test_webutil.py b/tests/pytests/unit/modules/test_webutil.py index d6e9d0b466d..038e4778206 100644 --- a/tests/pytests/unit/modules/test_webutil.py +++ b/tests/pytests/unit/modules/test_webutil.py @@ -4,7 +4,6 @@ Test cases for salt.modules.webutil """ - import pytest import salt.modules.webutil as htpasswd diff --git a/tests/pytests/unit/modules/test_win_autoruns.py b/tests/pytests/unit/modules/test_win_autoruns.py index dd8060eedd8..1261a05c012 100644 --- a/tests/pytests/unit/modules/test_win_autoruns.py +++ b/tests/pytests/unit/modules/test_win_autoruns.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.modules.win_autoruns as win_autoruns diff --git a/tests/pytests/unit/modules/test_win_dns_client.py b/tests/pytests/unit/modules/test_win_dns_client.py index 8dfad4d0127..8e30c1bb58e 100644 --- a/tests/pytests/unit/modules/test_win_dns_client.py +++ b/tests/pytests/unit/modules/test_win_dns_client.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import types import pytest diff --git a/tests/pytests/unit/modules/test_win_iis.py b/tests/pytests/unit/modules/test_win_iis.py index f5e37724d24..c2fb37daaba 100644 --- a/tests/pytests/unit/modules/test_win_iis.py +++ b/tests/pytests/unit/modules/test_win_iis.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_iis """ - import pytest import salt.modules.win_iis as win_iis @@ -602,7 +601,7 @@ def test_get_webconfiguration_settings(): for setting in settings: ps_cmd.extend( [ - "$Property = Get-WebConfigurationProperty -PSPath '{}'".format(name), + f"$Property = Get-WebConfigurationProperty -PSPath '{name}'", "-Name '{name}' -Filter '{filter}' -ErrorAction Stop;".format( filter=setting["filter"], name=setting["name"] ), diff --git a/tests/pytests/unit/modules/test_win_licence.py b/tests/pytests/unit/modules/test_win_licence.py index 2948be088f0..70a6cfbc490 100644 --- a/tests/pytests/unit/modules/test_win_licence.py +++ b/tests/pytests/unit/modules/test_win_licence.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_licence """ - import pytest import salt.modules.win_license as win_license diff --git a/tests/pytests/unit/modules/test_win_path.py b/tests/pytests/unit/modules/test_win_path.py index 7dad024a878..8b12653feed 100644 --- a/tests/pytests/unit/modules/test_win_path.py +++ b/tests/pytests/unit/modules/test_win_path.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import os import pytest diff --git a/tests/pytests/unit/modules/test_win_pkg.py b/tests/pytests/unit/modules/test_win_pkg.py index 2d8439f9b44..d892e79a21b 100644 --- a/tests/pytests/unit/modules/test_win_pkg.py +++ b/tests/pytests/unit/modules/test_win_pkg.py @@ -1,6 +1,7 @@ """ Tests for the win_pkg module """ + import logging import pytest diff --git a/tests/pytests/unit/modules/test_win_pki.py b/tests/pytests/unit/modules/test_win_pki.py index 128fb14f820..600282e8bd8 100644 --- a/tests/pytests/unit/modules/test_win_pki.py +++ b/tests/pytests/unit/modules/test_win_pki.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_pki """ - import pytest import salt.modules.win_pki as win_pki diff --git a/tests/pytests/unit/modules/test_win_powercfg.py b/tests/pytests/unit/modules/test_win_powercfg.py index e1cd9426a4c..77475464e47 100644 --- a/tests/pytests/unit/modules/test_win_powercfg.py +++ b/tests/pytests/unit/modules/test_win_powercfg.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_powercfg """ - import pytest import salt.modules.win_powercfg as powercfg diff --git a/tests/pytests/unit/modules/test_win_psget.py b/tests/pytests/unit/modules/test_win_psget.py index af7737b121f..417106affe8 100644 --- a/tests/pytests/unit/modules/test_win_psget.py +++ b/tests/pytests/unit/modules/test_win_psget.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_psget """ - import pytest import salt.modules.win_psget as win_psget diff --git a/tests/pytests/unit/modules/test_win_shadow.py b/tests/pytests/unit/modules/test_win_shadow.py index bccb67fe9da..dbac3807172 100644 --- a/tests/pytests/unit/modules/test_win_shadow.py +++ b/tests/pytests/unit/modules/test_win_shadow.py @@ -4,7 +4,6 @@ Test cases for salt.modules.win_shadow """ - import pytest import salt.modules.win_shadow as win_shadow diff --git a/tests/pytests/unit/modules/test_win_snmp.py b/tests/pytests/unit/modules/test_win_snmp.py index 339f834e0d8..bb8370a521a 100644 --- a/tests/pytests/unit/modules/test_win_snmp.py +++ b/tests/pytests/unit/modules/test_win_snmp.py @@ -2,7 +2,6 @@ Test cases for salt.modules.win_snmp """ - import pytest import salt.modules.win_snmp as win_snmp diff --git a/tests/pytests/unit/modules/test_win_system.py b/tests/pytests/unit/modules/test_win_system.py index a33aa3b1002..54eed432995 100644 --- a/tests/pytests/unit/modules/test_win_system.py +++ b/tests/pytests/unit/modules/test_win_system.py @@ -1,6 +1,7 @@ """ :codeauthor: Gareth J. Greenaway """ + import pytest import salt.modules.cmdmod as cmdmod diff --git a/tests/pytests/unit/modules/test_win_task.py b/tests/pytests/unit/modules/test_win_task.py index 6e71612264a..ee61d739b99 100644 --- a/tests/pytests/unit/modules/test_win_task.py +++ b/tests/pytests/unit/modules/test_win_task.py @@ -1,6 +1,7 @@ """ Test the win_task execution module """ + from datetime import datetime import pytest diff --git a/tests/pytests/unit/modules/test_win_timezone.py b/tests/pytests/unit/modules/test_win_timezone.py index 26a867dff85..b32b6a0187b 100644 --- a/tests/pytests/unit/modules/test_win_timezone.py +++ b/tests/pytests/unit/modules/test_win_timezone.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.win_timezone as win_timezone diff --git a/tests/pytests/unit/modules/test_win_wua.py b/tests/pytests/unit/modules/test_win_wua.py index 234574a015d..ee4db206a03 100644 --- a/tests/pytests/unit/modules/test_win_wua.py +++ b/tests/pytests/unit/modules/test_win_wua.py @@ -1,6 +1,7 @@ """ Test the win_wua execution module """ + import pytest import salt.modules.win_wua as win_wua diff --git a/tests/pytests/unit/modules/test_xapi_virt.py b/tests/pytests/unit/modules/test_xapi_virt.py index 47cdc4b6376..2f854f64cc9 100644 --- a/tests/pytests/unit/modules/test_xapi_virt.py +++ b/tests/pytests/unit/modules/test_xapi_virt.py @@ -4,7 +4,6 @@ Test cases for salt.modules.xapi """ - import pytest import salt.modules.xapi_virt as xapi diff --git a/tests/pytests/unit/modules/test_xfs.py b/tests/pytests/unit/modules/test_xfs.py index 9d1ce9dff34..79ff0dc2f34 100644 --- a/tests/pytests/unit/modules/test_xfs.py +++ b/tests/pytests/unit/modules/test_xfs.py @@ -2,7 +2,6 @@ Test cases for salt.modules.xfs """ - import textwrap import pytest diff --git a/tests/pytests/unit/modules/test_xml.py b/tests/pytests/unit/modules/test_xml.py index 334d2f2b73e..e627a5b6402 100644 --- a/tests/pytests/unit/modules/test_xml.py +++ b/tests/pytests/unit/modules/test_xml.py @@ -2,7 +2,6 @@ Tests for xml module """ - import pytest from salt.modules import xml diff --git a/tests/pytests/unit/modules/test_yumpkg.py b/tests/pytests/unit/modules/test_yumpkg.py index 35f545ad72b..ecdad27ac83 100644 --- a/tests/pytests/unit/modules/test_yumpkg.py +++ b/tests/pytests/unit/modules/test_yumpkg.py @@ -1562,9 +1562,9 @@ def test_remove_with_epoch_and_arch_info(): installed = "8:3.8.12-4.n.el7" list_pkgs_mock = MagicMock( side_effect=lambda **kwargs: { - name_and_arch: [installed] - if kwargs.get("versions_as_list", False) - else installed + name_and_arch: ( + [installed] if kwargs.get("versions_as_list", False) else installed + ) } ) cmd_mock = MagicMock( diff --git a/tests/pytests/unit/modules/test_zenoss.py b/tests/pytests/unit/modules/test_zenoss.py index 3d03f11d770..fb2834cc484 100644 --- a/tests/pytests/unit/modules/test_zenoss.py +++ b/tests/pytests/unit/modules/test_zenoss.py @@ -2,7 +2,6 @@ Test cases for salt.modules.keystone """ - import pytest import salt.modules.config as config diff --git a/tests/pytests/unit/modules/test_zfs.py b/tests/pytests/unit/modules/test_zfs.py index a9d8a3016ec..a60a61f2aa6 100644 --- a/tests/pytests/unit/modules/test_zfs.py +++ b/tests/pytests/unit/modules/test_zfs.py @@ -215,9 +215,9 @@ def test_create_error_missing_parent(utils_patch): ) ret = {} ret["stdout"] = "" - ret[ - "stderr" - ] = "cannot create 'myzpool/mydataset/mysubdataset': parent does not exist" + ret["stderr"] = ( + "cannot create 'myzpool/mydataset/mysubdataset': parent does not exist" + ) ret["retcode"] = 1 mock_cmd = MagicMock(return_value=ret) with patch.dict(zfs.__salt__, {"cmd.run_all": mock_cmd}), patch.dict( diff --git a/tests/pytests/unit/modules/test_znc.py b/tests/pytests/unit/modules/test_znc.py index a28f8f1ca26..1cf491e5b0a 100644 --- a/tests/pytests/unit/modules/test_znc.py +++ b/tests/pytests/unit/modules/test_znc.py @@ -4,7 +4,6 @@ TestCase for salt.modules.znc """ - import pytest import salt.modules.znc as znc diff --git a/tests/pytests/unit/modules/test_zpool.py b/tests/pytests/unit/modules/test_zpool.py index 48fcf9e272c..f3256db0b8c 100644 --- a/tests/pytests/unit/modules/test_zpool.py +++ b/tests/pytests/unit/modules/test_zpool.py @@ -469,9 +469,9 @@ def test_split_not_mirror(utils_patch): """ ret = {} ret["stdout"] = "" - ret[ - "stderr" - ] = "Unable to split datapool: Source pool must be composed only of mirrors" + ret["stderr"] = ( + "Unable to split datapool: Source pool must be composed only of mirrors" + ) ret["retcode"] = 1 mock_cmd = MagicMock(return_value=ret) diff --git a/tests/pytests/unit/modules/test_zypperpkg.py b/tests/pytests/unit/modules/test_zypperpkg.py index 2780524b559..1cb2d34b98a 100644 --- a/tests/pytests/unit/modules/test_zypperpkg.py +++ b/tests/pytests/unit/modules/test_zypperpkg.py @@ -2,7 +2,6 @@ :codeauthor: Gareth J. Greenaway """ - import os import textwrap diff --git a/tests/pytests/unit/modules/virt/conftest.py b/tests/pytests/unit/modules/virt/conftest.py index 03225530056..6e1bfa539b0 100644 --- a/tests/pytests/unit/modules/virt/conftest.py +++ b/tests/pytests/unit/modules/virt/conftest.py @@ -40,7 +40,7 @@ class MappedResultMock(MagicMock): def __init__(self): def mapped_results(*args, **kwargs): if args[0] not in self._instances.keys(): - raise virt.libvirt.libvirtError("Not found: {}".format(args[0])) + raise virt.libvirt.libvirtError(f"Not found: {args[0]}") return self._instances[args[0]] super().__init__(side_effect=mapped_results) @@ -150,8 +150,8 @@ def make_mock_storage_pool(): mocked_pool = mocked_conn.storagePoolLookupByName(name) source_def = source if not source and type == "disk": - source = "".format(name) - pool_path = "/path/to/{}".format(name) + source = f"" + pool_path = f"/path/to/{name}" mocked_pool.XMLDesc.return_value = """ @@ -185,7 +185,7 @@ def make_mock_storage_pool(): for volume in volumes: mocked_pool.storageVolLookupByName.add(volume) mocked_vol = mocked_pool.storageVolLookupByName(volume) - vol_path = "{}/{}".format(pool_path, volume) + vol_path = f"{pool_path}/{volume}" mocked_vol.XMLDesc.return_value = """ diff --git a/tests/pytests/unit/modules/virt/test_domain.py b/tests/pytests/unit/modules/virt/test_domain.py index 1d1a3d1849a..b0cb2f80f82 100644 --- a/tests/pytests/unit/modules/virt/test_domain.py +++ b/tests/pytests/unit/modules/virt/test_domain.py @@ -1941,14 +1941,17 @@ def test_update_disks(make_mock_vm): added_disk_path = os.path.join( virt.__salt__["config.get"]("virt:images"), "my_vm_added.qcow2" ) - assert mock_run.call_args[0][ - 0 - ] == 'qemu-img create -f qcow2 "{}" 2048M'.format(added_disk_path) + assert ( + mock_run.call_args[0][0] + == f'qemu-img create -f qcow2 "{added_disk_path}" 2048M' + ) assert mock_chmod.call_args[0][0] == added_disk_path assert [ - ET.fromstring(disk).find("source").get("file") - if str(disk).find(" -1 - else None + ( + ET.fromstring(disk).find("source").get("file") + if str(disk).find(" -1 + else None + ) for disk in ret["disk"]["attached"] ] == [None, os.path.join(root_dir, "my_vm_added.qcow2")] @@ -2018,9 +2021,11 @@ def test_update_disks_existing_block(make_mock_vm): ], ) assert [ - ET.fromstring(disk).find("source").get("file") - if str(disk).find(" -1 - else None + ( + ET.fromstring(disk).find("source").get("file") + if str(disk).find(" -1 + else None + ) for disk in ret["disk"]["attached"] ] == ["/dev/ssd/data"] diff --git a/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py b/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py index b9da371190b..1e34ffc4612 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py +++ b/tests/pytests/unit/modules/win_lgpo/test_admx_policies.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import glob import logging import os diff --git a/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py b/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py index 9acfc0f141c..7b3366eff8c 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py +++ b/tests/pytests/unit/modules/win_lgpo/test_defined_policies.py @@ -1,6 +1,7 @@ """ This tests policies that are defined in the giant dictionary in the LGPO module """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py b/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py index b9d659acb5f..5ce9ce2a4fb 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py +++ b/tests/pytests/unit/modules/win_lgpo/test_mechanisms.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import os import pytest diff --git a/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py b/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py index 88b1c05b4e7..4d39311f8e4 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py +++ b/tests/pytests/unit/modules/win_lgpo/test_point_print_enabled.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.cmdmod as cmdmod diff --git a/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py b/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py index 174ca38fb50..2196c7624c3 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py +++ b/tests/pytests/unit/modules/win_lgpo/test_point_print_nc.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.config diff --git a/tests/pytests/unit/modules/win_lgpo/test_policy_info.py b/tests/pytests/unit/modules/win_lgpo/test_policy_info.py index d0ed3c911a3..a11bf800dc0 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_policy_info.py +++ b/tests/pytests/unit/modules/win_lgpo/test_policy_info.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.win_file as win_file diff --git a/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py b/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py index bedacc237fb..2c3bb255212 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py +++ b/tests/pytests/unit/modules/win_lgpo/test_policy_info_functions.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.win_lgpo as win_lgpo diff --git a/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py b/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py index b7a6618f47e..8d49468792a 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py +++ b/tests/pytests/unit/modules/win_lgpo/test_policy_resources.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.cmdmod as cmdmod diff --git a/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py b/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py index 79c8a10393c..ae7a2a55f8a 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py +++ b/tests/pytests/unit/modules/win_lgpo/test_reg_pol.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import pytest import salt.modules.win_lgpo as win_lgpo diff --git a/tests/pytests/unit/modules/win_lgpo/test_secedit_policy.py b/tests/pytests/unit/modules/win_lgpo/test_secedit_policy.py index 6a0d2c027c5..81944e20ee3 100644 --- a/tests/pytests/unit/modules/win_lgpo/test_secedit_policy.py +++ b/tests/pytests/unit/modules/win_lgpo/test_secedit_policy.py @@ -78,7 +78,7 @@ def test_secedit_policy(shell, name, setting, exp_regexes, cumulative_rights, tm ) assert result is True temp_file = tmp_path / random_string("secedit-output-") - ret = shell.run("secedit", "/export", "/cfg", "{}".format(temp_file)) + ret = shell.run("secedit", "/export", "/cfg", f"{temp_file}") assert ret.returncode == 0 with salt.utils.files.fopen(temp_file, encoding="utf-16") as reader: content = reader.read() diff --git a/tests/pytests/unit/output/test_json_out.py b/tests/pytests/unit/output/test_json_out.py index 229315b31fe..3ade8e44e7c 100644 --- a/tests/pytests/unit/output/test_json_out.py +++ b/tests/pytests/unit/output/test_json_out.py @@ -1,6 +1,7 @@ """ unittests for json outputter """ + import pytest import salt.output.json_out as json_out diff --git a/tests/pytests/unit/output/test_nested.py b/tests/pytests/unit/output/test_nested.py index c56faf89672..4e85ff623cb 100644 --- a/tests/pytests/unit/output/test_nested.py +++ b/tests/pytests/unit/output/test_nested.py @@ -1,6 +1,7 @@ """ Unit tests for the Nested outputter """ + import pytest import salt.output.nested as nested diff --git a/tests/pytests/unit/output/test_yaml_out.py b/tests/pytests/unit/output/test_yaml_out.py index 6a87fd667c2..53380cc2c9a 100644 --- a/tests/pytests/unit/output/test_yaml_out.py +++ b/tests/pytests/unit/output/test_yaml_out.py @@ -1,6 +1,7 @@ """ unittests for yaml outputter """ + import pytest import salt.output.yaml_out as yaml diff --git a/tests/pytests/unit/pillar/test_csvpillar.py b/tests/pytests/unit/pillar/test_csvpillar.py index 82d270b0d43..cbb411ca9c2 100644 --- a/tests/pytests/unit/pillar/test_csvpillar.py +++ b/tests/pytests/unit/pillar/test_csvpillar.py @@ -1,6 +1,5 @@ """test for pillar csvpillar.py""" - import salt.pillar.csvpillar as csvpillar from tests.support.mock import mock_open, patch diff --git a/tests/pytests/unit/pillar/test_http_json_pillar.py b/tests/pytests/unit/pillar/test_http_json_pillar.py index 5040c2e7a14..fb9a3b09876 100644 --- a/tests/pytests/unit/pillar/test_http_json_pillar.py +++ b/tests/pytests/unit/pillar/test_http_json_pillar.py @@ -32,10 +32,10 @@ def test_ext_pillar_can_take_http_query_kwargs(backend, httpserver): # If the headers in header_dict are not in the request, httpserver will return an empty dictionary, so we know it will fail httpserver.expect_request( - "/http_json_pillar/{}".format(backend), + f"/http_json_pillar/{backend}", headers={"custom-backend-header": backend}, ).respond_with_data(salt.utils.json.dumps(response), content_type="text/plain") - url = httpserver.url_for("/http_json_pillar/{}".format(backend)) + url = httpserver.url_for(f"/http_json_pillar/{backend}") actual = http_json.ext_pillar("test-minion-id", {}, url, header_dict=header_dict) assert actual == response @@ -55,10 +55,10 @@ def test_ext_pillar_namespace(backend, httpserver): # If the headers in header_dict are not in the request, httpserver will return an empty dictionary, so we know it will fail httpserver.expect_request( - "/http_json_pillar/{}".format(backend), + f"/http_json_pillar/{backend}", headers={"custom-backend-header": backend}, ).respond_with_data(salt.utils.json.dumps(response), content_type="text/plain") - url = httpserver.url_for("/http_json_pillar/{}".format(backend)) + url = httpserver.url_for(f"/http_json_pillar/{backend}") actual = http_json.ext_pillar( "test-minion-id", {}, url, header_dict=header_dict, namespace=namespace diff --git a/tests/pytests/unit/pillar/test_http_yaml_pillar.py b/tests/pytests/unit/pillar/test_http_yaml_pillar.py index e9e0a5eee57..c4aa3450fe6 100644 --- a/tests/pytests/unit/pillar/test_http_yaml_pillar.py +++ b/tests/pytests/unit/pillar/test_http_yaml_pillar.py @@ -32,10 +32,10 @@ def test_ext_pillar_can_take_http_query_kwargs(backend, httpserver): # If the headers in header_dict are not in the request, httpserver will return an empty dictionary, so we know it will fail httpserver.expect_request( - "/http_yaml_pillar/{}".format(backend), + f"/http_yaml_pillar/{backend}", headers={"custom-backend-header": backend}, ).respond_with_data(salt.utils.json.dumps(response), content_type="text/plain") - url = httpserver.url_for("/http_yaml_pillar/{}".format(backend)) + url = httpserver.url_for(f"/http_yaml_pillar/{backend}") actual = http_yaml.ext_pillar("test-minion-id", {}, url, header_dict=header_dict) assert actual == response diff --git a/tests/pytests/unit/pillar/test_mysql.py b/tests/pytests/unit/pillar/test_mysql.py index 70dcf71fd9b..780fbca449e 100644 --- a/tests/pytests/unit/pillar/test_mysql.py +++ b/tests/pytests/unit/pillar/test_mysql.py @@ -843,7 +843,7 @@ def test_301_process_results_with_lists(): assert list(y.keys()) == ["g"] assert y["g"] == 2 else: - raise ValueError("Unexpected value {}".format(y)) + raise ValueError(f"Unexpected value {y}") elif "h" in x: assert len(x["h"]) == 1 for y in x["h"]: @@ -854,9 +854,9 @@ def test_301_process_results_with_lists(): assert len(y.keys()) == 2 assert y["k"] == 4 else: - raise ValueError("Unexpected value {}".format(y)) + raise ValueError(f"Unexpected value {y}") else: - raise ValueError("Unexpected value {}".format(x)) + raise ValueError(f"Unexpected value {x}") def test_302_process_results_with_lists_consecutive(): @@ -901,7 +901,7 @@ def test_302_process_results_with_lists_consecutive(): assert list(y.keys()) == ["g"] assert y["g"] == 2 else: - raise ValueError("Unexpected value {}".format(y)) + raise ValueError(f"Unexpected value {y}") elif len(x[0][0]) == 2: for y in x[0]: if "j" in y: @@ -911,6 +911,6 @@ def test_302_process_results_with_lists_consecutive(): assert len(y.keys()) == 2 assert y["k"] == 4 else: - raise ValueError("Unexpected value {}".format(len(x[0][0]))) + raise ValueError(f"Unexpected value {len(x[0][0])}") else: - raise ValueError("Unexpected value {}".format(x)) + raise ValueError(f"Unexpected value {x}") diff --git a/tests/pytests/unit/pillar/test_s3.py b/tests/pytests/unit/pillar/test_s3.py index ad7ff4cffba..14c76d84160 100644 --- a/tests/pytests/unit/pillar/test_s3.py +++ b/tests/pytests/unit/pillar/test_s3.py @@ -41,7 +41,7 @@ def test_refresh_buckets_cache_file(): first_range_end = 999 second_range_end = 1200 for i in range(0, first_range_end): - key_name = "{}/init.sls".format(i) + key_name = f"{i}/init.sls" tmp = { "Key": key_name, "LastModified": "2019-12-18T15:54:39.000Z", @@ -52,7 +52,7 @@ def test_refresh_buckets_cache_file(): mock_return_first.append(tmp) for i in range(first_range_end, second_range_end): - key_name = "{}/init.sls".format(i) + key_name = f"{i}/init.sls" tmp = { "Key": key_name, "LastModified": "2019-12-18T15:54:39.000Z", @@ -64,7 +64,7 @@ def test_refresh_buckets_cache_file(): _expected = {"base": {"dummy_bucket": []}} for i in range(0, second_range_end): - key_name = "{}/init.sls".format(i) + key_name = f"{i}/init.sls" tmp = { "Key": key_name, "LastModified": "2019-12-18T15:54:39.000Z", diff --git a/tests/pytests/unit/pillar/test_saltclass.py b/tests/pytests/unit/pillar/test_saltclass.py index 79fdaea8916..b96db78bc49 100644 --- a/tests/pytests/unit/pillar/test_saltclass.py +++ b/tests/pytests/unit/pillar/test_saltclass.py @@ -53,7 +53,7 @@ def temp_saltclass_tree(tmp_path, minion_id): """ default_init.write_text(test_list) - minion_node_file = nodes_dir / "{}.yml".format(minion_id) + minion_node_file = nodes_dir / f"{minion_id}.yml" nodes_text = """ environment: base diff --git a/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py b/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py index 7b703f4f901..8e632649ac1 100644 --- a/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py +++ b/tests/pytests/unit/proxy/nxos/test_nxos_nxapi.py @@ -32,7 +32,6 @@ def configure_loader_modules(): def test_check_virtual(): - """UT: nxos module:check_virtual method - return value""" result = nxos_proxy.__virtual__() @@ -40,7 +39,6 @@ def test_check_virtual(): def test_init(): - """UT: nxos module:init method - nxapi proxy""" with patch.object(nxos_proxy, "__opts__", {"proxy": {"connection": "nxapi"}}): @@ -50,7 +48,6 @@ def test_init(): def test_init_opts_none(): - """UT: nxos module:init method - __opts__ connection is None""" with patch.object(nxos_proxy, "__opts__", {"proxy": {"connection": None}}): @@ -60,14 +57,12 @@ def test_init_opts_none(): def test_init_bad_connection_type(): - """UT: nxos module:init method - bad CONNECTION type""" with patch.object(nxos_proxy, "__opts__", {"proxy": {"connection": "unknown"}}): assert not nxos_proxy.init() def test_initialized(): - """UT: nxos module:initialized method - nxapi proxy""" with patch( @@ -78,7 +73,6 @@ def test_initialized(): def test_ping(): - """UT: nxos module:ping method - nxapi proxy""" with patch("salt.proxy.nxos._ping_nxapi", autospec=True) as ping_nxapi: @@ -87,7 +81,6 @@ def test_ping(): def test_grains(): - """UT: nxos module:grains method - nxapi grains""" with patch( @@ -98,7 +91,6 @@ def test_grains(): def test_grains_cache_set(): - """UT: nxos module:grains method - nxapi grains cache set""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {"grains_cache": n9k_grains["nxos"]}): @@ -112,7 +104,6 @@ def test_grains_cache_set(): def test_grains_refresh(): - """UT: nxos module:grains_refresh method - nxapi grains""" device_details = {"grains_cache": None} @@ -125,7 +116,6 @@ def test_grains_refresh(): def test_sendline(): - """UT: nxos module:sendline method - nxapi""" command = "show version" @@ -136,7 +126,6 @@ def test_sendline(): def test_proxy_config(): - """UT: nxos module:proxy_config method - nxapi success path""" commands = ["feature bgp", "router bgp 65535"] @@ -148,7 +137,6 @@ def test_proxy_config(): def test_proxy_config_save_config(): - """UT: nxos module:proxy_config method - nxapi success path""" commands = ["feature bgp", "router bgp 65535"] @@ -160,7 +148,6 @@ def test_proxy_config_save_config(): def test__init_nxapi(): - """UT: nxos module:_init_nxapi method - successful connectinon""" opts = {"proxy": {"arg1": None}} @@ -194,7 +181,6 @@ def test_bad__init_nxapi(): def test__initialized_nxapi(): - """UT: nxos module:_initialized_nxapi method""" result = nxos_proxy._initialized_nxapi() @@ -206,7 +192,6 @@ def test__initialized_nxapi(): def test__ping_nxapi(): - """UT: nxos module:_ping_nxapi method""" result = nxos_proxy._ping_nxapi() @@ -218,7 +203,6 @@ def test__ping_nxapi(): def test__shutdown_nxapi(): - """UT: nxos module:_shutdown_nxapi method""" opts = {"id": "value"} @@ -229,7 +213,6 @@ def test__shutdown_nxapi(): def test__nxapi_request_ssh_return(): - """UT: nxos module:_nxapi_request method - CONNECTION == 'ssh'""" commands = "show version" @@ -240,7 +223,6 @@ def test__nxapi_request_ssh_return(): def test__nxapi_request_connect(): - """UT: nxos module:_nxapi_request method""" commands = "show version" diff --git a/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py b/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py index ef14addbdf9..b6f4f991ad4 100644 --- a/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py +++ b/tests/pytests/unit/proxy/nxos/test_nxos_ssh.py @@ -42,7 +42,6 @@ def configure_loader_modules(): def test_init(): - """UT: nxos module:init method - ssh proxy""" with patch("salt.proxy.nxos._init_ssh", autospec=True) as init_ssh: @@ -51,7 +50,6 @@ def test_init(): def test_init_opts_none(): - """UT: nxos module:init method - __opts__ connection is None""" with patch("salt.proxy.nxos.__opts__", {"proxy": {"connection": None}}): @@ -61,7 +59,6 @@ def test_init_opts_none(): def test_initialized(): - """UT: nxos module:initialized method - ssh proxy""" with patch("salt.proxy.nxos._initialized_ssh", autospec=True) as initialized_ssh: @@ -70,7 +67,6 @@ def test_initialized(): def test_ping(): - """UT: nxos module:ping method - ssh proxy""" with patch("salt.proxy.nxos._ping_ssh", autospec=True) as ping_ssh: @@ -79,7 +75,6 @@ def test_ping(): def test_grains(): - """UT: nxos module:grains method - ssh grains""" with patch( @@ -90,7 +85,6 @@ def test_grains(): def test_sendline(): - """UT: nxos module:sendline method - nxapi""" command = "show version" @@ -101,7 +95,6 @@ def test_sendline(): def test_proxy_config(): - """UT: nxos module:proxy_config method - ssh success path""" commands = ["feature bgp", "router bgp 65535"] @@ -113,7 +106,6 @@ def test_proxy_config(): def test_proxy_config_save_config(): - """UT: nxos module:proxy_config method - ssh success path""" commands = ["feature bgp", "router bgp 65535"] @@ -125,7 +117,6 @@ def test_proxy_config_save_config(): def test_proxy_config_error(): - """UT: nxos module:proxy_config method - CommandExecutionError""" with patch( @@ -156,7 +147,6 @@ def test__init_ssh_device_details(): def test__init_ssh_opts(): - """UT: nxos module:_init_ssh method - successful connectinon""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {}): @@ -174,7 +164,6 @@ def test__init_ssh_opts(): def test__init_ssh_prompt(): - """UT: nxos module:_init_ssh method - prompt regex""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {}): @@ -198,7 +187,6 @@ def test__init_ssh_prompt(): def test__initialized_ssh(): - """UT: nxos module:_initialized_ssh method""" with patch("salt.proxy.nxos.DEVICE_DETAILS", {"initialized": True}): @@ -211,7 +199,6 @@ def test__initialized_ssh(): def test__parse_output_for_errors(): - """UT: nxos module:_parse_output_for_errors method""" data = "% Incomplete command at '^' marker." @@ -246,7 +233,6 @@ def test__parse_output_for_errors(): def test__init_ssh_raise_exception(): - """UT: nxos module:_init_ssh method - raise exception""" class SSHException(Exception): diff --git a/tests/pytests/unit/proxy/test_esxdatacenter.py b/tests/pytests/unit/proxy/test_esxdatacenter.py index bcba6514af5..1142626e675 100644 --- a/tests/pytests/unit/proxy/test_esxdatacenter.py +++ b/tests/pytests/unit/proxy/test_esxdatacenter.py @@ -3,6 +3,7 @@ Tests for esxdatacenter proxy """ + import pytest import salt.exceptions diff --git a/tests/pytests/unit/proxy/test_napalm.py b/tests/pytests/unit/proxy/test_napalm.py index f93279af900..93b849a65a8 100644 --- a/tests/pytests/unit/proxy/test_napalm.py +++ b/tests/pytests/unit/proxy/test_napalm.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import pytest import salt.proxy.napalm as napalm_proxy diff --git a/tests/pytests/unit/renderers/test_aws_kms.py b/tests/pytests/unit/renderers/test_aws_kms.py index 9770531633f..8562d9f3e16 100644 --- a/tests/pytests/unit/renderers/test_aws_kms.py +++ b/tests/pytests/unit/renderers/test_aws_kms.py @@ -1,6 +1,7 @@ """ Unit tests for AWS KMS Decryption Renderer. """ + import pytest import salt.exceptions diff --git a/tests/pytests/unit/returners/test_elasticsearch_return.py b/tests/pytests/unit/returners/test_elasticsearch_return.py index 9b8940bc8f3..8c711d32c97 100644 --- a/tests/pytests/unit/returners/test_elasticsearch_return.py +++ b/tests/pytests/unit/returners/test_elasticsearch_return.py @@ -1,6 +1,7 @@ """ Test the elasticsearch returner """ + import pytest import salt.returners.elasticsearch_return as elasticsearch_return diff --git a/tests/pytests/unit/returners/test_pgjsonb.py b/tests/pytests/unit/returners/test_pgjsonb.py index 92abcddd7a8..d0c2bf83a5c 100644 --- a/tests/pytests/unit/returners/test_pgjsonb.py +++ b/tests/pytests/unit/returners/test_pgjsonb.py @@ -2,7 +2,6 @@ Unit tests for the PGJsonb returner (pgjsonb). """ - import pytest import salt.returners.pgjsonb as pgjsonb diff --git a/tests/pytests/unit/returners/test_slack_webhook_return.py b/tests/pytests/unit/returners/test_slack_webhook_return.py index 0cfc7df00c0..219c3208425 100644 --- a/tests/pytests/unit/returners/test_slack_webhook_return.py +++ b/tests/pytests/unit/returners/test_slack_webhook_return.py @@ -3,6 +3,7 @@ Unit tests for the Slack Webhook Returner. """ + import pytest import salt.returners.slack_webhook_return as slack_webhook @@ -183,9 +184,9 @@ def expected_payload(minion_name, author_icon): "Function: state.apply\nFunction Args: ['config.vim']\nJID:" " 20181227105933129338\nTotal: 4\nDuration: 27.03 secs" ), - "author_link": "{}".format(minion_name), - "author_name": "{}".format(minion_name), - "fallback": "{} | Failed".format(minion_name), + "author_link": f"{minion_name}", + "author_name": f"{minion_name}", + "fallback": f"{minion_name} | Failed", "author_icon": author_icon, }, {"color": "good", "title": "Unchanged: 2"}, @@ -257,7 +258,7 @@ def test_generate_payload_for_state_apply( """ Test _generate_payload private method """ - test_title = "{} | Failed".format(minion_name) + test_title = f"{minion_name} | Failed" test_report = slack_webhook._generate_report(ret, show_tasks) custom_grains = slack_webhook.__grains__ @@ -289,7 +290,7 @@ def test_generate_payload_for_test_ping(minion_name, author_icon, show_tasks): expected_payload = { "attachments": [ { - "fallback": "{} | Succeeded".format(minion_name), + "fallback": f"{minion_name} | Succeeded", "color": "#272727", "author_name": minion_name, "author_link": minion_name, @@ -301,7 +302,7 @@ def test_generate_payload_for_test_ping(minion_name, author_icon, show_tasks): ] } - test_title = "{} | Succeeded".format(minion_name) + test_title = f"{minion_name} | Succeeded" test_report = slack_webhook._generate_report(test_ping_ret, show_tasks) custom_grains = slack_webhook.__grains__ diff --git a/tests/pytests/unit/returners/test_smtp_return.py b/tests/pytests/unit/returners/test_smtp_return.py index 67ad2c877f8..61045bb548b 100644 --- a/tests/pytests/unit/returners/test_smtp_return.py +++ b/tests/pytests/unit/returners/test_smtp_return.py @@ -3,6 +3,7 @@ Test SMTP returner """ + import pytest import salt.returners.smtp_return as smtp diff --git a/tests/pytests/unit/returners/test_syslog_return.py b/tests/pytests/unit/returners/test_syslog_return.py index 8f8de24e18e..64dfca2eef2 100644 --- a/tests/pytests/unit/returners/test_syslog_return.py +++ b/tests/pytests/unit/returners/test_syslog_return.py @@ -3,6 +3,7 @@ :codeauthor: :email:`Megan Wilhite (mwilhite@saltstack.com)` """ + import pytest import salt.returners.syslog_return as syslog @@ -41,4 +42,4 @@ def test_syslog_returner_unicode(): try: syslog.returner(ret) except Exception as e: # pylint: disable=broad-except - pytest.fail("syslog.returner() failed with exception: {}".format(e)) + pytest.fail(f"syslog.returner() failed with exception: {e}") diff --git a/tests/pytests/unit/returners/test_telegram_return.py b/tests/pytests/unit/returners/test_telegram_return.py index 0502b6975a9..23cbec36ea5 100644 --- a/tests/pytests/unit/returners/test_telegram_return.py +++ b/tests/pytests/unit/returners/test_telegram_return.py @@ -3,6 +3,7 @@ :codeauthor: :email:`Roald Nefs (info@roaldnefs.com)` """ + import pytest import salt.returners.telegram_return as telegram diff --git a/tests/pytests/unit/roster/test_dir.py b/tests/pytests/unit/roster/test_dir.py index 72279119357..c99f70f61a0 100644 --- a/tests/pytests/unit/roster/test_dir.py +++ b/tests/pytests/unit/roster/test_dir.py @@ -2,7 +2,6 @@ Test the directory roster. """ - import logging import pytest @@ -111,14 +110,14 @@ def _test_match(ret, expected): assertDictEquals is too strict with OrderedDicts. The order isn't crucial for roster entries, so we test that they contain the expected members directly. """ - assert ret != {}, "Found no matches, expected {}".format(expected) + assert ret != {}, f"Found no matches, expected {expected}" for minion, data in ret.items(): assert minion in expected, "Expected minion {} to match, but it did not".format( minion ) assert ( dict(data) == expected[minion] - ), "Data for minion {} did not match expectations".format(minion) + ), f"Data for minion {minion} did not match expectations" def test_basic_glob(expected, create_roster_files): diff --git a/tests/pytests/unit/roster/test_terraform.py b/tests/pytests/unit/roster/test_terraform.py index b79d7985461..596c5723407 100644 --- a/tests/pytests/unit/roster/test_terraform.py +++ b/tests/pytests/unit/roster/test_terraform.py @@ -1,6 +1,7 @@ """ unittests for terraform roster """ + import pathlib import pytest diff --git a/tests/pytests/unit/runners/test_bgp.py b/tests/pytests/unit/runners/test_bgp.py index 4eeb32538e9..620e162a412 100644 --- a/tests/pytests/unit/runners/test_bgp.py +++ b/tests/pytests/unit/runners/test_bgp.py @@ -1,6 +1,7 @@ """ Test the bgp runner """ + import pytest import salt.runners.bgp as bgp diff --git a/tests/pytests/unit/runners/test_fileserver.py b/tests/pytests/unit/runners/test_fileserver.py index a258ace46ca..b664a56bb44 100644 --- a/tests/pytests/unit/runners/test_fileserver.py +++ b/tests/pytests/unit/runners/test_fileserver.py @@ -2,7 +2,6 @@ unit tests for the fileserver runner """ - import pytest import salt.loader @@ -20,7 +19,7 @@ class DummyFS: self.backends = backends def keys(self): - return ["{}.envs".format(x) for x in self.backends] + return [f"{x}.envs" for x in self.backends] @pytest.fixture diff --git a/tests/pytests/unit/runners/test_git_pillar.py b/tests/pytests/unit/runners/test_git_pillar.py index 958d8372360..9edabb64648 100644 --- a/tests/pytests/unit/runners/test_git_pillar.py +++ b/tests/pytests/unit/runners/test_git_pillar.py @@ -2,7 +2,6 @@ unit tests for the git_pillar runner """ - import logging import pytest diff --git a/tests/pytests/unit/runners/test_jobs.py b/tests/pytests/unit/runners/test_jobs.py index a1146e7f7d0..8d9fe3853a7 100644 --- a/tests/pytests/unit/runners/test_jobs.py +++ b/tests/pytests/unit/runners/test_jobs.py @@ -1,6 +1,7 @@ """ unit tests for the jobs runner """ + import pytest import salt.minion diff --git a/tests/pytests/unit/runners/test_network.py b/tests/pytests/unit/runners/test_network.py index 6d16d54eb94..9531d4ff8e0 100644 --- a/tests/pytests/unit/runners/test_network.py +++ b/tests/pytests/unit/runners/test_network.py @@ -1,6 +1,7 @@ """ Unit tests for Network runner """ + import logging import pytest diff --git a/tests/pytests/unit/runners/test_reactor.py b/tests/pytests/unit/runners/test_reactor.py index 10edc5de289..2b2def3cb65 100644 --- a/tests/pytests/unit/runners/test_reactor.py +++ b/tests/pytests/unit/runners/test_reactor.py @@ -2,7 +2,6 @@ unit tests for the reactor runner """ - import logging import pytest diff --git a/tests/pytests/unit/runners/test_saltutil.py b/tests/pytests/unit/runners/test_saltutil.py index e150dcc9703..f441e36aff2 100644 --- a/tests/pytests/unit/runners/test_saltutil.py +++ b/tests/pytests/unit/runners/test_saltutil.py @@ -115,13 +115,13 @@ def test_sync(module_type, module_sync_functions): sync_out = MagicMock(return_value=[[], True]) with patch("salt.utils.extmods.sync", sync_out) as extmods_sync: ret = saltutil.sync_modules() - func = "sync_{}".format(module_sync_functions[module_type]) + func = f"sync_{module_sync_functions[module_type]}" ret = getattr(saltutil, func)() assert ret == [] extmods_sync.assert_called_with( {}, - "{}".format(module_type), + f"{module_type}", extmod_blacklist=None, extmod_whitelist=None, saltenv="base", diff --git a/tests/pytests/unit/runners/test_spacewalk.py b/tests/pytests/unit/runners/test_spacewalk.py index c6bacd4b117..410b3dc290c 100644 --- a/tests/pytests/unit/runners/test_spacewalk.py +++ b/tests/pytests/unit/runners/test_spacewalk.py @@ -1,6 +1,7 @@ """ Unit tests for Spacewalk runner """ + import salt.runners.spacewalk as spacewalk from tests.support.mock import Mock, call, patch diff --git a/tests/pytests/unit/runners/test_winrepo.py b/tests/pytests/unit/runners/test_winrepo.py index aecdaaf10a4..4245ba453ac 100644 --- a/tests/pytests/unit/runners/test_winrepo.py +++ b/tests/pytests/unit/runners/test_winrepo.py @@ -2,7 +2,6 @@ Test the winrepo runner """ - import textwrap import pytest diff --git a/tests/pytests/unit/runners/vault/test_token_auth_deprecated.py b/tests/pytests/unit/runners/vault/test_token_auth_deprecated.py index feb0af6e9ad..63932911f51 100644 --- a/tests/pytests/unit/runners/vault/test_token_auth_deprecated.py +++ b/tests/pytests/unit/runners/vault/test_token_auth_deprecated.py @@ -5,7 +5,6 @@ This module only tests a deprecated function, see tests/pytests/unit/runners/test_vault.py for the current tests. """ - import logging import pytest diff --git a/tests/pytests/unit/sdb/test_yaml.py b/tests/pytests/unit/sdb/test_yaml.py index 102bf4881b2..d6a505178af 100644 --- a/tests/pytests/unit/sdb/test_yaml.py +++ b/tests/pytests/unit/sdb/test_yaml.py @@ -2,7 +2,6 @@ Test case for the YAML SDB module """ - import salt.sdb.yaml as sdb from tests.support.mock import MagicMock, patch diff --git a/tests/pytests/unit/serializers/test_serializers.py b/tests/pytests/unit/serializers/test_serializers.py index 0f3125c89e3..9721df6c0b4 100644 --- a/tests/pytests/unit/serializers/test_serializers.py +++ b/tests/pytests/unit/serializers/test_serializers.py @@ -153,7 +153,7 @@ def test_compare_sls_vs_yaml_with_jinja(): # BLAAM! yml_src is not valid ! final_obj = OrderedDict(yaml.deserialize(yml_src)) - assert obj != final_obj, "Objects matched! {} == {}".format(obj, final_obj) + assert obj != final_obj, f"Objects matched! {obj} == {final_obj}" @pytest.mark.skipif(yamlex.available is False, reason=SKIP_MESSAGE.format("sls")) diff --git a/tests/pytests/unit/state/test_state_basic.py b/tests/pytests/unit/state/test_state_basic.py index a8a56fba82b..c76a8b950ad 100644 --- a/tests/pytests/unit/state/test_state_basic.py +++ b/tests/pytests/unit/state/test_state_basic.py @@ -1,6 +1,7 @@ """ Test functions in state.py that are not a part of a class """ + import pytest import salt.state diff --git a/tests/pytests/unit/states/apache/test_conf.py b/tests/pytests/unit/states/apache/test_conf.py index 6d5fd04eb19..0a847bfd1c1 100644 --- a/tests/pytests/unit/states/apache/test_conf.py +++ b/tests/pytests/unit/states/apache/test_conf.py @@ -23,18 +23,18 @@ def test_enabled(): apache_conf.__salt__, {"apache.check_conf_enabled": mock, "apache.a2enconf": mock_str}, ): - comt = "{} already enabled.".format(name) + comt = f"{name} already enabled." ret.update({"comment": comt}) assert apache_conf.enabled(name) == ret - comt = "Apache conf {} is set to be enabled.".format(name) + comt = f"Apache conf {name} is set to be enabled." ret.update( {"comment": comt, "result": None, "changes": {"new": name, "old": None}} ) with patch.dict(apache_conf.__opts__, {"test": True}): assert apache_conf.enabled(name) == ret - comt = "Failed to enable {} Apache conf".format(name) + comt = f"Failed to enable {name} Apache conf" ret.update({"comment": comt, "result": False, "changes": {}}) with patch.dict(apache_conf.__opts__, {"test": False}): assert apache_conf.enabled(name) == ret @@ -54,16 +54,16 @@ def test_disabled(): apache_conf.__salt__, {"apache.check_conf_enabled": mock, "apache.a2disconf": mock_str}, ): - comt = "Apache conf {} is set to be disabled.".format(name) + comt = f"Apache conf {name} is set to be disabled." ret.update({"comment": comt, "changes": {"new": None, "old": name}}) with patch.dict(apache_conf.__opts__, {"test": True}): assert apache_conf.disabled(name) == ret - comt = "Failed to disable {} Apache conf".format(name) + comt = f"Failed to disable {name} Apache conf" ret.update({"comment": comt, "result": False, "changes": {}}) with patch.dict(apache_conf.__opts__, {"test": False}): assert apache_conf.disabled(name) == ret - comt = "{} already disabled.".format(name) + comt = f"{name} already disabled." ret.update({"comment": comt, "result": True}) assert apache_conf.disabled(name) == ret diff --git a/tests/pytests/unit/states/apache/test_module.py b/tests/pytests/unit/states/apache/test_module.py index 6edf200a4bc..8a647885fdd 100644 --- a/tests/pytests/unit/states/apache/test_module.py +++ b/tests/pytests/unit/states/apache/test_module.py @@ -27,18 +27,18 @@ def test_enabled(): apache_module.__salt__, {"apache.check_mod_enabled": mock, "apache.a2enmod": mock_str}, ): - comt = "{} already enabled.".format(name) + comt = f"{name} already enabled." ret.update({"comment": comt}) assert apache_module.enabled(name) == ret - comt = "Apache module {} is set to be enabled.".format(name) + comt = f"Apache module {name} is set to be enabled." ret.update( {"comment": comt, "result": None, "changes": {"new": "cgi", "old": None}} ) with patch.dict(apache_module.__opts__, {"test": True}): assert apache_module.enabled(name) == ret - comt = "Failed to enable {} Apache module".format(name) + comt = f"Failed to enable {name} Apache module" ret.update({"comment": comt, "result": False, "changes": {}}) with patch.dict(apache_module.__opts__, {"test": False}): assert apache_module.enabled(name) == ret @@ -58,16 +58,16 @@ def test_disabled(): apache_module.__salt__, {"apache.check_mod_enabled": mock, "apache.a2dismod": mock_str}, ): - comt = "Apache module {} is set to be disabled.".format(name) + comt = f"Apache module {name} is set to be disabled." ret.update({"comment": comt, "changes": {"new": None, "old": "cgi"}}) with patch.dict(apache_module.__opts__, {"test": True}): assert apache_module.disabled(name) == ret - comt = "Failed to disable {} Apache module".format(name) + comt = f"Failed to disable {name} Apache module" ret.update({"comment": comt, "result": False, "changes": {}}) with patch.dict(apache_module.__opts__, {"test": False}): assert apache_module.disabled(name) == ret - comt = "{} already disabled.".format(name) + comt = f"{name} already disabled." ret.update({"comment": comt, "result": True}) assert apache_module.disabled(name) == ret diff --git a/tests/pytests/unit/states/apache/test_site.py b/tests/pytests/unit/states/apache/test_site.py index 881148de493..ed53c53331f 100644 --- a/tests/pytests/unit/states/apache/test_site.py +++ b/tests/pytests/unit/states/apache/test_site.py @@ -23,18 +23,18 @@ def test_enabled(): apache_site.__salt__, {"apache.check_site_enabled": mock, "apache.a2ensite": mock_str}, ): - comt = "{} already enabled.".format(name) + comt = f"{name} already enabled." ret.update({"comment": comt}) assert apache_site.enabled(name) == ret - comt = "Apache site {} is set to be enabled.".format(name) + comt = f"Apache site {name} is set to be enabled." ret.update( {"comment": comt, "result": None, "changes": {"new": name, "old": None}} ) with patch.dict(apache_site.__opts__, {"test": True}): assert apache_site.enabled(name) == ret - comt = "Failed to enable {} Apache site".format(name) + comt = f"Failed to enable {name} Apache site" ret.update({"comment": comt, "result": False, "changes": {}}) with patch.dict(apache_site.__opts__, {"test": False}): assert apache_site.enabled(name) == ret @@ -54,16 +54,16 @@ def test_disabled(): apache_site.__salt__, {"apache.check_site_enabled": mock, "apache.a2dissite": mock_str}, ): - comt = "Apache site {} is set to be disabled.".format(name) + comt = f"Apache site {name} is set to be disabled." ret.update({"comment": comt, "changes": {"new": None, "old": name}}) with patch.dict(apache_site.__opts__, {"test": True}): assert apache_site.disabled(name) == ret - comt = "Failed to disable {} Apache site".format(name) + comt = f"Failed to disable {name} Apache site" ret.update({"comment": comt, "result": False, "changes": {}}) with patch.dict(apache_site.__opts__, {"test": False}): assert apache_site.disabled(name) == ret - comt = "{} already disabled.".format(name) + comt = f"{name} already disabled." ret.update({"comment": comt, "result": True}) assert apache_site.disabled(name) == ret diff --git a/tests/pytests/unit/states/file/test__clean_dir.py b/tests/pytests/unit/states/file/test__clean_dir.py index 43504105a31..7602ba6f93d 100644 --- a/tests/pytests/unit/states/file/test__clean_dir.py +++ b/tests/pytests/unit/states/file/test__clean_dir.py @@ -1,6 +1,7 @@ """ Tests for _clean_dir function """ + import pytest import salt.states.file as file diff --git a/tests/pytests/unit/states/file/test_absent.py b/tests/pytests/unit/states/file/test_absent.py index 62fc16eb6e0..3e0f7dce8ed 100644 --- a/tests/pytests/unit/states/file/test_absent.py +++ b/tests/pytests/unit/states/file/test_absent.py @@ -58,7 +58,7 @@ def test_absent(): assert filestate.absent("") == ret with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.absent(name) == ret @@ -69,7 +69,7 @@ def test_absent(): with patch.object(os.path, "isfile", mock_t): with patch.dict(filestate.__opts__, {"test": True}): - comt = "File {} is set for removal".format(name) + comt = f"File {name} is set for removal" ret.update( { "comment": comt, @@ -82,20 +82,20 @@ def test_absent(): with patch.dict(filestate.__opts__, {"test": False}): with patch.dict(filestate.__salt__, {"file.remove": mock_file}): - comt = "Removed file {}".format(name) + comt = f"Removed file {name}" ret.update( {"comment": comt, "result": True, "changes": {"removed": name}} ) assert filestate.absent(name) == ret - comt = "Removed file {}".format(name) + comt = f"Removed file {name}" ret.update({"comment": "", "result": False, "changes": {}}) assert filestate.absent(name) == ret with patch.object(os.path, "isfile", mock_f): with patch.object(os.path, "isdir", mock_t): with patch.dict(filestate.__opts__, {"test": True}): - comt = "Directory {} is set for removal".format(name) + comt = f"Directory {name} is set for removal" ret.update( {"comment": comt, "changes": {"removed": name}, "result": None} ) @@ -103,7 +103,7 @@ def test_absent(): with patch.dict(filestate.__opts__, {"test": False}): with patch.dict(filestate.__salt__, {"file.remove": mock_tree}): - comt = "Removed directory {}".format(name) + comt = f"Removed directory {name}" ret.update( { "comment": comt, @@ -113,12 +113,12 @@ def test_absent(): ) assert filestate.absent(name) == ret - comt = "Failed to remove directory {}".format(name) + comt = f"Failed to remove directory {name}" ret.update({"comment": comt, "result": False, "changes": {}}) assert filestate.absent(name) == ret with patch.object(os.path, "isdir", mock_f): with patch.dict(filestate.__opts__, {"test": True}): - comt = "File {} is not present".format(name) + comt = f"File {name} is not present" ret.update({"comment": comt, "result": True}) assert filestate.absent(name) == ret diff --git a/tests/pytests/unit/states/file/test_comment.py b/tests/pytests/unit/states/file/test_comment.py index 0eefd36d041..6ef8b72de28 100644 --- a/tests/pytests/unit/states/file/test_comment.py +++ b/tests/pytests/unit/states/file/test_comment.py @@ -59,7 +59,7 @@ def test_comment(): mock_t = MagicMock(return_value=True) mock_f = MagicMock(return_value=False) with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.comment(name, regex) == ret @@ -80,7 +80,7 @@ def test_comment(): ret.update({"comment": comt, "result": True}) assert filestate.comment(name, regex, ignore_missing=True) == ret - comt = "{}: Pattern not found".format(regex) + comt = f"{regex}: Pattern not found" ret.update({"comment": comt, "result": False}) assert filestate.comment(name, regex) == ret @@ -95,7 +95,7 @@ def test_comment(): }, ): with patch.dict(filestate.__opts__, {"test": True}): - comt = "File {} is set to be updated".format(name) + comt = f"File {name} is set to be updated" ret.update( {"comment": comt, "result": None, "changes": {name: "updated"}} ) @@ -134,7 +134,7 @@ def test_uncomment(): mock_f = MagicMock(return_value=False) mock = MagicMock(side_effect=[False, True, False, False, True, True, True]) with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.uncomment(name, regex) == ret @@ -151,12 +151,12 @@ def test_uncomment(): ret.update({"comment": comt, "result": True}) assert filestate.uncomment(name, regex) == ret - comt = "{}: Pattern not found".format(regex) + comt = f"{regex}: Pattern not found" ret.update({"comment": comt, "result": False}) assert filestate.uncomment(name, regex) == ret with patch.dict(filestate.__opts__, {"test": True}): - comt = "File {} is set to be updated".format(name) + comt = f"File {name} is set to be updated" ret.update( {"comment": comt, "result": None, "changes": {name: "updated"}} ) diff --git a/tests/pytests/unit/states/file/test_copy.py b/tests/pytests/unit/states/file/test_copy.py index d7becf580c8..291d28b4716 100644 --- a/tests/pytests/unit/states/file/test_copy.py +++ b/tests/pytests/unit/states/file/test_copy.py @@ -66,13 +66,13 @@ def test_copy(tmp_path): mock_grp = MagicMock(return_value=group) mock_io = MagicMock(side_effect=IOError) with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.copy_(name, source) == ret with patch.object(os.path, "isabs", mock_t): with patch.object(os.path, "exists", mock_f): - comt = 'Source file "{}" is not present'.format(source) + comt = f'Source file "{source}" is not present' ret.update({"comment": comt, "result": False}) assert filestate.copy_(name, source) == ret @@ -106,7 +106,7 @@ def test_copy(tmp_path): 'The target file "{}" exists and will not be ' "overwritten".format(name) ) - comt3 = 'File "{}" is set to be copied to "{}"'.format(source, name) + comt3 = f'File "{source}" is set to be copied to "{name}"' with patch.object(os.path, "isdir", mock_f): with patch.object(os.path, "lexists", mock_t): with patch.dict(filestate.__opts__, {"test": False}): @@ -165,7 +165,7 @@ def test_copy(tmp_path): }, ): - comt = 'Copied "{}" to "{}"'.format(source, name) + comt = f'Copied "{source}" to "{name}"' with patch.dict(filestate.__opts__, {"user": "salt"}), patch.object( os.path, "isdir", mock_t ), patch.object(os.path, "lexists", mock_f), patch.dict( @@ -186,7 +186,7 @@ def test_copy(tmp_path): res = filestate.copy_(name, source, group=group, preserve=False) assert res == ret - comt = 'Copied "{}" to "{}"'.format(source, name) + comt = f'Copied "{source}" to "{name}"' with patch.dict(filestate.__opts__, {"user": "salt"}), patch.object( os.path, "isdir", MagicMock(side_effect=[False, True, False]) ), patch.object(os.path, "lexists", mock_f), patch.dict( diff --git a/tests/pytests/unit/states/file/test_directory.py b/tests/pytests/unit/states/file/test_directory.py index 042ecc9e61f..1474e4eee1a 100644 --- a/tests/pytests/unit/states/file/test_directory.py +++ b/tests/pytests/unit/states/file/test_directory.py @@ -104,7 +104,7 @@ def test_directory(): mock_check = MagicMock( return_value=( None, - 'The directory "{}" will be changed'.format(name), + f'The directory "{name}" will be changed', {name: {"directory": "new"}}, ) ) @@ -132,7 +132,7 @@ def test_directory(): assert filestate.directory(name, user=user, group=group) == ret with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt}) assert filestate.directory(name, user=user, group=group) == ret @@ -153,12 +153,12 @@ def test_directory(): ) with patch.object(os.path, "isfile", mock_t): - comt = "Specified location {} exists and is a file".format(name) + comt = f"Specified location {name} exists and is a file" ret.update({"comment": comt}) assert filestate.directory(name, user=user, group=group) == ret with patch.object(os.path, "islink", mock_t): - comt = "Specified location {} exists and is a symlink".format(name) + comt = f"Specified location {name} exists and is a symlink" ret.update({"comment": comt}) assert filestate.directory(name, user=user, group=group) == ret @@ -182,7 +182,7 @@ def test_directory(): with patch.dict(filestate.__opts__, {"test": False}): with patch.object(os.path, "isdir", mock_f): - comt = "No directory to create {} in".format(name) + comt = f"No directory to create {name} in" ret.update({"comment": comt, "result": False}) assert filestate.directory(name, user=user, group=group) == ret @@ -193,7 +193,7 @@ def test_directory(): with patch.object( os.path, "isdir", MagicMock(side_effect=isdir_side_effect) ): - comt = "Failed to create directory {}".format(name) + comt = f"Failed to create directory {name}" ret.update( { "comment": comt, @@ -266,7 +266,7 @@ def test_directory(): == ret ) - comt = "Directory {} updated".format(name) + comt = f"Directory {name} updated" ret = { "name": name, "result": True, diff --git a/tests/pytests/unit/states/file/test_filestate.py b/tests/pytests/unit/states/file/test_filestate.py index f7daf51b5a6..0d0f95f8985 100644 --- a/tests/pytests/unit/states/file/test_filestate.py +++ b/tests/pytests/unit/states/file/test_filestate.py @@ -131,7 +131,7 @@ def test_contents_and_contents_pillar(): def test_contents_pillar_doesnt_add_more_newlines(): # make sure the newline - pillar_value = "i am the pillar value{}".format(os.linesep) + pillar_value = f"i am the pillar value{os.linesep}" returner = MagicMock(return_value=None) path = "/tmp/foo" @@ -182,12 +182,12 @@ def test_exists(): assert filestate.exists("") == ret with patch.object(os.path, "exists", mock_f): - comt = "Specified path {} does not exist".format(name) + comt = f"Specified path {name} does not exist" ret.update({"comment": comt, "name": name}) assert filestate.exists(name) == ret with patch.object(os.path, "exists", mock_t): - comt = "Path {} exists".format(name) + comt = f"Path {name} exists" ret.update({"comment": comt, "result": True}) assert filestate.exists(name) == ret @@ -209,12 +209,12 @@ def test_missing(): assert filestate.missing("") == ret with patch.object(os.path, "exists", mock_t): - comt = "Specified path {} exists".format(name) + comt = f"Specified path {name} exists" ret.update({"comment": comt, "name": name}) assert filestate.missing(name) == ret with patch.object(os.path, "exists", mock_f): - comt = "Path {} is missing".format(name) + comt = f"Path {name} is missing" ret.update({"comment": comt, "result": True}) assert filestate.missing(name) == ret @@ -271,7 +271,7 @@ def test_recurse(): assert filestate.recurse(name, source, user=user, group=group) == ret with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt}) assert filestate.recurse(name, source) == ret @@ -297,12 +297,12 @@ def test_recurse(): with patch.object(os.path, "isdir", mock_f): with patch.object(os.path, "exists", mock_t): - comt = "The path {} exists and is not a directory".format(name) + comt = f"The path {name} exists and is not a directory" ret.update({"comment": comt}) assert filestate.recurse(name, source) == ret with patch.object(os.path, "isdir", mock_t): - comt = "The directory {} is in the correct state".format(name) + comt = f"The directory {name} is in the correct state" ret.update({"comment": comt, "result": True}) assert filestate.recurse(name, source) == ret @@ -325,7 +325,7 @@ def test_replace(): mock_t = MagicMock(return_value=True) mock_f = MagicMock(return_value=False) with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.replace(name, pattern, repl) == ret @@ -356,7 +356,7 @@ def test_blockreplace(): mock_t = MagicMock(return_value=True) mock_f = MagicMock(return_value=False) with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.blockreplace(name) == ret @@ -389,26 +389,26 @@ def test_touch(): mock_t = MagicMock(return_value=True) mock_f = MagicMock(return_value=False) with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "name": name}) assert filestate.touch(name) == ret with patch.object(os.path, "isabs", mock_t): with patch.object(os.path, "exists", mock_f): with patch.dict(filestate.__opts__, {"test": True}): - comt = "File {} is set to be created".format(name) + comt = f"File {name} is set to be created" ret.update({"comment": comt, "result": None, "changes": {"new": name}}) assert filestate.touch(name) == ret with patch.dict(filestate.__opts__, {"test": False}): with patch.object(os.path, "isdir", mock_f): - comt = "Directory not present to touch file {}".format(name) + comt = f"Directory not present to touch file {name}" ret.update({"comment": comt, "result": False, "changes": {}}) assert filestate.touch(name) == ret with patch.object(os.path, "isdir", mock_t): with patch.dict(filestate.__salt__, {"file.touch": mock_t}): - comt = "Created empty file {}".format(name) + comt = f"Created empty file {name}" ret.update( {"comment": comt, "result": True, "changes": {"new": name}} ) @@ -482,7 +482,7 @@ def test_serialize_into_managed_file(): mock_t = MagicMock(return_value=True) mock_f = MagicMock(return_value=False) with patch.object(os.path, "isfile", mock_f): - comt = "File {} is not present and is not set for creation".format(name) + comt = f"File {name} is not present and is not set for creation" ret.update({"comment": comt, "name": name, "result": True}) assert filestate.serialize(name, create=False) == ret @@ -516,7 +516,7 @@ def test_serialize_into_managed_file(): # __opts__['test']=True with changes with patch.dict(filestate.__salt__, {"file.check_managed_changes": mock_changes}): with patch.dict(filestate.__opts__, {"test": True}): - comt = "Dataset will be serialized and stored into {}".format(name) + comt = f"Dataset will be serialized and stored into {name}" ret.update({"comment": comt, "result": None, "changes": True}) assert filestate.serialize(name, dataset=True, formatter="python") == ret @@ -525,14 +525,14 @@ def test_serialize_into_managed_file(): filestate.__salt__, {"file.check_managed_changes": mock_no_changes} ): with patch.dict(filestate.__opts__, {"test": True}): - comt = "The file {} is in the correct state".format(name) + comt = f"The file {name} is in the correct state" ret.update({"comment": comt, "result": True, "changes": False}) assert filestate.serialize(name, dataset=True, formatter="python") == ret mock = MagicMock(return_value=ret) with patch.dict(filestate.__opts__, {"test": False}): with patch.dict(filestate.__salt__, {"file.manage_file": mock}): - comt = "Dataset will be serialized and stored into {}".format(name) + comt = f"Dataset will be serialized and stored into {name}" ret.update({"comment": comt, "result": None}) assert filestate.serialize(name, dataset=True, formatter="python") == ret diff --git a/tests/pytests/unit/states/file/test_hardlink.py b/tests/pytests/unit/states/file/test_hardlink.py index 901cae3a4b0..ea0f9a131c0 100644 --- a/tests/pytests/unit/states/file/test_hardlink.py +++ b/tests/pytests/unit/states/file/test_hardlink.py @@ -94,7 +94,7 @@ def test_hardlink(tmp_path): ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}), patch.object( os.path, "isabs", mock_t ): - expected = "User {} does not exist".format(user) + expected = f"User {user} does not exist" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -104,7 +104,7 @@ def test_hardlink(tmp_path): ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_empty}), patch.object( os.path, "isabs", mock_t ): - expected = "Group {} does not exist".format(group) + expected = f"Group {group} does not exist" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -113,7 +113,7 @@ def test_hardlink(tmp_path): with patch.dict(filestate.__salt__, patches), patch.dict( filestate.__salt__, {"file.user_to_uid": mock_uid} ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}): - expected = "Specified file {} is not an absolute path".format(nonabs) + expected = f"Specified file {nonabs} is not an absolute path" ret = return_val(comment=expected, name=nonabs) assert filestate.hardlink(nonabs, target, user=user, group=group) == ret @@ -121,7 +121,7 @@ def test_hardlink(tmp_path): with patch.dict(filestate.__salt__, patches), patch.dict( filestate.__salt__, {"file.user_to_uid": mock_uid} ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}): - expected = "Specified target {} is not an absolute path".format(nonabs) + expected = f"Specified target {nonabs} is not an absolute path" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, nonabs, user=user, group=group) == ret # Test option -- nonexistent target @@ -132,7 +132,7 @@ def test_hardlink(tmp_path): ), patch.dict( filestate.__opts__, {"test": True} ): - expected = "Target {} for hard link does not exist".format(target) + expected = f"Target {target} for hard link does not exist" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -144,7 +144,7 @@ def test_hardlink(tmp_path): ), patch.dict( filestate.__opts__, {"test": True} ): - expected = "Unable to hard link from directory {}".format(test_dir) + expected = f"Unable to hard link from directory {test_dir}" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, test_dir, user=user, group=group) == ret @@ -154,7 +154,7 @@ def test_hardlink(tmp_path): ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}), patch.dict( filestate.__opts__, {"test": True} ): - expected = "Unable to hard link to directory {}".format(test_dir) + expected = f"Unable to hard link to directory {test_dir}" ret = return_val(comment=expected, name=test_dir) assert filestate.hardlink(test_dir, target, user=user, group=group) == ret @@ -164,7 +164,7 @@ def test_hardlink(tmp_path): ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}), patch.dict( filestate.__opts__, {"test": True} ): - expected = "Hard link {} to {} is set for creation".format(name, target) + expected = f"Hard link {name} to {target} is set for creation" changes = dict(new=name) ret = return_val(result=None, comment=expected, name=name, changes=changes) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -181,7 +181,7 @@ def test_hardlink(tmp_path): ), patch.dict( filestate.__opts__, {"test": True} ): - expected = "The hard link {} is presently targetting {}".format(name, target) + expected = f"The hard link {name} is presently targetting {target}" ret = return_val(result=True, comment=expected, name=name) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -197,7 +197,7 @@ def test_hardlink(tmp_path): ), patch.dict( filestate.__opts__, {"test": True} ): - expected = "Link {} target is set to be changed to {}".format(name, target) + expected = f"Link {name} target is set to be changed to {target}" changes = dict(change=name) ret = return_val(result=None, comment=expected, name=name, changes=changes) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -244,7 +244,7 @@ def test_hardlink(tmp_path): with patch.dict(filestate.__salt__, patches), patch.dict( filestate.__salt__, {"file.user_to_uid": mock_uid} ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}): - expected = "Unable to hard link from directory {}".format(test_dir) + expected = f"Unable to hard link from directory {test_dir}" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, test_dir, user=user, group=group) == ret @@ -252,7 +252,7 @@ def test_hardlink(tmp_path): with patch.dict(filestate.__salt__, patches), patch.dict( filestate.__salt__, {"file.user_to_uid": mock_uid} ), patch.dict(filestate.__salt__, {"file.group_to_gid": mock_gid}): - expected = "Unable to hard link to directory {}".format(test_dir) + expected = f"Unable to hard link to directory {test_dir}" ret = return_val(comment=expected, name=test_dir) assert filestate.hardlink(test_dir, target, user=user, group=group) == ret @@ -265,7 +265,7 @@ def test_hardlink(tmp_path): os.path, "isfile", mock_t ): - expected = "File exists where the hard link {} should be".format(name) + expected = f"File exists where the hard link {name} should be" ret = return_val(comment=expected, name=name) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -301,7 +301,7 @@ def test_hardlink(tmp_path): os.path, "isfile", mock_f ): - expected = "Set target of hard link {} -> {}".format(name, target) + expected = f"Set target of hard link {name} -> {target}" changes = dict(new=name) ret = return_val(result=True, comment=expected, name=name, changes=changes) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -342,7 +342,7 @@ def test_hardlink(tmp_path): os.path, "isfile", mock_f ): - expected = "Created new hard link {} -> {}".format(name, target) + expected = f"Created new hard link {name} -> {target}" changes = dict(new=name) ret = return_val(result=True, comment=expected, name=name, changes=changes) assert filestate.hardlink(name, target, user=user, group=group) == ret @@ -383,7 +383,7 @@ def test_hardlink(tmp_path): os.path, "isfile", mock_t ): - expected = "Created new hard link {} -> {}".format(name, target) + expected = f"Created new hard link {name} -> {target}" changes = dict(new=name) changes["forced"] = "File for hard link was forcibly replaced" ret = return_val(result=True, comment=expected, name=name, changes=changes) @@ -437,7 +437,7 @@ def test_hardlink(tmp_path): ): group = None - expected = "Created new hard link {} -> {}".format(name, target) + expected = f"Created new hard link {name} -> {target}" changes = dict(new=name) ret = return_val(result=True, comment=expected, name=name, changes=changes) assert filestate.hardlink(name, target, user=user, group=group) == ret diff --git a/tests/pytests/unit/states/file/test_managed.py b/tests/pytests/unit/states/file/test_managed.py index 4a826c26869..fc303d34139 100644 --- a/tests/pytests/unit/states/file/test_managed.py +++ b/tests/pytests/unit/states/file/test_managed.py @@ -179,7 +179,7 @@ def test_managed(): assert filestate.managed("") == ret with patch.object(os.path, "isfile", mock_f): - comt = "File {} is not present and is not set for creation".format(name) + comt = f"File {name} is not present and is not set for creation" ret.update({"comment": comt, "name": name, "result": True}) assert filestate.managed(name, create=False) == ret @@ -193,13 +193,13 @@ def test_managed(): assert filestate.managed(name, user=user, group=group) == ret with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "result": False}) assert filestate.managed(name, user=user, group=group) == ret with patch.object(os.path, "isabs", mock_t): with patch.object(os.path, "isdir", mock_t): - comt = "Specified target {} is a directory".format(name) + comt = f"Specified target {name} is a directory" ret.update({"comment": comt}) assert filestate.managed(name, user=user, group=group) == ret @@ -237,7 +237,7 @@ def test_managed(): with patch.object(os.path, "exists", mock_t): with patch.dict(filestate.__opts__, {"test": True}): - comt = "File {} not updated".format(name) + comt = f"File {name} not updated" ret.update({"comment": comt}) assert ( filestate.managed( @@ -246,7 +246,7 @@ def test_managed(): == ret ) - comt = "The file {} is in the correct state".format(name) + comt = f"The file {name} is in the correct state" ret.update({"comment": comt, "result": True}) assert ( filestate.managed( @@ -324,7 +324,7 @@ def test_managed(): if salt.utils.platform.is_windows(): mock_ret = MagicMock(return_value=ret) - comt = "File {} not updated".format(name) + comt = f"File {name} not updated" else: perms = {"luser": user, "lmode": "0644", "lgroup": group} mock_ret = MagicMock(return_value=(ret, perms)) @@ -359,7 +359,7 @@ def test_managed(): else: perms = {"luser": user, "lmode": "0644", "lgroup": group} mock_ret = MagicMock(return_value=(ret, perms)) - comt = "File {} not updated".format(name) + comt = f"File {name} not updated" with patch.dict(filestate.__salt__, {"file.check_perms": mock_ret}): with patch.object(os.path, "exists", mock_t): with patch.dict(filestate.__opts__, {"test": True}): diff --git a/tests/pytests/unit/states/file/test_prepend.py b/tests/pytests/unit/states/file/test_prepend.py index e0b4edb8d99..db528519ec0 100644 --- a/tests/pytests/unit/states/file/test_prepend.py +++ b/tests/pytests/unit/states/file/test_prepend.py @@ -86,13 +86,13 @@ def test_prepend(): assert filestate.prepend(name, makedirs=True) == ret with patch.object(os.path, "isabs", mock_f): - comt = "Specified file {} is not an absolute path".format(name) + comt = f"Specified file {name} is not an absolute path" ret.update({"comment": comt, "changes": {}}) assert filestate.prepend(name) == ret with patch.object(os.path, "isabs", mock_t): with patch.object(os.path, "exists", mock_t): - comt = "Failed to load template file {}".format(source) + comt = f"Failed to load template file {source}" ret.update({"comment": comt, "name": source, "data": []}) assert filestate.prepend(name, source=source) == ret @@ -104,7 +104,7 @@ def test_prepend(): with patch.dict(filestate.__utils__, {"files.is_text": mock_f}): with patch.dict(filestate.__opts__, {"test": True}): change = {"diff": "Replace binary file"} - comt = "File {} is set to be updated".format(name) + comt = f"File {name} is set to be updated" ret.update( {"comment": comt, "result": None, "changes": change} ) diff --git a/tests/pytests/unit/states/file/test_private_functions.py b/tests/pytests/unit/states/file/test_private_functions.py index b3fc7cbbe65..b2fa9059afb 100644 --- a/tests/pytests/unit/states/file/test_private_functions.py +++ b/tests/pytests/unit/states/file/test_private_functions.py @@ -37,7 +37,7 @@ def test__check_directory(tmp_path): def create_files(tmp_dir): for f in range(depth): - path = os.path.join(tmp_dir, "file_{:03}.txt".format(f)) + path = os.path.join(tmp_dir, f"file_{f:03}.txt") with salt.utils.files.fopen(path, "w+"): os.chmod(path, expected_mode) @@ -47,12 +47,12 @@ def test__check_directory(tmp_path): create_files(root_tmp_dir) for d in range(depth): - dir_name = os.path.join(root_tmp_dir, "dir{:03}".format(d)) + dir_name = os.path.join(root_tmp_dir, f"dir{d:03}") os.mkdir(dir_name) os.chmod(dir_name, expected_mode) create_files(dir_name) for s in range(depth): - sub_dir_name = os.path.join(dir_name, "dir{:03}".format(s)) + sub_dir_name = os.path.join(dir_name, f"dir{s:03}") os.mkdir(sub_dir_name) os.chmod(sub_dir_name, expected_mode) create_files(sub_dir_name) diff --git a/tests/pytests/unit/states/file/test_pruned.py b/tests/pytests/unit/states/file/test_pruned.py index 7afc8eadeb9..c57789ffe5b 100644 --- a/tests/pytests/unit/states/file/test_pruned.py +++ b/tests/pytests/unit/states/file/test_pruned.py @@ -28,7 +28,7 @@ def test_pruned_clean(directory_name): ret = filestate.pruned(name=directory_name) assert ret == { "changes": {}, - "comment": "Directory {} is not present".format(directory_name), + "comment": f"Directory {directory_name} is not present", "name": directory_name, "result": True, } @@ -41,7 +41,7 @@ def test_pruned_test(directory_name): ret = filestate.pruned(name=directory_name) assert ret == { "changes": {"deleted": directory_name}, - "comment": "Directory {} is set for removal".format(directory_name), + "comment": f"Directory {directory_name} is set for removal", "name": directory_name, "result": None, } @@ -55,7 +55,7 @@ def test_pruned_success(directory_name): ret = filestate.pruned(name=directory_name) assert ret == { "changes": {"deleted": directory_name}, - "comment": "Removed directory {}".format(directory_name), + "comment": f"Removed directory {directory_name}", "name": directory_name, "result": True, } diff --git a/tests/pytests/unit/states/file/test_retention_schedule.py b/tests/pytests/unit/states/file/test_retention_schedule.py index 3e9179afcbf..7fd57195a25 100644 --- a/tests/pytests/unit/states/file/test_retention_schedule.py +++ b/tests/pytests/unit/states/file/test_retention_schedule.py @@ -209,16 +209,14 @@ def test_retention_schedule(): } if test: expected_ret["result"] = None - expected_ret[ - "comment" - ] = "{} backups would have been removed from {}.\n" "".format( - len(deleted_files), fake_name + expected_ret["comment"] = ( + "{} backups would have been removed from {}.\n" + "".format(len(deleted_files), fake_name) ) else: - expected_ret[ - "comment" - ] = "{} backups were removed from {}.\n" "".format( - len(deleted_files), fake_name + expected_ret["comment"] = ( + "{} backups were removed from {}.\n" + "".format(len(deleted_files), fake_name) ) mock_remove.assert_has_calls( [call(os.path.join(fake_name, x)) for x in deleted_files], diff --git a/tests/pytests/unit/states/file/test_selinux.py b/tests/pytests/unit/states/file/test_selinux.py index 707f69f4d7f..54a781d4636 100644 --- a/tests/pytests/unit/states/file/test_selinux.py +++ b/tests/pytests/unit/states/file/test_selinux.py @@ -32,7 +32,7 @@ def test_selinux_change(): file_name = "/tmp/some-test-file" check_perms_result = [ { - "comment": "The file {} is set to be changed".format(file_name), + "comment": f"The file {file_name} is set to be changed", "changes": { "selinux": { "New": "User: unconfined_u Type: lost_found_t", diff --git a/tests/pytests/unit/states/file/test_symlink.py b/tests/pytests/unit/states/file/test_symlink.py index da2e0b7adc3..4b05b1521bb 100644 --- a/tests/pytests/unit/states/file/test_symlink.py +++ b/tests/pytests/unit/states/file/test_symlink.py @@ -91,7 +91,7 @@ def test_symlink(): }, ): if salt.utils.platform.is_windows(): - comt = "User {} does not exist".format(user) + comt = f"User {user} does not exist" ret = return_val({"comment": comt, "name": name}) else: comt = "User {} does not exist. Group {} does not exist.".format( @@ -114,12 +114,12 @@ def test_symlink(): os.path, "exists", mock_f ): if salt.utils.platform.is_windows(): - comt = "User {} does not exist".format(user) + comt = f"User {user} does not exist" ret = return_val( {"comment": comt, "result": False, "name": name, "changes": {}} ) else: - comt = "Symlink {} to {} is set for creation".format(name, target) + comt = f"Symlink {name} to {target} is set for creation" ret = return_val( {"comment": comt, "result": None, "changes": {"new": name}} ) @@ -141,12 +141,12 @@ def test_symlink(): os.path, "exists", mock_f ): if salt.utils.platform.is_windows(): - comt = "User {} does not exist".format(user) + comt = f"User {user} does not exist" ret = return_val( {"comment": comt, "result": False, "name": name, "changes": {}} ) else: - comt = "Directory {} for symlink is not present".format(test_dir) + comt = f"Directory {test_dir} for symlink is not present" ret = return_val({"comment": comt, "result": False, "changes": {}}) assert filestate.symlink(name, target, user=user, group=group) == ret @@ -169,9 +169,9 @@ def test_symlink(): "salt.utils.win_functions.get_sid_from_name", return_value="test-sid" ): if salt.utils.platform.is_windows(): - comt = "Symlink {} is present and owned by {}".format(name, user) + comt = f"Symlink {name} is present and owned by {user}" else: - comt = "Symlink {} is present and owned by {}:{}".format(name, user, group) + comt = f"Symlink {name} is present and owned by {user}:{group}" ret = return_val({"comment": comt, "result": True, "changes": {}}) assert filestate.symlink(name, target, user=user, group=group) == ret @@ -256,7 +256,7 @@ def test_symlink(): ), patch( "salt.utils.win_functions.get_sid_from_name", return_value="test-sid" ): - comt = "File exists where the symlink {} should be".format(name) + comt = f"File exists where the symlink {name} should be" ret = return_val({"comment": comt, "changes": {}, "result": False}) assert filestate.symlink(name, target, user=user, group=group) == ret @@ -281,7 +281,7 @@ def test_symlink(): ), patch( "salt.utils.win_functions.get_sid_from_name", return_value="test-sid" ): - comt = "Directory exists where the symlink {} should be".format(name) + comt = f"Directory exists where the symlink {name} should be" ret = return_val({"comment": comt, "result": False, "changes": {}}) assert filestate.symlink(name, target, user=user, group=group) == ret @@ -304,7 +304,7 @@ def test_symlink(): ), patch( "salt.utils.win_functions.get_sid_from_name", return_value="test-sid" ): - comt = "Unable to create new symlink {} -> {}: ".format(name, target) + comt = f"Unable to create new symlink {name} -> {target}: " ret = return_val({"comment": comt, "result": False, "changes": {}}) assert filestate.symlink(name, target, user=user, group=group) == ret @@ -331,7 +331,7 @@ def test_symlink(): ), patch( "salt.utils.win_functions.get_sid_from_name", return_value="test-sid" ): - comt = "Created new symlink {} -> {}".format(name, target) + comt = f"Created new symlink {name} -> {target}" ret = return_val({"comment": comt, "result": True, "changes": {"new": name}}) assert filestate.symlink(name, target, user=user, group=group) == ret @@ -392,7 +392,7 @@ def test_symlink(): ), patch( "salt.states.file._check_symlink_ownership", return_value=True ): - comt = "Created new symlink {} -> {}".format(name, target) + comt = f"Created new symlink {name} -> {target}" ret = return_val({"comment": comt, "result": True, "changes": {"new": name}}) res = filestate.symlink(name, target, user=user, group=user) assert res == ret @@ -423,9 +423,9 @@ def test_symlink(): "salt.states.file._get_symlink_ownership", return_value=(user, group) ): if salt.utils.platform.is_windows(): - comt = "Symlink {} is present and owned by {}".format(name, user) + comt = f"Symlink {name} is present and owned by {user}" else: - comt = "Symlink {} is present and owned by {}:{}".format(name, user, group) + comt = f"Symlink {name} is present and owned by {user}:{group}" ret = return_val({"comment": comt, "result": True, "changes": {}}) res = filestate.symlink(name, target, inherit_user_and_group=True) assert res == ret diff --git a/tests/pytests/unit/states/file/test_tidied.py b/tests/pytests/unit/states/file/test_tidied.py index e31e33293e6..0139cd3ac76 100644 --- a/tests/pytests/unit/states/file/test_tidied.py +++ b/tests/pytests/unit/states/file/test_tidied.py @@ -76,7 +76,7 @@ def test__tidied(): ] }, "result": True, - "comment": "Removed 3 files or directories from directory {}".format(name), + "comment": f"Removed 3 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 3 @@ -107,7 +107,7 @@ def test__tidied(): ] }, "result": True, - "comment": "Removed 6 files or directories from directory {}".format(name), + "comment": f"Removed 6 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 6 @@ -192,7 +192,7 @@ def test_tidied_with_exclude(): ] }, "result": True, - "comment": "Removed 2 files or directories from directory {}".format(name), + "comment": f"Removed 2 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 2 @@ -220,7 +220,7 @@ def test_tidied_with_exclude(): ] }, "result": True, - "comment": "Removed 5 files or directories from directory {}".format(name), + "comment": f"Removed 5 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 5 @@ -256,7 +256,7 @@ def test_tidied_with_exclude(): ] }, "result": True, - "comment": "Removed 6 files or directories from directory {}".format(name), + "comment": f"Removed 6 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 6 @@ -328,7 +328,7 @@ def test_tidied_with_full_path_exclude(): ] }, "result": True, - "comment": "Removed 2 files or directories from directory {}".format(name), + "comment": f"Removed 2 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 2 @@ -361,7 +361,7 @@ def test_tidied_with_full_path_exclude(): ] }, "result": True, - "comment": "Removed 5 files or directories from directory {}".format(name), + "comment": f"Removed 5 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 5 @@ -395,7 +395,7 @@ def test_tidied_with_full_path_exclude(): ] }, "result": True, - "comment": "Removed 6 files or directories from directory {}".format(name), + "comment": f"Removed 6 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 6 @@ -436,7 +436,7 @@ def test_tidied_age_size_args_AND_operator_age_not_size(): "name": name, "changes": {}, "result": True, - "comment": "Nothing to remove from directory {}".format(name), + "comment": f"Nothing to remove from directory {name}", } assert ret == exp assert remove.call_count == 0 @@ -500,7 +500,7 @@ def test_tidied_age_size_args_AND_operator_age_not_size_age_only(): ] }, "result": True, - "comment": "Removed 3 files or directories from directory {}".format(name), + "comment": f"Removed 3 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 3 @@ -541,7 +541,7 @@ def test_tidied_age_size_args_AND_operator_size_not_age(): "name": name, "changes": {}, "result": True, - "comment": "Nothing to remove from directory {}".format(name), + "comment": f"Nothing to remove from directory {name}", } assert ret == exp assert remove.call_count == 0 @@ -605,7 +605,7 @@ def test_tidied_age_size_args_AND_operator_size_not_age_size_only(): ] }, "result": True, - "comment": "Removed 3 files or directories from directory {}".format(name), + "comment": f"Removed 3 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 3 @@ -669,7 +669,7 @@ def test_tidied_age_size_args_AND_operator_size_and_age(): ] }, "result": True, - "comment": "Removed 3 files or directories from directory {}".format(name), + "comment": f"Removed 3 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 3 @@ -698,7 +698,7 @@ def test_tidied_filenotfound(tmp_path): "name": name, "changes": {}, "result": True, - "comment": "Nothing to remove from directory {}".format(name), + "comment": f"Nothing to remove from directory {name}", } assert ret == exp @@ -764,7 +764,7 @@ def test_tidied_rmlinks(): ] }, "result": True, - "comment": "Removed 2 files or directories from directory {}".format(name), + "comment": f"Removed 2 files or directories from directory {name}", } assert ret == exp assert remove.call_count == 2 diff --git a/tests/pytests/unit/states/mysql/test_database.py b/tests/pytests/unit/states/mysql/test_database.py index 4176d85fb88..d9a76f6d281 100644 --- a/tests/pytests/unit/states/mysql/test_database.py +++ b/tests/pytests/unit/states/mysql/test_database.py @@ -1,6 +1,7 @@ """ This test checks mysql_database salt state """ + import pytest import salt.states.mysql_database as mysql_database @@ -48,7 +49,7 @@ def test_present(): "Database character set {} != {} needs to be updated".format( mod_charset, charset ), - "Database {} is going to be updated".format(dbname), + f"Database {dbname} is going to be updated", ] ret.update({"comment": "\n".join(comt)}) ret.update({"result": None}) @@ -56,7 +57,7 @@ def test_present(): with patch.dict(mysql_database.__opts__, {"test": True}): comt = [ - "Database {} is already present".format(dbname), + f"Database {dbname} is already present", "Database collate {} != {} needs to be updated".format( mod_collate, collate ), @@ -89,7 +90,7 @@ def test_present(): ) with patch.dict(mysql_database.__opts__, {"test": False}): - comt = "Database {} is already present".format(dbname) + comt = f"Database {dbname} is already present" ret.update({"comment": comt}) ret.update({"result": True}) assert ( @@ -104,7 +105,7 @@ def test_present(): assert mysql_database.present(dbname) == ret with patch.object(mysql_database, "_get_mysql_error", mock_no_err): - comt = "The database {} has been created".format(dbname) + comt = f"The database {dbname} has been created" ret.update({"comment": comt, "result": True}) ret.update({"changes": {dbname: "Present"}}) @@ -116,7 +117,7 @@ def test_present(): ret["comment"] = "" with patch.object(mysql_database, "_get_mysql_error", mock_no_err): ret.update({"changes": {}}) - comt = "Failed to create database {}".format(dbname) + comt = f"Failed to create database {dbname}" ret.update({"comment": comt, "result": False}) assert mysql_database.present(dbname) == ret @@ -139,12 +140,12 @@ def test_absent(): {"mysql.db_exists": mock_db_exists, "mysql.db_remove": mock_remove}, ): with patch.dict(mysql_database.__opts__, {"test": True}): - comt = "Database {} is present and needs to be removed".format(dbname) + comt = f"Database {dbname} is present and needs to be removed" ret.update({"comment": comt, "result": None}) assert mysql_database.absent(dbname) == ret with patch.dict(mysql_database.__opts__, {}): - comt = "Database {} has been removed".format(dbname) + comt = f"Database {dbname} has been removed" ret.update({"comment": comt, "result": True}) ret.update({"changes": {dbname: "Absent"}}) assert mysql_database.absent(dbname) == ret diff --git a/tests/pytests/unit/states/mysql/test_query.py b/tests/pytests/unit/states/mysql/test_query.py index 1859afa3b2d..345774923b7 100644 --- a/tests/pytests/unit/states/mysql/test_query.py +++ b/tests/pytests/unit/states/mysql/test_query.py @@ -58,7 +58,7 @@ def test_run(): assert mysql_query.run(name, database, query) == ret with patch.object(mysql_query, "_get_mysql_error", mock_none): - comt = "Database {} is not present".format(name) + comt = f"Database {name} is not present" ret.update({"comment": comt, "result": None}) assert mysql_query.run(name, database, query) == ret diff --git a/tests/pytests/unit/states/postgresql/test_cluster.py b/tests/pytests/unit/states/postgresql/test_cluster.py index 52e9f087131..b816d0861d7 100644 --- a/tests/pytests/unit/states/postgresql/test_cluster.py +++ b/tests/pytests/unit/states/postgresql/test_cluster.py @@ -25,7 +25,7 @@ def test_present(): mock_t = MagicMock(return_value=True) mock_f = MagicMock(return_value=False) - infos = {"{}/{}".format(version, name): {}} + infos = {f"{version}/{name}": {}} mock = MagicMock(return_value=infos) with patch.dict( postgres_cluster.__salt__, @@ -35,17 +35,17 @@ def test_present(): "postgres.cluster_create": mock_t, }, ): - comt = "Cluster {}/{} is already present".format(version, name) + comt = f"Cluster {version}/{name} is already present" ret.update({"comment": comt, "result": True}) assert postgres_cluster.present(version, name) == ret - infos["{}/{}".format(version, name)]["port"] = 5433 + infos[f"{version}/{name}"]["port"] = 5433 comt = ( "Cluster {}/{} has wrong parameters " "which couldn't be changed on fly.".format(version, name) ) ret.update({"comment": comt, "result": False}) assert postgres_cluster.present(version, name, port=5434) == ret - infos["{}/{}".format(version, name)]["datadir"] = "/tmp/" + infos[f"{version}/{name}"]["datadir"] = "/tmp/" comt = ( "Cluster {}/{} has wrong parameters " "which couldn't be changed on fly.".format(version, name) @@ -61,17 +61,17 @@ def test_present(): "postgres.cluster_create": mock_t, }, ): - comt = "The cluster {}/{} has been created".format(version, name) + comt = f"The cluster {version}/{name} has been created" ret.update( { "comment": comt, "result": True, - "changes": {"{}/{}".format(version, name): "Present"}, + "changes": {f"{version}/{name}": "Present"}, } ) assert postgres_cluster.present(version, name) == ret with patch.dict(postgres_cluster.__opts__, {"test": True}): - comt = "Cluster {}/{} is set to be created".format(version, name) + comt = f"Cluster {version}/{name} is set to be created" ret.update({"comment": comt, "result": None, "changes": {}}) assert postgres_cluster.present(version, name) == ret @@ -83,7 +83,7 @@ def test_present(): "postgres.cluster_create": mock_f, }, ): - comt = "Failed to create cluster {}/{}".format(version, name) + comt = f"Failed to create cluster {version}/{name}" ret.update({"comment": comt, "result": False}) assert postgres_cluster.present(version, name) == ret @@ -104,12 +104,12 @@ def test_absent(): {"postgres.cluster_exists": mock, "postgres.cluster_remove": mock_t}, ): with patch.dict(postgres_cluster.__opts__, {"test": True}): - comt = "Cluster {}/{} is set to be removed".format(version, name) + comt = f"Cluster {version}/{name} is set to be removed" ret.update({"comment": comt, "result": None}) assert postgres_cluster.absent(version, name) == ret with patch.dict(postgres_cluster.__opts__, {"test": False}): - comt = "Cluster {}/{} has been removed".format(version, name) + comt = f"Cluster {version}/{name} has been removed" ret.update({"comment": comt, "result": True, "changes": {name: "Absent"}}) assert postgres_cluster.absent(version, name) == ret diff --git a/tests/pytests/unit/states/postgresql/test_database.py b/tests/pytests/unit/states/postgresql/test_database.py index 1e50574cad2..cb8b4c009c9 100644 --- a/tests/pytests/unit/states/postgresql/test_database.py +++ b/tests/pytests/unit/states/postgresql/test_database.py @@ -28,7 +28,7 @@ def test_present(): postgres_database.__salt__, {"postgres.db_list": mock, "postgres.db_alter": mock_t}, ): - comt = "Database {} is already present".format(name) + comt = f"Database {name} is already present" ret.update({"comment": comt, "result": True}) assert postgres_database.present(name) == ret @@ -68,15 +68,15 @@ def test_absent(): {"postgres.db_exists": mock, "postgres.db_remove": mock_t}, ): with patch.dict(postgres_database.__opts__, {"test": True}): - comt = "Database {} is set to be removed".format(name) + comt = f"Database {name} is set to be removed" ret.update({"comment": comt, "result": None}) assert postgres_database.absent(name) == ret with patch.dict(postgres_database.__opts__, {"test": False}): - comt = "Database {} has been removed".format(name) + comt = f"Database {name} has been removed" ret.update({"comment": comt, "result": True, "changes": {name: "Absent"}}) assert postgres_database.absent(name) == ret - comt = "Database {} is not present, so it cannot be removed".format(name) + comt = f"Database {name} is not present, so it cannot be removed" ret.update({"comment": comt, "result": True, "changes": {}}) assert postgres_database.absent(name) == ret diff --git a/tests/pytests/unit/states/postgresql/test_initdb.py b/tests/pytests/unit/states/postgresql/test_initdb.py index aee445743f3..f9f9d1e8f0e 100644 --- a/tests/pytests/unit/states/postgresql/test_initdb.py +++ b/tests/pytests/unit/states/postgresql/test_initdb.py @@ -21,7 +21,7 @@ def test_present_existing(): ret = {"name": name, "changes": {}, "result": False, "comment": ""} mock_true = MagicMock(return_value=True) with patch.dict(postgres_initdb.__salt__, {"postgres.datadir_exists": mock_true}): - _comt = "Postgres data directory {} is already present".format(name) + _comt = f"Postgres data directory {name} is already present" ret.update({"comment": _comt, "result": True}) assert postgres_initdb.present(name) == ret @@ -39,12 +39,12 @@ def test_present_non_existing_pass(): {"postgres.datadir_exists": mock_false, "postgres.datadir_init": mock_true}, ): with patch.dict(postgres_initdb.__opts__, {"test": True}): - _comt = "Postgres data directory {} is set to be initialized".format(name) + _comt = f"Postgres data directory {name} is set to be initialized" ret.update({"comment": _comt, "result": None}) assert postgres_initdb.present(name) == ret with patch.dict(postgres_initdb.__opts__, {"test": False}): - _comt = "Postgres data directory {} has been initialized".format(name) + _comt = f"Postgres data directory {name} has been initialized" _changes = {name: "Present"} ret.update({"comment": _comt, "result": True, "changes": _changes}) assert postgres_initdb.present(name) == ret @@ -62,6 +62,6 @@ def test_present_non_existing_fail(): {"postgres.datadir_exists": mock_false, "postgres.datadir_init": mock_false}, ): with patch.dict(postgres_initdb.__opts__, {"test": False}): - _comt = "Postgres data directory {} initialization failed".format(name) + _comt = f"Postgres data directory {name} initialization failed" ret.update({"comment": _comt, "result": False}) assert postgres_initdb.present(name) == ret diff --git a/tests/pytests/unit/states/postgresql/test_language.py b/tests/pytests/unit/states/postgresql/test_language.py index f8a1fa0dbd3..cdc88bd01b8 100644 --- a/tests/pytests/unit/states/postgresql/test_language.py +++ b/tests/pytests/unit/states/postgresql/test_language.py @@ -24,7 +24,7 @@ def test_present_existing(): postgres_language.__salt__, {"postgres.language_list": mock_language_list}, ): - comt = "Language {} is already installed".format(name) + comt = f"Language {name} is already installed" ret.update({"comment": comt, "result": True}) assert postgres_language.present(name, "testdb") == ret @@ -45,12 +45,12 @@ def test_present_non_existing_pass(): }, ): with patch.dict(postgres_language.__opts__, {"test": True}): - comt = "Language {} is set to be installed".format(name) + comt = f"Language {name} is set to be installed" ret.update({"comment": comt, "result": None}) assert postgres_language.present(name, "testdb") == ret with patch.dict(postgres_language.__opts__, {"test": False}): - comt = "Language {} has been installed".format(name) + comt = f"Language {name} has been installed" ret.update( {"comment": comt, "result": True, "changes": {"plpgsql": "Present"}} ) @@ -73,12 +73,12 @@ def test_present_non_existing_fail(): }, ): with patch.dict(postgres_language.__opts__, {"test": True}): - comt = "Language {} is set to be installed".format(name) + comt = f"Language {name} is set to be installed" ret.update({"comment": comt, "result": None}) assert postgres_language.present(name, "testdb") == ret with patch.dict(postgres_language.__opts__, {"test": False}): - comt = "Failed to install language {}".format(name) + comt = f"Failed to install language {name}" ret.update({"comment": comt, "result": False}) assert postgres_language.present(name, "testdb") == ret @@ -95,12 +95,12 @@ def test_absent_existing(): {"postgres.language_exists": mock_true, "postgres.language_remove": mock_true}, ): with patch.dict(postgres_language.__opts__, {"test": True}): - comt = "Language {} is set to be removed".format(name) + comt = f"Language {name} is set to be removed" ret.update({"comment": comt, "result": None}) assert postgres_language.absent(name, "testdb") == ret with patch.dict(postgres_language.__opts__, {"test": False}): - comt = "Language {} has been removed".format(name) + comt = f"Language {name} has been removed" ret.update( {"comment": comt, "result": True, "changes": {"plpgsql": "Absent"}} ) @@ -118,6 +118,6 @@ def test_absent_non_existing(): postgres_language.__salt__, {"postgres.language_exists": mock_false} ): with patch.dict(postgres_language.__opts__, {"test": True}): - comt = "Language {} is not present so it cannot be removed".format(name) + comt = f"Language {name} is not present so it cannot be removed" ret.update({"comment": comt, "result": True}) assert postgres_language.absent(name, "testdb") == ret diff --git a/tests/pytests/unit/states/rabbitmq/test_vhost.py b/tests/pytests/unit/states/rabbitmq/test_vhost.py index d6fc3e624f5..e61d1c8a766 100644 --- a/tests/pytests/unit/states/rabbitmq/test_vhost.py +++ b/tests/pytests/unit/states/rabbitmq/test_vhost.py @@ -48,7 +48,7 @@ def test_absent(): "name": name, "changes": {}, "result": True, - "comment": "Virtual Host '{}' is not present.".format(name), + "comment": f"Virtual Host '{name}' is not present.", } mock = MagicMock(return_value=False) diff --git a/tests/pytests/unit/states/test_alias.py b/tests/pytests/unit/states/test_alias.py index db2afb9e0c4..c9e4473b230 100644 --- a/tests/pytests/unit/states/test_alias.py +++ b/tests/pytests/unit/states/test_alias.py @@ -20,7 +20,7 @@ def test_present_has_target(): name = "saltdude" target = "dude@saltstack.com" ret = { - "comment": "Alias {} already present".format(name), + "comment": f"Alias {name} already present", "changes": {}, "name": name, "result": True, @@ -38,7 +38,7 @@ def test_present_has_not_target_test(): name = "saltdude" target = "dude@saltstack.com" ret = { - "comment": "Alias {} -> {} is set to be added".format(name, target), + "comment": f"Alias {name} -> {target} is set to be added", "changes": {}, "name": name, "result": None, @@ -57,7 +57,7 @@ def test_present_set_target(): name = "saltdude" target = "dude@saltstack.com" ret = { - "comment": "Set email alias {} -> {}".format(name, target), + "comment": f"Set email alias {name} -> {target}", "changes": {"alias": name}, "name": name, "result": True, @@ -78,7 +78,7 @@ def test_present_set_target_failed(): name = "saltdude" target = "dude@saltstack.com" ret = { - "comment": "Failed to set alias {} -> {}".format(name, target), + "comment": f"Failed to set alias {name} -> {target}", "changes": {}, "name": name, "result": False, @@ -98,7 +98,7 @@ def test_absent_already_gone(): """ name = "saltdude" ret = { - "comment": "Alias {} already absent".format(name), + "comment": f"Alias {name} already absent", "changes": {}, "name": name, "result": True, @@ -115,7 +115,7 @@ def test_absent_not_gone_test(): """ name = "saltdude" ret = { - "comment": "Alias {} is set to be removed".format(name), + "comment": f"Alias {name} is set to be removed", "changes": {}, "name": name, "result": None, @@ -133,7 +133,7 @@ def test_absent_rm_alias(): """ name = "saltdude" ret = { - "comment": "Removed alias {}".format(name), + "comment": f"Removed alias {name}", "changes": {"alias": name}, "name": name, "result": True, @@ -153,7 +153,7 @@ def test_absent_rm_alias_failed(): """ name = "saltdude" ret = { - "comment": "Failed to remove alias {}".format(name), + "comment": f"Failed to remove alias {name}", "changes": {}, "name": name, "result": False, diff --git a/tests/pytests/unit/states/test_alternatives.py b/tests/pytests/unit/states/test_alternatives.py index 9dbdd8b04f5..958e923af6c 100644 --- a/tests/pytests/unit/states/test_alternatives.py +++ b/tests/pytests/unit/states/test_alternatives.py @@ -36,7 +36,7 @@ def test_install(): } bad_link = "/bin/pager" - err = "the primary link for {} must be {}".format(name, link) + err = f"the primary link for {name} must be {link}" mock_cinst = MagicMock(side_effect=[True, False]) mock_cexist = MagicMock( @@ -55,7 +55,7 @@ def test_install(): "alternatives.show_link": mock_link, }, ): - comt = "Alternative {} for {} is already registered".format(path, name) + comt = f"Alternative {path} for {name} is already registered" ret.update({"comment": comt, "result": True}) assert alternatives.install(name, link, path, priority) == ret @@ -84,7 +84,7 @@ def test_install(): with patch.dict(alternatives.__opts__, {"test": False}): assert alternatives.install(name, link, path, priority) == ret - comt = "Alternative for {} not installed: {}".format(name, err) + comt = f"Alternative for {name} not installed: {err}" ret.update({"comment": comt, "result": False, "changes": {}, "link": bad_link}) with patch.dict(alternatives.__opts__, {"test": False}): assert alternatives.install(name, bad_link, path, priority) == ret @@ -133,12 +133,12 @@ def test_remove(): "alternatives.remove": mock_bool, }, ): - comt = "Alternative for {} will be removed".format(name) + comt = f"Alternative for {name} will be removed" ret.update({"comment": comt}) with patch.dict(alternatives.__opts__, {"test": True}): assert alternatives.remove(name, path) == ret - comt = "Alternative for {} removed".format(name) + comt = f"Alternative for {name} removed" ret.update({"comment": comt, "result": True}) with patch.dict(alternatives.__opts__, {"test": False}): assert alternatives.remove(name, path) == ret @@ -148,11 +148,11 @@ def test_remove(): with patch.dict(alternatives.__opts__, {"test": False}): assert alternatives.remove(name, path) == ret - comt = "Alternative for {} is set to it's default path True".format(name) + comt = f"Alternative for {name} is set to it's default path True" ret.update({"comment": comt, "result": True, "changes": {}}) assert alternatives.remove(name, path) == ret - comt = "Alternative for {} doesn't exist".format(name) + comt = f"Alternative for {name} doesn't exist" ret.update({"comment": comt, "result": False}) assert alternatives.remove(name, path) == ret @@ -175,11 +175,11 @@ def test_auto(): alternatives.__salt__, {"alternatives.display": mock, "alternatives.auto": mock_auto}, ): - comt = "{} already in auto mode".format(name) + comt = f"{name} already in auto mode" ret.update({"comment": comt}) assert alternatives.auto(name) == ret - comt = "{} will be put in auto mode".format(name) + comt = f"{name} will be put in auto mode" ret.update({"comment": comt, "result": None}) with patch.dict(alternatives.__opts__, {"test": True}): assert alternatives.auto(name) == ret @@ -213,20 +213,20 @@ def test_set(): "alternatives.set": mock_bool, }, ): - comt = "Alternative for {} already set to {}".format(name, path) + comt = f"Alternative for {name} already set to {path}" ret.update({"comment": comt}) assert alternatives.set_(name, path) == ret - comt = "Alternative for {} will be set to path /usr/bin/less".format(name) + comt = f"Alternative for {name} will be set to path /usr/bin/less" ret.update({"comment": comt, "result": None}) with patch.dict(alternatives.__opts__, {"test": True}): assert alternatives.set_(name, path) == ret - comt = "Alternative for {} not updated".format(name) + comt = f"Alternative for {name} not updated" ret.update({"comment": comt, "result": True}) with patch.dict(alternatives.__opts__, {"test": False}): assert alternatives.set_(name, path) == ret - comt = "Alternative {} for {} doesn't exist".format(path, name) + comt = f"Alternative {path} for {name} doesn't exist" ret.update({"comment": comt, "result": False}) assert alternatives.set_(name, path) == ret diff --git a/tests/pytests/unit/states/test_aptpkg.py b/tests/pytests/unit/states/test_aptpkg.py index fb36e377800..799a0c4ff92 100644 --- a/tests/pytests/unit/states/test_aptpkg.py +++ b/tests/pytests/unit/states/test_aptpkg.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import pytest import salt.states.aptpkg as aptpkg @@ -24,7 +23,7 @@ def test_held(): "name": name, "result": False, "changes": {}, - "comment": "Package {} does not have a state".format(name), + "comment": f"Package {name} does not have a state", } mock = MagicMock(return_value=False) diff --git a/tests/pytests/unit/states/test_archive.py b/tests/pytests/unit/states/test_archive.py index 178f00b83a1..b5350bc2dba 100644 --- a/tests/pytests/unit/states/test_archive.py +++ b/tests/pytests/unit/states/test_archive.py @@ -2,7 +2,6 @@ :codeauthor: Alexander Schwartz """ - import os import pytest @@ -305,7 +304,7 @@ def test_extracted_when_if_missing_path_exists(): with patch.object(os.path, "exists", MagicMock(return_value=True)): ret = archive.extracted(name, source=source, if_missing=if_missing) assert ret["result"], ret - assert ret["comment"] == "Path {} exists".format(if_missing) + assert ret["comment"] == f"Path {if_missing} exists" def test_clean_parent_conflict(): @@ -453,7 +452,7 @@ def test_skip_files_list_verify_success(): } mock_true = MagicMock(return_value=True) mock_false = MagicMock(return_value=False) - mock_cached = MagicMock(return_value="{}/{}".format(tmp_dir, source)) + mock_cached = MagicMock(return_value=f"{tmp_dir}/{source}") source_sum = {"hsum": "testhash", "hash_type": "sha256"} mock_hash = MagicMock(return_value=source_sum) mock_source_list = MagicMock(return_value=(source, None)) diff --git a/tests/pytests/unit/states/test_at.py b/tests/pytests/unit/states/test_at.py index 21f91bd5345..bf632e46601 100644 --- a/tests/pytests/unit/states/test_at.py +++ b/tests/pytests/unit/states/test_at.py @@ -60,7 +60,7 @@ def test_present(): { "result": False, "changes": {}, - "comment": "user {} does not exists".format(user), + "comment": f"user {user} does not exists", } ) @@ -134,7 +134,7 @@ def test_absent(): { "result": False, "changes": {}, - "comment": "limit parameter not supported {}".format(name), + "comment": f"limit parameter not supported {name}", } ) assert at.absent(name, limit="all") == ret_limit diff --git a/tests/pytests/unit/states/test_aws_sqs.py b/tests/pytests/unit/states/test_aws_sqs.py index dd132c88420..4a1dde198f0 100644 --- a/tests/pytests/unit/states/test_aws_sqs.py +++ b/tests/pytests/unit/states/test_aws_sqs.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.aws_sqs as aws_sqs @@ -23,12 +24,12 @@ def test_exists(): mock = MagicMock(side_effect=[False, True]) with patch.dict(aws_sqs.__salt__, {"aws_sqs.queue_exists": mock}): - comt = "AWS SQS queue {} is set to be created".format(name) + comt = f"AWS SQS queue {name} is set to be created" ret.update({"comment": comt}) with patch.dict(aws_sqs.__opts__, {"test": True}): assert aws_sqs.exists(name, region) == ret - comt = "{} exists in {}".format(name, region) + comt = f"{name} exists in {region}" ret.update({"comment": comt, "result": True}) assert aws_sqs.exists(name, region) == ret @@ -44,11 +45,11 @@ def test_absent(): mock = MagicMock(side_effect=[True, False]) with patch.dict(aws_sqs.__salt__, {"aws_sqs.queue_exists": mock}): - comt = "AWS SQS queue {} is set to be removed".format(name) + comt = f"AWS SQS queue {name} is set to be removed" ret.update({"comment": comt}) with patch.dict(aws_sqs.__opts__, {"test": True}): assert aws_sqs.absent(name, region) == ret - comt = "{} does not exist in {}".format(name, region) + comt = f"{name} does not exist in {region}" ret.update({"comment": comt, "result": True}) assert aws_sqs.absent(name, region) == ret diff --git a/tests/pytests/unit/states/test_blockdev.py b/tests/pytests/unit/states/test_blockdev.py index a1eacf2e53b..4fe322cc9f5 100644 --- a/tests/pytests/unit/states/test_blockdev.py +++ b/tests/pytests/unit/states/test_blockdev.py @@ -29,7 +29,7 @@ def test_tuned(): ret.update({"comment": comt}) assert blockdev.tuned(name) == ret - comt = "Changes to {} will be applied ".format(name) + comt = f"Changes to {name} will be applied " with patch.dict(blockdev.__salt__, {"file.is_blkdev": True}): ret.update({"comment": comt, "result": None}) with patch.dict(blockdev.__opts__, {"test": True}): @@ -47,7 +47,7 @@ def test_formatted(): with patch.object( os.path, "exists", MagicMock(side_effect=[False, True, True, True, True]) ): - comt = "{} does not exist".format(name) + comt = f"{name} does not exist" ret.update({"comment": comt}) assert blockdev.formatted(name) == ret @@ -55,7 +55,7 @@ def test_formatted(): # Test state return when block device is already in the correct state with patch.dict(blockdev.__salt__, {"cmd.run": mock_ext4}): - comt = "{} already formatted with ext4".format(name) + comt = f"{name} already formatted with ext4" ret.update({"comment": comt, "result": True}) assert blockdev.formatted(name) == ret @@ -69,7 +69,7 @@ def test_formatted(): with patch.dict( blockdev.__salt__, {"cmd.run": MagicMock(return_value="new-thing")} ): - comt = "Changes to {} will be applied ".format(name) + comt = f"Changes to {name} will be applied " ret.update({"comment": comt, "result": None}) with patch.object(salt.utils.path, "which", MagicMock(return_value=True)): with patch.dict(blockdev.__opts__, {"test": True}): @@ -83,7 +83,7 @@ def test_formatted(): "disk.format": MagicMock(return_value=True), }, ): - comt = "Failed to format {}".format(name) + comt = f"Failed to format {name}" ret.update({"comment": comt, "result": False}) with patch.object(salt.utils.path, "which", MagicMock(return_value=True)): with patch.dict(blockdev.__opts__, {"test": False}): diff --git a/tests/pytests/unit/states/test_boto_cloudfront.py b/tests/pytests/unit/states/test_boto_cloudfront.py index fef82fcda2c..6c3a7405d3f 100644 --- a/tests/pytests/unit/states/test_boto_cloudfront.py +++ b/tests/pytests/unit/states/test_boto_cloudfront.py @@ -1,6 +1,7 @@ """ Unit tests for the boto_cloudfront state module. """ + import copy import textwrap @@ -70,7 +71,7 @@ def test_present_from_scratch(): __salt__={"boto_cloudfront.get_distribution": mock_get}, __opts__={"test": True}, ): - comment = "Distribution {} set for creation.".format(name) + comment = f"Distribution {name} set for creation." assert boto_cloudfront.present(name, config, tags) == base_ret_with( {"result": None, "comment": comment, "changes": {"old": None, "new": name}} ) @@ -184,7 +185,7 @@ def test_present_update_config_and_tags(): __salt__={"boto_cloudfront.get_distribution": mock_get}, __opts__={"test": True}, ): - header = "Distribution {} set for new config:".format(name) + header = f"Distribution {name} set for new config:" assert boto_cloudfront.present(name, config, tags) == base_ret_with( { "result": None, @@ -219,7 +220,7 @@ def test_present_update_config_and_tags(): assert boto_cloudfront.present(name, config, tags) == base_ret_with( { "result": True, - "comment": "Updated distribution {}.".format(name), + "comment": f"Updated distribution {name}.", "changes": {"diff": diff}, } ) diff --git a/tests/pytests/unit/states/test_boto_cloudwatch_alarm.py b/tests/pytests/unit/states/test_boto_cloudwatch_alarm.py index 16c655a1cdf..2102f09a2ed 100644 --- a/tests/pytests/unit/states/test_boto_cloudwatch_alarm.py +++ b/tests/pytests/unit/states/test_boto_cloudwatch_alarm.py @@ -68,7 +68,7 @@ def test_absent(): boto_cloudwatch_alarm.__salt__, {"boto_cloudwatch.get_alarm": mock} ): with patch.dict(boto_cloudwatch_alarm.__opts__, {"test": True}): - comt = "alarm {} is set to be removed.".format(name) + comt = f"alarm {name} is set to be removed." ret.update({"comment": comt}) assert boto_cloudwatch_alarm.absent(name) == ret diff --git a/tests/pytests/unit/states/test_boto_dynamodb.py b/tests/pytests/unit/states/test_boto_dynamodb.py index 2375077b805..94df32d2381 100644 --- a/tests/pytests/unit/states/test_boto_dynamodb.py +++ b/tests/pytests/unit/states/test_boto_dynamodb.py @@ -44,7 +44,7 @@ def test_present(): assert boto_dynamodb.present(name) == ret with patch.dict(boto_dynamodb.__opts__, {"test": True}): - comt = "DynamoDB table {} would be created.".format(name) + comt = f"DynamoDB table {name} would be created." ret.update({"comment": comt, "result": None}) assert boto_dynamodb.present(name) == ret @@ -85,12 +85,12 @@ def test_absent(): boto_dynamodb.__salt__, {"boto_dynamodb.exists": mock, "boto_dynamodb.delete": mock_bool}, ): - comt = "DynamoDB table {} does not exist".format(name) + comt = f"DynamoDB table {name} does not exist" ret.update({"comment": comt}) assert boto_dynamodb.absent(name) == ret with patch.dict(boto_dynamodb.__opts__, {"test": True}): - comt = "DynamoDB table {} is set to be deleted".format(name) + comt = f"DynamoDB table {name} is set to be deleted" ret.update({"comment": comt, "result": None}) assert boto_dynamodb.absent(name) == ret @@ -100,6 +100,6 @@ def test_absent(): } with patch.dict(boto_dynamodb.__opts__, {"test": False}): - comt = "Deleted DynamoDB table {}".format(name) + comt = f"Deleted DynamoDB table {name}" ret.update({"comment": comt, "result": True, "changes": changes}) assert boto_dynamodb.absent(name) == ret diff --git a/tests/pytests/unit/states/test_boto_ec2.py b/tests/pytests/unit/states/test_boto_ec2.py index 6a41900c8d7..9ba763dec85 100644 --- a/tests/pytests/unit/states/test_boto_ec2.py +++ b/tests/pytests/unit/states/test_boto_ec2.py @@ -27,16 +27,16 @@ def test_key_present(): with patch.dict( boto_ec2.__salt__, {"boto_ec2.get_key": mock, "cp.get_file_str": mock_bool} ): - comt = "The key name {} already exists".format(name) + comt = f"The key name {name} already exists" ret.update({"comment": comt}) assert boto_ec2.key_present(name) == ret - comt = "File {} not found.".format(upublic) + comt = f"File {upublic} not found." ret.update({"comment": comt, "result": False}) assert boto_ec2.key_present(name, upload_public=upublic) == ret with patch.dict(boto_ec2.__opts__, {"test": True}): - comt = "The key {} is set to be created.".format(name) + comt = f"The key {name} is set to be created." ret.update({"comment": comt, "result": None}) assert boto_ec2.key_present(name, upload_public=upublic) == ret @@ -51,11 +51,11 @@ def test_key_absent(): mock = MagicMock(side_effect=[False, True]) with patch.dict(boto_ec2.__salt__, {"boto_ec2.get_key": mock}): - comt = "The key name {} does not exist".format(name) + comt = f"The key name {name} does not exist" ret.update({"comment": comt}) assert boto_ec2.key_absent(name) == ret with patch.dict(boto_ec2.__opts__, {"test": True}): - comt = "The key {} is set to be deleted.".format(name) + comt = f"The key {name} is set to be deleted." ret.update({"comment": comt, "result": None}) assert boto_ec2.key_absent(name) == ret diff --git a/tests/pytests/unit/states/test_boto_elasticache.py b/tests/pytests/unit/states/test_boto_elasticache.py index 3692577834c..3b2584cc23c 100644 --- a/tests/pytests/unit/states/test_boto_elasticache.py +++ b/tests/pytests/unit/states/test_boto_elasticache.py @@ -38,16 +38,16 @@ def test_present(): assert boto_elasticache.present(name, engine, cache_node_type) == ret with patch.dict(boto_elasticache.__opts__, {"test": True}): - comt = "Cache cluster {} is set to be created.".format(name) + comt = f"Cache cluster {name} is set to be created." ret.update({"comment": comt}) assert boto_elasticache.present(name, engine, cache_node_type) == ret with patch.dict(boto_elasticache.__opts__, {"test": False}): - comt = "Failed to create {} cache cluster.".format(name) + comt = f"Failed to create {name} cache cluster." ret.update({"comment": comt, "result": False}) assert boto_elasticache.present(name, engine, cache_node_type) == ret - comt = "Cache cluster {} is present.".format(name) + comt = f"Cache cluster {name} is present." ret.update({"comment": comt, "result": True}) assert boto_elasticache.present(name, engine, cache_node_type) == ret @@ -62,12 +62,12 @@ def test_absent(): mock = MagicMock(side_effect=[False, True]) with patch.dict(boto_elasticache.__salt__, {"boto_elasticache.exists": mock}): - comt = "{} does not exist in None.".format(name) + comt = f"{name} does not exist in None." ret.update({"comment": comt}) assert boto_elasticache.absent(name) == ret with patch.dict(boto_elasticache.__opts__, {"test": True}): - comt = "Cache cluster {} is set to be removed.".format(name) + comt = f"Cache cluster {name} is set to be removed." ret.update({"comment": comt, "result": None}) assert boto_elasticache.absent(name) == ret @@ -84,7 +84,7 @@ def test_creategroup(): mock = MagicMock(return_value=True) with patch.dict(boto_elasticache.__salt__, {"boto_elasticache.group_exists": mock}): - comt = "{} replication group exists .".format(name) + comt = f"{name} replication group exists ." ret.update({"comment": comt}) assert ( boto_elasticache.creategroup( diff --git a/tests/pytests/unit/states/test_boto_elb.py b/tests/pytests/unit/states/test_boto_elb.py index 08699d796fe..216352bb8ec 100644 --- a/tests/pytests/unit/states/test_boto_elb.py +++ b/tests/pytests/unit/states/test_boto_elb.py @@ -151,7 +151,7 @@ def test_register_instances(): mock_bool = MagicMock(return_value=False) with patch.dict(boto_elb.__salt__, {"boto_elb.exists": mock_bool}): - comt = "Could not find lb {}".format(name) + comt = f"Could not find lb {name}" ret.update({"comment": comt}) assert boto_elb.register_instances(name, instances) == ret @@ -166,11 +166,11 @@ def test_absent(): mock = MagicMock(side_effect=[False, True]) with patch.dict(boto_elb.__salt__, {"boto_elb.exists": mock}): - comt = "{} ELB does not exist.".format(name) + comt = f"{name} ELB does not exist." ret.update({"comment": comt}) assert boto_elb.absent(name) == ret with patch.dict(boto_elb.__opts__, {"test": True}): - comt = "ELB {} is set to be removed.".format(name) + comt = f"ELB {name} is set to be removed." ret.update({"comment": comt, "result": None}) assert boto_elb.absent(name) == ret diff --git a/tests/pytests/unit/states/test_boto_iam_role.py b/tests/pytests/unit/states/test_boto_iam_role.py index 0a577e56978..3d342f80df3 100644 --- a/tests/pytests/unit/states/test_boto_iam_role.py +++ b/tests/pytests/unit/states/test_boto_iam_role.py @@ -91,7 +91,7 @@ def test_present(): }, ): with patch.dict(boto_iam_role.__opts__, {"test": False}): - comt = " Failed to create {} IAM role.".format(name) + comt = f" Failed to create {name} IAM role." ret.update({"comment": comt}) assert boto_iam_role.present(name) == ret diff --git a/tests/pytests/unit/states/test_boto_kinesis.py b/tests/pytests/unit/states/test_boto_kinesis.py index 2c3c9491ad8..af2b345830a 100644 --- a/tests/pytests/unit/states/test_boto_kinesis.py +++ b/tests/pytests/unit/states/test_boto_kinesis.py @@ -79,7 +79,7 @@ def test_stream_present(): with patch.dict(boto_kinesis.__opts__, {"test": True}): # not present, test environment (dry run) - comt = "Kinesis stream {} would be created".format(name) + comt = f"Kinesis stream {name} would be created" ret.update({"comment": comt, "result": None}) assert ( boto_kinesis.present( @@ -149,21 +149,21 @@ def test_absent(): boto_kinesis.__salt__, {"boto_kinesis.exists": mock, "boto_kinesis.delete_stream": mock_bool}, ): - comt = "Kinesis stream {} does not exist".format(name) + comt = f"Kinesis stream {name} does not exist" ret.update({"comment": comt}) assert boto_kinesis.absent(name) == ret with patch.dict(boto_kinesis.__opts__, {"test": True}): - comt = "Kinesis stream {} would be deleted".format(name) + comt = f"Kinesis stream {name} would be deleted" ret.update({"comment": comt, "result": None}) assert boto_kinesis.absent(name) == ret changes = { - "new": "Stream {} deleted".format(name), - "old": "Stream {} exists".format(name), + "new": f"Stream {name} deleted", + "old": f"Stream {name} exists", } with patch.dict(boto_kinesis.__opts__, {"test": False}): - comt = "Deleted stream {}".format(name) + comt = f"Deleted stream {name}" ret.update({"comment": comt, "result": True, "changes": changes}) assert boto_kinesis.absent(name) == ret diff --git a/tests/pytests/unit/states/test_boto_lc.py b/tests/pytests/unit/states/test_boto_lc.py index ab44a58f586..604af3bd6a7 100644 --- a/tests/pytests/unit/states/test_boto_lc.py +++ b/tests/pytests/unit/states/test_boto_lc.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.boto_lc as boto_lc diff --git a/tests/pytests/unit/states/test_boto_route53.py b/tests/pytests/unit/states/test_boto_route53.py index 7d0f125223b..d46b94a29ca 100644 --- a/tests/pytests/unit/states/test_boto_route53.py +++ b/tests/pytests/unit/states/test_boto_route53.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.boto_route53 as boto53mod @@ -71,16 +72,16 @@ def test_present(): {"boto_route53.get_record": mock, "boto_route53.add_record": mock_bool}, ): with patch.dict(boto_route53.__opts__, {"test": False}): - comt = "Failed to add {} Route53 record.".format(name) + comt = f"Failed to add {name} Route53 record." ret.update({"comment": comt}) assert boto_route53.present(name, value, zone, record_type) == ret with patch.dict(boto_route53.__opts__, {"test": True}): - comt = "Route53 record {} set to be added.".format(name) + comt = f"Route53 record {name} set to be added." ret.update({"comment": comt, "result": None}) assert boto_route53.present(name, value, zone, record_type) == ret - comt = "Route53 record {} set to be updated.".format(name) + comt = f"Route53 record {name} set to be updated." ret.update({"comment": comt}) assert boto_route53.present(name, value, zone, record_type) == ret @@ -100,12 +101,12 @@ def test_absent(): mock = MagicMock(side_effect=[False, True]) with patch.dict(boto_route53.__salt__, {"boto_route53.get_record": mock}): - comt = "{} does not exist.".format(name) + comt = f"{name} does not exist." ret.update({"comment": comt}) assert boto_route53.absent(name, zone, record_type) == ret with patch.dict(boto_route53.__opts__, {"test": True}): - comt = "Route53 record {} set to be deleted.".format(name) + comt = f"Route53 record {name} set to be deleted." ret.update({"comment": comt, "result": None}) assert boto_route53.absent(name, zone, record_type) == ret diff --git a/tests/pytests/unit/states/test_boto_sns.py b/tests/pytests/unit/states/test_boto_sns.py index d6fbdcee059..22c994188be 100644 --- a/tests/pytests/unit/states/test_boto_sns.py +++ b/tests/pytests/unit/states/test_boto_sns.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.boto_sns as boto_sns @@ -25,17 +26,17 @@ def test_present(): with patch.dict( boto_sns.__salt__, {"boto_sns.exists": mock, "boto_sns.create": mock_bool} ): - comt = "AWS SNS topic {} present.".format(name) + comt = f"AWS SNS topic {name} present." ret.update({"comment": comt}) assert boto_sns.present(name) == ret with patch.dict(boto_sns.__opts__, {"test": True}): - comt = "AWS SNS topic {} is set to be created.".format(name) + comt = f"AWS SNS topic {name} is set to be created." ret.update({"comment": comt, "result": None}) assert boto_sns.present(name) == ret with patch.dict(boto_sns.__opts__, {"test": False}): - comt = "Failed to create {} AWS SNS topic".format(name) + comt = f"Failed to create {name} AWS SNS topic" ret.update({"comment": comt, "result": False}) assert boto_sns.present(name) == ret @@ -51,7 +52,7 @@ def test_absent(): exists_mock = MagicMock(side_effect=[False, True, True, True, True, True, True]) with patch.dict(boto_sns.__salt__, {"boto_sns.exists": exists_mock}): # tests topic already absent - comt = "AWS SNS topic {} does not exist.".format(name) + comt = f"AWS SNS topic {name} does not exist." ret.update({"comment": comt}) assert boto_sns.absent(name) == ret @@ -98,7 +99,7 @@ def test_absent(): with patch.dict(boto_sns.__salt__, {"boto_sns.delete": delete_mock}): # tests topic present, unsubscribe flag True, unsubscribe succeeded, # delete succeeded - comt = "AWS SNS topic {} deleted.".format(name) + comt = f"AWS SNS topic {name} deleted." ret.update( { "changes": { @@ -136,6 +137,6 @@ def test_absent(): assert boto_sns.absent(name) == ret # tests topic present, unsubscribe flag False, delete failed - comt = "Failed to delete {} AWS SNS topic.".format(name) + comt = f"Failed to delete {name} AWS SNS topic." ret.update({"changes": {}, "result": False, "comment": comt}) assert boto_sns.absent(name) == ret diff --git a/tests/pytests/unit/states/test_boto_sqs.py b/tests/pytests/unit/states/test_boto_sqs.py index 25175463eda..a656c47bee6 100644 --- a/tests/pytests/unit/states/test_boto_sqs.py +++ b/tests/pytests/unit/states/test_boto_sqs.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import textwrap import pytest @@ -53,7 +54,7 @@ def test_present(): assert boto_sqs.present(name) == ret with patch.dict(boto_sqs.__opts__, {"test": True}): - comt = ["SQS queue {} is set to be created.".format(name)] + comt = [f"SQS queue {name} is set to be created."] ret = base_ret.copy() ret.update( { @@ -101,13 +102,13 @@ def test_absent(): mock = MagicMock(side_effect=[{"result": False}, {"result": True}]) with patch.dict(boto_sqs.__salt__, {"boto_sqs.exists": mock}): - comt = "SQS queue {} does not exist in None.".format(name) + comt = f"SQS queue {name} does not exist in None." ret = base_ret.copy() ret.update({"result": True, "comment": comt}) assert boto_sqs.absent(name) == ret with patch.dict(boto_sqs.__opts__, {"test": True}): - comt = "SQS queue {} is set to be removed.".format(name) + comt = f"SQS queue {name} is set to be removed." ret = base_ret.copy() ret.update( { diff --git a/tests/pytests/unit/states/test_bower.py b/tests/pytests/unit/states/test_bower.py index f375f6ab58c..7a019d787b4 100644 --- a/tests/pytests/unit/states/test_bower.py +++ b/tests/pytests/unit/states/test_bower.py @@ -1,6 +1,7 @@ """ :codeauthor: Alexander Pyatkin """ + import pytest import salt.states.bower as bower diff --git a/tests/pytests/unit/states/test_chocolatey.py b/tests/pytests/unit/states/test_chocolatey.py index 5f24d3cb9ae..660ba4b61b2 100644 --- a/tests/pytests/unit/states/test_chocolatey.py +++ b/tests/pytests/unit/states/test_chocolatey.py @@ -1,6 +1,7 @@ """ Unit tests for chocolatey state """ + import logging import pytest diff --git a/tests/pytests/unit/states/test_cloud.py b/tests/pytests/unit/states/test_cloud.py index ef257ee1f60..556a4ddef9e 100644 --- a/tests/pytests/unit/states/test_cloud.py +++ b/tests/pytests/unit/states/test_cloud.py @@ -46,12 +46,12 @@ def test_present(): assert cloud.present(name, cloud_provider, unless="") == ret - comt = "Already present instance {}".format(name) + comt = f"Already present instance {name}" ret.update({"comment": comt}) assert cloud.present(name, cloud_provider) == ret with patch.dict(cloud.__opts__, {"test": True}): - comt = "Instance {} needs to be created".format(name) + comt = f"Instance {name} needs to be created" ret.update({"comment": comt, "result": None}) assert cloud.present(name, cloud_provider) == ret @@ -97,12 +97,12 @@ def test_absent(): assert cloud.absent(name, unless="") == ret - comt = "Already absent instance {}".format(name) + comt = f"Already absent instance {name}" ret.update({"comment": comt}) assert cloud.absent(name) == ret with patch.dict(cloud.__opts__, {"test": True}): - comt = "Instance {} needs to be destroyed".format(name) + comt = f"Instance {name} needs to be destroyed" ret.update({"comment": comt, "result": None}) assert cloud.absent(name) == ret @@ -150,22 +150,22 @@ def test_profile(): assert cloud.profile(name, profile, unless="") == ret - comt = "Already present instance {}".format(name) + comt = f"Already present instance {name}" ret.update({"comment": comt}) assert cloud.profile(name, profile) == ret with patch.dict(cloud.__opts__, {"test": True}): - comt = "Instance {} needs to be created".format(name) + comt = f"Instance {name} needs to be created" ret.update({"comment": comt, "result": None}) assert cloud.profile(name, profile) == ret with patch.dict(cloud.__opts__, {"test": False}): - comt = "Failed to create instance {} using profile {}".format(name, profile) + comt = f"Failed to create instance {name} using profile {profile}" ret.update({"comment": comt, "result": False}) assert cloud.profile(name, profile) == ret with patch.dict(cloud.__opts__, {"test": False}): - comt = "Failed to create instance {} using profile {}".format(name, profile) + comt = f"Failed to create instance {name} using profile {profile}" ret.update({"comment": comt, "result": False}) assert cloud.profile(name, profile) == ret @@ -188,17 +188,17 @@ def test_volume_present(): ret.update({"comment": comt}) assert cloud.volume_present(name) == ret - comt = "Volume exists: {}".format(name) + comt = f"Volume exists: {name}" ret.update({"comment": comt, "result": True}) assert cloud.volume_present(name) == ret with patch.dict(cloud.__opts__, {"test": True}): - comt = "Volume {} will be created.".format(name) + comt = f"Volume {name} will be created." ret.update({"comment": comt, "result": None}) assert cloud.volume_present(name) == ret with patch.dict(cloud.__opts__, {"test": False}): - comt = "Volume {} was created".format(name) + comt = f"Volume {name} was created" ret.update( { "comment": comt, @@ -232,12 +232,12 @@ def test_volume_absent(): assert cloud.volume_absent(name) == ret with patch.dict(cloud.__opts__, {"test": True}): - comt = "Volume {} will be deleted.".format(name) + comt = f"Volume {name} will be deleted." ret.update({"comment": comt, "result": None}) assert cloud.volume_absent(name) == ret with patch.dict(cloud.__opts__, {"test": False}): - comt = "Volume {} failed to delete.".format(name) + comt = f"Volume {name} failed to delete." ret.update({"comment": comt, "result": False}) assert cloud.volume_absent(name) == ret @@ -277,15 +277,15 @@ def test_volume_attached(): ret.update({"name": server_name}) assert cloud.volume_attached(name, server_name) == ret - comt = "Volume {} is already attached: True".format(disk_name) + comt = f"Volume {disk_name} is already attached: True" ret.update({"comment": comt, "result": True}) assert cloud.volume_attached(name, server_name) == ret - comt = "Volume {} does not exist".format(name) + comt = f"Volume {name} does not exist" ret.update({"comment": comt, "result": False}) assert cloud.volume_attached(name, server_name) == ret - comt = "Server {} does not exist".format(server_name) + comt = f"Server {server_name} does not exist" ret.update({"comment": comt, "result": False}) assert cloud.volume_attached(name, server_name) == ret @@ -294,12 +294,12 @@ def test_volume_attached(): cloud.__salt__, {"cloud.action": mock, "cloud.volume_attach": mock} ): with patch.dict(cloud.__opts__, {"test": True}): - comt = "Volume {} will be will be attached.".format(name) + comt = f"Volume {name} will be will be attached." ret.update({"comment": comt, "result": None}) assert cloud.volume_attached(name, server_name) == ret with patch.dict(cloud.__opts__, {"test": False}): - comt = "Volume {} was created".format(name) + comt = f"Volume {name} was created" ret.update( { "comment": comt, @@ -348,15 +348,15 @@ def test_volume_detached(): ret.update({"name": server_name}) assert cloud.volume_detached(name, server_name) == ret - comt = "Volume {} is not currently attached to anything.".format(disk_name) + comt = f"Volume {disk_name} is not currently attached to anything." ret.update({"comment": comt, "result": True}) assert cloud.volume_detached(name, server_name) == ret - comt = "Volume {} does not exist".format(name) + comt = f"Volume {name} does not exist" ret.update({"comment": comt}) assert cloud.volume_detached(name, server_name) == ret - comt = "Server {} does not exist".format(server_name) + comt = f"Server {server_name} does not exist" ret.update({"comment": comt}) assert cloud.volume_detached(name, server_name) == ret @@ -365,12 +365,12 @@ def test_volume_detached(): cloud.__salt__, {"cloud.action": mock, "cloud.volume_detach": mock} ): with patch.dict(cloud.__opts__, {"test": True}): - comt = "Volume {} will be will be detached.".format(name) + comt = f"Volume {name} will be will be detached." ret.update({"comment": comt, "result": None}) assert cloud.volume_detached(name, server_name) == ret with patch.dict(cloud.__opts__, {"test": False}): - comt = "Volume {} was created".format(name) + comt = f"Volume {name} was created" ret.update( { "comment": comt, diff --git a/tests/pytests/unit/states/test_consul.py b/tests/pytests/unit/states/test_consul.py index 02367458356..816278fa385 100644 --- a/tests/pytests/unit/states/test_consul.py +++ b/tests/pytests/unit/states/test_consul.py @@ -2,7 +2,6 @@ Test case for the consul state module """ - import logging import pytest diff --git a/tests/pytests/unit/states/test_ddns.py b/tests/pytests/unit/states/test_ddns.py index e14ec13f0b2..1a82b67dfd7 100644 --- a/tests/pytests/unit/states/test_ddns.py +++ b/tests/pytests/unit/states/test_ddns.py @@ -25,14 +25,14 @@ def test_present(): ret = {"name": name, "result": None, "comment": "", "changes": {}} with patch.dict(ddns.__opts__, {"test": True}): - comt = 'A record "{}" will be updated'.format(name) + comt = f'A record "{name}" will be updated' ret.update({"comment": comt}) assert ddns.present(name, zone, ttl, data) == ret with patch.dict(ddns.__opts__, {"test": False}): mock = MagicMock(return_value=None) with patch.dict(ddns.__salt__, {"ddns.update": mock}): - comt = 'A record "{}" already present with ttl of {}'.format(name, ttl) + comt = f'A record "{name}" already present with ttl of {ttl}' ret.update({"comment": comt, "result": True}) assert ddns.present(name, zone, ttl, data) == ret @@ -48,7 +48,7 @@ def test_absent(): ret = {"name": name, "result": None, "comment": "", "changes": {}} with patch.dict(ddns.__opts__, {"test": True}): - comt = 'None record "{}" will be deleted'.format(name) + comt = f'None record "{name}" will be deleted' ret.update({"comment": comt}) assert ddns.absent(name, zone, data) == ret diff --git a/tests/pytests/unit/states/test_debconfmod.py b/tests/pytests/unit/states/test_debconfmod.py index eae21c97535..3151e84275f 100644 --- a/tests/pytests/unit/states/test_debconfmod.py +++ b/tests/pytests/unit/states/test_debconfmod.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.debconfmod as debconfmod diff --git a/tests/pytests/unit/states/test_drac.py b/tests/pytests/unit/states/test_drac.py index 71f95396e25..3fba523410b 100644 --- a/tests/pytests/unit/states/test_drac.py +++ b/tests/pytests/unit/states/test_drac.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.drac as drac @@ -25,12 +26,12 @@ def test_present(): mock = MagicMock(return_value=[name]) with patch.dict(drac.__salt__, {"drac.list_users": mock}): with patch.dict(drac.__opts__, {"test": True}): - comt = "`{}` already exists".format(name) + comt = f"`{name}` already exists" ret.update({"comment": comt}) assert drac.present(name, password, permission) == ret with patch.dict(drac.__opts__, {"test": False}): - comt = "`{}` already exists".format(name) + comt = f"`{name}` already exists" ret.update({"comment": comt}) assert drac.present(name, password, permission) == ret @@ -46,12 +47,12 @@ def test_absent(): mock = MagicMock(return_value=[]) with patch.dict(drac.__salt__, {"drac.list_users": mock}): with patch.dict(drac.__opts__, {"test": True}): - comt = "`{}` does not exist".format(name) + comt = f"`{name}` does not exist" ret.update({"comment": comt}) assert drac.absent(name) == ret with patch.dict(drac.__opts__, {"test": False}): - comt = "`{}` does not exist".format(name) + comt = f"`{name}` does not exist" ret.update({"comment": comt}) assert drac.absent(name) == ret diff --git a/tests/pytests/unit/states/test_elasticsearch.py b/tests/pytests/unit/states/test_elasticsearch.py index b3d55e1df41..89e84b1bb9f 100644 --- a/tests/pytests/unit/states/test_elasticsearch.py +++ b/tests/pytests/unit/states/test_elasticsearch.py @@ -1,6 +1,7 @@ """ :codeauthor: Lukas Raska """ + import pytest import salt.utils.dictdiffer as dictdiffer diff --git a/tests/pytests/unit/states/test_eselect.py b/tests/pytests/unit/states/test_eselect.py index 02eed1a319d..c8e3e3caa09 100644 --- a/tests/pytests/unit/states/test_eselect.py +++ b/tests/pytests/unit/states/test_eselect.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.eselect as eselect @@ -23,6 +24,6 @@ def test_set_(): mock = MagicMock(return_value=target) with patch.dict(eselect.__salt__, {"eselect.get_current_target": mock}): - comt = "Target '{}' is already set on '{}' module.".format(target, name) + comt = f"Target '{target}' is already set on '{name}' module." ret.update({"comment": comt}) assert eselect.set_(name, target) == ret diff --git a/tests/pytests/unit/states/test_etcd_mod.py b/tests/pytests/unit/states/test_etcd_mod.py index e8fde7c48f1..17df492a1c0 100644 --- a/tests/pytests/unit/states/test_etcd_mod.py +++ b/tests/pytests/unit/states/test_etcd_mod.py @@ -9,7 +9,6 @@ :codeauthor: Caleb Beard """ - import pytest import salt.states.etcd_mod as etcd_state diff --git a/tests/pytests/unit/states/test_ethtool.py b/tests/pytests/unit/states/test_ethtool.py index c0f5267f811..dcf119fb417 100644 --- a/tests/pytests/unit/states/test_ethtool.py +++ b/tests/pytests/unit/states/test_ethtool.py @@ -51,9 +51,9 @@ def test_ethtool_pause(): with patch.dict(ethtool.__opts__, {"test": True}): expected["result"] = None expected["changes"] = {} - expected[ - "comment" - ] = "Device eth0 pause parameters are set to be updated:\nautoneg: off\nrx: off\ntx: off" + expected["comment"] = ( + "Device eth0 pause parameters are set to be updated:\nautoneg: off\nrx: off\ntx: off" + ) ret = ethtool.pause("eth0", autoneg=False, rx=False, tx=False) assert ret == expected mock_set.assert_not_called() diff --git a/tests/pytests/unit/states/test_firewalld.py b/tests/pytests/unit/states/test_firewalld.py index 867beadaa81..2f01ef6c6e0 100644 --- a/tests/pytests/unit/states/test_firewalld.py +++ b/tests/pytests/unit/states/test_firewalld.py @@ -1,6 +1,7 @@ """ :codeauthor: Hristo Voyvodov """ + import pytest import salt.states.firewalld as firewalld diff --git a/tests/pytests/unit/states/test_gem.py b/tests/pytests/unit/states/test_gem.py index 6d3a7ac001d..ab054904593 100644 --- a/tests/pytests/unit/states/test_gem.py +++ b/tests/pytests/unit/states/test_gem.py @@ -2,7 +2,6 @@ Tests of salt.states.gem """ - import pytest import salt.states.gem as gem diff --git a/tests/pytests/unit/states/test_git.py b/tests/pytests/unit/states/test_git.py index 7410239bac1..b9e9f7b6460 100644 --- a/tests/pytests/unit/states/test_git.py +++ b/tests/pytests/unit/states/test_git.py @@ -4,7 +4,6 @@ :codeauthor: Erik Johnson """ - import logging import pytest diff --git a/tests/pytests/unit/states/test_gnomedesktop.py b/tests/pytests/unit/states/test_gnomedesktop.py index 0229e734592..fd089bdc5a5 100644 --- a/tests/pytests/unit/states/test_gnomedesktop.py +++ b/tests/pytests/unit/states/test_gnomedesktop.py @@ -4,7 +4,6 @@ Test cases for salt.states.gnomedesktop """ - import pytest import salt.states.gnomedesktop as gnomedesktop diff --git a/tests/pytests/unit/states/test_grafana.py b/tests/pytests/unit/states/test_grafana.py index 3a6b73f947e..de36fa3389f 100644 --- a/tests/pytests/unit/states/test_grafana.py +++ b/tests/pytests/unit/states/test_grafana.py @@ -64,7 +64,7 @@ def test_dashboard_present(): with patch.dict(grafana.__opts__, {"test": True}): pytest.raises(SaltInvocationError, grafana.dashboard_present, name) - comt = "Dashboard {} is set to be created.".format(name) + comt = f"Dashboard {name} is set to be created." ret.update({"comment": comt}) assert grafana.dashboard_present(name, True) == ret diff --git a/tests/pytests/unit/states/test_grains.py b/tests/pytests/unit/states/test_grains.py index 8015eaf9340..a2df4028244 100644 --- a/tests/pytests/unit/states/test_grains.py +++ b/tests/pytests/unit/states/test_grains.py @@ -1,6 +1,7 @@ """ unit tests for the grains state """ + import contextlib import os diff --git a/tests/pytests/unit/states/test_group.py b/tests/pytests/unit/states/test_group.py index 72ec6ce3aa6..c401c884316 100644 --- a/tests/pytests/unit/states/test_group.py +++ b/tests/pytests/unit/states/test_group.py @@ -4,16 +4,12 @@ import salt.states.group as group import salt.utils.platform from tests.support.mock import MagicMock, call, patch -__context__ = {} - - -def ping(): - ... - @pytest.fixture def configure_loader_modules(): - return {group: {"__salt__": {"test.ping": ping}, "__opts__": {"test": False}}} + return { + group: {"__salt__": {"test.ping": MagicMock()}, "__opts__": {"test": False}} + } def test_present_with_non_unique_gid(): diff --git a/tests/pytests/unit/states/test_helm.py b/tests/pytests/unit/states/test_helm.py index d7d78432e17..9c91ab74f6c 100644 --- a/tests/pytests/unit/states/test_helm.py +++ b/tests/pytests/unit/states/test_helm.py @@ -2,7 +2,6 @@ Test cases for salt.modules.helm """ - import pytest import salt.states.helm as helm diff --git a/tests/pytests/unit/states/test_host.py b/tests/pytests/unit/states/test_host.py index 3a3ab022a02..5830747b115 100644 --- a/tests/pytests/unit/states/test_host.py +++ b/tests/pytests/unit/states/test_host.py @@ -50,9 +50,7 @@ def test_present(): ): ret = host.present(hostname, ip_str) assert ret["result"] is True - assert ret["comment"] == "Added host {} ({})".format(hostname, ip_str), ret[ - "comment" - ] + assert ret["comment"] == f"Added host {hostname} ({ip_str})", ret["comment"] assert ret["changes"] == {"added": {ip_str: [hostname]}}, ret["changes"] expected = [call(ip_str, hostname)] assert add_host.mock_calls == expected, add_host.mock_calls @@ -73,8 +71,8 @@ def test_present(): ): ret = host.present(hostname, ip_list) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] - assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] + assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] + assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]} }, ret["changes"] @@ -102,10 +100,9 @@ def test_present(): ): ret = host.present(hostname, ip_str) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_str) in ret["comment"] + assert f"Added host {hostname} ({ip_str})" in ret["comment"] assert ( - "Host {} present for IP address {}".format(hostname, ip_list[0]) - in ret["warnings"][0] + f"Host {hostname} present for IP address {ip_list[0]}" in ret["warnings"][0] ) assert ret["changes"] == {"added": {ip_str: [hostname]}}, ret["changes"] expected = [call(ip_str, hostname)] @@ -125,8 +122,8 @@ def test_present(): ): ret = host.present(hostname, ip_str, clean=True) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_str) in ret["comment"] - assert "Removed host {} ({})".format(hostname, ip_list[0]) in ret["comment"] + assert f"Added host {hostname} ({ip_str})" in ret["comment"] + assert f"Removed host {hostname} ({ip_list[0]})" in ret["comment"] assert ret["changes"] == { "added": {ip_str: [hostname]}, "removed": {ip_list[0]: [hostname]}, @@ -157,8 +154,8 @@ def test_present(): ): ret = host.present(hostname, ip_list) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] - assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] + assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] + assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]}, }, ret["changes"] @@ -179,9 +176,9 @@ def test_present(): ): ret = host.present(hostname, ip_list, clean=True) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] - assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] - assert "Removed host {} ({})".format(hostname, cur_ip) in ret["comment"] + assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] + assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] + assert f"Removed host {hostname} ({cur_ip})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]}, "removed": {cur_ip: [hostname]}, @@ -214,7 +211,7 @@ def test_present(): ): ret = host.present(hostname, ip_list) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] + assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] assert ret["changes"] == {"added": {ip_list[1]: [hostname]}}, ret["changes"] expected = [call(ip_list[1], hostname)] assert add_host.mock_calls == expected, add_host.mock_calls @@ -233,8 +230,8 @@ def test_present(): ): ret = host.present(hostname, ip_list, clean=True) assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] - assert "Removed host {} ({})".format(hostname, cur_ip) in ret["comment"] + assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] + assert f"Removed host {hostname} ({cur_ip})" in ret["comment"] assert ret["changes"] == { "added": {ip_list[1]: [hostname]}, "removed": {cur_ip: [hostname]}, @@ -261,7 +258,7 @@ def test_present(): assert ret["result"] is True assert ( ret["comment"] - == "Host {} ({}) already present".format(hostname, ip_str) + == f"Host {hostname} ({ip_str}) already present" in ret["comment"] ) assert ret["changes"] == {}, ret["changes"] @@ -289,14 +286,8 @@ def test_present(): ): ret = host.present(hostname, ip_list) assert ret["result"] is True - assert ( - "Host {} ({}) already present".format(hostname, ip_list[0]) - in ret["comment"] - ) - assert ( - "Host {} ({}) already present".format(hostname, ip_list[1]) - in ret["comment"] - ) + assert f"Host {hostname} ({ip_list[0]}) already present" in ret["comment"] + assert f"Host {hostname} ({ip_list[1]}) already present" in ret["comment"] assert ret["changes"] == {}, ret["changes"] assert add_host.mock_calls == [], add_host.mock_calls assert rm_host.mock_calls == [], rm_host.mock_calls @@ -320,14 +311,10 @@ def test_present(): ): ret = host.present(hostname, ip_list, comment="A comment") assert ret["result"] is True - assert "Added host {} ({})".format(hostname, ip_list[0]) in ret["comment"] - assert "Added host {} ({})".format(hostname, ip_list[1]) in ret["comment"] - assert ( - "Set comment for host {} (A comment)".format(ip_list[0]) in ret["comment"] - ) - assert ( - "Set comment for host {} (A comment)".format(ip_list[1]) in ret["comment"] - ) + assert f"Added host {hostname} ({ip_list[0]})" in ret["comment"] + assert f"Added host {hostname} ({ip_list[1]})" in ret["comment"] + assert f"Set comment for host {ip_list[0]} (A comment)" in ret["comment"] + assert f"Set comment for host {ip_list[1]} (A comment)" in ret["comment"] assert ret["changes"] == { "added": {ip_list[0]: [hostname], ip_list[1]: [hostname]}, "comment_added": {ip_list[0]: ["A comment"], ip_list[1]: ["A comment"]}, diff --git a/tests/pytests/unit/states/test_incron.py b/tests/pytests/unit/states/test_incron.py index 54415c01dcd..0b57680bac9 100644 --- a/tests/pytests/unit/states/test_incron.py +++ b/tests/pytests/unit/states/test_incron.py @@ -27,7 +27,7 @@ def test_present(): ret = {"name": name, "result": None, "comment": "", "changes": {}} - comt4 = "Incron {} for user root failed to commit with error \nabsent".format(name) + comt4 = f"Incron {name} for user root failed to commit with error \nabsent" mock_dict = MagicMock( return_value={"crons": [{"path": path, "cmd": cmd, "mask": mask}]} ) @@ -36,20 +36,20 @@ def test_present(): incron.__salt__, {"incron.list_tab": mock_dict, "incron.set_job": mock} ): with patch.dict(incron.__opts__, {"test": True}): - comt = "Incron {} is set to be added".format(name) + comt = f"Incron {name} is set to be added" ret.update({"comment": comt}) assert incron.present(name, path, mask, cmd) == ret with patch.dict(incron.__opts__, {"test": False}): - comt = "Incron {} already present".format(name) + comt = f"Incron {name} already present" ret.update({"comment": comt, "result": True}) assert incron.present(name, path, mask, cmd) == ret - comt = "Incron {} added to root's incrontab".format(name) + comt = f"Incron {name} added to root's incrontab" ret.update({"comment": comt, "changes": {"root": "salt"}}) assert incron.present(name, path, mask, cmd) == ret - comt = "Incron {} updated".format(name) + comt = f"Incron {name} updated" ret.update({"comment": comt}) assert incron.present(name, path, mask, cmd) == ret @@ -69,7 +69,7 @@ def test_absent(): ret = {"name": name, "result": True, "comment": "", "changes": {}} - comt4 = "Incron {} for user root failed to commit with error new".format(name) + comt4 = f"Incron {name} for user root failed to commit with error new" mock_dict = MagicMock( return_value={"crons": [{"path": path, "cmd": cmd, "mask": mask}]} ) @@ -78,16 +78,16 @@ def test_absent(): incron.__salt__, {"incron.list_tab": mock_dict, "incron.rm_job": mock} ): with patch.dict(incron.__opts__, {"test": True}): - comt = "Incron {} is absent".format(name) + comt = f"Incron {name} is absent" ret.update({"comment": comt}) assert incron.absent(name, path, mask, cmd) == ret with patch.dict(incron.__opts__, {"test": False}): - comt = "Incron {} already absent".format(name) + comt = f"Incron {name} already absent" ret.update({"comment": comt, "result": True}) assert incron.absent(name, path, mask, cmd) == ret - comt = "Incron {} removed from root's crontab".format(name) + comt = f"Incron {name} removed from root's crontab" ret.update({"comment": comt, "changes": {"root": "salt"}}) assert incron.absent(name, path, mask, cmd) == ret diff --git a/tests/pytests/unit/states/test_influxdb08_database.py b/tests/pytests/unit/states/test_influxdb08_database.py index d5685de2131..6b93b946586 100644 --- a/tests/pytests/unit/states/test_influxdb08_database.py +++ b/tests/pytests/unit/states/test_influxdb08_database.py @@ -28,22 +28,22 @@ def test_present(): {"influxdb08.db_exists": mock, "influxdb08.db_create": mock_t}, ): with patch.dict(influxdb08_database.__opts__, {"test": True}): - comt = "Database {} is absent and needs to be created".format(name) + comt = f"Database {name} is absent and needs to be created" ret.update({"comment": comt}) assert influxdb08_database.present(name) == ret with patch.dict(influxdb08_database.__opts__, {"test": False}): - comt = "Database {} has been created".format(name) + comt = f"Database {name} has been created" ret.update( {"comment": comt, "result": True, "changes": {"salt": "Present"}} ) assert influxdb08_database.present(name) == ret - comt = "Failed to create database {}".format(name) + comt = f"Failed to create database {name}" ret.update({"comment": comt, "result": False, "changes": {}}) assert influxdb08_database.present(name) == ret - comt = "Database {} is already present, so cannot be created".format(name) + comt = f"Database {name} is already present, so cannot be created" ret.update({"comment": comt, "result": True}) assert influxdb08_database.present(name) == ret @@ -63,19 +63,19 @@ def test_absent(): {"influxdb08.db_exists": mock, "influxdb08.db_remove": mock_t}, ): with patch.dict(influxdb08_database.__opts__, {"test": True}): - comt = "Database {} is present and needs to be removed".format(name) + comt = f"Database {name} is present and needs to be removed" ret.update({"comment": comt}) assert influxdb08_database.absent(name) == ret with patch.dict(influxdb08_database.__opts__, {"test": False}): - comt = "Database {} has been removed".format(name) + comt = f"Database {name} has been removed" ret.update({"comment": comt, "result": True, "changes": {"salt": "Absent"}}) assert influxdb08_database.absent(name) == ret - comt = "Failed to remove database {}".format(name) + comt = f"Failed to remove database {name}" ret.update({"comment": comt, "result": False, "changes": {}}) assert influxdb08_database.absent(name) == ret - comt = "Database {} is not present, so it cannot be removed".format(name) + comt = f"Database {name} is not present, so it cannot be removed" ret.update({"comment": comt, "result": True}) assert influxdb08_database.absent(name) == ret diff --git a/tests/pytests/unit/states/test_influxdb08_user.py b/tests/pytests/unit/states/test_influxdb08_user.py index d5f4f29131b..32d5565478b 100644 --- a/tests/pytests/unit/states/test_influxdb08_user.py +++ b/tests/pytests/unit/states/test_influxdb08_user.py @@ -38,22 +38,22 @@ def test_present(): assert influxdb08_user.present(name, passwd, database="mydb") == ret with patch.dict(influxdb08_user.__opts__, {"test": True}): - comt = "User {} is not present and needs to be created".format(name) + comt = f"User {name} is not present and needs to be created" ret.update({"comment": comt, "result": None}) assert influxdb08_user.present(name, passwd) == ret with patch.dict(influxdb08_user.__opts__, {"test": False}): - comt = "User {} has been created".format(name) + comt = f"User {name} has been created" ret.update( {"comment": comt, "result": True, "changes": {"salt": "Present"}} ) assert influxdb08_user.present(name, passwd) == ret - comt = "Failed to create user {}".format(name) + comt = f"Failed to create user {name}" ret.update({"comment": comt, "result": False, "changes": {}}) assert influxdb08_user.present(name, passwd) == ret - comt = "User {} is already present".format(name) + comt = f"User {name} is already present" ret.update({"comment": comt, "result": True}) assert influxdb08_user.present(name, passwd) == ret @@ -73,19 +73,19 @@ def test_absent(): {"influxdb08.user_exists": mock, "influxdb08.user_remove": mock_t}, ): with patch.dict(influxdb08_user.__opts__, {"test": True}): - comt = "User {} is present and needs to be removed".format(name) + comt = f"User {name} is present and needs to be removed" ret.update({"comment": comt}) assert influxdb08_user.absent(name) == ret with patch.dict(influxdb08_user.__opts__, {"test": False}): - comt = "User {} has been removed".format(name) + comt = f"User {name} has been removed" ret.update({"comment": comt, "result": True, "changes": {"salt": "Absent"}}) assert influxdb08_user.absent(name) == ret - comt = "Failed to remove user {}".format(name) + comt = f"Failed to remove user {name}" ret.update({"comment": comt, "result": False, "changes": {}}) assert influxdb08_user.absent(name) == ret - comt = "User {} is not present, so it cannot be removed".format(name) + comt = f"User {name} is not present, so it cannot be removed" ret.update({"comment": comt, "result": True}) assert influxdb08_user.absent(name) == ret diff --git a/tests/pytests/unit/states/test_ini_manage.py b/tests/pytests/unit/states/test_ini_manage.py index 9f0217b5b40..0401b5761f3 100644 --- a/tests/pytests/unit/states/test_ini_manage.py +++ b/tests/pytests/unit/states/test_ini_manage.py @@ -2,7 +2,6 @@ Test cases for salt.states.ini_manage """ - import copy import os diff --git a/tests/pytests/unit/states/test_iptables.py b/tests/pytests/unit/states/test_iptables.py index cb372f99a64..19e8d6d4150 100644 --- a/tests/pytests/unit/states/test_iptables.py +++ b/tests/pytests/unit/states/test_iptables.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.states.iptables as iptables diff --git a/tests/pytests/unit/states/test_kapacitor.py b/tests/pytests/unit/states/test_kapacitor.py index df748455541..172852f2744 100644 --- a/tests/pytests/unit/states/test_kapacitor.py +++ b/tests/pytests/unit/states/test_kapacitor.py @@ -2,7 +2,6 @@ Test cases for salt.states.kapacitor """ - import pytest import salt.states.kapacitor as kapacitor diff --git a/tests/pytests/unit/states/test_kernelpkg.py b/tests/pytests/unit/states/test_kernelpkg.py index 22b3cbf2db0..7aa35f6a556 100644 --- a/tests/pytests/unit/states/test_kernelpkg.py +++ b/tests/pytests/unit/states/test_kernelpkg.py @@ -2,7 +2,6 @@ Test cases for salt.states.kernelpkg """ - import pytest import salt.states.kernelpkg as kernelpkg diff --git a/tests/pytests/unit/states/test_keyboard.py b/tests/pytests/unit/states/test_keyboard.py index 5c00bc21e07..a642ae35308 100644 --- a/tests/pytests/unit/states/test_keyboard.py +++ b/tests/pytests/unit/states/test_keyboard.py @@ -29,17 +29,17 @@ def test_system(): with patch.dict( keyboard.__salt__, {"keyboard.get_sys": mock, "keyboard.set_sys": mock_t} ): - comt = "System layout {} already set".format(name) + comt = f"System layout {name} already set" ret.update({"comment": comt}) assert keyboard.system(name) == ret with patch.dict(keyboard.__opts__, {"test": True}): - comt = "System layout {} needs to be set".format(name) + comt = f"System layout {name} needs to be set" ret.update({"comment": comt, "result": None}) assert keyboard.system(name) == ret with patch.dict(keyboard.__opts__, {"test": False}): - comt = "Set system keyboard layout {}".format(name) + comt = f"Set system keyboard layout {name}" ret.update({"comment": comt, "result": True, "changes": {"layout": name}}) assert keyboard.system(name) == ret @@ -64,17 +64,17 @@ def test_xorg(): with patch.dict( keyboard.__salt__, {"keyboard.get_x": mock, "keyboard.set_x": mock_t} ): - comt = "XOrg layout {} already set".format(name) + comt = f"XOrg layout {name} already set" ret.update({"comment": comt}) assert keyboard.xorg(name) == ret with patch.dict(keyboard.__opts__, {"test": True}): - comt = "XOrg layout {} needs to be set".format(name) + comt = f"XOrg layout {name} needs to be set" ret.update({"comment": comt, "result": None}) assert keyboard.xorg(name) == ret with patch.dict(keyboard.__opts__, {"test": False}): - comt = "Set XOrg keyboard layout {}".format(name) + comt = f"Set XOrg keyboard layout {name}" ret.update({"comment": comt, "result": True, "changes": {"layout": name}}) assert keyboard.xorg(name) == ret diff --git a/tests/pytests/unit/states/test_keystone.py b/tests/pytests/unit/states/test_keystone.py index d0461180433..46b8c37141f 100644 --- a/tests/pytests/unit/states/test_keystone.py +++ b/tests/pytests/unit/states/test_keystone.py @@ -30,7 +30,7 @@ def test_user_present(): mock_f = MagicMock(return_value=False) mock_lst = MagicMock(return_value=["Error"]) with patch.dict(keystone.__salt__, {"keystone.tenant_get": mock_lst}): - comt = 'Tenant / project "{}" does not exist'.format(tenant) + comt = f'Tenant / project "{tenant}" does not exist' ret.update({"comment": comt}) assert keystone.user_present(name, password, email, tenant) == ret @@ -55,7 +55,7 @@ def test_user_present(): }, ): with patch.dict(keystone.__opts__, {"test": True}): - comt = 'User "{}" will be updated'.format(name) + comt = f'User "{name}" will be updated' ret.update( { "comment": comt, @@ -113,7 +113,7 @@ def test_user_present(): assert keystone.user_present(name, password, email) == ret with patch.dict(keystone.__opts__, {"test": False}): - comt = "Keystone user {} has been added".format(name) + comt = f"Keystone user {name} has been added" ret.update( {"comment": comt, "result": True, "changes": {"User": "Created"}} ) @@ -130,7 +130,7 @@ def test_user_absent(): "name": name, "changes": {}, "result": True, - "comment": 'User "{}" is already absent'.format(name), + "comment": f'User "{name}" is already absent', } mock_lst = MagicMock(side_effect=[["Error"], []]) @@ -138,7 +138,7 @@ def test_user_absent(): assert keystone.user_absent(name) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'User "{}" will be deleted'.format(name) + comt = f'User "{name}" will be deleted' ret.update({"comment": comt, "result": None}) assert keystone.user_absent(name) == ret @@ -154,7 +154,7 @@ def test_tenant_present(): "name": name, "changes": {}, "result": True, - "comment": 'Tenant / project "{}" already exists'.format(name), + "comment": f'Tenant / project "{name}" already exists', } mock_dict = MagicMock( @@ -171,7 +171,7 @@ def test_tenant_present(): {"keystone.tenant_get": mock_dict, "keystone.tenant_create": mock_t}, ): with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Tenant / project "{}" will be updated'.format(name) + comt = f'Tenant / project "{name}" will be updated' ret.update( { "comment": comt, @@ -181,7 +181,7 @@ def test_tenant_present(): ) assert keystone.tenant_present(name) == ret - comt = 'Tenant / project "{}" will be updated'.format(name) + comt = f'Tenant / project "{name}" will be updated' ret.update( { "comment": comt, @@ -191,7 +191,7 @@ def test_tenant_present(): ) assert keystone.tenant_present(name, description) == ret - comt = 'Tenant / project "{}" will be added'.format(name) + comt = f'Tenant / project "{name}" will be added' ret.update( { "comment": comt, @@ -202,7 +202,7 @@ def test_tenant_present(): assert keystone.tenant_present(name) == ret with patch.dict(keystone.__opts__, {"test": False}): - comt = 'Tenant / project "{}" has been added'.format(name) + comt = f'Tenant / project "{name}" has been added' ret.update( {"comment": comt, "result": True, "changes": {"Tenant": "Created"}} ) @@ -219,7 +219,7 @@ def test_tenant_absent(): "name": name, "changes": {}, "result": True, - "comment": 'Tenant / project "{}" is already absent'.format(name), + "comment": f'Tenant / project "{name}" is already absent', } mock_lst = MagicMock(side_effect=[["Error"], []]) @@ -227,7 +227,7 @@ def test_tenant_absent(): assert keystone.tenant_absent(name) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Tenant / project "{}" will be deleted'.format(name) + comt = f'Tenant / project "{name}" will be deleted' ret.update({"comment": comt, "result": None}) assert keystone.tenant_absent(name) == ret @@ -242,7 +242,7 @@ def test_role_present(): "name": name, "changes": {}, "result": True, - "comment": 'Role "{}" already exists'.format(name), + "comment": f'Role "{name}" already exists', } mock_lst = MagicMock(side_effect=[[], ["Error"]]) @@ -250,7 +250,7 @@ def test_role_present(): assert keystone.role_present(name) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Role "{}" will be added'.format(name) + comt = f'Role "{name}" will be added' ret.update({"comment": comt, "result": None}) assert keystone.role_present(name) == ret @@ -265,7 +265,7 @@ def test_role_absent(): "name": name, "changes": {}, "result": True, - "comment": 'Role "{}" is already absent'.format(name), + "comment": f'Role "{name}" is already absent', } mock_lst = MagicMock(side_effect=[["Error"], []]) @@ -273,7 +273,7 @@ def test_role_absent(): assert keystone.role_absent(name) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Role "{}" will be deleted'.format(name) + comt = f'Role "{name}" will be deleted' ret.update({"comment": comt, "result": None}) assert keystone.role_absent(name) == ret @@ -289,7 +289,7 @@ def test_service_present(): "name": name, "changes": {}, "result": True, - "comment": 'Service "{}" already exists'.format(name), + "comment": f'Service "{name}" already exists', } mock_lst = MagicMock(side_effect=[[], ["Error"]]) @@ -297,7 +297,7 @@ def test_service_present(): assert keystone.service_present(name, service_type) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Service "{}" will be added'.format(name) + comt = f'Service "{name}" will be added' ret.update({"comment": comt, "result": None}) assert keystone.service_present(name, service_type) == ret @@ -312,7 +312,7 @@ def test_service_absent(): "name": name, "changes": {}, "result": True, - "comment": 'Service "{}" is already absent'.format(name), + "comment": f'Service "{name}" is already absent', } mock_lst = MagicMock(side_effect=[["Error"], []]) @@ -320,7 +320,7 @@ def test_service_absent(): assert keystone.service_absent(name) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Service "{}" will be deleted'.format(name) + comt = f'Service "{name}" will be deleted' ret.update({"comment": comt, "result": None}) assert keystone.service_absent(name) == ret @@ -352,12 +352,12 @@ def test_endpoint_present(): {"keystone.endpoint_get": mock_lst, "keystone.endpoint_create": mock}, ): - comt = 'Endpoint for service "{}" already exists'.format(name) + comt = f'Endpoint for service "{name}" already exists' ret.update({"comment": comt, "result": True, "changes": {}}) assert keystone.endpoint_present(name) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Endpoint for service "{}" will be added'.format(name) + comt = f'Endpoint for service "{name}" will be added' ret.update( { "comment": comt, @@ -367,12 +367,12 @@ def test_endpoint_present(): ) assert keystone.endpoint_present(name) == ret - comt = 'Endpoint for service "{}" already exists'.format(name) + comt = f'Endpoint for service "{name}" already exists' ret.update({"comment": comt, "result": True, "changes": {}}) assert keystone.endpoint_present(name) == ret with patch.dict(keystone.__opts__, {"test": False}): - comt = 'Endpoint for service "{}" has been added'.format(name) + comt = f'Endpoint for service "{name}" has been added' ret.update({"comment": comt, "result": True, "changes": True}) assert keystone.endpoint_present(name) == ret @@ -384,7 +384,7 @@ def test_endpoint_absent(): """ name = "nova" region = "RegionOne" - comment = 'Endpoint for service "{}" is already absent'.format(name) + comment = f'Endpoint for service "{name}" is already absent' ret = {"name": name, "changes": {}, "result": True, "comment": comment} mock_lst = MagicMock(side_effect=[[], ["Error"]]) @@ -392,6 +392,6 @@ def test_endpoint_absent(): assert keystone.endpoint_absent(name, region) == ret with patch.dict(keystone.__opts__, {"test": True}): - comt = 'Endpoint for service "{}" will be deleted'.format(name) + comt = f'Endpoint for service "{name}" will be deleted' ret.update({"comment": comt, "result": None}) assert keystone.endpoint_absent(name, region) == ret diff --git a/tests/pytests/unit/states/test_kmod.py b/tests/pytests/unit/states/test_kmod.py index a4ec3dbc17c..a4375d5ad2c 100644 --- a/tests/pytests/unit/states/test_kmod.py +++ b/tests/pytests/unit/states/test_kmod.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.kmod as kmod @@ -21,14 +22,14 @@ def test_present(): mock_mod_list = MagicMock(return_value=[name]) with patch.dict(kmod.__salt__, {"kmod.mod_list": mock_mod_list}): - comment = "Kernel module {} is already present".format(name) + comment = f"Kernel module {name} is already present" ret.update({"comment": comment}) assert kmod.present(name) == ret mock_mod_list = MagicMock(return_value=[]) with patch.dict(kmod.__salt__, {"kmod.mod_list": mock_mod_list}): with patch.dict(kmod.__opts__, {"test": True}): - comment = "Kernel module {} is set to be loaded".format(name) + comment = f"Kernel module {name} is set to be loaded" ret.update({"comment": comment, "result": None}) assert kmod.present(name) == ret @@ -44,7 +45,7 @@ def test_present(): }, ): with patch.dict(kmod.__opts__, {"test": False}): - comment = "Loaded kernel module {}".format(name) + comment = f"Loaded kernel module {name}" ret.update( {"comment": comment, "result": True, "changes": {name: "loaded"}} ) @@ -124,7 +125,7 @@ def test_absent(): mock_mod_list = MagicMock(return_value=[name]) with patch.dict(kmod.__salt__, {"kmod.mod_list": mock_mod_list}): with patch.dict(kmod.__opts__, {"test": True}): - comment = "Kernel module {} is set to be removed".format(name) + comment = f"Kernel module {name} is set to be removed" ret.update({"comment": comment, "result": None}) assert kmod.absent(name) == ret @@ -134,7 +135,7 @@ def test_absent(): kmod.__salt__, {"kmod.mod_list": mock_mod_list, "kmod.remove": mock_remove} ): with patch.dict(kmod.__opts__, {"test": False}): - comment = "Removed kernel module {}".format(name) + comment = f"Removed kernel module {name}" ret.update( {"comment": comment, "result": True, "changes": {name: "removed"}} ) @@ -143,7 +144,7 @@ def test_absent(): mock_mod_list = MagicMock(return_value=[]) with patch.dict(kmod.__salt__, {"kmod.mod_list": mock_mod_list}): with patch.dict(kmod.__opts__, {"test": True}): - comment = "Kernel module {} is already removed".format(name) + comment = f"Kernel module {name} is already removed" ret.update({"comment": comment, "result": True, "changes": {}}) assert kmod.absent(name) == ret diff --git a/tests/pytests/unit/states/test_layman.py b/tests/pytests/unit/states/test_layman.py index ad3dec64b74..7979f665782 100644 --- a/tests/pytests/unit/states/test_layman.py +++ b/tests/pytests/unit/states/test_layman.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.states.layman as layman @@ -22,12 +23,12 @@ def test_present(): mock = MagicMock(side_effect=[[name], []]) with patch.dict(layman.__salt__, {"layman.list_local": mock}): - comt = "Overlay {} already present".format(name) + comt = f"Overlay {name} already present" ret.update({"comment": comt}) assert layman.present(name) == ret with patch.dict(layman.__opts__, {"test": True}): - comt = "Overlay {} is set to be added".format(name) + comt = f"Overlay {name} is set to be added" ret.update({"comment": comt, "result": None}) assert layman.present(name) == ret @@ -42,11 +43,11 @@ def test_absent(): mock = MagicMock(side_effect=[[], [name]]) with patch.dict(layman.__salt__, {"layman.list_local": mock}): - comt = "Overlay {} already absent".format(name) + comt = f"Overlay {name} already absent" ret.update({"comment": comt}) assert layman.absent(name) == ret with patch.dict(layman.__opts__, {"test": True}): - comt = "Overlay {} is set to be deleted".format(name) + comt = f"Overlay {name} is set to be deleted" ret.update({"comment": comt, "result": None}) assert layman.absent(name) == ret diff --git a/tests/pytests/unit/states/test_ldap.py b/tests/pytests/unit/states/test_ldap.py index bf57549fd9c..99d0e36a36e 100644 --- a/tests/pytests/unit/states/test_ldap.py +++ b/tests/pytests/unit/states/test_ldap.py @@ -7,6 +7,7 @@ was an ugly second implementation. I'm leaving it for now, but this should really be gutted and replaced with something sensible. """ + import copy import logging @@ -239,20 +240,24 @@ def _test_helper(init_db, expected_ret, replace, delete_others=False): "changes", { dn: { - "old": { - attr: vals - for attr, vals in old[dn].items() - if vals != new.get(dn, {}).get(attr, ()) - } - if dn in old - else None, - "new": { - attr: vals - for attr, vals in new[dn].items() - if vals != old.get(dn, {}).get(attr, ()) - } - if dn in new - else None, + "old": ( + { + attr: vals + for attr, vals in old[dn].items() + if vals != new.get(dn, {}).get(attr, ()) + } + if dn in old + else None + ), + "new": ( + { + attr: vals + for attr, vals in new[dn].items() + if vals != old.get(dn, {}).get(attr, ()) + } + if dn in new + else None + ), } for dn in replace if old.get(dn, {}) != new.get(dn, {}) @@ -323,20 +328,24 @@ def _test_helper_add(db, expected_ret, add_items, delete_others=False): "changes", { dn: { - "old": { - attr: vals - for attr, vals in old[dn].items() - if vals != new.get(dn, {}).get(attr, ()) - } - if dn in old - else None, - "new": { - attr: vals - for attr, vals in new[dn].items() - if vals != old.get(dn, {}).get(attr, ()) - } - if dn in new - else None, + "old": ( + { + attr: vals + for attr, vals in old[dn].items() + if vals != new.get(dn, {}).get(attr, ()) + } + if dn in old + else None + ), + "new": ( + { + attr: vals + for attr, vals in new[dn].items() + if vals != old.get(dn, {}).get(attr, ()) + } + if dn in new + else None + ), } for dn in add_items if old.get(dn, {}) != new.get(dn, {}) diff --git a/tests/pytests/unit/states/test_libcloud_dns.py b/tests/pytests/unit/states/test_libcloud_dns.py index 230ecb940d1..92e87531213 100644 --- a/tests/pytests/unit/states/test_libcloud_dns.py +++ b/tests/pytests/unit/states/test_libcloud_dns.py @@ -2,7 +2,6 @@ :codeauthor: Anthony Shaw """ - import pytest import salt.states.libcloud_dns as libcloud_dns diff --git a/tests/pytests/unit/states/test_linux_acl.py b/tests/pytests/unit/states/test_linux_acl.py index 60bbe55f51c..5a3d070a3d2 100644 --- a/tests/pytests/unit/states/test_linux_acl.py +++ b/tests/pytests/unit/states/test_linux_acl.py @@ -93,7 +93,7 @@ def test_present(): # Update - test=False with patch.dict(linux_acl.__salt__, {"acl.modfacl": mock_modfacl}): with patch.dict(linux_acl.__opts__, {"test": False}): - comt = "Updated permissions for {}".format(acl_name) + comt = f"Updated permissions for {acl_name}" ret = { "name": name, "comment": comt, @@ -118,7 +118,7 @@ def test_present(): {"acl.modfacl": MagicMock(side_effect=CommandExecutionError("Custom err"))}, ): with patch.dict(linux_acl.__opts__, {"test": False}): - comt = "Error updating permissions for {}: Custom err".format(acl_name) + comt = f"Error updating permissions for {acl_name}: Custom err" ret = { "name": name, "comment": comt, @@ -148,7 +148,7 @@ def test_present(): # New - test=False with patch.dict(linux_acl.__salt__, {"acl.modfacl": mock_modfacl}): with patch.dict(linux_acl.__opts__, {"test": False}): - comt = "Applied new permissions for {}".format(acl_name) + comt = f"Applied new permissions for {acl_name}" ret = { "name": name, "comment": comt, @@ -168,7 +168,7 @@ def test_present(): {"acl.modfacl": MagicMock(side_effect=CommandExecutionError("Custom err"))}, ): with patch.dict(linux_acl.__opts__, {"test": False}): - comt = "Error updating permissions for {}: Custom err".format(acl_name) + comt = f"Error updating permissions for {acl_name}: Custom err" ret = { "name": name, "comment": comt, @@ -395,7 +395,7 @@ def test_list_present(): {"acl.modfacl": MagicMock(side_effect=CommandExecutionError("Custom err"))}, ): with patch.dict(linux_acl.__opts__, {"test": False}): - comt = "Error updating permissions for {}: Custom err".format(acl_names) + comt = f"Error updating permissions for {acl_names}: Custom err" expected = { "name": name, "comment": comt, @@ -453,7 +453,7 @@ def test_list_present(): {"acl.modfacl": MagicMock(side_effect=CommandExecutionError("Custom err"))}, ): with patch.dict(linux_acl.__opts__, {"test": False}): - comt = "Error updating permissions for {}: Custom err".format(acl_names) + comt = f"Error updating permissions for {acl_names}: Custom err" expected = { "name": name, "comment": comt, diff --git a/tests/pytests/unit/states/test_lvm.py b/tests/pytests/unit/states/test_lvm.py index 10975dcdbd7..c2590c3277c 100644 --- a/tests/pytests/unit/states/test_lvm.py +++ b/tests/pytests/unit/states/test_lvm.py @@ -62,7 +62,7 @@ def test_pv_present(): """ name = "/dev/sda5" - comt = "Physical Volume {} already present".format(name) + comt = f"Physical Volume {name} already present" ret = {"name": name, "changes": {}, "result": True, "comment": comt} @@ -70,7 +70,7 @@ def test_pv_present(): with patch.dict(lvm.__salt__, {"lvm.pvdisplay": mock}): assert lvm.pv_present(name) == ret - comt = "Physical Volume {} is set to be created".format(name) + comt = f"Physical Volume {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.pv_present(name) == ret @@ -82,7 +82,7 @@ def test_pv_absent(): """ name = "/dev/sda5" - comt = "Physical Volume {} does not exist".format(name) + comt = f"Physical Volume {name} does not exist" ret = {"name": name, "changes": {}, "result": True, "comment": comt} @@ -90,7 +90,7 @@ def test_pv_absent(): with patch.dict(lvm.__salt__, {"lvm.pvdisplay": mock}): assert lvm.pv_absent(name) == ret - comt = "Physical Volume {} is set to be removed".format(name) + comt = f"Physical Volume {name} is set to be removed" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.pv_absent(name) == ret @@ -102,7 +102,7 @@ def test_vg_present(): """ name = "testvg00" - comt = "Failed to create Volume Group {}".format(name) + comt = f"Failed to create Volume Group {name}" ret = {"name": name, "changes": {}, "result": False, "comment": comt} @@ -111,7 +111,7 @@ def test_vg_present(): with patch.dict(lvm.__opts__, {"test": False}): assert lvm.vg_present(name) == ret - comt = "Volume Group {} is set to be created".format(name) + comt = f"Volume Group {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.vg_present(name) == ret @@ -123,7 +123,7 @@ def test_vg_absent(): """ name = "testvg00" - comt = "Volume Group {} already absent".format(name) + comt = f"Volume Group {name} already absent" ret = {"name": name, "changes": {}, "result": True, "comment": comt} @@ -131,7 +131,7 @@ def test_vg_absent(): with patch.dict(lvm.__salt__, {"lvm.vgdisplay": mock}): assert lvm.vg_absent(name) == ret - comt = "Volume Group {} is set to be removed".format(name) + comt = f"Volume Group {name} is set to be removed" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.vg_absent(name) == ret @@ -143,7 +143,7 @@ def test_lv_present(lv01, lv02): """ name = "testlv01" vgname = "testvg01" - comt = "Logical Volume {} already present".format(name) + comt = f"Logical Volume {name} already present" ret = {"name": name, "changes": {}, "result": True, "comment": comt} mock = MagicMock(return_value=lv01) @@ -152,7 +152,7 @@ def test_lv_present(lv01, lv02): mock = MagicMock(return_value=lv02) with patch.dict(lvm.__salt__, {"lvm.lvdisplay": mock}): - comt = "Logical Volume {} is set to be created".format(name) + comt = f"Logical Volume {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.lv_present(name, vgname=vgname) == ret @@ -177,7 +177,7 @@ def test_lv_present_with_valid_suffixes(lv01, lv02): "4194304s", "4194304S", ] - comt = "Logical Volume {} already present".format(name) + comt = f"Logical Volume {name} already present" ret = {"name": name, "changes": {}, "result": True, "comment": comt} mock = MagicMock(return_value=lv01) @@ -207,7 +207,7 @@ def test_lv_present_with_valid_suffixes(lv01, lv02): ] mock = MagicMock(return_value=lv02) with patch.dict(lvm.__salt__, {"lvm.lvdisplay": mock}): - comt = "Logical Volume {} is set to be created".format(name) + comt = f"Logical Volume {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): for size in sizes_list: @@ -221,12 +221,12 @@ def test_lv_present_with_invalid_suffixes(lv02): name = "testlv01" vgname = "testvg01" sizes_list = ["1B", "1b", "2K", "2k", "2KB", "2kb", "3BB", "3Bb", "4JKL", "YJK"] - comt = "Logical Volume {} already present".format(name) + comt = f"Logical Volume {name} already present" ret = {"name": name, "changes": {}, "result": True, "comment": comt} mock = MagicMock(return_value=lv02) with patch.dict(lvm.__salt__, {"lvm.lvdisplay": mock}): - comt = "Logical Volume {} is set to be created".format(name) + comt = f"Logical Volume {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): for size in sizes_list: @@ -258,7 +258,7 @@ def test_lv_present_with_percentage_extents(lv01, lv02): extents = "42%VG" mock = MagicMock(return_value=lv02) with patch.dict(lvm.__salt__, {"lvm.lvdisplay": mock}): - comt = "Logical Volume {} is set to be created".format(name) + comt = f"Logical Volume {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.lv_present(name, vgname=vgname, extents=extents) == ret @@ -270,7 +270,7 @@ def test_lv_present_with_force(lv01, lv02): """ name = "testlv01" vgname = "testvg01" - comt = "Logical Volume {} already present".format(name) + comt = f"Logical Volume {name} already present" ret = {"name": name, "changes": {}, "result": True, "comment": comt} mock = MagicMock(return_value=lv01) @@ -279,7 +279,7 @@ def test_lv_present_with_force(lv01, lv02): mock = MagicMock(return_value=lv02) with patch.dict(lvm.__salt__, {"lvm.lvdisplay": mock}): - comt = "Logical Volume {} is set to be created".format(name) + comt = f"Logical Volume {name} is set to be created" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.lv_present(name, vgname=vgname, force=True) == ret @@ -291,7 +291,7 @@ def test_lv_present_with_same_size(lv01): """ name = "testlv01" vgname = "testvg01" - comt = "Logical Volume {} already present".format(name) + comt = f"Logical Volume {name} already present" ret = {"name": name, "changes": {}, "result": True, "comment": comt} mock = MagicMock(return_value=lv01) @@ -305,7 +305,7 @@ def test_lv_present_with_increase(lv01): """ name = "testlv01" vgname = "testvg01" - comt = "Logical Volume {} is set to be resized".format(name) + comt = f"Logical Volume {name} is set to be resized" ret = {"name": name, "changes": {}, "result": None, "comment": comt} mock = MagicMock(return_value=lv01) @@ -334,7 +334,7 @@ def test_lv_present_with_reduce_with_force(lv01): """ name = "testlv01" vgname = "testvg01" - comt = "Logical Volume {} is set to be resized".format(name) + comt = f"Logical Volume {name} is set to be resized" ret = {"name": name, "changes": {}, "result": None, "comment": comt} mock = MagicMock(return_value=lv01) @@ -349,7 +349,7 @@ def test_lv_absent(): """ name = "testlv00" - comt = "Logical Volume {} already absent".format(name) + comt = f"Logical Volume {name} already absent" ret = {"name": name, "changes": {}, "result": True, "comment": comt} @@ -357,7 +357,7 @@ def test_lv_absent(): with patch.dict(lvm.__salt__, {"lvm.lvdisplay": mock}): assert lvm.lv_absent(name) == ret - comt = "Logical Volume {} is set to be removed".format(name) + comt = f"Logical Volume {name} is set to be removed" ret.update({"comment": comt, "result": None}) with patch.dict(lvm.__opts__, {"test": True}): assert lvm.lv_absent(name) == ret diff --git a/tests/pytests/unit/states/test_lxc.py b/tests/pytests/unit/states/test_lxc.py index 3ee57f1b3e7..398a0456f2f 100644 --- a/tests/pytests/unit/states/test_lxc.py +++ b/tests/pytests/unit/states/test_lxc.py @@ -44,7 +44,7 @@ def test_present(): ret.update({"comment": comt, "result": None}) assert lxc.present(name, running=True, clone_from=True) == ret - comt = "Container '{}' would be stopped".format(name) + comt = f"Container '{name}' would be stopped" ret.update({"comment": comt, "result": None}) assert lxc.present(name, running=False, clone_from=True) == ret @@ -69,17 +69,17 @@ def test_absent(): mock = MagicMock(side_effect=[False, True, True]) mock_des = MagicMock(return_value={"state": True}) with patch.dict(lxc.__salt__, {"lxc.exists": mock, "lxc.destroy": mock_des}): - comt = "Container '{}' does not exist".format(name) + comt = f"Container '{name}' does not exist" ret.update({"comment": comt}) assert lxc.absent(name) == ret with patch.dict(lxc.__opts__, {"test": True}): - comt = "Container '{}' would be destroyed".format(name) + comt = f"Container '{name}' would be destroyed" ret.update({"comment": comt, "result": None}) assert lxc.absent(name) == ret with patch.dict(lxc.__opts__, {"test": False}): - comt = "Container '{}' was destroyed".format(name) + comt = f"Container '{name}' was destroyed" ret.update({"comment": comt, "result": True, "changes": {"state": True}}) assert lxc.absent(name) == ret @@ -97,7 +97,7 @@ def test_running(): with patch.dict( lxc.__salt__, {"lxc.exists": mock, "lxc.state": mock_t, "lxc.start": mock} ): - comt = "Container '{}' does not exist".format(name) + comt = f"Container '{name}' does not exist" ret.update({"comment": comt}) assert lxc.running(name) == ret @@ -133,7 +133,7 @@ def test_frozen(): mock = MagicMock(return_value={"state": {"new": "stop"}}) mock_t = MagicMock(side_effect=["frozen", "stopped", "stopped"]) with patch.dict(lxc.__salt__, {"lxc.freeze": mock, "lxc.state": mock_t}): - comt = "Container '{}' is already frozen".format(name) + comt = f"Container '{name}' is already frozen" ret.update({"comment": comt}) assert lxc.frozen(name) == ret @@ -165,11 +165,11 @@ def test_stopped(): mock = MagicMock(return_value={"state": {"new": "stop"}}) mock_t = MagicMock(side_effect=[None, "stopped", "frozen", "frozen"]) with patch.dict(lxc.__salt__, {"lxc.stop": mock, "lxc.state": mock_t}): - comt = "Container '{}' does not exist".format(name) + comt = f"Container '{name}' does not exist" ret.update({"comment": comt}) assert lxc.stopped(name) == ret - comt = "Container '{}' is already stopped".format(name) + comt = f"Container '{name}' is already stopped" ret.update({"comment": comt, "result": True}) assert lxc.stopped(name) == ret @@ -209,7 +209,7 @@ def test_edited_conf(): """ name = "web01" - comment = "{} lxc.conf will be edited".format(name) + comment = f"{name} lxc.conf will be edited" ret = {"name": name, "result": True, "comment": comment, "changes": {}} diff --git a/tests/pytests/unit/states/test_makeconf.py b/tests/pytests/unit/states/test_makeconf.py index 7f7b3a4fb86..6a46675cbb1 100644 --- a/tests/pytests/unit/states/test_makeconf.py +++ b/tests/pytests/unit/states/test_makeconf.py @@ -24,7 +24,7 @@ def test_present(): mock_t = MagicMock(return_value=True) with patch.dict(makeconf.__salt__, {"makeconf.get_var": mock_t}): - comt = "Variable {} is already present in make.conf".format(name) + comt = f"Variable {name} is already present in make.conf" ret.update({"comment": comt}) assert makeconf.present(name) == ret @@ -39,6 +39,6 @@ def test_absent(): mock = MagicMock(return_value=None) with patch.dict(makeconf.__salt__, {"makeconf.get_var": mock}): - comt = "Variable {} is already absent from make.conf".format(name) + comt = f"Variable {name} is already absent from make.conf" ret.update({"comment": comt}) assert makeconf.absent(name) == ret diff --git a/tests/pytests/unit/states/test_mongodb_database.py b/tests/pytests/unit/states/test_mongodb_database.py index e82bb159d53..9e8ecf3b1a1 100644 --- a/tests/pytests/unit/states/test_mongodb_database.py +++ b/tests/pytests/unit/states/test_mongodb_database.py @@ -28,15 +28,15 @@ def test_absent(): {"mongodb.db_exists": mock, "mongodb.db_remove": mock_t}, ): with patch.dict(mongodb_database.__opts__, {"test": True}): - comt = "Database {} is present and needs to be removed".format(name) + comt = f"Database {name} is present and needs to be removed" ret.update({"comment": comt}) assert mongodb_database.absent(name) == ret with patch.dict(mongodb_database.__opts__, {"test": False}): - comt = "Database {} has been removed".format(name) + comt = f"Database {name} has been removed" ret.update({"comment": comt, "result": True, "changes": {"mydb": "Absent"}}) assert mongodb_database.absent(name) == ret - comt = "Database {} is not present".format(name) + comt = f"Database {name} is not present" ret.update({"comment": comt, "changes": {}}) assert mongodb_database.absent(name) == ret diff --git a/tests/pytests/unit/states/test_mongodb_user.py b/tests/pytests/unit/states/test_mongodb_user.py index cc1524c85c5..5ba8b11e23b 100644 --- a/tests/pytests/unit/states/test_mongodb_user.py +++ b/tests/pytests/unit/states/test_mongodb_user.py @@ -37,12 +37,12 @@ def test_present(): assert mongodb_user.present(name, passwd) == ret with patch.dict(mongodb_user.__opts__, {"test": True}): - comt = "User {} is not present and needs to be created".format(name) + comt = f"User {name} is not present and needs to be created" ret.update({"comment": comt, "result": None}) assert mongodb_user.present(name, passwd) == ret with patch.dict(mongodb_user.__opts__, {"test": False}): - comt = "User {} has been created".format(name) + comt = f"User {name} has been created" ret.update({"comment": comt, "result": True, "changes": {name: "Present"}}) assert mongodb_user.present(name, passwd) == ret @@ -62,15 +62,15 @@ def test_absent(): {"mongodb.user_exists": mock, "mongodb.user_remove": mock_t}, ): with patch.dict(mongodb_user.__opts__, {"test": True}): - comt = "User {} is present and needs to be removed".format(name) + comt = f"User {name} is present and needs to be removed" ret.update({"comment": comt, "result": None}) assert mongodb_user.absent(name) == ret with patch.dict(mongodb_user.__opts__, {"test": False}): - comt = "User {} has been removed".format(name) + comt = f"User {name} has been removed" ret.update({"comment": comt, "result": True, "changes": {name: "Absent"}}) assert mongodb_user.absent(name) == ret - comt = "User {} is not present".format(name) + comt = f"User {name} is not present" ret.update({"comment": comt, "result": True, "changes": {}}) assert mongodb_user.absent(name) == ret diff --git a/tests/pytests/unit/states/test_mount.py b/tests/pytests/unit/states/test_mount.py index 235cabc405e..14e716f24e6 100644 --- a/tests/pytests/unit/states/test_mount.py +++ b/tests/pytests/unit/states/test_mount.py @@ -1359,9 +1359,9 @@ def test_bind_mount_copy_active_opts(mount_name): ), ): with patch.dict(mount.__opts__, {"test": True}): - ret[ - "comment" - ] = "Remount would be forced because options (nodev,noexec,nosuid) changed" + ret["comment"] = ( + "Remount would be forced because options (nodev,noexec,nosuid) changed" + ) result = mount.mounted( name=name, device=device, diff --git a/tests/pytests/unit/states/test_npm.py b/tests/pytests/unit/states/test_npm.py index 093f7065f4f..6e8e1abe7e4 100644 --- a/tests/pytests/unit/states/test_npm.py +++ b/tests/pytests/unit/states/test_npm.py @@ -140,7 +140,7 @@ def test_cache_cleaned(): pkg_ret = {"name": name, "result": False, "comment": "", "changes": {}} ret = {"name": None, "result": False, "comment": "", "changes": {}} - mock_list = MagicMock(return_value=["~/.npm", "~/.npm/{}/".format(name)]) + mock_list = MagicMock(return_value=["~/.npm", f"~/.npm/{name}/"]) mock_cache_clean_success = MagicMock(return_value=True) mock_cache_clean_failure = MagicMock(return_value=False) mock_err = MagicMock(side_effect=CommandExecutionError) @@ -151,14 +151,14 @@ def test_cache_cleaned(): assert npm.cache_cleaned() == ret with patch.dict(npm.__salt__, {"npm.cache_list": mock_err}): - comt = "Error looking up cached {}: ".format(name) + comt = f"Error looking up cached {name}: " pkg_ret.update({"comment": comt}) assert npm.cache_cleaned(name) == pkg_ret mock_data = {"npm.cache_list": mock_list, "npm.cache_clean": MagicMock()} with patch.dict(npm.__salt__, mock_data): non_cached_pkg = "salt" - comt = "Package {} is not in the cache".format(non_cached_pkg) + comt = f"Package {non_cached_pkg} is not in the cache" pkg_ret.update({"name": non_cached_pkg, "result": True, "comment": comt}) assert npm.cache_cleaned(non_cached_pkg) == pkg_ret pkg_ret.update({"name": name}) @@ -169,7 +169,7 @@ def test_cache_cleaned(): assert npm.cache_cleaned() == ret with patch.dict(npm.__opts__, {"test": True}): - comt = "Cached {} set to be removed".format(name) + comt = f"Cached {name} set to be removed" pkg_ret.update({"result": None, "comment": comt}) assert npm.cache_cleaned(name) == pkg_ret @@ -181,7 +181,7 @@ def test_cache_cleaned(): assert npm.cache_cleaned() == ret with patch.dict(npm.__opts__, {"test": False}): - comt = "Cached {} successfully removed".format(name) + comt = f"Cached {name} successfully removed" pkg_ret.update( {"result": True, "comment": comt, "changes": {name: "Removed"}} ) @@ -199,7 +199,7 @@ def test_cache_cleaned(): assert npm.cache_cleaned() == ret with patch.dict(npm.__opts__, {"test": False}): - comt = "Error cleaning cached {}".format(name) + comt = f"Error cleaning cached {name}" pkg_ret.update({"result": False, "comment": comt}) pkg_ret["changes"] = {} assert npm.cache_cleaned(name) == pkg_ret diff --git a/tests/pytests/unit/states/test_pagerduty.py b/tests/pytests/unit/states/test_pagerduty.py index 799d266b9a1..549292c2c1f 100644 --- a/tests/pytests/unit/states/test_pagerduty.py +++ b/tests/pytests/unit/states/test_pagerduty.py @@ -25,13 +25,13 @@ def test_create_event(): ret = {"name": name, "result": None, "comment": "", "changes": {}} with patch.dict(pagerduty.__opts__, {"test": True}): - comt = "Need to create event: {}".format(name) + comt = f"Need to create event: {name}" ret.update({"comment": comt}) assert pagerduty.create_event(name, details, service_key, profile) == ret with patch.dict(pagerduty.__opts__, {"test": False}): mock_t = MagicMock(return_value=True) with patch.dict(pagerduty.__salt__, {"pagerduty.create_event": mock_t}): - comt = "Created event: {}".format(name) + comt = f"Created event: {name}" ret.update({"comment": comt, "result": True}) assert pagerduty.create_event(name, details, service_key, profile) == ret diff --git a/tests/pytests/unit/states/test_pdbedit.py b/tests/pytests/unit/states/test_pdbedit.py index 900553ca4cf..35d21efe5dd 100644 --- a/tests/pytests/unit/states/test_pdbedit.py +++ b/tests/pytests/unit/states/test_pdbedit.py @@ -22,4 +22,4 @@ def test_generate_absent(): pdbedit_mod.__salt__, {"cmd.run_all": MagicMock(return_value=cmd_ret)} ): ret = pdbedit.absent(name) - assert ret["comment"] == "account {} is absent".format(name) + assert ret["comment"] == f"account {name} is absent" diff --git a/tests/pytests/unit/states/test_pecl.py b/tests/pytests/unit/states/test_pecl.py index 132a8f8de7d..32a39d9504f 100644 --- a/tests/pytests/unit/states/test_pecl.py +++ b/tests/pytests/unit/states/test_pecl.py @@ -25,7 +25,7 @@ def test_installed(): mock_lst = MagicMock(return_value={name: "stable"}) mock_t = MagicMock(return_value=True) with patch.dict(pecl.__salt__, {"pecl.list": mock_lst, "pecl.install": mock_t}): - comt = "Pecl extension {} is already installed.".format(name) + comt = f"Pecl extension {name} is already installed." ret.update({"comment": comt, "result": True}) assert pecl.installed(name) == ret @@ -57,7 +57,7 @@ def test_removed(): mock_lst = MagicMock(side_effect=[{}, {name: "stable"}, {name: "stable"}]) mock_t = MagicMock(return_value=True) with patch.dict(pecl.__salt__, {"pecl.list": mock_lst, "pecl.uninstall": mock_t}): - comt = "Pecl extension {} is not installed.".format(name) + comt = f"Pecl extension {name} is not installed." ret.update({"comment": comt, "result": True}) assert pecl.removed(name) == ret diff --git a/tests/pytests/unit/states/test_pip.py b/tests/pytests/unit/states/test_pip.py index 1a71be86ac1..1c5cda4fe14 100644 --- a/tests/pytests/unit/states/test_pip.py +++ b/tests/pytests/unit/states/test_pip.py @@ -1,6 +1,7 @@ """ :codeauthor: Eric Graham """ + import logging import pytest diff --git a/tests/pytests/unit/states/test_ports.py b/tests/pytests/unit/states/test_ports.py index 3c1bded928a..6739437e0a4 100644 --- a/tests/pytests/unit/states/test_ports.py +++ b/tests/pytests/unit/states/test_ports.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import os import pytest @@ -66,7 +67,7 @@ def test_installed(): mock_dict = MagicMock(return_value={"origin": {"origin": "salt"}}) with patch.dict(ports.__salt__, {"pkg.list_pkgs": mock_dict}): with patch.dict(ports.__opts__, {"test": True}): - comt = "{} will be installed".format(name) + comt = f"{name} will be installed" ret.update({"comment": comt, "result": None}) assert ports.installed(name) == ret diff --git a/tests/pytests/unit/states/test_powerpath.py b/tests/pytests/unit/states/test_powerpath.py index 1f808581a45..4624df76d06 100644 --- a/tests/pytests/unit/states/test_powerpath.py +++ b/tests/pytests/unit/states/test_powerpath.py @@ -42,7 +42,7 @@ def test_license_present(): ret.update({"comment": comt, "result": False}) assert powerpath.license_present(name) == ret - comt = "License key {} already present".format(name) + comt = f"License key {name} already present" ret.update({"comment": comt, "result": True}) assert powerpath.license_present(name) == ret @@ -88,7 +88,7 @@ def test_license_absent(): ret.update({"comment": comt, "result": False}) assert powerpath.license_absent(name) == ret - comt = "License key {} not present".format(name) + comt = f"License key {name} not present" ret.update({"comment": comt, "result": True}) assert powerpath.license_absent(name) == ret diff --git a/tests/pytests/unit/states/test_pyrax_queues.py b/tests/pytests/unit/states/test_pyrax_queues.py index d5315163111..0f16e00fe4f 100644 --- a/tests/pytests/unit/states/test_pyrax_queues.py +++ b/tests/pytests/unit/states/test_pyrax_queues.py @@ -31,7 +31,7 @@ def test_present(): ] ) with patch.dict(pyrax_queues.__salt__, {"cloud.action": mock_dct}): - comt = "{} present.".format(name) + comt = f"{name} present." ret.update({"comment": comt}) assert pyrax_queues.present(name, provider) == ret diff --git a/tests/pytests/unit/states/test_rbenv.py b/tests/pytests/unit/states/test_rbenv.py index b9cf9917d49..2b62a828102 100644 --- a/tests/pytests/unit/states/test_rbenv.py +++ b/tests/pytests/unit/states/test_rbenv.py @@ -42,12 +42,12 @@ def test_installed(): ): with patch.dict(rbenv.__opts__, {"test": True}): name = "1.9.3-p551" - comt = "Ruby {} is set to be installed".format(name) + comt = f"Ruby {name} is set to be installed" ret = {"name": name, "changes": {}, "comment": comt, "result": None} assert rbenv.installed(name) == ret name = "2.4.1" - comt = "Ruby {} is already installed".format(name) + comt = f"Ruby {name} is already installed" ret = { "name": name, "changes": {}, @@ -58,7 +58,7 @@ def test_installed(): assert rbenv.installed(name) == ret name = "2.3.4" - comt = "Ruby {} is already installed".format(name) + comt = f"Ruby {name} is already installed" ret = { "name": name, "changes": {}, @@ -136,16 +136,16 @@ def test_absent(): with patch.dict(rbenv.__opts__, {"test": True}): name = "1.9.3-p551" - comt = "Rbenv not installed, {} not either".format(name) + comt = f"Rbenv not installed, {name} not either" ret = {"name": name, "changes": {}, "comment": comt, "result": True} assert rbenv.absent(name) == ret - comt = "Ruby {} is already uninstalled".format(name) + comt = f"Ruby {name} is already uninstalled" ret = {"name": name, "changes": {}, "comment": comt, "result": True} assert rbenv.absent(name) == ret name = "2.3.4" - comt = "Ruby {} is set to be uninstalled".format(name) + comt = f"Ruby {name} is set to be uninstalled" ret = { "name": name, "changes": {}, @@ -156,7 +156,7 @@ def test_absent(): assert rbenv.absent("2.3.4") == ret name = "2.4.1" - comt = "Ruby {} is set to be uninstalled".format(name) + comt = f"Ruby {name} is set to be uninstalled" ret = { "name": name, "changes": {}, @@ -168,11 +168,11 @@ def test_absent(): with patch.dict(rbenv.__opts__, {"test": False}): name = "1.9.3-p551" - comt = "Rbenv not installed, {} not either".format(name) + comt = f"Rbenv not installed, {name} not either" ret = {"name": name, "changes": {}, "comment": comt, "result": True} assert rbenv.absent(name) == ret - comt = "Ruby {} is already absent".format(name) + comt = f"Ruby {name} is already absent" ret = {"name": name, "changes": {}, "comment": comt, "result": True} assert rbenv.absent(name) == ret diff --git a/tests/pytests/unit/states/test_slack.py b/tests/pytests/unit/states/test_slack.py index 5f4dfaca645..a9b59f49592 100644 --- a/tests/pytests/unit/states/test_slack.py +++ b/tests/pytests/unit/states/test_slack.py @@ -29,7 +29,7 @@ def test_post_message_apikey(): with patch.dict(slack.__opts__, {"test": True}): mock = MagicMock(return_value=True) with patch.dict(slack.__salt__, {"config.get": mock}): - comt = "The following message is to be sent to Slack: {}".format(message) + comt = f"The following message is to be sent to Slack: {message}" ret.update({"comment": comt}) assert ( slack.post_message( @@ -129,7 +129,7 @@ def test_post_message_webhook(): with patch.dict(slack.__opts__, {"test": True}): mock = MagicMock(return_value=True) with patch.dict(slack.__salt__, {"config.get": mock}): - comt = "The following message is to be sent to Slack: {}".format(message) + comt = f"The following message is to be sent to Slack: {message}" ret.update({"comment": comt}) assert ( slack.post_message( diff --git a/tests/pytests/unit/states/test_smartos.py b/tests/pytests/unit/states/test_smartos.py index b42c7e528bc..2ef24355f2f 100644 --- a/tests/pytests/unit/states/test_smartos.py +++ b/tests/pytests/unit/states/test_smartos.py @@ -21,9 +21,10 @@ def test_config_present_does_not_exist(): with patch("salt.utils.atomicfile.atomic_open", side_effect=IOError): ret = smartos.config_present(name=name, value=value) assert not ret["result"] - assert ret[ - "comment" - ] == 'Could not add property {} with value "{}" to config'.format(name, value) + assert ( + ret["comment"] + == f'Could not add property {name} with value "{value}" to config' + ) def test_parse_vmconfig_vrrp(): diff --git a/tests/pytests/unit/states/test_splunk_search.py b/tests/pytests/unit/states/test_splunk_search.py index 0f51ffe7ad9..caa12d8486a 100644 --- a/tests/pytests/unit/states/test_splunk_search.py +++ b/tests/pytests/unit/states/test_splunk_search.py @@ -27,11 +27,11 @@ def test_present(): {"splunk_search.get": mock, "splunk_search.create": mock}, ): with patch.dict(splunk_search.__opts__, {"test": True}): - comt = "Would update {}".format(name) + comt = f"Would update {name}" ret.update({"comment": comt}) assert splunk_search.present(name) == ret - comt = "Would create {}".format(name) + comt = f"Would create {name}" ret.update({"comment": comt}) assert splunk_search.present(name) == ret @@ -53,10 +53,10 @@ def test_absent(): mock = MagicMock(side_effect=[True, False]) with patch.dict(splunk_search.__salt__, {"splunk_search.get": mock}): with patch.dict(splunk_search.__opts__, {"test": True}): - comt = "Would delete {}".format(name) + comt = f"Would delete {name}" ret.update({"comment": comt}) assert splunk_search.absent(name) == ret - comt = "{} is absent.".format(name) + comt = f"{name} is absent." ret.update({"comment": comt, "result": True, "changes": {}}) assert splunk_search.absent(name) == ret diff --git a/tests/pytests/unit/states/test_ssh_auth.py b/tests/pytests/unit/states/test_ssh_auth.py index 8f487da07cd..c192b65eade 100644 --- a/tests/pytests/unit/states/test_ssh_auth.py +++ b/tests/pytests/unit/states/test_ssh_auth.py @@ -144,7 +144,7 @@ def test_manage(): with patch("salt.states.ssh_auth.present") as call_mocked_present: mock_present = { "comment": ( - "The authorized host key newkey for user {} was added".format(user) + f"The authorized host key newkey for user {user} was added" ), "changes": {"newkey": "New"}, "result": True, diff --git a/tests/pytests/unit/states/test_ssh_known_hosts.py b/tests/pytests/unit/states/test_ssh_known_hosts.py index 67c69d270e6..524a000764c 100644 --- a/tests/pytests/unit/states/test_ssh_known_hosts.py +++ b/tests/pytests/unit/states/test_ssh_known_hosts.py @@ -76,7 +76,7 @@ def test_present(): } mock = MagicMock(return_value=result) with patch.dict(ssh_known_hosts.__salt__, {"ssh.set_known_host": mock}): - comt = "{}'s key saved to .ssh/known_hosts (key: {})".format(name, key) + comt = f"{name}'s key saved to .ssh/known_hosts (key: {key})" ret.update( { "comment": comt, diff --git a/tests/pytests/unit/states/test_supervisord.py b/tests/pytests/unit/states/test_supervisord.py index 4e5609f034c..3f8f7496f67 100644 --- a/tests/pytests/unit/states/test_supervisord.py +++ b/tests/pytests/unit/states/test_supervisord.py @@ -47,7 +47,7 @@ def test_dead(): ret = {"name": name, "changes": {}, "result": None, "comment": ""} with patch.dict(supervisord.__opts__, {"test": True}): - comt = "Service {} is set to be stopped".format(name) + comt = f"Service {name} is set to be stopped" ret.update({"comment": comt}) assert supervisord.dead(name) == ret diff --git a/tests/pytests/unit/states/test_sysctl.py b/tests/pytests/unit/states/test_sysctl.py index ec81ea9d7ab..5ffad3745d9 100644 --- a/tests/pytests/unit/states/test_sysctl.py +++ b/tests/pytests/unit/states/test_sysctl.py @@ -20,7 +20,7 @@ def test_empty_config_file_and_value_not_found(): """ name = "some.unknown.oid" value = "1" - comment = "Sysctl option {} would be changed to {}".format(name, value) + comment = f"Sysctl option {name} would be changed to {value}" ret = {"name": name, "result": None, "changes": {}, "comment": comment} @@ -59,7 +59,7 @@ def test_to_be_changed_not_configured(): """ name = "vfs.usermount" value = "1" - comment = "Sysctl option {} set to be changed to {}".format(name, value) + comment = f"Sysctl option {name} set to be changed to {value}" ret = {"name": name, "result": None, "changes": {}, "comment": comment} def mock_current(config_file=None): @@ -137,7 +137,7 @@ def test_no_change(): """ name = "vfs.usermount" value = "1" - comment = "Sysctl value {} = {} is already set".format(name, value) + comment = f"Sysctl value {name} = {value} is already set" ret = {"name": name, "result": True, "changes": {}, "comment": comment} def mock_config(config_file=None): @@ -159,7 +159,7 @@ def test_change(): name = "vfs.usermount" old_value = "2" value = "1" - comment = "Sysctl option {} would be changed to {}".format(name, value) + comment = f"Sysctl option {name} would be changed to {value}" ret = {"name": name, "result": None, "changes": {}, "comment": comment} def mock_config(config_file=None): @@ -180,7 +180,7 @@ def test_failed_to_set(): """ name = "net.isr.maxthreads" value = "8" - comment = "Failed to set {} to {}: ".format(name, value) + comment = f"Failed to set {name} to {value}: " ret = {"name": name, "result": False, "changes": {}, "comment": comment} with patch.dict(sysctl.__opts__, {"test": False}): @@ -195,7 +195,7 @@ def test_already_set(): """ name = "vfs.usermount" value = "1" - comment = "Sysctl value {} = {} is already set".format(name, value) + comment = f"Sysctl value {name} = {value} is already set" ret = {"name": name, "result": True, "changes": {}, "comment": comment} with patch.dict(sysctl.__opts__, {"test": False}): mock = MagicMock(return_value="Already set") @@ -209,7 +209,7 @@ def test_updated(): """ name = "vfs.usermount" value = "1" - comment = "Updated sysctl value {} = {}".format(name, value) + comment = f"Updated sysctl value {name} = {value}" changes = {name: value} ret = {"name": name, "result": True, "changes": changes, "comment": comment} with patch.dict(sysctl.__opts__, {"test": False}): diff --git a/tests/pytests/unit/states/test_sysfs.py b/tests/pytests/unit/states/test_sysfs.py index 030af223155..1e95400826d 100644 --- a/tests/pytests/unit/states/test_sysfs.py +++ b/tests/pytests/unit/states/test_sysfs.py @@ -1,6 +1,7 @@ """ :codeauthor: Piter Punk """ + import pytest import salt.states.sysfs as sysfs @@ -18,7 +19,7 @@ def test_if_the_sysfs_attribute_exists(): """ name = "block/sda/queue/this_does_not_exist" value = "none" - comment = "SysFS attribute {} doesn't exist.".format(name) + comment = f"SysFS attribute {name} doesn't exist." ret = {"name": name, "result": False, "changes": {}, "comment": comment} mock_read = MagicMock(return_value=False) @@ -32,7 +33,7 @@ def test_name_is_an_object_and_not_an_attribute(): """ name = "block/sda/queue" value = "none" - comment = "{} is not a SysFS attribute.".format(name) + comment = f"{name} is not a SysFS attribute." ret = {"name": name, "result": False, "changes": {}, "comment": comment} read_from_sysfs = { @@ -52,7 +53,7 @@ def test_already_set(): """ name = "block/sda/queue" value = "none" - comment = "SysFS attribute {} is already set.".format(name) + comment = f"SysFS attribute {name} is already set." ret = {"name": name, "result": True, "changes": {}, "comment": comment} read_from_sysfs = "[none] mq-deadline" @@ -68,7 +69,7 @@ def test_set_new_value_with_test_equals_true(): """ name = "devices/system/cpu/cpufreq/policy0" value = "powersave" - comment = "SysFS attribute {} set to be changed.".format(name) + comment = f"SysFS attribute {name} set to be changed." ret = {"name": name, "result": None, "changes": {}, "comment": comment} read_from_sysfs = "performance" @@ -85,7 +86,7 @@ def test_set_new_value_with_success(): """ name = "block/sda/queue/scheduler" value = "mq-deadline" - comment = "Updated SysFS attribute {} to {}".format(name, value) + comment = f"Updated SysFS attribute {name} to {value}" ret = {"name": name, "result": True, "changes": {name: value}, "comment": comment} read_from_sysfs = "[none] mq-deadline" @@ -104,7 +105,7 @@ def test_set_new_value_with_failure(): """ name = "block/sda/queue/scheduler" value = "imaginary_scheduler" - comment = "Failed to set {} to {}".format(name, value) + comment = f"Failed to set {name} to {value}" ret = {"name": name, "result": False, "changes": {}, "comment": comment} read_from_sysfs = "[none] mq-deadline" diff --git a/tests/pytests/unit/states/test_virtualenv_mod.py b/tests/pytests/unit/states/test_virtualenv_mod.py index 5c2e33b85d0..d614050202e 100644 --- a/tests/pytests/unit/states/test_virtualenv_mod.py +++ b/tests/pytests/unit/states/test_virtualenv_mod.py @@ -4,7 +4,6 @@ Test cases for salt.states.virtualenv_mod """ - import os import pytest diff --git a/tests/pytests/unit/states/test_webutil.py b/tests/pytests/unit/states/test_webutil.py index d8a10f2d7a0..de8041e9770 100644 --- a/tests/pytests/unit/states/test_webutil.py +++ b/tests/pytests/unit/states/test_webutil.py @@ -2,7 +2,6 @@ :codeauthor: Alexander Pyatkin """ - import pytest import salt.states.webutil as htpasswd diff --git a/tests/pytests/unit/states/test_win_lgpo.py b/tests/pytests/unit/states/test_win_lgpo.py index 438b5c38689..cd898843986 100644 --- a/tests/pytests/unit/states/test_win_lgpo.py +++ b/tests/pytests/unit/states/test_win_lgpo.py @@ -1,6 +1,7 @@ """ :codeauthor: Shane Lee """ + import copy import pytest diff --git a/tests/pytests/unit/states/test_win_path.py b/tests/pytests/unit/states/test_win_path.py index 4f685f6fb78..17507ef1ffa 100644 --- a/tests/pytests/unit/states/test_win_path.py +++ b/tests/pytests/unit/states/test_win_path.py @@ -39,7 +39,7 @@ def test_absent(name): # Test already absent with patch.dict(win_path.__salt__, {"win_path.exists": _mock([False])}): ret = copy.deepcopy(ret_base) - ret["comment"] = "{} is not in the PATH".format(name) + ret["comment"] = f"{name} is not in the PATH" ret["result"] = True assert win_path.absent(name) == ret @@ -48,7 +48,7 @@ def test_absent(name): win_path.__salt__, {"win_path.exists": _mock([True, False])} ): ret = copy.deepcopy(ret_base) - ret["comment"] = "Removed {} from the PATH".format(name) + ret["comment"] = f"Removed {name} from the PATH" ret["changes"]["removed"] = name ret["result"] = True assert win_path.absent(name) == ret @@ -58,7 +58,7 @@ def test_absent(name): win_path.__salt__, {"win_path.exists": _mock([True, True])} ): ret = copy.deepcopy(ret_base) - ret["comment"] = "Failed to remove {} from the PATH".format(name) + ret["comment"] = f"Failed to remove {name} from the PATH" ret["result"] = False assert win_path.absent(name) == ret @@ -68,14 +68,14 @@ def test_absent(name): # Test already absent with patch.dict(win_path.__salt__, {"win_path.exists": _mock([False])}): ret = copy.deepcopy(ret_base) - ret["comment"] = "{} is not in the PATH".format(name) + ret["comment"] = f"{name} is not in the PATH" ret["result"] = True assert win_path.absent(name) == ret # Test the test-mode return with patch.dict(win_path.__salt__, {"win_path.exists": _mock([True])}): ret = copy.deepcopy(ret_base) - ret["comment"] = "{} would be removed from the PATH".format(name) + ret["comment"] = f"{name} would be removed from the PATH" ret["result"] = None assert win_path.absent(name) == ret @@ -120,7 +120,7 @@ def test_exists_add_no_index_success(name): "name": name, "changes": {"index": {"old": None, "new": 3}}, "result": True, - "comment": "Added {} to the PATH.".format(name), + "comment": f"Added {name} to the PATH.", } @@ -151,7 +151,7 @@ def test_exists_add_no_index_failure(name): "name": name, "changes": {}, "result": False, - "comment": "Failed to add {} to the PATH.".format(name), + "comment": f"Failed to add {name} to the PATH.", } @@ -216,7 +216,7 @@ def test_exists_change_index_success(name): "name": name, "changes": {"index": {"old": 3, "new": 0}}, "result": True, - "comment": "Moved {} from index 3 to 0.".format(name), + "comment": f"Moved {name} from index 3 to 0.", } @@ -249,7 +249,7 @@ def test_exists_change_negative_index_success(name): "name": name, "changes": {"index": {"old": -2, "new": -1}}, "result": True, - "comment": "Moved {} from index -2 to -1.".format(name), + "comment": f"Moved {name} from index -2 to -1.", } @@ -350,7 +350,7 @@ def test_exists_change_index_failure(name): "name": name, "changes": {}, "result": False, - "comment": "Failed to move {} from index 3 to 0.".format(name), + "comment": f"Failed to move {name} from index 3 to 0.", } @@ -383,7 +383,7 @@ def test_exists_change_negative_index_failure(name): "name": name, "changes": {}, "result": False, - "comment": "Failed to move {} from index -2 to -1.".format(name), + "comment": f"Failed to move {name} from index -2 to -1.", } @@ -412,7 +412,7 @@ def test_exists_change_index_test_mode(name): "name": name, "changes": {"index": {"old": 3, "new": 0}}, "result": None, - "comment": "{} would be moved from index 3 to 0.".format(name), + "comment": f"{name} would be moved from index 3 to 0.", } @@ -441,7 +441,7 @@ def test_exists_change_negative_index_test_mode(name): "name": name, "changes": {"index": {"old": -2, "new": -1}}, "result": None, - "comment": "{} would be moved from index -2 to -1.".format(name), + "comment": f"{name} would be moved from index -2 to -1.", } @@ -479,7 +479,7 @@ def _test_exists_add_already_present(index, test_mode, name): "changes": {}, "result": True, "comment": "{} already exists in the PATH{}.".format( - name, " at index {}".format(index) if index is not None else "" + name, f" at index {index}" if index is not None else "" ), } diff --git a/tests/pytests/unit/states/test_win_wua.py b/tests/pytests/unit/states/test_win_wua.py index 51e1d9ef987..cc6e169b0f4 100644 --- a/tests/pytests/unit/states/test_win_wua.py +++ b/tests/pytests/unit/states/test_win_wua.py @@ -1,6 +1,7 @@ """ Test the win_wua state module """ + from collections import namedtuple import pytest @@ -337,7 +338,9 @@ def test_installed(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": False}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": { "installed": { @@ -433,7 +436,9 @@ def test_installed_test_mode(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": True}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": {}, "comment": "Updates will be installed:", @@ -493,7 +498,9 @@ def test_installed_already_installed(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": True}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": {}, "comment": "Updates already installed: KB4052623", @@ -593,7 +600,9 @@ def test_removed(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": False}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": { "removed": { @@ -658,7 +667,9 @@ def test_removed_test_mode(update_records, update_records_identity): ) patch_opts = patch.dict(win_wua.__opts__, {"test": True}) - with patch_winapi_com, patch_dispatch, patch_wua, patch_update_collection, patch_opts: + with ( + patch_winapi_com + ), patch_dispatch, patch_wua, patch_update_collection, patch_opts: expected = { "changes": {}, "comment": "Updates will be removed:", diff --git a/tests/pytests/unit/states/test_win_wusa.py b/tests/pytests/unit/states/test_win_wusa.py index 9b3b29d66b9..51a303179fa 100644 --- a/tests/pytests/unit/states/test_win_wusa.py +++ b/tests/pytests/unit/states/test_win_wusa.py @@ -30,10 +30,10 @@ def test_installed_existing(kb): """ mock_installed = MagicMock(return_value=True) with patch.dict(wusa.__salt__, {"wusa.is_installed": mock_installed}): - returned = wusa.installed(name=kb, source="salt://{}.msu".format(kb)) + returned = wusa.installed(name=kb, source=f"salt://{kb}.msu") expected = { "changes": {}, - "comment": "{} already installed".format(kb), + "comment": f"{kb} already installed", "name": kb, "result": True, } @@ -48,10 +48,10 @@ def test_installed_test_true(kb): with patch.dict(wusa.__salt__, {"wusa.is_installed": mock_installed}), patch.dict( wusa.__opts__, {"test": True} ): - returned = wusa.installed(name=kb, source="salt://{}.msu".format(kb)) + returned = wusa.installed(name=kb, source=f"salt://{kb}.msu") expected = { "changes": {}, - "comment": "{} would be installed".format(kb), + "comment": f"{kb} would be installed", "name": kb, "result": None, } @@ -68,10 +68,10 @@ def test_installed_cache_fail(kb): wusa.__salt__, {"wusa.is_installed": mock_installed, "cp.cache_file": mock_cache}, ): - returned = wusa.installed(name=kb, source="salt://{}.msu".format(kb)) + returned = wusa.installed(name=kb, source=f"salt://{kb}.msu") expected = { "changes": {}, - "comment": 'Unable to cache salt://{}.msu from saltenv "base"'.format(kb), + "comment": f'Unable to cache salt://{kb}.msu from saltenv "base"', "name": kb, "result": False, } @@ -83,7 +83,7 @@ def test_installed(kb): test wusa.installed assuming success """ mock_installed = MagicMock(side_effect=[False, True]) - mock_cache = MagicMock(return_value="C:\\{}.msu".format(kb)) + mock_cache = MagicMock(return_value=f"C:\\{kb}.msu") with patch.dict( wusa.__salt__, { @@ -92,10 +92,10 @@ def test_installed(kb): "wusa.install": MagicMock(), }, ): - returned = wusa.installed(name=kb, source="salt://{}.msu".format(kb)) + returned = wusa.installed(name=kb, source=f"salt://{kb}.msu") expected = { "changes": {"new": True, "old": False}, - "comment": "{} was installed. ".format(kb), + "comment": f"{kb} was installed. ", "name": kb, "result": True, } @@ -107,7 +107,7 @@ def test_installed_failed(kb): test wusa.installed with a failure """ mock_installed = MagicMock(side_effect=[False, False]) - mock_cache = MagicMock(return_value="C:\\{}.msu".format(kb)) + mock_cache = MagicMock(return_value=f"C:\\{kb}.msu") with patch.dict( wusa.__salt__, { @@ -116,10 +116,10 @@ def test_installed_failed(kb): "wusa.install": MagicMock(), }, ): - returned = wusa.installed(name=kb, source="salt://{}.msu".format(kb)) + returned = wusa.installed(name=kb, source=f"salt://{kb}.msu") expected = { "changes": {}, - "comment": "{} failed to install. ".format(kb), + "comment": f"{kb} failed to install. ", "name": kb, "result": False, } @@ -135,7 +135,7 @@ def test_uninstalled_non_existing(kb): returned = wusa.uninstalled(name=kb) expected = { "changes": {}, - "comment": "{} already uninstalled".format(kb), + "comment": f"{kb} already uninstalled", "name": kb, "result": True, } @@ -153,7 +153,7 @@ def test_uninstalled_test_true(kb): returned = wusa.uninstalled(name=kb) expected = { "changes": {}, - "comment": "{} would be uninstalled".format(kb), + "comment": f"{kb} would be uninstalled", "name": kb, "result": None, } @@ -172,7 +172,7 @@ def test_uninstalled(kb): returned = wusa.uninstalled(name=kb) expected = { "changes": {"new": False, "old": True}, - "comment": "{} was uninstalled".format(kb), + "comment": f"{kb} was uninstalled", "name": kb, "result": True, } @@ -191,7 +191,7 @@ def test_uninstalled_failed(kb): returned = wusa.uninstalled(name=kb) expected = { "changes": {}, - "comment": "{} failed to uninstall".format(kb), + "comment": f"{kb} failed to uninstall", "name": kb, "result": False, } diff --git a/tests/pytests/unit/states/test_xml.py b/tests/pytests/unit/states/test_xml.py index 81cada32504..22a0e292cec 100644 --- a/tests/pytests/unit/states/test_xml.py +++ b/tests/pytests/unit/states/test_xml.py @@ -26,7 +26,7 @@ def test_value_already_present(): "name": name, "changes": {}, "result": True, - "comment": "{} is already present".format(value), + "comment": f"{value} is already present", } with patch.dict(xml.__salt__, {"xml.get_value": MagicMock(return_value=value)}): @@ -48,7 +48,7 @@ def test_value_update(): "name": name, "changes": {name: {"new": value, "old": old_value}}, "result": True, - "comment": "{} updated".format(name), + "comment": f"{name} updated", } with patch.dict(xml.__salt__, {"xml.get_value": MagicMock(return_value=old_value)}): @@ -71,7 +71,7 @@ def test_value_update_test(): "name": name, "changes": {name: {"old": old_value, "new": value}}, "result": None, - "comment": "{} will be updated".format(name), + "comment": f"{name} will be updated", } with patch.dict(xml.__salt__, {"xml.get_value": MagicMock(return_value=old_value)}): @@ -91,7 +91,7 @@ def test_value_update_invalid_xpath(): "name": name, "changes": {}, "result": False, - "comment": "xpath query {} not found in {}".format(xpath, name), + "comment": f"xpath query {xpath} not found in {name}", } with patch.dict(xml.__salt__, {"xml.get_value": MagicMock(return_value=False)}): diff --git a/tests/pytests/unit/states/test_xmpp.py b/tests/pytests/unit/states/test_xmpp.py index bec7224cdf1..fe672be884a 100644 --- a/tests/pytests/unit/states/test_xmpp.py +++ b/tests/pytests/unit/states/test_xmpp.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import pytest import salt.states.xmpp as xmpp diff --git a/tests/pytests/unit/states/virt/test_domain.py b/tests/pytests/unit/states/virt/test_domain.py index 091dc5ccce2..c2ddebc7374 100644 --- a/tests/pytests/unit/states/virt/test_domain.py +++ b/tests/pytests/unit/states/virt/test_domain.py @@ -165,7 +165,11 @@ def test_defined_update(test): "initrd": "/root/f8-i386-initrd", "cmdline": "console=ttyS0 ks=http://example.com/f8-i386/os/", } - assert virt.defined("myvm", cpu=2, boot=boot,) == { + assert virt.defined( + "myvm", + cpu=2, + boot=boot, + ) == { "name": "myvm", "changes": {"myvm": {"definition": True, "cpu": True}}, "result": True if not test else None, @@ -262,9 +266,11 @@ def test_running_no_change(test, running): "name": "myvm", "result": True, "changes": {"myvm": {"started": True}} if running == "shutdown" else {}, - "comment": "Domain myvm started" - if running == "shutdown" - else "Domain myvm exists and is running", + "comment": ( + "Domain myvm started" + if running == "shutdown" + else "Domain myvm exists and is running" + ), } if running == "shutdown" and not test: start_mock.assert_called() @@ -426,9 +432,11 @@ def test_running_update(test, running): "name": "myvm", "changes": {"myvm": changes}, "result": True if not test else None, - "comment": "Domain myvm updated" - if running == "running" - else "Domain myvm updated and started", + "comment": ( + "Domain myvm updated" + if running == "running" + else "Domain myvm updated and started" + ), } if running == "shutdown" and not test: start_mock.assert_called() diff --git a/tests/pytests/unit/states/zabbix/test_action.py b/tests/pytests/unit/states/zabbix/test_action.py index 57da6be2684..7a7db80f094 100644 --- a/tests/pytests/unit/states/zabbix/test_action.py +++ b/tests/pytests/unit/states/zabbix/test_action.py @@ -159,10 +159,10 @@ def test_present_create(input_params): }, ): ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" created.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" created.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" did not exist.'.format(name), + "old": f'Zabbix Action "{name}" did not exist.', "new": 'Zabbix Action "{}" created according definition.'.format( name ), @@ -193,10 +193,10 @@ def test_present_exists(input_params, existing_obj): }, ): ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Action "{}" already exists and corresponds to a definition.'.format( + name + ) ) assert zabbix_action.present(name, {}) == ret @@ -232,14 +232,14 @@ def test_present_update(input_params, existing_obj_diff, diff_params): }, ): ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" updated.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" updated.' ret["changes"] = { name: { "old": ( 'Zabbix Action "{}" differed ' "in following parameters: {}".format(name, diff_params) ), - "new": 'Zabbix Action "{}" fixed.'.format(name), + "new": f'Zabbix Action "{name}" fixed.', } } assert zabbix_action.present(name, {}) == ret @@ -257,11 +257,11 @@ def test_absent_test_mode(): {"zabbix.get_object_id_by_params": MagicMock(return_value=11)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" would be deleted.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" would be deleted.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" exists.'.format(name), - "new": 'Zabbix Action "{}" would be deleted.'.format(name), + "old": f'Zabbix Action "{name}" exists.', + "new": f'Zabbix Action "{name}" would be deleted.', } } assert zabbix_action.absent(name) == ret @@ -279,7 +279,7 @@ def test_absent(): {"zabbix.get_object_id_by_params": MagicMock(return_value=False)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" does not exist.' assert zabbix_action.absent(name) == ret with patch.dict( @@ -291,11 +291,11 @@ def test_absent(): {"zabbix.run_query": MagicMock(return_value=True)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Action "{}" deleted.'.format(name) + ret["comment"] = f'Zabbix Action "{name}" deleted.' ret["changes"] = { name: { - "old": 'Zabbix Action "{}" existed.'.format(name), - "new": 'Zabbix Action "{}" deleted.'.format(name), + "old": f'Zabbix Action "{name}" existed.', + "new": f'Zabbix Action "{name}" deleted.', } } assert zabbix_action.absent(name) == ret diff --git a/tests/pytests/unit/states/zabbix/test_template.py b/tests/pytests/unit/states/zabbix/test_template.py index 203a80a50ae..0f42560b7ec 100644 --- a/tests/pytests/unit/states/zabbix/test_template.py +++ b/tests/pytests/unit/states/zabbix/test_template.py @@ -174,10 +174,10 @@ def test_present_create(substitute_params_create): }, ): ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" created.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" created.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" did not exist.'.format(name), + "old": f'Zabbix Template "{name}" did not exist.', "new": ( 'Zabbix Template "{}" created according definition.'.format( name @@ -261,10 +261,10 @@ def test_present_update(diff_params, substitute_params_update): }, ): ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" updated.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" updated.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" differed.'.format(name), + "old": f'Zabbix Template "{name}" differed.', "new": ( 'Zabbix Template "{}" updated according definition.'.format( name @@ -287,11 +287,11 @@ def test_absent_test_mode(): {"zabbix.get_object_id_by_params": MagicMock(return_value=11)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" would be deleted.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" would be deleted.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" exists.'.format(name), - "new": 'Zabbix Template "{}" would be deleted.'.format(name), + "old": f'Zabbix Template "{name}" exists.', + "new": f'Zabbix Template "{name}" would be deleted.', } } assert zabbix_template.absent(name) == ret @@ -309,7 +309,7 @@ def test_absent(): {"zabbix.get_object_id_by_params": MagicMock(return_value=False)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" does not exist.' assert zabbix_template.absent(name) == ret with patch.dict( @@ -321,11 +321,11 @@ def test_absent(): {"zabbix.run_query": MagicMock(return_value=True)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Template "{}" deleted.'.format(name) + ret["comment"] = f'Zabbix Template "{name}" deleted.' ret["changes"] = { name: { - "old": 'Zabbix Template "{}" existed.'.format(name), - "new": 'Zabbix Template "{}" deleted.'.format(name), + "old": f'Zabbix Template "{name}" existed.', + "new": f'Zabbix Template "{name}" deleted.', } } assert zabbix_template.absent(name) == ret diff --git a/tests/pytests/unit/states/zabbix/test_valuemap.py b/tests/pytests/unit/states/zabbix/test_valuemap.py index bc589d7bc92..f1686661ff6 100644 --- a/tests/pytests/unit/states/zabbix/test_valuemap.py +++ b/tests/pytests/unit/states/zabbix/test_valuemap.py @@ -93,10 +93,10 @@ def test_present_create(input_params): }, ): ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" created.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" created.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" did not exist.'.format(name), + "old": f'Zabbix Value map "{name}" did not exist.', "new": 'Zabbix Value map "{}" created according definition.'.format( name ), @@ -127,10 +127,10 @@ def test_present_exists(input_params, existing_obj): }, ): ret["result"] = True - ret[ - "comment" - ] = 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( - name + ret["comment"] = ( + 'Zabbix Value map "{}" already exists and corresponds to a definition.'.format( + name + ) ) assert zabbix_valuemap.present(name, {}) == ret @@ -166,14 +166,14 @@ def test_present_update(input_params, existing_obj_diff, diff_params): }, ): ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" updated.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" updated.' ret["changes"] = { name: { "old": ( 'Zabbix Value map "{}" differed ' "in following parameters: {}".format(name, diff_params) ), - "new": 'Zabbix Value map "{}" fixed.'.format(name), + "new": f'Zabbix Value map "{name}" fixed.', } } assert zabbix_valuemap.present(name, {}) == ret @@ -191,11 +191,11 @@ def test_absent_test_mode(): {"zabbix.get_object_id_by_params": MagicMock(return_value=11)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" would be deleted.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" would be deleted.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" exists.'.format(name), - "new": 'Zabbix Value map "{}" would be deleted.'.format(name), + "old": f'Zabbix Value map "{name}" exists.', + "new": f'Zabbix Value map "{name}" would be deleted.', } } assert zabbix_valuemap.absent(name) == ret @@ -213,7 +213,7 @@ def test_absent(): {"zabbix.get_object_id_by_params": MagicMock(return_value=False)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" does not exist.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" does not exist.' assert zabbix_valuemap.absent(name) == ret with patch.dict( @@ -225,11 +225,11 @@ def test_absent(): {"zabbix.run_query": MagicMock(return_value=True)}, ): ret["result"] = True - ret["comment"] = 'Zabbix Value map "{}" deleted.'.format(name) + ret["comment"] = f'Zabbix Value map "{name}" deleted.' ret["changes"] = { name: { - "old": 'Zabbix Value map "{}" existed.'.format(name), - "new": 'Zabbix Value map "{}" deleted.'.format(name), + "old": f'Zabbix Value map "{name}" existed.', + "new": f'Zabbix Value map "{name}" deleted.', } } assert zabbix_valuemap.absent(name) == ret diff --git a/tests/pytests/unit/test_acl.py b/tests/pytests/unit/test_acl.py index e5788fb846d..6c75b8902d1 100644 --- a/tests/pytests/unit/test_acl.py +++ b/tests/pytests/unit/test_acl.py @@ -2,7 +2,6 @@ Unit tests for salt.acl.ClientACL """ - import pytest from salt import acl diff --git a/tests/pytests/unit/test_config.py b/tests/pytests/unit/test_config.py index cb343cb75eb..7437c8214ed 100644 --- a/tests/pytests/unit/test_config.py +++ b/tests/pytests/unit/test_config.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_config Unit tests for salt's config modulet """ + import salt.config diff --git a/tests/pytests/unit/test_fileclient.py b/tests/pytests/unit/test_fileclient.py index d11f5ac2521..dee9d7901bd 100644 --- a/tests/pytests/unit/test_fileclient.py +++ b/tests/pytests/unit/test_fileclient.py @@ -1,6 +1,7 @@ """ Unit tests for salt.fileclient """ + import salt.config import salt.fileclient as fileclient from tests.support.mock import MagicMock, patch diff --git a/tests/pytests/unit/test_log.py b/tests/pytests/unit/test_log.py index 83d2e9e2cda..8e3a45b27ae 100644 --- a/tests/pytests/unit/test_log.py +++ b/tests/pytests/unit/test_log.py @@ -8,7 +8,6 @@ Test salt's "hacked" logging """ - import io import logging @@ -32,9 +31,9 @@ def test_issue_2853_regex_TypeError(): # Let's create another log instance to trigger salt's logging class # calculations. try: - SaltLoggingClass("{}.with_digits".format(__name__)) + SaltLoggingClass(f"{__name__}.with_digits") except Exception as err: # pylint: disable=broad-except - raise AssertionError("No exception should have been raised: {}".format(err)) + raise AssertionError(f"No exception should have been raised: {err}") # Remove the testing handler log.removeHandler(handler) @@ -49,9 +48,9 @@ def test_issue_2853_regex_TypeError(): # Let's create another log instance to trigger salt's logging class # calculations. try: - SaltLoggingClass("{}.without_digits".format(__name__)) + SaltLoggingClass(f"{__name__}.without_digits") except Exception as err: # pylint: disable=broad-except - raise AssertionError("No exception should have been raised: {}".format(err)) + raise AssertionError(f"No exception should have been raised: {err}") # Remove the testing handler log.removeHandler(handler) diff --git a/tests/pytests/unit/test_pillar.py b/tests/pytests/unit/test_pillar.py index d4a1a4e1c73..d44a337981f 100644 --- a/tests/pytests/unit/test_pillar.py +++ b/tests/pytests/unit/test_pillar.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~ """ - import logging import os import shutil diff --git a/tests/pytests/unit/test_request_channel.py b/tests/pytests/unit/test_request_channel.py index b8957f35e30..dda663057d9 100644 --- a/tests/pytests/unit/test_request_channel.py +++ b/tests/pytests/unit/test_request_channel.py @@ -1,6 +1,7 @@ """ :codeauthor: Thomas Jackson """ + import asyncio import ctypes import logging diff --git a/tests/pytests/unit/test_syspaths.py b/tests/pytests/unit/test_syspaths.py index 0ecb4789a61..66a0bc07596 100644 --- a/tests/pytests/unit/test_syspaths.py +++ b/tests/pytests/unit/test_syspaths.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_syspaths Unit tests for salt's syspaths module """ + import pytest import salt.syspaths diff --git a/tests/pytests/unit/test_version.py b/tests/pytests/unit/test_version.py index ec1abed9f77..fbcfe33222b 100644 --- a/tests/pytests/unit/test_version.py +++ b/tests/pytests/unit/test_version.py @@ -4,6 +4,7 @@ tests.pytests.unit.test_version Test salt's regex git describe version parsing """ + import re import pytest diff --git a/tests/pytests/unit/tokens/test_localfs.py b/tests/pytests/unit/tokens/test_localfs.py index b1d6395abc5..230871acc78 100644 --- a/tests/pytests/unit/tokens/test_localfs.py +++ b/tests/pytests/unit/tokens/test_localfs.py @@ -42,7 +42,7 @@ def test_write_token(tmp_path): tdata = salt.tokens.localfs.mk_token(opts, {}) assert "token" in tdata t_path = os.path.join(str(tmp_path), tdata["token"]) - temp_t_path = "{}.tmp".format(t_path) + temp_t_path = f"{t_path}.tmp" assert len(fopen.called_with) == 1, len(fopen.called_with) assert fopen.called_with == [((temp_t_path, "w+b"), {})], fopen.called_with assert len(rename.called_with) == 1, len(rename.called_with) diff --git a/tests/pytests/unit/transport/test_base.py b/tests/pytests/unit/transport/test_base.py index 96e4c06f038..5d541073d67 100644 --- a/tests/pytests/unit/transport/test_base.py +++ b/tests/pytests/unit/transport/test_base.py @@ -1,6 +1,7 @@ """ Unit tests for salt.transport.base. """ + import ssl import pytest diff --git a/tests/pytests/unit/utils/jinja/conftest.py b/tests/pytests/unit/utils/jinja/conftest.py index 0b77a4fb2f7..4007bfd6ea1 100644 --- a/tests/pytests/unit/utils/jinja/conftest.py +++ b/tests/pytests/unit/utils/jinja/conftest.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.jinja """ + import pytest diff --git a/tests/pytests/unit/utils/jinja/test_jinja.py b/tests/pytests/unit/utils/jinja/test_jinja.py index de8df6067f5..9e1b33c2ff0 100644 --- a/tests/pytests/unit/utils/jinja/test_jinja.py +++ b/tests/pytests/unit/utils/jinja/test_jinja.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.jinja """ + import salt.utils.dateutils # pylint: disable=unused-import from salt.utils.jinja import Markup, indent, tojson diff --git a/tests/pytests/unit/utils/scheduler/conftest.py b/tests/pytests/unit/utils/scheduler/conftest.py index e74b67091bf..a1c997b1234 100644 --- a/tests/pytests/unit/utils/scheduler/conftest.py +++ b/tests/pytests/unit/utils/scheduler/conftest.py @@ -3,7 +3,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import copy import logging diff --git a/tests/pytests/unit/utils/templates/test_jinja.py b/tests/pytests/unit/utils/templates/test_jinja.py index 6d47e6b80d3..99856f65054 100644 --- a/tests/pytests/unit/utils/templates/test_jinja.py +++ b/tests/pytests/unit/utils/templates/test_jinja.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.templates """ + import re from collections import OrderedDict diff --git a/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py b/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py index 3bad376f272..bd1d5fa2e1d 100644 --- a/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py +++ b/tests/pytests/unit/utils/templates/test_wrap_tmpl_func.py @@ -1,6 +1,7 @@ """ Unit tests for salt.utils.templates.py """ + import logging from pathlib import PurePath, PurePosixPath diff --git a/tests/pytests/unit/utils/test_aws.py b/tests/pytests/unit/utils/test_aws.py index c4e32e369a9..22597ffcd8b 100644 --- a/tests/pytests/unit/utils/test_aws.py +++ b/tests/pytests/unit/utils/test_aws.py @@ -4,6 +4,7 @@ Test the salt aws functions """ + import io import os import time diff --git a/tests/pytests/unit/utils/test_cache.py b/tests/pytests/unit/utils/test_cache.py index 34736530d5c..efe2f417c4d 100644 --- a/tests/pytests/unit/utils/test_cache.py +++ b/tests/pytests/unit/utils/test_cache.py @@ -139,7 +139,7 @@ def test_set_cache(minion_opts, cache_mods_path, cache_mod_name, cache_dir): assert cache_test_func()["called"] == 1 assert cache_test_func()["called"] == 2 - cache_file_name = "salt.loaded.ext.rawmodule.{}.p".format(cache_mod_name) + cache_file_name = f"salt.loaded.ext.rawmodule.{cache_mod_name}.p" cached_file = cache_dir / "context" / cache_file_name assert cached_file.exists() @@ -151,9 +151,7 @@ def test_set_cache(minion_opts, cache_mods_path, cache_mod_name, cache_dir): assert target_cache_data == dict(context, called=1) # Test cache de-serialize - cc = cache.ContextCache( - minion_opts, "salt.loaded.ext.rawmodule.{}".format(cache_mod_name) - ) + cc = cache.ContextCache(minion_opts, f"salt.loaded.ext.rawmodule.{cache_mod_name}") retrieved_cache = cc.get_cache_context() assert retrieved_cache == dict(context, called=1) diff --git a/tests/pytests/unit/utils/test_cloud.py b/tests/pytests/unit/utils/test_cloud.py index 00c4798812e..340f226aedf 100644 --- a/tests/pytests/unit/utils/test_cloud.py +++ b/tests/pytests/unit/utils/test_cloud.py @@ -6,7 +6,6 @@ """ - import os import string import tempfile diff --git a/tests/pytests/unit/utils/test_compat.py b/tests/pytests/unit/utils/test_compat.py index b86dea94296..0dacd615eb9 100644 --- a/tests/pytests/unit/utils/test_compat.py +++ b/tests/pytests/unit/utils/test_compat.py @@ -1,6 +1,7 @@ """ Unit tests for salt.utils.compat.py """ + import pytest import salt.utils.compat diff --git a/tests/pytests/unit/utils/test_crypt.py b/tests/pytests/unit/utils/test_crypt.py index 9a7b35f3d2b..ccf2cfbf46e 100644 --- a/tests/pytests/unit/utils/test_crypt.py +++ b/tests/pytests/unit/utils/test_crypt.py @@ -1,6 +1,7 @@ """ Unit tests for salt.utils.crypt.py """ + import pytest import salt.utils.crypt diff --git a/tests/pytests/unit/utils/test_data.py b/tests/pytests/unit/utils/test_data.py index d8ec03fc11c..bac2acb9dab 100644 --- a/tests/pytests/unit/utils/test_data.py +++ b/tests/pytests/unit/utils/test_data.py @@ -1,6 +1,7 @@ """ Tests for salt.utils.data """ + import builtins import logging diff --git a/tests/pytests/unit/utils/test_files.py b/tests/pytests/unit/utils/test_files.py index ded95093cd2..3a0fef843d8 100644 --- a/tests/pytests/unit/utils/test_files.py +++ b/tests/pytests/unit/utils/test_files.py @@ -2,7 +2,6 @@ Unit Tests for functions located in salt/utils/files.py """ - import copy import io import os @@ -28,7 +27,7 @@ def test_safe_rm_exceptions(tmp_path): def test_safe_walk_symlink_recursion(tmp_path): if tmp_path.stat().st_ino == 0: - pytest.xfail(reason="inodes not supported in {}".format(tmp_path)) + pytest.xfail(reason=f"inodes not supported in {tmp_path}") tmp_path = str(tmp_path) os.mkdir(os.path.join(tmp_path, "fax")) diff --git a/tests/pytests/unit/utils/test_nacl.py b/tests/pytests/unit/utils/test_nacl.py index e5de4b8e645..5c60d880b2f 100644 --- a/tests/pytests/unit/utils/test_nacl.py +++ b/tests/pytests/unit/utils/test_nacl.py @@ -1,6 +1,7 @@ """ Unit tests for the salt.utils.nacl module """ + import os import pytest diff --git a/tests/pytests/unit/utils/test_pycrypto.py b/tests/pytests/unit/utils/test_pycrypto.py index 693ad10e240..1dfcf9621c4 100644 --- a/tests/pytests/unit/utils/test_pycrypto.py +++ b/tests/pytests/unit/utils/test_pycrypto.py @@ -203,7 +203,7 @@ def test_secure_password(): ) ) ) - check_whitespace = re.compile(r"[{}]".format(string.whitespace)) + check_whitespace = re.compile(rf"[{string.whitespace}]") assert check_printable.search(ret) is None assert check_whitespace.search(ret) is None assert ret @@ -224,7 +224,7 @@ def test_secure_password_all_chars(): whitespace=True, printable=True, ) - check = re.compile(r"[^{}]".format(re.escape(string.printable))) + check = re.compile(rf"[^{re.escape(string.printable)}]") assert check.search(ret) is None assert ret @@ -245,7 +245,7 @@ def test_secure_password_no_has_random(): ) ) ) - check_whitespace = re.compile(r"[{}]".format(string.whitespace)) + check_whitespace = re.compile(rf"[{string.whitespace}]") assert check_printable.search(ret) is None assert check_whitespace.search(ret) is None assert ret @@ -259,6 +259,6 @@ def test_secure_password_all_chars_no_has_random(): """ with patch("salt.utils.pycrypto.HAS_RANDOM", False): ret = salt.utils.pycrypto.secure_password(printable=True) - check = re.compile("[^{}]".format(re.escape(string.printable))) + check = re.compile(f"[^{re.escape(string.printable)}]") assert check.search(ret) is None assert ret diff --git a/tests/pytests/unit/utils/test_rsax931.py b/tests/pytests/unit/utils/test_rsax931.py index 28585f04415..0c151fc3b27 100644 --- a/tests/pytests/unit/utils/test_rsax931.py +++ b/tests/pytests/unit/utils/test_rsax931.py @@ -1,6 +1,7 @@ """ Test the RSA ANSI X9.31 signer and verifier """ + import ctypes import ctypes.util import fnmatch diff --git a/tests/pytests/unit/utils/test_versions.py b/tests/pytests/unit/utils/test_versions.py index 417bb9e3632..a1197778296 100644 --- a/tests/pytests/unit/utils/test_versions.py +++ b/tests/pytests/unit/utils/test_versions.py @@ -58,9 +58,7 @@ def test_cmp_strict(v1, v2, wanted): ) except InvalidVersion: if wanted is not InvalidVersion: - raise AssertionError( - "cmp({}, {}) shouldn't raise InvalidVersion".format(v1, v2) - ) + raise AssertionError(f"cmp({v1}, {v2}) shouldn't raise InvalidVersion") @pytest.mark.parametrize( @@ -83,7 +81,7 @@ def test_cmp_strict(v1, v2, wanted): ) def test_cmp(v1, v2, wanted): res = LooseVersion(v1)._cmp(LooseVersion(v2)) - assert res == wanted, "cmp({}, {}) should be {}, got {}".format(v1, v2, wanted, res) + assert res == wanted, f"cmp({v1}, {v2}) should be {wanted}, got {res}" def test_compare(): @@ -249,7 +247,7 @@ def test_warn_until_warning_raised(subtests): "Deprecation Message until {version}!", _version_info_=(vrs.major - 1, 0), ) - assert "Deprecation Message until {}!".format(vrs.formatted_version) == str( + assert f"Deprecation Message until {vrs.formatted_version}!" == str( recorded_warnings[0].message ) diff --git a/tests/pytests/unit/utils/test_win_reg.py b/tests/pytests/unit/utils/test_win_reg.py index 206c40b3089..3954318c013 100644 --- a/tests/pytests/unit/utils/test_win_reg.py +++ b/tests/pytests/unit/utils/test_win_reg.py @@ -200,7 +200,7 @@ def test_list_keys_non_existing(fake_key): """ Test the list_keys function using a non existing registry key """ - expected = (False, "Cannot find key: HKLM\\{}".format(fake_key)) + expected = (False, f"Cannot find key: HKLM\\{fake_key}") assert win_reg.list_keys(hive="HKLM", key=fake_key) == expected @@ -208,7 +208,7 @@ def test_list_keys_access_denied(fake_key): """ Test the list_keys function using a registry key when access is denied """ - expected = (False, "Access is denied: HKLM\\{}".format(fake_key)) + expected = (False, f"Access is denied: HKLM\\{fake_key}") mock_error = MagicMock( side_effect=win32api.error(5, "RegOpenKeyEx", "Access is denied") ) @@ -261,7 +261,7 @@ def test_list_values_non_existing(fake_key): """ Test the list_values function using a non existing registry key """ - expected = (False, "Cannot find key: HKLM\\{}".format(fake_key)) + expected = (False, f"Cannot find key: HKLM\\{fake_key}") assert win_reg.list_values(hive="HKLM", key=fake_key) == expected @@ -269,7 +269,7 @@ def test_list_values_access_denied(fake_key): """ Test the list_values function using a registry key when access is denied """ - expected = (False, "Access is denied: HKLM\\{}".format(fake_key)) + expected = (False, f"Access is denied: HKLM\\{fake_key}") mock_error = MagicMock( side_effect=win32api.error(5, "RegOpenKeyEx", "Access is denied") ) @@ -359,7 +359,7 @@ def test_read_value_non_existing_key(fake_key): Test the read_value function using a non existing registry key """ expected = { - "comment": "Cannot find key: HKLM\\{}".format(fake_key), + "comment": f"Cannot find key: HKLM\\{fake_key}", "vdata": None, "vtype": None, "vname": "fake_name", @@ -375,7 +375,7 @@ def test_read_value_access_denied(fake_key): Test the read_value function using a registry key when access is denied """ expected = { - "comment": "Access is denied: HKLM\\{}".format(fake_key), + "comment": f"Access is denied: HKLM\\{fake_key}", "vdata": None, "vtype": None, "vname": "fake_name", diff --git a/tests/pytests/unit/utils/test_x509.py b/tests/pytests/unit/utils/test_x509.py index f13ac97fb33..ab7384ffde2 100644 --- a/tests/pytests/unit/utils/test_x509.py +++ b/tests/pytests/unit/utils/test_x509.py @@ -1472,9 +1472,11 @@ def test_parse_general_names_rejects_invalid(inpt): ) def test_get_dn(inpt, expected): expected_parsed = [ - cx509.RelativeDistinguishedName({x}) - if not isinstance(x, cx509.RelativeDistinguishedName) - else x + ( + cx509.RelativeDistinguishedName({x}) + if not isinstance(x, cx509.RelativeDistinguishedName) + else x + ) for x in expected ] res = x509._get_dn(inpt) diff --git a/tests/pytests/unit/utils/vault/conftest.py b/tests/pytests/unit/utils/vault/conftest.py index 1ab4e39a16e..58ab67da745 100644 --- a/tests/pytests/unit/utils/vault/conftest.py +++ b/tests/pytests/unit/utils/vault/conftest.py @@ -462,10 +462,8 @@ def req_any(req, request): @pytest.fixture def req_unwrapping(wrapped_role_id_lookup_response, role_id_response, req): - req.side_effect = ( - lambda method, url, **kwargs: _mock_json_response( - wrapped_role_id_lookup_response - ) + req.side_effect = lambda method, url, **kwargs: ( + _mock_json_response(wrapped_role_id_lookup_response) if url.endswith("sys/wrapping/lookup") else _mock_json_response(role_id_response) ) @@ -550,7 +548,7 @@ def salt_runtype(request): ] ) def opts_runtype(request): - return { + rtype = { "master": { "__role": "master", "vault": {}, @@ -585,4 +583,5 @@ def opts_runtype(request): "minion_remote": { "grains": {"id": "test-minion"}, }, - }[request.param] + } + return rtype[request.param] diff --git a/tests/pytests/unit/utils/vault/test_factory.py b/tests/pytests/unit/utils/vault/test_factory.py index e9d62165b93..e82b0251a15 100644 --- a/tests/pytests/unit/utils/vault/test_factory.py +++ b/tests/pytests/unit/utils/vault/test_factory.py @@ -633,11 +633,12 @@ class TestFetchSecretId: @pytest.fixture(params=["plain", "wrapped", "dict"]) def secret_id(self, secret_id_response, wrapped_secret_id_response, request): - return { + ret = { "plain": "test-secret-id", "wrapped": {"wrap_info": wrapped_secret_id_response["wrap_info"]}, "dict": secret_id_response["data"], - }[request.param] + } + return ret[request.param] @pytest.mark.parametrize("test_remote_config", ["approle"], indirect=True) @pytest.mark.parametrize( @@ -817,11 +818,12 @@ class TestFetchToken: @pytest.fixture(params=["plain", "wrapped", "dict"]) def token(self, token_auth, wrapped_token_auth_response, request): - return { + ret = { "plain": token_auth["auth"]["client_token"], "wrapped": {"wrap_info": wrapped_token_auth_response["wrap_info"]}, "dict": token_auth["auth"], - }[request.param] + } + return ret[request.param] @pytest.mark.parametrize( "test_remote_config", ["token", "wrapped_token"], indirect=True diff --git a/tests/pytests/unit/utils/verify/test_clean_path_link.py b/tests/pytests/unit/utils/verify/test_clean_path_link.py index ff83d1f54b3..8effa56a59c 100644 --- a/tests/pytests/unit/utils/verify/test_clean_path_link.py +++ b/tests/pytests/unit/utils/verify/test_clean_path_link.py @@ -1,6 +1,7 @@ """ Ensure salt.utils.clean_path works with symlinked directories and files """ + import ctypes import pytest diff --git a/tests/pytests/unit/utils/verify/test_verify.py b/tests/pytests/unit/utils/verify/test_verify.py index 5dcb90b0857..60171523cb4 100644 --- a/tests/pytests/unit/utils/verify/test_verify.py +++ b/tests/pytests/unit/utils/verify/test_verify.py @@ -257,9 +257,11 @@ def test_max_open_files(caplog): logmsg_chk.format( newmax, mof_test, - mof_test - newmax - if sys.platform.startswith("win") - else mof_h - newmax, + ( + mof_test - newmax + if sys.platform.startswith("win") + else mof_h - newmax + ), ) in caplog.messages ) @@ -279,9 +281,11 @@ def test_max_open_files(caplog): logmsg_crash.format( newmax, mof_test, - mof_test - newmax - if sys.platform.startswith("win") - else mof_h - newmax, + ( + mof_test - newmax + if sys.platform.startswith("win") + else mof_h - newmax + ), ) in caplog.messages ) diff --git a/tests/pytests/unit/utils/win_lgpo/test_auditpol.py b/tests/pytests/unit/utils/win_lgpo/test_auditpol.py index 1d67eb7640e..85e53780efe 100644 --- a/tests/pytests/unit/utils/win_lgpo/test_auditpol.py +++ b/tests/pytests/unit/utils/win_lgpo/test_auditpol.py @@ -64,7 +64,7 @@ def test_set_setting(settings): value = random.choice(settings) win_lgpo_auditpol.set_setting(name=name, value=value) switches = win_lgpo_auditpol.settings[value] - cmd = 'auditpol /set /subcategory:"{}" {}'.format(name, switches) + cmd = f'auditpol /set /subcategory:"{name}" {switches}' mock_set.assert_called_once_with(cmd=cmd, python_shell=True) mock_set.reset_mock() diff --git a/tests/support/case.py b/tests/support/case.py index 55b537f6ffd..a59da1742b7 100644 --- a/tests/support/case.py +++ b/tests/support/case.py @@ -77,7 +77,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): if timeout is None: timeout = self.RUN_TIMEOUT - arg_str = "-t {} {}".format(timeout, arg_str) + arg_str = f"-t {timeout} {arg_str}" return self.run_script( "salt", arg_str, @@ -99,7 +99,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): ssh_opts="", log_level="error", config_dir=None, - **kwargs + **kwargs, ): """ Execute salt-ssh @@ -128,7 +128,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): raw=True, timeout=timeout, config_dir=config_dir, - **kwargs + **kwargs, ) log.debug("Result of run_ssh for command '%s %s': %s", arg_str, kwargs, ret) return ret @@ -141,7 +141,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): asynchronous=False, timeout=None, config_dir=None, - **kwargs + **kwargs, ): """ Execute salt-run @@ -284,7 +284,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): catch_stderr=False, local=False, timeout=RUN_TIMEOUT, - **kwargs + **kwargs, ): """ Execute function with salt-call. @@ -349,7 +349,7 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): popen_kwargs=None, log_output=None, config_dir=None, - **kwargs + **kwargs, ): """ Execute a script with the given argument string @@ -398,13 +398,13 @@ class ShellCase(TestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixin): import salt.utils.json for key, value in kwargs.items(): - cmd += "'{}={} '".format(key, salt.utils.json.dumps(value)) + cmd += f"'{key}={salt.utils.json.dumps(value)} '" tmp_file = tempfile.SpooledTemporaryFile() popen_kwargs = dict( {"shell": True, "stdout": tmp_file, "universal_newlines": True}, - **popen_kwargs + **popen_kwargs, ) if catch_stderr is True: @@ -639,7 +639,7 @@ class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin): "cachedir": os.path.join(self._tmp_spm, "cache"), "spm_repo_dups": "ignore", "spm_share_dir": os.path.join(self._tmp_spm, "share"), - } + }, ) import salt.utils.yaml @@ -723,7 +723,7 @@ class ModuleCase(TestCase, SaltClientTestCaseMixin): minion_tgt="minion", timeout=300, master_tgt=None, - **kwargs + **kwargs, ): """ Run a single salt function and condition the return down to match the @@ -809,7 +809,7 @@ class ModuleCase(TestCase, SaltClientTestCaseMixin): job_data, job_kill ) ) - ret.append("[TEST SUITE ENFORCED]{}[/TEST SUITE ENFORCED]".format(msg)) + ret.append(f"[TEST SUITE ENFORCED]{msg}[/TEST SUITE ENFORCED]") return ret diff --git a/tests/support/cli_scripts.py b/tests/support/cli_scripts.py index ee18d6856a0..58e54c6ec56 100644 --- a/tests/support/cli_scripts.py +++ b/tests/support/cli_scripts.py @@ -5,7 +5,6 @@ Code to generate Salt CLI scripts for test runs """ - import logging import os diff --git a/tests/support/helpers.py b/tests/support/helpers.py index 32bdf043d75..ab435d248ff 100644 --- a/tests/support/helpers.py +++ b/tests/support/helpers.py @@ -8,6 +8,7 @@ Test support helpers """ + import asyncio import base64 import builtins diff --git a/tests/support/kernelpkg.py b/tests/support/kernelpkg.py index eada8d931d1..49c1efa5d3a 100644 --- a/tests/support/kernelpkg.py +++ b/tests/support/kernelpkg.py @@ -4,6 +4,7 @@ :maturity: develop .. versionadded:: 2018.3.0 """ + # pylint: disable=invalid-name,no-member diff --git a/tests/support/mixins.py b/tests/support/mixins.py index 53f7e75108b..6c3bdf2f0bb 100644 --- a/tests/support/mixins.py +++ b/tests/support/mixins.py @@ -91,7 +91,7 @@ class AdaptedConfigurationTestCaseMixin: if key not in config_overrides: config_overrides[key] = key if "log_file" not in config_overrides: - config_overrides["log_file"] = "logs/{}.log".format(config_for) + config_overrides["log_file"] = f"logs/{config_for}.log" if "user" not in config_overrides: config_overrides["user"] = RUNTIME_VARS.RUNNING_TESTS_USER config_overrides["root_dir"] = rootdir @@ -287,9 +287,9 @@ class SaltClientTestCaseMixin(AdaptedConfigurationTestCaseMixin): mopts = self.get_config( self._salt_client_config_file_name_, from_scratch=True ) - RUNTIME_VARS.RUNTIME_CONFIGS[ - "runtime_client" - ] = salt.client.get_local_client(mopts=mopts) + RUNTIME_VARS.RUNTIME_CONFIGS["runtime_client"] = ( + salt.client.get_local_client(mopts=mopts) + ) return RUNTIME_VARS.RUNTIME_CONFIGS["runtime_client"] @@ -443,7 +443,7 @@ class SaltReturnAssertsMixin: self.assertTrue(isinstance(ret, dict)) except AssertionError: raise AssertionError( - "{} is not dict. Salt returned: {}".format(type(ret).__name__, ret) + f"{type(ret).__name__} is not dict. Salt returned: {ret}" ) def assertReturnNonEmptySaltType(self, ret): @@ -478,7 +478,7 @@ class SaltReturnAssertsMixin: except (KeyError, TypeError): raise AssertionError( "Could not get ret{} from salt's return: {}".format( - "".join(["['{}']".format(k) for k in keys]), part + "".join([f"['{k}']" for k in keys]), part ) ) while okeys: @@ -487,7 +487,7 @@ class SaltReturnAssertsMixin: except (KeyError, TypeError): raise AssertionError( "Could not get ret{} from salt's return: {}".format( - "".join(["['{}']".format(k) for k in keys]), part + "".join([f"['{k}']" for k in keys]), part ) ) ret_data.append(ret_item) @@ -525,9 +525,7 @@ class SaltReturnAssertsMixin: ) ) except (AttributeError, IndexError): - raise AssertionError( - "Failed to get result. Salt Returned: {}".format(ret) - ) + raise AssertionError(f"Failed to get result. Salt Returned: {ret}") def assertSaltNoneReturn(self, ret): try: @@ -542,9 +540,7 @@ class SaltReturnAssertsMixin: ) ) except (AttributeError, IndexError): - raise AssertionError( - "Failed to get result. Salt Returned: {}".format(ret) - ) + raise AssertionError(f"Failed to get result. Salt Returned: {ret}") def assertInSaltComment(self, in_comment, ret): for saltret in self.__getWithinSaltReturn(ret, "comment"): @@ -633,7 +629,7 @@ class SaltMinionEventAssertsMixin: cls.fetch_proc = salt.utils.process.SignalHandlingProcess( target=_fetch_events, args=(cls.q, opts), - name="Process-{}-Queue".format(cls.__name__), + name=f"Process-{cls.__name__}-Queue", ) cls.fetch_proc.start() # Wait for the event bus to be connected @@ -670,6 +666,4 @@ class SaltMinionEventAssertsMixin: if time.time() - start >= timeout: break self.fetch_proc.terminate() - raise AssertionError( - "Event {} was not received by minion".format(desired_event) - ) + raise AssertionError(f"Event {desired_event} was not received by minion") diff --git a/tests/support/mock.py b/tests/support/mock.py index 2f9970d4b04..63e794f9764 100644 --- a/tests/support/mock.py +++ b/tests/support/mock.py @@ -11,6 +11,7 @@ Note: mock >= 2.0.0 required since unittest.mock does not have MagicMock.assert_called in Python < 3.6. """ + # pylint: disable=unused-import,function-redefined,blacklisted-module,blacklisted-external-module diff --git a/tests/support/napalm.py b/tests/support/napalm.py index 58bc45bfb18..bb096189403 100644 --- a/tests/support/napalm.py +++ b/tests/support/napalm.py @@ -4,7 +4,6 @@ Base classes for napalm unit tests :codeauthor: :email:`Anthony Shaw ` """ - from functools import wraps from salt.utils.immutabletypes import freeze diff --git a/tests/support/netapi.py b/tests/support/netapi.py index f61650173b9..e6a8339778d 100644 --- a/tests/support/netapi.py +++ b/tests/support/netapi.py @@ -30,9 +30,7 @@ class TestsHttpClient: if "headers" not in kwargs and self.headers: kwargs["headers"] = self.headers.copy() try: - response = await self.client.fetch( - "{}{}".format(self.address, path), **kwargs - ) + response = await self.client.fetch(f"{self.address}{path}", **kwargs) return self._decode_body(response) except HTTPError as exc: exc.response = self._decode_body(exc.response) @@ -75,7 +73,7 @@ class TestsTornadoHttpServer: @address.default def _address_default(self): - return "{}://127.0.0.1:{}".format(self.protocol, self.port) + return f"{self.protocol}://127.0.0.1:{self.port}" @server.default def _server_default(self): diff --git a/tests/support/pytest/etcd.py b/tests/support/pytest/etcd.py index 6606e9436b8..ac7609444ed 100644 --- a/tests/support/pytest/etcd.py +++ b/tests/support/pytest/etcd.py @@ -59,7 +59,7 @@ def confirm_container_started(timeout_at, container): sleeptime = 1 while time.time() <= timeout_at: try: - response = requests.get("http://localhost:{}/version".format(etcd_port)) + response = requests.get(f"http://localhost:{etcd_port}/version") try: version = response.json() if "etcdserver" in version: diff --git a/tests/support/pytest/helpers.py b/tests/support/pytest/helpers.py index 77d46e1dcf2..4ddb0f2548a 100644 --- a/tests/support/pytest/helpers.py +++ b/tests/support/pytest/helpers.py @@ -4,6 +4,7 @@ PyTest helpers functions """ + import logging import os import pathlib diff --git a/tests/support/pytest/loader.py b/tests/support/pytest/loader.py index 2ac99459c2a..62203a56016 100644 --- a/tests/support/pytest/loader.py +++ b/tests/support/pytest/loader.py @@ -4,6 +4,7 @@ Salt's Loader PyTest Mock Support """ + import logging import sys import types @@ -127,13 +128,11 @@ class LoaderModuleMock: self._finalizers.append((func, args, kwargs)) def _format_callback(self, callback, args, kwargs): - callback_str = "{}(".format(callback.__qualname__) + callback_str = f"{callback.__qualname__}(" if args: callback_str += ", ".join([repr(arg) for arg in args]) if kwargs: - callback_str += ", ".join( - ["{}={!r}".format(k, v) for (k, v) in kwargs.items()] - ) + callback_str += ", ".join([f"{k}={v!r}" for (k, v) in kwargs.items()]) callback_str += ")" return callback_str @@ -143,7 +142,7 @@ class LoaderModuleMock: sys_modules = mocks["sys.modules"] if not isinstance(sys_modules, dict): raise RuntimeError( - "'sys.modules' must be a dictionary not: {}".format(type(sys_modules)) + f"'sys.modules' must be a dictionary not: {type(sys_modules)}" ) patcher = patch.dict(sys.modules, values=sys_modules) patcher.start() diff --git a/tests/support/runtests.py b/tests/support/runtests.py index ce5c9644cd3..046c20bd01f 100644 --- a/tests/support/runtests.py +++ b/tests/support/runtests.py @@ -192,12 +192,16 @@ RUNTIME_VARS = RuntimeVars( TMP_BASEENV_PILLAR_TREE=paths.TMP_PILLAR_TREE, TMP_PRODENV_STATE_TREE=paths.TMP_PRODENV_STATE_TREE, TMP_PRODENV_PILLAR_TREE=paths.TMP_PRODENV_PILLAR_TREE, - SHELL_TRUE_PATH=salt.utils.path.which("true") - if not salt.utils.platform.is_windows() - else "cmd /c exit 0 > nul", - SHELL_FALSE_PATH=salt.utils.path.which("false") - if not salt.utils.platform.is_windows() - else "cmd /c exit 1 > nul", + SHELL_TRUE_PATH=( + salt.utils.path.which("true") + if not salt.utils.platform.is_windows() + else "cmd /c exit 0 > nul" + ), + SHELL_FALSE_PATH=( + salt.utils.path.which("false") + if not salt.utils.platform.is_windows() + else "cmd /c exit 1 > nul" + ), RUNNING_TESTS_USER=this_user(), RUNTIME_CONFIGS={}, CODE_DIR=paths.CODE_DIR, diff --git a/tests/support/sminion.py b/tests/support/sminion.py index abf45fd7bde..1fbe69dbd03 100644 --- a/tests/support/sminion.py +++ b/tests/support/sminion.py @@ -234,7 +234,7 @@ def check_required_sminion_attributes(sminion_attr, required_items): available_items = list(getattr(sminion, sminion_attr)) not_available_items = set() - name = "__not_available_{items}s__".format(items=sminion_attr) + name = f"__not_available_{sminion_attr}s__" if not hasattr(sminion, name): setattr(sminion, name, set()) diff --git a/tests/support/unit.py b/tests/support/unit.py index dc1051ea773..88dd7808a22 100644 --- a/tests/support/unit.py +++ b/tests/support/unit.py @@ -18,6 +18,7 @@ .. _`unittest2`: https://pypi.python.org/pypi/unittest2 """ + # pylint: disable=unused-import,blacklisted-module,deprecated-method @@ -225,7 +226,7 @@ class TestCase(_TestCase): found_zombies += 1 except Exception: # pylint: disable=broad-except pass - proc_info += "|Z:{}".format(found_zombies) + proc_info += f"|Z:{found_zombies}" proc_info += "] {short_desc}".format(short_desc=desc if desc else "") return proc_info else: diff --git a/tests/support/win_installer.py b/tests/support/win_installer.py index 6a2f387dc84..a316fc8dfa7 100644 --- a/tests/support/win_installer.py +++ b/tests/support/win_installer.py @@ -21,15 +21,15 @@ def latest_installer_name(arch="AMD64", **kwargs): """ Create an installer file name """ - return "Salt-Minion-Latest-Py3-{}-Setup.exe".format(arch) + return f"Salt-Minion-Latest-Py3-{arch}-Setup.exe" def download_and_verify(fp, name, repo=REPO): """ Download an installer and verify its contents. """ - md5 = "{}.md5".format(name) - url = lambda x: "{}/{}".format(repo, x) + md5 = f"{name}.md5" + url = lambda x: f"{repo}/{x}" resp = requests.get(url(md5)) if resp.status_code != 200: raise Exception("Unable to fetch installer md5") diff --git a/tests/support/xmlunit.py b/tests/support/xmlunit.py index 940bbfe66ae..5b959799cc0 100644 --- a/tests/support/xmlunit.py +++ b/tests/support/xmlunit.py @@ -9,6 +9,7 @@ XML Unit Tests """ + # pylint: disable=wrong-import-order,wrong-import-position diff --git a/tests/support/zfs.py b/tests/support/zfs.py index 31fabe3d059..b9631ac1b6c 100644 --- a/tests/support/zfs.py +++ b/tests/support/zfs.py @@ -5,7 +5,6 @@ ZFS related unit test data structures """ - import salt.utils.zfs from tests.support.mock import MagicMock, patch diff --git a/tests/unit/ext/test_ipaddress.py b/tests/unit/ext/test_ipaddress.py index e4b2f98c357..95b3692ddce 100644 --- a/tests/unit/ext/test_ipaddress.py +++ b/tests/unit/ext/test_ipaddress.py @@ -265,7 +265,7 @@ class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): ("s", "1.2.3.42"), ("", "1.2.3.42"), ] - for (fmt, txt) in v4_pairs: + for fmt, txt in v4_pairs: self.assertEqual(txt, format(v4, fmt)) def test_network_passed_as_address(self): @@ -312,7 +312,7 @@ class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): def test_invalid_characters(self): def assertBadOctet(addr, octet): - msg = "Only decimal digits permitted in {!r} in {!r}".format(octet, addr) + msg = f"Only decimal digits permitted in {octet!r} in {addr!r}" with self.assertAddressError(re.escape(msg)): ipaddress.IPv4Address(addr) @@ -402,7 +402,7 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): ("", "::102:32a"), ] - for (fmt, txt) in v6_pairs: + for fmt, txt in v6_pairs: self.assertEqual(txt, format(v6, fmt)) def test_network_passed_as_address(self): @@ -657,7 +657,7 @@ class NetmaskTestMixin_v4(CommonTestMixin_v4): def assertBadNetmask(addr, netmask): msg = "%r is not a valid netmask" % netmask with self.assertNetmaskError(re.escape(msg)): - self.factory("{}/{}".format(addr, netmask)) + self.factory(f"{addr}/{netmask}") assertBadNetmask("1.2.3.4", "") assertBadNetmask("1.2.3.4", "-1") @@ -827,7 +827,7 @@ class NetmaskTestMixin_v6(CommonTestMixin_v6): def assertBadNetmask(addr, netmask): msg = "%r is not a valid netmask" % netmask with self.assertNetmaskError(re.escape(msg)): - self.factory("{}/{}".format(addr, netmask)) + self.factory(f"{addr}/{netmask}") assertBadNetmask("::1", "") assertBadNetmask("::1", "::1") diff --git a/tests/unit/modules/nxos/nxos_n36k.py b/tests/unit/modules/nxos/nxos_n36k.py index c6e0879665f..3721337158b 100644 --- a/tests/unit/modules/nxos/nxos_n36k.py +++ b/tests/unit/modules/nxos/nxos_n36k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N36KPlatform(NXOSPlatform): - """Cisco Systems N36K Platform Unit Test Object""" chassis = "Nexus3000 N3K-C36180YC-R Chassis" diff --git a/tests/unit/modules/nxos/nxos_n3k.py b/tests/unit/modules/nxos/nxos_n3k.py index 9436978273f..0210f26caee 100644 --- a/tests/unit/modules/nxos/nxos_n3k.py +++ b/tests/unit/modules/nxos/nxos_n3k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N3KPlatform(NXOSPlatform): - """Cisco Systems N3K Platform Unit Test Object""" chassis = "Nexus 3172 Chassis" diff --git a/tests/unit/modules/nxos/nxos_n5k.py b/tests/unit/modules/nxos/nxos_n5k.py index b5f21f2e691..ccaf838658a 100644 --- a/tests/unit/modules/nxos/nxos_n5k.py +++ b/tests/unit/modules/nxos/nxos_n5k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N5KPlatform(NXOSPlatform): - """Cisco Systems N5K Platform Unit Test Object""" chassis = "cisco Nexus 5672UP 16G-FC Chassis" diff --git a/tests/unit/modules/nxos/nxos_n7k.py b/tests/unit/modules/nxos/nxos_n7k.py index 18018748c66..ec7b84768c3 100644 --- a/tests/unit/modules/nxos/nxos_n7k.py +++ b/tests/unit/modules/nxos/nxos_n7k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N7KPlatform(NXOSPlatform): - """Cisco Systems N7K Platform Unit Test Object""" chassis = "Nexus7000 C7010 (10 Slot) Chassis" diff --git a/tests/unit/modules/nxos/nxos_n93k.py b/tests/unit/modules/nxos/nxos_n93k.py index a495da3da05..15517fa524e 100644 --- a/tests/unit/modules/nxos/nxos_n93k.py +++ b/tests/unit/modules/nxos/nxos_n93k.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N93KPlatform(NXOSPlatform): - """Cisco Systems N93K Platform Unit Test Object""" chassis = "Nexus9000 C9396PX Chassis" diff --git a/tests/unit/modules/nxos/nxos_n93klxc.py b/tests/unit/modules/nxos/nxos_n93klxc.py index 4f45e3650a9..6cb91a819da 100644 --- a/tests/unit/modules/nxos/nxos_n93klxc.py +++ b/tests/unit/modules/nxos/nxos_n93klxc.py @@ -19,7 +19,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N93KLXCPlatform(NXOSPlatform): - """Cisco Systems N93K (boot mode lxc) Platform Unit Test Object""" chassis = "Nexus9000 C9396PX (LXC) Chassis" diff --git a/tests/unit/modules/nxos/nxos_n95k.py b/tests/unit/modules/nxos/nxos_n95k.py index c249f5e0bb7..1e3146affa6 100644 --- a/tests/unit/modules/nxos/nxos_n95k.py +++ b/tests/unit/modules/nxos/nxos_n95k.py @@ -21,7 +21,6 @@ from tests.unit.modules.nxos.nxos_platform import NXOSPlatform class N95KPlatform(NXOSPlatform): - """Cisco Systems N9K Platform Unit Test Object""" chassis = "Nexus9000 C9508 (8 Slot) Chassis" diff --git a/tests/unit/modules/nxos/nxos_platform.py b/tests/unit/modules/nxos/nxos_platform.py index 02cc2736523..22d8c8dc036 100644 --- a/tests/unit/modules/nxos/nxos_platform.py +++ b/tests/unit/modules/nxos/nxos_platform.py @@ -25,7 +25,6 @@ from string import Template class NXOSPlatform: - """Cisco Systems Base Platform Unit Test Object""" chassis = "Unknown NXOS Chassis" @@ -106,7 +105,6 @@ Module Image Running-Version(pri:alt) New-Versi install_all_non_disruptive_success = None def __init__(self, *args, **kwargs): - """ ckimage - current kickstart image cimage - current system image @@ -163,14 +161,12 @@ Module Image Running-Version(pri:alt) New-Versi @staticmethod def templatize(template, values): - """Substitute variables in template with their corresponding values""" return Template(template).substitute(values) @staticmethod def version_from_image(image): - """Given a NXOS image named image decompose to appropriate image version""" ver = None diff --git a/tests/unit/modules/test_boto3_elasticsearch.py b/tests/unit/modules/test_boto3_elasticsearch.py index 0e60a9e0746..4c3156042bf 100644 --- a/tests/unit/modules/test_boto3_elasticsearch.py +++ b/tests/unit/modules/test_boto3_elasticsearch.py @@ -1,6 +1,7 @@ """ Tests for salt.modules.boto3_elasticsearch """ + import datetime import random import string diff --git a/tests/unit/modules/test_boto3_route53.py b/tests/unit/modules/test_boto3_route53.py index 5e7332fbb35..eb19cd5e6c9 100644 --- a/tests/unit/modules/test_boto3_route53.py +++ b/tests/unit/modules/test_boto3_route53.py @@ -1,6 +1,7 @@ """ Tests for salt.modules.boto3_route53 """ + import random import string diff --git a/tests/unit/modules/test_boto_route53.py b/tests/unit/modules/test_boto_route53.py index 5c257c09c33..4f884dacad6 100644 --- a/tests/unit/modules/test_boto_route53.py +++ b/tests/unit/modules/test_boto_route53.py @@ -70,7 +70,7 @@ def _has_required_moto(): @pytest.mark.skipif(HAS_MOTO is False, reason="The moto module must be installed.") @pytest.mark.skipif( _has_required_moto() is False, - reason="The moto module must be >= to {}".format(required_moto), + reason=f"The moto module must be >= to {required_moto}", ) class BotoRoute53TestCase(TestCase, LoaderModuleMockMixin): """ diff --git a/tests/unit/modules/test_boto_secgroup.py b/tests/unit/modules/test_boto_secgroup.py index 05167ffe774..1832dac4323 100644 --- a/tests/unit/modules/test_boto_secgroup.py +++ b/tests/unit/modules/test_boto_secgroup.py @@ -70,7 +70,7 @@ boto_conn_parameters = { def _random_group_id(): - group_id = "sg-{:x}".format(random.randrange(2**32)) + group_id = f"sg-{random.randrange(2**32):x}" return group_id diff --git a/tests/unit/modules/test_boto_vpc.py b/tests/unit/modules/test_boto_vpc.py index a670cd3628f..0841dd7ac0d 100644 --- a/tests/unit/modules/test_boto_vpc.py +++ b/tests/unit/modules/test_boto_vpc.py @@ -708,7 +708,7 @@ class BotoVpcTestCase(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): ) @pytest.mark.skipif( _has_required_moto() is False, - reason="The moto version must be >= to version {}".format(required_moto_version), + reason=f"The moto version must be >= to version {required_moto_version}", ) class BotoVpcSubnetsTestCase(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): @mock_ec2_deprecated @@ -1262,7 +1262,7 @@ class BotoVpcCustomerGatewayTestCase(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): ) @pytest.mark.skipif( _has_required_moto() is False, - reason="The moto version must be >= to version {}".format(required_moto_version), + reason=f"The moto version must be >= to version {required_moto_version}", ) class BotoVpcDHCPOptionsTestCase(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): @mock_ec2_deprecated @@ -2223,7 +2223,7 @@ class BotoVpcRouteTablesTestCase(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): ) @pytest.mark.skipif( _has_required_moto() is False, - reason="The moto version must be >= to version {}".format(required_moto_version), + reason=f"The moto version must be >= to version {required_moto_version}", ) class BotoVpcPeeringConnectionsTest(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): @mock_ec2_deprecated @@ -2239,7 +2239,7 @@ class BotoVpcPeeringConnectionsTest(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): name="my_peering", requester_vpc_id=my_vpc.id, peer_vpc_id=other_vpc.id, - **conn_parameters + **conn_parameters, ) ) @@ -2256,7 +2256,7 @@ class BotoVpcPeeringConnectionsTest(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): requester_vpc_id=my_vpc.id, peer_vpc_id=other_vpc.id, peer_region="test_region", - **conn_parameters + **conn_parameters, ) @mock_ec2_deprecated @@ -2272,14 +2272,14 @@ class BotoVpcPeeringConnectionsTest(BotoVpcTestCaseBase, BotoVpcTestCaseMixin): requester_vpc_id=my_vpc.id, requester_vpc_name="foobar", peer_vpc_id=other_vpc.id, - **conn_parameters + **conn_parameters, ) boto_vpc.request_vpc_peering_connection( name="my_peering", requester_vpc_name="my_peering", peer_vpc_id=other_vpc.id, - **conn_parameters + **conn_parameters, ) diff --git a/tests/unit/modules/test_bsd_shadow.py b/tests/unit/modules/test_bsd_shadow.py index 11e20c6e7f6..e60acb5172f 100644 --- a/tests/unit/modules/test_bsd_shadow.py +++ b/tests/unit/modules/test_bsd_shadow.py @@ -1,6 +1,7 @@ """ :codeauthor: Alan Somers """ + import re import pytest diff --git a/tests/unit/modules/test_cron.py b/tests/unit/modules/test_cron.py index 0a35436b332..ba031d4fb4d 100644 --- a/tests/unit/modules/test_cron.py +++ b/tests/unit/modules/test_cron.py @@ -849,7 +849,7 @@ class CronTestCase(TestCase, LoaderModuleMockMixin): (L + "# foo\n* * * * * ls\n"), ( L - + "# foo {}:blah\n".format(cron.SALT_CRON_IDENTIFIER) + + f"# foo {cron.SALT_CRON_IDENTIFIER}:blah\n" + "* * * * * ls\n" ), ] @@ -1428,7 +1428,7 @@ class PsTestCase(TestCase, LoaderModuleMockMixin): Expected to run without runas argument. """ temp_path = "some_temp_path" - crontab_cmd = "crontab {}".format(temp_path) + crontab_cmd = f"crontab {temp_path}" with patch.dict(cron.__grains__, {"os_family": "RedHat"}), patch.dict( cron.__salt__, {"cmd.run_all": MagicMock()} @@ -1480,7 +1480,7 @@ class PsTestCase(TestCase, LoaderModuleMockMixin): Expected to run with runas argument. """ temp_path = "some_temp_path" - crontab_cmd = "crontab {}".format(temp_path) + crontab_cmd = f"crontab {temp_path}" with patch.dict(cron.__grains__, {"os_family": "RedHat"}), patch.dict( cron.__salt__, {"cmd.run_all": MagicMock()} @@ -1508,7 +1508,7 @@ class PsTestCase(TestCase, LoaderModuleMockMixin): Expected to run with runas argument. """ temp_path = "some_temp_path" - crontab_cmd = "crontab {}".format(temp_path) + crontab_cmd = f"crontab {temp_path}" with patch.dict(cron.__grains__, {"os_family": "AIX"}), patch.dict( cron.__salt__, {"cmd.run_all": MagicMock()} @@ -1531,7 +1531,7 @@ class PsTestCase(TestCase, LoaderModuleMockMixin): Expected to run with runas argument. """ temp_path = "some_temp_path" - crontab_cmd = "crontab {}".format(temp_path) + crontab_cmd = f"crontab {temp_path}" with patch.dict(cron.__grains__, {"os_family": "Solaris"}), patch.dict( cron.__salt__, {"cmd.run_all": MagicMock()} diff --git a/tests/unit/modules/test_freezer.py b/tests/unit/modules/test_freezer.py index 436ec4b7446..aaa542d0e4a 100644 --- a/tests/unit/modules/test_freezer.py +++ b/tests/unit/modules/test_freezer.py @@ -3,7 +3,6 @@ :platform: Linux """ - import salt.modules.freezer as freezer from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_influxdb08mod.py b/tests/unit/modules/test_influxdb08mod.py index d58d99da138..79cf8542d87 100644 --- a/tests/unit/modules/test_influxdb08mod.py +++ b/tests/unit/modules/test_influxdb08mod.py @@ -2,7 +2,6 @@ :codeauthor: Rupesh Tare """ - import salt.modules.influxdb08mod as influx08 from tests.support.mock import MagicMock, patch from tests.support.unit import TestCase diff --git a/tests/unit/modules/test_k8s.py b/tests/unit/modules/test_k8s.py index db11296bde5..bec159ffd9a 100644 --- a/tests/unit/modules/test_k8s.py +++ b/tests/unit/modules/test_k8s.py @@ -81,7 +81,7 @@ class TestK8SSecrets(TestCase): def test_get_one_secret(self): name = self.name - filename = "/tmp/{}.json".format(name) + filename = f"/tmp/{name}.json" with salt.utils.files.fopen(filename, "w") as f: salt.utils.json.dump(self.request, f) @@ -102,7 +102,7 @@ class TestK8SSecrets(TestCase): def test_get_decoded_secret(self): name = self.name - filename = "/tmp/{}.json".format(name) + filename = f"/tmp/{name}.json" with salt.utils.files.fopen(filename, "w") as f: salt.utils.json.dump(self.request, f) @@ -124,12 +124,10 @@ class TestK8SSecrets(TestCase): names = [] expected_data = {} for i in range(2): - names.append("/tmp/{}-{}".format(name, i)) - with salt.utils.files.fopen("/tmp/{}-{}".format(name, i), "w") as f: - expected_data["{}-{}".format(name, i)] = base64.b64encode( - "{}{}".format(name, i) - ) - f.write(salt.utils.stringutils.to_str("{}{}".format(name, i))) + names.append(f"/tmp/{name}-{i}") + with salt.utils.files.fopen(f"/tmp/{name}-{i}", "w") as f: + expected_data[f"{name}-{i}"] = base64.b64encode(f"{name}{i}") + f.write(salt.utils.stringutils.to_str(f"{name}{i}")) res = k8s.create_secret( "default", name, names, apiserver_url="http://127.0.0.1:8080" ) @@ -145,7 +143,7 @@ class TestK8SSecrets(TestCase): def test_update_secret(self): name = self.name - filename = "/tmp/{}.json".format(name) + filename = f"/tmp/{name}.json" with salt.utils.files.fopen(filename, "w") as f: salt.utils.json.dump(self.request, f) @@ -157,12 +155,12 @@ class TestK8SSecrets(TestCase): expected_data = {} names = [] for i in range(3): - names.append("/tmp/{}-{}-updated".format(name, i)) - with salt.utils.files.fopen("/tmp/{}-{}-updated".format(name, i), "w") as f: - expected_data["{}-{}-updated".format(name, i)] = base64.b64encode( - "{}{}-updated".format(name, i) + names.append(f"/tmp/{name}-{i}-updated") + with salt.utils.files.fopen(f"/tmp/{name}-{i}-updated", "w") as f: + expected_data[f"{name}-{i}-updated"] = base64.b64encode( + f"{name}{i}-updated" ) - f.write("{}{}-updated".format(name, i)) + f.write(f"{name}{i}-updated") res = k8s.update_secret( "default", name, names, apiserver_url="http://127.0.0.1:8080" @@ -180,7 +178,7 @@ class TestK8SSecrets(TestCase): def test_delete_secret(self): name = self.name - filename = "/tmp/{}.json".format(name) + filename = f"/tmp/{name}.json" with salt.utils.files.fopen(filename, "w") as f: salt.utils.json.dump(self.request, f) @@ -199,9 +197,7 @@ class TestK8SSecrets(TestCase): kubectl_out, err = proc.communicate() # stdout is empty, stderr is showing something like "not found" self.assertEqual("", kubectl_out) - self.assertEqual( - 'Error from server: secrets "{}" not found\n'.format(name), err - ) + self.assertEqual(f'Error from server: secrets "{name}" not found\n', err) @pytest.mark.skip_if_binaries_missing("kubectl") @@ -241,12 +237,12 @@ spec: """.format( name ) - filename = "/tmp/{}.yaml".format(name) + filename = f"/tmp/{name}.yaml" with salt.utils.files.fopen(filename, "w") as f: f.write(salt.utils.stringutils.to_str(request)) create = Popen( - ["kubectl", "--namespace={}".format(namespace), "create", "-f", filename], + ["kubectl", f"--namespace={namespace}", "create", "-f", filename], stdout=PIPE, ) # wee need to give kubernetes time save data in etcd @@ -256,7 +252,7 @@ spec: proc = Popen( [ "kubectl", - "--namespace={}".format(namespace), + f"--namespace={namespace}", "get", "quota", "-o", @@ -292,12 +288,12 @@ spec: """.format( name ) - filename = "/tmp/{}.yaml".format(name) + filename = f"/tmp/{name}.yaml" with salt.utils.files.fopen(filename, "w") as f: f.write(salt.utils.stringutils.to_str(request)) create = Popen( - ["kubectl", "--namespace={}".format(namespace), "create", "-f", filename], + ["kubectl", f"--namespace={namespace}", "create", "-f", filename], stdout=PIPE, ) # wee need to give kubernetes time save data in etcd @@ -309,7 +305,7 @@ spec: proc = Popen( [ "kubectl", - "--namespace={}".format(namespace), + f"--namespace={namespace}", "get", "quota", name, @@ -335,7 +331,7 @@ spec: proc = Popen( [ "kubectl", - "--namespace={}".format(namespace), + f"--namespace={namespace}", "get", "quota", name, @@ -371,12 +367,12 @@ spec: """.format( name ) - filename = "/tmp/{}.yaml".format(name) + filename = f"/tmp/{name}.yaml" with salt.utils.files.fopen(filename, "w") as f: f.write(salt.utils.stringutils.to_str(request)) create = Popen( - ["kubectl", "--namespace={}".format(namespace), "create", "-f", filename], + ["kubectl", f"--namespace={namespace}", "create", "-f", filename], stdout=PIPE, ) # wee need to give kubernetes time save data in etcd @@ -392,7 +388,7 @@ spec: proc = Popen( [ "kubectl", - "--namespace={}".format(namespace), + f"--namespace={namespace}", "get", "quota", name, @@ -449,7 +445,7 @@ spec: name ) limits = {"Container": {"defaultRequest": {"cpu": "100m"}}} - filename = "/tmp/{}.yaml".format(name) + filename = f"/tmp/{name}.yaml" with salt.utils.files.fopen(filename, "w") as f: f.write(salt.utils.stringutils.to_str(request)) @@ -505,7 +501,7 @@ spec: """.format( name ) - filename = "/tmp/{}.yaml".format(name) + filename = f"/tmp/{name}.yaml" with salt.utils.files.fopen(filename, "w") as f: f.write(salt.utils.stringutils.to_str(request)) diff --git a/tests/unit/modules/test_kernelpkg_linux_apt.py b/tests/unit/modules/test_kernelpkg_linux_apt.py index 92f40f89767..cf56deb4a4a 100644 --- a/tests/unit/modules/test_kernelpkg_linux_apt.py +++ b/tests/unit/modules/test_kernelpkg_linux_apt.py @@ -4,6 +4,7 @@ :maturity: develop .. versionadded:: 2018.3.0 """ + # pylint: disable=invalid-name,no-member import re @@ -39,7 +40,7 @@ class AptKernelPkgTestCase(KernelPkgTestCase, TestCase, LoaderModuleMockMixin): @classmethod def setUpClass(cls): version = re.match(r"^(\d+\.\d+\.\d+)-(\d+)", cls.KERNEL_LIST[-1]) - cls.LATEST = "{}.{}".format(version.group(1), version.group(2)) + cls.LATEST = f"{version.group(1)}.{version.group(2)}" for kernel in cls.KERNEL_LIST: pkg = "{}-{}".format( @@ -66,8 +67,7 @@ class AptKernelPkgTestCase(KernelPkgTestCase, TestCase, LoaderModuleMockMixin): Test - Return return the latest installed kernel version """ PACKAGE_LIST = [ - "{}-{}".format(kernelpkg._package_prefix(), kernel) - for kernel in self.KERNEL_LIST + f"{kernelpkg._package_prefix()}-{kernel}" for kernel in self.KERNEL_LIST ] # pylint: disable=protected-access mock = MagicMock(return_value=PACKAGE_LIST) diff --git a/tests/unit/modules/test_kernelpkg_linux_yum.py b/tests/unit/modules/test_kernelpkg_linux_yum.py index 4005a4897d7..058af383d60 100644 --- a/tests/unit/modules/test_kernelpkg_linux_yum.py +++ b/tests/unit/modules/test_kernelpkg_linux_yum.py @@ -4,6 +4,7 @@ :maturity: develop .. versionadded:: 2018.3.0 """ + # pylint: disable=invalid-name,no-member import pytest @@ -42,7 +43,7 @@ class YumKernelPkgTestCase(KernelPkgTestCase, TestCase, LoaderModuleMockMixin): "__grains__": { "os": self.OS_NAME, "osmajorrelease": self.OS_MAJORRELEASE, - "kernelrelease": "{}.{}".format(self.KERNEL_LIST[0], self.OS_ARCH), + "kernelrelease": f"{self.KERNEL_LIST[0]}.{self.OS_ARCH}", }, "__salt__": { "pkg.normalize_name": pkg.normalize_name, diff --git a/tests/unit/modules/test_kubernetesmod.py b/tests/unit/modules/test_kubernetesmod.py index 4d38d63bb51..049ed53663f 100644 --- a/tests/unit/modules/test_kubernetesmod.py +++ b/tests/unit/modules/test_kubernetesmod.py @@ -1,6 +1,7 @@ """ :codeauthor: Jochen Breuer """ + # pylint: disable=no-value-for-parameter import os from contextlib import contextmanager diff --git a/tests/unit/modules/test_libcloud_compute.py b/tests/unit/modules/test_libcloud_compute.py index a95a64c1bad..15893fefe3b 100644 --- a/tests/unit/modules/test_libcloud_compute.py +++ b/tests/unit/modules/test_libcloud_compute.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import logging import pytest diff --git a/tests/unit/modules/test_libcloud_dns.py b/tests/unit/modules/test_libcloud_dns.py index 87416c98199..77c64fa1ed2 100644 --- a/tests/unit/modules/test_libcloud_dns.py +++ b/tests/unit/modules/test_libcloud_dns.py @@ -1,6 +1,7 @@ """ :codeauthor: Anthony Shaw """ + import pytest import salt.modules.libcloud_dns as libcloud_dns diff --git a/tests/unit/modules/test_libcloud_loadbalancer.py b/tests/unit/modules/test_libcloud_loadbalancer.py index 02ae019759c..69b8ae26117 100644 --- a/tests/unit/modules/test_libcloud_loadbalancer.py +++ b/tests/unit/modules/test_libcloud_loadbalancer.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import pytest import salt.modules.libcloud_loadbalancer as libcloud_loadbalancer diff --git a/tests/unit/modules/test_libcloud_storage.py b/tests/unit/modules/test_libcloud_storage.py index 8f7fd069782..9347e2571c2 100644 --- a/tests/unit/modules/test_libcloud_storage.py +++ b/tests/unit/modules/test_libcloud_storage.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Anthony Shaw ` """ + import pytest import salt.modules.libcloud_storage as libcloud_storage diff --git a/tests/unit/modules/test_linux_acl.py b/tests/unit/modules/test_linux_acl.py index 35dadbedacf..b8e601344f1 100644 --- a/tests/unit/modules/test_linux_acl.py +++ b/tests/unit/modules/test_linux_acl.py @@ -15,7 +15,7 @@ class LinuxAclTestCase(TestCase, LoaderModuleMockMixin): self.file = "/tmp/file" self.quoted_file = '"/tmp/file"' self.files = ["/tmp/file1", "/tmp/file2", "/tmp/file3 with whitespaces"] - self.quoted_files = ['"{}"'.format(f) for f in self.files] + self.quoted_files = [f'"{f}"' for f in self.files] self.u_acl = ["u", "myuser", "rwx"] self.user_acl = ["user", "myuser", "rwx"] self.user_acl_cmd = "u:myuser:rwx" diff --git a/tests/unit/modules/test_localemod.py b/tests/unit/modules/test_localemod.py index 83496de3dfd..cc2706b20be 100644 --- a/tests/unit/modules/test_localemod.py +++ b/tests/unit/modules/test_localemod.py @@ -1,6 +1,7 @@ """ :codeauthor: Rupesh Tare """ + import pytest import salt.modules.localemod as localemod @@ -417,9 +418,7 @@ class LocalemodTestCase(TestCase, LoaderModuleMockMixin): == "/etc/sysconfig/language" ) assert localemod.__salt__["file.replace"].call_args[0][1] == "^RC_LANG=.*" - assert localemod.__salt__["file.replace"].call_args[0][ - 2 - ] == 'RC_LANG="{}"'.format(loc) + assert localemod.__salt__["file.replace"].call_args[0][2] == f'RC_LANG="{loc}"' @patch("salt.utils.path.which", MagicMock(return_value=None)) @patch( diff --git a/tests/unit/modules/test_memcached.py b/tests/unit/modules/test_memcached.py index b62986f2317..f51c9fb8e8d 100644 --- a/tests/unit/modules/test_memcached.py +++ b/tests/unit/modules/test_memcached.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.memcached as memcached from salt.exceptions import CommandExecutionError, SaltInvocationError from tests.support.mock import MagicMock, patch diff --git a/tests/unit/modules/test_napalm_probes.py b/tests/unit/modules/test_napalm_probes.py index 2ebda0dc84a..6eaa80b8310 100644 --- a/tests/unit/modules/test_napalm_probes.py +++ b/tests/unit/modules/test_napalm_probes.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import salt.modules.napalm_probes as napalm_probes import tests.support.napalm as napalm_test_support from tests.support.mixins import LoaderModuleMockMixin @@ -53,7 +52,7 @@ class NapalmProbesModuleTestCase(TestCase, LoaderModuleMockMixin): if template == "schedule_probes": assert kwargs["probes"] == self._test_schedule_probes.copy() return napalm_test_support.TEST_TERM_CONFIG.copy() - raise ValueError("incorrect template {}".format(template)) + raise ValueError(f"incorrect template {template}") module_globals = { "__salt__": { diff --git a/tests/unit/modules/test_napalm_yang_mod.py b/tests/unit/modules/test_napalm_yang_mod.py index 9d711b04ca3..6e5f848fb10 100644 --- a/tests/unit/modules/test_napalm_yang_mod.py +++ b/tests/unit/modules/test_napalm_yang_mod.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Anthony Shaw ` """ - import salt.modules.napalm_network as napalm_network import salt.modules.napalm_yang_mod as napalm_yang_mod import tests.support.napalm as napalm_test_support diff --git a/tests/unit/modules/test_netbox.py b/tests/unit/modules/test_netbox.py index a2257068b75..45958e677fb 100644 --- a/tests/unit/modules/test_netbox.py +++ b/tests/unit/modules/test_netbox.py @@ -1,6 +1,7 @@ """ :codeauthor: :email:`Zach Moody ` """ + import pytest import salt.modules.netbox as netbox diff --git a/tests/unit/modules/test_netscaler.py b/tests/unit/modules/test_netscaler.py index 46b195ec297..d320f0fbe5a 100644 --- a/tests/unit/modules/test_netscaler.py +++ b/tests/unit/modules/test_netscaler.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.netscaler as netscaler from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import MagicMock, patch diff --git a/tests/unit/modules/test_neutron.py b/tests/unit/modules/test_neutron.py index 7fed7bcc121..c6fb5b38445 100644 --- a/tests/unit/modules/test_neutron.py +++ b/tests/unit/modules/test_neutron.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.neutron as neutron from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import MagicMock diff --git a/tests/unit/modules/test_nova.py b/tests/unit/modules/test_nova.py index f9cb3db9490..47fa1d3742d 100644 --- a/tests/unit/modules/test_nova.py +++ b/tests/unit/modules/test_nova.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import salt.modules.nova as nova from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import MagicMock, patch diff --git a/tests/unit/modules/test_nxos.py b/tests/unit/modules/test_nxos.py index 7610abadab0..cedf1e707ff 100644 --- a/tests/unit/modules/test_nxos.py +++ b/tests/unit/modules/test_nxos.py @@ -45,7 +45,6 @@ from tests.unit.modules.nxos.nxos_show_run import ( class NxosTestCase(TestCase, LoaderModuleMockMixin): - """Test cases for salt.modules.nxos""" COPY_RS = "copy running-config startup-config" @@ -58,14 +57,12 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): @staticmethod def test_check_virtual(): - """UT: nxos module:check_virtual method - return value""" result = nxos_module.__virtual__() assert "nxos" in result def test_ping_proxy(self): - """UT: nxos module:ping method - proxy""" with patch("salt.utils.platform.is_proxy", return_value=True, autospec=True): with patch.dict( @@ -75,7 +72,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_ping_native_minion(self): - """UT: nxos module:ping method - proxy""" with patch("salt.utils.platform.is_proxy", return_value=False, autospec=True): @@ -86,7 +82,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_password_return_none(self): - """UT: nxos module:check_password method - return None""" username = "admin" @@ -97,7 +92,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIsNone(result) def test_check_password_password_nxos_comment(self): - """UT: nxos module:check_password method - password_line has '!'""" username = "admin" @@ -112,7 +106,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): reason="compatible crypt method for fake data not available", ) def test_check_password_password_encrypted_false(self): - """UT: nxos module:check_password method - password is not encrypted""" username = "salt_test" @@ -127,7 +120,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_password_password_encrypted_true(self): - """UT: nxos module:check_password method - password is encrypted""" username = "salt_test" @@ -142,7 +134,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_password_password_encrypted_true_negative(self): - """UT: nxos module:check_password method - password is not encrypted""" username = "salt_test" @@ -155,7 +146,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertFalse(result) def test_check_role_true(self): - """UT: nxos module:check_role method - Role configured""" username = "salt_test" @@ -166,7 +156,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_check_role_false(self): - """UT: nxos module:check_role method - Role not configured""" username = "salt_test" @@ -177,7 +166,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertFalse(result) def test_cmd_any_function(self): - """UT: nxos module:cmd method - check_role function""" with patch.dict( @@ -198,7 +186,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertTrue(result) def test_cmd_function_absent(self): - """UT: nxos module:cmd method - non existent function""" result = nxos_module.cmd( @@ -207,7 +194,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertFalse(result) def test_find_single_match(self): - """UT: nxos module:test_find method - Find single match in running config""" find_pattern = "^vrf context testing$" @@ -220,7 +206,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn(find_string, result) def test_find_multiple_matches(self): - """UT: nxos module:test_find method - Find multiple matches in running config""" find_pattern = "^no logging.*$" @@ -234,7 +219,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(len(result), 7) def test_get_roles_user_not_configured(self): - """UT: nxos module:get_roles method - User not configured""" username = "salt_does_not_exist" @@ -245,7 +229,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, []) def test_get_roles_user_configured(self): - """UT: nxos module:get_roles method - User configured""" username = "salt_test" @@ -260,7 +243,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result.sort(), expected_result.sort()) def test_get_roles_user_configured_no_role(self): - """UT: nxos module:get_roles method - User configured no roles""" username = "salt_test" @@ -271,7 +253,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, []) def test_get_user_configured(self): - """UT: nxos module:get_user method - User configured""" username = "salt_test" @@ -286,7 +267,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_grains(self): - """UT: nxos module:grains method""" nxos_module.DEVICE_DETAILS["grains_cache"] = {} @@ -316,7 +296,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_grains_get_cache(self): - """UT: nxos module:grains method""" expected_grains = { @@ -346,7 +325,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_grains_refresh(self): - """UT: nxos module:grains_refresh method""" expected_grains = { @@ -368,7 +346,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_system_info(self): - """UT: nxos module:system_info method""" expected_grains = { @@ -397,7 +374,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_grains) def test_sendline_invalid_method(self): - """UT: nxos module:sendline method - invalid method""" command = "show version" @@ -409,7 +385,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn("INPUT ERROR", result) def test_sendline_valid_method_proxy(self): - """UT: nxos module:sendline method - valid method over proxy""" command = "show version" @@ -424,7 +399,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn(n9k_show_ver, result) def test_sendline_valid_method_nxapi_uds(self): - """UT: nxos module:sendline method - valid method over nxapi uds""" command = "show version" @@ -440,7 +414,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn(n9k_show_ver, result) def test_show_raw_text_invalid(self): - """UT: nxos module:show method - invalid argument""" command = "show version" @@ -450,7 +423,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertIn("INPUT ERROR", result) def test_show_raw_text_true(self): - """UT: nxos module:show method - raw_test true""" command = "show version" @@ -463,7 +435,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, n9k_show_ver) def test_show_raw_text_true_multiple_commands(self): - """UT: nxos module:show method - raw_test true multiple commands""" command = "show bgp sessions ; show processes" @@ -475,7 +446,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, data) def test_show_nxapi(self): - """UT: nxos module:show method - nxapi returns info as list""" command = "show version; show interface eth1/1" @@ -491,7 +461,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result[1], n9k_show_ver_int_list[1]) def test_show_nxapi_structured(self): - """UT: nxos module:show method - nxapi returns info as list""" command = "show version; show interface eth1/1" @@ -507,7 +476,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result[1], n9k_show_ver_int_list_structured[1]) def test_show_run(self): - """UT: nxos module:show_run method""" expected_output = n9k_show_running_config_list[0] @@ -518,7 +486,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_show_ver(self): - """UT: nxos module:show_ver method""" expected_output = n9k_show_ver_list[0] @@ -529,7 +496,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_add_config(self): - """UT: nxos module:add_config method""" expected_output = "COMMAND_LIST: feature bgp" @@ -541,7 +507,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_commands(self): - """UT: nxos module:config method - Using commands arg""" commands = ["no feature ospf", ["no feature ospf"]] @@ -573,7 +538,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_commands_template_none(self): - """UT: nxos module:config method - Template engine is None""" commands = ["no feature ospf", ["no feature ospf"]] @@ -605,7 +569,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_commands_string(self): - """UT: nxos module:config method - Using commands arg and output is string""" commands = "no feature ospf" @@ -636,7 +599,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_file(self): - """UT: nxos module:config method - Using config_file arg""" config_file = "salt://bgp_config.txt" @@ -676,7 +638,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_config_file_error1(self): - """UT: nxos module:config method - Error file not found""" config_file = "salt://bgp_config.txt" @@ -704,7 +665,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): nxos_module.config(config_file=config_file) def test_config_nxos_error_ssh(self): - """UT: nxos module:config method - nxos device error over ssh transport""" commands = ["feature bgp", "router bgp 57"] @@ -740,7 +700,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, expected_output) def test_commands_error(self): - """UT: nxos module:config method - Mandatory arg commands not specified""" commands = None @@ -768,7 +727,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): nxos_module.config(commands=commands) def test_config_file_error2(self): - """UT: nxos module:config method - Mandatory arg config_file not specified""" config_file = None @@ -796,7 +754,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): nxos_module.config(config_file=config_file) def test_delete_config(self): - """UT: nxos module:delete_config method""" for lines in ["feature bgp", ["feature bgp"]]: @@ -806,7 +763,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, nxos_module.config.return_value) def test_remove_user(self): - """UT: nxos module:remove_user method""" with patch("salt.modules.nxos.config", autospec=True): @@ -815,7 +771,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, nxos_module.config.return_value) def test_replace(self): - """UT: nxos module:replace method""" old_value = "feature bgp" @@ -837,7 +792,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result["new"], ["feature ospf"]) def test_replace_full_match_true(self): - """UT: nxos module:replace method - full match true""" old_value = "feature bgp" @@ -859,7 +813,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result["new"], ["feature ospf"]) def test_replace_no_match(self): - """UT: nxos module:replace method - no match""" old_value = "feature does_not_exist" @@ -881,7 +834,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result["new"], []) def test_save_running_config(self): - """UT: nxos module:save_running_config method""" with patch( @@ -891,7 +843,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, save_running_config) def test_set_password_enc_false_cs_none(self): - """UT: nxos module:set_password method - encrypted False, crypt_salt None""" username = "devops" @@ -916,7 +867,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_enc_false_cs_set(self): - """UT: nxos module:set_password method - encrypted False, crypt_salt set""" username = "devops" @@ -944,7 +894,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_enc_true(self): - """UT: nxos module:set_password method - encrypted True""" username = "devops" @@ -968,7 +917,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_role_none(self): - """UT: nxos module:set_password method - role none""" username = "devops" @@ -993,7 +941,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual("password_set", result) def test_set_password_blowfish_crypt(self): - """UT: nxos module:set_password method - role none""" with self.assertRaises(SaltInvocationError): @@ -1002,7 +949,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): ) def test_set_role(self): - """UT: nxos module:save_running_config method""" username = "salt_test" @@ -1013,7 +959,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, set_role) def test_unset_role(self): - """UT: nxos module:save_running_config method""" username = "salt_test" @@ -1024,7 +969,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, unset_role) def test_configure_device(self): - """UT: nxos module:_configure_device method""" with patch("salt.utils.platform.is_proxy", autospec=True, return_value=True): @@ -1043,7 +987,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, "configured") def test_nxapi_config(self): - """UT: nxos module:_nxapi_config method""" mock_cmd = MagicMock(return_value={"nxos": {"save_config": False}}) @@ -1057,7 +1000,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, [["show version"], "router_data"]) def test_nxapi_config_failure(self): - """UT: nxos module:_nxapi_config method""" side_effect = ["Failure", "saved_data"] @@ -1073,7 +1015,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, [["show bad_command"], "Failure"]) def test_nxapi_request_proxy(self): - """UT: nxos module:_nxapi_request method - proxy""" with patch("salt.utils.platform.is_proxy", autospec=True, return_value=True): @@ -1087,7 +1028,6 @@ class NxosTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(result, "router_data") def test_nxapi_request_no_proxy(self): - """UT: nxos module:_nxapi_request method - no proxy""" with patch("salt.utils.platform.is_proxy", autospec=True, return_value=False): diff --git a/tests/unit/modules/test_nxos_upgrade.py b/tests/unit/modules/test_nxos_upgrade.py index 1b6be938ef4..1c0c5013caf 100644 --- a/tests/unit/modules/test_nxos_upgrade.py +++ b/tests/unit/modules/test_nxos_upgrade.py @@ -35,14 +35,12 @@ from tests.unit.modules.nxos.nxos_n95k import N95KPlatform class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): - """Test cases for salt.modules.nxos_upgrade""" platform_list = None @staticmethod def assert_platform_upgrade(condition, platform): - """Assert platform upgrade condition and display appropriate chassis & images upon assertion failure""" assert bool(condition), "{}: Upgrade {} -> {}".format( @@ -50,7 +48,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): ) def setup_loader_modules(self): - """Define list of platforms for Unit Test""" self.platform_list = [ @@ -81,7 +78,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): @staticmethod def test_check_upgrade_impact_input_validation(): - """UT: nxos_upgrade module:check_upgrade_impact method - input validation""" result = nxos_upgrade.check_upgrade_impact("dummy-platform-image.bin", issu=1) @@ -89,14 +85,12 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): @staticmethod def test_upgrade_input_validation(): - """UT: nxos_upgrade module:upgrade method - input validation""" result = nxos_upgrade.upgrade("dummy-platform-image.bin", issu=1) assert "Input Error" in result def test_check_upgrade_impact_backend_processing_error_500(self): - """UT: nxos_upgrade module:check_upgrade_impact method - error HTTP code 500""" for platform in self.platform_list: @@ -116,7 +110,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_internal_server_error_400_invalid_command(self): - """UT: nxos_upgrade module:check_upgrade_impact method - invalid command error HTTP code 400""" for platform in self.platform_list: @@ -134,7 +127,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_internal_server_error_400_in_progress(self): - """UT: nxos_upgrade module:check_upgrade_impact method - in-progress error HTTP code 400""" for platform in self.platform_list: @@ -152,7 +144,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_internal_server_error_500(self): - """UT: nxos_upgrade module:check_upgrade_impact method - internal server error HTTP code 500""" for platform in self.platform_list: @@ -176,7 +167,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_check_upgrade_impact_non_disruptive_success(self): - """UT: nxos_upgrade module:check_upgrade_impact method - non-disruptive success""" for platform in self.platform_list: @@ -197,7 +187,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["module_data"], platform) def test_check_upgrade_impact_disruptive_success(self): - """UT: nxos_upgrade module:check_upgrade_impact method - disruptive success""" for platform in self.platform_list: @@ -225,7 +214,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["module_data"], platform) def test_upgrade_show_install_all_impact_no_module_data(self): - """UT: nxos_upgrade module: upgrade method - no module data""" for platform in self.platform_list: @@ -245,7 +233,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): ) def test_upgrade_invalid_command(self): - """UT: nxos_upgrade module:upgrade method - invalid command""" for platform in self.platform_list: @@ -259,7 +246,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_in_progress(self): - """UT: nxos_upgrade module:upgrade method - in-progress""" for platform in self.platform_list: @@ -277,7 +263,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_in_progress_terminal_dont_ask(self): - """UT: nxos_upgrade module:upgrade method - in-progress (terminal don't-ask)""" for platform in self.platform_list: @@ -298,7 +283,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_in_progress_sans_terminal_dont_ask(self): - """UT: nxos_upgrade module:upgrade method - in-progress (sans terminal don't-ask)""" for platform in self.platform_list: @@ -316,7 +300,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_internal_server_error_500(self): - """UT: nxos_upgrade module:upgrade method - internal server error 500""" for platform in self.platform_list: @@ -337,7 +320,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_install_all_disruptive(self): - """UT: nxos_upgrade module:upgrade method - install all disruptive""" for platform in self.platform_list: @@ -367,7 +349,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): ) def test_upgrade_install_all_non_disruptive(self): - """UT: nxos_upgrade module:upgrade method - install all non-disruptive""" for platform in self.platform_list: @@ -390,7 +371,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["succeeded"], platform) def test_upgrade_CommandExecutionError_Exception(self): - """UT: nxos_upgrade module:upgrade method - raise CommandExecutionError exception #1""" for platform in self.platform_list: @@ -418,7 +398,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(not result["succeeded"], platform) def test_upgrade_CommandExecutionError_Exception2(self): - """UT: nxos_upgrade module:upgrade method - raise CommandExecutionError exception #2""" for platform in self.platform_list: @@ -454,7 +433,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["succeeded"], platform) def test_upgrade_NxosError_Exception(self): - """UT: nxos_upgrade module:upgrade method - raise NxosError exception""" for platform in self.platform_list: @@ -485,7 +463,6 @@ class NxosUpgradeTestCase(TestCase, LoaderModuleMockMixin): self.assert_platform_upgrade(result["succeeded"], platform) def test_upgrade_NxosError_Exception2(self): - """UT: nxos_upgrade module:upgrade method - raise NxosError exception #2""" for platform in self.platform_list: diff --git a/tests/unit/modules/test_openstack_config.py b/tests/unit/modules/test_openstack_config.py index 56976992c21..d014547160d 100644 --- a/tests/unit/modules/test_openstack_config.py +++ b/tests/unit/modules/test_openstack_config.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.openstack_config as openstack_config from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_opkg.py b/tests/unit/modules/test_opkg.py index d1df495db4b..6242f5fa31a 100644 --- a/tests/unit/modules/test_opkg.py +++ b/tests/unit/modules/test_opkg.py @@ -51,9 +51,9 @@ class OpkgTestCase(TestCase, LoaderModuleMockMixin): @classmethod def tearDownClass(cls): - cls.opkg_vim_info = ( - cls.opkg_vim_files - ) = cls.installed = cls.removed = cls.packages = None + cls.opkg_vim_info = cls.opkg_vim_files = cls.installed = cls.removed = ( + cls.packages + ) = None def setup_loader_modules(self): # pylint: disable=no-self-use """ diff --git a/tests/unit/modules/test_parted_partition.py b/tests/unit/modules/test_parted_partition.py index b164569c0c4..72fdded4af0 100644 --- a/tests/unit/modules/test_parted_partition.py +++ b/tests/unit/modules/test_parted_partition.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import salt.modules.parted_partition as parted from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_rh_ip.py b/tests/unit/modules/test_rh_ip.py index d061978ae35..b868144fb91 100644 --- a/tests/unit/modules/test_rh_ip.py +++ b/tests/unit/modules/test_rh_ip.py @@ -509,7 +509,7 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): expected = [ "downdelay=200", "miimon=100", - "mode={}".format(mode_num), + f"mode={mode_num}", "use_carrier=0", ] assert bonding_opts == expected, bonding_opts @@ -523,7 +523,7 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): "arp_ip_target=1.2.3.4,5.6.7.8", "downdelay=200", "miimon=100", - "mode={}".format(mode_num), + f"mode={mode_num}", "use_carrier=0", ] assert bonding_opts == expected, bonding_opts @@ -535,7 +535,7 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): expected = [ "arp_interval=300", "arp_ip_target=1.2.3.4,5.6.7.8", - "mode={}".format(mode_num), + f"mode={mode_num}", ] assert bonding_opts == expected, bonding_opts @@ -718,7 +718,7 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): "miimon=100", "mode=4", "use_carrier=0", - "xmit_hash_policy={}".format(hash_alg), + f"xmit_hash_policy={hash_alg}", ] assert bonding_opts == expected, bonding_opts @@ -739,7 +739,7 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): "miimon=100", "mode=4", "use_carrier=0", - "xmit_hash_policy={}".format(hash_alg), + f"xmit_hash_policy={hash_alg}", ] assert bonding_opts == expected, bonding_opts @@ -786,14 +786,12 @@ class RhipTestCase(TestCase, LoaderModuleMockMixin): raise else: expected = [ - "ad_select={}".format(ad_select), + f"ad_select={ad_select}", "downdelay=200", "lacp_rate={}".format( "1" if lacp_rate == "fast" - else "0" - if lacp_rate == "slow" - else lacp_rate + else "0" if lacp_rate == "slow" else lacp_rate ), "miimon=100", "mode=4", diff --git a/tests/unit/modules/test_snapper.py b/tests/unit/modules/test_snapper.py index 0729ad9a1ef..2ca4250e642 100644 --- a/tests/unit/modules/test_snapper.py +++ b/tests/unit/modules/test_snapper.py @@ -4,6 +4,7 @@ Unit tests for the Snapper module :codeauthor: Duncan Mac-Vicar P. :codeauthor: Pablo Suárez Hernández """ + import pytest import salt.modules.snapper as snapper diff --git a/tests/unit/modules/test_sqlite3.py b/tests/unit/modules/test_sqlite3.py index 1b534e7d963..8b69855dcce 100644 --- a/tests/unit/modules/test_sqlite3.py +++ b/tests/unit/modules/test_sqlite3.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.sqlite3 as sqlite3 from tests.support.mixins import LoaderModuleMockMixin from tests.support.unit import TestCase diff --git a/tests/unit/modules/test_ssh.py b/tests/unit/modules/test_ssh.py index 8ffbed434d5..10822f837f5 100644 --- a/tests/unit/modules/test_ssh.py +++ b/tests/unit/modules/test_ssh.py @@ -116,7 +116,7 @@ class SSHAuthKeyTestCase(TestCase, LoaderModuleMockMixin): _fh.write(comment_line) # Add empty line for #41335 _fh.write(empty_line) - _fh.write("{} {} {} {}".format(options, enc, key, email)) + _fh.write(f"{options} {enc} {key} {email}") with patch.dict(ssh.__salt__, {"user.info": MagicMock(return_value={})}): with patch( @@ -138,7 +138,7 @@ class SSHAuthKeyTestCase(TestCase, LoaderModuleMockMixin): key = "abcxyz" with salt.utils.files.fopen(temp_file.name, "a") as _fh: - _fh.write(salt.utils.stringutils.to_str("{} {}".format(enc, key))) + _fh.write(salt.utils.stringutils.to_str(f"{enc} {key}")) # Replace the simple key from before with the more complicated options + new email # Option example is taken from Pull Request #39855 @@ -181,7 +181,7 @@ class SSHAuthKeyTestCase(TestCase, LoaderModuleMockMixin): key = "abcxyz" with salt.utils.files.fopen(temp_file.name, "a") as _fh: - _fh.write(salt.utils.stringutils.to_str("{} {}".format(enc, key))) + _fh.write(salt.utils.stringutils.to_str(f"{enc} {key}")) # Replace the simple key from before with the more complicated options + new email # Option example is taken from Pull Request #39855 @@ -209,7 +209,7 @@ class SSHAuthKeyTestCase(TestCase, LoaderModuleMockMixin): with salt.utils.files.fopen(temp_file.name) as _fh: file_txt = salt.utils.stringutils.to_unicode(_fh.read()) # the initial key must have been replaced and no longer present - self.assertNotIn("\n{} {}\n".format(enc, key), file_txt) + self.assertNotIn(f"\n{enc} {key}\n", file_txt) # the new key must be present self.assertIn( "{} {} {} {}".format(",".join(options), enc, key, email), file_txt @@ -231,11 +231,7 @@ class SSHAuthKeyTestCase(TestCase, LoaderModuleMockMixin): email = "foo@example.com" with salt.utils.files.fopen(temp_file.name, "w") as _fh: - _fh.write( - salt.utils.stringutils.to_str( - "{} {} {} {}".format(options, enc, key, email) - ) - ) + _fh.write(salt.utils.stringutils.to_str(f"{options} {enc} {key} {email}")) with patch.dict(ssh.__salt__, {"user.info": MagicMock(return_value={})}): with patch( @@ -251,7 +247,7 @@ class SSHAuthKeyTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual( ssh.rm_auth_key( "foo", - "{}".format(key), + f"{key}", config=temp_file.name, ), "Key removed", diff --git a/tests/unit/modules/test_supervisord.py b/tests/unit/modules/test_supervisord.py index 1d4ce112f27..8bcae14288e 100644 --- a/tests/unit/modules/test_supervisord.py +++ b/tests/unit/modules/test_supervisord.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.supervisord as supervisord from salt.exceptions import CommandExecutionError from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/modules/test_sysmod.py b/tests/unit/modules/test_sysmod.py index 00185a90099..bd0d7073e8c 100644 --- a/tests/unit/modules/test_sysmod.py +++ b/tests/unit/modules/test_sysmod.py @@ -2,7 +2,6 @@ :codeauthor: Jayesh Kariya """ - import salt.modules.sysmod as sysmod from tests.support.mixins import LoaderModuleMockMixin from tests.support.mock import patch @@ -108,18 +107,18 @@ class SysmodTestCase(TestCase, LoaderModuleMockMixin): cls.salt_dunder = {} for func in cls._functions: - docstring = "docstring for {}".format(func) + docstring = f"docstring for {func}" cls.salt_dunder[func] = MockDocstringable(docstring) cls._docstrings[func] = docstring module = func.split(".")[0] cls._statedocstrings[func] = docstring - cls._statedocstrings[module] = "docstring for {}".format(module) + cls._statedocstrings[module] = f"docstring for {module}" cls._modules.add(func.split(".")[0]) - docstring = "docstring for {}".format(func) + docstring = f"docstring for {func}" mock = MockDocstringable(docstring) mock.set_module_docstring("docstring for {}".format(func.split(".")[0])) Mockstate.State.states[func] = mock diff --git a/tests/unit/modules/test_twilio_notify.py b/tests/unit/modules/test_twilio_notify.py index 682cb7f7711..4785e4a974d 100644 --- a/tests/unit/modules/test_twilio_notify.py +++ b/tests/unit/modules/test_twilio_notify.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.twilio_notify as twilio_notify diff --git a/tests/unit/modules/test_useradd.py b/tests/unit/modules/test_useradd.py index bc7903dd5bb..533e3644b3e 100644 --- a/tests/unit/modules/test_useradd.py +++ b/tests/unit/modules/test_useradd.py @@ -1,6 +1,7 @@ """ :codeauthor: Jayesh Kariya """ + import pytest import salt.modules.useradd as useradd diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py index 0342152a72d..d595b67f6c5 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py @@ -1831,18 +1831,22 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): ret = virt._diff_disk_lists(old_disks, new_disks) self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["unchanged"] ], [], ) self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["new"] ], ["/path/to/img3.qcow2", "/path/to/img0.qcow2", "/path/to/img4.qcow2", None], @@ -1853,9 +1857,11 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): ) self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["sorted"] ], ["/path/to/img3.qcow2", "/path/to/img0.qcow2", "/path/to/img4.qcow2", None], @@ -1863,9 +1869,11 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): self.assertEqual(ret["new"][1].find("target").get("bus"), "virtio") self.assertEqual( [ - disk.find("source").get("file") - if disk.find("source") is not None - else None + ( + disk.find("source").get("file") + if disk.find("source") is not None + else None + ) for disk in ret["deleted"] ], [ @@ -3501,9 +3509,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): }, virt.update("vm_with_memtune_param", mem=memtune_new_val), ) - self.assertEqual( - domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2) - ) + self.assertEqual(domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2)) setxml = ET.fromstring(define_mock.call_args[0][0]) self.assertEqual( @@ -3569,9 +3575,7 @@ class VirtTestCase(TestCase, LoaderModuleMockMixin): }, virt.update("vm_with_memtune_param", mem=max_swap_none), ) - self.assertEqual( - domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2) - ) + self.assertEqual(domain_mock.setMemoryFlags.call_args[0][0], int(2.5 * 1024**2)) setxml = ET.fromstring(define_mock.call_args[0][0]) self.assertEqual( diff --git a/tests/unit/modules/test_virtualenv_mod.py b/tests/unit/modules/test_virtualenv_mod.py index 468ce61f235..552a93264b2 100644 --- a/tests/unit/modules/test_virtualenv_mod.py +++ b/tests/unit/modules/test_virtualenv_mod.py @@ -278,7 +278,7 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin): python=sys.executable, ) mock.assert_called_once_with( - ["virtualenv", "--python={}".format(sys.executable), "/tmp/foo"], + ["virtualenv", f"--python={sys.executable}", "/tmp/foo"], runas=None, python_shell=False, ) diff --git a/tests/unit/modules/test_vsphere.py b/tests/unit/modules/test_vsphere.py index 7dcb13e4d30..da64fe52239 100644 --- a/tests/unit/modules/test_vsphere.py +++ b/tests/unit/modules/test_vsphere.py @@ -4,6 +4,7 @@ Tests for functions in salt.modules.vsphere """ + import pytest import salt.modules.vsphere as vsphere @@ -809,7 +810,7 @@ class VsphereTestCase(TestCase, LoaderModuleMockMixin): config = "foo" ret = { "success": False, - "message": "'{}' is not a valid config variable.".format(config), + "message": f"'{config}' is not a valid config variable.", } self.assertEqual( ret, vsphere._set_syslog_config_helper(HOST, USER, PASSWORD, config, "bar") @@ -3509,7 +3510,7 @@ class TestCertificateVerify(TestCase, LoaderModuleMockMixin): USER, PASSWORD, certificate_verify=certificate_verify_value, - **kwargs + **kwargs, ) http_query_mock.assert_called_once_with( "https://1.2.3.4:443/host/ssh_root_authorized_keys", @@ -3519,7 +3520,7 @@ class TestCertificateVerify(TestCase, LoaderModuleMockMixin): text=True, username="root", verify_ssl=certificate_verify_value, - **expected_kwargs + **expected_kwargs, ) def test_get_ssh_key(self): diff --git a/tests/unit/modules/test_win_system.py b/tests/unit/modules/test_win_system.py index 9a217c93d0e..ea73661dc39 100644 --- a/tests/unit/modules/test_win_system.py +++ b/tests/unit/modules/test_win_system.py @@ -633,6 +633,7 @@ class WinSystemTestCase(TestCase, LoaderModuleMockMixin): the WMI Class Win32_Processor. Older versions of Windows are missing this property """ + # Create a mock processor class that does not have the # NumberOfCoresEnabled property class MockWMIProcessor: diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py index c9c0685d4b9..55f8c85f71c 100644 --- a/tests/unit/modules/test_zypperpkg.py +++ b/tests/unit/modules/test_zypperpkg.py @@ -2,7 +2,6 @@ :codeauthor: Bo Maryniuk """ - import configparser import errno import io diff --git a/tests/unit/states/test_boto_vpc.py b/tests/unit/states/test_boto_vpc.py index 95febd66834..32305d1a589 100644 --- a/tests/unit/states/test_boto_vpc.py +++ b/tests/unit/states/test_boto_vpc.py @@ -267,7 +267,7 @@ class BotoVpcResourceTestCaseMixin(BotoVpcTestCaseMixin): vpc = self._create_vpc(name="test") with patch.dict(botomod.__salt__, self.funcs): resource_present_result = self.salt_states[ - "boto_vpc.{}_present".format(self.resource_type) + f"boto_vpc.{self.resource_type}_present" ](name="test", vpc_name="test", **self.extra_kwargs) self.assertTrue(resource_present_result["result"]) @@ -288,7 +288,7 @@ class BotoVpcResourceTestCaseMixin(BotoVpcTestCaseMixin): self._create_resource(vpc_id=vpc.id, name="test") with patch.dict(botomod.__salt__, self.funcs): resource_present_result = self.salt_states[ - "boto_vpc.{}_present".format(self.resource_type) + f"boto_vpc.{self.resource_type}_present" ](name="test", vpc_name="test", **self.extra_kwargs) self.assertTrue(resource_present_result["result"]) self.assertEqual(resource_present_result["changes"], {}) @@ -300,11 +300,11 @@ class BotoVpcResourceTestCaseMixin(BotoVpcTestCaseMixin): def test_present_with_failure(self): vpc = self._create_vpc(name="test") with patch( - "moto.ec2.models.{}".format(self.backend_create), + f"moto.ec2.models.{self.backend_create}", side_effect=BotoServerError(400, "Mocked error"), ): resource_present_result = self.salt_states[ - "boto_vpc.{}_present".format(self.resource_type) + f"boto_vpc.{self.resource_type}_present" ](name="test", vpc_name="test", **self.extra_kwargs) self.assertFalse(resource_present_result["result"]) @@ -322,7 +322,7 @@ class BotoVpcResourceTestCaseMixin(BotoVpcTestCaseMixin): """ with patch.dict(botomod.__salt__, self.funcs): resource_absent_result = self.salt_states[ - "boto_vpc.{}_absent".format(self.resource_type) + f"boto_vpc.{self.resource_type}_absent" ]("test") self.assertTrue(resource_absent_result["result"]) self.assertEqual(resource_absent_result["changes"], {}) @@ -339,7 +339,7 @@ class BotoVpcResourceTestCaseMixin(BotoVpcTestCaseMixin): with patch.dict(botomod.__salt__, self.funcs): resource_absent_result = self.salt_states[ - "boto_vpc.{}_absent".format(self.resource_type) + f"boto_vpc.{self.resource_type}_absent" ]("test") self.assertTrue(resource_absent_result["result"]) self.assertEqual( @@ -359,11 +359,11 @@ class BotoVpcResourceTestCaseMixin(BotoVpcTestCaseMixin): self._create_resource(vpc_id=vpc.id, name="test") with patch( - "moto.ec2.models.{}".format(self.backend_delete), + f"moto.ec2.models.{self.backend_delete}", side_effect=BotoServerError(400, "Mocked error"), ): resource_absent_result = self.salt_states[ - "boto_vpc.{}_absent".format(self.resource_type) + f"boto_vpc.{self.resource_type}_absent" ]("test") self.assertFalse(resource_absent_result["result"]) self.assertTrue("Mocked error" in resource_absent_result["comment"]) diff --git a/tests/unit/states/test_group.py b/tests/unit/states/test_group.py index b9bf3434e72..eaa1c61cf8f 100644 --- a/tests/unit/states/test_group.py +++ b/tests/unit/states/test_group.py @@ -2,7 +2,6 @@ :codeauthor: Rahul Handay """ - import salt.states.group as group from salt.utils.odict import OrderedDict from tests.support.mixins import LoaderModuleMockMixin diff --git a/tests/unit/states/test_ipset.py b/tests/unit/states/test_ipset.py index f253d52be1d..5c2993e6dfb 100644 --- a/tests/unit/states/test_ipset.py +++ b/tests/unit/states/test_ipset.py @@ -53,7 +53,7 @@ class IpsetSetPresentTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": True, - "comment": "ipset set {} already exists for ipv4".format(self.fake_name), + "comment": f"ipset set {self.fake_name} already exists for ipv4", "changes": {}, } self._runner(ret, check_set=True, new_set_assertion=False) @@ -66,7 +66,7 @@ class IpsetSetPresentTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": None, - "comment": "ipset set {} would be added for ipv4".format(self.fake_name), + "comment": f"ipset set {self.fake_name} would be added for ipv4", "changes": {}, } self._runner(ret, test=True, new_set_assertion=False) @@ -86,7 +86,7 @@ class IpsetSetPresentTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": False, - "comment": "Failed to create set {} for ipv4: ".format(self.fake_name), + "comment": f"Failed to create set {self.fake_name} for ipv4: ", "changes": {}, } self._runner(ret, new_set="") @@ -142,7 +142,7 @@ class IpsetSetAbsentTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": True, - "comment": "ipset set {} for ipv4 is already absent".format(self.fake_name), + "comment": f"ipset set {self.fake_name} for ipv4 is already absent", "changes": {}, } self._runner(ret, check_set=False, delete_set=None) @@ -151,7 +151,7 @@ class IpsetSetAbsentTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": None, - "comment": "ipset set {} for ipv4 would be removed".format(self.fake_name), + "comment": f"ipset set {self.fake_name} for ipv4 would be removed", "changes": {}, } self._runner(ret, test=True, delete_set=None) @@ -160,7 +160,7 @@ class IpsetSetAbsentTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": False, - "comment": "Failed to delete set {} for ipv4: ".format(self.fake_name), + "comment": f"Failed to delete set {self.fake_name} for ipv4: ", "changes": {}, } self._runner(ret, flush_assertion=True, delete_set_assertion=True) @@ -420,7 +420,7 @@ class IpsetFlushTestCase(TestCase, LoaderModuleMockMixin): ret = { "name": self.fake_name, "result": False, - "comment": "ipset set {} does not exist for ipv4".format(self.fake_name), + "comment": f"ipset set {self.fake_name} does not exist for ipv4", "changes": {}, } self._runner(ret, check_set=False, flush_assertion=False) diff --git a/tests/unit/states/test_module.py b/tests/unit/states/test_module.py index 4853c24ca07..4fd0dcad0bc 100644 --- a/tests/unit/states/test_module.py +++ b/tests/unit/states/test_module.py @@ -2,7 +2,6 @@ :codeauthor: Nicole Thomas (nicole@saltstack.com) """ - import logging from inspect import FullArgSpec diff --git a/tests/unit/states/test_syslog_ng.py b/tests/unit/states/test_syslog_ng.py index f367df58b17..132d95ad903 100644 --- a/tests/unit/states/test_syslog_ng.py +++ b/tests/unit/states/test_syslog_ng.py @@ -2,7 +2,6 @@ Test module for syslog_ng state """ - import os import re import tempfile diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 5cc58c273d0..c5196372b32 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -1,6 +1,7 @@ """ Unit tests for salt.config """ + import logging import os import textwrap @@ -52,7 +53,7 @@ MOCK_ETC_HOSTS = textwrap.dedent( hostname=MOCK_HOSTNAME ) ) -MOCK_ETC_HOSTNAME = "{}\n".format(MOCK_HOSTNAME) +MOCK_ETC_HOSTNAME = f"{MOCK_HOSTNAME}\n" PATH = "path/to/some/cloud/conf/file" DEFAULT = {"default_include": PATH} @@ -86,7 +87,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(master_config), + f"Sample config file '{master_config}' must be commented out.", ) def test_conf_minion_sample_is_commented(self): @@ -99,7 +100,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(minion_config), + f"Sample config file '{minion_config}' must be commented out.", ) def test_conf_cloud_sample_is_commented(self): @@ -112,7 +113,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(cloud_config), + f"Sample config file '{cloud_config}' must be commented out.", ) def test_conf_cloud_profiles_sample_is_commented(self): @@ -155,7 +156,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(proxy_config), + f"Sample config file '{proxy_config}' must be commented out.", ) def test_conf_roster_sample_is_commented(self): @@ -168,7 +169,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(roster_config), + f"Sample config file '{roster_config}' must be commented out.", ) def test_conf_cloud_profiles_d_files_are_commented(self): @@ -179,9 +180,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): """ cloud_sample_dir = SAMPLE_CONF_DIR + "cloud.profiles.d/" if not os.path.exists(cloud_sample_dir): - self.skipTest( - "Sample config directory '{}' is missing.".format(cloud_sample_dir) - ) + self.skipTest(f"Sample config directory '{cloud_sample_dir}' is missing.") cloud_sample_files = os.listdir(cloud_sample_dir) for conf_file in cloud_sample_files: profile_conf = cloud_sample_dir + conf_file @@ -189,7 +188,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(conf_file), + f"Sample config file '{conf_file}' must be commented out.", ) def test_conf_cloud_providers_d_files_are_commented(self): @@ -200,9 +199,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): """ cloud_sample_dir = SAMPLE_CONF_DIR + "cloud.providers.d/" if not os.path.exists(cloud_sample_dir): - self.skipTest( - "Sample config directory '{}' is missing.".format(cloud_sample_dir) - ) + self.skipTest(f"Sample config directory '{cloud_sample_dir}' is missing.") cloud_sample_files = os.listdir(cloud_sample_dir) for conf_file in cloud_sample_files: provider_conf = cloud_sample_dir + conf_file @@ -210,7 +207,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(conf_file), + f"Sample config file '{conf_file}' must be commented out.", ) def test_conf_cloud_maps_d_files_are_commented(self): @@ -221,9 +218,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): """ cloud_sample_dir = SAMPLE_CONF_DIR + "cloud.maps.d/" if not os.path.exists(cloud_sample_dir): - self.skipTest( - "Sample config directory '{}' is missing.".format(cloud_sample_dir) - ) + self.skipTest(f"Sample config directory '{cloud_sample_dir}' is missing.") cloud_sample_files = os.listdir(cloud_sample_dir) for conf_file in cloud_sample_files: map_conf = cloud_sample_dir + conf_file @@ -231,7 +226,7 @@ class SampleConfTest(DefaultConfigsBase, TestCase): self.assertEqual( ret, {}, - "Sample config file '{}' must be commented out.".format(conf_file), + f"Sample config file '{conf_file}' must be commented out.", ) @@ -239,14 +234,14 @@ def _unhandled_mock_read(filename): """ Raise an error because we should not be calling salt.utils.files.fopen() """ - raise CommandExecutionError("Unhandled mock read for {}".format(filename)) + raise CommandExecutionError(f"Unhandled mock read for {filename}") def _salt_configuration_error(filename): """ Raise an error to indicate error in the Salt configuration file """ - raise SaltConfigurationError("Configuration error in {}".format(filename)) + raise SaltConfigurationError(f"Configuration error in {filename}") class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): @@ -290,7 +285,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): os.makedirs(root_dir) fpath = os.path.join(root_dir, "config") with salt.utils.files.fopen(fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(root_dir, fpath)) + fp_.write(f"root_dir: {root_dir}\nlog_file: {fpath}\n") config = salt.config.master_config(fpath) self.assertEqual(config["log_file"], fpath) @@ -300,7 +295,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): os.makedirs(root_dir) fpath = os.path.join(root_dir, "config") with salt.utils.files.fopen(fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(root_dir, fpath)) + fp_.write(f"root_dir: {root_dir}\nlog_file: {fpath}\n") config = salt.config.master_config(fpath) self.assertEqual(config["log_file"], fpath) @@ -314,17 +309,17 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): env_fpath = os.path.join(env_root_dir, "config-env") with salt.utils.files.fopen(env_fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(env_root_dir, env_fpath)) + fp_.write(f"root_dir: {env_root_dir}\nlog_file: {env_fpath}\n") with patched_environ(SALT_MASTER_CONFIG=env_fpath): # Should load from env variable, not the default configuration file. - config = salt.config.master_config("{}/master".format(CONFIG_DIR)) + config = salt.config.master_config(f"{CONFIG_DIR}/master") self.assertEqual(config["log_file"], env_fpath) root_dir = os.path.join(tempdir, "foo", "bar") os.makedirs(root_dir) fpath = os.path.join(root_dir, "config") with salt.utils.files.fopen(fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(root_dir, fpath)) + fp_.write(f"root_dir: {root_dir}\nlog_file: {fpath}\n") # Let's set the environment variable, yet, since the configuration # file path is not the default one, i.e., the user has passed an # alternative configuration file form the CLI parser, the @@ -343,18 +338,18 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): env_fpath = os.path.join(env_root_dir, "config-env") with salt.utils.files.fopen(env_fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(env_root_dir, env_fpath)) + fp_.write(f"root_dir: {env_root_dir}\nlog_file: {env_fpath}\n") with patched_environ(SALT_MINION_CONFIG=env_fpath): # Should load from env variable, not the default configuration file - config = salt.config.minion_config("{}/minion".format(CONFIG_DIR)) + config = salt.config.minion_config(f"{CONFIG_DIR}/minion") self.assertEqual(config["log_file"], env_fpath) root_dir = os.path.join(tempdir, "foo", "bar") os.makedirs(root_dir) fpath = os.path.join(root_dir, "config") with salt.utils.files.fopen(fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(root_dir, fpath)) + fp_.write(f"root_dir: {root_dir}\nlog_file: {fpath}\n") # Let's set the environment variable, yet, since the configuration # file path is not the default one, i.e., the user has passed an # alternative configuration file form the CLI parser, the @@ -386,7 +381,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): # Now the client configuration file env_fpath = os.path.join(env_root_dir, "config-env") with salt.utils.files.fopen(env_fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(env_root_dir, env_fpath)) + fp_.write(f"root_dir: {env_root_dir}\nlog_file: {env_fpath}\n") with patched_environ( SALT_MASTER_CONFIG=master_config, SALT_CLIENT_CONFIG=env_fpath @@ -400,7 +395,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): os.makedirs(root_dir) fpath = os.path.join(root_dir, "config") with salt.utils.files.fopen(fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(root_dir, fpath)) + fp_.write(f"root_dir: {root_dir}\nlog_file: {fpath}\n") # Let's set the environment variable, yet, since the configuration # file path is not the default one, i.e., the user has passed an # alternative configuration file form the CLI parser, the @@ -1675,7 +1670,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): env_fpath = os.path.join(env_root_dir, "config-env") with salt.utils.files.fopen(env_fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(env_root_dir, env_fpath)) + fp_.write(f"root_dir: {env_root_dir}\nlog_file: {env_fpath}\n") with patched_environ(SALT_CLOUD_CONFIG=env_fpath): # Should load from env variable, not the default configuration file @@ -1686,7 +1681,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): os.makedirs(root_dir) fpath = os.path.join(root_dir, "config") with salt.utils.files.fopen(fpath, "w") as fp_: - fp_.write("root_dir: {}\nlog_file: {}\n".format(root_dir, fpath)) + fp_.write(f"root_dir: {root_dir}\nlog_file: {fpath}\n") # Let's set the environment variable, yet, since the configuration # file path is not the default one, i.e., the user has passed an # alternative configuration file form the CLI parser, the @@ -1725,9 +1720,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): """ config_file = self.get_config_file_path("cloud") log.debug("Cloud config file path: %s", config_file) - self.assertTrue( - os.path.exists(config_file), "{} does not exist".format(config_file) - ) + self.assertTrue(os.path.exists(config_file), f"{config_file} does not exist") config = salt.config.cloud_config(config_file) self.assertIn("providers", config) self.assertIn("ec2-config", config["providers"]) @@ -1900,7 +1893,7 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin): overrides = {} with salt.utils.files.fopen(fpath, "w") as wfh: - wfh.write("root_dir: /\nkey_logfile: key\ncachedir: {}".format(cachedir)) + wfh.write(f"root_dir: /\nkey_logfile: key\ncachedir: {cachedir}") config = salt.config.mminion_config(fpath, overrides) self.assertEqual(config["__role"], "master") self.assertEqual(config["cachedir"], cachedir) @@ -1944,7 +1937,7 @@ class APIConfigTestCase(DefaultConfigsBase, TestCase): RUNTIME_VARS.TMP_ROOT_DIR if RUNTIME_VARS.TMP_ROOT_DIR != "/" else "" ) if salt.utils.platform.is_windows(): - expected = "{}\\var\\log\\salt\\api".format(RUNTIME_VARS.TMP_ROOT_DIR) + expected = f"{RUNTIME_VARS.TMP_ROOT_DIR}\\var\\log\\salt\\api" ret = salt.config.api_config("/some/fake/path") self.assertEqual(ret["log_file"], expected) diff --git a/tests/unit/test_mock.py b/tests/unit/test_mock.py index a6c100dc41b..39ee7e65fc0 100644 --- a/tests/unit/test_mock.py +++ b/tests/unit/test_mock.py @@ -142,20 +142,20 @@ class MockOpenMixin: with salt.utils.files.fopen("foo.txt", mode) as self.fh: index = 0 for line in self.fh: - assert line == questions[index], "Line {}: {}".format(index, line) + assert line == questions[index], f"Line {index}: {line}" index += 1 if multifile: with salt.utils.files.fopen("bar.txt", mode) as self.fh2: index = 0 for line in self.fh2: - assert line == answers[index], "Line {}: {}".format(index, line) + assert line == answers[index], f"Line {index}: {line}" index += 1 with salt.utils.files.fopen("baz.txt", mode) as self.fh3: index = 0 for line in self.fh3: - assert line == answers[index], "Line {}: {}".format(index, line) + assert line == answers[index], f"Line {index}: {line}" index += 1 try: diff --git a/tests/unit/test_zypp_plugins.py b/tests/unit/test_zypp_plugins.py index 7bd248ffbd9..d7bc58e5a2e 100644 --- a/tests/unit/test_zypp_plugins.py +++ b/tests/unit/test_zypp_plugins.py @@ -1,6 +1,7 @@ """ :codeauthor: Bo Maryniuk """ + import imp import os @@ -32,7 +33,7 @@ class ZyppPluginsTestCase(TestCase): @pytest.mark.skipif( not os.path.exists(ZYPPNOTIFY_FILE), - reason="Required file '{}' does not exist.".format(ZYPPNOTIFY_FILE), + reason=f"Required file '{ZYPPNOTIFY_FILE}' does not exist.", ) def test_drift_detector(self): """ diff --git a/tests/unit/transport/test_ipc.py b/tests/unit/transport/test_ipc.py index 639a9f606f6..eb469d6efb4 100644 --- a/tests/unit/transport/test_ipc.py +++ b/tests/unit/transport/test_ipc.py @@ -1,6 +1,7 @@ """ :codeauthor: Mike Place """ + import errno import logging import os diff --git a/tests/unit/transport/test_tcp.py b/tests/unit/transport/test_tcp.py index 2719ab02a0c..0d53af250a6 100644 --- a/tests/unit/transport/test_tcp.py +++ b/tests/unit/transport/test_tcp.py @@ -54,7 +54,7 @@ class AsyncPubServerTest(AsyncTestCase, AdaptedConfigurationTestCaseMixin): "tcp_master_pull_port": tcp_master_pull_port, "tcp_master_publish_pull": tcp_master_publish_pull, "tcp_master_workers": tcp_master_workers, - } + }, ) cls.minion_config = cls.get_temp_config( @@ -64,8 +64,8 @@ class AsyncPubServerTest(AsyncTestCase, AdaptedConfigurationTestCaseMixin): "master_ip": "127.0.0.1", "auth_timeout": 1, "master_port": ret_port, - "master_uri": "tcp://127.0.0.1:{}".format(ret_port), - } + "master_uri": f"tcp://127.0.0.1:{ret_port}", + }, ) cls.process_manager = salt.utils.process.ProcessManager( @@ -121,7 +121,7 @@ class AsyncPubServerTest(AsyncTestCase, AdaptedConfigurationTestCaseMixin): if self._start_handlers.get(k) != v: failures.append((k, v)) if failures: - raise Exception("FDs still attached to the IOLoop: {}".format(failures)) + raise Exception(f"FDs still attached to the IOLoop: {failures}") del self.channel del self._start_handlers diff --git a/tests/unit/utils/test_color.py b/tests/unit/utils/test_color.py index b80b2e4eaf1..741db780a23 100644 --- a/tests/unit/utils/test_color.py +++ b/tests/unit/utils/test_color.py @@ -2,7 +2,6 @@ Unit tests for salt.utils.color.py """ - import salt.utils.color from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_context.py b/tests/unit/utils/test_context.py index c8b0e5f44f1..eebbb17fcaa 100644 --- a/tests/unit/utils/test_context.py +++ b/tests/unit/utils/test_context.py @@ -3,7 +3,6 @@ tests.unit.context_test ~~~~~~~~~~~~~~~~~~~~~~~ """ - import salt.utils.json from salt.utils.context import NamespacedDictWrapper from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_decorators.py b/tests/unit/utils/test_decorators.py index 21992ccacc4..e3be199a028 100644 --- a/tests/unit/utils/test_decorators.py +++ b/tests/unit/utils/test_decorators.py @@ -3,7 +3,6 @@ unit.utils.decorators_test """ - import inspect import salt.utils.decorators as decorators diff --git a/tests/unit/utils/test_dns.py b/tests/unit/utils/test_dns.py index 75ceeef1359..c8e72ade46f 100644 --- a/tests/unit/utils/test_dns.py +++ b/tests/unit/utils/test_dns.py @@ -307,7 +307,7 @@ class DNSlookupsCase(TestCase): self.assertEqual( lookup_cb("mocksrvr.example.com", rec_t, secure=True), False, - msg="Insecure {} returns should not be returned".format(rec_t), + msg=f"Insecure {rec_t} returns should not be returned", ) for rec_t, tests in secure.items(): @@ -316,7 +316,7 @@ class DNSlookupsCase(TestCase): self.assertEqual( lookup_cb("mocksrvr.example.com", rec_t, secure=True), test_res, - msg="Error parsing DNSSEC'd {} returns".format(rec_t), + msg=f"Error parsing DNSSEC'd {rec_t} returns", ) @pytest.mark.skipif( @@ -366,7 +366,7 @@ class DNSlookupsCase(TestCase): @pytest.mark.skipif(not salt.utils.dns.HAS_DIG, reason="dig is not available") def test_dig_options(self): - cmd = "dig {} -v".format(salt.utils.dns.DIG_OPTIONS) + cmd = f"dig {salt.utils.dns.DIG_OPTIONS} -v" cmd = salt.modules.cmdmod.retcode( cmd, python_shell=False, output_loglevel="quiet" ) @@ -585,7 +585,7 @@ class DNSlookupsCase(TestCase): self.assertEqual( _lookup_gai("mockq", rec_t), test_res, - msg="Error parsing {} returns".format(rec_t), + msg=f"Error parsing {rec_t} returns", ) def test_host(self): diff --git a/tests/unit/utils/test_doc.py b/tests/unit/utils/test_doc.py index 62be2d15880..31088ac0831 100644 --- a/tests/unit/utils/test_doc.py +++ b/tests/unit/utils/test_doc.py @@ -2,7 +2,6 @@ Unit Tests for functions located in salt.utils.doc.py. """ - import salt.utils.doc from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_dockermod.py b/tests/unit/utils/test_dockermod.py index f93f2a80b8b..14f6dbb9a26 100644 --- a/tests/unit/utils/test_dockermod.py +++ b/tests/unit/utils/test_dockermod.py @@ -114,19 +114,19 @@ class Assert: salt.utils.dockermod.translate_input( self.translator, validate_ip_addrs=False, - **{item: [{"foo": "bar"}, {"baz": "qux"}]} + **{item: [{"foo": "bar"}, {"baz": "qux"}]}, ), testcase.apply_defaults({name: expected}), ) if alias is not None: # Test collision - test_kwargs = {name: vals, alias: "hello{}world".format(delimiter)} + test_kwargs = {name: vals, alias: f"hello{delimiter}world"} testcase.assertEqual( salt.utils.dockermod.translate_input( self.translator, validate_ip_addrs=False, ignore_collisions=True, - **test_kwargs + **test_kwargs, ), testcase.apply_defaults({name: expected}), ) @@ -137,7 +137,7 @@ class Assert: self.translator, validate_ip_addrs=False, ignore_collisions=False, - **test_kwargs + **test_kwargs, ) @@ -505,7 +505,7 @@ class assert_device_rates(Assert): "Path '{}' is not absolute".format(path.replace("\\", "\\\\")), ): salt.utils.dockermod.translate_input( - self.translator, **{item: "{}:1048576".format(path)} + self.translator, **{item: f"{path}:1048576"} ) if name.endswith("_bps"): @@ -661,7 +661,7 @@ class assert_subnet(Assert): ): log.debug("Verifying '%s' is not a valid subnet", val) with testcase.assertRaisesRegex( - CommandExecutionError, "'{}' is not a valid subnet".format(val) + CommandExecutionError, f"'{val}' is not a valid subnet" ): salt.utils.dockermod.translate_input( self.translator, validate_ip_addrs=True, **{item: val} @@ -1945,7 +1945,7 @@ class TranslateNetworkInputTestCase(TranslateBase): for val in self.ip_addrs[False]: with self.assertRaisesRegex( - CommandExecutionError, "'{}' is not a valid IP address".format(val) + CommandExecutionError, f"'{val}' is not a valid IP address" ): salt.utils.dockermod.translate_input( self.translator, @@ -1983,7 +1983,7 @@ class TranslateNetworkInputTestCase(TranslateBase): for val in self.ip_addrs[False]: addresses = {"foo.bar.tld": val} with self.assertRaisesRegex( - CommandExecutionError, "'{}' is not a valid IP address".format(val) + CommandExecutionError, f"'{val}' is not a valid IP address" ): salt.utils.dockermod.translate_input( self.translator, validate_ip_addrs=True, **{item: addresses} diff --git a/tests/unit/utils/test_environment.py b/tests/unit/utils/test_environment.py index d36de65a33d..54972226994 100644 --- a/tests/unit/utils/test_environment.py +++ b/tests/unit/utils/test_environment.py @@ -1,6 +1,7 @@ """ Test case for utils/__init__.py """ + import salt.utils.environment from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_extend.py b/tests/unit/utils/test_extend.py index d96f588decc..94a9a92ca51 100644 --- a/tests/unit/utils/test_extend.py +++ b/tests/unit/utils/test_extend.py @@ -4,6 +4,7 @@ Test the salt extend script, leave templates/test alone to keep this working! """ + import os import shutil from datetime import date diff --git a/tests/unit/utils/test_filebuffer.py b/tests/unit/utils/test_filebuffer.py index b88a2f4fc56..5f0fc0f3fdb 100644 --- a/tests/unit/utils/test_filebuffer.py +++ b/tests/unit/utils/test_filebuffer.py @@ -6,7 +6,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ - import os from salt.utils.filebuffer import BufferedReader, InvalidFileMode diff --git a/tests/unit/utils/test_immutabletypes.py b/tests/unit/utils/test_immutabletypes.py index 745f9b933ed..28afcaac698 100644 --- a/tests/unit/utils/test_immutabletypes.py +++ b/tests/unit/utils/test_immutabletypes.py @@ -8,7 +8,6 @@ Test salt.utils.immutabletypes """ - import salt.utils.immutabletypes as immutabletypes from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_jid.py b/tests/unit/utils/test_jid.py index f6749228304..347e1411328 100644 --- a/tests/unit/utils/test_jid.py +++ b/tests/unit/utils/test_jid.py @@ -2,7 +2,6 @@ Tests for salt.utils.jid """ - import datetime import os @@ -35,9 +34,9 @@ class JidTestCase(TestCase): self.assertEqual(ret, "20021225120000000000") with patch("salt.utils.jid.LAST_JID_DATETIME", None): ret = salt.utils.jid.gen_jid({"unique_jid": True}) - self.assertEqual(ret, "20021225120000000000_{}".format(os.getpid())) + self.assertEqual(ret, f"20021225120000000000_{os.getpid()}") ret = salt.utils.jid.gen_jid({"unique_jid": True}) - self.assertEqual(ret, "20021225120000000001_{}".format(os.getpid())) + self.assertEqual(ret, f"20021225120000000001_{os.getpid()}") def test_deprecation_58225(self): # check that type error will be raised diff --git a/tests/unit/utils/test_job.py b/tests/unit/utils/test_job.py index 3d25719ade3..2e824e02351 100644 --- a/tests/unit/utils/test_job.py +++ b/tests/unit/utils/test_job.py @@ -2,7 +2,6 @@ unit tests for salt.utils.job """ - import salt.minion import salt.utils.job as job from tests.support.mock import patch diff --git a/tests/unit/utils/test_json.py b/tests/unit/utils/test_json.py index b123e7e8844..9b3a6c66362 100644 --- a/tests/unit/utils/test_json.py +++ b/tests/unit/utils/test_json.py @@ -105,7 +105,7 @@ class JSONTestCase(TestCase): self.assertDictEqual(ret, expected_ret) # Now pre-pend some garbage and re-test - garbage_prepend_json = "{}{}".format(LOREM_IPSUM, test_sample_json) + garbage_prepend_json = f"{LOREM_IPSUM}{test_sample_json}" ret = salt.utils.json.find_json(garbage_prepend_json) self.assertDictEqual(ret, expected_ret) diff --git a/tests/unit/utils/test_mac_utils.py b/tests/unit/utils/test_mac_utils.py index 9de2b56a844..609c939cd8d 100644 --- a/tests/unit/utils/test_mac_utils.py +++ b/tests/unit/utils/test_mac_utils.py @@ -1,6 +1,7 @@ """ mac_utils tests """ + import os import plistlib import subprocess diff --git a/tests/unit/utils/test_msgpack.py b/tests/unit/utils/test_msgpack.py index 9bcd9609e53..2d81c922f1b 100644 --- a/tests/unit/utils/test_msgpack.py +++ b/tests/unit/utils/test_msgpack.py @@ -1,6 +1,7 @@ """ Test the MessagePack utility """ + import inspect import os import pprint diff --git a/tests/unit/utils/test_pbm.py b/tests/unit/utils/test_pbm.py index b254ba8ada3..567e27e0c08 100644 --- a/tests/unit/utils/test_pbm.py +++ b/tests/unit/utils/test_pbm.py @@ -348,7 +348,7 @@ class GetStoragePoliciesTestCase(TestCase): resourceType=pbm.profile.ResourceTypeEnum.STORAGE ) ) - mock_obj.name = "fake_policy{}".format(i) + mock_obj.name = f"fake_policy{i}" self.mock_policies.append(mock_obj) patches = ( ( diff --git a/tests/unit/utils/test_proxy.py b/tests/unit/utils/test_proxy.py index 1c9a34ede31..a2ea8a6b660 100644 --- a/tests/unit/utils/test_proxy.py +++ b/tests/unit/utils/test_proxy.py @@ -3,7 +3,6 @@ :codeauthor: :email:`Gareth J. Greenaway ` """ - import salt.utils.proxy from tests.support.mock import patch from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_roster_matcher.py b/tests/unit/utils/test_roster_matcher.py index d49bc29f1de..b3ce554c837 100644 --- a/tests/unit/utils/test_roster_matcher.py +++ b/tests/unit/utils/test_roster_matcher.py @@ -1,6 +1,7 @@ """ Test generic roster matching utility. """ + import os import pytest diff --git a/tests/unit/utils/test_schema.py b/tests/unit/utils/test_schema.py index 113c6836e07..ebe3698978f 100644 --- a/tests/unit/utils/test_schema.py +++ b/tests/unit/utils/test_schema.py @@ -509,7 +509,7 @@ class ConfigTestCase(TestCase): Requirements.serialize(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -517,7 +517,7 @@ class ConfigTestCase(TestCase): Requirements.serialize(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -525,7 +525,7 @@ class ConfigTestCase(TestCase): Requirements.serialize(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -583,7 +583,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": False}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 1}, TestConf.serialize()) @@ -692,7 +692,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": "the item"}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") class TestConf(schema.Schema): item = schema.StringItem( @@ -702,7 +702,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": "the item"}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 3}, TestConf.serialize()) @@ -729,7 +729,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": "foo"}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") class TestConf(schema.Schema): item = schema.StringItem( @@ -752,7 +752,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -788,7 +788,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -825,7 +825,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -861,7 +861,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -897,7 +897,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -936,7 +936,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -985,7 +985,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1100,7 +1100,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 2}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": "3"}, TestConf.serialize()) @@ -1114,7 +1114,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 4.4}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 4}, TestConf.serialize()) @@ -1128,7 +1128,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 3}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 11}, TestConf.serialize()) @@ -1173,7 +1173,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 4}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") class TestConf(schema.Schema): item = schema.NumberItem( @@ -1289,7 +1289,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 2}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 3.1}, TestConf.serialize()) @@ -1303,7 +1303,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 4}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 3}, TestConf.serialize()) @@ -1317,7 +1317,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 3}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": 11}, TestConf.serialize()) @@ -1362,7 +1362,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": 4}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") class TestConf(schema.Schema): item = schema.IntegerItem( @@ -1497,7 +1497,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1523,7 +1523,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1567,7 +1567,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1591,7 +1591,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1611,7 +1611,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( {"item": ["Tobias"]}, @@ -1619,7 +1619,7 @@ class ConfigTestCase(TestCase): format_checker=jsonschema.FormatChecker(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1797,7 +1797,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": {"sides": 1}}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": {"sides": "1"}}, TestConf.serialize()) @@ -1820,7 +1820,7 @@ class ConfigTestCase(TestCase): {"item": {"sides": 1, "color": "red"}}, TestConf.serialize() ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1872,7 +1872,7 @@ class ConfigTestCase(TestCase): TestConf.serialize(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate( @@ -1904,7 +1904,7 @@ class ConfigTestCase(TestCase): {"item": {"color": "red", "sides": 1}}, TestConf.serialize() ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate( @@ -1912,7 +1912,7 @@ class ConfigTestCase(TestCase): TestConf.serialize(), ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": {"color": "blue"}}, TestConf.serialize()) @@ -1999,7 +1999,7 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": ["no"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": ["maybe"]}, TestConf.serialize()) @@ -2048,22 +2048,22 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": ["no"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate({"item": ["yes"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate({"item": [True]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate({"item": [False]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": ["maybe"]}, TestConf.serialize()) @@ -2108,12 +2108,12 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": ["no"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate({"item": ["yes"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": ["maybe"]}, TestConf.serialize()) @@ -2145,12 +2145,12 @@ class ConfigTestCase(TestCase): try: jsonschema.validate({"item": ["no"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") try: jsonschema.validate({"item": ["yes"]}, TestConf.serialize()) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({"item": [True]}, TestConf.serialize()) @@ -2494,7 +2494,7 @@ class ComplexSchemaTestCase(TestCase): try: jsonschema.validate({"complex_item": {"thirsty": True}}, serialized) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") @pytest.mark.skipif( HAS_JSONSCHEMA is False, reason="The 'jsonschema' library is missing" @@ -2515,7 +2515,7 @@ class ComplexSchemaTestCase(TestCase): try: jsonschema.validate({"complex_complex_item": {"hungry": True}}, serialized) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") @pytest.mark.skipif( HAS_JSONSCHEMA is False, reason="The 'jsonschema' library is missing" @@ -2533,7 +2533,7 @@ class ComplexSchemaTestCase(TestCase): serialized, ) except jsonschema.exceptions.ValidationError as exc: - self.fail("ValidationError raised: {}".format(exc)) + self.fail(f"ValidationError raised: {exc}") @pytest.mark.skipif( HAS_JSONSCHEMA is False, reason="The 'jsonschema' library is missing" diff --git a/tests/unit/utils/test_sdb.py b/tests/unit/utils/test_sdb.py index 87886cbc521..614a7173481 100644 --- a/tests/unit/utils/test_sdb.py +++ b/tests/unit/utils/test_sdb.py @@ -2,7 +2,6 @@ :codeauthor: :email:`Vernon Cole ` """ - import os import salt.utils.sdb as sdb diff --git a/tests/unit/utils/test_ssdp.py b/tests/unit/utils/test_ssdp.py index 252efeb735f..4af97ea071c 100644 --- a/tests/unit/utils/test_ssdp.py +++ b/tests/unit/utils/test_ssdp.py @@ -80,7 +80,7 @@ class SSDPBaseTestCase(TestCase, Mocks): Side effect :return: """ - raise AttributeError("attribute error: {}. {}".format(args, kwargs)) + raise AttributeError(f"attribute error: {args}. {kwargs}") @patch("salt.utils.ssdp._json", None) @patch("salt.utils.ssdp.asyncio", None) @@ -235,7 +235,7 @@ class SSDPFactoryTestCase(TestCase, Mocks): :return: """ factory = self.get_ssdp_factory() - data = "{}nonsense".format(ssdp.SSDPBase.DEFAULTS[ssdp.SSDPBase.SIGNATURE]) + data = f"{ssdp.SSDPBase.DEFAULTS[ssdp.SSDPBase.SIGNATURE]}nonsense" addr = "10.10.10.10", "foo.suse.de" with patch.object(factory, "log", MagicMock()), patch.object( factory, "_sendto", MagicMock() @@ -257,7 +257,7 @@ class SSDPFactoryTestCase(TestCase, Mocks): factory = self.get_ssdp_factory() factory.disable_hidden = True signature = ssdp.SSDPBase.DEFAULTS[ssdp.SSDPBase.SIGNATURE] - data = "{}nonsense".format(signature) + data = f"{signature}nonsense" addr = "10.10.10.10", "foo.suse.de" with patch.object(factory, "log", MagicMock()), patch.object( factory, "_sendto", MagicMock() @@ -269,10 +269,7 @@ class SSDPFactoryTestCase(TestCase, Mocks): in factory.log.debug.call_args[0][0] ) assert factory._sendto.called - assert ( - "{}:E:Invalid timestamp".format(signature) - == factory._sendto.call_args[0][0] - ) + assert f"{signature}:E:Invalid timestamp" == factory._sendto.call_args[0][0] def test_datagram_signature_outdated_timestamp_quiet(self): """ @@ -331,9 +328,9 @@ class SSDPFactoryTestCase(TestCase, Mocks): assert factory.log.debug.called assert factory.disable_hidden assert factory._sendto.called - assert factory._sendto.call_args[0][ - 0 - ] == "{}:E:Timestamp is too old".format(signature) + assert ( + factory._sendto.call_args[0][0] == f"{signature}:E:Timestamp is too old" + ) assert "Received outdated package" in factory.log.debug.call_args[0][0] def test_datagram_signature_correct_timestamp_reply(self): @@ -365,7 +362,7 @@ class SSDPFactoryTestCase(TestCase, Mocks): assert factory.disable_hidden assert factory._sendto.called assert factory._sendto.call_args[0][0] == salt.utils.stringutils.to_bytes( - "{}:@:{{}}".format(signature) + f"{signature}:@:{{}}" ) assert 'Received "%s" from %s:%s' in factory.log.debug.call_args[0][0] @@ -512,7 +509,7 @@ class SSDPClientTestCase(TestCase, Mocks): assert clnt._socket.sendto.called message, target = clnt._socket.sendto.call_args[0] assert message == salt.utils.stringutils.to_bytes( - "{}{}".format(config[ssdp.SSDPBase.SIGNATURE], f_time) + f"{config[ssdp.SSDPBase.SIGNATURE]}{f_time}" ) assert target[0] == "" assert target[1] == config[ssdp.SSDPBase.PORT] @@ -580,7 +577,7 @@ class SSDPClientTestCase(TestCase, Mocks): signature = ssdp.SSDPBase.DEFAULTS[ssdp.SSDPBase.SIGNATURE] fake_resource = SSDPClientTestCase.Resource() fake_resource.pool = [ - ("{}:E:{}".format(signature, error), "10.10.10.10"), + (f"{signature}:E:{error}", "10.10.10.10"), (None, None), ] @@ -613,7 +610,7 @@ class SSDPClientTestCase(TestCase, Mocks): signature = ssdp.SSDPBase.DEFAULTS[ssdp.SSDPBase.SIGNATURE] fake_resource = SSDPClientTestCase.Resource() fake_resource.pool = [ - ("{}:E:{}".format(signature, error), "10.10.10.10"), + (f"{signature}:E:{error}", "10.10.10.10"), (None, None), ] diff --git a/tests/unit/utils/test_state.py b/tests/unit/utils/test_state.py index 1b533e494f2..ba2c31d07f5 100644 --- a/tests/unit/utils/test_state.py +++ b/tests/unit/utils/test_state.py @@ -2,7 +2,6 @@ Unit Tests for functions located in salt.utils.state.py. """ - import copy import textwrap @@ -122,9 +121,7 @@ class StateUtilTestCase(TestCase): ), } for test, data in test_valid_false_states.items(): - self.assertFalse( - salt.utils.state.check_result(data), msg="{} failed".format(test) - ) + self.assertFalse(salt.utils.state.check_result(data), msg=f"{test} failed") test_valid_true_states = { "test1": salt.utils.odict.OrderedDict( [ @@ -214,9 +211,7 @@ class StateUtilTestCase(TestCase): ), } for test, data in test_valid_true_states.items(): - self.assertTrue( - salt.utils.state.check_result(data), msg="{} failed".format(test) - ) + self.assertTrue(salt.utils.state.check_result(data), msg=f"{test} failed") test_invalid_true_ht_states = { "test_onfail_simple2": ( salt.utils.odict.OrderedDict( @@ -519,7 +514,7 @@ class StateUtilTestCase(TestCase): tdata["__id__"] = t_ self.assertFalse( salt.utils.state.check_result(data, highstate=ht), - msg="{} failed".format(test), + msg=f"{test} failed", ) test_valid_true_ht_states = { @@ -746,7 +741,7 @@ class StateUtilTestCase(TestCase): tdata["__id__"] = t_ self.assertTrue( salt.utils.state.check_result(data, highstate=ht), - msg="{} failed".format(test), + msg=f"{test} failed", ) test_valid_false_state = {"host1": {"test_state": {"result": False}}} self.assertFalse(salt.utils.state.check_result(test_valid_false_state)) diff --git a/tests/unit/utils/test_systemd.py b/tests/unit/utils/test_systemd.py index 698a2337e5e..8f7e1de3b7a 100644 --- a/tests/unit/utils/test_systemd.py +++ b/tests/unit/utils/test_systemd.py @@ -78,7 +78,7 @@ class SystemdTestCase(TestCase): """ with patch("subprocess.Popen") as popen_mock: _version = 231 - output = "systemd {}\n-SYSVINIT".format(_version) + output = f"systemd {_version}\n-SYSVINIT" popen_mock.return_value = Mock( communicate=lambda *args, **kwargs: (output, None), pid=lambda: 12345, @@ -162,7 +162,7 @@ class SystemdTestCase(TestCase): with patch("subprocess.Popen") as popen_mock: _expected = False _version = 204 - _output = "systemd {}\n-SYSVINIT".format(_version) + _output = f"systemd {_version}\n-SYSVINIT" popen_mock.return_value = Mock( communicate=lambda *args, **kwargs: (_output, None), pid=lambda: 12345, @@ -196,7 +196,7 @@ class SystemdTestCase(TestCase): with patch("subprocess.Popen") as popen_mock: _expected = True _version = 205 - _output = "systemd {}\n-SYSVINIT".format(_version) + _output = f"systemd {_version}\n-SYSVINIT" popen_mock.return_value = Mock( communicate=lambda *args, **kwargs: (_output, None), pid=lambda: 12345, @@ -230,7 +230,7 @@ class SystemdTestCase(TestCase): with patch("subprocess.Popen") as popen_mock: _expected = True _version = 206 - _output = "systemd {}\n-SYSVINIT".format(_version) + _output = f"systemd {_version}\n-SYSVINIT" popen_mock.return_value = Mock( communicate=lambda *args, **kwargs: (_output, None), pid=lambda: 12345, diff --git a/tests/unit/utils/test_thin.py b/tests/unit/utils/test_thin.py index 7fd1e7b5dc3..d67dca16890 100644 --- a/tests/unit/utils/test_thin.py +++ b/tests/unit/utils/test_thin.py @@ -919,9 +919,9 @@ class SSHThinTestCase(TestCase): files = [] for py in ("py3", "pyall"): for i in range(1, 4): - files.append(os.path.join(py, "root", "r{}".format(i))) + files.append(os.path.join(py, "root", f"r{i}")) for i in range(4, 7): - files.append(os.path.join(py, "root2", "r{}".format(i))) + files.append(os.path.join(py, "root2", f"r{i}")) for cl in thin.tarfile.open().method_calls[:-6]: arcname = cl[2].get("arcname") self.assertIn(arcname, files) @@ -997,9 +997,9 @@ class SSHThinTestCase(TestCase): files = [] for py in ("pyall", "pyall", "py3"): for i in range(1, 4): - files.append(os.path.join("namespace", py, "root", "r{}".format(i))) + files.append(os.path.join("namespace", py, "root", f"r{i}")) for i in range(4, 7): - files.append(os.path.join("namespace", py, "root2", "r{}".format(i))) + files.append(os.path.join("namespace", py, "root2", f"r{i}")) for idx, cl in enumerate(thin.tarfile.open().method_calls[:-6]): arcname = cl[2].get("arcname") @@ -1247,7 +1247,7 @@ class SSHThinTestCase(TestCase): thin._pack_alternative(ext_conf, self.digest, self.tar) calls = self.tar.mock_calls for _file in exp_files: - assert [x for x in calls if "{}".format(_file) in x[-2]] + assert [x for x in calls if f"{_file}" in x[-2]] def test_pack_alternatives(self): """ @@ -1257,7 +1257,7 @@ class SSHThinTestCase(TestCase): thin._pack_alternative(self.ext_conf, self.digest, self.tar) calls = self.tar.mock_calls for _file in self.exp_files: - assert [x for x in calls if "{}".format(_file) in x[-2]] + assert [x for x in calls if f"{_file}" in x[-2]] assert [ x for x in calls @@ -1275,7 +1275,7 @@ class SSHThinTestCase(TestCase): thin._pack_alternative(self.ext_conf, self.digest, self.tar) calls = self.tar.mock_calls for _file in self.exp_files: - assert [x for x in calls if "{}".format(_file) in x[-2]] + assert [x for x in calls if f"{_file}" in x[-2]] assert [ x for x in calls @@ -1302,7 +1302,7 @@ class SSHThinTestCase(TestCase): assert msg in log_handler.messages calls = self.tar.mock_calls for _file in self.exp_files: - arg = [x for x in calls if "{}".format(_file) in x[-2]] + arg = [x for x in calls if f"{_file}" in x[-2]] kwargs = [ x for x in calls @@ -1344,7 +1344,7 @@ class SSHThinTestCase(TestCase): thin._pack_alternative(ext_conf, self.digest, self.tar) calls = self.tar.mock_calls for _file in exp_files: - assert [x for x in calls if "{}".format(_file) in x[-2]] + assert [x for x in calls if f"{_file}" in x[-2]] def test_pack_alternatives_empty_dependencies(self): """ @@ -1376,7 +1376,7 @@ class SSHThinTestCase(TestCase): thin._pack_alternative(ext_conf, self.digest, self.tar) calls = self.tar.mock_calls for _file in exp_files: - assert [x for x in calls if "{}".format(_file) in x[-2]] + assert [x for x in calls if f"{_file}" in x[-2]] @pytest.mark.slow_test @pytest.mark.skip_on_windows(reason="salt-ssh does not deploy to/from windows") @@ -1390,11 +1390,11 @@ class SSHThinTestCase(TestCase): # This was previously an integration test and is now here, as a unit test. # Should actually be a functional test with VirtualEnv() as venv: - salt.utils.thin.gen_thin(str(venv.venv_dir)) + thin.gen_thin(str(venv.venv_dir)) thin_dir = venv.venv_dir / "thin" thin_archive = thin_dir / "thin.tgz" tar = tarfile.open(str(thin_archive)) - tar.extractall(str(thin_dir)) + tar.extractall(str(thin_dir)) # nosec tar.close() ret = venv.run( venv.venv_python, diff --git a/tests/unit/utils/test_vmware.py b/tests/unit/utils/test_vmware.py index ca8cbdc46c4..e61539a29bf 100644 --- a/tests/unit/utils/test_vmware.py +++ b/tests/unit/utils/test_vmware.py @@ -3701,9 +3701,9 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def setUp(self): self.mock_si = MagicMock() self.mock_lic_assign_mgr = MagicMock() - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(return_value=self.mock_lic_assign_mgr) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(return_value=self.mock_lic_assign_mgr) + ) def tearDown(self): for attr in ("mock_si", "mock_lic_assign_mgr"): @@ -3712,9 +3712,9 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def test_raise_no_permission(self): exc = vim.fault.NoPermission() exc.privilegeId = "Fake privilege" - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(side_effect=exc) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(side_effect=exc) + ) with self.assertRaises(VMwareApiError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual( @@ -3725,9 +3725,9 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def test_raise_vim_fault(self): exc = vim.fault.VimFault() exc.msg = "VimFault msg" - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(side_effect=exc) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(side_effect=exc) + ) with self.assertRaises(VMwareApiError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual(excinfo.exception.strerror, "VimFault msg") @@ -3735,17 +3735,17 @@ class GetLicenseAssignmentManagerTestCase(TestCase): def test_raise_runtime_fault(self): exc = vmodl.RuntimeFault() exc.msg = "RuntimeFault msg" - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(side_effect=exc) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(side_effect=exc) + ) with self.assertRaises(VMwareRuntimeError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual(excinfo.exception.strerror, "RuntimeFault msg") def test_empty_license_assignment_manager(self): - type( - self.mock_si.content.licenseManager - ).licenseAssignmentManager = PropertyMock(return_value=None) + type(self.mock_si.content.licenseManager).licenseAssignmentManager = ( + PropertyMock(return_value=None) + ) with self.assertRaises(VMwareObjectRetrievalError) as excinfo: salt.utils.vmware.get_license_assignment_manager(self.mock_si) self.assertEqual( diff --git a/tests/unit/utils/test_vsan.py b/tests/unit/utils/test_vsan.py index 8231776d694..fe2cd6cf5c9 100644 --- a/tests/unit/utils/test_vsan.py +++ b/tests/unit/utils/test_vsan.py @@ -3,6 +3,7 @@ Tests functions in salt.utils.vsan """ + import logging import pytest diff --git a/tests/unit/utils/test_vt.py b/tests/unit/utils/test_vt.py index 876cf0e01fa..8984ace39cf 100644 --- a/tests/unit/utils/test_vt.py +++ b/tests/unit/utils/test_vt.py @@ -76,7 +76,7 @@ class VTTestCase(TestCase): buffer_o += stdout if stderr: buffer_e += stderr - assert buffer_o.strip() == "24 {}".format(cols) + assert buffer_o.strip() == f"24 {cols}" try: # Then wait for the terminal child to exit, this will raise an # exception if the process has already exited. @@ -120,7 +120,7 @@ class VTTestCase(TestCase): for idx in range(0, nr_ptys + n_executions): try: with salt.utils.vt.Terminal( - 'echo "Run {}"'.format(idx), + f'echo "Run {idx}"', shell=True, stream_stdout=False, stream_stderr=False, @@ -142,7 +142,7 @@ class VTTestCase(TestCase): for idx in range(0, nr_ptys + n_executions): try: terminal = salt.utils.vt.Terminal( - 'echo "Run {}"'.format(idx), + f'echo "Run {idx}"', shell=True, stream_stdout=False, stream_stderr=False, diff --git a/tests/unit/utils/test_win_chcp.py b/tests/unit/utils/test_win_chcp.py index 7fa0f0c35a8..b93e38f6b92 100644 --- a/tests/unit/utils/test_win_chcp.py +++ b/tests/unit/utils/test_win_chcp.py @@ -1,6 +1,7 @@ """ Test win_chcp """ + import pytest from salt.exceptions import CodePageError diff --git a/tests/unit/utils/test_win_service.py b/tests/unit/utils/test_win_service.py index a1acede897e..f6de830c2b9 100644 --- a/tests/unit/utils/test_win_service.py +++ b/tests/unit/utils/test_win_service.py @@ -14,9 +14,7 @@ class WinServiceImportTestCase(TestCase): Simply importing should not raise an error, especially on Linux """ if isinstance(win_service, Exception): - raise Exception( - "Importing win_system caused traceback: {}".format(win_service) - ) + raise Exception(f"Importing win_system caused traceback: {win_service}") @pytest.mark.skip_unless_on_windows diff --git a/tests/unit/utils/test_win_system.py b/tests/unit/utils/test_win_system.py index a30d539c53a..870b47bc4cd 100644 --- a/tests/unit/utils/test_win_system.py +++ b/tests/unit/utils/test_win_system.py @@ -18,9 +18,7 @@ class WinSystemImportTestCase(TestCase): def test_import(self): if isinstance(win_system, Exception): - raise Exception( - "Importing win_system caused traceback: {}".format(win_system) - ) + raise Exception(f"Importing win_system caused traceback: {win_system}") @pytest.mark.skip_unless_on_windows diff --git a/tests/unit/utils/test_xmlutil.py b/tests/unit/utils/test_xmlutil.py index d9a4ae5cc0c..4170cd80ffe 100644 --- a/tests/unit/utils/test_xmlutil.py +++ b/tests/unit/utils/test_xmlutil.py @@ -2,6 +2,7 @@ tests.unit.xmlutil_test ~~~~~~~~~~~~~~~~~~~~ """ + import xml.etree.ElementTree as ET import salt.utils.xmlutil as xml diff --git a/tests/unit/utils/test_yamlencoding.py b/tests/unit/utils/test_yamlencoding.py index 179b7067cd1..6e0876cbe83 100644 --- a/tests/unit/utils/test_yamlencoding.py +++ b/tests/unit/utils/test_yamlencoding.py @@ -2,7 +2,6 @@ Tests for salt.utils.yamlencoding """ - import salt.utils.yaml import salt.utils.yamlencoding from tests.support.unit import TestCase diff --git a/tests/unit/utils/test_zeromq.py b/tests/unit/utils/test_zeromq.py index 1dcd69af997..fdb4faaaeb1 100644 --- a/tests/unit/utils/test_zeromq.py +++ b/tests/unit/utils/test_zeromq.py @@ -1,6 +1,7 @@ """ Test salt.utils.zeromq """ + import pytest import zmq diff --git a/tests/unit/utils/test_zfs.py b/tests/unit/utils/test_zfs.py index 253710f94fe..cdde04336de 100644 --- a/tests/unit/utils/test_zfs.py +++ b/tests/unit/utils/test_zfs.py @@ -9,7 +9,6 @@ Tests for the zfs utils library .. versionadded:: 2018.3.1 """ - import salt.utils.zfs as zfs from salt.utils.odict import OrderedDict from tests.support.mock import MagicMock, patch diff --git a/tools/changelog.py b/tools/changelog.py index 12bbba22d3c..f39b3ed0a43 100644 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -1,6 +1,7 @@ """ These commands are used manage Salt's changelog. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/ci.py b/tools/ci.py index ae84227735d..85e4471b465 100644 --- a/tools/ci.py +++ b/tools/ci.py @@ -1,6 +1,7 @@ """ These commands are used in the CI pipeline. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/docs.py b/tools/docs.py index 5e38583024d..38604f32f25 100644 --- a/tools/docs.py +++ b/tools/docs.py @@ -1,6 +1,7 @@ """ These commands are used to generate Salt's manpages. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/pkg/__init__.py b/tools/pkg/__init__.py index 2d843893640..1ff06cae5f5 100644 --- a/tools/pkg/__init__.py +++ b/tools/pkg/__init__.py @@ -1,6 +1,7 @@ """ These commands are used to build Salt packages. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations @@ -61,7 +62,7 @@ class Recompress: d_targz = tempd.joinpath(targz.name) with tarfile.open(d_tar, "w|") as wfile: with tarfile.open(targz, "r:gz") as rfile: - rfile.extractall(d_src) + rfile.extractall(d_src) # nosec extracted_dir = next(pathlib.Path(d_src).iterdir()) for name in sorted(extracted_dir.rglob("*")): wfile.add( diff --git a/tools/pkg/build.py b/tools/pkg/build.py index c2c37eaa1f9..434e1060114 100644 --- a/tools/pkg/build.py +++ b/tools/pkg/build.py @@ -1,6 +1,7 @@ """ These commands are used to build the salt onedir and system packages. """ + # pylint: disable=resource-leakage,broad-except from __future__ import annotations @@ -227,7 +228,7 @@ def macos( 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) + tarball.extractall(path=build_root) # nosec else: ctx.info("Building package without an existing onedir") @@ -357,7 +358,7 @@ def windows( 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) + archive.extractall(unzip_dir) # nosec move_dir = unzip_dir / "salt" build_env = unzip_dir / "buildenv" diff --git a/tools/pkg/repo/__init__.py b/tools/pkg/repo/__init__.py index e48671051f2..fb028895553 100644 --- a/tools/pkg/repo/__init__.py +++ b/tools/pkg/repo/__init__.py @@ -1,6 +1,7 @@ """ These commands are used to build the package repository files. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/pkg/repo/create.py b/tools/pkg/repo/create.py index 1457d84a7af..0464249ad22 100644 --- a/tools/pkg/repo/create.py +++ b/tools/pkg/repo/create.py @@ -1,6 +1,7 @@ """ These commands are used to build the package repository files. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/pkg/repo/publish.py b/tools/pkg/repo/publish.py index 2a743ac046b..345705b4419 100644 --- a/tools/pkg/repo/publish.py +++ b/tools/pkg/repo/publish.py @@ -1,6 +1,7 @@ """ These commands are used to build the package repository files. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/precommit/__init__.py b/tools/precommit/__init__.py index c10eadeb479..2bffffbb2ec 100644 --- a/tools/precommit/__init__.py +++ b/tools/precommit/__init__.py @@ -1,6 +1,7 @@ """ These commands, and sub-commands, are used by pre-commit. """ + from ptscripts import command_group import tools.utils diff --git a/tools/precommit/changelog.py b/tools/precommit/changelog.py index 5e108af5f11..43c1f5f3e40 100644 --- a/tools/precommit/changelog.py +++ b/tools/precommit/changelog.py @@ -1,6 +1,7 @@ """ These commands are used to validate changelog entries """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/precommit/docs.py b/tools/precommit/docs.py index 84b741d3106..1fcb50592a4 100644 --- a/tools/precommit/docs.py +++ b/tools/precommit/docs.py @@ -1,6 +1,7 @@ """ Check salt code base for for missing or wrong docs """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/precommit/docstrings.py b/tools/precommit/docstrings.py index 0fecdcfcb1e..829acac37c0 100644 --- a/tools/precommit/docstrings.py +++ b/tools/precommit/docstrings.py @@ -1,6 +1,7 @@ """ Check salt code base for for missing or wrong docstrings. """ + # Skip mypy checks since it will follow into Salt which doesn't yet have proper types defined # mypy: ignore-errors # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated diff --git a/tools/precommit/filemap.py b/tools/precommit/filemap.py index 96a662fa7e7..7870375f299 100644 --- a/tools/precommit/filemap.py +++ b/tools/precommit/filemap.py @@ -1,6 +1,7 @@ """ `tests/filename_map.yml` validity checks """ + import pathlib import re diff --git a/tools/precommit/workflows.py b/tools/precommit/workflows.py index 9c9a9e95ee9..6ace8a3ecb2 100644 --- a/tools/precommit/workflows.py +++ b/tools/precommit/workflows.py @@ -1,6 +1,7 @@ """ These commands are used for our GitHub Actions workflows. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/release.py b/tools/release.py index 78fa1747aad..5943d1ed99d 100644 --- a/tools/release.py +++ b/tools/release.py @@ -1,6 +1,7 @@ """ These commands are used to release Salt. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/testsuite/__init__.py b/tools/testsuite/__init__.py index 08abf12ddcd..3c851336f5f 100644 --- a/tools/testsuite/__init__.py +++ b/tools/testsuite/__init__.py @@ -1,6 +1,7 @@ """ These commands are related to the test suite. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/testsuite/download.py b/tools/testsuite/download.py index d70dfb5f384..b1403556bd3 100644 --- a/tools/testsuite/download.py +++ b/tools/testsuite/download.py @@ -1,6 +1,7 @@ """ These commands are related to downloading test suite CI artifacts. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations diff --git a/tools/vm.py b/tools/vm.py index 996ebc845d1..8d1f93a1b06 100644 --- a/tools/vm.py +++ b/tools/vm.py @@ -2,6 +2,7 @@ These commands are used to create/destroy VMs, sync the local checkout to the VM and to run commands on the VM. """ + # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations From 539ad0f888762a30fedced3712226cd9d23b8cd1 Mon Sep 17 00:00:00 2001 From: Justin Zandbergen Date: Mon, 26 Feb 2024 10:40:10 +0100 Subject: [PATCH 45/54] Add changelog entry --- changelog/66126.fixed.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changelog/66126.fixed.md diff --git a/changelog/66126.fixed.md b/changelog/66126.fixed.md new file mode 100644 index 00000000000..9879189e644 --- /dev/null +++ b/changelog/66126.fixed.md @@ -0,0 +1,2 @@ +Fixed a issue with server channel where a minion's public key +would be rejected if it contained a final newline character. From b7f44da84926abd95f95028e54cd6f5844d86ebb Mon Sep 17 00:00:00 2001 From: Shane Lee Date: Wed, 28 Feb 2024 09:27:39 -0700 Subject: [PATCH 46/54] Refactor and add some tests Added the check to a few other places in channel server --- salt/channel/server.py | 16 +++++++-- tests/pytests/unit/channel/__init__.py | 0 tests/pytests/unit/channel/test_server.py | 43 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 tests/pytests/unit/channel/__init__.py create mode 100644 tests/pytests/unit/channel/test_server.py diff --git a/salt/channel/server.py b/salt/channel/server.py index 9be0178342a..fa352168e03 100644 --- a/salt/channel/server.py +++ b/salt/channel/server.py @@ -56,6 +56,16 @@ class ReqServerChannel: transport = salt.transport.request_server(opts, **kwargs) return cls(opts, transport) + @classmethod + def compare_keys(cls, key1, key2): + """ + Normalize and compare two keys + + Returns: + bool: ``True`` if the keys match, otherwise ``False`` + """ + return salt.crypt.clean_key(key1) == salt.crypt.clean_key(key2) + def __init__(self, opts, transport): self.opts = opts self.transport = transport @@ -381,7 +391,7 @@ class ReqServerChannel: elif os.path.isfile(pubfn): # The key has been accepted, check it with salt.utils.files.fopen(pubfn, "r") as pubfn_handle: - if salt.crypt.clean_key(pubfn_handle.read()) != load["pub"]: + if not self.compare_keys(pubfn_handle.read(), load["pub"]): log.error( "Authentication attempt from %s failed, the public " "keys did not match. This may be an attempt to compromise " @@ -490,7 +500,7 @@ class ReqServerChannel: # case. Otherwise log the fact that the minion is still # pending. with salt.utils.files.fopen(pubfn_pend, "r") as pubfn_handle: - if salt.crypt.clean_key(pubfn_handle.read()) != load["pub"]: + if not self.compare_keys(pubfn_handle.read(), load["pub"]): log.error( "Authentication attempt from %s failed, the public " "key in pending did not match. This may be an " @@ -546,7 +556,7 @@ class ReqServerChannel: # so, pass on doing anything here, and let it get automatically # accepted below. with salt.utils.files.fopen(pubfn_pend, "r") as pubfn_handle: - if salt.crypt.clean_key(pubfn_handle.read()) != load["pub"]: + if not self.compare_keys(pubfn_handle.read(), load["pub"]): log.error( "Authentication attempt from %s failed, the public " "keys in pending did not match. This may be an " diff --git a/tests/pytests/unit/channel/__init__.py b/tests/pytests/unit/channel/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/pytests/unit/channel/test_server.py b/tests/pytests/unit/channel/test_server.py new file mode 100644 index 00000000000..7e72f2f03d0 --- /dev/null +++ b/tests/pytests/unit/channel/test_server.py @@ -0,0 +1,43 @@ +import pytest + +import salt.channel.server as server + + +@pytest.fixture +def key_data(): + return [ + "-----BEGIN PUBLIC KEY-----", + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoe5QSDYRWKyknbVyRrIj", + "rm1ht5HgKzAVUber0x54+b/UgxTd1cqI6I+eDlx53LqZSH3G8Rd5cUh8LHoGedSa", + "E62vEiLAjgXa+RdgcGiQpYS8+Z2RvQJ8oIcZgO+2AzgBRHboNWHTYRRmJXCd3dKs", + "9tcwK6wxChR06HzGqaOTixAuQlegWbOTU+X4dXIbW7AnuQBt9MCib7SxHlscrqcS", + "cBrRvq51YP6cxPm/rZJdBqZhVrlghBvIpa45NApP5PherGi4AbEGYte4l+gC+fOA", + "osEBis1V27djPpIyQS4qk3XAPQg6CYQMDltHqA4Fdo0Nt7SMScxJhfH0r6zmBFAe", + "BQIDAQAB", + "-----END PUBLIC KEY-----", + ] + + +@pytest.mark.parametrize("linesep", ["\r\n", "\r", "\n"]) +def test_compare_keys(key_data, linesep): + src_key = linesep.join(key_data) + tgt_key = "\n".join(key_data) + assert server.ReqServerChannel.compare_keys(src_key, tgt_key) is True + + +@pytest.mark.parametrize("linesep", ["\r\n", "\r", "\n"]) +def test_compare_keys_newline_src(key_data, linesep): + src_key = linesep.join(key_data) + linesep + tgt_key = "\n".join(key_data) + assert src_key.endswith(linesep) + assert not tgt_key.endswith("\n") + assert server.ReqServerChannel.compare_keys(src_key, tgt_key) is True + + +@pytest.mark.parametrize("linesep", ["\r\n", "\r", "\n"]) +def test_compare_keys_newline_tgt(key_data, linesep): + src_key = linesep.join(key_data) + tgt_key = "\n".join(key_data) + "\n" + assert not src_key.endswith(linesep) + assert tgt_key.endswith("\n") + assert server.ReqServerChannel.compare_keys(src_key, tgt_key) is True From e14ece8d3bb61a9c75a54e45a49a422dfefcdd96 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sat, 2 Mar 2024 00:32:39 -0700 Subject: [PATCH 47/54] Fix test timeouts --- .../pytests/functional/modules/state/requisites/test_unless.py | 2 ++ tests/pytests/integration/modules/grains/test_append.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/pytests/functional/modules/state/requisites/test_unless.py b/tests/pytests/functional/modules/state/requisites/test_unless.py index 237163da40c..97aa37a5006 100644 --- a/tests/pytests/functional/modules/state/requisites/test_unless.py +++ b/tests/pytests/functional/modules/state/requisites/test_unless.py @@ -6,6 +6,7 @@ pytestmark = [ ] +@pytest.mark.timeout(120) def test_unless_req(state): ret = state.single(fun="test.succeed_with_changes", name="unless test", unless=[{}]) assert ret.result is True @@ -35,6 +36,7 @@ def test_unless_req(state): assert ret.comment == "Success!" +@pytest.mark.timeout(120) def test_unless_req_retcode(state): ret = state.single( fun="test.succeed_with_changes", diff --git a/tests/pytests/integration/modules/grains/test_append.py b/tests/pytests/integration/modules/grains/test_append.py index f6d3fa3015b..0338d93ae51 100644 --- a/tests/pytests/integration/modules/grains/test_append.py +++ b/tests/pytests/integration/modules/grains/test_append.py @@ -106,7 +106,7 @@ def test_grains_append_val_is_list(salt_call_cli, append_grain): assert ret.data == {append_grain.key: [append_grain.value, second_grain]} -@pytest.mark.timeout_unless_on_windows(240) +@pytest.mark.timeout_unless_on_windows(300) def test_grains_remove_add( salt_call_cli, append_grain, wait_for_pillar_refresh_complete ): From d286feabffc799cf85de45814ffc8c00288e256b Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sat, 2 Mar 2024 13:28:03 -0700 Subject: [PATCH 48/54] Fix pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c32ac1beb0..49513214dec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1520,7 +1520,7 @@ repos: - types-attrs - types-pyyaml - types-requests - - python-tools-scripts>=0.18.6 + - python-tools-scripts==0.18.6 - repo: https://github.com/saltstack/mirrors-nox rev: v2021.6.12 From 31c9d0df191009207c72ea73abfd3a1e3a0e6425 Mon Sep 17 00:00:00 2001 From: Salt Project Packaging Date: Sun, 3 Mar 2024 07:00:21 +0000 Subject: [PATCH 49/54] Release v3007.0 --- CHANGELOG.md | 180 + changelog/18907.fixed.md | 1 - changelog/40943.added.md | 1 - changelog/42039.fixed.md | 1 - changelog/45450.added.md | 1 - changelog/48067.fixed.md | 1 - changelog/50196.fixed.md | 1 - changelog/51605.fixed.md | 1 - changelog/51858.fixed.md | 1 - changelog/51986.fixed.md | 1 - changelog/52452.fixed.md | 1 - changelog/53120.changed.md | 1 - changelog/53666.added.md | 1 - changelog/53982.added.md | 1 - changelog/54426.fixed.md | 1 - changelog/55687.fixed.md | 1 - changelog/56441.fixed.md | 1 - changelog/57204.fixed.md | 1 - changelog/57541.added.md | 1 - changelog/57561.fixed.md | 1 - changelog/57946.fixed.md | 1 - changelog/58044.added.md | 1 - changelog/58174.fixed.md | 1 - changelog/58580.fixed.md | 1 - changelog/58936.fixed.md | 1 - changelog/59037.added.md | 1 - changelog/59514.fixed.md | 1 - changelog/59783.added.md | 1 - changelog/59806.fixed.md | 1 - changelog/60500.fixed.md | 1 - changelog/60779.fixed.md | 1 - changelog/61100.fixed.md | 1 - changelog/61143.fixed.md | 1 - changelog/61416.fixed.md | 1 - changelog/61620.fixed.md | 1 - changelog/62380.fixed.md | 1 - changelog/62520.removed.md | 1 - changelog/62589.added.md | 1 - changelog/62823.added.md | 1 - changelog/62825.added.md | 1 - changelog/62828.added.md | 1 - changelog/62961.added.md | 1 - changelog/63052.fixed.md | 1 - changelog/63143.added.md | 1 - changelog/63144.fixed.md | 1 - changelog/63153.fixed.md | 1 - changelog/63156.fixed.md | 1 - changelog/63159.fixed.md | 1 - changelog/63166.added.md | 1 - changelog/63214.fixed.md | 1 - changelog/63278.added.md | 1 - changelog/63278.fixed.md | 1 - changelog/63406.added.md | 1 - changelog/63416.added.md | 1 - changelog/63440.added.md | 1 - changelog/63442.added.md | 1 - changelog/63463.added.md | 1 - changelog/63545.added.md | 1 - changelog/63583.fixed.md | 1 - changelog/63708.fixed.md | 1 - changelog/63714.fixed.md | 1 - changelog/63767.fixed.md | 1 - changelog/63779.fixed.md | 1 - changelog/63905.added.md | 1 - changelog/63982.fixed.md | 1 - changelog/63985.added.md | 1 - changelog/63991.fixed.md | 1 - changelog/63996.fixed.md | 1 - changelog/64096.added.md | 1 - changelog/64224.deprecated.md | 1 - changelog/64256.added.md | 1 - changelog/64260.fixed.md | 1 - changelog/64300.fixed.md | 1 - changelog/64305.fixed.md | 1 - changelog/64322.removed.md | 1 - changelog/64369.fixed.md | 1 - changelog/64379.added.md | 1 - changelog/64417.removed.md | 1 - changelog/64418.added.md | 1 - changelog/64420.fixed.md | 1 - changelog/64450.fixed.md | 1 - changelog/64457.added.md | 1 - changelog/64457.changed.md | 6 - changelog/64459.removed.md | 1 - changelog/64460.removed.md | 1 - changelog/64461.removed.md | 1 - changelog/64462.changed.md | 1 - changelog/64488.fixed.md | 1 - changelog/64517.removed.md | 1 - changelog/64531.fixed.md | 1 - changelog/64532.added.md | 1 - changelog/64567.fixed.md | 1 - changelog/64569.added.md | 1 - changelog/64599.fixed.md | 2 - changelog/64600.added.md | 1 - changelog/64610.fixed.md | 1 - changelog/64660.added.md | 1 - changelog/64665.added.md | 1 - changelog/64893.deprecated.md | 1 - changelog/64894.deprecated.md | 1 - changelog/64896.deprecated.md | 1 - changelog/64909.deprecated.md | 1 - changelog/64924.fixed.md | 7 - changelog/64934.fixed.md | 1 - changelog/64939.added.md | 1 - changelog/64978.added.md | 1 - changelog/64989.security.md | 1 - changelog/65008.added.md | 3 - changelog/65067.fixed.md | 1 - changelog/65080.fixed.md | 1 - changelog/65137.security.md | 1 - changelog/65169.fixed.md | 1 - changelog/65220.added.md | 1 - changelog/65295.fixed.md | 1 - changelog/65435.fixed.md | 1 - changelog/65479.added.md | 1 - changelog/65480.fixed.md | 1 - changelog/65513.fixed.md | 1 - changelog/65542.deprecated.md | 1 - changelog/65562.fixed.md | 1 - changelog/65565.deprecated.md | 1 - changelog/65567.deprecated.md | 1 - changelog/65630.fixed.md | 1 - changelog/65645.added.md | 1 - changelog/65652.fixed.md | 1 - changelog/65686.fixed.md | 1 - changelog/65697.added.md | 1 - changelog/65713.added.md | 1 - changelog/65739.fixed.md | 1 - changelog/65744.added.md | 1 - changelog/65986.deprecated.md | 8 - changelog/66124.fixed.md | 1 - changelog/66126.fixed.md | 2 - doc/man/salt-api.1 | 2 +- doc/man/salt-call.1 | 2 +- doc/man/salt-cloud.1 | 2 +- doc/man/salt-cp.1 | 2 +- doc/man/salt-key.1 | 2 +- doc/man/salt-master.1 | 2 +- doc/man/salt-minion.1 | 2 +- doc/man/salt-proxy.1 | 2 +- doc/man/salt-run.1 | 2 +- doc/man/salt-ssh.1 | 2 +- doc/man/salt-syndic.1 | 2 +- doc/man/salt.1 | 2 +- doc/man/salt.7 | 31375 +++++++++++++------------------- doc/man/spm.1 | 2 +- doc/topics/releases/3007.0.md | 18 +- pkg/debian/changelog | 177 + pkg/rpm/salt.spec | 176 +- 150 files changed, 12961 insertions(+), 19145 deletions(-) delete mode 100644 changelog/18907.fixed.md delete mode 100644 changelog/40943.added.md delete mode 100644 changelog/42039.fixed.md delete mode 100644 changelog/45450.added.md delete mode 100644 changelog/48067.fixed.md delete mode 100644 changelog/50196.fixed.md delete mode 100644 changelog/51605.fixed.md delete mode 100644 changelog/51858.fixed.md delete mode 100644 changelog/51986.fixed.md delete mode 100644 changelog/52452.fixed.md delete mode 100644 changelog/53120.changed.md delete mode 100644 changelog/53666.added.md delete mode 100644 changelog/53982.added.md delete mode 100644 changelog/54426.fixed.md delete mode 100644 changelog/55687.fixed.md delete mode 100644 changelog/56441.fixed.md delete mode 100644 changelog/57204.fixed.md delete mode 100644 changelog/57541.added.md delete mode 100644 changelog/57561.fixed.md delete mode 100644 changelog/57946.fixed.md delete mode 100644 changelog/58044.added.md delete mode 100644 changelog/58174.fixed.md delete mode 100644 changelog/58580.fixed.md delete mode 100644 changelog/58936.fixed.md delete mode 100644 changelog/59037.added.md delete mode 100644 changelog/59514.fixed.md delete mode 100644 changelog/59783.added.md delete mode 100644 changelog/59806.fixed.md delete mode 100644 changelog/60500.fixed.md delete mode 100644 changelog/60779.fixed.md delete mode 100644 changelog/61100.fixed.md delete mode 100644 changelog/61143.fixed.md delete mode 100644 changelog/61416.fixed.md delete mode 100644 changelog/61620.fixed.md delete mode 100644 changelog/62380.fixed.md delete mode 100644 changelog/62520.removed.md delete mode 100644 changelog/62589.added.md delete mode 100644 changelog/62823.added.md delete mode 100644 changelog/62825.added.md delete mode 100644 changelog/62828.added.md delete mode 100644 changelog/62961.added.md delete mode 100644 changelog/63052.fixed.md delete mode 100644 changelog/63143.added.md delete mode 100644 changelog/63144.fixed.md delete mode 100644 changelog/63153.fixed.md delete mode 100644 changelog/63156.fixed.md delete mode 100644 changelog/63159.fixed.md delete mode 100644 changelog/63166.added.md delete mode 100644 changelog/63214.fixed.md delete mode 100644 changelog/63278.added.md delete mode 100644 changelog/63278.fixed.md delete mode 100644 changelog/63406.added.md delete mode 100644 changelog/63416.added.md delete mode 100644 changelog/63440.added.md delete mode 100644 changelog/63442.added.md delete mode 100644 changelog/63463.added.md delete mode 100644 changelog/63545.added.md delete mode 100644 changelog/63583.fixed.md delete mode 100644 changelog/63708.fixed.md delete mode 100644 changelog/63714.fixed.md delete mode 100644 changelog/63767.fixed.md delete mode 100644 changelog/63779.fixed.md delete mode 100644 changelog/63905.added.md delete mode 100644 changelog/63982.fixed.md delete mode 100644 changelog/63985.added.md delete mode 100644 changelog/63991.fixed.md delete mode 100644 changelog/63996.fixed.md delete mode 100644 changelog/64096.added.md delete mode 100644 changelog/64224.deprecated.md delete mode 100644 changelog/64256.added.md delete mode 100644 changelog/64260.fixed.md delete mode 100644 changelog/64300.fixed.md delete mode 100644 changelog/64305.fixed.md delete mode 100644 changelog/64322.removed.md delete mode 100644 changelog/64369.fixed.md delete mode 100644 changelog/64379.added.md delete mode 100644 changelog/64417.removed.md delete mode 100644 changelog/64418.added.md delete mode 100644 changelog/64420.fixed.md delete mode 100644 changelog/64450.fixed.md delete mode 100644 changelog/64457.added.md delete mode 100644 changelog/64457.changed.md delete mode 100644 changelog/64459.removed.md delete mode 100644 changelog/64460.removed.md delete mode 100644 changelog/64461.removed.md delete mode 100644 changelog/64462.changed.md delete mode 100644 changelog/64488.fixed.md delete mode 100644 changelog/64517.removed.md delete mode 100644 changelog/64531.fixed.md delete mode 100644 changelog/64532.added.md delete mode 100644 changelog/64567.fixed.md delete mode 100644 changelog/64569.added.md delete mode 100644 changelog/64599.fixed.md delete mode 100644 changelog/64600.added.md delete mode 100644 changelog/64610.fixed.md delete mode 100644 changelog/64660.added.md delete mode 100644 changelog/64665.added.md delete mode 100644 changelog/64893.deprecated.md delete mode 100644 changelog/64894.deprecated.md delete mode 100644 changelog/64896.deprecated.md delete mode 100644 changelog/64909.deprecated.md delete mode 100644 changelog/64924.fixed.md delete mode 100644 changelog/64934.fixed.md delete mode 100644 changelog/64939.added.md delete mode 100644 changelog/64978.added.md delete mode 100644 changelog/64989.security.md delete mode 100644 changelog/65008.added.md delete mode 100644 changelog/65067.fixed.md delete mode 100644 changelog/65080.fixed.md delete mode 100644 changelog/65137.security.md delete mode 100644 changelog/65169.fixed.md delete mode 100644 changelog/65220.added.md delete mode 100644 changelog/65295.fixed.md delete mode 100644 changelog/65435.fixed.md delete mode 100644 changelog/65479.added.md delete mode 100644 changelog/65480.fixed.md delete mode 100644 changelog/65513.fixed.md delete mode 100644 changelog/65542.deprecated.md delete mode 100644 changelog/65562.fixed.md delete mode 100644 changelog/65565.deprecated.md delete mode 100644 changelog/65567.deprecated.md delete mode 100644 changelog/65630.fixed.md delete mode 100644 changelog/65645.added.md delete mode 100644 changelog/65652.fixed.md delete mode 100644 changelog/65686.fixed.md delete mode 100644 changelog/65697.added.md delete mode 100644 changelog/65713.added.md delete mode 100644 changelog/65739.fixed.md delete mode 100644 changelog/65744.added.md delete mode 100644 changelog/65986.deprecated.md delete mode 100644 changelog/66124.fixed.md delete mode 100644 changelog/66126.fixed.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f69ebad42f0..3ea1a0e5d5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,186 @@ Versions are `MAJOR.PATCH`. # Changelog +## 3007.0 (2024-03-03) + + +### Removed + +- Removed RHEL 5 support since long since end-of-lifed [#62520](https://github.com/saltstack/salt/issues/62520) +- Removing Azure-Cloud modules from the code base. [#64322](https://github.com/saltstack/salt/issues/64322) +- Dropped Python 3.7 support since it's EOL in 27 Jun 2023 [#64417](https://github.com/saltstack/salt/issues/64417) +- Remove salt.payload.Serial [#64459](https://github.com/saltstack/salt/issues/64459) +- Remove netmiko_conn and pyeapi_conn from salt.modules.napalm_mod [#64460](https://github.com/saltstack/salt/issues/64460) +- Removed 'transport' arg from salt.utils.event.get_event [#64461](https://github.com/saltstack/salt/issues/64461) +- Removed the usage of retired Linode API v3 from Salt Cloud [#64517](https://github.com/saltstack/salt/issues/64517) + + +### Deprecated + +- Deprecate all Proxmox cloud modules [#64224](https://github.com/saltstack/salt/issues/64224) +- Deprecate all the Vault modules in favor of the Vault Salt Extension https://github.com/salt-extensions/saltext-vault. The Vault modules will be removed in Salt core in 3009.0. [#64893](https://github.com/saltstack/salt/issues/64893) +- Deprecate all the Docker modules in favor of the Docker Salt Extension https://github.com/saltstack/saltext-docker. The Docker modules will be removed in Salt core in 3009.0. [#64894](https://github.com/saltstack/salt/issues/64894) +- Deprecate all the Zabbix modules in favor of the Zabbix Salt Extension https://github.com/salt-extensions/saltext-zabbix. The Zabbix modules will be removed in Salt core in 3009.0. [#64896](https://github.com/saltstack/salt/issues/64896) +- Deprecate all the Apache modules in favor of the Apache Salt Extension https://github.com/salt-extensions/saltext-apache. The Apache modules will be removed in Salt core in 3009.0. [#64909](https://github.com/saltstack/salt/issues/64909) +- Deprecation warning for Salt's backport of ``OrderedDict`` class which will be removed in 3009 [#65542](https://github.com/saltstack/salt/issues/65542) +- Deprecate Kubernetes modules for move to saltext-kubernetes in version 3009 [#65565](https://github.com/saltstack/salt/issues/65565) +- Deprecated all Pushover modules in favor of the Salt Extension at https://github.com/salt-extensions/saltext-pushover. The Pushover modules will be removed from Salt core in 3009.0 [#65567](https://github.com/saltstack/salt/issues/65567) +- Removed deprecated code: + + * All of ``salt/log/`` which has been on a deprecation path for a long time. + * Some of the logging handlers found in ``salt/_logging/handlers`` have been removed since the standard library provides + them. + * Removed the deprecated ``salt/modules/cassandra_mod.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/cassandra_return.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/django_return.py`` module and any tests for it. [#65986](https://github.com/saltstack/salt/issues/65986) + + +### Changed + +- Masquerade property will not default to false turning off masquerade if not specified. [#53120](https://github.com/saltstack/salt/issues/53120) +- Addressed Python 3.11 deprecations: + + * Switch to `FullArgSpec` since Py 3.11 no longer has `ArgSpec`, deprecated since Py 3.0 + * Stopped using the deprecated `cgi` module. + * Stopped using the deprecated `pipes` module + * Stopped using the deprecated `imp` module [#64457](https://github.com/saltstack/salt/issues/64457) +- changed 'gpg_decrypt_must_succeed' default from False to True [#64462](https://github.com/saltstack/salt/issues/64462) + + +### Fixed + +- When an NFS or FUSE mount fails to unmount when mount options have changed, try again with a lazy umount before mounting again. [#18907](https://github.com/saltstack/salt/issues/18907) +- fix autoaccept gpg keys by supporting it in refresh_db module [#42039](https://github.com/saltstack/salt/issues/42039) +- Made cmd.script work with files from the fileserver via salt-ssh [#48067](https://github.com/saltstack/salt/issues/48067) +- Made slsutil.renderer work with salt-ssh [#50196](https://github.com/saltstack/salt/issues/50196) +- Fixed defaults.merge is not available when using salt-ssh [#51605](https://github.com/saltstack/salt/issues/51605) +- Fix extfs.mkfs missing parameter handling for -C, -d, and -e [#51858](https://github.com/saltstack/salt/issues/51858) +- Fixed Salt master does not renew token [#51986](https://github.com/saltstack/salt/issues/51986) +- Fixed salt-ssh continues state/pillar rendering with incorrect data when an exception is raised by a module on the target [#52452](https://github.com/saltstack/salt/issues/52452) +- Fix extfs.tune has 'reserved' documented twice and is missing the 'reserved_percentage' keyword argument [#54426](https://github.com/saltstack/salt/issues/54426) +- Fix the ability of the 'selinux.port_policy_present' state to modify. [#55687](https://github.com/saltstack/salt/issues/55687) +- Fixed config.get does not support merge option with salt-ssh [#56441](https://github.com/saltstack/salt/issues/56441) +- Removed an unused assignment in file.patch [#57204](https://github.com/saltstack/salt/issues/57204) +- Fixed vault module fetching more than one secret in one run with single-use tokens [#57561](https://github.com/saltstack/salt/issues/57561) +- Use brew path from which in mac_brew_pkg module and rely on _homebrew_bin() everytime [#57946](https://github.com/saltstack/salt/issues/57946) +- Fixed Vault verify option to work on minions when only specified in master config [#58174](https://github.com/saltstack/salt/issues/58174) +- Fixed vault command errors configured locally [#58580](https://github.com/saltstack/salt/issues/58580) +- Fixed issue with basic auth causing invalid header error and 401 Bad Request, by using HTTPBasicAuthHandler instead of header. [#58936](https://github.com/saltstack/salt/issues/58936) +- Make the LXD module work with pyLXD > 2.10 [#59514](https://github.com/saltstack/salt/issues/59514) +- Return error if patch file passed to state file.patch is malformed. [#59806](https://github.com/saltstack/salt/issues/59806) +- Handle failure and error information from tuned module/state [#60500](https://github.com/saltstack/salt/issues/60500) +- Fixed sdb.get_or_set_hash with Vault single-use tokens [#60779](https://github.com/saltstack/salt/issues/60779) +- Fixed state.test does not work with salt-ssh [#61100](https://github.com/saltstack/salt/issues/61100) +- Made slsutil.findup work with salt-ssh [#61143](https://github.com/saltstack/salt/issues/61143) +- Allow all primitive grain types for autosign_grains [#61416](https://github.com/saltstack/salt/issues/61416), [#63708](https://github.com/saltstack/salt/issues/63708) +- `ipset.new_set` no longer fails when creating a set type that uses the `family` create option [#61620](https://github.com/saltstack/salt/issues/61620) +- Fixed Vault session storage to allow unlimited use tokens [#62380](https://github.com/saltstack/salt/issues/62380) +- fix the efi grain on FreeBSD [#63052](https://github.com/saltstack/salt/issues/63052) +- Fixed gpg.receive_keys returns success on failed import [#63144](https://github.com/saltstack/salt/issues/63144) +- Fixed GPG state module always reports success without changes [#63153](https://github.com/saltstack/salt/issues/63153) +- Fixed GPG state module does not respect test mode [#63156](https://github.com/saltstack/salt/issues/63156) +- Fixed gpg.absent with gnupghome/user, fixed gpg.delete_key with gnupghome [#63159](https://github.com/saltstack/salt/issues/63159) +- Fixed service module does not handle enable/disable if systemd service is an alias [#63214](https://github.com/saltstack/salt/issues/63214) +- Made x509_v2 compound match detection use new runner instead of peer publishing [#63278](https://github.com/saltstack/salt/issues/63278) +- Need to make sure we update __pillar__ during a pillar refresh to ensure that process_beacons has the updated beacons loaded from pillar. [#63583](https://github.com/saltstack/salt/issues/63583) +- This implements the vpc_uuid parameter when creating a droplet. This parameter selects the correct virtual private cloud (private network interface). [#63714](https://github.com/saltstack/salt/issues/63714) +- pkg.installed no longer reports failure when installing packages that are installed via the task manager [#63767](https://github.com/saltstack/salt/issues/63767) +- mac_xattr.list and mac_xattr.read will replace undecode-able bytes to avoid raising CommandExecutionError. [#63779](https://github.com/saltstack/salt/issues/63779) [#63779](https://github.com/saltstack/salt/issues/63779) +- Fix aptpkg.latest_version performance, reducing number of times to 'shell out' [#63982](https://github.com/saltstack/salt/issues/63982) +- Added option to use a fresh connection for mysql cache [#63991](https://github.com/saltstack/salt/issues/63991) +- [lxd] Fixed a bug in `container_create` which prevented devices which are not of type `disk` to be correctly created and added to the container when passed via the `devices` parameter. [#63996](https://github.com/saltstack/salt/issues/63996) +- Skipped the `isfile` check to greatly increase speed of reading minion keys for systems with a large number of minions on slow file storage [#64260](https://github.com/saltstack/salt/issues/64260) +- Fix utf8 handling in 'pass' renderer [#64300](https://github.com/saltstack/salt/issues/64300) +- Upgade tornado to 6.3.2 [#64305](https://github.com/saltstack/salt/issues/64305) +- Prevent errors due missing 'transactional_update.apply' on SLE Micro and MicroOS. [#64369](https://github.com/saltstack/salt/issues/64369) +- Fix 'unable to unmount' failure to return False result instead of None [#64420](https://github.com/saltstack/salt/issues/64420) +- Fixed issue uninstalling duplicate packages in ``win_appx`` execution module [#64450](https://github.com/saltstack/salt/issues/64450) +- Clean up tech debt, IPC now uses tcp transport. [#64488](https://github.com/saltstack/salt/issues/64488) +- Made salt-ssh more strict when handling unexpected situations and state.* wrappers treat a remote exception as failure, excluded salt-ssh error returns from mine [#64531](https://github.com/saltstack/salt/issues/64531) +- Fix flaky test for LazyLoader with isolated mocking of threading.RLock [#64567](https://github.com/saltstack/salt/issues/64567) +- Fix possible `KeyError` exceptions in `salt.utils.user.get_group_dict` + while reading improper duplicated GID assigned for the user. [#64599](https://github.com/saltstack/salt/issues/64599) +- changed vm_config() to deep-merge vm_overrides of specific VM, instead of simple-merging the whole vm_overrides [#64610](https://github.com/saltstack/salt/issues/64610) +- Fix the way Salt tries to get the Homebrew's prefix + + The first attempt to get the Homebrew's prefix is to look for + the `HOMEBREW_PREFIX` environment variable. If it's not set, then + Salt tries to get the prefix from the `brew` command. However, the + `brew` command can fail. So a last attempt is made to get the + prefix by guessing the installation path. [#64924](https://github.com/saltstack/salt/issues/64924) +- Add missing MySQL Grant SERVICE_CONNECTION_ADMIN to mysql module. [#64934](https://github.com/saltstack/salt/issues/64934) +- Fixed slsutil.update with salt-ssh during template rendering [#65067](https://github.com/saltstack/salt/issues/65067) +- Keep track when an included file only includes sls files but is a requisite. [#65080](https://github.com/saltstack/salt/issues/65080) +- Fixed `gpg.present` succeeds when the keyserver is unreachable [#65169](https://github.com/saltstack/salt/issues/65169) +- Fix typo in nftables module to ensure unique nft family values [#65295](https://github.com/saltstack/salt/issues/65295) +- Dereference symlinks to set proper __cli opt [#65435](https://github.com/saltstack/salt/issues/65435) +- Made salt-ssh merge master top returns for the same environment [#65480](https://github.com/saltstack/salt/issues/65480) +- Account for situation where the metadata grain fails because the AWS environment requires an authentication token to query the metadata URL. [#65513](https://github.com/saltstack/salt/issues/65513) +- Improve the condition of overriding target for pip with VENV_PIP_TARGET environment variable. [#65562](https://github.com/saltstack/salt/issues/65562) +- Added SSH wrapper for logmod [#65630](https://github.com/saltstack/salt/issues/65630) +- Include changes in the results when schedule.present state is run with test=True. [#65652](https://github.com/saltstack/salt/issues/65652) +- Fix extfs.tune doesn't pass retcode to module.run [#65686](https://github.com/saltstack/salt/issues/65686) +- Return an error message when the DNS plugin is not supported [#65739](https://github.com/saltstack/salt/issues/65739) +- Execution modules have access to regular fileclient durring pillar rendering. [#66124](https://github.com/saltstack/salt/issues/66124) +- Fixed a issue with server channel where a minion's public key + would be rejected if it contained a final newline character. [#66126](https://github.com/saltstack/salt/issues/66126) + + +### Added + +- Allowed publishing to regular minions from the SSH wrapper [#40943](https://github.com/saltstack/salt/issues/40943) +- Added syncing of custom salt-ssh wrappers [#45450](https://github.com/saltstack/salt/issues/45450) +- Made salt-ssh sync custom utils [#53666](https://github.com/saltstack/salt/issues/53666) +- Add ability to use file.managed style check_cmd in file.serialize [#53982](https://github.com/saltstack/salt/issues/53982) +- Revised use of deprecated net-tools and added support for ip neighbour with IPv4 ip_neighs, IPv6 ip_neighs6 [#57541](https://github.com/saltstack/salt/issues/57541) +- Added password support to Redis returner. [#58044](https://github.com/saltstack/salt/issues/58044) +- Added a state (win_task) for managing scheduled tasks on Windows [#59037](https://github.com/saltstack/salt/issues/59037) +- Added keyring param to gpg modules [#59783](https://github.com/saltstack/salt/issues/59783) +- Added new grain to detect the Salt package type: onedir, pip or system [#62589](https://github.com/saltstack/salt/issues/62589) +- Added Vault AppRole and identity issuance to minions [#62823](https://github.com/saltstack/salt/issues/62823) +- Added Vault AppRole auth mount path configuration option [#62825](https://github.com/saltstack/salt/issues/62825) +- Added distribution of Vault authentication details via response wrapping [#62828](https://github.com/saltstack/salt/issues/62828) +- Add salt package type information. Either onedir, pip or system. [#62961](https://github.com/saltstack/salt/issues/62961) +- Added signature verification to file.managed/archive.extracted [#63143](https://github.com/saltstack/salt/issues/63143) +- Added signed_by_any/signed_by_all parameters to gpg.verify [#63166](https://github.com/saltstack/salt/issues/63166) +- Added match runner [#63278](https://github.com/saltstack/salt/issues/63278) +- Added Vault token lifecycle management [#63406](https://github.com/saltstack/salt/issues/63406) +- adding new call for openscap xccdf eval supporting new parameters [#63416](https://github.com/saltstack/salt/issues/63416) +- Added Vault lease management utility [#63440](https://github.com/saltstack/salt/issues/63440) +- implement removal of ptf packages in zypper pkg module [#63442](https://github.com/saltstack/salt/issues/63442) +- add JUnit output for saltcheck [#63463](https://github.com/saltstack/salt/issues/63463) +- Add ability for file.keyvalue to create a file if it doesn't exist [#63545](https://github.com/saltstack/salt/issues/63545) +- added cleanup of temporary mountpoint dir for macpackage installed state [#63905](https://github.com/saltstack/salt/issues/63905) +- Add pkg.installed show installable version in test mode [#63985](https://github.com/saltstack/salt/issues/63985) +- Added patch option to Vault SDB driver [#64096](https://github.com/saltstack/salt/issues/64096) +- Added flags to create local users and groups [#64256](https://github.com/saltstack/salt/issues/64256) +- Added inline specification of trusted CA root certificate for Vault [#64379](https://github.com/saltstack/salt/issues/64379) +- Add ability to return False result in test mode of configurable_test_state [#64418](https://github.com/saltstack/salt/issues/64418) +- Switched Salt's onedir Python version to 3.11 [#64457](https://github.com/saltstack/salt/issues/64457) +- Added support for dnf5 and its new command syntax [#64532](https://github.com/saltstack/salt/issues/64532) +- Adding a new decorator to indicate when a module is deprecated in favor of a Salt extension. [#64569](https://github.com/saltstack/salt/issues/64569) +- Add jq-esque to_entries and from_entries functions [#64600](https://github.com/saltstack/salt/issues/64600) +- Added ability to use PYTHONWARNINGS=ignore to silence deprecation warnings. [#64660](https://github.com/saltstack/salt/issues/64660) +- Add follow_symlinks to file.symlink exec module to switch to os.path.lexists when False [#64665](https://github.com/saltstack/salt/issues/64665) +- Strenghten Salt's HA capabilities with master clustering. [#64939](https://github.com/saltstack/salt/issues/64939) +- Added win_appx state and execution modules for managing Microsoft Store apps and deprovisioning them from systems [#64978](https://github.com/saltstack/salt/issues/64978) +- Add support for show_jid to salt-run + + Adds support for show_jid master config option to salt-run, so its behaviour matches the salt cli command. [#65008](https://github.com/saltstack/salt/issues/65008) +- Add ability to remove packages by wildcard via apt execution module [#65220](https://github.com/saltstack/salt/issues/65220) +- Added support for master top modules on masterless minions [#65479](https://github.com/saltstack/salt/issues/65479) +- Allowed accessing the regular mine from the SSH wrapper [#65645](https://github.com/saltstack/salt/issues/65645) +- Allow enabling backup for Linode in Salt Cloud [#65697](https://github.com/saltstack/salt/issues/65697) +- Add a backup schedule setter fFunction for Linode VMs [#65713](https://github.com/saltstack/salt/issues/65713) +- Add acme support for manual plugin hooks [#65744](https://github.com/saltstack/salt/issues/65744) + + +### Security + +- Upgrade to `tornado>=6.3.3` due to https://github.com/advisories/GHSA-qppv-j76h-2rpx [#64989](https://github.com/saltstack/salt/issues/64989) +- Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65137](https://github.com/saltstack/salt/issues/65137) + + ## 3007.0rc1 (2024-01-02) diff --git a/changelog/18907.fixed.md b/changelog/18907.fixed.md deleted file mode 100644 index 3c728b85db5..00000000000 --- a/changelog/18907.fixed.md +++ /dev/null @@ -1 +0,0 @@ -When an NFS or FUSE mount fails to unmount when mount options have changed, try again with a lazy umount before mounting again. diff --git a/changelog/40943.added.md b/changelog/40943.added.md deleted file mode 100644 index f8f5f8199ff..00000000000 --- a/changelog/40943.added.md +++ /dev/null @@ -1 +0,0 @@ -Allowed publishing to regular minions from the SSH wrapper diff --git a/changelog/42039.fixed.md b/changelog/42039.fixed.md deleted file mode 100644 index d3e9eab2d0c..00000000000 --- a/changelog/42039.fixed.md +++ /dev/null @@ -1 +0,0 @@ -fix autoaccept gpg keys by supporting it in refresh_db module diff --git a/changelog/45450.added.md b/changelog/45450.added.md deleted file mode 100644 index c7d6cd93074..00000000000 --- a/changelog/45450.added.md +++ /dev/null @@ -1 +0,0 @@ -Added syncing of custom salt-ssh wrappers diff --git a/changelog/48067.fixed.md b/changelog/48067.fixed.md deleted file mode 100644 index b060c44cde8..00000000000 --- a/changelog/48067.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Made cmd.script work with files from the fileserver via salt-ssh diff --git a/changelog/50196.fixed.md b/changelog/50196.fixed.md deleted file mode 100644 index 979411a640d..00000000000 --- a/changelog/50196.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Made slsutil.renderer work with salt-ssh diff --git a/changelog/51605.fixed.md b/changelog/51605.fixed.md deleted file mode 100644 index 990b34413d9..00000000000 --- a/changelog/51605.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed defaults.merge is not available when using salt-ssh diff --git a/changelog/51858.fixed.md b/changelog/51858.fixed.md deleted file mode 100644 index 72778ff2599..00000000000 --- a/changelog/51858.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix extfs.mkfs missing parameter handling for -C, -d, and -e diff --git a/changelog/51986.fixed.md b/changelog/51986.fixed.md deleted file mode 100644 index 2ac8623e859..00000000000 --- a/changelog/51986.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed Salt master does not renew token diff --git a/changelog/52452.fixed.md b/changelog/52452.fixed.md deleted file mode 100644 index 4b09aedca67..00000000000 --- a/changelog/52452.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed salt-ssh continues state/pillar rendering with incorrect data when an exception is raised by a module on the target diff --git a/changelog/53120.changed.md b/changelog/53120.changed.md deleted file mode 100644 index 9889e6e83f3..00000000000 --- a/changelog/53120.changed.md +++ /dev/null @@ -1 +0,0 @@ -Masquerade property will not default to false turning off masquerade if not specified. diff --git a/changelog/53666.added.md b/changelog/53666.added.md deleted file mode 100644 index 0f82455c934..00000000000 --- a/changelog/53666.added.md +++ /dev/null @@ -1 +0,0 @@ -Made salt-ssh sync custom utils diff --git a/changelog/53982.added.md b/changelog/53982.added.md deleted file mode 100644 index e9411910188..00000000000 --- a/changelog/53982.added.md +++ /dev/null @@ -1 +0,0 @@ -Add ability to use file.managed style check_cmd in file.serialize diff --git a/changelog/54426.fixed.md b/changelog/54426.fixed.md deleted file mode 100644 index 172458ae258..00000000000 --- a/changelog/54426.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix extfs.tune has 'reserved' documented twice and is missing the 'reserved_percentage' keyword argument diff --git a/changelog/55687.fixed.md b/changelog/55687.fixed.md deleted file mode 100644 index 73c8c852b3f..00000000000 --- a/changelog/55687.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix the ability of the 'selinux.port_policy_present' state to modify. diff --git a/changelog/56441.fixed.md b/changelog/56441.fixed.md deleted file mode 100644 index 489ad80f770..00000000000 --- a/changelog/56441.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed config.get does not support merge option with salt-ssh diff --git a/changelog/57204.fixed.md b/changelog/57204.fixed.md deleted file mode 100644 index 038b6642852..00000000000 --- a/changelog/57204.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Removed an unused assignment in file.patch diff --git a/changelog/57541.added.md b/changelog/57541.added.md deleted file mode 100644 index 985bad2ee10..00000000000 --- a/changelog/57541.added.md +++ /dev/null @@ -1 +0,0 @@ -Revised use of deprecated net-tools and added support for ip neighbour with IPv4 ip_neighs, IPv6 ip_neighs6 diff --git a/changelog/57561.fixed.md b/changelog/57561.fixed.md deleted file mode 100644 index 57ca72619ee..00000000000 --- a/changelog/57561.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed vault module fetching more than one secret in one run with single-use tokens diff --git a/changelog/57946.fixed.md b/changelog/57946.fixed.md deleted file mode 100644 index c2ad189fa7f..00000000000 --- a/changelog/57946.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Use brew path from which in mac_brew_pkg module and rely on _homebrew_bin() everytime diff --git a/changelog/58044.added.md b/changelog/58044.added.md deleted file mode 100644 index 5e4181520ef..00000000000 --- a/changelog/58044.added.md +++ /dev/null @@ -1 +0,0 @@ -Added password support to Redis returner. diff --git a/changelog/58174.fixed.md b/changelog/58174.fixed.md deleted file mode 100644 index e2059921109..00000000000 --- a/changelog/58174.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed Vault verify option to work on minions when only specified in master config diff --git a/changelog/58580.fixed.md b/changelog/58580.fixed.md deleted file mode 100644 index b86d0ac8d4b..00000000000 --- a/changelog/58580.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed vault command errors configured locally diff --git a/changelog/58936.fixed.md b/changelog/58936.fixed.md deleted file mode 100644 index 1ab53ccfe1b..00000000000 --- a/changelog/58936.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed issue with basic auth causing invalid header error and 401 Bad Request, by using HTTPBasicAuthHandler instead of header. diff --git a/changelog/59037.added.md b/changelog/59037.added.md deleted file mode 100644 index 6d74b4ba63c..00000000000 --- a/changelog/59037.added.md +++ /dev/null @@ -1 +0,0 @@ -Added a state (win_task) for managing scheduled tasks on Windows diff --git a/changelog/59514.fixed.md b/changelog/59514.fixed.md deleted file mode 100644 index 1c7726290d9..00000000000 --- a/changelog/59514.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Make the LXD module work with pyLXD > 2.10 diff --git a/changelog/59783.added.md b/changelog/59783.added.md deleted file mode 100644 index ba6d71d494d..00000000000 --- a/changelog/59783.added.md +++ /dev/null @@ -1 +0,0 @@ -Added keyring param to gpg modules diff --git a/changelog/59806.fixed.md b/changelog/59806.fixed.md deleted file mode 100644 index 2cca505c2bf..00000000000 --- a/changelog/59806.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Return error if patch file passed to state file.patch is malformed. diff --git a/changelog/60500.fixed.md b/changelog/60500.fixed.md deleted file mode 100644 index 1daf48c1a11..00000000000 --- a/changelog/60500.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Handle failure and error information from tuned module/state diff --git a/changelog/60779.fixed.md b/changelog/60779.fixed.md deleted file mode 100644 index 597117d1f18..00000000000 --- a/changelog/60779.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed sdb.get_or_set_hash with Vault single-use tokens diff --git a/changelog/61100.fixed.md b/changelog/61100.fixed.md deleted file mode 100644 index d7ac2b6bc3f..00000000000 --- a/changelog/61100.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed state.test does not work with salt-ssh diff --git a/changelog/61143.fixed.md b/changelog/61143.fixed.md deleted file mode 100644 index 08a62c9d8b1..00000000000 --- a/changelog/61143.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Made slsutil.findup work with salt-ssh diff --git a/changelog/61416.fixed.md b/changelog/61416.fixed.md deleted file mode 100644 index 3203a0a1c6a..00000000000 --- a/changelog/61416.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Allow all primitive grain types for autosign_grains diff --git a/changelog/61620.fixed.md b/changelog/61620.fixed.md deleted file mode 100644 index cd0818244ce..00000000000 --- a/changelog/61620.fixed.md +++ /dev/null @@ -1 +0,0 @@ -`ipset.new_set` no longer fails when creating a set type that uses the `family` create option diff --git a/changelog/62380.fixed.md b/changelog/62380.fixed.md deleted file mode 100644 index 839ec661d1a..00000000000 --- a/changelog/62380.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed Vault session storage to allow unlimited use tokens diff --git a/changelog/62520.removed.md b/changelog/62520.removed.md deleted file mode 100644 index 381c33ea090..00000000000 --- a/changelog/62520.removed.md +++ /dev/null @@ -1 +0,0 @@ -Removed RHEL 5 support since long since end-of-lifed diff --git a/changelog/62589.added.md b/changelog/62589.added.md deleted file mode 100644 index 2d4dcb0116e..00000000000 --- a/changelog/62589.added.md +++ /dev/null @@ -1 +0,0 @@ -Added new grain to detect the Salt package type: onedir, pip or system diff --git a/changelog/62823.added.md b/changelog/62823.added.md deleted file mode 100644 index cdce46c5b4e..00000000000 --- a/changelog/62823.added.md +++ /dev/null @@ -1 +0,0 @@ -Added Vault AppRole and identity issuance to minions diff --git a/changelog/62825.added.md b/changelog/62825.added.md deleted file mode 100644 index 8935d16d237..00000000000 --- a/changelog/62825.added.md +++ /dev/null @@ -1 +0,0 @@ -Added Vault AppRole auth mount path configuration option diff --git a/changelog/62828.added.md b/changelog/62828.added.md deleted file mode 100644 index d848300f676..00000000000 --- a/changelog/62828.added.md +++ /dev/null @@ -1 +0,0 @@ -Added distribution of Vault authentication details via response wrapping diff --git a/changelog/62961.added.md b/changelog/62961.added.md deleted file mode 100644 index bb33cbdd766..00000000000 --- a/changelog/62961.added.md +++ /dev/null @@ -1 +0,0 @@ -Add salt package type information. Either onedir, pip or system. diff --git a/changelog/63052.fixed.md b/changelog/63052.fixed.md deleted file mode 100644 index 9344ce70fae..00000000000 --- a/changelog/63052.fixed.md +++ /dev/null @@ -1 +0,0 @@ -fix the efi grain on FreeBSD diff --git a/changelog/63143.added.md b/changelog/63143.added.md deleted file mode 100644 index 9a423baeff4..00000000000 --- a/changelog/63143.added.md +++ /dev/null @@ -1 +0,0 @@ -Added signature verification to file.managed/archive.extracted diff --git a/changelog/63144.fixed.md b/changelog/63144.fixed.md deleted file mode 100644 index cc100dcd21f..00000000000 --- a/changelog/63144.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed gpg.receive_keys returns success on failed import diff --git a/changelog/63153.fixed.md b/changelog/63153.fixed.md deleted file mode 100644 index f1c617f8cd6..00000000000 --- a/changelog/63153.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed GPG state module always reports success without changes diff --git a/changelog/63156.fixed.md b/changelog/63156.fixed.md deleted file mode 100644 index 85efe22e226..00000000000 --- a/changelog/63156.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed GPG state module does not respect test mode diff --git a/changelog/63159.fixed.md b/changelog/63159.fixed.md deleted file mode 100644 index 914bb703b28..00000000000 --- a/changelog/63159.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed gpg.absent with gnupghome/user, fixed gpg.delete_key with gnupghome diff --git a/changelog/63166.added.md b/changelog/63166.added.md deleted file mode 100644 index bb672a367bf..00000000000 --- a/changelog/63166.added.md +++ /dev/null @@ -1 +0,0 @@ -Added signed_by_any/signed_by_all parameters to gpg.verify diff --git a/changelog/63214.fixed.md b/changelog/63214.fixed.md deleted file mode 100644 index 58d314aeaa5..00000000000 --- a/changelog/63214.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed service module does not handle enable/disable if systemd service is an alias diff --git a/changelog/63278.added.md b/changelog/63278.added.md deleted file mode 100644 index 5bbf1535cc2..00000000000 --- a/changelog/63278.added.md +++ /dev/null @@ -1 +0,0 @@ -Added match runner diff --git a/changelog/63278.fixed.md b/changelog/63278.fixed.md deleted file mode 100644 index dbf3c7ae562..00000000000 --- a/changelog/63278.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Made x509_v2 compound match detection use new runner instead of peer publishing diff --git a/changelog/63406.added.md b/changelog/63406.added.md deleted file mode 100644 index 25e0a5341df..00000000000 --- a/changelog/63406.added.md +++ /dev/null @@ -1 +0,0 @@ -Added Vault token lifecycle management diff --git a/changelog/63416.added.md b/changelog/63416.added.md deleted file mode 100644 index a59fb21eef4..00000000000 --- a/changelog/63416.added.md +++ /dev/null @@ -1 +0,0 @@ -adding new call for openscap xccdf eval supporting new parameters diff --git a/changelog/63440.added.md b/changelog/63440.added.md deleted file mode 100644 index a3fdd865d75..00000000000 --- a/changelog/63440.added.md +++ /dev/null @@ -1 +0,0 @@ -Added Vault lease management utility diff --git a/changelog/63442.added.md b/changelog/63442.added.md deleted file mode 100644 index ad81b2f9d51..00000000000 --- a/changelog/63442.added.md +++ /dev/null @@ -1 +0,0 @@ -implement removal of ptf packages in zypper pkg module diff --git a/changelog/63463.added.md b/changelog/63463.added.md deleted file mode 100644 index 0592bf74a7d..00000000000 --- a/changelog/63463.added.md +++ /dev/null @@ -1 +0,0 @@ -add JUnit output for saltcheck diff --git a/changelog/63545.added.md b/changelog/63545.added.md deleted file mode 100644 index c53ef8dda80..00000000000 --- a/changelog/63545.added.md +++ /dev/null @@ -1 +0,0 @@ -Add ability for file.keyvalue to create a file if it doesn't exist diff --git a/changelog/63583.fixed.md b/changelog/63583.fixed.md deleted file mode 100644 index f1b6e325070..00000000000 --- a/changelog/63583.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Need to make sure we update __pillar__ during a pillar refresh to ensure that process_beacons has the updated beacons loaded from pillar. diff --git a/changelog/63708.fixed.md b/changelog/63708.fixed.md deleted file mode 100644 index 3203a0a1c6a..00000000000 --- a/changelog/63708.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Allow all primitive grain types for autosign_grains diff --git a/changelog/63714.fixed.md b/changelog/63714.fixed.md deleted file mode 100644 index 76a603f3f9c..00000000000 --- a/changelog/63714.fixed.md +++ /dev/null @@ -1 +0,0 @@ -This implements the vpc_uuid parameter when creating a droplet. This parameter selects the correct virtual private cloud (private network interface). diff --git a/changelog/63767.fixed.md b/changelog/63767.fixed.md deleted file mode 100644 index 018b01feb18..00000000000 --- a/changelog/63767.fixed.md +++ /dev/null @@ -1 +0,0 @@ -pkg.installed no longer reports failure when installing packages that are installed via the task manager diff --git a/changelog/63779.fixed.md b/changelog/63779.fixed.md deleted file mode 100644 index 08e7fa44f6e..00000000000 --- a/changelog/63779.fixed.md +++ /dev/null @@ -1 +0,0 @@ -mac_xattr.list and mac_xattr.read will replace undecode-able bytes to avoid raising CommandExecutionError. [#63779](https://github.com/saltstack/salt/issues/63779) diff --git a/changelog/63905.added.md b/changelog/63905.added.md deleted file mode 100644 index 6545f2df43d..00000000000 --- a/changelog/63905.added.md +++ /dev/null @@ -1 +0,0 @@ -added cleanup of temporary mountpoint dir for macpackage installed state diff --git a/changelog/63982.fixed.md b/changelog/63982.fixed.md deleted file mode 100644 index 600e9bcb3a2..00000000000 --- a/changelog/63982.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix aptpkg.latest_version performance, reducing number of times to 'shell out' diff --git a/changelog/63985.added.md b/changelog/63985.added.md deleted file mode 100644 index 49b8114d7cb..00000000000 --- a/changelog/63985.added.md +++ /dev/null @@ -1 +0,0 @@ -Add pkg.installed show installable version in test mode diff --git a/changelog/63991.fixed.md b/changelog/63991.fixed.md deleted file mode 100644 index 03cdfb3210d..00000000000 --- a/changelog/63991.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Added option to use a fresh connection for mysql cache diff --git a/changelog/63996.fixed.md b/changelog/63996.fixed.md deleted file mode 100644 index 09f814a5fa4..00000000000 --- a/changelog/63996.fixed.md +++ /dev/null @@ -1 +0,0 @@ -[lxd] Fixed a bug in `container_create` which prevented devices which are not of type `disk` to be correctly created and added to the container when passed via the `devices` parameter. diff --git a/changelog/64096.added.md b/changelog/64096.added.md deleted file mode 100644 index 567ec1287df..00000000000 --- a/changelog/64096.added.md +++ /dev/null @@ -1 +0,0 @@ -Added patch option to Vault SDB driver diff --git a/changelog/64224.deprecated.md b/changelog/64224.deprecated.md deleted file mode 100644 index abbeca28b88..00000000000 --- a/changelog/64224.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate all Proxmox cloud modules diff --git a/changelog/64256.added.md b/changelog/64256.added.md deleted file mode 100644 index fba43a411f5..00000000000 --- a/changelog/64256.added.md +++ /dev/null @@ -1 +0,0 @@ -Added flags to create local users and groups diff --git a/changelog/64260.fixed.md b/changelog/64260.fixed.md deleted file mode 100644 index 6de5c7a72d0..00000000000 --- a/changelog/64260.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Skipped the `isfile` check to greatly increase speed of reading minion keys for systems with a large number of minions on slow file storage diff --git a/changelog/64300.fixed.md b/changelog/64300.fixed.md deleted file mode 100644 index 4418db1d04c..00000000000 --- a/changelog/64300.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix utf8 handling in 'pass' renderer diff --git a/changelog/64305.fixed.md b/changelog/64305.fixed.md deleted file mode 100644 index f2b4c0c5d7d..00000000000 --- a/changelog/64305.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Upgade tornado to 6.3.2 diff --git a/changelog/64322.removed.md b/changelog/64322.removed.md deleted file mode 100644 index fe7916f991f..00000000000 --- a/changelog/64322.removed.md +++ /dev/null @@ -1 +0,0 @@ -Removing Azure-Cloud modules from the code base. diff --git a/changelog/64369.fixed.md b/changelog/64369.fixed.md deleted file mode 100644 index 6c6b1eba5e0..00000000000 --- a/changelog/64369.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Prevent errors due missing 'transactional_update.apply' on SLE Micro and MicroOS. diff --git a/changelog/64379.added.md b/changelog/64379.added.md deleted file mode 100644 index 7e232ad85e0..00000000000 --- a/changelog/64379.added.md +++ /dev/null @@ -1 +0,0 @@ -Added inline specification of trusted CA root certificate for Vault diff --git a/changelog/64417.removed.md b/changelog/64417.removed.md deleted file mode 100644 index db689856f15..00000000000 --- a/changelog/64417.removed.md +++ /dev/null @@ -1 +0,0 @@ -Dropped Python 3.7 support since it's EOL in 27 Jun 2023 diff --git a/changelog/64418.added.md b/changelog/64418.added.md deleted file mode 100644 index b189c0d40f0..00000000000 --- a/changelog/64418.added.md +++ /dev/null @@ -1 +0,0 @@ -Add ability to return False result in test mode of configurable_test_state diff --git a/changelog/64420.fixed.md b/changelog/64420.fixed.md deleted file mode 100644 index d4f2be87d43..00000000000 --- a/changelog/64420.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix 'unable to unmount' failure to return False result instead of None diff --git a/changelog/64450.fixed.md b/changelog/64450.fixed.md deleted file mode 100644 index 86d36e8094c..00000000000 --- a/changelog/64450.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed issue uninstalling duplicate packages in ``win_appx`` execution module diff --git a/changelog/64457.added.md b/changelog/64457.added.md deleted file mode 100644 index b868b65eb7f..00000000000 --- a/changelog/64457.added.md +++ /dev/null @@ -1 +0,0 @@ -Switched Salt's onedir Python version to 3.11 diff --git a/changelog/64457.changed.md b/changelog/64457.changed.md deleted file mode 100644 index 8e3364743f9..00000000000 --- a/changelog/64457.changed.md +++ /dev/null @@ -1,6 +0,0 @@ -Addressed Python 3.11 deprecations: - -* Switch to `FullArgSpec` since Py 3.11 no longer has `ArgSpec`, deprecated since Py 3.0 -* Stopped using the deprecated `cgi` module. -* Stopped using the deprecated `pipes` module -* Stopped using the deprecated `imp` module diff --git a/changelog/64459.removed.md b/changelog/64459.removed.md deleted file mode 100644 index c37eda28fcd..00000000000 --- a/changelog/64459.removed.md +++ /dev/null @@ -1 +0,0 @@ -Remove salt.payload.Serial diff --git a/changelog/64460.removed.md b/changelog/64460.removed.md deleted file mode 100644 index c0465ad335b..00000000000 --- a/changelog/64460.removed.md +++ /dev/null @@ -1 +0,0 @@ -Remove netmiko_conn and pyeapi_conn from salt.modules.napalm_mod diff --git a/changelog/64461.removed.md b/changelog/64461.removed.md deleted file mode 100644 index 1d542f5e533..00000000000 --- a/changelog/64461.removed.md +++ /dev/null @@ -1 +0,0 @@ -Removed 'transport' arg from salt.utils.event.get_event diff --git a/changelog/64462.changed.md b/changelog/64462.changed.md deleted file mode 100644 index 8728b6eb2d8..00000000000 --- a/changelog/64462.changed.md +++ /dev/null @@ -1 +0,0 @@ -changed 'gpg_decrypt_must_succeed' default from False to True diff --git a/changelog/64488.fixed.md b/changelog/64488.fixed.md deleted file mode 100644 index ee4ef7af50d..00000000000 --- a/changelog/64488.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Clean up tech debt, IPC now uses tcp transport. diff --git a/changelog/64517.removed.md b/changelog/64517.removed.md deleted file mode 100644 index 4c7a2b82a67..00000000000 --- a/changelog/64517.removed.md +++ /dev/null @@ -1 +0,0 @@ -Removed the usage of retired Linode API v3 from Salt Cloud diff --git a/changelog/64531.fixed.md b/changelog/64531.fixed.md deleted file mode 100644 index 1e01e69eaae..00000000000 --- a/changelog/64531.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Made salt-ssh more strict when handling unexpected situations and state.* wrappers treat a remote exception as failure, excluded salt-ssh error returns from mine diff --git a/changelog/64532.added.md b/changelog/64532.added.md deleted file mode 100644 index 53595d69280..00000000000 --- a/changelog/64532.added.md +++ /dev/null @@ -1 +0,0 @@ -Added support for dnf5 and its new command syntax diff --git a/changelog/64567.fixed.md b/changelog/64567.fixed.md deleted file mode 100644 index 442d9eda9eb..00000000000 --- a/changelog/64567.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix flaky test for LazyLoader with isolated mocking of threading.RLock diff --git a/changelog/64569.added.md b/changelog/64569.added.md deleted file mode 100644 index 1ee4c96b146..00000000000 --- a/changelog/64569.added.md +++ /dev/null @@ -1 +0,0 @@ -Adding a new decorator to indicate when a module is deprecated in favor of a Salt extension. diff --git a/changelog/64599.fixed.md b/changelog/64599.fixed.md deleted file mode 100644 index 0d03c6b0cf7..00000000000 --- a/changelog/64599.fixed.md +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible `KeyError` exceptions in `salt.utils.user.get_group_dict` -while reading improper duplicated GID assigned for the user. diff --git a/changelog/64600.added.md b/changelog/64600.added.md deleted file mode 100644 index 05707b2bbe6..00000000000 --- a/changelog/64600.added.md +++ /dev/null @@ -1 +0,0 @@ -Add jq-esque to_entries and from_entries functions diff --git a/changelog/64610.fixed.md b/changelog/64610.fixed.md deleted file mode 100644 index de4628940bc..00000000000 --- a/changelog/64610.fixed.md +++ /dev/null @@ -1 +0,0 @@ -changed vm_config() to deep-merge vm_overrides of specific VM, instead of simple-merging the whole vm_overrides diff --git a/changelog/64660.added.md b/changelog/64660.added.md deleted file mode 100644 index 9c2e3db54bd..00000000000 --- a/changelog/64660.added.md +++ /dev/null @@ -1 +0,0 @@ -Added ability to use PYTHONWARNINGS=ignore to silence deprecation warnings. diff --git a/changelog/64665.added.md b/changelog/64665.added.md deleted file mode 100644 index 1f320613efe..00000000000 --- a/changelog/64665.added.md +++ /dev/null @@ -1 +0,0 @@ -Add follow_symlinks to file.symlink exec module to switch to os.path.lexists when False diff --git a/changelog/64893.deprecated.md b/changelog/64893.deprecated.md deleted file mode 100644 index efb81505f9d..00000000000 --- a/changelog/64893.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate all the Vault modules in favor of the Vault Salt Extension https://github.com/salt-extensions/saltext-vault. The Vault modules will be removed in Salt core in 3009.0. diff --git a/changelog/64894.deprecated.md b/changelog/64894.deprecated.md deleted file mode 100644 index 6f8feb46097..00000000000 --- a/changelog/64894.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate all the Docker modules in favor of the Docker Salt Extension https://github.com/saltstack/saltext-docker. The Docker modules will be removed in Salt core in 3009.0. diff --git a/changelog/64896.deprecated.md b/changelog/64896.deprecated.md deleted file mode 100644 index 9164da75e4a..00000000000 --- a/changelog/64896.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate all the Zabbix modules in favor of the Zabbix Salt Extension https://github.com/salt-extensions/saltext-zabbix. The Zabbix modules will be removed in Salt core in 3009.0. diff --git a/changelog/64909.deprecated.md b/changelog/64909.deprecated.md deleted file mode 100644 index 74901b7ac44..00000000000 --- a/changelog/64909.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate all the Apache modules in favor of the Apache Salt Extension https://github.com/salt-extensions/saltext-apache. The Apache modules will be removed in Salt core in 3009.0. diff --git a/changelog/64924.fixed.md b/changelog/64924.fixed.md deleted file mode 100644 index a843345813d..00000000000 --- a/changelog/64924.fixed.md +++ /dev/null @@ -1,7 +0,0 @@ -Fix the way Salt tries to get the Homebrew's prefix - -The first attempt to get the Homebrew's prefix is to look for -the `HOMEBREW_PREFIX` environment variable. If it's not set, then -Salt tries to get the prefix from the `brew` command. However, the -`brew` command can fail. So a last attempt is made to get the -prefix by guessing the installation path. diff --git a/changelog/64934.fixed.md b/changelog/64934.fixed.md deleted file mode 100644 index 601ee1f9132..00000000000 --- a/changelog/64934.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Add missing MySQL Grant SERVICE_CONNECTION_ADMIN to mysql module. diff --git a/changelog/64939.added.md b/changelog/64939.added.md deleted file mode 100644 index 17b9080bb09..00000000000 --- a/changelog/64939.added.md +++ /dev/null @@ -1 +0,0 @@ -Strenghten Salt's HA capabilities with master clustering. diff --git a/changelog/64978.added.md b/changelog/64978.added.md deleted file mode 100644 index 15974414a26..00000000000 --- a/changelog/64978.added.md +++ /dev/null @@ -1 +0,0 @@ -Added win_appx state and execution modules for managing Microsoft Store apps and deprovisioning them from systems diff --git a/changelog/64989.security.md b/changelog/64989.security.md deleted file mode 100644 index 65ec0821e67..00000000000 --- a/changelog/64989.security.md +++ /dev/null @@ -1 +0,0 @@ -Upgrade to `tornado>=6.3.3` due to https://github.com/advisories/GHSA-qppv-j76h-2rpx diff --git a/changelog/65008.added.md b/changelog/65008.added.md deleted file mode 100644 index 2e8b5adec5e..00000000000 --- a/changelog/65008.added.md +++ /dev/null @@ -1,3 +0,0 @@ -Add support for show_jid to salt-run - -Adds support for show_jid master config option to salt-run, so its behaviour matches the salt cli command. diff --git a/changelog/65067.fixed.md b/changelog/65067.fixed.md deleted file mode 100644 index d6de87b5bc1..00000000000 --- a/changelog/65067.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed slsutil.update with salt-ssh during template rendering diff --git a/changelog/65080.fixed.md b/changelog/65080.fixed.md deleted file mode 100644 index 92226b222fa..00000000000 --- a/changelog/65080.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Keep track when an included file only includes sls files but is a requisite. diff --git a/changelog/65137.security.md b/changelog/65137.security.md deleted file mode 100644 index 8d6f57c7d0c..00000000000 --- a/changelog/65137.security.md +++ /dev/null @@ -1 +0,0 @@ -Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c diff --git a/changelog/65169.fixed.md b/changelog/65169.fixed.md deleted file mode 100644 index 8210d1b62d7..00000000000 --- a/changelog/65169.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fixed `gpg.present` succeeds when the keyserver is unreachable diff --git a/changelog/65220.added.md b/changelog/65220.added.md deleted file mode 100644 index 6db0a4c4b0a..00000000000 --- a/changelog/65220.added.md +++ /dev/null @@ -1 +0,0 @@ -Add ability to remove packages by wildcard via apt execution module diff --git a/changelog/65295.fixed.md b/changelog/65295.fixed.md deleted file mode 100644 index c672de05b75..00000000000 --- a/changelog/65295.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix typo in nftables module to ensure unique nft family values diff --git a/changelog/65435.fixed.md b/changelog/65435.fixed.md deleted file mode 100644 index 5fa532891d3..00000000000 --- a/changelog/65435.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Dereference symlinks to set proper __cli opt diff --git a/changelog/65479.added.md b/changelog/65479.added.md deleted file mode 100644 index 037ba183c94..00000000000 --- a/changelog/65479.added.md +++ /dev/null @@ -1 +0,0 @@ -Added support for master top modules on masterless minions diff --git a/changelog/65480.fixed.md b/changelog/65480.fixed.md deleted file mode 100644 index ea30dbc50b7..00000000000 --- a/changelog/65480.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Made salt-ssh merge master top returns for the same environment diff --git a/changelog/65513.fixed.md b/changelog/65513.fixed.md deleted file mode 100644 index ea2b5f43f8a..00000000000 --- a/changelog/65513.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Account for situation where the metadata grain fails because the AWS environment requires an authentication token to query the metadata URL. diff --git a/changelog/65542.deprecated.md b/changelog/65542.deprecated.md deleted file mode 100644 index 13ad306efa9..00000000000 --- a/changelog/65542.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecation warning for Salt's backport of ``OrderedDict`` class which will be removed in 3009 diff --git a/changelog/65562.fixed.md b/changelog/65562.fixed.md deleted file mode 100644 index ba483b4b779..00000000000 --- a/changelog/65562.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Improve the condition of overriding target for pip with VENV_PIP_TARGET environment variable. diff --git a/changelog/65565.deprecated.md b/changelog/65565.deprecated.md deleted file mode 100644 index 95c4b572265..00000000000 --- a/changelog/65565.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecate Kubernetes modules for move to saltext-kubernetes in version 3009 diff --git a/changelog/65567.deprecated.md b/changelog/65567.deprecated.md deleted file mode 100644 index 54069d1cf04..00000000000 --- a/changelog/65567.deprecated.md +++ /dev/null @@ -1 +0,0 @@ -Deprecated all Pushover modules in favor of the Salt Extension at https://github.com/salt-extensions/saltext-pushover. The Pushover modules will be removed from Salt core in 3009.0 diff --git a/changelog/65630.fixed.md b/changelog/65630.fixed.md deleted file mode 100644 index e8650abcdc1..00000000000 --- a/changelog/65630.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Added SSH wrapper for logmod diff --git a/changelog/65645.added.md b/changelog/65645.added.md deleted file mode 100644 index eeddb0f332a..00000000000 --- a/changelog/65645.added.md +++ /dev/null @@ -1 +0,0 @@ -Allowed accessing the regular mine from the SSH wrapper diff --git a/changelog/65652.fixed.md b/changelog/65652.fixed.md deleted file mode 100644 index 2f93147a233..00000000000 --- a/changelog/65652.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Include changes in the results when schedule.present state is run with test=True. diff --git a/changelog/65686.fixed.md b/changelog/65686.fixed.md deleted file mode 100644 index 11dad52ae68..00000000000 --- a/changelog/65686.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Fix extfs.tune doesn't pass retcode to module.run diff --git a/changelog/65697.added.md b/changelog/65697.added.md deleted file mode 100644 index 322289aedc6..00000000000 --- a/changelog/65697.added.md +++ /dev/null @@ -1 +0,0 @@ -Allow enabling backup for Linode in Salt Cloud diff --git a/changelog/65713.added.md b/changelog/65713.added.md deleted file mode 100644 index 19f4b190f1a..00000000000 --- a/changelog/65713.added.md +++ /dev/null @@ -1 +0,0 @@ -Add a backup schedule setter fFunction for Linode VMs diff --git a/changelog/65739.fixed.md b/changelog/65739.fixed.md deleted file mode 100644 index 23eaea55c0f..00000000000 --- a/changelog/65739.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Return an error message when the DNS plugin is not supported diff --git a/changelog/65744.added.md b/changelog/65744.added.md deleted file mode 100644 index 1d751e475ce..00000000000 --- a/changelog/65744.added.md +++ /dev/null @@ -1 +0,0 @@ -Add acme support for manual plugin hooks diff --git a/changelog/65986.deprecated.md b/changelog/65986.deprecated.md deleted file mode 100644 index 582631a4100..00000000000 --- a/changelog/65986.deprecated.md +++ /dev/null @@ -1,8 +0,0 @@ -Removed deprecated code: - -* All of ``salt/log/`` which has been on a deprecation path for a long time. -* Some of the logging handlers found in ``salt/_logging/handlers`` have been removed since the standard library provides - them. -* Removed the deprecated ``salt/modules/cassandra_mod.py`` module and any tests for it. -* Removed the deprecated ``salt/returners/cassandra_return.py`` module and any tests for it. -* Removed the deprecated ``salt/returners/django_return.py`` module and any tests for it. diff --git a/changelog/66124.fixed.md b/changelog/66124.fixed.md deleted file mode 100644 index 2721fed62b3..00000000000 --- a/changelog/66124.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Execution modules have access to regular fileclient durring pillar rendering. diff --git a/changelog/66126.fixed.md b/changelog/66126.fixed.md deleted file mode 100644 index 9879189e644..00000000000 --- a/changelog/66126.fixed.md +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a issue with server channel where a minion's public key -would be rejected if it contained a final newline character. diff --git a/doc/man/salt-api.1 b/doc/man/salt-api.1 index f82b64a4acf..e1b6eaf98f6 100644 --- a/doc/man/salt-api.1 +++ b/doc/man/salt-api.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-API" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-API" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-api \- salt-api Command .sp diff --git a/doc/man/salt-call.1 b/doc/man/salt-call.1 index 01a8c6c5900..c5db295fe31 100644 --- a/doc/man/salt-call.1 +++ b/doc/man/salt-call.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-CALL" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-CALL" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-call \- salt-call Documentation .SH SYNOPSIS diff --git a/doc/man/salt-cloud.1 b/doc/man/salt-cloud.1 index e2c57db40fc..b9f7d287b03 100644 --- a/doc/man/salt-cloud.1 +++ b/doc/man/salt-cloud.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-CLOUD" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-CLOUD" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-cloud \- Salt Cloud Command .sp diff --git a/doc/man/salt-cp.1 b/doc/man/salt-cp.1 index bbd76b69121..4bbcd759a77 100644 --- a/doc/man/salt-cp.1 +++ b/doc/man/salt-cp.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-CP" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-CP" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-cp \- salt-cp Documentation .sp diff --git a/doc/man/salt-key.1 b/doc/man/salt-key.1 index c6de3044097..9287e07fa3c 100644 --- a/doc/man/salt-key.1 +++ b/doc/man/salt-key.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-KEY" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-KEY" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-key \- salt-key Documentation .SH SYNOPSIS diff --git a/doc/man/salt-master.1 b/doc/man/salt-master.1 index e7c04e2c15f..f645cd60541 100644 --- a/doc/man/salt-master.1 +++ b/doc/man/salt-master.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-MASTER" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-MASTER" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-master \- salt-master Documentation .sp diff --git a/doc/man/salt-minion.1 b/doc/man/salt-minion.1 index 70e2f1879c7..d3741f30dd3 100644 --- a/doc/man/salt-minion.1 +++ b/doc/man/salt-minion.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-MINION" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-MINION" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-minion \- salt-minion Documentation .sp diff --git a/doc/man/salt-proxy.1 b/doc/man/salt-proxy.1 index 93bdd1f6fae..d8e782ecc34 100644 --- a/doc/man/salt-proxy.1 +++ b/doc/man/salt-proxy.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-PROXY" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-PROXY" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-proxy \- salt-proxy Documentation .sp diff --git a/doc/man/salt-run.1 b/doc/man/salt-run.1 index 5231095e460..f786144b903 100644 --- a/doc/man/salt-run.1 +++ b/doc/man/salt-run.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-RUN" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-RUN" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-run \- salt-run Documentation .sp diff --git a/doc/man/salt-ssh.1 b/doc/man/salt-ssh.1 index 1835a0ba620..190a94b33ee 100644 --- a/doc/man/salt-ssh.1 +++ b/doc/man/salt-ssh.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-SSH" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-SSH" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-ssh \- salt-ssh Documentation .SH SYNOPSIS diff --git a/doc/man/salt-syndic.1 b/doc/man/salt-syndic.1 index 652fbeb0c94..5606f6698c0 100644 --- a/doc/man/salt-syndic.1 +++ b/doc/man/salt-syndic.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT-SYNDIC" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT-SYNDIC" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt-syndic \- salt-syndic Documentation .sp diff --git a/doc/man/salt.1 b/doc/man/salt.1 index 5faa32466d7..2f31d337ee0 100644 --- a/doc/man/salt.1 +++ b/doc/man/salt.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt \- salt .SH SYNOPSIS diff --git a/doc/man/salt.7 b/doc/man/salt.7 index 108bbdf6bf4..51163c375f2 100644 --- a/doc/man/salt.7 +++ b/doc/man/salt.7 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SALT" "7" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SALT" "7" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME salt \- Salt Documentation .SH SALT PROJECT @@ -1693,6 +1693,293 @@ for the current installation instructions. .sp This section explains how to configure user access, view and store job results, secure and troubleshoot, and how to perform many other administrative tasks. +.SS Configuring Salt +.sp +Salt configuration is very simple. The default configuration for the +\fI\%master\fP will work for most installations and the only requirement for +setting up a \fI\%minion\fP is to set the location of the master in the minion +configuration file. +.sp +The configuration files will be installed to \fB/etc/salt\fP and are named +after the respective components, \fB/etc/salt/master\fP, and +\fB/etc/salt/minion\fP\&. +.SS Master Configuration +.sp +By default the Salt master listens on ports 4505 and 4506 on all +interfaces (0.0.0.0). To bind Salt to a specific IP, redefine the +\(dqinterface\(dq directive in the master configuration file, typically +\fB/etc/salt/master\fP, as follows: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +\- #interface: 0.0.0.0 ++ interface: 10.0.0.1 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +After updating the configuration file, restart the Salt master. +See the \fI\%master configuration reference\fP +for more details about other configurable options. +.SS Minion Configuration +.sp +Although there are many Salt Minion configuration options, configuring +a Salt Minion is very simple. By default a Salt Minion will +try to connect to the DNS name \(dqsalt\(dq; if the Minion is able to +resolve that name correctly, no configuration is needed. +.sp +If the DNS name \(dqsalt\(dq does not resolve to point to the correct +location of the Master, redefine the \(dqmaster\(dq directive in the minion +configuration file, typically \fB/etc/salt/minion\fP, as follows: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +\- #master: salt ++ master: 10.0.0.1 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +After updating the configuration file, restart the Salt minion. +See the \fI\%minion configuration reference\fP +for more details about other configurable options. +.SS Proxy Minion Configuration +.sp +A proxy minion emulates the behaviour of a regular minion +and inherits their options. +.sp +Similarly, the configuration file is \fB/etc/salt/proxy\fP and the proxy +tries to connect to the DNS name \(dqsalt\(dq. +.sp +In addition to the regular minion options, +there are several proxy\-specific \- see the +\fI\%proxy minion configuration reference\fP\&. +.SS Running Salt +.INDENT 0.0 +.IP 1. 3 +Start the master in the foreground (to daemonize the process, pass the +\fI\%\-d flag\fP): +.INDENT 3.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-master +.ft P +.fi +.UNINDENT +.UNINDENT +.IP 2. 3 +Start the minion in the foreground (to daemonize the process, pass the +\fI\%\-d flag\fP): +.INDENT 3.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-minion +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.IP "Having trouble?" +.sp +The simplest way to troubleshoot Salt is to run the master and minion in +the foreground with \fI\%log level\fP set to \fBdebug\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-master \-\-log\-level=debug +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +For information on salt\(aqs logging system please see the \fI\%logging +document\fP\&. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.IP "Run as an unprivileged (non\-root) user" +.sp +To run Salt as another user, set the \fI\%user\fP parameter in the +master config file. +.sp +Additionally, ownership, and permissions need to be set such that the +desired user can read from and write to the following directories (and +their subdirectories, where applicable): +.INDENT 0.0 +.IP \(bu 2 +/etc/salt +.IP \(bu 2 +/var/cache/salt +.IP \(bu 2 +/var/log/salt +.IP \(bu 2 +/var/run/salt +.UNINDENT +.sp +More information about running salt as a non\-privileged user can be found +\fI\%here\fP\&. +.UNINDENT +.UNINDENT +.sp +There is also a full \fI\%troubleshooting guide\fP +available. +.SS Key Identity +.sp +Salt provides commands to validate the identity of your Salt master +and Salt minions before the initial key exchange. Validating key identity helps +avoid inadvertently connecting to the wrong Salt master, and helps prevent +a potential MiTM attack when establishing the initial connection. +.SS Master Key Fingerprint +.sp +Print the master key fingerprint by running the following command on the Salt master: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-key \-F master +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Copy the \fBmaster.pub\fP fingerprint from the \fILocal Keys\fP section, and then set this value +as the \fI\%master_finger\fP in the minion configuration file. Save the configuration +file and then restart the Salt minion. +.SS Minion Key Fingerprint +.sp +Run the following command on each Salt minion to view the minion key fingerprint: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-call \-\-local key.finger +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Compare this value to the value that is displayed when you run the +\fBsalt\-key \-\-finger \fP command on the Salt master. +.SS Key Management +.sp +Salt uses AES encryption for all communication between the Master and +the Minion. This ensures that the commands sent to the Minions cannot +be tampered with, and that communication between Master and Minion is +authenticated through trusted, accepted keys. +.sp +Before commands can be sent to a Minion, its key must be accepted on +the Master. Run the \fBsalt\-key\fP command to list the keys known to +the Salt Master: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[root@master ~]# salt\-key \-L +Unaccepted Keys: +alpha +bravo +charlie +delta +Accepted Keys: +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This example shows that the Salt Master is aware of four Minions, but none of +the keys has been accepted. To accept the keys and allow the Minions to be +controlled by the Master, again use the \fBsalt\-key\fP command: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[root@master ~]# salt\-key \-A +[root@master ~]# salt\-key \-L +Unaccepted Keys: +Accepted Keys: +alpha +bravo +charlie +delta +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The \fBsalt\-key\fP command allows for signing keys individually or in bulk. The +example above, using \fB\-A\fP bulk\-accepts all pending keys. To accept keys +individually use the lowercase of the same option, \fB\-a keyname\fP\&. +.sp +\fBSEE ALSO:\fP +.INDENT 0.0 +.INDENT 3.5 +\fI\%salt\-key manpage\fP +.UNINDENT +.UNINDENT +.SS Sending Commands +.sp +Communication between the Master and a Minion may be verified by running +the \fBtest.version\fP command: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[root@master ~]# salt alpha test.version +alpha: + 2018.3.4 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Communication between the Master and all Minions may be tested in a +similar way: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[root@master ~]# salt \(aq*\(aq test.version +alpha: + 2018.3.4 +bravo: + 2018.3.4 +charlie: + 2018.3.4 +delta: + 2018.3.4 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Each of the Minions should send a \fB2018.3.4\fP response as shown above, +or any other salt version installed. +.SS What\(aqs Next? +.sp +Understanding \fI\%targeting\fP is important. From there, depending +on the way you wish to use Salt, you should also proceed to learn about +\fI\%Remote Execution\fP and \fI\%Configuration Management\fP\&. .SS Configuring the Salt Master .sp The Salt system is amazingly simple and easy to configure, the two components @@ -1816,8 +2103,13 @@ enable_ssh_minions: True \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -Cross\-minion communication is still not possible. The Salt mine and -publish.publish do not work between minion types. +Enabling this does not influence the limitations on cross\-minion communication. +The Salt mine and \fBpublish.publish\fP do not work from regular minions +to SSH minions, the other way around is partly possible since 3007.0 +(during state rendering on the master). +This means you can use the mentioned functions to call out to regular minions +in \fBsls\fP templates and wrapper modules, but state modules +(which are executed on the remote) relying on them still do not work. .UNINDENT .UNINDENT .SS \fBret_port\fP @@ -1913,6 +2205,62 @@ pki_dir: /etc/salt/pki/master .fi .UNINDENT .UNINDENT +.SS \fBcluster_id\fP +.sp +New in version 3007. + +.sp +When defined, the master will operate in cluster mode. The master will send the +cluster key and id to minions instead of its own key and id. The master will +also forward its local event bus to other masters defined by \fBcluster_peers\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +cluster_id: master +.ft P +.fi +.UNINDENT +.UNINDENT +.SS \fBcluster_peers\fP +.sp +New in version 3007. + +.sp +When \fBcluster_id\fP is defined, this setting is a list of other master +(hostnames or ips) that will be in the cluster. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +cluster_peers: + \- master2 + \- master3 +.ft P +.fi +.UNINDENT +.UNINDENT +.SS \fBcluster_pki_dir\fP +.sp +New in version 3007. + +.sp +When \fBcluster_id\fP is defined, this sets the location of where this cluster +will store its cluster public and private key as well as any minion keys. This +setting will default to the value of \fBpki_dir\fP, but should be changed +to the filesystem location shared between peers in the cluster. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +cluster_pki: /my/gluster/share/pki +.ft P +.fi +.UNINDENT +.UNINDENT .SS \fBextension_modules\fP .sp Changed in version 2016.3.0: The default location for this directory has been moved. Prior to this @@ -6352,31 +6700,6 @@ minionfs_update_interval: 120 .fi .UNINDENT .UNINDENT -.SS azurefs: Azure File Server Backend -.sp -New in version 2015.8.0. - -.sp -See the \fI\%azurefs documentation\fP for usage -examples. -.SS \fBazurefs_update_interval\fP -.sp -New in version 2018.3.0. - -.sp -Default: \fB60\fP -.sp -This option defines the update interval (in seconds) for azurefs. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -azurefs_update_interval: 120 -.ft P -.fi -.UNINDENT -.UNINDENT .SS s3fs: S3 File Server Backend .sp New in version 0.16.0. @@ -7893,9 +8216,9 @@ and pkg modules. .nf .ft C peer: - foo.example.com: - \- test.* - \- pkg.* + foo\e.example\e.com: + \- test\e..* + \- pkg\e..* .ft P .fi .UNINDENT @@ -7918,22 +8241,34 @@ peer: This is not recommended, since it would allow anyone who gets root on any single minion to instantly have root on all of the minions! .sp -By adding an additional layer you can limit the target hosts in addition to the -accessible commands: +It is also possible to limit target hosts with the \fI\%Compound Matcher\fP\&. +You can achieve this by adding another layer in between the source and the +allowed functions: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C peer: - foo.example.com: - \(aqdb*\(aq: - \- test.* - \- pkg.* + \(aq.*\e.example\e.com\(aq: + \- \(aqG@role:db\(aq: + \- test\e..* + \- pkg\e..* .ft P .fi .UNINDENT .UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Notice that the source hosts are matched by a regular expression +on their minion ID, while target hosts can be matched by any of +the \fI\%available matchers\fP\&. +.sp +Note that globbing and regex matching on pillar values is not supported. You can only match exact values. +.UNINDENT +.UNINDENT .SS \fBpeer_run\fP .sp Default: \fB{}\fP @@ -11354,8 +11689,6 @@ pillar .UNINDENT .UNINDENT .SS Top File Settings -.sp -These parameters only have an effect if running a masterless minion. .SS \fBstate_top\fP .sp Default: \fBtop.sls\fP @@ -17915,7 +18248,7 @@ peer: .UNINDENT .UNINDENT .sp -This configuration will allow minions with IDs ending in example.com access +This configuration allows minions with IDs ending in \fB\&.example.com\fP access to the test, ps, and pkg module functions. .INDENT 0.0 .INDENT 3.5 @@ -17923,10 +18256,10 @@ to the test, ps, and pkg module functions. .nf .ft C peer: - .*example.com: - \- test.* - \- ps.* - \- pkg.* + .*\e.example.com: + \- test\e..* + \- ps\e..* + \- pkg\e..* .ft P .fi .UNINDENT @@ -17942,14 +18275,14 @@ allow minions ending with foo.org access to the publisher. .nf .ft C peer: - .*example.com: - \- test.* - \- ps.* - \- pkg.* - .*foo.org: - \- test.* - \- ps.* - \- pkg.* + .*\e.example.com: + \- test\e..* + \- ps\e..* + \- pkg\e..* + .*\e.foo.org: + \- test\e..* + \- ps\e..* + \- pkg\e..* .ft P .fi .UNINDENT @@ -17958,7 +18291,36 @@ peer: \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -Functions are matched using regular expressions. +Functions are matched using regular expressions as well. +.UNINDENT +.UNINDENT +.sp +It is also possible to limit target hosts with the \fI\%Compound Matcher\fP\&. +You can achieve this by adding another layer in between the source and the +allowed functions: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +peer: + \(aq.*\e.example\e.com\(aq: + \- \(aqG@role:db\(aq: + \- test\e..* + \- pkg\e..* +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Notice that the source hosts are matched by a regular expression +on their minion ID, while target hosts can be matched by any of +the \fI\%available matchers\fP\&. +.sp +Note that globbing and regex matching on pillar values is not supported. You can only match exact values. .UNINDENT .UNINDENT .SS Peer Runner Communication @@ -20721,10 +21083,12 @@ first.git: edit/vim.sls edit/vimrc nginx/init.sls + shell/init.sls second.git: edit/dev_vimrc haproxy/init.sls + shell.sls third: haproxy/haproxy.conf @@ -20748,6 +21112,14 @@ A request for the file \fBsalt://haproxy/haproxy.conf\fP will be served from the \fBfile:///root/third\fP repo. .UNINDENT .sp +Also a requested state file overrules a directory with an \fIinit.sls\fP\-file. +For example: +.INDENT 0.0 +.IP \(bu 2 +A request for \fBstate.apply shell\fP will be served from the +\fBhttps://github.com/example/second.git\fP git repo. +.UNINDENT +.sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 @@ -23364,6 +23736,46 @@ salt\-call sdb.get sdb://kevinopenstack/password .UNINDENT .UNINDENT .sp +For SDB sub\-keys, ie users[\(aquser1\(aq][\(aqid\(aq] +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +users: + user1: + id: 12345 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To get SDB sub\-keys from the CLI, use a colon to separate sub key values. For example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-call sdb.get sdb://users:user1:id +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To get SDB sub\-keys in a state file, use this syntax: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +users: + user1: + id: sdb.get sdb://users:user1:id +.ft P +.fi +.UNINDENT +.UNINDENT +.sp \fBWARNING:\fP .INDENT 0.0 .INDENT 3.5 @@ -24153,6 +24565,10 @@ use the same transport. We\(aqre investigating a report of an error when using mixed transport types at very heavy loads. .UNINDENT .UNINDENT +.SS TLS Support +.sp +The TLS transport supports full encryption and verification using both server +and client certificates. See \fI\%Transport TLS Support\fP for more details. .SS Wire Protocol .sp This implementation over TCP focuses on flexibility over absolute efficiency. @@ -24176,62 +24592,6 @@ Head contains header information (such as \(dqmessage id\(dq). The Body contains actual message that we are sending. With this flexible wire protocol we can implement any message semantics that we\(aqd like\-\- including multiplexed message passing on a single socket. -.SS TLS Support -.sp -New in version 2016.11.1. - -.sp -The TCP transport allows for the master/minion communication to be optionally -wrapped in a TLS connection. Enabling this is simple, the master and minion need -to be using the tcp connection, then the \fIssl\fP option is enabled. The \fIssl\fP -option is passed as a dict and corresponds to the options passed to the -Python \fI\%ssl.wrap_socket\fP -function. -.sp -A simple setup looks like this, on the Salt Master add the \fIssl\fP option to the -master configuration file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -ssl: - keyfile: - certfile: - ssl_version: PROTOCOL_TLSv1_2 - ciphers: ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The minimal \fIssl\fP option in the minion configuration file looks like this: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -ssl: True -# Versions below 2016.11.4: -ssl: {} -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Specific options can be sent to the minion also, as defined in the Python -\fIssl.wrap_socket\fP function. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -While setting the ssl_version is not required, we recommend it. Some older -versions of python do not support the latest TLS protocol and if this is -the case for your version of python we strongly recommend upgrading your -version of Python. Ciphers specification might be omitted, but strongly -recommended as otherwise all available ciphers will be enabled. -.UNINDENT -.UNINDENT .SS Crypto .sp The current implementation uses the same crypto as the \fBzeromq\fP transport. @@ -24259,6 +24619,118 @@ Salt CLI defaults to \fBglob\fP targeting type, so in order to target specific m .sp For the request server and client we send messages with a \(dqmessage id\(dq. This \(dqmessage id\(dq allows us to multiplex messages across the socket. +.SS Websocket Transport +.sp +The Websocket transport is an implementation of Salt\(aqs transport using the websocket protocol. +The Websocket transport is enabled by changing the \fI\%transport\fP setting +to \fBws\fP on each Salt minion and Salt master. +.SS TLS Support +.sp +The Websocket transport supports full encryption and verification using both server +and client certificates. See \fI\%Transport TLS Support\fP for more details. +.SS Publish Server and Client +.sp +The publish server and client are implemented using aiohttp. +.SS Request Server and Client +.sp +The request server and client are implemented using aiohttp. +.SS Transport TLS Support +.sp +Whenever possible transports should provide TLS Support. Currently the \fI\%TCP Transport\fP and +\fI\%Websocket Transport\fP transports support encryption and verification using TLS. +.sp +New in version 2016.11.1. + +.sp +The TCP transport allows for the master/minion communication to be optionally +wrapped in a TLS connection. Enabling this is simple, the master and minion need +to be using the tcp connection, then the \fBssl\fP option is enabled. The \fBssl\fP +option is passed as a dict and roughly corresponds to the options passed to the +Python \fI\%ssl.wrap_socket\fP +function for backwards compatability. +.sp +New in version 3007.0. + +.sp +The \fBssl\fP option accepts \fBverify_locations\fP and \fBverify_flags\fP\&. The +\fBverify_locations\fP option is a list of strings or dictionaries. Strings are +passed as a single argument to the SSL context\(aqs \fBload_verify_locations\fP +method. Dictionary keys are expected to be one of \fBcafile\fP, \fBcapath\fP, +\fBcadata\fP\&. For each corresponding key, the key and value will be passed as a +keyword argument to \fBload_verify_locations\fP\&. The \fBverify_flags\fP option is +a list of string names of verification flags which will be set on the SSL +context. All paths are assumed to be the full path to the file or directory. +.sp +A simple setup looks like this, on the Salt Master add the \fBssl\fP option to the +master configuration file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +ssl: + keyfile: + certfile: +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +A more complex setup looks like this, on the Salt Master add the \fBssl\fP +option to the master\(aqs configuration file. In this example the Salt Master will +require valid client side certificates from Minions by setting \fBcert_reqs\fP to +\fBCERT_REQUIRED\fP\&. The Salt Master will also check a certificate revocation list +if one is provided in \fBverify_locations\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +ssl: + keyfile: + certfile: + cert_reqs: CERT_REQUIRED + verify_locations: + \- + \- capath: + \- cafile: + verify_flags: + \- VERIFY_CRL_CHECK_CHAIN +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The minimal \fIssl\fP option in the minion configuration file looks like this: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +ssl: True +# Versions below 2016.11.4: +ssl: {} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +A Minion can be configured to present a client certificate to the master like this: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +ssl: + keyfile: + certfile: +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Specific options can be sent to the minion also, as defined in the Python +\fIssl.wrap_socket\fP function. .SS Master Tops System .sp In 0.10.4 the \fIexternal_nodes\fP system was upgraded to allow for modular @@ -24267,6 +24739,9 @@ subsystems to be used to generate the top file data for a \fI\%highstate\fP run The old \fIexternal_nodes\fP option has been removed. The master tops system provides a pluggable and extendable replacement for it, allowing for multiple different subsystems to provide top file data. +.sp +Changed in version 3007.0: Masterless minions now support master top modules as well. + .sp Using the new \fImaster_tops\fP option is simple: .INDENT 0.0 @@ -24389,5760 +24864,6 @@ functionality allowing a minion to treat master_tops as the single source of truth, irrespective of the top file. .UNINDENT .UNINDENT -.SS Returners -.sp -By default the return values of the commands sent to the Salt minions are -returned to the Salt master, however anything at all can be done with the results -data. -.sp -By using a Salt returner, results data can be redirected to external data\-stores -for analysis and archival. -.sp -Returners pull their configuration values from the Salt minions. Returners are only -configured once, which is generally at load time. -.sp -The returner interface allows the return data to be sent to any system that -can receive data. This means that return data can be sent to a Redis server, -a MongoDB server, a MySQL server, or any system. -.sp -\fBSEE ALSO:\fP -.INDENT 0.0 -.INDENT 3.5 -\fI\%Full list of builtin returners\fP -.UNINDENT -.UNINDENT -.SS Using Returners -.sp -All Salt commands will return the command data back to the master. Specifying -returners will ensure that the data is _also_ sent to the specified returner -interfaces. -.sp -Specifying what returners to use is done when the command is invoked: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.version \-\-return redis_return -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This command will ensure that the redis_return returner is used. -.sp -It is also possible to specify multiple returners: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.version \-\-return mongo_return,redis_return,cassandra_return -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -In this scenario all three returners will be called and the data from the -test.version command will be sent out to the three named returners. -.SS Writing a Returner -.sp -Returners are Salt modules that allow the redirection of results data to targets other than the Salt Master. -.SS Returners Are Easy To Write! -.sp -Writing a Salt returner is straightforward. -.sp -A returner is a Python module containing at minimum a \fBreturner\fP function. -Other optional functions can be included to add support for -\fI\%master_job_cache\fP, \fI\%Storing Job Results in an External System\fP, and \fI\%Event Returners\fP\&. -.INDENT 0.0 -.TP -.B \fBreturner\fP -The \fBreturner\fP function must accept a single argument. The argument -contains return data from the called minion function. If the minion -function \fBtest.version\fP is called, the value of the argument will be a -dictionary. Run the following command from a Salt master to get a sample -of the dictionary: -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call \-\-local \-\-metadata test.version \-\-out=pprint -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -import redis -import salt.utils.json - - -def returner(ret): - \(dq\(dq\(dq - Return information to a redis server - \(dq\(dq\(dq - # Get a redis connection - serv = redis.Redis(host=\(dqredis\-serv.example.com\(dq, port=6379, db=\(dq0\(dq) - serv.sadd(\(dq%(id)s:jobs\(dq % ret, ret[\(dqjid\(dq]) - serv.set(\(dq%(jid)s:%(id)s\(dq % ret, salt.utils.json.dumps(ret[\(dqreturn\(dq])) - serv.sadd(\(dqjobs\(dq, ret[\(dqjid\(dq]) - serv.sadd(ret[\(dqjid\(dq], ret[\(dqid\(dq]) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The above example of a returner set to send the data to a Redis server -serializes the data as JSON and sets it in redis. -.SS Using Custom Returner Modules -.sp -Place custom returners in a \fB_returners/\fP directory within the -\fI\%file_roots\fP specified by the master config file. -.sp -Custom returners are distributed when any of the following are called: -.INDENT 0.0 -.IP \(bu 2 -\fI\%state.apply\fP -.IP \(bu 2 -\fI\%saltutil.sync_returners\fP -.IP \(bu 2 -\fI\%saltutil.sync_all\fP -.UNINDENT -.sp -Any custom returners which have been synced to a minion that are named the -same as one of Salt\(aqs default set of returners will take the place of the -default returner with the same name. -.SS Naming the Returner -.sp -Note that a returner\(aqs default name is its filename (i.e. \fBfoo.py\fP becomes -returner \fBfoo\fP), but that its name can be overridden by using a -\fI\%__virtual__ function\fP\&. A good example of this can be -found in the \fI\%redis\fP returner, which is named \fBredis_return.py\fP but is -loaded as simply \fBredis\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -try: - import redis - - HAS_REDIS = True -except ImportError: - HAS_REDIS = False - -__virtualname__ = \(dqredis\(dq - - -def __virtual__(): - if not HAS_REDIS: - return False - return __virtualname__ -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Master Job Cache Support -.sp -\fI\%master_job_cache\fP, \fI\%Storing Job Results in an External System\fP, and \fI\%Event Returners\fP\&. -Salt\(aqs \fI\%master_job_cache\fP allows returners to be used as a pluggable -replacement for the \fI\%Default Job Cache\fP\&. In order to do so, a returner -must implement the following functions: -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -The code samples contained in this section were taken from the cassandra_cql -returner. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B \fBprep_jid\fP -Ensures that job ids (jid) don\(aqt collide, unless passed_jid is provided. -.sp -\fBnocache\fP is an optional boolean that indicates if return data -should be cached. \fBpassed_jid\fP is a caller provided jid which should be -returned unconditionally. -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -def prep_jid(nocache, passed_jid=None): # pylint: disable=unused\-argument - \(dq\(dq\(dq - Do any work necessary to prepare a JID, including sending a custom id - \(dq\(dq\(dq - return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid() -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B \fBsave_load\fP -Save job information. The \fBjid\fP is generated by \fBprep_jid\fP and should -be considered a unique identifier for the job. The jid, for example, could -be used as the primary/unique key in a database. The \fBload\fP is what is -returned to a Salt master by a minion. \fBminions\fP is a list of minions -that the job was run against. The following code example stores the load as -a JSON string in the salt.jids table. -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -import salt.utils.json - - -def save_load(jid, load, minions=None): - \(dq\(dq\(dq - Save the load to the specified jid id - \(dq\(dq\(dq - query = \(dq\(dq\(dqINSERT INTO salt.jids ( - jid, load - ) VALUES ( - \(aq{0}\(aq, \(aq{1}\(aq - );\(dq\(dq\(dq.format( - jid, salt.utils.json.dumps(load) - ) - - # cassandra_cql.cql_query may raise a CommandExecutionError - try: - __salt__[\(dqcassandra_cql.cql_query\(dq](query) - except CommandExecutionError: - log.critical(\(dqCould not save load in jids table.\(dq) - raise - except Exception as e: - log.critical(\(dqUnexpected error while inserting into jids: {0}\(dq.format(e)) - raise -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B \fBget_load\fP -must accept a job id (jid) and return the job load stored by \fBsave_load\fP, -or an empty dictionary when not found. -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -def get_load(jid): - \(dq\(dq\(dq - Return the load data that marks a specified jid - \(dq\(dq\(dq - query = \(dq\(dq\(dqSELECT load FROM salt.jids WHERE jid = \(aq{0}\(aq;\(dq\(dq\(dq.format(jid) - - ret = {} - - # cassandra_cql.cql_query may raise a CommandExecutionError - try: - data = __salt__[\(dqcassandra_cql.cql_query\(dq](query) - if data: - load = data[0].get(\(dqload\(dq) - if load: - ret = json.loads(load) - except CommandExecutionError: - log.critical(\(dqCould not get load from jids table.\(dq) - raise - except Exception as e: - log.critical( - \(dq\(dq\(dqUnexpected error while getting load from - jids: {0}\(dq\(dq\(dq.format( - str(e) - ) - ) - raise - - return ret -.ft P -.fi -.UNINDENT -.UNINDENT -.SS External Job Cache Support -.sp -Salt\(aqs \fI\%Storing Job Results in an External System\fP extends the \fI\%master_job_cache\fP\&. External -Job Cache support requires the following functions in addition to what is -required for Master Job Cache support: -.INDENT 0.0 -.TP -.B \fBget_jid\fP -Return a dictionary containing the information (load) returned by each -minion when the specified job id was executed. -.UNINDENT -.sp -Sample: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -{ - \(dqlocal\(dq: { - \(dqmaster_minion\(dq: { - \(dqfun_args\(dq: [], - \(dqjid\(dq: \(dq20150330121011408195\(dq, - \(dqreturn\(dq: \(dq2018.3.4\(dq, - \(dqretcode\(dq: 0, - \(dqsuccess\(dq: true, - \(dqcmd\(dq: \(dq_return\(dq, - \(dq_stamp\(dq: \(dq2015\-03\-30T12:10:12.708663\(dq, - \(dqfun\(dq: \(dqtest.version\(dq, - \(dqid\(dq: \(dqmaster_minion\(dq - } - } -} -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B \fBget_fun\fP -Return a dictionary of minions that called a given Salt function as their -last function call. -.UNINDENT -.sp -Sample: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -{ - \(dqlocal\(dq: { - \(dqminion1\(dq: \(dqtest.version\(dq, - \(dqminion3\(dq: \(dqtest.version\(dq, - \(dqminion2\(dq: \(dqtest.version\(dq - } -} -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B \fBget_jids\fP -Return a list of all job ids. -.UNINDENT -.sp -Sample: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -{ - \(dqlocal\(dq: [ - \(dq20150330121011408195\(dq, - \(dq20150330195922139916\(dq - ] -} -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B \fBget_minions\fP -Returns a list of minions -.UNINDENT -.sp -Sample: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -{ - \(dqlocal\(dq: [ - \(dqminion3\(dq, - \(dqminion2\(dq, - \(dqminion1\(dq, - \(dqmaster_minion\(dq - ] -} -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Please refer to one or more of the existing returners (i.e. mysql, -cassandra_cql) if you need further clarification. -.SS Event Support -.sp -An \fBevent_return\fP function must be added to the returner module to allow -events to be logged from a master via the returner. A list of events are passed -to the function by the master. -.sp -The following example was taken from the MySQL returner. In this example, each -event is inserted into the salt_events table keyed on the event tag. The tag -contains the jid and therefore is guaranteed to be unique. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -import salt.utils.json - - -def event_return(events): - \(dq\(dq\(dq - Return event to mysql server - - Requires that configuration be enabled via \(aqevent_return\(aq - option in master config. - \(dq\(dq\(dq - with _get_serv(events, commit=True) as cur: - for event in events: - tag = event.get(\(dqtag\(dq, \(dq\(dq) - data = event.get(\(dqdata\(dq, \(dq\(dq) - sql = \(dq\(dq\(dqINSERT INTO \(gasalt_events\(ga (\(gatag\(ga, \(gadata\(ga, \(gamaster_id\(ga ) - VALUES (%s, %s, %s)\(dq\(dq\(dq - cur.execute(sql, (tag, salt.utils.json.dumps(data), __opts__[\(dqid\(dq])) -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Testing the Returner -.sp -The \fBreturner\fP, \fBprep_jid\fP, \fBsave_load\fP, \fBget_load\fP, and -\fBevent_return\fP functions can be tested by configuring the -\fI\%master_job_cache\fP and \fI\%Event Returners\fP in the master config -file and submitting a job to \fBtest.version\fP each minion from the master. -.sp -Once you have successfully exercised the Master Job Cache functions, test the -External Job Cache functions using the \fBret\fP execution module. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call ret.get_jids cassandra_cql \-\-output=json -salt\-call ret.get_fun cassandra_cql test.version \-\-output=json -salt\-call ret.get_minions cassandra_cql \-\-output=json -salt\-call ret.get_jid cassandra_cql 20150330121011408195 \-\-output=json -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Event Returners -.sp -For maximum visibility into the history of events across a Salt -infrastructure, all events seen by a salt master may be logged to one or -more returners. -.sp -To enable event logging, set the \fBevent_return\fP configuration option in the -master config to the returner(s) which should be designated as the handler -for event returns. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Not all returners support event returns. Verify a returner has an -\fBevent_return()\fP function before using. -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -On larger installations, many hundreds of events may be generated on a -busy master every second. Be certain to closely monitor the storage of -a given returner as Salt can easily overwhelm an underpowered server -with thousands of returns. -.UNINDENT -.UNINDENT -.SS Full List of Returners -.SS returner modules -.TS -center; -|l|l|. -_ -T{ -\fI\%appoptics_return\fP -T} T{ -Salt returner to return highstate stats to AppOptics Metrics -T} -_ -T{ -\fI\%carbon_return\fP -T} T{ -Take data from salt and \(dqreturn\(dq it into a carbon receiver -T} -_ -T{ -\fI\%cassandra_cql_return\fP -T} T{ -Return data to a cassandra server -T} -_ -T{ -\fI\%cassandra_return\fP -T} T{ -T} -_ -T{ -\fI\%couchbase_return\fP -T} T{ -Simple returner for Couchbase. -T} -_ -T{ -\fI\%couchdb_return\fP -T} T{ -Simple returner for CouchDB. -T} -_ -T{ -\fI\%django_return\fP -T} T{ -Deprecated since version 3006.0. -T} -_ -T{ -\fI\%elasticsearch_return\fP -T} T{ -Return data to an elasticsearch server for indexing. -T} -_ -T{ -\fI\%etcd_return\fP -T} T{ -Return data to an etcd server or cluster -T} -_ -T{ -\fI\%highstate_return\fP -T} T{ -Return the results of a highstate (or any other state function that returns data in a compatible format) via an HTML email or HTML file. -T} -_ -T{ -\fI\%influxdb_return\fP -T} T{ -Return data to an influxdb server. -T} -_ -T{ -\fI\%kafka_return\fP -T} T{ -Return data to a Kafka topic -T} -_ -T{ -\fI\%librato_return\fP -T} T{ -Salt returner to return highstate stats to Librato -T} -_ -T{ -\fI\%local\fP -T} T{ -The local returner is used to test the returner interface, it just prints the return data to the console to verify that it is being passed properly -T} -_ -T{ -\fI\%local_cache\fP -T} T{ -Return data to local job cache -T} -_ -T{ -\fI\%mattermost_returner\fP -T} T{ -Return salt data via mattermost -T} -_ -T{ -\fI\%memcache_return\fP -T} T{ -Return data to a memcache server -T} -_ -T{ -\fI\%mongo_future_return\fP -T} T{ -Return data to a mongodb server -T} -_ -T{ -\fI\%mongo_return\fP -T} T{ -Return data to a mongodb server -T} -_ -T{ -\fI\%multi_returner\fP -T} T{ -Read/Write multiple returners -T} -_ -T{ -\fI\%mysql\fP -T} T{ -Return data to a mysql server -T} -_ -T{ -\fI\%nagios_nrdp_return\fP -T} T{ -Return salt data to Nagios -T} -_ -T{ -\fI\%odbc\fP -T} T{ -Return data to an ODBC compliant server. -T} -_ -T{ -\fI\%pgjsonb\fP -T} T{ -Return data to a PostgreSQL server with json data stored in Pg\(aqs jsonb data type -T} -_ -T{ -\fI\%postgres\fP -T} T{ -Return data to a postgresql server -T} -_ -T{ -\fI\%postgres_local_cache\fP -T} T{ -Use a postgresql server for the master job cache. -T} -_ -T{ -\fI\%pushover_returner\fP -T} T{ -Return salt data via pushover (\fI\%http://www.pushover.net\fP) -T} -_ -T{ -\fI\%rawfile_json\fP -T} T{ -Take data from salt and \(dqreturn\(dq it into a raw file containing the json, with one line per event. -T} -_ -T{ -\fI\%redis_return\fP -T} T{ -Return data to a redis server -T} -_ -T{ -\fI\%sentry_return\fP -T} T{ -Salt returner that reports execution results back to sentry. -T} -_ -T{ -\fI\%slack_returner\fP -T} T{ -Return salt data via slack -T} -_ -T{ -\fI\%slack_webhook_return\fP -T} T{ -Return salt data via Slack using Incoming Webhooks -T} -_ -T{ -\fI\%sms_return\fP -T} T{ -Return data by SMS. -T} -_ -T{ -\fI\%smtp_return\fP -T} T{ -Return salt data via email -T} -_ -T{ -\fI\%splunk\fP -T} T{ -Send json response data to Splunk via the HTTP Event Collector Requires the following config values to be specified in config or pillar: -T} -_ -T{ -\fI\%sqlite3_return\fP -T} T{ -Insert minion return data into a sqlite3 database -T} -_ -T{ -\fI\%syslog_return\fP -T} T{ -Return data to the host operating system\(aqs syslog facility -T} -_ -T{ -\fI\%telegram_return\fP -T} T{ -Return salt data via Telegram. -T} -_ -T{ -\fI\%xmpp_return\fP -T} T{ -Return salt data via xmpp -T} -_ -T{ -\fI\%zabbix_return\fP -T} T{ -Return salt data to Zabbix -T} -_ -.TE -.SS salt.returners.appoptics_return -.sp -Salt returner to return highstate stats to AppOptics Metrics -.sp -To enable this returner the minion will need the AppOptics Metrics -client importable on the Python path and the following -values configured in the minion or master config. -.sp -The AppOptics python client can be found at: -.sp -\fI\%https://github.com/appoptics/python\-appoptics\-metrics\fP -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -appoptics.api_token: abc12345def -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -An example configuration that returns the total number of successes -and failures for your salt highstate runs (the default) would look -like this: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -return: appoptics -appoptics.api_token: -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The returner publishes the following metrics to AppOptics: -.INDENT 0.0 -.IP \(bu 2 -saltstack.failed -.IP \(bu 2 -saltstack.passed -.IP \(bu 2 -saltstack.retcode -.IP \(bu 2 -saltstack.runtime -.IP \(bu 2 -saltstack.total -.UNINDENT -.sp -You can add a tags section to specify which tags should be attached to -all metrics created by the returner. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -appoptics.tags: - host_hostname_alias: - tier: - cluster: -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -If no tags are explicitly configured, then the tag key \fBhost_hostname_alias\fP -will be set, with the minion\(aqs \fBid\fP grain being the value. -.sp -In addition to the requested tags, for a highstate run each of these -will be tagged with the \fBkey:value\fP of \fBstate_type: highstate\fP\&. -.sp -In order to return metrics for \fBstate.sls\fP runs (distinct from highstates), you can -specify a list of state names to the key \fBappoptics.sls_states\fP like so: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -appoptics.sls_states: - \- role_salt_master.netapi - \- role_redis.config - \- role_smarty.dummy -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This will report success and failure counts on runs of the -\fBrole_salt_master.netapi\fP, \fBrole_redis.config\fP, and -\fBrole_smarty.dummy\fP states in addition to highstates. -.sp -This will report the same metrics as above, but for these runs the -metrics will be tagged with \fBstate_type: sls\fP and \fBstate_name\fP set to -the name of the state that was invoked, e.g. \fBrole_salt_master.netapi\fP\&. -.INDENT 0.0 -.TP -.B salt.returners.appoptics_return.returner(ret) -Parse the return data and return metrics to AppOptics. -.sp -For each state that\(aqs provided in the configuration, return tagged metrics for -the result of that state if it\(aqs present. -.UNINDENT -.SS salt.returners.carbon_return -.sp -Take data from salt and \(dqreturn\(dq it into a carbon receiver -.sp -Add the following configuration to the minion configuration file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -carbon.host: -carbon.port: 2003 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Errors when trying to convert data to numbers may be ignored by setting -\fBcarbon.skip_on_error\fP to \fITrue\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -carbon.skip_on_error: True -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -By default, data will be sent to carbon using the plaintext protocol. To use -the pickle protocol, set \fBcarbon.mode\fP to \fBpickle\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -carbon.mode: pickle -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B You can also specify the pattern used for the metric base path (except for virt modules metrics): -carbon.metric_base_pattern: carbon.[minion_id].[module].[function] -.TP -.B These tokens can used : -[module]: salt module -[function]: salt function -[minion_id]: minion id -.TP -.B Default is : -carbon.metric_base_pattern: [module].[function].[minion_id] -.UNINDENT -.sp -Carbon settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -carbon: - host: - port: - skip_on_error: True - mode: (pickle|text) - metric_base_pattern: | [module].[function].[minion_id] -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.carbon: - host: - port: - skip_on_error: True - mode: (pickle|text) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the carbon returner, append \(aq\-\-return carbon\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return carbon -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return carbon \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return carbon \-\-return_kwargs \(aq{\(dqskip_on_error\(dq: False}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.carbon_return.event_return(events) -Return event data to remote carbon server -.sp -Provide a list of events to be stored in carbon -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.carbon_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.carbon_return.returner(ret) -Return data to a remote carbon server using the text metric protocol -.sp -Each metric will look like: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -[module].[function].[minion_id].[metric path [...]].[metric name] -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.returners.cassandra_cql_return -.sp -Return data to a cassandra server -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.TP -.B maintainer -Corin Kochenower<\fI\%ckochenower@saltstack.com\fP> -.TP -.B maturity -new as of 2015.2 -.TP -.B depends -salt.modules.cassandra_cql -.TP -.B depends -DataStax Python Driver for Apache Cassandra -\fI\%https://github.com/datastax/python\-driver\fP -pip install cassandra\-driver -.TP -.B platform -all -.TP -.B configuration -To enable this returner, the minion will need the DataStax Python Driver -for Apache Cassandra ( \fI\%https://github.com/datastax/python\-driver\fP ) -installed and the following values configured in the minion or master -config. The list of cluster IPs must include at least one cassandra node -IP address. No assumption or default will be used for the cluster IPs. -The cluster IPs will be tried in the order listed. The port, username, -and password values shown below will be the assumed defaults if you do -not provide values.: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -cassandra: - cluster: - \- 192.168.50.11 - \- 192.168.50.12 - \- 192.168.50.13 - port: 9042 - username: salt - password: salt -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Use the following cassandra database schema: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -CREATE KEYSPACE IF NOT EXISTS salt - WITH replication = {\(aqclass\(aq: \(aqSimpleStrategy\(aq, \(aqreplication_factor\(aq : 1}; - -CREATE USER IF NOT EXISTS salt WITH PASSWORD \(aqsalt\(aq NOSUPERUSER; - -GRANT ALL ON KEYSPACE salt TO salt; - -USE salt; - -CREATE TABLE IF NOT EXISTS salt.salt_returns ( - jid text, - minion_id text, - fun text, - alter_time timestamp, - full_ret text, - return text, - success boolean, - PRIMARY KEY (jid, minion_id, fun) -) WITH CLUSTERING ORDER BY (minion_id ASC, fun ASC); -CREATE INDEX IF NOT EXISTS salt_returns_minion_id ON salt.salt_returns (minion_id); -CREATE INDEX IF NOT EXISTS salt_returns_fun ON salt.salt_returns (fun); - -CREATE TABLE IF NOT EXISTS salt.jids ( - jid text PRIMARY KEY, - load text -); - -CREATE TABLE IF NOT EXISTS salt.minions ( - minion_id text PRIMARY KEY, - last_fun text -); -CREATE INDEX IF NOT EXISTS minions_last_fun ON salt.minions (last_fun); - -CREATE TABLE IF NOT EXISTS salt.salt_events ( - id timeuuid, - tag text, - alter_time timestamp, - data text, - master_id text, - PRIMARY KEY (id, tag) -) WITH CLUSTERING ORDER BY (tag ASC); -CREATE INDEX tag ON salt.salt_events (tag); -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.sp -Required python modules: cassandra\-driver -.sp -To use the cassandra returner, append \(aq\-\-return cassandra_cql\(aq to the salt command. ex: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return_cql cassandra -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Note: if your Cassandra instance has not been tuned much you may benefit from -altering some timeouts in \fIcassandra.yaml\fP like so: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -# How long the coordinator should wait for read operations to complete -read_request_timeout_in_ms: 5000 -# How long the coordinator should wait for seq or index scans to complete -range_request_timeout_in_ms: 20000 -# How long the coordinator should wait for writes to complete -write_request_timeout_in_ms: 20000 -# How long the coordinator should wait for counter writes to complete -counter_write_request_timeout_in_ms: 10000 -# How long a coordinator should continue to retry a CAS operation -# that contends with other proposals for the same row -cas_contention_timeout_in_ms: 5000 -# How long the coordinator should wait for truncates to complete -# (This can be much longer, because unless auto_snapshot is disabled -# we need to flush first so we can snapshot before removing the data.) -truncate_request_timeout_in_ms: 60000 -# The default timeout for other, miscellaneous operations -request_timeout_in_ms: 20000 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -As always, your mileage may vary and your Cassandra cluster may have different -needs. SaltStack has seen situations where these timeouts can resolve -some stacktraces that appear to come from the Datastax Python driver. -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.event_return(events) -Return event to one of potentially many clustered cassandra nodes -.sp -Requires that configuration be enabled via \(aqevent_return\(aq -option in master config. -.sp -Cassandra does not support an auto\-increment feature due to the -highly inefficient nature of creating a monotonically increasing -number across all nodes in a distributed database. Each event -will be assigned a uuid by the connecting client. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.prep_jid(nocache, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.returner(ret) -Return data to one of potentially many clustered cassandra nodes -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.save_load(jid, load, minions=None) -Save the load to the specified jid id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_cql_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.cassandra_return -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -The \fIcassandra\fP returner is deprecated in favor of the \fIcassandra_cql\fP -returner. -.UNINDENT -.UNINDENT -.sp -Return data to a Cassandra ColumnFamily -.sp -Here\(aqs an example Keyspace / ColumnFamily setup that works with this -returner: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -create keyspace salt; -use salt; -create column family returns - with key_validation_class=\(aqUTF8Type\(aq - and comparator=\(aqUTF8Type\(aq - and default_validation_class=\(aqUTF8Type\(aq; -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Required python modules: pycassa -.INDENT 0.0 -.INDENT 3.5 -To use the cassandra returner, append \(aq\-\-return cassandra\(aq to the salt command. ex: -.INDENT 0.0 -.INDENT 3.5 -salt \(aq*\(aq test.ping \-\-return cassandra -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.cassandra_return.returner(ret) -Return data to a Cassandra ColumnFamily -.UNINDENT -.SS salt.returners.couchbase_return -.sp -Simple returner for Couchbase. Optional configuration -settings are listed below, along with sane defaults. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -couchbase.host: \(aqsalt\(aq -couchbase.port: 8091 -couchbase.bucket: \(aqsalt\(aq -couchbase.ttl: 86400 -couchbase.password: \(aqpassword\(aq -couchbase.skip_verify_views: False -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the couchbase returner, append \(aq\-\-return couchbase\(aq to the salt command. ex: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return couchbase -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return couchbase \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return couchbase \-\-return_kwargs \(aq{\(dqbucket\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -All of the return data will be stored in documents as follows: -.SS JID -.sp -load: load obj -tgt_minions: list of minions targeted -nocache: should we not cache the return data -.SS JID/MINION_ID -.sp -return: return_data -full_ret: full load of job return -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.prep_jid(nocache=False, passed_jid=None) -Return a job id and prepare the job id directory -This is the function responsible for making sure jids don\(aqt collide (unless -its passed a jid) -So do what you have to do to make sure that stays the case -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.returner(load) -Return data to couchbase bucket -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.save_load(jid, clear_load, minion=None) -Save the load to the specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchbase_return.save_minions(jid, minions, syndic_id=None) -Save/update the minion list for a given jid. The syndic_id argument is -included for API compatibility only. -.UNINDENT -.SS salt.returners.couchdb_return -.sp -Simple returner for CouchDB. Optional configuration -settings are listed below, along with sane defaults: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -couchdb.db: \(aqsalt\(aq -couchdb.url: \(aqhttp://salt:5984/\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.couchdb.db: \(aqsalt\(aq -alternative.couchdb.url: \(aqhttp://salt:5984/\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the couchdb returner, append \fB\-\-return couchdb\fP to the salt command. Example: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return couchdb -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \fB\-\-return_config alternative\fP to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return couchdb \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return couchdb \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS On concurrent database access -.sp -As this returner creates a couchdb document with the salt job id as document id -and as only one document with a given id can exist in a given couchdb database, -it is advised for most setups that every minion be configured to write to it own -database (the value of \fBcouchdb.db\fP may be suffixed with the minion id), -otherwise multi\-minion targeting can lead to losing output: -.INDENT 0.0 -.IP \(bu 2 -the first returning minion is able to create a document in the database -.IP \(bu 2 -other minions fail with \fB{\(aqerror\(aq: \(aqHTTP Error 409: Conflict\(aq}\fP -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.ensure_views() -This function makes sure that all the views that should -exist in the design document do exist. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.get_fun(fun) -Return a dict with key being minion and value -being the job details of the last run of function \(aqfun\(aq. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.get_jid(jid) -Get the document with a given JID. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.get_jids() -List all the jobs that we have.. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.get_minions() -Return a list of minion identifiers from a request of the view. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.get_valid_salt_views() -Returns a dict object of views that should be -part of the salt design document. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.returner(ret) -Take in the return and shove it into the couchdb database. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.couchdb_return.set_salt_view() -Helper function that sets the salt design -document. Uses get_valid_salt_views and some hardcoded values. -.UNINDENT -.SS salt.returners.django_return -.sp -Deprecated since version 3006.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This module has been deprecated and will be removed after January 2024. -.UNINDENT -.UNINDENT -.sp -A returner that will inform a Django system that -returns are available using Django\(aqs signal system. -.sp -\fI\%https://docs.djangoproject.com/en/dev/topics/signals/\fP -.sp -It is up to the Django developer to register necessary -handlers with the signals provided by this returner -and process returns as necessary. -.sp -The easiest way to use signals is to import them from -this returner directly and then use a decorator to register -them. -.sp -An example Django module that registers a function called -\(aqreturner_callback\(aq with this module\(aqs \(aqreturner\(aq function: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -import salt.returners.django_return -from django.dispatch import receiver - -@receiver(salt.returners.django_return, sender=returner) -def returner_callback(sender, ret): - print(\(aqI received {0} from {1}\(aq.format(ret, sender)) -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.django_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom ID -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.django_return.returner(ret) -Signal a Django server that a return is available -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.django_return.save_load(jid, load, minions=None) -Save the load to the specified jid -.UNINDENT -.SS salt.returners.elasticsearch_return -.sp -Return data to an elasticsearch server for indexing. -.INDENT 0.0 -.TP -.B maintainer -Jurnell Cockhren <\fI\%jurnell.cockhren@sophicware.com\fP>, Arnold Bechtoldt <\fI\%mail@arnoldbechtoldt.com\fP> -.TP -.B maturity -New -.TP -.B depends -\fI\%elasticsearch\-py\fP -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner the elasticsearch python client must be installed -on the desired minions (all or some subset). -.sp -Please see documentation of \fI\%elasticsearch execution module\fP -for a valid connection configuration. -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -The index that you wish to store documents will be created by Elasticsearch automatically if -doesn\(aqt exist yet. It is highly recommended to create predefined index templates with appropriate mapping(s) -that will be used by Elasticsearch upon index creation. Otherwise you will have problems as described in #20826. -.UNINDENT -.UNINDENT -.sp -To use the returner per salt call: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return elasticsearch -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -In order to have the returner apply to all minions: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -ext_job_cache: elasticsearch -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B Minion configuration: -.INDENT 7.0 -.TP -.B debug_returner_payload\(aq: False -Output the payload being posted to the log file in debug mode -.TP -.B doc_type: \(aqdefault\(aq -Document type to use for normal return messages -.TP -.B functions_blacklist -Optional list of functions that should not be returned to elasticsearch -.TP -.B index_date: False -Use a dated index (e.g. \-2016.11.29) -.TP -.B master_event_index: \(aqsalt\-master\-event\-cache\(aq -Index to use when returning master events -.TP -.B master_event_doc_type: \(aqefault\(aq -Document type to use got master events -.TP -.B master_job_cache_index: \(aqsalt\-master\-job\-cache\(aq -Index to use for master job cache -.TP -.B master_job_cache_doc_type: \(aqdefault\(aq -Document type to use for master job cache -.TP -.B number_of_shards: 1 -Number of shards to use for the indexes -.TP -.B number_of_replicas: 0 -Number of replicas to use for the indexes -.UNINDENT -.sp -NOTE: The following options are valid for \(aqstate.apply\(aq, \(aqstate.sls\(aq and \(aqstate.highstate\(aq functions only. -.INDENT 7.0 -.TP -.B states_count: False -Count the number of states which succeeded or failed and return it in top\-level item called \(aqcounts\(aq. -States reporting None (i.e. changes would be made but it ran in test mode) are counted as successes. -.TP -.B states_order_output: False -Prefix the state UID (e.g. file_|\-yum_configured_|\-/etc/yum.conf_|\-managed) with a zero\-padded version -of the \(aq__run_num__\(aq value to allow for easier sorting. Also store the state function (i.e. file.managed) -into a new key \(aq_func\(aq. Change the index to be \(aq\-ordered\(aq (e.g. salt\-state_apply\-ordered). -.TP -.B states_single_index: False -Store results for state.apply, state.sls and state.highstate in the salt\-state_apply index -(or \-ordered/\-) indexes if enabled -.UNINDENT -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -elasticsearch: - hosts: - \- \(dq10.10.10.10:9200\(dq - \- \(dq10.10.10.11:9200\(dq - \- \(dq10.10.10.12:9200\(dq - index_date: True - number_of_shards: 5 - number_of_replicas: 1 - debug_returner_payload: True - states_count: True - states_order_output: True - states_single_index: True - functions_blacklist: - \- test.ping - \- saltutil.find_job -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.elasticsearch_return.event_return(events) -Return events to Elasticsearch -.sp -Requires that the \fIevent_return\fP configuration be set in master config. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.elasticsearch_return.get_load(jid) -Return the load data that marks a specified jid -.sp -New in version 2015.8.1. - -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.elasticsearch_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.elasticsearch_return.returner(ret) -Process the return from Salt -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.elasticsearch_return.save_load(jid, load, minions=None) -Save the load to the specified jid id -.sp -New in version 2015.8.1. - -.UNINDENT -.SS salt.returners.etcd_return -.sp -Return data to an etcd server or cluster -.INDENT 0.0 -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -python\-etcd or etcd3\-py -.UNINDENT -.UNINDENT -.sp -In order to return to an etcd server, a profile should be created in the master -configuration file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my_etcd_config: - etcd.host: 127.0.0.1 - etcd.port: 2379 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -It is technically possible to configure etcd without using a profile, but this -is not considered to be a best practice, especially when multiple etcd servers -or clusters are available. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.host: 127.0.0.1 -etcd.port: 2379 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -In order to choose whether to use etcd API v2 or v3, you can put the following -configuration option in the same place as your etcd configuration. This option -defaults to true, meaning you will use v2 unless you specify otherwise. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.require_v2: True -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -When using API v3, there are some specific options available to be configured -within your etcd profile. They are defaulted to the following... -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.encode_keys: False -etcd.encode_values: True -etcd.raw_keys: False -etcd.raw_values: False -etcd.unicode_errors: \(dqsurrogateescape\(dq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBetcd.encode_keys\fP indicates whether you want to pre\-encode keys using msgpack before -adding them to etcd. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -If you set \fBetcd.encode_keys\fP to \fBTrue\fP, all recursive functionality will no longer work. -This includes \fBtree\fP and \fBls\fP and all other methods if you set \fBrecurse\fP/\fBrecursive\fP to \fBTrue\fP\&. -This is due to the fact that when encoding with msgpack, keys like \fB/salt\fP and \fB/salt/stack\fP will have -differing byte prefixes, and etcd v3 searches recursively using prefixes. -.UNINDENT -.UNINDENT -.sp -\fBetcd.encode_values\fP indicates whether you want to pre\-encode values using msgpack before -adding them to etcd. This defaults to \fBTrue\fP to avoid data loss on non\-string values wherever possible. -.sp -\fBetcd.raw_keys\fP determines whether you want the raw key or a string returned. -.sp -\fBetcd.raw_values\fP determines whether you want the raw value or a string returned. -.sp -\fBetcd.unicode_errors\fP determines what you policy to follow when there are encoding/decoding errors. -.sp -Additionally, two more options must be specified in the top\-level configuration -in order to use the etcd returner: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.returner: my_etcd_config -etcd.returner_root: /salt/return -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The \fBetcd.returner\fP option specifies which configuration profile to use. The -\fBetcd.returner_root\fP option specifies the path inside etcd to use as the root -of the returner system. -.sp -Once the etcd options are configured, the returner may be used: -.sp -CLI Example: -.INDENT 0.0 -.INDENT 3.5 -salt \(aq*\(aq test.ping \-\-return etcd -.UNINDENT -.UNINDENT -.sp -A username and password can be set: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.username: larry # Optional; requires etcd.password to be set -etcd.password: 123pass # Optional; requires etcd.username to be set -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -You can also set a TTL (time to live) value for the returner: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.ttl: 5 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Authentication with username and password, and ttl, currently requires the -\fBmaster\fP branch of \fBpython\-etcd\fP\&. -.sp -You may also specify different roles for read and write operations. First, -create the profiles as specified above. Then add: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -etcd.returner_read_profile: my_etcd_read -etcd.returner_write_profile: my_etcd_write -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.clean_old_jobs() -Included for API consistency -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.returner(ret) -Return data to an etcd server or cluster -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.save_load(jid, load, minions=None) -Save the load to the specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.etcd_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.highstate_return -.sp -Return the results of a highstate (or any other state function that returns -data in a compatible format) via an HTML email or HTML file. -.sp -New in version 2017.7.0. - -.sp -Similar results can be achieved by using the smtp returner with a custom template, -except an attempt at writing such a template for the complex data structure -returned by highstate function had proven to be a challenge, not to mention -that the smtp module doesn\(aqt support sending HTML mail at the moment. -.sp -The main goal of this returner was to produce an easy to read email similar -to the output of highstate outputter used by the CLI. -.sp -This returner could be very useful during scheduled executions, -but could also be useful for communicating the results of a manual execution. -.sp -Returner configuration is controlled in a standard fashion either via -highstate group or an alternatively named group. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq state.highstate \-\-return highstate -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config config\-name\(aq -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq state.highstate \-\-return highstate \-\-return_config simple -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Here is an example of what the configuration might look like: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -simple.highstate: - report_failures: True - report_changes: True - report_everything: False - failure_function: pillar.items - success_function: pillar.items - report_format: html - report_delivery: smtp - smtp_success_subject: \(aqsuccess minion {id} on host {host}\(aq - smtp_failure_subject: \(aqfailure minion {id} on host {host}\(aq - smtp_server: smtp.example.com - smtp_recipients: saltusers@example.com, devops@example.com - smtp_sender: salt@example.com -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The \fIreport_failures\fP, \fIreport_changes\fP, and \fIreport_everything\fP flags provide -filtering of the results. If you want an email to be sent every time, then -\fIreport_everything\fP is your choice. If you want to be notified only when -changes were successfully made use \fIreport_changes\fP\&. And \fIreport_failures\fP will -generate an email if there were failures. -.sp -The configuration allows you to run a salt module function in case of -success (\fIsuccess_function\fP) or failure (\fIfailure_function\fP). -.sp -Any salt function, including ones defined in the _module folder of your salt -repo, could be used here and its output will be displayed under the \(aqextra\(aq -heading of the email. -.sp -Supported values for \fIreport_format\fP are html, json, and yaml. The latter two -are typically used for debugging purposes, but could be used for applying -a template at some later stage. -.sp -The values for \fIreport_delivery\fP are smtp or file. In case of file delivery -the only other applicable option is \fIfile_output\fP\&. -.sp -In case of smtp delivery, smtp_* options demonstrated by the example above -could be used to customize the email. -.sp -As you might have noticed, the success and failure subjects contain {id} and {host} -values. Any other grain name could be used. As opposed to using -{{grains[\(aqid\(aq]}}, which will be rendered by the master and contain master\(aqs -values at the time of pillar generation, these will contain minion values at -the time of execution. -.INDENT 0.0 -.TP -.B salt.returners.highstate_return.returner(ret) -Check highstate return information and possibly fire off an email -or save a file. -.UNINDENT -.SS salt.returners.influxdb_return -.sp -Return data to an influxdb server. -.sp -New in version 2015.8.0. - -.sp -To enable this returner the minion will need the python client for influxdb -installed and the following values configured in the minion or master -config, these are the defaults: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -influxdb.db: \(aqsalt\(aq -influxdb.user: \(aqsalt\(aq -influxdb.password: \(aqsalt\(aq -influxdb.host: \(aqlocalhost\(aq -influxdb.port: 8086 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.influxdb.db: \(aqsalt\(aq -alternative.influxdb.user: \(aqsalt\(aq -alternative.influxdb.password: \(aqsalt\(aq -alternative.influxdb.host: \(aqlocalhost\(aq -alternative.influxdb.port: 6379 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the influxdb returner, append \(aq\-\-return influxdb\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return influxdb -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return influxdb \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return influxdb \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.returner(ret) -Return data to a influxdb data store -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.save_load(jid, load, minions=None) -Save the load to the specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.influxdb_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.kafka_return -.sp -Return data to a Kafka topic -.INDENT 0.0 -.TP -.B maintainer -Justin Desilets (\fI\%justin.desilets@gmail.com\fP) -.TP -.B maturity -20181119 -.TP -.B depends -confluent\-kafka -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner install confluent\-kafka and enable the following -settings in the minion config: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B returner.kafka.bootstrap: -.INDENT 7.0 -.IP \(bu 2 -\(dqserver1:9092\(dq -.IP \(bu 2 -\(dqserver2:9092\(dq -.IP \(bu 2 -\(dqserver3:9092\(dq -.UNINDENT -.UNINDENT -.sp -returner.kafka.topic: \(aqtopic\(aq -.UNINDENT -.UNINDENT -.sp -To use the kafka returner, append \fI\-\-return kafka\fP to the Salt command, eg; -.INDENT 0.0 -.INDENT 3.5 -salt \(aq*\(aq test.ping \-\-return kafka -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.kafka_return.returner(ret) -Return information to a Kafka server -.UNINDENT -.SS salt.returners.librato_return -.sp -Salt returner to return highstate stats to Librato -.sp -To enable this returner the minion will need the Librato -client importable on the Python path and the following -values configured in the minion or master config. -.sp -The Librato python client can be found at: -\fI\%https://github.com/librato/python\-librato\fP -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -librato.email: example@librato.com -librato.api_token: abc12345def -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This return supports multi\-dimension metrics for Librato. To enable -support for more metrics, the tags JSON object can be modified to include -other tags. -.sp -Adding EC2 Tags example: -If ec2_tags:region were desired within the tags for multi\-dimension. The tags -could be modified to include the ec2 tags. Multiple dimensions are added simply -by adding more tags to the submission. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -pillar_data = __salt__[\(aqpillar.raw\(aq]() -q.add(metric.name, value, tags={\(aqName\(aq: ret[\(aqid\(aq],\(aqRegion\(aq: pillar_data[\(aqec2_tags\(aq][\(aqName\(aq]}) -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.librato_return.returner(ret) -Parse the return data and return metrics to Librato. -.UNINDENT -.SS salt.returners.local -.sp -The local returner is used to test the returner interface, it just prints the -return data to the console to verify that it is being passed properly -.sp -To use the local returner, append \(aq\-\-return local\(aq to the salt command. ex: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return local -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local.event_return(event) -Print event return data to the terminal to verify functionality -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local.returner(ret) -Print the return data to the terminal to verify functionality -.UNINDENT -.SS salt.returners.local_cache -.sp -Return data to local job cache -.INDENT 0.0 -.TP -.B salt.returners.local_cache.clean_old_jobs() -Clean out the old jobs from the job cache -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.get_endtime(jid) -Retrieve the stored endtime for a given job -.sp -Returns False if no endtime is present -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.get_jids() -Return a dict mapping all job ids to job information -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.get_jids_filter(count, filter_find_job=True) -Return a list of all jobs information filtered by the given criteria. -:param int count: show not more than the count of most recent jobs -:param bool filter_find_jobs: filter out \(aqsaltutil.find_job\(aq jobs -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.load_reg() -Load the register from msgpack files -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.prep_jid(nocache=False, passed_jid=None, recurse_count=0) -Return a job id and prepare the job id directory. -.sp -This is the function responsible for making sure jids don\(aqt collide (unless -it is passed a jid). -So do what you have to do to make sure that stays the case -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.returner(load) -Return data to the local job cache -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.save_load(jid, clear_load, minions=None, recurse_count=0) -Save the load to the specified jid -.sp -minions argument is to provide a pre\-computed list of matched minions for -the job, for cases when this function can\(aqt compute that list itself (such -as for salt\-ssh) -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.save_minions(jid, minions, syndic_id=None) -Save/update the serialized list of minions for a given job -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.save_reg(data) -Save the register to msgpack files -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.local_cache.update_endtime(jid, time) -Update (or store) the end time for a given job -.sp -Endtime is stored as a plain text string -.UNINDENT -.SS salt.returners.mattermost_returner -.sp -Return salt data via mattermost -.sp -New in version 2017.7.0. - -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mattermost.hook (required) -mattermost.username (optional) -mattermost.channel (optional) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mattermost.channel -mattermost.hook -mattermost.username -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -mattermost settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mattermost: - channel: RoomName - hook: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - username: user -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the mattermost returner, append \(aq\-\-return mattermost\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mattermost -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(aqkey:\(aq: \(aqvalue\(aq}\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mattermost \-\-return_kwargs \(aq{\(aqchannel\(aq: \(aq#random\(aq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mattermost_returner.event_return(events) -Send the events to a mattermost room. -.INDENT 7.0 -.TP -.B Parameters -\fBevents\fP \-\- List of events -.TP -.B Returns -Boolean if messages were sent successfully. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mattermost_returner.post_message(channel, message, username, api_url, hook) -Send a message to a mattermost room. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBchannel\fP \-\- The room name. -.IP \(bu 2 -\fBmessage\fP \-\- The message to send to the mattermost room. -.IP \(bu 2 -\fBusername\fP \-\- Specify who the message is from. -.IP \(bu 2 -\fBhook\fP \-\- The mattermost hook, if not specified in the configuration. -.UNINDENT -.TP -.B Returns -Boolean if message was sent successfully. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mattermost_returner.returner(ret) -Send an mattermost message with the data -.UNINDENT -.SS salt.returners.memcache_return -.sp -Return data to a memcache server -.sp -To enable this returner the minion will need the python client for memcache -installed and the following values configured in the minion or master -config, these are the defaults. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -memcache.host: \(aqlocalhost\(aq -memcache.port: \(aq11211\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.memcache.host: \(aqlocalhost\(aq -alternative.memcache.port: \(aq11211\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -python2\-memcache uses \(aqlocalhost\(aq and \(aq11211\(aq as syntax on connection. -.sp -To use the memcache returner, append \(aq\-\-return memcache\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return memcache -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return memcache \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return memcache \-\-return_kwargs \(aq{\(dqhost\(dq: \(dqhostname.domain.com\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.returner(ret) -Return data to a memcache data store -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.save_load(jid, load, minions=None) -Save the load to the specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.memcache_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.mongo_future_return -.sp -Return data to a mongodb server -.sp -Required python modules: pymongo -.sp -This returner will send data from the minions to a MongoDB server. MongoDB -server can be configured by using host, port, db, user and password settings -or by connection string URI (for pymongo > 2.3). To configure the settings -for your MongoDB server, add the following lines to the minion config files: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mongo.db: -mongo.host: -mongo.user: -mongo.password: -mongo.port: 27017 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Or single URI: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mongo.uri: URI -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -where uri is in the format: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Example: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mongodb://db1.example.net:27017/mydatabase -mongodb://db1.example.net:27017,db2.example.net:2500/?replicaSet=test -mongodb://db1.example.net:27017,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -More information on URI format can be found in -\fI\%https://docs.mongodb.com/manual/reference/connection\-string/\fP -.sp -You can also ask for indexes creation on the most common used fields, which -should greatly improve performance. Indexes are not created by default. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mongo.indexes: true -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.mongo.db: -alternative.mongo.host: -alternative.mongo.user: -alternative.mongo.password: -alternative.mongo.port: 27017 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Or single URI: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.mongo.uri: URI -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This mongo returner is being developed to replace the default mongodb returner -in the future and should not be considered API stable yet. -.sp -To use the mongo returner, append \(aq\-\-return mongo\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.event_return(events) -Return events to Mongodb server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.get_fun(fun) -Return the most recent jobs that have executed the named function -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.get_jid(jid) -Return the return information associated with a jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.get_jids() -Return a list of job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.get_load(jid) -Return the load associated with a given job id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.returner(ret) -Return data to a mongodb server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.save_load(jid, load, minions=None) -Save the load for a given job id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_future_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.mongo_return -.sp -Return data to a mongodb server -.sp -Required python modules: pymongo -.sp -This returner will send data from the minions to a MongoDB server. To -configure the settings for your MongoDB server, add the following lines -to the minion config files. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mongo.db: -mongo.host: -mongo.user: -mongo.password: -mongo.port: 27017 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.mongo.db: -alternative.mongo.host: -alternative.mongo.user: -alternative.mongo.password: -alternative.mongo.port: 27017 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the mongo returner, append \(aq\-\-return mongo\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo_return -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo_return \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mongo \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_return.get_fun(fun) -Return the most recent jobs that have executed the named function -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_return.get_jid(jid) -Return the return information associated with a jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_return.returner(ret) -Return data to a mongodb server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mongo_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.multi_returner -.sp -Read/Write multiple returners -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.clean_old_jobs() -Clean out the old jobs from all returners (if you have it) -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.get_jid(jid) -Merge the return data from all returners -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.get_jids() -Return all job data from all returners -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.get_load(jid) -Merge the load data from all returners -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.prep_jid(nocache=False, passed_jid=None) -Call both with prep_jid on all returners in multi_returner -.sp -TODO: finish this, what do do when you get different jids from 2 returners... -since our jids are time based, this make this problem hard, because they -aren\(aqt unique, meaning that we have to make sure that no one else got the jid -and if they did we spin to get a new one, which means \(dqlocking\(dq the jid in 2 -returners is non\-trivial -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.returner(load) -Write return to all returners in multi_returner -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.save_load(jid, clear_load, minions=None) -Write load to all returners in multi_returner -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.multi_returner.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.mysql -.sp -Return data to a mysql server -.INDENT 0.0 -.TP -.B maintainer -Dave Boucha <\fI\%dave@saltstack.com\fP>, Seth House <\fI\%shouse@saltstack.com\fP> -.TP -.B maturity -mature -.TP -.B depends -python\-mysqldb -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner, the minion will need the python client for mysql -installed and the following values configured in the minion or master -config. These are the defaults: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mysql.host: \(aqsalt\(aq -mysql.user: \(aqsalt\(aq -mysql.pass: \(aqsalt\(aq -mysql.db: \(aqsalt\(aq -mysql.port: 3306 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -SSL is optional. The defaults are set to None. If you do not want to use SSL, -either exclude these options or set them to None. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -mysql.ssl_ca: None -mysql.ssl_cert: None -mysql.ssl_key: None -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration -with \fIalternative.\fP\&. Any values not found in the alternative configuration will -be pulled from the default location. As stated above, SSL configuration is -optional. The following ssl options are simply for illustration purposes: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.mysql.host: \(aqsalt\(aq -alternative.mysql.user: \(aqsalt\(aq -alternative.mysql.pass: \(aqsalt\(aq -alternative.mysql.db: \(aqsalt\(aq -alternative.mysql.port: 3306 -alternative.mysql.ssl_ca: \(aq/etc/pki/mysql/certs/localhost.pem\(aq -alternative.mysql.ssl_cert: \(aq/etc/pki/mysql/certs/localhost.crt\(aq -alternative.mysql.ssl_key: \(aq/etc/pki/mysql/certs/localhost.key\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Should you wish the returner data to be cleaned out every so often, set -\fIkeep_jobs_seconds\fP to the number of hours for the jobs to live in the -tables. Setting it to \fI0\fP will cause the data to stay in the tables. The -default setting for \fIkeep_jobs_seconds\fP is set to \fI86400\fP\&. -.sp -Should you wish to archive jobs in a different table for later processing, -set \fIarchive_jobs\fP to True. Salt will create 3 archive tables -.INDENT 0.0 -.IP \(bu 2 -\fIjids_archive\fP -.IP \(bu 2 -\fIsalt_returns_archive\fP -.IP \(bu 2 -\fIsalt_events_archive\fP -.UNINDENT -.sp -and move the contents of \fIjids\fP, \fIsalt_returns\fP, and \fIsalt_events\fP that are -more than \fIkeep_jobs_seconds\fP seconds old to these tables. -.sp -Use the following mysql database schema: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -CREATE DATABASE \(gasalt\(ga - DEFAULT CHARACTER SET utf8 - DEFAULT COLLATE utf8_general_ci; - -USE \(gasalt\(ga; - -\-\- -\-\- Table structure for table \(gajids\(ga -\-\- - -DROP TABLE IF EXISTS \(gajids\(ga; -CREATE TABLE \(gajids\(ga ( - \(gajid\(ga varchar(255) NOT NULL, - \(gaload\(ga mediumtext NOT NULL, - UNIQUE KEY \(gajid\(ga (\(gajid\(ga) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -\-\- -\-\- Table structure for table \(gasalt_returns\(ga -\-\- - -DROP TABLE IF EXISTS \(gasalt_returns\(ga; -CREATE TABLE \(gasalt_returns\(ga ( - \(gafun\(ga varchar(50) NOT NULL, - \(gajid\(ga varchar(255) NOT NULL, - \(gareturn\(ga mediumtext NOT NULL, - \(gaid\(ga varchar(255) NOT NULL, - \(gasuccess\(ga varchar(10) NOT NULL, - \(gafull_ret\(ga mediumtext NOT NULL, - \(gaalter_time\(ga TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - KEY \(gaid\(ga (\(gaid\(ga), - KEY \(gajid\(ga (\(gajid\(ga), - KEY \(gafun\(ga (\(gafun\(ga) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -\-\- -\-\- Table structure for table \(gasalt_events\(ga -\-\- - -DROP TABLE IF EXISTS \(gasalt_events\(ga; -CREATE TABLE \(gasalt_events\(ga ( -\(gaid\(ga BIGINT NOT NULL AUTO_INCREMENT, -\(gatag\(ga varchar(255) NOT NULL, -\(gadata\(ga mediumtext NOT NULL, -\(gaalter_time\(ga TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -\(gamaster_id\(ga varchar(255) NOT NULL, -PRIMARY KEY (\(gaid\(ga), -KEY \(gatag\(ga (\(gatag\(ga) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Required python modules: MySQLdb -.sp -To use the mysql returner, append \(aq\-\-return mysql\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mysql -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mysql \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return mysql \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.clean_old_jobs() -Called in the master\(aqs event loop every loop_interval. Archives and/or -deletes the events and job details from the database. -:return: -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.event_return(events) -Return event to mysql server -.sp -Requires that configuration be enabled via \(aqevent_return\(aq -option in master config. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.get_jids_filter(count, filter_find_job=True) -Return a list of all job ids -:param int count: show not more than the count of most recent jobs -:param bool filter_find_jobs: filter out \(aqsaltutil.find_job\(aq jobs -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.returner(ret) -Return data to a mysql server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.save_load(jid, load, minions=None) -Save the load to the specified jid id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.mysql.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.nagios_nrdp_return -.sp -Return salt data to Nagios -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -nagios.url (required) -nagios.token (required) -nagios.service (optional) -nagios.check_type (optional) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -nagios.url -nagios.token -nagios.service -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Nagios settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C - nagios: - url: http://localhost/nrdp - token: r4nd0mt0k3n - service: service\-check - - alternative.nagios: - url: http://localhost/nrdp - token: r4nd0mt0k3n - service: another\-service\-check - -To use the Nagios returner, append \(aq\-\-return nagios\(aq to the salt command. ex: - -\&.. code\-block:: bash - - salt \(aq*\(aq test.ping \-\-return nagios - -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. ex: - - salt \(aq*\(aq test.ping \-\-return nagios \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return nagios \-\-return_kwargs \(aq{\(dqservice\(dq: \(dqservice\-name\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.nagios_nrdp_return.returner(ret) -Send a message to Nagios with the data -.UNINDENT -.SS salt.returners.odbc -.sp -Return data to an ODBC compliant server. This driver was -developed with Microsoft SQL Server in mind, but theoretically -could be used to return data to any compliant ODBC database -as long as there is a working ODBC driver for it on your -minion platform. -.INDENT 0.0 -.TP -.B maintainer -.INDENT 7.0 -.IP C. 3 -.INDENT 3.0 -.IP R. 3 -Oldham (\fI\%cr@saltstack.com\fP) -.UNINDENT -.UNINDENT -.TP -.B maturity -New -.TP -.B depends -unixodbc, pyodbc, freetds (for SQL Server) -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner the minion will need -.sp -On Linux: -.INDENT 0.0 -.INDENT 3.5 -unixodbc (\fI\%http://www.unixodbc.org\fP) -pyodbc (\fIpip install pyodbc\fP) -The FreeTDS ODBC driver for SQL Server (\fI\%http://www.freetds.org\fP) -or another compatible ODBC driver -.UNINDENT -.UNINDENT -.sp -On Windows: -.INDENT 0.0 -.INDENT 3.5 -TBD -.UNINDENT -.UNINDENT -.sp -unixODBC and FreeTDS need to be configured via /etc/odbcinst.ini and -/etc/odbc.ini. -.sp -/etc/odbcinst.ini: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -[TDS] -Description=TDS -Driver=/usr/lib/x86_64\-linux\-gnu/odbc/libtdsodbc.so -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -(Note the above Driver line needs to point to the location of the FreeTDS -shared library. This example is for Ubuntu 14.04.) -.sp -/etc/odbc.ini: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -[TS] -Description = \(dqSalt Returner\(dq -Driver=TDS -Server = -Port = 1433 -Database = salt -Trace = No -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Also you need the following values configured in the minion or master config. -Configure as you see fit: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -returner.odbc.dsn: \(aqTS\(aq -returner.odbc.user: \(aqsalt\(aq -returner.odbc.passwd: \(aqsalt\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.returner.odbc.dsn: \(aqTS\(aq -alternative.returner.odbc.user: \(aqsalt\(aq -alternative.returner.odbc.passwd: \(aqsalt\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Running the following commands against Microsoft SQL Server in the desired -database as the appropriate user should create the database tables -correctly. Replace with equivalent SQL for other ODBC\-compliant servers -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C - \-\- - \-\- Table structure for table \(aqjids\(aq - \-\- - - if OBJECT_ID(\(aqdbo.jids\(aq, \(aqU\(aq) is not null - DROP TABLE dbo.jids - - CREATE TABLE dbo.jids ( - jid varchar(255) PRIMARY KEY, - load varchar(MAX) NOT NULL - ); - - \-\- - \-\- Table structure for table \(aqsalt_returns\(aq - \-\- - IF OBJECT_ID(\(aqdbo.salt_returns\(aq, \(aqU\(aq) IS NOT NULL - DROP TABLE dbo.salt_returns; - - CREATE TABLE dbo.salt_returns ( - added datetime not null default (getdate()), - fun varchar(100) NOT NULL, - jid varchar(255) NOT NULL, - retval varchar(MAX) NOT NULL, - id varchar(255) NOT NULL, - success bit default(0) NOT NULL, - full_ret varchar(MAX) - ); - - CREATE INDEX salt_returns_added on dbo.salt_returns(added); - CREATE INDEX salt_returns_id on dbo.salt_returns(id); - CREATE INDEX salt_returns_jid on dbo.salt_returns(jid); - CREATE INDEX salt_returns_fun on dbo.salt_returns(fun); - -To use this returner, append \(aq\-\-return odbc\(aq to the salt command. - -\&.. code\-block:: bash - - salt \(aq*\(aq status.diskusage \-\-return odbc - -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. - -\&.. versionadded:: 2015.5.0 - -\&.. code\-block:: bash - - salt \(aq*\(aq test.ping \-\-return odbc \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return odbc \-\-return_kwargs \(aq{\(dqdsn\(dq: \(dqdsn\-name\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.returner(ret) -Return data to an odbc server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.save_load(jid, load, minions=None) -Save the load to the specified jid id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.odbc.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.pgjsonb -.sp -Return data to a PostgreSQL server with json data stored in Pg\(aqs jsonb data type -.INDENT 0.0 -.TP -.B maintainer -Dave Boucha <\fI\%dave@saltstack.com\fP>, Seth House <\fI\%shouse@saltstack.com\fP>, C. R. Oldham <\fI\%cr@saltstack.com\fP> -.TP -.B maturity -Stable -.TP -.B depends -python\-psycopg2 -.TP -.B platform -all -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -There are three PostgreSQL returners. Any can function as an external -\fI\%master job cache\fP\&. but each has different -features. SaltStack recommends -\fI\%returners.pgjsonb\fP if you are working with -a version of PostgreSQL that has the appropriate native binary JSON types. -Otherwise, review -\fI\%returners.postgres\fP and -\fI\%returners.postgres_local_cache\fP -to see which module best suits your particular needs. -.UNINDENT -.UNINDENT -.sp -To enable this returner, the minion will need the python client for PostgreSQL -installed and the following values configured in the minion or master -config. These are the defaults: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -returner.pgjsonb.host: \(aqsalt\(aq -returner.pgjsonb.user: \(aqsalt\(aq -returner.pgjsonb.pass: \(aqsalt\(aq -returner.pgjsonb.db: \(aqsalt\(aq -returner.pgjsonb.port: 5432 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -SSL is optional. The defaults are set to None. If you do not want to use SSL, -either exclude these options or set them to None. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -returner.pgjsonb.sslmode: None -returner.pgjsonb.sslcert: None -returner.pgjsonb.sslkey: None -returner.pgjsonb.sslrootcert: None -returner.pgjsonb.sslcrl: None -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -New in version 2017.5.0. - -.sp -Alternative configuration values can be used by prefacing the configuration -with \fIalternative.\fP\&. Any values not found in the alternative configuration will -be pulled from the default location. As stated above, SSL configuration is -optional. The following ssl options are simply for illustration purposes: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.pgjsonb.host: \(aqsalt\(aq -alternative.pgjsonb.user: \(aqsalt\(aq -alternative.pgjsonb.pass: \(aqsalt\(aq -alternative.pgjsonb.db: \(aqsalt\(aq -alternative.pgjsonb.port: 5432 -alternative.pgjsonb.ssl_ca: \(aq/etc/pki/mysql/certs/localhost.pem\(aq -alternative.pgjsonb.ssl_cert: \(aq/etc/pki/mysql/certs/localhost.crt\(aq -alternative.pgjsonb.ssl_key: \(aq/etc/pki/mysql/certs/localhost.key\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Should you wish the returner data to be cleaned out every so often, set -\fBkeep_jobs_seconds\fP to the number of seconds for the jobs to live in the tables. -Setting it to \fB0\fP or leaving it unset will cause the data to stay in the tables. -.sp -Should you wish to archive jobs in a different table for later processing, -set \fBarchive_jobs\fP to True. Salt will create 3 archive tables; -.INDENT 0.0 -.IP \(bu 2 -\fBjids_archive\fP -.IP \(bu 2 -\fBsalt_returns_archive\fP -.IP \(bu 2 -\fBsalt_events_archive\fP -.UNINDENT -.sp -and move the contents of \fBjids\fP, \fBsalt_returns\fP, and \fBsalt_events\fP that are -more than \fBkeep_jobs_seconds\fP seconds old to these tables. -.sp -New in version 2019.2.0. - -.sp -Use the following Pg database schema: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -CREATE DATABASE salt - WITH ENCODING \(aqutf\-8\(aq; - -\-\- -\-\- Table structure for table \(gajids\(ga -\-\- -DROP TABLE IF EXISTS jids; -CREATE TABLE jids ( - jid varchar(255) NOT NULL primary key, - load jsonb NOT NULL -); -CREATE INDEX idx_jids_jsonb on jids - USING gin (load) - WITH (fastupdate=on); - -\-\- -\-\- Table structure for table \(gasalt_returns\(ga -\-\- - -DROP TABLE IF EXISTS salt_returns; -CREATE TABLE salt_returns ( - fun varchar(50) NOT NULL, - jid varchar(255) NOT NULL, - return jsonb NOT NULL, - id varchar(255) NOT NULL, - success varchar(10) NOT NULL, - full_ret jsonb NOT NULL, - alter_time TIMESTAMP WITH TIME ZONE DEFAULT NOW()); - -CREATE INDEX idx_salt_returns_id ON salt_returns (id); -CREATE INDEX idx_salt_returns_jid ON salt_returns (jid); -CREATE INDEX idx_salt_returns_fun ON salt_returns (fun); -CREATE INDEX idx_salt_returns_return ON salt_returns - USING gin (return) with (fastupdate=on); -CREATE INDEX idx_salt_returns_full_ret ON salt_returns - USING gin (full_ret) with (fastupdate=on); - -\-\- -\-\- Table structure for table \(gasalt_events\(ga -\-\- - -DROP TABLE IF EXISTS salt_events; -DROP SEQUENCE IF EXISTS seq_salt_events_id; -CREATE SEQUENCE seq_salt_events_id; -CREATE TABLE salt_events ( - id BIGINT NOT NULL UNIQUE DEFAULT nextval(\(aqseq_salt_events_id\(aq), - tag varchar(255) NOT NULL, - data jsonb NOT NULL, - alter_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - master_id varchar(255) NOT NULL); - -CREATE INDEX idx_salt_events_tag on - salt_events (tag); -CREATE INDEX idx_salt_events_data ON salt_events - USING gin (data) with (fastupdate=on); -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Required python modules: Psycopg2 -.sp -To use this returner, append \(aq\-\-return pgjsonb\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return pgjsonb -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return pgjsonb \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return pgjsonb \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.clean_old_jobs() -Called in the master\(aqs event loop every loop_interval. Archives and/or -deletes the events and job details from the database. -:return: -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.event_return(events) -Return event to Pg server -.sp -Requires that configuration be enabled via \(aqevent_return\(aq -option in master config. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.returner(ret) -Return data to a Pg server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.save_load(jid, load, minions=None) -Save the load to the specified jid id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pgjsonb.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.postgres -.sp -Return data to a postgresql server -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -There are three PostgreSQL returners. Any can function as an external -\fI\%master job cache\fP\&. but each has different -features. SaltStack recommends -\fI\%returners.pgjsonb\fP if you are working with -a version of PostgreSQL that has the appropriate native binary JSON types. -Otherwise, review -\fI\%returners.postgres\fP and -\fI\%returners.postgres_local_cache\fP -to see which module best suits your particular needs. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -None -.TP -.B maturity -New -.TP -.B depends -psycopg2 -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner the minion will need the psycopg2 installed and -the following values configured in the minion or master config: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -returner.postgres.host: \(aqsalt\(aq -returner.postgres.user: \(aqsalt\(aq -returner.postgres.passwd: \(aqsalt\(aq -returner.postgres.db: \(aqsalt\(aq -returner.postgres.port: 5432 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.returner.postgres.host: \(aqsalt\(aq -alternative.returner.postgres.user: \(aqsalt\(aq -alternative.returner.postgres.passwd: \(aqsalt\(aq -alternative.returner.postgres.db: \(aqsalt\(aq -alternative.returner.postgres.port: 5432 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Running the following commands as the postgres user should create the database -correctly: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -psql << EOF -CREATE ROLE salt WITH PASSWORD \(aqsalt\(aq; -CREATE DATABASE salt WITH OWNER salt; -EOF - -psql \-h localhost \-U salt << EOF -\-\- -\-\- Table structure for table \(aqjids\(aq -\-\- - -DROP TABLE IF EXISTS jids; -CREATE TABLE jids ( - jid varchar(20) PRIMARY KEY, - load text NOT NULL -); - -\-\- -\-\- Table structure for table \(aqsalt_returns\(aq -\-\- - -DROP TABLE IF EXISTS salt_returns; -CREATE TABLE salt_returns ( - fun varchar(50) NOT NULL, - jid varchar(255) NOT NULL, - return text NOT NULL, - full_ret text, - id varchar(255) NOT NULL, - success varchar(10) NOT NULL, - alter_time TIMESTAMP WITH TIME ZONE DEFAULT now() -); - -CREATE INDEX idx_salt_returns_id ON salt_returns (id); -CREATE INDEX idx_salt_returns_jid ON salt_returns (jid); -CREATE INDEX idx_salt_returns_fun ON salt_returns (fun); -CREATE INDEX idx_salt_returns_updated ON salt_returns (alter_time); - -\-\- -\-\- Table structure for table \(gasalt_events\(ga -\-\- - -DROP TABLE IF EXISTS salt_events; -DROP SEQUENCE IF EXISTS seq_salt_events_id; -CREATE SEQUENCE seq_salt_events_id; -CREATE TABLE salt_events ( - id BIGINT NOT NULL UNIQUE DEFAULT nextval(\(aqseq_salt_events_id\(aq), - tag varchar(255) NOT NULL, - data text NOT NULL, - alter_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - master_id varchar(255) NOT NULL -); - -CREATE INDEX idx_salt_events_tag on salt_events (tag); - -EOF -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Required python modules: psycopg2 -.sp -To use the postgres returner, append \(aq\-\-return postgres\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return postgres -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return postgres \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return postgres \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.event_return(events) -Return event to Pg server -.sp -Requires that configuration be enabled via \(aqevent_return\(aq -option in master config. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.returner(ret) -Return data to a postgres server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.save_load(jid, load, minions=None) -Save the load to the specified jid id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.postgres_local_cache -.sp -Use a postgresql server for the master job cache. This helps the job cache to -cope with scale. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -There are three PostgreSQL returners. Any can function as an external -\fI\%master job cache\fP\&. but each has different -features. SaltStack recommends -\fI\%returners.pgjsonb\fP if you are working with -a version of PostgreSQL that has the appropriate native binary JSON types. -Otherwise, review -\fI\%returners.postgres\fP and -\fI\%returners.postgres_local_cache\fP -to see which module best suits your particular needs. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -\fI\%gjredelinghuys@gmail.com\fP -.TP -.B maturity -Stable -.TP -.B depends -psycopg2 -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner the minion will need the psycopg2 installed and -the following values configured in the master config: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -master_job_cache: postgres_local_cache -master_job_cache.postgres.host: \(aqsalt\(aq -master_job_cache.postgres.user: \(aqsalt\(aq -master_job_cache.postgres.passwd: \(aqsalt\(aq -master_job_cache.postgres.db: \(aqsalt\(aq -master_job_cache.postgres.port: 5432 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Running the following command as the postgres user should create the database -correctly: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -psql << EOF -CREATE ROLE salt WITH PASSWORD \(aqsalt\(aq; -CREATE DATABASE salt WITH OWNER salt; -EOF -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -In case the postgres database is a remote host, you\(aqll need this command also: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -ALTER ROLE salt WITH LOGIN; -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -and then: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -psql \-h localhost \-U salt << EOF -\-\- -\-\- Table structure for table \(aqjids\(aq -\-\- - -DROP TABLE IF EXISTS jids; -CREATE TABLE jids ( - jid varchar(20) PRIMARY KEY, - started TIMESTAMP WITH TIME ZONE DEFAULT now(), - tgt_type text NOT NULL, - cmd text NOT NULL, - tgt text NOT NULL, - kwargs text NOT NULL, - ret text NOT NULL, - username text NOT NULL, - arg text NOT NULL, - fun text NOT NULL -); - -\-\- -\-\- Table structure for table \(aqsalt_returns\(aq -\-\- -\-\- note that \(aqsuccess\(aq must not have NOT NULL constraint, since -\-\- some functions don\(aqt provide it. - -DROP TABLE IF EXISTS salt_returns; -CREATE TABLE salt_returns ( - added TIMESTAMP WITH TIME ZONE DEFAULT now(), - fun text NOT NULL, - jid varchar(20) NOT NULL, - return text NOT NULL, - id text NOT NULL, - success boolean -); -CREATE INDEX ON salt_returns (added); -CREATE INDEX ON salt_returns (id); -CREATE INDEX ON salt_returns (jid); -CREATE INDEX ON salt_returns (fun); - -DROP TABLE IF EXISTS salt_events; -CREATE TABLE salt_events ( - id SERIAL, - tag text NOT NULL, - data text NOT NULL, - alter_time TIMESTAMP WITH TIME ZONE DEFAULT now(), - master_id text NOT NULL -); -CREATE INDEX ON salt_events (tag); -CREATE INDEX ON salt_events (data); -CREATE INDEX ON salt_events (id); -CREATE INDEX ON salt_events (master_id); -EOF -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Required python modules: psycopg2 -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.clean_old_jobs() -Clean out the old jobs from the job cache -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.event_return(events) -Return event to a postgres server -.sp -Require that configuration be enabled via \(aqevent_return\(aq -option in master config. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.get_jids() -Return a list of all job ids -For master job cache this also formats the output and returns a string -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.prep_jid(nocache=False, passed_jid=None) -Return a job id and prepare the job id directory -This is the function responsible for making sure jids don\(aqt collide -(unless its passed a jid). So do what you have to do to make sure that -stays the case -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.returner(load) -Return data to a postgres server -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.save_load(jid, clear_load, minions=None) -Save the load to the specified jid id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.postgres_local_cache.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.pushover_returner -.sp -Return salt data via pushover (\fI\%http://www.pushover.net\fP) -.sp -New in version 2016.3.0. - -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -pushover.user (required) -pushover.token (required) -pushover.title (optional) -pushover.device (optional) -pushover.priority (optional) -pushover.expire (optional) -pushover.retry (optional) -pushover.profile (optional) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -The \fBuser\fP here is your \fBuser key\fP, \fInot\fP the email address you use to -login to pushover.net. -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.pushover.user -alternative.pushover.token -alternative.pushover.title -alternative.pushover.device -alternative.pushover.priority -alternative.pushover.expire -alternative.pushover.retry -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -PushOver settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C - pushover: - user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - title: Salt Returner - device: phone - priority: \-1 - expire: 3600 - retry: 5 - - alternative.pushover: - user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - title: Salt Returner - device: phone - priority: 1 - expire: 4800 - retry: 2 - - pushover_profile: - pushover.token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - - pushover: - user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - profile: pushover_profile - - alternative.pushover: - user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - profile: pushover_profile - -To use the PushOver returner, append \(aq\-\-return pushover\(aq to the salt command. ex: - -\&.. code\-block:: bash - - salt \(aq*\(aq test.ping \-\-return pushover - -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. ex: - - salt \(aq*\(aq test.ping \-\-return pushover \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return pushover \-\-return_kwargs \(aq{\(dqtitle\(dq: \(dqSalt is awesome!\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.pushover_returner.returner(ret) -Send an PushOver message with the data -.UNINDENT -.SS salt.returners.rawfile_json -.sp -Take data from salt and \(dqreturn\(dq it into a raw file containing the json, with -one line per event. -.sp -Add the following to the minion or master configuration file. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -rawfile_json.filename: -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Default is \fB/var/log/salt/events\fP\&. -.sp -Common use is to log all events on the master. This can generate a lot of -noise, so you may wish to configure batch processing and/or configure the -\fI\%event_return_whitelist\fP or \fI\%event_return_blacklist\fP -to restrict the events that are written. -.INDENT 0.0 -.TP -.B salt.returners.rawfile_json.event_return(events) -Write event data (return data and non\-return data) to file on the master. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.rawfile_json.returner(ret) -Write the return data to a file on the minion. -.UNINDENT -.SS salt.returners.redis_return -.sp -Return data to a redis server -.sp -To enable this returner the minion will need the python client for redis -installed and the following values configured in the minion or master -config, these are the defaults: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -redis.db: \(aq0\(aq -redis.host: \(aqsalt\(aq -redis.port: 6379 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -New in version 2018.3.1: Alternatively a UNIX socket can be specified by \fIunix_socket_path\fP: - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -redis.db: \(aq0\(aq -redis.unix_socket_path: /var/run/redis/redis.sock -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Cluster Mode Example: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -redis.db: \(aq0\(aq -redis.cluster_mode: true -redis.cluster.skip_full_coverage_check: true -redis.cluster.startup_nodes: - \- host: redis\-member\-1 - port: 6379 - \- host: redis\-member\-2 - port: 6379 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.redis.db: \(aq0\(aq -alternative.redis.host: \(aqsalt\(aq -alternative.redis.port: 6379 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the redis returner, append \(aq\-\-return redis\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return redis -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return redis \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return redis \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Redis Cluster Mode Options: -.INDENT 0.0 -.TP -.B cluster_mode: \fBFalse\fP -Whether cluster_mode is enabled or not -.TP -.B cluster.startup_nodes: -A list of host, port dictionaries pointing to cluster members. At least one is required -but multiple nodes are better -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -redis.cluster.startup_nodes - \- host: redis\-member\-1 - port: 6379 - \- host: redis\-member\-2 - port: 6379 -.ft P -.fi -.UNINDENT -.UNINDENT -.TP -.B cluster.skip_full_coverage_check: \fBFalse\fP -Some cluster providers restrict certain redis commands such as CONFIG for enhanced security. -Set this option to true to skip checks that required advanced privileges. -.sp -\fBNOTE:\fP -.INDENT 7.0 -.INDENT 3.5 -Most cloud hosted redis clusters will require this to be set to \fBTrue\fP -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.clean_old_jobs() -Clean out minions\(aqs return data for old jobs. -.sp -Normally, hset \(aqret:\(aq are saved with a TTL, and will eventually -get cleaned by redis.But for jobs with some very late minion return, the -corresponding hset\(aqs TTL will be refreshed to a too late timestamp, we\(aqll -do manually cleaning here. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.get_jid(jid) -Return the information returned when the specified job id was executed -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.get_jids() -Return a dict mapping all job ids to job information -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.get_load(jid) -Return the load data that marks a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.returner(ret) -Return data to a redis data store -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.save_load(jid, load, minions=None) -Save the load to the specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.redis_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.sentry_return -.sp -Salt returner that reports execution results back to sentry. The returner will -inspect the payload to identify errors and flag them as such. -.sp -Pillar needs something like: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -raven: - servers: - \- http://192.168.1.1 - \- https://sentry.example.com - public_key: deadbeefdeadbeefdeadbeefdeadbeef - secret_key: beefdeadbeefdeadbeefdeadbeefdead - project: 1 - tags: - \- os - \- master - \- saltversion - \- cpuarch -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -or using a dsn: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -raven: - dsn: https://aaaa:bbbb@app.getsentry.com/12345 - tags: - \- os - \- master - \- saltversion - \- cpuarch -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fI\%https://pypi.python.org/pypi/raven\fP must be installed. -.sp -The pillar can be hidden on sentry return by setting hide_pillar: true. -.sp -The tags list (optional) specifies grains items that will be used as sentry -tags, allowing tagging of events in the sentry ui. -.sp -To report only errors to sentry, set report_errors_only: true. -.INDENT 0.0 -.TP -.B salt.returners.sentry_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sentry_return.returner(ret) -Log outcome to sentry. The returner tries to identify errors and report -them as such. All other messages will be reported at info level. -Failed states will be appended as separate list for convenience. -.UNINDENT -.SS salt.returners.slack_returner -.sp -Return salt data via slack -.sp -New in version 2015.5.0. - -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -slack.channel (required) -slack.api_key (required) -slack.username (required) -slack.as_user (required to see the profile picture of your bot) -slack.profile (optional) -slack.changes(optional, only show changes and failed states) -slack.only_show_failed(optional, only show failed states) -slack.yaml_format(optional, format the json in yaml format) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -slack.channel -slack.api_key -slack.username -slack.as_user -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Slack settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -slack: - channel: RoomName - api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - username: user - as_user: true - -alternative.slack: - room_id: RoomName - api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - from_name: user@email.com - -slack_profile: - slack.api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - slack.from_name: user@email.com - -slack: - profile: slack_profile - channel: RoomName - -alternative.slack: - profile: slack_profile - channel: RoomName -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the Slack returner, append \(aq\-\-return slack\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return slack -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return slack \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return slack \-\-return_kwargs \(aq{\(dqchannel\(dq: \(dq#random\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.slack_returner.returner(ret) -Send an slack message with the data -.UNINDENT -.SS salt.returners.slack_webhook_return -.sp -Return salt data via Slack using Incoming Webhooks -.INDENT 0.0 -.TP -.B codeauthor -\fICarlos D. Álvaro \fP -.UNINDENT -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -slack_webhook.webhook (required, the webhook id. Just the part after: \(aqhttps://hooks.slack.com/services/\(aq) -slack_webhook.success_title (optional, short title for succeeded states. By default: \(aq{id} | Succeeded\(aq) -slack_webhook.failure_title (optional, short title for failed states. By default: \(aq{id} | Failed\(aq) -slack_webhook.author_icon (optional, a URL that with a small 16x16px image. Must be of type: GIF, JPEG, PNG, and BMP) -slack_webhook.show_tasks (optional, show identifiers for changed and failed tasks. By default: False) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -slack_webhook.webhook -slack_webhook.success_title -slack_webhook.failure_title -slack_webhook.author_icon -slack_webhook.show_tasks -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Slack settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -slack_webhook: - webhook: T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX - success_title: \(aq[{id}] | Success\(aq - failure_title: \(aq[{id}] | Failure\(aq - author_icon: https://platform.slack\-edge.com/img/default_application_icon.png - show_tasks: true - -alternative.slack_webhook: - webhook: T00000000/C00000000/YYYYYYYYYYYYYYYYYYYYYYYY - show_tasks: false -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the Slack returner, -append \(aq\-\-return slack_webhook\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return slack_webhook -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, -append \(aq\-\-return_config alternative\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return slack_webhook \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.slack_webhook_return.event_return(events) -Send event data to returner function -:param events: The Salt event return -:return: The result of the post -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.slack_webhook_return.returner(ret, **kwargs) -Send a slack message with the data through a webhook -:param ret: The Salt return -:return: The result of the post -.UNINDENT -.SS salt.returners.sms_return -.sp -Return data by SMS. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.TP -.B maintainer -Damian Myerscough -.TP -.B maturity -new -.TP -.B depends -twilio -.TP -.B platform -all -.UNINDENT -.sp -To enable this returner the minion will need the python twilio library -installed and the following values configured in the minion or master -config: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -twilio.sid: \(aqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\(aq -twilio.token: \(aqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\(aq -twilio.to: \(aq+1415XXXXXXX\(aq -twilio.from: \(aq+1650XXXXXXX\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the sms returner, append \(aq\-\-return sms\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return sms -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sms_return.returner(ret) -Return a response in an SMS message -.UNINDENT -.SS salt.returners.smtp_return -.sp -Return salt data via email -.sp -The following fields can be set in the minion conf file. Fields are optional -unless noted otherwise. -.INDENT 0.0 -.IP \(bu 2 -\fBfrom\fP (required) The name/address of the email sender. -.IP \(bu 2 -.INDENT 2.0 -.TP -.B \fBto\fP (required) The names/addresses of the email recipients; -comma\-delimited. For example: \fByou@example.com,someoneelse@example.com\fP\&. -.UNINDENT -.IP \(bu 2 -\fBhost\fP (required) The SMTP server hostname or address. -.IP \(bu 2 -\fBport\fP The SMTP server port; defaults to \fB25\fP\&. -.IP \(bu 2 -.INDENT 2.0 -.TP -.B \fBusername\fP The username used to authenticate to the server. If specified a -password is also required. It is recommended but not required to also use -TLS with this option. -.UNINDENT -.IP \(bu 2 -\fBpassword\fP The password used to authenticate to the server. -.IP \(bu 2 -\fBtls\fP Whether to secure the connection using TLS; defaults to \fBFalse\fP -.IP \(bu 2 -\fBsubject\fP The email subject line. -.IP \(bu 2 -.INDENT 2.0 -.TP -.B \fBfields\fP Which fields from the returned data to include in the subject line -of the email; comma\-delimited. For example: \fBid,fun\fP\&. Please note, \fIthe -subject line is not encrypted\fP\&. -.UNINDENT -.IP \(bu 2 -.INDENT 2.0 -.TP -.B \fBgpgowner\fP A user\(aqs \fB~/.gpg\fP directory. This must contain a gpg -public key matching the address the mail is sent to. If left unset, no -encryption will be used. Requires \fBpython\-gnupg\fP to be installed. -.UNINDENT -.IP \(bu 2 -\fBtemplate\fP The path to a file to be used as a template for the email body. -.IP \(bu 2 -.INDENT 2.0 -.TP -.B \fBrenderer\fP A Salt renderer, or render\-pipe, to use to render the email -template. Default \fBjinja\fP\&. -.UNINDENT -.UNINDENT -.sp -Below is an example of the above settings in a Salt Minion configuration file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -smtp.from: me@example.net -smtp.to: you@example.com -smtp.host: localhost -smtp.port: 1025 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location. For example: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.smtp.username: saltdev -alternative.smtp.password: saltdev -alternative.smtp.tls: True -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the SMTP returner, append \(aq\-\-return smtp\(aq to the \fBsalt\fP command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return smtp -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the \fBsalt\fP command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return smtp \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the -\fBsalt\fP command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return smtp \-\-return_kwargs \(aq{\(dqto\(dq: \(dquser@domain.com\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -An easy way to test the SMTP returner is to use the development SMTP server -built into Python. The command below will start a single\-threaded SMTP server -that prints any email it receives to the console. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -python \-m smtpd \-n \-c DebuggingServer localhost:1025 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -New in version 2016.11.0. - -.sp -It is possible to send emails with selected Salt events by configuring \fBevent_return\fP option -for Salt Master. For example: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -event_return: smtp - -event_return_whitelist: - \- salt/key - -smtp.from: me@example.net -smtp.to: you@example.com -smtp.host: localhost -smtp.subject: \(aqSalt Master {{act}}ed key from Minion ID: {{id}}\(aq -smtp.template: /srv/salt/templates/email.j2 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Also you need to create additional file \fB/srv/salt/templates/email.j2\fP with email body template: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -act: {{act}} -id: {{id}} -result: {{result}} -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This configuration enables Salt Master to send an email when accepting or rejecting minions keys. -.INDENT 0.0 -.TP -.B salt.returners.smtp_return.event_return(events) -Return event data via SMTP -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.smtp_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.smtp_return.returner(ret) -Send an email with the data -.UNINDENT -.SS salt.returners.splunk -.sp -Send json response data to Splunk via the HTTP Event Collector -Requires the following config values to be specified in config or pillar: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -splunk_http_forwarder: - token: - indexer: - sourcetype: - index: - verify_ssl: true -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Run a test by using \fBsalt\-call test.ping \-\-return splunk\fP -.sp -Written by Scott Pack (github.com/scottjpack) -.INDENT 0.0 -.TP -.B salt.returners.splunk.event_return(events) -Return events to Splunk via the HTTP Event Collector. -Requires the Splunk HTTP Event Collector running on port 8088. -This is available on Splunk Enterprise version 6.3 or higher. -.UNINDENT -.INDENT 0.0 -.TP -.B class salt.returners.splunk.http_event_collector(token, http_event_server, host=\(aq\(aq, http_event_port=\(aq8088\(aq, http_event_server_ssl=True, max_bytes=100000, verify_ssl=True) -.INDENT 7.0 -.TP -.B sendEvent(payload, eventtime=\(aq\(aq) -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.splunk.returner(ret) -Send a message to Splunk via the HTTP Event Collector. -Requires the Splunk HTTP Event Collector running on port 8088. -This is available on Splunk Enterprise version 6.3 or higher. -.UNINDENT -.SS salt.returners.sqlite3 -.sp -Insert minion return data into a sqlite3 database -.INDENT 0.0 -.TP -.B maintainer -Mickey Malone <\fI\%mickey.malone@gmail.com\fP> -.TP -.B maturity -New -.TP -.B depends -None -.TP -.B platform -All -.UNINDENT -.sp -Sqlite3 is a serverless database that lives in a single file. -In order to use this returner the database file must exist, -have the appropriate schema defined, and be accessible to the -user whom the minion process is running as. This returner -requires the following values configured in the master or -minion config: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -sqlite3.database: /usr/lib/salt/salt.db -sqlite3.timeout: 5.0 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.sqlite3.database: /usr/lib/salt/salt.db -alternative.sqlite3.timeout: 5.0 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Use the commands to create the sqlite3 database and tables: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -sqlite3 /usr/lib/salt/salt.db << EOF -\-\- -\-\- Table structure for table \(aqjids\(aq -\-\- - -CREATE TABLE jids ( - jid TEXT PRIMARY KEY, - load TEXT NOT NULL - ); - -\-\- -\-\- Table structure for table \(aqsalt_returns\(aq -\-\- - -CREATE TABLE salt_returns ( - fun TEXT KEY, - jid TEXT KEY, - id TEXT KEY, - fun_args TEXT, - date TEXT NOT NULL, - full_ret TEXT NOT NULL, - success TEXT NOT NULL - ); -EOF -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the sqlite returner, append \(aq\-\-return sqlite3\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return sqlite3 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return sqlite3 \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return sqlite3 \-\-return_kwargs \(aq{\(dqdb\(dq: \(dq/var/lib/salt/another\-salt.db\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.get_fun(fun) -Return a dict of the last function called for all minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.get_jid(jid) -Return the information returned from a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.get_jids() -Return a list of all job ids -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.get_load(jid) -Return the load from a specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.get_minions() -Return a list of minions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.returner(ret) -Insert minion return data into the sqlite3 database -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.save_load(jid, load, minions=None) -Save the load to the specified jid -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.sqlite3_return.save_minions(jid, minions, syndic_id=None) -Included for API consistency -.UNINDENT -.SS salt.returners.syslog_return -.sp -Return data to the host operating system\(aqs syslog facility -.sp -To use the syslog returner, append \(aq\-\-return syslog\(aq to the -salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return syslog -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -syslog.level (optional, Default: LOG_INFO) -syslog.facility (optional, Default: LOG_USER) -syslog.tag (optional, Default: salt\-minion) -syslog.options (list, optional, Default: []) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Available levels, facilities, and options can be found in the -\fBsyslog\fP docs for your python version. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -The default tag comes from \fBsys.argv[0]\fP which is -usually \(dqsalt\-minion\(dq but could be different based on -the specific environment. -.UNINDENT -.UNINDENT -.sp -Configuration example: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -syslog.level: \(aqLOG_ERR\(aq -syslog.facility: \(aqLOG_DAEMON\(aq -syslog.tag: \(aqmysalt\(aq -syslog.options: - \- LOG_PID -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Of course you can also nest the options: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -syslog: - level: \(aqLOG_ERR\(aq - facility: \(aqLOG_DAEMON\(aq - tag: \(aqmysalt\(aq - options: - \- LOG_PID -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by -prefacing the configuration. Any values not found -in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -alternative.syslog.level: \(aqLOG_WARN\(aq -alternative.syslog.facility: \(aqLOG_NEWS\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append -\fB\-\-return_config alternative\fP to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return syslog \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append -\-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return syslog \-\-return_kwargs \(aq{\(dqlevel\(dq: \(dqLOG_DEBUG\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Syslog server implementations may have limits on the maximum -record size received by the client. This may lead to job -return data being truncated in the syslog server\(aqs logs. For -example, for rsyslog on RHEL\-based systems, the default -maximum record size is approximately 2KB (which return data -can easily exceed). This is configurable in rsyslog.conf via -the $MaxMessageSize config parameter. Please consult your syslog -implmentation\(aqs documentation to determine how to adjust this limit. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.syslog_return.prep_jid(nocache=False, passed_jid=None) -Do any work necessary to prepare a JID, including sending a custom id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.syslog_return.returner(ret) -Return data to the local syslog -.UNINDENT -.SS salt.returners.telegram_return -.sp -Return salt data via Telegram. -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -telegram.chat_id (required) -telegram.token (required) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Telegram settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -telegram: - chat_id: 000000000 - token: 000000000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the Telegram return, append \(aq\-\-return telegram\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return telegram -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.telegram_return.returner(ret) -Send a Telegram message with the data. -.INDENT 7.0 -.TP -.B Parameters -\fBret\fP \-\- The data to be sent. -.TP -.B Returns -Boolean if message was sent successfully. -.UNINDENT -.UNINDENT -.SS salt.returners.xmpp_return -.sp -Return salt data via xmpp -.INDENT 0.0 -.TP -.B depends -sleekxmpp >= 1.3.1 -.UNINDENT -.sp -The following fields can be set in the minion conf file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -xmpp.jid (required) -xmpp.password (required) -xmpp.recipient (required) -xmpp.profile (optional) -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Alternative configuration values can be used by prefacing the configuration. -Any values not found in the alternative configuration will be pulled from -the default location: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -xmpp.jid -xmpp.password -xmpp.recipient -xmpp.profile -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -XMPP settings may also be configured as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -xmpp: - jid: user@xmpp.domain.com/resource - password: password - recipient: user@xmpp.example.com - -alternative.xmpp: - jid: user@xmpp.domain.com/resource - password: password - recipient: someone@xmpp.example.com - -xmpp_profile: - xmpp.jid: user@xmpp.domain.com/resource - xmpp.password: password - -xmpp: - profile: xmpp_profile - recipient: user@xmpp.example.com - -alternative.xmpp: - profile: xmpp_profile - recipient: someone\-else@xmpp.example.com -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the XMPP returner, append \(aq\-\-return xmpp\(aq to the salt command. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return xmpp -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. -.sp -New in version 2015.5.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return xmpp \-\-return_config alternative -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. -.sp -New in version 2016.3.0. - -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return xmpp \-\-return_kwargs \(aq{\(dqrecipient\(dq: \(dqsomeone\-else@xmpp.example.com\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B class salt.returners.xmpp_return.SendMsgBot(jid, password, recipient, msg) -.INDENT 7.0 -.TP -.B start(event) -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.xmpp_return.returner(ret) -Send an xmpp message with the data -.UNINDENT -.SS salt.returners.zabbix_return -.sp -Return salt data to Zabbix -.sp -The following Type: \(dqZabbix trapper\(dq with \(dqType of information\(dq Text items are required: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -Key: salt.trap.info -Key: salt.trap.warning -Key: salt.trap.high -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To use the Zabbix returner, append \(aq\-\-return zabbix\(aq to the salt command. ex: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq test.ping \-\-return zabbix -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.zabbix_return.returner(ret) -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.zabbix_return.save_load(jid, load, minions=None) -Included for API consistency -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.zabbix_return.zabbix_send(key, output) -.UNINDENT -.INDENT 0.0 -.TP -.B salt.returners.zabbix_return.zbx() -.UNINDENT .SS Renderers .sp The Salt state system operates by gathering information from common data types @@ -39495,6 +34216,72 @@ Example 3: [80, 25, 22] .fi .UNINDENT .UNINDENT +.SS \fBto_entries\fP +.sp +New in version 3007.0. + +.sp +A port of the \fBto_entries\fP function from \fBjq\fP\&. This function converts between an object and an array of key\-value +pairs. If \fBto_entries\fP is passed an object, then for each \fBk: v\fP entry in the input, the output array includes +\fB{\(dqkey\(dq: k, \(dqvalue\(dq: v}\fP\&. The \fBfrom_entries\fP function performs the opposite conversion. \fBfrom_entries\fP accepts +\(dqkey\(dq, \(dqKey\(dq, \(dqname\(dq, \(dqName\(dq, \(dqvalue\(dq, and \(dqValue\(dq as keys. +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{{ {\(dqa\(dq: 1, \(dqb\(dq: 2} | to_entries }} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Returns: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[{\(dqkey\(dq:\(dqa\(dq, \(dqvalue\(dq:1}, {\(dqkey\(dq:\(dqb\(dq, \(dqvalue\(dq:2}] +.ft P +.fi +.UNINDENT +.UNINDENT +.SS \fBfrom_entries\fP +.sp +New in version 3007.0. + +.sp +A port of the \fBfrom_entries\fP function from \fBjq\fP\&. This function converts between an array of key\-value pairs and an +object. If \fBfrom_entries\fP is passed an object, then the input is expected to be an array of dictionaries in the format +of \fB{\(dqkey\(dq: k, \(dqvalue\(dq: v}\fP\&. The output will be be key\-value pairs \fBk: v\fP\&. \fBfrom_entries\fP accepts \(dqkey\(dq, \(dqKey\(dq, +\(dqname\(dq, \(dqName\(dq, \(dqvalue\(dq, and \(dqValue\(dq as keys. +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{{ [{\(dqkey\(dq:\(dqa\(dq, \(dqvalue\(dq:1}, {\(dqkey\(dq:\(dqb\(dq, \(dqvalue\(dq:2}] | from_entries }} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Returns: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{\(dqa\(dq: 1, \(dqb\(dq: 2} +.ft P +.fi +.UNINDENT +.UNINDENT .SS \fBto_snake_case\fP .sp New in version 3000. @@ -44893,6 +39680,106 @@ web6: .fi .UNINDENT .UNINDENT +.SS Master Cluster +.sp +A clustered Salt Master has several advantages over Salt\(aqs traditional High +Availability options. First, a master cluster is meant to be served behind a +load balancer. Minions only need to know about the load balancer\(aqs IP address. +Therefore, masters can be added and removed from a cluster without the need to +re\-configure minions. Another major benefit of master clusters over Salt\(aqs +older HA implimentations is that Masters in a cluster share the load of all +jobs. This allows Salt administrators to more easily scale their environments +to handle larger numbers of minions and larger jobs. +.SS Minimum Requirements +.sp +Running a cluster master requires all nodes in the cluster to have a shared +filesystem. The \fIcluster_pki_dir\fP, \fIcache_dir\fP, \fIfile_roots\fP and \fIpillar_roots\fP +must all be on a shared filesystem. Most implementations will also serve the +masters publish and request server ports via a tcp load balancer. All of the +masters in a cluster are assumed to be running on a reliable local area +network. +.sp +Each master in a cluster maintains its own public and private key, and an in +memory aes key. Each cluster peer also has access to the \fIcluster_pki_dir\fP +where a cluster wide public and private key are stored. In addition, the cluster +wide aes key is generated and stored in the \fIcluster_pki_dir\fP\&. Further, +when operating as a cluster, minion keys are stored in the \fIcluster_pki_dir\fP +instead of the master\(aqs \fIpki_dir\fP\&. +.SS Reference Implimentation +.sp +Gluster: \fI\%https://docs.gluster.org/en/main/Quick\-Start\-Guide/Quickstart/\fP +.sp +HAProxy: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +frontend salt\-master\-pub + mode tcp + bind 10.27.5.116:4505 + option tcplog + timeout client 1m + default_backend salt\-master\-pub\-backend + +backend salt\-master\-pub\-backend + mode tcp + option tcplog + #option log\-health\-checks + log global + #balance source + balance roundrobin + timeout connect 10s + timeout server 1m + server rserve1 10.27.12.13:4505 check + server rserve2 10.27.7.126:4505 check + server rserve3 10.27.3.73:4505 check + +frontend salt\-master\-req + mode tcp + bind 10.27.5.116:4506 + option tcplog + timeout client 1m + default_backend salt\-master\-req\-backend + +backend salt\-master\-req\-backend + mode tcp + option tcplog + #option log\-health\-checks + log global + balance roundrobin + #balance source + timeout connect 10s + timeout server 1m + server rserve1 10.27.12.13:4506 check + server rserve2 10.27.7.126:4506 check + server rserve3 10.27.3.73:4506 check +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Master Config: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +id: 10.27.12.13 +cluster_id: master_cluster +cluster_peers: + \- 10.27.7.126 + \- 10.27.3.73 +cluster_pki_dir: /my/gluster/share/pki +cache_dir: /my/gluster/share/cache +file_roots: + \- /my/gluster/share/srv/salt +pillar_roots: + \- /my/gluster/share/srv/pillar +.ft P +.fi +.UNINDENT +.UNINDENT .SS Remote execution tutorial .sp \fBBefore continuing\fP make sure you have a working Salt installation by @@ -46527,8 +41414,8 @@ Many of the most powerful and useful engineering solutions are founded on simple principles. Salt States strive to do just that: K.I.S.S. (Keep It Stupidly Simple) .sp -The core of the Salt State system is the SLS, or \fBS\fPa\fBL\fPt -\fBS\fPtate file. The SLS is a representation of the state in which +The core of the Salt State system is the SLS, or \fBS\fPtructured \fBL\fPayered \fBS\fPtate. +The SLS is a representation of the state in which a system should be in, and is set up to contain this data in a simple format. This is often called configuration management. .sp @@ -48841,7 +43728,7 @@ l_gsoc2014: \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -Welcome to SaltStack! I am excited that you are interested in Salt and +Welcome to Salt Project! I am excited that you are interested in Salt and starting down the path to better infrastructure management. I developed (and am continuing to develop) Salt with the goal of making the best software available to manage computers of almost any kind. I hope you enjoy @@ -48850,9 +43737,7 @@ working with Salt and that the software can solve your real world needs! .IP \(bu 2 Thomas S Hatch .IP \(bu 2 -Salt creator and Chief Developer -.IP \(bu 2 -CTO of SaltStack, Inc. +Salt Project creator and Chief Developer of Salt Project .UNINDENT .UNINDENT .UNINDENT @@ -49948,51 +44833,18 @@ From the minion folder, type .sp .nf .ft C -vagrant init +vagrant init ubuntu/focal64 .ft P .fi .UNINDENT .UNINDENT .sp -This command creates a default Vagrantfile configuration file. This +This command creates a default Vagrantfile configuration file and import focal64 virtualbox image file to configuration, so it could be used. This configuration file will be used to pass configuration parameters to the Salt provisioner in Step 3. -.SS Import Precise64 Ubuntu Box -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -vagrant box add precise64 http://files.vagrantup.com/precise64.box -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -This box is added at the global Vagrant level. You only need to do it -once as each VM will use this same file. -.UNINDENT -.UNINDENT .SS Modify the Vagrantfile .sp -Modify ./minion/Vagrantfile to use th precise64 box. Change the \fBconfig.vm.box\fP -line to: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -config.vm.box = \(dqprecise64\(dq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Uncomment the line creating a host\-only IP. This is the ip of your minion -(you can change it to something else if that IP is already in use): +Modify Vagrantfile to use th private_ip in local network. .INDENT 0.0 .INDENT 3.5 .sp @@ -50048,7 +44900,7 @@ vagrant ssh .UNINDENT .sp You should see the shell prompt change to something similar to -\fBvagrant@precise64:~$\fP meaning you\(aqre inside the VM. From there, enter the +\fBvagrant@focal64:~$\fP meaning you\(aqre inside the VM. From there, enter the following: .INDENT 0.0 .INDENT 3.5 @@ -54509,6 +49361,5650 @@ def foo(): .fi .UNINDENT .UNINDENT +.SS Returners +.sp +By default the return values of the commands sent to the Salt minions are +returned to the Salt master, however anything at all can be done with the results +data. +.sp +By using a Salt returner, results data can be redirected to external data\-stores +for analysis and archival. +.sp +Returners pull their configuration values from the Salt minions. Returners are only +configured once, which is generally at load time. +.sp +The returner interface allows the return data to be sent to any system that +can receive data. This means that return data can be sent to a Redis server, +a MongoDB server, a MySQL server, or any system. +.sp +\fBSEE ALSO:\fP +.INDENT 0.0 +.INDENT 3.5 +\fI\%Full list of builtin returners\fP +.UNINDENT +.UNINDENT +.SS Using Returners +.sp +All Salt commands will return the command data back to the master. Specifying +returners will ensure that the data is _also_ sent to the specified returner +interfaces. +.sp +Specifying what returners to use is done when the command is invoked: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.version \-\-return redis_return +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This command will ensure that the redis_return returner is used. +.sp +It is also possible to specify multiple returners: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.version \-\-return mongo_return,redis_return,cassandra_return +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +In this scenario all three returners will be called and the data from the +test.version command will be sent out to the three named returners. +.SS Writing a Returner +.sp +Returners are Salt modules that allow the redirection of results data to targets other than the Salt Master. +.SS Returners Are Easy To Write! +.sp +Writing a Salt returner is straightforward. +.sp +A returner is a Python module containing at minimum a \fBreturner\fP function. +Other optional functions can be included to add support for +\fI\%master_job_cache\fP, \fI\%Storing Job Results in an External System\fP, and \fI\%Event Returners\fP\&. +.INDENT 0.0 +.TP +.B \fBreturner\fP +The \fBreturner\fP function must accept a single argument. The argument +contains return data from the called minion function. If the minion +function \fBtest.version\fP is called, the value of the argument will be a +dictionary. Run the following command from a Salt master to get a sample +of the dictionary: +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-call \-\-local \-\-metadata test.version \-\-out=pprint +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +import redis +import salt.utils.json + + +def returner(ret): + \(dq\(dq\(dq + Return information to a redis server + \(dq\(dq\(dq + # Get a redis connection + serv = redis.Redis(host=\(dqredis\-serv.example.com\(dq, port=6379, db=\(dq0\(dq) + serv.sadd(\(dq%(id)s:jobs\(dq % ret, ret[\(dqjid\(dq]) + serv.set(\(dq%(jid)s:%(id)s\(dq % ret, salt.utils.json.dumps(ret[\(dqreturn\(dq])) + serv.sadd(\(dqjobs\(dq, ret[\(dqjid\(dq]) + serv.sadd(ret[\(dqjid\(dq], ret[\(dqid\(dq]) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The above example of a returner set to send the data to a Redis server +serializes the data as JSON and sets it in redis. +.SS Using Custom Returner Modules +.sp +Place custom returners in a \fB_returners/\fP directory within the +\fI\%file_roots\fP specified by the master config file. +.sp +Like all custom modules, these must be synced to the relevant master or minion +before they can be used. See \fI\%Modular Systems\fP for details. +.sp +Any custom returners which have been synced to a minion that are named the +same as one of Salt\(aqs default set of returners will take the place of the +default returner with the same name. +.SS Naming the Returner +.sp +Note that a returner\(aqs default name is its filename (i.e. \fBfoo.py\fP becomes +returner \fBfoo\fP), but that its name can be overridden by using a +\fI\%__virtual__ function\fP\&. A good example of this can be +found in the \fI\%redis\fP returner, which is named \fBredis_return.py\fP but is +loaded as simply \fBredis\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +try: + import redis + + HAS_REDIS = True +except ImportError: + HAS_REDIS = False + +__virtualname__ = \(dqredis\(dq + + +def __virtual__(): + if not HAS_REDIS: + return False + return __virtualname__ +.ft P +.fi +.UNINDENT +.UNINDENT +.SS Master Job Cache Support +.sp +\fI\%master_job_cache\fP, \fI\%Storing Job Results in an External System\fP, and \fI\%Event Returners\fP\&. +Salt\(aqs \fI\%master_job_cache\fP allows returners to be used as a pluggable +replacement for the \fI\%Default Job Cache\fP\&. In order to do so, a returner +must implement the following functions: +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The code samples contained in this section were taken from the cassandra_cql +returner. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \fBprep_jid\fP +Ensures that job ids (jid) don\(aqt collide, unless passed_jid is provided. +.sp +\fBnocache\fP is an optional boolean that indicates if return data +should be cached. \fBpassed_jid\fP is a caller provided jid which should be +returned unconditionally. +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +def prep_jid(nocache, passed_jid=None): # pylint: disable=unused\-argument + \(dq\(dq\(dq + Do any work necessary to prepare a JID, including sending a custom id + \(dq\(dq\(dq + return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid() +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \fBsave_load\fP +Save job information. The \fBjid\fP is generated by \fBprep_jid\fP and should +be considered a unique identifier for the job. The jid, for example, could +be used as the primary/unique key in a database. The \fBload\fP is what is +returned to a Salt master by a minion. \fBminions\fP is a list of minions +that the job was run against. The following code example stores the load as +a JSON string in the salt.jids table. +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +import salt.utils.json + + +def save_load(jid, load, minions=None): + \(dq\(dq\(dq + Save the load to the specified jid id + \(dq\(dq\(dq + query = \(dq\(dq\(dqINSERT INTO salt.jids ( + jid, load + ) VALUES ( + \(aq{0}\(aq, \(aq{1}\(aq + );\(dq\(dq\(dq.format( + jid, salt.utils.json.dumps(load) + ) + + # cassandra_cql.cql_query may raise a CommandExecutionError + try: + __salt__[\(dqcassandra_cql.cql_query\(dq](query) + except CommandExecutionError: + log.critical(\(dqCould not save load in jids table.\(dq) + raise + except Exception as e: + log.critical(\(dqUnexpected error while inserting into jids: {0}\(dq.format(e)) + raise +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \fBget_load\fP +must accept a job id (jid) and return the job load stored by \fBsave_load\fP, +or an empty dictionary when not found. +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +def get_load(jid): + \(dq\(dq\(dq + Return the load data that marks a specified jid + \(dq\(dq\(dq + query = \(dq\(dq\(dqSELECT load FROM salt.jids WHERE jid = \(aq{0}\(aq;\(dq\(dq\(dq.format(jid) + + ret = {} + + # cassandra_cql.cql_query may raise a CommandExecutionError + try: + data = __salt__[\(dqcassandra_cql.cql_query\(dq](query) + if data: + load = data[0].get(\(dqload\(dq) + if load: + ret = json.loads(load) + except CommandExecutionError: + log.critical(\(dqCould not get load from jids table.\(dq) + raise + except Exception as e: + log.critical( + \(dq\(dq\(dqUnexpected error while getting load from + jids: {0}\(dq\(dq\(dq.format( + str(e) + ) + ) + raise + + return ret +.ft P +.fi +.UNINDENT +.UNINDENT +.SS External Job Cache Support +.sp +Salt\(aqs \fI\%Storing Job Results in an External System\fP extends the \fI\%master_job_cache\fP\&. External +Job Cache support requires the following functions in addition to what is +required for Master Job Cache support: +.INDENT 0.0 +.TP +.B \fBget_jid\fP +Return a dictionary containing the information (load) returned by each +minion when the specified job id was executed. +.UNINDENT +.sp +Sample: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{ + \(dqlocal\(dq: { + \(dqmaster_minion\(dq: { + \(dqfun_args\(dq: [], + \(dqjid\(dq: \(dq20150330121011408195\(dq, + \(dqreturn\(dq: \(dq2018.3.4\(dq, + \(dqretcode\(dq: 0, + \(dqsuccess\(dq: true, + \(dqcmd\(dq: \(dq_return\(dq, + \(dq_stamp\(dq: \(dq2015\-03\-30T12:10:12.708663\(dq, + \(dqfun\(dq: \(dqtest.version\(dq, + \(dqid\(dq: \(dqmaster_minion\(dq + } + } +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \fBget_fun\fP +Return a dictionary of minions that called a given Salt function as their +last function call. +.UNINDENT +.sp +Sample: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{ + \(dqlocal\(dq: { + \(dqminion1\(dq: \(dqtest.version\(dq, + \(dqminion3\(dq: \(dqtest.version\(dq, + \(dqminion2\(dq: \(dqtest.version\(dq + } +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \fBget_jids\fP +Return a list of all job ids. +.UNINDENT +.sp +Sample: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{ + \(dqlocal\(dq: [ + \(dq20150330121011408195\(dq, + \(dq20150330195922139916\(dq + ] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \fBget_minions\fP +Returns a list of minions +.UNINDENT +.sp +Sample: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +{ + \(dqlocal\(dq: [ + \(dqminion3\(dq, + \(dqminion2\(dq, + \(dqminion1\(dq, + \(dqmaster_minion\(dq + ] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Please refer to one or more of the existing returners (i.e. mysql, +cassandra_cql) if you need further clarification. +.SS Event Support +.sp +An \fBevent_return\fP function must be added to the returner module to allow +events to be logged from a master via the returner. A list of events are passed +to the function by the master. +.sp +The following example was taken from the MySQL returner. In this example, each +event is inserted into the salt_events table keyed on the event tag. The tag +contains the jid and therefore is guaranteed to be unique. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +import salt.utils.json + + +def event_return(events): + \(dq\(dq\(dq + Return event to mysql server + + Requires that configuration be enabled via \(aqevent_return\(aq + option in master config. + \(dq\(dq\(dq + with _get_serv(events, commit=True) as cur: + for event in events: + tag = event.get(\(dqtag\(dq, \(dq\(dq) + data = event.get(\(dqdata\(dq, \(dq\(dq) + sql = \(dq\(dq\(dqINSERT INTO \(gasalt_events\(ga (\(gatag\(ga, \(gadata\(ga, \(gamaster_id\(ga ) + VALUES (%s, %s, %s)\(dq\(dq\(dq + cur.execute(sql, (tag, salt.utils.json.dumps(data), __opts__[\(dqid\(dq])) +.ft P +.fi +.UNINDENT +.UNINDENT +.SS Testing the Returner +.sp +The \fBreturner\fP, \fBprep_jid\fP, \fBsave_load\fP, \fBget_load\fP, and +\fBevent_return\fP functions can be tested by configuring the +\fI\%master_job_cache\fP and \fI\%Event Returners\fP in the master config +file and submitting a job to \fBtest.version\fP each minion from the master. +.sp +Once you have successfully exercised the Master Job Cache functions, test the +External Job Cache functions using the \fBret\fP execution module. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-call ret.get_jids cassandra_cql \-\-output=json +salt\-call ret.get_fun cassandra_cql test.version \-\-output=json +salt\-call ret.get_minions cassandra_cql \-\-output=json +salt\-call ret.get_jid cassandra_cql 20150330121011408195 \-\-output=json +.ft P +.fi +.UNINDENT +.UNINDENT +.SS Event Returners +.sp +For maximum visibility into the history of events across a Salt +infrastructure, all events seen by a salt master may be logged to one or +more returners. +.sp +To enable event logging, set the \fBevent_return\fP configuration option in the +master config to the returner(s) which should be designated as the handler +for event returns. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Not all returners support event returns. Verify a returner has an +\fBevent_return()\fP function before using. +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +On larger installations, many hundreds of events may be generated on a +busy master every second. Be certain to closely monitor the storage of +a given returner as Salt can easily overwhelm an underpowered server +with thousands of returns. +.UNINDENT +.UNINDENT +.SS Full List of Returners +.SS returner modules +.TS +center; +|l|l|. +_ +T{ +\fI\%appoptics_return\fP +T} T{ +Salt returner to return highstate stats to AppOptics Metrics +T} +_ +T{ +\fI\%carbon_return\fP +T} T{ +Take data from salt and \(dqreturn\(dq it into a carbon receiver +T} +_ +T{ +\fI\%cassandra_cql_return\fP +T} T{ +Return data to a cassandra server +T} +_ +T{ +\fI\%couchbase_return\fP +T} T{ +Simple returner for Couchbase. +T} +_ +T{ +\fI\%couchdb_return\fP +T} T{ +Simple returner for CouchDB. +T} +_ +T{ +\fI\%elasticsearch_return\fP +T} T{ +Return data to an elasticsearch server for indexing. +T} +_ +T{ +\fI\%etcd_return\fP +T} T{ +Return data to an etcd server or cluster +T} +_ +T{ +\fI\%highstate_return\fP +T} T{ +Return the results of a highstate (or any other state function that returns data in a compatible format) via an HTML email or HTML file. +T} +_ +T{ +\fI\%influxdb_return\fP +T} T{ +Return data to an influxdb server. +T} +_ +T{ +\fI\%kafka_return\fP +T} T{ +Return data to a Kafka topic +T} +_ +T{ +\fI\%librato_return\fP +T} T{ +Salt returner to return highstate stats to Librato +T} +_ +T{ +\fI\%local\fP +T} T{ +The local returner is used to test the returner interface, it just prints the return data to the console to verify that it is being passed properly +T} +_ +T{ +\fI\%local_cache\fP +T} T{ +Return data to local job cache +T} +_ +T{ +\fI\%mattermost_returner\fP +T} T{ +Return salt data via mattermost +T} +_ +T{ +\fI\%memcache_return\fP +T} T{ +Return data to a memcache server +T} +_ +T{ +\fI\%mongo_future_return\fP +T} T{ +Return data to a mongodb server +T} +_ +T{ +\fI\%mongo_return\fP +T} T{ +Return data to a mongodb server +T} +_ +T{ +\fI\%multi_returner\fP +T} T{ +Read/Write multiple returners +T} +_ +T{ +\fI\%mysql\fP +T} T{ +Return data to a mysql server +T} +_ +T{ +\fI\%nagios_nrdp_return\fP +T} T{ +Return salt data to Nagios +T} +_ +T{ +\fI\%odbc\fP +T} T{ +Return data to an ODBC compliant server. +T} +_ +T{ +\fI\%pgjsonb\fP +T} T{ +Return data to a PostgreSQL server with json data stored in Pg\(aqs jsonb data type +T} +_ +T{ +\fI\%postgres\fP +T} T{ +Return data to a postgresql server +T} +_ +T{ +\fI\%postgres_local_cache\fP +T} T{ +Use a postgresql server for the master job cache. +T} +_ +T{ +\fI\%pushover_returner\fP +T} T{ +T} +_ +T{ +\fI\%rawfile_json\fP +T} T{ +Take data from salt and \(dqreturn\(dq it into a raw file containing the json, with one line per event. +T} +_ +T{ +\fI\%redis_return\fP +T} T{ +Return data to a redis server +T} +_ +T{ +\fI\%sentry_return\fP +T} T{ +Salt returner that reports execution results back to sentry. +T} +_ +T{ +\fI\%slack_returner\fP +T} T{ +Return salt data via slack +T} +_ +T{ +\fI\%slack_webhook_return\fP +T} T{ +Return salt data via Slack using Incoming Webhooks +T} +_ +T{ +\fI\%sms_return\fP +T} T{ +Return data by SMS. +T} +_ +T{ +\fI\%smtp_return\fP +T} T{ +Return salt data via email +T} +_ +T{ +\fI\%splunk\fP +T} T{ +Send json response data to Splunk via the HTTP Event Collector Requires the following config values to be specified in config or pillar: +T} +_ +T{ +\fI\%sqlite3_return\fP +T} T{ +Insert minion return data into a sqlite3 database +T} +_ +T{ +\fI\%syslog_return\fP +T} T{ +Return data to the host operating system\(aqs syslog facility +T} +_ +T{ +\fI\%telegram_return\fP +T} T{ +Return salt data via Telegram. +T} +_ +T{ +\fI\%xmpp_return\fP +T} T{ +Return salt data via xmpp +T} +_ +T{ +\fI\%zabbix_return\fP +T} T{ +T} +_ +.TE +.SS salt.returners.appoptics_return +.sp +Salt returner to return highstate stats to AppOptics Metrics +.sp +To enable this returner the minion will need the AppOptics Metrics +client importable on the Python path and the following +values configured in the minion or master config. +.sp +The AppOptics python client can be found at: +.sp +\fI\%https://github.com/appoptics/python\-appoptics\-metrics\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +appoptics.api_token: abc12345def +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +An example configuration that returns the total number of successes +and failures for your salt highstate runs (the default) would look +like this: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +return: appoptics +appoptics.api_token: +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The returner publishes the following metrics to AppOptics: +.INDENT 0.0 +.IP \(bu 2 +saltstack.failed +.IP \(bu 2 +saltstack.passed +.IP \(bu 2 +saltstack.retcode +.IP \(bu 2 +saltstack.runtime +.IP \(bu 2 +saltstack.total +.UNINDENT +.sp +You can add a tags section to specify which tags should be attached to +all metrics created by the returner. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +appoptics.tags: + host_hostname_alias: + tier: + cluster: +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +If no tags are explicitly configured, then the tag key \fBhost_hostname_alias\fP +will be set, with the minion\(aqs \fBid\fP grain being the value. +.sp +In addition to the requested tags, for a highstate run each of these +will be tagged with the \fBkey:value\fP of \fBstate_type: highstate\fP\&. +.sp +In order to return metrics for \fBstate.sls\fP runs (distinct from highstates), you can +specify a list of state names to the key \fBappoptics.sls_states\fP like so: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +appoptics.sls_states: + \- role_salt_master.netapi + \- role_redis.config + \- role_smarty.dummy +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This will report success and failure counts on runs of the +\fBrole_salt_master.netapi\fP, \fBrole_redis.config\fP, and +\fBrole_smarty.dummy\fP states in addition to highstates. +.sp +This will report the same metrics as above, but for these runs the +metrics will be tagged with \fBstate_type: sls\fP and \fBstate_name\fP set to +the name of the state that was invoked, e.g. \fBrole_salt_master.netapi\fP\&. +.INDENT 0.0 +.TP +.B salt.returners.appoptics_return.returner(ret) +Parse the return data and return metrics to AppOptics. +.sp +For each state that\(aqs provided in the configuration, return tagged metrics for +the result of that state if it\(aqs present. +.UNINDENT +.SS salt.returners.carbon_return +.sp +Take data from salt and \(dqreturn\(dq it into a carbon receiver +.sp +Add the following configuration to the minion configuration file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +carbon.host: +carbon.port: 2003 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Errors when trying to convert data to numbers may be ignored by setting +\fBcarbon.skip_on_error\fP to \fITrue\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +carbon.skip_on_error: True +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +By default, data will be sent to carbon using the plaintext protocol. To use +the pickle protocol, set \fBcarbon.mode\fP to \fBpickle\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +carbon.mode: pickle +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B You can also specify the pattern used for the metric base path (except for virt modules metrics): +carbon.metric_base_pattern: carbon.[minion_id].[module].[function] +.TP +.B These tokens can used : +[module]: salt module +[function]: salt function +[minion_id]: minion id +.TP +.B Default is : +carbon.metric_base_pattern: [module].[function].[minion_id] +.UNINDENT +.sp +Carbon settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +carbon: + host: + port: + skip_on_error: True + mode: (pickle|text) + metric_base_pattern: | [module].[function].[minion_id] +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.carbon: + host: + port: + skip_on_error: True + mode: (pickle|text) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the carbon returner, append \(aq\-\-return carbon\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return carbon +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return carbon \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return carbon \-\-return_kwargs \(aq{\(dqskip_on_error\(dq: False}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.carbon_return.event_return(events) +Return event data to remote carbon server +.sp +Provide a list of events to be stored in carbon +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.carbon_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.carbon_return.returner(ret) +Return data to a remote carbon server using the text metric protocol +.sp +Each metric will look like: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +[module].[function].[minion_id].[metric path [...]].[metric name] +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.SS salt.returners.cassandra_cql_return +.sp +Return data to a cassandra server +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.TP +.B maintainer +Corin Kochenower<\fI\%ckochenower@saltstack.com\fP> +.TP +.B maturity +new as of 2015.2 +.TP +.B depends +salt.modules.cassandra_cql +.TP +.B depends +DataStax Python Driver for Apache Cassandra +\fI\%https://github.com/datastax/python\-driver\fP +pip install cassandra\-driver +.TP +.B platform +all +.TP +.B configuration +To enable this returner, the minion will need the DataStax Python Driver +for Apache Cassandra ( \fI\%https://github.com/datastax/python\-driver\fP ) +installed and the following values configured in the minion or master +config. The list of cluster IPs must include at least one cassandra node +IP address. No assumption or default will be used for the cluster IPs. +The cluster IPs will be tried in the order listed. The port, username, +and password values shown below will be the assumed defaults if you do +not provide values.: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +cassandra: + cluster: + \- 192.168.50.11 + \- 192.168.50.12 + \- 192.168.50.13 + port: 9042 + username: salt + password: salt +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Use the following cassandra database schema: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +CREATE KEYSPACE IF NOT EXISTS salt + WITH replication = {\(aqclass\(aq: \(aqSimpleStrategy\(aq, \(aqreplication_factor\(aq : 1}; + +CREATE USER IF NOT EXISTS salt WITH PASSWORD \(aqsalt\(aq NOSUPERUSER; + +GRANT ALL ON KEYSPACE salt TO salt; + +USE salt; + +CREATE TABLE IF NOT EXISTS salt.salt_returns ( + jid text, + minion_id text, + fun text, + alter_time timestamp, + full_ret text, + return text, + success boolean, + PRIMARY KEY (jid, minion_id, fun) +) WITH CLUSTERING ORDER BY (minion_id ASC, fun ASC); +CREATE INDEX IF NOT EXISTS salt_returns_minion_id ON salt.salt_returns (minion_id); +CREATE INDEX IF NOT EXISTS salt_returns_fun ON salt.salt_returns (fun); + +CREATE TABLE IF NOT EXISTS salt.jids ( + jid text PRIMARY KEY, + load text +); + +CREATE TABLE IF NOT EXISTS salt.minions ( + minion_id text PRIMARY KEY, + last_fun text +); +CREATE INDEX IF NOT EXISTS minions_last_fun ON salt.minions (last_fun); + +CREATE TABLE IF NOT EXISTS salt.salt_events ( + id timeuuid, + tag text, + alter_time timestamp, + data text, + master_id text, + PRIMARY KEY (id, tag) +) WITH CLUSTERING ORDER BY (tag ASC); +CREATE INDEX tag ON salt.salt_events (tag); +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.sp +Required python modules: cassandra\-driver +.sp +To use the cassandra returner, append \(aq\-\-return cassandra_cql\(aq to the salt command. ex: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return_cql cassandra +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Note: if your Cassandra instance has not been tuned much you may benefit from +altering some timeouts in \fIcassandra.yaml\fP like so: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# How long the coordinator should wait for read operations to complete +read_request_timeout_in_ms: 5000 +# How long the coordinator should wait for seq or index scans to complete +range_request_timeout_in_ms: 20000 +# How long the coordinator should wait for writes to complete +write_request_timeout_in_ms: 20000 +# How long the coordinator should wait for counter writes to complete +counter_write_request_timeout_in_ms: 10000 +# How long a coordinator should continue to retry a CAS operation +# that contends with other proposals for the same row +cas_contention_timeout_in_ms: 5000 +# How long the coordinator should wait for truncates to complete +# (This can be much longer, because unless auto_snapshot is disabled +# we need to flush first so we can snapshot before removing the data.) +truncate_request_timeout_in_ms: 60000 +# The default timeout for other, miscellaneous operations +request_timeout_in_ms: 20000 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +As always, your mileage may vary and your Cassandra cluster may have different +needs. SaltStack has seen situations where these timeouts can resolve +some stacktraces that appear to come from the Datastax Python driver. +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.event_return(events) +Return event to one of potentially many clustered cassandra nodes +.sp +Requires that configuration be enabled via \(aqevent_return\(aq +option in master config. +.sp +Cassandra does not support an auto\-increment feature due to the +highly inefficient nature of creating a monotonically increasing +number across all nodes in a distributed database. Each event +will be assigned a uuid by the connecting client. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.prep_jid(nocache, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.returner(ret) +Return data to one of potentially many clustered cassandra nodes +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.save_load(jid, load, minions=None) +Save the load to the specified jid id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.cassandra_cql_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.couchbase_return +.sp +Simple returner for Couchbase. Optional configuration +settings are listed below, along with sane defaults. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +couchbase.host: \(aqsalt\(aq +couchbase.port: 8091 +couchbase.bucket: \(aqsalt\(aq +couchbase.ttl: 86400 +couchbase.password: \(aqpassword\(aq +couchbase.skip_verify_views: False +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the couchbase returner, append \(aq\-\-return couchbase\(aq to the salt command. ex: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return couchbase +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return couchbase \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return couchbase \-\-return_kwargs \(aq{\(dqbucket\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +All of the return data will be stored in documents as follows: +.SS JID +.sp +load: load obj +tgt_minions: list of minions targeted +nocache: should we not cache the return data +.SS JID/MINION_ID +.sp +return: return_data +full_ret: full load of job return +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.prep_jid(nocache=False, passed_jid=None) +Return a job id and prepare the job id directory +This is the function responsible for making sure jids don\(aqt collide (unless +its passed a jid) +So do what you have to do to make sure that stays the case +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.returner(load) +Return data to couchbase bucket +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.save_load(jid, clear_load, minion=None) +Save the load to the specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchbase_return.save_minions(jid, minions, syndic_id=None) +Save/update the minion list for a given jid. The syndic_id argument is +included for API compatibility only. +.UNINDENT +.SS salt.returners.couchdb_return +.sp +Simple returner for CouchDB. Optional configuration +settings are listed below, along with sane defaults: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +couchdb.db: \(aqsalt\(aq +couchdb.url: \(aqhttp://salt:5984/\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.couchdb.db: \(aqsalt\(aq +alternative.couchdb.url: \(aqhttp://salt:5984/\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the couchdb returner, append \fB\-\-return couchdb\fP to the salt command. Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return couchdb +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \fB\-\-return_config alternative\fP to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return couchdb \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return couchdb \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.SS On concurrent database access +.sp +As this returner creates a couchdb document with the salt job id as document id +and as only one document with a given id can exist in a given couchdb database, +it is advised for most setups that every minion be configured to write to it own +database (the value of \fBcouchdb.db\fP may be suffixed with the minion id), +otherwise multi\-minion targeting can lead to losing output: +.INDENT 0.0 +.IP \(bu 2 +the first returning minion is able to create a document in the database +.IP \(bu 2 +other minions fail with \fB{\(aqerror\(aq: \(aqHTTP Error 409: Conflict\(aq}\fP +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.ensure_views() +This function makes sure that all the views that should +exist in the design document do exist. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.get_fun(fun) +Return a dict with key being minion and value +being the job details of the last run of function \(aqfun\(aq. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.get_jid(jid) +Get the document with a given JID. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.get_jids() +List all the jobs that we have.. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.get_minions() +Return a list of minion identifiers from a request of the view. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.get_valid_salt_views() +Returns a dict object of views that should be +part of the salt design document. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.returner(ret) +Take in the return and shove it into the couchdb database. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.couchdb_return.set_salt_view() +Helper function that sets the salt design +document. Uses get_valid_salt_views and some hardcoded values. +.UNINDENT +.SS salt.returners.elasticsearch_return +.sp +Return data to an elasticsearch server for indexing. +.INDENT 0.0 +.TP +.B maintainer +Jurnell Cockhren <\fI\%jurnell.cockhren@sophicware.com\fP>, Arnold Bechtoldt <\fI\%mail@arnoldbechtoldt.com\fP> +.TP +.B maturity +New +.TP +.B depends +\fI\%elasticsearch\-py\fP +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner the elasticsearch python client must be installed +on the desired minions (all or some subset). +.sp +Please see documentation of \fI\%elasticsearch execution module\fP +for a valid connection configuration. +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +The index that you wish to store documents will be created by Elasticsearch automatically if +doesn\(aqt exist yet. It is highly recommended to create predefined index templates with appropriate mapping(s) +that will be used by Elasticsearch upon index creation. Otherwise you will have problems as described in #20826. +.UNINDENT +.UNINDENT +.sp +To use the returner per salt call: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return elasticsearch +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +In order to have the returner apply to all minions: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +ext_job_cache: elasticsearch +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B Minion configuration: +.INDENT 7.0 +.TP +.B debug_returner_payload\(aq: False +Output the payload being posted to the log file in debug mode +.TP +.B doc_type: \(aqdefault\(aq +Document type to use for normal return messages +.TP +.B functions_blacklist +Optional list of functions that should not be returned to elasticsearch +.TP +.B index_date: False +Use a dated index (e.g. \-2016.11.29) +.TP +.B master_event_index: \(aqsalt\-master\-event\-cache\(aq +Index to use when returning master events +.TP +.B master_event_doc_type: \(aqefault\(aq +Document type to use got master events +.TP +.B master_job_cache_index: \(aqsalt\-master\-job\-cache\(aq +Index to use for master job cache +.TP +.B master_job_cache_doc_type: \(aqdefault\(aq +Document type to use for master job cache +.TP +.B number_of_shards: 1 +Number of shards to use for the indexes +.TP +.B number_of_replicas: 0 +Number of replicas to use for the indexes +.UNINDENT +.sp +NOTE: The following options are valid for \(aqstate.apply\(aq, \(aqstate.sls\(aq and \(aqstate.highstate\(aq functions only. +.INDENT 7.0 +.TP +.B states_count: False +Count the number of states which succeeded or failed and return it in top\-level item called \(aqcounts\(aq. +States reporting None (i.e. changes would be made but it ran in test mode) are counted as successes. +.TP +.B states_order_output: False +Prefix the state UID (e.g. file_|\-yum_configured_|\-/etc/yum.conf_|\-managed) with a zero\-padded version +of the \(aq__run_num__\(aq value to allow for easier sorting. Also store the state function (i.e. file.managed) +into a new key \(aq_func\(aq. Change the index to be \(aq\-ordered\(aq (e.g. salt\-state_apply\-ordered). +.TP +.B states_single_index: False +Store results for state.apply, state.sls and state.highstate in the salt\-state_apply index +(or \-ordered/\-) indexes if enabled +.UNINDENT +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +elasticsearch: + hosts: + \- \(dq10.10.10.10:9200\(dq + \- \(dq10.10.10.11:9200\(dq + \- \(dq10.10.10.12:9200\(dq + index_date: True + number_of_shards: 5 + number_of_replicas: 1 + debug_returner_payload: True + states_count: True + states_order_output: True + states_single_index: True + functions_blacklist: + \- test.ping + \- saltutil.find_job +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.elasticsearch_return.event_return(events) +Return events to Elasticsearch +.sp +Requires that the \fIevent_return\fP configuration be set in master config. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.elasticsearch_return.get_load(jid) +Return the load data that marks a specified jid +.sp +New in version 2015.8.1. + +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.elasticsearch_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.elasticsearch_return.returner(ret) +Process the return from Salt +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.elasticsearch_return.save_load(jid, load, minions=None) +Save the load to the specified jid id +.sp +New in version 2015.8.1. + +.UNINDENT +.SS salt.returners.etcd_return +.sp +Return data to an etcd server or cluster +.INDENT 0.0 +.TP +.B depends +.INDENT 7.0 +.IP \(bu 2 +python\-etcd or etcd3\-py +.UNINDENT +.UNINDENT +.sp +In order to return to an etcd server, a profile should be created in the master +configuration file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +my_etcd_config: + etcd.host: 127.0.0.1 + etcd.port: 2379 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +It is technically possible to configure etcd without using a profile, but this +is not considered to be a best practice, especially when multiple etcd servers +or clusters are available. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.host: 127.0.0.1 +etcd.port: 2379 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +In order to choose whether to use etcd API v2 or v3, you can put the following +configuration option in the same place as your etcd configuration. This option +defaults to true, meaning you will use v2 unless you specify otherwise. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.require_v2: True +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +When using API v3, there are some specific options available to be configured +within your etcd profile. They are defaulted to the following... +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.encode_keys: False +etcd.encode_values: True +etcd.raw_keys: False +etcd.raw_values: False +etcd.unicode_errors: \(dqsurrogateescape\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBetcd.encode_keys\fP indicates whether you want to pre\-encode keys using msgpack before +adding them to etcd. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +If you set \fBetcd.encode_keys\fP to \fBTrue\fP, all recursive functionality will no longer work. +This includes \fBtree\fP and \fBls\fP and all other methods if you set \fBrecurse\fP/\fBrecursive\fP to \fBTrue\fP\&. +This is due to the fact that when encoding with msgpack, keys like \fB/salt\fP and \fB/salt/stack\fP will have +differing byte prefixes, and etcd v3 searches recursively using prefixes. +.UNINDENT +.UNINDENT +.sp +\fBetcd.encode_values\fP indicates whether you want to pre\-encode values using msgpack before +adding them to etcd. This defaults to \fBTrue\fP to avoid data loss on non\-string values wherever possible. +.sp +\fBetcd.raw_keys\fP determines whether you want the raw key or a string returned. +.sp +\fBetcd.raw_values\fP determines whether you want the raw value or a string returned. +.sp +\fBetcd.unicode_errors\fP determines what you policy to follow when there are encoding/decoding errors. +.sp +Additionally, two more options must be specified in the top\-level configuration +in order to use the etcd returner: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.returner: my_etcd_config +etcd.returner_root: /salt/return +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The \fBetcd.returner\fP option specifies which configuration profile to use. The +\fBetcd.returner_root\fP option specifies the path inside etcd to use as the root +of the returner system. +.sp +Once the etcd options are configured, the returner may be used: +.sp +CLI Example: +.INDENT 0.0 +.INDENT 3.5 +salt \(aq*\(aq test.ping \-\-return etcd +.UNINDENT +.UNINDENT +.sp +A username and password can be set: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.username: larry # Optional; requires etcd.password to be set +etcd.password: 123pass # Optional; requires etcd.username to be set +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +You can also set a TTL (time to live) value for the returner: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.ttl: 5 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Authentication with username and password, and ttl, currently requires the +\fBmaster\fP branch of \fBpython\-etcd\fP\&. +.sp +You may also specify different roles for read and write operations. First, +create the profiles as specified above. Then add: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +etcd.returner_read_profile: my_etcd_read +etcd.returner_write_profile: my_etcd_write +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.clean_old_jobs() +Included for API consistency +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.returner(ret) +Return data to an etcd server or cluster +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.save_load(jid, load, minions=None) +Save the load to the specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.etcd_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.highstate_return +.sp +Return the results of a highstate (or any other state function that returns +data in a compatible format) via an HTML email or HTML file. +.sp +New in version 2017.7.0. + +.sp +Similar results can be achieved by using the smtp returner with a custom template, +except an attempt at writing such a template for the complex data structure +returned by highstate function had proven to be a challenge, not to mention +that the smtp module doesn\(aqt support sending HTML mail at the moment. +.sp +The main goal of this returner was to produce an easy to read email similar +to the output of highstate outputter used by the CLI. +.sp +This returner could be very useful during scheduled executions, +but could also be useful for communicating the results of a manual execution. +.sp +Returner configuration is controlled in a standard fashion either via +highstate group or an alternatively named group. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq state.highstate \-\-return highstate +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config config\-name\(aq +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq state.highstate \-\-return highstate \-\-return_config simple +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Here is an example of what the configuration might look like: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +simple.highstate: + report_failures: True + report_changes: True + report_everything: False + failure_function: pillar.items + success_function: pillar.items + report_format: html + report_delivery: smtp + smtp_success_subject: \(aqsuccess minion {id} on host {host}\(aq + smtp_failure_subject: \(aqfailure minion {id} on host {host}\(aq + smtp_server: smtp.example.com + smtp_recipients: saltusers@example.com, devops@example.com + smtp_sender: salt@example.com +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The \fIreport_failures\fP, \fIreport_changes\fP, and \fIreport_everything\fP flags provide +filtering of the results. If you want an email to be sent every time, then +\fIreport_everything\fP is your choice. If you want to be notified only when +changes were successfully made use \fIreport_changes\fP\&. And \fIreport_failures\fP will +generate an email if there were failures. +.sp +The configuration allows you to run a salt module function in case of +success (\fIsuccess_function\fP) or failure (\fIfailure_function\fP). +.sp +Any salt function, including ones defined in the _module folder of your salt +repo, could be used here and its output will be displayed under the \(aqextra\(aq +heading of the email. +.sp +Supported values for \fIreport_format\fP are html, json, and yaml. The latter two +are typically used for debugging purposes, but could be used for applying +a template at some later stage. +.sp +The values for \fIreport_delivery\fP are smtp or file. In case of file delivery +the only other applicable option is \fIfile_output\fP\&. +.sp +In case of smtp delivery, smtp_* options demonstrated by the example above +could be used to customize the email. +.sp +As you might have noticed, the success and failure subjects contain {id} and {host} +values. Any other grain name could be used. As opposed to using +{{grains[\(aqid\(aq]}}, which will be rendered by the master and contain master\(aqs +values at the time of pillar generation, these will contain minion values at +the time of execution. +.INDENT 0.0 +.TP +.B salt.returners.highstate_return.returner(ret) +Check highstate return information and possibly fire off an email +or save a file. +.UNINDENT +.SS salt.returners.influxdb_return +.sp +Return data to an influxdb server. +.sp +New in version 2015.8.0. + +.sp +To enable this returner the minion will need the python client for influxdb +installed and the following values configured in the minion or master +config, these are the defaults: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +influxdb.db: \(aqsalt\(aq +influxdb.user: \(aqsalt\(aq +influxdb.password: \(aqsalt\(aq +influxdb.host: \(aqlocalhost\(aq +influxdb.port: 8086 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.influxdb.db: \(aqsalt\(aq +alternative.influxdb.user: \(aqsalt\(aq +alternative.influxdb.password: \(aqsalt\(aq +alternative.influxdb.host: \(aqlocalhost\(aq +alternative.influxdb.port: 6379 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the influxdb returner, append \(aq\-\-return influxdb\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return influxdb +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return influxdb \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return influxdb \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.returner(ret) +Return data to a influxdb data store +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.save_load(jid, load, minions=None) +Save the load to the specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.influxdb_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.kafka_return +.sp +Return data to a Kafka topic +.INDENT 0.0 +.TP +.B maintainer +Justin Desilets (\fI\%justin.desilets@gmail.com\fP) +.TP +.B maturity +20181119 +.TP +.B depends +confluent\-kafka +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner install confluent\-kafka and enable the following +settings in the minion config: +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.TP +.B returner.kafka.bootstrap: +.INDENT 7.0 +.IP \(bu 2 +\(dqserver1:9092\(dq +.IP \(bu 2 +\(dqserver2:9092\(dq +.IP \(bu 2 +\(dqserver3:9092\(dq +.UNINDENT +.UNINDENT +.sp +returner.kafka.topic: \(aqtopic\(aq +.UNINDENT +.UNINDENT +.sp +To use the kafka returner, append \fI\-\-return kafka\fP to the Salt command, eg; +.INDENT 0.0 +.INDENT 3.5 +salt \(aq*\(aq test.ping \-\-return kafka +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.kafka_return.returner(ret) +Return information to a Kafka server +.UNINDENT +.SS salt.returners.librato_return +.sp +Salt returner to return highstate stats to Librato +.sp +To enable this returner the minion will need the Librato +client importable on the Python path and the following +values configured in the minion or master config. +.sp +The Librato python client can be found at: +\fI\%https://github.com/librato/python\-librato\fP +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +librato.email: example@librato.com +librato.api_token: abc12345def +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This return supports multi\-dimension metrics for Librato. To enable +support for more metrics, the tags JSON object can be modified to include +other tags. +.sp +Adding EC2 Tags example: +If ec2_tags:region were desired within the tags for multi\-dimension. The tags +could be modified to include the ec2 tags. Multiple dimensions are added simply +by adding more tags to the submission. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +pillar_data = __salt__[\(aqpillar.raw\(aq]() +q.add(metric.name, value, tags={\(aqName\(aq: ret[\(aqid\(aq],\(aqRegion\(aq: pillar_data[\(aqec2_tags\(aq][\(aqName\(aq]}) +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.librato_return.returner(ret) +Parse the return data and return metrics to Librato. +.UNINDENT +.SS salt.returners.local +.sp +The local returner is used to test the returner interface, it just prints the +return data to the console to verify that it is being passed properly +.sp +To use the local returner, append \(aq\-\-return local\(aq to the salt command. ex: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return local +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local.event_return(event) +Print event return data to the terminal to verify functionality +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local.returner(ret) +Print the return data to the terminal to verify functionality +.UNINDENT +.SS salt.returners.local_cache +.sp +Return data to local job cache +.INDENT 0.0 +.TP +.B salt.returners.local_cache.clean_old_jobs() +Clean out the old jobs from the job cache +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.get_endtime(jid) +Retrieve the stored endtime for a given job +.sp +Returns False if no endtime is present +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.get_jids() +Return a dict mapping all job ids to job information +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.get_jids_filter(count, filter_find_job=True) +Return a list of all jobs information filtered by the given criteria. +:param int count: show not more than the count of most recent jobs +:param bool filter_find_jobs: filter out \(aqsaltutil.find_job\(aq jobs +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.load_reg() +Load the register from msgpack files +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.prep_jid(nocache=False, passed_jid=None, recurse_count=0) +Return a job id and prepare the job id directory. +.sp +This is the function responsible for making sure jids don\(aqt collide (unless +it is passed a jid). +So do what you have to do to make sure that stays the case +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.returner(load) +Return data to the local job cache +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.save_load(jid, clear_load, minions=None, recurse_count=0) +Save the load to the specified jid +.sp +minions argument is to provide a pre\-computed list of matched minions for +the job, for cases when this function can\(aqt compute that list itself (such +as for salt\-ssh) +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.save_minions(jid, minions, syndic_id=None) +Save/update the serialized list of minions for a given job +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.save_reg(data) +Save the register to msgpack files +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.local_cache.update_endtime(jid, time) +Update (or store) the end time for a given job +.sp +Endtime is stored as a plain text string +.UNINDENT +.SS salt.returners.mattermost_returner +.sp +Return salt data via mattermost +.sp +New in version 2017.7.0. + +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mattermost.hook (required) +mattermost.username (optional) +mattermost.channel (optional) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mattermost.channel +mattermost.hook +mattermost.username +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +mattermost settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mattermost: + channel: RoomName + hook: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + username: user +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the mattermost returner, append \(aq\-\-return mattermost\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mattermost +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(aqkey:\(aq: \(aqvalue\(aq}\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mattermost \-\-return_kwargs \(aq{\(aqchannel\(aq: \(aq#random\(aq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mattermost_returner.event_return(events) +Send the events to a mattermost room. +.INDENT 7.0 +.TP +.B Parameters +\fBevents\fP \-\- List of events +.TP +.B Returns +Boolean if messages were sent successfully. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mattermost_returner.post_message(channel, message, username, api_url, hook) +Send a message to a mattermost room. +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBchannel\fP \-\- The room name. +.IP \(bu 2 +\fBmessage\fP \-\- The message to send to the mattermost room. +.IP \(bu 2 +\fBusername\fP \-\- Specify who the message is from. +.IP \(bu 2 +\fBhook\fP \-\- The mattermost hook, if not specified in the configuration. +.UNINDENT +.TP +.B Returns +Boolean if message was sent successfully. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mattermost_returner.returner(ret) +Send an mattermost message with the data +.UNINDENT +.SS salt.returners.memcache_return +.sp +Return data to a memcache server +.sp +To enable this returner the minion will need the python client for memcache +installed and the following values configured in the minion or master +config, these are the defaults. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +memcache.host: \(aqlocalhost\(aq +memcache.port: \(aq11211\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.memcache.host: \(aqlocalhost\(aq +alternative.memcache.port: \(aq11211\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +python2\-memcache uses \(aqlocalhost\(aq and \(aq11211\(aq as syntax on connection. +.sp +To use the memcache returner, append \(aq\-\-return memcache\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return memcache +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return memcache \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return memcache \-\-return_kwargs \(aq{\(dqhost\(dq: \(dqhostname.domain.com\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.returner(ret) +Return data to a memcache data store +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.save_load(jid, load, minions=None) +Save the load to the specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.memcache_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.mongo_future_return +.sp +Return data to a mongodb server +.sp +Required python modules: pymongo +.sp +This returner will send data from the minions to a MongoDB server. MongoDB +server can be configured by using host, port, db, user and password settings +or by connection string URI (for pymongo > 2.3). To configure the settings +for your MongoDB server, add the following lines to the minion config files: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mongo.db: +mongo.host: +mongo.user: +mongo.password: +mongo.port: 27017 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Or single URI: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mongo.uri: URI +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +where uri is in the format: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mongodb://db1.example.net:27017/mydatabase +mongodb://db1.example.net:27017,db2.example.net:2500/?replicaSet=test +mongodb://db1.example.net:27017,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +More information on URI format can be found in +\fI\%https://docs.mongodb.com/manual/reference/connection\-string/\fP +.sp +You can also ask for indexes creation on the most common used fields, which +should greatly improve performance. Indexes are not created by default. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mongo.indexes: true +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.mongo.db: +alternative.mongo.host: +alternative.mongo.user: +alternative.mongo.password: +alternative.mongo.port: 27017 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Or single URI: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.mongo.uri: URI +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This mongo returner is being developed to replace the default mongodb returner +in the future and should not be considered API stable yet. +.sp +To use the mongo returner, append \(aq\-\-return mongo\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.event_return(events) +Return events to Mongodb server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.get_fun(fun) +Return the most recent jobs that have executed the named function +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.get_jid(jid) +Return the return information associated with a jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.get_jids() +Return a list of job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.get_load(jid) +Return the load associated with a given job id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.returner(ret) +Return data to a mongodb server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.save_load(jid, load, minions=None) +Save the load for a given job id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_future_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.mongo_return +.sp +Return data to a mongodb server +.sp +Required python modules: pymongo +.sp +This returner will send data from the minions to a MongoDB server. To +configure the settings for your MongoDB server, add the following lines +to the minion config files. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mongo.db: +mongo.host: +mongo.user: +mongo.password: +mongo.port: 27017 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.mongo.db: +alternative.mongo.host: +alternative.mongo.user: +alternative.mongo.password: +alternative.mongo.port: 27017 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the mongo returner, append \(aq\-\-return mongo\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo_return +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo_return \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mongo \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_return.get_fun(fun) +Return the most recent jobs that have executed the named function +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_return.get_jid(jid) +Return the return information associated with a jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_return.returner(ret) +Return data to a mongodb server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mongo_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.multi_returner +.sp +Read/Write multiple returners +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.clean_old_jobs() +Clean out the old jobs from all returners (if you have it) +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.get_jid(jid) +Merge the return data from all returners +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.get_jids() +Return all job data from all returners +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.get_load(jid) +Merge the load data from all returners +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.prep_jid(nocache=False, passed_jid=None) +Call both with prep_jid on all returners in multi_returner +.sp +TODO: finish this, what do do when you get different jids from 2 returners... +since our jids are time based, this make this problem hard, because they +aren\(aqt unique, meaning that we have to make sure that no one else got the jid +and if they did we spin to get a new one, which means \(dqlocking\(dq the jid in 2 +returners is non\-trivial +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.returner(load) +Write return to all returners in multi_returner +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.save_load(jid, clear_load, minions=None) +Write load to all returners in multi_returner +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.multi_returner.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.mysql +.sp +Return data to a mysql server +.INDENT 0.0 +.TP +.B maintainer +Dave Boucha <\fI\%dave@saltstack.com\fP>, Seth House <\fI\%shouse@saltstack.com\fP> +.TP +.B maturity +mature +.TP +.B depends +python\-mysqldb +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner, the minion will need the python client for mysql +installed and the following values configured in the minion or master +config. These are the defaults: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mysql.host: \(aqsalt\(aq +mysql.user: \(aqsalt\(aq +mysql.pass: \(aqsalt\(aq +mysql.db: \(aqsalt\(aq +mysql.port: 3306 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +SSL is optional. The defaults are set to None. If you do not want to use SSL, +either exclude these options or set them to None. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +mysql.ssl_ca: None +mysql.ssl_cert: None +mysql.ssl_key: None +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration +with \fIalternative.\fP\&. Any values not found in the alternative configuration will +be pulled from the default location. As stated above, SSL configuration is +optional. The following ssl options are simply for illustration purposes: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.mysql.host: \(aqsalt\(aq +alternative.mysql.user: \(aqsalt\(aq +alternative.mysql.pass: \(aqsalt\(aq +alternative.mysql.db: \(aqsalt\(aq +alternative.mysql.port: 3306 +alternative.mysql.ssl_ca: \(aq/etc/pki/mysql/certs/localhost.pem\(aq +alternative.mysql.ssl_cert: \(aq/etc/pki/mysql/certs/localhost.crt\(aq +alternative.mysql.ssl_key: \(aq/etc/pki/mysql/certs/localhost.key\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Should you wish the returner data to be cleaned out every so often, set +\fIkeep_jobs_seconds\fP to the number of hours for the jobs to live in the +tables. Setting it to \fI0\fP will cause the data to stay in the tables. The +default setting for \fIkeep_jobs_seconds\fP is set to \fI86400\fP\&. +.sp +Should you wish to archive jobs in a different table for later processing, +set \fIarchive_jobs\fP to True. Salt will create 3 archive tables +.INDENT 0.0 +.IP \(bu 2 +\fIjids_archive\fP +.IP \(bu 2 +\fIsalt_returns_archive\fP +.IP \(bu 2 +\fIsalt_events_archive\fP +.UNINDENT +.sp +and move the contents of \fIjids\fP, \fIsalt_returns\fP, and \fIsalt_events\fP that are +more than \fIkeep_jobs_seconds\fP seconds old to these tables. +.sp +Use the following mysql database schema: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +CREATE DATABASE \(gasalt\(ga + DEFAULT CHARACTER SET utf8 + DEFAULT COLLATE utf8_general_ci; + +USE \(gasalt\(ga; + +\-\- +\-\- Table structure for table \(gajids\(ga +\-\- + +DROP TABLE IF EXISTS \(gajids\(ga; +CREATE TABLE \(gajids\(ga ( + \(gajid\(ga varchar(255) NOT NULL, + \(gaload\(ga mediumtext NOT NULL, + UNIQUE KEY \(gajid\(ga (\(gajid\(ga) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +\-\- +\-\- Table structure for table \(gasalt_returns\(ga +\-\- + +DROP TABLE IF EXISTS \(gasalt_returns\(ga; +CREATE TABLE \(gasalt_returns\(ga ( + \(gafun\(ga varchar(50) NOT NULL, + \(gajid\(ga varchar(255) NOT NULL, + \(gareturn\(ga mediumtext NOT NULL, + \(gaid\(ga varchar(255) NOT NULL, + \(gasuccess\(ga varchar(10) NOT NULL, + \(gafull_ret\(ga mediumtext NOT NULL, + \(gaalter_time\(ga TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + KEY \(gaid\(ga (\(gaid\(ga), + KEY \(gajid\(ga (\(gajid\(ga), + KEY \(gafun\(ga (\(gafun\(ga) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +\-\- +\-\- Table structure for table \(gasalt_events\(ga +\-\- + +DROP TABLE IF EXISTS \(gasalt_events\(ga; +CREATE TABLE \(gasalt_events\(ga ( +\(gaid\(ga BIGINT NOT NULL AUTO_INCREMENT, +\(gatag\(ga varchar(255) NOT NULL, +\(gadata\(ga mediumtext NOT NULL, +\(gaalter_time\(ga TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +\(gamaster_id\(ga varchar(255) NOT NULL, +PRIMARY KEY (\(gaid\(ga), +KEY \(gatag\(ga (\(gatag\(ga) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required python modules: MySQLdb +.sp +To use the mysql returner, append \(aq\-\-return mysql\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mysql +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mysql \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return mysql \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.clean_old_jobs() +Called in the master\(aqs event loop every loop_interval. Archives and/or +deletes the events and job details from the database. +:return: +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.event_return(events) +Return event to mysql server +.sp +Requires that configuration be enabled via \(aqevent_return\(aq +option in master config. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.get_jids_filter(count, filter_find_job=True) +Return a list of all job ids +:param int count: show not more than the count of most recent jobs +:param bool filter_find_jobs: filter out \(aqsaltutil.find_job\(aq jobs +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.returner(ret) +Return data to a mysql server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.save_load(jid, load, minions=None) +Save the load to the specified jid id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.mysql.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.nagios_nrdp_return +.sp +Return salt data to Nagios +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +nagios.url (required) +nagios.token (required) +nagios.service (optional) +nagios.check_type (optional) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +nagios.url +nagios.token +nagios.service +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Nagios settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C + nagios: + url: http://localhost/nrdp + token: r4nd0mt0k3n + service: service\-check + + alternative.nagios: + url: http://localhost/nrdp + token: r4nd0mt0k3n + service: another\-service\-check + +To use the Nagios returner, append \(aq\-\-return nagios\(aq to the salt command. ex: + +\&.. code\-block:: bash + + salt \(aq*\(aq test.ping \-\-return nagios + +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. ex: + + salt \(aq*\(aq test.ping \-\-return nagios \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return nagios \-\-return_kwargs \(aq{\(dqservice\(dq: \(dqservice\-name\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.nagios_nrdp_return.returner(ret) +Send a message to Nagios with the data +.UNINDENT +.SS salt.returners.odbc +.sp +Return data to an ODBC compliant server. This driver was +developed with Microsoft SQL Server in mind, but theoretically +could be used to return data to any compliant ODBC database +as long as there is a working ODBC driver for it on your +minion platform. +.INDENT 0.0 +.TP +.B maintainer +.INDENT 7.0 +.IP C. 3 +.INDENT 3.0 +.IP R. 3 +Oldham (\fI\%cr@saltstack.com\fP) +.UNINDENT +.UNINDENT +.TP +.B maturity +New +.TP +.B depends +unixodbc, pyodbc, freetds (for SQL Server) +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner the minion will need +.sp +On Linux: +.INDENT 0.0 +.INDENT 3.5 +unixodbc (\fI\%http://www.unixodbc.org\fP) +pyodbc (\fIpip install pyodbc\fP) +The FreeTDS ODBC driver for SQL Server (\fI\%http://www.freetds.org\fP) +or another compatible ODBC driver +.UNINDENT +.UNINDENT +.sp +On Windows: +.INDENT 0.0 +.INDENT 3.5 +TBD +.UNINDENT +.UNINDENT +.sp +unixODBC and FreeTDS need to be configured via /etc/odbcinst.ini and +/etc/odbc.ini. +.sp +/etc/odbcinst.ini: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[TDS] +Description=TDS +Driver=/usr/lib/x86_64\-linux\-gnu/odbc/libtdsodbc.so +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +(Note the above Driver line needs to point to the location of the FreeTDS +shared library. This example is for Ubuntu 14.04.) +.sp +/etc/odbc.ini: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +[TS] +Description = \(dqSalt Returner\(dq +Driver=TDS +Server = +Port = 1433 +Database = salt +Trace = No +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Also you need the following values configured in the minion or master config. +Configure as you see fit: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +returner.odbc.dsn: \(aqTS\(aq +returner.odbc.user: \(aqsalt\(aq +returner.odbc.passwd: \(aqsalt\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.returner.odbc.dsn: \(aqTS\(aq +alternative.returner.odbc.user: \(aqsalt\(aq +alternative.returner.odbc.passwd: \(aqsalt\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Running the following commands against Microsoft SQL Server in the desired +database as the appropriate user should create the database tables +correctly. Replace with equivalent SQL for other ODBC\-compliant servers +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C + \-\- + \-\- Table structure for table \(aqjids\(aq + \-\- + + if OBJECT_ID(\(aqdbo.jids\(aq, \(aqU\(aq) is not null + DROP TABLE dbo.jids + + CREATE TABLE dbo.jids ( + jid varchar(255) PRIMARY KEY, + load varchar(MAX) NOT NULL + ); + + \-\- + \-\- Table structure for table \(aqsalt_returns\(aq + \-\- + IF OBJECT_ID(\(aqdbo.salt_returns\(aq, \(aqU\(aq) IS NOT NULL + DROP TABLE dbo.salt_returns; + + CREATE TABLE dbo.salt_returns ( + added datetime not null default (getdate()), + fun varchar(100) NOT NULL, + jid varchar(255) NOT NULL, + retval varchar(MAX) NOT NULL, + id varchar(255) NOT NULL, + success bit default(0) NOT NULL, + full_ret varchar(MAX) + ); + + CREATE INDEX salt_returns_added on dbo.salt_returns(added); + CREATE INDEX salt_returns_id on dbo.salt_returns(id); + CREATE INDEX salt_returns_jid on dbo.salt_returns(jid); + CREATE INDEX salt_returns_fun on dbo.salt_returns(fun); + +To use this returner, append \(aq\-\-return odbc\(aq to the salt command. + +\&.. code\-block:: bash + + salt \(aq*\(aq status.diskusage \-\-return odbc + +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. + +\&.. versionadded:: 2015.5.0 + +\&.. code\-block:: bash + + salt \(aq*\(aq test.ping \-\-return odbc \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return odbc \-\-return_kwargs \(aq{\(dqdsn\(dq: \(dqdsn\-name\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.returner(ret) +Return data to an odbc server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.save_load(jid, load, minions=None) +Save the load to the specified jid id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.odbc.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.pgjsonb +.sp +Return data to a PostgreSQL server with json data stored in Pg\(aqs jsonb data type +.INDENT 0.0 +.TP +.B maintainer +Dave Boucha <\fI\%dave@saltstack.com\fP>, Seth House <\fI\%shouse@saltstack.com\fP>, C. R. Oldham <\fI\%cr@saltstack.com\fP> +.TP +.B maturity +Stable +.TP +.B depends +python\-psycopg2 +.TP +.B platform +all +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +There are three PostgreSQL returners. Any can function as an external +\fI\%master job cache\fP\&. but each has different +features. SaltStack recommends +\fI\%returners.pgjsonb\fP if you are working with +a version of PostgreSQL that has the appropriate native binary JSON types. +Otherwise, review +\fI\%returners.postgres\fP and +\fI\%returners.postgres_local_cache\fP +to see which module best suits your particular needs. +.UNINDENT +.UNINDENT +.sp +To enable this returner, the minion will need the python client for PostgreSQL +installed and the following values configured in the minion or master +config. These are the defaults: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +returner.pgjsonb.host: \(aqsalt\(aq +returner.pgjsonb.user: \(aqsalt\(aq +returner.pgjsonb.pass: \(aqsalt\(aq +returner.pgjsonb.db: \(aqsalt\(aq +returner.pgjsonb.port: 5432 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +SSL is optional. The defaults are set to None. If you do not want to use SSL, +either exclude these options or set them to None. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +returner.pgjsonb.sslmode: None +returner.pgjsonb.sslcert: None +returner.pgjsonb.sslkey: None +returner.pgjsonb.sslrootcert: None +returner.pgjsonb.sslcrl: None +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +New in version 2017.5.0. + +.sp +Alternative configuration values can be used by prefacing the configuration +with \fIalternative.\fP\&. Any values not found in the alternative configuration will +be pulled from the default location. As stated above, SSL configuration is +optional. The following ssl options are simply for illustration purposes: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.pgjsonb.host: \(aqsalt\(aq +alternative.pgjsonb.user: \(aqsalt\(aq +alternative.pgjsonb.pass: \(aqsalt\(aq +alternative.pgjsonb.db: \(aqsalt\(aq +alternative.pgjsonb.port: 5432 +alternative.pgjsonb.ssl_ca: \(aq/etc/pki/mysql/certs/localhost.pem\(aq +alternative.pgjsonb.ssl_cert: \(aq/etc/pki/mysql/certs/localhost.crt\(aq +alternative.pgjsonb.ssl_key: \(aq/etc/pki/mysql/certs/localhost.key\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Should you wish the returner data to be cleaned out every so often, set +\fBkeep_jobs_seconds\fP to the number of seconds for the jobs to live in the tables. +Setting it to \fB0\fP or leaving it unset will cause the data to stay in the tables. +.sp +Should you wish to archive jobs in a different table for later processing, +set \fBarchive_jobs\fP to True. Salt will create 3 archive tables; +.INDENT 0.0 +.IP \(bu 2 +\fBjids_archive\fP +.IP \(bu 2 +\fBsalt_returns_archive\fP +.IP \(bu 2 +\fBsalt_events_archive\fP +.UNINDENT +.sp +and move the contents of \fBjids\fP, \fBsalt_returns\fP, and \fBsalt_events\fP that are +more than \fBkeep_jobs_seconds\fP seconds old to these tables. +.sp +New in version 2019.2.0. + +.sp +Use the following Pg database schema: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +CREATE DATABASE salt + WITH ENCODING \(aqutf\-8\(aq; + +\-\- +\-\- Table structure for table \(gajids\(ga +\-\- +DROP TABLE IF EXISTS jids; +CREATE TABLE jids ( + jid varchar(255) NOT NULL primary key, + load jsonb NOT NULL +); +CREATE INDEX idx_jids_jsonb on jids + USING gin (load) + WITH (fastupdate=on); + +\-\- +\-\- Table structure for table \(gasalt_returns\(ga +\-\- + +DROP TABLE IF EXISTS salt_returns; +CREATE TABLE salt_returns ( + fun varchar(50) NOT NULL, + jid varchar(255) NOT NULL, + return jsonb NOT NULL, + id varchar(255) NOT NULL, + success varchar(10) NOT NULL, + full_ret jsonb NOT NULL, + alter_time TIMESTAMP WITH TIME ZONE DEFAULT NOW()); + +CREATE INDEX idx_salt_returns_id ON salt_returns (id); +CREATE INDEX idx_salt_returns_jid ON salt_returns (jid); +CREATE INDEX idx_salt_returns_fun ON salt_returns (fun); +CREATE INDEX idx_salt_returns_return ON salt_returns + USING gin (return) with (fastupdate=on); +CREATE INDEX idx_salt_returns_full_ret ON salt_returns + USING gin (full_ret) with (fastupdate=on); + +\-\- +\-\- Table structure for table \(gasalt_events\(ga +\-\- + +DROP TABLE IF EXISTS salt_events; +DROP SEQUENCE IF EXISTS seq_salt_events_id; +CREATE SEQUENCE seq_salt_events_id; +CREATE TABLE salt_events ( + id BIGINT NOT NULL UNIQUE DEFAULT nextval(\(aqseq_salt_events_id\(aq), + tag varchar(255) NOT NULL, + data jsonb NOT NULL, + alter_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + master_id varchar(255) NOT NULL); + +CREATE INDEX idx_salt_events_tag on + salt_events (tag); +CREATE INDEX idx_salt_events_data ON salt_events + USING gin (data) with (fastupdate=on); +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required python modules: Psycopg2 +.sp +To use this returner, append \(aq\-\-return pgjsonb\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return pgjsonb +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return pgjsonb \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return pgjsonb \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.clean_old_jobs() +Called in the master\(aqs event loop every loop_interval. Archives and/or +deletes the events and job details from the database. +:return: +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.event_return(events) +Return event to Pg server +.sp +Requires that configuration be enabled via \(aqevent_return\(aq +option in master config. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.returner(ret) +Return data to a Pg server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.save_load(jid, load, minions=None) +Save the load to the specified jid id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pgjsonb.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.postgres +.sp +Return data to a postgresql server +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +There are three PostgreSQL returners. Any can function as an external +\fI\%master job cache\fP\&. but each has different +features. SaltStack recommends +\fI\%returners.pgjsonb\fP if you are working with +a version of PostgreSQL that has the appropriate native binary JSON types. +Otherwise, review +\fI\%returners.postgres\fP and +\fI\%returners.postgres_local_cache\fP +to see which module best suits your particular needs. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B maintainer +None +.TP +.B maturity +New +.TP +.B depends +psycopg2 +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner the minion will need the psycopg2 installed and +the following values configured in the minion or master config: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +returner.postgres.host: \(aqsalt\(aq +returner.postgres.user: \(aqsalt\(aq +returner.postgres.passwd: \(aqsalt\(aq +returner.postgres.db: \(aqsalt\(aq +returner.postgres.port: 5432 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.returner.postgres.host: \(aqsalt\(aq +alternative.returner.postgres.user: \(aqsalt\(aq +alternative.returner.postgres.passwd: \(aqsalt\(aq +alternative.returner.postgres.db: \(aqsalt\(aq +alternative.returner.postgres.port: 5432 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Running the following commands as the postgres user should create the database +correctly: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +psql << EOF +CREATE ROLE salt WITH PASSWORD \(aqsalt\(aq; +CREATE DATABASE salt WITH OWNER salt; +EOF + +psql \-h localhost \-U salt << EOF +\-\- +\-\- Table structure for table \(aqjids\(aq +\-\- + +DROP TABLE IF EXISTS jids; +CREATE TABLE jids ( + jid varchar(20) PRIMARY KEY, + load text NOT NULL +); + +\-\- +\-\- Table structure for table \(aqsalt_returns\(aq +\-\- + +DROP TABLE IF EXISTS salt_returns; +CREATE TABLE salt_returns ( + fun varchar(50) NOT NULL, + jid varchar(255) NOT NULL, + return text NOT NULL, + full_ret text, + id varchar(255) NOT NULL, + success varchar(10) NOT NULL, + alter_time TIMESTAMP WITH TIME ZONE DEFAULT now() +); + +CREATE INDEX idx_salt_returns_id ON salt_returns (id); +CREATE INDEX idx_salt_returns_jid ON salt_returns (jid); +CREATE INDEX idx_salt_returns_fun ON salt_returns (fun); +CREATE INDEX idx_salt_returns_updated ON salt_returns (alter_time); + +\-\- +\-\- Table structure for table \(gasalt_events\(ga +\-\- + +DROP TABLE IF EXISTS salt_events; +DROP SEQUENCE IF EXISTS seq_salt_events_id; +CREATE SEQUENCE seq_salt_events_id; +CREATE TABLE salt_events ( + id BIGINT NOT NULL UNIQUE DEFAULT nextval(\(aqseq_salt_events_id\(aq), + tag varchar(255) NOT NULL, + data text NOT NULL, + alter_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + master_id varchar(255) NOT NULL +); + +CREATE INDEX idx_salt_events_tag on salt_events (tag); + +EOF +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required python modules: psycopg2 +.sp +To use the postgres returner, append \(aq\-\-return postgres\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return postgres +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return postgres \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return postgres \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.event_return(events) +Return event to Pg server +.sp +Requires that configuration be enabled via \(aqevent_return\(aq +option in master config. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.returner(ret) +Return data to a postgres server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.save_load(jid, load, minions=None) +Save the load to the specified jid id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.postgres_local_cache +.sp +Use a postgresql server for the master job cache. This helps the job cache to +cope with scale. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +There are three PostgreSQL returners. Any can function as an external +\fI\%master job cache\fP\&. but each has different +features. SaltStack recommends +\fI\%returners.pgjsonb\fP if you are working with +a version of PostgreSQL that has the appropriate native binary JSON types. +Otherwise, review +\fI\%returners.postgres\fP and +\fI\%returners.postgres_local_cache\fP +to see which module best suits your particular needs. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B maintainer +\fI\%gjredelinghuys@gmail.com\fP +.TP +.B maturity +Stable +.TP +.B depends +psycopg2 +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner the minion will need the psycopg2 installed and +the following values configured in the master config: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +master_job_cache: postgres_local_cache +master_job_cache.postgres.host: \(aqsalt\(aq +master_job_cache.postgres.user: \(aqsalt\(aq +master_job_cache.postgres.passwd: \(aqsalt\(aq +master_job_cache.postgres.db: \(aqsalt\(aq +master_job_cache.postgres.port: 5432 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Running the following command as the postgres user should create the database +correctly: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +psql << EOF +CREATE ROLE salt WITH PASSWORD \(aqsalt\(aq; +CREATE DATABASE salt WITH OWNER salt; +EOF +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +In case the postgres database is a remote host, you\(aqll need this command also: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +ALTER ROLE salt WITH LOGIN; +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +and then: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +psql \-h localhost \-U salt << EOF +\-\- +\-\- Table structure for table \(aqjids\(aq +\-\- + +DROP TABLE IF EXISTS jids; +CREATE TABLE jids ( + jid varchar(20) PRIMARY KEY, + started TIMESTAMP WITH TIME ZONE DEFAULT now(), + tgt_type text NOT NULL, + cmd text NOT NULL, + tgt text NOT NULL, + kwargs text NOT NULL, + ret text NOT NULL, + username text NOT NULL, + arg text NOT NULL, + fun text NOT NULL +); + +\-\- +\-\- Table structure for table \(aqsalt_returns\(aq +\-\- +\-\- note that \(aqsuccess\(aq must not have NOT NULL constraint, since +\-\- some functions don\(aqt provide it. + +DROP TABLE IF EXISTS salt_returns; +CREATE TABLE salt_returns ( + added TIMESTAMP WITH TIME ZONE DEFAULT now(), + fun text NOT NULL, + jid varchar(20) NOT NULL, + return text NOT NULL, + id text NOT NULL, + success boolean +); +CREATE INDEX ON salt_returns (added); +CREATE INDEX ON salt_returns (id); +CREATE INDEX ON salt_returns (jid); +CREATE INDEX ON salt_returns (fun); + +DROP TABLE IF EXISTS salt_events; +CREATE TABLE salt_events ( + id SERIAL, + tag text NOT NULL, + data text NOT NULL, + alter_time TIMESTAMP WITH TIME ZONE DEFAULT now(), + master_id text NOT NULL +); +CREATE INDEX ON salt_events (tag); +CREATE INDEX ON salt_events (data); +CREATE INDEX ON salt_events (id); +CREATE INDEX ON salt_events (master_id); +EOF +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required python modules: psycopg2 +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.clean_old_jobs() +Clean out the old jobs from the job cache +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.event_return(events) +Return event to a postgres server +.sp +Require that configuration be enabled via \(aqevent_return\(aq +option in master config. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.get_jids() +Return a list of all job ids +For master job cache this also formats the output and returns a string +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.prep_jid(nocache=False, passed_jid=None) +Return a job id and prepare the job id directory +This is the function responsible for making sure jids don\(aqt collide +(unless its passed a jid). So do what you have to do to make sure that +stays the case +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.returner(load) +Return data to a postgres server +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.save_load(jid, clear_load, minions=None) +Save the load to the specified jid id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.postgres_local_cache.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.pushover_returner +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%pushover Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp +Return salt data via pushover (\fI\%http://www.pushover.net\fP) +.sp +New in version 2016.3.0. + +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +pushover.user (required) +pushover.token (required) +pushover.title (optional) +pushover.device (optional) +pushover.priority (optional) +pushover.expire (optional) +pushover.retry (optional) +pushover.profile (optional) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The \fBuser\fP here is your \fBuser key\fP, \fInot\fP the email address you use to +login to pushover.net. +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.pushover.user +alternative.pushover.token +alternative.pushover.title +alternative.pushover.device +alternative.pushover.priority +alternative.pushover.expire +alternative.pushover.retry +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +PushOver settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C + pushover: + user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + title: Salt Returner + device: phone + priority: \-1 + expire: 3600 + retry: 5 + + alternative.pushover: + user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + title: Salt Returner + device: phone + priority: 1 + expire: 4800 + retry: 2 + + pushover_profile: + pushover.token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + + pushover: + user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + profile: pushover_profile + + alternative.pushover: + user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + profile: pushover_profile + +To use the PushOver returner, append \(aq\-\-return pushover\(aq to the salt command. ex: + +\&.. code\-block:: bash + + salt \(aq*\(aq test.ping \-\-return pushover + +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. ex: + + salt \(aq*\(aq test.ping \-\-return pushover \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return pushover \-\-return_kwargs \(aq{\(dqtitle\(dq: \(dqSalt is awesome!\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.pushover_returner.returner(ret) +Send an PushOver message with the data +.UNINDENT +.SS salt.returners.rawfile_json +.sp +Take data from salt and \(dqreturn\(dq it into a raw file containing the json, with +one line per event. +.sp +Add the following to the minion or master configuration file. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +rawfile_json.filename: +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Default is \fB/var/log/salt/events\fP\&. +.sp +Common use is to log all events on the master. This can generate a lot of +noise, so you may wish to configure batch processing and/or configure the +\fI\%event_return_whitelist\fP or \fI\%event_return_blacklist\fP +to restrict the events that are written. +.INDENT 0.0 +.TP +.B salt.returners.rawfile_json.event_return(events) +Write event data (return data and non\-return data) to file on the master. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.rawfile_json.returner(ret) +Write the return data to a file on the minion. +.UNINDENT +.SS salt.returners.redis_return +.sp +Return data to a redis server +.sp +To enable this returner the minion will need the python client for redis +installed and the following values configured in the minion or master +config, these are the defaults: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +redis.db: \(aq0\(aq +redis.host: \(aqsalt\(aq +redis.port: 6379 +redis.password: \(aq\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +New in version 2018.3.1: Alternatively a UNIX socket can be specified by \fIunix_socket_path\fP: + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +redis.db: \(aq0\(aq +redis.unix_socket_path: /var/run/redis/redis.sock +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Cluster Mode Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +redis.db: \(aq0\(aq +redis.cluster_mode: true +redis.cluster.skip_full_coverage_check: true +redis.cluster.startup_nodes: + \- host: redis\-member\-1 + port: 6379 + \- host: redis\-member\-2 + port: 6379 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.redis.db: \(aq0\(aq +alternative.redis.host: \(aqsalt\(aq +alternative.redis.port: 6379 +alternative.redis.password: \(aq\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the redis returner, append \(aq\-\-return redis\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return redis +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return redis \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return redis \-\-return_kwargs \(aq{\(dqdb\(dq: \(dqanother\-salt\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Redis Cluster Mode Options: +.INDENT 0.0 +.TP +.B cluster_mode: \fBFalse\fP +Whether cluster_mode is enabled or not +.TP +.B cluster.startup_nodes: +A list of host, port dictionaries pointing to cluster members. At least one is required +but multiple nodes are better +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +redis.cluster.startup_nodes + \- host: redis\-member\-1 + port: 6379 + \- host: redis\-member\-2 + port: 6379 +.ft P +.fi +.UNINDENT +.UNINDENT +.TP +.B cluster.skip_full_coverage_check: \fBFalse\fP +Some cluster providers restrict certain redis commands such as CONFIG for enhanced security. +Set this option to true to skip checks that required advanced privileges. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Most cloud hosted redis clusters will require this to be set to \fBTrue\fP +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.clean_old_jobs() +Clean out minions\(aqs return data for old jobs. +.sp +Normally, hset \(aqret:\(aq are saved with a TTL, and will eventually +get cleaned by redis.But for jobs with some very late minion return, the +corresponding hset\(aqs TTL will be refreshed to a too late timestamp, we\(aqll +do manually cleaning here. +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.get_jid(jid) +Return the information returned when the specified job id was executed +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.get_jids() +Return a dict mapping all job ids to job information +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.get_load(jid) +Return the load data that marks a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.returner(ret) +Return data to a redis data store +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.save_load(jid, load, minions=None) +Save the load to the specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.redis_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.sentry_return +.sp +Salt returner that reports execution results back to sentry. The returner will +inspect the payload to identify errors and flag them as such. +.sp +Pillar needs something like: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +raven: + servers: + \- http://192.168.1.1 + \- https://sentry.example.com + public_key: deadbeefdeadbeefdeadbeefdeadbeef + secret_key: beefdeadbeefdeadbeefdeadbeefdead + project: 1 + tags: + \- os + \- master + \- saltversion + \- cpuarch +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +or using a dsn: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +raven: + dsn: https://aaaa:bbbb@app.getsentry.com/12345 + tags: + \- os + \- master + \- saltversion + \- cpuarch +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fI\%https://pypi.python.org/pypi/raven\fP must be installed. +.sp +The pillar can be hidden on sentry return by setting hide_pillar: true. +.sp +The tags list (optional) specifies grains items that will be used as sentry +tags, allowing tagging of events in the sentry ui. +.sp +To report only errors to sentry, set report_errors_only: true. +.INDENT 0.0 +.TP +.B salt.returners.sentry_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sentry_return.returner(ret) +Log outcome to sentry. The returner tries to identify errors and report +them as such. All other messages will be reported at info level. +Failed states will be appended as separate list for convenience. +.UNINDENT +.SS salt.returners.slack_returner +.sp +Return salt data via slack +.sp +New in version 2015.5.0. + +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +slack.channel (required) +slack.api_key (required) +slack.username (required) +slack.as_user (required to see the profile picture of your bot) +slack.profile (optional) +slack.changes(optional, only show changes and failed states) +slack.only_show_failed(optional, only show failed states) +slack.yaml_format(optional, format the json in yaml format) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +slack.channel +slack.api_key +slack.username +slack.as_user +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Slack settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +slack: + channel: RoomName + api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + username: user + as_user: true + +alternative.slack: + room_id: RoomName + api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + from_name: user@email.com + +slack_profile: + slack.api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + slack.from_name: user@email.com + +slack: + profile: slack_profile + channel: RoomName + +alternative.slack: + profile: slack_profile + channel: RoomName +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the Slack returner, append \(aq\-\-return slack\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return slack +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return slack \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return slack \-\-return_kwargs \(aq{\(dqchannel\(dq: \(dq#random\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.slack_returner.returner(ret) +Send an slack message with the data +.UNINDENT +.SS salt.returners.slack_webhook_return +.sp +Return salt data via Slack using Incoming Webhooks +.INDENT 0.0 +.TP +.B codeauthor +\fICarlos D. Álvaro \fP +.UNINDENT +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +slack_webhook.webhook (required, the webhook id. Just the part after: \(aqhttps://hooks.slack.com/services/\(aq) +slack_webhook.success_title (optional, short title for succeeded states. By default: \(aq{id} | Succeeded\(aq) +slack_webhook.failure_title (optional, short title for failed states. By default: \(aq{id} | Failed\(aq) +slack_webhook.author_icon (optional, a URL that with a small 16x16px image. Must be of type: GIF, JPEG, PNG, and BMP) +slack_webhook.show_tasks (optional, show identifiers for changed and failed tasks. By default: False) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +slack_webhook.webhook +slack_webhook.success_title +slack_webhook.failure_title +slack_webhook.author_icon +slack_webhook.show_tasks +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Slack settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +slack_webhook: + webhook: T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX + success_title: \(aq[{id}] | Success\(aq + failure_title: \(aq[{id}] | Failure\(aq + author_icon: https://platform.slack\-edge.com/img/default_application_icon.png + show_tasks: true + +alternative.slack_webhook: + webhook: T00000000/C00000000/YYYYYYYYYYYYYYYYYYYYYYYY + show_tasks: false +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the Slack returner, +append \(aq\-\-return slack_webhook\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return slack_webhook +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, +append \(aq\-\-return_config alternative\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return slack_webhook \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.slack_webhook_return.event_return(events) +Send event data to returner function +:param events: The Salt event return +:return: The result of the post +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.slack_webhook_return.returner(ret, **kwargs) +Send a slack message with the data through a webhook +:param ret: The Salt return +:return: The result of the post +.UNINDENT +.SS salt.returners.sms_return +.sp +Return data by SMS. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.TP +.B maintainer +Damian Myerscough +.TP +.B maturity +new +.TP +.B depends +twilio +.TP +.B platform +all +.UNINDENT +.sp +To enable this returner the minion will need the python twilio library +installed and the following values configured in the minion or master +config: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +twilio.sid: \(aqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\(aq +twilio.token: \(aqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\(aq +twilio.to: \(aq+1415XXXXXXX\(aq +twilio.from: \(aq+1650XXXXXXX\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the sms returner, append \(aq\-\-return sms\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return sms +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sms_return.returner(ret) +Return a response in an SMS message +.UNINDENT +.SS salt.returners.smtp_return +.sp +Return salt data via email +.sp +The following fields can be set in the minion conf file. Fields are optional +unless noted otherwise. +.INDENT 0.0 +.IP \(bu 2 +\fBfrom\fP (required) The name/address of the email sender. +.IP \(bu 2 +.INDENT 2.0 +.TP +.B \fBto\fP (required) The names/addresses of the email recipients; +comma\-delimited. For example: \fByou@example.com,someoneelse@example.com\fP\&. +.UNINDENT +.IP \(bu 2 +\fBhost\fP (required) The SMTP server hostname or address. +.IP \(bu 2 +\fBport\fP The SMTP server port; defaults to \fB25\fP\&. +.IP \(bu 2 +.INDENT 2.0 +.TP +.B \fBusername\fP The username used to authenticate to the server. If specified a +password is also required. It is recommended but not required to also use +TLS with this option. +.UNINDENT +.IP \(bu 2 +\fBpassword\fP The password used to authenticate to the server. +.IP \(bu 2 +\fBtls\fP Whether to secure the connection using TLS; defaults to \fBFalse\fP +.IP \(bu 2 +\fBsubject\fP The email subject line. +.IP \(bu 2 +.INDENT 2.0 +.TP +.B \fBfields\fP Which fields from the returned data to include in the subject line +of the email; comma\-delimited. For example: \fBid,fun\fP\&. Please note, \fIthe +subject line is not encrypted\fP\&. +.UNINDENT +.IP \(bu 2 +.INDENT 2.0 +.TP +.B \fBgpgowner\fP A user\(aqs \fB~/.gpg\fP directory. This must contain a gpg +public key matching the address the mail is sent to. If left unset, no +encryption will be used. Requires \fBpython\-gnupg\fP to be installed. +.UNINDENT +.IP \(bu 2 +\fBtemplate\fP The path to a file to be used as a template for the email body. +.IP \(bu 2 +.INDENT 2.0 +.TP +.B \fBrenderer\fP A Salt renderer, or render\-pipe, to use to render the email +template. Default \fBjinja\fP\&. +.UNINDENT +.UNINDENT +.sp +Below is an example of the above settings in a Salt Minion configuration file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +smtp.from: me@example.net +smtp.to: you@example.com +smtp.host: localhost +smtp.port: 1025 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location. For example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.smtp.username: saltdev +alternative.smtp.password: saltdev +alternative.smtp.tls: True +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the SMTP returner, append \(aq\-\-return smtp\(aq to the \fBsalt\fP command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return smtp +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the \fBsalt\fP command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return smtp \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the +\fBsalt\fP command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return smtp \-\-return_kwargs \(aq{\(dqto\(dq: \(dquser@domain.com\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +An easy way to test the SMTP returner is to use the development SMTP server +built into Python. The command below will start a single\-threaded SMTP server +that prints any email it receives to the console. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +python \-m smtpd \-n \-c DebuggingServer localhost:1025 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +New in version 2016.11.0. + +.sp +It is possible to send emails with selected Salt events by configuring \fBevent_return\fP option +for Salt Master. For example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +event_return: smtp + +event_return_whitelist: + \- salt/key + +smtp.from: me@example.net +smtp.to: you@example.com +smtp.host: localhost +smtp.subject: \(aqSalt Master {{act}}ed key from Minion ID: {{id}}\(aq +smtp.template: /srv/salt/templates/email.j2 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Also you need to create additional file \fB/srv/salt/templates/email.j2\fP with email body template: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +act: {{act}} +id: {{id}} +result: {{result}} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This configuration enables Salt Master to send an email when accepting or rejecting minions keys. +.INDENT 0.0 +.TP +.B salt.returners.smtp_return.event_return(events) +Return event data via SMTP +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.smtp_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.smtp_return.returner(ret) +Send an email with the data +.UNINDENT +.SS salt.returners.splunk +.sp +Send json response data to Splunk via the HTTP Event Collector +Requires the following config values to be specified in config or pillar: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +splunk_http_forwarder: + token: + indexer: + sourcetype: + index: + verify_ssl: true +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Run a test by using \fBsalt\-call test.ping \-\-return splunk\fP +.sp +Written by Scott Pack (github.com/scottjpack) +.INDENT 0.0 +.TP +.B salt.returners.splunk.event_return(events) +Return events to Splunk via the HTTP Event Collector. +Requires the Splunk HTTP Event Collector running on port 8088. +This is available on Splunk Enterprise version 6.3 or higher. +.UNINDENT +.INDENT 0.0 +.TP +.B class salt.returners.splunk.http_event_collector(token, http_event_server, host=\(aq\(aq, http_event_port=\(aq8088\(aq, http_event_server_ssl=True, max_bytes=100000, verify_ssl=True) +.INDENT 7.0 +.TP +.B sendEvent(payload, eventtime=\(aq\(aq) +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.splunk.returner(ret) +Send a message to Splunk via the HTTP Event Collector. +Requires the Splunk HTTP Event Collector running on port 8088. +This is available on Splunk Enterprise version 6.3 or higher. +.UNINDENT +.SS salt.returners.sqlite3 +.sp +Insert minion return data into a sqlite3 database +.INDENT 0.0 +.TP +.B maintainer +Mickey Malone <\fI\%mickey.malone@gmail.com\fP> +.TP +.B maturity +New +.TP +.B depends +None +.TP +.B platform +All +.UNINDENT +.sp +Sqlite3 is a serverless database that lives in a single file. +In order to use this returner the database file must exist, +have the appropriate schema defined, and be accessible to the +user whom the minion process is running as. This returner +requires the following values configured in the master or +minion config: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +sqlite3.database: /usr/lib/salt/salt.db +sqlite3.timeout: 5.0 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.sqlite3.database: /usr/lib/salt/salt.db +alternative.sqlite3.timeout: 5.0 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Use the commands to create the sqlite3 database and tables: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +sqlite3 /usr/lib/salt/salt.db << EOF +\-\- +\-\- Table structure for table \(aqjids\(aq +\-\- + +CREATE TABLE jids ( + jid TEXT PRIMARY KEY, + load TEXT NOT NULL + ); + +\-\- +\-\- Table structure for table \(aqsalt_returns\(aq +\-\- + +CREATE TABLE salt_returns ( + fun TEXT KEY, + jid TEXT KEY, + id TEXT KEY, + fun_args TEXT, + date TEXT NOT NULL, + full_ret TEXT NOT NULL, + success TEXT NOT NULL + ); +EOF +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the sqlite returner, append \(aq\-\-return sqlite3\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return sqlite3 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return sqlite3 \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return sqlite3 \-\-return_kwargs \(aq{\(dqdb\(dq: \(dq/var/lib/salt/another\-salt.db\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.get_fun(fun) +Return a dict of the last function called for all minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.get_jid(jid) +Return the information returned from a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.get_jids() +Return a list of all job ids +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.get_load(jid) +Return the load from a specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.get_minions() +Return a list of minions +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.returner(ret) +Insert minion return data into the sqlite3 database +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.save_load(jid, load, minions=None) +Save the load to the specified jid +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.sqlite3_return.save_minions(jid, minions, syndic_id=None) +Included for API consistency +.UNINDENT +.SS salt.returners.syslog_return +.sp +Return data to the host operating system\(aqs syslog facility +.sp +To use the syslog returner, append \(aq\-\-return syslog\(aq to the +salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return syslog +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +syslog.level (optional, Default: LOG_INFO) +syslog.facility (optional, Default: LOG_USER) +syslog.tag (optional, Default: salt\-minion) +syslog.options (list, optional, Default: []) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Available levels, facilities, and options can be found in the +\fBsyslog\fP docs for your python version. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The default tag comes from \fBsys.argv[0]\fP which is +usually \(dqsalt\-minion\(dq but could be different based on +the specific environment. +.UNINDENT +.UNINDENT +.sp +Configuration example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +syslog.level: \(aqLOG_ERR\(aq +syslog.facility: \(aqLOG_DAEMON\(aq +syslog.tag: \(aqmysalt\(aq +syslog.options: + \- LOG_PID +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Of course you can also nest the options: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +syslog: + level: \(aqLOG_ERR\(aq + facility: \(aqLOG_DAEMON\(aq + tag: \(aqmysalt\(aq + options: + \- LOG_PID +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by +prefacing the configuration. Any values not found +in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +alternative.syslog.level: \(aqLOG_WARN\(aq +alternative.syslog.facility: \(aqLOG_NEWS\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append +\fB\-\-return_config alternative\fP to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return syslog \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append +\-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return syslog \-\-return_kwargs \(aq{\(dqlevel\(dq: \(dqLOG_DEBUG\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Syslog server implementations may have limits on the maximum +record size received by the client. This may lead to job +return data being truncated in the syslog server\(aqs logs. For +example, for rsyslog on RHEL\-based systems, the default +maximum record size is approximately 2KB (which return data +can easily exceed). This is configurable in rsyslog.conf via +the $MaxMessageSize config parameter. Please consult your syslog +implmentation\(aqs documentation to determine how to adjust this limit. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.syslog_return.prep_jid(nocache=False, passed_jid=None) +Do any work necessary to prepare a JID, including sending a custom id +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.syslog_return.returner(ret) +Return data to the local syslog +.UNINDENT +.SS salt.returners.telegram_return +.sp +Return salt data via Telegram. +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +telegram.chat_id (required) +telegram.token (required) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Telegram settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +telegram: + chat_id: 000000000 + token: 000000000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the Telegram return, append \(aq\-\-return telegram\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return telegram +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.telegram_return.returner(ret) +Send a Telegram message with the data. +.INDENT 7.0 +.TP +.B Parameters +\fBret\fP \-\- The data to be sent. +.TP +.B Returns +Boolean if message was sent successfully. +.UNINDENT +.UNINDENT +.SS salt.returners.xmpp_return +.sp +Return salt data via xmpp +.INDENT 0.0 +.TP +.B depends +sleekxmpp >= 1.3.1 +.UNINDENT +.sp +The following fields can be set in the minion conf file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +xmpp.jid (required) +xmpp.password (required) +xmpp.recipient (required) +xmpp.profile (optional) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Alternative configuration values can be used by prefacing the configuration. +Any values not found in the alternative configuration will be pulled from +the default location: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +xmpp.jid +xmpp.password +xmpp.recipient +xmpp.profile +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +XMPP settings may also be configured as: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +xmpp: + jid: user@xmpp.domain.com/resource + password: password + recipient: user@xmpp.example.com + +alternative.xmpp: + jid: user@xmpp.domain.com/resource + password: password + recipient: someone@xmpp.example.com + +xmpp_profile: + xmpp.jid: user@xmpp.domain.com/resource + xmpp.password: password + +xmpp: + profile: xmpp_profile + recipient: user@xmpp.example.com + +alternative.xmpp: + profile: xmpp_profile + recipient: someone\-else@xmpp.example.com +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the XMPP returner, append \(aq\-\-return xmpp\(aq to the salt command. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return xmpp +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the alternative configuration, append \(aq\-\-return_config alternative\(aq to the salt command. +.sp +New in version 2015.5.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return xmpp \-\-return_config alternative +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To override individual configuration items, append \-\-return_kwargs \(aq{\(dqkey:\(dq: \(dqvalue\(dq}\(aq to the salt command. +.sp +New in version 2016.3.0. + +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return xmpp \-\-return_kwargs \(aq{\(dqrecipient\(dq: \(dqsomeone\-else@xmpp.example.com\(dq}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B class salt.returners.xmpp_return.SendMsgBot(jid, password, recipient, msg) +.INDENT 7.0 +.TP +.B start(event) +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.xmpp_return.returner(ret) +Send an xmpp message with the data +.UNINDENT +.SS salt.returners.zabbix_return +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp +Return salt data to Zabbix +.sp +The following Type: \(dqZabbix trapper\(dq with \(dqType of information\(dq Text items are required: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +Key: salt.trap.info +Key: salt.trap.warning +Key: salt.trap.high +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +To use the Zabbix returner, append \(aq\-\-return zabbix\(aq to the salt command. ex: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq test.ping \-\-return zabbix +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.zabbix_return.returner(ret) +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.zabbix_return.save_load(jid, load, minions=None) +Included for API consistency +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.zabbix_return.zabbix_send(key, output) +.UNINDENT +.INDENT 0.0 +.TP +.B salt.returners.zabbix_return.zbx() +.UNINDENT .SS Executors .sp Executors are used by minion to execute module functions. Executors can be used @@ -56374,17 +56870,17 @@ exist on the subject, to either execute in an imperative fashion where things are executed in the order in which they are defined, or in a declarative fashion where dependencies need to be mapped between objects. .sp -Imperative ordering is finite and generally considered easier to write, but +Imperative ordering is deterministic and generally considered easier to write, but declarative ordering is much more powerful and flexible but generally considered more difficult to create. .sp Salt has been created to get the best of both worlds. States are evaluated in -a finite order, which guarantees that states are always executed in the same +a deterministic order, which guarantees that states are always executed in the same order, and the states runtime is declarative, making Salt fully aware of dependencies via the \fIrequisite\fP system. .SS State Auto Ordering .sp -Salt always executes states in a finite manner, meaning that they will always +Salt always executes states in a deterministic manner, meaning that they will always execute in the same order regardless of the system that is executing them. This evaluation order makes it easy to know what order the states will be executed in, but it is important to note that the requisite system will override the ordering @@ -66117,8 +66613,8 @@ be set: .nf .ft C my\-linode\-config: - apikey: asldkgfakl;sdfjsjaslfjaklsdjf;askldjfaaklsjdfhasldsadfghdkf - password: F00barbaz + apikey: asldkgfaklsdfjsjaslfjaklsdjf;askldjfaaklsjdfhasldsadfghdkf + password: F00barbazlonglongp@ssword ssh_pubkey: ssh\-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKHEOLLbeXgaqRQT9NBAopVz366SdYc0KKX33vAnq+2R user@host ssh_key_file: ~/.ssh/id_ed25519 driver: linode @@ -66575,64 +67071,28 @@ It is possible to use Salt Cloud to spin up Windows instances, and then install Salt on them. This functionality is available on all cloud providers that are supported by Salt Cloud. However, it may not necessarily be available on all Windows images. +.SS Dependencies +.sp +Salt Cloud needs the following packages: +.INDENT 0.0 +.IP \(bu 2 +\fI\%pypsexec\fP\&. +.IP \(bu 2 +\fI\%smbprotocol\fP\&. +.UNINDENT +.sp +For versions of Salt prior to 3006, Salt Cloud has a dependency on the +\fBimpacket\fP library to set up the Windows Salt Minion installer: +.INDENT 0.0 +.IP \(bu 2 +\fI\%impacket\fP\&. +.UNINDENT .SS Requirements .sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Support \fBwinexe\fP and \fBimpacket\fP has been deprecated and will be removed in -3001. These dependencies are replaced by \fBpypsexec\fP and \fBsmbprotocol\fP -respectively. These are pure python alternatives that are compatible with all -supported python versions. -.UNINDENT -.UNINDENT -.sp -Salt Cloud makes use of \fIimpacket\fP and \fIwinexe\fP to set up the Windows Salt -Minion installer. -.sp -\fIimpacket\fP is usually available as either the \fIimpacket\fP or the -\fIpython\-impacket\fP package, depending on the distribution. More information on -\fIimpacket\fP can be found at the project home: -.INDENT 0.0 -.IP \(bu 2 -\fI\%impacket project home\fP -.UNINDENT -.sp -\fIwinexe\fP is less commonly available in distribution\-specific repositories. -However, it is currently being built for various distributions in 3rd party -channels: -.INDENT 0.0 -.IP \(bu 2 -\fI\%RPMs at pbone.net\fP -.UNINDENT -.INDENT 0.0 -.IP \(bu 2 -\fI\%openSUSE Build Service\fP -.UNINDENT -.INDENT 0.0 -.IP \(bu 2 -\fI\%pypsexec project home\fP -.UNINDENT -.INDENT 0.0 -.IP \(bu 2 -\fI\%smbprotocol project home\fP -.UNINDENT -.sp -Optionally WinRM can be used instead of \fIwinexe\fP if the python module \fIpywinrm\fP -is available and WinRM is supported on the target Windows version. Information -on pywinrm can be found at the project home: -.INDENT 0.0 -.IP \(bu 2 -\fI\%pywinrm project home\fP -.UNINDENT -.sp -Additionally, a copy of the Salt Minion Windows installer must be present on -the system on which Salt Cloud is running. This installer may be downloaded -from saltstack.com: -.INDENT 0.0 -.IP \(bu 2 -\fI\%SaltStack Download Area\fP -.UNINDENT +A copy of the Salt Minion Windows installer must be present on the system on +which Salt Cloud is running. See +\fI\%Windows \- Salt install guide\fP for information about downloading +and using the Salt Minion Windows installer. .SS Self Signed Certificates with WinRM .sp Salt\-Cloud can use versions of \fBpywinrm<=0.1.1\fP or \fBpywinrm>=0.2.1\fP\&. @@ -67045,2197 +67505,6 @@ my\-aliyun\-config: Aliyun ECS REST API documentation is available from \fI\%Aliyun ECS API\fP\&. .UNINDENT .UNINDENT -.SS Getting Started With Azure -.sp -New in version 2014.1.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 due to -the deprecation of the \(dqClassic\(dq API for Azure. Please migrate to -\fI\%Azure Resource Manager by March 1, 2023\fP -.UNINDENT -.UNINDENT -.sp -Azure is a cloud service by Microsoft providing virtual machines, SQL services, -media services, and more. This document describes how to use Salt Cloud to -create a virtual machine on Azure, with Salt installed. -.sp -More information about Azure is located at \fI\%http://www.windowsazure.com/\fP\&. -.SS Dependencies -.INDENT 0.0 -.IP \(bu 2 -\fI\%Microsoft Azure SDK for Python\fP >= 1.0.2 -.IP \(bu 2 -The python\-requests library, for Python < 2.7.9. -.IP \(bu 2 -A Microsoft Azure account -.IP \(bu 2 -OpenSSL (to generate the certificates) -.IP \(bu 2 -\fI\%Salt\fP -.UNINDENT -.SS Configuration -.sp -Set up the provider config at \fB/etc/salt/cloud.providers.d/azure.conf\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -# Note: This example is for /etc/salt/cloud.providers.d/azure.conf - -my\-azure\-config: - driver: azure - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - certificate_path: /etc/salt/azure.pem - - # Set up the location of the salt master - # - minion: - master: saltmaster.example.com - - # Optional - management_host: management.core.windows.net -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The certificate used must be generated by the user. OpenSSL can be used to -create the management certificates. Two certificates are needed: a .cer file, -which is uploaded to Azure, and a .pem file, which is stored locally. -.sp -To create the .pem file, execute the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -openssl req \-x509 \-nodes \-days 365 \-newkey rsa:1024 \-keyout /etc/salt/azure.pem \-out /etc/salt/azure.pem -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -To create the .cer file, execute the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -openssl x509 \-inform pem \-in /etc/salt/azure.pem \-outform der \-out /etc/salt/azure.cer -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -After creating these files, the .cer file will need to be uploaded to -Azure via the \(dqUpload a Management Certificate\(dq action of the \(dqManagement Certificates\(dq -tab within the \(dqSettings\(dq section of the management portal. -.sp -Optionally, a \fBmanagement_host\fP may be configured, if necessary for the region. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Changed in version 2015.8.0. - -.sp -The \fBprovider\fP parameter in cloud provider definitions was renamed to \fBdriver\fP\&. This -change was made to avoid confusion with the \fBprovider\fP parameter that is used in cloud profile -definitions. Cloud provider definitions now use \fBdriver\fP to refer to the Salt cloud module that -provides the underlying functionality to connect to a cloud host, while cloud profiles continue -to use \fBprovider\fP to refer to provider configurations that you define. -.UNINDENT -.UNINDENT -.SS Cloud Profiles -.sp -Set up an initial profile at \fB/etc/salt/cloud.profiles\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -azure\-ubuntu: - provider: my\-azure\-config - image: \(aqb39f27a8b8c64d52b05eac6a62ebad85__Ubuntu\-12_04_3\-LTS\-amd64\-server\-20131003\-en\-us\-30GB\(aq - size: Small - location: \(aqEast US\(aq - ssh_username: azureuser - ssh_password: verybadpass - slot: production - media_link: \(aqhttp://portalvhdabcdefghijklmn.blob.core.windows.net/vhds\(aq - virtual_network_name: azure\-virtual\-network - subnet_name: azure\-subnet -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -These options are described in more detail below. Once configured, the profile -can be realized with a salt command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-p azure\-ubuntu newinstance -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This will create an salt minion instance named \fBnewinstance\fP in Azure. If -the command was executed on the salt\-master, its Salt key will automatically -be signed on the master. -.sp -Once the instance has been created with salt\-minion installed, connectivity to -it can be verified with Salt: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt newinstance test.version -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Profile Options -.sp -The following options are currently available for Azure. -.SS provider -.sp -The name of the provider as configured in -\fI/etc/salt/cloud.providers.d/azure.conf\fP\&. -.SS image -.sp -The name of the image to use to create a VM. Available images can be viewed -using the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-\-list\-images my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS size -.sp -The name of the size to use to create a VM. Available sizes can be viewed using -the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-\-list\-sizes my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS location -.sp -The name of the location to create a VM in. Available locations can be viewed -using the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-\-list\-locations my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS affinity_group -.sp -The name of the affinity group to create a VM in. Either a \fBlocation\fP or an -\fBaffinity_group\fP may be specified, but not both. See Affinity Groups below. -.SS ssh_username -.sp -The user to use to log into the newly\-created VM to install Salt. -.SS ssh_password -.sp -The password to use to log into the newly\-created VM to install Salt. -.SS slot -.sp -The environment to which the hosted service is deployed. Valid values are -\fIstaging\fP or \fIproduction\fP\&. When set to \fIproduction\fP, the resulting URL of the -new VM will be \fI.cloudapp.net\fP\&. When set to \fIstaging\fP, the resulting -URL will contain a generated hash instead. -.SS media_link -.sp -This is the URL of the container that will store the disk that this VM uses. -Currently, this container must already exist. If a VM has previously been -created in the associated account, a container should already exist. In the web -interface, go into the Storage area and click one of the available storage -selections. Click the Containers link, and then copy the URL from the container -that will be used. It generally looks like: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -http://portalvhdabcdefghijklmn.blob.core.windows.net/vhds -.ft P -.fi -.UNINDENT -.UNINDENT -.SS service_name -.sp -The name of the service in which to create the VM. If this is not specified, -then a service will be created with the same name as the VM. -.SS virtual_network_name -.sp -Optional. The name of the virtual network for the VM to join. If this is not -specified, then no virtual network will be joined. -.SS subnet_name -.sp -Optional. The name of the subnet in the virtual network for the VM to join. -Requires that a \fBvirtual_network_name\fP is specified. -.SS Show Instance -.sp -This action is a thin wrapper around \fB\-\-full\-query\fP, which displays details on -a single instance only. In an environment with several machines, this will save -a user from having to sort through all instance data, just to examine a single -instance. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-a show_instance myinstance -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Destroying VMs -.sp -There are certain options which can be specified in the global cloud -configuration file (usually \fB/etc/salt/cloud\fP) which affect Salt Cloud\(aqs -behavior when a VM is destroyed. -.SS cleanup_disks -.sp -New in version 2015.8.0. - -.sp -Default is \fBFalse\fP\&. When set to \fBTrue\fP, Salt Cloud will wait for the VM to -be destroyed, then attempt to destroy the main disk that is associated with the -VM. -.SS cleanup_vhds -.sp -New in version 2015.8.0. - -.sp -Default is \fBFalse\fP\&. Requires \fBcleanup_disks\fP to be set to \fBTrue\fP\&. When -also set to \fBTrue\fP, Salt Cloud will ask Azure to delete the VHD associated -with the disk that is also destroyed. -.SS cleanup_services -.sp -New in version 2015.8.0. - -.sp -Default is \fBFalse\fP\&. Requires \fBcleanup_disks\fP to be set to \fBTrue\fP\&. When -also set to \fBTrue\fP, Salt Cloud will wait for the disk to be destroyed, then -attempt to remove the service that is associated with the VM. Because the disk -belongs to the service, the disk must be destroyed before the service can be. -.SS Managing Hosted Services -.sp -New in version 2015.8.0. - -.sp -An account can have one or more hosted services. A hosted service is required -in order to create a VM. However, as mentioned above, if a hosted service is not -specified when a VM is created, then one will automatically be created with the -name of the name. The following functions are also available. -.SS create_service -.sp -Create a hosted service. The following options are available. -.SS name -.sp -Required. The name of the hosted service to create. -.SS label -.sp -Required. A label to apply to the hosted service. -.SS description -.sp -Optional. A longer description of the hosted service. -.SS location -.sp -Required, if \fBaffinity_group\fP is not set. The location in which to create the -hosted service. Either the \fBlocation\fP or the \fBaffinity_group\fP must be set, -but not both. -.SS affinity_group -.sp -Required, if \fBlocation\fP is not set. The affinity group in which to create the -hosted service. Either the \fBlocation\fP or the \fBaffinity_group\fP must be set, -but not both. -.SS extended_properties -.sp -Optional. Dictionary containing name/value pairs of hosted service properties. -You can have a maximum of 50 extended property name/value pairs. The maximum -length of the Name element is 64 characters, only alphanumeric characters and -underscores are valid in the Name, and the name must start with a letter. -The value has a maximum length of 255 characters. -.SS CLI Example -.sp -The following example illustrates creating a hosted service. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_service my\-azure name=my\-service label=my\-service location=\(aqWest US\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_service -.sp -Return details about a specific hosted service. Can also be called with -\fBget_service\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage my\-azure name=my\-service -.ft P -.fi -.UNINDENT -.UNINDENT -.SS list_services -.sp -List all hosted services associates with the subscription. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_services my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_service -.sp -Delete a specific hosted service. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_service my\-azure name=my\-service -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Storage Accounts -.sp -New in version 2015.8.0. - -.sp -Salt Cloud can manage storage accounts associated with the account. The -following functions are available. Deprecated marked as deprecated are marked -as such as per the SDK documentation, but are still included for completeness -with the SDK. -.SS create_storage -.sp -Create a storage account. The following options are supported. -.SS name -.sp -Required. The name of the storage account to create. -.SS label -.sp -Required. A label to apply to the storage account. -.SS description -.sp -Optional. A longer description of the storage account. -.SS location -.sp -Required, if \fBaffinity_group\fP is not set. The location in which to create the -storage account. Either the \fBlocation\fP or the \fBaffinity_group\fP must be set, -but not both. -.SS affinity_group -.sp -Required, if \fBlocation\fP is not set. The affinity group in which to create the -storage account. Either the \fBlocation\fP or the \fBaffinity_group\fP must be set, -but not both. -.SS extended_properties -.sp -Optional. Dictionary containing name/value pairs of storage account properties. -You can have a maximum of 50 extended property name/value pairs. The maximum -length of the Name element is 64 characters, only alphanumeric characters and -underscores are valid in the Name, and the name must start with a letter. The -value has a maximum length of 255 characters. -.SS geo_replication_enabled -.sp -Deprecated. Replaced by the account_type parameter. -.SS account_type -.sp -Specifies whether the account supports locally\-redundant storage, geo\-redundant -storage, zone\-redundant storage, or read access geo\-redundant storage. Possible -values are: -.INDENT 0.0 -.IP \(bu 2 -Standard_LRS -.IP \(bu 2 -Standard_ZRS -.IP \(bu 2 -Standard_GRS -.IP \(bu 2 -Standard_RAGRS -.UNINDENT -.SS CLI Example -.sp -The following example illustrates creating a storage account. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_storage my\-azure name=my\-storage label=my\-storage location=\(aqWest US\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS list_storage -.sp -List all storage accounts associates with the subscription. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_storage my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_storage -.sp -Return details about a specific storage account. Can also be called with -\fBget_storage\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage my\-azure name=my\-storage -.ft P -.fi -.UNINDENT -.UNINDENT -.SS update_storage -.sp -Update details concerning a storage account. Any of the options available in -\fBcreate_storage\fP can be used, but the name cannot be changed. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_storage my\-azure name=my\-storage label=my\-storage -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_storage -.sp -Delete a specific storage account. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_storage my\-azure name=my\-storage -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_storage_keys -.sp -Returns the primary and secondary access keys for the specified storage account. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_keys my\-azure name=my\-storage -.ft P -.fi -.UNINDENT -.UNINDENT -.SS regenerate_storage_keys -.sp -Regenerate storage account keys. Requires a key_type (\(dqprimary\(dq or \(dqsecondary\(dq) -to be specified. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f regenerate_storage_keys my\-azure name=my\-storage key_type=primary -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Disks -.sp -New in version 2015.8.0. - -.sp -When a VM is created, a disk will also be created for it. The following -functions are available for managing disks. Deprecated marked as deprecated are -marked as such as per the SDK documentation, but are still included for -completeness with the SDK. -.SS show_disk -.sp -Return details about a specific disk. Can also be called with \fBget_disk\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_disk my\-azure name=my\-disk -.ft P -.fi -.UNINDENT -.UNINDENT -.SS list_disks -.sp -List all disks associates with the account. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_disks my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS update_disk -.sp -Update details for a disk. The following options are available. -.SS name -.sp -Required. The name of the disk to update. -.SS has_operating_system -.sp -Deprecated. -.SS label -.sp -Required. The label for the disk. -.SS media_link -.sp -Deprecated. The location of the disk in the account, including the storage -container that it is in. This should not need to be changed. -.SS new_name -.sp -Deprecated. If renaming the disk, the new name. -.SS os -.sp -Deprecated. -.SS CLI Example -.sp -The following example illustrates updating a disk. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_disk my\-azure name=my\-disk label=my\-disk -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_disk -.sp -Delete a specific disk. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_disk my\-azure name=my\-disk -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Service Certificates -.sp -New in version 2015.8.0. - -.sp -Stored at the cloud service level, these certificates are used by your deployed -services. For more information on service certificates, see the following link: -.INDENT 0.0 -.IP \(bu 2 -\fI\%Manage Certificates\fP -.UNINDENT -.sp -The following functions are available. -.SS list_service_certificates -.sp -List service certificates associated with the account. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_service_certificates my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_service_certificate -.sp -Show the data for a specific service certificate associated with the account. -The \fBname\fP, \fBthumbprint\fP, and \fBthumbalgorithm\fP can be obtained from -\fBlist_service_certificates\fP\&. Can also be called with -\fBget_service_certificate\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_service_certificate my\-azure name=my_service_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.SS add_service_certificate -.sp -Add a service certificate to the account. This requires that a certificate -already exists, which is then added to the account. For more information on -creating the certificate itself, see: -.INDENT 0.0 -.IP \(bu 2 -\fI\%Create a Service Certificate for Azure\fP -.UNINDENT -.sp -The following options are available. -.SS name -.sp -Required. The name of the hosted service that the certificate will belong to. -.SS data -.sp -Required. The base\-64 encoded form of the pfx file. -.SS certificate_format -.sp -Required. The service certificate format. The only supported value is pfx. -.SS password -.sp -The certificate password. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f add_service_certificate my\-azure name=my\-cert \e - data=\(aq...CERT_DATA...\(aq certificate_format=pfx password=verybadpass -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_service_certificate -.sp -Delete a service certificate from the account. The \fBname\fP, \fBthumbprint\fP, -and \fBthumbalgorithm\fP can be obtained from \fBlist_service_certificates\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_service_certificate my\-azure \e - name=my_service_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Management Certificates -.sp -New in version 2015.8.0. - -.sp -A Azure management certificate is an X.509 v3 certificate used to authenticate -an agent, such as Visual Studio Tools for Windows Azure or a client application -that uses the Service Management API, acting on behalf of the subscription owner -to manage subscription resources. Azure management certificates are uploaded to -Azure and stored at the subscription level. The management certificate store can -hold up to 100 certificates per subscription. These certificates are used to -authenticate your Windows Azure deployment. -.sp -For more information on management certificates, see the following link. -.INDENT 0.0 -.IP \(bu 2 -\fI\%Manage Certificates\fP -.UNINDENT -.sp -The following functions are available. -.SS list_management_certificates -.sp -List management certificates associated with the account. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_management_certificates my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_management_certificate -.sp -Show the data for a specific management certificate associated with the account. -The \fBname\fP, \fBthumbprint\fP, and \fBthumbalgorithm\fP can be obtained from -\fBlist_management_certificates\fP\&. Can also be called with -\fBget_management_certificate\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_management_certificate my\-azure name=my_management_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.SS add_management_certificate -.sp -Management certificates must have a key length of at least 2048 bits and should -reside in the Personal certificate store. When the certificate is installed on -the client, it should contain the private key of the certificate. To upload to -the certificate to the Microsoft Azure Management Portal, you must export it as -a .cer format file that does not contain the private key. For more information -on creating management certificates, see the following link: -.INDENT 0.0 -.IP \(bu 2 -\fI\%Create and Upload a Management Certificate for Azure\fP -.UNINDENT -.sp -The following options are available. -.SS public_key -.sp -A base64 representation of the management certificate public key. -.SS thumbprint -.sp -The thumb print that uniquely identifies the management certificate. -.SS data -.sp -The certificate\(aqs raw data in base\-64 encoded .cer format. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f add_management_certificate my\-azure public_key=\(aq...PUBKEY...\(aq \e - thumbprint=0123456789ABCDEF data=\(aq...CERT_DATA...\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_management_certificate -.sp -Delete a management certificate from the account. The \fBthumbprint\fP can be -obtained from \fBlist_management_certificates\fP\&. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_management_certificate my\-azure thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Virtual Network Management -.sp -New in version 2015.8.0. - -.sp -The following are functions for managing virtual networks. -.SS list_virtual_networks -.sp -List input endpoints associated with the deployment. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_virtual_networks my\-azure service=myservice deployment=mydeployment -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Input Endpoints -.sp -New in version 2015.8.0. - -.sp -Input endpoints are used to manage port access for roles. Because endpoints -cannot be managed by the Azure Python SDK, Salt Cloud uses the API directly. -With versions of Python before 2.7.9, the \fBrequests\-python\fP package needs to -be installed in order for this to work. Additionally, the following needs to be -set in the master\(aqs configuration file: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -backend: requests -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The following functions are available. -.SS list_input_endpoints -.sp -List input endpoints associated with the deployment -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_input_endpoints my\-azure service=myservice deployment=mydeployment -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_input_endpoint -.sp -Show an input endpoint associated with the deployment -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_input_endpoint my\-azure service=myservice \e - deployment=mydeployment name=SSH -.ft P -.fi -.UNINDENT -.UNINDENT -.SS add_input_endpoint -.sp -Add an input endpoint to the deployment. Please note that there may be a delay -before the changes show up. The following options are available. -.SS service -.sp -Required. The name of the hosted service which the VM belongs to. -.SS deployment -.sp -Required. The name of the deployment that the VM belongs to. If the VM was -created with Salt Cloud, the deployment name probably matches the VM name. -.SS role -.sp -Required. The name of the role that the VM belongs to. If the VM was created -with Salt Cloud, the role name probably matches the VM name. -.SS name -.sp -Required. The name of the input endpoint. This typically matches the port that -the endpoint is set to. For instance, port 22 would be called SSH. -.SS port -.sp -Required. The public (Internet\-facing) port that is used for the endpoint. -.SS local_port -.sp -Optional. The private port on the VM itself that will be matched with the port. -This is typically the same as the \fBport\fP\&. If this value is not specified, it -will be copied from \fBport\fP\&. -.SS protocol -.sp -Required. Either \fBtcp\fP or \fBudp\fP\&. -.SS enable_direct_server_return -.sp -Optional. If an internal load balancer exists in the account, it can be used -with a direct server return. The default value is \fBFalse\fP\&. Please see the -following article for an explanation of this option. -.INDENT 0.0 -.IP \(bu 2 -\fI\%Load Balancing for Azure Infrastructure Services\fP -.UNINDENT -.SS timeout_for_tcp_idle_connection -.sp -Optional. The default value is \fB4\fP\&. Please see the following article for an -explanation of this option. -.INDENT 0.0 -.IP \(bu 2 -\fI\%Configurable Idle Timeout for Azure Load Balancer\fP -.UNINDENT -.SS CLI Example -.sp -The following example illustrates adding an input endpoint. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f add_input_endpoint my\-azure service=myservice \e - deployment=mydeployment role=myrole name=HTTP local_port=80 \e - port=80 protocol=tcp enable_direct_server_return=False \e - timeout_for_tcp_idle_connection=4 -.ft P -.fi -.UNINDENT -.UNINDENT -.SS update_input_endpoint -.sp -Updates the details for a specific input endpoint. All options from -\fBadd_input_endpoint\fP are supported. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_input_endpoint my\-azure service=myservice \e - deployment=mydeployment role=myrole name=HTTP local_port=80 \e - port=80 protocol=tcp enable_direct_server_return=False \e - timeout_for_tcp_idle_connection=4 -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_input_endpoint -.sp -Delete an input endpoint from the deployment. Please note that there may be a -delay before the changes show up. The following items are required. -.SS CLI Example -.sp -The following example illustrates deleting an input endpoint. -.SS service -.sp -The name of the hosted service which the VM belongs to. -.SS deployment -.sp -The name of the deployment that the VM belongs to. If the VM was created with -Salt Cloud, the deployment name probably matches the VM name. -.SS role -.sp -The name of the role that the VM belongs to. If the VM was created with Salt -Cloud, the role name probably matches the VM name. -.SS name -.sp -The name of the input endpoint. This typically matches the port that the -endpoint is set to. For instance, port 22 would be called SSH. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_input_endpoint my\-azure service=myservice \e - deployment=mydeployment role=myrole name=HTTP -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Affinity Groups -.sp -New in version 2015.8.0. - -.sp -Affinity groups allow you to group your Azure services to optimize performance. -All services and VMs within an affinity group will be located in the same -region. For more information on Affinity groups, see the following link: -.INDENT 0.0 -.IP \(bu 2 -\fI\%Create an Affinity Group in the Management Portal\fP -.UNINDENT -.sp -The following functions are available. -.SS list_affinity_groups -.sp -List input endpoints associated with the account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_affinity_groups my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS show_affinity_group -.sp -Show an affinity group associated with the account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_affinity_group my\-azure service=myservice \e - deployment=mydeployment name=SSH -.ft P -.fi -.UNINDENT -.UNINDENT -.SS create_affinity_group -.sp -Create a new affinity group. The following options are supported. -.SS name -.sp -Required. The name of the new affinity group. -.SS location -.sp -Required. The region in which the affinity group lives. -.SS label -.sp -Required. A label describing the new affinity group. -.SS description -.sp -Optional. A longer description of the affinity group. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_affinity_group my\-azure name=my_affinity_group \e - label=my\-affinity\-group location=\(aqWest US\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS update_affinity_group -.sp -Update an affinity group\(aqs properties -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_affinity_group my\-azure name=my_group label=my_group -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delete_affinity_group -.sp -Delete a specific affinity group associated with the account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_affinity_group my\-azure name=my_affinity_group -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Managing Blob Storage -.sp -New in version 2015.8.0. - -.sp -Azure storage containers and their contents can be managed with Salt Cloud. This -is not as elegant as using one of the other available clients in Windows, but it -benefits Linux and Unix users, as there are fewer options available on those -platforms. -.SS Blob Storage Configuration -.sp -Blob storage must be configured differently than the standard Azure -configuration. Both a \fBstorage_account\fP and a \fBstorage_key\fP must be -specified either through the Azure provider configuration (in addition to the -other Azure configuration) or via the command line. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -storage_account: mystorage -storage_key: ffhj334fDSGFEGDFGFDewr34fwfsFSDFwe== -.ft P -.fi -.UNINDENT -.UNINDENT -.SS storage_account -.sp -This is one of the storage accounts that is available via the \fBlist_storage\fP -function. -.SS storage_key -.sp -Both a primary and a secondary \fBstorage_key\fP can be obtained by running the -\fBshow_storage_keys\fP function. Either key may be used. -.SS Blob Functions -.sp -The following functions are made available through Salt Cloud for managing -blog storage. -.SS make_blob_url -.sp -Creates the URL to access a blob -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f make_blob_url my\-azure container=mycontainer blob=myblob -.ft P -.fi -.UNINDENT -.UNINDENT -.SS container -.sp -Name of the container. -.SS blob -.sp -Name of the blob. -.SS account -.sp -Name of the storage account. If not specified, derives the host base -from the provider configuration. -.SS protocol -.sp -Protocol to use: \(aqhttp\(aq or \(aqhttps\(aq. If not specified, derives the host -base from the provider configuration. -.SS host_base -.sp -Live host base URL. If not specified, derives the host base from the -provider configuration. -.SS list_storage_containers -.sp -List containers associated with the storage account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_storage_containers my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS create_storage_container -.sp -Create a storage container -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of container to create. -.SS meta_name_values -.sp -Optional. A dict with name_value pairs to associate with the -container as metadata. Example:{\(aqCategory\(aq:\(aqtest\(aq} -.SS blob_public_access -.sp -Optional. Possible values include: container, blob -.SS fail_on_exist -.sp -Specify whether to throw an exception when the container exists. -.SS show_storage_container -.sp -Show a container associated with the storage account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of container to show. -.SS show_storage_container_metadata -.sp -Show a storage container\(aqs metadata -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container_metadata my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of container to show. -.SS lease_id -.sp -If specified, show_storage_container_metadata only succeeds if the -container\(aqs lease is active and matches this ID. -.SS set_storage_container_metadata -.sp -Set a storage container\(aqs metadata -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_storage_container my\-azure name=mycontainer \e - x_ms_meta_name_values=\(aq{\(dqmy_name\(dq: \(dqmy_value\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of existing container. -meta_name_values -\fB\(ga\(ga\(ga\(ga\(ga\(ga\(ga\(ga\(ga\(ga\(ga\(ga\fP -A dict containing name, value for metadata. -Example: {\(aqcategory\(aq:\(aqtest\(aq} -lease_id -\fB\(ga\(ga\(ga\(ga\fP -If specified, set_storage_container_metadata only succeeds if the -container\(aqs lease is active and matches this ID. -.SS show_storage_container_acl -.sp -Show a storage container\(aqs acl -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container_acl my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of existing container. -.SS lease_id -.sp -If specified, show_storage_container_acl only succeeds if the -container\(aqs lease is active and matches this ID. -.SS set_storage_container_acl -.sp -Set a storage container\(aqs acl -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of existing container. -.SS signed_identifiers -.sp -SignedIdentifiers instance -.SS blob_public_access -.sp -Optional. Possible values include: container, blob -.SS lease_id -.sp -If specified, set_storage_container_acl only succeeds if the -container\(aqs lease is active and matches this ID. -.SS delete_storage_container -.sp -Delete a container associated with the storage account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of container to create. -.SS fail_not_exist -.sp -Specify whether to throw an exception when the container exists. -.SS lease_id -.sp -If specified, delete_storage_container only succeeds if the -container\(aqs lease is active and matches this ID. -.SS lease_storage_container -.sp -Lease a container associated with the storage account -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f lease_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.SS name -.sp -Name of container to create. -.SS lease_action -.sp -Required. Possible values: acquire|renew|release|break|change -.SS lease_id -.sp -Required if the container has an active lease. -.SS lease_duration -.sp -Specifies the duration of the lease, in seconds, or negative one -(\-1) for a lease that never expires. A non\-infinite lease can be -between 15 and 60 seconds. A lease duration cannot be changed -using renew or change. For backwards compatibility, the default is -60, and the value is only used on an acquire operation. -.SS lease_break_period -.sp -Optional. For a break operation, this is the proposed duration of -seconds that the lease should continue before it is broken, between -0 and 60 seconds. This break period is only used if it is shorter -than the time remaining on the lease. If longer, the time remaining -on the lease is used. A new lease will not be available before the -break period has expired, but the lease may be held for longer than -the break period. If this header does not appear with a break -operation, a fixed\-duration lease breaks after the remaining lease -period elapses, and an infinite lease breaks immediately. -.SS proposed_lease_id -.sp -Optional for acquire, required for change. Proposed lease ID, in a -GUID string format. -.SS list_blobs -.sp -List blobs associated with the container -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_blobs my\-azure container=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.SS container -.sp -The name of the storage container -.SS prefix -.sp -Optional. Filters the results to return only blobs whose names -begin with the specified prefix. -.SS marker -.sp -Optional. A string value that identifies the portion of the list -to be returned with the next list operation. The operation returns -a marker value within the response body if the list returned was -not complete. The marker value may then be used in a subsequent -call to request the next set of list items. The marker value is -opaque to the client. -.SS maxresults -.sp -Optional. Specifies the maximum number of blobs to return, -including all BlobPrefix elements. If the request does not specify -maxresults or specifies a value greater than 5,000, the server will -return up to 5,000 items. Setting maxresults to a value less than -or equal to zero results in error response code 400 (Bad Request). -.SS include -.sp -Optional. Specifies one or more datasets to include in the -response. To specify more than one of these options on the URI, -you must separate each option with a comma. Valid values are: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -snapshots: - Specifies that snapshots should be included in the - enumeration. Snapshots are listed from oldest to newest in - the response. -metadata: - Specifies that blob metadata be returned in the response. -uncommittedblobs: - Specifies that blobs for which blocks have been uploaded, - but which have not been committed using Put Block List - (REST API), be included in the response. -copy: - Version 2012\-02\-12 and newer. Specifies that metadata - related to any current or previous Copy Blob operation - should be included in the response. -.ft P -.fi -.UNINDENT -.UNINDENT -.SS delimiter -.sp -Optional. When the request includes this parameter, the operation -returns a BlobPrefix element in the response body that acts as a -placeholder for all blobs whose names begin with the same -substring up to the appearance of the delimiter character. The -delimiter may be a single character or a string. -.SS show_blob_service_properties -.sp -Show a blob\(aqs service properties -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_blob_service_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS set_blob_service_properties -.sp -Sets the properties of a storage account\(aqs Blob service, including -Windows Azure Storage Analytics. You can also use this operation to -set the default request version for all incoming requests that do not -have a version specified. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_blob_service_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS properties -.sp -a StorageServiceProperties object. -.SS timeout -.sp -Optional. The timeout parameter is expressed in seconds. -.SS show_blob_properties -.sp -Returns all user\-defined metadata, standard HTTP properties, and -system properties for the blob. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_blob_properties my\-azure container=mycontainer blob=myblob -.ft P -.fi -.UNINDENT -.UNINDENT -.SS container -.sp -Name of existing container. -.SS blob -.sp -Name of existing blob. -.SS lease_id -.sp -Required if the blob has an active lease. -.SS set_blob_properties -.sp -Set a blob\(aqs properties -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_blob_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.SS container -.sp -Name of existing container. -.SS blob -.sp -Name of existing blob. -.SS blob_cache_control -.sp -Optional. Modifies the cache control string for the blob. -.SS blob_content_type -.sp -Optional. Sets the blob\(aqs content type. -.SS blob_content_md5 -.sp -Optional. Sets the blob\(aqs MD5 hash. -.SS blob_content_encoding -.sp -Optional. Sets the blob\(aqs content encoding. -.SS blob_content_language -.sp -Optional. Sets the blob\(aqs content language. -.SS lease_id -.sp -Required if the blob has an active lease. -.SS blob_content_disposition -.sp -Optional. Sets the blob\(aqs Content\-Disposition header. -The Content\-Disposition response header field conveys additional -information about how to process the response payload, and also can -be used to attach additional metadata. For example, if set to -attachment, it indicates that the user\-agent should not display the -response, but instead show a Save As dialog with a filename other -than the blob name specified. -.SS put_blob -.sp -Upload a blob -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f put_blob my\-azure container=base name=top.sls blob_path=/srv/salt/top.sls -salt\-cloud \-f put_blob my\-azure container=base name=content.txt blob_content=\(aqSome content\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.SS container -.sp -Name of existing container. -.SS name -.sp -Name of existing blob. -.SS blob_path -.sp -The path on the local machine of the file to upload as a blob. Either -this or blob_content must be specified. -.SS blob_content -.sp -The actual content to be uploaded as a blob. Either this or blob_path -must me specified. -.SS cache_control -.sp -Optional. The Blob service stores this value but does not use or -modify it. -.SS content_language -.sp -Optional. Specifies the natural languages used by this resource. -.SS content_md5 -.sp -Optional. An MD5 hash of the blob content. This hash is used to -verify the integrity of the blob during transport. When this header -is specified, the storage service checks the hash that has arrived -with the one that was sent. If the two hashes do not match, the -operation will fail with error code 400 (Bad Request). -.SS blob_content_type -.sp -Optional. Set the blob\(aqs content type. -.SS blob_content_encoding -.sp -Optional. Set the blob\(aqs content encoding. -.SS blob_content_language -.sp -Optional. Set the blob\(aqs content language. -.SS blob_content_md5 -.sp -Optional. Set the blob\(aqs MD5 hash. -.SS blob_cache_control -.sp -Optional. Sets the blob\(aqs cache control. -.SS meta_name_values -.sp -A dict containing name, value for metadata. -.SS lease_id -.sp -Required if the blob has an active lease. -.SS get_blob -.sp -Download a blob -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f get_blob my\-azure container=base name=top.sls local_path=/srv/salt/top.sls -salt\-cloud \-f get_blob my\-azure container=base name=content.txt return_content=True -.ft P -.fi -.UNINDENT -.UNINDENT -.SS container -.sp -Name of existing container. -.SS name -.sp -Name of existing blob. -.SS local_path -.sp -The path on the local machine to download the blob to. Either this or -return_content must be specified. -.SS return_content -.sp -Whether or not to return the content directly from the blob. If -specified, must be True or False. Either this or the local_path must -be specified. -.SS snapshot -.sp -Optional. The snapshot parameter is an opaque DateTime value that, -when present, specifies the blob snapshot to retrieve. -.SS lease_id -.sp -Required if the blob has an active lease. -.SS progress_callback -.sp -callback for progress with signature function(current, total) where -current is the number of bytes transferred so far, and total is the -size of the blob. -.SS max_connections -.sp -Maximum number of parallel connections to use when the blob size -exceeds 64MB. -Set to 1 to download the blob chunks sequentially. -Set to 2 or more to download the blob chunks in parallel. This uses -more system resources but will download faster. -.SS max_retries -.sp -Number of times to retry download of blob chunk if an error occurs. -.SS retry_wait -.sp -Sleep time in secs between retries. -.SS Getting Started With Azure ARM -.sp -New in version 2016.11.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.sp -Azure is a cloud service by Microsoft providing virtual machines, SQL services, -media services, and more. Azure ARM (aka, the Azure Resource Manager) is a next -generation version of the Azure portal and API. This document describes how to -use Salt Cloud to create a virtual machine on Azure ARM, with Salt installed. -.sp -More information about Azure is located at \fI\%http://www.windowsazure.com/\fP\&. -.SS Dependencies -.INDENT 0.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0rc6 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.4 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 0.33.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 0.30.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.32.0 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.IP \(bu 2 -A Microsoft Azure account -.IP \(bu 2 -\fI\%Salt\fP -.UNINDENT -.SS Installation Tips -.sp -Because the \fBazure\fP library requires the \fBcryptography\fP library, which is -compiled on\-the\-fly by \fBpip\fP, you may need to install the development tools -for your operating system. -.sp -Before you install \fBazure\fP with \fBpip\fP, you should make sure that the -required libraries are installed. -.SS Debian -.sp -For Debian and Ubuntu, the following command will ensure that the required -dependencies are installed: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -sudo apt\-get install build\-essential libssl\-dev libffi\-dev python\-dev -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Red Hat -.sp -For Fedora and RHEL\-derivatives, the following command will ensure that the -required dependencies are installed: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -sudo yum install gcc libffi\-devel python\-devel openssl\-devel -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Configuration -.sp -Set up the provider config at \fB/etc/salt/cloud.providers.d/azurearm.conf\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -# Note: This example is for /etc/salt/cloud.providers.d/azurearm.conf - -my\-azurearm\-config: - driver: azurearm - master: salt.example.com - subscription_id: 01234567\-890a\-bcde\-f012\-34567890abdc - - # https://apps.dev.microsoft.com/#/appList - username: @.onmicrosoft.com - password: verybadpass - location: westus - resource_group: my_rg - - # Optional - network_resource_group: my_net_rg - cleanup_disks: True - cleanup_vhds: True - cleanup_data_disks: True - cleanup_interfaces: True - custom_data: \(aqThis is custom data\(aq - expire_publisher_cache: 604800 # 7 days - expire_offer_cache: 518400 # 6 days - expire_sku_cache: 432000 # 5 days - expire_version_cache: 345600 # 4 days - expire_group_cache: 14400 # 4 hours - expire_interface_cache: 3600 # 1 hour - expire_network_cache: 3600 # 1 hour -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Cloud Profiles -.sp -Set up an initial profile at \fB/etc/salt/cloud.profiles\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -azure\-ubuntu\-pass: - provider: my\-azure\-config - image: Canonical|UbuntuServer|14.04.5\-LTS|14.04.201612050 - size: Standard_D1_v2 - location: eastus - ssh_username: azureuser - ssh_password: verybadpass - -azure\-ubuntu\-key: - provider: my\-azure\-config - image: Canonical|UbuntuServer|14.04.5\-LTS|14.04.201612050 - size: Standard_D1_v2 - location: eastus - ssh_username: azureuser - ssh_publickeyfile: /path/to/ssh_public_key.pub - -azure\-win2012: - provider: my\-azure\-config - image: MicrosoftWindowsServer|WindowsServer|2012\-R2\-Datacenter|latest - size: Standard_D1_v2 - location: westus - win_username: azureuser - win_password: verybadpass -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -These options are described in more detail below. Once configured, the profile -can be realized with a salt command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-p azure\-ubuntu newinstance -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This will create an salt minion instance named \fBnewinstance\fP in Azure. If -the command was executed on the salt\-master, its Salt key will automatically -be signed on the master. -.sp -Once the instance has been created with salt\-minion installed, connectivity to -it can be verified with Salt: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt newinstance test.version -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Profile Options -.sp -The following options are currently available for Azure ARM. -.SS provider -.sp -The name of the provider as configured in -\fI/etc/salt/cloud.providers.d/azure.conf\fP\&. -.SS image -.sp -Required. The name of the image to use to create a VM. Available images can be -viewed using the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-\-list\-images my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -As you will see in \fB\-\-list\-images\fP, image names are comprised of the following -fields, separated by the pipe (\fB|\fP) character: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -publisher: For example, Canonical or MicrosoftWindowsServer -offer: For example, UbuntuServer or WindowsServer -sku: Such as 14.04.5\-LTS or 2012\-R2\-Datacenter -version: Such as 14.04.201612050 or latest -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -It is possible to specify the URL or resource ID path of a custom image that you -have access to, such as: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -https://.blob.core.windows.net/system/Microsoft.Compute/Images//template\-osDisk.01234567\-890a\-bcdef0123\-4567890abcde.vhd -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -or: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -/subscriptions/XXXXXXXX\-XXXX\-XXXX\-XXXX\-XXXXXXXXXXXX/resourceGroups/myRG/providers/Microsoft.Compute/images/myImage -.ft P -.fi -.UNINDENT -.UNINDENT -.SS size -.sp -Required. The name of the size to use to create a VM. Available sizes can be -viewed using the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-\-list\-sizes my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS location -.sp -Required. The name of the location to create a VM in. Available locations can -be viewed using the following command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-\-list\-locations my\-azure\-config -.ft P -.fi -.UNINDENT -.UNINDENT -.SS ssh_username -.sp -Required for Linux. The admin user to add on the instance. It is also used to log -into the newly\-created VM to install Salt. -.SS ssh_keyfile -.sp -Required if using SSH key authentication. The path on the Salt master to the SSH private -key used during the minion bootstrap process. -.SS ssh_publickeyfile -.sp -Use either \fBssh_publickeyfile\fP or \fBssh_password\fP\&. The path on the Salt master to the -SSH public key which will be pushed to the Linux VM. -.SS ssh_password -.sp -Use either \fBssh_publickeyfile\fP or \fBssh_password\fP\&. The password for the admin user on -the newly\-created Linux virtual machine. -.SS win_username -.sp -Required for Windows. The user to use to log into the newly\-created Windows VM -to install Salt. -.SS win_password -.sp -Required for Windows. The password to use to log into the newly\-created Windows -VM to install Salt. -.SS win_installer -.sp -Required for Windows. The path to the Salt installer to be uploaded. -.SS resource_group -.sp -Required. The resource group that all VM resources (VM, network interfaces, -etc) will be created in. -.SS network_resource_group -.sp -Optional. If specified, then the VM will be connected to the virtual network -in this resource group, rather than the parent resource group of the instance. -The VM interfaces and IPs will remain in the configured \fBresource_group\fP with -the VM. -.SS network -.sp -Required. The virtual network that the VM will be spun up in. -.SS subnet -.sp -Optional. The subnet inside the virtual network that the VM will be spun up in. -Default is \fBdefault\fP\&. -.SS allocate_public_ip -.sp -Optional. Default is \fBFalse\fP\&. If set to \fBTrue\fP, a public IP will -be created and assigned to the VM. -.SS load_balancer -.sp -Optional. The load\-balancer for the VM\(aqs network interface to join. If -specified the backend_pool option need to be set. -.SS backend_pool -.sp -Optional. Required if the load_balancer option is set. The load\-balancer\(aqs -Backend Pool the VM\(aqs network interface will join. -.SS iface_name -.sp -Optional. The name to apply to the VM\(aqs network interface. If not supplied, the -value will be set to \fB\-iface0\fP\&. -.SS dns_servers -.sp -Optional. A \fBlist\fP of the DNS servers to configure for the network interface -(will be set on the VM by the DHCP of the VNET). -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my\-azurearm\-profile: - provider: azurearm\-provider - network: mynetwork - dns_servers: - \- 10.1.1.4 - \- 10.1.1.5 -.ft P -.fi -.UNINDENT -.UNINDENT -.SS availability_set -.sp -Optional. If set, the VM will be added to the specified availability set. -.SS volumes -.sp -Optional. A list of dictionaries describing data disks to attach to the -instance can be specified using this setting. The data disk dictionaries are -passed entirely to the \fI\%Azure DataDisk object\fP, -so ad\-hoc options can be handled as long as they are valid properties of the -object. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -volumes: -\- disk_size_gb: 50 - caching: ReadWrite -\- disk_size_gb: 100 - caching: ReadWrite - managed_disk: - storage_account_type: Standard_LRS -.ft P -.fi -.UNINDENT -.UNINDENT -.SS cleanup_disks -.sp -Optional. Default is \fBFalse\fP\&. If set to \fBTrue\fP, disks will be cleaned up -when the VM that they belong to is deleted. -.SS cleanup_vhds -.sp -Optional. Default is \fBFalse\fP\&. If set to \fBTrue\fP, VHDs will be cleaned up -when the VM and disk that they belong to are deleted. Requires \fBcleanup_disks\fP -to be set to \fBTrue\fP\&. -.SS cleanup_data_disks -.sp -Optional. Default is \fBFalse\fP\&. If set to \fBTrue\fP, data disks (non\-root -volumes) will be cleaned up whtn the VM that they are attached to is deleted. -Requires \fBcleanup_disks\fP to be set to \fBTrue\fP\&. -.SS cleanup_interfaces -.sp -Optional. Default is \fBFalse\fP\&. Normally when a VM is deleted, its associated -interfaces and IPs are retained. This is useful if you expect the deleted VM -to be recreated with the same name and network settings. If you would like -interfaces and IPs to be deleted when their associated VM is deleted, set this -to \fBTrue\fP\&. -.SS userdata -.sp -Optional. Any custom cloud data that needs to be specified. How this data is -used depends on the operating system and image that is used. For instance, -Linux images that use \fBcloud\-init\fP will import this data for use with that -program. Some Windows images will create a file with a copy of this data, and -others will ignore it. If a Windows image creates a file, then the location -will depend upon the version of Windows. This will be ignored if the -\fBuserdata_file\fP is specified. -.SS userdata_file -.sp -Optional. The path to a file to be read and submitted to Azure as user data. -How this is used depends on the operating system that is being deployed. If -used, any \fBuserdata\fP setting will be ignored. -.SS userdata_sendkeys -.sp -Optional. Set to \fBTrue\fP in order to generate salt minion keys and provide -them as variables to the userdata script when running it through the template -renderer. The keys can be referenced as \fB{{opts[\(aqpriv_key\(aq]}}\fP and -\fB{{opts[\(aqpub_key\(aq]}}\fP\&. -.SS userdata_template -.sp -Optional. Enter the renderer, such as \fBjinja\fP, to be used for the userdata -script template. -.SS wait_for_ip_timeout -.sp -Optional. Default is \fB600\fP\&. When waiting for a VM to be created, Salt Cloud -will attempt to connect to the VM\(aqs IP address until it starts responding. This -setting specifies the maximum time to wait for a response. -.SS wait_for_ip_interval -.sp -Optional. Default is \fB10\fP\&. How long to wait between attempts to connect to -the VM\(aqs IP. -.SS wait_for_ip_interval_multiplier -.sp -Optional. Default is \fB1\fP\&. Increase the interval by this multiplier after -each request; helps with throttling. -.SS expire_publisher_cache -.sp -Optional. Default is \fB604800\fP\&. When fetching image data using -\fB\-\-list\-images\fP, a number of web calls need to be made to the Azure ARM API. -This is normally very fast when performed using a VM that exists inside Azure -itself, but can be very slow when made from an external connection. -.sp -By default, the publisher data will be cached, and only updated every \fB604800\fP -seconds (7 days). If you need the publisher cache to be updated at a different -frequency, change this setting. Setting it to \fB0\fP will turn off the publisher -cache. -.SS expire_offer_cache -.sp -Optional. Default is \fB518400\fP\&. See \fBexpire_publisher_cache\fP for details on -why this exists. -.sp -By default, the offer data will be cached, and only updated every \fB518400\fP -seconds (6 days). If you need the offer cache to be updated at a different -frequency, change this setting. Setting it to \fB0\fP will turn off the publiser -cache. -.SS expire_sku_cache -.sp -Optional. Default is \fB432000\fP\&. See \fBexpire_publisher_cache\fP for details on -why this exists. -.sp -By default, the sku data will be cached, and only updated every \fB432000\fP -seconds (5 days). If you need the sku cache to be updated at a different -frequency, change this setting. Setting it to \fB0\fP will turn off the sku -cache. -.SS expire_version_cache -.sp -Optional. Default is \fB345600\fP\&. See \fBexpire_publisher_cache\fP for details on -why this exists. -.sp -By default, the version data will be cached, and only updated every \fB345600\fP -seconds (4 days). If you need the version cache to be updated at a different -frequency, change this setting. Setting it to \fB0\fP will turn off the version -cache. -.SS expire_group_cache -.sp -Optional. Default is \fB14400\fP\&. See \fBexpire_publisher_cache\fP for details on -why this exists. -.sp -By default, the resource group data will be cached, and only updated every -\fB14400\fP seconds (4 hours). If you need the resource group cache to be updated -at a different frequency, change this setting. Setting it to \fB0\fP will turn -off the resource group cache. -.SS expire_interface_cache -.sp -Optional. Default is \fB3600\fP\&. See \fBexpire_publisher_cache\fP for details on -why this exists. -.sp -By default, the interface data will be cached, and only updated every \fB3600\fP -seconds (1 hour). If you need the interface cache to be updated at a different -frequency, change this setting. Setting it to \fB0\fP will turn off the interface -cache. -.SS expire_network_cache -.sp -Optional. Default is \fB3600\fP\&. See \fBexpire_publisher_cache\fP for details on -why this exists. -.sp -By default, the network data will be cached, and only updated every \fB3600\fP -seconds (1 hour). If you need the network cache to be updated at a different -frequency, change this setting. Setting it to \fB0\fP will turn off the network -cache. -.SS Other Options -.sp -Other options relevant to Azure ARM. -.SS storage_account -.sp -Required for actions involving an Azure storage account. -.SS storage_key -.sp -Required for actions involving an Azure storage account. -.SS Show Instance -.sp -This action is a thin wrapper around \fB\-\-full\-query\fP, which displays details on -a single instance only. In an environment with several machines, this will save -a user from having to sort through all instance data, just to examine a single -instance. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-a show_instance myinstance -.ft P -.fi -.UNINDENT -.UNINDENT .SS Getting Started with CloudStack .sp CloudStack is one the most popular cloud projects. It\(aqs an open source project @@ -69495,7 +67764,7 @@ digitalocean\-ubuntu: image: 14.04 x64 size: 512MB location: New York 1 - private_networking: True + vpc_name: Optional backups_enabled: True ipv6: True create_dns_record: True @@ -70252,7 +68521,7 @@ base_ec2_vpc: image: ami\-a73264ce size: m1.xlarge ssh_username: ec2\-user - script: /etc/salt/cloud.deploy.d/user_data.sh + script: /etc/salt/cloud.deploy.d/my_bootstrap.sh network_interfaces: \- DeviceIndex: 0 PrivateIpAddresses: @@ -73118,9 +71387,6 @@ This driver requires the Python \fBrequests\fP library to be installed. .B \fBpassword\fP \fB(Required)\fP The default password to set on new VMs. Must be 8 characters with at least one lowercase, uppercase, and numeric. .TP -.B \fBapi_version\fP -The version of the Linode API to interact with. Defaults to \fBv3\fP\&. -.TP .B \fBpoll_interval\fP The rate of time in milliseconds to poll the Linode API for changes. Defaults to \fB500\fP\&. .TP @@ -73138,24 +71404,8 @@ Set up the provider cloud configuration file at \fB/etc/salt/cloud.providers\fP .ft C my\-linode\-provider: driver: linode - api_version: v4 apikey: f4ZsmwtB1c7f85Jdu43RgXVDFlNjuJaeIYV8QMftTqKScEB2vSosFSr... - password: F00barbaz -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -For use with APIv3 (deprecated): -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my\-linode\-provider\-v3: - driver: linode - apikey: f4ZsmwtB1c7f85Jdu43RgXVDFlNjuJaeIYV8QMftTqKScEB2vSosFSr... - password: F00barbaz + password: F00barbazverylongp@ssword .ft P .fi .UNINDENT @@ -73166,20 +71416,19 @@ my\-linode\-provider\-v3: .TP .B \fBimage\fP \fB(Required)\fP The image to deploy the boot disk from. This should be an image ID -(e.g. \fBlinode/ubuntu16.04\fP); official images start with \fBlinode/\fP\&. For APIv3, -this would be an image label (i.e. Ubuntu 16.04). See \fI\%listing images\fP -for more options. +(e.g. \fBlinode/ubuntu22.04\fP); official images start with \fBlinode/\fP\&. .TP .B \fBlocation\fP \fB(Required)\fP The location of the VM. This should be a Linode region -(e.g. \fBus\-east\fP). For APIv3, this would be a datacenter location -(e.g. \fBNewark, NJ, USA\fP). See \fI\%listing locations\fP for -more options. +(e.g. \fBus\-east\fP). See \fI\%the list of locations\fP and +\fI\%the guide to choose a location\fP +for more options. .TP .B \fBsize\fP \fB(Required)\fP The size of the VM. This should be a Linode instance type ID -(e.g. \fBg6\-standard\-2\fP). For APIv3, this would be a plan ID (e.g. \fBLinode 2GB\fP). -See \fI\%listing sizes\fP for more options. +(e.g. \fBg6\-standard\-2\fP). See \fI\%the list of sizes\fP and +\fI\%the guide to choose a size\fP +for more options. .TP .B \fBpassword\fP (overrides provider) \fB(*Required)\fP The default password for the VM. Must be provided at the profile @@ -73189,21 +71438,20 @@ or provider level. New in version 2016.3.0. .sp -Whether or not to assign a private key to the VM. Defaults to \fBFalse\fP\&. +\fB(optional)\fP Whether or not to assign a private IP to the VM. Defaults to \fBFalse\fP\&. +.TP +.B \fBbackups_enabled\fP +\fB(optional)\fP Whether or not to enable the backup for this VM. Backup can be +configured in your Linode account Defaults to \fBFalse\fP\&. .TP .B \fBcloneform\fP -The name of the Linode to clone from. -.TP -.B \fBdisk_size\fP -\fB(Deprecated)\fP The amount of disk space to allocate for the OS disk. This has no -effect with APIv4; the size of the boot disk will be the remainder of disk space -after the swap partition is allocated. +\fB(optional)\fP The name of the Linode to clone from. .TP .B \fBssh_interface\fP New in version 2016.3.0. .sp -The interface with which to connect over SSH. Valid options are \fBprivate_ips\fP or +\fB(optional)\fP The interface with which to connect over SSH. Valid options are \fBprivate_ips\fP or \fBpublic_ips\fP\&. Defaults to \fBpublic_ips\fP\&. .sp If specifying \fBprivate_ips\fP, the Linodes must be hosted within the same data center @@ -73216,14 +71464,14 @@ the Network Helper on your Linode account, please see \fI\%Linode\(aqs Network H documentation. .TP .B \fBssh_pubkey\fP -The public key to authorize for SSH with the VM. +\fB(optional)\fP The public key to authorize for SSH with the VM. .TP .B \fBswap\fP -The amount of disk space to allocate for the swap partition. Defaults to \fB256\fP\&. +\fB(optional)\fP The amount of disk space to allocate for the swap partition. Defaults to \fB256\fP\&. .UNINDENT .SS Example Configuration .sp -Set up a profile configuration in \fB/etc/salt/cloud.profiles.d/\fP: +Set up a profile configuration at \fB/etc/salt/cloud.profiles\fP or \fB/etc/salt/cloud.profiles.d/*.conf\fP: .INDENT 0.0 .INDENT 3.5 .sp @@ -73232,7 +71480,7 @@ Set up a profile configuration in \fB/etc/salt/cloud.profiles.d/\fP: my\-linode\-profile: provider: my\-linode\-provider size: g6\-standard\-1 - image: linode/alpine3.12 + image: linode/ubuntu22.04 location: us\-east .ft P .fi @@ -73275,10 +71523,10 @@ A more advanced configuration utlizing all of the configuration options might lo .ft C my\-linode\-profile\-advanced: provider: my\-linode\-provider - size: g6\-standard\-3 - image: linode/alpine3.10 - location: eu\-west - password: bogus123X + size: g6\-standard\-1 + image: linode/ubuntu22.04 + location: us\-central + password: iamaverylongp@ssword assign_private_ip: true ssh_interface: private_ips ssh_pubkey: ssh\-rsa AAAAB3NzaC1yc2EAAAADAQAB... @@ -73287,26 +71535,9 @@ my\-linode\-profile\-advanced: .fi .UNINDENT .UNINDENT -.sp -A legacy configuration for use with APIv3 might look like: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my\-linode\-profile\-v3: - provider: my\-linode\-provider\-v3 - size: Nanode 1GB - image: Alpine 3.12 - location: Fremont, CA, USA -.ft P -.fi -.UNINDENT -.UNINDENT .SS Migrating to APIv4 .sp -Linode APIv3 has been deprecated and will be shutdown in the coming months. You can opt\-in to using -APIv4 by setting the \fBapi_version\fP provider configuration option to \fBv4\fP\&. +Linode APIv3 has been removed, and APIv4 is the only available version. .sp When switching to APIv4, you will also need to generate a new token. See \fI\%here\fP @@ -73317,18 +71548,18 @@ for more information. \fBsize\fP, and \fBimage\fP have moved from accepting label based references to IDs. See the \fI\%profile configuration\fP section for more details. .sp -\fBThe \(ga\(gadisk_size\(ga\(ga profile configuration parameter has been deprecated.\fP The parameter will not be taken into +\fBThe \(ga\(gadisk_size\(ga\(ga profile configuration parameter has been removed.\fP The parameter will not be taken into account when creating new VMs while targeting APIv4. See the \fBdisk_size\fP description under the \fI\%profile configuration\fP section for more details. .sp \fBThe \(ga\(gaboot\(ga\(ga function no longer requires a \(ga\(gaconfig_id\(ga\(ga.\fP A config can be inferred by the API instead when booting. .sp -\fBThe \(ga\(gaclone\(ga\(ga function has renamed parameters to match convention.\fP The old version of these parameters will not -be supported when targeting APIv4. -* \fBdatacenter_id\fP has been deprecated in favor of \fBlocation\fP\&. -* \fBplan_id\fP has been deprecated in favor of \fBsize\fP\&. +\fBThe \(ga\(gaclone\(ga\(ga function has renamed parameters to match convention.\fP The old version of these parameters are no longer +supported. +* \fBdatacenter_id\fP has been removed and replaced by \fBlocation\fP\&. +* \fBplan_id\fP has been removed and replaced by \fBsize\fP\&. .sp -\fBThe \(ga\(gaget_plan_id\(ga\(ga function has been deprecated and will not be supported by APIv4.\fP IDs are now the only way +\fBThe \(ga\(gaget_plan_id\(ga\(ga function has been removed and is not supported by APIv4.\fP IDs are now the only way of referring to a \(dqplan\(dq (or type/size). .SS Query Utilities .SS Listing Sizes @@ -73424,7 +71655,7 @@ my\-linode\-config: \-\-\-\-\-\-\-\-\-\- linode: \-\-\-\-\-\-\-\-\-\- - linode/alpine3.10: + linode/ubuntu22.04: \-\-\-\-\-\-\-\-\-\- created: 2019\-06\-20T17:17:11 @@ -73439,7 +71670,7 @@ my\-linode\-config: expiry: None id: - linode/alpine3.10 + linode/ubuntu22.04 is_public: True label: @@ -74933,6 +73164,14 @@ resources such as servers. The default wait_for_timeout is 15 minutes. For more information concerning cloud profiles, see \fI\%here\fP\&. .SS Getting Started With Proxmox .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This cloud provider will be removed from Salt in version 3009.0 in favor of +the \fI\%saltext.proxmox Salt Extension\fP +.UNINDENT +.UNINDENT +.sp Proxmox Virtual Environment is a complete server virtualization management solution, based on OpenVZ(in Proxmox up to 3.4)/LXC(from Proxmox 4.0 and up) and full virtualization with KVM. Further information can be found at: @@ -79398,10 +77637,7 @@ upon execution. Most often, it uses \fBget_configured_provider()\fP to determine if the necessary configuration has been set up. It may also check for necessary imports, to decide whether to load the module. In most cases, it will return a \fBTrue\fP or \fBFalse\fP value. If the name of the driver used does not match the -filename, then that name should be returned instead of \fBTrue\fP\&. An example of -this may be seen in the Azure module: -.sp -\fI\%https://github.com/saltstack/salt/tree/master/salt/cloud/clouds/msazure.py\fP +filename, then that name should be returned instead of \fBTrue\fP\&. .SS The get_configured_provider() Function .sp This function uses \fBconfig.is_provider_configured()\fP to determine whether @@ -79632,8 +77868,7 @@ salt\-cloud \-\-list\-sizes my\-cloud\-provider .sp This function builds the deploy script to be used on the remote machine. It is likely to be moved into the \fBsalt.utils.cloud\fP library in the near future, as -it is very generic and can usually be copied wholesale from another module. An -excellent example is in the Azure driver. +it is very generic and can usually be copied wholesale from another module. .SS The destroy() Function .sp This function irreversibly destroys a virtual machine on the cloud provider. @@ -85326,6 +83561,12 @@ are built with the \fI\%relenv\fP tool. .sp 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 \fI\%here\fP\&. +.SS Package Grain +.sp +In the 3007.0 release a new package grain was added. This detects how Salt was installed using the \fI_pkg.txt\fP +in the root of the Salt repo. By default this is set to \fBpip\fP, but it is set to \fBonedir\fP when \fBtools pkg build salt\-onedir\fP +is run in our pipelines when building our onedir packages. If you are building your own custom packages, please ensure you set +\fB_pkg.txt\fP contents to be the type of package you are creating. The options are \fBpip\fP, \fBonedir\fP or \fBsystem\fP\&. .SS How to build onedir only .INDENT 0.0 .IP 1. 3 @@ -91663,6 +89904,8 @@ mysql.user: None mysql.password: None mysql.database: salt_cache mysql.table_name: cache +# This may be enabled to create a fresh connection on every call +mysql.fresh_connection: false .ft P .fi .UNINDENT @@ -91715,7 +89958,7 @@ bank. Get a cursor and run a query. Reconnect up to \fBretries\fP times if needed. Returns: cursor, affected rows counter -Raises: SaltCacheError, AttributeError, OperationalError +Raises: SaltCacheError, AttributeError, OperationalError, InterfaceError .UNINDENT .INDENT 0.0 .TP @@ -92003,12 +90246,6 @@ AliYun ECS Cloud Module T} _ T{ -\fI\%azurearm\fP -T} T{ -Azure ARM Cloud Module -T} -_ -T{ \fI\%clc\fP T} T{ CenturyLink Cloud Module @@ -92081,12 +90318,6 @@ Install Salt on an LXC Container T} _ T{ -\fI\%msazure\fP -T} T{ -Azure Cloud Module -T} -_ -T{ \fI\%oneandone\fP T} T{ 1&1 Cloud Server Module @@ -92125,7 +90356,6 @@ _ T{ \fI\%proxmox\fP T} T{ -Proxmox Cloud Module T} _ T{ @@ -92458,366 +90688,6 @@ salt\-cloud \-a stop myinstance force=True .UNINDENT .UNINDENT .UNINDENT -.SS salt.cloud.clouds.azurearm -.SS Azure ARM Cloud Module -.sp -New in version 2016.11.0. - -.sp -Changed in version 2019.2.0. - -.sp -The Azure ARM cloud module is used to control access to Microsoft Azure Resource Manager -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0rc6 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.4 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 0.33.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 0.30.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.30.0rc6 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.32.0 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B configuration -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.TP -.B if using Managed Service Identity authentication: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.INDENT 7.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.IP \(bu 2 -HTTP base URL for a custom endpoint, such as Azure Stack. The \fB/metadata/endpoints\fP path will be added to the URL. -.UNINDENT -.TP -\fBuserdata\fP and \fBuserdata_file\fP: -Azure Resource Manager uses a separate VirtualMachineExtension object to pass userdata scripts to the virtual -machine. Arbitrary shell commands can be passed via the \fBuserdata\fP parameter, or via a file local to the Salt -Cloud system using the \fBuserdata_file\fP parameter. Note that the local file is not treated as a script by the -extension, so \(dqone\-liners\(dq probably work best. If greater functionality is desired, a web\-hosted script file can -be specified via \fBuserdata_file: https://raw.githubusercontent.com/account/repo/master/azure\-script.py\fP, which -will be executed on the system after VM creation. For Windows systems, script files ending in \fB\&.ps1\fP will be -executed with \fBpowershell.exe\fP\&. The \fBuserdata\fP parameter takes precedence over the \fBuserdata_file\fP parameter -when creating the custom script extension. -.TP -\fBwin_installer\fP: -This parameter, which holds the local path to the Salt Minion installer package, is used to determine if the -virtual machine type will be \(dqWindows\(dq. Only set this parameter on profiles which install Windows operating systems. -.UNINDENT -.UNINDENT -.sp -Example \fB/etc/salt/cloud.providers\fP or -\fB/etc/salt/cloud.providers.d/azure.conf\fP configuration: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my\-azure\-config with username and password: - driver: azurearm - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - username: larry - password: 123pass - -Or my\-azure\-config with service principal: - driver: azurearm - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - tenant: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - client_id: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - secret: XXXXXXXXXXXXXXXXXXXXXXXX - cloud_environment: AZURE_US_GOV_CLOUD - - The Service Principal can be created with the new Azure CLI (https://github.com/Azure/azure\-cli) with: - az ad sp create\-for\-rbac \-n \(dqhttp://\(dq \-\-role \-\-scopes - For example, this creates a service principal with \(aqowner\(aq role for the whole subscription: - az ad sp create\-for\-rbac \-n \(dqhttp://mysaltapp\(dq \-\-role owner \-\-scopes /subscriptions/3287abc8\-f98a\-c678\-3bde\-326766fd3617 - - *Note: review the details of Service Principals. Owner role is more than you normally need, and you can restrict - scope to a resource group or individual resources. -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.avail_images(call=None) -Return a dict of all available images on the provider -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.avail_locations(call=None) -Return a dict of all available regions. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.avail_sizes(call=None) -Return a list of sizes available from the provider -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.create(vm_) -Create a single VM from a data dict. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.create_network_interface(call=None, kwargs=None) -Create a network interface. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.create_or_update_vmextension(call=None, kwargs=None) -New in version 2019.2.0. - -.sp -Create or update a VM extension object \(dqinside\(dq of a VM object. -.INDENT 7.0 -.TP -.B required kwargs: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -extension_name: myvmextension -virtual_machine_name: myvm -settings: {\(dqcommandToExecute\(dq: \(dqhostname\(dq} -.ft P -.fi -.UNINDENT -.UNINDENT -.TP -.B optional kwargs: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -resource_group: < inferred from cloud configs > -location: < inferred from cloud configs > -publisher: < default: Microsoft.Azure.Extensions > -virtual_machine_extension_type: < default: CustomScript > -type_handler_version: < default: 2.0 > -auto_upgrade_minor_version: < default: True > -protected_settings: < default: None > -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.delete_blob(call=None, kwargs=None) -Delete a blob from a container. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.delete_interface(call=None, kwargs=None) -Delete a network interface. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.delete_managed_disk(call=None, kwargs=None) -Delete a managed disk from a resource group. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.destroy(name, call=None, kwargs=None) -Destroy a VM. -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-d myminion -salt\-cloud \-a destroy myminion service_name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.get_api_versions(call=None, kwargs=None) -Get a resource type api versions -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.get_configured_provider() -Return the first configured provider instance. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.get_conn(client_type) -Return a connection object for a client type. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.get_dependencies() -Warn if dependencies aren\(aqt met. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.get_location(call=None, kwargs=None) -Return the location that is configured for this provider -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.get_resource_by_id(resource_id, api_version, extract_value=None) -Get an AzureARM resource by id -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_blobs(call=None, kwargs=None) -List blobs. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_nodes(call=None) -List VMs on this Azure account -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_nodes_full(call=None) -List all VMs on the subscription with full information -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_resource_groups(call=None) -List resource groups associated with the subscription -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_storage_accounts(call=None) -List storage accounts within the subscription. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_subnets(call=None, kwargs=None) -List subnets in a virtual network. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.list_virtual_networks(call=None, kwargs=None) -List virtual networks. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.request_instance(vm_, kwargs=None) -Request a VM from Azure. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.show_instance(name, call=None) -Show the details from AzureARM concerning an instance -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.start(name, call=None) -New in version 2019.2.0. - -.sp -Start a VM -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-a start myminion -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.azurearm.stop(name, call=None) -New in version 2019.2.0. - -.sp -Stop (deallocate) a VM -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-a stop myminion -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT .SS salt.cloud.clouds.clc .SS CenturyLink Cloud Module .sp @@ -96517,8 +94387,6 @@ Return a list of the VMs that are on the provider, with select fields .SS The Linode Cloud Module .sp The Linode cloud module is used to interact with the Linode Cloud. -.sp -You can target a specific version of the Linode API with the \fBapi_version\fP parameter. The default is \fBv3\fP\&. .SS Provider .sp The following provider parameters are supported: @@ -96528,8 +94396,6 @@ The following provider parameters are supported: .IP \(bu 2 \fBpassword\fP: (required) The default password to set on new VMs. Must be 8 characters with at least one lowercase, uppercase, and numeric. .IP \(bu 2 -\fBapi_version\fP: (optional) The version of the Linode API to interact with. Defaults to \fBv3\fP\&. -.IP \(bu 2 \fBpoll_interval\fP: (optional) The rate of time in milliseconds to poll the Linode API for changes. Defaults to \fB500\fP\&. .IP \(bu 2 \fBratelimit_sleep\fP: (optional) The time in seconds to wait before retrying after a ratelimit has been enforced. Defaults to \fB0\fP\&. @@ -96538,8 +94404,8 @@ The following provider parameters are supported: \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -APIv3 usage is deprecated and will be removed in a future release in favor of APIv4. To move to APIv4 now, -set the \fBapi_version\fP parameter in your provider configuration to \fBv4\fP\&. See the full migration guide +APIv3 usage has been removed in favor of APIv4. To move to APIv4 now, +See the full migration guide here \fI\%https://docs.saltproject.io/en/latest/topics/cloud/linode.html#migrating\-to\-apiv4\fP\&. .UNINDENT .UNINDENT @@ -96552,24 +94418,8 @@ Set up the provider configuration at \fB/etc/salt/cloud.providers\fP or \fB/etc/ .ft C my\-linode\-provider: driver: linode - api_version: v4 apikey: f4ZsmwtB1c7f85Jdu43RgXVDFlNjuJaeIYV8QMftTqKScEB2vSosFSr... - password: F00barbaz -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -For use with APIv3 (deprecated): -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my\-linode\-provider\-v3: - driver: linode - apikey: f4ZsmwtB1c7f85Jdu43RgXVDFlNjuJaeIYV8QMftTqKScEB2vSosFSr... - password: F00barbaz + password: F00barbazverylongp@ssword .ft P .fi .UNINDENT @@ -96579,15 +94429,17 @@ my\-linode\-provider\-v3: The following profile parameters are supported: .INDENT 0.0 .IP \(bu 2 -\fBsize\fP: (required) The size of the VM. This should be a Linode instance type ID (i.e. \fBg6\-standard\-2\fP). For APIv3, this would be a plan ID (i.e. \fBLinode 2GB\fP). Run \fBsalt\-cloud \-f avail_sizes my\-linode\-provider\fP for options. +\fBsize\fP: (required) The size of the VM. This should be a Linode instance type ID (i.e. \fBg6\-standard\-2\fP). Run \fBsalt\-cloud \-f avail_sizes my\-linode\-provider\fP for options. .IP \(bu 2 -\fBlocation\fP: (required) The location of the VM. This should be a Linode region (e.g. \fBus\-east\fP). For APIv3, this would be a datacenter location (i.e. \fBNewark, NJ, USA\fP). Run \fBsalt\-cloud \-f avail_locations my\-linode\-provider\fP for options. +\fBlocation\fP: (required) The location of the VM. This should be a Linode region (e.g. \fBus\-east\fP). Run \fBsalt\-cloud \-f avail_locations my\-linode\-provider\fP for options. .IP \(bu 2 -\fBimage\fP: (required) The image to deploy the boot disk from. This should be an image ID (e.g. \fBlinode/ubuntu16.04\fP); official images start with \fBlinode/\fP\&. For APIv3, this would be an image label (i.e. Ubuntu 16.04). Run \fBsalt\-cloud \-f avail_images my\-linode\-provider\fP for more options. +\fBimage\fP: (required) The image to deploy the boot disk from. This should be an image ID (e.g. \fBlinode/ubuntu22.04\fP); official images start with \fBlinode/\fP\&. Run \fBsalt\-cloud \-f avail_images my\-linode\-provider\fP for more options. .IP \(bu 2 \fBpassword\fP: (*required) The default password for the VM. Must be provided at the profile or provider level. .IP \(bu 2 -\fBassign_private_ip\fP: (optional) Whether or not to assign a private key to the VM. Defaults to \fBFalse\fP\&. +\fBassign_private_ip\fP: (optional) Whether or not to assign a private IP to the VM. Defaults to \fBFalse\fP\&. +.IP \(bu 2 +\fBbackups_enabled\fP: (optional) Whether or not to enable the backup for this VM. Backup can be configured in your Linode account Defaults to \fBFalse\fP\&. .IP \(bu 2 \fBssh_interface\fP: (optional) The interface with which to connect over SSH. Valid options are \fBprivate_ips\fP or \fBpublic_ips\fP\&. Defaults to \fBpublic_ips\fP\&. .IP \(bu 2 @@ -96596,8 +94448,6 @@ The following profile parameters are supported: \fBswap\fP: (optional) The amount of disk space to allocate for the swap partition. Defaults to \fB256\fP\&. .IP \(bu 2 \fBclonefrom\fP: (optional) The name of the Linode to clone from. -.IP \(bu 2 -\fBdisk_size\fP: (deprecated, optional) The amount of disk space to allocate for the OS disk. This has no effect with APIv4; the size of the boot disk will be the remainder of disk space after the swap parition is allocated. .UNINDENT .sp Set up a profile configuration in \fB/etc/salt/cloud.profiles.d/\fP: @@ -96610,36 +94460,27 @@ my\-linode\-profile: # a minimal configuration provider: my\-linode\-provider size: g6\-standard\-1 - image: linode/alpine3.12 + image: linode/ubuntu22.04 location: us\-east my\-linode\-profile\-advanced: # an advanced configuration provider: my\-linode\-provider size: g6\-standard\-3 - image: linode/alpine3.10 + image: linode/ubuntu22.04 location: eu\-west password: bogus123X assign_private_ip: true ssh_interface: private_ips ssh_pubkey: ssh\-rsa AAAAB3NzaC1yc2EAAAADAQAB... swap_size: 512 - -my\-linode\-profile\-v3: - # a legacy configuration - provider: my\-linode\-provider\-v3 - size: Nanode 1GB - image: Alpine 3.12 - location: Fremont, CA, USA .ft P .fi .UNINDENT .UNINDENT .SS Migrating to APIv4 .sp -In order to target APIv4, ensure your provider configuration has \fBapi_version\fP set to \fBv4\fP\&. -.sp -You will also need to generate a new token for your account. See \fI\%https://www.linode.com/docs/platform/api/getting\-started\-with\-the\-linode\-api/#create\-an\-api\-token\fP +You will need to generate a new token for your account. See \fI\%https://www.linode.com/docs/products/tools/api/get\-started/#create\-an\-api\-token\fP .sp There are a few changes to note: \- There has been a general move from label references to ID references. The profile configuration parameters \fBlocation\fP, \fBsize\fP, and \fBimage\fP have moved from being label based references to IDs. See the profile section for more information. In addition to these inputs being changed, \fBavail_sizes\fP, \fBavail_locations\fP, and \fBavail_images\fP now output options sorted by ID instead of label. @@ -96647,10 +94488,7 @@ There are a few changes to note: .INDENT 0.0 .TP .B maintainer -Charles Kenney <\fI\%ckenney@linode.com\fP> -.TP -.B maintainer -Phillip Campbell <\fI\%pcampbell@linode.com\fP> +Linode Developer Tools and Experience Team <\fI\%dev\-dx@linode.com\fP> .TP .B depends requests @@ -96709,11 +94547,6 @@ get_config_id implementation .UNINDENT .INDENT 7.0 .TP -.B get_plan_id(kwargs=None) -get_plan_id implementation -.UNINDENT -.INDENT 7.0 -.TP .B abstract list_nodes() list_nodes implementation .UNINDENT @@ -96759,100 +94592,6 @@ stop implementation .UNINDENT .INDENT 0.0 .TP -.B class salt.cloud.clouds.linode.LinodeAPIv3 -.INDENT 7.0 -.TP -.B avail_images() -avail_images implementation -.UNINDENT -.INDENT 7.0 -.TP -.B avail_locations() -avail_locations implementation -.UNINDENT -.INDENT 7.0 -.TP -.B avail_sizes() -avail_sizes implementation -.UNINDENT -.INDENT 7.0 -.TP -.B boot(name=None, kwargs=None) -boot implementation -.UNINDENT -.INDENT 7.0 -.TP -.B clone(kwargs=None) -clone implementation -.UNINDENT -.INDENT 7.0 -.TP -.B create(vm_) -create implementation -.UNINDENT -.INDENT 7.0 -.TP -.B create_config(kwargs=None) -create_config implementation -.UNINDENT -.INDENT 7.0 -.TP -.B destroy(name) -destroy implementation -.UNINDENT -.INDENT 7.0 -.TP -.B get_config_id(kwargs=None) -get_config_id implementation -.UNINDENT -.INDENT 7.0 -.TP -.B get_plan_id(kwargs=None) -get_plan_id implementation -.UNINDENT -.INDENT 7.0 -.TP -.B list_nodes() -list_nodes implementation -.UNINDENT -.INDENT 7.0 -.TP -.B list_nodes_full() -list_nodes_full implementation -.UNINDENT -.INDENT 7.0 -.TP -.B list_nodes_min() -list_nodes_min implementation -.UNINDENT -.INDENT 7.0 -.TP -.B reboot(name) -reboot implementation -.UNINDENT -.INDENT 7.0 -.TP -.B show_instance(name) -show_instance implementation -.UNINDENT -.INDENT 7.0 -.TP -.B show_pricing(kwargs=None) -show_pricing implementation -.UNINDENT -.INDENT 7.0 -.TP -.B start(name) -start implementation -.UNINDENT -.INDENT 7.0 -.TP -.B stop(name) -stop implementation -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP .B class salt.cloud.clouds.linode.LinodeAPIv4 .INDENT 7.0 .TP @@ -96896,6 +94635,10 @@ destroy implementation .UNINDENT .INDENT 7.0 .TP +.B classmethod get_api_instance() +.UNINDENT +.INDENT 7.0 +.TP .B get_config_id(kwargs=None) get_config_id implementation .UNINDENT @@ -96921,6 +94664,10 @@ reboot implementation .UNINDENT .INDENT 7.0 .TP +.B set_backup_schedule(label, linode_id, day, window, auto_enable=False) +.UNINDENT +.INDENT 7.0 +.TP .B show_instance(name) show_instance implementation .UNINDENT @@ -97057,14 +94804,6 @@ The location of the new Linode. Required. .TP .B size The size of the new Linode (must be greater than or equal to the clone source). Required. -.TP -.B datacenter_id -The ID of the Datacenter where the Linode will be placed. Required for APIv3 usage. -Deprecated. Use \fBlocation\fP instead. -.TP -.B plan_id -The ID of the plan (size) of the Linode. Required. Required for APIv3 usage. -Deprecated. Use \fBsize\fP instead. .UNINDENT .sp CLI Example: @@ -97073,7 +94812,7 @@ CLI Example: .sp .nf .ft C -salt\-cloud \-f clone my\-linode\-config linode_id=1234567 datacenter_id=2 plan_id=5 +salt\-cloud \-f clone my\-linode\-config linode_id=1234567 location=us\-central size=g6\-standard\-1 .ft P .fi .UNINDENT @@ -97203,29 +94942,6 @@ salt\-cloud \-f get_linode my\-linode\-config linode_id=1234567 .UNINDENT .INDENT 0.0 .TP -.B salt.cloud.clouds.linode.get_plan_id(kwargs=None, call=None) -Returns the Linode Plan ID. -.INDENT 7.0 -.TP -.B label -The label, or name, of the plan to get the ID from. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f get_plan_id linode label=\(dqNanode 1GB\(dq -salt\-cloud \-f get_plan_id linode label=\(dqLinode 2GB\(dq -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP .B salt.cloud.clouds.linode.list_nodes(call=None) Returns a list of linodes, keeping only a brief listing. .sp @@ -97335,6 +95051,81 @@ salt\-cloud \-a reboot vm_name .UNINDENT .INDENT 0.0 .TP +.B salt.cloud.clouds.linode.set_backup_schedule(name=None, kwargs=None, call=None) +Set the backup schedule for a Linode. +.INDENT 7.0 +.TP +.B name +The name (label) of the Linode. Can be used instead of +\fBlinode_id\fP\&. +.TP +.B linode_id +The ID of the Linode instance to set the backup schedule for. +If provided, will be used as an alternative to \fBname\fP and +reduces the number of API calls to Linode by one. Will be +preferred over \fBname\fP\&. +.TP +.B auto_enable +If \fBTrue\fP, automatically enable the backup feature for the Linode +if it wasn\(aqt already enabled. Optional parameter, default to \fBFalse\fP\&. +.TP +.B day +Possible values: +\fBSunday\fP, \fBMonday\fP, \fBTuesday\fP, \fBWednesday\fP, +\fBThursday\fP, \fBFriday\fP, \fBSaturday\fP +.sp +The day of the week that your Linode\(aqs weekly Backup is taken. +If not set manually, a day will be chosen for you. Backups are +taken every day, but backups taken on this day are preferred +when selecting backups to retain for a longer period. +.sp +If not set manually, then when backups are initially enabled, +this may come back as \fBScheduling\fP until the day is automatically +selected. +.TP +.B window +Possible values: +\fBW0\fP, \fBW2\fP, \fBW4\fP, \fBW6\fP, \fBW8\fP, \fBW10\fP, +\fBW12\fP, \fBW14\fP, \fBW16\fP, \fBW18\fP, \fBW20\fP, \fBW22\fP +.sp +The window in which your backups will be taken, in UTC. A backups +window is a two\-hour span of time in which the backup may occur. +.sp +For example, \fBW10\fP indicates that your backups should be taken +between 10:00 and 12:00. If you do not choose a backup window, one +will be selected for you automatically. +.sp +If not set manually, when backups are initially enabled this may come +back as \fBScheduling\fP until the window is automatically selected. +.UNINDENT +.sp +Can be called as an action (which requires a name): +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-cloud \-a set_backup_schedule my\-linode\-instance day=Monday window=W20 auto_enable=True +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\&...or as a function (which requires either a name or linode_id): +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-cloud \-f set_backup_schedule my\-linode\-provider name=my\-linode\-instance day=Monday window=W20 auto_enable=True +salt\-cloud \-f set_backup_schedule my\-linode\-provider linode_id=1225876 day=Monday window=W20 auto_enable=True +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.cloud.clouds.linode.show_instance(name, call=None) Displays details about a particular Linode VM. Either a name or a linode_id must be provided. @@ -97487,1918 +95278,6 @@ Return a list of the VMs that are on the provider, with select fields .B salt.cloud.clouds.lxc.show_instance(name, call=None) Show the details from the provider concerning an instance .UNINDENT -.SS salt.cloud.clouds.msazure -.SS Azure Cloud Module -.sp -The Azure cloud module is used to control access to Microsoft Azure -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 due to -the deprecation of the \(dqClassic\(dq API for Azure. Please migrate to -\fI\%Azure Resource Manager by March 1, 2023\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%Microsoft Azure SDK for Python\fP >= 1.0.2 -.IP \(bu 2 -python\-requests, for Python < 2.7.9 -.UNINDENT -.TP -.B configuration -Required provider parameters: -.INDENT 7.0 -.IP \(bu 2 -\fBapikey\fP -.IP \(bu 2 -\fBcertificate_path\fP -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBbackend\fP -.UNINDENT -.sp -A Management Certificate (.pem and .crt files) must be created and the .pem -file placed on the same machine that salt\-cloud is run from. Information on -creating the pem file to use, and uploading the associated cer file can be -found at: -.sp -\fI\%http://www.windowsazure.com/en\-us/develop/python/how\-to\-guides/service\-management/\fP -.sp -For users with Python < 2.7.9, \fBbackend\fP must currently be set to \fBrequests\fP\&. -.UNINDENT -.sp -Example \fB/etc/salt/cloud.providers\fP or -\fB/etc/salt/cloud.providers.d/azure.conf\fP configuration: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -my\-azure\-config: - driver: azure - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - certificate_path: /etc/salt/azure.pem - management_host: management.core.windows.net -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.add_input_endpoint(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Add an input endpoint to the deployment. Please note that -there may be a delay before the changes show up. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f add_input_endpoint my\-azure service=myservice \e - deployment=mydeployment role=myrole name=HTTP local_port=80 \e - port=80 protocol=tcp enable_direct_server_return=False \e - timeout_for_tcp_idle_connection=4 -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.add_management_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Add a new management certificate -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f add_management_certificate my\-azure public_key=\(aq...PUBKEY...\(aq \e - thumbprint=0123456789ABCDEF data=\(aq...CERT_DATA...\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.add_service_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Add a new service certificate -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f add_service_certificate my\-azure name=my_service_certificate \e - data=\(aq...CERT_DATA...\(aq certificate_format=sha1 password=verybadpass -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.avail_images(conn=None, call=None) -List available images for Azure -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.avail_locations(conn=None, call=None) -List available locations for Azure -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.avail_sizes(call=None) -Return a list of sizes from Azure -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.cleanup_unattached_disks(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Cleans up all disks associated with the account, which are not attached. -\fB* CAUTION *\fP This is a destructive function with no undo button, and no -\(dqAre you sure?\(dq confirmation! -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f cleanup_unattached_disks my\-azure name=my_disk -salt\-cloud \-f cleanup_unattached_disks my\-azure name=my_disk delete_vhd=True -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.create(vm_) -Create a single VM from a data dict -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.create_affinity_group(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Create a new affinity group -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_affinity_group my\-azure name=my_affinity_group -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.create_attach_volumes(name, kwargs, call=None, wait_to_finish=True) -Create and attach volumes to created node -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.create_service(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Create a new hosted service -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_service my\-azure name=my_service label=my_service location=\(aqWest US\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.create_storage(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Create a new storage account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_storage my\-azure name=my_storage label=my_storage location=\(aqWest US\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.create_storage_container(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Create a storage container -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f create_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to create. -.TP -.B meta_name_values: -Optional. A dict with name_value pairs to associate with the -container as metadata. Example:{\(aqCategory\(aq:\(aqtest\(aq} -.TP -.B blob_public_access: -Optional. Possible values include: container, blob -.TP -.B fail_on_exist: -Specify whether to throw an exception when the container exists. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_affinity_group(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a specific affinity group associated with the account -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_affinity_group my\-azure name=my_affinity_group -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_disk(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a specific disk associated with the account -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_disk my\-azure name=my_disk -salt\-cloud \-f delete_disk my\-azure name=my_disk delete_vhd=True -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_input_endpoint(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete an input endpoint from the deployment. Please note that -there may be a delay before the changes show up. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_input_endpoint my\-azure service=myservice \e - deployment=mydeployment role=myrole name=HTTP -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_management_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a specific certificate associated with the management -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_management_certificate my\-azure name=my_management_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_service(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a specific service associated with the account -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_service my\-azure name=my_service -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_service_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a specific certificate associated with the service -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_service_certificate my\-azure name=my_service_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_storage(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a specific storage account -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_storage my\-azure name=my_storage -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.delete_storage_container(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Delete a container associated with the storage account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f delete_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to create. -.TP -.B fail_not_exist: -Specify whether to throw an exception when the container exists. -.TP -.B lease_id: -If specified, delete_storage_container only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.destroy(name, conn=None, call=None, kwargs=None) -Destroy a VM -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-d myminion -salt\-cloud \-a destroy myminion service_name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_affinity_group(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Show an affinity group associated with the account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_affinity_group my\-azure service=myservice \e - deployment=mydeployment name=SSH -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_blob(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Download a blob -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f get_blob my\-azure container=base name=top.sls local_path=/srv/salt/top.sls -salt\-cloud \-f get_blob my\-azure container=base name=content.txt return_content=True -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -Name of existing container. -.TP -.B name: -Name of existing blob. -.TP -.B local_path: -The path on the local machine to download the blob to. Either this or -return_content must be specified. -.TP -.B return_content: -Whether or not to return the content directly from the blob. If -specified, must be True or False. Either this or the local_path must -be specified. -.TP -.B snapshot: -Optional. The snapshot parameter is an opaque DateTime value that, -when present, specifies the blob snapshot to retrieve. -.TP -.B lease_id: -Required if the blob has an active lease. -.TP -.B progress_callback: -callback for progress with signature function(current, total) where -current is the number of bytes transferred so far, and total is the -size of the blob. -.TP -.B max_connections: -Maximum number of parallel connections to use when the blob size -exceeds 64MB. -Set to 1 to download the blob chunks sequentially. -Set to 2 or more to download the blob chunks in parallel. This uses -more system resources but will download faster. -.TP -.B max_retries: -Number of times to retry download of blob chunk if an error occurs. -.TP -.B retry_wait: -Sleep time in secs between retries. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_blob_properties(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Returns all user\-defined metadata, standard HTTP properties, and -system properties for the blob. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_blob_properties my\-azure container=mycontainer blob=myblob -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -Name of existing container. -.TP -.B blob: -Name of existing blob. -.TP -.B lease_id: -Required if the blob has an active lease. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_blob_service_properties(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a blob\(aqs service properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_blob_service_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_configured_provider() -Return the first configured instance. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_conn() -Return a conn object for the passed VM data -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_dependencies() -Warn if dependencies aren\(aqt met. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_deployment(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_deployment my\-azure name=my_deployment -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_disk(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a disk -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_disk my\-azure name=my_disk -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_input_endpoint(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Show an input endpoint associated with the deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_input_endpoint my\-azure service=myservice \e - deployment=mydeployment name=SSH -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_management_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a management_certificate -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f get_management_certificate my\-azure name=my_management_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_operation_status(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Get Operation Status, based on a request ID -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f get_operation_status my\-azure id=0123456789abcdef0123456789abcdef -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_service_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a service certificate -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_service_certificate my\-azure name=my_service_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_storage(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List storage service properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage my\-azure name=my_storage -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_storage_conn(storage_account=None, storage_key=None, conn_kwargs=None) -New in version 2015.8.0. - -.sp -Return a storage_conn object for the storage account -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_storage_container(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a container associated with the storage account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to show. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_storage_container_acl(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a storage container\(aqs acl -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container_acl my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of existing container. -.TP -.B lease_id: -If specified, show_storage_container_acl only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_storage_container_metadata(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a storage container\(aqs metadata -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container_metadata my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to show. -.TP -.B lease_id: -If specified, show_storage_container_metadata only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.get_storage_keys(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Show storage account keys -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_keys my\-azure name=my_storage -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.lease_storage_container(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Lease a container associated with the storage account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f lease_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to create. -.TP -.B lease_action: -Required. Possible values: acquire|renew|release|break|change -.TP -.B lease_id: -Required if the container has an active lease. -.TP -.B lease_duration: -Specifies the duration of the lease, in seconds, or negative one -(\-1) for a lease that never expires. A non\-infinite lease can be -between 15 and 60 seconds. A lease duration cannot be changed -using renew or change. For backwards compatibility, the default is -60, and the value is only used on an acquire operation. -.TP -.B lease_break_period: -Optional. For a break operation, this is the proposed duration of -seconds that the lease should continue before it is broken, between -0 and 60 seconds. This break period is only used if it is shorter -than the time remaining on the lease. If longer, the time remaining -on the lease is used. A new lease will not be available before the -break period has expired, but the lease may be held for longer than -the break period. If this header does not appear with a break -operation, a fixed\-duration lease breaks after the remaining lease -period elapses, and an infinite lease breaks immediately. -.TP -.B proposed_lease_id: -Optional for acquire, required for change. Proposed lease ID, in a -GUID string format. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_affinity_groups(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List input endpoints associated with the deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_affinity_groups my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_blobs(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -List blobs associated with the container -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_blobs my\-azure container=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -The name of the storage container -.TP -.B prefix: -Optional. Filters the results to return only blobs whose names -begin with the specified prefix. -.TP -.B marker: -Optional. A string value that identifies the portion of the list -to be returned with the next list operation. The operation returns -a marker value within the response body if the list returned was -not complete. The marker value may then be used in a subsequent -call to request the next set of list items. The marker value is -opaque to the client. -.TP -.B maxresults: -Optional. Specifies the maximum number of blobs to return, -including all BlobPrefix elements. If the request does not specify -maxresults or specifies a value greater than 5,000, the server will -return up to 5,000 items. Setting maxresults to a value less than -or equal to zero results in error response code 400 (Bad Request). -.TP -.B include: -Optional. Specifies one or more datasets to include in the -response. To specify more than one of these options on the URI, -you must separate each option with a comma. Valid values are: -.INDENT 7.0 -.TP -.B snapshots: -Specifies that snapshots should be included in the -enumeration. Snapshots are listed from oldest to newest in -the response. -.TP -.B metadata: -Specifies that blob metadata be returned in the response. -.TP -.B uncommittedblobs: -Specifies that blobs for which blocks have been uploaded, -but which have not been committed using Put Block List -(REST API), be included in the response. -.TP -.B copy: -Version 2012\-02\-12 and newer. Specifies that metadata -related to any current or previous Copy Blob operation -should be included in the response. -.UNINDENT -.TP -.B delimiter: -Optional. When the request includes this parameter, the operation -returns a BlobPrefix element in the response body that acts as a -placeholder for all blobs whose names begin with the same -substring up to the appearance of the delimiter character. The -delimiter may be a single character or a string. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_disks(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List disks associated with the account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_disks my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_hosted_services(conn=None, call=None) -List VMs on this Azure account, with full information -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_input_endpoints(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List input endpoints associated with the deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_input_endpoints my\-azure service=myservice deployment=mydeployment -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_management_certificates(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List management certificates associated with the subscription -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_management_certificates my\-azure name=my_management -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_nodes(conn=None, call=None) -List VMs on this Azure account -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_nodes_full(conn=None, call=None) -List VMs on this Azure account, with full information -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_nodes_select(conn=None, call=None) -Return a list of the VMs that are on the provider, with select fields -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_service_certificates(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List certificates associated with the service -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_service_certificates my\-azure name=my_service -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_services(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List hosted services associated with the account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_services my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_storage(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List storage accounts associated with the account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_storage my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_storage_containers(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -List containers associated with the storage account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_storage_containers my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_storage_services(conn=None, call=None) -List VMs on this Azure account, with full information -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.list_virtual_networks(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List input endpoints associated with the deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f list_virtual_networks my\-azure service=myservice deployment=mydeployment -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.make_blob_url(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Creates the URL to access a blob -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f make_blob_url my\-azure container=mycontainer blob=myblob -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -Name of the container. -.TP -.B blob: -Name of the blob. -.TP -.B account: -Name of the storage account. If not specified, derives the host base -from the provider configuration. -.TP -.B protocol: -Protocol to use: \(aqhttp\(aq or \(aqhttps\(aq. If not specified, derives the host -base from the provider configuration. -.TP -.B host_base: -Live host base URL. If not specified, derives the host base from the -provider configuration. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.put_blob(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Upload a blob -.sp -CLI Examples: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f put_blob my\-azure container=base name=top.sls blob_path=/srv/salt/top.sls -salt\-cloud \-f put_blob my\-azure container=base name=content.txt blob_content=\(aqSome content\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -Name of existing container. -.TP -.B name: -Name of existing blob. -.TP -.B blob_path: -The path on the local machine of the file to upload as a blob. Either -this or blob_content must be specified. -.TP -.B blob_content: -The actual content to be uploaded as a blob. Either this or blob_path -must me specified. -.TP -.B cache_control: -Optional. The Blob service stores this value but does not use or -modify it. -.TP -.B content_language: -Optional. Specifies the natural languages used by this resource. -.TP -.B content_md5: -Optional. An MD5 hash of the blob content. This hash is used to -verify the integrity of the blob during transport. When this header -is specified, the storage service checks the hash that has arrived -with the one that was sent. If the two hashes do not match, the -operation will fail with error code 400 (Bad Request). -.TP -.B blob_content_type: -Optional. Set the blob\(aqs content type. -.TP -.B blob_content_encoding: -Optional. Set the blob\(aqs content encoding. -.TP -.B blob_content_language: -Optional. Set the blob\(aqs content language. -.TP -.B blob_content_md5: -Optional. Set the blob\(aqs MD5 hash. -.TP -.B blob_cache_control: -Optional. Sets the blob\(aqs cache control. -.TP -.B meta_name_values: -A dict containing name, value for metadata. -.TP -.B lease_id: -Required if the blob has an active lease. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.query(path, method=\(aqGET\(aq, data=None, params=None, header_dict=None, decode=True) -Perform a query directly against the Azure REST API -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.regenerate_storage_keys(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Regenerate storage account keys. Requires a key_type (\(dqprimary\(dq or -\(dqsecondary\(dq) to be specified. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f regenerate_storage_keys my\-azure name=my_storage key_type=primary -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.script(vm_) -Return the script deployment object -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.set_blob_properties(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Set a blob\(aqs properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_blob_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -Name of existing container. -.TP -.B blob: -Name of existing blob. -.TP -.B blob_cache_control: -Optional. Modifies the cache control string for the blob. -.TP -.B blob_content_type: -Optional. Sets the blob\(aqs content type. -.TP -.B blob_content_md5: -Optional. Sets the blob\(aqs MD5 hash. -.TP -.B blob_content_encoding: -Optional. Sets the blob\(aqs content encoding. -.TP -.B blob_content_language: -Optional. Sets the blob\(aqs content language. -.TP -.B lease_id: -Required if the blob has an active lease. -.TP -.B blob_content_disposition: -Optional. Sets the blob\(aqs Content\-Disposition header. -The Content\-Disposition response header field conveys additional -information about how to process the response payload, and also can -be used to attach additional metadata. For example, if set to -attachment, it indicates that the user\-agent should not display the -response, but instead show a Save As dialog with a filename other -than the blob name specified. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.set_blob_service_properties(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Sets the properties of a storage account\(aqs Blob service, including -Windows Azure Storage Analytics. You can also use this operation to -set the default request version for all incoming requests that do not -have a version specified. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_blob_service_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B properties: -a StorageServiceProperties object. -.TP -.B timeout: -Optional. The timeout parameter is expressed in seconds. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.set_storage_container_acl(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Set a storage container\(aqs acl -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_storage_container my\-azure name=mycontainer -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of existing container. -.TP -.B signed_identifiers: -SignedIdentifers instance -.TP -.B blob_public_access: -Optional. Possible values include: container, blob -.TP -.B lease_id: -If specified, set_storage_container_acl only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.set_storage_container_metadata(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Set a storage container\(aqs metadata -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f set_storage_container my\-azure name=mycontainer \e - x_ms_meta_name_values=\(aq{\(dqmy_name\(dq: \(dqmy_value\(dq}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of existing container. -.TP -.B meta_name_values: -A dict containing name, value for metadata. -Example: {\(aqcategory\(aq:\(aqtest\(aq} -.TP -.B lease_id: -If specified, set_storage_container_metadata only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_affinity_group(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Show an affinity group associated with the account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_affinity_group my\-azure service=myservice \e - deployment=mydeployment name=SSH -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_blob_properties(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Returns all user\-defined metadata, standard HTTP properties, and -system properties for the blob. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_blob_properties my\-azure container=mycontainer blob=myblob -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B container: -Name of existing container. -.TP -.B blob: -Name of existing blob. -.TP -.B lease_id: -Required if the blob has an active lease. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_blob_service_properties(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a blob\(aqs service properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_blob_service_properties my\-azure -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_deployment(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_deployment my\-azure name=my_deployment -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_disk(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a disk -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_disk my\-azure name=my_disk -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_input_endpoint(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Show an input endpoint associated with the deployment -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_input_endpoint my\-azure service=myservice \e - deployment=mydeployment name=SSH -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_instance(name, call=None) -Show the details from the provider concerning an instance -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_management_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a management_certificate -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f get_management_certificate my\-azure name=my_management_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_service(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List hosted service properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_service my\-azure name=my_service -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_service_certificate(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Return information about a service certificate -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_service_certificate my\-azure name=my_service_certificate \e - thumbalgorithm=sha1 thumbprint=0123456789ABCDEF -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_storage(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -List storage service properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage my\-azure name=my_storage -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_storage_container(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a container associated with the storage account -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to show. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_storage_container_acl(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a storage container\(aqs acl -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container_acl my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of existing container. -.TP -.B lease_id: -If specified, show_storage_container_acl only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_storage_container_metadata(kwargs=None, storage_conn=None, call=None) -New in version 2015.8.0. - -.sp -Show a storage container\(aqs metadata -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_container_metadata my\-azure name=myservice -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B name: -Name of container to show. -.TP -.B lease_id: -If specified, show_storage_container_metadata only succeeds if the -container\(aqs lease is active and matches this ID. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.show_storage_keys(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Show storage account keys -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f show_storage_keys my\-azure name=my_storage -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.update_affinity_group(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Update an affinity group\(aqs properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_affinity_group my\-azure name=my_group label=my_group -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.update_disk(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Update a disk\(aqs properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_disk my\-azure name=my_disk label=my_disk -salt\-cloud \-f update_disk my\-azure name=my_disk new_name=another_disk -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.update_input_endpoint(kwargs=None, conn=None, call=None, activity=\(aqupdate\(aq) -New in version 2015.8.0. - -.sp -Update an input endpoint associated with the deployment. Please note that -there may be a delay before the changes show up. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_input_endpoint my\-azure service=myservice \e - deployment=mydeployment role=myrole name=HTTP local_port=80 \e - port=80 protocol=tcp enable_direct_server_return=False \e - timeout_for_tcp_idle_connection=4 -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.cloud.clouds.msazure.update_storage(kwargs=None, conn=None, call=None) -New in version 2015.8.0. - -.sp -Update a storage account\(aqs properties -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-cloud \-f update_storage my\-azure name=my_storage label=my_storage -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT .SS salt.cloud.clouds.oneandone .SS 1&1 Cloud Server Module .sp @@ -103421,6 +99300,14 @@ salt\-cloud \-a stop vm_name Checks profitbricks version .UNINDENT .SS salt.cloud.clouds.proxmox +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%proxmox Salt Extension\fP\&. +.UNINDENT +.UNINDENT .SS Proxmox Cloud Module .sp New in version 2014.7.0. @@ -103450,6 +99337,14 @@ my\-proxmox\-config: .fi .UNINDENT .UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This cloud provider will be removed from Salt in version 3009.0 in favor of +the \fI\%saltext.proxmox Salt Extension\fP +.UNINDENT +.UNINDENT .INDENT 0.0 .TP .B maintainer @@ -107719,293 +103614,6 @@ salt\-cloud \-a vif_list xenvm01 .UNINDENT .UNINDENT .UNINDENT -.SS Configuring Salt -.sp -Salt configuration is very simple. The default configuration for the -\fI\%master\fP will work for most installations and the only requirement for -setting up a \fI\%minion\fP is to set the location of the master in the minion -configuration file. -.sp -The configuration files will be installed to \fB/etc/salt\fP and are named -after the respective components, \fB/etc/salt/master\fP, and -\fB/etc/salt/minion\fP\&. -.SS Master Configuration -.sp -By default the Salt master listens on ports 4505 and 4506 on all -interfaces (0.0.0.0). To bind Salt to a specific IP, redefine the -\(dqinterface\(dq directive in the master configuration file, typically -\fB/etc/salt/master\fP, as follows: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -\- #interface: 0.0.0.0 -+ interface: 10.0.0.1 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -After updating the configuration file, restart the Salt master. -See the \fI\%master configuration reference\fP -for more details about other configurable options. -.SS Minion Configuration -.sp -Although there are many Salt Minion configuration options, configuring -a Salt Minion is very simple. By default a Salt Minion will -try to connect to the DNS name \(dqsalt\(dq; if the Minion is able to -resolve that name correctly, no configuration is needed. -.sp -If the DNS name \(dqsalt\(dq does not resolve to point to the correct -location of the Master, redefine the \(dqmaster\(dq directive in the minion -configuration file, typically \fB/etc/salt/minion\fP, as follows: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -\- #master: salt -+ master: 10.0.0.1 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -After updating the configuration file, restart the Salt minion. -See the \fI\%minion configuration reference\fP -for more details about other configurable options. -.SS Proxy Minion Configuration -.sp -A proxy minion emulates the behaviour of a regular minion -and inherits their options. -.sp -Similarly, the configuration file is \fB/etc/salt/proxy\fP and the proxy -tries to connect to the DNS name \(dqsalt\(dq. -.sp -In addition to the regular minion options, -there are several proxy\-specific \- see the -\fI\%proxy minion configuration reference\fP\&. -.SS Running Salt -.INDENT 0.0 -.IP 1. 3 -Start the master in the foreground (to daemonize the process, pass the -\fI\%\-d flag\fP): -.INDENT 3.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-master -.ft P -.fi -.UNINDENT -.UNINDENT -.IP 2. 3 -Start the minion in the foreground (to daemonize the process, pass the -\fI\%\-d flag\fP): -.INDENT 3.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-minion -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.IP "Having trouble?" -.sp -The simplest way to troubleshoot Salt is to run the master and minion in -the foreground with \fI\%log level\fP set to \fBdebug\fP: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-master \-\-log\-level=debug -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -For information on salt\(aqs logging system please see the \fI\%logging -document\fP\&. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.INDENT 3.5 -.IP "Run as an unprivileged (non\-root) user" -.sp -To run Salt as another user, set the \fI\%user\fP parameter in the -master config file. -.sp -Additionally, ownership, and permissions need to be set such that the -desired user can read from and write to the following directories (and -their subdirectories, where applicable): -.INDENT 0.0 -.IP \(bu 2 -/etc/salt -.IP \(bu 2 -/var/cache/salt -.IP \(bu 2 -/var/log/salt -.IP \(bu 2 -/var/run/salt -.UNINDENT -.sp -More information about running salt as a non\-privileged user can be found -\fI\%here\fP\&. -.UNINDENT -.UNINDENT -.sp -There is also a full \fI\%troubleshooting guide\fP -available. -.SS Key Identity -.sp -Salt provides commands to validate the identity of your Salt master -and Salt minions before the initial key exchange. Validating key identity helps -avoid inadvertently connecting to the wrong Salt master, and helps prevent -a potential MiTM attack when establishing the initial connection. -.SS Master Key Fingerprint -.sp -Print the master key fingerprint by running the following command on the Salt master: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-key \-F master -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Copy the \fBmaster.pub\fP fingerprint from the \fILocal Keys\fP section, and then set this value -as the \fI\%master_finger\fP in the minion configuration file. Save the configuration -file and then restart the Salt minion. -.SS Minion Key Fingerprint -.sp -Run the following command on each Salt minion to view the minion key fingerprint: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call \-\-local key.finger -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Compare this value to the value that is displayed when you run the -\fBsalt\-key \-\-finger \fP command on the Salt master. -.SS Key Management -.sp -Salt uses AES encryption for all communication between the Master and -the Minion. This ensures that the commands sent to the Minions cannot -be tampered with, and that communication between Master and Minion is -authenticated through trusted, accepted keys. -.sp -Before commands can be sent to a Minion, its key must be accepted on -the Master. Run the \fBsalt\-key\fP command to list the keys known to -the Salt Master: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -[root@master ~]# salt\-key \-L -Unaccepted Keys: -alpha -bravo -charlie -delta -Accepted Keys: -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -This example shows that the Salt Master is aware of four Minions, but none of -the keys has been accepted. To accept the keys and allow the Minions to be -controlled by the Master, again use the \fBsalt\-key\fP command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -[root@master ~]# salt\-key \-A -[root@master ~]# salt\-key \-L -Unaccepted Keys: -Accepted Keys: -alpha -bravo -charlie -delta -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The \fBsalt\-key\fP command allows for signing keys individually or in bulk. The -example above, using \fB\-A\fP bulk\-accepts all pending keys. To accept keys -individually use the lowercase of the same option, \fB\-a keyname\fP\&. -.sp -\fBSEE ALSO:\fP -.INDENT 0.0 -.INDENT 3.5 -\fI\%salt\-key manpage\fP -.UNINDENT -.UNINDENT -.SS Sending Commands -.sp -Communication between the Master and a Minion may be verified by running -the \fBtest.version\fP command: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -[root@master ~]# salt alpha test.version -alpha: - 2018.3.4 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Communication between the Master and all Minions may be tested in a -similar way: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -[root@master ~]# salt \(aq*\(aq test.version -alpha: - 2018.3.4 -bravo: - 2018.3.4 -charlie: - 2018.3.4 -delta: - 2018.3.4 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Each of the Minions should send a \fB2018.3.4\fP response as shown above, -or any other salt version installed. -.SS What\(aqs Next? -.sp -Understanding \fI\%targeting\fP is important. From there, depending -on the way you wish to use Salt, you should also proceed to learn about -\fI\%Remote Execution\fP and \fI\%Configuration Management\fP\&. .SS engine modules .TS center; @@ -108014,7 +103622,6 @@ _ T{ \fI\%docker_events\fP T} T{ -Send events from Docker events :Depends: Docker API >= 1.22 T} _ T{ @@ -108128,6 +103735,14 @@ _ .TE .SS salt.engines.docker_events .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Send events from Docker events :Depends: Docker API >= 1.22 .INDENT 0.0 @@ -111080,30 +106695,6 @@ Support for the Amazon Simple Queue Service. T} _ T{ -\fI\%azurearm_compute\fP -T} T{ -Azure (ARM) Compute Execution Module -T} -_ -T{ -\fI\%azurearm_dns\fP -T} T{ -Azure (ARM) DNS Execution Module -T} -_ -T{ -\fI\%azurearm_network\fP -T} T{ -Azure (ARM) Network Execution Module -T} -_ -T{ -\fI\%azurearm_resource\fP -T} T{ -Azure (ARM) Resource Execution Module -T} -_ -T{ \fI\%bamboohr\fP T} T{ Support for BambooHR @@ -111386,11 +106977,6 @@ Cassandra Database Module T} _ T{ -\fI\%cassandra_mod\fP -T} T{ -T} -_ -T{ \fI\%celery\fP T} T{ Support for scheduling celery tasks. @@ -111561,7 +107147,6 @@ _ T{ \fI\%deb_apache\fP T} T{ -Support for Apache T} _ T{ @@ -111645,13 +107230,11 @@ _ T{ \fI\%dockercompose\fP T} T{ -Module to import docker\-compose via saltstack T} _ T{ \fI\%dockermod\fP T} T{ -Management of Docker Containers T} _ T{ @@ -111903,7 +107486,7 @@ _ T{ \fI\%gpg\fP T} T{ -Manage a GPG keychains, add keys, create keys, retrieve keys from keyservers. +Manage GPG keychains, add keys, create keys, retrieve keys from keyservers. T} _ T{ @@ -112170,7 +107753,6 @@ _ T{ \fI\%k8s\fP T} T{ -Salt module to manage Kubernetes cluster T} _ T{ @@ -112236,13 +107818,11 @@ _ T{ \fI\%kubeadm\fP T} T{ -Module for kubeadm :maintainer: Alberto Planas <\fI\%aplanas@suse.com\fP> :maturity: new :depends: None :platform: Linux T} _ T{ \fI\%kubernetesmod\fP T} T{ -Module for handling kubernetes calls. T} _ T{ @@ -113118,7 +108698,6 @@ _ T{ \fI\%pushover_notify\fP T} T{ -Module for sending messages to Pushover (\fI\%https://www.pushover.net\fP) T} _ T{ @@ -113580,7 +109159,6 @@ _ T{ \fI\%suse_apache\fP T} T{ -Support for Apache T} _ T{ @@ -113790,7 +109368,6 @@ _ T{ \fI\%vault\fP T} T{ -Functions to interact with Hashicorp Vault. T} _ T{ @@ -113848,6 +109425,12 @@ Support for htpasswd command. T} _ T{ +\fI\%win_appx\fP +T} T{ +Manage provisioned apps +T} +_ +T{ \fI\%win_auditpol\fP T} T{ A salt module for modifying the audit policies on the machine @@ -114138,7 +109721,6 @@ _ T{ \fI\%zabbix\fP T} T{ -Support for Zabbix T} _ T{ @@ -114257,7 +109839,7 @@ Make sure the appropriate certbot plugin for the wanted DNS provider is installed before using this module. .INDENT 0.0 .TP -.B salt.modules.acme.cert(name, aliases=None, email=None, webroot=None, test_cert=False, renew=None, keysize=None, server=None, owner=\(aqroot\(aq, group=\(aqroot\(aq, mode=\(aq0640\(aq, certname=None, preferred_challenges=None, tls_sni_01_port=None, tls_sni_01_address=None, http_01_port=None, http_01_address=None, dns_plugin=None, dns_plugin_credentials=None) +.B salt.modules.acme.cert(name, aliases=None, email=None, webroot=None, test_cert=False, renew=None, keysize=None, server=None, owner=\(aqroot\(aq, group=\(aqroot\(aq, mode=\(aq0640\(aq, certname=None, preferred_challenges=None, tls_sni_01_port=None, tls_sni_01_address=None, http_01_port=None, http_01_address=None, dns_plugin=None, dns_plugin_credentials=None, manual_auth_hook=None, manual_cleanup_hook=None) Obtain/renew a certificate from an ACME CA, probably Let\(aqs Encrypt. .INDENT 7.0 .TP @@ -114315,6 +109897,10 @@ the specified DNS plugin .IP \(bu 2 \fBdns_plugin_propagate_seconds\fP \-\- Number of seconds to wait for DNS propogations before asking ACME servers to verify the DNS record. (default 10) +.IP \(bu 2 +\fBmanual_auth_hook\fP \-\- Path to the manual authentication hook script. +.IP \(bu 2 +\fBmanual_cleanup_hook\fP \-\- Path to the manual cleanup or post\-authentication hook script. .UNINDENT .TP .B Return type @@ -116867,6 +112453,9 @@ salt \(aq*\(aq pkg.autoremove purge=True This function is an alias of \fBlatest_version\fP\&. .INDENT 7.0 .INDENT 3.5 +Changed in version 3007.0. + +.sp Return the latest version of the named package available for upgrade or installation. If more than one package name is specified, a dict of name/version pairs is returned. @@ -117378,6 +112967,9 @@ Returns a dict containing the new package names and versions: .INDENT 0.0 .TP .B salt.modules.aptpkg.latest_version(*names, **kwargs) +Changed in version 3007.0. + +.sp Return the latest version of the named package available for upgrade or installation. If more than one package name is specified, a dict of name/version pairs is returned. @@ -119966,6 +115558,13 @@ Artifactory username. Optional parameter. Artifactory password. Optional parameter. .UNINDENT .UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.artifactory.set_basic_auth(url, username, password) +Sets the username and password for a specific url. Helper method. +.sp +CLI Example: +.UNINDENT .SS salt.modules.at .sp Wrapper module for at(1) @@ -120722,3957 +116321,6 @@ salt \(aq*\(aq aws_sqs.receive_message num=10 .sp New in version 2014.7.0. -.UNINDENT -.SS salt.modules.azurearm_compute -.sp -Azure (ARM) Compute Execution Module -.sp -New in version 2019.2.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as keyword arguments -to every function in order to work properly. -.sp -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.UNINDENT -.INDENT 0.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. -.INDENT 7.0 -.TP -.B Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.availability_set_create_or_update(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update an availability set. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The availability set to create. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -availability set. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.availability_set_create_or_update testset testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.availability_set_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete an availability set. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The availability set to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -availability set. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.availability_set_delete testset testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.availability_set_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get a dictionary representing an availability set\(aqs properties. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The availability set to get. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -availability set. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.availability_set_get testset testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.availability_sets_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all availability sets within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list availability -sets within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.availability_sets_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.availability_sets_list_available_sizes(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all available virtual machine sizes that can be used to -to create a new virtual machine in an existing availability set. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The availability set name to list available -virtual machine sizes within. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name to list available -availability set sizes within. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.availability_sets_list_available_sizes testset testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_capture(name, destination_name, resource_group, prefix=\(aqcapture\-\(aq, overwrite=False, **kwargs) -New in version 2019.2.0. - -.sp -Captures the VM by copying virtual hard disks of the VM and outputs -a template that can be used to create similar VMs. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine. -.IP \(bu 2 -\fBdestination_name\fP \-\- The destination container name. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.IP \(bu 2 -\fBprefix\fP \-\- (Default: \(aqcapture\-\(aq) The captured virtual hard disk\(aqs name prefix. -.IP \(bu 2 -\fBoverwrite\fP \-\- (Default: False) Overwrite the destination disk in case of conflict. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_capture testvm testcontainer testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_convert_to_managed_disks(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Converts virtual machine disks from blob\-based to managed disks. Virtual -machine must be stop\-deallocated before invoking this operation. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine to convert. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_convert_to_managed_disks testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_deallocate(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Power off a virtual machine and deallocate compute resources. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine to deallocate. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_deallocate testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_generalize(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Set the state of a virtual machine to \(aqgeneralized\(aq. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_generalize testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Retrieves information about the model view or the instance view of a -virtual machine. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_get testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_power_off(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Power off (stop) a virtual machine. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine to stop. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_power_off testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_redeploy(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Redeploy a virtual machine. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine to redeploy. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_redeploy testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_restart(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Restart a virtual machine. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine to restart. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_restart testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machine_start(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Power on (start) a virtual machine. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine to start. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machine_start testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machines_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all virtual machines within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list virtual -machines within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machines_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machines_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all virtual machines within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machines_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_compute.virtual_machines_list_available_sizes(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Lists all available virtual machine sizes to which the specified virtual -machine can be resized. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual machine. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual machine. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_compute.virtual_machines_list_available_sizes testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.modules.azurearm_dns -.sp -Azure (ARM) DNS Execution Module -.sp -New in version 3000. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-dns\fP >= 2.0.0rc1 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as keyword arguments -to every function in order to work properly. -.UNINDENT -.sp -Required provider parameters: -.INDENT 0.0 -.INDENT 3.5 -if using username and password: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.UNINDENT -.UNINDENT -.sp -if using a service principal: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.INDENT 0.0 -.INDENT 3.5 -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. -.sp -Possible values: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.record_set_create_or_update(name, zone_name, resource_group, record_type, **kwargs) -New in version 3000. - -.sp -Creates or updates a record set within a DNS zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the record set, relative to the name of the zone. -.IP \(bu 2 -\fBzone_name\fP \-\- The name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.IP \(bu 2 -\fBrecord_type\fP \-\- The type of DNS record in this record set. Record sets of type SOA can be -updated but not created (they are created when the DNS zone is created). -Possible values include: \(aqA\(aq, \(aqAAAA\(aq, \(aqCAA\(aq, \(aqCNAME\(aq, \(aqMX\(aq, \(aqNS\(aq, \(aqPTR\(aq, \(aqSOA\(aq, \(aqSRV\(aq, \(aqTXT\(aq -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.record_set_create_or_update myhost myzone testgroup A - arecords=\(aq[{ipv4_address: 10.0.0.1}]\(aq ttl=300 -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.record_set_delete(name, zone_name, resource_group, record_type, **kwargs) -New in version 3000. - -.sp -Deletes a record set from a DNS zone. This operation cannot be undone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the record set, relative to the name of the zone. -.IP \(bu 2 -\fBzone_name\fP \-\- The name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.IP \(bu 2 -\fBrecord_type\fP \-\- The type of DNS record in this record set. Record sets of type SOA cannot be -deleted (they are deleted when the DNS zone is deleted). -Possible values include: \(aqA\(aq, \(aqAAAA\(aq, \(aqCAA\(aq, \(aqCNAME\(aq, \(aqMX\(aq, \(aqNS\(aq, \(aqPTR\(aq, \(aqSOA\(aq, \(aqSRV\(aq, \(aqTXT\(aq -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.record_set_delete myhost myzone testgroup A -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.record_set_get(name, zone_name, resource_group, record_type, **kwargs) -New in version 3000. - -.sp -Get a dictionary representing a record set\(aqs properties. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the record set, relative to the name of the zone. -.IP \(bu 2 -\fBzone_name\fP \-\- The name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.IP \(bu 2 -\fBrecord_type\fP \-\- The type of DNS record in this record set. -Possible values include: \(aqA\(aq, \(aqAAAA\(aq, \(aqCAA\(aq, \(aqCNAME\(aq, \(aqMX\(aq, \(aqNS\(aq, \(aqPTR\(aq, \(aqSOA\(aq, \(aqSRV\(aq, \(aqTXT\(aq -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.record_set_get \(aq@\(aq myzone testgroup SOA -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.record_sets_list_by_dns_zone(zone_name, resource_group, top=None, recordsetnamesuffix=None, **kwargs) -New in version 3000. - -.sp -Lists all record sets in a DNS zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBzone_name\fP \-\- The name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.IP \(bu 2 -\fBtop\fP \-\- The maximum number of record sets to return. If not specified, -returns up to 100 record sets. -.IP \(bu 2 -\fBrecordsetnamesuffix\fP \-\- The suffix label of the record set name that has -to be used to filter the record set enumerations. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.record_sets_list_by_dns_zone myzone testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.record_sets_list_by_type(zone_name, resource_group, record_type, top=None, recordsetnamesuffix=None, **kwargs) -New in version 3000. - -.sp -Lists the record sets of a specified type in a DNS zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBzone_name\fP \-\- The name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.IP \(bu 2 -\fBrecord_type\fP \-\- The type of record sets to enumerate. -Possible values include: \(aqA\(aq, \(aqAAAA\(aq, \(aqCAA\(aq, \(aqCNAME\(aq, \(aqMX\(aq, \(aqNS\(aq, \(aqPTR\(aq, \(aqSOA\(aq, \(aqSRV\(aq, \(aqTXT\(aq -.IP \(bu 2 -\fBtop\fP \-\- The maximum number of record sets to return. If not specified, -returns up to 100 record sets. -.IP \(bu 2 -\fBrecordsetnamesuffix\fP \-\- The suffix label of the record set name that has -to be used to filter the record set enumerations. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.record_sets_list_by_type myzone testgroup SOA -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.zone_create_or_update(name, resource_group, **kwargs) -New in version 3000. - -.sp -Creates or updates a DNS zone. Does not modify DNS records within the zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the DNS zone to create (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.zone_create_or_update myzone testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.zone_delete(name, resource_group, **kwargs) -New in version 3000. - -.sp -Delete a DNS zone within a resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the DNS zone to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.zone_delete myzone testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.zone_get(name, resource_group, **kwargs) -New in version 3000. - -.sp -Get a dictionary representing a DNS zone\(aqs properties, but not the -record sets within the zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The DNS zone to get. -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.zone_get myzone testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.zones_list(top=None, **kwargs) -New in version 3000. - -.sp -Lists the DNS zones in all resource groups in a subscription. -.INDENT 7.0 -.TP -.B Parameters -\fBtop\fP \-\- The maximum number of DNS zones to return. If not specified, -eturns up to 100 zones. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.zones_list -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_dns.zones_list_by_resource_group(resource_group, top=None, **kwargs) -New in version 3000. - -.sp -Lists the DNS zones in a resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBresource_group\fP \-\- The name of the resource group. -.IP \(bu 2 -\fBtop\fP \-\- The maximum number of DNS zones to return. If not specified, -returns up to 100 zones. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_dns.zones_list_by_resource_group testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.modules.azurearm_network -.sp -Azure (ARM) Network Execution Module -.sp -New in version 2019.2.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as keyword arguments -to every function in order to work properly. -.sp -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.UNINDENT -.INDENT 0.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. -.INDENT 7.0 -.TP -.B Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.check_dns_name_availability(name, region, **kwargs) -New in version 2019.2.0. - -.sp -Check whether a domain name in the current zone is available for use. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The DNS name to query. -.IP \(bu 2 -\fBregion\fP \-\- The region to query for the DNS name in question. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.check_dns_name_availability testdnsname westus -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.check_ip_address_availability(ip_address, virtual_network, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Check that a private ip address is available within the specified -virtual network. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBip_address\fP \-\- The ip_address to query. -.IP \(bu 2 -\fBvirtual_network\fP \-\- The virtual network to query for the IP address -in question. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.check_ip_address_availability 10.0.0.4 testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.default_security_rule_get(name, security_group, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a default security rule within a security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the security rule to query. -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group containing the -security rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.default_security_rule_get DenyAllOutBound testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.default_security_rules_list(security_group, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List default security rules within a security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.default_security_rules_list testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.get_virtual_machine_scale_set_network_interface(name, scale_set, vm_index, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get information about a specific network interface within a scale set. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network interface to query. -.IP \(bu 2 -\fBscale_set\fP \-\- The name of the scale set containing the interface. -.IP \(bu 2 -\fBvm_index\fP \-\- The virtual machine index. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -scale set. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.get_virtual_machine_scale_set_network_interface test\-iface0 testset testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.list_virtual_machine_scale_set_network_interfaces(scale_set, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get information about all network interfaces within a scale set. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBscale_set\fP \-\- The name of the scale set to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -scale set. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.list_virtual_machine_scale_set_vm_network_interfaces testset testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.list_virtual_machine_scale_set_vm_network_interfaces(scale_set, vm_index, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get information about all network interfaces in a specific virtual machine within a scale set. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBscale_set\fP \-\- The name of the scale set to query. -.IP \(bu 2 -\fBvm_index\fP \-\- The virtual machine index. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -scale set. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.list_virtual_machine_scale_set_vm_network_interfaces testset testvm testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.load_balancer_create_or_update(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a load balancer within a specified resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the load balancer to create. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -load balancer. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.load_balancer_create_or_update testlb testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.load_balancer_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a load balancer. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the load balancer to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -load balancer. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.load_balancer_delete testlb testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.load_balancer_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific load balancer. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the load balancer to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -load balancer. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.load_balancer_get testlb testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.load_balancers_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all load balancers within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list load balancers -within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.load_balancers_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.load_balancers_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all load balancers within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.load_balancers_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interface_create_or_update(name, ip_configurations, subnet, virtual_network, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a network interface within a specified resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network interface to create. -.IP \(bu 2 -\fBip_configurations\fP \-\- A list of dictionaries representing valid -NetworkInterfaceIPConfiguration objects. The \(aqname\(aq key is required at -minimum. At least one IP Configuration must be present. -.IP \(bu 2 -\fBsubnet\fP \-\- The name of the subnet assigned to the network interface. -.IP \(bu 2 -\fBvirtual_network\fP \-\- The name of the virtual network assigned to the subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interface_create_or_update test\-iface0 [{\(aqname\(aq: \(aqtestipconfig1\(aq}] testsubnet testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interface_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a network interface. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network interface to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network interface. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interface_delete test\-iface0 testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interface_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific network interface. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network interface to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network interface. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interface_get test\-iface0 testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interface_get_effective_route_table(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get all route tables for a specific network interface. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network interface to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network interface. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interface_get_effective_route_table test\-iface0 testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interface_list_effective_network_security_groups(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get all network security groups applied to a specific network interface. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network interface to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network interface. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interface_list_effective_network_security_groups test\-iface0 testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interfaces_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all network interfaces within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list network -interfaces within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interfaces_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_interfaces_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all network interfaces within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_interfaces_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_security_group_create_or_update(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a network security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network security group to create. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_security_group_create_or_update testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_security_group_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a network security group within a resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network security group to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_security_group_delete testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_security_group_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a network security group within a resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the network security group to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_security_group_get testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_security_groups_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all network security groups within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list network security groups within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_security_groups_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.network_security_groups_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all network security groups within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.network_security_groups_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.public_ip_address_create_or_update(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a public IP address within a specified resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the public IP address to create. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -public IP address. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.public_ip_address_create_or_update test\-ip\-0 testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.public_ip_address_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a public IP address. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the public IP address to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -public IP address. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.public_ip_address_delete test\-pub\-ip testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.public_ip_address_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific public IP address. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the public IP address to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -public IP address. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.public_ip_address_get test\-pub\-ip testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.public_ip_addresses_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all public IP addresses within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list public IP -addresses within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.public_ip_addresses_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.public_ip_addresses_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all public IP addresses within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.public_ip_addresses_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_create_or_update(name, address_prefix, next_hop_type, route_table, resource_group, next_hop_ip_address=None, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a route within a specified route table. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route to create. -.IP \(bu 2 -\fBaddress_prefix\fP \-\- The destination CIDR to which the route applies. -.IP \(bu 2 -\fBnext_hop_type\fP \-\- The type of Azure hop the packet should be sent to. Possible values are: -\(aqVirtualNetworkGateway\(aq, \(aqVnetLocal\(aq, \(aqInternet\(aq, \(aqVirtualAppliance\(aq, and \(aqNone\(aq. -.IP \(bu 2 -\fBnext_hop_ip_address\fP \-\- Optional IP address to which packets should be forwarded. Next hop -values are only allowed in routes where the next_hop_type is \(aqVirtualAppliance\(aq. -.IP \(bu 2 -\fBroute_table\fP \-\- The name of the route table containing the route. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_create_or_update test\-rt \(aq10.0.0.0/8\(aq test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_delete(name, route_table, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a route from a route table. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The route to delete. -.IP \(bu 2 -\fBroute_table\fP \-\- The route table containing the route. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_delete test\-rt test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_create_or_update(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a route filter within a specified resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route filter to create. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_create_or_update test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a route filter. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route filter to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_delete test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific route filter. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route table to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_get test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_rule_create_or_update(name, access, communities, route_filter, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a rule within a specified route filter. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the rule to create. -.IP \(bu 2 -\fBaccess\fP \-\- The access type of the rule. Valid values are \(aqAllow\(aq and \(aqDeny\(aq. -.IP \(bu 2 -\fBcommunities\fP \-\- A list of BGP communities to filter on. -.IP \(bu 2 -\fBroute_filter\fP \-\- The name of the route filter containing the rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_rule_create_or_update test\-rule allow \(dq[\(aq12076:51006\(aq]\(dq test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_rule_delete(name, route_filter, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a route filter rule. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The route filter rule to delete. -.IP \(bu 2 -\fBroute_filter\fP \-\- The route filter containing the rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_rule_delete test\-rule test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_rule_get(name, route_filter, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific route filter rule. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The route filter rule to query. -.IP \(bu 2 -\fBroute_filter\fP \-\- The route filter containing the rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_rule_get test\-rule test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filter_rules_list(route_filter, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all routes within a route filter. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBroute_filter\fP \-\- The route filter to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route filter. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filter_rules_list test\-filter testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filters_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all route filters within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list route -filters within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filters_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_filters_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all route filters within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_filters_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_get(name, route_table, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific route. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The route to query. -.IP \(bu 2 -\fBroute_table\fP \-\- The route table containing the route. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_get test\-rt test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_table_create_or_update(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a route table within a specified resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route table to create. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_table_create_or_update test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_table_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a route table. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route table to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_table_delete test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_table_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific route table. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the route table to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_table_get test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_tables_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all route tables within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list route -tables within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_tables_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.route_tables_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all route tables within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.route_tables_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.routes_list(route_table, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all routes within a route table. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBroute_table\fP \-\- The route table to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -route table. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.routes_list test\-rt\-table testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.security_rule_create_or_update(name, access, direction, priority, protocol, security_group, resource_group, source_address_prefix=None, destination_address_prefix=None, source_port_range=None, destination_port_range=None, source_address_prefixes=None, destination_address_prefixes=None, source_port_ranges=None, destination_port_ranges=None, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a security rule within a specified network security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the security rule to create. -.IP \(bu 2 -\fBaccess\fP \-\- \(aqallow\(aq or \(aqdeny\(aq -.IP \(bu 2 -\fBdirection\fP \-\- \(aqinbound\(aq or \(aqoutbound\(aq -.IP \(bu 2 -\fBpriority\fP \-\- Integer between 100 and 4096 used for ordering rule application. -.IP \(bu 2 -\fBprotocol\fP \-\- \(aqtcp\(aq, \(aqudp\(aq, or \(aq*\(aq -.IP \(bu 2 -\fBdestination_address_prefix\fP \-\- The CIDR or destination IP range. Asterix \(aq*\(aq can also be used to match all destination IPs. -Default tags such as \(aqVirtualNetwork\(aq, \(aqAzureLoadBalancer\(aq and \(aqInternet\(aq can also be used. -If this is an ingress rule, specifies where network traffic originates from. -.IP \(bu 2 -\fBdestination_port_range\fP \-\- The destination port or range. Integer or range between 0 and 65535. Asterix \(aq*\(aq -can also be used to match all ports. -.IP \(bu 2 -\fBsource_address_prefix\fP \-\- The CIDR or source IP range. Asterix \(aq*\(aq can also be used to match all source IPs. -Default tags such as \(aqVirtualNetwork\(aq, \(aqAzureLoadBalancer\(aq and \(aqInternet\(aq can also be used. -If this is an ingress rule, specifies where network traffic originates from. -.IP \(bu 2 -\fBsource_port_range\fP \-\- The source port or range. Integer or range between 0 and 65535. Asterix \(aq*\(aq -can also be used to match all ports. -.IP \(bu 2 -\fBdestination_address_prefixes\fP \-\- A list of destination_address_prefix values. This parameter overrides destination_address_prefix -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBdestination_port_ranges\fP \-\- A list of destination_port_range values. This parameter overrides destination_port_range -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBsource_address_prefixes\fP \-\- A list of source_address_prefix values. This parameter overrides source_address_prefix -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBsource_port_ranges\fP \-\- A list of source_port_range values. This parameter overrides source_port_range -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group containing the -security rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.security_rule_create_or_update testrule1 allow outbound 101 tcp testnsg testgroup source_address_prefix=\(aq*\(aq destination_address_prefix=internet source_port_range=\(aq*\(aq destination_port_range=\(aq1\-1024\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.security_rule_delete(security_rule, security_group, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a security rule within a specified security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the security rule to delete. -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group containing the -security rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.security_rule_delete testrule1 testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.security_rule_get(security_rule, security_group, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get a security rule within a specified network security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the security rule to query. -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group containing the -security rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.security_rule_get testrule1 testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.security_rules_list(security_group, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List security rules within a network security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -network security group. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.security_rules_list testnsg testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.subnet_create_or_update(name, address_prefix, virtual_network, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a subnet. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name assigned to the subnet being created or updated. -.IP \(bu 2 -\fBaddress_prefix\fP \-\- A valid CIDR block within the virtual network. -.IP \(bu 2 -\fBvirtual_network\fP \-\- The virtual network name containing the -subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.subnet_create_or_update testsubnet \(aq10.0.0.0/24\(aq testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.subnet_delete(name, virtual_network, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a subnet. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the subnet to delete. -.IP \(bu 2 -\fBvirtual_network\fP \-\- The virtual network name containing the -subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.subnet_delete testsubnet testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.subnet_get(name, virtual_network, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific subnet. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the subnet to query. -.IP \(bu 2 -\fBvirtual_network\fP \-\- The virtual network name containing the -subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.subnet_get testsubnet testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.subnets_list(virtual_network, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all subnets within a virtual network. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBvirtual_network\fP \-\- The virtual network name to list subnets within. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.subnets_list testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.usages_list(location, **kwargs) -New in version 2019.2.0. - -.sp -List subscription network usage for a location. -.INDENT 7.0 -.TP -.B Parameters -\fBlocation\fP \-\- The Azure location to query for network usage. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.usages_list westus -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.virtual_network_create_or_update(name, address_prefixes, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a virtual network. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name assigned to the virtual network being -created or updated. -.IP \(bu 2 -\fBaddress_prefixes\fP \-\- A list of CIDR blocks which can be used -by subnets within the virtual network. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.virtual_network_create_or_update testnet [\(aq10.0.0.0/16\(aq] testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.virtual_network_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a virtual network. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual network to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.virtual_network_delete testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.virtual_network_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific virtual network. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the virtual network to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -virtual network. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.virtual_network_get testnet testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.virtual_networks_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all virtual networks within a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list virtual networks -within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.virtual_networks_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_network.virtual_networks_list_all(**kwargs) -New in version 2019.2.0. - -.sp -List all virtual networks within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_network.virtual_networks_list_all -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.modules.azurearm_resource -.sp -Azure (ARM) Resource Execution Module -.sp -New in version 2019.2.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as keyword arguments -to every function in order to work properly. -.sp -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.UNINDENT -.INDENT 0.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. -.INDENT 7.0 -.TP -.B Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_cancel(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Cancel a deployment if in \(aqAccepted\(aq or \(aqRunning\(aq state. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to cancel. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_cancel testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_check_existence(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Check the existence of a deployment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_check_existence testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_create_or_update(name, resource_group, deploy_mode=\(aqincremental\(aq, debug_setting=\(aqnone\(aq, deploy_params=None, parameters_link=None, deploy_template=None, template_link=None, **kwargs) -New in version 2019.2.0. - -.sp -Deploys resources to a resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to create or update. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.IP \(bu 2 -\fBdeploy_mode\fP \-\- The mode that is used to deploy resources. This value can be either -\(aqincremental\(aq or \(aqcomplete\(aq. In Incremental mode, resources are deployed without deleting -existing resources that are not included in the template. In Complete mode, resources -are deployed and existing resources in the resource group that are not included in -the template are deleted. Be careful when using Complete mode as you may -unintentionally delete resources. -.IP \(bu 2 -\fBdebug_setting\fP \-\- The debug setting of the deployment. The permitted values are \(aqnone\(aq, -\(aqrequestContent\(aq, \(aqresponseContent\(aq, or \(aqrequestContent,responseContent\(aq. By logging -information about the request or response, you could potentially expose sensitive data -that is retrieved through the deployment operations. -.IP \(bu 2 -\fBdeploy_params\fP \-\- JSON string containing name and value pairs that define the deployment -parameters for the template. You use this element when you want to provide the parameter -values directly in the request rather than link to an existing parameter file. Use either -the parameters_link property or the deploy_params property, but not both. -.IP \(bu 2 -\fBparameters_link\fP \-\- The URI of a parameters file. You use this element to link to an existing -parameters file. Use either the parameters_link property or the deploy_params property, but not both. -.IP \(bu 2 -\fBdeploy_template\fP \-\- JSON string of template content. You use this element when you want to pass -the template syntax directly in the request rather than link to an existing template. Use either -the template_link property or the deploy_template property, but not both. -.IP \(bu 2 -\fBtemplate_link\fP \-\- The URI of the template. Use either the template_link property or the -deploy_template property, but not both. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_create_or_update testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_delete(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Delete a deployment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to delete. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_delete testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_export_template(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Exports the template used for the specified deployment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_export_template testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_get(name, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific deployment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_get testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_operation_get(operation, deployment, resource_group, **kwargs) -New in version 2019.2.0. - -.sp -Get a deployment operation within a deployment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBoperation\fP \-\- The operation ID of the operation within the deployment. -.IP \(bu 2 -\fBdeployment\fP \-\- The name of the deployment containing the operation. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_operation_get XXXXX testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_operations_list(name, resource_group, result_limit=10, **kwargs) -New in version 2019.2.0. - -.sp -List all deployment operations within a deployment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to query. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.IP \(bu 2 -\fBresult_limit\fP \-\- (Default: 10) The limit on the list of deployment -operations. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_operations_list testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployment_validate(name, resource_group, deploy_mode=None, debug_setting=None, deploy_params=None, parameters_link=None, deploy_template=None, template_link=None, **kwargs) -New in version 2019.2.0. - -.sp -Validates whether the specified template is syntactically correct -and will be accepted by Azure Resource Manager. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the deployment to validate. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group name assigned to the -deployment. -.IP \(bu 2 -\fBdeploy_mode\fP \-\- The mode that is used to deploy resources. This value can be either -\(aqincremental\(aq or \(aqcomplete\(aq. In Incremental mode, resources are deployed without deleting -existing resources that are not included in the template. In Complete mode, resources -are deployed and existing resources in the resource group that are not included in -the template are deleted. Be careful when using Complete mode as you may -unintentionally delete resources. -.IP \(bu 2 -\fBdebug_setting\fP \-\- The debug setting of the deployment. The permitted values are \(aqnone\(aq, -\(aqrequestContent\(aq, \(aqresponseContent\(aq, or \(aqrequestContent,responseContent\(aq. By logging -information about the request or response, you could potentially expose sensitive data -that is retrieved through the deployment operations. -.IP \(bu 2 -\fBdeploy_params\fP \-\- JSON string containing name and value pairs that define the deployment -parameters for the template. You use this element when you want to provide the parameter -values directly in the request rather than link to an existing parameter file. Use either -the parameters_link property or the deploy_params property, but not both. -.IP \(bu 2 -\fBparameters_link\fP \-\- The URI of a parameters file. You use this element to link to an existing -parameters file. Use either the parameters_link property or the deploy_params property, but not both. -.IP \(bu 2 -\fBdeploy_template\fP \-\- JSON string of template content. You use this element when you want to pass -the template syntax directly in the request rather than link to an existing template. Use either -the template_link property or the deploy_template property, but not both. -.IP \(bu 2 -\fBtemplate_link\fP \-\- The URI of the template. Use either the template_link property or the -deploy_template property, but not both. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployment_validate testdeploy testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.deployments_list(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all deployments within a resource group. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.deployments_list testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_assignment_create(name, scope, definition_name, **kwargs) -New in version 2019.2.0. - -.sp -Create a policy assignment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the policy assignment to create. -.IP \(bu 2 -\fBscope\fP \-\- The scope of the policy assignment. -.IP \(bu 2 -\fBdefinition_name\fP \-\- The name of the policy definition to assign. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_assignment_create testassign /subscriptions/bc75htn\-a0fhsi\-349b\-56gh\-4fghti\-f84852 testpolicy -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_assignment_delete(name, scope, **kwargs) -New in version 2019.2.0. - -.sp -Delete a policy assignment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the policy assignment to delete. -.IP \(bu 2 -\fBscope\fP \-\- The scope of the policy assignment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_assignment_delete testassign /subscriptions/bc75htn\-a0fhsi\-349b\-56gh\-4fghti\-f84852 -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_assignment_get(name, scope, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific policy assignment. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the policy assignment to query. -.IP \(bu 2 -\fBscope\fP \-\- The scope of the policy assignment. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_assignment_get testassign /subscriptions/bc75htn\-a0fhsi\-349b\-56gh\-4fghti\-f84852 -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_assignments_list(**kwargs) -New in version 2019.2.0. - -.sp -List all policy assignments for a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_assignments_list -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_assignments_list_for_resource_group(resource_group, **kwargs) -New in version 2019.2.0. - -.sp -List all policy assignments for a resource group. -.INDENT 7.0 -.TP -.B Parameters -\fBresource_group\fP \-\- The resource group name to list policy assignments within. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_assignments_list_for_resource_group testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_definition_create_or_update(name, policy_rule, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a policy definition. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the policy definition to create or update. -.IP \(bu 2 -\fBpolicy_rule\fP \-\- A dictionary defining the -\fI\%policy rule\fP\&. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_definition_create_or_update testpolicy \(aq{...rule definition..}\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_definition_delete(name, **kwargs) -New in version 2019.2.0. - -.sp -Delete a policy definition. -.INDENT 7.0 -.TP -.B Parameters -\fBname\fP \-\- The name of the policy definition to delete. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_definition_delete testpolicy -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_definition_get(name, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a specific policy definition. -.INDENT 7.0 -.TP -.B Parameters -\fBname\fP \-\- The name of the policy definition to query. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_definition_get testpolicy -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.policy_definitions_list(hide_builtin=False, **kwargs) -New in version 2019.2.0. - -.sp -List all policy definitions for a subscription. -.INDENT 7.0 -.TP -.B Parameters -\fBhide_builtin\fP \-\- Boolean which will filter out BuiltIn policy definitions from the result. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.policy_definitions_list -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.resource_group_check_existence(name, **kwargs) -New in version 2019.2.0. - -.sp -Check for the existence of a named resource group in the current subscription. -.INDENT 7.0 -.TP -.B Parameters -\fBname\fP \-\- The resource group name to check. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.resource_group_check_existence testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.resource_group_create_or_update(name, location, **kwargs) -New in version 2019.2.0. - -.sp -Create or update a resource group in a given location. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the resource group to create or update. -.IP \(bu 2 -\fBlocation\fP \-\- The location of the resource group. This value -is not able to be updated once the resource group is created. -.UNINDENT -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.resource_group_create_or_update testgroup westus -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.resource_group_delete(name, **kwargs) -New in version 2019.2.0. - -.sp -Delete a resource group from the subscription. -.INDENT 7.0 -.TP -.B Parameters -\fBname\fP \-\- The resource group name to delete. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.resource_group_delete testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.resource_group_get(name, **kwargs) -New in version 2019.2.0. - -.sp -Get a dictionary representing a resource group\(aqs properties. -.INDENT 7.0 -.TP -.B Parameters -\fBname\fP \-\- The resource group name to get. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.resource_group_get testgroup -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.resource_groups_list(**kwargs) -New in version 2019.2.0. - -.sp -List all resource groups within a subscription. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.resource_groups_list -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.subscription_get(subscription_id=None, **kwargs) -New in version 2019.2.0. - -.sp -Get details about a subscription. -.INDENT 7.0 -.TP -.B Parameters -\fBsubscription_id\fP \-\- The ID of the subscription to query. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.subscription_get XXXXXXXX -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.subscriptions_list(**kwargs) -New in version 2019.2.0. - -.sp -List all subscriptions for a tenant. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.subscriptions_list -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.subscriptions_list_locations(subscription_id=None, **kwargs) -New in version 2019.2.0. - -.sp -List all locations for a subscription. -.INDENT 7.0 -.TP -.B Parameters -\fBsubscription_id\fP \-\- The ID of the subscription to query. -.UNINDENT -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.subscriptions_list_locations XXXXXXXX -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.azurearm_resource.tenants_list(**kwargs) -New in version 2019.2.0. - -.sp -List all tenants for your account. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call azurearm_resource.tenants_list -.ft P -.fi -.UNINDENT -.UNINDENT .UNINDENT .SS salt.modules.bamboohr .sp @@ -147448,197 +139096,6 @@ salt \(aqminion1\(aq cassandra_cql.version contact_points=minion1 .UNINDENT .UNINDENT .UNINDENT -.SS salt.modules.cassandra_mod -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -The \fIcassandra\fP module is deprecated in favor of the \fIcassandra_cql\fP -module. -.UNINDENT -.UNINDENT -.sp -Cassandra NoSQL Database Module -.INDENT 0.0 -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -pycassa Cassandra Python adapter -.UNINDENT -.TP -.B configuration -The location of the \(aqnodetool\(aq command, host, and thrift port needs to be -specified via pillar: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -cassandra.nodetool: /usr/local/bin/nodetool -cassandra.host: localhost -cassandra.thrift_port: 9160 -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.column_families(keyspace=None) -Return existing column families for all keyspaces -or just the provided one. -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.column_families -salt \(aq*\(aq cassandra.column_families -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.column_family_definition(keyspace, column_family) -Return a dictionary of column family definitions for the given -keyspace/column_family -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.column_family_definition -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.compactionstats() -Return compactionstats info -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.compactionstats -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.info() -Return cassandra node info -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.info -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.keyspaces() -Return existing keyspaces -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.keyspaces -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.netstats() -Return netstats info -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.netstats -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.ring() -Return cassandra ring info -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.ring -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.tpstats() -Return tpstats info -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.tpstats -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.modules.cassandra_mod.version() -Return the cassandra version -.sp -CLI Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt \(aq*\(aq cassandra.version -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT .SS salt.modules.celery .sp Support for scheduling celery tasks. The worker is independent of salt and thus can run in a different @@ -157921,6 +149378,87 @@ depending on the shell being used to run the command. .UNINDENT .INDENT 0.0 .TP +.B salt.modules.cp.cache_file_ssh(path, saltenv=None, source_hash=None, verify_ssl=True, use_etag=False) +This function is an alias of \fBcache_file\fP\&. +.INDENT 7.0 +.INDENT 3.5 +Changed in version 3005: \fBsaltenv\fP will use value from config if not explicitly set + +.sp +Used to cache a single file on the Minion +.sp +Returns the location of the new cached file on the Minion +.INDENT 0.0 +.TP +.B source_hash +If \fBname\fP is an http(s) or ftp URL and the file exists in the +minion\(aqs file cache, this option can be passed to keep the minion from +re\-downloading the file if the cached copy matches the specified hash. +.sp +New in version 2018.3.0. + +.TP +.B verify_ssl +If \fBFalse\fP, remote https file sources (\fBhttps://\fP) and source_hash +will not attempt to validate the servers certificate. Default is True. +.sp +New in version 3002. + +.TP +.B use_etag +If \fBTrue\fP, remote http/https file sources will attempt to use the +ETag header to determine if the remote file needs to be downloaded. +This provides a lightweight mechanism for promptly refreshing files +changed on a web server without requiring a full hash comparison via +the \fBsource_hash\fP parameter. +.sp +New in version 3005. + +.UNINDENT +.sp +CLI Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq cp.cache_file salt://path/to/file +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +There are two ways of defining the fileserver environment (a.k.a. +\fBsaltenv\fP) from which to cache the file. One is to use the \fBsaltenv\fP +parameter, and the other is to use a querystring syntax in the \fBsalt://\fP +URL. The below two examples are equivalent: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq cp.cache_file salt://foo/bar.conf saltenv=config +salt \(aq*\(aq cp.cache_file salt://foo/bar.conf?saltenv=config +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +If the path being cached is a \fBsalt://\fP URI, and the path does not exist, +then \fBFalse\fP will be returned. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +It may be necessary to quote the URL when using the querystring method, +depending on the shell being used to run the command. +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.cp.cache_files(paths, saltenv=None) Changed in version 3005: \fBsaltenv\fP will use value from config if not explicitly set @@ -158262,6 +149800,33 @@ salt \(aq*\(aq cp.hash_file salt://path/to/file .UNINDENT .INDENT 0.0 .TP +.B salt.modules.cp.hash_file_ssh(path, saltenv=None) +This function is an alias of \fBhash_file\fP\&. +.INDENT 7.0 +.INDENT 3.5 +Changed in version 3005: \fBsaltenv\fP will use value from config if not explicitly set + +.sp +Return the hash of a file, to get the hash of a file on the +salt master file server prepend the path with salt:// +otherwise, prepend the file with / for a local file. +.sp +CLI Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq cp.hash_file salt://path/to/file +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.cp.is_cached(path, saltenv=None) Changed in version 3005: \fBsaltenv\fP will use value from config if not explicitly set @@ -158367,7 +149932,7 @@ salt \(aq*\(aq cp.list_minion Changed in version 3005: \fBsaltenv\fP will use value from config if not explicitly set .sp -List all of the available state modules in an environment +List all of the available state files in an environment .sp CLI Example: .INDENT 7.0 @@ -160186,6 +151751,14 @@ salt ns1 ddns.update example.com host1 60 A 10.0.0.1 .UNINDENT .SS salt.modules.deb_apache .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%apache Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Support for Apache .sp Please note: The functions in here are Debian\-specific. Placing them in this @@ -161962,6 +153535,14 @@ salt \(aq*\(aq disk.blkid token=\(aqTYPE=ext4\(aq .TP .B salt.modules.disk.dump(device, args=None) Return all contents of dumpe2fs for a specified device +.INDENT 7.0 +.TP +.B device +The device path to dump. +.TP +.B args +A list of attributes to return. Returns all by default. +.UNINDENT .sp CLI Example: .INDENT 7.0 @@ -162081,13 +153662,19 @@ salt \(aq*\(aq disk.get_fstype_from_path /root .UNINDENT .INDENT 0.0 .TP -.B salt.modules.disk.hdparms(disks, args=None) -Retrieve all info\(aqs for all disks -parse \(aqem into a nice dict -(which, considering hdparms output, is quite a hassle) +.B salt.modules.disk.hdparms(disks, args=\(aqaAbBcCdgHiJkMmNnQrRuW\(aq) +Retrieve disk parameters. .sp New in version 2016.3.0. +.INDENT 7.0 +.TP +.B disks +Single disk or list of disks to query. +.TP +.B args +Sequence of \fBhdparm\fP flags to fetch. +.UNINDENT .sp CLI Example: .INDENT 7.0 @@ -162140,6 +153727,11 @@ salt \(aq*\(aq disk.hpa /dev/sda 10543256 .TP .B salt.modules.disk.inodeusage(args=None) Return inode usage information for volumes mounted on this minion +.INDENT 7.0 +.TP +.B args +Sequence of flags to pass to the \fBdf\fP command. +.UNINDENT .sp CLI Example: .INDENT 7.0 @@ -162180,6 +153772,11 @@ salt \(aq*\(aq disk.iostat 1 5 disks=sda .TP .B salt.modules.disk.percent(args=None) Return partition information for volumes mounted on this minion +.INDENT 7.0 +.TP +.B args +Specify a single partition for which to return data. +.UNINDENT .sp CLI Example: .INDENT 7.0 @@ -162264,6 +153861,11 @@ options. .TP .B salt.modules.disk.usage(args=None) Return usage information for volumes mounted on this minion +.INDENT 7.0 +.TP +.B args +Sequence of flags to pass to the \fBdf\fP command. +.UNINDENT .sp Changed in version 2019.2.0: Default for SunOS changed to 1 kilobyte blocks @@ -162821,6 +154423,14 @@ salt ns1 dnsutil.serial example.com .UNINDENT .SS salt.modules.dockercompose .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Module to import docker\-compose via saltstack .sp New in version 2016.3.0. @@ -163467,6 +155077,14 @@ salt myminion dockercompose.up /path/where/docker\-compose/stored \(aq[janus]\(a .UNINDENT .SS salt.modules.dockermod .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Docker Containers .sp New in version 2015.8.0. @@ -173724,8 +165342,16 @@ salt \(aq*\(aq extfs.dump /dev/sda1 .UNINDENT .INDENT 0.0 .TP -.B salt.modules.extfs.mkfs(device, fs_type, **kwargs) +.B salt.modules.extfs.mkfs(device, fs_type, full_return=False, **kwargs) Create a file system on the specified device +.INDENT 7.0 +.TP +.B full_return +False +If \fBTrue\fP, the full \fBcmd.run_all\fP dictionary will be returned +instead of just stdout/stderr text. Useful for setting the result of +the \fBmodule.run\fP state. +.UNINDENT .sp CLI Example: .INDENT 7.0 @@ -173792,6 +165418,12 @@ option twice (it is already set once); this is truly dangerous \fBusage_type\fP: how the filesystem is going to be used .IP \(bu 2 \fBuuid\fP: set the UUID for the file system +.IP \(bu 2 +\fBcluster_size\fP: specify the size of cluster in bytes for file systems using the bigalloc feature +.IP \(bu 2 +\fBroot_directory\fP: copy the contents of the given directory into the root directory of the file system +.IP \(bu 2 +\fBerrors_behavior\fP: change the behavior of the kernel code when errors are detected .UNINDENT .sp See the \fBmke2fs(8)\fP manpage for a more complete description of these @@ -173799,8 +165431,16 @@ options. .UNINDENT .INDENT 0.0 .TP -.B salt.modules.extfs.tune(device, **kwargs) +.B salt.modules.extfs.tune(device, full_return=False, **kwargs) Set attributes for the specified device (using tune2fs) +.INDENT 7.0 +.TP +.B full_return +False +If \fBTrue\fP, the full \fBcmd.run_all\fP dictionary will be returned +instead of just stdout/stderr text. Useful for setting the result of +the \fBmodule.run\fP state. +.UNINDENT .sp CLI Example: .INDENT 7.0 @@ -173837,7 +165477,7 @@ Valid options are: .IP \(bu 2 \fBlabel\fP: label to apply to the file system .IP \(bu 2 -\fBreserved\fP: percentage of blocks reserved for super\-user +\fBreserved_percentage\fP: percentage of blocks reserved for super\-user .IP \(bu 2 \fBlast_dir\fP: last mounted directory .IP \(bu 2 @@ -175204,7 +166844,7 @@ salt \(aq*\(aq file.get_hash /etc/shadow .UNINDENT .INDENT 0.0 .TP -.B salt.modules.file.get_managed(name, template, source, source_hash, source_hash_name, user, group, mode, attrs, saltenv, context, defaults, skip_verify=False, verify_ssl=True, use_etag=False, **kwargs) +.B salt.modules.file.get_managed(name, template, source, source_hash, source_hash_name, user, group, mode, attrs, saltenv, context, defaults, skip_verify=False, verify_ssl=True, use_etag=False, source_hash_sig=None, signed_by_any=None, signed_by_all=None, keyring=None, gnupghome=None, **kwargs) Return the managed file data for file.managed .INDENT 7.0 .TP @@ -175272,6 +166912,43 @@ the \fBsource_hash\fP parameter. .sp New in version 3005. +.TP +.B source_hash_sig +When \fBsource\fP is a remote file source, \fBsource_hash\fP is a file, +\fBskip_verify\fP is not true and \fBuse_etag\fP is not true, ensure a +valid GPG signature exists on the source hash file. +Set this to \fBtrue\fP for an inline (clearsigned) signature, or to a +file URI retrievable by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +New in version 3007.0. + +.TP +.B signed_by_any +When verifying \fBsource_hash_sig\fP, require at least one valid signature +from one of a list of key fingerprints. This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +When verifying \fBsource_hash_sig\fP, require a valid signature from each +of the key fingerprints in this list. This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B keyring +When verifying \fBsource_hash_sig\fP, use this keyring. +.sp +New in version 3007.0. + +.TP +.B gnupghome +When verifying \fBsource_hash_sig\fP, use this GnuPG home. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -175333,7 +167010,7 @@ salt \(aq*\(aq file.get_selinux_context /etc/hosts .UNINDENT .INDENT 0.0 .TP -.B salt.modules.file.get_source_sum(file_name=\(aq\(aq, source=\(aq\(aq, source_hash=None, source_hash_name=None, saltenv=\(aqbase\(aq, verify_ssl=True) +.B salt.modules.file.get_source_sum(file_name=\(aq\(aq, source=\(aq\(aq, source_hash=None, source_hash_name=None, saltenv=\(aqbase\(aq, verify_ssl=True, source_hash_sig=None, signed_by_any=None, signed_by_all=None, keyring=None, gnupghome=None) New in version 2016.11.0. .sp @@ -175373,6 +167050,42 @@ will not attempt to validate the servers certificate. Default is True. .sp New in version 3002. +.TP +.B source_hash_sig +When \fBsource\fP is a remote file source and \fBsource_hash\fP is a file, +ensure a valid GPG signature exists on the source hash file. +Set this to \fBtrue\fP for an inline (clearsigned) signature, or to a +file URI retrievable by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +New in version 3007.0. + +.TP +.B signed_by_any +When verifying \fBsource_hash_sig\fP, require at least one valid signature +from one of a list of key fingerprints. This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +When verifying \fBsource_hash_sig\fP, require a valid signature from each +of the key fingerprints in this list. This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B keyring +When verifying \fBsource_hash_sig\fP, use this keyring. +.sp +New in version 3007.0. + +.TP +.B gnupghome +When verifying \fBsource_hash_sig\fP, use this GnuPG home. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -176321,7 +168034,7 @@ salt \(aq*\(aq file.makedirs_perms /opt/code .UNINDENT .INDENT 0.0 .TP -.B salt.modules.file.manage_file(name, sfn, ret, source, source_sum, user, group, mode, attrs, saltenv, backup, makedirs=False, template=None, show_changes=True, contents=None, dir_mode=None, follow_symlinks=True, skip_verify=False, keep_mode=False, encoding=None, encoding_errors=\(aqstrict\(aq, seuser=None, serole=None, setype=None, serange=None, verify_ssl=True, use_etag=False, **kwargs) +.B salt.modules.file.manage_file(name, sfn, ret, source, source_sum, user, group, mode, attrs, saltenv, backup, makedirs=False, template=None, show_changes=True, contents=None, dir_mode=None, follow_symlinks=True, skip_verify=False, keep_mode=False, encoding=None, encoding_errors=\(aqstrict\(aq, seuser=None, serole=None, setype=None, serange=None, verify_ssl=True, use_etag=False, signature=None, source_hash_sig=None, signed_by_any=None, signed_by_all=None, keyring=None, gnupghome=None, **kwargs) Checks the destination against what was retrieved with get_managed and makes the appropriate modifications (if necessary). .INDENT 7.0 @@ -176463,6 +168176,80 @@ the \fBsource_hash\fP parameter. .sp New in version 3005. +.TP +.B signature +Ensure a valid GPG signature exists on the selected \fBsource\fP file. +Set this to true for inline signatures, or to a file URI retrievable +by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature is only enforced directly after caching the file, +before it is moved to its final destination. Existing target files +(with the correct checksum) will neither be checked nor deleted. +.sp +It will be enforced regardless of source type and will be +required on the final output, therefore this does not lend itself +well when templates are rendered. +The file will not be modified, meaning inline signatures are not +removed. +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B source_hash_sig +When \fBsource\fP is a remote file source, \fBsource_hash\fP is a file, +\fBskip_verify\fP is not true and \fBuse_etag\fP is not true, ensure a +valid GPG signature exists on the source hash file. +Set this to \fBtrue\fP for an inline (clearsigned) signature, or to a +file URI retrievable by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature on the \fBsource_hash\fP file is enforced regardless of +changes since its contents are used to check if an existing file +is in the correct state \- but only for remote sources! +As for \fBsignature\fP, existing target files will not be modified, +only the cached source_hash and source_hash_sig files will be removed. +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B signed_by_any +When verifying signatures either on the managed file or its source hash file, +require at least one valid signature from one of a list of key fingerprints. +This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +When verifying signatures either on the managed file or its source hash file, +require a valid signature from each of the key fingerprints in this list. +This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B keyring +When verifying signatures, use this keyring. +.sp +New in version 3007.0. + +.TP +.B gnupghome +When verifying signatures, use this GnuPG home. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -177615,7 +169402,7 @@ salt \(aq*\(aq file.statvfs /path/to/file .UNINDENT .INDENT 0.0 .TP -.B salt.modules.file.symlink(src, path, force=False, atomic=False) +.B salt.modules.file.symlink(src, path, force=False, atomic=False, follow_symlinks=True) Create a symbolic link (symlink, soft link) to a file .INDENT 7.0 .TP @@ -177631,6 +169418,10 @@ Create a symbolic link (symlink, soft link) to a file .IP \(bu 2 \fBatomic\fP (\fI\%bool\fP) \-\- Use atomic file operations to create the symlink \&.. versionadded:: 3006.0 +.IP \(bu 2 +\fBfollow_symlinks\fP (\fI\%bool\fP) \-\- If set to \fBFalse\fP, use \fBos.path.lexists()\fP for existence checks +instead of \fBos.path.exists()\fP\&. +\&.. versionadded:: 3007.0 .UNINDENT .TP .B Returns @@ -188418,8 +180209,8 @@ salt \(aq*\(aq google_chat.send_message \(dqhttps://chat.googleapis.com/v1/space .UNINDENT .SS salt.modules.gpg .sp -Manage a GPG keychains, add keys, create keys, retrieve keys from keyservers. -Sign, encrypt and sign plus encrypt text and files. +Manage GPG keychains, add keys, create keys, retrieve keys from keyservers. +Sign, encrypt, sign plus encrypt and verify text and files. .sp New in version 2015.5.0. @@ -188435,7 +180226,36 @@ libraries are not supported. .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.create_key(key_type=\(aqRSA\(aq, key_length=1024, name_real=\(aqAutogenerated Key\(aq, name_comment=\(aqGenerated by SaltStack\(aq, name_email=None, subkey_type=None, subkey_length=None, expire_date=None, use_passphrase=False, user=None, gnupghome=None) +.B class salt.modules.gpg.FixedVerify(gpg) +This is a workaround for \fI\%https://github.com/vsajip/python\-gnupg/issues/214\fP\&. +It ensures invalid or otherwise unverified signatures are not +merged into sig_info in any way. +.sp +\fI\%https://github.com/vsajip/python\-gnupg/commit/ee94a7ecc1a86484c9f02337e2bbdd05fd32b383\fP +.INDENT 7.0 +.TP +.B handle_status(key, value) +Handle status messages from the \fIgpg\fP child process. These are lines of the format +.INDENT 7.0 +.INDENT 3.5 +[GNUPG:] +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBkey\fP (\fI\%str\fP) \-\- Identifies what the status message is. +.IP \(bu 2 +\fBvalue\fP (\fI\%str\fP) \-\- Identifies additional data, which differs depending on the key. +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.gpg.create_key(key_type=\(aqRSA\(aq, key_length=1024, name_real=\(aqAutogenerated Key\(aq, name_comment=\(aqGenerated by SaltStack\(aq, name_email=None, subkey_type=None, subkey_length=None, expire_date=None, use_passphrase=False, user=None, gnupghome=None, keyring=None) Create a key in the GPG keychain .sp \fBNOTE:\fP @@ -188444,7 +180264,7 @@ Create a key in the GPG keychain GPG key generation requires \fIa lot\fP of entropy and randomness. Difficult to do over a remote connection, consider having another process available which is generating randomness for -the machine. Also especially difficult on virtual machines, +the machine. Also especially difficult on virtual machines, consider the \fI\%rng\-tools\fP package. .sp @@ -188482,16 +180302,23 @@ You can specify an ISO date, A number of days/weeks/months/years, an epoch value, or 0 for a non\-expiring key. .TP .B use_passphrase -Whether to use a passphrase with the signing key. Passphrase is received -from Pillar. +Whether to use a passphrase with the signing key. The passphrase is +retrieved from the Pillar key \fBgpg_passphrase\fP\&. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188508,34 +180335,41 @@ salt \-t 15 \(aq*\(aq gpg.create_key .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.decrypt(user=None, text=None, filename=None, output=None, use_passphrase=False, gnupghome=None, bare=False) -Decrypt a message or file +.B salt.modules.gpg.decrypt(user=None, text=None, filename=None, output=None, use_passphrase=False, gnupghome=None, bare=False, keyring=None) +Decrypt a message or a file .INDENT 7.0 .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B text The encrypted text to decrypt. .TP .B filename -The encrypted filename to decrypt. +The path of the encrypted file to decrypt. .TP .B output -The filename where the decrypted data will be written, default is standard out. +Instead of printing to standard out, write the output to this path. .TP .B use_passphrase -Whether to use a passphrase with the signing key. Passphrase is received -from Pillar. +Whether to use a passphrase with the signing key. The passphrase is retrieved +from Pillar value \fBgpg_passphrase\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. .TP .B bare If \fBTrue\fP, return the (armored) decrypted block as a string without the standard comment/res dict. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188554,8 +180388,8 @@ salt \(aq*\(aq gpg.decrypt filename=\(aq/path/to/important.file.gpg\(aq use_pass .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.delete_key(keyid=None, fingerprint=None, delete_secret=False, user=None, gnupghome=None, use_passphrase=True) -Get a key from the GPG keychain +.B salt.modules.gpg.delete_key(keyid=None, fingerprint=None, delete_secret=False, user=None, gnupghome=None, use_passphrase=True, keyring=None) +Delete a key from the GPG keychain. .INDENT 7.0 .TP .B keyid @@ -188570,18 +180404,26 @@ Secret keys must be deleted before deleting any corresponding public keys. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. .TP .B use_passphrase -Whether to use a passphrase with the signing key. Passphrase is received -from Pillar. +Whether to use a passphrase with the signing key. The passphrase is retrieved +from the Pillar key \fBgpg_passphrase\fP\&. Note that this defaults to True here, +contrary to the rest of the module functions that provide this parameter. .sp New in version 3003. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188604,13 +180446,13 @@ salt \(aq*\(aq gpg.delete_key keyid=3FAD9F1E user=username delete_secret=True .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.encrypt(user=None, recipients=None, text=None, filename=None, output=None, sign=None, use_passphrase=False, always_trust=False, gnupghome=None, bare=False) -Encrypt a message or file +.B salt.modules.gpg.encrypt(user=None, recipients=None, text=None, filename=None, output=None, sign=None, use_passphrase=False, always_trust=False, gnupghome=None, bare=False, keyring=None) +Encrypt a message or a file .INDENT 7.0 .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B recipients @@ -188621,10 +180463,10 @@ key can be used. The text to encrypt. .TP .B filename -The filename to encrypt. +The path of the file to encrypt. .TP .B output -The filename where the signed file will be written, default is standard out. +Instead of printing to standard out, write the output to this path. .TP .B sign Whether to sign, in addition to encrypt, the data. \fBTrue\fP to use @@ -188632,7 +180474,7 @@ default key or fingerprint to specify a different key to sign with. .TP .B use_passphrase Whether to use a passphrase with the signing key. -Passphrase is received from Pillar. +The passphrase is retrieved from the Pillar key \fBgpg_passphrase\fP\&. .TP .B always_trust Skip key validation and assume that used keys are fully trusted. @@ -188641,11 +180483,18 @@ New in version 3006.0. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. .TP .B bare If \fBTrue\fP, return the (armored) encrypted block as a string without the standard comment/res dict. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188667,7 +180516,7 @@ salt \(aq*\(aq gpg.encrypt filename=\(aq/path/to/important.file\(aq sign=True us .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.export_key(keyids=None, secret=False, user=None, gnupghome=None, use_passphrase=False, output=None, bare=False) +.B salt.modules.gpg.export_key(keyids=None, secret=False, user=None, gnupghome=None, use_passphrase=False, output=None, bare=False, keyring=None) Export a key from the GPG keychain .INDENT 7.0 .TP @@ -188681,21 +180530,21 @@ Export the secret key identified by the \fBkeyids\fP information passed. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. .TP .B use_passphrase Whether to use a passphrase to export the secret key. -Passphrase is received from Pillar. +The passphrase is retrieved from the Pillar key \fBgpg_passphrase\fP\&. .sp New in version 3003. .TP .B output -The filename where the exported key data will be written to, default is standard out. +Instead of printing to standard out, write the output to this path. .sp New in version 3006.0. @@ -188706,6 +180555,13 @@ standard comment/res dict. .sp New in version 3006.0. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188726,7 +180582,7 @@ salt \(aq*\(aq gpg.export_key keyids=\(dq[\(aq3FAD9F1E\(aq,\(aq3FBD8F1E\(aq]\(dq .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.get_key(keyid=None, fingerprint=None, user=None, gnupghome=None) +.B salt.modules.gpg.get_key(keyid=None, fingerprint=None, user=None, gnupghome=None, keyring=None) Get a key from the GPG keychain .INDENT 7.0 .TP @@ -188738,11 +180594,18 @@ The fingerprint of the key to be retrieved. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188763,8 +180626,8 @@ salt \(aq*\(aq gpg.get_key keyid=3FAD9F1E user=username .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.get_secret_key(keyid=None, fingerprint=None, user=None, gnupghome=None) -Get a key from the GPG keychain +.B salt.modules.gpg.get_secret_key(keyid=None, fingerprint=None, user=None, gnupghome=None, keyring=None) +Get a secret key from the GPG keychain .INDENT 7.0 .TP .B keyid @@ -188775,11 +180638,18 @@ The fingerprint of the key to be retrieved. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188800,23 +180670,30 @@ salt \(aq*\(aq gpg.get_secret_key keyid=3FAD9F1E user=username .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.import_key(text=None, filename=None, user=None, gnupghome=None) -Import a key from text or file +.B salt.modules.gpg.import_key(text=None, filename=None, user=None, gnupghome=None, keyring=None) +Import a key from text or a file .INDENT 7.0 .TP .B text -The text containing to import. +The text containing the key to import. .TP .B filename -The filename containing the key to import. +The path of the file containing the key to import. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188834,17 +180711,24 @@ salt \(aq*\(aq gpg.import_key filename=\(aq/path/to/public\-key\-file\(aq .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.list_keys(user=None, gnupghome=None) +.B salt.modules.gpg.list_keys(user=None, gnupghome=None, keyring=None) List keys in GPG keychain .INDENT 7.0 .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188861,17 +180745,24 @@ salt \(aq*\(aq gpg.list_keys .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.list_secret_keys(user=None, gnupghome=None) +.B salt.modules.gpg.list_secret_keys(user=None, gnupghome=None, keyring=None) List secret keys in GPG keychain .INDENT 7.0 .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188888,24 +180779,31 @@ salt \(aq*\(aq gpg.list_secret_keys .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.receive_keys(keyserver=None, keys=None, user=None, gnupghome=None) -Receive key(s) from keyserver and add them to keychain +.B salt.modules.gpg.receive_keys(keyserver=None, keys=None, user=None, gnupghome=None, keyring=None) +Receive key(s) from keyserver and add them to the keychain .INDENT 7.0 .TP .B keyserver Keyserver to use for searching for GPG keys, defaults to keys.openpgp.org .TP .B keys -The keyID(s) to retrieve from the keyserver. Can be specified as a comma +The keyID(s) to retrieve from the keyserver. Can be specified as a comma separated string or a list. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188926,8 +180824,8 @@ salt \(aq*\(aq gpg.receive_keys keys=3FAD9F1E user=username .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.search_keys(text, keyserver=None, user=None) -Search keys from keyserver +.B salt.modules.gpg.search_keys(text, keyserver=None, user=None, gnupghome=None) +Search for keys on a keyserver .INDENT 7.0 .TP .B text @@ -188938,8 +180836,14 @@ Keyserver to use for searching for GPG keys, defaults to keys.openpgp.org. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. +.TP +.B gnupghome +Specify the location where the GPG keyring and related files are stored. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -188960,34 +180864,41 @@ salt \(aq*\(aq gpg.search_keys user@example.com keyserver=keyserver.ubuntu.com u .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.sign(user=None, keyid=None, text=None, filename=None, output=None, use_passphrase=False, gnupghome=None) -Sign message or file +.B salt.modules.gpg.sign(user=None, keyid=None, text=None, filename=None, output=None, use_passphrase=False, gnupghome=None, keyring=None) +Sign a message or a file .INDENT 7.0 .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B keyid -The keyid of the key to set the trust level for, defaults to +The keyid of the key to use for signing, defaults to the first key in the secret keyring. .TP .B text The text to sign. .TP .B filename -The filename to sign. +The path of the file to sign. .TP .B output -The filename where the signed file will be written, default is standard out. +Instead of printing to standard out, write the output to this path. .TP .B use_passphrase -Whether to use a passphrase with the signing key. Passphrase is received -from Pillar. +Whether to use a passphrase with the signing key. The passphrase is +retrieved from the Pillar key \fBgpg_passphrase\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -189008,8 +180919,8 @@ salt \(aq*\(aq gpg.sign filename=\(aq/path/to/important.file\(aq use_passphrase= .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.trust_key(keyid=None, fingerprint=None, trust_level=None, user=None) -Set the trust level for a key in GPG keychain +.B salt.modules.gpg.trust_key(keyid=None, fingerprint=None, trust_level=None, user=None, gnupghome=None, keyring=None) +Set the trust level for a key in the GPG keychain .INDENT 7.0 .TP .B keyid @@ -189025,8 +180936,21 @@ expired, unknown, not_trusted, marginally, fully, ultimately .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. +.TP +.B gnupghome +Specify the location where the GPG keyring and related files are stored. +.sp +New in version 3007.0. + +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -189045,26 +180969,26 @@ salt \(aq*\(aq gpg.trust_key keys=3FAD9F1E trust_level=\(aqultimately\(aq user=\ .UNINDENT .INDENT 0.0 .TP -.B salt.modules.gpg.verify(text=None, user=None, filename=None, gnupghome=None, signature=None, trustmodel=None) -Verify a message or file +.B salt.modules.gpg.verify(text=None, user=None, filename=None, gnupghome=None, signature=None, trustmodel=None, signed_by_any=None, signed_by_all=None, keyring=None) +Verify a message or a file .INDENT 7.0 .TP .B text The text to verify. .TP .B filename -The filename to verify. +The path of the file to verify. .TP .B user Which user\(aqs keychain to access, defaults to user Salt is running as. -Passing the user as \fBsalt\fP will set the GnuPG home directory to the +Passing the user as \fBsalt\fP will set the GnuPG home directory to \fB/etc/salt/gpgkeys\fP\&. .TP .B gnupghome -Specify the location where GPG keyring and related files are stored. +Specify the location where the GPG keyring and related files are stored. .TP .B signature -Specify the filename of a detached signature. +Specify the path of a detached signature. .sp New in version 2018.3.0. @@ -189093,6 +181017,31 @@ auto .sp New in version 2019.2.0. +.TP +.B signed_by_any +A list of key fingerprints from which any valid signature +will mark verification as passed. If none of the provided +keys signed the data, verification will fail. Optional. +Note that this does not take into account trust. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +A list of key fingerprints whose signatures are required +for verification to pass. If a single provided key did +not sign the data, verification will fail. Optional. +Note that this does not take into account trust. +.sp +New in version 3007.0. + +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -189103,7 +181052,6 @@ CLI Example: .ft C salt \(aq*\(aq gpg.verify text=\(aqHello there. How are you?\(aq salt \(aq*\(aq gpg.verify filename=\(aq/path/to/important.file\(aq -salt \(aq*\(aq gpg.verify filename=\(aq/path/to/important.file\(aq use_passphrase=True salt \(aq*\(aq gpg.verify filename=\(aq/path/to/important.file\(aq trustmodel=direct .ft P .fi @@ -190876,7 +182824,7 @@ minion, and it is using a different module (or gives an error similar to .UNINDENT .INDENT 0.0 .TP -.B salt.modules.groupadd.add(name, gid=None, system=False, root=None, non_unique=False) +.B salt.modules.groupadd.add(name, gid=None, system=False, root=None, non_unique=False, local=False) Changed in version 3006.0. .sp @@ -190900,6 +182848,12 @@ Allow creating groups with duplicate (non\-unique) GIDs .sp New in version 3006.0. +.TP +.B local +Specifically add the group locally rather than through remote providers (e.g. LDAP) +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -190984,7 +182938,7 @@ salt \(aq*\(aq group.chgid foo 4376 .UNINDENT .INDENT 0.0 .TP -.B salt.modules.groupadd.delete(name, root=None) +.B salt.modules.groupadd.delete(name, root=None, local=False) Remove the named group .INDENT 7.0 .TP @@ -190993,6 +182947,13 @@ Name group to delete .TP .B root Directory to chroot into +.TP +.B local (Only on systems with lgroupdel available): +Ensure the group account is removed locally ignoring global +account management (default is False). +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -194495,7 +186456,7 @@ Passes through all the parameters described in the \fI\%utils.http.query function\fP: .INDENT 7.0 .TP -.B salt.utils.http.query(url, method=\(aqGET\(aq, params=None, data=None, data_file=None, header_dict=None, header_list=None, header_file=None, username=None, password=None, auth=None, decode=False, decode_type=\(aqauto\(aq, status=False, headers=False, text=False, cookies=None, cookie_jar=None, cookie_format=\(aqlwp\(aq, persist_session=False, session_cookie_jar=None, data_render=False, data_renderer=None, header_render=False, header_renderer=None, template_dict=None, test=False, test_url=None, node=\(aqminion\(aq, port=80, opts=None, backend=None, ca_bundle=None, verify_ssl=None, cert=None, text_out=None, headers_out=None, decode_out=None, stream=False, streaming_callback=None, header_callback=None, handle=False, agent=\(aqSalt/3006.7\(aq, hide_fields=None, raise_error=True, formdata=False, formdata_fieldname=None, formdata_filename=None, decode_body=True, **kwargs) +.B salt.utils.http.query(url, method=\(aqGET\(aq, params=None, data=None, data_file=None, header_dict=None, header_list=None, header_file=None, username=None, password=None, auth=None, decode=False, decode_type=\(aqauto\(aq, status=False, headers=False, text=False, cookies=None, cookie_jar=None, cookie_format=\(aqlwp\(aq, persist_session=False, session_cookie_jar=None, data_render=False, data_renderer=None, header_render=False, header_renderer=None, template_dict=None, test=False, test_url=None, node=\(aqminion\(aq, port=80, opts=None, backend=None, ca_bundle=None, verify_ssl=None, cert=None, text_out=None, headers_out=None, decode_out=None, stream=False, streaming_callback=None, header_callback=None, handle=False, agent=\(aqSalt/3007.0\(aq, hide_fields=None, raise_error=True, formdata=False, formdata_fieldname=None, formdata_filename=None, decode_body=True, **kwargs) Query a resource, and decode the return data .UNINDENT .INDENT 7.0 @@ -203061,6 +195022,14 @@ salt \(aqdevice_name\(aq junos.zeroize .UNINDENT .SS salt.modules.k8s .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%kubernetes Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Salt module to manage Kubernetes cluster .sp New in version 2016.3.0. @@ -206332,6 +198301,14 @@ salt \(aq*\(aq kmod.remove kvm .UNINDENT .SS salt.modules.kubeadm .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%kubernetes Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Module for kubeadm :maintainer: Alberto Planas <\fI\%aplanas@suse.com\fP> :maturity: new @@ -207277,6 +199254,14 @@ salt \(aq*\(aq kubeadm.version .UNINDENT .SS salt.modules.kubernetesmod .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%kubernetes Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Module for handling kubernetes calls. .INDENT 0.0 .TP @@ -214635,7 +206620,7 @@ CLI Example: .sp .nf .ft C -salt myminion lxc.run mycontainer \(aqifconfig \-a\(aq +salt myminion lxc.run mycontainer \(aqip addr show\(aq .ft P .fi .UNINDENT @@ -214904,7 +206889,7 @@ CLI Example: .sp .nf .ft C -salt myminion lxc.run_stdout mycontainer \(aqifconfig \-a\(aq +salt myminion lxc.run_stdout mycontainer \(aqip addr show\(aq .ft P .fi .UNINDENT @@ -218622,6 +210607,14 @@ salt \(aq*\(aq assistive.remove com.smileonmymac.textexpander .sp Homebrew for macOS .sp +It is recommended for the \fBsalt\-minion\fP to have the \fBHOMEBREW_PREFIX\fP +environment variable set. +.sp +This will ensure that Salt uses the correct path for the \fBbrew\fP binary. +.sp +Typically, this is set to \fB/usr/local\fP for Intel Macs and \fB/opt/homebrew\fP +for Apple Silicon Macs. +.sp \fBIMPORTANT:\fP .INDENT 0.0 .INDENT 3.5 @@ -218705,6 +210698,23 @@ salt \(aq*\(aq pkg.hold pkgs=\(aq[\(dqfoo\(dq, \(dqbar\(dq]\(aq .UNINDENT .INDENT 0.0 .TP +.B salt.modules.mac_brew_pkg.homebrew_prefix() +Returns the full path to the homebrew prefix. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq pkg.homebrew_prefix +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.mac_brew_pkg.info_installed(*names, **kwargs) Return the information of the named package(s) installed on the system. .sp @@ -229636,7 +221646,7 @@ salt \(aq*\(aq mount.swaps .UNINDENT .INDENT 0.0 .TP -.B salt.modules.mount.umount(name, device=None, user=None, util=\(aqmount\(aq) +.B salt.modules.mount.umount(name, device=None, user=None, util=\(aqmount\(aq, lazy=False) Attempt to unmount a device by specifying the directory it is mounted on .sp CLI Example: @@ -235309,37 +227319,6 @@ salt \(aq*\(aq napalm.netmiko_config https://bit.ly/2sgljCB .UNINDENT .INDENT 0.0 .TP -.B salt.modules.napalm_mod.netmiko_conn(**kwargs) -New in version 2019.2.0. - -.sp -Return the connection object with the network device, over Netmiko, passing -the authentication details from the existing NAPALM connection. -.sp -\fBWARNING:\fP -.INDENT 7.0 -.INDENT 3.5 -This function is not suitable for CLI usage, more rather to be used -in various Salt modules. -.UNINDENT -.UNINDENT -.sp -USAGE Example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -conn = __salt__[\(aqnapalm.netmiko_conn\(aq]() -res = conn.send_command(\(aqshow interfaces\(aq) -conn.disconnect() -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP .B salt.modules.napalm_mod.netmiko_fun(fun, *args, **kwargs) New in version 2019.2.0. @@ -235640,38 +227619,6 @@ salt \(aq*\(aq napalm.pyeapi_config \(aqntp server 1.2.3.4\(aq .UNINDENT .INDENT 0.0 .TP -.B salt.modules.napalm_mod.pyeapi_conn(**kwargs) -New in version 2019.2.0. - -.sp -Return the connection object with the Arista switch, over \fBpyeapi\fP, -passing the authentication details from the existing NAPALM connection. -.sp -\fBWARNING:\fP -.INDENT 7.0 -.INDENT 3.5 -This function is not suitable for CLI usage, more rather to be used in -various Salt modules, to reusing the established connection, as in -opposite to opening a new connection for each task. -.UNINDENT -.UNINDENT -.sp -Usage example: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -conn = __salt__[\(aqnapalm.pyeapi_conn\(aq]() -res1 = conn.run_commands(\(aqshow version\(aq) -res2 = conn.get_config(as_string=True) -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP .B salt.modules.napalm_mod.pyeapi_nxos_api_args(**prev_kwargs) New in version 2019.2.0. @@ -243866,6 +235813,46 @@ salt \(aq*\(aq network.ip_in_subnet 172.17.0.4 172.16.0.0/12 .UNINDENT .INDENT 0.0 .TP +.B salt.modules.network.ip_neighs() +Return the ip neighbour (arp) table from the minion for IPv4 addresses +.sp +New in version 3007.0. + +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq network.ip_neighs +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.network.ip_neighs6() +Return the ip neighbour (arp) table from the minion for IPv6 addresses +.sp +New in version 3007.0. + +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq network.ip_neighs6 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.network.ip_networks(interface=None, include_loopback=False, verbose=False) New in version 3001. @@ -244007,6 +235994,56 @@ salt \(aq*\(aq network.iphexval 10.0.0.1 .UNINDENT .INDENT 0.0 .TP +.B salt.modules.network.ipneighs() +This function is an alias of \fBip_neighs\fP\&. +.INDENT 7.0 +.INDENT 3.5 +Return the ip neighbour (arp) table from the minion for IPv4 addresses +.sp +New in version 3007.0. + +.sp +CLI Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq network.ip_neighs +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.network.ipneighs6() +This function is an alias of \fBip_neighs6\fP\&. +.INDENT 7.0 +.INDENT 3.5 +Return the ip neighbour (arp) table from the minion for IPv6 addresses +.sp +New in version 3007.0. + +.sp +CLI Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq network.ip_neighs6 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.network.is_loopback(ip_addr) Check if the given IP address is a loopback address .sp @@ -250456,7 +242493,7 @@ CLI Example: .sp .nf .ft C -salt myminion nspawn.run mycontainer \(aqifconfig \-a\(aq +salt myminion nspawn.run mycontainer \(aqip addr show\(aq .ft P .fi .UNINDENT @@ -250630,7 +242667,7 @@ CLI Example: .sp .nf .ft C -salt myminion nspawn.run_stdout mycontainer \(aqifconfig \-a\(aq +salt myminion nspawn.run_stdout mycontainer \(aqip addr show\(aq .ft P .fi .UNINDENT @@ -252853,6 +244890,68 @@ salt \(aq*\(aq openscap.xccdf \(dqeval \-\-profile Default /usr/share/openscap/ .UNINDENT .UNINDENT .UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.openscap.xccdf_eval(xccdffile, ovalfiles=None, profile=None, rule=None, oval_results=None, results=None, report=None, fetch_remote_resources=None, tailoring_file=None, tailoring_id=None, remediate=None) +Run \fBoscap xccdf eval\fP commands on minions. +.sp +New in version 3007.0. + +.sp +It uses cp.push_dir to upload the generated files to the salt master +in the master\(aqs minion files cachedir +(defaults to \fB/var/cache/salt/master/minions/minion\-id/files\fP) +.sp +It needs \fBfile_recv\fP set to \fBTrue\fP in the master configuration file. +.INDENT 7.0 +.TP +.B xccdffile +the path to the xccdf file to evaluate +.TP +.B ovalfiles +additional oval definition files +.TP +.B profile +the name of Profile to be evaluated +.TP +.B rule +the name of a single rule to be evaluated +.TP +.B oval_results +save OVAL results as well (True or False) +.TP +.B results +write XCCDF Results into given file +.TP +.B report +write HTML report into given file +.TP +.B fetch_remote_resources +download remote content referenced by XCCDF (True or False) +.TP +.B tailoring_file +use given XCCDF Tailoring file +.TP +.B tailoring_id +use given DS component as XCCDF Tailoring file +.TP +.B remediate +automatically execute XCCDF fix elements for failed rules. +Use of this option is always at your own risk. (True or False) +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq openscap.xccdf_eval /usr/share/openscap/scap\-yast2sec\-xccdf.xml profile=Default +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.modules.openstack_config .sp Modify, retrieve, or delete values from OpenStack configuration files. @@ -271426,6 +263525,14 @@ salt \(dq*\(dq pushbullet.push_note device=\(dqChrome\(dq title=\(dqExample titl .UNINDENT .SS salt.modules.pushover_notify .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%pushover Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Module for sending messages to Pushover (\fI\%https://www.pushover.net\fP) .sp New in version 2016.3.0. @@ -280345,7 +272452,7 @@ New in version 3000. .UNINDENT .INDENT 0.0 .TP -.B salt.modules.saltcheck.run_highstate_tests(saltenv=None, only_fails=False) +.B salt.modules.saltcheck.run_highstate_tests(saltenv=None, only_fails=False, junit=False) Execute all tests for states assigned to the minion through highstate and return results .INDENT 7.0 .TP @@ -280355,6 +272462,9 @@ Execute all tests for states assigned to the minion through highstate and return \fBsaltenv\fP (\fI\%str\fP) \-\- optional saltenv. Defaults to base .IP \(bu 2 \fBonly_fails\fP (\fI\%bool\fP) \-\- boolean to only print failure results +.IP \(bu 2 +\fBjunit\fP (\fI\%bool\fP) \-\- boolean to print results in junit format +\&.. versionadded:: 3007.0 .UNINDENT .UNINDENT .sp @@ -280372,7 +272482,7 @@ salt \(aq*\(aq saltcheck.run_highstate_tests .UNINDENT .INDENT 0.0 .TP -.B salt.modules.saltcheck.run_state_tests(state, saltenv=None, check_all=False, only_fails=False) +.B salt.modules.saltcheck.run_state_tests(state, saltenv=None, check_all=False, only_fails=False, junit=False) Execute tests for a salt state and return results Nested states will also be tested .INDENT 7.0 @@ -280387,6 +272497,9 @@ Nested states will also be tested \fBcheck_all\fP (\fI\%bool\fP) \-\- boolean to run all tests in state/saltcheck\-tests directory .IP \(bu 2 \fBonly_fails\fP (\fI\%bool\fP) \-\- boolean to only print failure results +.IP \(bu 2 +\fBjunit\fP (\fI\%bool\fP) \-\- boolean to print results in junit format +\&.. versionadded:: 3007.0 .UNINDENT .UNINDENT .sp @@ -280409,7 +272522,7 @@ of parallel processes. .UNINDENT .INDENT 0.0 .TP -.B salt.modules.saltcheck.run_state_tests_ssh(state, saltenv=None, check_all=False, only_fails=False) +.B salt.modules.saltcheck.run_state_tests_ssh(state, saltenv=None, check_all=False, only_fails=False, junit=False) This function is an alias of \fBrun_state_tests\fP\&. .INDENT 7.0 .INDENT 3.5 @@ -280428,6 +272541,10 @@ boolean to run all tests in state/saltcheck\-tests directory .TP .B param bool only_fails boolean to only print failure results +.TP +.B param bool junit +boolean to print results in junit format +\&.. versionadded:: 3007.0 .UNINDENT .sp CLI Example: @@ -281076,6 +273193,12 @@ salt \(aq*\(aq saltutil.signal_job 15 .INDENT 0.0 .TP .B salt.modules.saltutil.sync_all(saltenv=None, refresh=True, extmod_whitelist=None, extmod_blacklist=None, clean_pillar_cache=False) +Changed in version 3007.0: On masterless minions, master top modules are now synced as well. +When \fBrefresh\fP is set to \fBTrue\fP, this module\(aqs cache containing +the environments from which extension modules are synced when +\fBsaltenv\fP is not specified will be refreshed. + +.sp Changed in version 2015.8.11,2016.3.2: On masterless minions, pillar modules are now synced, and refreshed when \fBrefresh\fP is set to \fBTrue\fP\&. @@ -281088,7 +273211,9 @@ grains, returners, output modules, renderers, and utils. .B refresh True Also refresh the execution modules and recompile pillar data available -to the minion. This refresh will be performed even if no new dynamic +to the minion. If this is a masterless minion, also refresh the environments +from which extension modules are synced after syncing master tops. +This refresh will be performed even if no new dynamic modules are synced. Set to \fBFalse\fP to prevent this refresh. .UNINDENT .sp @@ -281739,8 +273864,7 @@ are found, then the \fBbase\fP environment will be synced. True If \fBTrue\fP, refresh the available execution modules on the minion. This refresh will be performed even if no new renderers are synced. -Set to \fBFalse\fP to prevent this refresh. Set to \fBFalse\fP to prevent -this refresh. +Set to \fBFalse\fP to prevent this refresh. .TP .B extmod_whitelist None @@ -281825,11 +273949,6 @@ one environment, pass a comma\-separated list. If not passed, then all environments configured in the \fI\%top files\fP will be checked for sdb modules to sync. If no top files are found, then the \fBbase\fP environment will be synced. .TP -.B refresh -False -This argument has no affect and is included for consistency with the -other sync functions. -.TP .B extmod_whitelist None comma\-separated list of modules to sync @@ -281986,6 +274105,59 @@ salt \(aq*\(aq saltutil.sync_thorium saltenv=base,dev .UNINDENT .INDENT 0.0 .TP +.B salt.modules.saltutil.sync_tops(saltenv=None, refresh=True, extmod_whitelist=None, extmod_blacklist=None) +New in version 3007.0. + +.sp +Sync master tops from \fBsalt://_tops\fP to the minion. +.INDENT 7.0 +.TP +.B saltenv +The fileserver environment from which to sync. To sync from more than +one environment, pass a comma\-separated list. +.sp +If not passed, then all environments configured in the \fI\%top files\fP will be checked for master tops to sync. If no top files +are found, then the \fBbase\fP environment will be synced. +.TP +.B refresh +True +Refresh this module\(aqs cache containing the environments from which +extension modules are synced when \fBsaltenv\fP is not specified. +This refresh will be performed even if no new master tops are synced. +Set to \fBFalse\fP to prevent this refresh. +.TP +.B extmod_whitelist +None +comma\-separated list of modules to sync +.TP +.B extmod_blacklist +None +comma\-separated list of modules to blacklist based on type +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This function will raise an error if executed on a traditional (i.e. +not masterless) minion +.UNINDENT +.UNINDENT +.sp +CLI Examples: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq saltutil.sync_tops +salt \(aq*\(aq saltutil.sync_tops saltenv=dev +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.saltutil.sync_utils(saltenv=None, refresh=True, extmod_whitelist=None, extmod_blacklist=None) New in version 2014.7.0. @@ -282031,6 +274203,59 @@ salt \(aq*\(aq saltutil.sync_utils saltenv=base,dev .UNINDENT .INDENT 0.0 .TP +.B salt.modules.saltutil.sync_wrapper(saltenv=None, refresh=True, extmod_whitelist=None, extmod_blacklist=None) +New in version 3007.0. + +.sp +Sync salt\-ssh wrapper modules from \fBsalt://_wrapper\fP to the minion. +.INDENT 7.0 +.TP +.B saltenv +The fileserver environment from which to sync. To sync from more than +one environment, pass a comma\-separated list. +.sp +If not passed, then all environments configured in the \fI\%top files\fP will be checked for wrappers to sync. If no top files +are found, then the \fBbase\fP environment will be synced. +.TP +.B refresh +True +If \fBTrue\fP, refresh the available wrapper modules on the minion. +This refresh will be performed even if no wrappers are synced. +Set to \fBFalse\fP to prevent this refresh. +.TP +.B extmod_whitelist +None +comma\-seperated list of modules to sync +.TP +.B extmod_blacklist +None +comma\-seperated list of modules to blacklist based on type +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This function will raise an error if executed on a traditional (i.e. +not masterless) minion. +.UNINDENT +.UNINDENT +.sp +CLI Examples: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq saltutil.sync_wrapper +salt \(aq*\(aq saltutil.sync_wrapper saltenv=dev +salt \(aq*\(aq saltutil.sync_wrapper saltenv=base,dev +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.saltutil.term_all_jobs() Sends a termination signal (SIGTERM 15) to all currently running jobs .sp @@ -283329,8 +275554,8 @@ CLI Example: .sp .nf .ft C -salt \(aq*\(aq selinux.port_add_policy add tcp/8080 http_port_t -salt \(aq*\(aq selinux.port_add_policy add foobar http_port_t protocol=tcp port=8091 +salt \(aq*\(aq selinux.port_add_policy tcp/8080 http_port_t +salt \(aq*\(aq selinux.port_add_policy foobar http_port_t protocol=tcp port=8091 .ft P .fi .UNINDENT @@ -283418,6 +275643,46 @@ salt \(aq*\(aq selinux.port_get_policy foobar protocol=tcp port=80 .UNINDENT .INDENT 0.0 .TP +.B salt.modules.selinux.port_modify_policy(name, sel_type=None, protocol=None, port=None, sel_range=None) +New in version 2019.2.0. + +.sp +Modifies the SELinux policy for a given protocol and port. +.sp +Returns the result of the call to semanage. +.INDENT 7.0 +.TP +.B name +The protocol and port spec. Can be formatted as \fB(tcp|udp)/(port|port\-range)\fP\&. +.TP +.B sel_type +The SELinux Type. Required. +.TP +.B protocol +The protocol for the port, \fBtcp\fP or \fBudp\fP\&. Required if name is not formatted. +.TP +.B port +The port or port range. Required if name is not formatted. +.TP +.B sel_range +The SELinux MLS/MCS Security Range. +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq selinux.port_modify_policy tcp/8080 http_port_t +salt \(aq*\(aq selinux.port_modify_policy foobar http_port_t protocol=tcp port=8091 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.selinux.remove_semod(module) Remove SELinux module .sp @@ -294626,6 +286891,14 @@ salt \(aq*\(aq supervisord.update .UNINDENT .SS salt.modules.suse_apache .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%apache Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Support for Apache .sp Please note: The functions in here are SUSE\-specific. Placing them in this @@ -297678,24 +289951,26 @@ Support for reboot, shutdown, etc on POSIX\-like systems. \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -If you have configured a wrapper such as \fBmolly\-guard\fP to -intercept \fIinteractive\fP shutdown commands, be aware that calling -\fBsystem.halt\fP, \fBsystem.poweroff\fP, \fBsystem.reboot\fP, and -\fBsystem.shutdown\fP with \fBsalt\-call\fP will hang indefinitely -while the wrapper script waits for user input. Calling them with -\fBsalt\fP will work as expected. +If a wrapper such as \fBmolly\-guard\fP to intercept \fIinteractive\fP shutdown +commands is configured, calling \fI\%system.halt\fP, +\fI\%system.poweroff\fP, +\fI\%system.reboot\fP, and +\fI\%system.shutdown\fP with \fBsalt\-call\fP will +hang indefinitely while the wrapper script waits for user input. Calling them +with \fBsalt\fP will work as expected. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B salt.modules.system.get_computer_desc() -Get PRETTY_HOSTNAME value stored in /etc/machine\-info +Get \fBPRETTY_HOSTNAME\fP value stored in \fB/etc/machine\-info\fP If this file doesn\(aqt exist or the variable doesn\(aqt exist -return False. +return \fBFalse\fP\&. .INDENT 7.0 .TP .B Returns -Value of PRETTY_HOSTNAME if this does not exist False. +Value of \fBPRETTY_HOSTNAME\fP in \fB/etc/machine\-info\fP\&. +If file/variable does not exist \fBFalse\fP\&. .TP .B Return type \fI\%str\fP @@ -297733,6 +290008,14 @@ salt \(aq*\(aq network.get_hostname .INDENT 0.0 .TP .B salt.modules.system.get_reboot_required_witnessed() +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This only applies to Minions running on NI Linux RT +.UNINDENT +.UNINDENT +.sp Determine if at any time during the current boot session the salt minion witnessed an event indicating that a reboot is required. .INDENT 7.0 @@ -297763,11 +290046,11 @@ Get the system date .INDENT 7.0 .TP .B Parameters -\fButc_offset\fP (\fI\%str\fP) \-\- The utc offset in 4 digit (+0600) format with an -optional sign (+/\-). Will default to None which will use the local -timezone. To set the time based off of UTC use \(dq\(aq+0000\(aq\(dq. Note: if +\fButc_offset\fP (\fI\%str\fP) \-\- The UTC offset in 4 digit (\fB+0600\fP) format with an +optional sign (\fB+\fP/\fB\-\fP). Will default to \fBNone\fP which will use the local +timezone. To set the time based off of UTC use \fB+0000\fP\&. Note: If being passed through the command line will need to be quoted twice to -allow negative offsets. +allow negative offsets (e.g. \fB\(dq\(aq+0000\(aq\(dq\fP). .TP .B Returns Returns the system date. @@ -297795,14 +290078,14 @@ Get the system date/time. .INDENT 7.0 .TP .B Parameters -\fButc_offset\fP (\fI\%str\fP) \-\- The utc offset in 4 digit (+0600) format with an -optional sign (+/\-). Will default to None which will use the local -timezone. To set the time based off of UTC use \(dq\(aq+0000\(aq\(dq. Note: if +\fButc_offset\fP (\fI\%str\fP) \-\- The UTC offset in 4 digit (\fB+0600\fP) format with an +optional sign (\fB+\fP/\fB\-\fP). Will default to \fBNone\fP which will use the local +timezone. To set the time based off of UTC use \fB+0000\fP\&. Note: If being passed through the command line will need to be quoted twice to -allow negative offsets. +allow negative offsets (e.g. \fB\(dq\(aq+0000\(aq\(dq\fP). .TP .B Returns -Returns the system time in YYYY\-MM\-DD hh:mm:ss format. +Returns the system time in \fBYYYY\-MM\-DD hh:mm:ss\fP format. .TP .B Return type \fI\%str\fP @@ -297827,14 +290110,14 @@ Get the system time. .INDENT 7.0 .TP .B Parameters -\fButc_offset\fP (\fI\%str\fP) \-\- The utc offset in 4 digit (+0600) format with an -optional sign (+/\-). Will default to None which will use the local -timezone. To set the time based off of UTC use \(dq\(aq+0000\(aq\(dq. Note: if +\fButc_offset\fP (\fI\%str\fP) \-\- The UTC offset in 4 digit (e.g. \fB+0600\fP) format with an +optional sign (\fB+\fP/\fB\-\fP). Will default to \fBNone\fP which will use the local +timezone. To set the time based off of UTC use \fB+0000\fP\&. Note: If being passed through the command line will need to be quoted twice to -allow negative offsets. +allow negative offsets (e.g. \fB\(dq\(aq+0000\(aq\(dq\fP). .TP .B Returns -Returns the system time in HH:MM:SS AM/PM format. +Returns the system time in \fBHH:MM:SS AM/PM\fP format. .TP .B Return type \fI\%str\fP @@ -297872,7 +290155,7 @@ salt \(aq*\(aq system.halt .INDENT 0.0 .TP .B salt.modules.system.has_settable_hwclock() -Returns True if the system has a hardware clock capable of being +Returns \fBTrue\fP if the system has a hardware clock capable of being set from software. .sp CLI Example: @@ -297946,16 +290229,16 @@ salt \(aq*\(aq system.reboot .INDENT 0.0 .TP .B salt.modules.system.set_computer_desc(desc) -Set PRETTY_HOSTNAME value stored in /etc/machine\-info +Set \fBPRETTY_HOSTNAME\fP value stored in \fB/etc/machine\-info\fP This will create the file if it does not exist. If -it is unable to create or modify this file returns False. +it is unable to create or modify this file, \fBFalse\fP is returned. .INDENT 7.0 .TP .B Parameters \fBdesc\fP (\fI\%str\fP) \-\- The computer description .TP .B Returns -False on failure. True if successful. +\fBFalse\fP on failure. \fBTrue\fP if successful. .UNINDENT .sp CLI Example: @@ -297990,6 +290273,14 @@ salt \(aq*\(aq system.set_computer_name master.saltstack.com .INDENT 0.0 .TP .B salt.modules.system.set_reboot_required_witnessed() +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This only applies to Minions running on NI Linux RT +.UNINDENT +.UNINDENT +.sp This function is used to remember that an event indicating that a reboot is required was witnessed. This function writes to a temporary filesystem so the event gets cleared upon reboot. @@ -298001,6 +290292,8 @@ the event gets cleared upon reboot. .B Return type \fI\%bool\fP .UNINDENT +.sp +CLI Example: .INDENT 7.0 .INDENT 3.5 .sp @@ -298015,7 +290308,7 @@ salt \(aq*\(aq system.set_reboot_required_witnessed .INDENT 0.0 .TP .B salt.modules.system.set_system_date(newdate, utc_offset=None) -Set the system date. Use format for the date. +Set the system date. Use \fB\fP format for the date. .INDENT 7.0 .TP .B Parameters @@ -298024,17 +290317,17 @@ Set the system date. Use format for the date. The date to set. Can be any of the following formats: .INDENT 7.0 .IP \(bu 2 -YYYY\-MM\-DD +\fBYYYY\-MM\-DD\fP .IP \(bu 2 -MM\-DD\-YYYY +\fBMM\-DD\-YYYY\fP .IP \(bu 2 -MM\-DD\-YY +\fBMM\-DD\-YY\fP .IP \(bu 2 -MM/DD/YYYY +\fBMM/DD/YYYY\fP .IP \(bu 2 -MM/DD/YY +\fBMM/DD/YY\fP .IP \(bu 2 -YYYY/MM/DD +\fBYYYY/MM/DD\fP .UNINDENT .UNINDENT @@ -298056,9 +290349,10 @@ salt \(aq*\(aq system.set_system_date \(aq03\-28\-13\(aq .B salt.modules.system.set_system_date_time(years=None, months=None, days=None, hours=None, minutes=None, seconds=None, utc_offset=None) Set the system date and time. Each argument is an element of the date, but not required. If an element is not passed, the current system value for -that element will be used. For example, if you don\(aqt pass the year, the -current system year will be used. (Used by set_system_date and -set_system_time) +that element will be used. For example, if the year is not passed, the +current system year will be used. (Used by +\fI\%system.set_system_date\fP and +\fI\%system.set_system_time\fP) .sp Updates hardware clock, if present, in addition to software (kernel) clock. @@ -298067,27 +290361,27 @@ Updates hardware clock, if present, in addition to software .B Parameters .INDENT 7.0 .IP \(bu 2 -\fByears\fP (\fI\%int\fP) \-\- Years digit, ie: 2015 +\fByears\fP (\fI\%int\fP) \-\- Years digit, e.g.: \fB2015\fP .IP \(bu 2 -\fBmonths\fP (\fI\%int\fP) \-\- Months digit: 1 \- 12 +\fBmonths\fP (\fI\%int\fP) \-\- Months digit: \fB1\fP\-\fB12\fP .IP \(bu 2 -\fBdays\fP (\fI\%int\fP) \-\- Days digit: 1 \- 31 +\fBdays\fP (\fI\%int\fP) \-\- Days digit: \fB1\fP\-\fB31\fP .IP \(bu 2 -\fBhours\fP (\fI\%int\fP) \-\- Hours digit: 0 \- 23 +\fBhours\fP (\fI\%int\fP) \-\- Hours digit: \fB0\fP\-\fB23\fP .IP \(bu 2 -\fBminutes\fP (\fI\%int\fP) \-\- Minutes digit: 0 \- 59 +\fBminutes\fP (\fI\%int\fP) \-\- Minutes digit: \fB0\fP\-\fB59\fP .IP \(bu 2 -\fBseconds\fP (\fI\%int\fP) \-\- Seconds digit: 0 \- 59 +\fBseconds\fP (\fI\%int\fP) \-\- Seconds digit: \fB0\fP\-\fB59\fP .IP \(bu 2 -\fButc_offset\fP (\fI\%str\fP) \-\- The utc offset in 4 digit (+0600) format with an -optional sign (+/\-). Will default to None which will use the local -timezone. To set the time based off of UTC use \(dq\(aq+0000\(aq\(dq. Note: if +\fButc_offset\fP (\fI\%str\fP) \-\- The UTC offset in 4 digit (\fB+0600\fP) format with an +optional sign (\fB+\fP/\fB\-\fP). Will default to \fBNone\fP which will use the local +timezone. To set the time based off of UTC use \fB+0000\fP\&. Note: If being passed through the command line will need to be quoted twice to -allow negative offsets. +allow negative offsets (e.g. \fB\(dq\(aq+0000\(aq\(dq\fP). .UNINDENT .TP .B Returns -True if successful. Otherwise False. +\fBTrue\fP if successful. Otherwise \fBFalse\fP\&. .TP .B Return type \fI\%bool\fP @@ -298117,26 +290411,32 @@ Set the system time. \fBnewtime\fP (\fI\%str\fP) \-\- .sp The time to set. Can be any of the following formats. -\- HH:MM:SS AM/PM -\- HH:MM AM/PM -\- HH:MM:SS (24 hour) -\- HH:MM (24 hour) +.INDENT 2.0 +.IP \(bu 2 +\fBHH:MM:SS AM/PM\fP +.IP \(bu 2 +\fBHH:MM AM/PM\fP +.IP \(bu 2 +\fBHH:MM:SS\fP (24 hour) +.IP \(bu 2 +\fBHH:MM\fP (24 hour) +.UNINDENT .sp -Note that the salt command line parser parses the date/time -before we obtain the argument (preventing us from doing utc) +Note that the Salt command line parser parses the date/time +before we obtain the argument (preventing us from doing UTC) Therefore the argument must be passed in as a string. -Meaning you may have to quote the text twice from the command line. +Meaning the text might have to be quoted twice on the command line. .IP \(bu 2 -\fButc_offset\fP (\fI\%str\fP) \-\- The utc offset in 4 digit (+0600) format with an -optional sign (+/\-). Will default to None which will use the local -timezone. To set the time based off of UTC use \(dq\(aq+0000\(aq\(dq. Note: if +\fButc_offset\fP (\fI\%str\fP) \-\- The UTC offset in 4 digit (\fB+0600\fP) format with an +optional sign (\fB+\fP/\fB\-\fP). Will default to \fBNone\fP which will use the local +timezone. To set the time based off of UTC use \fB+0000\fP\&. Note: If being passed through the command line will need to be quoted twice to -allow negative offsets. +allow negative offsets (e.g. \fB\(dq\(aq+0000\(aq\(dq\fP) .UNINDENT .TP .B Returns -Returns True if successful. Otherwise False. +Returns \fBTrue\fP if successful. Otherwise \fBFalse\fP\&. .TP .B Return type \fI\%bool\fP @@ -303831,7 +296131,7 @@ Linux .INDENT 0.0 .TP .B salt.modules.tuned.active() -Return current active profile +Return current active profile in stdout key if retcode is 0, otherwise raw result .sp CLI Example: .INDENT 7.0 @@ -304499,7 +296799,7 @@ minion, and it is using a different module (or gives an error similar to .UNINDENT .INDENT 0.0 .TP -.B salt.modules.useradd.add(name, uid=None, gid=None, groups=None, home=None, shell=None, unique=True, system=False, fullname=\(aq\(aq, roomnumber=\(aq\(aq, workphone=\(aq\(aq, homephone=\(aq\(aq, other=\(aq\(aq, createhome=True, loginclass=None, nologinit=False, root=None, usergroup=None) +.B salt.modules.useradd.add(name, uid=None, gid=None, groups=None, home=None, shell=None, unique=True, system=False, fullname=\(aq\(aq, roomnumber=\(aq\(aq, workphone=\(aq\(aq, homephone=\(aq\(aq, other=\(aq\(aq, createhome=True, loginclass=None, nologinit=False, root=None, usergroup=None, local=False) Add a user to the minion .INDENT 7.0 .TP @@ -304556,6 +296856,12 @@ Directory to chroot into .TP .B usergroup Create and add the user to a new primary group of the same name +.TP +.B local (Only on systems with luseradd available) +Specifically add the user locally rather than possibly through remote providers (e.g. LDAP) +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -304886,7 +297192,7 @@ salt \(aq*\(aq user.chworkphone foo 7735550123 .UNINDENT .INDENT 0.0 .TP -.B salt.modules.useradd.delete(name, remove=False, force=False, root=None) +.B salt.modules.useradd.delete(name, remove=False, force=False, root=None, local=False) Remove a user from the minion .INDENT 7.0 .TP @@ -304901,6 +297207,13 @@ Force some actions that would fail otherwise .TP .B root Directory to chroot into +.TP +.B local (Only on systems with luserdel available): +Ensure the user account is removed locally ignoring global +account management (default is False). +.sp +New in version 3007.0. + .UNINDENT .sp CLI Example: @@ -305270,8 +297583,9 @@ defined by having a \fIconfig.vm.network \(dqpublic_network\(dq\fP statement in The IP address of the bridged adapter will typically be assigned by DHCP and unknown to you, but you should be able to determine what IP network the address will be chosen from. If you enter a CIDR network mask, Salt will attempt to find the VM\(aqs address for you. -The host machine will send an \(dqifconfig\(dq command to the VM (using ssh to \fIssh_host\fP:\fIssh_port\fP) -and return the IP address of the first interface it can find which matches your mask. +The host machine will send an \(dqip link show\(dq or \(dqifconfig\(dq command to the VM +(using ssh to \fIssh_host\fP:\fIssh_port\fP) and return the IP address of the first interface it +can find which matches your mask. .UNINDENT .INDENT 0.0 .TP @@ -305666,7 +297980,14 @@ salt \(aq*\(aq varnish.version .UNINDENT .SS salt.modules.vault .sp -Functions to interact with Hashicorp Vault. +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%vault Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.SS Functions to interact with Hashicorp Vault. .INDENT 0.0 .TP .B maintainer @@ -305691,81 +298012,343 @@ If you see the following error, you\(aqll need to upgrade \fBrequests\fP to at l .fi .UNINDENT .UNINDENT -.INDENT 0.0 -.TP -.B configuration -The salt\-master must be configured to allow peer\-runner -configuration, as well as configuration for the module. +.SS Configuration .sp -Add this segment to the master configuration file, or -/etc/salt/master.d/vault.conf: -.INDENT 7.0 +In addition to the module configuration, it is required for the Salt master +to be configured to allow peer runs in order to use the Vault integration. +.sp +Changed in version 3007.0: The \fBvault\fP configuration structure has changed significantly to account +for many new features. If found, the old structure will be automatically +translated to the new one. +.sp +\fBPlease update your peer_run configuration\fP to take full advantage of the +updated modules. The old endpoint (\fBvault.generate_token\fP) will continue +to work, but result in unnecessary roundtrips once your minions have been +updated. + +.sp +To allow minions to pull configuration and credentials from the Salt master, +add this segment to the master configuration file: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +peer_run: + .*: + \- vault.get_config # always + \- vault.generate_new_token # relevant when \(gatoken\(ga == \(gaissue:type\(ga + \- vault.generate_secret_id # relevant when \(gaapprole\(ga == \(gaissue:type\(ga +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Minimally required configuration: +.INDENT 0.0 .INDENT 3.5 .sp .nf .ft C vault: - url: https://vault.service.domain:8200 - verify: /etc/ssl/certs/ca\-certificates.crt - role_name: minion_role - namespace: vault_enterprice_namespace - auth: - method: approle - role_id: 11111111\-2222\-3333\-4444\-1111111111111 - secret_id: 11111111\-1111\-1111\-1111\-1111111111111 - policies: - \- saltstack/minions - \- saltstack/minion/{minion} - .. more policies - keys: - \- n63/TbrQuL3xaIW7ZZpuXj/tIfnK1/MbVxO4vT3wYD2A - \- S9OwCvMRhErEA4NVVELYBs6w/Me6+urgUr24xGK44Uy3 - \- F1j4b7JKq850NS6Kboiy5laJ0xY8dWJvB3fcwA+SraYl - \- 1cYtvjKJNDVam9c7HNqJUfINk4PYyAXIpjkpN/sIuzPv - \- 3pPK5X6vGtwLhNOFv1U2elahECz3HpRUfNXJFYLw6lid + auth: + token: abcdefg\-hijklmnop\-qrstuvw + server: + url: https://vault.example.com:8200 .ft P .fi .UNINDENT .UNINDENT +.sp +A sensible example configuration, e.g. in \fB/etc/salt/master.d/vault.conf\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +vault: + auth: + method: approle + role_id: e5a7b66e\-5d08\-da9c\-7075\-71984634b882 + secret_id: 841771dc\-11c9\-bbc7\-bcac\-6a3945a69cd9 + cache: + backend: file + issue: + token: + role_name: salt_minion + params: + explicit_max_ttl: 30 + num_uses: 10 + policies: + assign: + \- salt_minion + \- salt_role_{pillar[roles]} + server: + url: https://vault.example.com:8200 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The above configuration requires the following policies for the master: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# Issue tokens +path \(dqauth/token/create\(dq { + capabilities = [\(dqcreate\(dq, \(dqread\(dq, \(dqupdate\(dq] +} + +# Issue tokens with token roles +path \(dqauth/token/create/*\(dq { + capabilities = [\(dqcreate\(dq, \(dqread\(dq, \(dqupdate\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +A sensible example configuration that issues AppRoles to minions +from a separate authentication endpoint (notice differing mounts): +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +vault: + auth: + method: approle + mount: approle # <\-\- mount the salt master authenticates at + role_id: e5a7b66e\-5d08\-da9c\-7075\-71984634b882 + secret_id: 841771dc\-11c9\-bbc7\-bcac\-6a3945a69cd9 + cache: + backend: file + issue: + type: approle + approle: + mount: salt\-minions # <\-\- mount the salt master manages + metadata: + entity: + minion\-id: \(aq{minion}\(aq + role: \(aq{pillar[role]}\(aq + server: + url: https://vault.example.com:8200 +ext_pillar: + \- vault: path=salt/minions/{minion} + \- vault: path=salt/roles/{pillar[role]} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The above configuration requires the following policies for the master: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# List existing AppRoles +path \(dqauth/salt\-minions/role\(dq { + capabilities = [\(dqlist\(dq] +} + +# Manage AppRoles +path \(dqauth/salt\-minions/role/*\(dq { + capabilities = [\(dqread\(dq, \(dqcreate\(dq, \(dqupdate\(dq, \(dqdelete\(dq] +} + +# Lookup mount accessor +path \(dqsys/auth/salt\-minions\(dq { + capabilities = [\(dqread\(dq, \(dqsudo\(dq] +} + +# Lookup entities by alias name (role\-id) and alias mount accessor +path \(dqidentity/lookup/entity\(dq { + capabilities = [\(dqcreate\(dq, \(dqupdate\(dq] + allowed_parameters = { + \(dqalias_name\(dq = [] + \(dqalias_mount_accessor\(dq = [\(dqauth_approle_0a1b2c3d\(dq] + } +} + +# Manage entities with name prefix salt_minion_ +path \(dqidentity/entity/name/salt_minion_*\(dq { + capabilities = [\(dqread\(dq, \(dqcreate\(dq, \(dqupdate\(dq, \(dqdelete\(dq] +} + +# Create entity aliases – you can restrict the mount_accessor +# This might allow privilege escalation in case the salt master +# is compromised and the attacker knows the entity ID of an +# entity with relevant policies attached \- although you might +# have other problems at that point. +path \(dqidentity/entity\-alias\(dq { + capabilities = [\(dqcreate\(dq, \(dqupdate\(dq] + allowed_parameters = { + \(dqid\(dq = [] + \(dqcanonical_id\(dq = [] + \(dqmount_accessor\(dq = [\(dqauth_approle_0a1b2c3d\(dq] + \(dqname\(dq = [] + } +} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +This enables you to write templated ACL policies like: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqsalt/data/minions/{{identity.entity.metadata.minion\-id}}\(dq { + capabilities = [\(dqread\(dq] +} + +path \(dqsalt/data/roles/{{identity.entity.metadata.role}}\(dq { + capabilities = [\(dqread\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +AppRole policies and entity metadata are generally not updated +automatically. After a change, you will need to synchronize +them by running \fI\%vault.sync_approles\fP +or \fI\%vault.sync_entities\fP respectively. +.UNINDENT +.UNINDENT +.sp +All possible master configuration options with defaults: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +vault: + auth: + approle_mount: approle + approle_name: salt\-master + method: token + role_id: + secret_id: null + token: + token_lifecycle: + minimum_ttl: 10 + renew_increment: null + cache: + backend: session + config: 3600 + kv_metadata: connection + secret: ttl + issue: + allow_minion_override_params: false + type: token + approle: + mount: salt\-minions + params: + bind_secret_id: true + secret_id_num_uses: 1 + secret_id_ttl: 60 + token_explicit_max_ttl: 60 + token_num_uses: 10 + secret_id_bound_cidrs: null + token_ttl: null + token_max_ttl: null + token_no_default_policy: false + token_period: null + token_bound_cidrs: null + token: + role_name: null + params: + explicit_max_ttl: null + num_uses: 1 + ttl: null + period: null + no_default_policy: false + renewable: true + wrap: 30s + keys: [] + metadata: + entity: + minion\-id: \(aq{minion}\(aq + secret: + saltstack\-jid: \(aq{jid}\(aq + saltstack\-minion: \(aq{minion}\(aq + saltstack\-user: \(aq{user}\(aq + policies: + assign: + \- saltstack/minions + \- saltstack/{minion} + cache_time: 60 + refresh_pillar: null + server: + url: + namespace: null + verify: null +.ft P +.fi +.UNINDENT +.UNINDENT +.SS \fBauth\fP +.sp +Contains authentication information for the local machine. +.INDENT 0.0 +.TP +.B approle_mount +New in version 3007.0. + +.sp +The name of the AppRole authentication mount point. Defaults to \fBapprole\fP\&. +.TP +.B approle_name +New in version 3007.0. + +.sp +The name of the AppRole. Defaults to \fBsalt\-master\fP\&. +.sp +\fBNOTE:\fP .INDENT 7.0 +.INDENT 3.5 +Only relevant when a locally configured role_id/secret_id uses +response wrapping. +.UNINDENT +.UNINDENT .TP -.B url -Url to your Vault installation. Required. -.TP -.B verify -For details please see -\fI\%https://requests.readthedocs.io/en/master/user/advanced/#ssl\-cert\-verification\fP +.B method +Currently only \fBtoken\fP and \fBapprole\fP auth types are supported. +Defaults to \fBtoken\fP\&. .sp -New in version 2018.3.0. +AppRole is the preferred way to authenticate with Vault as it provides +some advanced options to control the authentication process. +Please see the \fI\%Vault documentation\fP +for more information. +.TP +.B role_id +The role ID of the AppRole. Required if \fBauth:method\fP == \fBapprole\fP\&. +.sp +Changed in version 3007.0: In addition to a plain string, this can also be specified as a +dictionary that includes \fBwrap_info\fP, i.e. the return payload +of a wrapping request. .TP -.B namespaces -Optional Vault Namespace. Used with Vault enterprice +.B secret_id +The secret ID of the AppRole. +Only required if the configured AppRole requires it. .sp -For detail please see: -\fI\%https://www.vaultproject.io/docs/enterprise/namespaces\fP -.sp -New in version 3004. +Changed in version 3007.0: In addition to a plain string, this can also be specified as a +dictionary that includes \fBwrap_info\fP, i.e. the return payload +of a wrapping request. .TP -.B role_name -Role name for minion tokens created. If omitted, minion tokens will be -created without any role, thus being able to inherit any master token -policy (including token creation capabilities). Optional. -.sp -For details please see: -\fI\%https://www.vaultproject.io/api/auth/token/index.html#create\-token\fP -.sp -Example configuration: -\fI\%https://www.nomadproject.io/docs/vault\-integration/index.html#vault\-token\-role\-configuration\fP -.TP -.B auth -Currently only token and approle auth types are supported. Required. -.sp -Approle is the preferred way to authenticate with Vault as it provide -some advanced options to control authentication process. -Please visit Vault documentation for more info: -\fI\%https://www.vaultproject.io/docs/auth/approle.html\fP +.B token +Token to authenticate to Vault with. Required if \fBauth:method\fP == \fBtoken\fP\&. .sp The token must be able to create tokens with the policies that should be assigned to minions. @@ -305777,10 +298360,12 @@ config example: .nf .ft C vault: - url: https://vault.service.domain:8200 auth: method: token token: sdb://osenv/VAULT_TOKEN + server: + url: https://vault.service.domain:8200 + osenv: driver: env .ft P @@ -305800,47 +298385,303 @@ export VAULT_TOKEN=11111111\-1111\-1111\-1111\-1111111111111 .UNINDENT .UNINDENT .sp -Configuration keys \fBuses\fP or \fBttl\fP may also be specified under \fBauth\fP -to configure the tokens generated on behalf of minions to be reused for the -defined number of uses or length of time in seconds. These settings may also be configured -on the minion when \fBallow_minion_override\fP is set to \fBTrue\fP in the master -config. +Changed in version 3007.0: In addition to a plain string, this can also be specified as a +dictionary that includes \fBwrap_info\fP, i.e. the return payload +of a wrapping request. + +.TP +.B token_lifecycle +Token renewal settings. .sp -Defining \fBuses\fP will cause the salt master to generate a token with that number of uses rather -than a single use token. This multi\-use token will be cached on the minion. The type of minion -cache can be specified with \fBtoken_backend: session\fP or \fBtoken_backend: disk\fP\&. The value of -\fBsession\fP is the default, and will store the vault information in memory only for that session. -The value of \fBdisk\fP will write to an on disk file, and persist between state runs (most -helpful for multi\-use tokens). +\fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 +This setting can be specified inside a minion\(aqs configuration as well +and will override the master\(aqs default for the minion. .sp -.nf -.ft C -vault: - auth: - method: token - token: xxxxxx - uses: 10 - ttl: 43200 - allow_minion_override: True - token_backend: disk +Token lifecycle settings have significancy for any authentication method, +not just \fBtoken\fP\&. +.UNINDENT +.UNINDENT +.sp +\fBminimum_ttl\fP specifies the time (in seconds or as a time string like \fB24h\fP) +an in\-use token should be valid for. If the current validity period is less +than this and the token is renewable, a renewal will be attempted. If it is +not renewable or a renewal does not extend the ttl beyond the specified minimum, +a new token will be generated. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Since leases like database credentials are tied to a token, setting this to +a much higher value than the default can be necessary, depending on your +specific use case and configuration. +.UNINDENT +.UNINDENT +.sp +\fBrenew_increment\fP specifies the amount of time the token\(aqs validity should +be requested to be renewed for when renewing a token. When unset, will extend +the token\(aqs validity by its default ttl. +Set this to \fBfalse\fP to disable token renewals. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +The Vault server is allowed to disregard this request. +.UNINDENT +.UNINDENT +.UNINDENT +.SS \fBcache\fP +.sp +Configures token/lease and metadata cache (for KV secrets) on all hosts +as well as configuration cache on minions that receive issued credentials. +.INDENT 0.0 +.TP +.B backend +Changed in version 3007.0: This used to be found in \fBauth:token_backend\fP\&. - .. versionchanged:: 3001 -.ft P -.fi +.sp +The cache backend in use. Defaults to \fBsession\fP, which will store the +Vault configuration in memory only for that specific Salt run. +\fBdisk\fP/\fBfile\fP/\fBlocalfs\fP will force using the localfs driver, regardless +of configured minion data cache. +Setting this to anything else will use the default configured cache for +minion data (\fI\%cache\fP), by default the local filesystem +as well. +.TP +.B clear_attempt_revocation +New in version 3007.0. + +.sp +When flushing still valid cached tokens and leases, attempt to have them +revoked after a (short) delay. Defaults to \fB60\fP\&. +Set this to false to disable revocation (not recommended). +.TP +.B clear_on_unauthorized +New in version 3007.0. + +.sp +When encountering an \fBUnauthorized\fP response with an otherwise valid token, +flush the cache and request new credentials. Defaults to true. +If your policies are relatively stable, disabling this will prevent +a lot of unnecessary overhead, with the tradeoff that once they change, +you might have to clear the cache manually or wait for the token to expire. +.TP +.B config +New in version 3007.0. + +.sp +The time in seconds to cache queried configuration from the master. +Defaults to \fB3600\fP (one hour). Set this to \fBnull\fP to disable +cache expiration. Changed \fBserver\fP configuration on the master will +still be recognized, but changes in \fBauth\fP and \fBcache\fP will need +a manual update using \fBvault.update_config\fP or cache clearance +using \fBvault.clear_cache\fP\&. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Expiring the configuration will also clear cached authentication +credentials and leases. .UNINDENT .UNINDENT .TP -.B policies -Policies that are assigned to minions when requesting a token. These -can either be static, eg \fBsaltstack/minions\fP, or templated with grain -values, eg \fBmy\-policies/{grains[os]}\fP\&. \fB{minion}\fP is shorthand for -\fBgrains[id]\fP, eg \fBsaltstack/minion/{minion}\fP\&. +.B expire_events +New in version 3007.0. + .sp -New in version 3006.0: Policies can be templated with pillar values as well: \fBsalt_role_{pillar[roles]}\fP +Fire an event when the session cache containing leases is cleared +(\fBvault/cache//clear\fP) or cached leases have expired +(\fBvault/lease//expire\fP). +A reactor can be employed to ensure fresh leases are issued. +Defaults to false. +.TP +.B kv_metadata +New in version 3007.0. + +.sp +The time in seconds to cache KV metadata used to determine if a path +is using version 1/2 for. Defaults to \fBconnection\fP, which will clear +the metadata cache once a new configuration is requested from the +master. Setting this to \fBnull\fP will keep the information +indefinitely until the cache is cleared manually using +\fBvault.clear_cache\fP with \fBconnection=false\fP\&. +.TP +.B secret +New in version 3007.0. + +.sp +The time in seconds to cache tokens/secret IDs for. Defaults to \fBttl\fP, +which caches the secret for as long as it is valid, unless a new configuration +is requested from the master. +.UNINDENT +.SS \fBissue\fP +.sp +Configures authentication data issued by the master to minions. +.INDENT 0.0 +.TP +.B type +New in version 3007.0. + +.sp +The type of authentication to issue to minions. Can be \fBtoken\fP or \fBapprole\fP\&. +Defaults to \fBtoken\fP\&. +.sp +To be able to issue AppRoles to minions, the master needs to be able to +create new AppRoles on the configured auth mount (see policy example above). +It is strongly encouraged to create a separate mount dedicated to minions. +.TP +.B approle +New in version 3007.0. + +.sp +Configuration regarding issued AppRoles. +.sp +\fBmount\fP specifies the name of the auth mount the master manages. +Defaults to \fBsalt\-minions\fP\&. This mount should be exclusively dedicated +to the Salt master. +.sp +\fBparams\fP configures the AppRole the master creates for minions. See the +\fI\%Vault AppRole API docs\fP +for details. If you update these params, you can update the minion AppRoles +manually using the vault runner: \fBsalt\-run vault.sync_approles\fP, but they +will be updated automatically during a request by a minion as well. +.TP +.B token +New in version 3007.0. + +.sp +Configuration regarding issued tokens. +.sp +\fBrole_name\fP specifies the role name for minion tokens created. Optional. +.sp +Changed in version 3007.0: This used to be found in \fBrole_name\fP\&. + +.sp +If omitted, minion tokens will be created without any role, thus being able +to inherit any master token policy (including token creation capabilities). +.sp +Example configuration: +\fI\%https://www.nomadproject.io/docs/vault\-integration/index.html#vault\-token\-role\-configuration\fP +.sp +\fBparams\fP configures the tokens the master issues to minions. +.sp +Changed in version 3007.0: This used to be found in \fBauth:ttl\fP and \fBauth:uses\fP\&. +The possible parameters were synchronized with the Vault nomenclature: +.INDENT 7.0 +.INDENT 3.5 +.INDENT 0.0 +.IP \(bu 2 +\fBttl\fP previously was mapped to \fBexplicit_max_ttl\fP on Vault, not \fBttl\fP\&. +For the same behavior as before, you will need to set \fBexplicit_max_ttl\fP now. +.IP \(bu 2 +\fBuses\fP is now called \fBnum_uses\fP\&. +.UNINDENT +.UNINDENT +.UNINDENT + +.sp +See the \fI\%Vault token API docs\fP +for details. To make full use of multi\-use tokens, you should configure a cache +that survives a single session (e.g. \fBdisk\fP). +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +If unset, the master issues single\-use tokens to minions, which can be quite expensive. +.UNINDENT +.UNINDENT +.TP +.B allow_minion_override_params +Changed in version 3007.0: This used to be found in \fBauth:allow_minion_override\fP\&. + +.sp +Whether to allow minions to request to override parameters for issuing credentials. +See \fBissue_params\fP below. +.TP +.B wrap +New in version 3007.0. + +.sp +The time a minion has to unwrap a wrapped secret issued by the master. +Set this to false to disable wrapping, otherwise a time string like \fB30s\fP +can be used. Defaults to \fB30s\fP\&. +.UNINDENT +.SS \fBkeys\fP +.INDENT 0.0 +.INDENT 3.5 +List of keys to use to unseal vault server with the \fBvault.unseal\fP runner. +.UNINDENT +.UNINDENT +.SS \fBmetadata\fP +.sp +New in version 3007.0. + +.sp +Configures metadata for the issued entities/secrets. Values have to be strings +and can be templated with the following variables: +.INDENT 0.0 +.IP \(bu 2 +\fB{jid}\fP Salt job ID that issued the secret. +.IP \(bu 2 +\fB{minion}\fP The minion ID the secret was issued for. +.IP \(bu 2 +\fB{user}\fP The user the Salt daemon issuing the secret was running as. +.IP \(bu 2 +\fB{pillar[]}\fP A minion pillar value that does not depend on Vault. +.IP \(bu 2 +\fB{grains[]}\fP A minion grain value. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Values have to be strings, hence templated variables that resolve to lists +will be concatenated to a lexicographically sorted comma\-separated list +(Python \fBlist.sort()\fP). +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B entity +Configures the metadata associated with the minion entity inside Vault. +Entities are only created when issuing AppRoles to minions. +.TP +.B secret +Configures the metadata associated with issued tokens/secret IDs. They +are logged in plaintext to the Vault audit log. +.UNINDENT +.SS \fBpolicies\fP +.sp +Changed in version 3007.0: This used to specify the list of policies associated with a minion token only. +The equivalent is found in \fBassign\fP\&. + +.INDENT 0.0 +.TP +.B assign +List of policies that are assigned to issued minion authentication data, +either token or AppRole. +.sp +They can be static strings or string templates with +.INDENT 7.0 +.IP \(bu 2 +\fB{minion}\fP The minion ID. +.IP \(bu 2 +\fB{pillar[]}\fP A minion pillar value. +.IP \(bu 2 +\fB{grains[]}\fP A minion grain value. +.UNINDENT +.sp +For pillar and grain values, lists are expanded, so \fBsalt_role_{pillar[roles]}\fP +with \fB[a, b]\fP results in \fBsalt_role_a\fP and \fBsalt_role_b\fP to be issued. +.sp +Defaults to \fB[saltstack/minions, saltstack/{minion}]\fP\&. +.sp +New in version 3006.0: Policies can be templated with pillar values as well: \fBsalt_role_{pillar[roles]}\fP\&. Make sure to only reference pillars that are not sourced from Vault since the latter -ones might be unavailable during policy rendering. +ones might be unavailable during policy rendering. If you use the Vault +integration in one of your pillar \fBsls\fP files, all values from that file +will be absent during policy rendering, even the ones that do not depend on Vault. .sp \fBIMPORTANT:\fP @@ -305851,26 +298692,6 @@ everything except \fBgrains[id]\fP is minion\-controlled. .UNINDENT .UNINDENT .sp -If a template contains a grain which evaluates to a list, it will be -expanded into multiple policies. For example, given the template -\fBsaltstack/by\-role/{grains[roles]}\fP, and a minion having these grains: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -grains: - roles: - \- web - \- database -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The minion will have the policies \fBsaltstack/by\-role/web\fP and -\fBsaltstack/by\-role/database\fP\&. -.sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 @@ -305880,67 +298701,186 @@ throw an exception. Strings and numbers are examples of types which work well. .UNINDENT .UNINDENT -.sp -Optional. If policies is not configured, \fBsaltstack/minions\fP and -\fBsaltstack/{minion}\fP are used as defaults. .TP -.B policies_refresh_pillar -Whether to refresh the pillar data when rendering templated policies. -When unset (=null/None), will only refresh when the cached data -is unavailable, boolean values force one behavior always. +.B cache_time +New in version 3007.0. + +.sp +Number of seconds compiled templated policies are cached on the master. +This is important when using pillar values in templates, since compiling +the pillar is an expensive operation. .sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 -Using cached pillar data only (policies_refresh_pillar=False) -might cause the policies to be out of sync. If there is no cached pillar -data available for the minion, pillar templates will fail to render at all. +Only effective when issuing tokens to minions. Token policies +need to be compiled every time a token is requested, while AppRole\-associated +policies are written to Vault configuration the first time authentication data +is requested (they can be refreshed on demand by running +\fBsalt\-run vault.sync_approles\fP). +.sp +They will also be refreshed in case other issuance parameters are changed +(such as uses/ttl), either on the master or the minion +(if allow_minion_override_params is True). +.UNINDENT +.UNINDENT +.TP +.B refresh_pillar +New in version 3007.0. + +.sp +Whether to refresh the minion pillar when compiling templated policies +that contain pillar variables. +Only effective when issuing tokens to minions (see note on cache_time above). +.INDENT 7.0 +.IP \(bu 2 +\fBnull\fP (default) only compiles the pillar when no cached pillar is found. +.IP \(bu 2 +\fBfalse\fP never compiles the pillar. This means templated policies that +contain pillar values are skipped if no cached pillar is found. +.IP \(bu 2 +\fBtrue\fP always compiles the pillar. This can cause additional strain +on the master since the compilation is costly. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Hardcoded to True when issuing AppRoles. +.sp +Using cached pillar data only (refresh_pillar=False) might cause the policies +to be out of sync. If there is no cached pillar data available for the minion, +pillar templates will fail to render at all. .sp If you use pillar values for templating policies and do not disable refreshing pillar data, make sure the relevant values are not sourced from Vault (ext_pillar, sdb) or from a pillar sls file that uses the vault -execution module. Although this will often work when cached pillar data is +execution/sdb module. Although this will often work when cached pillar data is available, if the master needs to compile the pillar data during policy rendering, all Vault modules will be broken to prevent an infinite loop. .UNINDENT .UNINDENT +.UNINDENT +.SS \fBserver\fP +.sp +Changed in version 3007.0: The values found in here were found in the \fBvault\fP root namespace previously. + +.sp +Configures Vault server details. +.INDENT 0.0 .TP -.B policies_cache_time -Policy computation can be heavy in case pillar data is used in templated policies and -it has not been cached. Therefore, a short\-lived cache specifically for rendered policies -is used. This specifies the expiration timeout in seconds. Defaults to 60. +.B url +URL of your Vault installation. Required. .TP -.B keys -List of keys to use to unseal vault server with the vault.unseal runner. +.B verify +Configures certificate verification behavior when issuing requests to the +Vault server. If unset, requests will use the CA certificates bundled with \fBcertifi\fP\&. +.sp +For details, please see \fI\%the requests documentation\fP\&. +.sp +New in version 2018.3.0. + +.sp +Changed in version 3007.0: Minions again respect the master configuration value, which was changed +implicitly in v3001. If this value is set in the minion configuration +as well, it will take precedence. +.sp +In addition, this value can now be set to a PEM\-encoded CA certificate +to use as the sole trust anchor for certificate chain verification. + .TP -.B config_location +.B namespace +Optional Vault namespace. Used with Vault Enterprise. +.sp +For details please see: +\fI\%https://www.vaultproject.io/docs/enterprise/namespaces\fP +.sp +New in version 3004. + +.UNINDENT +.sp +Minion configuration (optional): +.SS \fBconfig_location\fP +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.INDENT 3.5 Where to get the connection details for calling vault. By default, vault will try to determine if it needs to request the connection details from the master or from the local config. This optional option will force vault to use the connection details from the master or the local config. Can only be either \fBmaster\fP or \fBlocal\fP\&. -.INDENT 7.0 -.INDENT 3.5 +.UNINDENT +.UNINDENT +.sp New in version 3006.0. .UNINDENT +.UNINDENT +.SS \fBissue_params\fP +.INDENT 0.0 +.INDENT 3.5 +Request overrides for token/AppRole issuance. This needs to be allowed +on the master by setting \fBissue:allow_minion_override_params\fP to true. +See the master configuration \fBissue:token:params\fP or \fBissue:approle:params\fP +for reference. +.sp +Changed in version 3007.0: For token issuance, this used to be found in \fBauth:ttl\fP and \fBauth:uses\fP\&. +Mind that the parameter names have been synchronized with Vault, see notes +above (TLDR: \fBttl\fP => \fBexplicit_max_ttl\fP, \fBuses\fP => \fBnum_uses\fP\&. + .UNINDENT .UNINDENT .sp -Add this segment to the master configuration file, or -/etc/salt/master.d/peer_run.conf: +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +\fBauth:token_lifecycle\fP and \fBserver:verify\fP can be set on the minion as well. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.clear_cache(connection=True, session=False) +New in version 3007.0. + +.sp +Delete Vault caches. Will ensure the current token and associated leases +are revoked by default. +.sp +The cache is organized in a hierarchy: \fB/vault/connection/session/leases\fP\&. +(\fIitalics\fP mark data that is only cached when receiving configuration from a master) +.sp +\fBconnection\fP contains KV metadata (by default), \fIconfiguration\fP and \fI(AppRole) auth credentials\fP\&. +\fBsession\fP contains the currently active token. +\fBleases\fP contains leases issued to the currently active token like database credentials. +.sp +CLI Example: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C -peer_run: - .*: - \- vault.generate_token +salt \(aq*\(aq vault.clear_cache +salt \(aq*\(aq vault.clear_cache session=True .ft P .fi .UNINDENT .UNINDENT +.INDENT 7.0 +.TP +.B connection +Only clear the cached data scoped to a connection. This includes +configuration, auth credentials, the currently active auth token +as well as leases and KV metadata (by default). Defaults to true. +Set this to false to clear all Vault caches. +.TP +.B session +Only clear the cached data scoped to a session. This only includes +leases and the currently active auth token, but not configuration +or (AppRole) auth credentials. Defaults to false. +Setting this to true will keep the connection cache, regardless +of \fBconnection\fP\&. +.UNINDENT .UNINDENT .INDENT 0.0 .TP @@ -305948,7 +298888,10 @@ peer_run: Changed in version 3001. .sp -Delete minion Vault token cache file +Changed in version 3007.0: This is now an alias for \fBvault.clear_cache\fP with \fBconnection=True\fP\&. + +.sp +Delete minion Vault token cache. .sp CLI Example: .INDENT 7.0 @@ -305964,8 +298907,9 @@ salt \(aq*\(aq vault.clear_token_cache .UNINDENT .INDENT 0.0 .TP -.B salt.modules.vault.delete_secret(path) -Delete secret at the path in vault. The vault policy used must allow this. +.B salt.modules.vault.delete_secret(path, *args) +Delete secret at . The vault policy used must allow this. +If is on KV v2, the secret will be soft\-deleted. .sp CLI Example: .INDENT 7.0 @@ -305974,10 +298918,44 @@ CLI Example: .nf .ft C salt \(aq*\(aq vault.delete_secret \(dqsecret/my/secret\(dq +salt \(aq*\(aq vault.delete_secret \(dqsecret/my/secret\(dq 1 2 3 .ft P .fi .UNINDENT .UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dq/\(dq { + capabilities = [\(dqdelete\(dq] +} + +# or KV v2 +path \(dq/data/\(dq { + capabilities = [\(dqdelete\(dq] +} + +# KV v2 versions +path \(dq/delete/\(dq { + capabilities = [\(dqupdate\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B path +The path to the secret, including mount. +.UNINDENT +.sp +New in version 3007.0: For KV v2, you can specify versions to soft\-delete as supplemental +positional arguments. + .UNINDENT .INDENT 0.0 .TP @@ -305985,8 +298963,8 @@ salt \(aq*\(aq vault.delete_secret \(dqsecret/my/secret\(dq New in version 3001. .sp -Destroy specified secret version at the path in vault. The vault policy -used must allow this. Only supported on Vault KV version 2 +Destroy specified secret versions . The vault policy +used must allow this. Only supported on Vault KV version 2. .sp CLI Example: .INDENT 7.0 @@ -305999,17 +298977,60 @@ salt \(aq*\(aq vault.destroy_secret \(dqsecret/my/secret\(dq 1 2 .fi .UNINDENT .UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dq/destroy/\(dq { + capabilities = [\(dqupdate\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B path +The path to the secret, including mount. +.UNINDENT +.sp +You can specify versions to destroy as supplemental positional arguments. +At least one is required. .UNINDENT .INDENT 0.0 .TP -.B salt.modules.vault.list_secrets(path, default=) +.B salt.modules.vault.get_server_config() +New in version 3007.0. + +.sp +Return the server connection configuration that\(aqs currently in use by Salt. +Contains \fBurl\fP, \fBverify\fP and \fBnamespace\fP\&. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.get_server_config +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.list_secrets(path, default=, keys_only=False) +List secret keys at . The vault policy used must allow this. +The path should end with a trailing slash. +.sp Changed in version 3001: The \fBdefault\fP argument has been added. When the path or path/key combination is not found, an exception will be raised, unless a default is provided. -.sp -List secret keys at the path in vault. The vault policy used must allow this. -The path should end with a trailing slash. .sp CLI Example: .INDENT 7.0 @@ -306022,59 +299043,415 @@ salt \(aq*\(aq vault.list_secrets \(dqsecret/my/\(dq .fi .UNINDENT .UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dq/\(dq { + capabilities = [\(dqlist\(dq] +} + +# or KV v2 +path \(dq/metadata/\(dq { + capabilities = [\(dqlist\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B path +The path to the secret, including mount. +.TP +.B default +New in version 3001. + +.sp +When the path is not found, an exception will be raised, unless a default +is provided here. +.TP +.B keys_only +New in version 3007.0. + +.sp +This function used to return a dictionary like \fB{\(dqkeys\(dq: [\(dqsome/\(dq, \(dqsome/key\(dq]}\fP\&. +Setting this to True will only return the list of keys. +For backwards\-compatibility reasons, this defaults to False. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.patch_secret(path, **kwargs) +Patch secret dataset at . Fields are specified as arbitrary keyword arguments. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This works even for older Vault versions, KV v1 and with missing +\fBpatch\fP capability, but will use more than one request to simulate +the functionality by issuing a read and update request. +.sp +For proper, single\-request patching, requires versions of KV v2 that +support the \fBpatch\fP capability and the \fBpatch\fP capability to be available +for the path. +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This uses JSON Merge Patch format internally. +Keys set to \fBnull\fP (JSON/YAML)/\fBNone\fP (Python) will be deleted. +.UNINDENT +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.patch_secret \(dqsecret/my/secret\(dq password=\(dqbaz\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +# Proper patching +path \(dq/data/\(dq { + capabilities = [\(dqpatch\(dq] +} + +# OR (!), for older KV v2 setups: + +path \(dq/data/\(dq { + capabilities = [\(dqread\(dq, \(dqupdate\(dq] +} + +# OR (!), for KV v1 setups: + +path \(dq/\(dq { + capabilities = [\(dqread\(dq, \(dqupdate\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B path +The path to the secret, including mount. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.policies_list() +New in version 3007.0. + +.sp +List all ACL policies. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.policies_list +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqsys/policy\(dq { + capabilities = [\(dqread\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.policy_delete(policy) +New in version 3007.0. + +.sp +Delete an ACL policy. Returns False if the policy did not exist. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.policy_delete salt_minion +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqsys/policy/\(dq { + capabilities = [\(dqdelete\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B policy +The name of the policy to delete. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.policy_fetch(policy) +New in version 3007.0. + +.sp +Fetch the rules associated with an ACL policy. Returns None if the policy +does not exist. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.policy_fetch salt_minion +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqsys/policy/\(dq { + capabilities = [\(dqread\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B policy +The name of the policy to fetch. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.policy_write(policy, rules) +New in version 3007.0. + +.sp +Create or update an ACL policy. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.policy_write salt_minion \(aqpath \(dqsecret/foo\(dq {...}\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqsys/policy/\(dq { + capabilities = [\(dqcreate\(dq, \(dqupdate\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B policy +The name of the policy to create/update. +.TP +.B rules +Rules to write, formatted as in\-line HCL. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.query(method, endpoint, payload=None) +New in version 3007.0. + +.sp +Issue arbitrary queries against the Vault API. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.query GET auth/token/lookup\-self +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: Depends on the query. +.sp +You can ask the vault CLI to output the necessary policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +vault read \-output\-policy auth/token/lookup\-self +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B method +HTTP method to use. +.TP +.B endpoint +Vault API endpoint to issue the request against. Do not include \fB/v1/\fP\&. +.TP +.B payload +Optional dictionary to use as JSON payload. +.UNINDENT .UNINDENT .INDENT 0.0 .TP .B salt.modules.vault.read_secret(path, key=None, metadata=False, default=) +Return the value of at in vault, or entire secret. +.sp Changed in version 3001: The \fBdefault\fP argument has been added. When the path or path/key combination is not found, an exception will be raised, unless a default is provided. .sp -Return the value of key at path in vault, or entire secret +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq vault.read_secret salt/kv/secret +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dq/\(dq { + capabilities = [\(dqread\(dq] +} + +# or KV v2 +path \(dq/data/\(dq { + capabilities = [\(dqread\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT .INDENT 7.0 .TP -.B Parameters -\fBmetadata\fP \-\- -.sp -Optional \- If using KV v2 backend, display full results, including metadata -.sp +.B path +The path to the secret, including mount. +.TP +.B key +The data field at to read. If unspecified, returns the +whole dataset. +.TP +.B metadata New in version 3001. - -.UNINDENT .sp -Jinja Example: +If using KV v2 backend, display full results, including metadata. +Defaults to False. +.TP +.B default +New in version 3001. + +.sp +When the path or path/key combination is not found, an exception will +be raised, unless a default is provided here. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.vault.update_config(keep_session=False) +New in version 3007.0. + +.sp +Attempt to update the cached configuration without clearing the +currently active Vault session. +.sp +CLI Example: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C -my\-secret: {{ salt[\(aqvault\(aq].read_secret(\(aqsecret/my/secret\(aq, \(aqsome\-key\(aq) }} - -{{ salt[\(aqvault\(aq].read_secret(\(aq/secret/my/secret\(aq, \(aqsome\-key\(aq, metadata=True)[\(aqdata\(aq] }} +salt \(aq*\(aq vault.update_config .ft P .fi .UNINDENT .UNINDENT .INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -{% set supersecret = salt[\(aqvault\(aq].read_secret(\(aqsecret/my/secret\(aq) %} -secrets: - first: {{ supersecret.first }} - second: {{ supersecret.second }} -.ft P -.fi -.UNINDENT +.TP +.B keep_session +Only update configuration that can be updated without +creating a new login session. +If this is false, still tries to keep the active session, +but might clear it if the server configuration has changed +significantly. +Defaults to False. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B salt.modules.vault.write_raw(path, raw) -Set raw data at the path in vault. The vault policy used must allow this. +Set raw data at . The vault policy used must allow this. .sp CLI Example: .INDENT 7.0 @@ -306087,11 +299464,22 @@ salt \(aq*\(aq vault.write_raw \(dqsecret/my/secret\(dq \(aq{\(dquser\(dq:\(dqfo .fi .UNINDENT .UNINDENT +.sp +Required policy: see write_secret +.INDENT 7.0 +.TP +.B path +The path to the secret, including mount. +.TP +.B raw +Secret data to write to . Has to be a mapping. +.UNINDENT .UNINDENT .INDENT 0.0 .TP .B salt.modules.vault.write_secret(path, **kwargs) -Set secret at the path in vault. The vault policy used must allow this. +Set secret dataset at . The vault policy used must allow this. +Fields are specified as arbitrary keyword arguments. .sp CLI Example: .INDENT 7.0 @@ -306104,6 +299492,30 @@ salt \(aq*\(aq vault.write_secret \(dqsecret/my/secret\(dq user=\(dqfoo\(dq pass .fi .UNINDENT .UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dq/\(dq { + capabilities = [\(dqcreate\(dq, \(dqupdate\(dq] +} + +# or KV v2 +path \(dq/data/\(dq { + capabilities = [\(dqcreate\(dq, \(dqupdate\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B path +The path to the secret, including mount. +.UNINDENT .UNINDENT .SS salt.modules.vbox_guest .sp @@ -318434,6 +311846,348 @@ salt \(aq*\(aq webutil.verify /etc/httpd/htpasswd larry maybepassword opts=ns .UNINDENT .UNINDENT .UNINDENT +.SS salt.modules.win_appx +.SS Manage provisioned apps +.sp +New in version 3007.0. + +.sp +Provisioned apps are part of the image and are installed for every user the +first time the user logs on. Provisioned apps are also updated and sometimes +reinstalled when the system is updated. +.sp +Apps removed with this module will remove the app for all users and deprovision +the app. Deprovisioned apps will neither be installed for new users nor will +they be upgraded. +.sp +An app removed with this module can only be re\-provisioned on the machine, but +it can\(aqt be re\-installed for all users. Also, once a package has been +deprovisioned, the only way to reinstall it is to download the package. This is +difficult. The steps are outlined below: +.INDENT 0.0 +.IP 1. 3 +.INDENT 3.0 +.TP +.B Obtain the Microsoft Store URL for the app: +.INDENT 7.0 +.IP \(bu 2 +Open the page for the app in the Microsoft Store +.IP \(bu 2 +Click the share button and copy the URL +.UNINDENT +.UNINDENT +.IP 2. 3 +.INDENT 3.0 +.TP +.B Look up the packages on \fI\%https://store.rg\-adguard.net/\fP: +.INDENT 7.0 +.IP \(bu 2 +Ensure \fBURL (link)\fP is selected in the first dropdown +.IP \(bu 2 +Paste the URL in the search field +.IP \(bu 2 +Ensure Retail is selected in the 2nd dropdown +.IP \(bu 2 +Click the checkmark button +.UNINDENT +.UNINDENT +.UNINDENT +.sp +This should return a list of URLs for the package and all dependencies for all +architectures. Download the package and all dependencies for your system +architecture. These will usually have one of the following file extensions: +.INDENT 0.0 +.IP \(bu 2 +\fB\&.appx\fP +.IP \(bu 2 +\fB\&.appxbundle\fP +.IP \(bu 2 +\fB\&.msix\fP +.IP \(bu 2 +\fB\&.msixbundle\fP +.UNINDENT +.sp +Dependencies will need to be installed first. +.sp +Not all packages can be found this way, but it seems like most of them can. +.sp +Use the \fBappx.install\fP function to provision the new app. +.INDENT 0.0 +.TP +.B salt.modules.win_appx.install(package) +This function uses \fBdism\fP to provision a package. This means that it will +be made a part of the online image and added to new users on the system. If +a package has dependencies, those must be installed first. +.sp +If a package installed using this function has been deprovisioned +previously, the registry entry marking it as deprovisioned will be removed. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +There is no \fBappx.present\fP state. Instead, use the +\fBdism.provisioned_package_installed\fP state. +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B Parameters +\fBpackage\fP (\fI\%str\fP) \-\- +.sp +The full path to the package to install. Can be one of the +following: +.INDENT 7.0 +.IP \(bu 2 +\fB\&.appx\fP or \fB\&.appxbundle\fP +.IP \(bu 2 +\fB\&.msix\fP or \fB\&.msixbundle\fP +.IP \(bu 2 +\fB\&.ppkg\fP +.UNINDENT + +.TP +.B Returns +\fBTrue\fP if successful, otherwise \fBFalse\fP +.TP +.B Return type +\fI\%bool\fP +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(dq*\(dq appx.install \(dqC:\eTemp\eMicrosoft.ZuneMusic.msixbundle\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.win_appx.list_(query=None, field=\(aqName\(aq, include_store=False, frameworks=False, bundles=True) +Get a list of Microsoft Store packages installed on the system. +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBquery\fP (\fI\%str\fP) \-\- +.sp +The query string to use to filter packages to be listed. The string +can match multiple packages. \fBNone\fP will return all packages. Here +are some example strings: +.INDENT 2.0 +.IP \(bu 2 +\fB*teams*\fP \- Returns Microsoft Teams +.IP \(bu 2 +\fB*zune*\fP \- Returns Windows Media Player and ZuneVideo +.IP \(bu 2 +\fB*zuneMusic*\fP \- Only returns Windows Media Player +.IP \(bu 2 +\fB*xbox*\fP \- Returns all xbox packages, there are 5 by default +.IP \(bu 2 +\fB*\fP \- Returns everything but the Microsoft Store, unless +\fBinclude_store=True\fP +.UNINDENT + +.IP \(bu 2 +\fBfield\fP (\fI\%str\fP) \-\- +.sp +This function returns a list of packages on the system. It can +display a short name or a full name. If \fBNone\fP is passed, a +dictionary will be returned with some common fields. The default is +\fBName\fP\&. Valid options are any fields returned by the powershell +command \fBGet\-AppxPackage\fP\&. Here are some useful fields: +.INDENT 2.0 +.IP \(bu 2 +Name +.IP \(bu 2 +Version +.IP \(bu 2 +PackageFullName +.IP \(bu 2 +PackageFamilyName +.UNINDENT + +.IP \(bu 2 +\fBinclude_store\fP (\fI\%bool\fP) \-\- Include the Microsoft Store in the results. Default is \fBFalse\fP +.IP \(bu 2 +\fBframeworks\fP (\fI\%bool\fP) \-\- Include frameworks in the results. Default is \fBFalse\fP +.IP \(bu 2 +\fBbundles\fP (\fI\%bool\fP) \-\- If \fBTrue\fP, this will return application bundles only. If +\fBFalse\fP, this will return individual packages only, even if they +are part of a bundle. +.UNINDENT +.TP +.B Returns +A list of packages ordered by the string passed in field +list: A list of dictionaries of package information if field is \fBNone\fP +.TP +.B Return type +\fI\%list\fP +.TP +.B Raises +\fI\%CommandExecutionError\fP \-\- If an error is encountered retrieving packages +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +# List installed apps that contain the word \(dqcandy\(dq +salt \(aq*\(aq appx.list *candy* + +# Return more information about the package +salt \(aq*\(aq appx.list *candy* field=None + +# List all installed apps, including the Microsoft Store +salt \(aq*\(aq appx.list include_store=True + +# List all installed apps, including frameworks +salt \(aq*\(aq appx.list frameworks=True + +# List all installed apps that are bundles +salt \(aq*\(aq appx.list bundles=True +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.win_appx.list_deprovisioned(query=None) +When an app is deprovisioned, a registry key is created that will keep it +from being reinstalled during a major system update. This function returns a +list of keys for apps that have been deprovisioned. +.INDENT 7.0 +.TP +.B Parameters +\fBquery\fP (\fI\%str\fP) \-\- +.sp +The query string to use to filter packages to be listed. The string +can match multiple packages. \fBNone\fP will return all packages. Here +are some example strings: +.INDENT 7.0 +.IP \(bu 2 +\fB*teams*\fP \- Returns Microsoft Teams +.IP \(bu 2 +\fB*zune*\fP \- Returns Windows Media Player and ZuneVideo +.IP \(bu 2 +\fB*zuneMusic*\fP \- Only returns Windows Media Player +.IP \(bu 2 +\fB*xbox*\fP \- Returns all xbox packages, there are 5 by default +.IP \(bu 2 +\fB*\fP \- Returns everything but the Microsoft Store, unless +\fBinclude_store=True\fP +.UNINDENT + +.TP +.B Returns +A list of packages matching the query criteria +.TP +.B Return type +\fI\%list\fP +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(dq*\(dq appx.list_deprovisioned *zune* +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.win_appx.remove(query=None, include_store=False, frameworks=False, deprovision_only=False) +Removes Microsoft Store packages from the system. If the package is part of +a bundle, the entire bundle will be removed. +.sp +This function removes the package for all users on the system. It also +deprovisions the package so that it isn\(aqt re\-installed by later system +updates. To only deprovision a package and not remove it for all users, set +\fBdeprovision_only=True\fP\&. +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBquery\fP (\fI\%str\fP) \-\- +.sp +The query string to use to select the packages to be removed. If the +string matches multiple packages, they will all be removed. Here are +some example strings: +.INDENT 2.0 +.IP \(bu 2 +\fB*teams*\fP \- Remove Microsoft Teams +.IP \(bu 2 +\fB*zune*\fP \- Remove Windows Media Player and ZuneVideo +.IP \(bu 2 +\fB*zuneMusic*\fP \- Only remove Windows Media Player +.IP \(bu 2 +\fB*xbox*\fP \- Remove all xbox packages, there are 5 by default +.IP \(bu 2 +\fB*\fP \- Remove everything but the Microsoft Store, unless +\fBinclude_store=True\fP +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 2.0 +.INDENT 3.5 +Use the \fBappx.list\fP function to make sure your query is +returning what you expect. Then use the same query to remove +those packages +.UNINDENT +.UNINDENT + +.IP \(bu 2 +\fBinclude_store\fP (\fI\%bool\fP) \-\- Include the Microsoft Store in the results of the query to be +removed. Use this with caution. It is difficult to reinstall the +Microsoft Store once it has been removed with this function. Default +is \fBFalse\fP +.IP \(bu 2 +\fBframeworks\fP (\fI\%bool\fP) \-\- Include frameworks in the results of the query to be removed. +Default is \fBFalse\fP +.IP \(bu 2 +\fBdeprovision_only\fP (\fI\%bool\fP) \-\- Only deprovision the package. The package will be removed from the +current user and added to the list of deprovisioned packages. The +package will not be re\-installed in future system updates. New users +of the system will not have the package installed. However, the +package will still be installed for existing users. Default is +\fBFalse\fP +.UNINDENT +.TP +.B Returns +\fBTrue\fP if successful, \fBNone\fP if no packages found +.TP +.B Return type +\fI\%bool\fP +.TP +.B Raises +\fI\%CommandExecutionError\fP \-\- On errors encountered removing the package +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(dq*\(dq appx.remove *candy* +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.modules.win_auditpol .sp A salt module for modifying the audit policies on the machine @@ -319314,6 +313068,64 @@ salt \(aq*\(aq dism.add_package C:\ePackages\epackage.cab .UNINDENT .INDENT 0.0 .TP +.B salt.modules.win_dism.add_provisioned_package(package, image=None, restart=False) +Provision a package using DISM. A provisioned package will install for new +users on the system. It will also be reinstalled on each user if the system +is updated. +.sp +New in version 3007.0. + +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBpackage\fP (\fI\%str\fP) \-\- +.sp +The package to install. Can be one of the following: +.INDENT 2.0 +.IP \(bu 2 +\fB\&.appx\fP or \fB\&.appxbundle\fP +.IP \(bu 2 +\fB\&.msix\fP or \fB\&.msixbundle\fP +.IP \(bu 2 +\fB\&.ppkg\fP +.UNINDENT + +.IP \(bu 2 +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP\&. +.IP \(bu 2 +\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the installation. Default is +\fBFalse\fP +.UNINDENT +.TP +.B Returns +A dictionary containing the results of the command +.TP +.B Return type +\fI\%dict\fP +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq dism.add_provisioned_package C:\ePackages\epackage.appx +salt \(aq*\(aq dism.add_provisioned_package C:\ePackages\epackage.appxbundle +salt \(aq*\(aq dism.add_provisioned_package C:\ePackages\epackage.msix +salt \(aq*\(aq dism.add_provisioned_package C:\ePackages\epackage.msixbundle +salt \(aq*\(aq dism.add_provisioned_package C:\ePackages\epackage.ppkg +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.modules.win_dism.available_capabilities(image=None) List the capabilities available on the system .INDENT 7.0 @@ -319646,7 +313458,40 @@ CLI Example: .sp .nf .ft C -salt \(aq*\(aq dism. package_info C:\epackages\epackage.cab +salt \(aq*\(aq dism.package_info C:\epackages\epackage.cab +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.modules.win_dism.provisioned_packages(image=None) +List the packages installed on the system +.sp +New in version 3007.0. + +.INDENT 7.0 +.TP +.B Parameters +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline +Windows image. If \fINone\fP is passed, the running operating system is +targeted. Default is None. +.TP +.B Returns +A list of installed packages +.TP +.B Return type +\fI\%list\fP +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt \(aq*\(aq dism.installed_packages .ft P .fi .UNINDENT @@ -322198,7 +316043,7 @@ salt \(aq*\(aq file.stats /etc/passwd .UNINDENT .INDENT 0.0 .TP -.B salt.modules.win_file.symlink(src, link, force=False, atomic=False) +.B salt.modules.win_file.symlink(src, link, force=False, atomic=False, follow_symlinks=True) Create a symbolic link to a file .sp This is only supported with Windows Vista or later and must be executed by @@ -322221,6 +316066,10 @@ If it doesn\(aqt, an error will be raised. .IP \(bu 2 \fBatomic\fP (\fI\%bool\fP) \-\- Use atomic file operations to create the symlink \&.. versionadded:: 3006.0 +.IP \(bu 2 +\fBfollow_symlinks\fP (\fI\%bool\fP) \-\- If set to \fBFalse\fP, use \fBos.path.lexists()\fP for existence checks +instead of \fBos.path.exists()\fP\&. +\&.. versionadded:: 3007.0 .UNINDENT .TP .B Returns @@ -327012,8 +320861,7 @@ salt \(aq*\(aq ntp.set_servers \(aqpool.ntp.org\(aq \(aqus.pool.ntp.org\(aq Manage the Windows System PATH .sp Note that not all Windows applications will rehash the PATH environment variable, -Only the ones that listen to the WM_SETTINGCHANGE message -\fI\%http://support.microsoft.com/kb/104011\fP +Only the ones that listen to the WM_SETTINGCHANGE message. .INDENT 0.0 .TP .B salt.modules.win_path.add(path, index=None, **kwargs) @@ -336964,7 +330812,7 @@ salt \(aq*\(aq wusa.is_installed KB123456 .UNINDENT .INDENT 0.0 .TP -.B salt.modules.win_wusa.list() +.B salt.modules.win_wusa.list_() Get a list of updates installed on the machine .INDENT 7.0 .TP @@ -338358,7 +332206,8 @@ peer: .UNINDENT .sp In order for the \fI\%Compound Matcher\fP to work with restricting signing -policies to a subset of minions, in addition calls to \fI\%match.compound\fP +policies to a subset of minions, in addition calls to +\fI\%match.compound_matches\fP by the minion acting as the CA must be permitted: .INDENT 0.0 .INDENT 3.5 @@ -338371,8 +332220,9 @@ peer: .*: \- x509.sign_remote_certificate +peer_run: ca_server: - \- match.compound + \- match.compound_matches .ft P .fi .UNINDENT @@ -338381,11 +332231,29 @@ peer: \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -Compound matching in signing policies currently has security tradeoffs since the -CA server queries the requesting minion itself if it matches, not the Salt master. -It is recommended to rely on glob matching only. +When compound match expressions are employed, pillar values can only be matched +literally. This is a barrier to enumeration attacks by the CA server. +.sp +Also note that compound matching requires a minion data cache on the master. +Any certificate signing request will be denied if \fI\%minion_data_cache\fP is +disabled (it is enabled by default). .UNINDENT .UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +Since grain values are controlled by minions, you should avoid using them +to restrict certificate issuance. +.sp +See \fI\%Is Targeting using Grain Data Secure?\fP\&. +.UNINDENT +.UNINDENT +.sp +Changed in version 3007.0: Previously, a compound expression match was validated by the requesting minion +itself via peer publishing, which did not protect from compromised minions. +The new match validation takes place on the master using peer running. + .SS Signing policies .sp In addition, the minion representing the CA needs to have at least one @@ -338461,6 +332329,27 @@ during the first state run. For \fBx509.private_key_managed\fP, the file mode defaults to \fB0400\fP\&. This should be considered a bug fix because writing private keys with world\-readable permissions by default is a security issue. +.IP \(bu 2 +Restricting signing policies using compound match expressions requires peer run +permissions instead of peer publishing permissions: +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# x509, x509_v2 in 3006.* +peer: + ca_server: + \- match.compound + +# x509_v2 from 3007.0 onwards +peer_run: + ca_server: + \- match.compound_matches +.ft P +.fi +.UNINDENT .UNINDENT .sp Note that when a \fBca_server\fP is involved, both peers must use the updated module version. @@ -341059,6 +334948,9 @@ automatically in place of YUM in Fedora 22 and newer. .sp New in version 3003: Support for \fBtdnf\fP on Photon OS. +.sp +New in version 3007.0: Support for \fBdnf5\(ga\fP on Fedora 39 + .INDENT 0.0 .TP .B class salt.modules.yumpkg.AvailablePackages(*args, **kwargs) @@ -343172,6 +337064,14 @@ salt \(aq*\(aq pkg.version_cmp \(aq0.2\-001\(aq \(aq0.2.0.1\-002\(aq .UNINDENT .SS salt.modules.zabbix .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Support for Zabbix .INDENT 0.0 .TP @@ -350761,7 +344661,7 @@ salt \(aq*\(aq pkg.purge pkgs=\(aq[\(dqfoo\(dq, \(dqbar\(dq]\(aq .UNINDENT .INDENT 0.0 .TP -.B salt.modules.zypperpkg.refresh_db(force=None, root=None) +.B salt.modules.zypperpkg.refresh_db(force=None, root=None, gpgautoimport=False, **kwargs) Trigger a repository refresh by calling \fBzypper refresh\fP\&. Refresh will run with \fB\-\-force\fP if the \(dqforce=True\(dq flag is passed on the CLI or \fBrefreshdb_force\fP is set to \fBtrue\fP in the pillar. The CLI option @@ -350779,6 +344679,20 @@ It will return a dict: .UNINDENT .UNINDENT .INDENT 7.0 +.TP +.B gpgautoimport +False +If set to True, automatically trust and import public GPG key for +the repository. +.sp +New in version 3007.0. + +.TP +.B repos +Refresh just the specified repos +.sp +New in version 3007.0. + .TP .B root operate on a different root directory. @@ -350858,6 +344772,11 @@ salt \(aq*\(aq pkg.remove pkgs=\(aq[\(dqfoo\(dq, \(dqbar\(dq]\(aq .fi .UNINDENT .UNINDENT +.sp +Changed in version 3007.0: Can now remove also PTF packages which require a different handling in the backend. + +.sp +Can now remove also PTF packages which require a different handling in the backend. .UNINDENT .INDENT 0.0 .TP @@ -351317,7 +345236,6 @@ _ T{ \fI\%docker\fP T} T{ -Docker executor module T} _ T{ @@ -351349,6 +345267,14 @@ Directly calls the given function with arguments .UNINDENT .SS salt.executors.docker .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Docker executor module .sp New in version 2019.2.0. @@ -351549,12 +345475,6 @@ center; |l|l|. _ T{ -\fI\%azurefs\fP -T} T{ -The backend for serving files from the Azure blob storage service. -T} -_ -T{ \fI\%gitfs\fP T} T{ Git Fileserver Backend @@ -351591,68 +345511,6 @@ Subversion Fileserver Backend T} _ .TE -.SS salt.fileserver.azurefs -.sp -The backend for serving files from the Azure blob storage service. -.sp -New in version 2015.8.0. - -.sp -To enable, add \fBazurefs\fP to the \fI\%fileserver_backend\fP option in -the Master config file. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -fileserver_backend: - \- azurefs -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Starting in Salt 2018.3.0, this fileserver requires the standalone Azure -Storage SDK for Python. Theoretically any version >= v0.20.0 should work, but -it was developed against the v0.33.0 version. -.sp -Each storage container will be mapped to an environment. By default, containers -will be mapped to the \fBbase\fP environment. You can override this behavior with -the \fBsaltenv\fP configuration option. You can have an unlimited number of -storage containers, and can have a storage container serve multiple -environments, or have multiple storage containers mapped to the same -environment. Normal first\-found rules apply, and storage containers are -searched in the order they are defined. -.sp -You must have either an account_key or a sas_token defined for each container, -if it is private. If you use a sas_token, it must have READ and LIST -permissions. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -azurefs: - \- account_name: my_storage - account_key: \(aqfNH9cRp0+qVIVYZ+5rnZAhHc9ycOUcJnHtzpfOr0W0sxrtL2KVLuMe1xDfLwmfed+JJInZaEdWVCPHD4d/oqeA==\(aq - container_name: my_container - \- account_name: my_storage - sas_token: \(aqss=b&sp=&sv=2015\-07\-08&sig=cohxXabx8FQdXsSEHyUXMjsSfNH2tZ2OB97Ou44pkRE%3D&srt=co&se=2017\-04\-18T21%3A38%3A01Z\(aq - container_name: my_dev_container - saltenv: dev - \- account_name: my_storage - container_name: my_public_container -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Do not include the leading ? for sas_token if generated from the web -.UNINDENT -.UNINDENT .SS salt.fileserver.gitfs .sp Git Fileserver Backend @@ -352120,12 +345978,6 @@ Grains from cloud metadata servers at 169.254.169.254 T} _ T{ -\fI\%metadata_azure\fP -T} T{ -Grains from cloud metadata servers at 169.254.169.254 in Azure Virtual Machine -T} -_ -T{ \fI\%metadata_gce\fP T} T{ Grains from cloud metadata servers at 169.254.169.254 in google compute engine @@ -352162,6 +346014,12 @@ Simple grain to merge the opts into the grains directly if the grain_opts config T} _ T{ +\fI\%package\fP +T} T{ +Grains for detecting what type of package Salt is using +T} +_ +T{ \fI\%panos\fP T} T{ Generate baseline proxy minion grains for panos hosts. @@ -352675,35 +346533,6 @@ metadata_server_grains: True .TP .B salt.grains.metadata.metadata() .UNINDENT -.SS salt.grains.metadata_azure -.sp -Grains from cloud metadata servers at 169.254.169.254 in Azure Virtual Machine -.sp -New in version 3006.0. - -.INDENT 0.0 -.TP -.B depends -requests -.UNINDENT -.sp -To enable these grains that pull from the \fI\%http://169.254.169.254/metadata/instance?api\-version=2020\-09\-01\fP -metadata server set \fImetadata_server_grains: True\fP in the minion config. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -metadata_server_grains: True -.ft P -.fi -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.grains.metadata_azure.metadata() -Takes no arguments, returns a dictionary of metadata values from Azure. -.UNINDENT .SS salt.grains.metadata_gce .sp Grains from cloud metadata servers at 169.254.169.254 in @@ -353241,6 +347070,18 @@ configuration value is set. .B salt.grains.opts.opts() Return the minion configuration settings .UNINDENT +.SS salt.grains.package +.sp +Grains for detecting what type of package Salt is using +.sp +New in version 3007.0. + +.INDENT 0.0 +.TP +.B salt.grains.package.package() +Function to determine if the user is currently using +onedir, pip or system level package of Salt. +.UNINDENT .SS salt.grains.panos .sp Generate baseline proxy minion grains for panos hosts. @@ -356499,7 +350340,7 @@ data: { .SS \fB/\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.SaltAPIHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.SaltAPIHandler(*args, **kwargs) Main API handler for base \(dq/\(dq .INDENT 7.0 .TP @@ -356689,7 +350530,7 @@ stop on failure please use compound\-command\-execution. .SS \fB/login\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.SaltAuthHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.SaltAuthHandler(*args, **kwargs) Handler for login requests .INDENT 7.0 .TP @@ -356861,7 +350702,7 @@ Set\-Cookie: session_id=6d1b722e; expires=Sat, 17 Nov 2012 03:23:52 GMT; Path=/ .SS \fB/minions\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.MinionSaltAPIHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.MinionSaltAPIHandler(*args, **kwargs) A convenience endpoint for minion related functions .INDENT 7.0 .TP @@ -357031,7 +350872,7 @@ return: .SS \fB/jobs\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.JobsSaltAPIHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.JobsSaltAPIHandler(*args, **kwargs) A convenience endpoint for job cache data .INDENT 7.0 .TP @@ -357164,7 +351005,7 @@ return: .SS \fB/run\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.RunSaltAPIHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.RunSaltAPIHandler(*args, **kwargs) Endpoint to run commands without normal session handling .INDENT 7.0 .TP @@ -357253,7 +351094,7 @@ return: .SS \fB/events\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.EventsSaltAPIHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.EventsSaltAPIHandler(*args, **kwargs) Expose the Salt event bus .sp The event bus on the Salt master exposes a large variety of things, notably @@ -357424,7 +351265,7 @@ data: {\(dqtag\(dq: \(dq20140112010149808995\(dq, \(dqdata\(dq: {\(dqfun_args\(d .SS \fB/hook\fP .INDENT 0.0 .TP -.B class salt.netapi.rest_tornado.saltnado.WebhookSaltAPIHandler(application, request, **kwargs) +.B class salt.netapi.rest_tornado.saltnado.WebhookSaltAPIHandler(*args, **kwargs) A generic web hook entry point that fires an event on Salt\(aqs event bus .sp External services can POST data to this URL to trigger an event in Salt. @@ -358776,12 +352617,6 @@ center; |l|l|. _ T{ -\fI\%azureblob\fP -T} T{ -Use Azure Blob as a Pillar source. -T} -_ -T{ \fI\%cmd_json\fP T} T{ Execute a command and read the output as JSON. @@ -359064,95 +352899,26 @@ Pillar data from vCenter or an ESXi host T} _ .TE -.SS salt.pillar.azureblob +.SS salt.pillar.cmd_json .sp -Use Azure Blob as a Pillar source. +Execute a command and read the output as JSON. The JSON data is then directly overlaid onto the minion\(aqs Pillar data. +.SS Configuring the CMD_JSON ext_pillar .sp -New in version 3001. - -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\-storage\-blob\fP >= 12.0.0 -.UNINDENT -.UNINDENT -.sp -The Azure Blob ext_pillar can be configured with the following parameters: +Set the following Salt config to setup cmd json result as external pillar source: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ext_pillar: - \- azureblob: - container: \(aqtest_container\(aq - connection_string: \(aqconnection_string\(aq - multiple_env: False - environment: \(aqbase\(aq - blob_cache_expire: 30 - blob_sync_on_update: True + \- cmd_json: \(aqecho {\(dqarg\(dq:\(dqvalue\(dq}\(aq .ft P .fi .UNINDENT .UNINDENT -.INDENT 0.0 -.TP -.B param container -The name of the target Azure Blob Container. -.TP -.B param connection_string -The connection string to use to access the specified Azure Blob Container. -.TP -.B param multiple_env -Specifies whether the pillar should interpret top level folders as pillar environments. -Defaults to false. -.TP -.B param environment -Specifies which environment the container represents when in single environment mode. Defaults -to \(aqbase\(aq and is ignored if multiple_env is set as True. -.TP -.B param blob_cache_expire -Specifies expiration time of the Azure Blob metadata cache file. Defaults to 30s. -.TP -.B param blob_sync_on_update -Specifies if the cache is synced on update. Defaults to True. -.UNINDENT -.INDENT 0.0 -.TP -.B salt.pillar.azureblob.ext_pillar(minion_id, pillar, container, connection_string, multiple_env=False, environment=\(aqbase\(aq, blob_cache_expire=30, blob_sync_on_update=True) -Execute a command and read the output as YAML. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBcontainer\fP \-\- The name of the target Azure Blob Container. -.IP \(bu 2 -\fBconnection_string\fP \-\- The connection string to use to access the specified Azure Blob Container. -.IP \(bu 2 -\fBmultiple_env\fP \-\- Specifies whether the pillar should interpret top level folders as pillar environments. -Defaults to false. -.IP \(bu 2 -\fBenvironment\fP \-\- Specifies which environment the container represents when in single environment mode. Defaults -to \(aqbase\(aq and is ignored if multiple_env is set as True. -.IP \(bu 2 -\fBblob_cache_expire\fP \-\- Specifies expiration time of the Azure Blob metadata cache file. Defaults to 30s. -.IP \(bu 2 -\fBblob_sync_on_update\fP \-\- Specifies if the cache is synced on update. Defaults to True. -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.pillar.cmd_json .sp -Execute a command and read the output as JSON. The JSON data is then directly overlaid onto the minion\(aqs Pillar data. +This will run the command \fBecho {arg: value}\fP on the master. +.SS Module Documentation .INDENT 0.0 .TP .B salt.pillar.cmd_json.ext_pillar(minion_id, pillar, command) @@ -365519,7 +359285,7 @@ ext_pillar: .UNINDENT .sp Each key needs to have all the key\-value pairs with the names you -require. Avoid naming every key \(aqpassword\(aq as you they will collide: +require. Avoid naming every key \(aqpassword\(aq as they will collide. .sp If you want to nest results under a nesting_key name use the following format: .INDENT 0.0 @@ -365577,7 +359343,7 @@ ext_pillar: .UNINDENT .UNINDENT .sp -You can also use nesting here as well. Identical nesting keys will get merged. +You can also use nesting here as well. Identical nesting keys will get merged. .INDENT 0.0 .INDENT 3.5 .sp @@ -365668,6 +359434,7 @@ vault ext_pillar paths. Using pillar values to template vault pillar paths requires them to be defined before the vault ext_pillar is called. Especially consider the significancy of \fI\%ext_pillar_first\fP master config setting. +You cannot use pillar values sourced from Vault in pillar\-templated policies. .sp If a pillar pattern matches multiple paths, the results are merged according to the master configuration values \fI\%pillar_source_merging_strategy\fP @@ -365969,7 +359736,6 @@ _ T{ \fI\%docker\fP T} T{ -Docker Proxy Minion T} _ T{ @@ -366764,6 +360530,14 @@ For this proxy shutdown is a no\-op .UNINDENT .SS salt.proxy.docker .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Docker Proxy Minion .sp New in version 2019.2.0. @@ -371702,6 +365476,12 @@ General management functions for salt, tools like seeing what hosts are up and w T} _ T{ +\fI\%match\fP +T} T{ +Run matchers from the master context. +T} +_ +T{ \fI\%mattermost\fP T} T{ Module for sending messages to Mattermost @@ -371824,7 +365604,6 @@ _ T{ \fI\%vault\fP T} T{ -Runner functions supporting the Vault modules. T} _ T{ @@ -375565,6 +369344,55 @@ salt\-run manage.versions .UNINDENT .UNINDENT .UNINDENT +.SS salt.runners.match +.sp +Run matchers from the master context. +.sp +New in version 3007.0. + +.INDENT 0.0 +.TP +.B salt.runners.match.compound_matches(expr, minion_id) +Check whether a minion is matched by a given compound match expression. +On success, this function will return the minion ID, otherwise False. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Pillar values will be matched literally only since this function is intended +for remote calling. This also applies to node groups defined on the master. +Custom matchers are not respected. +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +If a module calls this runner from a minion, you will need to explicitly +allow the remote call. See \fI\%peer_run\fP\&. +.UNINDENT +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run match.compound_matches \(aqI@foo:bar and G@os:Deb* and not db*\(aq myminion +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B expr +The \fI\%Compound Matcher\fP expression to validate against. +.TP +.B minion_id +The minion ID of the minion to check the match for. +.UNINDENT +.UNINDENT .SS salt.runners.mattermost .sp \fBNote for 2017.7 releases!\fP @@ -378251,6 +372079,41 @@ salt\-run saltutil.sync_wheel .UNINDENT .UNINDENT .UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.saltutil.sync_wrapper(saltenv=\(aqbase\(aq, extmod_whitelist=None, extmod_blacklist=None) +New in version 3007.0. + +.sp +Sync salt\-ssh wrapper modules from \fBsalt://_wrapper\fP to the master. +.INDENT 7.0 +.TP +.B saltenv +base +The fileserver environment from which to sync. To sync from more than +one environment, pass a comma\-separated list. +.TP +.B extmod_whitelist +None +comma\-seperated list of modules to sync +.TP +.B extmod_blacklist +None +comma\-seperated list of modules to blacklist based on type +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run saltutil.sync_wrapper +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.runners.sdb .sp Runner for setting and querying data via the sdb API on the master @@ -379478,8 +373341,16 @@ salt\-run thin.generate_min .UNINDENT .SS salt.runners.vault .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%vault Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Runner functions supporting the Vault modules. Configuration instructions are -documented in the execution module docs. +documented in the \fI\%execution module docs\fP\&. .INDENT 0.0 .TP .B maintainer @@ -379499,12 +373370,145 @@ once an item is requested. .UNINDENT .INDENT 0.0 .TP -.B salt.runners.vault.generate_token(minion_id, signature, impersonated_by_master=False, ttl=None, uses=None) -Generate a Vault token for minion minion_id +.B salt.runners.vault.cleanup_auth() +New in version 3007.0. + +.sp +Removes AppRoles and entities associated with unknown minion IDs. +Can only clean up entities if the AppRole still exists. +.sp +\fBWARNING:\fP +.INDENT 7.0 +.INDENT 3.5 +Make absolutely sure that the configured minion approle issue mount is +exclusively dedicated to the Salt master, otherwise you might lose data +by using this function! (config: \fBvault:issue:approle:mount\fP) +.sp +This detects unknown existing AppRoles by listing all roles on the +configured minion AppRole mount and deducting known minions from the +returned list. +.UNINDENT +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.cleanup_auth +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.clear_cache(master=True, minions=True) +New in version 3007.0. + +.sp +Clears master cache of Vault\-specific data. This can include: +\- AppRole metadata +\- rendered policies +\- cached authentication credentials for impersonated minions +\- cached KV metadata for impersonated minions +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.clear_cache +salt\-run vault.clear_cache minions=false +salt\-run vault.clear_cache master=false minions=\(aq[minion1, minion2]\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B master +Clear cached data for the master context. +Includes cached master authentication data and KV metadata. +Defaults to true. +.TP +.B minions +Clear cached data for minions on the master. +Can include cached authentication credentials and KV metadata +for pillar compilation as well as AppRole metadata and +rendered policies for credential issuance. +Defaults to true. Set this to a list of minion IDs to only clear +cached data pertaining to thse minions. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.generate_new_token(minion_id, signature, impersonated_by_master=False, issue_params=None) +New in version 3007.0. + +.sp +Generate a Vault token for minion . .INDENT 7.0 .TP .B minion_id -The id of the minion that requests a token +The ID of the minion that requests a token. +.TP +.B signature +Cryptographic signature which validates that the request is indeed sent +by the minion (or the master, see impersonated_by_master). +.TP +.B impersonated_by_master +If the master needs to create a token on behalf of the minion, this is +True. This happens when the master generates minion pillars. +.TP +.B issue_params +Dictionary of parameters for the generated tokens. +See master configuration \fBvault:issue:token:params\fP for possible values. +Requires \fBvault:issue:allow_minion_override_params\fP master configuration +setting to be effective. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.generate_secret_id(minion_id, signature, impersonated_by_master=False, issue_params=None) +New in version 3007.0. + +.sp +Generate a Vault secret ID for minion . Requires the master to be configured +to generate AppRoles for minions (configuration: \fBvault:issue:type\fP). +.INDENT 7.0 +.TP +.B minion_id +The ID of the minion that requests a secret ID. +.TP +.B signature +Cryptographic signature which validates that the request is indeed sent +by the minion (or the master, see impersonated_by_master). +.TP +.B impersonated_by_master +If the master needs to create a token on behalf of the minion, this is +True. This happens when the master generates minion pillars. +.TP +.B issue_params +Dictionary of configuration values for the generated AppRole. +See master configuration vault:issue:approle:params for possible values. +Requires \fBvault:issue:allow_minion_override_params\fP master configuration +setting to be effective. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.generate_token(minion_id, signature, impersonated_by_master=False, ttl=None, uses=None, upgrade_request=False) +Deprecated since version 3007.0. + +.sp +Generate a Vault token for minion . +.INDENT 7.0 +.TP +.B minion_id +The ID of the minion that requests a token. .TP .B signature Cryptographic signature which validates that the request is indeed sent @@ -379519,6 +373523,180 @@ Ticket time to live in seconds, 1m minutes, or 2h hrs .TP .B uses Number of times a token can be used +.TP +.B upgrade_request +In case the new runner endpoints have not been whitelisted for peer running, +this endpoint serves as a gateway to \fBvault.get_config\fP\&. +Defaults to False. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.get_config(minion_id, signature, impersonated_by_master=False, issue_params=None, config_only=False) +New in version 3007.0. + +.sp +Return Vault configuration for minion . +.INDENT 7.0 +.TP +.B minion_id +The ID of the minion that requests the configuration. +.TP +.B signature +Cryptographic signature which validates that the request is indeed sent +by the minion (or the master, see impersonated_by_master). +.TP +.B impersonated_by_master +If the master needs to contact the Vault server on behalf of the minion, this is +True. This happens when the master generates minion pillars. +.TP +.B issue_params +Parameters for credential issuance. +Requires \fBvault:issue:allow_minion_override_params\fP master configuration +setting to be effective. +.TP +.B config_only +In case the master is configured to issue tokens, do not include a new +token in the response. This is used for configuration update checks. +Defaults to false. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.get_role_id(minion_id, signature, impersonated_by_master=False, issue_params=None) +New in version 3007.0. + +.sp +Return the Vault role\-id for minion . Requires the master to be configured +to generate AppRoles for minions (configuration: \fBvault:issue:type\fP). +.INDENT 7.0 +.TP +.B minion_id +The ID of the minion that requests a role\-id. +.TP +.B signature +Cryptographic signature which validates that the request is indeed sent +by the minion (or the master, see impersonated_by_master). +.TP +.B impersonated_by_master +If the master needs to create a token on behalf of the minion, this is +True. This happens when the master generates minion pillars. +.TP +.B issue_params +Dictionary of configuration values for the generated AppRole. +See master configuration vault:issue:approle:params for possible values. +Requires \fBvault:issue:allow_minion_override_params\fP master configuration +setting to be effective. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.list_approles() +New in version 3007.0. + +.sp +List all AppRoles that have been created by the Salt master. +They are named after the minions. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.list_approles +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqauth//role\(dq { + capabilities = [\(dqlist\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.list_entities() +New in version 3007.0. + +.sp +List all entities that have been created by the Salt master. +They are named \fIsalt_minion_{minion_id}\fP\&. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.list_entities +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Required policy: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +path \(dqidentity/entity/name\(dq { + capabilities = [\(dqlist\(dq] +} +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.show_approle(minion_id) +New in version 3007.0. + +.sp +Show AppRole configuration for . +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.show_approle db1 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.show_entity(minion_id) +New in version 3007.0. + +.sp +Show entity metadata for . +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.show_entity db1 +.ft P +.fi +.UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 @@ -379528,19 +373706,28 @@ Show the Vault policies that are applied to tokens for the given minion. .INDENT 7.0 .TP .B minion_id -The minion\(aqs id. +The ID of the minion to show policies for. .TP .B refresh_pillar Whether to refresh the pillar data when rendering templated policies. None will only refresh when the cached data is unavailable, boolean values force one behavior always. -Defaults to config value \fBpolicies_refresh_pillar\fP or None. +Defaults to config value \fBvault:policies:refresh_pillar\fP or None. .TP .B expire Policy computation can be heavy in case pillar data is used in templated policies and it has not been cached. Therefore, a short\-lived cache specifically for rendered policies is used. This specifies the expiration timeout in seconds. -Defaults to config value \fBpolicies_cache_time\fP or 60. +Defaults to config value \fBvault:policies:cache_time\fP or 60. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +When issuing AppRoles to minions, the shown policies are read from Vault +configuration for the minion\(aqs AppRole and thus refresh_pillar/expire +will not be honored. +.UNINDENT .UNINDENT .sp CLI Example: @@ -379557,6 +373744,107 @@ salt\-run vault.show_policies myminion .UNINDENT .INDENT 0.0 .TP +.B salt.runners.vault.sync_approles(minions=None, up=False, down=False) +New in version 3007.0. + +.sp +Sync minion AppRole parameters with current settings, including associated +token policies. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Only updates existing AppRoles. They are issued during the first request +for one by the minion. +Running this will reset minion overrides, which are reapplied automatically +during the next request for authentication details. +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +Unlike when issuing tokens, AppRole\-associated policies are not regularly +refreshed automatically. It is advised to schedule regular runs of this function. +.UNINDENT +.UNINDENT +.sp +If no parameter is specified, will try to sync AppRoles for all known minions. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.sync_approles +salt\-run vault.sync_approles ecorp +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B minions +(List of) ID(s) of the minion(s) to update the AppRole for. +Defaults to None. +.TP +.B up +Find all minions that are up and update their AppRoles. +Defaults to False. +.TP +.B down +Find all minions that are down and update their AppRoles. +Defaults to False. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.runners.vault.sync_entities(minions=None, up=False, down=False) +New in version 3007.0. + +.sp +Sync minion entities with current settings. Only updates entities for minions +with existing AppRoles. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +This updates associated metadata only. Entities are created only +when issuing AppRoles to minions (\fBvault:issue:type\fP == \fBapprole\fP). +.UNINDENT +.UNINDENT +.sp +If no parameter is specified, will try to sync entities for all known minions. +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +salt\-run vault.sync_entities +.ft P +.fi +.UNINDENT +.UNINDENT +.INDENT 7.0 +.TP +.B minions +(List of) ID(s) of the minion(s) to update the entity for. +Defaults to None. +.TP +.B up +Find all minions that are up and update their associated entities. +Defaults to False. +.TP +.B down +Find all minions that are down and update their associated entities. +Defaults to False. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.runners.vault.unseal() Unseal Vault server .sp @@ -380976,7 +375264,7 @@ New in version 2016.11.0. .sp This module allows access to Hashicorp Vault using an \fBsdb://\fP URI. .sp -Base configuration instructions are documented in the execution module docs. +Base configuration instructions are documented in the \fI\%execution module docs\fP\&. Below are noted extra configuration required for the sdb module, but the base configuration must also be completed. .sp @@ -381021,6 +375309,20 @@ $ vault read \-field=mypassword secret/passwords .ft P .fi .UNINDENT +.UNINDENT +.SS Further configuration +.sp +The following options can be set in the profile: +.INDENT 0.0 +.TP +.B patch +When writing data, partially update the secret instead of overwriting it completely. +This is usually the expected behavior, since without this option, +each secret path can only contain a single mapping key safely. +Defaults to \fBFalse\fP for backwards\-compatibility reasons. +.sp +New in version 3007.0. + .UNINDENT .INDENT 0.0 .TP @@ -382107,25 +376409,21 @@ _ T{ \fI\%apache\fP T} T{ -Apache state T} _ T{ \fI\%apache_conf\fP T} T{ -Manage Apache Confs T} _ T{ \fI\%apache_module\fP T} T{ -Manage Apache Modules T} _ T{ \fI\%apache_site\fP T} T{ -Manage Apache Sites T} _ T{ @@ -382165,30 +376463,6 @@ Manage SQS Queues T} _ T{ -\fI\%azurearm_compute\fP -T} T{ -Azure (ARM) Compute State Module -T} -_ -T{ -\fI\%azurearm_dns\fP -T} T{ -Azure (ARM) DNS State Module -T} -_ -T{ -\fI\%azurearm_network\fP -T} T{ -Azure (ARM) Network State Module -T} -_ -T{ -\fI\%azurearm_resource\fP -T} T{ -Azure (ARM) Resource State Module -T} -_ -T{ \fI\%beacon\fP T} T{ Management of the Salt beacons @@ -382539,25 +376813,21 @@ _ T{ \fI\%docker_container\fP T} T{ -Management of Docker containers T} _ T{ \fI\%docker_image\fP T} T{ -Management of Docker images T} _ T{ \fI\%docker_network\fP T} T{ -Management of Docker networks T} _ T{ \fI\%docker_volume\fP T} T{ -Management of Docker volumes T} _ T{ @@ -382707,7 +376977,7 @@ _ T{ \fI\%gpg\fP T} T{ -Management of the GPG keychains +Manage GPG keychains T} _ T{ @@ -383012,7 +377282,6 @@ _ T{ \fI\%kubernetes\fP T} T{ -Manage kubernetes resources as salt states T} _ T{ @@ -383600,7 +377869,6 @@ _ T{ \fI\%pushover\fP T} T{ -Send a message to PushOver T} _ T{ @@ -383929,7 +378197,6 @@ _ T{ \fI\%vault\fP T} T{ -States for managing Hashicorp Vault. T} _ T{ @@ -383963,6 +378230,12 @@ Support for htpasswd module. T} _ T{ +\fI\%win_appx\fP +T} T{ +Manage Microsoft Store apps on Windows. +T} +_ +T{ \fI\%win_certutil\fP T} T{ Installing of certificates to the Windows Certificate Manager @@ -384071,6 +378344,12 @@ Management of Windows system information T} _ T{ +\fI\%win_task\fP +T} T{ +State module for adding and removing scheduled tasks using the Windows Task Scheduler. +T} +_ +T{ \fI\%win_wua\fP T} T{ Installation of Windows Updates using the Windows Update Agent @@ -384121,55 +378400,46 @@ _ T{ \fI\%zabbix_action\fP T} T{ -Management of Zabbix Action object over Zabbix API. T} _ T{ \fI\%zabbix_host\fP T} T{ -Management of Zabbix hosts. T} _ T{ \fI\%zabbix_hostgroup\fP T} T{ -Management of Zabbix host groups. T} _ T{ \fI\%zabbix_mediatype\fP T} T{ -Management of Zabbix mediatypes. T} _ T{ \fI\%zabbix_template\fP T} T{ -New in version 2017.7.0. T} _ T{ \fI\%zabbix_user\fP T} T{ -Management of Zabbix users. T} _ T{ \fI\%zabbix_usergroup\fP T} T{ -Management of Zabbix user groups. T} _ T{ \fI\%zabbix_usermacro\fP T} T{ -Management of Zabbix usermacros. T} _ T{ \fI\%zabbix_valuemap\fP T} T{ -Management of Zabbix Valuemap object over Zabbix API. T} _ T{ @@ -384247,7 +378517,7 @@ dev.example.com: .UNINDENT .INDENT 0.0 .TP -.B salt.states.acme.cert(name, aliases=None, email=None, webroot=None, test_cert=False, renew=None, keysize=None, server=None, owner=\(aqroot\(aq, group=\(aqroot\(aq, mode=\(aq0640\(aq, certname=None, preferred_challenges=None, tls_sni_01_port=None, tls_sni_01_address=None, http_01_port=None, http_01_address=None, dns_plugin=None, dns_plugin_credentials=None) +.B salt.states.acme.cert(name, aliases=None, email=None, webroot=None, test_cert=False, renew=None, keysize=None, server=None, owner=\(aqroot\(aq, group=\(aqroot\(aq, mode=\(aq0640\(aq, certname=None, preferred_challenges=None, tls_sni_01_port=None, tls_sni_01_address=None, http_01_port=None, http_01_address=None, dns_plugin=None, dns_plugin_credentials=None, manual_auth_hook=None, manual_cleanup_hook=None) Obtain/renew a certificate from an ACME CA, probably Let\(aqs Encrypt. .INDENT 7.0 .TP @@ -384298,6 +378568,10 @@ will still attempt to connect on port 80. \fBdns_plugin\fP \-\- Name of a DNS plugin to use (currently only \(aqcloudflare\(aq) .IP \(bu 2 \fBdns_plugin_credentials\fP \-\- Path to the credentials file if required by the specified DNS plugin +.IP \(bu 2 +\fBmanual_auth_hook\fP \-\- Path to the authentication hook script. +.IP \(bu 2 +\fBmanual_cleanup_hook\fP \-\- Path to the cleanup or post\-authentication hook script. .UNINDENT .UNINDENT .UNINDENT @@ -384573,6 +378847,14 @@ run nginx install: .UNINDENT .SS salt.states.apache .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%apache Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Apache state .sp New in version 2014.7.0. @@ -384676,6 +378958,14 @@ it still needs keyword \fBthis\fP with empty string (or \(dq\(dq if nicer outpu .UNINDENT .SS salt.states.apache_conf .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%apache Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Manage Apache Confs .sp New in version 2016.3.0. @@ -384720,6 +379010,14 @@ Name of the Apache conf .UNINDENT .SS salt.states.apache_module .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%apache Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Manage Apache Modules .sp New in version 2014.7.0. @@ -384770,6 +379068,14 @@ Name of the Apache module .UNINDENT .SS salt.states.apache_site .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%apache Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Manage Apache Sites .sp New in version 2016.3.0. @@ -384832,7 +379138,7 @@ New in version 2014.1.0. .INDENT 0.0 .TP -.B salt.states.archive.extracted(name, source, source_hash=None, source_hash_name=None, source_hash_update=False, skip_files_list_verify=False, skip_verify=False, password=None, options=None, list_options=None, force=False, overwrite=False, clean=False, clean_parent=False, user=None, group=None, if_missing=None, trim_output=False, use_cmd_unzip=None, extract_perms=True, enforce_toplevel=True, enforce_ownership_on=None, archive_format=None, use_etag=False, **kwargs) +.B salt.states.archive.extracted(name, source, source_hash=None, source_hash_name=None, source_hash_update=False, skip_files_list_verify=False, skip_verify=False, password=None, options=None, list_options=None, force=False, overwrite=False, clean=False, clean_parent=False, user=None, group=None, if_missing=None, trim_output=False, use_cmd_unzip=None, extract_perms=True, enforce_toplevel=True, enforce_ownership_on=None, archive_format=None, use_etag=False, signature=None, source_hash_sig=None, signed_by_any=None, signed_by_all=None, keyring=None, gnupghome=None, **kwargs) New in version 2014.1.0. .sp @@ -385458,6 +379764,76 @@ the \fBsource_hash\fP parameter. .sp New in version 3005. +.TP +.B signature +Ensure a valid GPG signature exists on the selected \fBsource\fP file. +This needs to be a file URI retrievable by +\fI:py:func:\(gacp.cache_file \fP which +identifies a detached signature. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature is only enforced directly after caching the file, +before it is extracted to its final destination. Existing files +at the target will never be modified. +.sp +It will be enforced regardless of source type. +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B source_hash_sig +When \fBsource\fP is a remote file source, \fBsource_hash\fP is a file, +\fBskip_verify\fP is not true and \fBuse_etag\fP is not true, ensure a +valid GPG signature exists on the source hash file. +Set this to \fBtrue\fP for an inline (clearsigned) signature, or to a +file URI retrievable by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature on the \fBsource_hash\fP file is enforced regardless of +changes since its contents are used to check if an existing file +is in the correct state \- but only for remote sources! +As for \fBsignature\fP, existing target files will not be modified, +only the cached source_hash and source_hash_sig files will be removed. +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B signed_by_any +When verifying signatures either on the managed file or its source hash file, +require at least one valid signature from one of a list of key fingerprints. +This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +When verifying signatures either on the managed file or its source hash file, +require a valid signature from each of the key fingerprints in this list. +This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B keyring +When verifying signatures, use this keyring. +.sp +New in version 3007.0. + +.TP +.B gnupghome +When verifying signatures, use this GnuPG home. +.sp +New in version 3007.0. + .UNINDENT .sp \fBExamples\fP @@ -385837,31 +380213,6 @@ New in version 0.17.0. This state requires the \fBaugeas\fP Python module. .sp \fI\%Augeas\fP can be used to manage configuration files. -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -Minimal installations of Debian and Ubuntu have been seen to have packaging -bugs with python\-augeas, causing the augeas module to fail to import. If -the minion has the augeas module installed, and the state fails with a -comment saying that the state is unavailable, first restart the salt\-minion -service. If the problem persists past that, the following command can be -run from the master to determine what is causing the import to fail: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt minion\-id cmd.run \(aqpython \-c \(dqfrom augeas import Augeas\(dq\(aq -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -For affected Debian/Ubuntu hosts, installing \fBlibpython2.7\fP has been -known to resolve the issue. -.UNINDENT -.UNINDENT .INDENT 0.0 .TP .B salt.states.augeas.change(name, context=None, changes=None, lens=None, load_path=None, **kwargs) @@ -386023,7 +380374,7 @@ zabbix\-service: \- set \(dqservice\-name[. = \(aqzabbix\-agent\(aq]/protocol\(dq tcp \- set \(dqservice\-name[. = \(aqzabbix\-agent\(aq]/#comment\(dq \(dqZabbix Agent service\(dq \- rm \(dqservice\-name[. = \(aqim\-obsolete\(aq]\(dq - \- unless: grep \(dqzabbix\-agent\(dq /etc/services + \- unless: grep \(aq^zabbix\-agent\es\(aq /etc/services .ft P .fi .UNINDENT @@ -386111,2131 +380462,6 @@ Name of the user performing the SQS operations Include additional arguments and options to the aws command line .UNINDENT .UNINDENT -.SS salt.states.azurearm_compute -.sp -Azure (ARM) Compute State Module -.sp -New in version 2019.2.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as a dictionary of -keyword arguments to the \fBconnection_auth\fP parameter in order to work properly. Since the authentication -parameters are sensitive, it\(aqs recommended to pass them to the states via pillar. -.sp -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.INDENT 7.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.sp -Example Pillar for Azure Resource Manager authentication: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -azurearm: - user_pass_auth: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - username: fletch - password: 123pass - mysubscription: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - tenant: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - client_id: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - secret: XXXXXXXXXXXXXXXXXXXXXXXX - cloud_environment: AZURE_PUBLIC_CLOUD -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Example states using Azure Resource Manager authentication: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -{% set profile = salt[\(aqpillar.get\(aq](\(aqazurearm:mysubscription\(aq) %} -Ensure availability set exists: - azurearm_compute.availability_set_present: - \- name: my_avail_set - \- resource_group: my_rg - \- virtual_machines: - \- my_vm1 - \- my_vm2 - \- tags: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - -Ensure availability set is absent: - azurearm_compute.availability_set_absent: - \- name: other_avail_set - \- resource_group: my_rg - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_compute.availability_set_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure an availability set does not exist in a resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the availability set. -.IP \(bu 2 -\fBresource_group\fP \-\- Name of the resource group containing the availability set. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_compute.availability_set_present(name, resource_group, tags=None, platform_update_domain_count=None, platform_fault_domain_count=None, virtual_machines=None, sku=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure an availability set exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the availability set. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the availability set. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the availability set object. -.IP \(bu 2 -\fBplatform_update_domain_count\fP \-\- An optional parameter which indicates groups of virtual machines and underlying physical hardware that can be -rebooted at the same time. -.IP \(bu 2 -\fBplatform_fault_domain_count\fP \-\- An optional parameter which defines the group of virtual machines that share a common power source and network -switch. -.IP \(bu 2 -\fBvirtual_machines\fP \-\- A list of names of existing virtual machines to be included in the availability set. -.IP \(bu 2 -\fBsku\fP \-\- The availability set SKU, which specifies whether the availability set is managed or not. Possible values are -\(aqAligned\(aq or \(aqClassic\(aq. An \(aqAligned\(aq availability set is managed, \(aqClassic\(aq is not. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure availability set exists: - azurearm_compute.availability_set_present: - \- name: aset1 - \- resource_group: group1 - \- platform_update_domain_count: 5 - \- platform_fault_domain_count: 3 - \- sku: aligned - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - \- require: - \- azurearm_resource: Ensure resource group exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.states.azurearm_dns -.sp -Azure (ARM) DNS State Module -.sp -New in version 3000. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-dns\fP >= 1.0.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as a dictionary of -keyword arguments to the \fBconnection_auth\fP parameter in order to work properly. Since the authentication -parameters are sensitive, it\(aqs recommended to pass them to the states via pillar. -.UNINDENT -.sp -Required provider parameters: -.INDENT 0.0 -.INDENT 3.5 -if using username and password: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.UNINDENT -.UNINDENT -.sp -if using a service principal: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.INDENT 0.0 -.INDENT 3.5 -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. Possible values: -.sp -Possible values: -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.UNINDENT -.sp -Example Pillar for Azure Resource Manager authentication: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -azurearm: - user_pass_auth: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - username: fletch - password: 123pass - mysubscription: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - tenant: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - client_id: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - secret: XXXXXXXXXXXXXXXXXXXXXXXX - cloud_environment: AZURE_PUBLIC_CLOUD -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Example states using Azure Resource Manager authentication: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -{% set profile = salt[\(aqpillar.get\(aq](\(aqazurearm:mysubscription\(aq) %} -Ensure DNS zone exists: - azurearm_dns.zone_present: - \- name: contoso.com - \- resource_group: my_rg - \- tags: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - -Ensure DNS record set exists: - azurearm_dns.record_set_present: - \- name: web - \- zone_name: contoso.com - \- resource_group: my_rg - \- record_type: A - \- ttl: 300 - \- arecords: - \- ipv4_address: 10.0.0.1 - \- tags: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - -Ensure DNS record set is absent: - azurearm_dns.record_set_absent: - \- name: web - \- zone_name: contoso.com - \- resource_group: my_rg - \- record_type: A - \- connection_auth: {{ profile }} - -Ensure DNS zone is absent: - azurearm_dns.zone_absent: - \- name: contoso.com - \- resource_group: my_rg - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_dns.record_set_absent(name, zone_name, resource_group, connection_auth=None) -New in version 3000. - -.sp -Ensure a record set does not exist in the DNS zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the record set. -.IP \(bu 2 -\fBzone_name\fP \-\- Name of the DNS zone. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the DNS zone. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_dns.record_set_present(name, zone_name, resource_group, record_type, if_match=None, if_none_match=None, etag=None, metadata=None, ttl=None, arecords=None, aaaa_records=None, mx_records=None, ns_records=None, ptr_records=None, srv_records=None, txt_records=None, cname_record=None, soa_record=None, caa_records=None, connection_auth=None, **kwargs) -New in version 3000. - -.sp -Ensure a record set exists in a DNS zone. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- The name of the record set, relative to the name of the zone. -.IP \(bu 2 -\fBzone_name\fP \-\- Name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the DNS zone. -.IP \(bu 2 -\fBrecord_type\fP \-\- The type of DNS record in this record set. Record sets of type SOA can be updated but not created -(they are created when the DNS zone is created). Possible values include: \(aqA\(aq, \(aqAAAA\(aq, \(aqCAA\(aq, \(aqCNAME\(aq, -\(aqMX\(aq, \(aqNS\(aq, \(aqPTR\(aq, \(aqSOA\(aq, \(aqSRV\(aq, \(aqTXT\(aq -.IP \(bu 2 -\fBif_match\fP \-\- The etag of the record set. Omit this value to always overwrite the current record set. Specify the last\-seen -etag value to prevent accidentally overwritting any concurrent changes. -.IP \(bu 2 -\fBif_none_match\fP \-\- Set to \(aq*\(aq to allow a new record set to be created, but to prevent updating an existing record set. Other values -will be ignored. -.IP \(bu 2 -\fBetag\fP \-\- The etag of the record set. \fI\%Etags\fP are -used to handle concurrent changes to the same resource safely. -.IP \(bu 2 -\fBmetadata\fP \-\- A dictionary of strings can be passed as tag metadata to the record set object. -.IP \(bu 2 -\fBttl\fP \-\- The TTL (time\-to\-live) of the records in the record set. Required when specifying record information. -.IP \(bu 2 -\fBarecords\fP \-\- The list of A records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBaaaa_records\fP \-\- The list of AAAA records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBmx_records\fP \-\- The list of MX records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBns_records\fP \-\- The list of NS records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBptr_records\fP \-\- The list of PTR records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBsrv_records\fP \-\- The list of SRV records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBtxt_records\fP \-\- The list of TXT records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBcname_record\fP \-\- The CNAME record in the record set. View the -\fI\%Azure SDK documentation\fP -to create a dictionary representing the record object. -.IP \(bu 2 -\fBsoa_record\fP \-\- The SOA record in the record set. View the -\fI\%Azure SDK documentation\fP -to create a dictionary representing the record object. -.IP \(bu 2 -\fBcaa_records\fP \-\- The list of CAA records in the record set. View the -\fI\%Azure SDK documentation\fP -to create a list of dictionaries representing the record objects. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure record set exists: - azurearm_dns.record_set_present: - \- name: web - \- zone_name: contoso.com - \- resource_group: my_rg - \- record_type: A - \- ttl: 300 - \- arecords: - \- ipv4_address: 10.0.0.1 - \- metadata: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_dns.zone_absent(name, resource_group, connection_auth=None) -New in version 3000. - -.sp -Ensure a DNS zone does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the DNS zone. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the DNS zone. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_dns.zone_present(name, resource_group, etag=None, if_match=None, if_none_match=None, registration_virtual_networks=None, resolution_virtual_networks=None, tags=None, zone_type=\(aqPublic\(aq, connection_auth=None, **kwargs) -New in version 3000. - -.sp -Ensure a DNS zone exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the DNS zone (without a terminating dot). -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the DNS zone. -.IP \(bu 2 -\fBetag\fP \-\- The etag of the zone. \fI\%Etags\fP are used -to handle concurrent changes to the same resource safely. -.IP \(bu 2 -\fBif_match\fP \-\- The etag of the DNS zone. Omit this value to always overwrite the current zone. Specify the last\-seen etag -value to prevent accidentally overwritting any concurrent changes. -.IP \(bu 2 -\fBif_none_match\fP \-\- Set to \(aq*\(aq to allow a new DNS zone to be created, but to prevent updating an existing zone. Other values will -be ignored. -.IP \(bu 2 -\fBregistration_virtual_networks\fP \-\- -.sp -A list of references to virtual networks that register hostnames in this DNS zone. This is only when zone_type -is Private. (requires \fI\%azure\-mgmt\-dns\fP >= 2.0.0rc1) - -.IP \(bu 2 -\fBresolution_virtual_networks\fP \-\- -.sp -A list of references to virtual networks that resolve records in this DNS zone. This is only when zone_type is -Private. (requires \fI\%azure\-mgmt\-dns\fP >= 2.0.0rc1) - -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the DNS zone object. -.IP \(bu 2 -\fBzone_type\fP \-\- .INDENT 2.0 -.TP -.B The type of this DNS zone (Public or Private). Possible values include: \(aqPublic\(aq, \(aqPrivate\(aq. Default value: \(aqPublic\(aq -(requires \fI\%azure\-mgmt\-dns\fP >= 2.0.0rc1) -.UNINDENT - -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure DNS zone exists: - azurearm_dns.zone_present: - \- name: contoso.com - \- resource_group: my_rg - \- zone_type: Private - \- registration_virtual_networks: - \- /subscriptions/{{ sub }}/resourceGroups/my_rg/providers/Microsoft.Network/virtualNetworks/test_vnet - \- tags: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.states.azurearm_network -.sp -Azure (ARM) Network State Module -.sp -New in version 2019.2.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as a dictionary of -keyword arguments to the \fBconnection_auth\fP parameter in order to work properly. Since the authentication -parameters are sensitive, it\(aqs recommended to pass them to the states via pillar. -.sp -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.INDENT 7.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.sp -Example Pillar for Azure Resource Manager authentication: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -azurearm: - user_pass_auth: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - username: fletch - password: 123pass - mysubscription: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - tenant: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - client_id: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - secret: XXXXXXXXXXXXXXXXXXXXXXXX - cloud_environment: AZURE_PUBLIC_CLOUD -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Example states using Azure Resource Manager authentication: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -{% set profile = salt[\(aqpillar.get\(aq](\(aqazurearm:mysubscription\(aq) %} -Ensure virtual network exists: - azurearm_network.virtual_network_present: - \- name: my_vnet - \- resource_group: my_rg - \- address_prefixes: - \- \(aq10.0.0.0/8\(aq - \- \(aq192.168.0.0/16\(aq - \- dns_servers: - \- \(aq8.8.8.8\(aq - \- tags: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - -Ensure virtual network is absent: - azurearm_network.virtual_network_absent: - \- name: other_vnet - \- resource_group: my_rg - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.load_balancer_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a load balancer does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the load balancer. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the load balancer. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.load_balancer_present(name, resource_group, sku=None, frontend_ip_configurations=None, backend_address_pools=None, load_balancing_rules=None, probes=None, inbound_nat_rules=None, inbound_nat_pools=None, outbound_nat_rules=None, tags=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a load balancer exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the load balancer. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the load balancer. -.IP \(bu 2 -\fBsku\fP \-\- The load balancer SKU, which can be \(aqBasic\(aq or \(aqStandard\(aq. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the load balancer object. -.IP \(bu 2 -\fBfrontend_ip_configurations\fP \-\- -.sp -An optional list of dictionaries representing valid FrontendIPConfiguration objects. A frontend IP -configuration can be either private (using private IP address and subnet parameters) or public (using a -reference to a public IP address object). Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBname\fP: The name of the resource that is unique within a resource group. -.IP \(bu 2 -\fBprivate_ip_address\fP: The private IP address of the IP configuration. Required if -\(aqprivate_ip_allocation_method\(aq is \(aqStatic\(aq. -.IP \(bu 2 -\fBprivate_ip_allocation_method\fP: The Private IP allocation method. Possible values are: \(aqStatic\(aq and -\(aqDynamic\(aq. -.IP \(bu 2 -\fBsubnet\fP: Name of an existing subnet inside of which the frontend IP will reside. -.IP \(bu 2 -\fBpublic_ip_address\fP: Name of an existing public IP address which will be assigned to the frontend IP object. -.UNINDENT - -.IP \(bu 2 -\fBbackend_address_pools\fP \-\- An optional list of dictionaries representing valid BackendAddressPool objects. Only the \(aqname\(aq parameter is -valid for a BackendAddressPool dictionary. All other parameters are read\-only references from other objects -linking to the backend address pool. Inbound traffic is randomly load balanced across IPs in the backend IPs. -.IP \(bu 2 -\fBprobes\fP \-\- -.sp -An optional list of dictionaries representing valid Probe objects. Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBname\fP: The name of the resource that is unique within a resource group. -.IP \(bu 2 -\fBprotocol\fP: The protocol of the endpoint. Possible values are \(aqHttp\(aq or \(aqTcp\(aq. If \(aqTcp\(aq is specified, a -received ACK is required for the probe to be successful. If \(aqHttp\(aq is specified, a 200 OK response from the -specified URI is required for the probe to be successful. -.IP \(bu 2 -\fBport\fP: The port for communicating the probe. Possible values range from 1 to 65535, inclusive. -.IP \(bu 2 -\fBinterval_in_seconds\fP: The interval, in seconds, for how frequently to probe the endpoint for health status. -Typically, the interval is slightly less than half the allocated timeout period (in seconds) which allows two -full probes before taking the instance out of rotation. The default value is 15, the minimum value is 5. -.IP \(bu 2 -\fBnumber_of_probes\fP: The number of probes where if no response, will result in stopping further traffic from -being delivered to the endpoint. This values allows endpoints to be taken out of rotation faster or slower -than the typical times used in Azure. -.IP \(bu 2 -\fBrequest_path\fP: The URI used for requesting health status from the VM. Path is required if a protocol is -set to \(aqHttp\(aq. Otherwise, it is not allowed. There is no default value. -.UNINDENT - -.IP \(bu 2 -\fBload_balancing_rules\fP \-\- -.sp -An optional list of dictionaries representing valid LoadBalancingRule objects. Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBname\fP: The name of the resource that is unique within a resource group. -.IP \(bu 2 -\fBload_distribution\fP: The load distribution policy for this rule. Possible values are \(aqDefault\(aq, \(aqSourceIP\(aq, -and \(aqSourceIPProtocol\(aq. -.IP \(bu 2 -\fBfrontend_port\fP: The port for the external endpoint. Port numbers for each rule must be unique within the -Load Balancer. Acceptable values are between 0 and 65534. Note that value 0 enables \(aqAny Port\(aq. -.IP \(bu 2 -\fBbackend_port\fP: The port used for internal connections on the endpoint. Acceptable values are between 0 and -65535. Note that value 0 enables \(aqAny Port\(aq. -.IP \(bu 2 -\fBidle_timeout_in_minutes\fP: The timeout for the TCP idle connection. The value can be set between 4 and 30 -minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP. -.IP \(bu 2 -\fBenable_floating_ip\fP: Configures a virtual machine\(aqs endpoint for the floating IP capability required -to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn -Availability Groups in SQL server. This setting can\(aqt be changed after you create the endpoint. -.IP \(bu 2 -\fBdisable_outbound_snat\fP: Configures SNAT for the VMs in the backend pool to use the public IP address -specified in the frontend of the load balancing rule. -.IP \(bu 2 -\fBfrontend_ip_configuration\fP: Name of the frontend IP configuration object used by the load balancing rule -object. -.IP \(bu 2 -\fBbackend_address_pool\fP: Name of the backend address pool object used by the load balancing rule object. -Inbound traffic is randomly load balanced across IPs in the backend IPs. -.IP \(bu 2 -\fBprobe\fP: Name of the probe object used by the load balancing rule object. -.UNINDENT - -.IP \(bu 2 -\fBinbound_nat_rules\fP \-\- -.sp -An optional list of dictionaries representing valid InboundNatRule objects. Defining inbound NAT rules on your -load balancer is mutually exclusive with defining an inbound NAT pool. Inbound NAT pools are referenced from -virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an -Inbound NAT pool. They have to reference individual inbound NAT rules. Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBname\fP: The name of the resource that is unique within a resource group. -.IP \(bu 2 -\fBfrontend_ip_configuration\fP: Name of the frontend IP configuration object used by the inbound NAT rule -object. -.IP \(bu 2 -\fBprotocol\fP: Possible values include \(aqUdp\(aq, \(aqTcp\(aq, or \(aqAll\(aq. -.IP \(bu 2 -\fBfrontend_port\fP: The port for the external endpoint. Port numbers for each rule must be unique within the -Load Balancer. Acceptable values range from 1 to 65534. -.IP \(bu 2 -\fBbackend_port\fP: The port used for the internal endpoint. Acceptable values range from 1 to 65535. -.IP \(bu 2 -\fBidle_timeout_in_minutes\fP: The timeout for the TCP idle connection. The value can be set between 4 and 30 -minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP. -.IP \(bu 2 -\fBenable_floating_ip\fP: Configures a virtual machine\(aqs endpoint for the floating IP capability required -to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn -Availability Groups in SQL server. This setting can\(aqt be changed after you create the endpoint. -.UNINDENT - -.IP \(bu 2 -\fBinbound_nat_pools\fP \-\- -.sp -An optional list of dictionaries representing valid InboundNatPool objects. They define an external port range -for inbound NAT to a single backend port on NICs associated with a load balancer. Inbound NAT rules are created -automatically for each NIC associated with the Load Balancer using an external port from this range. Defining an -Inbound NAT pool on your Load Balancer is mutually exclusive with defining inbound NAT rules. Inbound NAT pools -are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot -reference an inbound NAT pool. They have to reference individual inbound NAT rules. Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBname\fP: The name of the resource that is unique within a resource group. -.IP \(bu 2 -\fBfrontend_ip_configuration\fP: Name of the frontend IP configuration object used by the inbound NAT pool -object. -.IP \(bu 2 -\fBprotocol\fP: Possible values include \(aqUdp\(aq, \(aqTcp\(aq, or \(aqAll\(aq. -.IP \(bu 2 -\fBfrontend_port_range_start\fP: The first port number in the range of external ports that will be used to -provide Inbound NAT to NICs associated with a load balancer. Acceptable values range between 1 and 65534. -.IP \(bu 2 -\fBfrontend_port_range_end\fP: The last port number in the range of external ports that will be used to -provide Inbound NAT to NICs associated with a load balancer. Acceptable values range between 1 and 65535. -.IP \(bu 2 -\fBbackend_port\fP: The port used for internal connections to the endpoint. Acceptable values are between 1 and -65535. -.UNINDENT - -.IP \(bu 2 -\fBoutbound_nat_rules\fP \-\- -.sp -An optional list of dictionaries representing valid OutboundNatRule objects. Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBname\fP: The name of the resource that is unique within a resource group. -.IP \(bu 2 -\fBfrontend_ip_configuration\fP: Name of the frontend IP configuration object used by the outbound NAT rule -object. -.IP \(bu 2 -\fBbackend_address_pool\fP: Name of the backend address pool object used by the outbound NAT rule object. -Outbound traffic is randomly load balanced across IPs in the backend IPs. -.IP \(bu 2 -\fBallocated_outbound_ports\fP: The number of outbound ports to be used for NAT. -.UNINDENT - -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure load balancer exists: - azurearm_network.load_balancer_present: - \- name: lb1 - \- resource_group: group1 - \- location: eastus - \- frontend_ip_configurations: - \- name: lb1_feip1 - public_ip_address: pub_ip1 - \- backend_address_pools: - \- name: lb1_bepool1 - \- probes: - \- name: lb1_webprobe1 - protocol: tcp - port: 80 - interval_in_seconds: 5 - number_of_probes: 2 - \- load_balancing_rules: - \- name: lb1_webprobe1 - protocol: tcp - frontend_port: 80 - backend_port: 80 - idle_timeout_in_minutes: 4 - frontend_ip_configuration: lb1_feip1 - backend_address_pool: lb1_bepool1 - probe: lb1_webprobe1 - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - \- require: - \- azurearm_resource: Ensure resource group exists - \- azurearm_network: Ensure public IP exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.network_interface_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a network interface does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the network interface. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the network interface. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.network_interface_present(name, ip_configurations, subnet, virtual_network, resource_group, tags=None, virtual_machine=None, network_security_group=None, dns_settings=None, mac_address=None, primary=None, enable_accelerated_networking=None, enable_ip_forwarding=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a network interface exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the network interface. -.IP \(bu 2 -\fBip_configurations\fP \-\- A list of dictionaries representing valid NetworkInterfaceIPConfiguration objects. The \(aqname\(aq key is required at -minimum. At least one IP Configuration must be present. -.IP \(bu 2 -\fBsubnet\fP \-\- Name of the existing subnet assigned to the network interface. -.IP \(bu 2 -\fBvirtual_network\fP \-\- Name of the existing virtual network containing the subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the virtual network. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the network interface object. -.IP \(bu 2 -\fBnetwork_security_group\fP \-\- The name of the existing network security group to assign to the network interface. -.IP \(bu 2 -\fBvirtual_machine\fP \-\- The name of the existing virtual machine to assign to the network interface. -.IP \(bu 2 -\fBdns_settings\fP \-\- -.sp -An optional dictionary representing a valid NetworkInterfaceDnsSettings object. Valid parameters are: -.INDENT 2.0 -.IP \(bu 2 -\fBdns_servers\fP: List of DNS server IP addresses. Use \(aqAzureProvidedDNS\(aq to switch to Azure provided DNS -resolution. \(aqAzureProvidedDNS\(aq value cannot be combined with other IPs, it must be the only value in -dns_servers collection. -.IP \(bu 2 -\fBinternal_dns_name_label\fP: Relative DNS name for this NIC used for internal communications between VMs in -the same virtual network. -.IP \(bu 2 -\fBinternal_fqdn\fP: Fully qualified DNS name supporting internal communications between VMs in the same virtual -network. -.IP \(bu 2 -\fBinternal_domain_name_suffix\fP: Even if internal_dns_name_label is not specified, a DNS entry is created for -the primary NIC of the VM. This DNS name can be constructed by concatenating the VM name with the value of -internal_domain_name_suffix. -.UNINDENT - -.IP \(bu 2 -\fBmac_address\fP \-\- Optional string containing the MAC address of the network interface. -.IP \(bu 2 -\fBprimary\fP \-\- Optional boolean allowing the interface to be set as the primary network interface on a virtual machine -with multiple interfaces attached. -.IP \(bu 2 -\fBenable_accelerated_networking\fP \-\- Optional boolean indicating whether accelerated networking should be enabled for the interface. -.IP \(bu 2 -\fBenable_ip_forwarding\fP \-\- Optional boolean indicating whether IP forwarding should be enabled for the interface. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure network interface exists: - azurearm_network.network_interface_present: - \- name: iface1 - \- subnet: vnet1_sn1 - \- virtual_network: vnet1 - \- resource_group: group1 - \- ip_configurations: - \- name: iface1_ipc1 - public_ip_address: pub_ip2 - \- dns_settings: - internal_dns_name_label: decisionlab\-int\-test\-label - \- primary: True - \- enable_accelerated_networking: True - \- enable_ip_forwarding: False - \- network_security_group: nsg1 - \- connection_auth: {{ profile }} - \- require: - \- azurearm_network: Ensure subnet exists - \- azurearm_network: Ensure network security group exists - \- azurearm_network: Ensure another public IP exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.network_security_group_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a network security group does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the network security group. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the network security group. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.network_security_group_present(name, resource_group, tags=None, security_rules=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a network security group exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the network security group. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the network security group. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the network security group object. -.IP \(bu 2 -\fBsecurity_rules\fP \-\- An optional list of dictionaries representing valid SecurityRule objects. See the -documentation for the security_rule_present state or security_rule_create_or_update execution module -for more information on required and optional parameters for security rules. The rules are only -managed if this parameter is present. When this parameter is absent, implemented rules will not be removed, -and will merely become unmanaged. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure network security group exists: - azurearm_network.network_security_group_present: - \- name: nsg1 - \- resource_group: group1 - \- security_rules: - \- name: nsg1_rule1 - priority: 100 - protocol: tcp - access: allow - direction: outbound - source_address_prefix: virtualnetwork - destination_address_prefix: internet - source_port_range: \(aq*\(aq - destination_port_range: \(aq*\(aq - \- name: nsg1_rule2 - priority: 101 - protocol: tcp - access: allow - direction: inbound - source_address_prefix: internet - destination_address_prefix: virtualnetwork - source_port_range: \(aq*\(aq - destination_port_ranges: - \- \(aq80\(aq - \- \(aq443\(aq - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - \- require: - \- azurearm_resource: Ensure resource group exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.public_ip_address_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a public IP address does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the public IP address. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the public IP address. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.public_ip_address_present(name, resource_group, tags=None, sku=None, public_ip_allocation_method=None, public_ip_address_version=None, dns_settings=None, idle_timeout_in_minutes=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a public IP address exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the public IP address. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the public IP address. -.IP \(bu 2 -\fBdns_settings\fP \-\- An optional dictionary representing a valid PublicIPAddressDnsSettings object. Parameters include -\(aqdomain_name_label\(aq and \(aqreverse_fqdn\(aq, which accept strings. The \(aqdomain_name_label\(aq parameter is concatenated -with the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. -If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS -system. The \(aqreverse_fqdn\(aq parameter is a user\-visible, fully qualified domain name that resolves to this public -IP address. If the reverse FQDN is specified, then a PTR DNS record is created pointing from the IP address in -the in\-addr.arpa domain to the reverse FQDN. -.IP \(bu 2 -\fBsku\fP \-\- The public IP address SKU, which can be \(aqBasic\(aq or \(aqStandard\(aq. -.IP \(bu 2 -\fBpublic_ip_allocation_method\fP \-\- The public IP allocation method. Possible values are: \(aqStatic\(aq and \(aqDynamic\(aq. -.IP \(bu 2 -\fBpublic_ip_address_version\fP \-\- The public IP address version. Possible values are: \(aqIPv4\(aq and \(aqIPv6\(aq. -.IP \(bu 2 -\fBidle_timeout_in_minutes\fP \-\- An integer representing the idle timeout of the public IP address. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the public IP address object. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure public IP exists: - azurearm_network.public_ip_address_present: - \- name: pub_ip1 - \- resource_group: group1 - \- dns_settings: - domain_name_label: decisionlab\-ext\-test\-label - \- sku: basic - \- public_ip_allocation_method: static - \- public_ip_address_version: ipv4 - \- idle_timeout_in_minutes: 4 - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - \- require: - \- azurearm_resource: Ensure resource group exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.route_absent(name, route_table, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a route table does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the route table. -.IP \(bu 2 -\fBroute_table\fP \-\- The name of the existing route table containing the route. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the route table. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.route_present(name, address_prefix, next_hop_type, route_table, resource_group, next_hop_ip_address=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a route exists within a route table. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the route. -.IP \(bu 2 -\fBaddress_prefix\fP \-\- The destination CIDR to which the route applies. -.IP \(bu 2 -\fBnext_hop_type\fP \-\- The type of Azure hop the packet should be sent to. Possible values are: \(aqVirtualNetworkGateway\(aq, \(aqVnetLocal\(aq, -\(aqInternet\(aq, \(aqVirtualAppliance\(aq, and \(aqNone\(aq. -.IP \(bu 2 -\fBnext_hop_ip_address\fP \-\- The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop -type is \(aqVirtualAppliance\(aq. -.IP \(bu 2 -\fBroute_table\fP \-\- The name of the existing route table which will contain the route. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the route table. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure route exists: - azurearm_network.route_present: - \- name: rt1_route2 - \- route_table: rt1 - \- resource_group: group1 - \- address_prefix: \(aq192.168.0.0/16\(aq - \- next_hop_type: vnetlocal - \- connection_auth: {{ profile }} - \- require: - \- azurearm_network: Ensure route table exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.route_table_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a route table does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the route table. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the route table. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.route_table_present(name, resource_group, tags=None, routes=None, disable_bgp_route_propagation=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a route table exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the route table. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the route table. -.IP \(bu 2 -\fBroutes\fP \-\- An optional list of dictionaries representing valid Route objects contained within a route table. See the -documentation for the route_present state or route_create_or_update execution module for more information on -required and optional parameters for routes. The routes are only managed if this parameter is present. When this -parameter is absent, implemented routes will not be removed, and will merely become unmanaged. -.IP \(bu 2 -\fBdisable_bgp_route_propagation\fP \-\- An optional boolean parameter setting whether to disable the routes learned by BGP on the route table. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the route table object. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure route table exists: - azurearm_network.route_table_present: - \- name: rt1 - \- resource_group: group1 - \- routes: - \- name: rt1_route1 - address_prefix: \(aq0.0.0.0/0\(aq - next_hop_type: internet - \- name: rt1_route2 - address_prefix: \(aq192.168.0.0/16\(aq - next_hop_type: vnetlocal - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - \- require: - \- azurearm_resource: Ensure resource group exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.security_rule_absent(name, security_group, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a security rule does not exist in the network security group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the security rule. -.IP \(bu 2 -\fBsecurity_group\fP \-\- The network security group containing the security rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the network security group. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.security_rule_present(name, access, direction, priority, protocol, security_group, resource_group, destination_address_prefix=None, destination_port_range=None, source_address_prefix=None, source_port_range=None, description=None, destination_address_prefixes=None, destination_port_ranges=None, source_address_prefixes=None, source_port_ranges=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a security rule exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the security rule. -.IP \(bu 2 -\fBaccess\fP \-\- \(aqallow\(aq or \(aqdeny\(aq -.IP \(bu 2 -\fBdirection\fP \-\- \(aqinbound\(aq or \(aqoutbound\(aq -.IP \(bu 2 -\fBpriority\fP \-\- Integer between 100 and 4096 used for ordering rule application. -.IP \(bu 2 -\fBprotocol\fP \-\- \(aqtcp\(aq, \(aqudp\(aq, or \(aq*\(aq -.IP \(bu 2 -\fBsecurity_group\fP \-\- The name of the existing network security group to contain the security rule. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the network security group. -.IP \(bu 2 -\fBdescription\fP \-\- Optional description of the security rule. -.IP \(bu 2 -\fBdestination_address_prefix\fP \-\- The CIDR or destination IP range. Asterix \(aq*\(aq can also be used to match all destination IPs. -Default tags such as \(aqVirtualNetwork\(aq, \(aqAzureLoadBalancer\(aq and \(aqInternet\(aq can also be used. -If this is an ingress rule, specifies where network traffic originates from. -.IP \(bu 2 -\fBdestination_port_range\fP \-\- The destination port or range. Integer or range between 0 and 65535. Asterix \(aq*\(aq -can also be used to match all ports. -.IP \(bu 2 -\fBsource_address_prefix\fP \-\- The CIDR or source IP range. Asterix \(aq*\(aq can also be used to match all source IPs. -Default tags such as \(aqVirtualNetwork\(aq, \(aqAzureLoadBalancer\(aq and \(aqInternet\(aq can also be used. -If this is an ingress rule, specifies where network traffic originates from. -.IP \(bu 2 -\fBsource_port_range\fP \-\- The source port or range. Integer or range between 0 and 65535. Asterix \(aq*\(aq -can also be used to match all ports. -.IP \(bu 2 -\fBdestination_address_prefixes\fP \-\- A list of destination_address_prefix values. This parameter overrides destination_address_prefix -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBdestination_port_ranges\fP \-\- A list of destination_port_range values. This parameter overrides destination_port_range -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBsource_address_prefixes\fP \-\- A list of source_address_prefix values. This parameter overrides source_address_prefix -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBsource_port_ranges\fP \-\- A list of source_port_range values. This parameter overrides source_port_range -and will cause any value entered there to be ignored. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure security rule exists: - azurearm_network.security_rule_present: - \- name: nsg1_rule2 - \- security_group: nsg1 - \- resource_group: group1 - \- priority: 101 - \- protocol: tcp - \- access: allow - \- direction: inbound - \- source_address_prefix: internet - \- destination_address_prefix: virtualnetwork - \- source_port_range: \(aq*\(aq - \- destination_port_ranges: - \- \(aq80\(aq - \- \(aq443\(aq - \- connection_auth: {{ profile }} - \- require: - \- azurearm_network: Ensure network security group exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.subnet_absent(name, virtual_network, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a virtual network does not exist in the virtual network. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the subnet. -.IP \(bu 2 -\fBvirtual_network\fP \-\- Name of the existing virtual network containing the subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the virtual network. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.subnet_present(name, address_prefix, virtual_network, resource_group, security_group=None, route_table=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a subnet exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the subnet. -.IP \(bu 2 -\fBaddress_prefix\fP \-\- A CIDR block used by the subnet within the virtual network. -.IP \(bu 2 -\fBvirtual_network\fP \-\- Name of the existing virtual network to contain the subnet. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the virtual network. -.IP \(bu 2 -\fBsecurity_group\fP \-\- The name of the existing network security group to assign to the subnet. -.IP \(bu 2 -\fBroute_table\fP \-\- The name of the existing route table to assign to the subnet. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure subnet exists: - azurearm_network.subnet_present: - \- name: vnet1_sn1 - \- virtual_network: vnet1 - \- resource_group: group1 - \- address_prefix: \(aq192.168.1.0/24\(aq - \- security_group: nsg1 - \- route_table: rt1 - \- connection_auth: {{ profile }} - \- require: - \- azurearm_network: Ensure virtual network exists - \- azurearm_network: Ensure network security group exists - \- azurearm_network: Ensure route table exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.virtual_network_absent(name, resource_group, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a virtual network does not exist in the resource group. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the virtual network. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the virtual network. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_network.virtual_network_present(name, address_prefixes, resource_group, dns_servers=None, tags=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a virtual network exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the virtual network. -.IP \(bu 2 -\fBresource_group\fP \-\- The resource group assigned to the virtual network. -.IP \(bu 2 -\fBaddress_prefixes\fP \-\- A list of CIDR blocks which can be used by subnets within the virtual network. -.IP \(bu 2 -\fBdns_servers\fP \-\- A list of DNS server addresses. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the virtual network object. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure virtual network exists: - azurearm_network.virtual_network_present: - \- name: vnet1 - \- resource_group: group1 - \- address_prefixes: - \- \(aq10.0.0.0/8\(aq - \- \(aq192.168.0.0/16\(aq - \- dns_servers: - \- \(aq8.8.8.8\(aq - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - \- require: - \- azurearm_resource: Ensure resource group exists -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.SS salt.states.azurearm_resource -.sp -Azure (ARM) Resource State Module -.sp -New in version 2019.2.0. - -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -This cloud provider will be removed from Salt in version 3007 in favor of -the \fI\%saltext.azurerm Salt Extension\fP -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B maintainer -<\fI\%devops@eitr.tech\fP> -.TP -.B maturity -new -.TP -.B depends -.INDENT 7.0 -.IP \(bu 2 -\fI\%azure\fP >= 2.0.0 -.IP \(bu 2 -\fI\%azure\-common\fP >= 1.1.8 -.IP \(bu 2 -\fI\%azure\-mgmt\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-compute\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-network\fP >= 1.7.1 -.IP \(bu 2 -\fI\%azure\-mgmt\-resource\fP >= 1.1.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-storage\fP >= 1.0.0 -.IP \(bu 2 -\fI\%azure\-mgmt\-web\fP >= 0.32.0 -.IP \(bu 2 -\fI\%azure\-storage\fP >= 0.34.3 -.IP \(bu 2 -\fI\%msrestazure\fP >= 0.4.21 -.UNINDENT -.TP -.B platform -linux -.TP -.B configuration -This module requires Azure Resource Manager credentials to be passed as a dictionary of -keyword arguments to the \fBconnection_auth\fP parameter in order to work properly. Since the authentication -parameters are sensitive, it\(aqs recommended to pass them to the states via pillar. -.sp -Required provider parameters: -.INDENT 7.0 -.TP -.B if using username and password: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBusername\fP -.IP \(bu 2 -\fBpassword\fP -.UNINDENT -.TP -.B if using a service principal: -.INDENT 7.0 -.IP \(bu 2 -\fBsubscription_id\fP -.IP \(bu 2 -\fBtenant\fP -.IP \(bu 2 -\fBclient_id\fP -.IP \(bu 2 -\fBsecret\fP -.UNINDENT -.UNINDENT -.sp -Optional provider parameters: -.INDENT 7.0 -.TP -\fBcloud_environment\fP: Used to point the cloud driver to different API endpoints, such as Azure GovCloud. Possible values: -.INDENT 7.0 -.IP \(bu 2 -\fBAZURE_PUBLIC_CLOUD\fP (default) -.IP \(bu 2 -\fBAZURE_CHINA_CLOUD\fP -.IP \(bu 2 -\fBAZURE_US_GOV_CLOUD\fP -.IP \(bu 2 -\fBAZURE_GERMAN_CLOUD\fP -.UNINDENT -.UNINDENT -.sp -Example Pillar for Azure Resource Manager authentication: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -azurearm: - user_pass_auth: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - username: fletch - password: 123pass - mysubscription: - subscription_id: 3287abc8\-f98a\-c678\-3bde\-326766fd3617 - tenant: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - client_id: ABCDEFAB\-1234\-ABCD\-1234\-ABCDEFABCDEF - secret: XXXXXXXXXXXXXXXXXXXXXXXX - cloud_environment: AZURE_PUBLIC_CLOUD -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -Example states using Azure Resource Manager authentication: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -{% set profile = salt[\(aqpillar.get\(aq](\(aqazurearm:mysubscription\(aq) %} -Ensure resource group exists: - azurearm_resource.resource_group_present: - \- name: my_rg - \- location: westus - \- tags: - how_awesome: very - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} - -Ensure resource group is absent: - azurearm_resource.resource_group_absent: - \- name: other_rg - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_resource.policy_assignment_absent(name, scope, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a policy assignment does not exist in the provided scope. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the policy assignment. -.IP \(bu 2 -\fBscope\fP \-\- The scope of the policy assignment. -.UNINDENT -.UNINDENT -.INDENT 7.0 -.TP -.B connection_auth -A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_resource.policy_assignment_present(name, scope, definition_name, display_name=None, description=None, assignment_type=None, parameters=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a security policy assignment exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the policy assignment. -.IP \(bu 2 -\fBscope\fP \-\- The scope of the policy assignment. -.IP \(bu 2 -\fBdefinition_name\fP \-\- The name of the policy definition to assign. -.IP \(bu 2 -\fBdisplay_name\fP \-\- The display name of the policy assignment. -.IP \(bu 2 -\fBdescription\fP \-\- The policy assignment description. -.IP \(bu 2 -\fBassignment_type\fP \-\- The type of policy assignment. -.IP \(bu 2 -\fBparameters\fP \-\- Required dictionary if a parameter is used in the policy rule. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure policy assignment exists: - azurearm_resource.policy_assignment_present: - \- name: testassign - \- scope: /subscriptions/bc75htn\-a0fhsi\-349b\-56gh\-4fghti\-f84852 - \- definition_name: testpolicy - \- display_name: Test Assignment - \- description: Test assignment for testing assignments. - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_resource.policy_definition_absent(name, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a policy definition does not exist in the current subscription. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the policy definition. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_resource.policy_definition_present(name, policy_rule=None, policy_type=None, mode=None, display_name=None, description=None, metadata=None, parameters=None, policy_rule_json=None, policy_rule_file=None, template=\(aqjinja\(aq, source_hash=None, source_hash_name=None, skip_verify=False, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a security policy definition exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the policy definition. -.IP \(bu 2 -\fBpolicy_rule\fP \-\- A YAML dictionary defining the policy rule. See \fI\%Azure Policy Definition documentation\fP for details on the -structure. One of \fBpolicy_rule\fP, \fBpolicy_rule_json\fP, or \fBpolicy_rule_file\fP is required, in that order of -precedence for use if multiple parameters are used. -.IP \(bu 2 -\fBpolicy_rule_json\fP \-\- -.sp -A text field defining the entirety of a policy definition in JSON. See \fI\%Azure Policy Definition documentation\fP for details on the -structure. One of \fBpolicy_rule\fP, \fBpolicy_rule_json\fP, or \fBpolicy_rule_file\fP is required, in that order of -precedence for use if multiple parameters are used. Note that the \fIname\fP field in the JSON will override the -\fBname\fP parameter in the state. - -.IP \(bu 2 -\fBpolicy_rule_file\fP \-\- -.sp -The source of a JSON file defining the entirety of a policy definition. See \fI\%Azure Policy Definition -documentation\fP for -details on the structure. One of \fBpolicy_rule\fP, \fBpolicy_rule_json\fP, or \fBpolicy_rule_file\fP is required, -in that order of precedence for use if multiple parameters are used. Note that the \fIname\fP field in the JSON -will override the \fBname\fP parameter in the state. - -.IP \(bu 2 -\fBskip_verify\fP \-\- Used for the \fBpolicy_rule_file\fP parameter. If \fBTrue\fP, hash verification of remote file sources -(\fBhttp://\fP, \fBhttps://\fP, \fBftp://\fP) will be skipped, and the \fBsource_hash\fP argument will be ignored. -.IP \(bu 2 -\fBsource_hash\fP \-\- This can be a source hash string or the URI of a file that contains source hash strings. -.IP \(bu 2 -\fBsource_hash_name\fP \-\- When \fBsource_hash\fP refers to a hash file, Salt will try to find the correct hash by matching the -filename/URI associated with that hash. -.IP \(bu 2 -\fBpolicy_type\fP \-\- The type of policy definition. Possible values are NotSpecified, BuiltIn, and Custom. Only used with the -\fBpolicy_rule\fP parameter. -.IP \(bu 2 -\fBmode\fP \-\- The policy definition mode. Possible values are NotSpecified, Indexed, and All. Only used with the -\fBpolicy_rule\fP parameter. -.IP \(bu 2 -\fBdisplay_name\fP \-\- The display name of the policy definition. Only used with the \fBpolicy_rule\fP parameter. -.IP \(bu 2 -\fBdescription\fP \-\- The policy definition description. Only used with the \fBpolicy_rule\fP parameter. -.IP \(bu 2 -\fBmetadata\fP \-\- The policy definition metadata defined as a dictionary. Only used with the \fBpolicy_rule\fP parameter. -.IP \(bu 2 -\fBparameters\fP \-\- Required dictionary if a parameter is used in the policy rule. Only used with the \fBpolicy_rule\fP parameter. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure policy definition exists: - azurearm_resource.policy_definition_present: - \- name: testpolicy - \- display_name: Test Policy - \- description: Test policy for testing policies. - \- policy_rule: - if: - allOf: - \- equals: Microsoft.Compute/virtualMachines/write - source: action - \- field: location - in: - \- eastus - \- eastus2 - \- centralus - then: - effect: deny - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_resource.resource_group_absent(name, connection_auth=None) -New in version 2019.2.0. - -.sp -Ensure a resource group does not exist in the current subscription. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the resource group. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.UNINDENT -.INDENT 0.0 -.TP -.B salt.states.azurearm_resource.resource_group_present(name, location, managed_by=None, tags=None, connection_auth=None, **kwargs) -New in version 2019.2.0. - -.sp -Ensure a resource group exists. -.INDENT 7.0 -.TP -.B Parameters -.INDENT 7.0 -.IP \(bu 2 -\fBname\fP \-\- Name of the resource group. -.IP \(bu 2 -\fBlocation\fP \-\- The Azure location in which to create the resource group. This value cannot be updated once -the resource group is created. -.IP \(bu 2 -\fBmanaged_by\fP \-\- The ID of the resource that manages this resource group. This value cannot be updated once -the resource group is created. -.IP \(bu 2 -\fBtags\fP \-\- A dictionary of strings can be passed as tag metadata to the resource group object. -.IP \(bu 2 -\fBconnection_auth\fP \-\- A dict with subscription and authentication parameters to be used in connecting to the -Azure Resource Manager API. -.UNINDENT -.UNINDENT -.sp -Example usage: -.INDENT 7.0 -.INDENT 3.5 -.sp -.nf -.ft C -Ensure resource group exists: - azurearm_resource.resource_group_present: - \- name: group1 - \- location: eastus - \- tags: - contact_name: Elmer Fudd Gantry - \- connection_auth: {{ profile }} -.ft P -.fi -.UNINDENT -.UNINDENT -.UNINDENT .SS salt.states.beacon .SS Management of the Salt beacons .sp @@ -403671,13 +395897,13 @@ mappedname: \- size=256 swap: - crypted.mapped: + cryptdev.mapped: \- device: /dev/sdx4 \- keyfile: /dev/urandom \- opts: swap,cipher=aes\-cbc\-essiv:sha256,size=256 mappedbyuuid: - crypted.mapped: + cryptdev.mapped: \- device: UUID=066e0200\-2867\-4ebe\-b9e6\-f30026ca2314 \- keyfile: /etc/keyfile.key \- config: /etc/alternate\-crypttab @@ -404869,6 +397095,14 @@ Set to \fITrue\fP to evaluate the free space instead. .UNINDENT .SS salt.states.docker_container .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Docker containers .sp New in version 2017.7.0. @@ -407368,6 +399602,14 @@ containers are absent. Set this to \fBFalse\fP to suppress that error. .UNINDENT .SS salt.states.docker_image .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Docker images .sp New in version 2017.7.0. @@ -407704,6 +399946,14 @@ Additional keyword arguments to pass to .UNINDENT .SS salt.states.docker_network .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Docker networks .sp New in version 2017.7.0. @@ -408352,6 +400602,14 @@ mynet: .UNINDENT .SS salt.states.docker_volume .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%docker Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Docker volumes .sp New in version 2017.7.0. @@ -411987,7 +404245,7 @@ text 4 .UNINDENT .INDENT 0.0 .TP -.B salt.states.file.cached(name, source_hash=\(aq\(aq, source_hash_name=None, skip_verify=False, saltenv=\(aqbase\(aq, use_etag=False) +.B salt.states.file.cached(name, source_hash=\(aq\(aq, source_hash_name=None, skip_verify=False, saltenv=\(aqbase\(aq, use_etag=False, source_hash_sig=None, signed_by_any=None, signed_by_all=None, keyring=None, gnupghome=None) New in version 2017.7.3. .sp @@ -412059,6 +404317,54 @@ the \fBsource_hash\fP parameter. .sp New in version 3005. +.TP +.B source_hash_sig +When \fBname\fP is a remote file source, \fBsource_hash\fP is a file, +\fBskip_verify\fP is not true and \fBuse_etag\fP is not true, ensure a +valid GPG signature exists on the source hash file. +Set this to \fBtrue\fP for an inline (clearsigned) signature, or to a +file URI retrievable by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature on the \fBsource_hash\fP file is enforced regardless of +changes since its contents are used to check if an existing file +is in the correct state \- but only for remote sources! +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B signed_by_any +When verifying \fBsource_hash_sig\fP, require at least one valid signature +from one of a list of key fingerprints. This is passed to +\fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +When verifying \fBsource_hash_sig\fP, require a valid signature from each +of the key fingerprints in this list. This is passed to +\fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B keyring +When verifying signatures, use this keyring. +.sp +New in version 3007.0. + +.TP +.B gnupghome +When verifying signatures, use this GnuPG home. +.sp +New in version 3007.0. + .UNINDENT .sp This state will in most cases not be useful in SLS files, but it is useful @@ -412808,7 +405114,7 @@ permissions for those directories. .UNINDENT .INDENT 0.0 .TP -.B salt.states.file.keyvalue(name, key=None, value=None, key_values=None, separator=\(aq=\(aq, append_if_not_found=False, prepend_if_not_found=False, search_only=False, show_changes=True, ignore_if_missing=False, count=1, uncomment=None, key_ignore_case=False, value_ignore_case=False) +.B salt.states.file.keyvalue(name, key=None, value=None, key_values=None, separator=\(aq=\(aq, append_if_not_found=False, prepend_if_not_found=False, search_only=False, show_changes=True, ignore_if_missing=False, count=1, uncomment=None, key_ignore_case=False, value_ignore_case=False, create_if_missing=False) Key/Value based editing of a file. .sp New in version 3001. @@ -412893,6 +405199,12 @@ key is kept as\-is. Values are checked case insensitively, trying to set e.g. \(aqYes\(aq while the current value is \(aqyes\(aq, will not result in changes when \fBvalue_ignore_case\fP is set to True. +.TP +.B create_if_missing +Create the file if the destination file is not found. +.sp +New in version 3007.0. + .UNINDENT .sp An example of using \fBfile.keyvalue\fP to ensure sshd does not allow @@ -413357,7 +405669,7 @@ line present to be present in between \fBbefore\fP and \fBafter\fP\&. .UNINDENT .INDENT 0.0 .TP -.B salt.states.file.managed(name, source=None, source_hash=\(aq\(aq, source_hash_name=None, keep_source=True, user=None, group=None, mode=None, attrs=None, template=None, makedirs=False, dir_mode=None, context=None, replace=True, defaults=None, backup=\(aq\(aq, show_changes=True, create=True, contents=None, tmp_dir=\(aq\(aq, tmp_ext=\(aq\(aq, contents_pillar=None, contents_grains=None, contents_newline=True, contents_delimiter=\(aq:\(aq, encoding=None, encoding_errors=\(aqstrict\(aq, allow_empty=True, follow_symlinks=True, check_cmd=None, skip_verify=False, selinux=None, win_owner=None, win_perms=None, win_deny_perms=None, win_inheritance=True, win_perms_reset=False, verify_ssl=True, use_etag=False, **kwargs) +.B salt.states.file.managed(name, source=None, source_hash=\(aq\(aq, source_hash_name=None, keep_source=True, user=None, group=None, mode=None, attrs=None, template=None, makedirs=False, dir_mode=None, context=None, replace=True, defaults=None, backup=\(aq\(aq, show_changes=True, create=True, contents=None, tmp_dir=\(aq\(aq, tmp_ext=\(aq\(aq, contents_pillar=None, contents_grains=None, contents_newline=True, contents_delimiter=\(aq:\(aq, encoding=None, encoding_errors=\(aqstrict\(aq, allow_empty=True, follow_symlinks=True, check_cmd=None, skip_verify=False, selinux=None, win_owner=None, win_perms=None, win_deny_perms=None, win_inheritance=True, win_perms_reset=False, verify_ssl=True, use_etag=False, signature=None, source_hash_sig=None, signed_by_any=None, signed_by_all=None, keyring=None, gnupghome=None, **kwargs) Manage a given file, this function allows for a file to be downloaded from the salt master and potentially run through a templating system. .INDENT 7.0 @@ -413830,6 +406142,17 @@ be used instead. However, this will not work for binary files in Salt releases before 2015.8.4. .UNINDENT .UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +For information on using Salt Slots and how to incorporate +execution module returns into file content or data, refer to the +\fI\%Salt Slots documentation\fP\&. +.UNINDENT +.UNINDENT +.INDENT 7.0 .TP .B contents_grains New in version 2014.7.0. @@ -414129,6 +406452,80 @@ the \fBsource_hash\fP parameter. .sp New in version 3005. +.TP +.B signature +Ensure a valid GPG signature exists on the selected \fBsource\fP file. +Set this to true for inline signatures, or to a file URI retrievable +by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature is only enforced directly after caching the file, +before it is moved to its final destination. Existing target files +(with the correct checksum) will neither be checked nor deleted. +.sp +It will be enforced regardless of source type and will be +required on the final output, therefore this does not lend itself +well when templates are rendered. +The file will not be modified, meaning inline signatures are not +removed. +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B source_hash_sig +When \fBsource\fP is a remote file source, \fBsource_hash\fP is a file, +\fBskip_verify\fP is not true and \fBuse_etag\fP is not true, ensure a +valid GPG signature exists on the source hash file. +Set this to \fBtrue\fP for an inline (clearsigned) signature, or to a +file URI retrievable by \fI:py:func:\(gacp.cache_file \fP +for a detached one. +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +A signature on the \fBsource_hash\fP file is enforced regardless of +changes since its contents are used to check if an existing file +is in the correct state \- but only for remote sources! +As for \fBsignature\fP, existing target files will not be modified, +only the cached source_hash and source_hash_sig files will be removed. +.UNINDENT +.UNINDENT +.sp +New in version 3007.0. + +.TP +.B signed_by_any +When verifying signatures either on the managed file or its source hash file, +require at least one valid signature from one of a list of key fingerprints. +This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B signed_by_all +When verifying signatures either on the managed file or its source hash file, +require a valid signature from each of the key fingerprints in this list. +This is passed to \fI\%gpg.verify\fP\&. +.sp +New in version 3007.0. + +.TP +.B keyring +When verifying signatures, use this keyring. +.sp +New in version 3007.0. + +.TP +.B gnupghome +When verifying signatures, use this GnuPG home. +.sp +New in version 3007.0. + .UNINDENT .UNINDENT .INDENT 0.0 @@ -414240,8 +406637,8 @@ state argument for supported state functions. It should not be called directly. .B salt.states.file.mod_run_check_cmd(cmd, filename, **check_cmd_opts) Execute the check_cmd logic. .sp -Return a result dict if \fBcheck_cmd\fP succeeds (check_cmd == 0) -otherwise return True +Return True if \fBcheck_cmd\fP succeeds (check_cmd == 0) +otherwise return a result dict .UNINDENT .INDENT 0.0 .TP @@ -414438,10 +406835,10 @@ may specify a single line of text or a list of lines to append. .INDENT 7.0 .TP .B name -The location of the file to append to. +The location of the file to prepend to. .TP .B text -The text to be appended, which can be a single string or a list +The text to be prepended, which can be a single string or a list of strings. .TP .B makedirs @@ -414451,7 +406848,7 @@ the parent directories will be created to facilitate the creation of the named file. Defaults to False. .TP .B source -A single source file to append. This source file can be hosted on either +A single source file to prepend. This source file can be hosted on either the salt master server, or on an HTTP or FTP server. Both HTTPS and HTTP are supported as well as downloading directly from Amazon S3 compatible URLs with both pre\-configured and automatic IAM credentials @@ -414502,7 +406899,7 @@ md5 32 See the \fBsource_hash\fP parameter description for \fI\%file.managed\fP function for more details and examples. .TP .B template -The named templating engine will be used to render the appended\-to file. +The named templating engine will be used to render the source file(s). Defaults to \fBjinja\fP\&. The following templates are supported: .INDENT 7.0 .IP \(bu 2 @@ -414520,7 +406917,7 @@ Defaults to \fBjinja\fP\&. The following templates are supported: .UNINDENT .TP .B sources -A list of source files to append. If the files are hosted on an HTTP or +A list of source files to prepend. If the files are hosted on an HTTP or FTP server, the source_hashes argument is also required. .TP .B source_hashes @@ -414540,6 +406937,10 @@ New in version 2015.8.4. Spaces and Tabs in text are ignored by default, when searching for the appending content, one space or multiple tabs are the same for salt. Set this option to \fBFalse\fP if you want to change this behavior. +.TP +.B header +Forces the text to be prepended. If it exists in the file but not at +the beginning, then it prepends a duplicate. .UNINDENT .sp Multi\-line example: @@ -415192,7 +407593,7 @@ Usage example: .UNINDENT .INDENT 0.0 .TP -.B salt.states.file.serialize(name, dataset=None, dataset_pillar=None, user=None, group=None, mode=None, backup=\(aq\(aq, makedirs=False, show_changes=True, create=True, merge_if_exists=False, encoding=None, encoding_errors=\(aqstrict\(aq, serializer=None, serializer_opts=None, deserializer_opts=None, **kwargs) +.B salt.states.file.serialize(name, dataset=None, dataset_pillar=None, user=None, group=None, mode=None, backup=\(aq\(aq, makedirs=False, show_changes=True, create=True, merge_if_exists=False, encoding=None, encoding_errors=\(aqstrict\(aq, serializer=None, serializer_opts=None, deserializer_opts=None, check_cmd=None, tmp_dir=\(aq\(aq, tmp_ext=\(aq\(aq, **kwargs) Serializes dataset and store it into managed file. Useful for sharing simple configuration files. .INDENT 7.0 @@ -415212,6 +407613,17 @@ causing indentation mismatches. .sp New in version 2015.8.0. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +For information on using Salt Slots and how to incorporate +execution module returns into file content or data, refer to the +\fI\%Salt Slots documentation\fP\&. +.UNINDENT +.UNINDENT +.INDENT 7.0 .TP .B serializer (or formatter) Write the data as this format. See the list of @@ -415362,6 +407774,61 @@ which accept a callable object cannot be handled in an SLS file. .sp New in version 2019.2.0. +.TP +.B check_cmd +The specified command will be run with an appended argument of a +\fItemporary\fP file containing the new file contents. If the command +exits with a zero status the new file contents will be written to +the state output destination. If the command exits with a nonzero exit +code, the state will fail and no changes will be made to the file. +.sp +For example, the following could be used to verify sudoers before making +changes: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +/etc/consul.d/my_config.json: + file.serialize: + \- dataset: + datacenter: \(dqeast\-aws\(dq + data_dir: \(dq/opt/consul\(dq + log_level: \(dqINFO\(dq + node_name: \(dqfoobar\(dq + server: true + watches: + \- type: checks + handler: \(dq/usr/bin/health\-check\-handler.sh\(dq + telemetry: + statsite_address: \(dq127.0.0.1:2180\(dq + \- serializer: json + \- check_cmd: consul validate +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBNOTE\fP: This \fBcheck_cmd\fP functions differently than the requisite +\fBcheck_cmd\fP\&. +.sp +New in version 3007.0. + +.TP +.B tmp_dir +Directory for temp file created by \fBcheck_cmd\fP\&. Useful for checkers +dependent on config file location (e.g. daemons restricted to their +own config directories by an apparmor profile). +.sp +New in version 3007.0. + +.TP +.B tmp_ext +Suffix for temp file created by \fBcheck_cmd\fP\&. Useful for checkers +dependent on config file extension. +.sp +New in version 3007.0. + .UNINDENT .sp For example, this state: @@ -415467,7 +407934,7 @@ process. For existing files and directories it\(aqs not enforced. .UNINDENT .INDENT 0.0 .TP -.B salt.states.file.symlink(name, target, force=False, backupname=None, makedirs=False, user=None, group=None, mode=None, win_owner=None, win_perms=None, win_deny_perms=None, win_inheritance=None, atomic=False, disallow_copy_and_unlink=False, inherit_user_and_group=False, **kwargs) +.B salt.states.file.symlink(name, target, force=False, backupname=None, makedirs=False, user=None, group=None, mode=None, win_owner=None, win_perms=None, win_deny_perms=None, win_inheritance=None, atomic=False, disallow_copy_and_unlink=False, inherit_user_and_group=False, follow_symlinks=True, **kwargs) Create a symbolic link (symlink, soft link) .sp If the file already exists and is a symlink pointing to any location other @@ -415578,6 +408045,14 @@ override this behavior. .sp New in version 3006.0. +.TP +.B follow_symlinks (bool): +If set to \fBFalse\fP, the underlying \fBfile.symlink\fP execution module +and any checks in this state will use \fBos.path.lexists()\fP for +existence checks instead of \fBos.path.exists()\fP\&. +.sp +New in version 3007.0. + .UNINDENT .UNINDENT .INDENT 0.0 @@ -415994,7 +408469,7 @@ Returns a pretty dictionary meant for command line output. .UNINDENT .INDENT 0.0 .TP -.B salt.states.firewalld.present(name, block_icmp=None, prune_block_icmp=False, default=None, masquerade=False, ports=None, prune_ports=False, port_fwd=None, prune_port_fwd=False, services=None, prune_services=False, interfaces=None, prune_interfaces=False, sources=None, prune_sources=False, rich_rules=None, prune_rich_rules=False) +.B salt.states.firewalld.present(name, block_icmp=None, prune_block_icmp=False, default=None, masquerade=None, ports=None, prune_ports=False, port_fwd=None, prune_port_fwd=False, services=None, prune_services=False, interfaces=None, prune_interfaces=False, sources=None, prune_sources=False, rich_rules=None, prune_rich_rules=False) Ensure a zone has specific attributes. .INDENT 7.0 .TP @@ -416006,8 +408481,8 @@ None Set this zone as the default zone if \fBTrue\fP\&. .TP .B masquerade -False -Enable or disable masquerade for a zone. +None +Enable or disable masquerade for a zone. By default it will not change it. .TP .B block_icmp None @@ -417895,55 +410370,76 @@ desktop_lockdown: sets values in the org.gnome.desktop.lockdown schema wm_preferences: sets values in the org.gnome.desktop.wm.preferences schema .UNINDENT .SS salt.states.gpg -.SS Management of the GPG keychains +.SS Manage GPG keychains .sp New in version 2016.3.0. .INDENT 0.0 .TP -.B salt.states.gpg.absent(name, keys=None, user=None, gnupghome=None, **kwargs) -Ensure GPG public key is absent in keychain +.B salt.states.gpg.absent(name, keys=None, user=None, gnupghome=None, keyring=None, keyring_absent_if_empty=False, **kwargs) +Ensure a GPG public key is absent from the keychain. .INDENT 7.0 .TP .B name -The unique name or keyid for the GPG public key. +The key ID of the GPG public key. .TP .B keys -The keyId or keyIds to add to the GPG keychain. +The key ID or key IDs to remove from the GPG keychain. .TP .B user -Remove GPG keys from the specified user\(aqs keychain +Remove GPG keys from the specified user\(aqs keychain. .TP .B gnupghome -Override GNUPG Home directory +Override GnuPG home directory. +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + +.TP +.B keyring_absent_if_empty +Make sure to not leave behind an empty keyring file +if \fBkeyring\fP was specified. Defaults to false. +.sp +New in version 3007.0. + .UNINDENT .UNINDENT .INDENT 0.0 .TP -.B salt.states.gpg.present(name, keys=None, user=None, keyserver=None, gnupghome=None, trust=None, **kwargs) -Ensure GPG public key is present in keychain +.B salt.states.gpg.present(name, keys=None, user=None, keyserver=None, gnupghome=None, trust=None, keyring=None, **kwargs) +Ensure a GPG public key is present in the GPG keychain. .INDENT 7.0 .TP .B name -The unique name or keyid for the GPG public key. +The key ID of the GPG public key. .TP .B keys -The keyId or keyIds to add to the GPG keychain. +The key ID or key IDs to add to the GPG keychain. .TP .B user -Add GPG keys to the specified user\(aqs keychain +Add GPG keys to the specified user\(aqs keychain. .TP .B keyserver The keyserver to retrieve the keys from. .TP .B gnupghome -Override GNUPG Home directory +Override GnuPG home directory. .TP .B trust Trust level for the key in the keychain, -ignored by default. Valid trust levels: +ignored by default. Valid trust levels: expired, unknown, not_trusted, marginally, fully, ultimately +.TP +.B keyring +Limit the operation to this specific keyring, specified as +a local filesystem path. +.sp +New in version 3007.0. + .UNINDENT .UNINDENT .SS salt.states.grafana @@ -419185,12 +411681,24 @@ cheese: .UNINDENT .INDENT 0.0 .TP -.B salt.states.group.absent(name) +.B salt.states.group.absent(name, local=False) Ensure that the named group is absent .INDENT 7.0 .TP .B Parameters +.INDENT 7.0 +.IP \(bu 2 \fBname\fP (\fI\%str\fP) \-\- The name of the group to remove +.IP \(bu 2 +\fBlocal\fP (\fIOnly on systems with lgroupdel available\fP) \-\- +.sp +Ensure the group account is removed locally ignoring global +account management (default is False). +.sp +New in version 3007.0. + + +.UNINDENT .UNINDENT .sp Example: @@ -419209,7 +411717,7 @@ db_admin: .UNINDENT .INDENT 0.0 .TP -.B salt.states.group.present(name, gid=None, system=False, addusers=None, delusers=None, members=None, non_unique=False) +.B salt.states.group.present(name, gid=None, system=False, addusers=None, delusers=None, members=None, non_unique=False, local=False) Changed in version 3006.0. .sp @@ -419245,6 +411753,15 @@ Allow creating groups with duplicate (non\-unique) GIDs New in version 3006.0. +.IP \(bu 2 +\fBlocal\fP (\fIOnly on systems with lgroupadd available\fP) \-\- +.sp +Create the group account locally ignoring global account management +(default is False). +.sp +New in version 3007.0. + + .UNINDENT .UNINDENT .sp @@ -424264,6 +416781,14 @@ New in version 2016.3.0. .UNINDENT .UNINDENT .SS salt.states.kubernetes +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%kubernetes Salt Extension\fP\&. +.UNINDENT +.UNINDENT .SS Manage kubernetes resources as salt states .sp NOTE: This module requires the proper pillar values set. See @@ -425462,6 +417987,23 @@ root: .UNINDENT .UNINDENT .sp +Ensure a Linux ACL is present as a default for all new objects +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +root: + acl.present: + \- name: /root + \- acl_type: \(dqdefault:user\(dq + \- acl_name: damian + \- perms: rwx +.ft P +.fi +.UNINDENT +.UNINDENT +.sp Ensure a Linux ACL does not exist .INDENT 0.0 .INDENT 3.5 @@ -425516,6 +418058,26 @@ root: .fi .UNINDENT .UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +The effective permissions of Linux file access control lists (ACLs) are +governed by the \(dqeffective rights mask\(dq (the \fImask\fP line in the output of +the \fIgetfacl\fP command) combined with the \fIperms\fP set by this module: any +permission bits (for example, r=read) present in an ACL but not in the mask +are ignored. The mask is automatically recomputed when setting an ACL, so +normally this isn\(aqt important. However, if the file permissions are +changed (with \fIchmod\fP or \fIfile.managed\fP, for example), the mask will +generally be set based on just the group bits of the file permissions. +.sp +As a result, when using \fIfile.managed\fP or similar to control file +permissions as well as this module, you should set your group permissions +to be at least as broad as any permissions in your ACL. Otherwise, the two +state declarations will each register changes each run, and if the \fIfile\fP +declaration runs later, your ACL will be ineffective. +.UNINDENT +.UNINDENT .INDENT 0.0 .TP .B salt.states.linux_acl.absent(name, acl_type, acl_name=\(aq\(aq, perms=\(aq\(aq, recurse=False) @@ -436833,8 +429395,7 @@ Make sure the package is installed .B name The name of the python package to install. You can also specify version numbers here using the standard operators \fB==, >=, <=\fP\&. If -\fBrequirements\fP is given, this parameter will be ignored. -.UNINDENT +\fBrequirements\fP or \fBpkgs\fP is given, this parameter will be ignored. .sp Example: .INDENT 7.0 @@ -436852,9 +429413,33 @@ django: .UNINDENT .UNINDENT .sp -This will install the latest Django version greater than 1.6 but less +Installs the latest Django version greater than 1.6 but less than 1.7. +.TP +.B pkgs +A list of python packages to install. This let you install multiple +packages at the same time. +.sp +Example: .INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +django\-and\-psycopg2: + pip.installed: + \- pkgs: + \- django >= 1.6, <= 1.7 + \- psycopg2 >= 2.8.4 + \- require: + \- pkg: python\-pip +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Installs the latest Django version greater than 1.6 but less than 1.7 +and the latest psycopg2 greater than 2.8.4 at the same time. .TP .B requirements Path to a pip requirements file. If the path begins with salt:// @@ -437271,7 +429856,7 @@ done to keep systemd from killing the package manager commands spawned by Salt, when Salt updates itself (see \fBKillMode\fP in the \fI\%systemd.kill(5)\fP manpage for more information). If desired, usage of \fI\%systemd\-run(1)\fP can be suppressed by setting a \fI\%config option\fP -called \fBsystemd.use_scope\fP, with a value of \fBFalse\fP (no quotes). +called \fBsystemd.scope\fP, with a value of \fBFalse\fP (no quotes). .UNINDENT .UNINDENT .sp @@ -437673,6 +430258,9 @@ By default, this parameter is set to \fBFalse\fP\&. .INDENT 0.0 .TP .B salt.states.pkg.installed(name, version=None, refresh=None, fromrepo=None, skip_verify=False, skip_suggestions=False, pkgs=None, sources=None, allow_updates=False, pkg_verify=False, normalize=True, ignore_epoch=None, reinstall=False, update_holds=False, **kwargs) +Changed in version 3007.0. + +.sp Ensure that the package is installed, and that it is the correct version (if specified). .sp @@ -437706,6 +430294,16 @@ Any argument that is passed through to the \fBinstall\fP function, which is not defined for that function, will be silently ignored. .UNINDENT .UNINDENT +.sp +\fBNOTE:\fP +.INDENT 7.0 +.INDENT 3.5 +In Windows, some packages are installed using the task manager. The Salt +minion installer does this. In that case, there is no way to know if the +package installs correctly. All that can be reported is that the task +that launches the installer started successfully. +.UNINDENT +.UNINDENT .INDENT 7.0 .TP .B Parameters @@ -438585,6 +431183,9 @@ small reductions in waiting time can add up. .INDENT 0.0 .TP .B salt.states.pkg.latest(name, refresh=None, fromrepo=None, skip_verify=False, pkgs=None, watch_flags=True, **kwargs) +Changed in version 3007.0. + +.sp Ensure that the named package is installed and the latest available package. If the package can be updated, this state function will update the package. Generally it is better for the @@ -440307,7 +432908,18 @@ The name of the database to manage Default tablespace for the database .TP .B encoding -The character encoding scheme to be used in this database +The character encoding scheme to be used in this database. The encoding +has to be defined in the following format (without hyphen). +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +\- encoding: UTF8 +.ft P +.fi +.UNINDENT +.UNINDENT .TP .B lc_collate The LC_COLLATE setting to be used in this database @@ -441628,6 +434240,14 @@ macOS .UNINDENT .UNINDENT .SS salt.states.pushover +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%pushover Salt Extension\fP\&. +.UNINDENT +.UNINDENT .SS Send a message to PushOver .sp This state is useful for sending messages to PushOver during state runs. @@ -444460,6 +437080,24 @@ sync_everything: .UNINDENT .INDENT 0.0 .TP +.B salt.states.saltutil.sync_tops(name, **kwargs) +Performs the same task as saltutil.sync_tops module +See \fI\%saltutil module for full list of options\fP +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +sync_everything: + saltutil.sync_tops: + \- refresh: True +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP .B salt.states.saltutil.sync_utils(name, **kwargs) Performs the same task as saltutil.sync_utils module See \fI\%saltutil module for full list of options\fP @@ -444476,6 +437114,27 @@ sync_everything: .UNINDENT .UNINDENT .UNINDENT +.INDENT 0.0 +.TP +.B salt.states.saltutil.sync_wrapper(name, **kwargs) +New in version 3007.0. + +.sp +Performs the same task as saltutil.sync_wrapper module +See \fI\%saltutil module for full list of options\fP +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +sync_everything: + saltutil.sync_wrapper: + \- refresh: True +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.states.schedule .SS Management of the Salt scheduler .INDENT 0.0 @@ -444773,6 +437432,9 @@ period ends. .TP .B offline Add the scheduled job to the Salt minion when the Salt minion is not running. +.sp +New in version 3006.3. + .UNINDENT .UNINDENT .SS salt.states.selinux @@ -447888,7 +440550,7 @@ is\-pillar\-foo\-present\-and\-bar\-is\-int: .UNINDENT .INDENT 0.0 .TP -.B salt.states.test.configurable_test_state(name, changes=True, result=True, comment=\(aq\(aq, warnings=None) +.B salt.states.test.configurable_test_state(name, changes=True, result=True, comment=\(aq\(aq, warnings=None, allow_test_mode_failure=False) New in version 2014.7.0. .sp @@ -447955,6 +440617,14 @@ Default is None .sp New in version 3000. +.TP +.B allow_test_mode_failure +When False, running this state in test mode can only return a True +or None result. When set to True and result is set to False, the +test mode result will be False. Default is False +.sp +New in version 3007.0. + .UNINDENT .UNINDENT .INDENT 0.0 @@ -448705,11 +441375,9 @@ Example tuned.sls file to set profile to virtual\-guest .B tuned: .INDENT 7.0 .TP -.B tuned: +.B tuned.profile .INDENT 7.0 .IP \(bu 2 -profile -.IP \(bu 2 name: virtual\-guest .UNINDENT .UNINDENT @@ -448806,7 +441474,7 @@ testuser: .UNINDENT .INDENT 0.0 .TP -.B salt.states.user.absent(name, purge=False, force=False) +.B salt.states.user.absent(name, purge=False, force=False, local=False) Ensure that the named user is absent .INDENT 7.0 .TP @@ -448821,11 +441489,18 @@ Default is \fBFalse\fP\&. If the user is logged in, the absent state will fail. Set the force option to True to remove the user even if they are logged in. Not supported in FreeBSD and Solaris, Default is \fBFalse\fP\&. +.TP +.B local (Only on systems with luserdel available): +Ensure the user account is removed locally ignoring global account management +(default is False). +.sp +New in version 3007.0. + .UNINDENT .UNINDENT .INDENT 0.0 .TP -.B salt.states.user.present(name, uid=None, gid=None, usergroup=None, groups=None, optional_groups=None, remove_groups=True, home=None, createhome=True, password=None, hash_password=False, enforce_password=True, empty_password=False, shell=None, unique=True, system=False, fullname=None, roomnumber=None, workphone=None, homephone=None, other=None, loginclass=None, date=None, mindays=None, maxdays=None, inactdays=None, warndays=None, expire=None, win_homedrive=None, win_profile=None, win_logonscript=None, win_description=None, nologinit=False, allow_uid_change=False, allow_gid_change=False, password_lock=None) +.B salt.states.user.present(name, uid=None, gid=None, usergroup=None, groups=None, optional_groups=None, remove_groups=True, home=None, createhome=True, password=None, hash_password=False, enforce_password=True, empty_password=False, shell=None, unique=True, system=False, fullname=None, roomnumber=None, workphone=None, homephone=None, other=None, loginclass=None, date=None, mindays=None, maxdays=None, inactdays=None, warndays=None, expire=None, win_homedrive=None, win_profile=None, win_logonscript=None, win_description=None, nologinit=False, allow_uid_change=False, allow_gid_change=False, password_lock=None, local=False) Ensure that the named user is present with the specified properties .INDENT 7.0 .TP @@ -449026,6 +441701,13 @@ Number of days prior to maxdays to warn users. .B expire Date that account expires, represented in days since epoch (January 1, 1970). +.TP +.B local (Only on systems with luseradd available): +Create the user account locally ignoring global account management +(default is False). +.sp +New in version 3007.0. + .UNINDENT .sp The below parameters apply to windows only: @@ -449344,8 +442026,17 @@ node_name: .UNINDENT .SS salt.states.vault .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%vault Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp States for managing Hashicorp Vault. -Currently handles policies. Configuration instructions are documented in the execution module docs. +Currently handles policies. +Configuration instructions are documented in the \fI\%execution module docs\fP\&. .INDENT 0.0 .TP .B maintainer @@ -449360,6 +442051,16 @@ all .sp New in version 2017.7.0. +.INDENT 0.0 +.TP +.B salt.states.vault.policy_absent(name) +Ensure a Vault policy with the given name and rules is absent. +.INDENT 7.0 +.TP +.B name +The name of the policy +.UNINDENT +.UNINDENT .INDENT 0.0 .TP .B salt.states.vault.policy_present(name, rules) @@ -451879,6 +444580,94 @@ Update an existing user\(aqs password if it\(aqs different from what\(aqs in the htpasswd file (unlike force, which updates regardless) .UNINDENT .UNINDENT +.SS salt.states.win_appx +.sp +Manage Microsoft Store apps on Windows. Removing an app with this modules will +deprovision the app from the online Windows image. +.sp +New in version 3007.0. + +.INDENT 0.0 +.TP +.B salt.states.win_appx.absent(name, query, include_store=False, frameworks=False, deprovision_only=False) +Removes Microsoft Store packages from the system. If the package is part of +a bundle, the entire bundle will be removed. +.sp +This function removes the package for all users on the system. It also +deprovisions the package so that it isn\(aqt re\-installed by later system +updates. To only deprovision a package and not remove it for all users, set +\fBdeprovision_only=True\fP\&. +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBquery\fP (\fI\%str\fP) \-\- +.sp +The query string to use to select the packages to be removed. If the +string matches multiple packages, they will all be removed. Here are +some example strings: +.nf +string | description | +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- | \-\-\-\-\-\-\-\-\-\-\- | +\fB*teams*\fP | Remove Microsoft Teams | +\fB*zune*\fP | Remove Windows Media Player and Zune Video | +\fB*zuneMusic*\fP | Only remove Windows Media Player | +\fB*xbox*\fP | Remove all xBox packages, there are 5 by default +\fB*\fP | Remove everything but the Microsoft Store, unless \fBinclude_store=True\fP | +.fi +.sp +.sp +\fBNOTE:\fP +.INDENT 2.0 +.INDENT 3.5 +Use the \fBappx.list\fP function to make sure your query is +returning what you expect. Then use the same query to remove +those packages +.UNINDENT +.UNINDENT + +.IP \(bu 2 +\fBinclude_store\fP (\fI\%bool\fP) \-\- Include the Microsoft Store in the results of the query to be +removed. Use this with caution. It is difficult to reinstall the +Microsoft Store once it has been removed with this function. Default +is \fBFalse\fP +.IP \(bu 2 +\fBframeworks\fP (\fI\%bool\fP) \-\- Include frameworks in the results of the query to be removed. +Default is \fBFalse\fP +.IP \(bu 2 +\fBdeprovision_only\fP (\fI\%bool\fP) \-\- Only deprovision the package. The package will be removed from the +current user and added to the list of deprovisioned packages. The +package will not be re\-installed in future system updates. New users +of the system will not have the package installed. However, the +package will still be installed for existing users. Default is +\fBFalse\fP +.UNINDENT +.TP +.B Returns +\fBTrue\fP if successful, \fBNone\fP if no packages found +.TP +.B Return type +\fI\%bool\fP +.TP +.B Raises +\fI\%CommandExecutionError\fP \-\- On errors encountered removing the package +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +remove_candy_crush: + appx.absent: + \- query: \(dq*candy*\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.states.win_certutil .SS Installing of certificates to the Windows Certificate Manager .sp @@ -452107,7 +444896,7 @@ Ensure an ACE is present .SS salt.states.win_dism .SS Installing of Windows features using DISM .sp -Install windows features/capabilties with DISM +Install Windows features, capabilities, and packages with DISM .INDENT 0.0 .INDENT 3.5 .sp @@ -452135,12 +444924,11 @@ Install a DISM capability .IP \(bu 2 \fBsource\fP (\fI\%str\fP) \-\- The optional source of the capability .IP \(bu 2 -\fBlimit_access\fP (\fI\%bool\fP) \-\- Prevent DISM from contacting Windows Update for -online images +\fBlimit_access\fP (\fI\%bool\fP) \-\- Prevent DISM from contacting Windows Update for online images .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 \fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the install .UNINDENT @@ -452149,7 +444937,7 @@ targeted. Default is None. Example .sp Run \fBdism.available_capabilities\fP to get a list of available -capabilities. This will help you get the proper name to use. +capabilities. This will help you get the proper name to use .INDENT 7.0 .INDENT 3.5 .sp @@ -452174,19 +444962,18 @@ Uninstall a DISM capability .IP \(bu 2 \fBname\fP (\fI\%str\fP) \-\- The capability to uninstall .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 -\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the -uninstall +\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the uninstall .UNINDENT .UNINDENT .sp Example .sp Run \fBdism.installed_capabilities\fP to get a list of installed -capabilities. This will help you get the proper name to use. +capabilities. This will help you get the proper name to use .INDENT 7.0 .INDENT 3.5 .sp @@ -452211,21 +444998,19 @@ Install a DISM feature .IP \(bu 2 \fBname\fP (\fI\%str\fP) \-\- The feature in which to install .IP \(bu 2 -\fBpackage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The parent package for the feature. You do not -have to specify the package if it is the Windows Foundation Package. -Otherwise, use package to specify the parent package of the feature +\fBpackage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The parent package for the feature. You do not have to specify the +package if it is the Windows Foundation Package. Otherwise, use +package to specify the parent package of the feature .IP \(bu 2 \fBsource\fP (\fI\%str\fP) \-\- The optional source of the feature .IP \(bu 2 -\fBlimit_access\fP (\fI\%bool\fP) \-\- Prevent DISM from contacting Windows Update for -online images +\fBlimit_access\fP (\fI\%bool\fP) \-\- Prevent DISM from contacting Windows Update for online images .IP \(bu 2 -\fBenable_parent\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- True will enable all parent features of -the specified feature +\fBenable_parent\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- \fBTrue\fP will enable all parent features of the specified feature .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 \fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the install .UNINDENT @@ -452234,7 +445019,7 @@ targeted. Default is None. Example .sp Run \fBdism.available_features\fP to get a list of available features. -This will help you get the proper name to use. +This will help you get the proper name to use .INDENT 7.0 .INDENT 3.5 .sp @@ -452259,22 +445044,21 @@ Disables a feature. .IP \(bu 2 \fBname\fP (\fI\%str\fP) \-\- The feature to disable .IP \(bu 2 -\fBremove_payload\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Remove the feature\(aqs payload. Must -supply source when enabling in the future. +\fBremove_payload\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Remove the feature\(aqs payload. Must supply source when enabling in +the future. .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 -\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the -uninstall +\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the uninstall .UNINDENT .UNINDENT .sp Example .sp Run \fBdism.installed_features\fP to get a list of installed features. -This will help you get the proper name to use. +This will help you get the proper name to use .INDENT 7.0 .INDENT 3.5 .sp @@ -452301,15 +445085,13 @@ New in version 3006.0. .B Parameters .INDENT 7.0 .IP \(bu 2 -\fBname\fP (\fI\%str\fP) \-\- The name of the KB. Can be with or without the KB at the -beginning. +\fBname\fP (\fI\%str\fP) \-\- The name of the KB. Can be with or without the KB at the beginning .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 -\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the -uninstall +\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the uninstall .UNINDENT .UNINDENT .sp @@ -452342,18 +445124,16 @@ Install a package. .B Parameters .INDENT 7.0 .IP \(bu 2 -\fBname\fP (\fI\%str\fP) \-\- The package to install. Can be a .cab file, a .msu file, -or a folder +\fBname\fP (\fI\%str\fP) \-\- The package to install. Can be a .cab file, a .msu file, or a folder .IP \(bu 2 -\fBignore_check\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Skip installation of the package if the -applicability checks fail +\fBignore_check\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Skip installation of the package if the applicability checks fail .IP \(bu 2 -\fBprevent_pending\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Skip the installation of the package -if there are pending online actions +\fBprevent_pending\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Skip the installation of the package if there are pending online +actions .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 \fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the install .UNINDENT @@ -452382,17 +445162,16 @@ Uninstall a package .B Parameters .INDENT 7.0 .IP \(bu 2 -\fBname\fP (\fI\%str\fP) \-\- The full path to the package. Can be either a .cab file or a -folder. Should point to the original source of the package, not to -where the file is installed. This can also be the name of a package as listed in -\fBdism.installed_packages\fP +\fBname\fP (\fI\%str\fP) \-\- The full path to the package. Can be either a .cab file or a folder. +Should point to the original source of the package, not to where the +file is installed. This can also be the name of a package as listed +in \fBdism.installed_packages\fP .IP \(bu 2 -\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline -Windows image. If \fINone\fP is passed, the running operating system is -targeted. Default is None. +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP .IP \(bu 2 -\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the -uninstall +\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the uninstall .UNINDENT .UNINDENT .sp @@ -452416,6 +445195,58 @@ remove_KB1231231: .UNINDENT .UNINDENT .UNINDENT +.INDENT 0.0 +.TP +.B salt.states.win_dism.provisioned_package_installed(name, image=None, restart=False) +Provision a package on a Windows image. +.sp +New in version 3007.0. + +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBname\fP (\fI\%str\fP) \-\- +.sp +The package to install. Can be one of the following: +.INDENT 2.0 +.IP \(bu 2 +\fB\&.appx\fP or \fB\&.appxbundle\fP +.IP \(bu 2 +\fB\&.msix\fP or \fB\&.msixbundle\fP +.IP \(bu 2 +\fB\&.ppkg\fP +.UNINDENT +.sp +The name of the file before the file extension must match the name +of the package after it is installed. This name can be found by +running \fBdism.provisioned_packages\fP + +.IP \(bu 2 +\fBimage\fP (\fIOptional\fP\fI[\fP\fI\%str\fP\fI]\fP) \-\- The path to the root directory of an offline Windows image. If +\fBNone\fP is passed, the running operating system is targeted. +Default is \fBNone\fP +.IP \(bu 2 +\fBrestart\fP (\fIOptional\fP\fI[\fP\fI\%bool\fP\fI]\fP) \-\- Reboot the machine if required by the installation. Default is +\fBFalse\fP +.UNINDENT +.UNINDENT +.sp +Example +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +install_windows_media_player: + dism.provisioned_package_installed: + \- name: C:\ePackages\eMicrosoft.ZuneVideo_2019.22091.10036.0_neutral_~_8wekyb3d8bbwe.Msixbundle +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.states.win_dns_client .sp Module for configuring DNS Client on Windows systems @@ -455409,6 +448240,118 @@ set workgroup: .UNINDENT .UNINDENT .UNINDENT +.SS salt.states.win_task +.sp +State module for adding and removing scheduled tasks using the Windows Task +Scheduler. +.INDENT 0.0 +.TP +.B salt.states.win_task.absent(name, location=\(aq\e\e\(aq) +Delete a task from the task scheduler. +.sp +New in version 3007.0. + +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBname\fP (\fI\%str\fP) \-\- The name of the task to delete. +.IP \(bu 2 +\fBlocation\fP (\fI\%str\fP) \-\- A string value representing the location of the task. +Default is \(dq\e\(dq which is the root for the task scheduler +(C:WindowsSystem32tasks). +.UNINDENT +.TP +.B Returns +\fBTrue\fP if successful, otherwise \fBFalse\fP +.TP +.B Return type +\fI\%bool\fP +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +test_win_task_absent: + task.absent: + \- name: salt + \- location: \(dq\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B salt.states.win_task.present(name, location=\(aq\e\e\(aq, user_name=\(aqSystem\(aq, password=None, force=False, **kwargs) +Create a new task in the designated location. This function has many keyword +arguments that are not listed here. For additional arguments see: +.sp +New in version 3007.0. + +.INDENT 7.0 +.IP \(bu 2 +\fBedit_task()\fP +.IP \(bu 2 +\fBadd_action()\fP +.IP \(bu 2 +\fBadd_trigger()\fP +.UNINDENT +.INDENT 7.0 +.TP +.B Parameters +.INDENT 7.0 +.IP \(bu 2 +\fBname\fP (\fI\%str\fP) \-\- The name of the task. This will be displayed in the task +scheduler. +.IP \(bu 2 +\fBlocation\fP (\fI\%str\fP) \-\- A string value representing the location in which to +create the task. Default is \(dq\e\(dq which is the root for the task +scheduler (C:WindowsSystem32tasks). +.IP \(bu 2 +\fBuser_name\fP (\fI\%str\fP) \-\- The user account under which to run the task. To +specify the \(dqSystem\(dq account, use \(dqSystem\(dq. The password will be +ignored. +.IP \(bu 2 +\fBpassword\fP (\fI\%str\fP) \-\- The password to use for authentication. This should set +the task to run whether the user is logged in or not, but is +currently not working. +.IP \(bu 2 +\fBforce\fP (\fI\%bool\fP) \-\- Overwrite the existing task. +.UNINDENT +.TP +.B Returns +A dictionary containing the results of the state +.TP +.B Return type +\fI\%dict\fP +.UNINDENT +.sp +CLI Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +test_win_task_present: + task.present: + \- name: salt + \- location: \(dq\(dq + \- force: True + \- action_type: Execute + \- cmd: \(dqdel /Q /S C:\e\eTemp\(dq + \- trigger_type: Once + \- start_date: 12\-1\-16 + \- start_time: 01:00 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT .SS salt.states.win_wua .sp Installation of Windows Updates using the Windows Update Agent @@ -457194,6 +450137,14 @@ The message to send to the XMPP user .UNINDENT .SS salt.states.zabbix_action .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix Action object over Zabbix API. .sp New in version 2017.7.0. @@ -457295,6 +450246,14 @@ zabbix\-action\-present: .UNINDENT .SS salt.states.zabbix_host .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix hosts. .INDENT 0.0 .TP @@ -457447,6 +450406,14 @@ create_test_host: .UNINDENT .SS salt.states.zabbix_hostgroup .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix host groups. .INDENT 0.0 .TP @@ -457523,6 +450490,14 @@ create_testing_host_group: .UNINDENT .SS salt.states.zabbix_mediatype .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix mediatypes. .INDENT 0.0 .TP @@ -457600,6 +450575,14 @@ make_new_mediatype: .UNINDENT .SS salt.states.zabbix_template .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp New in version 2017.7.0. .sp @@ -457832,6 +450815,14 @@ zabbix\-template\-present: .UNINDENT .SS salt.states.zabbix_user .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix users. .INDENT 0.0 .TP @@ -457997,6 +450988,14 @@ make_user: .UNINDENT .SS salt.states.zabbix_usergroup .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix user groups. .INDENT 0.0 .TP @@ -458079,6 +451078,14 @@ make_new_thai_monks_usergroup: .UNINDENT .SS salt.states.zabbix_usermacro .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix usermacros. :codeauthor: Raymond Kuiper <\fI\%qix@the\-wired.net\fP> .INDENT 0.0 @@ -458153,6 +451160,14 @@ override host usermacro: .UNINDENT .SS salt.states.zabbix_valuemap .sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +This module will be removed from Salt in version 3009 in favor of +the \fI\%zabbix Salt Extension\fP\&. +.UNINDENT +.UNINDENT +.sp Management of Zabbix Valuemap object over Zabbix API. .sp New in version 2017.7.0. @@ -462168,7 +455183,7 @@ The key to return information about. .sp .nf .ft C ->>> wheel.cmd(\(aqkey.key_str\(aq, [\(aqminion1\(aq]) +>>> wheel.cmd(\(aqkey.print\(aq, [\(aqminion1\(aq]) {\(aqminions\(aq: {\(aqminion1\(aq: \(aq\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-\enMIIBIjANBgkqhkiG9w0B \&... TWugEQpPt\eniQIDAQAB\en\-\-\-\-\-END PUBLIC KEY\-\-\-\-\-\(aq}} @@ -464093,6 +457108,19 @@ your deployment as needed for redundancy, geographical distribution, and scale. Salt supports several features for high availability and fault tolerance. Brief documentation for these features is listed alongside their configuration parameters in \fI\%Configuration file examples\fP\&. +.SS Master Cluster +.sp +New in version 3007. + +.sp +Salt masters can be configured to act as a cluster. All masters in a cluster +are peers. Job workloads are shared accross the cluster. Master clusters +provide a way to scale masters horizontally. They do not require changes to +the minions\(aq configuration to add more resources. Cluster implementations are +expected to use a load balancer, shared filesystem, and run on a reliable +network. +.sp +\fI\%Master Cluster Tutorial\fP .SS Multimaster .sp Salt minions can connect to multiple masters at one time by configuring the @@ -464590,6 +457618,128 @@ file\-in\-user\-home: .fi .UNINDENT .UNINDENT +.SS Example Usage +.sp +In Salt, slots are a powerful feature that allows you to populate information +dynamically within your Salt states. One of the best use cases for slots is when +you need to reference data that is created or modified during the course of a +Salt run. +.sp +Consider the following example, where we aim to add a user named \(aqfoobar\(aq to a +group named \(aqknown_users\(aq with specific user and group IDs. To achieve this, we +utilize slots to retrieve the group ID of \(aqknown_users\(aq as it is created or +modified during the Salt run. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +add_group_known_users: + group.present: + \- name: known_users + +add_user: + user.present: + \- name: foobar + \- uid: 600 + \- gid: __slot__:salt:group.info(\(dqknown_users\(dq).gid + \- require: + \- group: add_group_known_users +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +In this example, the \fBadd_group_known_users\fP state ensures the presence of the +\(aqknown_users\(aq group. Then, within the \fBadd_user\fP state, we use the slot +\fB__slot__:salt:group.info(\(dqknown_users\(dq).gid\fP to dynamically retrieve the +group ID of \(aqknown_users,\(aq which may have been modified during the execution of +the previous state. This approach ensures that our user \(aqfoobar\(aq is associated +with the correct group, even if the group information changes during the Salt +run. +.sp +Slots offer a flexible way to work with changing data and dynamically populate +your Salt states, making your configurations adaptable and robust. +.SS Execution module returns as file contents or data +.sp +The following examples demonstrate how to use execution module returns as file +contents or data in Salt states. These examples show how to incorporate the +output of execution functions into file contents or data in the \fIfile.managed\fP +and \fIfile.serialize\fP states. +.SS Content from execution modules +.sp +You can use the results of execution modules directly as file contents in Salt +states. This can be useful for dynamically generating file content based on the +output of execution functions. +.sp +\fBExample 1: Using \(gatest.echo\(ga Output as File Content\fP +.sp +The following Salt state uses the \fItest.echo\fP execution function to generate the +text \(dqhello world.\(dq This output is then used as the content of the file +\fI/tmp/things.txt\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +content\-from\-slots: + file.managed: + \- name: /tmp/things.txt + \- contents: __slot__:salt:test.echo(\(dqhello world\(dq) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBExample 2: Using Multiple \(gatest.echo\(ga Outputs as Appended Content\fP +.sp +In this example, two \fItest.echo\fP execution functions are used to generate +\(dqhello\(dq and \(dqworld\(dq strings. These strings are then joined by newline characters +and then used as the content of the file \fI/tmp/things.txt\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +content\-from\-multiple\-slots: + file.managed: + \- name: /tmp/things.txt + \- contents: + \- __slot__:salt:test.echo(\(dqhello\(dq) + \- __slot__:salt:test.echo(\(dqworld\(dq) +.ft P +.fi +.UNINDENT +.UNINDENT +.SS Serializing data from execution modules +.sp +You can also serialize data obtained from execution modules and write it to +files using Salt states. This allows you to capture and store structured data +for later use. +.sp +\fBExample: Serializing \(gagrains.items()\(ga Output to JSON\fP +.sp +In this example, the \fIgrains.items()\fP execution function retrieves system +information. The obtained data is then serialized into JSON format and saved to +the file \fI/tmp/grains.json\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +serialize\-dataset\-from\-slots: + file.serialize: + \- name: /tmp/grains.json + \- serializer: json + \- dataset: __slot__:salt:grains.items() +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +These examples showcase how to leverage Salt\(aqs flexibility to use execution +module returns as file contents or serialized data in your Salt states, allowing +for dynamic and customized configurations. .SH WINDOWS .sp This section contains details on the Windows Package Manager, and specific information you need @@ -464825,92 +457975,196 @@ ssm.exe set ObjectName \(dq.\e\(dq \(dq\(dq .SS Windows Package Manager .SS Introduction .sp -The Windows Package Manager provides a software repository and a package manager -similar to what is provided by \fByum\fP and \fBapt\fP on Linux. This tool enables -the installation of software on remote Windows systems. +Salt provides a Windows package management tool for installing, updating, +removing, and managing software packages on remote Windows systems. This tool +provides a software repository and a package manager similar to what is provided +by \fByum\fP and \fBapt\fP on Linux. The repository contains a collection of package +definition files. +.SS What are package definition files? .sp -The repository contains a collection of software definition files. A software -definition file is a YAML/JINJA file with an \fB\&.sls\fP file extension. It -contains all the information Salt needs to install a software package on a -Windows system, including the download location of the installer, required -command\-line switches for silent install, etc. -.sp -Software definition files can be hosted in one or more Git repositories. The -default repository is hosted on GitHub by SaltStack. It is maintained by -SaltStack and the Salt community and contains software definition files for many -common Windows packages. Anyone is welcome to submit a pull request to this -repo to add new software definitions. The default github repository is: +A package definition file is a YAML/JINJA2 file with a \fB\&.sls\fP file extension +that contains all the information needed to install software using Salt. It +defines: .INDENT 0.0 .IP \(bu 2 +Full name of the software package +.IP \(bu 2 +The version of the software package +.IP \(bu 2 +Download location of the software package +.IP \(bu 2 +Command\-line switches for silent install and uninstall +.IP \(bu 2 +Whether or not to use the Windows task scheduler to install the package +.UNINDENT +.sp +Package definition files can be hosted in one or more Git repositories. The +\fB\&.sls\fP files used to install Windows packages are not distributed by default +with Salt. You have to initialize and clone the default repository \fI\%salt\-winrepo\-ng\fP -.UNINDENT +which is hosted on GitHub by SaltStack. The repository contains package +definition files for many common Windows packages and is maintained by SaltStack +and the Salt community. Anyone can submit a pull request to this repo to add +new package definitions. .sp -The Windows Package Manager is used the same way as other package managers Salt -is aware of. For example: +You can manage the package definition file through either Salt or Git. You can +download software packages from either a git repository or from HTTP(S) or FTP +URLs. You can store the installer defined in the package definition file +anywhere as long as it is accessible from the host running Salt. +.sp +You can use the Salt Windows package manager like \fByum\fP on Linux. You do not +have to know the underlying command to install the software. .INDENT 0.0 .IP \(bu 2 -the \fBpkg.installed\fP and similar states work on Windows. +Use \fBpkg.install\fP to install a package using a package manager based on +the OS the system runs on. .IP \(bu 2 -the \fBpkg.install\fP and similar module functions work on Windows. +Use \fBpkg.installed\fP to check if a particular package is installed in the +minion. .UNINDENT .sp -High level differences to \fByum\fP and \fBapt\fP are: +\fBNOTE:\fP .INDENT 0.0 -.IP \(bu 2 -The repository metadata (SLS files) can be managed through either Salt or git -.IP \(bu 2 -Packages can be downloaded from within the Salt repository, a git repository -or from HTTP(S) or FTP URLs -.IP \(bu 2 -No dependencies are managed. Dependencies between packages need to be managed -manually +.INDENT 3.5 +The Salt Windows package manager does not automatically resolve dependencies +while installing, updating, or removing packages. You have to manage the +dependencies between packages manually. .UNINDENT -.SS Requirements +.UNINDENT +.SS Quickstart .sp -If using the a software definition files hosted on a Git repo, the following -libraries are required: +This quickstart guides you through using the Windows Salt package manager +(winrepo) to install software packages in four steps: .INDENT 0.0 -.IP \(bu 2 -GitPython 0.3 or later -.sp -or -.IP \(bu 2 -pygit2 0.20.3 with libgit 0.20.0 or later +.IP 1. 3 +(Optional) \fI\%Install libraries\fP +.IP 2. 3 +\fI\%Populate the local Git repository\fP +.IP 3. 3 +\fI\%Update minion database\fP +.IP 4. 3 +\fI\%Install software packages\fP .UNINDENT -.SS Quick Start +.SS Install libraries .sp -You can get up and running with winrepo pretty quickly just using the defaults. -Assuming no changes to the default configuration (ie, \fBfile_roots\fP) run the -following commands on the master: +(Optional) If you are using the Salt Windows package manager with package +definition files hosted on a Salt Git repo, install the libraries \fBGitPython\fP +or \fBpygit2\fP\&. +.SS Populate the local Git repository +.sp +The SLS files used to install Windows packages are not distributed by default +with Salt. Assuming no changes to the default configuration (\fBfile_roots\fP), +initialize and clone \fI\%salt\-winrepo\-ng\fP +repository. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C salt\-run winrepo.update_git_repos -salt * pkg.refresh_db -salt * pkg.install firefox_x64 .ft P .fi .UNINDENT .UNINDENT .sp -On a masterless minion run the following: +On successful execution of \fI\%winrepo.update_git_repos\fP, +the winrepo repository is cloned on the master in the location specified in +\fBwinrepo_dir_ng\fP and all package definition files are pulled down from the Git +repository. +.sp +On a masterless minion, use \fBsalt\-call\fP to initialize and clone the +\fI\%salt\-winrepo\-ng\fP .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C salt\-call \-\-local winrepo.update_git_repos -salt\-call \-\-local pkg.refresh_db -salt\-call \-\-local pkg.install firefox_x64 .ft P .fi .UNINDENT .UNINDENT .sp -These commands clone the default winrepo from github, update the winrepo -database on the minion, and install the latest version of Firefox. +On successful execution of the runner, the winrepo repository is cloned on the +minion in the location specified in \fBwinrepo_dir_ng\fP and all package +definition files are pulled down from the Git repository. +.SS Update minion database +.sp +Run \fI\%pkg.refresh_db\fP on all Windows +minions to create a database entry for every package definition file and build +the package database. +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# From the master +salt \-G \(aqos:windows\(aq pkg.refresh_db + +# From the minion in masterless mode +salt\-call \-\-local pkg.refresh_db +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The \fI\%pkg.refresh_db\fP command parses the +YAML/JINJA package definition files and generates the database. The above +command returns the following summary denoting the number of packages that +succeeded or failed to compile: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +local: + \-\-\-\-\-\-\-\-\-\- + failed: + 0 + success: + 301 + total: + 301 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +This command can take a few minutes to complete as all the package +definition files are copied to the minion and the database is generated. +.UNINDENT +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +You can use \fBpkg.refresh_db\fP when writing new Windows package definitions +to check for errors in the definitions against one or more Windows minions. +.UNINDENT +.UNINDENT +.SS Install software package +.sp +You can now install a software package using +\fI\%pkg.install\fP: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +# From the master +salt * pkg.install \(aqfirefox_x64\(aq + +# From the minion in masterless mode +salt\-call \-\-local pkg.install \(dqfirefox_x64\(dq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The above command installs the latest version of Firefox on the minions. .SS Configuration .sp The Github repository (winrepo) is synced to the \fBfile_roots\fP in a location @@ -464924,7 +458178,7 @@ Masterless minion: \fBC:\esalt\esrv\esalt\ewin\erepo\-ng\fP (\fBsalt://win/repo\ .UNINDENT .SS Master Configuration .sp -The following are settings are available for configuring the winrepo on the +The following settings are available for configuring the winrepo on the master: .INDENT 0.0 .IP \(bu 2 @@ -464963,8 +458217,8 @@ is \fB/srv/salt/win/repo\-ng\fP\&. .INDENT 0.0 .INDENT 3.5 You can change the location of the winrepo directory. However, it must -always be set to a path that is inside the \fBfile_roots\fP\&. -Otherwise the software definition files will be unreachable by the minion. +always be set to a path that is inside the \fBfile_roots\fP\&. Otherwise, the +software definition files will be unreachable by the minion. .UNINDENT .UNINDENT .sp @@ -465001,7 +458255,7 @@ winrepo_remotes: [] .sp \fI\%winrepo_remotes_ng\fP (list) .sp -This setting tells the \fBwinrepo.upgate_git_repos\fP command where the next +This setting tells the \fBwinrepo.update_git_repos\fP command where the next generation winrepo is hosted. This a list of URLs to multiple git repos. The default is a list containing a single URL: .sp @@ -465103,20 +458357,20 @@ minions whether in masterless mode or not. \fI\%winrepo_cache_expire_max\fP (int) .sp Sets the maximum age in seconds of the winrepo metadata file to avoid it -becoming stale. If the metadata file is older than this setting it will trigger +becoming stale. If the metadata file is older than this setting, it will trigger a \fBpkg.refresh_db\fP on the next run of any \fBpkg\fP module function that requires the metadata file. Default is 604800 (1 week). .sp Software package definitions are automatically refreshed if stale after -\fI\%winrepo_cache_expire_max\fP\&. Running a highstate normal forces the -refresh of the package definition and generation of the metadata, unless -the metadata is younger than \fI\%winrepo_cache_expire_max\fP\&. +\fI\%winrepo_cache_expire_max\fP\&. Running a highstate forces the refresh +of the package definitions and regenerates the metadata, unless the metadata is +younger than \fI\%winrepo_cache_expire_max\fP\&. .SS winrepo_cache_expire_min .sp \fI\%winrepo_cache_expire_min\fP (int) .sp Sets the minimum age in seconds of the winrepo metadata file to avoid refreshing -too often. If the metadata file is older than this setting the metadata will be +too often. If the metadata file is older than this setting, the metadata will be refreshed unless you pass \fBrefresh: False\fP in the state. Default is 1800 (30 min). .SS winrepo_cachefile @@ -465136,16 +458390,16 @@ different environments. Default is \fBsalt://win/repo\-ng/\fP\&. .INDENT 0.0 .INDENT 3.5 If the default for \fBwinrepo_dir_ng\fP is changed, this setting may need to -changed on each minion. The default setting for \fBwinrepo_dir_ng\fP is -\fB/srv/salt/win/repo\-ng\fP\&. If that were changed to \fB/srv/salt/new/repo\-ng\fP -then the \fBwinrepo_source_dir\fP would need to be changed to -\fBsalt://new/repo\-ng\fP +be changed on each minion. The default setting for \fBwinrepo_dir_ng\fP is +\fB/srv/salt/win/repo\-ng\fP\&. If that were changed to +\fB/srv/salt/new/repo\-ng\fP, then the \fBwinrepo_source_dir\fP would need to be +changed to \fBsalt://new/repo\-ng\fP .UNINDENT .UNINDENT .SS Masterless Minion Configuration .sp -The following are settings are available for configuring the winrepo on a -masterless minion: +The following settings are available for configuring the winrepo on a masterless +minion: .INDENT 0.0 .IP \(bu 2 \fI\%winrepo_dir\fP @@ -465170,15 +458424,15 @@ The default is: \fBC:\esalt\esrv\esalt\ewin\erepo\fP .sp \fI\%winrepo_dir_ng\fP (str) .sp -The location in the \fBfile_roots where the winrepo files are kept. The default -is \(ga\(gaC:\esalt\esrv\esalt\ewin\erepo\-ng\fP\&. +The location in the \fBfile_roots\fP where the winrepo files are kept. The default +is \fBC:\esalt\esrv\esalt\ewin\erepo\-ng\fP\&. .sp \fBWARNING:\fP .INDENT 0.0 .INDENT 3.5 You can change the location of the winrepo directory. However, it must -always be set to a path that is inside the \fBfile_roots\fP\&. -Otherwise the software definition files will be unreachable by the minion. +always be set to a path that is inside the \fBfile_roots\fP\&. Otherwise, the +software definition files will be unreachable by the minion. .UNINDENT .UNINDENT .sp @@ -465216,134 +458470,15 @@ winrepo_remotes: [] .sp \fI\%winrepo_remotes_ng\fP (list) .sp -This setting tells the \fBwinrepo.upgate_git_repos\fP command where the next +This setting tells the \fBwinrepo.update_git_repos\fP command where the next generation winrepo is hosted. This a list of URLs to multiple git repos. The default is a list containing a single URL: .sp \fI\%https://github.com/saltstack/salt\-winrepo\-ng\fP -.SS Initialization -.SS Populate the Local Repository -.sp -The SLS files used to install Windows packages are not distributed by default -with Salt. Use the \fI\%winrepo.update_git_repos\fP -runner initialize the repository in the location specified by \fBwinrepo_dir_ng\fP -in the master config. This will pull the software definition files down from the -git repository. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-run winrepo.update_git_repos -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -If running a minion in masterless mode, the same command can be run using -\fBsalt\-call\fP\&. The repository will be initialized in the location specified by -\fBwinrepo_dir_ng\fP in the minion config. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-call \-\-local winrepo.update_git_repos -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -These commands will also sync down the legacy repo to maintain backwards -compatibility with legacy minions. See \fI\%Legacy Minions\fP -.sp -The legacy repo can be disabled by setting it to an empty list in the master or -minion config. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -winrepo_remotes: [] -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Generate the Metadata File (Legacy) -.sp -This step is only required if you are supporting legacy minions. In current -usage the metadata file is generated on the minion in the next step, Update -the Minion Database. For legacy minions the metadata file is generated on the -master using the \fI\%winrepo.genrepo\fP runner. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-run winrepo.genrepo -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Update the Minion Database -.sp -Run \fI\%pkg.refresh_db\fP on each of your -Windows minions to synchronize the package repository to the minion and build -the package database. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -# From the master -salt \-G \(aqos:windows\(aq pkg.refresh_db - -# From the minion in masterless mode -salt\-call \-\-local pkg.refresh_db -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The above command returns the following summary denoting the number of packages -that succeeded or failed to compile: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -local: - \-\-\-\-\-\-\-\-\-\- - failed: - 0 - success: - 301 - total: - 301 -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -This command can take a few minutes to complete as the software definition -files are copied to the minion and the database is generated. -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Use \fBpkg.refresh_db\fP when developing new Windows package definitions to -check for errors in the definitions against one or more Windows minions. -.UNINDENT -.UNINDENT .SS Usage .sp -After completing the configuration and initialization steps, you are ready to -manage software on your Windows minions. +After completing the configuration and initialization, you can use the Salt +package manager commands to manage software on Windows minions. .sp \fBNOTE:\fP .INDENT 0.0 @@ -465352,10 +458487,54 @@ The following example commands can be run from the master using \fBsalt\fP or on a masterless minion using \fBsalt\-call\fP .UNINDENT .UNINDENT -.SS List Installed Packages +.TS +center; +|l|l|l|. +_ +T{ +T} T{ +Command +T} T{ +Description +T} +_ +T{ +1 +T} T{ +\fI\%pkg.list_pkgs\fP +T} T{ +Displays a list of all packages installed in the system. +T} +_ +T{ +2 +T} T{ +\fI\%pkg.list_available\fP +T} T{ +Displays the versions available of a particular package to be installed. +T} +_ +T{ +3 +T} T{ +\fI\%pkg.install\fP +T} T{ +Installs a given package. +T} +_ +T{ +4 +T} T{ +\fI\%pkg.remove\fP +T} T{ +Uninstalls a given package. +T} +_ +.TE +.SS List installed packages .sp -You can get a list of packages installed on the system using -\fI\%pkg.list_pkgs\fP\&. +Use \fI\%pkg.list_pkgs\fP to display a list of +packages installed on the system. .INDENT 0.0 .INDENT 3.5 .sp @@ -465371,8 +458550,9 @@ salt\-call \-\-local pkg.list_pkgs .UNINDENT .UNINDENT .sp -This will return all software installed on the system whether it is managed by -Salt or not as shown below: +The command displays the software name and the version for every package +installed on the system irrespective of whether it was installed by the Salt +package manager. .INDENT 0.0 .INDENT 3.5 .sp @@ -465399,19 +458579,23 @@ local: .UNINDENT .UNINDENT .sp -You can tell by how the software name is displayed which software is managed by -Salt and which software is not. When Salt finds a match in the winrepo database -it displays the short name as defined in the software definition file. It is -usually a single\-word, lower\-case name. All other software names will be -displayed with the full name as they are shown in Add/Remove Programs. So, in -the return above, you can see that Git (git), Nullsoft Installer (nsis), Python -3.7 (python3_x64) and Salt (salt\-minion\-py3) all have a corresponding software -definition file. The others do not. -.SS List Available Versions +The software name indicates whether the software is managed by Salt or not. .sp -You can query the available version of a package using -\fI\%pkg.list_available\fP and passing the -name of the software: +If Salt finds a match in the winrepo database, then the software name is the +short name as defined in the package definition file. It is usually a +single\-word, lower\-case name. +.sp +All other software names are displayed as the full name as shown in +Add/Remove Programs. In the above example, Git (git), Nullsoft Installer (nsis), +Python 3.7 (python3_x64), and Salt (salt\-minion\-py3) have corresponding package +definition files and are managed by Salt, while Frhed 1.6.0, GNU Privacy guard, +and GPG4win are not. +.SS List available versions +.sp +Use \fI\%pkg.list_available\fP to display +a list of versions of a package available for installation. You can pass the +name of the software in the command. You can refer to the software by its +\fBname\fP or its \fBfull_name\fP surrounded by quotes. .INDENT 0.0 .INDENT 3.5 .sp @@ -465427,7 +458611,7 @@ salt\-call \-\-local pkg.list_available firefox_x64 .UNINDENT .UNINDENT .sp -The above command will return the following: +The command lists all versions of Firefox available for installation. .INDENT 0.0 .INDENT 3.5 .sp @@ -465452,21 +458636,18 @@ winminion: .UNINDENT .UNINDENT .sp -As you can see, there are many versions of Firefox available for installation. -You can refer to a software package by its \fBname\fP or its \fBfull_name\fP -surrounded by quotes. -.sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -From a Linux master it is OK to use single\-quotes. However, the \fBcmd\fP -shell on Windows requires you to use double\-quotes when wrapping strings -that may contain spaces. Powershell seems to accept either one. +For a Linux master, you can surround the file name with single quotes. +However, for the \fBcmd\fP shell on Windows, use double quotes when wrapping +strings that may contain spaces. Powershell accepts either single quotes or +double quotes. .UNINDENT .UNINDENT -.SS Install a Package +.SS Install a package .sp -You can install a package using \fI\%pkg.install\fP: +Use \fI\%pkg.install\fP: to install a package. .INDENT 0.0 .INDENT 3.5 .sp @@ -465482,7 +458663,7 @@ salt\-call \-\-local pkg.install \(dqfirefox_x64\(dq .UNINDENT .UNINDENT .sp -The above will install the latest version of Firefox. +The command installs the latest version of Firefox. .INDENT 0.0 .INDENT 3.5 .sp @@ -465498,13 +458679,13 @@ salt\-call \-\-local pkg.install \(dqfirefox_x64\(dq version=74.0 .UNINDENT .UNINDENT .sp -The above will install version 74.0 of Firefox. +The command installs version 74.0 of Firefox. .sp -If a different version of the package is already installed it will be replaced -with the version in the winrepo (only if the package itself supports live +If a different version of the package is already installed, then the old version +is replaced with the version in the winrepo (only if the package supports live updating). .sp -You can also specify the full name: +You can also specify the full name of the software while installing: .INDENT 0.0 .INDENT 3.5 .sp @@ -465519,9 +458700,9 @@ salt\-call \-\-local pkg.install \(dqMozilla Firefox 17.0.1 (x86 en\-US)\(dq .fi .UNINDENT .UNINDENT -.SS Remove a Package +.SS Remove a package .sp -You can uninstall a package using \fI\%pkg.remove\fP: +Use \fI\%pkg.remove\fP to remove a package. .INDENT 0.0 .INDENT 3.5 .sp @@ -465536,28 +458717,21 @@ salt\-call \-\-local pkg.remove firefox_x64 .fi .UNINDENT .UNINDENT -.SS Software Definition Files +.SS Package definition file directory structure and naming .sp -A software definition file is a YAML/JINJA2 file that contains all the -information needed to install a piece of software using Salt. It defines -information about the package to include version, full name, flags required for -the installer and uninstaller, whether or not to use the Windows task scheduler -to install the package, where to download the installation package, etc. -.SS Directory Structure and Naming +All package definition files are stored in the location configured in the +\fBwinrepo_dir_ng\fP setting. All files in this directory with a \fB\&.sls\fP file +extension are considered package definition files. These files are evaluated to +create the metadata file on the minion. .sp -The files are stored in the location designated by the \fBwinrepo_dir_ng\fP -setting. All files in this directory that have a \fB\&.sls\fP file extension are -considered software definition files. The files are evaluated to create the -metadata file on the minion. -.sp -You can maintain standalone software definition files that point to software on -other servers or on the internet. In this case the file name would be the short -name of the software with the \fB\&.sls\fP extension, ie \fBfirefox.sls\fP\&. +You can maintain standalone package definition files that point to software on +other servers or on the internet. In this case the file name is the short name +of the software with the \fB\&.sls\fP extension, for example,\(ga\(gafirefox.sls\(ga\(ga. .sp You can also store the binaries for your software together with their software definition files in their own directory. In this scenario, the directory name -would be the short name for the software and the software definition file would -be inside that directory and named \fBinit.sls\fP\&. +is the short name for the software and the package definition file stored that +directory is named \fBinit.sls\fP\&. .sp Look at the following example directory structure on a Linux master assuming default config settings: @@ -465602,98 +458776,54 @@ srv/ .UNINDENT .UNINDENT .sp -In the above directory structure, the user has created the \fBcustom_defs\fP -directory in which to store their custom software definition files. In that -directory you see a folder for MS Office 2013 that contains all the installer -files along with a software definition file named \fBinit.sls\fP\&. The user has -also created two more standalone software definition files; \fBopenssl.sls\fP and -\fBzoom.sls\fP\&. -.sp -The \fBsalt\-winrepo\-ng\fP directory is created by the \fBwinrepo.update_git_repos\fP -command. This folder contains the clone of the git repo designated by the -\fBwinrepo_remotes_ng\fP config setting. -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -It is recommended that the user not modify the files in the -\fBsalt\-winrepo\-ng\fP directory as it will break future runs of -\fBwinrepo.update_git_repos\fP\&. -.UNINDENT -.UNINDENT -.sp -\fBWARNING:\fP -.INDENT 0.0 -.INDENT 3.5 -It is recommended that the user not place any custom software definition -files in the \fBsalt\-winrepo\-ng\fP directory. The \fBwinrepo.update_git_repos\fP -command wipes out the contents of the \fBsalt\-winrepo\-ng\fP directory each -time it is run. Any extra files stored there will be lost. -.UNINDENT -.UNINDENT -.SS Writing Software Definition Files -.sp -A basic software definition file is really easy to write if you already know -some basic things about your software: +In the above directory structure: .INDENT 0.0 .IP \(bu 2 -The full name as shown in Add/Remove Programs +The \fBcustom_defs\fP directory contains the following custom package definition +files. +.INDENT 2.0 +.IP \(bu 2 +A folder for MS Office 2013 that contains the installer files for all the +MS Office software and a package definition file named \fBinit.sls\fP\&. +.IP \(bu 2 +Two additional standalone package definition files \fBopenssl.sls\fP and +\fBzoom.sls\fP to install OpenSSl and Zoom. +.UNINDENT +.IP \(bu 2 +The \fBsalt\-winrepo\-ng\fP directory contains the clone of the git repo specified +by the \fBwinrepo_remotes_ng\fP config setting. +.UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +Do not modify the files in the \fBsalt\-winrepo\-ng\fP directory as it breaks +future runs of \fBwinrepo.update_git_repos\fP\&. +.UNINDENT +.UNINDENT +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +Do not place any custom software definition files in the \fBsalt\-winrepo\-ng\fP +directory as the \fBwinrepo.update_git_repos\fP command wipes out the contents +of the \fBsalt\-winrepo\-ng\fP directory each time it is run and any extra files +stored in the Salt winrepo are lost. +.UNINDENT +.UNINDENT +.SS Writing package definition files +.sp +You can write your own software definition file if you know: +.INDENT 0.0 +.IP \(bu 2 +The full name of the software as shown in Add/Remove Programs .IP \(bu 2 The exact version number as shown in Add/Remove Programs .IP \(bu 2 How to install your software silently from the command line .UNINDENT .sp -The software definition file itself is just a data structure written in YAML. -The top level item is a short name that Salt will use to reference the software. -There can be only one short name in the file and it must be unique across all -software definition files in the repo. This is the name that will be used to -install/remove the software. It is also the name that will appear when Salt -finds a match in the repo when running \fBpkg.list_pkgs\fP\&. -.sp -The next indentation level is the version number. There can be many of these, -but they must be unique within the file. This is also displayed in -\fBpkg.list_pkgs\fP\&. -.sp -The last indentation level contains the information Salt needs to actually -install the software. Available parameters are: -.INDENT 0.0 -.IP \(bu 2 -\fBfull_name\fP : The full name as displayed in Add/Remove Programs -.IP \(bu 2 -\fBinstaller\fP : The location of the installer binary -.IP \(bu 2 -\fBinstall_flags\fP : The flags required to install silently -.IP \(bu 2 -\fBuninstaller\fP : The location of the uninstaller binary -.IP \(bu 2 -\fBuninstall_flags\fP : The flags required to uninstall silently -.IP \(bu 2 -\fBmsiexec\fP : Use msiexec to install this package -.IP \(bu 2 -\fBallusers\fP : If this is an MSI, install to all users -.IP \(bu 2 -\fBcache_dir\fP : Cache the entire directory in the installer URL if it starts with \fBsalt://\fP -.IP \(bu 2 -\fBcache_file\fP : Cache a single file in the installer URL if it starts with \fBsalt://\fP -.IP \(bu 2 -\fBuse_scheduler\fP : Launch the installer using the task scheduler -.IP \(bu 2 -\fBsource_hash\fP : The hash sum for the installer -.UNINDENT -.sp -Usage of these parameters is demonstrated in the following examples and -discussed in more detail below. To understand these examples you\(aqll need a basic -understanding of Jinja. The following links have some basic tips and best -practices for working with Jinja in Salt: -.sp -\fI\%Understanding Jinja\fP -.sp -\fI\%Jinja\fP -.SS Example: Basic -.sp -Take a look at this basic, pure YAML example for a software definition file for -Firefox: +Here is a YAML software definition file for Firefox: .INDENT 0.0 .INDENT 3.5 .sp @@ -465717,40 +458847,157 @@ firefox_x64: .UNINDENT .UNINDENT .sp -You can see the first item is the short name for the software, in this case -\fBfirefox_x64\fP\&. It is the first line in the definition. The next line is -indented two spaces and contains the software \fBversion\fP\&. The lines following -the \fBversion\fP are indented two more spaces and contain all the information -needed to install the Firefox package. +The package definition file itself is a data structure written in YAML with +three indentation levels: +.INDENT 0.0 +.IP \(bu 2 +The first level item is a short name that Salt uses to reference the software. +This short name is used to install and remove the software and it must be +unique across all package definition files in the repo. Also, there must be +only one short name in the file. +.IP \(bu 2 +The second level item is the version number. There can be multiple version +numbers for a package but they must be unique within the file. +.UNINDENT +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +When running \fBpkg.list_pkgs\fP, the short name and version number are +displayed when Salt finds a match in the repo. Otherwise, the full package +name is displayed. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.IP \(bu 2 +The third indentation level contains all parameters that Salt needs to install +the software. The parameters are: +.INDENT 2.0 +.IP \(bu 2 +\fBfull_name\fP : The full name as displayed in Add/Remove Programs +.IP \(bu 2 +\fBinstaller\fP : The location of the installer binary +.IP \(bu 2 +\fBinstall_flags\fP : The flags required to install silently +.IP \(bu 2 +\fBuninstaller\fP : The location of the uninstaller binary +.IP \(bu 2 +\fBuninstall_flags\fP : The flags required to uninstall silently +.IP \(bu 2 +\fBmsiexec\fP : Use msiexec to install this package +.IP \(bu 2 +\fBallusers\fP : If this is an MSI, install to all users +.IP \(bu 2 +\fBcache_dir\fP : Cache the entire directory in the installer URL if it starts +with \fBsalt://\fP +.IP \(bu 2 +\fBcache_file\fP : Cache a single file in the installer URL if it starts with +\fBsalt://\fP +.IP \(bu 2 +\fBuse_scheduler\fP : Launch the installer using the task scheduler +.IP \(bu 2 +\fBsource_hash\fP : The hash sum for the installer +.UNINDENT +.UNINDENT +.SS Example package definition files +.sp +This section provides some examples of package definition files for different +use cases such as: +.INDENT 0.0 +.IP \(bu 2 +Writing a \fI\%simple package definition file\fP +.IP \(bu 2 +Writing a \fI\%JINJA templated package definition file\fP +.IP \(bu 2 +Writing a package definition file to \fI\%install the latest version of the software\fP +.IP \(bu 2 +Writing a package definition file to \fI\%install an MSI patch\fP +.UNINDENT +.sp +These examples enable you to gain a better understanding of the usage of +different file parameters. To understand the examples, you need a basic +\fI\%Understanding Jinja\fP\&. +For an exhaustive dive into Jinja, refer to the official +\fI\%Jinja Template Designer documentation\fP\&. +.SS Example: Simple +.sp +Here is a pure YAML example of a simple package definition file for Firefox: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +firefox_x64: + \(aq74.0\(aq: + full_name: Mozilla Firefox 74.0 (x64 en\-US) + installer: \(aqhttps://download\-installer.cdn.mozilla.net/pub/firefox/releases/74.0/win64/en\-US/Firefox%20Setup%2074.0.exe\(aq + install_flags: \(aq/S\(aq + uninstaller: \(aq%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe\(aq + uninstall_flags: \(aq/S\(aq + \(aq73.0.1\(aq: + full_name: Mozilla Firefox 73.0.1 (x64 en\-US) + installer: \(aqhttps://download\-installer.cdn.mozilla.net/pub/firefox/releases/73.0.1/win64/en\-US/Firefox%20Setup%2073.0.1.exe\(aq + install_flags: \(aq/S\(aq + uninstaller: \(aq%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe\(aq + uninstall_flags: \(aq/S\(aq +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +The first line is the short name of the software which is \fBfirefox_x64\fP\&. .sp \fBIMPORTANT:\fP .INDENT 0.0 .INDENT 3.5 -The package name must be unique to all other packages in the software +The short name must be unique across all other short names in the software repository. The \fBfull_name\fP combined with the version must also be unique. -They must also match exactly what is shown in Add/Remove Programs -(\fBappwiz.cpl\fP). +.UNINDENT +.UNINDENT +.sp +The second line is the \fBsoftware version\fP and is indented two spaces. +.sp +\fBIMPORTANT:\fP +.INDENT 0.0 +.INDENT 3.5 +The version number must be enclosed in quotes or the YAML parser removes the +trailing zeros. For example, if the version number \fB74.0\fP is not enclosed +within quotes, then the version number is rendered as \fB74\fP\&. +.UNINDENT +.UNINDENT +.sp +The lines following the \fBversion\fP are indented two more spaces and contain all +the information needed to install the Firefox package. +.sp +\fBIMPORTANT:\fP +.INDENT 0.0 +.INDENT 3.5 +You can specify multiple versions of software by specifying multiple version +numbers at the same indentation level as the first with its software +definition below it. .UNINDENT .UNINDENT .sp \fBIMPORTANT:\fP .INDENT 0.0 .INDENT 3.5 -The version number must be enclosed in quotes, otherwise the YAML parser -will remove trailing zeros. For example, \fI74.0\fP will just become \fI74\fP\&. +The \fBfull_name\fP must match exactly what is shown in Add/Remove Programs +(\fBappwiz.cpl\fP) .UNINDENT .UNINDENT +.SS Example: JINJA templated package definition file .sp -As you can see in the example above, a software definition file can define -multiple versions for the same piece of software. These are denoted by putting -the next version number at the same indentation level as the first with its -software definition information indented below it. -.SS Example: Jinja +JINJA is the default templating language used in package definition files. You +can use JINJA to add variables and expressions to package definition files that +get replaced with values when the \fB\&.sls\fP go through the Salt renderer. .sp -When there are tens or hundreds of versions available for a piece of software -definition file can become quite large. This is a scenario where Jinja can be -helpful. Consider the following software definition file for Firefox using -Jinja: +When there are tens or hundreds of versions available for a piece of software, +the definition file can become large and cumbersome to maintain. In this +scenario, JINJA can be used to add logic, variables, and expressions to +automatically create the package definition file for software with multiple +versions. +.sp +Here is a an example of a package definition file for Firefox that uses JINJA: .INDENT 0.0 .INDENT 3.5 .sp @@ -465776,28 +459023,26 @@ firefox_x64: .UNINDENT .UNINDENT .sp -In this example we are able to generate a software definition file that defines -how to install 12 versions of Firefox. We use Jinja to create a list of -available versions. That list is in a \fBfor loop\fP where each version is placed -in the \fBversion\fP variable. The version is inserted everywhere there is a -\fB{{ version }}\fP marker inside the \fBfor loop\fP\&. +In this example, JINJA is used to generate a package definition file that +defines how to install 12 versions of Firefox. Jinja is used to create a list of +available versions. The list is iterated through a \fBfor loop\fP where each +version is placed in the \fBversion\fP variable. The version is inserted +everywhere there is a \fB{{ version }}\fP marker inside the \fBfor loop\fP\&. .sp -You\(aqll notice that there is a single variable (\fBlang\fP) defined at the top of -the software definition. Because these files are going through the Salt renderer -many Salt modules are exposed via the \fBsalt\fP keyword. In this case it is -calling the \fBconfig.get\fP function to get a language setting that can be placed -in the minion config. If it is not there, it defaults to \fBen\-US\fP\&. -.SS Example: Latest +The single variable (\fBlang\fP) defined at the top of the package definition +identifies the language of the package. You can access the Salt modules using +the \fBsalt\fP keyword. In this case, the \fBconfig.get\fP function is invoked to +retrieve the language setting. If the \fBlang\fP variable is not defined then the +default value is \fBen\-US\fP\&. +.SS Example: Package definition file to install the latest version .sp -There are some software vendors that do not provide access to all versions of -their software. Instead they provide a single URL to what is always the latest -version. In some cases the software keeps itself up to date. One example of this -is the Google Chrome web browser. -.sp -\fI\%Chrome\fP +Some software vendors do not provide access to all versions of their software. +Instead, they provide a single URL to what is always the latest version. In some +cases, the software keeps itself up to date. One example of this is the \fI\%Google +Chrome web browser\fP\&. .sp To handle situations such as these, set the version to \fIlatest\fP\&. Here\(aqs an -example: +example of a package definition file to install the latest version of Chrome. .INDENT 0.0 .INDENT 3.5 .sp @@ -465816,23 +459061,22 @@ chrome: .UNINDENT .UNINDENT .sp -The above example shows us two things. First it demonstrates the usage of -\fBlatest\fP as the version. In this case Salt will install the version of Chrome -at the URL and report that version. +In the above example: +.INDENT 0.0 +.IP \(bu 2 +\fBVersion\fP is set to \fBlatest\fP\&. Salt then installs the latest version of +Chrome at the URL and displays that version. +.IP \(bu 2 +\fBmsiexec\fP is set to \fBTrue\fP, hence the software is installed using an MSI. +.UNINDENT +.SS Example: Package definition file to install an MSI patch .sp -The second thing to note is that this is installing software using an MSI. You -can see that \fBmsiexec\fP is set to \fBTrue\fP\&. -.SS Example: MSI Patch +For MSI installers, when the \fBmsiexec\fP parameter is set to true, the \fB/i\fP +option is used for installation, and the \fB/x\fP option is used for +uninstallation. However, when installing an MSI patch, the \fB/i\fP and \fB/x\fP +options cannot be combined. .sp -When the \fBmsiexec\fP parameter is set to \fBTrue\fP it uses the \fB/i\fP option for -installs and the \fB/x\fP option for uninstalls. This is problematic when trying -to install an MSI patch which requires the \fB/p\fP option. You can\(aqt combine the -\fB/i\fP and \fB/p\fP options. So how do you apply a patch to installed software in -winrepo using an \fB\&.msp\fP file? -.sp -One wiley contributor came up with the following solution to this problem by -using the \fB%cd%\fP environment variable. Consider the following software -definition file: +Here is an example of a package definition file to install an MSI patch: .INDENT 0.0 .INDENT 3.5 .sp @@ -465853,46 +459097,52 @@ MyApp: uninstaller: \(aq{B5B5868F\-23BA\-297A\-917D\-0DF345TF5764}\(aq uninstall_flags: \(aq/qn /norestart\(aq msiexec: True - cache_file: salt://win/repo/MyApp/MyApp.1.1.msp + cache_file: salt://win/repo\-ng/MyApp/MyApp.1.1.msp .ft P .fi .UNINDENT .UNINDENT .sp -There are a few things to note about this software definition file. First, is -the solution we are trying to solve, that of applying a patch. Version \fB1.0\fP -just installs the application using the \fB1.0\fP MSI defined in the \fBinstaller\fP -parameter. There is nothing special in the \fBinstall_flags\fP and nothing is -cached. +In the above example: +.INDENT 0.0 +.IP \(bu 2 +Version \fB1.0\fP of the software installs the application using the \fB1.0\fP +MSI defined in the \fBinstaller\fP parameter. +.IP \(bu 2 +There is no file to be cached and the \fBinstall_flags\fP parameter does not +include any special values. +.UNINDENT .sp -Version \fB1.1\fP uses the same installer, but uses the \fBcache_file\fP option to -specify a single file to cache. In order for this to work the MSP file needs to -be in the same directory as the MSI file on the \fBfile_roots\fP\&. +Version \fB1.1\fP of the software uses the same installer file as Version +\fB1.0\fP\&. Now, to apply a patch to Version 1.0, make the following changes in +the package definition file: +.INDENT 0.0 +.IP \(bu 2 +Place the patch file (MSP file) in the same directory as the installer file +(MSI file) on the \fBfile_roots\fP +.IP \(bu 2 +In the \fBcache_file\fP parameter, specify the path to the single patch file. +.IP \(bu 2 +In the \fBinstall_flags\fP parameter, add the \fB/update\fP flag and include the +path to the MSP file using the \fB%cd%\fP environment variable. \fB%cd%\fP +resolves to the current working directory, which is the location in the minion +cache where the installer file is cached. +.UNINDENT .sp -The final step to getting this to work is to add the additional \fB/update\fP flag -to the \fBinstall_flags\fP parameter. Add the path to the MSP file using the -\fB%cd%\fP environment variable. \fB%cd%\fP resolves to the current working -directory which is the location in the minion cache where the installer file is -cached. +For more information, see issue \fI\%#32780\fP\&. .sp -See issue \fI\%#32780\fP for more -details. -.sp -This same approach could be used for applying MST files for MSIs and answer -files for other types of .exe based installers. +The same approach could be used for applying MST files for MSIs and answer files +for other types of .exe\-based installers. .SS Parameters .sp -These are the parameters that can be used to generate a software definition -file. These parameters are all placed under the \fBversion\fP in the software -definition file: -.sp -Example usage can be found on the \fI\%github repo\fP +This section describes the parameters placed under the \fBversion\fP in the +package definition file. Examples can be found on the \fI\%Salt winrepo repository\fP\&. .SS full_name (str) .sp -This is the full name for the software as shown in \(dqPrograms and Features\(dq in -the control panel. You can also get this information by installing the package -manually and then running \fBpkg.list_pkgs\fP\&. Here\(aqs an example of the output -from \fBpkg.list_pkgs\fP: +The full name of the software as shown in \(dqAdd/Remove Programs\(dq. You can also +retrieve the full name of the package by installing the package manually and +then running \fBpkg.list_pkgs\fP\&. Here\(aqs an example of the output from +\fBpkg.list_pkgs\fP: .INDENT 0.0 .INDENT 3.5 .sp @@ -465914,14 +459164,11 @@ test\-2008 .UNINDENT .UNINDENT .sp -Notice the Full Name for Firefox: \fBMozilla Firefox 74.0 (x64 en\-US)\fP\&. That\(aqs -exactly what should be in the \fBfull_name\fP parameter in the software definition -file. +Notice the full Name for Firefox: \fBMozilla Firefox 74.0 (x64 en\-US)\fP\&. The +\fBfull_name\fP parameter in the package definition file must match this name. .sp -If any of the software installed on the machine matches the full name defined in -one of the software definition files in the repository the package name will be -returned. The example below shows the \fBpkg.list_pkgs\fP for a machine that has -Mozilla Firefox 74.0 installed and a software definition for that version of +The example below shows the \fBpkg.list_pkgs\fP for a machine that has Mozilla +Firefox 74.0 installed with a package definition file for that version of Firefox. .INDENT 0.0 .INDENT 3.5 @@ -465943,24 +459190,27 @@ test\-2008: .UNINDENT .UNINDENT .sp +On running \fBpkg.list_pkgs\fP, if any of the software installed on the machine +matches the full name defined in any one of the software definition files in the +repository, then the package name is displayed in the output. +.sp \fBIMPORTANT:\fP .INDENT 0.0 .INDENT 3.5 -The version number and \fBfull_name\fP need to match the output from -\fBpkg.list_pkgs\fP exactly so that the installation status can be verified -by the state system. +The version number and \fBfull_name\fP must match the output of +\fBpkg.list_pkgs\fP so that the installation status can be verified by the +state system. .UNINDENT .UNINDENT .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -It is still possible to successfully install packages using \fBpkg.install\fP, -even if the \fBfull_name\fP or the version number don\(aqt match exactly. The -module will complete successfully, but continue to display the full name -in \fBpkg.list_pkgs\fP\&. If this is happening, verify that the \fBfull_name\fP -and the \fBversion\fP match exactly what is displayed in Add/Remove -Programs. +You can successfully install packages using \fBpkg.install\fP, even if the +\fBfull_name\fP or the version number doesn\(aqt match. The module will complete +successfully, but continue to display the full name in \fBpkg.list_pkgs\fP\&. +If this is happening, verify that the \fBfull_name\fP and the \fBversion\fP +match exactly what is displayed in Add/Remove Programs. .UNINDENT .UNINDENT .sp @@ -465983,50 +459233,57 @@ minion you\(aqre testing new definitions on. .UNINDENT .SS installer (str) .sp -This is the path to the binary (\fB\&.exe\fP, \fB\&.msi\fP) that will install the -package. This can be a local path or a URL. If it is a URL or a Salt path -(\fBsalt://\fP), the package will be cached locally and then executed. If it is a -path to a file on disk or a file share, it will be executed directly. +The path to the binary (\fB\&.exe\fP, \fB\&.msi\fP) that installs the package. +.sp +This can be a local path or a URL. If it is a URL or a Salt path (\fBsalt://\fP), +then the package is cached locally and then executed. If it is a path to a file +on disk or a file share, then it is executed directly. .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -When storing software in the same location as the winrepo it is usually best -practice to place each installer in its own directory rather than in the -root of winrepo. +When storing software in the same location as the winrepo: +.INDENT 0.0 +.IP \(bu 2 +Create a sub folder named after the package. +.IP \(bu 2 +Store the package definition file named \fBinit.sls\fP and the binary +installer in the same sub folder if you are hosting those files on the +\fBfile_roots\fP\&. +.UNINDENT +.UNINDENT +.UNINDENT .sp -Best practice is to create a sub folder named after the package. That folder -will contain the software definition file named \fBinit.sls\fP\&. The binary -installer should be stored in that directory as well if you\(aqre hosting those -files on the file_roots. -.sp -\fBpkg.refresh_db\fP will process all \fB\&.sls\fP files in all sub directories -in the \fBwinrepo_dir_ng\fP directory. +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +The \fBpkg.refresh_db\fP command processes all \fB\&.sls\fP files in all sub +directories in the \fBwinrepo_dir_ng\fP directory. .UNINDENT .UNINDENT .SS install_flags (str) .sp -This setting contains any flags that need to be passed to the installer to make -it perform a silent install. These can often be found by adding \fB/?\fP or \fB/h\fP -when running the installer from the command\-line. A great resource for finding -these silent install flags is the WPKG project \fI\%wiki\fP: +The flags passed to the installer for silent installation. +.sp +You may be able to find these flags by adding \fB/?\fP or \fB/h\fP when running the +installer from the command line. See \fI\%WPKG project wiki\fP for information on silent install flags. .sp \fBWARNING:\fP .INDENT 0.0 .INDENT 3.5 -Salt will appear to hang if the installer is expecting user input. So it is -imperative that the software have the ability to install silently. +Always ensure that the installer has the ability to install silently, +otherwise Salt appears to hang while the installer waits for user input. .UNINDENT .UNINDENT .SS uninstaller (str) .sp -This is the path to the program used to uninstall this software. This can be the -path to the same \fBexe\fP or \fBmsi\fP used to install the software. Exe -uninstallers are pretty straight forward. MSIs, on the other hand, can be -handled a couple different ways. You can use the GUID for the software to -uninstall or you can use the same MSI used to install the software. +The path to the program to uninstall the software. .sp -You can usually find uninstall information in the registry: +This can be the path to the same \fB\&.exe\fP or \fB\&.msi\fP used to install the +software. If you use a \fB\&.msi\fP to install the software, then you can either +use the GUID of the software or the same \fB\&.msi\fP to uninstall the software. +.sp +You can find the uninstall information in the registry: .INDENT 0.0 .IP \(bu 2 Software\eMicrosoft\eWindows\eCurrentVersion\eUninstall @@ -466034,7 +459291,7 @@ Software\eMicrosoft\eWindows\eCurrentVersion\eUninstall Software\eWOW6432Node\eMicrosoft\eWindows\eCurrentVersion\eUninstall .UNINDENT .sp -Here\(aqs an example using the GUID to uninstall software. +Here\(aqs an example that uses the GUID to uninstall software: .INDENT 0.0 .INDENT 3.5 .sp @@ -466053,7 +459310,7 @@ Here\(aqs an example using the GUID to uninstall software. .UNINDENT .UNINDENT .sp -Here\(aqs an example using the same MSI used to install the software: +Here\(aqs an example that uses the MSI installer to uninstall software: .INDENT 0.0 .INDENT 3.5 .sp @@ -466073,22 +459330,22 @@ Here\(aqs an example using the same MSI used to install the software: .UNINDENT .SS uninstall_flags (str) .sp -This setting contains any flags that need to be passed to the uninstaller to -make it perform a silent uninstall. These can often be found by adding \fB/?\fP or -\fB/h\fP when running the uninstaller from the command\-line. A great resource for -finding these silent install flags the WPKG project \fI\%wiki\fP: +The flags passed to the uninstaller for silent uninstallation. +.sp +You may be able to find these flags by adding \fB/?\fP or \fB/h\fP when running the +uninstaller from the command\-line. See \fI\%WPKG project wiki\fP for information on silent uninstall flags. .sp \fBWARNING:\fP .INDENT 0.0 .INDENT 3.5 -Salt will appear to hang if the uninstaller is expecting user input. So it -is imperative that the software have the ability to uninstall silently. +Always ensure that the installer has the ability to uninstall silently, +otherwise Salt appears to hang while the uninstaller waits for user input. .UNINDENT .UNINDENT .SS msiexec (bool, str) .sp -This tells Salt to use \fBmsiexec /i\fP to install the package and \fBmsiexec /x\fP -to uninstall. This is for \fB\&.msi\fP installations only. +This setting informs Salt to use \fBmsiexec /i\fP to install the package and \fBmsiexec /x\fP +to uninstall. This setting only applies to \fB\&.msi\fP installations. .sp Possible options are: .INDENT 0.0 @@ -466123,19 +459380,21 @@ install the software for all users. The default is \fBTrue\fP\&. .SS cache_dir (bool) .sp This setting requires the software to be stored on the \fBfile_roots\fP and only -applies to URLs that begin with \fBsalt://\fP\&. If \fBTrue\fP the entire directory -where the installer resides will be recursively cached. This is useful for -installers that depend on other files in the same directory for installation. +applies to URLs that begin with \fBsalt://\fP\&. If set to \fBTrue\fP, then the +entire directory where the installer resides is recursively cached. This is +useful for installers that depend on other files in the same directory for +installation. .sp \fBWARNING:\fP .INDENT 0.0 .INDENT 3.5 -Be aware that all files and directories in the same location as the -installer file will be copied down to the minion. If you place your -software definition file in the root of winrepo (\fB/srv/salt/win/repo\-ng\fP) -and it contains \fBcache_dir: True\fP the entire contents of winrepo will be -cached to the minion. Therefore, it is best practice to place your installer -files in a subdirectory if they are to be stored in winrepo. +If set to \fBTrue\fP, then all files and directories in the same location as +the installer file are copied down to the minion. For example, if you place +your package definition file with \fBcache_dir: True\fP in the root of winrepo +(\fB/srv/salt/win/repo\-ng\fP) then the entire contents of winrepo is cached to +the minion. Therefore, it is best practice to place your package definition +file along with its installer files in a subdirectory if they are stored in +winrepo. .UNINDENT .UNINDENT .sp @@ -466158,33 +459417,33 @@ sqlexpress: .SS cache_file (str) .sp This setting requires the file to be stored on the \fBfile_roots\fP and only -applies to URLs that begin with \fBsalt://\fP\&. It indicates a single file to copy -down for use with the installer. It is copied to the same location as the -installer. Use this over \fBcache_dir\fP if there are many files in the directory -and you only need a specific file and don\(aqt want to cache additional files that -may reside in the installer directory. +applies to URLs that begin with \fBsalt://\fP\&. It indicates that the single file +specified is copied down for use with the installer. It is copied to the same +location as the installer. Use this setting instead of \fBcache_dir\fP when you +only need to cache a single file. .SS use_scheduler (bool) .sp -If set to \fBTrue\fP, Windows will use the task scheduler to run the installation. -A one\-time task will be created in the task scheduler and launched. The return -to the minion will be that the task was launched successfully, not that the -software was installed successfully. +If set to \fBTrue\fP, Windows uses the task scheduler to run the installation. A +one\-time task is created in the task scheduler and launched. The return to the +minion is that the task was launched successfully, not that the software was +installed successfully. .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -This is used by the software definition for Salt itself. The first thing the +This is used in the package definition for Salt itself. The first thing the Salt installer does is kill the Salt service, which then kills all child processes. If the Salt installer is launched via Salt, then the installer -itself is killed leaving Salt on the machine but not running. Use of the -task scheduler allows an external process to launch the Salt installation so -its processes aren\(aqt killed when the Salt service is stopped. +is killed with the salt\-minion service, leaving Salt on the machine but not +running. Using the task scheduler allows an external process to launch the +Salt installer so its processes aren\(aqt killed when the Salt service is +stopped. .UNINDENT .UNINDENT .SS source_hash (str) .sp -This tells Salt to compare a hash sum of the installer to the provided hash sum -before execution. The value can be formatted as \fB=\fP, +This setting informs Salt to compare a hash sum of the installer to the provided +hash sum before execution. The value can be formatted as \fB=\fP, or it can be a URI to a file containing the hash sum. .sp For a list of supported algorithms, see the \fI\%hashlib documentation\fP\&. @@ -466211,7 +459470,7 @@ messageanalyzer: .SS Not Implemented .sp The following parameters are often seen in the software definition files hosted -on the Git repo. However, they are not implemented and have no effect on the +on the Git repo. However, they are not implemented and do not affect the installation process. .INDENT 0.0 .TP @@ -466226,11 +459485,10 @@ Not implemented The Windows Software Repository functions similarly in a standalone environment, with a few differences in the configuration. .sp -To replace the winrepo runner that is used on the Salt master, an -\fBexecution module\fP exists to provide the same -functionality to standalone minions. The functions are named the same as the -ones in the runner, and are used in the same way; the only difference is that -\fBsalt\-call\fP is used instead of \fBsalt\-run\fP: +To replace the winrepo runner used on the Salt master, an \fBexecution module\fP exists to provide the same functionality to standalone +minions. The functions for the module share the same names with functions in the +runner and are used in the same way; the only difference is that \fBsalt\-call\fP +is used instead of \fBsalt\-run\fP to run those functions: .INDENT 0.0 .INDENT 3.5 .sp @@ -466243,25 +459501,31 @@ salt\-call pkg.refresh_db .UNINDENT .UNINDENT .sp -After executing the previous commands the repository on the standalone system is -ready for use. +After executing the previous commands, the repository on the standalone system +is ready for use. .SS Troubleshooting -.SS My software installs correctly but pkg.installed says it failed +.SS My software installs correctly but \fBpkg.installed\fP says it failed .sp -If you have a package that seems to install properly, but Salt reports a failure +If you have a package that seems to install properly but Salt reports a failure then it is likely you have a \fBversion\fP or \fBfull_name\fP mismatch. -.sp -Check the exact \fBfull_name\fP and \fBversion\fP as shown in Add/Remove Programs -(\fBappwiz.cpl\fP). Use \fBpkg.list_pkgs\fP to check that the \fBfull_name\fP and -\fBversion\fP exactly match what is installed. Make sure the software definition -file has the exact value for \fBfull_name\fP and that the version matches exactly. -.sp -Also, make sure the version is wrapped in single quotes in the software +.INDENT 0.0 +.IP \(bu 2 +Check the \fBfull_name\fP and \fBversion\fP of the package as shown in Add/Remove +Programs (\fBappwiz.cpl\fP). +.IP \(bu 2 +Use \fBpkg.list_pkgs\fP to check that the \fBfull_name\fP and \fBversion\fP exactly +match what is installed. +.IP \(bu 2 +Verify that the \fBfull_name\fP and \fBversion\fP in the package definition file +match the full name and version in Add/Remove programs. +.IP \(bu 2 +Ensure that the \fBversion\fP is wrapped in single quotes in the package definition file. -.SS Changes to sls files not being picked up +.UNINDENT +.SS Changes to package definition files not being picked up .sp -You may have recently updated some of the software definition files on the repo. -Ensure you have refreshed the database on the minion. +Make sure you refresh the database on the minion (\fBpkg.refresh_db\fP) after +updating package definition files in the repo. .INDENT 0.0 .INDENT 3.5 .sp @@ -466272,75 +459536,33 @@ salt winminion pkg.refresh_db .fi .UNINDENT .UNINDENT -.SS How Success and Failure are Reported by pkg.installed -.sp -The install state/module function of the Windows package manager works roughly -as follows: -.INDENT 0.0 -.IP 1. 3 -Execute \fBpkg.list_pkgs\fP to get a list of software currently on the machine -.IP 2. 3 -Compare the requested version with the installed version -.IP 3. 3 -If versions are the same, report no changes needed -.IP 4. 3 -Install the software as described in the software definition file -.IP 5. 3 -Execute \fBpkg.list_pkgs\fP to get a new list of software currently on the -machine -.IP 6. 3 -Compare the requested version with the new installed version -.IP 7. 3 -If versions are the same, report success -.IP 8. 3 -If versions are different, report failure -.UNINDENT -.SS Winrepo Upgrade Issues +.SS Winrepo upgrade issues .sp To minimize potential issues, it is a good idea to remove any winrepo git repositories that were checked out by the legacy (pre\-2015.8.0) winrepo code -when upgrading the master to 2015.8.0 or later. Run -\fI\%winrepo.update_git_repos\fP to -clone them anew after the master is started. -.SS \fI\%pygit2\fP/\fI\%GitPython\fP Support for Maintaining Git Repos +when upgrading the master to 2015.8.0 or later. Run \fI\%winrepo.update_git_repos\fP to clone them anew after the master is +started. +.SS pygit2 / GitPython Support for Maintaining Git Repos .sp -The \fI\%winrepo.update_git_repos\fP -runner now makes use of the same underlying code used by the \fI\%Git Fileserver Backend\fP -and \fI\%Git External Pillar\fP to maintain and update -its local clones of git repositories. If a compatible version of either \fI\%pygit2\fP -(0.20.3 and later) or \fI\%GitPython\fP (0.3.0 or later) is installed, Salt will use it -instead of the old method (which invokes the \fI\%git.latest\fP -state). +pygit2 and GitPython are the supported python interfaces to Git. The runner +\fI\%winrepo.update_git_repos\fP uses the +same underlying code as \fI\%Git Fileserver Backend\fP and +\fI\%Git External Pillar\fP to maintain and update its +local clones of git repositories. .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -If compatible versions of both \fI\%pygit2\fP and \fI\%GitPython\fP are installed, then -Salt will prefer \fI\%pygit2\fP\&. To override this behavior use the -\fI\%winrepo_provider\fP configuration parameter: -.INDENT 0.0 -.INDENT 3.5 +If compatible versions of both pygit2 and GitPython are installed, then +Salt will prefer pygit2. To override this behavior use the +\fI\%winrepo_provider\fP configuration parameter, ie: +\fBwinrepo_provider: gitpython\fP +.UNINDENT +.UNINDENT +.SS Accessing authenticated Git repos (pygit2) .sp -.nf -.ft C -winrepo_provider: gitpython -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -The \fBwinrepo execution module\fP (discussed -above in the \fI\%Managing Windows Software on a Standalone Windows Minion\fP section) does not yet officially support the new -\fI\%pygit2\fP/\fI\%GitPython\fP functionality, but if either \fI\%pygit2\fP or \fI\%GitPython\fP is -installed into Salt\(aqs bundled Python then it \fIshould\fP work. However, it -should be considered experimental at this time. -.UNINDENT -.UNINDENT -.SS Accessing Authenticated Git Repos (pygit2) -.sp -Support for pygit2 added the ability to access authenticated git repositories -and to set per\-remote config settings. An example of this would be the -following: +pygit2 enables you to access authenticated git repositories and set per\-remote +config settings. An example of this is: .INDENT 0.0 .INDENT 3.5 .sp @@ -466363,26 +459585,25 @@ winrepo_remotes: \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 -Per\-remote configuration settings work in the same fashion as they do in +The per\-remote configuration settings work in the same manner as they do in gitfs, with global parameters being overridden by their per\-remote -counterparts. For instance, setting \fI\%winrepo_passphrase\fP would -set a global passphrase for winrepo that would apply to all SSH\-based +counterparts. For instance, setting \fI\%winrepo_passphrase\fP +sets a global passphrase for winrepo that applies to all SSH\-based remotes, unless overridden by a \fBpassphrase\fP per\-remote parameter. .sp -See \fI\%here\fP for more a more in\-depth +See \fI\%here\fP for a detailed explanation of how per\-remote configuration works in gitfs. The same principles apply to winrepo. .UNINDENT .UNINDENT -.SS Maintaining Git Repos +.SS Maintaining Git repos .sp -A \fBclean\fP argument has been added to the +A \fBclean\fP argument is added to the \fI\%winrepo.update_git_repos\fP -runner. When \fBclean\fP is \fBTrue\fP it will tell the runner to dispose of +runner to maintain the Git repos. When \fBclean=True\fP the runner removes directories under the \fI\%winrepo_dir_ng\fP/\fI\%winrepo_dir_ng\fP -which are not explicitly configured. This prevents the need to manually remove -these directories when a repo is removed from the config file. To clean these -old directories, just pass \fBclean=True\fP: +that are not explicitly configured. This eliminates the need to manually remove +these directories when a repo is removed from the config file. .INDENT 0.0 .INDENT 3.5 .sp @@ -466394,15 +459615,15 @@ salt\-run winrepo.update_git_repos clean=True .UNINDENT .UNINDENT .sp -If a mix of git and non\-git Windows Repo definition files are being used, then -this should \fInot\fP be used, as it will remove the directories containing non\-git +If a mix of git and non\-git Windows Repo definition files are used, then +do not pass \fBclean=True\fP, as it removes the directories containing non\-git definitions. -.SS Name Collisions Between Repos +.SS Name collisions between repos .sp -Collisions between repo names are now detected. The +Salt detects collisions between repository names. The \fI\%winrepo.update_git_repos\fP -runner will not proceed if any are detected. Consider the following -configuration: +runner does not execute successfully if any collisions between repository names +are detected. Consider the following configuration: .INDENT 0.0 .INDENT 3.5 .sp @@ -466411,16 +459632,16 @@ configuration: winrepo_remotes: \- https://foo.com/bar/baz.git \- https://mydomain.tld/baz.git - \- https://github.com/foobar/baz + \- https://github.com/foobar/baz.git .ft P .fi .UNINDENT .UNINDENT .sp -The \fI\%winrepo.update_git_repos\fP -runner will refuse to update repos here, as all three of these repos would be -checked out to the same directory. To work around this, a per\-remote parameter -called \fBname\fP can be used to resolve these conflicts: +With the above configuration, the \fI\%winrepo.update_git_repos\fP +runner fails to execute as all three repos would be checked out to the same +directory. To resolve this conflict, use the per\-remote parameter called +\fBname\fP\&. .INDENT 0.0 .INDENT 3.5 .sp @@ -466430,297 +459651,22 @@ winrepo_remotes: \- https://foo.com/bar/baz.git \- https://mydomain.tld/baz.git: \- name: baz_junior - \- https://github.com/foobar/baz: + \- https://github.com/foobar/baz.git: \- name: baz_the_third .ft P .fi .UNINDENT .UNINDENT -.SS Legacy Minions .sp -The Windows Package Manager was upgraded with breaking changes starting with -Salt 2015.8.0. To maintain backwards compatibility Salt continues to support -older minions. -.sp -The breaking change was to generate the winrepo database on the minion instead -of the master. This allowed for the use of Jinja in the software definition -files. It enabled the use of pillar, grains, execution modules, etc. during -compile time. To support this new functionality, a next\-generation (ng) repo was -created. -.sp -See the \fI\%Changes in Version 2015.8.0\fP for -details. -.sp -On prior versions of Salt, or legacy minions, the winrepo database was -generated on the master and pushed down to the minions. Any grains exposed at -compile time would have been those of the master and not the minion. -.sp -The repository for legacy minions is named \fBsalt\-winrepo\fP and is located at: +Now on running the \fI\%winrepo.update_git_repos\fP: .INDENT 0.0 .IP \(bu 2 -\fI\%https://github.com/saltstack/salt\-winrepo\fP -.UNINDENT -.SS Legacy Configuration -.sp -Winrepo settings were changed with the introduction of the Next Generation (ng) -of winrepo. -.SS Legacy Master Config Options -.sp -There were three options available for a legacy master to configure winrepo. -Unless you\(aqre running a legacy master as well, you shouldn\(aqt need to configure -any of these. -.INDENT 0.0 +\fI\%https://foo.com/bar/baz.git\fP repo is initialized and cloned under the \fBwin_repo_dir_ng\fP directory. .IP \(bu 2 -\fBwin_gitrepos\fP +\fI\%https://mydomain.tld/baz.git\fP repo is initialized and cloned under the \fBwin_repo_dir_ng\ebaz_junior\fP directory. .IP \(bu 2 -\fBwin_repo\fP -.IP \(bu 2 -\fBwin_repo_mastercachefile\fP +\fI\%https://github.com/foobar/baz.git\fP repo is initialized and cloned under the \fBwin_repo_dir_ng\ebaz_the_third\fP directory. .UNINDENT -.sp -\fBwin_gitrepos\fP: (list) -.sp -A list of URLs to github repos. Default is a list with a single URL: -.INDENT 0.0 -.IP \(bu 2 -\(aq\fI\%https://github.com/saltstack/salt\-winrepo.git\fP\(aq -.UNINDENT -.sp -\fBwin_repo\fP: (str) -.sp -The location on the master to store the winrepo. The default is -\fB/srv/salt/win/repo\fP\&. -.sp -\fBwin_repo_mastercachefile\fP: (str) -The location on the master to generate the winrepo database file. The default is -\fB/srv/salt/win/repo/winrep.p\fP -.SS Legacy Minion Config Options -.sp -There is only one option available to configure a legacy minion for winrepo. -.INDENT 0.0 -.IP \(bu 2 -\fBwin_repo_cachefile\fP -.UNINDENT -.sp -\fBwin_repo_cachefile\fP: (str) -.sp -The location on the Salt file server to obtain the winrepo database file. The -default is \fBsalt://win/repo/winrepo.p\fP -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -If the location of the \fBwinrepo.p\fP file is not in the default location on -the master, the \fI\%win_repo_cachefile\fP setting will need to be -updated to reflect the proper location on each minion. -.UNINDENT -.UNINDENT -.SS Legacy Quick Start -.sp -You can get up and running with winrepo pretty quickly just using the defaults. -Assuming no changes to the default configuration (ie, \fBfile_roots\fP) run the -following commands on the master: -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-run winrepo.update_git_repos -salt\-run winrepo.genrepo -salt * pkg.refresh_db -salt * pkg.install firefox -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -These commands clone the default winrepo from github, generate the metadata -file, push the metadata file down to the legacy minion, and install the latest -version of Firefox. -.SS Legacy Initialization -.sp -Initializing the winrepo for a legacy minion is similar to that for a newer -minion. There is an added step in that the metadata file needs to be generated -on the master prior to refreshing the database on the minion. -.SS Populate the Local Repository -.sp -The SLS files used to install Windows packages are not distributed by default -with Salt. So, the first step is to clone the repo to the master. Use the -\fI\%winrepo.update_git_repos\fP -runner initialize the repository in the location specified by \fBwinrepo_dir\fP -in the master config. This will pull the software definition files down from the -git repository. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-run winrepo.update_git_repos -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Generate the Metadata File -.sp -The next step is to create the metadata file for the repo (\fBwinrepo.p\fP). -The metadata file is generated on the master using the -\fI\%winrepo.genrepo\fP runner. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -salt\-run winrepo.genrepo -.ft P -.fi -.UNINDENT -.UNINDENT -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -You only need to do this if you need to support legacy minions. -.UNINDENT -.UNINDENT -.SS Update the Minion Database -.sp -Run \fI\%pkg.refresh_db\fP on each of your -Windows minions to copy the metadata file down to the minion. -.INDENT 0.0 -.INDENT 3.5 -.sp -.nf -.ft C -# From the master -salt \-G \(aqos:windows\(aq pkg.refresh_db -.ft P -.fi -.UNINDENT -.UNINDENT -.SS Changes in Version 2015.8.0+ -.sp -Git repository management for the Windows Software Repository changed in version -2015.8.0, and several master/minion config parameters were renamed for -consistency. -.sp -For a complete list of the new winrepo config options, see -\fI\%here\fP for master config options, and -\fI\%here\fP for configuration options for masterless Windows -minions. -.SS \fI\%pygit2\fP/\fI\%GitPython\fP Support -.sp -On the master, the -\fI\%winrepo.update_git_repos\fP -runner was updated to use either \fI\%pygit2\fP or \fI\%GitPython\fP to checkout the git -repositories containing repo data. If \fI\%pygit2\fP or \fI\%GitPython\fP is installed, -existing winrepo git checkouts should be removed after upgrading to 2015.8.0. -Then they should be cloned again by running -\fI\%winrepo.update_git_repos\fP\&. -.sp -If neither \fI\%GitPython\fP nor \fI\%pygit2\fP are installed, Salt will fall back to -pre\-existing behavior for -\fI\%winrepo.update_git_repos\fP, and a -warning will be logged in the master log. -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -Standalone Windows minions do not support the new \fI\%GitPython\fP/\fI\%pygit2\fP -functionality, and will instead use the -\fI\%git.latest\fP state to keep repositories -up\-to\-date. More information on how to use the Windows Software Repo on a -standalone minion can be found \fI\%here\fP\&. -.UNINDENT -.UNINDENT -.SS Config Parameters Renamed -.sp -Many of the legacy winrepo configuration parameters changed in version 2015.8.0 -to make them more consistent. Below are the parameters which changed for -version 2015.8.0: -.sp -Master Config -.TS -center; -|l|l|. -_ -T{ -Old Name -T} T{ -New Name -T} -_ -T{ -win_repo -T} T{ -\fI\%winrepo_dir\fP -T} -_ -T{ -win_repo_mastercachefile -T} T{ -No longer used on master -T} -_ -T{ -win_gitrepos -T} T{ -\fI\%winrepo_remotes\fP -T} -_ -.TE -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -The \fBwinrepo_dir_ng\fP and \fBwinrepo_remotes_ng\fP settings were introduced -in 2015.8.0 for working with the next generation repo. -.UNINDENT -.UNINDENT -.sp -See \fI\%here\fP for detailed information on all -master config options for the Windows Repo. -.sp -Minion Config -.TS -center; -|l|l|. -_ -T{ -Old Name -T} T{ -New Name -T} -_ -T{ -win_repo -T} T{ -\fI\%winrepo_dir\fP -T} -_ -T{ -win_repo_cachefile -T} T{ -\fI\%winrepo_cachefile\fP -T} -_ -T{ -win_gitrepos -T} T{ -\fI\%winrepo_remotes\fP -T} -_ -.TE -.sp -\fBNOTE:\fP -.INDENT 0.0 -.INDENT 3.5 -The \fBwinrepo_dir_ng\fP and \fBwinrepo_remotes_ng\fP settings were introduced -in 2015.8.0 for working with the next generation repo. -.UNINDENT -.UNINDENT -.sp -See \fI\%here\fP for detailed information on all -minion config options for the Windows Repo. .SS Windows\-specific Behaviour .sp Salt is capable of managing Windows systems, however due to various differences @@ -468188,6 +461134,10 @@ Development begins on \fBAluminium\fP, or \fBv3003\fP, after the \fBv3002\fP tag applied to the \fBmaster\fP branch. Once this occurs, all uses of the \fBwarn_until\fP function targeting \fBAluminium\fP, along with the code they are warning about should be removed from the code. +.SS Silence Deprecation Warnings +.sp +If you set the \fIPYTHONWARNINGS\fP environment variable to \fIignore\fP Salt will +not print the deprecation warnings. .SS Python 2 Deprecation FAQ .SS FAQ .INDENT 0.0 @@ -469810,6 +462760,92 @@ Please be certain to scrub any logs or SLS files for sensitive data! .UNINDENT .UNINDENT .UNINDENT +.SS Salt Extensions +.sp +Salt modules can be distributed as Salt Extensions. +.sp +The existing Salt modules will be carved up into one of three categories. Each category will be +implemented in the following way: +.sp +## Core Modules +.sp +Core Modules will be kept inside the main Salt codebase, and development will be tied to the +Salt release cycle. +.sp +## Supported Modules +.sp +Supported modules will be moved to their own repositories within the SaltStack Github +organization where they can be maintained separately from the Salt codebase. +.sp +## Community Modules +.sp +Remaining modules will be deprecated from the Salt Core codebase and community members +will be able to continue independent maintainership if they are interested. Some plugins are +almost exclusively maintained by external corporations – if these corporations wish for formal +documentation outlining transfer of ownership it can be handled on a case\-by\-case basis. The +community modules can be hosted either in individual or corporate source control systems, +alternatively they can also be hosted in the community run Salt Extensions Github organization, +that will operate like the the Salt Formulas Github organization. +The criteria to determine which category to place modules in will follow these rules: +.sp +## Core Modules +.INDENT 0.0 +.IP 1. 3 +Required Salt Functionality +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.IP a. 3 +Modules such as state, sys, peer, grains, pillar, etc. +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.IP 2. 3 +Modules critical to Salt’s Multi OS support +.UNINDENT +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.IP a. 3 +Modules that function across multiple operating systems like cmd and file. +.UNINDENT +.UNINDENT +.UNINDENT +.sp +## Supported Modules +.sp +1. Modules to support specific operating systems traditionally maintained by the core team +– such as RedHat, MacOS, Windows, Solaris, etc. +.INDENT 0.0 +.IP 2. 3 +Modules to support specific but critical applications, such as Apache, MySQL, etc. +.UNINDENT +.sp +3. Modules created and maintained as part of VMware backed support agreements and +contracts. +.sp +## Community Extension Modules +.sp +1. Modules to support specific operating systems traditionally maintained by the OS vendor +– such as SUSE, openBSD, NetBSD, etc. +.INDENT 0.0 +.IP 2. 3 +Modules to support cloud interfaces, such as AWS, Azure, etc. +.UNINDENT +.sp +3. Modules no longer maintained, or which we suspect are also no longer used or +maintained, such as moosefs, qemu_img, etc. +.SS How do I deprecate a Salt module to a Salt extension +.sp +To indicate that a Salt module is being deprecated in favor of a Salt extension, +for each Salt module include \fB__deprecated__\fP tuple in the module. The tuple +should include the version of Salt that the module will be removed, the name of the +collection of modules that are being deprecated, and the URL where the source for +the new extension can be found. The version should be 2 major versions from the +next major release. For example, if the next major release of Salt is 3100, the +deprecation version should be set to 3102. .SS Salt Topology .sp Salt is based on a powerful, asynchronous, network topology using ZeroMQ. Many @@ -470530,7 +463566,7 @@ dynamic modules when states are run. To disable this behavior set \fI\%autoload_dynamic_modules\fP to \fBFalse\fP in the minion config. .sp When dynamic modules are autoloaded via states, only the modules defined in the -same saltenvs as the states currently being run. +same saltenv as the states currently being run are synced. .SS Sync Via the saltutil Module .sp The saltutil module has a number of functions that can be used to sync all @@ -470538,6 +463574,8 @@ or specific dynamic modules. The \fBsaltutil.sync_*\fP \fI\%execution functions\fP and \fI\%runner functions\fP can be used to sync modules to minions and the master, respectively. +.sp +If saltenv environments are used (through the \fI\%top file\fP, the \fI\%environment\fP option of the minion configuration file, or as an argument on the command line) modules will be synced from the applied environments. .SS The extmods Directory .sp Any files places in the directory set by \fBextension_modules\fP settings @@ -470680,7 +463718,7 @@ _ T{ Log Handler T} T{ -\fBsalt.log.handlers\fP (\fI\%index\fP) +\fBsalt.log_handlers\fP (\fI\%index\fP) T} T{ \fBlog_handlers\fP T} T{ @@ -470842,7 +463880,7 @@ SSH Wrapper T} T{ \fBsalt.client.ssh.wrapper\fP T} T{ -\fBwrapper\fP [1] +\fBwrapper\fP T} T{ \fBwrapper_dirs\fP T} @@ -477108,6 +470146,405 @@ See the \fI\%version numbers\fP page for more information about the version numbering scheme. .UNINDENT .SS Upcoming release +(release\-3007.0)= +.SS Salt 3007.0 release notes +.SS Salt\(aqs \fBsetup.py\fP customizations +.INDENT 0.0 +.INDENT 3.5 +:warning: \fBDeprecation Notice\fP: +In Salt 3009, the \fBsetup.py\fP file will be stripped of it\(aqs custom additions and migrated to a plain \fBpyproject.toml\fP python package +or whatever is found best during the process of removing the customizations. +\fBIf you\(aqre relying on these customizations please stop as your workflow will break in the future\fP\&. +.UNINDENT +.UNINDENT +.SS Python 3.7 Support Dropped +.sp +Support for python 3.7 has been dropped since it reached end\-of\-line in 27 Jun 2023. +.SS Azure Salt Extension +.sp +Starting from Salt version 3007.0, the Azure functionality previously available in the Salt code base is fully removed. To continue using Salt\(aqs features for interacting with Azure resources, users are required to utilize the Azure Salt extension. For more information, refer to the \fI\%Azure Salt Extension GitHub repository\fP\&. +.SS New Package Grain +.sp +A new \fBpackage\fP grain was added in 3007.0 This detects how Salt was installed using the \fB_pkg.txt\fP in the root of +the directory. If you are building packages of Salt you need to ensure this file is set to the correct package type +that you are building. The options are \fBpip\fP, \fBonedir\fP, or \fBsystem\fP\&. By default this file is already set to \fBpip\fP\&. +.SS Improved Vault integration +.sp +This release features a much deeper integration with HashiCorp Vault, for which +many parts of the implementation core were improved. Among other things, the Salt +daemons now attempt to renew/revoke their access tokens and can manage long\-lived leases, +while the Salt master now distributes authentication secrets using response wrapping. +An important new feature concerns the way Vault policies can be managed. +.sp +In versions before 3006, the Salt master only issued tokens to minions, whose policies +could be templated with the minion ID and (insecure) grain values. +3006 introduced secure templating of those policies with pillar values, as well as +templating of Vault external pillar paths with pillar values. These improvements reduced the +overhead of managing Vault policies securely. +.sp +In addition, the Salt master can now be configured to issue AppRoles +to minions and manage their metadata using a similar templating approach. +Since this metadata can be taken advantage of in templated policies on the Vault side, +the need for many boilerplate policies is reduced even further: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C + path \(dqsalt/data/minions/{{identity.entity.metadata.minion\-id}}\(dq { + capabilities = [\(dqcreate\(dq, \(dqread\(dq, \(dqwrite\(dq, \(dqdelete\(dq, \(dqpatch\(dq] + } + + path \(dqsalt/data/roles/{{identity.entity.metadata.role}}\(dq { + capabilities = [\(dqread\(dq] + } + +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Although existing configurations will keep working without intervention after upgrading +the Salt master, it is strongly recommended to adjust the \fBpeer_run\fP configuration to +include the new issuance endpoints in order to avoid unnecessary overhead: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +peer_run: + .*: + \- vault.get_config + \- vault.generate_new_token + +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Please see the \fI\%Vault execution module docs\fP for +details and setup instructions regarding AppRole issuance. +.sp +Note: The Vault modules are being moved to a \fI\%Salt extension\fP, +but this improvement has still been merged into core for a smoother transition. +.SS Changelog +.SS Removed +.INDENT 0.0 +.IP \(bu 2 +Removed RHEL 5 support since long since end\-of\-lifed \fI\%#62520\fP +.IP \(bu 2 +Removing Azure\-Cloud modules from the code base. \fI\%#64322\fP +.IP \(bu 2 +Dropped Python 3.7 support since it\(aqs EOL in 27 Jun 2023 \fI\%#64417\fP +.IP \(bu 2 +Remove salt.payload.Serial \fI\%#64459\fP +.IP \(bu 2 +Remove netmiko_conn and pyeapi_conn from salt.modules.napalm_mod \fI\%#64460\fP +.IP \(bu 2 +Removed \(aqtransport\(aq arg from salt.utils.event.get_event \fI\%#64461\fP +.IP \(bu 2 +Removed the usage of retired Linode API v3 from Salt Cloud \fI\%#64517\fP +.UNINDENT +.SS Deprecated +.INDENT 0.0 +.IP \(bu 2 +Deprecate all Proxmox cloud modules \fI\%#64224\fP +.IP \(bu 2 +Deprecate all the Vault modules in favor of the Vault Salt Extension \fI\%https://github.com/salt\-extensions/saltext\-vault\fP\&. The Vault modules will be removed in Salt core in 3009.0. \fI\%#64893\fP +.IP \(bu 2 +Deprecate all the Docker modules in favor of the Docker Salt Extension \fI\%https://github.com/saltstack/saltext\-docker\fP\&. The Docker modules will be removed in Salt core in 3009.0. \fI\%#64894\fP +.IP \(bu 2 +Deprecate all the Zabbix modules in favor of the Zabbix Salt Extension \fI\%https://github.com/salt\-extensions/saltext\-zabbix\fP\&. The Zabbix modules will be removed in Salt core in 3009.0. \fI\%#64896\fP +.IP \(bu 2 +Deprecate all the Apache modules in favor of the Apache Salt Extension \fI\%https://github.com/salt\-extensions/saltext\-apache\fP\&. The Apache modules will be removed in Salt core in 3009.0. \fI\%#64909\fP +.IP \(bu 2 +Deprecation warning for Salt\(aqs backport of \fBOrderedDict\fP class which will be removed in 3009 \fI\%#65542\fP +.IP \(bu 2 +Deprecate Kubernetes modules for move to saltext\-kubernetes in version 3009 \fI\%#65565\fP +.IP \(bu 2 +Deprecated all Pushover modules in favor of the Salt Extension at \fI\%https://github.com/salt\-extensions/saltext\-pushover\fP\&. The Pushover modules will be removed from Salt core in 3009.0 \fI\%#65567\fP +.IP \(bu 2 +Removed deprecated code: +.INDENT 2.0 +.IP \(bu 2 +All of \fBsalt/log/\fP which has been on a deprecation path for a long time. +.IP \(bu 2 +Some of the logging handlers found in \fBsalt/_logging/handlers\fP have been removed since the standard library provides +them. +.IP \(bu 2 +Removed the deprecated \fBsalt/modules/cassandra_mod.py\fP module and any tests for it. +.IP \(bu 2 +Removed the deprecated \fBsalt/returners/cassandra_return.py\fP module and any tests for it. +.IP \(bu 2 +Removed the deprecated \fBsalt/returners/django_return.py\fP module and any tests for it. \fI\%#65986\fP +.UNINDENT +.UNINDENT +.SS Changed +.INDENT 0.0 +.IP \(bu 2 +Masquerade property will not default to false turning off masquerade if not specified. \fI\%#53120\fP +.IP \(bu 2 +Addressed Python 3.11 deprecations: +.INDENT 2.0 +.IP \(bu 2 +Switch to \fBFullArgSpec\fP since Py 3.11 no longer has \fBArgSpec\fP, deprecated since Py 3.0 +.IP \(bu 2 +Stopped using the deprecated \fBcgi\fP module. +.IP \(bu 2 +Stopped using the deprecated \fBpipes\fP module +.IP \(bu 2 +Stopped using the deprecated \fBimp\fP module \fI\%#64457\fP +.UNINDENT +.IP \(bu 2 +changed \(aqgpg_decrypt_must_succeed\(aq default from False to True \fI\%#64462\fP +.UNINDENT +.SS Fixed +.INDENT 0.0 +.IP \(bu 2 +When an NFS or FUSE mount fails to unmount when mount options have changed, try again with a lazy umount before mounting again. \fI\%#18907\fP +.IP \(bu 2 +fix autoaccept gpg keys by supporting it in refresh_db module \fI\%#42039\fP +.IP \(bu 2 +Made cmd.script work with files from the fileserver via salt\-ssh \fI\%#48067\fP +.IP \(bu 2 +Made slsutil.renderer work with salt\-ssh \fI\%#50196\fP +.IP \(bu 2 +Fixed defaults.merge is not available when using salt\-ssh \fI\%#51605\fP +.IP \(bu 2 +Fix extfs.mkfs missing parameter handling for \-C, \-d, and \-e \fI\%#51858\fP +.IP \(bu 2 +Fixed Salt master does not renew token \fI\%#51986\fP +.IP \(bu 2 +Fixed salt\-ssh continues state/pillar rendering with incorrect data when an exception is raised by a module on the target \fI\%#52452\fP +.IP \(bu 2 +Fix extfs.tune has \(aqreserved\(aq documented twice and is missing the \(aqreserved_percentage\(aq keyword argument \fI\%#54426\fP +.IP \(bu 2 +Fix the ability of the \(aqselinux.port_policy_present\(aq state to modify. \fI\%#55687\fP +.IP \(bu 2 +Fixed config.get does not support merge option with salt\-ssh \fI\%#56441\fP +.IP \(bu 2 +Removed an unused assignment in file.patch \fI\%#57204\fP +.IP \(bu 2 +Fixed vault module fetching more than one secret in one run with single\-use tokens \fI\%#57561\fP +.IP \(bu 2 +Use brew path from which in mac_brew_pkg module and rely on _homebrew_bin() everytime \fI\%#57946\fP +.IP \(bu 2 +Fixed Vault verify option to work on minions when only specified in master config \fI\%#58174\fP +.IP \(bu 2 +Fixed vault command errors configured locally \fI\%#58580\fP +.IP \(bu 2 +Fixed issue with basic auth causing invalid header error and 401 Bad Request, by using HTTPBasicAuthHandler instead of header. \fI\%#58936\fP +.IP \(bu 2 +Make the LXD module work with pyLXD > 2.10 \fI\%#59514\fP +.IP \(bu 2 +Return error if patch file passed to state file.patch is malformed. \fI\%#59806\fP +.IP \(bu 2 +Handle failure and error information from tuned module/state \fI\%#60500\fP +.IP \(bu 2 +Fixed sdb.get_or_set_hash with Vault single\-use tokens \fI\%#60779\fP +.IP \(bu 2 +Fixed state.test does not work with salt\-ssh \fI\%#61100\fP +.IP \(bu 2 +Made slsutil.findup work with salt\-ssh \fI\%#61143\fP +.IP \(bu 2 +Allow all primitive grain types for autosign_grains \fI\%#61416\fP, \fI\%#63708\fP +.IP \(bu 2 +\fBipset.new_set\fP no longer fails when creating a set type that uses the \fBfamily\fP create option \fI\%#61620\fP +.IP \(bu 2 +Fixed Vault session storage to allow unlimited use tokens \fI\%#62380\fP +.IP \(bu 2 +fix the efi grain on FreeBSD \fI\%#63052\fP +.IP \(bu 2 +Fixed gpg.receive_keys returns success on failed import \fI\%#63144\fP +.IP \(bu 2 +Fixed GPG state module always reports success without changes \fI\%#63153\fP +.IP \(bu 2 +Fixed GPG state module does not respect test mode \fI\%#63156\fP +.IP \(bu 2 +Fixed gpg.absent with gnupghome/user, fixed gpg.delete_key with gnupghome \fI\%#63159\fP +.IP \(bu 2 +Fixed service module does not handle enable/disable if systemd service is an alias \fI\%#63214\fP +.IP \(bu 2 +Made x509_v2 compound match detection use new runner instead of peer publishing \fI\%#63278\fP +.IP \(bu 2 +Need to make sure we update \fBpillar\fP during a pillar refresh to ensure that process_beacons has the updated beacons loaded from pillar. \fI\%#63583\fP +.IP \(bu 2 +This implements the vpc_uuid parameter when creating a droplet. This parameter selects the correct virtual private cloud (private network interface). \fI\%#63714\fP +.IP \(bu 2 +pkg.installed no longer reports failure when installing packages that are installed via the task manager \fI\%#63767\fP +.IP \(bu 2 +mac_xattr.list and mac_xattr.read will replace undecode\-able bytes to avoid raising CommandExecutionError. \fI\%#63779\fP \fI\%#63779\fP +.IP \(bu 2 +Fix aptpkg.latest_version performance, reducing number of times to \(aqshell out\(aq \fI\%#63982\fP +.IP \(bu 2 +Added option to use a fresh connection for mysql cache \fI\%#63991\fP +.IP \(bu 2 +[lxd] Fixed a bug in \fBcontainer_create\fP which prevented devices which are not of type \fBdisk\fP to be correctly created and added to the container when passed via the \fBdevices\fP parameter. \fI\%#63996\fP +.IP \(bu 2 +Skipped the \fBisfile\fP check to greatly increase speed of reading minion keys for systems with a large number of minions on slow file storage \fI\%#64260\fP +.IP \(bu 2 +Fix utf8 handling in \(aqpass\(aq renderer \fI\%#64300\fP +.IP \(bu 2 +Upgade tornado to 6.3.2 \fI\%#64305\fP +.IP \(bu 2 +Prevent errors due missing \(aqtransactional_update.apply\(aq on SLE Micro and MicroOS. \fI\%#64369\fP +.IP \(bu 2 +Fix \(aqunable to unmount\(aq failure to return False result instead of None \fI\%#64420\fP +.IP \(bu 2 +Fixed issue uninstalling duplicate packages in \fBwin_appx\fP execution module \fI\%#64450\fP +.IP \(bu 2 +Clean up tech debt, IPC now uses tcp transport. \fI\%#64488\fP +.IP \(bu 2 +Made salt\-ssh more strict when handling unexpected situations and state.* wrappers treat a remote exception as failure, excluded salt\-ssh error returns from mine \fI\%#64531\fP +.IP \(bu 2 +Fix flaky test for LazyLoader with isolated mocking of threading.RLock \fI\%#64567\fP +.IP \(bu 2 +Fix possible \fBKeyError\fP exceptions in \fBsalt.utils.user.get_group_dict\fP +while reading improper duplicated GID assigned for the user. \fI\%#64599\fP +.IP \(bu 2 +changed vm_config() to deep\-merge vm_overrides of specific VM, instead of simple\-merging the whole vm_overrides \fI\%#64610\fP +.IP \(bu 2 +Fix the way Salt tries to get the Homebrew\(aqs prefix +.sp +The first attempt to get the Homebrew\(aqs prefix is to look for +the \fBHOMEBREW_PREFIX\fP environment variable. If it\(aqs not set, then +Salt tries to get the prefix from the \fBbrew\fP command. However, the +\fBbrew\fP command can fail. So a last attempt is made to get the +prefix by guessing the installation path. \fI\%#64924\fP +.IP \(bu 2 +Add missing MySQL Grant SERVICE_CONNECTION_ADMIN to mysql module. \fI\%#64934\fP +.IP \(bu 2 +Fixed slsutil.update with salt\-ssh during template rendering \fI\%#65067\fP +.IP \(bu 2 +Keep track when an included file only includes sls files but is a requisite. \fI\%#65080\fP +.IP \(bu 2 +Fixed \fBgpg.present\fP succeeds when the keyserver is unreachable \fI\%#65169\fP +.IP \(bu 2 +Fix typo in nftables module to ensure unique nft family values \fI\%#65295\fP +.IP \(bu 2 +Dereference symlinks to set proper __cli opt \fI\%#65435\fP +.IP \(bu 2 +Made salt\-ssh merge master top returns for the same environment \fI\%#65480\fP +.IP \(bu 2 +Account for situation where the metadata grain fails because the AWS environment requires an authentication token to query the metadata URL. \fI\%#65513\fP +.IP \(bu 2 +Improve the condition of overriding target for pip with VENV_PIP_TARGET environment variable. \fI\%#65562\fP +.IP \(bu 2 +Added SSH wrapper for logmod \fI\%#65630\fP +.IP \(bu 2 +Include changes in the results when schedule.present state is run with test=True. \fI\%#65652\fP +.IP \(bu 2 +Fix extfs.tune doesn\(aqt pass retcode to module.run \fI\%#65686\fP +.IP \(bu 2 +Return an error message when the DNS plugin is not supported \fI\%#65739\fP +.IP \(bu 2 +Execution modules have access to regular fileclient durring pillar rendering. \fI\%#66124\fP +.IP \(bu 2 +Fixed a issue with server channel where a minion\(aqs public key +would be rejected if it contained a final newline character. \fI\%#66126\fP +.UNINDENT +.SS Added +.INDENT 0.0 +.IP \(bu 2 +Allowed publishing to regular minions from the SSH wrapper \fI\%#40943\fP +.IP \(bu 2 +Added syncing of custom salt\-ssh wrappers \fI\%#45450\fP +.IP \(bu 2 +Made salt\-ssh sync custom utils \fI\%#53666\fP +.IP \(bu 2 +Add ability to use file.managed style check_cmd in file.serialize \fI\%#53982\fP +.IP \(bu 2 +Revised use of deprecated net\-tools and added support for ip neighbour with IPv4 ip_neighs, IPv6 ip_neighs6 \fI\%#57541\fP +.IP \(bu 2 +Added password support to Redis returner. \fI\%#58044\fP +.IP \(bu 2 +Added a state (win_task) for managing scheduled tasks on Windows \fI\%#59037\fP +.IP \(bu 2 +Added keyring param to gpg modules \fI\%#59783\fP +.IP \(bu 2 +Added new grain to detect the Salt package type: onedir, pip or system \fI\%#62589\fP +.IP \(bu 2 +Added Vault AppRole and identity issuance to minions \fI\%#62823\fP +.IP \(bu 2 +Added Vault AppRole auth mount path configuration option \fI\%#62825\fP +.IP \(bu 2 +Added distribution of Vault authentication details via response wrapping \fI\%#62828\fP +.IP \(bu 2 +Add salt package type information. Either onedir, pip or system. \fI\%#62961\fP +.IP \(bu 2 +Added signature verification to file.managed/archive.extracted \fI\%#63143\fP +.IP \(bu 2 +Added signed_by_any/signed_by_all parameters to gpg.verify \fI\%#63166\fP +.IP \(bu 2 +Added match runner \fI\%#63278\fP +.IP \(bu 2 +Added Vault token lifecycle management \fI\%#63406\fP +.IP \(bu 2 +adding new call for openscap xccdf eval supporting new parameters \fI\%#63416\fP +.IP \(bu 2 +Added Vault lease management utility \fI\%#63440\fP +.IP \(bu 2 +implement removal of ptf packages in zypper pkg module \fI\%#63442\fP +.IP \(bu 2 +add JUnit output for saltcheck \fI\%#63463\fP +.IP \(bu 2 +Add ability for file.keyvalue to create a file if it doesn\(aqt exist \fI\%#63545\fP +.IP \(bu 2 +added cleanup of temporary mountpoint dir for macpackage installed state \fI\%#63905\fP +.IP \(bu 2 +Add pkg.installed show installable version in test mode \fI\%#63985\fP +.IP \(bu 2 +Added patch option to Vault SDB driver \fI\%#64096\fP +.IP \(bu 2 +Added flags to create local users and groups \fI\%#64256\fP +.IP \(bu 2 +Added inline specification of trusted CA root certificate for Vault \fI\%#64379\fP +.IP \(bu 2 +Add ability to return False result in test mode of configurable_test_state \fI\%#64418\fP +.IP \(bu 2 +Switched Salt\(aqs onedir Python version to 3.11 \fI\%#64457\fP +.IP \(bu 2 +Added support for dnf5 and its new command syntax \fI\%#64532\fP +.IP \(bu 2 +Adding a new decorator to indicate when a module is deprecated in favor of a Salt extension. \fI\%#64569\fP +.IP \(bu 2 +Add jq\-esque to_entries and from_entries functions \fI\%#64600\fP +.IP \(bu 2 +Added ability to use PYTHONWARNINGS=ignore to silence deprecation warnings. \fI\%#64660\fP +.IP \(bu 2 +Add follow_symlinks to file.symlink exec module to switch to os.path.lexists when False \fI\%#64665\fP +.IP \(bu 2 +Strenghten Salt\(aqs HA capabilities with master clustering. \fI\%#64939\fP +.IP \(bu 2 +Added win_appx state and execution modules for managing Microsoft Store apps and deprovisioning them from systems \fI\%#64978\fP +.IP \(bu 2 +Add support for show_jid to salt\-run +.sp +Adds support for show_jid master config option to salt\-run, so its behaviour matches the salt cli command. \fI\%#65008\fP +.IP \(bu 2 +Add ability to remove packages by wildcard via apt execution module \fI\%#65220\fP +.IP \(bu 2 +Added support for master top modules on masterless minions \fI\%#65479\fP +.IP \(bu 2 +Allowed accessing the regular mine from the SSH wrapper \fI\%#65645\fP +.IP \(bu 2 +Allow enabling backup for Linode in Salt Cloud \fI\%#65697\fP +.IP \(bu 2 +Add a backup schedule setter fFunction for Linode VMs \fI\%#65713\fP +.IP \(bu 2 +Add acme support for manual plugin hooks \fI\%#65744\fP +.UNINDENT +.SS Security +.INDENT 0.0 +.IP \(bu 2 +Upgrade to \fBtornado>=6.3.3\fP due to \fI\%https://github.com/advisories/GHSA\-qppv\-j76h\-2rpx\fP \fI\%#64989\fP +.IP \(bu 2 +Update to \fBgitpython>=3.1.35\fP due to \fI\%https://github.com/advisories/GHSA\-wfm5\-v35h\-vwf4\fP and \fI\%https://github.com/advisories/GHSA\-cwvm\-v4w8\-q58c\fP \fI\%#65137\fP +.UNINDENT +.sp +See \fI\%Install a release candidate\fP +for more information about installing an RC when one is available. +.SS Previous releases (release\-3006.0)= .SS Salt 3006.0 release notes .SS Onedir packaging @@ -478467,10 +471904,6 @@ In the process, we were also required to update to \fBpyOpenSSL==24.0.0\fP \fI\% .IP \(bu 2 Bump to \fBcryptography==42.0.3\fP due to \fI\%https://github.com/advisories/GHSA\-3ww4\-gg4f\-jr7f\fP \fI\%#66090\fP .UNINDENT -.sp -See \fI\%Install a release candidate\fP -for more information about installing an RC when one is available. -.SS Previous releases .SS Salt 3005 release notes \- Codename Phosphorus .SS Python 3.5 and 3.6 deprecation .sp @@ -493359,7 +486792,7 @@ backends: .IP \(bu 2 \fI\%roots_update_interval\fP .IP \(bu 2 -\fI\%azurefs_update_interval\fP +\fBazurefs_update_interval\fP .IP \(bu 2 \fI\%gitfs_update_interval\fP .IP \(bu 2 @@ -531637,7 +525070,7 @@ newer Azure Portal website. .SS Clouds .INDENT 0.0 .IP \(bu 2 -\fI\%salt.cloud.clouds.azurearm\fP +\fBsalt.cloud.clouds.azurearm\fP .UNINDENT .SS Engines .INDENT 0.0 @@ -536520,7 +529953,7 @@ salt\-cloud will check for the presence of the master configuration parameter will be performed on the userdata_file. .sp In addition, the other cloud drivers which support setting a \fBuserdata_file\fP -(\fI\%azurearm\fP, \fBnova\fP, and \fI\%openstack\fP) +(\fBazurearm\fP, \fBnova\fP, and \fI\%openstack\fP) have had templating support added to bring them to feature parity with the ec2 driver\(aqs implementation of the \fBuserdata_file\fP option. .SS Changelog for v2016.11.3..v2016.11.4 @@ -559340,8 +552773,7 @@ later minions. When using this new repository, the repo cache is compiled on the Salt Minion, which enables pillar, grains and other things to be available during compilation time. .sp -See the \fI\%Windows Software Repository\fP -documentation for more information. +See the Windows Software Repository documentation for more information. .SS Changes to legacy Windows repository .sp If you have pre 2015.8 Windows minions connecting to your 2015.8 Salt master, you @@ -559351,8 +552783,7 @@ If you were previously using this repository and have customized settings, be aware that several config options have been renamed to make their naming more consistent. .sp -See the \fI\%Windows Software Repository\fP -documentation for more information. +See the Windows Software Repository documentation for more information. .SS Win System Module .sp The unit of the \fBtimeout\fP parameter in the \fBsystem.halt\fP, @@ -602075,7 +595506,7 @@ The mysql_user state enables mysql user management. The virtualenv state can manage the state of Python virtual environments. Thanks to Whitinge for the virtualenv state .SS New Returners -.SS \fI\%cassandra_returner\fP +.SS \fBcassandra_returner\fP .sp A returner allowing Salt to send data to a cassandra server. Thanks to Byron Clark for contributing this returner diff --git a/doc/man/spm.1 b/doc/man/spm.1 index f9be92b6be5..155053d433e 100644 --- a/doc/man/spm.1 +++ b/doc/man/spm.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "SPM" "1" "Generated on February 20, 2024 at 09:55:17 PM UTC." "3006.7" "Salt" +.TH "SPM" "1" "Generated on March 03, 2024 at 06:52:04 AM UTC." "3007.0" "Salt" .SH NAME spm \- Salt Package Manager Command .sp diff --git a/doc/topics/releases/3007.0.md b/doc/topics/releases/3007.0.md index 73d955875c7..4f8e70e7419 100644 --- a/doc/topics/releases/3007.0.md +++ b/doc/topics/releases/3007.0.md @@ -102,6 +102,14 @@ This is auto generated - Deprecation warning for Salt's backport of ``OrderedDict`` class which will be removed in 3009 [#65542](https://github.com/saltstack/salt/issues/65542) - Deprecate Kubernetes modules for move to saltext-kubernetes in version 3009 [#65565](https://github.com/saltstack/salt/issues/65565) - Deprecated all Pushover modules in favor of the Salt Extension at https://github.com/salt-extensions/saltext-pushover. The Pushover modules will be removed from Salt core in 3009.0 [#65567](https://github.com/saltstack/salt/issues/65567) +- Removed deprecated code: + + * All of ``salt/log/`` which has been on a deprecation path for a long time. + * Some of the logging handlers found in ``salt/_logging/handlers`` have been removed since the standard library provides + them. + * Removed the deprecated ``salt/modules/cassandra_mod.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/cassandra_return.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/django_return.py`` module and any tests for it. [#65986](https://github.com/saltstack/salt/issues/65986) ### Changed @@ -181,8 +189,6 @@ This is auto generated - Fixed slsutil.update with salt-ssh during template rendering [#65067](https://github.com/saltstack/salt/issues/65067) - Keep track when an included file only includes sls files but is a requisite. [#65080](https://github.com/saltstack/salt/issues/65080) - Fixed `gpg.present` succeeds when the keyserver is unreachable [#65169](https://github.com/saltstack/salt/issues/65169) -- Fix issue with openscap when the error was outside the expected scope. It now - returns failed with the error code and the error [#65193](https://github.com/saltstack/salt/issues/65193) - Fix typo in nftables module to ensure unique nft family values [#65295](https://github.com/saltstack/salt/issues/65295) - Dereference symlinks to set proper __cli opt [#65435](https://github.com/saltstack/salt/issues/65435) - Made salt-ssh merge master top returns for the same environment [#65480](https://github.com/saltstack/salt/issues/65480) @@ -190,11 +196,11 @@ This is auto generated - Improve the condition of overriding target for pip with VENV_PIP_TARGET environment variable. [#65562](https://github.com/saltstack/salt/issues/65562) - Added SSH wrapper for logmod [#65630](https://github.com/saltstack/salt/issues/65630) - Include changes in the results when schedule.present state is run with test=True. [#65652](https://github.com/saltstack/salt/issues/65652) -- Fixed Salt-SSH pillar rendering and state rendering with nested SSH calls when called via saltutil.cmd or in an orchestration [#65670](https://github.com/saltstack/salt/issues/65670) - Fix extfs.tune doesn't pass retcode to module.run [#65686](https://github.com/saltstack/salt/issues/65686) -- Fix boto execution module loading [#65691](https://github.com/saltstack/salt/issues/65691) -- Removed PR 65185 changes since incomplete solution [#65692](https://github.com/saltstack/salt/issues/65692) - Return an error message when the DNS plugin is not supported [#65739](https://github.com/saltstack/salt/issues/65739) +- Execution modules have access to regular fileclient durring pillar rendering. [#66124](https://github.com/saltstack/salt/issues/66124) +- Fixed a issue with server channel where a minion's public key + would be rejected if it contained a final newline character. [#66126](https://github.com/saltstack/salt/issues/66126) ### Added @@ -205,6 +211,7 @@ This is auto generated - Add ability to use file.managed style check_cmd in file.serialize [#53982](https://github.com/saltstack/salt/issues/53982) - Revised use of deprecated net-tools and added support for ip neighbour with IPv4 ip_neighs, IPv6 ip_neighs6 [#57541](https://github.com/saltstack/salt/issues/57541) - Added password support to Redis returner. [#58044](https://github.com/saltstack/salt/issues/58044) +- Added a state (win_task) for managing scheduled tasks on Windows [#59037](https://github.com/saltstack/salt/issues/59037) - Added keyring param to gpg modules [#59783](https://github.com/saltstack/salt/issues/59783) - Added new grain to detect the Salt package type: onedir, pip or system [#62589](https://github.com/saltstack/salt/issues/62589) - Added Vault AppRole and identity issuance to minions [#62823](https://github.com/saltstack/salt/issues/62823) @@ -232,6 +239,7 @@ This is auto generated - Add jq-esque to_entries and from_entries functions [#64600](https://github.com/saltstack/salt/issues/64600) - Added ability to use PYTHONWARNINGS=ignore to silence deprecation warnings. [#64660](https://github.com/saltstack/salt/issues/64660) - Add follow_symlinks to file.symlink exec module to switch to os.path.lexists when False [#64665](https://github.com/saltstack/salt/issues/64665) +- Strenghten Salt's HA capabilities with master clustering. [#64939](https://github.com/saltstack/salt/issues/64939) - Added win_appx state and execution modules for managing Microsoft Store apps and deprovisioning them from systems [#64978](https://github.com/saltstack/salt/issues/64978) - Add support for show_jid to salt-run diff --git a/pkg/debian/changelog b/pkg/debian/changelog index c615e70d78a..680ff3a2683 100644 --- a/pkg/debian/changelog +++ b/pkg/debian/changelog @@ -1,3 +1,180 @@ +salt (3007.0) stable; urgency=medium + + + # Removed + + * Removed RHEL 5 support since long since end-of-lifed [#62520](https://github.com/saltstack/salt/issues/62520) + * Removing Azure-Cloud modules from the code base. [#64322](https://github.com/saltstack/salt/issues/64322) + * Dropped Python 3.7 support since it's EOL in 27 Jun 2023 [#64417](https://github.com/saltstack/salt/issues/64417) + * Remove salt.payload.Serial [#64459](https://github.com/saltstack/salt/issues/64459) + * Remove netmiko_conn and pyeapi_conn from salt.modules.napalm_mod [#64460](https://github.com/saltstack/salt/issues/64460) + * Removed 'transport' arg from salt.utils.event.get_event [#64461](https://github.com/saltstack/salt/issues/64461) + * Removed the usage of retired Linode API v3 from Salt Cloud [#64517](https://github.com/saltstack/salt/issues/64517) + + # Deprecated + + * Deprecate all Proxmox cloud modules [#64224](https://github.com/saltstack/salt/issues/64224) + * Deprecate all the Vault modules in favor of the Vault Salt Extension https://github.com/salt-extensions/saltext-vault. The Vault modules will be removed in Salt core in 3009.0. [#64893](https://github.com/saltstack/salt/issues/64893) + * Deprecate all the Docker modules in favor of the Docker Salt Extension https://github.com/saltstack/saltext-docker. The Docker modules will be removed in Salt core in 3009.0. [#64894](https://github.com/saltstack/salt/issues/64894) + * Deprecate all the Zabbix modules in favor of the Zabbix Salt Extension https://github.com/salt-extensions/saltext-zabbix. The Zabbix modules will be removed in Salt core in 3009.0. [#64896](https://github.com/saltstack/salt/issues/64896) + * Deprecate all the Apache modules in favor of the Apache Salt Extension https://github.com/salt-extensions/saltext-apache. The Apache modules will be removed in Salt core in 3009.0. [#64909](https://github.com/saltstack/salt/issues/64909) + * Deprecation warning for Salt's backport of ``OrderedDict`` class which will be removed in 3009 [#65542](https://github.com/saltstack/salt/issues/65542) + * Deprecate Kubernetes modules for move to saltext-kubernetes in version 3009 [#65565](https://github.com/saltstack/salt/issues/65565) + * Deprecated all Pushover modules in favor of the Salt Extension at https://github.com/salt-extensions/saltext-pushover. The Pushover modules will be removed from Salt core in 3009.0 [#65567](https://github.com/saltstack/salt/issues/65567) + * Removed deprecated code: + + * All of ``salt/log/`` which has been on a deprecation path for a long time. + * Some of the logging handlers found in ``salt/_logging/handlers`` have been removed since the standard library provides + them. + * Removed the deprecated ``salt/modules/cassandra_mod.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/cassandra_return.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/django_return.py`` module and any tests for it. [#65986](https://github.com/saltstack/salt/issues/65986) + + # Changed + + * Masquerade property will not default to false turning off masquerade if not specified. [#53120](https://github.com/saltstack/salt/issues/53120) + * Addressed Python 3.11 deprecations: + + * Switch to `FullArgSpec` since Py 3.11 no longer has `ArgSpec`, deprecated since Py 3.0 + * Stopped using the deprecated `cgi` module. + * Stopped using the deprecated `pipes` module + * Stopped using the deprecated `imp` module [#64457](https://github.com/saltstack/salt/issues/64457) + * changed 'gpg_decrypt_must_succeed' default from False to True [#64462](https://github.com/saltstack/salt/issues/64462) + + # Fixed + + * When an NFS or FUSE mount fails to unmount when mount options have changed, try again with a lazy umount before mounting again. [#18907](https://github.com/saltstack/salt/issues/18907) + * fix autoaccept gpg keys by supporting it in refresh_db module [#42039](https://github.com/saltstack/salt/issues/42039) + * Made cmd.script work with files from the fileserver via salt-ssh [#48067](https://github.com/saltstack/salt/issues/48067) + * Made slsutil.renderer work with salt-ssh [#50196](https://github.com/saltstack/salt/issues/50196) + * Fixed defaults.merge is not available when using salt-ssh [#51605](https://github.com/saltstack/salt/issues/51605) + * Fix extfs.mkfs missing parameter handling for -C, -d, and -e [#51858](https://github.com/saltstack/salt/issues/51858) + * Fixed Salt master does not renew token [#51986](https://github.com/saltstack/salt/issues/51986) + * Fixed salt-ssh continues state/pillar rendering with incorrect data when an exception is raised by a module on the target [#52452](https://github.com/saltstack/salt/issues/52452) + * Fix extfs.tune has 'reserved' documented twice and is missing the 'reserved_percentage' keyword argument [#54426](https://github.com/saltstack/salt/issues/54426) + * Fix the ability of the 'selinux.port_policy_present' state to modify. [#55687](https://github.com/saltstack/salt/issues/55687) + * Fixed config.get does not support merge option with salt-ssh [#56441](https://github.com/saltstack/salt/issues/56441) + * Removed an unused assignment in file.patch [#57204](https://github.com/saltstack/salt/issues/57204) + * Fixed vault module fetching more than one secret in one run with single-use tokens [#57561](https://github.com/saltstack/salt/issues/57561) + * Use brew path from which in mac_brew_pkg module and rely on _homebrew_bin() everytime [#57946](https://github.com/saltstack/salt/issues/57946) + * Fixed Vault verify option to work on minions when only specified in master config [#58174](https://github.com/saltstack/salt/issues/58174) + * Fixed vault command errors configured locally [#58580](https://github.com/saltstack/salt/issues/58580) + * Fixed issue with basic auth causing invalid header error and 401 Bad Request, by using HTTPBasicAuthHandler instead of header. [#58936](https://github.com/saltstack/salt/issues/58936) + * Make the LXD module work with pyLXD > 2.10 [#59514](https://github.com/saltstack/salt/issues/59514) + * Return error if patch file passed to state file.patch is malformed. [#59806](https://github.com/saltstack/salt/issues/59806) + * Handle failure and error information from tuned module/state [#60500](https://github.com/saltstack/salt/issues/60500) + * Fixed sdb.get_or_set_hash with Vault single-use tokens [#60779](https://github.com/saltstack/salt/issues/60779) + * Fixed state.test does not work with salt-ssh [#61100](https://github.com/saltstack/salt/issues/61100) + * Made slsutil.findup work with salt-ssh [#61143](https://github.com/saltstack/salt/issues/61143) + * Allow all primitive grain types for autosign_grains [#61416](https://github.com/saltstack/salt/issues/61416), [#63708](https://github.com/saltstack/salt/issues/63708) + * `ipset.new_set` no longer fails when creating a set type that uses the `family` create option [#61620](https://github.com/saltstack/salt/issues/61620) + * Fixed Vault session storage to allow unlimited use tokens [#62380](https://github.com/saltstack/salt/issues/62380) + * fix the efi grain on FreeBSD [#63052](https://github.com/saltstack/salt/issues/63052) + * Fixed gpg.receive_keys returns success on failed import [#63144](https://github.com/saltstack/salt/issues/63144) + * Fixed GPG state module always reports success without changes [#63153](https://github.com/saltstack/salt/issues/63153) + * Fixed GPG state module does not respect test mode [#63156](https://github.com/saltstack/salt/issues/63156) + * Fixed gpg.absent with gnupghome/user, fixed gpg.delete_key with gnupghome [#63159](https://github.com/saltstack/salt/issues/63159) + * Fixed service module does not handle enable/disable if systemd service is an alias [#63214](https://github.com/saltstack/salt/issues/63214) + * Made x509_v2 compound match detection use new runner instead of peer publishing [#63278](https://github.com/saltstack/salt/issues/63278) + * Need to make sure we update __pillar__ during a pillar refresh to ensure that process_beacons has the updated beacons loaded from pillar. [#63583](https://github.com/saltstack/salt/issues/63583) + * This implements the vpc_uuid parameter when creating a droplet. This parameter selects the correct virtual private cloud (private network interface). [#63714](https://github.com/saltstack/salt/issues/63714) + * pkg.installed no longer reports failure when installing packages that are installed via the task manager [#63767](https://github.com/saltstack/salt/issues/63767) + * mac_xattr.list and mac_xattr.read will replace undecode-able bytes to avoid raising CommandExecutionError. [#63779](https://github.com/saltstack/salt/issues/63779) [#63779](https://github.com/saltstack/salt/issues/63779) + * Fix aptpkg.latest_version performance, reducing number of times to 'shell out' [#63982](https://github.com/saltstack/salt/issues/63982) + * Added option to use a fresh connection for mysql cache [#63991](https://github.com/saltstack/salt/issues/63991) + * [lxd] Fixed a bug in `container_create` which prevented devices which are not of type `disk` to be correctly created and added to the container when passed via the `devices` parameter. [#63996](https://github.com/saltstack/salt/issues/63996) + * Skipped the `isfile` check to greatly increase speed of reading minion keys for systems with a large number of minions on slow file storage [#64260](https://github.com/saltstack/salt/issues/64260) + * Fix utf8 handling in 'pass' renderer [#64300](https://github.com/saltstack/salt/issues/64300) + * Upgade tornado to 6.3.2 [#64305](https://github.com/saltstack/salt/issues/64305) + * Prevent errors due missing 'transactional_update.apply' on SLE Micro and MicroOS. [#64369](https://github.com/saltstack/salt/issues/64369) + * Fix 'unable to unmount' failure to return False result instead of None [#64420](https://github.com/saltstack/salt/issues/64420) + * Fixed issue uninstalling duplicate packages in ``win_appx`` execution module [#64450](https://github.com/saltstack/salt/issues/64450) + * Clean up tech debt, IPC now uses tcp transport. [#64488](https://github.com/saltstack/salt/issues/64488) + * Made salt-ssh more strict when handling unexpected situations and state.* wrappers treat a remote exception as failure, excluded salt-ssh error returns from mine [#64531](https://github.com/saltstack/salt/issues/64531) + * Fix flaky test for LazyLoader with isolated mocking of threading.RLock [#64567](https://github.com/saltstack/salt/issues/64567) + * Fix possible `KeyError` exceptions in `salt.utils.user.get_group_dict` + while reading improper duplicated GID assigned for the user. [#64599](https://github.com/saltstack/salt/issues/64599) + * changed vm_config() to deep-merge vm_overrides of specific VM, instead of simple-merging the whole vm_overrides [#64610](https://github.com/saltstack/salt/issues/64610) + * Fix the way Salt tries to get the Homebrew's prefix + + The first attempt to get the Homebrew's prefix is to look for + the `HOMEBREW_PREFIX` environment variable. If it's not set, then + Salt tries to get the prefix from the `brew` command. However, the + `brew` command can fail. So a last attempt is made to get the + prefix by guessing the installation path. [#64924](https://github.com/saltstack/salt/issues/64924) + * Add missing MySQL Grant SERVICE_CONNECTION_ADMIN to mysql module. [#64934](https://github.com/saltstack/salt/issues/64934) + * Fixed slsutil.update with salt-ssh during template rendering [#65067](https://github.com/saltstack/salt/issues/65067) + * Keep track when an included file only includes sls files but is a requisite. [#65080](https://github.com/saltstack/salt/issues/65080) + * Fixed `gpg.present` succeeds when the keyserver is unreachable [#65169](https://github.com/saltstack/salt/issues/65169) + * Fix typo in nftables module to ensure unique nft family values [#65295](https://github.com/saltstack/salt/issues/65295) + * Dereference symlinks to set proper __cli opt [#65435](https://github.com/saltstack/salt/issues/65435) + * Made salt-ssh merge master top returns for the same environment [#65480](https://github.com/saltstack/salt/issues/65480) + * Account for situation where the metadata grain fails because the AWS environment requires an authentication token to query the metadata URL. [#65513](https://github.com/saltstack/salt/issues/65513) + * Improve the condition of overriding target for pip with VENV_PIP_TARGET environment variable. [#65562](https://github.com/saltstack/salt/issues/65562) + * Added SSH wrapper for logmod [#65630](https://github.com/saltstack/salt/issues/65630) + * Include changes in the results when schedule.present state is run with test=True. [#65652](https://github.com/saltstack/salt/issues/65652) + * Fix extfs.tune doesn't pass retcode to module.run [#65686](https://github.com/saltstack/salt/issues/65686) + * Return an error message when the DNS plugin is not supported [#65739](https://github.com/saltstack/salt/issues/65739) + * Execution modules have access to regular fileclient durring pillar rendering. [#66124](https://github.com/saltstack/salt/issues/66124) + * Fixed a issue with server channel where a minion's public key + would be rejected if it contained a final newline character. [#66126](https://github.com/saltstack/salt/issues/66126) + + # Added + + * Allowed publishing to regular minions from the SSH wrapper [#40943](https://github.com/saltstack/salt/issues/40943) + * Added syncing of custom salt-ssh wrappers [#45450](https://github.com/saltstack/salt/issues/45450) + * Made salt-ssh sync custom utils [#53666](https://github.com/saltstack/salt/issues/53666) + * Add ability to use file.managed style check_cmd in file.serialize [#53982](https://github.com/saltstack/salt/issues/53982) + * Revised use of deprecated net-tools and added support for ip neighbour with IPv4 ip_neighs, IPv6 ip_neighs6 [#57541](https://github.com/saltstack/salt/issues/57541) + * Added password support to Redis returner. [#58044](https://github.com/saltstack/salt/issues/58044) + * Added a state (win_task) for managing scheduled tasks on Windows [#59037](https://github.com/saltstack/salt/issues/59037) + * Added keyring param to gpg modules [#59783](https://github.com/saltstack/salt/issues/59783) + * Added new grain to detect the Salt package type: onedir, pip or system [#62589](https://github.com/saltstack/salt/issues/62589) + * Added Vault AppRole and identity issuance to minions [#62823](https://github.com/saltstack/salt/issues/62823) + * Added Vault AppRole auth mount path configuration option [#62825](https://github.com/saltstack/salt/issues/62825) + * Added distribution of Vault authentication details via response wrapping [#62828](https://github.com/saltstack/salt/issues/62828) + * Add salt package type information. Either onedir, pip or system. [#62961](https://github.com/saltstack/salt/issues/62961) + * Added signature verification to file.managed/archive.extracted [#63143](https://github.com/saltstack/salt/issues/63143) + * Added signed_by_any/signed_by_all parameters to gpg.verify [#63166](https://github.com/saltstack/salt/issues/63166) + * Added match runner [#63278](https://github.com/saltstack/salt/issues/63278) + * Added Vault token lifecycle management [#63406](https://github.com/saltstack/salt/issues/63406) + * adding new call for openscap xccdf eval supporting new parameters [#63416](https://github.com/saltstack/salt/issues/63416) + * Added Vault lease management utility [#63440](https://github.com/saltstack/salt/issues/63440) + * implement removal of ptf packages in zypper pkg module [#63442](https://github.com/saltstack/salt/issues/63442) + * add JUnit output for saltcheck [#63463](https://github.com/saltstack/salt/issues/63463) + * Add ability for file.keyvalue to create a file if it doesn't exist [#63545](https://github.com/saltstack/salt/issues/63545) + * added cleanup of temporary mountpoint dir for macpackage installed state [#63905](https://github.com/saltstack/salt/issues/63905) + * Add pkg.installed show installable version in test mode [#63985](https://github.com/saltstack/salt/issues/63985) + * Added patch option to Vault SDB driver [#64096](https://github.com/saltstack/salt/issues/64096) + * Added flags to create local users and groups [#64256](https://github.com/saltstack/salt/issues/64256) + * Added inline specification of trusted CA root certificate for Vault [#64379](https://github.com/saltstack/salt/issues/64379) + * Add ability to return False result in test mode of configurable_test_state [#64418](https://github.com/saltstack/salt/issues/64418) + * Switched Salt's onedir Python version to 3.11 [#64457](https://github.com/saltstack/salt/issues/64457) + * Added support for dnf5 and its new command syntax [#64532](https://github.com/saltstack/salt/issues/64532) + * Adding a new decorator to indicate when a module is deprecated in favor of a Salt extension. [#64569](https://github.com/saltstack/salt/issues/64569) + * Add jq-esque to_entries and from_entries functions [#64600](https://github.com/saltstack/salt/issues/64600) + * Added ability to use PYTHONWARNINGS=ignore to silence deprecation warnings. [#64660](https://github.com/saltstack/salt/issues/64660) + * Add follow_symlinks to file.symlink exec module to switch to os.path.lexists when False [#64665](https://github.com/saltstack/salt/issues/64665) + * Strenghten Salt's HA capabilities with master clustering. [#64939](https://github.com/saltstack/salt/issues/64939) + * Added win_appx state and execution modules for managing Microsoft Store apps and deprovisioning them from systems [#64978](https://github.com/saltstack/salt/issues/64978) + * Add support for show_jid to salt-run + + Adds support for show_jid master config option to salt*run, so its behaviour matches the salt cli command. [#65008](https://github.com/saltstack/salt/issues/65008) + * Add ability to remove packages by wildcard via apt execution module [#65220](https://github.com/saltstack/salt/issues/65220) + * Added support for master top modules on masterless minions [#65479](https://github.com/saltstack/salt/issues/65479) + * Allowed accessing the regular mine from the SSH wrapper [#65645](https://github.com/saltstack/salt/issues/65645) + * Allow enabling backup for Linode in Salt Cloud [#65697](https://github.com/saltstack/salt/issues/65697) + * Add a backup schedule setter fFunction for Linode VMs [#65713](https://github.com/saltstack/salt/issues/65713) + * Add acme support for manual plugin hooks [#65744](https://github.com/saltstack/salt/issues/65744) + + # Security + + * Upgrade to `tornado>=6.3.3` due to https://github.com/advisories/GHSA-qppv-j76h-2rpx [#64989](https://github.com/saltstack/salt/issues/64989) + * Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65137](https://github.com/saltstack/salt/issues/65137) + + + -- Salt Project Packaging Sun, 03 Mar 2024 06:51:04 +0000 + salt (3006.7) stable; urgency=medium diff --git a/pkg/rpm/salt.spec b/pkg/rpm/salt.spec index 289c204ab24..04cf63b5c57 100644 --- a/pkg/rpm/salt.spec +++ b/pkg/rpm/salt.spec @@ -31,7 +31,7 @@ %define fish_dir %{_datadir}/fish/vendor_functions.d Name: salt -Version: 3007.0~rc1 +Version: 3007.0 Release: 0 Summary: A parallel remote execution system Group: System Environment/Daemons @@ -646,6 +646,180 @@ if [ $1 -ge 1 ] ; then fi %changelog +* Sun Mar 03 2024 Salt Project Packaging - 3007.0 + +# Removed + +- Removed RHEL 5 support since long since end-of-lifed [#62520](https://github.com/saltstack/salt/issues/62520) +- Removing Azure-Cloud modules from the code base. [#64322](https://github.com/saltstack/salt/issues/64322) +- Dropped Python 3.7 support since it's EOL in 27 Jun 2023 [#64417](https://github.com/saltstack/salt/issues/64417) +- Remove salt.payload.Serial [#64459](https://github.com/saltstack/salt/issues/64459) +- Remove netmiko_conn and pyeapi_conn from salt.modules.napalm_mod [#64460](https://github.com/saltstack/salt/issues/64460) +- Removed 'transport' arg from salt.utils.event.get_event [#64461](https://github.com/saltstack/salt/issues/64461) +- Removed the usage of retired Linode API v3 from Salt Cloud [#64517](https://github.com/saltstack/salt/issues/64517) + +# Deprecated + +- Deprecate all Proxmox cloud modules [#64224](https://github.com/saltstack/salt/issues/64224) +- Deprecate all the Vault modules in favor of the Vault Salt Extension https://github.com/salt-extensions/saltext-vault. The Vault modules will be removed in Salt core in 3009.0. [#64893](https://github.com/saltstack/salt/issues/64893) +- Deprecate all the Docker modules in favor of the Docker Salt Extension https://github.com/saltstack/saltext-docker. The Docker modules will be removed in Salt core in 3009.0. [#64894](https://github.com/saltstack/salt/issues/64894) +- Deprecate all the Zabbix modules in favor of the Zabbix Salt Extension https://github.com/salt-extensions/saltext-zabbix. The Zabbix modules will be removed in Salt core in 3009.0. [#64896](https://github.com/saltstack/salt/issues/64896) +- Deprecate all the Apache modules in favor of the Apache Salt Extension https://github.com/salt-extensions/saltext-apache. The Apache modules will be removed in Salt core in 3009.0. [#64909](https://github.com/saltstack/salt/issues/64909) +- Deprecation warning for Salt's backport of ``OrderedDict`` class which will be removed in 3009 [#65542](https://github.com/saltstack/salt/issues/65542) +- Deprecate Kubernetes modules for move to saltext-kubernetes in version 3009 [#65565](https://github.com/saltstack/salt/issues/65565) +- Deprecated all Pushover modules in favor of the Salt Extension at https://github.com/salt-extensions/saltext-pushover. The Pushover modules will be removed from Salt core in 3009.0 [#65567](https://github.com/saltstack/salt/issues/65567) +- Removed deprecated code: + + * All of ``salt/log/`` which has been on a deprecation path for a long time. + * Some of the logging handlers found in ``salt/_logging/handlers`` have been removed since the standard library provides + them. + * Removed the deprecated ``salt/modules/cassandra_mod.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/cassandra_return.py`` module and any tests for it. + * Removed the deprecated ``salt/returners/django_return.py`` module and any tests for it. [#65986](https://github.com/saltstack/salt/issues/65986) + +# Changed + +- Masquerade property will not default to false turning off masquerade if not specified. [#53120](https://github.com/saltstack/salt/issues/53120) +- Addressed Python 3.11 deprecations: + + * Switch to `FullArgSpec` since Py 3.11 no longer has `ArgSpec`, deprecated since Py 3.0 + * Stopped using the deprecated `cgi` module. + * Stopped using the deprecated `pipes` module + * Stopped using the deprecated `imp` module [#64457](https://github.com/saltstack/salt/issues/64457) +- changed 'gpg_decrypt_must_succeed' default from False to True [#64462](https://github.com/saltstack/salt/issues/64462) + +# Fixed + +- When an NFS or FUSE mount fails to unmount when mount options have changed, try again with a lazy umount before mounting again. [#18907](https://github.com/saltstack/salt/issues/18907) +- fix autoaccept gpg keys by supporting it in refresh_db module [#42039](https://github.com/saltstack/salt/issues/42039) +- Made cmd.script work with files from the fileserver via salt-ssh [#48067](https://github.com/saltstack/salt/issues/48067) +- Made slsutil.renderer work with salt-ssh [#50196](https://github.com/saltstack/salt/issues/50196) +- Fixed defaults.merge is not available when using salt-ssh [#51605](https://github.com/saltstack/salt/issues/51605) +- Fix extfs.mkfs missing parameter handling for -C, -d, and -e [#51858](https://github.com/saltstack/salt/issues/51858) +- Fixed Salt master does not renew token [#51986](https://github.com/saltstack/salt/issues/51986) +- Fixed salt-ssh continues state/pillar rendering with incorrect data when an exception is raised by a module on the target [#52452](https://github.com/saltstack/salt/issues/52452) +- Fix extfs.tune has 'reserved' documented twice and is missing the 'reserved_percentage' keyword argument [#54426](https://github.com/saltstack/salt/issues/54426) +- Fix the ability of the 'selinux.port_policy_present' state to modify. [#55687](https://github.com/saltstack/salt/issues/55687) +- Fixed config.get does not support merge option with salt-ssh [#56441](https://github.com/saltstack/salt/issues/56441) +- Removed an unused assignment in file.patch [#57204](https://github.com/saltstack/salt/issues/57204) +- Fixed vault module fetching more than one secret in one run with single-use tokens [#57561](https://github.com/saltstack/salt/issues/57561) +- Use brew path from which in mac_brew_pkg module and rely on _homebrew_bin() everytime [#57946](https://github.com/saltstack/salt/issues/57946) +- Fixed Vault verify option to work on minions when only specified in master config [#58174](https://github.com/saltstack/salt/issues/58174) +- Fixed vault command errors configured locally [#58580](https://github.com/saltstack/salt/issues/58580) +- Fixed issue with basic auth causing invalid header error and 401 Bad Request, by using HTTPBasicAuthHandler instead of header. [#58936](https://github.com/saltstack/salt/issues/58936) +- Make the LXD module work with pyLXD > 2.10 [#59514](https://github.com/saltstack/salt/issues/59514) +- Return error if patch file passed to state file.patch is malformed. [#59806](https://github.com/saltstack/salt/issues/59806) +- Handle failure and error information from tuned module/state [#60500](https://github.com/saltstack/salt/issues/60500) +- Fixed sdb.get_or_set_hash with Vault single-use tokens [#60779](https://github.com/saltstack/salt/issues/60779) +- Fixed state.test does not work with salt-ssh [#61100](https://github.com/saltstack/salt/issues/61100) +- Made slsutil.findup work with salt-ssh [#61143](https://github.com/saltstack/salt/issues/61143) +- Allow all primitive grain types for autosign_grains [#61416](https://github.com/saltstack/salt/issues/61416), [#63708](https://github.com/saltstack/salt/issues/63708) +- `ipset.new_set` no longer fails when creating a set type that uses the `family` create option [#61620](https://github.com/saltstack/salt/issues/61620) +- Fixed Vault session storage to allow unlimited use tokens [#62380](https://github.com/saltstack/salt/issues/62380) +- fix the efi grain on FreeBSD [#63052](https://github.com/saltstack/salt/issues/63052) +- Fixed gpg.receive_keys returns success on failed import [#63144](https://github.com/saltstack/salt/issues/63144) +- Fixed GPG state module always reports success without changes [#63153](https://github.com/saltstack/salt/issues/63153) +- Fixed GPG state module does not respect test mode [#63156](https://github.com/saltstack/salt/issues/63156) +- Fixed gpg.absent with gnupghome/user, fixed gpg.delete_key with gnupghome [#63159](https://github.com/saltstack/salt/issues/63159) +- Fixed service module does not handle enable/disable if systemd service is an alias [#63214](https://github.com/saltstack/salt/issues/63214) +- Made x509_v2 compound match detection use new runner instead of peer publishing [#63278](https://github.com/saltstack/salt/issues/63278) +- Need to make sure we update __pillar__ during a pillar refresh to ensure that process_beacons has the updated beacons loaded from pillar. [#63583](https://github.com/saltstack/salt/issues/63583) +- This implements the vpc_uuid parameter when creating a droplet. This parameter selects the correct virtual private cloud (private network interface). [#63714](https://github.com/saltstack/salt/issues/63714) +- pkg.installed no longer reports failure when installing packages that are installed via the task manager [#63767](https://github.com/saltstack/salt/issues/63767) +- mac_xattr.list and mac_xattr.read will replace undecode-able bytes to avoid raising CommandExecutionError. [#63779](https://github.com/saltstack/salt/issues/63779) [#63779](https://github.com/saltstack/salt/issues/63779) +- Fix aptpkg.latest_version performance, reducing number of times to 'shell out' [#63982](https://github.com/saltstack/salt/issues/63982) +- Added option to use a fresh connection for mysql cache [#63991](https://github.com/saltstack/salt/issues/63991) +- [lxd] Fixed a bug in `container_create` which prevented devices which are not of type `disk` to be correctly created and added to the container when passed via the `devices` parameter. [#63996](https://github.com/saltstack/salt/issues/63996) +- Skipped the `isfile` check to greatly increase speed of reading minion keys for systems with a large number of minions on slow file storage [#64260](https://github.com/saltstack/salt/issues/64260) +- Fix utf8 handling in 'pass' renderer [#64300](https://github.com/saltstack/salt/issues/64300) +- Upgade tornado to 6.3.2 [#64305](https://github.com/saltstack/salt/issues/64305) +- Prevent errors due missing 'transactional_update.apply' on SLE Micro and MicroOS. [#64369](https://github.com/saltstack/salt/issues/64369) +- Fix 'unable to unmount' failure to return False result instead of None [#64420](https://github.com/saltstack/salt/issues/64420) +- Fixed issue uninstalling duplicate packages in ``win_appx`` execution module [#64450](https://github.com/saltstack/salt/issues/64450) +- Clean up tech debt, IPC now uses tcp transport. [#64488](https://github.com/saltstack/salt/issues/64488) +- Made salt-ssh more strict when handling unexpected situations and state.* wrappers treat a remote exception as failure, excluded salt-ssh error returns from mine [#64531](https://github.com/saltstack/salt/issues/64531) +- Fix flaky test for LazyLoader with isolated mocking of threading.RLock [#64567](https://github.com/saltstack/salt/issues/64567) +- Fix possible `KeyError` exceptions in `salt.utils.user.get_group_dict` + while reading improper duplicated GID assigned for the user. [#64599](https://github.com/saltstack/salt/issues/64599) +- changed vm_config() to deep-merge vm_overrides of specific VM, instead of simple-merging the whole vm_overrides [#64610](https://github.com/saltstack/salt/issues/64610) +- Fix the way Salt tries to get the Homebrew's prefix + + The first attempt to get the Homebrew's prefix is to look for + the `HOMEBREW_PREFIX` environment variable. If it's not set, then + Salt tries to get the prefix from the `brew` command. However, the + `brew` command can fail. So a last attempt is made to get the + prefix by guessing the installation path. [#64924](https://github.com/saltstack/salt/issues/64924) +- Add missing MySQL Grant SERVICE_CONNECTION_ADMIN to mysql module. [#64934](https://github.com/saltstack/salt/issues/64934) +- Fixed slsutil.update with salt-ssh during template rendering [#65067](https://github.com/saltstack/salt/issues/65067) +- Keep track when an included file only includes sls files but is a requisite. [#65080](https://github.com/saltstack/salt/issues/65080) +- Fixed `gpg.present` succeeds when the keyserver is unreachable [#65169](https://github.com/saltstack/salt/issues/65169) +- Fix typo in nftables module to ensure unique nft family values [#65295](https://github.com/saltstack/salt/issues/65295) +- Dereference symlinks to set proper __cli opt [#65435](https://github.com/saltstack/salt/issues/65435) +- Made salt-ssh merge master top returns for the same environment [#65480](https://github.com/saltstack/salt/issues/65480) +- Account for situation where the metadata grain fails because the AWS environment requires an authentication token to query the metadata URL. [#65513](https://github.com/saltstack/salt/issues/65513) +- Improve the condition of overriding target for pip with VENV_PIP_TARGET environment variable. [#65562](https://github.com/saltstack/salt/issues/65562) +- Added SSH wrapper for logmod [#65630](https://github.com/saltstack/salt/issues/65630) +- Include changes in the results when schedule.present state is run with test=True. [#65652](https://github.com/saltstack/salt/issues/65652) +- Fix extfs.tune doesn't pass retcode to module.run [#65686](https://github.com/saltstack/salt/issues/65686) +- Return an error message when the DNS plugin is not supported [#65739](https://github.com/saltstack/salt/issues/65739) +- Execution modules have access to regular fileclient durring pillar rendering. [#66124](https://github.com/saltstack/salt/issues/66124) +- Fixed a issue with server channel where a minion's public key + would be rejected if it contained a final newline character. [#66126](https://github.com/saltstack/salt/issues/66126) + +# Added + +- Allowed publishing to regular minions from the SSH wrapper [#40943](https://github.com/saltstack/salt/issues/40943) +- Added syncing of custom salt-ssh wrappers [#45450](https://github.com/saltstack/salt/issues/45450) +- Made salt-ssh sync custom utils [#53666](https://github.com/saltstack/salt/issues/53666) +- Add ability to use file.managed style check_cmd in file.serialize [#53982](https://github.com/saltstack/salt/issues/53982) +- Revised use of deprecated net-tools and added support for ip neighbour with IPv4 ip_neighs, IPv6 ip_neighs6 [#57541](https://github.com/saltstack/salt/issues/57541) +- Added password support to Redis returner. [#58044](https://github.com/saltstack/salt/issues/58044) +- Added a state (win_task) for managing scheduled tasks on Windows [#59037](https://github.com/saltstack/salt/issues/59037) +- Added keyring param to gpg modules [#59783](https://github.com/saltstack/salt/issues/59783) +- Added new grain to detect the Salt package type: onedir, pip or system [#62589](https://github.com/saltstack/salt/issues/62589) +- Added Vault AppRole and identity issuance to minions [#62823](https://github.com/saltstack/salt/issues/62823) +- Added Vault AppRole auth mount path configuration option [#62825](https://github.com/saltstack/salt/issues/62825) +- Added distribution of Vault authentication details via response wrapping [#62828](https://github.com/saltstack/salt/issues/62828) +- Add salt package type information. Either onedir, pip or system. [#62961](https://github.com/saltstack/salt/issues/62961) +- Added signature verification to file.managed/archive.extracted [#63143](https://github.com/saltstack/salt/issues/63143) +- Added signed_by_any/signed_by_all parameters to gpg.verify [#63166](https://github.com/saltstack/salt/issues/63166) +- Added match runner [#63278](https://github.com/saltstack/salt/issues/63278) +- Added Vault token lifecycle management [#63406](https://github.com/saltstack/salt/issues/63406) +- adding new call for openscap xccdf eval supporting new parameters [#63416](https://github.com/saltstack/salt/issues/63416) +- Added Vault lease management utility [#63440](https://github.com/saltstack/salt/issues/63440) +- implement removal of ptf packages in zypper pkg module [#63442](https://github.com/saltstack/salt/issues/63442) +- add JUnit output for saltcheck [#63463](https://github.com/saltstack/salt/issues/63463) +- Add ability for file.keyvalue to create a file if it doesn't exist [#63545](https://github.com/saltstack/salt/issues/63545) +- added cleanup of temporary mountpoint dir for macpackage installed state [#63905](https://github.com/saltstack/salt/issues/63905) +- Add pkg.installed show installable version in test mode [#63985](https://github.com/saltstack/salt/issues/63985) +- Added patch option to Vault SDB driver [#64096](https://github.com/saltstack/salt/issues/64096) +- Added flags to create local users and groups [#64256](https://github.com/saltstack/salt/issues/64256) +- Added inline specification of trusted CA root certificate for Vault [#64379](https://github.com/saltstack/salt/issues/64379) +- Add ability to return False result in test mode of configurable_test_state [#64418](https://github.com/saltstack/salt/issues/64418) +- Switched Salt's onedir Python version to 3.11 [#64457](https://github.com/saltstack/salt/issues/64457) +- Added support for dnf5 and its new command syntax [#64532](https://github.com/saltstack/salt/issues/64532) +- Adding a new decorator to indicate when a module is deprecated in favor of a Salt extension. [#64569](https://github.com/saltstack/salt/issues/64569) +- Add jq-esque to_entries and from_entries functions [#64600](https://github.com/saltstack/salt/issues/64600) +- Added ability to use PYTHONWARNINGS=ignore to silence deprecation warnings. [#64660](https://github.com/saltstack/salt/issues/64660) +- Add follow_symlinks to file.symlink exec module to switch to os.path.lexists when False [#64665](https://github.com/saltstack/salt/issues/64665) +- Strenghten Salt's HA capabilities with master clustering. [#64939](https://github.com/saltstack/salt/issues/64939) +- Added win_appx state and execution modules for managing Microsoft Store apps and deprovisioning them from systems [#64978](https://github.com/saltstack/salt/issues/64978) +- Add support for show_jid to salt-run + + Adds support for show_jid master config option to salt-run, so its behaviour matches the salt cli command. [#65008](https://github.com/saltstack/salt/issues/65008) +- Add ability to remove packages by wildcard via apt execution module [#65220](https://github.com/saltstack/salt/issues/65220) +- Added support for master top modules on masterless minions [#65479](https://github.com/saltstack/salt/issues/65479) +- Allowed accessing the regular mine from the SSH wrapper [#65645](https://github.com/saltstack/salt/issues/65645) +- Allow enabling backup for Linode in Salt Cloud [#65697](https://github.com/saltstack/salt/issues/65697) +- Add a backup schedule setter fFunction for Linode VMs [#65713](https://github.com/saltstack/salt/issues/65713) +- Add acme support for manual plugin hooks [#65744](https://github.com/saltstack/salt/issues/65744) + +# Security + +- Upgrade to `tornado>=6.3.3` due to https://github.com/advisories/GHSA-qppv-j76h-2rpx [#64989](https://github.com/saltstack/salt/issues/64989) +- Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65137](https://github.com/saltstack/salt/issues/65137) + + * Tue Feb 20 2024 Salt Project Packaging - 3006.7 # Deprecated From 9dee4488add049620544fd4561daec249621db99 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Thu, 29 Feb 2024 14:38:19 +0000 Subject: [PATCH 50/54] Add changelog entry about removed code --- changelog/66160.removed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/66160.removed.md diff --git a/changelog/66160.removed.md b/changelog/66160.removed.md new file mode 100644 index 00000000000..319112ac9d9 --- /dev/null +++ b/changelog/66160.removed.md @@ -0,0 +1 @@ +The ``salt.utils.psutil_compat`` was deprecated and now removed in Salt 3008. Please use the ``psutil`` module directly. From 1f22924a9a5da9348f7a766487fd5b2f449f5b95 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Thu, 29 Feb 2024 15:25:45 +0000 Subject: [PATCH 51/54] Fix the broken `tools docs` command during the merge-forward --- tools/docs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/docs.py b/tools/docs.py index 63cbb331797..3471ea1e8f2 100644 --- a/tools/docs.py +++ b/tools/docs.py @@ -27,6 +27,12 @@ docs = command_group( requirements_files=[ tools.utils.REPO_ROOT / "requirements" / "base.txt", tools.utils.REPO_ROOT / "requirements" / "zeromq.txt", + tools.utils.REPO_ROOT + / "requirements" + / "static" + / "ci" + / "py{}.{}".format(*sys.version_info) + / "docs.txt", ], install_args=[ "--constraint", From 628c0d271349b173b4af7c8bd9b88890c033a2ed Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 5 Mar 2024 21:53:45 +0000 Subject: [PATCH 52/54] Fix lint issues in 3007.x branch --- salt/client/ssh/wrapper/__init__.py | 6 ++- salt/client/ssh/wrapper/cp.py | 4 +- salt/client/ssh/wrapper/mine.py | 24 ++++++++---- salt/modules/win_appx.py | 4 +- .../rest_tornado/saltnado_websockets.py | 2 +- salt/transport/ws.py | 15 ++++---- salt/utils/vault/cache.py | 2 +- salt/utils/vault/factory.py | 9 +++-- salt/utils/vault/leases.py | 4 +- salt/utils/win_pwsh.py | 2 +- .../integration/modules/test_pillar.py | 4 +- tests/pytests/integration/ssh/test_cp.py | 38 +++++++++---------- tests/pytests/unit/crypt/test_crypt.py | 2 +- tests/pytests/unit/states/test_selinux.py | 12 +++--- tests/pytests/unit/test_request_channel.py | 2 +- 15 files changed, 71 insertions(+), 59 deletions(-) diff --git a/salt/client/ssh/wrapper/__init__.py b/salt/client/ssh/wrapper/__init__.py index 4d29c168491..cfa977be0f0 100644 --- a/salt/client/ssh/wrapper/__init__.py +++ b/salt/client/ssh/wrapper/__init__.py @@ -271,7 +271,7 @@ def parse_ret(stdout, stderr, retcode, result_only=False): try: retcode = int(retcode) except (TypeError, ValueError): - log.warning(f"Got an invalid retcode for host: '{retcode}'") + log.warning("Got an invalid retcode for host: '%s'", retcode) retcode = 1 if "Permission denied" in stderr: @@ -307,7 +307,9 @@ def parse_ret(stdout, stderr, retcode, result_only=False): # Ensure a reported local retcode is kept (at least) retcode = max(retcode, remote_retcode) except (TypeError, ValueError): - log.warning(f"Host reported an invalid retcode: '{remote_retcode}'") + log.warning( + "Host reported an invalid retcode: '%s'", remote_retcode + ) retcode = max(retcode, 1) if not isinstance(result, dict): diff --git a/salt/client/ssh/wrapper/cp.py b/salt/client/ssh/wrapper/cp.py index 111eab1ae39..eadabbcb750 100644 --- a/salt/client/ssh/wrapper/cp.py +++ b/salt/client/ssh/wrapper/cp.py @@ -964,7 +964,7 @@ class SSHCpClient(salt.fileclient.FSClient): def _send_file(self, src, dest, makedirs, cachedir): def _error(stdout, stderr): - log.error(f"Failed sending file: {stderr or stdout}") + log.error("Failed sending file: %s", stderr or stdout) if Path(self.get_cachedir(cachedir)) in Path(src).parents: # remove the cached file if the transfer fails Path(src).unlink(missing_ok=True) @@ -1022,7 +1022,7 @@ class SSHCpClient(salt.fileclient.FSClient): "rm -rf " + shlex.quote(str(path)) ) if retcode: - log.error(f"Failed deleting path '{path}': {stderr or stdout}") + log.error("Failed deleting path '%s': %s", path, stderr or stdout) return not retcode def get_url( diff --git a/salt/client/ssh/wrapper/mine.py b/salt/client/ssh/wrapper/mine.py index 80e114ac738..6656ac6b56b 100644 --- a/salt/client/ssh/wrapper/mine.py +++ b/salt/client/ssh/wrapper/mine.py @@ -102,21 +102,29 @@ def get( for host, data in mrets.items(): if not isinstance(data, dict): log.error( - f"Error executing mine func {fun} on {host}: {data}." - " Excluding minion from mine." + "Error executing mine func %s on %s: %s." + " Excluding minion from mine.", + fun, + host, + data, ) elif "_error" in data: log.error( - f"Error executing mine func {fun} on {host}: {data['_error']}." - " Excluding minion from mine. Full output in debug log." + "Error executing mine func %s on %s: %s." + " Excluding minion from mine. Full output in debug log.", + fun, + host, + data["_error"], ) - log.debug(f"Return was: {salt.utils.json.dumps(data)}") + log.debug("Return was: %s", salt.utils.json.dumps(data)) elif "return" not in data: log.error( - f"Error executing mine func {fun} on {host}: No return was specified." - " Excluding minion from mine. Full output in debug log." + "Error executing mine func %s on %s: No return was specified." + " Excluding minion from mine. Full output in debug log.", + fun, + host, ) - log.debug(f"Return was: {salt.utils.json.dumps(data)}") + log.debug("Return was: %s", salt.utils.json.dumps(data)) else: rets[host] = data["return"] return rets diff --git a/salt/modules/win_appx.py b/salt/modules/win_appx.py index e6057f8fa3b..fa288d56054 100644 --- a/salt/modules/win_appx.py +++ b/salt/modules/win_appx.py @@ -270,7 +270,7 @@ def remove(query=None, include_store=False, frameworks=False, deprovision_only=F remove_package(item) else: if bundle and bundle["IsBundle"]: - log.debug(f'Found bundle: {bundle["PackageFullName"]}') + log.debug("Found bundle: %s", bundle["PackageFullName"]) remove_name = bundle["PackageFullName"] if deprovision_only: log.debug("Deprovisioning package: %s", remove_name) @@ -288,7 +288,7 @@ def remove(query=None, include_store=False, frameworks=False, deprovision_only=F # The old one will not have an installer and will throw an error # We should be safe just logging the message # This is really hard to replicate - log.debug(f"There was an error removing package: {remove_name}") + log.debug("There was an error removing package: %s", remove_name) log.debug(exc) if isinstance(packages, list): diff --git a/salt/netapi/rest_tornado/saltnado_websockets.py b/salt/netapi/rest_tornado/saltnado_websockets.py index 32ae448ff6e..8a52f3c11d8 100644 --- a/salt/netapi/rest_tornado/saltnado_websockets.py +++ b/salt/netapi/rest_tornado/saltnado_websockets.py @@ -314,7 +314,7 @@ class AllEventsHandler( """ # pylint: disable=W0221 - def get(self, token): + def get(self, token): # pylint: disable=invalid-overridden-method """ Check the token, returns a 401 if the token is invalid. Else open the websocket connection diff --git a/salt/transport/ws.py b/salt/transport/ws.py index 142ffe58817..301beff484f 100644 --- a/salt/transport/ws.py +++ b/salt/transport/ws.py @@ -128,9 +128,9 @@ class PublishClient(salt.transport.base.PublishClient): conn = aiohttp.UnixConnector(path=self.path) session = aiohttp.ClientSession(connector=conn) if self.ssl: - url = f"https://ipc.saltproject.io/ws" + url = "https://ipc.saltproject.io/ws" else: - url = f"http://ipc.saltproject.io/ws" + url = "http://ipc.saltproject.io/ws" log.error("pub client connect %r %r", url, ctx) ws = await asyncio.wait_for(session.ws_connect(url, ssl=ctx), 3) except Exception as exc: # pylint: disable=broad-except @@ -154,7 +154,7 @@ class PublishClient(salt.transport.base.PublishClient): if self._ws is None: self._ws, self._session = await self.getstream(timeout=timeout) if self.connect_callback: - self.connect_callback(True) + self.connect_callback(True) # pylint: disable=not-callable self.connected = True async def connect( @@ -282,9 +282,6 @@ class PublishServer(salt.transport.base.DaemonizedPublishServer): def __setstate__(self, state): self.__init__(**state) - def __setstate__(self, state): - self.__init__(state["opts"]) - def __getstate__(self): return { "opts": self.opts, @@ -424,7 +421,9 @@ class PublishServer(salt.transport.base.DaemonizedPublishServer): self._connecting = asyncio.create_task(self._connect()) return self._connecting - async def publish(self, payload, **kwargs): + async def publish( + self, payload, **kwargs + ): # pylint: disable=invalid-overridden-method """ Publish "load" to minions """ @@ -545,7 +544,7 @@ class RequestClient(salt.transport.base.RequestClient): self._closed = False self.ssl = self.opts.get("ssl", None) - async def connect(self): + async def connect(self): # pylint: disable=invalid-overridden-method ctx = None if self.ssl is not None: ctx = tornado.netutil.ssl_options_to_context(self.ssl, server_side=False) diff --git a/salt/utils/vault/cache.py b/salt/utils/vault/cache.py index 7e14681699e..393c51d57b2 100644 --- a/salt/utils/vault/cache.py +++ b/salt/utils/vault/cache.py @@ -96,7 +96,7 @@ class CommonCache: if int(time.time()) - updated >= self.ttl: if flush: log.debug( - f"Cached data in {self.cbank}/{ckey} outdated, flushing." + "Cached data in %s/%s outdated, flushing.", self.cbank, ckey ) self.flush() return False diff --git a/salt/utils/vault/factory.py b/salt/utils/vault/factory.py index 6f437f0e10a..5be01d4e167 100644 --- a/salt/utils/vault/factory.py +++ b/salt/utils/vault/factory.py @@ -213,11 +213,14 @@ def clear_cache( ] ): scope = cbank.split("/")[-1] - _get_event(opts)(tag=f"vault/cache/{scope}/clear") + _get_event(opts)( # pylint: disable=no-value-for-parameter + tag=f"vault/cache/{scope}/clear" + ) except Exception as err: # pylint: disable=broad-except log.error( - "Failed to revoke token or send event before clearing cache:\n" - f"{type(err).__name__}: {err}" + "Failed to revoke token or send event before clearing cache:\n%s: %s", + type(err).__name__, + err, ) if cbank in context: diff --git a/salt/utils/vault/leases.py b/salt/utils/vault/leases.py index 34214309887..f8ebd4f3060 100644 --- a/salt/utils/vault/leases.py +++ b/salt/utils/vault/leases.py @@ -518,8 +518,8 @@ class LeaseStore: try: self.renew(lease, increment=increment) except (VaultPermissionDeniedError, VaultNotFoundError) as err: - log.warning(f"Failed renewing cached lease: {type(err).__name__}") - log.debug(f"Lease ID was: {lease}") + log.warning("Failed renewing cached lease: %s", type(err).__name__) + log.debug("Lease ID was: %s", lease) failed.append(ckey) if failed: raise VaultException(f"Failed renewing some leases: {list(failed)}") diff --git a/salt/utils/win_pwsh.py b/salt/utils/win_pwsh.py index 7e6e659f91f..c1cf5929332 100644 --- a/salt/utils/win_pwsh.py +++ b/salt/utils/win_pwsh.py @@ -49,7 +49,7 @@ def run_dict(cmd, cwd=None): if "retcode" not in ret or ret["retcode"] != 0: # run_all logs an error to log.error, fail hard back to the user - raise CommandExecutionError(f"Issue executing PowerShell cmd", info=ret) + raise CommandExecutionError("Issue executing PowerShell cmd", info=ret) # Sometimes Powershell returns an empty string, which isn't valid JSON if ret["stdout"] == "": diff --git a/tests/pytests/integration/modules/test_pillar.py b/tests/pytests/integration/modules/test_pillar.py index eceede84493..8ebe4e1a03c 100644 --- a/tests/pytests/integration/modules/test_pillar.py +++ b/tests/pytests/integration/modules/test_pillar.py @@ -662,7 +662,7 @@ def test_pillar_refresh_pillar_beacons( # Give the beacons a chance to start time.sleep(5) - event_tag = f"salt/beacon/*/status/*" + event_tag = "salt/beacon/*/status/*" start_time = time.time() event_pattern = (salt_master.id, event_tag) @@ -686,7 +686,7 @@ def test_pillar_refresh_pillar_beacons( # Give the beacons a chance to stop time.sleep(5) - event_tag = f"salt/beacon/*/status/*" + event_tag = "salt/beacon/*/status/*" start_time = time.time() event_pattern = (salt_master.id, event_tag) diff --git a/tests/pytests/integration/ssh/test_cp.py b/tests/pytests/integration/ssh/test_cp.py index 051b0713877..030dc3b14e9 100644 --- a/tests/pytests/integration/ssh/test_cp.py +++ b/tests/pytests/integration/ssh/test_cp.py @@ -88,7 +88,7 @@ def test_get_file(salt_ssh_cli, tmp_path, template, dst_is_dir, cachedir): ) for path in (tgt, master_path): assert path.exists() - data = path.read_text() + data = path.read_text(encoding="utf-8") assert "Gromit" in data assert "bacon" not in data @@ -101,7 +101,7 @@ def test_get_file_gzipped(salt_ssh_cli, caplog, tmp_path): assert res.data == str(tgt) assert "The gzip argument to cp.get_file in salt-ssh is unsupported" in caplog.text assert tgt.exists() - data = tgt.read_text() + data = tgt.read_text(encoding="utf-8") assert "KNIGHT: They're nervous, sire." in data assert "bacon" not in data @@ -125,7 +125,7 @@ def test_get_file_makedirs(salt_ssh_cli, tmp_path, cachedir): ) for path in (tgt, master_path): assert path.exists() - data = path.read_text() + data = path.read_text(encoding="utf-8") assert "KNIGHT: They're nervous, sire." in data assert "bacon" not in data @@ -137,7 +137,7 @@ def test_get_file_from_env(salt_ssh_cli, tmp_path, suffix): assert ret.returncode == 0 assert ret.data assert ret.data == str(tgt) - data = tgt.read_text() + data = tgt.read_text(encoding="utf-8") assert "Gromit" in data assert ("Comte" in data) is bool(suffix) @@ -175,7 +175,7 @@ def test_get_template(salt_ssh_cli, tmp_path, cachedir): ) for path in (tgt, master_path): assert tgt.exists() - data = tgt.read_text() + data = tgt.read_text(encoding="utf-8") assert "bacon" in data assert "spam" not in data @@ -198,7 +198,7 @@ def test_get_template_dest_empty(salt_ssh_cli, cachedir): assert res.data == str(tgt) for file in (tgt, master_path): assert file.exists() - data = file.read_text() + data = file.read_text(encoding="utf-8") assert "bacon" in data assert "spam" not in data @@ -293,7 +293,7 @@ def test_get_url(salt_ssh_cli, tmp_path, dst_is_dir, cachedir): ) for file in (tgt, master_path): assert file.exists() - data = file.read_text() + data = file.read_text(encoding="utf-8") assert "KNIGHT: They're nervous, sire." in data assert "bacon" not in data @@ -317,7 +317,7 @@ def test_get_url_makedirs(salt_ssh_cli, tmp_path, cachedir): ) for file in (tgt, master_path): assert file.exists() - data = file.read_text() + data = file.read_text(encoding="utf-8") assert "KNIGHT: They're nervous, sire." in data assert "bacon" not in data @@ -343,7 +343,7 @@ def test_get_url_dest_empty(salt_ssh_cli, cachedir): assert res.data == str(tgt) for file in (tgt, master_path): assert file.exists() - data = file.read_text() + data = file.read_text(encoding="utf-8") assert "KNIGHT: They're nervous, sire." in data assert "bacon" not in data @@ -387,7 +387,7 @@ def test_get_url_https(salt_ssh_cli, tmp_path, cachedir): ) for path in (tgt, master_path): assert path.exists() - data = path.read_text() + data = path.read_text(encoding="utf-8") assert "Salt Project" in data assert "Package" in data assert "Repo" in data @@ -414,7 +414,7 @@ def test_get_url_https_dest_empty(salt_ssh_cli, tmp_path, cachedir): assert res.data == str(tgt) for path in (tgt, master_path): assert path.exists() - data = path.read_text() + data = path.read_text(encoding="utf-8") assert "Salt Project" in data assert "Package" in data assert "Repo" in data @@ -500,7 +500,7 @@ def test_get_url_ftp(salt_ssh_cli, tmp_path, cachedir): ) for path in (tgt, master_path): assert path.exists() - data = path.read_text() + data = path.read_text(encoding="utf-8") assert "The official FreeBSD" in data @@ -515,7 +515,7 @@ def test_get_file_str_salt(salt_ssh_cli, cachedir): master_path = _convert(salt_ssh_cli, cachedir, tgt, master=True) for path in (tgt, master_path): assert path.exists() - text = path.read_text() + text = path.read_text(encoding="utf-8") assert "KNIGHT: They're nervous, sire." in text @@ -540,7 +540,7 @@ def test_get_file_str_https(salt_ssh_cli, cachedir): master_path = _convert(salt_ssh_cli, cachedir, tgt, master=True) for path in (tgt, master_path): assert path.exists() - text = path.read_text() + text = path.read_text(encoding="utf-8") assert "Salt Project" in text assert "Package" in text assert "Repo" in text @@ -572,7 +572,7 @@ def test_cache_file(salt_ssh_cli, suffix, cachedir): ) master_path = _convert(salt_ssh_cli, cachedir, tgt, master=True) for file in (tgt, master_path): - data = file.read_text() + data = file.read_text(encoding="utf-8") assert "Gromit" in data assert ("Comte" in data) is bool(suffix) @@ -622,7 +622,7 @@ def test_cache_file_context_cache(salt_ssh_cli, cachedir, _cache_twice): for file in (tgt, _convert(salt_ssh_cli, cachedir, tgt, master=True)): assert tgt.exists() # If both files were present, they should not be re-fetched - assert "wasmodifiedhahaha" in tgt.read_text() + assert "wasmodifiedhahaha" in tgt.read_text(encoding="utf-8") @pytest.mark.parametrize("_cache_twice", ("master", "minion"), indirect=True) @@ -637,7 +637,7 @@ def test_cache_file_context_cache_requires_both_caches( for file in (tgt, _convert(salt_ssh_cli, cachedir, tgt, master=True)): assert tgt.exists() # If one of the files was removed, it should be re-fetched - assert "wasmodifiedhahaha" not in tgt.read_text() + assert "wasmodifiedhahaha" not in tgt.read_text(encoding="utf-8") def test_cache_file_nonexistent_source(salt_ssh_cli): @@ -663,7 +663,7 @@ def test_cache_files(salt_ssh_cli, files): assert isinstance(path, str) path = Path(path) assert path.exists() - data = Path(path).read_text() + data = Path(path).read_text(encoding="utf-8") assert "ARTHUR:" in data assert "bacon" not in data @@ -893,4 +893,4 @@ def test_cp_cache_file_as_workaround_for_missing_map_file( assert isinstance(ret.data, dict) assert ret.data assert tgt.exists() - assert tgt.read_text().strip() == "bar" + assert tgt.read_text(encoding="utf-8").strip() == "bar" diff --git a/tests/pytests/unit/crypt/test_crypt.py b/tests/pytests/unit/crypt/test_crypt.py index 6062dd0c44d..a9475d05b75 100644 --- a/tests/pytests/unit/crypt/test_crypt.py +++ b/tests/pytests/unit/crypt/test_crypt.py @@ -193,4 +193,4 @@ def test_pwdata_decrypt(): b"\x1a(\x04&yL8\x19s\n\x11\x81\xfd?\xfb2\x80Ll\xa1\xdc\xc9\xb6P\xca\x8d'\x11\xc1" b"\x07\xa5\xa1\x058\xc7\xce\xbeb\x92\xbf\x0bL\xec\xdf\xc3M\x83\xfb$\xec\xd5\xf9" ) - assert "1234", salt.crypt.pwdata_decrypt(key_string, pwdata) + assert salt.crypt.pwdata_decrypt(key_string, pwdata) == "1234" diff --git a/tests/pytests/unit/states/test_selinux.py b/tests/pytests/unit/states/test_selinux.py index 006bfdec3ef..55fdbcd6027 100644 --- a/tests/pytests/unit/states/test_selinux.py +++ b/tests/pytests/unit/states/test_selinux.py @@ -151,14 +151,14 @@ def test_port_policy_present(): with patch.dict(selinux.__opts__, {"test": False}): comt = ( f'SELinux policy for "{name}" already present ' - + f'with specified sel_type "http_cache_port_t", protocol "None" ' - + f'and port "None".' + + 'with specified sel_type "http_cache_port_t", protocol "None" ' + + 'and port "None".' ) ret.update({"comment": comt, "result": True}) assert selinux.port_policy_present(name, "http_cache_port_t") == ret comt = ( - f'SELinux policy for "name" already present ' + 'SELinux policy for "name" already present ' + f'with specified sel_type "http_cache_port_t", protocol "{protocol}" ' + f'and port "{port}".' ) @@ -337,14 +337,14 @@ def test_port_policy_absent(): with patch.dict(selinux.__opts__, {"test": False}): comt = ( f'SELinux policy for "{name}" already absent ' - + f'with specified sel_type "http_cache_port_t", protocol "None" ' - + f'and port "None".' + + 'with specified sel_type "http_cache_port_t", protocol "None" ' + + 'and port "None".' ) ret.update({"comment": comt, "changes": {}, "result": True}) assert selinux.port_policy_absent(name, "http_cache_port_t") == ret comt = ( - f'SELinux policy for "name" already absent ' + 'SELinux policy for "name" already absent ' + f'with specified sel_type "http_cache_port_t", protocol "{protocol}" ' + f'and port "{port}".' ) diff --git a/tests/pytests/unit/test_request_channel.py b/tests/pytests/unit/test_request_channel.py index dda663057d9..f4a0f031266 100644 --- a/tests/pytests/unit/test_request_channel.py +++ b/tests/pytests/unit/test_request_channel.py @@ -511,7 +511,7 @@ def test_req_server_chan_encrypt_v2(master_opts, pki_dir): if HAS_M2: aes = key.private_decrypt(ret["key"], RSA.pkcs1_oaep_padding) else: - cipher = PKCS1_OAEP.new(key) + cipher = PKCS1_OAEP.new(key) # pylint: disable=used-before-assignment aes = cipher.decrypt(ret["key"]) pcrypt = salt.crypt.Crypticle(master_opts, aes) signed_msg = pcrypt.loads(ret[dictkey]) From bd564da5b8b7f2e44fe6a2a0080be91ce2336126 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 6 Mar 2024 12:17:24 +0000 Subject: [PATCH 53/54] Skip test if the `rpmdev-vercmp` is not found --- tests/pytests/pkg/integration/test_version.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/pytests/pkg/integration/test_version.py b/tests/pytests/pkg/integration/test_version.py index 1c193a882ab..0524df8ad73 100644 --- a/tests/pytests/pkg/integration/test_version.py +++ b/tests/pytests/pkg/integration/test_version.py @@ -85,7 +85,7 @@ def test_compare_versions(version, binary, install_salt): ) -@pytest.mark.skip_unless_on_darwin() +@pytest.mark.skip_unless_on_darwin @pytest.mark.parametrize( "symlink", [ @@ -117,7 +117,8 @@ def test_symlinks_created(version, symlink, install_salt): ret.stdout.matcher.fnmatch_lines([f"*{version}*"]) -@pytest.mark.skip_on_windows() +@pytest.mark.skip_on_windows +@pytest.mark.skip_if_binaries_missing("rpmdev-vercmp") def test_compare_pkg_versions_redhat_rc(version, install_salt): """ Test compare pkg versions for redhat RC packages. A tilde should be included From c336cdb1c92a39653075e9ffa1612e2243753768 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 6 Mar 2024 12:34:45 +0000 Subject: [PATCH 54/54] Fix test failures --- tests/pytests/unit/states/test_group.py | 8 +++++++- tests/unit/modules/test_zcbuildout.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/pytests/unit/states/test_group.py b/tests/pytests/unit/states/test_group.py index c401c884316..905a94186c3 100644 --- a/tests/pytests/unit/states/test_group.py +++ b/tests/pytests/unit/states/test_group.py @@ -1,5 +1,6 @@ import pytest +import salt.modules.test as testmod import salt.states.group as group import salt.utils.platform from tests.support.mock import MagicMock, call, patch @@ -7,8 +8,13 @@ from tests.support.mock import MagicMock, call, patch @pytest.fixture def configure_loader_modules(): + return { - group: {"__salt__": {"test.ping": MagicMock()}, "__opts__": {"test": False}} + testmod: {}, + group: { + "__salt__": {"test.ping": testmod.ping}, + "__opts__": {"test": False}, + }, } diff --git a/tests/unit/modules/test_zcbuildout.py b/tests/unit/modules/test_zcbuildout.py index 1e2d2836bfd..49aa738329d 100644 --- a/tests/unit/modules/test_zcbuildout.py +++ b/tests/unit/modules/test_zcbuildout.py @@ -258,7 +258,7 @@ class BuildoutTestCase(Base): else: line_break = "\n" self.assertEqual( - f"foo{line_break}", + f"# pylint: skip-file{line_break}foo{line_break}", buildout._get_bootstrap_content(os.path.join(self.tdir, "var", "tb", "2")), )

uGDD4?TI5bzH5ZdwKhV5^&l z6@i0BGeVEf&82LsVtPwY)|UUz;Mu2eFwSzy%^*0br~d)}7=H5Sr`JAFoOvCJ9$kf3 zsPstbd`@4zh7_Y#JHs)aah51GMZN2B4kQM+%Ebkk6cEj}4xb)a2VyP@=g2(SH&xDvj6r4GR)YQ$qAGKWG6hHgDV1%UYDF8(wz)a> z#>n))_v8sdTQZYEGm4cPi8Kj~X|Tw{_6gF3MmrbM^S21v#te<<{Vwj0XNR|$kKyVc zP&%~uKdgr7a`g`m+&`=Wk62COPb9n?exC^`XZB2KQ4cgk@|!Ww%QCYJrL=&3f@Tp~ zIVt*WLWwQF%(<4#07NoGWLprw-5>tJ+BX{y>7&lGwDGGd6hl(pBCRSA_=~|%F(5;V z5D(3lVfi?m*BO%I<+mw{fwbDp@N~;7i7w=sHx^%7aZA4lU%-fgzv~HQhs4j0KlL5E z^pdNYF5!6!oAV=8w{NgnXupp6Ul%c(B~C2_i*?ou5q9DQHBfH!nfISg4=6 zR$cVtvQIduvN@t<$af7Ufr)h`pK@pumggeO*`qtUG*c_+FGOsKYjvDecB;`7UFb1=e zCg$w3bEz683>(%_(f4HyDTmoyczTv(psgs&lYtz`Fw@qR(QXdxmb&4t*-(q%?>hCa zOlhw)FW-MkWgQGyZCQohNC-}ltHIPV;98@i16juBNVnvi5PYpKrkq5oNeaTUyn z#`!#EM~?7+S-BQt`UvYKX;(~D8nQQ^?$tzyWp9{WZ+cN}0-QY*8`GasTrlB1tVIMi z$5e8uKJ4Qo@^0u>(ZaVGviX2TVHd`9i2s1x6#HxIj{i5Z@wcS9mirxKrMSICa`KBo{tl^s4ZyLbkM?9>;e2Yb;;}JZi5E(>5NL1utiGDK25~ zL#y%uYt7A@ZLM^-=sN^cI&z_=6%MSEAn$om_CTdz^Q4u-n73ao<;iD$M3eS_GKs4w z$^FBageG5fDGg8SopnK`_y*X&W3Q5Si!~v~LiLl=&4DKVDq;%h$RpXV@AN8-7U&Z;fuCSHK$|o0_b%oQNx7OJD#*LNWGX%2MobR zHI%c3G(bZMSwSwB>Oy2(#&DS00+ZPpEP3t^sAnx$Rox{>??Dp&@ry`vEw=|FoQi=b zyBb;5Iri96<1xJy-Y{4K2UYJ&nSSzdzn@OjTy`cHc3uorZq!vRM%X*7F{LaphDMqB zZ;ZUL&bF)Wn~U@nAiSPTwq9VTSCvua@SudxXDi59kiHnLb24&2lz!h1W*2v+UKc31 zc%Z&#(8(y`rRa(3nH&5fqXl5ONkApH0~%#CXtEc$e^0MjI{lbQ6idwZ4_FQ-a?z1e zdR{ z$%Z6Hzh3H1fvO{YkpH59!shKVLp(I;RgP|mrTjv?F~O%VkEdxvB*Yv0F*vAyk^ z?w2zf#HT9Wu(vC))oBHzQwgGOs}_E>c?a6v4+61lGF|p*?OZPEvD|L1K!c>)nbOr& zT)OwoLUYY@H4Ay7UTcDmodgJ-D+1A6Ezwy=MBk?AKf?V;HV-Hf`M!;5u`ybn~)t7!I|$sJ|&# z%$7CGjV>h&OG9cg&h|LUW;XH)!U_3v509rmu*b7M*!u68AL#MS4_@w$_jYdHuz!m1 zV_Jv>B}U!`_5jB^)Lm44Yic5y1^GG9>W)aHQlFFPbW(b~tCVSGI|!*to1ewSGFzd2 zN~wvaXiOl&6(4DY$UVLiv{ofQyF+`h_-`o9nSI01V@jN>uO!cHPks!sqmk|G#UUb7 zd8Guv_Tyq=U*F_ot40241iOx*Ck3BkgNU=EgEiaIlPIe`KOXeQv&;$#j9AxF|N3XI(FIbi z)=7vj=I6n0Y6%Z+ckaISI-iqC(G)nD+ss%!tzyAs(M$m!9It!BKD##sIwwH)LcOkYS85 zrL+!9ZZP&HwVIukS=_DMhLOpQj4&c4QA$PPi?Sh3kw*LAF`iu{h4L<*Ys@hB=$hep zoIf;LNE2aG&&8{kwxq$j=G-=aq4@!-WV9>}kqYt9#j#);8w3y7tLkPyN!#ew76-Du7`@(6I^v8po)1 zGgAi3Z$3l}E8onO#2i{F>;-OvEe*f}po!a2q{k=inB19p?A@7NUI1GNi&EwQoRqQY zk$A!AMQ0!?@#G-456zi84u-JF6!xeqRlk~V=!%u2Zdq&NY2~WS*J}8p7r)7UQi@Ff z{0pTV>Ebs^`9%@u96GbElxRAGBRat5@xrhSg;&pk3SDBALSZjfA=l(e=)i&?j#CBn zPFae%UWpsVft^Ze_>)Sl;YEvwdpp)8Y*Gn(q+e?`#DZ~E(B$Q8nXTEXRL@Cwi?l9% z%$rt;&06rFEK#-mUWteD;urJ8F%cl$9{Vh_j6U|^u_u@pLiek@3hDvqLuWFtbDLC= zJ}zQ%i_>oQ2fwAtsl^Fw0zZaR2j>%RHP5<)ZKzNT^aZj?U(fFuKeY(%%HpC{${JWO zOzD(bI4gcvt8Ed3fy%VkwxUftlhs$RNwJ8<6I1fmabDHNB~zu` zf&B1fhrdkTEr!isC-9~VryV4_JHE6SA}Py^IcHMiGUjh_-ana4;}ECY2Y*tu7j%fJ zGe7Ilmk(Rz#uA#f=N9FmM&b+|k5Gu}t}|ALnwVl_a7kK6K9ZKsP4RT-+=~2Ud;J7X z;EHUH5vk186RsC_eIn1T(}Ugr+1*(p5O_4y@0hAz&}6twx?I{EGbvo>+GD6(VA#U! z0^nb-UiBo5*RBo_EKhOAAy*xezBC3>{WnrHLiF+57l%7ud2T4CD+cA48k(pyP1jw0 z0iw77)+!=m%>HKMQ6B;b`eYdeEHQij$_#kkkx^If)x8pDCeWJQaS~!%xrrE`T~*aY zba__~)gb#)IuX@>=Xz!bhjD;F6wn;zy09+QLUsEh0WTflPc(7mBE;gs(zlNuJwWUv zM?KLn^M-nVxymW>VWXX0@ZTKdpAZd02j9TxePqKa35{w+_PW=e2$RxXE_<>|FtQk! zkCgWiW`qvf4r%YpVS{(EqH>*T;V<1UO*C*e^iF3j`-teyh0=?p?>sJpC5MI9_?~!l z0@q7^2Xj~ugHH(B8u_3dw}ls@;&w}3|B?ALbZ<5Dx{^3dyQ)LRD+`|vMk zsVXi*kJ))CFB6+74Cbx3>(o1u5v4lRgWRsC|KNAJ!7jm z%oIv|gs$B-?%(AwHho$47Xhrh@tsn^ZGVQ3-L}wxM{IZE1|BWC*b-8_I6nMgjM}fP zO4>+yxG5GGFGc4zgRNJX0alp1p`j$y#6Kgw!wc&+)`j+cUniC7L0~3YvYE3Qf&ce| z&#zGsorXq9DxkmIe$AJ0NCA;`Gmmmqv3z~&K-z(QObQ3n2K<;eOR_8nH3HjW1J@Pf zLqe#_e^IL3N2(38b*kF2TjV}yT5uJx^-{)`H<(?h8)gc;kro~h1uo||-kKX^%_HtE zOnXQvE3?*$(i0f^8~jM{tu*CQ^ZnQFMDMTWX-L%y0fZ|FqH(QVG>P z-N4Dt4yToeBsIT{OnuInUD>!D@|}*+jIWEh5{vNcs+b=OvKP6oVAk-lnIl`(9P|>S z^^;Q}!kz(Xi7j~DJ`e#h$XYb+jAGmT6eH ztR7C%FV?fmuLiZBe8DN?n*P=J=C!L=ftJo_3Ii$B2yPwm<&RgZ(2+s}TVJDZhHK=^ zKXO@TxOH?yUI;VZt$Jc-Iy8zRN_P<%gXNtovxIe{bcv`DcezmP&#qRAZUc4%kvRfL z+3ba{Jrax4#73myHc`HjKt9<)&Hx8;S^ZHe8KsHK2P$$1==xc(94yPXQpnJ@1Ojvc zy)P4E%^PME)9xOIX0V+3#_o@1ys_zlj3u9IJ4ZR=rpO?9Mo0l^{04wfAxNfY7GzG+ z3qLM&?)YUbCx<=;J{FPdPUsnzHBc?8{L7)c+i z-7+aEE-!vOWiW&;MgTGph=ni45&CURdH3#o^X;R%e@o{zyWU@g4z4_F3^vGNuD?)DG-W=c99JHp7EmIZ2j{M%7!m2t`XI z^0x%CO%7{s{}ku<;?+LoEmhYQ*LRJZ6pk`_XfNj944x0m88?OoXv-*xr@jO9=G0UM zj;sTGHo|e-s;!(rns44}p4p~%TB*c~C-pb>HH<<~%JWxxqK))FZ{UTZ`tLJJ$lLVa zMreV(RQC5?=Vm-OiUCsGYe!dfsrUSV>o=)@!pQH*7WDv9I5E{*s!B6wMP`*QyfV~0 zNLa(xQKy1juTWk}Fp<3(DR>GlJli`*9)S>#;CQoY8$?_c?IJ;sQRNR{k;CT1i1#Mv zaeLKygP$By@<35_P8Se(*AI{C6=QS~Ck{|AYDFT#Ar2_bk1bNthpJFXq)8Fuok>Nu zpe)rGRLpTR+9Juv}d}%8N?@(*_N~PZb6#E!u5qWnZSeb^~Z>0R~k4Z(A`UXu?C*=`SHWMD}y@+ z10#$ReB>fTkeq&2xk;8z5zwa8wob~M2c?N|31vfthq~!z$`Zu41uMb1 zL*iKBh5D!MhMXbepOOKUK2M3_!tE@II?FZ)e#vs`jOqn>Dcuwu-fS_6&O%B^er}8K zoKtZDSg2)wU)$-kL*)`zPw3B4(E;f+;b(y!iz& zroP#vf2z^yThyQn#C~Hi~cm|byE)x{nN_lS68lGU7Z~N zxccVJo7JXsKCV5zpbS^r)$+jRSsDn^8cq-FAplTvqkx?r&EN(0b{-K(dXL%v;3PvV z^Pw?;l71&f=@5h&EI|o=odE!Uj5HIubSi%Z#NEtS&{j9(K-2ZYJfpc9L{hU2(h}xh zLd^62j?0K@w6QEamiFXP6#V#^ebG$TDU%X@)I4-8gp}sLBr^lMl8}Z2v7sYN} zfA-{tobYaa`RvAPvMc;tM7CQ`uEWKT35K1(hdIkT6NBz=%K_Q?*8zTCnwseu8o zVf>1_OPi-JF2~GG$d7?+q7F#QjoWmg4%(wz=HJYrv$=H+Lpj_y2E2hVo6rdn8=Wm`-7t9KhL4-j1p&Bm~6_lpmVIW3wFyh`HKqc=nChB zbX-!zW!km@D?LFh+d66{iZn}9**P;ct#E3l?R?IjG6;yapsiW!~?iNRRmsZyPU-bSg>`~tc)WyK67F1S)V@UXRm1U^hk28 z(kU@{E>1A3Q41NWH^Hvv_H9SWE$9I0IPn-eC0?Zm=mrftMRx^so!RDAm`2tIaMt|_x{TOD+MjXCbc4y05gQa`-9}OtzMDYbOTWs9EJXq6v z9QBsvsK*32Um92+gu-i?vOc=>v9y3Oh8JPs@$TdYt5Kr7dm!BlNW@#b0xg2;4SJHg z;-`GmPyt#$&Ms9fAanG??6UEb9DH^e{ohG`Dvf#@gMppPAXDfUTR6h0<1Rfg#&v1< zdUuCX1Kbya20Rr4v1kPCdGufDWFQ=Qrr2B9frkc_}9ra03GuPMs<BFKcZ_hFbY|7+Y)n~(poRQ~N=LQUj2G7H>^}WE-uEcnU2!^1} zCbd^i?Hv^}4>lvitaj5E+*#P|jjta2nlurAyj;0Q4x?6)bb^&gaMSn z?+5>PW7O1jv)`MK9^P4h6j(9dtp()^Ai&1Y(BWV_BW43zeF-G z9G_IOBZJVL$Kl<9+Z6~&jU}7Seg?GG??2oaQ9b_tL((s7jO=F?xAOGl@YLk`a-#4rx*?)a^_u+$ezWC3_ z8=H@GeDHXzuOITT_p(iPbo)MMZnXCAYyYJ$IhXYTza6bFeR&2R*xtzr%C99>2mf_@ z{NnT#@&tAiLL{&~;WO=)sQPvC@i%0r`Z z`Mr!^D$p^4Jnig`3C2(w`Y3kzRM%KPjui-kBm{(|6UAOsQZGD3xfFR@3r?NoxNB+y;eSaa{xk3Fy(D4nj<5wOTc|(Cf zY!LcIY2|;Zp9j~yT z|NivG>ua~HZqbcZ{`winPIb(qzH?YJP`>k8IKvfL6v4L{gFU@*ltUeT_(+s*3Y%a| zh5>CTKrtC_9dEzRh&5JUEdrD&+!^08ZzqYd&t0y)v05INrvg#4E<}jzu%E8HI~s9! zE-1K=&HneMqrkj&AIcA|me{7F5x%v$3YydA^~wI;NH*e=x8QtSw?|t_RYE;!ytsmGu@-S>FvF$t7OJ#kXbAl6hOgpIzGZr*rB49?=FOd^_xm^$$( zX1q4}bZfwcF9*uITN!*siZxWK?Xf~^B=L0W&^p0z!@7#eSWCn2rl=@nnB-qmrLn8< z#7w(%1+D#sGW?s>K)XTRSQS7qG0)ayxXGyvS2$haB4?TxgSQ>ty2*s&Tt-jcfni(= zK1r3QM_guDJ%PohY^ja%yM6!*hyHOiw;^B|F~CTMg~8fakf2B3I^|j3+QC6})eGMe zcWs?5qg~{P1Y{mrU_cNtqCycq6}+<4$%T_cVv#ur@)dIVx|LWz;f^G%TvUODE9f3y zdxAU$TiD`Ge-~DvOaoZdlr_6ASev2EJj4Nc>7s($6cYCrKT)>erWJ_0ny`pO{$&!~ zX0}|--vk>#m(6SNejU1%u(h5pmLT}LRc|D7;*k~9l=kGCp8cB6&@Qb*71+xMcOQRq z=U$Ot#F#`vqbI}p#TX#QQ?Oh)RO%lUF-i%C=g?3eq=nG}UJR9r5Asxpmko)Gi>Z+o z?#Rah4HqenfiJVnBGG&5MHBWmyrRWSeHmmoaBlaYj3F>5HB9b1{du2%3J9o%`{P8P zdQxME+*Gi^-%ahMe;+d~%_McVTRCGC0jo^W-d}WsyzyE46Wx8#_T)D~e5R*XViLQX zli&Tay~(e;wBcctAvMKaDM?(*v`KQn8P{n@I6qckSKuRk#9FMlnrJzM`29 zZ!O5K*kM&jBAs}bnn0KHsvp%`F$oTkX(oKWGz&BPz!O{z{sb!$p*_YgETu%wqe_{YUN;q;qBus0yMoJ7Ut$B zmtqCJ{aOPz0r`S-)<2BL=9EkZVKh0Zl~~7!GSdNEvPZ(+&+&F5ERnI zwQb*fd|9*!Miy*fjl!dtI^pN4^oYz2-=RS6>)q|wa9__&E>oRYzTZk~XR>^Pu0`BX z!BPjWuv+4iLaHl71aiJuL}iNHW|`A@Hfx5OLq+e~2%~iy!QekOtP0zQOc92Ie>^6? z_|`ENv(B6-?lmT5&f&odSrg5crDdFOe~O$UX2@jHjYYmSLReYZ_DI>rp2;AkAkv&7 zHG;Ro0p%A#t{M7R#wSikF)Ed)j^wfUk0=cRP)Zwh-5ce{rJ&p%e*V3;zi z?{fKiSrPa+sK$;a}J5Fm*aFf0Q)tn7X5&-Yh{zWTc6ngPkm-n&n3ZPvg{AF8XX zs_WF%=q;=?M=)b8USeWb@`B$q5_aTCUU+f_PV*(dz^fHX66XBN3R^;!T}lhoPBlOp z0u@W(Uk55v**H()5|wXZtBv<7h6@&2?vg2`txfo=ky@K^jiA7E##bjVkCxk5e{H>1 zP-~7}tT-_)*+)7}rZC?}Js{(+YsPN(D=9OBh#bgi;D6XZvN8I>Z-d++6duMifR}3M zlQX)+W74YetmL#U0XYNoY&#A7>VviSfP4FR=N#x5_acDNY#OGA*oc#X@5sPW+b3P* zug1RQJo1xTN`=hJ$<)@HBXnAFSYzjbS;EDdKqUs!4CMNEQ-bA(2ZK8fe5}NFdeFC$ z1N%zw`)?OrfVZB%0&l|-9yv6RHozDrDN(N(>nVWy&ZPKSEN5UtgRj2u-~h&HJ($}n z$gb*pxz4{BVNvof0Buclm`o%dqR-r&rI7NTuEP$UBMdRin4AiWS5vg4`ww4it$9XR zJ(QoYQzPLP6Ra+}D(7))#P5$@9C1Yz1ekzJ8E%gHnGNMgZ3e6b-!1n>YB(B&29OQR zTuFnQ#h+AR9HVZ9M;#l4=TNf<#(4m2;mT@Y@ldS_)5FRnmg`l_Fc~(hY7TSVj8u270*=)E;-gi&zP5-Fb*!hc zo_$lMbrKz#Mk>D3w(A&@Q-`*tD~!g+GAi9p5m`>RQ|YDi+N8pO7f?R@`2!kB)NR5i zfE3hTdO^i59Egw+)|YOOAWs`!?6zCFQ8mM3r#dXW@=IWhShX0SF)Y4CS5c(fu3TCf zNwW^6_^Z5vEP*5vNv#u9ND!g;Db$>iR!fr4$`??*JW?bWj1OL7M$}^uWC0fDiRiK6 zohqr0qR2oviY@dYE+XfG*E28K5Fjax-9X^4o8^l;v_NwUwf$l!>!HzL=8QUhD;F3x-AU(ab^;!w??LmUYI< z?+v(%3<&5;4(F2Hz(wdj-G4oE{29&PW4a4W;TjY;i&a644FVwLYVE}XqJ*ee5Du|c zo7OQc*TOk+Lc2@lIpITWkU)H$U3FlM;`{6Qq5lm&po`&XC?^?bo)Ypn9r84Bm&=>Y zf4wufv+*zMgV0Z`(}Y^|r$lV_h{i)sy304&*(NICde!g|>WTb?9Ggd|`NQ6($g5X- z2M54E`HzEy(RjZJWCES+gh%?3%QTH7S+C))F0SHl*6P8sOO=fE6?r+cYI4HopW2r9 z?Npoe=I&YtI3v8^oQ25_*I?PI`7C6u8tO~Nc5-l5K!o^M!iSLoR5gB8OGOhn7NPXY zh54Ovc5^nyOAh#x2l-fey@ECHdkW{OYw5J+d zRh3~(q4FTQ7Sy{-AE`XRejJm~T;m}txNVwC^V|f%W(q7qRSSOQO^KDADbh>#EYIZKU@q! z6I@@tJ9_YN{r1LRbI{r}3z$WRDl%eW1fVaiDaJ3ap_bEsA7-HYx2p+addJ92r z4jE;Y>b!~LM(JRR)yR2iE(PKvc#w#XSRQAbNw1Znp&=hx2 zBKDFGaY?5Tr-h#3Ru7n@bOt?jWbyggsp^-F8cU}9c3D~avJ{%W<_NfXc7&PwqVX+OZJ6w42qks+J2>utoRFzD_Ivc5+_m! zWJ=3Lda;H&ywRGqq+OI>>JcS#1j{)4aj*qnxV|&L8J#!k$S- zaLgFV2+fke)klG$X#}?#U0_x7+iL+IEpz}blDJ%Qjl!=VV2V|o_JL4r_q`s>#9`LEYC1tafXi2#GU;YxCvEK3w`r= zk-XKt*D4h(+tfv^>{^^5eBheR6=O;14#u!t%dl$sK1lj?*I#c_1!eC#E>5{W^$%aB zp6hdaYIvL5QM?#^AbV-k>JSZKxvDkue^ur**fapG@oTB@H_jINmLpnPx|ST14FY(1 z!HOl!+k0GK91KZm;)nInlm^`|t=U7h*O3n#c3vQ0TjQ%_meo@0j1z09{m?&0m}i}| z6GWG?E-B;gn9zOWZEnfvi^Q;CivIH3TTbQ{G?ly&1PC*6ksiJu|3A6QWKqrjTa&H*#-_zEz%B zJDO`D1>%%yw)LzGtZ$JtGIdfv-9L5V;+NYtEhF3-2BFFVw<=^{Op)yc8OczMj;h}0-gH9D-F)$GbeLz%twoc<;&3< zx=034e+JcHg#mnI&f%R`+`BU(`Y3M+-fYY2x*rP4CR<-q(JQ(B5DiTXr=UA!vxp+H z^D2A`pgiH*(Z6b?cD`#s($6T~EJk4|O@lyEt}FRKOJ-5V8kL?MxH8TXW&8PqUlpqh z3>u1fT6%+vR9p8S{*5>2R4k8QQ39;5#_ZFWTIX5n|9;+D7r8LZBf(UyP3Hh&1 z*4!L5wM}z%rfO?plj?6Xv13Qy3Z_~$=Rq|ay=u?MfKU-?`?LrBTES@h39(Ba76PDH z5rebm$qeo+4+u!;t{P_&a{ijP@Kv!q9y~ZYAw5&<1gW6Ot z4Tg(j5aj!KntY^t+zT(0C(GasjAebc8FVi2(n&JRbnZG4rVNr0e#PD12w~*@6(DSc zuxx`8w7_~#-IcsOkTXY5@dgcADhoQ!_Q{idjs_0XqqD;&C`(d4bH}fUDt%nJxzLn! zNiM0G1a!~$Rd5dfmKA=^V2c#i>cD{hM%0M}aQ^G~vRyJQf|)G~02jia^-vaA;S7F; zz3TU0oqnyqPHi(i(4KjrVviSq2V?^@AXArtTcxdQrXUHM)9Bsf>6O}IUkRj8phtN> z-PxmZH@z&+WM~QR#9dmX9pMLKW$Gxi7)z2QE_Y33=w9MW6B=T48Z_dmCTtzFMYU^R zaq>}%gG$upLh-B4U8t&|Xs}#uo;5bMq}+c7bPjJu?5qxQM$iMH>xuZ-Ri<*z0BLIc zgsN^I5duCk4Ef4LEM<{cYxx$dp9Kt4YnqN>J}EoGR?NJ)#``dCnK|}@zoweQZ^aUF znG3xxO-?9IjaF<|n7oSZ=8w845&c!x5-FS)>YAx)-hC)1rWczfdDCeK{=|a7nT!B} ze^)oxHa0x=bHxg-Um2`z{^iQxZ>x8CVoS9?#L@e^Ug3ny{U(ttB?DO=Q-d34Tanud zLvZ?AhLL0kZ)l&L6a)0}V@rfX)fY%spf4V@bo1$hlw!SpU>eVsa zn9Of2*9SgkT%S?D1$G|$nAae=F_PC5&>Y zOQuo$TktKizi!)Z$?`&_<{G?({IoIV5#;C29cf$OmY;AH_1{V5@6a!zx;vpInPxTvm&R=;}Q-N9VO}JnxdR)3zV#Q zcEa`Eg{Qk^D{sp*Qu!=hCTm&cWy=@zm`-$9m5!%Y1iCGoug)a@g zbfYvUo2vE6b@RP+6d#A8X2m<(D5cK_6H6E$GX46k4LJ>DGV*KPdpxp&sy?QwgFbzaPJUpHGRbe_XP4sw5Tyi4kkv>unS<_y8 zY?1fpnklpo31u$P$LQwd4%e*`%?=`2#*bOvV>7V@eJRGpmb-o-0ur#cHfXF4GZsua z*$G7YIaSgRQrSD=gc&;bIx-!~Y~(Q7XDLDO5k92m(vQRYn=(U$akH)38PKg(Y?b@d zMB{FA6(EK017PaS4 zw2rovvUj#^o#=3ZK-*O(v#7CeqK}`W$Pa0PrS?J=gEw6}-ntg!ZO!?vWyGr1bx2$c z8Q#S9`g8aqt(aml;?Ftt4&NyIRD;QhMe2|HXh6dDEBn|{Q>%ozpH8LLRT&66{+dz? z*AYMUAc<>J)?vh|+hsf;_Hz1LNJ`2vUpE@)k3%)p!x5yYE;q?VpQD6mXicRHIrerC9$ik;rnQE`yHvcFJX>)xJ{_YTTJz!Qj*Gy^ zm-lV=nRJ_AD2CGV+GC*Qa5LFPaIiFuiKbEkuQjJ*LhH}np@Zl&Nv8qO$fr0!xC}S) zoi<~{BIoAcs)lc~5tEp6%D|p+)J=_Qk|~(#lbR`w-di6e5lIU43xyab#aXkoqzF*z zNUatD*siSR9fzjdmBCC}ZyMEO2X65|*?aBPEbKm?Ss{~5hv& zMo#s?E;0I)qgA8Y~F^=pqO`8~60@Y~y6O-7sttK?DIheh&)~B1bNP7-k_^}b3aU_px zS=`u`;SExGVpLcU{HrL0-5`_L<*udWuH2<|tL}x`xh#)(x#Q*+7+3FYT_3DclNtXI zH>$qdx=T3+-5}6eP9POKSBlB*Cv79)Fowk!C?5?dmky`#?b4ah=1(B|krx!|C^H4L zQfumtqGfo$JsO+S&X&5glCzP?lE2!-1UNYA@*@$6RH*KG)t=G19Maa@0Ew{C`jKt} z=hGGd6=5YSoKhqTD@QTwsv$+%rb$;^oJj#S9q$_O*k>_9xG2DJV6z zrA}#~mh+GPrPsyj$xBklD*EEVeg@@m#XGD|#^f5>=eg4Geg4L(!kSU{EFO<~OuL;I ztfj_9okXC`w;n9mlvyuQGx&|b`;EUX)f$nInjPX_eaTBw)+QdR66dHT?w8L$AACCa zk+_`x-6;N>zF&SCT)lqv%fSjiKL3L8G-N?5#F_pncjz8&ztCkONBRh?p%r(hNAth} z#RV=hWHcGOkn28!UHy}O{yDzaAHV&rXjskkkBBlWV0TsOh^0`ej{jm2K{Eb9F`KhX zfi+3M=KQ6#jHMg7>mBFzln1Q3<$ZsS?=-K;4+dK(88wSUb$*5M5>4VFBeqZ@(QWpW zB^pR#*;__XO=!?bhBf2Hgy&?y2UXk*rbbbGl;c18X8YvlaJ%0d-#=#Qm5JT6V+nn; zPtuJ{NIufQn+jlGzrH_tAO@5@iWG{8YnP=alMt)F>H@~bm&%U~RUmVUBtv)Qf*M5; zXNheET&sOF)kL$pP*3%wwEuDF57U^<75Yi}5)!P&vS)vFc|nK0P2ExFO23wr ze7>hDgHO4-Hsr=+);Um0T&6=%4*%u;$@s`#99u*wSmvR-%PA~!59M5G?-kh=6kkz7 zg~u!dv5naXiV#f%R7yiuRMeU{thQ95cVlz(!^XW^_kYlBV*c;z!J_8FY1SR!x~!N} z-Y$UB7Q-9C`98Y8X0BZLoG zd8cLdY{2$m`l=S9g)+I+!HRT3_+*#vAD`)5uQ?||7ao&T7mGjA94R6Ba2k1?;=T@8 zZA51!U-g$GU}D+E4hvl2VNEdw?|q|P>{y0k<6qRFJR03rjb`pnB495Ktuo4uY@}<>#C^;&Tu)3ZyZu`lxvLR!Xu)TL1<`=3CSWQp zn03Lt{5Mce<7PAOBG;i`y(EM_;ZI|NR~0R=*E#hpCMe{8gCBTt!t)d!dc%o#JJ^3> z?iadI+l=TX?;h?cSwDu$nxG82gJjR)T1RKAr2b>QdZFxGpN+c*&+RNB@s67=k<$D_ zsV*OPdIHJ?{AsNJLXWlQaQ1Gz9BTA6%YfCIl==Ls-Y`#3U2Ev28%iuVqecZZZVW?e zMSY}&3VHqd)LruM?lKuymSSzZUrDwFw{>hMj2qsTH|JY({c_o^Isl@bb#vl@+O)O@ z1CgxsaGkg|PyD&~?K*Cu2lqGm@2&MayaY==_36&CdxqP5D{<-nR6y4_777yMb!e#O zUnB4)I79zc-Zm+BD>L50Xc{O8r)PjDtYHfaa`%`3pHxSmioZbvM$L8(Y0)qMu=C$A z6l7)dSI(VwvC;;zenwyHdd%{ zBGNzJJCw7|Xv;JD{mPjWj+KJj5n8EL!(|w>a_Zf2&kg}$*Vah4!>eflvB{6zVt`5B zm=nVs9<57kw2V{XFTD40|6$a9tyUn>QdJp1*N}Gl4mXc{8D{TbGrAdxoMOz-COl^98^5GePlVe9JV|*45HZ;B#jjR z<+wo<`Ce3u);XYqz@;J@ac=DO>+vCTJ52=@1$FVmIjf>2p*t0(9FvcJVXy7JY#DsC zZZ{cJ+z{WCQJxXTci1<0H#<-(Zl$MpxDc|lM}^XZH%wDp=A{xgBU#OnyIz1@s-58J z!CZA!I8l&b7ZBfj{TEzqvw)DDGr+g4YR*Y7g z|G7l?=8{eo+z@ecD1Csl%7-vPWRFYYzS=*M&x7k-+N#XtBXeF?u8^@CPral^PKnZV zX+pljB^x9^4M4E=M1dY1vuyEh_h_*_u&Q552T>Ic!fK}~&_E@Rc;^e>v(_WUyfX(% zhus>Ag~b_ARIf;D&s-@jq1%K(TVFT21;!>FDq&ktmK|V<&J3_YHK3C;79R->tSMo~ z6?F!t{dG~_82JLqZb|(5gVH&Xj-lH1y<`SxyUi6jxFPj!-yfB3T)EAa*x1*Gz8`-y zAzzD)XJJ#z_{iQU8fv?Ty!UFH>aQWGtbjfU*~PEk)QHI2_DuNW=Rf`Sx0(~?>@GKt zqZxq8h~7OR6`$ZP?-C;`pmAytx?-URuKK_+;+_r8H3O#y8W0Gq;PC2yE417HK0cWZ z?bUhEUJGdd2P`Hord-#SNgBZG&gJv>-F=%~Dl|!+WM)wbMnwR~x=}u1;V_p#vv{G& zZlA*o(?n@J*!1n=!M0bjL)Eo0vZfp=)uSfmIK_ekji?*T-gSv*xnPq$Y(=?{qh;C^ zQ?8v#zJ&~~*|_K1@?1%bY)x7ckSzd)*{=_`C8WH;YEOCay+aAFwjhy`kPoEfs^z~3 zJ@FH}J&f&4iUrR`nXC3>i{jB28O8k|0lS64IWCpZ+YKAqzDx#JH%-8VM9oY znsl|35@BGC`ILUH!K+2`|oQ^h8-y24WF znaszwz`Ga3xPE;?uwf#LvWv7!DoTP(`DK}3bk6^>{2E2j&!|*<^bYgRa|^S3Nllyb z9mam$H>gWqFjZ;cxl{hEwZ5xt^@slaj}CpS;$^-7^b*Us**_)CNU{WkQy`Kyg#GOL znzZtHyB&wRmFBRL_KaYnJvsW?r{&H%o0*rZ_NcN}J%{ZPiDsgpDD&?sT~S8ca3VRi|4urp;H8o5bBQ|L*$W z-uHLz)S|=&nwAs-CSPx_VuwfxeZ!C3);drebkl=h@21K&xB{#3l>DZp{xqOASPWUq z;%`IPK38&@E0n6W3cR+4IT>oDN@~5>ID1-}qvWE7k0K~mT;k!;QaaY|Kpn@i?%Cc)*)BKBYuu zAohgZ=|g0P;3HXQMK5k4_!`?|6)&nDDB~v3$u0J11)6Wm_3XBx-B@Qi>B!uWEb|;yhHdsgqn}BL*_+Lx1LU^Y&)quQR{an#J zE2rb;wT1lVy7~B~zLxwu&pjJN+jAB;_>;-=CPXF^Rrg_!6pR0Au%wy*NKMN`waR2r z!*Bj=adFowQ~c~d9uYOR!Ye;B*5&J$zg}GY@!xJ@!=pP|k%0?UW$ zCle5b4{dHw>EE;ibU76HUt{GrNcJJja93yy-|T2}?Ys56>t^f6=H;ntN^Tv6K50e^Ri%c=kZcmGksSmn#pP1N2nJaZ2xY?ar(89IlCm<`enwFfm^|Ou zR&%=mQ$)c#>Y#CGVj_|XA?0wuRk{eh`Flj$PoH`|N#x?&t8G287BYKy{oRMyBG*c} z{CZph&+v09qU>3jeFU9WWs~`MYVs0wz8Yjs!M$>=IX=S&-C(y>mb~ppdR-W0`HJsp zOJ&S~WF(Xj#SdE@KMQ>Po+G==Sl|Jd6DpJ%zK{j>6Xj)6#bwGPaXxBzU5NQ(T5-H$ z0jYXL9)K9r%HbvSxhLCRRmBY)5oGlM!*r`5FFz>2Uc!q$ok?}L$;JXQ9-2Ty&%bzg z!YExfd}~^sb_6|4ezs$UTEI=Gg$Zs~A=)?zC8Z!Or0Z1h)!uBsEz|vr4YKnV2XWr_hKRff4aasuWg%v=$YlttXOFA{6WA0ZiBU4?p z_s(HADA@CLy%!bPU1md@T`~&P3ED)fYG5OY<`;}=#RK~`phie#lBD_+0*Q^`TvPQf z?k)35St&yx)fLNva1$TBT-uxb#~v<&lYOOOUPKG;vBP6Z4d}%!YE#hosmyWuX zF1(6 zcd6`~|z9Ay;W;E&LA^wrDS=)FV1g@e5%4Dcuj+W4BGwo(LD2ayp#*J)rM z`q7dUBkiH*Zeu<2Ju9tAP$3OHvXuww5Gfdx3=3X&v`cK$89nk9fS8 z10`bfY;FBb?l4kvNyQ^cQ%^rBs0Rv!g@@(}#4E0o2+Hxa+8mb={1DGxmb;pR*{}-R z$Avv6)Q|yF>C4l)lqIl9y=0p}#jl6ka{D0V!Uh@%mE4YA7Kt&~{BHdYIrbY5)|E<5 zTEG>6*Nd+J;paA<8F!Y*XQ`>($2QnBcf$nnL`DhJ%2l{GDtdJ^meUaj2<`UC-T(|T zB>inBa7DmCgmsJqGr`(YDw5<^6malxqFomwH;IcnN;tN1FT%E^8?&hxo2*d)t>61g z--5nU-mSi$QVH$Dpsl|2zD%fu(-&-BeE?a8=ZQx^5^1U@=x&3mp{}x6GN3bfOvE0t zANUGS7Mr$L2BfELtv?+7W%bU+t<|md(Kq++-&tS1Cq}Lmk{Dw#rB>$04^?RCHHn7X zr>Ad*CUQQhKU#EB)1#a%=k&Tg%waWaNCXs9Sj+~5a&OUusI*G^Ja_3kL?9PM_e>qu zlThBvE3tVH)i%XmX5l+Il^d=rbP?wXq3A{Xl(bG8$xajf7N?0HTf%sD_lA;8$a*_# zniCbb!OD+HhP99WsyL_k{duLQUnwaqf5+RDi z{mGJUu;5VTT$8sO**4hbF{fuVr=%~k3n~$3M}AT6`uECImo&U1VKRAsiot|>#uH%_ zY&w*1;#l0VBvxxi2p+SA=Y216pMqT39Wq0n@XFHO-jPPvyoIb0s2aIy$#D84*I`g1 zw4U!j^V0;1*7v8+5w6cI-BS`-E)fkL=PDhXR2vz2vt}UFR!4#i!wMZtF4Vw6E%XT! z$uv&;B?*fGR;~Plxt&WYLWRQY7~Hl{ARlby8hF)q48B|v07J4_EG$-)`;lDeYX!85 z?SOvNzz((eI->+lff{OSz$lj@jZMZr-JL_Op_i|e+%Vn7pf-~-cef@oQ2%64 zuW;lgqq03VtGys!0}XzvDSsOLS(aEKC+W@A*E&uE)1a9QdB+sOv}wc_RKmg7ZhT4- zDchEixuiH}CLWku#$k01z4+ zF$LQM6T9r+E2%=nOX@dx#B2y5?NyyHngAiO?7PfemueZw>Qw@NoR#DT*ik)(L34nP zurN?o5qeP_(pJk10CtF6vhZ7g{fGBCuA zt}szhpf9O5rnJ_7C)Qcp$NFI3B9UWji} z9_OE_B)QnNPi501ru&kphbn8%$+mY=9*jtcxDFsh)7R?wNs8Mc(#n!PXH1mtRIM8L z;u1xyK)`8i3tR;86QlFZYhlGlDrho`!(ptOwb_D^oImR(%=Wcwq9eq4S_@?ZIJy#8 zT^gf+nI8SCrRQC}{UZ%i@0I1Yg&Z(l;nK?4nbC9a3{3_^^^S=!i4#dI#ScY8QaDdBAK~FJT~0 zZT0;Kp8*ubZ2SUhtDd4eqm$--mr}G%&#=$S3pz(ThZLO6{RHdHD6KzivK)e}y@0v$ z3B^Y}y^^vTKW)Ge?=${t7%HF@d&@${H`kUI(r9C4}F0>S=?mmA?D zy$7U}f+r~2(tzw<`Ao{-awa!A??<_@Wo32a@As5zMO*OHal%?cIu8#|CcGP5l6y?T z7{!MClk}1e8NzJFu<@;5^CPrT6ndWp?Vy>#8WrGY3P}Q+lo>P3RK=0Nq%Y5NhS>8M zAlwR0YPQRtl)SFO<0`q~h*oj|uXWCBW2kR35NyDlDr8!{=GbvwESbnq9d1c|A$cNw z5|hEy9Dt?$qsuQ&C8=n6VE+6BNECUv+dG= zCd*>r^vebUV-=lyC8c=nB`y(27~#DbemWUmANWIqfqw9=mBN;`@`k^V7k#sL|%e{d?9z*-&<<$-uJZ*~2Yyw3SyMBYjY)v3A-TsKoBvQwjG+D z8?UJHc^5@e{!2ZGma259eBkNgpp@atFWqqqP&yjkds+6n+9twHXMm!~1eUli!_Mm= z85yR?J<_wp1pa_p5Z1>FrEHZKx#B^%`&;+d?%%O%XhU5AT)DP<6~<{=>O(IXz54C? zy)AFqYVmOWU%%Jg<-6-!-`&6E4Y-onX><2J&dk+Yw;p`5^U^Z9hsDuYU ziNoMUiRqP(Kjyb~6$Jo|!Fe(P)7cdLV(^9H-&|~k3h?;rB@VtSGVzM*@^XwTmS;C- zg8|F&V0DiNY{arW)+;sJZQNUf=qZ&<*v1~&nHZ_-y}b?p!0l0dE{0NH81nO!7h?DS z)8g;TiSNa#@bwQ57}^M5>1aXpf12MC3f2Q1Dt#^g#OdT>-JBXrTad~s@g5PNkE@eP z|IE;ZKjzK5;=4M)V=vVi<4$pavtwckkh+y)_q+X$8dWv_l*~A{~jxBSM z1qcp=FK}2)!$dH!pv0b>?2~iJ4KpGp5y|D8aY}Ir_2_0^ZQ`WhkKHHL-+=h$5S=t2 zvNPOwh&!Zp$K1FmJk_*kL=l_nE9|^LeK}`ys-*{s_%j9@u5afm*gI;ilh45wwZ{uj z4#v+$`@4@_Z;JhuT)8IX<3|Lk_~!KlsBo2?ovf73Yk4^Ox^>~LLZG}^k#5b1hm%$n z^uhswQu!DYCe3%#Ipg!f8HxIUTO7)RCWywM_%c@^QN9u1h&T{5ch~RgS&%y$cQ?2^ ztq)fJI{o3T^>4oa){mO|_qGs%b{$uwBU!adM%nVmR{F%aOy{YygM^X*atDGW48+xN zrZk(_C8NV^;DzeUe0RAef48nZE7WOs#9)4#G1Nuq$7^)OXq2JwiLu`;jOIlZEHXeq zg{#SW_2&=;_^uU!$S)L%Q)V$jQ25a!vOJ9^9~WEI5uM8)-&77OOn~lTt+nNk6+`3^OOrh#t>ZsQsSHSHPz2%@ zQA@D>4Cg6vHYXJu&v18kRKAJ|^og}iWZ5q7_8@b3#lla@5>EtwXgD}y0P5@*Zw?!e zNzC*oU|-R^f_>k1Bt}Xl0%=e*p-o~4I-WRbv}#lBu4_{w?1_J%v>U0NWV*HiD~4dM z=!BymXO6||sLS)igTe2Xf1jt*ZEIYGtV=kx8aL*5uZ{bnd=9`+{FzAzO`~J3TWr>8@VMA{VzR~Z;2=o2 zEV+gNkheftw2{rKl3%t|9mo-o(t52;MV~@YA%F?C%ND}=6M0)GncbNJf;h|>g*_1b z4nvVjE`7kXoy#VW+(BXXB4)9e&0o=)=x_oqFB9y+?CwO3btr6Tmh`_#?vb~9%(ZZn zRM?_AAFXy3qJ{izs839(l`q%hO3C(9iIq`|Ob@o{Eh?yoxaBZFta=!I!G&%$p!=ek zLefHV}4xYXv zNjF>9L)Kl~o7UvW&)ZW*UFVZ!ACXj~>6F>Pl7#7c&1|Wc1REN9)S}y6qN>O9J!z87 znfd|6Vah_WH8M4cWdmD4zEv~jBe6!VP^*tufn>D;j*w9&q6{seiv3G%ZCec3i#4}s!qO{`qeu;$J9xHU zGSPOi8IH$?AHWz>=qS$u3|Ri!=v*@8M9a0*a12XpweAFvw=QNQ$=w7$vNYbOis{eOE-K>{7-fQ z@9rx*ru9u@-e`fvBCt~M;#P%b^6X%85^%Ce6Q{p}lU9WHiDx=Y4ZTT1Bv7aFJK1=~ zb?QAk@;_cEZ!}rIh?tlohd{iP9-sYB+Jydr)(H`UQ_-*1)KZjPuh5zr`i)4YiLOlj zl1YTejvERd=5)CRhZs5#7T86W5$J-;8Aggpgw|ZF7a5NHZV%~|Z!=Pqg*pkdS@A3UA1G`nn@c>~^?ZBj zi$8q%hcA(Z&7)?G%ck&;rsJkJ_1g+xe02W6fBdK4pEvLk2~Xpb7u~Vvay7=i?DEDd z^wD|Ep$>6Q)1z|Xej;05H-f>+-S6*gZES9A*#+RXkGT1Ycbe^>b@jCvdz0s9r>Y!R zq6dsuKJ)uITx%Y`C|hdpqaNxeAqqr8pn9X0vqX&Ur?a;C)!yLWDRu0JiKr4AcYg;t zY}>y1-TjAK8}~N0#NzEpiWtY_xH{drcJ+t^Hml25XwjUb{c`+(_GP~{Qp&3b%J)4T zI0e9coFppHD$kb{2t_-T)rk)|Y{;u0cTeaeTu!J-qi`}qCzdhhC8#vlLk1AgIj-FY zZqS73r}Hbng#)JHaJgp7pTculfB(`8;K*I zJ5h*6>`3fc<6fOXZD`Q)L0$|;RL$EiEoaU2PAkxe7hJ)Yc}{-$hd-QqoM~L?PfG{e z|M|wm_XVlc>w_OGz1!AuW9!8`b|L)ue0=hboycmUN@b`cA7BGarY;>TSK{w7>XIxx z9meMl-)KR9{HIy8T3A$Qu;lP_hkYkvY+-kWP8xLa6jF{m6!5# zZcE|{FAld)Uc6iDcSOhw)lIn&I0U{LNj(>Et_YI+0N-D5q5d@K(z~3*r`xZ`N8`f} zDpig_-N|7=#wkrKPhKLJqTgbWH7B5BaRv z!v#7{X=I+%5i!RqA3^s3$y88*eDmzCKG;x5b^L^6S^p%U@T3Hb9>pkn=WhwOQ$}K& z9N04cmADtIQlFjNN*{beX4XF8Tj)Mxw&pbU;I0Cno>tq*vs;+FIh3D;I?a*p%+29r z)t@4xf{PNo=xxQP^05nYXo<5#a#)Pb8F-*uiRSyaZJj%+MIM^i7z4&Q8iRK(nKqo| z8Q^svcN2!cW8NO=;+ay9W^D@5(C)~(V$nfG zPZO@$B}S&dg$Z^kT4c0ABQ8p~=(p-g4PQIb>$2p)VFucbr0$hxvSj-7kGkHHH zGgU1#J2{wMN4zZ=Hw_|(@|>8Aav)ps(_X0xdri+m2^9ID_$^<6mw*Y(X9!!lRg%6p z{quo)L?_qtZo_p6CqxbWQnEaiJf(_&DY}#fO!d$4i{+2~kw(H_o}}A=qj+%VO93~s z_fa!g{4gX%D_m@$fXGx=p8pBA6i9RknPT5I;>w@q@ekFoiJ+NKaE?kG^oWFDIdG@) z()&fqg@6bonMk^T4E@uYf0u?GHJ=NKEdQwI=o(FIVB;m(>Gd^ zVz+r!fKy-bcM~=VsWqGy8>|i& z8`kSpO?Y7Nl*DYNH18%qB|P&MjHd!N(dU0vDnx9I<<~|QPHdHKX~2sWUa8 zu%Qdx^`oYmt$!=4S^7u+!3@~JZKSRw`@G3``%}j5 zC~U~q+<)xbkaqhDl#$Omidp+1gJMnw4;B0GU;D`N0$NbyJ+c;AShIR^8`I`&F`TYB zh)H-MNqKw{ouSupUv3&2LEU>5KSW$?y8I&Z*=P&z1OEhsmW#$6Mqkipor6ojU7^ zjEV_#F_aWm)MHih)Y(Z3&u$L9kcJ|RQK*Y1gZ6!4Y4sD+Eq z3^j?3m|~8r(B~)zWpa1JJa?@0W6jbzQ!Li!QjVct!B9of@fo*XyvUzlR+tv1-n&J7 zTw~<#l`4l2;p6RU>T`&k`n< zFl991%x1rqOA@9++DGG8nTJ`WmO&>Q_qf-5=g!8xZ*|ymVP4lQZCbG5NVRGtF^C&D zrgLqr-+ge0qJ0lkX-4H1Hn;wEXPxSR>s$5_N0 zDQwCyY)#Yxtglylnsb|*JzI+jBUfd2P6-R?S)BS=B~v*m%PnFU{n@>EfClmE^BI;%Khys=w9CMh|BMdMSJ0b?-m zQ~dV4-yBcqxP+ci6jYN?-sVjz=AOvLuuLK{7nOMmum;B15JBoj-d+{+VhlwSqMk^ppyiQctx~ z=8)xslZBP}<%@d9gz_TM*R0NfC98s6-o^d+H)5T>OjUdB-4hIZlUbqhPeM~%R8fM8 zn_Vyj0G_^+T%8y|H z98pvod<4=!Iy)2!azjYkOXLf;X1x4TAW>5IPWrAq1QKd=6k-9^2UB^#H<*i-Po zWZv5q_u(qZP|Uo{eFgb+^KZLa$3tM$iE4&{d_-0v4NsgTf%X}Y>lBO%OLB4zFTdh}Ni?y^WO;n@Y(;Qk=8hh?BO|-HX8T3CI@{2KJYl|8RWJR`C#@%#Fg_NnP>;pH_?{tbLK3R%10-Vj@Zb_w-f`~hn(r;D$bKbJXztZTe7IJ4BMaJj#f{}*US)^h6(eq5}@&x#YU4jWA-J5f)~ZoWBuIzD={CL&r>nAm)dcOE;_)==DWf zet%>|J3%Ju`a5*^ZtsBi9^RpYUS*PnHM@%s*-+LLn(u5MKH1&&X47999nSc8WHn)( zRA)6=+n(&0u`<6|Lw57qZHTY-=C`?fW|xoVH`+9dWo8>r*J%=lruew9k^kAVaBIZ` zq)yCe^8jCX&jh)fQ)6z8U+^%@e_9vR&lHp{UU&x!k!X_BKA;ecSqZA?VPs|epwtW+n9P6x@iv!kOu-KpQkPh#&%@dP&oKZ>4o zGmrAnSzf(*wXCvl{-}__vw#eeMb`uN0N*TImrOQBfl(v-oUgqX!c2H&l(-dcaidG+T%|9QB6 ze{=Y26`)Ud|7WT{tSuI9dXO;incYItt=TA`o$7*}X*)V|%(r=ndZ1H{9p|DW=K!>2 z{o_YgGO+k33Xts&T`4b(31bze(V+6vu+2JsrNW`aEZD5lAO@?Ue8CnT1D?@CEMnlG zVh zIhmqvSzSXjNL3ENz*(`M$7fIAh9uAQ23Sj14+<`cwj^fwRZHea12hHsTsYXUPW+k& z|DDB}{S9Pkes=x2TrzhfNske!K26lia1iM&Wys%JQ5k{j*Mon4w9$ULoLZ44(m%iC z_NUSv>&(9x5Dl2_56{Ui45Cy^FMWt(#~*pj&e#MVFfW9qAh}_;3xXj2#J(vCT(py= zYH=Psw~cn!e7X2ZqCa~M^~B?8{6(Qx6;rG~S_}}T@F2L2KujB)MI(z@h;aD5R}4v? zg~2qqL^VQ^wsMXJs~Ww+to~e(zAer3;oj5GG}okfCWP(I1}eLand~%+qDp@&41y4>=vQzXqb}#;JKkCn;&{y?PLsu<6`C99#f3y1X!tTGiN#eS^#>)KOQyOc z60&B9%M?XwB18!|A;B?M>ceES!1h4u#P~!9uyu@&qf_Y{5~`~QtFkpRxdM(~tqdkI zL3m*q%#m>o%Xg99u=;H-)S!*Q>PD0GHi+TvwRVTmiGP~BvdnUXL~(ZMYBH7E zk>Bxhp%YA(=zbv9V72e$wUR1l5}#^fM(-mc!;mf2=HT8E8BS_K-g4R5ie{*1QXg@r2WilkT*h zfER;oAWsgnuevk(Nu8y@dDjm3roa+t3o$RU-&-}%>FeeSK8Izzt?2E3y!sQ)Q|WSx zTcfr6ckfae@5+GUc=y-xPo#ba5xq11c#RmezR7>Tl)owjp}EAl)2lDZJRbeigCc1r0P{Lx8D85PpMziAt?WF z^%W|t`{$L}reYv^5l#OnP$`{fO5_mCbh?dZy+UCj$DH(lSr+alPC_g@-A9d@Ml$TBcS-t zbiWv)>Sue>cQ(5dn&Vj7c+yln*RlEFj>47=6KO)EhyCc9rwR54qn|QQ$g>={VqDAz zhaU~4@vWC-^buk>Rth~9H+*i|3}UngzS)vore36u0KoOZ)k^2G^S5P#CRQguYLICw zG)&D-Gr_@@=*z+=6+u;$>_)CAuz#e63?|11qukJv$Q)KwjDo?GEzB-)9J1qis+dRW z#K)W_sN97n;9@dPxw1|+WmntM$6EF6SJ|k9DosRd{MNfLw9xLRC+EK9$qXMo!Uk?y zXnt=YOr0qP5k0O9uJvP9gVKyV%F?m~5*S;`{nhRij;99a^+rii*5r8kj!vIq`%P9p z^;~2Q@)q}-g;?y|;mD4D{xfY|hh)*v5$2hO$SOH|AiD-k82P2D`2YWZ#lXxz^3gi^OKX&Mi$ZB4>J64@ zng%lLL;t8ua>WB=^LqE)X2ACJZc3Tiehz;jc!Im)hipxI=gf-3^2n|wrjRJ$kFR@* zfon{{LG)@l0SjxY!J=eaYN6Fi9OD);zu1~CypZkzWHr&}!fA*yKw%_n4#58adU3{E z3mFZ3S5o~n9(Zsve!0&jX-NJV5#47{f?ZFtbOTFS+m|Y&nhlojAc<}rZ}Lu?g>#L@ z^N-NM+k{?1Rz80ja8e)}**9HK16T6*wtS1ymYaCU}L)Qojx^{ghoiiS2+`GKQRkNecoA6D=$>b zmTPtVY-WIG>-1! z)%d8&xFyCsGakP9alLdZL3*Od*rvi9w&nE9)S}#VhY!pbRXR=@Y&zRv0gh8cBB|7;R@Pr##_2! zpNBSnk2$3hhnBSIK1X#?FR@BzCY--VL|F5=1|`mpkCks{%N9>rie6l7v~*!G<4I;b zg||=pIfGtmAD_rfV z^0tjmLgk$Syl8qq*tdaKT;5Q!_>lW?cCBk*;f=OLx`1m5@+d(0xz!azZM#e2yoGS1 zJs0@ZKxNQbLf;g4(@88T(?TA;W?$gr`j&*=H`PDL)_!y~+xg1-T%0tjxix$1jhV$( zAO_NkeSPRMMt~w94@0?1Z$R-MX#t;blnW1TYO4Q~ybi_3s@pnxG(dHJ)=O{Ts9Y#9 zg2&pc&a=%5!*o(Q2t@cYh^$X$oRyPlh4Db62YC_YjqanMZCWpL;`^SB^O2ej zZA-+1*`dRUO$bFi8Ng4mq=pK%j3&;N@khgyYFIO-{=RwmqFyGc0e|?zAN=i{pd_`@ zKVp?PrT46fjj$8yYWm*7|9c_qsp(uZtxIfu*#$vz9g4Q3BFiyI1aubCL}CR+|FTru zU*GCq>liZsR}#gnlU$-TIZc%Q!I;eRDKuo4aptnu1jDm0A#ZZnT1n zux533&tj$Iiczvr-!UfjLoAdUeZxX%h9CMMCKl@p5Q_ox!CRDpwbfWL3Xl4E3!}||=WNwp(=%_3` zZA;^L6gDJsg=MYpmrH}C8}q11AcPFgJ}!iteL7cX(ik04)sLAO!l}P;8;!qO=DGxO zkt-}U(pG;t88(~U4^qPakLYLNw&Wq{TjVwNyIJIcXxccQ@%WL>=I`E8^GgaGQ6{_k zLipD1TotLO_X$sjWM&>rWEk%elo{-vS=RZkyl&%Tc_WZkXZG45#Zct;ke5-(Wx8Q2 z<(M4lUDRM@iZces*DPm6xlHvgZi>n#lg(?lLM6j_yc695(8v5f|A6~@n75&ORz~Qw z67BG|OvjWw9k-XIe~@Tp5=D!<=z=bASa+NlMiK28RriR#sG<17>ce|f324jB;TB@h z9eQCr*c+_8K(!~!7dIj2@1?h9ZH2V7->Y|7`>n{*!)2vh2Swmll2EfO4!^!(>B$*` zleGK?6Cm!az;uliuy9!-9vt2Lg57$IziglIfHAVvRqf7pb<8PkQrDc7A$vjvA3Sk- zuaPUs2X%sNbEnuxPdXp11sq+c<1tnN`NS^$i_wL%EujoW!sM`nI&$`p>JQt2mJ44C1*EQ6G z1I1wIV-#D7v_Q}KD6f*41J|PI#+%Sq>3z{^;s0_w8nF{CG*-x(t|+nX&H?!Opdo@P z2!~4*3hDZ5-Kh~57^*R*;c#*}LT&1RVQB-XarJI!q$WMkWN*lTsrXdvN140nHvE3; z_R=3q7GW+s=j&|QdGn=bx}pr5vzbrtWs@CD0hENbthD987<^0YfD7iFs-4Y__WijL zVajAibP11X`_Qz7S$?#zNHtL19ni;4wJ=&>h0nSOXj<26{A$o$*INgZ)raaGEMB&t z_<`G8?kuBL(J#3>J9eZ%)zTS0+vyTbOI}nhy9@y=wP2`Pwnc-+Y}~|Evlc@6oB`{P zrWRG>PQ%c?`e>?oZj74hpN6j`j6O?rwPlQ&cDAsxo`d3|tLf)!hyX5xG~^P}c3PiV zcmG}PYdi$5A`3EHEN(-IguQ3H9geWG>Mv4$RGP!8z#%rgZ!!RdY$l3-sg*K>$PYQ= zTq&bXsX=g?zkv9?6$lAeEpm4dwU`n%22EKr@&W=^td^gpRbQWC#9Dg(_|sq^hMCKF z%=*C3DNk@Ly?peU?9fA`Xwh+<2-mDokzOY-e$&-T?KIuq7awF(nJA0LV;dUS}XC zvC^cmIY~3wyIR^Cf!PkGG1V3JL+p5-~PEiq$7KRTrO zVp!#wJDk7$Z6i1u8nU&EfR5y4>9~0&B%1T;=c0Z2V{YDPOQ*Q*-Cw`H^|uG>KXtoF z-s~t(zqiNe!Nb*W@2(P_@A=mzGj7TPRqw?2R`0I=G)>6$kWb)~7nL~6@8*EExxTiw zasS>7*bKFH^T$%-eekl{C zGW>Jrw!&o>XXNY|XOFUR@7DTX=fFC<=lZ={@73@A*6O$K)p6~dj#Y9~y-oaH8I$!l z??HPT_x`f}aBKb6#fWeJh*$~g-==$M{?Uo>zhi?Qtnwi3>Ya=24@v@c?+)H;Uw$2n zi|y`hox|bL2nOdydaooFHT%KQ`}K#Td(aBJ7se`z@c(k8&J?@%&N~(UJE;7dJNMWA zWwiS6+l%dpSyhyvdape>Z@sfIHJ?RhpDh3HOmeSMeOArUhnyJxvik5Hh~Y2WC;yKa zW@xSds}+>Ewcbw(@1gLlZ?3IA=+k%R5ajpwepRp0=l#%=wTso%sP?MhY(=Yk&ptaE z-&Z#MPtwrMdb8_^{gztb`v0vGP+~AACB|y~>%y<@R>8=&Yb|;#64>>BAF&x4br%hdub0JFA<*zneL87|wpN`uBMB1}_S^`E-D07} zwYUnB7b;k|yIcYJ(U2Rp1qzMYhD4u)JE4Y!p1R3grnplTdc?D7mi=KAHD$WEe9}R+ zjs4{8DNj}eB#m#SyH>T$UGOeVTYcAT8$I=b{#C#Jf+xp5uXb#7@BZk{>fLW{t^V50 zt0vOCQBkcVYyI6e=7S@zgQm@`hZ}3eQm9S8`punnkvORbac8LO^X6OghbE@0m|MnK z3c)l{G3Svc{4(XkbVso}8NN?thINC1afB^830^iP+5O6>KeGWvjf zf~{|24BTN}uD}Fh&0g2*FDh>$SBgAP+pN43Noi8x2x>qJdy76rhcqvn5nhd)+lMIC zz5L=5^)VJ~jbzhO6T|~^B3&x*l;~Z+Wx{J$fxBEizqU{o$Art3qUwuPiX8F|x8prP zEj0w<(hV-c>~0)=qcHm7r;}?4DP%63E<8cLB$Q4vM+ni4)XmnS8ErV`HJ@o&_ zpu}9K`0Rf=gUXfoYZ;VmzlQUSvSP@J=2ajBTy!{@52tRZK-!&FqV+Dnr-o!br0ePKNgytxDZItfN z)O%aN%I&9J4`D`}+{~*MS(28Id=G`Q4Cdu+XqeQwbmP;BDUFr+ne^Cr;bIt?W??5AY=ZjeANBTBLY-A~)nZ#Yzs zb2mD9fH4hUs?-H1IdgY_woj$Exw@#B#`dneV-{8D3=Q*gVu2;j>Dcj7B(?NlrE#`s z%Boyz7==z$y_;oUp}VA0X@9aozL9x}gBE4*S*wya(IQgKnE#ptoETOqI6nETEeXNC zbmRDJ@_cdT$eN+zs+>?i6E6%gKGsV=^_Tj+gPk@Vr$lhlXga^ofe_4hVHFM7-HPH_ zgNxfyI_=Donrllrr74k*dq(VNWvayoj;E3}9Ht7RyTR3re!c-lCpW>GPUjh6ba6B6 zeGD-=yD8Sw`CMa+&hKQ7P46mqCrirsjDt2hb(Frqyo8)gTz+2MJ}c?FEh{Z+EQY(u zs)CnkVbZ8CL31LptmM$fu;`%4(~*sfo_A^EY&xajVj#*7+Pvo^x?5u>QL*g z0VjfUG_9b$b9AkCs|uyPW_Tzcm5$Z;_(oTRr;XI_;eO5bM%BPb_**St5uQR zcJSeCR@!4DnlhB?+CAYf%Zfyu@9NmK`4^)s-I$@+w+x>5VZa1ameu*p=Ne*BCSws+ zWUiwcmX>Cu@{AS7syzy#8!K|5b01PqY*UzbtlJMlMrVlka)i%V&jt7?db$(4F|K>r z$96atGQ&~r--013(>J<@yT95LcBSn?53AnvuIlvaH8KOtoTa|%P#u$oCY=@`x% z?YLaP*YH=XORvMfof%WZRr=20wcxSREV)NSQqJFtGf&Gn{6@a3aAx?u5gZU@Cau5L zEDRr&y$?kI#7y4PDQ%lo?UD`AfG|F8K~Obp^J(eV$-V-msZe49~ z-`&^gs5Jl0J4+e6kYpkQv!Evg*by~@^MwtAIS~{~Hd7O*b91oEt`F8MHfg4Ir|El% zrN+5?F-Zi39YN#}a-GouEWByZy)86tZ&MiXT18x%Q)xg{R-A{Ww?~~uqcx>HjYe28 zde6_OmB7QK{l-A01?uUG9DeHL>Ij-%s{q;3Ci1e9jvP$2yu~zSot>%5=f;3DWE%4} zleKzWM5NV9M2&?UQt`#cHP;q)6~n~Ez|g-`2*fu>QDl{}I2s=Y+?8s%V~j^cYN@2?=KY2AZe$FWB0VPU-8LhW#frp z^smyoKAof&I=$)D{$p47^B#-9v@)eI|F;iXQ#tDyrw|Uy+cFukW2~oHG6_ob=LOA-e1y z!mzPwd@0F$T@s|~_4_#n7PF^mb>vW;;-dPxt)Qh~ifkoA6aOhr(?W*kjF{;(DE%Ds zez)B>s8kGN1m7#3(&K`X(|Ho52Iz>vUWuD5Q;@|kv-}J$M}NcgOc| zqhF$IsVRX5scs#{Yn)p;Pd-s7sB8Mn%^vQ5G~I${g^OKJ5oU@^=*EnkhMHA{3`nfL zBda&U`+{u#4vhPrEaxCqVrM>!Ra6=WO2cI{ji2xdMa!vu46>YIk63=5_NeG5ljr+S zQFwB=hEkFpXS?{M5LPNelAk(UfSJ`h+<#qm7TqYOB}#U-08?x6;o>kRvQp@_7D(=J zLXMdJwLOg0B=6`ebpGmPT*nn(C7k@q{QS27d)uQp1+QhCwsPXe$DNIPmLFK1gYqE% zspaiRqoitNhvmC5j~_6DZ#-*U@K?k-|BPHv)?@$4^llNFxiHLU7{6Pg{}zN=hqvC1 z?GL*!3nhsZOVGu-EnV}_voKr}Z=_RXq@q`xYY)oAWxG2fn{%@y&D`)T&hU~;s7d`!KOM!$IfeSR`NI@6Qz@sD>rD6&01!q?`D z8JN_nDiD=o6q%cuMT_M1Aewg1U;P{ic*P*?(LKEbD&Lffbp-TZS7RDFJA|0S;@7H1 z9jw})7aFxyo2iVRhrB0!Hs?$Wwb8n*!xud&{X51#5RK!Isu}#=!Ghla;Pdt}GEc(h zsYqSaWwN$2%-0@((zWW#grR_)Lau6D(Yw2PTAR?-2prP7Vn=htTlW@}Q@ss3@@Pzy zIf@{gY2O&YH_w+}T6uJ|IC%TVUoL;W!c(phNJC54!*3M$UK}dy7dZTE@H?qU)yi7- z%B}U=tKZ+*8u5H);$dU!D56&xI%R+|U~Mu{tyywVc3Yu|5f-M^bX)m5Uh&I)%) z-}uHVbuovtHCGJ!ZRbrU*Q3vSgw$2kro2mPqG9h&*_~n0tP@iu^vZ*2SqT2%;K}w5 zk9cBc*b6|$Wp)C)wMP( z88l5zDZjmcn*?%zwztDU!|RiE@p zFKGx@9>&r->B1#&8+BFt8NwGj?F6N5;0|>vxmG#vJa5%We2UqJW{&>Jfojv8$h%d2 zI;vAO?ia7-b^W@R92%|OTl?<*!}VLdx~&2k+yyGSh838+Xvby^;sk+_ijKnBoGzj0 z^sGu9a%I};idI4ls)hbF62D?Kn=7*VG?&dVGo7!Vs2aT*uWkWJMWdE1-`H$!(K%!i z%6fXm<(*7Xp|Za6!$&Ql9#@{~p%{Z6<0tWYZc*0jN|xayN$(_ofR>gT53 zA>bBMaC;EXYs%NJ%LENXx|I9Jsy$r%$R6ugKp+ll2%x7pxF6)*3cXb~( z#BaZaxM}UGCS3uO2Qoq$PoUj`OWncfe(vk_hx@N7$eJF&!L7Zg+sfc>hGGcQ%^MNZ zJT7%3%Q2Ri$X=D1;^$8s1r;+tz)R|8U2YVw z@ZnHGD+>O#p{Ll_b&o)i>r?kl`kPv8S-te<_NST4vCuY8cd7=|iO?O6HlNjrR>DU9~d$H4g5v}dVZoej2kIP;J{oLKCS%+tr&y_eYj*JJ`94)ywU%vO zI<}Q4CE9XnopAg^7qYh2?Njoy?YZnE0tGqe%<8;~wM{`3@QU5b+aO@WuCm1%E!xo@M%hy7kM1Y#}1IOpXUZd0jrf}i@y*%Q5MK%0~C*|X<^$qp34Lv*U5gAYha zkh&h@AWn{O`u=r zajoF#_~2mtN+g~#$3)i@>x&_Fw@rqAaUhnK3^O)ADDHi4N12mBoav@ui22I4+;cOyEx6YlVIOewb z=!BV&urBl@o7C*p^D*K6mXylzqzf^oD_5x{pG-eGc@Z~tj(Kx-W&e#MXk&kuOw2Pq zC05>t)lun^)uJcX2zgZDAL@_s%QRE2?*ChSTzPo^?)+>F=DgpZpg%X&XcqqKiiHRr zq#yDS$*40^;<(jNImiAX#R*BNM)Oiq#guMgwwN*%_n8#l<$w=; zAZ4*H9W^#r<3Mfp%+H9%OqED0&ZSO-N7U-JJmw3D8~c+}N*HDqz_xtw3CeNf$@ zf7Rx9OJ@lU30KRuaDW`19-6=#xsMKFPqXmml)Oflxn+IrPpB({8{}c=m!+kyny}#J z?^lEW<9*m+HrQ8ayE+);%Ou!@df$a)FS#Il$;GM(58a*}_LpxJA$}5Lz<~fty*KpA zHOiIoV0-Vd0f?TMZ7iQU26lPync2-U^5jq$=sBTKe6w@)lW{f)2tPkPJ)T@&S$T%K zd-i0R;MU5M@e@SC&iK_z<~%GPKR;f1wf|y&<*v-(rMni+ZnCxRRr#G) zcXspwmBlcv4v#@+a^>Bi>k&n5=<2`n_a@GppXle@dfG$dyE(*c-;buGs;z78l3K`~ zvz)m=*Xw8+R(lh(G@|&IkE8zZ3Jmhu!1Q8LJ@L>@?3$$X-84K!{G5f>aB=7I;Pb23 zt}gMPKMekvd>hWs@922AeH2Y@qon9W<+)ls1moj3C;QKypPD&)u)o7=gmMFNejS?6 zJ5P*yMo5GY(IBvpcy?!#N1u{v z3B!NBeC_k)tL+Si2kUF2rX`K8Eni#yJcHdnQly#0BTGIYE#vRjc+u1@{cOh6H1)sx zTGqKMoT0@gn~2VUyjDFz`nmVXGdlRKsnV!4GS;S;z8%p)N;6b@>cIcZdg^6 z=E`fUX?r1annLGidxE&N5V8*A0m1ZdlmaYtTt9lbe=s&>7ArW@?Dyv0$xFns>o5gT_Fk-Bn(F`uuBZ~+`7jcJ_}Gc)Gh~PU zebz``7Y4?x{ek=k(1xTVj)sNtvE(2^)ne1+>x^IFm_#<6?C+Xmm+%Gwm}d0s5U--U zn!%oGm_FZVnPHaiSA4(`0I$46L?;(Kk_pzoM>on(@V8JwlqMIk9l!4LL9G;Mwgd|E2oFYE7qcD*7H_;-?yGs zMP3K-twZ!#BNAJftvL?HdOyy*=rIVHP;_+faETE}wBH?^@v8L;JAwC0U?H~&9DfGZ zc(MNA&1Y!AY&t@1SG%qt%bW3;oOVz5pJAcsuM-~)DWkv}?(^E^SCMTEwM>#3NYm}< zz0o0hjG^!9?|=XM3=;J0)_vm@c!bk?&tHBOV#OxHj7v?liyc!f${sGes)yq6%-%Dm zzo`(_YH{5vqwny^?sm_-S(^zaRZ1>zRY3pa!R{OOn!^rWc*4L>QBF*I37BRr*{2y5 z@NDJH@zexFsy$k>ByVJtX^Rxxg*>vJmaQ|u+;2L6K8%@XC&9IH$2_nD|zH)MMEFP;AlTS zVrTv6wsdKe3_jvwpRkfLPKAOwOjs?T1GjBz(!w$NY$ouTM zJOI~NZ3g>)obB&m(j4tBff|wu;y7vT6ZCn7AhQLq5gJ{BfN}PoKHcBhM?umVb+G-P zZzNl`2MziMi+rJQ>=SIj%g!|AmPoUm38HPNtzdEZbUd~{O>E+p8X=q!M|d=6Ze~H! z3Z0h^VLlxo6rq^6#}&$kp%o672kyI6%JY#fC`2$cW0t5bTyVE!J8s;l?jvW$gc@hd z&z23n&#{S#4vkOHJbUn#QkIw$11X7uv<=#OB&O_~t(bdJ7U7d5FGh$a$(YXXeYx67FR^TZ@uDhgyxTX^QaR1sLk9-63 zv5UC4l}_u=3UK;GVt5RUa;xc-BhBGxqF2q|n4gchc6ZWW&e_(XYx6@(Tlf1yY!Z)K zyB)1#)LLk^-7%?KNctuBw2KEYw}s0V&X16XRyKVJYI)F7X&XC+FaCz^bGZEmRcB8xFzLI0{r>*e z`sNhUhi(mxo*wXeylrpOcn*MT&+&o~<~l)T@e{ERz*@x%Jebf*q)bB-MwbCH+}OOo z^v6Gb`A4F_Wx1jP8x)RY9vz>KkYOcxOjy;Iv+hC{?5F!Gq0*OJA7%fK>ts z^=wX#c(DKEWE;(WX=yMyBi{^Bd3Ss?=4*X~J|m$aHM7x7$LsvgD)1q^F+1hB>zPz16Rul-aci*sOo@s(T~D6u11>~mSHAaN z@9mtKLGVhcgDA_=w2nE!p{`@Fgiz=3#AslHfW;4v6#G-$CBY&+8y<*!vM|)lCN@8e z>j%aw@tqw6eCnTOA| zPj=0Q4ZRq7HrdltL;UT1r9zj)52A4UFZXxPnwo(r=2?28rRN9;FpO_zUU3U2Wj>$& znGIdUdT#N}_sHIWKOXzp#%)Nm6Vp?iIE~TEB#e*SoUZK5+$ zx?5s|w>~cmt^!oy%lUDJv*f3#D2no zzq0r2Z|>~qW1_KwDtXR_nXwb7C3V-TPqlM1Q9PP*boAg{K8vLr2H72Rzid@*_eE8G z;B|%$Vy4G!5OWS-VS3I4gcXNz+)P^fTzHnW+|tsWH{FAlLw>QDc6yL^o_~0eiF>A` z--YK&>u}ywVK-JYHN7r8Q5Y`M^N0X-Q8?v%HOB7^5W~n81!gcV&Ai!9wQqX+Z-Mjb*5@Y41*e!IgP~v5<#Nu^%khpGt7#CV za=MNy5(gJ-D$_wyM3(jAh4jUEq4PW|=zE>{k~hHV zUojSvXsHWmn>SSHD`y*n2(FrPY7P=xuE2B_zlrhG(>_pX! z4&#HmG>?sD1r^&S6)JAaIk{@4yBd1aHdEkaIW?%N2Z13RuvfzpsMzG&Ub+FzSXTqH;h?X<;CvOH z=x)@|B;no}OlxXx_7)J&^ib`b7E`bUA4xYuS*Feozvl;N@vhY{(KV%VBWfUO!9@RF zXSfhzz{uTPVJqMbktloLf}wdMVru^6+8FDfUj>7I2*!@JexAa!oiMx`#_neDT>^6* zG&-F&49;7%VDcvY$l6aDoo>{UIGrPM-f7#W5~01NSi~91;Nn7faTPS%ZKivd;GXA$ zc+(9?kPcDwOuOmu{QMIB>EOC?V)PKxiAK{fw`*EWlT)Nub0Yc!@R=O=Hjs!qN%G;`F)TcnvX6T+!A`1R3G(eP_)`dzV-XREHfL}xyWWi^AjBi+& zLP-fy6GVcrjZ0d6fFWGohlt>iUML-47P56|7(Lw7tPog}Wj2$x!B75P0}R}YG?Q=w z$KRhKs$gLZK{{}dm_~V+lp{?*q#EODKih4$Dd}af0)TS)myWo&LDTBM5+*D@;@>CD zLU*>LR*@}O`)uz^7H9{#r{~-!DcSu#^1lKoaHf(ul!k_dC#VfH-42l3CP@(uo?ogu$T<2eEaQ>#@VwKR(vJQLhvqKxx%J z5~D?%k)hN!Nh%V$)OH@5Z2}Qaw&#w`uA4gM_H?>iNJpW;mkV(u1)VfpMC1*6ZEV|K zm;Ab%&r;ml`f6j-NQRBrhE%{cXx5Hvqk*Lzn95V#aKarAaMo9DG|>qzgl#M86o58N zOSfY60X}ZVxVkz>JnKhZqcdX=DyRRG0VKf1#4H7jZuUa3gmvorN|KaIZK3h3i=&Od z?4vfs*pi$@h%S(DHLBAQFdiKyN@4$}Mwk*lk~RH60uNN=vwdRZgG2!=Hqk(lRoGr1 zYWVaDsO=5T5s(Zd`Ul}oGryY3EEcV@@ucWySFCU!XM}RLQ%OiNgxBoOrZ4ap|A*P^u$~ew*E!7zD5Rvv=WgGB-|{gnE$nUK zAp`}~F}v29R2xRk@-$LF@D`q5lJ{nDd0IyaD{NRG%3#A6*!QN0Y2uV+!R3k(16wlS zcN8eLJzvFg&~Ka#a#JgTq4bal=mHJ3(Sa1HKVHd_0aMFeEJ(tcepcIq=0OeV4cuZ# zc=H;+} zbhTq!oRs**O1N3JaOT*P@J+OIhDY$F_#DcUV%rqn<3Pp6ZA)z3tT>`mkaDS@Hn4Zr z+r1}~r-@fcd|wV+6F9>h7D5&{5gIOGDVhg3mvo^4(5WEUOGZ(!7l$}U!7xtS7S*tD zSFR#1je^#kdON}$7lH`Lr>!IAb(u!?1%3@S28vWz(Oee4qf0S!2iF=y$z z_jEG3utAzPB%f-C^<{!obs*ZktK)#DTSI=l_ zcr~)vtOxceRWRM@C{NU+*3xwc=t6oHQiQW|mH147u3t31J z>045#d?S3KEhao3WJG^r=RJ}^!-HieZFrJ2snI^!p#aR5QS&J#-L)NHwJ>-|DEM&n zDmp#>(LN9y1ad8>+{XhNmMm`IoT2rIFTK3LJyPt1+*E{*&*D#k54d~-a~@u49`E!1 zx1hO5K|b-FCVELa&^YSka)is<$U;mhg`FP9BoODQF)`$wtB^{$dewhZbL^OdP>q@2 z2Q1o0<^bF{S<%ErEjVWuQ2!{&&ce$~X{x$rTMjVAeOBT66B5G7&?WuHU6#kNg%Ajm znjK3C5#CnIj&8Kcx zWRdYrA+8--+}Ys(sYd*Ymt;a74+h6_iz#fegrpn}=C2sd($VT}9pXjWAMU_Q1(J>h zggH*gXlcX$7z|kT0e~1Gs}-mj?kZiJ_0j(jL2i04xZ2R2!pC6xo`hIkMWHXg?0EPv z|B!!lt0*tGS9bN%UT0VJiw|PhEb1ItC&@DuT11BFAAax~l-^?!McpZSOkNe!Q1EMe z|0tth+JL381H>@_2XfIHLb#Hy&>x`SI3M^$Y9`Z@$lmQ_h@A5ugEv|RTTe^5Pzw%= zBSl!_(1lpDVs1RoNeL;r8D_vOUKJlA1q$<>WW#A5D9eo%+k=${v{(T!K+gX*n~Zz7 z;D%c+h=LUqN?Y*)pB=MGff3+@+onh(53EGg^D!^}PH+(pgb-(bh(m>xR|=jA18Gin zC0V%cE=eth8j%C?3+*}n4dt;jqxIN7;b*orVPZ`i_%?J- zERwZbF;0}nvJR9R@qJ=Y%z2kn|Ma%iT6KQ>n=ZRFNvZDtVMIg9x&lbsTtFbONm0PW z$)(GtJC3pGKP(O!&8m zYUc4UUM}fd0MRroaT4r_4an9Ku^(L-CUr7Ww7bb|ea4EP?+ zpWrX65Atu~F_5ExA|(w_QJ%vwXz$~<}6k{7Frd>8or~m`MUg(Xm z8xD>tA-XGbO0gIIOO8MP%t-*}L!qQAlQUwGRO9CMgGV?@Kxe!2=6BnlkN@J>bATGKH@28+V zB6T5YjEOsX@6|-YkZG^(4anr?mJ)YFZC#oRNC>R4@fJ8Dt%W-xOI&tV4bo#RQ7RIp z=dZEkkvG!)U%Lj&848EBQvZyS&Zq` z8aP=vgXujZLogsAbI%}R$dQ2}QLBvv7k4BNoo4q??W{Zs&2dZwuP@$*YHw+@;Od6D z3~LvfgO~+D=L!Y5GUN|H5~GDtjBvU8{Tzle+jD>}>cl-cDpcg*0$2 z9{One^RJsYXe2+BP<=niM#B^r@zT&pwZ!mev<7hESec$P{(*lsb02M%Vh;dID^7%v z3j7Ih5-{WfQDc9KJ9SN{X4!M^ZbC5wJQmZd;6>ipz!kmmBFf?#UfISLqJh}bpC`^S z{i&n_KHGqH(qoj@a>($6yOW&y5~t~329_m!P%`ftu$KTDs3!8EH`qcKLkzSU4(^Q& z`MiWhN{N?;7p!}3FLObngqe)y%PuX8<`0kO8ZgsornY2jC4u&CKZzXQpRl}*t_sNR zJ0YV_MaP-J!l7b9Z5x*dz0sZP1AoihiyIr(#i9+kf)(1Q!3tnz61S2cw;9PL$CG{B zg5f1ymDUl#McK`E>%gSREvKzvtCQVmBbtGSs`qbWW9RAPXSv4FQNX2ilGkZ7N~!6X z3*E!?jzAohR#HugWHQAV;g>4l1(`2ZV)xZFUT9~DM62J5a-(fi6plP)g-0fWFh3qC z%xo(XMIDDjp+WmgWY59j|1Jl_M?qM=VyN#QDHLXkAA}jI38Zc#GrI;V=0;>^GNsAV zpC^{y)-$&$q2ttMna6I5x>g#tNfdxZ$XtIlQU^dnl!R$Wc%9UR#cu}?lF^kU`RAQo6z_%qPbUTABjDrg(0e`a=p zfMEF^HwPzbmK+UEV46We4|u*l0EpV{A=r8>f#^W$Bmx==O(DV!knFWxJHk~XWa@>3 zt+heOUm5QY{A-8YZ&I&y^JKyz&C70!v<~(Te{qkT~b|o6Us}iVH;{M z{T2*1MpQuQWqh<9(#q{KlMkKNoI#-$Yyd-byhTRE^}IA>-Tvo zW3TUU9OK74lku;3FkLOd`&x21ZSU2Dd5G0OTtCD=N)Jd5vCeAQLmXSb&qEx0eTPFFKjtBhe=T>2wY?wW z`1OZ(h`*FvD@z>W2&5125W92dy1dw}!avMd=Gnu#)L%>Q?$zCO% zNd}v@a->3$Q13HXv+EMGc2UJXXheq^f63yMrEx!ru<4^R_(ht7i1op;tVdYWOY>8O z+(9p^i~g{lS?l3DB$0rS%gCFMd@0yGhqH0#z2%K+iDOwpagVTX(#$EMhpB(o5*MOc zXp|@t-#@=+{&@ASc~Aeyd{iawrFa82b=?eAKQi@{29Uz+pkPl3Zkv_ht3EBU%ox~! z=y{-3xzvpf+_^F4Rq!wxz?eyT460wex<*2zUQe!uv6HwY=}r$gnUVQ&F_Y%C*W(w| zp{D?n;y(16L?Tok_T2LIBUjWg&F1y!^bi!o#eWlJYv&B|RbuSXZ6r0C&FTc}s(pkf z*LKN%cywFCK86-%99lY$Q?G|%nj^_`J5y}dw%RWwgOzO|0wD>c+P<|DQ?t-0K1Z2w z$GH!x=b?lb!Y=rwj!ufN*6>tgS4OSid?Q zeusN^wF$v7EByLh=uLU@e#FuvE)@u8%NBmh9OEIJ(ulBHf(<8(z0^spV#DQ_e}oj!sz^BUcdBZ2Q{Ms>>{o_e7kTd!`U|bZ&Oa8zv5-S zvap~JAe1CHXYJm@m$JEFaJbNNyV}(fl&Bd%(4+R{1lR6^28OsmFNZmjYaqBAlh#r8 zw@7o$&cHDwtnh4r%7!AyQ9A8cFSQWLOV1y`+l2av&HG;I`qglL#%ZuC&*f%;V4Uvy zFN&xaU68KFLWqLGd~TJdmD`8M)?M*bug=s}>SoZT`cX|zP}=1m_VnHfea$wX5VM1@ zJH*h%Of-h#F1Cgqwk$HvBh0F5PioK*a<-b{QzM*e=n@6Pt_D?=tNj4)Y(6?6wJ+$1I*H-MqAhGKF+kdCipr7#G;B`Tgnr;tmweh4haeT)7vF_=8`I)+8=gI*`0zf1_bMu zI`|GF0uj#V#MnR)h_MWpXoR}J|Bk?hT#n*e-y%MK8E_X{qv%=3JyjVqDz1oDJIq%g zm!bRCHEDpMm;DH_^5KAI$HB!i> z=MukK)qoNM^^Dc7csOFlwdjQc`@ES<@?v7JEPRj{q%m-c9z{`mN?{bvHk(WANQQ_Q zJzT=wGgGLtBDsoD(G969WW){Yn}h?2mMx(IPyc38_J*VTzs|{IB6m=j9_J9+lcvZ? z8XWfjt_{9KY8Ev5uglkH^ijuqA*qlB$)NL#5rqUD+wM}z7#iS`jACCMKw?fNM`SMV zAd7qeMCLk?cu1FpBjvd10-`&Ikhldl7r;h$0iGBCm~+Meut%&_J4mL%Hlx`@(r`(- zEJ`A%+j#WtDl#OkqNY4*<@p)3k-2|$DOx7g%ND{!9p?xMjGKup2HcWFXwwIIjhRvk zpPOVdtIO8ucp%|8!;OxrEHE>ab(~e3FcKdjK@@CM5msTjde9S@RlpgtBDC&Qt^s2sPF;_h3e{C^!_y{)ne6&a zfSH?0-o-{-152RgPBmJs#O3&HTenZkJr3Uz2&g__G0W)DukEw)xDweGawt#$U**i} zSB1I17vz)`miz3~yJZQ=gB#st{>mr$Zm5(jTlbU#pploWR-O2u{1e~Z4}isQHURvn zkGs>7%}EinVDz4t51PW@v_FR{33i+bOf$&1d^^gRvw43EcikekvgHFQyNKh|SWC$} zbYcyhW6QY(2x!^8DBdaiv|dWA6^3t1*PHr*BkM$wWyBz)f9pxJEI(1ipnOt(xidz& zpk9ivfb<5sd~MwXJ75&kG zb~ZCiFGdS^BZy2UgOv=xdV>erVBqaycWp5O>M_^PVChoCEs>%bK0X_RVl!~!oC@gr z*DWN<7L7d!lBX`FuKsiKiOA4OkN?Mu4iRP4HK zH8rbOj^2enN6hRxKe+|M|J`u#3Pc~ss=Q<63Jn%s*ddbgLa!q`f64hVpanO^V3>un z*FMNPRPD8Mb7AO+9Q1$=NBlpo1013{sAdtC9FWk1PcBD+HMRiT6b znhwhW2Js&bx%`m-hW=fSNnf&sBqq=U%|nQoDx4PqPC(nR$N-YH>XBxq7U4O8VcB~p zbf?Cuwey*0Ub!vvs|#}NJidOF8I@RVi?0>&(W#b(8viiE3%}!>%rRK679zNdPfVNoxliJ%P?B&9vPiS7ybEJ(UWg1MoXAG2euwG z@w)`@?DBIB3r4gsHpJW5tZJ8f7s?1FnsmeM#2O`WAd&pj+SrfS;5Q_~6r$WztVi}V zjmAol9*VqeSZxgi1;iM}Z&;J($%pk6ecU$#T{u)EV4XNIHu<6H`f}U1YaJxh9KmaP z-aHAQLsmRb1_+qerjQW(myqUVQX?gnIk$Tk#$`~r&0bwGaYJ|i_zy-m=_Ii0{u>nMv!w9PCOl%98E|jxb8ZIY9?i03MFfvIJz~2CEjMI9K^K= z|BG~%0^9#MwXa^zg)2|sTa3IaN(8J?7ywZi^W`CEOES_wjD6)G8& zjpOk3Jq#bVo$qI3=tipRWAeT{C{7746@4cL%KGL}=rvUm3s>lJAL$N)FAPX_gQ&a!52c)IOX%zc%|E&0vA>1MH zIc(REOtf}1A`N+?k@cOBPA0JA+d@(@W!&ZfqTHlir=tcF#sZT#HuSa-Ox^+;P4FvD zqz>Woio8gTAE%Sa@!=a`3wcX>5zQ9txz{`Ek7)YPB9M~(F@ypQhadvH^Veu@WB8LVbS^OPq5AnK`_R5~N~-6Z5m{rFJ3;}hH>giEhR20g z8Pl|+KGI7JLpkcD+o%p;V@d%_OUx_Gbai%#z$%0VPO9_a(R8wUf;^6cSCi?t2p_ma z{RCLp_i=z;XB!AgvHD;-IK^!tB*RQMaepxVZg@1<)p|4t0Z;|a*Gg!1s2s3#*_wi0 z6xp;7msZpHE`ta@h+04VuN9drSWCCFu5}WS*(l@!GOkOL5)>&k6+*B0#L2phhBwc{ z#5><`^<$i)ZbwlIo5xH_M;L@)N7kf(l|R6mul=n)kSbT!1gZeQJfiT72Hpl@G>T>= z58e^?I19tPwjhoayvvw?CUdCuK$U`nCFwmTCnxZ{DuGQN2f|S|_temmObzw}ay!y( zSq6){Y1c$kbj(|SksOsAi+!HUHBSi@=`%9rrJF*HQ?>cm@ERQSa(2n`Ho}pxci@UA zSUT8pJS^m)f14aOT8NCiy*KJcJPbCdr`QHqjD_an49jWP;|ghkv$E0gF50rNYxn~N zqND{&>G|43Hp3a`m&1}Dcon^U4%u#}FGnuU>f}I4}AJYcB{) ze=KlCcB8@3@I)=Z4ZB=!XrUkSi>E|yZnVswSRqNdo4A^<)Ozt0wT4g?toINcC=J^a z_CaWXMos5rX#68Uz~{yVH~tedw;>RS0_to5?4Y&IQ-O&YGjTzwu`@nIy}1#{D9!*U zg3p^h!`@G`@|#(}9DuZ?$cZiejiwOy*f5IC*Hd%aQU-N98Qlq2##x1M2&=vw`pim_ zNYOquY$GfzI(rI#_Ive*>TW5jFVx0<#54_I+Gc7>fdiXDiT|z?lACLd0y3hJ{;o~x z>f95EZ%deh9=02O+w@N!_Mb4~Hd-cJnh6pj0nuW)B{4G=E$8^Hp5_QSHt-H-6wE>c z!IYXQQPe|51Bo#p9P8`hb{hznP~ppg&2ZGV-Mda}lphYOUvfuMTZWyoqn`H( zQZ2Y_Hn_~pF(~(YUxLoW>{Ag8c!9EV3 zDguZ2Ol0|BjwDmD@Y9_J9E@}ilDij_RVyBjOeX$97^U8B>gn5u!!e>fhx6mf5$H^7 zyuof*Ryj3wj>Bo>u<#RDHZ0>kA)KR@@8qH(;?ujLqSy{iQ4O1K5&SEd0377DGp4FT zSoZ+Ti11OzM$XI>;hL*@aioU}}39(Kkz}x(M=JON%$>+?9>RvL5+2zH>WNOAXf}(q?N$EeE&o5wPzBs#BgUxSURo(T$c-<{cYy5T%?`?WM zORt72_j8ViGhtXfkaqg{8HBt!j3T2qO(VOrI|yDGgc)AM6yYW~g&p}EFc6*e6l4HU zpS%KtgbfQI(f3^E$^I*H$+T6mQXtB4y{p7LUX~GCl!lS+UtUo>- ztW{t2zXhGbY)vzlW`~zU6rG3CemsD{6^%A#Cc>>JnJ;Q|&uR6BA@HMO3m&#BOJ(Q- zm+#>pMTCqC-M+Df)xsS)pI-qV6!K}d)Zx=pvr>aIp=yA&u| z3<)H*VowZ?+`1pSK-`b`%|9;=Aaj-|aFQTkeGu(-I7q6a2OKku|3JgK&D`rsVM|E& zz8HnQkzE3z*9^V~vST_3U@sd_CKqzYcE)-JZ@`-HTE!VFx*hW4VBG%j^o+8{baHum zmU+~Oqu{{mGf2nAvA->psX1U9ZbpP#^EPw5cx(?$NB9cJh27#y8VfRPuY;6pQdhn5=CitE{QpfRNECVs!UK($CA zb+r#Gp_N>CVMkSBvIM!hiVy`#7h@PG`8qj^&~GANMfwZkMKj%U&m;+`@`exMJU>G5 zLzI2O8B22Mpw1rZ?LqbgiNhsB>>&i*c;x^d7@Sx*QYhy09PG}fFHla4|HF4XY4JJz z4jx3USD|97M6%-iikoO!O%DGCe_+HnKJNAA6U9bJ0chhV{cQflz4QzWI2xQyMmX{G z(#ez{nx1b|Z*d5IpbX47o{7X1yc&*145ghyyv1kY^yeDHSH50VxsTxGlswSr-wrjBt&VeU6fslGZ6&r5>d1?LeR}fcrbqeW^fJ?#gKzgxn;uX zld?dAfJ}x~;r>wA3pSACknD(#I?>7*8H~N+eWocEB~C+85HJiUC#xZ5A6GXAUWg{F zY#${&sc_Apah<}kc6qo4)rHE}D$1^}9za}58DTb-9L2nrKqJD2KyEQ15~b=!Lqj?0SP1SO(kzML zE2&7y$Q%AMCy3Z4s_n0~_rBPEy7d<@g$@!dKyw)%y|LhAZL*2`p$GCMn&7U^be_H5 z+S@tU+1h-bAd!csQ2X_E3xQud@0(o11peO zC?BDWeW>kOyww8`vU+9kF0Ts&V0S(9f4D5*hb}ldAWD@p-c$?TxrM;bp|p;1W`N5K z+8Nby8*abuQwG_nwnfWFSkB=LF*#5#Uybj`>7*is<@dkq4@a~Q+^Gihqcy!zrEzq= zT97EAggnjrU+u%32c!V0gp=qMm1nBLmlr=d1ZCKFgWi_mDe2oWP!=|ba=HOvn-_5T z=y{ZLH5r4>=YYBl<)>h4WbS%ByTm$>X!+rawb6Iq^WyDw5XjHkyFtKg4waloqpo@n zG?;D!HX(DOP->dA6ceiXn+vkK7`_6MDufR54$$CyG9Kb`&fvI&YGJQfssyjWs5$09 z=KpRW2y6r_dvc`d9TD`SoQ4rPpfv`cav1?RzQ&n>IS*DLTt~veJFYf&cV>5B>H>L( zoXeNsSa^5`D1#V{;Z$sI(3Qrg!H6il%}4ZTmLUZFSJTP(v>g1s!_bKCyFu}(UWgRj z7@m%YC%_Awj{!0@&ufS3y-!`)!Mn{|Br+rcreM`P-E^CI|KXH^)SYVoe?O5we)5eW zGkdqSJsLp%8UY=J<6+j6{9LB^Y3Y)T_-?a)LI}r%87@1D_|gJwuY9mX;qMz1!B*OydUJi`-apvc2Rug{i;;x+3w|ZVdtjw~A&FZ>&11?-HZDS)SFfc$G zwDFrs(7^;LT_y7Vzocgs+Ls~I*VqhE6|c1sADSS34Pd%reJyx?aAN&604jEfYeDm0 z8p2pLziVg+*VquV{9J2G{=29f*8qdsx2^?+|2eA5HQ+=$-?gCh-$4nw#`?vQxex#! zK>TfzIuec$UMW^d(3OD$+9cB#a^=`>dO;3XcNjEc_2M9-id{gIq95q+7Q=k{l-{9i zaDcD(o~%`ys!&9Uo>66x_9^kBQ~Fs?l3@T)%|be*=Xr z-&8N*Re+meHixrj`cixY5_Xi#KvaTeO+eSHaA*p4q@-M^3nA3e@7n<;Jg9zCe=h$KwOtmX^NaWfH3(%|%&DU;i*LuU;_FtG_GU-;?=d%i#qtkC>b=@Q z0M-N3trs^}149K|{vXAUN^Zp=JInC=^1PT3ymYV5hPcx!2#=V$V<^&4h;e>kBR1E; zz)M^<8+EgbWIAEcJ%Kqev#tZu!Bk!^^Kg{G{0ULo%s0N3Tn_`hkXgVXB$Y9E{>wlx z?@0lN_#K^*?k_uP4Cb=0xam!w2%PITueL@L7>#X@d}hIn+6FDyl_gnut>9E`iQJUc z2ikvap(jTi-EZYsqhy&ab7tf}5wj5=KYKc|zml3{xFBU%@Mc zG-@{EW?&_Kt0Vk%(`Z_wH zG7{k_vE=y3m2ugTEcJ_9Sa?#1uF_U_zK)|`*nWFKtVYn*_T3^$uq_MWi>Nq-Z+V_Q z5=Ak1;RL}6mp3E-qww)(X{i36fxSF*DxcWVdaggesUCcmpSkBLqJPsu=t%~UEW63# zUlL z0Yo105GZT!0(Q~5aEyEJ^xw~sRmoZ#$qr(gUyFba(7L7Cvu|t=d}|3Bg|cVj!a`nZ z&A~35p8}LMl1~I$NcM9K=ytwBfeL~xZV#`cgzaJsRkl|azj2NvrP#ltzK34+i6U?a zUc${yKR(?L%KeeX*UaXe9RDR3rM=SPu1hS(E6jv*%bK(>Agxayb6bk?I!sAoiVbIjkiCb+(=oUAPQK83w*7r~*{t zE;BV`0JpC(VCn~8xOLeR^_{0P$gg6`#L0@0A8Oo$^a{I&-UGY^N6@jpQ+bnMPvsYZ=LO;9&Vg;Qesj?27*@hq3=FN;;U~PE}Y{wp(G@OfTt(D0SrVyoGHjl zVvspks#d^-6gXOAQd+fQ(4;-5-n-E#`w{rIPA1=wWFxG3vn@sTD-;aVt#re4P5ySx zO}C4y_zY=Q;`vS9>&D@|rQu{_du`jNpWCy1^O8$=**CUn=ryYmXB|Fw2w3^Vjg8&C z%`d*%WUZxx?Y;eP5}7*dR`;8WxmLHIKY6zGAJVHr7z=VLt!jx7;{zN8h?N4_Kx^cK z#O}O3mWWh`Odt6f5v3$Lf!~e3gU-wNB~>vIDg{*0Zyhz}eTkD45@Q#WMqps zt!wO5h%KrxSBR#?We*E6=2<_*wF*4YeK>;xicBBJAnO`tAeh5AXk0>plmH^xW^GWi^YKz7%PkZpA%W^pG9e%0PdOb) zT~0}4U?}1k{m{-2`cv4ga8q!EyF*VPz+iLbIC}@PmL3kF?tGgFB;Nai74C0u9qc@N zT3_6PZ+4#k30M5KAJsqNfIlmUDBQF-VT+*SKz)BO-G2J0*9upHNY0(fZ;Bd?mR>gH zzm@aZDUOC0xTztqw$lH061N@=wB*ZRlN;6gub7utEmgld_VP^Wr^)XN&Z->t-0G5i zD8DZFT3A8r0$R3!oh~%l77_$B=h^8M+gi{MU&0lfOevj|V$gkSWGzZ=8z_yBa;*)0 zno2^nj#b^bkGHDtW^3iMt2Xzlsb8_X3qF_az2b8rf$ea6=dXY6sO5C=-O0PLkw(~o z=6nP6S}5}DJbkqNe~Lsv0VNmg>eFYBw)e#XCS0h2!LS$CC$*!7MhiH~?&jXX&gPS! zoS`se4mLqiH6aG0EHu*N59r%E8NL?9hDPJ*?4w2!CBy+5D%F4>h%Lpgo5YR)`St_B z4SRYZkk?@wxBgF?Prlx6+16ZW3PZ|18ds!5QkS;a^c}qztfHPtNIdKiw?Fk==Ay5d!(KfZ(L(0OOZTDz26nh}zlB*QK^ydw6B@)b-W zBBiQocF@xuTQp0KvVf)A04)-<0&R2ei)IvK-_1CxqY5~eI%4hp|9E6+)j2sy{=-Is zh9DMs`p27-yT8Y2wjgdHJX2p7ob z4Aw&mT7V<&r^3RHn!+Pe;sjaXZy0^kp0RY2f!ELY|U z08VZ=xtwW#9!^%7kqxVBltIYc$BP=|@KI1q*g&e-6FU|1$Wl@jH%G0@6lL z$QYlr615dXYg6lhuUkR{1(R!o0R%fI$ko&#b7#gfCgs%aK16jgf^2^dRmM`QpahL0QPASuTJ%d#izA$vJU5#cve+8nWIR zp4$AsR^%E|EayT-NZ)4eAUGQ3(3t~NV=UuBvlC^#ol`udz=&_LON6clFHnAjK$acJ zeB;;y=RUI%qOE(VnxU2#q0x#}KbrQB9X9PDpGS<;zp}MpS04=_*fL-l5Q#g9qGTsf zsk6q-jwJTVe+j;DZF-mr8ybe&6NXZbhLeZUa+<8&+Pch(buqc{^PQ5kWc-xRoehu* z5NQvwG>E=Daa7RitgK{G2Pm1y4bo4L`U-!|s)OFa_WwDMbXO7;Bz=LuBtSbl19w9? zyJ?M&Hn1~=Z4AxO4MZlA$q07@(-|~Q+CFb#Ty^SZELUDMGbsY7k(6Aef)XwzTH0!` zv8O$8`=U_dUti2_udGXCZR=Qy@(ZOKDR{5jZ%Eg==_oxFwq1QXIIdE%PJG?s5AN3! zZY}TY29_W~XQ;IV;$SBd^VTp_x#@|Nqtc3rlh!VGWy^_B?QHSxFX_#?5+yJ@faslY zqS-8QEqS-IGa4Zb1s4(+^beaIDD598_Sv=tM9Q$GnHKD`j1!JNTq#n*6n%k4)7dEp z+MJdpA+S^HfuC$%ZlK}0g7W!+b$_SY^aT3W^*4)mtic`3(aMAB-c<+^G9r%FMYn^P z(sKaAYeRLuCuHRF1Tyk~!0}HlBEaT{mO4YUNY|ukg3(`W*9>6`E5f;waGK>o*+Ri` zeY_DEDpu=wGpl)q<>6{1auIBrtKiaa;a^vuJ@V*sRLU;mk&$e zr2m?X6$=M7U-}iJKGvXtu-bG;{%*tiV-*5Eh*ZvQB@OXsm8P!eiATv*xC?-q%~^J} zVLi+47j^;CI$}_9S1#6ogdl$|uB#xhl=2hP@Jbdw4Q&;KD-Xf}Ld>bvHUfHCsTj-Uj^$$3tjgo`k_!0z3|Z=>bjuXS-aqz}af z6qz}K*9Iw`nQoT}=@GFyV=8FQa5_ODQf83VTR0dFN$&5^Aj-~Taq6Dma}@`&S3*cC;h zpUI?kGMx8^6pW_S_hGa-wRRMlymkiW+y5Y3*F8fb9~TPryl3rj{|$gH2@NVb8Kvc#m!ejD6H( zHx*a>1F-J)(!F6KY!&`!(|Mf6L?rwX{ORF8k$ei+-zxBd2wL7W2Em3G#FCB!Qp$Un zNaoL?nLd?kX_p95vtYwajA0vIGeJq)EJUAeYt1+l8=LR3T@U#a1}W*^=ab0c{35ZH z@K27Fbplh5D7mFl&BjrMDj8h7==xZ50XzLr+7U0ju8HQ9PjK-JV`#gsE5J=IWP$Kp zG)>j^?>THilM9K0h+o@7MQN^!|Dvrbfslzwf16FlJ;sTn`mJ?rbFLc!{6ILZjnti^ zL`lKAUXH=*>8hn%u|Bxd3o8(Z$$kKw)>GAnn1brSEUWo7u!o-VR@jaIQRct(Z|j2j z!|&k8a)IA&;^d?|qy|`_$jv&Vb%r9n(CpUsDe>cIzJ)6?SAd0FN z>Q{Xf5)c0n$gMMk|~ST|rh(X)9pD=fVpY?d&M zf|P1T4IqP9lzg1Xg>4vPP&(1@S)gh%T5=S0I^b52Kz&A9vPZ<(+ImZ5Fv;v^2DW1L z*8|!P4G_5YmS34SxI#yuWphh+W1m%wB9L_}fr72z_P*`R5s~b+S4c9h=g`qM9%vxI z5%!qM#G%+N1~u=+0e2DquO+0Yj-2$H_ zp9<^OR#q+tg)>?(!CUtXL?P+7;kld2P1KhYEB{$Bw|{b?IvpjA?|7I3qbh6sD0=u_ z#N_4WlwnS_NgGEdH}5|}$c5!O-(EV%6@CDdV)_vy_5RH?}*6?!^c+%AJI~12#ohlhgFR3 z8_pIeMT&YnJUtg%+1}+LbngF!GDa-nb}={6|F%53Q|-RNoyW1(HZn|cgxURa7t_E+ zAFKl&U$U{8EEPUNa4)VE69iksEgmYR=O`TX9l!*bY$&l@gJ2ovC}=z$3{Y+WE=DBa z0YucYcX~OTp*#Tp-G*Oy{%Qb2l>bBm5<(ZZYOyxdh^e~cOVs5W9`ULxLk|(?3Fb<7 z!Y!FsxD^lKXQ%=RMgmfZNfOg7aKH!dq6XXK2-Tvv2<;EnyK$wp8eSo36@qsJzMda1 z!!k2S2PVkXtf0ktsh{2E8~LXUCE>9w#&|1iP-`dz zUY3*6;Z!><)gdqAzr#ZB`BETAEV<~;VSkMOON*aVW=U#Q)&TJ9`!-C|D2M$kfswOR zAt{C%jv^0@*XKTHkm}&@?g&mm3hvl9?!EC$sX+i7&UQ$o(6q};9hWs%Y|)oZ%;*v^8T>TSnsA=F{|F)Q$aVq9gkw>!$F4@vTdfx^3Pb zKbuE(hmkZ-#Jc<@Ip~hbEjVF=%Gn$ht#3=tvw6%qED77Mw685tcE1j;jtTjkF*=ir zAPt`&YEWV_&g3dPNGuo@#%9&ra-=sLJ_BNsug zIs%JiIv`mbDhk^)_918mFA?}vju-q3+`biuM7YUvZi?gT0~{#@?u?)KW{XM7KU;k; zoNc2bC!7`~Ug{iHA6#6{&br<{=_kQE>C!GByU4M)J8u=Im2~HaS%9D|>c$_eE&@RXvUA;kA}uvyd8dXVVW?8~=T1c#jaF zG-VIM`KddQ4j7BYDYzwXy?TtC;#56hGpAB{1QFQ&Qsn{U0>pafsm9(Ba{_aYuQtEv zF+>foEI&~CO0n&;>b`4PxI-f`VWQgzT50nGzw_;1bbgr?mObeCy?JQ>&F!zn`{dp@ z=h;~=-rF^g(Emrpd%Hy$-an|n$1M?k&Hn#TyicqHk!ZhPh)xC^$N6c z2zP0*z3xvWlCk6gV!#fl*J1z_)&p(PG=(K1JdlVY6UQ;Ix609>tyPW`ZLM#|vB5kd5L`hqL{L6kK)>zLuolnS+HXNiB zMd*d%80kQUX1wTQ_$4ZtatkFA&ki;n_a?xj?7OY_?x=jnXngCFk>c5Ra;;nELaWg0 z>?P2L-|;ZOz?;3&+r{!qtx4Hix%90c%0-pzr9|24OJRuFON&6`knn0jiJRfIz|>EY zxTH%jz8x!tR%m&MIP$@?cqk{d=Iw`7hVoQ# z@$@z%|0?WFsYK?)g(gmlRJa$g#=i=BAtZ>9{s5FS7y{)p-qq2fPX%2IZv9M zd<{z2Zo6FSy`XF+jak^(pcRc^L%V>12v$T`xu7NSwj8a<1c~3IOTJr9VG{CMEzB?2 z?4H1t1g4nAYGEo(hHX}waMUq|#Lk?vh9>5{M&YqX>*#2L2%2-0DHr1*4Q#hz=|d%J z)cb)+(Y6%;MK4eM$~H}cZ)o=G!`1g4?41MyC#9Ao10+lUoBLZkI{?~jjzFEXF9p4J z`|zr~)+^%ICb*k!W4Q*<8@#4bwc9yAg!cy92Va7E#PKEaxl%YE59x$vlO{N@QFXtj zpe3U>b)D*v#Jt8f9f3q}x1m`ySOBsOAlOE#>;R?UUE=L1C*d4SY$zE9V1LiM2~yPc zSJgYv)1!ds*#}A~*n6UTBC9jAr2%aCMR70DBp6@SHPaBxo`^$d`+vu;b-Rumwvv#J zK?!pXE_NstCQQJso443bK%i>^_1Z#-ol_`)`hZjpMN%At(-cuW3F*Gec#^(d~&Wb@{6uDq9zKo5BMY2mr0{flLPWW`qL% zeiE!k#wV*)SDw;2@b_{Ls!ytWE&D*2YRr@(KoGT`ODD~V@_alt=2kD>HroWWr3^2q z;jG^~@}E~@myVd{FMUpiutSTzU<8V$H%*JS0r%yVM1|zt^V^}r(9h4@b36i zR|Bl$-Ab{>E@;dTNbQ@!!?(@HSiUokBvy_T+?!uCch}sNgFppk;{LGt^EM*U>IC2< z^S#~5*bK$yz-CN_UYgB_G>X|4$~MO=|JgyHF-Kf0f$Q<8L=C+BjDPE=s=JAzN-06V zSDxUG$EJ_N_p0CFd;3)QYmic!KGktm_lw^Nz?S$<^}_faS;aEzRGksu`5FU3Ovp)M zdbm~n(U*karSSofe$^j12iTxs^NBz8U2a`ODy5Zx$#JPh=YqXp5vgFGkQ|wseINrs?mCP%>>7W2jw=Zr9$INk*CW-AuZ@#nQXE z!t4Z3>GY(eMvLb21d`2U-v{AOBCO{Z@UAqG08@Ef2TN;%V@9Hb)w{ndBP?LzKEtKK zzz?p<_~V_HKmUc)ttP4WjMS~bGQf6{x zdc`Y|I1@iaC0(q>Hj|FxDlg|58zum@(F%nMCOxc(v2fE*n$ND;Tmzn) zRALie>K~U3uhBphY+MO>i0fz`Gcysn2iIgml0-8h8xZPYDsDNWO_Z@BmhMHopl(4^ z-=kZ1J)Eh?10^5Vu6`KA70GCaR|;LzqpV#J(Ta>qIhqtl!M~N|atxKC6CnC5f>uxj z5!ri6mc*UlKjk0xjuN20>%4WJU-DX{CHzgk@k4SORfbq>j^z^We^ShUeoywUjf^(I;pCr_7-^Cp%Kf#w`d|uj)D~0 zv4h; z@GHMY92+jiu6$2YpM`uEsgxEA;o;)e;0G&(gnTX)F)NOloP66Kq2JIG_%lH#<&^9W zy-ByVm;6F$w>v)gq&@;W$=k^+wZA&h5$uWROjb@)&Af!C+Wj<&^K1gI7WGbz{ydrD z>Oz^zLN3+AX_s{xt`|sPH?N|=SAaXX-0i#<2?!yK%Xu`=sbb4BYGm(1lXs;$4VKSF zas!XQ5{;bH*sgO25`w^%{D<4N0{B8pbE~irFPJOvCA-Jr7n+4%?q^3I64`Zk$)Jll z2;1ykj=k!T5Ibe7c2PdR1l3GJ)STQzJjBdL;-PD8Y9jm=P432*+4`KU5D2BwYY{!+ z)f{^Cfn`$!lrm14Sy6z!%1dZJxso5MxD|LC{$!*{z$>LTj(T?V%GO9QK0cj?dnFC1 zjExA?u87`i8A?&%noPI2Er57J{6C^|t$K-HN5L{|)D~Wh2EppA=4PQeK-3g>OP*}| z=*Eb&DZi91Kuuxv;2%z~Jn~a?24uq6-rPg{!_l|65~cOf5TwX!B)4%xW_E!LHgbve z;MMRH8;h>+6V{TsuYm_RGUHBmh}I=^tK9 z=IiWc9YrPK!e2iej@MiIlkWPLxW6>5_(^pz=%3pdM^JtS)#v+m~2W*8)RlV(JPyYQE+DY+ehXl$#-Dqeo@7d;0+P(7u zgEA6CYNAfKP3B zWd^tIw0D5Yc-xzQ+TQOyd-~)rxSWR@K}-Wdt?~wO0rx**^2-+_5t{u{8r`aHpxF&g z%O}c2&x#kb+!&U=Rz2F;Lv^obdw)S>GD1H$@#`Jf$w1bm2b{6S&znD!yqg3d;DhfF z&PY-jpf1*~n=j`6e>Zu||G;r1x(Tw^YJc|GO^5P2&w$Py?QRPD`s`-$5UITepWVc= zZ&vG!Wxl}#bd4L%OUg{_!34KhUO73zlfc1{exa6ZqXjvfI=?<2ts!XuaYH+Yi1``s z51l&D@v>gZlGc zl7vVKo5C`1{)mB`Au7rDWGQ1rZCyP>Zmc!uf`jp@J{ZimQb`j91%X3WG}WPoPj9$j zs+_>V>0f~>fGxlw*z^K7KQthsV3EG_a_JUS6%2>GC}od%6S;Uxp2%jOqedTYD@)3^ zqrn9(+CoA_Vh1`ryy36W9#454M->##*Bz{VnV2*)Gc>?l0Sy zH%DjoYu4Mr-saZQ^U}uXNq))t+1)(Y`m#2sOk|uR5zTCEIGCTTO{S;oXY=#X`t;=J zH^2M+zb(cN=^CTT7}=`;f>dD0yzlD)N3sII;;t(3<0FDL#S#qE|os<9PXlq&6JK{Q>WyW}}E==122u z2;FZVGW`ppYH%RC}|AV1exg;TO%b|))Lx5OG|Cdq)OTL)ZthTl)~@;%D!rVwp7`tJ4`#u z3?Q062r=eZ5ORA4aMfd^`3}U-WA_6;OmiQB0Yan*`?q;HpD^GXsyQQe9XeqY$0OK? zFiF&$J+tkEBp?XZgT7@w$fini)6OxpEZ!x>eYfu>L)l}bhxm>G+tm9-9b_g9r1N<- zjyu$)$S?N_Mkv++k6ZO}b}R)nXXm&wOud zF9Ln#&ff^A7^l`d`g-pP0-M@ipCE0@x4aLdZ3s%m*VdtWNZ^7P{n~rCea30mHs%Ys zE08{BGW}Mlivv9Fji=`{bvFhsF%vVYkHP81JCOb%DX~@~=)MH`^~W!bGnk@K-!I># zl7$9xku$&*6vtCD5boIph})i!gvixiW;Z*=z5C;d6fM%sGbrLIS9gwhTL%^=K({#> zU|%8-t{or1WRvhZ*@2JbfnT<=*Ty)gi2+$zUjSegrgdWl!6B5cKLaw3MoH=dmFlzu zkYnOGjBWX@3&3Sq>&6Ev=bG;?-Ff7~GL0J+AtW=>?IR{#(F549hrHv%7!esrK?ok} zcAie^6v@a6xpP8S@Mk$Li`^TnjM~udR<_F4CwOS=>X#2cAuUoNcB)j*<=UK2T~0^Z zQXlJqNB$CugQD2@JxF^qk&H0*rX+-jmAZh|4QeDps5AV1x{LZ1m0+8T6Ut_x3RJSY zf{9_k?}#fhr`Vrj3pJ=;K3t_W zO@IBV4judx{f1NeBhI3j#g+mwRFZ|Kk#mdSjUbB8t^x8D_U7l4bBz5(kP9U2e8MKT z98G~)c@ducgsb?vwuq=v=qkpQThf-=5!?2E&T?#~<-U|ls?=zgtVee3DQrs{6>197 zGN3jg;@1yix3<48=Re%3UOMG}Nm-oTK=p*u1la?slJqsZ7#yjQhgDHv3YeUqgVC@7 z;#n+3=1f@6xY|B|BR!Z+u46l-F{PPJ!B}*JTwfWZ0$hGVRHC)AgnU7S1T0i zQN-*o4-R(yq(pmtv48NCr$&@10Pff)%Y8MK)he>g6ZdfRxg zTOAD<82~L$&CVOuJ=_bi!bKa^-L<>-RQbf>F~u1+wV$R3VbNIs0>byTjK3ZT}NVtm;yb*L$Vt+N5 zPAAlz<0xkTPe!?SH;f_4Qqeq{wLD~m!_i>IV?>vq*jfz=vF|HZK)W4nm+1Ym>^uN3 zE((GB;RGr*_8=tQpoTyMRqg-#dgoeCLv{*y2h-RYdfvnj>@cnCB)qutdOU*Zn5w*& z?;{$lGcyVkHEql0*0^OV2-=| zSqv;BK^h>n{wiljP}5<0)dZwBo57N>I`6;k9lim9z+|2>(Vr zv&rOJg8xhYbTo~y4n6Zdb6E$N zUF%2C(5CaX3nVztVQ7S^21nu#WjW9m@xxg3S^?e~P2BJeWLENos#6^6f!HAULy!Sh zl)x^OD`C8sBDE!QO6*<_JPv?Hwsn9P(>EQShYn9LY&QXM{2fMfXi{5WhoNEJbzl8R zr~&nxbto|FCR4BPQoa)?$>$H-t=7+C`CN!GNPiA9^_cOKYNFQ9)uN;GuPCNgXiF+= zY$a`#+kL9-*VzBcjW75_ASG@qrD1Y9Y8_ZLUXg$wQ7`l_2S!pTTM7W(;!G|;@T7JY z$X$49+b&d+tx}COGfepc=S*#qin)?>UW$4J*9s6zl3mYdij0VjfnaKk%f(g8??qc3 zDqsuAmgUkqh@&&ml=MasjG|A;3)bX||@a8DvEH8%I>oyZf=~ zY9G69d8hi=3=SXLU>|$`67_yVP1`k)IloHa7RV(b7J(RB%Hqvg5i$ffHFTHUjp*+} zpX5pLfw~;T=Rm*1V8jRu8rN4?N})HKvC>cXt^_Xgc!*nB^wf?AS*v#wU!?97-_~vi zU34Uwh<8Zy3tFe^)U90L(vojDL7M4B4;7Bmegqoa9$4E1(4g4@l)+YW?D zIf5sQs#&2H`iTp72+DDxT!^)G09j)&I!37wcFX#?a0*KKTz}8_3-<(qhD+ci(}{o@ zX8j}_fzC1vN7^s+J9(wllVT7WK*pU&*oSoV(!sE1Lo?(bP?-;2if4$yr6RLQYfjgv zs7uhRloC0!oJoPpon^KJ-~$AMJ*5@GBKH~op_V2{27I3yFeWk;$U`cA+J`e%vXX_C zGVC3hGR;@Y8X!a(W5uwWH7f|VLSKhX%BSPs`YeQlF`Aal_R1*fIzj?@NDeI25W@3M$7#5Po?_q$#s_#UsCiV|{##^r|$D zwXROBihLbxhm}Qm+bXgnA7~5?U?4LxzLmQ+ppdS3TP$Dmp}qi>zVPnLY5%(+j?9H4Z zy|$bE4G2BwToeRU?t~!VXC{QFs^nchzfx`%6*l&#(g@{uFU4yE1v%KoMjt7>pp>N% zlif}bz1GAzfK<3^*pJyD2sJ@s3K3s;($O})UY8sjXXB?OipGgf5#+WwBk#1v{xNP` zO46%{p_C~ljs#kl$SrXX$hTJz%Y`dbAN$7W9;h&H_xx_=aqpP=pqfHcp@@T9S`@Qz}+{UO~^U>B5r-U)47Rb<=nR;LrE z5H%5*jcHDyd95?YT2T?MJEG`6jbA#P?U?!6fKv6T_?B`{o0QY=1?0faH)$6Eb<&5r z(diR~QTil+L60>f_qNBgOL!CDV4&|v7%43vjJ0)SYnXdDOG z%RgN84VR0jxXeF3Y?VgdS5x=)u*rCzQn0yqkrBpll%gqW5rV49Med}l0BIN=OH8xIAqr(CGA9?C`)5=Xf-M;6|mQCGHE zNgZEOz5x25S9tXh`uX#w4ad)3WuCX8dgGN^$?jdH>Y9G{U32-URF=*+9 z{;lFFA1ba)puEt^0DD&-Nl3mDGp+F?kCLkW{EGU4F9p8>|#(*!)Q4z_Gq6t#6< zm{Qe9f%DZseEbmoZz(fT1>L3bHaDAoVQ89vawX&7Hrsa0uI26tr|F|C|HNPEF6qv0 z{c+>P`iu4TA+=I$B>wBU1ng8Tz6$V+GCfU|-ThnOx@s+e5d;=9iJm!Lqnd3lTpPp0 zHJn8r^3n%oB8N*k4$~m|lbT5y4;{hrSGO>mQ*#PD=$ zUFb+U`SPV`D;Yr!nu`vU*ev3=zT|QZN-mNaC_~d6J`HR1*S2$U0DDoca+k40J=wil z+aOa5(+R8ao@$JzY;moHmYd}~x?#Vg=5C?Cpp@T4s7<1ua$|oFPIP?VLgM5OB4*J?5pn z>Bfen^TibeX*pz5`;_z^d_$gJPKN<&p~id#PZ$JEF=tbPBPWZhk6#Ie#T|!V{1oU2 zSU#WNvM6q}$|HB+u!XjRxnkol=><6Bsx>sC9N4-`O#YmGVHEad>Eme3( zjCt88n4kr}aGh$HNo+xJCu(0w3{Ch5>S?Ovn0H6jBnfiUxKU*h3&UejIZlG7Xrx)! zP`d#cGEx~KTE=Pc+IZ4CnvPC-Gk@uKJby&zV;bfe&HEnuLShSsp$45nyG)s?OG{>r zsvhHp6L^fljOmJCNIDu_9#drUMvQtSP?|a-;y#-WPlqrMJF}wXlD0Lr3^4Y*%kYUu zSD2CC+`i(Rl(>6?efJi^{9)pf8ceWzG0=bq!9sY$id%*yBE@NH(7n#;Cm7IP>%K^1L=d>>vJ!NiY9+Tut-qxF$E6D0kbQ0d1R zkPw%!@S88DFUI`eO;9eTF-)Zm$<8qCUwp&~UvY^OB|ZWfVd6oF*>ze$q0O*)R;MJ) znzC9JgeLSXi>nWW{dJXruqXDKOz)5F1TEGi{4`>JE&)JX zB4(V95P)OVA&mD>i}101vjfUOKF!Ql*mk`Nax2Ud>CX6B_=IU`E@#NhhOlF_h6;~UychGP9I{Yc*AX!OhOi<#|lN3bYq876M?dcJ}gpt_OG zK^LI=9$b)m{`~`W86Yfs)k{P~=`Hl`6hVSLk8$znc+fjKyBvQzz~$rgl z2g$j?kRRxKh$)3RjJL0jnBT`wJ8TWQJmB1w+!kA7YYH%dn(6`%O!Pb`VNNx}u$Ih{ z00HH>Ja=u-8BO$>4q%ga>%+k|{SAwAh4K6al8V}a5@Hpmnh^qU)=%$#>g^Ips?!tb zA2bR%PpTOt?R+#&gJlA78gH!lqlR!Q#l``7%338XCejq1497&$lxw7 zZDtWgu5nC++WJhrBL^r1en${HX5BdXs}GV#B;d^1Ja$pwo@Pi2>YH_#F`rHZV;d&M2t*5kb3Gf(OhehPrD#`OskdNJd#?~)2|lWltxpfiFlZ|RJ|M~>Zn81* z&W%tScL$Gq8dTj9B^TZKw}3~w{Al}{^PCN{6oAsQu0SODA+h{3Gz_4>KByP5M)4Un=DJ! zXRXa953DU(DS7E8(%A}RJKq~9P7J8HrAf3!@k8e9zrL@<_>6#Zu2c$36Zj?ba482u z&J*zFnI`I#%xhFAeYV097`TmfMas@?F-FPfD_T$kP&pgC28gh9>QFX5ODQP(;v7O- zh>foB(HOIHic$p3Q-EvYz*;*v`KSu~bYPigFANWq!|!qAyWi-*Vc$^Q-c2uRv_~8~ z>ZU_?vQF@)_GTYiE1q~W*))I0N+>oBl!(E{oH^I4ps14{dv#<$sP~D`KtcW9O3)$D$fcK8{ zizG5A@F#8k1oB&KCpSOa*~$q-b}&}f@tF4CC|FHi!Zyl7wPQv*f{w!AHCw714c-cR z>z0W0I73q1@%*IQ`PGaCekq{g6Z|)t0Z7(;6ZI!BHl^3^53uzuRx*7&fWFPl$Hx_o zmlp%18G(cYNSE?~0n3Dff5t{l^PMutDSs`tvVbEwiy9V~OU6&C^BIA}4)2j6BM@Z7 z)4vZd?ubbWbL6_SBs9QzrT?vR zp)y396o4;(O9-!|4`-lA{}4x#!Y`;}o+6k~5H*6m^(evyM>=Ci%Q2WIi&u^2eMv(UK@g&QwIUIUA@OU?4n&+W7QzTH=Cj(D zv_X1L4O*J`s=`p5m-c5I$j&orZs5LCgth8c4mw_Dqr{_8I0#S*Axj*I6 z*+786De~fsFV7F*NS0*{$4Ih*G$5cu><|U9@HrCgCYd~puHe0u^K)DnXzq0Z5i@{5 z303fc$PCBu=pg*Mx_K^RPEJms`^|2GSE@@EZ7`-qC%|t&wIWg-?6}Zcy?-a=UDm3{ zIP|;{NczjHMkr{=Is&gSw2)Eg@<_U+;ScGk^aex0r;BMI*Y$#?g1GO&8pOk+H6|1i zd$QDdK)2rx=Ii%gk%3t;vNh}&Efdv6!1;(1L;mX55<0lZRzguu%*>D#)oS0=ChBhU%POALmf-6A?nkkbU9{S zoo?ql$bn_=D?|F0RE@wiI3-qNukKS-U;@M-b%me)RQU8pu(1eu;NycMr^5rCjq^1Z@s@1=?d=3+Z0lU z?xV?6I0=ye8yPfl<^aj8l)_B*^*CE4~hEfo)gq%uG;$i9Td+(%#N zh6%gE$LIYi(n5&@lj9^B9)JY9y@&Fm52ywLNRMLPb^1F24WC^?xa>pd<2Zlof7f4w z;c>JExpeK3N}|X>wRd^==Kue{|KF_oPn?vE4SNBHGUU~@r>Grd-|tHbsI{GEYkuxP zhrJ&V1JtC!p~gr$+2c!_Y)B@U`qqU_y6sY|)b(E1FGDOm~JYb zu`}vgMsj?B$HOTU!~3#nfUo9sLa)5oJ{xje?8DvH_a4`Vn7^86ZnpFoqfS9S1dk{%$F?(zW}45JzvFxp>m{SKi~p6*oDXPY=P|f z_(2m5n~ob-`Ptz(Afvyz`{MPl4?#vh#s7YNlZz|+MS#k$y<=?ef9~u`*gX*k?A^#Z zKu!F9CPGB@+YR5IJJlD1F)r7PRxd6|(wHC)2}tth_tW+s?&I}ZvySioKIvKQw2*|P z%f|Mf-qn1Fl1@yT(Ur&KY>;k%C3zR|oy~8Eyt2nEy#o~ot$7Og#_<;EF1a)mu9Kzp zpiZ2onAOA}5J#hhgLPdyO24>h$f7P?MxJV7W7`@H!GlD2nlh_L}{2FW&sGm zW)x449wYd)8zGh0%RXxF&)EU6ODjm2e(pjKqEfP1V`74zoMku%NQ2?2w6wANFb9k+Lxb)}P7$-IK$L|DjQsx4<`Be%01c)&Vd6s#e#Jo#BIfY`Rc{gA zs>wg0O?*dP3V$Lk0qsLzrfMU?@~CutOWl9FUrTT;b=>K>i- zju9R_gcXf}=U`wVy@;L{oE9xZCD6i|m)o=QrL9Ij1icr}n52Y+|4~IRn@YyA*kONk zbV-YeD55ZZBH03bo5x3eqLF`OA>av^{*Hagm5eJ}YQo$*4c zsjc!Eso6=BGU`L*N~y8F3S5iL|x0o3ssvXl9@UYH0=a=H?58+T*>t8$ny1=0w(D!6yR0bcKEn6Z~C-KC3>1UVJx%*D;@$^ZPf+2W$2~Zv|ceR9~ViKJ}I584lZ8l;*IG`cbbF?%6(r6@xo0>h} z{N_IpENXY+T1BA1`H;S_1s-LpKi_U>>u~)H=z!9k`9{0Om{ZjoEE5tx*Y>w@_xcWpJ z-V&ek+^3(yb>;^@e!cLT4p_e>j8Ic5HBm&&iRqO&a|v%qcf+H@{xKuz{JxIjrpRoT z(N^N@Hq-RxqLg!rT+Leb6>HQ>YGq_FlcJQ+3M*9B5eHNY7N<2iSvj78Tnx%l1}w}f zT+!rf7n1nKSd}~$>q#)$EDk=~87s?ffCyNn5Q7vX*(C-wfRVx?9uXT0)~bIH4pez$ z5h^l@)abh&XdDR+Y8OBTp!e5F3RGrg^A7W^RT&@wT*RK_YGJe$$f@N@b+smKYLk}zE{2t}Vc*%r*fVRvZZKm?LLOvKa;CfmRz0L+aKf}JmV9qn zW~?92&^*?%e{UTY?9uv7gf@FZgHj^(v~oeV%UPMMT;fKS`Cb|}bO0mBbOFc(V!qm!dqhYZ!aKProq(DLVTDkdR~wcnguIxg4BtG#Jr1f(TLBUiYb%e08yd=Gr=k9}BzkF`(W*b$8OxWUN!9HYe_!&BgmnoRIzSwg- zsR1pDYewtXGbJHC@~{Rfy_S*qTz;X5WG}LzlZi+Zgg5k&U`tHOaccPZM#r&S^B)24 zy0_%&Mkhh~+PioL28)9dT2L5x@$?-G{~ zWdeu@)7DOk&j>8BnD{2pDKX+Do02c8ISc|ct;K@XIEP9K6a7_Msd`M#)IWud4f4J9 zUMvavF)AFH5g9#`?P}kG^-cXhG@j|%)eZn}TFq=C@IZ)~HV?_BWvFYt^sU?ycd9EUnXcvy&`doDHZbEt7T{1HvMIZ!3pjD4cQ` zO~A}%+7k&}ND%392e1BO@c@ zl#!9WF0Xz9O$0?1U55-GLf+xALQ;A`W=V+E4zuaX2_5ubO`58T2mO#|{JzO4!pa)* zIr+oGY@rDby=jwtJ_9d-`i)vll-@k@W6{zHds2-__&meJn~cI_AP$%)N1j3?>!kcF z%p!WIRlJ5uK1KP44KiaYhJzl*xilVG=Fb} z@$i7;Z@&rcrXTk~HcEcTFTG=2C4Q!hrgP@jBl{d>I}-=g=08pFknP}k;@b|3BcdX zkApGgLkX+hgX*dsY%oT}N}1tUbD@%rCQ5A>!B1&GiMkgtGSDtU{a2XPh|Ei<{+LqE zg;9o{%4QBIE-uMJ!SNnkVCEWHBr7sn4sqhyVonI_O4tdI0YsJ;Z=LvswNfKIACdC2 z=yTQ!bHzV!uDEt-VN}RrY6Lob1z*-4Wz_OD2AtLr>FnM^OLdsj z63HjuBt6g=obZ@`67X03W_YEOo+CB^oypDHo2MKAOS>bpE77XlGX+q5|a* zHAfm7Q#txH6Cvth!egrxbE9^P_CwlA9z1vM!u}~76_DE|A|rZ|ebXwwc)zfQq>>pV zt&zbO@E8&It2MrWoyqg%U}^0f zMLKGJnE0IggGOD@Fbx}xDX^(bg1BDq@hU|yC7({qLR5W9H;;8oXp=#fY1xu{u*>d- zwk3bcgql?QEVcpero_D?Tp{fFD(cDtY*6PCw?9Ui5b~fZQ8EPv%Ov%L3TU01N;RU`GK`^GBx^v)lF}iPkAg)% z#Ra9n%JqnSZ4bxNCRAQ7Eb`7!E!d=Wf|Z=LaOshLFA29*4Rr53C54ScdbWclNe?QF z#6V)bg^!dZu07K+L&mpwK$1ey#8NtZ%|qfEqX=^#LDYDY5=2O)bx5Vz+afduW>s~B zOjR`vstCXoVm0_~WIR3;%|RL%P)dV30qr12oe}{=FdGRQ?v=?_k{^KbE^f%oG2Bgb{P!B@kI5r@{y3?=pPf;#ukeCyd`iJ>^29bn(8whr} zaX4)g=!0`#t_KZ{P$oIkQ_^*!=9j%Mxe$vTdJP0DKEyZuR%Dy3B7U!Qw`;8RB&k#< z;8-QBf`fb?W@+$FDOlsllMXM)`%ZWOLJL{honstiLu3%vDyPtG&@eIuPBXM)`=||y z=xDd}-}2;--t{aJdT-T-%7V7G!kVk0?|WP5{4#V9=Gv&aD3{jvbU%^H3~hIAgN) z-_kH0;)P-+%h)r+boTGl-=Iv~1nbZll}1tl=PYm^Bnp&5MjSE-Y_->fR}vcMpTQ*y zC+y2JrH5lgGNeTUA^Ng;st%7avo!1KGE=5r!(^DTRgGi#k`TTf&aaDM&Xj(Vk_V28 z{!JpmU6l)|sI4n;H9``wg|ihu6B3d0p%zoI36~ZIehj=p3E`I&jVgO~aMg~Fq-WV? za|nFEMuz7oM;zhSc&N^BPyy($(Gfc40dICW&|!tX)E2A>Y?%Y5HywOD*#5PiYgc7u zQb~VN*#rt+l?G47II;c`3p+oiZWkRcEe(tT(?J#CV-Ov|N44W$@AjTaWz>B1rbY+g z59}SFeZ_<$VJHOVa0Gx`DMnT+d=qUe<)3Q$ zs*J1&w7Ra->|2OF&9KpB40xBd`KTbR)(C3tPa|omdw}B)tnn5!Ja%cLQb3XvZo)he zd(V-9e1T>??`uJ^L<-YtF3HpQq33#_c7!dla_I<~+-R@5FQ*}LMJE4RFrgyk8RJ)| z5P>h`U|SbhDtnavW3AW9S=ZHdV{10D$yL@ZFw`|RYU##q29~d<#3-|>CC5R^K!Y*K zH08qrTVe=`VVeruDlm*0mK6U4GM8DInvJXWY{lwmHqX1eB9AK3b)HED>9*S7rVcD< z2qRO}f?-_Re@Egd(81B57u|m%Lf*nTckqK$E9R`BabcPAG9*b!Km(Yhj0+?DDitqe z^mMst{>!2AE(@(4wlPkrtt+Oyl-!-4dnAzL7Ziz_2@x#;;@8WJKKuBz7!ZCl+32)*HhKASU*tVWDt(kg>(sE9L2`Fbc9>= zH!}yXJKuB;zn;JUXzr0XGjW#0+KcouilhY7Ae5%Hnz5s14(J;u?`uw8Ag7iLCdIuY zEOZpSk~t#m(4jtevk7lNtsrKkt`ZZpWO-m&(x;h5mVu{HQUBjc@4h#M(`G3D z0D`Wa^O5kJ>#?Xml@%E%;ZN?6NEFYQiO*{|$<$#J>WoauFNN;@T*i+#A-JS!PWaVg zfO?Wrni7oZHPv6tD$Zv@ak0wHgS~Jr_=z=FTvVy5;x0?Iy?IS5q`b69H%MU0X;lf{jn5 zI%Y{w&Sbm})Vm<-8$G8VBT4o<#+3Sv$vA78NY6!O#%>P4SEcb&V(1E+S(H5}3^8t! zV(2+A33@6zwwlSzv=*?*D3!zISHCC%E1M#YV^o=;a$Qo-YEhE6 zKi9Pc!S1y{t9BnjClU3wVM742<>MR2ac_hDZ0J5Q({Q9K7%GZe?@NZnU)$8tsvC0?M3sg zqLCznh1+V!Jvn52s&*0v{xM)&9xns+Oa=svixVCikTirYsu@KDL*uZAZFJxdtILLtFSTM;zNV^CK;9xl+Yd{7yO zS3s&5m~TzsmKEu+VMxPXQjaIP{nVoN7NHa@7Gyy~{FeGL~zAsCQQkx|l)sjer z;-Gz(U4^TW?K)C~%)PW!rcf?NN+aP645PBnmy@xA$WAxgpiox%XZ7rqDHIaAsQ)xi zS(aCuoGzTL45G_HSxKiEEA@mPd&WSX(XiT;>J^gBg? z+n};cTAga#RFAJDOCVJn9?Fz8DIOSy#QurlrAA@Hlo1Lzwys4T9Vd8`&p%5&>^lXD56I2FIBgEeha`KQZV}XSfl8HOf{2$%YWbuTXvW)kBeDn% zftGFA`kHVsPT*hx(!fc=RoP05Z?~`eG2QQ7<(|7|W?=0G-B|-yaySRU zQu?M~Gv~JgRBphWus{t?mBxYE6L#c+I~C~3mu2~`Nv0y7!|8R5tE?Wl`Tm-!UiR)| z$CiSEEqT6>y4f)&$j7b4ma4sR!yIg=szEUcI~&qnNEQSckd3sol=<@!0zU@-V`16? zAV|jMbQZ&74vvp?7Bcztyn_o9HN^|I*9y1Cc@a2s1CakFNfR>CBq4yk=9k&%G?M+b|uH$BiJhm*5G6flT-;j|$DO};#Rdy0FKaNsE7HbO4!Nr6FlR}A;J z5hXwE^hIN`b`DS%t3DZ;B(GBZ%SlBzD=;ddWM#C7hbuK%_5-;y=}=hK?-c1RJ?wrX zvw;^pB?}-GPPT_?qso9NP4(juQl~<1XG=a1jgBZp2l*2ujBcrzQTA0`%?6`8G#-DV zI#<8brE9E!H2KA$U8v-$lcLU+sWun2J6t@;xofvhxT8s|0~oRsfuwFN-AP7HYz7k{ zUqK*T1vhGPuM51Euq^ps-2fQE%f_<0;QNs{J5Vf0OD!r&Yz8DbWnCBNUY&L#&1f(VRe zT!PLFiblc;bxprui8bwutV9Nswtj8Ug#6~4Hin2k46Jtv^sw)cRgjF5jgz)GcUSI1 zdeKE4?G7Zfv)xrJvnv8q%GHsJK~8NmxnZJ4i-P<94y}090Y=nB)*!c>qv6D?mDek9{aYR?zX+o!LQOLa3EV*aY|M$N&e^tI=2&etvxcjR=yJ4U%@RHZ@P zf9$ZWqk7VHJ?{DIz#KI#pVH}`zd@&akjNvaW-%z}H53**|4{68yTx-{7Ia-%b#1_- zCh1dp^6YQud`jig+{LMM^)ubLdNB4aZVTN{Er;u{=M0c@+-9PGF z-^-uBDfpvi?Nhq_^Ec=A+rp|N{>bTjfV2c&*{kQ3Z^Vwc2FOv9^eH|5`J40j2T43~ zULF=3lPAS;vDa>$VLc6aIlL#;tF)XWL8U*_X`dg>us+M1^ONJ*-qFFr;=&kfrH!Wblo1FJ8^g6VQ#+H`&460^Zk1d?_GMDKOqJq<{OxNI4!aBRymCl0X$&$rgbt+K`@O|Q`4GE zH$8Xxb^kAb*(gT&lmV@Un+s^sugE5R6q78@J8xKhAk>m;A0zjFh=($YWuOkOBq#ny za2de}!0FRTjK!Oa@z{c|o753(aSypX8@ybeB?5P)SZ%Q;d8-5R;}R!Rt_yYeR1x|o zn<{j6VLXVuFd2xL1zh$?jf^@uGHn>jhd8CxPCB*8=I68F-A_ug5>5s zMd6Kit?Q+z-kZA$tWneO31gxdz>Q4aO?;*iRjsbkf zo074iBQdlP`MjQnzX8yrCg~G~JVB}(6J_-zAGLh2f4SK{f7k839Y2HS53 zf+K*_r!)L+a36NWq>f;V3q9rNXWFi_Y_9}r_@vkYup6HkJs`KjBcnJO7Sw!llQPa% z>Jhu{!NEljx#51^Eglv9S2%IHfm`6^;Ns6x)Q45s5m4cU$~aqJx*B80f;KomjWeZs z%d$palhpdGK=Q`4Di;*e3w9Pzfqntu62Vz|+layVmM|fOxPsFJ3<1+wfN}aF2W^zT17a zytC%-c5w|Tvu|Q9k0MfWB6Xb8fYX_~_5GU;D~)i+6!RAW2j1fVeiK}O6Rg6EC+w{5 zShoPIJJfyLM$2;ue_Qg&!CqMzLm?|OkT&tODoR$APV;BSrDKHzqGfyp2zGkf zD+LqeUblFpx~`^z9Gd2FS2_Gz)5yAzPXez?BR_3D>Xf#97aC7^!{lu47dLTCJE^{4 zl)^vp+;`m>Z57^z6lXD>RStzO#y_H6KG}#%(oyQ6(?_}41IWoCg%ye?ILPnLqE_KY zEh#ie3a{J_=-y@mG4?ktRS#~ ztM&qriSX0<#i^9do7G!Scv_tASd0R73Qkc8IMze~&bR}h*TFeBBpq%04=7@?kBSDx zS94Tq?f3123no)wmEuC9-ksuc{`?r>5-CqwF~y<0nbaHu=Qy7DF?7s&CaE}EwTZ=H z`-Fi~#I5p(0IjBs)#(yK;$n+lABW9QHdTKFO{5}((T39?rM$xRR9-A{H{5f1iW)OD zZ0vl9Lb#YC4lMQ*N@`(%`Pt}ayl92hOAZfNB#vdC91wq(xf*shdJM+?1G^~cSu!Vz zXm}X2Kh7EeM>#WSX$83-DqjawDKe8z`e^;}!>qu5TxG}y27_E2pjfZB8=?+W%%cby zSt2hu@$cp8GgMx#v7SU$2302Im8^rGytacWi}V$At<0+4i@ z1Hfj>jt;wAQ_^s{ywKb7%9`Ku&4Nf`weV94SpGLIQgffngJG5kZ>Pw7P9@sm`Q zz%)UzFc!~yxwk(3&`apS5JkXid3R-F!yna=v%ZKn4hjB>t449#iq_>j?jp4ojy1}l z75DEN^l)`Zzd$kV!_(HxnKi>Lh}|aJXkqQ*$*`VyuiO=S(q@dU<2RcD$f#`Y8z-&z#j&20 z!ZgJRnyOkHDUS?a50O`m-9`Jd*e>p>Ddv~#N^DqOT2oCf1Y>1#BeC=Z=B8<;+z*-> z_Zvi8BVNE4T+DlLiU-uk((Js4fyE{H75LBpJr;yRxwbcm1s)hL}W@@h(#R`f7R-}A9YTfzrz7Z)m9G2(rE zw6qjW0KMtSZ%7xplwYqH%Dpv^WSL8hR8qu_2YDqC7{dl}f2mMup|Zzy6$Vmfoij7O znkB`QanOS$ruClj;?0O$1+Yj9Tq_*b3_f&LeCWjOqoh$JYu)l2Tz#@AhLg4=CaV~t zEE985W}5I#8^JH!v(1f;P*%}Y7gvtl+aKciHk#bLEqXgZU-PYJ^>-9HBRzKx+ z`@P&_O4)YQf>=WAJ;W!(k{0o*V5+3GzA-vUJ;x2-vJpusNKF&JaD7M!PLxfP0l_Jv z*kCsxdS2_DR*lKo#y3l^{{G|pxw+{d-#=LYX=*m1pahfW%O(Z+2g(>EG~&?;hK)|Q z3YuSB2#T>twe#*_H|B^z{9`6Vu~}XU3*Td2B2uItl7ulq_a5@TR@(U^iDhUQUanQy zm;u6CA`OVzlt_W)$F-)4mn*x|(5CQy&bo|qhA@(hBHYFtg0(1|zqABW9wUU?v>P~@ zEN9(3J2=-h44iLL+SzHD^Ja+>nr)=j`F4QB*jZ&Q zr3|f*v4y~7Ep0E(j~>EKk-ar-(wGqVW+n$zN)a`R7gk->h%k4A_CH`LnSg?Dp=E4J zUg3#!BL~7n?&7{;W~Q(zFruRV>sKPc&^USc<(F=6>)kA0)3Ez;tOif#{aTAeg9m{y?+R$!5doir;q#w#s0B@hWm}d)hK!`{lQA- z3*f}_>guZTLAu?2ow2gh=%D`WR=kwt4mh$mtSJZ#x()ltCld< z%{Yr#meIx$ZU>^tY_y}%j9Wg{C9#!FMP{!>DM3j0x(C>gk*_2>1TDgZniNP@AlDuD zQ&S-@%FnnNBHEm1GUqqkPn#gOsLQJ{J)KbYFU9?A8iE9zo)!)lV@;%;@H^zuCL(IM zWgVxUVd!AiPJ&>B6#(nN2q>Q;P!xGy!pBJnHI>A|{u_}g#EhYQsoR(!cw_2oML zII_6>w2w#y^$F54aQ+uRTpaYtf>C2r%LtEPXn{HPA@IWXdXVB2^nkt=BnW;E_{Yy4 zb7bqQt8IV(~?SA{>u!~Q@PLe#etKsG1{>&of3Sh9rC}LG| zHOcMIZ^NKPrU_yd;m!y)R@=7Tq}w`;kr`fg?EFg$SuYqW8mGJn0N03}!Jo6(l>3KM z9-s{L;R!Jb#ea{%at}OjhGvKDW4WS$d^{0;39t7% zkogfXf8~evSi=K@;J-y&JAj}Ww~znCg^`2?F<)DK#EgYolu5aq`H75^eaNldYzW;3 z3BaA2<8Jqi<2~q}$^8)F5+)-EK)_mM4g@cfGKYisE28zrHV2^T?G;~jTm#U?a7M&o1zi^UT-yxTjLsRMo^A*a!T`ZLRDE&%pS^=oH#Y@X@Pe z_S?tZcg{uy*+@)mVyA0Ll0Y>}z*iKaMBSqE8uyuU@-U@Xd$^(j&#@Q4 z*KQFDB|*7~QzzVbQZkGr7=GbNX;ISvum8#An>kg+tF0| zlEwq9)5L|8xT(~eO1FL31f@q4WbX-FM-QHU6`1-bmQzJ}%y zSx~@0U;=N%6@YI|uz`5q&HkItQJI!tRP1!0o*y+PMXw~_Af2&C!QCG4@fZC`MDDhq zZ8z7pp5Fm+vDDr-CQf*1qNC<=Q2+h1Xq*(&1(@?MMdJ3PMLKPfh3u!G0~oznxj8P zJ~S4RevO7~SypP?VE$_X+Py8ltbWTyr#K2@Q!$@|tGQg?7BJ&QTYmgf9wO%)$x!w+ zd>`&P$#>v+`Hr8p-pl1QZ^1+I3~3IUgRa9?It%EAs^TvPu;!Mx=Zy%dh*f!L{74i9 zz7So3e}hnd%VjtO{_@|(fWQ2=D)=T^IfFzCl*MAC8bTWxVYdBJFnsPo@0SF8vg(mfOUf6(+y!C{wl^h5!Ek& ztbUBHfiph;!Z+oj86+tQ@>cZ?n@4S}lOW(E5(u@_Q0OKi@Hq`S^0wo2*!eZV$tWP) z582c0HAo3XXLbZSN>^-iC=e0r=x`K;{-K|b8pc1u5I6$iUC8Xi*4cSOmMw1SqAa|F zBy)JjZwdq!VD1$A-x!&5!%`dS`i26xrZfy8IwtnBzEt!={u!d-cNYv%g1xa%#7Yu+ zI60IW_M83^n<+%5hl*XKXqjA_IOPw3rEN3sN=XZzOg*cZeqbC3Nrn6fo;sr2^eY(E z4M+M3>Q;=GtTd26Gt`&zc#fjc&`bn-*p!EZ4iTgHwjNex{g|rO5W?K_qGc52ZqP2G z_OKqpxUdv)oQUO9B<~ioTDo($s5XQyUzJymNEDdcPq@CT%}u;r=8iCo=zg(L@J>7M zVKi;cT~tFDdss--e%*yE0Al-yZeR4;xLQs{ub=?YGgmNxpuasX7VnuL8fv}v-AeJm zmNwUGy5whA7rK3(O#@9>eNFL3XU*zu#Dd9qc$w>3Y&0(PtF!6-nQTK# zxrMW*jWJ_@3sDojhqpG&Pvazt$CT=8m1c&Z>mBdZx3?vB9Rn>=s z6RBv6-^Z_)C=;Nm!V|T3C>&it>Aw{4hpm${=djSgSSq;YD(~%Add1wJkE)01XQFgO zdP%6Py0ZoJB(Fc>hv@m2z%N8tgJ7UDBl2PNl;nmU%%u`M8kjnRD!d7lHkU*nO?5;$I#5KjbT*LqNafa3m7C@NUgXD+EU(S!%}4;X-q4ZDJF&zfDS%~fm6&DN&HJ#^lgGnluuE4LgPczK~hP1`O#*K`))XgNYj7BMJ zQw#(1ZTp>AL)Mz+uubo!XzhI{kC4I;H4=mxG-8=>X_wjOXEs*k8c0ZHiHzXbi*Ay4 z3pv#-0mhB(U+?ow2UHBscwQwtI37&8YIl3oF7KdjaIObwa>%4c!WP^yRCpz(gYeadWOcwe~Q0U&zqcQ_}6D`c;f^gNhoOiDovc!u#y zBpsh17lL$?#D#>CLCP~b;qC&n6Bw%K7azJ8)Rf*5KfvS0aV45E|7`bg&ZpDHRuSDW znNp4i+$k%m3L2m{gv=cnlL zB`83Pn?beq9uoH$+2+Oi`rQ1|(mbm66vgyo`+aUH{tvGN(~#O*;Pdbco5XMVlYA{L zp6LB%#qx3cJun73FWS9-7GJge_n8y?{^VVIf9A0LIBNpgj)=xv+&T}ko%e9R?LOok zLcPb?XaCXdzbUqv#PiiJCujWn7d!#|-pbb~D`{XEVFDw*IWHFG<`$>%*F6v&T=;Ce zc-re;K>L8rp5Q_Rgw3@?<qjEN2<*<*8`JiGz8(BV_ywhh!44zbU5YizOI~ zdDnn7iLTkl#KD5K!oR~?EqE(5lL1+B9d$Mns;nU!xh=nB=CSwA1CZt#NDMLtlEn{BM>(X54RdTdIbQ#~JdQFBaoB|V2 zhKG4X_;6s5_jQo+_vJgy*f4h!|K$a7ShL*X3o>6MNg{Nq8$`i zngn@U7PkI^au{+s^znoqb0QyLn^M4CRX~NIUPe55qbQuZT6N(c^Pn%oo>$_`v z&6VZty_Y*{9(^>kpXY2qHl*!fB&-e~zsJox1I3ZTrc%fzx?H+qQv-o}V##q~JB6VA z8|*)bdx52&e<%Hfo~`{n!stLpqpA`P;*18OQBJCkaB`<_Ra0U37>p3%y$MC5X8d;k zC&{Ow>iNk2Opt{0FQ%`w-ym6|-xmc>K#h1qeWX%om#j5l3eqO&ip{FZ9kY)g?!x+_ z?FeI4l6!HO7hD=vWR2Mv+6X)t_lPSXuTMD~yu|d`vIU{%a=3!9cYb=<>Q(k1dXDlY z6E%x7^E3A!&Mb;#a5<7%b4-_6nqPP{Gk^E)%)Nz~#fJgpRRjrgG01{p?@c8D4Ddh# zcn2Iejyr;)uQ0>*NkUosgoq4{Xq07wFiCDo)L9a`j==0a{N(17nlR*K$QdFT_*lP~ zQ=Sz@ldtYpeI;vDcf=yg+PTsI8IbU^wy$U0&Mh`|c41B$r3$c3ewn_R#O+sM4t5cyQ+?4(GzEP9LY@N0c zl>B3g=7?74Jj15(seOCD@>?_! z$rc4UNgyJeKL~%hh=vl{qd2g{ql4DzBsL-1g&eFFaZDsR4(DDoz@>*EJ;V8G3PNcH zz?;}C0zf870wQ;Pu}hDn+7QmBstb0yXo%1cRf&&dcrQEc6M)Y3bkUF?HF&b$IznP` z`=G@`1r{%8?V|zg8vIEIRvhE#;Yl)9ERZ={zUmPK?1CF&RLH=f5fws830X6;UNpHB zh)EPianNU97uZzC)_Q_~3I*xg_uS=Mb;uxS&btUCv=Mj?m`zD|T_Jj~U4LUf9tE?{ zyeqzJ>I7^2m2;-?V3?1LvFODY`Zpar|HRW!_-sI>2TF)QES2rS5ew=Vq(sc(KV*!dyjgD+89XQY z(9#3!LKP&P|MA9_S=2loweKKAjsLExfc5`cs;1m-?Ma=j0dqzgMsqJ~)I{1;PNAouiJP_lG`4g40>Mhg2M9F(UO@5BcI)ukM0q)(-0tK)dVZZqOrWgqYTnkrY64 z)WlRaoMdnM@u9Xl0_y991uNpgUnaNXYLR^{Ug$WqMjll?HN>~R*PtXBq$ey zJ(8Z2sRA8zo6w~&bTHb(3zSqMz&`{dP7Q${b`LI?XA){G=pexYvzQx6geYL53)lAJ zB*^4R`()aaQEs*|tB~3JL=MTD_}rDFXxp83fy-J>kOvh%k(r_0OIuAisoP^5*~or^ zy427F;40Z7#KtdPLoD}*)Cr1M@L$jj01)(pWr0!+cmWJ3$-77A@4y-noN-+!3xU?C z231&~SNX2b^0Gdty=NP{#qQSn-uKHpYXyGZ-r4$YV|8t{`1Xfl@7Y?hvbFug&c@Sc zd&RS@=c{WwyT$V6DxPlc?QDGea&HR{ZlnCb#_nxm!FS7>KNM?!gR8Z>TWswV8!xt> zZvY-T*je7(+gRJZQ*3OmJb$^mvHA2)0T{*R)?V>^x?JDb+hlj^=x@2$Uf$W;Sb6yzLGkUEJKI~k0*&Ka-Pm1uzP#~b zZFL4XpxbE-i&yvEPpzTDj) z35D*Pduuy8FSqwLwl=3Q?cak)JH^T}T61<+i>*zWWK7f6&JTo3V#sXVDZYQUhUb{} zO&cD{YmhJ~v$3(lX%1haSFq1sGT35s?dkK4r)!%lYs6`bfWF_@U7I4P<(&}WT z4*Px?J%e}9J3iyc^v8sqL2k@$v9Vq(uYLzGKwLg1G;qc4hH(&{?!H`kX4LnU0qgwW zEizCcX>lU05APGr>Z;Eb9-l939cg5-`;zjJS5YFH>Y95rmgbVi*9ft5EXUjx;KeZr z&%b#+^SVz(iPCB_2qDdOdYxHxBK<%FL1Q8NO>Gm{BfU;R{rs*y3B|9_0l12S-{7KBmu^I9wh0M*Wp!Wi5w#v*~I=$pm5xMO5wpo$ch;W->~m_HLH z4?H{@fpGQUf*c(YY@G4Hb;9x(gec59CK%!CK@eo!@gNAN4+0R@8xMkVsh;PFWa$XY zj0r*6s{#w3@iF1}=ZN%Z6g}dD7ziE2e`;WtC8n9o5a6!0P_P&W9~j@FovqV-N0Zvs z^~D?R{`Yz?p2cLBgm<<ZS5B0!Vo@^bo&L&w8PveL5sV6y!^6dVDyLd2lhaVnx4)kHwhYR-?5DT_1u|3!> zgA^u|hm*%$)X^iOO@3fDwR=B`9Q8XC;-y#+cv z(~nVNxC!G!3QeYa3tNb!9d}`DG@B@|j;7dCfXJY0U9=A5aPhCWIoOmrD+Z%`VUZ`8 z_N26vcy-%u?|7XJ-|RbK{V5N?gs+6TYR5x-CI|@8Q~6TI#c+~lsWjW~;cX&1&LJYe zh6YXU4of57p33VdHY{RY*&_7AsFFu@*d2bo1-Db+YPhZwY#B0?oMRONNJ>Evj8*TP z3CnG$C#${}xl;AQ1qI((_-d@N>c*E-c76)!u0~!Pb`5)ggZ=>aFfJATsO1E9t&=JN zL4<>~*yM6@89W0J8zYi53(>0qKY&2JNeqn+}8h@Sc_EJ};374nqI6_chYT7yM1DC&Phzgtg+wNW|f1sVI-kzySZ%bC_`WE<2Wt+j7tER zb8CjQV7ikjDUf(V66#@$vy4V-AI)*E0FE5O4wS2IXru!`%#<}-3(tO2Dj0~yvNfK< zeT|5ITd!_)rQZk4c1kFQR8W2`+g3RV%asufUsTt_;Y4%_Iqk5On&hF+C~J%qRoCF4 zuOQdMhnNza74fKH6W>HABHL(_3G@Jb`Y}q%!8q(3HXNR<=yU@v2>qm;sfN<^BG&i- zWi;DyTq>Hpa~(D|Oqlm_fX%WDWk*BjxN1lwS~eW{6xaT!vZ4to+>9N|&+OG0gEZ`t z5mFA3oppydHP7Jje}`I~-F zCbUGtNUJav%FXFy@EhhQi64QWns0!|0eYyS+)DdY!lhOYxeb#TVl_TlGLiOjaEA3o zX?B^qY%OFgg5)q95f-GOm+%tX)nUrCGdQ6dXOl!`&3#I`gp&uNC_~EvA3`9v>$2v| zkjnaz6F1}Fc-5H*+#V***&he`kvoF2H(}ItB4p`c!bmBR67(a&Q;#yGG?iycR0_y6 z86j<|QW98Lu^8$7#NPSvaoeb&c; ztSVU;wec57dNqrzb8)I%lZO~^2p1uE(?@wvw|0cP%`Sp(!px;!=T33^M-=2j5!Ofe zZyEos;J?+|!j=;_8l}ZrLByC}jNIbCHyYn;f2D(Z{Oa#ZKhA#h`A=U?ElqvX_;L0} z6n5SIDhw6x<@H~t@D?vPay&zWzf3iLlt)4bJmVvL^f^Cssyv?IvkA>yCc>KjD+sEg z5U?~h9(p!-a;0@jlT3(%4B;~*-oo&NA%aZ2Nl;`4DQNhBS#SNeWap`+C=)EENytCW z)4J^Oq*7&)+1@En39jZPXae*i5}=u~q_qzJroU8Uu-k8MKEr(0qCa0Q$lbs+881sMw9&V63Uqli9j07jl!}Ca~qVm^s5w|GC}L80OZCcYDxwN=MzA~R5(sJ2-&R4ShTn( z9aQ~-b}N^rT_oNh_5L{W+4hPtFOqtBs=>`mZoMG4%w_@0-~b7W@ZdQW4X{S*^uv_r zi(zj@>-|;pxzn-C>$8_<_E4r~@OX-%0I>nBgPv5Bgoj{&isj-{s52Xc!{F53P`_Y~ z)oSKo?1fu3xO@@kr$yYDumMN-8sSU@!GmqZv80SsKOO5Z$(Rg2XX~{kq?;meL!qE4 z3F$(vTA$oj;MYh!#E=5!C3d-krU%Ct!d)tGq(-E0T1Z|GJZDhIo?tN>65tCZ;UK@4>VB9Fa&zoMwrd?-!90~V?AeJaCCg!=46rnq4;w~NYXu>0 zD+I+5-R%?wC=ErR$r_bVxYq-{hrMYw9oh^%5$w-+2eQHUmBE4O>9v~dqhEZ-$W@#o z4G2ONbS_SLhKm{1ELX-I`5}Kg$W{H7LDXPR_m7<`fTEgeZ-)6N*YpoxSZ3B(E zAHXgufJvSV7{7UUV6Vi32eWQkb_0B)K2nUq{kU%+)@;>7CD63UI_@G9cmJ5e!g_HR z1c$if+5&Eb@-kCB>G;K~<>~d-^byZdeq8unPde&G@SlC}*o?Y_@J*X{ySC(Tk{hKu zt&p|o8#tFa$5|zC5H(CSjzH~;#y6jpP@^X^`NhIL`WB_WmJbhcmNu{jMZ^~rK`DL7 z0n~KJ(?hk&(uoz&M6s@>D~uVGWYV)FQwTjvRn5SuSlN@y->#rI^wVb>|M8#CUu6zyL`T{anao9vxHd`X;ShbufD3JTDUYk3&Ko{pxtXwgM z)j?)=!Vt(?U^=!C7z`0FSTKs?2#`uJISUkM8O-tIS_YOCJn!|-!UatOOzRy$_I)K2 z1E41R>`;l_)1duSUeq9ESIN7ADzGGD=o!9H)m*4U#`^XHveq@(27AVa-8U3-AV;th*K9Dg%?CAD-o!E9H3eFKf{v^M*{uWo>J%`Vu8s!~!@3Msw* z(0rTs|8rM21nvm?AK)`^>*(t|$Pk=&MA1%g_ywxWwYxlZ#zl^=!$WCJ3aPjjq*yZ` z__rvA!JwRh!_V=B!v=Orz!3{bxphU#GK-X;pp#2JAm(I6m>r4IHasL~ydDIxTybF| zOgWoZB8WdKH>9ZRgU_VauwIRFxoZl{Pf~O@SU;L_*er`1xzr(vVxkuzpNNBG!ui-q zZ5Ji*(^7FxK2opF{w7a*m^-wGps`6taSgp`rMgow)o50UT-i>ICWbrh_5ioBn5iSS zYkG$O8IA2Jm^SR{AYXOjtKIrc`P)Cb%w-P@me@jgj3cnz%n01UDzX2*?17Xg=|94ndEwnCup$C}^^Wsuq$*CLJhnFa_?HX)h&rY{iWCB1Bx7*C$&HW&1v6 zNbE?I5*Dwx%dB*UD1)2hep^IhWCD^_$@ApX^Bg~uhdP_7_#^f7Nak= zS8z^F0@M0Q=1IAyz%vAVJv6eM^jLO6tUij)FZgd6q1<-y3(u^+X(4(cTr@E5NECd` zQ}oin%4%Uc07wF2dWirvt42Uh+Frkn&vZbr$aUBaGV#e-INYQ@gOWHYV(A|NJBU*rj;F?)GC9>6AE%x@W(ZKxUo*;4H2t$aFS4$fD!w>%FD_7OfAR!hPniU zAQ>YkR-jdLOI;;mRoB$jBUZYnF2T$$s>|8f&ZCwEh?pVRua?~`?6Ey*F0+-)h)9Ij9n=($N z%Mll!Yy6asH9kmegaBcFQ5x{Z;=e)f!%qll%mM-gshOs0uQ3^j-1>NBN`n8Ok_#FQ zd6&qG(^3i=X%}JULS4j}BLZ2=E2rE6vNXDgUdtknK~ zK@I4V=}q%G-qdEK2@TDF2e7ejxhun_PdD-Ii#kVN(T{TV(BrNFt zd1Y*X%;KZ6+lhyFQ7@5ya*~lS_m(R@zhC?LgR0LTtkpq(aJl>RM&0EXl(ZT&6)sAr z?V3TgI%#d z5lUR#;_Qi?&Fu-n5VfL?Q2B-Rs9`v-ox->dX3Wve5z~C+aq;r@DOw8QI#@~iYL1rWzmAJnfRG|)Fw7ex=MHe3q^k=z ziF2w4r#zq5){*mu?C>+~MVz}za3k2x^4>D;m1mb=-2fvSsX@8cB*Z+r3_*W<2^_r% zr!+&;U%+ck5*jHny+VPS&zL9rpmxeRL|>RWrG`6_EUg6nX}itB@=}u*hd9v)fd&|X z5?0~PE=|#X7nMyQE>2&gK-3$#I~NuRY(H+nOT{s*RfRx}6y{>*?1DhD_{@-#U-8t1 zjCrEd5BZiDt}{_}X1z%=S>K*XE%|!-LROeR|EtS;Yb0#Rmy?r_iWFvQU}gv;;*#I< z(10{S%Do;lwMH%oRcgzW%jpsYd<&*&IxK$*O^gkMZ1G@Y+RL|V#-e{4viuVC@v$eR z>Bry5t&ObBUJLoFns-cYA`x!M-~7vX&=gkK_((&GR-7+o#9hQ-$OiE^{tUu$dVZLn zlWqDJa^{`)>v1y#PmXZWAnqQL3>~ya%`j$TP|ec@a8(~oR>qB-#Y&l`r3~$q^D4A# zdKgXk51toF&%v&yL*zX3nf~glQr>|%HM>FV8KH`p6G&hV^PiK@s3pE}B2fhzB1%2P zl&pc)G}W0_mXc)8TLa6X^q31Ff5at_KN0C(dL&}7^vq?BKUO}#KAzD=F(!pVpjkiR zBO%8GW`>31!YY>EB^^GNk;Je;Ks13JmY<+zp#dE{_BsX9tB~0(Od1y_KMhhNejOe` zpc2o#0T*=qmcLbgCbWs)xgHsW=LC!2`V+v_AtqBD*vBMXI?X_}W~S3Oak7)AalVs> z$&{y0lUYw6JJve!^2X+#Gi$SCvxO&Bi(dzGrG?K$uZ#bZ3t#)J)jHK{-}y`b)zv4f zSRa%ZayD0(!9*E{$lYhMha$0f9@9YT(SNt5|M?T^%j=I{{y07J(_i#Bh4t%#C0+3e zcqe)ygY#oHQgOghRtL|@%vuM!Cd2Fvk=tR-eA?Ly-ClA6L%YUA_))2OZ9yL3)o?-L zKm|r{J3x410#fg4@v^Pe!#ijf*0R17lh%2Cxg zg|>mgs#X&tS>aJU>}t;MH^3Jt6Z#m5n1KY4?o^MLulTBuTbfi>%G zQ>V=(g`79bNcs_Ysln;5FCnK&%x}brfSfFz3Sbs^ld0NGB#3IdF1)}5B`oXDCjR{6 zWMk?tU*7ra*LD?@OFmUZRp&UxRx}C^QA{FIKdn-dE-yJ(%GDMhiF3rqb@QX|;)=~_ z5!?k|wgOwE;XLFw9oSd&V1vZ8_q_K?-a-UvG=ba_>ppD%dVgsNK91kFPy&yAazJp0 z#Ai`pW5uyc&IL?J95`w6+7bY>i_Pp(GOz|mhMX1!#j-j-CC5Rc@GV1kArlr}Fnoj< zCFXUUZ2gbJvWi#6uDmvYG7912=d93wAVoJ&S-t3J!bX}FZI>_fQO!vz`r!--s;M8# zb<+T#3IHcam>R=66c%%lGULdzka&w0v81aEgYnl+_X6P-T-|Os2wbFQFpq@EmKUe( zKI-|wn~F{_~31< zxC1E@+Kcg+i6jy@$FNpV;-oz&tnfv?IIHvkRmrE7Q|$4QVk*(AA{<1M@L`RR(pN)d6i7oDUQEMokI6$fv~2R8?sP(*=rs>Efhn_QY4N*We5j zT$a=lXArp8_e_vt32<2JNd$#YM0jxmY`euH4SW~e2Dgw5ga)+`$B~a-Dd9aDY2Ktq zPp9Onuae~TWROcpUUpS76rL<0_NY@0!HG@2Bx0lwO4U20TNBs$7@{pG-yqe?AR2tL zb8P%|L&XJ`-VUKu&4pG8F$Op0%vi}`5_hR*F?oGS9+Nf@^zyHAnXG7iP_w4}Wmwgv z={0HzOi=a`vn)+Y)4cR#_8T}!wD7Xo7-krj*LEd2JziB$QUBtSMD=E%tN)mi)}Pf; zH@+W1;N-(g(AZm5k@-dljI1qexZ{YJlu6@OQA;Z0H<%}k4Ii<5dZ^5W*lJZQ{x>-Y ziR~aZ#o1&5#>VQu%E9B0Pk4Ey)zJD~0F^34Xt6Zu7#vM#@hFM{3I*MS0jhI;wSs@c zcI@LUeumvAs3dV@^j}v>B~_tX#bZjR-P2~Pf6(brEO4QHhC0mlNP(j&sXxHd30DIb&xJ_b0d`#&1p6Lt&gqCC1p_Yld5H1m2@M{7 zi6@60(uh2EhYgLB^c1q%L*GnUSF6uQ=eh1e1Eam6gK?(o{;6#+g;EgUiO7J~RPp8G zYJP}S+dhUFG;ue&(j8|>c6n@vTqLcwE^AG7yyR^@>#%K(Dd|I$+ z@(vxNpm>rOYVcYE6GcW>H-cq}C0qhl)4co2&IdRmup;xGjH5&7i$4C7jH&$#L3li1 z{8X7DV^JB}a0q&DwRPzp1Xn;{t$_WgnGGLaX<|cbo7bG&hG2PRbIhEBL?=ZCDd{Bx z;e4BX=ah?%bmibF7=Hg#>B_wAUibY6>grRwT@n`owtGjo!5p`r=mjVvZXFT`@+FRa z;3_rTJB#0D|MVv&s$ffhWDgrG@FSOia4ll%-w>b?fee(xW4Uq+SYpo?N##gP;YkqE zn;8dsiybcOO!4JH0KrTjOUH@?VoLD#^QueIdeXCbB zjk>?7j*^ig0jLu7W6TEHX}?Ax7@+uu-EkmH_u-Y>W~l9vwpPy^KQZ42L_tjqHOL(D z(o#=De7}=8dd~t!jG5peFbz7uKJ+TBp1wZG`Is!aXS|nirg#b3$ZUGW2u>!h;Z_`( zYlNvFZiX-DIEjbEIWg*KDLP_Jp(D{#Akz2=tWwk*%fBfmlm={2^gnyi*dnQYn z9FM6Itk1a4ZIxUZK`EIYsV(DZ3V6A0kZZVKdQHvi8Ef*rma*pwrnC<1x!KjL5toYF zR0d0YiIP$6*Tww8gPA$}Z+_|F+`~DRQe%#qjEDDvEiKM3Je&$}o(x{pqm#~}_wPS2 zXyWLAM|-S2K1N%vfVAm0L<%k$i>qr$xA-(|x{4bTP!R--F8)=NV(o9B2jt!a!3rm* zD7e^*9zoo1V>x0Fayw^f!1TM?t<#*%CxEr&$V4%jBC-KU2I22Ql04Q9S^)u6T`lTh#_mGgPkbW;2L-qzbSLHL9X7n5bR8 zcZKWLgs4VXJbahxSku_H2bs3y8#`nuk72K&u#+0?x6%|ZVMf`Dci_~{u~JkS$YL!J zcwH2<(~n8E@C!+ogZHTFAX9)Wo{bQZFr0^%_4HFY74r|bcTxt)TYiiIEau07iYXG8 zV$fbx(6B_>{XTE7b>$&5%vr{Dhr!0sU!fszWa+rMFPF}t%<-u#N_>bnNB!=>Tip9_ z3b&S5mp1vk>9Fb#D0@(a)FZw*kT{$Rx;)K?`m{Wxf;Nse?T87YXYOc=^7 zm1!aM>p<^8Sb;V(8EpnZh7WTh3goc>2bzunJASJHlEgt7WL#Sl!^S3CZcUxI{;>Y_ z6B|^CJ9iO(IC#1990EC*mpTiyVhSFDlcG?Nv$c{`4HaH#aDl34Fj3U76|nxaMvj%| zv;p%(TI=}bH7qljUJZM3r@&>b&$qVsnz&K*Z$Iq)u)U^_DnHlrYQ3G>(FgZ#4jypi__7O>(>|n+8gGCgoukrU~g}84NfnE z)p3EWUjMhm`$^!^e9`~0_v0y|%dEG4|E|^6^X;y|6~eWalH#d_Shx1qxiyrKv@Y|)CiB%+BN=Bf;w-*_)V|) z@LrnF#H#6Qg?+On58yhZ&JPXdw9SefcKLdD%A>$}_ zTJLn}h)NB0YEjqo6vR)w#d>$E2M}ejHbM#SFuA4=>E6-ngv5Nx(RCJS`jDJL>Y+>@ zciuuz=&h3BycLD05jvlriAa7m)kKH73%U!Z7g<0&!u=A4gxVSMMoZ0rt}R-sH%(2;Cc2?XqwKb>`?{@4#8D&(v5_r zS&FT#{*2EM)sm@$GNdX|M=dkJf7_nzWq{xu3vY)`OWwRNO7w>Z7}B_}cu%^J1)*G@UKPw^#E}MDLTM)_?Qo5w??}8s<=DHoV`?Z z?%~Y(I|j93jCgnjgGeR`w{2<(V_OMF7sruC^)Z@_qvGcY#9F)W!kGI%(^C;bK^($r z6RhxvglzoWGu1P5+D)36;a1y`h5!)}qTq@s+Qdi~Gery?sk)Qc5$9gdqzWF5_RQ;< zQb4*H8cH|KyK{FvYe4NTXO8kn3%YGE=#(qOvICvv46BS5Bz@Or>E6oVkqov8pMYlo zz+Q+T<%9%RGisu$7SrXnR>olZ*75~P0PNi@=_%K<7vnj%2e|aj_hi=*Q z+s8*TE#I|{k(Aw-`kkd(v6fY8()d*sHDfoH@NBIewUg=?*mf(BHHWsS?}!jb_Y|9H z?Nj_GviU@>GM6hjPOy`J0^v~RJL@Y8_vi1&U7F=zyQq_T0dMiOcCVXi2+g0M$q9;b zU=NOZ7#Yp~xIh$6Tt)8};sVt=M3r&DPOIW^TPpTq0XH2`F@ZaUNt9CNP@$Hd4ytBh zcaM$`ECH1p1fnZ|KVdxs_<7e((eWMSKUX$VhS0>>p0?>Lwg^dg;!H>q>`OD}Nb`XK8X24U|dflH5gHL!3GWpCRDwR0oEm(RhWN zJFq0i2A~zbIpQIEC%(*`ej+~(r8Gt)l!gqDkCoygFoo)Q;zAT5!4wH{s4=;vRySC@ zl??BW3Pu?s#%_y~0)v1zFY{&GhbbGI7-<+Qu&-RWE79P$& z{M=4=O)t*Oi-Ch@cVLd_Wa4318c&8QVH)V&eMTNRv8X}TI)`=RYm8B9sNfLgpXv9H zX}il;`R2H5T50l(?PO{&WaS&5IH8`IMkb;-y~Rr8C*7VBx1XCE=(G9$-rOU-Y7x=T z)QX}j#RpMR(Z)|RX0-ce!b8||0)CJ}e5P^==iydb#|IY>@me7lk_aXuY7QSBw2;oA zWPu4lUXUR|qlCKe#p834 zDInzP-(vDFAy084Ad?7F0WRMII=km3mxrg2#mC6JR7X-?aDZ046xUbiTEPa>rX-W7 z$!JBgNR(HT;t|NLDy;K_gPWh#zDB{53?3TzNPvYb6rf@yrW=zY{|7s%fI{`antoDB zncl1cgKg-)SVy<~cXXt8mfFYa<;nQKpvamFU?7xNH+Q{^QMiNf7F-IJfz=yeRXYuk zRdWxB9ZzEJqDNfA1;$W_JSxen6d9`^GRR7U^6DeS3VA#DQ^wWLv>M8Hio4tnbm%&3 zT#&Xncw-X9l?X;k z1`aP3xj+CpL5H0~icjcGj28FQZ0;IE0S<6b0qh2iiz#$S^gqjZb%4W+rzU@THMz1G zSt{^xi6SEiqWo5dIY6E=bu<_Ogzbea(~^A>^c3$af+LIjFHt>Sl}|VZ5~Q(wO)U?1 zK&d6dmO+AD_&}}Kh^jYQ$0w8*?!T@hN_^CP??xbM?81$lF1|P6#LUQ31c`W^-T`*8 zxvkk!=_{9(op6^Jb<$6ZMNT2&S4?^v1q6$Xb1qjUhSR(R&8JcmULX_^NLMU=IHX|g4YQ&_hu3~Mw{{Ay4iC{3tFXa;h$ zgbcQy&^HzhZ}#7Gj^G+6`bL(W30Ck&=O^1g=;|s1` zDmt}}lYY4ePa#ZcDIfqgDld7$1ufJwz$x|kK@IV$1|9p~#L+VLdDOi)J-nmV7OtxP z4BZ>vChSvZ{)L!%NW+Dk5&m)tMxDSJ!wy%X$v4lt^ znQP|LFDh?yE0lUA==Svv$U+^3F#wK8?l!lygnnaLys43x8_i}_XD0Ej(e|(lk|1hW zX=H$;Wtv7~s5E_W+q2aAU0D275@{+s;x@e9777-Og#*UC=$3Y%-{6N;4#^4y=4l^T zEWkh`Lf}Ir#FBj2ga3vw0atPtMk03BXNqM>_>tr(+AVO1*@>8QP|r@aJA@}1ndT@A zH-CXI`rTumzqftiPJf0OMNEX_28>!m1~rO$fV z$u5SOY|N)pks4E3Bx{`yqjh2X{<;Ma!!Ck|g%$^p(Ig9T+e^T_Mdil1z+}8`0HENx zaTK^nc|$%G_X(m095ihN(ZB$vPu0Uy_(MdX$cm$FUplQJf2!Oj*fw`|j1G<<~@i-rx^@ zfZnpGyY8}vL_TWi)S#7J0_WWiaFs<>RdbB&#qv-b`TRqHJw0Vq)AuKx_w7UFs_>0K z!>%1YNQ@3yBi!7F!OfPH(+72zY}b+^*_NyixN29nL=*XhL>KeXkhGoKlmyte#Coyi zdqooH!V(JDCQYPMplIcIp~NdTO{<1NJ`z|MQ;PqN)YZA>5Grvq%44E+85j+ROvoog z4foGofl;iLuI8MTlu?|ppFjChd7Ik`rW8Dao(fUPHPK?}QDur6ph! z1t#OgDNh>4&(@Y#N1#mc*~t5f_{9$5v+LkYd?L&mq*vFTukEdkK>H9U63-Dt%7_$^ zjGe@1*Fjuyicl4GGRWsorok%0D}Nl*QcvD2FK=({j$&r)IzTkm6L?(ZZHsIKdy9%r z`I{J)2|lnSw_lDN#l`>VAYP6!hULALXDPeOOd~wjUMjLIG)~Cx;=^iI+S$c9^3Z;E zvq$nxDLoL%_c zI>^PZ%-rL)i3CezQb<54VTv{gWP*32w;HZE)L@ zXHcwsb3~6tzA7aMsq;Ri7Gp(qNjN zlNoUoWG}R^nS>BJ;w$;+T}f|QSccuwn{;^Czr+>u)$``*(j)AOve{suOY0yuSe#&JjO}-69n|m8$DB(; zjI8Tjy%JbI0e9=MjYO@7f^gDdfI&Gum?{RWEij%fe zUS>@PqNZg9GZ^YI!&sv>!+0P7b!Ny6Q|GRy$K8EI>CzahzZwSIVH)*y!MfE731Cai zM;Z=RaV@n10b-)Roo|tKP~n2u@WYU}X(tSW)#;vdnbojfEb+m=mF*+RKz$sTLD`Z; z?iHS<`2toYd-`W~@PyWvdX;4)n!?te{A(1AxS}CiBF?{x8>1LMrpQ0=JOO1u(VMMv zxZ-e1A+8KV2tPT%i}vQl81z?@Y=_8zz^+>sLrJLCWHfGGFc28E3s4bZ8YHjB)cBN4 zThF*Y<<7PU;&aF+oD!8`HoSnJbC`0iZ~0EBxNsKTm4e*duaxI8V5kQ@WV&lGUVB{zQh4aXMQBS zENU{?q}W#C&eF(TygfH!@pa74y)l5%^xpAR8G1}}YPVsai_~&yT$XxfNYc?5-@aWg zpH5~LiP7B6-c+<|C!U~A9xGP)*Pwk%dr?eP8m?lUZ&G4!Z|ZBuXl8C~(tIMzL@X9NUvHocKw-9dIcF)pbP- zDRz#7wlPxvRW6xjJO~X zt~Vo!|FYNS3M<0RJ3otDG?<{qd{26>;j?gfhqj*0E+$nfHo%rq&3qk0PlQ{XzvH86 z_`pb7N{*ff`663&*roGB;lUUfo%c+jta*?pElBmAo0MTU2C%e89yq8eJycce3!hNL zi7zTegqjbU^K;F6&^mMP=N`;0&)tJC&tKnfF4*h&xw(aOJ%x2lu|$?twv9XK`O5Z~ z5ugp$g%EFhOgPSAO%aD>Xd6k{AKR2gq9^i9Lz+pBsxAQ~T+&n?rvlFp8sIPiE;gM( z-N>2K_W7)oLP89l)rMr9m9nB`ug7xFClc?v<$)Fhg`IcOrK zryN8ubFF4n3PdVr9(IsrjX)XX5zmOUkcOK>42xVUb5_7bU4X3g;WMTY!aP4hUSIzW zk_xDi%oHp>w9k`+|6~y}^9KR*G99n!1zxc{;wZ*9jwotS&`5kJo+>-)9K(x$+iq)W zIe$g@Nm2CqnChvd5SvQcoLKLWMH235%z5<{9Q(&OQ!L4jD=?}| zl3I*mjBeI8SGHC+HlHHQ<}Qyzsp;B(=;jfnkx(XAK1ph> zOPvN4i8*s*Bs@6o_Jb3y%;UsJQ5fP142_iIY(33wq|0F~Hhv~k$j>(vEC07I@wx~$ z2*lVQ?MukobE!n_NBL!jIKm`+Ldk`NWFJ8|U7VRtDfuyo9MF2fKL!AN$A)Ea(~n(I zH%8S5oqlW_te`|-1#r}fOkPKXVIT^jQZ3Vf7}*ie6E-435dtLEyM32gakN2^BxYG4 zMR=*&%&xXGI%O|a1rY(>B@c5{PdJ2;KtZYktshD?yf~Bu1mSb3YwEQYf(Ttf(Bptj zOu))X>Td@QC61$+aDcb@-P+E^`VY@!&v{Pd&RCK?Hr-yMezK+%;Gq%>#2@Ap22wJC zj;~9=anM{@-q>8z%4G)mK>r8^m?b=5(dI33yZ8C zHT;|VUQ`;p20J+1bzb0<91eT&)G;>9&rtI;VS(w+erKujy;LK2h(gE@gfiu+j|BZ>EWUxG6gAfYRr}R)aNd(!1Oi}Ls$fKq^L0H4-X^#-~6j6sa z+O|}o@79DykG_^$+T>@IQ^I>SJE=I||MlQTYSK9_ojl~`1@n-#109KAXn6QHDbn(6 z`Y{41%?K@+Oh&0oZ|jG4rpgC*)542jxYb!&N^%^=4YK~v96&lIElI6wK71YqkxV1x zS-C0aN~fFo5KJ)SZJBcMZxDk6GdMWDF^55sos1(v%@o*SS3S%LWM;4|NHD{I<}H7T zNtLR3cq_6>$E@lg0g2Hn6yYqf75sj?0063=Ztjcb%JTE)%@;49?`<@<*LK#oc3!B+ zha&1WO+%nR)3&O?L_M}N(3DpDM&Q}6#|by;O~@V18NzG=rNdm*1nXcPSxqVF5jPLC zddw;#6wn&F;25@aHlH|Q6RyIP@mY`|I3q;Ld(siS3Yj?)sZr_1 zd0cC5{iiq>MkvTbcx70A%2m|CK+Qa2wNPcxNC`?MjX&tD)ko;oCQDrAGUb(}@GTCY z+npt)Ll9waqNL#)+DX#Uo%m$Ow*>22FD9oZ#c4;!kfS zb%c$0LEH=NiDgk>H*QV3F?0v{;xf{YE}gf#t0pycpF-5o zL69h%iWreLOw2?OA4OsyoH~ADGHw;<&aa85fA8F1pX>%c!LCL^ecux) zRc-!rjrj+jft-j5Mx}_E2r2V)E+1;+x{M+xMz{VQADbMAkI_;=Haa4VL&KiF9_?E( zl1fW*mm$&0MahM#bx}FZ|6Yvg-m{w}%n%uoY*U@%c&X)~>uQ)b7HO_$#yy=ok>%<1 zo0@?6x{j<@h+^!x$i6Mba=exlZfAi~oql&gpIK2NHyU3(m|0kuqGiYhTYQGhJq)H1 z!~#lQ1u%#RPvL(bsn%U=l-?u0CECPF#oD!bg?4sB&}S$)v8kC6v!< z;wY*@V>ytHAK7!;8IV!r-@^r(gih~$KrJ9a{g$X4-&|C%O^8U}LXfVpt~g5mj4mx` zm&Jfnqa(#OG-5_WbN>RRv6|99Y-~XDQ-70x))2p#2jZdjkqnH2hl$j*EM!IdfXDbF z37LzA@>}>LnjDh`vg8rbxKXPIuM+=h%r@&AYtL7Ap(GNTp!`Mat&pdL5d&^xW3=*e zcW>*(&f0&yTuaY{Wyz3Z4Q+Gl+pX0fGUu=sLu@*)tlcn*wViGA#FBJYq7x3dRXx`8 zh*fW}NsS2RuDr55art?inIDhNbt`YI86b02F^by0U{OdX5jM1~agdE!_((31G>r4k z366D0t*?3P_CsW$(j}{)cr6j6W!N3G1cNe(2t-TKm7W}jLmf6)oBiVF)^V$M(wO=g zLBls4tRkH4GH~)e>dC_6W%UY+RPV9+1gxi1TqugvJLG#FA~uAgt=c^8h_LqCl&Va9 z(^@aE!*pPX^+J@ITGvva2417wKz&00LUkDX_s~2;q z`awiqa;?59Dh@K<2 zZcbe_5w+>yf;KUI*|gCzszN{Q2FJUywYj;rvR4}R5CpD9iM*SXAoX39Xf)QsM?eay z0X!;bjxj|$YsmQFp6X>9@xsF8r)!(ZsapiBaiyBnc(KrPD!|;P7@rTBgzC9WZm$H= z6Ld5=c)*3%K>5v0JW>D)V}8c>6vrR~yW{TkuIx*#fQ))Mi#=-2H#H~f(o0}8VBO3P zYk(GkR(A`W;a6vcpyD_Kl02}uU#3yyaILDRK4`TVyCrlSe`n1W%KJjU!V_UaS<@}a92z3sWI}qGh)|>UjgbaJ8#FlMq_VdiX^AiF3 zrTKjpFp-Su(2YQkRV0n~*)Ar^hDttzaYToMC21U>t0rgq$P)v}7!yaWw`n@5Z*K>F zst7icqbyiOlK|OeiFcF2v*4PIKP0ShUE~N32`?O3bW6p!v!eLUGSk8J4z-L}C^;C? z`qX(M(MayGTQl4=8G^Yqj>8g@<%5XvK)Qm7rwNHB!^iN8D$)4Xtw}MM^wk&rCEQRs zsX_5taQW+QFN{EkN~k*Cp_haxHpoC?KOX1yp+=%{2J9(!d4Rp(1t*HXmbw;m!r5z7 z^m33P%-vNw-zik8Oh0Bv${(e$h<=DUNEfi(E+CN+TO-_;flY>759~a%E-?1vlH&Io zq{RBrkelUsyCEC1!F?fnIMbm&6FltHMz)T*n}BNwi|6gr*C<#BR~+k7?xnYM?wZx> zysHC@w-pDCC4M5T<#=Dr}hY)QFIz-ZtNkG8zS(R>=&mPAhL zynE8tyN-V0_4J4r(@mN}*Rr&A*10F(x$3@NGJc4@xv^u~0xvU};e4zFvg)jb1-e+{;ZcZyqR#M(K>X(A$Ylg@ee zSo0WF0!Zs7sLu5yH&Mw92tG2k;KXIDa^#ap0=`Gc93al9{j-gn|CIIoo#0@dX&@%y z&+H?l5x^20f~$p}h|Dqf#UXmm{XoJU)UZW9K=%|_1XfDNMJ`jVB3QbNEn)DbhH8u! zQ@B8JEPS5x@PY_OC88iPA+%~AM#5HhY6+#&l|A+UfA-$Ip{*lXAO1V}6ek|;m9Wij zXK@@mEW+ThYQtbMyh0KnBP5LkHrUSn?C#J^j_1zY`9(7^(mCDL)m7Ei)z#J2 zI_Ef_7 zxnrv0U^KZ`#Ay;bwyjSgai}WknFPIQk;d&zEK4-&t;I9u`c7VLlH*1dK5@X z`E_Aq@Fo=`CjNy-X|c7AC*p=xIbcQO4|YZ08fUIMZvV}Mcvk^}t4f9E3gKzecWXxB zxLUzjGsQ4hz+sD@R_S*cE`6=ez6z63=DDHN6Z0?V!xpk%SXw4-<6B z9VKG_L@*m+)Bs(EtcrPTcVEN{i0hw55yGqif(V-Yk6}M>3(bgmD)jo>po8wkCrXl> z@Uq?r^j!>bUAFPA&Wtkhf`$z> zi~*FoN6g*Rq?wx>qyJo%g0BlT_n5D5=GL>m{_wQ;u3_R{becmPdy=2{$FPD@tiyqa zGtCmfh&D>W0yKA7Dy{gG2AZwvGcpi>2?@3o6H4C>^fdfitFf z`dlk^-o~R~$_{MK5vG400hB2l9dOqnXO`h&QSWE8feCORULZy2kr}vn4GRF5H;VB` zDv9kUv$?Ss0>A@U6v4#pnf?+P$sXhcXox#`eVCRnxW;~Z2If^Px1vbB!uv`=s% zi?^1yqT)7=Nzz(*@yqP=Pt!lXn`A-Kz@4Pt-YISIz*=>qQhHN8!gdj?oTIJ9%@PQU zTvYk*jcX@GiMIuyab!^74v%zRNEfo+jYThz)?Ukem2#e^d5~_|n_gmjiD@1az(iAl z43J9R@2W_e{VIWKyPwhjkooL?5(`;;5dNJ`LS{73Y|v*fv`wR^l%~G8wY&E}{+NMG z&|A4kNze+q9G6%BLVOh8Bvch5am#@c8jN}duk%2$TWL$B3FH6YL6e~)Qo8HxT4|;^_eKC6hN7HND(nxOyu{lsCq{5 z=3YZ+P}wpCTqaRE+FLAdA&Eou8Q-_ItLw|$o&%YD|1$QM{5%-LGuUK`Jty%A(y3j; zQ2l+>M8F1vAYyeet)WM~zWzl88^hp6qwSQBCcvGz)pBVOXK^;xv7LQnw&?-FNQ2@5 zQv!EOn^Ojs8l3rnql{>;ZR9dk!+j&eyj{}Vg?z+K$0Gw9a~dX)pe-}_$4~53ya7aB zvMGo3^v*P{;EhKYn%Z2BCIb>o4X@`74zr8+8B!Y*q*FpoQIPKbQ_Kd-F7}XdiC4S_ z@SAVOqC5??fePV0KXb~YC3R7AEC@|o*ym=rv)R- z6E^BRBSR-6JXW-VRq1&~u*B)|GPtP?*(M3h1Q(*4E<*;G?X0kmBHngxzGw4Q&8%x_ zm(jSEpdd6DEr)B}5xX~YJ%u~WrzrAM5FI(N-){XZSGQt*`K4A}o%&IvT>Y8eQ6*$^ z{ zeN)3a8R(@3Pov3GiLlU3+6K4nmUy8H#=Bv=C@`l=2Bxv(?Y>0+_?utf|318`~GByPHtwxB(LviJx@)3{G;A=j~&Xi9L*0!_dwstDAVPChgoe!|7Aj)vn#2PePdUFTtX%vJBxWeRu9F07;;=Ss&MU^-PHGu4z>!5{vji&~(TfpK-?T22sk0buU3SU^@ zNbV!+teOey+&PDpIsf|INxOgIu(S~G*DoU@2y4r^#Rci=@HRQGkc@AUVRj`yCm3Z(H7XfjJ zsZwB6wuT>B2;cBB=s>G0kVzodzE+Jd>dnre9@f0}2;iR>tgSUF zl}*1?XC$f{IS}WqNu1g+K{sazb!liIko3y*ONR^QtQ0C17BlxEz)>T>Rvr6> z6F||vA15>gh?T8n!MO<(Qa@I_Z=Weuu1%M|G<>!4wNpw(>VjkN>0hbUsZ|&fXjSId zNv$pe-Kq2-EQP}M)sjRpS=}d@NKAzC5W^;wCCcZFLs|^YBxQ?Fy)Y`;UCr`!(m^Rs z2KH^~D_nR;GS!M@Nnm=~N7@r;9n*%HF+`!jXTX!RW%bL9g3FO6eEOX@AZi;4cMwB)ZBjk9kjk zUbHPsT*iiIyoiBj#6PigHNoiq_TsVee~HDdNfj&?fPu2cjY!GoY@G_WI{gT%wu>EJ zmx5VpzU9_a0ULdM_47Y|nVX*V2g`E+U19xxF#vr=S+MLo0GpkD>VXB#0hfV$4TKGm z?6R7sB3MIzA!pK%_^Wr1^Av&v&L8E6#(>JZ|4YH1amTZ$BQnRjPC{QPpC@AsT(G7e zRKY%yL@dgNoUVe*@C^NCwg^31_X^U?Y(_T_(yzdG6WvJ_!;WNZ!qe65qUW;97;JrK zv4o@Y30f47`R_1JOyFnm%GBma0wwT|H*~(4$b;lcvxcu=$`@wb?toP<0F;pJk|f#I zBtJ-eulJE~0jj2w-6fm!%0-14Yksp;7AXjmc)!@5KArX(d{QrYlt%YjOuY+?XatrL zzK~=>kXUPBc`(ae zxA3jmmyB&*p^-9Du?%~pdXP4LeSpW2sL?u^YRj6!!toxRJ`Ni_(m7^ zs`lWJ#|*=l{x;Pbj$;ikukfzj#q~%#YdhEwY>#**$Ogq?4)U9mnqe1BaT75BD~eD+ zKaRRsbJH$^3Eev#Va0adHW4$}2FGr|bZ}I@KoTQGthqf^qK2bm=@mr35{V`Jhk z`~B`{y3@WqneGoyXU;A!x--L*=KPOyKmHAl8E!gEElkfv<<(_A!|ts>aDZH=ON7{sAUKm6gA*F)YJRF%MDRYlP?m9PfaiwzrcCd{0RTuTNMo@H9xhik-zi>L2lgM zch_2tYKDr=m;~D5gpmB34XgEZEWJCA0s9UVO0_yWj5>mtTA@~ zdHnWvN|1t$_X!R@5REQ7lsme9I{OnRZeGy94j6gJ zV>B~A_w;*=Dw%p+WZ&9aebXjN7>fvPA=FOJcZo|Amk}U36$FSPoJG`pV~81Rbk(_J z$f4Laa>m~HZ0>quLBmQB5+A!)@qe?;#Ce8W<6NWQbi*R=sN)K7gxKhH%<>HcAuXQb zl;$aImQUVvSZrQi;mj}&-d!Y)u<>MrEMBPnW2;3Qhazt^mdUPImnE{7Ie{3uz#}s@ zem7u`Oy}YJBY-s01sDHXF3wyuko-;p=%JY8z%hY_Jh!MNQY0R67Qr~Y!iCu(Y`1h( z+Yz&?xd@qynpkFEL_l9z--5Bw`X?vY4yrJ-7&3)o(Wqr;nZXbbSB}eP?dG{X6s0Ew zg}!=Pi8zOy2cDerC4n+nb%9gWCZ|L&;kFw+*ts|kMQgwVlbfwF3~0r*q^F|@Svzc! zG^0fq$-sAkacLGo>gFU>G-+*8^S?5=LWKk}#w=dV|eZi(VI$}sg6d%8 za<4{GgxGTh=woQuuvhV58!MtIo^YKleM~T?2CWmaM^(RPP~1=k_^~1<&;p?|mx~8O zBsresHtJAXI9xD*F>XZ>y8%P-@@SdizDV5-rb*Ep%&?-jC5&&*RHm;u2Egt$v8lXK zY=TENIOiSz~piqCD^hC zEwHgGoaS_l|I@e7Jjb#c>vH%|a0XN!Vqt5aXV2gN3r*!r+pDG<4g;~~TBA6(!kKv) zE0bgNl6qoz1-@`JDK$KII7#y!71}yhR{U*+d_xel_~SD)Kv7gWftazn_1P%5Wu6Zo z+m;aHY>`{GUx1~%(*=nSBAHpoDfDoXmX5U4pjc)p#Hfl$RxIgy7|AQxCm@8<8%xqDNC79%ozd`cqkqc(kcej;4vZleB|po{%FV?|zjt#eo$i4t zhdY}6>u~36V7>wlM+e2fadmly9xtB_flLKyG|r;uP5$_`Ihz0BNBWjX8CURif7t3o zOK7>%K=R4w@1~E<_g@j4)WXp{7N7Z6wSqmtYx>ViqA1fC^3 zt6Yj>Dj83Mp^2*iV5LGg@qTkQ&^Ttg8?PQ<=s`I+{DeI^z{S30zUlxGbUKbDsDuH7 zaIRsJg4x(Hyvb9|Vh1|3uAn#msR%;*Ndv8Z^XdZXMbx0>i}o8#odE|W2L}DRaMt6p zM$aar{kRe^DiQoicD%Z_UWqE(t5uw#Dnyh zw!MLSd@Ir7)(W0(Rm5FymT?xWwy{`_c4}oLATCAdq=mM!URmB)L~hxYY2bqPqf#9Q zuA<5sEl|0iv+IhqW`uGq5@guLapqSme={E z^ri&5ES8a%T0vKs=o;i%+=x~dH<8Y?Vxbmqp%%D?%pIjob^x@g)RrpM^=hqJie7DR zuLuu#;uSMyMKwEg^~N@tvl`VZNOHNdSX~q}00~sA{7jUVYL#`N=lWK)R4&&f!}KHs zVGpDNF&0sEMF_vWWie&{!MpA9K4FtS!k)*`-dYLIAq!hd#YIvGXWiD9$#_=`%|fWE z7M$;Rv{ibwv5pk4%O&ErO<;TLmC_`bx(+;F5i(ofTSU{4C^SzY0*?B1-BHuZJ6Hgg zN9(K6;z}K$R%{)}N@d;1m5_6J&2S_+ez0KRPDhk55)e)&R)g6*fG5oShWZT+8)`Uc zUri^CnUWS412LdO)fsE)@N3L!R0Y6)Ij3?WZ3OeIm~CjM)j`HMIOuK+kQw=FvV9~| zJsPS?d4LrdbGNZ5!dd$hn)?LM`x^DGcS(h290kVKMeK|XVkuUEK{N;9Si`g ziGjps%@KCPK14KcxaouWQ>~c%W{oHS*aWayhAWY#6ig_P5)X=nSXKHWY`dgUtPb{y zacYdw!|YG&okqxF?k=w$N3YOIA1BWj zabqGv$a`1U_ixelWB|X0^rRxj0yhBp?amOdM#GtIAD)Pr(HYhUzAr;eHB;DW_Wf8L zw%bdU6@otE+atWi4s<4I2sTCbjwkl;RqfwIo3`u}- zfyxK?4zy5;?sVK))eH;E?7lT)0~r1T7#V8UBvk|_0 z%_LKYS;Ug&y(xa1MW0D9sryMGfPIGSM@KN2j*h_L>FF6bnlO)XqLJ~h%uAE7Zp=~c zAQ*C?gY*ZG-xRoxL*kr40NXj#}qmZ{a ziN4m#%i(3{Bw=cb!&vGkO?8X^_oW4ffwltbXex@f>^ex3#3pR-b^+7!{HS+%@M=--n7f~us72T^K^}qz~5Od)ERB-93&3# z3dFdWS{O)$3BxexP`fZotRKh;^J?k^OJm>^ZN>xFddRQBK3vl-K`gwT2%vq8d!m5_|MySkXJu0bx`(^u9Cw)e;nbxcI9w(xC(LdOf*dgb`@K_? z9bIAj1DcH*?`m*5#7-^J_hsS-bZj72>OIe>gng0TJE7L#13J4 z7@h4xaMOdRi2ERg%x-QJUy8(WwC!YU=0=QY#x$ook6niAiuIX^h<7 zo}tYbGns^T5wfJt9yTMk_bOIDA1&3^H&)WNJW$`m8I=A98LZgqI>ual12+{8J23IE zY)fGnGh)&Vx;vt3>=six^zXuyxL{1i3iqk{btT%)uzdnLA*ljl8K@PYfN@|C&#>CU zzwMSOm?S<dLQa=K7_J3IB$?~f)Y{=k{0m^hMbQbo>5 z@USaj$w3uMIJAC|n(^5w!>XbtFqyb`JBK_I7`!oL{h()+U{D4Sl7tFS1b5bOS)}Mo z21-DE8`)|FdwkeH(7*@m(1L`F)S>$#l&#b_9K(ZRfjVJf>W4=o#6-0}w&4nz`*D&A zL!D01_ffH;ul$%`hcGg4f%|0o$<*AFN0>T)xB}Q8La0CBUZ69ycXMB$IC?WXHFtGP zN7w>W4gVxy)iV~&%}>uhfyTh{tHY~=h$ufvIr`$E2fCQ(kO-j%jFkqz5E{cM5zc@Y zu-3Uo()&P-MXXaWVgR`?LMV%@5oKS)AxNHmCjlSseuBG1p`^$7Z9Pj0pdTXWnkY8( zLT_aPnmlxcwRzMWHa;SJ`MBL|aFHtl*~guzM*5H*2MPqnwd)UnaU82oY~m~cNF~t& z80%Z>Z_JghUS(2!9=CA>$7sq3K|Uccxg&{2E@G5M9bG}#!$}gd;I7x>+-7vM*I_fd zoTDhPo9*9Sp^76})6ZqSHD0Ld4FI8KtL7-cE0T?LNVV zS8&KtKkXrG$LScMm!M%86yxDS_u5rZa8LqEoEa{2M#JU|izlKb#z&{5U^*(wzJ8$=uTrNiqO-J{A1k8u{V-#t$d0AAedn z{-O2#92Q%%v(4uBPrsji`r{9?PZ~cg%s+k7div9XYs8){Dr{6{FE=W4%jH_@b+xm! zQm((QRcZ&XcV|~?WqCJyxqLqNx>BouD3`WYcB|#52eYdSmD=m2gW2wHyS2ght?Jp$ zRVRt!`CnXQgU=^$&Rc!TIs4&5yN< zxr6$`*=YY_uv)9lEp3%rOPlrj>Ta*KP+1&Qw@W{jS_`im&H2~=DA(&-yXW1t-Rf$+ zT-)lkX0Pj;-GiHhQft(@cs;E5mO97hb5AO3gQbJg>t3~cu)O|R+ za900#e!YCL^>p{V+}JDiKY%{l$E)WbYpA>VuKc7@FE1UOo4U2Rt@3O$R(F5le6HOc zylJg00akZzuZy<#ww`Y7jegtfmRFm#xs`+2)=F(*b*(nr?QG7LvB5uBs&%`a{f}Ff zuIbzgm5>^=5$guSeC|S$%JJ&?uK` zbJgBpsWm%S+kJDkg^OGls)eQUn;uKMO|rG38o+wMhcyMF$9X%BR7%)Ne9t-oGq&9-`bHHcMx z^>w-Qdb|2z06Gqa`}1>sq0d@*4}AX~d~cAi^q_@@DH} zd3SfAeA!;Z`!3$^+4q;F-8bdha=^!$^6~rf-oe)HyCo}Q3!rhWK6~(SzuwwzzFPlS z?+sp;Yfne}^H0kMbG4iL#o)X=e?3q6ZItGgw@c06R6bWxx7$h7-8?==-Rf2aux_^Y zt|3G9@2juoD#xX{>hVHrW4GS@tup^pqq284zd!qQskV2yT)sG)ZJ(l@xr58SdULi_ zAM8UOAiskp%24y7ymq{H(1A>S*uQwXh4*XqH?7{mY<-YDhF3X;G1j`v%je|zl3a>h9LN z`do8%uv_cxzTaM5IxD~W>3X+U`>i!wKd3MNw7p*$%^&ojQCuoSu9vENKYhPdUs~Vl_J_5P<;3 zrOjID?0Rc&YpYQ@SUavRLTdNtc4x2OZ?5j&)L!jA{cZMg>3IHfx7l5KSAAFCsFp6f z`@Q}GaQx8txc^&icCK5lpY2rU7H1oK&<$_Sp4O_ZovrzUtL_^v9@i5(dlyglH!og)*j#IERMyV+H>tb{oA#@xv+Y{&Zz zjq}FAd+4H?j^VQ^bUiMZUfsa&UK2XBT-*O`x4Zfd&;GGnd%Aoue+gZBIVgYZE^L-w zFV*VxS7>_&^Aq8%ZN55a?A5y~^;fUY8}C;4_x3i2oAs@$}jK0d$L;}%-3f@r(S)1zgk{} zo_JdR*!=BywRy9eWVX=}l#&G_1ZUeb`*6S2pJc`{3=t!CH53du8)_dw1}D^VRhp=mePOH<-^iH|DPg z_4)3{O852q;dTW37r`_X~=KKLV#94i7H2xvNLU0n=9cLvs*41|AM5F>L~`2B66eSwSti>;QVuaOKuQa~Jt ztIX!kjD<(cbBLuQ@XJEI@Vqen;3e!vB!QT=PG{3IG|8H@Cu!gWE zlG<@m??`ed^g;Ek@>4Gub|R7(!3Iz$$B7DqzbYpe|F8^oRNe zpwg8}{yl02Tupfa5c?3vwQAfd|OZank5bV>R6#{u z6wrgXe8W$+>poV@-&1&}(@>-K1-uC$`a>S!`HwgXRgo@1RnV2QYz}rE>QkI~;vsmP z(YOr0qO3WLB+gtW1~A8w0-?a^mhKheS5+>sufr(}%KjM++^XAmj+YUe@AF2EK~{d; zp1*1uS8Q(lYqLAyff%vA>(&sG8}MvJ75+~)7Ypnp6#$=;RTg}tF5zS zdi>mpRPZiaK>u#E+8&nvfeaAUe%N=1?fr@N%U7e?^M5mx1Z^`z_h*Q3+Fn{-)1 zePz*l{`EwQd7=NU1|&|gf4wpI%hw~+cmHmL!b0Jz>Z|X*9<7jC+T?fmO0s3){d4Ed zjH%D{B%A;R3vcByuFO~$w8@Z6z?&Pq5JE{20tgl~X6_AOV7bYaWqVXifGWhKdCo4V z{xbbiMjq&kH6_o$YvRmep^7CqZ}L0BC3TCH%Fz*%km4vC`G)+DY6oHw(`v)OV>U}% zdX8l~!v{u4)`AtY+&<59tr7^)!Cf%e0R4cK7Lz?NCOS3YCep(b;gsxR*nQA+UGOhCXie-IC~ij(_Q(e?)1O6 zX`^46B*WOEc0J>BWT5Almp2tqu6JrAG%$pJ)nkJh4d7}rJ!d^M!_$q@TkKXBCt(GC zEbycOMpuAq8I;GG4g0Zhg-AAxP3i2lHrz;>5_^gc^fb)Ui|3jvabWd`uyy2XU2~<5flVRFo@n| zoFhjy{ezV)hOIVCash|~{d+2C3<|UgNK}mtL=aC6!W1Mo*85JMS;8fy2@XVHT?akE z;t=+zSlwRP)?5qG2PEKlsl-Av#!ulG9hchYR(}16KaF&;3wlDf~M2is;yO%c(QuQK>VjGn^w+r;A%=N@Esvsm^qkuZ)E*W(hjbCJ}T{E z%;D}M%CCF4QN_c#yM^hB_25rq!3xXL{T5L0@= zCEH|bZO@rU++OjqpUC?naJB~+dT3j{WLh5R7JiW%x78UYgzzEVG>v%waQ4gR@pl{5 zpdyx1v5Fg|;N^?>yH{bw7m13m!ivumHMhc-FtlS$+LzYP9Zb5E6UqWe?d0Pt(;7{r zX&um!sEXz37~x)0>hKcl_l$Rt9=^k(BK?v=h?j6HWxUghAaBM?$|NdssUkH4lHFq5 zSn_#!zNLaO-0oaHoQr%V?Vs}lW@rGfa!pxR#Y{N{Ao0`#2 z#cR9*5}};xi!O?kr@UlQ=Wt7)gjH^UCdawSl6tt_ll}0;;i=?L^83oLc+CMDk0h3* zl5y2ylx^O}@&#J#yeA?{DVPhFRmo3y;=OgfOP|W~IZ$&uk$+6AVEXO*#?4sm-DBPX zsAt3wjEv=)-c_s=6e-ky9BzKjuy5n{+i16PBudF)D_Z{we+T-^EP^aCF?Wt5mD*GU zVd`1I^4>%(k`~H@@HBFS>Nw}QMKJN2vxy6FUm9Y`>~}a_(XS$r4w@O6x6WgRG|PIl zqBw!{6BEby&-Mgg%~-T}gZL8p{g)iaG~?amxUoJ`I)aM0i|YLptWxX-*n1X1ecZA5 z#OO?s;N$T%z$;TjS&urhR`(4tV8Q{(Td-Sp3pQfdvl{Nj;8w-4A5g)VgpGmVex$xL z@{FZ}xO$B4=Gk224@8nb-hMISp&<0vm+s+Wu_5!(A@2y{bKo&R@>BMhA9mrpl;8m+ z2&kh6kB#__<@7B7kb)T@W&j{%yBsb`kAU0>EajX_S(Wyb`kluAT}N!(5cKw^Z~g9L zcB0pp?TqaKRqCaLrgd?kzle1ouBgI)aXpK5%iDx5X7rdc4eHj~wp(8S*4CYRVTDlw z(;V#1C_q(`ftiIlMN}P5wqk%$XSCJtWmM#%=9Y>(#=)9VoBjaSPU9SF+CmtQLKYB5 zQj9XLy!<>38$<_<3_i{3X#1^x^GjJe`WoILZr=-lunBnG;R-*8b5wF|>R6yf32#gH zL*oWX&v?yE1Ba2i!P#3gQYT_W=CJIH(p}FPpx>der7#9Kf7-g{u|w2~0$WgqCuc8D zO7jLoAyyJXty^x1Ni7iKxQatAj`lTTwUB54K1Gcxw7Ek`&gby<;1KJ7N6#Z%DCkh- z0_@MxG%nG>X=0Uns^?(vhQjCuUk=4{1Gxex?-vmEc1@AiOQ{o*pxcOEe#Fr+coU{5 zZ+6pk>}?*C1d(N}U^ty1J0%1lSjd#c;V=0KRv{p9)WHFA@ew0;lFd^~f7%eM0LMH+ z5n80gDbyK;M6p_|3C?7Y!h^DdRbvjF3UOS!Bfz+P{4N6GB_hdsB4#F-#Ei%{fyf61 zbLAurD8rC8h3>HO4*mYp`A?1n7KrA4H0z?QNl11Uxz`vU?y8Od+N{mmtQE0mrt+~a za_4tQSvz2ZW;*xNpz_UEG3>i_5hC-^t**-O`XD`ZA8(e=1S}3xA?b&2W zS7OfwlOgxrWd98MH*X84gu7{O0+ZJ5@QvTcfurv~X_MVZwb#EH>Q#MUm_7d5bJnX- zjp7dp;%)I@f-}T5#p44xmf&P=8Vu^v(g>(hA4`6lG+374;bLB z&dB{l90iTJrrY7A+uPlCv59nTwKqG#KSkX?gOS$6FMi;gkm+_Z_t4WKJ{zo&SgKF?;giyRX@I?cdVH4JF6r3|u z!Lq|GkdCn(g#FS#4MF>!{k=msxv~nwwrkyIKEw5@+-8v;)iNpyWicT;eW?a zI9W@Di$X}BrC@Ri2KRwUIIBxH6tzrdp0YqvlQlUl$$HdR2}0ED$}+W;m@8(@NrsLa*p#d>=ME@1V zr_{DmVuo^P0^O!W{+x3l7%@KYdf>?Wa^VaiW7hu#S5?Rgb21#I+PQ3bE4-yI!tR2m zm0W~Gj`$yvI5PPakK*{DJ({F5<1Z^Qewq+g&;8FBs)1=@v4z68!w6S{ELN7m)L7`A zJYOlviz&RZGrwA8b(3t4x0wyS6&Sxi%{T;iq>zVTln9cb!CxYW$f5i6;#N}wIiD^& zqZ1^iHO~WKu%QMPN@9aL=7e++Pb#f3p)&Oy7^4{T%!gz+h{Mnw(@V�RE)lF(#|xU)xIl=!Ha1<#LI=XEtrEW5cFJ73)T zio=_F(PKPuxAPI{0S$^_q(V4)0nrvwWDqe;iSSJz?Qy_hC@e=c!<6uK*1VXfR?E5) zW^|B2k_Tv!B~H0_b7$!?7PtlCga#eKB}R9bt~*B?S@CKu-4qjzkC!t`YBvEKA)_?L znPU^y4lbt2J)D&M>TxzC@>UpDs0MlV%pwTh8LA}k^0M_u21lh&M;cu0AdJjhl{QH# zNDpF|rPRPG*D@nVAtb0~Smroqx+A5`!IWJ;M&&)h6u|&0(w)BqJ8ky4*_zKWQ{t~mL8LS?3s3eViblWF5 zZfAbT#iCYgdT~kUOp40{>)E6)6H*VqlD#56Mtzu56@0=^uy*55f?Rf)BAz|7XS-cH z=%#CAOe<4f$i1e{XwM*(RXV2EAzI}&B?KqiG+C!minqt{z!|qYaMQpkZUyb)eGAD! znF_VTSSN{+!rj+M^$C@U_+1{yLMy#4S)PcV2-wub|!nO$p|O*cq8o5<6bEmQQ%KZ!Pc5 zPT+4gB>^kUl#4svkro)YKOihg0(LGt$8z(Ay)_tPVhYK=ko2j6add)<2QfsN z9D!#y0|X~Rf#EJ4jK3jt{Se_KEgS@drpI|e#v3w&GOcBfN!*Ex>oJ>566P{sKNR@e zJzj5t6IN`Ri!^xaa9+88+QWK4@6j;)HGpv0F`ff^bhp_?#0hS@M|AlRX?&p#S~$*( zQ><>tYa?5>z*L{jg@p1o(6ouMbkYAbv^1x1D(0UWBjfXVD)#woS@l-VPX9jrRwhII z#a$H5v)`ksw*fN0M~~hfUv;`I+>LUHYbY-pW`gsUncs;ukd2`kH%cb-Ch7K2B?Qs1 zZ>Nu@et(JVS#Y*6c=YozTKIhYxxD-t_hOtiJ~uuKMxO`W&x6S#3cj621*FZIeE4Yc z<>bqv{6>)J|T_hDF5{!Z@FY{kw!@q(Hzn~#rNGP2Q z+=*pbgt?4XDz9QFSQ9?Sg15^mV;vacS?>I5RI`?fQ#Shqhm7uu5!)MQnkQ{MJ2k+9 z0-sNDyQmzxM}E1#O+T9WqrW9n1aR0IU|VKbif2Ai-T*5#1cQbjdXT}rkX2&j^pBV_z4I1H&ElI<1 zi3A>o3+7Mst34D`Lv{~6lT_ykZFfv7S>BK_UrV~hu;ZoEjL-xj{+bXl#Z^N9@Dy7D z7p`(beK_A|2r@bN!*_sZRjeNff#@?Z77Y$ClVHu+?KHT~(B2zO98-#aFTVZzBbdGyFX!F?uPp*#JT!p`^9X`npRL~X&wgCRDY>UMD8!=4HmhvLg;m=>lm zald?~RX-!-sdxSv7t-*qQ{214*~gM4r8}+a`$<1C$K)Xh?Pr3BC7TSQffYePR`2{K z?<0S8prL9wzxmlCHH*m^oLmgqO_`>yn0ms=O#Gxz9<#;VVtxxTx5m*^SpJASKYaA| z@523m7ON%Wg4nZ0O2$j$`mGHxc1%Yqf!_9#VjD=r*R zB9`qDrcOsTPK^9aC#HCmnunX>rLTmfu)KV2wxB9NtLeWPm0=--l^5<+`ANL;6Ia=b zGaE*RXLu6OF(inv=s+*%;NyMoMP_uK#G;8;f@Cm8@4cfX5LXt;o+p2ZP5n%a>QD23 zOoCzG$DYkSUibr+_Sfc9!tOj=p?)ebdsD!{K*7dnVRCKoS$qUFT8;*oVp_7~k_+ej z%=iI{QDvm%2ukYcJ()`Glz_27%sPbVXwkHJN32-hS}cL(71T<&(O8KeYZ4endYpc0j1_MS0&;wGAkUk%uyVKL7d5Juh}MZBWwWz^LPFJ3d^TXJivFv;-} z-qB8s0-o?^KJfqu128!Wu}-{GTuH=9k!T{9Y(Y6cYJww)F%gIjkmB^imy>pNnXQRZ zn5R>rvo97o4FPgCh@J^8x_LGs?03t1?(O}crxP%$hK)_+4sD#ap*jiy@yLu=KO?ae zIK1Vtxev|ApM)jod=i*RseY##q^I)%VaCiIEY2QCwl_6qG@%piQ#o&i>~N;l0Np(8 zH4b0xk=Q%`1f)l}XBB$|l8hvUcCqZalz9wnykcC<-1uxzK zBZK4qdB$+jo$5Elv!=h2-##Sig&(147>P3t2L6l^a}=T>*U7 z06pVev$%sR=micVTt*%mu6rHo!FJUH)>ov?6}M~Rkc=huPVYz@gGDK7 zcDsrNU5wBMk@X0_m?a6W-$>3-mH`Qkt{?+F9t`EQP>2BrqZl?Zg#c3V`R(Cad+PIQv}Wnl*gW`?nqto%)M z#8$xYbDl&cap589_@)4dTj4r1?W6`R?dw2T*-Ah${`3ReK^8y-v;HGYBm6Q|<*x?~ zB(t=`#6+^`KuM1S+1a2w#mDSewTkWeew5gd;o;O7(9-X_ME&D;$flBV&nLW89=yH# zz>ENw#K?nm+e>2yiKr@HDG_!gRX-^JP}iI!^2ND+3UEq{9O%!}BjGtbu-4fCBk9*7 zXBHdySojR47~iaQY+(aM*kf1sK^slteSuQ{n5+M?i;kQ%q`9X9wKm8ES)iziOfWQ=xNR9C84Oh+GX_c@bls4mxrT= zv|ZHj4k#51KI;!(A;0Osg+PTNa(>4+-d;T5931hIz_B&~DISAf@#XXH{{Fc!`uz5n z7tf=|81WDJXlnB9R9$7s|w2#kIK6ToNpsP%orpeAZS?3z2rkIr)-U*b5OR5suO*9*|yU1Db z$!Rc4gP<-TF@Q9oqC=J$s*mpy#;T4mWsb+qV-ye}MF3kn)$cf_zLl`6e$g`@64k+s zbsx)GksOIXx%|+Nw#(6}>IQI;BMpHmxDCko+dHRM{VT+!(EHx)HU^`15*mtMVEu+^ zj+wxG$7AJ~io)W<$e$o9bb|8v)v)7r_iCAxK+AIV)v^oa#VM<}>kf!!SDm{{Rb&Q& zJo%FVL6=j_SpTr*b6U_VvI=jRz7$9lbye~ml6D~XbAPl5xGyzRE_Uzjd9a7S_ME!8?&D5~B_sR_y z#N8q8q#dZAK#>G+re5TnHuBOA7>-PKP2vZvYO1t#n`?wBEWbAU!i_lLpMe#R1BtJw zeLq6&tdiqZJXLF^<@xB(S)O+>=`cbvEIJA!u`;i)XTVWy-MvY9XKBBQyJ?)#9`by0 zj&mFh#3D_E_b+9!h?Sx)8Xua~pl5$->M;_c!;7OK5r-xh01{n(g2wF%%SG+Dl`DN0 z;?LlkHTMTs2V;XZbl=KH@UVSMYgL3CwWBic9(Oc}-^9MbT}NCE(P|=GESRcr0N|=O zx;o(<@(9WjIG!*##oV~TtcXA`nHsGt&)nw4H+q#M#12W}uguy^kus}I*ynvjo=J*3 zfrR$d=VhlfNvg$|P+V<~9P-Y&8ODoEM{5X70Z8$uA=8%i)d&5Bj$%KUcM7{38e=A4 z-JB;bRYWH<{gEt&yQ(P5%n3H*?wIMY{q1LLe9`O5Qy9p9d}#Tl`{4!VWY)e+DCs zKOy*g{oy%d*G=>=CMLunGEhUs()I~99IZOdEv1o-F`|(E2~Q0-9bt?V3Yt1fqy?K& ze4OS2XGCq-<*X-y{CEpB(EztZGaBII@ePE$HxTR@`X1a;$D9^) zNcq{8kHD$rMz?vzTO)++Zupup8{>wb11dV8)BZRzEV;}0G-rRzwPm2)dGikdA@Zqq zzQ^NWBm8^Wj{bs;y&vv_FI+L>{eMD{B;_(Woumh-n{WmS*W( z2EtVHssdLG?rqlTzRkoGc3?o4k(fyYe~vR=f)AJEHk#C}RRytP13W^L&Is8mT#HD{ zjYFu%1R@Dm<*15;wNT$!d>C@dMVmxdjXDTc#?3iA+7h>hA-GJDch)&Q+wntu78jeC z+#cpy+jut;#V;DyMc#Gk+Ma^rCed?N`4akuO+BVR2s%20n-fBnJj&9(p9nBWQZ{A| z#kxwmlO^q;z>X77UiyaPF9QMuYF!isnj34&EOyZ%Lf&C~oFd*_jEYuYZn2R_23job zh$n5PF8a6#r`PXIeQe`;-xiLX;9eY^8#JK%aU}8Fk1+{KIQQihg7N$W2Yl9%Hy-eY za+wW8ntmXL#S;aoM4z@of$TBPWEAe^jhJ82WMym|<3=viR9M!L6wR3_YZT2+zk!)D zi=8|~Pq7JH`IQMD(5K%x5Yz+lMZn?TGwqWiT#ph!<|p_u778%?igRsYHZiT5klrvP z)`T35pQ@76j(ELDf>aAwdoXA?(ZcPs?Uzi3$r(DXN=3%M_GB13{XscSU6}h5PrvSr z6R2XY(ULoSX?r$9|5IfJnjoQ005<80_`fv?e2GT4v&4UfHh(i-llN{o5x;pHT|Z`k z!9%RdZWxCxi!Uq_9>7?kYqs}5bgEvsAnM&lQs}Ai`zrNCE_yDRN7v}v2x;080R+_^ zWb4A>_RW;6s^S0YOS3Nh?iu2~n~3LS70f8e6pEu$11>%qT|a-MwecN20_v*34s&9A zXpD+xTmKKQF*4QBJuK8*(!U;KV?7Gc}bRc@{&Q?lDg2_@9_@Sr&ZE97`(5 zlr5J~uYs{e1Y)pasPSzQcuM=mZMv)~DSYBp0_+0JFh#D(3B|G6!(151BZpk^H@i4p zi~|$!1y4uo%%Ykc;~1(Y9hfBJqm_8l8Nx!eO2C+g9+qeYk1_BW`iy&T8c|XK9fu6HpPKm# z!};38&{YqcIo0`?OP#Pydkjnql`IM)4;u&wA7NLyS#=B)9vTgh0s1%ra4E2b;b zHkVy^zb%l!h2&l|YnzqY9ZV~7CygfttdkMJNaz4?ZpWfHaXm(B;jQe3&C(n<-(jrN zrK0P}pPlHkJ}qp`t=^b3ifMx#l;(HwnxS4F?dsSzDlV$y=el5Uc!f_C z_zC`Nc0UKR?HRzx;yZ z+K6pJTzxV+$g?aZn%NQcR=I|F-~c^^IK-)f>m)+ zJZmHgW$k?D-Lk31(z58i>e!4Iec}aM7y2+&lF#!{kdB5NnbG5DnwQNUj&U>8#0{azX!Rj%Qr>lNtBlukvC;4x6P>JH?_2+X%@i`&&?05-elR zg@h4<0iEu$^=4rkHDPK8=LgoANQvHQB;R1h9Q}%=@Q6{O$aI0s9sWcX7QM$lGltH? z42#iC(fH0+ULN@NTHpD41!*-}> zXad2Vi$HU*()&NjRgFP^A~EPMaOHM1HIl?@D=t-v1vy6a`U4Yq^Ha{a`Ko}j~%hoA*w6^81}Pe_ARQTQvJ zwc3eCKhNu}xW}TSSMs^%KOJMBi96uUUXFDCxWc-xhoWytl3N9In zuMtSY2-*<|%Zk2MQtWs|7c$}$Ogg53M}`|FTTYzKTI+aBt&C(QT4|7|WS({tkBNxI zKz6VaJIh)Pxi#_;PbDNVCxCKmcq;kcsvzI@qK`rA8fgidh$w<{#U$q{HYdf@W)`vN z`Pt>=VDxNe2Ah3nSI5&hPB+6Nb$t24RNzK2ryj{_fINpck|j^J*$iwtjSM2cDq7jR(Cfg=U}5Scz@yU?73Z1!8+Tg2J9 zZ+WI>G|=m%Z1yws4Duzp1ELCkY?xm9ykS{4XUO(lWU#3mt*&q2?ncDe#pv`7hY7)D z87VI7lNn{^D4)V9y;&~pRM)q+5|G;0O#KB~jHVN?%;@8ho=e<(A$y}jpnyq~I5);Q zml_*_u5+B(2d$28B1d?a0t~yYYA^sd!nREX3BzC_Sr7_Sh;Bi(kQSoTO`R=@-exq0 zG?NxS(M6eAW}b9;FI;RhR;+x1xiD(Bv5A0WWv!^lRMC^s?*Rx&aOr;AH}-*C$s{P7 zCvjt9!cxyOEml)`H@+&gG0t(0z_c`wJZ|ASN5^Ob-L`uh-(1ZgiQAv%pa+`IOJBz4 zg1a*}zaq;V9-}n9gB!TAndU2}*fvNUvJG#8NzGxp4cqNES{p`vgv%GRV(06UW3(-h zp3loBTbmtEHqA=*a7|9;RYpoUw;)0?p&KypuquH;?zFFk&HP68g?(n*vyjE8*Kw{B z7)GA%zX>?#YiuXl?1xrv?>CYk^AN-fho;3uuydyyQiE9+QAVLocri>2ph7_aysiUw&s+x<(R=6u_=_wbFh~#Veee6*1^RtBJTq z7z5JRwH4$zP{B^doR6ma!_yf<(b0^!|2XRg-HiSy-F8e9x11;oP2M#s&Nk?bwnrU{&|Nizoe#!LO75(CdYTCRo}aDY8v#mo!=COkCma@sr$|TK zyL3Z3S>9lFYqt@*)RDwwRFPzX-kU7(SMn1jgZhSRSgE<<;?(^)Ak@%BHU;(0?zj0p^^D--rx0?`XB3UAgCrLx=)Hho(Q9)AoR8>Qz*rs?_1s;m8x$%rRrP($ z&k_g}37;^J(Fz+og6|rBpQ5zPWEEHO1Fft%uG>z_q_4%y>bRehzIN9WuA%JC`{wW8 z{a~`P3#BaiOUedVwqX`Ie(9W&zbsmrQ8n__QZ%zg&>Pj27mY!&Ae+UK{|)*_pW`+W zoKH^(UxG$@fsP%__JSh{06*?I+KQ!!aW4|!60P}O0D!CGCxKiQVf*L-e2H4fV2c-B z5Bg4w@lxa~rdZ<(-HSQCTBtwC0K=Z3fG3_X$iGRk$iK>Fl7H`eL^k>7zO7tF`NAGZ zF00}$3BzNf$;}_1K)QT|TNf_cCA&&Xmdmwhl3X7@-DD{49A|~WH_uZcYBZB#PVh-x z9gaB)!dDNt5Ub_L5oicH%al4CvO~GRWeRnE2Y)-t&$pZe}f&Z zTI^Xg_plf(ZtScrMl;dM`m6OS{!Zb)=}5~WOOP%6;_cyJ<8ZKrI~i zfn08%Org)VPm|An-%v%Je33vMP+s7Wd z=zuWhb)>-_4qd#C)YkeNWGvnlzS~=`uDK34ZlEhct&Aq4#jTYrRBovSBRd0_L46X$ zD`vfqCcRAC>PKg|hsJEOpkp9jipZ0Ib~t*3ch9(y^O;?pG*2w`U5~+r$(Mo%wKG4T zqeIqzNZ77b&q6|a7#-?hb3-npU<^t3p6CNX#5)-jvBUitME%?!e%>xSG+p_iVS}fW z2rGWR2(`mpG0p6mEb2Pk4V;9SW?`VxnI`z;x0BJ|ke@*=2*NIIr`P`W+rJmLwzo>C zvbDWfsg%mx5R8d;(BS0c#J7K3e=F)QRE-i<0CgG!)~UJ-R%}6e+Gp5sW0;B5OiuS^ z1`3jLlHtKrNdOu_oDU>e!zE|DVnGA^POxDJrwDc^NJV^~LDK!$f;DKDiRtYFwo=s`KA zWW@c3PJu9H3s#f>$XML**PgEkT%Ypg)OOz^}*>Jjr+7_-MUEC?H z991?JD{H079hyni$!se$M8yx#?x`OjWt0}lPTsU+$P%m|$ep9XRp6!&-gp&i7mUX%2J1T=N>coj(<|Xf6mao1TniJ99yC8(+1|8^4jU9fE92J* zl$m-#C*)dnb7K{QQXBd?nt3Rxj7E6GdvP_x5QEDQ%Y2G6K}fpQ81^tHVTTAgNtk^? zy#Baq@d6fx_#P!7jP39cf` z<}anu7)Jj#N(0$iy>7QceSf9lBw&pCh>fv-vHD1l<3L95IFj!*c0KspN3Sny$M0R% z!OJEp+pg9a#=V7j-DnY465|w2FM8f<=+|HEm+4lULEOUkyWPdi(yLz{?=8zkv!)>^ zv3|csy!YZ24;b*&jlFq#x!V|xHt>jPMR+SDqYN+$M?01B6wbr&&l6b)%bFHjQIRfg z3C3SlP1@iztAH_fgr)SMZS*i`OH3VEF0&?1w!o_me=?8|=vbXgP&KCl30cQcR;9mb zWa_VFbU`EVDULmh4&Pd>#NBeYIVq|to zi)B1&p5w--5gc)et{~u`HfpbHRWaS{j<4X1Y+_vhArzuP21_YE(>B17CWhKHMY>^s%W|nY>w#GkC&*+qmjc z6JvDy{d1{6dMH|QU$|gK2N~M#UBY~Ph?5Vv&Kn1vZ!}w(T-gLTsL1R%-7fDcxADD> znKQl`O*&+pAgB|`0C?P{F&g0#RG#U(8dxn+CH)ME;5h2zTnA18=&gS6juTVU`KZ=I zLXhF8(Ovc<%Yv~Ny07Bqa-g`=M;Jg8_l`%;Pvpt3Bb8^K9}$gXE8I=%M8ERpaeNp6 zi^C`%K75!SoDHT}~v}iI)B6?$dG0V-Yg3>fph-j=VJlcc}N3S=kVkjhF#|p;5VWP2 z8v`d|vI#wz*Pbl^y@*3=xQq+BgiC=eU?$^>&>c!K4`gG|yxI|(8{bwkejn>qec#Rw z>9B|H)lsDEQ?jK@5Mw(kHDBG0;^y6ztRs z+hEe#HgaTN+hL$`W+PziTZoVwYl-R% zJk_S~FI!_jqP?>=`%2NVkJza+81)8aND;2%5X`|nk z9kDk8kr;h$Mlb@WU3b0JFGV5Xq(w8cOb+-|*+6ayJX3c0A_rb#e5AmSshW-lW#M?= zQt*=K`t21~R)rjnCkFs-eWpT#Ur(7FyHbd}ik~aeLOLzI)w;jGHC5A5JBB!8E1~Il z--4~7Y~1;jpK+3O$CgE4@Ak}G9I6O3$6u6Dv@v8cXtV_b~ zD@k4TKdGu6v^ySA$W`rP2ASdeb=13L$S{6{V2&{pCXyv`4s(-{yuNQlHmLVu|By+R30o! za(GQ)sNOY&u9sHRY7zy2PFUv`j6QCx!_hJQAc3ae31Ry&{Tr;lEg3Pt`U#WMuF}HK z%_$%$Mr6#Gti+FJDF-#}za)*gNH@k?a(E)0YNLx|d954g3PebhBSCzu#`>9s;@6v6 zQ_!6Rv&#WDGDjjhjO{k^^k3ND@zhEW>oG$*?5_~w&hznXnga1 z%+$^0!`EB@aY3Ww%{G{MD$lHcSX!4q^!0^ZFtxKMH#q^Ot=Ng}KC6^$15n3lKozMPU->pwfS)-jYhl6GiX8WW3bfy^VXFWgk0mw zA@rxLA_z{FRrKeDhjvOXle6w^wNu?+)8tp5CUeGA^=gPrM%Yalvm->$k2tr)6PHRd zWK@|L_!DtwwUN(UeN~IOwh?L+`<)a(qgvvHXi&tTsDet*5zCnEgBur`XKn1$z~X|k z4|dbIGsUZR61!sXB}oN4;v7vRHg;kNoLXeLB3$-fHrf0=Yha&%x91(V;ZC%Bi!hUP#Rx*FY`{62vkXnS z64xL-9gpg8r&qR?TRB3YlcnU-z_s#j=jb*8Sac42|S6$%Px_@K*;pR}M~U;Koo7%H<-Ti!8%wbmG#D9~rA8GZHl*Q7bYq=5WqtEX5?I zI#Fy`8o%6K;!G%@46CAWdeh-t1vRM=BoYUA5sK)`8tOyG-X(7$Z=?6@+-wZqYM;{EA#o*?EUv1^lb_#&?e;&p8z9`Y2o$aZ(26X`kteo#@DLoa7= zVn4>w|8i-$x?SEss+4vX%ZvCbcjKa^KqveCSfNsCJ2p1j)liLjnPodSt$HSK0|oJO zroNXR(i{19A+F{it&DjX+Lt?hhC87zLu64##%l$EafAM(W*T9eZ^hnt;VLo7y#X4C z6KnA^q02L(XKGBdl{l6xn9{mR1MeeNKxqoFGCzzigaOK9DH8CKQ(q3jz+;@0Xa%DG zdIwDmRt7)bn*Ny->LC#OogL#?vlhD3WIzI`A~K{0Pc4-b5=c@@;NSS0N!WCHz*vOB zzwtc|`zHM~{>1+ZG?W`fP#qc_iVpf~a+2(^r7VN<`0_>MOOD)3q0Xn!xc<#%nG32d zWqe^og=0$wd(OxL#hmlCWt1l$I0Zz0B)URRb*^x5D6;)WxQ!qNgn%GaqP%izyQ)C< zC`YgPahvHDrwkyT8VTLct;6I_9g1t!yvET5s_y^?Z}R4-59^xG(Vj`6RGks8B!a0g zBx@z5I!k#F18@g+73eH_)$rc<%rj+>jPXbiblx~%N&ER4V`4TJAKOa)_^>7T*N>I) zPvhnMue1i4jd||wtU+e;DEH5!Rz8Ks_b)t&U>(h%9uYMYPTUD9M+J=`3E^rtF0lSb z@c;YvkpXqYr4r8P#SE4-i?b09SYQf>KGSi=`yA|nmI|&`;HA3#F0%RY8ech30SgZ< zzlYp@Mkpo^xZnm#9C(0#O?orKRC}5T!qk9o784?Sjs>$b+|0{WywcV1q=|z!FLVv? zGw^x-681f@VzX7cEQC1ti@kh_7PSXtEN=hL9z}v6xvMmIWCZ6Ge*QN0utcVIA1%uNU0y)`oetnrf;dY5T zM%-DBdqU%q7`BtqZ1=1T-++n&ZMzUe($g2-<&a} z$AHK{-q8}s!XnD(CR7gl%|NpK;?KNpRB)gI{$p@djwxUinG8+Xiw`$O3{FvOkKK>C z+fXjM(OI1EwJ<=&2yv{O?TddH>rryVFq2bJ=Tht?$efC?Y$nF6sfUX=_>nj%;nc5A zd~RN1g0xQ0JaurwX_eRQ$*dbb#8MCUf@5FSp>V&(V$S;+d zJId&aO!-W%bFjW!?GKR{CDk0*+|wm2MlCl9Vk1^LD03HGLTOx+em_$*G>JWPl2~Oc z$f*~&yi1H4Ro%sKGJp0Axu}j7Yt`+I?ZuU&mD=VG2`Y{wqu)#>;378Cbek&H2_jfv zexZxb$2P8}ePOSRO7$)t1Q;IK5A1Gn3aKT+SpXrn-ZZg?_Sj@lZt4X#rLTr<@Lvz= zmUIW$NTlR)DHbs0wEDv-tSsT#Q>i8#Fmk0YPFmbiifaRqzXnJ4c;$VgD@%z~{C*Omgwf|uhR&j^iMNo|@(z+F#p0#(!9ABM|=%JtPwJ&GzgWq3v zTEF}-|HHzMj>;1Z3*0fTP1^TL9wvZ6GJ!70&X+}pvHOBC(frUV!bKKz7?;AMjm}!-ZDhk6EltuO|Sw2mX-l5muM)<<+v9lxQ`dD?iBe+vM zV>C^R~jwqzomoH47U*OOR{HN&%?xbsRO2(Ks)Rw*D5lgtQ%C2j^BqS?FJeB9!uSA8YF-(~7|>sJB(B=LE_a z&JE2{;T0>+ZOS98l1LGqzmBhvG{V>cc!B%HGOdT0)!_{kQBVjX?Dur*OPho?4K#vP zJG3%PqcFioZL6`cr{ocX5Cu(z5=3wDu&=%%?DiKx{HfVO>WG!^uJ@EW4Bnbrzl-Q$G0Rv)CY_TNz;R6;}GSVG(!~3L{75>x(^hw zb6ZUR;0Id^C{6I*l^AbKW7&R*;0a**Udhkp`kxyAQrErK5sM4bA7sLO5k2tS&a0`z z?7_6V+W-m{J&2Ka5{GIYANB%hzBdyY*i8N`h20dAB_U6~NJ5?z{*n-8aC1b@mJp{T z?;#tpI)7R!V$hQEps^-cVce?7WjTX_|4L2Y318+4j{tc^X^%VI*Dk|2hUuxw*<%&kP@504|>^CF}Izy)@;iEQr z35!`6PUoh!kgz-bzKw)m_C6{ogD%ZF*p^TY`9^#S-2jW2886Dn?$V)|xbhL zZd1V>LCg<93Kgh=&Kw(m#IJ_QAxJ`bTYF^{X|P?N?rz(uD8SwU_575PG#iB|uBej` zV~&Xs85aichU+w4(6AH8;-QYLq|4`U0#ZnEGG*GN_&O|WFj%sk3>_Jbxda>?AimVFMh}q1G zPL>bx!8=PbutueRa&lS&&pbKU3X%WLH8XDeP79?56@jGp<@l5zKcVv1u>FrK_yb56 zbSp4__2nhb!K7lW_zJEFF_-zBpU^dNjCIsGZzKVg=%4o8ldj2WTX+o3YIXFsfb4-x zv^K@u?^9M07t)bC6Cvcnr}%AfpQ$nK02Dz1g~>mH1#W;k%!d#Ta z4TMwFV$w&IlrKM#j;j3%99khH*A7VuB;-B)+H&4;CViAo(9um%2p!I@aOyw>q|Vn= zHCh0gEe6^RBb{}PDGWP|)6EmO1eov_->bNEF4+O1=IRH8w&m|^E)ftvDT=)HPktAx z*kTFE9ErrqGju9&nij&dp^{&b%>P0b8>v=5e$9BduI@SwEZ( z`&Wb10)owX!f6>Hw0zAXb4CqJp+W_vGL&pyJ=V2Kc+C76zUqt?kFiC6b=lrQ8`#t# z^p^_dnV(10;lr0{TC-JtWPs!HNR(1I4roT1|-Wu64x~PpnSKp=VrC zv%m2t{#QUEFKB@(l!l-S%#ud<`za>o4i}P8y#imU-z0u^UjwX7w&)Ck`2N_JGIZpJ zjJYO#a0y#YdxH*x)a?i>lLDz%m<|m$fne;mX;CHcW)hee4o~0|K%{<%FFZx?&CW>@ z9eo$`$6DsJhf})SV$NQT;D&6pn2WR+$P-4Mt-$3;PRK2X5+XCeK@RTt<(A`s`3{px z{19Onwx_U+5#muSe6k+5Mdx8&?{zMVZ~y-6aP<45$!E|0;N)u%z&E|YCrJkdj$!LI zn6#j~rPmhVUr&7f6%*HS)MoLZgzpoHPm5Q*&ObWHVvCN5xtti39-TmJh0gKY zIh<7;@GRlYB&nP-5XVZ;)?Gnz)hn_9VEj%={{k>F3NTPCDEm7B4jw_V&^SNv75|E+ zuug9D))bMzGTE&OOf2#%31eBsHE;=H5gY7;2xSs}K~m>d)f@NEKb;4K;-24>!A!7; zTUIhU3^<9WwhIB_eclxTY7SW@E0TUGEUtRkCOc2jNy_>$>IKmPB}0T*SzNJtgLgb5 zfR5V3!wT8rpx93NnZWbK6^fbf0=n=!=p)}GJPJSj`ZLfzc>Xo{;}BxsJ%ik1+nGCa z$kn_Hi{gbnT|JLZ(vp>_A#|N>N1;x@AbUlY-)x45F1Ra?J~{v~TH;4QaD}&XHmD;) z1_zNtZ+r$$o+W|WN?~KQzvAQTBsRN%iQ;-oqplx8o1Ff-xeb@`QW~d*e(W|%b4F!I zD)n)sst}kA9V;g>lG5D6gShf=y~CHR4O~1no2`~yZ3(v!PR1GHrZi)5jT$HI<^JHt zUXBgAEc2MVBJZdY=-lM%K+N-DPEXJ1|4mYR&PO3H>|+3P7>cG)vHaR$72B2Szdo)a zurX5S!@i0k3~g#GVK?IsSZY>O~p=^_g+ z@N~@LLl^oo*}ILeq_rk%Z4QChL_oF3hj&~C4LH$FKZtMXusdSGnImk12N2Iaq{<3z zgYXVv)ZjC;F5F=4&n9I*((+y% zPmW&B{L#V4fqTxK?+dzs6$O?PL=Vmi@&3W1oqYz&;W+i;0}_z8OT%G*s8_?XGvTN3 z+*~I0VoxuXdKN8S9CuEy`d9WWrG)ukT|(tQjvjDDLj^Kjz*i?fF^IUHiiwet)E`^O z(J_vvvs$>-Z=5h@+Fp?}XoobD9~8(|7wr_x>*zDn38V-Pf9C`7RuMB22ftx%!_TF; zXXWAnlZ$5h`HbzXNx2!|9q2he_493DoZF)dmg_1bra)?t+W>=Q(kp8a-9CUPMrZvG zjvt0Ys3yya#27Zn+16a(_OoYA%z&5eEDS)<%ogCOQAGeT*Ss7knb0zZV7B*(Z0pGY zfQ(4}oRC5jHINsZXmpy{uHtPO_;^hQPp33(0~M%?OzZ(3K@=|n|0M(_2whOA)PKXx zAQ8QA=JMLoVqx~?1z1w)$vkHYDk`|u4e1`jLkGz^>{Ig&I|qhKa{U`vyrbQ5E1VE% zf(-f_I73sT*cOXN4GMsaFb>(;Gwj^~g?;Ps`oRFp7*d`Su|X9?aGStf)5kzOOjYfM z56HePQCn0!8!~nfZgY3lkW05?V9IVNt}bbxHvWJ1-gUjL<4P0$ud9GGbOW>nQgR%p zhmk4K6lJp`OB|ARCL_vhkN`zQB)|ZmWJdP$e9v4%|D3DqEBW4c9qP3A20>YNCo@JI z5!ky9t5&UAwQ8N}jH%gS%7NRU_2fYgxaH%Rp-92rS58MG$R+Ux6}WChLQZonr*0Yb zBbi!7;b$OrQ&CcCK&TRiw6*WT9{g#Ng(K6;C0_RZjNWR=0JU)eOVO(u^fkfyccNd|d zFds!MmI#U~-vJI~g#`o_DIyR6t<~HMM~Fo^Lr^M1RtO1cJw7%Ry4&jBuS^$bf}e%( zEasRP>pNW}9W6Lt9@968?3zhK;agZ_%#udm|RCfAv#?OwyeU zV7J4~4&B+fOLD}eKohweT9<9iPC4J5Ub9j=HA?%~01W7m<43o(1YCv7{n0RHd+=;} zaPVY27WJ|{iZD|i%(+vsEf+3w+G~QCYeEAm3@h>6AX@E!aX394p1{$^28}n#+FRl^ zj&yxXwqD!E_$EGIw7z<~<&easE<-%L992MqM3dJ6jEXy<6}?f&0L#%vQ)UVrmI+ta zJ)U}#CetxfpGwB6Qq@AueKw~#5kMiy%xzLf&VX3BMMBwApdHe5+uNDb)rl;~xuBOV zqhYBvr&Tl0&xOANG1{#+>sRm|=Fx4k!2i8uK9a|urPH2!?hRTNT`NeTH{ysjU)6t`Egf{nDwV0Yu4Hff@{c+**ue~yx}`Fwy4!$&%& zT4OWz$HS&Ft{cReDP$*R(n{TP-JJx&(q)AkZbluIbx@z~O;0we%+mC?iN8jLS)B#H zHN>_gT~N9S6vNHglnB1Z!<|Iech!BQDiFlNH4*{$tx~2SmBICyE_HhAVcc>-*HR;L zGZs$w(FMS!G+6f82zIlJYS}~y_6|5)=Gyr)LHAWs1ASCOfqziQ&GAzw(%rx#NCp-Z zUFhM1c?Id@g(>6D+KGrm7ZQRPS%-XH@Axijj1BUWQj?H5HegTcaII28lL}g*yHwq- zZG-#}l?4-St8=h>3E#H!!PXDQ0|cQVXW3H4Z0?n8;~S1MjZ{=VL3uNf!^Ahp+JG?r z4)i*SwkBcS-eOz@d=h`voGo>6DUsM~oFB?lTQo`SV3n$=utq+5!u?R}QSW7&!jjIF z{}nEkm>!}7W6Gf-%|!W12!+>^my|;BImjyL++;-#5z$)sEqMnrGUEEV_UOpt3RHT? z1Ql8@4};6C_13)-9!^#Y1Yq#PP6FE97SafHt$hg!v!Pb{C@3SDefCsAmDJykmS28$zkpZ8Kr z_`(6xI+bIn3Occ=1aDbAQ`WZ=3va|}0u+vHbn~m(-m1;HTmK#AQgVC4dj+YWfx-@u zjKgHPNG;trE||Zn%fJlLEnxAucCj@;C(T12gq~71NT9Jn zNs={!M?Q`HHM%hHfd)iZHbIBncRtn^yPs^Qv58XrNgFj@ zHDR(MX%*F9xGdLLV!6dz(ISm-X70fDDhY{kT%SoFNEr>oaQ?6)zGf%@qA!U?I8-#e zkMlurV2vI=D`B(|(Ap%Cb6~LLP}h92L~7Z&=klltKc}lrBR98*nZq#@!*eDH>)eR0 z-g(x1q}JAOlrfzM#SDi^QL+%R1+OUjBl!^$3l+b%qoj-n!O2Ja%ZiX<5m=F+np*}Q z7302T+)8=tq#aiZ?Yx~?E95@&U2T5IBeBMBzA@I;F%SRy_ zW>Q!D!IG6D-8;dkCBcT}!V(f`1yZX4HXI|FesOKhkx_C4qw2g+3WqdJPMlrh;8#Yd zL>w{Wc*&**n{&LGLeX5kpCZ;w4s$tJASE9LzA{S=&~MhEhABy{r`Z51w@`%1jesN+ zRyzc)@LNjRMq|X2$N>3jEs-ueHzOIaGTPhEHlKd`ck6Y{5NlR~7>O*cfB=KE&Tc$&@q!pgP)guEXwpE18UfkZ+roK$tLendmwu;wuN6 z&Tkve1@}IS^vnUlLPxV%9VrKN1Y2|I-OdK0{(~)5Blaldl|V_yI{5B7$a?`rc{U4+ z08JBP!N5NhxC`p`Z`~4n*DgC}NV3~t4oeJW)3*6^V{h-9jh$lVeEzSSJ}HOEslkST z;q8<#WV4jG=*C;nl3js?u{AoVwSx|Wk`yOW<6u+`@_KLb_Rb;Uef@lQo80WXt%$T> z2LQ!6-m|sSk)sG!TWv$NLlOk4(vDddOB6!3JHFiUv@j;j^L+mKXU5(-b&*ki_*3Ej zcLkaQ8nII$&*ZmZX*ffXHMJ3X?z9sy`hjS!|Zc`u;YPlLMM< zb7H+_XbO>f9w570Uv2O0Z|xrLZ|r`xwSS0v9D?6_KvE`g+*o9Co)~2%rfH zAQqZr&YQPC9tcK|)mg_5hEk_$sq`^-?;@R++g8+Hgw3mH6x)~rlWTAFS&6%26L)tt z(Sx0Tu)VYI*Z|X0@JX_o!7zh_CfH7f9yKc|oqV$e*7o@D$@Ax+^MEHiFgUSjD`-3` zolrz*u{^LQWqgOS1FlSHIda$ea9B7zfgc%Q=-cHxIPR*i*rMpMgCqM_>(If{S5KdR zx$$)G1ri5(Yw_AWc0O&td{N>%H}gA@XsKkJ@7p?vn@itujS=hEYo~A?qS9(;g|uI9 zj#Y`06LGUpwSTEd=M|+uMSTCF_4|9D-@BLKNonR9#X%ID8&wBEn5^;!^d_=McvF#~ zK^xV>o$c$G5FS5eXMZZkh|H0tkQpQ8%c-R7g+)^r~B zilv@qBKa<4-z||~a%y6CL>g=U#T>5IR`B z7B7rzK|e-t9&`{kwDs2SKK;Yze<;VuE}1t<)3u2z4_+R~>ve{FPS}l(2qlx1tj}!4=9NQn z7{6cw&|J-73FqtrGnz9|KH#_$+R8wvZ8K*JXrf{YncL=>a3u*Sb#U9O-{T^MbE<}= z`+G~`hOW&3whXaB44%SDF`AupL@$xsB$htn()?(OWHiuJ2q6nS*8#?5;LBIzj6iyI zbc9nhh zNv3VICf8vl15v6rrcfhF=Z@DBy-?%WxWoi#H;w;rF*36Al;#45g@rvtdyqwaAWy~M zU=Et`F2uvn58tWfg@ht}TeVkygADk$S5>oh8o^PR&)7uTr`k8p2gsEQ{&9SXyclnA zR&k_o@g#wFj|XoeTm{=mI66B4zns1vUbJvWEy6%?Uls_e?-6bBHaZsNkZun~(3 z5d=s(0#c_5oDnX6UAIyfi8^JM!LpYPao;6GxK*Zz73OdqViTW8%%^XU$<7s@{1AB%rLoq8+?;)4rjmz#f@pIFljrq8AQ`Sp4_VFw zX#irpB>_t?s?Mciv8W>kg;>bZ!z^WjB?Ob1HTBLr9k|_KpC%IyJk1;Ozp@T(Z7j6v zydwW5(xJ$yVe5v7{s7MM)4|2T!8&)u7fh47`VwDd&-~jZoWAL_6>8|h5YH{fUNR)g zT44Pq(yn9!PN5SBi4o9n-G2S_%kRM44tOJ{j$CX>d#e?G z(*pbsZh})~8XjBDom`*YACKBIL_Fgrmf@^%>e!$_S@PU;?Ke2$v2OZ_dv^Y`wsWDG zxNe%3!n@kaY#(UQoDc&fR>kt8RTJ@^NVe8k#Rr;;T<=ytky)d|UqVmTUm0 zeDV-~q)@T*q-`}d!WLe9zxpz3q!DQ~1G&8DN`7LT@HD1YB6#zSECb~70t*=w#%-pV z`W@bMdJbu^KEk$JpYOzbX}|lv(|Ndt|HvZ_4px@m-M{X|FR@-&ts+D4yoC8ZEFK53u{k{UL*Yr6eGRLIH5kF7Y4y=YkdZ1 zAUL{llG4@`YVNrSYXtGE2<4D&5)hkb!<#H*8GoGqHCZ`TTBNW2`%m-dL8iZPgmdVe z$gc^+xNhDcu0!8@cDAG3U6(pe3UbpEmPkm-(~P4zxLLC6bmdYIOh(kZrQHV3s+88; zQ;XKfNUWI#q}TP?ApnezX(Ra& z!eaDiU3`o}T1yMXz9D)kDDvLb7ABYp=3;ot6R5nRX)DA$IZqXxO**vqMw?gw3z&mA zxFFac4w{BZbh&w2$*-NwZxspojvs#|>%!0Mp$~1vO4J;0u>yn z0PB*T381l@4^>#3Pb!u|P z$4Ys)tlG;$bcQJvDQ2`7mi`P^T}T$I@nraFIKnH*hha6nfk!ym_s%_;g@X?7noz(- zCUUMlY)o5IWM7avTyuVMFBKmCDm(j!bogy zTSRA|3#2JYX>Vo)AqZFCUwT=bYd4i*3k>m(iDnJAiVFGaMmGhjY#up6bL#$n(NXmQ; zp_!?ALPEh<&E7&?G3VtrEaa0}kM8b>P=RBigb%C5FvwEc%^;S&+xnN-clQ{){} z6UakYIb|gf-7i}A5q;v66$zrF)${SPcBEVVl_3PVVCaFV)0Ut#Z^nD;JG59_ij;&| zv2`Z{f5~V3{FIclnu{|%)g#e$K#Wkve@aBfS#oGo+^}{b1SfFR3`^n8XqILem#q`P__l!O z4Y~q%w1e2NuCCO7gL=B{ETPILpDYbo5&wTvAd98bN#t*Sd_eX6zsp9cHBg7WF1>m2 zyCj0j-=Pox%D=^W)s5qA?+j_Y*JK3YRnLa^Z^5y-ldKkjg8~Cs_;2Z5n71k;8dW#7u%vU#rAZnu1CT zTfs!8W9nqpaq13&qtl>w4xg-xtHaqCZu9&}L+IP_DlAd07#qj5!ef~SeV2}h& zkVAXir!eeGTySk=JhhI$)GgayHVbo}_}LmG)yQ67k>a#75;IcjA)AB##)%NOHAf^y z5yOgUYbf^i6LGP160Sv2Y}KKNEuS32U?%ygIOwEHe_?R@9Q_mmxPZQoTl=^#Tc-$r zArDKkxJ`4xL#jq8)Hz;mJsaXuxD5nbocBhf)`Jn_F7Wk{e_81d*4ZFG{|0G$*!pt( z>eUdpkhUKDb>+yuKSDH6f8|Juvh)+E=_K1M6jcx~F0LT2pUy;E#~Zt_)j-8aMhL#h z1iBYz1NeEg-VEWn#d?+*n@#a#if29CSC5?$7l(ryj&Orc-!mX$fHql-6XDoaZ{1q0 zVgX|^ih{A4_00w<9!Q=~lU9Sz~{u>-~U=$Ik<4^HICqp8+e!7fRxpd&6& z++_}t&9NH-(7+MMcC8=vcpV`Nz`+xkKnD~1^G7KZDsMkO*nS?4XvNEKXTvj8b8jYe zAgl6YHHzX$5YpQMI3n*6j*AEiX?=ACiK?{+ElqFOdNAeRd-p$o^a{qOGapPSyx26a zx|1GFuvypdWECd-!k`-921PluOAam0t1Vai<4gKre*$g$WXdg8?naun-~l8zsSoK; zF+n?&T=AB?jf`eG=uMD(XE-XFGVY+OQ0@Htn0k>Q%ra98QI=QBcJCmN_b<;i^*6&f zIgASPI8Qx!YI#1dEmCO)U&>86bJOwD5!+-mJSB-Td2tpxbW3r7F%!1pwhcZ)E9U6X ze(;b1xW@nC-2km->Lj9lifg-fQQZx;ky{;Ec3Zfs9y5dW&OVr|R95mU*nUU6F;nL6 z%4UlE9LrzHVPG0>P%J;7T0OuYXv^aX5`pUuAk!^{IE$6Z7t$EPOhbUic1LGuE~5oD zk|fMR2Drfw%4JNc+v>f7vH?jp$tpM^>yC`bj4Y9rxF!lbgrCr5vXbQmPT*tx(rRr# zZ;g-s3ak`$s$fPI^IQ^2LG2MAL4yhJG_C;v$t?FrSJq%?*Hivh5>x&86jQ_T2`0fu zM}r}LViuYF7o1k6iDO4Hh&YF#VWS(7Uwl~dcOzNn^46-%T~AH6zmt|~YNArqtBWE48 zM_T(>3tp-a?9%3SkMM=wS*9B*mX&eUNkau?aUD1{ohK=COJb?F8zD0H@~jW?n6-E3h2LNPhS_KEt*d1G&7Ja&)1iM8qXa4U?8sNF04hOb|bw z5Y6H}oN9@dV9h{*V101=Mm=+v^~7^L=d8lr`EZ9D7tTKXE{Z8WkeN(?;{ZuCw}&Hh zR$;>wob*x%)`4ph;-@XC>XTI23i_fh7gd7Z*Mgk!PEI{a|< z66VJ*7toNbe)g~b8lwZCw3h2diP1;cz(r`iIE0vlOOmK*FzGRJAK_=AT8RvKOL_{i zDKe8~F;d_XbQv^5qUZJ#QXmdHcRrfliPD)I3+^gewyvO%Q%N5y1m+r$3!KBpqiKR_ zHXFHO?s9o^ICw_EmIEAx+HCTfuc`Zug)=Cg#E+;9R41AjW~b6x}YA*C7UT z$`vGTak@6CjG{CMq7Y{d(QRR#aXl2;QCWJ#| z7Pod>Q$FQ##LW#eXj`r*OT+QLhvdjSb&n^L%L}N`%6U?zU@$HXcs~|MLH^1uw~!`g zCAcInbJ>!DFWLrXO^Rx^9B2#+lMG|)`BRF5%Ak0#;i1z5Z-^BE3?b2xvHN z3V>7AXCf)K-yIym0Z;fej&nHEpJ3556?EXWEA8cjsoaVdSA9vgO(d3&ga_ga;eGw_ z@pN@Ge#^gs4np%F0|7Av*t|oO_rdhz&O!U(a_8XfC(8#1_vtn`IT-!O|0c`$wem4u zW)BYzKJ7gGB9{8`kIO$z$;K%U;&13M*|8~f3YdC&UkJK8FTTG+2ga8lf6@_0#`t^r z<4^AVcmU7M1Bl&OiSPhL4%&;u1?6?0(>ofEy40sp56x*E4F*VD6p+b@cK>~6I^w+l z>9UB1(8g6fumV1+6YxE}S05ZaR4`FBLEhcgef+YyI)}>HV`R84_#r6Sd*O?fjGQdm zL`QrVmstE3X3Md0bT&SI9rS@2>CYM6!Nc{HPr~pXuIB@+qYg?J;y~aXH%!A4c3@x= z#H49T<5aXCuBXNwB1!Uu+VzE~2AN%-a2r7j%yU|uQuaXKX3l51EYl%ZYa+k5RIX(_ zkw+Y2-@#cmP!{I`>n!`tXDxD)2e*+EVQu{-R^rYBdWx@K!&+Jg(@#D@dpocOoe$Pu z^tylF=>D(6gCG8I(mnX$$LS0%kZ>9G(ZaCr9Lx~oc;{du|H{>q490L2yl9VP!mJl=-%wygn&r$l zOEH{kj5uiw545Sg2{uD+!jLc68%HipK{pM%969bPT$auTWN`Qq@XLDq2$R#^c$b*g znriS+d>opXR+z6gGheyjW&CgG^u;}Rzp>x7#&$)jggAizpgaAah!Pfhx?6X0pbT&{ z9=~4w;ne&Xy+`{i^9sDSQ2_UfULIj?>!NzPm`K7DbcBa|aCpck(gyzCPw3dYi9&pw zIi*sPnhsTtStW^j0~qc0sP#3htuR21&j%_Joef_PY8V$Pp?s^w7GX^uuR(U2wcfS9 z-rC*aAn$+ryY?TG{l`1uUqR~t8y9Uly(8GA;9YjXn`NhB?KnmTBG{Z&?>w9`yvHo$ z6%w-MAm8cKh~dSoJZYEs?)bMH2_!H@bd{*%X6bFX_DwuFEar(VsAU;G=hhsSSur)S ztwgZ1J=Qs&G^?k0=PAQ z7xLtERqiMT#g5GiVhQDsd(a6L=KUL5?4^ZwLhMCe-X&>$69y)|yweh;D*<^~s1J(= zjBYF*4MsHI(`FLgC_@9H%itX>MI{P{I!xOx6HVJAH3}CNKwYuH;0m5cL0mpMmd6N~ zYPBGOil+$`JF=J+i7Z!NH$d2GiF+dI9V1&f6hTl*p$RBPnDha1*!V3*36&pDjB1x{ zbwCO7tY=IpR8=lwQby>Rsur7FHIvwnv737%UeFVibkIxLz%z?#@K9iWER>sE9?v=j z!ocKZj)50^jl%>_g`5Y8j^RxSKw>#CcymU1lO?#B znt_xKl1eFH5z0!j1TkhzGf*Gme&&iXFR*uR(ovd*B;EP`M>G83FuTOF=#S67efr}n z!r@o>Yq?{ue_Uc5T*P5jzQ?vU?XE}iw+k;q-yEd!=Qx^#brZC#EW_9j#b&H66P*&; zeA~GTjKp#tIDd^|1TGfD@$wIU_=BbSh{7#lupoGH8Lm{n2}_y}0F--qnCr}b5X}Ue za3X_#PEGmPb-}8l-vDxPU?+>faq90<9|f?@JH+&R4%A9(XEHv%eN;S8r+%C|a-takwuzNKcVe%B1VYFnvF}&xv9oDn>4MzAZc(fw>N);612BFhO7!Y1r+AAzPu3!!(M$8TsB6CN%DjeQKX}`lj4!ErMT!1NIS1=E)E1vIJ<*$9&9MKBayghlD{NNsg^Iz$lAO;{!MtGKUUMolJP-*I`3d0 z5_qjTb^rRD))BzJHUnJVDp*poV;-x=F0yRVPjcD`)0|Dd?UcptMfP!9IEGkL;hkec zE%%HBg2H2?{XlGO>)>iy7dvV2pmQ57bV}l%gI$59OJ9)>R;_NbGqR^d!J~si2o`mrQQ-`z63=#${-t=vz^4&rY@8cfOA6E_zCK6K!jZv^T_a98@~b zQ@lxeWzm{WMrZhuuQrak3s@_8#JwXE+V0EPzKm z4d8I*mR9&eRy+6_zS$jkC~iI9zx9B1*VQjiy|0mf9}#BK%!5^Vi%aMCvsPl8PV(}) zX7Ga_km4B9i%evg3~Ym(*t@M_l3GiE9WP3?hOIU%)$QlpFGYcwkH80voG&{Xvflcp zH-fh|{a+;V4z962o(IREKRjO#wdiD$q|||TD(k|%9Y)R9)Ed)9dKODasP&2Zcw^X% zRHd6rABpadCcOz>uiQ$r*8_C)DcSzS_b)6{F zXlC%6FbdLs01Y4W9w0V_x~d+m0g}o>mR`t|0hY;aDoqEmVA2my@vxzN*v$ModxLga z$J?{rK`~Jvf|3iiXJtl?l-hmbafn&beC4_6o%-`Pj> z?Z#91eeFYQ<+B0BtItvrUnH7EJs`n?EBqBMc-bb@(7(k+&Fz1qWu<@zdV(Mz1wm>| z5&#a)uB*V!?Oo{>*ILMl99_3hynlVQw)Wk|({Hy9cenn>x7)j0k5S@@lyxmCyzeg0 z#5`%pSYzsKn*aYkyjZAj=-AOG-7yUFjXhHXZJI+{9vHe%1=>(ogN1tJiSfO=q`!io zT2o-KEp;EPMzC|Dp*wj7(H%A5Tf`YsR5RQ4nS{b4E*|QVKInK3mH0djUm-+#&_$6KO5!?WoDvkJrnz+K3;8P-o__896WsTl) z;#t)mt2eDNETuGs9nC<5P$qB0~-tF(ionG&y2Zl-gMI49{DXDbJkWp?LXh!zn=I_XO)0- z9Y1uMNc_scBgVK&N;#a90HZ!de&#YK>k&x<7o15LdVF9TGdyM?z>sqLNacywNXL#J z+~@NK6xmO7W33$g5!k`gma)2UcoJSkcGZV@lXqx;W9N0SSgX=qS3k?gc?pCTVQe<2 zgn=MWrW_TT8`{VUkpIcjsK8JXNs6}$Kld#zYz@$pLj>DVR2#4f;sLs0Jne?)AU)pp zzRG@Bz)0hMWEXrI8CGpfk~fG6hd||WvZA6H#IrT-HUe_Yy@mD6)`w4?iKQu#hQf?p zlDjqoB+H0|^M^@~ya{0`6w(V31TO?9r6D5^O9X8bSfkO)3ADmBe6(ET7<r%Q<4_@}~=HhAV8AwuX4opPB7roB=(K}d6w zTwS?Td#R_(Cl@s!<)g-xmJa@Onc$|I0Aa1b8MOL4nlG2y&7LaR?F@Td=zA`P$H>48 zqC7dlu%H7nd?kwbwAaK3Fih1iGO5s94t{{-qm%kR6Issy$~9|#k}*x8D8QnoH00=r zq(r(G+KFzGf&X$=Y=RRXSUyb_SfBu1Q99|rnKs_rwBf>7VGU5}z4}nhs<=`ZiKZpy zuP8CsB!ZXEAoXuQzfMD+sPu!)@47loTK)Mp3XJ|7>L|C1K(G>z)sMwAYf;G*A{g>RW%h?4u}zt2eC&1Jqpk z`(T!5jb6QlCTK%MU>1`NrWWI1DX=k^1v&A!eS~bo0diesu%~l9g;>#J+j32!EGsAC zS$%y5tIC_SrpA)C5Kw={&f*6f;@>WzBetw9Aw*M({wPWpFN_qA_Ql7(j@g!|N zVL8~BN1)rxcf-puVT;0s{Zu2R3J~y|5SB7%uBTDA4##R`%SQTDUpQzko`{kKRZ4;5s?ov1QSN^YEFS~`P5PIOw~96Fw)u=D;t?B8 z_C7~+9mw+%NmT%4yGf2*J+EUwcIeE;iY4hdyGx6E>--WLh2e-sckGSz&5lQsWXO$O zWD?9IL6?7U6ibhvb)_CBDQ>;js!5_mPJp3iqsvLk_dBUkU35P5cnZ;`eccxe0Ai!p z==hgdwIuZ#!Z;56LngVx3p9|*GD9#n4t5Ev5+-FXgd*BHX!Ra2(A0R7xqWCoSVazR*e1k|#+fgv;d}r_E{P=JR}VAkSPBCgl8X@*wh4YdZtc@|E>(r#qAJ4_Ck+A*!ISDr_13 zrG#aL8n=Rir0lpSV7*h|0DK*n9F9v4kn)*-c>bs%`6XxMQ8&^br>$0$<_jZEO|%X} zjLJrp>H&w1yumX@)J)#Iv<~%=VqggvLo(YuC^c|`JS#!9`*)9qNaP7~@#FEaDGHqt zRUIiMy(K)M;nywlUy%F&z>U1UNNe1|GXoC%L3em@;Q(h*Q|DV2?{0TA?&9XCA3;MBObmJHp;nw!_EsNEIw z3=(tVhJwLlPcH8f2QqyCquUIZO`IX9kL=BT_@}<2Unul`Q8C3tUW9h5|<9hf5jYSt1xg zxxSWJ3@>#gcs+&l1Csi?2|*+>IL-(*F^aCp9Z2|CAyoIP$bYluR&6XdY?BwV7Hygit_nWl(MIEOHBPMnI9Y!pTif!*zU9kZG1)ad zEi;)%VuvhB$*84FXD%Vsa~7_M?wey~M@tGMu*3qD*(|548OC%ZzciFNWf+V$`OOe2 z7GvFHl8h6WmOEWH)bI(>vw7Qff71lLwWl=2J4GuQQ)Z_2wf{k~03 zLJ~12)bM+6c6EkK0XYPQ@bA=8eqetg&EOhSE!*4^J;u<@K65)9%8yoH*XH^M^|hrnhYuOI?J zSz`COJsS>iZQq{;$V4!j{S^|_gAt#sybezujn9W8_~@exy{Rs0=i({?4YB{Ar>jPL zKp2CVwz2!wx8H0%+dtgd*!5h^JjbeyBpij_E}V3iVLbG3Dwf- zE(?#*&2M-2;PAwv@Xox1yTzM9UCI63Eh&WiCHY>YjcC7x5O_A8z^h!IC+EYx0d$iX zDdfws1eK`gV9z|h!`Zb_00X#?vViN#@zf4T5Ud~1^(3x(5o@$yiP(xuapF#EJd5XX zh)-~kMC?rN4|HuWaat-JCBDl_^N0lje`P*>AkSThX|4RYv0IZnbZF)5q9&bXWNm3d zcNsPZ)Lox?s2*^RA$y;;E-yG<%F&WH>OwiqjUXV^p!3<>&UcVE5b-V2kvJ-YM(`hW zAh-|$9@C__1lw*auAX|fG#p4;vgKXTjp!LhQ4yFD&3!!9sSF(z&&pe3F*|mZ#fpOr z8^iPwcGnOI-SC;(+{kXQco;F<>byO@!Wk3iF*^S8wt!Q3{^G=@r)n}DlW~BhObd?m zCtO^}cW%ita9e7Aa%)^w{juTdhKFg$RAFolXBWuXTjv6p@i)es@O+8G(`0rT1@Pbr z0p1feabSz){S(DKmL#tfr#6%}w}<>aI!N&kT#6l_@gmCbebmr2mj(qgIP4F>ri6}<{^<%o`Y&8xXX8W^bKx0q30YEhUXeM*kReEEmWoL+@3RQ_e2=IEL zNx22Q3&q%B z4oQWKYNba^0+S1o;_T2DMu+voSNlvZ2{=U@6Xe&OUwC>*<_&f2fXb>#L$w;%`jZfv z3$TEJnkp-v{UMcw_vnIQld?4l8po)mVHDYM8z4^_aw8yL6jZ>A0`2Ti zD&!}M&`E9tb*B!UtHbDiat~K!4>1G_MU3QHyN{;seV+>_(y8(Q04Nwp#kb5+#3`xd z1qL+jW}-5~Bvs^n=||4Bpe5&7xHlvccH{7)=%6DHLjmUT9}&xjg-{^&!!0%(KZ@tJ zq~&B1UOi4Sa8z~+8yY;cMl&uVil;)P32D_YVRaPIikfs>aYAUTO~h4V3^n)MPc%Fm z$a-}S{h^*_q%gNpVSUa$-1>!krEjXg44gOnv+f&46gIhbeSxUGbm+Uz)GJf z+lvxM9zUYUGzmSDKwM~EKyaR|7MBv`VM;(%6y(#F|8j0YvXiFr>iI(VKDjW_r7(eH zUH;_B{QNF3XQwC=)`rL$+^>`!hUWl;Pw`w;5@L#}*{(u4iS(CUtpnZuIi?k~5}{AZ zLF(0VNNEI$0Rxq18|yy`em% zO!7-~uY+`%wW_$?#!ih>3anc=qv8-tm9L`cWBcQNB@H~=N;T>`6H%a{g$5rcwQFE< zbQy(tBW1SX@-rBSiMLev z*#!fL>rk-Zm}{%2K{&8&Kdj$f6VY*|<^8)9i_nH-@qoJJ41V)x-jb7$?jhi(a1I#$ z(4uCRe?8%}rG*jLYU}d|jSnslMC16fX*KjWnlW)-Qva~zb;3w0#sQ@U7YuU3W~G-e z5a1=W_byN%W)3-9F}D^C=3FOE<S(oDzN z=`u8LvBrker?}%8EpX>vkLx)RMGSCZE>_4$xl1-jd0S#XdHVvg+@txLt6z2e1UOPeqHT=vsNgKI)Nc-L@9ogG$$%5} zE^?!Dp2=|`C#7(F{<(fi?q2j5*8hI%*vbmgK9{8NvjO@ty(WE>d5 zHQq!pVU@{=arB+%Ta)dUBK*mbv3<;5yT@{uRWuKh1xTTdvmso{r)Hbg(pI>pbjqjO zGM<<|@SrWX88JNk%*`KqhgNMu!TS7X3ACOAtq)mKQaBjl(DBU*08__M{fm zpiJl1jV0<^pw4}61ED~DeK=0ft?uuW+VzJm8LHxm@-k9IC_0D%Npw;w_(BD25wMG$ zT>!_}JVW`&;fXNabK={gH5Q57Uv=+yRP(&a79(*M*AQW^1*o_RE%t0H;7&SDw$Be{ zw?+{bcV3p!mM|)D!C~*7@#y-o@j|0;!(*)gQ6vz^25H7~zgqIc3@xMfCLEL7(QqLX zG#{r#k$)6bSS-i9UFF_&ySmP+rKs6(#spr-?vZ)YttHmZZ~Ojx@B5Oc*nNqL{ePjG zqoD|U@AUEFg8ANF)M_MsUr8hL8^<89_ZP$0hX?`vE7ok@S#`f~j0)es@Ltp|TyIkNAMpmXZ491T(*Z5{UY(p1onnDRpFDL<*`du-!0 zb#Pggh$GJCS5~Y_nYsqj>6+h=PibRQ^I+jTXjdNqp4eCuOgD-UJ$_GVR;pc_?0Qce z*|}!ir=eB`o$rdyy@5NYZ~^mpXumoeAN9_7SbT+ll2?U~Hgg9^h@%MlPFBZ1sdq*2LZX`zTz&>fb54^Y7=h&X3$-mr9@v2=;LaFD ze2pa98-4VPP!j-iMc-4LjTIz;=N$VgJ$eyZFr&*ldTrprf7Ch}j)W@kcQv`FgiYcE1(VMEx0y7@wWfBk>6+z7M~5a`3;Z(Z z3TKT7TVyQVu3|gsnB$-WZx5rv{E8>pB29(T^p`>2@)i!Q;ZDt?-h|>#(T(2InDx}^ zupOos>9r(VXA7AWaFm5TD8hptmKOo3+Z9$T6$w(&Jz{mmOGb75V1tXaN$^%e4GoG< z+x-hx$T1w3drTIXf$Rj?K;O9N8Z2l!CEHQbwWRTJjwA=HZR$$HfdfDTvb7Y*i0!w%Ds5>eji^+8|#7ZhFY5 ziO2?MGRVt(FLFHIYM301hzoKqUvMP0;)IcVz;M34s46azmv1CcCV4kxqYtWH^IKi` zf+@J)0^Vy9d8pJ5bWj~sb&Pc}Q8EEg#!)}wVMvzl;-t!erG6!eh}h*-pXY-Z3DL$a z2_$qzBRQ63wb54;R(0STOmfgqy*+Zv#2kZ4Fs_P#+H|1-bT6q&3f?kb*;1(4*Y4(0 zukdDEVUIjs8hQZ%GCH=SDbg=QO0Hv(kh#~QOhC9D&z=wmFy~cKs^nW75guZe+&0Xy znOgL8d=9|{hORbl+v0Npuc*6LJHtA2jNXEm+c|SQWBGU5xMpGJ`QFwp6L#R8c>Pd0 zZ4Kv6Mw;I_B1nY^-M$1p*aPUDjwrtIYar!PIOD%#idE{!R_eb86bVi0coa?WO)CIl zhKl@V^;lkrHYh?dFiBpmE^gs*Gd3%p(Ztjt;x!M^1$~m>Y7{%W+q(1aVD!_$h+0na z7k*NDO=ry}od+a8hv#kSaYE@+n}QZJZ9&hjrV=eRCpn3*vy{x2;tAN`_;AF>rt3)$ zvNuI8hy+0~Ercr2Ddon>33b`1D=_D{%U`=ZUW>n2bRitZ;)FCLP6|_ul}q&W=cMSGDF0HgqDT+o7sX;ent}n zu)99^0sAVWNeYF2cF}vJTlI>drJ&*fky z$EUbP8mFBa@Ucv3+@N#%z0dFE3T$5qH^59jeG6iztQ25MmNsFjrA@!d(M;|~!`ad0 z@$12?J7%+D(kjt~)7>kasV3zeCH&5oM-I-Sifx=6q^JgzNq!^vwzR?P%v zw0*l~_8W=!6mGCeW)(pqIOmW?CCY(e6Sk8C<5EZmo;iHHuPFCnE(!&Q5rvpC z6jzL8sH|b&D&tqvZ7rGb|3wP{AH9pg^c0?>$LIa9@#`S~72`HWTIZU(ZIw&b;_uzO z0hx39X9Vif8@IxTSeTy(2&01#rrs}tfLN$DsDv;034VpP)NIIDO>c(hm|FbdzauE% z`4@@NSa!0QS|dH*cuE*nmFU9Yjo9_k)Qz0mx< z(kmNTDuYp921QxPGM(!+<6S!i(zVUZO)eQTScRy7d79U5T@7r0#==8fxfgKRu%GgP zUc*3i41BpM5`cA)3!TVkaE2@g#TE~r{N7u6s=nT-SbFV*E*ac^q9a6lU~+Y7u9Qvq zmy$xPUQYd7I--CVPk7LcKqDgx$)Fo_RmokP`Iwsl+Du8YfyC=P^bzM7s%;L-qjYr` zrs}1nSHt1e^ibiibI;taW8v;-2W%?mOl>Xw;rdA!NKD<`ay7wyg4!ByRxs>QDl3JMGo)MSuIS^KgwyLuy$0 z{a~fD^2ze@!&Ly8tR?)AdMH({3j!`{$D-S;+>84!HUDJ%El$V?>?zJ1Y=EC7C5$hi z3kI!qWN0st`O9?DfUu1wvFmWm<%`Jm@?o>#x$;2@dR@aWeBc;RbEF=-N!CBJx z9iUVf%4r6MWr*5zEwRh_BpilVA34fK`3YP{kSNX8L&?Izh}9>qzEBm@HRLVJRKaV) zXtMq)$G?P?VWG+LoB1NE+^kyOSH|va?0>yiEWQNf(V_0Tc}H=lG=&yL3>%&; zzMG7zu1XyeYZmVN&TP5A7L%&$!^bYWPd!)jjp?s&hdLaLnAfhO6IS9hM%9vtY!k!&T68caF=`yvf^WnXP=j&qn zPBYTG$QTN7nj!Q_zQitVS2(lCDNa{ZdpJEDUE-JsH5w3r_)LIPI*+t5MM!-vIhDF} zN=X`UoS=W57jOWZs)(k-&!Z-xI`yv#Q3g4opFhhi!Oz^;#!*$2CR0h~&w;|y&NQUu zWNTaCu2naq8-bBeYD23fR;HlpL6^tsX@cNi0v{FX2Z5Yl{2~Y;4iBr5{B;NEu}g6g|6=Pwhd7&^6|{N%ma8>&K7MZf^WG0rNGk~pKW|gX)iejw zk2^2!b^rUy%TJd1{oz{Y#q0A|FPEvgd3dz^aQPt~FRjvyq0E0h&8yJBgZcP+Cdg8a zjF2y{;p}9M^xw#s$InAfy}aoX2)#BdR;e05`RJD)KBS=I-lX4EVf&YsI-rM~iidke z{Ad)ui3Wa(Y2>5Dup{D!c6=l0L#yN)D|_YV*A+fUIcMV@@(y*UmnX=!k}Tu*=Ub}D zqJvHwXL9k0gEj}Ue?H`jEHOn61{?w8p8Awt-b)OkC*(O86J=f-V=}n+YEojmk@r-@ zXlRXR@a}{+d}Q_S)oSnJ`0@h+3I2)Lkp2g3(Hw`nv$LN)DN`m29dzkl@pI93+~fY0 zwDR*fD;qmBE2C~CqVGWxiC&*hzN!Vt30T(a2RO_vxL#_yE2VL`E958WpNAAk@^DHs z1;{@mKFntb8hJQoc25y9A=a+O*&iX$KtPP3vuT5F-%yBdXo+=ythx?a7hs@|P%8isED z*4qWH6(1UBF%d3tLytq|e~Wg@rEXN!AM;|`e^#3M2SqG>2!BJY6JqlBeJK`fGtf7= zLX92AToy!mZFUw-FPn1M+~mR=9<6AF7w07_oW%!{+MCqbnMpCv$8QGO?VkF5bQ0rG zvIRsY!a*$vb;;y%P*f?u2V=$A;5(|_)2?yGy#^BhVJ?Iwy4YQgmF3D7iaWMC476$;psa=$^N( zgUea$@0y8gl+XSvq->*>e<)GYJ@d!f%I3OYpkDoWY+k#CC(>v-TLUx7d_qJWptsNGV-Dz4%s42P=LXnbiK~P z88r%$8km*Vw{Tu-ih30H4NbNp4jgdnD3YxtQI*Zo&P{~R25hEMXHAj!5I5NhGC5qO zGnDYXT6s-n!MgqzkkqadF{{lMLYhO|jOgpIv;dUz<;nMiG3*CXh78`P*ownz^8ef% zCB-tYVRac^++leB>8Cs!kk>e)X+Em#x|cAhC;HST)Wc>9)du1CR1}YvrW||>$A${! zUIzgV8TH+}H&nnTTk?-On{z**?h5_F|Fx<}W$E_iMD3ei@P19fG7_t1toIijt9Aqb zFK|oR4c-n^|EVw*I3<8YBzJ3RzarU)&~`bfMXT4=%+%uYUvX}_u0GqCM<8>iN4l*U z5SxtbhQIhxhsk2a>MOYV$s_`49;&^zCUGA8X(QkaqqACSc+UZ7uQemcp)ZIb+0iPF zvTX)`oL@4r4pVDzqvG*RVpV!AP~u8!OH*pBwJuIC7#||h`70N=wZk3hQdZKG87AkM z0V$Cmi5qx$US&k`{vUz&_%6_}Zwcw-vwqEN*EJY+9wj0tyJTh~=5SS@+|N4)d0yln z0e_i>=7S-zvDKSklFov2u-Jinej2y^qiLiih?_q`B)0#Mkn0~~Z1wUlKLO^1%%K=g z#7nb5$rm?IjYII?pVpnavmm9pxz$X1BRWdb$#TA?S#@8On~ z(p~>HqRXz|_1V!}X1Qf%q}J>$+^Q$9;OWcj;ycGk!%DATX70O7uBg9Y`^C`U7W;}f z9U?y#(%tyxP;TJtJLlqj@_{hUrqWL%jg$)1RJtl>(#0J{J%rJVb=n0NNH|Q*l3^n& zfS9pjGpmbIh|?arOcx%lYU$cberv`9_e-u5HAx=##g)96orZmXE_v)DDH@XL@#b42 zjl03}h+I|3X~%?B22@V&oSlER>5tRgIEjgHu1hwu!vDI}$_NSS!Wo)7oibYU|N15B zL(W#8EKf&4_NHcC)=4yxgcEL^tdM5?i5ZzHI+Xqxc^#=c5x*2kq@}-kg|XgOgDiSH z7g7>s;!2k*4T6j6)e<%KC1KO*8GsxNXJ<$7z=HkAp6K}ua>Myxb~^5tw_P#FUATA% z&p0~_g0_Y?XwvX~Bj9z*N26UnN8~oKbfUEtYy)r}|T?RgL z4nn1s_RGSpM}_gKOty4G5*$cO2+^m^J4( zumI1;*M1Q){z~#GkYk{>n1=YJ<>!_n+8fCcQV5IdWa9U7aWRf#wo#G%^8g9`Hgy}Y zt_REC?&*2&dwMp7aW8cD%r-6$fb=++6s5!S1E_nM4l_JxENCS}^!}zdLPnzIM)xjX zy&52)THh|LnbJgs`#mc)o*!&K4|{siwbjipzJVBw1QV+DKX@#W7D$P3h1-tDXK+(G z*uhdS+NmjpWQDlD65=~991;YD2Sr_n!8~;QqMkjulX+YY$4hT8hrInL8YCh#$^Ak6 zT7Pd)e1D)L9?k~wS#!Ids&0|8KJEP{kn%JKUSqYrRAuDtB2 zeK{EYwFlR{*4EKrayA&Y9=wJ;*n2&DbTrT>D}A{w>V}s~h2s0;BVN1k&E@EI>%kPc zck$)X<#d7&&a&laxc{@Y0i;9Uf@?rW44%W+NB+giuimnoKoLMR8yJ_vI--^a`W&1_ z`qLJ@0qxl>6$_F>(IZF$twv7PaIRRIHnTpd0;GSa+eT$%U7N)sk-A(snqMI*#j}Y& z;gz0|EQAhT$=yGZ66)JUelWQj#gq|YZ+9Vs)FdmS{ie*SFZ zDI`0i=oa;%^esY;{h{q(P_0!R6l%H&kk9Stu~RxP;6X|>9(;Mwoib_Qlvaj|=muvJcni2XxGatSbE2BGgZ_wY+~5Wx41 zz?8f&o_W0nZ;JxSc3K18kp(y~kGP6NXMegFIFld*VE!6WmdxVL@c1<*D&AZbTWEE_ zH{lsU?KBTwJR2hG*Rqh+c>G#GBzYT#Zwg_T{y&RB`FLw*cWZNFf9vs@xDj@{37DL6 zgmNy{Jy1HYPn##bGqs>5xhCsxmssCjPK=EjR#Cqo6&ib6dAJ&bRxr>oE|i`LqQ2Z* zknl%HYq1cJP^~e1bulOx!w&jBhL6nn+%wjI_!dA{IX!6R;_UJjCPvod!jpq~QxOFh z>GaR1uv+jYt}*dUp%I%ef{;alkGTRj@=SOwYZcH4Kc0+XdASkQazvByE6nF2pgo4r zgC0~3gByb1ju?qgsYqH_crMbI>NyL=h}P&qMwryJWo!2bwUCP%2PWKa1o}i$Z_&UC z%akN)Sj`!7WVIpT8m<_cv@nj=WH^0IS6(d*zJ7An!!=K2_D2}vus`T6HoVt^!9^D- zRTdzxnwggC#Azhq-CQT*Ge~NSb&H9#E#hV!PhSr&gqT5Ay17_VY2RM@eqw~1>0+SB zT^Iwb6!mHXOZ(d**x2S38eqCs4L*XxlgvYdzH9$NDYWYZKCSYd>o3e3m?j8*9S|T~ z5;O&jn#WaG7l0Dj4h4L|<^nN49kc zZO9J|b;fuCguNH6Yu;Z8bAWUocjPI~m{AoXC^(W&AG}KRw#B*;fF;STXL1dd&f?%! zH)gH=f}3ZhQMHy1RT%~r>+TFa1U$Y);FlTV_-m0mK8yB8 zRmht<8(1k1rXS{V5WBtvihR>^t*z-~s1Br)SU>8`VF7yebx_=^!yilm`V-qKk{zd} zv>nNXjvL~)m2maQ5-!9-%^_7oLBk(>e?l zV1RlIMvc2%ksAlw;vKYkXQlNxl~Y;As0Rh3unJk_E$+Ja=5t>OKXx~Oj_tH6Fjj2l zKXWW~onUa^f^*-YV5Xwx9T^;D&HAx$B#wM6a6f0p1|Sg7Eg&J9#2jN*b2Gvj8h2F9 z)d>@1tONa&Ul7HIUOekQX!hS@#zHpFn zuP;g<{D84gX(Pb}X0KMxEc$4el;jwZXzOf+ICsB1LKJBXOD@(%VuitMjqh3#Z@+rV zR64;@6L{y62?5WP@=WAmf2S~Zxfz`G<_e1~&Od@>q?mB`sJd$?_aQ7ou) z8SOBCOIy*|`WlIM(2B4!S&`8yy@Z3(=G#8rf^Eoskcn{|aTad}5O}dS;7AQ+_9c!w zSGeRF$2x8@s{QdRb$IIbKpMK>^DNMZgpI2JL+mCzP$2dXCMUh)!R^2tWHVr^x=Du% zbhQ1{TyM;_QSXg$@Z8a;NXK5AU2!UVSVC6f4$TQHeHXx0KsS`=+o!;dO0 z;bEkqbRVp{dBUMekt7tZvLCm?Wd8(y^wfq)D}*&gVC_OmU|4M$!VsZ9_@RQQ%F^we?0+x#4lCw*$*tChs<*2MjK<)`oCu2pGIxt+0 z*AkIcX~+DRp9F-Z)85o}0GrOh@M3LtecSmg9RdTWzJmm6XY(kKpBeZNA{gAYhEoxR zdbptC&7f1I05~E_x!&}(EJZrZ;=tEw>p32pXV;5x7uS4OvVBXSft$HHD+naI+gh2v z8Lg}=w-9DP+x$a6-bZJ#zuX-q?qTpqw=+^UoCsx!aa^_tF2L(9l-u%0Ic-)3R57@~ z)wlPAF{-x!mtI5|Wv^nimNxU^s2%aLO& z?L+&!`Q4uU>?1Wim9Xs<=7>keTIwR@_xTta7HCl9$I;&>@)uZ?zo)O{&&l-c_%(Ex z{Bii?`QG04(?gt7ph#PSo|+Oti6Fuj5J1~ByaTOdK7fQGSqGP%6nl}h1Sy#d1@1he zwL6@RJ&&YLM8OqV$F4DId>=4J5gck+j0Ion#=+KfA)HJ-3iGjB!*T5yYBg13)p?Hf z?M*SA)2L!3jkpLlm?MeJ@KX&i%b)xNWgz$L&cW6X$DlfDOqS~BCb&?#7G^M+j3?_G zxQUiuTH|A+y@lv&wiJQRb$T=?BeVutW@kNIBEPbP3#viL-@u3jAGZ$l@()(Exm4$( z1IQLw7B=6>fLBzr_vzs5WW`mL*)xexzt=toypJPct(CfFDI2Z^l`@@a-Gx5Jh1~* zlA{N@E%I`CeAUz8==DA_04PaIE&%4N;Cz*1;f#dld|=)6cWq22W|dW5v^9pR{qm=d zF8DLFU)K;DBjT1=KJ*%~niFGi zdzTI?&8zD-x$AI>-nMW#4r3Ig(FBSLn=NmkpPZw8Y*IB;5Px(jOm%M;2w)i|~0`Tac zS!Y!}e_%keX@T0JZUGPL^iw32+exvK3XIV;UokClCcFtb&qc3-q6eud?+VV+M&9AU3F*2YdOWnI=ZP1E1r zY=SL6YZ$nm1UTkdH9(KJv)Scyqskq5mWt_UE%7nHj;__Z>++Y>9;!k{^f1yy5tgEU ziDE7=h}|w^VM^Oa80ibWxj0SDp`>9=`trd!$`X-P8hE2xVce`+na83L45ztvWGKb1 z7AYny-LfNs3|&FEnfTrJFTTHfFn#&)!$%0~4Pi$=f)Q(c6r#VTokCnO%L`6I%k<+| z`bnw5uFERhFBij-`zt+vgCh?RCkmZo@hCOn$V;eYPg!{~ zCX$h87;(fw%>3U69^5Ldjt5hE0l{N+s@84VEWn@W^|K9^axiN;=!anod3%?RQ1huu zkY-?DiFw&DfC4t+aYxqxSDF{^uJdSZFW{?wdO_{L$K{DHpM|6?L5|H&%99oT>hzRV z^>k6wKtfbND}fX}5l{e!@o+N4`~s2i9H94rWct21izh(HhvJ*=QA>tL>&>5nH-H=y zbUCjeo{AO}U0(u(P0SYaF+e549fLEFaTq=bbcrA7Ita6zZ5tJul*6|j#{tWosAUjz zSbs34aL1C9^Bn|2maGnOsdsD?C5(6AMs+6umcV!?!3JlNa3;eM72?mpj7giJ=h~fN z5yrQap@>&ZGhE+CYcjGpMybmal#i3v&euDk2$*BZLzrKw7=A*F#K!wTmbIC*N6f~} zy6^g^3N3(DWLLc3S-k_IQp)?Z0GFyK4QB$?xM~uV@fe{IoBPjq|8lsuwX?CifvvuiQu&N29AOQ#DZ8e^lV~) z%6htdk})e2u`Ni}=ID3;r_(fOw45_%s$|9Kc%{zslXS-^db%eECP?u(@C249h|KW> zfvDXdyy;?Fr@S8S3`%=b{T|hE)K2N1%UoyNDxq7i=2VEVLh#etyMq(#Qy6i_6Jn=5 zRABlnJ(DCuTk4+^7it7k(_(3C#=L(y#Qg$t!GwtPCK;vSdD73cy{5g42`5JIg3Ii_>GL?B^7z?IBa9%P$4h=2#< z7Oyj~pq80GVHt=l_d0(R!GRf8S&_~oJGvYrM5*L$NC*Z+%vD>3bYv-GN~)BC4QQDI zBQ78{@S6r^vZv~GTGR>Z=bpuwlJ6qzQ%Tm)@yT`_^f1iy}sib?s6UMDQSe|Dg8zOt@mWP)UD>?jOO+ktQYwgdlp=RD+pm~@fQ*&lsMGm{84TF>%rMY=fQ&q43xkg51qi(6uwcj9t@a_ z6@pb!{Wn^@Blrzi$aoCxfI36O2Z}ZQIWahfhY%VSEKA1OZ{1ojR3n+|EeWQy0Cr>t zq?O!fSx1U24w$>%c}pY3qYp1lYhdkVDJAY$%<@!)V#cCi0+lpt_PmjzK1>XWb?QXe zAKSPg8)y(m$fl(N{~rac-}vNB`6PG>4hl$U;$MoCBer7}PnF>m4_zKdWBZfdXvzdY z!I7gVtA{CeO6{LGSJs!%g6e%)l#pC03dwiSJVGZ`$s z`?=Qqui4=K4cUr^tuM!~UJZMraqGcfSB~uaqv_zRzj7o=VZyF9?7=H6WL(L%waRAJ zlJqMP*?Xc{scv0MlM|pumOI#@)+%PPrV_S3&U0B2Os%FcbsC$D2mGQ1gS2#YqpfrP z=4eQ%+nBO#@39rs*jZIHaeIT79uEB{xabM12QE^g3uJJ!a%OI|_{esgZgl%0s<3Yj zyI&#OVO;O==>Qt2yjga5iq(Vd@d$}-sG$KW;8S`&W#A)~`HERl1fedlCdp1hkjqWfL$1m9uF&~c)W6IDxmlb)#9MLhT77)iP!<@k8z`Y{;bpvFX8 zN*dZHRTa4qydbO~&l^(az-bE3usE8rC165OzK37uz05NzQ5ao^U|RY)K@O7)O?Q(_ zyH;m|MJ20ltlqudYwE{?rq%iYZW5s-ti97AuA%sLa`q)%)i9=xT=5NMj7rLIA(jwf z)yU`ulFpSO7CaTmC`J=`u`-{`nIR!4Yr`2q&}^j}YpK(zr4KjG!BKKXhskLzjaYY$ z^s!^+LZOU6^|c*Bm-+Mh`U=W#YP05d!@zA2|7Zji*6_^`DU~Ho>-cr=73Sx?2FY+T zoocRirN_kpA%p*AAfZQgEhys)vEe`|4I$|e-BU_BgoWl1Z>W;%)X7h4Ybdd)g#%R& z^foA==~Ru#<$fDEROorf?q0|;Xv1d(WckBYox@4+Ax=2d*ZccB+|hoxs-2ZZ*b`@F zhb?5BsgWnf9--WnO9o_br0)x?tw;cWc6K=#{(NX?DfxCX+|_n>ctBhnz&*vuF9zXM z5Oy7iC3ly5kCca#^9cv<&^~c`dDNAcRbyLp7}nb2I6ppzgRf-RmdjDf?YMF7pb6DW z>tTVl=8nnq8fR+}`TLw7ZK{sK6+P5HwGfOjXq^qu zhxIIoJv0O~NX=9XQlNLy;8V8ev%qdrs~DT)r;ddeLH=4$P4M^cwcrEJPG2B(IVTI7 z1D14y^L5JVA9((RKX2?l+kW;{a}omYFsa>mSA>^shxE;g0N9El;3kMgUK2WMzy*0@ zXB#U0uupgk{ul3P* z-kSw`AY!}++VV~4BjaC%(7y_k{SfJXrmINtgHZPYvcABGG85Axm{aUhT48vi??*I@^0et<&(vuUqrMu9jBU-tNIpkRnfo} zo@6a};j?@98y8KD)E&v22R-F*f&!*_V2b31=zadGe&WPvUay? zR}go*65Is6ZDiC5>D-}kgjGHU{SRl!ToueuaR%-BpotCCj0oXG`9Vlp$!09hO0wT1 zOd%d;VE;$9#R--IPEN;zTCQKm>Fk*tW^n3yy~o--Xc14D5XYH@Z(47%rj|!Dp&uST z*?zipczCyk3#ETwaVV(;_Tuu0j;ysn5((DBQ3B z*(pECEV(I9C*HL)Hdh+I9Jfx@u;xd1-s#^~@q0vk~9~ zzW?VqhlmCvp@u4{Qs`NLJ|SIH>~pqYaaf_q*;ak_K7Nh-RuGQH zmadQ?132+m{-|UOVc!UC6KS$bux05Kp`OPOn&5~9j>DMy^@QZ!8|!k$rpwH%k{_qy zXMnwc{+9bN|5{{CBpn1YP>B_mU_ueHl}isATqqJxTQ+aq4(w24&39*KoDDjmh`3zL zi#xU{6p^;L==d=}UeFVy9VBCCew-BT6y{*bHe2tm)l3}^bA-l)4h>Oz?4elzU%@etQa!4qei<_3#+ zi#u^Mnr@4!oQb#(nY?Du@3fKCaWtL6(UNGqo#3P-;~X8r`_`M0L348z5v?Og*^uy& z;Z1r~8wcSbIvE+=djqpFF@Qm8AN90ZJ!;tshi=Z5lX9h&XI77@J*83dvQqD7T0pET zri!jnxCW`SMue=!UUMEqWh?m{z&ymsu!x_A9{RX<0#kbR^j#%F#mEbCU~G7YlES~k zjxm^*>JwEouPnQQNg?nGjcc)QM^1rfW9H+duQYe`*5*d*cz}b%$xt2>=#>`FVR9uo z*^8GvurVFrq%S(Fy4jougPiV=;jwpyEC3@o`QXrm#MH_*lqm|Z@UtxP`XVFdRZEgt z^B6^1JAk5J*bVu?wGh?Dun|=CfQB%BIy`}jUAYuy??Tmu$jyNi}x8t@g2u zM1e);8Y3#W{E-Io1gDg-n%`+<6^4vnM0y$H*xI+n^89DyvUk-U8 z$rke6J^A+O({FdT@5rK+0((s*>ehl}p1dPSzLN|jkr004TajG_2KIj!-y?$@-dX+*J z()r9*|317pLio(;{grzw_mYOIe65kELGxiY6pB=lp(S$DFUnJ!`u`_js0#W&7AL(C zqoj`Hz4&DP0q83srFu(pvF3~%O@S@GgBvhF)6ozoV`wua@YHy zD>lKrZG7*uRB3WQR3rGjMVl0h^Dl~uIXZxduIjp-yG&E5eu*g`(FynKL)XyoN6@6` zG=g}X_*jEZCmR0=y~ztCI0PFo&B$B@)Z>b6SDH_bXov+9-SJh^yx)z#nw(tN3!KBOFV;pwG zoAr~X&AU-=B`pW;r0QDoCJwZ9I-bfgo2+Dro5Z-a(;;rYBHdbBP)k_awaY0YG8-@) z=g3X5Ze&e_H5lVrT~E=rzb0E2XP0Vc&lR!6{{DaV-gK?aqgfmM&rv9Rwo1b_bOZ<==-|4KIRBuLcd*J5z{qkF za1lWE_7+NogC%LvuMGN3`VGv@A$N=WxKgmo0BpHRYXh^{uM}CYoih07q+eHr9_B@$RO*Leh7aI!zpZmyuq$gbcE_ zF5Zs?GL~0x1?V?r`Ic~V!$HIjw~A*D3Fpz;zZOIxXE{VoUJbZcWwH+R4mn1(T=1{7 zO6IpMgN>n2czw?rKN`vM4m%DCgfItlzeUGL(KgxoK{+$)UqnKiR=vqY$1Wd`x@`TH zcdozjDD8-mQ!TS{3<8%8%#+zD)K*_=kI%Apfui*HkabpTksgGP07~gj)$?J?B1yDI zn$gN9(~gVe`3iF{=^t!_wDCP~fYPk*8_$Cb4jxxHreb_>+Y?lR6{WT;Ijl2&1YCvl zC6F8y>in00BXfUsr9l1i1ErSl$}@qP)iyFiOY4k{EGV9r3p;nUT+(;eGd(-gmodEO z65FN!LsV)Tw~_`aNJ#XUwIDVW7Gx+l1_j+v1t#$NSa7;+bz37ihQLZ_1|ghFKV`K@ zFLH=?@1F)1e8>}KEshZO1EBPP4YZ^?%l$G1O%cTO_#uudi% zzAsSlR5S-jrz6?cLJw`1LZ<`WN(+&ycyf-A4#P@w!uW9tUmd&UbPR_+73?D()*7Ns zJ3%Hx;|bh73=q!yJOVI!p~EjBKQOHWV!w@+5qzXZ!EO*D8GLISpK<^CuyKh)@)R*S z^sqaC>-v>f)Qre-o_v+nA}o(G=99v>*Q6Q<8_*$M+@*g*2Bp%pD-`(?+*A5>d3voo zyUK^C+oRR8VM|tD6^=vaB=mNfAWOXl=*Uc{8xz{+5Xeaz%?z8Mgr$9R)?jDJ|=Ca=Nb? zsR1*~0DHdS@HGHu7-Ux|!z9tZ*n{F^?~rb41LjD#96CvMCt$c2`?%q&bjQOPal`oR z0H3LgUS|)!Pr?i%D&axt_Vw%6?`Iw!z4!0R)>E(~HHsf3xsoZ2?wFav!O*q%g2QxO zWoH|k%j@uf^dMb-xwf#p1+ZTKh^&>@@xQ~&8j@|=P)@cP;oc)dJ8~t#qx0$0S8Hz8 z!W&dQJLns>dAvV6m=VXhIvfidIcT4(4!xz#P#EP!kTebeN<%Uz89Nm@z1U zGOE7OxmCDQyKVLy3Y4ZEjl|N2tm9&}h zTYiFbQ%7XY_~$4qV0vNHQtmV_PV=EQPT#tkSHx`f5lKd(mAQlLj zzEp%+7iYpMQQA7M1zSnp5#?OwBD~|5?q`aD=tl7o@i;R{)iZgb#4VIM=Tp@&&P+Py zFnJc-NbX-95$xckW&dM<0y4uPKmq(Q&V|=noN>s~PfvqSrMuWPC!H)Fb{~=RCjsl~ zrsKc5Q{kn?+$sC~9PXHV zmfj`g_I50C3;;U*AwM`2PLMbEp;i*T=~rFtIvxj!Asel6;ceY!G%624c;SQ!8Q_7zmu-n*`!nIsXUHv!>V(R&=2C$pDlWr2JjkV``abfy{W@2gMa2Cq4(`WU zFwXEzY#q+jW`oXG#y?EgdjLd!!sCb+X>w-Dp8w(p@lQExYd^J#bvTqH{#YAJn`vN!r|UEj z+WP@!cl_i0gx3NJNyIivRL4)H*?zY(3z=F8&`qd^uHU(N=W6q?JDXAgVX1q(OWpQ> z8}z4~zf+8iasHGotXpvIiFk3%QXHQ`if70GVvDq5o(0t+)TGtLIlx{<+ZavoUE;@h z_^@(Vavg;{nMz&-%tB!Wl8Q*ew*CRoHhL94viv=^MDY{aB@iEngNLXuf?w#OqJ1L4 zEih!5u044kQgXDDJ)M4Mfb{8_NHzicV`K@`+7FgNooZ<~s)+cB=7G}cZ%>X>%l)_T zXrf;m4&E|vAlt^*k473*YFKgt8dSP8a7jRp^LRikO|y*zNn_{$XbN(d4YqBKLN3w= zxGN@`8DWw?h1qrbv*Ey;#2rLZS4kI3y#`8cLmI*+QaU>$YJ{n#Y}Y&wv|>qgAsF@^ zSWl#r9ZNje^7<6OlQUDDBG1=hvwB3;UIKWA4bspy?$gB3F~)u%@h#l&AjP!mJ^sPp ze{R%%x_R^d{rkg7VMN48*Z8AKn@Csq6)+dt91dnsmjKHM>~ctwbCAy8iGROH#qd#n ziu_$;9YksLllUr7jmDc#7V_i}{t@^uT)8siCaw~V$wJ%?7$UsMqOU_lCo)Qm2@g*% zF4`SrQx<>=zkgMn6HnpOS~{z@5!Z^qeoY>M=lm3cK##muy>^5$4osSC2~oZZYH6cO zF^<8sKi@+svolH7f^b)?z$|R2KFK=tbik1S&*nbd)X4Q+9Jj%qnk&6nr!CG^aXk7j zvT{m-j8|&0BXJyp#V!0|N45m0A7(t>b@JDu*^d~TQ z%-}|(_=8&4PrNnS)7AgOt_{r^oGltW@9iLKruE&Fw;)) zqdVe*+vxSiWpGPNqEhGe=F)&^ zKs9E8j{fNx;yjVGty%+lq(^{~X{$YDpG|xg9u`C{Q>4u~6l8PkkQt9y->^Uw=4Du= zOq^G^V!qh`3*^g0)zCg^9)~T-uyNrGw59?DT)#~L6>HusOLQv6(?dk48r-2OPU`ANL_L^2%((mE>Kfn5Nd2fAVeHnLu`=ntDQKdH~qFDs` z%aRQO6NmV?NTm$tKq&@js`{|#ILb74Nz6xeio)AiP`Qo&1Xz_?4;RUn2-n%(x-Kj~ zez|R#DDW}32C$&|HY?{UE+MB?ZljGXct`EF#?J#6YJE)wH_{^AI1)_TM&S_2M@dx@H0KRAGA3nCifgBY8^>W37f|68GO@%;eBdKzAiIEQD0c=A->&cuqdF z0vP5Vo_?6EuKlFW9GntK>!1oR2zwgUrW6D!dFD5_q`)|n4WAU(HQ?NZiDE_ zZDk*dmgu;PqGggkyEND!QvRmXEmQBKkgg03QBg$57Kxif1Y7DqGR3$u#otsOkSw*A zr-$vP5h^T=^n(tyA!CCb#-nO_xar1#^w$Rch9e44w|mC8JSK* z`of+xb2LM5QuuU1hcQ4#<=2o`%=C`)y-w;9{EaXOS&m82QFx8;^>d*2SeCJcb0N%H z&hi`;w<=_zo&6zXs<>>|QiSEb(|YF!8E)CzGAQjqP^`EZGdgIec@+*~Dz8c8H>$|% zbtR<>`~%OEJ8A)f=QHK61zzO_bOXq6lG54}FyG07@+OvqJ|Yk7;u&UyoUcw>nOukD zYXhq=mzBst8j;i!t#}^T9e%_4U6~ACd+smL?(xq!^M|o#uK2W1$29Mfg!@$>a4^7*?`(h2Ov=j?oZ$qgog zf2t^$Is_Rjk5~1OXK2mCX_=u&%H<%baZ^h+Tt<;tx3-`Gmq`;*B;I7NV{n$DVAdL( z8M2TOGm|-kZqpB|wc0A)C34f1@*e!E>IiJo7n*#Zt|{1+N*f||%k_eNZl4k&%Gb$B zrzCXAZn3bjy|VKbTCS}%ge0ZT-E`IRs3wCA80N*xmF1maMF9v6zR?Eh_dpmaADy#D znh1plb|Pg0b37aj;8D>1!}E^I^Ddg+W7mq*3{zSQ`=IQmSMiL|$DP|~UA85QvP?Ow zgCgU%R;E9}`&n%QMt_+aT?=aEbF%?IJWua@xHMRL7^4RCIu{FVh@9vVVaaX%keVf@XFRQYZ;Hm(i-=g=0`{1RI@V# z%p%FTP_R&CO0_TF6lzT6jPcM`OBNVtYvNdsK!pwc1`0ULF- z;l%>QvWE4`jNpawviE2?SX^Bx^^wpBb_-~N_3)aP;K1-5{mq#IcLIw<7rX^>!qM=v zDiqD~Dd$n69lF7heSYUDQ<*b`IhGLhp;P<8+%5pn>Fz#&jM;g(JAZbzgyeX;TkR@x z${ne+Nfj-O9IqRYyDqvDv?t9nquH!>nx*`xfI%w=E*~vFI*W;~Sip!?I>#*3_G35o z?n$qG#>#*28NrZ9IS-B#a7L;aI)7o~hYk3WXf3aaH%m|U7B|)(uRIalrRM{zELB$E z!CuqLVIeP{e0gGG9VV_hO%U%rpaBq6>Zrr>qeedhtQ;BWdu>=!L;)+H1~i2&Y_ula z7Nz70XQ!YO=LyxYC{2iXggO7`}8ZKcOiHMA+d zzv!At*O4%=lIv1g*xa<2!men>O!A}h+q>((O0KQ)bS@Jrvq}y#ZJsbrj%nkdR-l9{ zM0pZqu1WJXuJK3?&WYziz|D~PK89QAalLt_iRwaPfbLvEOxBTnd%;Aq+ds*z!3nxcg_#NGqY20wSA*7xP<4uB)Qx)W9tm>wLXqf=0t z3~LD~lSa8h(K54MRm!RcV3M*UC~hn$f|LsJYcN}Ig-BQfsR9=_8lS0bgsZ36>X*)~ z$x=n~6a4i4qLaGSNe^}4^kL(p@2ju_!qSKo@E00X&zvfD?XzUWJrASUgbGlTFQ-R1M+e9d* z{q1SJa=Z>Vb`vXK@aqVT=R2M1Wzu<+Q6o{nFMt^rcQ?(oJ2i}cr)3LORom_idhkj5$)EDxPFiNn)!F2ijg~`{4Lr|EGn}o@VI*SfzIN;JEz=J{3nO za)bQhY3=$`a87o+2Ds&nc6Yy-@6LV)oE`EDdn!qqCA@OVX~(F3wq4|`Lx)vxP+*bH z)O@vDruQ|NM6ptrUT&?5XEs1_23t6V7GYO)8DH(!lL#g@J^gwF+uS#U)ZT%(VmGn^ z?g1~9t`5It{4xlwj8_ps#oh6dcD;+ zoraMpZ1h9PEWh>X4p;mHA-FvVLwc;W%P1=h^;mn^0aX@4ltAD>752jF2|Q% zVCwc@=lV*v9|;n1*{E++?m;}_P#y78eT!d2#`fG?*2HN3V4z;V1O0Fb`cQxC6V~2j z17s?4SIbqhL_NAIqP4bjUWdeyX1|f6vW1GFH4JZg{B&0Rud{tGe}wLno5^XDtVDNA zH93Dv&%_bqw$l$`8?4z4N9y2cnHABYzK$qj)oHDB@C>2b3SW zpF~W`|0EEe*nq(KE(T`a8WThe(t^4Pl0=?P-moCfhXy%H7j^)|L*zGR_=d=04`yB4 zv}G)Jp@y;FaEav^ljlV6$(|+)sjRfLwkgPuB{%WpNouL&d@uLGKeuHjhQ23SiReQM99{kee$D&slm;%-3S>{JDI+x@e%cARg` zDqooC%laXw7?fiNNTA(2-D z2ee983IH5BdH(yZ6V7p1fJ7+p=4S?0qQ(bzK{!s`Pyp3neYSyw64`gb%c?v@wZv0! zJfvwFQw)RBydUhJ(jzJT=%U=XcKfEF)=Or^(mbK0cEp>p05msO?;cdoV9X?Ng7=ff zNm<|>ZyMRgR5w>(7Q~yt51>P|a01xeT%&6$S+q$VpSz|uPf$o6%2voMlNa^g2O@=A+1tt z)Hq#Xa;c#{FeRcqTGy2KrO?E34O)`Juq>h4{4INFRu~;2ykH=cd7lA)MYe?T1EY?F z#?&Ctq@g?(Zd$v8G_Yj7MR@2p;fw|6{p0$<379#k%ViCIs7Hp5TV4Y6viQ4S2VcAl z<(i8!ym>ri=o$6v^cmYSLr)lwdk(6q=H{(U=~XP+#1Aen zlCd9jYXMgVwPmLbzQZ1Zg0bTf5||C~?bh+lpoCMfNwTgWqmA$96|Wpwdi@l3lz6;= zHf1TdAL7z0n2jpSH~D1lAARB%>l2s6npJNdK-&k;P=pHaZlV-%N>ld?Nhx>vpT`JB zN`05F_e;((P(0>0HGJP)fE$nfo|?k7fENif1MS+sn~Y62jiI}}y9I4gp;OETsgZ+a z>IldUkbG9$*gdF)ZNE~t>1mxVp;+%2=tETs7}lXkQJJqpH7;Y<{w*5ZHB&7vpQ6W* zlX*62pWyFMrQ;^zTPUq4v`|B99l#$hQiIImGz_9AW7ZxMQ=> zN9SI0b`GyA75zZhxG~>V-#Fh`tIbTIo~2sD(#?6XlA*2jncOxZ>j9JMZ7;Qq?ZvOj zTYS|7h9t`w%Zu<0(UT$iS&FljGM~vj?QNu$T@;fURc}(=lN^P-l4{dtY$BQHjB)O3 z-9(&3OOrDg!ov88+B@=P_z13gFF6!0pLKnxI;5oZbj#0kflOg-yIoJXTi z#Oyv~9xw?RRWe99iRGZVEIQT5>5w@x6Z9_62A+*~1&7l*ng+uo?=)T3Ep^5 z>Wq5m^j(~L4V3b6$LzbFB z9=;|c&N!xXgJ%W2O2F65&7r`K4gwbW3ccw@IvE)MVH^{yP(h4Iu-sK`JU&W;u#4_* z5LUZ+T;xZL)ebcP0;U&H@2JEoggpa+HCHmME@siwq%6<2H`Y~Xgbg4LLK($uq|PFI z(p=OCUMgV$)ahf;3pRlljIT!a6`PnSijEFu8rf6pOW*fzWZucO*?8t)D#=Ie{IbgS z`j+D-vg{wRvONKb836~MkVf~b5tOn+eYtiHr2}bDVi7^=pe0gqT6LHzB=3RxfgCb- zHEvZ_`wjb)yLE@n1|lQ7W( zk%lcOJ6fXmr6Qn@3yesLLCpejSQ$=UM_d}tnHbIV%2fbee_;b4in79gMJkilB`Ldz zF};Kxxp2WQ5)8+c$2Ksb5nR+Dvstpua49I7O!y^2Q?df_;(CmnvgR#_RY2>eOT{l7 zCAF%=WE6lc?{pKi8+5>MT_us94q6lJ{XQBJj{{Td&kjVb=_Vv}rL2*eMq^r$ks%&^c8~#b1Cx0ZAQ8q`~(k z(K!P2=12(*KEtgHNal$+H|i)wqbo`Tc<~~?N>A$Zbx#&~V@Uw%lUQC7-*Gak{18*^-`&h8pY zc)XIB=@nT!u*&Ztvp-qGhdyc{0~fHv^6NIW`;0+oHcq6vV@dfajW}=|TH?x!_ylO5 zApnU-m$pq-?b;7OrQi;5HT==Lkb|sKZm9$Cj{_Jau(m=-#NcG71ij+F^m7CFmokFF z0^ve`t)ma{A)%_EJWrg)Dzq%)3Pz1+R!sIgrQ8o#vZxWGWa^!5Fglt|rc(CpA{>Xp zf*iD(lvF_Af$4h>O;*j{=D!moq-(*3m00o-%qoHdAQ1(=gn1I4sfbl#1pF5;NnDGr zzi43P0?C}=wuju8?$)0ON8*oi|5EhZX$5n#2b5ty)ym*5i?S+s;GV@mo>UJSuA_$H~7Wc*PDbO3oEnlUXNyo(oT>@&DetvQwfR{2}s7G`-iHT&e zfS~r1O8IrY3GjdlYN7*OJ+6)7x_c_y9qJACkAB)mz1RQi@aQKIU)&QJPZdrb0gP%u zXh9Jcdk_Tb_;TcGFdktqNHP%ww@F;pQ6E*hg`_ijzJGMA!4xzy3(a;Ipn755+e`{X zh3lR=xS%_qe;Frd7)$TLt9%D{Mp}~BnA&CyhEWvRTgSWWPfHEqYjH-L@}{Zer9h*5kxS>#TPMf+Vhm&FTr89M{;p`o zRi~&sKgt2LI~mzdd^CT==pn|<=yc^c{U^bE?(u^r(P;sRlEJ&F`r-pP3OMlSjp2eixBDrj!5#jIP6SE z%cCiTxKc@>e&tqKT&3j}*(dGX;BH<+y>rQ?`5Av=p`4$%Dcmo>ep^(wcK|vrfBGT( zfV*`Ck`u&~NCvpaN%&)AAn(K#2=CO&@~el+yK=#452YG9pht?qS4bNZ^Ypjy;!K$` zeA^p5bNTK>(=FtKbS!~h{uskh&zV}2nIoE#URQ{ZVA*QlBPk0{5urcIy8965Dw0 zU;$3Mu>;!YKKiP+H+_D79l_i=?{IP%aHY~?M3;+3)BI;h%&ECgvG0@n20M0jha-QH zZ%s_>Iosf?HN_?)LWWIAXZUXf2r~ia!@}E#^Ei{RXD&om%?Bc)9@cBf&aBmlo3qy3 zpZywbF<18jJxHm%B>DbTd7>$0VAp|J6-pB`z4#S)g*70R(XFH8X2D3MirLXnNR+m7 zwFDt_Hvvkk#nFt^-C3cNv|WGZKsf^K(lIq$lX%PE+BR!5$q$D12M+ zX9xdQCm^=bF!pGaQ;<$LiPW+T(~PRtKE(qV+TOjCbT`XQJ zmBb{6t253>x_$Q7k%%9vXJ-GS^7E#u2Hs7VX0Gj?eO~?n;mjA#1`~R7& zT>16tmC^$?75?tw%+;T-Je-Wokqek}?RTj(ildfp! zqMLgyl>wz5Un;PLX5xm@Evo1cmRnN#yf2QQw zlSs8k|2%(wTtxX<`?yuwK81=EKIr)UQC(}GOXiJ4y%b|1{8ZC*Z{m1x!Ymzl>X;Gr zVSq+c%oendb?ep6!EvMuHjv~@lyuBNM`yKFD@aNMYM3M6fsz!NP~?VKF5d`NgqKqP z0)tof$YqP-OXwXO21W5i)5Y||e-(pKHlvSKG05^?6p5G+*NDRr3XmjEgm+7$quCVF zZ9BJVfK$rv_Wnv|G|xYsA^qh-&Mcz!A3z=Pn_k}-tOqidMD zWEi>2Ja;+oHjgvkw(DWdCQ#JYQPBp{xSPTpzWnTY)FzN)Tt6}p@5;^_y;ypIlHMPf zxMS|ap}@O9E6P>!-vv*#~6d#PQgc%KTi+@*#$*>w(RzWWH{5mz-aU$ht&mss6Dl?cSIjg1X-jKI%3Xh{s^X{Muj>PaA=rtsn&^wyX`nR||uH~gMIQ%Fk% zNh%vx464_&#=%K+^6VuPI9OsKyi-I+U--;$ZXu!V-hJl&^{4fi=j@Km zpO}HPtJ|Q*K#E}DKvVciva2SzR49O(lK&PhDRPMjJEXlj9CjCAO1e25B2zcb4NmPC z&4{48NI2AQNjW^coKP3TUmZy5EPi%Fusx$*N?(f3h~x7-%W$9}F$u;?7zwwC@L!{P zDT7Yfg1_hBn`^>Z8{IwBdqx7tgJ>s-*~518t^)PKm0)$nZ@e4coi5+T!chugIv{Ecx9qp-0rD-ITvPhbn=`k5iyw-xpZgvC z4Vjaw-|*&v4+F!`3dw`(9^%K+E`(n(W^m{M z*uk%h;QHG@kPKdL@qz{{CXkd9AC5AzRnymkWC*o#jOwIwQ*j^s`J({R4s^Vg#;gZ+V&OMei>1zxX!6YZm!NH03pY!5U7XA)-BV#%6%En`LuXGw@` zF>89O_$#4>xrdcQ{&V23FL81eN|$v+V}7y3!V9ks-VvJ!;;NsL-s94N%Lx*=0l#xu zIf5wxPy7anx^&P3qxw;FQtgknFTfB^Sq9-! zh5Lt+0HtY$%5N5B*VDNqHrQPf4vXaaNRf|&jsT?5mV8YYHD7}C>LFPg0_ZolmY=}? zdS`EAYiW5az)6mt;H9+}ZH)Y$UND=d7yZtxKR13AWR!mIZvL7aEIS2<%Rk3KhJv=~ zYictDR=-8&iPQApQY)~OgojDtV$r6NDe&a?5Gi!cMw4|=daly<-ZNXoMwm{$ay zH(CeHeyu*|zAsJALYiUO(8=VZ!cS&{My_A(XFmiDZM0ecnVZOLn&4_E$OW-?1r2na z_N8xQz}`oOA^Xf_s?3zhIg2SM@sFbMVhL{t+3Or0sGP&EDl$t}`{ywg&)Vq-dT`OI` zR+>gVmmE!UG9y?0h4>QYbb$m!{doP>^;_xV8n&j8mGKg#J6;>T(whjra%>aFc8`C(x2DN2yxrOiq-jAY7)R=hCT9L%Ecr0X zUl1Ijfh!nDQQxCy77UrSJ>W3cOF?b5nFka7NNtCAn?imCbQA%z~2XNfPCNR5aEz$;FLLxoCZwgW3E6>F@*F%8D5Yh=~|4aFm;}0CnHn&pG=*M z`r}Y3Q8m)|2*&Y(We0H*-3Cr7J)kjgr4+6b4)&wS>3KE0s@2nyb7FIif`5aUpp4I3 z(9HcB=yS%HgPV&zSbS&EJ9kScy(Gjw6G!M9+L0>nYM(m3Gj+Qu<>f1=QgBmX;gzH2 z82=1WR^e(mj7rl5ydj)5M-9ljnTXA0Dr&_nX6DrO1E_dYB^Tee<&iZyYP^s8G$4aQ zy>;Co84Y#psUcO`B|H`p7O7#0wqfUBG`fyXp9IqmrSCp~Ao3J(80f89dc22TqspR# z#C!0WK<-ly1!5OR4i11}P-);4?j)C%1Qv}V zueL7zzC@m-NF_1r;f}?vAd6m^`NFg0{0XndzrJcKqi+KOitZpou1l5gyH{rHbmass zlC^tQZ$c_T(bA%>IW9s9j|>ck^9@m#5M;qi>7J0>Td;*kjq!p=3uC%JyJ_AU;`ygP zCLa6@dcaJ>6D5fCB;|bhXj%eQ?J*Ccdx1fwrBUVJN@=~(?3U)CnL?JpRtf&Q`s*Y2 z%S^5QkOT5(v;@R#{TT2i+@T_3;ncIsPUGm9NLYi7OOiN(zTo_TiFje)(*Y9&tPgSMnwb-kqAd@2$4rnb<3qycot9DAfZ)!z4Vj6TZ0 zjnToqPs6$trNhqTtw!~NMromabkwNABj>^UnSJ~H5$vtCnSDi;N9K;ab%_!PuW5aP zD_#eGJUVG1yTpFiRrd3_t)J6)Rc$dT_Va!XO%YFjUV4BWshycm^=BW7cH#hW z_Fb?ca@2+h14;9`CLYw*p*`;O5p$VpKY5u)oBH%cjf(dWrZXCGW(@d;lcO2=L z;o1icfLNQMDZ!=Q2hC$~X5J^?hrIH)%1W(l(zF!>8jxw&5-fu#(236KEXd7AL2K;F zy;M3^TBMDGLU;3%JmVJqL)%pLK$z+N}OxoihT2>x1^|i-a!cgq6&iy8wZUZ zBAn_iicejX-NQB7hqS~@yIHGXc8T@#5tg@Xqetf{l}^O)!+;idvR#DZNoy243Caw% zSwYbdSD?ADIN}OhZHt!~cAQI%uEJoHRgMN7%&i%Hr)^BI#3O)fX&DxaMUPcQIhn=kbU^KK(D9UP$V;!-UEmqtPctWz_?kFrUfj1)%^lj0*# z0`#b4gMg?(@=*CAqDn%^Mg{>W^bsiDC~HDeM&1;SoGaDZ7cIh$OudXS@|4~F(GjGQ z5kPJ;vap%E0Vqx+y?KL2o6)W;rYoQSe$M~rr3^?(ig0a9ZO~K1D^M8#jhnOOkSg$s z1KJ4m0XGPqOyMuGd;bhBn`~oLc*Nzkku~@fMKPxn%;Hkp1J_83%T6IW*7{=INroxa z`ln|jp{Bg*r`0pA;TS1`d)UaiqzA7KT*kazhLQ{b0-3z6Q~=U5>k{ub@>tFVReGtNqwK6s-ek;dGz%E>$%h<`AN7080 zO?}S&LIo)Wj+7-;@?RCi|Fe=PQIOCvR z0uupGaXQ?c8Q~Bn9h^M|7c`$tqqZaEMD=W5!kNN+!KRD|as>yP3V}zX1>;*}7RY6X zMu3Pb9s3sfajST=wEh7v0MNBlKY(*0ig-(I`qE_HBuK(R>d5bmk@9fB4&Cr+?_XyP z3F6?B0dNFjCP-BF!}kw1H*3SoB7j@ZNZZAj*xgddKodlc-we5E+|!GK?FMUyUDTUP z61~-;eOTe9fql7$Yp}&06R7y%1QV8wrCO`DP_rGm45hk~N-vwnWiexR9_lzQOosRR zGLBD*DM}U7F=Mg*BUJKaEgaRk%*`!stgX$jFM<6q2=OY(bof{KzQV=J7?2X+wSd=E z77qze{t}CjpHsFtc`kCw74V6z}&++o>~T*jmVcfdLisJhT}OO3_Ljcf*0QN9Mi_ zxtJ@Gn@V>eP^y%3n+5n2F>LuW6)<->lNGfL=L6%FKTVn?%Nak@BQ(XCRv8G*jMt(^zja0|@7xx3gRZKiFe{ zy2bB#Lh@7Aav-yCaMKS#BdJ$WI*g(-$z2Ox9cSC{z09eU*!WMe(l0Jn`V3rmQ5jM_ zkT0@YIBvk#4&79vS;|o1n2%Vk;x?5eHs0puoM#rr4 zfl(_T;y-d)dQMKQjj! z<*}xy0hF917Adzgs+WM?a_{o!65lHi9z0my*qPYDE)2e+l@oy;OlPxtDV{t~-idsk zJ`?UfI2X|t7;Q!S=#>5j!ZlcA=b@D&azs2QntDDPY#Ncp?uxMIh3viq2F~)|#qUd1 z@-*9Slrwx55$SR!l|&p^gi}sv=vpE?fpK4LBg0GbB?t0Xs`%YjhAjPNdu4!^44~wJ z_o=ZGE+d6FEuT?9;g-S&y;N^P&i?EdK%90CJV9!n>e(4Q6>RG^nrza4Oxka9I zQO?M_HiUI7AUTnJr?Fp#)G91~MP0Z8NRl4CG5MUnQJjowLQ=IW^{}W1ZqR-bLB3L^ z@HbcTg`5!LMo8%v!RqubRXPk4E2gy%95oyg>^@!W3PyblO+A=(jBM>H&q8mZQ?fs-pl{C703y+#2eg#p5c9SB=qq5za(g?F$I$ z^mW%)s#5;Gi?GhY3w{bkFizecOF=BYV0Oy<)lMVQy11PKku4{czuJt=us_mXZm!pq zfdHy+thwl&_N{HS40gvVao3#xx&=s=9MmoD8Rx}~#>vCV{DDIKlv`HpmL`idC_uxG z69@^k>tnfUBIHyOA&f>2i3lHFAa5qp(vAFu=N1l+gg?rZXU>IzYC3bYayK{s_1VWH zUtu`VSf^EPDqWFsM$vlwVHKQEA|$$H1;V2HC?Jm%bRL5jnwzs?e*-p{q;E_}n$k|w z+2w*I28k!WzAm zHp54ky=-;+XJ=AUkaiw8=anYE??Mw@+OF42$KYVa{F81Z$$G64T6hcf_Sq2!ZtRak z?^IYI`wdv~#f)@-ykRtx=|_5E@Koea;_aQVMP5o{81z{?-EcD{zj7Fduj#geS!@ve zOzrm%PU;rQGcbp0C*#qb%U~6*9MP=lwYr6ZAJb*{`)$%i!jHKiYM-BsrGdeKg*V)o zJ!opehu1Y(g)WfSBt3%89K2<&L())r$vCB|oQ6^;-4?47E5r@FKETJX(&dJ7hmU>R z`u*baUN%!PHClU08(b%u-EO`Ql1G9`xM_bkq;Y22m~16)N(4!NNXDe5xnUa>fy;KD zVej!?h6EvOt|9!qO&!kcusoo@PFbfL(LHDH?tBdvY_}Jh7b%n4-;hna?zZILFLyd> z1ZQ&!_2F>fP71mjfazUMDHvVNjvsXQU2QXh6ZT<#y5rO_DH-s~v{Kss$YiMG;(gJv z#ZS1Rs6?6DJ`!vjdN}|1eACNgbf52HZDgP=^pDCgg<;Ug`2>vCWxms?UP|xL+6T(9 zVI5R^Ib4Z3nkT>0Ut&~N2dkM*#_KPsI<(Iw^j74!YN%asY{zNHeKKdhx>0REkepS2 z3GP8j0;ox%5K9OHqX(oAn>f3X**J%ejk>+iyBLI}fn-ThR-~_0cRI}Qo=y<%w8rYcYfn7rGN4R11vg5mBEcC5Kq1LC*7TbAFQ2KmI(SO72N@NY zB6OFKj^Db#tKUXa<-*^I((+(;KUph1qjFHgVo0(F55;-Rvhc~wXtC8ti%VE?2ODd# z&8wVCz`2OOa|T{I2wb6!_YwCFf{gNndmTqw4r61W02!{?-m3Td9fp!Z%`^R}-f81b z!_AAtRK4#pJx(S%O?RC}S_wk3+MQ``n80B&mw<{n6@LJnJlM#Mm4P6CoI*J=EgGI4 zBTY+olhp^vogzHlJ@U21>XXsU=N_X9J6!3XX^a@fEZ~=qtx_e<@U8bOHH4_&PW$7f zT$bMm2MK=WO+khqWVGA?z8t`y&Z{Ief{EX{FbBgWhpudJ15*+>zrMYqEhUwvFuC2+~wueY~|6n%x6ImaItzQTxz@;k)k(&q4`Ek5-Z*}W}nQ`K8VA!FPqL)UM zyEb{EOngj5P?o2s6%jl%{h&H2J$|Pu_JxWD$I!B z=y~z*L8C!a_|r48%eDaw+?4ihC?{(xG$$EI*l76L&~G-dC^%u(8;s`97!@TkXY@~` zBZ>|NsTfF9Am@8?I27GA?fZ>fD?!apKRiCkx?+BuCb+#Nq&E-LA+sG(dLV>Y)% zC20DO56rkeFyB^!+mM4FE-kG$U;!;XuS1Aw_1;5#c+lb}GbjF&M{VFfs+QroVYIXp zoPZ9;jeP{&7)p4_iPa60H`Bf~87k0}s{1FV6dlTm>Pv4oBXY)u@dA+b99b-v!7pU;)jLXQi0at!sZz=FwTnFxlb-=a#AS&AbY zJYa<3AZx}-zrv##pEUBj9UQ-AiPU7hPGjm0UV)lu#f820x(iyF`QW8nDaI$wjQ06v zMxq+6-tUY|vd;^V?AwH4*rX0GYi-+innFj;`Tx+)acL*0j36YO0~yLL9)$X<`VFgY z$+uc@?(3<~zlDe4AP+`M88uAPCHVel`veA)IL>U?x<-9dHXF<^gjmPYCPK8k5Ca~Z z)sP0G8@mwt1PSA5?6&Hs?ejX$QXUOB#=+d!E%DW{&%U|7t|K$%y$cbs*M(7E=LoHj zy)^9yUHa@-dfDZY_9ey;kLGXa&dsyrjCYiCb>Ga*t!(ejZ*9%LE&ZPUCU8RBjPy1p znIY&4?aT!m>K54v^>u9 z(<>;XKJ2B_8)kcZ(&TXtI%o96Uwo60+Y$ zmhh(gSf}LP`hW`vbdO;t@c`IE3Wy4FCw7Pr7m{Yhw+Youqog@i847ar6#WP3&Sv^6 z=iO%MO%pwz4*}&KTqo$PV8#m_7Jah?a3;{Iqvje0PbEK1x-%TK+B;4;0P*`^J)t~M z@pDI8X8n3DOyo;ZS~?OU?&qbSOXYxlE0^F)Y=4)7EmoVo9UUl7={wFygFV9woaGDO zimY-oRUokZV5~^)qKV*Cx5E^D`Hx<|!>{WwXAOAQTyVS?DHuPGhZt|KUdVvK<_ixM zC(<}DxFmV#hewSgLFQ@oqz>~BBo#41YXWJp3)bKu4g(1y13)h7E!Md_uLnhGp}tiw zWw}umj|4EXh4^trDl;G>#R>5t?c&AbYasCjq5?q2M0|b6wDQt8zrdcKH?N0GCObi$ zZu5{K*^OT|yMBVzp?mIb?#}+C7~WGjSXX9D9=0dezqeU+!FR@IwCTy^8XI zB3GFtgks?;;D;2g=mzC?0@n06@qYf0D3II**j*mFhQga9#e&@FW=BIoI~2xD(!6Ni z8yFeUkBi3l%!#ID)SPF5erYQkOHJlA}s5-3dD=!$L(Q3OC{hC+PyU10k}l~BIZG=%;N0&1GBqUpJWoD;R7 zqeIO?GkEtnj{8ZlGyfAk{~UNE{@Tl(P8$Ifoe4PfW8GMbklEPmn$s4s`G(vt)Ts$0UWmd0^6=#V0t= zeWdwhdTZ38(X#(Ji8u6|fVlZqHR6;fHNrIfP4aH&`@E!y4sb?!+=#v5Dr1M_!zTsE z=ZEq{DwkeDshvPVc`jNd!J_>YsWXb_{!=n(6i@eMi8bH|#9Wqn*$?2z!LJHzPMXYO zDmwBU;}qH1zfJZBr8`0=a+a#!zCLdB>XhBQGrd)UbCg^xc)k^sEK$?2?e zC{GGimBhEoP{BpZf}!{tKLbc;$*g}osEZRAt|#@632pD8T1xz~Pa&^GuTQrY5HQPe zK_`LWwfqCzu0)yc`p_9xkGDC}Z*?+YlugSWiM&uYCriy;&-71mORSFrHU>t6cIV+1 z`M7EmMN%0lehsfAFkg~5;?1QLhzA#<06Bi7MMS0~v^~%$MR5H(Mo7rGDiI!GG7Ku~ zh#}hg$yDD48nc~s+J+A*#?n^4|y0QfJZ?J_<;07 zZBd0+$F)*@=4b}qzU|rlYKNv)`*rTd%=MY;!3RJ24<=n}`DAh=+o@X^dzkoQrm=bt3>cGe?iZw8C^Z?FctoNL3aT;C*vw&!Ces6-{#i#UpY53 z15G;>`3U>oM*AR8Su))twisTcvm*a%6dm2jJsd7a0s^1ff9&M{&F$pI2YRn+Ui3p9~`%#u|m^sAE`olNoiNxhg}WX zuhsL%2dg@Byc@QQaG-c*XLm3ihByvINX`uK4Hz0~4XCrhF1jcuq#Hwgqy=CGX2-vQ zMW2cZ=w(JJB??;vH8@_+o=Ouo1yD3E7h#uVZgD7kMd#sab@Puvn?W5$P6Npxk)tc& zN7qV|pLbh-KvR>k9A&K}riJnPn#jbZ38QO~vc_vysI4*eNTF`&J5*Gq!vHbL91MnO zn4EGcQ6YJojgIqmtGQr(j&HCUH_mvg@xbG;@~pbZ{MEB{&m3b500+b^zvpZ}Q{&Nr$ zDo8zSrx0TybwxHn_d2M=ksUK->~I~*l5|cz1%f*W!<+c|qOLZI#&}yB7Yiey8hpj? z0ac~wII1B8aN+>{ctTi)JHwUpW$eQ?j1Y%Uc5>H^wNW*w5j;CI{VY7X#LXod zlddj_aw_vcMN>>a#O-GMg41Pb83R*n1wPWqr?!D6_1Hq}0$e!?&q znNb@fY5yWBn<5K>I@1BK!u=M6|AZA1_6yPgLAg-0q#ad=+t0?Rx4H*pU#IojW8-b8Uuz)SZfPAJB~N!^}22NvZz zoHZlQ*+NHvx*Ak8i`mw{hOfWQ3FeEOFFbVq2bEt@7n@NXa5Q@0MAC1DFMZxg<~!u% z9IC!E|6XStLtK;K3lXm?4RTRWM_3i*@c`5{?Q#IH;7Lt#_n0V)(S{;Q)sL%E+Or#p&r3`=iE&9(ZKN_nS!d4@@`wm~OVMC%Fk&1CLc*x-7T zGHm;(GX_G)NVpsU2!{#LSB@YK;j+DkS%nPsG9h+w0I7En+fZ4FN-24!tROo`ejX!* z>pw1e)8*ySzva)Alb5v&8gx@FUiKQz-OWy$Rf08pigRQ8(>wrG z)1~VeX%eS(8`fpi3>uH2aM}+UCGz z=CpJVXHMudUP>h7L6Bu8Wt^xJ{X5NvCdkGG|8&c4G1U9fIq@haG7c08RA2)|lpIi4 ztVT0rroNq@qs|10U)~yb_oHmbiqY!9NY}qUr%%Aj-SUULMKnmITt&LS?9jz&TmlEm zfipPmJ?mpYL4hd>^OgjeVYchwxpcoJ>q)>OJxd!|cdpT?@;WuJ*a`HagZJoGFq#9U z%uK@ouKcyllw1@J2~KeL>k?kwe8wu)8;x~%77AOjK)1oI0r z9{8J($$9{Vvzwq0>yg@4mB6q7CHLX%7!*IbVs0(Yd7>50esGWb7sOC{KN@Rh@FY-6N1;#e*)M$&bYmY zHoPei0G5M}Pa-5(Vm%9S#(il7Cph3KkV1q=tFReB)&UKha0~NC2N8%4J^0&J5{?I} z4T(v;1-mg<=z14vlhIy~z;~+Xl7cZ+It&L+pW_#wp?TH>&#)Y!NtpRZ7# z()a77Q)V|u!l)Lg0kRWI?1i{xAOfEPy1^)TMyYndLmJYH7`^!ytTN6ErF7J6?;`@v z7L13P6LJ(j(+<^3@FA(U&KsR}OUM%5Yvs#4964-C#+sYMV78x11@iS3Tq50GfJni~ zIRZQkJ)yxrW3-`Ojo?-o>f;g+2W%3XAcwV#NWARiv)_-A2|=Wsn{UdZgA=&^m;;Kg zCU*K!#AxG`-732ol(1drN7v^&?Gf1g$vV!-v)k3IZgchuhq#bvrL0k$^g};P-{fSP zN*R^%N;6Q!A*aW{L$vMuqXHRM1u~MlKoW5r;&C0OFA(lhGlA-RGe!qTHHUQ>RVOiC zmQKA+k~bMtXoxPtsgmv18huZvAm5|L7d%KGT0X}Hq_4f+b-f3C2K2Y!!B984xw&w# zp_Jy!gxH8HOIT;#eBt-wO{M35L^L=tcuM8H8qzn;VIpr^&Py9yJ$cn*-pn0b{Oo=yBN1L4FcDe7 zkqADNkvI0^ooZr!^~B+yige>uqyyPk88eD#|I^+_hf2eqyRo0tqW3Y1+V_6rmtP;) zUNmqrhrgA&Sr6$i%wL|4q~B`qBjpB+Hpl<^KP^=9X_g)!9YDK_c%DZ`?e4Fg3^=jwf7;72&*gNCh6r666bq@v~zKIEkKLtmLHT??YLQM*G4TDC#_6bt+W%@$5 z3A&a27>=szlF2SLnJYeE64BV2>aJ{isFqrxBdSu9gsBviwQ%$NF{WVT^xy8;W+k#| za`bq-%j@`$ptydU(n;DXq*xo|L+La~E$ybDY|PQA_RJYQQWz5pWS@xpl3+0izP9C( zj5BCLcZ(}!Jzh7T`+UTN=GvJV5cGJsp0xUSl=t0w z%tBqO4b;6nJ#4owy&~2rTL0~uR*Ob~3KKNjW2F!IAnCzXq`4v+BBFPV7(7_q6=^zg zX3l3A#IGT%qVYN}^zzYi>aYxL4OE08(W?s02u38|a&`OxX+b!kZO0EPofGo97KH?@ zx*kYYg2W?{+R%I`>$LztN{yq$CKg1KOb#Byg$J=`SXmry88`w1cHvkS#-m#WrvvA- zCekIzU>F<-D{t?>jj^%pNn)L%XdMnfj2AUxvKIeQp*O7JIc}|TU-(z)ac~&%;$#Nc zVnibZ#WEsfoPJ19#ZM_)Aq5vLX}CU&onS0U8(R^(vJ7BCD#HblD&@CVdR6*)&OGvx zc@CRZRa5#2e=d1|q5>|wQ7GWg&22Bw!&1AqKEJk%e8Gd7Jbt;ly0iRdC%8|@z1VMx z*OQ_Jp9s>|O5^mbNhh8%6KVzls>}aJ^)#;PNr^?hV;pEE zfm6hX2aRcbHfmy?j`IFr>SqZ>&-*;9o~g6TiRbI_!gezOwyBXv9htdvf-~t zYVf7@MXT9Hsmji7vH-7P*T#RE5TX3e7?ZgBHmu7aAtJk*$BmZmpZ|cmr7~Tu9D)6K z-Kf`^^bBg?uSXa9*UZ6jl;Y}n{TyuG7D|0SIO$YdkE%7W_KtB+GG~pI2rD^X;1J34 z04F0+*p;4ctSxWC3kEc{3_}-aw>(ZW?aqJC6}hm3-?0=heYA*8@D#<>}oJtEFyK%Yk+U($l_Ly~_In-FA9UX0xBkj;aC59uz<2D~TAfkt$oR{`5 z9UQ|QppF{31J2E%A)QF$|QJ}KB)i@do zR5oDxbmUYsGOBN#ZZ7HzcQv?A(HAZ%jl?GPmq3nUhg`p?{E5qO_lU{Ln7$4NRov{Q zMhEbZkyXB!M#=Hem0`-UEO|Xx1~}8<7(%m>7`^)2L_kT0>Jl;XfaGH5Q)BTQq)vM1&Mb z=n?9Z;l5PLpa0|C_38W7>BCmaU|V zCM$c3$~LSvMfcN$84XMr+fV1GZz#jWq;?ePkg18qqtGKsW5+At&?Zbr@9~;9-VQm+ zaON8j5Q`=v!+f*6wY{>jE>C>C*UGd9#cv&y>o-mXXoQp}LUhRReNmraa9doIZpT@@GmVUyh7X-LXfYD}Ude{k}W> zefN9Ff6+G)7@}|J?cE75acg;Xd479&j{#R$Q)v!2vb;B)77^qQcbxC|=l`hqYkc>Q zEB^OexAaPvr*2@F47#TzK4n-_>LI__5ZUyK0JC@6JJlnAJdy}n18E4eB0^_d*|-sqX)R1;>^I2oL?a`Vu)r}p`CX>!(4o!QSZo%n<0 zw-P#z-p%QCpxPoWqyXcN&10IfE~=7&%A|$T!(dnt>IRCA0JkrDZa|uW$xP`g zT1vnAc+*m5olM=H=;mvzOQh!=d2HpE0w_882775M5pa1!^!oA7JKn zMg3$lydnhGN*h?q_V#M&yip}f2{Cyl5Rmf=tmS5bkOLmD*Ysw1Srh(qHzytdXK9d9 zH928OcHYMd3D3-MEDw1oHKfe691HaNK?T5w*TB2s56Mvte72(bdL1)^Cxw}JiBy?| zT=O|{4P0o3wFyUbtyJytYgAIWK&`q)_v9Kq9Za^6@peNs#BSLY?WCd`$_QvClPk~l zrQS+X8hf+Khj_cFSD2ZiJU657VV201slc4+!SXr-=U_=xCZE8sPd-RZn7ytxWiFGz zHSEE4D99^ei;3pAR(kN@!P4@p&6f+$m)}lI^JiiC$;x^OpRBGdmhh>3II*^}vbgeo zetqHSkIQQmLJd0Z!FFq-J9q4i$~A#`|^BiVd?4nU$*bmum7^vetzrY z&eGk(iO1`UpPFypznPtH)Nj@ry?Za-%wNBCw%ys-*{`m(K5nevI)1r&`|j$eTSqsx z7w^1%w!HT0Y3KT-&w(!f-ja!#D`nAJ*^~aB&9PHnGb!)l0y3y$! z_B(gpym;04^nRm%GI6hY@#CjY-TI9eXR{~Gryus0wz}`PKRvtCSiST3cJ;EgaBye2 z|DiW~@8Dp4e&y5k&g%QsD8^LH=Zr_ zH(q^war@St{bv{Z+ugGpuPz!N4ttv~8uj(7y-y!5uP!&9K6`fhsw~p3V&X(IZ z-@mQipEz54b?4yKht_uW>cz&v^`*OKi}$N{_FMJq`{%0%r?0bMg52&du4Qd;3eRmuH!Tb=cV)%Wk~>&q92(BFA-|MB(3-ixbupRHb0mnSZ^ zm;3Ymt<$S#TOS(t7PeY1W}iHNd9XNtu{=Nj;-{bV8Z56bWiCN-Q&N|c6k*7f^A}z2 z+|K-y?QeVOuD@!`-h6(idbarL{oOmQ#nxi;=ET~Imz%ZcSLg57Kb*XUAn>Mr^Ww$A z+tbTe%{QkvXIrzsbl==LTU>p+`C{kkW#`BDZ}v}Kd|J4;xBdLXX03TVaXx={{cL}& zj>~)ZVsm!By?_4l&Dy<>FZyqu@2@TGyuI1~<@Uzi?%LJO!zcS^z2} z*?rmC*_haW(|dDgwe$YQt&5YbUi)shH+wPr_UzWJt*7<-+szLrjmGxvweHg!?-x!E zR!)|mcDL{v{_?3_ds+SX_WIhy>3;QkfAjds%azvI=BMSS7oE2s78aI!ug^E{-|gKz z?;U=;xANnM^PBfhj<3JH)4Te<^?vonOJp^^+33Ic<#3|aUR-;;veCbNe$svZ(~Q?bT0@k8hqm|8TMY_G){7 zeRKQf{`;#pYe&x}I2>-me9+tvFgcaM%1PTv0VdcM9fdvpHi zdj0a&(ars%yExse-KWbRe!Oh0ys7=zJU+kETl{fzq4pGn^K9w)M6Y>s}7BPz;FSd_wc5M(Jsm!J<>$C>vH&pzpA!s1?As@()>9nq7Zx_+bNTW+0 zOX>xH+0mI2X6;&_?lVT2yp-^$q+d{S_UcDa0;0x7yqQGzPFfcUR?J7SS3?p7=3(-T zpOr?AM@ha0uqgrFxt;C#uG~GY65uXefiv=lN}9$YnaH0?H$;i#K&g9?eDMNS@XeZm zDUzP(Jr=BQ%Haz>=J}^~?8auzwLPE_igp@)r5egP`?Y-$SDg|PYQSM~$D%zH?oooyCw*pMstP;DA$SO{b1dr+?O)^{I4` zn?fL5eEh+sOB7*U&}=3tfg-#Kov7%`1HT5(*%MTOgP*f^57BxJ(|85v5v)$;0{0JO zu>rvDi~s8;B$Sk)AR}i7dZ^63eB@H|MFMjQ)6;4Js|dP->!vr&Lm!ZM0PxT+( z6)dr}1rCOEOQ(*JdI4vdOy_-5g2b&hy5gCLRB{N?#|x7xraSO)*$k+OlfM!EFRPNv zj;*$)`Cu?r9g_esvCXy8nV}%?&z+AvE7qzRJuSg~O|Ya=-oV3U7(!D&&GZgaW{}h1 zxW7NsXwND=?#>+dPMZOyAm&88KAd+N>0zY#nzF?CAdASr*l%I=&|_5ian|iXfEnvu zMIz1>lf|;r>oiW?U>T6}Vg+D->GfW(IC)^|vs@zp9mM!7InKMO;lwk{_nDBSKLW)c zvvNF_dI)9nSmdHEj`{vqVij|xc&js4f0i$EsSN3BulyijttZKQx2#? zu+u4amA+`jqgh?qE!3iAY=ja@Dj8bVI zI?$8k@Z85S50?Cu{3aARR{H?^S(k5NV92`z}ZZ7z^GG%LsENN2|h|v}c`*YFI=5agAoN=%ahYC4} zxWfpEe+&9KIQ@^tKWdhk8TatE=Uf@P7sc)4o8*nWeb@BxKuypgM{4%9Y9`Go$fz$P;ricDZ6U$ z>oLk$ubaC$Y>1+Q}P?zuG^l>RpnzbJm5@lG90cdMcwgH~PpOIOBe zW+a%QOb zbPl)9v+{3_mEr%s4-KN1g%_%Ko@K6vpRb76`xCZ0HWVK}FuGtnq{egA+r z9-Xl(3I3O+G7j#77gK}|)M%}PIy4c5w?e9$rrJjLB>lE?ZThxNWistYfVT~VtyI1! zW_SjD)xgVJf0IKNQ zfV732J%Iq*W#2e)-r8cFHoPYg%UtnV=Kz^P`>8{u9H4^|ltc=FWP)LbKb#8{^!n_P z3=@3iq3ZyM7=X27K?39>r(Xhy2al`;ohqc&y}W*f$$%T)7cu;uOYKaYjVL_=+YqlaNaBJvsbYJYqA zHZ_!MZp{6z{i`)c3)+&PTEBu8snNC(fXgt4bn9mSsL|p|eaeme7Mf&A@^+*H``!A7 zY;(JQO3*_i4+;%?N-y}e2sDzBz~!FNg=ORBIbyq6-+e6gTtUlrRiEJh-tJxUCEytq z_lDO*zo$tzQ>z)Nj|+SlV;VK;4eOwLu`Q)m=7j9sB*Dn;JZpI*f9vph4fV4qW6iL} z_0A{*yYm{QZPI3httE}~lUi(_)jsa>KdTLd6LgtkEV`Et3aO6`G4&t3c&WS#7%9?Z03yvh$pV=F8$8$#tVlLFF{RE@z__Wb#cRYfe4quO6W~IK`v_?$xa)B!2?y8^YnXr$Oe&k8;ZsZaC2f^XvN)V-5^foq*0=MX5rnDnugqYIS z@#sAU&oKxs@XJCLTOwkJNN_=P%PX)&7C^v}syqPb!NL;c4%R;*l3XTNM^`Y75jP1A z%yVBQ|0nU1Ij*gq9Vu+#cq42ggLU3TL5-|s1+A{9RGD77;y{c*H#!XWC58~k#f!e* zK*h0<1HF6RF%lmQzx8PBZtwDgb;WEa^^9`CjoZloT!7> zouwe)sbdD;9d3q0_|`678=kLL<_HogZZ)^S;EcKKY>8)_UmdkA_AqQ(=R^ThvGoEl zZe+idU=uL2p4qFylXp!y&h$g7w>Omyqji_k5%lLs1q`jeb;{<$$|8@*BH0VznDo$O z=HC^a#7!P7m`93$b{v;ts`%+giJnvXH3LLaN;{yJzUp8O$~#cxP~^htBlwLtkEd8U z6ZyxA=aD|2WPHLz2)=u()7TgRjd})!bEI07w9fLV%lUFf&8)o^rQPnnu} zL@<-##iwJ7KedF7kQ`66F8L(TxGqK!8Fd3jD_UNd-+;SIZn%Q6;0f0!n#NnV^7Lt| zn*c#flyR*Fp6Y6GGIarb8WD?dNQq9efPngNJ?Sm`i#%|=KPRa=_r;&#z|O!oJjO3V z<_uH&cfv!^!kDNQP&ESYn;c*W&JaU#sfnL4yG-xjr_@ce*5j#4h)qn&1|WSP01YIp zyj_$+$4|%)IzpyJUQ7I&5y1qy(cS$vDfu}rf6_b5KHDZ`h^#>6gXX$&OUhh|uO_XU z>w?5}Qm39Y9ypYwxODee=Sf6qc{JFj;{ad}rgA>wbDjP_F%01K@cbaSM3MBEnhWYC z$GDIa)lW=T_Z^5c2(nbx$>yWeSG5TR6|;gutAj@;)kL`~O;>|_Qa#3L>JS;`i4!Pu zt*2tVZ;t0!hSWS3+e&GYtobAZZbjP`vDAKt)RbU{C@7AlN4~H+VQG?#e&qSAxW)gv zAFg%CcG#42`3>Vn7)-nHJqlcR9Y+}7el+ipUvU>o-nyJKE%@H10s|Ht`k2dS^C^|t zj5CeZF;Tf|H#Ywzc#u#L$P7h{Xc@Zi$`|d<2>>s-HjxhV_uorVextIxg~GIC8OLz^ z#0?y_b8)wHfbpKFh#F8l(<-Df-oj5^1oDjMcQ{FK&BBi}$T#XdCdH1XAVw^3 zbd5e!f(VeK#j22|wX!UI?M(Y=aNR-k@D4>Uxw|Ckh2%w-$_z?{-I1x^W6bZfS;5NP z>yfwi+|f-hNttsMD!gvbCJy)GjvQM_tCTBuhybQnEXq_aa9Yo!101~;$wS+$dJ0g^A3z?2#kf0gQkHdoT=c3yRN8;~t z79sX+_m7SMN~UDUc^lXzxuO-sS!!rQ*Ls6twWQWFmGmVMdVtesne2x`7<42Of(Hz!)h`Mbnnj1~Cj$=x&KTzn6wgU>BC_BB zvoc3dp9=V<^~Uds_pFIXt4zlf-B9wD+{)l<$F+z`kxBT89>m2sb9TY~&8IwU{NIJ| zKuk^>yuaR`h>6$=z6kwoW2BCVr_y?*>$pvV+IG?Mu$gd5l%wH|T!+zHN@azsvkW77 zBLyh-^|YRY#i$?P3%|72GQVoNV2bcrc%Hpu|DxzmB2`j)ABoH+y#gc}ygNAefjDJnak*<$o921BA` zC(of4T1$&5>Nd9?7i)JTSs;#`d?Q8sp$sf z7D!2UcM`TNn#gk-kldCoJ}ke~Da+`+klxszPUdEfO> zRl9a=5R~PfOvY%p2<%-St5&UAwZ3ZAo!0vSc1y<49pD%cyzsNp2;#KV;AR1hJ#Q2W z_!KOjF6%y)0WMdCk|?0wp}PeNt@7O6iS3?2&3k=oazHJQw7?s{X2!CGP!mcVRX|( z^zwbQB31}Xs3ug#g zY3yu*VBK_%Yupx7B%E85;a6V*_tIQbdu-EdOkW9(UcZtmuYoK1Ql%+Y;HSD{*Pk@1 zt|cTaEW)rKL4nyOY=euC+XKO^N;R*m(Yb8FKeS+AKOZ0b85}xnd7s{x>1;>}izu*3 z+(hTLD4+&~9P^b9A$i_@ki{AMDCSM=Cy-0py<)H?<9N^hx6(_pV*|gD6V%&{V~us3 z5fm1%_vU{cQFF0NBDS8(bnLCw>3RN}dim;;_$%25mT0kEJ3ZaQ-Ks@{T&FFbv1JV189@NG%|Ybb`mUp@S$$fxY2%@bwO#^1o0q;5p4`;kQ?bmGXk=jCJ0)}0 z*4IsylgoI2F1#h~4yE9QoqMoV$emIaVX3(9j3$YrXl;WG1jDkvQRd}q+YD>T73{h~ z+G6!kvMEa=LU zCiZLg58byK3t@%dtPYYXS=SC=NgIy_N6r2vAH&uATQs2*_+%XGRnovxnGaB0ornA4 zGM2fvz0)cDm8|Wy=ukGc6KqFYCkFf!h$WggAI1&6%tyd&gG~V7Z{_H?jop4_O|O| z2cE^l$xvMW^;u0?&V5x5Apb4`B;}CnLnjgf$sOv(#rSQ9#&JH&0*1HLa4E+AYMh^m3njjOUCa@WZ8njDI@MS5!JO2%lRgZ40DxD7Iz5t4H9aElq3=?$-JA9e$TlBNS;Ho)LVPizVfQTo?6^B?*X zahEjQT9{Vx?;(Qd3mkICd05{V^eQXJhP;}!|89)y0Q9`p5Qpi%;K7Y6$K+56ic;le zfvO26=Jqp(2suIrA?^Wo%B!+m4Qmp<0Hw)F*X2IT{RNwl+o02}%tu&n zu-=%g!Ma$&MS~NoDwGs9<0cN2ny``sT25j7d+lt}VbTff)qx91FpOsoT3tn6BDoLb zor$=qLRg%;C{TM9F%JdXmrW-k8$Sg2e3Vt)v|^$2=}L8rk$ix%f5tB4 zS#$ffsVLwnu32B5i;Ol(DWV6`F8DTihEPSaO=)F2^)&qhVqR6>$T5+@i~$ zRroPB5HZ1tG%3eUI<{x$-HUOTrUAwqO(m;aciKN5*yTBVsw3zkW?rs!At{=Z=NrDh z$$$PkpH{GUTcpuMdNnwjF;^xG8A&)W(m`yew5eDI*N_m;K%$k&2SoZ?`8vSFI?^!E zyp8#*s|;C*WGm`fvhI@IVlMF}^+7@y7PY8Ig~{vo>jktT=qYD?oLWXalW&!+ZpvHu z>zytY+x)t%ubZccLr!!FL$E6b5}U}m7^&>5)@VpV z>5Rvo-)YqgoGZT6Did+(b941peoYHvbxg^n2y{X-N07-p7+!+>7f45wzFt7X_sm!XkSr-bb)n(ri8 z48pkMK}61Q6s55#F|szNMM0+v1+oY=!Xx2xIAV;+m3+J?m>4B(RJ_a8#8P{r>7lw0 z5g0ce#JRzlq)=rwNC=6_j{Km^qfAh7SY#v3t(;n(C5@;RVw%xT8^@8-T|x@rBC;c) zMol6Cwn0k6xO9R^v=T%)@C+kt5g3XhghN}7chbrd*~PS`-G}dyo6dqlF;c^R#9e~X zsOxznOqb7qtRKZ!>wF_K&+t6W+u^w{)5&xNL!uFQ5|0y*P-UO7HiQR02PNRhh#Vpy zTqR+~ZlN%MUMV!`#bv$(Frq@7NV4^?AVHOM(qJ)21BXiu?E+T7hHN)5&{~Fzz&B_! z9t%Ul-ABxIin~(}ec`ldMCQpMoJ6Yz&U36WV%*3}G}F*B7m`NoDmxC6Z&6056NL-P zkuW&IY`}q5N}(>_t1R5Pofb+(O7E;dL$y$yak-Q+8$z;3S<_&z) zfVeY6C_k1GxY&DhsOA?UkW;S)kU~5}YF=L-2CzXZua40#LUs1|ZdR3yYQdw3Y#2AAZ z7fQV?)7p?VPfU2Fwl<<~6awVD#vrNU*!;_sggo6O;0VceB5PX zzxCdx;~6fki2W%ohir7OzL>s_$Bw@MWgXf{W4JD1A@iXL=60nm1+Mt&<>XXUB%8ma z(hm7H+)Nx+g5Ns4I01SQp>^zh8oV25s|YP$lwjrag&`%E2rDsgi8+grLK4sNVEoE| zQK`Oou5jt+F8nGn3dX_BYmR#n&7yeD<>Vj6<1CK7Fq@#&7G+jug ze(1`#*>{)za^0to>nBAH4rm}Okrp(6X5}Rd1R@9)m9>itL^9xriT4dag$avfW*xt8ULOy%E3ad8@NE=8Eo^oD7>z_Eo;Ym26 zZU-IVDwUys{eS1s4^R8kDGZB^qfh27+W`V0l(1jLeDzn2zii2M9D{AlXv2}v1d2%P zdW*-POG=2_duq+_Sx>5GgGjkh21ddh*-jjTelwm?*L`5iOHxd}Qw3J85}~XUSUC-d zZ-ystPVs+eOx%uwPJp~#_=VH#qs#vanp2R!e;Ms5*NSGyQ^R9rj(YeR?W-R-O=%<) zgS=Zan@;Y#cV23G5KDJD3QoZ0)KUP<8}98 zNYg=oa)=1d0EM*(;UJ8xTAe`4`3tpup|R4|5Nf|-cQm%NRnz=ZWvjeD)k!oCq}pG) zyaMJz^Jq9*xCz*?xGEFS!gxzG%!)j~0|`O;^9nA5o9^q6ZMD}|wP=t?88Ld>(i6~T z^vP}fSJJkE87%dUhWaJ;Md^Ow3KzqRQ!hQ=hM`H0t^^fi;XvT4G>;jGQg)OP!b|&t zO+8eN6Ab=~`ey02>4|S;eXu{Z2>WS<4{eleFV7B-hZCk3bck;Mw3sM%3&dtnEw^qZ z0$HFJvh^s~CnNXk@0ui>f}D2$=yHo^!eM!bKi4ausXx-5 z57szcZQX4hLpP+re5ZA<1+(Ox*8SFOa$1$lxfpO-M+cijLRw(DSwdn(wvOUL5>hFp znc)k-0qMhPwO;IQwfg7uS`LoB4VYm$er!bwK3?4eTZfb^_f<4#2L@BnV-ZN+`2t!? zC++688D0zon4pEt7}DeSSNBW4lcK>&p$#~x^{J5dU zH&x3jIBB0CWhE{Hsy@6NoWdEJKRvwc*Git@8dsPs@}dV&`jcm=>Kd7K1v;)?0W@DP z!9GjYq62>{DRki&F$=BMtF9qKs;uu&o&p6Dy{6SbvodK5%rFdauwCgrQcTZh6J~#W zcDHr!3)34s@y6A&;uIxI-i;{cvBaX4j$k9~k2K@9)oG+Bl;v;?UP)b=!yYWGi#b3_ zV_8Z;suAd1nIc)Bfh(vSNaL6apqM_xYqCkxmI?Wy9(k3tXhCE3%HO-Ua)IiQ|I%1O z0iohB3E_n43Ls~$=i;fGrp)78m8c+3#eklS%c-$+ zF-F)5p4+|U-ea;D$SLEJ^#WoyvLD2@n2+ptzJP_-{`q&ms{+fXvPA(bz*VXw6_rVd z7C;hx3gc*J$p)H%$?{R^;xB$;Cpy~Zo>J`ndxkx>RBwCf6uKqxS2!=D+zjtbWL7Tx zN~@I4dyt?}JdpYq)BpJQ{|Em)_+t8y1dl(q``Yk9`_d@>CR0&=nyided@W$lK+UjC zz*71pF8J|jAkaw^G-&VN8NSTRH@rxxFI#%ktq~^{jRdQqTn;W!>q@Q;unY>!GTn#9 z(%2pYUL;_GO~eN9E$FjkSNNSWDEzE~g$EJaI@`Z%-OGj(38P6k*s!f5#-OoP|PW*>1H7k78HmEc+ zQerV0_)NQA2q&nKRyHoI0b$%Ay1-a!TV}mZw)p-h7vF#U`~Tqb%L*rSt2sl%K!cU0 znn2X(D=|8i7fls!4Gc$p6ugaU*(^3~#?BcGQYqz65Wg$$wk4_|Es+f8udt`)$P{Bi ztFX}yF^~V-Hd?zgiR2709D&AU>s#>BuyJF?Ft~Y9LRetWY{Jfh8>wt$qJ9%IG@vHH!w65g;^h&`6LAn4tX)-|I7GK7q|jO5;3obegO#OB_2z8JLQCZf(1IQTFIIdzup>pEan znin`73j;Qs+*S3@R=6pF6puhRs>$lN|B)Pa{nsv^eUyLotE^uExQN@tf+L-qIADlK zoGX7CzQdjCLEl2MT{`adB#?MqWK{=Gz6547INX!U=dQszU$AAb(;i%c^q`EVh~@GR z=u)3#1#44ixXKnk0)!wBO~fhPe^4MW3ak=#DM1suu)}c&L|@=MoLvLTy$jN1ifl%`?3#Zk|FD(;+G-PSZYkaN(t1QHxM-8O) z?zA4^{sx=g)zwf7OxBW8M@*(W$pQAk03@*yP!r1wYo9YnXmJR(Wh1Z?-VyFfERsmPY>VboL3Gs>E2ej{!bcDwvwi8E^odVL7|AMed!RYhzPoA>yhidjt5z)d}WKdx?~IMslFgZN>FZGC?Ckn)?cP-Ccx!~>zc054WpIb zqI;y8pDjGsE1i>W69V#CRE|Y7D4qRu`_~Zmq(zx~D z&&vn){X5umj+PIkC`-fFCM=zPa_H~pmlMXuNu0C$ttq~vCu%sji02enk_}qSktFq= zZmn-V-`!+W$3qO_0>=vF{2R@*li|UPYPJMM$cC;b2++~dfMZ*^af7BPy)4EDy^k*# z7@X`kc$3WT<=OFgbjhdZh|wEe;M-_AJ{{nGM%)>x{|5R0kBisQO9QW}pf1e)%!RA9 z0>m5R_ag=@4<`HTZ~BN0Cyh)lGN?+$H{KmiW94_EtlAqf>L0bmDrVJkNf(k zSmNcy@N^%CS#kf{bo0l-Ap*hyG!~dFp6?Jf%fkqJ!~V&*wKF^z3@2C<7yP*l66H@U zi^0igynHx5lSSlpc4ouYvpx>ky+Mu1Y`A=;KeF;GHzcUH1(t+-nwV$OFHVv|bASrN z-P@ks_#lFj=svB@f85&Zt-sjV>}~Gsyx7?Vqcq1<{{H3j?U%bxHaB|fPu8CQX_F-_ zpH*J+`^}x*tryRef=Fc|eIoEguX~F23RFHGp3HC`NY37cc?KDdEJZx=BDWz0f@BTV zI()~Eyic8}?OmkNlAE7!kr;T|Dep|j=8!zc()3h-VTWYm z!U6p9&v%2#0YrIfDDOVLzSz65ho~{d844UK;^=5_ z4vN9iCTuO*@tgj;!HomNd_=q%BA0L6V8cX(ep8Y4q(V;F3r)c*S|P~)t8Ya#6N#YV%7kKlve#j#gFi&0(iwM z$$?^4Wqfl*hr$)=5f?{iwRW7vKkJVWxC5x8u(~v?7vItYw$+@n3A!;~jso7xWSP9W zMvxJb%2?)LPFZp%<;<(A+dG@R-MzKFm%F|7XP7GqVoQKn!a48pgvyng9x7v+7qhxF z1948@432b*Ew_N})Hbg|sW?K(^^mEVzJd8_S~}6~&*-wcCuZ4v*M*bvydv3BwiUr0 zH|A+_?KB#s?E7xGQRR?LWR>&_c#_z#D zY6G#ABU7hc#epO%I&X%*8?x|vQ3VQ{(Z$aI32Z$*Y+NS-?`;8qjx>|aweVB5+@zgl z^yaUePK>LPR*c;O#pJv80!itFM`F9i->^`~PUA{Rb{B7-e}%R^q=NIvgdj$r-f#WU zD{)N?FOV==@3FOD7Bo;Idhc+lw)13sMR&WoMAvp;<#gr(71+5Sw9@NLQaXk04tXUU zk(t2iaHoH93GA^o69-+DbJODdenqQoL-(f-s5)P-h$0NC_fEq;kpXfpMhRjZRo)f_ zA5QfAHs%bmVdYmjE@7xX$=1Xi9^7CaC=sHx;v!Ok_r9!3PhlxlR#K^9!k^1t8EuEx zb;gsAoUQSb-~b|y>K82)4gDZ}lyx|^n=UwF$=(bd+78O4eY3s<^Wj8yl%@r+g9Nw( zK$I%i?mSu<(_5h~GwLP5Ldhru|2lxHyOnYe|7kpHQNi1 zMXS}0mPb)g`GC#M=7BKeg}Q}XohaoYZikZDai`UFC? zJ-_u1HdvAQLtef{hPePy)*$=ExhM9!t>f1FK?`?*wJ)HR@LzGR_uZ#{2N`qdOc{VF zA_pPtI=Iiq@)9_W*xy{Dr7cR0l#pa+$f-Aigp*{#X9AC62?~FOgAVK_XhSYGr=0|$ zwYitHh;>t8Z$2d5k0i-EdZOq`i|%}-4%k%ZOhDIUaMGU~!JI1@Al|7WlglxrW;LE!QyF&~&m* zcuz8nxbc|m^C{b3h=pa7k0;}^cnF&(Uno|C>Tu^VoF@JweL-CLK#Zb@JtbCqP};!% zN_%R@B~9ECUK2F=tj01V%YEs(P>_}QBx;gWWbn2x^Pa12*UGm#-FLT%KDeb4_kj2) z(nK1`EMpl&+wORJ@e3JuU+nJ9weFe>7f|>uhH!ekx?1yf;c)hC+-QRfAgX!^Vz%=d zHSbrbTbqbN?c5{A%BrUP>WfDlkw~vo3A(xnZDif0CLmyRti>?nnxF%dQC`5pWbhDHs@|zZeX=; zN4O0JDY~!jZ}Z2))7cRmyE;q6ck7tjp&f5vGd|$y+^&5cblQd==F1f4tiM@Z-P-M~ z?d+`mQ|n{?=Ee3NeEw@s;TYZ4Niy&8B@7Jj87GacM7&5jq}TRiizC}kb#rUSLRe-9 z&ljGB!5+4FbA-4~^rVe@xD9|fBUAdZM~G)3acINccitEi5YZKG&%2Qdu~$~8!)o9z zb@a=o4#qHluvh8ef3u@}3Ff7@w8@14R_CO2L?Z?g-k`VPRto;uKnCZEtDK_o;OzY3 z5_S~4uL%@#QGn3${>}_pQO*XS&VgK#+G(>z3D1H&aR%BLLjrC|Yu`4A6YiX$msL81 z<<&^5a&H~MDhWQehH7BOc7IoESXN!4fh5w+5}-!{2?7(%RlYQmMT4C^i13hz9y5&* zM0^|tK)@7?eB-yXb6pAWEBb&m(xN{}vccV9Oal|29#L-qKYuqoN^-da2t*+80trA= zb7MzyTcIBS^lFkY3OCp> zYfdl>)7CEIX1i6xZZb2CKp6r*J5WixIZ%X!p9DM*!OPLn>_8$KnWIj$L>stL!f=H3 z03WY0Dy0#b)IdrF6ds=r;f@LzOc3-|Q{knrLPG#&ixD%REfJbXW|l1ka4&_&8vkAw ztt=Qy++Q9GpRp1TMG(G%rC~iG+hmfpJE1Co^c<0DtrOTGvBH>2G2JC3pp$DulxJE7 z5#UL_8pgEbJiQ^P!(V@nwPGaC_#E@Ovq3aaGsDA%qx{D7XtX6!*0{o}c4$;gPWB5@gr(;|PQ_7aL33c5Col<)Z?8aN z@Tou>Hq>d4!W!1Jk%5MhZ`(UL-$tS|2?EFJm1+S96%6y7d zy%4;6;c5y__UlS@PCc&G270O-fGzM7S~;pztF}0=k?NS@ulUUtxzqNEyjTp+u%cp+pG9+qNs$GPoo7b zKSR3J%O*AL_hSe_&eATR3PaV?mqA<*QZRyh{mhz}Uu!0qIMzP)aou){(I2 zo^Dw_4@e}(tu_KxT0hbD5>Is(5)~zlBVR1tp# z4`VZ>dBA0i*;K5yG^Jb|DEOSNe$Qu}O%L0Sq|0CYB)zp$p_lJs>BhN>-3N4}(|13g zKJN5q6rgCr$Av6*CJkORIcia%c!H2NR-*+LNZ_{<+JpW@r_E!SfAhC>0gYAsQ=2c4 zV_~*zh@i84Fl;F8UrwhV!!<>1kEY(#y32zs-W16`B`9u83sF>=*mc@V&^1ALB|Qx$ zzbrWsuwM<0pKNG!;Wj%HvSm6`el}(6#s1cd%tGi*z*70ihf$i1nGEvB*_u6`$hn3^ zGJ~vd}7ChqS zr)@M51g7_|W{%Zk{Z|@e6|iXw=C?^Dgol_SaU{8GVZ2vcX&;ZleHbbrCL0MHP%Eu<4b7j|8ckd96pwItU9b2Cv~ooP zZHeEn@8TDBQ9T8DEifgp_cH*=c3J}_NdO!ms&`I3^|MGttQ}1*yOY@>R&?bCN^N8C zHVd`DQBEA>gmr*ZXy=DOotIEcfTE6=Y7dbW{jxQnIT!d0?#$bZVQfL8yR}}KPgwIx zHg}jzrL;)j7T0_SH$4DIP|*~Ui(vE7`hpNH>=}S7R&lThl#5}9>m9P*RlXNynW!*~ zz$XxDIDI2dW!x=<(SzWTT#A#2bXb^NVNA|cEJT9Oc`gn7YB4B*p~KnqVtm%MkwcJM z0P2lR92;6++uPh&ZP62sX3k}|)^*F^m%08Ek6c7OzaxbgG+&9WUEEL#)?+saL8U@A z7o+$^`%@>}B7@Yo!yN1iB$yC9yHT%hB% zBWOLRNZmt(r*%0A@896w3Ys;6{IDh2ZXMn&2Ajuxz@oPBIn*gkAh59>;qFcz^N(8( zrx%ofFm+@HfF)09Lv|{W3b=e7-o?Nh!zXk${L7%aP}#QXWV2=@ZE0>hFDBOLSx;M^i zRkovl?RE=e|JTI;?w=pdsu;V95tEIrZLiPBaS!`Abc(HJHac3t_SuzhK8D2r7~*(3 zj%)@yF1EWx*7ufFOZ^R!WtU1jE(|~(iq>x#$j}W$wBSzYLYO3mSzz&Pi_pd+&~(IM ziA=fJ^E1zjp~CuR(jgq0x|+#b-&+1>_6=td_6MZM zYRKVn6+5>9&!s5Q+q3GdMJ`#~=x(5pOIIx~*Np#(w z!R!X&ngHt}^ka($&j*{hQ5npQ8wwhiLD+83-ykJ>1=t%m_82|^9xStCxC){%vDR-L zgHiju-60kk*Q*XjvL}1hnclvU24z@VFvd-1hi_J|0tm!AIvP(_thIY!DdUy1OZ(Y+ zwYVJ@|gO9fm~*;a0NAaQ*P$x-TG(PbafGGz|PFNRR-V>GeG~ zMG?B@n2YAv(!mZoY-dw$&m=w&{bXt?&@aL}+T*9VuNreX+pSGL64#A*fGOlm%Fz+kdo3YZLwEA=UE zTX0XZWt}3_XvmEF0uKJFl7KJHEAiDEONb)DQUiQ(pQ_KZsqsK->fiGo#l>l`TIke{ z-W$MMETapKl*Z1l6Pm<2ehUF9Wnlf#U}X9{uf#J?Y9h&UUWf*| zZF*gpkcB4+oK#pjftjhBg=I0^n*FzcZ|aZ0GsV!}oE*0cp&v+@%rs*CLQ0C|oC(gusN zbImD??i@=MNL-^LERk*bM&NH#%}JvX5Kn?81?o<_SS$`=siGv7dvf(JQz#3aHI+>J zgR)odCRYOs?bnK=glh6=a3OQ8YUZrTCBimKfgEnQElJuQ%~3$TTOmr-R3TD&s8UDF zAQd3f!lV{2DwIRfS1AtBd1T4k_nc%5`W%eTvuPL?q3dSQc6dhYm;>D)+RBZthVBb zTu8b!TUR8wa3a|42=sJ61nh7S!b*(R$h7GQ#Oj*iQ2H2;k6^DlI75stjF)C^A)tXM zkH$F*n?ssCBm_N{9WWM&B_Ea-e7 zUGx+QgnM!)Rr;uS(3JC!|fsG744LhFE-W6Lu z_7(?U^i|FTKamglYl+6RANeF8&l$Sc6z1di)`Md*wRyw|@G8jt0H|um$i#FA5*KyR zVp>8ZbXdZKwEcs`@X%s?I(#c@-wy&LCU>zhB8C8=t~Q1*rma^YHuQ3k4OP!_WDaa(C@kX;TINaNS& z%}9v1|V4Z-U7nNpX(Q(A*|7q|*LP!r4`IZyA6vEneY5zWwR;9aT2;#&xKOus8wA2m*3h{uc3pp2_{$o@ zhMaa}y9*Q`G+|L(L9M9x%ohSmo$(7`U}tbKgU_}vI_qDsYO%23nC6Wd6f8WZPc*vs z19-im*$gD(_FOoeyLH+S$ry+u$ndADt4WFh$=HT@uA;!IwU<{a&+|?bn@CuARC&@o z`2o>riQFq-o{RBBE()vkA)-ilLW)F60Y?hG$I$q}(QjNS~;03%9CipPD4gniG&Y1 zluB1nef3S#?kUeS8(mx z`&^APTz!>_kEBt4RDqiIe1d-#ETATW<856JqJW+yTP7ei_ju8z^1bqZq%6HOQ4_dD&2R4^YJ|1I)=q+r+q=f#Fto%@vRKAJ;k71j+xZpjO`vy# zpMaNB9pw#z$RI$K5@zYvzdGNxkSl~^Myg8GH{%j8L&5rt*tOXy+)?5nwdn{G>J#Ww zWJFn*YMDV|3hy{rr-Ay771&JH^;mY28V*(qrFWZfNhO{v12O$*wwAmEJLMv~k41)I zI0dr>2On?m;VpBOg(Xieq-H7MtSYK>+I4}Z&LlBDwUX9oDVk2Nu&c&-A<;!6Mrc}% zo@TED?ai^NvIW>Mn4vf$?Nk-70%UKtQ7agXlC{Dn`3YN)G!NdN2_)5Fum;fz^BsZ< z*)Fp2GMhBXYW~K?aRL} zQLwd6&-y>&CIE$j!?HJp>5o=0wiAD)yo9{yQ^G}j4}f@_S%(uqmUu|Z;SL;MCg<}+ zk2K;ZbX>(yU>|NLbL{C#FvQe6f(2H~Xv{mU-v+AsZQxeuF_Qo!K?xpLd1TlWy#hHQ zcz~A%FEKWZhqiyR5g67lV6K2&;^l-AO!10Z5z?GNOG5Z+=kmz;Yi>l0Vr0m;%zHaI zWWNVSra$p^_(W)0(kpsz?oT#{`JLX8+o;Lsp#d?{*hf)-hET~yQAJwbKa0gNI}FzD z!(GIEzqz|2!QY4o1^Kex2=l{}GM> z;`(C$(&X!T%u7Zl`}(J;5CW!o>#g5@YsGNK^Zqu@G128U-QPnpP{fa&odXni5bc2# z6J)?Y(SwL$&&5yNacaYaHjjM``xsivJV=j`&j_gqw&9oIWu=qWgJXH}-BfRD{+Yfb zhs>_ab=lPKL|4HzJk<+I)=r0gzcmb8v~6~TP|D66BC#rFOb9y`2a3@MWORPfjXc5(t^GOs^U=(|f+Er*omss!6oOr3Hty&6KD`3`J znjH?)YkXxMp}cyR7`{*9G9Q|U>Vq}|D7m{;G+eJ*vmDGudYxh@5cTI|M}~whbO^*V zFv+O0(>{TSbUHpkDhPx|A{gqMTVFi6)#{G!wVrIQZ9tFe^)|M4dcA~2$;NBVbstLT zA}(TMw)hA>@jTa|j|(vOaj6C^Oa{VoD~Se~!ox_JjqiylPLrH$bF4`%=H}FhGprB> zjnEe%)+@GofB?bCC5>DCckq@nNF#&{5WdJ}O>;K_1d2c`XP7NTnP`S;&X*%BVUD~& zBTj+EfY&b$hyORAG$Kd62Fao}H0^VNlj9-!s1eHvxm72JmBks%7XE@c?~t5BoBzxw z?U#G&+4++>)PE#iWhe*T?nNKle78IJ5m6Ccq>{mYfBu(nPYUAwtq|f_t zbQ96>^LHF&L(W&5g5u_rqF}*3B3mW6k$F^@ELgdd`8K{sj(?|h7f$SeTIKn%N!b~M zu6GeFkK5ZPgSFEW=3RJm))7fzb#?d2+C88*t}r%&I=E)@;?e9FDVMOrRbt72Zb~S- z%&H8N%xr{X@zDPf010j7Am`U+eZo$8h>JY&=K}Eeh5PLccvCUVy70cX_xG_aAe$|| zTcLwFg%X1JDFt3ZGi0dC_`g}Mm`o==gHG-5m{xF~gD zDy3*7rbwIR^1?B9&rjLL7GjBg1XNB|{0Pg69D_+me#eY@3E(zMpE`>^PYlthVJ^cg zITL(irDCZpzq$%u3HOs`48x7l*s{Zl;ljm&!E&IJ(3eJhpN#BtOi4r-JLczS&5Uwq zOE7?Q_(v;;r$eR^!leU5&B~i0;+l~!3J$nsLpRw*_(LLQ--+aEi zS)0XyUewWP??Dl&PjYz8tbB7`!}3{wTOcGyqUu6mWf_UgsY1MyULkZ}T)Sd2Vb|!B z#<1aN(jSfv#_y$bv+Z7|f8TmmrqF!5P)|hl{j?SaXAtW?sp?_Bdmzg7b!wka3!VMd zR&lz4C7Z8`w;3mH;;ccoGQ#6oi&F&G>Xwr9a6N{dHyh^I+wYOXPT_tWOn>pNFiT(m z;+^=};9tBWZmGXK&L9Y%{^CP{fOs)HtaU?yo1=6edMd_nvo%r;G^Hue20a={95b25 z|Cy+_)YH$GZWj-EZ?idHggS|f ziTDG4=hn$zhUW|z5BnyXF{nr|kVdAIE~l=${OO<50evE!1mU3|*UVtZ<@tAvHth*u zAt&1uVv88{_*(sqFda?CN3+8r2HxUf6S2RxR$448`d1j*(hNpg6LF)ZHmY{$Po+Dk z$1K`?s97u0vNdB!z0wr-jK@arw5nR4N{`Z!8%%>fmu*6#4nQlQ$@3g=OSF{K{15>Z zQ>PwJn^4z7;3Qmfhl37+Y(y;gzi$7#y$n0x=K9`?oqy`>Zf>vbtl=y4K!#e7jbtid zMNv%UPaaP~_yyn+<^!Vb*&~l1jp!6(iwvWt2*qZMn538-bC>;&$v&i`1ko`JpzWk2 zN1F~1d@N&@fz%AF-V#9O9p=madzrr?u!$W&;8qO7Hq@R@4p)4EhcC*Ha|RlRmCi{U zfyZ(+RnN?6-x2E-n!@k;fJrp|7|@rSRQpIz>`I09>*kZ|cQwIjJK(s-g9mlc)uac7 z3l_Id`=7dJ-J{l%)!`~6`C?ZIqK)Nn0YDAf6&pX+5O%0qO{-N}JU%y(`R1!7PD`C= z^L-O$=U_ss#KFc!z#mV-f@^>Hm*3o6nL);7&A|v4623X#pMLohtt_19`n(p0-L7<8 zt7qd+Tq--3g%4*zp;l2yR1}&3Y88zh8~T^lvjC= z1T#6ktYz{-?7{oR4b@9hDniHCk^jXDwxrmryRYqnxz1j1{l&9qo6q;|wDx)%FV_8M z`QoXhLt`$y@`QX5wn0cN*jMb_sP=OY{qSviDz*yQUhjt|TYHGl+=Se2S){q`_wGvy_m}H_R)ZF1}Z-{fpPXlf{OEuZFi*_g*LahPQ*>kmB_W zoDz9W z#=1y<$>b)0l}IYv#fY!8vd?{1HQ+2^=)Sl#woxlIaqb}RN<$w)a}a!Ro!~dE2M->! zH(xw%->9?K8xOt(lZC6Dhc5SUPhSY5#|a-vsP20Lc$*aJ9Num%c>9Hr%VI|{+5Ka9 zY{cP=ybthoo?lLeCvR{kCR~|jrGcAYcSjiSkylmr($>4-;61Ces+SYjCk8_Y3Uf&! zjGwP@(<<`4^LQ0S1{o@cwSriKmDbw3@$iUwkZ}e}6H-plHHshOg40t!kOh4ph8sc$ zm>n>HAnbGT3tTwJi?MS54`1IP+k%P!I}_mU(cCdO>a>v-3CC9u>4~%cWU}&PS#JU8 z!9G@aDao082bVod014loQ5?H4kqC_D43jrt%4BSbD{_Z zH3!1AT={XImaz-=HeWnV*g)Q)CX!-z2%MWBF)L^WV~CjK)6%HuSHFvaYbIf! zYZ*wWb;+Qk8{5#AR#(sZ=ls&CyRU9weI>#@$O)pD$G#$s0~j+2P}D9^-uM*WC_F)) z+dtgJG1SYb(sCw+GmG1`1EJ_uzk7VQ`**K@w?qb6m39LG$Xdfc9-c>?3roLRx+-A4 z1cm*M{eRi|+dq7LH@U`-jVbfM26{_fterOY!|fNln>)RY&F_0ZtnEDCdj6;0-qy2C zLS<2B?DqB_o74ekYQmS6BVV#~KCL$KgE(HN1E>all?MF@ys$TVy(eo=WqaPr*}cK+gx6wxyR zX*0YB2v*Du@ zCe94GU|*@QMm(@x9`+|kNX*b5A(B{{$?4F&A-t0caT3EHrIY|0VWK|?q%3BZax7rg3h~hA4Qhwv{V$^bLG;CQW@-uOz)rfT3#Oz+~6jxtPWi{6xS+?;$V1jFvB6$ z3xqpS`sltHPcLW%6XayAn}xW0VGA!GGSU_!Vx`N4SgL;5CoPw-e%KG(BbyIf@CyKk zk_hhWmWPfvwV~toBLEAkc%z6Szk?4wB|F$c<@#@d*^fCzV(Cu~-yqEat_h*hN(!|R zhLg77MFQ7ZPTpdP$XTTpFUJi=bz{r8_JgoN8k8KukQ$DUZ?A^VQ8&)rm?hI!hPKjk zBB|-QsAy?BoXRc?qr*da3SmS3mN$|ekHZ|6V)@&;s*oXor;`$lhW;qRv@b5tjSB>+ zCvG@WVm7fIL>T_JkeI41XT`yT#_xO6>1mI*CY?;6e@N$5+O`}lVSp1gCDH1J!}_X$ zy3ufnmg0>ek`fV~@RV#PilZvkam>;h~0W~ z^lmsAk9e(2_L3s(;OGffe>{ib*hs8}miyvhJU+$Pm#R(5wFE&>MmD$58R&d6q<2XS zCBPJ&41u%}aSTg_?J7W-=GUP04)zVlHgV05o~DLQ%2|NZ3P;wNyGr$1Z&PW??Sfex zc8{(Gv_4~!^=t&{CxJ+Ba}2RaGBHYn9|Eaj^-+`cy9nZjXex)24JxawwYpjrwiNdq zjg?Pnr%)?hS+%;g5p*~^xAV!V)r%wa!D`T(vk)G zY=FeBNL+%*Ttx=A80ME12QJlc$`107Z^Xm zDGf3yCt z2|ZhxGj##FLbLT*bC8;WozvAPP>J`4MNO6>$ENh81O$1QPmrp6FyMt@a^4!j(=kNE ztNLHXVgu2?!W=bIzBjRi`)-e@|B?IF@gLURn`r%ElGOlaaV9}8i? zdNL&&=Q(3hUVFtB!tThj{1C6Ag{zY^)+ja33Wf~pWCz22q?ykJ!fY(8zz>EG0euF8 zsQ!-sCR6MWn}(oSF^~}vN&GL*#)-yk-tNIdM2>wZGUlZ~*Z$f|9iQ^# zr7HN)Or}U~BUV(dDk##p3fEPX)^}H&zz!irXTu){S(s3!*wXt<03i}906fGj(0)*u z0p1kc3&%jET)qq?X=&EM( zaTzO|Pq-Ztp&F{h(!2z5R8Eev-Bh7uZ~QDVwhl}!^uaV7&>=3y;AlwJ$geo@Chf|gR-Mj?(VJ;x!^*!PxU=&Lp$*Hge|MYTzg_LTdV6;A`Zm4| zzdgA9?d@;zcxi=qSC^+=G_FDUW=W1`Uh0Lw+E_6C+*+5rB$!APc37BLxuP(mxKak8 zLluW#7;fuB0l=Sb75gZVXmvv+FiUg>VwEo05D|%2-~5SFGnaU=`_0Otvv67Jb|caP z)d-DF^htqY_|`uP^Otb9-@X5J9a=BOzuL=3hGdOHW=r+x+<7Z+BKcF5UhOIErpT*tM`xb=rIj;r`oI z=9rKtFA?jsz4PKRf{Yk|ue*yJ4KK4JEb9uG9JgUfyD|>pn;ao6>|T{Nbf}5%zdn6z z2Am0;LN~{38;-mDqpjx*Vn#@ej?B#$_YR-4u@hzL!);-_(8 zyClyzFSRU2_InV-DmbnH^V4!`^G96rE^(fK2WO%H%{4f01>wo0Y4aIMbVBlAi~6h( zZ6;@3H7^@myX$K^8@=@>YtR3*xmyj(^u@!!*;If?!$d$g(2yV6V`N5fC7^t{$6t3z zz+$Rtnj*IUNz=rNx9U?BWXo)HoHhWSPTD<52}0=XIGaRqazN!tWRHa{l#lBylTV4a zwqi()L;zqO9&FKCmGVATU}o$p5$092HR`1m7%s^gsj-fAC)6Smrr2%TwC=bc69Cu2 zD1eYrNJ&~&Gg5+WkcZ;tDiZl5@+go-yS94D!c(%Y6L7B}jsjs6@Z>13BdECC&7}p# zZ83NC_0AMn7h*WAvQ>A7#kvh*Tvja&BzjF!P-7nHgNfCT20sR)%5=aG8_8hCjY$D% zX2yO%RN#H3ZIupr)YlTJiwB>0yi{saFM&oR(N0YZY97@{@_yEqdy^Q>D8@8JH}jQI z1P?jOn7`=^0ZVr*0l$WAt9G*A=DjD?$VjTuhzw}mk|-G*#JPnMw@5#?5FdG~q$$oJ z6&-PrJj|3VL1A^uXr?vQC+n+yL8?qin)>&cIA8!s|@0j7W+%11Rb^>fy#&vymx$c}$1fXe)+U!%5t#8!XFj`j{!s zi?sbAV8H5!`ShcdW?W6jWs_1L4G4!y3!Fpn)*MfNf}T9(nLgf}MsuD4K6g|fp-_F~ zx)Q?~w1ccNL_Hjd!tK&*^8$gg)>-#r+?CwZkh0mA?ExVmjXFDLD}2mswV1)$u%m)e z0MQ2G*F9wiSi>qe#X~#H@orHqt^_4q+E`P#@m89tDJs4e|a4PFJ zSr~h`e~mZVAchw~x-e!T(3j_(`UlhT=?v$D^@-=Q2)0A_G1%0!cE!j{D;REq`m!Z zCMTJ$W4+R{?=xB?wKVo6@39<+g96}DtI#MkkTk>O9*;C4Q~d1oC|np12?&Teir$2B zM5-fPxB?vs64`0&Mo8?cqwT^FK#j=0%nukwW$r%KIjV&hhozF4E!b9R7Hx~GMttVm zqxEfu9BFFabcqC3SwkMt9H4887Leh7&_QF|q_c`CEfo;dvs*XMRw8do6%yFP6%@aW zZ@L+j=mA%^bVa7%l-DWxdz=r4(@s26b^!MrIV5o$_vOx0$wth$bo``pJRpk%;a;{Z zR>5{VInpUQ1iY>zFr34ITszyqM@;D^K#2aGn8F?QudNqbezc9L>Wx^9rDRS~>^yIV zh;PI-E{`tPWjjQy^aLimtQG7!4FS?SdIP4NV}6f|9zY;m;)Vd6poa{2hH-;S9wNCN zP8*BQ7c_)T`!~P8_cvb|FUELCT&e|9>w>!lQD!|X6N3tN$~_#;{C@4}*2dc2W)FQd zFtCK4BI|j;=_y&d5Y0fiDd>Jl`!Bmms%Bf|i_Cq3ZI zK;&6ofYsZ@y?oC$6B3ej6E1z%`oXp(>Lsic(B5dvI>yl&+AQ87Q)X>|Y$%a}+o_IJ zD@-DZ>S_H%W9JqUaq}=TMWNXQn<$2VGzLM7UP|ia%Momkcq5^HB#`CSm3Pwo!Q?C4 zN%NZoL<=Q>Kz2G^zLnsIkZO>J3=r2PX0ihdEb-tHh_MOlPhRZqWo@z=TfA9eTFF6( zSJG&mXR#tb`F#(!9@s(Phd+d4;D=Px7;UWpa({t$3%+c`gCQXWf(o#4VQtq)3fE0~ zYdJF5cili?Ghc@vSfL3i5`MM5D~CT>I)wk@^C1Y6vD8k?jX>Wlo`DO$XU=S#K$;8> zAOPZsI*cZGL(xHwEr6hp29^|ov1ytPXWb6w+bLnl*CJ(pX~%keZP>Afz+=%hd-uz{ z7dzG)ia#3kXAnJcQU_V7S`QBJ^Sh(t(@W&L=1I1PlDPp2i5^uhpD?mh!HG<~hI9F8 zV4>{+_QxZ5Y#-5Gw$*wbA`in>B03%xfJsTZK^P+D?kh+P5Nrbos3Vdg$ZIoLo>Dh~ zSCbQ66Xdx7XyTw8hCt(H%$?EgqY1?{S97T)6xBzmh-8bV!4-_+9)>~_} z0XIDU*lO+ZUs#*}ZHD7*@YU*T>680$00EP$FCbVk9{t*anmCbwsYQG(R4dh zc!#@fhvzfckj6OgTd6K-Ja!>lAO;cdTqyYa-51Y`lEGg=9?)o6!fsq!r5d?rk!OCV zi^>V#L9+@sdsOMrPexO!s&Cj*vC-bK6i+eMs{&+flsJ?-b~{Q~7J49<<9bY4P7-ux zFWD#M+E&s>74S^MO-}(=TLwdma6)(%wKF%zn6xdjC8AFh8v+1fP!m|Cm84CT#OpSL z58n+(u;C9ckig!J&t>KmR=*7KgANoO8~;dv6HDqgOm=>)#?R??uJo3HVlW_+m9C!w zk&FaesQ?I7*7pvTTvF@tZ%r&j8QO*Hj}msS0WzQtH%)3JF|{qZB?@Yl3aYd-&yl;@6H(;C7jh@l0^-NRZ~|LW3Q@ixU#Yud~Jr( zypkM)HNSfEL0Aq~HE{L7!ww@elTQZA`3FEY935hbx)RH$I>sK-iefDsn!{ht`$$}` zxZTzH7VUE4f7FHA!kJRK28!iE?g=ehw2BZ0e#{FrSxg!T@;Qclg&vm=y}DiGTS%OZX3nbfW?Ey!5m$r6mxZgJ5?p~RfwiK9`{^PW zISRQjGe=T(1pcFip~!i7{s@QP{fC@<|46H*=9T#f-9>Wj+}>Z741aVi=N*&wPGPrk z$3AU+2)}`8_WTrrU#E?%I&v=kPV2srDy#TMm{#+!yqK>I`m0}??GK$0Hxc<>cFB>W0asaEN^*ro(MVpT@M=qCGA^~b7y-|1J!|&!5->P&)nucr52v_uW~?MzkY2rh zq{l_s>xT+{A3HP)BmjkCDK#0w~^5jp4M^Ue}$ zmr9}t3i`GX?n12dy(mfwAUxZSFC|C`0SD>s6?E~6Wy>NeOY^f7iaFq}xaj-%Z={U) zOzX=?LOb;_)N5+5M3=}wHICo7SezHjVne_6%_4U8`8crC;4jI1y^l!e&3yM)%3gr7 zRX49wBdIqM$gPa%$~rYnEVv_S?cLeIa|psUJQSB~GX8wr840ALPe>sf z^*O@f^#oGrF55Sk&JdhBKEf>ZCnr<`lWsSu!Bm~R`ZvzOFN&ILveHNdF3#~}hfn1kR@-Z#r z-?VO4Y`;#nNm;BQ&z68|31WA)o*>_~h!$}sBHo&`7o(esxZ?pGTj6>nCbxUk1ldp; zX~2(;oO#8GBA!&=XC7m6Ht-Dc;JVV!l`9w5lL;Fjng=bx5=_=#Ng#a}V@$rWwoJqgS&h{8;#ENB>PJ z6}VL5!5KQ`w>ct6L_OR`oZRtNmFeL1e7|{{gBg3(= z!7vbCAK|3xAMW~1C9i)M zn4is6YluxQZ2&mLXQs#Nv@P%`P?5Eluw(bwrP{%-_jp`+j|XG%aEyZckt{l^GlU#DZ7F)_M|=k30_%cEiK1DuV5vJ+U;S4e<|$GBS~eRy9U zo=gUVQTq5Rd3-rwYipWE=VQyim#1g_6CksnzW9T@IK1pv8vh%4DmScIVPkcT zgMNge%pdgE+m{%Mv_-6D+=qusi?nU-d0u=C`*1>sqwcubG(nKf7+HRE<`3Fm)~iyg|I|KDqmbO zY5N+PF7y9L%0{*m*3m9YKr@jHZ3uQ&P#TU7ra>3g9vmaLb6yK@K!U5QX;nQDZ@?L$ z**27)ZatRu5BU#a*dXS-^(B4JU|@+Im#*?U3AcS$NPWt@&4c5=8a9MyRvS z@|WMyE|5Ug4ePYwto$hDXbBaS;mU%oZQYIYnC z`KDw@AHu+R$sf`10O8Uj9MA+kd~*vU*I_5=w}Z|4kCZVy`4TQ!l=uUNaODCDg%=HX z&;(#hjXd)egrK8A*|sbI;xaGzF~D9|+sg|!w%q<>G7JtUY6xYha;CNrRJ4 zlmTpL_xb=D1DXd{NR%Zh*CNKVs+sodlWjSB$jItP<-JgtkYh;q-S-0?saz%V%kk|M z_}79U0$HW+wAX}FF3|S{c58&xg0V`N&8pM}I~^+`jd& zy&M+6{nyLw2P<4W4~^V@6#%a*0EVE>>~ghv5u5V`$F=iw#8T_ACwRFY;kJ?Fk;Z~H zi=A5|$eR1|Z#WQgjXJv4uBxD7rU|xLHvu8|0-gFO3tsit+2hAJ0f);}vZr%zv%^c1 z#kXE$^=P}20Nd|FFk91wc`|LAlgW7U1i+p$ptdq~o4AbaVq=I!f;_Ac=64Tqt39sY z!!bO@$Tc+^p6@>&?@mv{&nW!Uz6#x(x&*Gtj8iV>g>ah~V9|rghjuGx7RI{+LAdq9 z0AYcX)`JOteD`*Qkd}j~pVA2@daii@=rQgX{9pg?7-5Oqr!(9$H5#`b9OKy`9xb2S zqwjFuVuTY-=<(7!bOj}$)}WYVR9rtGB=NgW9Lj24lnYjV?6jKb)P$Q)}f{+54x zc%|=qD>qOD?ebq%PX4FA@o$G6+-7fhdt;yAt?0jeVELSVhN$4 zm~hxdFbiC`lrWRm7;Sw&h^sin;9aI-;Z`+otZ*& z7TMT92;-n+=I$O(^wG9!bYbs>Nm!KO%B8;r3lEu#9v3@6o0mcJA?9 zE?rv!f{Cl#bor@OJ%nxUtWY@FiHo4~thV1Q+~bXxe}Nr=cLM8RYC|oThySHMymC=A z-O255<&xTHl&7!TARtgYE@C2sgscvzEi9NWoOL} z*PjiLGwTvl$kbs%KdqH7|CzQ)oW^cZZ-Gv$g%s#7R}em2>XC_O=JiN&9pGwfYc1>Y z$&>G&mAadLxl(iu5<`Q-HwYz%-w7EsB*{;_dV6r;ESM3*D>yE&f(y%s&=9997ceC8 zqO~_;T&Oxa;UQ}sVE1%*HpD%ToEu#K4L=X_iD3mDk7+o^nxk1(x4a^(&^BtAiJ~q+ zcE_-Mk8@s9;oH8+V6FPs)z$AecXqd4Jg@4c$^H^fNNiknLISsHcdFtSj%!mW19>uG z!5uTw1+gjIRbNhMKzfy&LQFqk*V^anz#gLqlcQi)2RphLsGyd543ahMb^)_<5O9SQ zIx;8}Ab$pQ9F2FH5YmW=e19;{L-WR?V0RyK3+qqduEXY`l5D5l?T*G>h%MOIrnHU+ zO2Q#}Ak5m9?{s?xkut{xkfM$jaK$HsQye!%xO2rhBn-u*$kkP6XlQ4gb_;KjDZ1~+ zleauFg6uv4DB(_k;|ILMO^*>k^!i*MqYB;_c(p~m1Z9?$wG`^3;^F(6)9COGdPNjh z=*gy<3y7aQ!vGioFStccn;$l~TA5hKTh<(>l>{BDs~ek-Uj8X*G@(0S;D|GH29*~g zum~G+Z3i1hN|J#H*XYYLBbUzGw1w0)JY0u3u^*A)NNFp;yEL34 z)bvLr84{YqVm4JnK{82^!5?v*gIKJ%tZ?0TY9v}-GERZ9wS;TbXV{AyOY@(}(kRra z4Jpu2@RLC9v?1(MDfiJ+4nFkNS8b-U$;oVeW=>Y^F6R~bBKHWjFp)lAZAcm;?h;?% z4xcZkSi{V+f*%kvzesPI_X-$0Bh=0)ySucXSK{nTRH+#(TR4<1lt=P?ukkB3i zch96ru#s3-*L&U-Ubq_iAG16URS@6-=QTtL zE^+7{XLhkG3Qwe&3W6E^H#_G=+$0j_-hs+8IzcgFT>t?{-@sFmR$ajupVJ{l8v37vaW`RNltcWPSp}g0geSi$HSO)aU<($5ju6| z66rN$)Dl!86UyLpd@iv>2Q%FMNj*MH0dOsOw*GLpb=1Gak5f#+)&*%TAu)=%7W{_8 z*T}u+Q;A4hxo^nEeTxM_LK3lr!-~kc(t@>@maUXZp_ue=X9l>)D>4;)fBKkrmsYoj z!sOJb^ZAS3)^lXDTU+0QF5EMn0?+o8+V)#3C92+ia7 zh_dEdsqs2$0bpLmWwiG6>5CtFyDzslcX(Y$8B(s#TB}$p!yjoNnhlS%_4Elqp_YBO zL@B=H%Y?WvsWvq|f6;G@RRWuhg3W^B*#xGR6-aGhfN)w&Zq8l4ES#pgYhK8Ng`cW8 zsn1L-0{S4w=nXPXN4qaKUi4mWZIq|Ot3$pM>*EFZ?jdxL0|1W{^I-o+NM`_>FEk=- z2(oK4RBt$XHx@OSBjk$czZ;`-nxhdkc>;A2F%h6Dtcq!it7HP^R@u3{XZ}U+NbkHH zEn1Sjo*s-9U&ZkYTY(2>8OJb zAJ;GYUZykF3fV0xaAz<(Z=hM3Es3F~r129N2Izv|0iIZw`KU(=iilk+{Mn`Cb$0ao z&e`w~9xK_6GKR=mC0DvB>6r4kWb5S)+&sMesMpiX6B5FVC6h z2_?usr3s73kFRQK3&Gig8jKuby?I9jZrxO~{8%(Xc4dForqpP=tL!Ppu zfZHcz6k6O5u|tJ6oQ=T_%cYBWByqCh4!oo(j<|7njt>6SbD>K~!e(8NhN{FJYO&g_ z%+ZN9l%|!AaZJW?$k)!9h608KFmkLYd)jbV23V@Pz_Q-8>zeb>+-&ffVF5bZKwG(| zP&Z=u3$23OI1HD57m8wnO)eXC=+jQIl(bG!3){Rn*5c#ZYMpobw(VE?S^Y%Bn&Ps> z;qh>Q!_3%RV*A)&s)8517YSiT8OZ4^R@Gwl*`4F;&ZD#u9+p#{htJd|BK5Zd|64CA z%PUIf?uJO0LwyqnvJGc7IH9l#MBvdWGASvdgH$fNhYK)8euuC;9GzvmUd)y#A6I~8 zd;BcHm$?hW+Tbw`zn~&-;zbJX@`bzv09Q{R9it%JcW-;gsMJG*Aw-)cP>*)ZzNFhu zTkc$?ToZ#yKx=H^LA7T^xq=k`MOwORbqAU2Xgtviw|~J-OG5o8jIcC=G9}!x<(Q)I z#7_HxsuPU6B-RmkGG&|!R}+wqWdv=7cbI}`Xf!>;xf3{}MPU|A6NWzifL4lgOsp6J z#S%?L4~Qgzh^wpr@N#RjbOS&Xb_j0#bv5UYW#ghT24A605?ZstjaQWlzQKF3X0T`Y z$`!JErsq~V*lQ&h0HzC?8azKEUc*4wm7s%{>$C!Ista6o;UP{#0hNySL!w+RCc(X8 z7kwz-Pz0c8x{i2wcC-vrOKS~R&+g1d*PnqVxPD&1Qx_D{RZMjiQ(a<89urgDfT=D> zh}O@p*f$Ul!5o~|8%83*R5zuoCls38Tev$RA|F9kTGu&+7iNqQg+YiU%a>LY&i2a7 zf(t60N1h=}!rovXn7;3y%T+TZDP%b1s^T*!;$(j_SOc$zl6edN=gllMio-60p1Z_d zS8e?5;8}nl12@|)msBkYyFdn#RzBw1vGV>7F4J~nGz zM-m}C{6z7+VJz{;XSH&~NJ4Eclvn9YE7k?`9jM$)`A<3I5aCzg-hs;e9PHc`2`M2O zFKhRU)(Mx?*#yjY274mx%3E_(2bphST`$j4NP|(lAuM~ z>><%KtQ-lXwI=*DZ9o{&lUncA4iKwrT|!uEEQi2WY^e(r+>jg^!4x>BNrX?yU2Th$ zC6X8De2b^KPfr&pxh?_D0O8N@K`c=Ih3pBbhJ3FVC%-bawD87p%5wk@gSi|+_aQ!dP|8WUUJnR(8BV!6)OhMcUg$$io7yA*i3ET$)Vodw~OR_ivxS z>EqzJgf&>wS9dQWtInO)?`!6%r9)$1ub4L`Wjy&M`C9 z1<9v~)cRh7Uut}n0|nm1@Uy!5XlL#D`jZ|mWL(?z*t%Ty@eKn}1Wa}pP)6|iX+IDX z_ZQH}tF!P(>diREIH!4;U>V56U5iwxwcoVBk{DpV`%Xz^nY6>tEj#NRs$XgVY${l>dOozjr!5tqrQnBx1M}#w24uaJzisC(#cOcaS zX4^$;^&`11#j4$ha0}aM5t6&qil;~1mE@v&@)~iYYfoQp_MX3Zz6mSIh8~BdYl4a_ z{Ahl{OPm?7T}YfAhf=X9FAhs`lI3b}ez1$#;dD3c!lI?8un;G+zj*g%IZh1Y2pnZN zm}1M(v9k%2*Ush!P_lI#Z9@pYgu#iT>j}0ET523}t=Uf=8n9lfC_zB*|73Wm%)@AVnB&Z}Kin^mWku#sP?MyS&eJa%t z^DdIL8hR5)L}PE~XB>mS7Tcbp=2?FPADcM2$XNUnz5M5AN$K_exyIlO2UA3}8hZA% zsr~TwlBNOrkRh4zy0{5+GxMxC2y$gg00>kv9P1-hf^b~Q&W?DG#V`V%U9zqyPcI=c zj>QNG(EciQBKQc2IC^R<^df1fwi|ktsP*l?93h>Iq@9HTI2#1_T&JzLfM({9z_tu- z7LJ#M=kS2K^$n}jXxr1!=@mk#=R-*SISx-$CjCjAwq!gKlmWbRLUJPJ2Md8o zK>$Z6aQT=(QyXmS^P@-+10@%zK^P#JRLaic0JWpaR}gY zXMj8!h>eEyD~kP>tzCNaap^9crVN;t;76hDQ$)y}@a{^OQn*dS4E=U6IOkWrf{U5N zzQlhaf5vm(jh6REfaYudq`kjASJ{st)xOxlTM(8rR{%(H@fvLR9?@kM(iO72z zV=W5?jNORr-q>8<;t}ND(=CQzKLt;_tE7;<-@!2y-1G-0qsjV^P%I7h(mBk(S}A$x zIC$1SZ+!O;vjMI?54q619UHHl1FIKd!Kj^L2`Z68g*Njuc_A=`6q_F)a! z{FV>^3MA58ii2na{(b-EvH=9hbUqQaipi?XU=lQl;-h;*kQNA?nwRSHgkU#^Y+iYv zHxvihQD!%28cbeOL^e;4abvM{Q5&ui?H1#)k^LnWOf*4bF;zXsTSP$eU543fVzCS% zpqW=op$jBTqvKg8Ihn__h%}d_G6-Eg_`F@Axq$KcXrx1lH`GS-NW~AKdK~0+@o0JC z=3`}1#1XwV({S$NAVP-8&(@jEMCc4eprl1gpN~sjjtCMoKwnI@;n{;IxpkCNrxD&w zL-iusWg21Ql?Rn&`OfGsq=y^_L|)n_V$TF0K54JYyHhzYrHha78#q+J$WgqXMi=#r05CP=q+iu^$$ZN^x|c8a zYapSzO8-hIfUb4%6eLxf#HRjr`YKd-JHxt&+|83cckfa}=d)mZZq6*sZ4~!3AV{k= zM1)6v0xz&rceU0W#@U4Fraz%!TtL~>C|_k0vH;hDeXBmN1}5@@y!(VEg(o*b8KbEk zN7sjWINcNx^ZFE^Cw{AR5ESZQPoAqzeu^rwL`)9Hv*||Ub_)qdNGXw_C)3f8?;&o- z5hax&CKTvVvY!75t{J50TSlzURruxy2xGOfD zN3)Y?V-5P6_SI_L+M8U`c0(_Rs02ZOvO(a`t5^$y(E!pd&%usoCvPIG?;(NtjNo9h zHU-1uv~_D)PdV2nZ28vmtqM2^9&GC%kb-?f9d+Xxr>|~o`D9`a1pLV5i^sjLAc=2U z-C8pO`>zR~uTJ<}G&9nd6^zYB(fh6kGbPC}!uhjY!d^^{+S!kWB23LwF0nf}!{!Sk zB8-L;9P-v1NAxRnM>Bu=)glYpE`zOev0TBP>DT zL%WrJs(VOgI>nsP4o#9lTv{im6x?5Rr&WJ=fT1AhSS-gm_`+C}d8GKH`XVP257x+m z`{E5Fs^$DVA|oZ{UrRhuf+Eq~An2mme=*6%$IB;mMAhTwYr_BY=!K2#BrRt?PC#+N|ReJGbi?CP1T z!;ZIJIZ)J~A28rw!(?ner=4xu!^IkI&QP910|HMGe-DOVn)!1zsR8h_+4SNWGY3lQ z8zb?Y7<|(WeyNH#I~pH!Cx8E@e_{Sv7>uneAp?t2@v!7d-|m$~-fzYqZIQI|I700`!G25>wMnGGRCA2$#PEH!XLZVTJN2?qmY0V+{1rweJk&eV?qSQ{jM zMC|4xa5%+Jt{j8cew>><06Dxl?Fx{YGih1nfYC>lQbX@pdtm`3^rd7g85MpT%VtOG z(X{LsCSX>ld^R0VqMaV23_>{Wv;#Z`o~}b1!ILte8E#567^jxtbRWV6OYZ#W(kW&^ zoG57o`PgOy;PS$ork4kNnE_ehFQk8d8j>4d8|emLLIvl@n=;rNKfyI9*lvB$FD9Qv z1OzqAI5!sGo1~9N=)jq;PnZLglG40Z7;kwo5a|gqD1}y7nV)oP(ba|^f^QI*QMgvJ zt!4*_#O6M6ZWNpX_5ZW?u8VOU$GPZ#KgEa}2|$SeMa9`Cn~`Zkyx6cQ5&HnKs6~y_lr7-B62Ys7l{g4l5;oUZ zcrJ+{-N`8(zOwnYz253u*+aQDKyp?h# zXzp|gk&mJpk7^RuR@GEux*!{z-W;rg-a>%L{p3uct@y`a!_|H|f;PfbIe4rNgaY`7gapymR3nahi`c?U$&Sx!f`&ZQEeB*Dvc@nX zN$*vKnuW|L!z2$=hfYVPhLik|+(S~@t4^;^>W*Zxhbr+Y!B>XSL9N_JvuymV?1g%J z%hyxfcwOwKK1(gNz+;z2Nb7h0nF;1-8WnXdO%2J5pbYpwQK$vRkmD6G`%hnwVK z=PZcD`B`pmI%ot6Amn|-xVIvYpXNqMelBU|ZVh<1!*KA1N)!{(BFzP}s|o|6Xscxx zIGVGSF3~eE1cD5hc!4VkA32A+ZqaE-km03Fba3~d?djB!sP4g1gfBT1)C$A(_BLF> z`(`L9r+-qo(9ZcDnrgIzND_7xbtc8W{<|{Vnmxw|I}ND_Qr?$%6lq1}f{#oqmEznR zU)k$vI0}_T4R;XB)&;p`>*8izjHC~9Y{2NQ8v1Vs>vv$FhwC28)Ss@5D4$f^EMi!< zwgZHN(KAj|RHT$O3LC&<7NYrh_?Gm9W$fU5e@xHA*s}~3Gl8-$kjG7LVH;97C}lGh zP*w=+FD)WN3Fdk|F5{klYdx6UbhTrP~E56WFU>P>G8Z$_xsNA%aNHJU~_P z@%doKG=OYc!$ySH?udTisiARI%9{!DAmTWLxr~{T8%a+j_XfnDw?&}_0}4_IFnC4R z0!l|D{{_{-J;IH3jFUo=BE7w^hUh-_*3400(kED6bj03Ue>oj#DrYmpoCo%-H#*mm z*)Y6n=PetYc2{oq_AMS(`zj%Cfn36Lv$tJzBfNWO1pZpC_31hVza=0l(@EpRd`AF6O^(vF)`(>zvdSwrGizn(g zlWnW1kC$IYpED_J)Xh%%EI+nGnU%FOUHN+VENQ@E_0iO9zFJAx0+M2@5L zkkO4#1LFD9cT-D%TrcoK(~3)QemvmtMj;)ELcfw(b&T#s>B2hPW5nG0-&UAGM;Upj19GYOcrPz}6n&rLEWRq+BB?sHDr5N}% zb7V6vP-ksq!<9PH0yN@gT2)WbG z??xxsNzsUzUxbN+UUOf!f~qPwllb4HUAu_2((rZiBH=Hr zRCKVHC!2$v?{IU%=ei^1Rdolr9b`J*6AwYLsYzL|BQDm#FtDGc@8BDV?J0*KtswGK z!6UkUGJzC!tJ>ki;h7nEQ~93Z{CTqH@V)>H{F!qe%DxzjzKVONFl z1z55=Q*Qm-k(P_Ffi$^A+hNuoPY@q|M)gnd1-549T4ptO{6p%X#9+Q zjSU@fRx2H^+QeM!?e3mUo=Z=i@qnG}<^gxwAJ34chJKfbYmn;+ofy`{_OXVWbG0*w ztgN+Ec&CYLpS%;`fx@^!1(4q;{*y7DN2B#cFgiqcl z-Q)7Q$E#;zKLguLPlUob!q2k zT0&Prux1DT*S9~$#jakMbYPqMvBh_g@q;}o6_y3;4|4+AI!APSFDywbxV$b9moZ!E zd|I;B&TD!L=liqM2Qsj{1OG zLKXw0KTP&sppib1Rs{t|M<({VC|f=)-W&j8zpTj%vJ?29MCs2VN~4*iCq$%XmAtWAR@yEZ9O4_lZ->*j0+$ih2wC%F z3x(a6Zv=lCksGm-L{LY@%oDdCFKU}Gd=j%r1L8`S;J>jJ{4!$pxI?W;WYvIOtHdRj zT)(*GQJ^gxya8xPn>P0qNnYC$Cqi9F^V#dQn^za{Wjmh)J}x=o;_1E_m(5GISa*)% z;6m->4G=Lb;e09?PZfVZ>t%k;(8=AG{kQwv_drY(04N^!Xz;#fw7m43;_C;$aSh zDQ)i@`PJRs?wZ8DXhNS4OgT?h1;A<1;vZ=YN$m`hj82CZX8QQ~m9efVWydT4dBAGZ z__$5>j%8Kq_V*lzQ&5k1nFl92cMF>mytL1e#FJJPxrvz;PMBnEqmcFsws~G+yB~Mp z|NN^@Tj8H$E8M@&-J~}e#rFdX%~0BiUZL zJ!z1Mw|`+1S3UAXrGCg*ZdT9y{qBTuE#D+p7$`)7D$;!s!HyvVO;luCLli*eZHMD40EE|CJNTqGy1 zuHZEguu+qH0$l(vtf#QyVhjoO@oIxL1;lb?^YB}}%}l!!(Io#Q!EKOVQp@WdNPno) z_1dz^siP)oPjnVJMpNX9S!6+d;JQ^ktG=bICZtc}tPx=o*LJak^xx8XwrYLnxCVMT z$VCvBq;OpTzYqdj4&DOQi@^P5PHL3Ali06k`&v(DzM~u})~s>@uW({gHo&72I?Juv zCqJeI+B;*yR`m&~hp`&Zd2*OL>ma`A;7BZkq{vTII8 z5Z!=JrtYs(d(B>JUb?PysFSXA;s=YZ#`Jfh<*Ti>hvwGWP5g4c>k#Zi9N-?A1SO_wQ~d}?yx zCBWG}8lKUEI0;fnf*Qq(I&(}a$v7;Stnju5{vK#4;#g|cb@%e z>mh4=)op9%(e{(g2YmSt-ItHIp5P*{M-TD#*Jk$(8BbSim#pXYqAii^-Sd1p{45# zuWik9xj~gFyv0|!NK$TPo&yTb@oWAr1@||kc zvRuT-;Ck2b@%gcj_yYA-ImDw8f`;Zv}uk7j!>FO8!CBgs-|zM znp2be(Me(*2oOnUv=$bFGQqDTB1j{Wdurq!#yU_^f`{eJ;OpPa%LQCx5EqMm&~2Fy z0)K7f&2ebTVM%GsTO?Mb(>x@$k^>3yH)}EtMd*?B%O|-ZtI(OOmGVihkdRrG5EM$r zmfs*%jCyP{dv`r>q7b>&4tH@bx&LOZE8y?mh0J;J_}R|4yW5)&{wEDfX)f#TKGY;z^;q;yePd_s14A*n{ zz3VQ$d4Tvs1l{;@g@A8fV~R+eQe##dgd6s{#pY{cg`}E;;;8va&^4i1zlZ3*ZClfT$$FqN z0CUv0Qah+tj8;Y&{*hs>-vc``gx=^3Y1;CSfPAlKm9SQ(Fp8~%Vrp5kIlX+51)Yv6 zADeg*BxASM0NH>D9-%QSC}c)`qXPts^OMCi=QdV*?ixlUO|7K=$}|~WaK;tG>1Lqu!53dNke+JU44a5jQnmqQiRh*MuS-a+6*RPz z*EQjA?dA{RArh7Zj8*L7t@Cf5RW2sVjwX8ahrTU{E4H_+iO0nuL!H`*(yL zzkzUvyA~HvE+d4Z{yO>PI!{#gf1THnP<+U>0O=Y8Ws+mrw}N3Oth_ z;V76gZ!T!GA4aw)bZvwa1zp^>_i-TW`^U++#*?%|U-J22WEIOBjDL05#%kz+%4-BL z-9Z4Z6AZmvl|Q>kWqXWoKaLJof2iKA);deK#-JgOq#@pb3_U; zlEq4_l=|=$LloG?PN0L-Y78oASlgsb>}5VW`U$uFru(#fl7H#99?hAnrDad**Yav@ zE+t$73yEU2I~xtB*d@qP4*pQIa6OirD4-*y3k4F9QebF?SVmLGgifs8aYtnw8SA%?cyEIgAp#@pI0ICA{_xZYO|a zYtHkAh4S49sXQ^*qX{moC!%E=1oK_q{j@<{{w_s_)8?%^BhQ6CsYk>+5>zGNDI7g? z%PAof%MMQVzfvG?mJP%9$2V=BW}%ocUG&qV7wE{K9Y_~I1`?er{{TCnj=I$cDXVFk z;ka>U)0>)TMy}xksBj_YICU;ZmI3AS1j7wC4_h;pdwpW|I%hFW7VyieMP|!dDSw|~pPpl8Uc9~pD%>Z%K znsWwJXOvhGG)+C}+OL|vNs{^P{7b@ER`x-uHA_9-xmKAa`N=KI#-O9pYpL?zTJN^s zvO<3)+w0VQrc!SrtA%`$e+4R*5tMvZslplRG=sY;CD+2M;u@g@l3$v|sc7Nac_>v# z%DLpI);TQ4#k+faeEi$x|Aw7{{dd`))x!`#+N$5mtxVsOFpW zvz~U{)jfOtz^~pzt5wcj&I_zAvYkq6Cgx@&*I|eaf50;}#-z(71G96y6HSP^fUU9x zm7ux35m#<$l!__ymEq*T8Y&8xTzwh)Mr&|+7KOMsx##YhHp299_yU5GN;- zLk3e^4^!wc%+p>Bf~~B57O1#?9Bi(j&eY}02)yPW{^_S~H@Q?_Cp1L&_91f;D8f=5 z7yWdYgX4pa-b^&kcmA2ZA5)+8Ok_g(0V{c($O?b0FSYw-WG5VtUf;c&kNEEvFgpmA z6t?qjztaR92--~)OxR96%ifml>7zPv@u8;G#OS32y!6=3<)H_%QcPWM&*o3j)3eFS z>+RCLG}?Xk&Emo6^$<4zwkrkG$#*BCzwj==(ZQdFN9VzWvYOx6Ht!5MqgI2k=d^{z zE1#G_fI=oUE(P%mb993{`U~VT>_6}Q$`ATfh$BU|l#6WRsws;~y*{`~V0h0|6(ppU zDOPJM58f?l#Rg}!>$7A_u=rwP`?h>Nym0G>#ItUx-lD$-f;4l%uo^n-)f!Jl&laVv zgJt1CTW1%~HNm1MA;jS1MAdHat<5>!3DyGtUFfqu1lVps$1qUNnyz zXI9^iMyHb3af+)m-xc)LJlLDllnqx}JD8ljT1^)cM5^tQhBb-gV#rlvxR>Qu11Sx! z^XH=Xm=4pBYy$NhB!y^AsPm?(uUe(M{?Lh7)l! zIz|Fru}t7hmucWff1x`RG7cnaB^z^E%Oy88Bn~K05#a!Xb-7sj7y7+47egcb?!pvi zhA=G}vCkB*GUbgvVeGHr#MK#J0ea8ydi{$EZytCK8PBwu$#Q_B;AhT=wE*R4g4arS zZ<+~FLooqwQesPb5HoVtQ;;@d3Neq{1|%;9E>}K$qg{UPVi&h7rR(GloXFhX=4J0| zD3I=c8mXt#5?@#71P|%ZqZO2!5l=^r#60l zk-#%_!}#oT5&u5Jxq&4o7R@au?v~_Ml$-;N#|7@bBp+c{!8@#k*#vCs$qab4Wkrg# zbj;S+;=qy_uh8vl5tFrTK`sb4O;FfA=Y=!Bwlia{4`r2fm>g;$XYc4;x9Ici^C0<( zR}V(-EQ*FmUO}Q`KW$EZ^z90&MX0f-`3&t53~nD%)3wYhZMMGkt)(rFt3-OL)iwTi)YIn-)|?nAP6XwGwyZ%c#jg*p$@>OZx1uY0O0nOSqaNFiCEN>Jgs}} zG94?(q{%Ll4k?+9^37Z;MZfdpeTmZE7N8S^jS?=q3cq$;70wtZ+yQ0$X$&3f(b+oJ z3FTe?6Z1wwjxGM8ix!?fJjIkt)Vib&8>C&Y7Emfn7`E_Oqcwv*PEC%^#z^%8D7E}; z(?Dl({D*|;9*jAY`)V(6CHRS$G8hI#iv{uxPtW#oq37NR>Oh)3&YZ1q-ZU@oqVJeJ z_Kx_tCZD8ZiEGzA=a(TecA7Uk`YR!yKQjs)|DwqKAC5wgFSr&Iwm28D5KYbv^qvS?B%|u7 zm!!U`2@wGE32_ktE^P6Nv>1d}K!KB-uV+_az^aLBK*7QmD-aV%rZYeiG}!3bA}9gI%);n7oN%wIC-%5ykx zYe(IDaGTiQoO<+^yJp~Q3+lN9hsdQC*qzAfxhUoiGnTU90EfD!i4X3-8^Y6OIvx5G z*Ui(tK$^(lIh<2$H4l5QbV9F%bm5k>1cm&Tf`c7^U9^Fn!BFnhq1(ScyDTK>G>u-4 zQW;}A6SE!c3;2r-J#-R;jMXpcOXE-HL=0`C7_4FVx3hyV0~HHE`PBBp`WG>C;N#=c z$B2h;H9#7&ZXokbDsXv_sRKd5_O57?ilPz4iL@r#t`Lk%z&$H-u4u76y96*0u(jFg z(XRSl?ee}GIH{ol+>N8hTG|^&iq9%vtx8-GzuhWdA`3x&Cz2B>_SbIaQoL!0&6wy4 zINLFgF!ReHTuxCyg;B5#-2S8+Z3Ir);aa&>21QB}Ry{z;RdUE}%)Wu{12PROnijY_^o+jWg7204!Rz#2N^fc_MM8~Q8x~=qFz_ih z%U)ABV}~mYHDC$e;kXO!e7ehoZo5i6tMX@8PKQ0@Zg+!{&ipSGRKB#)NV9W(ATZODyV6_p9ByM$WXx9IrF); zTljS!bB(4`=$F6AK<=tH^%@(M>(hAfL-q9ibb`qVxLXTsWuFCC=^y7aJgo zE!7-&o}tdV?C%w{BNqD08JIZr-6F}k6hVUy25>aqyE-|b@*Hv?bAk}gCa~{~n)Gl} z#XXxD@1OUIa#E=xr9~jP=IQJRb#VyWCXqw}^uoOuoSz;}hX-lng~}0&kkYGjsHAkh zV(Rl)om#(=EvKU?Svi*ZB$X#-Is~}aNmHeEK~VT z#Eu6!@nf(~7Z(jYkc29|XtbX{9mz(SVK3xCt%k}@YyK#H{hc8zC%6mz>noLt! zBwkm>aAi0g9zA%2>^&f8Y2Iv1YpWmX_SyVuPZvEjHh<<^nP?N%Dl8M{M+dSWZvtL8-zK?-c8vq*7T=NBzGL_Id2~H->L@ z*rILcvUsLH?sUW`H;^;tNidyfc}bLh3}voE1=|f<<5vtU#RAH*q^tut~1$6%oNLHmbe5Wf3 zvXK;!VDQ>NZ3UBMzVNHkax|PXGPG;?G4Wg#!)o4j2P=vq&{SvLjNKMRt?gu$L}%Nk zruN^2r|a2swUu}5o@MJ_e4$Nt=lF#Lv#L2CIxMa_uWg_QquD;Tg4xCH^J;q3ybOH? z+?8G#4eIPKnw*L)rT7P}1d>Tk>?mgTs+!%znLJ(d+Vv5RW-`MJ?f%zdnRRshnYi7{oGA8_sj6ZLPL2gF>x zfo+hcWlqma-oSf%F#FBRe%&rp*bn)3Wsy5jukAE4tsor@+-q0j3aa@C2S3mY(_u^I zzpN%XeBxANKWf2|nkuv3@YsOKhE}n|;<2-6?AZstv5L8M)rPxctn1d=%hfy<2#_DzY+^)K zH(_A*>P5b0X3-0E5Hg&ng@f~%?A_$*Gx{39gnx;}>vlAKwN&oj z=)q_$&OI;e(sUkyFCO_xts5D#q9c;n+PHVhwE_j2c6*bSG{gTV50)!>uoOAdmm&_B zghZ8x7Ck&agOBCll71^Ys)3l_N*0LJMUd-N#pE0hjGBIIX<_YJGWO`VrVFK0NQ$&& z(?Rs~j%@%}6c-cPVp1F-KQbkk>|g8Ns(e%pJxI&!mftWLTg0$w1i2JwrsP}#GSx(W ze#lJYnFCqaO7e;WkyMh9)jEyo{z;t60~J}7 zw%-au$bSBLGQ@Im%*1UbPhGE_{krQzlU-JzgDuO3=oEt#T}a}8I<#+eKt=?6U>4FT zQFsGZR6J6LNtPVVP@zg>dd-Owp9aw_2x<8$w5lFX;Xze2V@pfs-&H{wp_Y-a`Smg~ zWb^2#Z}(2J7W0)3GL36hrNTPw=^hE_b65#vC~uH=@c9=kd`P&k#XKO>N#WBKV3)rF z4CGlX(A&B-5OwYd>Duh~m6znSgzud1A-&k|CMQ1*k48TZzMk^;^n7^#5JK{316ghE z!CCe8ud0hwX`yug)7x%46LKEH8CHlwehqfMd-7;^>nW1xKizz?yZPkFv+sAm+kUwD z;t`m$NYyVT|M2V^lz#pK1@XSf)}P+*Jo@(8pIE)f*DtRXi4cpCj7F?>D$p z++t7+W9!>(jAHA>Zfx~V7i&)*ZSFjkOA79EQRaPaKH1vjSnmLBGC^?RfFBf$r8tv= zM^2ozZ?;}M-g@-p;qHrn+a{(95Yx+@N1M-|J;mz+G3oWgt>>HHJW;SP3({v$`n+#N zQh1>j%ZJ0Wp#%E)=PG8B{T7>}yq>0SZqDU{O{KgXj2L%JT)MRvG2tAJPDWF`QHo1} z_}W$-K7mU^Ba}0PT9p^^ngH`JRCN72ZO;6edX&V98Uuw?c5orFCff^rahHLDft4}C zgCA^tu6~$Hqg<$KXeXp{Jb{Kfc7(KMvMLJbEV4>4x!7XhGmWBaUk<+h+5*-(go02k z9W$H3$6YcTRh0BP6~6k%e{2*c5tr*`l4i9Mj@9i6(%4LgM-tU0;LI!hdpbqCGSO)4 z4|H;tRz9Smxs70kG(pMjWNMqlYOb=)PRv@1NAT0n~P^(jh5|F%px9F7`ZP%Q4=Hx?gcWGV3P4~ zjhqIv){p*v@PGGEgRmIb5xE9QE^q~wE|y}(8cIx!Kv@Hr%tbnbi%Hag>Jlhl%%!D+ zvDn-?gjpkm**ZGV^x??YL%8n%Pj?!)NhRh2r~Z0Nz;*@D=5~zOamC9)r*oehrZBw; zBItJALpW*3EkTlAE&%J1rW@^p>a(90o?fwx*nPFvEUpF{5;lC4%nTDC%}pKF@Y_OLU{T=f<+}wMVsh5+OH6F15jz^{cY0 z4fOR>Fq-piHtBcDN)*-ly_|6e6t*ydkCKVDoR-^k*xM2OHNYW(m@EX%ZAUD^A?a8%uPe`=tIpkdg$Psj6o>V`HYJDM@(KF=Q!$B#Gh)lyB|VH0WMwS{y@?oHik94O!%85>0Lb3-CS zI=ZDJJ}?Cmkl22EhAY!?*a{OHY*68 zY$kSRZ^o~oFB%4CEo5m$gLNLpiXK`x!*0OhL6X4fPEL=!FbHez^65xTs~gn=dAPQ3FJkCa{d!?cOc65Dj_rzoT_H$_ z)su?O^$mFC{9I$S5W8p)ARqJ7#OOlIux1b39~m~pmgj)$qDzzp<-{_!Fi&!WQ`k5^ z-U=j+g|D5uCj&w!Qha58xKy|rTP8Y@bk%A`7s&@mmL3eDy)N-=g`XbucA}+1zz?MP z72~C}%lViGc}|BSqZL;osUGoR(iOd#_*XDup_I~uIA*;bA8sI7j$9+#@W+V_@cT+3 zy@Wd$ZDbA(yuQ3f1M&_|r{e>-SJF561{cfFC5zvP)qTc-_)Q)iACFbZ0o~&s>qA{U z#Ge<&t{UQyMM~_hsVvpQu$=l7Nhg7HnL8H-(6QY@0O!c0ZjcrW^HW9L#qRo|?X=q8 zYQ!C(i}?2iLJh+0$UA6)U^Hlm{KA2C9roBPKUbT$`JrxXH&0xS;F>dQXb^(MV%@J_9PH-0 zPpmYl2gwlwNh_9#@#({89gef4uBa%0*Bq3^pCdeH4hmazfi$U-mN7bBi05%rjqM7< z*k-k5>)SA;GqCQC$y=l8o7>}3tkwq^D1taA?jC(q&kO3&d>&NSEOOtY;!ujEGZE)pzaH9zh5XPY9=h1xu9}iLDf;Xi39QOD{c!R3?E%KtU(qAoCTJYPSt{qhuD+icSpz!>JYv$VO7+aq=aD+WR_(wnUv<~hdqzGz8 z*{M0n#(8wzl?}gSnvpk59Hw}XKY`0*PJ8oHVj=`_|6s@;;$X3Hno^Ziqze26TKCd4kzdrcU|qn8T$}!)w472 z^1h8sZncc}R#HpH$sz)Q1#m0hc5~`_wn*_j=T6IF!DP!~a>^uS3hlRY^bU{NYv`2(~9-2 z7B!{h~ohri`*3$bXT~| z$~zqX<9Xr1E6=kB@2|Vc9sKDYu0MPFUU57`1INL zPgir8g1Xa{=s-c+*0&1^Zcqq++XWJmP{_VpL0?caG}Ry$JfY&MD9T6Kj8|KB{`T~7MYhD+)O22SKZ~xHN%?ZyfV21eD=8W z)HyKqg~JOgQ>>vQsVnp>00_$o?xR$e8XkgXcA(p;&acvif!47;ge%mZou55>{S6a7 z&GHTOxIXRe$>jZs5-vM*;}`qZsjJ6F{Rl&nxssKhvsE0J!B+loqPd}vYZ)L5TMUnY z{eugQ7R#n{j;Kt|L0l{5UaqjSMt+V{1ac$G$nfZ4N>oCS%xv6gAPDp)AC7k|G;8Pfz?&k zSd|}LYr8O2y(e}IOv9ebo4q2(bubYp`tn?9HPrWo{bZ0s!xY9SiC~2Fds(80-Kna> zpK|^23os32i?U7{W~UA2ZAou?M!tal`v~3nGLJ|no4vqTS!~M$!&mI5g}WwMtzf-A z9G?u2c7UYiSv1T;DGJbp4I(zo%|6;M1Qsc>N7Cx=fM#~GB*clYFRMe24!7#io?&a|Wi9kvJ z9m~6sd7?lmQ;SEfnx|M>3bdTr2GpXcegbvM3Z(PG6f1;6yulSSl{v!O!@1711T6*HG!9T%U1zTn8mv7u1 zgnrAubFchXvn$Jn{?sFvxzbrUxE+~oKpb|NH$-Li2GZ759hZtiXc|R}!d*_Y!gD8Q zj-8^E{h<0{7G>hR=})$UE7=a3q0~#B{>b%XZt6V6!9;hD9OF$oHPT)7qXUGabY5d0X)i>Y z)MoW~%&{%dr^7c!2yi&J2HSvN;{|G^#*_ms$b}+eKqP|dPsD(}c1#%429xCjYzUEJ z5{62uAw-YZQ|NeP&fjV#;(aQfTSO&fGON6Rbkv&o8|<8ewe`)PzWM0^9ED(Shn@Qy z$w2ZzY~Jhulckq?d`=Ki&Iv1$#Lh~!4L zVrCBs9|MeMb%Rahy5&g>Zm8Ng+^EMWsj1D#^?7Jv&eyXy!?VF5@1_v^D|rzQK18>5 z?~nrHhjVA+0lY$>7@=f?fkJzR6imo|f5^0_)|A=wx=t$^RKBAV&wkc=i6#Y|B@*TK zMkX$O5k&Q96n>}z?$fQ(y8EB3-@_)QsmP_S)R1AkQ7`zg>rj&#ygom|6|?X}JQSS# zRtIm0qo$vTR^ocS`?@(+aMcePlvI#8`YT<)2W0^(1|SENt97*kiWL#w<9)$-Ivq-g zOkar6QYmi=Dxm=wdfj6Tly!uu!EJ7O1vAcEVB&@#GL|3sJ**H$bDi=WslF+ zOvFvyhnzG{Cdked(jyF9da1z4Qf85i!Sstfg52;y`TW;^mk}#A03P+rhwRHAT#*zF z@1a3A@;jsid!!N-*$G=xaXI$h(ul!lC!=St+0t5t(L`+c0=PO$s}p(R+^}8B8v-W^ zWmR2SYSv1GZv3L9u7zCycy;ZQjYb)9-YPGY$Wsz#O=S*h8;W7qNr2NPMY)`$LP#e< zo>||#*+;+II?AZd*t*LWtuLO^AZ@yW;CaU?0uHp7Xn7GSJMf`y&(}=zzP3=1CK~mI zoTrqALR;d>!rxaV@6Z;TxC*6f+^W!cFV+`OyG#B`M9Xm3$|b96>7&SxGYD|+YqDD#H-2M=b!a|V!jr|{^So)w(Bnc%IMaNrUlK!vP zq*Pj;i5XU$v8pR zYmqa0q2jf5H42nG#Pt;h!_M022o13m_)| zS)51j% zKRuG)8QhgrX8qpi1QBkMy+FAX;3+OKXMhCQ2O2{8@$8Y@+1Wh;basn1(1|gNGsNEb3EdH>#2GGpztePvMhN$M#H1 zw;K-BC30(|vOai$g?0cAv`u1)f&wf)V)H5LCPt-4WAV)aZ^VsbmbcGd!{cY}n#CUY zX-<_7s^T%0ujh)-_|fM!cMTzA5_9%=GTm0e&@X~OuDUR1gZF=S&Ra9!|GngrtS+!> zU$aDNH~TZlBBA>3^pFk_yyX`S=9%-;i@SHXpKQK({A}l2_g&oGdGxzS{~BeJ%d5^> zpfq+#27=*U4Ma(FU60gk$xD;QM&;t=_I!kpi|Cw)k&3R7py--Ros&_t241y{yLXG+ zt)Abfjn^7c{JRo?}L~Fd#S?#-Cj;jNcxb=97CX! zBzy}HXaW!1`P9+vb&=Mh88tevTgi0(7>?;j;~`u> zOogD}F$DGsVK(hnLxw$s>1VtHH%2C=<^;jROCl8XNbD4T-&GQQK-bAxK2(f49X|Xhg{4Mj@^rO;Qs%QTi4bX(Flt%h39<}_ZuQZp5Y9i^jtxn(RV z=KJ@h$&y3k*dIU_9UsdqZB^>vcn~@gbU+?(R?dkj4Xm6Y%B6pG5rQn~P15yE-OM8_ z<0Q4f+#wwq^>NMM<=}*@yh<|}KiG2p$pf@@ba>8o)evKClK=${w{^l3F*c+mo5;Kx z8{ES(j5G-GQ7*WMscku+iQx~N$R&&jdFa3B+;WxtOlL_i;rT(#IM=(Y?o!5Fjjn&0 z*Xb%I#V6=miL{4ORAW)9LSm{ch8+n1n$hx1P!49Y6Cqjw1?IZ z2^^M+P<3)xZA(yWZS_45o%}F4xyZrQf@h*wbCEbo(!QPJ@CdP}`L;GkpZ!I9IPIG8 zl<0W)7WcB9!|M{4f-|EQ55kYd_40JQ{}%gTED*SllRH=O@cb|1o~tuOlW2llgp*5$ zS~Mm2-wLs0sw&ryD(cqbK(KhMQ8I%GiYx8;Q_@>x%jSP_X>MN+7giG}hion{YQ`jF z1UA4UHSUCAF6@*^^r%Vs3xI<0q+W)_*n*~YR};7`6N3U+v@bhH*W*elTXzr-5}gb} zHyP!vin2DNbYclBq=z{;!TbIVa<3fW!bKdf!mo|Do!bK$Sfi>Nzkh}?2c@FcY?>rd zprIaOXiTusAgMSy*Jc$9LNH1qpYEf*;(fH&5-j0igv~q;-2jR(Z`fAZ;k<@g854xZ zmdE